const sanitizeHtml = require('sanitize-html');
const { FONT_NAMES } = require('./fonts');
const OPTIONS = {
// b/i are included because execCommand('bold'/'italic') emits those in
// some browsers; transformTags normalizes them to the semantic tags.
allowedTags: ['strong', 'em', 'u', 'span', 'br', 'b', 'i'],
transformTags: {
b: 'strong',
i: 'em',
},
allowedAttributes: {
span: ['data-font'],
},
// Reject any span whose data-font isn't one of our curated fonts, instead
// of silently passing through an attacker-controlled string.
exclusiveFilter: (frame) => {
if (frame.tag === 'span') {
const font = frame.attribs && frame.attribs['data-font'];
return !font || !FONT_NAMES.includes(font);
}
return false;
},
disallowedTagsMode: 'discard',
};
/** Sanitizes rich-text HTML from the admin editor down to a small allowlist
* (bold/italic/underline + font-picker spans) before it's stored or rendered
* on the public site. Anything else - scripts, styles, links, attributes -
* is stripped, not escaped, so plain text content is preserved. */
function sanitizeRichText(html) {
if (typeof html !== 'string') return '';
return sanitizeHtml(html, OPTIONS).trim();
}
module.exports = { sanitizeRichText };