From 1213d5fa200ff00fd04a9b85b84cab32caa86fc1 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, 21 Oct 2023 10:38:14 +0900 Subject: [PATCH 1/8] =?UTF-8?q?Fix:=20#137=20=E3=83=AD=E3=83=BC=E3=82=AB?= =?UTF-8?q?=E3=83=AB=E3=81=AE=E3=82=AB=E3=82=B9=E3=82=BF=E3=83=A0=E7=B5=B5?= =?UTF-8?q?=E6=96=87=E5=AD=97=E3=81=AB`remote=5Furl`=E3=81=8C=E8=A8=AD?= =?UTF-8?q?=E5=AE=9A=E3=81=95=E3=82=8C=E3=82=8B=E3=83=90=E3=82=B0=E3=82=92?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E3=81=97=E3=81=9F=E3=81=AE=E3=81=AB=E4=BC=B4?= =?UTF-8?q?=E3=81=86=E3=80=81=E6=97=A2=E5=AD=98=E3=81=AE=E3=83=87=E3=83=BC?= =?UTF-8?q?=E3=82=BF=E3=81=8B=E3=82=89=E5=89=8A=E9=99=A4=E3=81=99=E3=82=8B?= =?UTF-8?q?=E3=83=9E=E3=82=A4=E3=82=B0=E3=83=AC=E3=83=BC=E3=82=B7=E3=83=A7?= =?UTF-8?q?=E3=83=B3=E3=82=B3=E3=83=BC=E3=83=89=20(#158)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...ove_remote_uri_from_local_custom_emojis.rb | 21 +++++++++++++++++++ db/schema.rb | 2 +- 2 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 db/post_migrate/20231021005339_remove_remote_uri_from_local_custom_emojis.rb diff --git a/db/post_migrate/20231021005339_remove_remote_uri_from_local_custom_emojis.rb b/db/post_migrate/20231021005339_remove_remote_uri_from_local_custom_emojis.rb new file mode 100644 index 00000000000000..d541de7429d261 --- /dev/null +++ b/db/post_migrate/20231021005339_remove_remote_uri_from_local_custom_emojis.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +require Rails.root.join('lib', 'mastodon', 'migration_helpers') + +class RemoveRemoteUriFromLocalCustomEmojis < ActiveRecord::Migration[7.0] + include Mastodon::MigrationHelpers + + disable_ddl_transaction! + + class CustomEmoji < ApplicationRecord; end + + def up + safety_assured do + CustomEmoji.transaction do + CustomEmoji.where(domain: nil).update_all(image_remote_url: nil, uri: nil) # rubocop:disable Rails/SkipsModelValidations + end + end + end + + def down; end +end diff --git a/db/schema.rb b/db/schema.rb index 7a4ee11608c751..af31ed869b33a9 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.0].define(version: 2023_10_09_235215) do +ActiveRecord::Schema[7.0].define(version: 2023_10_21_005339) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" From 76edf824995e8235fc0e589e6cabb38cd4580b47 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, 21 Oct 2023 21:40:34 +0900 Subject: [PATCH 2/8] =?UTF-8?q?Fix:=20=E3=83=96=E3=83=BC=E3=82=B9=E3=83=88?= =?UTF-8?q?=E3=81=8C=EF=BC=91=E3=81=A4=E3=81=A7=E3=82=82=E3=81=82=E3=82=8B?= =?UTF-8?q?=E3=81=A8=E6=8A=95=E7=A8=BF=E3=81=AE=E3=82=A8=E3=82=AF=E3=82=B9?= =?UTF-8?q?=E3=83=9D=E3=83=BC=E3=83=88=E6=99=82=E3=81=AB=E3=82=A8=E3=83=A9?= =?UTF-8?q?=E3=83=BC=E3=81=8C=E5=87=BA=E3=82=8B=E5=95=8F=E9=A1=8C=20(#149)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix: ブーストが1つでもあるとバックアップ時にエラーが出る問題 * Test: 限定投稿の扱い --- app/services/concerns/payloadable.rb | 3 ++- spec/services/backup_service_spec.rb | 13 ++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/app/services/concerns/payloadable.rb b/app/services/concerns/payloadable.rb index 73c397852e768b..b0bab9a081ecb0 100644 --- a/app/services/concerns/payloadable.rb +++ b/app/services/concerns/payloadable.rb @@ -16,8 +16,9 @@ def serialize_payload(record, serializer, options = {}) always_sign = options.delete(:always_sign) payload = ActiveModelSerializers::SerializableResource.new(record, options.merge(serializer: serializer, adapter: ActivityPub::Adapter)).as_json object = record.respond_to?(:virtual_object) ? record.virtual_object : record + bearcap = object.is_a?(String) && record.respond_to?(:type) && (record.type == 'Create' || record.type == 'Update') - if ((object.respond_to?(:sign?) && object.sign?) && signer && (always_sign || signing_enabled?)) || object.is_a?(String) + if ((object.respond_to?(:sign?) && object.sign?) && signer && (always_sign || signing_enabled?)) || bearcap ActivityPub::LinkedDataSignature.new(payload).sign!(signer, sign_with: sign_with) else payload diff --git a/spec/services/backup_service_spec.rb b/spec/services/backup_service_spec.rb index 806ba18323ea56..f5ad319136992b 100644 --- a/spec/services/backup_service_spec.rb +++ b/spec/services/backup_service_spec.rb @@ -9,6 +9,8 @@ let!(:attachment) { Fabricate(:media_attachment, account: user.account) } let!(:status) { Fabricate(:status, account: user.account, text: 'Hello', visibility: :public, media_attachments: [attachment]) } let!(:private_status) { Fabricate(:status, account: user.account, text: 'secret', visibility: :private) } + let!(:limited_status) { Fabricate(:status, account: user.account, text: 'sec mutual', visibility: :limited, limited_scope: :mutual) } + let!(:reblog_status) { Fabricate(:status, account: user.account, reblog_of_id: Fabricate(:status).id) } let!(:favourite) { Fabricate(:favourite, account: user.account) } let!(:bookmark) { Fabricate(:bookmark, account: user.account) } let!(:backup) { Fabricate(:backup, user: user) } @@ -60,10 +62,12 @@ def expect_outbox_export aggregate_failures do expect(json['@context']).to_not be_nil expect(json['type']).to eq 'OrderedCollection' - expect(json['totalItems']).to eq 2 + expect(json['totalItems']).to eq 4 expect(json['orderedItems'][0]['@context']).to be_nil expect(json['orderedItems'][0]).to include_create_item(status) expect(json['orderedItems'][1]).to include_create_item(private_status) + expect(json['orderedItems'][2]).to include_create_item(limited_status) + expect(json['orderedItems'][3]).to include_announce_item(reblog_status) end end @@ -98,4 +102,11 @@ def include_create_item(status) }), }) end + + def include_announce_item(status) + include({ + 'type' => 'Announce', + 'object' => ActivityPub::TagManager.instance.uri_for(status.reblog), + }) + end end From 5497e2ae5dd762b991f73df471343a3e0fe7a70c 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: Sun, 22 Oct 2023 09:09:01 +0900 Subject: [PATCH 3/8] =?UTF-8?q?Add:=20=E3=82=AB=E3=82=B9=E3=82=BF=E3=83=A0?= =?UTF-8?q?=E7=B5=B5=E6=96=87=E5=AD=97=E3=81=AE=E3=82=A8=E3=82=A4=E3=83=AA?= =?UTF-8?q?=E3=82=A2=E3=82=B9=E5=90=8D=E3=82=92=E9=80=A3=E5=90=88=20(#135)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add: カスタム絵文字のエイリアス名を連合 * Fix test --- app/helpers/context_helper.rb | 2 ++ app/lib/activitypub/activity/create.rb | 1 + app/lib/activitypub/activity/like.rb | 1 + app/lib/activitypub/parser/custom_emoji_parser.rb | 4 ++++ app/serializers/activitypub/emoji_serializer.rb | 8 ++++++-- app/services/activitypub/process_status_update_service.rb | 1 + 6 files changed, 15 insertions(+), 2 deletions(-) diff --git a/app/helpers/context_helper.rb b/app/helpers/context_helper.rb index 69a8767f0fcf38..ab0d44ca69b8cc 100644 --- a/app/helpers/context_helper.rb +++ b/app/helpers/context_helper.rb @@ -30,6 +30,8 @@ module ContextHelper other_setting: { 'fedibird' => 'http://fedibird.com/ns#', 'otherSetting' => 'fedibird:otherSetting' }, references: { 'fedibird' => 'http://fedibird.com/ns#', 'references' => { '@id' => 'fedibird:references', '@type' => '@id' } }, quote_uri: { 'fedibird' => 'http://fedibird.com/ns#', 'quoteUri' => 'fedibird:quoteUri' }, + keywords: { 'schema' => 'http://schema.org#', 'keywords' => 'schema:keywords' }, + license: { 'schema' => 'http://schema.org#', 'license' => 'schema:license' }, olm: { 'toot' => 'http://joinmastodon.org/ns#', 'Device' => 'toot:Device', 'Ed25519Signature' => 'toot:Ed25519Signature', 'Ed25519Key' => 'toot:Ed25519Key', 'Curve25519Key' => 'toot:Curve25519Key', 'EncryptedMessage' => 'toot:EncryptedMessage', 'publicKeyBase64' => 'toot:publicKeyBase64', 'deviceId' => 'toot:deviceId', 'claim' => { '@type' => '@id', '@id' => 'toot:claim' }, diff --git a/app/lib/activitypub/activity/create.rb b/app/lib/activitypub/activity/create.rb index fe37c3234bfe5d..204899fa398f19 100644 --- a/app/lib/activitypub/activity/create.rb +++ b/app/lib/activitypub/activity/create.rb @@ -274,6 +274,7 @@ def process_emoji(tag) emoji.image_remote_url = custom_emoji_parser.image_remote_url emoji.license = custom_emoji_parser.license emoji.is_sensitive = custom_emoji_parser.is_sensitive + emoji.aliases = custom_emoji_parser.aliases emoji.save rescue Seahorse::Client::NetworkingError => e Rails.logger.warn "Error storing emoji: #{e}" diff --git a/app/lib/activitypub/activity/like.rb b/app/lib/activitypub/activity/like.rb index ba103b1fa7b3f1..8be83456139eae 100644 --- a/app/lib/activitypub/activity/like.rb +++ b/app/lib/activitypub/activity/like.rb @@ -127,6 +127,7 @@ def process_emoji(tag) emoji.image_remote_url = custom_emoji_parser.image_remote_url emoji.license = custom_emoji_parser.license emoji.is_sensitive = custom_emoji_parser.is_sensitive + emoji.aliases = custom_emoji_parser.aliases emoji.save rescue Seahorse::Client::NetworkingError => e Rails.logger.warn "Error storing emoji: #{e}" diff --git a/app/lib/activitypub/parser/custom_emoji_parser.rb b/app/lib/activitypub/parser/custom_emoji_parser.rb index e217b5ec96fb04..e2c48b0a907f73 100644 --- a/app/lib/activitypub/parser/custom_emoji_parser.rb +++ b/app/lib/activitypub/parser/custom_emoji_parser.rb @@ -15,6 +15,10 @@ def shortcode @json['name']&.delete(':') end + def aliases + as_array(@json['keywords']) + end + def image_remote_url @json.dig('icon', 'url') end diff --git a/app/serializers/activitypub/emoji_serializer.rb b/app/serializers/activitypub/emoji_serializer.rb index 98525d3131ab18..a8dfff58f6f84c 100644 --- a/app/serializers/activitypub/emoji_serializer.rb +++ b/app/serializers/activitypub/emoji_serializer.rb @@ -3,9 +3,9 @@ class ActivityPub::EmojiSerializer < ActivityPub::Serializer include RoutingHelper - context_extensions :emoji + context_extensions :emoji, :license, :keywords - attributes :id, :type, :domain, :name, :is_sensitive, :updated + attributes :id, :type, :domain, :name, :keywords, :is_sensitive, :updated attribute :license, if: -> { object.license.present? } @@ -23,6 +23,10 @@ def domain object.domain.presence || Rails.configuration.x.local_domain end + def keywords + object.aliases + end + def icon object.image end diff --git a/app/services/activitypub/process_status_update_service.rb b/app/services/activitypub/process_status_update_service.rb index c7bc93f7813fe6..cbef13fbed71a3 100644 --- a/app/services/activitypub/process_status_update_service.rb +++ b/app/services/activitypub/process_status_update_service.rb @@ -249,6 +249,7 @@ def update_emojis! emoji.image_remote_url = custom_emoji_parser.image_remote_url emoji.license = custom_emoji_parser.license emoji.is_sensitive = custom_emoji_parser.is_sensitive + emoji.aliases = custom_emoji_parser.aliases emoji.save rescue Seahorse::Client::NetworkingError => e Rails.logger.warn "Error storing emoji: #{e}" From 4f37ede88607eaa88c02f98e4f1453b0ae97722f 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: Sun, 22 Oct 2023 09:40:20 +0900 Subject: [PATCH 4/8] =?UTF-8?q?Fix:=20#162=20=E7=B7=A8=E9=9B=86=EF=BC=8F?= =?UTF-8?q?=E4=BB=96=E3=81=AE=E3=82=B5=E3=83=BC=E3=83=90=E3=83=BC=E3=81=8B?= =?UTF-8?q?=E3=82=89=E3=81=AE=E7=B7=A8=E9=9B=86=E3=81=A7=E3=80=81=E3=83=95?= =?UTF-8?q?=E3=82=A9=E3=83=AD=E3=83=BC=E3=81=97=E3=81=A6=E3=81=84=E3=81=AA?= =?UTF-8?q?=E3=81=84=E7=9B=B8=E6=89=8B=E3=81=8B=E3=82=89=E3=81=AE=E3=83=A1?= =?UTF-8?q?=E3=83=B3=E3=82=B7=E3=83=A7=E3=83=B3=E3=81=AB=E9=96=A2=E3=81=99?= =?UTF-8?q?=E3=82=8BNG=E3=83=AF=E3=83=BC=E3=83=89=E3=81=AB=E5=AF=BE?= =?UTF-8?q?=E5=BF=9C=20(#163)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix: #162 フォローしていないアカウントへのメンションのNGワードが編集で有効にならない問題 * Fix: 他のサーバーから来た編集についても適用 --- .../process_status_update_service.rb | 15 ++ app/services/post_status_service.rb | 2 +- app/services/update_status_service.rb | 15 +- .../process_status_update_service_spec.rb | 173 +++++++++++++++++- spec/services/post_status_service_spec.rb | 20 ++ spec/services/update_status_service_spec.rb | 99 ++++++++++ 6 files changed, 315 insertions(+), 9 deletions(-) diff --git a/app/services/activitypub/process_status_update_service.rb b/app/services/activitypub/process_status_update_service.rb index cbef13fbed71a3..765a59c890d543 100644 --- a/app/services/activitypub/process_status_update_service.rb +++ b/app/services/activitypub/process_status_update_service.rb @@ -5,6 +5,8 @@ class ActivityPub::ProcessStatusUpdateService < BaseService include Redisable include Lockable + class AbortError < ::StandardError; end + def call(status, activity_json, object_json, request_id: nil) raise ArgumentError, 'Status has unsaved changes' if status.changed? @@ -30,6 +32,9 @@ def call(status, activity_json, object_json, request_id: nil) handle_implicit_update! end + @status + rescue AbortError + @status.reload @status end @@ -46,6 +51,7 @@ def handle_explicit_update! update_poll! update_immediate_attributes! update_metadata! + validate_status_mentions! create_edits! end @@ -160,6 +166,15 @@ def valid_status? !Admin::NgWord.reject?("#{@status_parser.spoiler_text}\n#{@status_parser.text}") && !Admin::NgWord.hashtag_reject?(@raw_tags.size) end + def validate_status_mentions! + raise AbortError if mention_to_stranger? && Admin::NgWord.stranger_mention_reject?("#{@status.spoiler_text}\n#{@status.text}") + end + + def mention_to_stranger? + @status.mentions.map(&:account).to_a.any? { |mentioned_account| mentioned_account.id != @status.account.id && !mentioned_account.following?(@status.account) } || + (@status.thread.present? && @status.thread.account.id != @status.account.id && !@status.thread.account.following?(@status.account)) + end + def update_immediate_attributes! @status.text = @status_parser.text || '' @status.spoiler_text = @status_parser.spoiler_text || '' diff --git a/app/services/post_status_service.rb b/app/services/post_status_service.rb index 5410323dbb5e42..0e3bd8805de509 100644 --- a/app/services/post_status_service.rb +++ b/app/services/post_status_service.rb @@ -214,7 +214,7 @@ def validate_status_mentions! end def mention_to_stranger? - @status.mentions.map(&:account).to_a.any? { |mentioned_account| mentioned_account.id != @account && !mentioned_account.following?(@account) } || + @status.mentions.map(&:account).to_a.any? { |mentioned_account| mentioned_account.id != @account.id && !mentioned_account.following?(@account) } || (@in_reply_to && @in_reply_to.account.id != @account.id && !@in_reply_to.account.following?(@account)) end diff --git a/app/services/update_status_service.rb b/app/services/update_status_service.rb index 0a5de6b907b3bf..a9733b0658f09b 100644 --- a/app/services/update_status_service.rb +++ b/app/services/update_status_service.rb @@ -35,10 +35,13 @@ def call(status, account_id, options = {}) update_poll! if @options.key?(:poll) update_immediate_attributes! create_edit! unless @options[:no_history] + + reset_preview_card! + process_mentions_service.call(@status) + validate_status_mentions! end queue_poll_notifications! - reset_preview_card! update_metadata! update_references! broadcast_updates! @@ -81,6 +84,15 @@ def validate_status! raise Mastodon::ValidationError, I18n.t('statuses.too_many_hashtags') if Admin::NgWord.hashtag_reject_with_extractor?(@options[:text]) end + def validate_status_mentions! + raise Mastodon::ValidationError, I18n.t('statuses.contains_ng_words') if mention_to_stranger? && Setting.stranger_mention_from_local_ng && Admin::NgWord.stranger_mention_reject?("#{@options[:spoiler_text]}\n#{@options[:text]}") + end + + def mention_to_stranger? + @status.mentions.map(&:account).to_a.any? { |mentioned_account| mentioned_account.id != @status.account.id && !mentioned_account.following?(@status.account) } || + (@status.thread.present? && @status.thread.account.id != @status.account.id && !@status.thread.account.following?(@status.account)) + end + def validate_media! return [] if @options[:media_ids].blank? || !@options[:media_ids].is_a?(Enumerable) @@ -167,7 +179,6 @@ def update_references! def update_metadata! ProcessHashtagsService.new.call(@status) - process_mentions_service.call(@status) @status.update(limited_scope: :circle) if process_mentions_service.mentions? end diff --git a/spec/services/activitypub/process_status_update_service_spec.rb b/spec/services/activitypub/process_status_update_service_spec.rb index 9d91f31cc5c2c5..0612c94d8c42ea 100644 --- a/spec/services/activitypub/process_status_update_service_spec.rb +++ b/spec/services/activitypub/process_status_update_service_spec.rb @@ -9,19 +9,24 @@ def poll_option_json(name, votes) RSpec.describe ActivityPub::ProcessStatusUpdateService, type: :service do subject { described_class.new } - let!(:status) { Fabricate(:status, text: 'Hello world', account: Fabricate(:account, domain: 'example.com')) } + let(:thread) { nil } + let!(:status) { Fabricate(:status, text: 'Hello world', account: Fabricate(:account, domain: 'example.com'), thread: thread) } + let(:json_tags) do + [ + { type: 'Hashtag', name: 'hoge' }, + { type: 'Mention', href: ActivityPub::TagManager.instance.uri_for(alice) }, + ] + end + let(:content) { 'Hello universe' } let(:payload) do { '@context': 'https://www.w3.org/ns/activitystreams', id: 'foo', type: 'Note', summary: 'Show more', - content: 'Hello universe', + content: content, updated: '2021-09-08T22:39:25Z', - tag: [ - { type: 'Hashtag', name: 'hoge' }, - { type: 'Mention', href: ActivityPub::TagManager.instance.uri_for(alice) }, - ], + tag: json_tags, } end let(:json) { Oj.load(Oj.dump(payload)) } @@ -462,5 +467,161 @@ def poll_option_json(name, votes) subject.call(status, json, json) expect(status.reload.edited_at.to_s).to eq '2021-09-08 22:39:25 UTC' end + + describe 'ng word is set' do + let(:json_tags) { [] } + + context 'when hit ng words' do + let(:content) { 'ng word test' } + + it 'update status' do + Form::AdminSettings.new(ng_words: 'test').save + + subject.call(status, json, json) + expect(status.reload.text).to_not eq content + end + end + + context 'when not hit ng words' do + let(:content) { 'ng word aiueo' } + + it 'update status' do + Form::AdminSettings.new(ng_words: 'test').save + + subject.call(status, json, json) + expect(status.reload.text).to eq content + end + end + + context 'when hit ng words for mention' do + let(:json_tags) do + [ + { type: 'Mention', href: ActivityPub::TagManager.instance.uri_for(alice) }, + ] + end + let(:content) { 'ng word test' } + + it 'update status' do + Form::AdminSettings.new(ng_words_for_stranger_mention: 'test', stranger_mention_from_local_ng: '1').save + + subject.call(status, json, json) + expect(status.reload.text).to_not eq content + expect(status.mentioned_accounts.pluck(:id)).to_not include alice.id + end + end + + context 'when hit ng words for mention but local posts are not checked' do + let(:json_tags) do + [ + { type: 'Mention', href: ActivityPub::TagManager.instance.uri_for(alice) }, + ] + end + let(:content) { 'ng word test' } + + it 'update status' do + Form::AdminSettings.new(ng_words_for_stranger_mention: 'test', stranger_mention_from_local_ng: '0').save + + subject.call(status, json, json) + expect(status.reload.text).to_not eq content + expect(status.mentioned_accounts.pluck(:id)).to_not include alice.id + end + end + + context 'when hit ng words for mention to follower' do + let(:json_tags) do + [ + { type: 'Mention', href: ActivityPub::TagManager.instance.uri_for(alice) }, + ] + end + let(:content) { 'ng word test' } + + before do + alice.follow!(status.account) + end + + it 'update status' do + Form::AdminSettings.new(ng_words_for_stranger_mention: 'test').save + + subject.call(status, json, json) + expect(status.reload.text).to eq content + expect(status.mentioned_accounts.pluck(:id)).to include alice.id + end + end + + context 'when hit ng words for reply' do + let(:json_tags) do + [ + { type: 'Mention', href: ActivityPub::TagManager.instance.uri_for(alice) }, + ] + end + let(:content) { 'ng word test' } + let(:thread) { Fabricate(:status, account: alice) } + + it 'update status' do + Form::AdminSettings.new(ng_words_for_stranger_mention: 'test').save + + subject.call(status, json, json) + expect(status.reload.text).to_not eq content + expect(status.mentioned_accounts.pluck(:id)).to_not include alice.id + end + end + + context 'when hit ng words for reply to follower' do + let(:json_tags) do + [ + { type: 'Mention', href: ActivityPub::TagManager.instance.uri_for(alice) }, + ] + end + let(:content) { 'ng word test' } + let(:thread) { Fabricate(:status, account: alice) } + + before do + alice.follow!(status.account) + end + + it 'update status' do + Form::AdminSettings.new(ng_words_for_stranger_mention: 'test').save + + subject.call(status, json, json) + expect(status.reload.text).to eq content + expect(status.mentioned_accounts.pluck(:id)).to include alice.id + end + end + + context 'when using hashtag under limit' do + let(:json_tags) do + [ + { type: 'Hashtag', name: 'a' }, + { type: 'Hashtag', name: 'b' }, + ] + end + let(:content) { 'ohagi is good' } + + it 'update status' do + Form::AdminSettings.new(post_hash_tags_max: 2).save + + subject.call(status, json, json) + expect(status.reload.text).to eq content + end + end + + context 'when using hashtag over limit' do + let(:json_tags) do + [ + { type: 'Hashtag', name: 'a' }, + { type: 'Hashtag', name: 'b' }, + { type: 'Hashtag', name: 'c' }, + ] + end + let(:content) { 'ohagi is good' } + + it 'update status' do + Form::AdminSettings.new(post_hash_tags_max: 2).save + + subject.call(status, json, json) + expect(status.reload.text).to_not eq content + end + end + end end end diff --git a/spec/services/post_status_service_spec.rb b/spec/services/post_status_service_spec.rb index adf7e33d8ec9a9..a1a242a51752c4 100644 --- a/spec/services/post_status_service_spec.rb +++ b/spec/services/post_status_service_spec.rb @@ -510,6 +510,26 @@ expect(status).to be_persisted expect(status.text).to eq text end + + it 'using hashtag under limit' do + account = Fabricate(:account) + text = '#a #b' + Form::AdminSettings.new(post_hash_tags_max: 2).save + + status = subject.call(account, text: text) + + expect(status).to be_persisted + expect(status.tags.count).to eq 2 + expect(status.text).to eq text + end + + it 'using hashtag over limit' do + account = Fabricate(:account) + text = '#a #b #c' + Form::AdminSettings.new(post_hash_tags_max: 2).save + + expect { subject.call(account, text: text) }.to raise_error Mastodon::ValidationError + end end def create_status_with_options(**options) diff --git a/spec/services/update_status_service_spec.rb b/spec/services/update_status_service_spec.rb index 288466bdeb784a..d2f3d42a0f09ed 100644 --- a/spec/services/update_status_service_spec.rb +++ b/spec/services/update_status_service_spec.rb @@ -218,4 +218,103 @@ subject.call(status, status.account_id, text: 'Bar') expect(ActivityPub::DistributionWorker).to have_received(:perform_async) end + + describe 'ng word is set' do + let(:account) { Fabricate(:account) } + let(:status) { PostStatusService.new.call(account, text: 'ohagi') } + + it 'hit ng words' do + text = 'ng word test' + Form::AdminSettings.new(ng_words: 'test').save + + expect { subject.call(status, status.account_id, text: text) }.to raise_error(Mastodon::ValidationError) + end + + it 'not hit ng words' do + text = 'ng word aiueo' + Form::AdminSettings.new(ng_words: 'test').save + + status2 = subject.call(status, status.account_id, text: text) + + expect(status2).to be_persisted + expect(status2.text).to eq text + end + + it 'hit ng words for mention' do + Fabricate(:account, username: 'ohagi', domain: nil) + text = 'ng word test @ohagi' + Form::AdminSettings.new(ng_words_for_stranger_mention: 'test', stranger_mention_from_local_ng: '1').save + + expect { subject.call(status, status.account_id, text: text) }.to raise_error(Mastodon::ValidationError) + expect(status.reload.text).to_not eq text + expect(status.mentioned_accounts.pluck(:username)).to_not include 'ohagi' + end + + it 'hit ng words for mention but local posts are not checked' do + Fabricate(:account, username: 'ohagi', domain: nil) + text = 'ng word test @ohagi' + Form::AdminSettings.new(ng_words_for_stranger_mention: 'test', stranger_mention_from_local_ng: '0').save + + status2 = subject.call(status, status.account_id, text: text) + + expect(status2).to be_persisted + expect(status2.text).to eq text + end + + it 'hit ng words for mention to follower' do + mentioned = Fabricate(:account, username: 'ohagi', domain: nil) + mentioned.follow!(account) + text = 'ng word test @ohagi' + Form::AdminSettings.new(ng_words_for_stranger_mention: 'test', stranger_mention_from_local_ng: '1').save + + status2 = subject.call(status, status.account_id, text: text) + + expect(status2).to be_persisted + expect(status2.text).to eq text + end + + it 'hit ng words for reply' do + text = 'ng word test' + Form::AdminSettings.new(ng_words_for_stranger_mention: 'test', stranger_mention_from_local_ng: '1').save + + status = PostStatusService.new.call(account, text: 'hello', thread: Fabricate(:status)) + + expect { subject.call(status, status.account_id, text: text) }.to raise_error(Mastodon::ValidationError) + expect(status.reload.text).to_not eq text + end + + it 'hit ng words for reply to follower' do + mentioned = Fabricate(:account, username: 'ohagi', domain: nil) + mentioned.follow!(account) + text = 'ng word test' + Form::AdminSettings.new(ng_words_for_stranger_mention: 'test', stranger_mention_from_local_ng: '1').save + + status = PostStatusService.new.call(account, text: 'hello', thread: Fabricate(:status, account: mentioned)) + + status = subject.call(status, status.account_id, text: text) + + expect(status).to be_persisted + expect(status.text).to eq text + end + + it 'using hashtag under limit' do + text = '#a #b' + Form::AdminSettings.new(post_hash_tags_max: 2).save + + subject.call(status, status.account_id, text: text) + + expect(status.reload.tags.count).to eq 2 + expect(status.text).to eq text + end + + it 'using hashtag over limit' do + text = '#a #b #c' + Form::AdminSettings.new(post_hash_tags_max: 2).save + + expect { subject.call(status, status.account_id, text: text) }.to raise_error Mastodon::ValidationError + + expect(status.reload.tags.count).to eq 0 + expect(status.text).to_not eq text + end + end end From eb52b7215242be8f99c76ea88c59f0718cdad199 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: Sun, 22 Oct 2023 09:46:19 +0900 Subject: [PATCH 5/8] =?UTF-8?q?Fix:=20=E4=BB=96=E3=81=AE=E3=82=B5=E3=83=BC?= =?UTF-8?q?=E3=83=90=E3=83=BC=E5=90=8C=E5=A3=AB=E3=81=AE=E3=82=B9=E3=82=BF?= =?UTF-8?q?=E3=83=B3=E3=83=97=E3=81=A7`emoji=5Freaction=5Fpolicy`=E3=81=8C?= =?UTF-8?q?=E9=81=A9=E7=94=A8=E3=81=95=E3=82=8C=E3=82=8B=E5=95=8F=E9=A1=8C?= =?UTF-8?q?=20(#165)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix: 他のサーバー同士のスタンプで`emoji_reaction_policy`が適用される問題 * こっちに変更 * #161 テストを追加 * テスト修正 --- app/models/account.rb | 1 + spec/models/account_spec.rb | 201 ++++++++++++++++++++++++++++++++++++ 2 files changed, 202 insertions(+) diff --git a/app/models/account.rb b/app/models/account.rb index 3b3dc09f0ef1cc..7170cbe1e268e3 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -399,6 +399,7 @@ def show_emoji_reaction?(account) def allow_emoji_reaction?(account) return false if account.nil? + return true unless local? || account.local? show_emoji_reaction?(account) end diff --git a/spec/models/account_spec.rb b/spec/models/account_spec.rb index c13d57c7614cc1..5cdc31ecd94358 100644 --- a/spec/models/account_spec.rb +++ b/spec/models/account_spec.rb @@ -246,6 +246,207 @@ end end + describe '#allow_emoji_reaction?' do + let(:policy) { :allow } + let(:reactioned) { Fabricate(:user, settings: { emoji_reaction_policy: policy }).account } + let(:followee) { Fabricate(:account) } + let(:follower) { Fabricate(:account) } + let(:mutual) { Fabricate(:account) } + let(:anyone) { Fabricate(:account) } + + before do + follower.follow!(reactioned) + reactioned.follow!(followee) + mutual.follow!(reactioned) + reactioned.follow!(mutual) + end + + context 'when policy is arrow' do + it 'allows anyone' do + expect(reactioned.allow_emoji_reaction?(anyone)).to be true + end + + it 'allows followee' do + expect(reactioned.allow_emoji_reaction?(followee)).to be true + end + + it 'allows follower' do + expect(reactioned.allow_emoji_reaction?(follower)).to be true + end + + it 'allows mutual' do + expect(reactioned.allow_emoji_reaction?(mutual)).to be true + end + + it 'allows self' do + expect(reactioned.allow_emoji_reaction?(reactioned)).to be true + end + end + + context 'when policy is following_only' do + let(:policy) { :following_only } + + it 'allows anyone' do + expect(reactioned.allow_emoji_reaction?(anyone)).to be false + end + + it 'allows followee' do + expect(reactioned.allow_emoji_reaction?(followee)).to be true + end + + it 'allows follower' do + expect(reactioned.allow_emoji_reaction?(follower)).to be false + end + + it 'allows mutual' do + expect(reactioned.allow_emoji_reaction?(mutual)).to be true + end + + it 'allows self' do + expect(reactioned.allow_emoji_reaction?(reactioned)).to be true + end + end + + context 'when policy is followers_only' do + let(:policy) { :followers_only } + + it 'allows anyone' do + expect(reactioned.allow_emoji_reaction?(anyone)).to be false + end + + it 'allows followee' do + expect(reactioned.allow_emoji_reaction?(followee)).to be false + end + + it 'allows follower' do + expect(reactioned.allow_emoji_reaction?(follower)).to be true + end + + it 'allows mutual' do + expect(reactioned.allow_emoji_reaction?(mutual)).to be true + end + + it 'allows self' do + expect(reactioned.allow_emoji_reaction?(reactioned)).to be true + end + end + + context 'when policy is mutuals_only' do + let(:policy) { :mutuals_only } + + it 'allows anyone' do + expect(reactioned.allow_emoji_reaction?(anyone)).to be false + end + + it 'allows followee' do + expect(reactioned.allow_emoji_reaction?(followee)).to be false + end + + it 'allows follower' do + expect(reactioned.allow_emoji_reaction?(follower)).to be false + end + + it 'allows mutual' do + expect(reactioned.allow_emoji_reaction?(mutual)).to be true + end + + it 'allows self' do + expect(reactioned.allow_emoji_reaction?(reactioned)).to be true + end + end + + context 'when policy is outside_only' do + let(:policy) { :outside_only } + + it 'allows anyone' do + expect(reactioned.allow_emoji_reaction?(anyone)).to be false + end + + it 'allows followee' do + expect(reactioned.allow_emoji_reaction?(followee)).to be true + end + + it 'allows follower' do + expect(reactioned.allow_emoji_reaction?(follower)).to be true + end + + it 'allows mutual' do + expect(reactioned.allow_emoji_reaction?(mutual)).to be true + end + + it 'allows self' do + expect(reactioned.allow_emoji_reaction?(reactioned)).to be true + end + end + + context 'when policy is block' do + let(:policy) { :block } + + it 'allows anyone' do + expect(reactioned.allow_emoji_reaction?(anyone)).to be false + end + + it 'allows followee' do + expect(reactioned.allow_emoji_reaction?(followee)).to be false + end + + it 'allows follower' do + expect(reactioned.allow_emoji_reaction?(follower)).to be false + end + + it 'allows mutual' do + expect(reactioned.allow_emoji_reaction?(mutual)).to be false + end + + it 'allows self' do + expect(reactioned.allow_emoji_reaction?(reactioned)).to be false + end + end + + context 'when reactioned is remote user' do + let(:reactioned) { Fabricate(:account, domain: 'foo.bar', uri: 'https://foo.bar/actor', settings: { emoji_reaction_policy: :following_only }) } + + it 'allows anyone' do + expect(reactioned.allow_emoji_reaction?(anyone)).to be false + end + + it 'allows followee' do + expect(reactioned.allow_emoji_reaction?(followee)).to be true + end + end + + context 'when reactor is remote user' do + let(:anyone) { Fabricate(:account, domain: 'foo.bar', uri: 'https://foo.bar/actor/anyone') } + let(:policy) { :following_only } + + it 'allows anyone' do + expect(reactioned.allow_emoji_reaction?(anyone)).to be false + end + + it 'allows followee' do + expect(reactioned.allow_emoji_reaction?(followee)).to be true + end + end + + context 'when both are remote user' do + let(:reactioned) { Fabricate(:account, domain: 'foo.bar', uri: 'https://foo.bar/actor', settings: { emoji_reaction_policy: policy }) } + let(:anyone) { Fabricate(:account, domain: 'foo.bar', uri: 'https://foo.bar/actor/anyone') } + let(:followee) { Fabricate(:account, domain: 'foo.bar', uri: 'https://foo.bar/actor/followee') } + + it 'allows anyone' do + expect(reactioned.allow_emoji_reaction?(anyone)).to be true + end + + context 'with blocking' do + let(:policy) { :block } + + it 'allows anyone' do + expect(reactioned.allow_emoji_reaction?(anyone)).to be true + end + end + end + end + describe '#favourited?' do subject { Fabricate(:account) } From 3174ad301ebd1ae235d87aa9781d2f42557f5cbc 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: Sun, 22 Oct 2023 09:49:36 +0900 Subject: [PATCH 6/8] =?UTF-8?q?Change:=20#101=20=E3=82=BB=E3=82=AD?= =?UTF-8?q?=E3=83=A5=E3=83=AA=E3=83=86=E3=82=A3=E9=96=A2=E9=80=A3=E6=96=87?= =?UTF-8?q?=E6=9B=B8=E3=81=AE=E9=82=A6=E8=A8=B3=20(#167)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Change: #101 セキュリティ関連文書の邦訳 * 間違ってkmyblueに来た場合を追記 * 誤字 * 表現 * 表現 --- .github/ISSUE_TEMPLATE/1.bug_report.yml | 2 +- SECURITY.md | 33 ++++++++++++++----------- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/1.bug_report.yml b/.github/ISSUE_TEMPLATE/1.bug_report.yml index 10e7e534580cb7..10421eed7b17f4 100644 --- a/.github/ISSUE_TEMPLATE/1.bug_report.yml +++ b/.github/ISSUE_TEMPLATE/1.bug_report.yml @@ -1,5 +1,5 @@ name: バグ報告 -description: kmyblueのバグ報告 +description: kmyblueのバグ報告(ただし情報改竄、秘密情報の漏洩、システムの破損などが発生するバグは、こちらではなく「Security」タブよりセキュリティインシデントとして報告してください) labels: [bug] body: - type: textarea diff --git a/SECURITY.md b/SECURITY.md index 3e13377db63eb4..d5b27adfac1bf7 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,22 +1,25 @@ -# Security Policy +# セキュリティポリシー -If you believe you've identified a security vulnerability in Mastodon (a bug that allows something to happen that shouldn't be possible), you can either: +kmyblueのプログラムにおいてセキュリティインシデントを発見した場合、kmyblueに報告してください。 -- open a [Github security issue on the Mastodon project](https://github.com/mastodon/mastodon/security/advisories/new) -- reach us at +kmyblueにセキュリティインシデントを報告する場合、以下の手順を踏んでください。 -You should _not_ report such issues on public GitHub issues or in other public spaces to give us time to publish a fix for the issue without exposing Mastodon's users to increased risk. +- [こちらのリンクから新規インシデントを起票してください](https://github.com/kmycode/mastodon/security/advisories/new) +- メール 、または[@askyq@kmy.blue](https://kmy.blue/@askyq)宛に、**セキュリティインシデントを起票したことだけ**を連絡してください。セキュリティインシデントの内容は、絶対に連絡に含めないでください(リンクくらいなら含めていいかな) -## Scope +他のkmyblueフォークの利用者の安全のために少しでも時間稼ぎをしなければいけないので、この問題をIssueを含む公開された場所で記述しないでください。 -A "vulnerability in Mastodon" is a vulnerability in the code distributed through our main source code repository on GitHub. Vulnerabilities that are specific to a given installation (e.g. misconfiguration) should be reported to the owner of that installation and not us. +## 範囲 -## Supported Versions +こちらが対応できる範囲は、当リポジトリで公開しているソースコードのみとなります。当リポジトリの依存パッケージ内に問題がある場合は、そちらに報告してください。 -| Version | Supported | -| ------- | ---------------- | -| 4.2.x | Yes | -| 4.1.x | Yes | -| 4.0.x | Until 2023-10-31 | -| 3.5.x | Until 2023-12-31 | -| < 3.5 | No | +もしあなたに専門知識があり、それが本家Mastodon由来の問題であると信じるに足る根拠がある場合、kmyblueではなくMastodonのほうに報告してください。kmyblueに報告されても、Mastodonより先に修正してしまうことでMastodonにセキュリティリスクを発生させる可能性がありますし、本家Mastodonの対応を待つにしてもkmyblueのほうに来てしまったセキュリティインシデントの対応に困ります(本家がなかなか対応してくれない可能性を考えると削除しづらい)。もし間違ってkmyblueに来た場合、kmyblue開発者の責任で振り分けを行います。 + +## サポートするバージョン + +下記以外のバージョンは、セキュリティインシデントを起票されても対応しません。 + +- 最新メジャーバージョン、かつ、最新マイナーバージョン + - 最新メジャーバージョンのサポートは、次のメジャーバージョンが出た時点で終了します +- LTS + - LTSのサポートは、次のLTSが出た時点で終了します(ただし移行期間があってもいいと思ってるので、1〜3ヶ月以内ならセキュリティインシデントの程度に応じて対応する可能性があります) From e3ec2f92dcf622dfce1a68d93e13d38684162c14 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: Sun, 22 Oct 2023 09:49:51 +0900 Subject: [PATCH 7/8] =?UTF-8?q?Add:=20#22=20=E6=8B=A1=E5=BC=B5=E3=83=89?= =?UTF-8?q?=E3=83=A1=E3=82=A4=E3=83=B3=E3=83=96=E3=83=AD=E3=83=83=E3=82=AF?= =?UTF-8?q?=E3=81=AE=E8=A8=AD=E5=AE=9A=E7=94=BB=E9=9D=A2=E3=81=AB=E8=A6=8B?= =?UTF-8?q?=E5=87=BA=E3=81=97=20(#164)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_domain_block_list.html.haml | 44 +++++++++++++++++++ app/views/admin/domain_blocks/edit.html.haml | 43 ++---------------- app/views/admin/domain_blocks/new.html.haml | 43 ++---------------- config/locales/en.yml | 5 +++ config/locales/ja.yml | 7 ++- 5 files changed, 63 insertions(+), 79 deletions(-) create mode 100644 app/views/admin/domain_blocks/_domain_block_list.html.haml diff --git a/app/views/admin/domain_blocks/_domain_block_list.html.haml b/app/views/admin/domain_blocks/_domain_block_list.html.haml new file mode 100644 index 00000000000000..d16c639dd01656 --- /dev/null +++ b/app/views/admin/domain_blocks/_domain_block_list.html.haml @@ -0,0 +1,44 @@ +%h4= I18n.t('admin.domain_blocks.headers.harassment') + +.fields-group + = f.input :reject_favourite, as: :boolean, kmyblue: true, wrapper: :with_label, label: I18n.t('admin.domain_blocks.reject_favourite'), hint: I18n.t('admin.domain_blocks.reject_favourite_hint') + +.fields-group + = f.input :reject_reply, as: :boolean, kmyblue: true, wrapper: :with_label, label: I18n.t('admin.domain_blocks.reject_reply'), hint: I18n.t('admin.domain_blocks.reject_reply_hint') + +.fields-group + = f.input :reject_reply_exclude_followers, as: :boolean, kmyblue: true, wrapper: :with_label, label: I18n.t('admin.domain_blocks.reject_reply_exclude_followers'), hint: I18n.t('admin.domain_blocks.reject_reply_exclude_followers_hint') + +.fields-group + = f.input :reject_hashtag, as: :boolean, kmyblue: true, wrapper: :with_label, label: I18n.t('admin.domain_blocks.reject_hashtag'), hint: I18n.t('admin.domain_blocks.reject_hashtag_hint') + +.fields-group + = f.input :reject_straight_follow, as: :boolean, kmyblue: true, wrapper: :with_label, label: I18n.t('admin.domain_blocks.reject_straight_follow'), hint: I18n.t('admin.domain_blocks.reject_straight_follow_hint') + +.fields-group + = f.input :reject_new_follow, as: :boolean, kmyblue: true, wrapper: :with_label, label: I18n.t('admin.domain_blocks.reject_new_follow'), hint: I18n.t('admin.domain_blocks.reject_new_follow_hint') + +.fields-group + = f.input :reject_friend, as: :boolean, kmyblue: true, wrapper: :with_label, label: I18n.t('admin.domain_blocks.reject_friend'), hint: I18n.t('admin.domain_blocks.reject_friend_hint') + +%h4= I18n.t('admin.domain_blocks.headers.invalid_privacy') + +.fields-group + = f.input :reject_send_not_public_searchability, as: :boolean, kmyblue: true, wrapper: :with_label, label: I18n.t('admin.domain_blocks.reject_send_not_public_searchability'), hint: I18n.t('admin.domain_blocks.reject_send_not_public_searchability_hint') + +.fields-group + = f.input :reject_send_dissubscribable, as: :boolean, kmyblue: true, wrapper: :with_label, label: I18n.t('admin.domain_blocks.reject_send_dissubscribable'), hint: I18n.t('admin.domain_blocks.reject_send_dissubscribable_hint') + +.fields-group + = f.input :detect_invalid_subscription, as: :boolean, kmyblue: true, wrapper: :with_label, label: I18n.t('admin.domain_blocks.detect_invalid_subscription'), hint: I18n.t('admin.domain_blocks.detect_invalid_subscription_hint') + +%h4= I18n.t('admin.domain_blocks.headers.disagreement') + +.fields-group + = f.input :reject_send_public_unlisted, as: :boolean, kmyblue: true, wrapper: :with_label, label: I18n.t('admin.domain_blocks.reject_send_public_unlisted'), hint: I18n.t('admin.domain_blocks.reject_send_public_unlisted_hint') + +.fields-group + = f.input :reject_send_media, as: :boolean, kmyblue: true, wrapper: :with_label, label: I18n.t('admin.domain_blocks.reject_send_media'), hint: I18n.t('admin.domain_blocks.reject_send_media_hint') + +.fields-group + = f.input :reject_send_sensitive, as: :boolean, kmyblue: true, wrapper: :with_label, label: I18n.t('admin.domain_blocks.reject_send_sensitive'), hint: I18n.t('admin.domain_blocks.reject_send_sensitive_hint') diff --git a/app/views/admin/domain_blocks/edit.html.haml b/app/views/admin/domain_blocks/edit.html.haml index cf83d383e9fcee..7454d81539e525 100644 --- a/app/views/admin/domain_blocks/edit.html.haml +++ b/app/views/admin/domain_blocks/edit.html.haml @@ -11,47 +11,12 @@ .fields-row__column.fields-row__column-6.fields-group = f.input :severity, collection: DomainBlock.severities.keys, wrapper: :with_label, include_blank: false, label_method: ->(type) { t("admin.domain_blocks.new.severity.#{type}") }, hint: t('admin.domain_blocks.new.severity.desc_html') - .fields-group - = f.input :reject_media, as: :boolean, wrapper: :with_label, label: I18n.t('admin.domain_blocks.reject_media'), hint: I18n.t('admin.domain_blocks.reject_media_hint') - - .fields-group - = f.input :reject_favourite, as: :boolean, wrapper: :with_label, label: I18n.t('admin.domain_blocks.reject_favourite'), hint: I18n.t('admin.domain_blocks.reject_favourite_hint') - - .fields-group - = f.input :reject_reply, as: :boolean, wrapper: :with_label, label: I18n.t('admin.domain_blocks.reject_reply'), hint: I18n.t('admin.domain_blocks.reject_reply_hint') - - .fields-group - = f.input :reject_reply_exclude_followers, as: :boolean, wrapper: :with_label, label: I18n.t('admin.domain_blocks.reject_reply_exclude_followers'), hint: I18n.t('admin.domain_blocks.reject_reply_exclude_followers_hint') - - .fields-group - = f.input :reject_send_not_public_searchability, as: :boolean, wrapper: :with_label, label: I18n.t('admin.domain_blocks.reject_send_not_public_searchability'), hint: I18n.t('admin.domain_blocks.reject_send_not_public_searchability_hint') - - .fields-group - = f.input :reject_send_dissubscribable, as: :boolean, wrapper: :with_label, label: I18n.t('admin.domain_blocks.reject_send_dissubscribable'), hint: I18n.t('admin.domain_blocks.reject_send_dissubscribable_hint') - - .fields-group - = f.input :reject_send_public_unlisted, as: :boolean, wrapper: :with_label, label: I18n.t('admin.domain_blocks.reject_send_public_unlisted'), hint: I18n.t('admin.domain_blocks.reject_send_public_unlisted_hint') - - .fields-group - = f.input :reject_send_media, as: :boolean, wrapper: :with_label, label: I18n.t('admin.domain_blocks.reject_send_media'), hint: I18n.t('admin.domain_blocks.reject_send_media_hint') + = render 'domain_block_list', f: f - .fields-group - = f.input :reject_send_sensitive, as: :boolean, wrapper: :with_label, label: I18n.t('admin.domain_blocks.reject_send_sensitive'), hint: I18n.t('admin.domain_blocks.reject_send_sensitive_hint') + %h4= I18n.t('admin.domain_blocks.headers.mastodon_default') .fields-group - = f.input :reject_hashtag, as: :boolean, wrapper: :with_label, label: I18n.t('admin.domain_blocks.reject_hashtag'), hint: I18n.t('admin.domain_blocks.reject_hashtag_hint') - - .fields-group - = f.input :reject_straight_follow, as: :boolean, wrapper: :with_label, label: I18n.t('admin.domain_blocks.reject_straight_follow'), hint: I18n.t('admin.domain_blocks.reject_straight_follow_hint') - - .fields-group - = f.input :reject_new_follow, as: :boolean, wrapper: :with_label, label: I18n.t('admin.domain_blocks.reject_new_follow'), hint: I18n.t('admin.domain_blocks.reject_new_follow_hint') - - .fields-group - = f.input :reject_friend, as: :boolean, wrapper: :with_label, label: I18n.t('admin.domain_blocks.reject_friend'), hint: I18n.t('admin.domain_blocks.reject_friend_hint') - - .fields-group - = f.input :detect_invalid_subscription, as: :boolean, wrapper: :with_label, label: I18n.t('admin.domain_blocks.detect_invalid_subscription'), hint: I18n.t('admin.domain_blocks.detect_invalid_subscription_hint') + = f.input :reject_media, as: :boolean, wrapper: :with_label, label: I18n.t('admin.domain_blocks.reject_media'), hint: I18n.t('admin.domain_blocks.reject_media_hint') .fields-group = f.input :reject_reports, as: :boolean, wrapper: :with_label, label: I18n.t('admin.domain_blocks.reject_reports'), hint: I18n.t('admin.domain_blocks.reject_reports_hint') @@ -69,7 +34,7 @@ = f.input :hidden, as: :boolean, wrapper: :with_label, label: I18n.t('admin.domain_blocks.hidden'), hint: I18n.t('admin.domain_blocks.hidden_hint') .fields-group - = f.input :hidden_anonymous, as: :boolean, wrapper: :with_label, label: I18n.t('admin.domain_blocks.hidden_anonymous'), hint: I18n.t('admin.domain_blocks.hidden_anonymous_hint') + = f.input :hidden_anonymous, kmyblue: true, as: :boolean, wrapper: :with_label, label: I18n.t('admin.domain_blocks.hidden_anonymous'), hint: I18n.t('admin.domain_blocks.hidden_anonymous_hint') .actions = f.button :button, t('generic.save_changes'), type: :submit diff --git a/app/views/admin/domain_blocks/new.html.haml b/app/views/admin/domain_blocks/new.html.haml index ed5142934fd675..ad25fcebbd3411 100644 --- a/app/views/admin/domain_blocks/new.html.haml +++ b/app/views/admin/domain_blocks/new.html.haml @@ -11,47 +11,12 @@ .fields-row__column.fields-row__column-6.fields-group = f.input :severity, collection: DomainBlock.severities.keys, wrapper: :with_label, include_blank: false, label_method: ->(type) { t(".severity.#{type}") }, hint: t('.severity.desc_html') - .fields-group - = f.input :reject_media, as: :boolean, wrapper: :with_label, label: I18n.t('admin.domain_blocks.reject_media'), hint: I18n.t('admin.domain_blocks.reject_media_hint') - - .fields-group - = f.input :reject_favourite, as: :boolean, wrapper: :with_label, label: I18n.t('admin.domain_blocks.reject_favourite'), hint: I18n.t('admin.domain_blocks.reject_favourite_hint') - - .fields-group - = f.input :reject_reply, as: :boolean, wrapper: :with_label, label: I18n.t('admin.domain_blocks.reject_reply'), hint: I18n.t('admin.domain_blocks.reject_reply_hint') - - .fields-group - = f.input :reject_reply_exclude_followers, as: :boolean, wrapper: :with_label, label: I18n.t('admin.domain_blocks.reject_reply_exclude_followers'), hint: I18n.t('admin.domain_blocks.reject_reply_exclude_followers_hint') - - .fields-group - = f.input :reject_send_not_public_searchability, as: :boolean, wrapper: :with_label, label: I18n.t('admin.domain_blocks.reject_send_not_public_searchability'), hint: I18n.t('admin.domain_blocks.reject_send_not_public_searchability_hint') - - .fields-group - = f.input :reject_send_dissubscribable, as: :boolean, wrapper: :with_label, label: I18n.t('admin.domain_blocks.reject_send_dissubscribable'), hint: I18n.t('admin.domain_blocks.reject_send_dissubscribable_hint') - - .fields-group - = f.input :reject_send_public_unlisted, as: :boolean, wrapper: :with_label, label: I18n.t('admin.domain_blocks.reject_send_public_unlisted'), hint: I18n.t('admin.domain_blocks.reject_send_public_unlisted_hint') - - .fields-group - = f.input :reject_send_media, as: :boolean, wrapper: :with_label, label: I18n.t('admin.domain_blocks.reject_send_media'), hint: I18n.t('admin.domain_blocks.reject_send_media_hint') + = render 'domain_block_list', f: f - .fields-group - = f.input :reject_send_sensitive, as: :boolean, wrapper: :with_label, label: I18n.t('admin.domain_blocks.reject_send_sensitive'), hint: I18n.t('admin.domain_blocks.reject_send_sensitive_hint') + %h4= I18n.t('admin.domain_blocks.headers.mastodon_default') .fields-group - = f.input :reject_hashtag, as: :boolean, wrapper: :with_label, label: I18n.t('admin.domain_blocks.reject_hashtag'), hint: I18n.t('admin.domain_blocks.reject_hashtag_hint') - - .fields-group - = f.input :reject_straight_follow, as: :boolean, wrapper: :with_label, label: I18n.t('admin.domain_blocks.reject_straight_follow'), hint: I18n.t('admin.domain_blocks.reject_straight_follow_hint') - - .fields-group - = f.input :reject_new_follow, as: :boolean, wrapper: :with_label, label: I18n.t('admin.domain_blocks.reject_new_follow'), hint: I18n.t('admin.domain_blocks.reject_new_follow_hint') - - .fields-group - = f.input :reject_friend, as: :boolean, wrapper: :with_label, label: I18n.t('admin.domain_blocks.reject_friend'), hint: I18n.t('admin.domain_blocks.reject_friend_hint') - - .fields-group - = f.input :detect_invalid_subscription, as: :boolean, wrapper: :with_label, label: I18n.t('admin.domain_blocks.detect_invalid_subscription'), hint: I18n.t('admin.domain_blocks.detect_invalid_subscription_hint') + = f.input :reject_media, as: :boolean, wrapper: :with_label, label: I18n.t('admin.domain_blocks.reject_media'), hint: I18n.t('admin.domain_blocks.reject_media_hint') .fields-group = f.input :reject_reports, as: :boolean, wrapper: :with_label, label: I18n.t('admin.domain_blocks.reject_reports'), hint: I18n.t('admin.domain_blocks.reject_reports_hint') @@ -69,7 +34,7 @@ = f.input :hidden, as: :boolean, wrapper: :with_label, label: I18n.t('admin.domain_blocks.hidden'), hint: I18n.t('admin.domain_blocks.hidden_hint') .fields-group - = f.input :hidden_anonymous, as: :boolean, wrapper: :with_label, label: I18n.t('admin.domain_blocks.hidden_anonymous'), hint: I18n.t('admin.domain_blocks.hidden_anonymous_hint') + = f.input :hidden_anonymous, kmyblue: true, as: :boolean, wrapper: :with_label, label: I18n.t('admin.domain_blocks.hidden_anonymous'), hint: I18n.t('admin.domain_blocks.hidden_anonymous_hint') .actions = f.button :button, t('.create'), type: :submit diff --git a/config/locales/en.yml b/config/locales/en.yml index 747545112824bb..85db9c5a66cbb3 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -415,6 +415,11 @@ en: existing_domain_block: You have already imposed stricter limits on %{name}. existing_domain_block_html: You have already imposed stricter limits on %{name}, you need to unblock it first. export: Export + headers: + disagreement: Protect sensitive posts from political disagreement + harassment: Harassment or spam + invalid_privacy: Privacy is not protected + mastodon_default: Original Mastodon supports import: Import new: create: Create block diff --git a/config/locales/ja.yml b/config/locales/ja.yml index e0539d21501b7f..a5fbf480a12062 100644 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@ -402,12 +402,17 @@ ja: created_msg: ドメインブロック処理を完了しました destroyed_msg: ドメインブロックを外しました detect_invalid_subscription: 不正な購読を行うサーバーとしてマークする - detect_invalid_subscription_hint: Misskey、Calckeyなどは購読機能で未フォローユーザーの未収載投稿を拾います。これをマークしたサーバーは、ユーザーが任意で配送を拒否できます。停止とは無関係です + detect_invalid_subscription_hint: 未フォローユーザーの未収載投稿が自由に購読・検索できるサーバーとしてマークします。Misskeyサーバーはこのチェックに関係なく、自動で制限が有効とみなされます。各ユーザーはそれぞれのプライバシー追加設定でMisskeyサーバーへの配送制限を有効にすることで、これらのサーバーへローカル公開・未収載投稿を鍵付きで配信できるようになります。停止とは無関係です domain: ドメイン edit: ドメインブロックを編集 existing_domain_block: あなたは既に%{name}さんに厳しい制限を課しています。 existing_domain_block_html: 既に%{name}に対して、より厳しい制限を課しています。先にその制限を解除する必要があります。 export: エクスポート + headers: + disagreement: 政治的な意見の相違からの敏感な投稿の保護 + harassment: 嫌がらせまたはスパム + invalid_privacy: プライバシーが守られていない + mastodon_default: 本家Mastodonの設定項目 hidden: 非公開にする hidden_hint: 公開することで当サーバーの安全が脅かされる場合、このドメインブロックを非公開にすることができます。 hidden_anonymous: 未ログインユーザーに非公開にする From bcb3acdccd29253fcc0138f4d17f3f04b5f9af41 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: Sun, 22 Oct 2023 09:56:43 +0900 Subject: [PATCH 8/8] =?UTF-8?q?Fix:=20=E3=83=95=E3=83=AC=E3=83=B3=E3=83=89?= =?UTF-8?q?=E3=82=B5=E3=83=BC=E3=83=90=E3=83=BC=E3=81=8A=E3=82=88=E3=81=B3?= =?UTF-8?q?Misskey=E3=81=A7=E7=B7=A8=E9=9B=86=E3=81=8C=E9=80=A3=E5=90=88?= =?UTF-8?q?=E3=81=A7=E3=81=8D=E3=81=AA=E3=81=84=E5=95=8F=E9=A1=8C=20(#168)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix: フレンドサーバー間で編集が機能しない問題 * リファクタリング --- .../status_update_distribution_worker.rb | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/app/workers/activitypub/status_update_distribution_worker.rb b/app/workers/activitypub/status_update_distribution_worker.rb index a79ede2bf61104..a7081bed8e5e37 100644 --- a/app/workers/activitypub/status_update_distribution_worker.rb +++ b/app/workers/activitypub/status_update_distribution_worker.rb @@ -15,15 +15,27 @@ def perform(status_id, options = {}) protected - def activity + def build_activity(for_misskey: false, for_friend: false) ActivityPub::ActivityPresenter.new( id: [ActivityPub::TagManager.instance.uri_for(@status), '#updates/', @status.edited_at.to_i].join, type: 'Update', actor: ActivityPub::TagManager.instance.uri_for(@status.account), published: @status.edited_at, - to: ActivityPub::TagManager.instance.to(@status), - cc: ActivityPub::TagManager.instance.cc(@status), + to: for_friend ? ActivityPub::TagManager.instance.to_for_friend(@status) : ActivityPub::TagManager.instance.to(@status), + cc: for_misskey ? ActivityPub::TagManager.instance.cc_for_misskey : ActivityPub::TagManager.instance.cc(@status), virtual_object: @status ) end + + def activity + build_activity + end + + def activity_for_misskey + build_activity(for_misskey: true) + end + + def activity_for_friend + build_activity(for_friend: true) + end end