@render-policy/core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +23 -0
- package/dist/binding.d.ts +28 -0
- package/dist/binding.d.ts.map +1 -0
- package/dist/binding.js +32 -0
- package/dist/binding.js.map +1 -0
- package/dist/data/sink-domains.d.ts +14 -0
- package/dist/data/sink-domains.d.ts.map +1 -0
- package/dist/data/sink-domains.js +91 -0
- package/dist/data/sink-domains.js.map +1 -0
- package/dist/decisions.d.ts +22 -0
- package/dist/decisions.d.ts.map +1 -0
- package/dist/decisions.js +2 -0
- package/dist/decisions.js.map +1 -0
- package/dist/dom.d.ts +13 -0
- package/dist/dom.d.ts.map +1 -0
- package/dist/dom.js +25 -0
- package/dist/dom.js.map +1 -0
- package/dist/errors.d.ts +3 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +5 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/internal.d.ts +12 -0
- package/dist/internal.d.ts.map +1 -0
- package/dist/internal.js +10 -0
- package/dist/internal.js.map +1 -0
- package/dist/markdown.d.ts +15 -0
- package/dist/markdown.d.ts.map +1 -0
- package/dist/markdown.js +15 -0
- package/dist/markdown.js.map +1 -0
- package/dist/policy.d.ts +141 -0
- package/dist/policy.d.ts.map +1 -0
- package/dist/policy.js +110 -0
- package/dist/policy.js.map +1 -0
- package/dist/render.d.ts +79 -0
- package/dist/render.d.ts.map +1 -0
- package/dist/render.js +130 -0
- package/dist/render.js.map +1 -0
- package/dist/sanitize.d.ts +17 -0
- package/dist/sanitize.d.ts.map +1 -0
- package/dist/sanitize.js +321 -0
- package/dist/sanitize.js.map +1 -0
- package/dist/sinks.d.ts +16 -0
- package/dist/sinks.d.ts.map +1 -0
- package/dist/sinks.js +24 -0
- package/dist/sinks.js.map +1 -0
- package/dist/stream.d.ts +57 -0
- package/dist/stream.d.ts.map +1 -0
- package/dist/stream.js +180 -0
- package/dist/stream.js.map +1 -0
- package/dist/url.d.ts +48 -0
- package/dist/url.d.ts.map +1 -0
- package/dist/url.js +105 -0
- package/dist/url.js.map +1 -0
- package/dist/window.d.ts +15 -0
- package/dist/window.d.ts.map +1 -0
- package/dist/window.js +9 -0
- package/dist/window.js.map +1 -0
- package/package.json +62 -0
package/dist/policy.js
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A RenderPolicy is the single place where an application decides what
|
|
3
|
+
* agent-generated content may do once it reaches the DOM.
|
|
4
|
+
*
|
|
5
|
+
* Sanitization (no scripts, no event handlers, no unknown elements) is not
|
|
6
|
+
* negotiable and is not part of the policy. The policy covers what a
|
|
7
|
+
* sanitizer alone cannot decide for you, grouped into three concerns:
|
|
8
|
+
*
|
|
9
|
+
* - `content`: which elements, attributes and classes agent output may carry.
|
|
10
|
+
* - `urls`: which URLs any attribute may point at (schemes, sink hosts, encoded
|
|
11
|
+
* payloads, and an application hook that decides or rewrites each one).
|
|
12
|
+
* - `images`: what happens to the image requests those URLs would make, which
|
|
13
|
+
* fire without a click (host allowlist, query strings, proxy rewrite, placeholder).
|
|
14
|
+
*/
|
|
15
|
+
export const DEFAULT_URL_HEURISTICS = Object.freeze({
|
|
16
|
+
maxLength: 2048,
|
|
17
|
+
maxTokenLength: 64,
|
|
18
|
+
minEntropy: 4,
|
|
19
|
+
});
|
|
20
|
+
/** Content rules are identical in every mode; modes differ only in their URL and image posture. */
|
|
21
|
+
const CONTENT = Object.freeze({
|
|
22
|
+
allowImages: true,
|
|
23
|
+
allowForms: false,
|
|
24
|
+
allowSvg: false,
|
|
25
|
+
allowMedia: false,
|
|
26
|
+
allowInlineStyles: false,
|
|
27
|
+
allowDataAttributes: false,
|
|
28
|
+
allowTargetBlank: true,
|
|
29
|
+
allowedClassPatterns: Object.freeze([/^language-[\w+#.-]+$/, /^rp-[\w-]+$/]),
|
|
30
|
+
forbidTags: Object.freeze([]),
|
|
31
|
+
forbidAttributes: Object.freeze([]),
|
|
32
|
+
});
|
|
33
|
+
const URLS_COMMON = { allowedSchemes: Object.freeze(['http', 'https', 'mailto', 'tel']), allowRelativeUrls: true, decide: null };
|
|
34
|
+
const IMAGES_COMMON = { allowWildcardHosts: false, rewriteUrl: null, blocked: 'placeholder' };
|
|
35
|
+
/**
|
|
36
|
+
* Mode presets.
|
|
37
|
+
*
|
|
38
|
+
* - strict: no remote images at all; sink hosts blocked; heuristics on.
|
|
39
|
+
* - balanced: remote images only from the allowlist, query strings stripped; sink hosts blocked; heuristics on.
|
|
40
|
+
* - permissive: every host allowed, nothing rewritten; sink hosts and nothing else are only logged.
|
|
41
|
+
*
|
|
42
|
+
* Sanitization is identical in all three modes. Permissive is still XSS-safe; it just stops
|
|
43
|
+
* making decisions about where data may flow.
|
|
44
|
+
*/
|
|
45
|
+
export const MODE_PRESETS = Object.freeze({
|
|
46
|
+
strict: Object.freeze({
|
|
47
|
+
mode: 'strict',
|
|
48
|
+
content: CONTENT,
|
|
49
|
+
urls: Object.freeze({ ...URLS_COMMON, heuristics: DEFAULT_URL_HEURISTICS, sinkDenylist: 'block' }),
|
|
50
|
+
images: Object.freeze({ ...IMAGES_COMMON, hosts: 'none', query: 'strip' }),
|
|
51
|
+
}),
|
|
52
|
+
balanced: Object.freeze({
|
|
53
|
+
mode: 'balanced',
|
|
54
|
+
content: CONTENT,
|
|
55
|
+
urls: Object.freeze({ ...URLS_COMMON, heuristics: DEFAULT_URL_HEURISTICS, sinkDenylist: 'block' }),
|
|
56
|
+
images: Object.freeze({ ...IMAGES_COMMON, hosts: Object.freeze([]), query: 'strip' }),
|
|
57
|
+
}),
|
|
58
|
+
permissive: Object.freeze({
|
|
59
|
+
mode: 'permissive',
|
|
60
|
+
content: CONTENT,
|
|
61
|
+
urls: Object.freeze({ ...URLS_COMMON, heuristics: false, sinkDenylist: 'log' }),
|
|
62
|
+
images: Object.freeze({ ...IMAGES_COMMON, hosts: 'any', query: 'keep' }),
|
|
63
|
+
}),
|
|
64
|
+
});
|
|
65
|
+
export const DEFAULT_MODE = 'balanced';
|
|
66
|
+
/**
|
|
67
|
+
* Build a policy from a mode preset plus explicit overrides. Each group is merged on top of the
|
|
68
|
+
* preset, so an override names only the fields it changes. Throws on configurations that silently
|
|
69
|
+
* widen exposure (wildcard hosts without opting in).
|
|
70
|
+
*/
|
|
71
|
+
export function resolvePolicy(mode = DEFAULT_MODE, overrides = {}) {
|
|
72
|
+
const preset = MODE_PRESETS[mode];
|
|
73
|
+
if (!preset) {
|
|
74
|
+
throw new Error(`@render-policy/core: unknown mode "${String(mode)}"`);
|
|
75
|
+
}
|
|
76
|
+
const policy = {
|
|
77
|
+
mode,
|
|
78
|
+
content: { ...preset.content, ...stripUndefined(overrides.content ?? {}) },
|
|
79
|
+
urls: { ...preset.urls, ...stripUndefined(overrides.urls ?? {}) },
|
|
80
|
+
images: { ...preset.images, ...stripUndefined(overrides.images ?? {}) },
|
|
81
|
+
};
|
|
82
|
+
if (Array.isArray(policy.images.hosts) && !policy.images.allowWildcardHosts) {
|
|
83
|
+
const wildcard = policy.images.hosts.find((h) => h.includes('*'));
|
|
84
|
+
if (wildcard) {
|
|
85
|
+
throw new Error(`@render-policy/core: images.hosts contains the wildcard pattern "${wildcard}" but images.allowWildcardHosts is false. ` +
|
|
86
|
+
'List exact hosts, or set images.allowWildcardHosts: true deliberately.');
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
for (const scheme of policy.urls.allowedSchemes) {
|
|
90
|
+
if (scheme !== scheme.toLowerCase() || scheme.endsWith(':')) {
|
|
91
|
+
throw new Error(`@render-policy/core: urls.allowedSchemes entries must be lower-case and without the colon (got "${scheme}")`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
for (const pattern of policy.content.allowedClassPatterns) {
|
|
95
|
+
if (pattern.global || pattern.sticky) {
|
|
96
|
+
throw new Error(`@render-policy/core: content.allowedClassPatterns must not use the g or y flags (got ${String(pattern)})`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return policy;
|
|
100
|
+
}
|
|
101
|
+
function stripUndefined(value) {
|
|
102
|
+
const out = {};
|
|
103
|
+
for (const key of Object.keys(value)) {
|
|
104
|
+
if (value[key] !== undefined) {
|
|
105
|
+
out[key] = value[key];
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return out;
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy.js","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"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"}
|
package/dist/render.d.ts
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { TrustedHTML } from 'trusted-types/lib/index.js';
|
|
2
|
+
import type { RenderDecision } from './decisions.js';
|
|
3
|
+
import { type MarkdownRenderer } from './markdown.js';
|
|
4
|
+
import { type RenderMode, type RenderPolicy, type RenderPolicyOverrides } from './policy.js';
|
|
5
|
+
import type { SinkDenylist } from './sinks.js';
|
|
6
|
+
import { type RenderStream, type StreamOptions } from './stream.js';
|
|
7
|
+
import { type RenderWindow } from './window.js';
|
|
8
|
+
/** Where rendered content goes: an element, a shadow root or a fragment. Never a whole document. */
|
|
9
|
+
export type RenderTarget = Element | DocumentFragment;
|
|
10
|
+
export interface RenderResult {
|
|
11
|
+
readonly decisions: readonly RenderDecision[];
|
|
12
|
+
}
|
|
13
|
+
/** What a render knows about itself. Transforms receive it, with the document added. */
|
|
14
|
+
export interface RenderContext {
|
|
15
|
+
/** True while a stream renders, intermediate or final. Default false. */
|
|
16
|
+
readonly streaming: boolean;
|
|
17
|
+
/** True for a one-shot render or the final render of a stream. Default true. */
|
|
18
|
+
readonly final: boolean;
|
|
19
|
+
/** True when the source ended inside a code fence that the stream closed for display. Default false. */
|
|
20
|
+
readonly openFenceAtEnd: boolean;
|
|
21
|
+
}
|
|
22
|
+
export interface RenderOptions extends Partial<RenderContext> {
|
|
23
|
+
/**
|
|
24
|
+
* Keep the leading child nodes of the target that are unchanged and replace only
|
|
25
|
+
* from the first difference. Used by streams; a one-shot render replaces everything.
|
|
26
|
+
*/
|
|
27
|
+
readonly patch?: boolean;
|
|
28
|
+
}
|
|
29
|
+
export interface TransformContext extends RenderContext {
|
|
30
|
+
/** The document to create nodes in. The fragment itself may belong to the parser's document. */
|
|
31
|
+
readonly document: Document;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Post-processes a sanitized fragment before insertion: diagrams, syntax highlighting,
|
|
35
|
+
* link decorations. A transform runs on already-sanitized content and is trusted code;
|
|
36
|
+
* whatever it adds is inserted as is. A transform that throws is skipped and journaled;
|
|
37
|
+
* the fragment is inserted without its work.
|
|
38
|
+
*/
|
|
39
|
+
export type FragmentTransform = (fragment: DocumentFragment, context: TransformContext) => void;
|
|
40
|
+
export interface FragmentResult extends RenderResult {
|
|
41
|
+
readonly fragment: DocumentFragment;
|
|
42
|
+
}
|
|
43
|
+
export interface RendererOptions {
|
|
44
|
+
/** The window to render with. Defaults to the global window; pass a JSDOM window in tests. */
|
|
45
|
+
readonly window?: RenderWindow;
|
|
46
|
+
/** Policy preset. Default 'balanced'. */
|
|
47
|
+
readonly mode?: RenderMode;
|
|
48
|
+
/** Overrides applied on top of the preset. Each group (`content`, `urls`, `images`) is merged. */
|
|
49
|
+
readonly policy?: RenderPolicyOverrides;
|
|
50
|
+
/** Replace the bundled sink denylist. */
|
|
51
|
+
readonly sinkDenylist?: SinkDenylist;
|
|
52
|
+
/** Replace the Markdown renderer. Its output is sanitized regardless. */
|
|
53
|
+
readonly markdown?: MarkdownRenderer;
|
|
54
|
+
/** Receive every policy decision as it is made. */
|
|
55
|
+
readonly onDecision?: (decision: RenderDecision) => void;
|
|
56
|
+
/** Post-processors applied to every sanitized fragment before insertion, in order. */
|
|
57
|
+
readonly transforms?: readonly FragmentTransform[];
|
|
58
|
+
}
|
|
59
|
+
export interface Renderer {
|
|
60
|
+
readonly policy: RenderPolicy;
|
|
61
|
+
/** Sanitize HTML into an inert fragment without touching any live DOM. */
|
|
62
|
+
sanitizeHtml(html: string, options?: RenderOptions): FragmentResult;
|
|
63
|
+
/** Convert Markdown and sanitize into an inert fragment. */
|
|
64
|
+
markdownToFragment(markdown: string, options?: RenderOptions): FragmentResult;
|
|
65
|
+
/** Sanitize and insert with replaceChildren(). innerHTML is never used. */
|
|
66
|
+
renderHtmlInto(target: RenderTarget, html: string, options?: RenderOptions): RenderResult;
|
|
67
|
+
/** Convert Markdown, sanitize and insert with replaceChildren(). Falls back to plain text if the Markdown step throws. */
|
|
68
|
+
renderMarkdownInto(target: RenderTarget, markdown: string, options?: RenderOptions): RenderResult;
|
|
69
|
+
/** Insert plain text. Never interpreted as markup. */
|
|
70
|
+
renderTextInto(target: RenderTarget, text: string): void;
|
|
71
|
+
/** Escape hatch for string sinks you cannot remove: sanitized HTML as a TrustedHTML where the API exists, else a string. */
|
|
72
|
+
trustedHTML(html: string): TrustedHTML | string;
|
|
73
|
+
/** Same as trustedHTML, from Markdown. */
|
|
74
|
+
markdownToTrustedHTML(markdown: string): TrustedHTML | string;
|
|
75
|
+
/** Incremental rendering for streamed model output. */
|
|
76
|
+
createStream(target: RenderTarget, options?: StreamOptions): RenderStream;
|
|
77
|
+
}
|
|
78
|
+
export declare function createRenderer(options?: RendererOptions): Renderer;
|
|
79
|
+
//# sourceMappingURL=render.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAE9D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAGrD,OAAO,EAA0B,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAC9E,OAAO,EAAiB,KAAK,UAAU,EAAE,KAAK,YAAY,EAAE,KAAK,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAE5G,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAsB,KAAK,YAAY,EAAE,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AACxF,OAAO,EAAiB,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAE/D,oGAAoG;AACpG,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,gBAAgB,CAAC;AAEtD,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,SAAS,EAAE,SAAS,cAAc,EAAE,CAAC;CAC/C;AAED,wFAAwF;AACxF,MAAM,WAAW,aAAa;IAC5B,yEAAyE;IACzE,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,gFAAgF;IAChF,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,wGAAwG;IACxG,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;CAClC;AAED,MAAM,WAAW,aAAc,SAAQ,OAAO,CAAC,aAAa,CAAC;IAC3D;;;OAGG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,gBAAiB,SAAQ,aAAa;IACrD,gGAAgG;IAChG,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;CAC7B;AAED;;;;;GAKG;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,QAAQ,EAAE,gBAAgB,EAAE,OAAO,EAAE,gBAAgB,KAAK,IAAI,CAAC;AAEhG,MAAM,WAAW,cAAe,SAAQ,YAAY;IAClD,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC;CACrC;AAED,MAAM,WAAW,eAAe;IAC9B,8FAA8F;IAC9F,QAAQ,CAAC,MAAM,CAAC,EAAE,YAAY,CAAC;IAC/B,yCAAyC;IACzC,QAAQ,CAAC,IAAI,CAAC,EAAE,UAAU,CAAC;IAC3B,kGAAkG;IAClG,QAAQ,CAAC,MAAM,CAAC,EAAE,qBAAqB,CAAC;IACxC,yCAAyC;IACzC,QAAQ,CAAC,YAAY,CAAC,EAAE,YAAY,CAAC;IACrC,yEAAyE;IACzE,QAAQ,CAAC,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IACrC,mDAAmD;IACnD,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,cAAc,KAAK,IAAI,CAAC;IACzD,sFAAsF;IACtF,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,iBAAiB,EAAE,CAAC;CACpD;AAED,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,0EAA0E;IAC1E,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,cAAc,CAAC;IACpE,4DAA4D;IAC5D,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,cAAc,CAAC;IAC9E,2EAA2E;IAC3E,cAAc,CAAC,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,YAAY,CAAC;IAC1F,0HAA0H;IAC1H,kBAAkB,CAAC,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,YAAY,CAAC;IAClG,sDAAsD;IACtD,cAAc,CAAC,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACzD,4HAA4H;IAC5H,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,MAAM,CAAC;IAChD,0CAA0C;IAC1C,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,GAAG,MAAM,CAAC;IAC9D,uDAAuD;IACvD,YAAY,CAAC,MAAM,EAAE,YAAY,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,YAAY,CAAC;CAC3E;AASD,wBAAgB,cAAc,CAAC,OAAO,GAAE,eAAoB,GAAG,QAAQ,CAqHtE"}
|
package/dist/render.js
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { SINK_DENYLIST } from './data/sink-domains.js';
|
|
2
|
+
import { patchChildren } from './dom.js';
|
|
3
|
+
import { messageOf } from './errors.js';
|
|
4
|
+
import { createMarkdownRenderer } from './markdown.js';
|
|
5
|
+
import { resolvePolicy } from './policy.js';
|
|
6
|
+
import { createSanitizer } from './sanitize.js';
|
|
7
|
+
import { createRenderStream } from './stream.js';
|
|
8
|
+
import { resolveWindow } from './window.js';
|
|
9
|
+
const MARKDOWN_FAILED = Object.freeze({
|
|
10
|
+
kind: 'blocked',
|
|
11
|
+
subject: 'markdown',
|
|
12
|
+
code: 'markdown-failed',
|
|
13
|
+
reason: 'the Markdown renderer threw; the input was rendered as plain text',
|
|
14
|
+
});
|
|
15
|
+
export function createRenderer(options = {}) {
|
|
16
|
+
const win = resolveWindow(options.window);
|
|
17
|
+
const policy = resolvePolicy(options.mode, options.policy);
|
|
18
|
+
const sanitizer = createSanitizer(win, policy, options.sinkDenylist ?? SINK_DENYLIST);
|
|
19
|
+
const markdown = options.markdown ?? createMarkdownRenderer();
|
|
20
|
+
const onDecision = options.onDecision;
|
|
21
|
+
const transforms = options.transforms ?? [];
|
|
22
|
+
/** Run the transforms; a transform that throws is skipped and reported, the others still run. */
|
|
23
|
+
const applyTransforms = (fragment, options) => {
|
|
24
|
+
if (transforms.length === 0)
|
|
25
|
+
return [];
|
|
26
|
+
const context = {
|
|
27
|
+
streaming: options?.streaming ?? false,
|
|
28
|
+
final: options?.final ?? true,
|
|
29
|
+
openFenceAtEnd: options?.openFenceAtEnd ?? false,
|
|
30
|
+
// The fragment belongs to the sanitizer's parser document; transforms create nodes in the live one.
|
|
31
|
+
document: win.document,
|
|
32
|
+
};
|
|
33
|
+
const failures = [];
|
|
34
|
+
for (const transform of transforms) {
|
|
35
|
+
try {
|
|
36
|
+
transform(fragment, context);
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
failures.push({ kind: 'flagged', subject: 'transform', code: 'transform-failed', reason: `a transform threw and was skipped: ${messageOf(error)}` });
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return failures;
|
|
43
|
+
};
|
|
44
|
+
const emit = (decisions) => {
|
|
45
|
+
if (!onDecision)
|
|
46
|
+
return;
|
|
47
|
+
for (const decision of decisions)
|
|
48
|
+
onDecision(decision);
|
|
49
|
+
};
|
|
50
|
+
const toHtml = (source) => {
|
|
51
|
+
try {
|
|
52
|
+
return { html: markdown(source) };
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return { failed: true };
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
const documentOf = (target) => target.ownerDocument ?? win.document;
|
|
59
|
+
const renderTextInto = (target, text) => {
|
|
60
|
+
target.replaceChildren(documentOf(target).createTextNode(text));
|
|
61
|
+
};
|
|
62
|
+
const sanitizeHtml = (html, options) => {
|
|
63
|
+
const { output, decisions: sanitized } = sanitizer.toFragment(html);
|
|
64
|
+
const failures = applyTransforms(output, options);
|
|
65
|
+
const decisions = failures.length === 0 ? sanitized : [...sanitized, ...failures];
|
|
66
|
+
emit(decisions);
|
|
67
|
+
return { fragment: output, decisions };
|
|
68
|
+
};
|
|
69
|
+
const markdownToFragment = (source, options) => {
|
|
70
|
+
const converted = toHtml(source);
|
|
71
|
+
if ('failed' in converted) {
|
|
72
|
+
const fragment = win.document.createDocumentFragment();
|
|
73
|
+
fragment.append(source);
|
|
74
|
+
emit([MARKDOWN_FAILED]);
|
|
75
|
+
return { fragment, decisions: [MARKDOWN_FAILED] };
|
|
76
|
+
}
|
|
77
|
+
return sanitizeHtml(converted.html, options);
|
|
78
|
+
};
|
|
79
|
+
const insert = (target, fragment, options) => {
|
|
80
|
+
if (options?.patch) {
|
|
81
|
+
patchChildren(target, fragment);
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
target.replaceChildren(fragment);
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
const renderHtmlInto = (target, html, options) => {
|
|
88
|
+
const { fragment, decisions } = sanitizeHtml(html, options);
|
|
89
|
+
insert(target, fragment, options);
|
|
90
|
+
return { decisions };
|
|
91
|
+
};
|
|
92
|
+
const renderMarkdownInto = (target, source, options) => {
|
|
93
|
+
const converted = toHtml(source);
|
|
94
|
+
if ('failed' in converted) {
|
|
95
|
+
renderTextInto(target, source);
|
|
96
|
+
emit([MARKDOWN_FAILED]);
|
|
97
|
+
return { decisions: [MARKDOWN_FAILED] };
|
|
98
|
+
}
|
|
99
|
+
return renderHtmlInto(target, converted.html, options);
|
|
100
|
+
};
|
|
101
|
+
const trustedHTML = (html) => {
|
|
102
|
+
const { output, decisions } = sanitizer.toTrustedHTML(html);
|
|
103
|
+
emit(decisions);
|
|
104
|
+
return output;
|
|
105
|
+
};
|
|
106
|
+
return {
|
|
107
|
+
policy,
|
|
108
|
+
sanitizeHtml,
|
|
109
|
+
markdownToFragment,
|
|
110
|
+
renderHtmlInto,
|
|
111
|
+
renderMarkdownInto,
|
|
112
|
+
renderTextInto,
|
|
113
|
+
trustedHTML,
|
|
114
|
+
markdownToTrustedHTML(source) {
|
|
115
|
+
const converted = toHtml(source);
|
|
116
|
+
if ('failed' in converted) {
|
|
117
|
+
emit([MARKDOWN_FAILED]);
|
|
118
|
+
return trustedHTML(escapeText(source));
|
|
119
|
+
}
|
|
120
|
+
return trustedHTML(converted.html);
|
|
121
|
+
},
|
|
122
|
+
createStream(target, streamOptions = {}) {
|
|
123
|
+
return createRenderStream(target, streamOptions, { markdown: renderMarkdownInto, html: renderHtmlInto });
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
function escapeText(text) {
|
|
128
|
+
return text.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=render.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.js","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { TrustedHTML } from 'trusted-types/lib/index.js';
|
|
2
|
+
import type { RenderDecision } from './decisions.js';
|
|
3
|
+
import type { RenderPolicy } from './policy.js';
|
|
4
|
+
import { type SinkDenylist } from './sinks.js';
|
|
5
|
+
import type { RenderWindow } from './window.js';
|
|
6
|
+
export interface SanitizeOutcome<T> {
|
|
7
|
+
readonly output: T;
|
|
8
|
+
readonly decisions: readonly RenderDecision[];
|
|
9
|
+
}
|
|
10
|
+
export interface Sanitizer {
|
|
11
|
+
/** Sanitize into an inert DocumentFragment. This is the only path the renderer uses. */
|
|
12
|
+
toFragment(html: string): SanitizeOutcome<DocumentFragment>;
|
|
13
|
+
/** Sanitize to a TrustedHTML when the Trusted Types API is present, else a string. */
|
|
14
|
+
toTrustedHTML(html: string): SanitizeOutcome<TrustedHTML | string>;
|
|
15
|
+
}
|
|
16
|
+
export declare function createSanitizer(win: RenderWindow, policy: RenderPolicy, denylist: SinkDenylist): Sanitizer;
|
|
17
|
+
//# sourceMappingURL=sanitize.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sanitize.d.ts","sourceRoot":"","sources":["../src/sanitize.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,KAAK,EAAqC,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAExF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAa,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,MAAM,WAAW,eAAe,CAAC,CAAC;IAChC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IACnB,QAAQ,CAAC,SAAS,EAAE,SAAS,cAAc,EAAE,CAAC;CAC/C;AAED,MAAM,WAAW,SAAS;IACxB,wFAAwF;IACxF,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,CAAC,gBAAgB,CAAC,CAAC;IAC5D,sFAAsF;IACtF,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,CAAC,WAAW,GAAG,MAAM,CAAC,CAAC;CACpE;AAgFD,wBAAgB,eAAe,CAAC,GAAG,EAAE,YAAY,EAAE,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,YAAY,GAAG,SAAS,CA4P1G"}
|