class AlexaVerifier::Verifier
A namespace for all of our verifiers to live under @since 0.1
Attributes
Public Class Methods
Create a new AlexaVerifier::Verifier
object
@yield the configuration block @yieldparam config [AlexaVerifier::Configuration] the configuration object
# File lib/alexa_verifier/verifier.rb, line 14 def initialize @configuration = AlexaVerifier::Configuration.new yield @configuration if block_given? end
Public Instance Methods
Used to configure AlexaVerifier
.
@example
AlexaVerifier.configure do |c| c.some_config_option = true end
@yield the configuration block @yieldparam config [AlexaVerifier::Configuration] the configuration object
# File lib/alexa_verifier/verifier.rb, line 70 def configure yield @configuration end
Validate a request object from Rack. Raise an error if it is not valid.
@param [Rack::Request::Env] request a Rack HTTP Request
@raise [AlexaVerifier::InvalidCertificateURIError]
there was a problem validating the certificate URI from your request
@return [nil] will always return nil
# File lib/alexa_verifier/verifier.rb, line 29 def valid!(request) signature_certificate_url = request.env['HTTP_SIGNATURECERTCHAINURL'] AlexaVerifier::Verifier::CertificateURIVerifier.valid!(signature_certificate_url) if @configuration.verify_uri? raw_body = request.body.read request.body && request.body.rewind # call the rewind method if it exists (handles Sinatra specifically) check_that_request_is_timely(raw_body) if @configuration.verify_timeliness? check_that_request_is_valid(signature_certificate_url, request, raw_body) true end
Validate a request object from Rack. Return a boolean.
@param [Rack::Request::Env] request a Rack HTTP Request @return [Boolean] is the request valid?
# File lib/alexa_verifier/verifier.rb, line 49 def valid?(request) begin valid!(request) rescue AlexaVerifier::BaseError => e puts e return false end true end
Private Instance Methods
Prevent replays of requests by checking that they are timely.
@param [String] raw_body the raw body of our https request @raise [AlexaVerifier::InvalidRequestError] raised when the timestamp is not timely, or is not set
# File lib/alexa_verifier/verifier.rb, line 80 def check_that_request_is_timely(raw_body) request_json = JSON.parse(raw_body) raise AlexaVerifier::InvalidRequestError, 'Timestamp field not present in request' if request_json.fetch('request', {}).fetch('timestamp', nil).nil? request_is_timely = (Time.parse(request_json['request']['timestamp'].to_s) >= (Time.now - REQUEST_THRESHOLD)) raise AlexaVerifier::InvalidRequestError, "Request is from more than #{REQUEST_THRESHOLD} seconds ago" unless request_is_timely end
Check that our request is valid.
@param [String] signature_certificate_url the url for our signing certificate @param [Rack::Request::Env] request the request object @param [String] raw_body the raw body of our https request
# File lib/alexa_verifier/verifier.rb, line 94 def check_that_request_is_valid(signature_certificate_url, request, raw_body) certificate, chain = AlexaVerifier::CertificateStore.fetch(signature_certificate_url) if @configuration.verify_certificate? || @configuration.verify_signature? begin AlexaVerifier::Verifier::CertificateVerifier.valid!(certificate, chain) if @configuration.verify_certificate? check_that_request_was_signed(certificate.public_key, request, raw_body) if @configuration.verify_signature? rescue AlexaVerifier::InvalidCertificateError, AlexaVerifier::InvalidRequestError => error # We don't want to cache a certificate that fails our checks as it could lock us out of valid requests for the cache length AlexaVerifier::CertificateStore.delete(signature_certificate_url) raise error end end
Check that our request was signed by a given public key.
@param [OpenSSL::PKey::PKey] certificate_public_key the public key we are checking @param [Rack::Request::Env] request the request object we are checking @param [String] raw_body the raw body of our https request @raise [AlexaVerifier::InvalidRequestError] raised if our signature does not match the certificate provided
# File lib/alexa_verifier/verifier.rb, line 115 def check_that_request_was_signed(certificate_public_key, request, raw_body) signed_by_certificate = certificate_public_key.verify( OpenSSL::Digest::SHA1.new, Base64.decode64(request.env['HTTP_SIGNATURE']), raw_body ) raise AlexaVerifier::InvalidRequestError, 'Signature does not match certificate provided' unless signed_by_certificate end