Skip to content

Commit 0204555

Browse files
committed
AC-9986: wysiwyg editor content validation
1 parent 9ae6c5d commit 0204555

File tree

3 files changed

+71
-20
lines changed

3 files changed

+71
-20
lines changed

app/design/adminhtml/Magento/backend/i18n/en_US.csv

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -548,3 +548,5 @@ Dashboard,Dashboard
548548
"Store Email Addresses Section","Store Email Addresses Section"
549549
"Email to a Friend","Email to a Friend"
550550
"Invalid data type","Invalid data type"
551+
"Invalid value provided for attribute %1","Invalid value provided for attribute %1"
552+

lib/internal/Magento/Framework/Test/Unit/Validator/HTML/ConfigurableWYSIWYGValidatorTest.php

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,24 @@ public function getConfigurations(): array
165165
true,
166166
[],
167167
['div' => ['src' => false]]
168+
],
169+
'invalid-allowed-tag-attributes' => [
170+
['a'],
171+
['href'],
172+
['a' => ['href']],
173+
'<a href="javascript:alert(1)">a</a>',
174+
false,
175+
[],
176+
[]
177+
],
178+
'allowed-empty-tag' => [
179+
[],
180+
[],
181+
[],
182+
'',
183+
false,
184+
[],
185+
[]
168186
]
169187
];
170188
}
@@ -224,20 +242,23 @@ function (string $givenTag, array $attrs) use ($tag, $allowedAttributes): void {
224242
);
225243
$tagValidatorsMocks[$tag] = [$mock];
226244
}
227-
$validator = new ConfigurableWYSIWYGValidator(
228-
$allowedTags,
229-
$allowedAttr,
230-
$allowedTagAttrs,
231-
$attrValidators,
232-
$tagValidatorsMocks
233-
);
234-
$valid = true;
235245
try {
236-
$validator->validate($html);
237-
} catch (ValidationException $exception) {
246+
$validator = new ConfigurableWYSIWYGValidator(
247+
$allowedTags,
248+
$allowedAttr,
249+
$allowedTagAttrs,
250+
$attrValidators,
251+
$tagValidatorsMocks
252+
);
253+
$valid = true;
254+
try {
255+
$validator->validate($html);
256+
} catch (ValidationException $exception) {
257+
$valid = false;
258+
}
259+
} catch (\InvalidArgumentException $exception) {
238260
$valid = false;
239261
}
240-
241262
self::assertEquals($isValid, $valid);
242263
}
243264
}

lib/internal/Magento/Framework/Validator/HTML/ConfigurableWYSIWYGValidator.php

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,14 @@
1515
*/
1616
class ConfigurableWYSIWYGValidator implements WYSIWYGValidatorInterface
1717
{
18+
/**
19+
* @var string
20+
*/
21+
private static string $xssFiltrationPattern =
22+
'/((javascript(\\\\x3a|:|%3A))|(data(\\\\x3a|:|%3A))|(vbscript:)|(script)|(alert\())|'
23+
. '((\\\\x6A\\\\x61\\\\x76\\\\x61\\\\x73\\\\x63\\\\x72\\\\x69\\\\x70\\\\x74(\\\\x3a|:|%3A))|'
24+
. '(\\\\x64\\\\x61\\\\x74\\\\x61(\\\\x3a|:|%3A)))/i';
25+
1826
/**
1927
* @var string[]
2028
*/
@@ -84,6 +92,7 @@ public function validate(string $content): void
8492
$this->validateConfigured($xpath);
8593
$this->callAttributeValidators($xpath);
8694
$this->callTagValidators($xpath);
95+
$this->validateAttributeValue($xpath);
8796
}
8897

8998
/**
@@ -98,16 +107,16 @@ private function validateConfigured(\DOMXPath $xpath): void
98107
//Validating tags
99108
$found = $xpath->query(
100109
'//*['
101-
. implode(
102-
' and ',
103-
array_map(
104-
function (string $tag): string {
105-
return "name() != '$tag'";
106-
},
107-
array_merge($this->allowedTags, ['body', 'html'])
108-
)
110+
. implode(
111+
' and ',
112+
array_map(
113+
function (string $tag): string {
114+
return "name() != '$tag'";
115+
},
116+
array_merge($this->allowedTags, ['body', 'html'])
109117
)
110-
.']'
118+
)
119+
.']'
111120
);
112121
if (count($found)) {
113122
throw new ValidationException(
@@ -242,4 +251,23 @@ function () use (&$loaded) {
242251

243252
return $dom;
244253
}
254+
255+
/**
256+
* Validate values of html attributes
257+
*
258+
* @param \DOMXPath $xpath
259+
* @return void
260+
* @throws ValidationException
261+
*/
262+
private function validateAttributeValue(\DOMXPath $xpath): void
263+
{
264+
$nodes = $xpath->query('//@*');
265+
foreach ($nodes as $node) {
266+
if (preg_match(self::$xssFiltrationPattern, $node->parentNode->getAttribute($node->nodeName))) {
267+
throw new ValidationException(
268+
__('Invalid value provided for attribute %1', $node->nodeName)
269+
);
270+
}
271+
}
272+
}
245273
}

0 commit comments

Comments
 (0)