kt-paperclip 8.0.0 → 8.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 57acb40c010d089179840fb06116bb36527035ce5e6ddaa25531d2d24067456f
4
- data.tar.gz: f49b37dbd63550be17c59b47ce930981dae6f7d88461cf90721925051e579efa
3
+ metadata.gz: 71b12469bab65eb2861d1170c154ecf1a08f6a0591806096f3d49f598f4ec115
4
+ data.tar.gz: 12efe7db20633834994b3b1836cc697ff21dbf1bd37851346d1bd5e0961aa045
5
5
  SHA512:
6
- metadata.gz: f92b7453a259e25763375ba727dc262910ec647e54017182befa98e0330e6ac5890cd76ab27476a3be6725de35aeb8b85f73db463ad75007370d0076ed3220bb
7
- data.tar.gz: dae535db1d37087c4505aaa0db691c2e300377755c9345ef412a28dfde1bf55f64f169d6f438d0285672db9bc8681629708c1c366e719cfcb2773d89f6ad5906
6
+ metadata.gz: 6db416b89eaa01127e3b8eb7ac7615a19d840a236ea114be4814675d61765fa53f25e25b351b5d9438badf06ab3a20ec036565a418f47dbbcd97563d96e0f91f
7
+ data.tar.gz: 8aa390b628e9926d17c9de71e0dfe861fe2197762fff916064e1b61bd18fda5e3d2f6eda291d4e208e36ecb2fa3fc98ca366e5a28c479f7dde00b02736be2765
data/README.md CHANGED
@@ -90,7 +90,7 @@ Requirements
90
90
 
91
91
  ### Ruby and Rails
92
92
 
