Class: ShippingEasy::Signature

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

Overview

Used to generate ShippingEasy API signatures or to compare signature with one another.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ Signature

Creates a new API signature object.

options - The Hash options used to create a signature:

:api_secret - A ShippingEasy-supplied API secret
:method - The HTTP method used in the request. Either :get or :post. Default is :get.
:path - The URI path of the request. E.g. "/api/orders"
:params - The query params passed in as part of the request.
:body - The body of the request which should normally be a JSON payload.


21
22
23
24
25
26
27
28
29
# File 'lib/shipping_easy/signature.rb', line 21

def initialize(options = {})
  options = options.dup
  @api_secret = options.delete(:api_secret) || ""
  @method = options.fetch(:method, :get).to_s.upcase
  @path = options.delete(:path) || ""
  @body = options.delete(:body) || ""
  @params = options[:params].nil? ? {} : options.delete(:params).dup
  @params.delete(:api_signature) # remove for convenience
end

Instance Attribute Details

#api_secretObject (readonly)

Returns the value of attribute api_secret.



6
7
8
# File 'lib/shipping_easy/signature.rb', line 6

def api_secret
  @api_secret
end

#bodyObject (readonly)

Returns the value of attribute body.



6
7
8
# File 'lib/shipping_easy/signature.rb', line 6

def body
  @body
end

#methodObject (readonly)

Returns the value of attribute method.



6
7
8
# File 'lib/shipping_easy/signature.rb', line 6

def method
  @method
end

#paramsObject (readonly)

Returns the value of attribute params.



6
7
8
# File 'lib/shipping_easy/signature.rb', line 6

def params
  @params
end

#pathObject (readonly)

Returns the value of attribute path.



6
7
8
# File 'lib/shipping_easy/signature.rb', line 6

def path
  @path
end

Instance Method Details

#==(other_signature) ⇒ Object

Equality operator to determine if another signature object, or string, matches the current signature. If a string is passed in, it should represent the encrypted form of the API signature, not the plaintext version.

It uses a constant time string comparison function to limit the vulnerability of timing attacks.

Returns true if the supplied string or signature object matches the current object.



66
67
68
69
70
71
72
73
74
# File 'lib/shipping_easy/signature.rb', line 66

def ==(other_signature)
  expected_signature, supplied_signature = self.to_s, other_signature.to_s
  return false if expected_signature.nil? || supplied_signature.nil? || expected_signature.empty? || supplied_signature.empty?
  return false if expected_signature.bytesize != supplied_signature.bytesize
  l = expected_signature.unpack "C#{expected_signature.bytesize}"
  res = 0
  supplied_signature.each_byte { |byte| res |= byte ^ l.shift }
  res == 0
end

#encryptedObject

Encrypts the plaintext signature with the supplied API secret. This signature should be included when making a ShippingEasy API call.

Returns an encrypted signature.



56
57
58
# File 'lib/shipping_easy/signature.rb', line 56

def encrypted
  OpenSSL::HMAC::hexdigest("sha256", api_secret, plaintext)
end

#plaintextObject

Concatenates the parts of the base signature into a plaintext string using the following order:

  1. Capitilized method of the request. E.g. “POST”

  2. The URI path

  3. The query parameters sorted alphabetically and concatenated together into a URL friendly format: param1=ABC&param2=XYZ

  4. The request body as a string if one exists

All parts are then concatenated together with an ampersand. The result resembles something like this:

“POST&/api/orders&param1=ABC&param2=XYZ&flops","cost":"10.00","shipping_cost":"2.00"}”

Returns a correctly contenated plaintext API signature.



43
44
45
46
47
48
49
50
# File 'lib/shipping_easy/signature.rb', line 43

def plaintext
  parts = []
  parts << method
  parts << path
  parts << Rack::Utils.build_query(params.sort)
  parts << body.to_s unless body.nil? || body == ""
  parts.join("&")
end

#to_sObject

Returns the encrypted form of the signature.

Returns an encrypted signature.



79
80
81
# File 'lib/shipping_easy/signature.rb', line 79

def to_s
  encrypted
end