carrierwave 0.9.0 → 3.0.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.

Files changed (56) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +508 -158
  3. data/lib/carrierwave/compatibility/paperclip.rb +31 -21
  4. data/lib/carrierwave/downloader/base.rb +101 -0
  5. data/lib/carrierwave/downloader/remote_file.rb +68 -0
  6. data/lib/carrierwave/error.rb +1 -0
  7. data/lib/carrierwave/locale/en.yml +11 -5
  8. data/lib/carrierwave/mount.rb +220 -187
  9. data/lib/carrierwave/mounter.rb +255 -0
  10. data/lib/carrierwave/orm/activerecord.rb +24 -34
  11. data/lib/carrierwave/processing/mini_magick.rb +142 -79
  12. data/lib/carrierwave/processing/rmagick.rb +76 -35
  13. data/lib/carrierwave/processing/vips.rb +284 -0
  14. data/lib/carrierwave/processing.rb +1 -1
  15. data/lib/carrierwave/sanitized_file.rb +89 -70
  16. data/lib/carrierwave/storage/abstract.rb +16 -3
  17. data/lib/carrierwave/storage/file.rb +71 -3
  18. data/lib/carrierwave/storage/fog.rb +215 -58
  19. data/lib/carrierwave/storage.rb +1 -7
  20. data/lib/carrierwave/test/matchers.rb +88 -19
  21. data/lib/carrierwave/uploader/cache.rb +88 -44
  22. data/lib/carrierwave/uploader/callbacks.rb +1 -3
  23. data/lib/carrierwave/uploader/configuration.rb +81 -9
  24. data/lib/carrierwave/uploader/content_type_allowlist.rb +62 -0
  25. data/lib/carrierwave/uploader/content_type_denylist.rb +62 -0
  26. data/lib/carrierwave/uploader/default_url.rb +3 -5
  27. data/lib/carrierwave/uploader/dimension.rb +66 -0
  28. data/lib/carrierwave/uploader/download.rb +5 -69
  29. data/lib/carrierwave/uploader/extension_allowlist.rb +63 -0
  30. data/lib/carrierwave/uploader/extension_denylist.rb +64 -0
  31. data/lib/carrierwave/uploader/file_size.rb +43 -0
  32. data/lib/carrierwave/uploader/mountable.rb +13 -8
  33. data/lib/carrierwave/uploader/processing.rb +54 -21
  34. data/lib/carrierwave/uploader/proxy.rb +30 -8
  35. data/lib/carrierwave/uploader/remove.rb +0 -2
  36. data/lib/carrierwave/uploader/serialization.rb +3 -5
  37. data/lib/carrierwave/uploader/store.rb +59 -28
  38. data/lib/carrierwave/uploader/url.rb +8 -7
  39. data/lib/carrierwave/uploader/versions.rb +173 -124
  40. data/lib/carrierwave/uploader.rb +12 -6
  41. data/lib/carrierwave/utilities/file_name.rb +47 -0
  42. data/lib/carrierwave/utilities/uri.rb +14 -12
  43. data/lib/carrierwave/utilities.rb +2 -3
  44. data/lib/carrierwave/validations/active_model.rb +7 -13
  45. data/lib/carrierwave/version.rb +1 -1
  46. data/lib/carrierwave.rb +41 -16
  47. data/lib/generators/templates/{uploader.rb → uploader.rb.erb} +5 -9
  48. data/lib/generators/uploader_generator.rb +3 -3
  49. metadata +224 -100
  50. data/lib/carrierwave/locale/cs.yml +0 -11
  51. data/lib/carrierwave/locale/de.yml +0 -11
  52. data/lib/carrierwave/locale/nl.yml +0 -11
  53. data/lib/carrierwave/locale/sk.yml +0 -11
  54. data/lib/carrierwave/processing/mime_types.rb +0 -73
  55. data/lib/carrierwave/uploader/extension_blacklist.rb +0 -47
  56. data/lib/carrierwave/uploader/extension_whitelist.rb +0 -49
@@ -1,3 +1,5 @@
1
+ require 'carrierwave/downloader/base'
2
+
1
3
  module CarrierWave
2
4
 
