@aroha-sdk/core 1.0.0 → 1.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/dist/crypto/encryption.d.ts +39 -0
- package/dist/crypto/encryption.d.ts.map +1 -0
- package/dist/crypto/encryption.js +88 -0
- package/dist/crypto/encryption.js.map +1 -0
- package/dist/crypto/index.d.ts +3 -0
- package/dist/crypto/index.d.ts.map +1 -0
- package/dist/crypto/index.js +3 -0
- package/dist/crypto/index.js.map +1 -0
- package/dist/crypto/signing.d.ts +43 -0
- package/dist/crypto/signing.d.ts.map +1 -0
- package/dist/crypto/signing.js +80 -0
- package/dist/crypto/signing.js.map +1 -0
- package/dist/identity/credentials.d.ts +81 -0
- package/dist/identity/credentials.d.ts.map +1 -0
- package/dist/identity/credentials.js +82 -0
- package/dist/identity/credentials.js.map +1 -0
- package/dist/identity/did-cache.d.ts +46 -0
- package/dist/identity/did-cache.d.ts.map +1 -0
- package/dist/identity/did-cache.js +90 -0
- package/dist/identity/did-cache.js.map +1 -0
- package/dist/identity/did.d.ts +139 -0
- package/dist/identity/did.d.ts.map +1 -0
- package/dist/identity/did.js +291 -0
- package/dist/identity/did.js.map +1 -0
- package/dist/identity/index.d.ts +5 -0
- package/dist/identity/index.d.ts.map +1 -0
- package/dist/identity/index.js +5 -0
- package/dist/identity/index.js.map +1 -0
- package/dist/identity/web-did.d.ts +131 -0
- package/dist/identity/web-did.d.ts.map +1 -0
- package/dist/identity/web-did.js +338 -0
- package/dist/identity/web-did.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/messages/envelope.d.ts +102 -0
- package/dist/messages/envelope.d.ts.map +1 -0
- package/dist/messages/envelope.js +106 -0
- package/dist/messages/envelope.js.map +1 -0
- package/dist/messages/idempotency.d.ts +61 -0
- package/dist/messages/idempotency.d.ts.map +1 -0
- package/dist/messages/idempotency.js +93 -0
- package/dist/messages/idempotency.js.map +1 -0
- package/dist/messages/index.d.ts +5 -0
- package/dist/messages/index.d.ts.map +1 -0
- package/dist/messages/index.js +5 -0
- package/dist/messages/index.js.map +1 -0
- package/dist/messages/nonce.d.ts +60 -0
- package/dist/messages/nonce.d.ts.map +1 -0
- package/dist/messages/nonce.js +94 -0
- package/dist/messages/nonce.js.map +1 -0
- package/dist/messages/types.d.ts +302 -0
- package/dist/messages/types.d.ts.map +1 -0
- package/dist/messages/types.js +38 -0
- package/dist/messages/types.js.map +1 -0
- package/dist/transport/client.d.ts +79 -0
- package/dist/transport/client.d.ts.map +1 -0
- package/dist/transport/client.js +182 -0
- package/dist/transport/client.js.map +1 -0
- package/dist/transport/http-utils.d.ts +3 -0
- package/dist/transport/http-utils.d.ts.map +1 -0
- package/dist/transport/http-utils.js +27 -0
- package/dist/transport/http-utils.js.map +1 -0
- package/dist/transport/index.d.ts +4 -0
- package/dist/transport/index.d.ts.map +1 -0
- package/dist/transport/index.js +4 -0
- package/dist/transport/index.js.map +1 -0
- package/dist/transport/server.d.ts +123 -0
- package/dist/transport/server.d.ts.map +1 -0
- package/dist/transport/server.js +251 -0
- package/dist/transport/server.js.map +1 -0
- package/package.json +5 -1
- package/tsconfig.json +0 -10
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Aroha Web-Native Identity — did:aroha-web:
|
|
3
|
+
*
|
|
4
|
+
* A DNS-anchored DID method that requires NO central Aroha registry.
|
|
5
|
+
* Identity is verified by TWO independent channels simultaneously:
|
|
6
|
+
*
|
|
7
|
+
* 1. HTTPS — DID Document served at:
|
|
8
|
+
* https://{domain}/.well-known/aroha/agents/{path}/did.json
|
|
9
|
+
*
|
|
10
|
+
* 2. DNS TXT — Key-commitment record at:
|
|
11
|
+
* _aroha.{domain} IN TXT "v=aroha1; path={path}; keyhash={sha256 of pubkey}"
|
|
12
|
+
*
|
|
13
|
+
* Both channels must agree. Domain hijacking via HTTPS alone is insufficient —
|
|
14
|
+
* the attacker would also need to control DNS to forge the key-commitment.
|
|
15
|
+
* This is a meaningful security upgrade over single-channel HTTPS identity
|
|
16
|
+
* (did:wba, did:web).
|
|
17
|
+
*
|
|
18
|
+
* Key rotation:
|
|
19
|
+
* Rotations are cryptographically chained — the new key is signed by the old
|
|
20
|
+
* key and a 24-hour cool-down window is enforced before the new key is trusted.
|
|
21
|
+
* The rotation record is embedded in the DID Document under `keyHistory`.
|
|
22
|
+
*
|
|
23
|
+
* DID format:
|
|
24
|
+
* did:aroha-web:{domain}[:{path}]
|
|
25
|
+
* e.g. did:aroha-web:stripe.com:payments-agent
|
|
26
|
+
* did:aroha-web:internal.example.corp:invoicing
|
|
27
|
+
*
|
|
28
|
+
* Resolution produces the same DIDDocument format as did:aroha: — full
|
|
29
|
+
* interoperability with the rest of the Aroha stack.
|
|
30
|
+
*/
|
|
31
|
+
import * as ed from "@noble/ed25519";
|
|
32
|
+
import { sha256 } from "@noble/hashes/sha256";
|
|
33
|
+
import { sha512 } from "@noble/hashes/sha512";
|
|
34
|
+
import { bytesToHex } from "@noble/hashes/utils";
|
|
35
|
+
import { toMultibase, fromMultibase, } from "./did.js";
|
|
36
|
+
ed.etc.sha512Sync = (...m) => sha512(...m);
|
|
37
|
+
// ─── DID parsing ──────────────────────────────────────────────────────────────
|
|
38
|
+
/** Parse `did:aroha-web:domain[:path]` into its components. */
|
|
39
|
+
export function parseWebDID(did) {
|
|
40
|
+
const prefix = "did:aroha-web:";
|
|
41
|
+
if (!did.startsWith(prefix)) {
|
|
42
|
+
throw new Error(`Not a did:aroha-web: identifier: ${did}`);
|
|
43
|
+
}
|
|
44
|
+
const rest = did.slice(prefix.length);
|
|
45
|
+
const colonIdx = rest.indexOf(":");
|
|
46
|
+
if (colonIdx === -1) {
|
|
47
|
+
return { domain: rest, path: "agent" };
|
|
48
|
+
}
|
|
49
|
+
return {
|
|
50
|
+
domain: rest.slice(0, colonIdx),
|
|
51
|
+
path: rest.slice(colonIdx + 1).replace(/:/g, "/"),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
export function buildWebDID(domain, path) {
|
|
55
|
+
const normalised = path.replace(/\//g, ":");
|
|
56
|
+
return `did:aroha-web:${domain}:${normalised}`;
|
|
57
|
+
}
|
|
58
|
+
export function isWebDID(did) {
|
|
59
|
+
return did.startsWith("did:aroha-web:");
|
|
60
|
+
}
|
|
61
|
+
// ─── Well-known path ──────────────────────────────────────────────────────────
|
|
62
|
+
/**
|
|
63
|
+
* The HTTP path at which the DID Document should be served.
|
|
64
|
+
* e.g. `did:aroha-web:stripe.com:payments` → `/.well-known/aroha/agents/payments/did.json`
|
|
65
|
+
*/
|
|
66
|
+
export function wellKnownPath(did) {
|
|
67
|
+
const { path } = parseWebDID(did);
|
|
68
|
+
return `/.well-known/aroha/agents/${path}/did.json`;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* The full HTTPS URL for a given did:aroha-web: identifier.
|
|
72
|
+
*/
|
|
73
|
+
export function wellKnownUrl(did) {
|
|
74
|
+
const { domain, path } = parseWebDID(did);
|
|
75
|
+
return `https://${domain}/.well-known/aroha/agents/${path}/did.json`;
|
|
76
|
+
}
|
|
77
|
+
// ─── DNS TXT record ───────────────────────────────────────────────────────────
|
|
78
|
+
/**
|
|
79
|
+
* Returns the DNS TXT record VALUE (not the full DNS record) for the
|
|
80
|
+
* key-commitment. Publish at: `_aroha.{domain} IN TXT "{this value}"`
|
|
81
|
+
*
|
|
82
|
+
* Format: `v=aroha1; path={path}; keyhash={sha256hex}`
|
|
83
|
+
*/
|
|
84
|
+
export function dnsTXTValue(did, publicKey) {
|
|
85
|
+
const { path } = parseWebDID(did);
|
|
86
|
+
const keyhash = bytesToHex(sha256(publicKey));
|
|
87
|
+
return `v=aroha1; path=${path}; keyhash=${keyhash}`;
|
|
88
|
+
}
|
|
89
|
+
/** Parse a DNS TXT value back to its fields. Returns null if invalid. */
|
|
90
|
+
export function parseDNSTXT(txt) {
|
|
91
|
+
if (!txt.includes("v=aroha1"))
|
|
92
|
+
return null;
|
|
93
|
+
const fields = {};
|
|
94
|
+
for (const part of txt.split(";")) {
|
|
95
|
+
const eq = part.indexOf("=");
|
|
96
|
+
if (eq === -1)
|
|
97
|
+
continue;
|
|
98
|
+
fields[part.slice(0, eq).trim()] = part.slice(eq + 1).trim();
|
|
99
|
+
}
|
|
100
|
+
if (!fields.path || !fields.keyhash)
|
|
101
|
+
return null;
|
|
102
|
+
return { path: fields.path, keyhash: fields.keyhash };
|
|
103
|
+
}
|
|
104
|
+
// ─── Key commitment hash ──────────────────────────────────────────────────────
|
|
105
|
+
export function keyCommitmentHash(publicKey) {
|
|
106
|
+
return bytesToHex(sha256(publicKey));
|
|
107
|
+
}
|
|
108
|
+
// ─── Generate ─────────────────────────────────────────────────────────────────
|
|
109
|
+
/**
|
|
110
|
+
* Generate a new did:aroha-web: identity.
|
|
111
|
+
*
|
|
112
|
+
* Returns the key pair, the DID Document to serve at the well-known path,
|
|
113
|
+
* the DNS TXT value to publish, and the well-known URL.
|
|
114
|
+
*
|
|
115
|
+
* @param domain The company domain (e.g. "stripe.com")
|
|
116
|
+
* @param path Agent identifier within the domain (e.g. "payments-agent")
|
|
117
|
+
* @param endpoint The Aroha HTTP endpoint URL (e.g. "https://agents.stripe.com/aroha/v1")
|
|
118
|
+
*/
|
|
119
|
+
export async function generateWebAgent(domain, path, endpoint) {
|
|
120
|
+
const privateKey = ed.utils.randomPrivateKey();
|
|
121
|
+
const publicKey = await ed.getPublicKeyAsync(privateKey);
|
|
122
|
+
const did = buildWebDID(domain, path);
|
|
123
|
+
const keyId = `${did}#key-1`;
|
|
124
|
+
const now = new Date().toISOString();
|
|
125
|
+
const agentEndpoint = endpoint ?? `https://${domain}/aroha/v1`;
|
|
126
|
+
const webDoc = {
|
|
127
|
+
"@context": [
|
|
128
|
+
"https://www.w3.org/ns/did/v1",
|
|
129
|
+
"https://w3id.org/security/suites/ed25519-2020/v1",
|
|
130
|
+
"https://aroha-labs.com/contexts/aroha-web/v1",
|
|
131
|
+
],
|
|
132
|
+
id: did,
|
|
133
|
+
verificationMethod: [
|
|
134
|
+
{
|
|
135
|
+
id: keyId,
|
|
136
|
+
type: "Ed25519VerificationKey2020",
|
|
137
|
+
controller: did,
|
|
138
|
+
publicKeyMultibase: toMultibase(publicKey),
|
|
139
|
+
},
|
|
140
|
+
],
|
|
141
|
+
authentication: [keyId],
|
|
142
|
+
assertionMethod: [keyId],
|
|
143
|
+
keyAgreement: [keyId],
|
|
144
|
+
service: [
|
|
145
|
+
{
|
|
146
|
+
id: `${did}#aroha`,
|
|
147
|
+
type: "ArohaEndpoint",
|
|
148
|
+
serviceEndpoint: agentEndpoint,
|
|
149
|
+
},
|
|
150
|
+
],
|
|
151
|
+
created: now,
|
|
152
|
+
updated: now,
|
|
153
|
+
arohaWeb: {
|
|
154
|
+
domain,
|
|
155
|
+
path,
|
|
156
|
+
keyCommitmentHash: keyCommitmentHash(publicKey),
|
|
157
|
+
keyHistory: [],
|
|
158
|
+
},
|
|
159
|
+
};
|
|
160
|
+
const txt = dnsTXTValue(did, publicKey);
|
|
161
|
+
const url = wellKnownUrl(did);
|
|
162
|
+
return {
|
|
163
|
+
did,
|
|
164
|
+
privateKey,
|
|
165
|
+
publicKey,
|
|
166
|
+
document: webDoc,
|
|
167
|
+
webDocument: webDoc,
|
|
168
|
+
dnsTXTRecord: txt,
|
|
169
|
+
wellKnownUrl: url,
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
// ─── Key rotation ──────────────────────────────────────────────────────────────
|
|
173
|
+
/**
|
|
174
|
+
* Rotate to a new key pair. The old key signs a rotation record that is
|
|
175
|
+
* embedded in the new DID Document. The new key is not trusted until
|
|
176
|
+
* `coolDownHours` (default 24h) after the rotation is announced.
|
|
177
|
+
*
|
|
178
|
+
* Publish the returned `webDocument` at the well-known URL and update the
|
|
179
|
+
* DNS TXT record with `dnsTXTRecord` to complete the rotation.
|
|
180
|
+
*/
|
|
181
|
+
export async function rotateKey(current, coolDownHours = 24) {
|
|
182
|
+
const newPrivateKey = ed.utils.randomPrivateKey();
|
|
183
|
+
const newPublicKey = await ed.getPublicKeyAsync(newPrivateKey);
|
|
184
|
+
const oldPubKeyMultibase = toMultibase(current.publicKey);
|
|
185
|
+
const now = new Date();
|
|
186
|
+
const trustAfter = new Date(now.getTime() + coolDownHours * 3_600_000);
|
|
187
|
+
// Rotation payload: predecessorKey ∥ newKeyHash ∥ rotatedAt
|
|
188
|
+
const newKeyHash = keyCommitmentHash(newPublicKey);
|
|
189
|
+
const payload = new TextEncoder().encode(oldPubKeyMultibase + newKeyHash + now.toISOString());
|
|
190
|
+
const sig = await ed.signAsync(payload, current.privateKey);
|
|
191
|
+
const rotation = {
|
|
192
|
+
rotatedAt: now.toISOString(),
|
|
193
|
+
trustAfter: trustAfter.toISOString(),
|
|
194
|
+
predecessorKey: oldPubKeyMultibase,
|
|
195
|
+
newKeyHash,
|
|
196
|
+
predecessorSignature: Buffer.from(sig).toString("base64url"),
|
|
197
|
+
};
|
|
198
|
+
const { domain, path } = current.webDocument.arohaWeb;
|
|
199
|
+
const did = buildWebDID(domain, path);
|
|
200
|
+
const keyId = `${did}#key-1`;
|
|
201
|
+
const ts = now.toISOString();
|
|
202
|
+
const newDoc = {
|
|
203
|
+
...current.webDocument,
|
|
204
|
+
verificationMethod: [
|
|
205
|
+
{
|
|
206
|
+
id: keyId,
|
|
207
|
+
type: "Ed25519VerificationKey2020",
|
|
208
|
+
controller: did,
|
|
209
|
+
publicKeyMultibase: toMultibase(newPublicKey),
|
|
210
|
+
},
|
|
211
|
+
],
|
|
212
|
+
updated: ts,
|
|
213
|
+
arohaWeb: {
|
|
214
|
+
...current.webDocument.arohaWeb,
|
|
215
|
+
keyCommitmentHash: keyCommitmentHash(newPublicKey),
|
|
216
|
+
keyHistory: [rotation, ...current.webDocument.arohaWeb.keyHistory],
|
|
217
|
+
},
|
|
218
|
+
};
|
|
219
|
+
return {
|
|
220
|
+
did,
|
|
221
|
+
privateKey: newPrivateKey,
|
|
222
|
+
publicKey: newPublicKey,
|
|
223
|
+
document: newDoc,
|
|
224
|
+
webDocument: newDoc,
|
|
225
|
+
dnsTXTRecord: dnsTXTValue(did, newPublicKey),
|
|
226
|
+
wellKnownUrl: wellKnownUrl(did),
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
// ─── Resolve ──────────────────────────────────────────────────────────────────
|
|
230
|
+
/**
|
|
231
|
+
* Resolve a did:aroha-web: identifier.
|
|
232
|
+
*
|
|
233
|
+
* Fetches the DID Document over HTTPS and, if `verifyDNS` is true,
|
|
234
|
+
* also verifies the DNS TXT key-commitment. Both must match for full
|
|
235
|
+
* two-factor verification.
|
|
236
|
+
*
|
|
237
|
+
* In Node.js server environments, pass a custom `dnsResolver` to perform
|
|
238
|
+
* the DNS TXT lookup. In browser or edge environments, set `verifyDNS: false`
|
|
239
|
+
* (single-channel HTTPS-only, same security as did:wba).
|
|
240
|
+
*
|
|
241
|
+
* @param did The did:aroha-web: identifier to resolve
|
|
242
|
+
* @param verifyDNS Whether to check the DNS TXT record (default: true)
|
|
243
|
+
* @param dnsResolver Optional custom DNS TXT resolver
|
|
244
|
+
*/
|
|
245
|
+
export async function resolveWebDID(did, verifyDNS = true, dnsResolver, fetchTimeoutMs = 10_000) {
|
|
246
|
+
const url = wellKnownUrl(did);
|
|
247
|
+
// ── Step 1: Fetch DID Document over HTTPS ─────────────────────────────────
|
|
248
|
+
const ctrl = new AbortController();
|
|
249
|
+
const timer = setTimeout(() => ctrl.abort(), fetchTimeoutMs);
|
|
250
|
+
let res;
|
|
251
|
+
try {
|
|
252
|
+
res = await fetch(url, {
|
|
253
|
+
headers: { Accept: "application/json" },
|
|
254
|
+
signal: ctrl.signal,
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
finally {
|
|
258
|
+
clearTimeout(timer);
|
|
259
|
+
}
|
|
260
|
+
if (!res.ok) {
|
|
261
|
+
throw new Error(`Failed to resolve ${did}: HTTP ${res.status} from ${url}`);
|
|
262
|
+
}
|
|
263
|
+
const doc = await res.json();
|
|
264
|
+
if (doc.id !== did) {
|
|
265
|
+
throw new Error(`DID mismatch: document claims ${doc.id}, expected ${did}`);
|
|
266
|
+
}
|
|
267
|
+
const activeKey = fromMultibase(doc.verificationMethod[0].publicKeyMultibase);
|
|
268
|
+
// ── Step 2: Verify all rotation records in keyHistory ────────────────────
|
|
269
|
+
if (doc.arohaWeb?.keyHistory?.length > 0) {
|
|
270
|
+
for (const rotation of doc.arohaWeb.keyHistory) {
|
|
271
|
+
const rotationValid = await verifyKeyRotation(rotation);
|
|
272
|
+
if (!rotationValid) {
|
|
273
|
+
throw new Error(`DID ${did}: key rotation record (rotatedAt ${rotation.rotatedAt}) has invalid predecessor signature`);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
// ── Step 4: Check key rotation cool-down ─────────────────────────────────
|
|
278
|
+
let keyTrusted = true;
|
|
279
|
+
let trustReason;
|
|
280
|
+
if (doc.arohaWeb?.keyHistory?.length > 0) {
|
|
281
|
+
const latestRotation = doc.arohaWeb.keyHistory[0];
|
|
282
|
+
const trustAfter = new Date(latestRotation.trustAfter);
|
|
283
|
+
if (new Date() < trustAfter) {
|
|
284
|
+
keyTrusted = false;
|
|
285
|
+
trustReason = `Key rotation cool-down active until ${latestRotation.trustAfter}`;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
// ── Step 5: DNS TXT key-commitment verification ────────────────────────────
|
|
289
|
+
let dnsVerified = false;
|
|
290
|
+
if (verifyDNS) {
|
|
291
|
+
const { domain, path } = parseWebDID(did);
|
|
292
|
+
let txtRecords = [];
|
|
293
|
+
if (dnsResolver) {
|
|
294
|
+
txtRecords = await dnsResolver(domain).catch(() => []);
|
|
295
|
+
}
|
|
296
|
+
else if (typeof globalThis["Deno"] !== "undefined") {
|
|
297
|
+
// Deno DNS API
|
|
298
|
+
try {
|
|
299
|
+
const denoGlobal = globalThis.Deno;
|
|
300
|
+
const records = await denoGlobal
|
|
301
|
+
.resolveDns(`_aroha.${domain}`, "TXT");
|
|
302
|
+
txtRecords = records.flat();
|
|
303
|
+
}
|
|
304
|
+
catch { /* DNS unavailable — fall back to HTTPS-only */ }
|
|
305
|
+
}
|
|
306
|
+
// Node.js: caller must pass dnsResolver (avoids bundling dns module in core)
|
|
307
|
+
for (const txt of txtRecords) {
|
|
308
|
+
const parsed = parseDNSTXT(txt);
|
|
309
|
+
if (!parsed)
|
|
310
|
+
continue;
|
|
311
|
+
if (parsed.path !== path)
|
|
312
|
+
continue;
|
|
313
|
+
const expectedHash = keyCommitmentHash(activeKey);
|
|
314
|
+
if (parsed.keyhash === expectedHash) {
|
|
315
|
+
dnsVerified = true;
|
|
316
|
+
break;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
return { document: doc, dnsVerified, keyTrusted, trustReason };
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Verify a key rotation record — confirms the predecessor key signed the
|
|
324
|
+
* rotation event voluntarily (prevents unauthorized key replacement).
|
|
325
|
+
*/
|
|
326
|
+
export async function verifyKeyRotation(rotation) {
|
|
327
|
+
try {
|
|
328
|
+
const predKey = fromMultibase(rotation.predecessorKey);
|
|
329
|
+
const newHash = rotation.newKeyHash;
|
|
330
|
+
const payload = new TextEncoder().encode(rotation.predecessorKey + newHash + rotation.rotatedAt);
|
|
331
|
+
const sig = Buffer.from(rotation.predecessorSignature, "base64url");
|
|
332
|
+
return await ed.verifyAsync(sig, payload, predKey);
|
|
333
|
+
}
|
|
334
|
+
catch {
|
|
335
|
+
return false;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
//# sourceMappingURL=web-did.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"web-did.js","sourceRoot":"","sources":["../../src/identity/web-did.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,KAAK,EAAE,MAAM,gBAAgB,CAAC;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAe,MAAM,qBAAqB,CAAC;AAC9D,OAAO,EAKL,WAAW,EACX,aAAa,GACd,MAAM,UAAU,CAAC;AAElB,EAAE,CAAC,GAAG,CAAC,UAAU,GAAG,CAAC,GAAG,CAA4B,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;AAqCtE,iFAAiF;AAEjF,+DAA+D;AAC/D,MAAM,UAAU,WAAW,CAAC,GAAW;IACrC,MAAM,MAAM,GAAG,gBAAgB,CAAC;IAChC,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CAAC,oCAAoC,GAAG,EAAE,CAAC,CAAC;IAC7D,CAAC;IACD,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACtC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACnC,IAAI,QAAQ,KAAK,CAAC,CAAC,EAAE,CAAC;QACpB,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;IACzC,CAAC;IACD,OAAO;QACL,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC;QAC/B,IAAI,EAAI,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC;KACpD,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,MAAc,EAAE,IAAY;IACtD,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAC5C,OAAO,iBAAiB,MAAM,IAAI,UAAU,EAAE,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,GAAW;IAClC,OAAO,GAAG,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC;AAC1C,CAAC;AAED,iFAAiF;AAEjF;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,GAAW;IACvC,MAAM,EAAE,IAAI,EAAE,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;IAClC,OAAO,6BAA6B,IAAI,WAAW,CAAC;AACtD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,GAAW;IACtC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;IAC1C,OAAO,WAAW,MAAM,6BAA6B,IAAI,WAAW,CAAC;AACvE,CAAC;AAED,iFAAiF;AAEjF;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CAAC,GAAW,EAAE,SAAqB;IAC5D,MAAM,EAAE,IAAI,EAAE,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;IAClC,MAAM,OAAO,GAAI,UAAU,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC;IAC/C,OAAO,kBAAkB,IAAI,aAAa,OAAO,EAAE,CAAC;AACtD,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,WAAW,CAAC,GAAW;IACrC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC;QAAE,OAAO,IAAI,CAAC;IAC3C,MAAM,MAAM,GAA2B,EAAE,CAAC;IAC1C,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QAClC,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC7B,IAAI,EAAE,KAAK,CAAC,CAAC;YAAE,SAAS;QACxB,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC/D,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IACjD,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC;AACxD,CAAC;AAED,iFAAiF;AAEjF,MAAM,UAAU,iBAAiB,CAAC,SAAqB;IACrD,OAAO,UAAU,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC;AACvC,CAAC;AAED,iFAAiF;AAEjF;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,MAAc,EACd,IAAY,EACZ,QAAiB;IAEjB,MAAM,UAAU,GAAG,EAAE,CAAC,KAAK,CAAC,gBAAgB,EAAE,CAAC;IAC/C,MAAM,SAAS,GAAI,MAAM,EAAE,CAAC,iBAAiB,CAAC,UAAU,CAAC,CAAC;IAE1D,MAAM,GAAG,GAAM,WAAW,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACzC,MAAM,KAAK,GAAI,GAAG,GAAG,QAAQ,CAAC;IAC9B,MAAM,GAAG,GAAM,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACxC,MAAM,aAAa,GAAG,QAAQ,IAAI,WAAW,MAAM,WAAW,CAAC;IAE/D,MAAM,MAAM,GAAmB;QAC7B,UAAU,EAAE;YACV,8BAA8B;YAC9B,kDAAkD;YAClD,8CAA8C;SAC/C;QACD,EAAE,EAAE,GAAG;QACP,kBAAkB,EAAE;YAClB;gBACE,EAAE,EAAkB,KAAK;gBACzB,IAAI,EAAgB,4BAA4B;gBAChD,UAAU,EAAU,GAAG;gBACvB,kBAAkB,EAAE,WAAW,CAAC,SAAS,CAAC;aAC3C;SACF;QACD,cAAc,EAAI,CAAC,KAAK,CAAC;QACzB,eAAe,EAAG,CAAC,KAAK,CAAC;QACzB,YAAY,EAAM,CAAC,KAAK,CAAC;QACzB,OAAO,EAAE;YACP;gBACE,EAAE,EAAe,GAAG,GAAG,QAAQ;gBAC/B,IAAI,EAAa,eAAe;gBAChC,eAAe,EAAE,aAAa;aAC/B;SACF;QACD,OAAO,EAAE,GAAG;QACZ,OAAO,EAAE,GAAG;QACZ,QAAQ,EAAE;YACR,MAAM;YACN,IAAI;YACJ,iBAAiB,EAAE,iBAAiB,CAAC,SAAS,CAAC;YAC/C,UAAU,EAAE,EAAE;SACf;KACF,CAAC;IAEF,MAAM,GAAG,GAAG,WAAW,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;IACxC,MAAM,GAAG,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;IAE9B,OAAO;QACL,GAAG;QACH,UAAU;QACV,SAAS;QACT,QAAQ,EAAO,MAAM;QACrB,WAAW,EAAI,MAAM;QACrB,YAAY,EAAG,GAAG;QAClB,YAAY,EAAG,GAAG;KACnB,CAAC;AACJ,CAAC;AAED,kFAAkF;AAElF;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,OAAwB,EACxB,aAAa,GAAG,EAAE;IAElB,MAAM,aAAa,GAAG,EAAE,CAAC,KAAK,CAAC,gBAAgB,EAAE,CAAC;IAClD,MAAM,YAAY,GAAI,MAAM,EAAE,CAAC,iBAAiB,CAAC,aAAa,CAAC,CAAC;IAEhE,MAAM,kBAAkB,GAAG,WAAW,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAC1D,MAAM,GAAG,GAAS,IAAI,IAAI,EAAE,CAAC;IAC7B,MAAM,UAAU,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,aAAa,GAAG,SAAS,CAAC,CAAC;IAEvE,4DAA4D;IAC5D,MAAM,UAAU,GAAG,iBAAiB,CAAC,YAAY,CAAC,CAAC;IACnD,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CACtC,kBAAkB,GAAG,UAAU,GAAG,GAAG,CAAC,WAAW,EAAE,CACpD,CAAC;IACF,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;IAE5D,MAAM,QAAQ,GAAsB;QAClC,SAAS,EAAa,GAAG,CAAC,WAAW,EAAE;QACvC,UAAU,EAAY,UAAU,CAAC,WAAW,EAAE;QAC9C,cAAc,EAAQ,kBAAkB;QACxC,UAAU;QACV,oBAAoB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC;KAC7D,CAAC;IAEF,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,WAAW,CAAC,QAAQ,CAAC;IACtD,MAAM,GAAG,GAAK,WAAW,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACxC,MAAM,KAAK,GAAG,GAAG,GAAG,QAAQ,CAAC;IAC7B,MAAM,EAAE,GAAM,GAAG,CAAC,WAAW,EAAE,CAAC;IAEhC,MAAM,MAAM,GAAmB;QAC7B,GAAG,OAAO,CAAC,WAAW;QACtB,kBAAkB,EAAE;YAClB;gBACE,EAAE,EAAkB,KAAK;gBACzB,IAAI,EAAgB,4BAA4B;gBAChD,UAAU,EAAU,GAAG;gBACvB,kBAAkB,EAAE,WAAW,CAAC,YAAY,CAAC;aAC9C;SACF;QACD,OAAO,EAAE,EAAE;QACX,QAAQ,EAAE;YACR,GAAG,OAAO,CAAC,WAAW,CAAC,QAAQ;YAC/B,iBAAiB,EAAE,iBAAiB,CAAC,YAAY,CAAC;YAClD,UAAU,EAAS,CAAC,QAAQ,EAAE,GAAG,OAAO,CAAC,WAAW,CAAC,QAAQ,CAAC,UAAU,CAAC;SAC1E;KACF,CAAC;IAEF,OAAO;QACL,GAAG;QACH,UAAU,EAAI,aAAa;QAC3B,SAAS,EAAK,YAAY;QAC1B,QAAQ,EAAM,MAAM;QACpB,WAAW,EAAG,MAAM;QACpB,YAAY,EAAE,WAAW,CAAC,GAAG,EAAE,YAAY,CAAC;QAC5C,YAAY,EAAE,YAAY,CAAC,GAAG,CAAC;KAChC,CAAC;AACJ,CAAC;AAED,iFAAiF;AAEjF;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,GAAW,EACX,SAAS,GAAG,IAAI,EAChB,WAAmD,EACnD,cAAc,GAAG,MAAM;IAEvB,MAAM,GAAG,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;IAE9B,6EAA6E;IAC7E,MAAM,IAAI,GAAG,IAAI,eAAe,EAAE,CAAC;IACnC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,cAAc,CAAC,CAAC;IAC7D,IAAI,GAAa,CAAC;IAClB,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;YACrB,OAAO,EAAE,EAAE,MAAM,EAAE,kBAAkB,EAAE;YACvC,MAAM,EAAE,IAAI,CAAC,MAAM;SACpB,CAAC,CAAC;IACL,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,KAAK,CAAC,CAAC;IACtB,CAAC;IACD,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,qBAAqB,GAAG,UAAU,GAAG,CAAC,MAAM,SAAS,GAAG,EAAE,CAAC,CAAC;IAC9E,CAAC;IACD,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,IAAI,EAAoB,CAAC;IAE/C,IAAI,GAAG,CAAC,EAAE,KAAK,GAAG,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CAAC,iCAAiC,GAAG,CAAC,EAAE,cAAc,GAAG,EAAE,CAAC,CAAC;IAC9E,CAAC;IAED,MAAM,SAAS,GAAG,aAAa,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC;IAE9E,4EAA4E;IAC5E,IAAI,GAAG,CAAC,QAAQ,EAAE,UAAU,EAAE,MAAM,GAAG,CAAC,EAAE,CAAC;QACzC,KAAK,MAAM,QAAQ,IAAI,GAAG,CAAC,QAAQ,CAAC,UAAU,EAAE,CAAC;YAC/C,MAAM,aAAa,GAAG,MAAM,iBAAiB,CAAC,QAAQ,CAAC,CAAC;YACxD,IAAI,CAAC,aAAa,EAAE,CAAC;gBACnB,MAAM,IAAI,KAAK,CACb,OAAO,GAAG,oCAAoC,QAAQ,CAAC,SAAS,qCAAqC,CACtG,CAAC;YACJ,CAAC;QACH,CAAC;IACH,CAAC;IAED,4EAA4E;IAC5E,IAAI,UAAU,GAAG,IAAI,CAAC;IACtB,IAAI,WAA+B,CAAC;IACpC,IAAI,GAAG,CAAC,QAAQ,EAAE,UAAU,EAAE,MAAM,GAAG,CAAC,EAAE,CAAC;QACzC,MAAM,cAAc,GAAG,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QAClD,MAAM,UAAU,GAAG,IAAI,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC;QACvD,IAAI,IAAI,IAAI,EAAE,GAAG,UAAU,EAAE,CAAC;YAC5B,UAAU,GAAG,KAAK,CAAC;YACnB,WAAW,GAAG,uCAAuC,cAAc,CAAC,UAAU,EAAE,CAAC;QACnF,CAAC;IACH,CAAC;IAED,8EAA8E;IAC9E,IAAI,WAAW,GAAG,KAAK,CAAC;IACxB,IAAI,SAAS,EAAE,CAAC;QACd,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;QAC1C,IAAI,UAAU,GAAa,EAAE,CAAC;QAC9B,IAAI,WAAW,EAAE,CAAC;YAChB,UAAU,GAAG,MAAM,WAAW,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;QACzD,CAAC;aAAM,IAAI,OAAQ,UAAsC,CAAC,MAAM,CAAC,KAAK,WAAW,EAAE,CAAC;YAClF,eAAe;YACf,IAAI,CAAC;gBACH,MAAM,UAAU,GAAI,UAA6F,CAAC,IAAI,CAAC;gBACvH,MAAM,OAAO,GAAG,MAAM,UAAU;qBAC7B,UAAU,CAAC,UAAU,MAAM,EAAE,EAAE,KAAK,CAAC,CAAC;gBACzC,UAAU,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;YAC9B,CAAC;YAAC,MAAM,CAAC,CAAC,+CAA+C,CAAC,CAAC;QAC7D,CAAC;QACD,6EAA6E;QAE7E,KAAK,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;YAC7B,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;YAChC,IAAI,CAAC,MAAM;gBAAE,SAAS;YACtB,IAAI,MAAM,CAAC,IAAI,KAAK,IAAI;gBAAE,SAAS;YACnC,MAAM,YAAY,GAAG,iBAAiB,CAAC,SAAS,CAAC,CAAC;YAClD,IAAI,MAAM,CAAC,OAAO,KAAK,YAAY,EAAE,CAAC;gBACpC,WAAW,GAAG,IAAI,CAAC;gBACnB,MAAM;YACR,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,GAAG,EAAE,WAAW,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC;AACjE,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,QAA2B;IACjE,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,aAAa,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;QACvD,MAAM,OAAO,GAAG,QAAQ,CAAC,UAAU,CAAC;QACpC,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CACtC,QAAQ,CAAC,cAAc,GAAG,OAAO,GAAG,QAAQ,CAAC,SAAS,CACvD,CAAC;QACF,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,oBAAoB,EAAE,WAAW,CAAC,CAAC;QACpE,OAAO,MAAM,EAAE,CAAC,WAAW,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IACrD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @aroha-sdk/core — Aroha Protocol Layers 0–3
|
|
3
|
+
*
|
|
4
|
+
* Layer 0: Transport → ArohaServer, ArohaClient
|
|
5
|
+
* Layer 1: Identity → generateDID, DIDDocument, issueCredential, verifyCredential
|
|
6
|
+
* Auth → issueCredential, verifyCredential, ArohaRole, RbacPolicy, checkPermission
|
|
7
|
+
* Layer 3: Messaging → buildEnvelope, validateEnvelope, ArohaEnvelope, all message types
|
|
8
|
+
* Crypto: → signMessage, verifyMessageSignature, encryptBody, decryptBody
|
|
9
|
+
*/
|
|
10
|
+
export * from "./identity/index.js";
|
|
11
|
+
export * from "./crypto/index.js";
|
|
12
|
+
export * from "./messages/index.js";
|
|
13
|
+
export * from "./transport/index.js";
|
|
14
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @aroha-sdk/core — Aroha Protocol Layers 0–3
|
|
3
|
+
*
|
|
4
|
+
* Layer 0: Transport → ArohaServer, ArohaClient
|
|
5
|
+
* Layer 1: Identity → generateDID, DIDDocument, issueCredential, verifyCredential
|
|
6
|
+
* Auth → issueCredential, verifyCredential, ArohaRole, RbacPolicy, checkPermission
|
|
7
|
+
* Layer 3: Messaging → buildEnvelope, validateEnvelope, ArohaEnvelope, all message types
|
|
8
|
+
* Crypto: → signMessage, verifyMessageSignature, encryptBody, decryptBody
|
|
9
|
+
*/
|
|
10
|
+
export * from "./identity/index.js";
|
|
11
|
+
export * from "./crypto/index.js";
|
|
12
|
+
export * from "./messages/index.js";
|
|
13
|
+
export * from "./transport/index.js";
|
|
14
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Aroha Protocol — Layer 3 Message Envelope
|
|
3
|
+
*
|
|
4
|
+
* Implements the spec's message envelope format.
|
|
5
|
+
* Every Aroha message, regardless of type, uses this envelope.
|
|
6
|
+
*
|
|
7
|
+
* Responsibilities:
|
|
8
|
+
* - Build outbound envelopes (build + sign)
|
|
9
|
+
* - Validate inbound envelopes (schema + signature + nonce + expiry + recipient)
|
|
10
|
+
*
|
|
11
|
+
* This module is pure protocol. It does not route messages or apply
|
|
12
|
+
* business logic — that belongs to the application tier.
|
|
13
|
+
*/
|
|
14
|
+
import { type MessageProof } from "../crypto/signing.js";
|
|
15
|
+
import { NonceRegistry } from "./nonce.js";
|
|
16
|
+
import { type ArohaMessageType, type ArohaBodyByType } from "./types.js";
|
|
17
|
+
export interface ArohaEnvelope<T extends ArohaMessageType = ArohaMessageType> {
|
|
18
|
+
"@context": string[];
|
|
19
|
+
id: string;
|
|
20
|
+
type: T;
|
|
21
|
+
from: string;
|
|
22
|
+
to: string;
|
|
23
|
+
created: string;
|
|
24
|
+
expires: string;
|
|
25
|
+
nonce: string;
|
|
26
|
+
correlationId: string;
|
|
27
|
+
body: T extends keyof ArohaBodyByType ? ArohaBodyByType[T] : Record<string, unknown>;
|
|
28
|
+
proof?: MessageProof;
|
|
29
|
+
/** W3C Trace Context traceparent header — injected by @aroha-sdk/telemetry for distributed tracing. */
|
|
30
|
+
traceparent?: string;
|
|
31
|
+
/**
|
|
32
|
+
* Model routing hint — set by @aroha-sdk/orchestrator ModelRouter.
|
|
33
|
+
* Informational only: tells the receiving agent which model tier to use
|
|
34
|
+
* for processing this request. Never enforced by the transport layer.
|
|
35
|
+
*/
|
|
36
|
+
routingHint?: {
|
|
37
|
+
complexity: "trivial" | "standard" | "complex";
|
|
38
|
+
suggestedModel?: string;
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Build and sign an outbound Aroha message envelope.
|
|
43
|
+
*
|
|
44
|
+
* @param type One of the 15 Aroha message types
|
|
45
|
+
* @param from Sender DID (did:aroha:<id>)
|
|
46
|
+
* @param to Recipient DID (did:aroha:<id>)
|
|
47
|
+
* @param body Message body — typed per message type
|
|
48
|
+
* @param correlationId Saga or session ID linking related messages
|
|
49
|
+
* @param privateKey Sender's Ed25519 private key
|
|
50
|
+
* @param ttlSeconds How long the message is valid (default: 300s / 5min)
|
|
51
|
+
*/
|
|
52
|
+
export interface BuildEnvelopeOptions {
|
|
53
|
+
ttlSeconds?: number;
|
|
54
|
+
/** W3C Trace Context traceparent — propagated by @aroha-sdk/telemetry. */
|
|
55
|
+
traceparent?: string;
|
|
56
|
+
/** Model routing hint — set by @aroha-sdk/orchestrator ModelRouter. */
|
|
57
|
+
routingHint?: ArohaEnvelope["routingHint"];
|
|
58
|
+
}
|
|
59
|
+
export declare function buildEnvelope<T extends ArohaMessageType>(type: T, from: string, to: string, body: T extends keyof ArohaBodyByType ? ArohaBodyByType[T] : Record<string, unknown>, correlationId: string, privateKey: Uint8Array, ttlSecondsOrOptions?: number | BuildEnvelopeOptions): Promise<ArohaEnvelope<T>>;
|
|
60
|
+
/**
|
|
61
|
+
* Build an unsigned Aroha envelope for use within a trusted network mesh
|
|
62
|
+
* (VPC, mTLS service mesh). The receiving server must be configured with
|
|
63
|
+
* bypassSignatureFor to accept envelopes from this sender DID.
|
|
64
|
+
*/
|
|
65
|
+
export declare function buildUnsignedEnvelope<T extends ArohaMessageType>(type: T, from: string, to: string, body: T extends keyof ArohaBodyByType ? ArohaBodyByType[T] : Record<string, unknown>, correlationId: string, opts?: BuildEnvelopeOptions): Promise<ArohaEnvelope<T>>;
|
|
66
|
+
export type ValidationResult = {
|
|
67
|
+
valid: true;
|
|
68
|
+
} | {
|
|
69
|
+
valid: false;
|
|
70
|
+
reason: string;
|
|
71
|
+
};
|
|
72
|
+
/**
|
|
73
|
+
* Validate an inbound Aroha message envelope.
|
|
74
|
+
*
|
|
75
|
+
* Checks (per spec):
|
|
76
|
+
* 1. Signature verification (against provided public key)
|
|
77
|
+
* 2. Message expiry (expires field)
|
|
78
|
+
* 3. Nonce freshness (replay attack prevention)
|
|
79
|
+
* 4. Recipient match (to field must equal this agent's DID)
|
|
80
|
+
*
|
|
81
|
+
* @param envelope The received message envelope
|
|
82
|
+
* @param senderPubKey Ed25519 public key of the claimed sender (looked up from registry)
|
|
83
|
+
* @param myDID This agent's DID (to verify the "to" field)
|
|
84
|
+
* @param nonceRegistry Shared nonce registry for this agent
|
|
85
|
+
*/
|
|
86
|
+
export interface ValidateEnvelopeOptions {
|
|
87
|
+
/** Skip Ed25519 signature check — use only within trusted mesh / VPC environments. */
|
|
88
|
+
skipSignature?: boolean;
|
|
89
|
+
/**
|
|
90
|
+
* Clock skew tolerance in milliseconds applied to the expires check.
|
|
91
|
+
* Accepts messages that expired up to this many ms ago.
|
|
92
|
+
* Recommended: 5000 (5s) for cross-region deployments.
|
|
93
|
+
* Default: 0 (strict).
|
|
94
|
+
*/
|
|
95
|
+
clockToleranceMs?: number;
|
|
96
|
+
}
|
|
97
|
+
export declare function validateEnvelope(envelope: ArohaEnvelope, senderPubKey: Uint8Array, myDID: string, nonceRegistry: NonceRegistry, options?: ValidateEnvelopeOptions): Promise<ValidationResult>;
|
|
98
|
+
/** Create a new correlationId for a new saga or session. */
|
|
99
|
+
export declare function newCorrelationId(): string;
|
|
100
|
+
/** Extract the sender's DID from an envelope. */
|
|
101
|
+
export declare function senderDID(envelope: ArohaEnvelope): string;
|
|
102
|
+
//# sourceMappingURL=envelope.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"envelope.d.ts","sourceRoot":"","sources":["../../src/messages/envelope.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Aroha Protocol — Layer 3 Message Envelope
|
|
3
|
+
*
|
|
4
|
+
* Implements the spec's message envelope format.
|
|
5
|
+
* Every Aroha message, regardless of type, uses this envelope.
|
|
6
|
+
*
|
|
7
|
+
* Responsibilities:
|
|
8
|
+
* - Build outbound envelopes (build + sign)
|
|
9
|
+
* - Validate inbound envelopes (schema + signature + nonce + expiry + recipient)
|
|
10
|
+
*
|
|
11
|
+
* This module is pure protocol. It does not route messages or apply
|
|
12
|
+
* business logic — that belongs to the application tier.
|
|
13
|
+
*/
|
|
14
|
+
import { randomBytes } from "@noble/hashes/utils";
|
|
15
|
+
import { v4 as uuidv4 } from "uuid";
|
|
16
|
+
import { signMessage, verifyMessageSignature } from "../crypto/signing.js";
|
|
17
|
+
// ─── Build ────────────────────────────────────────────────────────────────────
|
|
18
|
+
const Aroha_CONTEXT = [
|
|
19
|
+
"https://aroha-labs.com/contexts/v1",
|
|
20
|
+
"https://w3id.org/security/suites/ed25519-2020/v1",
|
|
21
|
+
];
|
|
22
|
+
export async function buildEnvelope(type, from, to, body, correlationId, privateKey, ttlSecondsOrOptions = 300) {
|
|
23
|
+
const opts = typeof ttlSecondsOrOptions === "number"
|
|
24
|
+
? { ttlSeconds: ttlSecondsOrOptions }
|
|
25
|
+
: ttlSecondsOrOptions;
|
|
26
|
+
const ttlSeconds = opts.ttlSeconds ?? 300;
|
|
27
|
+
const now = new Date();
|
|
28
|
+
const expires = new Date(now.getTime() + ttlSeconds * 1000);
|
|
29
|
+
const envelope = {
|
|
30
|
+
"@context": Aroha_CONTEXT,
|
|
31
|
+
id: `urn:uuid:${uuidv4()}`,
|
|
32
|
+
type,
|
|
33
|
+
from,
|
|
34
|
+
to,
|
|
35
|
+
created: now.toISOString(),
|
|
36
|
+
expires: expires.toISOString(),
|
|
37
|
+
nonce: Buffer.from(randomBytes(32)).toString("hex"),
|
|
38
|
+
correlationId,
|
|
39
|
+
body,
|
|
40
|
+
...(opts.traceparent ? { traceparent: opts.traceparent } : {}),
|
|
41
|
+
...(opts.routingHint ? { routingHint: opts.routingHint } : {}),
|
|
42
|
+
};
|
|
43
|
+
const keyId = `${from}#key-1`;
|
|
44
|
+
const proof = await signMessage(envelope, privateKey, keyId);
|
|
45
|
+
return { ...envelope, proof };
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Build an unsigned Aroha envelope for use within a trusted network mesh
|
|
49
|
+
* (VPC, mTLS service mesh). The receiving server must be configured with
|
|
50
|
+
* bypassSignatureFor to accept envelopes from this sender DID.
|
|
51
|
+
*/
|
|
52
|
+
export async function buildUnsignedEnvelope(type, from, to, body, correlationId, opts = {}) {
|
|
53
|
+
const ttlSeconds = opts.ttlSeconds ?? 300;
|
|
54
|
+
const now = new Date();
|
|
55
|
+
const expires = new Date(now.getTime() + ttlSeconds * 1000);
|
|
56
|
+
return {
|
|
57
|
+
"@context": Aroha_CONTEXT,
|
|
58
|
+
id: `urn:uuid:${uuidv4()}`,
|
|
59
|
+
type,
|
|
60
|
+
from,
|
|
61
|
+
to,
|
|
62
|
+
created: now.toISOString(),
|
|
63
|
+
expires: expires.toISOString(),
|
|
64
|
+
nonce: Buffer.from(randomBytes(32)).toString("hex"),
|
|
65
|
+
correlationId,
|
|
66
|
+
body,
|
|
67
|
+
...(opts.traceparent ? { traceparent: opts.traceparent } : {}),
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
export async function validateEnvelope(envelope, senderPubKey, myDID, nonceRegistry, options) {
|
|
71
|
+
// 1. Recipient check — must be addressed to us
|
|
72
|
+
if (envelope.to !== myDID) {
|
|
73
|
+
return { valid: false, reason: `Message addressed to ${envelope.to}, not ${myDID}` };
|
|
74
|
+
}
|
|
75
|
+
// 2. Expiry check
|
|
76
|
+
const tolerance = options?.clockToleranceMs ?? 0;
|
|
77
|
+
if (tolerance < 0) {
|
|
78
|
+
return { valid: false, reason: "Invalid clockToleranceMs: must be non-negative" };
|
|
79
|
+
}
|
|
80
|
+
if (new Date(envelope.expires).getTime() + tolerance < Date.now()) {
|
|
81
|
+
return { valid: false, reason: `Message expired at ${envelope.expires} (outside tolerance window)` };
|
|
82
|
+
}
|
|
83
|
+
// 3. Nonce check (replay prevention)
|
|
84
|
+
const nonceFresh = await nonceRegistry.checkAsync(envelope.nonce, envelope.expires);
|
|
85
|
+
if (!nonceFresh) {
|
|
86
|
+
return { valid: false, reason: "Nonce replay detected" };
|
|
87
|
+
}
|
|
88
|
+
// 4. Signature verification (skip in trusted mesh mode)
|
|
89
|
+
if (!options?.skipSignature) {
|
|
90
|
+
const isValid = await verifyMessageSignature(envelope, senderPubKey);
|
|
91
|
+
if (!isValid) {
|
|
92
|
+
return { valid: false, reason: "Signature verification failed" };
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return { valid: true };
|
|
96
|
+
}
|
|
97
|
+
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
98
|
+
/** Create a new correlationId for a new saga or session. */
|
|
99
|
+
export function newCorrelationId() {
|
|
100
|
+
return `saga-${uuidv4()}`;
|
|
101
|
+
}
|
|
102
|
+
/** Extract the sender's DID from an envelope. */
|
|
103
|
+
export function senderDID(envelope) {
|
|
104
|
+
return envelope.from;
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=envelope.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"envelope.js","sourceRoot":"","sources":["../../src/messages/envelope.ts"],"names":[],"mappings":"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"}
|