carrierwave 0.11.2 → 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.

Files changed (58) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +255 -125
  3. data/lib/carrierwave/compatibility/paperclip.rb +0 -2
  4. data/lib/carrierwave/error.rb +1 -0
  5. data/lib/carrierwave/locale/en.yml +7 -4
  6. data/lib/carrierwave/mount.rb +219 -176
  7. data/lib/carrierwave/mounter.rb +165 -0
  8. data/lib/carrierwave/orm/activerecord.rb +50 -21
  9. data/lib/carrierwave/processing/mini_magick.rb +86 -15
  10. data/lib/carrierwave/processing/rmagick.rb +63 -8
  11. data/lib/carrierwave/processing.rb +0 -1
  12. data/lib/carrierwave/sanitized_file.rb +51 -46
  13. data/lib/carrierwave/storage/abstract.rb +15 -2
  14. data/lib/carrierwave/storage/file.rb +69 -2
  15. data/lib/carrierwave/storage/fog.rb +152 -33
  16. data/lib/carrierwave/storage.rb +0 -9
  17. data/lib/carrierwave/test/matchers.rb +77 -12
  18. data/lib/carrierwave/uploader/cache.rb +41 -27
  19. data/lib/carrierwave/uploader/callbacks.rb +0 -2
  20. data/lib/carrierwave/uploader/configuration.rb +54 -9
  21. data/lib/carrierwave/uploader/content_type_whitelist.rb +1 -1
  22. data/lib/carrierwave/uploader/default_url.rb +3 -5
  23. data/lib/carrierwave/uploader/download.rb +66 -15
  24. data/lib/carrierwave/uploader/extension_blacklist.rb +14 -10
  25. data/lib/carrierwave/uploader/extension_whitelist.rb +13 -10
  26. data/lib/carrierwave/uploader/file_size.rb +43 -0
  27. data/lib/carrierwave/uploader/mountable.rb +7 -8
  28. data/lib/carrierwave/uploader/processing.rb +10 -10
  29. data/lib/carrierwave/uploader/proxy.rb +5 -7
  30. data/lib/carrierwave/uploader/remove.rb +0 -2
  31. data/lib/carrierwave/uploader/serialization.rb +1 -3
  32. data/lib/carrierwave/uploader/store.rb +14 -23
  33. data/lib/carrierwave/uploader/url.rb +3 -5
  34. data/lib/carrierwave/uploader/versions.rb +82 -82
  35. data/lib/carrierwave/uploader.rb +11 -2
  36. data/lib/carrierwave/utilities/uri.rb +5 -6
  37. data/lib/carrierwave/utilities.rb +0 -3
  38. data/lib/carrierwave/validations/active_model.rb +3 -5
  39. data/lib/carrierwave/version.rb +1 -1
  40. data/lib/carrierwave.rb +32 -10
  41. data/lib/generators/templates/uploader.rb +4 -8
  42. metadata +64 -79
  43. data/lib/carrierwave/locale/cs.yml +0 -11
  44. data/lib/carrierwave/locale/de.yml +0 -11
  45. data/lib/carrierwave/locale/el.yml +0 -11
  46. data/lib/carrierwave/locale/es.yml +0 -11
  47. data/lib/carrierwave/locale/fr.yml +0 -11
  48. data/lib/carrierwave/locale/ja.yml +0 -11
  49. data/lib/carrierwave/locale/nb.yml +0 -11
  50. data/lib/carrierwave/locale/nl.yml +0 -11
  51. data/lib/carrierwave/locale/pl.yml +0 -11
  52. data/lib/carrierwave/locale/pt-BR.yml +0 -11
  53. data/lib/carrierwave/locale/pt-PT.yml +0 -11
  54. data/lib/carrierwave/locale/ru.yml +0 -11
  55. data/lib/carrierwave/locale/sk.yml +0 -11
  56. data/lib/carrierwave/locale/tr.yml +0 -11
  57. data/lib/carrierwave/processing/mime_types.rb +0 -74
  58. data/lib/carrierwave/utilities/deprecation.rb +0 -18
@@ -1,5 +1,3 @@
1
- # encoding: utf-8
2
-
3
1
  module CarrierWave
4
2
 
5
3
  class FormNotMultipart < UploadError
@@ -54,13 +52,7 @@ module CarrierWave
54
52
  # It's recommended that you keep cache files in one place only.
