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
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
|