aws-url 0.1.1 → 0.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/README.md CHANGED
@@ -2,18 +2,10 @@
2
2
 
3
3
  [![travis][status]][travis]
4
4
 
5
- A minimum-viable URL builder for [Amazon Web Services (AWS)][aws].
6
-
7
- ![bezos][bezos]
8
-
9
- [Vacuum][vacuum] and [Peddler][peddler] use AWS URL.
10
-
11
- [Fog][fog] doesn't.
5
+ AWS URL is a minimum-viable URL builder for [Amazon Web Services (AWS)][aws]
6
+ API queries. It signs requests with [Signature Version 2][sign].
12
7
 
13
8
  [status]: https://secure.travis-ci.org/hakanensari/aws-url.png
14
9
  [travis]: http://travis-ci.org/hakanensari/aws-url
15
10
  [aws]: http://aws.amazon.com/
16
- [vacuum]: https://github.com/hakanensari/vacuum
17
- [peddler]: https://github.com/hakanensari/peddler
18
- [fog]: https://github.com/fog/fog
19
- [bezos]: http://www.wired.com/images/article/magazine/1605/mf_amazon_f.jpg
11
+ [sign]: http://docs.amazonwebservices.com/general/latest/gr/signature-version-2.html
@@ -6,7 +6,7 @@ Gem::Specification.new do |gem|
6
6
  gem.authors = ['Hakan Ensari']
7
7
  gem.email = ['hakan.ensari@papercavalier.com']
8
8
  gem.description = %q{A minimum-viable URL builder for Amazon Web Services (AWS)}
9
- gem.summary = %q{Builds an Amazon Web Services URL}
9
+ gem.summary = %q{Signs an Amazon Web Services URL}
10
10
  gem.homepage = 'https://github.com/hakanensari/aws-url'
11
11
 
12
12
  gem.files = `git ls-files`.split($\)
@@ -16,6 +16,6 @@ Gem::Specification.new do |gem|
16
16
  gem.require_paths = ['lib']
17
17
  gem.version = AWS::URL::VERSION
18
18
 
19
- gem.add_development_dependency 'rake', '~> 0.9'
20
- gem.add_development_dependency 'rspec', '~> 2.9'
19
+ gem.add_development_dependency 'rake', '~> 0.9'
20
+ gem.add_development_dependency 'rspec', '~> 2.9'
21
21
  end
@@ -1,63 +1,57 @@
1
+ # Standard library dependencies.
1
2
  require 'base64'
2
3
  require 'openssl'
3
4
  require 'time'
4
5
  require 'uri'
5
6
 
7
+ # Internal dependencies.
8
+ require 'aws/url/signature'
9
+
6
10
  module AWS
7
11
  # A Signed Amazon Web Services (AWS) URL.
8
12
  #
9
- # Currently supports Signature Version 2.
10
- #
11
- # Note to self: Do not touch this code unless you have a compelling reason.
13
+ # Supports Signature Version 2.
12
14
  class URL
13
- # The SHA256 hash algorithm.
14
- SHA256 = OpenSSL::Digest::SHA256.new
15
+ UNRESERVED = /([^\w.~-]+)/
15
16
 
16
17
  # Initializes a new URL.
17
18
  #
18
19
  # base_url - The String base URL, including scheme, host and path, of the
19
20
  # AWS endpoint.
21
+ # action - The String-like HTTP action.
20
22
  # key - The String AWS access key id.
21
23
  # secret - The String AWS secret key.
22
- def initialize(base_url, key, secret)
24
+ def initialize(base_url, action, key, secret)
23
25
  @base_url = URI base_url
26
+ @action = action.to_s.upcase
24
27
  @key = key
25
28
  @secret = secret
26
29
  @params = {}
27
30
  end
28
31
 
29
- # Builds a signed URL for specified HTTP method.
30
- #
31
- # method - A String-like HTTP method.
32
- #
33
- # Returns a String URL.
34
- def build(method)
35
- # Build an unsigned query string.
36
- query = params.sort.map { |k, v| "#{k}=#{ percent_encode v }" }.join '&'
37
-
38
- # Build the signature.
39
- string_to_sign = [
40
- method.to_s.upcase,
41
- @base_url.host,
42
- @base_url.path,
43
- query
44
- ].join "\n"
45
- signature = sign string_to_sign
46
-
47
- "#{@base_url}?#{query}&Signature=#{percent_encode signature}"
48
- end
49
-
50
32
  # Returns the Hash AWS parameters.
51
33
  def params
52
34
  default_params.merge @params
53
35
  end
54
36
 
37
+ # Returns the signed query String.
38
+ def query
39
+ "#{unsigned_query}&Signature=#{escape signature}"
40
+ end
41
+
42
+ # Returns the signed URL String.
43
+ def to_s
44
+ "#{@base_url}?#{query}"
45
+ end
46
+
55
47
  # Updates the AWS parameters.
56
48
  #
57
49
  # hash - A Hash.
58
50
  #
59
51
  # Returns self.
60
52
  def update(hash)
53
+ @unsigned_query = nil
54
+
61
55
  hash.each do |key, val|
62
56
  # Syntactic sugar: Camelize symbol keys.
63
57
  if key.is_a? Symbol
@@ -71,12 +65,6 @@ module AWS
71
65
 
72
66
  private
73
67
 
74
- def percent_encode(value)
75
- value.to_s.gsub(/([^\w.~-]+)/) do
76
- '%' + $1.unpack('H2' * $1.bytesize).join('%').upcase
77
- end
78
- end
79
-
80
68
  def default_params
81
69
  {
82
70
  'AWSAccessKeyId' => @key,
@@ -86,9 +74,28 @@ module AWS
86
74
  }
