1145dbd327
* Add a more descriptive PrivateNetworkAddressError exception class * Remove unnecessary exception class to rescue clause * Remove unnecessary include to JsonLdHelper * Give more neutral error message when too many webfinger redirects * Remove unnecessary guard condition * Rework how “ActivityPub::FetchRemoteAccountService” handles errors Add “suppress_errors” keyword argument to avoid raising errors in ActivityPub::FetchRemoteAccountService#call (default/previous behavior). * Rework how “ActivityPub::FetchRemoteKeyService” handles errors Add “suppress_errors” keyword argument to avoid raising errors in ActivityPub::FetchRemoteKeyService#call (default/previous behavior). * Fix Webfinger::RedirectError not being a subclass of Webfinger::Error * Add suppress_errors option to ResolveAccountService Defaults to true (to preserve previous behavior). If set to false, errors will be raised instead of caught, allowing the caller to be informed of what went wrong. * Return more precise error when failing to fetch account signing AP payloads * Add tests * Fixes * Refactor error handling a bit * Fix various issues * Add specific error when provided Digest is not 256 bits of base64-encoded data * Please CodeClimate * Improve webfinger error reporting
77 lines
2.5 KiB
Ruby
77 lines
2.5 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
class ActivityPub::FetchRemoteKeyService < BaseService
|
|
include JsonLdHelper
|
|
|
|
class Error < StandardError; end
|
|
|
|
# Returns account that owns the key
|
|
def call(uri, id: true, prefetched_body: nil, suppress_errors: true)
|
|
raise Error, 'No key URI given' if uri.blank?
|
|
|
|
if prefetched_body.nil?
|
|
if id
|
|
@json = fetch_resource_without_id_validation(uri)
|
|
if person?
|
|
@json = fetch_resource(@json['id'], true)
|
|
elsif uri != @json['id']
|
|
raise Error, "Fetched URI #{uri} has wrong id #{@json['id']}"
|
|
end
|
|
else
|
|
@json = fetch_resource(uri, id)
|
|
end
|
|
else
|
|
@json = body_to_json(prefetched_body, compare_id: id ? uri : nil)
|
|
end
|
|
|
|
raise Error, "Unable to fetch key JSON at #{uri}" if @json.nil?
|
|
raise Error, "Unsupported JSON-LD context for document #{uri}" unless supported_context?(@json)
|
|
raise Error, "Unexpected object type for key #{uri}" unless expected_type?
|
|
return find_account(@json['id'], @json, suppress_errors) if person?
|
|
|
|
@owner = fetch_resource(owner_uri, true)
|
|
|
|
raise Error, "Unable to fetch actor JSON #{owner_uri}" if @owner.nil?
|
|
raise Error, "Unsupported JSON-LD context for document #{owner_uri}" unless supported_context?(@owner)
|
|
raise Error, "Unexpected object type for actor #{owner_uri} (expected any of: #{SUPPORTED_TYPES})" unless expected_owner_type?
|
|
raise Error, "publicKey id for #{owner_uri} does not correspond to #{@json['id']}" unless confirmed_owner?
|
|
|
|
find_account(owner_uri, @owner, suppress_errors)
|
|
rescue Error => e
|
|
Rails.logger.debug "Fetching key #{uri} failed: #{e.message}"
|
|
raise unless suppress_errors
|
|
end
|
|
|
|
private
|
|
|
|
def find_account(uri, prefetched_body, suppress_errors)
|
|
account = ActivityPub::TagManager.instance.uri_to_resource(uri, Account)
|
|
account ||= ActivityPub::FetchRemoteAccountService.new.call(uri, prefetched_body: prefetched_body, suppress_errors: suppress_errors)
|
|
account
|
|
end
|
|
|
|
def expected_type?
|
|
person? || public_key?
|
|
end
|
|
|
|
def person?
|
|
equals_or_includes_any?(@json['type'], ActivityPub::FetchRemoteAccountService::SUPPORTED_TYPES)
|
|
end
|
|
|
|
def public_key?
|
|
@json['publicKeyPem'].present? && @json['owner'].present?
|
|
end
|
|
|
|
def owner_uri
|
|
@owner_uri ||= value_or_id(@json['owner'])
|
|
end
|
|
|
|
def expected_owner_type?
|
|
equals_or_includes_any?(@owner['type'], ActivityPub::FetchRemoteAccountService::SUPPORTED_TYPES)
|
|
end
|
|
|
|
def confirmed_owner?
|
|
value_or_id(@owner['publicKey']) == @json['id']
|
|
end
|
|
end
|