Add rate limiting to user friendships

This commit is contained in:
Tom Hughes 2021-05-11 12:02:05 +01:00
parent 4d164df5b8
commit 84c601460f
6 changed files with 33 additions and 8 deletions

View file

@ -19,6 +19,8 @@ class FriendshipsController < ApplicationController
friendship.befriendee = @new_friend
if current_user.is_friends_with?(@new_friend)
flash[:warning] = t "friendships.make_friend.already_a_friend", :name => @new_friend.display_name
elsif current_user.friendships.where("created_at >= ?", Time.now.getutc - 1.hour).count >= current_user.max_friends_per_hour
flash.now[:error] = t "friendships.make_friend.limit_exceeded"
elsif friendship.save
flash[:notice] = t "friendships.make_friend.success", :name => @new_friend.display_name
UserMailer.friendship_notification(friendship).deliver_later

View file

@ -305,6 +305,15 @@ class User < ApplicationRecord
max_messages.clamp(0, Settings.max_messages_per_hour)
end
def max_friends_per_hour
account_age_in_seconds = Time.now.utc - creation_time
account_age_in_hours = account_age_in_seconds / 3600
recent_friends = friendships.where("created_at >= ?", Time.now.utc - 3600).count
active_reports = issues.with_status(:open).sum(:reports_count)
max_messages = account_age_in_hours.ceil + recent_friends - active_reports * 10
max_messages.clamp(0, Settings.max_friends_per_hour)
end
private
def set_defaults

View file

@ -487,6 +487,7 @@ en:
success: "%{name} is now your friend!"
failed: "Sorry, failed to add %{name} as a friend."
already_a_friend: "You are already friends with %{name}."
limit_exceeded: "You have friended a lot of users recently. Please wait a while before trying to friend any more."
remove_friend:
heading: "Unfriend %{user}?"
button: "Unfriend"

View file

@ -45,6 +45,8 @@ web_timeout: 30
user_block_periods: [0, 1, 3, 6, 12, 24, 48, 96, 168, 336, 731, 4383, 8766, 87660]
# Rate limit for message sending
max_messages_per_hour: 60
# Rate limit for friending
max_friends_per_hour: 60
# Domain for handling message replies
#messages_domain: "messages.openstreetmap.org"
# Geonames authentication details

View file

@ -0,0 +1,9 @@
class AddTimeToFriendships < ActiveRecord::Migration[6.0]
disable_ddl_transaction!
def change
add_column :friends, :created_at, :datetime
add_index :friends, [:user_id, :created_at], :algorithm => :concurrently
remove_index :friends, :column => :user_id, :name => "friends_user_id_idx"
end
end

View file

@ -720,7 +720,8 @@ CREATE TABLE public.diary_entry_subscriptions (
CREATE TABLE public.friends (
id bigint NOT NULL,
user_id bigint NOT NULL,
friend_user_id bigint NOT NULL
friend_user_id bigint NOT NULL,
created_at timestamp without time zone
);
@ -2146,13 +2147,6 @@ CREATE INDEX diary_entry_language_code_created_at_index ON public.diary_entries
CREATE INDEX diary_entry_user_id_created_at_index ON public.diary_entries USING btree (user_id, created_at);
--
-- Name: friends_user_id_idx; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX friends_user_id_idx ON public.friends USING btree (user_id);
--
-- Name: gpx_file_tags_gpxid_idx; Type: INDEX; Schema: public; Owner: -
--
@ -2279,6 +2273,13 @@ CREATE INDEX index_client_applications_on_user_id ON public.client_applications
CREATE INDEX index_diary_entry_subscriptions_on_diary_entry_id ON public.diary_entry_subscriptions USING btree (diary_entry_id);
--
-- Name: index_friends_on_user_id_and_created_at; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX index_friends_on_user_id_and_created_at ON public.friends USING btree (user_id, created_at);
--
-- Name: index_issue_comments_on_issue_id; Type: INDEX; Schema: public; Owner: -
--
@ -3123,6 +3124,7 @@ INSERT INTO "schema_migrations" (version) VALUES
('20201006213836'),
('20201006220807'),
('20201214144017'),
('20210511104518'),
('21'),
('22'),
('23'),