parent
7d96d5828e
commit
9dd11117db
12 changed files with 149 additions and 11 deletions
|
@ -34,7 +34,9 @@ module Admin
|
||||||
def test_words
|
def test_words
|
||||||
sensitive_words = settings_params['sensitive_words'].split(/\r\n|\r|\n/)
|
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/)
|
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
|
end
|
||||||
|
|
||||||
def after_update_redirect_path
|
def after_update_redirect_path
|
||||||
|
|
|
@ -81,6 +81,7 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
|
||||||
@raw_mention_uris = []
|
@raw_mention_uris = []
|
||||||
|
|
||||||
process_status_params
|
process_status_params
|
||||||
|
process_sensitive_words
|
||||||
process_tags
|
process_tags
|
||||||
process_audience
|
process_audience
|
||||||
|
|
||||||
|
@ -144,6 +145,14 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
|
||||||
}
|
}
|
||||||
end
|
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?
|
def valid_status?
|
||||||
valid = true
|
valid = true
|
||||||
valid = false if valid && !valid_status_for_ng_rule?
|
valid = false if valid && !valid_status_for_ng_rule?
|
||||||
|
|
|
@ -2,8 +2,13 @@
|
||||||
|
|
||||||
class Admin::SensitiveWord
|
class Admin::SensitiveWord
|
||||||
class << self
|
class << self
|
||||||
def sensitive?(text, spoiler_text)
|
def sensitive?(text, spoiler_text, local: true)
|
||||||
exposure_text = spoiler_text.presence || text
|
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) }) ||
|
(spoiler_text.blank? && sensitive_words.any? { |word| include?(text, word) }) ||
|
||||||
sensitive_words_for_full.any? { |word| include?(exposure_text, word) }
|
sensitive_words_for_full.any? { |word| include?(exposure_text, word) }
|
||||||
end
|
end
|
||||||
|
@ -12,6 +17,10 @@ class Admin::SensitiveWord
|
||||||
spoiler_text.present? ? "#{spoiler_text}\n\n#{text}" : text
|
spoiler_text.present? ? "#{spoiler_text}\n\n#{text}" : text
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def alternative_text
|
||||||
|
Setting.auto_warning_text.presence || I18n.t('admin.sensitive_words.alert') || 'CW'
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def include?(text, word)
|
def include?(text, word)
|
||||||
|
@ -29,5 +38,13 @@ class Admin::SensitiveWord
|
||||||
def sensitive_words_for_full
|
def sensitive_words_for_full
|
||||||
Setting.sensitive_words_for_full || []
|
Setting.sensitive_words_for_full || []
|
||||||
end
|
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
|
||||||
end
|
end
|
||||||
|
|
|
@ -53,6 +53,9 @@ class Form::AdminSettings
|
||||||
post_stranger_mentions_max
|
post_stranger_mentions_max
|
||||||
sensitive_words
|
sensitive_words
|
||||||
sensitive_words_for_full
|
sensitive_words_for_full
|
||||||
|
sensitive_words_all
|
||||||
|
sensitive_words_all_for_full
|
||||||
|
auto_warning_text
|
||||||
authorized_fetch
|
authorized_fetch
|
||||||
receive_other_servers_emoji_reaction
|
receive_other_servers_emoji_reaction
|
||||||
streaming_other_servers_emoji_reaction
|
streaming_other_servers_emoji_reaction
|
||||||
|
@ -127,6 +130,8 @@ class Form::AdminSettings
|
||||||
ng_words_for_stranger_mention
|
ng_words_for_stranger_mention
|
||||||
sensitive_words
|
sensitive_words
|
||||||
sensitive_words_for_full
|
sensitive_words_for_full
|
||||||
|
sensitive_words_all
|
||||||
|
sensitive_words_all_for_full
|
||||||
emoji_reaction_disallow_domains
|
emoji_reaction_disallow_domains
|
||||||
permit_new_account_domains
|
permit_new_account_domains
|
||||||
).freeze
|
).freeze
|
||||||
|
|
|
@ -210,6 +210,8 @@ class ActivityPub::ProcessStatusUpdateService < BaseService
|
||||||
@status.sensitive = @account.sensitized? || @status_parser.sensitive || false
|
@status.sensitive = @account.sensitized? || @status_parser.sensitive || false
|
||||||
@status.language = @status_parser.language
|
@status.language = @status_parser.language
|
||||||
|
|
||||||
|
process_sensitive_words
|
||||||
|
|
||||||
@significant_changes = text_significantly_changed? || @status.spoiler_text_changed? || @media_attachments_changed || @poll_changed
|
@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.edited_at = @status_parser.edited_at if significant_changes?
|
||||||
|
@ -217,6 +219,14 @@ class ActivityPub::ProcessStatusUpdateService < BaseService
|
||||||
@status.save!
|
@status.save!
|
||||||
end
|
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
|
def read_metadata
|
||||||
@raw_tags = []
|
@raw_tags = []
|
||||||
@raw_mentions = []
|
@raw_mentions = []
|
||||||
|
|
|
@ -122,7 +122,8 @@ class PostStatusService < BaseService
|
||||||
def process_sensitive_words
|
def process_sensitive_words
|
||||||
if [:public, :public_unlisted, :login].include?(@visibility&.to_sym) && Admin::SensitiveWord.sensitive?(@text, @options[:spoiler_text] || '')
|
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])
|
@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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -209,7 +209,8 @@ class UpdateStatusService < BaseService
|
||||||
return unless [:public, :public_unlisted, :login].include?(@status.visibility&.to_sym) && Admin::SensitiveWord.sensitive?(@status.text, @status.spoiler_text || '')
|
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.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
|
end
|
||||||
|
|
||||||
def update_expiration!
|
def update_expiration!
|
||||||
|
|
|
@ -15,5 +15,14 @@
|
||||||
.fields-group
|
.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')
|
= 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
|
.actions
|
||||||
= f.button :button, t('generic.save_changes'), type: :submit
|
= f.button :button, t('generic.save_changes'), type: :submit
|
||||||
|
|
|
@ -958,9 +958,13 @@ en:
|
||||||
title: Server rules
|
title: Server rules
|
||||||
sensitive_words:
|
sensitive_words:
|
||||||
alert: This post contains sensitive words, so alert added
|
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.
|
auto_warning_text: Custom warning text
|
||||||
keywords: Sensitive keywords for local posts
|
auto_warning_text_hint: If not specified, the default warning text is used.
|
||||||
keywords_for_all: Sensitive keywords for local posts (Contains CW alert)
|
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
|
keywords_for_all_hint: The first character of the line is "?". to use regular expressions
|
||||||
title: Sensitive words and moderation options
|
title: Sensitive words and moderation options
|
||||||
settings:
|
settings:
|
||||||
|
|
|
@ -954,9 +954,13 @@ ja:
|
||||||
title: サーバーのルール
|
title: サーバーのルール
|
||||||
sensitive_words:
|
sensitive_words:
|
||||||
alert: この投稿にはセンシティブなキーワードが含まれるため、警告文が追加されました
|
alert: この投稿にはセンシティブなキーワードが含まれるため、警告文が追加されました
|
||||||
hint: センシティブなキーワードの設定は、ローカルタイムラインを流れる公開範囲「公開」「ローカル公開」「ログインユーザーのみ」に対して適用されます。条件に該当した投稿には強制的に警告文章が追加されます。
|
auto_warning_text: カスタム警告文
|
||||||
keywords: ローカル投稿のみに適用するセンシティブなキーワード(警告文は除外)
|
auto_warning_text_hint: 指定しなかった場合は、各言語のデフォルト警告文が使用されます
|
||||||
keywords_for_all: ローカル投稿のみに適用するセンシティブなキーワード(警告文にも適用)
|
hint: センシティブなキーワードの設定は、当サーバーのローカルユーザーによる公開範囲「公開」「ローカル公開」「ログインユーザーのみ」に対して適用されます。
|
||||||
|
keywords: ローカルの投稿に適用するセンシティブなキーワード(警告文は除外)
|
||||||
|
keywords_all: ローカル・リモートの投稿に適用するセンシティブなキーワード(警告文は除外)
|
||||||
|
keywords_all_for_all: ローカル・リモートの投稿に適用するセンシティブなキーワード(警告文にも適用)
|
||||||
|
keywords_for_all: ローカルの投稿に適用するセンシティブなキーワード(警告文にも適用)
|
||||||
keywords_for_all_hint: ここで指定したキーワードを含む投稿は強制的にCWになります。警告文にも含まれていればCWになります。行が「?」で始まっていれば正規表現が使えます
|
keywords_for_all_hint: ここで指定したキーワードを含む投稿は強制的にCWになります。警告文にも含まれていればCWになります。行が「?」で始まっていれば正規表現が使えます
|
||||||
keywords_hint: ここで指定したキーワードを含む投稿は強制的にCWになります。ただし警告文に使用していた場合は無視されます
|
keywords_hint: ここで指定したキーワードを含む投稿は強制的にCWになります。ただし警告文に使用していた場合は無視されます
|
||||||
title: センシティブ単語と設定
|
title: センシティブ単語と設定
|
||||||
|
|
|
@ -2087,6 +2087,45 @@ RSpec.describe ActivityPub::Activity::Create do
|
||||||
end
|
end
|
||||||
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
|
context 'when hashtags limit is set' do
|
||||||
let(:post_hash_tags_max) { 2 }
|
let(:post_hash_tags_max) { 2 }
|
||||||
let(:custom_before) { true }
|
let(:custom_before) { true }
|
||||||
|
|
|
@ -682,7 +682,7 @@ RSpec.describe ActivityPub::ProcessStatusUpdateService, type: :service do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when ng rule is existing' do
|
describe 'ng rule is set' do
|
||||||
context 'when ng rule is match' do
|
context 'when ng rule is match' do
|
||||||
before do
|
before do
|
||||||
Fabricate(:ng_rule, account_domain: 'example.com', status_text: 'universe')
|
Fabricate(:ng_rule, account_domain: 'example.com', status_text: 'universe')
|
||||||
|
@ -707,5 +707,42 @@ RSpec.describe ActivityPub::ProcessStatusUpdateService, type: :service do
|
||||||
end
|
end
|
||||||
end
|
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
|
||||||
end
|
end
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue