claudetech/ruby-simple-api-auth

View on GitHub
lib/simple-api-auth/signer.rb

Summary

Maintainability
A
0 mins
Test Coverage
module SimpleApiAuth
  class Signer
    attr_accessor :hasher

    def initialize(options = {})
      hasher_class = options[:hasher] || SimpleApiAuth.config.hasher
      self.hasher = hasher_class.new
    end

    def sign(request, secret_key)
      fail SigningError, 'time header is not present' if request.time.nil?

      signing_key = make_signing_key(request, secret_key)
      SimpleApiAuth.log(Logger::DEBUG, "Signing key(hex): #{Digest.hexencode(signing_key)}")

      string_to_sign = make_string_to_sign(request)
      SimpleApiAuth.log(Logger::DEBUG, "String to sign: #{string_to_sign}")

      signature = hasher.hmac(signing_key, string_to_sign)
      Digest.hexencode(signature)
    end

    def make_string_to_sign(request)
      hashed_request = make_hashed_request(request)
      SimpleApiAuth.log(Logger::DEBUG, "Hashed request: #{hashed_request}")
      [
        request.time.iso8601,
        hashed_request
      ].join("\n")
    end

    def make_hashed_request(request)
      canonical_request_string = make_canonical_request(request)
      SimpleApiAuth.log(Logger::DEBUG, "Canonical request string: #{canonical_request_string}")
      Digest.hexencode(hasher.hash(canonical_request_string))
    end

    private

    def make_signing_key(request, secret_key)
      date = request.time.strftime('%Y%m%d')
      hashed_date = hasher.hmac('saa' + secret_key, date)
      hasher.hmac(hashed_date, 'saa_request')
    end

    def make_canonical_request(request)
      [
        request.http_verb,
        URI.encode(request.uri),
        URI.encode(request.query_string),
        Digest.hexencode(hasher.hash(request.body.read))
      ].join("\n")
    end
  end
end