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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: fc82b1086314ce00c9bda47de03a897ecd59f1e3dca2f0b7617de586c572e129
|
4
|
+
data.tar.gz: dea3d79dfd532cf823f49eb22790c39aeffa5d273b3010763345f0ccb00fb201
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f489411ef1403569962e800e548e0511a258d1861b577c13d822d26a3d662e216694c213f43ba07898feabc47d2f5b9e6b3ac2b4df27a11a2826e97b07ea685f
|
7
|
+
data.tar.gz: b604ac58fe82f7d10077855f562665f93f7edf54261bc2f3556b9ed6fd7f378c5626dc9f7a0fad9218b8fa05802b4cc8d2a29023c20f6f18b760b4b8b66a816d
|
data/.travis.yml
CHANGED
@@ -1,12 +1,14 @@
|
|
1
1
|
rvm:
|
2
|
-
- 2.3
|
3
|
-
- 2.4
|
4
|
-
- 2.5
|
2
|
+
- 2.3
|
3
|
+
- 2.4
|
4
|
+
- 2.5
|
5
|
+
|
5
6
|
script: 'bundle exec rspec spec'
|
6
7
|
gemfile:
|
7
|
-
- Gemfile
|
8
8
|
- gemfiles/4.2.gemfile
|
9
9
|
- gemfiles/5.1.gemfile
|
10
|
+
- gemfiles/5.2.gemfile
|
11
|
+
|
10
12
|
# Move to containerized travis, see http://docs.travis-ci.com/user/migrating-from-legacy
|
11
13
|
sudo: false
|
12
14
|
cache: bundler
|
data/Changelog.md
CHANGED
@@ -1,8 +1,38 @@
|
|
1
|
+
### 2.1.0
|
2
|
+
|
3
|
+
Features:
|
4
|
+
* Refactor policies to seperate classes and add back the old policy for
|
5
|
+
backwards compatibility.
|
6
|
+
* Added `direct_fog_hash` method that can be used for returning json
|
7
|
+
|
8
|
+
Misc:
|
9
|
+
* Removed deprecated `key` methods.
|
10
|
+
* Removed deprecated `:with_path` option for `direct_fog_url`
|
11
|
+
|
12
|
+
### 2.0.0
|
13
|
+
|
14
|
+
Features:
|
15
|
+
* [BREAKING CHANGE] Add support for Carrierwave 1.x. Drops support for Carrierwave < 1.0 (Kevin Reintjes @kreintjes).
|
16
|
+
|
17
|
+
Misc:
|
18
|
+
* Dropped support for ruby 2.0 and 2.1, they have [reached their end of life](https://www.ruby-lang.org/en/news/2017/04/01/support-of-ruby-2-1-has-ended/)
|
19
|
+
* Update Ruby and Rails versions for Travis so builds succeed once again (Kevin Reintjes @kreintjes)
|
20
|
+
|
21
|
+
### 1.1.0
|
22
|
+
|
23
|
+
Deprecations:
|
24
|
+
* Calling `direct_fog_url` with `:with_path` is deprecated, please use `url` instead.
|
25
|
+
|
1
26
|
### 1.0.0
|
2
27
|
|
3
28
|
Features:
|
4
29
|
* 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
30
|
|
31
|
+
### 0.0.17
|
32
|
+
|
33
|
+
Misc:
|
34
|
+
* Pin carrierwave to 0.11
|
35
|
+
|
6
36
|
### 0.0.16
|
7
37
|
|
8
38
|
Bug Fixes:
|
data/README.md
CHANGED
@@ -280,7 +280,7 @@ If your upload was successful then you will be redirected to the `success_action
|
|
280
280
|
|
281
281
|
The `key` is the most important piece of information as we can use it for validating the file extension, downloading the file from S3, processing it and re-uploading it.
|
282
282
|
|
283
|
-
If you're using ActiveRecord, CarrierWaveDirect will by default validate the file extension based off your `
|
283
|
+
If you're using ActiveRecord, CarrierWaveDirect will by default validate the file extension based off your `extension_whitelist` in your uploader. See the [CarrierWave readme](https://github.com/jnicklas/carrierwave) for more info. You can then use the helper `filename_valid?` to check if the filename is valid. e.g.
|
284
284
|
|
285
285
|
```ruby
|
286
286
|
class UsersController < ApplicationController
|
@@ -326,7 +326,7 @@ Now that the basic building blocks are in place you can process and save your av
|
|
326
326
|
class User < ActiveRecord::Base
|
327
327
|
def save_and_process_avatar(options = {})
|
328
328
|
if options[:now]
|
329
|
-
self.remote_avatar_url = avatar.
|
329
|
+
self.remote_avatar_url = avatar.url
|
330
330
|
save
|
331
331
|
else
|
332
332
|
Resque.enqueue(AvatarProcessor, attributes)
|
@@ -363,7 +363,7 @@ Your users may find it convenient to upload a file from a location on the Intern
|
|
363
363
|
class User < ActiveRecord::Base
|
364
364
|
def save_and_process_avatar(options = {})
|
365
365
|
if options[:now]
|
366
|
-
self.remote_avatar_url = has_remote_avatar_net_url? ? remote_avatar_net_url : avatar.
|
366
|
+
self.remote_avatar_url = has_remote_avatar_net_url? ? remote_avatar_net_url : avatar.url
|
367
367
|
save
|
368
368
|
else
|
369
369
|
Resque.enqueue(AvatarProcessor, attributes)
|
@@ -399,13 +399,13 @@ Validates that the filename in the database is unique. Turned *on* by default
|
|
399
399
|
validates :avatar, :filename_format => true
|
400
400
|
```
|
401
401
|
|
402
|
-
Validates that the uploaded filename is valid. As well as validating the extension against the `
|
402
|
+
Validates that the uploaded filename is valid. As well as validating the extension against the `extension_whitelist` it also validates that the `upload_dir` is correct. Turned *on* by default
|
403
403
|
|
404
404
|
```ruby
|
405
405
|
validates :avatar, :remote_net_url_format => true
|
406
406
|
```
|
407
407
|
|
408
|
-
Validates that the remote net url is valid. As well as validating the extension against the `
|
408
|
+
Validates that the remote net url is valid. As well as validating the extension against the `extension_whitelist` it also validates that url is valid and has only the schemes specified in the `url_scheme_whitelist`. Turned *on* by default
|
409
409
|
|
410
410
|
## Configuration
|
411
411
|
|
@@ -521,7 +521,7 @@ Factory.define :user |f|
|
|
521
521
|
end
|
522
522
|
```
|
523
523
|
|
524
|
-
This will return a valid key based off your `upload_dir` and your `
|
524
|
+
This will return a valid key based off your `upload_dir` and your `extension_whitelist`
|
525
525
|
|
526
526
|
### Faking a background download
|
527
527
|
|
@@ -534,7 +534,7 @@ upload_path = find_upload_path
|
|
534
534
|
redirect_key = sample_key(:base => find_key, :filename => File.basename(upload_path))
|
535
535
|
|
536
536
|
uploader.key = redirect_key
|
537
|
-
download_url = uploader.
|
537
|
+
download_url = uploader.url
|
538
538
|
|
539
539
|
# Register the download url and return the uploaded file in the body
|
540
540
|
FakeWeb.register_uri(:get, download_url, :body => File.open(upload_path))
|
data/carrierwave_direct.gemspec
CHANGED
@@ -14,14 +14,15 @@ Gem::Specification.new do |s|
|
|
14
14
|
|
15
15
|
s.rubyforge_project = "carrierwave_direct"
|
16
16
|
|
17
|
-
s.add_dependency "carrierwave",
|
17
|
+
s.add_dependency "carrierwave", '>= 1.0.0'
|
18
18
|
s.add_dependency "fog-aws"
|
19
19
|
|
20
|
-
s.add_development_dependency "rspec"
|
20
|
+
s.add_development_dependency "rspec", '~> 3.0'
|
21
21
|
s.add_development_dependency "timecop"
|
22
22
|
s.add_development_dependency "rails", ">= 3.2.12"
|
23
23
|
s.add_development_dependency "sqlite3"
|
24
24
|
s.add_development_dependency "capybara"
|
25
|
+
s.add_development_dependency "byebug"
|
25
26
|
|
26
27
|
s.files = `git ls-files`.split("\n")
|
27
28
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
data/gemfiles/4.2.gemfile
CHANGED
data/gemfiles/5.1.gemfile
CHANGED
@@ -0,0 +1,13 @@
|
|
1
|
+
source "https://rubygems.org"
|
2
|
+
|
3
|
+
gem "carrierwave"
|
4
|
+
gem "fog-aws"
|
5
|
+
|
6
|
+
group :test do
|
7
|
+
gem "rspec", '~> 3.0'
|
8
|
+
gem "timecop"
|
9
|
+
gem "rails", "~>5.2.0"
|
10
|
+
gem "sqlite3", :platform => [:ruby, :mswin, :mingw]
|
11
|
+
gem "capybara"
|
12
|
+
# gem "activerecord-jdbcsqlite3-adapter", :platform => :jruby
|
13
|
+
end
|
@@ -5,19 +5,21 @@ module CarrierWaveDirect
|
|
5
5
|
def file_field(method, options = {})
|
6
6
|
@object.policy(enforce_utf8: true)
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
fields = required_base_fields
|
11
|
-
|
12
|
-
fields << content_type_field(options)
|
13
|
-
|
14
|
-
fields << success_action_field(options)
|
8
|
+
fields = hidden_fields(options)
|
15
9
|
|
16
10
|
# The file field must be the last element in the form.
|
17
11
|
# Any element after this will be ignored by Amazon.
|
12
|
+
options.merge!(:name => "file")
|
13
|
+
|
18
14
|
fields << super
|
19
15
|
end
|
20
16
|
|
17
|
+
def fields_except_file_field(options = {})
|
18
|
+
@object.policy(enforce_utf8: true)
|
19
|
+
|
20
|
+
hidden_fields(options)
|
21
|
+
end
|
22
|
+
|
21
23
|
def content_type_label(content=nil)
|
22
24
|
content ||= 'Content Type'
|
23
25
|
@template.label_tag('Content-Type', content)
|
@@ -29,14 +31,28 @@ module CarrierWaveDirect
|
|
29
31
|
|
30
32
|
private
|
31
33
|
|
34
|
+
def hidden_fields(options)
|
35
|
+
fields = required_base_fields
|
36
|
+
fields << content_type_field(options)
|
37
|
+
fields << success_action_field(options)
|
38
|
+
fields
|
39
|
+
end
|
40
|
+
|
32
41
|
def required_base_fields
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
42
|
+
fields = ''.html_safe
|
43
|
+
@object.direct_fog_hash(enforce_utf8: true).each do |key, value|
|
44
|
+
normalized_keys = {
|
45
|
+
'X-Amz-Signature': 'signature',
|
46
|
+
'X-Amz-Credential': 'credential',
|
47
|
+
'X-Amz-Algorithm': 'algorithm',
|
48
|
+
'X-Amz-Date': 'date'
|
49
|
+
}
|
50
|
+
id = "#{@template.dom_class(@object)}_#{normalized_keys[key] || key}"
|
51
|
+
if key != :uri
|
52
|
+
fields << @template.hidden_field_tag(key, value, id: id, required: false)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
fields
|
40
56
|
end
|
41
57
|
|
42
58
|
def content_type_field(options)
|
@@ -14,7 +14,7 @@ module CarrierWaveDirect
|
|
14
14
|
def #{column}; self; end
|
15
15
|
RUBY
|
16
16
|
end
|
17
|
-
|
17
|
+
|
18
18
|
self.instance_eval <<-RUBY, __FILE__, __LINE__+1
|
19
19
|
attr_accessor :remote_#{column}_net_url
|
20
20
|
RUBY
|
@@ -23,16 +23,6 @@ module CarrierWaveDirect
|
|
23
23
|
include mod
|
24
24
|
mod.class_eval <<-RUBY, __FILE__, __LINE__+1
|
25
25
|
|
26
|
-
def key
|
27
|
-
warn "key method is deprecated, please use column_key method instead."
|
28
|
-
send(:#{column}).key
|
29
|
-
end
|
30
|
-
|
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
26
|
def #{column}_key
|
37
27
|
send(:#{column}).key
|
38
28
|
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require "carrierwave_direct/policies/base"
|
2
|
+
|
3
|
+
module CarrierWaveDirect
|
4
|
+
module Policies
|
5
|
+
class Aws4HmacSha256 < Base
|
6
|
+
|
7
|
+
def direct_fog_hash(policy_options = {})
|
8
|
+
{
|
9
|
+
key: uploader.key,
|
10
|
+
acl: uploader.acl,
|
11
|
+
policy: policy(policy_options),
|
12
|
+
'X-Amz-Signature': signature,
|
13
|
+
'X-Amz-Credential': credential,
|
14
|
+
'X-Amz-Algorithm': algorithm,
|
15
|
+
'X-Amz-Date': date,
|
16
|
+
uri: uploader.direct_fog_url,
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
def date
|
21
|
+
timestamp.strftime("%Y%m%dT%H%M%SZ")
|
22
|
+
end
|
23
|
+
|
24
|
+
def generate(options, &block)
|
25
|
+
|
26
|
+
return @policy if @policy.present?
|
27
|
+
conditions = []
|
28
|
+
|
29
|
+
conditions << ["starts-with", "$utf8", ""] if options[:enforce_utf8]
|
30
|
+
conditions << ["starts-with", "$key", uploader.key.sub(/#{Regexp.escape(CarrierWaveDirect::Uploader::FILENAME_WILDCARD)}\z/, "")]
|
31
|
+
conditions << {'X-Amz-Algorithm' => algorithm}
|
32
|
+
conditions << {'X-Amz-Credential' => credential}
|
33
|
+
conditions << {'X-Amz-Date' => date }
|
34
|
+
conditions << ["starts-with", "$Content-Type", ""] if uploader.will_include_content_type
|
35
|
+
conditions << {"bucket" => uploader.fog_directory}
|
36
|
+
conditions << {"acl" => uploader.acl}
|
37
|
+
|
38
|
+
if uploader.use_action_status
|
39
|
+
conditions << {"success_action_status" => uploader.success_action_status}
|
40
|
+
else
|
41
|
+
conditions << {"success_action_redirect" => uploader.success_action_redirect}
|
42
|
+
end
|
43
|
+
|
44
|
+
conditions << ["content-length-range", options[:min_file_size], options[:max_file_size]]
|
45
|
+
|
46
|
+
yield conditions if block_given?
|
47
|
+
|
48
|
+
@policy = Base64.encode64(
|
49
|
+
{
|
50
|
+
'expiration' => (Time.now + options[:expiration]).utc.iso8601,
|
51
|
+
'conditions' => conditions
|
52
|
+
}.to_json
|
53
|
+
).gsub("\n","")
|
54
|
+
end
|
55
|
+
|
56
|
+
def credential
|
57
|
+
"#{uploader.aws_access_key_id}/#{timestamp.strftime("%Y%m%d")}/#{uploader.region}/s3/aws4_request"
|
58
|
+
end
|
59
|
+
|
60
|
+
def algorithm
|
61
|
+
'AWS4-HMAC-SHA256'
|
62
|
+
end
|
63
|
+
|
64
|
+
def clear!
|
65
|
+
super
|
66
|
+
@timestamp = nil
|
67
|
+
end
|
68
|
+
|
69
|
+
def signature
|
70
|
+
OpenSSL::HMAC.hexdigest(
|
71
|
+
'sha256',
|
72
|
+
signing_key,
|
73
|
+
policy
|
74
|
+
)
|
75
|
+
end
|
76
|
+
|
77
|
+
def signing_key(options = {})
|
78
|
+
#AWS Signature Version 4
|
79
|
+
kDate = OpenSSL::HMAC.digest('sha256', "AWS4" + uploader.aws_secret_access_key, timestamp.strftime("%Y%m%d"))
|
80
|
+
kRegion = OpenSSL::HMAC.digest('sha256', kDate, uploader.region)
|
81
|
+
kService = OpenSSL::HMAC.digest('sha256', kRegion, 's3')
|
82
|
+
kSigning = OpenSSL::HMAC.digest('sha256', kService, "aws4_request")
|
83
|
+
|
84
|
+
kSigning
|
85
|
+
end
|
86
|
+
|
87
|
+
def timestamp
|
88
|
+
@timestamp ||= Time.now.utc
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require "carrierwave_direct/policies/base"
|
2
|
+
|
3
|
+
module CarrierWaveDirect
|
4
|
+
module Policies
|
5
|
+
class AwsBase64Sha1 < Base
|
6
|
+
def signature
|
7
|
+
Base64.encode64(
|
8
|
+
OpenSSL::HMAC.digest(
|
9
|
+
OpenSSL::Digest.new('sha1'),
|
10
|
+
uploader.aws_secret_access_key, policy
|
11
|
+
)
|
12
|
+
).gsub("\n", "")
|
13
|
+
end
|
14
|
+
|
15
|
+
def direct_fog_hash(policy_options = {})
|
16
|
+
{
|
17
|
+
key: uploader.key,
|
18
|
+
AWSAccessKeyId: uploader.aws_access_key_id,
|
19
|
+
acl: uploader.acl,
|
20
|
+
policy: policy(policy_options),
|
21
|
+
signature: signature,
|
22
|
+
uri: uploader.direct_fog_url
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
def generate(options, &block)
|
27
|
+
|
28
|
+
return @policy if @policy.present?
|
29
|
+
conditions = []
|
30
|
+
|
31
|
+
conditions << ["starts-with", "$utf8", ""] if options[:enforce_utf8]
|
32
|
+
conditions << ["starts-with", "$key", uploader.key.sub(/#{Regexp.escape(CarrierWaveDirect::Uploader::FILENAME_WILDCARD)}\z/, "")]
|
33
|
+
conditions << ["starts-with", "$Content-Type", ""] if uploader.will_include_content_type
|
34
|
+
conditions << {"bucket" => uploader.fog_directory}
|
35
|
+
conditions << {"acl" => uploader.acl}
|
36
|
+
|
37
|
+
if uploader.use_action_status
|
38
|
+
conditions << {"success_action_status" => uploader.success_action_status}
|
39
|
+
else
|
40
|
+
conditions << {"success_action_redirect" => uploader.success_action_redirect}
|
41
|
+
end
|
42
|
+
|
43
|
+
conditions << ["content-length-range", options[:min_file_size], options[:max_file_size]]
|
44
|
+
|
45
|
+
yield conditions if block_given?
|
46
|
+
|
47
|
+
@policy = Base64.encode64(
|
48
|
+
{
|
49
|
+
'expiration' => (Time.now + options[:expiration]).utc.iso8601,
|
50
|
+
'conditions' => conditions
|
51
|
+
}.to_json
|
52
|
+
).gsub("\n","")
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module CarrierWaveDirect
|
2
|
+
module Policies
|
3
|
+
class Base
|
4
|
+
attr_reader :uploader
|
5
|
+
def initialize(uploader)
|
6
|
+
@uploader = uploader
|
7
|
+
end
|
8
|
+
|
9
|
+
def policy(options = {}, &block)
|
10
|
+
options[:expiration] ||= uploader.upload_expiration
|
11
|
+
options[:min_file_size] ||= uploader.min_file_size
|
12
|
+
options[:max_file_size] ||= uploader.max_file_size
|
13
|
+
@policy ||= generate(options, &block)
|
14
|
+
end
|
15
|
+
|
16
|
+
def clear!
|
17
|
+
@policy = nil
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|