87
75
  end
88
76
 
89
- def sign(message)
90
- digest = OpenSSL::HMAC.digest SHA256, @secret, message
91
- Base64.encode64(digest).chomp
77
+ def escape(value)
78
+ value.to_s.gsub(UNRESERVED) do
79
+ '%' + $1.unpack('H2' * $1.bytesize).join('%').upcase
80
+ end
81
+ end
82
+
83
+ def signature
84
+ Signature.build @secret, string_to_sign
85
+ end
86
+
87
+ def string_to_sign
88
+ [
89
+ @action,
90
+ @base_url.host,
91
+ @base_url.path,
92
+ unsigned_query
93
+ ].join "\n"
94
+ end
95
+
96
+ def unsigned_query
97
+ @unsigned_query ||=
98
+ params.map { |k, v| "#{k}=#{ escape v }" }.sort.join '&'
92
99
  end
93
100
  end
94
101
  end
@@ -0,0 +1,31 @@
1
+ module AWS
2
+ class URL
3
+ # Internal: A signature builder.
4
+ class Signature
5
+ SHA256 = OpenSSL::Digest::SHA256.new
6
+
7
+ # Builds a signature.
8
+ #
9
+ # secret - A String AWS secret key.
10
+ # message - The String to sign.
11
+ #
12
+ # Returns a String signature.
13
+ def self.build(secret, message)
14
+ new(secret, message).build
15
+ end
16
+
17
+ def initialize(secret, message)
18
+ @secret = secret
19
+ @message = message
20
+ end
21
+
22
+ def build
23
+ Base64.encode64(digest).chomp
24
+ end
25
+
26
+ def digest
27
+ OpenSSL::HMAC.digest SHA256, @secret, @message
28
+ end
29
+ end
30
+ end
31
+ end
@@ -1,5 +1,5 @@
1
1
  module AWS
2
2
  class URL
3
- VERSION = '0.1.1'
3
+ VERSION = '0.2.0'
4
4
  end
5
5
  end
@@ -2,41 +2,48 @@ require 'spec_helper'
2
2
 
3
3
  module AWS
4
4
  describe URL do
5
-
6
5
  before do
7
6
  @base_url = 'http://example.com/path'
8
- @url = URL.new @base_url, 'key', 'secret'
9
- end
10
-
11
- describe '#build' do
12
- subject { @url.build :get }
13
-
14
- it 'includes the base URL' do
15
- should { include @base_url }
16
- end
17
-
18
- it 'is signed' do
19
- should { match /Signature=[^&]+$/ }
20
- end
7
+ @url = URL.new @base_url, :get, 'key', 'secret'
21
8
  end
22
9
 
23
10
  describe '#params' do
24
11
  subject { @url.params }
25
12
 
26
13
  it 'includes a key' do
27
- should { include 'AWSAccessKeyId' }
14
+ should include 'AWSAccessKeyId'
28
15
  end
29
16
 
30
17
  it 'includes a signature version' do
31
- should { include 'SignatureVersion' }
18
+ should include 'SignatureVersion'
32
19
  end
33
20
 
34
21
  it 'includes a signature method' do
35
- should { include 'SignatureMethod' }
22
+ should include 'SignatureMethod'
36
23
  end
37
24
 
38
25
  it 'includes a timestamp' do
39
- should { include 'Timestamp' }
26
+ should include 'Timestamp'
27
+ end
28
+ end
29
+
30
+ describe '#query' do
31
+ subject { @url.query }
32
+
33
+ it 'is signed' do
34
+ should match /Signature=[^&]+$/
35
+ end
36
+ end
37
+
38
+ describe '#to_s' do
39
+ subject { @url.to_s }
40
+
41
+ it 'includes the base URL' do
42
+ should include @base_url
43
+ end
44
+
45
+ it 'includes the signed query' do
46
+ should include @url.query
40
47
  end
41
48
  end
42
49
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aws-url
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-05-23 00:00:00.000000000 Z
12
+ date: 2012-06-28 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
16
- requirement: &70339646668100 !ruby/object:Gem::Requirement
16
+ requirement: !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,10 +21,15 @@ dependencies:
21
21
  version: '0.9'
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *70339646668100
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '0.9'
25
30
  - !ruby/object:Gem::Dependency
26
31
  name: rspec
27
- requirement: &70339646667600 !ruby/object:Gem::Requirement
32
+ requirement: !ruby/object:Gem::Requirement
28
33
  none: false
29
34
  requirements:
30
35
  - - ~>
@@ -32,7 +37,12 @@ dependencies:
32
37
  version: '2.9'
33
38
  type: :development
34
39
  prerelease: false
35
- version_requirements: *70339646667600
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: '2.9'
36
46
  description: A minimum-viable URL builder for Amazon Web Services (AWS)
37
47
  email:
38
48
  - hakan.ensari@papercavalier.com
@@ -49,6 +59,7 @@ files:
49
59
  - aws-url.gemspec
50
60
  - lib/aws-url.rb
51
61
  - lib/aws/url.rb
62
+ - lib/aws/url/signature.rb
52
63
  - lib/aws/url/version.rb
53
64
  - spec/aws/url_spec.rb
54
65
  - spec/spec_helper.rb
@@ -72,10 +83,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
72
83
  version: '0'
73
84
  requirements: []
74
85
  rubyforge_project:
75
- rubygems_version: 1.8.11
86
+ rubygems_version: 1.8.23
76
87
  signing_key:
77
88
  specification_version: 3
78
- summary: Builds an Amazon Web Services URL
89
+ summary: Signs an Amazon Web Services URL
79
90
  test_files:
80
91
  - spec/aws/url_spec.rb
81
92
  - spec/spec_helper.rb