carrierwave 0.9.0 → 2.1.1

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 (51) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +362 -116
  3. data/lib/carrierwave/compatibility/paperclip.rb +29 -21
  4. data/lib/carrierwave/downloader/base.rb +83 -0
  5. data/lib/carrierwave/downloader/remote_file.rb +65 -0
  6. data/lib/carrierwave/error.rb +1 -0
  7. data/lib/carrierwave/locale/en.yml +7 -4
  8. data/lib/carrierwave/mount.rb +238 -186
  9. data/lib/carrierwave/mounter.rb +188 -0
  10. data/lib/carrierwave/orm/activerecord.rb +60 -24
  11. data/lib/carrierwave/processing/mini_magick.rb +139 -78
  12. data/lib/carrierwave/processing/rmagick.rb +68 -23
  13. data/lib/carrierwave/processing.rb +0 -1
  14. data/lib/carrierwave/sanitized_file.rb +67 -27
  15. data/lib/carrierwave/storage/abstract.rb +15 -2
  16. data/lib/carrierwave/storage/file.rb +69 -2
  17. data/lib/carrierwave/storage/fog.rb +180 -41
  18. data/lib/carrierwave/storage.rb +1 -7
  19. data/lib/carrierwave/test/matchers.rb +77 -12
  20. data/lib/carrierwave/uploader/cache.rb +74 -38
  21. data/lib/carrierwave/uploader/callbacks.rb +0 -2
  22. data/lib/carrierwave/uploader/configuration.rb +72 -6
  23. data/lib/carrierwave/uploader/content_type_blacklist.rb +48 -0
  24. data/lib/carrierwave/uploader/content_type_whitelist.rb +48 -0
  25. data/lib/carrierwave/uploader/default_url.rb +3 -5
  26. data/lib/carrierwave/uploader/download.rb +5 -69
  27. data/lib/carrierwave/uploader/extension_blacklist.rb +14 -10
  28. data/lib/carrierwave/uploader/extension_whitelist.rb +13 -10
  29. data/lib/carrierwave/uploader/file_size.rb +43 -0
  30. data/lib/carrierwave/uploader/mountable.rb +13 -8
  31. data/lib/carrierwave/uploader/processing.rb +15 -17
  32. data/lib/carrierwave/uploader/proxy.rb +16 -7
  33. data/lib/carrierwave/uploader/remove.rb +0 -2
  34. data/lib/carrierwave/uploader/serialization.rb +3 -5
  35. data/lib/carrierwave/uploader/store.rb +17 -24
  36. data/lib/carrierwave/uploader/url.rb +3 -5
  37. data/lib/carrierwave/uploader/versions.rb +117 -86
  38. data/lib/carrierwave/uploader.rb +6 -2
  39. data/lib/carrierwave/utilities/uri.rb +5 -6
  40. data/lib/carrierwave/utilities.rb +1 -3
  41. data/lib/carrierwave/validations/active_model.rb +3 -7
  42. data/lib/carrierwave/version.rb +1 -1
  43. data/lib/carrierwave.rb +36 -3
  44. data/lib/generators/templates/uploader.rb +4 -8
  45. data/lib/generators/uploader_generator.rb +1 -1
  46. metadata +195 -94
  47. data/lib/carrierwave/locale/cs.yml +0 -11
  48. data/lib/carrierwave/locale/de.yml +0 -11
  49. data/lib/carrierwave/locale/nl.yml +0 -11
  50. data/lib/carrierwave/locale/sk.yml +0 -11
  51. data/lib/carrierwave/processing/mime_types.rb +0 -73
@@ -1,5 +1,3 @@
1
- # encoding: utf-8
2
-
3
1
  module CarrierWave
4
2
  module Compatibility
5
3
 
@@ -46,11 +44,31 @@ module CarrierWave
46
44
  # THE SOFTWARE.
47
45
  #
48
46
  module Paperclip
