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 +56 -0
- data/awsraw.gemspec +2 -2
- data/lib/awsraw/s3/query_string_signer.rb +53 -0
- data/lib/awsraw/s3/signer.rb +9 -3
- data/lib/awsraw/version.rb +1 -1
- data/spec/s3/query_string_signer_spec.rb +29 -0
- data/spec/s3/signer_spec.rb +4 -4
- metadata +55 -59
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
|
data/lib/awsraw/s3/signer.rb
CHANGED
@@ -16,14 +16,20 @@ module AWSRaw
|
|
16
16
|
@secret_access_key = secret_access_key
|
17
17
|
end
|
18
18
|
|
19
|
-
def
|
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)
|
data/lib/awsraw/version.rb
CHANGED
@@ -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
|
+
|
data/spec/s3/signer_spec.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
require 'awsraw/s3/signer'
|
2
2
|
|
3
3
|
describe AWSRaw::S3::Signer do
|
4
|
-
let(:access_key_id) { "
|
5
|
-
let(:secret_access_key) { "
|
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}:
|
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}:
|
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
|
-
|
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
|
-
|
19
|
-
|
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:
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
26
|
none: false
|
27
|
-
requirements:
|
28
|
-
- -
|
29
|
-
- !ruby/object:Gem::Version
|
30
|
-
|
31
|
-
|
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:
|
41
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
42
|
none: false
|
41
|
-
requirements:
|
42
|
-
- -
|
43
|
-
- !ruby/object:Gem::Version
|
44
|
-
|
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
|
-
|
86
|
-
segments:
|
78
|
+
requirements:
|
79
|
+
- - ! '>='
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '0'
|
82
|
+
segments:
|
87
83
|
- 0
|
88
|
-
|
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
|
-
|
95
|
-
segments:
|
87
|
+
requirements:
|
88
|
+
- - ! '>='
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '0'
|
91
|
+
segments:
|
96
92
|
- 0
|
97
|
-
|
93
|
+
hash: 2614771455796597765
|
98
94
|
requirements: []
|
99
|
-
|
100
95
|
rubyforge_project: awsraw
|
101
|
-
rubygems_version: 1.
|
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
|