cloudfront-signer 1.0.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.
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in aws-cf-signer.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ Copyright (c) 2011 Anthony Bouch
2
+ Portions Copyright (c) 2011 Dylan Vaughn
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining
5
+ a copy of this software and associated documentation files (the
6
+ "Software"), to deal in the Software without restriction, including
7
+ without limitation the rights to use, copy, modify, merge, publish,
8
+ distribute, sublicense, and/or sell copies of the Software, and to
9
+ permit persons to whom the Software is furnished to do so, subject to
10
+ the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,103 @@
1
+ cloudfront-signer
2
+ =================
3
+
4
+ A fork of Dylan Vaughn's [excellent signing gem](https://github.com/stlondemand/aws_cf_signer).
5
+
6
+ See Amazon docs for [Using a Signed URL to Serve Private Content](http://docs.amazonwebservices.com/AmazonCloudFront/latest/DeveloperGuide/index.html?PrivateContent.html)
7
+
8
+ This version uses all class methods and a configure method to initialize options.
9
+
10
+ Seperate helper methods exist for safe signing of urls and stream paths, each of which has slightly different requirements. For example, urls must not contain any spaces, whereas a stream path can. Also we might not want to html escape a url or path if it is being supplied to a JavaScript block or Flash object.
11
+
12
+ Installation
13
+ ------------
14
+
15
+ The original gem was published as `aws_cf_signer`. Use `gem install aws_cf_signer` to install that version.
16
+
17
+ This gem has been publised as `cloudfront-signer`. Use `gem install cloudfront-signer` to install this gem.
18
+
19
+ Alternatively, place a copy of cloudfront-signer.rb (and the cloundfront-signer sub directory) in your lib directory.
20
+
21
+ In either case the signing class must be configured - supplying the path to a signing key.
22
+
23
+ In a Rails app this can be done by creating an initializer script in the /config/initializers directory.
24
+
25
+ e.g.
26
+
27
+ require 'cloudfront-signer'
28
+
29
+ AWS::CF::Signer.configure! "#{Rails.root}/keys/pk-APKAIKURNAUNR2BDSFDMA.pem"
30
+
31
+
32
+ Usage
33
+ -----
34
+
35
+ Call the class `sign_url` or `sign_path` method with optional policy settings.
36
+
37
+ AWS::CF::Signer.sign_url 'http://mydomain/path/to/my/content'
38
+
39
+ or
40
+
41
+ AWS::CF::Signer.sign_url 'http://mydomain/path/to/my/content', :expires => Time.now + 600
42
+
43
+ Streaming paths can be signed with the `sign_path` method.
44
+
45
+ AWS::CF::Signer.sign_path 'path/to/my/content'
46
+
47
+ or
48
+
49
+ AWS::CF::Signer.sign_path 'path/to/my/content', :expires => Time.now + 600
50
+
51
+
52
+ Both `sign_url` and `sign_path` have _safe_ versions that HTML encode the result allowing signed paths or urls to be placed in HTML markup. The 'non'-safe versions can be used for placing signed urls or paths in JavaScript blocks or Flash params.
53
+
54
+
55
+ ### Custom Policies
56
+
57
+ See Example Custom Policy 1 at above AWS doc link
58
+
59
+ url = AWS::CF::Signer.sign_url('http://d604721fxaaqy9.cloudfront.net/training/orientation.avi',
60
+ :expires => 'Sat, 14 Nov 2009 22:20:00 GMT',
61
+ :resource => 'http://d604721fxaaqy9.cloudfront.net/training/*',
62
+ :ip_range => '145.168.143.0/24'
63
+ )
64
+
65
+ See Example Custom Policy 2 at above AWS doc link
66
+
67
+ url = AWS::CF::Signer.sign_url('http://d84l721fxaaqy9.cloudfront.net/downloads/pictures.tgz',
68
+ :starting => 'Thu, 30 Apr 2009 06:43:10 GMT',
69
+ :expires => 'Fri, 16 Oct 2009 06:31:56 GMT',
70
+ :resource => 'http://*',
71
+ :ip_range => '216.98.35.1/32'
72
+ )
73
+
74
+ You can also pass in a path to a policy file. This will supersede any other policy options
75
+
76
+ url = AWS::CF::Signer.sign_url('http://d84l721fxaaqy9.cloudfront.net/downloads/pictures.tgz', :policy_file => '/path/to/policy/file.txt')
77
+
78
+
79
+ Note on Patches/Pull Requests (verbatum from Dylan's original repository)
80
+ -------------------------------------------------------------------------
81
+
82
+ * Fork the project.
83
+ * Make your feature addition or bug fix.
84
+ * Add tests for it. This is important so I don't break it in a
85
+ future version unintentionally.
86
+ * Commit, do not mess with rakefile, version, or history.
87
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
88
+ * Send me a pull request. Bonus points for topic branches.
89
+
90
+ Attributions
91
+ ------------
92
+
93
+ Parts of signing code taken from a question on Stack Overflow asked by Ben Wiseley, and answered by Blaz Lipuscek and Manual M:
94
+
95
+ * [http://stackoverflow.com/questions/2632457/create-signed-urls-for-cloudfront-with-ruby](http://stackoverflow.com/questions/2632457/create-signed-urls-for-cloudfront-with-ruby)
96
+ * [http://stackoverflow.com/users/315829/ben-wiseley](http://stackoverflow.com/users/315829/ben-wiseley)
97
+ * [http://stackoverflow.com/users/267804/blaz-lipuscek](http://stackoverflow.com/users/267804/blaz-lipuscek)
98
+ * [http://stackoverflow.com/users/327914/manuel-m](http://stackoverflow.com/users/327914/manuel-m)
99
+
100
+ License
101
+ -------
102
+
103
+ cloudfront-signer is distributed under the MIT License, portions copyright © 2011 Dylan Vaughn, STL, Anthony Bouch
@@ -0,0 +1,11 @@
1
+ require 'bundler/gem_tasks'
2
+
3
+ require "rspec/core/rake_task"
4
+
5
+ RSpec::Core::RakeTask.new(:spec) do |t|
6
+ t.pattern = 'spec/**/*_spec.rb'
7
+ t.rspec_opts = ["--colour", "--format", "nested"]
8
+ end
9
+
10
+ task :default => :spec
11
+
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "cloudfront-signer/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "cloudfront-signer"
7
+ s.version = AWS::CF::VERSION
8
+ s.authors = ["Anthony Bouch"]
9
+ s.email = ["tony@58bits.com"]
10
+ s.homepage = "http://github.com/58bits/cloudfront-signer"
11
+ s.summary = %q{A gem to sign url and stream paths for Amazon CloudFront private content.}
12
+ s.description = %q{A fork of Dylan Vaughn's excellent signing gem - https://github.com/stlondemand/aws_cf_signer. The gem has been rewritten to use class methods and includes specific signing methods for both url and streaming paths, including html 'safe' escpaed versions of each.}
13
+
14
+ s.rubyforge_project = "cloudfront-signer"
15
+
16
+ s.add_development_dependency "rspec"
17
+
18
+ s.files = `git ls-files`.split("\n")
19
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
20
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
21
+ s.require_paths = ["lib"]
22
+ end
@@ -0,0 +1,188 @@
1
+ # A re-write of https://github.com/stlondemand/aws_cf_signer
2
+ #
3
+ require 'openssl'
4
+ require 'time'
5
+ require 'base64'
6
+ require "cloudfront-signer/version"
7
+
8
+ module AWS
9
+ module CF
10
+ class Signer
11
+ # Public non-inheritable class accessors
12
+ #----------------------------------------------------------------------------
13
+ class << self
14
+ attr_accessor :key_pair_id
15
+
16
+ def key_path
17
+ @key_path
18
+ end
19
+
20
+ def key_path=(path)
21
+ raise ArgumentError.new("The signing key could not be found at #{path}") unless File.exists?(path)
22
+ @key_path = path
23
+ @key = OpenSSL::PKey::RSA.new(File.readlines(path).join(""))
24
+ end
25
+
26
+ def default_expires
27
+ @default_expires ||= 3600
28
+ end
29
+
30
+ def default_expires=(value)
31
+ raise ArgumentError.new("The default expires value must be an integer") unless value.is_a?(Integer)
32
+ @default_expires = value
33
+ end
34
+
35
+ private
36
+
37
+ # Private key
38
+ #----------------------------------------------------------------------------
39
+ def private_key
40
+ @key
41
+ end
42
+ end
43
+
44
+ #----------------------------------------------------------------------------
45
+ def self.is_configured?
46
+ if self.key_path && self.key_pair_id && private_key
47
+ return true
48
+ else
49
+ return false
50
+ end
51
+ end
52
+
53
+
54
+ # Configure the signing class.
55
+ #----------------------------------------------------------------------------
56
+ def self.configure!(key_path, options = {})
57
+
58
+ raise ArgumentError.new("You must supply the path to a PEM format private RSA key.") if key_path.nil?
59
+ self.key_path = key_path
60
+
61
+ @key_pair_id = options[:key_pair_id] || extract_key_pair_id(key_path)
62
+ unless @key_pair_id
63
+ raise ArgumentError.new("The Cloudfront signing key id could not be inferred from #{key_path}. Please supply the key pair id as a configuration arguemet.")
64
+ end
65
+
66
+ @default_expires = options[:default_expires] ? options[:default_expires] : 3600
67
+ end
68
+
69
+
70
+ # Signing methods
71
+ #----------------------------------------------------------------------------
72
+
73
+ # Sign a url - encoding any spaces in the url before signing. CloudFront
74
+ # stipulates that signed URLs must not contain spaces (as opposed to stream
75
+ # paths/filenames which CAN contain spaces).
76
+ #----------------------------------------------------------------------------
77
+ def self.sign_url(subject, policy_options = {})
78
+ self.sign(subject, {:remove_spaces => true}, policy_options)
79
+ end
80
+
81
+ # Sign a url (as above) and HTML encode the result.
82
+ #----------------------------------------------------------------------------
83
+ def self.sign_url_safe(subject, policy_options = {})
84
+ self.sign(subject, {:remove_spaces => true, :html_escape => true}, policy_options)
85
+ end
86
+
87
+ # Sign a stream path part or filename (spaces are allowed in stream paths
88
+ # and so are not removed).
89
+ #----------------------------------------------------------------------------
90
+ def self.sign_path(subject, policy_options ={})
91
+ self.sign(subject, {:remove_spaces => false}, policy_options)
92
+ end
93
+
94
+ # Sign a stream path or filename and HTML encode the result.
95
+ #----------------------------------------------------------------------------
96
+ def self.sign_path_safe(subject, policy_options ={})
97
+ self.sign(subject, {:remove_spaces => false, :html_escape => true}, policy_options)
98
+ end
99
+
100
+
101
+ # Sign a subject url or stream resource name with optional configuration and
102
+ # policy options
103
+ #----------------------------------------------------------------------------
104
+ def self.sign(subject, configuration_options = {}, policy_options = {})
105
+
106
+ raise "Configure using AWS::CF.Signer.configure! before signing." unless self.is_configured?
107
+
108
+ # If the url or stream path already has a query string parameter - append to that.
109
+ separator = subject =~ /\?/ ? '&' : '?'
110
+
111
+ if configuration_options[:remove_spaces]
112
+ subject.gsub!(/\s/, "%20")
113
+ end
114
+
115
+ if policy_options[:policy_file]
116
+ policy = IO.read(policy_options[:policy_file])
117
+ result = "#{subject}#{separator}Policy=#{encode_policy(policy)}&Signature=#{create_signature(policy)}&Key-Pair-Id=#{@key_pair_id}"
118
+ else
119
+ if policy_options.keys.size <= 1
120
+ # Canned Policy - shorter URL
121
+ expires_at = epoch_time(policy_options[:expires] || Time.now + self.default_expires)
122
+ policy = %({"Statement":[{"Resource":"#{subject}","Condition":{"DateLessThan":{"AWS:EpochTime":#{expires_at}}}}]})
123
+ result = "#{subject}#{separator}Expires=#{expires_at}&Signature=#{create_signature(policy)}&Key-Pair-Id=#{@key_pair_id}"
124
+ else
125
+ # Custom Policy
126
+ resource = policy_options[:resource] || subject
127
+ policy = generate_custom_policy(resource, policy_options)
128
+ result = "#{subject}#{separator}Policy=#{encode_policy(policy)}&Signature=#{create_signature(policy)}&Key-Pair-Id=#{@key_pair_id}"
129
+ end
130
+ end
131
+
132
+ if configuration_options[:html_escape]
133
+ return html_encode(result)
134
+ else
135
+ return result
136
+ end
137
+ end
138
+
139
+
140
+ # Private helper methods
141
+ #----------------------------------------------------------------------------
142
+ private
143
+
144
+
145
+ #----------------------------------------------------------------------------
146
+ def self.generate_custom_policy(resource, options)
147
+ conditions = ["\"DateLessThan\":{\"AWS:EpochTime\":#{epoch_time(options[:expires])}}"]
148
+ conditions << "\"DateGreaterThan\":{\"AWS:EpochTime\":#{epoch_time(options[:starting])}}" if options[:starting]
149
+ conditions << "\"IpAddress\":{\"AWS:SourceIp\":\"#{options[:ip_range]}\"" if options[:ip_range]
150
+ %({"Statement":[{"Resource":"#{resource}","Condition":{#{conditions.join(',')}}}}]})
151
+ end
152
+
153
+ #----------------------------------------------------------------------------
154
+ def self.epoch_time(timelike)
155
+ case timelike
156
+ when String then Time.parse(timelike).to_i
157
+ when Time then timelike.to_i
158
+ else raise ArgumentError.new("Invalid argument - String or Time required - #{timelike.class} passed.")
159
+ end
160
+ end
161
+
162
+ #----------------------------------------------------------------------------
163
+ def self.encode_policy(policy)
164
+ url_encode(Base64.encode64(policy))
165
+ end
166
+
167
+ #----------------------------------------------------------------------------
168
+ def self.create_signature(policy)
169
+ url_encode(Base64.encode64(private_key.sign(OpenSSL::Digest::SHA1.new, (policy))))
170
+ end
171
+
172
+ #----------------------------------------------------------------------------
173
+ def self.extract_key_pair_id(key_path)
174
+ File.basename(key_path) =~ /^pk-(.*).pem$/ ? $1 : nil
175
+ end
176
+
177
+ #----------------------------------------------------------------------------
178
+ def self.url_encode(s)
179
+ s.gsub('+','-').gsub('=','_').gsub('/','~').gsub(/\n/,'').gsub(' ','')
180
+ end
181
+
182
+ #----------------------------------------------------------------------------
183
+ def self.html_encode(s)
184
+ return s.gsub('?', '%3F').gsub('=', '%3D').gsub('&', '%26')
185
+ end
186
+ end
187
+ end
188
+ end
@@ -0,0 +1,5 @@
1
+ module AWS
2
+ module CF
3
+ VERSION = "1.0.0"
4
+ end
5
+ end
@@ -0,0 +1,15 @@
1
+ -----BEGIN RSA PRIVATE KEY-----
2
+ MIICXgIBAAKBgQCp280I7v8JBVJBN7Kdfl4eD+noyqzbLAsz9mIr07hZQ3PjVa5g
3
+ 3j5Q8oXioU2ycxzXephfPr83l/FTAtPSZQ94Jh6u/CdoEYXfEtFbJYQ2lHXrra36
4
+ yVcyyxQ6tAKgUHdWnZ/vbItUhLnhCSqwelTNpgRzf6AKdVOtQPaZ+bnkQQIDAQAB
5
+ AoGAXWSPTbQq4gjc+yLmwJW0pg7V67tUY4XJ+x4jSDm3CM1/sKVxpa1M0jEm0D8k
6
+ e1Ozrf6oPOZBOQ4AEEZjtTD/2Yi8U0bwG97fg9NlZddGNN2jj8pEOWY53/iVWcfb
7
+ VGXVDlhUA0uIZhKK3Sl2SW9t/8p7affjJmGKn2nGLieRKIkCQQDQmExXqRnVNtCz
8
+ qjTPt81MU4cIrzXr/tUC9s6An8OcgiTDjiIOnY3XB/F19lpMQIMEzrB7f04GrpkQ
9
+ 0w6p/3NXAkEA0HXjiSyZaEoXoR2e/dTZrKw8npnjjW0CpKeSf8PK8qpFPK0UJOk7
10
+ aU0rStQmoAmygcHiw3hJ7slyVS8f9zn+JwJBAMMVbHCfadWKSm19RZ7um0ZC6Asr
11
+ MhbgYX9AK6kHwf3hiViK2TcqCrmMaDqWh6TAwMgCNfOKAAMnz2d4vEIo8kkCQQCl
12
+ qnq4gkQsWG2s8jBvg1+2VW8bkCsCMvbdyfqoJP69mUnK7bXLm7tGdTiJkE5d8zb0
13
+ 3hQLyiXfaiK9xeS+gk0TAkEAtuFcd+taoBnjhVL6q0OhNuA1T1+qYr5fyzQWKKKC
14
+ +WMRi2/JCJCL/SX12q5hMq759VnzfnbgqwAq6MlPUZKEBQ==
15
+ -----END RSA PRIVATE KEY-----
@@ -0,0 +1,6 @@
1
+ -----BEGIN PUBLIC KEY-----
2
+ MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCp280I7v8JBVJBN7Kdfl4eD+no
3
+ yqzbLAsz9mIr07hZQ3PjVa5g3j5Q8oXioU2ycxzXephfPr83l/FTAtPSZQ94Jh6u
4
+ /CdoEYXfEtFbJYQ2lHXrra36yVcyyxQ6tAKgUHdWnZ/vbItUhLnhCSqwelTNpgRz
5
+ f6AKdVOtQPaZ+bnkQQIDAQAB
6
+ -----END PUBLIC KEY-----
@@ -0,0 +1,74 @@
1
+ require 'spec_helper'
2
+
3
+ describe AWS::CF::Signer do
4
+
5
+ let(:key_path) { File.expand_path(File.dirname(__FILE__) + '/keys/pk-APKAIKUROOUNR2BAFUUU.pem') }
6
+
7
+ before(:each) do
8
+ AWS::CF::Signer.configure!(key_path)
9
+ end
10
+
11
+ describe "before default use" do
12
+
13
+ it "should be configured" do
14
+ AWS::CF::Signer.is_configured?.should eql(true)
15
+ end
16
+
17
+ it "should expire urls and paths in one hour by default" do
18
+ AWS::CF::Signer.default_expires.should eql(3600)
19
+ end
20
+
21
+ it "should optionally be configured to expire urls and paths in ten minutes" do
22
+ AWS::CF::Signer.configure!(key_path, :default_expires => 600)
23
+ AWS::CF::Signer.default_expires.should eql(600)
24
+ end
25
+ end
26
+
27
+ describe "when signing a url" do
28
+
29
+ it "should remove spaces from the url" do
30
+ url = "http://somedomain.com/sign me"
31
+ result = AWS::CF::Signer.sign_url(url)
32
+ (result =~ /\s/).should be_nil
33
+ end
34
+
35
+ it "should not html encode the signed url by default" do
36
+ url = "http://somedomain.com/someresource?opt1=one&opt2=two"
37
+ result = AWS::CF::Signer.sign_url(url)
38
+ (result =~ /\?/).should_not be_nil
39
+ (result =~ /=/).should_not be_nil
40
+ (result =~ /&/).should_not be_nil
41
+ end
42
+
43
+ it "should optionally html encode the signed url" do
44
+ url = "http://somedomain.com/someresource?opt1=one&opt2=two"
45
+ result = AWS::CF::Signer.sign_url_safe(url)
46
+ (result =~ /\?/).should be_nil
47
+ (result =~ /=/).should be_nil
48
+ (result =~ /&/).should be_nil
49
+ end
50
+
51
+ it "should expire in one hour by default" do
52
+ url = "http://somedomain.com/sign me"
53
+ result = AWS::CF::Signer.sign_url(url)
54
+ get_query_value(result, 'Expires').to_i.should eql((Time.now + 3600).to_i)
55
+ end
56
+
57
+ it "should optionally expire in ten minutes" do
58
+ url = "http://somedomain.com/sign me"
59
+ result = AWS::CF::Signer.sign_url(url, :expires => Time.now + 600)
60
+ get_query_value(result, 'Expires').to_i.should eql((Time.now + 600 ).to_i)
61
+ end
62
+
63
+ end
64
+
65
+
66
+ describe "when signing a path" do
67
+
68
+ it "should not remove spaces from the path" do
69
+ path = "/someprefix/sign me"
70
+ result = AWS::CF::Signer.sign_path(path)
71
+ (result =~ /\s/).should_not be_nil
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,20 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+
4
+ require 'rspec'
5
+ require 'cloudfront-signer'
6
+
7
+ def get_query_value(url, key)
8
+ query_string = url.slice((url =~ /\?/) + 1..-1)
9
+ pairs = query_string.split('&')
10
+ pairs.each do |item|
11
+ if item.start_with?(key)
12
+ return item.split('=')[1]
13
+ end
14
+ end
15
+ end
16
+
17
+
18
+ RSpec.configure do |config|
19
+
20
+ end
metadata ADDED
@@ -0,0 +1,76 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cloudfront-signer
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Anthony Bouch
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-08-08 00:00:00.000000000 +07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rspec
17
+ requirement: &2151692620 !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: '0'
23
+ type: :development
24
+ prerelease: false
25
+ version_requirements: *2151692620
26
+ description: A fork of Dylan Vaughn's excellent signing gem - https://github.com/stlondemand/aws_cf_signer.
27
+ The gem has been rewritten to use class methods and includes specific signing methods
28
+ for both url and streaming paths, including html 'safe' escpaed versions of each.
29
+ email:
30
+ - tony@58bits.com
31
+ executables: []
32
+ extensions: []
33
+ extra_rdoc_files: []
34
+ files:
35
+ - .gitignore
36
+ - Gemfile
37
+ - LICENSE
38
+ - README.markdown
39
+ - Rakefile
40
+ - cloudfront-signer.gemspec
41
+ - lib/cloudfront-signer.rb
42
+ - lib/cloudfront-signer/version.rb
43
+ - spec/keys/pk-APKAIKUROOUNR2BAFUUU.pem
44
+ - spec/keys/rsa-APKAIKUROOUNR2BAFUUU.pem
45
+ - spec/signer_spec.rb
46
+ - spec/spec_helper.rb
47
+ has_rdoc: true
48
+ homepage: http://github.com/58bits/cloudfront-signer
49
+ licenses: []
50
+ post_install_message:
51
+ rdoc_options: []
52
+ require_paths:
53
+ - lib
54
+ required_ruby_version: !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ! '>='
58
+ - !ruby/object:Gem::Version
59
+ version: '0'
60
+ required_rubygems_version: !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ requirements: []
67
+ rubyforge_project: cloudfront-signer
68
+ rubygems_version: 1.6.2
69
+ signing_key:
70
+ specification_version: 3
71
+ summary: A gem to sign url and stream paths for Amazon CloudFront private content.
72
+ test_files:
73
+ - spec/keys/pk-APKAIKUROOUNR2BAFUUU.pem
74
+ - spec/keys/rsa-APKAIKUROOUNR2BAFUUU.pem
75
+ - spec/signer_spec.rb
76
+ - spec/spec_helper.rb