carrierwave 0.11.2 → 3.0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +452 -178
  3. data/lib/carrierwave/compatibility/paperclip.rb +4 -4
  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 +217 -182
  9. data/lib/carrierwave/mounter.rb +255 -0
  10. data/lib/carrierwave/orm/activerecord.rb +29 -35
  11. data/lib/carrierwave/processing/mini_magick.rb +140 -84
  12. data/lib/carrierwave/processing/rmagick.rb +72 -21
  13. data/lib/carrierwave/processing/vips.rb +284 -0
  14. data/lib/carrierwave/processing.rb +1 -1
  15. data/lib/carrierwave/sanitized_file.rb +83 -84
  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 -57
  19. data/lib/carrierwave/storage.rb +1 -9
  20. data/lib/carrierwave/test/matchers.rb +88 -19
  21. data/lib/carrierwave/uploader/cache.rb +75 -45
  22. data/lib/carrierwave/uploader/callbacks.rb +1 -3
  23. data/lib/carrierwave/uploader/configuration.rb +80 -16
  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 +4 -74
  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 +48 -13
  34. data/lib/carrierwave/uploader/proxy.rb +20 -9
  35. data/lib/carrierwave/uploader/remove.rb +0 -2
  36. data/lib/carrierwave/uploader/serialization.rb +2 -4
  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 +171 -123
  40. data/lib/carrierwave/uploader.rb +12 -10
  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 +1 -3
  44. data/lib/carrierwave/validations/active_model.rb +7 -11
  45. data/lib/carrierwave/version.rb +1 -1
  46. data/lib/carrierwave.rb +39 -21
  47. data/lib/generators/templates/{uploader.rb → uploader.rb.erb} +6 -10
  48. data/lib/generators/uploader_generator.rb +3 -3
  49. metadata +135 -83
  50. data/lib/carrierwave/locale/cs.yml +0 -11
  51. data/lib/carrierwave/locale/de.yml +0 -11
  52. data/lib/carrierwave/locale/el.yml +0 -11
  53. data/lib/carrierwave/locale/es.yml +0 -11
  54. data/lib/carrierwave/locale/fr.yml +0 -11
  55. data/lib/carrierwave/locale/ja.yml +0 -11
  56. data/lib/carrierwave/locale/nb.yml +0 -11
  57. data/lib/carrierwave/locale/nl.yml +0 -11
  58. data/lib/carrierwave/locale/pl.yml +0 -11
  59. data/lib/carrierwave/locale/pt-BR.yml +0 -11
  60. data/lib/carrierwave/locale/pt-PT.yml +0 -11
  61. data/lib/carrierwave/locale/ru.yml +0 -11
  62. data/lib/carrierwave/locale/sk.yml +0 -11
  63. data/lib/carrierwave/locale/tr.yml +0 -11
  64. data/lib/carrierwave/processing/mime_types.rb +0 -74
  65. data/lib/carrierwave/uploader/content_type_blacklist.rb +0 -48
  66. data/lib/carrierwave/uploader/content_type_whitelist.rb +0 -48
  67. data/lib/carrierwave/uploader/extension_blacklist.rb +0 -47
  68. data/lib/carrierwave/uploader/extension_whitelist.rb +0 -49
  69. data/lib/carrierwave/utilities/deprecation.rb +0 -18
@@ -1,5 +1,3 @@
1
- # encoding: utf-8
2
-
3
1
  module CarrierWave
4
2
  module Compatibility
5
3
 
@@ -58,10 +56,11 @@ module CarrierWave
58
56
  :basename => lambda{|u, f| u.filename.gsub(/#{File.extname(u.filename)}$/, "") },
59
57
  :extension => lambda{|u, d| File.extname(u.filename).gsub(/^\.+/, "")},
60
58
  :class => lambda{|u, f| u.model.class.name.underscore.pluralize}
61
- }
59
+ }.freeze
62
60
 
63
61
  included do
64
62
  attr_accessor :filename
63
+
65
64
  class_attribute :mappings
66
65
  self.mappings ||= DEFAULT_MAPPINGS.dup
67
66
  end
@@ -94,7 +93,8 @@ module CarrierWave
94
93
  end
95
94
  end
96
95
 
97
- private
96
+ private
97
+
98
98
  def interpolate_paperclip_path(path)
99
99
  mappings.each_pair.inject(path) do |agg, pair|
100
100
  agg.gsub(":#{pair[0]}") { pair[1].call(self, self.paperclip_style).to_s }
