UNPKG

@ordojs/security

Version:

Security package for OrdoJS with XSS, CSRF, and injection protection

113 lines 3.4 kB
/** * Escape special HTML characters to prevent XSS attacks in template interpolations */ /** * Map of characters that need to be escaped in HTML */ const HTML_ESCAPE_MAP = { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;', '/': '&#x2F;', '`': '&#x60;', '=': '&#x3D;', }; /** * Regular expression to match characters that need to be escaped */ const HTML_ESCAPE_REGEX = /[&<>"'`=\/]/g; /** * Escape HTML special characters to prevent XSS attacks * @param value String value to escape * @returns Escaped HTML string */ export function escapeHtml(value) { return String(value).replace(HTML_ESCAPE_REGEX, (char) => HTML_ESCAPE_MAP[char] || char); } /** * Template escaper for automatic HTML escaping in template interpolations */ export class TemplateEscaper { options; /** * Create a new TemplateEscaper instance * @param options Template escaper options */ constructor(options = {}) { this.options = { escapeByDefault: true, allowRawHtml: false, ...options, }; } /** * Escape a value for safe HTML interpolation * @param value Value to escape * @returns Escaped value */ escape(value) { if (value === null || value === undefined) { return ''; } if (typeof value === 'object') { return escapeHtml(JSON.stringify(value)); } return escapeHtml(String(value)); } /** * Create a tagged template function that automatically escapes interpolated values * @returns Tagged template function */ createEscapedTemplate() { return (strings, ...values) => { let result = ''; for (let i = 0; i < strings.length; i++) { result += strings[i]; if (i < values.length) { result += this.escape(values[i]); } } return result; }; } /** * Create a tagged template function that allows raw HTML (use with caution) * @returns Tagged template function for raw HTML * @throws Error if raw HTML is not allowed in options */ createRawTemplate() { if (!this.options.allowRawHtml) { throw new Error('Raw HTML templates are not allowed. Set allowRawHtml: true in options to enable.'); } return (strings, ...values) => { let result = ''; for (let i = 0; i < strings.length; i++) { result += strings[i]; if (i < values.length) { result += String(values[i]); } } return result; }; } } /** * Default template escaper instance */ export const defaultTemplateEscaper = new TemplateEscaper(); /** * Tagged template function that automatically escapes interpolated values * @example html\`<div>\${userInput}</div>\` // userInput is automatically escaped */ export const html = defaultTemplateEscaper.createEscapedTemplate(); /** * Create a raw HTML tagged template (use with caution) * Must be explicitly enabled by setting allowRawHtml: true */ export function createRawHtmlTemplate() { const escaper = new TemplateEscaper({ allowRawHtml: true }); return escaper.createRawTemplate(); } //# sourceMappingURL=template-escaper.js.map