class Alexandria::Amazon::Ecs

Constants

SERVICE_URLS

Public Class Methods

camelize(string) click to toggle source
# File lib/alexandria/book_providers/amazon_ecs_util.rb, line 184
def self.camelize(string)
  string.to_s
    .gsub(%r{/(.?)}) { "::" + Regexp.last_match[1].upcase }
    .gsub(/(^|_)(.)/) { Regexp.last_match[2].upcase }
end
configure() { |options| ... } click to toggle source
# File lib/alexandria/book_providers/amazon_ecs_util.rb, line 58
def self.configure(&_proc)
  yield @@options
end
debug() click to toggle source

Get debug flag.

# File lib/alexandria/book_providers/amazon_ecs_util.rb, line 49
def self.debug
  @@debug
end
debug=(dbg) click to toggle source

Set debug flag to true or false.

# File lib/alexandria/book_providers/amazon_ecs_util.rb, line 54
def self.debug=(dbg)
  @@debug = dbg
end
hmac_sha256(message, key) click to toggle source
# File lib/alexandria/book_providers/amazon_ecs_util.rb, line 190
def self.hmac_sha256(message, key)
  block_size = 64
  ipad = "\x36" * block_size
  opad = "\x5c" * block_size
  if key.size > block_size
    d = Digest::SHA256.new
    key = d.digest(key)
  end

  ipad_bytes = ipad.bytes.map { |b| b }
  opad_bytes = opad.bytes.map { |b| b }
  key_bytes = key.bytes.map { |b| b }
  ipad_xor = ""
  opad_xor = ""
  (0..key.size - 1).each do |i|
    ipad_xor << (ipad_bytes[i] ^ key_bytes[i])
    opad_xor << (opad_bytes[i] ^ key_bytes[i])
  end

  ipad = ipad_xor + ipad[key.size..-1]
  opad = opad_xor + opad[key.size..-1]

  # inner hash
  d1 = Digest::SHA256.new
  d1.update(ipad)
  d1.update(message)
  msg_hash = d1.digest

  # outer hash
  d2 = Digest::SHA256.new
  d2.update(opad)
  d2.update(msg_hash)
  d2.digest
end
item_lookup(item_id, opts = {}) click to toggle source

Search an item by ASIN no.

# File lib/alexandria/book_providers/amazon_ecs_util.rb, line 80
def self.item_lookup(item_id, opts = {})
  opts[:operation] = "ItemLookup"
  opts[:item_id] = item_id

  send_request(opts)
end
options() click to toggle source

Default search options

# File lib/alexandria/book_providers/amazon_ecs_util.rb, line 35
def self.options
  @@options
end
options=(opts) click to toggle source

Set default search options

# File lib/alexandria/book_providers/amazon_ecs_util.rb, line 44
def self.options=(opts)
  @@options = opts
end
prepare_url(opts) click to toggle source
# File lib/alexandria/book_providers/amazon_ecs_util.rb, line 164
def self.prepare_url(opts)
  country = opts.delete(:country)
  country = country.nil? ? "us" : country
  request_url = SERVICE_URLS[country.to_sym]
  unless request_url
    raise Amazon::RequestError,
          format(_("Invalid country '%<country>s'"), country: country)
  end

  qs = ""
  opts.each do |k, v|
    next unless v

    v = v.join(",") if v.is_a? Array
    qs << "&#{camelize(k.to_s)}=#{CGI.escape(v.to_s)}"
  end
  url = "#{request_url}#{qs}"
  sign_request(url)
end
secret_access_key=(key) click to toggle source
# File lib/alexandria/book_providers/amazon_ecs_util.rb, line 39
def self.secret_access_key=(key)
  @@secret_access_key = key
end
send_request(opts) click to toggle source

Generic send request to ECS REST service. You have to specify the :operation parameter.

# File lib/alexandria/book_providers/amazon_ecs_util.rb, line 95
def self.send_request(opts)
  opts = options.merge(opts) if options
  request_url = prepare_url(opts)
  log.debug { "Request URL: #{request_url}" }

  res = transport.get_response(URI.parse(request_url))
  unless res.is_a? Net::HTTPSuccess
    raise Amazon::RequestError, format(_("HTTP Response: %<code>s %<message>s"),
                                       code: res.code, message: res.message)
  end

  Response.new(res.body)
end
sign_request(request) click to toggle source
# File lib/alexandria/book_providers/amazon_ecs_util.rb, line 225
def self.sign_request(request)
  raise AmazonNotConfiguredError unless @@secret_access_key

  # Step 0 : Split apart request string
  url_pattern = %r{http://([^/]+)(/[^?]+)\?(.*$)}
  url_pattern =~ request
  host = Regexp.last_match[1]
  path = Regexp.last_match[2]
  param_string = Regexp.last_match[3]

  # Step 1: enter the timestamp
  t = Time.now.getutc # MUST be in UTC
  stamp = t.strftime("%Y-%m-%dT%H:%M:%SZ")
  param_string += "&Timestamp=#{stamp}"

  # Step 2 : URL-encode
  param_string = param_string.gsub(",", "%2C").gsub(":", "%3A")
  #   NOTE : take care not to double-encode

  # Step 3 : Split the parameter/value pairs
  params = param_string.split("&")

  # Step 4 : Sort params
  params.sort!

  # Step 5 : Rejoin the param string
  canonical_param_string = params.join("&")

  # Steps 6 & 7: Prepend HTTP request info
  string_to_sign = "GET\n#{host}\n#{path}\n#{canonical_param_string}"

  # Step 8 : Calculate RFC 2104-compliant HMAC with SHA256 hash algorithm
  sig = hmac_sha256(string_to_sign, @@secret_access_key)
  base64_sig = [sig].pack("m").strip

  # Step 9 : URL-encode + and = in sig
  base64_sig = CGI.escape(base64_sig)

  # Step 10 : Add the URL encoded signature to your request
  "http://#{host}#{path}?#{param_string}&Signature=#{base64_sig}"
end
transport() click to toggle source

HACK : copied from book_providers.rb

# File lib/alexandria/book_providers/amazon_ecs_util.rb, line 88
def self.transport
  config = Alexandria::Preferences.instance.http_proxy_config
  config ? Net::HTTP.Proxy(*config) : Net::HTTP
end