carrierwave 0.10.0 → 1.2.0

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 (61) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +248 -116
  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 +82 -15
  10. data/lib/carrierwave/processing/rmagick.rb +47 -4
  11. data/lib/carrierwave/processing.rb +0 -1
  12. data/lib/carrierwave/sanitized_file.rb +38 -18
  13. data/lib/carrierwave/storage/abstract.rb +15 -2
  14. data/lib/carrierwave/storage/file.rb +65 -2
  15. data/lib/carrierwave/storage/fog.rb +106 -31
  16. data/lib/carrierwave/storage.rb +0 -7
  17. data/lib/carrierwave/test/matchers.rb +77 -12
  18. data/lib/carrierwave/uploader/cache.rb +58 -30
  19. data/lib/carrierwave/uploader/callbacks.rb +0 -2
  20. data/lib/carrierwave/uploader/configuration.rb +51 -8
  21. data/lib/carrierwave/uploader/content_type_blacklist.rb +48 -0
  22. data/lib/carrierwave/uploader/content_type_whitelist.rb +48 -0
  23. data/lib/carrierwave/uploader/default_url.rb +3 -5
  24. data/lib/carrierwave/uploader/download.rb +15 -8
  25. data/lib/carrierwave/uploader/extension_blacklist.rb +14 -10
  26. data/lib/carrierwave/uploader/extension_whitelist.rb +13 -10
  27. data/lib/carrierwave/uploader/file_size.rb +43 -0
  28. data/lib/carrierwave/uploader/magic_mime_blacklist.rb +94 -0
  29. data/lib/carrierwave/uploader/magic_mime_whitelist.rb +94 -0
  30. data/lib/carrierwave/uploader/mountable.rb +7 -8
  31. data/lib/carrierwave/uploader/processing.rb +10 -10
  32. data/lib/carrierwave/uploader/proxy.rb +5 -7
  33. data/lib/carrierwave/uploader/remove.rb +0 -2
  34. data/lib/carrierwave/uploader/serialization.rb +1 -3
  35. data/lib/carrierwave/uploader/store.rb +5 -23
  36. data/lib/carrierwave/uploader/url.rb +3 -5
  37. data/lib/carrierwave/uploader/versions.rb +75 -82
  38. data/lib/carrierwave/uploader.rb +6 -2
  39. data/lib/carrierwave/utilities/uri.rb +5 -6
  40. data/lib/carrierwave/utilities.rb +0 -3
  41. data/lib/carrierwave/validations/active_model.rb +3 -5
  42. data/lib/carrierwave/version.rb +1 -1
  43. data/lib/carrierwave.rb +12 -10
  44. data/lib/generators/templates/uploader.rb +4 -6
  45. metadata +37 -61
  46. data/lib/carrierwave/locale/cs.yml +0 -11
  47. data/lib/carrierwave/locale/de.yml +0 -11
  48. data/lib/carrierwave/locale/el.yml +0 -11
  49. data/lib/carrierwave/locale/es.yml +0 -11
  50. data/lib/carrierwave/locale/fr.yml +0 -11
  51. data/lib/carrierwave/locale/ja.yml +0 -11
  52. data/lib/carrierwave/locale/nb.yml +0 -11
  53. data/lib/carrierwave/locale/nl.yml +0 -11
  54. data/lib/carrierwave/locale/pl.yml +0 -11
  55. data/lib/carrierwave/locale/pt-BR.yml +0 -11
  56. data/lib/carrierwave/locale/pt-PT.yml +0 -11
  57. data/lib/carrierwave/locale/ru.yml +0 -11
  58. data/lib/carrierwave/locale/sk.yml +0 -11
  59. data/lib/carrierwave/locale/tr.yml +0 -11
  60. data/lib/carrierwave/processing/mime_types.rb +0 -74
  61. data/lib/carrierwave/utilities/deprecation.rb +0 -18
