PluginProbe
Extendify / trunk
Extendify vtrunk
3.2.1 3.2.0 3.1.6 3.1.5 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 3.0.6 3.0.5 3.0.4 trunk 0.1.0 0.10.0 0.10.1 0.10.2 0.11.0 0.11.1 0.2.0 0.3.0 0.3.1 0.4.0 0.5.0 0.6.0 All 127 releases
← All changes | app/Shared/Services/BlockStyleVariations.php +44 -2 3.1.6 → trunk View file →
@@ -33,9 +33,15 @@
33 33 * @return void
34 34 */
35 35 public static function registerStored()
36 36 {
37 - self::registerNames(get_option(self::OPTION, []));
37 + $stored = get_option(self::OPTION, []);
38 + $valid = self::validBlockTypes($stored);
39 + if ($valid !== $stored) {
40 + update_option(self::OPTION, $valid);
41 + }
42 +
43 + self::registerNames($valid);
38 44 }
39 45
40 46 /**
41 47 * A design flow's write carries the names it needs, so nothing is fetched or
@@ -52,8 +58,13 @@
52 58 if (!$isWrite || strpos($request->get_route(), '/wp/v2/global-styles') !== 0) {
53 59 return $response;
54 60 }
55 61
62 + // This filter runs before the route's permission_callback, so auth is checked here.
63 + if (!current_user_can('edit_theme_options')) {
64 + return $response;
65 + }
66 +
56 67 $names = self::namesInWrite($request->get_param('styles'));
57 68 if (!$names) {
58 69 return $response;
59 70 }
@@ -72,8 +83,12 @@
72 83 {
73 84 $blocks = is_array($styles) ? ($styles['blocks'] ?? []) : [];
74 85 $names = [];
75 86 foreach ((array) $blocks as $blockType => $block) {
87 + if (!self::isValidBlockType($blockType)) {
88 + continue;
89 + }
90 +
76 91 $variations = is_array($block) ? ($block['variations'] ?? []) : [];
77 92 $ours = array_filter(array_keys((array) $variations), function ($name) {
78 93 return is_string($name) && strpos($name, 'ext-') === 0;
79 94 });
@@ -102,8 +117,31 @@
102 117 return $merged;
103 118 }
104 119
105 120 /**
121 + * A block-style key is interpolated unescaped into core's inline
122 + * registerBlockStyle() script, so only a real "namespace/block" name is
123 + * ever stored or registered — anything else is an injection attempt.
124 + *
125 + * @param mixed $blockType - The array key from a global-styles write.
126 + * @return bool
127 + */
128 + private static function isValidBlockType($blockType)
129 + {
130 + return is_string($blockType) && preg_match('~^[a-z0-9-]+/[a-z0-9-]+$~', $blockType) === 1;
131 + }
132 +
133 + /**
134 + * @param mixed $stored - The persisted names per block type.
135 + * @return array<string, array<string>>
136 + */
137 + private static function validBlockTypes($stored)
138 + {
139 + $names = is_array($stored) ? $stored : [];
140 + return array_filter($names, [self::class, 'isValidBlockType'], ARRAY_FILTER_USE_KEY);
141 + }
142 +
143 + /**
106 144 * @param mixed $names - Variation names per block type.
107 145 * @return void
108 146 */
109 147 private static function registerNames($names)
@@ -109,10 +147,14 @@
109 147 private static function registerNames($names)
110 148 {
111 149 $registry = \WP_Block_Styles_Registry::get_instance();
112 150 foreach ((array) $names as $blockType => $blockNames) {
151 + if (!self::isValidBlockType($blockType)) {
152 + continue;
153 + }
154 +
113 155 foreach ((array) $blockNames as $name) {
114 - if (!is_string($blockType) || !is_string($name) || $registry->is_registered($blockType, $name)) {
156 + if (!is_string($name) || $registry->is_registered($blockType, $name)) {
115 157 continue;
116 158 }
117 159
118 160 \register_block_style($blockType, ['name' => $name, 'label' => $name]);