view_component 3.26.0 → 3.27.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/docs/CHANGELOG.md +6 -0
- data/lib/view_component/base.rb +16 -1
- data/lib/view_component/collection.rb +10 -5
- data/lib/view_component/errors.rb +13 -0
- data/lib/view_component/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ea3b7eaa6244e04ffa83e7c9d4aeafca18230bedcce0fb160b1001b0441270b0
|
|
4
|
+
data.tar.gz: aa605998a6e975f74c307faca61ec6d10b837cdee83c48fe2424e5b6421daf8a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a3ec820b42851cb62062972e1473ebb508798e0acd63bfff6e6fda1087c62776806c0199a9e11d6b13bd2914330bf0ad1cb899511c55f62af1538be7a9292a13
|
|
7
|
+
data.tar.gz: 748b43b70dec2efc5319bec3379f6b7cf115789f731e3a32af789c304644d20f14d62c9bc727ab88baa4a52dbeba806f8f403dcee1bcf1bc9a6df6ee73f0d412
|
data/docs/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,12 @@ nav_order: 6
|
|
|
10
10
|
|
|
11
11
|
## main
|
|
12
12
|
|
|
13
|
+
## 3.27.0
|
|
14
|
+
|
|
15
|
+
* [Security] Fix incomplete remediation for CVE-2026-54497 (GHSA-8qw7-6phv-7q6p): reused ViewComponent instances could still leak `with_content` and `renders_one`/`renders_many` slot content from an earlier render into a later render because slot state and content set via `with_content` are populated by the caller before `render_in` runs and were not cleared by the previous per-render reset. Reinstate the `ViewComponent::ReusedInstanceError` guard that raises when a component instance is rendered more than once. Rebuild collection child components per render and dup collection spacer components before each render so that legitimate re-rendering of `Collection`/spacer objects continues to work.
|
|
16
|
+
|
|
17
|
+
*Yazan Balawneh, Cystack.ps*
|
|
18
|
+
|
|
13
19
|
## 3.26.0
|
|
14
20
|
|
|
15
21
|
* Fix rendering partials from components rendered as a collection when the original view context is explicitly stashed as `nil`.
|
data/lib/view_component/base.rb
CHANGED
|
@@ -83,6 +83,7 @@ module ViewComponent
|
|
|
83
83
|
def render_in(view_context, **options, &block)
|
|
84
84
|
self.class.compile(raise_errors: true)
|
|
85
85
|
|
|
86
|
+
__vc_check_reused_instance!
|
|
86
87
|
__vc_reset_render_state!
|
|
87
88
|
|
|
88
89
|
@view_context = view_context
|
|
@@ -137,6 +138,7 @@ module ViewComponent
|
|
|
137
138
|
end
|
|
138
139
|
ensure
|
|
139
140
|
@current_template = old_current_template
|
|
141
|
+
@__vc_rendered = true
|
|
140
142
|
end
|
|
141
143
|
|
|
142
144
|
# Subclass components that call `super` inside their template code will cause a
|
|
@@ -410,7 +412,9 @@ module ViewComponent
|
|
|
410
412
|
# state from a previous render. Slot state (`@__vc_set_slots`,
|
|
411
413
|
# `@__vc_content_set_by_with_content`) is intentionally preserved because it
|
|
412
414
|
# is populated by callers _before_ `render_in` runs (e.g. via `with_*`
|
|
413
|
-
# slot setters or `with_content`)
|
|
415
|
+
# slot setters or `with_content`); reuse of an instance that has slot or
|
|
416
|
+
# `with_content` state is guarded against separately by
|
|
417
|
+
# `__vc_check_reused_instance!`.
|
|
414
418
|
def __vc_reset_render_state!
|
|
415
419
|
%i[
|
|
416
420
|
@__vc_controller
|
|
@@ -422,6 +426,17 @@ module ViewComponent
|
|
|
422
426
|
end
|
|
423
427
|
end
|
|
424
428
|
|
|
429
|
+
# Raises when a component instance is rendered more than once.
|
|
430
|
+
# Reusing a component instance across renders can leak request-scoped state
|
|
431
|
+
# (controller, helpers, request, view_flow, slot content, `with_content`)
|
|
432
|
+
# from an earlier render into a later one. See
|
|
433
|
+
# `ViewComponent::ReusedInstanceError` and GHSA-8qw7-6phv-7q6p.
|
|
434
|
+
def __vc_check_reused_instance!
|
|
435
|
+
return unless defined?(@__vc_rendered) && @__vc_rendered
|
|
436
|
+
|
|
437
|
+
raise ReusedInstanceError.new(self.class.name)
|
|
438
|
+
end
|
|
439
|
+
|
|
425
440
|
# Configuration for generators.
|
|
426
441
|
#
|
|
427
442
|
# All options under this namespace default to `false` unless otherwise
|
|
@@ -72,13 +72,18 @@ module ViewComponent
|
|
|
72
72
|
@options.merge(item_options)
|
|
73
73
|
end
|
|
74
74
|
|
|
75
|
+
# Render the spacer through a fresh `dup` so a collection rendered multiple
|
|
76
|
+
# times does not reuse (and trip the single-render guard on) the spacer
|
|
77
|
+
# instance passed by the caller.
|
|
75
78
|
def rendered_spacer(view_context)
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
79
|
+
return "" unless @spacer_component
|
|
80
|
+
|
|
81
|
+
spacer = @spacer_component.dup
|
|
82
|
+
if spacer.instance_variable_defined?(:@__vc_rendered)
|
|
83
|
+
spacer.remove_instance_variable(:@__vc_rendered)
|
|
81
84
|
end
|
|
85
|
+
spacer.set_original_view_context(__vc_original_view_context) if spacer.respond_to?(:set_original_view_context)
|
|
86
|
+
spacer.render_in(view_context)
|
|
82
87
|
end
|
|
83
88
|
end
|
|
84
89
|
end
|
|
@@ -175,6 +175,19 @@ module ViewComponent
|
|
|
175
175
|
"To fix this issue, pass a value."
|
|
176
176
|
end
|
|
177
177
|
|
|
178
|
+
class ReusedInstanceError < StandardError
|
|
179
|
+
MESSAGE =
|
|
180
|
+
"ViewComponent instances are single-use; a COMPONENT instance was rendered more than once.\n\n" \
|
|
181
|
+
"Reusing a component instance across renders can leak request-scoped state " \
|
|
182
|
+
"(controller, helpers, request, view_flow, slot content, `with_content`) from an earlier render " \
|
|
183
|
+
"into a later one, which has security and correctness implications (GHSA-8qw7-6phv-7q6p).\n\n" \
|
|
184
|
+
"To fix this issue, create a new component instance per render."
|
|
185
|
+
|
|
186
|
+
def initialize(klass_name)
|
|
187
|
+
super(MESSAGE.gsub("COMPONENT", klass_name.to_s))
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
|
|
178
191
|
class TranslateCalledBeforeRenderError < BaseError
|
|
179
192
|
MESSAGE =
|
|
180
193
|
"`#translate` can't be used before rendering as it depends " \
|