cloudfront-signer 2.2.0 → 2.2.1
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.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/.travis.yml +9 -0
- data/ChangeLog.markdown +3 -1
- data/Gemfile +2 -2
- data/LICENSE +2 -1
- data/README.markdown +55 -43
- data/Rakefile +3 -4
- data/cloudfront-signer.gemspec +22 -17
- data/lib/cloudfront-signer.rb +77 -56
- data/lib/cloudfront-signer/version.rb +3 -3
- data/lib/generators/cloudfront/install/install_generator.rb +5 -5
- data/lib/generators/cloudfront/install/templates/cloudfront-signer.rb +2 -2
- data/spec/signer_spec.rb +53 -57
- data/spec/spec_helper.rb +6 -6
- metadata +24 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: af2fd7402de3304dcebf5c73545b34f34a4bd793
|
4
|
+
data.tar.gz: 1758268e87d18ecaca43588ca03b34a0bd00e7a6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 61d635f44898c5ad71c2dad0a75c475f0307c8dd7f16b7e14e58ee789552c60e312ebe8dbf9e5cfe926db34356fc208ba57b4270b5f106dcdd8e03990e89b0b7
|
7
|
+
data.tar.gz: 779f86267e2e7027a28ce2ff11629349f325cac5d608065b914cc72b9fc42407d8fa99c7ad77414820ccfcfc840d1b2cb254de7691c1677d1c06608eefca40b8
|
data/.travis.yml
ADDED
data/ChangeLog.markdown
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
### 2.2.1 / 2015-04-29
|
2
|
+
* Fixes policy generation when specifying an ip_range. See https://github.com/leonelgalan/cloudfront-signer/commit/18b19cc2f833850f360a92f4e244358601bba5ec#commitcomment-11249140 for details.
|
3
|
+
|
1
4
|
### 2.2.0 / 2015-04-29
|
2
5
|
* Accepted merge request from https://github.com/leonelgalan - `sign_params` method returns raw params to be used in urls or cookies.
|
3
6
|
|
@@ -7,4 +10,3 @@
|
|
7
10
|
### 2.1.1 / 2013-10-31
|
8
11
|
* Added changelog file
|
9
12
|
* Aceppted merge request from https://github.com/bullfight, Refactored configuration to allow for key to be passed in directly.
|
10
|
-
|
data/Gemfile
CHANGED
data/LICENSE
CHANGED
data/README.markdown
CHANGED
@@ -1,10 +1,10 @@
|
|
1
|
-
# cloudfront-signer
|
1
|
+
# cloudfront-signer [](https://travis-ci.org/leonelgalan/cloudfront-signer) [](https://codeclimate.com/github/leonelgalan/cloudfront-signer) [](https://codeclimate.com/github/leonelgalan/cloudfront-signer/coverage) [](http://badge.fury.io/rb/cloudfront-signer) [](https://gemnasium.com/leonelgalan/cloudfront-signer)
|
2
2
|
|
3
3
|
See the [ChangeLog](https://github.com/58bits/cloudfront-signer/blob/master/ChangeLog.markdown) for details of this release.
|
4
4
|
|
5
|
-
|
5
|
+
See Amazon docs for [Serving Private Content through CloudFront](http://docs.amazonwebservices.com/AmazonCloudFront/latest/DeveloperGuide/index.html?PrivateContent.html)
|
6
6
|
|
7
|
-
|
7
|
+
A fork and rewrite started by [Anthony Bouch](https://github.com/58bits) of Dylan Vaughn's [aws_cf_signer](https://github.com/stlondemand/aws_cf_signer).
|
8
8
|
|
9
9
|
This version uses all class methods and a configure method to set options.
|
10
10
|
|
@@ -12,47 +12,60 @@ Seperate helper methods exist for safe signing of urls and stream paths, each of
|
|
12
12
|
|
13
13
|
## Installation
|
14
14
|
|
15
|
-
The original gem was published as `aws_cf_signer`. Use `gem install aws_cf_signer` to install that version.
|
16
|
-
|
17
15
|
This gem has been publised as `cloudfront-signer`. Use `gem install cloudfront-signer` to install this gem.
|
18
16
|
|
19
17
|
Alternatively, place a copy of cloudfront-signer.rb (and the cloundfront-signer sub directory) in your lib directory.
|
20
18
|
|
21
19
|
In either case the signing class must be configured - supplying the path to a signing key, or supplying the signing key directly as a string along with the `key_pair_id`. Create the initializer by running:
|
22
20
|
|
23
|
-
```
|
24
|
-
bundle exec rails
|
21
|
+
```sh
|
22
|
+
bundle exec rails generate cloudfront:install
|
25
23
|
```
|
26
24
|
|
27
|
-
and customizing the resulting
|
25
|
+
and customizing the resulting _config/initializers/cloudfront-signer.rb_ file.
|
28
26
|
|
29
|
-
### Generated
|
27
|
+
### Generated _cloudfront-signer.rb_
|
30
28
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
29
|
+
```ruby
|
30
|
+
AWS::CF::Signer.configure do |config|
|
31
|
+
config.key_path = '/path/to/keyfile.pem'
|
32
|
+
# config.key = ENV.fetch('PRIVATE_KEY') # key_path not required if key supplied directly
|
33
|
+
config.key_pair_id = 'XXYYZZ'
|
34
|
+
config.default_expires = 3600
|
35
|
+
end
|
36
|
+
```
|
37
37
|
|
38
38
|
## Usage
|
39
39
|
|
40
40
|
Call the class `sign_url` or `sign_path` method with optional policy settings.
|
41
41
|
|
42
|
-
|
42
|
+
```ruby
|
43
|
+
AWS::CF::Signer.sign_url 'http://mydomain/path/to/my/content'
|
44
|
+
```
|
43
45
|
|
44
46
|
or
|
45
47
|
|
46
|
-
|
48
|
+
```ruby
|
49
|
+
AWS::CF::Signer.sign_url 'http://mydomain/path/to/my/content', expires: Time.now + 600
|
50
|
+
```
|
47
51
|
|
48
52
|
Streaming paths can be signed with the `sign_path` method.
|
49
53
|
|
50
|
-
|
54
|
+
```ruby
|
55
|
+
AWS::CF::Signer.sign_path 'path/to/my/content'
|
56
|
+
```
|
51
57
|
|
52
58
|
or
|
53
59
|
|
54
|
-
|
60
|
+
```ruby
|
61
|
+
AWS::CF::Signer.sign_path 'path/to/my/content', expires: Time.now + 600
|
62
|
+
```
|
55
63
|
|
64
|
+
Raw parameters can be get with the `signed_params` method. See [commit message](https://github.com/leonelgalan/cloudfront-signer/commit/fedcc3182e32133e4bd0ad0b79c0106168896c91) for additional details.
|
65
|
+
|
66
|
+
```ruby
|
67
|
+
AWS::CF::Signer.sign_params 'path/to/my/content'
|
68
|
+
```
|
56
69
|
|
57
70
|
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.
|
58
71
|
|
@@ -61,25 +74,30 @@ Both `sign_url` and `sign_path` have _safe_ versions that HTML encode the result
|
|
61
74
|
|
62
75
|
See Example Custom Policy 1 at above AWS doc link
|
63
76
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
77
|
+
```ruby
|
78
|
+
url = AWS::CF::Signer.sign_url 'http://d604721fxaaqy9.cloudfront.net/training/orientation.avi',
|
79
|
+
expires: 'Sat, 14 Nov 2009 22:20:00 GMT',
|
80
|
+
resource: 'http://d604721fxaaqy9.cloudfront.net/training/*',
|
81
|
+
ip_range: '145.168.143.0/24'
|
82
|
+
)
|
83
|
+
```
|
69
84
|
|
70
85
|
See Example Custom Policy 2 at above AWS doc link
|
71
86
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
87
|
+
```ruby
|
88
|
+
AWS::CF::Signer.sign_url 'http://d84l721fxaaqy9.cloudfront.net/downloads/pictures.tgz',
|
89
|
+
starting: 'Thu, 30 Apr 2009 06:43:10 GMT',
|
90
|
+
expires: 'Fri, 16 Oct 2009 06:31:56 GMT',
|
91
|
+
resource: 'http://*',
|
92
|
+
ip_range: '216.98.35.1/32'
|
93
|
+
```
|
78
94
|
|
79
95
|
You can also pass in a path to a policy file. This will supersede any other policy options
|
80
96
|
|
81
|
-
|
82
|
-
|
97
|
+
```ruby
|
98
|
+
AWS::CF::Signer.sign_url 'http://d84l721fxaaqy9.cloudfront.net/downloads/pictures.tgz',
|
99
|
+
policy_file: '/path/to/policy/file.txt'
|
100
|
+
```
|
83
101
|
|
84
102
|
## Patches/Pull Requests
|
85
103
|
|
@@ -90,18 +108,12 @@ You can also pass in a path to a policy file. This will supersede any other poli
|
|
90
108
|
* Send me a pull request. Bonus points for topic branches.
|
91
109
|
|
92
110
|
## Attributions
|
111
|
+
Hat tip to [Anthony Bouch](https://github.com/58bits) for contributing to Dylan's effort. Only reading both gem's code I was able to figure out the signing needed for the newly introduced signed cookies.
|
93
112
|
|
94
|
-
|
95
|
-
|
96
|
-
* [http://stackoverflow.com/questions/2632457/create-signed-urls-for-cloudfront-with-ruby](http://stackoverflow.com/questions/2632457/create-signed-urls-for-cloudfront-with-ruby)
|
97
|
-
* [http://stackoverflow.com/users/315829/ben-wiseley](http://stackoverflow.com/users/315829/ben-wiseley)
|
98
|
-
* [http://stackoverflow.com/users/267804/blaz-lipuscek](http://stackoverflow.com/users/267804/blaz-lipuscek)
|
99
|
-
* [http://stackoverflow.com/users/327914/manuel-m](http://stackoverflow.com/users/327914/manuel-m)
|
100
|
-
|
101
|
-
Note: Dylan blazed a trail here - however, after several attempts, I was unable to contact Dylan in order to suggest that we combine our efforts to produce a single gem - hence the re-write and new gem here.
|
113
|
+
> Dylan blazed a trail here - however, after several attempts, I was unable to contact Dylan in order to suggest that we combine our efforts to produce a single gem - hence the re-write and new gem here. - **Anthony Bouch**
|
102
114
|
|
115
|
+
Parts of signing code taken from a question on [Stack Overflow](http://stackoverflow.com/questions/2632457/create-signed-urls-for-cloudfront-with-ruby) asked by [Ben Wiseley](http://stackoverflow.com/users/315829/ben-wiseley), and answered by [Blaz Lipuscek](http://stackoverflow.com/users/267804/blaz-lipuscek) and [Manual M](http://stackoverflow.com/users/327914/manuel-m).
|
103
116
|
|
104
|
-
License
|
105
|
-
-------
|
117
|
+
## License
|
106
118
|
|
107
|
-
cloudfront-signer is distributed under the MIT License, portions copyright ©
|
119
|
+
cloudfront-signer is distributed under the MIT License, portions copyright © 2015 Dylan Vaughn, STL, Anthony Bouch, Leonel Galán
|
data/Rakefile
CHANGED
@@ -1,11 +1,10 @@
|
|
1
1
|
require 'bundler/gem_tasks'
|
2
2
|
|
3
|
-
require
|
3
|
+
require 'rspec/core/rake_task'
|
4
4
|
|
5
5
|
RSpec::Core::RakeTask.new(:spec) do |t|
|
6
6
|
t.pattern = 'spec/**/*_spec.rb'
|
7
|
-
t.rspec_opts = [
|
7
|
+
t.rspec_opts = ['--colour', '--format', 'nested']
|
8
8
|
end
|
9
9
|
|
10
|
-
task :
|
11
|
-
|
10
|
+
task default: :spec
|
data/cloudfront-signer.gemspec
CHANGED
@@ -1,22 +1,27 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
|
3
|
-
require
|
2
|
+
$LOAD_PATH.push File.expand_path('../lib', __FILE__)
|
3
|
+
require 'cloudfront-signer/version'
|
4
4
|
|
5
5
|
Gem::Specification.new do |s|
|
6
|
-
s.name
|
7
|
-
s.version
|
8
|
-
s.authors
|
9
|
-
s.email
|
10
|
-
s.homepage
|
11
|
-
s.summary
|
12
|
-
|
6
|
+
s.name = 'cloudfront-signer'
|
7
|
+
s.version = AWS::CF::VERSION
|
8
|
+
s.authors = ['Anthony Bouch', 'Leonel Galan']
|
9
|
+
s.email = ['tony@58bits.com', 'leonelgalan@gmail.com']
|
10
|
+
s.homepage = 'http://github.com/leonelgalan/cloudfront-signer'
|
11
|
+
s.summary = 'A gem to sign url and stream paths for Amazon CloudFront ' \
|
12
|
+
'private content.'
|
13
|
+
s.description = 'A gem to sign url and stream paths for Amazon CloudFront ' \
|
14
|
+
'private content. Includes specific signing methods for ' \
|
15
|
+
"both url and streaming paths, including html 'safe' " \
|
16
|
+
'escaped versions of each.'
|
17
|
+
s.license = 'MIT'
|
13
18
|
|
14
|
-
s.rubyforge_project =
|
15
|
-
|
16
|
-
s.add_development_dependency
|
17
|
-
|
18
|
-
s.
|
19
|
-
s.
|
20
|
-
|
21
|
-
s.require_paths = [
|
19
|
+
s.rubyforge_project = 'cloudfront-signer'
|
20
|
+
s.add_development_dependency 'rspec'
|
21
|
+
s.add_development_dependency 'codeclimate-test-reporter'
|
22
|
+
s.files = `git ls-files`.split("\n")
|
23
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
24
|
+
s.executables = `git ls-files -- bin/*`.split("\n")
|
25
|
+
.map { |f| File.basename f }
|
26
|
+
s.require_paths = ['lib']
|
22
27
|
end
|
data/lib/cloudfront-signer.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
require 'openssl'
|
4
4
|
require 'time'
|
5
5
|
require 'base64'
|
6
|
-
require
|
6
|
+
require 'cloudfront-signer/version'
|
7
7
|
require 'json'
|
8
8
|
|
9
9
|
module AWS
|
@@ -11,9 +11,8 @@ module AWS
|
|
11
11
|
class Signer
|
12
12
|
# Public non-inheritable class accessors
|
13
13
|
class << self
|
14
|
-
|
15
|
-
#
|
16
|
-
# been inferred from the key_path
|
14
|
+
# Public: Provides a configuration option to set the key_pair_id if it
|
15
|
+
# has not been inferred from the key_path
|
17
16
|
#
|
18
17
|
# Examples
|
19
18
|
#
|
@@ -34,12 +33,16 @@ module AWS
|
|
34
33
|
#
|
35
34
|
# Returns nothing.
|
36
35
|
def key_path=(path)
|
37
|
-
|
36
|
+
unless File.exist?(path)
|
37
|
+
fail ArgumentError,
|
38
|
+
"The signing key could not be found at #{path}"
|
39
|
+
end
|
38
40
|
@key_path = path
|
39
|
-
self.key=
|
41
|
+
self.key = File.readlines(path).join('')
|
40
42
|
end
|
41
43
|
|
42
|
-
# Public: Provides a configuration option to set the key directly as a
|
44
|
+
# Public: Provides a configuration option to set the key directly as a
|
45
|
+
# string e.g. as an ENV var
|
43
46
|
#
|
44
47
|
# Examples
|
45
48
|
#
|
@@ -54,12 +57,10 @@ module AWS
|
|
54
57
|
# Public: Provides an accessor to the key_path
|
55
58
|
#
|
56
59
|
# Returns a String value indicating the current setting
|
57
|
-
|
58
|
-
@key_path
|
59
|
-
end
|
60
|
-
|
60
|
+
attr_reader :key_path
|
61
61
|
|
62
|
-
# Public: Provides a configuration option that sets the default_expires
|
62
|
+
# Public: Provides a configuration option that sets the default_expires
|
63
|
+
# in milliseconds
|
63
64
|
#
|
64
65
|
# Examples
|
65
66
|
#
|
@@ -68,9 +69,7 @@ module AWS
|
|
68
69
|
# end
|
69
70
|
#
|
70
71
|
# Returns nothing.
|
71
|
-
|
72
|
-
@default_expires = value
|
73
|
-
end
|
72
|
+
attr_writer :default_expires
|
74
73
|
|
75
74
|
# Public: Provides an accessor to the default_expires value
|
76
75
|
#
|
@@ -79,7 +78,6 @@ module AWS
|
|
79
78
|
@default_expires ||= 3600
|
80
79
|
end
|
81
80
|
|
82
|
-
|
83
81
|
private
|
84
82
|
|
85
83
|
# Private: Provides an accessor to the RSA key value
|
@@ -104,16 +102,20 @@ module AWS
|
|
104
102
|
#
|
105
103
|
# Returns nothing.
|
106
104
|
def self.configure
|
107
|
-
|
108
105
|
yield self if block_given?
|
109
106
|
|
110
|
-
|
107
|
+
unless key_path || private_key
|
108
|
+
fail ArgumentError,
|
109
|
+
'You must supply the path to a PEM format RSA key pair.'
|
110
|
+
end
|
111
111
|
|
112
112
|
unless @key_pair_id
|
113
|
-
@key_pair_id = extract_key_pair_id(
|
114
|
-
|
113
|
+
@key_pair_id = extract_key_pair_id(key_path)
|
114
|
+
fail ArgumentError,
|
115
|
+
'The Cloudfront signing key id could not be inferred from ' \
|
116
|
+
"#{key_path}. Please supply the key pair id as a " \
|
117
|
+
'configuration argument.' unless @key_pair_id
|
115
118
|
end
|
116
|
-
|
117
119
|
end
|
118
120
|
|
119
121
|
# Public: Provides a configuration check method which tests to see
|
@@ -121,55 +123,58 @@ module AWS
|
|
121
123
|
#
|
122
124
|
# Returns a Boolean value indicating that settings are present.
|
123
125
|
def self.is_configured?
|
124
|
-
(
|
126
|
+
(key_pair_id.nil? || private_key.nil?) ? false : true
|
125
127
|
end
|
126
128
|
|
127
|
-
# Public: Sign a url - encoding any spaces in the url before signing.
|
128
|
-
# stipulates that signed URLs must not contain spaces (as
|
129
|
-
# paths/filenames which CAN contain spaces).
|
129
|
+
# Public: Sign a url - encoding any spaces in the url before signing.
|
130
|
+
# CloudFront stipulates that signed URLs must not contain spaces (as
|
131
|
+
# opposed to stream paths/filenames which CAN contain spaces).
|
130
132
|
#
|
131
133
|
# Returns a String
|
132
134
|
def self.sign_url(subject, policy_options = {})
|
133
|
-
|
135
|
+
sign subject, { remove_spaces: true }, policy_options
|
134
136
|
end
|
135
137
|
|
136
|
-
|
137
|
-
|
138
138
|
# Public: Sign a url (as above) and HTML encode the result.
|
139
139
|
#
|
140
140
|
# Returns a String
|
141
141
|
def self.sign_url_safe(subject, policy_options = {})
|
142
|
-
|
142
|
+
sign subject, { remove_spaces: true, html_escape: true }, policy_options
|
143
143
|
end
|
144
144
|
|
145
|
-
# Public: Sign a stream path part or filename (spaces are allowed in
|
146
|
-
# and so are not removed).
|
145
|
+
# Public: Sign a stream path part or filename (spaces are allowed in
|
146
|
+
# stream paths and so are not removed).
|
147
147
|
#
|
148
148
|
# Returns a String
|
149
|
-
def self.sign_path(subject, policy_options ={})
|
150
|
-
|
149
|
+
def self.sign_path(subject, policy_options = {})
|
150
|
+
sign subject, { remove_spaces: false }, policy_options
|
151
151
|
end
|
152
152
|
|
153
153
|
# Public: Sign a stream path or filename and HTML encode the result.
|
154
154
|
#
|
155
155
|
# Returns a String
|
156
|
-
def self.sign_path_safe(subject, policy_options ={})
|
157
|
-
|
156
|
+
def self.sign_path_safe(subject, policy_options = {})
|
157
|
+
sign subject,
|
158
|
+
{ remove_spaces: false, html_escape: true },
|
159
|
+
policy_options
|
158
160
|
end
|
159
161
|
|
160
|
-
# Public: Builds a signed url or stream resource name with optional
|
161
|
-
# policy options
|
162
|
+
# Public: Builds a signed url or stream resource name with optional
|
163
|
+
# configuration and policy options
|
162
164
|
#
|
163
165
|
# Returns a String
|
164
166
|
def self.sign(subject, configuration_options = {}, policy_options = {})
|
165
|
-
# If the url or stream path already has a query string parameter -
|
167
|
+
# If the url or stream path already has a query string parameter -
|
168
|
+
# append to that.
|
166
169
|
separator = subject =~ /\?/ ? '&' : '?'
|
167
170
|
|
168
|
-
if configuration_options[:remove_spaces]
|
169
|
-
subject.gsub!(/\s/, "%20")
|
170
|
-
end
|
171
|
+
subject.gsub!(/\s/, '%20') if configuration_options[:remove_spaces]
|
171
172
|
|
172
|
-
result = subject +
|
173
|
+
result = subject +
|
174
|
+
separator +
|
175
|
+
signed_params(subject, policy_options).collect do |key, value|
|
176
|
+
"#{key}=#{value}"
|
177
|
+
end.join('&')
|
173
178
|
|
174
179
|
if configuration_options[:html_escape]
|
175
180
|
return html_encode(result)
|
@@ -178,8 +183,8 @@ module AWS
|
|
178
183
|
end
|
179
184
|
end
|
180
185
|
|
181
|
-
# Public: Sign a subject url or stream resource name with optional policy
|
182
|
-
# It returns raw params to be used in urls or cookies
|
186
|
+
# Public: Sign a subject url or stream resource name with optional policy
|
187
|
+
# options. It returns raw params to be used in urls or cookies
|
183
188
|
#
|
184
189
|
# Returns a Hash
|
185
190
|
def self.signed_params(subject, policy_options = {})
|
@@ -189,12 +194,13 @@ module AWS
|
|
189
194
|
policy = IO.read(policy_options[:policy_file])
|
190
195
|
result['Policy'] = encode_policy(policy)
|
191
196
|
else
|
192
|
-
policy_options[:expires] = epoch_time(policy_options[:expires] ||
|
197
|
+
policy_options[:expires] = epoch_time(policy_options[:expires] ||
|
198
|
+
Time.now + default_expires)
|
193
199
|
|
194
200
|
if policy_options.keys.size <= 1
|
195
201
|
# Canned Policy - shorter URL
|
196
202
|
expires_at = policy_options[:expires]
|
197
|
-
policy = %
|
203
|
+
policy = %{{"Statement":[{"Resource":"#{subject}","Condition":{"DateLessThan":{"AWS:EpochTime":#{expires_at}}}}]}}
|
198
204
|
result['Expires'] = expires_at
|
199
205
|
else
|
200
206
|
# Custom Policy
|
@@ -208,13 +214,23 @@ module AWS
|
|
208
214
|
'Key-Pair-Id' => @key_pair_id
|
209
215
|
end
|
210
216
|
|
211
|
-
# Private helper methods
|
212
217
|
private
|
213
218
|
|
214
219
|
def self.generate_custom_policy(resource, options)
|
215
|
-
conditions = {
|
216
|
-
|
217
|
-
|
220
|
+
conditions = {
|
221
|
+
'DateLessThan' => {
|
222
|
+
'AWS:EpochTime' => epoch_time(options[:expires])
|
223
|
+
}
|
224
|
+
}
|
225
|
+
|
226
|
+
conditions['DateGreaterThan'] = {
|
227
|
+
'AWS:EpochTime' => epoch_time(options[:starting])
|
228
|
+
} if options[:starting]
|
229
|
+
|
230
|
+
conditions['IpAddress'] = {
|
231
|
+
'AWS:SourceIp' => options[:ip_range]
|
232
|
+
} if options[:ip_range]
|
233
|
+
|
218
234
|
{
|
219
235
|
'Statement' => [{
|
220
236
|
'Resource' => resource,
|
@@ -228,28 +244,33 @@ module AWS
|
|
228
244
|
when String then Time.parse(timelike).to_i
|
229
245
|
when Time then timelike.to_i
|
230
246
|
when Fixnum then timelike
|
231
|
-
else
|
247
|
+
else fail ArgumentError,
|
248
|
+
'Invalid argument - String, Fixnum or Time required - ' \
|
249
|
+
"#{timelike.class} passed."
|
232
250
|
end
|
233
251
|
end
|
234
252
|
|
235
253
|
def self.encode_policy(policy)
|
236
|
-
url_encode
|
254
|
+
url_encode Base64.encode64(policy)
|
237
255
|
end
|
238
256
|
|
239
257
|
def self.create_signature(policy)
|
240
|
-
url_encode
|
258
|
+
url_encode Base64.encode64(
|
259
|
+
private_key.sign(OpenSSL::Digest::SHA1.new, (policy))
|
260
|
+
)
|
241
261
|
end
|
242
262
|
|
243
263
|
def self.extract_key_pair_id(key_path)
|
244
|
-
File.basename(key_path) =~ /^pk-(.*).pem$/ ?
|
264
|
+
File.basename(key_path) =~ /^pk-(.*).pem$/ ? Regexp.last_match[1] : nil
|
245
265
|
end
|
246
266
|
|
247
267
|
def self.url_encode(s)
|
248
|
-
s.gsub('+','-').gsub('=','_').gsub('/','~').gsub(/\n/,
|
268
|
+
s.gsub('+', '-').gsub('=', '_').gsub('/', '~').gsub(/\n/, '')
|
269
|
+
.gsub(' ', '')
|
249
270
|
end
|
250
271
|
|
251
272
|
def self.html_encode(s)
|
252
|
-
|
273
|
+
s.gsub('?', '%3F').gsub('=', '%3D').gsub('&', '%26')
|
253
274
|
end
|
254
275
|
end
|
255
276
|
end
|
@@ -3,12 +3,12 @@ require 'rails/generators'
|
|
3
3
|
|
4
4
|
module Cloudfront
|
5
5
|
class InstallGenerator < Rails::Generators::Base
|
6
|
-
source_root File.expand_path(
|
7
|
-
|
8
|
-
desc
|
6
|
+
source_root File.expand_path('../templates', __FILE__)
|
7
|
+
|
8
|
+
desc 'This generator creates an initializer file at config/initializers'
|
9
9
|
def add_initializer
|
10
|
-
template
|
10
|
+
template 'cloudfront-signer.rb',
|
11
|
+
'config/initializers/cloudfront-signer.rb'
|
11
12
|
end
|
12
13
|
end
|
13
14
|
end
|
14
|
-
|
@@ -1,6 +1,6 @@
|
|
1
1
|
AWS::CF::Signer.configure do |config|
|
2
2
|
config.key_path = '/path/to/keyfile.pem'
|
3
|
-
# config.key = ENV.fetch('PRIVATE_KEY')
|
4
|
-
config.key_pair_id =
|
3
|
+
# or config.key = ENV.fetch('PRIVATE_KEY')
|
4
|
+
config.key_pair_id = 'XXYYZZ'
|
5
5
|
config.default_expires = 3600
|
6
6
|
end
|
data/spec/signer_spec.rb
CHANGED
@@ -2,10 +2,12 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe AWS::CF::Signer do
|
4
4
|
let(:key_pair_id) { 'APKAIKUROOUNR2BAFUUU' }
|
5
|
-
let(:key_path)
|
6
|
-
|
5
|
+
let(:key_path) do
|
6
|
+
File.expand_path File.dirname(__FILE__) + "/keys/pk-#{key_pair_id}.pem"
|
7
|
+
end
|
8
|
+
let(:key) { File.readlines(key_path).join '' }
|
7
9
|
|
8
|
-
context
|
10
|
+
context 'configured with key and key_pair_id' do
|
9
11
|
before do
|
10
12
|
AWS::CF::Signer.configure do |config|
|
11
13
|
config.key_pair_id = key_pair_id
|
@@ -13,98 +15,92 @@ describe AWS::CF::Signer do
|
|
13
15
|
end
|
14
16
|
end
|
15
17
|
|
16
|
-
it
|
17
|
-
AWS::CF::Signer.is_configured
|
18
|
+
it 'should be configured' do
|
19
|
+
expect(AWS::CF::Signer.is_configured?).to be true
|
18
20
|
end
|
19
21
|
|
20
|
-
it
|
21
|
-
AWS::CF::Signer.send(:private_key).
|
22
|
+
it 'sets the private_key' do
|
23
|
+
expect(AWS::CF::Signer.send(:private_key)).to(
|
24
|
+
be_an_instance_of OpenSSL::PKey::RSA
|
25
|
+
)
|
22
26
|
end
|
23
27
|
|
24
|
-
it
|
25
|
-
url =
|
28
|
+
it 'should expire in one hour by default' do
|
29
|
+
url = 'http://somedomain.com/sign me'
|
26
30
|
result = AWS::CF::Signer.sign_url(url)
|
27
|
-
get_query_value(result, 'Expires').to_i.
|
31
|
+
expect(get_query_value(result, 'Expires').to_i).to(
|
32
|
+
eq Time.now.to_i + 3600
|
33
|
+
)
|
28
34
|
end
|
29
35
|
end
|
30
36
|
|
31
|
-
context
|
32
|
-
|
37
|
+
context 'configured with key_path' do
|
33
38
|
before(:each) do
|
34
39
|
AWS::CF::Signer.configure do |config|
|
35
40
|
config.key_path = key_path
|
36
|
-
#config.key_pair_id = "XXYYZZ"
|
37
|
-
#config.default_expires = 3600
|
38
41
|
end
|
39
42
|
end
|
40
43
|
|
41
|
-
describe
|
42
|
-
|
43
|
-
|
44
|
-
AWS::CF::Signer.is_configured?.should eql(true)
|
44
|
+
describe 'before default use' do
|
45
|
+
it 'should be configured' do
|
46
|
+
expect(AWS::CF::Signer.is_configured?).to be true
|
45
47
|
end
|
46
48
|
|
47
|
-
it
|
48
|
-
AWS::CF::Signer.send(:private_key).
|
49
|
+
it 'sets the private_key' do
|
50
|
+
expect(AWS::CF::Signer.send(:private_key)).to(
|
51
|
+
be_an_instance_of OpenSSL::PKey::RSA
|
52
|
+
)
|
49
53
|
end
|
50
54
|
|
51
|
-
it
|
52
|
-
AWS::CF::Signer.default_expires.
|
55
|
+
it 'should expire urls and paths in one hour by default' do
|
56
|
+
expect(AWS::CF::Signer.default_expires).to eq 3600
|
53
57
|
end
|
54
58
|
|
55
|
-
it
|
59
|
+
it 'should optionally be configured to expire urls and paths' do
|
56
60
|
AWS::CF::Signer.default_expires = 600
|
57
|
-
AWS::CF::Signer.default_expires.
|
61
|
+
expect(AWS::CF::Signer.default_expires).to eq 600
|
58
62
|
AWS::CF::Signer.default_expires = nil
|
59
63
|
end
|
60
64
|
end
|
61
65
|
|
62
|
-
describe
|
63
|
-
|
64
|
-
|
65
|
-
url
|
66
|
-
result = AWS::CF::Signer.sign_url(url)
|
67
|
-
(result =~ /\s/).should be_nil
|
66
|
+
describe 'when signing a url' do
|
67
|
+
it 'should remove spaces from the url' do
|
68
|
+
url = 'http://somedomain.com/sign me'
|
69
|
+
expect(AWS::CF::Signer.sign_url(url)).not_to match(/\s/)
|
68
70
|
end
|
69
71
|
|
70
|
-
it
|
71
|
-
url =
|
72
|
-
|
73
|
-
(result =~ /\?/).should_not be_nil
|
74
|
-
(result =~ /=/).should_not be_nil
|
75
|
-
(result =~ /&/).should_not be_nil
|
72
|
+
it 'should not html encode the signed url by default' do
|
73
|
+
url = 'http://somedomain.com/someresource?opt1=one&opt2=two'
|
74
|
+
expect(AWS::CF::Signer.sign_url(url)).to match(/\?|=|&/)
|
76
75
|
end
|
77
76
|
|
78
|
-
it
|
79
|
-
url =
|
80
|
-
|
81
|
-
(result =~ /\?/).should be_nil
|
82
|
-
(result =~ /=/).should be_nil
|
83
|
-
(result =~ /&/).should be_nil
|
77
|
+
it 'should optionally html encode the signed url' do
|
78
|
+
url = 'http://somedomain.com/someresource?opt1=one&opt2=two'
|
79
|
+
expect(AWS::CF::Signer.sign_url_safe(url)).not_to match(/\?|=|&/)
|
84
80
|
end
|
85
81
|
|
86
|
-
it
|
87
|
-
url =
|
82
|
+
it 'should expire in one hour by default' do
|
83
|
+
url = 'http://somedomain.com/sign me'
|
88
84
|
result = AWS::CF::Signer.sign_url(url)
|
89
|
-
get_query_value(result, 'Expires').to_i.
|
85
|
+
expect(get_query_value(result, 'Expires').to_i).to(
|
86
|
+
eq Time.now.to_i + 3600
|
87
|
+
)
|
90
88
|
end
|
91
89
|
|
92
|
-
it
|
93
|
-
url =
|
94
|
-
result = AWS::CF::Signer.sign_url(url, :
|
95
|
-
get_query_value(result, 'Expires').to_i.
|
90
|
+
it 'should optionally expire in ten minutes' do
|
91
|
+
url = 'http://somedomain.com/sign me'
|
92
|
+
result = AWS::CF::Signer.sign_url(url, expires: Time.now + 600)
|
93
|
+
expect(get_query_value(result, 'Expires').to_i).to(
|
94
|
+
eq Time.now.to_i + 600
|
95
|
+
)
|
96
96
|
end
|
97
|
-
|
98
97
|
end
|
99
98
|
|
100
|
-
describe
|
101
|
-
|
102
|
-
|
103
|
-
path
|
104
|
-
result = AWS::CF::Signer.sign_path(path)
|
105
|
-
(result =~ /\s/).should_not be_nil
|
99
|
+
describe 'when signing a path' do
|
100
|
+
it 'should not remove spaces from the path' do
|
101
|
+
path = '/someprefix/sign me'
|
102
|
+
expect(AWS::CF::Signer.sign_path(path)).to match(/\s/)
|
106
103
|
end
|
107
|
-
|
108
104
|
end
|
109
105
|
end
|
110
106
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
require 'codeclimate-test-reporter'
|
2
|
+
CodeClimate::TestReporter.start
|
3
|
+
|
1
4
|
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
5
|
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
3
6
|
|
@@ -5,16 +8,13 @@ require 'rspec'
|
|
5
8
|
require 'cloudfront-signer'
|
6
9
|
|
7
10
|
def get_query_value(url, key)
|
8
|
-
query_string = url.slice((url =~ /\?/) + 1..-1)
|
11
|
+
query_string = url.slice((url =~ /\?/) + 1..-1)
|
9
12
|
pairs = query_string.split('&')
|
10
13
|
pairs.each do |item|
|
11
|
-
if item.start_with?(key)
|
12
|
-
return item.split('=')[1]
|
13
|
-
end
|
14
|
+
return item.split('=')[1] if item.start_with?(key)
|
14
15
|
end
|
15
16
|
end
|
16
17
|
|
17
|
-
|
18
|
-
RSpec.configure do |config|
|
18
|
+
RSpec.configure do |_config|
|
19
19
|
|
20
20
|
end
|
metadata
CHANGED
@@ -1,14 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cloudfront-signer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.2.
|
4
|
+
version: 2.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Anthony Bouch
|
8
|
+
- Leonel Galan
|
8
9
|
autorequire:
|
9
10
|
bindir: bin
|
10
11
|
cert_chain: []
|
11
|
-
date: 2015-
|
12
|
+
date: 2015-05-18 00:00:00.000000000 Z
|
12
13
|
dependencies:
|
13
14
|
- !ruby/object:Gem::Dependency
|
14
15
|
name: rspec
|
@@ -24,17 +25,33 @@ dependencies:
|
|
24
25
|
- - ">="
|
25
26
|
- !ruby/object:Gem::Version
|
26
27
|
version: '0'
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: codeclimate-test-reporter
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '0'
|
35
|
+
type: :development
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '0'
|
27
42
|
description: A gem to sign url and stream paths for Amazon CloudFront private content.
|
28
43
|
Includes specific signing methods for both url and streaming paths, including html
|
29
|
-
'safe'
|
44
|
+
'safe' escaped versions of each.
|
30
45
|
email:
|
31
46
|
- tony@58bits.com
|
47
|
+
- leonelgalan@gmail.com
|
32
48
|
executables: []
|
33
49
|
extensions: []
|
34
50
|
extra_rdoc_files: []
|
35
51
|
files:
|
36
52
|
- ".gitignore"
|
37
53
|
- ".rspec"
|
54
|
+
- ".travis.yml"
|
38
55
|
- ChangeLog.markdown
|
39
56
|
- Gemfile
|
40
57
|
- LICENSE
|
@@ -49,8 +66,9 @@ files:
|
|
49
66
|
- spec/keys/rsa-APKAIKUROOUNR2BAFUUU.pem
|
50
67
|
- spec/signer_spec.rb
|
51
68
|
- spec/spec_helper.rb
|
52
|
-
homepage: http://github.com/
|
53
|
-
licenses:
|
69
|
+
homepage: http://github.com/leonelgalan/cloudfront-signer
|
70
|
+
licenses:
|
71
|
+
- MIT
|
54
72
|
metadata: {}
|
55
73
|
post_install_message:
|
56
74
|
rdoc_options: []
|
@@ -77,3 +95,4 @@ test_files:
|
|
77
95
|
- spec/keys/rsa-APKAIKUROOUNR2BAFUUU.pem
|
78
96
|
- spec/signer_spec.rb
|
79
97
|
- spec/spec_helper.rb
|
98
|
+
has_rdoc:
|