carrierwave_direct 0.0.15 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +8 -8
- data/Changelog.md +17 -0
- data/README.md +31 -5
- data/carrierwave_direct.gemspec +3 -4
- data/gemfiles/{4.0.gemfile → 4.2.gemfile} +4 -5
- data/gemfiles/{4.1.gemfile → 5.1.gemfile} +4 -5
- data/lib/carrierwave_direct/form_builder.rb +6 -2
- data/lib/carrierwave_direct/mount.rb +16 -4
- data/lib/carrierwave_direct/orm/activerecord.rb +1 -1
- data/lib/carrierwave_direct/test/capybara_helpers.rb +4 -2
- data/lib/carrierwave_direct/uploader.rb +53 -15
- data/lib/carrierwave_direct/validations/active_model.rb +1 -1
- data/lib/carrierwave_direct/version.rb +1 -1
- data/lib/carrierwave_direct.rb +1 -2
- data/spec/form_builder_spec.rb +13 -7
- data/spec/mount_spec.rb +1 -1
- data/spec/orm/activerecord_spec.rb +47 -12
- data/spec/orm/indirect_activerecord_spec.rb +7 -1
- data/spec/support/view_helpers.rb +1 -1
- data/spec/test/capybara_helpers_spec.rb +3 -4
- data/spec/uploader/direct_url_spec.rb +2 -3
- data/spec/uploader_spec.rb +53 -30
- metadata +11 -26
- data/gemfiles/3.2.gemfile +0 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b64419d902b8c1afba920fafe9a7029dd4c3d94a
|
4
|
+
data.tar.gz: 5dfbb28ea14db2c7ae9bd665192c009534cbef90
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c8f39ac6ced22656b3a96821356d92333f9ca141f215bb66125b3d2a8fa282718341adb133b0baa33308f9268cf1ef2014e59e3e21bb1f7949a389f170b4c1be
|
7
|
+
data.tar.gz: b2e2fe378dfed399fc011fb4ebcb8a94d5d4ffe4cb4c982ed71b918aa53fa7767a1b1c6d226e6fda5ad2169af24af2a43c83b80b300650367ad49aa0e6faa9d6
|
data/.travis.yml
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
rvm:
|
2
|
-
-
|
3
|
-
- 2.
|
4
|
-
- 2.
|
5
|
-
install:
|
6
|
-
- 'travis_retry bundle install'
|
2
|
+
- 2.3.0
|
3
|
+
- 2.4.0
|
4
|
+
- 2.5.0
|
7
5
|
script: 'bundle exec rspec spec'
|
8
6
|
gemfile:
|
9
7
|
- Gemfile
|
10
|
-
- gemfiles/
|
11
|
-
- gemfiles/
|
12
|
-
|
8
|
+
- gemfiles/4.2.gemfile
|
9
|
+
- gemfiles/5.1.gemfile
|
10
|
+
# Move to containerized travis, see http://docs.travis-ci.com/user/migrating-from-legacy
|
11
|
+
sudo: false
|
12
|
+
cache: bundler
|
data/Changelog.md
CHANGED
@@ -1,3 +1,20 @@
|
|
1
|
+
### 1.0.0
|
2
|
+
|
3
|
+
Features:
|
4
|
+
* Upgraded signing algorithm to use [AWS V4 POST authentication](http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-authentication-HTTPPOST.html). This is a breaking change if you are constructing your own upload forms or submitting your own POST requests. See the Sinatra section of the README for a summary of the new fields required in your V4 POST request. (Fran Worley @fran-worley)
|
5
|
+
|
6
|
+
### 0.0.16
|
7
|
+
|
8
|
+
Bug Fixes:
|
9
|
+
* Allow uploader columns to be named `file` (Diego Plentz @plentz and Moisés Viloria @mois3x)
|
10
|
+
* `["starts-with", "$utf8", ""]` is not needed as condition (Rocco Galluzzo @byterussian)
|
11
|
+
|
12
|
+
Misc:
|
13
|
+
* Dropped support for ruby 1.9, it has [reached its end of life](https://www.ruby-lang.org/en/news/2014/01/10/ruby-1-9-3-will-end-on-2015/)
|
14
|
+
* Add 2.2.0 support to travis.
|
15
|
+
* Compatible with Capybara 2.7
|
16
|
+
* Replaced fog dependency with fog-aws; significantly reduces gem footprint
|
17
|
+
|
1
18
|
### 0.0.15
|
2
19
|
|
3
20
|
[Full Changes](https://github.com/dwilkie/carrierwave_direct/compare/v0.0.14...v0.0.15)
|
data/README.md
CHANGED
@@ -113,15 +113,19 @@ end
|
|
113
113
|
```
|
114
114
|
```haml
|
115
115
|
# index.haml
|
116
|
+
# Now using AWS POST authentication V4
|
117
|
+
# See http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-authentication-HTTPPOST.html for more information
|
116
118
|
|
117
119
|
%form{:action => @uploader.direct_fog_url, :method => "post", :enctype => "multipart/form-data"}
|
118
120
|
%input{:name => "utf8", :type => "hidden"}
|
119
121
|
%input{:type => "hidden", :name => "key", :value => @uploader.key}
|
120
|
-
%input{:type => "hidden", :name => "AWSAccessKeyId", :value => @uploader.aws_access_key_id}
|
121
122
|
%input{:type => "hidden", :name => "acl", :value => @uploader.acl}
|
122
123
|
%input{:type => "hidden", :name => "success_action_redirect", :value => @uploader.success_action_redirect}
|
123
124
|
%input{:type => "hidden", :name => "policy", :value => @uploader.policy}
|
124
|
-
%input{:type => "hidden", :name => "
|
125
|
+
%input{:type => "hidden", :name => "x-amz-algorithm", :value => @uploader.algorithm}
|
126
|
+
%input{:type => "hidden", :name => "x-amz-credential", :value => @uploader.credential}
|
127
|
+
%input{:type => "hidden", :name => "x-amz-date", :value => @uploader.date}
|
128
|
+
%input{:type => "hidden", :name => "x-amz-signature", :value => @uploader.signature}
|
125
129
|
%input{:name => "file", :type => "file"}
|
126
130
|
%input{:type => "submit", :value => "Upload to S3"}
|
127
131
|
```
|
@@ -156,7 +160,7 @@ end
|
|
156
160
|
After uploading to S3, You'll need to update the uploader object with the returned key in the controller action that corresponds to `new_user_url`:
|
157
161
|
|
158
162
|
```ruby
|
159
|
-
@uploader.update_attribute :
|
163
|
+
@uploader.update_attribute :avatar_key, params[:key]
|
160
164
|
```
|
161
165
|
|
162
166
|
You can also pass html options like this:
|
@@ -429,6 +433,29 @@ CarrierWave.configure do |config|
|
|
429
433
|
end
|
430
434
|
```
|
431
435
|
|
436
|
+
## Bucket CORS configuration and usage with CloudFront
|
437
|
+
|
438
|
+
If you are using a javascript uploader (e.g. Dropzone, jQuery Upload, Uploadify, etc.) you will need to add CORS configuration to your bucket, otherwise default bucket configuration will deny CORS requests. To do that open your bucket in Amazon console, click on its properties and add a CORS configuration similar to this
|
439
|
+
|
440
|
+
```xml
|
441
|
+
<CORSConfiguration>
|
442
|
+
<CORSRule>
|
443
|
+
<!-- Optionally change this with your domain, it should not be an issue since your bucket accepts only signed writes -->
|
444
|
+
<AllowedOrigin>*</AllowedOrigin>
|
445
|
+
<AllowedMethod>GET</AllowedMethod>
|
446
|
+
<AllowedMethod>POST</AllowedMethod>
|
447
|
+
<MaxAgeSeconds>3000</MaxAgeSeconds>
|
448
|
+
<AllowedHeader>Authorization</AllowedHeader>
|
449
|
+
<AllowedHeader>Content-Type</AllowedHeader>
|
450
|
+
<AllowedHeader>Origin</AllowedHeader>
|
451
|
+
</CORSRule>
|
452
|
+
</CORSConfiguration>
|
453
|
+
```
|
454
|
+
|
455
|
+
When you use this gem in conjunction with CloudFront you'll need an additional step otherwise it won't work as expected. This is strictly necessary if you configured CarrierWave `asset_host` to use a CloudFront in front of your bucket because your forms will be posted to that url.
|
456
|
+
|
457
|
+
To solve this issue you must enable POST requests in your CloudFront distribution settings. Here is a [step by step walkthrough](http://blog.celingest.com/en/2014/10/02/tutorial-using-cors-with-cloudfront-and-s3/) that explain this setup. It also explain CORS configuration.
|
458
|
+
|
432
459
|
## Testing with CarrierWaveDirect
|
433
460
|
|
434
461
|
CarrierWaveDirect provides a couple of helpers to help with integration and unit testing. You don't want to contact the Internet during your tests as this is slow, expensive and unreliable. You should first put fog into mock mode by doing something like this.
|
@@ -531,8 +558,6 @@ en:
|
|
531
558
|
|
532
559
|
## Caveats
|
533
560
|
|
534
|
-
Don't name your string column `file`. It will result in a stack level too deep exception. See [this issue](https://github.com/dwilkie/carrierwave_direct/issues/10) for more info.
|
535
|
-
|
536
561
|
If you're Rails app was newly generated *after* version 3.2.3 and your testing this in development you may run into an issue where an `ActiveModel::MassAssignmentSecurity::Error` is raised when being redirected from S3. You can fix this by setting `config.active_record.mass_assignment_sanitizer = :logger` in your `config/environments/development.rb` file.
|
537
562
|
|
538
563
|
## Contributing to CarrierWaveDirect
|
@@ -575,3 +600,4 @@ Thank you to everybody who has contributed to [CarrierWaveDirect](https://github
|
|
575
600
|
* [colinyoung (Colin Young)](https://github.com/colinyoung) - Content-Type support
|
576
601
|
* [jkamenik (John Kamenik)](https://github.com/jkamenik) - Content-Type support
|
577
602
|
* [filiptepper (Filip Tepper)](https://github.com/filiptepper) - Autoload UUID on heroku
|
603
|
+
* [mois3x (Moisés Viloria)](https://github.com/mois3x) and [plentz (Diego Plentz)](https://github.com/plentz) - Allow uploader columns to be named `file`
|
data/carrierwave_direct.gemspec
CHANGED
@@ -10,13 +10,12 @@ Gem::Specification.new do |s|
|
|
10
10
|
s.homepage = "https://github.com/dwilkie/carrierwave_direct"
|
11
11
|
s.summary = %q{Upload direct to S3 using CarrierWave}
|
12
12
|
s.description = %q{Process your uploads in the background by uploading directly to S3}
|
13
|
-
s.required_ruby_version = ">=
|
13
|
+
s.required_ruby_version = ">= 2.0.0"
|
14
14
|
|
15
15
|
s.rubyforge_project = "carrierwave_direct"
|
16
16
|
|
17
|
-
s.add_dependency "carrierwave"
|
18
|
-
s.add_dependency "
|
19
|
-
s.add_dependency "fog"
|
17
|
+
s.add_dependency "carrierwave", "~>0.11"
|
18
|
+
s.add_dependency "fog-aws"
|
20
19
|
|
21
20
|
s.add_development_dependency "rspec"
|
22
21
|
s.add_development_dependency "timecop"
|
@@ -1,13 +1,12 @@
|
|
1
1
|
source "https://rubygems.org"
|
2
2
|
|
3
|
-
gem "carrierwave"
|
4
|
-
gem "
|
5
|
-
gem "fog"
|
3
|
+
gem "carrierwave", "~>0.11"
|
4
|
+
gem "fog-aws"
|
6
5
|
|
7
6
|
group :test do
|
8
|
-
gem "rspec", '3.0
|
7
|
+
gem "rspec", '~> 3.0'
|
9
8
|
gem "timecop"
|
10
|
-
gem "rails", "~>4.
|
9
|
+
gem "rails", "~>4.2.0"
|
11
10
|
gem "sqlite3", :platform => [:ruby, :mswin, :mingw]
|
12
11
|
gem "capybara"
|
13
12
|
# gem "activerecord-jdbcsqlite3-adapter", :platform => :jruby
|
@@ -1,13 +1,12 @@
|
|
1
1
|
source "https://rubygems.org"
|
2
2
|
|
3
|
-
gem "carrierwave"
|
4
|
-
gem "
|
5
|
-
gem "fog"
|
3
|
+
gem "carrierwave", "~>0.11"
|
4
|
+
gem "fog-aws"
|
6
5
|
|
7
6
|
group :test do
|
8
|
-
gem "rspec", '3.0
|
7
|
+
gem "rspec", '~> 3.0'
|
9
8
|
gem "timecop"
|
10
|
-
gem "rails", "~>
|
9
|
+
gem "rails", "~>5.1.0"
|
11
10
|
gem "sqlite3", :platform => [:ruby, :mswin, :mingw]
|
12
11
|
gem "capybara"
|
13
12
|
# gem "activerecord-jdbcsqlite3-adapter", :platform => :jruby
|
@@ -3,6 +3,8 @@
|
|
3
3
|
module CarrierWaveDirect
|
4
4
|
class FormBuilder < ActionView::Helpers::FormBuilder
|
5
5
|
def file_field(method, options = {})
|
6
|
+
@object.policy(enforce_utf8: true)
|
7
|
+
|
6
8
|
options.merge!(:name => "file")
|
7
9
|
|
8
10
|
fields = required_base_fields
|
@@ -29,10 +31,12 @@ module CarrierWaveDirect
|
|
29
31
|
|
30
32
|
def required_base_fields
|
31
33
|
hidden_field(:key, :name => "key") <<
|
32
|
-
hidden_field(:aws_access_key_id, :name => "AWSAccessKeyId") <<
|
33
34
|
hidden_field(:acl, :name => "acl") <<
|
34
35
|
hidden_field(:policy, :name => "policy") <<
|
35
|
-
hidden_field(:signature, :name => "
|
36
|
+
hidden_field(:signature, :name => "X-Amz-Signature") <<
|
37
|
+
hidden_field(:credential, :name => "X-Amz-Credential") <<
|
38
|
+
hidden_field(:algorithm, :name => "X-Amz-Algorithm") <<
|
39
|
+
hidden_field(:date, :name => "X-Amz-Date")
|
36
40
|
end
|
37
41
|
|
38
42
|
def content_type_field(options)
|
@@ -9,10 +9,12 @@ module CarrierWaveDirect
|
|
9
9
|
# Don't go further unless the class included CarrierWaveDirect::Uploader
|
10
10
|
return unless uploader.ancestors.include?(CarrierWaveDirect::Uploader)
|
11
11
|
|
12
|
-
uploader.
|
13
|
-
|
14
|
-
|
15
|
-
|
12
|
+
unless uploader.instance_methods.include?(column)
|
13
|
+
uploader.class_eval <<-RUBY, __FILE__, __LINE__+1
|
14
|
+
def #{column}; self; end
|
15
|
+
RUBY
|
16
|
+
end
|
17
|
+
|
16
18
|
self.instance_eval <<-RUBY, __FILE__, __LINE__+1
|
17
19
|
attr_accessor :remote_#{column}_net_url
|
18
20
|
RUBY
|
@@ -22,10 +24,20 @@ module CarrierWaveDirect
|
|
22
24
|
mod.class_eval <<-RUBY, __FILE__, __LINE__+1
|
23
25
|
|
24
26
|
def key
|
27
|
+
warn "key method is deprecated, please use column_key method instead."
|
25
28
|
send(:#{column}).key
|
26
29
|
end
|
27
30
|
|
28
31
|
def key=(k)
|
32
|
+
warn "key= method is deprecated, please use column_key= method instead."
|
33
|
+
send(:#{column}).key = k
|
34
|
+
end
|
35
|
+
|
36
|
+
def #{column}_key
|
37
|
+
send(:#{column}).key
|
38
|
+
end
|
39
|
+
|
40
|
+
def #{column}_key=(k)
|
29
41
|
send(:#{column}).key = k
|
30
42
|
end
|
31
43
|
|
@@ -32,7 +32,7 @@ module CarrierWaveDirect
|
|
32
32
|
self.instance_eval <<-RUBY, __FILE__, __LINE__+1
|
33
33
|
attr_accessor :skip_is_attached_validations
|
34
34
|
unless defined?(ActiveModel::ForbiddenAttributesProtection) && ancestors.include?(ActiveModel::ForbiddenAttributesProtection)
|
35
|
-
attr_accessible
|
35
|
+
attr_accessible :#{column}_key, :remote_#{column}_net_url
|
36
36
|
end
|
37
37
|
RUBY
|
38
38
|
|
@@ -33,12 +33,14 @@ module CarrierWaveDirect
|
|
33
33
|
sample_key_args.unshift(uploader) if method(:sample_key).arity == -2
|
34
34
|
options[:redirect_key] = sample_key(*sample_key_args)
|
35
35
|
end
|
36
|
-
|
36
|
+
|
37
|
+
redirect_url_params = Rack::Utils.parse_nested_query(redirect_url.query)
|
38
|
+
|
37
39
|
redirect_url.query = Rack::Utils.build_nested_query({
|
38
40
|
:bucket => uploader.fog_directory,
|
39
41
|
:key => options[:redirect_key],
|
40
42
|
:etag => "\"d41d8cd98f00b204e9800998ecf8427\""
|
41
|
-
})
|
43
|
+
}.merge(redirect_url_params))
|
42
44
|
|
43
45
|
# click the button
|
44
46
|
click_button button_locator
|
@@ -1,5 +1,6 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
|
+
require "securerandom"
|
3
4
|
require "carrierwave_direct/uploader/content_type"
|
4
5
|
require "carrierwave_direct/uploader/direct_url"
|
5
6
|
|
@@ -25,29 +26,50 @@ module CarrierWaveDirect
|
|
25
26
|
include CarrierWaveDirect::Uploader::ContentType
|
26
27
|
include CarrierWaveDirect::Uploader::DirectUrl
|
27
28
|
|
29
|
+
#ensure that region returns something. Since sig v4 it is required in the signing key & credentials
|
30
|
+
def region
|
31
|
+
defined?(super) ? super : "us-east-1"
|
32
|
+
end
|
33
|
+
|
28
34
|
def acl
|
29
35
|
fog_public ? 'public-read' : 'private'
|
30
36
|
end
|
31
37
|
|
32
|
-
def policy(options = {})
|
38
|
+
def policy(options = {}, &block)
|
33
39
|
options[:expiration] ||= upload_expiration
|
34
40
|
options[:min_file_size] ||= min_file_size
|
35
41
|
options[:max_file_size] ||= max_file_size
|
36
42
|
|
37
|
-
@
|
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)
|
46
|
+
end
|
47
|
+
|
48
|
+
def date
|
49
|
+
@timestamp ||= Time.now.utc.strftime("%Y%m%dT%H%M%SZ")
|
50
|
+
end
|
51
|
+
|
52
|
+
def algorithm
|
53
|
+
'AWS4-HMAC-SHA256'
|
54
|
+
end
|
55
|
+
|
56
|
+
def credential
|
57
|
+
@date ||= Time.now.utc.strftime("%Y%m%d")
|
58
|
+
"#{aws_access_key_id}/#{@date}/#{region}/s3/aws4_request"
|
38
59
|
end
|
39
60
|
|
40
61
|
def clear_policy!
|
41
62
|
@policy = nil
|
63
|
+
@date = nil
|
64
|
+
@timestamp = nil
|
42
65
|
end
|
43
66
|
|
44
67
|
def signature
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
).gsub("\n","")
|
68
|
+
OpenSSL::HMAC.hexdigest(
|
69
|
+
'sha256',
|
70
|
+
signing_key,
|
71
|
+
policy
|
72
|
+
)
|
51
73
|
end
|
52
74
|
|
53
75
|
def url_scheme_white_list
|
@@ -61,7 +83,8 @@ module CarrierWaveDirect
|
|
61
83
|
def key
|
62
84
|
return @key if @key.present?
|
63
85
|
if present?
|
64
|
-
|
86
|
+
identifier = model.send("#{mounted_as}_identifier")
|
87
|
+
self.key = "#{store_dir}/#{identifier}"
|
65
88
|
else
|
66
89
|
@key = "#{store_dir}/#{guid}/#{FILENAME_WILDCARD}"
|
67
90
|
end
|
@@ -74,7 +97,7 @@ module CarrierWaveDirect
|
|
74
97
|
end
|
75
98
|
|
76
99
|
def guid
|
77
|
-
|
100
|
+
SecureRandom.uuid
|
78
101
|
end
|
79
102
|
|
80
103
|
def has_key?
|
@@ -133,11 +156,13 @@ module CarrierWaveDirect
|
|
133
156
|
end
|
134
157
|
|
135
158
|
def generate_policy(options)
|
136
|
-
conditions = [
|
137
|
-
["starts-with", "$utf8", ""],
|
138
|
-
["starts-with", "$key", key.sub(/#{Regexp.escape(FILENAME_WILDCARD)}\z/, "")]
|
139
|
-
]
|
159
|
+
conditions = []
|
140
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}
|
141
166
|
conditions << ["starts-with", "$Content-Type", ""] if will_include_content_type
|
142
167
|
conditions << {"bucket" => fog_directory}
|
143
168
|
conditions << {"acl" => acl}
|
@@ -150,12 +175,25 @@ module CarrierWaveDirect
|
|
150
175
|
|
151
176
|
conditions << ["content-length-range", options[:min_file_size], options[:max_file_size]]
|
152
177
|
|
178
|
+
yield conditions if block_given?
|
179
|
+
|
153
180
|
Base64.encode64(
|
154
181
|
{
|
155
|
-
'expiration' => Time.now
|
182
|
+
'expiration' => (Time.now + options[:expiration]).utc.iso8601,
|
156
183
|
'conditions' => conditions
|
157
184
|
}.to_json
|
158
185
|
).gsub("\n","")
|
159
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
|
197
|
+
end
|
160
198
|
end
|
161
199
|
end
|
@@ -22,7 +22,7 @@ module CarrierWaveDirect
|
|
22
22
|
|
23
23
|
class FilenameFormatValidator < ::ActiveModel::EachValidator
|
24
24
|
def validate_each(record, attribute, value)
|
25
|
-
if record.send("has_#{attribute}_upload?") && record.
|
25
|
+
if record.send("has_#{attribute}_upload?") && record.send("#{attribute}_key") !~ record.send(attribute).key_regexp
|
26
26
|
extensions = record.send(attribute).extension_white_list
|
27
27
|
message = I18n.t("errors.messages.carrierwave_direct_filename_invalid")
|
28
28
|
|
data/lib/carrierwave_direct.rb
CHANGED
data/spec/form_builder_spec.rb
CHANGED
@@ -12,11 +12,13 @@ end
|
|
12
12
|
shared_examples_for 'hidden values form' do
|
13
13
|
hidden_fields = [
|
14
14
|
:key,
|
15
|
-
{:
|
15
|
+
{:credential => "X-Amz-Credential"},
|
16
|
+
{:algorithm => "X-Amz-Algorithm"},
|
17
|
+
{:date => "X-Amz-Date"},
|
18
|
+
{:signature => "X-Amz-Signature"},
|
16
19
|
:acl,
|
17
20
|
:success_action_redirect,
|
18
|
-
:policy
|
19
|
-
:signature
|
21
|
+
:policy
|
20
22
|
]
|
21
23
|
|
22
24
|
hidden_fields.each do |input|
|
@@ -60,19 +62,23 @@ describe CarrierWaveDirect::FormBuilder do
|
|
60
62
|
|
61
63
|
default_hidden_fields = [
|
62
64
|
:key,
|
63
|
-
{:
|
65
|
+
{:credential => "X-Amz-Credential"},
|
66
|
+
{:algorithm => "X-Amz-Algorithm"},
|
67
|
+
{:date => "X-Amz-Date"},
|
68
|
+
{:signature => "X-Amz-Signature"},
|
64
69
|
:acl,
|
65
70
|
:success_action_redirect,
|
66
71
|
:policy,
|
67
|
-
:signature
|
68
72
|
]
|
69
73
|
status_hidden_fields = [
|
70
74
|
:key,
|
71
|
-
{:
|
75
|
+
{:credential => "X-Amz-Credential"},
|
76
|
+
{:algorithm => "X-Amz-Algorithm"},
|
77
|
+
{:date => "X-Amz-Date"},
|
78
|
+
{:signature => "X-Amz-Signature"},
|
72
79
|
:acl,
|
73
80
|
:success_action_status,
|
74
81
|
:policy,
|
75
|
-
:signature
|
76
82
|
]
|
77
83
|
|
78
84
|
# http://aws.amazon.com/articles/1434?_encoding=UTF8
|
data/spec/mount_spec.rb
CHANGED
@@ -40,7 +40,7 @@ describe CarrierWaveDirect::Mount do
|
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
|
-
it_should_delegate(:
|
43
|
+
it_should_delegate(:video_key, :to => "video#key", :accessible => { "has_video_upload?" => false })
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
@@ -9,8 +9,12 @@ describe CarrierWaveDirect::ActiveRecord do
|
|
9
9
|
:adapter => 'sqlite3',
|
10
10
|
:database => ':memory:'
|
11
11
|
}
|
12
|
-
|
13
|
-
|
12
|
+
if ActiveRecord::VERSION::MAJOR >= 5
|
13
|
+
migration_class = ::ActiveRecord::Migration[5.0]
|
14
|
+
else
|
15
|
+
migration_class = ::ActiveRecord::Migration
|
16
|
+
end
|
17
|
+
class TestMigration < migration_class
|
14
18
|
def self.up
|
15
19
|
create_table :parties, :force => true do |t|
|
16
20
|
t.column :video, :string
|
@@ -19,6 +23,9 @@ describe CarrierWaveDirect::ActiveRecord do
|
|
19
23
|
create_table :dances, :force => true do |t|
|
20
24
|
t.column :location, :string
|
21
25
|
end
|
26
|
+
create_table :resources, :force => true do |t|
|
27
|
+
t.column :file, :string
|
28
|
+
end
|
22
29
|
end
|
23
30
|
|
24
31
|
def self.down
|
@@ -34,6 +41,10 @@ describe CarrierWaveDirect::ActiveRecord do
|
|
34
41
|
class Dance < ActiveRecord::Base
|
35
42
|
end
|
36
43
|
|
44
|
+
class Resource < ActiveRecord::Base
|
45
|
+
mount_uploader :file, DirectUploader
|
46
|
+
end
|
47
|
+
|
37
48
|
ActiveRecord::Base.establish_connection(dbconfig)
|
38
49
|
|
39
50
|
# turn off migration output
|
@@ -111,7 +122,7 @@ describe CarrierWaveDirect::ActiveRecord do
|
|
111
122
|
shared_examples_for "without an upload" do
|
112
123
|
before do
|
113
124
|
subject.remote_video_net_url = remote_video_net_url
|
114
|
-
subject.
|
125
|
+
subject.video_key = upload_path
|
115
126
|
end
|
116
127
|
|
117
128
|
it "should not be valid on create" do
|
@@ -162,7 +173,7 @@ describe CarrierWaveDirect::ActiveRecord do
|
|
162
173
|
let(:dance) { Dance.new }
|
163
174
|
|
164
175
|
before { Dance.mount_uploader(:non_existing_column, DirectUploader, mount_on: :location) }
|
165
|
-
before { dance.
|
176
|
+
before { dance.non_existing_column_key = sample_key}
|
166
177
|
|
167
178
|
it "uses the column it's mounted on for checking uniqueness" do
|
168
179
|
expect { dance.valid? }.to_not raise_error
|
@@ -212,7 +223,7 @@ describe CarrierWaveDirect::ActiveRecord do
|
|
212
223
|
context "where the file upload is" do
|
213
224
|
context "nil" do
|
214
225
|
before do
|
215
|
-
subject.
|
226
|
+
subject.video_key = nil
|
216
227
|
end
|
217
228
|
|
218
229
|
it "should be valid" do
|
@@ -222,7 +233,7 @@ describe CarrierWaveDirect::ActiveRecord do
|
|
222
233
|
|
223
234
|
context "blank" do
|
224
235
|
before do
|
225
|
-
subject.
|
236
|
+
subject.video_key = ""
|
226
237
|
end
|
227
238
|
|
228
239
|
it "should be valid" do
|
@@ -238,7 +249,7 @@ describe CarrierWaveDirect::ActiveRecord do
|
|
238
249
|
|
239
250
|
context "and the uploaded file's extension is included in the list" do
|
240
251
|
before do
|
241
|
-
subject.
|
252
|
+
subject.video_key = sample_key(:extension => "avi")
|
242
253
|
end
|
243
254
|
|
244
255
|
it "should be valid" do
|
@@ -248,7 +259,7 @@ describe CarrierWaveDirect::ActiveRecord do
|
|
248
259
|
|
249
260
|
context "but uploaded file's extension is not included in the list" do
|
250
261
|
before do
|
251
|
-
subject.
|
262
|
+
subject.video_key = sample_key(:extension => "mp3")
|
252
263
|
end
|
253
264
|
|
254
265
|
it_should_behave_like "an invalid filename"
|
@@ -468,7 +479,7 @@ describe CarrierWaveDirect::ActiveRecord do
|
|
468
479
|
|
469
480
|
context "with an upload by file" do
|
470
481
|
before do
|
471
|
-
subject.
|
482
|
+
subject.video_key = sample_key
|
472
483
|
end
|
473
484
|
|
474
485
|
it "should be valid" do
|
@@ -520,7 +531,7 @@ describe CarrierWaveDirect::ActiveRecord do
|
|
520
531
|
|
521
532
|
describe "#key" do
|
522
533
|
it "should be accessible" do
|
523
|
-
party_class.new(:
|
534
|
+
party_class.new(:video_key => "some key").video_key.should == "some key"
|
524
535
|
end
|
525
536
|
end
|
526
537
|
|
@@ -554,7 +565,7 @@ describe CarrierWaveDirect::ActiveRecord do
|
|
554
565
|
context "has an upload" do
|
555
566
|
context "with a valid filename" do
|
556
567
|
before do
|
557
|
-
subject.
|
568
|
+
subject.video_key = sample_key(:model_class => subject.class)
|
558
569
|
end
|
559
570
|
|
560
571
|
it "should be true" do
|
@@ -565,7 +576,7 @@ describe CarrierWaveDirect::ActiveRecord do
|
|
565
576
|
end
|
566
577
|
|
567
578
|
context "with an invalid filename" do
|
568
|
-
before { subject.
|
579
|
+
before { subject.video_key = sample_key(:model_class => subject.class, :valid => false) }
|
569
580
|
|
570
581
|
it "should be false" do
|
571
582
|
subject.filename_valid?.should be false
|
@@ -582,4 +593,28 @@ describe CarrierWaveDirect::ActiveRecord do
|
|
582
593
|
end
|
583
594
|
end
|
584
595
|
end
|
596
|
+
|
597
|
+
describe "class Resource < ActiveRecord::Base; mount_uploader :file, DirectUploader; end" do
|
598
|
+
include UploaderHelpers
|
599
|
+
include ModelHelpers
|
600
|
+
|
601
|
+
let(:resource_class) do
|
602
|
+
Class.new(Resource)
|
603
|
+
end
|
604
|
+
|
605
|
+
let(:subject) do
|
606
|
+
resource = resource_class.new
|
607
|
+
end
|
608
|
+
|
609
|
+
def mount_uploader
|
610
|
+
resource_class.mount_uploader :file, DirectUploader
|
611
|
+
end
|
612
|
+
|
613
|
+
#See resource table migration
|
614
|
+
it "should be valid still when a file column exists in table" do
|
615
|
+
expect(subject).to be_valid
|
616
|
+
end
|
617
|
+
|
618
|
+
|
619
|
+
end
|
585
620
|
end
|
@@ -10,7 +10,13 @@ describe CarrierWave::ActiveRecord do
|
|
10
10
|
:database => ':memory:'
|
11
11
|
}
|
12
12
|
|
13
|
-
|
13
|
+
if ActiveRecord::VERSION::MAJOR >= 5
|
14
|
+
migration_class = ::ActiveRecord::Migration[5.0]
|
15
|
+
else
|
16
|
+
migration_class = ::ActiveRecord::Migration
|
17
|
+
end
|
18
|
+
|
19
|
+
class OtherTestMigration < migration_class
|
14
20
|
def self.up
|
15
21
|
create_table :other_parties, :force => true do |t|
|
16
22
|
t.column :video, :string
|
@@ -44,7 +44,7 @@ describe CarrierWaveDirect::Test::CapybaraHelpers do
|
|
44
44
|
|
45
45
|
def stub_common
|
46
46
|
stub_page
|
47
|
-
find_element_value("input[name='success_action_redirect']", "http://example.com", visible: false)
|
47
|
+
find_element_value("input[name='success_action_redirect']", "http://example.com?custom_param=value", visible: false)
|
48
48
|
allow(subject).to receive(:visit)
|
49
49
|
end
|
50
50
|
|
@@ -79,8 +79,8 @@ describe CarrierWaveDirect::Test::CapybaraHelpers do
|
|
79
79
|
|
80
80
|
it_should_behave_like "submitting the form"
|
81
81
|
|
82
|
-
it "should redirect to the page's success_action_redirect url" do
|
83
|
-
expect(subject).to receive(:visit).with(/^http:\/\/example.com/)
|
82
|
+
it "should redirect to the page's success_action_redirect url and preserve custom parameters" do
|
83
|
+
expect(subject).to receive(:visit).with(/^http:\/\/example.com\?.*custom_param=value/)
|
84
84
|
upload_directly
|
85
85
|
end
|
86
86
|
|
@@ -160,4 +160,3 @@ describe CarrierWaveDirect::Test::CapybaraHelpers do
|
|
160
160
|
end
|
161
161
|
end
|
162
162
|
end
|
163
|
-
|
@@ -7,6 +7,8 @@ describe CarrierWaveDirect::Uploader::DirectUrl do
|
|
7
7
|
|
8
8
|
let(:subject) { DirectUploader.new }
|
9
9
|
|
10
|
+
let(:mounted_subject) { DirectUploader.new(mounted_model, sample(:mounted_as)) }
|
11
|
+
|
10
12
|
describe "#direct_fog_url" do
|
11
13
|
it "should return the result from CarrierWave::Storage::Fog::File#public_url" do
|
12
14
|
expect(subject.direct_fog_url).to eq CarrierWave::Storage::Fog::File.new(
|
@@ -22,6 +24,3 @@ describe CarrierWaveDirect::Uploader::DirectUrl do
|
|
22
24
|
end
|
23
25
|
end
|
24
26
|
end
|
25
|
-
|
26
|
-
|
27
|
-
|
data/spec/uploader_spec.rb
CHANGED
@@ -7,7 +7,7 @@ describe CarrierWaveDirect::Uploader do
|
|
7
7
|
include ModelHelpers
|
8
8
|
|
9
9
|
let(:subject) { DirectUploader.new }
|
10
|
-
let(:mounted_model) { double(sample(:mounted_model_name)) }
|
10
|
+
let(:mounted_model) { double(sample(:mounted_model_name), video_identifier: sample(:stored_filename)) }
|
11
11
|
let(:mounted_subject) { DirectUploader.new(mounted_model, sample(:mounted_as)) }
|
12
12
|
let(:direct_subject) { DirectUploader.new }
|
13
13
|
|
@@ -73,6 +73,7 @@ describe CarrierWaveDirect::Uploader do
|
|
73
73
|
|
74
74
|
context "but the uploaders url is '#{sample(:s3_file_url)}'" do
|
75
75
|
before do
|
76
|
+
allow(mounted_subject).to receive(:store_dir).and_return(sample(:store_dir))
|
76
77
|
allow(mounted_subject).to receive(:url).and_return(sample(:s3_file_url))
|
77
78
|
allow(mounted_subject).to receive(:present?).and_return(true)
|
78
79
|
end
|
@@ -253,19 +254,6 @@ describe CarrierWaveDirect::Uploader do
|
|
253
254
|
end
|
254
255
|
end
|
255
256
|
|
256
|
-
context "and the model's remote url contains already escaped characters" do
|
257
|
-
before do
|
258
|
-
subject.key = nil
|
259
|
-
allow(subject).to receive(:present?).and_return(:true)
|
260
|
-
allow(subject).to receive(:url).and_return("http://anyurl.com/any_path/video_dir/filename%20%28%29%2B%5B%5D2.avi")
|
261
|
-
end
|
262
|
-
|
263
|
-
it "should not double escape already escaped characters" do
|
264
|
-
expect(subject.key).to match /filename \(\)\+\[\]2.avi/
|
265
|
-
end
|
266
|
-
|
267
|
-
end
|
268
|
-
|
269
257
|
context "and the model's remote #{sample(:mounted_as)} url is blank" do
|
270
258
|
before do
|
271
259
|
allow(mounted_model).to receive(
|
@@ -287,10 +275,30 @@ describe CarrierWaveDirect::Uploader do
|
|
287
275
|
end
|
288
276
|
|
289
277
|
# http://aws.amazon.com/articles/1434?_encoding=UTF8
|
278
|
+
#http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-UsingHTTPPOST.html
|
290
279
|
describe "#policy" do
|
291
|
-
|
280
|
+
|
281
|
+
|
282
|
+
def decoded_policy(options = {}, &block)
|
292
283
|
instance = options.delete(:subject) || subject
|
293
|
-
JSON.parse(Base64.decode64(instance.policy(options)))
|
284
|
+
JSON.parse(Base64.decode64(instance.policy(options, &block)))
|
285
|
+
end
|
286
|
+
|
287
|
+
context "policy is given a block" do
|
288
|
+
it "should yield the options to the block" do
|
289
|
+
number = 0
|
290
|
+
subject.policy do |conditions|
|
291
|
+
number+=1
|
292
|
+
end
|
293
|
+
expect(number).to eq 1
|
294
|
+
end
|
295
|
+
it "should include new options in the conditions" do
|
296
|
+
policy = subject.policy do |conditions|
|
297
|
+
conditions << {"x-aws-storage-class" => "STANDARD"}
|
298
|
+
end
|
299
|
+
decoded = JSON.parse(Base64.decode64(policy))
|
300
|
+
expect(decoded['conditions'].last['x-aws-storage-class']).to eq "STANDARD"
|
301
|
+
end
|
294
302
|
end
|
295
303
|
|
296
304
|
it "should return Base64-encoded JSON" do
|
@@ -316,14 +324,15 @@ describe CarrierWaveDirect::Uploader do
|
|
316
324
|
decoded_policy(options)["expiration"]
|
317
325
|
end
|
318
326
|
|
327
|
+
# JSON times have no seconds, so accept upto one second inaccuracy
|
319
328
|
def have_expiration(expires_in = DirectUploader.upload_expiration)
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
)
|
329
|
+
be_within(1.second).of (Time.now + expires_in)
|
330
|
+
end
|
331
|
+
|
332
|
+
it "should be valid ISO8601 and not use default Time#to_json" do
|
333
|
+
Time.any_instance.stub(:to_json) { '"Invalid time"' } # JSON gem
|
334
|
+
Time.any_instance.stub(:as_json) { '"Invalid time"' } # Active Support
|
335
|
+
expect { Time.iso8601(expiration) }.to_not raise_error
|
327
336
|
end
|
328
337
|
|
329
338
|
it "should be #{DirectUploader.upload_expiration / 3600} hours from now" do
|
@@ -353,9 +362,12 @@ describe CarrierWaveDirect::Uploader do
|
|
353
362
|
end
|
354
363
|
|
355
364
|
context "should include" do
|
356
|
-
|
357
|
-
|
358
|
-
|
365
|
+
it "'utf8' if enforce_ut8 is set" do
|
366
|
+
expect(conditions(enforce_utf8: true)).to have_condition(:utf8)
|
367
|
+
end
|
368
|
+
|
369
|
+
it "'utf8' if enforce_ut8 is set" do
|
370
|
+
expect(conditions).to_not have_condition(:utf8)
|
359
371
|
end
|
360
372
|
|
361
373
|
# S3 conditions
|
@@ -467,13 +479,24 @@ describe CarrierWaveDirect::Uploader do
|
|
467
479
|
expect(subject.signature).to_not include("\n")
|
468
480
|
end
|
469
481
|
|
470
|
-
it "should return a
|
471
|
-
expect(
|
472
|
-
OpenSSL::Digest.new('
|
473
|
-
subject.
|
482
|
+
it "should return a HMAC hexdigest encoded 'sha256' hash of the secret key and policy document" do
|
483
|
+
expect(subject.signature).to eq OpenSSL::HMAC.hexdigest(
|
484
|
+
OpenSSL::Digest.new('sha256'),
|
485
|
+
subject.send(:signing_key), subject.policy
|
474
486
|
)
|
475
487
|
end
|
476
488
|
end
|
489
|
+
#http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-UsingHTTPPOST.html
|
490
|
+
describe "#signature_key" do
|
491
|
+
it "should include correct signature_key elements" do
|
492
|
+
kDate = OpenSSL::HMAC.digest('sha256', "AWS4" + subject.aws_secret_access_key, Time.now.utc.strftime("%Y%m%d"))
|
493
|
+
kRegion = OpenSSL::HMAC.digest('sha256', kDate, subject.region)
|
494
|
+
kService = OpenSSL::HMAC.digest('sha256', kRegion, 's3')
|
495
|
+
kSigning = OpenSSL::HMAC.digest('sha256', kService, "aws4_request")
|
496
|
+
|
497
|
+
expect(subject.send(:signing_key)).to eq (kSigning)
|
498
|
+
end
|
499
|
+
end
|
477
500
|
|
478
501
|
|
479
502
|
# note that 'video' is hardcoded into the MountedClass support file
|
metadata
CHANGED
@@ -1,45 +1,31 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: carrierwave_direct
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Wilkie
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-07-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: carrierwave
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '0'
|
19
|
+
version: '0.11'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: '0'
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: uuidtools
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - ">="
|
24
|
+
- - "~>"
|
32
25
|
- !ruby/object:Gem::Version
|
33
|
-
version: '0'
|
34
|
-
type: :runtime
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - ">="
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: '0'
|
26
|
+
version: '0.11'
|
41
27
|
- !ruby/object:Gem::Dependency
|
42
|
-
name: fog
|
28
|
+
name: fog-aws
|
43
29
|
requirement: !ruby/object:Gem::Requirement
|
44
30
|
requirements:
|
45
31
|
- - ">="
|
@@ -137,9 +123,8 @@ files:
|
|
137
123
|
- README.md
|
138
124
|
- Rakefile
|
139
125
|
- carrierwave_direct.gemspec
|
140
|
-
- gemfiles/
|
141
|
-
- gemfiles/
|
142
|
-
- gemfiles/4.1.gemfile
|
126
|
+
- gemfiles/4.2.gemfile
|
127
|
+
- gemfiles/5.1.gemfile
|
143
128
|
- lib/carrierwave_direct.rb
|
144
129
|
- lib/carrierwave_direct/action_view_extensions/form_helper.rb
|
145
130
|
- lib/carrierwave_direct/form_builder.rb
|
@@ -187,7 +172,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
187
172
|
requirements:
|
188
173
|
- - ">="
|
189
174
|
- !ruby/object:Gem::Version
|
190
|
-
version:
|
175
|
+
version: 2.0.0
|
191
176
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
192
177
|
requirements:
|
193
178
|
- - ">="
|
@@ -195,7 +180,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
195
180
|
version: '0'
|
196
181
|
requirements: []
|
197
182
|
rubyforge_project: carrierwave_direct
|
198
|
-
rubygems_version: 2.2.
|
183
|
+
rubygems_version: 2.5.2.3
|
199
184
|
signing_key:
|
200
185
|
specification_version: 4
|
201
186
|
summary: Upload direct to S3 using CarrierWave
|
data/gemfiles/3.2.gemfile
DELETED
@@ -1,14 +0,0 @@
|
|
1
|
-
source "https://rubygems.org"
|
2
|
-
|
3
|
-
gem "carrierwave"
|
4
|
-
gem "uuidtools"
|
5
|
-
gem "fog"
|
6
|
-
|
7
|
-
group :test do
|
8
|
-
gem "rspec", '3.0.0'
|
9
|
-
gem "timecop"
|
10
|
-
gem "rails", "~>3.2.12"
|
11
|
-
gem "sqlite3", :platform => [:ruby, :mswin, :mingw]
|
12
|
-
gem "capybara"
|
13
|
-
# gem "activerecord-jdbcsqlite3-adapter", :platform => :jruby
|
14
|
-
end
|