55
53
  #
56
54
  def clean_cached_files!(seconds=60*60*24)
57
- Dir.glob(File.expand_path(File.join(cache_dir, '*'), CarrierWave.root)).each do |dir|
58
- time = dir.scan(/(\d+)-\d+-\d+/).first.map { |t| t.to_i }
59
- time = Time.at(*time)
60
- if time < (Time.now.utc - seconds)
61
- FileUtils.rm_rf(dir)
62
- end
63
- end
55
+ cache_storage.new(CarrierWave::Uploader::Base.new).clean_cache!(seconds)
64
56
  end
65
57
  end
66
58
 
@@ -89,10 +81,8 @@ module CarrierWave
89
81
  _content = file.read
90
82
  if _content.is_a?(File) # could be if storage is Fog
91
83
  sanitized = CarrierWave::Storage::Fog.new(self).retrieve!(File.basename(_content.path))
92
- sanitized.read if sanitized.exists?
93
-
94
84
  else
95
- sanitized = SanitizedFile.new :tempfile => StringIO.new(file.read),
85
+ sanitized = SanitizedFile.new :tempfile => StringIO.new(_content),
96
86
  :filename => File.basename(path), :content_type => file.content_type
97
87
  end
98
88
  sanitized
@@ -127,22 +117,28 @@ module CarrierWave
127
117
  #
128
118
  def cache!(new_file = sanitized_file)
129
119
  new_file = CarrierWave::SanitizedFile.new(new_file)
120
+ return if new_file.empty?
121
+
122
+ raise CarrierWave::FormNotMultipart if new_file.is_path? && ensure_multipart_form
130
123
 
131
- unless new_file.empty?
132
- raise CarrierWave::FormNotMultipart if new_file.is_path? && ensure_multipart_form
124
+ self.cache_id = CarrierWave.generate_cache_id unless cache_id
133
125
 
134
- with_callbacks(:cache, new_file) do
135
- self.cache_id = CarrierWave.generate_cache_id unless cache_id
126
+ @filename = new_file.filename
127
+ self.original_filename = new_file.filename
136
128
 
137
- @filename = new_file.filename
138
- self.original_filename = new_file.filename
129
+ begin
130
+ # first, create a workfile on which we perform processings
131
+ if move_to_cache
132
+ @file = new_file.move_to(File.expand_path(workfile_path, root), permissions, directory_permissions)
133
+ else
134
+ @file = new_file.copy_to(File.expand_path(workfile_path, root), permissions, directory_permissions)
135
+ end
139
136
 
140
- if move_to_cache
141
- @file = new_file.move_to(cache_path, permissions, directory_permissions)
142
- else
143
- @file = new_file.copy_to(cache_path, permissions, directory_permissions)
144
- end
137
+ with_callbacks(:cache, @file) do
138
+ @file = cache_storage.cache!(@file)
145
139
  end
140
+ ensure
141
+ FileUtils.rm_rf(workfile_path(''))
146
142
  end
147
143
  end
148
144
 
@@ -161,14 +157,29 @@ module CarrierWave
161
157
  with_callbacks(:retrieve_from_cache, cache_name) do
162
158
  self.cache_id, self.original_filename = cache_name.to_s.split('/', 2)
163
159
  @filename = original_filename
164
- @file = CarrierWave::SanitizedFile.new(cache_path)
160
+ @file = cache_storage.retrieve_from_cache!(full_filename(original_filename))
165
161
  end
166
162
  end
167
163
 
164
+ ##
165
+ # Calculates the path where the cache file should be stored.
166
+ #
167
+ # === Parameters
168
+ #
169
+ # [for_file (String)] name of the file <optional>
170
+ #
171
+ # === Returns
172
+ #
173
+ # [String] the cache path
174
+ #
175
+ def cache_path(for_file=full_filename(original_filename))
176
+ File.join(*[cache_dir, @cache_id, for_file].compact)
177
+ end
178
+
168
179
  private
169
180
 
170
- def cache_path
171
- File.expand_path(File.join(cache_dir, cache_name), root)
181
+ def workfile_path(for_file=original_filename)
182
+ File.join(CarrierWave.tmp_path, @cache_id, version_name.to_s, for_file)
172
183
  end
173
184
 
174
185
  attr_reader :cache_id, :original_filename
@@ -179,7 +190,7 @@ module CarrierWave
179
190
  def cache_id=(cache_id)
180
191
  # Earlier version used 3 part cache_id. Thus we should allow for
181
192
  # the cache_id to have both 3 part and 4 part formats.
182
- raise CarrierWave::InvalidParameter, "invalid cache id" unless cache_id =~ /\A[\d]+\-[\d]+(\-[\d]{4})?\-[\d]{4}\z/
193
+ raise CarrierWave::InvalidParameter, "invalid cache id" unless cache_id =~ /\A(-)?[\d]+\-[\d]+(\-[\d]{4})?\-[\d]{4}\z/
183
194
  @cache_id = cache_id
184
195
  end
185
196
 
@@ -188,6 +199,9 @@ module CarrierWave
188
199
  @original_filename = filename
189
200
  end
190
201
 
202
+ def cache_storage
203
+ @cache_storage ||= self.class.cache_storage.new(self)
204
+ end
191
205
  end # Cache
192
206
  end # Uploader
193
207
  end # CarrierWave
@@ -1,5 +1,3 @@
1
- # encoding: utf-8
2
-
3
1
  module CarrierWave
4
2
  module Uploader
5
3
  module Callbacks
@@ -5,7 +5,7 @@ module CarrierWave
5
5
  extend ActiveSupport::Concern
6
6
 
7
7
  included do
8
- class_attribute :_storage, :instance_writer => false
8
+ class_attribute :_storage, :_cache_storage, :instance_writer => false
9
9
 
10
10
  add_config :root
11
11
  add_config :base_path
@@ -23,12 +23,14 @@ module CarrierWave
23
23
  add_config :remove_previously_stored_files_after_update
24
24
 
25
25
  # fog
26
+ add_config :fog_provider
26
27
  add_config :fog_attributes
27
28
  add_config :fog_credentials
28
29
  add_config :fog_directory
29
30
  add_config :fog_public
30
31
  add_config :fog_authenticated_url_expiration
31
32
  add_config :fog_use_ssl_for_aws
33
+ add_config :fog_aws_accelerate
32
34
 
33
35
  # Mounting
34
36
  add_config :ignore_integrity_errors
@@ -38,6 +40,7 @@ module CarrierWave
38
40
  add_config :validate_processing
39
41
  add_config :validate_download
40
42
  add_config :mount_on
43
+ add_config :cache_only
41
44
 
42
45
  # set default values
43
46
  reset_config
@@ -69,36 +72,76 @@ module CarrierWave
69
72
  # storage MyCustomStorageEngine
70
73
  #
71
74
  def storage(storage = nil)
72
- if storage
73
- self._storage = storage.is_a?(Symbol) ? eval(storage_engines[storage]) : storage
75
+ case storage
76
+ when Symbol
77
+ if storage_engine = storage_engines[storage]
78
+ self._storage = eval storage_engine
79
+ else
80
+ raise CarrierWave::UnknownStorageError, "Unknown storage: #{storage}"
81
+ end
82
+ when nil
83
+ storage
84
+ else
85
+ self._storage = storage
74
86
  end
75
87
  _storage
76
88
  end
77
89
  alias_method :storage=, :storage
78
90
 
91
+ ##
92
+ # Sets the cache storage engine to be used when storing cache files with this uploader.
93
+ # Same as .storage except for required methods being #cache!(CarrierWave::SanitizedFile),
94
+ # #retrieve_from_cache! and #delete_dir!.
95
+ #
96
+ # === Parameters
97
+ #
98
+ # [storage (Symbol, Class)] The cache storage engine to use for this uploader
99
+ #
100
+ # === Returns
101
+ #
102
+ # [Class] the cache storage engine to be used with this uploader
103
+ #
104
+ # === Examples
105
+ #
106
+ # cache_storage :file
107
+ # cache_storage CarrierWave::Storage::File
108
+ # cache_storage MyCustomStorageEngine
109
+ #
110
+ def cache_storage(storage = nil)
111
+ if storage
112
+ self._cache_storage = storage.is_a?(Symbol) ? eval(storage_engines[storage]) : storage
113
+ end
114
+ _cache_storage
115
+ end
116
+ alias_method :cache_storage=, :cache_storage
117
+
79
118
  def add_config(name)
80
119
  class_eval <<-RUBY, __FILE__, __LINE__ + 1
120
+ @#{name} = nil
121
+
81
122
  def self.eager_load_fog(fog_credentials)
