From bd415af9a11fe7057c9f428b7bdaeb8d4fb3a77b Mon Sep 17 00:00:00 2001 From: Claire Date: Wed, 3 Jan 2024 11:23:58 +0100 Subject: [PATCH 01/23] Change streaming API host to not be overridden to localhost in development mode (#28557) --- config/initializers/1_hosts.rb | 2 +- spec/requests/content_security_policy_spec.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config/initializers/1_hosts.rb b/config/initializers/1_hosts.rb index 6ff0845c4665cf..5c59e28bd12764 100644 --- a/config/initializers/1_hosts.rb +++ b/config/initializers/1_hosts.rb @@ -23,7 +23,7 @@ if Rails.env.production? "ws#{https ? 's' : ''}://#{web_host}" else - "ws://#{ENV['REMOTE_DEV'] == 'true' ? host.split(':').first : 'localhost'}:4000" + "ws://#{host.split(':').first}:4000" end end diff --git a/spec/requests/content_security_policy_spec.rb b/spec/requests/content_security_policy_spec.rb index 7610e698cdf4cd..d4cc40bce5d976 100644 --- a/spec/requests/content_security_policy_spec.rb +++ b/spec/requests/content_security_policy_spec.rb @@ -20,7 +20,7 @@ "form-action 'self'", "child-src 'self' blob: https://cb6e6126.ngrok.io", "worker-src 'self' blob: https://cb6e6126.ngrok.io", - "connect-src 'self' data: blob: https://cb6e6126.ngrok.io ws://localhost:4000", + "connect-src 'self' data: blob: https://cb6e6126.ngrok.io ws://cb6e6126.ngrok.io:4000", "script-src 'self' https://cb6e6126.ngrok.io 'wasm-unsafe-eval'" ) end From 092bb8a27af9ee87ff9ebabaf354477470ea3a94 Mon Sep 17 00:00:00 2001 From: Claire Date: Wed, 3 Jan 2024 12:29:26 +0100 Subject: [PATCH 02/23] Fix Mastodon not correctly processing HTTP Signatures with query strings (#28476) --- .../concerns/signature_verification.rb | 22 ++++++- app/lib/request.rb | 11 +++- spec/requests/signature_verification_spec.rb | 66 +++++++++++++++++++ 3 files changed, 95 insertions(+), 4 deletions(-) diff --git a/app/controllers/concerns/signature_verification.rb b/app/controllers/concerns/signature_verification.rb index f0a344f1c97d64..35391e64c44390 100644 --- a/app/controllers/concerns/signature_verification.rb +++ b/app/controllers/concerns/signature_verification.rb @@ -91,14 +91,23 @@ def signed_request_actor raise SignatureVerificationError, "Public key not found for key #{signature_params['keyId']}" if actor.nil? signature = Base64.decode64(signature_params['signature']) - compare_signed_string = build_signed_string + compare_signed_string = build_signed_string(include_query_string: true) return actor unless verify_signature(actor, signature, compare_signed_string).nil? + # Compatibility quirk with older Mastodon versions + compare_signed_string = build_signed_string(include_query_string: false) + return actor unless verify_signature(actor, signature, compare_signed_string).nil? + actor = stoplight_wrap_request { actor_refresh_key!(actor) } raise SignatureVerificationError, "Could not refresh public key #{signature_params['keyId']}" if actor.nil? + compare_signed_string = build_signed_string(include_query_string: true) + return actor unless verify_signature(actor, signature, compare_signed_string).nil? + + # Compatibility quirk with older Mastodon versions + compare_signed_string = build_signed_string(include_query_string: false) return actor unless verify_signature(actor, signature, compare_signed_string).nil? fail_with! "Verification failed for #{actor.to_log_human_identifier} #{actor.uri} using rsa-sha256 (RSASSA-PKCS1-v1_5 with SHA-256)", signed_string: compare_signed_string, signature: signature_params['signature'] @@ -180,11 +189,18 @@ def verify_signature(actor, signature, compare_signed_string) nil end - def build_signed_string + def build_signed_string(include_query_string: true) signed_headers.map do |signed_header| case signed_header when Request::REQUEST_TARGET - "#{Request::REQUEST_TARGET}: #{request.method.downcase} #{request.path}" + if include_query_string + "#{Request::REQUEST_TARGET}: #{request.method.downcase} #{request.original_fullpath}" + else + # Current versions of Mastodon incorrectly omit the query string from the (request-target) pseudo-header. + # Therefore, temporarily support such incorrect signatures for compatibility. + # TODO: remove eventually some time after release of the fixed version + "#{Request::REQUEST_TARGET}: #{request.method.downcase} #{request.path}" + end when '(created)' raise SignatureVerificationError, 'Invalid pseudo-header (created) for rsa-sha256' unless signature_algorithm == 'hs2019' raise SignatureVerificationError, 'Pseudo-header (created) used but corresponding argument missing' if signature_params['created'].blank? diff --git a/app/lib/request.rb b/app/lib/request.rb index 5f128af734c1e9..8d4120868d4feb 100644 --- a/app/lib/request.rb +++ b/app/lib/request.rb @@ -77,6 +77,7 @@ def initialize(verb, url, **options) @url = Addressable::URI.parse(url).normalize @http_client = options.delete(:http_client) @allow_local = options.delete(:allow_local) + @full_path = options.delete(:with_query_string) @options = options.merge(socket_class: use_proxy? || @allow_local ? ProxySocket : Socket) @options = @options.merge(timeout_class: PerOperationWithDeadline, timeout_options: TIMEOUT) @options = @options.merge(proxy_url) if use_proxy? @@ -146,7 +147,7 @@ def http_client private def set_common_headers! - @headers[REQUEST_TARGET] = "#{@verb} #{@url.path}" + @headers[REQUEST_TARGET] = request_target @headers['User-Agent'] = Mastodon::Version.user_agent @headers['Host'] = @url.host @headers['Date'] = Time.now.utc.httpdate @@ -157,6 +158,14 @@ def set_digest! @headers['Digest'] = "SHA-256=#{Digest::SHA256.base64digest(@options[:body])}" end + def request_target + if @url.query.nil? || !@full_path + "#{@verb} #{@url.path}" + else + "#{@verb} #{@url.path}?#{@url.query}" + end + end + def signature algorithm = 'rsa-sha256' signature = Base64.strict_encode64(@keypair.sign(OpenSSL::Digest.new('SHA256'), signed_string)) diff --git a/spec/requests/signature_verification_spec.rb b/spec/requests/signature_verification_spec.rb index b753750b840595..401828c4a3c5d1 100644 --- a/spec/requests/signature_verification_spec.rb +++ b/spec/requests/signature_verification_spec.rb @@ -94,6 +94,72 @@ end end + context 'with a valid signature on a GET request that has a query string' do + let(:signature_header) do + 'keyId="https://remote.domain/users/bob#main-key",algorithm="rsa-sha256",headers="date host (request-target)",signature="SDMa4r/DQYMXYxVgYO2yEqGWWUXugKjVuz0I8dniQAk+aunzBaF2aPu+4grBfawAshlx1Xytl8lhb0H2MllEz16/tKY7rUrb70MK0w8ohXgpb0qs3YvQgdj4X24L1x2MnkFfKHR/J+7TBlnivq0HZqXm8EIkPWLv+eQxu8fbowLwHIVvRd/3t6FzvcfsE0UZKkoMEX02542MhwSif6cu7Ec/clsY9qgKahb9JVGOGS1op9Lvg/9y1mc8KCgD83U5IxVygYeYXaVQ6gixA9NgZiTCwEWzHM5ELm7w5hpdLFYxYOHg/3G3fiqJzpzNQAcCD4S4JxfE7hMI0IzVlNLT6A=="' # rubocop:disable Layout/LineLength + end + + it 'successfuly verifies signature', :aggregate_failures do + expect(signature_header).to eq build_signature_string(actor_keypair, 'https://remote.domain/users/bob#main-key', 'get /activitypub/success?foo=42', { 'Date' => 'Wed, 20 Dec 2023 10:00:00 GMT', 'Host' => 'www.example.com' }) + + get '/activitypub/success?foo=42', headers: { + 'Host' => 'www.example.com', + 'Date' => 'Wed, 20 Dec 2023 10:00:00 GMT', + 'Signature' => signature_header, + } + + expect(response).to have_http_status(200) + expect(body_as_json).to match( + signed_request: true, + signature_actor_id: actor.id.to_s + ) + end + end + + context 'when the query string is missing from the signature verification (compatibility quirk)' do + let(:signature_header) do + 'keyId="https://remote.domain/users/bob#main-key",algorithm="rsa-sha256",headers="date host (request-target)",signature="Z8ilar3J7bOwqZkMp7sL8sRs4B1FT+UorbmvWoE+A5UeoOJ3KBcUmbsh+k3wQwbP5gMNUrra9rEWabpasZGphLsbDxfbsWL3Cf0PllAc7c1c7AFEwnewtExI83/qqgEkfWc2z7UDutXc2NfgAx89Ox8DXU/fA2GG0jILjB6UpFyNugkY9rg6oI31UnvfVi3R7sr3/x8Ea3I9thPvqI2byF6cojknSpDAwYzeKdngX3TAQEGzFHz3SDWwyp3jeMWfwvVVbM38FxhvAnSumw7YwWW4L7M7h4M68isLimoT3yfCn2ucBVL5Dz8koBpYf/40w7QidClAwCafZQFC29yDOg=="' # rubocop:disable Layout/LineLength + end + + it 'successfuly verifies signature', :aggregate_failures do + expect(signature_header).to eq build_signature_string(actor_keypair, 'https://remote.domain/users/bob#main-key', 'get /activitypub/success', { 'Date' => 'Wed, 20 Dec 2023 10:00:00 GMT', 'Host' => 'www.example.com' }) + + get '/activitypub/success?foo=42', headers: { + 'Host' => 'www.example.com', + 'Date' => 'Wed, 20 Dec 2023 10:00:00 GMT', + 'Signature' => signature_header, + } + + expect(response).to have_http_status(200) + expect(body_as_json).to match( + signed_request: true, + signature_actor_id: actor.id.to_s + ) + end + end + + context 'with mismatching query string' do + let(:signature_header) do + 'keyId="https://remote.domain/users/bob#main-key",algorithm="rsa-sha256",headers="date host (request-target)",signature="SDMa4r/DQYMXYxVgYO2yEqGWWUXugKjVuz0I8dniQAk+aunzBaF2aPu+4grBfawAshlx1Xytl8lhb0H2MllEz16/tKY7rUrb70MK0w8ohXgpb0qs3YvQgdj4X24L1x2MnkFfKHR/J+7TBlnivq0HZqXm8EIkPWLv+eQxu8fbowLwHIVvRd/3t6FzvcfsE0UZKkoMEX02542MhwSif6cu7Ec/clsY9qgKahb9JVGOGS1op9Lvg/9y1mc8KCgD83U5IxVygYeYXaVQ6gixA9NgZiTCwEWzHM5ELm7w5hpdLFYxYOHg/3G3fiqJzpzNQAcCD4S4JxfE7hMI0IzVlNLT6A=="' # rubocop:disable Layout/LineLength + end + + it 'fails to verify signature', :aggregate_failures do + expect(signature_header).to eq build_signature_string(actor_keypair, 'https://remote.domain/users/bob#main-key', 'get /activitypub/success?foo=42', { 'Date' => 'Wed, 20 Dec 2023 10:00:00 GMT', 'Host' => 'www.example.com' }) + + get '/activitypub/success?foo=43', headers: { + 'Host' => 'www.example.com', + 'Date' => 'Wed, 20 Dec 2023 10:00:00 GMT', + 'Signature' => signature_header, + } + + expect(body_as_json).to match( + signed_request: true, + signature_actor_id: nil, + error: anything + ) + end + end + context 'with a mismatching path' do it 'fails to verify signature', :aggregate_failures do get '/activitypub/alternative-path', headers: { From e12d8893f42e5d2b2c71b43e0dff09438fbe81a2 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Wed, 3 Jan 2024 08:06:15 -0500 Subject: [PATCH 03/23] Fix intermittent failure from unspecified order in `export_domain_blocks` controller spec (#28562) --- app/controllers/admin/export_domain_blocks_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/admin/export_domain_blocks_controller.rb b/app/controllers/admin/export_domain_blocks_controller.rb index 433b8a158787a7..ffc4478172634d 100644 --- a/app/controllers/admin/export_domain_blocks_controller.rb +++ b/app/controllers/admin/export_domain_blocks_controller.rb @@ -68,7 +68,7 @@ def export_headers def export_data CSV.generate(headers: export_headers, write_headers: true) do |content| - DomainBlock.with_limitations.each do |instance| + DomainBlock.with_limitations.order(id: :asc).each do |instance| content << [instance.domain, instance.severity, instance.reject_media, instance.reject_reports, instance.public_comment, instance.obfuscate] end end From 74a0d81e90607c275ab9c411a8b9c29512afa961 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Wed, 3 Jan 2024 08:06:38 -0500 Subject: [PATCH 04/23] Add coverage for CLI `self-destruct` command (#28565) Co-authored-by: Claire --- spec/lib/mastodon/cli/main_spec.rb | 109 +++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) diff --git a/spec/lib/mastodon/cli/main_spec.rb b/spec/lib/mastodon/cli/main_spec.rb index 59f1fc47841954..931ca57c302639 100644 --- a/spec/lib/mastodon/cli/main_spec.rb +++ b/spec/lib/mastodon/cli/main_spec.rb @@ -20,4 +20,113 @@ .to output_results(Mastodon::Version.to_s) end end + + describe '#self_destruct' do + let(:action) { :self_destruct } + + context 'with self destruct mode enabled' do + before do + allow(SelfDestructHelper).to receive(:self_destruct?).and_return(true) + end + + context 'with pending accounts' do + before { Fabricate(:account) } + + it 'reports about pending accounts' do + expect { subject } + .to output_results( + 'already enabled', + 'still pending deletion' + ) + .and raise_error(SystemExit) + end + end + + context 'with sidekiq notices being processed' do + before do + Account.delete_all + stats_double = instance_double(Sidekiq::Stats, enqueued: 5) + allow(Sidekiq::Stats).to receive(:new).and_return(stats_double) + end + + it 'reports about notices' do + expect { subject } + .to output_results( + 'already enabled', + 'notices are still being' + ) + .and raise_error(SystemExit) + end + end + + context 'with sidekiq failed deliveries' do + before do + Account.delete_all + stats_double = instance_double(Sidekiq::Stats, enqueued: 0, retry_size: 10) + allow(Sidekiq::Stats).to receive(:new).and_return(stats_double) + end + + it 'reports about notices' do + expect { subject } + .to output_results( + 'already enabled', + 'some have failed and are scheduled' + ) + .and raise_error(SystemExit) + end + end + + context 'with self descruct mode ready' do + before do + Account.delete_all + stats_double = instance_double(Sidekiq::Stats, enqueued: 0, retry_size: 0) + allow(Sidekiq::Stats).to receive(:new).and_return(stats_double) + end + + it 'reports about notices' do + expect { subject } + .to output_results( + 'already enabled', + 'can safely delete all data' + ) + .and raise_error(SystemExit) + end + end + end + + context 'with self destruct mode disabled' do + before do + allow(SelfDestructHelper).to receive(:self_destruct?).and_return(false) + end + + context 'with an incorrect response to hostname' do + let(:prompt_double) { instance_double(TTY::Prompt, ask: 'wrong') } + + before do + allow(TTY::Prompt).to receive(:new).and_return(prompt_double) + end + + it 'reports failed answer' do + expect { subject } + .to raise_error(SystemExit) + end + end + + context 'with a correct response to hostname' do + # TODO: Update after tty-prompt replace with Thor methods + let(:prompt_double) { instance_double(TTY::Prompt, ask: Rails.configuration.x.local_domain, warn: nil, no?: false, ok: nil) } + + before do + allow(TTY::Prompt).to receive(:new).and_return(prompt_double) + end + + it 'instructs to set the appropriate environment variable' do + expect { subject } + .to_not raise_error + # TODO: Update after tty-prompt replace with Thor methods + expect(prompt_double).to have_received(:ok).with(/add the following variable/) + end + end + end + end end From 51d2b80ff7407a6c49a44eee80c67f81dc09d7dc Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Wed, 3 Jan 2024 08:22:03 -0500 Subject: [PATCH 05/23] Solve `Abc/*` metrics for `db/*migrate*` files (#28568) --- .rubocop.yml | 2 - ...221101190723_backfill_admin_action_logs.rb | 159 +++++++++++------- ...114142_backfill_admin_action_logs_again.rb | 159 +++++++++++------- 3 files changed, 204 insertions(+), 116 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index 61cb1164b4d406..8832e28f6e9113 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -74,14 +74,12 @@ Metrics/ModuleLength: Metrics/AbcSize: Exclude: - 'lib/mastodon/cli/*.rb' - - db/*migrate/**/* # Reason: Currently disabled in .rubocop_todo.yml # https://docs.rubocop.org/rubocop/cops_metrics.html#metricscyclomaticcomplexity Metrics/CyclomaticComplexity: Exclude: - lib/mastodon/cli/*.rb - - db/*migrate/**/* # Reason: # https://docs.rubocop.org/rubocop/cops_metrics.html#metricsparameterlists diff --git a/db/post_migrate/20221101190723_backfill_admin_action_logs.rb b/db/post_migrate/20221101190723_backfill_admin_action_logs.rb index 6476f4b13a740e..1d8d983b3a4b4b 100644 --- a/db/post_migrate/20221101190723_backfill_admin_action_logs.rb +++ b/db/post_migrate/20221101190723_backfill_admin_action_logs.rb @@ -77,90 +77,135 @@ class AdminActionLog < ApplicationRecord def up safety_assured do - AdminActionLog.includes(:account).where(target_type: 'Account', human_identifier: nil).find_each do |log| - next if log.account.nil? + process_logs_for_account + process_logs_for_user + process_logs_for_report + process_logs_for_domain_block + process_logs_for_domain_allow + process_logs_for_email_domain_block + process_logs_for_unavailable_domain + process_logs_for_status + process_logs_for_account_warning + process_logs_for_announcement + process_logs_for_ip_block + process_logs_for_custom_emoji + process_logs_for_canonical_email_block + process_logs_for_appeal + end + end - log.update_attribute('human_identifier', log.account.acct) - end + def down; end - AdminActionLog.includes(user: :account).where(target_type: 'User', human_identifier: nil).find_each do |log| - next if log.user.nil? + private - log.update_attribute('human_identifier', log.user.account.acct) - log.update_attribute('route_param', log.user.account_id) - end + def process_logs_for_account + AdminActionLog.includes(:account).where(target_type: 'Account', human_identifier: nil).find_each do |log| + next if log.account.nil? - AdminActionLog.where(target_type: 'Report', human_identifier: nil).in_batches.update_all('human_identifier = target_id::text') + log.update_attribute('human_identifier', log.account.acct) + end + end - AdminActionLog.includes(:domain_block).where(target_type: 'DomainBlock').find_each do |log| - next if log.domain_block.nil? + def process_logs_for_user + AdminActionLog.includes(user: :account).where(target_type: 'User', human_identifier: nil).find_each do |log| + next if log.user.nil? - log.update_attribute('human_identifier', log.domain_block.domain) - end + log.update_attribute('human_identifier', log.user.account.acct) + log.update_attribute('route_param', log.user.account_id) + end + end - AdminActionLog.includes(:domain_allow).where(target_type: 'DomainAllow').find_each do |log| - next if log.domain_allow.nil? + def process_logs_for_report + AdminActionLog.where(target_type: 'Report', human_identifier: nil).in_batches.update_all('human_identifier = target_id::text') + end - log.update_attribute('human_identifier', log.domain_allow.domain) - end + def process_logs_for_domain_block + AdminActionLog.includes(:domain_block).where(target_type: 'DomainBlock').find_each do |log| + next if log.domain_block.nil? - AdminActionLog.includes(:email_domain_block).where(target_type: 'EmailDomainBlock').find_each do |log| - next if log.email_domain_block.nil? + log.update_attribute('human_identifier', log.domain_block.domain) + end + end - log.update_attribute('human_identifier', log.email_domain_block.domain) - end + def process_logs_for_domain_allow + AdminActionLog.includes(:domain_allow).where(target_type: 'DomainAllow').find_each do |log| + next if log.domain_allow.nil? - AdminActionLog.includes(:unavailable_domain).where(target_type: 'UnavailableDomain').find_each do |log| - next if log.unavailable_domain.nil? + log.update_attribute('human_identifier', log.domain_allow.domain) + end + end - log.update_attribute('human_identifier', log.unavailable_domain.domain) - end + def process_logs_for_email_domain_block + AdminActionLog.includes(:email_domain_block).where(target_type: 'EmailDomainBlock').find_each do |log| + next if log.email_domain_block.nil? - AdminActionLog.includes(status: :account).where(target_type: 'Status', human_identifier: nil).find_each do |log| - next if log.status.nil? + log.update_attribute('human_identifier', log.email_domain_block.domain) + end + end - log.update_attribute('human_identifier', log.status.account.acct) - log.update_attribute('permalink', log.status.uri) - end + def process_logs_for_unavailable_domain + AdminActionLog.includes(:unavailable_domain).where(target_type: 'UnavailableDomain').find_each do |log| + next if log.unavailable_domain.nil? - AdminActionLog.includes(account_warning: :account).where(target_type: 'AccountWarning', human_identifier: nil).find_each do |log| - next if log.account_warning.nil? + log.update_attribute('human_identifier', log.unavailable_domain.domain) + end + end - log.update_attribute('human_identifier', log.account_warning.account.acct) - end + def process_logs_for_status + AdminActionLog.includes(status: :account).where(target_type: 'Status', human_identifier: nil).find_each do |log| + next if log.status.nil? - AdminActionLog.includes(:announcement).where(target_type: 'Announcement', human_identifier: nil).find_each do |log| - next if log.announcement.nil? + log.update_attribute('human_identifier', log.status.account.acct) + log.update_attribute('permalink', log.status.uri) + end + end - log.update_attribute('human_identifier', log.announcement.text) - end + def process_logs_for_account_warning + AdminActionLog.includes(account_warning: :account).where(target_type: 'AccountWarning', human_identifier: nil).find_each do |log| + next if log.account_warning.nil? - AdminActionLog.includes(:ip_block).where(target_type: 'IpBlock', human_identifier: nil).find_each do |log| - next if log.ip_block.nil? + log.update_attribute('human_identifier', log.account_warning.account.acct) + end + end - log.update_attribute('human_identifier', "#{log.ip_block.ip}/#{log.ip_block.ip.prefix}") - end + def process_logs_for_announcement + AdminActionLog.includes(:announcement).where(target_type: 'Announcement', human_identifier: nil).find_each do |log| + next if log.announcement.nil? - AdminActionLog.includes(:custom_emoji).where(target_type: 'CustomEmoji', human_identifier: nil).find_each do |log| - next if log.custom_emoji.nil? + log.update_attribute('human_identifier', log.announcement.text) + end + end - log.update_attribute('human_identifier', log.custom_emoji.shortcode) - end + def process_logs_for_ip_block + AdminActionLog.includes(:ip_block).where(target_type: 'IpBlock', human_identifier: nil).find_each do |log| + next if log.ip_block.nil? - AdminActionLog.includes(:canonical_email_block).where(target_type: 'CanonicalEmailBlock', human_identifier: nil).find_each do |log| - next if log.canonical_email_block.nil? + log.update_attribute('human_identifier', "#{log.ip_block.ip}/#{log.ip_block.ip.prefix}") + end + end - log.update_attribute('human_identifier', log.canonical_email_block.canonical_email_hash) - end + def process_logs_for_custom_emoji + AdminActionLog.includes(:custom_emoji).where(target_type: 'CustomEmoji', human_identifier: nil).find_each do |log| + next if log.custom_emoji.nil? - AdminActionLog.includes(appeal: :account).where(target_type: 'Appeal', human_identifier: nil).find_each do |log| - next if log.appeal.nil? + log.update_attribute('human_identifier', log.custom_emoji.shortcode) + end + end - log.update_attribute('human_identifier', log.appeal.account.acct) - log.update_attribute('route_param', log.appeal.account_warning_id) - end + def process_logs_for_canonical_email_block + AdminActionLog.includes(:canonical_email_block).where(target_type: 'CanonicalEmailBlock', human_identifier: nil).find_each do |log| + next if log.canonical_email_block.nil? + + log.update_attribute('human_identifier', log.canonical_email_block.canonical_email_hash) end end - def down; end + def process_logs_for_appeal + AdminActionLog.includes(appeal: :account).where(target_type: 'Appeal', human_identifier: nil).find_each do |log| + next if log.appeal.nil? + + log.update_attribute('human_identifier', log.appeal.account.acct) + log.update_attribute('route_param', log.appeal.account_warning_id) + end + end end diff --git a/db/post_migrate/20221206114142_backfill_admin_action_logs_again.rb b/db/post_migrate/20221206114142_backfill_admin_action_logs_again.rb index 3c68470a7f3812..c080e77ecfd09a 100644 --- a/db/post_migrate/20221206114142_backfill_admin_action_logs_again.rb +++ b/db/post_migrate/20221206114142_backfill_admin_action_logs_again.rb @@ -77,90 +77,135 @@ class AdminActionLog < ApplicationRecord def up safety_assured do - AdminActionLog.includes(:account).where(target_type: 'Account', human_identifier: nil).find_each do |log| - next if log.account.nil? + process_logs_for_account + process_logs_for_user + process_logs_for_report + process_logs_for_domain_block + process_logs_for_domain_allow + process_logs_for_email_domain_block + process_logs_for_unavailable_domain + process_logs_for_status + process_logs_for_account_warning + process_logs_for_announcement + process_logs_for_ip_block + process_logs_for_custom_emoji + process_logs_for_canonical_email_block + process_logs_for_appeal + end + end - log.update_attribute('human_identifier', log.account.acct) - end + def down; end - AdminActionLog.includes(user: :account).where(target_type: 'User', human_identifier: nil).find_each do |log| - next if log.user.nil? + private - log.update_attribute('human_identifier', log.user.account.acct) - log.update_attribute('route_param', log.user.account_id) - end + def process_logs_for_account + AdminActionLog.includes(:account).where(target_type: 'Account', human_identifier: nil).find_each do |log| + next if log.account.nil? - AdminActionLog.where(target_type: 'Report', human_identifier: nil).in_batches.update_all('human_identifier = target_id::text') + log.update_attribute('human_identifier', log.account.acct) + end + end - AdminActionLog.includes(:domain_block).where(target_type: 'DomainBlock').find_each do |log| - next if log.domain_block.nil? + def process_logs_for_user + AdminActionLog.includes(user: :account).where(target_type: 'User', human_identifier: nil).find_each do |log| + next if log.user.nil? - log.update_attribute('human_identifier', log.domain_block.domain) - end + log.update_attribute('human_identifier', log.user.account.acct) + log.update_attribute('route_param', log.user.account_id) + end + end - AdminActionLog.includes(:domain_allow).where(target_type: 'DomainAllow').find_each do |log| - next if log.domain_allow.nil? + def process_logs_for_report + AdminActionLog.where(target_type: 'Report', human_identifier: nil).in_batches.update_all('human_identifier = target_id::text') + end - log.update_attribute('human_identifier', log.domain_allow.domain) - end + def process_logs_for_domain_block + AdminActionLog.includes(:domain_block).where(target_type: 'DomainBlock').find_each do |log| + next if log.domain_block.nil? - AdminActionLog.includes(:email_domain_block).where(target_type: 'EmailDomainBlock').find_each do |log| - next if log.email_domain_block.nil? + log.update_attribute('human_identifier', log.domain_block.domain) + end + end - log.update_attribute('human_identifier', log.email_domain_block.domain) - end + def process_logs_for_domain_allow + AdminActionLog.includes(:domain_allow).where(target_type: 'DomainAllow').find_each do |log| + next if log.domain_allow.nil? - AdminActionLog.includes(:unavailable_domain).where(target_type: 'UnavailableDomain').find_each do |log| - next if log.unavailable_domain.nil? + log.update_attribute('human_identifier', log.domain_allow.domain) + end + end - log.update_attribute('human_identifier', log.unavailable_domain.domain) - end + def process_logs_for_email_domain_block + AdminActionLog.includes(:email_domain_block).where(target_type: 'EmailDomainBlock').find_each do |log| + next if log.email_domain_block.nil? - AdminActionLog.includes(status: :account).where(target_type: 'Status', human_identifier: nil).find_each do |log| - next if log.status.nil? + log.update_attribute('human_identifier', log.email_domain_block.domain) + end + end - log.update_attribute('human_identifier', log.status.account.acct) - log.update_attribute('permalink', log.status.uri) - end + def process_logs_for_unavailable_domain + AdminActionLog.includes(:unavailable_domain).where(target_type: 'UnavailableDomain').find_each do |log| + next if log.unavailable_domain.nil? - AdminActionLog.includes(account_warning: :account).where(target_type: 'AccountWarning', human_identifier: nil).find_each do |log| - next if log.account_warning.nil? + log.update_attribute('human_identifier', log.unavailable_domain.domain) + end + end - log.update_attribute('human_identifier', log.account_warning.account.acct) - end + def process_logs_for_status + AdminActionLog.includes(status: :account).where(target_type: 'Status', human_identifier: nil).find_each do |log| + next if log.status.nil? - AdminActionLog.includes(:announcement).where(target_type: 'Announcement', human_identifier: nil).find_each do |log| - next if log.announcement.nil? + log.update_attribute('human_identifier', log.status.account.acct) + log.update_attribute('permalink', log.status.uri) + end + end - log.update_attribute('human_identifier', log.announcement.text) - end + def process_logs_for_account_warning + AdminActionLog.includes(account_warning: :account).where(target_type: 'AccountWarning', human_identifier: nil).find_each do |log| + next if log.account_warning.nil? - AdminActionLog.includes(:ip_block).where(target_type: 'IpBlock', human_identifier: nil).find_each do |log| - next if log.ip_block.nil? + log.update_attribute('human_identifier', log.account_warning.account.acct) + end + end - log.update_attribute('human_identifier', "#{log.ip_block.ip}/#{log.ip_block.ip.prefix}") - end + def process_logs_for_announcement + AdminActionLog.includes(:announcement).where(target_type: 'Announcement', human_identifier: nil).find_each do |log| + next if log.announcement.nil? - AdminActionLog.includes(:custom_emoji).where(target_type: 'CustomEmoji', human_identifier: nil).find_each do |log| - next if log.custom_emoji.nil? + log.update_attribute('human_identifier', log.announcement.text) + end + end - log.update_attribute('human_identifier', log.custom_emoji.shortcode) - end + def process_logs_for_ip_block + AdminActionLog.includes(:ip_block).where(target_type: 'IpBlock', human_identifier: nil).find_each do |log| + next if log.ip_block.nil? - AdminActionLog.includes(:canonical_email_block).where(target_type: 'CanonicalEmailBlock', human_identifier: nil).find_each do |log| - next if log.canonical_email_block.nil? + log.update_attribute('human_identifier', "#{log.ip_block.ip}/#{log.ip_block.ip.prefix}") + end + end - log.update_attribute('human_identifier', log.canonical_email_block.canonical_email_hash) - end + def process_logs_for_custom_emoji + AdminActionLog.includes(:custom_emoji).where(target_type: 'CustomEmoji', human_identifier: nil).find_each do |log| + next if log.custom_emoji.nil? - AdminActionLog.includes(appeal: :account).where(target_type: 'Appeal', human_identifier: nil).find_each do |log| - next if log.appeal.nil? + log.update_attribute('human_identifier', log.custom_emoji.shortcode) + end + end - log.update_attribute('human_identifier', log.appeal.account.acct) - log.update_attribute('route_param', log.appeal.account_warning_id) - end + def process_logs_for_canonical_email_block + AdminActionLog.includes(:canonical_email_block).where(target_type: 'CanonicalEmailBlock', human_identifier: nil).find_each do |log| + next if log.canonical_email_block.nil? + + log.update_attribute('human_identifier', log.canonical_email_block.canonical_email_hash) end end - def down; end + def process_logs_for_appeal + AdminActionLog.includes(appeal: :account).where(target_type: 'Appeal', human_identifier: nil).find_each do |log| + next if log.appeal.nil? + + log.update_attribute('human_identifier', log.appeal.account.acct) + log.update_attribute('route_param', log.appeal.account_warning_id) + end + end end From 5c769de096ce7205308deaf5d62ad516b1e39259 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Wed, 3 Jan 2024 09:12:56 -0500 Subject: [PATCH 06/23] Add spec coverage for `CLI::Media#remove_orphans` command (#28267) --- lib/mastodon/cli/base.rb | 1 + spec/lib/mastodon/cli/media_spec.rb | 54 +++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/lib/mastodon/cli/base.rb b/lib/mastodon/cli/base.rb index 32aff2fcc50451..8c222bbb2b3040 100644 --- a/lib/mastodon/cli/base.rb +++ b/lib/mastodon/cli/base.rb @@ -4,6 +4,7 @@ require_relative '../../../config/environment' require 'thor' +require 'pastel' require_relative 'progress_helper' module Mastodon diff --git a/spec/lib/mastodon/cli/media_spec.rb b/spec/lib/mastodon/cli/media_spec.rb index 24e1467a3ca8c9..071bcd9e34a98f 100644 --- a/spec/lib/mastodon/cli/media_spec.rb +++ b/spec/lib/mastodon/cli/media_spec.rb @@ -184,4 +184,58 @@ end end end + + describe '#remove_orphans' do + let(:action) { :remove_orphans } + + before do + FileUtils.mkdir_p Rails.public_path.join('system') + end + + context 'without any options' do + it 'runs without error' do + expect { subject } + .to output_results('Removed', 'orphans (approx') + end + end + + context 'when in azure mode' do + before do + allow(Paperclip::Attachment).to receive(:default_options).and_return(storage: :azure) + end + + it 'warns about usage and exits' do + expect { subject } + .to output_results('azure storage driver is not supported') + .and raise_error(SystemExit) + end + end + + context 'when in fog mode' do + before do + allow(Paperclip::Attachment).to receive(:default_options).and_return(storage: :fog) + end + + it 'warns about usage and exits' do + expect { subject } + .to output_results('fog storage driver is not supported') + .and raise_error(SystemExit) + end + end + + context 'when in filesystem mode' do + before do + allow(File).to receive(:delete).and_return(true) + media_attachment.delete + end + + let(:media_attachment) { Fabricate(:media_attachment) } + + it 'removes the unlinked files' do + expect { subject } + .to output_results('Removed', 'orphans (approx') + expect(File).to have_received(:delete).with(media_attachment.file.path) + end + end + end end From 905794fd57386a33f8773cbeaec7b1cbb37c3e68 Mon Sep 17 00:00:00 2001 From: Claire Date: Wed, 3 Jan 2024 16:04:10 +0100 Subject: [PATCH 07/23] Remove v3.5 branch from supported Mastodon versions (#28574) --- SECURITY.md | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index 954ff73a247425..81472b01b4306f 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -13,10 +13,8 @@ A "vulnerability in Mastodon" is a vulnerability in the code distributed through ## Supported Versions -| Version | Supported | -| ------- | ---------------- | -| 4.2.x | Yes | -| 4.1.x | Yes | -| 4.0.x | No | -| 3.5.x | Until 2023-12-31 | -| < 3.5 | No | +| Version | Supported | +| ------- | --------- | +| 4.2.x | Yes | +| 4.1.x | Yes | +| < 4.1 | No | From f92d8c654df654538096efff05e9b1a989d01490 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Wed, 3 Jan 2024 10:08:08 -0500 Subject: [PATCH 08/23] Standardize on Thor methods in CLI classes (#28566) --- lib/mastodon/cli/federation.rb | 36 +++++++--------- lib/mastodon/cli/preview_cards.rb | 1 - spec/lib/mastodon/cli/main_spec.rb | 66 +++++++++++++++++++++++++----- 3 files changed, 69 insertions(+), 34 deletions(-) diff --git a/lib/mastodon/cli/federation.rb b/lib/mastodon/cli/federation.rb index 1b4cb467a571bb..4a4dde36868a55 100644 --- a/lib/mastodon/cli/federation.rb +++ b/lib/mastodon/cli/federation.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require 'tty-prompt' - module Mastodon::CLI module Federation extend ActiveSupport::Concern @@ -30,45 +28,39 @@ module Federation LONG_DESC def self_destruct if SelfDestructHelper.self_destruct? - prompt.ok('Self-destruct mode is already enabled for this Mastodon server') + say('Self-destruct mode is already enabled for this Mastodon server', :green) pending_accounts = Account.local.without_suspended.count + Account.local.suspended.joins(:deletion_request).count sidekiq_stats = Sidekiq::Stats.new if pending_accounts.positive? - prompt.warn("#{pending_accounts} accounts are still pending deletion.") + say("#{pending_accounts} accounts are still pending deletion.", :yellow) elsif sidekiq_stats.enqueued.positive? - prompt.warn('Deletion notices are still being processed') + say('Deletion notices are still being processed', :yellow) elsif sidekiq_stats.retry_size.positive? - prompt.warn('At least one delivery attempt for each deletion notice has been made, but some have failed and are scheduled for retry') + say('At least one delivery attempt for each deletion notice has been made, but some have failed and are scheduled for retry', :yellow) else - prompt.ok('Every deletion notice has been sent! You can safely delete all data and decomission your servers!') + say('Every deletion notice has been sent! You can safely delete all data and decomission your servers!', :green) end exit(0) end - exit(1) unless prompt.ask('Type in the domain of the server to confirm:', required: true) == Rails.configuration.x.local_domain + exit(1) unless ask('Type in the domain of the server to confirm:') == Rails.configuration.x.local_domain - prompt.warn('This operation WILL NOT be reversible.') - prompt.warn('While the data won\'t be erased locally, the server will be in a BROKEN STATE afterwards.') - prompt.warn('The deletion process itself may take a long time, and will be handled by Sidekiq, so do not shut it down until it has finished (you will be able to re-run this command to see the state of the self-destruct process).') + say('This operation WILL NOT be reversible.', :yellow) + say('While the data won\'t be erased locally, the server will be in a BROKEN STATE afterwards.', :yellow) + say('The deletion process itself may take a long time, and will be handled by Sidekiq, so do not shut it down until it has finished (you will be able to re-run this command to see the state of the self-destruct process).', :yellow) - exit(1) if prompt.no?('Are you sure you want to proceed?') + exit(1) if no?('Are you sure you want to proceed?') self_destruct_value = Rails.application.message_verifier('self-destruct').generate(Rails.configuration.x.local_domain) - prompt.ok('To switch Mastodon to self-destruct mode, add the following variable to your evironment (e.g. by adding a line to your `.env.production`) and restart all Mastodon processes:') - prompt.ok(" SELF_DESTRUCT=#{self_destruct_value}") - prompt.ok("\nYou can re-run this command to see the state of the self-destruct process.") - rescue TTY::Reader::InputInterrupt + say('To switch Mastodon to self-destruct mode, add the following variable to your evironment (e.g. by adding a line to your `.env.production`) and restart all Mastodon processes:', :green) + say(" SELF_DESTRUCT=#{self_destruct_value}", :green) + say("\nYou can re-run this command to see the state of the self-destruct process.", :green) + rescue Interrupt exit(1) end - - private - - def prompt - @prompt ||= TTY::Prompt.new - end end end end diff --git a/lib/mastodon/cli/preview_cards.rb b/lib/mastodon/cli/preview_cards.rb index 2df3d095da0f2a..9b20a0cbb8662d 100644 --- a/lib/mastodon/cli/preview_cards.rb +++ b/lib/mastodon/cli/preview_cards.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true -require 'tty-prompt' require_relative 'base' module Mastodon::CLI diff --git a/spec/lib/mastodon/cli/main_spec.rb b/spec/lib/mastodon/cli/main_spec.rb index 931ca57c302639..081cd2dd47df0a 100644 --- a/spec/lib/mastodon/cli/main_spec.rb +++ b/spec/lib/mastodon/cli/main_spec.rb @@ -100,33 +100,77 @@ end context 'with an incorrect response to hostname' do - let(:prompt_double) { instance_double(TTY::Prompt, ask: 'wrong') } - before do - allow(TTY::Prompt).to receive(:new).and_return(prompt_double) + answer_hostname_incorrectly end - it 'reports failed answer' do + it 'exits silently' do expect { subject } .to raise_error(SystemExit) end end - context 'with a correct response to hostname' do - # TODO: Update after tty-prompt replace with Thor methods - let(:prompt_double) { instance_double(TTY::Prompt, ask: Rails.configuration.x.local_domain, warn: nil, no?: false, ok: nil) } + context 'with a correct response to hostname but no to proceed' do + before do + answer_hostname_correctly + decline_proceed + end + + it 'passes first step but stops before instructions' do + expect { subject } + .to output_results('operation WILL NOT') + .and raise_error(SystemExit) + end + end + context 'with a correct response to hostname and yes to proceed' do before do - allow(TTY::Prompt).to receive(:new).and_return(prompt_double) + answer_hostname_correctly + accept_proceed end it 'instructs to set the appropriate environment variable' do expect { subject } - .to_not raise_error - # TODO: Update after tty-prompt replace with Thor methods - expect(prompt_double).to have_received(:ok).with(/add the following variable/) + .to output_results( + 'operation WILL NOT', + 'the following variable' + ) end end + + private + + def answer_hostname_incorrectly + allow(cli.shell) + .to receive(:ask) + .with('Type in the domain of the server to confirm:') + .and_return('wrong.host') + .once + end + + def answer_hostname_correctly + allow(cli.shell) + .to receive(:ask) + .with('Type in the domain of the server to confirm:') + .and_return(Rails.configuration.x.local_domain) + .once + end + + def decline_proceed + allow(cli.shell) + .to receive(:no?) + .with('Are you sure you want to proceed?') + .and_return(true) + .once + end + + def accept_proceed + allow(cli.shell) + .to receive(:no?) + .with('Are you sure you want to proceed?') + .and_return(false) + .once + end end end end From 195b89d33619e0ce4271cef33fc29379254206f1 Mon Sep 17 00:00:00 2001 From: Michael Stanclift Date: Wed, 3 Jan 2024 13:02:53 -0600 Subject: [PATCH 09/23] Fix .opus file uploads being misidentified by Paperclip (#28580) --- app/models/concerns/attachmentable.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/models/concerns/attachmentable.rb b/app/models/concerns/attachmentable.rb index 4cdbdeb4738a49..3b7db1fcef3b7c 100644 --- a/app/models/concerns/attachmentable.rb +++ b/app/models/concerns/attachmentable.rb @@ -11,11 +11,12 @@ module Attachmentable # For some file extensions, there exist different content # type variants, and browsers often send the wrong one, # for example, sending an audio .ogg file as video/ogg, - # likewise, MimeMagic also misreports them as such. For + # likewise, kt-paperclip also misreports them as such. For # those files, it is necessary to use the output of the # `file` utility instead INCORRECT_CONTENT_TYPES = %w( audio/vorbis + audio/opus video/ogg video/webm ).freeze From dfdadb92e834cc099d16d7539a661105e1d12390 Mon Sep 17 00:00:00 2001 From: Claire Date: Thu, 4 Jan 2024 10:07:05 +0100 Subject: [PATCH 10/23] Add ability to require approval when users sign up using specific email domains (#28468) --- .../admin/email_domain_blocks_controller.rb | 4 ++-- .../admin/email_domain_blocks_controller.rb | 2 +- app/models/email_domain_block.rb | 23 +++++++++++-------- app/models/user.rb | 8 ++++++- .../admin/email_domain_block_serializer.rb | 2 +- .../_email_domain_block.html.haml | 4 ++++ .../admin/email_domain_blocks/new.html.haml | 3 +++ config/locales/en.yml | 1 + ...ow_with_approval_to_email_domain_blocks.rb | 7 ++++++ db/schema.rb | 3 ++- .../email_domain_blocks_controller_spec.rb | 3 ++- .../auth/registrations_controller_spec.rb | 19 +++++++++++++++ spec/services/app_sign_up_service_spec.rb | 21 +++++++++++++++++ 13 files changed, 84 insertions(+), 16 deletions(-) create mode 100644 db/migrate/20231222100226_add_allow_with_approval_to_email_domain_blocks.rb diff --git a/app/controllers/admin/email_domain_blocks_controller.rb b/app/controllers/admin/email_domain_blocks_controller.rb index 4a3228ec300466..ff754bc0b47033 100644 --- a/app/controllers/admin/email_domain_blocks_controller.rb +++ b/app/controllers/admin/email_domain_blocks_controller.rb @@ -40,7 +40,7 @@ def create (@email_domain_block.other_domains || []).uniq.each do |domain| next if EmailDomainBlock.where(domain: domain).exists? - other_email_domain_block = EmailDomainBlock.create!(domain: domain, parent: @email_domain_block) + other_email_domain_block = EmailDomainBlock.create!(domain: domain, allow_with_approval: @email_domain_block.allow_with_approval, parent: @email_domain_block) log_action :create, other_email_domain_block end end @@ -65,7 +65,7 @@ def set_resolved_records end def resource_params - params.require(:email_domain_block).permit(:domain, other_domains: []) + params.require(:email_domain_block).permit(:domain, :allow_with_approval, other_domains: []) end def form_email_domain_block_batch_params diff --git a/app/controllers/api/v1/admin/email_domain_blocks_controller.rb b/app/controllers/api/v1/admin/email_domain_blocks_controller.rb index 850eda62241655..df54b9f0a404d1 100644 --- a/app/controllers/api/v1/admin/email_domain_blocks_controller.rb +++ b/app/controllers/api/v1/admin/email_domain_blocks_controller.rb @@ -55,7 +55,7 @@ def set_email_domain_block end def resource_params - params.permit(:domain) + params.permit(:domain, :allow_with_approval) end def insert_pagination_headers diff --git a/app/models/email_domain_block.rb b/app/models/email_domain_block.rb index 60e90208dbe1ea..f1b14c8b08cf30 100644 --- a/app/models/email_domain_block.rb +++ b/app/models/email_domain_block.rb @@ -4,11 +4,12 @@ # # Table name: email_domain_blocks # -# id :bigint(8) not null, primary key -# domain :string default(""), not null -# created_at :datetime not null -# updated_at :datetime not null -# parent_id :bigint(8) +# id :bigint(8) not null, primary key +# domain :string default(""), not null +# created_at :datetime not null +# updated_at :datetime not null +# parent_id :bigint(8) +# allow_with_approval :boolean default(FALSE), not null # class EmailDomainBlock < ApplicationRecord @@ -42,8 +43,8 @@ def initialize(domain_or_domains, attempt_ip: nil) @attempt_ip = attempt_ip end - def match? - blocking? || invalid_uri? + def match?(...) + blocking?(...) || invalid_uri? end private @@ -52,8 +53,8 @@ def invalid_uri? @uris.any?(&:nil?) end - def blocking? - blocks = EmailDomainBlock.where(domain: domains_with_variants).order(Arel.sql('char_length(domain) desc')) + def blocking?(allow_with_approval: false) + blocks = EmailDomainBlock.where(domain: domains_with_variants, allow_with_approval: allow_with_approval).order(Arel.sql('char_length(domain) desc')) blocks.each { |block| block.history.add(@attempt_ip) } if @attempt_ip.present? blocks.any? end @@ -86,4 +87,8 @@ def extract_uris(domain_or_domains) def self.block?(domain_or_domains, attempt_ip: nil) Matcher.new(domain_or_domains, attempt_ip: attempt_ip).match? end + + def self.requires_approval?(domain_or_domains, attempt_ip: nil) + Matcher.new(domain_or_domains, attempt_ip: attempt_ip).match?(allow_with_approval: true) + end end diff --git a/app/models/user.rb b/app/models/user.rb index a1574c02ad86c9..be1e84b49c838f 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -418,7 +418,7 @@ def render_and_send_devise_message(notification, *args, **kwargs) def set_approved self.approved = begin - if sign_up_from_ip_requires_approval? + if sign_up_from_ip_requires_approval? || sign_up_email_requires_approval? false else open_registrations? || valid_invitation? || external? @@ -430,6 +430,12 @@ def sign_up_from_ip_requires_approval? !sign_up_ip.nil? && IpBlock.where(severity: :sign_up_requires_approval).where('ip >>= ?', sign_up_ip.to_s).exists? end + def sign_up_email_requires_approval? + return false unless email.present? || unconfirmed_email.present? + + EmailDomainBlock.requires_approval?(email.presence || unconfirmed_email, attempt_ip: sign_up_ip) + end + def open_registrations? Setting.registrations_mode == 'open' end diff --git a/app/serializers/rest/admin/email_domain_block_serializer.rb b/app/serializers/rest/admin/email_domain_block_serializer.rb index a026ff680e74c1..afe7722cb58ba7 100644 --- a/app/serializers/rest/admin/email_domain_block_serializer.rb +++ b/app/serializers/rest/admin/email_domain_block_serializer.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class REST::Admin::EmailDomainBlockSerializer < ActiveModel::Serializer - attributes :id, :domain, :created_at, :history + attributes :id, :domain, :created_at, :history, :allow_with_approval def id object.id.to_s diff --git a/app/views/admin/email_domain_blocks/_email_domain_block.html.haml b/app/views/admin/email_domain_blocks/_email_domain_block.html.haml index 7cb973c4b4e047..f6a6e826670ff4 100644 --- a/app/views/admin/email_domain_blocks/_email_domain_block.html.haml +++ b/app/views/admin/email_domain_blocks/_email_domain_block.html.haml @@ -12,3 +12,7 @@ · = t('admin.email_domain_blocks.attempts_over_week', count: email_domain_block.history.reduce(0) { |sum, day| sum + day.accounts }) + + - if email_domain_block.allow_with_approval? + · + = t('admin.email_domain_blocks.allow_registrations_with_approval') diff --git a/app/views/admin/email_domain_blocks/new.html.haml b/app/views/admin/email_domain_blocks/new.html.haml index fa1d950ad2b333..3d31487733ee34 100644 --- a/app/views/admin/email_domain_blocks/new.html.haml +++ b/app/views/admin/email_domain_blocks/new.html.haml @@ -7,6 +7,9 @@ .fields-group = f.input :domain, wrapper: :with_block_label, label: t('admin.email_domain_blocks.domain'), input_html: { readonly: defined?(@resolved_records) } + .fields-group + = f.input :allow_with_approval, wrapper: :with_label, hint: false, label: I18n.t('admin.email_domain_blocks.allow_registrations_with_approval') + - if defined?(@resolved_records) %p.hint= t('admin.email_domain_blocks.resolved_dns_records_hint_html') diff --git a/config/locales/en.yml b/config/locales/en.yml index 15d682d1739a59..50f814a81d56a6 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -425,6 +425,7 @@ en: view: View domain block email_domain_blocks: add_new: Add new + allow_registrations_with_approval: Allow registrations with approval attempts_over_week: one: "%{count} attempt over the last week" other: "%{count} sign-up attempts over the last week" diff --git a/db/migrate/20231222100226_add_allow_with_approval_to_email_domain_blocks.rb b/db/migrate/20231222100226_add_allow_with_approval_to_email_domain_blocks.rb new file mode 100644 index 00000000000000..01e8edfed46898 --- /dev/null +++ b/db/migrate/20231222100226_add_allow_with_approval_to_email_domain_blocks.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class AddAllowWithApprovalToEmailDomainBlocks < ActiveRecord::Migration[7.1] + def change + add_column :email_domain_blocks, :allow_with_approval, :boolean, default: false, null: false + end +end diff --git a/db/schema.rb b/db/schema.rb index 126ed8785a450f..4ea9744f401566 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.1].define(version: 2023_12_12_073317) do +ActiveRecord::Schema[7.1].define(version: 2023_12_22_100226) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -435,6 +435,7 @@ t.datetime "created_at", precision: nil, null: false t.datetime "updated_at", precision: nil, null: false t.bigint "parent_id" + t.boolean "allow_with_approval", default: false, null: false t.index ["domain"], name: "index_email_domain_blocks_on_domain", unique: true end diff --git a/spec/controllers/admin/email_domain_blocks_controller_spec.rb b/spec/controllers/admin/email_domain_blocks_controller_spec.rb index 42866001449b7c..9379fe374aa3c4 100644 --- a/spec/controllers/admin/email_domain_blocks_controller_spec.rb +++ b/spec/controllers/admin/email_domain_blocks_controller_spec.rb @@ -12,13 +12,14 @@ describe 'GET #index' do around do |example| default_per_page = EmailDomainBlock.default_per_page - EmailDomainBlock.paginates_per 1 + EmailDomainBlock.paginates_per 2 example.run EmailDomainBlock.paginates_per default_per_page end it 'returns http success' do 2.times { Fabricate(:email_domain_block) } + Fabricate(:email_domain_block, allow_with_approval: true) get :index, params: { page: 2 } expect(response).to have_http_status(200) end diff --git a/spec/controllers/auth/registrations_controller_spec.rb b/spec/controllers/auth/registrations_controller_spec.rb index 37172f8d24477f..bd1c6165951ebf 100644 --- a/spec/controllers/auth/registrations_controller_spec.rb +++ b/spec/controllers/auth/registrations_controller_spec.rb @@ -135,6 +135,25 @@ end end + context 'when user has an email address requiring approval' do + subject do + Setting.registrations_mode = 'open' + Fabricate(:email_domain_block, allow_with_approval: true, domain: 'example.com') + request.headers['Accept-Language'] = accept_language + post :create, params: { user: { account_attributes: { username: 'test' }, email: 'test@example.com', password: '12345678', password_confirmation: '12345678', agreement: 'true' } } + end + + it 'creates unapproved user and redirects to setup' do + subject + expect(response).to redirect_to auth_setup_path + + user = User.find_by(email: 'test@example.com') + expect(user).to_not be_nil + expect(user.locale).to eq(accept_language) + expect(user.approved).to be(false) + end + end + context 'with Approval-based registrations without invite' do subject do Setting.registrations_mode = 'approved' diff --git a/spec/services/app_sign_up_service_spec.rb b/spec/services/app_sign_up_service_spec.rb index 0adb473f17770b..86e64dab21cdd5 100644 --- a/spec/services/app_sign_up_service_spec.rb +++ b/spec/services/app_sign_up_service_spec.rb @@ -27,6 +27,27 @@ end end + context 'when the email address requires approval' do + before do + Setting.registrations_mode = 'open' + Fabricate(:email_domain_block, allow_with_approval: true, domain: 'email.com') + end + + it 'creates an unapproved user', :aggregate_failures do + access_token = subject.call(app, remote_ip, params) + expect(access_token).to_not be_nil + expect(access_token.scopes.to_s).to eq 'read write' + + user = User.find_by(id: access_token.resource_owner_id) + expect(user).to_not be_nil + expect(user.confirmed?).to be false + expect(user.approved?).to be false + + expect(user.account).to_not be_nil + expect(user.invite_request).to be_nil + end + end + context 'when registrations are closed' do before do Setting.registrations_mode = 'none' From 38e5d1b53f042f17d18092471302445a902fae07 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 4 Jan 2024 10:15:56 +0100 Subject: [PATCH 11/23] Update dependency net-ldap to v0.19.0 (#28588) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 295461bd35fc46..8d01167537cc6a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -474,7 +474,7 @@ GEM net-imap (0.4.4) date net-protocol - net-ldap (0.18.0) + net-ldap (0.19.0) net-pop (0.1.2) net-protocol net-protocol (0.2.2) From 0f3f98c01f33b0fd5968c8247f15dd0961afc9bc Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 4 Jan 2024 10:16:12 +0100 Subject: [PATCH 12/23] Update dependency react-redux-loading-bar to v5.0.8 (#28587) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 3cd45a11d66f87..fd18bd96355cae 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13673,8 +13673,8 @@ __metadata: linkType: hard "react-redux-loading-bar@npm:^5.0.4": - version: 5.0.7 - resolution: "react-redux-loading-bar@npm:5.0.7" + version: 5.0.8 + resolution: "react-redux-loading-bar@npm:5.0.8" dependencies: prop-types: "npm:^15.7.2" react-lifecycles-compat: "npm:^3.0.4" @@ -13683,7 +13683,7 @@ __metadata: react-dom: ^0.14.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 react-redux: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 redux: ^3.0.0 || ^4.0.0 || ^5.0.0 - checksum: 45333093e7d28df923a657ad89ffe4673d7bd135ef57c0143fb4d868f21b57aeb9044691f553f7d2afbcc9080a1f8cd3cec5b274c80cb57faf0e87a70f7a2cce + checksum: 797c1abf8bcc947feb127380e6d363db264c12bc94e578d635f86f1d806b0ec714dc3723e54c884937448b17f9042cfc995fe7a1deaf558efc01681e43e4669c languageName: node linkType: hard From 9c268c9413a5bb6f1bad5c531dfdd0391326873f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 4 Jan 2024 09:16:29 +0000 Subject: [PATCH 13/23] Update dependency axios to v1.6.4 (#28586) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/yarn.lock b/yarn.lock index fd18bd96355cae..b2ffa3b9ea94a0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4678,13 +4678,13 @@ __metadata: linkType: hard "axios@npm:^1.4.0": - version: 1.6.3 - resolution: "axios@npm:1.6.3" + version: 1.6.4 + resolution: "axios@npm:1.6.4" dependencies: - follow-redirects: "npm:^1.15.0" + follow-redirects: "npm:^1.15.4" form-data: "npm:^4.0.0" proxy-from-env: "npm:^1.1.0" - checksum: dcc6d982353db33e6893ef01cdf81d0a0548dbd8fba0cb046dc4aee1a6a16226721faa4c2a13b2673d47130509629cdb93bb991b3a2bd4ef17a5ac27a8bba0da + checksum: daac697fa1ea9865cb48e9edb7eacd99e8a9214997f2d8e886cb61c380a613e5c270078bfc153ac96206680106c223f005f0e4bf2f3b2ddd88e559ecf970521f languageName: node linkType: hard @@ -8163,13 +8163,13 @@ __metadata: languageName: node linkType: hard -"follow-redirects@npm:^1.0.0, follow-redirects@npm:^1.15.0": - version: 1.15.3 - resolution: "follow-redirects@npm:1.15.3" +"follow-redirects@npm:^1.0.0, follow-redirects@npm:^1.15.4": + version: 1.15.4 + resolution: "follow-redirects@npm:1.15.4" peerDependenciesMeta: debug: optional: true - checksum: 915a2cf22e667bdf47b1a43cc6b7dce14d95039e9bbf9a24d0e739abfbdfa00077dd43c86d4a7a19efefcc7a99af144920a175eedc3888d268af5df67c272ee5 + checksum: 5f37ed9170c9eb19448c5418fdb0f2b73f644b5364834e70791a76ecc7db215246f9773bbef4852cfae4067764ffc852e047f744b661b0211532155b73556a6a languageName: node linkType: hard From 9826b7780ab4f0a6cbb633bf159fcea4db1b7ed9 Mon Sep 17 00:00:00 2001 From: Emelia Smith Date: Thu, 4 Jan 2024 10:18:03 +0100 Subject: [PATCH 14/23] Streaming: use standard cors package instead of custom implementation (#28523) --- streaming/index.js | 16 ++-------------- streaming/package.json | 2 ++ yarn.lock | 25 +++++++++++++++++++++++-- 3 files changed, 27 insertions(+), 16 deletions(-) diff --git a/streaming/index.js b/streaming/index.js index fb3e3fb2be1cd4..42d0afc7c5bdea 100644 --- a/streaming/index.js +++ b/streaming/index.js @@ -5,6 +5,7 @@ const http = require('http'); const path = require('path'); const url = require('url'); +const cors = require('cors'); const dotenv = require('dotenv'); const express = require('express'); const Redis = require('ioredis'); @@ -187,6 +188,7 @@ const startServer = async () => { const pgPool = new pg.Pool(pgConfigFromEnv(process.env)); const server = http.createServer(app); + app.use(cors()); /** * @type {Object.): void>>} @@ -327,19 +329,6 @@ const startServer = async () => { } }; - /** - * @param {any} req - * @param {any} res - * @param {function(Error=): void} next - */ - const allowCrossDomain = (req, res, next) => { - res.header('Access-Control-Allow-Origin', '*'); - res.header('Access-Control-Allow-Headers', 'Authorization, Accept, Cache-Control'); - res.header('Access-Control-Allow-Methods', 'GET, OPTIONS'); - - next(); - }; - /** * @param {any} req * @param {any} res @@ -987,7 +976,6 @@ const startServer = async () => { api.use(setRequestId); api.use(setRemoteAddress); - api.use(allowCrossDomain); api.use(authenticationMiddleware); api.use(errorMiddleware); diff --git a/streaming/package.json b/streaming/package.json index 0cfc5b32765fc6..2d70acb829cac3 100644 --- a/streaming/package.json +++ b/streaming/package.json @@ -16,6 +16,7 @@ "check:types": "tsc --noEmit" }, "dependencies": { + "cors": "^2.8.5", "dotenv": "^16.0.3", "express": "^4.18.2", "ioredis": "^5.3.2", @@ -28,6 +29,7 @@ "ws": "^8.12.1" }, "devDependencies": { + "@types/cors": "^2.8.16", "@types/express": "^4.17.17", "@types/npmlog": "^7.0.0", "@types/pg": "^8.6.6", diff --git a/yarn.lock b/yarn.lock index b2ffa3b9ea94a0..7b7f0e3153232e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2468,12 +2468,14 @@ __metadata: version: 0.0.0-use.local resolution: "@mastodon/streaming@workspace:streaming" dependencies: + "@types/cors": "npm:^2.8.16" "@types/express": "npm:^4.17.17" "@types/npmlog": "npm:^7.0.0" "@types/pg": "npm:^8.6.6" "@types/uuid": "npm:^9.0.0" "@types/ws": "npm:^8.5.9" bufferutil: "npm:^4.0.7" + cors: "npm:^2.8.5" dotenv: "npm:^16.0.3" eslint-define-config: "npm:^2.0.0" express: "npm:^4.18.2" @@ -3027,6 +3029,15 @@ __metadata: languageName: node linkType: hard +"@types/cors@npm:^2.8.16": + version: 2.8.16 + resolution: "@types/cors@npm:2.8.16" + dependencies: + "@types/node": "npm:*" + checksum: ebcfb325b102739249bbaa4845cf1cf4830baf5490a32bcd1a85cd9b8c4d4b9eaaaea94423e454b5b7c9da77e46a64db80d2381d3bc3f940d15d13814e87b70a + languageName: node + linkType: hard + "@types/emoji-mart@npm:^3.0.9": version: 3.0.14 resolution: "@types/emoji-mart@npm:3.0.14" @@ -5973,6 +5984,16 @@ __metadata: languageName: node linkType: hard +"cors@npm:^2.8.5": + version: 2.8.5 + resolution: "cors@npm:2.8.5" + dependencies: + object-assign: "npm:^4" + vary: "npm:^1" + checksum: 373702b7999409922da80de4a61938aabba6929aea5b6fd9096fefb9e8342f626c0ebd7507b0e8b0b311380744cc985f27edebc0a26e0ddb784b54e1085de761 + languageName: node + linkType: hard + "cosmiconfig@npm:^7.0.0": version: 7.1.0 resolution: "cosmiconfig@npm:7.1.0" @@ -11953,7 +11974,7 @@ __metadata: languageName: node linkType: hard -"object-assign@npm:^4.0.1, object-assign@npm:^4.1.1": +"object-assign@npm:^4, object-assign@npm:^4.0.1, object-assign@npm:^4.1.1": version: 4.1.1 resolution: "object-assign@npm:4.1.1" checksum: 1f4df9945120325d041ccf7b86f31e8bcc14e73d29171e37a7903050e96b81323784ec59f93f102ec635bcf6fa8034ba3ea0a8c7e69fa202b87ae3b6cec5a414 @@ -16728,7 +16749,7 @@ __metadata: languageName: node linkType: hard -"vary@npm:~1.1.2": +"vary@npm:^1, vary@npm:~1.1.2": version: 1.1.2 resolution: "vary@npm:1.1.2" checksum: f15d588d79f3675135ba783c91a4083dcd290a2a5be9fcb6514220a1634e23df116847b1cc51f66bfb0644cf9353b2abb7815ae499bab06e46dd33c1a6bf1f4f From 06374d07c3ce5eab2560ae85b56939cef575aee8 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 4 Jan 2024 10:19:38 +0100 Subject: [PATCH 15/23] Update dependency cssnano to v6.0.3 (#28581) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 196 +++++++++++++++++++++++++++--------------------------- 1 file changed, 98 insertions(+), 98 deletions(-) diff --git a/yarn.lock b/yarn.lock index 7b7f0e3153232e..99c3eedb26b017 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5208,7 +5208,7 @@ __metadata: languageName: node linkType: hard -"browserslist@npm:^4.0.0, browserslist@npm:^4.21.10, browserslist@npm:^4.21.4, browserslist@npm:^4.22.2": +"browserslist@npm:^4.0.0, browserslist@npm:^4.21.10, browserslist@npm:^4.22.2": version: 4.22.2 resolution: "browserslist@npm:4.22.2" dependencies: @@ -6140,7 +6140,7 @@ __metadata: languageName: node linkType: hard -"css-declaration-sorter@npm:^7.0.0": +"css-declaration-sorter@npm:^7.1.1": version: 7.1.1 resolution: "css-declaration-sorter@npm:7.1.1" peerDependencies: @@ -6228,7 +6228,7 @@ __metadata: languageName: node linkType: hard -"css-tree@npm:^2.2.1, css-tree@npm:^2.3.1": +"css-tree@npm:^2.3.1": version: 2.3.1 resolution: "css-tree@npm:2.3.1" dependencies: @@ -6278,42 +6278,42 @@ __metadata: languageName: node linkType: hard -"cssnano-preset-default@npm:^6.0.2": - version: 6.0.2 - resolution: "cssnano-preset-default@npm:6.0.2" +"cssnano-preset-default@npm:^6.0.3": + version: 6.0.3 + resolution: "cssnano-preset-default@npm:6.0.3" dependencies: - css-declaration-sorter: "npm:^7.0.0" + css-declaration-sorter: "npm:^7.1.1" cssnano-utils: "npm:^4.0.1" postcss-calc: "npm:^9.0.1" - postcss-colormin: "npm:^6.0.1" - postcss-convert-values: "npm:^6.0.1" + postcss-colormin: "npm:^6.0.2" + postcss-convert-values: "npm:^6.0.2" postcss-discard-comments: "npm:^6.0.1" postcss-discard-duplicates: "npm:^6.0.1" postcss-discard-empty: "npm:^6.0.1" postcss-discard-overridden: "npm:^6.0.1" - postcss-merge-longhand: "npm:^6.0.1" - postcss-merge-rules: "npm:^6.0.2" + postcss-merge-longhand: "npm:^6.0.2" + postcss-merge-rules: "npm:^6.0.3" postcss-minify-font-values: "npm:^6.0.1" postcss-minify-gradients: "npm:^6.0.1" - postcss-minify-params: "npm:^6.0.1" - postcss-minify-selectors: "npm:^6.0.1" + postcss-minify-params: "npm:^6.0.2" + postcss-minify-selectors: "npm:^6.0.2" postcss-normalize-charset: "npm:^6.0.1" postcss-normalize-display-values: "npm:^6.0.1" postcss-normalize-positions: "npm:^6.0.1" postcss-normalize-repeat-style: "npm:^6.0.1" postcss-normalize-string: "npm:^6.0.1" postcss-normalize-timing-functions: "npm:^6.0.1" - postcss-normalize-unicode: "npm:^6.0.1" + postcss-normalize-unicode: "npm:^6.0.2" postcss-normalize-url: "npm:^6.0.1" postcss-normalize-whitespace: "npm:^6.0.1" postcss-ordered-values: "npm:^6.0.1" - postcss-reduce-initial: "npm:^6.0.1" + postcss-reduce-initial: "npm:^6.0.2" postcss-reduce-transforms: "npm:^6.0.1" - postcss-svgo: "npm:^6.0.1" - postcss-unique-selectors: "npm:^6.0.1" + postcss-svgo: "npm:^6.0.2" + postcss-unique-selectors: "npm:^6.0.2" peerDependencies: postcss: ^8.4.31 - checksum: c6f97674704c3a2a2473440549eac38ac722feebabbd39f2d4d1b8fae7f137f8fd0dfb88929e1ff737d54008de583c39e96f9dc450f2d71f8be6fc3bac2840a3 + checksum: d100a1f8ab71adbb6df85e00f4a9e5d04ac06fc50343157eef853aded3f75dd0489dd845a5b2fb43ca701bd88c39c5aa88673f842bc1f94f4318c7b38ced1963 languageName: node linkType: hard @@ -6327,23 +6327,14 @@ __metadata: linkType: hard "cssnano@npm:^6.0.1": - version: 6.0.2 - resolution: "cssnano@npm:6.0.2" + version: 6.0.3 + resolution: "cssnano@npm:6.0.3" dependencies: - cssnano-preset-default: "npm:^6.0.2" + cssnano-preset-default: "npm:^6.0.3" lilconfig: "npm:^3.0.0" peerDependencies: postcss: ^8.4.31 - checksum: 5f4146a6c8937d24b0d1d33e3acd85db7913c7558cc80b23169f86c9a552d091a26e0af6adcc535f8355561872f797a917b9353e38fe935bbaf08ec2b66f5ff8 - languageName: node - linkType: hard - -"csso@npm:5.0.5": - version: 5.0.5 - resolution: "csso@npm:5.0.5" - dependencies: - css-tree: "npm:~2.2.0" - checksum: ab4beb1e97dd7e207c10e9925405b45f15a6cd1b4880a8686ad573aa6d476aed28b4121a666cffd26c37a26179f7b54741f7c257543003bfb244d06a62ad569b + checksum: d1669eb987fd96159bae262ef2f76c1a64fffefe8fa593918a6bda377977798b60fb4a6a871a9b9a9deb11258130ee254fdb8c3144769b3060ad9f2a95a4ed0a languageName: node linkType: hard @@ -6356,6 +6347,15 @@ __metadata: languageName: node linkType: hard +"csso@npm:^5.0.5": + version: 5.0.5 + resolution: "csso@npm:5.0.5" + dependencies: + css-tree: "npm:~2.2.0" + checksum: ab4beb1e97dd7e207c10e9925405b45f15a6cd1b4880a8686ad573aa6d476aed28b4121a666cffd26c37a26179f7b54741f7c257543003bfb244d06a62ad569b + languageName: node + linkType: hard + "cssom@npm:^0.5.0": version: 0.5.0 resolution: "cssom@npm:0.5.0" @@ -12743,29 +12743,29 @@ __metadata: languageName: node linkType: hard -"postcss-colormin@npm:^6.0.1": - version: 6.0.1 - resolution: "postcss-colormin@npm:6.0.1" +"postcss-colormin@npm:^6.0.2": + version: 6.0.2 + resolution: "postcss-colormin@npm:6.0.2" dependencies: - browserslist: "npm:^4.21.4" + browserslist: "npm:^4.22.2" caniuse-api: "npm:^3.0.0" colord: "npm:^2.9.1" postcss-value-parser: "npm:^4.2.0" peerDependencies: postcss: ^8.4.31 - checksum: b0056812b3436b05b6b84284a1ebe68a72299f23e7eeb0b7b40a775978d06a1cbe235f3665e3f694f5de76fe7d9b93db607536d07697b31a59fd4e8705e5b64d + checksum: 229681f9b89ba0909b4c69563837b0c32cc3d1c17ed1b00c33d4abfb0a0ef455124968e4885b5f92c64482e92074cd1958018ec111ed5d118f1e24baeda19c14 languageName: node linkType: hard -"postcss-convert-values@npm:^6.0.1": - version: 6.0.1 - resolution: "postcss-convert-values@npm:6.0.1" +"postcss-convert-values@npm:^6.0.2": + version: 6.0.2 + resolution: "postcss-convert-values@npm:6.0.2" dependencies: - browserslist: "npm:^4.21.4" + browserslist: "npm:^4.22.2" postcss-value-parser: "npm:^4.2.0" peerDependencies: postcss: ^8.4.31 - checksum: 53b951d7475206969c63b8427a2dea0ccba0a7cb08122e5f05aee8d12b09c870c070b101c9f8eceda76ff4d0fd9e5fa9385e83f143d658bb729dbb6a3583b872 + checksum: 882d0b7839ef07ac8ffbf9cb48db0f610939a3496bd0321c7f23096ead676f13e09ab3d9c20ff3dbe2c887e855826051ca7dffeaffce5068cfdc9aaa573a3842 languageName: node linkType: hard @@ -12828,29 +12828,29 @@ __metadata: languageName: node linkType: hard -"postcss-merge-longhand@npm:^6.0.1": - version: 6.0.1 - resolution: "postcss-merge-longhand@npm:6.0.1" +"postcss-merge-longhand@npm:^6.0.2": + version: 6.0.2 + resolution: "postcss-merge-longhand@npm:6.0.2" dependencies: postcss-value-parser: "npm:^4.2.0" - stylehacks: "npm:^6.0.1" + stylehacks: "npm:^6.0.2" peerDependencies: postcss: ^8.4.31 - checksum: 2c0eb81b6c6d3d2af3b129c46d10317b7923f218db1cadcb4723091fb951fe4624638002b65f235151129d4ce9b4775a6ed0d5fa13419c0df580f72e15fa4ad3 + checksum: 2b3fae51bffc5962258d638bc7f415237593b515f369233e023f0eae5b13116297463c04b8c47a7b7af51cba5faaa7f517b653f6123e51935d670d4d4de5a26d languageName: node linkType: hard -"postcss-merge-rules@npm:^6.0.2": - version: 6.0.2 - resolution: "postcss-merge-rules@npm:6.0.2" +"postcss-merge-rules@npm:^6.0.3": + version: 6.0.3 + resolution: "postcss-merge-rules@npm:6.0.3" dependencies: - browserslist: "npm:^4.21.4" + browserslist: "npm:^4.22.2" caniuse-api: "npm:^3.0.0" cssnano-utils: "npm:^4.0.1" - postcss-selector-parser: "npm:^6.0.5" + postcss-selector-parser: "npm:^6.0.15" peerDependencies: postcss: ^8.4.31 - checksum: 138a9921423420116b20e5761a1139392f0bcfcf34264fe11e254917d9c3170e3c0478a1b409e227d22bb0d9820b0168a871a240215d114e9c1e218ee6c132e6 + checksum: c8355db11aa60bedcb1e6535fcd70f6ecec2dadd5c2975d3accf0eedbc92af782ac1f5e91a53866816ce332e4cbf1b94749a9425067935be066bc0c974e30fee languageName: node linkType: hard @@ -12878,27 +12878,27 @@ __metadata: languageName: node linkType: hard -"postcss-minify-params@npm:^6.0.1": - version: 6.0.1 - resolution: "postcss-minify-params@npm:6.0.1" +"postcss-minify-params@npm:^6.0.2": + version: 6.0.2 + resolution: "postcss-minify-params@npm:6.0.2" dependencies: - browserslist: "npm:^4.21.4" + browserslist: "npm:^4.22.2" cssnano-utils: "npm:^4.0.1" postcss-value-parser: "npm:^4.2.0" peerDependencies: postcss: ^8.4.31 - checksum: 0b34817f032ec9793fad4d33f3ba5551531073a36c9120d77194a3edeee860132951ed6954913494e5a6752ae8da1bc5cdb2a44fa5f428621afae8edddb0ca80 + checksum: 6638460d2be4a2eca8adee8409b70d6c6a19aff8cf93fda1b45c9da627b258b6baaa6acb48f51d26cd287704a235f9c9ae2e4744335b1fd47e163177c33896df languageName: node linkType: hard -"postcss-minify-selectors@npm:^6.0.1": - version: 6.0.1 - resolution: "postcss-minify-selectors@npm:6.0.1" +"postcss-minify-selectors@npm:^6.0.2": + version: 6.0.2 + resolution: "postcss-minify-selectors@npm:6.0.2" dependencies: - postcss-selector-parser: "npm:^6.0.5" + postcss-selector-parser: "npm:^6.0.15" peerDependencies: postcss: ^8.4.31 - checksum: ffc7ebb286beda2b2aa0ed13abafc89b5ffe232a48d57d3f2b9f69e167e354482a6f5279e9118bed753bf6e82d3cfb21228a6b07acd93d0dc9e01bbf0e7ebc75 + checksum: 5437b586c1237fc442e7e6078d4f23c987efc456366368b07a0da67332b04bd55821cedf0441e73e1209689f63139e272d930508e2963ba6e27c46561a661128 languageName: node linkType: hard @@ -13010,15 +13010,15 @@ __metadata: languageName: node linkType: hard -"postcss-normalize-unicode@npm:^6.0.1": - version: 6.0.1 - resolution: "postcss-normalize-unicode@npm:6.0.1" +"postcss-normalize-unicode@npm:^6.0.2": + version: 6.0.2 + resolution: "postcss-normalize-unicode@npm:6.0.2" dependencies: - browserslist: "npm:^4.21.4" + browserslist: "npm:^4.22.2" postcss-value-parser: "npm:^4.2.0" peerDependencies: postcss: ^8.4.31 - checksum: 8057748dade94dc2dd63a3b75a85e394c2e9a7076053886ff08aa9b7729d383f204eda52d882e5361ae1ec493036e90b2e18dcc5f8c9b3a8f1cbfada12bcc05b + checksum: ea696194f65ad31de2a9c022f1946a07c298f04070706d88a20061845e1e052e645c74b5bc785595814db87d14e435f85e968a44855dedc207d8c0b5d43b1aee languageName: node linkType: hard @@ -13056,15 +13056,15 @@ __metadata: languageName: node linkType: hard -"postcss-reduce-initial@npm:^6.0.1": - version: 6.0.1 - resolution: "postcss-reduce-initial@npm:6.0.1" +"postcss-reduce-initial@npm:^6.0.2": + version: 6.0.2 + resolution: "postcss-reduce-initial@npm:6.0.2" dependencies: - browserslist: "npm:^4.21.4" + browserslist: "npm:^4.22.2" caniuse-api: "npm:^3.0.0" peerDependencies: postcss: ^8.4.31 - checksum: 3f8f6c26ceeb79ddc285b0e01183fe30e911dd26b3abcdca56568e2bef3747f2b7f22ee3f9117e9752e1e93c10bcd88bd6a2842ca525b54336726292ebd3c3ad + checksum: d35ad6f9725cdceb390a97a461e8594df7fbed4c55497c90d07c42f8343bf80139e720eaebc580bf480bf10e92959490aa308af66d8802ba71c327bdf08c93a1 languageName: node linkType: hard @@ -13104,36 +13104,36 @@ __metadata: languageName: node linkType: hard -"postcss-selector-parser@npm:^6.0.11, postcss-selector-parser@npm:^6.0.13, postcss-selector-parser@npm:^6.0.2, postcss-selector-parser@npm:^6.0.4, postcss-selector-parser@npm:^6.0.5": - version: 6.0.13 - resolution: "postcss-selector-parser@npm:6.0.13" +"postcss-selector-parser@npm:^6.0.11, postcss-selector-parser@npm:^6.0.13, postcss-selector-parser@npm:^6.0.15, postcss-selector-parser@npm:^6.0.2, postcss-selector-parser@npm:^6.0.4": + version: 6.0.15 + resolution: "postcss-selector-parser@npm:6.0.15" dependencies: cssesc: "npm:^3.0.0" util-deprecate: "npm:^1.0.2" - checksum: 51f099b27f7c7198ea1826470ef0adfa58b3bd3f59b390fda123baa0134880a5fa9720137b6009c4c1373357b144f700b0edac73335d0067422063129371444e + checksum: 48b425d6cef497bcf6b7d136f6fd95cfca43026955e07ec9290d3c15457de3a862dbf251dd36f42c07a0d5b5ab6f31e41acefeff02528995a989b955505e440b languageName: node linkType: hard -"postcss-svgo@npm:^6.0.1": - version: 6.0.1 - resolution: "postcss-svgo@npm:6.0.1" +"postcss-svgo@npm:^6.0.2": + version: 6.0.2 + resolution: "postcss-svgo@npm:6.0.2" dependencies: postcss-value-parser: "npm:^4.2.0" - svgo: "npm:^3.0.5" + svgo: "npm:^3.2.0" peerDependencies: postcss: ^8.4.31 - checksum: 021da9b0d0696fce970f407891a0d6c05e51d1908af435026e0cd5936a75cd8502a7d504cd0e6a33b6f3369fee41f01b848e5bd919aecc3e804ce6308e91a6cc + checksum: db607404d09af256c7957a0ace822d651a00a52a1796da603f93ba3f0a095ac7595e1f624b9dc53f362ab10e382845d7873f485980f9c92fcb86256833f5e835 languageName: node linkType: hard -"postcss-unique-selectors@npm:^6.0.1": - version: 6.0.1 - resolution: "postcss-unique-selectors@npm:6.0.1" +"postcss-unique-selectors@npm:^6.0.2": + version: 6.0.2 + resolution: "postcss-unique-selectors@npm:6.0.2" dependencies: - postcss-selector-parser: "npm:^6.0.5" + postcss-selector-parser: "npm:^6.0.15" peerDependencies: postcss: ^8.4.31 - checksum: 637e35775d0ee8fbcf4a81b28d3832c5076de7c0232eb7769d4fbbf783f26793e2ec95e18461ae3b9f5f5cd63c3de9db102464487ba2488d4947aad24dc8841f + checksum: a0fe112d1094f90e1bfcfd2174a74b2fd0630a24449e9942923d02956c7d64ea4add5adede53d9efb3f6d40cd388ac150d032a115f6a46b73d5f3d3d26fa1bb7 languageName: node linkType: hard @@ -15606,15 +15606,15 @@ __metadata: languageName: node linkType: hard -"stylehacks@npm:^6.0.1": - version: 6.0.1 - resolution: "stylehacks@npm:6.0.1" +"stylehacks@npm:^6.0.2": + version: 6.0.2 + resolution: "stylehacks@npm:6.0.2" dependencies: - browserslist: "npm:^4.21.4" - postcss-selector-parser: "npm:^6.0.4" + browserslist: "npm:^4.22.2" + postcss-selector-parser: "npm:^6.0.15" peerDependencies: postcss: ^8.4.31 - checksum: 0877016f5b2a06b8ceaf39382b0c33da11ea93268209444f67f29b1ce465994058f305fc3bc90dda21e8664c959561fbb06ba12b82289c3b26ba832c6979d513 + checksum: 658cac8b28edcb94d1db67808ab3aaa511cb1b9293594fc95607ee42ac4f57e742d9a1fa3ff5d5849db692971dc2a310e9ac1ed0bd4ea4bc48c80f5a6ef823fc languageName: node linkType: hard @@ -15838,20 +15838,20 @@ __metadata: languageName: node linkType: hard -"svgo@npm:^3.0.5": - version: 3.1.0 - resolution: "svgo@npm:3.1.0" +"svgo@npm:^3.2.0": + version: 3.2.0 + resolution: "svgo@npm:3.2.0" dependencies: "@trysound/sax": "npm:0.2.0" commander: "npm:^7.2.0" css-select: "npm:^5.1.0" - css-tree: "npm:^2.2.1" + css-tree: "npm:^2.3.1" css-what: "npm:^6.1.0" - csso: "npm:5.0.5" + csso: "npm:^5.0.5" picocolors: "npm:^1.0.0" bin: svgo: ./bin/svgo - checksum: b3f00b3319dee6ddc53f8b8ac5acef581860e1708c98b492169e096621edc1bdf46e3778099e3dffb5116bf0d4c074a686099843dbc020c73b3ccfae7b6a88f0 + checksum: 28fa9061ccbcf2e3616d48d1feb613aaa05f8f290a329beb0e585914f1864385152934a7d4d683a4609fafbae3d51666633437c359c5c5ef74fb58ad09092a7c languageName: node linkType: hard From f06c1f1552f289bd357e4f05cd6486832cf5028f Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 4 Jan 2024 04:20:32 -0500 Subject: [PATCH 16/23] Fix `Capybara/ClickLinkOrButtonStyle` cop in spec/features (#28576) --- Gemfile.lock | 2 +- spec/features/admin/accounts_spec.rb | 8 ++--- spec/features/admin/custom_emojis_spec.rb | 2 +- spec/features/admin/domain_blocks_spec.rb | 18 +++++----- .../admin/email_domain_blocks_spec.rb | 2 +- spec/features/admin/ip_blocks_spec.rb | 2 +- spec/features/admin/software_updates_spec.rb | 4 +-- spec/features/admin/statuses_spec.rb | 2 +- .../links/preview_card_providers_spec.rb | 2 +- spec/features/admin/trends/links_spec.rb | 2 +- spec/features/admin/trends/statuses_spec.rb | 2 +- spec/features/admin/trends/tags_spec.rb | 2 +- spec/features/captcha_spec.rb | 2 +- spec/features/log_in_spec.rb | 6 ++-- spec/features/oauth_spec.rb | 36 +++++++++---------- spec/support/stories/profile_stories.rb | 2 +- spec/system/new_statuses_spec.rb | 4 +-- 17 files changed, 49 insertions(+), 49 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 8d01167537cc6a..c3f27966d64812 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -676,7 +676,7 @@ GEM unicode-display_width (>= 2.4.0, < 3.0) rubocop-ast (1.30.0) parser (>= 3.2.1.0) - rubocop-capybara (2.19.0) + rubocop-capybara (2.20.0) rubocop (~> 1.41) rubocop-factory_bot (2.24.0) rubocop (~> 1.33) diff --git a/spec/features/admin/accounts_spec.rb b/spec/features/admin/accounts_spec.rb index ad9c51485a76db..6d7bab1844ccbf 100644 --- a/spec/features/admin/accounts_spec.rb +++ b/spec/features/admin/accounts_spec.rb @@ -22,7 +22,7 @@ context 'without selecting any accounts' do it 'displays a notice about account selection' do - click_button button_for_suspend + click_on button_for_suspend expect(page).to have_content(selection_error_text) end @@ -32,7 +32,7 @@ it 'suspends the account' do batch_checkbox_for(approved_user_account).check - click_button button_for_suspend + click_on button_for_suspend expect(approved_user_account.reload).to be_suspended end @@ -42,7 +42,7 @@ it 'approves the account user' do batch_checkbox_for(unapproved_user_account).check - click_button button_for_approve + click_on button_for_approve expect(unapproved_user_account.reload.user).to be_approved end @@ -52,7 +52,7 @@ it 'rejects and removes the account' do batch_checkbox_for(unapproved_user_account).check - click_button button_for_reject + click_on button_for_reject expect { unapproved_user_account.reload }.to raise_error(ActiveRecord::RecordNotFound) end diff --git a/spec/features/admin/custom_emojis_spec.rb b/spec/features/admin/custom_emojis_spec.rb index 3fea8f06fe6f50..8a8b6efcd119fb 100644 --- a/spec/features/admin/custom_emojis_spec.rb +++ b/spec/features/admin/custom_emojis_spec.rb @@ -16,7 +16,7 @@ context 'without selecting any records' do it 'displays a notice about selection' do - click_button button_for_enable + click_on button_for_enable expect(page).to have_content(selection_error_text) end diff --git a/spec/features/admin/domain_blocks_spec.rb b/spec/features/admin/domain_blocks_spec.rb index 4379ac91dbabb5..6a1405cdf64169 100644 --- a/spec/features/admin/domain_blocks_spec.rb +++ b/spec/features/admin/domain_blocks_spec.rb @@ -14,7 +14,7 @@ fill_in 'domain_block_domain', with: 'example.com' select I18n.t('admin.domain_blocks.new.severity.silence'), from: 'domain_block_severity' - click_button I18n.t('admin.domain_blocks.new.create') + click_on I18n.t('admin.domain_blocks.new.create') expect(DomainBlock.exists?(domain: 'example.com', severity: 'silence')).to be true expect(DomainBlockWorker).to have_received(:perform_async) @@ -27,14 +27,14 @@ fill_in 'domain_block_domain', with: 'example.com' select I18n.t('admin.domain_blocks.new.severity.suspend'), from: 'domain_block_severity' - click_button I18n.t('admin.domain_blocks.new.create') + click_on I18n.t('admin.domain_blocks.new.create') # It doesn't immediately block but presents a confirmation screen expect(page).to have_title(I18n.t('admin.domain_blocks.confirm_suspension.title', domain: 'example.com')) expect(DomainBlockWorker).to_not have_received(:perform_async) # Confirming creates a block - click_button I18n.t('admin.domain_blocks.confirm_suspension.confirm') + click_on I18n.t('admin.domain_blocks.confirm_suspension.confirm') expect(DomainBlock.exists?(domain: 'example.com', severity: 'suspend')).to be true expect(DomainBlockWorker).to have_received(:perform_async) @@ -49,14 +49,14 @@ fill_in 'domain_block_domain', with: 'example.com' select I18n.t('admin.domain_blocks.new.severity.suspend'), from: 'domain_block_severity' - click_button I18n.t('admin.domain_blocks.new.create') + click_on I18n.t('admin.domain_blocks.new.create') # It doesn't immediately block but presents a confirmation screen expect(page).to have_title(I18n.t('admin.domain_blocks.confirm_suspension.title', domain: 'example.com')) expect(DomainBlockWorker).to_not have_received(:perform_async) # Confirming updates the block - click_button I18n.t('admin.domain_blocks.confirm_suspension.confirm') + click_on I18n.t('admin.domain_blocks.confirm_suspension.confirm') expect(domain_block.reload.severity).to eq 'suspend' expect(DomainBlockWorker).to have_received(:perform_async) @@ -71,14 +71,14 @@ fill_in 'domain_block_domain', with: 'subdomain.example.com' select I18n.t('admin.domain_blocks.new.severity.suspend'), from: 'domain_block_severity' - click_button I18n.t('admin.domain_blocks.new.create') + click_on I18n.t('admin.domain_blocks.new.create') # It doesn't immediately block but presents a confirmation screen expect(page).to have_title(I18n.t('admin.domain_blocks.confirm_suspension.title', domain: 'subdomain.example.com')) expect(DomainBlockWorker).to_not have_received(:perform_async) # Confirming creates the block - click_button I18n.t('admin.domain_blocks.confirm_suspension.confirm') + click_on I18n.t('admin.domain_blocks.confirm_suspension.confirm') expect(DomainBlock.where(domain: 'subdomain.example.com', severity: 'suspend')).to exist expect(DomainBlockWorker).to have_received(:perform_async) @@ -96,14 +96,14 @@ visit edit_admin_domain_block_path(domain_block) select I18n.t('admin.domain_blocks.new.severity.suspend'), from: 'domain_block_severity' - click_button I18n.t('generic.save_changes') + click_on I18n.t('generic.save_changes') # It doesn't immediately block but presents a confirmation screen expect(page).to have_title(I18n.t('admin.domain_blocks.confirm_suspension.title', domain: 'example.com')) expect(DomainBlockWorker).to_not have_received(:perform_async) # Confirming updates the block - click_button I18n.t('admin.domain_blocks.confirm_suspension.confirm') + click_on I18n.t('admin.domain_blocks.confirm_suspension.confirm') expect(DomainBlockWorker).to have_received(:perform_async) expect(domain_block.reload.severity).to eq 'suspend' diff --git a/spec/features/admin/email_domain_blocks_spec.rb b/spec/features/admin/email_domain_blocks_spec.rb index 80efe72e95c568..14959cbe74b0dd 100644 --- a/spec/features/admin/email_domain_blocks_spec.rb +++ b/spec/features/admin/email_domain_blocks_spec.rb @@ -16,7 +16,7 @@ context 'without selecting any records' do it 'displays a notice about selection' do - click_button button_for_delete + click_on button_for_delete expect(page).to have_content(selection_error_text) end diff --git a/spec/features/admin/ip_blocks_spec.rb b/spec/features/admin/ip_blocks_spec.rb index 465c8891907013..c9b16f6f78fb1d 100644 --- a/spec/features/admin/ip_blocks_spec.rb +++ b/spec/features/admin/ip_blocks_spec.rb @@ -16,7 +16,7 @@ context 'without selecting any records' do it 'displays a notice about selection' do - click_button button_for_delete + click_on button_for_delete expect(page).to have_content(selection_error_text) end diff --git a/spec/features/admin/software_updates_spec.rb b/spec/features/admin/software_updates_spec.rb index a2373d35a6080c..4a635d1a794f8f 100644 --- a/spec/features/admin/software_updates_spec.rb +++ b/spec/features/admin/software_updates_spec.rb @@ -11,13 +11,13 @@ it 'shows a link to the software updates page, which links to release notes' do visit settings_profile_path - click_link I18n.t('admin.critical_update_pending') + click_on I18n.t('admin.critical_update_pending') expect(page).to have_title(I18n.t('admin.software_updates.title')) expect(page).to have_content('99.99.99') - click_link I18n.t('admin.software_updates.release_notes') + click_on I18n.t('admin.software_updates.release_notes') expect(page).to have_current_path('https://github.com/mastodon/mastodon/releases/v99', url: true) end end diff --git a/spec/features/admin/statuses_spec.rb b/spec/features/admin/statuses_spec.rb index a21c901a921b23..531d0de9538b21 100644 --- a/spec/features/admin/statuses_spec.rb +++ b/spec/features/admin/statuses_spec.rb @@ -17,7 +17,7 @@ context 'without selecting any records' do it 'displays a notice about selection' do - click_button button_for_report + click_on button_for_report expect(page).to have_content(selection_error_text) end diff --git a/spec/features/admin/trends/links/preview_card_providers_spec.rb b/spec/features/admin/trends/links/preview_card_providers_spec.rb index cf9796abf362cd..dca89117b1079a 100644 --- a/spec/features/admin/trends/links/preview_card_providers_spec.rb +++ b/spec/features/admin/trends/links/preview_card_providers_spec.rb @@ -16,7 +16,7 @@ context 'without selecting any records' do it 'displays a notice about selection' do - click_button button_for_allow + click_on button_for_allow expect(page).to have_content(selection_error_text) end diff --git a/spec/features/admin/trends/links_spec.rb b/spec/features/admin/trends/links_spec.rb index 8b1b991a5a85cc..99638bc069ffbe 100644 --- a/spec/features/admin/trends/links_spec.rb +++ b/spec/features/admin/trends/links_spec.rb @@ -16,7 +16,7 @@ context 'without selecting any records' do it 'displays a notice about selection' do - click_button button_for_allow + click_on button_for_allow expect(page).to have_content(selection_error_text) end diff --git a/spec/features/admin/trends/statuses_spec.rb b/spec/features/admin/trends/statuses_spec.rb index a578ab05593c08..779a15d38fbec3 100644 --- a/spec/features/admin/trends/statuses_spec.rb +++ b/spec/features/admin/trends/statuses_spec.rb @@ -16,7 +16,7 @@ context 'without selecting any records' do it 'displays a notice about selection' do - click_button button_for_allow + click_on button_for_allow expect(page).to have_content(selection_error_text) end diff --git a/spec/features/admin/trends/tags_spec.rb b/spec/features/admin/trends/tags_spec.rb index 7502bc8c6f50c1..52e49c3a5d92b6 100644 --- a/spec/features/admin/trends/tags_spec.rb +++ b/spec/features/admin/trends/tags_spec.rb @@ -16,7 +16,7 @@ context 'without selecting any records' do it 'displays a notice about selection' do - click_button button_for_allow + click_on button_for_allow expect(page).to have_content(selection_error_text) end diff --git a/spec/features/captcha_spec.rb b/spec/features/captcha_spec.rb index 906aec4af977bd..15c37eb463aebb 100644 --- a/spec/features/captcha_spec.rb +++ b/spec/features/captcha_spec.rb @@ -23,7 +23,7 @@ expect(user.reload.confirmed?).to be false # It redirects to app and confirms user - click_button I18n.t('challenge.confirm') + click_on I18n.t('challenge.confirm') expect(user.reload.confirmed?).to be true expect(page).to have_current_path(/\A#{client_app.confirmation_redirect_uri}/, url: true) diff --git a/spec/features/log_in_spec.rb b/spec/features/log_in_spec.rb index 7e5196aba99564..c64e19d2b7c43f 100644 --- a/spec/features/log_in_spec.rb +++ b/spec/features/log_in_spec.rb @@ -19,7 +19,7 @@ it 'A valid email and password user is able to log in' do fill_in 'user_email', with: email fill_in 'user_password', with: password - click_button I18n.t('auth.login') + click_on I18n.t('auth.login') expect(subject).to have_css('div.app-holder') end @@ -27,7 +27,7 @@ it 'A invalid email and password user is not able to log in' do fill_in 'user_email', with: 'invalid_email' fill_in 'user_password', with: 'invalid_password' - click_button I18n.t('auth.login') + click_on I18n.t('auth.login') expect(subject).to have_css('.flash-message', text: failure_message('invalid')) end @@ -38,7 +38,7 @@ it 'A unconfirmed user is able to log in' do fill_in 'user_email', with: email fill_in 'user_password', with: password - click_button I18n.t('auth.login') + click_on I18n.t('auth.login') expect(subject).to have_css('div.admin-wrapper') end diff --git a/spec/features/oauth_spec.rb b/spec/features/oauth_spec.rb index 0e612b56a5a24f..967956cc8ea91a 100644 --- a/spec/features/oauth_spec.rb +++ b/spec/features/oauth_spec.rb @@ -20,7 +20,7 @@ expect(page).to have_content(I18n.t('doorkeeper.authorizations.buttons.authorize')) # Upon authorizing, it redirects to the apps' callback URL - click_button I18n.t('doorkeeper.authorizations.buttons.authorize') + click_on I18n.t('doorkeeper.authorizations.buttons.authorize') expect(page).to have_current_path(/\A#{client_app.redirect_uri}/, url: true) # It grants the app access to the account @@ -35,7 +35,7 @@ expect(page).to have_content(I18n.t('doorkeeper.authorizations.buttons.deny')) # Upon denying, it redirects to the apps' callback URL - click_button I18n.t('doorkeeper.authorizations.buttons.deny') + click_on I18n.t('doorkeeper.authorizations.buttons.deny') expect(page).to have_current_path(/\A#{client_app.redirect_uri}/, url: true) # It does not grant the app access to the account @@ -63,17 +63,17 @@ # Failing to log-in presents the form again fill_in 'user_email', with: email fill_in 'user_password', with: 'wrong password' - click_button I18n.t('auth.login') + click_on I18n.t('auth.login') expect(page).to have_content(I18n.t('auth.login')) # Logging in redirects to an authorization page fill_in 'user_email', with: email fill_in 'user_password', with: password - click_button I18n.t('auth.login') + click_on I18n.t('auth.login') expect(page).to have_content(I18n.t('doorkeeper.authorizations.buttons.authorize')) # Upon authorizing, it redirects to the apps' callback URL - click_button I18n.t('doorkeeper.authorizations.buttons.authorize') + click_on I18n.t('doorkeeper.authorizations.buttons.authorize') expect(page).to have_current_path(/\A#{client_app.redirect_uri}/, url: true) # It grants the app access to the account @@ -90,17 +90,17 @@ # Failing to log-in presents the form again fill_in 'user_email', with: email fill_in 'user_password', with: 'wrong password' - click_button I18n.t('auth.login') + click_on I18n.t('auth.login') expect(page).to have_content(I18n.t('auth.login')) # Logging in redirects to an authorization page fill_in 'user_email', with: email fill_in 'user_password', with: password - click_button I18n.t('auth.login') + click_on I18n.t('auth.login') expect(page).to have_content(I18n.t('doorkeeper.authorizations.buttons.authorize')) # Upon denying, it redirects to the apps' callback URL - click_button I18n.t('doorkeeper.authorizations.buttons.deny') + click_on I18n.t('doorkeeper.authorizations.buttons.deny') expect(page).to have_current_path(/\A#{client_app.redirect_uri}/, url: true) # It does not grant the app access to the account @@ -120,27 +120,27 @@ # Failing to log-in presents the form again fill_in 'user_email', with: email fill_in 'user_password', with: 'wrong password' - click_button I18n.t('auth.login') + click_on I18n.t('auth.login') expect(page).to have_content(I18n.t('auth.login')) # Logging in redirects to a two-factor authentication page fill_in 'user_email', with: email fill_in 'user_password', with: password - click_button I18n.t('auth.login') + click_on I18n.t('auth.login') expect(page).to have_content(I18n.t('simple_form.hints.sessions.otp')) # Filling in an incorrect two-factor authentication code presents the form again fill_in 'user_otp_attempt', with: 'wrong' - click_button I18n.t('auth.login') + click_on I18n.t('auth.login') expect(page).to have_content(I18n.t('simple_form.hints.sessions.otp')) # Filling in the correct TOTP code redirects to an app authorization page fill_in 'user_otp_attempt', with: user.current_otp - click_button I18n.t('auth.login') + click_on I18n.t('auth.login') expect(page).to have_content(I18n.t('doorkeeper.authorizations.buttons.authorize')) # Upon authorizing, it redirects to the apps' callback URL - click_button I18n.t('doorkeeper.authorizations.buttons.authorize') + click_on I18n.t('doorkeeper.authorizations.buttons.authorize') expect(page).to have_current_path(/\A#{client_app.redirect_uri}/, url: true) # It grants the app access to the account @@ -157,27 +157,27 @@ # Failing to log-in presents the form again fill_in 'user_email', with: email fill_in 'user_password', with: 'wrong password' - click_button I18n.t('auth.login') + click_on I18n.t('auth.login') expect(page).to have_content(I18n.t('auth.login')) # Logging in redirects to a two-factor authentication page fill_in 'user_email', with: email fill_in 'user_password', with: password - click_button I18n.t('auth.login') + click_on I18n.t('auth.login') expect(page).to have_content(I18n.t('simple_form.hints.sessions.otp')) # Filling in an incorrect two-factor authentication code presents the form again fill_in 'user_otp_attempt', with: 'wrong' - click_button I18n.t('auth.login') + click_on I18n.t('auth.login') expect(page).to have_content(I18n.t('simple_form.hints.sessions.otp')) # Filling in the correct TOTP code redirects to an app authorization page fill_in 'user_otp_attempt', with: user.current_otp - click_button I18n.t('auth.login') + click_on I18n.t('auth.login') expect(page).to have_content(I18n.t('doorkeeper.authorizations.buttons.authorize')) # Upon denying, it redirects to the apps' callback URL - click_button I18n.t('doorkeeper.authorizations.buttons.deny') + click_on I18n.t('doorkeeper.authorizations.buttons.deny') expect(page).to have_current_path(/\A#{client_app.redirect_uri}/, url: true) # It does not grant the app access to the account diff --git a/spec/support/stories/profile_stories.rb b/spec/support/stories/profile_stories.rb index 82667ca080c99b..2b345ddef10b31 100644 --- a/spec/support/stories/profile_stories.rb +++ b/spec/support/stories/profile_stories.rb @@ -18,7 +18,7 @@ def as_a_logged_in_user visit new_user_session_path fill_in 'user_email', with: email fill_in 'user_password', with: password - click_button I18n.t('auth.login') + click_on I18n.t('auth.login') end def with_alice_as_local_user diff --git a/spec/system/new_statuses_spec.rb b/spec/system/new_statuses_spec.rb index 244101f4d4fd6b..02f2e283931eec 100644 --- a/spec/system/new_statuses_spec.rb +++ b/spec/system/new_statuses_spec.rb @@ -24,7 +24,7 @@ within('.compose-form') do fill_in "What's on your mind?", with: status_text - click_button 'Publish!' + click_on 'Publish!' end expect(subject).to have_css('.status__content__text', text: status_text) @@ -37,7 +37,7 @@ within('.compose-form') do fill_in "What's on your mind?", with: status_text - click_button 'Publish!' + click_on 'Publish!' end expect(subject).to have_css('.status__content__text', text: status_text) From 1af5c3770153e7c3569d13c431e988049956ae8b Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 4 Jan 2024 04:21:27 -0500 Subject: [PATCH 17/23] Use heredoc on federation CLI warning strings (#28578) --- lib/mastodon/cli/federation.rb | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/lib/mastodon/cli/federation.rb b/lib/mastodon/cli/federation.rb index 4a4dde36868a55..8bb46ecb1ae5af 100644 --- a/lib/mastodon/cli/federation.rb +++ b/lib/mastodon/cli/federation.rb @@ -48,19 +48,31 @@ def self_destruct exit(1) unless ask('Type in the domain of the server to confirm:') == Rails.configuration.x.local_domain - say('This operation WILL NOT be reversible.', :yellow) - say('While the data won\'t be erased locally, the server will be in a BROKEN STATE afterwards.', :yellow) - say('The deletion process itself may take a long time, and will be handled by Sidekiq, so do not shut it down until it has finished (you will be able to re-run this command to see the state of the self-destruct process).', :yellow) + say(<<~WARNING, :yellow) + This operation WILL NOT be reversible. + While the data won't be erased locally, the server will be in a BROKEN STATE afterwards. + The deletion process itself may take a long time, and will be handled by Sidekiq, so do not shut it down until it has finished (you will be able to re-run this command to see the state of the self-destruct process). + WARNING exit(1) if no?('Are you sure you want to proceed?') - self_destruct_value = Rails.application.message_verifier('self-destruct').generate(Rails.configuration.x.local_domain) - say('To switch Mastodon to self-destruct mode, add the following variable to your evironment (e.g. by adding a line to your `.env.production`) and restart all Mastodon processes:', :green) - say(" SELF_DESTRUCT=#{self_destruct_value}", :green) - say("\nYou can re-run this command to see the state of the self-destruct process.", :green) + say(<<~INSTRUCTIONS, :green) + To switch Mastodon to self-destruct mode, add the following variable to your evironment (e.g. by adding a line to your `.env.production`) and restart all Mastodon processes: + SELF_DESTRUCT=#{self_destruct_value} + You can re-run this command to see the state of the self-destruct process. + INSTRUCTIONS rescue Interrupt exit(1) end + + private + + def self_destruct_value + Rails + .application + .message_verifier('self-destruct') + .generate(Rails.configuration.x.local_domain) + end end end end From bdf4750633703d97269522759ea6f2f8ecbd4976 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 4 Jan 2024 09:24:13 +0000 Subject: [PATCH 18/23] New Crowdin Translations (automated) (#28590) Co-authored-by: GitHub Actions --- app/javascript/mastodon/locales/ia.json | 25 +++++++++++++++++++++++- app/javascript/mastodon/locales/lad.json | 1 + app/javascript/mastodon/locales/nn.json | 2 +- app/javascript/mastodon/locales/no.json | 2 +- config/locales/devise.ie.yml | 7 +++++++ config/locales/doorkeeper.ie.yml | 3 +++ config/locales/lad.yml | 21 ++++++++++++++++++++ config/locales/simple_form.ie.yml | 12 ++++++++++++ 8 files changed, 70 insertions(+), 3 deletions(-) diff --git a/app/javascript/mastodon/locales/ia.json b/app/javascript/mastodon/locales/ia.json index 35397b8e12f747..9781d6aa773191 100644 --- a/app/javascript/mastodon/locales/ia.json +++ b/app/javascript/mastodon/locales/ia.json @@ -38,12 +38,14 @@ "confirmation_modal.cancel": "Cancellar", "confirmations.delete.confirm": "Deler", "confirmations.delete_list.confirm": "Deler", + "confirmations.edit.confirm": "Modificar", "confirmations.logout.confirm": "Clauder le session", "copy_icon_button.copied": "Copiate al area de transferentia", "copypaste.copy_to_clipboard": "Copiar al area de transferentia", "disabled_account_banner.account_settings": "Parametros de conto", "dismissable_banner.dismiss": "Dimitter", "emoji_button.activity": "Activitate", + "emoji_button.clear": "Rader", "emoji_button.custom": "Personalisate", "emoji_button.search_results": "Resultatos de recerca", "empty_column.account_unavailable": "Profilo non disponibile", @@ -69,16 +71,37 @@ "navigation_bar.about": "A proposito de", "navigation_bar.advanced_interface": "Aperir in un interfacie web avantiate", "navigation_bar.blocks": "Usatores blocate", + "navigation_bar.discover": "Discoperir", + "navigation_bar.edit_profile": "Modificar profilo", "navigation_bar.favourites": "Favoritos", "navigation_bar.lists": "Listas", "navigation_bar.logout": "Clauder le session", "navigation_bar.preferences": "Preferentias", + "navigation_bar.search": "Cercar", "navigation_bar.security": "Securitate", "notifications.column_settings.alert": "Notificationes de scriptorio", "notifications.column_settings.filter_bar.advanced": "Monstrar tote le categorias", "notifications.column_settings.sound": "Reproducer sono", "notifications.filter.all": "Toto", + "notifications.grant_permission": "Conceder permission.", + "notifications.group": "{count} notificationes", "onboarding.compose.template": "Salute #Mastodon!", "onboarding.profile.save_and_continue": "Salvar e continuar", - "onboarding.share.title": "Compartir tu profilo" + "onboarding.share.title": "Compartir tu profilo", + "onboarding.steps.share_profile.title": "Compartir tu profilo de Mastodon", + "relative_time.just_now": "ora", + "relative_time.today": "hodie", + "reply_indicator.cancel": "Cancellar", + "report.next": "Sequente", + "report.placeholder": "Commentos additional", + "report.reasons.dislike": "Non me place", + "search.quick_action.go_to_account": "Vader al profilo {x}", + "search_results.accounts": "Profilos", + "search_results.see_all": "Vider toto", + "status.delete": "Deler", + "status.share": "Compartir", + "status.translate": "Traducer", + "status.translated_from_with": "Traducite ab {lang} usante {provider}", + "tabs_bar.home": "Initio", + "tabs_bar.notifications": "Notificationes" } diff --git a/app/javascript/mastodon/locales/lad.json b/app/javascript/mastodon/locales/lad.json index ce6cb564730ef6..2067edcc706950 100644 --- a/app/javascript/mastodon/locales/lad.json +++ b/app/javascript/mastodon/locales/lad.json @@ -501,6 +501,7 @@ "onboarding.steps.setup_profile.title": "Personaliza tu profil", "onboarding.steps.share_profile.body": "Informe a tus amigos komo toparte en Mastodon", "onboarding.steps.share_profile.title": "Partaja tu profil de Mastodon", + "password_confirmation.mismatching": "Los dos kodes son desferentes", "picture_in_picture.restore": "Restora", "poll.closed": "Serrado", "poll.refresh": "Arefreska", diff --git a/app/javascript/mastodon/locales/nn.json b/app/javascript/mastodon/locales/nn.json index e5b1d2b3780e63..ec2ff8214457b7 100644 --- a/app/javascript/mastodon/locales/nn.json +++ b/app/javascript/mastodon/locales/nn.json @@ -606,7 +606,7 @@ "search.quick_action.status_search": "Innlegg som samsvarer med {x}", "search.search_or_paste": "Søk eller lim inn URL", "search_popout.full_text_search_disabled_message": "Ikkje tilgjengeleg på {domain}.", - "search_popout.full_text_search_logged_out_message": "Bare tilgjengelig ved innlogging.", + "search_popout.full_text_search_logged_out_message": "Bare tilgjengelig når man er logget inn.", "search_popout.language_code": "ISO-språkkode", "search_popout.options": "Søkjealternativ", "search_popout.quick_actions": "Hurtighandlinger", diff --git a/app/javascript/mastodon/locales/no.json b/app/javascript/mastodon/locales/no.json index c0f50283acbdd9..50da3bb2be109b 100644 --- a/app/javascript/mastodon/locales/no.json +++ b/app/javascript/mastodon/locales/no.json @@ -606,7 +606,7 @@ "search.quick_action.status_search": "Innlegg som samsvarer med {x}", "search.search_or_paste": "Søk eller lim inn URL", "search_popout.full_text_search_disabled_message": "Ikke tilgjengelig på {domain}.", - "search_popout.full_text_search_logged_out_message": "Bare tilgjengelig ved innlogging.", + "search_popout.full_text_search_logged_out_message": "Bare tilgjengelig når man er logget inn.", "search_popout.language_code": "ISO språkkode", "search_popout.options": "Alternativer for søk", "search_popout.quick_actions": "Hurtighandlinger", diff --git a/config/locales/devise.ie.yml b/config/locales/devise.ie.yml index e4f2e6fb190f17..687e7115a6d152 100644 --- a/config/locales/devise.ie.yml +++ b/config/locales/devise.ie.yml @@ -46,6 +46,10 @@ ie: title: 2FA desvalidat two_factor_enabled: title: 2FA permisset + two_factor_recovery_codes_changed: + explanation: Li anteyan codes de recuperation ha esset ínvalidat, e novis generat. + subject: 'Mastodon: 2-factor codes de recuperation regenerat' + title: 2FA codes de recuperation changeat unlock_instructions: subject: 'Mastodon: Desserral instructiones' webauthn_credential: @@ -55,8 +59,11 @@ ie: webauthn_disabled: subject: 'Mastodon: Autentication con claves de securitá desactivisat' title: Claves de securitá desactivisat + webauthn_enabled: + title: Claves de securitá activisat omniauth_callbacks: failure: Ne posset autenticar te de %{kind} pro "%{reason}". + success: Successosimen autenticat de conto %{kind}. passwords: no_token: Tu ne posse accessar ti-ci págine sin venir de un email pri reiniciar li passa-parol. Si tu ha venit de un email pri reiniciar li passa-parol, ples far cert que tu usat li complet URL providet. send_instructions: Si tui email-adresse existe in nor database, tu va reciver un ligament por recuperar li passa-parol a tui email-adresse in quelc minutes. Ples vider tui spam-emails si tu ne recivet ti email. diff --git a/config/locales/doorkeeper.ie.yml b/config/locales/doorkeeper.ie.yml index 86a5de7b37ecca..b778871e3a4879 100644 --- a/config/locales/doorkeeper.ie.yml +++ b/config/locales/doorkeeper.ie.yml @@ -31,6 +31,7 @@ ie: redirect_uri: Usar un linea per URI index: application: Aplication + callback_url: URL de retrovocada delete: Deleter empty: Tu have null aplicationes. name: Nómine @@ -42,6 +43,7 @@ ie: show: actions: Actiones application_id: Clave de client + callback_urls: URLs de retrovocada secret: Secrete de client title: 'Aplication: %{name}' authorizations: @@ -51,6 +53,7 @@ ie: error: title: Alquo ha errat new: + review_permissions: Inspecter permissiones title: Autorisation besonat authorized_applications: buttons: diff --git a/config/locales/lad.yml b/config/locales/lad.yml index 5c541d9f999423..323ade8ddb0968 100644 --- a/config/locales/lad.yml +++ b/config/locales/lad.yml @@ -383,7 +383,11 @@ lad: confirm_suspension: cancel: Anula confirm: Suspende + permanent_action: Si kites la suspensyon no restoraras dingunos datos ni relasyones. + remove_all_data: Esto efasara todo el kontenido, multimedia i datos de profiles de los kuentos en este domeno de tu sirvidor. + stop_communication: Tu sirvidor deshara de komunikarse kon estos sirvidores. title: Konfirma bloko de domeno para %{domain} + undo_relationships: Esto kitara todas las relasyones de segimyento entre tu kuentos en estos sirvidores i el tu sirvidor. created_msg: El bloko de domeno esta siendo prosesado destroyed_msg: El bloko de domeno se dezizo domain: Domeno @@ -772,6 +776,8 @@ lad: type: Tipo types: major: Versyon prinsipala + minor: Versyon minora + patch: Versyon de remendo – koreksyones de yerros i trokamientos simples version: Versyon statuses: account: Autor @@ -829,8 +835,10 @@ lad: message_html: No ay dingun prosedura Sidekiq en egzekusion para la(s) kola(s) %{value}. Por favor, reviza tu konfigurasyon de Sidekiq software_version_critical_check: action: Amostra aktualizasyones desponivles + message_html: Una aktualizasyon kritika de Mastodon esta desponivle. Por favor aktualiza pishin. software_version_patch_check: action: Amostra aktualizasyones desponivles + message_html: Una aktualizasyon de Mastodon kon koreksyon de yerros esta desponivle. upload_check_privacy_error: action: Klika aki para mas enformasyon message_html: "Tu sirvidor de web es mal konfigurado. La privasita de tus utilizadores esta en riziko." @@ -945,6 +953,7 @@ lad: next_steps: Puedes achetar la apelasyon para dezazer la dechizyon de moderasyon, o ignorarla. subject: "%{username} esta apelando a una dechizyon de moderasyon en %{instance}" new_critical_software_updates: + body: Ay mueva versyon kritika de Mastodon. Es posivle ke keras aktualizar pishin! subject: Ay aktualizasyones kritikas de Mastodon desponivles para %{instance}! new_pending_account: body: Los peratim del muevo kuento estan abashos. Puedes achetar o refuzar esta aplikasyon. @@ -1045,13 +1054,17 @@ lad: accept: Acheta back: Atras preamble: Estas son establesidas i aplikadas por los moderadores de %{domain}. + preamble_invited: Antes de kontinuar, por favor reviza las reglas del sirvidor establesidas por los moderatores de %{domain}. title: Algunas reglas bazikas. title_invited: Fuites envitado. security: Sigurita set_new_password: Establese muevo kod setup: email_below_hint_html: Mira en tu kuti de spam o solisita de muevo. Si el adreso de posta elektronika ke aparese aki es yerrado, puedes trokarlo aki. + email_settings_hint_html: Klika el atadjiko ke te embimos para verifikar %{email}. Asperaremos aki. link_not_received: No risivites un atadijo? + new_confirmation_instructions_sent: Resiviras un muevo mesaj de posta elektronika kon el atadjio de konfirmasyon en unos minutos! + title: Reviza tu kuti de arivo sign_in: preamble_html: Konektate kon tus kredensiales de %{domain}. Si tu kuento esta balabayado en otruno servidor, no puedras konektarte aki. title: Konektate kon %{domain} @@ -1246,9 +1259,11 @@ lad: imports: errors: empty: Dosya CSV vaziya + incompatible_type: Inkompativle kon el tipo de importo eskojido invalid_csv_file: 'Dosya CSV no valida. Yerro: %{error}' over_rows_processing_limit: kontiene mas de %{count} filas too_large: Dosya es mas grande + failures: Yerros imported: Importado modes: merge: Une @@ -1671,6 +1686,9 @@ lad: month: "%b %Y" time: "%H:%M" with_time_zone: "%d de %b del %Y, %H:%M %Z" + translation: + errors: + too_many_requests: Ay demaziadas solisitudes de servisyo de traduksyon. two_factor_authentication: add: Adjusta disable: Inkapasita autentifikasyon en dos pasos @@ -1750,9 +1768,12 @@ lad: title: Bienvenido, %{name}! users: follow_limit_reached: No puedes segir a mas de %{limit} personas + go_to_sso_account_settings: Va a la konfigurasyon de kuento de tu prokurador de identita invalid_otp_token: Kodiche de dos pasos no valido + otp_lost_help_html: Si pedriste akseso a los dos, puedes kontaktarte kon %{email} signed_in_as: 'Konektado komo:' verification: + here_is_how: Ansina es komo verification: Verifikasyon verified_links: Tus atadijos verifikados webauthn_credentials: diff --git a/config/locales/simple_form.ie.yml b/config/locales/simple_form.ie.yml index bde52e2a783ea0..bd055b1c9eb24a 100644 --- a/config/locales/simple_form.ie.yml +++ b/config/locales/simple_form.ie.yml @@ -86,6 +86,7 @@ ie: ip_block: comment: Facultativ. Ne obliviar pro quo tu adjuntet ti-ci regul. expires_in: IP-adresses es un ressurse finit, quelcvez partit e transferet de manu a manu. Pro to, un índefinit bloccada de IP ne es recomandat. + ip: Intrar un adresse IPv4 o IPv6. Tu posse bloccar un tot intervalle de ili con li sintaxe CIDR. Atention a ne bloccar te self! severities: no_access: Bloccar accesse a omni ressurses sign_up_block: Nov registrationes ne va esser possibil @@ -93,6 +94,10 @@ ie: severity: Selecter quo va evenir con demandes ex ti-ci IP rule: text: Descrir un regul o postulation por usatores sur ti-ci servitor. Prova scrir un descrition curt e simplic + sessions: + otp: 'Intrar li 2-factor code generat del app sur tui portabile o usar un de tui codes de recuperation:' + settings: + show_application: Totvez, tu va sempre posser vider quel app ha publicat tui posta. user: role: Permissiones de usator decidet per su rol user_role: @@ -111,6 +116,7 @@ ie: name: Etiquette value: Contenete indexable: Includer public postas in resultates de sercha + unlocked: Automaticmen acceptar nov sequitores account_alias: acct: Usator-nómine del anteyan conto account_migration: @@ -158,6 +164,7 @@ ie: max_uses: Max grand númere de usas new_password: Nov passa-parol note: Biografie + otp_attempt: 2-factor code password: Passa-parol phrase: Clave-parol o frase setting_advanced_layout: Possibilisar web-interfacie avansat @@ -165,10 +172,12 @@ ie: setting_default_language: Lingue in quel postar setting_default_privacy: Privatie de postada setting_default_sensitive: Sempre marcar medie quam sensitiv + setting_display_media: Exposition de medie setting_display_media_default: Predefinitiones setting_display_media_hide_all: Celar omno setting_display_media_show_all: Monstrar omno setting_expand_spoilers: Sempre expander postas marcat con admonitiones de contenete + setting_hide_network: Celar tui grafica social setting_system_font_ui: Usar predefinit fonte de sistema setting_theme: Tema de situ setting_trends: Monstrar li hodial tendenties @@ -179,6 +188,7 @@ ie: title: Titul type: Specie de importation username: Nómine de usator + username_or_email: Usator-nómine o E-posta whole_word: Plen parol featured_tag: name: Hashtag @@ -193,11 +203,13 @@ ie: custom_css: Custom CSS profile_directory: Possibilisar profilarium registrations_mode: Qui posse registrar se + require_invite_text: Exiger un rason por adherer se show_domain_blocks: Vider bloccas de dominia show_domain_blocks_rationale: Monstrar pro quo cert dominias esset bloccat site_contact_email: Contact e-mail adresse site_contact_username: Usator-nómine de contact site_extended_description: Extendet descrition + site_short_description: Descrition del servitor site_title: Nómine de servitor theme: Predefenit tema trendable_by_default: Possibilisar tendenties sin priori inspection From da7290839aa140e5aa082dc1d57bfa59933178c3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 4 Jan 2024 10:24:43 +0100 Subject: [PATCH 19/23] Update dependency stylelint-config-standard-scss to v13 (#28589) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 24 ++++++++++++------------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/package.json b/package.json index 82cfd689a57ba0..a5b6a228ca415a 100644 --- a/package.json +++ b/package.json @@ -202,7 +202,7 @@ "prettier": "^3.0.0", "react-test-renderer": "^18.2.0", "stylelint": "^16.0.2", - "stylelint-config-standard-scss": "^12.0.0", + "stylelint-config-standard-scss": "^13.0.0", "typescript": "^5.0.4", "webpack-dev-server": "^3.11.3", "yargs": "^17.7.2" diff --git a/yarn.lock b/yarn.lock index 99c3eedb26b017..e1c8ab3fb88d16 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2433,7 +2433,7 @@ __metadata: stacktrace-js: "npm:^2.0.2" stringz: "npm:^2.1.0" stylelint: "npm:^16.0.2" - stylelint-config-standard-scss: "npm:^12.0.0" + stylelint-config-standard-scss: "npm:^13.0.0" substring-trie: "npm:^1.0.2" terser-webpack-plugin: "npm:^4.2.3" tesseract.js: "npm:^2.1.5" @@ -15644,30 +15644,30 @@ __metadata: languageName: node linkType: hard -"stylelint-config-standard-scss@npm:^12.0.0": - version: 12.0.0 - resolution: "stylelint-config-standard-scss@npm:12.0.0" +"stylelint-config-standard-scss@npm:^13.0.0": + version: 13.0.0 + resolution: "stylelint-config-standard-scss@npm:13.0.0" dependencies: stylelint-config-recommended-scss: "npm:^14.0.0" - stylelint-config-standard: "npm:^35.0.0" + stylelint-config-standard: "npm:^36.0.0" peerDependencies: postcss: ^8.3.3 - stylelint: ^16.0.2 + stylelint: ^16.1.0 peerDependenciesMeta: postcss: optional: true - checksum: 7f3ccfb4175f9c50b69d30ca35a97887008c5ba493dbe7d5bce0b57b1eafd21b268177b82404368e7780600077cba784f98e1046671724be3b29a00c6a7913a4 + checksum: 4abf317676184f4aaace6ce72b9fc9e2dffe051d43dd5637afc5803b062ea381e2807ae983c045dff22e96af58388a8b1fe9a8bdda9f97bc3660280cf24fb4d3 languageName: node linkType: hard -"stylelint-config-standard@npm:^35.0.0": - version: 35.0.0 - resolution: "stylelint-config-standard@npm:35.0.0" +"stylelint-config-standard@npm:^36.0.0": + version: 36.0.0 + resolution: "stylelint-config-standard@npm:36.0.0" dependencies: stylelint-config-recommended: "npm:^14.0.0" peerDependencies: - stylelint: ^16.0.0 - checksum: 791fbc26cc3029ce3c2423a643e903545b5e4cd605251b18f0ce790bac6fbaaf380469845c1ff45f4e320126af9f8a9dc1ca85d0df9274277ae60da91e81895b + stylelint: ^16.1.0 + checksum: 1fc9adddfc5cf0a1d7a443182a0731712a3950ace72a24081b4ede2b0bb6fc1eebd003c009f1d8d06c3a64ba9b31b0ed12512db2f91c8fa549238d8341580e4b languageName: node linkType: hard From 419c659bc445fa258550b7e1bf00251663ca6a21 Mon Sep 17 00:00:00 2001 From: Claire Date: Thu, 4 Jan 2024 15:14:46 +0100 Subject: [PATCH 20/23] Add fallback redirection when getting a webfinger query `WEB_DOMAIN@WEB_DOMAIN` (#28592) --- app/controllers/well_known/webfinger_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/well_known/webfinger_controller.rb b/app/controllers/well_known/webfinger_controller.rb index 364fbf8a18c47e..72f0ea890fc654 100644 --- a/app/controllers/well_known/webfinger_controller.rb +++ b/app/controllers/well_known/webfinger_controller.rb @@ -21,7 +21,7 @@ def set_account username = username_from_resource @account = begin - if username == Rails.configuration.x.local_domain + if username == Rails.configuration.x.local_domain || username == Rails.configuration.x.web_domain Account.representative else Account.find_local!(username) From d0fd14f851871659834ae600f043d81e352cdc1f Mon Sep 17 00:00:00 2001 From: Claire Date: Thu, 4 Jan 2024 15:17:38 +0100 Subject: [PATCH 21/23] Fix scrolling to detailed status not always working (#28577) --- .../mastodon/features/status/index.jsx | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/app/javascript/mastodon/features/status/index.jsx b/app/javascript/mastodon/features/status/index.jsx index 67a9697311ebbd..c581255c992f67 100644 --- a/app/javascript/mastodon/features/status/index.jsx +++ b/app/javascript/mastodon/features/status/index.jsx @@ -582,16 +582,20 @@ class Status extends ImmutablePureComponent { )); } - setRef = c => { + setContainerRef = c => { this.node = c; }; + setStatusRef = c => { + this.statusNode = c; + }; + _scrollStatusIntoView () { const { status, multiColumn } = this.props; if (status) { - window.requestAnimationFrame(() => { - this.node?.querySelector('.detailed-status__wrapper')?.scrollIntoView(true); + requestIdleCallback(() => { + this.statusNode?.scrollIntoView(true); // In the single-column interface, `scrollIntoView` will put the post behind the header, // so compensate for that. @@ -629,9 +633,8 @@ class Status extends ImmutablePureComponent { } // Scroll to focused post if it is loaded - const child = this.node?.querySelector('.detailed-status__wrapper'); - if (child) { - return [0, child.offsetTop]; + if (this.statusNode) { + return [0, this.statusNode.offsetTop]; } // Do not scroll otherwise, `componentDidUpdate` will take care of that @@ -692,11 +695,11 @@ class Status extends ImmutablePureComponent { /> -
+
{ancestors} -
+
Date: Thu, 4 Jan 2024 11:40:28 -0500 Subject: [PATCH 22/23] Solve remaining `db/*migrate*` cops (#28579) --- .rubocop_todo.yml | 4 - .../20170901141119_truncate_preview_cards.rb | 10 +-- ...024224956_migrate_account_conversations.rb | 2 +- ..._preserve_old_layout_for_existing_users.rb | 2 +- ...04024901_migrate_settings_to_user_roles.rb | 77 ++++++++++++------- 5 files changed, 54 insertions(+), 41 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index bc66bc4addafc7..d68832e85efef1 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -165,7 +165,6 @@ Rails/WhereExists: - 'app/validators/reaction_validator.rb' - 'app/validators/vote_validator.rb' - 'app/workers/move_worker.rb' - - 'db/migrate/20190529143559_preserve_old_layout_for_existing_users.rb' - 'lib/tasks/tests.rake' - 'spec/models/account_spec.rb' - 'spec/services/activitypub/process_collection_service_spec.rb' @@ -253,8 +252,6 @@ Style/GuardClause: - 'app/workers/redownload_media_worker.rb' - 'app/workers/remote_account_refresh_worker.rb' - 'config/initializers/devise.rb' - - 'db/migrate/20170901141119_truncate_preview_cards.rb' - - 'db/post_migrate/20220704024901_migrate_settings_to_user_roles.rb' - 'lib/devise/strategies/two_factor_ldap_authenticatable.rb' - 'lib/devise/strategies/two_factor_pam_authenticatable.rb' - 'lib/mastodon/cli/accounts.rb' @@ -275,7 +272,6 @@ Style/HashAsLastArrayItem: - 'app/models/status.rb' - 'app/services/batched_remove_status_service.rb' - 'app/services/notify_service.rb' - - 'db/migrate/20181024224956_migrate_account_conversations.rb' # This cop supports unsafe autocorrection (--autocorrect-all). Style/HashTransformValues: diff --git a/db/migrate/20170901141119_truncate_preview_cards.rb b/db/migrate/20170901141119_truncate_preview_cards.rb index 22a7731099435b..b4ba8c45ea633d 100644 --- a/db/migrate/20170901141119_truncate_preview_cards.rb +++ b/db/migrate/20170901141119_truncate_preview_cards.rb @@ -22,11 +22,9 @@ def up end def down - if ActiveRecord::Base.connection.table_exists? 'deprecated_preview_cards' - drop_table :preview_cards - rename_table :deprecated_preview_cards, :preview_cards - else - raise ActiveRecord::IrreversibleMigration, 'Previous preview cards table has already been removed' - end + raise ActiveRecord::IrreversibleMigration, 'Previous preview cards table has already been removed' unless ActiveRecord::Base.connection.table_exists? 'deprecated_preview_cards' + + drop_table :preview_cards + rename_table :deprecated_preview_cards, :preview_cards end end diff --git a/db/migrate/20181024224956_migrate_account_conversations.rb b/db/migrate/20181024224956_migrate_account_conversations.rb index 93ef5da6157f2d..d879fd88a24228 100644 --- a/db/migrate/20181024224956_migrate_account_conversations.rb +++ b/db/migrate/20181024224956_migrate_account_conversations.rb @@ -105,7 +105,7 @@ def up end end - notifications_about_direct_statuses.includes(:account, mention: { status: [:account, mentions: :account] }).find_each do |notification| + notifications_about_direct_statuses.includes(:account, mention: { status: [:account, { mentions: :account }] }).find_each do |notification| MigrationAccountConversation.add_status(notification.account, notification.target_status) migrated += 1 diff --git a/db/migrate/20190529143559_preserve_old_layout_for_existing_users.rb b/db/migrate/20190529143559_preserve_old_layout_for_existing_users.rb index 88dcea43600044..4597ec5ef4c08a 100644 --- a/db/migrate/20190529143559_preserve_old_layout_for_existing_users.rb +++ b/db/migrate/20190529143559_preserve_old_layout_for_existing_users.rb @@ -9,7 +9,7 @@ def up # on the to-be-changed default User.where(User.arel_table[:current_sign_in_at].gteq(1.month.ago)).find_each do |user| - next if Setting.unscoped.where(thing_type: 'User', thing_id: user.id, var: 'advanced_layout').exists? + next if Setting.unscoped.exists?(thing_type: 'User', thing_id: user.id, var: 'advanced_layout') user.settings.advanced_layout = true end diff --git a/db/post_migrate/20220704024901_migrate_settings_to_user_roles.rb b/db/post_migrate/20220704024901_migrate_settings_to_user_roles.rb index 254690cc3a4c34..00afee26d0c8d5 100644 --- a/db/post_migrate/20220704024901_migrate_settings_to_user_roles.rb +++ b/db/post_migrate/20220704024901_migrate_settings_to_user_roles.rb @@ -6,36 +6,55 @@ class MigrateSettingsToUserRoles < ActiveRecord::Migration[6.1] class UserRole < ApplicationRecord; end def up - owner_role = UserRole.find_by(name: 'Owner') - admin_role = UserRole.find_by(name: 'Admin') - moderator_role = UserRole.find_by(name: 'Moderator') - everyone_role = UserRole.find_by(id: -99) - - min_invite_role = Setting.min_invite_role - show_staff_badge = Setting.show_staff_badge - - if everyone_role - everyone_role.permissions &= ~::UserRole::FLAGS[:invite_users] unless min_invite_role == 'user' - everyone_role.save - end - - if owner_role - owner_role.highlighted = show_staff_badge - owner_role.save - end - - if admin_role - admin_role.permissions |= ::UserRole::FLAGS[:invite_users] if %w(admin moderator).include?(min_invite_role) - admin_role.highlighted = show_staff_badge - admin_role.save - end - - if moderator_role - moderator_role.permissions |= ::UserRole::FLAGS[:invite_users] if %w(moderator).include?(min_invite_role) - moderator_role.highlighted = show_staff_badge - moderator_role.save - end + process_role_everyone + process_role_owner + process_role_admin + process_role_moderator end def down; end + + private + + def process_role_everyone + everyone_role = UserRole.find_by(id: -99) + return unless everyone_role + + everyone_role.permissions &= ~::UserRole::FLAGS[:invite_users] unless min_invite_role == 'user' + everyone_role.save + end + + def process_role_owner + owner_role = UserRole.find_by(name: 'Owner') + return unless owner_role + + owner_role.highlighted = show_staff_badge + owner_role.save + end + + def process_role_admin + admin_role = UserRole.find_by(name: 'Admin') + return unless admin_role + + admin_role.permissions |= ::UserRole::FLAGS[:invite_users] if %w(admin moderator).include?(min_invite_role) + admin_role.highlighted = show_staff_badge + admin_role.save + end + + def process_role_moderator + moderator_role = UserRole.find_by(name: 'Moderator') + return unless moderator_role + + moderator_role.permissions |= ::UserRole::FLAGS[:invite_users] if %w(moderator).include?(min_invite_role) + moderator_role.highlighted = show_staff_badge + moderator_role.save + end + + def min_invite_role + Setting.min_invite_role + end + + def show_staff_badge + Setting.show_staff_badge + end end From 964a0ecf37c46bafba3e33aceacc9f80c78d9779 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 4 Jan 2024 11:55:00 -0500 Subject: [PATCH 23/23] Add sleep statement to nudge thread scheduler in request pool spec (#28596) --- spec/lib/request_pool_spec.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/spec/lib/request_pool_spec.rb b/spec/lib/request_pool_spec.rb index f179e6ca94a079..bdb0859d764a36 100644 --- a/spec/lib/request_pool_spec.rb +++ b/spec/lib/request_pool_spec.rb @@ -33,11 +33,13 @@ subject - threads = Array.new(20) do |_i| + threads = Array.new(3) do Thread.new do - 20.times do + 2.times do subject.with('http://example.com') do |http_client| http_client.get('/').flush + # Nudge scheduler to yield and exercise the full pool + sleep(0) end end end