@aithos/sdk 0.1.0-alpha.6 → 0.1.0-alpha.60
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/README.md +202 -7
- package/dist/src/agent-dispatch.d.ts +18 -0
- package/dist/src/agent-dispatch.js +178 -0
- package/dist/src/agent-loop.d.ts +94 -0
- package/dist/src/agent-loop.js +95 -0
- package/dist/src/agent-tools.d.ts +24 -0
- package/dist/src/agent-tools.js +147 -0
- package/dist/src/apps.d.ts +224 -0
- package/dist/src/apps.js +432 -0
- package/dist/src/assets.d.ts +225 -0
- package/dist/src/assets.js +534 -0
- package/dist/src/auth-api.d.ts +219 -0
- package/dist/src/auth-api.js +248 -0
- package/dist/src/auth.d.ts +591 -0
- package/dist/src/auth.js +947 -31
- package/dist/src/compute.d.ts +674 -6
- package/dist/src/compute.js +968 -20
- package/dist/src/data-schema-contacts-v1.d.ts +14 -0
- package/dist/src/data-schema-contacts-v1.js +28 -0
- package/dist/src/data.d.ts +368 -0
- package/dist/src/data.js +1124 -0
- package/dist/src/endpoints.d.ts +43 -0
- package/dist/src/endpoints.js +23 -0
- package/dist/src/ethos.d.ts +85 -0
- package/dist/src/ethos.js +463 -7
- package/dist/src/index.d.ts +22 -4
- package/dist/src/index.js +47 -2
- package/dist/src/internal/cmk-wrap.d.ts +41 -0
- package/dist/src/internal/cmk-wrap.js +132 -0
- package/dist/src/internal/delegate-bundle.js +7 -2
- package/dist/src/internal/envelope.d.ts +93 -0
- package/dist/src/internal/envelope.js +59 -0
- package/dist/src/internal/owner-signers.d.ts +5 -2
- package/dist/src/internal/owner-signers.js +22 -1
- package/dist/src/internal/recovery-file.d.ts +2 -0
- package/dist/src/internal/recovery-file.js +7 -0
- package/dist/src/key-store.d.ts +10 -0
- package/dist/src/key-store.js +6 -0
- package/dist/src/mandates.d.ts +58 -1
- package/dist/src/mandates.js +46 -3
- package/dist/src/migrate.d.ts +105 -0
- package/dist/src/migrate.js +367 -0
- package/dist/src/react/AithosAsset.d.ts +66 -0
- package/dist/src/react/AithosAsset.js +67 -0
- package/dist/src/react/context.d.ts +29 -0
- package/dist/src/react/context.js +31 -0
- package/dist/src/react/index.d.ts +29 -0
- package/dist/src/react/index.js +31 -0
- package/dist/src/react/use-aithos-asset.d.ts +39 -0
- package/dist/src/react/use-aithos-asset.js +118 -0
- package/dist/src/react/use-transcribe-pending.d.ts +21 -0
- package/dist/src/react/use-transcribe-pending.js +47 -0
- package/dist/src/rotate.d.ts +94 -0
- package/dist/src/rotate.js +298 -0
- package/dist/src/sdk.d.ts +36 -2
- package/dist/src/sdk.js +72 -1
- package/dist/src/transcribe-resilience.d.ts +57 -0
- package/dist/src/transcribe-resilience.js +203 -0
- package/dist/src/web.d.ts +279 -0
- package/dist/src/web.js +186 -0
- package/dist/test/agent-dispatch.test.d.ts +2 -0
- package/dist/test/agent-dispatch.test.js +222 -0
- package/dist/test/agent-loop.test.d.ts +2 -0
- package/dist/test/agent-loop.test.js +117 -0
- package/dist/test/agent-tools.test.d.ts +2 -0
- package/dist/test/agent-tools.test.js +50 -0
- package/dist/test/auth-j3.test.js +32 -1
- package/dist/test/canonical-conformance.test.d.ts +2 -0
- package/dist/test/canonical-conformance.test.js +86 -0
- package/dist/test/compute-delegate-path.test.d.ts +2 -0
- package/dist/test/compute-delegate-path.test.js +183 -0
- package/dist/test/compute.test.js +4 -0
- package/dist/test/converse.test.d.ts +2 -0
- package/dist/test/converse.test.js +162 -0
- package/dist/test/data-sphere.test.d.ts +2 -0
- package/dist/test/data-sphere.test.js +57 -0
- package/dist/test/endpoints.test.js +40 -1
- package/dist/test/envelope-core-conformance.test.d.ts +2 -0
- package/dist/test/envelope-core-conformance.test.js +75 -0
- package/dist/test/envelope.test.d.ts +2 -0
- package/dist/test/envelope.test.js +318 -0
- package/dist/test/ethos-first-edition.test.d.ts +2 -0
- package/dist/test/ethos-first-edition.test.js +371 -0
- package/dist/test/invoke-turn-sdk.test.d.ts +2 -0
- package/dist/test/invoke-turn-sdk.test.js +177 -0
- package/dist/test/migrate.test.d.ts +2 -0
- package/dist/test/migrate.test.js +340 -0
- package/dist/test/owner-data-client.test.d.ts +2 -0
- package/dist/test/owner-data-client.test.js +88 -0
- package/dist/test/rotate-ethos.test.d.ts +2 -0
- package/dist/test/rotate-ethos.test.js +151 -0
- package/dist/test/rotate.test.d.ts +2 -0
- package/dist/test/rotate.test.js +63 -0
- package/dist/test/schema-autoresolve.test.d.ts +2 -0
- package/dist/test/schema-autoresolve.test.js +146 -0
- package/dist/test/sdk.test.js +11 -2
- package/dist/test/signup-bootstrap.test.d.ts +2 -0
- package/dist/test/signup-bootstrap.test.js +311 -0
- package/dist/test/transcribe-invoke.test.d.ts +2 -0
- package/dist/test/transcribe-invoke.test.js +204 -0
- package/dist/test/transcribe.test.d.ts +2 -0
- package/dist/test/transcribe.test.js +186 -0
- package/dist/test/web.test.d.ts +2 -0
- package/dist/test/web.test.js +270 -0
- package/package.json +20 -3
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// Copyright 2026 Mathieu Colla
|
|
3
|
+
// Unit tests for the signed-envelope primitive — both the SDK-internal
|
|
4
|
+
// helper `signOwnerEnvelope` and the public surface
|
|
5
|
+
// `AithosAuth.signEnvelope`.
|
|
6
|
+
//
|
|
7
|
+
// Two levels of testing:
|
|
8
|
+
//
|
|
9
|
+
// 1. Internal helper: tests that can inject deterministic `now` and
|
|
10
|
+
// `nonce` to lock byte-for-byte output. These guard against any
|
|
11
|
+
// future drift in canonicalization, default TTL, field order, or
|
|
12
|
+
// crypto wiring.
|
|
13
|
+
//
|
|
14
|
+
// 2. Public surface: tests that exercise the full path through
|
|
15
|
+
// `AithosAuth.signEnvelope`, including sphere resolution, throw
|
|
16
|
+
// semantics, and binding to the loaded owner's DID. These guard
|
|
17
|
+
// the developer contract documented in the JSDoc.
|
|
18
|
+
import { strict as assert } from "node:assert";
|
|
19
|
+
import { describe, it } from "node:test";
|
|
20
|
+
import { createBrowserIdentity, sign as ed25519Sign, verify as ed25519Verify, } from "@aithos/protocol-client";
|
|
21
|
+
import { AithosAuth, AithosSDKError, memoryKeyStore, noopStore, } from "../src/index.js";
|
|
22
|
+
import { signOwnerEnvelope } from "../src/internal/envelope.js";
|
|
23
|
+
import { serializeRecoveryFile } from "../src/internal/recovery-file.js";
|
|
24
|
+
/* -------------------------------------------------------------------------- */
|
|
25
|
+
/* Test helpers */
|
|
26
|
+
/* -------------------------------------------------------------------------- */
|
|
27
|
+
/** Build a minimal AithosAuth, no network, no persistence. */
|
|
28
|
+
function makeAuth() {
|
|
29
|
+
return new AithosAuth({
|
|
30
|
+
authBaseUrl: "https://auth.test",
|
|
31
|
+
fetch: (() => {
|
|
32
|
+
throw new Error("network not expected in this test");
|
|
33
|
+
}),
|
|
34
|
+
sessionStore: noopStore(),
|
|
35
|
+
keyStore: memoryKeyStore(),
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
/** Recovery-file text + DID for a fresh BrowserIdentity. */
|
|
39
|
+
function recoveryTextFor(handle, displayName) {
|
|
40
|
+
const id = createBrowserIdentity(handle, displayName);
|
|
41
|
+
return { text: serializeRecoveryFile(id).text, did: id.did };
|
|
42
|
+
}
|
|
43
|
+
/** Inline signer wrapping a raw seed — matches what data.ts does. */
|
|
44
|
+
function inlineSigner(seed) {
|
|
45
|
+
return {
|
|
46
|
+
async sign(message) {
|
|
47
|
+
return ed25519Sign(message, seed);
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/** base64url decoder for envelope.proof.proofValue. */
|
|
52
|
+
function base64urlDecode(s) {
|
|
53
|
+
const std = s.replace(/-/g, "+").replace(/_/g, "/");
|
|
54
|
+
const padded = std + "=".repeat((4 - (std.length % 4)) % 4);
|
|
55
|
+
const bin = atob(padded);
|
|
56
|
+
const out = new Uint8Array(bin.length);
|
|
57
|
+
for (let i = 0; i < bin.length; i++)
|
|
58
|
+
out[i] = bin.charCodeAt(i);
|
|
59
|
+
return out;
|
|
60
|
+
}
|
|
61
|
+
/** Canonicalize a JS value the same way envelope.ts does — for the
|
|
62
|
+
* test that recomputes the bytes the server would verify against. */
|
|
63
|
+
function canonical(value) {
|
|
64
|
+
if (value === null)
|
|
65
|
+
return "null";
|
|
66
|
+
if (typeof value === "boolean")
|
|
67
|
+
return value ? "true" : "false";
|
|
68
|
+
if (typeof value === "number")
|
|
69
|
+
return value.toString();
|
|
70
|
+
if (typeof value === "string")
|
|
71
|
+
return JSON.stringify(value);
|
|
72
|
+
if (Array.isArray(value)) {
|
|
73
|
+
return "[" + value.map(canonical).join(",") + "]";
|
|
74
|
+
}
|
|
75
|
+
if (typeof value === "object") {
|
|
76
|
+
const obj = value;
|
|
77
|
+
const keys = Object.keys(obj).sort();
|
|
78
|
+
return ("{" +
|
|
79
|
+
keys.map((k) => JSON.stringify(k) + ":" + canonical(obj[k])).join(",") +
|
|
80
|
+
"}");
|
|
81
|
+
}
|
|
82
|
+
throw new Error(`Cannot canonicalize ${typeof value}`);
|
|
83
|
+
}
|
|
84
|
+
/* -------------------------------------------------------------------------- */
|
|
85
|
+
/* signOwnerEnvelope — internal helper */
|
|
86
|
+
/* -------------------------------------------------------------------------- */
|
|
87
|
+
describe("signOwnerEnvelope (internal helper)", () => {
|
|
88
|
+
it("signs an envelope whose signature verifies under the signer's pubkey", async () => {
|
|
89
|
+
const id = createBrowserIdentity("alice", "Alice");
|
|
90
|
+
const envelope = await signOwnerEnvelope({
|
|
91
|
+
iss: id.did,
|
|
92
|
+
aud: "https://api.example.com/v1/widgets",
|
|
93
|
+
method: "myapp.widgets.create",
|
|
94
|
+
params: { name: "Widget #1" },
|
|
95
|
+
signer: inlineSigner(id.public.seed),
|
|
96
|
+
verificationMethod: `${id.did}#public`,
|
|
97
|
+
});
|
|
98
|
+
// Re-derive the exact bytes the server would canonicalize and check.
|
|
99
|
+
const { proof, ...unsignedWithEmptyProof } = envelope;
|
|
100
|
+
const unsigned = {
|
|
101
|
+
...unsignedWithEmptyProof,
|
|
102
|
+
proof: { ...proof, proofValue: "" },
|
|
103
|
+
};
|
|
104
|
+
const bytes = new TextEncoder().encode(canonical(unsigned));
|
|
105
|
+
const sig = base64urlDecode(envelope.proof.proofValue);
|
|
106
|
+
assert.ok(ed25519Verify(sig, bytes, id.public.publicKey), "envelope signature must verify under the public-sphere pubkey");
|
|
107
|
+
});
|
|
108
|
+
it("produces an envelope conforming to spec §11.2 shape", async () => {
|
|
109
|
+
const id = createBrowserIdentity("alice", "Alice");
|
|
110
|
+
const envelope = await signOwnerEnvelope({
|
|
111
|
+
iss: id.did,
|
|
112
|
+
aud: "https://api.example.com/v1/x",
|
|
113
|
+
method: "x.do",
|
|
114
|
+
params: {},
|
|
115
|
+
signer: inlineSigner(id.public.seed),
|
|
116
|
+
verificationMethod: `${id.did}#public`,
|
|
117
|
+
});
|
|
118
|
+
assert.equal(envelope["aithos-envelope"], "0.1.0");
|
|
119
|
+
assert.equal(envelope.iss, id.did);
|
|
120
|
+
assert.equal(envelope.aud, "https://api.example.com/v1/x");
|
|
121
|
+
assert.equal(envelope.method, "x.do");
|
|
122
|
+
assert.equal(typeof envelope.iat, "number");
|
|
123
|
+
assert.equal(typeof envelope.exp, "number");
|
|
124
|
+
assert.equal(typeof envelope.nonce, "string");
|
|
125
|
+
assert.ok(envelope.params_hash.startsWith("sha256-"));
|
|
126
|
+
assert.equal(envelope.proof.type, "Ed25519Signature2020");
|
|
127
|
+
assert.equal(envelope.proof.verificationMethod, `${id.did}#public`);
|
|
128
|
+
assert.equal(typeof envelope.proof.created, "string");
|
|
129
|
+
assert.ok(envelope.proof.proofValue.length > 0);
|
|
130
|
+
});
|
|
131
|
+
it("params_hash is canonical — key order does not affect the hash", async () => {
|
|
132
|
+
const id = createBrowserIdentity("alice", "Alice");
|
|
133
|
+
const common = {
|
|
134
|
+
iss: id.did,
|
|
135
|
+
aud: "https://api.example.com/v1/x",
|
|
136
|
+
method: "x.do",
|
|
137
|
+
signer: inlineSigner(id.public.seed),
|
|
138
|
+
verificationMethod: `${id.did}#public`,
|
|
139
|
+
now: new Date("2024-01-01T00:00:00.000Z"),
|
|
140
|
+
nonce: "01HXJZK7MK8VPN0FQR5T6Y2A3Z",
|
|
141
|
+
};
|
|
142
|
+
const env1 = await signOwnerEnvelope({
|
|
143
|
+
...common,
|
|
144
|
+
params: { alpha: 1, beta: 2, gamma: [3, 4] },
|
|
145
|
+
});
|
|
146
|
+
const env2 = await signOwnerEnvelope({
|
|
147
|
+
...common,
|
|
148
|
+
params: { gamma: [3, 4], alpha: 1, beta: 2 },
|
|
149
|
+
});
|
|
150
|
+
assert.equal(env1.params_hash, env2.params_hash, "params_hash must be stable across JS object key order");
|
|
151
|
+
});
|
|
152
|
+
it("respects an explicit ttlSeconds", async () => {
|
|
153
|
+
const id = createBrowserIdentity("alice", "Alice");
|
|
154
|
+
const envelope = await signOwnerEnvelope({
|
|
155
|
+
iss: id.did,
|
|
156
|
+
aud: "https://api.example.com/v1/x",
|
|
157
|
+
method: "x.do",
|
|
158
|
+
params: {},
|
|
159
|
+
signer: inlineSigner(id.public.seed),
|
|
160
|
+
verificationMethod: `${id.did}#public`,
|
|
161
|
+
now: new Date("2024-01-01T00:00:00.000Z"),
|
|
162
|
+
ttlSeconds: 173,
|
|
163
|
+
});
|
|
164
|
+
assert.equal(envelope.exp - envelope.iat, 173);
|
|
165
|
+
});
|
|
166
|
+
it("defaults ttlSeconds to 60 — guards against drift from data.ts's prior behavior", async () => {
|
|
167
|
+
const id = createBrowserIdentity("alice", "Alice");
|
|
168
|
+
const envelope = await signOwnerEnvelope({
|
|
169
|
+
iss: id.did,
|
|
170
|
+
aud: "https://api.example.com/v1/x",
|
|
171
|
+
method: "x.do",
|
|
172
|
+
params: {},
|
|
173
|
+
signer: inlineSigner(id.public.seed),
|
|
174
|
+
verificationMethod: `${id.did}#public`,
|
|
175
|
+
now: new Date("2024-01-01T00:00:00.000Z"),
|
|
176
|
+
});
|
|
177
|
+
assert.equal(envelope.exp - envelope.iat, 60);
|
|
178
|
+
});
|
|
179
|
+
it("nonce defaults to a fresh value per call (unique across calls)", async () => {
|
|
180
|
+
const id = createBrowserIdentity("alice", "Alice");
|
|
181
|
+
const args = {
|
|
182
|
+
iss: id.did,
|
|
183
|
+
aud: "https://api.example.com/v1/x",
|
|
184
|
+
method: "x.do",
|
|
185
|
+
params: {},
|
|
186
|
+
signer: inlineSigner(id.public.seed),
|
|
187
|
+
verificationMethod: `${id.did}#public`,
|
|
188
|
+
};
|
|
189
|
+
const e1 = await signOwnerEnvelope(args);
|
|
190
|
+
const e2 = await signOwnerEnvelope(args);
|
|
191
|
+
assert.notEqual(e1.nonce, e2.nonce, "two successive calls must produce different nonces");
|
|
192
|
+
});
|
|
193
|
+
it("is deterministic when now and nonce are both injected (regression lock)", async () => {
|
|
194
|
+
// With identical inputs INCLUDING the override hooks, two calls must
|
|
195
|
+
// produce byte-for-byte identical envelopes — including the
|
|
196
|
+
// signature. This catches any future regression in canonicalization,
|
|
197
|
+
// ordering, default values, or signing path.
|
|
198
|
+
const id = createBrowserIdentity("alice", "Alice");
|
|
199
|
+
const args = {
|
|
200
|
+
iss: id.did,
|
|
201
|
+
aud: "https://api.example.com/v1/widgets",
|
|
202
|
+
method: "myapp.widgets.create",
|
|
203
|
+
params: { name: "Widget #1", count: 3, tags: ["a", "b"] },
|
|
204
|
+
signer: inlineSigner(id.public.seed),
|
|
205
|
+
verificationMethod: `${id.did}#public`,
|
|
206
|
+
now: new Date("2024-01-01T00:00:00.000Z"),
|
|
207
|
+
nonce: "01HXJZK7MK8VPN0FQR5T6Y2A3Z",
|
|
208
|
+
ttlSeconds: 120,
|
|
209
|
+
};
|
|
210
|
+
const e1 = await signOwnerEnvelope(args);
|
|
211
|
+
const e2 = await signOwnerEnvelope(args);
|
|
212
|
+
assert.deepEqual(e1, e2, "envelope must be deterministic under fixed inputs");
|
|
213
|
+
// Belt and braces: also lock the timestamp arithmetic.
|
|
214
|
+
assert.equal(e1.iat, 1704067200);
|
|
215
|
+
assert.equal(e1.exp, 1704067320);
|
|
216
|
+
assert.equal(e1.nonce, "01HXJZK7MK8VPN0FQR5T6Y2A3Z");
|
|
217
|
+
assert.equal(e1.proof.created, "2024-01-01T00:00:00.000Z");
|
|
218
|
+
assert.equal(e1.proof.verificationMethod, `${id.did}#public`);
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
/* -------------------------------------------------------------------------- */
|
|
222
|
+
/* AithosAuth.signEnvelope — public surface */
|
|
223
|
+
/* -------------------------------------------------------------------------- */
|
|
224
|
+
describe("AithosAuth.signEnvelope (public surface)", () => {
|
|
225
|
+
it("defaults to the public sphere when no sphere is passed", async () => {
|
|
226
|
+
const auth = makeAuth();
|
|
227
|
+
const { text, did } = recoveryTextFor("alice", "Alice");
|
|
228
|
+
await auth.signInWithRecovery({ file: text });
|
|
229
|
+
const envelope = await auth.signEnvelope({
|
|
230
|
+
aud: "https://api.example.com/v1/x",
|
|
231
|
+
method: "x.do",
|
|
232
|
+
params: { ok: true },
|
|
233
|
+
});
|
|
234
|
+
assert.equal(envelope.iss, did);
|
|
235
|
+
assert.equal(envelope.proof.verificationMethod, `${did}#public`);
|
|
236
|
+
});
|
|
237
|
+
it("honors explicit sphere overrides (root / public / circle / self)", async () => {
|
|
238
|
+
const auth = makeAuth();
|
|
239
|
+
const { text, did } = recoveryTextFor("alice", "Alice");
|
|
240
|
+
await auth.signInWithRecovery({ file: text });
|
|
241
|
+
for (const sphere of ["root", "public", "circle", "self"]) {
|
|
242
|
+
const envelope = await auth.signEnvelope({
|
|
243
|
+
aud: "https://api.example.com/v1/x",
|
|
244
|
+
method: "x.do",
|
|
245
|
+
params: {},
|
|
246
|
+
sphere,
|
|
247
|
+
});
|
|
248
|
+
assert.equal(envelope.proof.verificationMethod, `${did}#${sphere}`, `verificationMethod must end with #${sphere}`);
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
it("throws auth_not_signed_in when no owner is loaded", async () => {
|
|
252
|
+
const auth = makeAuth();
|
|
253
|
+
await assert.rejects(() => auth.signEnvelope({
|
|
254
|
+
aud: "https://api.example.com/v1/x",
|
|
255
|
+
method: "x.do",
|
|
256
|
+
params: {},
|
|
257
|
+
}), (e) => e instanceof AithosSDKError &&
|
|
258
|
+
e.code === "auth_not_signed_in");
|
|
259
|
+
});
|
|
260
|
+
it("throws auth_invalid_sphere when an unknown sphere is passed (untyped caller)", async () => {
|
|
261
|
+
const auth = makeAuth();
|
|
262
|
+
const { text } = recoveryTextFor("alice", "Alice");
|
|
263
|
+
await auth.signInWithRecovery({ file: text });
|
|
264
|
+
await assert.rejects(() => auth.signEnvelope({
|
|
265
|
+
aud: "https://api.example.com/v1/x",
|
|
266
|
+
method: "x.do",
|
|
267
|
+
params: {},
|
|
268
|
+
// Untyped callers (e.g. plain JS) could pass anything.
|
|
269
|
+
sphere: "bogus",
|
|
270
|
+
}), (e) => e instanceof AithosSDKError &&
|
|
271
|
+
e.code === "auth_invalid_sphere");
|
|
272
|
+
});
|
|
273
|
+
it("envelope ttlSeconds defaults to 60 — non-regression of internal default", async () => {
|
|
274
|
+
const auth = makeAuth();
|
|
275
|
+
const { text } = recoveryTextFor("alice", "Alice");
|
|
276
|
+
await auth.signInWithRecovery({ file: text });
|
|
277
|
+
const envelope = await auth.signEnvelope({
|
|
278
|
+
aud: "https://api.example.com/v1/x",
|
|
279
|
+
method: "x.do",
|
|
280
|
+
params: {},
|
|
281
|
+
});
|
|
282
|
+
assert.equal(envelope.exp - envelope.iat, 60);
|
|
283
|
+
});
|
|
284
|
+
it("envelope ttlSeconds is honored when provided", async () => {
|
|
285
|
+
const auth = makeAuth();
|
|
286
|
+
const { text } = recoveryTextFor("alice", "Alice");
|
|
287
|
+
await auth.signInWithRecovery({ file: text });
|
|
288
|
+
const envelope = await auth.signEnvelope({
|
|
289
|
+
aud: "https://api.example.com/v1/x",
|
|
290
|
+
method: "x.do",
|
|
291
|
+
params: {},
|
|
292
|
+
ttlSeconds: 240,
|
|
293
|
+
});
|
|
294
|
+
assert.equal(envelope.exp - envelope.iat, 240);
|
|
295
|
+
});
|
|
296
|
+
it("envelope signs with the correct sphere key (sig verifies under that pubkey)", async () => {
|
|
297
|
+
const auth = makeAuth();
|
|
298
|
+
const id = createBrowserIdentity("alice", "Alice");
|
|
299
|
+
const { text } = serializeRecoveryFile(id);
|
|
300
|
+
await auth.signInWithRecovery({ file: text });
|
|
301
|
+
const envelope = await auth.signEnvelope({
|
|
302
|
+
aud: "https://api.example.com/v1/x",
|
|
303
|
+
method: "x.do",
|
|
304
|
+
params: { x: 1 },
|
|
305
|
+
sphere: "circle",
|
|
306
|
+
});
|
|
307
|
+
// Reconstruct what the server would canonicalize-and-verify.
|
|
308
|
+
const { proof, ...unsignedWithEmptyProof } = envelope;
|
|
309
|
+
const unsigned = {
|
|
310
|
+
...unsignedWithEmptyProof,
|
|
311
|
+
proof: { ...proof, proofValue: "" },
|
|
312
|
+
};
|
|
313
|
+
const bytes = new TextEncoder().encode(canonical(unsigned));
|
|
314
|
+
const sig = base64urlDecode(envelope.proof.proofValue);
|
|
315
|
+
assert.ok(ed25519Verify(sig, bytes, id.circle.publicKey), "envelope signed with sphere 'circle' must verify under circle.publicKey");
|
|
316
|
+
});
|
|
317
|
+
});
|
|
318
|
+
//# sourceMappingURL=envelope.test.js.map
|