UNPKG

next-csrf

Version:

CSRF mitigation library for Next.js

195 lines (194 loc) 5.62 kB
"use strict"; var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; result["default"] = mod; return result; }; Object.defineProperty(exports, "__esModule", { value: true }); /* Module dependencies */ var ElementType = __importStar(require("domelementtype")); var entities = __importStar(require("entities")); /* mixed-case SVG and MathML tags & attributes recognized by the HTML parser, see https://html.spec.whatwg.org/multipage/parsing.html#parsing-main-inforeign */ var foreignNames_1 = require("./foreignNames"); var unencodedElements = new Set([ "style", "script", "xmp", "iframe", "noembed", "noframes", "plaintext", "noscript", ]); /* Format attributes */ function formatAttributes(attributes, opts) { if (!attributes) return; return Object.keys(attributes) .map(function (key) { var _a; var value = attributes[key]; if (opts.xmlMode === "foreign") { /* fix up mixed-case attribute names */ key = (_a = foreignNames_1.attributeNames.get(key)) !== null && _a !== void 0 ? _a : key; } if (!opts.emptyAttrs && !opts.xmlMode && (value === null || value === "")) { return key; } return key + "=\"" + (opts.decodeEntities ? entities.encodeXML(value) : value.replace(/"/g, "&quot;")) + "\""; }) .join(" "); } /* Self-enclosing tags */ var singleTag = new Set([ "area", "base", "basefont", "br", "col", "command", "embed", "frame", "hr", "img", "input", "isindex", "keygen", "link", "meta", "param", "source", "track", "wbr", ]); /** * Renders a DOM node or an array of DOM nodes to a string. * * Can be thought of as the equivalent of the `outerHTML` of the passed node(s). * * @param node Node to be rendered. * @param options Changes serialization behavior */ function render(node, options) { if (options === void 0) { options = {}; } // TODO: This is a bit hacky. var nodes = Array.isArray(node) || node.cheerio ? node : [node]; var output = ""; for (var i = 0; i < nodes.length; i++) { output += renderNode(nodes[i], options); } return output; } exports.default = render; function renderNode(node, options) { switch (node.type) { case "root": return render(node.children, options); case ElementType.Directive: return renderDirective(node); case ElementType.Comment: return renderComment(node); case ElementType.CDATA: return renderCdata(node); default: return ElementType.isTag(node) ? renderTag(node, options) : renderText(node, options); } } var foreignModeIntegrationPoints = new Set([ "mi", "mo", "mn", "ms", "mtext", "annotation-xml", "foreignObject", "desc", "title", ]); var foreignElements = new Set(["svg", "math"]); function renderTag(elem, opts) { var _a; // Handle SVG / MathML in HTML if (opts.xmlMode === "foreign") { /* fix up mixed-case element names */ elem.name = (_a = foreignNames_1.elementNames.get(elem.name)) !== null && _a !== void 0 ? _a : elem.name; /* exit foreign mode at integration points */ if (elem.parent && foreignModeIntegrationPoints.has(elem.parent.name)) opts = __assign(__assign({}, opts), { xmlMode: false }); } if (!opts.xmlMode && foreignElements.has(elem.name)) { opts = __assign(__assign({}, opts), { xmlMode: "foreign" }); } var tag = "<" + elem.name; var attribs = formatAttributes(elem.attribs, opts); if (attribs) { tag += " " + attribs; } if ((!elem.children || elem.children.length === 0) && (opts.xmlMode ? // in XML mode or foreign mode, and user hasn't explicitly turned off self-closing tags opts.selfClosingTags !== false : // user explicitly asked for self-closing tags, even in HTML mode opts.selfClosingTags && singleTag.has(elem.name))) { if (!opts.xmlMode) tag += " "; tag += "/>"; } else { tag += ">"; if (elem.children) { tag += render(elem.children, opts); } if (opts.xmlMode || !singleTag.has(elem.name)) { tag += "</" + elem.name + ">"; } } return tag; } function renderDirective(elem) { return "<" + elem.data + ">"; } function renderText(elem, opts) { var data = elem.data || ""; // if entities weren't decoded, no need to encode them back if (opts.decodeEntities && !(elem.parent && unencodedElements.has(elem.parent.name))) { data = entities.encodeXML(data); } return data; } function renderCdata(elem) { return "<![CDATA[" + elem.children[0].data + "]]>"; } function renderComment(elem) { return "<!--" + elem.data + "-->"; }