From 2c049e561160a93da717d915b6277913eb9ad4ce Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Mon, 27 May 2024 13:25:21 +0300 Subject: [PATCH 1/4] Remove imports from embedded styles --- public/scripts/chats.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/public/scripts/chats.js b/public/scripts/chats.js index 3187276d7..4bea9ed58 100644 --- a/public/scripts/chats.js +++ b/public/scripts/chats.js @@ -471,6 +471,9 @@ export function decodeStyleTags(text) { const rules = ast?.stylesheet?.rules; if (rules) { for (const rule of rules) { + if (rule.type === 'import') { + rules.splice(rules.indexOf(rule), 1); + } if (rule.type === 'rule') { if (rule.selectors) { From 99e09f0b91fc918b547f63f0a88f6f7289d8d898 Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Mon, 27 May 2024 13:43:59 +0300 Subject: [PATCH 2/4] Improve external media removal in style blocks --- public/scripts/chats.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/public/scripts/chats.js b/public/scripts/chats.js index 4bea9ed58..84f316e63 100644 --- a/public/scripts/chats.js +++ b/public/scripts/chats.js @@ -463,6 +463,7 @@ export function encodeStyleTags(text) { */ export function decodeStyleTags(text) { const styleDecodeRegex = /(.+?)<\/custom-style>/gms; + const mediaAllowed = isExternalMediaAllowed(); return text.replaceAll(styleDecodeRegex, (_, style) => { try { @@ -491,6 +492,13 @@ export function decodeStyleTags(text) { } } } + if (!mediaAllowed && Array.isArray(rule.declarations) && rule.declarations.length > 0) { + for (const declaration of rule.declarations) { + if (declaration.value.includes('://')) { + rule.declarations.splice(rule.declarations.indexOf(declaration), 1); + } + } + } } } } From 62a1919402faa555c3d670d517fa8872be60a898 Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Mon, 27 May 2024 14:26:59 +0300 Subject: [PATCH 3/4] Use recursive stylesheet sanitation --- public/scripts/chats.js | 74 +++++++++++++++++++++++------------------ 1 file changed, 42 insertions(+), 32 deletions(-) diff --git a/public/scripts/chats.js b/public/scripts/chats.js index 84f316e63..7223ed27c 100644 --- a/public/scripts/chats.js +++ b/public/scripts/chats.js @@ -465,42 +465,52 @@ export function decodeStyleTags(text) { const styleDecodeRegex = /(.+?)<\/custom-style>/gms; const mediaAllowed = isExternalMediaAllowed(); + function sanitizeRule(rule) { + if (rule.selectors) { + for (let i = 0; i < rule.selectors.length; i++) { + let selector = rule.selectors[i]; + if (selector) { + let selectors = (selector.split(' ') ?? []).map((v) => { + if (v.startsWith('.')) { + return '.custom-' + v.substring(1); + } + return v; + }).join(' '); + + rule.selectors[i] = '.mes_text ' + selectors; + } + } + } + if (!mediaAllowed && Array.isArray(rule.declarations) && rule.declarations.length > 0) { + for (const declaration of rule.declarations) { + if (declaration.value.includes('://')) { + rule.declarations.splice(rule.declarations.indexOf(declaration), 1); + } + } + } + } + + function sanitizeRuleSet(ruleSet) { + if (ruleSet.type === 'rule') { + sanitizeRule(ruleSet); + } + + if (Array.isArray(ruleSet.rules)) { + ruleSet.rules = ruleSet.rules.filter(rule => rule.type !== 'import'); + + for (const mediaRule of ruleSet.rules) { + sanitizeRuleSet(mediaRule); + } + } + } + return text.replaceAll(styleDecodeRegex, (_, style) => { try { let styleCleaned = unescape(style).replaceAll(//g, ''); const ast = css.parse(styleCleaned); - const rules = ast?.stylesheet?.rules; - if (rules) { - for (const rule of rules) { - if (rule.type === 'import') { - rules.splice(rules.indexOf(rule), 1); - } - - if (rule.type === 'rule') { - if (rule.selectors) { - for (let i = 0; i < rule.selectors.length; i++) { - let selector = rule.selectors[i]; - if (selector) { - let selectors = (selector.split(' ') ?? []).map((v) => { - if (v.startsWith('.')) { - return '.custom-' + v.substring(1); - } - return v; - }).join(' '); - - rule.selectors[i] = '.mes_text ' + selectors; - } - } - } - if (!mediaAllowed && Array.isArray(rule.declarations) && rule.declarations.length > 0) { - for (const declaration of rule.declarations) { - if (declaration.value.includes('://')) { - rule.declarations.splice(rule.declarations.indexOf(declaration), 1); - } - } - } - } - } + const sheet = ast?.stylesheet; + if (sheet) { + sanitizeRuleSet(ast.stylesheet); } return ``; } catch (error) { From 66db820c9e6a66300499ca3fe46c934b7f9d4f8e Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Mon, 27 May 2024 19:55:55 +0300 Subject: [PATCH 4/4] Fix external style declaration filtering --- public/scripts/chats.js | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/public/scripts/chats.js b/public/scripts/chats.js index 7223ed27c..83352f644 100644 --- a/public/scripts/chats.js +++ b/public/scripts/chats.js @@ -466,11 +466,11 @@ export function decodeStyleTags(text) { const mediaAllowed = isExternalMediaAllowed(); function sanitizeRule(rule) { - if (rule.selectors) { + if (Array.isArray(rule.selectors)) { for (let i = 0; i < rule.selectors.length; i++) { - let selector = rule.selectors[i]; + const selector = rule.selectors[i]; if (selector) { - let selectors = (selector.split(' ') ?? []).map((v) => { + const selectors = (selector.split(' ') ?? []).map((v) => { if (v.startsWith('.')) { return '.custom-' + v.substring(1); } @@ -482,16 +482,12 @@ export function decodeStyleTags(text) { } } if (!mediaAllowed && Array.isArray(rule.declarations) && rule.declarations.length > 0) { - for (const declaration of rule.declarations) { - if (declaration.value.includes('://')) { - rule.declarations.splice(rule.declarations.indexOf(declaration), 1); - } - } + rule.declarations = rule.declarations.filter(declaration => !declaration.value.includes('://')); } } function sanitizeRuleSet(ruleSet) { - if (ruleSet.type === 'rule') { + if (Array.isArray(ruleSet.selectors) || Array.isArray(ruleSet.declarations)) { sanitizeRule(ruleSet); }