diff --git a/app/controllers/admin/domain_blocks_controller.rb b/app/controllers/admin/domain_blocks_controller.rb index 750f5c995c..48f2fdbbf6 100644 --- a/app/controllers/admin/domain_blocks_controller.rb +++ b/app/controllers/admin/domain_blocks_controller.rb @@ -78,15 +78,15 @@ module Admin end def update_params - params.require(:domain_block).permit(:severity, :reject_media, :reject_reports, :private_comment, :public_comment, :obfuscate) + params.require(:domain_block).permit(:severity, :reject_media, :reject_favourite, :reject_reply, :reject_send_not_public_searchability, :reject_send_unlisted_dissubscribable, :reject_send_public_unlisted, :reject_send_dissubscribable, :reject_send_media, :reject_send_sensitive, :reject_hashtag, :reject_straight_follow, :reject_new_follow, :reject_reports, :private_comment, :public_comment, :obfuscate, :hidden, :hidden_anonymous) end def resource_params - params.require(:domain_block).permit(:domain, :severity, :reject_media, :reject_reports, :private_comment, :public_comment, :obfuscate) + params.require(:domain_block).permit(:domain, :severity, :reject_media, :reject_favourite, :reject_reply, :reject_send_not_public_searchability, :reject_send_unlisted_dissubscribable, :reject_send_public_unlisted, :reject_send_dissubscribable, :reject_send_media, :reject_send_sensitive, :reject_hashtag, :reject_straight_follow, :reject_new_follow, :reject_reports, :private_comment, :public_comment, :obfuscate, :hidden, :hidden_anonymous) end def form_domain_block_batch_params - params.require(:form_domain_block_batch).permit(domain_blocks_attributes: [:enabled, :domain, :severity, :reject_media, :reject_reports, :private_comment, :public_comment, :obfuscate]) + params.require(:form_domain_block_batch).permit(domain_blocks_attributes: [:enabled, :domain, :severity, :reject_media, :reject_favourite, :reject_reply, :reject_send_not_public_searchability, :reject_send_unlisted_dissubscribable, :reject_send_public_unlisted, :reject_send_dissubscribable, :reject_send_media, :reject_send_sensitive, :reject_hashtag, :reject_straight_follow, :reject_new_follow, :reject_reports, :private_comment, :public_comment, :obfuscate, :hidden, :hidden_anonymous]) end def action_from_button diff --git a/app/controllers/api/v1/admin/domain_blocks_controller.rb b/app/controllers/api/v1/admin/domain_blocks_controller.rb index 8b77e9717d..a981fba005 100644 --- a/app/controllers/api/v1/admin/domain_blocks_controller.rb +++ b/app/controllers/api/v1/admin/domain_blocks_controller.rb @@ -69,7 +69,7 @@ class Api::V1::Admin::DomainBlocksController < Api::BaseController end def domain_block_params - params.permit(:severity, :reject_media, :reject_reports, :private_comment, :public_comment, :obfuscate) + params.permit(:severity, :reject_media, :reject_favourite, :reject_reply, :reject_reports, :reject_send_not_public_searchability, :reject_send_unlisted_dissubscribable, :reject_send_public_unlisted, :reject_send_dissubscribable, :reject_send_media, :reject_send_sensitive, :reject_hashtag, :reject_straight_follow, :reject_new_follow, :private_comment, :public_comment, :obfuscate, :hidden, :hidden_anonymous) end def insert_pagination_headers @@ -101,6 +101,6 @@ class Api::V1::Admin::DomainBlocksController < Api::BaseController end def resource_params - params.permit(:domain, :severity, :reject_media, :reject_reports, :private_comment, :public_comment, :obfuscate) + params.permit(:domain, :severity, :reject_media, :reject_favourite, :reject_reply, :reject_send_not_public_searchability, :reject_send_unlisted_dissubscribable, :reject_send_public_unlisted, :reject_send_dissubscribable, :reject_send_media, :reject_send_sensitive, :reject_hashtag, :reject_straight_follow, :reject_new_follow, :reject_reports, :private_comment, :public_comment, :obfuscate, :hidden, :hidden_anonymous) end end diff --git a/app/controllers/api/v1/instances/domain_blocks_controller.rb b/app/controllers/api/v1/instances/domain_blocks_controller.rb index e954c45897..15fba7ecd1 100644 --- a/app/controllers/api/v1/instances/domain_blocks_controller.rb +++ b/app/controllers/api/v1/instances/domain_blocks_controller.rb @@ -26,5 +26,6 @@ class Api::V1::Instances::DomainBlocksController < Api::BaseController def set_domain_blocks @domain_blocks = DomainBlock.with_user_facing_limitations.by_severity + @domain_blocks = @domain_blocks.filter { |block| !block.hidden_anonymous } if !user_signed_in? end end diff --git a/app/javascript/mastodon/features/about/index.jsx b/app/javascript/mastodon/features/about/index.jsx index bb35f3203b..47d88fcf6c 100644 --- a/app/javascript/mastodon/features/about/index.jsx +++ b/app/javascript/mastodon/features/about/index.jsx @@ -17,6 +17,8 @@ const messages = defineMessages({ title: { id: 'column.about', defaultMessage: 'About' }, rules: { id: 'about.rules', defaultMessage: 'Server rules' }, blocks: { id: 'about.blocks', defaultMessage: 'Moderated servers' }, + noop: { id: 'about.domain_blocks.noop.title', defaultMessage: 'Soft limited' }, + noopExplanation: { id: 'about.domain_blocks.noop.explanation', defaultMessage: 'This server is limited partically.' }, silenced: { id: 'about.domain_blocks.silenced.title', defaultMessage: 'Limited' }, silencedExplanation: { id: 'about.domain_blocks.silenced.explanation', defaultMessage: 'You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.' }, suspended: { id: 'about.domain_blocks.suspended.title', defaultMessage: 'Suspended' }, @@ -33,6 +35,11 @@ const severityMessages = { title: messages.suspended, explanation: messages.suspendedExplanation, }, + + noop: { + title: messages.noop, + explanation: messages.noopExplanation, + }, }; const mapStateToProps = state => ({ @@ -186,7 +193,7 @@ class About extends React.PureComponent {
{block.get('domain')}
- {intl.formatMessage(severityMessages[block.get('severity')].title)} + {intl.formatMessage(severityMessages[block.get('severity_ex') || block.get('severity')].title)}

{(block.get('comment') || '').length > 0 ? block.get('comment') : }

diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json index 28a53a8d17..7cfade1cc7 100644 --- a/app/javascript/mastodon/locales/en.json +++ b/app/javascript/mastodon/locales/en.json @@ -4,6 +4,8 @@ "about.disclaimer": "Mastodon is free, open-source software, and a trademark of Mastodon gGmbH.", "about.domain_blocks.no_reason_available": "Reason not available", "about.domain_blocks.preamble": "Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.", + "about.domain_blocks.noop.title": "Soft limited", + "about.domain_blocks.noop.explanation": "This server is limited partically.", "about.domain_blocks.silenced.explanation": "You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.", "about.domain_blocks.silenced.title": "Limited", "about.domain_blocks.suspended.explanation": "No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.", diff --git a/app/javascript/mastodon/locales/ja.json b/app/javascript/mastodon/locales/ja.json index fd6118a5c7..985e46b020 100644 --- a/app/javascript/mastodon/locales/ja.json +++ b/app/javascript/mastodon/locales/ja.json @@ -5,6 +5,8 @@ "about.domain_blocks.no_reason_available": "制限理由", "about.domain_blocks.preamble": "Mastodonでは連合先のどのようなサーバーのユーザーとも交流できます。ただし次のサーバーには例外が設定されています。", "about.domain_blocks.silenced.explanation": "このサーバーのプロフィールやコンテンツは、明示的に検索したり、フォローでオプトインしない限り、通常は表示されません。", + "about.domain_blocks.noop.title": "一部制限", + "about.domain_blocks.noop.explanation": "このサーバーは部分的に制限されています。", "about.domain_blocks.silenced.title": "制限", "about.domain_blocks.suspended.explanation": "これらのサーバーからのデータは処理されず、保存や変換もされません。該当するユーザーとの交流もできません。", "about.domain_blocks.suspended.title": "停止済み", diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index fc41023806..d125a3db8c 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -9280,12 +9280,6 @@ noscript { overflow: hidden; text-overflow: ellipsis; } - - p { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - } } } } diff --git a/app/lib/activitypub/activity/create.rb b/app/lib/activitypub/activity/create.rb index 95009e0081..6a305c90b9 100644 --- a/app/lib/activitypub/activity/create.rb +++ b/app/lib/activitypub/activity/create.rb @@ -215,7 +215,7 @@ class ActivityPub::Activity::Create < ActivityPub::Activity end def process_hashtag(tag) - return if tag['name'].blank? + return if tag['name'].blank? || ignore_hashtags? Tag.find_or_create_by_names(tag['name']) do |hashtag| @tags << hashtag unless @tags.include?(hashtag) || !hashtag.valid? @@ -392,6 +392,14 @@ class ActivityPub::Activity::Create < ActivityPub::Activity !replied_to_status.nil? && replied_to_status.account.local? end + def reject_reply_to_local? + @reject_reply_to_local ||= DomainBlock.reject_reply?(@account.domain) + end + + def ignore_hashtags? + @ignore_hashtags ||= DomainBlock.reject_hashtag?(@account.domain) + end + def related_to_local_activity? fetch? || followed_by_local_accounts? || requested_through_relay? || responds_to_followed_account? || addresses_local_accounts? diff --git a/app/lib/activitypub/activity/follow.rb b/app/lib/activitypub/activity/follow.rb index 97e41ab789..3714648c01 100644 --- a/app/lib/activitypub/activity/follow.rb +++ b/app/lib/activitypub/activity/follow.rb @@ -15,7 +15,7 @@ class ActivityPub::Activity::Follow < ActivityPub::Activity return end - if target_account.blocking?(@account) || target_account.domain_blocking?(@account.domain) || target_account.moved? || target_account.instance_actor? + if target_account.blocking?(@account) || target_account.domain_blocking?(@account.domain) || target_account.moved? || target_account.instance_actor? || block_new_follow? reject_follow_request!(target_account) return end @@ -30,7 +30,7 @@ class ActivityPub::Activity::Follow < ActivityPub::Activity follow_request = FollowRequest.create!(account: @account, target_account: target_account, uri: @json['id']) - if target_account.locked? || @account.silenced? + if target_account.locked? || @account.silenced? || block_straight_follow? LocalNotificationWorker.perform_async(target_account.id, follow_request.id, 'FollowRequest', 'follow_request') else AuthorizeFollowService.new.call(@account, target_account) @@ -42,4 +42,12 @@ class ActivityPub::Activity::Follow < ActivityPub::Activity json = Oj.dump(serialize_payload(FollowRequest.new(account: @account, target_account: target_account, uri: @json['id']), ActivityPub::RejectFollowSerializer)) ActivityPub::DeliveryWorker.perform_async(json, target_account.id, @account.inbox_url) end + + def block_straight_follow? + @block_straight_follow ||= DomainBlock.reject_straight_follow?(@account.domain) + end + + def block_new_follow? + @block_new_follow ||= DomainBlock.reject_new_follow?(@account.domain) + end end diff --git a/app/lib/status_reach_finder.rb b/app/lib/status_reach_finder.rb index cbcc0e6b61..63a4f23740 100644 --- a/app/lib/status_reach_finder.rb +++ b/app/lib/status_reach_finder.rb @@ -22,7 +22,7 @@ class StatusReachFinder if @status.reblog? [] else - Account.where(id: reached_account_ids).inboxes + Account.where(id: reached_account_ids).where.not(domain: banned_domains).inboxes end end @@ -74,7 +74,7 @@ class StatusReachFinder elsif @status.direct_visibility? || @status.limited_visibility? [] else - @status.account.followers.inboxes + @status.account.followers.where.not(domain: banned_domains).inboxes end end @@ -93,4 +93,16 @@ class StatusReachFinder def unsafe? @options[:unsafe] end + + def banned_domains + return @banned_domains if @banned_domains + blocks = [] + blocks << DomainBlock.where(reject_send_not_public_searchability: true).pluck(:domain) if @status.compute_searchability != 'public' + blocks << DomainBlock.where(reject_send_unlisted_dissubscribable: true).pluck(:domain) if @status.unlisted_visibility? && @status.account.dissubscribable + blocks << DomainBlock.where(reject_send_public_unlisted: true).pluck(:domain) if @status.public_unlisted_visibility? + blocks << DomainBlock.where(reject_send_dissubscribable: true).pluck(:domain) if @status.account.dissubscribable + blocks << DomainBlock.where(reject_send_media: true).pluck(:domain) if @status.with_media? + blocks << DomainBlock.where(reject_send_sensitive: true).pluck(:domain) if (@status.with_media? && @status.sensitive) || @status.spoiler_text + return @banned_domains = blocks.uniq + end end diff --git a/app/models/account.rb b/app/models/account.rb index 94660ed494..28e669be97 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -112,8 +112,8 @@ class Account < ApplicationRecord scope :bots, -> { where(actor_type: %w(Application Service)) } scope :groups, -> { where(actor_type: 'Group') } scope :alphabetic, -> { order(domain: :asc, username: :asc) } - scope :matches_username, ->(value) { where('lower((username)::text) LIKE lower(?)', "#{value}%") } - scope :matches_display_name, ->(value) { where(arel_table[:display_name].matches("#{value}%")) } + scope :matches_username, ->(value) { where('lower((username)::text) ~ lower(?)', "#{value}") } + scope :matches_display_name, ->(value) { where(arel_table[:display_name].matches_regexp("#{value}")) } scope :matches_domain, ->(value) { where(arel_table[:domain].matches("%#{value}%")) } scope :without_unapproved, -> { left_outer_joins(:user).remote.or(left_outer_joins(:user).merge(User.approved.confirmed)) } scope :searchable, -> { without_unapproved.without_suspended.where(moved_to_account_id: nil) } diff --git a/app/models/account_statuses_filter.rb b/app/models/account_statuses_filter.rb index 068ab329e9..d0a1cc5518 100644 --- a/app/models/account_statuses_filter.rb +++ b/app/models/account_statuses_filter.rb @@ -26,13 +26,20 @@ class AccountStatusesFilter scope.merge!(no_reblogs_scope) if exclude_reblogs? scope.merge!(hashtag_scope) if tagged? + scope.merge!(scope.where(searchability: :public)) if domain_block&.reject_send_not_public_searchability + scope.merge!(scope.where.not(visibility: :unlisted)) if domain_block&.reject_send_unlisted_dissubscribable && @account.dissubscribable + scope.merge!(scope.where.not(visibility: :public_unlisted)) if domain_block&.reject_send_public_unlisted + scope.merge!(scope.where(spoiler_text: ['', nil])) if domain_block&.reject_send_sensitive + scope end private def initial_scope - if suspended? + if suspended? || (domain_block&.reject_send_dissubscribable && @account.dissubscribable) + Status.none + elsif domain_block&.reject_send_media Status.none elsif anonymous? account.statuses.where(visibility: %i(public unlisted public_unlisted)) @@ -131,4 +138,8 @@ class AccountStatusesFilter def truthy_param?(key) ActiveModel::Type::Boolean.new.cast(params[key]) end + + def domain_block + @domain_block = DomainBlock.find_by(domain: @account&.domain) + end end diff --git a/app/models/domain_block.rb b/app/models/domain_block.rb index fbb045416c..f0cb28feec 100644 --- a/app/models/domain_block.rb +++ b/app/models/domain_block.rb @@ -4,16 +4,29 @@ # # Table name: domain_blocks # -# id :bigint(8) not null, primary key -# domain :string default(""), not null -# created_at :datetime not null -# updated_at :datetime not null -# severity :integer default("silence") -# reject_media :boolean default(FALSE), not null -# reject_reports :boolean default(FALSE), not null -# private_comment :text -# public_comment :text -# obfuscate :boolean default(FALSE), not null +# id :bigint(8) not null, primary key +# domain :string default(""), not null +# created_at :datetime not null +# updated_at :datetime not null +# severity :integer default("silence") +# reject_media :boolean default(FALSE), not null +# reject_reports :boolean default(FALSE), not null +# private_comment :text +# public_comment :text +# obfuscate :boolean default(FALSE), not null +# reject_favourite :boolean default(FALSE), not null +# reject_reply :boolean default(FALSE), not null +# reject_send_not_public_searchability :boolean default(FALSE), not null +# reject_send_unlisted_dissubscribable :boolean default(FALSE), not null +# reject_send_public_unlisted :boolean default(FALSE), not null +# reject_send_dissubscribable :boolean default(FALSE), not null +# reject_send_media :boolean default(FALSE), not null +# reject_send_sensitive :boolean default(FALSE), not null +# reject_hashtag :boolean default(FALSE), not null +# reject_straight_follow :boolean default(FALSE), not null +# reject_new_follow :boolean default(FALSE), not null +# hidden :boolean default(FALSE), not null +# hidden_anonymous :boolean default(FALSE), not null # class DomainBlock < ApplicationRecord @@ -29,8 +42,8 @@ class DomainBlock < ApplicationRecord delegate :count, to: :accounts, prefix: true scope :matches_domain, ->(value) { where(arel_table[:domain].matches("%#{value}%")) } - scope :with_user_facing_limitations, -> { where(severity: [:silence, :suspend]) } - scope :with_limitations, -> { where(severity: [:silence, :suspend]).or(where(reject_media: true)) } + scope :with_user_facing_limitations, -> { where(hidden: false) } + scope :with_limitations, -> { where(severity: [:silence, :suspend]).or(where(reject_media: true)).or(where(reject_favourite: true)).or(where(reject_reply: true)).or(where(reject_new_follow: true)).or(where(reject_straight_follow: true)) } scope :by_severity, -> { order(Arel.sql('(CASE severity WHEN 0 THEN 1 WHEN 1 THEN 2 WHEN 2 THEN 0 END), domain')) } def to_log_human_identifier @@ -41,7 +54,21 @@ class DomainBlock < ApplicationRecord if suspend? [:suspend] else - [severity.to_sym, reject_media? ? :reject_media : nil, reject_reports? ? :reject_reports : nil].reject { |policy| policy == :noop || policy.nil? } + [severity.to_sym, + reject_media? ? :reject_media : nil, + reject_favourite? ? :reject_favourite : nil, + reject_reply? ? :reject_reply : nil, + reject_send_not_public_searchability? ? :reject_send_not_public_searchability : nil, + reject_send_unlisted_dissubscribable? ? :reject_send_unlisted_dissubscribable : nil, + reject_send_public_unlisted? ? :reject_send_public_unlisted : nil, + reject_send_dissubscribable? ? :reject_send_dissubscribable : nil, + reject_send_media? ? :reject_send_media : nil, + reject_send_sensitive? ? :reject_send_sensitive : nil, + reject_hashtag? ? :reject_hashtag : nil, + reject_straight_follow? ? :reject_straight_follow : nil, + reject_new_follow? ? :reject_new_follow : nil, + reject_reports? ? :reject_reports : nil + ].reject { |policy| policy == :noop || policy.nil? } end end @@ -58,6 +85,26 @@ class DomainBlock < ApplicationRecord !!rule_for(domain)&.reject_media? end + def reject_favourite?(domain) + !!rule_for(domain)&.reject_favourite? + end + + def reject_reply?(domain) + !!rule_for(domain)&.reject_reply? + end + + def reject_hashtag?(domain) + !!rule_for(domain)&.reject_hashtag? + end + + def reject_straight_follow?(domain) + !!rule_for(domain)&.reject_straight_follow? + end + + def reject_new_follow?(domain) + !!rule_for(domain)&.reject_new_follow? + end + def reject_reports?(domain) !!rule_for(domain)&.reject_reports? end diff --git a/app/policies/status_policy.rb b/app/policies/status_policy.rb index a33d1f1112..5d2bf17da6 100644 --- a/app/policies/status_policy.rb +++ b/app/policies/status_policy.rb @@ -18,7 +18,7 @@ class StatusPolicy < ApplicationPolicy elsif private? owned? || following_author? || mention_exists? else - current_account.nil? || (!author_blocking? && !author_blocking_domain?) + current_account.nil? || (!author_blocking? && !author_blocking_domain? && !server_blocking_domain?) end end @@ -99,4 +99,18 @@ class StatusPolicy < ApplicationPolicy def author record.account end + + def server_blocking_domain? + @domain_block = DomainBlock.find_by(domain: current_account&.domain) + if @domain_block + (@domain_block.reject_send_not_public_searchability && record.compute_searchability != 'public') || + (@domain_block.reject_send_unlisted_dissubscribable && record.unlisted_visibility? && record.account.dissubscribable) || + (@domain_block.reject_send_public_unlisted && record.public_unlisted_visibility?) || + (@domain_block.reject_send_dissubscribable && record.account.dissubscribable) || + (@domain_block.reject_send_media && record.with_media?) || + (@domain_block.reject_send_sensitive && ((record.with_media? && record.sensitive) || record.spoiler_text)) + else + false + end + end end diff --git a/app/serializers/rest/admin/domain_block_serializer.rb b/app/serializers/rest/admin/domain_block_serializer.rb index b955d008a6..df167cec70 100644 --- a/app/serializers/rest/admin/domain_block_serializer.rb +++ b/app/serializers/rest/admin/domain_block_serializer.rb @@ -2,7 +2,10 @@ class REST::Admin::DomainBlockSerializer < ActiveModel::Serializer attributes :id, :domain, :created_at, :severity, - :reject_media, :reject_reports, + :reject_media, :reject_favourite, :reject_reply, :reject_reports, + :reject_send_not_public_searchability, :reject_send_unlisted_dissubscribable, + :reject_send_public_unlisted, :reject_send_dissubscribable, :reject_send_media, :reject_send_sensitive, + :reject_hashtag, :reject_straight_follow, :reject_new_follow, :private_comment, :public_comment, :obfuscate def id diff --git a/app/serializers/rest/domain_block_serializer.rb b/app/serializers/rest/domain_block_serializer.rb index 678463e13b..ad352db619 100644 --- a/app/serializers/rest/domain_block_serializer.rb +++ b/app/serializers/rest/domain_block_serializer.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class REST::DomainBlockSerializer < ActiveModel::Serializer - attributes :domain, :digest, :severity, :comment + attributes :domain, :digest, :severity, :severity_ex, :comment def domain object.public_domain @@ -11,6 +11,14 @@ class REST::DomainBlockSerializer < ActiveModel::Serializer object.domain_digest end + def severity + object.severity == 'noop' ? 'silence' : object.severity + end + + def severity_ex + object.severity + end + def comment object.public_comment if instance_options[:with_comment] end diff --git a/app/services/fan_out_on_write_service.rb b/app/services/fan_out_on_write_service.rb index 7ce2b833ec..4d1e604efc 100644 --- a/app/services/fan_out_on_write_service.rb +++ b/app/services/fan_out_on_write_service.rb @@ -131,7 +131,6 @@ class FanOutOnWriteService < BaseService antennas.in_batches do |ans| ans.each do |antenna| next if !antenna.enabled? - next if antenna.keywords.any? && !([nil, :public].include?(@status.searchability&.to_sym)) next if antenna.keywords.any? && !antenna.keywords.any? { |keyword| @status.text.include?(keyword) } next if antenna.exclude_keywords&.any? { |keyword| @status.text.include?(keyword) } next if antenna.exclude_accounts&.include?(@status.account_id) diff --git a/app/services/update_account_service.rb b/app/services/update_account_service.rb index 4604d71b2b..ee5e567292 100644 --- a/app/services/update_account_service.rb +++ b/app/services/update_account_service.rb @@ -21,12 +21,16 @@ class UpdateAccountService < BaseService def authorize_all_follow_requests(account) follow_requests = FollowRequest.where(target_account: account) - follow_requests = follow_requests.preload(:account).select { |req| !req.account.silenced? } + follow_requests = follow_requests.preload(:account).select { |req| !req.account.silenced? && !reject_straight_follow_domains.include?(req.account.domain) } AuthorizeFollowWorker.push_bulk(follow_requests, limit: 1_000) do |req| [req.account_id, req.target_account_id] end end + def reject_straight_follow_domains + DomainBlock.where(reject_straight_follow: true).pluck(:domain) + end + def check_links(account) VerifyAccountLinksWorker.perform_async(account.id) if account.fields.any?(&:requires_verification?) end diff --git a/app/views/admin/domain_blocks/edit.html.haml b/app/views/admin/domain_blocks/edit.html.haml index 39c6d108a7..aea62d51c8 100644 --- a/app/views/admin/domain_blocks/edit.html.haml +++ b/app/views/admin/domain_blocks/edit.html.haml @@ -17,6 +17,39 @@ .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_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_unlisted_dissubscribable, as: :boolean, wrapper: :with_label, label: I18n.t('admin.domain_blocks.reject_send_unlisted_dissubscribable'), hint: I18n.t('admin.domain_blocks.reject_send_unlisted_dissubscribable_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') + + .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') + + .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_reports, as: :boolean, wrapper: :with_label, label: I18n.t('admin.domain_blocks.reject_reports'), hint: I18n.t('admin.domain_blocks.reject_reports_hint') @@ -29,5 +62,11 @@ .field-group = f.input :public_comment, wrapper: :with_label, label: I18n.t('admin.domain_blocks.public_comment'), hint: t('admin.domain_blocks.public_comment_hint'), as: :string + .fields-group + = 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') + .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 bcaa331b56..470cf52cea 100644 --- a/app/views/admin/domain_blocks/new.html.haml +++ b/app/views/admin/domain_blocks/new.html.haml @@ -17,6 +17,39 @@ .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_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_unlisted_dissubscribable, as: :boolean, wrapper: :with_label, label: I18n.t('admin.domain_blocks.reject_send_unlisted_dissubscribable'), hint: I18n.t('admin.domain_blocks.reject_send_unlisted_dissubscribable_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') + + .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') + + .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_reports, as: :boolean, wrapper: :with_label, label: I18n.t('admin.domain_blocks.reject_reports'), hint: I18n.t('admin.domain_blocks.reject_reports_hint') @@ -29,5 +62,11 @@ .field-group = f.input :public_comment, wrapper: :with_label, label: I18n.t('admin.domain_blocks.public_comment'), hint: t('admin.domain_blocks.public_comment_hint'), as: :string + .fields-group + = 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') + .actions = f.button :button, t('.create'), type: :submit diff --git a/app/views/admin/export_domain_blocks/_domain_block.html.haml b/app/views/admin/export_domain_blocks/_domain_block.html.haml index 5d4b6c4d0d..8054b5ab2a 100644 --- a/app/views/admin/export_domain_blocks/_domain_block.html.haml +++ b/app/views/admin/export_domain_blocks/_domain_block.html.haml @@ -10,6 +10,17 @@ = f.hidden_field :domain = f.hidden_field :severity = f.hidden_field :reject_media + = f.hidden_field :reject_favourite + = f.hidden_field :reject_reply + = f.hidden_field :reject_send_not_public_searchability + = f.hidden_field :reject_send_unlisted_dissubscribable + = f.hidden_field :reject_send_public_unlisted + = f.hidden_field :reject_send_dissubscribable + = f.hidden_field :reject_send_media + = f.hidden_field :reject_send_sensitive + = f.hidden_field :reject_hashtag + = f.hidden_field :reject_straight_follow + = f.hidden_field :reject_new_follow = f.hidden_field :reject_reports = f.hidden_field :obfuscate = f.hidden_field :private_comment diff --git a/config/locales/en.yml b/config/locales/en.yml index eaa457b93f..0037b9329a 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -412,10 +412,32 @@ en: private_comment_hint: Comment about this domain limitation for internal use by the moderators. public_comment: Public comment public_comment_hint: Comment about this domain limitation for the general public, if advertising the list of domain limitations is enabled. + reject_favourite: Reject favourites + reject_favourite_hint: Reject favourites or emoji-reaction in the future + reject_hashtag: Reject hashtags + reject_hashtag_hint: Reject hashtags in the future reject_media: Reject media files reject_media_hint: Removes locally stored media files and refuses to download any in the future. Irrelevant for suspensions + reject_new_follow: Reject follows + reject_new_follow_hint: Reject follows in the future + reject_reply: Reject replies + reject_reply_hint: Reject replies in the future reject_reports: Reject reports reject_reports_hint: Ignore all reports coming from this domain. Irrelevant for suspensions + reject_send_dissubscribable: 購読拒否アカウントの投稿を配送しない + reject_send_dissubscribable_hint: 相手サーバーからのフェッチは防げません。停止とは無関係です + reject_send_media: 画像付き投稿を配送しない + reject_send_media_hint: 相手サーバーからのフェッチは防げません。停止とは無関係です + reject_send_not_public_searchability: 検索許可が「公開」でない投稿を配送しない + reject_send_not_public_searchability_hint: 相手サーバーからのフェッチは防げません。停止とは無関係です + reject_send_public_unlisted: ローカル公開投稿を配送しない + reject_send_public_unlisted_hint: 相手サーバーからのフェッチは防げません。停止とは無関係です + reject_send_sensitive: センシティブな投稿を配送しない + reject_send_sensitive_hint: 相手サーバーからのフェッチは防げません。停止とは無関係です + reject_send_unlisted_dissubscribable: 購読拒否アカウントの未収載投稿を配送しない + reject_send_unlisted_dissubscribable_hint: 相手サーバーからのフェッチは防げません。停止とは無関係です + reject_straight_follow: Reject straight follow + reject_straight_follow_hint: The server accounts must be authenticated when follow our accounts undo: Undo domain block view: View domain block email_domain_blocks: @@ -483,7 +505,12 @@ en: description_html: You can define content policies that will be applied to all accounts from this domain and any of its subdomains. limited_federation_mode_description_html: You can chose whether to allow federation with this domain. policies: + reject_favourite: Reject favourite + reject_hashtag: Reject hashtags reject_media: Reject media + reject_new_follow: Reject follows + reject_straight_follow: Reject straight follow + reject_reply: Reject reply reject_reports: Reject reports silence: Limit suspend: Suspend diff --git a/config/locales/ja.yml b/config/locales/ja.yml index ad13ea7758..983db7bcf4 100644 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@ -387,6 +387,10 @@ ja: existing_domain_block: あなたは既に%{name}さんに厳しい制限を課しています。 existing_domain_block_html: 既に%{name}に対して、より厳しい制限を課しています。先にその制限を解除する必要があります。 export: エクスポート + hidden: 非公開にする + hidden_hint: 公開することで当サーバーの安全が脅かされる場合、このドメインブロックを非公開にすることができます。 + hidden_anonymous: 未ログインユーザーに非公開にする + hidden_anonymous_hint: 公開することで当サーバーの安全が脅かされる場合、非ログインユーザーに限りこのドメインブロックを非公開にすることができます。 import: インポート new: create: ブロックを作成 @@ -405,10 +409,32 @@ ja: private_comment_hint: このコメントは同じサーバーのモデレーターも閲覧できます。 public_comment: コメント (公開) public_comment_hint: ドメインブロックの公開を有効にしている場合、このコメントも公開されます。 + reject_favourite: お気に入り、絵文字リアクションを拒否 + reject_favourite_hint: 今後のお気に入り、絵文字リアクションを拒否します。停止とは無関係です + reject_hashtag: ハッシュタグを拒否 + reject_hashtag_hint: ハッシュタグで検索できなくなり、トレンドにも影響しなくなります。停止とは無関係です reject_media: メディアファイルを拒否 reject_media_hint: ローカルに保存されたメディアファイルを削除し、今後のダウンロードを拒否します。停止とは無関係です + reject_new_follow: 新規フォローを拒否 + reject_new_follow_hint: 今後の新規フォローを拒否します。停止とは無関係です + reject_reply: リプライを拒否 + reject_reply_hint: 今後のリプライを拒否します。停止とは無関係です reject_reports: 通報を拒否 reject_reports_hint: このドメインからの通報をすべて無視します。停止とは無関係です + reject_send_dissubscribable: 購読拒否アカウントの投稿を配送しない + reject_send_dissubscribable_hint: 相手サーバーからのフェッチは防げません。停止とは無関係です + reject_send_media: 画像付き投稿を配送しない + reject_send_media_hint: 相手サーバーからのフェッチは防げません。停止とは無関係です + reject_send_not_public_searchability: 検索許可が「公開」でない投稿を配送しない + reject_send_not_public_searchability_hint: 相手サーバーからのフェッチは防げません。停止とは無関係です + reject_send_public_unlisted: ローカル公開投稿を配送しない + reject_send_public_unlisted_hint: 相手サーバーからのフェッチは防げません。停止とは無関係です + reject_send_sensitive: センシティブな投稿を配送しない + reject_send_sensitive_hint: 相手サーバーからのフェッチは防げません。停止とは無関係です + reject_send_unlisted_dissubscribable: 購読拒否アカウントの未収載投稿を配送しない + reject_send_unlisted_dissubscribable_hint: 相手サーバーからのフェッチは防げません。停止とは無関係です + reject_straight_follow: フォローを強制的に審査制にする + reject_straight_follow_hint: 相手からのフォローは当サーバーのアカウントの承認が必須になります undo: ドメインブロックを戻す view: ドメインブロックを表示 email_domain_blocks: @@ -473,8 +499,19 @@ ja: description_html: このドメインとそのサブドメインのすべてのアカウントに適用されるコンテンツポリシーを定義できます。 limited_federation_mode_description_html: このドメインとの連合を許可するかどうかを選択できます。 policies: + reject_favourite: お気に入りを拒否 + reject_hashtag: ハッシュタグを拒否 reject_media: メディアを拒否する + reject_new_follow: 新規フォローを拒否 + reject_reply: リプライを拒否 reject_reports: 通報を拒否 + reject_send_dissubscribable: 購読拒否投稿配送なし + reject_send_media: メディア付き投稿配送なし + reject_send_not_public_searchability: 検索許可全て投稿配送なし + reject_send_public_unlisted: ローカル公開投稿配送なし + reject_send_sensitive: センシティブ投稿配送なし + reject_send_unlisted_dissubscribable: 購読拒否未収載投稿配送なし + reject_straight_follow: フォローを制限 silence: 制限 suspend: サスペンド policy: ポリシー @@ -961,7 +998,7 @@ ja: accounts_hint: ローカルアカウントの場合は「@info」、リモートアカウントの場合は「@info@example.com」の形式で指定します。サーバーが認識していないアカウントは保存時に自動的に削除されます。 accounts_raw: 絞り込むアカウント available: 有効 - description: アンテナは、サーバーが認識した全ての公開・ローカル公開投稿のうち、検索許可が「公開」または明示的に設定されていないもの(検索許可システムに対応していないサーバーからの投稿)、かつ購読を拒否していないすべてのアカウントからの投稿が対象です。検出された投稿は、指定したリストに追加されます。 + description: アンテナは、サーバーが認識した全ての公開・ローカル公開投稿のうち、購読を拒否していないすべてのアカウントからの投稿が対象です。検出された投稿は、指定したリストに追加されます。 domains_hint: ドメインとは、アカウントIDやサイトのURLのうち「kmy.blue」「example.com」に該当する部分です domains_raw: 絞り込むドメイン exclude_accounts_raw: 除外するアカウント diff --git a/db/migrate/20230427072650_add_reject_sending_to_domain_blocks.rb b/db/migrate/20230427072650_add_reject_sending_to_domain_blocks.rb new file mode 100644 index 0000000000..0679cb3003 --- /dev/null +++ b/db/migrate/20230427072650_add_reject_sending_to_domain_blocks.rb @@ -0,0 +1,10 @@ +class AddRejectSendingToDomainBlocks < ActiveRecord::Migration[6.1] + def change + add_column :domain_blocks, :reject_send_not_public_searchability, :boolean, null: false, default: false + add_column :domain_blocks, :reject_send_unlisted_dissubscribable, :boolean, null: false, default: false + add_column :domain_blocks, :reject_send_public_unlisted, :boolean, null: false, default: false + add_column :domain_blocks, :reject_send_dissubscribable, :boolean, null: false, default: false + add_column :domain_blocks, :reject_send_media, :boolean, null: false, default: false + add_column :domain_blocks, :reject_send_sensitive, :boolean, null: false, default: false + end +end diff --git a/db/migrate/20230427122753_add_some_to_domain_blocks.rb b/db/migrate/20230427122753_add_some_to_domain_blocks.rb new file mode 100644 index 0000000000..b553af4cca --- /dev/null +++ b/db/migrate/20230427122753_add_some_to_domain_blocks.rb @@ -0,0 +1,7 @@ +class AddSomeToDomainBlocks < ActiveRecord::Migration[6.1] + def change + add_column :domain_blocks, :reject_hashtag, :boolean, null: false, default: false + add_column :domain_blocks, :reject_straight_follow, :boolean, null: false, default: false + add_column :domain_blocks, :reject_new_follow, :boolean, null: false, default: false + end +end diff --git a/db/migrate/20230427233749_add_hidden_to_domain_blocks.rb b/db/migrate/20230427233749_add_hidden_to_domain_blocks.rb new file mode 100644 index 0000000000..0d64308525 --- /dev/null +++ b/db/migrate/20230427233749_add_hidden_to_domain_blocks.rb @@ -0,0 +1,6 @@ +class AddHiddenToDomainBlocks < ActiveRecord::Migration[6.1] + def change + add_column :domain_blocks, :hidden, :boolean, null: false, default: false + add_column :domain_blocks, :hidden_anonymous, :boolean, null: false, default: false + end +end diff --git a/db/schema.rb b/db/schema.rb index aef6f3736e..5779eaac91 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.define(version: 2023_04_26_013738) do +ActiveRecord::Schema.define(version: 2023_04_27_233749) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -468,6 +468,19 @@ ActiveRecord::Schema.define(version: 2023_04_26_013738) do t.text "private_comment" t.text "public_comment" t.boolean "obfuscate", default: false, null: false + t.boolean "reject_favourite", default: false, null: false + t.boolean "reject_reply", default: false, null: false + t.boolean "reject_send_not_public_searchability", default: false, null: false + t.boolean "reject_send_unlisted_dissubscribable", default: false, null: false + t.boolean "reject_send_public_unlisted", default: false, null: false + t.boolean "reject_send_dissubscribable", default: false, null: false + t.boolean "reject_send_media", default: false, null: false + t.boolean "reject_send_sensitive", default: false, null: false + t.boolean "reject_hashtag", default: false, null: false + t.boolean "reject_straight_follow", default: false, null: false + t.boolean "reject_new_follow", default: false, null: false + t.boolean "hidden", default: false, null: false + t.boolean "hidden_anonymous", default: false, null: false t.index ["domain"], name: "index_domain_blocks_on_domain", unique: true end