carrierwave 2.1.1 → 2.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.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 84145959d912145a2915ab7adb9ccbd6bf7a971ab00cef83fb7f5092c349c9c5
4
- data.tar.gz: 9ba122388fb8ff36563001ea9144e4a1d523b7be78433fed2a971a82588de5c8
3
+ metadata.gz: a6e511db9d3eebc43bd42613884cf42ba2ad5f236a438a609cccc67c6ce3d192
4
+ data.tar.gz: 20cef424394b5a40d27e73e8677161870c6d35f60734fd05cf2d0666f461b834
5
5
  SHA512:
6
- metadata.gz: 70f718887e9f4223405d8f273cafaf429395725eead688918d454499a50063fdc748cc519440d2010f783cfa1ec3ba19f54b5e07dc644d195cbe6d59f1c5b6b2
7
- data.tar.gz: 50907c92735e096c691a1ee7d440a2b83de736de3016b78c11796d0c558c283774236e5acf18abb552212816a38905986a6ec3ad0d956736f88c79ae99cd9aa6
6
+ metadata.gz: 28aeace46926db2716ac4600a67cb3a318c553f8f04f533fcf19afaddbafc46489bc3df5d523bc878f5b77164d4110c69ddfe346944caeb46b0dd83df39d7ac9
7
+ data.tar.gz: dc271f6fdfd5a515295185265a53b0b894ecef7e1d72bdcaa062357dacd5c7e9bca54a818ffcd344a95b341628451f5b6e579b62587845148075f9db9de949f7
data/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  This gem provides a simple and extremely flexible way to upload files from Ruby applications.
4
4
  It works well with Rack based web applications, such as Ruby on Rails.
5
5
 
