carrierwave 0.11.2 → 3.0.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +452 -178
- data/lib/carrierwave/compatibility/paperclip.rb +4 -4
- data/lib/carrierwave/downloader/base.rb +101 -0
- data/lib/carrierwave/downloader/remote_file.rb +68 -0
- data/lib/carrierwave/error.rb +1 -0
- data/lib/carrierwave/locale/en.yml +11 -5
- data/lib/carrierwave/mount.rb +217 -182
- data/lib/carrierwave/mounter.rb +255 -0
- data/lib/carrierwave/orm/activerecord.rb +29 -35
- data/lib/carrierwave/processing/mini_magick.rb +140 -84
- data/lib/carrierwave/processing/rmagick.rb +72 -21
- data/lib/carrierwave/processing/vips.rb +284 -0
- data/lib/carrierwave/processing.rb +1 -1
- data/lib/carrierwave/sanitized_file.rb +83 -84
- data/lib/carrierwave/storage/abstract.rb +16 -3
- data/lib/carrierwave/storage/file.rb +71 -3
- data/lib/carrierwave/storage/fog.rb +215 -57
- data/lib/carrierwave/storage.rb +1 -9
- data/lib/carrierwave/test/matchers.rb +88 -19
- data/lib/carrierwave/uploader/cache.rb +75 -45
- data/lib/carrierwave/uploader/callbacks.rb +1 -3
- data/lib/carrierwave/uploader/configuration.rb +80 -16
- data/lib/carrierwave/uploader/content_type_allowlist.rb +62 -0
- data/lib/carrierwave/uploader/content_type_denylist.rb +62 -0
- data/lib/carrierwave/uploader/default_url.rb +3 -5
- data/lib/carrierwave/uploader/dimension.rb +66 -0
- data/lib/carrierwave/uploader/download.rb +4 -74
- data/lib/carrierwave/uploader/extension_allowlist.rb +63 -0
- data/lib/carrierwave/uploader/extension_denylist.rb +64 -0
- data/lib/carrierwave/uploader/file_size.rb +43 -0
- data/lib/carrierwave/uploader/mountable.rb +13 -8
- data/lib/carrierwave/uploader/processing.rb +48 -13
- data/lib/carrierwave/uploader/proxy.rb +20 -9
- data/lib/carrierwave/uploader/remove.rb +0 -2
- data/lib/carrierwave/uploader/serialization.rb +2 -4
- data/lib/carrierwave/uploader/store.rb +59 -28
- data/lib/carrierwave/uploader/url.rb +8 -7
- data/lib/carrierwave/uploader/versions.rb +171 -123
- data/lib/carrierwave/uploader.rb +12 -10
- data/lib/carrierwave/utilities/file_name.rb +47 -0
- data/lib/carrierwave/utilities/uri.rb +14 -12
- data/lib/carrierwave/utilities.rb +1 -3
- data/lib/carrierwave/validations/active_model.rb +7 -11
- data/lib/carrierwave/version.rb +1 -1
- data/lib/carrierwave.rb +39 -21
- data/lib/generators/templates/{uploader.rb → uploader.rb.erb} +6 -10
- data/lib/generators/uploader_generator.rb +3 -3
- metadata +135 -83
- data/lib/carrierwave/locale/cs.yml +0 -11
- data/lib/carrierwave/locale/de.yml +0 -11
- data/lib/carrierwave/locale/el.yml +0 -11
- data/lib/carrierwave/locale/es.yml +0 -11
- data/lib/carrierwave/locale/fr.yml +0 -11
- data/lib/carrierwave/locale/ja.yml +0 -11
- data/lib/carrierwave/locale/nb.yml +0 -11
- data/lib/carrierwave/locale/nl.yml +0 -11
- data/lib/carrierwave/locale/pl.yml +0 -11
- data/lib/carrierwave/locale/pt-BR.yml +0 -11
- data/lib/carrierwave/locale/pt-PT.yml +0 -11
- data/lib/carrierwave/locale/ru.yml +0 -11
- data/lib/carrierwave/locale/sk.yml +0 -11
- data/lib/carrierwave/locale/tr.yml +0 -11
- data/lib/carrierwave/processing/mime_types.rb +0 -74
- data/lib/carrierwave/uploader/content_type_blacklist.rb +0 -48
- data/lib/carrierwave/uploader/content_type_whitelist.rb +0 -48
- data/lib/carrierwave/uploader/extension_blacklist.rb +0 -47
- data/lib/carrierwave/uploader/extension_whitelist.rb +0 -49
- 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
|
-
|
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
|
data/lib/carrierwave/error.rb
CHANGED
@@ -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
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
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"
|