carrierwave 1.2.3 → 1.3.2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of carrierwave might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: e37b68386a3a7becb2363f72f3ce38e8b9049a9a
4
- data.tar.gz: 5391ed9991a220136287ad472d243c0ee5164492
2
+ SHA256:
3
+ metadata.gz: d5e6d1dd656203f5e14c43b75b807e793d623126006ddf8c5a4f9f4706faa750
4
+ data.tar.gz: 82281b939837f54716f580a1deb6397d87cc9bb867dc6a6938a4322d795500b1
5
5
  SHA512:
6
- metadata.gz: 2cfc444237e06625db981b6a502847d9a64bd52dc7a7fd4a5189ffc878914fdf7f252d504b54b49d13cb63b2c7d90afdbabaee3b6fb482a3c8bcec49546a51da
7
- data.tar.gz: 637ee1e7a31c735ff3b9fd7035e7cc897e8acfc610eadeb8c96de778c9b8c64d4a9bcb2e80fe1ed63454e35a029a8ea8224eb3022a748f8a8caa134b9f2048c3
6
+ metadata.gz: 8eca3a53204f520d0cabf6e2384e6670cb634159e4b6c1e8d3915b6bab8473f21fb116047129b142a986588ea27401131d095186657770d7c31b03d6c929a1c9
7
+ data.tar.gz: 316797cffad6d2568e50929862cd80ba3e56c05d557f70f8631b66fc60ffd65fe5862afe4121a1e5e775e55a5f6c9a6c14414bce6a57deab2d12a8a127ed5b0d
data/README.md CHANGED
@@ -89,7 +89,7 @@ a migration:
89
89
 
90
90
 
91
91
  rails g migration add_avatar_to_users avatar:string
92
- rake db:migrate
92
+ rails db:migrate
93
93
 
94
94
  Open your model file and mount the uploader:
95
95
 
@@ -144,12 +144,12 @@ example, create a migration like this:
144
144
  #### For databases with ActiveRecord json data type support (e.g. PostgreSQL, MySQL)
145
145
 
146
146
  rails g migration add_avatars_to_users avatars:json
147
- rake db:migrate
147
+ rails db:migrate
148
148
 
149
149
  #### For database without ActiveRecord json data type support (e.g. SQLite)
150
150
 
151
151
  rails g migration add_avatars_to_users avatars:string
152
- rake db:migrate
152
+ rails db:migrate
153
153
 
154
154
  __Note__: JSON datatype doesn't exists in SQLite adapter, that's why you can use a string datatype which will be serialized in model.
155
155
 
@@ -163,6 +163,9 @@ class User < ActiveRecord::Base
163
163
  end
