Merge remote-tracking branch 'parent/main' into upstream-20230105
This commit is contained in:
commit
a0a3d1b101
65 changed files with 1008 additions and 453 deletions
|
@ -75,7 +75,6 @@ Metrics/AbcSize:
|
|||
Exclude:
|
||||
- 'app/serializers/initial_state_serializer.rb'
|
||||
- 'lib/mastodon/cli/*.rb'
|
||||
- db/*migrate/**/*
|
||||
|
||||
# Reason: Currently disabled in .rubocop_todo.yml
|
||||
# https://docs.rubocop.org/rubocop/cops_metrics.html#metricscyclomaticcomplexity
|
||||
|
@ -87,7 +86,6 @@ Metrics/CyclomaticComplexity:
|
|||
- 'app/services/delivery_antenna_service.rb'
|
||||
- 'app/services/post_status_service.rb'
|
||||
- lib/mastodon/cli/*.rb
|
||||
- db/*migrate/**/*
|
||||
|
||||
# Reason:
|
||||
# https://docs.rubocop.org/rubocop/cops_metrics.html#metricsparameterlists
|
||||
|
|
|
@ -167,7 +167,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'
|
||||
|
@ -255,8 +254,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'
|
||||
|
@ -277,7 +274,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:
|
||||
|
|
|
@ -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)
|
||||
|
@ -678,7 +678,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)
|
||||
|
|
|
@ -40,7 +40,7 @@ module Admin
|
|||
(@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 @@ module Admin
|
|||
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
|
||||
|
|
|
@ -68,7 +68,7 @@ module Admin
|
|||
|
||||
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
|
||||
|
|
|
@ -55,7 +55,7 @@ class Api::V1::Admin::EmailDomainBlocksController < Api::BaseController
|
|||
end
|
||||
|
||||
def resource_params
|
||||
params.permit(:domain)
|
||||
params.permit(:domain, :allow_with_approval)
|
||||
end
|
||||
|
||||
def insert_pagination_headers
|
||||
|
|
|
@ -91,14 +91,23 @@ module SignatureVerification
|
|||
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 @@ module SignatureVerification
|
|||
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?
|
||||
|
|
|
@ -21,7 +21,7 @@ module WellKnown
|
|||
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)
|
||||
|
|
|
@ -654,16 +654,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.
|
||||
|
@ -701,9 +705,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
|
||||
|
@ -768,12 +771,12 @@ class Status extends ImmutablePureComponent {
|
|||
/>
|
||||
|
||||
<ScrollContainer scrollKey='thread' shouldUpdateScroll={this.shouldUpdateScroll}>
|
||||
<div className={classNames('scrollable', { fullscreen })} ref={this.setRef}>
|
||||
<div className={classNames('scrollable', { fullscreen })} ref={this.setContainerRef}>
|
||||
{references}
|
||||
{ancestors}
|
||||
|
||||
<HotKeys handlers={handlers}>
|
||||
<div className={classNames('focusable', 'detailed-status__wrapper', `detailed-status__wrapper-${status.get('visibility')}`)} tabIndex={0} aria-label={textForScreenReader(intl, status, false)}>
|
||||
<div className={classNames('focusable', 'detailed-status__wrapper', `detailed-status__wrapper-${status.get('visibility')}`)} tabIndex={0} aria-label={textForScreenReader(intl, status, false)} ref={this.setStatusRef}>
|
||||
<DetailedStatus
|
||||
key={`details-${status.get('id')}`}
|
||||
status={status}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -77,6 +77,7 @@ class Request
|
|||
@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 @@ class Request
|
|||
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 @@ class Request
|
|||
@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))
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 @@ class EmailDomainBlock < ApplicationRecord
|
|||
@attempt_ip = attempt_ip
|
||||
end
|
||||
|
||||
def match?
|
||||
blocking? || invalid_uri?
|
||||
def match?(...)
|
||||
blocking?(...) || invalid_uri?
|
||||
end
|
||||
|
||||
private
|
||||
|
@ -52,8 +53,8 @@ class EmailDomainBlock < ApplicationRecord
|
|||
@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 @@ class EmailDomainBlock < ApplicationRecord
|
|||
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
|
||||
|
|
|
@ -420,7 +420,7 @@ class User < ApplicationRecord
|
|||
|
||||
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?
|
||||
|
@ -432,6 +432,12 @@ class User < ApplicationRecord
|
|||
!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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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')
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ Rails.application.configure do
|
|||
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
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -472,6 +472,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"
|
||||
|
|
|
@ -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: "<strong>Tu sirvidor de web es mal konfigurado. La privasita de tus utilizadores esta en riziko.</strong>"
|
||||
|
@ -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 <strong>%{domain}</strong>. 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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -22,11 +22,9 @@ class TruncatePreviewCards < ActiveRecord::Migration[5.1]
|
|||
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
|
||||
|
|
|
@ -105,7 +105,7 @@ class MigrateAccountConversations < ActiveRecord::Migration[5.2]
|
|||
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
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ class PreserveOldLayoutForExistingUsers < ActiveRecord::Migration[5.2]
|
|||
# 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
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -77,90 +77,135 @@ class BackfillAdminActionLogs < ActiveRecord::Migration[6.1]
|
|||
|
||||
def up
|
||||
safety_assured do
|
||||
AdminActionLog.includes(:account).where(target_type: 'Account', human_identifier: nil).find_each do |log|
|
||||
next if log.account.nil?
|
||||
|
||||
log.update_attribute('human_identifier', log.account.acct)
|
||||
end
|
||||
|
||||
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.user.account.acct)
|
||||
log.update_attribute('route_param', log.user.account_id)
|
||||
end
|
||||
|
||||
AdminActionLog.where(target_type: 'Report', human_identifier: nil).in_batches.update_all('human_identifier = target_id::text')
|
||||
|
||||
AdminActionLog.includes(:domain_block).where(target_type: 'DomainBlock').find_each do |log|
|
||||
next if log.domain_block.nil?
|
||||
|
||||
log.update_attribute('human_identifier', log.domain_block.domain)
|
||||
end
|
||||
|
||||
AdminActionLog.includes(:domain_allow).where(target_type: 'DomainAllow').find_each do |log|
|
||||
next if log.domain_allow.nil?
|
||||
|
||||
log.update_attribute('human_identifier', log.domain_allow.domain)
|
||||
end
|
||||
|
||||
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.email_domain_block.domain)
|
||||
end
|
||||
|
||||
AdminActionLog.includes(:unavailable_domain).where(target_type: 'UnavailableDomain').find_each do |log|
|
||||
next if log.unavailable_domain.nil?
|
||||
|
||||
log.update_attribute('human_identifier', log.unavailable_domain.domain)
|
||||
end
|
||||
|
||||
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.status.account.acct)
|
||||
log.update_attribute('permalink', log.status.uri)
|
||||
end
|
||||
|
||||
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.account_warning.account.acct)
|
||||
end
|
||||
|
||||
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.announcement.text)
|
||||
end
|
||||
|
||||
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.ip_block.ip}/#{log.ip_block.ip.prefix}")
|
||||
end
|
||||
|
||||
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.custom_emoji.shortcode)
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
def down; end
|
||||
|
||||
private
|
||||
|
||||
def process_logs_for_account
|
||||
AdminActionLog.includes(:account).where(target_type: 'Account', human_identifier: nil).find_each do |log|
|
||||
next if log.account.nil?
|
||||
|
||||
log.update_attribute('human_identifier', log.account.acct)
|
||||
end
|
||||
end
|
||||
|
||||
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.user.account.acct)
|
||||
log.update_attribute('route_param', log.user.account_id)
|
||||
end
|
||||
end
|
||||
|
||||
def process_logs_for_report
|
||||
AdminActionLog.where(target_type: 'Report', human_identifier: nil).in_batches.update_all('human_identifier = target_id::text')
|
||||
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?
|
||||
|
||||
log.update_attribute('human_identifier', log.domain_block.domain)
|
||||
end
|
||||
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?
|
||||
|
||||
log.update_attribute('human_identifier', log.domain_allow.domain)
|
||||
end
|
||||
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?
|
||||
|
||||
log.update_attribute('human_identifier', log.email_domain_block.domain)
|
||||
end
|
||||
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?
|
||||
|
||||
log.update_attribute('human_identifier', log.unavailable_domain.domain)
|
||||
end
|
||||
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?
|
||||
|
||||
log.update_attribute('human_identifier', log.status.account.acct)
|
||||
log.update_attribute('permalink', log.status.uri)
|
||||
end
|
||||
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?
|
||||
|
||||
log.update_attribute('human_identifier', log.account_warning.account.acct)
|
||||
end
|
||||
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?
|
||||
|
||||
log.update_attribute('human_identifier', log.announcement.text)
|
||||
end
|
||||
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?
|
||||
|
||||
log.update_attribute('human_identifier', "#{log.ip_block.ip}/#{log.ip_block.ip.prefix}")
|
||||
end
|
||||
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?
|
||||
|
||||
log.update_attribute('human_identifier', log.custom_emoji.shortcode)
|
||||
end
|
||||
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 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
|
||||
|
|
|
@ -77,90 +77,135 @@ class BackfillAdminActionLogsAgain < ActiveRecord::Migration[6.1]
|
|||
|
||||
def up
|
||||
safety_assured do
|
||||
AdminActionLog.includes(:account).where(target_type: 'Account', human_identifier: nil).find_each do |log|
|
||||
next if log.account.nil?
|
||||
|
||||
log.update_attribute('human_identifier', log.account.acct)
|
||||
end
|
||||
|
||||
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.user.account.acct)
|
||||
log.update_attribute('route_param', log.user.account_id)
|
||||
end
|
||||
|
||||
AdminActionLog.where(target_type: 'Report', human_identifier: nil).in_batches.update_all('human_identifier = target_id::text')
|
||||
|
||||
AdminActionLog.includes(:domain_block).where(target_type: 'DomainBlock').find_each do |log|
|
||||
next if log.domain_block.nil?
|
||||
|
||||
log.update_attribute('human_identifier', log.domain_block.domain)
|
||||
end
|
||||
|
||||
AdminActionLog.includes(:domain_allow).where(target_type: 'DomainAllow').find_each do |log|
|
||||
next if log.domain_allow.nil?
|
||||
|
||||
log.update_attribute('human_identifier', log.domain_allow.domain)
|
||||
end
|
||||
|
||||
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.email_domain_block.domain)
|
||||
end
|
||||
|
||||
AdminActionLog.includes(:unavailable_domain).where(target_type: 'UnavailableDomain').find_each do |log|
|
||||
next if log.unavailable_domain.nil?
|
||||
|
||||
log.update_attribute('human_identifier', log.unavailable_domain.domain)
|
||||
end
|
||||
|
||||
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.status.account.acct)
|
||||
log.update_attribute('permalink', log.status.uri)
|
||||
end
|
||||
|
||||
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.account_warning.account.acct)
|
||||
end
|
||||
|
||||
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.announcement.text)
|
||||
end
|
||||
|
||||
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.ip_block.ip}/#{log.ip_block.ip.prefix}")
|
||||
end
|
||||
|
||||
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.custom_emoji.shortcode)
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
def down; end
|
||||
|
||||
private
|
||||
|
||||
def process_logs_for_account
|
||||
AdminActionLog.includes(:account).where(target_type: 'Account', human_identifier: nil).find_each do |log|
|
||||
next if log.account.nil?
|
||||
|
||||
log.update_attribute('human_identifier', log.account.acct)
|
||||
end
|
||||
end
|
||||
|
||||
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.user.account.acct)
|
||||
log.update_attribute('route_param', log.user.account_id)
|
||||
end
|
||||
end
|
||||
|
||||
def process_logs_for_report
|
||||
AdminActionLog.where(target_type: 'Report', human_identifier: nil).in_batches.update_all('human_identifier = target_id::text')
|
||||
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?
|
||||
|
||||
log.update_attribute('human_identifier', log.domain_block.domain)
|
||||
end
|
||||
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?
|
||||
|
||||
log.update_attribute('human_identifier', log.domain_allow.domain)
|
||||
end
|
||||
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?
|
||||
|
||||
log.update_attribute('human_identifier', log.email_domain_block.domain)
|
||||
end
|
||||
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?
|
||||
|
||||
log.update_attribute('human_identifier', log.unavailable_domain.domain)
|
||||
end
|
||||
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?
|
||||
|
||||
log.update_attribute('human_identifier', log.status.account.acct)
|
||||
log.update_attribute('permalink', log.status.uri)
|
||||
end
|
||||
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?
|
||||
|
||||
log.update_attribute('human_identifier', log.account_warning.account.acct)
|
||||
end
|
||||
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?
|
||||
|
||||
log.update_attribute('human_identifier', log.announcement.text)
|
||||
end
|
||||
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?
|
||||
|
||||
log.update_attribute('human_identifier', "#{log.ip_block.ip}/#{log.ip_block.ip.prefix}")
|
||||
end
|
||||
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?
|
||||
|
||||
log.update_attribute('human_identifier', log.custom_emoji.shortcode)
|
||||
end
|
||||
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 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
|
||||
|
|
|
@ -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_14_225249) 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"
|
||||
|
||||
|
@ -596,6 +596,7 @@ ActiveRecord::Schema[7.1].define(version: 2023_12_14_225249) do
|
|||
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
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ require_relative '../../../config/boot'
|
|||
require_relative '../../../config/environment'
|
||||
|
||||
require 'thor'
|
||||
require 'pastel'
|
||||
require_relative 'progress_helper'
|
||||
|
||||
module Mastodon
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'tty-prompt'
|
||||
|
||||
module Mastodon::CLI
|
||||
module Federation
|
||||
extend ActiveSupport::Concern
|
||||
|
@ -30,44 +28,50 @@ module Mastodon::CLI
|
|||
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(<<~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 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(<<~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 prompt
|
||||
@prompt ||= TTY::Prompt.new
|
||||
def self_destruct_value
|
||||
Rails
|
||||
.application
|
||||
.message_verifier('self-destruct')
|
||||
.generate(Rails.configuration.x.local_domain)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'tty-prompt'
|
||||
require_relative 'base'
|
||||
|
||||
module Mastodon::CLI
|
||||
|
|
|
@ -207,7 +207,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"
|
||||
|
|
|
@ -12,13 +12,14 @@ RSpec.describe Admin::EmailDomainBlocksController do
|
|||
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
|
||||
|
|
|
@ -135,6 +135,25 @@ RSpec.describe Auth::RegistrationsController do
|
|||
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'
|
||||
|
|
|
@ -22,7 +22,7 @@ describe 'Admin::Accounts' do
|
|||
|
||||
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 @@ describe 'Admin::Accounts' do
|
|||
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 @@ describe 'Admin::Accounts' do
|
|||
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 @@ describe 'Admin::Accounts' do
|
|||
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
|
||||
|
|
|
@ -16,7 +16,7 @@ describe 'Admin::CustomEmojis' do
|
|||
|
||||
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
|
||||
|
|
|
@ -14,7 +14,7 @@ describe 'blocking domains through the moderation interface' do
|
|||
|
||||
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 @@ describe 'blocking domains through the moderation interface' do
|
|||
|
||||
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 @@ describe 'blocking domains through the moderation interface' do
|
|||
|
||||
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 @@ describe 'blocking domains through the moderation interface' do
|
|||
|
||||
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 @@ describe 'blocking domains through the moderation interface' do
|
|||
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'
|
||||
|
|
|
@ -16,7 +16,7 @@ describe 'Admin::EmailDomainBlocks' do
|
|||
|
||||
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
|
||||
|
|
|
@ -16,7 +16,7 @@ describe 'Admin::IpBlocks' do
|
|||
|
||||
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
|
||||
|
|
|
@ -11,13 +11,13 @@ describe 'finding software updates through the admin interface' do
|
|||
|
||||
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
|
||||
|
|
|
@ -17,7 +17,7 @@ describe 'Admin::Statuses' do
|
|||
|
||||
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
|
||||
|
|
|
@ -16,7 +16,7 @@ describe 'Admin::Trends::Links::PreviewCardProviders' do
|
|||
|
||||
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
|
||||
|
|
|
@ -16,7 +16,7 @@ describe 'Admin::Trends::Links' do
|
|||
|
||||
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
|
||||
|
|
|
@ -16,7 +16,7 @@ describe 'Admin::Trends::Statuses' do
|
|||
|
||||
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
|
||||
|
|
|
@ -16,7 +16,7 @@ describe 'Admin::Trends::Tags' do
|
|||
|
||||
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
|
||||
|
|
|
@ -23,7 +23,7 @@ describe 'email confirmation flow when captcha is enabled' do
|
|||
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)
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ describe 'Log in' do
|
|||
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 @@ describe 'Log in' do
|
|||
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 @@ describe 'Log in' do
|
|||
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
|
||||
|
|
|
@ -20,7 +20,7 @@ describe 'Using OAuth from an external app' do
|
|||
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 @@ describe 'Using OAuth from an external app' do
|
|||
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 @@ describe 'Using OAuth from an external app' do
|
|||
# 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 @@ describe 'Using OAuth from an external app' do
|
|||
# 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 @@ describe 'Using OAuth from an external app' do
|
|||
# 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 @@ describe 'Using OAuth from an external app' do
|
|||
# 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
|
||||
|
|
|
@ -20,4 +20,157 @@ describe Mastodon::CLI::Main do
|
|||
.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
|
||||
before do
|
||||
answer_hostname_incorrectly
|
||||
end
|
||||
|
||||
it 'exits silently' do
|
||||
expect { subject }
|
||||
.to raise_error(SystemExit)
|
||||
end
|
||||
end
|
||||
|
||||
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
|
||||
answer_hostname_correctly
|
||||
accept_proceed
|
||||
end
|
||||
|
||||
it 'instructs to set the appropriate environment variable' do
|
||||
expect { subject }
|
||||
.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
|
||||
|
|
|
@ -184,4 +184,58 @@ describe Mastodon::CLI::Media do
|
|||
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
|
||||
|
|
|
@ -33,11 +33,13 @@ describe RequestPool do
|
|||
|
||||
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
|
||||
|
|
|
@ -20,7 +20,7 @@ describe 'Content-Security-Policy' do
|
|||
"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
|
||||
|
|
|
@ -94,6 +94,72 @@ describe 'signature verification concern' do
|
|||
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: {
|
||||
|
|
|
@ -27,6 +27,27 @@ RSpec.describe AppSignUpService, type: :service do
|
|||
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'
|
||||
|
|
|
@ -18,7 +18,7 @@ module ProfileStories
|
|||
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
|
||||
|
|
|
@ -24,7 +24,7 @@ describe 'NewStatuses' do
|
|||
|
||||
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 @@ describe 'NewStatuses' do
|
|||
|
||||
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)
|
||||
|
|
|
@ -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.<string, Array.<function(Object<string, any>): 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
|
||||
|
@ -1042,7 +1031,6 @@ const startServer = async () => {
|
|||
|
||||
api.use(setRequestId);
|
||||
api.use(setRemoteAddress);
|
||||
api.use(allowCrossDomain);
|
||||
|
||||
api.use(authenticationMiddleware);
|
||||
api.use(errorMiddleware);
|
||||
|
|
|
@ -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",
|
||||
|
|
267
yarn.lock
267
yarn.lock
|
@ -2452,7 +2452,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"
|
||||
|
@ -2487,12 +2487,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"
|
||||
|
@ -3046,6 +3048,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"
|
||||
|
@ -4697,13 +4708,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
|
||||
|
||||
|
@ -5216,7 +5227,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:
|
||||
|
@ -5992,6 +6003,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"
|
||||
|
@ -6147,7 +6168,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:
|
||||
|
@ -6235,7 +6256,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:
|
||||
|
@ -6285,42 +6306,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
|
||||
|
||||
|
@ -6334,23 +6355,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
|
||||
|
||||
|
@ -6363,6 +6375,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"
|
||||
|
@ -8191,13 +8212,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
|
||||
|
||||
|
@ -11981,7 +12002,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
|
||||
|
@ -12750,29 +12771,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
|
||||
|
||||
|
@ -12835,29 +12856,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
|
||||
|
||||
|
@ -12885,27 +12906,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
|
||||
|
||||
|
@ -13017,15 +13038,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
|
||||
|
||||
|
@ -13063,15 +13084,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
|
||||
|
||||
|
@ -13111,36 +13132,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
|
||||
|
||||
|
@ -13708,8 +13729,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"
|
||||
|
@ -13718,7 +13739,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
|
||||
|
||||
|
@ -15620,15 +15641,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
|
||||
|
||||
|
@ -15658,30 +15679,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
|
||||
|
||||
|
@ -15852,20 +15873,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
|
||||
|
||||
|
@ -16772,7 +16793,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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue