aws-url 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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