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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4f9e56f05064fcec0e706c91c80c85c5e4bdbf93
4
- data.tar.gz: 0f8c4b55fc49a71f4e4a8ac5992e82a684ffb99b
3
+ metadata.gz: b64419d902b8c1afba920fafe9a7029dd4c3d94a
4
+ data.tar.gz: 5dfbb28ea14db2c7ae9bd665192c009534cbef90
5
5
  SHA512:
6
- metadata.gz: 47fe09989e7dba3b47476aaa6c3137e2d01f9809778ff3763a3121c922bc0690816593add6a3a625be6174e9e0f2c00e1b8d9221372e4a9890953cc28e0d8a1a
7
- data.tar.gz: ae5b467e4542cd5940df6aca828396b82eb0df9647a0b283ae4abf7c3babdf862041c46a76290f5081bd70c78fe1772a6cda347d3c550d56d415582c000b0ca2
6
+ metadata.gz: c8f39ac6ced22656b3a96821356d92333f9ca141f215bb66125b3d2a8fa282718341adb133b0baa33308f9268cf1ef2014e59e3e21bb1f7949a389f170b4c1be
7
+ data.tar.gz: b2e2fe378dfed399fc011fb4ebcb8a94d5d4ffe4cb4c982ed71b918aa53fa7767a1b1c6d226e6fda5ad2169af24af2a43c83b80b300650367ad49aa0e6faa9d6
data/.travis.yml CHANGED
@@ -1,12 +1,12 @@
1
1
  rvm:
2
- - 1.9.3
3
- - 2.0.0
4
- - 2.1.0
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/3.2.gemfile
11
- - gemfiles/4.0.gemfile
12
- - gemfiles/4.1.gemfile
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 => "signature", :value => @uploader.signature}
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 :key, params[:key]
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`
@@ -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 = ">= 1.9.0"
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 "uuidtools"
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 "uuidtools"
5
- gem "fog"
3
+ gem "carrierwave", "~>0.11"
4
+ gem "fog-aws"
6
5
 
7
6
  group :test do
8
- gem "rspec", '3.0.0'
7
+ gem "rspec", '~> 3.0'
9
8
  gem "timecop"
10
- gem "rails", "~>4.0.0"
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 "uuidtools"
5
- gem "fog"
3
+ gem "carrierwave", "~>0.11"
4
+ gem "fog-aws"
6
5
 
7
6
  group :test do
8
- gem "rspec", '3.0.0'
7
+ gem "rspec", '~> 3.0'
9
8
  gem "timecop"
10
- gem "rails", "~>4.1.0"
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 => "signature")
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.class_eval <<-RUBY, __FILE__, __LINE__+1
13
- def #{column}; self; end
14
- RUBY
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 :key, :remote_#{column}_net_url
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
- @policy ||= generate_policy(options)
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
- Base64.encode64(
46
- OpenSSL::HMAC.digest(
47
- OpenSSL::Digest.new('sha1'),
48
- aws_secret_access_key, policy
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
- self.key = decoded_key # explicitly set key
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
- UUIDTools::UUID.random_create
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.utc + options[:expiration],
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.key !~ record.send(attribute).key_regexp
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
 
@@ -1,6 +1,6 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  module CarrierwaveDirect
4
- VERSION = "0.0.15"
4
+ VERSION = "1.0.0"
5
5
  end
6
6
 
@@ -1,8 +1,7 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  require "carrierwave"
4
- require "uuidtools"
5
- require "fog"
4
+ require "fog/aws"
6
5
 
7
6
  module CarrierWaveDirect
8
7
 
@@ -12,11 +12,13 @@ end
12
12
  shared_examples_for 'hidden values form' do
13
13
  hidden_fields = [
14
14
  :key,
15
- {:aws_access_key_id => "AWSAccessKeyId"},
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
- {:aws_access_key_id => "AWSAccessKeyId"},
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
- {:aws_access_key_id => "AWSAccessKeyId"},
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(:key, :to => "video#key", :accessible => { "has_video_upload?" => false })
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
- class TestMigration < ActiveRecord::Migration
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.key = upload_path
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.non_existing_column.key = sample_key}
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.key = nil
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.key = ""
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.key = sample_key(:extension => "avi")
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.key = sample_key(:extension => "mp3")
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.key = sample_key
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(:key => "some key").key.should == "some key"
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.key = sample_key(:model_class => subject.class)
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.key = sample_key(:model_class => subject.class, :valid => false) }
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
- class OtherTestMigration < ActiveRecord::Migration
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
@@ -10,7 +10,7 @@ module ViewHelpers
10
10
  end
11
11
 
12
12
  def have_parent_selector(options = {})
13
- have_selector(:xpath, parent_selector_xpath, options)
13
+ have_selector(:xpath, parent_selector_xpath, options.merge(visible: false))
14
14
  end
15
15
 
16
16
  def parent_selector_xpath
@@ -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
-
@@ -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
- def decoded_policy(options = {})
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
- eql(
321
- Time.parse(
322
- JSON.parse({
323
- "expiry" => Time.now + expires_in
324
- }.to_json)["expiry"]
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
- # Rails form builder conditions
357
- it "'utf8'" do
358
- expect(conditions).to have_condition(:utf8)
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 base64 encoded 'sha1' hash of the secret key and policy document" do
471
- expect(Base64.decode64(subject.signature)).to eq OpenSSL::HMAC.digest(
472
- OpenSSL::Digest.new('sha1'),
473
- subject.aws_secret_access_key, subject.policy
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.15
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: 2015-02-25 00:00:00.000000000 Z
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/3.2.gemfile
141
- - gemfiles/4.0.gemfile
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: 1.9.0
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.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