carrierwave 1.2.1 → 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 +5 -5
- data/README.md +28 -14
- data/lib/carrierwave.rb +20 -0
- data/lib/carrierwave/locale/en.yml +1 -1
- data/lib/carrierwave/processing/mini_magick.rb +9 -5
- data/lib/carrierwave/processing/rmagick.rb +18 -4
- data/lib/carrierwave/sanitized_file.rb +8 -8
- data/lib/carrierwave/storage/file.rb +5 -1
- data/lib/carrierwave/storage/fog.rb +54 -12
- data/lib/carrierwave/uploader.rb +9 -0
- data/lib/carrierwave/uploader/configuration.rb +3 -1
- data/lib/carrierwave/uploader/content_type_whitelist.rb +1 -1
- data/lib/carrierwave/uploader/download.rb +59 -15
- data/lib/carrierwave/uploader/store.rb +9 -0
- data/lib/carrierwave/uploader/versions.rb +8 -1
- data/lib/carrierwave/version.rb +1 -1
- data/lib/generators/templates/uploader.rb +0 -2
- metadata +69 -16
- data/lib/carrierwave/uploader/magic_mime_blacklist.rb +0 -94
- data/lib/carrierwave/uploader/magic_mime_whitelist.rb +0 -94
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: d5e6d1dd656203f5e14c43b75b807e793d623126006ddf8c5a4f9f4706faa750
|
4
|
+
data.tar.gz: 82281b939837f54716f580a1deb6397d87cc9bb867dc6a6938a4322d795500b1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8eca3a53204f520d0cabf6e2384e6670cb634159e4b6c1e8d3915b6bab8473f21fb116047129b142a986588ea27401131d095186657770d7c31b03d6c929a1c9
|
7
|
+
data.tar.gz: 316797cffad6d2568e50929862cd80ba3e56c05d557f70f8631b66fc60ffd65fe5862afe4121a1e5e775e55a5f6c9a6c14414bce6a57deab2d12a8a127ed5b0d
|
data/README.md
CHANGED
@@ -4,8 +4,8 @@ This gem provides a simple and extremely flexible way to upload files from Ruby
|
|
4
4
|
It works well with Rack based web applications, such as Ruby on Rails.
|
5
5
|
|
6
6
|
[![Build Status](https://travis-ci.org/carrierwaveuploader/carrierwave.svg?branch=master)](http://travis-ci.org/carrierwaveuploader/carrierwave)
|
7
|
-
[![Code Climate](
|
8
|
-
[![
|
7
|
+
[![Code Climate](https://codeclimate.com/github/carrierwaveuploader/carrierwave.svg)](https://codeclimate.com/github/carrierwaveuploader/carrierwave)
|
8
|
+
[![SemVer](https://api.dependabot.com/badges/compatibility_score?dependency-name=carrierwave&package-manager=bundler&version-scheme=semver)](https://dependabot.com/compatibility-score.html?dependency-name=carrierwave&package-manager=bundler&version-scheme=semver)
|
9
9
|
|
10
10
|
|
11
11
|
## Information
|
@@ -24,7 +24,7 @@ It works well with Rack based web applications, such as Ruby on Rails.
|
|
24
24
|
Install the latest release:
|
25
25
|
|
26
26
|
```
|
27
|
-
$ gem install carrierwave
|
27
|
+
$ gem install carrierwave
|
28
28
|
```
|
29
29
|
|
30
30
|
In Rails, add it to your Gemfile:
|
@@ -89,7 +89,7 @@ a migration:
|
|
89
89
|
|
90
90
|
|
91
91
|
rails g migration add_avatar_to_users avatar:string
|
92
|
-
|
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
|
-
|
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
|
-
|
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
|
|
@@ -301,8 +304,16 @@ end
|
|
301
304
|
```
|
302
305
|
|
303
306
|
When this uploader is used, an uploaded image would be scaled to be no larger
|
304
|
-
than 800 by 800 pixels.
|
305
|
-
|
307
|
+
than 800 by 800 pixels. The original aspect ratio will be kept.
|
308
|
+
A version called thumb is then created, which is scaled
|
309
|
+
to exactly 200 by 200 pixels.
|
310
|
+
|
311
|
+
If you would like to crop images to a specific height and width you
|
312
|
+
can use the alternative option of '''resize_to_fill'''. It will make sure
|
313
|
+
that the width and height specified are filled, only cropping
|
314
|
+
if the aspect ratio requires it.
|
315
|
+
|
316
|
+
The uploader could be used like this:
|
306
317
|
|
307
318
|
```ruby
|
308
319
|
uploader = AvatarUploader.new
|
@@ -625,6 +636,8 @@ describe MyUploader do
|
|
625
636
|
end
|
626
637
|
```
|
627
638
|
|
639
|
+
If you're looking for minitest asserts, checkout [carrierwave_asserts](https://github.com/hcfairbanks/carrierwave_asserts).
|
640
|
+
|
628
641
|
Setting the enable_processing flag on an uploader will prevent any of the versions from processing as well.
|
629
642
|
Processing can be enabled for a single version by setting the processing flag on the version like so:
|
630
643
|
|
@@ -659,15 +672,16 @@ CarrierWave.configure do |config|
|
|
659
672
|
config.fog_provider = 'fog/aws' # required
|
660
673
|
config.fog_credentials = {
|
661
674
|
provider: 'AWS', # required
|
662
|
-
aws_access_key_id: 'xxx', # required
|
663
|
-
aws_secret_access_key: 'yyy', # required
|
675
|
+
aws_access_key_id: 'xxx', # required unless using use_iam_profile
|
676
|
+
aws_secret_access_key: 'yyy', # required unless using use_iam_profile
|
677
|
+
use_iam_profile: true, # optional, defaults to false
|
664
678
|
region: 'eu-west-1', # optional, defaults to 'us-east-1'
|
665
679
|
host: 's3.example.com', # optional, defaults to nil
|
666
680
|
endpoint: 'https://s3.example.com:8080' # optional, defaults to nil
|
667
681
|
}
|
668
|
-
config.fog_directory = '
|
669
|
-
config.fog_public = false
|
670
|
-
config.fog_attributes = { cache_control: "public, max-age=#{365.
|
682
|
+
config.fog_directory = 'name_of_bucket' # required
|
683
|
+
config.fog_public = false # optional, defaults to true
|
684
|
+
config.fog_attributes = { cache_control: "public, max-age=#{365.days.to_i}" } # optional, defaults to {}
|
671
685
|
end
|
672
686
|
```
|
673
687
|
|
@@ -912,7 +926,7 @@ errors:
|
|
912
926
|
carrierwave_download_error: could not be downloaded
|
913
927
|
extension_whitelist_error: "You are not allowed to upload %{extension} files, allowed types: %{allowed_types}"
|
914
928
|
extension_blacklist_error: "You are not allowed to upload %{extension} files, prohibited types: %{prohibited_types}"
|
915
|
-
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}"
|
916
930
|
content_type_blacklist_error: "You are not allowed to upload %{content_type} files"
|
917
931
|
rmagick_processing_error: "Failed to manipulate with rmagick, maybe it is not an image?"
|
918
932
|
mini_magick_processing_error: "Failed to manipulate with MiniMagick, maybe it is not an image? Original Error: %{e}"
|
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
|
@@ -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}"
|
@@ -61,6 +61,13 @@ module CarrierWave
|
|
61
61
|
e.message << " (You may need to install the mini_magick gem)"
|
62
62
|
raise e
|
63
63
|
end
|
64
|
+
|
65
|
+
prepend Module.new {
|
66
|
+
def initialize(*)
|
67
|
+
super
|
68
|
+
@format = nil
|
69
|
+
end
|
70
|
+
}
|
64
71
|
end
|
65
72
|
|
66
73
|
module ClassMethods
|
@@ -303,6 +310,7 @@ module CarrierWave
|
|
303
310
|
|
304
311
|
if @format
|
305
312
|
move_to = current_path.chomp(File.extname(current_path)) + ".#{@format}"
|
313
|
+
file.content_type = ::MIME::Types.type_for(move_to).first.to_s
|
306
314
|
file.move_to(move_to, permissions, directory_permissions)
|
307
315
|
end
|
308
316
|
|
@@ -333,11 +341,7 @@ module CarrierWave
|
|
333
341
|
end
|
334
342
|
|
335
343
|
def mini_magick_image
|
336
|
-
|
337
|
-
::MiniMagick::Image.open(url)
|
338
|
-
else
|
339
|
-
::MiniMagick::Image.open(current_path)
|
340
|
-
end
|
344
|
+
::MiniMagick::Image.read(read)
|
341
345
|
end
|
342
346
|
|
343
347
|
end # MiniMagick
|
@@ -67,6 +67,13 @@ module CarrierWave
|
|
67
67
|
e.message << " (You may need to install the rmagick gem)"
|
68
68
|
raise e
|
69
69
|
end
|
70
|
+
|
71
|
+
prepend Module.new {
|
72
|
+
def initialize(*)
|
73
|
+
super
|
74
|
+
@format = nil
|
75
|
+
end
|
76
|
+
}
|
70
77
|
end
|
71
78
|
|
72
79
|
module ClassMethods
|
@@ -346,7 +353,7 @@ module CarrierWave
|
|
346
353
|
frames = ::Magick::ImageList.new
|
347
354
|
|
348
355
|
image.each_with_index do |frame, index|
|
349
|
-
frame = yield
|
356
|
+
frame = yield(*[frame, index, options].take(block.arity)) if block_given?
|
350
357
|
frames << frame if frame
|
351
358
|
end
|
352
359
|
frames.append(true) if block_given?
|
@@ -356,6 +363,7 @@ module CarrierWave
|
|
356
363
|
if options[:format] || @format
|
357
364
|
frames.write("#{options[:format] || @format}:#{current_path}", &write_block)
|
358
365
|
move_to = current_path.chomp(File.extname(current_path)) + ".#{options[:format] || @format}"
|
366
|
+
file.content_type = ::MIME::Types.type_for(move_to).first.to_s
|
359
367
|
file.move_to(move_to, permissions, directory_permissions)
|
360
368
|
else
|
361
369
|
frames.write(current_path, &write_block)
|
@@ -370,9 +378,15 @@ module CarrierWave
|
|
370
378
|
|
371
379
|
def create_info_block(options)
|
372
380
|
return nil unless options
|
373
|
-
|
374
|
-
|
375
|
-
|
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
|
376
390
|
end
|
377
391
|
|
378
392
|
def destroy_image(image)
|
@@ -20,7 +20,7 @@ module CarrierWave
|
|
20
20
|
#
|
21
21
|
class SanitizedFile
|
22
22
|
|
23
|
-
|
23
|
+
attr_reader :file
|
24
24
|
|
25
25
|
class << self
|
26
26
|
attr_writer :sanitize_regexp
|
@@ -32,6 +32,7 @@ module CarrierWave
|
|
32
32
|
|
33
33
|
def initialize(file)
|
34
34
|
self.file = file
|
35
|
+
@content = nil
|
35
36
|
end
|
36
37
|
|
37
38
|
##
|
@@ -113,12 +114,11 @@ module CarrierWave
|
|
113
114
|
# [String, nil] the path where the file is located.
|
114
115
|
#
|
115
116
|
def path
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
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)
|
122
122
|
end
|
123
123
|
end
|
124
124
|
|
@@ -312,7 +312,7 @@ module CarrierWave
|
|
312
312
|
def mkdir!(path, directory_permissions)
|
313
313
|
options = {}
|
314
314
|
options[:mode] = directory_permissions if directory_permissions
|
315
|
-
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))
|
316
316
|
end
|
317
317
|
|
318
318
|
def chmod!(path, permissions)
|
@@ -7,6 +7,10 @@ module CarrierWave
|
|
7
7
|
# pretty much it.
|
8
8
|
#
|
9
9
|
class File < Abstract
|
10
|
+
def initialize(*)
|
11
|
+
super
|
12
|
+
@cache_called = nil
|
13
|
+
end
|
10
14
|
|
11
15
|
##
|
12
16
|
# Move the file to the uploader's store path.
|
@@ -62,7 +66,7 @@ module CarrierWave
|
|
62
66
|
#
|
63
67
|
def cache!(new_file)
|
64
68
|
new_file.move_to(::File.expand_path(uploader.cache_path, uploader.root), uploader.permissions, uploader.directory_permissions, true)
|
65
|
-
rescue Errno::EMLINK => e
|
69
|
+
rescue Errno::EMLINK, Errno::ENOSPC => e
|
66
70
|
raise(e) if @cache_called
|
67
71
|
@cache_called = true
|
68
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
|
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
|
-
|
197
|
-
|
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
|
@@ -266,7 +270,7 @@ module CarrierWave
|
|
266
270
|
end
|
267
271
|
|
268
272
|
def initialize(uploader, base, path)
|
269
|
-
@uploader, @base, @path = uploader, base, path
|
273
|
+
@uploader, @base, @path, @content_type = uploader, base, path, nil
|
270
274
|
end
|
271
275
|
|
272
276
|
##
|
@@ -276,6 +280,16 @@ module CarrierWave
|
|
276
280
|
#
|
277
281
|
# [String] contents of file
|
278
282
|
def read
|
283
|
+
file_body = file.body
|
284
|
+
|
285
|
+
return if file_body.nil?
|
286
|
+
return file_body unless file_body.is_a?(::File)
|
287
|
+
|
288
|
+
# Fog::Storage::XXX::File#body could return the source file which was upoloaded to the remote server.
|
289
|
+
read_source_file(file_body) if ::File.exist?(file_body.path)
|
290
|
+
|
291
|
+
# If the source file doesn't exist, the remote content is read
|
292
|
+
@file = nil # rubocop:disable Gitlab/ModuleWithInstanceVariables
|
279
293
|
file.body
|
280
294
|
end
|
281
295
|
|
@@ -313,7 +327,7 @@ module CarrierWave
|
|
313
327
|
fog_file = new_file.to_file
|
314
328
|
@content_type ||= new_file.content_type
|
315
329
|
@file = directory.files.create({
|
316
|
-
:body =>
|
330
|
+
:body => fog_file ? fog_file : new_file.read,
|
317
331
|
:content_type => @content_type,
|
318
332
|
:key => path,
|
319
333
|
:public => @uploader.fog_public
|
@@ -342,15 +356,19 @@ module CarrierWave
|
|
342
356
|
end
|
343
357
|
else
|
344
358
|
# AWS/Google optimized for speed over correctness
|
345
|
-
case
|
359
|
+
case fog_provider
|
346
360
|
when 'AWS'
|
347
361
|
# check if some endpoint is set in fog_credentials
|
348
362
|
if @uploader.fog_credentials.has_key?(:endpoint)
|
349
363
|
"#{@uploader.fog_credentials[:endpoint]}/#{@uploader.fog_directory}/#{encoded_path}"
|
350
364
|
else
|
351
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
|
+
|
352
370
|
# if directory is a valid subdomain, use that style for access
|
353
|
-
if
|
371
|
+
if valid_subdomain
|
354
372
|
s3_subdomain = @uploader.fog_aws_accelerate ? "s3-accelerate" : "s3"
|
355
373
|
"#{protocol}://#{@uploader.fog_directory}.#{s3_subdomain}.amazonaws.com/#{encoded_path}"
|
356
374
|
else
|
@@ -456,7 +474,31 @@ module CarrierWave
|
|
456
474
|
end
|
457
475
|
|
458
476
|
def acl_header
|
459
|
-
|
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
|
486
|
+
end
|
487
|
+
|
488
|
+
def read_source_file(file_body)
|
489
|
+
return unless ::File.exist?(file_body.path)
|
490
|
+
|
491
|
+
begin
|
492
|
+
file_body = ::File.open(file_body.path) if file_body.closed? # Reopen if it's already closed
|
493
|
+
file_body.read
|
494
|
+
ensure
|
495
|
+
file_body.close
|
496
|
+
end
|
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)
|
460
502
|
end
|
461
503
|
end
|
462
504
|
|
data/lib/carrierwave/uploader.rb
CHANGED
@@ -43,6 +43,15 @@ module CarrierWave
|
|
43
43
|
class Base
|
44
44
|
attr_reader :file
|
45
45
|
|
46
|
+
##
|
47
|
+
# Workaround for class_attribute malfunction when used with Module#prepend
|
48
|
+
#
|
49
|
+
if RUBY_VERSION < '2.1.0'
|
50
|
+
def self.singleton_class?
|
51
|
+
!ancestors.include? self
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
46
55
|
include CarrierWave::Uploader::Configuration
|
47
56
|
include CarrierWave::Uploader::Callbacks
|
48
57
|
include CarrierWave::Uploader::Proxy
|
@@ -117,12 +117,14 @@ module CarrierWave
|
|
117
117
|
|
118
118
|
def add_config(name)
|
119
119
|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
120
|
+
@#{name} = nil
|
121
|
+
|
120
122
|
def self.eager_load_fog(fog_credentials)
|
121
123
|
# see #1198. This will hopefully no longer be necessary after fog 2.0
|
122
124
|
require self.fog_provider
|
123
125
|
require 'carrierwave/storage/fog'
|
124
126
|
Fog::Storage.new(fog_credentials) if fog_credentials.present?
|
125
|
-
end
|
127
|
+
end unless defined? eager_load_fog
|
126
128
|
|
127
129
|
def self.#{name}(value=nil)
|
128
130
|
@#{name} = value if value
|
@@ -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,14 +11,18 @@ module CarrierWave
|
|
10
11
|
include CarrierWave::Uploader::Cache
|
11
12
|
|
12
13
|
class RemoteFile
|
13
|
-
|
14
|
+
attr_reader :uri
|
15
|
+
|
16
|
+
def initialize(uri, remote_headers = {}, skip_ssrf_protection: false)
|
14
17
|
@uri = uri
|
15
|
-
@remote_headers = remote_headers
|
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
|
16
21
|
end
|
17
22
|
|
18
23
|
def original_filename
|
19
24
|
filename = filename_from_header || filename_from_uri
|
20
|
-
mime_type = MIME::Types[
|
25
|
+
mime_type = MIME::Types[content_type].first
|
21
26
|
unless File.extname(filename).present? || mime_type.blank?
|
22
27
|
filename = "#{filename}.#{mime_type.extensions.first}"
|
23
28
|
end
|
@@ -32,15 +37,35 @@ module CarrierWave
|
|
32
37
|
@uri.scheme =~ /^https?$/
|
33
38
|
end
|
34
39
|
|
35
|
-
|
40
|
+
def content_type
|
41
|
+
@content_type || 'application/octet-stream'
|
42
|
+
end
|
43
|
+
|
44
|
+
def headers
|
45
|
+
@headers || {}
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
36
49
|
|
37
50
|
def file
|
38
51
|
if @file.blank?
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
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
|
44
69
|
end
|
45
70
|
@file
|
46
71
|
|
@@ -49,14 +74,14 @@ module CarrierWave
|
|
49
74
|
end
|
50
75
|
|
51
76
|
def filename_from_header
|
52
|
-
if
|
53
|
-
match =
|
77
|
+
if headers['content-disposition']
|
78
|
+
match = headers['content-disposition'].match(/filename="?([^"]+)/)
|
54
79
|
return match[1] unless match.nil? || match[1].empty?
|
55
80
|
end
|
56
81
|
end
|
57
82
|
|
58
83
|
def filename_from_uri
|
59
|
-
URI.
|
84
|
+
URI::DEFAULT_PARSER.unescape(File.basename(@uri.path))
|
60
85
|
end
|
61
86
|
|
62
87
|
def method_missing(*args, &block)
|
@@ -74,7 +99,7 @@ module CarrierWave
|
|
74
99
|
#
|
75
100
|
def download!(uri, remote_headers = {})
|
76
101
|
processed_uri = process_uri(uri)
|
77
|
-
file = RemoteFile.new(processed_uri, remote_headers)
|
102
|
+
file = RemoteFile.new(processed_uri, remote_headers, skip_ssrf_protection: skip_ssrf_protection?(processed_uri))
|
78
103
|
raise CarrierWave::DownloadError, "trying to download a file which is not served over HTTP" unless file.http?
|
79
104
|
cache!(file)
|
80
105
|
end
|
@@ -91,11 +116,30 @@ module CarrierWave
|
|
91
116
|
rescue URI::InvalidURIError
|
92
117
|
uri_parts = uri.split('?')
|
93
118
|
# regexp from Ruby's URI::Parser#regexp[:UNSAFE], with [] specifically removed
|
94
|
-
encoded_uri = URI.
|
95
|
-
encoded_uri << '?' << URI.
|
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?
|
96
121
|
URI.parse(encoded_uri) rescue raise CarrierWave::DownloadError, "couldn't parse URL"
|
97
122
|
end
|
98
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
|
99
143
|
end # Download
|
100
144
|
end # Uploader
|
101
145
|
end # CarrierWave
|
@@ -7,6 +7,15 @@ module CarrierWave
|
|
7
7
|
include CarrierWave::Uploader::Configuration
|
8
8
|
include CarrierWave::Uploader::Cache
|
9
9
|
|
10
|
+
included do
|
11
|
+
prepend Module.new {
|
12
|
+
def initialize(*)
|
13
|
+
super
|
14
|
+
@file, @filename, @cache_id = nil
|
15
|
+
end
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
10
19
|
##
|
11
20
|
# Override this in your Uploader to change the filename.
|
12
21
|
#
|
@@ -19,6 +19,13 @@ module CarrierWave
|
|
19
19
|
after :remove, :remove_versions!
|
20
20
|
after :retrieve_from_cache, :retrieve_versions_from_cache!
|
21
21
|
after :retrieve_from_store, :retrieve_versions_from_store!
|
22
|
+
|
23
|
+
prepend Module.new {
|
24
|
+
def initialize(*)
|
25
|
+
super
|
26
|
+
@versions = nil
|
27
|
+
end
|
28
|
+
}
|
22
29
|
end
|
23
30
|
|
24
31
|
module ClassMethods
|
@@ -77,7 +84,7 @@ module CarrierWave
|
|
77
84
|
# value from the parent class unless explicitly overwritten
|
78
85
|
def self.enable_processing(value=nil)
|
79
86
|
self.enable_processing = value if value
|
80
|
-
if !@enable_processing.nil?
|
87
|
+
if defined?(@enable_processing) && !@enable_processing.nil?
|
81
88
|
@enable_processing
|
82
89
|
else
|
83
90
|
superclass.enable_processing
|
data/lib/carrierwave/version.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
class <%= class_name %>Uploader < CarrierWave::Uploader::Base
|
2
|
-
|
3
2
|
# Include RMagick or MiniMagick support:
|
4
3
|
# include CarrierWave::RMagick
|
5
4
|
# include CarrierWave::MiniMagick
|
@@ -45,5 +44,4 @@ class <%= class_name %>Uploader < CarrierWave::Uploader::Base
|
|
45
44
|
# def filename
|
46
45
|
# "something.jpg" if original_filename
|
47
46
|
# end
|
48
|
-
|
49
47
|
end
|
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
|
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:
|
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
|
@@ -123,35 +137,49 @@ dependencies:
|
|
123
137
|
- !ruby/object:Gem::Version
|
124
138
|
version: '0'
|
125
139
|
- !ruby/object:Gem::Dependency
|
126
|
-
name: fog
|
140
|
+
name: fog-aws
|
127
141
|
requirement: !ruby/object:Gem::Requirement
|
128
142
|
requirements:
|
129
143
|
- - ">="
|
130
144
|
- !ruby/object:Gem::Version
|
131
|
-
version:
|
145
|
+
version: '0'
|
132
146
|
type: :development
|
133
147
|
prerelease: false
|
134
148
|
version_requirements: !ruby/object:Gem::Requirement
|
135
149
|
requirements:
|
136
150
|
- - ">="
|
137
151
|
- !ruby/object:Gem::Version
|
138
|
-
version:
|
152
|
+
version: '0'
|
139
153
|
- !ruby/object:Gem::Dependency
|
140
|
-
name:
|
154
|
+
name: fog-google
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - "~>"
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: 1.7.1
|
160
|
+
type: :development
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - "~>"
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: 1.7.1
|
167
|
+
- !ruby/object:Gem::Dependency
|
168
|
+
name: fog-local
|
141
169
|
requirement: !ruby/object:Gem::Requirement
|
142
170
|
requirements:
|
143
171
|
- - ">="
|
144
172
|
- !ruby/object:Gem::Version
|
145
|
-
version:
|
173
|
+
version: '0'
|
146
174
|
type: :development
|
147
175
|
prerelease: false
|
148
176
|
version_requirements: !ruby/object:Gem::Requirement
|
149
177
|
requirements:
|
150
178
|
- - ">="
|
151
179
|
- !ruby/object:Gem::Version
|
152
|
-
version:
|
180
|
+
version: '0'
|
153
181
|
- !ruby/object:Gem::Dependency
|
154
|
-
name:
|
182
|
+
name: fog-rackspace
|
155
183
|
requirement: !ruby/object:Gem::Requirement
|
156
184
|
requirements:
|
157
185
|
- - ">="
|
@@ -164,6 +192,34 @@ dependencies:
|
|
164
192
|
- - ">="
|
165
193
|
- !ruby/object:Gem::Version
|
166
194
|
version: '0'
|
195
|
+
- !ruby/object:Gem::Dependency
|
196
|
+
name: mini_magick
|
197
|
+
requirement: !ruby/object:Gem::Requirement
|
198
|
+
requirements:
|
199
|
+
- - ">="
|
200
|
+
- !ruby/object:Gem::Version
|
201
|
+
version: 3.6.0
|
202
|
+
type: :development
|
203
|
+
prerelease: false
|
204
|
+
version_requirements: !ruby/object:Gem::Requirement
|
205
|
+
requirements:
|
206
|
+
- - ">="
|
207
|
+
- !ruby/object:Gem::Version
|
208
|
+
version: 3.6.0
|
209
|
+
- !ruby/object:Gem::Dependency
|
210
|
+
name: rmagick
|
211
|
+
requirement: !ruby/object:Gem::Requirement
|
212
|
+
requirements:
|
213
|
+
- - "~>"
|
214
|
+
- !ruby/object:Gem::Version
|
215
|
+
version: '2.16'
|
216
|
+
type: :development
|
217
|
+
prerelease: false
|
218
|
+
version_requirements: !ruby/object:Gem::Requirement
|
219
|
+
requirements:
|
220
|
+
- - "~>"
|
221
|
+
- !ruby/object:Gem::Version
|
222
|
+
version: '2.16'
|
167
223
|
- !ruby/object:Gem::Dependency
|
168
224
|
name: timecop
|
169
225
|
requirement: !ruby/object:Gem::Requirement
|
@@ -243,8 +299,6 @@ files:
|
|
243
299
|
- lib/carrierwave/uploader/extension_blacklist.rb
|
244
300
|
- lib/carrierwave/uploader/extension_whitelist.rb
|
245
301
|
- lib/carrierwave/uploader/file_size.rb
|
246
|
-
- lib/carrierwave/uploader/magic_mime_blacklist.rb
|
247
|
-
- lib/carrierwave/uploader/magic_mime_whitelist.rb
|
248
302
|
- lib/carrierwave/uploader/mountable.rb
|
249
303
|
- lib/carrierwave/uploader/processing.rb
|
250
304
|
- lib/carrierwave/uploader/proxy.rb
|
@@ -263,7 +317,7 @@ homepage: https://github.com/carrierwaveuploader/carrierwave
|
|
263
317
|
licenses:
|
264
318
|
- MIT
|
265
319
|
metadata: {}
|
266
|
-
post_install_message:
|
320
|
+
post_install_message:
|
267
321
|
rdoc_options:
|
268
322
|
- "--main"
|
269
323
|
require_paths:
|
@@ -279,9 +333,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
279
333
|
- !ruby/object:Gem::Version
|
280
334
|
version: '0'
|
281
335
|
requirements: []
|
282
|
-
|
283
|
-
|
284
|
-
signing_key:
|
336
|
+
rubygems_version: 3.1.2
|
337
|
+
signing_key:
|
285
338
|
specification_version: 4
|
286
339
|
summary: Ruby file upload library
|
287
340
|
test_files: []
|
@@ -1,94 +0,0 @@
|
|
1
|
-
module CarrierWave
|
2
|
-
module Uploader
|
3
|
-
|
4
|
-
##
|
5
|
-
# This modules validates the content type of a file with the use of
|
6
|
-
# ruby-filemagic gem and a blacklist regular expression. If you want
|
7
|
-
# to use this, you'll need to require this file:
|
8
|
-
#
|
9
|
-
# require 'carrierwave/uploader/magic_mime_blacklist'
|
10
|
-
#
|
11
|
-
# And then include it in your uploader:
|
12
|
-
#
|
13
|
-
# class MyUploader < CarrierWave::Uploader::Base
|
14
|
-
# include CarrierWave::Uploader::MagicMimeBlacklist
|
15
|
-
#
|
16
|
-
# def blacklist_mime_type_pattern
|
17
|
-
# /image\//
|
18
|
-
# end
|
19
|
-
# end
|
20
|
-
#
|
21
|
-
module MagicMimeBlacklist
|
22
|
-
extend ActiveSupport::Concern
|
23
|
-
|
24
|
-
included do
|
25
|
-
begin
|
26
|
-
require "filemagic"
|
27
|
-
rescue LoadError => e
|
28
|
-
e.message << " (You may need to install the ruby-filemagic gem)"
|
29
|
-
raise e
|
30
|
-
end
|
31
|
-
|
32
|
-
before :cache, :check_blacklist_pattern!
|
33
|
-
end
|
34
|
-
|
35
|
-
##
|
36
|
-
# Override this method in your uploader to provide a black list pattern (regexp)
|
37
|
-
# of content-types which are prohibited to be uploaded.
|
38
|
-
# Compares the file's content-type.
|
39
|
-
#
|
40
|
-
# === Returns
|
41
|
-
#
|
42
|
-
# [Regexp] a black list regexp to match the content_type
|
43
|
-
#
|
44
|
-
# === Examples
|
45
|
-
#
|
46
|
-
# def blacklist_mime_type_pattern
|
47
|
-
# /(text|application)\/json/
|
48
|
-
# end
|
49
|
-
#
|
50
|
-
def blacklist_mime_type_pattern; end
|
51
|
-
|
52
|
-
private
|
53
|
-
|
54
|
-
def check_blacklist_pattern!(new_file)
|
55
|
-
return if blacklist_mime_type_pattern.nil?
|
56
|
-
|
57
|
-
content_type = extract_content_type(new_file)
|
58
|
-
|
59
|
-
if content_type.match(blacklist_mime_type_pattern)
|
60
|
-
raise CarrierWave::IntegrityError,
|
61
|
-
I18n.translate(:"errors.messages.mime_type_pattern_black_list_error",
|
62
|
-
:content_type => content_type)
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
##
|
67
|
-
# Extracts the content type of the given file
|
68
|
-
#
|
69
|
-
# === Returns
|
70
|
-
#
|
71
|
-
# [String] the extracted content type
|
72
|
-
#
|
73
|
-
def extract_content_type(new_file)
|
74
|
-
content_type = nil
|
75
|
-
|
76
|
-
File.open(new_file.path) do |fd|
|
77
|
-
data = fd.read(1024) || ""
|
78
|
-
content_type = filemagic.buffer(data)
|
79
|
-
end
|
80
|
-
|
81
|
-
content_type
|
82
|
-
end
|
83
|
-
|
84
|
-
##
|
85
|
-
# FileMagic object with the MAGIC_MIME_TYPE flag set
|
86
|
-
#
|
87
|
-
# @return [FileMagic] a filemagic object
|
88
|
-
def filemagic
|
89
|
-
@filemagic ||= FileMagic.new(FileMagic::MAGIC_MIME_TYPE)
|
90
|
-
end
|
91
|
-
|
92
|
-
end # MagicMimeblackList
|
93
|
-
end # Uploader
|
94
|
-
end # CarrierWave
|
@@ -1,94 +0,0 @@
|
|
1
|
-
module CarrierWave
|
2
|
-
module Uploader
|
3
|
-
|
4
|
-
##
|
5
|
-
# This modules validates the content type of a file with the use of
|
6
|
-
# ruby-filemagic gem and a whitelist regular expression. If you want
|
7
|
-
# to use this, you'll need to require this file:
|
8
|
-
#
|
9
|
-
# require 'carrierwave/uploader/magic_mime_whitelist'
|
10
|
-
#
|
11
|
-
# And then include it in your uploader:
|
12
|
-
#
|
13
|
-
# class MyUploader < CarrierWave::Uploader::Base
|
14
|
-
# include CarrierWave::Uploader::MagicMimeWhitelist
|
15
|
-
#
|
16
|
-
# def whitelist_mime_type_pattern
|
17
|
-
# /image\//
|
18
|
-
# end
|
19
|
-
# end
|
20
|
-
#
|
21
|
-
module MagicMimeWhitelist
|
22
|
-
extend ActiveSupport::Concern
|
23
|
-
|
24
|
-
included do
|
25
|
-
begin
|
26
|
-
require "filemagic"
|
27
|
-
rescue LoadError => e
|
28
|
-
e.message << " (You may need to install the ruby-filemagic gem)"
|
29
|
-
raise e
|
30
|
-
end
|
31
|
-
|
32
|
-
before :cache, :check_whitelist_pattern!
|
33
|
-
end
|
34
|
-
|
35
|
-
##
|
36
|
-
# Override this method in your uploader to provide a white list pattern (regexp)
|
37
|
-
# of content-types which are allowed to be uploaded.
|
38
|
-
# Compares the file's content-type.
|
39
|
-
#
|
40
|
-
# === Returns
|
41
|
-
#
|
42
|
-
# [Regexp] a white list regexp to match the content_type
|
43
|
-
#
|
44
|
-
# === Examples
|
45
|
-
#
|
46
|
-
# def whitelist_mime_type_pattern
|
47
|
-
# /(text|application)\/json/
|
48
|
-
# end
|
49
|
-
#
|
50
|
-
def whitelist_mime_type_pattern; end
|
51
|
-
|
52
|
-
private
|
53
|
-
|
54
|
-
def check_whitelist_pattern!(new_file)
|
55
|
-
return if whitelist_mime_type_pattern.nil?
|
56
|
-
|
57
|
-
content_type = extract_content_type(new_file)
|
58
|
-
|
59
|
-
if !content_type.match(whitelist_mime_type_pattern)
|
60
|
-
raise CarrierWave::IntegrityError,
|
61
|
-
I18n.translate(:"errors.messages.mime_type_pattern_white_list_error",
|
62
|
-
:content_type => content_type)
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
##
|
67
|
-
# Extracts the content type of the given file
|
68
|
-
#
|
69
|
-
# === Returns
|
70
|
-
#
|
71
|
-
# [String] the extracted content type
|
72
|
-
#
|
73
|
-
def extract_content_type(new_file)
|
74
|
-
content_type = nil
|
75
|
-
|
76
|
-
File.open(new_file.path) do |fd|
|
77
|
-
data = fd.read(1024) || ""
|
78
|
-
content_type = filemagic.buffer(data)
|
79
|
-
end
|
80
|
-
|
81
|
-
content_type
|
82
|
-
end
|
83
|
-
|
84
|
-
##
|
85
|
-
# FileMagic object with the MAGIC_MIME_TYPE flag set
|
86
|
-
#
|
87
|
-
# @return [FileMagic] a filemagic object
|
88
|
-
def filemagic
|
89
|
-
@filemagic ||= FileMagic.new(FileMagic::MAGIC_MIME_TYPE)
|
90
|
-
end
|
91
|
-
|
92
|
-
end # MagicMimeWhiteList
|
93
|
-
end # Uploader
|
94
|
-
end # CarrierWave
|