phx-node
Version:
PHX NODE
63 lines • 2.72 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.PHXEmailRenderToHTML = exports.PHXAllowTags = void 0;
const liquidjs_1 = require("liquidjs");
const PHXAllowTags = (html) => {
const allowedTags = ["p", "b", "i", "a", "br", "img"];
const tagRegex = /<\/?([a-zA-Z0-9]+)(\s[^>]*)?>/g;
let match;
while ((match = tagRegex.exec(html)) !== null) {
const [fullMatch, tagName, attrs = ""] = match;
const lowerTag = tagName.toLowerCase();
if (fullMatch.startsWith("</"))
continue;
if (!allowedTags.includes(lowerTag)) {
throw new Error(`Tag <${lowerTag}> is not allowed`);
}
const cleanedAttrs = attrs.trim();
if (/class\s*=/i.test(cleanedAttrs)) {
throw new Error(`Tag <${lowerTag}> cannot have class attribute`);
}
if (/on[a-z]+\s*=/i.test(cleanedAttrs)) {
throw new Error(`Tag <${lowerTag}> contains forbidden event attribute`);
}
if (lowerTag !== "img" && /\bstyle\s*=/i.test(cleanedAttrs)) {
throw new Error(`Tag <${lowerTag}> cannot have style attribute`);
}
if (lowerTag === "a") {
const hrefMatch = cleanedAttrs === null || cleanedAttrs === void 0 ? void 0 : cleanedAttrs.match(/\bhref\s*=\s*(?:"[^"]*"|'[^']*'|[^\s>]+)/i);
if (!hrefMatch) {
throw new Error(`<a> tag must have valid href`);
}
}
if (lowerTag === "img") {
const cleanedAttrs = attrs === null || attrs === void 0 ? void 0 : attrs.trim();
const srcMatch = cleanedAttrs === null || cleanedAttrs === void 0 ? void 0 : cleanedAttrs.match(/\bsrc\s*=\s*(?:"[^"]*"|'[^']*'|[^\s>]+)/i);
if (!srcMatch) {
throw new Error(`<img> tag must have valid src`);
}
}
if (attrs && lowerTag !== "a" && lowerTag !== "img") {
const cleanedAttrs = attrs.trim();
if (cleanedAttrs) {
throw new Error(`Tag <${lowerTag}> should not have attributes`);
}
}
}
return html;
};
exports.PHXAllowTags = PHXAllowTags;
const PHXEmailRenderToHTML = (html, obj) => {
const htmlSanitize = (0, exports.PHXAllowTags)(html);
const validatedValue = {};
for (const [key, value] of Object.entries(obj)) {
validatedValue[key] = (0, exports.PHXAllowTags)(value);
}
const liquid = new liquidjs_1.Liquid({
strictVariables: true,
strictFilters: true,
});
return liquid.parseAndRenderSync(htmlSanitize, validatedValue);
};
exports.PHXEmailRenderToHTML = PHXEmailRenderToHTML;
//# sourceMappingURL=email-render-to-HTML.js.map