diff options
author | Claire <claire.github-309c@sitedethib.com> | 2022-09-21 22:45:57 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-09-21 22:45:57 +0200 |
commit | 8cf7006d4efbcfdd4a4ab688db1bcc73a2915a47 (patch) | |
tree | e07bfabeb68cdd8ff5832069d1d64bf3b7ae685a /app/controllers/concerns | |
parent | 84aff598ea0b5670ef2a0d1009bca9c9136c2d50 (diff) |
Refactor ActivityPub handling to prepare for non-Account actors (#19212)
* Move ActivityPub::FetchRemoteAccountService to ActivityPub::FetchRemoteActorService ActivityPub::FetchRemoteAccountService is kept as a wrapper for when the actor is specifically required to be an Account * Refactor SignatureVerification to allow non-Account actors * fixup! Move ActivityPub::FetchRemoteAccountService to ActivityPub::FetchRemoteActorService * Refactor ActivityPub::FetchRemoteKeyService to potentially return non-Account actors * Refactor inbound ActivityPub payload processing to accept non-Account actors * Refactor inbound ActivityPub processing to accept activities relayed through non-Account * Refactor how Account key URIs are built * Refactor Request and drop unused key_id_format parameter * Rename ActivityPub::Dereferencer `signature_account` to `signature_actor`
Diffstat (limited to 'app/controllers/concerns')
-rw-r--r-- | app/controllers/concerns/signature_verification.rb | 52 |
1 files changed, 31 insertions, 21 deletions
diff --git a/app/controllers/concerns/signature_verification.rb b/app/controllers/concerns/signature_verification.rb index 4da068aed..2394574b3 100644 --- a/app/controllers/concerns/signature_verification.rb +++ b/app/controllers/concerns/signature_verification.rb @@ -45,10 +45,14 @@ module SignatureVerification end end - def require_signature! + def require_account_signature! render plain: signature_verification_failure_reason, status: signature_verification_failure_code unless signed_request_account end + def require_actor_signature! + render plain: signature_verification_failure_reason, status: signature_verification_failure_code unless signed_request_actor + end + def signed_request? request.headers['Signature'].present? end @@ -68,7 +72,11 @@ module SignatureVerification end def signed_request_account - return @signed_request_account if defined?(@signed_request_account) + signed_request_actor.is_a?(Account) ? signed_request_actor : nil + end + + def signed_request_actor + return @signed_request_actor if defined?(@signed_request_actor) raise SignatureVerificationError, 'Request not signed' unless signed_request? raise SignatureVerificationError, 'Incompatible request signature. keyId and signature are required' if missing_required_signature_parameters? @@ -78,22 +86,22 @@ module SignatureVerification verify_signature_strength! verify_body_digest! - account = account_from_key_id(signature_params['keyId']) + actor = actor_from_key_id(signature_params['keyId']) - raise SignatureVerificationError, "Public key not found for key #{signature_params['keyId']}" if account.nil? + 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 - return account unless verify_signature(account, signature, compare_signed_string).nil? + return actor unless verify_signature(actor, signature, compare_signed_string).nil? - account = stoplight_wrap_request { account.possibly_stale? ? account.refresh! : account_refresh_key(account) } + actor = stoplight_wrap_request { actor_refresh_key!(actor) } - raise SignatureVerificationError, "Public key not found for key #{signature_params['keyId']}" if account.nil? + raise SignatureVerificationError, "Public key not found for key #{signature_params['keyId']}" if actor.nil? - return account unless verify_signature(account, signature, compare_signed_string).nil? + return actor unless verify_signature(actor, signature, compare_signed_string).nil? - fail_with! "Verification failed for #{account.username}@#{account.domain} #{account.uri} using rsa-sha256 (RSASSA-PKCS1-v1_5 with SHA-256)" + fail_with! "Verification failed for #{actor.to_log_human_identifier} #{actor.uri} using rsa-sha256 (RSASSA-PKCS1-v1_5 with SHA-256)" rescue SignatureVerificationError => e fail_with! e.message rescue HTTP::Error, OpenSSL::SSL::SSLError => e @@ -112,7 +120,7 @@ module SignatureVerification def fail_with!(message) @signature_verification_failure_reason = message - @signed_request_account = nil + @signed_request_actor = nil end def signature_params @@ -160,10 +168,10 @@ module SignatureVerification raise SignatureVerificationError, "Invalid Digest value. Computed SHA-256 digest: #{body_digest}; given: #{sha256[1]}" end - def verify_signature(account, signature, compare_signed_string) - if account.keypair.public_key.verify(OpenSSL::Digest.new('SHA256'), signature, compare_signed_string) - @signed_request_account = account - @signed_request_account + def verify_signature(actor, signature, compare_signed_string) + if actor.keypair.public_key.verify(OpenSSL::Digest.new('SHA256'), signature, compare_signed_string) + @signed_request_actor = actor + @signed_request_actor end rescue OpenSSL::PKey::RSAError nil @@ -226,7 +234,7 @@ module SignatureVerification signature_params['keyId'].blank? || signature_params['signature'].blank? end - def account_from_key_id(key_id) + def actor_from_key_id(key_id) domain = key_id.start_with?('acct:') ? key_id.split('@').last : key_id if domain_not_allowed?(domain) @@ -237,13 +245,13 @@ module SignatureVerification if key_id.start_with?('acct:') stoplight_wrap_request { ResolveAccountService.new.call(key_id.gsub(/\Aacct:/, ''), suppress_errors: false) } elsif !ActivityPub::TagManager.instance.local_uri?(key_id) - account = ActivityPub::TagManager.instance.uri_to_resource(key_id, Account) + account = ActivityPub::TagManager.instance.uri_to_actor(key_id) account ||= stoplight_wrap_request { ActivityPub::FetchRemoteKeyService.new.call(key_id, id: false, suppress_errors: false) } account end rescue Mastodon::PrivateNetworkAddressError => e raise SignatureVerificationError, "Requests to private network addresses are disallowed (tried to query #{e.host})" - rescue Mastodon::HostValidationError, ActivityPub::FetchRemoteAccountService::Error, ActivityPub::FetchRemoteKeyService::Error, Webfinger::Error => e + rescue Mastodon::HostValidationError, ActivityPub::FetchRemoteActorService::Error, ActivityPub::FetchRemoteKeyService::Error, Webfinger::Error => e raise SignatureVerificationError, e.message end @@ -255,12 +263,14 @@ module SignatureVerification .run end - def account_refresh_key(account) - return if account.local? || !account.activitypub? - ActivityPub::FetchRemoteAccountService.new.call(account.uri, only_key: true, suppress_errors: false) + def actor_refresh_key!(actor) + return if actor.local? || !actor.activitypub? + return actor.refresh! if actor.respond_to?(:refresh!) && actor.possibly_stale? + + ActivityPub::FetchRemoteActorService.new.call(actor.uri, only_key: true, suppress_errors: false) rescue Mastodon::PrivateNetworkAddressError => e raise SignatureVerificationError, "Requests to private network addresses are disallowed (tried to query #{e.host})" - rescue Mastodon::HostValidationError, ActivityPub::FetchRemoteAccountService::Error, Webfinger::Error => e + rescue Mastodon::HostValidationError, ActivityPub::FetchRemoteActorService::Error, Webfinger::Error => e raise SignatureVerificationError, e.message end end |