Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add: #605 リモート投稿に適用するセンシティブワード設定 #612

Merged
merged 2 commits into from
Feb 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion app/controllers/admin/sensitive_words_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
9 changes: 9 additions & 0 deletions app/lib/activitypub/activity/create.rb
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ def process_status
@raw_mention_uris = []

process_status_params
process_sensitive_words
process_tags
process_audience

Expand Down Expand Up @@ -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?
Expand Down
19 changes: 18 additions & 1 deletion app/models/admin/sensitive_word.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
Expand All @@ -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
5 changes: 5 additions & 0 deletions app/models/form/admin_settings.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
10 changes: 10 additions & 0 deletions app/services/activitypub/process_status_update_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -210,13 +210,23 @@ 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?

@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 = []
Expand Down
3 changes: 2 additions & 1 deletion app/services/post_status_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
3 changes: 2 additions & 1 deletion app/services/update_status_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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!
Expand Down
9 changes: 9 additions & 0 deletions app/views/admin/sensitive_words/show.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -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
10 changes: 7 additions & 3 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
10 changes: 7 additions & 3 deletions config/locales/ja.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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: センシティブ単語と設定
Expand Down
39 changes: 39 additions & 0 deletions spec/lib/activitypub/activity/create_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand Down
39 changes: 38 additions & 1 deletion spec/services/activitypub/process_status_update_service_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand All @@ -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
Loading