Skip to content

Commit

Permalink
cleanHtml use allowedTags instead of disallowedTags and improved CSS …
Browse files Browse the repository at this point in the history
…handling
  • Loading branch information
the-djmaze committed Sep 16, 2024
1 parent 05812c6 commit cfbc474
Showing 1 changed file with 60 additions and 25 deletions.
85 changes: 60 additions & 25 deletions dev/Common/Html.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,34 @@ const
"'": '''
},

disallowedTags = [
'svg','script','title','link','base','meta',
'input','output','select','button','textarea',
'bgsound','keygen','source','object','embed','applet','iframe','frame','frameset','video','audio','area','map'
// not supported by <template> element
// ,'html','head','body'
keepTagContent = 'form,button,data', // font

allowedTags = [
// Structural Elements:
'blockquote','br','div','figcaption','figure','h1','h2','h3','h4','h5','h6','hgroup','hr','p','wbr',
'article','aside','header','footer','main','section',
'details','summary',
// List Elements
'dd','dl','dt','li','ol','ul',
// Text Formatting Elements
'a','abbr','address','b','bdi','bdo','cite','code','del','dfn',
'em','i','ins','kbd','mark','pre','q','rp','rt','ruby','s','samp','small',
'span','strong','sub','sup','time','u','var',
// Deprecated by HTML Standard
'acronym','big','center','dir','font','marquee',
'nobr','noembed','noframes','plaintext','rb','rtc','strike','tt',
// Media Elements
'img',//'picture','source',
// Table Elements
'caption','col','colgroup','table','tbody','td','tfoot','th','thead','tr',
// Disallowed but converted later
'style','xmp'
].join(','),

nonEmptyTags = [
'A','B','EM','I','SPAN','STRONG'
],

blockquoteSwitcher = () => {
SettingsUserStore.collapseBlockquotes() &&
// tmpl.content.querySelectorAll('blockquote').forEach(node => {
Expand Down Expand Up @@ -102,8 +122,10 @@ const
},

cleanCSS = source =>
source.trim().replace(/(^|;)\s*-(ms|webkit)-[^;]+(;|$)/g, '')
.replace(/white-space[^;]+(;|$)/g, '')
source.trim()
.replace(/;\s*-[^;]+/g, '')
.replace(/^\s*-[^;]+(;|$)/g, '')
.replace(/white-space[^;]+/g, '')
// Drop Microsoft Office style properties
// .replace(/mso-[^:;]+:[^;]+/gi, '')
,
Expand Down Expand Up @@ -145,14 +167,14 @@ const
if (source) {
source = source
// strip comments
.replace(/\/\*[\s\S]*?\*\/|<!--|-->/gi, '')
// strip import statements
.replace(/@import .*?;/gi , '')
// strip keyframe statements
.replace(/((@.*?keyframes [\s\S]*?){([\s\S]*?}\s*?)})/gi, '');
.replace(/\/\*[\s\S]*?\*\//gi, '')
// strip MS Word comments
.replace(/<!--[\s\S]*?-->/gi, '');
// strip HTML
// .replace(/<\/?[a-z][\s\S]*?>/gi, '');

// unified regex to match css & media queries together
let unified = /((\s*?(?:\/\*[\s\S]*?\*\/)?\s*?@media[\s\S]*?){([\s\S]*?)}\s*?})|(([\s\S]*?){([\s\S]*?)})/gi,
let unified = /(?:(\s*?@(?:media)[\s\S]*?){([\s\S]*?)}\s*?})|(?:([\s\S]*?){([\s\S]*?)})/gi,
arr;

while (true) {
Expand All @@ -161,7 +183,7 @@ const
break;
}

let selector = arr[arr[2] === undefined ? 5 : 2].split('\r\n').join('\n').trim()
let selector = arr[arr[2] === undefined ? 3 : 1].split('\r\n').join('\n').trim()
// Never have more than a single line break in a row
.replace(/\n+/, "\n")
// Remove :root and html
Expand All @@ -173,13 +195,14 @@ const
css.push({
selector: selector,
type: 'media',
subStyles: parseCSS(arr[3] + '\n}') //recursively parse media query inner css
subStyles: parseCSS(arr[2] + '\n}') //recursively parse media query inner css
});
} else if (selector && !selector.includes('@')) {
// we have standard css
// ignores @import, @keyframe, @font-face statements
css.push({
selector: selector,
rules: cleanCSS(arr[6])
rules: cleanCSS(arr[4])
});
}
}
Expand Down Expand Up @@ -258,9 +281,6 @@ export const
'abbr', 'scope',
// td
'colspan', 'rowspan', 'headers'
],
nonEmptyTags = [
'A','B','EM','I','SPAN','STRONG'
];

if (SettingsUserStore.allowStyles()) {
Expand Down Expand Up @@ -307,13 +327,21 @@ export const
}
});

// https://github.com/the-djmaze/snappymail/issues/1125
tmpl.content.querySelectorAll(keepTagContent).forEach(oElement => replaceWithChildren(oElement));

tmpl.content.querySelectorAll(
disallowedTags
':not('+allowedTags+')'
+ (0 < bqLevel ? ',' + (new Array(1 + bqLevel).fill('blockquote').join(' ')) : '')
).forEach(oElement => oElement.remove());

// https://github.com/the-djmaze/snappymail/issues/1125
tmpl.content.querySelectorAll('form,button').forEach(oElement => replaceWithChildren(oElement));
/* // Is this slower or faster?
).forEach(oElement => {
if (!node || !node.contains(oElement)) {
oElement.remove();
node = oElement;
}
});
*/

// https://github.com/the-djmaze/snappymail/issues/1641
let body = tmpl.content.querySelector('.mail-body');
Expand Down Expand Up @@ -346,6 +374,13 @@ export const
return;
}

if ('XMP' === name) {
const pre = createElement('pre');
pre.innerHTML = encodeHtml(oElement.innerHTML);
oElement.replaceWith(pre);
return;
}

// \MailSo\Base\HtmlUtils::ClearTags()
if ('none' == oStyle.display
|| 'hidden' == oStyle.visibility
Expand Down Expand Up @@ -432,7 +467,7 @@ export const
}

// if (['CENTER','FORM'].includes(name)) {
if ('O:P' === name || (nonEmptyTags.includes(name) && ('' == oElement.textContent.trim()))) {
if (nonEmptyTags.includes(name) && ('' == oElement.textContent.trim())) {
('A' !== name || !oElement.querySelector('IMG')) && replaceWithChildren(oElement);
return;
}
Expand Down

0 comments on commit cfbc474

Please sign in to comment.