From 9dd11117dbdd1de4291bbda84e2a40f691eba973 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: Tue, 27 Feb 2024 10:14:42 +0900 Subject: [PATCH] =?UTF-8?q?Add:=20#605=20=E3=83=AA=E3=83=A2=E3=83=BC?= =?UTF-8?q?=E3=83=88=E6=8A=95=E7=A8=BF=E3=81=AB=E9=81=A9=E7=94=A8=E3=81=99?= =?UTF-8?q?=E3=82=8B=E3=82=BB=E3=83=B3=E3=82=B7=E3=83=86=E3=82=A3=E3=83=96?= =?UTF-8?q?=E3=83=AF=E3=83=BC=E3=83=89=E8=A8=AD=E5=AE=9A=20(#612)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/sensitive_words_controller.rb | 4 +- app/lib/activitypub/activity/create.rb | 9 +++++ app/models/admin/sensitive_word.rb | 19 ++++++++- app/models/form/admin_settings.rb | 5 +++ .../process_status_update_service.rb | 10 +++++ app/services/post_status_service.rb | 3 +- app/services/update_status_service.rb | 3 +- .../admin/sensitive_words/show.html.haml | 9 +++++ config/locales/en.yml | 10 +++-- config/locales/ja.yml | 10 +++-- spec/lib/activitypub/activity/create_spec.rb | 39 +++++++++++++++++++ .../process_status_update_service_spec.rb | 39 ++++++++++++++++++- 12 files changed, 149 insertions(+), 11 deletions(-) diff --git a/app/controllers/admin/sensitive_words_controller.rb b/app/controllers/admin/sensitive_words_controller.rb index eaa6ae802eb3b4..f98fc4202da4ee 100644 --- a/app/controllers/admin/sensitive_words_controller.rb +++ b/app/controllers/admin/sensitive_words_controller.rb @@ -34,7 +34,9 @@ def create def test_words sensitive_words = settings_params['sensitive_words'].split(/\r\n|\r|\n/) sensitive_words_for_full = settings_params['sensitive_words_for_full'].split(/\r\n|\r|\n/) - Admin::NgWord.reject_with_custom_words?('Sample text', sensitive_words + sensitive_words_for_full) + sensitive_words_all = settings_params['sensitive_words_all'].split(/\r\n|\r|\n/) + sensitive_words_all_for_full = settings_params['sensitive_words_all_for_full'].split(/\r\n|\r|\n/) + Admin::NgWord.reject_with_custom_words?('Sample text', sensitive_words + sensitive_words_for_full + sensitive_words_all + sensitive_words_all_for_full) end def after_update_redirect_path diff --git a/app/lib/activitypub/activity/create.rb b/app/lib/activitypub/activity/create.rb index aa112975f4f59f..d59436c0814508 100644 --- a/app/lib/activitypub/activity/create.rb +++ b/app/lib/activitypub/activity/create.rb @@ -81,6 +81,7 @@ def process_status @raw_mention_uris = [] process_status_params + process_sensitive_words process_tags process_audience @@ -144,6 +145,14 @@ def process_status_params } end + def process_sensitive_words + return unless %i(public public_unlisted login).include?(@params[:visibility].to_sym) && Admin::SensitiveWord.sensitive?(@params[:text], @params[:spoiler_text], local: false) + + @params[:text] = Admin::SensitiveWord.modified_text(@params[:text], @params[:spoiler_text]) + @params[:spoiler_text] = Admin::SensitiveWord.alternative_text + @params[:sensitive] = true + end + def valid_status? valid = true valid = false if valid && !valid_status_for_ng_rule? diff --git a/app/models/admin/sensitive_word.rb b/app/models/admin/sensitive_word.rb index ec905fe0759022..8f9421f5b909e1 100644 --- a/app/models/admin/sensitive_word.rb +++ b/app/models/admin/sensitive_word.rb @@ -2,8 +2,13 @@ class Admin::SensitiveWord class << self - def sensitive?(text, spoiler_text) + def sensitive?(text, spoiler_text, local: true) exposure_text = spoiler_text.presence || text + + sensitive = (spoiler_text.blank? && sensitive_words_all.any? { |word| include?(text, word) }) || + sensitive_words_all_for_full.any? { |word| include?(exposure_text, word) } + return sensitive if sensitive || !local + (spoiler_text.blank? && sensitive_words.any? { |word| include?(text, word) }) || sensitive_words_for_full.any? { |word| include?(exposure_text, word) } end @@ -12,6 +17,10 @@ def modified_text(text, spoiler_text) spoiler_text.present? ? "#{spoiler_text}\n\n#{text}" : text end + def alternative_text + Setting.auto_warning_text.presence || I18n.t('admin.sensitive_words.alert') || 'CW' + end + private def include?(text, word) @@ -29,5 +38,13 @@ def sensitive_words def sensitive_words_for_full Setting.sensitive_words_for_full || [] end + + def sensitive_words_all + Setting.sensitive_words_all || [] + end + + def sensitive_words_all_for_full + Setting.sensitive_words_all_for_full || [] + end end end diff --git a/app/models/form/admin_settings.rb b/app/models/form/admin_settings.rb index 99d738d348f62f..8a823fa1b75699 100644 --- a/app/models/form/admin_settings.rb +++ b/app/models/form/admin_settings.rb @@ -53,6 +53,9 @@ class Form::AdminSettings post_stranger_mentions_max sensitive_words sensitive_words_for_full + sensitive_words_all + sensitive_words_all_for_full + auto_warning_text authorized_fetch receive_other_servers_emoji_reaction streaming_other_servers_emoji_reaction @@ -127,6 +130,8 @@ class Form::AdminSettings ng_words_for_stranger_mention sensitive_words sensitive_words_for_full + sensitive_words_all + sensitive_words_all_for_full emoji_reaction_disallow_domains permit_new_account_domains ).freeze diff --git a/app/services/activitypub/process_status_update_service.rb b/app/services/activitypub/process_status_update_service.rb index 19b1fa9ae4e717..f174ae1575172e 100644 --- a/app/services/activitypub/process_status_update_service.rb +++ b/app/services/activitypub/process_status_update_service.rb @@ -210,6 +210,8 @@ def update_immediate_attributes! @status.sensitive = @account.sensitized? || @status_parser.sensitive || false @status.language = @status_parser.language + process_sensitive_words + @significant_changes = text_significantly_changed? || @status.spoiler_text_changed? || @media_attachments_changed || @poll_changed @status.edited_at = @status_parser.edited_at if significant_changes? @@ -217,6 +219,14 @@ def update_immediate_attributes! @status.save! end + def process_sensitive_words + return unless %i(public public_unlisted login).include?(@status.visibility.to_sym) && Admin::SensitiveWord.sensitive?(@status.text, @status.spoiler_text, local: false) + + @status.text = Admin::SensitiveWord.modified_text(@status.text, @status.spoiler_text) + @status.spoiler_text = Admin::SensitiveWord.alternative_text + @status.sensitive = true + end + def read_metadata @raw_tags = [] @raw_mentions = [] diff --git a/app/services/post_status_service.rb b/app/services/post_status_service.rb index fb049946123347..4663b9e6314419 100644 --- a/app/services/post_status_service.rb +++ b/app/services/post_status_service.rb @@ -122,7 +122,8 @@ def overwrite_dtl_post def process_sensitive_words if [:public, :public_unlisted, :login].include?(@visibility&.to_sym) && Admin::SensitiveWord.sensitive?(@text, @options[:spoiler_text] || '') @text = Admin::SensitiveWord.modified_text(@text, @options[:spoiler_text]) - @options[:spoiler_text] = I18n.t('admin.sensitive_words.alert') + @options[:spoiler_text] = Admin::SensitiveWord.alternative_text + @sensitive = true end end diff --git a/app/services/update_status_service.rb b/app/services/update_status_service.rb index e21eab80665315..2a3bf5f179d599 100644 --- a/app/services/update_status_service.rb +++ b/app/services/update_status_service.rb @@ -209,7 +209,8 @@ def process_sensitive_words return unless [:public, :public_unlisted, :login].include?(@status.visibility&.to_sym) && Admin::SensitiveWord.sensitive?(@status.text, @status.spoiler_text || '') @status.text = Admin::SensitiveWord.modified_text(@status.text, @status.spoiler_text) - @status.spoiler_text = I18n.t('admin.sensitive_words.alert') + @status.spoiler_text = Admin::SensitiveWord.alternative_text + @status.sensitive = true end def update_expiration! diff --git a/app/views/admin/sensitive_words/show.html.haml b/app/views/admin/sensitive_words/show.html.haml index dab3e8e1450fa1..746f34f75e8862 100644 --- a/app/views/admin/sensitive_words/show.html.haml +++ b/app/views/admin/sensitive_words/show.html.haml @@ -15,5 +15,14 @@ .fields-group = f.input :sensitive_words, wrapper: :with_label, as: :text, input_html: { rows: 8 }, label: t('admin.sensitive_words.keywords'), hint: t('admin.sensitive_words.keywords_hint') + .fields-group + = f.input :sensitive_words_all_for_full, wrapper: :with_label, as: :text, input_html: { rows: 12 }, label: t('admin.sensitive_words.keywords_all_for_all'), hint: t('admin.sensitive_words.keywords_for_all_hint') + + .fields-group + = f.input :sensitive_words_all, wrapper: :with_label, as: :text, input_html: { rows: 12 }, label: t('admin.sensitive_words.keywords_all'), hint: t('admin.sensitive_words.keywords_hint') + + .fields-group + = f.input :auto_warning_text, wrapper: :with_label, input_html: { placeholder: t('admin.sensitive_words.alert') }, label: t('admin.sensitive_words.auto_warning_text'), hint: t('admin.sensitive_words.auto_warning_text_hint') + .actions = f.button :button, t('generic.save_changes'), type: :submit diff --git a/config/locales/en.yml b/config/locales/en.yml index 3e9223865fb47a..7bf22c1ea27860 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -958,9 +958,13 @@ en: title: Server rules sensitive_words: alert: This post contains sensitive words, so alert added - hint: The sensitive keywords setting is applied to the "Public", "Local Public", and "Logged-in Users Only" public ranges that flow through the local timeline. A mandatory warning text will be added to any post that meets the criteria. - keywords: Sensitive keywords for local posts - keywords_for_all: Sensitive keywords for local posts (Contains CW alert) + auto_warning_text: Custom warning text + auto_warning_text_hint: If not specified, the default warning text is used. + hint: This keywords is applied to public posts only.. + keywords: Sensitive keywords for local only + keywords_all: Sensitive keywords for local+remote + keywords_all_for_all: Sensitive keywords for local+remote (Contains CW alert) + keywords_for_all: Sensitive keywords for local only (Contains CW alert) keywords_for_all_hint: The first character of the line is "?". to use regular expressions title: Sensitive words and moderation options settings: diff --git a/config/locales/ja.yml b/config/locales/ja.yml index a497bdcf248327..005217f1acdc04 100644 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@ -954,9 +954,13 @@ ja: title: サーバーのルール sensitive_words: alert: この投稿にはセンシティブなキーワードが含まれるため、警告文が追加されました - hint: センシティブなキーワードの設定は、ローカルタイムラインを流れる公開範囲「公開」「ローカル公開」「ログインユーザーのみ」に対して適用されます。条件に該当した投稿には強制的に警告文章が追加されます。 - keywords: ローカル投稿のみに適用するセンシティブなキーワード(警告文は除外) - keywords_for_all: ローカル投稿のみに適用するセンシティブなキーワード(警告文にも適用) + auto_warning_text: カスタム警告文 + auto_warning_text_hint: 指定しなかった場合は、各言語のデフォルト警告文が使用されます + hint: センシティブなキーワードの設定は、当サーバーのローカルユーザーによる公開範囲「公開」「ローカル公開」「ログインユーザーのみ」に対して適用されます。 + keywords: ローカルの投稿に適用するセンシティブなキーワード(警告文は除外) + keywords_all: ローカル・リモートの投稿に適用するセンシティブなキーワード(警告文は除外) + keywords_all_for_all: ローカル・リモートの投稿に適用するセンシティブなキーワード(警告文にも適用) + keywords_for_all: ローカルの投稿に適用するセンシティブなキーワード(警告文にも適用) keywords_for_all_hint: ここで指定したキーワードを含む投稿は強制的にCWになります。警告文にも含まれていればCWになります。行が「?」で始まっていれば正規表現が使えます keywords_hint: ここで指定したキーワードを含む投稿は強制的にCWになります。ただし警告文に使用していた場合は無視されます title: センシティブ単語と設定 diff --git a/spec/lib/activitypub/activity/create_spec.rb b/spec/lib/activitypub/activity/create_spec.rb index 4b10224bb6d6cd..1c50156b822404 100644 --- a/spec/lib/activitypub/activity/create_spec.rb +++ b/spec/lib/activitypub/activity/create_spec.rb @@ -2087,6 +2087,45 @@ def activity_for_object(json) end end + context 'when sensitive word is set' do + let(:custom_before) { true } + let(:content) { 'Lorem ipsum' } + let(:sensitive_words_all) { 'hello' } + let(:object_json) do + { + id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join, + type: 'Note', + content: content, + to: 'https://www.w3.org/ns/activitystreams#Public', + } + end + + before do + Form::AdminSettings.new(sensitive_words_all: sensitive_words_all, sensitive_words: 'ipsum').save + subject.perform + end + + context 'when not contains sensitive words' do + it 'creates status' do + status = sender.statuses.first + + expect(status).to_not be_nil + expect(status.spoiler_text).to eq '' + end + end + + context 'when contains sensitive words' do + let(:content) { 'hello world' } + + it 'creates status' do + status = sender.statuses.first + + expect(status).to_not be_nil + expect(status.spoiler_text).to_not eq '' + end + end + end + context 'when hashtags limit is set' do let(:post_hash_tags_max) { 2 } let(:custom_before) { true } diff --git a/spec/services/activitypub/process_status_update_service_spec.rb b/spec/services/activitypub/process_status_update_service_spec.rb index 232dff2962873b..9a02b500d2d62a 100644 --- a/spec/services/activitypub/process_status_update_service_spec.rb +++ b/spec/services/activitypub/process_status_update_service_spec.rb @@ -682,7 +682,7 @@ def poll_option_json(name, votes) end end - context 'when ng rule is existing' do + describe 'ng rule is set' do context 'when ng rule is match' do before do Fabricate(:ng_rule, account_domain: 'example.com', status_text: 'universe') @@ -707,5 +707,42 @@ def poll_option_json(name, votes) end end end + + describe 'sensitive word is set' do + let(:payload) do + { + '@context': 'https://www.w3.org/ns/activitystreams', + id: 'foo', + type: 'Note', + content: content, + updated: '2021-09-08T22:39:25Z', + tag: json_tags, + } + end + + context 'when hit sensitive words' do + let(:content) { 'ng word aiueo' } + + it 'update status' do + Form::AdminSettings.new(sensitive_words_all: 'test').save + + subject.call(status, json, json) + expect(status.reload.text).to eq content + expect(status.spoiler_text).to eq '' + end + end + + context 'when not hit sensitive words' do + let(:content) { 'ng word test' } + + it 'update status' do + Form::AdminSettings.new(sensitive_words_all: 'test').save + + subject.call(status, json, json) + expect(status.reload.text).to eq content + expect(status.spoiler_text).to_not eq '' + end + end + end end end