sealbridge 0.0.1 → 0.2.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/NOTICE +43 -0
- package/README.ja.md +397 -0
- package/README.md +567 -1
- package/dist/cli/dist/acp.d.ts +2 -0
- package/dist/cli/dist/acp.js +6 -0
- package/dist/cli/dist/acp.js.map +1 -0
- package/dist/cli/dist/approval-summary.d.ts +2 -0
- package/dist/cli/dist/approval-summary.js +32 -0
- package/dist/cli/dist/approval-summary.js.map +1 -0
- package/dist/cli/dist/board.d.ts +47 -0
- package/dist/cli/dist/board.js +255 -0
- package/dist/cli/dist/board.js.map +1 -0
- package/dist/cli/dist/contacts.d.ts +18 -0
- package/dist/cli/dist/contacts.js +154 -0
- package/dist/cli/dist/contacts.js.map +1 -0
- package/dist/cli/dist/doctor.d.ts +13 -0
- package/dist/cli/dist/doctor.js +30 -0
- package/dist/cli/dist/doctor.js.map +1 -0
- package/dist/cli/dist/error-messages.d.ts +2 -0
- package/dist/cli/dist/error-messages.js +24 -0
- package/dist/cli/dist/error-messages.js.map +1 -0
- package/dist/cli/dist/index.d.ts +2 -0
- package/dist/cli/dist/index.js +194 -0
- package/dist/cli/dist/index.js.map +1 -0
- package/dist/cli/dist/invite-share.d.ts +16 -0
- package/dist/cli/dist/invite-share.js +163 -0
- package/dist/cli/dist/invite-share.js.map +1 -0
- package/dist/cli/dist/mcp.d.ts +17 -0
- package/dist/cli/dist/mcp.js +105 -0
- package/dist/cli/dist/mcp.js.map +1 -0
- package/dist/cli/dist/network.d.ts +1 -0
- package/dist/cli/dist/network.js +396 -0
- package/dist/cli/dist/network.js.map +1 -0
- package/dist/cli/dist/public-settings.d.ts +27 -0
- package/dist/cli/dist/public-settings.js +33 -0
- package/dist/cli/dist/public-settings.js.map +1 -0
- package/dist/cli/dist/receipt.d.ts +39 -0
- package/dist/cli/dist/receipt.js +90 -0
- package/dist/cli/dist/receipt.js.map +1 -0
- package/dist/cli/dist/receive-hook.d.ts +2 -0
- package/dist/cli/dist/receive-hook.js +35 -0
- package/dist/cli/dist/receive-hook.js.map +1 -0
- package/dist/cli/dist/task-input.d.ts +2 -0
- package/dist/cli/dist/task-input.js +19 -0
- package/dist/cli/dist/task-input.js.map +1 -0
- package/dist/cli/dist/wake-hook.d.ts +3 -0
- package/dist/cli/dist/wake-hook.js +32 -0
- package/dist/cli/dist/wake-hook.js.map +1 -0
- package/dist/examples/two-owner-demo/alice-policy.json +4 -0
- package/dist/examples/two-owner-demo/bob-policy.json +4 -0
- package/dist/examples/two-owner-demo/dist/run-demo.d.ts +71 -0
- package/dist/examples/two-owner-demo/dist/run-demo.js +383 -0
- package/dist/examples/two-owner-demo/dist/run-demo.js.map +1 -0
- package/dist/package.json +1 -0
- package/dist/packages/adapters/dist/command.d.ts +122 -0
- package/dist/packages/adapters/dist/command.js +378 -0
- package/dist/packages/adapters/dist/command.js.map +1 -0
- package/dist/packages/adapters/dist/credential-proxy.d.ts +37 -0
- package/dist/packages/adapters/dist/credential-proxy.js +363 -0
- package/dist/packages/adapters/dist/credential-proxy.js.map +1 -0
- package/dist/packages/adapters/dist/index.d.ts +6 -0
- package/dist/packages/adapters/dist/index.js +6 -0
- package/dist/packages/adapters/dist/index.js.map +1 -0
- package/dist/packages/adapters/dist/mcp.d.ts +32 -0
- package/dist/packages/adapters/dist/mcp.js +87 -0
- package/dist/packages/adapters/dist/mcp.js.map +1 -0
- package/dist/packages/adapters/dist/openai.d.ts +23 -0
- package/dist/packages/adapters/dist/openai.js +81 -0
- package/dist/packages/adapters/dist/openai.js.map +1 -0
- package/dist/packages/adapters/dist/sandbox.d.ts +45 -0
- package/dist/packages/adapters/dist/sandbox.js +60 -0
- package/dist/packages/adapters/dist/sandbox.js.map +1 -0
- package/dist/packages/core/dist/capability.d.ts +36 -0
- package/dist/packages/core/dist/capability.js +203 -0
- package/dist/packages/core/dist/capability.js.map +1 -0
- package/dist/packages/core/dist/contract.d.ts +33 -0
- package/dist/packages/core/dist/contract.js +97 -0
- package/dist/packages/core/dist/contract.js.map +1 -0
- package/dist/packages/core/dist/crypto.d.ts +34 -0
- package/dist/packages/core/dist/crypto.js +329 -0
- package/dist/packages/core/dist/crypto.js.map +1 -0
- package/dist/packages/core/dist/discovery.d.ts +129 -0
- package/dist/packages/core/dist/discovery.js +527 -0
- package/dist/packages/core/dist/discovery.js.map +1 -0
- package/dist/packages/core/dist/edge.d.ts +4 -0
- package/dist/packages/core/dist/edge.js +6 -0
- package/dist/packages/core/dist/edge.js.map +1 -0
- package/dist/packages/core/dist/index.d.ts +9 -0
- package/dist/packages/core/dist/index.js +10 -0
- package/dist/packages/core/dist/index.js.map +1 -0
- package/dist/packages/core/dist/receipts.d.ts +9 -0
- package/dist/packages/core/dist/receipts.js +67 -0
- package/dist/packages/core/dist/receipts.js.map +1 -0
- package/dist/packages/core/dist/relay-auth.d.ts +40 -0
- package/dist/packages/core/dist/relay-auth.js +106 -0
- package/dist/packages/core/dist/relay-auth.js.map +1 -0
- package/dist/packages/core/dist/revocation.d.ts +58 -0
- package/dist/packages/core/dist/revocation.js +112 -0
- package/dist/packages/core/dist/revocation.js.map +1 -0
- package/dist/packages/core/dist/schema.d.ts +11 -0
- package/dist/packages/core/dist/schema.js +48 -0
- package/dist/packages/core/dist/schema.js.map +1 -0
- package/dist/packages/core/dist/types.d.ts +172 -0
- package/dist/packages/core/dist/types.js +2 -0
- package/dist/packages/core/dist/types.js.map +1 -0
- package/dist/packages/ledger/dist/index.d.ts +84 -0
- package/dist/packages/ledger/dist/index.js +269 -0
- package/dist/packages/ledger/dist/index.js.map +1 -0
- package/dist/packages/relay/dist/fetch.d.ts +250 -0
- package/dist/packages/relay/dist/fetch.js +1401 -0
- package/dist/packages/relay/dist/fetch.js.map +1 -0
- package/dist/packages/relay/dist/index.d.ts +103 -0
- package/dist/packages/relay/dist/index.js +855 -0
- package/dist/packages/relay/dist/index.js.map +1 -0
- package/dist/packages/relay/dist/journal.d.ts +77 -0
- package/dist/packages/relay/dist/journal.js +339 -0
- package/dist/packages/relay/dist/journal.js.map +1 -0
- package/dist/packages/relay/dist/notifications.d.ts +63 -0
- package/dist/packages/relay/dist/notifications.js +55 -0
- package/dist/packages/relay/dist/notifications.js.map +1 -0
- package/dist/packages/relay/dist/retry.d.ts +12 -0
- package/dist/packages/relay/dist/retry.js +59 -0
- package/dist/packages/relay/dist/retry.js.map +1 -0
- package/dist/packages/relay/dist/ssrf.d.ts +32 -0
- package/dist/packages/relay/dist/ssrf.js +213 -0
- package/dist/packages/relay/dist/ssrf.js.map +1 -0
- package/dist/packages/relay/dist/worker.d.ts +92 -0
- package/dist/packages/relay/dist/worker.js +460 -0
- package/dist/packages/relay/dist/worker.js.map +1 -0
- package/dist/packages/runtime/dist/a2a.d.ts +8 -0
- package/dist/packages/runtime/dist/a2a.js +69 -0
- package/dist/packages/runtime/dist/a2a.js.map +1 -0
- package/dist/packages/runtime/dist/adapter.d.ts +51 -0
- package/dist/packages/runtime/dist/adapter.js +2 -0
- package/dist/packages/runtime/dist/adapter.js.map +1 -0
- package/dist/packages/runtime/dist/approval-providers.d.ts +99 -0
- package/dist/packages/runtime/dist/approval-providers.js +269 -0
- package/dist/packages/runtime/dist/approval-providers.js.map +1 -0
- package/dist/packages/runtime/dist/daily-limit.d.ts +2 -0
- package/dist/packages/runtime/dist/daily-limit.js +54 -0
- package/dist/packages/runtime/dist/daily-limit.js.map +1 -0
- package/dist/packages/runtime/dist/gateway.d.ts +35 -0
- package/dist/packages/runtime/dist/gateway.js +92 -0
- package/dist/packages/runtime/dist/gateway.js.map +1 -0
- package/dist/packages/runtime/dist/inbox.d.ts +10 -0
- package/dist/packages/runtime/dist/inbox.js +24 -0
- package/dist/packages/runtime/dist/inbox.js.map +1 -0
- package/dist/packages/runtime/dist/index.d.ts +13 -0
- package/dist/packages/runtime/dist/index.js +14 -0
- package/dist/packages/runtime/dist/index.js.map +1 -0
- package/dist/packages/runtime/dist/mcp-server.d.ts +90 -0
- package/dist/packages/runtime/dist/mcp-server.js +647 -0
- package/dist/packages/runtime/dist/mcp-server.js.map +1 -0
- package/dist/packages/runtime/dist/mcp-tool-catalog.d.ts +3 -0
- package/dist/packages/runtime/dist/mcp-tool-catalog.js +507 -0
- package/dist/packages/runtime/dist/mcp-tool-catalog.js.map +1 -0
- package/dist/packages/runtime/dist/mcp.d.ts +73 -0
- package/dist/packages/runtime/dist/mcp.js +67 -0
- package/dist/packages/runtime/dist/mcp.js.map +1 -0
- package/dist/packages/runtime/dist/policy.d.ts +19 -0
- package/dist/packages/runtime/dist/policy.js +41 -0
- package/dist/packages/runtime/dist/policy.js.map +1 -0
- package/dist/packages/runtime/dist/quota.d.ts +39 -0
- package/dist/packages/runtime/dist/quota.js +147 -0
- package/dist/packages/runtime/dist/quota.js.map +1 -0
- package/dist/packages/runtime/dist/session-audit.d.ts +107 -0
- package/dist/packages/runtime/dist/session-audit.js +520 -0
- package/dist/packages/runtime/dist/session-audit.js.map +1 -0
- package/dist/packages/runtime/dist/session-timeouts.d.ts +33 -0
- package/dist/packages/runtime/dist/session-timeouts.js +62 -0
- package/dist/packages/runtime/dist/session-timeouts.js.map +1 -0
- package/dist/packages/runtime/dist/session.d.ts +323 -0
- package/dist/packages/runtime/dist/session.js +2252 -0
- package/dist/packages/runtime/dist/session.js.map +1 -0
- package/dist/packages/runtime/dist/task-journal.d.ts +36 -0
- package/dist/packages/runtime/dist/task-journal.js +104 -0
- package/dist/packages/runtime/dist/task-journal.js.map +1 -0
- package/dist/packages/runtime/dist/verifier.d.ts +64 -0
- package/dist/packages/runtime/dist/verifier.js +109 -0
- package/dist/packages/runtime/dist/verifier.js.map +1 -0
- package/dist/packages/sandbox/dist/container.d.ts +33 -0
- package/dist/packages/sandbox/dist/container.js +189 -0
- package/dist/packages/sandbox/dist/container.js.map +1 -0
- package/dist/packages/sandbox/dist/index.d.ts +34 -0
- package/dist/packages/sandbox/dist/index.js +179 -0
- package/dist/packages/sandbox/dist/index.js.map +1 -0
- package/dist/packages/sandbox/dist/permission.d.ts +58 -0
- package/dist/packages/sandbox/dist/permission.js +90 -0
- package/dist/packages/sandbox/dist/permission.js.map +1 -0
- package/dist/spec/README.ja.md +76 -0
- package/dist/spec/README.md +135 -0
- package/dist/spec/ack-receipt.schema.json +77 -0
- package/dist/spec/agent-card.schema.json +83 -0
- package/dist/spec/approval-receipt.schema.json +94 -0
- package/dist/spec/audit-entry.schema.json +101 -0
- package/dist/spec/capability-token.schema.json +133 -0
- package/dist/spec/envelope.schema.json +197 -0
- package/dist/spec/examples/sample-ack-receipt.json +16 -0
- package/dist/spec/examples/sample-agent-card.json +35 -0
- package/dist/spec/examples/sample-approval-receipt.json +18 -0
- package/dist/spec/examples/sample-audit-entry.json +37 -0
- package/dist/spec/examples/sample-capability-token.json +39 -0
- package/dist/spec/examples/sample-envelope.json +21 -0
- package/dist/spec/examples/sample-task-manifest.json +141 -0
- package/dist/spec/examples/sample-usage-receipt.json +19 -0
- package/dist/spec/task-manifest.schema.json +422 -0
- package/dist/spec/usage-receipt.schema.json +91 -0
- package/package.json +61 -5
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { AgentAdapter, AgentTaskContext } from '@acp/runtime';
|
|
2
|
+
import type { Json } from '@acp/core';
|
|
3
|
+
/**
|
|
4
|
+
* Runs task JavaScript and reports the isolation the host runner actually used.
|
|
5
|
+
*
|
|
6
|
+
* `subprocess_restricted` (the default, and the fallback when Podman or Docker
|
|
7
|
+
* is absent) is a separate OS process. The child gets a sanitized environment
|
|
8
|
+
* (no inherited credentials or `NODE_OPTIONS`), a temporary scratch directory,
|
|
9
|
+
* a wall-clock timeout followed by SIGTERM then SIGKILL, and an output byte cap.
|
|
10
|
+
* `detectNodePermissionFlag` / `resolveNodePermissionArgs` in `@acp/sandbox`
|
|
11
|
+
* select `--permission` on Node.js >= 22.13 and on Node.js 23+, or
|
|
12
|
+
* `--experimental-permission` on earlier Node.js 20 and 22 releases, and pair
|
|
13
|
+
* that flag with `--allow-fs-read` and `--allow-fs-write` for the scratch
|
|
14
|
+
* directory. Those flags restrict filesystem, child-process, worker-thread, and
|
|
15
|
+
* native-addon access. They do not block `fetch`, `node:net`, `node:http`,
|
|
16
|
+
* `node:https`, `node:dns`, or `node:dgram`, and they are not a kernel network
|
|
17
|
+
* namespace. When this Node binary advertises neither flag, the child still
|
|
18
|
+
* starts and `sandboxBoundary.permissionModelActive` is false.
|
|
19
|
+
*
|
|
20
|
+
* Task source is evaluated with `node:vm` in that same child. Node.js documents
|
|
21
|
+
* that `node:vm` is not a security mechanism against untrusted code. A
|
|
22
|
+
* null-prototype context that omits `process` and `require`, and deleting
|
|
23
|
+
* `globalThis.fetch` and `WebSocket` in the wrapper, only shrinks the API the
|
|
24
|
+
* guest script sees.
|
|
25
|
+
*
|
|
26
|
+
* Untrusted third-party code requires `oci_container`
|
|
27
|
+
* (`isolationLevel: 'oci_container'`). That path runs Podman or Docker with
|
|
28
|
+
* `--network none`, a read-only root filesystem, `--cap-drop ALL`,
|
|
29
|
+
* `--security-opt no-new-privileges`, and PID and memory limits.
|
|
30
|
+
* `ExecutionAttestation.effectiveIsolationLevel` is `subprocess_restricted` or
|
|
31
|
+
* `oci_container` from the path that ran. `VerificationEngine` rejects a
|
|
32
|
+
* `subprocess_restricted` attestation when the contract requires `oci_container`,
|
|
33
|
+
* unless `sandboxPolicy.allowSubprocessFallback` is true.
|
|
34
|
+
*/
|
|
35
|
+
export declare class SandboxAgentAdapter implements AgentAdapter {
|
|
36
|
+
readonly code: string;
|
|
37
|
+
readonly id = "sandbox";
|
|
38
|
+
readonly name = "Restricted JavaScript Worker";
|
|
39
|
+
readonly skills: {
|
|
40
|
+
id: string;
|
|
41
|
+
name: string;
|
|
42
|
+
}[];
|
|
43
|
+
constructor(code?: string);
|
|
44
|
+
executeTask(context: AgentTaskContext): Promise<Json>;
|
|
45
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
import { runContainerOrSubprocessSandbox } from '../../sandbox/dist/index.js';
|
|
3
|
+
/**
|
|
4
|
+
* Runs task JavaScript and reports the isolation the host runner actually used.
|
|
5
|
+
*
|
|
6
|
+
* `subprocess_restricted` (the default, and the fallback when Podman or Docker
|
|
7
|
+
* is absent) is a separate OS process. The child gets a sanitized environment
|
|
8
|
+
* (no inherited credentials or `NODE_OPTIONS`), a temporary scratch directory,
|
|
9
|
+
* a wall-clock timeout followed by SIGTERM then SIGKILL, and an output byte cap.
|
|
10
|
+
* `detectNodePermissionFlag` / `resolveNodePermissionArgs` in `@acp/sandbox`
|
|
11
|
+
* select `--permission` on Node.js >= 22.13 and on Node.js 23+, or
|
|
12
|
+
* `--experimental-permission` on earlier Node.js 20 and 22 releases, and pair
|
|
13
|
+
* that flag with `--allow-fs-read` and `--allow-fs-write` for the scratch
|
|
14
|
+
* directory. Those flags restrict filesystem, child-process, worker-thread, and
|
|
15
|
+
* native-addon access. They do not block `fetch`, `node:net`, `node:http`,
|
|
16
|
+
* `node:https`, `node:dns`, or `node:dgram`, and they are not a kernel network
|
|
17
|
+
* namespace. When this Node binary advertises neither flag, the child still
|
|
18
|
+
* starts and `sandboxBoundary.permissionModelActive` is false.
|
|
19
|
+
*
|
|
20
|
+
* Task source is evaluated with `node:vm` in that same child. Node.js documents
|
|
21
|
+
* that `node:vm` is not a security mechanism against untrusted code. A
|
|
22
|
+
* null-prototype context that omits `process` and `require`, and deleting
|
|
23
|
+
* `globalThis.fetch` and `WebSocket` in the wrapper, only shrinks the API the
|
|
24
|
+
* guest script sees.
|
|
25
|
+
*
|
|
26
|
+
* Untrusted third-party code requires `oci_container`
|
|
27
|
+
* (`isolationLevel: 'oci_container'`). That path runs Podman or Docker with
|
|
28
|
+
* `--network none`, a read-only root filesystem, `--cap-drop ALL`,
|
|
29
|
+
* `--security-opt no-new-privileges`, and PID and memory limits.
|
|
30
|
+
* `ExecutionAttestation.effectiveIsolationLevel` is `subprocess_restricted` or
|
|
31
|
+
* `oci_container` from the path that ran. `VerificationEngine` rejects a
|
|
32
|
+
* `subprocess_restricted` attestation when the contract requires `oci_container`,
|
|
33
|
+
* unless `sandboxPolicy.allowSubprocessFallback` is true.
|
|
34
|
+
*/
|
|
35
|
+
export class SandboxAgentAdapter {
|
|
36
|
+
code;
|
|
37
|
+
id = 'sandbox';
|
|
38
|
+
name = 'Restricted JavaScript Worker';
|
|
39
|
+
skills = [{ id: 'json-task', name: 'JSON task' }];
|
|
40
|
+
constructor(code = 'return input;') {
|
|
41
|
+
this.code = code;
|
|
42
|
+
}
|
|
43
|
+
async executeTask(context) {
|
|
44
|
+
const policy = context.manifest.sandboxPolicy;
|
|
45
|
+
if (policy.networkAccess !== 'none' || policy.filesystemScope !== 'ephemeral_workspace_only')
|
|
46
|
+
throw new Error('UNSUPPORTED_SANDBOX_POLICY');
|
|
47
|
+
const result = await runContainerOrSubprocessSandbox({
|
|
48
|
+
code: this.code,
|
|
49
|
+
input: context.input,
|
|
50
|
+
isolationLevel: policy.isolationLevel,
|
|
51
|
+
timeoutMs: context.manifest.budget.maxWallClockSeconds * 1000,
|
|
52
|
+
signal: context.signal,
|
|
53
|
+
onTool: (name, args) => context.callTool(name, args),
|
|
54
|
+
onUsage: (inputTokens, outputTokens) => context.reportUsage({ inputTokens, outputTokens }),
|
|
55
|
+
});
|
|
56
|
+
context.reportIsolation?.(result.effectiveIsolationLevel, result.sandboxBoundary);
|
|
57
|
+
return result.output;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=sandbox.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sandbox.js","sourceRoot":"","sources":["../src/sandbox.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,OAAO,EAAE,+BAA+B,EAAE,MAAM,cAAc,CAAC;AAI/D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,MAAM,OAAO,mBAAmB;IAIT;IAHZ,EAAE,GAAG,SAAS,CAAC;IACf,IAAI,GAAG,8BAA8B,CAAC;IACtC,MAAM,GAAG,CAAC,EAAE,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC;IAC3D,YAAqB,OAAO,eAAe;QAAtB,SAAI,GAAJ,IAAI,CAAkB;IAAG,CAAC;IAC/C,KAAK,CAAC,WAAW,CAAC,OAAyB;QACzC,MAAM,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC;QAC9C,IAAI,MAAM,CAAC,aAAa,KAAK,MAAM,IAAI,MAAM,CAAC,eAAe,KAAK,0BAA0B;YAC1F,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;QAChD,MAAM,MAAM,GAAG,MAAM,+BAA+B,CAAC;YACnD,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,cAAc,EAAE,MAAM,CAAC,cAAc;YACrC,SAAS,EAAE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,mBAAmB,GAAG,IAAI;YAC7D,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,MAAM,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,EAAE,IAAY,CAAC;YAC5D,OAAO,EAAE,CAAC,WAAW,EAAE,YAAY,EAAE,EAAE,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,WAAW,EAAE,YAAY,EAAE,CAAC;SAC3F,CAAC,CAAC;QACH,OAAO,CAAC,eAAe,EAAE,CAAC,MAAM,CAAC,uBAAuB,EAAE,MAAM,CAAC,eAAe,CAAC,CAAC;QAClF,OAAO,MAAM,CAAC,MAAM,CAAC;IACvB,CAAC;CACF"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { RevocationList } from './revocation.js';
|
|
2
|
+
import type { Capability, CapabilityToken, KeyPair, Schema } from './types.js';
|
|
3
|
+
export declare function violation(detail: string): never;
|
|
4
|
+
export declare function resourceWithin(child: string, parent: string): boolean;
|
|
5
|
+
export declare function schemaNarrows(child: Schema, parent: Schema): boolean;
|
|
6
|
+
export declare function assertAttenuation(parent: CapabilityToken, child: CapabilityToken): void;
|
|
7
|
+
export declare function createCapability(params: Omit<Capability, 'type' | 'id' | 'issuer' | 'parentHash'>, key: KeyPair, parent?: CapabilityToken): CapabilityToken;
|
|
8
|
+
export interface CapabilityContext {
|
|
9
|
+
rootDid: string;
|
|
10
|
+
audience: string;
|
|
11
|
+
taskId: string;
|
|
12
|
+
now?: number;
|
|
13
|
+
}
|
|
14
|
+
export declare function verifyCapabilityChain(chain: CapabilityToken[], context: CapabilityContext): CapabilityToken;
|
|
15
|
+
/**
|
|
16
|
+
* True when `issuerDid` signed this token or an ancestor in the chain.
|
|
17
|
+
* `payload.issuer` is ignored unless that token's signature verifies for the
|
|
18
|
+
* same DID. Callers must pass a chain that has already passed
|
|
19
|
+
* `verifyCapabilityChain` for the context being evaluated: a self-signed
|
|
20
|
+
* token controls only itself, not another issuer's token that reused its id.
|
|
21
|
+
*/
|
|
22
|
+
export declare function capabilityIssuerControls(chain: CapabilityToken[], index: number, issuerDid: string): boolean;
|
|
23
|
+
export declare class CapabilityGuard {
|
|
24
|
+
private readonly registry?;
|
|
25
|
+
private counts;
|
|
26
|
+
private revoked;
|
|
27
|
+
constructor(registry?: RevocationList | undefined);
|
|
28
|
+
revokeTask(taskId: string): void;
|
|
29
|
+
authorize(chain: CapabilityToken[], context: CapabilityContext, tool: string, args: Record<string, unknown>, resource: string): void;
|
|
30
|
+
/**
|
|
31
|
+
* A notice revokes this token only when its issuer controls the token in
|
|
32
|
+
* this verified chain. A third party who minted a different token with the
|
|
33
|
+
* same id does not.
|
|
34
|
+
*/
|
|
35
|
+
private capabilityTargetRevoked;
|
|
36
|
+
}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0 AND MIT
|
|
2
|
+
// Adapted from newtro/delegateos src/core/dct.ts and chain.ts (MIT), Scott Smith.
|
|
3
|
+
import { randomUUID } from 'node:crypto';
|
|
4
|
+
import { canonicalize, digest, signPayload, verifySigned } from './crypto.js';
|
|
5
|
+
import { DEFAULT_CLOCK_SKEW_MS } from './discovery.js';
|
|
6
|
+
import { validateSchema, createAjv, assertSynchronousSchema } from './schema.js';
|
|
7
|
+
export function violation(detail) {
|
|
8
|
+
throw new Error('CAPABILITY_VIOLATION: ' + detail);
|
|
9
|
+
}
|
|
10
|
+
// Only exact URIs and terminal /* prefixes are supported. No glob inference.
|
|
11
|
+
export function resourceWithin(child, parent) {
|
|
12
|
+
if (child === parent)
|
|
13
|
+
return true;
|
|
14
|
+
if (!parent.endsWith('/*'))
|
|
15
|
+
return false;
|
|
16
|
+
const prefix = parent.slice(0, -1);
|
|
17
|
+
return (child.startsWith(prefix) &&
|
|
18
|
+
!child.slice(prefix.length).includes('..') &&
|
|
19
|
+
!/%2e|%2f|%5c/i.test(child) &&
|
|
20
|
+
!child.includes('\\'));
|
|
21
|
+
}
|
|
22
|
+
// General JSON Schema containment is undecidable. Accept identical schemas or
|
|
23
|
+
// explicit allOf inheritance only; reject all other rewrites, including equivalent ones.
|
|
24
|
+
function assertToolSchema(schema) {
|
|
25
|
+
assertSynchronousSchema(schema);
|
|
26
|
+
const check = (s) => {
|
|
27
|
+
if (!s || typeof s !== 'object')
|
|
28
|
+
return;
|
|
29
|
+
for (const [k, v] of Object.entries(s)) {
|
|
30
|
+
if (['$ref', '$dynamicRef', '$id', '$anchor', '$dynamicAnchor'].includes(k))
|
|
31
|
+
violation('tool schemas must be self-contained');
|
|
32
|
+
check(v);
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
check(schema);
|
|
36
|
+
createAjv().compile(schema);
|
|
37
|
+
}
|
|
38
|
+
export function schemaNarrows(child, parent) {
|
|
39
|
+
if (canonicalize(child) === canonicalize(parent))
|
|
40
|
+
return true;
|
|
41
|
+
return (Array.isArray(child.allOf) &&
|
|
42
|
+
child.allOf.some((s) => canonicalize(s) === canonicalize(parent)));
|
|
43
|
+
}
|
|
44
|
+
export function assertAttenuation(parent, child) {
|
|
45
|
+
const p = parent.payload, c = child.payload;
|
|
46
|
+
if (c.parentHash !== digest(parent) ||
|
|
47
|
+
p.audience !== c.issuer ||
|
|
48
|
+
p.taskId !== c.taskId ||
|
|
49
|
+
c.maxDepth > p.maxDepth - 1 ||
|
|
50
|
+
c.maxCalls > p.maxCalls ||
|
|
51
|
+
Date.parse(c.expiresAt) > Date.parse(p.expiresAt) ||
|
|
52
|
+
Date.parse(c.notBefore) < Date.parse(p.notBefore) ||
|
|
53
|
+
!resourceWithin(c.resource, p.resource))
|
|
54
|
+
violation('non-monotonic delegation');
|
|
55
|
+
for (const tool of c.allowedTools)
|
|
56
|
+
if (!p.allowedTools.includes(tool) ||
|
|
57
|
+
!c.argConstraints[tool] ||
|
|
58
|
+
!p.argConstraints[tool] ||
|
|
59
|
+
!schemaNarrows(c.argConstraints[tool], p.argConstraints[tool]))
|
|
60
|
+
violation('tool or argument schema escalation');
|
|
61
|
+
}
|
|
62
|
+
export function createCapability(params, key, parent) {
|
|
63
|
+
const token = signPayload({
|
|
64
|
+
...params,
|
|
65
|
+
type: 'CapabilityToken',
|
|
66
|
+
id: randomUUID(),
|
|
67
|
+
issuer: key.did,
|
|
68
|
+
parentHash: parent ? digest(parent) : null,
|
|
69
|
+
}, key);
|
|
70
|
+
validateSchema('capability-token', token);
|
|
71
|
+
for (const tool of token.payload.allowedTools)
|
|
72
|
+
if (!token.payload.argConstraints[tool] ||
|
|
73
|
+
!createAjv().validateSchema(token.payload.argConstraints[tool]))
|
|
74
|
+
violation('missing or invalid tool schema');
|
|
75
|
+
for (const tool of token.payload.allowedTools)
|
|
76
|
+
assertToolSchema(token.payload.argConstraints[tool]);
|
|
77
|
+
if (parent)
|
|
78
|
+
assertAttenuation(parent, token);
|
|
79
|
+
return token;
|
|
80
|
+
}
|
|
81
|
+
export function verifyCapabilityChain(chain, context) {
|
|
82
|
+
if (!chain.length || chain.length > 32)
|
|
83
|
+
violation('invalid proof chain length');
|
|
84
|
+
for (let i = 0; i < chain.length; i++) {
|
|
85
|
+
const t = chain[i], p = t.payload;
|
|
86
|
+
try {
|
|
87
|
+
validateSchema('capability-token', t);
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
violation('malformed token');
|
|
91
|
+
}
|
|
92
|
+
if (!verifySigned(t, p.issuer) ||
|
|
93
|
+
p.taskId !== context.taskId ||
|
|
94
|
+
(context.now ?? Date.now()) + DEFAULT_CLOCK_SKEW_MS < Date.parse(p.notBefore) ||
|
|
95
|
+
(context.now ?? Date.now()) >= Date.parse(p.expiresAt) ||
|
|
96
|
+
Date.parse(p.notBefore) >= Date.parse(p.expiresAt))
|
|
97
|
+
violation('signature, task or time');
|
|
98
|
+
for (const name of p.allowedTools)
|
|
99
|
+
if (!p.argConstraints[name] || !createAjv().validateSchema(p.argConstraints[name]))
|
|
100
|
+
violation('invalid tool schema');
|
|
101
|
+
for (const tool of p.allowedTools)
|
|
102
|
+
assertToolSchema(p.argConstraints[tool]);
|
|
103
|
+
if (i === 0) {
|
|
104
|
+
if (p.issuer !== context.rootDid || p.parentHash !== null)
|
|
105
|
+
violation('untrusted root');
|
|
106
|
+
}
|
|
107
|
+
else
|
|
108
|
+
assertAttenuation(chain[i - 1], t);
|
|
109
|
+
}
|
|
110
|
+
const leaf = chain[chain.length - 1];
|
|
111
|
+
if (leaf.payload.audience !== context.audience)
|
|
112
|
+
violation('audience');
|
|
113
|
+
return leaf;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* True when `issuerDid` signed this token or an ancestor in the chain.
|
|
117
|
+
* `payload.issuer` is ignored unless that token's signature verifies for the
|
|
118
|
+
* same DID. Callers must pass a chain that has already passed
|
|
119
|
+
* `verifyCapabilityChain` for the context being evaluated: a self-signed
|
|
120
|
+
* token controls only itself, not another issuer's token that reused its id.
|
|
121
|
+
*/
|
|
122
|
+
export function capabilityIssuerControls(chain, index, issuerDid) {
|
|
123
|
+
if (!issuerDid)
|
|
124
|
+
return false;
|
|
125
|
+
for (let i = 0; i <= index && i < chain.length; i++) {
|
|
126
|
+
const token = chain[i];
|
|
127
|
+
if (!token?.payload || token.payload.issuer !== issuerDid)
|
|
128
|
+
continue;
|
|
129
|
+
if (!verifySigned(token, issuerDid))
|
|
130
|
+
continue;
|
|
131
|
+
return true;
|
|
132
|
+
}
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
function capabilityIdentity(token) {
|
|
136
|
+
return digest({ issuer: token.payload.issuer, id: token.payload.id });
|
|
137
|
+
}
|
|
138
|
+
export class CapabilityGuard {
|
|
139
|
+
registry;
|
|
140
|
+
counts = new Map();
|
|
141
|
+
revoked = new Set();
|
|
142
|
+
constructor(registry) {
|
|
143
|
+
this.registry = registry;
|
|
144
|
+
}
|
|
145
|
+
revokeTask(taskId) {
|
|
146
|
+
this.revoked.add(taskId);
|
|
147
|
+
}
|
|
148
|
+
authorize(chain, context, tool, args, resource) {
|
|
149
|
+
// Task revocation does not read the chain. Check it before maxCalls so a
|
|
150
|
+
// settled task still fails closed after its counters are exhausted.
|
|
151
|
+
if (this.revoked.has(context.taskId))
|
|
152
|
+
violation('revoked task');
|
|
153
|
+
// Verify before trusting payload.issuer or treating a shared token id as revoked.
|
|
154
|
+
const leaf = verifyCapabilityChain(chain, context);
|
|
155
|
+
if (this.registry) {
|
|
156
|
+
for (let index = 0; index < chain.length; index++) {
|
|
157
|
+
const token = chain[index];
|
|
158
|
+
// The signed id is stable across representations. Digest targets remain
|
|
159
|
+
// supported after verification has required canonical signature encoding.
|
|
160
|
+
if (this.capabilityTargetRevoked(chain, index, token.payload.id) ||
|
|
161
|
+
this.capabilityTargetRevoked(chain, index, digest(token)))
|
|
162
|
+
throw new Error('TOKEN_REVOKED');
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
if (!leaf.payload.allowedTools.includes(tool) ||
|
|
166
|
+
!resourceWithin(resource, leaf.payload.resource) ||
|
|
167
|
+
!createAjv().compile(leaf.payload.argConstraints[tool])(args))
|
|
168
|
+
violation('tool, scope or arguments');
|
|
169
|
+
// Reserve synchronously before any asynchronous tool side effect. Parent IDs
|
|
170
|
+
// share counters across siblings; a caller must reuse this owner-side guard.
|
|
171
|
+
for (const t of chain)
|
|
172
|
+
if ((this.counts.get(capabilityIdentity(t)) ?? 0) >= t.payload.maxCalls)
|
|
173
|
+
violation('maxCalls exhausted');
|
|
174
|
+
for (const t of chain) {
|
|
175
|
+
const id = capabilityIdentity(t);
|
|
176
|
+
this.counts.set(id, (this.counts.get(id) ?? 0) + 1);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* A notice revokes this token only when its issuer controls the token in
|
|
181
|
+
* this verified chain. A third party who minted a different token with the
|
|
182
|
+
* same id does not.
|
|
183
|
+
*/
|
|
184
|
+
capabilityTargetRevoked(chain, index, targetId) {
|
|
185
|
+
const registry = this.registry;
|
|
186
|
+
if (!registry || !targetId)
|
|
187
|
+
return false;
|
|
188
|
+
const source = registry;
|
|
189
|
+
if (typeof source.noticesFor !== 'function')
|
|
190
|
+
return registry.isRevoked('capability', targetId);
|
|
191
|
+
const notices = source.noticesFor('capability', targetId);
|
|
192
|
+
if (notices.some((notice) => capabilityIssuerControls(chain, index, notice.payload.issuerDid)))
|
|
193
|
+
return true;
|
|
194
|
+
if (typeof source.unexplainedRevocation === 'function')
|
|
195
|
+
return source.unexplainedRevocation('capability', targetId);
|
|
196
|
+
// Listed notices are authoritative. An empty list plus a bare bit is an
|
|
197
|
+
// opaque registry that cannot show the issuer.
|
|
198
|
+
if (notices.length > 0)
|
|
199
|
+
return false;
|
|
200
|
+
return registry.isRevoked('capability', targetId);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
//# sourceMappingURL=capability.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capability.js","sourceRoot":"","sources":["../src/capability.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { KeyPair, Signed, TaskManifest } from './types.js';
|
|
2
|
+
export interface TaskContract {
|
|
3
|
+
manifest: TaskManifest;
|
|
4
|
+
proposal: Signed<TaskManifest>;
|
|
5
|
+
acceptance: Signed<{
|
|
6
|
+
type: 'ACCEPT';
|
|
7
|
+
manifestDigest: string;
|
|
8
|
+
taskId: string;
|
|
9
|
+
}>;
|
|
10
|
+
contractDigest: string;
|
|
11
|
+
}
|
|
12
|
+
export declare function createContract(manifest: TaskManifest, proposal: Signed<TaskManifest>, worker: KeyPair): TaskContract;
|
|
13
|
+
export declare function verifyContract(c: TaskContract): boolean;
|
|
14
|
+
export type State = 'PROPOSED' | 'ACCEPTED' | 'IN_PROGRESS' | 'DELIVERED' | 'VERIFY_ACCEPT' | 'VERIFY_REJECT' | 'SETTLED' | 'CANCELLED' | 'DISPUTED';
|
|
15
|
+
export type ContractEvent = 'ACCEPT' | 'START' | 'DELIVER' | 'VERIFY_ACCEPT' | 'VERIFY_REJECT' | 'SETTLE' | 'CANCEL' | 'DISPUTE';
|
|
16
|
+
export declare const transitions: Partial<Record<State, Partial<Record<ContractEvent, State>>>>;
|
|
17
|
+
export declare function nextState(state: State, event: ContractEvent): State;
|
|
18
|
+
export interface Transition {
|
|
19
|
+
taskId: string;
|
|
20
|
+
contractDigest: string;
|
|
21
|
+
seq: number;
|
|
22
|
+
from: State;
|
|
23
|
+
event: ContractEvent;
|
|
24
|
+
}
|
|
25
|
+
export declare class ContractMachine {
|
|
26
|
+
#private;
|
|
27
|
+
readonly contract: TaskContract;
|
|
28
|
+
readonly history: Signed<Transition>[];
|
|
29
|
+
get state(): State;
|
|
30
|
+
constructor(contract: TaskContract);
|
|
31
|
+
event(event: ContractEvent, key: KeyPair): Signed<Transition>;
|
|
32
|
+
apply(signed: Signed<Transition>): State;
|
|
33
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0 AND MIT
|
|
2
|
+
// Adapted from newtro/delegateos src/core/contract.ts (MIT), Scott Smith.
|
|
3
|
+
import { digest, signPayload, verifySigned } from './crypto.js';
|
|
4
|
+
import { validateManifest } from './schema.js';
|
|
5
|
+
export function createContract(manifest, proposal, worker) {
|
|
6
|
+
validateManifest(manifest);
|
|
7
|
+
if (!manifest.worker ||
|
|
8
|
+
worker.did !== manifest.worker.ownerDid ||
|
|
9
|
+
digest(manifest) !== digest(proposal.payload) ||
|
|
10
|
+
!verifySigned(proposal, manifest.requester.ownerDid))
|
|
11
|
+
throw new Error('INVALID_CONTRACT');
|
|
12
|
+
const acceptance = signPayload({ type: 'ACCEPT', manifestDigest: digest(manifest), taskId: manifest.taskId }, worker);
|
|
13
|
+
return {
|
|
14
|
+
manifest: structuredClone(manifest),
|
|
15
|
+
proposal,
|
|
16
|
+
acceptance,
|
|
17
|
+
contractDigest: digest({ proposal, acceptance }),
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
export function verifyContract(c) {
|
|
21
|
+
try {
|
|
22
|
+
validateManifest(c.manifest);
|
|
23
|
+
return (!!c.manifest.worker &&
|
|
24
|
+
digest(c.manifest) === digest(c.proposal.payload) &&
|
|
25
|
+
verifySigned(c.proposal, c.manifest.requester.ownerDid) &&
|
|
26
|
+
verifySigned(c.acceptance, c.manifest.worker.ownerDid) &&
|
|
27
|
+
c.acceptance.payload.type === 'ACCEPT' &&
|
|
28
|
+
c.acceptance.payload.taskId === c.manifest.taskId &&
|
|
29
|
+
c.acceptance.payload.manifestDigest === digest(c.manifest) &&
|
|
30
|
+
c.contractDigest === digest({ proposal: c.proposal, acceptance: c.acceptance }));
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
export const transitions = {
|
|
37
|
+
PROPOSED: { ACCEPT: 'ACCEPTED', CANCEL: 'CANCELLED' },
|
|
38
|
+
ACCEPTED: { START: 'IN_PROGRESS', CANCEL: 'CANCELLED' },
|
|
39
|
+
IN_PROGRESS: { DELIVER: 'DELIVERED', CANCEL: 'CANCELLED' },
|
|
40
|
+
DELIVERED: {
|
|
41
|
+
VERIFY_ACCEPT: 'VERIFY_ACCEPT',
|
|
42
|
+
VERIFY_REJECT: 'VERIFY_REJECT',
|
|
43
|
+
DISPUTE: 'DISPUTED',
|
|
44
|
+
},
|
|
45
|
+
VERIFY_ACCEPT: { SETTLE: 'SETTLED' },
|
|
46
|
+
VERIFY_REJECT: { DISPUTE: 'DISPUTED', CANCEL: 'CANCELLED' },
|
|
47
|
+
DISPUTED: { SETTLE: 'SETTLED' },
|
|
48
|
+
};
|
|
49
|
+
export function nextState(state, event) {
|
|
50
|
+
const next = transitions[state]?.[event];
|
|
51
|
+
if (!next)
|
|
52
|
+
throw new Error('INVALID_STATE_TRANSITION');
|
|
53
|
+
return next;
|
|
54
|
+
}
|
|
55
|
+
export class ContractMachine {
|
|
56
|
+
contract;
|
|
57
|
+
#state = 'PROPOSED';
|
|
58
|
+
#seq = 0;
|
|
59
|
+
history = [];
|
|
60
|
+
get state() {
|
|
61
|
+
return this.#state;
|
|
62
|
+
}
|
|
63
|
+
constructor(contract) {
|
|
64
|
+
this.contract = contract;
|
|
65
|
+
if (!verifyContract(contract))
|
|
66
|
+
throw new Error('INVALID_CONTRACT');
|
|
67
|
+
}
|
|
68
|
+
event(event, key) {
|
|
69
|
+
return signPayload({
|
|
70
|
+
taskId: this.contract.manifest.taskId,
|
|
71
|
+
contractDigest: this.contract.contractDigest,
|
|
72
|
+
seq: this.#seq,
|
|
73
|
+
from: this.#state,
|
|
74
|
+
event,
|
|
75
|
+
}, key);
|
|
76
|
+
}
|
|
77
|
+
apply(signed) {
|
|
78
|
+
const p = signed.payload, m = this.contract.manifest;
|
|
79
|
+
const workerEvents = ['ACCEPT', 'START', 'DELIVER'];
|
|
80
|
+
const expected = workerEvents.includes(p.event) ? m.worker.ownerDid : m.requester.ownerDid;
|
|
81
|
+
const either = ['CANCEL', 'DISPUTE'].includes(p.event);
|
|
82
|
+
if (!verifySigned(signed) ||
|
|
83
|
+
(!either && signed.signature.signerDid !== expected) ||
|
|
84
|
+
(either &&
|
|
85
|
+
![m.requester.ownerDid, m.worker.ownerDid].includes(signed.signature.signerDid)) ||
|
|
86
|
+
p.taskId !== m.taskId ||
|
|
87
|
+
p.contractDigest !== this.contract.contractDigest ||
|
|
88
|
+
p.seq !== this.#seq ||
|
|
89
|
+
p.from !== this.#state)
|
|
90
|
+
throw new Error('INVALID_TRANSITION_SIGNATURE');
|
|
91
|
+
this.#state = nextState(this.#state, p.event);
|
|
92
|
+
this.#seq++;
|
|
93
|
+
this.history.push(structuredClone(signed));
|
|
94
|
+
return this.#state;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=contract.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contract.js","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { KeyObject } from 'node:crypto';
|
|
2
|
+
import type { EncryptedEnvelopePayload, Json, KeyPair, Signature, Signed, SignedEnvelope } from './types.js';
|
|
3
|
+
export declare function canonicalize(v: unknown): string;
|
|
4
|
+
export declare function digestBytes(v: string | Uint8Array): string;
|
|
5
|
+
export declare function digest(v: unknown): string;
|
|
6
|
+
export declare function generateKeyPair(): KeyPair;
|
|
7
|
+
export declare function resolveDid(did: string): KeyObject;
|
|
8
|
+
export declare function signPayload<T>(payload: T, key: KeyPair, signedAt?: string): Signed<T>;
|
|
9
|
+
export declare function verifySigned<T>(value: Signed<T>, expectedDid?: string): boolean;
|
|
10
|
+
export declare function verifySignature(payload: unknown, signature: Signature, expectedDid?: string): boolean;
|
|
11
|
+
export interface EnvelopeHeaderContext {
|
|
12
|
+
taskId: string;
|
|
13
|
+
seq: number;
|
|
14
|
+
eventType: string;
|
|
15
|
+
senderDid: string;
|
|
16
|
+
recipientDid: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* HKDF-SHA256 info for envelope payload encryption.
|
|
20
|
+
* Binds the canonical header to the ephemeral X25519 public key and the
|
|
21
|
+
* recipient static X25519 public key so the AES key is tied to this
|
|
22
|
+
* Diffie-Hellman transcript as well as the header. Both keys are the raw
|
|
23
|
+
* 32-byte values, encoded base64url. AES-GCM additional data stays the
|
|
24
|
+
* header alone, and the 12-byte nonce stays the HKDF salt.
|
|
25
|
+
*/
|
|
26
|
+
export declare function envelopeHkdfInfo(context: EnvelopeHeaderContext, ephemeralPublicKey: Uint8Array, recipientPublicKey: Uint8Array): Buffer;
|
|
27
|
+
export declare function isEncryptedEnvelopePayload(payload: unknown): payload is EncryptedEnvelopePayload;
|
|
28
|
+
export declare function encryptEnvelopePayload(payload: Json, context: EnvelopeHeaderContext): EncryptedEnvelopePayload;
|
|
29
|
+
export declare function decryptEnvelopePayload<T = Json>(payload: Json, recipient: KeyPair, context: EnvelopeHeaderContext, options?: {
|
|
30
|
+
requireEncrypted?: boolean;
|
|
31
|
+
}): T;
|
|
32
|
+
export declare function openEnvelope<T = Json>(envelope: SignedEnvelope, recipient: KeyPair, options?: {
|
|
33
|
+
requireEncrypted?: boolean;
|
|
34
|
+
}): T;
|