Skip to content

Commit

Permalink
Merge pull request #427 from kmycode/upstream-20230105
Browse files Browse the repository at this point in the history
Upstream 20230105
  • Loading branch information
kmycode authored Jan 5, 2024
2 parents 9ff2306 + a0a3d1b commit 5f144c0
Show file tree
Hide file tree
Showing 65 changed files with 958 additions and 403 deletions.
2 changes: 0 additions & 2 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
4 changes: 0 additions & 4 deletions .rubocop_todo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -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'
Expand All @@ -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:
Expand Down
4 changes: 2 additions & 2 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions app/controllers/admin/email_domain_blocks_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def create
(@email_domain_block.other_domains || []).uniq.each do |domain|
next if EmailDomainBlock.where(domain: domain).exists?

other_email_domain_block = EmailDomainBlock.create!(domain: domain, parent: @email_domain_block)
other_email_domain_block = EmailDomainBlock.create!(domain: domain, allow_with_approval: @email_domain_block.allow_with_approval, parent: @email_domain_block)
log_action :create, other_email_domain_block
end
end
Expand All @@ -65,7 +65,7 @@ def set_resolved_records
end

def resource_params
params.require(:email_domain_block).permit(:domain, other_domains: [])
params.require(:email_domain_block).permit(:domain, :allow_with_approval, other_domains: [])
end

def form_email_domain_block_batch_params
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/admin/export_domain_blocks_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ def export_headers

def export_data
CSV.generate(headers: export_headers, write_headers: true) do |content|
DomainBlock.with_limitations.each do |instance|
DomainBlock.with_limitations.order(id: :asc).each do |instance|
content << [instance.domain, instance.severity, instance.reject_media, instance.reject_reports, instance.public_comment, instance.obfuscate]
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def set_email_domain_block
end

def resource_params
params.permit(:domain)
params.permit(:domain, :allow_with_approval)
end

def insert_pagination_headers
Expand Down
22 changes: 19 additions & 3 deletions app/controllers/concerns/signature_verification.rb
Original file line number Diff line number Diff line change
Expand Up @@ -91,14 +91,23 @@ def signed_request_actor
raise SignatureVerificationError, "Public key not found for key #{signature_params['keyId']}" if actor.nil?

signature = Base64.decode64(signature_params['signature'])
compare_signed_string = build_signed_string
compare_signed_string = build_signed_string(include_query_string: true)

return actor unless verify_signature(actor, signature, compare_signed_string).nil?

# Compatibility quirk with older Mastodon versions
compare_signed_string = build_signed_string(include_query_string: false)
return actor unless verify_signature(actor, signature, compare_signed_string).nil?

actor = stoplight_wrap_request { actor_refresh_key!(actor) }

raise SignatureVerificationError, "Could not refresh public key #{signature_params['keyId']}" if actor.nil?

compare_signed_string = build_signed_string(include_query_string: true)
return actor unless verify_signature(actor, signature, compare_signed_string).nil?

# Compatibility quirk with older Mastodon versions
compare_signed_string = build_signed_string(include_query_string: false)
return actor unless verify_signature(actor, signature, compare_signed_string).nil?

fail_with! "Verification failed for #{actor.to_log_human_identifier} #{actor.uri} using rsa-sha256 (RSASSA-PKCS1-v1_5 with SHA-256)", signed_string: compare_signed_string, signature: signature_params['signature']
Expand Down Expand Up @@ -180,11 +189,18 @@ def verify_signature(actor, signature, compare_signed_string)
nil
end

def build_signed_string
def build_signed_string(include_query_string: true)
signed_headers.map do |signed_header|
case signed_header
when Request::REQUEST_TARGET
"#{Request::REQUEST_TARGET}: #{request.method.downcase} #{request.path}"
if include_query_string
"#{Request::REQUEST_TARGET}: #{request.method.downcase} #{request.original_fullpath}"
else
# Current versions of Mastodon incorrectly omit the query string from the (request-target) pseudo-header.
# Therefore, temporarily support such incorrect signatures for compatibility.
# TODO: remove eventually some time after release of the fixed version
"#{Request::REQUEST_TARGET}: #{request.method.downcase} #{request.path}"
end
when '(created)'
raise SignatureVerificationError, 'Invalid pseudo-header (created) for rsa-sha256' unless signature_algorithm == 'hs2019'
raise SignatureVerificationError, 'Pseudo-header (created) used but corresponding argument missing' if signature_params['created'].blank?
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/well_known/webfinger_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def set_account
username = username_from_resource

