carrierwave_direct 2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 2e621e1fb10f3bba48a832af319f33b716bd776f
4
- data.tar.gz: 23229444c9b6dd113103e936540595ce02043a85
2
+ SHA256:
3
+ metadata.gz: fc82b1086314ce00c9bda47de03a897ecd59f1e3dca2f0b7617de586c572e129
4
+ data.tar.gz: dea3d79dfd532cf823f49eb22790c39aeffa5d273b3010763345f0ccb00fb201
5
5
  SHA512:
6
- metadata.gz: d3aba2a7b886f6d49d29dc76be5a0de541809dc3056da4c56bf7c93cf35b5437f3b231cbed14b45773f024fcfbddcd08c27e771369a238ba442da780177db5c3
7
- data.tar.gz: 50b38cd5b7fe29eb7c0037390e712f3618ec68eb8e28d491bd2b0b9097c45b581698ff6e9573507cefa1aa58431a2900f92adf593ded249c87cd972b2936e6d7
6
+ metadata.gz: f489411ef1403569962e800e548e0511a258d1861b577c13d822d26a3d662e216694c213f43ba07898feabc47d2f5b9e6b3ac2b4df27a11a2826e97b07ea685f
7
+ data.tar.gz: b604ac58fe82f7d10077855f562665f93f7edf54261bc2f3556b9ed6fd7f378c5626dc9f7a0fad9218b8fa05802b4cc8d2a29023c20f6f18b760b4b8b66a816d
@@ -5,10 +5,10 @@ rvm:
5
5
 
6
6
  script: 'bundle exec rspec spec'
7
7
  gemfile:
8
- - Gemfile
9
8
  - gemfiles/4.2.gemfile
10
9
  - gemfiles/5.1.gemfile
11
-
10
+ - gemfiles/5.2.gemfile
11
+
12
12
  # Move to containerized travis, see http://docs.travis-ci.com/user/migrating-from-legacy
13
13
  sudo: false
14
14
  cache: bundler
@@ -1,3 +1,14 @@
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
+
1
12
  ### 2.0.0
2
13
 
3
14
  Features:
@@ -10,7 +21,7 @@ Misc:
10
21
  ### 1.1.0
11
22
 
12
23
  Deprecations:
13
- * Calling `direct_for_url` with `:with_path` is deprecated, please use `url` instead.
24
+ * Calling `direct_fog_url` with `:with_path` is deprecated, please use `url` instead.
14
25
 
15
26
  ### 1.0.0
16
27
 
data/README.md CHANGED
@@ -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.direct_fog_url(:with_path => true)
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)
@@ -17,7 +17,7 @@ Gem::Specification.new do |s|
17
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"
@@ -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
- options.merge!(:name => "file")
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
- hidden_field(:key, :name => "key") <<
34
- hidden_field(:acl, :name => "acl") <<
35
- hidden_field(:policy, :name => "policy") <<
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")
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
@@ -2,7 +2,8 @@
2
2
 
3
3
  require "securerandom"
4
4
  require "carrierwave_direct/uploader/content_type"
5
- require "carrierwave_direct/uploader/direct_url"
5
+ require "carrierwave_direct/policies/aws_base64_sha1"
6
+ require "carrierwave_direct/policies/aws4_hmac_sha256"
6
7
 
7
8
  module CarrierWaveDirect
8
9
  module Uploader
@@ -24,7 +25,6 @@ module CarrierWaveDirect
24
25
  end
25
26
 
26
27
  include CarrierWaveDirect::Uploader::ContentType
27
- include CarrierWaveDirect::Uploader::DirectUrl
28
28
 
29
29
  #ensure that region returns something. Since sig v4 it is required in the signing key & credentials
30
30
  def region
@@ -36,40 +36,27 @@ module CarrierWaveDirect
36
36
  end
37
37
 
38
38
  def policy(options = {}, &block)
39
- options[:expiration] ||= upload_expiration
40
- options[:min_file_size] ||= min_file_size
41
- options[:max_file_size] ||= max_file_size
42
-
43
- @date ||= Time.now.utc.strftime("%Y%m%d")
44
- @timestamp ||= Time.now.utc.strftime("%Y%m%dT%H%M%SZ")
45
- @policy ||= generate_policy(options, &block)
39
+ signing_policy.policy(options, &block)
46
40
  end
47
41
 
48
42
  def date
49
- @timestamp ||= Time.now.utc.strftime("%Y%m%dT%H%M%SZ")
43
+ signing_policy.date
50
44
  end
51
45
 
52
46
  def algorithm
53
- 'AWS4-HMAC-SHA256'
47
+ signing_policy.algorithm
54
48
  end
55
49
 
56
50
  def credential
57
- @date ||= Time.now.utc.strftime("%Y%m%d")
58
- "#{aws_access_key_id}/#{@date}/#{region}/s3/aws4_request"
51
+ signing_policy.credential
59
52
  end
60
53
 
61
54
  def clear_policy!
62
- @policy = nil
63
- @date = nil
64
- @timestamp = nil
55
+ signing_policy.clear!
65
56
  end
66
57
 
67
58
  def signature
68
- OpenSSL::HMAC.hexdigest(
69
- 'sha256',
70
- signing_key,
71
- policy
72
- )
59
+ signing_policy.signature
73
60
  end
74
61
 