93
- Paperclip now requires Ruby version **>= 2.3** and Rails version **>= 4.2**
93
+ Paperclip now requires Ruby version **>= 2.7** and Rails version **>= 5.2**
94
94
  (only if you're going to use Paperclip with Ruby on Rails).
95
95
 
96
96
  ### ImageMagick Image Processor
@@ -139,7 +139,7 @@ Paperclip is distributed as a gem, which is how it should be used in your app.
139
139
  Include the gem in your Gemfile:
140
140
 
141
141
  ```ruby
142
- gem "kt-paperclip", "~> 6.4", ">= 6.4.1"
142
+ gem "kt-paperclip", "~> 8.0"
143
143
  ```
144
144
 
145
145
  Or, if you want to get the latest, you can get master from the main paperclip repository:
@@ -375,8 +375,10 @@ validates_attachment :avatar,
375
375
  content_type: ["image/jpeg", "image/gif", "image/png"]
376
376
  ```
377
377
 
378
- `Paperclip::ContentTypeDetector` will attempt to match a file's extension to an
379
- inferred content_type, regardless of the actual contents of the file.
378
+ `Paperclip::ContentTypeDetector` uses the file's extension as a hint when the contents alone are
379
+ ambiguous, so the stored `content_type` is not by itself proof of what a file contains. The check
380
+ that ignores the filename entirely is `validates_media_type_spoof_detection` (see Security
381
+ Validations below); use it alongside your `content_type` validation.
380
382
 
381
383
  ### Duplicate error messages
382
384
 
@@ -444,17 +446,26 @@ being uploaded as JPEGs, but will not prevent GIFs from being uploaded with a
444
446
  `.jpg` extension. This validation will only add validation errors to the form. It
445
447
  will not cause errors to be raised.
446
448
 
449
+ The type is detected from the file's contents only, using magic-number detection plus the Unix
450
+ `file` utility. The filename is never consulted. Where `file` is unavailable the check falls back
451
+ to magic-number detection alone, which cannot identify text-based formats; content it cannot
452
+ identify at all is accepted rather than rejected.
453
+
447
454
  This can sometimes cause false validation errors in applications that use custom
448
455
  file extensions. In these cases you may wish to add your custom extension to the
449
456
  list of content type mappings by creating `config/initializers/paperclip.rb`:
450
457
 
451
458
  ```ruby
452
- # Allow ".foo" as an extension for files with the MIME type "text/plain".
459
+ # Allow ".foo" as an extension for files whose contents are detected as "text/plain".
453
460
  Paperclip.options[:content_type_mappings] = {
454
461
  foo: %w(text/plain)
455
462
  }
456
463
  ```
457
464
 
465
+ The value is the type the *contents* detect as (what `file -b --mime` reports), not the type you
466
+ would like the extension to mean. Text-based formats such as SVG and CSV are the usual reason to
467
+ need one.
468
+
458
469
  ---
459
470
 
460
471
  Defaults
@@ -42,12 +42,27 @@ module Paperclip
42
42
  end
43
43
 
44
44
  def calculated_type_mismatch?
45
- supplied_media_type.present? &&
46
- !calculated_content_type.include?(supplied_media_type)
45
+ return false if supplied_media_type.blank?
46
+ # Fast path: the magic number already supports the supplied type, no shell out needed.
47
+ return false if supplied_type_consistent_with?(type_from_magic)
48
+ # The bytes told us nothing at all, so there is nothing to contradict the supplied type.
49
+ return false if calculated_content_types.empty?
50
+
51
+ !supplied_type_consistent_with?(type_from_file_command)
52
+ end
53
+
54
+ # The supplied type is supported by the bytes if it shares their media type, or if it is a
55
+ # specialization of what the bytes resolved to: image/svg+xml is a child of application/xml,
56
+ # which is all the magic number of an SVG with an XML declaration can tell us.
57
+ def supplied_type_consistent_with?(type)
58
+ return false if type.blank?
59
+
60
+ type.include?(supplied_media_type) ||
61
+ !!Marcel::Magic.child?(supplied_content_type, type)
47
62
  end
48
63
 
49
64
  def mapping_override_mismatch?
50
- !Array(mapped_content_type).include?(calculated_content_type)
65
+ (Array(mapped_content_type) & calculated_content_types).empty?
51
66
  end
52
67
 
53
68
  def supplied_content_type
@@ -66,12 +81,35 @@ module Paperclip
66
81
  @media_types_from_name ||= content_types_from_name.collect(&:media_type)
67
82
  end
68
83
 
84
+ # Every type the file's *contents* resolve to. The filename is deliberately never consulted
85
+ # here -- trusting it is what let a renamed file pass this check (kreeti/kt-paperclip#173).
86
+ def calculated_content_types
87
+ @calculated_content_types ||=
88
+ # Both sources return nil, never a blank string, when they come up empty.
89
+ [type_from_magic, type_from_file_command].compact.uniq
90
+ end
91
+
69
92
  def calculated_content_type
70
- @calculated_content_type ||= ContentTypeDetector.new(@file.path).detect("")
93
+ @calculated_content_type ||= calculated_content_types.first.to_s
71
94
  end
72
95
 
73
- def calculated_media_type
74
- @calculated_media_type ||= calculated_content_type.split("/").first
96
+ # Note the absence of a `name:` argument. Marcel lets the filename decide when the bytes carry
97
+ # no magic number of their own, which is exactly what spoof detection must not allow.
98
+ def type_from_magic
99
+ return @type_from_magic if defined?(@type_from_magic)
100
+
101
+ type = Marcel::MimeType.for(Pathname.new(@file.path))
102
+ # Marcel::MimeType returns 'application/octet-stream' if it can't find a valid type.
103
+ @type_from_magic = type == ContentTypeDetector::SENSIBLE_DEFAULT ? nil : type
104
+ rescue Errno::ENOENT => e
105
+ Paperclip.log("Error while determining content type: #{e}")
106
+ @type_from_magic = nil
107
+ end
108
+
109
+ def type_from_file_command
110
+ return @type_from_file_command if defined?(@type_from_file_command)
111
+
112
+ @type_from_file_command = Commands::UnixFile.detect_content_type(@file.path)
75
113
  end
76
114
 
77
115
  def mapped_content_type
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Paperclip
4
- VERSION = "8.0.0" unless defined?(Paperclip::VERSION)
4
+ VERSION = "8.0.1" unless defined?(Paperclip::VERSION)
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kt-paperclip
3
3
  version: !ruby/object:Gem::Version
4
- version: 8.0.0
4
+ version: 8.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Surendra Singhi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-06-30 00:00:00.000000000 Z
11
+ date: 2026-10-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel