Spaces:
Sleeping
Sleeping
File size: 2,957 Bytes
cb43fbd | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 | import DOMPurify from 'isomorphic-dompurify';
/**
* HTML sanitisation for TREK.
*
* TREK currently has no rich-text editor and no user-provided HTML reaches
* the database, so this module exists only to guard the handful of client
* sites that interpolate user-controlled strings into a markup template
* (today: the Journey suggestion banner). It is also the future home for
* sanitisation if TipTap / Markdown ever ships.
*
* Why isomorphic-dompurify: works unchanged in browser (DOMPurify) and Node
* (DOMPurify + jsdom). Tree-shakes correctly so the client bundle does not
* pull jsdom.
*/
// Inline-only tags. Block-level markup (paragraphs, lists, headings) is not
// expected in the surfaces we render today, so we keep the allow-list minimal
// and rely on `sanitizeRichTextHtml` when a richer surface needs full prose.
const INLINE_TAGS = [
'b',
'strong',
'i',
'em',
'u',
's',
'del',
'ins',
'mark',
'code',
'sub',
'sup',
'br',
'span',
] as const;
const FULL_TAGS = [
...INLINE_TAGS,
'p',
'div',
'ul',
'ol',
'li',
'h1',
'h2',
'h3',
'h4',
'h5',
'h6',
'blockquote',
'pre',
'hr',
'a',
] as const;
const SAFE_ATTRIBUTES = ['href', 'rel', 'target'] as const;
/**
* Escapes the five HTML metacharacters so a raw string can be safely
* interpolated into an HTML template. Use this BEFORE substitution when a
* user-controlled value lands inside a markup-shaped translation string.
*
* This is *not* a substitute for `sanitizeInlineHtml`: escape input, then
* sanitise the resulting template — both layers run together in `tHtml`.
*/
export function escapeHtml(value: string): string {
return value
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
/**
* Strict inline sanitiser. Use for short, mostly-text strings that may include
* basic emphasis (`<strong>`, `<em>`, …) — e.g. the Journey suggestion banner
* where a translated template embeds a user-controlled trip title.
*
* Drops every tag outside the inline allow-list, strips all attributes, and
* blocks every URL scheme except http/https/mailto/tel via DOMPurify's
* built-in URL allow-list.
*/
export function sanitizeInlineHtml(html: string): string {
if (!html) return '';
return DOMPurify.sanitize(html, {
ALLOWED_TAGS: [...INLINE_TAGS],
ALLOWED_ATTR: [],
KEEP_CONTENT: true,
ALLOW_DATA_ATTR: false,
});
}
/**
* Permissive rich-text sanitiser. Use when a surface legitimately renders a
* prose document (lists, paragraphs, links). Keeps the same tag families as
* the inline sanitiser plus block-level markup and anchors with safe attrs.
*/
export function sanitizeRichTextHtml(html: string): string {
if (!html) return '';
return DOMPurify.sanitize(html, {
ALLOWED_TAGS: [...FULL_TAGS],
ALLOWED_ATTR: [...SAFE_ATTRIBUTES],
ALLOW_DATA_ATTR: false,
});
}
|