Use recursive stylesheet sanitation
| @@ -465,18 +465,7 @@ export function decodeStyleTags(text) { | ||
| 465 | 465 | const styleDecodeRegex = /<custom-style>(.+?)<\/custom-style>/gms; |
| 466 | 466 | const mediaAllowed = isExternalMediaAllowed(); |
| 467 | 467 | |
| 468 | - return text.replaceAll(styleDecodeRegex, (_, style) => { | |
| 468 | + function sanitizeRule(rule) { | |
| 469 | - try { | |
| 470 | - let styleCleaned = unescape(style).replaceAll(/<br\/>/g, ''); | |
| 471 | - const ast = css.parse(styleCleaned); | |
| 472 | - const rules = ast?.stylesheet?.rules; | |
| 473 | - if (rules) { | |
| 474 | - for (const rule of rules) { | |
| 475 | - if (rule.type === 'import') { | |
| 476 | - rules.splice(rules.indexOf(rule), 1); | |
| 477 | - } | |
| 478 | - | |
| 479 | - if (rule.type === 'rule') { | |
| 480 | 469 | if (rule.selectors) { |
| 481 | 470 | for (let i = 0; i < rule.selectors.length; i++) { |
| 482 | 471 | let selector = rule.selectors[i]; |
| @@ -500,7 +489,28 @@ export function decodeStyleTags(text) { | ||
| 500 | 489 | } |
| 501 | 490 | } |
| 502 | 491 | } |
| 492 | + | |
| 493 | + function sanitizeRuleSet(ruleSet) { | |
| 494 | + if (ruleSet.type === 'rule') { | |
| 495 | + sanitizeRule(ruleSet); | |
| 503 | 496 | } |
| 497 | + | |
| 498 | + if (Array.isArray(ruleSet.rules)) { | |
| 499 | + ruleSet.rules = ruleSet.rules.filter(rule => rule.type !== 'import'); | |
| 500 | + | |
| 501 | + for (const mediaRule of ruleSet.rules) { | |
| 502 | + sanitizeRuleSet(mediaRule); | |
| 503 | + } | |
| 504 | + } | |
| 505 | + } | |
| 506 | + | |
| 507 | + return text.replaceAll(styleDecodeRegex, (_, style) => { | |
| 508 | + try { | |
| 509 | + let styleCleaned = unescape(style).replaceAll(/<br\/>/g, ''); | |
| 510 | + const ast = css.parse(styleCleaned); | |
| 511 | + const sheet = ast?.stylesheet; | |
| 512 | + if (sheet) { | |
| 513 | + sanitizeRuleSet(ast.stylesheet); | |
| 504 | 514 | } |
| 505 | 515 | return `<style>${css.stringify(ast)}</style>`; |
| 506 | 516 | } catch (error) { |