image_processing 2.0.2 → 2.1.0
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 +4 -4
- data/CHANGELOG.md +10 -0
- data/lib/image_processing/chainable.rb +11 -12
- data/lib/image_processing/mini_magick.rb +25 -5
- data/lib/image_processing/processor.rb +9 -0
- data/lib/image_processing/version.rb +1 -1
- data/lib/image_processing.rb +19 -0
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a52c42f1463cc15caf0dfe57bc8a5efeb464006a2a29bbf1b8c842ada339e4aa
|
|
4
|
+
data.tar.gz: 2344e1015b02f4b24363371d8877bdcc4fb28b9fb820e15d2e2446f7874443c6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 90c29ed45d475cc54f814a368e894504f5bc012835ef989d3678568dfb3cd29aca144e88cb17d102ffc82dcbd94c4d46de7d9a5fbc0474c0f6b15c481a1f4bb3
|
|
7
|
+
data.tar.gz: 8a7f991cf00725e1d5618add34f9b57814e2e273d8b9575f49e61701e80259ac8c2cd61028cdaefc6b4a6694a8a922d2246f5f6b8f7ee7184ff31bd0f8644813
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
## 2.1.0 (2026-09-01)
|
|
2
|
+
|
|
3
|
+
* [minimagick] Add `inherit_fds:` so a loader can name an already-open input (thanks to @flavorjones)
|
|
4
|
+
|
|
5
|
+
## 2.0.3 (2026-08-06)
|
|
6
|
+
|
|
7
|
+
* Prevent remote code execution when operation names come from user input, closing bypasses through the `#operation` meta-builder, `#method_missing`, and nested `#send` calls (reported by @szymonsec)
|
|
8
|
+
|
|
9
|
+
* [minimagick] Prevent remote code execution through unsafe public methods (e.g. `#instance_eval`, `#send`) passed as loader/saver option names
|
|
10
|
+
|
|
1
11
|
## 2.0.2 (2026-06-03)
|
|
2
12
|
|
|
3
13
|
* Raise `LoadError` instead of `ImageProcessing::Error` when soft dependencies are missing (@bdewater-thatch)
|
|
@@ -86,25 +86,24 @@ module ImageProcessing
|
|
|
86
86
|
private
|
|
87
87
|
|
|
88
88
|
# This prevents calling unsafe Ruby core methods such as `Kernel#system`,
|
|
89
|
-
# which would allow for remote shell execution.
|
|
89
|
+
# which would allow for remote shell execution. The processor enforces the
|
|
90
|
+
# same guard when operations are dispatched, which also covers paths that
|
|
91
|
+
# bypass this early check (e.g. the #operation meta-builder).
|
|
92
|
+
#
|
|
93
|
+
# Bang names are rejected here because they are Chainable's execution
|
|
94
|
+
# shortcut (see #method_missing), not operations to chain.
|
|
90
95
|
def invalid_operation?(name)
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
owner = method(name).owner
|
|
94
|
-
[BasicObject, Kernel, Object, Module].include?(owner)
|
|
95
|
-
rescue NameError
|
|
96
|
-
false
|
|
96
|
+
name.end_with?("!") || ImageProcessing.unsafe_method?(self, name)
|
|
97
97
|
end
|
|
98
98
|
|
|
99
99
|
# Assume that any unknown method names an operation supported by the
|
|
100
100
|
# processor. Add a bang ("!") if you want processing to be performed.
|
|
101
|
-
def method_missing(name,
|
|
102
|
-
return super if name.
|
|
103
|
-
return public_send(name.to_s.chomp("!"),
|
|
101
|
+
def method_missing(name, ...)
|
|
102
|
+
return super if name.end_with?("?")
|
|
103
|
+
return public_send(name.to_s.chomp("!"), ...).call if name.end_with?("!")
|
|
104
104
|
|
|
105
|
-
operation(name,
|
|
105
|
+
operation(name, ...)
|
|
106
106
|
end
|
|
107
|
-
ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords, true)
|
|
108
107
|
|
|
109
108
|
# Empty options which the builder starts with.
|
|
110
109
|
DEFAULT_OPTIONS = {
|
|
@@ -9,11 +9,20 @@ module ImageProcessing
|
|
|
9
9
|
module MiniMagick
|
|
10
10
|
extend Chainable
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
# mini_magick gained `inherit_fds:` on MiniMagick::Shell#execute in 5.4.0.
|
|
13
|
+
INHERIT_FDS_MINIMUM_VERSION = Gem::Version.new("5.4.0")
|
|
14
|
+
|
|
15
|
+
def self.convert_shim(inherit_fds: nil, &block)
|
|
16
|
+
if inherit_fds && ::MiniMagick.version < INHERIT_FDS_MINIMUM_VERSION
|
|
17
|
+
raise LoadError, "The `inherit_fds` loader option requires mini_magick #{INHERIT_FDS_MINIMUM_VERSION} or newer, but mini_magick #{::MiniMagick.version} is loaded. Please upgrade the gem."
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
options = inherit_fds ? { inherit_fds: inherit_fds } : {}
|
|
21
|
+
|
|
13
22
|
if ::MiniMagick.respond_to?(:convert)
|
|
14
|
-
::MiniMagick.convert(&block)
|
|
23
|
+
::MiniMagick.convert(**options, &block)
|
|
15
24
|
else
|
|
16
|
-
::MiniMagick::Tool::Convert.new(&block)
|
|
25
|
+
::MiniMagick::Tool::Convert.new(**options, &block)
|
|
17
26
|
end
|
|
18
27
|
end
|
|
19
28
|
|
|
@@ -37,12 +46,16 @@ module ImageProcessing
|
|
|
37
46
|
# Initializes the image on disk into a MiniMagick::Tool object. Accepts
|
|
38
47
|
# additional options related to loading the image (e.g. geometry).
|
|
39
48
|
# Additionally auto-orients the image to be upright.
|
|
40
|
-
|
|
49
|
+
# `inherit_fds` names IO objects the tool inherits, so the source may be a
|
|
50
|
+
# `/dev/fd/N` path. The source stays a path, so `loader`, `page` and
|
|
51
|
+
# `geometry` still apply to it, which they would not if the caller passed
|
|
52
|
+
# a pre-built MiniMagick::Tool carrying the descriptor.
|
|
53
|
+
def self.load_image(path_or_magick, loader: nil, page: nil, geometry: nil, auto_orient: true, inherit_fds: nil, **options)
|
|
41
54
|
if path_or_magick.is_a?(::MiniMagick::Tool)
|
|
42
55
|
magick = path_or_magick
|
|
43
56
|
else
|
|
44
57
|
source_path = path_or_magick
|
|
45
|
-
magick = ::ImageProcessing::MiniMagick.convert_shim
|
|
58
|
+
magick = ::ImageProcessing::MiniMagick.convert_shim(inherit_fds: inherit_fds)
|
|
46
59
|
|
|
47
60
|
Utils.apply_options(magick, **options)
|
|
48
61
|
|
|
@@ -225,6 +238,13 @@ module ImageProcessing
|
|
|
225
238
|
# Applies options from the provided hash.
|
|
226
239
|
def apply_options(magick, define: {}, **options)
|
|
227
240
|
options.each do |option, value|
|
|
241
|
+
# Loader/saver option names may come from user input, so guard
|
|
242
|
+
# against dispatching to unsafe Ruby core methods (e.g. #send,
|
|
243
|
+
# #instance_eval) that public_send does not block on its own.
|
|
244
|
+
if ImageProcessing.unsafe_method?(magick, option)
|
|
245
|
+
raise Error, "#{option.inspect} is not a valid option"
|
|
246
|
+
end
|
|
247
|
+
|
|
228
248
|
case value
|
|
229
249
|
when true, nil then magick.public_send(option)
|
|
230
250
|
when false then magick.public_send(option).+
|
|
@@ -53,6 +53,15 @@ module ImageProcessing
|
|
|
53
53
|
# operation directly on the accumulator object. This provides a common
|
|
54
54
|
# umbrella above defined macros and direct operations.
|
|
55
55
|
def apply_operation(name, *args, &block)
|
|
56
|
+
# Chainable performs the same check when operations are built, but that
|
|
57
|
+
# guard only sees the outer builder method name, so it can be routed
|
|
58
|
+
# around via the #operation meta-builder, #method_missing, or a nested
|
|
59
|
+
# #send. This is the single point every operation is finally dispatched
|
|
60
|
+
# through, so enforcing the guard here closes all of those paths.
|
|
61
|
+
if ImageProcessing.unsafe_method?(self, name)
|
|
62
|
+
fail Error, "#{name.inspect} is not a valid operation"
|
|
63
|
+
end
|
|
64
|
+
|
|
56
65
|
receiver = respond_to?(name) ? self : @accumulator
|
|
57
66
|
|
|
58
67
|
if args.last.is_a?(Hash)
|
data/lib/image_processing.rb
CHANGED
|
@@ -7,6 +7,25 @@ require "image_processing/version"
|
|
|
7
7
|
module ImageProcessing
|
|
8
8
|
Error = Class.new(StandardError)
|
|
9
9
|
|
|
10
|
+
# Method owners considered unsafe to dispatch to when a method name comes
|
|
11
|
+
# from user input, because they expose Ruby's metaprogramming and shell
|
|
12
|
+
# primitives (e.g. Kernel#send, Kernel#eval, BasicObject#instance_eval,
|
|
13
|
+
# Kernel#system). Any name whose implementation is inherited from one of
|
|
14
|
+
# these should never be treated as an image operation or a loader/saver
|
|
15
|
+
# option.
|
|
16
|
+
UNSAFE_METHOD_OWNERS = [BasicObject, Kernel, Object, Module].freeze
|
|
17
|
+
|
|
18
|
+
# Whether calling +name+ on +receiver+ would dispatch to an unsafe Ruby core
|
|
19
|
+
# method rather than a genuine operation. Used as a single, shared guard at
|
|
20
|
+
# every place where a user-provided name is dispatched via +public_send+.
|
|
21
|
+
def self.unsafe_method?(receiver, name)
|
|
22
|
+
UNSAFE_METHOD_OWNERS.include?(receiver.method(name.to_s).owner)
|
|
23
|
+
rescue NameError
|
|
24
|
+
# An unknown name is not a Ruby core method, so it is safe to forward to
|
|
25
|
+
# the receiver (which will reject it if it is not a real operation).
|
|
26
|
+
false
|
|
27
|
+
end
|
|
28
|
+
|
|
10
29
|
autoload :MiniMagick, "image_processing/mini_magick"
|
|
11
30
|
autoload :Vips, "image_processing/vips"
|
|
12
31
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: image_processing
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.0
|
|
4
|
+
version: 2.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Janko Marohnić
|
|
@@ -105,7 +105,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
105
105
|
- !ruby/object:Gem::Version
|
|
106
106
|
version: '0'
|
|
107
107
|
requirements: []
|
|
108
|
-
rubygems_version: 4.0.
|
|
108
|
+
rubygems_version: 4.0.13
|
|
109
109
|
specification_version: 4
|
|
110
110
|
summary: High-level wrapper for processing images for the web with ImageMagick or
|
|
111
111
|
libvips.
|