@@ -0,0 +1,101 @@
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
+ include CarrierWave::Utilities::Uri
10
+
11
+ attr_reader :uploader
12
+
13
+ def initialize(uploader)
14
+ @uploader = uploader
15
+ end
16
+
17
+ ##
18
+ # Downloads a file from given URL and returns a RemoteFile.
19
+ #
20
+ # === Parameters
21
+ #
22
+ # [url (String)] The URL where the remote file is stored
23
+ # [remote_headers (Hash)] Request headers
24
+ #
25
+ def download(url, remote_headers = {})
26
+ @current_download_retry_count = 0
27
+ headers = remote_headers.
28
+ reverse_merge('User-Agent' => "CarrierWave/#{CarrierWave::VERSION}")
29
+ uri = process_uri(url.to_s)
30
+ begin
31
+ if skip_ssrf_protection?(uri)
32
+ response = OpenURI.open_uri(process_uri(url.to_s), headers)
33
+ else
34
+ request = nil
35
+ if ::SsrfFilter::VERSION.to_f < 1.1
36
+ response = SsrfFilter.get(uri, headers: headers) do |req|
37
+ request = req
38
+ end
39
+ else
40
+ response = SsrfFilter.get(uri, headers: headers, request_proc: ->(req) { request = req }) do |res|
41
+ res.body # ensure to read body
42
+ end
43
+ end
44
+ response.uri = request.uri
45
+ response.value
46
+ end
47
+ rescue StandardError => e
48
+ if @current_download_retry_count < @uploader.download_retry_count
49
+ @current_download_retry_count += 1
50
+ sleep @uploader.download_retry_wait_time
51
+ retry
52
+ else
53
+ raise CarrierWave::DownloadError, "could not download file: #{e.message}"
54
+ end
55
+ end
56
+ CarrierWave::Downloader::RemoteFile.new(response)
57
+ end
58
+
59
+ ##
60
+ # Processes the given URL by parsing it, and escaping if necessary. Public to allow overriding.
61
+ #
62
+ # === Parameters
63
+ #
64
+ # [url (String)] The URL where the remote file is stored
65
+ #
66
+ def process_uri(source)
67
+ uri = Addressable::URI.parse(source)
68
+ uri.host = uri.normalized_host
69
+ # Perform decode first, as the path is likely to be already encoded
70
+ uri.path = encode_path(decode_uri(uri.path)) if uri.path =~ CarrierWave::Utilities::Uri::PATH_UNSAFE
71
+ uri.query = encode_non_ascii(uri.query) if uri.query
72
+ uri.fragment = encode_non_ascii(uri.fragment) if uri.fragment
73
+ URI.parse(uri.to_s)
74
+ rescue URI::InvalidURIError, Addressable::URI::InvalidURIError
75
+ raise CarrierWave::DownloadError, "couldn't parse URL: #{source}"
76
+ end
77
+
78
+ ##
79
+ # If this returns true, SSRF protection will be bypassed.
80
+ # You can override this if you want to allow accessing specific local URIs that are not SSRF exploitable.
81
+ #
82
+ # === Parameters
83
+ #
84
+ # [uri (URI)] The URI where the remote file is stored
85
+ #
86
+ # === Examples
87
+ #
88
+ # class CarrierWave::Downloader::CustomDownloader < CarrierWave::Downloader::Base
89
+ # def skip_ssrf_protection?(uri)
90
+ # uri.hostname == 'localhost' && uri.port == 80
91
+ # end
92
+ # end
93
+ #
94
+ # my_uploader.downloader = CarrierWave::Downloader::CustomDownloader
95
+ #
96
+ def skip_ssrf_protection?(uri)
97
+ false
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,68 @@
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
+ body = file.body
12
+ raise CarrierWave::DownloadError, 'could not download file: No Content' if body.nil?
13
+
14
+ @file = StringIO.new(body)
15
+ @content_type = file.content_type
16
+ @headers = file
17
+ @uri = file.uri
18
+ else
19
+ @file = file
20
+ @content_type = file.content_type
21
+ @headers = file.meta
22
+ @uri = file.base_uri
23
+ end
24
+ end
25
+
26
+ def content_type
27
+ @content_type || 'application/octet-stream'
28
+ end
29
+
30
+ def headers
31
+ @headers || {}
32
+ end
33
+
34
+ def original_filename
35
+ filename = filename_from_header || filename_from_uri
36
+ extensions = Marcel::Magic.new(content_type).extensions
37
+ unless File.extname(filename).present? || extensions.blank?
38
+ extension = extensions.first
39
+ filename = "#{filename}.#{extension}"
40
+ end
41
+ filename
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
+
63
+ def respond_to_missing?(*args)
64
+ super || file.respond_to?(*args)
65
+ end
66
+ end
67
+ end
68
+ end
@@ -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,14 @@ 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}"
11
- mini_magick_processing_error: "Failed to manipulate with MiniMagick, maybe it is not an image? Original Error: %{e}"
7
+ extension_allowlist_error: "You are not allowed to upload %{extension} files, allowed types: %{allowed_types}"
8
+ extension_denylist_error: "You are not allowed to upload %{extension} files, prohibited types: %{prohibited_types}"
9
+ content_type_allowlist_error: "You are not allowed to upload %{content_type} files, allowed types: %{allowed_types}"
10
+ content_type_denylist_error: "You are not allowed to upload %{content_type} files"
11
+ processing_error: "Failed to manipulate, maybe it is not an image?"
12
+ min_size_error: "File size should be greater than %{min_size}"
13
+ max_size_error: "File size should be less than %{max_size}"
14
+ min_width_error: "Image width should be greater than %{min_width}px"
15
+ max_width_error: "Image width should be less than %{max_width}px"
16
+ min_height_error: "Image height should be greater than %{min_height}px"
17
+ max_height_error: "Image height should be less than %{max_height}px"