3
5
  module Uploader
@@ -5,7 +7,7 @@ module CarrierWave
5
7
  extend ActiveSupport::Concern
6
8
 
7
9
  included do
8
- class_attribute :_storage, :instance_writer => false
10
+ class_attribute :_storage, :_cache_storage, :instance_writer => false
9
11
 
10
12
  add_config :root
11
13
  add_config :base_path
@@ -21,14 +23,18 @@ module CarrierWave
21
23
  add_config :move_to_cache
22
24
  add_config :move_to_store
23
25
  add_config :remove_previously_stored_files_after_update
26
+ add_config :downloader
27
+ add_config :force_extension
24
28
 
25
29
  # fog
30
+ add_deprecated_config :fog_provider
26
31
  add_config :fog_attributes
27
32
  add_config :fog_credentials
28
33
  add_config :fog_directory
29
34
  add_config :fog_public
30
35
  add_config :fog_authenticated_url_expiration
31
36
  add_config :fog_use_ssl_for_aws
37
+ add_config :fog_aws_accelerate
32
38
 
33
39
  # Mounting
34
40
  add_config :ignore_integrity_errors
@@ -38,6 +44,9 @@ module CarrierWave
38
44
  add_config :validate_processing
39
45
  add_config :validate_download
40
46
  add_config :mount_on
47
+ add_config :cache_only
48
+ add_config :download_retry_count
49
+ add_config :download_retry_wait_time
41
50
 
42
51
  # set default values
43
52
  reset_config
@@ -69,20 +78,58 @@ module CarrierWave
69
78
  # storage MyCustomStorageEngine
70
79
  #
71
80
  def storage(storage = nil)
72
- if storage
73
- self._storage = storage.is_a?(Symbol) ? eval(storage_engines[storage]) : storage
81
+ case storage
82
+ when Symbol
83
+ if (storage_engine = storage_engines[storage])
84
+ self._storage = eval storage_engine
85
+ else
86
+ raise CarrierWave::UnknownStorageError, "Unknown storage: #{storage}"
87
+ end
88
+ when nil
89
+ storage
90
+ else
91
+ self._storage = storage
74
92
  end
75
93
  _storage
76
94
  end
77
95
  alias_method :storage=, :storage
78
96
 
97
+ ##
98
+ # Sets the cache storage engine to be used when storing cache files with this uploader.
99
+ # Same as .storage except for required methods being #cache!(CarrierWave::SanitizedFile),
100
+ # #retrieve_from_cache! and #delete_dir!.
101
+ #
102
+ # === Parameters
103
+ #
104
+ # [storage (Symbol, Class)] The cache storage engine to use for this uploader
105
+ #
106
+ # === Returns
107
+ #
108
+ # [Class] the cache storage engine to be used with this uploader
109
+ #
110
+ # === Examples
111
+ #
112
+ # cache_storage :file
113
+ # cache_storage CarrierWave::Storage::File
114
+ # cache_storage MyCustomStorageEngine
115
+ #
116
+ def cache_storage(storage = false)
117
+ unless storage == false
118
+ self._cache_storage = storage.is_a?(Symbol) ? eval(storage_engines[storage]) : storage
119
+ end
120
+ _cache_storage
121
+ end
122
+ alias_method :cache_storage=, :cache_storage
123
+
79
124
  def add_config(name)
80
125
  class_eval <<-RUBY, __FILE__, __LINE__ + 1
126
+ @#{name} = nil
127
+
81
128
  def self.#{name}(value=nil)
82
- @#{name} = value if value
129
+ @#{name} = value unless value.nil?
83
130
  return @#{name} if self.object_id == #{self.object_id} || defined?(@#{name})
84
131
  name = superclass.#{name}
