47 lines
1.6 KiB
TypeScript
47 lines
1.6 KiB
TypeScript
/**
|
|
* Zentral konfigurierter `marked`-Parser. Wichtig: deaktiviert das
|
|
* Rendern von **rohem HTML** in Markdown-Quellen — sonst kann ein
|
|
* Editor (oder ein kompromittiertes Editor-Konto) `<script>` oder
|
|
* `<iframe>`-Tags direkt einschleusen. Marked rendert sie standardmäßig
|
|
* wörtlich durch.
|
|
*
|
|
* `marked` ist Singleton: einmaliger Side-Effect-Import setzt die
|
|
* Renderer-Hooks global. Komponenten und Loader importieren `marked`
|
|
* von hier statt direkt von "marked".
|
|
*
|
|
* Komponenten, die `marked.parse(...)` aufrufen, sollten das Resultat
|
|
* weiterhin nur über `{@html}` einsetzen — der Sanitizer hier deckt das
|
|
* Markdown-→-HTML-Mapping ab. Roh-HTML-Felder (HtmlBlock) werden zusätzlich
|
|
* über `$lib/sanitize-blocks.server` gefiltert.
|
|
*/
|
|
import { marked } from 'marked';
|
|
|
|
let configured = false;
|
|
|
|
function configure() {
|
|
if (configured) return;
|
|
marked.setOptions({ gfm: true });
|
|
marked.use({
|
|
renderer: {
|
|
// Allow only <span style="..."> and </span> — strip all other raw HTML.
|
|
html(token: { text: string }) {
|
|
let s = token.text;
|
|
// Protect <span style="…"> (style value must not contain < or >)
|
|
s = s.replace(/<span\s+style="([^"<>]{0,400})"\s*>/gi, '\x00span:$1\x00');
|
|
s = s.replace(/<\/span>/gi, '\x00/span\x00');
|
|
// Strip all remaining HTML tags
|
|
s = s.replace(/<[^>]+>/g, '');
|
|
// Restore safe spans
|
|
s = s.replace(/\x00span:([^\x00]*)\x00/g, '<span style="$1">');
|
|
s = s.replace(/\x00\/span\x00/g, '</span>');
|
|
return s;
|
|
},
|
|
},
|
|
});
|
|
configured = true;
|
|
}
|
|
|
|
configure();
|
|
|
|
export { marked };
|