From 74119418851efde3b721ce3c682c200cf9628e94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?KMY=EF=BC=88=E9=9B=AA=E3=81=82=E3=81=99=E3=81=8B=EF=BC=89?= Date: Sat, 17 Feb 2024 09:50:06 +0900 Subject: [PATCH] =?UTF-8?q?Add:=20=E3=83=A1=E3=83=B3=E3=82=B7=E3=83=A7?= =?UTF-8?q?=E3=83=B3=E6=95=B0=E4=B8=8A=E9=99=90=20(#565)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add: メンション数上限 * Fix test --- app/lib/activitypub/activity/create.rb | 5 ++- app/models/admin/ng_word.rb | 13 ++++++ app/models/form/admin_settings.rb | 2 + .../process_status_update_service.rb | 2 +- app/services/post_status_service.rb | 3 +- app/services/update_status_service.rb | 3 +- app/views/admin/ng_words/show.html.haml | 3 ++ config/locales/en.yml | 2 + config/locales/ja.yml | 2 + spec/lib/activitypub/activity/create_spec.rb | 41 +++++++++++++++++++ spec/services/post_status_service_spec.rb | 23 +++++++++++ 11 files changed, 94 insertions(+), 5 deletions(-) diff --git a/app/lib/activitypub/activity/create.rb b/app/lib/activitypub/activity/create.rb index d137a642000573..b73c2cddd1112d 100644 --- a/app/lib/activitypub/activity/create.rb +++ b/app/lib/activitypub/activity/create.rb @@ -143,8 +143,9 @@ def process_status_params end def valid_status? - valid = !Admin::NgWord.reject?("#{@params[:spoiler_text]}\n#{@params[:text]}", uri: @params[:uri], target_type: :status, public: @status_parser.distributable_visibility?) && !Admin::NgWord.hashtag_reject?(@tags.size) - + valid = !Admin::NgWord.reject?("#{@params[:spoiler_text]}\n#{@params[:text]}", uri: @params[:uri], target_type: :status, public: @status_parser.distributable_visibility?) + valid = !Admin::NgWord.hashtag_reject?(@tags.size) if valid + valid = !Admin::NgWord.mention_reject?(@mentions.count { |m| !m.silent }) if valid valid = !Admin::NgWord.stranger_mention_reject?("#{@params[:spoiler_text]}\n#{@params[:text]}", uri: @params[:uri], target_type: :status, public: @status_parser.distributable_visibility?) if valid && (mention_to_local_stranger? || reference_to_local_stranger?) valid diff --git a/app/models/admin/ng_word.rb b/app/models/admin/ng_word.rb index 3e7c7e78cee326..c3d8c020a34fb3 100644 --- a/app/models/admin/ng_word.rb +++ b/app/models/admin/ng_word.rb @@ -26,6 +26,14 @@ def hashtag_reject_with_extractor?(text) hashtag_reject?(Extractor.extract_hashtags(text)&.size || 0) end + def mention_reject?(mention_count) + post_mentions_max.positive? && post_mentions_max < mention_count + end + + def mention_reject_with_extractor?(text) + mention_reject?(text.gsub(Account::MENTION_RE)&.count || 0) + end + private def include?(text, word) @@ -49,6 +57,11 @@ def post_hash_tags_max value.is_a?(Integer) && value.positive? ? value : 0 end + def post_mentions_max + value = Setting.post_mentions_max + value.is_a?(Integer) && value.positive? ? value : 0 + end + def record!(type, text, keyword, options) return unless options[:uri] && options[:target_type] return if options.key?(:public) && !options.delete(:public) diff --git a/app/models/form/admin_settings.rb b/app/models/form/admin_settings.rb index 3cb864ace58cb4..144bb1a2ecf038 100644 --- a/app/models/form/admin_settings.rb +++ b/app/models/form/admin_settings.rb @@ -49,6 +49,7 @@ class Form::AdminSettings stranger_mention_from_local_ng hide_local_users_for_anonymous post_hash_tags_max + post_mentions_max sensitive_words sensitive_words_for_full authorized_fetch @@ -69,6 +70,7 @@ class Form::AdminSettings content_cache_retention_period backups_retention_period post_hash_tags_max + post_mentions_max registrations_limit registrations_limit_per_day registrations_start_hour diff --git a/app/services/activitypub/process_status_update_service.rb b/app/services/activitypub/process_status_update_service.rb index 5dc3aa4fc131d2..2549c44ed6596e 100644 --- a/app/services/activitypub/process_status_update_service.rb +++ b/app/services/activitypub/process_status_update_service.rb @@ -161,7 +161,7 @@ def update_poll!(allow_significant_changes: true) end def valid_status? - !Admin::NgWord.reject?("#{@status_parser.spoiler_text}\n#{@status_parser.text}", uri: @status.uri, target_type: :status) && !Admin::NgWord.hashtag_reject?(@raw_tags.size) + !Admin::NgWord.reject?("#{@status_parser.spoiler_text}\n#{@status_parser.text}", uri: @status.uri, target_type: :status) && !Admin::NgWord.hashtag_reject?(@raw_tags.size) && !Admin::NgWord.mention_reject?(@raw_mentions.size) end def validate_status_mentions! diff --git a/app/services/post_status_service.rb b/app/services/post_status_service.rb index 1f9f1c05928caf..d0341f65b5310c 100644 --- a/app/services/post_status_service.rb +++ b/app/services/post_status_service.rb @@ -209,7 +209,8 @@ def postprocess_status! def validate_status! raise Mastodon::ValidationError, I18n.t('statuses.contains_ng_words') if Admin::NgWord.reject?("#{@options[:spoiler_text]}\n#{@options[:text]}") - raise Mastodon::ValidationError, I18n.t('statuses.too_many_hashtags') if Admin::NgWord.hashtag_reject_with_extractor?(@options[:text]) + raise Mastodon::ValidationError, I18n.t('statuses.too_many_hashtags') if Admin::NgWord.hashtag_reject_with_extractor?(@text) + raise Mastodon::ValidationError, I18n.t('statuses.too_many_mentions') if Admin::NgWord.mention_reject_with_extractor?(@text) end def validate_status_mentions! diff --git a/app/services/update_status_service.rb b/app/services/update_status_service.rb index da47dfb5f56afd..59caf4c6bb5b3e 100644 --- a/app/services/update_status_service.rb +++ b/app/services/update_status_service.rb @@ -82,7 +82,8 @@ def update_media_attachments! def validate_status! raise Mastodon::ValidationError, I18n.t('statuses.contains_ng_words') if Admin::NgWord.reject?("#{@options[:spoiler_text]}\n#{@options[:text]}") - raise Mastodon::ValidationError, I18n.t('statuses.too_many_hashtags') if Admin::NgWord.hashtag_reject_with_extractor?(@options[:text]) + raise Mastodon::ValidationError, I18n.t('statuses.too_many_hashtags') if Admin::NgWord.hashtag_reject_with_extractor?(@options[:text] || '') + raise Mastodon::ValidationError, I18n.t('statuses.too_many_mentions') if Admin::NgWord.mention_reject_with_extractor?(@options[:text] || '') end def validate_status_mentions! diff --git a/app/views/admin/ng_words/show.html.haml b/app/views/admin/ng_words/show.html.haml index 8b7c943f64dd94..5af34cb80a0bda 100644 --- a/app/views/admin/ng_words/show.html.haml +++ b/app/views/admin/ng_words/show.html.haml @@ -23,6 +23,9 @@ .fields-group = f.input :post_hash_tags_max, wrapper: :with_label, as: :integer, label: t('admin.ng_words.post_hash_tags_max') + .fields-group + = f.input :post_mentions_max, wrapper: :with_label, as: :integer, label: t('admin.ng_words.post_mentions_max') + .fields-group = f.input :hide_local_users_for_anonymous, wrapper: :with_label, as: :boolean, label: t('admin.ng_words.hide_local_users_for_anonymous') diff --git a/config/locales/en.yml b/config/locales/en.yml index 7978e4eb24f97c..da882712525a4d 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -648,6 +648,7 @@ en: keywords_for_stranger_mention_hint: 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 + post_mentions_max: Mentions max for posts stranger_mention_from_local_ng: フォローしていないアカウントへのメンションのNGワードを、ローカルユーザーによる投稿にも適用する stranger_mention_from_local_ng_hint: サーバーの登録が承認制でない場合、あなたのサーバーにもスパムが入り込む可能性があります test_error: Testing is returned any errors @@ -1941,6 +1942,7 @@ en: show_thread: Show thread title: '%{name}: "%{quote}"' too_many_hashtags: Too many hashtags + too_many_mentions: Too many mentions visibilities: direct: Direct login: Login only diff --git a/config/locales/ja.yml b/config/locales/ja.yml index e44b0041e42650..d5eccff6d5a362 100644 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@ -641,6 +641,7 @@ ja: keywords_for_stranger_mention_hint: フォローしていないアカウントへのメンション、参照、引用にのみ適用されます keywords_hint: 行を「?」で始めると、正規表現が使えます post_hash_tags_max: 投稿に設定可能なハッシュタグの最大数 + post_mentions_max: 投稿に設定可能なメンションの最大数 stranger_mention_from_local_ng: フォローしていないアカウントへのメンションのNGワードを、ローカルユーザーによる投稿にも適用する stranger_mention_from_local_ng_hint: サーバーの登録が承認制でない場合、あなたのサーバーにもスパムが入り込む可能性があります test_error: NGワードのテストに失敗しました。正規表現のミスが含まれているかもしれません @@ -1914,6 +1915,7 @@ ja: show_thread: スレッドを表示 title: '%{name}: "%{quote}"' too_many_hashtags: ハッシュタグが多すぎます + too_many_mentions: メンションが多すぎます visibilities: direct: ダイレクト login: ログインユーザーのみ diff --git a/spec/lib/activitypub/activity/create_spec.rb b/spec/lib/activitypub/activity/create_spec.rb index 36a39f905cd97c..53662d0bf4f7c1 100644 --- a/spec/lib/activitypub/activity/create_spec.rb +++ b/spec/lib/activitypub/activity/create_spec.rb @@ -2066,6 +2066,47 @@ def activity_for_object(json) end end end + + context 'when mentions limit is set' do + let(:post_mentions_max) { 2 } + let(:custom_before) { true } + let(:object_json) do + { + id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join, + type: 'Note', + content: 'Lorem ipsum', + tag: [ + { + type: 'Mention', + href: ActivityPub::TagManager.instance.uri_for(Fabricate(:account)), + }, + { + type: 'Mention', + href: ActivityPub::TagManager.instance.uri_for(Fabricate(:account)), + }, + ], + } + end + + before do + Form::AdminSettings.new(post_mentions_max: post_mentions_max).save + subject.perform + end + + context 'when limit is enough' do + it 'creates status' do + expect(sender.statuses.first).to_not be_nil + end + end + + context 'when limit is over' do + let(:post_mentions_max) { 1 } + + it 'creates status' do + expect(sender.statuses.first).to be_nil + end + end + end end context 'when object URI uses bearcaps' do diff --git a/spec/services/post_status_service_spec.rb b/spec/services/post_status_service_spec.rb index c8c8a30c7b945b..e7fa1a8ddfeb61 100644 --- a/spec/services/post_status_service_spec.rb +++ b/spec/services/post_status_service_spec.rb @@ -740,6 +740,29 @@ expect { subject.call(account, text: text) }.to raise_error Mastodon::ValidationError end + + it 'using mentions under limit' do + Fabricate(:account, username: 'a') + Fabricate(:account, username: 'b') + account = Fabricate(:account) + text = '@a @b' + Form::AdminSettings.new(post_mentions_max: 2).save + + status = subject.call(account, text: text) + + expect(status).to be_persisted + expect(status.text).to eq text + end + + it 'using mentions over limit' do + Fabricate(:account, username: 'a') + Fabricate(:account, username: 'b') + account = Fabricate(:account) + text = '@a @b' + Form::AdminSettings.new(post_mentions_max: 1).save + + expect { subject.call(account, text: text) }.to raise_error Mastodon::ValidationError + end end def create_status_with_options(**options)