awsraw 0.0.2 → 0.1.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 ADDED
@@ -0,0 +1,56 @@
1
+ # awsraw
2
+
3
+ A client for [Amazon Web Services](http://www.amazonaws.com/) in the style of
4
+ [FlickRaw](http://hanklords.github.com/flickraw/)
5
+
6
+ ## Background
7
+
8
+ AWSRaw helps you make authenticated requests to AWS's various services. It
9
+ doesn't provide any higher-level concepts like, for example, "delete this
10
+ file from S3". Instead, you should understand S3's http API and know that
11
+ sending a `DELETE` request to the bucket/key URL will result in the file
12
+ being deleted.
13
+
14
+ While these higher-level concepts can be useful (see, e.g.,
15
+ [fog](https://github.com/fog/fog)), they can also get in the way. Being
16
+ able to use a new AWS feature by simply following the AWS docs' examples
17
+ directly is very nice, instead of having to dig deep into a higher-level
18
+ library to figure out how they've mapped that new feature into their
19
+ terminology and API.
20
+
21
+ ## Usage
22
+
23
+ ### S3
24
+
25
+ Standard requests:
26
+
27
+ ```ruby
28
+ require 'awsraw/s3/client'
29
+
30
+ s3 = AWSRaw::S3::Client.new(
31
+ ENV['AWS_ACCESS_KEY_ID'],
32
+ ENV['AWS_SECRET_ACCESS_KEY'])
33
+
34
+ s3.request(:method => "PUT",
35
+ :bucket => "mah-sekret-buckit",
36
+ :key => "reaction.gif",
37
+ :content => File.read("reaction.gif"),
38
+ :headers => { "Content-Type" => "image/gif" })
39
+ ```
40
+
41
+ Signed query-string requests, to allow authorized clients to get protected
42
+ resources:
43
+
44
+ ```ruby
45
+ require 'awsraw/s3/query_string_signer'
46
+
47
+ signer = AWSRaw::S3::QueryStringSigner.new(
48
+ ENV['AWS_ACCESS_KEY_ID'],
49
+ ENV['AWS_SECRET_ACCESS_KEY'])
50
+
51
+ url = "http://s3.amazonaws.com/mah-sekret-bucket/reaction.gif"
52
+ expiry = Time.now.utc + 60 # 1 minute from now
53
+ temporary_url = signer.sign_with_query_string(url, expiry.to_i)
54
+ puts temporary_url
55
+ # => "http://s3.amazonaws.com/mah-sekret-bucket/reaction.gif?Signature=..."
56
+ ```
data/awsraw.gemspec CHANGED
@@ -5,8 +5,8 @@ require "awsraw/version"
5
5
  Gem::Specification.new do |s|
6
6
  s.name = "awsraw"
7
7
  s.version = Awsraw::VERSION
8
- s.authors = ["Pete Yandell"]
9
- s.email = ["pete@notahat.com"]
8
+ s.authors = ["Pete Yandell", "David Goodlad"]
9
+ s.email = ["pete@notahat.com", "david@goodlad.net"]
10
10
  s.homepage = "http://github.com/envato/awsraw"
11
11
  s.summary = %q{Minimal AWS client}
12
12
  s.description = %q{A client for Amazon Web Services in the style of FlickRaw}
@@ -0,0 +1,53 @@
1
+ require 'awsraw/s3/signer'
2
+ require 'cgi'
3
+
4
+ module AWSRaw
5
+ module S3
6
+
7
+ # Generates a signed query string to make an authenticated S3 GET request
8
+ #
9
+ # See http://docs.amazonwebservices.com/AmazonS3/latest/dev/RESTAuthentication.html#RESTAuthenticationQueryStringAuth
10
+ #
11
+ # The Authorization header method is usually preferable, as implemented in
12
+ # AWSRaw::S3::Signer. However, you may have occasions where you need a
13
+ # simple "download URL", without having to tell your user-agent (browser,
14
+ # curl, wget, etc) about all the special AWS headers. The query string
15
+ # authentication method is useful in those cases.
16
+ class QueryStringSigner < Signer
17
+ def sign_with_query_string(url, expires)
18
+ query_string_hash = query_string_hash(url, expires)
19
+
20
+ uri = URI.parse(url)
21
+ uri.query = query_string_hash.map { |k,v| "#{k}=#{v}" }.join("&")
22
+ uri.to_s
23
+ end
24
+
25
+ def query_string_hash(url, expires)
26
+ string_to_sign = string_to_sign(url, expires)
27
+ signature = encoded_signature(string_to_sign)
28
+
29
+ {
30
+ "AWSAccessKeyId" => @access_key_id,
31
+ "Expires" => expires.to_s,
32
+ "Signature" => CGI.escape(signature)
33
+ }
34
+ end
35
+
36
+ def string_to_sign(url, expires)
37
+ [
38
+ "GET",
39
+ # Assume user-agent won't send Content-MD5 header
40
+ "",
41
+ # Assume user-agent won't send Content-Type header
42
+ "",
43
+ expires.to_s,
44
+ # Assume user-agent won't send any amz headers
45
+ canonicalized_amz_headers({}),
46
+ canonicalized_resource(URI.parse(url))
47
+ ].flatten.join("\n")
48
+ end
49
+
50
+ end
51
+
52
+ end
53
+ end
@@ -16,14 +16,20 @@ module AWSRaw
16
16
  @secret_access_key = secret_access_key
17
17
  end
18
18
 
19
- def signature(request)
19
+ def authorization_header_value(request)
20
20
  string_to_sign = string_to_sign(request)
21
+ signature = encoded_signature(string_to_sign)
21
22
 
23
+ "AWS #{@access_key_id}:#{signature}"
24
+ end
25
+
26
+ # Backwards compatibility
27
+ alias_method :signature, :authorization_header_value
28
+
29
+ def encoded_signature(string_to_sign)
22
30
  digest = OpenSSL::Digest::Digest.new("sha1")
23
31
  sha = OpenSSL::HMAC.digest(digest, @secret_access_key, string_to_sign)
24
32
  signature = Base64.encode64(sha).strip
25
-
26
- "AWS #{@access_key_id}:#{signature}"
27
33
  end
28
34
 
29
35
  def string_to_sign(request)
@@ -1,3 +1,3 @@
1
1
  module Awsraw
2
- VERSION = "0.0.2"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -0,0 +1,29 @@
1
+ require 'awsraw/s3/query_string_signer'
2
+
3
+ describe AWSRaw::S3::QueryStringSigner do
4
+ let(:access_key_id) { "AKIAIOSFODNN7EXAMPLE" }
5
+ let(:secret_access_key) { "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" }
6
+
7
+ subject { AWSRaw::S3::QueryStringSigner.new(access_key_id, secret_access_key) }
8
+
9
+ context "examples from Amazon docs" do
10
+ it "signs a get request correctly" do
11
+ url = "http://s3.amazonaws.com/johnsmith/photos/puppy.jpg"
12
+ expiry = 1175139620
13
+
14
+ subject.string_to_sign(url, expiry).should ==
15
+ "GET\n\n\n#{expiry}\n/johnsmith/photos/puppy.jpg"
16
+
17
+ subject.query_string_hash(url, expiry).should == {
18
+ "AWSAccessKeyId" => access_key_id,
19
+ "Expires" => expiry.to_s,
20
+ "Signature" => "NpgCjnDzrM%2BWFzoENXmpNDUsSn8%3D"
21
+ }
22
+
23
+ subject.sign_with_query_string(url, expiry).to_s.should ==
24
+ "http://s3.amazonaws.com/johnsmith/photos/puppy.jpg?AWSAccessKeyId=#{access_key_id}&Expires=#{expiry}&Signature=NpgCjnDzrM%2BWFzoENXmpNDUsSn8%3D"
25
+ end
26
+
27
+ end
28
+ end
29
+
@@ -1,8 +1,8 @@
1
1
  require 'awsraw/s3/signer'
2
2
 
3
3
  describe AWSRaw::S3::Signer do
4
- let(:access_key_id) { "0PN5J17HBGZHT7JJ3X82" }
5
- let(:secret_access_key) { "uV3F3YluFJax1cknvbcGwgjvx4QpvB+leU8dUj2o" }
4
+ let(:access_key_id) { "AKIAIOSFODNN7EXAMPLE" }
5
+ let(:secret_access_key) { "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" }
6
6
 
7
7
  subject { AWSRaw::S3::Signer.new(access_key_id, secret_access_key) }
8
8
 
@@ -17,7 +17,7 @@ describe AWSRaw::S3::Signer do
17
17
  subject.string_to_sign(request).should ==
18
18
  "GET\n\n\nTue, 27 Mar 2007 19:36:42 +0000\n/johnsmith/photos/puppy.jpg"
19
19
 
20
- subject.signature(request).should == "AWS #{access_key_id}:xXjDGYUmKxnwqr5KXNPGldn5LbA="
20
+ subject.signature(request).should == "AWS #{access_key_id}:bWq2s1WEIj+Ydj0vQ697zp+IXMU="
21
21
  end
22
22
 
23
23
  it "signs an upload correctly" do
@@ -42,7 +42,7 @@ describe AWSRaw::S3::Signer do
42
42
  subject.string_to_sign(request).should ==
43
43
  "PUT\n4gJE4saaMU4BqNR0kLY+lw==\napplication/x-download\nTue, 27 Mar 2007 21:06:08 +0000\nx-amz-acl:public-read\nx-amz-meta-checksumalgorithm:crc32\nx-amz-meta-filechecksum:0x02661779\nx-amz-meta-reviewedby:joe@johnsmith.net,jane@johnsmith.net\n/static.johnsmith.net/db-backup.dat.gz"
44
44
 
45
- subject.signature(request).should == "AWS #{access_key_id}:C0FlOtU8Ylb9KDTpZqYkZPX91iI="
45
+ subject.signature(request).should == "AWS #{access_key_id}:ilyl83RwaSoYIEdixDQcA4OnAnc="
46
46
  end
47
47
 
48
48
  end
metadata CHANGED
@@ -1,107 +1,103 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: awsraw
3
- version: !ruby/object:Gem::Version
4
- hash: 27
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
5
  prerelease:
6
- segments:
7
- - 0
8
- - 0
9
- - 2
10
- version: 0.0.2
11
6
  platform: ruby
12
- authors:
7
+ authors:
13
8
  - Pete Yandell
9
+ - David Goodlad
14
10
  autorequire:
15
11
  bindir: bin
16
12
  cert_chain: []
17
-
18
- date: 2012-02-12 00:00:00 +11:00
19
- default_executable:
20
- dependencies:
21
- - !ruby/object:Gem::Dependency
13
+ date: 2012-11-22 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
22
16
  name: rake
17
+ requirement: !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: '0'
23
23
  type: :development
24
24
  prerelease: false
25
- version_requirements: &id001 !ruby/object:Gem::Requirement
25
+ version_requirements: !ruby/object:Gem::Requirement
26
26
  none: false
27
- requirements:
28
- - - ">="
29
- - !ruby/object:Gem::Version
30
- hash: 3
31
- segments:
32
- - 0
33
- version: "0"
34
- requirement: *id001
35
- - !ruby/object:Gem::Dependency
27
+ requirements:
28
+ - - ! '>='
29
+ - !ruby/object:Gem::Version
30
+ version: '0'
31
+ - !ruby/object:Gem::Dependency
36
32
  name: rspec
33
+ requirement: !ruby/object:Gem::Requirement
34
+ none: false
35
+ requirements:
36
+ - - ! '>='
37
+ - !ruby/object:Gem::Version
38
+ version: '0'
37
39
  type: :development
38
40
  prerelease: false
39
- version_requirements: &id002 !ruby/object:Gem::Requirement
41
+ version_requirements: !ruby/object:Gem::Requirement
40
42
  none: false
41
- requirements:
42
- - - ">="
43
- - !ruby/object:Gem::Version
44
- hash: 3
45
- segments:
46
- - 0
47
- version: "0"
48
- requirement: *id002
43
+ requirements:
44
+ - - ! '>='
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
49
47
  description: A client for Amazon Web Services in the style of FlickRaw
50
- email:
48
+ email:
51
49
  - pete@notahat.com
50
+ - david@goodlad.net
52
51
  executables: []
53
-
54
52
  extensions: []
55
-
56
53
  extra_rdoc_files: []
57
-
58
- files:
54
+ files:
59
55
  - .gitignore
60
56
  - Gemfile
57
+ - README.md
61
58
  - Rakefile
62
59
  - awsraw.gemspec
63
60
  - lib/awsraw.rb
64
61
  - lib/awsraw/s3/client.rb
62
+ - lib/awsraw/s3/query_string_signer.rb
65
63
  - lib/awsraw/s3/request.rb
66
64
  - lib/awsraw/s3/response.rb
67
65
  - lib/awsraw/s3/signer.rb
68
66
  - lib/awsraw/version.rb
69
67
  - spec/s3/client_spec.rb
68
+ - spec/s3/query_string_signer_spec.rb
70
69
  - spec/s3/signer_spec.rb
71
- has_rdoc: true
72
70
  homepage: http://github.com/envato/awsraw
73
71
  licenses: []
74
-
75
72
  post_install_message:
76
73
  rdoc_options: []
77
-
78
- require_paths:
74
+ require_paths:
79
75
  - lib
80
- required_ruby_version: !ruby/object:Gem::Requirement
76
+ required_ruby_version: !ruby/object:Gem::Requirement
81
77
  none: false
82
- requirements:
83
- - - ">="
84
- - !ruby/object:Gem::Version
85
- hash: 3
86
- segments:
78
+ requirements:
79
+ - - ! '>='
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ segments:
87
83
  - 0
88
- version: "0"
89
- required_rubygems_version: !ruby/object:Gem::Requirement
84
+ hash: 2614771455796597765
85
+ required_rubygems_version: !ruby/object:Gem::Requirement
90
86
  none: false
91
- requirements:
92
- - - ">="
93
- - !ruby/object:Gem::Version
94
- hash: 3
95
- segments:
87
+ requirements:
88
+ - - ! '>='
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ segments:
96
92
  - 0
97
- version: "0"
93
+ hash: 2614771455796597765
98
94
  requirements: []
99
-
100
95
  rubyforge_project: awsraw
101
- rubygems_version: 1.6.2
96
+ rubygems_version: 1.8.23
102
97
  signing_key:
103
98
  specification_version: 3
104
99
  summary: Minimal AWS client
105
- test_files:
100
+ test_files:
106
101
  - spec/s3/client_spec.rb
102
+ - spec/s3/query_string_signer_spec.rb
107
103
  - spec/s3/signer_spec.rb