Move signature verification stoplight to the requests themselves (#10813)

* Move signature verification stoplight to the requests themselves

This avoids blocking messages from known keys for 5 minutes when only one fails…

* Put the stoplight on the actual client IP, not a potential reverse proxy
This commit is contained in:
ThibG 2019-05-23 15:22:39 +02:00 committed by Eugen Rochko
parent 369eb63321
commit 89d600bedb

View file

@ -43,13 +43,7 @@ module SignatureVerification
return return
end end
account_stoplight = Stoplight("source:#{request.ip}") { account_from_key_id(signature_params['keyId']) } account = account_from_key_id(signature_params['keyId'])
.with_fallback { nil }
.with_threshold(1)
.with_cool_off_time(5.minutes.seconds)
.with_error_handler { |error, handle| error.is_a?(HTTP::Error) ? handle.call(error) : raise(error) }
account = account_stoplight.run
if account.nil? if account.nil?
@signature_verification_failure_reason = "Public key not found for key #{signature_params['keyId']}" @signature_verification_failure_reason = "Public key not found for key #{signature_params['keyId']}"
@ -62,13 +56,7 @@ module SignatureVerification
return account unless verify_signature(account, signature, compare_signed_string).nil? return account unless verify_signature(account, signature, compare_signed_string).nil?
account_stoplight = Stoplight("source:#{request.ip}") { account.possibly_stale? ? account.refresh! : account_refresh_key(account) } account = stoplight_wrap_request { account.possibly_stale? ? account.refresh! : account_refresh_key(account) }
.with_fallback { nil }
.with_threshold(1)
.with_cool_off_time(5.minutes.seconds)
.with_error_handler { |error, handle| error.is_a?(HTTP::Error) ? handle.call(error) : raise(error) }
account = account_stoplight.run
if account.nil? if account.nil?
@signature_verification_failure_reason = "Public key not found for key #{signature_params['keyId']}" @signature_verification_failure_reason = "Public key not found for key #{signature_params['keyId']}"
@ -136,14 +124,23 @@ module SignatureVerification
def account_from_key_id(key_id) def account_from_key_id(key_id)
if key_id.start_with?('acct:') if key_id.start_with?('acct:')
ResolveAccountService.new.call(key_id.gsub(/\Aacct:/, '')) stoplight_wrap_request { ResolveAccountService.new.call(key_id.gsub(/\Aacct:/, '')) }
elsif !ActivityPub::TagManager.instance.local_uri?(key_id) elsif !ActivityPub::TagManager.instance.local_uri?(key_id)
account = ActivityPub::TagManager.instance.uri_to_resource(key_id, Account) account = ActivityPub::TagManager.instance.uri_to_resource(key_id, Account)
account ||= ActivityPub::FetchRemoteKeyService.new.call(key_id, id: false) account ||= stoplight_wrap_request { ActivityPub::FetchRemoteKeyService.new.call(key_id, id: false) }
account account
end end
end end
def stoplight_wrap_request(&block)
Stoplight("source:#{request.remote_ip}", &block)
.with_fallback { nil }
.with_threshold(1)
.with_cool_off_time(5.minutes.seconds)
.with_error_handler { |error, handle| error.is_a?(HTTP::Error) ? handle.call(error) : raise(error) }
.run
end
def account_refresh_key(account) def account_refresh_key(account)
return if account.local? || !account.activitypub? return if account.local? || !account.activitypub?
ActivityPub::FetchRemoteAccountService.new.call(account.uri, only_key: true) ActivityPub::FetchRemoteAccountService.new.call(account.uri, only_key: true)