From c2b4588f1cd65f2b36fc45f998681492ef2f0f79 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 3 Jan 2024 10:04:59 +0100 Subject: [PATCH 1/6] Update dependency sass to v1.69.7 (#28570) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 571e29e7d3..2bab9a2d0d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -14554,15 +14554,15 @@ __metadata: linkType: hard "sass@npm:^1.62.1": - version: 1.69.6 - resolution: "sass@npm:1.69.6" + version: 1.69.7 + resolution: "sass@npm:1.69.7" dependencies: chokidar: "npm:>=3.0.0 <4.0.0" immutable: "npm:^4.0.0" source-map-js: "npm:>=0.6.2 <2.0.0" bin: sass: sass.js - checksum: 8153db8e51e74a9007bb54332e14d122c34288c7d21a5f2eaefef753a1b7bb13f35e042dc6247253dab5b1550b05cea27970371e7548286b4f50f23dd1147d89 + checksum: 773d0938e7d4ff3972d3fda3132f34fe98a2f712e028a58e28fecd615434795eff3266eddc38d5e13f03b90c0d6360d0e737b30bff2949a47280c64a18e0fb18 languageName: node linkType: hard From 8c5d3e527892dee08f5f6ae7517f9af8f3b4963e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 3 Jan 2024 09:05:52 +0000 Subject: [PATCH 2/6] Update dependency puma to v6.4.1 (#28569) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 08b9fc0de4..295461bd35 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -544,7 +544,7 @@ GEM psych (5.1.2) stringio public_suffix (5.0.4) - puma (6.4.0) + puma (6.4.1) nio4r (~> 2.0) pundit (2.3.1) activesupport (>= 3.0.0) From 2b330ede224d4fcc79b48f0de36da1ca9909d83d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 3 Jan 2024 10:10:19 +0100 Subject: [PATCH 3/6] Update dependency eslint-plugin-jsdoc to v48 (#28564) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 54dac54cd5..82cfd689a5 100644 --- a/package.json +++ b/package.json @@ -189,7 +189,7 @@ "eslint-import-resolver-typescript": "^3.5.5", "eslint-plugin-formatjs": "^4.10.1", "eslint-plugin-import": "~2.29.0", - "eslint-plugin-jsdoc": "^47.0.0", + "eslint-plugin-jsdoc": "^48.0.0", "eslint-plugin-jsx-a11y": "~6.8.0", "eslint-plugin-prettier": "^5.0.0", "eslint-plugin-promise": "~6.1.1", diff --git a/yarn.lock b/yarn.lock index 2bab9a2d0d..3cd45a11d6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2368,7 +2368,7 @@ __metadata: eslint-import-resolver-typescript: "npm:^3.5.5" eslint-plugin-formatjs: "npm:^4.10.1" eslint-plugin-import: "npm:~2.29.0" - eslint-plugin-jsdoc: "npm:^47.0.0" + eslint-plugin-jsdoc: "npm:^48.0.0" eslint-plugin-jsx-a11y: "npm:~6.8.0" eslint-plugin-prettier: "npm:^5.0.0" eslint-plugin-promise: "npm:~6.1.1" @@ -7407,9 +7407,9 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-jsdoc@npm:^47.0.0": - version: 47.0.1 - resolution: "eslint-plugin-jsdoc@npm:47.0.1" +"eslint-plugin-jsdoc@npm:^48.0.0": + version: 48.0.1 + resolution: "eslint-plugin-jsdoc@npm:48.0.1" dependencies: "@es-joy/jsdoccomment": "npm:~0.41.0" are-docs-informative: "npm:^0.0.2" @@ -7422,7 +7422,7 @@ __metadata: spdx-expression-parse: "npm:^4.0.0" peerDependencies: eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 - checksum: f2657cfc1394af0fca2c9c079065ffbc4e5fd41678299afb9ae261aff246cbd861d0ff38b57258caf6c9e9c57eb9975c75cd47c9f8c92bfefdaa4924eef62c24 + checksum: 9b211cfb2e07e076dad12681cd2045c65766dd24fe9399fd0adeaf6f8785f9a4dd58608f1183195f63d3c6c91013aa1cf9edc9101580cff9cb60e1e688f456f9 languageName: node linkType: hard From 7cce2a41f279ff157cb04d826bd5c46a129689aa Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 3 Jan 2024 10:19:46 +0100 Subject: [PATCH 4/6] New Crowdin Translations (automated) (#28573) Co-authored-by: GitHub Actions --- app/javascript/mastodon/locales/ia.json | 63 ++++++++++++++++++++++++- app/javascript/mastodon/locales/lt.json | 4 +- app/javascript/mastodon/locales/ta.json | 10 ++-- config/locales/doorkeeper.ie.yml | 4 ++ config/locales/simple_form.ie.yml | 6 +++ 5 files changed, 79 insertions(+), 8 deletions(-) diff --git a/app/javascript/mastodon/locales/ia.json b/app/javascript/mastodon/locales/ia.json index 917a034667..35397b8e12 100644 --- a/app/javascript/mastodon/locales/ia.json +++ b/app/javascript/mastodon/locales/ia.json @@ -1,23 +1,84 @@ { "account.add_or_remove_from_list": "Adder o remover ab listas", + "account.badges.group": "Gruppo", + "account.block": "Blocar @{name}", + "account.block_short": "Blocar", + "account.blocked": "Blocate", "account.copy": "Copiar ligamine a profilo", + "account.edit_profile": "Modificar profilo", + "account.go_to_profile": "Vader al profilo", + "account.moved_to": "{name} indicava que lor nove conto ora es:", + "account.share": "Compartir profilo de @{name}", + "account.unblock": "Disblocar @{name}", + "account.unblock_short": "Disblocar", + "account.unendorse": "Non evidentiar sur le profilo", + "account_note.placeholder": "Clicca pro adder un nota", + "admin.dashboard.retention.cohort_size": "Nove usatores", + "audio.hide": "Celar audio", + "autosuggest_hashtag.per_week": "{count} per septimana", "bundle_column_error.network.title": "Error de rete", + "bundle_column_error.retry": "Tentar novemente", + "bundle_column_error.return": "Retornar al initio", "bundle_modal_error.close": "Clauder", + "bundle_modal_error.retry": "Tentar novemente", + "column.blocks": "Usatores blocate", + "column.directory": "Navigar profilos", + "column.favourites": "Favoritos", "column.home": "Initio", + "column.lists": "Listas", + "column.notifications": "Notificationes", + "column_header.hide_settings": "Celar le parametros", + "column_header.show_settings": "Monstrar le parametros", "column_subheading.settings": "Parametros", + "compose.language.change": "Cambiar le lingua", "compose.language.search": "Cercar linguas...", "compose.published.open": "Aperir", + "compose_form.poll.add_option": "Adder un option", + "compose_form.poll.remove_option": "Remover iste option", "confirmation_modal.cancel": "Cancellar", + "confirmations.delete.confirm": "Deler", + "confirmations.delete_list.confirm": "Deler", "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.custom": "Personalisate", + "emoji_button.search_results": "Resultatos de recerca", + "empty_column.account_unavailable": "Profilo non disponibile", + "errors.unexpected_crash.report_issue": "Signalar un defecto", + "explore.search_results": "Resultatos de recerca", + "explore.trending_links": "Novas", + "firehose.all": "Toto", "firehose.local": "Iste servitor", + "firehose.remote": "Altere servitores", "footer.about": "A proposito de", + "footer.directory": "Directorio de profilos", + "footer.privacy_policy": "Politica de confidentialitate", + "footer.source_code": "Vider le codice fonte", + "footer.status": "Stato", "home.pending_critical_update.link": "Vider actualisationes", "keyboard_shortcuts.my_profile": "Aperir tu profilo", "lightbox.close": "Clauder", "lightbox.next": "Sequente", "link_preview.author": "Per {name}", "lists.account.add": "Adder al lista", - "navigation_bar.about": "A proposito de" + "mute_modal.duration": "Duration", + "mute_modal.hide_notifications": "Celar notificationes de iste usator?", + "navigation_bar.about": "A proposito de", + "navigation_bar.advanced_interface": "Aperir in un interfacie web avantiate", + "navigation_bar.blocks": "Usatores blocate", + "navigation_bar.favourites": "Favoritos", + "navigation_bar.lists": "Listas", + "navigation_bar.logout": "Clauder le session", + "navigation_bar.preferences": "Preferentias", + "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", + "onboarding.compose.template": "Salute #Mastodon!", + "onboarding.profile.save_and_continue": "Salvar e continuar", + "onboarding.share.title": "Compartir tu profilo" } diff --git a/app/javascript/mastodon/locales/lt.json b/app/javascript/mastodon/locales/lt.json index 82f1669b1a..ec0d30363c 100644 --- a/app/javascript/mastodon/locales/lt.json +++ b/app/javascript/mastodon/locales/lt.json @@ -2,7 +2,7 @@ "about.blocks": "Prižiūrimi serveriai", "about.contact": "Kontaktuoti:", "about.disclaimer": "Mastodon – nemokama atvirojo kodo programa ir Mastodon gGmbH prekės ženklas.", - "about.domain_blocks.no_reason_available": "Priežastis nežinoma", + "about.domain_blocks.no_reason_available": "Priežastis nepateikta", "about.domain_blocks.preamble": "Mastodon paprastai leidžia peržiūrėti turinį ir bendrauti su naudotojais iš bet kurio kito fediverse esančio serverio. Šios yra išimtys, kurios buvo padarytos šiame konkrečiame serveryje.", "about.domain_blocks.silenced.explanation": "Paprastai nematysi profilių ir turinio iš šio serverio, nebent jį aiškiai ieškosi arba pasirinksi jį sekdamas (-a).", "about.domain_blocks.silenced.title": "Ribota", @@ -35,7 +35,7 @@ "account.follow_back": "Sekti atgal", "account.followers": "Sekėjai", "account.followers.empty": "Šio naudotojo dar niekas neseka.", - "account.followers_counter": "{count, plural, one {{counter} sekėjas (-a)} few {{counter} sekėjai} many {{counter} sekėjo} other {{counter} sekėjų}}", + "account.followers_counter": "{count, plural, one {{counter} sekėjas} few {{counter} sekėjai} many {{counter} sekėjo} other {{counter} sekėjų}}", "account.following": "Seka", "account.following_counter": "{count, plural, one {{counter} Seka} few {{counter} Seka} many {{counter} Seka} other {{counter} Seka}}", "account.follows.empty": "Šis (-i) naudotojas (-a) dar nieko neseka.", diff --git a/app/javascript/mastodon/locales/ta.json b/app/javascript/mastodon/locales/ta.json index 955955b8c2..5290e13ff4 100644 --- a/app/javascript/mastodon/locales/ta.json +++ b/app/javascript/mastodon/locales/ta.json @@ -78,11 +78,11 @@ "bundle_modal_error.close": "மூடுக", "bundle_modal_error.message": "இக்கூற்றை ஏற்றம் செய்யும்பொழுது ஏதோ தவறு ஏற்பட்டுள்ளது.", "bundle_modal_error.retry": "மீண்டும் முயற்சி செய்", - "closed_registrations.other_server_instructions": "மசுடோடன் இரு பரவலாக்கப்பட்ட மென்பொருள் என்பதால், நீங்கள் வேரு ஒரு வழங்கியில் கணக்கை உருவாக்கியிருந்தாலும் இந்த வழங்கியில் பயன்படுத்தலாம்.", - "closed_registrations_modal.description": "{domain} இல் இப்பொழுது கணக்குகள் உருவாக்க முடியாது. நீங்கள் மசுடோடன் பயன்படுத்த, குறிப்பாக {domain} முகவரியில் கணக்கைத் துவங்க வேண்டும் என்ற அவசியமில்லை என்பதை மனதில் வைத்துக் கொள்ளவும்.", + "closed_registrations.other_server_instructions": "மேச்டடான் இரு பரவலாக்கப்பட்ட மென்பொருள் என்பதால், நீங்கள் வேரு ஒரு வழங்கியில் கணக்கை உருவாக்கியிருந்தாலும் இந்த வழங்கியில் பயன்படுத்தலாம்.", + "closed_registrations_modal.description": "{domain} இல் இப்பொழுது கணக்குகள் உருவாக்க முடியாது. நீங்கள் மேச்டடான் பயன்படுத்த, குறிப்பாக {domain} முகவரியில் கணக்கைத் துவங்க வேண்டும் என்ற அவசியமில்லை என்பதை மனதில் வைத்துக் கொள்ளவும்.", "closed_registrations_modal.find_another_server": "வேறொரு வழங்கியைக் கண்டுபிடி", - "closed_registrations_modal.preamble": "மசுடோடன் ஒரு பரவலாக்கப்பட்ட மென்பொருள். ஆதனால் நீங்கள் எங்குக் கணக்கை உருவாக்கினாலும் இந்த வழங்கியில் உள்ள யாருடன் வேண்டும் என்றாலும் உரவாடலாம். நீங்களே கூட ஒரு வழங்கியை நிறுவலாம்!", - "closed_registrations_modal.title": "மசுடோடன் கணக்கு துவங்கப்படுகிறது", + "closed_registrations_modal.preamble": "மேச்டடான் ஒரு பரவலாக்கப்பட்ட மென்பொருள். ஆதனால் நீங்கள் எங்குக் கணக்கை உருவாக்கினாலும் இந்த வழங்கியில் உள்ள யாருடன் வேண்டும் என்றாலும் உரவாடலாம். நீங்களே கூட ஒரு வழங்கியை நிறுவலாம்!", + "closed_registrations_modal.title": "மேச்டடான் கணக்கு துவங்கப்படுகிறது", "column.about": "பற்றி", "column.blocks": "தடுக்கப்பட்ட பயனர்கள்", "column.bookmarks": "அடையாளக்குறிகள்", @@ -113,7 +113,7 @@ "compose.language.search": "தேடல் மொழிகள்...", "compose.published.body": "பதிவிடப்பட்டது.", "compose.published.open": "திற", - "compose.saved.body": "பதிவி சேமிக்கப்பட்டது.", + "compose.saved.body": "பதிவு சேமிக்கப்பட்டது.", "compose_form.direct_message_warning_learn_more": "மேலும் அறிய", "compose_form.encryption_warning": "Mastodonல் உள்ள பதிவுகள் முறையாக என்க்ரிப்ட்(encrypt) செய்யபடவில்லை. அதனால் முக்கிய தகவல்களை இங்கே பகிர வேண்டாம்.", "compose_form.hashtag_warning": "This post won't be listed under any hashtag as it is unlisted. Only public posts can be searched by hashtag.", diff --git a/config/locales/doorkeeper.ie.yml b/config/locales/doorkeeper.ie.yml index 1b4b5994bd..86a5de7b37 100644 --- a/config/locales/doorkeeper.ie.yml +++ b/config/locales/doorkeeper.ie.yml @@ -70,6 +70,10 @@ ie: invalid_redirect_uri: Li uri de redirection includet ne es valid. invalid_request: unknown: Li petition manca un postulat parametre, include un ne apoyat parametre-valore, o es altrimen mal format. + invalid_token: + expired: Li access-clave expirat + revoked: Li access-clave esset revocat + unknown: Li accesse-clave es ínvalid unsupported_grant_type: Li tip de autorisation concedet ne es subtenet per li autorisant servitor. unsupported_response_type: Li autorisant servitor ne subtene ti-ci tip de response. flash: diff --git a/config/locales/simple_form.ie.yml b/config/locales/simple_form.ie.yml index f945e2342e..bde52e2a78 100644 --- a/config/locales/simple_form.ie.yml +++ b/config/locales/simple_form.ie.yml @@ -68,6 +68,7 @@ ie: form_admin_settings: backups_retention_period: Mantener usator-generat archives por li specificat quantitá de dies. bootstrap_timeline_accounts: Ti-ci contos va esser pinglat al parte superiori del recomandationes por nov usatores. + mascot: Substitue li ilustration in li avansat interfacie web. peers_api_enabled: Un liste de nómines de dominia queles ti-ci servitor ha incontrat in li fediverse. Ci null data es includet pri ca tu confedera con un cert servitor o ne; it indica solmen que tui servitor conosse it. Usat per servicies colectent general statisticas pri federation. profile_directory: Li profilarium monstra omni usatores volent esser decovribil. site_contact_email: Qualmen on posse contacter te por inquestes legal o de apoy. @@ -110,6 +111,10 @@ ie: name: Etiquette value: Contenete indexable: Includer public postas in resultates de sercha + account_alias: + acct: Usator-nómine del anteyan conto + account_migration: + acct: Usator-nómine del nov conto account_warning_preset: text: Textu prefigurat title: Titul @@ -240,6 +245,7 @@ ie: url: URL de punctu terminal 'no': 'No' not_recommended: Ne recomandat + overridden: Substituet recommended: Recomandat required: mark: "*" From bd415af9a11fe7057c9f428b7bdaeb8d4fb3a77b Mon Sep 17 00:00:00 2001 From: Claire Date: Wed, 3 Jan 2024 11:23:58 +0100 Subject: [PATCH 5/6] Change streaming API host to not be overridden to localhost in development mode (#28557) --- config/initializers/1_hosts.rb | 2 +- spec/requests/content_security_policy_spec.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config/initializers/1_hosts.rb b/config/initializers/1_hosts.rb index 6ff0845c46..5c59e28bd1 100644 --- a/config/initializers/1_hosts.rb +++ b/config/initializers/1_hosts.rb @@ -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 diff --git a/spec/requests/content_security_policy_spec.rb b/spec/requests/content_security_policy_spec.rb index 7610e698cd..d4cc40bce5 100644 --- a/spec/requests/content_security_policy_spec.rb +++ b/spec/requests/content_security_policy_spec.rb @@ -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 From 092bb8a27af9ee87ff9ebabaf354477470ea3a94 Mon Sep 17 00:00:00 2001 From: Claire Date: Wed, 3 Jan 2024 12:29:26 +0100 Subject: [PATCH 6/6] Fix Mastodon not correctly processing HTTP Signatures with query strings (#28476) --- .../concerns/signature_verification.rb | 22 ++++++- app/lib/request.rb | 11 +++- spec/requests/signature_verification_spec.rb | 66 +++++++++++++++++++ 3 files changed, 95 insertions(+), 4 deletions(-) diff --git a/app/controllers/concerns/signature_verification.rb b/app/controllers/concerns/signature_verification.rb index f0a344f1c9..35391e64c4 100644 --- a/app/controllers/concerns/signature_verification.rb +++ b/app/controllers/concerns/signature_verification.rb @@ -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? diff --git a/app/lib/request.rb b/app/lib/request.rb index 5f128af734..8d4120868d 100644 --- a/app/lib/request.rb +++ b/app/lib/request.rb @@ -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)) diff --git a/spec/requests/signature_verification_spec.rb b/spec/requests/signature_verification_spec.rb index b753750b84..401828c4a3 100644 --- a/spec/requests/signature_verification_spec.rb +++ b/spec/requests/signature_verification_spec.rb @@ -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: {