47
+ extend ActiveSupport::Concern
48
+
49
+ DEFAULT_MAPPINGS = {
50
+ :rails_root => lambda{|u, f| Rails.root.to_s },
51
+ :rails_env => lambda{|u, f| Rails.env },
52
+ :id_partition => lambda{|u, f| ("%09d" % u.model.id).scan(/\d{3}/).join("/")},
53
+ :id => lambda{|u, f| u.model.id },
54
+ :attachment => lambda{|u, f| u.mounted_as.to_s.downcase.pluralize },
55
+ :style => lambda{|u, f| u.paperclip_style },
56
+ :basename => lambda{|u, f| u.filename.gsub(/#{File.extname(u.filename)}$/, "") },
57
+ :extension => lambda{|u, d| File.extname(u.filename).gsub(/^\.+/, "")},
58
+ :class => lambda{|u, f| u.model.class.name.underscore.pluralize}
59
+ }
60
+
61
+ included do
62
+ attr_accessor :filename
63
+ class_attribute :mappings
64
+ self.mappings ||= DEFAULT_MAPPINGS.dup
65
+ end
49
66
 
50
67
  def store_path(for_file=filename)
51
68
  path = paperclip_path
69
+ self.filename = for_file
52
70
  path ||= File.join(*[store_dir, paperclip_style.to_s, for_file].compact)
53
- interpolate_paperclip_path(path, for_file)
71
+ interpolate_paperclip_path(path)
54
72
  end
55
73
 
56
74
  def store_dir
@@ -68,28 +86,18 @@ module CarrierWave
68
86
  version_name || paperclip_default_style
69
87
  end
70
88
 
71
- private
72
-
73
- def interpolate_paperclip_path(path, filename)
74
- mappings.inject(path) do |agg, pair|
75
- agg.gsub(":#{pair[0]}") { pair[1].call(self, filename).to_s }
89
+ module ClassMethods
90
+ def interpolate(sym, &block)
91
+ mappings[sym] = block
76
92
  end
77
93
  end
78
94
 
79
- def mappings
80
- [
81
- [:rails_root , lambda{|u, f| Rails.root }],
82
- [:rails_env , lambda{|u, f| Rails.env }],
83
- [:class , lambda{|u, f| u.model.class.name.underscore.pluralize}],
84
- [:id_partition , lambda{|u, f| ("%09d" % u.model.id).scan(/\d{3}/).join("/")}],
85
- [:id , lambda{|u, f| u.model.id }],
86
- [:attachment , lambda{|u, f| u.mounted_as.to_s.downcase.pluralize }],
87
- [:style , lambda{|u, f| u.paperclip_style }],
88
- [:basename , lambda{|u, f| f.gsub(/#{File.extname(f)}$/, "") }],
89
- [:extension , lambda{|u, f| File.extname(f).gsub(/^\.+/, "")}]
90
- ]
95
+ private
96
+ def interpolate_paperclip_path(path)
97
+ mappings.each_pair.inject(path) do |agg, pair|
98
+ agg.gsub(":#{pair[0]}") { pair[1].call(self, self.paperclip_style).to_s }
99
+ end
91
100
  end
92
-
93
101
  end # Paperclip
94
102
  end # Compatibility
95
103
  end # CarrierWave
@@ -0,0 +1,83 @@
1
+ require 'open-uri'
2
+ require 'ssrf_filter'
3
+ require 'addressable'
4
+ require 'carrierwave/downloader/remote_file'
5
+
6
+ module CarrierWave
7
+ module Downloader
8
+ class Base
9
+ attr_reader :uploader
10
+
11
+ def initialize(uploader)
12
+ @uploader = uploader
13
+ end
14
+
15
+ ##
16
+ # Downloads a file from given URL and returns a RemoteFile.
17
+ #
18
+ # === Parameters
19
+ #
20
+ # [url (String)] The URL where the remote file is stored
21
+ # [remote_headers (Hash)] Request headers
22
+ #
23
+ def download(url, remote_headers = {})
24
+ headers = remote_headers.
25
+ reverse_merge('User-Agent' => "CarrierWave/#{CarrierWave::VERSION}")
26
+ uri = process_uri(url.to_s)
27
+ begin
28
+ if skip_ssrf_protection?(uri)
29
+ response = OpenURI.open_uri(process_uri(url.to_s), headers)
30
+ else
31
+ request = nil
32
+ response = SsrfFilter.get(uri, headers: headers) do |req|
33
+ request = req
34
+ end
35
+ response.uri = request.uri
36
+ response.value
37
+ end
38
+ rescue StandardError => e
39
+ raise CarrierWave::DownloadError, "could not download file: #{e.message}"
40
+ end
41
+ CarrierWave::Downloader::RemoteFile.new(response)
42
+ end
43
+
44
+ ##
45
+ # Processes the given URL by parsing and escaping it. Public to allow overriding.
46
+ #
47
+ # === Parameters
48
+ #
49
+ # [url (String)] The URL where the remote file is stored
50
+ #
51
+ def process_uri(uri)
52
+ uri_parts = uri.split('?')
53
+ encoded_uri = Addressable::URI.parse(uri_parts.shift).normalize.to_s
54
+ encoded_uri << '?' << Addressable::URI.encode(uri_parts.join('?')).gsub('%5B', '[').gsub('%5D', ']') if uri_parts.any?
55
+ URI.parse(encoded_uri)
56
+ rescue URI::InvalidURIError, Addressable::URI::InvalidURIError
57
+ raise CarrierWave::DownloadError, "couldn't parse URL: #{uri}"
58
+ end
59
+
60
+ ##
61
+ # If this returns true, SSRF protection will be bypassed.
62
+ # You can override this if you want to allow accessing specific local URIs that are not SSRF exploitable.
63
+ #
64
+ # === Parameters
65
+ #
66
+ # [uri (URI)] The URI where the remote file is stored
67
+ #
68
+ # === Examples
69
+ #
70
+ # class CarrierWave::Downloader::CustomDownloader < CarrierWave::Downloader::Base
71
+ # def skip_ssrf_protection?(uri)
72
+ # uri.hostname == 'localhost' && uri.port == 80
73
+ # end
74
+ # end
75
+ #
76
+ # my_uploader.downloader = CarrierWave::Downloader::CustomDownloader
77
+ #
78
+ def skip_ssrf_protection?(uri)
79
+ false
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,65 @@
1
+ module CarrierWave
2
+ module Downloader
3
+ class RemoteFile
4
+ attr_reader :file, :uri
5
+
6
+ def initialize(file)
7
+ case file
8
+ when String
9
+ @file = StringIO.new(file)
10
+ when Net::HTTPResponse
11
+ @file = StringIO.new(file.body)
12
+ @content_type = file.content_type
13
+ @headers = file
14
+ @uri = file.uri
15
+ else
16
+ @file = file
17
+ @content_type = file.content_type
18
+ @headers = file.meta
19
+ @uri = file.base_uri
20
+ end
21
+ end
22
+
23
+ def content_type
24
+ @content_type || 'application/octet-stream'
25
+ end
26
+
27
+ def headers
28
+ @headers || {}
29
+ end
30
+
31
+ def original_filename
32
+ filename = filename_from_header || filename_from_uri
33
+ mime_type = MiniMime.lookup_by_content_type(content_type)
34
+ unless File.extname(filename).present? || mime_type.blank?
35
+ filename = "#{filename}.#{mime_type.extension}"
36
+ end
37
+ filename
38
+ end
39
+
40
+ def respond_to?(*args)
41
+ super || file.respond_to?(*args)
42
+ end
43
+
44
+ private
45
+
46
+ def filename_from_header
47
+ return nil unless headers['content-disposition']
48
+
49
+ match = headers['content-disposition'].match(/filename=(?:"([^"]+)"|([^";]+))/)
50
+ return nil unless match
51
+
52
+ match[1].presence || match[2].presence
53
+ end
54
+
55
+ def filename_from_uri
56
+ CGI.unescape(File.basename(uri.path))
57
+ end
58
+
59
+ def method_missing(*args, &block)
60
+ file.send(*args, &block)
61
+ end
62
+ end
63
+ end
64
+ end
65
+
@@ -4,4 +4,5 @@ module CarrierWave
4
4
  class InvalidParameter < UploadError; end
5
5
  class ProcessingError < UploadError; end
6
6
  class DownloadError < UploadError; end
7
+ class UnknownStorageError < StandardError; end
7
8
  end
@@ -4,8 +4,11 @@ en:
4
4
  carrierwave_processing_error: failed to be processed
5
5
  carrierwave_integrity_error: is not of an allowed file type
6
6
  carrierwave_download_error: could not be downloaded
7
- extension_white_list_error: "You are not allowed to upload %{extension} files, allowed types: %{allowed_types}"
8
- extension_black_list_error: "You are not allowed to upload %{extension} files, prohibited types: %{prohibited_types}"
9
- rmagick_processing_error: "Failed to manipulate with rmagick, maybe it is not an image? Original Error: %{e}"
10
- mime_types_processing_error: "Failed to process file with MIME::Types, maybe not valid content-type? Original Error: %{e}"
7
+ extension_whitelist_error: "You are not allowed to upload %{extension} files, allowed types: %{allowed_types}"
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, allowed types: %{allowed_types}"
10
+ content_type_blacklist_error: "You are not allowed to upload %{content_type} files"
11
+ rmagick_processing_error: "Failed to manipulate with rmagick, maybe it is not an image?"
11
12
  mini_magick_processing_error: "Failed to manipulate with MiniMagick, maybe it is not an image? Original Error: %{e}"
13
+ min_size_error: "File size should be greater than %{min_size}"
14
+ max_size_error: "File size should be less than %{max_size}"