paperclip 3.5.4 → 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of paperclip might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/Gemfile +1 -0
- data/LICENSE +1 -3
- data/NEWS +25 -21
- data/README.md +35 -1
- data/features/step_definitions/attachment_steps.rb +2 -0
- data/features/step_definitions/rails_steps.rb +1 -0
- data/lib/paperclip.rb +1 -0
- data/lib/paperclip/attachment.rb +25 -1
- data/lib/paperclip/callbacks.rb +1 -1
- data/lib/paperclip/content_type_detector.rb +1 -13
- data/lib/paperclip/errors.rb +5 -0
- data/lib/paperclip/has_attached_file.rb +5 -0
- data/lib/paperclip/io_adapters/abstract_adapter.rb +1 -1
- data/lib/paperclip/io_adapters/attachment_adapter.rb +4 -4
- data/lib/paperclip/io_adapters/data_uri_adapter.rb +4 -9
- data/lib/paperclip/io_adapters/stringio_adapter.rb +10 -8
- data/lib/paperclip/media_type_spoof_detector.rb +36 -0
- data/lib/paperclip/tempfile_factory.rb +5 -1
- data/lib/paperclip/validators.rb +6 -1
- data/lib/paperclip/validators/attachment_content_type_validator.rb +4 -0
- data/lib/paperclip/validators/attachment_file_name_validator.rb +80 -0
- data/lib/paperclip/validators/attachment_file_type_ignorance_validator.rb +29 -0
- data/lib/paperclip/validators/attachment_presence_validator.rb +4 -0
- data/lib/paperclip/validators/attachment_size_validator.rb +4 -0
- data/lib/paperclip/validators/media_type_spoof_detection_validator.rb +27 -0
- data/lib/paperclip/version.rb +1 -1
- data/test/attachment_definitions_test.rb +1 -0
- data/test/attachment_test.rb +40 -43
- data/test/content_type_detector_test.rb +0 -10
- data/test/fixtures/empty.html +1 -0
- data/test/has_attached_file_test.rb +3 -1
- data/test/helper.rb +11 -4
- data/test/io_adapters/abstract_adapter_test.rb +1 -0
- data/test/io_adapters/attachment_adapter_test.rb +1 -1
- data/test/io_adapters/data_uri_adapter_test.rb +2 -2
- data/test/io_adapters/file_adapter_test.rb +0 -11
- data/test/io_adapters/http_url_proxy_adapter_test.rb +2 -3
- data/test/io_adapters/stringio_adapter_test.rb +1 -1
- data/test/matchers/have_attached_file_matcher_test.rb +3 -2
- data/test/matchers/validate_attachment_content_type_matcher_test.rb +13 -12
- data/test/matchers/validate_attachment_presence_matcher_test.rb +8 -7
- data/test/matchers/validate_attachment_size_matcher_test.rb +12 -11
- data/test/media_type_spoof_detector_test.rb +28 -0
- data/test/meta_class_test.rb +2 -2
- data/test/schema_test.rb +6 -0
- data/test/storage/fog_test.rb +4 -4
- data/test/storage/s3_test.rb +32 -31
- data/test/tempfile_factory_test.rb +13 -1
- data/test/validators/attachment_file_name_validator_test.rb +162 -0
- data/test/validators/attachment_presence_validator_test.rb +1 -1
- data/test/validators/media_type_spoof_detection_validator_test.rb +12 -0
- data/test/validators_test.rb +43 -3
- metadata +14 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 748ce579f297e0d58f7ee6e72b2968341af560be
|
4
|
+
data.tar.gz: 47ed54affca1e4c7736eddcb33dfac09763d871d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1337da62c00c9b10e151b8a1efd10b611d92c0601c3471bab99b57acbdf7c532e9714ce271c1bc01dbbc499aa71938ba5865b15ff44f1f68d7c0e919e24d00b8
|
7
|
+
data.tar.gz: e8fe2a23b8bc5fbbfc9e5ead740a42a6ff7ccb93c9cc452e10cd443b510560ac826d6ef1d3a6dcbefe5ce13bf4b8b7799fd7a6f290c26b27874ac166c89d501d
|
data/Gemfile
CHANGED
data/LICENSE
CHANGED
@@ -3,7 +3,7 @@ LICENSE
|
|
3
3
|
|
4
4
|
The MIT License
|
5
5
|
|
6
|
-
Copyright (c) 2008-
|
6
|
+
Copyright (c) 2008-2014 Jon Yurek and thoughtbot, inc.
|
7
7
|
|
8
8
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
9
9
|
of this software and associated documentation files (the "Software"), to deal
|
@@ -22,5 +22,3 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
22
22
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
23
23
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
24
24
|
THE SOFTWARE.
|
25
|
-
|
26
|
-
|
data/NEWS
CHANGED
@@ -1,28 +1,32 @@
|
|
1
|
-
New in
|
1
|
+
New in 4.0.0:
|
2
2
|
|
3
|
-
|
3
|
+
* Security: Attachments are checked to make sure they're not pulling a fast one.
|
4
|
+
* Security: It is now *enforced* that every attachment has a file/mime validation.
|
5
|
+
* Bug Fix: Removed a call to IOAdapter#close that was causing issues.
|
6
|
+
* Improvement: Added bullets to the 3.5.3 list of changes. Very important.
|
7
|
+
* Improcement: Updated the copyright to 2014
|
4
8
|
|
5
9
|
New in 3.5.3:
|
6
10
|
|
7
|
-
Improvement: After three long, hard years... we know how to upgrade
|
8
|
-
Bug Fix: #expiring_url returns 'missing' urls if nothing is attached
|
9
|
-
Improvement: Lots of documentation fixes
|
10
|
-
Improvement: Lots of fixes for Ruby warnings
|
11
|
-
Improvement: Test the most appropriate Ruby/Rails comobinations on Travis
|
12
|
-
Improvement: Delegate more IO methods through IOAdapters
|
13
|
-
Improvement: Remove Rails 4 deprecations
|
14
|
-
Improvement: Both S3's and Fog's #expiring_url can take a Time or Int
|
15
|
-
Bug Fix: Both S3's and Fog's expiring_url respect style when missing the file
|
16
|
-
Bug Fix: Timefiles will have a reasonable-length name. They're all MD5 hashes now
|
17
|
-
Bug Fix: Don't delete files off S3 when reprocessing due to AWS inconsistencies
|
18
|
-
Bug Fix: "swallow_stream" isn't thread dafe. Use :swallow_stderr
|
19
|
-
Improvement: Regexps use \A and \Z instead of ^ and $
|
20
|
-
Improvement: :s3_credentials can take a lambda as an argument
|
21
|
-
Improvement: Search up the class heirarchy for attachments
|
22
|
-
Improvement: deep_merge options instead of regular merge
|
23
|
-
Bug Fix: Prevent file deletion on transaction rollback
|
24
|
-
Test Improvement: Ensure more files are properly closed during tests
|
25
|
-
Test Bug Fix: Return the gemfile's syntax to normal
|
11
|
+
* Improvement: After three long, hard years... we know how to upgrade
|
12
|
+
* Bug Fix: #expiring_url returns 'missing' urls if nothing is attached
|
13
|
+
* Improvement: Lots of documentation fixes
|
14
|
+
* Improvement: Lots of fixes for Ruby warnings
|
15
|
+
* Improvement: Test the most appropriate Ruby/Rails comobinations on Travis
|
16
|
+
* Improvement: Delegate more IO methods through IOAdapters
|
17
|
+
* Improvement: Remove Rails 4 deprecations
|
18
|
+
* Improvement: Both S3's and Fog's #expiring_url can take a Time or Int
|
19
|
+
* Bug Fix: Both S3's and Fog's expiring_url respect style when missing the file
|
20
|
+
* Bug Fix: Timefiles will have a reasonable-length name. They're all MD5 hashes now
|
21
|
+
* Bug Fix: Don't delete files off S3 when reprocessing due to AWS inconsistencies
|
22
|
+
* Bug Fix: "swallow_stream" isn't thread dafe. Use :swallow_stderr
|
23
|
+
* Improvement: Regexps use \A and \Z instead of ^ and $
|
24
|
+
* Improvement: :s3_credentials can take a lambda as an argument
|
25
|
+
* Improvement: Search up the class heirarchy for attachments
|
26
|
+
* Improvement: deep_merge options instead of regular merge
|
27
|
+
* Bug Fix: Prevent file deletion on transaction rollback
|
28
|
+
* Test Improvement: Ensure more files are properly closed during tests
|
29
|
+
* Test Bug Fix: Return the gemfile's syntax to normal
|
26
30
|
|
27
31
|
New in 3.5.2:
|
28
32
|
|
data/README.md
CHANGED
@@ -104,6 +104,7 @@ Quick Start
|
|
104
104
|
class User < ActiveRecord::Base
|
105
105
|
attr_accessible :avatar
|
106
106
|
has_attached_file :avatar, :styles => { :medium => "300x300>", :thumb => "100x100>" }, :default_url => "/images/:style/missing.png"
|
107
|
+
validates_attachment_content_type :avatar, :content_type => /\Aimage\/.*\Z/
|
107
108
|
end
|
108
109
|
```
|
109
110
|
|
@@ -112,6 +113,7 @@ end
|
|
112
113
|
```ruby
|
113
114
|
class User < ActiveRecord::Base
|
114
115
|
has_attached_file :avatar, :styles => { :medium => "300x300>", :thumb => "100x100>" }, :default_url => "/images/:style/missing.png"
|
116
|
+
validates_attachment_content_type :avatar, :content_type => /\Aimage\/.*\Z/
|
115
117
|
end
|
116
118
|
```
|
117
119
|
|
@@ -302,6 +304,38 @@ validates_attachment :avatar,
|
|
302
304
|
`Paperclip::ContentTypeDetector` will attempt to match a file's extension to an
|
303
305
|
inferred content_type, regardless of the actual contents of the file.
|
304
306
|
|
307
|
+
Security Validations
|
308
|
+
====================
|
309
|
+
|
310
|
+
NOTE: Starting at version 4.0.0, all attachments are *required* to include a
|
311
|
+
content_type validation, a file_name validation, or to explicitly state that
|
312
|
+
they're not going to have either. *Paperclip will raise an error* if you do not
|
313
|
+
do this.
|
314
|
+
|
315
|
+
```ruby
|
316
|
+
class ActiveRecord::Base
|
317
|
+
has_attached_file :avatar
|
318
|
+
# Validate content type
|
319
|
+
validates_attachment_content_type :avatar, :content_type => /\Aimage/
|
320
|
+
# Validate filename
|
321
|
+
validates_attachment_file_name :avatar, :matches => [/png\Z/, /jpe?g\Z/]
|
322
|
+
# Explicitly do not validate
|
323
|
+
do_not_validate_attachment_file_type :avatar
|
324
|
+
end
|
325
|
+
```
|
326
|
+
|
327
|
+
This keeps Paperclip secure-by-default, and will prevent people trying to mess
|
328
|
+
with your filesystem.
|
329
|
+
|
330
|
+
NOTE: Also starting at version 4.0.0, Paperclip has another validation that
|
331
|
+
cannot be turned off. This validation will prevent content type spoofing. That
|
332
|
+
is, uploading, say, a PHP document as part of the EXIF tags of a well-formed
|
333
|
+
JPEG. This check is limited to the media type (the first part of the MIME type,
|
334
|
+
so, 'text' in 'text/plain'). This will prevent HTML documents from being
|
335
|
+
uploaded as JPEGs, but will not prevent GIFs from being uploaded with a .jpg
|
336
|
+
extension. This validation will only add validation errors to the form. It will
|
337
|
+
not cause Errors to be raised.
|
338
|
+
|
305
339
|
Defaults
|
306
340
|
--------
|
307
341
|
Global defaults for all your paperclip attachments can be defined by changing the Paperclip::Attachment.default_options Hash, this can be useful for setting your default storage settings per example so you won't have to define them in every has_attached_file definition.
|
@@ -754,5 +788,5 @@ The names and logos for thoughtbot are trademarks of thoughtbot, inc.
|
|
754
788
|
License
|
755
789
|
-------
|
756
790
|
|
757
|
-
Paperclip is Copyright © 2008-
|
791
|
+
Paperclip is Copyright © 2008-2014 thoughtbot, inc. It is free software, and may be
|
758
792
|
redistributed under the terms specified in the MIT-LICENSE file.
|
@@ -11,8 +11,10 @@ World(AttachmentHelpers)
|
|
11
11
|
|
12
12
|
When /^I modify my attachment definition to:$/ do |definition|
|
13
13
|
content = in_current_dir { File.read("app/models/user.rb") }
|
14
|
+
name = content[/has_attached_file :\w+/][/:\w+/]
|
14
15
|
content.gsub!(/has_attached_file.+end/m, <<-FILE)
|
15
16
|
#{definition}
|
17
|
+
do_not_validate_attachment_file_type #{name}
|
16
18
|
end
|
17
19
|
FILE
|
18
20
|
|
@@ -69,6 +69,7 @@ def attach_attachment(name, definition = nil)
|
|
69
69
|
snippet += ", \n"
|
70
70
|
snippet += definition
|
71
71
|
end
|
72
|
+
snippet += "\ndo_not_validate_attachment_file_type :#{name}\n"
|
72
73
|
in_current_dir do
|
73
74
|
transform_file("app/models/user.rb") do |content|
|
74
75
|
content.sub(/end\Z/, "#{snippet}\nend")
|
data/lib/paperclip.rb
CHANGED
@@ -43,6 +43,7 @@ require 'paperclip/attachment'
|
|
43
43
|
require 'paperclip/storage'
|
44
44
|
require 'paperclip/callbacks'
|
45
45
|
require 'paperclip/file_command_content_type_detector'
|
46
|
+
require 'paperclip/media_type_spoof_detector'
|
46
47
|
require 'paperclip/content_type_detector'
|
47
48
|
require 'paperclip/glue'
|
48
49
|
require 'paperclip/errors'
|
data/lib/paperclip/attachment.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
require 'uri'
|
3
3
|
require 'paperclip/url_generator'
|
4
|
+
require 'active_support/deprecation'
|
4
5
|
|
5
6
|
module Paperclip
|
6
7
|
# The Attachment class manages the files for a given attachment. It saves
|
@@ -93,6 +94,7 @@ module Paperclip
|
|
93
94
|
# new_user.avatar = old_user.avatar
|
94
95
|
def assign uploaded_file
|
95
96
|
ensure_required_accessors!
|
97
|
+
ensure_required_validations!
|
96
98
|
file = Paperclip.io_adapters.for(uploaded_file)
|
97
99
|
|
98
100
|
return nil if not file.assignment?
|
@@ -166,6 +168,18 @@ module Paperclip
|
|
166
168
|
path.respond_to?(:unescape) ? path.unescape : path
|
167
169
|
end
|
168
170
|
|
171
|
+
# :nodoc:
|
172
|
+
def staged_path(style_name = default_style)
|
173
|
+
if staged?
|
174
|
+
@queued_for_write[style_name].path
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
# :nodoc:
|
179
|
+
def staged?
|
180
|
+
! @queued_for_write.empty?
|
181
|
+
end
|
182
|
+
|
169
183
|
# Alias to +url+
|
170
184
|
def to_s style_name = default_style
|
171
185
|
url(style_name)
|
@@ -373,6 +387,16 @@ module Paperclip
|
|
373
387
|
@options[:path].respond_to?(:call) ? @options[:path].call(self) : @options[:path]
|
374
388
|
end
|
375
389
|
|
390
|
+
def active_validator_classes
|
391
|
+
@instance.class.validators.map(&:class)
|
392
|
+
end
|
393
|
+
|
394
|
+
def ensure_required_validations!
|
395
|
+
if (active_validator_classes & Paperclip::REQUIRED_VALIDATORS).empty?
|
396
|
+
raise Paperclip::Errors::MissingRequiredValidatorError
|
397
|
+
end
|
398
|
+
end
|
399
|
+
|
376
400
|
def ensure_required_accessors! #:nodoc:
|
377
401
|
%w(file_name).each do |field|
|
378
402
|
unless @instance.respond_to?("#{name}_#{field}") && @instance.respond_to?("#{name}_#{field}=")
|
@@ -482,7 +506,7 @@ module Paperclip
|
|
482
506
|
end
|
483
507
|
end
|
484
508
|
|
485
|
-
# called by storage after the writes are flushed and before @
|
509
|
+
# called by storage after the writes are flushed and before @queued_for_write is cleared
|
486
510
|
def after_flush_writes
|
487
511
|
@queued_for_write.each do |style, file|
|
488
512
|
file.close unless file.closed?
|
data/lib/paperclip/callbacks.rb
CHANGED
@@ -7,7 +7,7 @@ module Paperclip
|
|
7
7
|
|
8
8
|
module Defining
|
9
9
|
def define_paperclip_callbacks(*callbacks)
|
10
|
-
define_callbacks
|
10
|
+
define_callbacks(*[callbacks, {:terminator => "result == false"}].flatten)
|
11
11
|
callbacks.each do |callback|
|
12
12
|
eval <<-end_callbacks
|
13
13
|
def before_#{callback}(*args, &blk)
|
@@ -32,10 +32,6 @@ module Paperclip
|
|
32
32
|
EMPTY_TYPE
|
33
33
|
elsif calculated_type_matches.any?
|
34
34
|
calculated_type_matches.first
|
35
|
-
elsif official_type_matches.any?
|
36
|
-
official_type_matches.first
|
37
|
-
elsif unofficial_type_matches.any?
|
38
|
-
unofficial_type_matches.first
|
39
35
|
else
|
40
36
|
type_from_file_command || SENSIBLE_DEFAULT
|
41
37
|
end.to_s
|
@@ -46,7 +42,7 @@ module Paperclip
|
|
46
42
|
def empty_file?
|
47
43
|
File.exists?(@filename) && File.size(@filename) == 0
|
48
44
|
end
|
49
|
-
|
45
|
+
|
50
46
|
alias :empty? :empty_file?
|
51
47
|
|
52
48
|
def blank_name?
|
@@ -61,14 +57,6 @@ module Paperclip
|
|
61
57
|
possible_types.select{|content_type| content_type == type_from_file_command }
|
62
58
|
end
|
63
59
|
|
64
|
-
def official_type_matches
|
65
|
-
possible_types.reject{|content_type| content_type.match(/\/x-/) }
|
66
|
-
end
|
67
|
-
|
68
|
-
def unofficial_type_matches
|
69
|
-
possible_types.select{|content_type| content_type.match(/\/x-/) }
|
70
|
-
end
|
71
|
-
|
72
60
|
def type_from_file_command
|
73
61
|
@type_from_file_command ||= FileCommandContentTypeDetector.new(@filename).detect
|
74
62
|
end
|
data/lib/paperclip/errors.rb
CHANGED
@@ -13,6 +13,11 @@ module Paperclip
|
|
13
13
|
class CommandNotFoundError < Paperclip::Error
|
14
14
|
end
|
15
15
|
|
16
|
+
# Attachments require a content_type or file_name validator,
|
17
|
+
# or to have explicitly opted out of them.
|
18
|
+
class MissingRequiredValidatorError < Paperclip::Error
|
19
|
+
end
|
20
|
+
|
16
21
|
# Will be thrown when ImageMagic cannot determine the uploaded file's
|
17
22
|
# metadata, usually this would mean the file is not an image.
|
18
23
|
class NotIdentifiedByImageMagickError < Paperclip::Error
|
@@ -18,6 +18,7 @@ module Paperclip
|
|
18
18
|
register_new_attachment
|
19
19
|
add_active_record_callbacks
|
20
20
|
add_paperclip_callbacks
|
21
|
+
add_required_validations
|
21
22
|
end
|
22
23
|
|
23
24
|
private
|
@@ -77,6 +78,10 @@ module Paperclip
|
|
77
78
|
Paperclip::AttachmentRegistry.register(@klass, @name, @options)
|
78
79
|
end
|
79
80
|
|
81
|
+
def add_required_validations
|
82
|
+
@klass.validates_media_type_spoof_detection @name
|
83
|
+
end
|
84
|
+
|
80
85
|
def add_active_record_callbacks
|
81
86
|
name = @name
|
82
87
|
@klass.send(:after_save) { send(name).send(:save) }
|
@@ -20,11 +20,11 @@ module Paperclip
|
|
20
20
|
@size = @tempfile.size || @target.size
|
21
21
|
end
|
22
22
|
|
23
|
-
def copy_to_tempfile(
|
24
|
-
if
|
25
|
-
|
23
|
+
def copy_to_tempfile(source)
|
24
|
+
if source.staged?
|
25
|
+
FileUtils.cp(source.staged_path(@style), destination.path)
|
26
26
|
else
|
27
|
-
|
27
|
+
source.copy_to_local_file(@style, destination.path)
|
28
28
|
end
|
29
29
|
destination
|
30
30
|
end
|
@@ -4,19 +4,14 @@ module Paperclip
|
|
4
4
|
REGEXP = /\Adata:([-\w]+\/[-\w\+]+);base64,(.*)/m
|
5
5
|
|
6
6
|
def initialize(target_uri)
|
7
|
-
|
8
|
-
cache_current_values
|
9
|
-
@tempfile = copy_to_tempfile
|
7
|
+
super(extract_target(target_uri))
|
10
8
|
end
|
11
9
|
|
12
10
|
private
|
13
11
|
|
14
|
-
def
|
15
|
-
|
16
|
-
|
17
|
-
@content_type = data_uri_parts[1] || 'text/plain'
|
18
|
-
@target = StringIO.new(Base64.decode64(data_uri_parts[2] || ''))
|
19
|
-
@size = @target.size
|
12
|
+
def extract_target(uri)
|
13
|
+
data_uri_parts = uri.match(REGEXP) || []
|
14
|
+
StringIO.new(Base64.decode64(data_uri_parts[2] || ''))
|
20
15
|
end
|
21
16
|
|
22
17
|
end
|
@@ -2,8 +2,8 @@ module Paperclip
|
|
2
2
|
class StringioAdapter < AbstractAdapter
|
3
3
|
def initialize(target)
|
4
4
|
@target = target
|
5
|
-
cache_current_values
|
6
5
|
@tempfile = copy_to_tempfile
|
6
|
+
cache_current_values
|
7
7
|
end
|
8
8
|
|
9
9
|
attr_writer :content_type
|
@@ -11,13 +11,10 @@ module Paperclip
|
|
11
11
|
private
|
12
12
|
|
13
13
|
def cache_current_values
|
14
|
-
@
|
15
|
-
@original_filename
|
16
|
-
|
17
|
-
|
18
|
-
@content_type = @target.content_type if @target.respond_to?(:content_type)
|
19
|
-
@content_type ||= "text/plain"
|
20
|
-
|
14
|
+
@content_type = ContentTypeDetector.new(@tempfile.path).detect
|
15
|
+
original_filename = @target.original_filename if @target.respond_to?(:original_filename)
|
16
|
+
original_filename ||= "data.#{extension_for(@content_type)}"
|
17
|
+
self.original_filename = original_filename.strip
|
21
18
|
@size = @target.size
|
22
19
|
end
|
23
20
|
|
@@ -29,6 +26,11 @@ module Paperclip
|
|
29
26
|
destination
|
30
27
|
end
|
31
28
|
|
29
|
+
def extension_for(content_type)
|
30
|
+
type = MIME::Types[content_type].first
|
31
|
+
type && type.extensions.first
|
32
|
+
end
|
33
|
+
|
32
34
|
end
|
33
35
|
end
|
34
36
|
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Paperclip
|
2
|
+
class MediaTypeSpoofDetector
|
3
|
+
def self.using(file, name)
|
4
|
+
new(file, name)
|
5
|
+
end
|
6
|
+
|
7
|
+
def initialize(file, name)
|
8
|
+
@file = file
|
9
|
+
@name = name
|
10
|
+
end
|
11
|
+
|
12
|
+
def spoofed?
|
13
|
+
if ! @name.blank?
|
14
|
+
! supplied_file_media_type.include?(calculated_media_type)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def supplied_file_media_type
|
21
|
+
MIME::Types.type_for(@name).collect(&:media_type)
|
22
|
+
end
|
23
|
+
|
24
|
+
def calculated_media_type
|
25
|
+
type_from_file_command.split("/").first
|
26
|
+
end
|
27
|
+
|
28
|
+
def type_from_file_command
|
29
|
+
begin
|
30
|
+
Paperclip.run("file", "-b --mime-type :file", :file => @file.path)
|
31
|
+
rescue Cocaine::CommandLineError
|
32
|
+
""
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module Paperclip
|
2
2
|
class TempfileFactory
|
3
3
|
|
4
|
-
def generate(name)
|
4
|
+
def generate(name = random_name)
|
5
5
|
@name = name
|
6
6
|
file = Tempfile.new([basename, extension])
|
7
7
|
file.binmode
|
@@ -15,5 +15,9 @@ module Paperclip
|
|
15
15
|
def basename
|
16
16
|
Digest::MD5.hexdigest(File.basename(@name, extension))
|
17
17
|
end
|
18
|
+
|
19
|
+
def random_name
|
20
|
+
SecureRandom.uuid
|
21
|
+
end
|
18
22
|
end
|
19
23
|
end
|