@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/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 render-policy contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# @render-policy/core
|
|
2
|
+
|
|
3
|
+
Render Markdown or HTML that an agent wrote without ever assigning `innerHTML`: sanitize into a
|
|
4
|
+
`DocumentFragment`, apply a policy for images, links and hosts, insert with `replaceChildren()`.
|
|
5
|
+
Trusted Types compatible. Streaming aware.
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { createRenderer } from '@render-policy/core';
|
|
9
|
+
|
|
10
|
+
const renderer = createRenderer({ mode: 'balanced', policy: { images: { hosts: ['cdn.example.com'] } } });
|
|
11
|
+
renderer.renderMarkdownInto(element, message.content);
|
|
12
|
+
|
|
13
|
+
const stream = renderer.createStream(element);
|
|
14
|
+
stream.push(chunk);
|
|
15
|
+
stream.end();
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
`createContentBinding(renderer, element, { mode, schedule, onDecisions })` is the lifecycle a framework
|
|
19
|
+
adapter needs (`update(content, streaming)`); the building blocks the renderer is made of are in
|
|
20
|
+
`@render-policy/core/internal`, outside semver.
|
|
21
|
+
|
|
22
|
+
Full documentation, modes, policy reference and threat model: the
|
|
23
|
+
[repository README](https://github.com/shteynu/render-policy#readme).
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { RenderDecision } from './decisions.js';
|
|
2
|
+
import type { Renderer, RenderTarget } from './render.js';
|
|
3
|
+
import type { Scheduler, StreamOptions } from './stream.js';
|
|
4
|
+
export interface ContentBindingOptions {
|
|
5
|
+
/** Interpret the content as Markdown (default) or HTML. */
|
|
6
|
+
readonly mode?: 'markdown' | 'html';
|
|
7
|
+
/** Coalesces streaming renders, for example `frameScheduler(window)`. Default: render on every update. */
|
|
8
|
+
readonly schedule?: Scheduler;
|
|
9
|
+
/** Stream behaviour while streaming (withheld URLs, fence closing, tail patching). */
|
|
10
|
+
readonly stream?: Pick<StreamOptions, 'holdIncompleteUrls' | 'closeFences' | 'patch'>;
|
|
11
|
+
/** Receives the decision journal of every one-shot render and of the final render of a stream. */
|
|
12
|
+
readonly onDecisions?: (decisions: readonly RenderDecision[]) => void;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* One piece of agent content bound to one target: the lifecycle every framework adapter
|
|
16
|
+
* needs, written once. `update(content, streaming)` starts a stream on the first streaming
|
|
17
|
+
* update, feeds it while streaming stays true, ends it with a final render when streaming
|
|
18
|
+
* turns false, and otherwise renders in one shot.
|
|
19
|
+
*/
|
|
20
|
+
export interface ContentBinding {
|
|
21
|
+
update(content: string, streaming?: boolean): void;
|
|
22
|
+
/** True while a stream is open. */
|
|
23
|
+
readonly streaming: boolean;
|
|
24
|
+
/** Forget the open stream, if any. The target is left as it is. */
|
|
25
|
+
dispose(): void;
|
|
26
|
+
}
|
|
27
|
+
export declare function createContentBinding(renderer: Renderer, target: RenderTarget, options?: ContentBindingOptions): ContentBinding;
|
|
28
|
+
//# sourceMappingURL=binding.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"binding.d.ts","sourceRoot":"","sources":["../src/binding.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,KAAK,EAAgB,SAAS,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE1E,MAAM,WAAW,qBAAqB;IACpC,2DAA2D;IAC3D,QAAQ,CAAC,IAAI,CAAC,EAAE,UAAU,GAAG,MAAM,CAAC;IACpC,0GAA0G;IAC1G,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,CAAC;IAC9B,sFAAsF;IACtF,QAAQ,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,aAAa,EAAE,oBAAoB,GAAG,aAAa,GAAG,OAAO,CAAC,CAAC;IACtF,kGAAkG;IAClG,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,SAAS,EAAE,SAAS,cAAc,EAAE,KAAK,IAAI,CAAC;CACvE;AAED;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IACnD,mCAAmC;IACnC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,mEAAmE;IACnE,OAAO,IAAI,IAAI,CAAC;CACjB;AAED,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,GAAE,qBAA0B,GAAG,cAAc,CAgClI"}
|
package/dist/binding.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export function createContentBinding(renderer, target, options = {}) {
|
|
2
|
+
const mode = options.mode ?? 'markdown';
|
|
3
|
+
let stream = null;
|
|
4
|
+
const report = (decisions) => {
|
|
5
|
+
options.onDecisions?.(decisions);
|
|
6
|
+
};
|
|
7
|
+
return {
|
|
8
|
+
update(content, streaming = false) {
|
|
9
|
+
if (streaming) {
|
|
10
|
+
stream ??= renderer.createStream(target, { ...options.stream, mode, schedule: options.schedule });
|
|
11
|
+
stream.set(content);
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
if (stream) {
|
|
15
|
+
const open = stream;
|
|
16
|
+
stream = null;
|
|
17
|
+
open.set(content);
|
|
18
|
+
report(open.end().decisions);
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
const result = mode === 'html' ? renderer.renderHtmlInto(target, content) : renderer.renderMarkdownInto(target, content);
|
|
22
|
+
report(result.decisions);
|
|
23
|
+
},
|
|
24
|
+
get streaming() {
|
|
25
|
+
return stream !== null;
|
|
26
|
+
},
|
|
27
|
+
dispose() {
|
|
28
|
+
stream = null;
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=binding.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"binding.js","sourceRoot":"","sources":["../src/binding.ts"],"names":[],"mappings":"AA6BA,MAAM,UAAU,oBAAoB,CAAC,QAAkB,EAAE,MAAoB,EAAE,OAAO,GAA0B,EAAE;IAChH,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,UAAU,CAAC;IACxC,IAAI,MAAM,GAAwB,IAAI,CAAC;IAEvC,MAAM,MAAM,GAAG,CAAC,SAAoC,EAAQ,EAAE;QAC5D,OAAO,CAAC,WAAW,EAAE,CAAC,SAAS,CAAC,CAAC;IACnC,CAAC,CAAC;IAEF,OAAO;QACL,MAAM,CAAC,OAAO,EAAE,SAAS,GAAG,KAAK;YAC/B,IAAI,SAAS,EAAE,CAAC;gBACd,MAAM,KAAK,QAAQ,CAAC,YAAY,CAAC,MAAM,EAAE,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;gBAClG,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;gBACpB,OAAO;YACT,CAAC;YACD,IAAI,MAAM,EAAE,CAAC;gBACX,MAAM,IAAI,GAAG,MAAM,CAAC;gBACpB,MAAM,GAAG,IAAI,CAAC;gBACd,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;gBAClB,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;gBAC7B,OAAO;YACT,CAAC;YACD,MAAM,MAAM,GAAG,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,cAAc,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,kBAAkB,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;YACzH,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAC3B,CAAC;QACD,IAAI,SAAS;YACX,OAAO,MAAM,KAAK,IAAI,CAAC;QACzB,CAAC;QACD,OAAO;YACL,MAAM,GAAG,IAAI,CAAC;QAChB,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { SinkDenylist } from '../sinks.js';
|
|
2
|
+
/**
|
|
3
|
+
* Hosts that exist to receive whatever is sent to them. An agent that was
|
|
4
|
+
* prompt-injected does not need a server of its own: an image pointing at a
|
|
5
|
+
* request catcher, a tunnel or a public bucket is enough to carry the
|
|
6
|
+
* conversation out.
|
|
7
|
+
*
|
|
8
|
+
* This file is data, not code. It is versioned separately from the library
|
|
9
|
+
* and can be replaced at runtime through `createRenderer({ sinkDenylist })`.
|
|
10
|
+
* It is a starting set, not an exhaustive one: pair it with an image host
|
|
11
|
+
* allowlist and a CSP `img-src`.
|
|
12
|
+
*/
|
|
13
|
+
export declare const SINK_DENYLIST: SinkDenylist;
|
|
14
|
+
//# sourceMappingURL=sink-domains.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sink-domains.d.ts","sourceRoot":"","sources":["../../src/data/sink-domains.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAa,MAAM,aAAa,CAAC;AAE3D;;;;;;;;;;GAUG;AACH,eAAO,MAAM,aAAa,EAAE,YAmF1B,CAAC"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hosts that exist to receive whatever is sent to them. An agent that was
|
|
3
|
+
* prompt-injected does not need a server of its own: an image pointing at a
|
|
4
|
+
* request catcher, a tunnel or a public bucket is enough to carry the
|
|
5
|
+
* conversation out.
|
|
6
|
+
*
|
|
7
|
+
* This file is data, not code. It is versioned separately from the library
|
|
8
|
+
* and can be replaced at runtime through `createRenderer({ sinkDenylist })`.
|
|
9
|
+
* It is a starting set, not an exhaustive one: pair it with an image host
|
|
10
|
+
* allowlist and a CSP `img-src`.
|
|
11
|
+
*/
|
|
12
|
+
export const SINK_DENYLIST = Object.freeze({
|
|
13
|
+
version: '2026-09-30',
|
|
14
|
+
entries: Object.freeze([
|
|
15
|
+
// Out-of-band interaction services used to prove exfiltration.
|
|
16
|
+
{ pattern: 'interact.sh', category: 'oast' },
|
|
17
|
+
{ pattern: 'oast.fun', category: 'oast' },
|
|
18
|
+
{ pattern: 'oast.live', category: 'oast' },
|
|
19
|
+
{ pattern: 'oast.me', category: 'oast' },
|
|
20
|
+
{ pattern: 'oast.online', category: 'oast' },
|
|
21
|
+
{ pattern: 'oast.pro', category: 'oast' },
|
|
22
|
+
{ pattern: 'oast.site', category: 'oast' },
|
|
23
|
+
{ pattern: 'burpcollaborator.net', category: 'oast' },
|
|
24
|
+
{ pattern: 'oastify.com', category: 'oast' },
|
|
25
|
+
{ pattern: 'canarytokens.com', category: 'oast' },
|
|
26
|
+
{ pattern: 'dnslog.cn', category: 'oast' },
|
|
27
|
+
{ pattern: 'ceye.io', category: 'oast' },
|
|
28
|
+
// Request catchers and inbound webhooks.
|
|
29
|
+
{ pattern: 'webhook.site', category: 'webhook' },
|
|
30
|
+
{ pattern: 'requestbin.com', category: 'webhook' },
|
|
31
|
+
{ pattern: 'requestbin.net', category: 'webhook' },
|
|
32
|
+
{ pattern: 'pipedream.net', category: 'webhook' },
|
|
33
|
+
{ pattern: 'requestcatcher.com', category: 'webhook' },
|
|
34
|
+
{ pattern: 'hookbin.com', category: 'webhook' },
|
|
35
|
+
{ pattern: 'postb.in', category: 'webhook' },
|
|
36
|
+
{ pattern: 'beeceptor.com', category: 'webhook' },
|
|
37
|
+
{ pattern: 'mockbin.org', category: 'webhook' },
|
|
38
|
+
{ pattern: 'ptsv2.com', category: 'webhook' },
|
|
39
|
+
{ pattern: 'ptsv3.com', category: 'webhook' },
|
|
40
|
+
{ pattern: 'hooks.slack.com', category: 'webhook' },
|
|
41
|
+
{ pattern: 'hooks.zapier.com', category: 'webhook' },
|
|
42
|
+
{ pattern: 'maker.ifttt.com', category: 'webhook' },
|
|
43
|
+
{ pattern: 'discord.com/api/webhooks', category: 'webhook' },
|
|
44
|
+
{ pattern: 'discordapp.com/api/webhooks', category: 'webhook' },
|
|
45
|
+
// Tunnels that expose a laptop to the internet.
|
|
46
|
+
{ pattern: 'ngrok.io', category: 'tunnel' },
|
|
47
|
+
{ pattern: 'ngrok.app', category: 'tunnel' },
|
|
48
|
+
{ pattern: 'ngrok-free.app', category: 'tunnel' },
|
|
49
|
+
{ pattern: 'ngrok.dev', category: 'tunnel' },
|
|
50
|
+
{ pattern: 'loca.lt', category: 'tunnel' },
|
|
51
|
+
{ pattern: 'serveo.net', category: 'tunnel' },
|
|
52
|
+
{ pattern: 'trycloudflare.com', category: 'tunnel' },
|
|
53
|
+
{ pattern: 'localhost.run', category: 'tunnel' },
|
|
54
|
+
{ pattern: 'lhr.life', category: 'tunnel' },
|
|
55
|
+
// Anonymous serverless endpoints.
|
|
56
|
+
{ pattern: 'workers.dev', category: 'serverless' },
|
|
57
|
+
{ pattern: 'val.run', category: 'serverless' },
|
|
58
|
+
{ pattern: 'deno.dev', category: 'serverless' },
|
|
59
|
+
{ pattern: 'repl.co', category: 'serverless' },
|
|
60
|
+
{ pattern: 'replit.app', category: 'serverless' },
|
|
61
|
+
{ pattern: 'replit.dev', category: 'serverless' },
|
|
62
|
+
// Forms: the agent asks the user to "confirm" something on a page the attacker owns.
|
|
63
|
+
{ pattern: 'forms.gle', category: 'forms' },
|
|
64
|
+
{ pattern: 'docs.google.com/forms', category: 'forms' },
|
|
65
|
+
{ pattern: 'forms.office.com', category: 'forms' },
|
|
66
|
+
{ pattern: 'forms.microsoft.com', category: 'forms' },
|
|
67
|
+
{ pattern: 'typeform.com', category: 'forms' },
|
|
68
|
+
{ pattern: 'jotform.com', category: 'forms' },
|
|
69
|
+
{ pattern: 'tally.so', category: 'forms' },
|
|
70
|
+
{ pattern: 'surveymonkey.com', category: 'forms' },
|
|
71
|
+
{ pattern: 'formspree.io', category: 'forms' },
|
|
72
|
+
{ pattern: 'getform.io', category: 'forms' },
|
|
73
|
+
{ pattern: 'formsubmit.co', category: 'forms' },
|
|
74
|
+
{ pattern: 'formcarry.com', category: 'forms' },
|
|
75
|
+
// Public object storage with anonymous write or logging.
|
|
76
|
+
{ pattern: 'blob.core.windows.net', category: 'blob-storage' },
|
|
77
|
+
{ pattern: 's3.amazonaws.com', category: 'blob-storage' },
|
|
78
|
+
{ pattern: 'storage.googleapis.com', category: 'blob-storage' },
|
|
79
|
+
{ pattern: 'r2.dev', category: 'blob-storage' },
|
|
80
|
+
{ pattern: 'digitaloceanspaces.com', category: 'blob-storage' },
|
|
81
|
+
{ pattern: 'backblazeb2.com', category: 'blob-storage' },
|
|
82
|
+
{ pattern: 'wasabisys.com', category: 'blob-storage' },
|
|
83
|
+
{ pattern: 'file.io', category: 'blob-storage' },
|
|
84
|
+
{ pattern: 'transfer.sh', category: 'blob-storage' },
|
|
85
|
+
{ pattern: '0x0.st', category: 'blob-storage' },
|
|
86
|
+
{ pattern: 'catbox.moe', category: 'blob-storage' },
|
|
87
|
+
{ pattern: 'tmpfiles.org', category: 'blob-storage' },
|
|
88
|
+
{ pattern: 'gofile.io', category: 'blob-storage' },
|
|
89
|
+
]),
|
|
90
|
+
});
|
|
91
|
+
//# sourceMappingURL=sink-domains.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sink-domains.js","sourceRoot":"","sources":["../../src/data/sink-domains.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export type DecisionKind = 'blocked' | 'rewritten' | 'flagged';
|
|
2
|
+
export type DecisionSubject = 'element' | 'attribute' | 'link' | 'image' | 'url' | 'class' | 'markdown' | 'transform';
|
|
3
|
+
/** Codes the core emits. A transform may add its own; prefix them with its name (`diagram-…`). */
|
|
4
|
+
export type CoreDecisionCode = 'event-handler' | 'event-handler-survived' | 'class-not-allowed' | 'class-filtered' | 'target-not-allowed' | 'scheme-not-allowed' | 'url-unparsable' | 'relative-url-not-allowed' | 'sink-host' | 'url-denied' | 'url-rewritten' | 'url-rewrite-invalid' | 'url-decider-failed' | 'remote-images-disabled' | 'image-host-not-allowed' | 'image-query-denied' | 'image-query-stripped' | 'url-too-long' | 'url-encoded-payload' | 'image-rewrite-rejected' | 'image-rewrite-invalid' | 'image-rewrite-failed' | 'image-rewritten' | 'image-without-src' | 'element-not-allowed' | 'attribute-not-allowed' | 'markdown-failed' | 'transform-failed';
|
|
5
|
+
/** A known code, with room for codes a transform defines. */
|
|
6
|
+
export type DecisionCode = CoreDecisionCode | (string & {});
|
|
7
|
+
/**
|
|
8
|
+
* One policy decision made while rendering. The journal is the audit trail of a render:
|
|
9
|
+
* what was blocked, what was rewritten, and what was let through but is worth a look
|
|
10
|
+
* (`flagged`: a sink host under `sinkDenylist: 'log'`, a transform that failed).
|
|
11
|
+
* `code` is stable and meant for programs; `reason` is for people and may change.
|
|
12
|
+
*/
|
|
13
|
+
export interface RenderDecision {
|
|
14
|
+
readonly kind: DecisionKind;
|
|
15
|
+
readonly subject: DecisionSubject;
|
|
16
|
+
readonly code: DecisionCode;
|
|
17
|
+
readonly reason: string;
|
|
18
|
+
readonly tag?: string;
|
|
19
|
+
readonly attribute?: string;
|
|
20
|
+
readonly value?: string;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=decisions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decisions.d.ts","sourceRoot":"","sources":["../src/decisions.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,CAAC;AAE/D,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG,WAAW,GAAG,MAAM,GAAG,OAAO,GAAG,KAAK,GAAG,OAAO,GAAG,UAAU,GAAG,WAAW,CAAC;AAEtH,kGAAkG;AAClG,MAAM,MAAM,gBAAgB,GACxB,eAAe,GACf,wBAAwB,GACxB,mBAAmB,GACnB,gBAAgB,GAChB,oBAAoB,GACpB,oBAAoB,GACpB,gBAAgB,GAChB,0BAA0B,GAC1B,WAAW,GACX,YAAY,GACZ,eAAe,GACf,qBAAqB,GACrB,oBAAoB,GACpB,wBAAwB,GACxB,wBAAwB,GACxB,oBAAoB,GACpB,sBAAsB,GACtB,cAAc,GACd,qBAAqB,GACrB,wBAAwB,GACxB,uBAAuB,GACvB,sBAAsB,GACtB,iBAAiB,GACjB,mBAAmB,GACnB,qBAAqB,GACrB,uBAAuB,GACvB,iBAAiB,GACjB,kBAAkB,CAAC;AAEvB,6DAA6D;AAC7D,MAAM,MAAM,YAAY,GAAG,gBAAgB,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;AAE5D;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC;IAClC,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decisions.js","sourceRoot":"","sources":["../src/decisions.ts"],"names":[],"mappings":""}
|
package/dist/dom.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Replace the children of `target` with the children of `fragment`, keeping the
|
|
3
|
+
* leading child nodes that are unchanged. During streaming the settled blocks
|
|
4
|
+
* keep their DOM nodes (no flicker, no lost selection, no re-layout above the
|
|
5
|
+
* cursor) and only the block being typed is replaced.
|
|
6
|
+
*
|
|
7
|
+
* Both inputs are trusted here: the fragment comes out of the sanitizer.
|
|
8
|
+
*/
|
|
9
|
+
export declare function patchChildren(target: ParentNode, fragment: DocumentFragment): {
|
|
10
|
+
readonly kept: number;
|
|
11
|
+
readonly replaced: number;
|
|
12
|
+
};
|
|
13
|
+
//# sourceMappingURL=dom.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dom.d.ts","sourceRoot":"","sources":["../src/dom.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,gBAAgB,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAelI"}
|
package/dist/dom.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Replace the children of `target` with the children of `fragment`, keeping the
|
|
3
|
+
* leading child nodes that are unchanged. During streaming the settled blocks
|
|
4
|
+
* keep their DOM nodes (no flicker, no lost selection, no re-layout above the
|
|
5
|
+
* cursor) and only the block being typed is replaced.
|
|
6
|
+
*
|
|
7
|
+
* Both inputs are trusted here: the fragment comes out of the sanitizer.
|
|
8
|
+
*/
|
|
9
|
+
export function patchChildren(target, fragment) {
|
|
10
|
+
const current = Array.from(target.childNodes);
|
|
11
|
+
const next = Array.from(fragment.childNodes);
|
|
12
|
+
let kept = 0;
|
|
13
|
+
while (kept < current.length && kept < next.length && current[kept].isEqualNode(next[kept])) {
|
|
14
|
+
kept += 1;
|
|
15
|
+
}
|
|
16
|
+
for (let i = current.length - 1; i >= kept; i -= 1) {
|
|
17
|
+
current[i].remove();
|
|
18
|
+
}
|
|
19
|
+
const tail = next.slice(kept);
|
|
20
|
+
if (tail.length > 0) {
|
|
21
|
+
target.append(...tail);
|
|
22
|
+
}
|
|
23
|
+
return { kept, replaced: tail.length };
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=dom.js.map
|
package/dist/dom.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dom.js","sourceRoot":"","sources":["../src/dom.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,UAAU,aAAa,CAAC,MAAkB,EAAE,QAA0B;IAC1E,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IAC9C,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;IAC7C,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,OAAO,IAAI,GAAG,OAAO,CAAC,MAAM,IAAI,IAAI,GAAG,IAAI,CAAC,MAAM,IAAI,OAAO,CAAC,IAAI,CAAE,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAE,CAAC,EAAE,CAAC;QAC9F,IAAI,IAAI,CAAC,CAAC;IACZ,CAAC;IACD,KAAK,IAAI,CAAC,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QACnD,OAAO,CAAC,CAAC,CAAE,CAAC,MAAM,EAAE,CAAC;IACvB,CAAC;IACD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC9B,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACpB,MAAM,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;IACzB,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC;AACzC,CAAC"}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAEhD"}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,MAAM,UAAU,SAAS,CAAC,KAAc;IACtC,OAAO,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAChE,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export { createRenderer } from './render.js';
|
|
2
|
+
export type { FragmentResult, FragmentTransform, RenderContext, RenderOptions, RenderResult, RenderTarget, Renderer, RendererOptions, TransformContext } from './render.js';
|
|
3
|
+
export { createContentBinding } from './binding.js';
|
|
4
|
+
export type { ContentBinding, ContentBindingOptions } from './binding.js';
|
|
5
|
+
export { DEFAULT_MODE, DEFAULT_URL_HEURISTICS, MODE_PRESETS, resolvePolicy } from './policy.js';
|
|
6
|
+
export type { ContentPolicy, HostPattern, ImagePolicy, ImageHosts, RenderMode, RenderPolicy, RenderPolicyOverrides, UrlContext, UrlDecider, UrlDecision, UrlHeuristics, UrlPolicy, UrlSubject } from './policy.js';
|
|
7
|
+
export type { CoreDecisionCode, DecisionCode, DecisionKind, DecisionSubject, RenderDecision } from './decisions.js';
|
|
8
|
+
export { createMarkdownRenderer } from './markdown.js';
|
|
9
|
+
export type { MarkdownOptions, MarkdownRenderer } from './markdown.js';
|
|
10
|
+
export { completeFences, defaultScheduler, frameScheduler, holdIncompleteHtml, holdIncompleteMarkdown } from './stream.js';
|
|
11
|
+
export type { RenderStream, Scheduler, StreamOptions } from './stream.js';
|
|
12
|
+
export { checkUrl, hostMatches } from './url.js';
|
|
13
|
+
export type { ParsedUrl, UrlProblem, UrlVerdict } from './url.js';
|
|
14
|
+
export { matchSink, mergeSinkDenylists } from './sinks.js';
|
|
15
|
+
export type { SinkCategory, SinkDenylist, SinkEntry } from './sinks.js';
|
|
16
|
+
export { SINK_DENYLIST } from './data/sink-domains.js';
|
|
17
|
+
export { resolveWindow } from './window.js';
|
|
18
|
+
export type { RenderWindow } from './window.js';
|
|
19
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,YAAY,EAAE,cAAc,EAAE,iBAAiB,EAAE,aAAa,EAAE,aAAa,EAAE,YAAY,EAAE,YAAY,EAAE,QAAQ,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE5K,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,YAAY,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAE1E,OAAO,EAAE,YAAY,EAAE,sBAAsB,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAChG,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,EAAE,YAAY,EAAE,qBAAqB,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,aAAa,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEnN,YAAY,EAAE,gBAAgB,EAAE,YAAY,EAAE,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAEpH,OAAO,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AACvD,YAAY,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEvE,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,cAAc,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAC3H,YAAY,EAAE,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE1E,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACjD,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAElE,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAC3D,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAExE,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAEvD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { createRenderer } from './render.js';
|
|
2
|
+
export { createContentBinding } from './binding.js';
|
|
3
|
+
export { DEFAULT_MODE, DEFAULT_URL_HEURISTICS, MODE_PRESETS, resolvePolicy } from './policy.js';
|
|
4
|
+
export { createMarkdownRenderer } from './markdown.js';
|
|
5
|
+
export { completeFences, defaultScheduler, frameScheduler, holdIncompleteHtml, holdIncompleteMarkdown } from './stream.js';
|
|
6
|
+
export { checkUrl, hostMatches } from './url.js';
|
|
7
|
+
export { matchSink, mergeSinkDenylists } from './sinks.js';
|
|
8
|
+
export { SINK_DENYLIST } from './data/sink-domains.js';
|
|
9
|
+
export { resolveWindow } from './window.js';
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAG7C,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAGpD,OAAO,EAAE,YAAY,EAAE,sBAAsB,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAKhG,OAAO,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAGvD,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,cAAc,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAG3H,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAGjD,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAG3D,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAEvD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Building blocks the public entry does not expose: `@render-policy/core/internal`.
|
|
3
|
+
* They exist for this repository's tests and proofs and for integrators who need the
|
|
4
|
+
* pieces rather than the renderer. They are not covered by semver.
|
|
5
|
+
*/
|
|
6
|
+
export { patchChildren } from './dom.js';
|
|
7
|
+
export { createSanitizer } from './sanitize.js';
|
|
8
|
+
export type { SanitizeOutcome, Sanitizer } from './sanitize.js';
|
|
9
|
+
export { createRenderStream } from './stream.js';
|
|
10
|
+
export type { StreamRenderOps } from './stream.js';
|
|
11
|
+
export { checkUrlHeuristics, normalizeUrl, shannonEntropy, usableBase } from './url.js';
|
|
12
|
+
//# sourceMappingURL=internal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"internal.d.ts","sourceRoot":"","sources":["../src/internal.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,YAAY,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAChE,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,YAAY,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC"}
|
package/dist/internal.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Building blocks the public entry does not expose: `@render-policy/core/internal`.
|
|
3
|
+
* They exist for this repository's tests and proofs and for integrators who need the
|
|
4
|
+
* pieces rather than the renderer. They are not covered by semver.
|
|
5
|
+
*/
|
|
6
|
+
export { patchChildren } from './dom.js';
|
|
7
|
+
export { createSanitizer } from './sanitize.js';
|
|
8
|
+
export { createRenderStream } from './stream.js';
|
|
9
|
+
export { checkUrlHeuristics, normalizeUrl, shannonEntropy, usableBase } from './url.js';
|
|
10
|
+
//# sourceMappingURL=internal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"internal.js","sourceRoot":"","sources":["../src/internal.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEhD,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEjD,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/** Markdown to HTML. The output is untrusted: it always goes through the sanitizer afterwards. */
|
|
2
|
+
export type MarkdownRenderer = (markdown: string) => string;
|
|
3
|
+
export interface MarkdownOptions {
|
|
4
|
+
/** GitHub Flavored Markdown (tables, strikethrough, autolinks). Default true. */
|
|
5
|
+
readonly gfm?: boolean;
|
|
6
|
+
/** Render single newlines as <br>. Default false. */
|
|
7
|
+
readonly breaks?: boolean;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* The default Markdown renderer, built on marked. Raw HTML in the Markdown is
|
|
11
|
+
* passed through unchanged on purpose: sanitization runs last, on the final HTML,
|
|
12
|
+
* so nothing the Markdown step produces can bypass it.
|
|
13
|
+
*/
|
|
14
|
+
export declare function createMarkdownRenderer(options?: MarkdownOptions): MarkdownRenderer;
|
|
15
|
+
//# sourceMappingURL=markdown.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../src/markdown.ts"],"names":[],"mappings":"AAEA,kGAAkG;AAClG,MAAM,MAAM,gBAAgB,GAAG,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC;AAE5D,MAAM,WAAW,eAAe;IAC9B,iFAAiF;IACjF,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC;IACvB,qDAAqD;IACrD,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,GAAE,eAAoB,GAAG,gBAAgB,CAOtF"}
|
package/dist/markdown.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Marked } from 'marked';
|
|
2
|
+
/**
|
|
3
|
+
* The default Markdown renderer, built on marked. Raw HTML in the Markdown is
|
|
4
|
+
* passed through unchanged on purpose: sanitization runs last, on the final HTML,
|
|
5
|
+
* so nothing the Markdown step produces can bypass it.
|
|
6
|
+
*/
|
|
7
|
+
export function createMarkdownRenderer(options = {}) {
|
|
8
|
+
const marked = new Marked({
|
|
9
|
+
gfm: options.gfm ?? true,
|
|
10
|
+
breaks: options.breaks ?? false,
|
|
11
|
+
async: false,
|
|
12
|
+
});
|
|
13
|
+
return (markdown) => marked.parse(markdown, { async: false });
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=markdown.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown.js","sourceRoot":"","sources":["../src/markdown.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAYhC;;;;GAIG;AACH,MAAM,UAAU,sBAAsB,CAAC,OAAO,GAAoB,EAAE;IAClE,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC;QACxB,GAAG,EAAE,OAAO,CAAC,GAAG,IAAI,IAAI;QACxB,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,KAAK;QAC/B,KAAK,EAAE,KAAK;KACb,CAAC,CAAC;IACH,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;AAChE,CAAC"}
|
package/dist/policy.d.ts
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
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 type RenderMode = 'strict' | 'balanced' | 'permissive';
|
|
16
|
+
/** `cdn.example.com` matches exactly; `*.example.com` matches subdomains only when `allowWildcardHosts` is on. */
|
|
17
|
+
export type HostPattern = string;
|
|
18
|
+
/** `'none'`: no remote images at all. `'any'`: every host. An array: an allowlist of host patterns. */
|
|
19
|
+
export type ImageHosts = 'none' | 'any' | readonly HostPattern[];
|
|
20
|
+
export interface UrlHeuristics {
|
|
21
|
+
/** Longest URL accepted at all, in characters, after normalization. */
|
|
22
|
+
readonly maxLength: number;
|
|
23
|
+
/** A path segment or query value longer than this is inspected for encoded payloads. */
|
|
24
|
+
readonly maxTokenLength: number;
|
|
25
|
+
/** Shannon entropy (bits per character) at or above which a long token counts as an encoded payload. */
|
|
26
|
+
readonly minEntropy: number;
|
|
27
|
+
}
|
|
28
|
+
/** What a URL decision applies to: an `href` link, an image `src`, or another URL attribute. */
|
|
29
|
+
export type UrlSubject = 'link' | 'image' | 'url';
|
|
30
|
+
/** What a `urls.decide` hook is told about the URL it is judging. */
|
|
31
|
+
export interface UrlContext {
|
|
32
|
+
readonly subject: UrlSubject;
|
|
33
|
+
/** The element's tag, lower-case. */
|
|
34
|
+
readonly tag: string;
|
|
35
|
+
/** The attribute the URL came from, lower-case. */
|
|
36
|
+
readonly attribute: string;
|
|
37
|
+
/** True when the value resolves within the page's own origin without naming a scheme or host. */
|
|
38
|
+
readonly relative: boolean;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* A `urls.decide` verdict. `null` means "no opinion; apply the rest of the policy". A decision may
|
|
42
|
+
* deny the URL (drop the attribute), rewrite it (route a link through a redirector, an image through
|
|
43
|
+
* a proxy — the result is re-checked against the scheme allowlist), and carry a reason for the journal.
|
|
44
|
+
*/
|
|
45
|
+
export interface UrlDecision {
|
|
46
|
+
/** `false` drops the attribute. Omitted or `true` keeps it (subject to any `rewrite`). */
|
|
47
|
+
readonly allow?: boolean;
|
|
48
|
+
/** Replace the URL with this value. Re-validated against `allowedSchemes`. */
|
|
49
|
+
readonly rewrite?: string;
|
|
50
|
+
/** Recorded in the decision journal. */
|
|
51
|
+
readonly reason?: string;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* An application hook, run for every URL attribute after the scheme, relative and sink-denylist
|
|
55
|
+
* checks pass. It is where a link policy lives (deny or redirect off-site links); it runs for
|
|
56
|
+
* images too, before the image-specific policy. Trusted application code: if it throws, that one
|
|
57
|
+
* URL is dropped and the render goes on.
|
|
58
|
+
*/
|
|
59
|
+
export type UrlDecider = (url: URL, context: UrlContext) => UrlDecision | null;
|
|
60
|
+
/** Which elements, attributes and classes agent output may carry. Sanitization is applied regardless. */
|
|
61
|
+
export interface ContentPolicy {
|
|
62
|
+
/** Allow `<img>` at all. Same-origin and relative images are always allowed when this is on. */
|
|
63
|
+
readonly allowImages: boolean;
|
|
64
|
+
/** Allow form controls. Off by default: a rendered password field is a phishing form inside the chat. */
|
|
65
|
+
readonly allowForms: boolean;
|
|
66
|
+
/** Allow inline SVG (a sanitized subset). Off by default. */
|
|
67
|
+
readonly allowSvg: boolean;
|
|
68
|
+
/** Allow audio/video/source/track/picture. Off by default: they request URLs without a click, like images. */
|
|
69
|
+
readonly allowMedia: boolean;
|
|
70
|
+
/** Allow the style attribute. Off by default: agent content must not restyle or overlay the host UI. */
|
|
71
|
+
readonly allowInlineStyles: boolean;
|
|
72
|
+
/** Allow data-* attributes. Off by default: host scripts commonly read them as configuration. */
|
|
73
|
+
readonly allowDataAttributes: boolean;
|
|
74
|
+
/** Allow target="_blank" on links. rel="noopener noreferrer" is always enforced when a target is present. */
|
|
75
|
+
readonly allowTargetBlank: boolean;
|
|
76
|
+
/** Class names the content may carry; every other class is stripped. Patterns must not be global regexes. */
|
|
77
|
+
readonly allowedClassPatterns: readonly RegExp[];
|
|
78
|
+
/** Extra tags to forbid on top of the built-in list. */
|
|
79
|
+
readonly forbidTags: readonly string[];
|
|
80
|
+
/** Extra attributes to forbid on top of the built-in list. */
|
|
81
|
+
readonly forbidAttributes: readonly string[];
|
|
82
|
+
}
|
|
83
|
+
/** Which URLs any attribute may point at. */
|
|
84
|
+
export interface UrlPolicy {
|
|
85
|
+
/** URL schemes allowed in href/src/etc., lower-case, without the colon. Everything else is dropped. */
|
|
86
|
+
readonly allowedSchemes: readonly string[];
|
|
87
|
+
/** Scheme-less URLs resolve against the host page. Turn off to require absolute URLs. */
|
|
88
|
+
readonly allowRelativeUrls: boolean;
|
|
89
|
+
/** Length and entropy checks against encoded payloads hidden in a URL. `false` disables them. */
|
|
90
|
+
readonly heuristics: UrlHeuristics | false;
|
|
91
|
+
/** Hosts known to receive arbitrary data (webhook catchers, tunnels, forms, blob storage): block, log only, or ignore. */
|
|
92
|
+
readonly sinkDenylist: 'block' | 'log' | 'off';
|
|
93
|
+
/** Application hook to allow, deny or rewrite each URL. `null` to make no per-URL decisions. */
|
|
94
|
+
readonly decide: UrlDecider | null;
|
|
95
|
+
}
|
|
96
|
+
/** What happens to the image requests URLs would make (they fire without a click). */
|
|
97
|
+
export interface ImagePolicy {
|
|
98
|
+
/** Which remote hosts may receive image requests. */
|
|
99
|
+
readonly hosts: ImageHosts;
|
|
100
|
+
/** Honour `*.example.com` patterns in `hosts`. Off by default: a wildcard allows every subdomain, including user-controlled ones. */
|
|
101
|
+
readonly allowWildcardHosts: boolean;
|
|
102
|
+
/** Query strings on remote images: keep them, strip them (breaks signed URLs, defeats `?data=` exfiltration) or reject the image. */
|
|
103
|
+
readonly query: 'keep' | 'strip' | 'deny';
|
|
104
|
+
/** Rewrite allowed remote image URLs, for example through an image proxy. Return null to block the image. */
|
|
105
|
+
readonly rewriteUrl: ((url: URL) => string | null) | null;
|
|
106
|
+
/** Show a blocked image as a "click to open" placeholder link, or remove it silently. */
|
|
107
|
+
readonly blocked: 'remove' | 'placeholder';
|
|
108
|
+
}
|
|
109
|
+
export interface RenderPolicy {
|
|
110
|
+
readonly mode: RenderMode;
|
|
111
|
+
readonly content: ContentPolicy;
|
|
112
|
+
readonly urls: UrlPolicy;
|
|
113
|
+
readonly images: ImagePolicy;
|
|
114
|
+
}
|
|
115
|
+
/** A partial override of any group, merged onto a mode preset by {@link resolvePolicy}. */
|
|
116
|
+
export interface RenderPolicyOverrides {
|
|
117
|
+
readonly mode?: RenderMode;
|
|
118
|
+
readonly content?: Partial<ContentPolicy>;
|
|
119
|
+
readonly urls?: Partial<UrlPolicy>;
|
|
120
|
+
readonly images?: Partial<ImagePolicy>;
|
|
121
|
+
}
|
|
122
|
+
export declare const DEFAULT_URL_HEURISTICS: UrlHeuristics;
|
|
123
|
+
/**
|
|
124
|
+
* Mode presets.
|
|
125
|
+
*
|
|
126
|
+
* - strict: no remote images at all; sink hosts blocked; heuristics on.
|
|
127
|
+
* - balanced: remote images only from the allowlist, query strings stripped; sink hosts blocked; heuristics on.
|
|
128
|
+
* - permissive: every host allowed, nothing rewritten; sink hosts and nothing else are only logged.
|
|
129
|
+
*
|
|
130
|
+
* Sanitization is identical in all three modes. Permissive is still XSS-safe; it just stops
|
|
131
|
+
* making decisions about where data may flow.
|
|
132
|
+
*/
|
|
133
|
+
export declare const MODE_PRESETS: Readonly<Record<RenderMode, RenderPolicy>>;
|
|
134
|
+
export declare const DEFAULT_MODE: RenderMode;
|
|
135
|
+
/**
|
|
136
|
+
* Build a policy from a mode preset plus explicit overrides. Each group is merged on top of the
|
|
137
|
+
* preset, so an override names only the fields it changes. Throws on configurations that silently
|
|
138
|
+
* widen exposure (wildcard hosts without opting in).
|
|
139
|
+
*/
|
|
140
|
+
export declare function resolvePolicy(mode?: RenderMode, overrides?: RenderPolicyOverrides): RenderPolicy;
|
|
141
|
+
//# sourceMappingURL=policy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"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"}
|