carrierwave_direct 2.0.0 → 2.1.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
- 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