dynamodb 1.1.1 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +0 -1
- data/Rakefile +1 -1
- data/dynamodb.gemspec +2 -0
- data/lib/dynamodb.rb +0 -2
- data/lib/dynamodb/connection.rb +21 -13
- data/lib/dynamodb/request.rb +26 -91
- data/lib/dynamodb/version.rb +1 -1
- data/spec/dynamodb/request_spec.rb +22 -21
- metadata +34 -2
    
        data/Gemfile
    CHANGED
    
    
    
        data/Rakefile
    CHANGED
    
    
    
        data/dynamodb.gemspec
    CHANGED
    
    | @@ -13,8 +13,10 @@ Gem::Specification.new do |s| | |
| 13 13 | 
             
              s.executables  = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
         | 
| 14 14 | 
             
              s.homepage     = 'http://github.com/groupme/dynamodb'
         | 
| 15 15 |  | 
| 16 | 
            +
              s.add_runtime_dependency 'aws4', '0.0.1'
         | 
| 16 17 | 
             
              s.add_runtime_dependency 'multi_json', '1.3.7'
         | 
| 17 18 |  | 
| 19 | 
            +
              s.add_development_dependency 'rake'
         | 
| 18 20 | 
             
              s.add_development_dependency 'rspec', '2.8.0'
         | 
| 19 21 | 
             
              s.add_development_dependency 'webmock', '1.8.11'
         | 
| 20 22 | 
             
            end
         | 
    
        data/lib/dynamodb.rb
    CHANGED
    
    | @@ -9,8 +9,6 @@ module DynamoDB | |
| 9 9 | 
             
              class ServerError < BaseError; end
         | 
| 10 10 | 
             
              class AuthenticationError < BaseError; end
         | 
| 11 11 |  | 
| 12 | 
            -
              Credentials = Struct.new(:access_key_id, :secret_access_key)
         | 
| 13 | 
            -
             | 
| 14 12 | 
             
              require 'dynamodb/version'
         | 
| 15 13 | 
             
              require 'dynamodb/connection'
         | 
| 16 14 | 
             
              require 'dynamodb/http_handler'
         | 
    
        data/lib/dynamodb/connection.rb
    CHANGED
    
    | @@ -1,3 +1,5 @@ | |
| 1 | 
            +
            require "aws4/signer"
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            module DynamoDB
         | 
| 2 4 | 
             
              # Establishes a connection to Amazon DynamoDB using credentials.
         | 
| 3 5 | 
             
              class Connection
         | 
| @@ -14,42 +16,48 @@ module DynamoDB | |
| 14 16 | 
             
                # Create a connection
         | 
| 15 17 | 
             
                # uri:          # default 'https://dynamodb.us-east-1.amazonaws.com/'
         | 
| 16 18 | 
             
                # timeout:      # default 5 seconds
         | 
| 17 | 
            -
                # api_version:  # default | 
| 19 | 
            +
                # api_version:  # default
         | 
| 18 20 | 
             
                #
         | 
| 19 21 | 
             
                def initialize(opts = {})
         | 
| 20 | 
            -
                  if opts[:access_key_id] && opts[:secret_access_key]
         | 
| 21 | 
            -
                    @credentials = DynamoDB::Credentials.new(opts[:access_key_id], opts[:secret_access_key])
         | 
| 22 | 
            -
                  else
         | 
| 22 | 
            +
                  if !(opts[:access_key_id] && opts[:secret_access_key])
         | 
| 23 23 | 
             
                    raise ArgumentError.new("access_key_id and secret_access_key are required")
         | 
| 24 24 | 
             
                  end
         | 
| 25 25 |  | 
| 26 | 
            -
                  @uri = URI(opts[:uri] || "https://dynamodb.us-east-1.amazonaws.com/")
         | 
| 27 26 | 
             
                  set_timeout(opts[:timeout]) if opts[:timeout]
         | 
| 28 | 
            -
             | 
| 27 | 
            +
                  @uri = URI(opts[:uri] || "https://dynamodb.us-east-1.amazonaws.com/")
         | 
| 28 | 
            +
                  region = @uri.host.split(".", 4)[1] || "us-east-1"
         | 
| 29 29 | 
             
                  @api_version = opts[:api_version] || "DynamoDB_20111205"
         | 