6
- [![Build Status](https://travis-ci.org/carrierwaveuploader/carrierwave.svg?branch=master)](http://travis-ci.org/carrierwaveuploader/carrierwave)
6
+ [![Build Status](https://github.com/carrierwaveuploader/carrierwave/workflows/Test/badge.svg)](https://github.com/carrierwaveuploader/carrierwave/actions)
7
7
  [![Code Climate](https://codeclimate.com/github/carrierwaveuploader/carrierwave.svg)](https://codeclimate.com/github/carrierwaveuploader/carrierwave)
8
8
  [![SemVer](https://api.dependabot.com/badges/compatibility_score?dependency-name=carrierwave&package-manager=bundler&version-scheme=semver)](https://dependabot.com/compatibility-score.html?dependency-name=carrierwave&package-manager=bundler&version-scheme=semver)
9
9
 
@@ -94,7 +94,7 @@ a migration:
94
94
  Open your model file and mount the uploader:
95
95
 
96
96
  ```ruby
97
- class User < ActiveRecord::Base
97
+ class User < ApplicationRecord
98
98
  mount_uploader :avatar, AvatarUploader
99
99
  end
100
100
  ```
@@ -157,7 +157,7 @@ Open your model file and mount the uploader:
157
157
 
158
158
 
159
159
  ```ruby
160
- class User < ActiveRecord::Base
160
+ class User < ApplicationRecord
161
161
  mount_uploaders :avatars, AvatarUploader
162
162
  serialize :avatars, JSON # If you use SQLite, add this line.
163
163
  end
@@ -230,7 +230,7 @@ end
230
230
  ## Securing uploads
231
231
 
232
232
  Certain files might be dangerous if uploaded to the wrong location, such as PHP
233
- files or other script files. CarrierWave allows you to specify a whitelist of
233
+ files or other script files. CarrierWave allows you to specify an allowlist of
234
234
  allowed extensions or content types.
235
235
 
236
236
  If you're mounting the uploader, uploading a file with the wrong extension will
@@ -238,7 +238,7 @@ make the record invalid instead. Otherwise, an error is raised.
238
238
 
239
239
  ```ruby
240
240
  class MyUploader < CarrierWave::Uploader::Base
241
- def extension_whitelist
241
+ def extension_allowlist
242
242
  %w(jpg jpeg gif png)
243
243
  end
244
244
  end
@@ -249,45 +249,45 @@ Let's say we need an uploader that accepts only images. This can be done like th
249
249
 
250
250
  ```ruby
251
251
  class MyUploader < CarrierWave::Uploader::Base
252
- def content_type_whitelist
252
+ def content_type_allowlist
253
253
  /image\//
254
254
  end
255
255
  end
256
256
  ```
257
257
 
258
- You can use a blacklist to reject content types.
258
+ You can use a denylist to reject content types.
259
259
  Let's say we need an uploader that reject JSON files. This can be done like this
260
260
 
261
261
  ```ruby
262
262
  class NoJsonUploader < CarrierWave::Uploader::Base
263
- def content_type_blacklist
263
+ def content_type_denylist
264
264
  ['application/text', 'application/json']
265
265
  end
266
266
  end
267
267
  ```
268
268
 
269
269
  ### CVE-2016-3714 (ImageTragick)
270
- This version of CarrierWave has the ability to mitigate CVE-2016-3714. However, you **MUST** set a content_type_whitelist in your uploaders for this protection to be effective, and you **MUST** either disable ImageMagick's default SVG delegate or use the RSVG delegate for SVG processing.
270
+ This version of CarrierWave has the ability to mitigate CVE-2016-3714. However, you **MUST** set a content_type_allowlist in your uploaders for this protection to be effective, and you **MUST** either disable ImageMagick's default SVG delegate or use the RSVG delegate for SVG processing.
271
271
 
272
272
 
273
- A valid whitelist that will restrict your uploader to images only, and mitigate the CVE is:
273
+ A valid allowlist that will restrict your uploader to images only, and mitigate the CVE is:
274
274
 
275
275
  ```ruby
276
276
  class MyUploader < CarrierWave::Uploader::Base
277
- def content_type_whitelist
277
+ def content_type_allowlist
278
278
  [/image\//]
279
279
  end
280
280
  end
281
281
  ```
282
282
 
283
- **WARNING**: A `content_type_whitelist` is the only form of whitelist or blacklist supported by CarrierWave that can effectively mitigate against CVE-2016-3714. Use of `extension_whitelist` will not inspect the file headers, and thus still leaves your application open to the vulnerability.
283
+ **WARNING**: A `content_type_allowlist` is the only form of allowlist or denylist supported by CarrierWave that can effectively mitigate against CVE-2016-3714. Use of `extension_allowlist` will not inspect the file headers, and thus still leaves your application open to the vulnerability.
284
284
 
285
285
  ### Filenames and unicode chars
286
286
 
287
287
  Another security issue you should care for is the file names (see
288
288
  [Ruby On Rails Security Guide](http://guides.rubyonrails.org/security.html#file-uploads)).
289
289
  By default, CarrierWave provides only English letters, arabic numerals and some symbols as
290
- white-listed characters in the file name. If you want to support local scripts (Cyrillic letters, letters with diacritics and so on), you
290
+ allowlisted characters in the file name. If you want to support local scripts (Cyrillic letters, letters with diacritics and so on), you
291
291
  have to override `sanitize_regexp` method. It should return regular expression which would match
292
292
  all *non*-allowed symbols.
293
293
 
@@ -717,6 +717,9 @@ CarrierWave.configure do |config|
717
717
  config.fog_directory = 'name_of_bucket' # required
718
718
  config.fog_public = false # optional, defaults to true
719
719
  config.fog_attributes = { cache_control: "public, max-age=#{365.days.to_i}" } # optional, defaults to {}
720
+ # For an application which utilizes multiple servers but does not need caches persisted across requests,
721
+ # uncomment the line :file instead of the default :storage. Otherwise, it will use AWS as the temp cache store.
722
+ # config.cache_storage = :file
720
723
  end
721
724
  ```
722
725
 
@@ -797,30 +800,43 @@ end
797
800
  That's it! You can still use the `CarrierWave::Uploader#url` method to return
798
801
  the url to the file on Rackspace Cloud Files.
799
802
 
800
- ## Using Google Storage for Developers
803
+ ## Using Google Cloud Storage
801
804
 
802
- [Fog](http://github.com/fog/fog-google) is used to support Google Storage for Developers. Ensure you have it in your Gemfile:
805
+ [Fog](http://github.com/fog/fog-google) is used to support Google Cloud Storage. Ensure you have it in your Gemfile:
803
806
 
804
807
  ```ruby
805
808
  gem "fog-google"
806
- gem "google-api-client", "> 0.8.5", "< 0.9"
807
- gem "mime-types"
808
809
  ```
809
810
 
810
- You'll need to configure a directory (also known as a bucket), access key id and secret access key in the initializer.
811
+ You'll need to configure a directory (also known as a bucket) and the credentials in the initializer.
811
812
  For the sake of performance it is assumed that the directory already exists, so please create it if need be.
812
813
 
813
814
  Please read the [fog-google README](https://github.com/fog/fog-google/blob/master/README.md) on how to get credentials.
814
815
 
816
+ For Google Storage JSON API (recommended):
817
+ ```ruby
818
+ CarrierWave.configure do |config|
819
+ config.fog_provider = 'fog/google'
820
+ config.fog_credentials = {
821
+ provider: 'Google',
822
+ google_project: 'my-project',
823
+ google_json_key_string: 'xxxxxx'
824
+ # or use google_json_key_location if using an actual file
825
+ }
826
+ config.fog_directory = 'google_cloud_storage_bucket_name'
827
+ end
828
+ ```
815
829
 
830
+ For Google Storage XML API:
816
831
  ```ruby
817
832
  CarrierWave.configure do |config|
818
- config.fog_credentials = {
819
- provider: 'Google',
820
- google_storage_access_key_id: 'xxxxxx',
821
- google_storage_secret_access_key: 'yyyyyy'
822
- }
823
- config.fog_directory = 'name_of_directory'
833
+ config.fog_provider = 'fog/google'
834
+ config.fog_credentials = {
835
+ provider: 'Google',
836
+ google_storage_access_key_id: 'xxxxxx',
837
+ google_storage_secret_access_key: 'yyyyyy'
838
+ }
839
+ config.fog_directory = 'google_cloud_storage_bucket_name'
824
840
  end
825
841
  ```
826
842
 
@@ -964,10 +980,10 @@ errors:
964
980
  carrierwave_processing_error: failed to be processed
965
981
  carrierwave_integrity_error: is not of an allowed file type
966
982
  carrierwave_download_error: could not be downloaded
967
- extension_whitelist_error: "You are not allowed to upload %{extension} files, allowed types: %{allowed_types}"
968
- extension_blacklist_error: "You are not allowed to upload %{extension} files, prohibited types: %{prohibited_types}"
969
- content_type_whitelist_error: "You are not allowed to upload %{content_type} files, allowed types: %{allowed_types}"
970
- content_type_blacklist_error: "You are not allowed to upload %{content_type} files"
983
+ extension_allowlist_error: "You are not allowed to upload %{extension} files, allowed types: %{allowed_types}"
984
+ extension_denylist_error: "You are not allowed to upload %{extension} files, prohibited types: %{prohibited_types}"
985
+ content_type_allowlist_error: "You are not allowed to upload %{content_type} files, allowed types: %{allowed_types}"
986
+ content_type_denylist_error: "You are not allowed to upload %{content_type} files"
971
987
  rmagick_processing_error: "Failed to manipulate with rmagick, maybe it is not an image?"
972
988
  mini_magick_processing_error: "Failed to manipulate with MiniMagick, maybe it is not an image? Original Error: %{e}"
973
989
  min_size_error: "File size should be greater than %{min_size}"
@@ -1015,12 +1031,12 @@ end
1015
1031
  Will add these callbacks:
1016
1032
 
1017
1033
  ```ruby
1018
- after_save :store_avatar!
1019
1034
  before_save :write_avatar_identifier
1035
+ after_save :store_previous_changes_for_avatar
1020
1036
  after_commit :remove_avatar!, on: :destroy
1021
1037
  after_commit :mark_remove_avatar_false, on: :update
1022
- after_save :store_previous_changes_for_avatar
1023
1038
  after_commit :remove_previously_stored_avatar, on: :update
1039
+ after_commit :store_avatar!, on: [:create, :update]
1024
1040
  ```
1025
1041
 
1026
1042
  If you want to skip any of these callbacks (eg. you want to keep the existing
@@ -42,7 +42,7 @@ module CarrierWave
42
42
  end
43
43
 
44
44
  ##
45
- # Processes the given URL by parsing and escaping it. Public to allow overriding.
45
+ # Processes the given URL by parsing it, and escaping if necessary. Public to allow overriding.
46
46
  #
47
47
  # === Parameters
48
48
  #
@@ -51,8 +51,12 @@ module CarrierWave
51
51
  def process_uri(uri)
52
52
  uri_parts = uri.split('?')
53
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)
54
+ query = uri_parts.any? ? "?#{uri_parts.join('?')}" : ''
55
+ begin
56
+ URI.parse("#{encoded_uri}#{query}")
57
+ rescue URI::InvalidURIError
58
+ URI.parse("#{encoded_uri}#{URI::DEFAULT_PARSER.escape(query)}")
59
+ end
56
60
  rescue URI::InvalidURIError, Addressable::URI::InvalidURIError
57
61
  raise CarrierWave::DownloadError, "couldn't parse URL: #{uri}"
58
62
  end
@@ -4,11 +4,12 @@ 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_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"
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
11
  rmagick_processing_error: "Failed to manipulate with rmagick, maybe it is not an image?"
12
12
  mini_magick_processing_error: "Failed to manipulate with MiniMagick, maybe it is not an image? Original Error: %{e}"
13
+ vips_processing_error: "Failed to manipulate with vips, maybe it is not an image? Original Error: %{e}"
13
14
  min_size_error: "File size should be greater than %{min_size}"
14
15
  max_size_error: "File size should be less than %{max_size}"
@@ -1,2 +1,3 @@
1
1
  require "carrierwave/processing/rmagick"
2
2
  require "carrierwave/processing/mini_magick"
3
+ require "carrierwave/processing/vips"
@@ -228,7 +228,7 @@ module CarrierWave
228
228
  height = dimension_from height
229
229
  manipulate! do |img|
230
230
  img.resize_to_fit!(width, height)
231
- new_img = ::Magick::Image.new(width, height) { self.background_color = background == :transparent ? 'rgba(255,255,255,0)' : background.to_s }
231
+ new_img = ::Magick::Image.new(width, height) { |img| img.background_color = background == :transparent ? 'rgba(255,255,255,0)' : background.to_s }
232
232
  if background == :transparent
233
233
  filled = new_img.matte_floodfill(1, 1)
234
234
  else
@@ -0,0 +1,284 @@
1
+ module CarrierWave
2
+
3
+ ##
4
+ # This module simplifies manipulation with vips by providing a set
5
+ # of convenient helper methods. If you want to use them, you'll need to
6
+ # require this file:
7
+ #
8
+ # require 'carrierwave/processing/vips'
9
+ #
10
+ # And then include it in your uploader:
11
+ #
12
+ # class MyUploader < CarrierWave::Uploader::Base
13
+ # include CarrierWave::Vips
14
+ # end
15
+ #
16
+ # You can now use the provided helpers:
17
+ #
18
+ # class MyUploader < CarrierWave::Uploader::Base
19
+ # include CarrierWave::Vips
20
+ #
21
+ # process :resize_to_fit => [200, 200]
22
+ # end
23
+ #
24
+ # Or create your own helpers with the powerful vips! method, which
25
+ # yields an ImageProcessing::Builder object. Check out the ImageProcessing
26
+ # docs at http://github.com/janko-m/image_processing and the list of all
27
+ # available Vips options at
28
+ # https://libvips.github.io/libvips/API/current/using-cli.html for more info.
29
+ #
30
+ # class MyUploader < CarrierWave::Uploader::Base
31
+ # include CarrierWave::Vips
32
+ #
33
+ # process :radial_blur => 10
34
+ #
35
+ # def radial_blur(amount)
36
+ # vips! do |builder|
37
+ # builder.radial_blur(amount)
38
+ # builder = yield(builder) if block_given?
39
+ # builder
40
+ # end
41
+ # end
42
+ # end
43
+ #
44
+ # === Note
45
+ #
46
+ # The ImageProcessing gem uses ruby-vips, a binding for the vips image
47
+ # library. You can find more information here:
48
+ #
49
+ # https://github.com/libvips/ruby-vips
50
+ #
51
+ #
52
+ module Vips
53
+ extend ActiveSupport::Concern
54
+
55
+ included do
56
+ require "image_processing/vips"
57
+ # We need to disable caching since we're editing images in place.
58
+ ::Vips.cache_set_max(0)
59
+ end
60
+
61
+ module ClassMethods
62
+ def convert(format)
63
+ process :convert => format
64
+ end
65
+
66
+ def resize_to_limit(width, height)
67
+ process :resize_to_limit => [width, height]
68
+ end
69
+
70
+ def resize_to_fit(width, height)
71
+ process :resize_to_fit => [width, height]
72
+ end
73
+
74
+ def resize_to_fill(width, height, gravity='centre')
75
+ process :resize_to_fill => [width, height, gravity]
76
+ end
77
+
78
+ def resize_and_pad(width, height, background=nil, gravity='centre', alpha=nil)
79
+ process :resize_and_pad => [width, height, background, gravity, alpha]
80
+ end
81
+ end
82
+
83
+ ##
84
+ # Changes the image encoding format to the given format
85
+ #
86
+ # See https://libvips.github.io/libvips/API/current/using-cli.html#using-command-line-conversion
87
+ #
88
+ # === Parameters
89
+ #
90
+ # [format (#to_s)] an abbreviation of the format
91
+ #
92
+ # === Yields
93
+ #
94
+ # [Vips::Image] additional manipulations to perform
95
+ #
96
+ # === Examples
97
+ #
98
+ # image.convert(:png)
99
+ #
100
+ def convert(format, page=nil)
101
+ vips! do |builder|
102
+ builder = builder.convert(format)
103
+ builder = builder.loader(page: page) if page
104
+ builder
105
+ end
106
+ end
107
+
108
+ ##
109
+ # Resize the image to fit within the specified dimensions while retaining
110
+ # the original aspect ratio. Will only resize the image if it is larger than the
111
+ # specified dimensions. The resulting image may be shorter or narrower than specified
112
+ # in the smaller dimension but will not be larger than the specified values.
113
+ #
114
+ # === Parameters
115
+ #
116
+ # [width (Integer)] the width to scale the image to
117
+ # [height (Integer)] the height to scale the image to
118
+ # [combine_options (Hash)] additional Vips options to apply before resizing
119
+ #
120
+ # === Yields
121
+ #
122
+ # [Vips::Image] additional manipulations to perform
123
+ #
124
+ def resize_to_limit(width, height, combine_options: {})
125
+ width, height = resolve_dimensions(width, height)
126
+
127
+ vips! do |builder|
128
+ builder.resize_to_limit(width, height)
129
+ .apply(combine_options)
130
+ end
131
+ end
132
+
133
+ ##
134
+ # Resize the image to fit within the specified dimensions while retaining
135
+ # the original aspect ratio. The image may be shorter or narrower than
136
+ # specified in the smaller dimension but will not be larger than the specified values.
137
+ #
138
+ # === Parameters
139
+ #
140
+ # [width (Integer)] the width to scale the image to
141
+ # [height (Integer)] the height to scale the image to
142
+ # [combine_options (Hash)] additional Vips options to apply before resizing
143
+ #
144
+ # === Yields
145
+ #
146
+ # [Vips::Image] additional manipulations to perform
147
+ #
148
+ def resize_to_fit(width, height, combine_options: {})
149
+ width, height = resolve_dimensions(width, height)
150
+
151
+ vips! do |builder|
152
+ builder.resize_to_fit(width, height)
153
+ .apply(combine_options)
154
+ end
155
+ end
156
+
157
+ ##
158
+ # Resize the image to fit within the specified dimensions while retaining
159
+ # the aspect ratio of the original image. If necessary, crop the image in the
160
+ # larger dimension.
161
+ #
162
+ # === Parameters
163
+ #
164
+ # [width (Integer)] the width to scale the image to
165
+ # [height (Integer)] the height to scale the image to
166
+ # [combine_options (Hash)] additional vips options to apply before resizing
167
+ #
168
+ # === Yields
169
+ #
170
+ # [Vips::Image] additional manipulations to perform
171
+ #
172
+ def resize_to_fill(width, height, _gravity = nil, combine_options: {})
173
+ width, height = resolve_dimensions(width, height)
174
+
175
+ vips! do |builder|
176
+ builder.resize_to_fill(width, height).apply(combine_options)
177
+ end
178
+ end
179
+
180
+ ##
181
+ # Resize the image to fit within the specified dimensions while retaining
182
+ # the original aspect ratio. If necessary, will pad the remaining area
183
+ # with the given color, which defaults to transparent (for gif and png,
184
+ # white for jpeg).
185
+ #
186
+ # See https://libvips.github.io/libvips/API/current/libvips-conversion.html#VipsCompassDirection
187
+ # for gravity options.
188
+ #
189
+ # === Parameters
190
+ #
191
+ # [width (Integer)] the width to scale the image to
192
+ # [height (Integer)] the height to scale the image to
193
+ # [background (List, nil)] the color of the background as a RGB, like [0, 255, 255], nil indicates transparent
194
+ # [gravity (String)] how to position the image
195
+ # [alpha (Boolean, nil)] pad the image with the alpha channel if supported
196
+ # [combine_options (Hash)] additional vips options to apply before resizing
197
+ #
198
+ # === Yields
199
+ #
200
+ # [Vips::Image] additional manipulations to perform
201
+ #
202
+ def resize_and_pad(width, height, background=nil, gravity='centre', alpha=nil, combine_options: {})
203
+ width, height = resolve_dimensions(width, height)
204
+
205
+ vips! do |builder|
206
+ builder.resize_and_pad(width, height, background: background, gravity: gravity, alpha: alpha)
207
+ .apply(combine_options)
208
+ end
209
+ end
210
+
211
+ ##
212
+ # Returns the width of the image in pixels.
213
+ #
214
+ # === Returns
215
+ #
216
+ # [Integer] the image's width in pixels
217
+ #
218
+ def width
219
+ vips_image.width
220
+ end
221
+
222
+ ##
223
+ # Returns the height of the image in pixels.
224
+ #
225
+ # === Returns
226
+ #
227
+ # [Integer] the image's height in pixels
228
+ #
229
+ def height
230
+ vips_image.height
231
+ end
232
+
233
+ # Process the image with vip, using the ImageProcessing gem. This
234
+ # method will build a "convert" vips command and execute it on the
235
+ # current image.
236
+ #
237
+ # === Gotcha
238
+ #
239
+ # This method assumes that the object responds to +current_path+.
240
+ # Any class that this module is mixed into must have a +current_path+ method.
241
+ # CarrierWave::Uploader does, so you won't need to worry about this in
242
+ # most cases.
243
+ #
244
+ # === Yields
245
+ #
246
+ # [ImageProcessing::Builder] use it to define processing to be performed
247
+ #
248
+ # === Raises
249
+ #
250
+ # [CarrierWave::ProcessingError] if processing failed.
251
+ def vips!
252
+ builder = ImageProcessing::Vips.source(current_path)
253
+ builder = yield(builder)
254
+
255
+ result = builder.call
256
+ result.close
257
+
258
+ FileUtils.mv result.path, current_path
259
+
260
+ if File.extname(result.path) != File.extname(current_path)
261
+ move_to = current_path.chomp(File.extname(current_path)) + File.extname(result.path)
262
+ file.content_type = ::MiniMime.lookup_by_filename(move_to).content_type
263
+ file.move_to(move_to, permissions, directory_permissions)
264
+ end
265
+ rescue ::Vips::Error => e
266
+ message = I18n.translate(:"errors.messages.vips_processing_error", :e => e)
267
+ raise CarrierWave::ProcessingError, message
268
+ end
269
+
270
+ private
271
+
272
+ def resolve_dimensions(*dimensions)
273
+ dimensions.map do |value|
274
+ next value unless value.instance_of?(Proc)
275
+ value.arity >= 1 ? value.call(self) : value.call
276
+ end
277
+ end
278
+
279
+ def vips_image
280
+ ::Vips::Image.new_from_buffer(read, "")
281
+ end
282
+
283
+ end # Vips
284
+ end # CarrierWave
@@ -2,6 +2,7 @@ require 'pathname'
2
2
  require 'active_support/core_ext/string/multibyte'
3
3
  require 'mini_mime'
4
4
  require 'mimemagic'
5
+ require 'mimemagic/overlay'
5
6
 
6
7
  module CarrierWave
7
8
 
@@ -181,9 +182,9 @@ module CarrierWave
181
182
  move!(new_path)
182
183
  chmod!(new_path, permissions)
183
184
  if keep_filename
184
- self.file = {:tempfile => new_path, :filename => original_filename, :content_type => content_type}
185
+ self.file = {:tempfile => new_path, :filename => original_filename, :content_type => @content_type}
185
186
  else
186
- self.file = {:tempfile => new_path, :content_type => content_type}
187
+ self.file = {:tempfile => new_path, :content_type => @content_type}
187
188
  end
188
189
  self
189
190
  end
@@ -330,9 +331,16 @@ module CarrierWave
330
331
 
331
332
  def mime_magic_content_type
332
333
  if path
333
- File.open(path) do |file|
334
- MimeMagic.by_magic(file).try(:type) || 'invalid/invalid'
334
+ type = File.open(path) do |file|
335
+ MimeMagic.by_magic(file).try(:type)
335
336
  end
337
+
338
+ if type.nil?
339
+ type = ::MiniMime.lookup_by_filename(path).try(:content_type)
340
+ type = 'invalid/invalid' unless type.nil? || type.start_with?('text/')
341
+ end
342
+
343
+ type
336
344
  end
337
345
  rescue Errno::ENOENT
338
346
  nil
@@ -200,7 +200,7 @@ module CarrierWave
200
200
  # avoid a get by using local references
201
201
  local_directory = connection.directories.new(:key => @uploader.fog_directory)
202
202
  local_file = local_directory.files.new(:key => path)
203
- expire_at = options[:expire_at] || ::Fog::Time.now + @uploader.fog_authenticated_url_expiration
203
+ expire_at = options[:expire_at] || ::Fog::Time.now.since(@uploader.fog_authenticated_url_expiration.to_i)
204
204
  case @uploader.fog_credentials[:provider]
205
205
  when 'AWS', 'Google'
206
206
  # Older versions of fog-google do not support options as a parameter
@@ -450,7 +450,7 @@ module CarrierWave
450
450
  # @return [CarrierWave::Storage::Fog::File] the location where the file will be stored.
451
451
  #
452
452
  def copy_to(new_path)
453
- connection.copy_object(@uploader.fog_directory, file.key, @uploader.fog_directory, new_path, acl_header)
453
+ connection.copy_object(@uploader.fog_directory, file.key, @uploader.fog_directory, new_path, copy_options)
454
454
  CarrierWave::Storage::Fog::File.new(@uploader, @base, new_path)
455
455
  end
456
456
 
@@ -494,9 +494,18 @@ module CarrierWave
494
494
  @file ||= directory.files.head(path)
495
495
  end
496
496
 
497
+ def copy_options
498
+ options = {}
499
+ options.merge!(acl_header) if acl_header.present?
500
+ options['Content-Type'] ||= content_type if content_type
501
+ options.merge(@uploader.fog_attributes)
502
+ end
503
+
497
504
  def acl_header
498
505
  if fog_provider == 'AWS'
499
506
  { 'x-amz-acl' => @uploader.fog_public ? 'public-read' : 'private' }
507
+ elsif fog_provider == "Google"
508
+ @uploader.fog_public ? { destination_predefined_acl: "publicRead" } : {}
500
509
  else
501
510
  {}
502
511
  end
@@ -76,7 +76,7 @@ module CarrierWave
76
76
  # [Bool] whether the current file is cached
77
77
  #
78
78
  def cached?
79
- @cache_id
79
+ !!@cache_id
80
80
  end
81
81
 
82
82
  ##
@@ -8,39 +8,48 @@ module CarrierWave
8
8
  end
9
9
 
10
10
  ##
11
- # Override this method in your uploader to provide a blacklist of files content types
11
+ # Override this method in your uploader to provide a denylist of files content types
12
12
  # which are not allowed to be uploaded.
13
13
  # Not only strings but Regexp are allowed as well.
14
14
  #
15
15
  # === Returns
16
16
  #
17
- # [NilClass, String, Regexp, Array[String, Regexp]] a blacklist of content types which are not allowed to be uploaded
17
+ # [NilClass, String, Regexp, Array[String, Regexp]] a denylist of content types which are not allowed to be uploaded
18
18
  #
19
19
  # === Examples
20
20
  #
21
- # def content_type_blacklist
21
+ # def content_type_denylist
22
22
  # %w(text/json application/json)
23
23
  # end
24
24
  #
25
25
  # Basically the same, but using a Regexp:
26
26
  #
27
- # def content_type_blacklist
27
+ # def content_type_denylist
28
28
  # [/(text|application)\/json/]
29
29
  # end
30
30
  #
31
- def content_type_blacklist; end
31
+ def content_type_denylist
32
+ if respond_to?(:content_type_blacklist)
33
+ ActiveSupport::Deprecation.warn "#content_type_blacklist is deprecated, use #content_type_denylist instead." unless instance_variable_defined?(:@content_type_blacklist_warned)
34
+ @content_type_blacklist_warned = true
35
+ content_type_blacklist
36
+ end
37
+ end
32
38
 
33
39
  private
34
40
 
35
41
  def check_content_type_blacklist!(new_file)
42
+ return unless content_type_denylist
43
+
36
44
  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)
45
+ if blacklisted_content_type?(content_type)
46
+ raise CarrierWave::IntegrityError, I18n.translate(:"errors.messages.content_type_blacklist_error",
47
+ content_type: content_type, default: :"errors.messages.content_type_denylist_error")
39
48
  end
40
49
  end
41
50
 
42
51
  def blacklisted_content_type?(content_type)
43
- Array(content_type_blacklist).any? { |item| content_type =~ /#{item}/ }
52
+ Array(content_type_denylist).any? { |item| content_type =~ /#{item}/ }
44
53
  end
45
54
 
46
55
  end # ContentTypeBlacklist
@@ -8,39 +8,51 @@ module CarrierWave
8
8
  end
9
9
 
10
10
  ##
11
- # Override this method in your uploader to provide a whitelist of files content types
11
+ # Override this method in your uploader to provide an allowlist of files content types
12
12
  # which are allowed to be uploaded.
13
13
  # Not only strings but Regexp are allowed as well.
14
14
  #
15
15
  # === Returns
16
16
  #
17
- # [NilClass, String, Regexp, Array[String, Regexp]] a whitelist of content types which are allowed to be uploaded
17
+ # [NilClass, String, Regexp, Array[String, Regexp]] an allowlist of content types which are allowed to be uploaded
18
18
  #
19
19
  # === Examples
20
20
  #
21
- # def content_type_whitelist
21
+ # def content_type_allowlist
22
22
  # %w(text/json application/json)
23
23
  # end
24
24
  #
25
25
  # Basically the same, but using a Regexp:
26
26
  #
27
- # def content_type_whitelist
27
+ # def content_type_allowlist
28
28
  # [/(text|application)\/json/]
29
29
  # end
30
30
  #
31
- def content_type_whitelist; end
31
+ def content_type_allowlist
32
+ if respond_to?(:content_type_whitelist)
33
+ ActiveSupport::Deprecation.warn "#content_type_whitelist is deprecated, use #content_type_allowlist instead." unless instance_variable_defined?(:@content_type_whitelist_warned)
34
+ @content_type_whitelist_warned = true
35
+ content_type_whitelist
36
+ end
37
+ end
32
38
 
33
39
  private
34
40
 
35
41
  def check_content_type_whitelist!(new_file)
42
+ return unless content_type_allowlist
43
+
36
44
  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, allowed_types: Array(content_type_whitelist).join(", "))
45
+ if !whitelisted_content_type?(content_type)
46
+ raise CarrierWave::IntegrityError, I18n.translate(:"errors.messages.content_type_whitelist_error", content_type: content_type,
47
+ allowed_types: Array(content_type_allowlist).join(", "), default: :"errors.messages.content_type_allowlist_error")
39
48
  end
40
49
  end
41
50
 
42
51
  def whitelisted_content_type?(content_type)
43
- Array(content_type_whitelist).any? { |item| content_type =~ /#{item}/ }
52
+ Array(content_type_allowlist).any? do |item|
53
+ item = Regexp.quote(item) if item.class != Regexp
54
+ content_type =~ /#{item}/
55
+ end
44
56
  end
45
57
 
46
58
  end # ContentTypeWhitelist
@@ -8,43 +8,51 @@ module CarrierWave
8
8
  end
9
9
 
10
10
  ##
11
- # Override this method in your uploader to provide a black list of extensions which
11
+ # Override this method in your uploader to provide a denylist of extensions which
12
12
  # are prohibited to be uploaded. Compares the file's extension case insensitive.
13
13
  # Furthermore, not only strings but Regexp are allowed as well.
14
14
  #
15
- # When using a Regexp in the black list, `\A` and `\z` are automatically added to
15
+ # When using a Regexp in the denylist, `\A` and `\z` are automatically added to
16
16
  # the Regexp expression, also case insensitive.
17
17
  #
18
18
  # === Returns
19
19
 
20
- # [NilClass, String, Regexp, Array[String, Regexp]] a black list of extensions which are prohibited to be uploaded
20
+ # [NilClass, String, Regexp, Array[String, Regexp]] a deny list of extensions which are prohibited to be uploaded
21
21
  #
22
22
  # === Examples
23
23
  #
24
- # def extension_blacklist
24
+ # def extension_denylist
25
25
  # %w(swf tiff)
26
26
  # end
27
27
  #
28
28
  # Basically the same, but using a Regexp:
29
29
  #
30
- # def extension_blacklist
30
+ # def extension_denylist
31
31
  # [/swf/, 'tiff']
32
32
  # end
33
33
  #
34
-
35
- def extension_blacklist; end
34
+ def extension_denylist
35
+ if respond_to?(:extension_blacklist)
36
+ ActiveSupport::Deprecation.warn "#extension_blacklist is deprecated, use #extension_denylist instead." unless instance_variable_defined?(:@extension_blacklist_warned)
37
+ @extension_blacklist_warned = true
38
+ extension_blacklist
39
+ end
40
+ end
36
41
 
37
42
  private
38
43
 
39
44
  def check_extension_blacklist!(new_file)
45
+ return unless extension_denylist
46
+
40
47
  extension = new_file.extension.to_s
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(", "))
48
+ if blacklisted_extension?(extension)
49
+ raise CarrierWave::IntegrityError, I18n.translate(:"errors.messages.extension_blacklist_error", extension: new_file.extension.inspect,
50
+ prohibited_types: Array(extension_denylist).join(", "), default: :"errors.messages.extension_denylist_error")
43
51
  end
44
52
  end
45
53
 
46
54
  def blacklisted_extension?(extension)
47
- Array(extension_blacklist).any? { |item| extension =~ /\A#{item}\z/i }
55
+ Array(extension_denylist).any? { |item| extension =~ /\A#{item}\z/i }
48
56
  end
49
57
  end
50
58
  end
@@ -8,45 +8,54 @@ module CarrierWave
8
8
  end
9
9
 
10
10
  ##
11
- # Override this method in your uploader to provide a white list of extensions which
11
+ # Override this method in your uploader to provide an allowlist of extensions which
12
12
  # are allowed to be uploaded. Compares the file's extension case insensitive.
13
13
  # Furthermore, not only strings but Regexp are allowed as well.
14
14
  #
15
- # When using a Regexp in the white list, `\A` and `\z` are automatically added to
15
+ # When using a Regexp in the allowlist, `\A` and `\z` are automatically added to
16
16
  # the Regexp expression, also case insensitive.
17
17
  #
18
18
  # === Returns
19
19
  #
20
- # [NilClass, String, Regexp, Array[String, Regexp]] a white list of extensions which are allowed to be uploaded
20
+ # [NilClass, String, Regexp, Array[String, Regexp]] an allowlist of extensions which are allowed to be uploaded
21
21
  #
22
22
  # === Examples
23
23
  #
24
- # def extension_whitelist
24
+ # def extension_allowlist
25
25
  # %w(jpg jpeg gif png)
26
26
  # end
27
27
  #
28
28
  # Basically the same, but using a Regexp:
29
29
  #
30
- # def extension_whitelist
30
+ # def extension_allowlist
31
31
  # [/jpe?g/, 'gif', 'png']
32
32
  # end
33
33
  #
34
- def extension_whitelist; end
34
+ def extension_allowlist
35
+ if respond_to?(:extension_whitelist)
36
+ ActiveSupport::Deprecation.warn "#extension_whitelist is deprecated, use #extension_allowlist instead." unless instance_variable_defined?(:@extension_whitelist_warned)
37
+ @extension_whitelist_warned = true
38
+ extension_whitelist
39
+ end
40
+ end
35
41
 
36
42
  private
37
43
 
38
44
  def check_extension_whitelist!(new_file)
45
+ return unless extension_allowlist
46
+
39
47
  extension = new_file.extension.to_s
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(", "))
48
+ if !whitelisted_extension?(extension)
49
+ # Look for whitelist first, then fallback to allowlist
50
+ raise CarrierWave::IntegrityError, I18n.translate(:"errors.messages.extension_whitelist_error", extension: new_file.extension.inspect,
51
+ allowed_types: Array(extension_allowlist).join(", "), default: :"errors.messages.extension_allowlist_error")
42
52
  end
43
53
  end
44
54
 
45
55
  def whitelisted_extension?(extension)
46
56
  downcase_extension = extension.downcase
47
- Array(extension_whitelist).any? { |item| downcase_extension =~ /\A#{item}\z/i }
57
+ Array(extension_allowlist).any? { |item| downcase_extension =~ /\A#{item}\z/i }
48
58
  end
49
-
50
59
  end # ExtensionWhitelist
51
60
  end # Uploader
52
61
  end # CarrierWave
@@ -15,9 +15,12 @@ module CarrierWave
15
15
  # [String] the location where this file is accessible via a url
16
16
  #
17
17
  def url(options = {})
18
- if file.respond_to?(:url) && !(tmp_url = file.url).blank?
19
- file.method(:url).arity.zero? ? tmp_url : file.url(options)
20
- elsif file.respond_to?(:path)
18
+ if file.respond_to?(:url)
19
+ tmp_url = file.method(:url).arity.zero? ? file.url : file.url(options)
20
+ return tmp_url if tmp_url.present?
21
+ end
22
+
23
+ if file.respond_to?(:path)
21
24
  path = encode_path(file.path.sub(File.expand_path(root), ''))
22
25
 
23
26
  if host = asset_host
@@ -23,7 +23,7 @@ module CarrierWave
23
23
  prepend Module.new {
24
24
  def initialize(*)
25
25
  super
26
- @versions = nil
26
+ @versions, @versions_to_cache, @versions_to_store = nil
27
27
  end
28
28
  }
29
29
  end
@@ -1,3 +1,3 @@
1
1
  module CarrierWave
2
- VERSION = "2.1.1"
2
+ VERSION = "2.2.0"
3
3
  end
@@ -33,9 +33,9 @@ class <%= class_name %>Uploader < CarrierWave::Uploader::Base
33
33
  # process resize_to_fit: [50, 50]
34
34
  # end
35
35
 
36
- # Add a white list of extensions which are allowed to be uploaded.
36
+ # Add an allowlist of extensions which are allowed to be uploaded.
37
37
  # For images you might use something like this:
38
- # def extension_whitelist
38
+ # def extension_allowlist
39
39
  # %w(jpg jpeg gif png)
40
40
  # end
41
41
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: carrierwave
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.1
4
+ version: 2.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jonas Nicklas
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-02-08 00:00:00.000000000 Z
11
+ date: 2021-02-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -252,14 +252,14 @@ dependencies:
252
252
  name: rmagick
253
253
  requirement: !ruby/object:Gem::Requirement
254
254
  requirements:
255
- - - "~>"
255
+ - - ">="
256
256
  - !ruby/object:Gem::Version
257
257
  version: '2.16'
258
258
  type: :development
259
259
  prerelease: false
260
260
  version_requirements: !ruby/object:Gem::Requirement
261
261
  requirements:
262
- - - "~>"
262
+ - - ">="
263
263
  - !ruby/object:Gem::Version
264
264
  version: '2.16'
265
265
  - !ruby/object:Gem::Dependency
@@ -304,6 +304,20 @@ dependencies:
304
304
  - - ">="
305
305
  - !ruby/object:Gem::Version
306
306
  version: '0'
307
+ - !ruby/object:Gem::Dependency
308
+ name: pry-byebug
309
+ requirement: !ruby/object:Gem::Requirement
310
+ requirements:
311
+ - - ">="
312
+ - !ruby/object:Gem::Version
313
+ version: '0'
314
+ type: :development
315
+ prerelease: false
316
+ version_requirements: !ruby/object:Gem::Requirement
317
+ requirements:
318
+ - - ">="
319
+ - !ruby/object:Gem::Version
320
+ version: '0'
307
321
  description: Upload files in your Ruby applications, map them to a range of ORMs,
308
322
  store them on different backends.
309
323
  email:
@@ -326,6 +340,7 @@ files:
326
340
  - lib/carrierwave/processing.rb
327
341
  - lib/carrierwave/processing/mini_magick.rb
328
342
  - lib/carrierwave/processing/rmagick.rb
343
+ - lib/carrierwave/processing/vips.rb
329
344
  - lib/carrierwave/sanitized_file.rb
330
345
  - lib/carrierwave/storage.rb
331
346
  - lib/carrierwave/storage/abstract.rb