34 lines
1.1 KiB
TypeScript
34 lines
1.1 KiB
TypeScript
// Centralized text-to-HTML escaping. Use everywhere user-provided strings flow
|
|
// into an HTML context (emails, raw markup, etc). React's JSX rendering escapes
|
|
// by default; this is for the non-JSX paths.
|
|
|
|
const REPLACE: Record<string, string> = {
|
|
"&": "&",
|
|
"<": "<",
|
|
">": ">",
|
|
'"': """,
|
|
"'": "'",
|
|
};
|
|
|
|
export function escapeHtml(input: unknown): string {
|
|
if (input === null || input === undefined) return "";
|
|
return String(input).replace(/[&<>"']/g, (c) => REPLACE[c] ?? c);
|
|
}
|
|
|
|
// Strip everything that smells like markup. Use for places where the value
|
|
// should be plain text but might be rendered raw (mailer subject lines, etc.).
|
|
export function stripTags(input: unknown): string {
|
|
return String(input ?? "").replace(/<[^>]*>/g, "");
|
|
}
|
|
|
|
// Quick allowlist URL check — refuses anything that isn't http/https. Used on
|
|
// the redirect-after-submit setting and on webhook URLs.
|
|
export function isSafeUrl(url: string): boolean {
|
|
try {
|
|
const u = new URL(url);
|
|
return u.protocol === "http:" || u.protocol === "https:";
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|