active_storage_validations 3.0.5 → 3.0.6
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:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: fb09e2b76b2325f8dab17bd4774b91bb1f041766e3705e563f338951d04e191a
|
|
4
|
+
data.tar.gz: 56ed87a99def7941a8d17e4433980c947c8771c3dd42141d0f1f13702c8556c2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 84fb802a4958ef5b3e00e088383768540849a883b3f2bd757b19ed24c0516d1fd8a498aaaac93ef0e02d6105dca0c6058e5a85ac3a4d1a1b0d79cd1e682dfb45
|
|
7
|
+
data.tar.gz: de96e6b525ca4ff0e9e3342b9bd1719c199e956b807467c62d6f063e649f80348e9b323525b1c99f203b025e08a995bc8534b1fd01c434579eca5526ee2ced61
|
|
@@ -19,6 +19,28 @@ module ActiveStorageValidations
|
|
|
19
19
|
].freeze
|
|
20
20
|
METADATA_KEYS = %i[].freeze
|
|
21
21
|
|
|
22
|
+
# Content types whose libvips loaders are marked untrusted / unfuzzed
|
|
23
|
+
# (VIPS_OPERATION_UNTRUSTED). After Rails calls `Vips.block_untrusted(true)`,
|
|
24
|
+
# analysis of these types returns no width/height (empty metadata here),
|
|
25
|
+
# which is not the same as a corrupt / unprocessable file.
|
|
26
|
+
#
|
|
27
|
+
# Matches the formats called out in the Active Storage security release
|
|
28
|
+
# changelogs (7.2.3.2 / 8.0.5.1 / 8.1.3.1):
|
|
29
|
+
# https://github.com/rails/rails/blob/v8.1.3.1/activestorage/CHANGELOG.md
|
|
30
|
+
# https://github.com/rails/rails/security/advisories/GHSA-xr9x-r78c-5hrm
|
|
31
|
+
VIPS_UNTRUSTED_CONTENT_TYPES = %w[
|
|
32
|
+
image/bmp
|
|
33
|
+
image/vnd.microsoft.icon
|
|
34
|
+
image/vnd.adobe.photoshop
|
|
35
|
+
image/svg+xml
|
|
36
|
+
image/jxl
|
|
37
|
+
image/jp2
|
|
38
|
+
image/x-portable-anymap
|
|
39
|
+
image/x-portable-bitmap
|
|
40
|
+
image/x-portable-graymap
|
|
41
|
+
image/x-portable-pixmap
|
|
42
|
+
].freeze
|
|
43
|
+
|
|
22
44
|
def validate_each(record, attribute, _value)
|
|
23
45
|
return if no_attachments?(record, attribute)
|
|
24
46
|
|
|
@@ -28,10 +50,47 @@ module ActiveStorageValidations
|
|
|
28
50
|
private
|
|
29
51
|
|
|
30
52
|
def is_valid?(record, attribute, attachable, metadata)
|
|
31
|
-
return if
|
|
53
|
+
return if metadata.present?
|
|
54
|
+
return if vips_unanalyzable_by_policy?(attachable)
|
|
32
55
|
|
|
33
56
|
errors_options = initialize_error_options(options, attachable)
|
|
34
57
|
add_error(record, attribute, ERROR_TYPES.first, **errors_options)
|
|
35
58
|
end
|
|
59
|
+
|
|
60
|
+
def vips_unanalyzable_by_policy?(attachable)
|
|
61
|
+
image_processor == :vips &&
|
|
62
|
+
self.class.vips_untrusted_operations_blocked? &&
|
|
63
|
+
VIPS_UNTRUSTED_CONTENT_TYPES.include?(attachable_content_type(attachable))
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
class << self
|
|
67
|
+
# Detect whether libvips is currently blocking untrusted operations.
|
|
68
|
+
# There is no public getter for `Vips.block_untrusted`, so we probe whether
|
|
69
|
+
# an untrusted loader (svgload) is available via `vips_foreign_find_load`.
|
|
70
|
+
def vips_untrusted_operations_blocked?
|
|
71
|
+
return @vips_untrusted_operations_blocked if defined?(@vips_untrusted_operations_blocked)
|
|
72
|
+
|
|
73
|
+
@vips_untrusted_operations_blocked = detect_vips_untrusted_operations_blocked?
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def reset_vips_untrusted_operations_blocked_cache!
|
|
77
|
+
remove_instance_variable(:@vips_untrusted_operations_blocked) if defined?(@vips_untrusted_operations_blocked)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
private
|
|
81
|
+
|
|
82
|
+
def detect_vips_untrusted_operations_blocked?
|
|
83
|
+
require "vips"
|
|
84
|
+
require "tempfile"
|
|
85
|
+
|
|
86
|
+
Tempfile.create([ "asv_vips_untrusted_probe", ".svg" ]) do |file|
|
|
87
|
+
file.write('<svg xmlns="http://www.w3.org/2000/svg" width="1" height="1"/>')
|
|
88
|
+
file.flush
|
|
89
|
+
::Vips.vips_foreign_find_load(file.path).nil?
|
|
90
|
+
end
|
|
91
|
+
rescue LoadError, StandardError
|
|
92
|
+
false
|
|
93
|
+
end
|
|
94
|
+
end
|
|
36
95
|
end
|
|
37
96
|
end
|
|
@@ -44,7 +44,7 @@ module ActiveStorageValidations
|
|
|
44
44
|
return to_enum(:attachables_and_blobs, record, attribute) if changes.blank? || !block_given?
|
|
45
45
|
|
|
46
46
|
if changes.is_a?(ActiveStorage::Attached::Changes::CreateMany)
|
|
47
|
-
changes.attachables.zip(changes.blobs).uniq { |
|
|
47
|
+
changes.attachables.zip(changes.blobs).uniq { |attachable, blob| attachable_blob_key(attachable, blob) }.each do |attachable, blob|
|
|
48
48
|
yield attachable, blob
|
|
49
49
|
end
|
|
50
50
|
else
|
|
@@ -52,6 +52,12 @@ module ActiveStorageValidations
|
|
|
52
52
|
end
|
|
53
53
|
end
|
|
54
54
|
|
|
55
|
+
def attachable_blob_key(attachable, blob)
|
|
56
|
+
return [ :blob_id, blob.id ] if blob&.id
|
|
57
|
+
|
|
58
|
+
[ :attachable, attachable.object_id ]
|
|
59
|
+
end
|
|
60
|
+
|
|
55
61
|
def changes_for(record, attribute)
|
|
56
62
|
if record.public_send(attribute).is_a?(ActiveStorage::Attached::One)
|
|
57
63
|
record.attachment_changes[attribute.to_s].presence || record.public_send(attribute)
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: active_storage_validations
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.0.
|
|
4
|
+
version: 3.0.6
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Igor Kasyanchuk
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-08-01 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activejob
|
|
@@ -108,6 +108,20 @@ dependencies:
|
|
|
108
108
|
- - ">="
|
|
109
109
|
- !ruby/object:Gem::Version
|
|
110
110
|
version: 4.9.5
|
|
111
|
+
- !ruby/object:Gem::Dependency
|
|
112
|
+
name: minitest
|
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
|
114
|
+
requirements:
|
|
115
|
+
- - "~>"
|
|
116
|
+
- !ruby/object:Gem::Version
|
|
117
|
+
version: '5.0'
|
|
118
|
+
type: :development
|
|
119
|
+
prerelease: false
|
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
121
|
+
requirements:
|
|
122
|
+
- - "~>"
|
|
123
|
+
- !ruby/object:Gem::Version
|
|
124
|
+
version: '5.0'
|
|
111
125
|
- !ruby/object:Gem::Dependency
|
|
112
126
|
name: minitest-focus
|
|
113
127
|
requirement: !ruby/object:Gem::Requirement
|