@@ -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,17 +72,55 @@ 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
81
120
  def self.eager_load_fog(fog_credentials)
82
121
  # see #1198. This will hopefully no longer be necessary after fog 2.0
122
+ require self.fog_provider
123
+ require 'carrierwave/storage/fog'
83
124
  Fog::Storage.new(fog_credentials) if fog_credentials.present?
84
125
  end
85
126
 
@@ -88,17 +129,17 @@ module CarrierWave
88
129
  eager_load_fog(value) if value && '#{name}' == 'fog_credentials'
89
130
  return @#{name} if self.object_id == #{self.object_id} || defined?(@#{name})
90
131
  name = superclass.#{name}
91
- return nil if name.nil? && !instance_variable_defined?("@#{name}")
132
+ return nil if name.nil? && !instance_variable_defined?(:@#{name})
92
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
93
134
  end
94
135
 
95
136
  def self.#{name}=(value)
96
- eager_load_fog(value) if '#{name}' == 'fog_credentials'
137
+ eager_load_fog(value) if '#{name}' == 'fog_credentials' && value.present?
97
138
  @#{name} = value
98
139
  end
99
140
 
100
141
  def #{name}=(value)
101
- self.class.eager_load_fog(value) if '#{name}' == 'fog_credentials'
142
+ self.class.eager_load_fog(value) if '#{name}' == 'fog_credentials' && value.present?
102
143
  @#{name} = value
103
144
  end
104
145
 
@@ -107,7 +148,7 @@ module CarrierWave
107
148
  value = self.class.#{name} unless instance_variable_defined?(:@#{name})
108
149
  if value.instance_of?(Proc)
109
150
  value.arity >= 1 ? value.call(self) : value.call
110
- else
151
+ else
111
152
  value
112
153
  end
113
154
  end
@@ -130,11 +171,14 @@ module CarrierWave
130
171
  :fog => "CarrierWave::Storage::Fog"
131
172
  }
132
173
  config.storage = :file
174
+ config.cache_storage = :file
175
+ config.fog_provider = 'fog'
133
176
  config.fog_attributes = {}
134
177
  config.fog_credentials = {}
135
178
  config.fog_public = true
136
179
  config.fog_authenticated_url_expiration = 600
137
180
  config.fog_use_ssl_for_aws = true
181
+ config.fog_aws_accelerate = false
138
182
  config.store_dir = 'uploads'
139
183
  config.cache_dir = 'uploads/tmp'
140
184
  config.delete_tmp_file_after_storage = true
@@ -158,4 +202,3 @@ module CarrierWave
158
202
  end
159
203
  end
160
204
  end
161
-
@@ -0,0 +1,48 @@
1
+ module CarrierWave
2
+ module Uploader
3
+ module ContentTypeBlacklist
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ before :cache, :check_content_type_blacklist!
8
+ end
9
+
10
+ ##
11
+ # Override this method in your uploader to provide a blacklist 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 blacklist of content types which are not allowed to be uploaded
18
+ #
19
+ # === Examples
20
+ #
21
+ # def content_type_blacklist
22
+ # %w(text/json application/json)
23
+ # end
24
+ #
25
+ # Basically the same, but using a Regexp:
26
+ #
27
+ # def content_type_blacklist
28
+ # [/(text|application)\/json/]
29
+ # end
30
+ #
31
+ def content_type_blacklist; end
32
+
33
+ private
34
+
35
+ def check_content_type_blacklist!(new_file)
36
+ content_type = new_file.content_type
37
+ if content_type_blacklist && blacklisted_content_type?(content_type)
38
+ raise CarrierWave::IntegrityError, I18n.translate(:"errors.messages.content_type_blacklist_error", content_type: content_type)
39
+ end
40
+ end
41
+
42
+ def blacklisted_content_type?(content_type)
43
+ Array(content_type_blacklist).any? { |item| content_type =~ /#{item}/ }
44
+ end
45
+
46
+ end # ContentTypeBlacklist
47
+ end # Uploader
48
+ end # CarrierWave
@@ -0,0 +1,48 @@
1
+ module CarrierWave
2
+ module Uploader
3
+ module ContentTypeWhitelist
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ before :cache, :check_content_type_whitelist!
8
+ end
9
+
10
+ ##
11
+ # Override this method in your uploader to provide a whitelist 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]] a whitelist of content types which are allowed to be uploaded
18
+ #
19
+ # === Examples
20
+ #
21
+ # def content_type_whitelist
22
+ # %w(text/json application/json)
23
+ # end
24
+ #
25
+ # Basically the same, but using a Regexp:
26
+ #
27
+ # def content_type_whitelist
28
+ # [/(text|application)\/json/]
29
+ # end
30
+ #
31
+ def content_type_whitelist; end
32
+
33
+ private
34
+
35
+ def check_content_type_whitelist!(new_file)
36
+ content_type = new_file.content_type
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)
39
+ end
40
+ end
41
+
42
+ def whitelisted_content_type?(content_type)
43
+ Array(content_type_whitelist).any? { |item| content_type =~ /#{item}/ }
44
+ end
45
+
46
+ end # ContentTypeWhitelist
47
+ end # Uploader
48
+ 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
@@ -1,5 +1,3 @@
1
- # encoding: utf-8
2
-
3
1
  require 'open-uri'
4
2
 
5
3
  module CarrierWave
@@ -12,12 +10,13 @@ module CarrierWave
12
10
  include CarrierWave::Uploader::Cache
13
11
 
14
12
  class RemoteFile
15
- def initialize(uri)
13
+ def initialize(uri, remote_headers = {})
16
14
  @uri = uri
15
+ @remote_headers = remote_headers
17
16
  end
18
17
 
19
18
  def original_filename
20
- filename = filename_from_header || File.basename(file.base_uri.path)
19
+ filename = filename_from_header || filename_from_uri
21
20
  mime_type = MIME::Types[file.content_type].first
22
21
  unless File.extname(filename).present? || mime_type.blank?
23
22
  filename = "#{filename}.#{mime_type.extensions.first}"
@@ -37,12 +36,15 @@ module CarrierWave
37
36
 
38
37
  def file
39
38
  if @file.blank?
40
- @file = Kernel.open(@uri.to_s)
39
+ headers = @remote_headers.
40
+ reverse_merge('User-Agent' => "CarrierWave/#{CarrierWave::VERSION}")
41
+
42
+ @file = Kernel.open(@uri.to_s, headers)
41
43
  @file = @file.is_a?(String) ? StringIO.new(@file) : @file
42
44
  end
43
45
  @file
44
46
 
45
- rescue Exception => e
47
+ rescue StandardError => e
46
48
  raise CarrierWave::DownloadError, "could not download file: #{e.message}"
47
49
  end
48
50
 
@@ -53,6 +55,10 @@ module CarrierWave
53
55
  end
54
56
  end
55
57
 
58
+ def filename_from_uri
59
+ URI.decode(File.basename(file.base_uri.path))
60
+ end
61
+
56
62
  def method_missing(*args, &block)
57
63
  file.send(*args, &block)
58
64
  end
@@ -64,10 +70,11 @@ module CarrierWave
64
70
  # === Parameters
65
71
  #
66
72
  # [url (String)] The URL where the remote file is stored
73
+ # [remote_headers (Hash)] Request headers
67
74
  #
68
- def download!(uri)
75
+ def download!(uri, remote_headers = {})
69
76
  processed_uri = process_uri(uri)
70
- file = RemoteFile.new(processed_uri)
77
+ file = RemoteFile.new(processed_uri, remote_headers)
71
78
  raise CarrierWave::DownloadError, "trying to download a file which is not served over HTTP" unless file.http?
72
79
  cache!(file)
73
80
  end
@@ -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
@@ -0,0 +1,94 @@
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
@@ -0,0 +1,94 @@
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