75
62
  def url_scheme_white_list
@@ -80,13 +67,22 @@ module CarrierWaveDirect
80
67
  false
81
68
  end
82
69
 
70
+ def signing_policy_class
71
+ @signing_policy_class ||= Policies::Aws4HmacSha256
72
+ end
73
+
74
+ def signing_policy_class=(signing_policy_class)
75
+ @signing_policy_class = signing_policy_class
76
+ end
77
+
83
78
  def key
84
79
  return @key if @key.present?
85
80
  if present?
86
81
  identifier = model.send("#{mounted_as}_identifier")
87
- self.key = "#{store_dir}/#{identifier}"
82
+ self.key = [store_dir, identifier].join("/")
88
83
  else
89
- @key = "#{store_dir}/#{guid}/#{FILENAME_WILDCARD}"
84
+ guid = SecureRandom.uuid
85
+ @key = [store_dir, guid, FILENAME_WILDCARD].join("/")
90
86
  end
91
87
  @key
92
88
  end
@@ -96,10 +92,6 @@ module CarrierWaveDirect
96
92
  update_version_keys(:with => @key)
97
93
  end
98
94
 
99
- def guid
100
- SecureRandom.uuid
101
- end
102
-
103
95
  def has_key?
104
96
  key !~ /#{Regexp.escape(FILENAME_WILDCARD)}\z/
105
97
  end
@@ -117,27 +109,37 @@ module CarrierWaveDirect
117
109
  unless has_key?
118
110
  # Use the attached models remote url to generate a new key otherwise return nil
119
111
  remote_url = model.send("remote_#{mounted_as}_url")
120
- remote_url ? key_from_file(CarrierWave::SanitizedFile.new(remote_url).filename) : return
112
+ if remote_url
113
+ key_from_file(CarrierWave::SanitizedFile.new(remote_url).filename)
114
+ else
115
+ return
116
+ end
121
117
  end
122
118
 
123
- key_path = key.split("/")
119
+ key_parts = key.split("/")
120
+ filename = key_parts.pop
121
+ guid = key_parts.pop
122
+
124
123
  filename_parts = []
125
- filename_parts.unshift(key_path.pop)
126
- unique_key = key_path.pop
127
- filename_parts.unshift(unique_key) if unique_key
124
+ filename_parts << guid if guid
125
+ filename_parts << filename
128
126
  filename_parts.join("/")
129
127
  end
130
128
 
131
- private
129
+ def direct_fog_url
130
+ CarrierWave::Storage::Fog::File.new(self, CarrierWave::Storage::Fog.new(self), nil).public_url
131
+ end
132
132
 
133
- def decoded_key
134
- URI.decode(URI.parse(url).path[1 .. -1])
133
+ def direct_fog_hash(policy_options = {})
134
+ signing_policy.direct_fog_hash(policy_options)
135
135
  end
136
136
 
137
- def key_from_file(fname)
137
+ private
138
+
139
+ def key_from_file(filename)
138
140
  new_key_parts = key.split("/")
139
141
  new_key_parts.pop
140
- new_key_parts << fname
142
+ new_key_parts << filename
141
143
  self.key = new_key_parts.join("/")
142
144
  end
143
145
 
@@ -155,45 +157,8 @@ module CarrierWaveDirect
155
157
  [for_file.chomp(extname), version_name].compact.join('_') << extname
156
158
  end
157
159
 
158
- def generate_policy(options)
159
- conditions = []
160
-
161
- conditions << ["starts-with", "$utf8", ""] if options[:enforce_utf8]
162
- conditions << ["starts-with", "$key", key.sub(/#{Regexp.escape(FILENAME_WILDCARD)}\z/, "")]
163
- conditions << {'X-Amz-Algorithm' => algorithm}
164
- conditions << {'X-Amz-Credential' => credential}
165
- conditions << {'X-Amz-Date' => date}
166
- conditions << ["starts-with", "$Content-Type", ""] if will_include_content_type
167
- conditions << {"bucket" => fog_directory}
168
- conditions << {"acl" => acl}
169
-
170
- if use_action_status
171
- conditions << {"success_action_status" => success_action_status}
172
- else
173
- conditions << {"success_action_redirect" => success_action_redirect}
174
- end
175
-
176
- conditions << ["content-length-range", options[:min_file_size], options[:max_file_size]]
177
-
178
- yield conditions if block_given?
179
-
180
- Base64.encode64(
181
- {
182
- 'expiration' => (Time.now + options[:expiration]).utc.iso8601,
183
- 'conditions' => conditions
184
- }.to_json
185
- ).gsub("\n","")
186
- end
187
-
188
- def signing_key(options = {})
189
- @date ||= Time.now.utc.strftime("%Y%m%d")
190
- #AWS Signature Version 4
191
- kDate = OpenSSL::HMAC.digest('sha256', "AWS4" + aws_secret_access_key, @date)
192
- kRegion = OpenSSL::HMAC.digest('sha256', kDate, region)
193
- kService = OpenSSL::HMAC.digest('sha256', kRegion, 's3')
194
- kSigning = OpenSSL::HMAC.digest('sha256', kService, "aws4_request")
195
-
196
- kSigning
160
+ def signing_policy
161
+ @signing_policy ||= signing_policy_class.new(self)
197
162
  end
198
163
  end
199
164
  end