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.
- checksums.yaml +7 -0
- data/README.md +362 -116
- data/lib/carrierwave/compatibility/paperclip.rb +29 -21
- data/lib/carrierwave/downloader/base.rb +83 -0
- data/lib/carrierwave/downloader/remote_file.rb +65 -0
- data/lib/carrierwave/error.rb +1 -0
- data/lib/carrierwave/locale/en.yml +7 -4
- data/lib/carrierwave/mount.rb +238 -186
- data/lib/carrierwave/mounter.rb +188 -0
- data/lib/carrierwave/orm/activerecord.rb +60 -24
- data/lib/carrierwave/processing/mini_magick.rb +139 -78
- data/lib/carrierwave/processing/rmagick.rb +68 -23
- data/lib/carrierwave/processing.rb +0 -1
- data/lib/carrierwave/sanitized_file.rb +67 -27
- data/lib/carrierwave/storage/abstract.rb +15 -2
- data/lib/carrierwave/storage/file.rb +69 -2
- data/lib/carrierwave/storage/fog.rb +180 -41
- data/lib/carrierwave/storage.rb +1 -7
- data/lib/carrierwave/test/matchers.rb +77 -12
- data/lib/carrierwave/uploader/cache.rb +74 -38
- data/lib/carrierwave/uploader/callbacks.rb +0 -2
- data/lib/carrierwave/uploader/configuration.rb +72 -6
- data/lib/carrierwave/uploader/content_type_blacklist.rb +48 -0
- data/lib/carrierwave/uploader/content_type_whitelist.rb +48 -0
- data/lib/carrierwave/uploader/default_url.rb +3 -5
- data/lib/carrierwave/uploader/download.rb +5 -69
- data/lib/carrierwave/uploader/extension_blacklist.rb +14 -10
- data/lib/carrierwave/uploader/extension_whitelist.rb +13 -10
- data/lib/carrierwave/uploader/file_size.rb +43 -0
- data/lib/carrierwave/uploader/mountable.rb +13 -8
- data/lib/carrierwave/uploader/processing.rb +15 -17
- data/lib/carrierwave/uploader/proxy.rb +16 -7
- data/lib/carrierwave/uploader/remove.rb +0 -2
- data/lib/carrierwave/uploader/serialization.rb +3 -5
- data/lib/carrierwave/uploader/store.rb +17 -24
- data/lib/carrierwave/uploader/url.rb +3 -5
- data/lib/carrierwave/uploader/versions.rb +117 -86
- data/lib/carrierwave/uploader.rb +6 -2
- data/lib/carrierwave/utilities/uri.rb +5 -6
- data/lib/carrierwave/utilities.rb +1 -3
- data/lib/carrierwave/validations/active_model.rb +3 -7
- data/lib/carrierwave/version.rb +1 -1
- data/lib/carrierwave.rb +36 -3
- data/lib/generators/templates/uploader.rb +4 -8
- data/lib/generators/uploader_generator.rb +1 -1
- metadata +195 -94
- data/lib/carrierwave/locale/cs.yml +0 -11
- data/lib/carrierwave/locale/de.yml +0 -11
- data/lib/carrierwave/locale/nl.yml +0 -11
- data/lib/carrierwave/locale/sk.yml +0 -11
- 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
|
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
|
-
|
72
|
-
|
73
|
-
|
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
|
-
|
80
|
-
|
81
|
-
|
82
|
-
[
|
83
|
-
|
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
|
+
|
data/lib/carrierwave/error.rb
CHANGED
@@ -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
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
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}"
|