82
123
  # see #1198. This will hopefully no longer be necessary after fog 2.0
124
+ require self.fog_provider
125
+ require 'carrierwave/storage/fog'
83
126
  Fog::Storage.new(fog_credentials) if fog_credentials.present?
84
- end
127
+ end unless defined? eager_load_fog
85
128
 
86
129
  def self.#{name}(value=nil)
87
130
  @#{name} = value if value
88
131
  eager_load_fog(value) if value && '#{name}' == 'fog_credentials'
89
132
  return @#{name} if self.object_id == #{self.object_id} || defined?(@#{name})
90
133
  name = superclass.#{name}
91
- return nil if name.nil? && !instance_variable_defined?("@#{name}")
134
+ return nil if name.nil? && !instance_variable_defined?(:@#{name})
92
135
  @#{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
93
136
  end
94
137
 
95
138
  def self.#{name}=(value)
96
- eager_load_fog(value) if '#{name}' == 'fog_credentials'
139
+ eager_load_fog(value) if '#{name}' == 'fog_credentials' && value.present?
97
140
  @#{name} = value
98
141
  end
99
142
 
100
143
  def #{name}=(value)
101
- self.class.eager_load_fog(value) if '#{name}' == 'fog_credentials'
144
+ self.class.eager_load_fog(value) if '#{name}' == 'fog_credentials' && value.present?
102
145
  @#{name} = value
103
146
  end
104
147
 
@@ -107,7 +150,7 @@ module CarrierWave
107
150
  value = self.class.#{name} unless instance_variable_defined?(:@#{name})
108
151
  if value.instance_of?(Proc)
109
152
  value.arity >= 1 ? value.call(self) : value.call
110
- else
153
+ else
111
154
  value
112
155
  end
113
156
  end
@@ -130,11 +173,14 @@ module CarrierWave
130
173
  :fog => "CarrierWave::Storage::Fog"
131
174
  }
132
175
  config.storage = :file
176
+ config.cache_storage = :file
177
+ config.fog_provider = 'fog'
133
178
  config.fog_attributes = {}
134
179
  config.fog_credentials = {}
135
180
  config.fog_public = true
136
181
  config.fog_authenticated_url_expiration = 600
137
182
  config.fog_use_ssl_for_aws = true
183
+ config.fog_aws_accelerate = false
138
184
  config.store_dir = 'uploads'
139
185
  config.cache_dir = 'uploads/tmp'
140
186
  config.delete_tmp_file_after_storage = true
@@ -158,4 +204,3 @@ module CarrierWave
158
204
  end
159
205
  end
160
206
  end
161
-
@@ -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,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
@@ -1,6 +1,5 @@
1
- # encoding: utf-8
2
-
3
1
  require 'open-uri'
2
+ require 'ssrf_filter'
4
3
 
5
4
  module CarrierWave
6
5
  module Uploader
@@ -12,13 +11,18 @@ module CarrierWave
12
11
  include CarrierWave::Uploader::Cache
13
12
 
14
13
  class RemoteFile
15
- def initialize(uri)
14
+ attr_reader :uri
15
+
16
+ def initialize(uri, remote_headers = {}, skip_ssrf_protection: false)
16
17
  @uri = uri
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
- filename = filename_from_header || File.basename(file.base_uri.path)
21
- mime_type = MIME::Types[file.content_type].first
24
+ filename = filename_from_header || filename_from_uri
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,26 +37,53 @@ 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
- @file = Kernel.open(@uri.to_s)
41
- @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
42
69
  end
43
70
  @file
44
71
 
45
- rescue Exception => e
72
+ rescue StandardError => e
46
73
  raise CarrierWave::DownloadError, "could not download file: #{e.message}"
47
74
  end
48
75
 
49
76
  def filename_from_header
50
- if file.meta.include? 'content-disposition'
51
- match = file.meta['content-disposition'].match(/filename="?([^"]+)/)
77
+ if headers['content-disposition']
78
+ match = headers['content-disposition'].match(/filename="?([^"]+)/)
52
79
  return match[1] unless match.nil? || match[1].empty?
53
80
  end
54
81
  end
55
82
 
83
+ def filename_from_uri
84
+ URI::DEFAULT_PARSER.unescape(File.basename(@uri.path))
85
+ end
86
+
56
87
  def method_missing(*args, &block)
