cdn 0.1.2
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 +7 -0
- data/.gitignore +18 -0
- data/Gemfile +10 -0
- data/Gemfile.lock +35 -0
- data/README.md +48 -0
- data/Rakefile +15 -0
- data/cdn.gemspec +26 -0
- data/lib/cdn.rb +78 -0
- data/lib/cdn/configuration.rb +14 -0
- data/lib/cdn/providers/choopa.rb +27 -0
- data/lib/cdn/providers/cloudfront.rb +37 -0
- data/lib/cdn/providers/swiftwill.rb +47 -0
- data/lib/cdn/version.rb +3 -0
- data/spec/cdn_spec.rb +50 -0
- data/spec/pk-APKAIBJYP63EELSELVPQ.pem +15 -0
- data/spec/providers/choopa_spec.rb +28 -0
- data/spec/providers/cloudfront_spec.rb +28 -0
- data/spec/providers/swiftwill_spec.rb +56 -0
- data/spec/spec_helper.rb +22 -0
- metadata +164 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 35a4d354f84113e85ad19fa8079627adcb98af02
|
|
4
|
+
data.tar.gz: eecc6b5b759fecb65e8ef1374da6f8c578277da6
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 23f852bb011c006223e38e3fb431125bff42a1459da472346cd6ec461c7ebbad1443602340cbf15668014fe5850e91ffcccd2bcf9041cb356a006b9c639eafe8
|
|
7
|
+
data.tar.gz: cba29e963508e0601580d05a2ed4da0475545015c5d50b9ed2d36c9ef608d41e722991d89408a9abc3d3cd97aa070ac164ed29ff0762e7379ee52879563e9452
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
GEM
|
|
2
|
+
remote: https://rubygems.org/
|
|
3
|
+
specs:
|
|
4
|
+
activesupport (4.0.0)
|
|
5
|
+
i18n (~> 0.6, >= 0.6.4)
|
|
6
|
+
minitest (~> 4.2)
|
|
7
|
+
multi_json (~> 1.3)
|
|
8
|
+
thread_safe (~> 0.1)
|
|
9
|
+
tzinfo (~> 0.3.37)
|
|
10
|
+
atomic (1.1.10)
|
|
11
|
+
aws_cf_signer (0.1.1)
|
|
12
|
+
i18n (0.6.4)
|
|
13
|
+
minitest (4.7.5)
|
|
14
|
+
multi_json (1.7.7)
|
|
15
|
+
rake (11.1.2)
|
|
16
|
+
rspec-core (3.4.4)
|
|
17
|
+
rspec-support (~> 3.4.0)
|
|
18
|
+
rspec-support (3.4.1)
|
|
19
|
+
thread_safe (0.1.0)
|
|
20
|
+
atomic
|
|
21
|
+
timecop (0.6.1)
|
|
22
|
+
tzinfo (0.3.37)
|
|
23
|
+
|
|
24
|
+
PLATFORMS
|
|
25
|
+
ruby
|
|
26
|
+
|
|
27
|
+
DEPENDENCIES
|
|
28
|
+
activesupport
|
|
29
|
+
aws_cf_signer
|
|
30
|
+
rake
|
|
31
|
+
rspec-core
|
|
32
|
+
timecop
|
|
33
|
+
|
|
34
|
+
BUNDLED WITH
|
|
35
|
+
1.10.5
|
data/README.md
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# CDN Gem
|
|
2
|
+
|
|
3
|
+
Provides an interface to various cdn services.
|
|
4
|
+
|
|
5
|
+
## Configure
|
|
6
|
+
```ruby
|
|
7
|
+
CDN.configure do |config|
|
|
8
|
+
config.enabled = true
|
|
9
|
+
config.provider = "MyProvider"
|
|
10
|
+
config.domain = "mydomain.com"
|
|
11
|
+
config.http_large_secret = "secret"
|
|
12
|
+
config.http_small_secret = "secret"
|
|
13
|
+
end
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
The CDN module uses provider classes for
|
|
17
|
+
the actual implementation of each service.
|
|
18
|
+
A provider class needs to implement two methods
|
|
19
|
+
for compliance.
|
|
20
|
+
|
|
21
|
+
```ruby
|
|
22
|
+
generate_token(file_name, options)
|
|
23
|
+
generate_url(options)
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Each of the methods should return a string
|
|
27
|
+
To use the helper, include the module.
|
|
28
|
+
|
|
29
|
+
```ruby
|
|
30
|
+
class ApplicationController
|
|
31
|
+
include CDN
|
|
32
|
+
end
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
And then simply call the helper.
|
|
36
|
+
|
|
37
|
+
```ruby
|
|
38
|
+
cdn_large_url("/path/to/my/file")
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
It can also be called with options.
|
|
42
|
+
|
|
43
|
+
```ruby
|
|
44
|
+
cdn_large_url("/path/to/my/file",
|
|
45
|
+
protocol: "https",
|
|
46
|
+
domain: "mydomain.com",
|
|
47
|
+
token: { expires_in: 1.day })
|
|
48
|
+
```
|
data/Rakefile
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
require 'bundler/gem_tasks'
|
|
2
|
+
require 'rake'
|
|
3
|
+
require 'rspec/core/rake_task'
|
|
4
|
+
|
|
5
|
+
namespace :spec do
|
|
6
|
+
RSpec::Core::RakeTask.new(:normal) do |t|
|
|
7
|
+
t.pattern ='spec/**/*_spec.rb'
|
|
8
|
+
t.rcov = false
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
desc 'RSpec tests'
|
|
13
|
+
task spec: 'spec:normal'
|
|
14
|
+
|
|
15
|
+
task default: 'spec'
|
data/cdn.gemspec
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
|
+
require 'cdn/version'
|
|
5
|
+
|
|
6
|
+
Gem::Specification.new do |s|
|
|
7
|
+
s.name = 'cdn'
|
|
8
|
+
s.version = CDN::VERSION
|
|
9
|
+
s.authors = ['Russ Smith (russ@bashme.org)']
|
|
10
|
+
s.email = 'russ@bashme.org'
|
|
11
|
+
s.homepage = 'http://github.com/sscgroup/cdn'
|
|
12
|
+
s.summary = 'CDN support for various providers.'
|
|
13
|
+
s.description = 'CDN support for various providers.'
|
|
14
|
+
|
|
15
|
+
s.files = `git ls-files -z`.split("\x0")
|
|
16
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
|
17
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
|
18
|
+
s.require_paths = ['lib']
|
|
19
|
+
s.add_dependency('activesupport', '>= 2.3.10')
|
|
20
|
+
s.add_dependency('aws_cf_signer', '~> 0.1')
|
|
21
|
+
s.add_dependency('erubis')
|
|
22
|
+
s.add_development_dependency('rake')
|
|
23
|
+
s.add_development_dependency('rspec', '~> 2.5')
|
|
24
|
+
s.add_development_dependency('yard')
|
|
25
|
+
s.add_development_dependency('timecop')
|
|
26
|
+
end
|
data/lib/cdn.rb
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
require 'openssl'
|
|
2
|
+
require 'uri'
|
|
3
|
+
require 'cgi'
|
|
4
|
+
require 'aws_cf_signer'
|
|
5
|
+
require 'active_support/core_ext'
|
|
6
|
+
require 'active_support/inflector'
|
|
7
|
+
|
|
8
|
+
require 'cdn/configuration'
|
|
9
|
+
require 'cdn/providers/choopa'
|
|
10
|
+
require 'cdn/providers/swiftwill'
|
|
11
|
+
require 'cdn/providers/cloudfront'
|
|
12
|
+
|
|
13
|
+
# CDN helper methods.
|
|
14
|
+
#
|
|
15
|
+
module CDN
|
|
16
|
+
def self.configuration
|
|
17
|
+
@configuration ||= Configuration.new
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def self.configure
|
|
21
|
+
config = configuration
|
|
22
|
+
yield(config)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def self.cdn_provider
|
|
26
|
+
"CDN::#{self.configuration.provider}".constantize
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Generates a CDN url for the path and options given.
|
|
30
|
+
# Uses the set CDN provider given in the configuration.
|
|
31
|
+
#
|
|
32
|
+
# path - Relative path for file.
|
|
33
|
+
# options - Hash of options given to the generator.
|
|
34
|
+
# Also takes a :token to customize the token generator.
|
|
35
|
+
#
|
|
36
|
+
# Returns a url.
|
|
37
|
+
|
|
38
|
+
def cdn_url(path, options = {})
|
|
39
|
+
return path unless CDN.configuration.enabled
|
|
40
|
+
|
|
41
|
+
options[:token] ||= {}
|
|
42
|
+
options[:domain] ||= CDN.configuration.domain
|
|
43
|
+
path = CDN.configuration.path_processor.call(path) if CDN.configuration.path_processor
|
|
44
|
+
|
|
45
|
+
url = CDN.cdn_provider.generate_url(
|
|
46
|
+
protocol: options[:protocol] || CDN.configuration.protocol || :http,
|
|
47
|
+
domain: options[:domain],
|
|
48
|
+
path: URI.parse(path).path,
|
|
49
|
+
token: CDN.cdn_provider.generate_token(path, options))
|
|
50
|
+
|
|
51
|
+
# Preserving any existing query params.
|
|
52
|
+
if query = URI.parse(path).query
|
|
53
|
+
query = CGI.parse(query)
|
|
54
|
+
query = query.merge(CGI.parse(url.query.to_s))
|
|
55
|
+
url.query = query.collect { |k,v| (v.empty?) ? k : "#{k}=#{v[0]}" }.join("&")
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
url.to_s
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Alias for cdn_url with :cdn_type set to large.
|
|
62
|
+
#
|
|
63
|
+
CDN.CDN.# Returns a url.
|
|
64
|
+
|
|
65
|
+
def cdn_large_url(path, options = {})
|
|
66
|
+
cdn_url(path, { :token => { :cdn_type => :large }}.merge(options))
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Alias for cdn_url with :cdn_type set to small.
|
|
70
|
+
#
|
|
71
|
+
# Returns a url.
|
|
72
|
+
|
|
73
|
+
def cdn_small_url(path, options = {})
|
|
74
|
+
options[:domain] ||= CDN.configuration.small_domain
|
|
75
|
+
options[:domain] ||= CDN.configuration.domain
|
|
76
|
+
cdn_url(path, { token: { cdn_type: :small }}.merge(options))
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
module CDN
|
|
2
|
+
class Configuration
|
|
3
|
+
attr_accessor :enabled
|
|
4
|
+
attr_accessor :provider
|
|
5
|
+
attr_accessor :domain
|
|
6
|
+
attr_accessor :small_domain
|
|
7
|
+
attr_accessor :http_large_secret
|
|
8
|
+
attr_accessor :http_small_secret
|
|
9
|
+
attr_accessor :protocol
|
|
10
|
+
attr_accessor :path_processor
|
|
11
|
+
attr_accessor :aws_pem_file
|
|
12
|
+
attr_accessor :ntp_drift_seconds
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module CDN
|
|
2
|
+
class Choopa
|
|
3
|
+
def self.generate_token(path, options = {})
|
|
4
|
+
self.new.generate_token(path, options)
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def self.generate_url(options = {})
|
|
8
|
+
((options[:protocol] == :https) ? URI::HTTPS : URI::HTTP).build(
|
|
9
|
+
host: options[:domain],
|
|
10
|
+
path: options[:path],
|
|
11
|
+
query: options[:token])
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def generate_token(path, options = {})
|
|
15
|
+
return '' if options[:token] && options[:token][:cdn_type].to_s == 'small'
|
|
16
|
+
|
|
17
|
+
options[:start] ||= 0
|
|
18
|
+
options[:expires_in] ||= 600
|
|
19
|
+
|
|
20
|
+
expires_at = (options[:expires_in].is_a?(Fixnum)) ? Time.now.to_i + options[:expires_in] : options[:expires_in].to_i
|
|
21
|
+
expires_at_hex = expires_at.to_s(16)
|
|
22
|
+
hash = Digest::MD5.hexdigest(File.join(path, CDN.configuration.http_large_secret, expires_at_hex))
|
|
23
|
+
|
|
24
|
+
"e=#{expires_at_hex}&h=#{hash}&start=#{options[:start]}"
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
module CDN
|
|
2
|
+
class Cloudfront
|
|
3
|
+
def self.generate_token(path, options = {})
|
|
4
|
+
self.new.generate_token(path, options)
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def self.generate_url(options = {})
|
|
8
|
+
((options[:protocol] == :https) ? URI::HTTPS : URI::HTTP).build(
|
|
9
|
+
host: options[:domain],
|
|
10
|
+
path: options[:path],
|
|
11
|
+
query: options[:token])
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def generate_token(path, options = {})
|
|
15
|
+
url = if options[:token] && options[:token][:cdn_type].to_s == 'small'
|
|
16
|
+
AwsCfSigner.new(CDN.configuration.aws_pem_file).sign(
|
|
17
|
+
"http://#{options[:domain]}#{path}",
|
|
18
|
+
{ ending: Time.now.utc + 1.year })
|
|
19
|
+
else
|
|
20
|
+
AwsCfSigner.new(CDN.configuration.aws_pem_file).sign(
|
|
21
|
+
"http://#{options[:domain]}#{path}",
|
|
22
|
+
self.normalize_options(options))
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
url.split('?').last
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
protected
|
|
29
|
+
|
|
30
|
+
def normalize_options(options)
|
|
31
|
+
params = {}
|
|
32
|
+
params[:ip_range] = options[:allow_ip] if options[:allow_ip]
|
|
33
|
+
params[:ending] = (options[:expires_in].is_a?(Fixnum)) ? Time.now.utc + options[:expires_in] : Time.now.utc + 1.hour
|
|
34
|
+
params
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
module CDN
|
|
2
|
+
class Swiftwill
|
|
3
|
+
def self.generate_token(path, options = {})
|
|
4
|
+
self.new.generate_token(path, options)
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def self.generate_url(options = {})
|
|
8
|
+
((options[:protocol] == :https) ? URI::HTTPS : URI::HTTP).build(
|
|
9
|
+
host: options[:domain],
|
|
10
|
+
path: options[:path],
|
|
11
|
+
query: options[:token])
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def generate_token(path, options = {})
|
|
15
|
+
return '' if options[:token] && options[:token][:cdn_type].to_s == 'small'
|
|
16
|
+
start = options[:start] || 0
|
|
17
|
+
options = self.normalize_options(options)
|
|
18
|
+
hash_string = "#{path}?" + params_string(options)
|
|
19
|
+
options.delete(:clientip)
|
|
20
|
+
params_string(options) + '&hash=0' + hash_string(hash_string, CDN.configuration.http_large_secret) + "&start=#{start}"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
protected
|
|
24
|
+
|
|
25
|
+
def hash_string(string, secret)
|
|
26
|
+
OpenSSL::HMAC.hexdigest(OpenSSL::Digest::Digest.new("sha1"), secret, string.to_s)[0..19]
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def params_string(options)
|
|
30
|
+
options.collect { |k,v| "#{k}=#{v}" }.join("&")
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def normalize_options(options)
|
|
34
|
+
params = {}
|
|
35
|
+
options[:expires_in] ||= 600
|
|
36
|
+
options[:expires_in] += ntp_drift_seconds
|
|
37
|
+
params[:clientip] = options[:allow_ip] if options[:allow_ip]
|
|
38
|
+
params[:nvb] = (Time.now - ntp_drift_seconds).utc.strftime("%Y%m%d%H%M%S")
|
|
39
|
+
params[:nva] = ((options[:expires_in].is_a?(Fixnum)) ? Time.now.utc + options[:expires_in] : options[:expires_in]).utc.strftime("%Y%m%d%H%M%S")
|
|
40
|
+
params
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def ntp_drift_seconds
|
|
44
|
+
(CDN.configuration.ntp_drift_seconds || 300).to_i
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
data/lib/cdn/version.rb
ADDED
data/spec/cdn_spec.rb
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
|
|
3
|
+
describe CDN do
|
|
4
|
+
include CDN
|
|
5
|
+
|
|
6
|
+
before do
|
|
7
|
+
CDN.configure do |config|
|
|
8
|
+
config.enabled = true
|
|
9
|
+
config.provider = "TestProvider"
|
|
10
|
+
config.domain = "localhost"
|
|
11
|
+
config.http_large_secret = "secret"
|
|
12
|
+
config.http_small_secret = "secret"
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
describe "cdn_url" do
|
|
17
|
+
it "appends to the query string if it already exists" do
|
|
18
|
+
url = cdn_url("/system/content/videos/4810/screenshot_9484_thumb.jpg?1306909458")
|
|
19
|
+
url.should match(/1306909458/)
|
|
20
|
+
url.should match(/testtoken/)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
describe "cdn_large_url" do
|
|
25
|
+
it "returns a url with a token" do
|
|
26
|
+
url = cdn_large_url("/my/file")
|
|
27
|
+
url.should match(/testtoken/)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
describe "cdn_small_url" do
|
|
32
|
+
it "returns a url with a token" do
|
|
33
|
+
url = cdn_small_url("/my/file")
|
|
34
|
+
url.should match(/testtoken/)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
context "with a custom path processor" do
|
|
39
|
+
before do
|
|
40
|
+
CDN.configure do |config|
|
|
41
|
+
config.path_processor = lambda { |p| "/modifiedpath" }
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it "modifies the path before generating the url" do
|
|
46
|
+
url = cdn_url("/my/file")
|
|
47
|
+
url.should match(/modifiedpath/)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
-----BEGIN RSA PRIVATE KEY-----
|
|
2
|
+
MIICXQIBAAKBgQDlxuuGAVeWkhnXO2RxJOztTJRnGVwK9sobO+qBdRKml2nJ1Tjs
|
|
3
|
+
3quzBnrA7pQp3gws7Jdcs0tfsQRVNzPOrGsEZFc3mLC5UTIxXvXfhDsUcB5lcodk
|
|
4
|
+
KXN9XRrJzxZETR9wIDusQ472ps+uuoe7N/dfDbU9c76JWmBOciiUgUNiNQIDAQAB
|
|
5
|
+
AoGBAMPNohBcfm4R7DFMLEh6ZefFdUTyCExTh2Bzy18sC4uoxX43072N9pSlNd/I
|
|
6
|
+
rruKu6dgqY9WPim6J+4SD3TT2pCS6vQ3oOr8X8wn1YAUI0IoBeAo1wzOMf86uaaU
|
|
7
|
+
lYAyoVmHA7gU6mplcCQVG+OBBKFwRqmkMEQ5Fr5/rTq58LxhAkEA+5e7atsmb+OX
|
|
8
|
+
sDVul0KT4NtWkoscrFE58lrtgSnxajMwjrgq7gWaU4wA/7InG9m0QXoFjzVTs4M8
|
|
9
|
+
PYGvFe8sWQJBAOnNWwHDdt3BZf23amw15MqBOrsdo2e0a7TlO2zHAJJgLiqC2pXa
|
|
10
|
+
CpbnGBqX238DmJ0ZQZalWA/ZmAJitBTWOT0CQCh9Q8EvoaDyHLBT+QdIxKm0Qtt0
|
|
11
|
+
ndmxfMTfE0ftKxfvQwpE40vJBQwbBPIhhp+5yoObEpf4eg7yuNghLb827YkCQD4d
|
|
12
|
+
9UPurrIUJAjYpknBt9ulofj80uFGqicRkExCQwCg1SMuSOzvVUjqdRj7p7GDPxTe
|
|
13
|
+
FPL1UwRDB4P6vWWb1PECQQD1/CntgLp34FikMJ/AZTAxtgBMMdyncQH2jxntn+pK
|
|
14
|
+
kh3IndxZ5SXQL+/ur7eJozisxN8isXaRK1Gq9swmEmka
|
|
15
|
+
-----END RSA PRIVATE KEY-----
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
|
|
3
|
+
describe CDN::Choopa do
|
|
4
|
+
before do
|
|
5
|
+
CDN.configure do |config|
|
|
6
|
+
config.http_large_secret = "secret"
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
context "when cdn type is small" do
|
|
11
|
+
it "returns an empty string" do
|
|
12
|
+
token = CDN::Choopa.generate_token("/my/file", :token => { :cdn_type => :small })
|
|
13
|
+
token.should == ""
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
context "when cdn type is large or nothing" do
|
|
18
|
+
it "generates a hash of 20 characters" do
|
|
19
|
+
token = CDN::Choopa.generate_token("/my/file")
|
|
20
|
+
token.should match(/h=([0-9a-z]{32})/)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it "generates a hash with an expiration" do
|
|
24
|
+
token = CDN::Choopa.generate_token("/my/file")
|
|
25
|
+
token.should match(/e=([0-9a-z]{8})/)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
|
|
3
|
+
describe CDN::Cloudfront do
|
|
4
|
+
let(:time_format) { "%Y%m%d%H%M%S" }
|
|
5
|
+
|
|
6
|
+
before do
|
|
7
|
+
CDN.configure do |config|
|
|
8
|
+
config.domain = "somedomain.cloudfront.net"
|
|
9
|
+
config.http_large_secret = "secret"
|
|
10
|
+
config.aws_pem_file = File.join(File.dirname(__FILE__), "..", "pk-APKAIBJYP63EELSELVPQ.pem")
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
context "when cdn type is small" do
|
|
15
|
+
it "returns a open ended url with an expires time" do
|
|
16
|
+
token = CDN::Cloudfront.generate_token("/my/file", :token => { :cdn_type => :small })
|
|
17
|
+
token.should match(/Expires=/)
|
|
18
|
+
token.should match(/Signature=/)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
context "when cdn type is large or nothing" do
|
|
23
|
+
it "generates a signed url" do
|
|
24
|
+
token = CDN::Cloudfront.generate_token("/my/file", allow_ip: "127.0.0.1")
|
|
25
|
+
token.should match(/Policy=/)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
|
|
3
|
+
describe CDN::Swiftwill do
|
|
4
|
+
let(:time_format) { "%Y%m%d%H%M%S" }
|
|
5
|
+
let(:ntp_drift) { 30.seconds.to_i }
|
|
6
|
+
|
|
7
|
+
before do
|
|
8
|
+
CDN.configure do |config|
|
|
9
|
+
config.http_large_secret = "secret"
|
|
10
|
+
config.ntp_drift_seconds = ntp_drift
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
context "when cdn type is small" do
|
|
15
|
+
it "returns an empty string" do
|
|
16
|
+
token = CDN::Swiftwill.generate_token("/my/file", :token => { :cdn_type => :small })
|
|
17
|
+
token.should == ""
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
context "when cdn type is large or nothing" do
|
|
22
|
+
it "generates a hash of 20 characters" do
|
|
23
|
+
token = CDN::Swiftwill.generate_token("/my/file")
|
|
24
|
+
token.should match(/hash=0([0-9A-Za-z]{20})/)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it "generates a hash based on a client ip" do
|
|
28
|
+
token = CDN::Swiftwill.generate_token("/my/file", :allow_ip => "192.168.0.1")
|
|
29
|
+
token.should match(/hash=0([0-9A-Za-z]{20})/)
|
|
30
|
+
token.should_not match(/clientip/)
|
|
31
|
+
token.should_not match(/allow_ip/)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
context "based on expiration" do
|
|
35
|
+
context "when expires_in is empty" do
|
|
36
|
+
it "generates a hash with an expiration of 0" do
|
|
37
|
+
token = CDN::Swiftwill.generate_token("/my/file")
|
|
38
|
+
token.should match(/hash=0([0-9A-Za-z]{20})/)
|
|
39
|
+
token.should match(/nvb=\d{14}/)
|
|
40
|
+
token.should match(/nva=\d{14}/)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
context "when expires_in is not empty" do
|
|
45
|
+
it "generates a hash based on the given expiration" do
|
|
46
|
+
Timecop.freeze(Time.now.utc) do
|
|
47
|
+
token = CDN::Swiftwill.generate_token("/my/file", :expires_in => (Time.now.utc + 1.day))
|
|
48
|
+
token.should match(/hash=0([0-9A-Za-z]{20})/)
|
|
49
|
+
token.should match(/nvb=#{(Time.now.utc - ntp_drift).strftime(time_format)}/)
|
|
50
|
+
token.should match(/nva=#{(Time.now.utc + ntp_drift + 1.day).strftime(time_format)}/)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
require "cdn"
|
|
2
|
+
require "timecop"
|
|
3
|
+
|
|
4
|
+
module CDN
|
|
5
|
+
class TestProvider
|
|
6
|
+
def self.generate_token(file_name, options = {})
|
|
7
|
+
"testtoken"
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def self.generate_url(options = {})
|
|
11
|
+
((options[:protocol] == :https) ? URI::HTTPS : URI::HTTP).build(
|
|
12
|
+
:host => options[:domain],
|
|
13
|
+
:path => options[:path],
|
|
14
|
+
:query => options[:token])
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
RSpec.configure do |config|
|
|
20
|
+
config.filter_run :focus => true
|
|
21
|
+
config.run_all_when_everything_filtered = true
|
|
22
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: cdn
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.2
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Russ Smith (russ@bashme.org)
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2016-05-25 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: activesupport
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ">="
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: 2.3.10
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - ">="
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: 2.3.10
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: aws_cf_signer
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '0.1'
|
|
34
|
+
type: :runtime
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '0.1'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: erubis
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - ">="
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '0'
|
|
48
|
+
type: :runtime
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - ">="
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '0'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: rake
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - ">="
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '0'
|
|
62
|
+
type: :development
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - ">="
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '0'
|
|
69
|
+
- !ruby/object:Gem::Dependency
|
|
70
|
+
name: rspec
|
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
|
72
|
+
requirements:
|
|
73
|
+
- - "~>"
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: '2.5'
|
|
76
|
+
type: :development
|
|
77
|
+
prerelease: false
|
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - "~>"
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: '2.5'
|
|
83
|
+
- !ruby/object:Gem::Dependency
|
|
84
|
+
name: yard
|
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
|
86
|
+
requirements:
|
|
87
|
+
- - ">="
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: '0'
|
|
90
|
+
type: :development
|
|
91
|
+
prerelease: false
|
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
+
requirements:
|
|
94
|
+
- - ">="
|
|
95
|
+
- !ruby/object:Gem::Version
|
|
96
|
+
version: '0'
|
|
97
|
+
- !ruby/object:Gem::Dependency
|
|
98
|
+
name: timecop
|
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
|
100
|
+
requirements:
|
|
101
|
+
- - ">="
|
|
102
|
+
- !ruby/object:Gem::Version
|
|
103
|
+
version: '0'
|
|
104
|
+
type: :development
|
|
105
|
+
prerelease: false
|
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
107
|
+
requirements:
|
|
108
|
+
- - ">="
|
|
109
|
+
- !ruby/object:Gem::Version
|
|
110
|
+
version: '0'
|
|
111
|
+
description: CDN support for various providers.
|
|
112
|
+
email: russ@bashme.org
|
|
113
|
+
executables: []
|
|
114
|
+
extensions: []
|
|
115
|
+
extra_rdoc_files: []
|
|
116
|
+
files:
|
|
117
|
+
- ".gitignore"
|
|
118
|
+
- Gemfile
|
|
119
|
+
- Gemfile.lock
|
|
120
|
+
- README.md
|
|
121
|
+
- Rakefile
|
|
122
|
+
- cdn.gemspec
|
|
123
|
+
- lib/cdn.rb
|
|
124
|
+
- lib/cdn/configuration.rb
|
|
125
|
+
- lib/cdn/providers/choopa.rb
|
|
126
|
+
- lib/cdn/providers/cloudfront.rb
|
|
127
|
+
- lib/cdn/providers/swiftwill.rb
|
|
128
|
+
- lib/cdn/version.rb
|
|
129
|
+
- spec/cdn_spec.rb
|
|
130
|
+
- spec/pk-APKAIBJYP63EELSELVPQ.pem
|
|
131
|
+
- spec/providers/choopa_spec.rb
|
|
132
|
+
- spec/providers/cloudfront_spec.rb
|
|
133
|
+
- spec/providers/swiftwill_spec.rb
|
|
134
|
+
- spec/spec_helper.rb
|
|
135
|
+
homepage: http://github.com/sscgroup/cdn
|
|
136
|
+
licenses: []
|
|
137
|
+
metadata: {}
|
|
138
|
+
post_install_message:
|
|
139
|
+
rdoc_options: []
|
|
140
|
+
require_paths:
|
|
141
|
+
- lib
|
|
142
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
143
|
+
requirements:
|
|
144
|
+
- - ">="
|
|
145
|
+
- !ruby/object:Gem::Version
|
|
146
|
+
version: '0'
|
|
147
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
148
|
+
requirements:
|
|
149
|
+
- - ">="
|
|
150
|
+
- !ruby/object:Gem::Version
|
|
151
|
+
version: '0'
|
|
152
|
+
requirements: []
|
|
153
|
+
rubyforge_project:
|
|
154
|
+
rubygems_version: 2.4.5
|
|
155
|
+
signing_key:
|
|
156
|
+
specification_version: 4
|
|
157
|
+
summary: CDN support for various providers.
|
|
158
|
+
test_files:
|
|
159
|
+
- spec/cdn_spec.rb
|
|
160
|
+
- spec/pk-APKAIBJYP63EELSELVPQ.pem
|
|
161
|
+
- spec/providers/choopa_spec.rb
|
|
162
|
+
- spec/providers/cloudfront_spec.rb
|
|
163
|
+
- spec/providers/swiftwill_spec.rb
|
|
164
|
+
- spec/spec_helper.rb
|