85
- return nil if name.nil? && !instance_variable_defined?("@#{name}")
132
+ return nil if name.nil? && !instance_variable_defined?(:@#{name})
86
133
  @#{name} = name && !name.is_a?(Module) && !name.is_a?(Symbol) && !name.is_a?(Numeric) && !name.is_a?(TrueClass) && !name.is_a?(FalseClass) ? name.dup : name
87
134
  end
88
135
 
@@ -99,13 +146,33 @@ module CarrierWave
99
146
  value = self.class.#{name} unless instance_variable_defined?(:@#{name})
100
147
  if value.instance_of?(Proc)
101
148
  value.arity >= 1 ? value.call(self) : value.call
102
- else
149
+ else
103
150
  value
104
151
  end
105
152
  end
106
153
  RUBY
107
154
  end
108
155
 
156
+ def add_deprecated_config(name)
157
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
158
+ def self.#{name}(value=nil)
159
+ ActiveSupport::Deprecation.warn "##{name} is deprecated and has no effect"
160
+ end
161
+
162
+ def self.#{name}=(value)
163
+ ActiveSupport::Deprecation.warn "##{name} is deprecated and has no effect"
164
+ end
165
+
166
+ def #{name}=(value)
167
+ ActiveSupport::Deprecation.warn "##{name} is deprecated and has no effect"
168
+ end
169
+
170
+ def #{name}
171
+ ActiveSupport::Deprecation.warn "##{name} is deprecated and has no effect"
172
+ end
173
+ RUBY
174
+ end
175
+
109
176
  def configure
110
177
  yield self
111
178
  end
@@ -115,24 +182,28 @@ module CarrierWave
115
182
  #
116
183
  def reset_config
117
184
  configure do |config|
118
- config.permissions = 0644
119
- config.directory_permissions = 0755
185
+ config.permissions = 0o644
186
+ config.directory_permissions = 0o755
120
187
  config.storage_engines = {
121
188
  :file => "CarrierWave::Storage::File",
122
189
  :fog => "CarrierWave::Storage::Fog"
123
190
  }
124
191
  config.storage = :file
192
+ config.cache_storage = nil
125
193
  config.fog_attributes = {}
126
194
  config.fog_credentials = {}
127
195
  config.fog_public = true
128
196
  config.fog_authenticated_url_expiration = 600
129
197
  config.fog_use_ssl_for_aws = true
198
+ config.fog_aws_accelerate = false
130
199
  config.store_dir = 'uploads'
131
200
  config.cache_dir = 'uploads/tmp'
132
201
  config.delete_tmp_file_after_storage = true
133
202
  config.move_to_cache = false
134
203
  config.move_to_store = false
135
204
  config.remove_previously_stored_files_after_update = true
205
+ config.downloader = CarrierWave::Downloader::Base
206
+ config.force_extension = false
136
207
  config.ignore_integrity_errors = true
137
208
  config.ignore_processing_errors = true
138
209
  config.ignore_download_errors = true
@@ -143,6 +214,8 @@ module CarrierWave
143
214
  config.base_path = CarrierWave.base_path
144
215
  config.enable_processing = true
145
216
  config.ensure_multipart_form = true
217
+ config.download_retry_count = 0
218
+ config.download_retry_wait_time = 5
146
219
  end
147
220
  end
148
221
  end
@@ -150,4 +223,3 @@ module CarrierWave
150
223
  end
151
224
  end
152
225
  end
153
-
@@ -0,0 +1,62 @@
1
+ module CarrierWave
2
+ module Uploader
3
+ module ContentTypeAllowlist
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ before :cache, :check_content_type_allowlist!
8
+ end
9
+
10
+ ##
11
+ # Override this method in your uploader to provide an allowlist of files content types
12
+ # which are allowed to be uploaded.
13
+ # Not only strings but Regexp are allowed as well.
14
+ #
15
+ # === Returns
16
+ #
17
+ # [NilClass, String, Regexp, Array[String, Regexp]] an allowlist of content types which are allowed to be uploaded
18
+ #
19
+ # === Examples
20
+ #
21
+ # def content_type_allowlist
22
+ # %w(text/json application/json)
23
+ # end
24
+ #
25
+ # Basically the same, but using a Regexp:
26
+ #
27
+ # def content_type_allowlist
28
+ # [/(text|application)\/json/]
29
+ # end
30
+ #
31
+ def content_type_allowlist
32
+ end
33
+
34
+ private
35
+
36
+ def check_content_type_allowlist!(new_file)
37
+ allowlist = content_type_allowlist
38
+ if !allowlist && respond_to?(:content_type_whitelist) && content_type_whitelist
39
+ ActiveSupport::Deprecation.warn "#content_type_whitelist is deprecated, use #content_type_allowlist instead." unless instance_variable_defined?(:@content_type_whitelist_warned)
40
+ @content_type_whitelist_warned = true
41
+ allowlist = content_type_whitelist
42
+ end
43
+
44
+ return unless allowlist
45
+
46
+ content_type = new_file.content_type
47
+ if !allowlisted_content_type?(allowlist, content_type)
48
+ raise CarrierWave::IntegrityError, I18n.translate(:"errors.messages.content_type_allowlist_error", content_type: content_type,
49
+ allowed_types: Array(allowlist).join(", "), default: :"errors.messages.content_type_whitelist_error")
50
+ end
51
+ end
52
+
53
+ def allowlisted_content_type?(allowlist, content_type)
54
+ Array(allowlist).any? do |item|
55
+ item = Regexp.quote(item) if item.class != Regexp
56
+ content_type =~ /#{item}/
57
+ end
58
+ end
59
+
60
+ end # ContentTypeAllowlist
61
+ end # Uploader
62
+ end # CarrierWave
@@ -0,0 +1,62 @@
1
+ module CarrierWave
2
+ module Uploader
3
+ module ContentTypeDenylist
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ before :cache, :check_content_type_denylist!
8
+ end
9
+
10
+ ##
11
+ # Override this method in your uploader to provide a denylist of files content types
12
+ # which are not allowed to be uploaded.
13
+ # Not only strings but Regexp are allowed as well.
14
+ #
15
+ # === Returns
16
+ #
17
+ # [NilClass, String, Regexp, Array[String, Regexp]] a denylist of content types which are not allowed to be uploaded
18
+ #
19
+ # === Examples
20
+ #
21
+ # def content_type_denylist
22
+ # %w(text/json application/json)
23
+ # end
24
+ #
25
+ # Basically the same, but using a Regexp:
26
+ #
27
+ # def content_type_denylist
28
+ # [/(text|application)\/json/]
29
+ # end
30
+ #
31
+ def content_type_denylist
32
+ end
33
+
34
+ private
35
+
36
+ def check_content_type_denylist!(new_file)
37
+ denylist = content_type_denylist
38
+ if !denylist && respond_to?(:content_type_blacklist) && content_type_blacklist
39
+ ActiveSupport::Deprecation.warn "#content_type_blacklist is deprecated, use #content_type_denylist instead." unless instance_variable_defined?(:@content_type_blacklist_warned)
40
+ @content_type_blacklist_warned = true
41
+ denylist = content_type_blacklist
42
+ end
43
+
44
+ return unless denylist
45
+
46
+ ActiveSupport::Deprecation.warn "Use of #content_type_denylist is deprecated for the security reason, use #content_type_allowlist instead to explicitly state what are safe to accept" unless instance_variable_defined?(:@content_type_denylist_warned)
47
+ @content_type_denylist_warned = true
48
+
49
+ content_type = new_file.content_type
50
+ if denylisted_content_type?(denylist, content_type)
51
+ raise CarrierWave::IntegrityError, I18n.translate(:"errors.messages.content_type_denylist_error",
52
+ content_type: content_type, default: :"errors.messages.content_type_blacklist_error")
53
+ end
54
+ end
55
+
56
+ def denylisted_content_type?(denylist, content_type)
57
+ Array(denylist).any? { |item| content_type =~ /#{item}/ }
58
+ end
59
+
60
+ end # ContentTypeDenylist
61
+ end # Uploader
62
+ end # CarrierWave
@@ -1,19 +1,17 @@
1
- # encoding: utf-8
2
-
3
1
  module CarrierWave
4
2
  module Uploader
5
3
  module DefaultUrl
6
4
 
7
5
  def url(*args)
8
- super || default_url
6
+ super || default_url(*args)
9
7
  end
10
8
 
11
9
  ##
12
10
  # Override this method in your uploader to provide a default url
13
11
  # in case no file has been cached/stored yet.
14
12
  #
15
- def default_url; end
13
+ def default_url(*args); end
16
14
 
17
15
  end # DefaultPath
18
16
  end # Uploader
19
- end # CarrierWave
17
+ end # CarrierWave
@@ -0,0 +1,66 @@
1
+ require 'active_support'
2
+
3
+ module CarrierWave
4
+ module Uploader
5
+ module Dimension
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ before :cache, :check_dimensions!
10
+ end
11
+
12
+ ##
13
+ # Override this method in your uploader to provide a Range of width which
14
+ # are allowed to be uploaded.
15
+ # === Returns
16
+ #
17
+ # [NilClass, Range] a width range which are permitted to be uploaded
18
+ #
19
+ # === Examples
20
+ #
21
+ # def width_range
22
+ # 1000..2000
23
+ # end
24
+ #
25
+ def width_range; end
26
+
27
+ ##
28
+ # Override this method in your uploader to provide a Range of height which
29
+ # are allowed to be uploaded.
30
+ # === Returns
31
+ #
32
+ # [NilClass, Range] a height range which are permitted to be uploaded
33
+ #
34
+ # === Examples
35
+ #
36
+ # def height_range
37
+ # 1000..
38
+ # end
39
+ #
40
+ def height_range; end
41
+
42
+ private
43
+
44
+ def check_dimensions!(new_file)
45
+ # NOTE: Skip the check for resized images
46
+ return if version_name.present?
47
+ return unless width_range || height_range
48
+
49
+ unless respond_to?(:width) || respond_to?(:height)
50
+ raise 'You need to include one of CarrierWave::MiniMagick, CarrierWave::RMagick, or CarrierWave::Vips to perform image dimension validation'
51
+ end
52
+
53
+ if width_range&.begin && width < width_range.begin
54
+ raise CarrierWave::IntegrityError, I18n.translate(:"errors.messages.min_width_error", :min_width => ActiveSupport::NumberHelper.number_to_delimited(width_range.begin))
55
+ elsif width_range&.end && width > width_range.end
56
+ raise CarrierWave::IntegrityError, I18n.translate(:"errors.messages.max_width_error", :max_width => ActiveSupport::NumberHelper.number_to_delimited(width_range.end))
57
+ elsif height_range&.begin && height < height_range.begin
58
+ raise CarrierWave::IntegrityError, I18n.translate(:"errors.messages.min_height_error", :min_height => ActiveSupport::NumberHelper.number_to_delimited(height_range.begin))
59
+ elsif height_range&.end && height > height_range.end
60
+ raise CarrierWave::IntegrityError, I18n.translate(:"errors.messages.max_height_error", :max_height => ActiveSupport::NumberHelper.number_to_delimited(height_range.end))
61
+ end
62
+ end
63
+
64
+ end # Dimension
65
+ end # Uploader
66
+ end # CarrierWave
@@ -1,7 +1,3 @@
1
- # encoding: utf-8
2
-
3
- require 'open-uri'
4
-
5
1
  module CarrierWave
6
2
  module Uploader
7
3
  module Download
@@ -11,78 +7,18 @@ module CarrierWave
11
7
  include CarrierWave::Uploader::Configuration
12
8
  include CarrierWave::Uploader::Cache
13
9
 
14
- class RemoteFile
15
- def initialize(uri)
16
- @uri = uri
17
- end
18
-
19
- def original_filename
20
- if file.meta.include? 'content-disposition'
21
- match = file.meta['content-disposition'].match(/filename=(\"?)(.+)\1/)
22
- return match[2] unless match.nil?
23
- end
24
- File.basename(file.base_uri.path)
25
- end
26
-
27
- def respond_to?(*args)
28
- super or file.respond_to?(*args)
29
- end
30
-
31
- def http?
32
- @uri.scheme =~ /^https?$/
33
- end
34
-
35
- private
36
-
37
- def file
38
- if @file.blank?
39
- @file = Kernel.open(@uri.to_s)
40
- @file = @file.is_a?(String) ? StringIO.new(@file) : @file
41
- end
42
- @file
43
-
44
- rescue Exception => e
45
- raise CarrierWave::DownloadError, "could not download file: #{e.message}"
46
- end
47
-
48
- def method_missing(*args, &block)
49
- file.send(*args, &block)
50
- end
51
- end
52
-
53
- ##
54
- # Caches the file by downloading it from the given URL.
55
- #
56
- # === Parameters
57
- #
58
- # [url (String)] The URL where the remote file is stored
59
- #
60
- def download!(uri)
61
- unless uri.blank?
62
- processed_uri = process_uri(uri)
63
- file = RemoteFile.new(processed_uri)
64
- raise CarrierWave::DownloadError, "trying to download a file which is not served over HTTP" unless file.http?
65
- cache!(file)
66
- end
67
- end
68
-
69
10
  ##
70
- # Processes the given URL by parsing and escaping it. Public to allow overriding.
11
+ # Caches the file by downloading it from the given URL, using downloader.
71
12
  #
72
13
  # === Parameters
73
14
  #
74
15
  # [url (String)] The URL where the remote file is stored
16
+ # [remote_headers (Hash)] Request headers
75
17
  #
76
- def process_uri(uri)
77
- URI.parse(uri)
78
- rescue URI::InvalidURIError
79
- uri_parts = uri.split('?')
80
- # regexp from Ruby's URI::Parser#regexp[:UNSAFE], with [] specifically removed
81
- encoded_uri = URI.encode(uri_parts.shift, /[^\-_.!~*'()a-zA-Z\d;\/?:@&=+$,]/)
82
- encoded_uri << '?' << URI.encode(uri_parts.join('?')) if uri_parts.any?
83
- URI.parse(encoded_uri) rescue raise CarrierWave::DownloadError, "couldn't parse URL"
18
+ def download!(uri, remote_headers = {})
19
+ file = downloader.new(self).download(uri, remote_headers)
20
+ cache!(file)
84
21
  end
85
-
86
22
  end # Download
87
23
  end # Uploader
88
24
  end # CarrierWave
@@ -0,0 +1,63 @@
1
+ module CarrierWave
2
+ module Uploader
3
+ module ExtensionAllowlist
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ before :cache, :check_extension_allowlist!
8
+ end
9
+
10
+ ##
11
+ # Override this method in your uploader to provide an allowlist of extensions which
12
+ # are allowed to be uploaded. Compares the file's extension case insensitive.
13
+ # Furthermore, not only strings but Regexp are allowed as well.
14
+ #
15
+ # When using a Regexp in the allowlist, `\A` and `\z` are automatically added to
16
+ # the Regexp expression, also case insensitive.
17
+ #
18
+ # === Returns
19
+ #
20
+ # [NilClass, String, Regexp, Array[String, Regexp]] an allowlist of extensions which are allowed to be uploaded
21
+ #
22
+ # === Examples
23
+ #
24
+ # def extension_allowlist
25
+ # %w(jpg jpeg gif png)
26
+ # end
27
+ #
28
+ # Basically the same, but using a Regexp:
29
+ #
30
+ # def extension_allowlist
31
+ # [/jpe?g/, 'gif', 'png']
32
+ # end
33
+ #
34
+ def extension_allowlist
35
+ end
36
+
37
+ private
38
+
39
+ def check_extension_allowlist!(new_file)
40
+ allowlist = extension_allowlist
41
+ if !allowlist && respond_to?(:extension_whitelist) && extension_whitelist
42
+ ActiveSupport::Deprecation.warn "#extension_whitelist is deprecated, use #extension_allowlist instead." unless instance_variable_defined?(:@extension_whitelist_warned)
43
+ @extension_whitelist_warned = true
44
+ allowlist = extension_whitelist
45
+ end
46
+
47
+ return unless allowlist
48
+
49
+ extension = new_file.extension.to_s
50
+ if !allowlisted_extension?(allowlist, extension)
51
+ # Look for whitelist first, then fallback to allowlist
52
+ raise CarrierWave::IntegrityError, I18n.translate(:"errors.messages.extension_allowlist_error", extension: new_file.extension.inspect,
53
+ allowed_types: Array(allowlist).join(", "), default: :"errors.messages.extension_whitelist_error")
54
+ end
55
+ end
56
+
57
+ def allowlisted_extension?(allowlist, extension)
58
+ downcase_extension = extension.downcase
59
+ Array(allowlist).any? { |item| downcase_extension =~ /\A#{item}\z/i }
60
+ end
61
+ end # ExtensionAllowlist
62
+ end # Uploader
63
+ end # CarrierWave
@@ -0,0 +1,64 @@
1
+ module CarrierWave
2
+ module Uploader
3
+ module ExtensionDenylist
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ before :cache, :check_extension_denylist!
8
+ end
9
+
10
+ ##
11
+ # Override this method in your uploader to provide a denylist of extensions which
12
+ # are prohibited to be uploaded. Compares the file's extension case insensitive.
13
+ # Furthermore, not only strings but Regexp are allowed as well.
14
+ #
15
+ # When using a Regexp in the denylist, `\A` and `\z` are automatically added to
16
+ # the Regexp expression, also case insensitive.
17
+ #
18
+ # === Returns
19
+
20
+ # [NilClass, String, Regexp, Array[String, Regexp]] a deny list of extensions which are prohibited to be uploaded
21
+ #
22
+ # === Examples
23
+ #
24
+ # def extension_denylist
25
+ # %w(swf tiff)
26
+ # end
27
+ #
28
+ # Basically the same, but using a Regexp:
29
+ #
30
+ # def extension_denylist
31
+ # [/swf/, 'tiff']
32
+ # end
33
+ #
34
+ def extension_denylist
35
+ end
36
+
37
+ private
38
+
39
+ def check_extension_denylist!(new_file)
40
+ denylist = extension_denylist
41
+ if !denylist && respond_to?(:extension_blacklist) && extension_blacklist
42
+ ActiveSupport::Deprecation.warn "#extension_blacklist is deprecated, use #extension_denylist instead." unless instance_variable_defined?(:@extension_blacklist_warned)
43
+ @extension_blacklist_warned = true
44
+ denylist = extension_blacklist
45
+ end
46
+
47
+ return unless denylist
48
+
49
+ ActiveSupport::Deprecation.warn "Use of #extension_denylist is deprecated for the security reason, use #extension_allowlist instead to explicitly state what are safe to accept" unless instance_variable_defined?(:@extension_denylist_warned)
50
+ @extension_denylist_warned = true
51
+
52
+ extension = new_file.extension.to_s
53
+ if denylisted_extension?(denylist, extension)
54
+ raise CarrierWave::IntegrityError, I18n.translate(:"errors.messages.extension_denylist_error", extension: new_file.extension.inspect,
55
+ prohibited_types: Array(extension_denylist).join(", "), default: :"errors.messages.extension_blacklist_error")
56
+ end
57
+ end
58
+
59
+ def denylisted_extension?(denylist, extension)
60
+ Array(denylist).any? { |item| extension =~ /\A#{item}\z/i }
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,43 @@
1
+ require 'active_support'
2
+
3
+ module CarrierWave
4
+ module Uploader
5
+ module FileSize
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ before :cache, :check_size!
10
+ end
11
+
12
+ ##
13
+ # Override this method in your uploader to provide a Range of Size which
14
+ # are allowed to be uploaded.
15
+ # === Returns
16
+ #
17
+ # [NilClass, Range] a size range (in bytes) which are permitted to be uploaded
18
+ #
19
+ # === Examples
20
+ #
21
+ # def size_range
22
+ # 3256...5748
23
+ # end
24
+ #
25
+ def size_range; end
26
+
27
+ private
28
+
29
+ def check_size!(new_file)
30
+ size = new_file.size
31
+ expected_size_range = size_range
32
+ if expected_size_range.is_a?(::Range)
33
+ if size < expected_size_range.min
34
+ raise CarrierWave::IntegrityError, I18n.translate(:"errors.messages.min_size_error", :min_size => ActiveSupport::NumberHelper.number_to_human_size(expected_size_range.min))
35
+ elsif size > expected_size_range.max
36
+ raise CarrierWave::IntegrityError, I18n.translate(:"errors.messages.max_size_error", :max_size => ActiveSupport::NumberHelper.number_to_human_size(expected_size_range.max))
37
+ end
38
+ end
39
+ end
40
+
41
+ end # FileSize
42
+ end # Uploader
43
+ end # CarrierWave