57
88
  file.send(*args, &block)
58
89
  end
@@ -64,10 +95,11 @@ module CarrierWave
64
95
  # === Parameters
65
96
  #
66
97
  # [url (String)] The URL where the remote file is stored
98
+ # [remote_headers (Hash)] Request headers
67
99
  #
68
- def download!(uri)
100
+ def download!(uri, remote_headers = {})
69
101
  processed_uri = process_uri(uri)
70
- file = RemoteFile.new(processed_uri)
102
+ file = RemoteFile.new(processed_uri, remote_headers, skip_ssrf_protection: skip_ssrf_protection?(processed_uri))
71
103
  raise CarrierWave::DownloadError, "trying to download a file which is not served over HTTP" unless file.http?
72
104
  cache!(file)
73
105
  end
@@ -84,11 +116,30 @@ module CarrierWave
84
116
  rescue URI::InvalidURIError
85
117
  uri_parts = uri.split('?')
86
118
  # regexp from Ruby's URI::Parser#regexp[:UNSAFE], with [] specifically removed
87
- encoded_uri = URI.encode(uri_parts.shift, /[^\-_.!~*'()a-zA-Z\d;\/?:@&=+$,]/)
88
- 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?
89
121
  URI.parse(encoded_uri) rescue raise CarrierWave::DownloadError, "couldn't parse URL"
90
122
  end
91
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
92
143
  end # Download
93
144
  end # Uploader
94
145
  end # CarrierWave
@@ -4,7 +4,7 @@ module CarrierWave
4
4
  extend ActiveSupport::Concern
5
5
 
6
6
  included do
7
- before :cache, :check_blacklist!
7
+ before :cache, :check_extension_blacklist!
8
8
  end
9
9
 
10
10
  ##
@@ -16,32 +16,36 @@ module CarrierWave
16
16
  # the Regexp expression, also case insensitive.
17
17
  #
18
18
  # === Returns
19
-
20
- # [NilClass, Array[String,Regexp]] a black list of extensions which are prohibited to be uploaded
19
+
20
+ # [NilClass, String, Regexp, Array[String, Regexp]] a black list of extensions which are prohibited to be uploaded
21
21
  #
22
22
  # === Examples
23
23
  #
24
- # def extension_black_list
24
+ # def extension_blacklist
25
25
  # %w(swf tiff)
26
26
  # end
27
27
  #
28
28
  # Basically the same, but using a Regexp:
29
29
  #
30
- # def extension_black_list
30
+ # def extension_blacklist
31
31
  # [/swf/, 'tiff']
32
32
  # end
33
33
  #
34
-
35
- def extension_black_list; end
34
+
35
+ def extension_blacklist; end
36
36
 
37
37
  private
38
38
 
39
- def check_blacklist!(new_file)
39
+ def check_extension_blacklist!(new_file)
40
40
  extension = new_file.extension.to_s
41
- if extension_black_list and extension_black_list.detect { |item| extension =~ /\A#{item}\z/i }
42
- raise CarrierWave::IntegrityError, I18n.translate(:"errors.messages.extension_black_list_error", :extension => new_file.extension.inspect, :prohibited_types => extension_black_list.join(", "))
41
+ if extension_blacklist && blacklisted_extension?(extension)
42
+ raise CarrierWave::IntegrityError, I18n.translate(:"errors.messages.extension_blacklist_error", extension: new_file.extension.inspect, prohibited_types: Array(extension_blacklist).join(", "))
43
43
  end
44
44
  end
45
+
46
+ def blacklisted_extension?(extension)
47
+ Array(extension_blacklist).any? { |item| extension =~ /\A#{item}\z/i }
48
+ end
45
49
  end
46
50
  end
47
51
  end
@@ -1,12 +1,10 @@
1
- # encoding: utf-8
2
-
3
1
  module CarrierWave
4
2
  module Uploader
5
3
  module ExtensionWhitelist
6
4
  extend ActiveSupport::Concern
7
5
 
8
6
  included do
9
- before :cache, :check_whitelist!
7
+ before :cache, :check_extension_whitelist!
10
8
  end
11
9
 
12
10
  ##
@@ -19,31 +17,36 @@ module CarrierWave
19
17
  #
20
18
  # === Returns
21
19
  #
22
- # [NilClass, Array[String,Regexp]] a white list of extensions which are allowed to be uploaded
20
+ # [NilClass, String, Regexp, Array[String, Regexp]] a white list of extensions which are allowed to be uploaded
23
21
  #
24
22
  # === Examples
25
23
  #
26
- # def extension_white_list
24
+ # def extension_whitelist
27
25
  # %w(jpg jpeg gif png)
28
26
  # end
29
27
  #
30
28
  # Basically the same, but using a Regexp:
31
29
  #
32
- # def extension_white_list
30
+ # def extension_whitelist
33
31
  # [/jpe?g/, 'gif', 'png']
34
32
  # end
35
33
  #
36
- def extension_white_list; end
34
+ def extension_whitelist; end
37
35
 
38
36
  private
39
37
 
40
- def check_whitelist!(new_file)
38
+ def check_extension_whitelist!(new_file)
41
39
  extension = new_file.extension.to_s
42
- if extension_white_list and not extension_white_list.detect { |item| extension =~ /\A#{item}\z/i }
43
- raise CarrierWave::IntegrityError, I18n.translate(:"errors.messages.extension_white_list_error", :extension => new_file.extension.inspect, :allowed_types => extension_white_list.join(", "))
40
+ if extension_whitelist && !whitelisted_extension?(extension)
41
+ raise CarrierWave::IntegrityError, I18n.translate(:"errors.messages.extension_whitelist_error", extension: new_file.extension.inspect, allowed_types: Array(extension_whitelist).join(", "))
44
42
  end
45
43
  end
46
44
 
45
+ def whitelisted_extension?(extension)
46
+ downcase_extension = extension.downcase
47
+ Array(extension_whitelist).any? { |item| downcase_extension =~ /\A#{item}\z/i }
48
+ end
49
+
47
50
  end # ExtensionWhitelist
48
51
  end # Uploader
49
52
  end # CarrierWave
@@ -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 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
@@ -1,5 +1,3 @@
1
- # encoding: utf-8
2
-
3
1
  module CarrierWave
4
2
  module Uploader
5
3
  module Mountable
@@ -7,13 +5,14 @@ module CarrierWave
7
5
  attr_reader :model, :mounted_as
8
6
 
9
7
  ##
10
- # If a model is given as the first parameter, it will be stored in the uploader, and
11
- # available throught +#model+. Likewise, mounted_as stores the name of the column
12
- # where this instance of the uploader is mounted. These values can then be used inside
13
- # your uploader.
8
+ # If a model is given as the first parameter, it will be stored in the
9
+ # uploader, and available through +#model+. Likewise, mounted_as stores
10
+ # the name of the column where this instance of the uploader is mounted.
11
+ # These values can then be used inside your uploader.
14
12
  #
15
- # If you do not wish to mount your uploaders with the ORM extensions in -more then you
16
- # can override this method inside your uploader. Just be sure to call +super+
13
+ # If you do not wish to mount your uploaders with the ORM extensions in
14
+ # -more then you can override this method inside your uploader. Just be
15
+ # sure to call +super+
17
16
  #
18
17
  # === Parameters
19
18
  #
@@ -1,5 +1,3 @@
1
- # encoding: utf-8
2
-
3
1
  module CarrierWave
4
2
  module Uploader
5
3
  module Processing
@@ -11,7 +9,7 @@ module CarrierWave
11
9
  class_attribute :processors, :instance_writer => false
12
10
  self.processors = []
13
11
 
14
- after :cache, :process!
12
+ before :cache, :process!
15
13
  end
16
14
 
17
15
  module ClassMethods
@@ -73,15 +71,17 @@ module CarrierWave
73
71
  def process!(new_file=nil)
74
72
  return unless enable_processing
75
73
 
76
- self.class.processors.each do |method, args, condition|
77
- if(condition)
78
- if condition.respond_to?(:call)
79
- next unless condition.call(self, :args => args, :method => method, :file => new_file)
80
- else
81
- next unless self.send(condition, new_file)
74
+ with_callbacks(:process, new_file) do
75
+ self.class.processors.each do |method, args, condition|
76
+ if(condition)
77
+ if condition.respond_to?(:call)
78
+ next unless condition.call(self, :args => args, :method => method, :file => new_file)
79
+ else
80
+ next unless self.send(condition, new_file)
81
+ end
82
82
  end
83
+ self.send(method, *args)
83
84
  end
84
- self.send(method, *args)
85
85
  end
86
86
  end
87
87