diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index fb8130f51b..0372ee4442 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,6 +1,6 @@ # This configuration was generated by # `rubocop --auto-gen-config --auto-gen-only-exclude --no-offense-counts --no-auto-gen-timestamp` -# using RuboCop version 1.76.1. +# using RuboCop version 1.76.2. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new diff --git a/Gemfile b/Gemfile index db2b82955b..ffd5371b06 100644 --- a/Gemfile +++ b/Gemfile @@ -111,7 +111,7 @@ group :opentelemetry do gem 'opentelemetry-instrumentation-concurrent_ruby', '~> 0.22.0', require: false gem 'opentelemetry-instrumentation-excon', '~> 0.23.0', require: false gem 'opentelemetry-instrumentation-faraday', '~> 0.27.0', require: false - gem 'opentelemetry-instrumentation-http', '~> 0.24.0', require: false + gem 'opentelemetry-instrumentation-http', '~> 0.25.0', require: false gem 'opentelemetry-instrumentation-http_client', '~> 0.23.0', require: false gem 'opentelemetry-instrumentation-net_http', '~> 0.23.0', require: false gem 'opentelemetry-instrumentation-pg', '~> 0.30.0', require: false diff --git a/Gemfile.lock b/Gemfile.lock index c2d89e3c4f..5f8c685a89 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -90,7 +90,9 @@ GEM public_suffix (>= 2.0.2, < 7.0) aes_key_wrap (1.1.0) android_key_attestation (0.3.0) - annotaterb (4.15.0) + annotaterb (4.16.0) + activerecord (>= 6.0.0) + activesupport (>= 6.0.0) ast (2.4.3) attr_required (1.0.2) aws-eventstream (1.3.2) @@ -178,7 +180,7 @@ GEM database_cleaner-core (~> 2.0.0) database_cleaner-core (2.0.1) date (3.4.1) - debug (1.10.0) + debug (1.11.0) irb (~> 1.10) reline (>= 0.3.8) debug_inspector (1.2.0) @@ -222,6 +224,7 @@ GEM mail (~> 2.7) email_validator (2.2.4) activemodel + erb (5.0.1) erubi (1.13.1) et-orbi (1.2.11) tzinfo @@ -236,7 +239,7 @@ GEM logger faraday-follow_redirects (0.3.0) faraday (>= 1, < 3) - faraday-httpclient (2.0.1) + faraday-httpclient (2.0.2) httpclient (>= 2.2) faraday-net_http (3.4.0) net-http (>= 0.5.0) @@ -550,7 +553,7 @@ GEM opentelemetry-instrumentation-faraday (0.27.0) opentelemetry-api (~> 1.0) opentelemetry-instrumentation-base (~> 0.23.0) - opentelemetry-instrumentation-http (0.24.0) + opentelemetry-instrumentation-http (0.25.0) opentelemetry-api (~> 1.0) opentelemetry-instrumentation-base (~> 0.23.0) opentelemetry-instrumentation-http_client (0.23.0) @@ -705,7 +708,8 @@ GEM link_header (~> 0.0, >= 0.0.8) rdf-normalize (0.7.0) rdf (~> 3.3) - rdoc (6.13.1) + rdoc (6.14.0) + erb psych (>= 4.0.0) redcarpet (3.6.1) redis (4.8.1) @@ -757,7 +761,7 @@ GEM rspec-mocks (~> 3.0) sidekiq (>= 5, < 9) rspec-support (3.13.3) - rubocop (1.76.1) + rubocop (1.76.2) json (~> 2.3) language_server-protocol (~> 3.17.0.2) lint_roller (~> 1.1.0) @@ -765,7 +769,7 @@ GEM parser (>= 3.3.0.2) rainbow (>= 2.2.2, < 4.0) regexp_parser (>= 2.9.3, < 3.0) - rubocop-ast (>= 1.45.0, < 2.0) + rubocop-ast (>= 1.45.1, < 2.0) ruby-progressbar (~> 1.7) unicode-display_width (>= 2.4.0, < 4.0) rubocop-ast (1.45.1) @@ -1027,7 +1031,7 @@ DEPENDENCIES opentelemetry-instrumentation-concurrent_ruby (~> 0.22.0) opentelemetry-instrumentation-excon (~> 0.23.0) opentelemetry-instrumentation-faraday (~> 0.27.0) - opentelemetry-instrumentation-http (~> 0.24.0) + opentelemetry-instrumentation-http (~> 0.25.0) opentelemetry-instrumentation-http_client (~> 0.23.0) opentelemetry-instrumentation-net_http (~> 0.23.0) opentelemetry-instrumentation-pg (~> 0.30.0) diff --git a/app/controllers/concerns/signature_verification.rb b/app/controllers/concerns/signature_verification.rb index 669169e017..902feef683 100644 --- a/app/controllers/concerns/signature_verification.rb +++ b/app/controllers/concerns/signature_verification.rb @@ -82,7 +82,7 @@ module SignatureVerification end def actor_from_key_id - key_id = signature_key_id + key_id = signed_request.key_id domain = key_id.start_with?('acct:') ? key_id.split('@').last : key_id if domain_not_allowed?(domain) diff --git a/app/javascript/mastodon/components/status_banner.tsx b/app/javascript/mastodon/components/status_banner.tsx index 34af209198..e11b2c9279 100644 --- a/app/javascript/mastodon/components/status_banner.tsx +++ b/app/javascript/mastodon/components/status_banner.tsx @@ -8,6 +8,10 @@ export enum BannerVariant { Filter = 'filter', } +const stopPropagation: MouseEventHandler = (e) => { + e.stopPropagation(); +}; + export const StatusBanner: React.FC<{ children: React.ReactNode; variant: BannerVariant; @@ -38,6 +42,7 @@ export const StatusBanner: React.FC<{ : 'content-warning content-warning--filter' } onClick={forwardClick} + onMouseUp={stopPropagation} >
{children}
diff --git a/app/javascript/styles/mastodon/_variables.scss b/app/javascript/styles/mastodon/_variables.scss index d528cba6c4..e2a5afbe01 100644 --- a/app/javascript/styles/mastodon/_variables.scss +++ b/app/javascript/styles/mastodon/_variables.scss @@ -96,6 +96,7 @@ $media-modal-media-max-width: 100%; $media-modal-media-max-height: 80%; $no-gap-breakpoint: 1175px; +$mobile-menu-breakpoint: 760px; $mobile-breakpoint: 630px; $no-columns-breakpoint: 600px; diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index a49a73d0c4..506e2f0264 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -294,7 +294,7 @@ &:hover, &:active, - &:focus { + &:focus-visible { color: lighten($action-button-color, 7%); background-color: rgba($action-button-color, 0.15); } @@ -314,7 +314,7 @@ &:hover, &:active, - &:focus { + &:focus-visible { color: darken($lighter-text-color, 7%); background-color: rgba($lighter-text-color, 0.15); } @@ -334,7 +334,7 @@ &:hover, &:active, - &:focus { + &:focus-visible { color: $highlight-text-color; background-color: transparent; } @@ -2863,17 +2863,18 @@ a.account__display-name { } .ui__navigation-bar { - position: sticky; + position: fixed; bottom: 0; - background: var(--background-color); - backdrop-filter: var(--background-filter); - border-top: 1px solid var(--background-border-color); z-index: 3; display: flex; align-items: center; justify-content: space-between; + width: 100%; gap: 8px; padding-bottom: env(safe-area-inset-bottom); + background: var(--background-color); + backdrop-filter: var(--background-filter); + border-top: 1px solid var(--background-border-color); .layout-multiple-columns & { display: none; @@ -2984,11 +2985,20 @@ a.account__display-name { } .ui { + --mobile-bottom-nav-height: 55px; + --last-content-item-border-width: 2px; + flex: 0 0 auto; display: flex; flex-direction: column; width: 100%; height: 100%; + + @media (max-width: #{$mobile-menu-breakpoint - 1}) { + padding-bottom: calc( + var(--mobile-bottom-nav-height) - var(--last-content-item-border-width) + ); + } } .drawer { @@ -3475,6 +3485,7 @@ a.account__display-name { &__header { display: flex; align-items: center; + padding-inline-end: 4px; &__sep { width: 0; diff --git a/app/lib/emoji_formatter.rb b/app/lib/emoji_formatter.rb index a31353616d..c193df9bb6 100644 --- a/app/lib/emoji_formatter.rb +++ b/app/lib/emoji_formatter.rb @@ -46,12 +46,12 @@ class EmojiFormatter if inside_shortname && text[i] == ':' inside_shortname = false - shortcode = text[shortname_start_index + 1..i - 1] + shortcode = text[(shortname_start_index + 1)..(i - 1)] char_after = text[i + 1] next unless (char_after.nil? || !DISALLOWED_BOUNDING_REGEX.match?(char_after)) && (emoji = emoji_map[shortcode]) - result << tree.document.create_text_node(text[last_index..shortname_start_index - 1]) if shortname_start_index.positive? + result << tree.document.create_text_node(text[last_index..(shortname_start_index - 1)]) if shortname_start_index.positive? result << tree.document.fragment(tag_for_emoji(shortcode, emoji)) last_index = i + 1 diff --git a/app/lib/text_formatter.rb b/app/lib/text_formatter.rb index a7620fb74d..45fb06e705 100644 --- a/app/lib/text_formatter.rb +++ b/app/lib/text_formatter.rb @@ -58,7 +58,7 @@ class TextFormatter prefix = url.match(URL_PREFIX_REGEX).to_s display_url = url[prefix.length, 30] - suffix = url[prefix.length + 30..] + suffix = url[(prefix.length + 30)..] cutoff = url[prefix.length..].length > 30 if suffix && suffix.length == 1 # revert truncation to account for ellipsis diff --git a/config/initializers/ffmpeg.rb b/config/initializers/ffmpeg.rb index 87f85eeec7..ea7f3f08cb 100644 --- a/config/initializers/ffmpeg.rb +++ b/config/initializers/ffmpeg.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true Rails.application.configure do - config.x.ffmpeg_binary = ENV['FFMPEG_BINARY'] || 'ffmpeg' - config.x.ffprobe_binary = ENV['FFPROBE_BINARY'] || 'ffprobe' + config.x.ffmpeg_binary = ENV.fetch('FFMPEG_BINARY', 'ffmpeg') + config.x.ffprobe_binary = ENV.fetch('FFPROBE_BINARY', 'ffprobe') end diff --git a/spec/requests/signature_verification_spec.rb b/spec/requests/signature_verification_spec.rb index 9f516d154d..edcc2b673d 100644 --- a/spec/requests/signature_verification_spec.rb +++ b/spec/requests/signature_verification_spec.rb @@ -352,6 +352,33 @@ RSpec.describe 'signature verification concern' do end end + # TODO: Remove when feature is enabled + context 'with an HTTP Message Signature (final RFC version) when support is disabled' do + before { Fabricate(:account, domain: 'remote.domain', uri: 'https://remote.domain/users/bob', private_key: nil, public_key: actor_keypair.public_key.to_pem) } + + context 'with a valid signature on a GET request' do + let(:signature_input) do + 'sig1=("@method" "@target-uri");created=1703066400;keyid="https://remote.domain/users/bob#main-key"' + end + let(:signature_header) do + 'sig1=:WfM6q/qBqhUyqPUDt9metjadJGtLLpmMTBzk/t+R3byKe4/TGAXC6vBB/M6NsD5qv8GCmQGtisCMQxJQO0IGODGzi+Jv+eqDJ50agMVXNV6nUOzY44c4/XTPoI98qyx1oEMa4Hefy3vSYKq96iDVAc+RDLCMTeGP3wn9wizjD1SNmU0RZI1bTB+eCkywMP9mM5zXzUOYF+Qkuf+WdEpPR1XUGPlnqfdvPalcKVfaI/VThBjI91D/lmUGoa69x4EBEHM+aJmW6086e7/dVh+FndKkdGfXslZXFZKi2flTGQZgEWLn948SqAaJQROkJg8B14Sb1NONS1qZBhK3Mum8Pg==:' # rubocop:disable Layout/LineLength + end + + it 'cannot verify signature', :aggregate_failures do + get '/activitypub/signature_required', headers: { + 'Host' => 'www.example.com', + 'Signature-Input' => signature_input, + 'Signature' => signature_header, + } + + expect(response).to have_http_status(401) + expect(response.parsed_body).to match( + error: 'Error parsing signature parameters' + ) + end + end + end + context 'with an HTTP Message Signature (final RFC version)', feature: :http_message_signatures do context 'with a known account' do let!(:actor) { Fabricate(:account, domain: 'remote.domain', uri: 'https://remote.domain/users/bob', private_key: nil, public_key: actor_keypair.public_key.to_pem) }