@account = begin
if username == Rails.configuration.x.local_domain
if username == Rails.configuration.x.local_domain || username == Rails.configuration.x.web_domain
Account.representative
else
Account.find_local!(username)
Expand Down
19 changes: 11 additions & 8 deletions app/javascript/mastodon/features/status/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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}
Expand Down
25 changes: 24 additions & 1 deletion app/javascript/mastodon/locales/ia.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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"
}
1 change: 1 addition & 0 deletions app/javascript/mastodon/locales/lad.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
2 changes: 1 addition & 1 deletion app/javascript/mastodon/locales/nn.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
2 changes: 1 addition & 1 deletion app/javascript/mastodon/locales/no.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
11 changes: 10 additions & 1 deletion app/lib/request.rb
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ def initialize(verb, url, **options)
@url = Addressable::URI.parse(url).normalize
@http_client = options.delete(:http_client)
@allow_local = options.delete(:allow_local)
@full_path = options.delete(:with_query_string)
@options = options.merge(socket_class: use_proxy? || @allow_local ? ProxySocket : Socket)
@options = @options.merge(timeout_class: PerOperationWithDeadline, timeout_options: TIMEOUT)
@options = @options.merge(proxy_url) if use_proxy?
Expand Down Expand Up @@ -146,7 +147,7 @@ def http_client
private

def set_common_headers!
@headers[REQUEST_TARGET] = "#{@verb} #{@url.path}"
@headers[REQUEST_TARGET] = request_target
@headers['User-Agent'] = Mastodon::Version.user_agent
@headers['Host'] = @url.host
@headers['Date'] = Time.now.utc.httpdate
Expand All @@ -157,6 +158,14 @@ def set_digest!
@headers['Digest'] = "SHA-256=#{Digest::SHA256.base64digest(@options[:body])}"
end

def request_target
if @url.query.nil? || !@full_path
"#{@verb} #{@url.path}"
else
"#{@verb} #{@url.path}?#{@url.query}"
end
end

def signature
algorithm = 'rsa-sha256'
signature = Base64.strict_encode64(@keypair.sign(OpenSSL::Digest.new('SHA256'), signed_string))
Expand Down
3 changes: 2 additions & 1 deletion app/models/concerns/attachmentable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
23 changes: 14 additions & 9 deletions app/models/email_domain_block.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -42,8 +43,8 @@ def initialize(domain_or_domains, attempt_ip: nil)
@attempt_ip = attempt_ip
end

def match?
blocking? || invalid_uri?
def match?(...)
blocking?(...) || invalid_uri?
end

private
Expand All @@ -52,8 +53,8 @@ def invalid_uri?
@uris.any?(&:nil?)
end

def blocking?
blocks = EmailDomainBlock.where(domain: domains_with_variants).order(Arel.sql('char_length(domain) desc'))
def blocking?(allow_with_approval: false)
blocks = EmailDomainBlock.where(domain: domains_with_variants, allow_with_approval: allow_with_approval).order(Arel.sql('char_length(domain) desc'))
blocks.each { |block| block.history.add(@attempt_ip) } if @attempt_ip.present?
blocks.any?
end
Expand Down Expand Up @@ -86,4 +87,8 @@ def extract_uris(domain_or_domains)
def self.block?(domain_or_domains, attempt_ip: nil)
Matcher.new(domain_or_domains, attempt_ip: attempt_ip).match?
end

def self.requires_approval?(domain_or_domains, attempt_ip: nil)
Matcher.new(domain_or_domains, attempt_ip: attempt_ip).match?(allow_with_approval: true)
end
end
8 changes: 7 additions & 1 deletion app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,7 @@ def render_and_send_devise_message(notification, *args, **kwargs)

def set_approved
self.approved = begin
if sign_up_from_ip_requires_approval?
if sign_up_from_ip_requires_approval? || sign_up_email_requires_approval?
false
else
open_registrations? || valid_invitation? || external?
Expand All @@ -432,6 +432,12 @@ def sign_up_from_ip_requires_approval?
!sign_up_ip.nil? && IpBlock.where(severity: :sign_up_requires_approval).where('ip >>= ?', sign_up_ip.to_s).exists?
end

def sign_up_email_requires_approval?
return false unless email.present? || unconfirmed_email.present?

EmailDomainBlock.requires_approval?(email.presence || unconfirmed_email, attempt_ip: sign_up_ip)
end

def open_registrations?
Setting.registrations_mode == 'open'
end
Expand Down
Loading

0 comments on commit 5f144c0

Please sign in to comment.