Class: Signature::Request

Inherits:
Object
  • Object
show all
Includes:
QueryEncoder
Defined in:
lib/signature.rb

Constant Summary collapse

ISO8601 =
"%Y-%m-%dT%H:%M:%SZ"

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from QueryEncoder

encode_param, encode_param_without_escaping

Constructor Details

#initialize(method, path, query) ⇒ Request

Returns a new instance of Request.

Raises:

  • (ArgumentError)


28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/signature.rb', line 28

def initialize(method, path, query)
  raise ArgumentError, "Expected string" unless path.kind_of?(String)
  raise ArgumentError, "Expected hash" unless query.kind_of?(Hash)

  query_hash = {}
  auth_hash = {}
  query.each do |key, v|
    k = key.to_s.downcase
    k[0..4] == 'auth_' ? auth_hash[k] = v : query_hash[k] = v
  end

  @method = method.upcase
  @path, @query_hash, @auth_hash = path, query_hash, auth_hash
  @signed = false
end

Instance Attribute Details

#pathObject

Returns the value of attribute path.



21
22
23
# File 'lib/signature.rb', line 21

def path
  @path
end

#query_hashObject

Returns the value of attribute query_hash.



21
22
23
# File 'lib/signature.rb', line 21

def query_hash
  @query_hash
end

Instance Method Details

#auth_hashObject

Expose the authentication parameters for a signed request



158
159
160
161
# File 'lib/signature.rb', line 158

def auth_hash
  raise "Request not signed" unless @signed
  @auth_hash
end

#authenticate(timestamp_grace = 600) ⇒ Object

Authenticate a request

Takes a block which will be called with the auth_key from the request, and which should return a Signature::Token (or nil if no token can be found for the key)

Raises errors in the same way as authenticate_by_token!

Raises:

  • (ArgumentError)


105
106
107
108
109
110
111
112
113
114
115
# File 'lib/signature.rb', line 105

def authenticate(timestamp_grace = 600)
  raise ArgumentError, "Block required" unless block_given?
  key = @auth_hash['auth_key']
  raise AuthenticationError, "Missing parameter: auth_key" unless key
  token = yield key
  unless token
    raise AuthenticationError, "Unknown auth_key"
  end
  authenticate_by_token!(token, timestamp_grace)
  return token
end

#authenticate_async(timestamp_grace = 600) ⇒ Object

Authenticate a request asynchronously

This method is useful it you’re running a server inside eventmachine and need to lookup the token asynchronously.

The block is passed an auth key and a deferrable which should succeed with the token, or fail if the token cannot be found

This method returns a deferrable which succeeds with the valid token, or fails with an AuthenticationError which can be used to pass the error back to the user



129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/signature.rb', line 129

def authenticate_async(timestamp_grace = 600)
  raise ArgumentError, "Block required" unless block_given?
  df = EM::DefaultDeferrable.new

  key = @auth_hash['auth_key']

  unless key
    df.fail(AuthenticationError.new("Missing parameter: auth_key"))
    return
  end

  token_df = yield key
  token_df.callback { |token|
    begin
      authenticate_by_token!(token, timestamp_grace)
      df.succeed(token)
    rescue AuthenticationError => e
      df.fail(e)
    end
  }
  token_df.errback {
    df.fail(AuthenticationError.new("Unknown auth_key"))
  }
ensure
  return df
end

#authenticate_by_token(token, timestamp_grace = 600) ⇒ Object

Authenticate the request with a token, but rather than raising an exception if the request is invalid, simply returns false



91
92
93
94
95
# File 'lib/signature.rb', line 91

def authenticate_by_token(token, timestamp_grace = 600)
  authenticate_by_token!(token, timestamp_grace)
rescue AuthenticationError
  false
end

#authenticate_by_token!(token, timestamp_grace = 600) ⇒ Object

Authenticates the request with a token

Raises an AuthenticationError if the request is invalid. AuthenticationError exception messages are designed to be exposed to API consumers, and should help them correct errors generating signatures

Timestamp: Unless timestamp_grace is set to nil (which allows this check to be skipped), AuthenticationError will be raised if the timestamp is missing or further than timestamp_grace period away from the real time (defaults to 10 minutes)

Signature: Raises AuthenticationError if the signature does not match the computed HMAC. The error contains a hint for how to sign.



74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/signature.rb', line 74

def authenticate_by_token!(token, timestamp_grace = 600)
  # Validate that your code has provided a valid token. This does not
  # raise an AuthenticationError since passing tokens with empty secret is
  # a code error which should be fixed, not reported to the API's consumer
  if token.secret.nil? || token.secret.empty?
    raise "Provided token is missing secret"
  end

  validate_version!
  validate_timestamp!(timestamp_grace)
  validate_signature!(token)
  true
end

#sign(token) ⇒ Object

Sign the request with the given token, and return the computed authentication parameters



47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/signature.rb', line 47

def sign(token)
  @auth_hash = {
    :auth_version => "1.0",
    :auth_key => token.key,
    :auth_timestamp => Time.now.to_i.to_s
  }
  @auth_hash[:auth_signature] = signature(token)

  @signed = true

  return @auth_hash
end

#signed_paramsObject

Query parameters merged with the computed authentication parameters



165
166
167
# File 'lib/signature.rb', line 165

def signed_params
  @query_hash.merge(auth_hash)
end