diff --git a/app/models/form/admin_settings.rb b/app/models/form/admin_settings.rb index bd7bed3af52961..55909bc0ce98f8 100644 --- a/app/models/form/admin_settings.rb +++ b/app/models/form/admin_settings.rb @@ -39,6 +39,7 @@ class Form::AdminSettings captcha_enabled ng_words ng_words_for_stranger_mention + stranger_mention_from_local_ng hide_local_users_for_anonymous post_hash_tags_max sensitive_words @@ -79,6 +80,7 @@ class Form::AdminSettings check_lts_version_only enable_public_unlisted_visibility unlocked_friend + stranger_mention_from_local_ng ).freeze UPLOAD_KEYS = %i( diff --git a/app/services/post_status_service.rb b/app/services/post_status_service.rb index cdd1aa86747e89..5410323dbb5e42 100644 --- a/app/services/post_status_service.rb +++ b/app/services/post_status_service.rb @@ -146,6 +146,7 @@ def process_status! @status = @account.statuses.new(status_attributes) process_mentions_service.call(@status, limited_type: @status.limited_visibility? ? @limited_scope : '', circle: @circle, save_records: false) safeguard_mentions!(@status) + validate_status_mentions! @status.limited_scope = :personal if @status.limited_visibility? && !process_mentions_service.mentions? @@ -208,6 +209,15 @@ def validate_status! raise Mastodon::ValidationError, I18n.t('statuses.too_many_hashtags') if Admin::NgWord.hashtag_reject_with_extractor?(@options[:text]) end + def validate_status_mentions! + raise Mastodon::ValidationError, I18n.t('statuses.contains_ng_words') if mention_to_stranger? && Setting.stranger_mention_from_local_ng && Admin::NgWord.stranger_mention_reject?("#{@options[:spoiler_text]}\n#{@options[:text]}") + end + + def mention_to_stranger? + @status.mentions.map(&:account).to_a.any? { |mentioned_account| mentioned_account.id != @account && !mentioned_account.following?(@account) } || + (@in_reply_to && @in_reply_to.account.id != @account.id && !@in_reply_to.account.following?(@account)) + end + def validate_media! if @options[:media_ids].blank? || !@options[:media_ids].is_a?(Enumerable) @media = [] diff --git a/app/views/admin/ng_words/show.html.haml b/app/views/admin/ng_words/show.html.haml index 3450135c3c64a3..2a81eec057b1e5 100644 --- a/app/views/admin/ng_words/show.html.haml +++ b/app/views/admin/ng_words/show.html.haml @@ -10,6 +10,9 @@ .fields-group = f.input :ng_words_for_stranger_mention, wrapper: :with_label, as: :text, input_html: { rows: 12 }, label: t('admin.ng_words.keywords_for_stranger_mention'), hint: t('admin.ng_words.keywords_for_stranger_mention_hint') + .fields-group + = f.input :stranger_mention_from_local_ng, wrapper: :with_label, as: :boolean, label: t('admin.ng_words.stranger_mention_from_local_ng'), hint: t('admin.ng_words.stranger_mention_from_local_ng_hint') + .fields-group = f.input :ng_words, wrapper: :with_label, as: :text, input_html: { rows: 12 }, label: t('admin.ng_words.keywords'), hint: t('admin.ng_words.keywords_hint') diff --git a/config/locales/en.yml b/config/locales/en.yml index b5e9f348236dc8..747545112824bb 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -647,6 +647,8 @@ en: keywords_for_stranger_mention_hint: Currently this words are checked posts from other servers only. keywords_hint: The first character of the line is "?". to use regular expressions post_hash_tags_max: Hash tags max for posts + stranger_mention_from_local_ng: フォローしていないアカウントへのメンションのNGワードを、ローカルユーザーによる投稿にも適用する + stranger_mention_from_local_ng_hint: サーバーの登録が承認制でない場合、あなたのサーバーにもスパムが入り込む可能性があります test_error: Testing is returned any errors title: NG words and against spams relationships: diff --git a/config/locales/ja.yml b/config/locales/ja.yml index 98de29324f8366..e0539d21501b7f 100644 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@ -647,6 +647,8 @@ ja: keywords_for_stranger_mention_hint: フォローしていないアカウントへのメンションにのみ適用されます。現状は外部サーバーから来た投稿のみに適用されます keywords_hint: 行を「?」で始めると、正規表現が使えます post_hash_tags_max: 投稿に設定可能なハッシュタグの最大数 + stranger_mention_from_local_ng: フォローしていないアカウントへのメンションのNGワードを、ローカルユーザーによる投稿にも適用する + stranger_mention_from_local_ng_hint: サーバーの登録が承認制でない場合、あなたのサーバーにもスパムが入り込む可能性があります test_error: NGワードのテストに失敗しました。正規表現のミスが含まれているかもしれません title: NGワードとスパム relationships: diff --git a/config/settings.yml b/config/settings.yml index 1fb106e680a2e9..65128db7f0ff7f 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -44,6 +44,7 @@ defaults: &defaults check_lts_version_only: true enable_public_unlisted_visibility: true unlocked_friend: false + stranger_mention_from_local_ng: true development: <<: *defaults diff --git a/spec/services/post_status_service_spec.rb b/spec/services/post_status_service_spec.rb index f63829f23495e1..adf7e33d8ec9a9 100644 --- a/spec/services/post_status_service_spec.rb +++ b/spec/services/post_status_service_spec.rb @@ -436,6 +436,82 @@ expect(status2.id).to eq status1.id end + describe 'ng word is set' do + it 'hit ng words' do + account = Fabricate(:account) + text = 'ng word test' + Form::AdminSettings.new(ng_words: 'test').save + + expect { subject.call(account, text: text) }.to raise_error(Mastodon::ValidationError) + end + + it 'not hit ng words' do + account = Fabricate(:account) + text = 'ng word aiueo' + Form::AdminSettings.new(ng_words: 'test').save + + status = subject.call(account, text: text) + + expect(status).to be_persisted + expect(status.text).to eq text + end + + it 'hit ng words for mention' do + account = Fabricate(:account) + mentioned = Fabricate(:account, username: 'ohagi', domain: nil) + text = 'ng word test @ohagi' + Form::AdminSettings.new(ng_words_for_stranger_mention: 'test', stranger_mention_from_local_ng: '1').save + + expect { subject.call(account, text: text) }.to raise_error(Mastodon::ValidationError) + end + + it 'hit ng words for mention but local posts are not checked' do + account = Fabricate(:account) + mentioned = Fabricate(:account, username: 'ohagi', domain: nil) + text = 'ng word test @ohagi' + Form::AdminSettings.new(ng_words_for_stranger_mention: 'test', stranger_mention_from_local_ng: '0').save + + status = subject.call(account, text: text) + + expect(status).to be_persisted + expect(status.text).to eq text + end + + it 'hit ng words for mention to follower' do + account = Fabricate(:account) + mentioned = Fabricate(:account, username: 'ohagi', domain: nil) + mentioned.follow!(account) + text = 'ng word test @ohagi' + Form::AdminSettings.new(ng_words_for_stranger_mention: 'test', stranger_mention_from_local_ng: '1').save + + status = subject.call(account, text: text) + + expect(status).to be_persisted + expect(status.text).to eq text + end + + it 'hit ng words for reply' do + account = Fabricate(:account) + text = 'ng word test' + Form::AdminSettings.new(ng_words_for_stranger_mention: 'test', stranger_mention_from_local_ng: '1').save + + expect { subject.call(account, text: text, thread: Fabricate(:status)) }.to raise_error(Mastodon::ValidationError) + end + + it 'hit ng words for reply to follower' do + account = Fabricate(:account) + mentioned = Fabricate(:account, username: 'ohagi', domain: nil) + mentioned.follow!(account) + text = 'ng word test' + Form::AdminSettings.new(ng_words_for_stranger_mention: 'test', stranger_mention_from_local_ng: '1').save + + status = subject.call(account, text: text) + + expect(status).to be_persisted + expect(status.text).to eq text + end + end + def create_status_with_options(**options) subject.call(Fabricate(:account), options.merge(text: 'test')) end