diff --git a/app/models/form/admin_settings.rb b/app/models/form/admin_settings.rb index 2513023b6e..f0dec6967e 100644 --- a/app/models/form/admin_settings.rb +++ b/app/models/form/admin_settings.rb @@ -64,6 +64,7 @@ class Form::AdminSettings unlocked_friend enable_local_timeline emoji_reaction_disallow_domains + permit_new_account_domains ).freeze INTEGER_KEYS = %i( @@ -123,6 +124,7 @@ class Form::AdminSettings sensitive_words sensitive_words_for_full emoji_reaction_disallow_domains + permit_new_account_domains ).freeze attr_accessor(*KEYS) diff --git a/app/services/activitypub/process_account_service.rb b/app/services/activitypub/process_account_service.rb index 5b1cfe2f59..8c45fd2d5d 100644 --- a/app/services/activitypub/process_account_service.rb +++ b/app/services/activitypub/process_account_service.rb @@ -13,7 +13,7 @@ class ActivityPub::ProcessAccountService < BaseService # Should be called with confirmed valid JSON # and WebFinger-resolved username and domain - def call(username, domain, json, options = {}) + def call(username, domain, json, options = {}) # rubocop:disable Metrics/PerceivedComplexity return if json['inbox'].blank? || unsupported_uri_scheme?(json['id']) || domain_not_allowed?(domain) @options = options @@ -37,6 +37,8 @@ class ActivityPub::ProcessAccountService < BaseService @suspension_changed = false if @account.nil? + return nil if blocking_new_account?(@domain) + with_redis do |redis| return nil if redis.pfcount("unique_subdomains_for:#{PublicSuffix.domain(@domain, ignore_private: true)}") >= SUBDOMAINS_RATELIMIT @@ -130,6 +132,16 @@ class ActivityPub::ProcessAccountService < BaseService @account.memorial = @json['memorial'] || false end + def blocking_new_account?(domain) + return false if permit_new_account_domains.blank? + + permit_new_account_domains.exclude?(domain) + end + + def permit_new_account_domains + (Setting.permit_new_account_domains || []).compact_blank + end + def valid_account? display_name = @json['name'] || '' note = @json['summary'] || '' diff --git a/app/views/admin/ng_words/show.html.haml b/app/views/admin/ng_words/show.html.haml index d188a179c0..18d57d3468 100644 --- a/app/views/admin/ng_words/show.html.haml +++ b/app/views/admin/ng_words/show.html.haml @@ -32,5 +32,8 @@ .fields-group = f.input :hide_local_users_for_anonymous, wrapper: :with_label, as: :boolean, label: t('admin.ng_words.hide_local_users_for_anonymous') + .fields-group + = f.input :permit_new_account_domains, wrapper: :with_label, as: :text, kmyblue: true, input_html: { rows: 6 }, label: t('admin.special_instances.permit_new_account_domains'), hint: t('admin.special_instances.permit_new_account_domains_hint') + .actions = f.button :button, t('generic.save_changes'), type: :submit diff --git a/config/locales/en.yml b/config/locales/en.yml index ddb7b03869..a7387e29aa 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -918,6 +918,8 @@ en: special_instances: emoji_reaction_disallow_domains: Domains we are not permitted emoji reaction emoji_reaction_disallow_domains_hint: If you need to be considerate to your coalition partners, set the domain with a new line separator. It is not possible to put an emoji reaction on a post from a set domain. + permit_new_account_domains: Domain to allow recognition of new accounts + permit_new_account_domains_hint: Only new account information sent from the domain specified here will be saved if more than one is specified, title: Special servers statuses: account: Author diff --git a/config/locales/ja.yml b/config/locales/ja.yml index 2b87a13798..b4bb14f0cc 100644 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@ -909,6 +909,8 @@ ja: special_instances: emoji_reaction_disallow_domains: 自分のサーバーが絵文字リアクションをすることを許可しないドメイン emoji_reaction_disallow_domains_hint: 連合先に配慮する必要がある場合、ドメインを改行区切りで設定します。設定されたドメインの投稿に絵文字リアクションを付けることはできません。 + permit_new_account_domains: 新規アカウントの認知を許可するドメイン + permit_new_account_domains_hint: 1つ以上指定した場合、ここで指定されたドメインから送られてくる新規アカウント情報だけが保存されるようになります title: 特殊なサーバー statuses: account: 作成者 diff --git a/spec/services/activitypub/process_account_service_spec.rb b/spec/services/activitypub/process_account_service_spec.rb index 2763805f6d..95cf92a46c 100644 --- a/spec/services/activitypub/process_account_service_spec.rb +++ b/spec/services/activitypub/process_account_service_spec.rb @@ -9,6 +9,58 @@ RSpec.describe ActivityPub::ProcessAccountService, type: :service do stub_request(:get, 'https://example.com/.well-known/nodeinfo').to_return(status: 404) end + describe 'about blocking new remote account' do + subject { described_class.new.call('alice', 'example.com', payload) } + + let(:permit_new_account_domains) { nil } + let(:payload) do + { + id: 'https://foo.test', + type: 'Actor', + inbox: 'https://foo.test/inbox', + actor_type: 'Person', + summary: 'new bio', + }.with_indifferent_access + end + + before do + Setting.permit_new_account_domains = permit_new_account_domains + end + + it 'created account in a simple case' do + expect(subject).to_not be_nil + expect(subject.uri).to eq 'https://foo.test' + end + + context 'when is blocked' do + let(:permit_new_account_domains) { ['foo.bar'] } + + it 'does not create account' do + expect(subject).to be_nil + end + + context 'with has existing account' do + before do + Fabricate(:account, uri: 'https://foo.test', domain: 'example.com', username: 'alice', note: 'old bio') + end + + it 'updated account' do + expect(subject).to_not be_nil + expect(subject.note).to eq 'new bio' + end + end + end + + context 'when is in whitelist' do + let(:permit_new_account_domains) { ['example.com'] } + + it 'does not create account' do + expect(subject).to_not be_nil + expect(subject.uri).to eq 'https://foo.test' + end + end + end + context 'with searchability' do subject { described_class.new.call('alice', 'example.com', payload) }