carrierwave_direct 1.0.0 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.travis.yml +6 -4
- data/Changelog.md +30 -0
- data/README.md +7 -7
- data/carrierwave_direct.gemspec +3 -2
- data/gemfiles/4.2.gemfile +1 -1
- data/gemfiles/5.1.gemfile +1 -1
- data/gemfiles/5.2.gemfile +13 -0
- data/lib/carrierwave_direct/action_view_extensions/form_helper.rb +1 -1
- data/lib/carrierwave_direct/form_builder.rb +30 -14
- data/lib/carrierwave_direct/mount.rb +1 -11
- data/lib/carrierwave_direct/policies/aws4_hmac_sha256.rb +93 -0
- data/lib/carrierwave_direct/policies/aws_base64_sha1.rb +57 -0
- data/lib/carrierwave_direct/policies/base.rb +21 -0
- data/lib/carrierwave_direct/test/helpers.rb +1 -1
- data/lib/carrierwave_direct/uploader.rb +42 -77
- data/lib/carrierwave_direct/validations/active_model.rb +2 -2
- data/lib/carrierwave_direct/version.rb +1 -1
- data/spec/form_builder_spec.rb +11 -8
- data/spec/mount_spec.rb +2 -2
- data/spec/orm/activerecord_spec.rb +5 -5
- data/spec/policies/aws4_hmac_sha256_spec.rb +243 -0
- data/spec/policies/aws_base64_sha1_spec.rb +229 -0
- data/spec/spec_helper.rb +5 -0
- data/spec/support/carrier_wave_config.rb +1 -0
- data/spec/test/helpers_spec.rb +3 -3
- data/spec/uploader_spec.rb +19 -37
- metadata +33 -14
- data/lib/carrierwave_direct/uploader/direct_url.rb +0 -15
- data/spec/uploader/direct_url_spec.rb +0 -26
@@ -18,7 +18,7 @@ module CarrierWaveDirect
|
|
18
18
|
options[:filename] = filename_parts.join(".")
|
19
19
|
end
|
20
20
|
options[:filename] ||= "filename"
|
21
|
-
valid_extension = uploader.
|
21
|
+
valid_extension = uploader.extension_whitelist.first if uploader.extension_whitelist
|
22
22
|
options[:extension] = options[:extension] ? options[:extension].gsub(".", "") : (valid_extension || "extension")
|
23
23
|
key = options[:base].split("/")
|
24
24
|
key.pop
|
@@ -2,7 +2,8 @@
|
|
2
2
|
|
3
3
|
require "securerandom"
|
4
4
|
require "carrierwave_direct/uploader/content_type"
|
5
|
-
require "carrierwave_direct/
|
5
|
+
require "carrierwave_direct/policies/aws_base64_sha1"
|
6
|
+
require "carrierwave_direct/policies/aws4_hmac_sha256"
|
6
7
|
|
7
8
|
module CarrierWaveDirect
|
8
9
|
module Uploader
|
@@ -24,7 +25,6 @@ module CarrierWaveDirect
|
|
24
25
|
end
|
25
26
|
|
26
27
|
include CarrierWaveDirect::Uploader::ContentType
|
27
|
-
include CarrierWaveDirect::Uploader::DirectUrl
|
28
28
|
|
29
29
|
#ensure that region returns something. Since sig v4 it is required in the signing key & credentials
|
30
30
|
def region
|
@@ -36,40 +36,27 @@ module CarrierWaveDirect
|
|
36
36
|
end
|
37
37
|
|
38
38
|
def policy(options = {}, &block)
|
39
|
-
options
|
40
|
-
options[:min_file_size] ||= min_file_size
|
41
|
-
options[:max_file_size] ||= max_file_size
|
42
|
-
|
43
|
-
@date ||= Time.now.utc.strftime("%Y%m%d")
|
44
|
-
@timestamp ||= Time.now.utc.strftime("%Y%m%dT%H%M%SZ")
|
45
|
-
@policy ||= generate_policy(options, &block)
|
39
|
+
signing_policy.policy(options, &block)
|
46
40
|
end
|
47
41
|
|
48
42
|
def date
|
49
|
-
|
43
|
+
signing_policy.date
|
50
44
|
end
|
51
45
|
|
52
46
|
def algorithm
|
53
|
-
|
47
|
+
signing_policy.algorithm
|
54
48
|
end
|
55
49
|
|
56
50
|
def credential
|
57
|
-
|
58
|
-
"#{aws_access_key_id}/#{@date}/#{region}/s3/aws4_request"
|
51
|
+
signing_policy.credential
|
59
52
|
end
|
60
53
|
|
61
54
|
def clear_policy!
|
62
|
-
|
63
|
-
@date = nil
|
64
|
-
@timestamp = nil
|
55
|
+
signing_policy.clear!
|
65
56
|
end
|
66
57
|
|
67
58
|
def signature
|
68
|
-
|
69
|
-
'sha256',
|
70
|
-
signing_key,
|
71
|
-
policy
|
72
|
-
)
|
59
|
+
signing_policy.signature
|
73
60
|
end
|
74
61
|
|
75
62
|
def url_scheme_white_list
|
@@ -80,13 +67,22 @@ module CarrierWaveDirect
|
|
80
67
|
false
|
81
68
|
end
|
82
69
|
|
70
|
+
def signing_policy_class
|
71
|
+
@signing_policy_class ||= Policies::Aws4HmacSha256
|
72
|
+
end
|
73
|
+
|
74
|
+
def signing_policy_class=(signing_policy_class)
|
75
|
+
@signing_policy_class = signing_policy_class
|
76
|
+
end
|
77
|
+
|
83
78
|
def key
|
84
79
|
return @key if @key.present?
|
85
80
|
if present?
|
86
81
|
identifier = model.send("#{mounted_as}_identifier")
|
87
|
-
self.key =
|
82
|
+
self.key = [store_dir, identifier].join("/")
|
88
83
|
else
|
89
|
-
|
84
|
+
guid = SecureRandom.uuid
|
85
|
+
@key = [store_dir, guid, FILENAME_WILDCARD].join("/")
|
90
86
|
end
|
91
87
|
@key
|
92
88
|
end
|
@@ -96,10 +92,6 @@ module CarrierWaveDirect
|
|
96
92
|
update_version_keys(:with => @key)
|
97
93
|
end
|
98
94
|
|
99
|
-
def guid
|
100
|
-
SecureRandom.uuid
|
101
|
-
end
|
102
|
-
|
103
95
|
def has_key?
|
104
96
|
key !~ /#{Regexp.escape(FILENAME_WILDCARD)}\z/
|
105
97
|
end
|
@@ -109,7 +101,7 @@ module CarrierWaveDirect
|
|
109
101
|
end
|
110
102
|
|
111
103
|
def extension_regexp
|
112
|
-
allowed_file_types =
|
104
|
+
allowed_file_types = extension_whitelist
|
113
105
|
extension_regexp = allowed_file_types.present? && allowed_file_types.any? ? "(#{allowed_file_types.join("|")})" : "\\w+"
|
114
106
|
end
|
115
107
|
|
@@ -117,27 +109,37 @@ module CarrierWaveDirect
|
|
117
109
|
unless has_key?
|
118
110
|
# Use the attached models remote url to generate a new key otherwise return nil
|
119
111
|
remote_url = model.send("remote_#{mounted_as}_url")
|
120
|
-
|
112
|
+
if remote_url
|
113
|
+
key_from_file(CarrierWave::SanitizedFile.new(remote_url).filename)
|
114
|
+
else
|
115
|
+
return
|
116
|
+
end
|
121
117
|
end
|
122
118
|
|
123
|
-
|
119
|
+
key_parts = key.split("/")
|
120
|
+
filename = key_parts.pop
|
121
|
+
guid = key_parts.pop
|
122
|
+
|
124
123
|
filename_parts = []
|
125
|
-
filename_parts
|
126
|
-
|
127
|
-
filename_parts.unshift(unique_key) if unique_key
|
124
|
+
filename_parts << guid if guid
|
125
|
+
filename_parts << filename
|
128
126
|
filename_parts.join("/")
|
129
127
|
end
|
130
128
|
|
131
|
-
|
129
|
+
def direct_fog_url
|
130
|
+
CarrierWave::Storage::Fog::File.new(self, CarrierWave::Storage::Fog.new(self), nil).public_url
|
131
|
+
end
|
132
132
|
|
133
|
-
def
|
134
|
-
|
133
|
+
def direct_fog_hash(policy_options = {})
|
134
|
+
signing_policy.direct_fog_hash(policy_options)
|
135
135
|
end
|
136
136
|
|
137
|
-
|
137
|
+
private
|
138
|
+
|
139
|
+
def key_from_file(filename)
|
138
140
|
new_key_parts = key.split("/")
|
139
141
|
new_key_parts.pop
|
140
|
-
new_key_parts <<
|
142
|
+
new_key_parts << filename
|
141
143
|
self.key = new_key_parts.join("/")
|
142
144
|
end
|
143
145
|
|
@@ -155,45 +157,8 @@ module CarrierWaveDirect
|
|
155
157
|
[for_file.chomp(extname), version_name].compact.join('_') << extname
|
156
158
|
end
|
157
159
|
|
158
|
-
def
|
159
|
-
|
160
|
-
|
161
|
-
conditions << ["starts-with", "$utf8", ""] if options[:enforce_utf8]
|
162
|
-
conditions << ["starts-with", "$key", key.sub(/#{Regexp.escape(FILENAME_WILDCARD)}\z/, "")]
|
163
|
-
conditions << {'X-Amz-Algorithm' => algorithm}
|
164
|
-
conditions << {'X-Amz-Credential' => credential}
|
165
|
-
conditions << {'X-Amz-Date' => date}
|
166
|
-
conditions << ["starts-with", "$Content-Type", ""] if will_include_content_type
|
167
|
-
conditions << {"bucket" => fog_directory}
|
168
|
-
conditions << {"acl" => acl}
|
169
|
-
|
170
|
-
if use_action_status
|
171
|
-
conditions << {"success_action_status" => success_action_status}
|
172
|
-
else
|
173
|
-
conditions << {"success_action_redirect" => success_action_redirect}
|
174
|
-
end
|
175
|
-
|
176
|
-
conditions << ["content-length-range", options[:min_file_size], options[:max_file_size]]
|
177
|
-
|
178
|
-
yield conditions if block_given?
|
179
|
-
|
180
|
-
Base64.encode64(
|
181
|
-
{
|
182
|
-
'expiration' => (Time.now + options[:expiration]).utc.iso8601,
|
183
|
-
'conditions' => conditions
|
184
|
-
}.to_json
|
185
|
-
).gsub("\n","")
|
186
|
-
end
|
187
|
-
|
188
|
-
def signing_key(options = {})
|
189
|
-
@date ||= Time.now.utc.strftime("%Y%m%d")
|
190
|
-
#AWS Signature Version 4
|
191
|
-
kDate = OpenSSL::HMAC.digest('sha256', "AWS4" + aws_secret_access_key, @date)
|
192
|
-
kRegion = OpenSSL::HMAC.digest('sha256', kDate, region)
|
193
|
-
kService = OpenSSL::HMAC.digest('sha256', kRegion, 's3')
|
194
|
-
kSigning = OpenSSL::HMAC.digest('sha256', kService, "aws4_request")
|
195
|
-
|
196
|
-
kSigning
|
160
|
+
def signing_policy
|
161
|
+
@signing_policy ||= signing_policy_class.new(self)
|
197
162
|
end
|
198
163
|
end
|
199
164
|
end
|
@@ -23,7 +23,7 @@ module CarrierWaveDirect
|
|
23
23
|
class FilenameFormatValidator < ::ActiveModel::EachValidator
|
24
24
|
def validate_each(record, attribute, value)
|
25
25
|
if record.send("has_#{attribute}_upload?") && record.send("#{attribute}_key") !~ record.send(attribute).key_regexp
|
26
|
-
extensions = record.send(attribute).
|
26
|
+
extensions = record.send(attribute).extension_whitelist
|
27
27
|
message = I18n.t("errors.messages.carrierwave_direct_filename_invalid")
|
28
28
|
|
29
29
|
if extensions.present?
|
@@ -43,7 +43,7 @@ module CarrierWaveDirect
|
|
43
43
|
url_scheme_white_list = uploader.url_scheme_white_list
|
44
44
|
|
45
45
|
if (remote_net_url !~ URI.regexp(url_scheme_white_list) || remote_net_url !~ /#{uploader.extension_regexp}\z/)
|
46
|
-
extensions = uploader.
|
46
|
+
extensions = uploader.extension_whitelist
|
47
47
|
|
48
48
|
message = I18n.t("errors.messages.carrierwave_direct_filename_invalid")
|
49
49
|
|
data/spec/form_builder_spec.rb
CHANGED
@@ -30,13 +30,14 @@ shared_examples_for 'hidden values form' do
|
|
30
30
|
end
|
31
31
|
|
32
32
|
it "should have a hidden field for '#{name}'" do
|
33
|
+
allow(direct_uploader.send(:signing_policy)).to receive(key).and_return(key.to_s)
|
33
34
|
allow(direct_uploader).to receive(key).and_return(key.to_s)
|
34
35
|
expect(subject).to have_input(
|
35
36
|
:direct_uploader,
|
36
37
|
key,
|
37
38
|
:type => :hidden,
|
38
39
|
:name => name,
|
39
|
-
:value => key,
|
40
|
+
:value => direct_uploader.send(key),
|
40
41
|
:required => false
|
41
42
|
)
|
42
43
|
end
|
@@ -83,7 +84,7 @@ describe CarrierWaveDirect::FormBuilder do
|
|
83
84
|
|
84
85
|
# http://aws.amazon.com/articles/1434?_encoding=UTF8
|
85
86
|
context "form" do
|
86
|
-
|
87
|
+
subject { form_with_default_file_field }
|
87
88
|
it_should_behave_like 'hidden values form'
|
88
89
|
|
89
90
|
default_hidden_fields.each do |input|
|
@@ -95,13 +96,14 @@ describe CarrierWaveDirect::FormBuilder do
|
|
95
96
|
end
|
96
97
|
|
97
98
|
it "should have a hidden field for '#{name}'" do
|
99
|
+
allow(direct_uploader.send(:signing_policy)).to receive(key).and_return(key.to_s)
|
98
100
|
allow(direct_uploader).to receive(key).and_return(key.to_s)
|
99
|
-
expect(
|
101
|
+
expect(subject).to have_input(
|
100
102
|
:direct_uploader,
|
101
103
|
key,
|
102
104
|
:type => :hidden,
|
103
105
|
:name => name,
|
104
|
-
:value => key,
|
106
|
+
:value => direct_uploader.send(key),
|
105
107
|
:required => false
|
106
108
|
)
|
107
109
|
end
|
@@ -116,20 +118,21 @@ describe CarrierWaveDirect::FormBuilder do
|
|
116
118
|
end
|
117
119
|
|
118
120
|
it "should have a hidden field for '#{name}'" do
|
121
|
+
allow(direct_uploader.send(:signing_policy)).to receive(key).and_return(key.to_s)
|
119
122
|
allow(direct_uploader).to receive(key).and_return(key.to_s)
|
120
123
|
expect(form_with_file_field_and_no_redirect).to have_input(
|
121
124
|
:direct_uploader,
|
122
125
|
key,
|
123
126
|
:type => :hidden,
|
124
127
|
:name => name,
|
125
|
-
:value => key,
|
128
|
+
:value => direct_uploader.send(key),
|
126
129
|
:required => false
|
127
130
|
)
|
128
131
|
end
|
129
132
|
end
|
130
133
|
|
131
134
|
it "should have an input for a file to upload" do
|
132
|
-
expect(
|
135
|
+
expect(subject).to have_input(
|
133
136
|
:direct_uploader,
|
134
137
|
:video,
|
135
138
|
:type => :file,
|
@@ -142,7 +145,7 @@ describe CarrierWaveDirect::FormBuilder do
|
|
142
145
|
|
143
146
|
describe "#content_type_select" do
|
144
147
|
context "form" do
|
145
|
-
|
148
|
+
subject do
|
146
149
|
form do |f|
|
147
150
|
f.content_type_select
|
148
151
|
end
|
@@ -178,7 +181,7 @@ describe CarrierWaveDirect::FormBuilder do
|
|
178
181
|
|
179
182
|
describe "#content_type_label" do
|
180
183
|
context "form" do
|
181
|
-
|
184
|
+
subject do
|
182
185
|
form do |f|
|
183
186
|
f.content_type_label
|
184
187
|
end
|
data/spec/mount_spec.rb
CHANGED
@@ -18,12 +18,12 @@ describe CarrierWaveDirect::Mount do
|
|
18
18
|
|
19
19
|
describe "#has_video_upload?" do
|
20
20
|
it "returns false when video does not have a key" do
|
21
|
-
|
21
|
+
subject.video.key = nil
|
22
22
|
expect(subject).to_not have_video_upload
|
23
23
|
end
|
24
24
|
|
25
25
|
it "returns true when video has a key" do
|
26
|
-
|
26
|
+
subject.video.key = sample(:s3_key)
|
27
27
|
expect(subject).to have_video_upload
|
28
28
|
end
|
29
29
|
end
|
@@ -104,8 +104,8 @@ describe CarrierWaveDirect::ActiveRecord do
|
|
104
104
|
messages = I18n.t("errors.messages.carrierwave_direct_filename_invalid")
|
105
105
|
|
106
106
|
if i18n_options
|
107
|
-
if i18n_options[:
|
108
|
-
extensions = i18n_options[:
|
107
|
+
if i18n_options[:extension_whitelist]
|
108
|
+
extensions = i18n_options[:extension_whitelist].to_sentence
|
109
109
|
messages += I18n.t("errors.messages.carrierwave_direct_allowed_extensions", :extensions => extensions)
|
110
110
|
end
|
111
111
|
|
@@ -244,7 +244,7 @@ describe CarrierWaveDirect::ActiveRecord do
|
|
244
244
|
|
245
245
|
context "where the uploader has an extension white list" do
|
246
246
|
before do
|
247
|
-
subject.video.stub(:
|
247
|
+
subject.video.stub(:extension_whitelist).and_return(%w{avi mp4})
|
248
248
|
end
|
249
249
|
|
250
250
|
context "and the uploaded file's extension is included in the list" do
|
@@ -302,7 +302,7 @@ describe CarrierWaveDirect::ActiveRecord do
|
|
302
302
|
context "on create" do
|
303
303
|
context "where the uploader has an extension white list" do
|
304
304
|
before do
|
305
|
-
subject.video.stub(:
|
305
|
+
subject.video.stub(:extension_whitelist).and_return(%w{avi mp4})
|
306
306
|
end
|
307
307
|
|
308
308
|
context "and the url's extension is included in the list" do
|
@@ -325,7 +325,7 @@ describe CarrierWaveDirect::ActiveRecord do
|
|
325
325
|
end
|
326
326
|
|
327
327
|
it_should_behave_like "a remote net url i18n error message" do
|
328
|
-
let(:i18n_options) { {:
|
328
|
+
let(:i18n_options) { {:extension_whitelist => %w{avi mp4} } }
|
329
329
|
end
|
330
330
|
|
331
331
|
it "should include the white listed extensions in the error message" do
|
@@ -0,0 +1,243 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'spec_helper'
|
3
|
+
require 'data/sample_data'
|
4
|
+
|
5
|
+
describe CarrierWaveDirect::Policies::Aws4HmacSha256 do
|
6
|
+
let(:subject) { described_class.new(uploader) }
|
7
|
+
let(:uploader) { DirectUploader.new }
|
8
|
+
let(:mounted_model) { MountedClass.new }
|
9
|
+
let(:mounted_subject) { DirectUploader.new(mounted_model, sample(:mounted_as)) }
|
10
|
+
|
11
|
+
describe "#direct_fog_hash" do
|
12
|
+
it "should return the policy hash" do
|
13
|
+
expect(subject.direct_fog_hash.keys).to eq([:key, :acl, :policy, :"X-Amz-Signature", :"X-Amz-Credential", :"X-Amz-Algorithm", :"X-Amz-Date", :uri])
|
14
|
+
expect(subject.direct_fog_hash[:acl]).to eq 'public-read'
|
15
|
+
expect(subject.direct_fog_hash[:key]).to match /\$\{filename\}/
|
16
|
+
expect(subject.direct_fog_hash[:"X-Amz-Algorithm"]).to eq "AWS4-HMAC-SHA256"
|
17
|
+
expect(subject.direct_fog_hash[:uri]).to eq "https://s3.amazonaws.com/AWS_FOG_DIRECTORY/"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# http://aws.amazon.com/articles/1434?_encoding=UTF8
|
22
|
+
#http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-UsingHTTPPOST.html
|
23
|
+
describe "#policy" do
|
24
|
+
def decoded_policy(options = {}, &block)
|
25
|
+
instance = options.delete(:subject) || subject
|
26
|
+
JSON.parse(Base64.decode64(instance.policy(options, &block)))
|
27
|
+
end
|
28
|
+
|
29
|
+
context "policy is given a block" do
|
30
|
+
it "should yield the options to the block" do
|
31
|
+
number = 0
|
32
|
+
subject.policy do |conditions|
|
33
|
+
number+=1
|
34
|
+
end
|
35
|
+
expect(number).to eq 1
|
36
|
+
end
|
37
|
+
it "should include new options in the conditions" do
|
38
|
+
policy = subject.policy do |conditions|
|
39
|
+
conditions << {"x-aws-storage-class" => "STANDARD"}
|
40
|
+
end
|
41
|
+
decoded = JSON.parse(Base64.decode64(policy))
|
42
|
+
expect(decoded['conditions'].last['x-aws-storage-class']).to eq "STANDARD"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should return Base64-encoded JSON" do
|
47
|
+
expect(decoded_policy).to be_a(Hash)
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should not contain any new lines" do
|
51
|
+
expect(subject.policy).to_not include("\n")
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should be cached" do
|
55
|
+
Timecop.freeze(Time.now) do
|
56
|
+
@policy_now = subject.policy
|
57
|
+
end
|
58
|
+
Timecop.freeze(1.second.from_now) do
|
59
|
+
@policy_later = subject.policy
|
60
|
+
end
|
61
|
+
expect(@policy_later).to eql @policy_now
|
62
|
+
end
|
63
|
+
|
64
|
+
context "expiration" do
|
65
|
+
def expiration(options = {})
|
66
|
+
decoded_policy(options)["expiration"]
|
67
|
+
end
|
68
|
+
|
69
|
+
# JSON times have no seconds, so accept upto one second inaccuracy
|
70
|
+
def have_expiration(expires_in = DirectUploader.upload_expiration)
|
71
|
+
be_within(1.second).of (Time.now + expires_in)
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should be valid ISO8601 and not use default Time#to_json" do
|
75
|
+
Time.any_instance.stub(:to_json) { '"Invalid time"' } # JSON gem
|
76
|
+
Time.any_instance.stub(:as_json) { '"Invalid time"' } # Active Support
|
77
|
+
expect { Time.iso8601(expiration) }.to_not raise_error
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should be #{DirectUploader.upload_expiration / 3600} hours from now" do
|
81
|
+
Timecop.freeze(Time.now) do
|
82
|
+
expect(Time.parse(expiration)).to have_expiration
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should be encoded as a utc time" do
|
87
|
+
expect(Time.parse(expiration)).to be_utc
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should be #{sample(:expiration) / 60 } minutes from now when passing {:expiration => #{sample(:expiration)}}" do
|
91
|
+
Timecop.freeze(Time.now) do
|
92
|
+
expect(Time.parse(expiration(:expiration => sample(:expiration)))).to have_expiration(sample(:expiration))
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
context "conditions" do
|
98
|
+
def conditions(options = {})
|
99
|
+
decoded_policy(options)["conditions"]
|
100
|
+
end
|
101
|
+
|
102
|
+
def have_condition(field, value = nil)
|
103
|
+
field.is_a?(Hash) ? include(field) : include(["starts-with", "$#{field}", value.to_s])
|
104
|
+
end
|
105
|
+
|
106
|
+
context "should include" do
|
107
|
+
it "'utf8' if enforce_ut8 is set" do
|
108
|
+
expect(conditions(enforce_utf8: true)).to have_condition(:utf8)
|
109
|
+
end
|
110
|
+
|
111
|
+
it "'utf8' if enforce_ut8 is set" do
|
112
|
+
expect(conditions).to_not have_condition(:utf8)
|
113
|
+
end
|
114
|
+
|
115
|
+
# S3 conditions
|
116
|
+
it "'key'" do
|
117
|
+
allow(mounted_subject).to receive(:key).and_return(sample(:s3_key))
|
118
|
+
expect(conditions(
|
119
|
+
:subject => mounted_subject
|
120
|
+
)).to have_condition(:key, sample(:s3_key))
|
121
|
+
end
|
122
|
+
|
123
|
+
it "'key' without FILENAME_WILDCARD" do
|
124
|
+
expect(conditions(
|
125
|
+
:subject => mounted_subject
|
126
|
+
)).to have_condition(:key, mounted_subject.key.sub("${filename}", ""))
|
127
|
+
end
|
128
|
+
|
129
|
+
it "'bucket'" do
|
130
|
+
expect(conditions).to have_condition("bucket" => uploader.fog_directory)
|
131
|
+
end
|
132
|
+
|
133
|
+
it "'acl'" do
|
134
|
+
expect(conditions).to have_condition("acl" => uploader.acl)
|
135
|
+
end
|
136
|
+
|
137
|
+
it "'success_action_redirect'" do
|
138
|
+
uploader.success_action_redirect = "http://example.com/some_url"
|
139
|
+
expect(conditions).to have_condition("success_action_redirect" => "http://example.com/some_url")
|
140
|
+
end
|
141
|
+
|
142
|
+
it "does not have 'content-type' when will_include_content_type is false" do
|
143
|
+
allow(uploader.class).to receive(:will_include_content_type).and_return(false)
|
144
|
+
expect(conditions).to_not have_condition('Content-Type')
|
145
|
+
end
|
146
|
+
|
147
|
+
it "has 'content-type' when will_include_content_type is true" do
|
148
|
+
allow(uploader.class).to receive(:will_include_content_type).and_return(true)
|
149
|
+
expect(conditions).to have_condition('Content-Type')
|
150
|
+
end
|
151
|
+
|
152
|
+
context 'when use_action_status is true' do
|
153
|
+
before(:all) do
|
154
|
+
DirectUploader.use_action_status = true
|
155
|
+
end
|
156
|
+
|
157
|
+
after(:all) do
|
158
|
+
DirectUploader.use_action_status = false
|
159
|
+
end
|
160
|
+
|
161
|
+
it "'success_action_status'" do
|
162
|
+
uploader.success_action_status = '200'
|
163
|
+
expect(conditions).to have_condition("success_action_status" => "200")
|
164
|
+
end
|
165
|
+
|
166
|
+
it "does not have 'success_action_redirect'" do
|
167
|
+
uploader.success_action_redirect = "http://example.com/some_url"
|
168
|
+
expect(conditions).to_not have_condition("success_action_redirect" => "http://example.com/some_url")
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
context "'content-length-range of'" do
|
173
|
+
def have_content_length_range(options = {})
|
174
|
+
include([
|
175
|
+
"content-length-range",
|
176
|
+
options[:min_file_size] || DirectUploader.min_file_size,
|
177
|
+
options[:max_file_size] || DirectUploader.max_file_size,
|
178
|
+
])
|
179
|
+
end
|
180
|
+
|
181
|
+
it "#{DirectUploader.min_file_size} bytes" do
|
182
|
+
expect(conditions).to have_content_length_range
|
183
|
+
end
|
184
|
+
|
185
|
+
it "#{DirectUploader.max_file_size} bytes" do
|
186
|
+
expect(conditions).to have_content_length_range
|
187
|
+
end
|
188
|
+
|
189
|
+
it "#{sample(:min_file_size)} bytes when passing {:min_file_size => #{sample(:min_file_size)}}" do
|
190
|
+
expect(conditions(
|
191
|
+
:min_file_size => sample(:min_file_size)
|
192
|
+
)).to have_content_length_range(:min_file_size => sample(:min_file_size))
|
193
|
+
end
|
194
|
+
|
195
|
+
it "#{sample(:max_file_size)} bytes when passing {:max_file_size => #{sample(:max_file_size)}}" do
|
196
|
+
expect(conditions(
|
197
|
+
:max_file_size => sample(:max_file_size)
|
198
|
+
)).to have_content_length_range(:max_file_size => sample(:max_file_size))
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
describe "clear!" do
|
206
|
+
it "should reset the cached policy string" do
|
207
|
+
Timecop.freeze(Time.now) do
|
208
|
+
@policy_now = subject.policy
|
209
|
+
end
|
210
|
+
subject.clear!
|
211
|
+
|
212
|
+
Timecop.freeze(1.second.from_now) do
|
213
|
+
@policy_after_reset = subject.policy
|
214
|
+
end
|
215
|
+
expect(@policy_after_reset).not_to eql @policy_now
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
describe "#signature" do
|
220
|
+
it "should not contain any new lines" do
|
221
|
+
expect(subject.signature).to_not include("\n")
|
222
|
+
end
|
223
|
+
|
224
|
+
it "should return a HMAC hexdigest encoded 'sha256' hash of the secret key and policy document" do
|
225
|
+
expect(subject.signature).to eq OpenSSL::HMAC.hexdigest(
|
226
|
+
OpenSSL::Digest.new('sha256'),
|
227
|
+
subject.signing_key, subject.policy
|
228
|
+
)
|
229
|
+
end
|
230
|
+
end
|
231
|
+
#http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-UsingHTTPPOST.html
|
232
|
+
describe "#signature_key" do
|
233
|
+
it "should include correct signature_key elements" do
|
234
|
+
kDate = OpenSSL::HMAC.digest('sha256', "AWS4" + uploader.aws_secret_access_key, Time.now.utc.strftime("%Y%m%d"))
|
235
|
+
kRegion = OpenSSL::HMAC.digest('sha256', kDate, uploader.region)
|
236
|
+
kService = OpenSSL::HMAC.digest('sha256', kRegion, 's3')
|
237
|
+
kSigning = OpenSSL::HMAC.digest('sha256', kService, "aws4_request")
|
238
|
+
|
239
|
+
expect(subject.signing_key).to eq (kSigning)
|
240
|
+
end
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|