From 2a043237fb36c134b061b97b8f625c5e733cac9c Mon Sep 17 00:00:00 2001 From: KMY Date: Sun, 3 Sep 2023 11:06:00 +0900 Subject: [PATCH 01/11] Fix some setting messages --- app/views/settings/privacy_extra/show.html.haml | 2 +- config/locales/ja.yml | 4 ++-- config/locales/simple_form.ja.yml | 3 ++- yarn.lock | 11 +++++++++++ 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/app/views/settings/privacy_extra/show.html.haml b/app/views/settings/privacy_extra/show.html.haml index 53c11f9cdd..c9ccd03013 100644 --- a/app/views/settings/privacy_extra/show.html.haml +++ b/app/views/settings/privacy_extra/show.html.haml @@ -19,7 +19,7 @@ = ff.input :translatable_private, wrapper: :with_label, kmyblue: true, label: I18n.t('simple_form.labels.defaults.setting_translatable_private') .fields-group - = ff.input :link_preview, wrapper: :with_label, kmyblue: true, label: I18n.t('simple_form.labels.defaults.setting_link_preview') + = ff.input :link_preview, wrapper: :with_label, kmyblue: true, label: I18n.t('simple_form.labels.defaults.setting_link_preview'), hint: I18n.t('simple_form.hints.defaults.setting_link_preview') %h4= t 'privacy_extra.stop_deliver' diff --git a/config/locales/ja.yml b/config/locales/ja.yml index 3a88918add..db29718139 100644 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@ -1594,10 +1594,10 @@ ja: search_hint_html: Control how you want to be found. Do you want people to find you by what you've publicly posted about? Do you want people outside Mastodon to find your profile when searching the web? Please mind that total exclusion from all search engines cannot be guaranteed for public information. title: Privacy and reach privacy_extra: - hint_html: これらはkmyblue独自のプライバシー設定項目です。この機能を利用することで、あなたは追加の恩恵を受けることができます。なおこれらの設定の一部は他のサーバーにも送信されますが、kmyblue以外で対応が確認されているソフトウェアは現在確認できていません。他のサーバーではこれらの設定は無視されること、ご了承ください。 + hint_html: これらはkmyblue独自のプライバシー設定項目です。この機能を利用することで、あなたは追加の恩恵を受けることができます。なおこれらの設定の一部は他のサーバーにも送信されますが、kmyblue以外で対応するソフトウェアは現在確認できていません。他のサーバーではこれらの設定は無視されること、ご了承ください。 post_processing_hint_html: 投稿された情報に対して、システムが追加で行うことができる操作を制御します。これらには、第三者のサイトへあなたの投稿に関する情報の送信を伴う設定も含まれます。 post_processing: 投稿の処理 - stop_deliver: 配送停止 + stop_deliver: 配送制限 stop_deliver_hint_html: Mastodonの投稿を、他のソフトウェアでは自由に検索することができます。Mastodon内で行ったプライバシーの設定は無視され、あなたの投稿が意図しない人に見つかるおそれがあります。ここでは、他のサーバーやソフトウェアであなたの投稿が見つからないようにする設定が可能です。ただしリスクは伴います。 title: プライバシー追加設定 privacy_policy: diff --git a/config/locales/simple_form.ja.yml b/config/locales/simple_form.ja.yml index a1c5c825a7..36a9628bae 100644 --- a/config/locales/simple_form.ja.yml +++ b/config/locales/simple_form.ja.yml @@ -65,11 +65,12 @@ ja: setting_default_sensitive: 閲覧注意状態のメディアはデフォルトでは内容が伏せられ、クリックして初めて閲覧できるようになります setting_disallow_unlisted_public_searchability: この設定を有効にすると、未収載投稿と検索範囲「全て」は両立できず不特定多数からの検索が不可になります。Fedibirdと同じ挙動になります setting_display_media_default: 閲覧注意としてマークされたメディアは隠す + setting_display_media_expand: Misskeyなどは4個を超えて投稿可能です。その追加分を最大16個まで表示します。kmyblueからアップロードはできません setting_display_media_hide_all: メディアを常に隠す setting_display_media_show_all: メディアを常に表示する setting_emoji_reaction_streaming_notify_impl2: 当該サーバーの独自機能に対応したアプリを利用時に、スタンプ機能を利用できます。動作確認していないため(そもそもそのようなアプリ自体を確認できていないため)正しく動かない場合があります setting_hide_network: フォローとフォロワーの情報がプロフィールページで見られないようにします - setting_display_media_expand: Misskeyなどは4個を超えて投稿可能です。その追加分を最大16個まで表示します。kmyblueからアップロードはできません + setting_link_preview: プレビュー生成を停止することは、センシティブなサイトへのリンクを頻繁に投稿する人にも有効かもしれません setting_noai: AI学習への利用を禁止するメタタグをプロフィールページに追加します。ただし実効性があるとは限りません setting_public_post_to_unlisted: 未対応のサードパーティアプリからもローカル公開で投稿できますが、公開投稿はWeb以外できなくなります setting_reject_unlisted_subscription: Misskeyやそのフォーク(Calckeyなど)は、フォローしていないアカウントの「未収載」投稿を **購読・検索** することができます。これはkmyblueの挙動と異なります。そのようなサーバーに、指定した公開範囲の投稿を「フォロワーのみ」として配送します。ただし構造上、完璧な対応は困難でたまに未収載として配信されること、ご理解ください diff --git a/yarn.lock b/yarn.lock index 2ffc5b1c45..258809b68b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8115,6 +8115,11 @@ lodash.debounce@^4.0.8: resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow== +lodash.defaults@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" + integrity sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ== + lodash.escape@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/lodash.escape/-/lodash.escape-4.0.1.tgz#c9044690c21e04294beaa517712fded1fa88de98" @@ -8140,6 +8145,11 @@ lodash.invokemap@^4.6.0: resolved "https://registry.yarnpkg.com/lodash.invokemap/-/lodash.invokemap-4.6.0.tgz#1748cda5d8b0ef8369c4eb3ec54c21feba1f2d62" integrity sha512-CfkycNtMqgUlfjfdh2BhKO/ZXrP8ePOX5lEU/g0R3ItJcnuxWDwokMGKx1hWcfOikmyOVx6X9IwWnDGlgKl61w== +lodash.isarguments@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" + integrity sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg== + lodash.isboolean@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" @@ -11420,6 +11430,7 @@ stringz@^2.1.0: char-regex "^1.0.2" "strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: + name strip-ansi-cjs version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== From f250353fd2feff863489f12020356d23ee6a6491 Mon Sep 17 00:00:00 2001 From: KMY Date: Sun, 3 Sep 2023 22:21:19 +0900 Subject: [PATCH 02/11] Fix search error --- app/lib/search_query_transformer.rb | 2 +- yarn.lock | 10 ---------- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/app/lib/search_query_transformer.rb b/app/lib/search_query_transformer.rb index 8ab60405df..6f85234cc8 100644 --- a/app/lib/search_query_transformer.rb +++ b/app/lib/search_query_transformer.rb @@ -54,7 +54,7 @@ class SearchQueryTransformer < Parslet::Transform def to_query # { multi_match: { type: 'most_fields', query: @term, fields: ['text', 'text.stemmed'], operator: 'and' } } - { match_phrase: { text: { query: @phrase } } } + { match_phrase: { text: { query: @term } } } end end diff --git a/yarn.lock b/yarn.lock index 258809b68b..5d4c0ba40f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8115,11 +8115,6 @@ lodash.debounce@^4.0.8: resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow== -lodash.defaults@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" - integrity sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ== - lodash.escape@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/lodash.escape/-/lodash.escape-4.0.1.tgz#c9044690c21e04294beaa517712fded1fa88de98" @@ -8145,11 +8140,6 @@ lodash.invokemap@^4.6.0: resolved "https://registry.yarnpkg.com/lodash.invokemap/-/lodash.invokemap-4.6.0.tgz#1748cda5d8b0ef8369c4eb3ec54c21feba1f2d62" integrity sha512-CfkycNtMqgUlfjfdh2BhKO/ZXrP8ePOX5lEU/g0R3ItJcnuxWDwokMGKx1hWcfOikmyOVx6X9IwWnDGlgKl61w== -lodash.isarguments@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" - integrity sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg== - lodash.isboolean@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" From 1a11680704f1110a19c501aaf5d81bf8d3e6d8e2 Mon Sep 17 00:00:00 2001 From: KMY Date: Sun, 3 Sep 2023 22:33:43 +0900 Subject: [PATCH 03/11] Remove google ad tags --- app/views/layouts/application.html.haml | 9 --------- config/initializers/content_security_policy.rb | 11 ++--------- 2 files changed, 2 insertions(+), 18 deletions(-) diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index c3bf00b675..4fe2f18bfb 100755 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -38,15 +38,6 @@ = yield :header_tags - %script{ 'src' => "https://www.googletagmanager.com/gtag/js?id=AW-11130587137", 'async' => true } - - :javascript - window.dataLayer = window.dataLayer || []; - function gtag(){dataLayer.push(arguments);} - gtag('js', new Date()); - - gtag('config', 'AW-11130587137'); - %body{ class: body_classes } = content_for?(:content) ? yield(:content) : yield diff --git a/config/initializers/content_security_policy.rb b/config/initializers/content_security_policy.rb index b4f26c9567..59ac3bdea2 100644 --- a/config/initializers/content_security_policy.rb +++ b/config/initializers/content_security_policy.rb @@ -19,13 +19,6 @@ media_host ||= host_to_url(ENV['AZURE_ALIAS_HOST']) media_host ||= host_to_url(ENV['S3_HOSTNAME']) if ENV['S3_ENABLED'] == 'true' media_host ||= assets_host -google_host = 'https://www.googletagmanager.com' -google_host2 = 'https://googleads.g.doubleclick.net' -google_host3 = 'https://www.googleadservices.com' -google_host4 = 'https://www.google.co.jp' -google_host5 = 'https://www.google.com' -google_tag_script_hash = "'sha256-CS1WvLDd3zJOdxpEk+N+VigcWMa6V345p2HS0WYiFWE='" - Rails.application.config.content_security_policy do |p| p.base_uri :none p.default_src :none @@ -45,10 +38,10 @@ Rails.application.config.content_security_policy do |p| webpacker_urls = %w(ws http).map { |protocol| "#{protocol}#{Webpacker.dev_server.https? ? 's' : ''}://#{webpacker_public_host}" } p.connect_src :self, :data, :blob, assets_host, media_host, Rails.configuration.x.streaming_api_base_url, *webpacker_urls - p.script_src :self, :unsafe_inline, :unsafe_eval, assets_host, google_host, google_host2, google_host3 + p.script_src :self, :unsafe_inline, :unsafe_eval, assets_host else p.connect_src :self, :data, :blob, assets_host, media_host, Rails.configuration.x.streaming_api_base_url - p.script_src :self, assets_host, "'wasm-unsafe-eval'", google_host, google_host2, google_host3, google_host4, google_host5, google_tag_script_hash + p.script_src :self, assets_host, "'wasm-unsafe-eval'" end end From 43144661ea17a59a4396e96d71d50de4a6f44a7a Mon Sep 17 00:00:00 2001 From: KMY Date: Sun, 3 Sep 2023 22:35:37 +0900 Subject: [PATCH 04/11] Fix test --- spec/requests/content_security_policy_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/requests/content_security_policy_spec.rb b/spec/requests/content_security_policy_spec.rb index 7563e75fd2..7eb27d61d6 100644 --- a/spec/requests/content_security_policy_spec.rb +++ b/spec/requests/content_security_policy_spec.rb @@ -21,7 +21,7 @@ describe 'Content-Security-Policy' do "child-src 'self' blob: https://cb6e6126.ngrok.io", "worker-src 'self' blob: https://cb6e6126.ngrok.io", "connect-src 'self' data: blob: https://cb6e6126.ngrok.io https://cb6e6126.ngrok.io ws://localhost:4000", - "script-src 'self' https://cb6e6126.ngrok.io 'wasm-unsafe-eval' https://www.googletagmanager.com https://googleads.g.doubleclick.net https://www.googleadservices.com https://www.google.co.jp https://www.google.com 'sha256-CS1WvLDd3zJOdxpEk+N+VigcWMa6V345p2HS0WYiFWE='" + "script-src 'self' https://cb6e6126.ngrok.io 'wasm-unsafe-eval'" ) end end From 7a0bf2e9483cd1f071c4dc6289a20841d1052a3c Mon Sep 17 00:00:00 2001 From: KMY Date: Mon, 4 Sep 2023 12:07:29 +0900 Subject: [PATCH 05/11] Add extended domain block tests --- app/lib/activitypub/activity/create.rb | 32 +++++--- .../lib/activitypub/activity/announce_spec.rb | 16 ++++ spec/lib/activitypub/activity/create_spec.rb | 77 ++++++++++++++++++- spec/lib/activitypub/activity/follow_spec.rb | 31 +++++++- spec/lib/activitypub/activity/like_spec.rb | 28 ++++++- spec/lib/status_reach_finder_spec.rb | 62 +++++++++++++++ 6 files changed, 231 insertions(+), 15 deletions(-) diff --git a/app/lib/activitypub/activity/create.rb b/app/lib/activitypub/activity/create.rb index a27a19418a..b4a5b3f23d 100644 --- a/app/lib/activitypub/activity/create.rb +++ b/app/lib/activitypub/activity/create.rb @@ -48,8 +48,6 @@ class ActivityPub::Activity::Create < ActivityPub::Activity def create_status return reject_payload! if unsupported_object_type? || non_matching_uri_hosts?(@account.uri, object_uri) || tombstone_exists? || !related_to_local_activity? - return reject_payload! if (reply_to_local? || reply_to_local_account?) && reject_reply_to_local? - return reject_payload! if (!reply_to_local_account_following? || !reply_to_local_status_following?) && reject_reply_exclude_followers? with_redis_lock("create:#{object_uri}") do return if delete_arrived_first?(object_uri) || poll_vote? @@ -63,7 +61,7 @@ class ActivityPub::Activity::Create < ActivityPub::Activity end end - @status + @status || reject_payload! end def audience_to @@ -90,7 +88,9 @@ class ActivityPub::Activity::Create < ActivityPub::Activity process_tags process_audience - return unless valid_status? + return nil unless valid_status? + return nil if (reply_to_local? || reply_to_local_account? || reply_to_local_from_tags?) && reject_reply_to_local? + return nil if (!reply_to_local_account_following? || !reply_to_local_status_following? || !reply_to_local_from_tags_following?) && reject_reply_exclude_followers? ApplicationRecord.transaction do @status = Status.create!(@params) @@ -148,14 +148,6 @@ class ActivityPub::Activity::Create < ActivityPub::Activity !Admin::NgWord.reject?("#{@params[:spoiler_text]}\n#{@params[:text]}") && !Admin::NgWord.hashtag_reject?(@tags.size) end - def reply_to_local_account? - accounts_in_audience.any?(&:local?) - end - - def reply_to_local_account_following? - !reply_to_local_account? || accounts_in_audience.none? { |account| account.local? && !account.following?(@account) } - end - def accounts_in_audience return @accounts_in_audience if @accounts_in_audience @@ -420,6 +412,22 @@ class ActivityPub::Activity::Create < ActivityPub::Activity @skip_download ||= DomainBlock.reject_media?(@account.domain) end + def reply_to_local_account? + accounts_in_audience.any?(&:local?) + end + + def reply_to_local_account_following? + !reply_to_local_account? || accounts_in_audience.none? { |account| account.local? && !account.following?(@account) } + end + + def reply_to_local_from_tags? + (@mentions.nil? || @mentions.any? { |m| m.account.local? }) + end + + def reply_to_local_from_tags_following? + (@mentions.nil? || @mentions.none? { |m| m.account.local? && !m.account.following?(@account) }) + end + def reply_to_local? !replied_to_status.nil? && replied_to_status.account.local? end diff --git a/spec/lib/activitypub/activity/announce_spec.rb b/spec/lib/activitypub/activity/announce_spec.rb index 8ad892975d..5e3f679af1 100644 --- a/spec/lib/activitypub/activity/announce_spec.rb +++ b/spec/lib/activitypub/activity/announce_spec.rb @@ -97,6 +97,22 @@ RSpec.describe ActivityPub::Activity::Announce do end end + context 'with domain block' do + before do + Fabricate(:account) + Fabricate(:domain_block, domain: 'example.com', severity: :suspend) + subject.perform + end + + let(:object_json) do + ActivityPub::TagManager.instance.uri_for(status) + end + + it 'does not creates a reblog by sender of status', pending: 'considering spec' do + expect(sender.reblogged?(status)).to be false + end + end + context 'when the status belongs to a local user' do before do subject.perform diff --git a/spec/lib/activitypub/activity/create_spec.rb b/spec/lib/activitypub/activity/create_spec.rb index 354787f820..9c4bba3e62 100644 --- a/spec/lib/activitypub/activity/create_spec.rb +++ b/spec/lib/activitypub/activity/create_spec.rb @@ -29,10 +29,11 @@ RSpec.describe ActivityPub::Activity::Create do subject { described_class.new(json, sender) } let(:sender_software) { 'mastodon' } + let(:custom_before) { false } before do Fabricate(:instance_info, domain: 'example.com', software: sender_software) - subject.perform + subject.perform unless custom_before end context 'when object has been edited' do @@ -648,6 +649,80 @@ RSpec.describe ActivityPub::Activity::Create do end end + context 'with mentions domain block reject_reply' do + before do + Fabricate(:domain_block, domain: 'example.com', severity: :noop, reject_reply: true) + subject.perform + end + + let(:custom_before) { true } + let(:recipient) { Fabricate(:account) } + + 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(recipient), + }, + ], + } + end + + it 'creates status' do + status = sender.statuses.first + + expect(status).to be_nil + end + end + + context 'with mentions domain block reject_reply_exclude_followers' do + before do + Fabricate(:domain_block, domain: 'example.com', severity: :noop, reject_reply_exclude_followers: true) + recipient.follow!(sender) if follow + subject.perform + end + + let(:custom_before) { true } + let(:follow) { false } + let(:recipient) { Fabricate(:account) } + + 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(recipient), + }, + ], + } + end + + context 'when follower' do + let(:follow) { true } + + it 'creates status' do + status = sender.statuses.first + + expect(status).to_not be_nil + end + end + + context 'when not follower' do + it 'creates status' do + status = sender.statuses.first + + expect(status).to be_nil + end + end + end + context 'with media attachments' do let(:object_json) do { diff --git a/spec/lib/activitypub/activity/follow_spec.rb b/spec/lib/activitypub/activity/follow_spec.rb index c1829cb8d7..ee007082a7 100644 --- a/spec/lib/activitypub/activity/follow_spec.rb +++ b/spec/lib/activitypub/activity/follow_spec.rb @@ -3,7 +3,7 @@ require 'rails_helper' RSpec.describe ActivityPub::Activity::Follow do - let(:sender) { Fabricate(:account) } + let(:sender) { Fabricate(:account, domain: 'example.com', inbox_url: 'https://example.com/inbox') } let(:recipient) { Fabricate(:account) } let(:json) do @@ -82,6 +82,35 @@ RSpec.describe ActivityPub::Activity::Follow do expect(sender.follow_requests.find_by(target_account: recipient).uri).to eq 'foo' end end + + context 'when domain block reject_straight_follow' do + before do + Fabricate(:domain_block, domain: 'example.com', reject_straight_follow: true) + subject.perform + end + + it 'does not create a follow from sender to recipient' do + expect(sender.following?(recipient)).to be false + end + + it 'creates a follow request' do + expect(sender.requested?(recipient)).to be true + expect(sender.follow_requests.find_by(target_account: recipient).uri).to eq 'foo' + end + end + + context 'when domain block reject_new_follow' do + before do + Fabricate(:domain_block, domain: 'example.com', reject_new_follow: true) + stub_request(:post, 'https://example.com/inbox').to_return(status: 200, body: '', headers: {}) + subject.perform + end + + it 'does not create a follow from sender to recipient' do + expect(sender.following?(recipient)).to be false + expect(sender.requested?(recipient)).to be false + end + end end context 'when a follow relationship already exists' do diff --git a/spec/lib/activitypub/activity/like_spec.rb b/spec/lib/activitypub/activity/like_spec.rb index 640d61ab36..7635616b16 100644 --- a/spec/lib/activitypub/activity/like_spec.rb +++ b/spec/lib/activitypub/activity/like_spec.rb @@ -3,7 +3,7 @@ require 'rails_helper' RSpec.describe ActivityPub::Activity::Like do - let(:sender) { Fabricate(:account) } + let(:sender) { Fabricate(:account, domain: 'example.com', uri: 'https://example.com/') } let(:recipient) { Fabricate(:account) } let(:status) { Fabricate(:status, account: recipient) } @@ -28,4 +28,30 @@ RSpec.describe ActivityPub::Activity::Like do expect(sender.favourited?(status)).to be true end end + + describe '#perform when domain_block' do + subject { described_class.new(json, sender) } + + before do + Fabricate(:domain_block, domain: 'example.com', severity: :noop, reject_favourite: true) + subject.perform + end + + it 'does not create a favourite from sender to status' do + expect(sender.favourited?(status)).to be false + end + end + + describe '#perform when normal domain_block' do + subject { described_class.new(json, sender) } + + before do + Fabricate(:domain_block, domain: 'example.com', severity: :suspend) + subject.perform + end + + it 'does not create a favourite from sender to status', pending: 'considering spec' do + expect(sender.favourited?(status)).to be false + end + end end diff --git a/spec/lib/status_reach_finder_spec.rb b/spec/lib/status_reach_finder_spec.rb index 0db2666b9e..57946d3a70 100644 --- a/spec/lib/status_reach_finder_spec.rb +++ b/spec/lib/status_reach_finder_spec.rb @@ -154,5 +154,67 @@ describe StatusReachFinder do end end end + + context 'with extended domain block' do + subject do + described_class.new(status) + end + + before do + bob.follow!(alice) + tom.follow!(alice) + Fabricate(:domain_block, domain: 'example.com', severity: 'noop', **properties) + end + + let(:properties) { {} } + let(:visibility) { :public } + let(:searchability) { :public } + let(:dissubscribable) { false } + let(:spoiler_text) { '' } + let(:status) { Fabricate(:status, account: alice, visibility: visibility, searchability: searchability, spoiler_text: spoiler_text) } + let(:alice) { Fabricate(:account, username: 'alice', dissubscribable: dissubscribable) } + let(:bob) { Fabricate(:account, username: 'bob', domain: 'example.com', protocol: :activitypub, uri: 'https://example.com/', inbox_url: 'https://example.com/inbox') } + let(:tom) { Fabricate(:account, username: 'tom', domain: 'tom.com', protocol: :activitypub, uri: 'https://tom.com/', inbox_url: 'https://tom.com/inbox') } + + context 'when reject_send_not_public_searchability' do + let(:properties) { { reject_send_not_public_searchability: true } } + let(:searchability) { :private } + + it 'does not include the inbox of blocked domain' do + expect(subject.inboxes).to_not include 'https://example.com/inbox' + expect(subject.inboxes).to include 'https://tom.com/inbox' + end + end + + context 'when reject_send_public_unlisted' do + let(:properties) { { reject_send_public_unlisted: true } } + let(:visibility) { :public_unlisted } + + it 'does not include the inbox of blocked domain' do + expect(subject.inboxes).to_not include 'https://example.com/inbox' + expect(subject.inboxes).to include 'https://tom.com/inbox' + end + + context 'when reject_send_dissubscribable' do + let(:properties) { { reject_send_dissubscribable: true } } + let(:dissubscribable) { true } + + it 'does not include the inbox of blocked domain' do + expect(subject.inboxes).to_not include 'https://example.com/inbox' + expect(subject.inboxes).to include 'https://tom.com/inbox' + end + end + + context 'when reject_send_sensitive' do + let(:properties) { { reject_send_sensitive: true } } + let(:spoiler_text) { 'CW' } + + it 'does not include the inbox of blocked domain' do + expect(subject.inboxes).to_not include 'https://example.com/inbox' + expect(subject.inboxes).to include 'https://tom.com/inbox' + end + end + end + end end end From adccba6c59ecf0c022eb4a83c1960529b9f4724a Mon Sep 17 00:00:00 2001 From: KMY Date: Mon, 4 Sep 2023 16:46:45 +0900 Subject: [PATCH 06/11] Add detecting unlisted-public post on antenna --- .rubocop.yml | 2 ++ app/services/delivery_antenna_service.rb | 23 ++++++++++--- app/workers/feed_insert_worker.rb | 5 ++- .../services/delivery_antenna_service_spec.rb | 32 +++++++++++++++++-- 4 files changed, 53 insertions(+), 9 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index e022754eab..ef40e95a2a 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -89,6 +89,7 @@ Metrics/CyclomaticComplexity: - 'app/lib/feed_manager.rb' - 'app/policies/status_policy.rb' - 'app/services/activitypub/process_account_service.rb' + - 'app/services/delivery_antenna_service.rb' - 'app/services/post_status_service.rb' - lib/mastodon/cli/*.rb - db/*migrate/**/* @@ -101,6 +102,7 @@ Metrics/ParameterLists: Metrics/PerceivedComplexity: Exclude: - 'app/policies/status_policy.rb' + - 'app/services/delivery_antenna_service.rb' - 'app/services/post_status_service.rb' # Reason: Prevailing style is argument file paths diff --git a/app/services/delivery_antenna_service.rb b/app/services/delivery_antenna_service.rb index 31b61b71e1..3d4f7c0b51 100644 --- a/app/services/delivery_antenna_service.rb +++ b/app/services/delivery_antenna_service.rb @@ -20,6 +20,7 @@ class DeliveryAntennaService def delivery! tag_ids = @status.tags.pluck(:id) domain = @account.domain || Rails.configuration.x.local_domain + follower_ids = @status.unlisted_visibility? ? @status.account.followers.pluck(:id) : [] antennas = Antenna.availables antennas = antennas.left_joins(:antenna_domains).where(any_domains: true).or(Antenna.left_joins(:antenna_domains).where(antenna_domains: { name: domain })) @@ -32,7 +33,7 @@ class DeliveryAntennaService antennas = antennas.left_joins(:antenna_tags).where(any_tags: true).or(Antenna.left_joins(:antenna_tags).where(antenna_tags: { tag_id: tag_ids })) antennas = antennas.where(account_id: Account.without_suspended.joins(:user).select('accounts.id').where('users.current_sign_in_at > ?', User::ACTIVE_DURATION.ago)) - antennas = antennas.where(account: @status.account.followers) if [:public, :public_unlisted, :login, :limited].exclude?(@status.visibility.to_sym) + antennas = antennas.where(account: @status.account.followers) if [:public, :public_unlisted, :login, :limited].exclude?(@status.visibility.to_sym) && !@status.public_searchability? antennas = antennas.where(account: @status.mentioned_accounts) if @status.visibility.to_sym == :limited antennas = antennas.where(with_media_only: false) unless @status.with_media? antennas = antennas.where(ignore_reblog: false) if @status.reblog? @@ -49,6 +50,8 @@ class DeliveryAntennaService next if antenna.exclude_accounts&.include?(@status.account_id) next if antenna.exclude_domains&.include?(domain) next if antenna.exclude_tags&.any? { |tag_id| tag_ids.include?(tag_id) } + next if @status.unlisted_visibility? && !@status.public_searchability? && follower_ids.exclude?(antenna.account_id) + next if @status.unlisted_visibility? && @status.public_searchability? && follower_ids.exclude?(antenna.account_id) && antenna.any_keywords && antenna.any_tags collection.push(antenna) end @@ -84,10 +87,13 @@ class DeliveryAntennaService @stl_home = stl_home @home_account_ids = [] @list_ids = [] + @antenna_timeline_ids = [] end def push(antenna) - if antenna.list_id.zero? + if !antenna.insert_feeds? + @antenna_timeline_ids << { id: antenna.id, antenna_id: antenna.id } + elsif antenna.list_id.zero? @home_account_ids << { id: antenna.account_id, antenna_id: antenna.id } if @home_account_ids.none? { |id| id[:id] == antenna.account_id } elsif @list_ids.none? { |id| id[:id] == antenna.list_id } @list_ids << { id: antenna.list_id, antenna_id: antenna.id } @@ -97,6 +103,7 @@ class DeliveryAntennaService def deliver! lists = @list_ids homes = @home_account_ids + timelines = @antenna_timeline_ids if lists.any? FeedInsertWorker.push_bulk(lists) do |list| @@ -104,10 +111,16 @@ class DeliveryAntennaService end end - return unless homes.any? + if homes.any? + FeedInsertWorker.push_bulk(homes) do |home| + [@status.id, home[:id], 'home', { 'update' => @update, 'antenna_id' => home[:antenna_id] }] + end + end - FeedInsertWorker.push_bulk(homes) do |home| - [@status.id, home[:id], 'home', { 'update' => @update, 'antenna_id' => home[:antenna_id] }] + return unless timelines.any? + + FeedInsertWorker.push_bulk(timelines) do |antenna| + [@status.id, antenna[:id], 'antenna', { 'update' => @update }] end end end diff --git a/app/workers/feed_insert_worker.rb b/app/workers/feed_insert_worker.rb index 7bc046f2e2..22acd0aa6f 100644 --- a/app/workers/feed_insert_worker.rb +++ b/app/workers/feed_insert_worker.rb @@ -17,6 +17,9 @@ class FeedInsertWorker when :list @list = List.find(id) @follower = @list.account + when :antenna + @antenna = Antenna.find(id) + @follower = @antenna.account end end @@ -40,7 +43,7 @@ class FeedInsertWorker def feed_filtered? case @type - when :home + when :home, :antenna FeedManager.instance.filter?(:home, @status, @follower) when :tags FeedManager.instance.filter?(:tags, @status, @follower) diff --git a/spec/services/delivery_antenna_service_spec.rb b/spec/services/delivery_antenna_service_spec.rb index ba20157348..117fcf182c 100644 --- a/spec/services/delivery_antenna_service_spec.rb +++ b/spec/services/delivery_antenna_service_spec.rb @@ -7,8 +7,8 @@ RSpec.describe DeliveryAntennaService, type: :service do let(:last_active_at) { Time.now.utc } let(:last_active_at_tom) { Time.now.utc } - let(:visibility) { 'public' } - let(:searchability) { 'public' } + let(:visibility) { :public } + let(:searchability) { :public } let(:domain) { nil } let(:spoiler_text) { '' } let(:tags) { Tag.find_or_create_by_names(['hoge']) } @@ -35,7 +35,7 @@ RSpec.describe DeliveryAntennaService, type: :service do allow(redis).to receive(:publish) - subject.call(status, true, stl_home) + subject.call(status, false, stl_home) end def home_feed_of(account) @@ -241,6 +241,18 @@ RSpec.describe DeliveryAntennaService, type: :service do end end + context 'when multiple antennas from same owner with keyword' do + let!(:antenna) { antenna_with_keyword(tom, 'body') } + let!(:empty_antenna) { antenna_with_keyword(tom, 'body') } + + [1, 2, 3, 4, 5].each do |_| + it 'detecting antenna' do + expect(antenna_feed_of(antenna)).to include status.id + expect(antenna_feed_of(empty_antenna)).to include status.id + end + end + end + context 'when multiple antennas insert home with keyword' do let!(:antenna) { antenna_with_keyword(bob, 'body', insert_feeds: true) } let!(:empty_antenna) { antenna_with_keyword(tom, 'body', insert_feeds: true) } @@ -264,4 +276,18 @@ RSpec.describe DeliveryAntennaService, type: :service do expect(list_feed_of(empty_antenna.list)).to include status.id end end + + context 'with keyword and unlisted visibility/public searchability by not following' do + let!(:antenna) { antenna_with_keyword(tom, 'body') } + let!(:empty_antenna) { antenna_with_account(tom, alice) } + let(:visibility) { :unlisted } + + it 'detecting antenna' do + expect(antenna_feed_of(antenna)).to include status.id + end + + it 'not detecting antenna' do + expect(antenna_feed_of(empty_antenna)).to_not include status.id + end + end end From c0c2eef1c71406bb81dcd74b9319635d9d4f2366 Mon Sep 17 00:00:00 2001 From: KMY Date: Mon, 4 Sep 2023 16:54:16 +0900 Subject: [PATCH 07/11] Add unlisted post test by following --- .../services/delivery_antenna_service_spec.rb | 43 ++++++++++++++++--- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/spec/services/delivery_antenna_service_spec.rb b/spec/services/delivery_antenna_service_spec.rb index 117fcf182c..961ccc6a5c 100644 --- a/spec/services/delivery_antenna_service_spec.rb +++ b/spec/services/delivery_antenna_service_spec.rb @@ -277,17 +277,50 @@ RSpec.describe DeliveryAntennaService, type: :service do end end - context 'with keyword and unlisted visibility/public searchability by not following' do + context 'with keyword and unlisted visibility by not following' do let!(:antenna) { antenna_with_keyword(tom, 'body') } let!(:empty_antenna) { antenna_with_account(tom, alice) } let(:visibility) { :unlisted } - it 'detecting antenna' do - expect(antenna_feed_of(antenna)).to include status.id + context 'when public searchability' do + it 'detecting antenna' do + expect(antenna_feed_of(antenna)).to include status.id + end + + it 'not detecting antenna' do + expect(antenna_feed_of(empty_antenna)).to_not include status.id + end end - it 'not detecting antenna' do - expect(antenna_feed_of(empty_antenna)).to_not include status.id + context 'when private searchability' do + let(:searchability) { :private } + + it 'not detecting antenna' do + expect(antenna_feed_of(antenna)).to_not include status.id + expect(antenna_feed_of(empty_antenna)).to_not include status.id + end + end + end + + context 'with keyword and unlisted visibility by following' do + let!(:antenna) { antenna_with_keyword(bob, 'body') } + let!(:empty_antenna) { antenna_with_account(bob, alice) } + let(:visibility) { :unlisted } + + context 'when public searchability' do + it 'detecting antenna' do + expect(antenna_feed_of(antenna)).to include status.id + expect(antenna_feed_of(empty_antenna)).to include status.id + end + end + + context 'when private searchability' do + let(:searchability) { :private } + + it 'detecting antenna' do + expect(antenna_feed_of(antenna)).to include status.id + expect(antenna_feed_of(empty_antenna)).to include status.id + end end end end From 53fc5039100f37ac8066edac5203d41dda2ecc95 Mon Sep 17 00:00:00 2001 From: KMY Date: Mon, 4 Sep 2023 16:57:35 +0900 Subject: [PATCH 08/11] Add account domain block test partically --- spec/lib/activitypub/activity/like_spec.rb | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/spec/lib/activitypub/activity/like_spec.rb b/spec/lib/activitypub/activity/like_spec.rb index 7635616b16..51493f7bc8 100644 --- a/spec/lib/activitypub/activity/like_spec.rb +++ b/spec/lib/activitypub/activity/like_spec.rb @@ -54,4 +54,17 @@ RSpec.describe ActivityPub::Activity::Like do expect(sender.favourited?(status)).to be false end end + + describe '#perform when account domain_block' do + subject { described_class.new(json, sender) } + + before do + Fabricate(:account_domain_block, account: recipient, domain: 'example.com') + subject.perform + end + + it 'does not create a favourite from sender to status', pending: 'considering spec' do + expect(sender.favourited?(status)).to be false + end + end end From cfba10448ed3863b44b389106f45389e3c74e0d8 Mon Sep 17 00:00:00 2001 From: KMY Date: Mon, 4 Sep 2023 18:36:56 +0900 Subject: [PATCH 09/11] Block too short antenna keyword --- app/controllers/api/v1/antennas/keywords_controller.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/controllers/api/v1/antennas/keywords_controller.rb b/app/controllers/api/v1/antennas/keywords_controller.rb index b35fb535dc..5260a66bc0 100644 --- a/app/controllers/api/v1/antennas/keywords_controller.rb +++ b/app/controllers/api/v1/antennas/keywords_controller.rb @@ -17,6 +17,7 @@ class Api::V1::Antennas::KeywordsController < Api::BaseController new_keywords = @antenna.keywords || [] keywords.each do |keyword| raise Mastodon::ValidationError, I18n.t('antennas.errors.duplicate_keyword') if new_keywords.include?(keyword) + raise Mastodon::ValidationError, I18n.t('antennas.errors.too_short_keyword') if keyword.length < 2 new_keywords << keyword end From cee5f845facfe47c33d7ded2b2b342826b9419be Mon Sep 17 00:00:00 2001 From: KMY Date: Mon, 4 Sep 2023 18:40:18 +0900 Subject: [PATCH 10/11] Add translation --- config/locales/en.yml | 5 +++++ config/locales/ja.yml | 1 + 2 files changed, 6 insertions(+) diff --git a/config/locales/en.yml b/config/locales/en.yml index 9ac7bce983..d6fd65bbeb 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1043,11 +1043,16 @@ en: keyword: Keywords tag: Tags errors: + duplicate_account: Duplicate account + duplicate_domain: Duplicate domain + duplicate_keyword: Duplicate keyword + duplicate_tag: Duplicate tag limit: accounts: 登録できるアカウント数の上限に達しています domains: 登録できるドメイン数の上限に達しています keywords: 登録できるキーワード数の上限に達しています tags: 登録できるタグ数の上限に達しています + too_short_keyword: Too short keyword! must 2 and more letters edit: accounts_hint: \@askyq or @askyq@example.com accounts_raw: Account list diff --git a/config/locales/ja.yml b/config/locales/ja.yml index db29718139..c5f2546149 100644 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@ -1032,6 +1032,7 @@ ja: tags: 登録できるタグ数の上限に達しています over_limit: 所持できるアンテナ数 %{limit}を超えています over_stl_limit: 所持できるSTLモード付きアンテナ数 (ホーム/リストそれぞれにつき%{limit}) を超えています + too_short_keyword: キーワードが短すぎます edit: accounts_hint: ローカルアカウントの場合は「@info」、リモートアカウントの場合は「@info@example.com」の形式で指定します。サーバーが認識していないアカウントは保存時に自動的に削除されます。 accounts_raw: 絞り込むアカウント From aba7af8e593c69ef25f663170ab7a53a73eeb785 Mon Sep 17 00:00:00 2001 From: KMY Date: Mon, 4 Sep 2023 21:16:14 +0900 Subject: [PATCH 11/11] Reverse reply_to_local requirement to return false when no check tags --- app/lib/activitypub/activity/create.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/lib/activitypub/activity/create.rb b/app/lib/activitypub/activity/create.rb index b4a5b3f23d..a884e14154 100644 --- a/app/lib/activitypub/activity/create.rb +++ b/app/lib/activitypub/activity/create.rb @@ -421,11 +421,11 @@ class ActivityPub::Activity::Create < ActivityPub::Activity end def reply_to_local_from_tags? - (@mentions.nil? || @mentions.any? { |m| m.account.local? }) + (@mentions.present? && @mentions.any? { |m| m.account.local? }) end def reply_to_local_from_tags_following? - (@mentions.nil? || @mentions.none? { |m| m.account.local? && !m.account.following?(@account) }) + (@mentions.present? && @mentions.none? { |m| m.account.local? && !m.account.following?(@account) }) end def reply_to_local?