| 30 | 
            +
                  @signer = AWS4::Signer.new(
         | 
| 31 | 
            +
                    access_key: opts[:access_key_id],
         | 
| 32 | 
            +
                    secret_key: opts[:secret_access_key],
         | 
| 33 | 
            +
                    region: region
         | 
| 34 | 
            +
                  )
         | 
| 30 35 | 
             
                end
         | 
| 31 36 |  | 
| 32 37 | 
             
                # Create and send a request to DynamoDB
         | 
| 33 38 | 
             
                #
         | 
| 34 39 | 
             
                # This returns either a SuccessResponse or a FailureResponse.
         | 
| 35 40 | 
             
                #
         | 
| 36 | 
            -
                # `operation` can be any DynamoDB operation. ` | 
| 41 | 
            +
                # `operation` can be any DynamoDB operation. `body` is a hash that will be
         | 
| 37 42 | 
             
                # used as the request body (in JSON format). More info available at:
         | 
| 38 43 | 
             
                # http://docs.amazonwebservices.com/amazondynamodb/latest/developerguide
         | 
| 39 44 | 
             
                #
         | 
| 40 | 
            -
                def post(operation,  | 
| 45 | 
            +
                def post(operation, body={})
         | 
| 41 46 | 
             
                  request = DynamoDB::Request.new(
         | 
| 42 | 
            -
                     | 
| 43 | 
            -
                     | 
| 44 | 
            -
                     | 
| 45 | 
            -
                     | 
| 46 | 
            -
                    data:        data
         | 
| 47 | 
            +
                    signer: @signer,
         | 
| 48 | 
            +
                    uri: @uri,
         | 
| 49 | 
            +
                    operation: version(operation),
         | 
| 50 | 
            +
                    body: body
         | 
| 47 51 | 
             
                  )
         | 
| 48 52 | 
             
                  http_handler.handle(request)
         | 
| 49 53 | 
             
                end
         | 
| 50 54 |  | 
| 51 55 | 
             
                private
         | 
| 52 56 |  | 
| 57 | 
            +
                def version(op)
         | 
| 58 | 
            +
                  "#{@api_version}.#{op}"
         | 
| 59 | 
            +
                end
         | 
| 60 | 
            +
             | 
| 53 61 | 
             
                def http_handler
         | 
| 54 62 | 
             
                  self.class.http_handler
         | 
| 55 63 | 
             
                end
         | 
    
        data/lib/dynamodb/request.rb
    CHANGED
    
    | @@ -1,107 +1,42 @@ | |
| 1 | 
            -
            require "base64"
         | 
| 2 | 
            -
            require "openssl"
         | 
| 3 | 
            -
             | 
| 4 1 | 
             
            module DynamoDB
         | 
| 5 2 | 
             
              class Request
         | 
| 6 | 
            -
                 | 
| 7 | 
            -
             | 
| 8 | 
            -
                    Base64.encode64(
         | 
| 9 | 
            -
                      OpenSSL::HMAC.digest('sha256', key, Digest::SHA256.digest(signing_string))
         | 
| 10 | 
            -
                    ).strip
         | 
| 11 | 
            -
                  end
         | 
| 12 | 
            -
                end
         | 
| 3 | 
            +
                RFC1123 = "%a, %d %b %Y %H:%M:%S GMT"
         | 
| 4 | 
            +
                ISO8601 = "%Y%m%dT%H%M%SZ"
         | 
| 13 5 |  | 
| 14 | 
            -
                attr_reader :uri, : | 
| 6 | 
            +
                attr_reader :uri, :operation, :body, :signer
         | 
| 15 7 |  | 
| 16 8 | 
             
                def initialize(args = {})
         | 
| 17 | 
            -
                  @uri | 
| 18 | 
            -
                  @ | 
| 19 | 
            -
                  @ | 
| 20 | 
            -
                  @ | 
| 21 | 
            -
                  @api_version  = args[:api_version]
         | 
| 22 | 
            -
                  @region       = args[:region] || "us-east-1"
         | 
| 23 | 
            -
                  @datetime     = Time.now.utc.strftime("%Y%m%dT%H%M%SZ")
         | 
| 24 | 
            -
                  @service      = "dynamodb"
         | 
| 25 | 
            -
                end
         | 
| 26 | 
            -
             | 
| 27 | 
            -
                def our_headers
         | 
| 28 | 
            -
                  {
         | 
| 29 | 
            -
                    "user-agent"           => "groupme/dynamodb",
         | 
| 30 | 
            -
                    "host"                 => uri.host,
         | 
| 31 | 
            -
                    "content-type"         => "application/x-amz-json-1.0",
         | 
| 32 | 
            -
                    "content-length"       => body.size,
         | 
| 33 | 
            -
                    "x-amz-date"           => datetime,
         | 
| 34 | 
            -
                    "x-amz-target"         => "#{api_version}.#{operation}",
         | 
| 35 | 
            -
                    "x-amz-content-sha256" => hexdigest(body || '')
         | 
| 36 | 
            -
                  }
         | 
| 9 | 
            +
                  @uri        = args[:uri]
         | 
| 10 | 
            +
                  @operation  = args[:operation]
         | 
| 11 | 
            +
                  @body       = MultiJson.dump(args[:body])
         | 
| 12 | 
            +
                  @signer     = args[:signer]
         | 
| 37 13 | 
             
                end
         | 
| 38 14 |  | 
| 39 15 | 
             
                def headers
         | 
| 40 | 
            -
                  @headers ||=  | 
| 41 | 
            -
                end
         | 
| 42 | 
            -
             | 
| 43 | 
            -
                 | 
| 44 | 
            -
             | 
| 45 | 
            -
                 | 
| 46 | 
            -
             | 
| 47 | 
            -
             | 
| 48 | 
            -
             | 
| 49 | 
            -
             | 
| 50 | 
            -
             | 
| 51 | 
            -
             | 
| 52 | 
            -
             | 
| 53 | 
            -
             | 
| 54 | 
            -
             | 
| 55 | 
            -
             | 
| 56 | 
            -
                   | 
| 57 | 
            -
                   | 
| 58 | 
            -
                  k_region = hmac(k_date, region)
         | 
| 59 | 
            -
                  k_service = hmac(k_region, service)
         | 
| 60 | 
            -
                  k_credentials = hmac(k_service, 'aws4_request')
         | 
| 61 | 
            -
                  hexhmac(k_credentials, string_to_sign)
         | 
| 62 | 
            -
                end
         | 
| 63 | 
            -
             | 
| 64 | 
            -
                def string_to_sign
         | 
| 65 | 
            -
                  parts = []
         | 
| 66 | 
            -
                  parts << 'AWS4-HMAC-SHA256'
         | 
| 67 | 
            -
                  parts << datetime
         | 
| 68 | 
            -
                  parts << credential_string
         | 
| 69 | 
            -
                  parts << hexdigest(canonical_request)
         | 
| 70 | 
            -
                  parts.join("\n")
         | 
| 71 | 
            -
                end
         | 
| 72 | 
            -
             | 
| 73 | 
            -
                def credential_string
         | 
| 74 | 
            -
                  parts = []
         | 
| 75 | 
            -
                  parts << datetime[0,8]
         | 
| 76 | 
            -
                  parts << region
         | 
| 77 | 
            -
                  parts << service
         | 
| 78 | 
            -
                  parts << 'aws4_request'
         | 
| 79 | 
            -
                  parts.join("/")
         | 
| 80 | 
            -
                end
         | 
| 81 | 
            -
             | 
| 82 | 
            -
                def canonical_request
         | 
| 83 | 
            -
                  parts = []
         | 
| 84 | 
            -
                  parts << "POST"
         | 
| 85 | 
            -
                  parts << uri.path
         | 
| 86 | 
            -
                  parts << uri.query
         | 
| 87 | 
            -
                  parts << our_headers.sort.map {|k, v| [k,v].join(':')}.join("\n") + "\n"
         | 
| 88 | 
            -
                  parts << "content-length;content-type;host;user-agent;x-amz-content-sha256;x-amz-date;x-amz-target"
         | 
| 89 | 
            -
                  parts << our_headers['x-amz-content-sha256']
         | 
| 90 | 
            -
                  parts.join("\n")
         | 
| 16 | 
            +
                  @headers ||= signed_headers
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                private
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                def signed_headers
         | 
| 22 | 
            +
                  date = Time.now.utc
         | 
| 23 | 
            +
                  h = {
         | 
| 24 | 
            +
                    "Date"                 => date.strftime(RFC1123),
         | 
| 25 | 
            +
                    "User-Agent"           => "groupme/dynamodb",
         | 
| 26 | 
            +
                    "Host"                 => uri.host,
         | 
| 27 | 
            +
                    "Content-Type"         => "application/x-amz-json-1.0",
         | 
| 28 | 
            +
                    "Content-Length"       => body.size.to_s,
         | 
| 29 | 
            +
                    "X-AMZ-Date"           => date.strftime(ISO8601),
         | 
| 30 | 
            +
                    "X-AMZ-Target"         => operation,
         | 
| 31 | 
            +
                    "X-AMZ-Content-SHA256" => hexdigest(body || '')
         | 
| 32 | 
            +
                  }
         | 
| 33 | 
            +
                  signer.sign("POST", uri, h, body)
         | 
| 91 34 | 
             
                end
         | 
| 92 35 |  | 
| 93 | 
            -
                def hexdigest | 
| 36 | 
            +
                def hexdigest(value)
         | 
| 94 37 | 
             
                  digest = Digest::SHA256.new
         | 
| 95 38 | 
             
                  digest.update(value)
         | 
| 96 39 | 
             
                  digest.hexdigest
         | 
| 97 40 | 
             
                end
         | 
| 98 | 
            -
             | 
| 99 | 
            -
                def hmac key, value
         | 
| 100 | 
            -
                  OpenSSL::HMAC.digest(OpenSSL::Digest::Digest.new('sha256'), key, value)
         | 
| 101 | 
            -
                end
         | 
| 102 | 
            -
             | 
| 103 | 
            -
                def hexhmac key, value
         | 
| 104 | 
            -
                  OpenSSL::HMAC.hexdigest(OpenSSL::Digest::Digest.new('sha256'), key, value)
         | 
| 105 | 
            -
                end
         | 
| 106 41 | 
             
              end
         | 
| 107 42 | 
             
            end
         | 
    
        data/lib/dynamodb/version.rb
    CHANGED
    
    
| @@ -1,31 +1,32 @@ | |
| 1 1 | 
             
            require "spec_helper"
         | 
| 2 2 |  | 
| 3 3 | 
             
            describe DynamoDB::Request do
         | 
| 4 | 
            -
              let(:uri)         { URI("https://dynamodb.us-east-1.amazonaws.com/") }
         | 
| 5 | 
            -
              let(:credentials) { DynamoDB::Credentials.new("access_key_id", "secret_access_key") }
         | 
| 6 | 
            -
              let(:data)        { {} }
         | 
| 7 | 
            -
              let(:request) {
         | 
| 8 | 
            -
                DynamoDB::Request.new(
         | 
| 9 | 
            -
                  uri:          uri,
         | 
| 10 | 
            -
                  api_version:  "DynamoDB_20111205",
         | 
| 11 | 
            -
                  credentials:  credentials,
         | 
| 12 | 
            -
                  data:         data,
         | 
| 13 | 
            -
                  operation:    "ListTables",
         | 
| 14 | 
            -
                )
         | 
| 15 | 
            -
              }
         | 
| 16 | 
            -
             | 
| 17 4 | 
             
              it "signs the request" do
         | 
| 18 5 | 
             
                Time.stub(now: Time.parse("20130508T201304Z"))
         | 
| 19 6 |  | 
| 7 | 
            +
                uri = URI("https://dynamodb.us-east-1.amazonaws.com/")
         | 
| 8 | 
            +
                signer = AWS4::Signer.new(
         | 
| 9 | 
            +
                  access_key: "access_key_id",
         | 
| 10 | 
            +
                  secret_key: "secret_access_key",
         | 
| 11 | 
            +
                  region: "us-east-1"
         | 
| 12 | 
            +
                )
         | 
| 13 | 
            +
                request = DynamoDB::Request.new(
         | 
| 14 | 
            +
                  uri: uri,
         | 
| 15 | 
            +
                  signer: signer,
         | 
| 16 | 
            +
                  body: {},
         | 
| 17 | 
            +
                  operation: "DynamoDB_20111205.ListTables",
         | 
| 18 | 
            +
                )
         | 
| 19 | 
            +
             | 
| 20 20 | 
             
                request.headers.should == {
         | 
| 21 | 
            -
                  " | 
| 22 | 
            -
                  " | 
| 23 | 
            -
                  " | 
| 24 | 
            -
                  " | 
| 25 | 
            -
                  " | 
| 26 | 
            -
                  " | 
| 27 | 
            -
                  " | 
| 28 | 
            -
                  " | 
| 21 | 
            +
                  "Content-Type"=>"application/x-amz-json-1.0",
         | 
| 22 | 
            +
                  "Content-Length"=>"2",
         | 
| 23 | 
            +
                  "Date"=>"Wed, 08 May 2013 20:13:04 GMT",
         | 
| 24 | 
            +
                  "User-Agent"=>"groupme/dynamodb",
         | 
| 25 | 
            +
                  "Host"=>"dynamodb.us-east-1.amazonaws.com",
         | 
| 26 | 
            +
                  "X-AMZ-Target"=>"DynamoDB_20111205.ListTables",
         | 
| 27 | 
            +
                  "X-AMZ-Date"=>"20130508T201304Z",
         | 
| 28 | 
            +
                  "X-AMZ-Content-SHA256"=>"44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a",
         | 
| 29 | 
            +
                  "Authorization"=>"AWS4-HMAC-SHA256 Credential=access_key_id/20130508/us-east-1/dynamodb/aws4_request, SignedHeaders=content-length;content-type;date;host;user-agent;x-amz-content-sha256;x-amz-date;x-amz-target, Signature=9e551627237673b4deaa2c22fd3b3777d6d0705facd35b56b289e357c4995c46"
         | 
| 29 30 | 
             
                }
         | 
| 30 31 | 
             
              end
         | 
| 31 32 | 
             
            end
         | 
    
        metadata
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: dynamodb
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 1. | 
| 4 | 
            +
              version: 1.2.0
         | 
| 5 5 | 
             
              prerelease: 
         | 
| 6 6 | 
             
            platform: ruby
         | 
| 7 7 | 
             
            authors:
         | 
| @@ -10,8 +10,24 @@ authors: | |
| 10 10 | 
             
            autorequire: 
         | 
| 11 11 | 
             
            bindir: bin
         | 
| 12 12 | 
             
            cert_chain: []
         | 
| 13 | 
            -
            date: 2013-05- | 
| 13 | 
            +
            date: 2013-05-17 00:00:00.000000000 Z
         | 
| 14 14 | 
             
            dependencies:
         | 
| 15 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 16 | 
            +
              name: aws4
         | 
| 17 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 18 | 
            +
                none: false
         | 
| 19 | 
            +
                requirements:
         | 
| 20 | 
            +
                - - '='
         | 
| 21 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 22 | 
            +
                    version: 0.0.1
         | 
| 23 | 
            +
              type: :runtime
         | 
| 24 | 
            +
              prerelease: false
         | 
| 25 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 26 | 
            +
                none: false
         | 
| 27 | 
            +
                requirements:
         | 
| 28 | 
            +
                - - '='
         | 
| 29 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 30 | 
            +
                    version: 0.0.1
         | 
| 15 31 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 16 32 | 
             
              name: multi_json
         | 
| 17 33 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| @@ -28,6 +44,22 @@ dependencies: | |
| 28 44 | 
             
                - - '='
         | 
| 29 45 | 
             
                  - !ruby/object:Gem::Version
         | 
| 30 46 | 
             
                    version: 1.3.7
         | 
| 47 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 48 | 
            +
              name: rake
         | 
| 49 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 50 | 
            +
                none: false
         | 
| 51 | 
            +
                requirements:
         | 
| 52 | 
            +
                - - ! '>='
         | 
| 53 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 54 | 
            +
                    version: '0'
         | 
| 55 | 
            +
              type: :development
         | 
| 56 | 
            +
              prerelease: false
         | 
| 57 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 58 | 
            +
                none: false
         | 
| 59 | 
            +
                requirements:
         | 
| 60 | 
            +
                - - ! '>='
         | 
| 61 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 62 | 
            +
                    version: '0'
         | 
| 31 63 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 32 64 | 
             
              name: rspec
         | 
| 33 65 | 
             
              requirement: !ruby/object:Gem::Requirement
         |