Skip to content
Snippets Groups Projects
Unverified Commit a46ab86a authored by Eugen Rochko's avatar Eugen Rochko Committed by GitHub
Browse files

Limit the number of people that can be followed from one account (#8807)

Configurable soft limit of 7,500, and above that, configurable
ratio of 1.1 * followers, controlled by:

- MAX_FOLLOWS_THRESHOLD
- MAX_FOLLOWS_RATIO

Fix #2311
parent 186024a0
No related branches found
No related tags found
No related merge requests found
......@@ -25,6 +25,7 @@ class Follow < ApplicationRecord
has_one :notification, as: :activity, dependent: :destroy
validates :account_id, uniqueness: { scope: :target_account_id }
validates_with FollowLimitValidator, on: :create
scope :recent, -> { reorder(id: :desc) }
......
......@@ -22,6 +22,7 @@ class FollowRequest < ApplicationRecord
has_one :notification, as: :activity, dependent: :destroy
validates :account_id, uniqueness: { scope: :target_account_id }
validates_with FollowLimitValidator, on: :create
def authorize!
account.follow!(target_account, reblogs: show_reblogs, uri: uri)
......
# frozen_string_literal: true
class FollowLimitValidator < ActiveModel::Validator
LIMIT = ENV.fetch('MAX_FOLLOWS_THRESHOLD', 7_500).to_i
RATIO = ENV.fetch('MAX_FOLLOWS_RATIO', 1.1).to_f
def validate(follow)
return if follow.account.nil? || !follow.account.local?
follow.errors.add(:base, I18n.t('users.follow_limit_reached', limit: self.class.limit_for_account(follow.account))) if limit_reached?(follow.account)
end
class << self
def limit_for_account(account)
if account.following_count < LIMIT
LIMIT
else
account.followers_count * RATIO
end
end
end
private
def limit_reached?(account)
account.following_count >= self.class.limit_for_account(account)
end
end
......@@ -37,6 +37,8 @@ class ImportWorker
end
def import_rows
CSV.new(import_contents).reject(&:blank?)
rows = CSV.new(import_contents).reject(&:blank?)
rows = rows.take(FollowLimitValidator.limit_for_account(@import.account)) if @import.type == 'following'
rows
end
end
......@@ -917,6 +917,7 @@ en:
tips: Tips
title: Welcome aboard, %{name}!
users:
follow_limit_reached: You cannot follow more than %{limit} people
invalid_email: The e-mail address is invalid
invalid_otp_token: Invalid two-factor code
otp_lost_help_html: If you lost access to both, you may get in touch with %{email}
......
......@@ -23,6 +23,20 @@ RSpec.describe Follow, type: :model do
follow.valid?
expect(follow).to model_have_error_on_field(:target_account)
end
it 'is invalid if account already follows too many people' do
alice.update(following_count: FollowLimitValidator::LIMIT)
expect(subject).to_not be_valid
expect(subject).to model_have_error_on_field(:base)
end
it 'is valid if account is only on the brink of following too many people' do
alice.update(following_count: FollowLimitValidator::LIMIT - 1)
expect(subject).to be_valid
expect(subject).to_not model_have_error_on_field(:base)
end
end
describe 'recent' do
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment