carrierwave_direct 1.0.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
|