]> git.openstreetmap.org Git - rails.git/commitdiff
Add rate limiting to user friendships
authorTom Hughes <tom@compton.nu>
Tue, 11 May 2021 11:02:05 +0000 (12:02 +0100)
committerTom Hughes <tom@compton.nu>
Tue, 11 May 2021 11:10:36 +0000 (12:10 +0100)
app/controllers/friendships_controller.rb
app/models/user.rb
config/locales/en.yml
config/settings.yml
db/migrate/20210511104518_add_time_to_friendships.rb [new file with mode: 0644]
db/structure.sql

index 0bff13df6efb573c478798eabc3e69bde3c3fc1d..5cdb2a4e4323ea11645383bea4ebf94edeb2561b 100644 (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
index 26a9f33e153bf04c92d81335577bf37ded97bd27..a2c0619dea9031b91a04e40230e4554c1149d64b 100644 (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
index cfe717fe261ca16c3084f82c61766797146db2c2..e04a6ac874f9e1eb411aa240bd61953d4118a5c6 100644 (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"
index 3dd73297220e15b138482854559e424912372550..81ab3701597a304a314adb95e6bcf2a4adf525c8 100644 (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
diff --git a/db/migrate/20210511104518_add_time_to_friendships.rb b/db/migrate/20210511104518_add_time_to_friendships.rb
new file mode 100644 (file)
index 0000000..4f426a6
--- /dev/null
@@ -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
index 89a62626eef8d627d193992b08b817219749e194..957dee817f87ca0d45b4b7e8ac03089c3237c090 100644 (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'),