164
164
  ```
165
165
 
166
+ Make sure that you mount the uploader with write (mount_uploaders) with `s` not (mount_uploader)
167
+ in order to avoid errors when uploading multiple files
168
+
166
169
  Make sure your file input fields are set up as multiple file fields. For
167
170
  example in Rails you'll want to do something like this:
168
171
 
@@ -923,7 +926,7 @@ errors:
923
926
  carrierwave_download_error: could not be downloaded
924
927
  extension_whitelist_error: "You are not allowed to upload %{extension} files, allowed types: %{allowed_types}"
925
928
  extension_blacklist_error: "You are not allowed to upload %{extension} files, prohibited types: %{prohibited_types}"
926
- content_type_whitelist_error: "You are not allowed to upload %{content_type} files"
929
+ content_type_whitelist_error: "You are not allowed to upload %{content_type} files, allowed types: %{allowed_types}"
927
930
  content_type_blacklist_error: "You are not allowed to upload %{content_type} files"
928
931
  rmagick_processing_error: "Failed to manipulate with rmagick, maybe it is not an image?"
929
932
  mini_magick_processing_error: "Failed to manipulate with MiniMagick, maybe it is not an image? Original Error: %{e}"
@@ -6,7 +6,7 @@ en:
6
6
  carrierwave_download_error: could not be downloaded
7
7
  extension_whitelist_error: "You are not allowed to upload %{extension} files, allowed types: %{allowed_types}"
8
8
  extension_blacklist_error: "You are not allowed to upload %{extension} files, prohibited types: %{prohibited_types}"
9
- content_type_whitelist_error: "You are not allowed to upload %{content_type} files"
9
+ content_type_whitelist_error: "You are not allowed to upload %{content_type} files, allowed types: %{allowed_types}"
10
10
  content_type_blacklist_error: "You are not allowed to upload %{content_type} files"
11
11
  rmagick_processing_error: "Failed to manipulate with rmagick, maybe it is not an image?"
12
12
  mini_magick_processing_error: "Failed to manipulate with MiniMagick, maybe it is not an image? Original Error: %{e}"
@@ -341,11 +341,7 @@ module CarrierWave
341
341
  end
342
342
 
343
343
  def mini_magick_image
344
- if url
345
- ::MiniMagick::Image.open(url)
346
- else
347
- ::MiniMagick::Image.open(current_path)
348
- end
344
+ ::MiniMagick::Image.read(read)
349
345
  end
350
346
 
351
347
  end # MiniMagick
@@ -378,9 +378,15 @@ module CarrierWave
378
378
 
379
379
  def create_info_block(options)
380
380
  return nil unless options
381
- assignments = options.map { |k, v| "self.#{k} = #{v}" }
382
- code = "lambda { |img| " + assignments.join(";") + "}"
383
- eval code
381
+ proc do |img|
382
+ options.each do |k, v|
383
+ if v.is_a?(String) && (matches = v.match(/^["'](.+)["']/))
384
+ ActiveSupport::Deprecation.warn "Passing quoted strings like #{v} to #manipulate! is deprecated, pass them without quoting."
385
+ v = matches[1]
386
+ end
387
+ img.public_send(:"#{k}=", v)
388
+ end
389
+ end
384
390
  end
385
391
 
386
392
  def destroy_image(image)
@@ -114,12 +114,11 @@ module CarrierWave
114
114
  # [String, nil] the path where the file is located.
115
115
  #
116
116
  def path
117
- unless @file.blank?
118
- if is_path?
119
- File.expand_path(@file)
120
- elsif @file.respond_to?(:path) and not @file.path.blank?
121
- File.expand_path(@file.path)
122
- end
117
+ return if @file.blank?
118
+ if is_path?
119
+ File.expand_path(@file)
120
+ elsif @file.respond_to?(:path) && !@file.path.blank?
121
+ File.expand_path(@file.path)
123
122
  end
124
123
  end
125
124
 
@@ -313,7 +312,7 @@ module CarrierWave
313
312
  def mkdir!(path, directory_permissions)
314
313
  options = {}
315
314
  options[:mode] = directory_permissions if directory_permissions
316
- FileUtils.mkdir_p(File.dirname(path), options) unless File.exist?(File.dirname(path))
315
+ FileUtils.mkdir_p(File.dirname(path), **options) unless File.exist?(File.dirname(path))
317
316
  end
318
317
 
319
318
  def chmod!(path, permissions)
@@ -66,7 +66,7 @@ module CarrierWave
66
66
  #
67
67
  def cache!(new_file)
68
68
  new_file.move_to(::File.expand_path(uploader.cache_path, uploader.root), uploader.permissions, uploader.directory_permissions, true)
69
- rescue Errno::EMLINK => e
69
+ rescue Errno::EMLINK, Errno::ENOSPC => e
70
70
  raise(e) if @cache_called
71
71
  @cache_called = true
72
72
 
@@ -177,7 +177,7 @@ module CarrierWave
177
177
 
178
178
  ##
179
179
  # Return a temporary authenticated url to a private file, if available
180
- # Only supported for AWS, Rackspace and Google providers
180
+ # Only supported for AWS, Rackspace, Google and AzureRM providers
181
181
  #
182
182
  # === Returns
183
183
  #
@@ -186,18 +186,22 @@ module CarrierWave
186
186
  # [NilClass] no authenticated url available
187
187
  #
188
188
  def authenticated_url(options = {})
189
- if ['AWS', 'Google', 'Rackspace', 'OpenStack'].include?(@uploader.fog_credentials[:provider])
189
+ if ['AWS', 'Google', 'Rackspace', 'OpenStack', 'AzureRM'].include?(@uploader.fog_credentials[:provider])
190
190
  # avoid a get by using local references
191
191
  local_directory = connection.directories.new(:key => @uploader.fog_directory)
192
192
  local_file = local_directory.files.new(:key => path)
193
193
  expire_at = ::Fog::Time.now + @uploader.fog_authenticated_url_expiration
194
194
  case @uploader.fog_credentials[:provider]
195
- when 'AWS'
196
- local_file.url(expire_at, options)
197
- when 'Rackspace'
195
+ when 'AWS', 'Google'
196
+ # Older versions of fog-google do not support options as a parameter
197
+ if url_options_supported?(local_file)
198
+ local_file.url(expire_at, options)
199
+ else
200
+ warn "Options hash not supported in #{local_file.class}. You may need to upgrade your Fog provider."
201
+ local_file.url(expire_at)
202
+ end
203
+ when 'Rackspace', 'OpenStack'
198
204
  connection.get_object_https_url(@uploader.fog_directory, path, expire_at, options)
199
- when 'OpenStack'
200
- connection.get_object_https_url(@uploader.fog_directory, path, expire_at)
201
205
  else
202
206
  local_file.url(expire_at)
203
207
  end
@@ -352,15 +356,19 @@ module CarrierWave
352
356
  end
353
357
  else
354
358
  # AWS/Google optimized for speed over correctness
355
- case @uploader.fog_credentials[:provider].to_s
359
+ case fog_provider
356
360
  when 'AWS'
357
361
  # check if some endpoint is set in fog_credentials
358
362
  if @uploader.fog_credentials.has_key?(:endpoint)
359
363
  "#{@uploader.fog_credentials[:endpoint]}/#{@uploader.fog_directory}/#{encoded_path}"
360
364
  else
361
365
  protocol = @uploader.fog_use_ssl_for_aws ? "https" : "http"
366
+
367
+ subdomain_regex = /^(?:[a-z]|\d(?!\d{0,2}(?:\d{1,3}){3}$))(?:[a-z0-9\.]|(?![\-])|\-(?![\.])){1,61}[a-z0-9]$/
368
+ valid_subdomain = @uploader.fog_directory.to_s =~ subdomain_regex && !(protocol == 'https' && @uploader.fog_directory =~ /\./)
369
+
362
370
  # if directory is a valid subdomain, use that style for access
363
- if @uploader.fog_directory.to_s =~ /^(?:[a-z]|\d(?!\d{0,2}(?:\d{1,3}){3}$))(?:[a-z0-9\.]|(?![\-])|\-(?![\.])){1,61}[a-z0-9]$/
371
+ if valid_subdomain
364
372
  s3_subdomain = @uploader.fog_aws_accelerate ? "s3-accelerate" : "s3"
365
373
  "#{protocol}://#{@uploader.fog_directory}.#{s3_subdomain}.amazonaws.com/#{encoded_path}"
366
374
  else
@@ -466,7 +474,15 @@ module CarrierWave
466
474
  end
467
475
 
468
476
  def acl_header
469
- {'x-amz-acl' => @uploader.fog_public ? 'public-read' : 'private'}
477
+ if fog_provider == 'AWS'
478
+ { 'x-amz-acl' => @uploader.fog_public ? 'public-read' : 'private' }
479
+ else
480
+ {}
481
+ end
482
+ end
483
+
484
+ def fog_provider
485
+ @uploader.fog_credentials[:provider].to_s
470
486
  end
471
487
 
472
488
  def read_source_file(file_body)
@@ -479,6 +495,11 @@ module CarrierWave
479
495
  file_body.close
480
496
  end
481
497
  end
498
+
499
+ def url_options_supported?(local_file)
500
+ parameters = local_file.method(:url).parameters
501
+ parameters.count == 2 && parameters[1].include?(:options)
502
+ end
482
503
  end
483
504
 
484
505
  end # Fog
@@ -35,7 +35,7 @@ module CarrierWave
35
35
  def check_content_type_whitelist!(new_file)
36
36
  content_type = new_file.content_type
37
37
  if content_type_whitelist && !whitelisted_content_type?(content_type)
38
- raise CarrierWave::IntegrityError, I18n.translate(:"errors.messages.content_type_whitelist_error", content_type: content_type)
38
+ raise CarrierWave::IntegrityError, I18n.translate(:"errors.messages.content_type_whitelist_error", content_type: content_type, allowed_types: Array(content_type_whitelist).join(", "))
39
39
  end
40
40
  end
41
41
 
@@ -1,4 +1,5 @@
1
1
  require 'open-uri'
2
+ require 'ssrf_filter'
2
3
 
3
4
  module CarrierWave
4
5
  module Uploader
@@ -10,15 +11,18 @@ module CarrierWave
10
11
  include CarrierWave::Uploader::Cache
11
12
 
12
13
  class RemoteFile
13
- def initialize(uri, remote_headers = {})
14
+ attr_reader :uri
15
+
16
+ def initialize(uri, remote_headers = {}, skip_ssrf_protection: false)
14
17
  @uri = uri
15
- @remote_headers = remote_headers
16
- @file = nil
18
+ @remote_headers = remote_headers.reverse_merge('User-Agent' => "CarrierWave/#{CarrierWave::VERSION}")
19
+ @file, @content_type, @headers = nil
20
+ @skip_ssrf_protection = skip_ssrf_protection
17
21
  end
18
22
 
19
23
  def original_filename
20
24
  filename = filename_from_header || filename_from_uri
21
- mime_type = MIME::Types[file.content_type].first
25
+ mime_type = MIME::Types[content_type].first
22
26
  unless File.extname(filename).present? || mime_type.blank?
23
27
  filename = "#{filename}.#{mime_type.extensions.first}"
24
28
  end
@@ -33,15 +37,35 @@ module CarrierWave
33
37
  @uri.scheme =~ /^https?$/
34
38
  end
35
39
 
36
- private
40
+ def content_type
41
+ @content_type || 'application/octet-stream'
42
+ end
43
+
44
+ def headers
45
+ @headers || {}
46
+ end
47
+
48
+ private
37
49
 
38
50
  def file
39
51
  if @file.blank?
40
- headers = @remote_headers.
41
- reverse_merge('User-Agent' => "CarrierWave/#{CarrierWave::VERSION}")
42
-
43
- @file = Kernel.open(@uri.to_s, headers)
44
- @file = @file.is_a?(String) ? StringIO.new(@file) : @file
52
+ if @skip_ssrf_protection
53
+ @file = (URI.respond_to?(:open) ? URI : Kernel).open(@uri.to_s, @remote_headers)
54
+ @file = @file.is_a?(String) ? StringIO.new(@file) : @file
55
+ @content_type = @file.content_type
56
+ @headers = @file.meta
57
+ @uri = @file.base_uri
58
+ else
59
+ request = nil
60
+ response = SsrfFilter.get(@uri, headers: @remote_headers) do |req|
61
+ request = req
62
+ end
63
+ response.value
64
+ @file = StringIO.new(response.body)
65
+ @content_type = response.content_type
66
+ @headers = response
67
+ @uri = request.uri
68
+ end
45
69
  end
46
70
  @file
47
71
 
@@ -50,14 +74,14 @@ module CarrierWave
50
74
  end
51
75
 
52
76
  def filename_from_header
53
- if file.meta.include? 'content-disposition'
54
- match = file.meta['content-disposition'].match(/filename="?([^"]+)/)
77
+ if headers['content-disposition']
78
+ match = headers['content-disposition'].match(/filename="?([^"]+)/)
55
79
  return match[1] unless match.nil? || match[1].empty?
56
80
  end
57
81
  end
58
82
 
59
83
  def filename_from_uri
60
- URI.decode(File.basename(file.base_uri.path))
84
+ URI::DEFAULT_PARSER.unescape(File.basename(@uri.path))
61
85
  end
62
86
 
63
87
  def method_missing(*args, &block)
@@ -75,7 +99,7 @@ module CarrierWave
75
99
  #
76
100
  def download!(uri, remote_headers = {})
77
101
  processed_uri = process_uri(uri)
78
- file = RemoteFile.new(processed_uri, remote_headers)
102
+ file = RemoteFile.new(processed_uri, remote_headers, skip_ssrf_protection: skip_ssrf_protection?(processed_uri))
79
103
  raise CarrierWave::DownloadError, "trying to download a file which is not served over HTTP" unless file.http?
80
104
  cache!(file)
81
105
  end
@@ -92,11 +116,30 @@ module CarrierWave
92
116
  rescue URI::InvalidURIError
93
117
  uri_parts = uri.split('?')
94
118
  # regexp from Ruby's URI::Parser#regexp[:UNSAFE], with [] specifically removed
95
- encoded_uri = URI.encode(uri_parts.shift, /[^\-_.!~*'()a-zA-Z\d;\/?:@&=+$,]/)
96
- encoded_uri << '?' << URI.encode(uri_parts.join('?')) if uri_parts.any?
119
+ encoded_uri = URI::DEFAULT_PARSER.escape(uri_parts.shift, /[^\-_.!~*'()a-zA-Z\d;\/?:@&=+$,]/)
120
+ encoded_uri << '?' << URI::DEFAULT_PARSER.escape(uri_parts.join('?')) if uri_parts.any?
97
121
  URI.parse(encoded_uri) rescue raise CarrierWave::DownloadError, "couldn't parse URL"
98
122
  end
99
123
 
124
+ ##
125
+ # If this returns true, SSRF protection will be bypassed.
126
+ # You can override this if you want to allow accessing specific local URIs that are not SSRF exploitable.
127
+ #
128
+ # === Parameters
129
+ #
130
+ # [uri (URI)] The URI where the remote file is stored
131
+ #
132
+ # === Examples
133
+ #
134
+ # class MyUploader < CarrierWave::Uploader::Base
135
+ # def skip_ssrf_protection?(uri)
136
+ # uri.hostname == 'localhost' && uri.port == 80
137
+ # end
138
+ # end
139
+ #
140
+ def skip_ssrf_protection?(uri)
141
+ false
142
+ end
100
143
  end # Download
101
144
  end # Uploader
102
145
  end # CarrierWave
@@ -1,3 +1,3 @@
1
1
  module CarrierWave
2
- VERSION = "1.2.3"
2
+ VERSION = "1.3.2"
3
3
  end
data/lib/carrierwave.rb CHANGED
@@ -34,6 +34,26 @@ if defined?(Merb)
34
34
  Dir.glob(File.join(Merb.load_paths[:uploaders])).each {|f| require f }
35
35
  end
36
36
 
37
+ elsif defined?(Jets)
38
+
39
+ module CarrierWave
40
+ class Turbine < Jets::Turbine
41
+ initializer "carrierwave.setup_paths" do |app|
42
+ CarrierWave.root = Jets.root.to_s
43
+ CarrierWave.tmp_path = "/tmp/carrierwave"
44
+ CarrierWave.configure do |config|
45
+ config.cache_dir = "/tmp/carrierwave/uploads/tmp"
46
+ end
47
+ end
48
+
49
+ initializer "carrierwave.active_record" do
50
+ ActiveSupport.on_load :active_record do
51
+ require 'carrierwave/orm/activerecord'
52
+ end
53
+ end
54
+ end
55
+ end
56
+
37
57
  elsif defined?(Rails)
38
58
 
39
59
  module CarrierWave
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: carrierwave
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.3
4
+ version: 1.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jonas Nicklas
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-06-30 00:00:00.000000000 Z
11
+ date: 2021-02-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '1.16'
55
+ - !ruby/object:Gem::Dependency
56
+ name: ssrf_filter
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.0'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: pg
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -140,16 +154,16 @@ dependencies:
140
154
  name: fog-google
141
155
  requirement: !ruby/object:Gem::Requirement
142
156
  requirements:
143
- - - "<="
157
+ - - "~>"
144
158
  - !ruby/object:Gem::Version
145
- version: 0.1.0
159
+ version: 1.7.1
146
160
  type: :development
147
161
  prerelease: false
148
162
  version_requirements: !ruby/object:Gem::Requirement
149
163
  requirements:
150
- - - "<="
164
+ - - "~>"
151
165
  - !ruby/object:Gem::Version
152
- version: 0.1.0
166
+ version: 1.7.1
153
167
  - !ruby/object:Gem::Dependency
154
168
  name: fog-local
155
169
  requirement: !ruby/object:Gem::Requirement
@@ -196,16 +210,16 @@ dependencies:
196
210
  name: rmagick
197
211
  requirement: !ruby/object:Gem::Requirement
198
212
  requirements:
199
- - - ">="
213
+ - - "~>"
200
214
  - !ruby/object:Gem::Version
201
- version: '0'
215
+ version: '2.16'
202
216
  type: :development
203
217
  prerelease: false
204
218
  version_requirements: !ruby/object:Gem::Requirement
205
219
  requirements:
206
- - - ">="
220
+ - - "~>"
207
221
  - !ruby/object:Gem::Version
208
- version: '0'
222
+ version: '2.16'
209
223
  - !ruby/object:Gem::Dependency
210
224
  name: timecop
211
225
  requirement: !ruby/object:Gem::Requirement
@@ -303,7 +317,7 @@ homepage: https://github.com/carrierwaveuploader/carrierwave
303
317
  licenses:
304
318
  - MIT
305
319
  metadata: {}
306
- post_install_message:
320
+ post_install_message:
307
321
  rdoc_options:
308
322
  - "--main"
309
323
  require_paths:
@@ -319,9 +333,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
319
333
  - !ruby/object:Gem::Version
320
334
  version: '0'
321
335
  requirements: []
322
- rubyforge_project:
323
- rubygems_version: 2.5.2
324
- signing_key:
336
+ rubygems_version: 3.1.2
337
+ signing_key:
325
338
  specification_version: 4
326
339
  summary: Ruby file upload library
327
340
  test_files: []