@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,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Aroha Protocol — Layer 3 Encryption
|
|
3
|
+
*
|
|
4
|
+
* Implements the spec rule:
|
|
5
|
+
* "For sensitive body fields, senders SHOULD encrypt using DIDComm v2 JWE
|
|
6
|
+
* with the recipient's public key."
|
|
7
|
+
*
|
|
8
|
+
* Uses X25519 ECDH for key agreement + AES-256-GCM for content encryption.
|
|
9
|
+
* This is a protocol-level primitive. It does not know what is being encrypted
|
|
10
|
+
* or why — that is the application's concern.
|
|
11
|
+
*/
|
|
12
|
+
export interface EncryptedBody {
|
|
13
|
+
/** Algorithm identifier */
|
|
14
|
+
alg: "ECDH-ES+A256GCM";
|
|
15
|
+
/** Base64url-encoded ephemeral X25519 public key */
|
|
16
|
+
epk: string;
|
|
17
|
+
/** Base64url-encoded IV (12 bytes for AES-GCM) */
|
|
18
|
+
iv: string;
|
|
19
|
+
/** Base64url-encoded ciphertext */
|
|
20
|
+
ciphertext: string;
|
|
21
|
+
/** Base64url-encoded AES-GCM authentication tag (16 bytes) */
|
|
22
|
+
tag: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Encrypt a message body for a specific recipient.
|
|
26
|
+
*
|
|
27
|
+
* @param plaintext The body object to encrypt (will be JSON-serialized)
|
|
28
|
+
* @param recipientPubKey Recipient's Ed25519 public key (32 bytes).
|
|
29
|
+
* We convert it to X25519 for ECDH.
|
|
30
|
+
*/
|
|
31
|
+
export declare function encryptBody(plaintext: Record<string, unknown>, recipientPubKey: Uint8Array): Promise<EncryptedBody>;
|
|
32
|
+
/**
|
|
33
|
+
* Decrypt an encrypted message body.
|
|
34
|
+
*
|
|
35
|
+
* @param encrypted The EncryptedBody from the message
|
|
36
|
+
* @param privateKey Recipient's Ed25519 private key (32 bytes)
|
|
37
|
+
*/
|
|
38
|
+
export declare function decryptBody(encrypted: EncryptedBody, privateKey: Uint8Array): Promise<Record<string, unknown>>;
|
|
39
|
+
//# sourceMappingURL=encryption.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"encryption.d.ts","sourceRoot":"","sources":["../../src/crypto/encryption.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAQH,MAAM,WAAW,aAAa;IAC5B,2BAA2B;IAC3B,GAAG,EAAE,iBAAiB,CAAC;IACvB,oDAAoD;IACpD,GAAG,EAAE,MAAM,CAAC;IACZ,kDAAkD;IAClD,EAAE,EAAE,MAAM,CAAC;IACX,mCAAmC;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,8DAA8D;IAC9D,GAAG,EAAE,MAAM,CAAC;CACb;AAID;;;;;;GAMG;AACH,wBAAsB,WAAW,CAC/B,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAClC,eAAe,EAAE,UAAU,GAC1B,OAAO,CAAC,aAAa,CAAC,CA0BxB;AAID;;;;;GAKG;AACH,wBAAsB,WAAW,CAC/B,SAAS,EAAE,aAAa,EACxB,UAAU,EAAE,UAAU,GACrB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAclC"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Aroha Protocol — Layer 3 Encryption
|
|
3
|
+
*
|
|
4
|
+
* Implements the spec rule:
|
|
5
|
+
* "For sensitive body fields, senders SHOULD encrypt using DIDComm v2 JWE
|
|
6
|
+
* with the recipient's public key."
|
|
7
|
+
*
|
|
8
|
+
* Uses X25519 ECDH for key agreement + AES-256-GCM for content encryption.
|
|
9
|
+
* This is a protocol-level primitive. It does not know what is being encrypted
|
|
10
|
+
* or why — that is the application's concern.
|
|
11
|
+
*/
|
|
12
|
+
import { x25519, edwardsToMontgomeryPub, edwardsToMontgomeryPriv } from "@noble/curves/ed25519";
|
|
13
|
+
import { randomBytes, concatBytes } from "@noble/hashes/utils";
|
|
14
|
+
import { sha256 } from "@noble/hashes/sha256";
|
|
15
|
+
// ─── Encrypt ──────────────────────────────────────────────────────────────────
|
|
16
|
+
/**
|
|
17
|
+
* Encrypt a message body for a specific recipient.
|
|
18
|
+
*
|
|
19
|
+
* @param plaintext The body object to encrypt (will be JSON-serialized)
|
|
20
|
+
* @param recipientPubKey Recipient's Ed25519 public key (32 bytes).
|
|
21
|
+
* We convert it to X25519 for ECDH.
|
|
22
|
+
*/
|
|
23
|
+
export async function encryptBody(plaintext, recipientPubKey) {
|
|
24
|
+
// Convert Ed25519 pubkey to X25519 for key exchange
|
|
25
|
+
const recipientX25519 = ed25519PubKeyToX25519(recipientPubKey);
|
|
26
|
+
// Generate ephemeral X25519 keypair
|
|
27
|
+
const ephemeralPriv = x25519.utils.randomPrivateKey();
|
|
28
|
+
const ephemeralPub = x25519.getPublicKey(ephemeralPriv);
|
|
29
|
+
// ECDH shared secret
|
|
30
|
+
const sharedSecret = x25519.getSharedSecret(ephemeralPriv, recipientX25519);
|
|
31
|
+
// Derive AES-256-GCM key from shared secret via SHA-256
|
|
32
|
+
const aesKey = sha256(sharedSecret);
|
|
33
|
+
// Encrypt with AES-256-GCM
|
|
34
|
+
const iv = randomBytes(12);
|
|
35
|
+
const plaintextBytes = new TextEncoder().encode(JSON.stringify(plaintext));
|
|
36
|
+
const { ciphertext, tag } = await aesGcmEncrypt(aesKey, iv, plaintextBytes);
|
|
37
|
+
return {
|
|
38
|
+
alg: "ECDH-ES+A256GCM",
|
|
39
|
+
epk: Buffer.from(ephemeralPub).toString("base64url"),
|
|
40
|
+
iv: Buffer.from(iv).toString("base64url"),
|
|
41
|
+
ciphertext: Buffer.from(ciphertext).toString("base64url"),
|
|
42
|
+
tag: Buffer.from(tag).toString("base64url"),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
// ─── Decrypt ──────────────────────────────────────────────────────────────────
|
|
46
|
+
/**
|
|
47
|
+
* Decrypt an encrypted message body.
|
|
48
|
+
*
|
|
49
|
+
* @param encrypted The EncryptedBody from the message
|
|
50
|
+
* @param privateKey Recipient's Ed25519 private key (32 bytes)
|
|
51
|
+
*/
|
|
52
|
+
export async function decryptBody(encrypted, privateKey) {
|
|
53
|
+
// Convert Ed25519 private key to X25519
|
|
54
|
+
const x25519Priv = ed25519PrivKeyToX25519(privateKey);
|
|
55
|
+
const ephemeralPub = Buffer.from(encrypted.epk, "base64url");
|
|
56
|
+
const sharedSecret = x25519.getSharedSecret(x25519Priv, ephemeralPub);
|
|
57
|
+
const aesKey = sha256(sharedSecret);
|
|
58
|
+
const iv = Buffer.from(encrypted.iv, "base64url");
|
|
59
|
+
const ciphertext = Buffer.from(encrypted.ciphertext, "base64url");
|
|
60
|
+
const tag = Buffer.from(encrypted.tag, "base64url");
|
|
61
|
+
const plaintext = await aesGcmDecrypt(aesKey, iv, ciphertext, tag);
|
|
62
|
+
return JSON.parse(new TextDecoder().decode(plaintext));
|
|
63
|
+
}
|
|
64
|
+
// ─── Key Conversion ───────────────────────────────────────────────────────────
|
|
65
|
+
// Ed25519 keys can be converted to X25519 (Curve25519) via the birational map
|
|
66
|
+
// between the two curve models. @noble/curves implements the correct conversion.
|
|
67
|
+
function ed25519PubKeyToX25519(edPub) {
|
|
68
|
+
return edwardsToMontgomeryPub(edPub);
|
|
69
|
+
}
|
|
70
|
+
function ed25519PrivKeyToX25519(edPriv) {
|
|
71
|
+
return edwardsToMontgomeryPriv(edPriv);
|
|
72
|
+
}
|
|
73
|
+
// ─── AES-256-GCM (Web Crypto API) ────────────────────────────────────────────
|
|
74
|
+
async function aesGcmEncrypt(key, iv, plaintext) {
|
|
75
|
+
const cryptoKey = await crypto.subtle.importKey("raw", key, { name: "AES-GCM" }, false, ["encrypt"]);
|
|
76
|
+
const encrypted = await crypto.subtle.encrypt({ name: "AES-GCM", iv, tagLength: 128 }, cryptoKey, plaintext);
|
|
77
|
+
const buf = new Uint8Array(encrypted);
|
|
78
|
+
const ciphertext = buf.slice(0, buf.length - 16);
|
|
79
|
+
const tag = buf.slice(buf.length - 16);
|
|
80
|
+
return { ciphertext, tag };
|
|
81
|
+
}
|
|
82
|
+
async function aesGcmDecrypt(key, iv, ciphertext, tag) {
|
|
83
|
+
const cryptoKey = await crypto.subtle.importKey("raw", key, { name: "AES-GCM" }, false, ["decrypt"]);
|
|
84
|
+
const combined = concatBytes(ciphertext, tag);
|
|
85
|
+
const decrypted = await crypto.subtle.decrypt({ name: "AES-GCM", iv, tagLength: 128 }, cryptoKey, combined);
|
|
86
|
+
return new Uint8Array(decrypted);
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=encryption.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"encryption.js","sourceRoot":"","sources":["../../src/crypto/encryption.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/crypto/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/crypto/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Aroha Protocol — Layer 3 Signing
|
|
3
|
+
*
|
|
4
|
+
* Implements the signing rule from the spec:
|
|
5
|
+
* "The proof.proofValue MUST be the Ed25519 signature over the canonical
|
|
6
|
+
* JSON of the message with the proof field omitted, keys sorted
|
|
7
|
+
* lexicographically."
|
|
8
|
+
*
|
|
9
|
+
* This module is pure protocol infrastructure. It knows nothing about
|
|
10
|
+
* what the message body contains or what the agent does with it.
|
|
11
|
+
*/
|
|
12
|
+
export interface MessageProof {
|
|
13
|
+
type: "Ed25519Signature2020";
|
|
14
|
+
created: string;
|
|
15
|
+
verificationMethod: string;
|
|
16
|
+
proofPurpose: "authentication";
|
|
17
|
+
proofValue: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Sign a Aroha message.
|
|
21
|
+
* Returns a proof object to embed in the message envelope.
|
|
22
|
+
*
|
|
23
|
+
* @param message Full message object (proof field will be excluded before signing)
|
|
24
|
+
* @param privateKey Ed25519 private key (32 bytes)
|
|
25
|
+
* @param verificationMethodId e.g. "did:aroha:my-agent#key-1"
|
|
26
|
+
*/
|
|
27
|
+
export declare function signMessage(message: Record<string, unknown>, privateKey: Uint8Array, verificationMethodId: string): Promise<MessageProof>;
|
|
28
|
+
/**
|
|
29
|
+
* Verify a Aroha message signature.
|
|
30
|
+
*
|
|
31
|
+
* @param message Full message object including the proof field
|
|
32
|
+
* @param publicKey Ed25519 public key (32 bytes) of the claimed sender
|
|
33
|
+
* @returns true if signature is valid, false otherwise
|
|
34
|
+
*/
|
|
35
|
+
export declare function verifyMessageSignature(message: Record<string, unknown>, publicKey: Uint8Array): Promise<boolean>;
|
|
36
|
+
/**
|
|
37
|
+
* Produce the canonical JSON string of a message for signing/verification.
|
|
38
|
+
*
|
|
39
|
+
* Per spec: exclude the "proof" field, sort all keys lexicographically
|
|
40
|
+
* at every level of nesting.
|
|
41
|
+
*/
|
|
42
|
+
export declare function canonicalizeMessage(message: Record<string, unknown>): string;
|
|
43
|
+
//# sourceMappingURL=signing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signing.d.ts","sourceRoot":"","sources":["../../src/crypto/signing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AASH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,sBAAsB,CAAC;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,YAAY,EAAE,gBAAgB,CAAC;IAC/B,UAAU,EAAE,MAAM,CAAC;CACpB;AAID;;;;;;;GAOG;AACH,wBAAsB,WAAW,CAC/B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,UAAU,EAAE,UAAU,EACtB,oBAAoB,EAAE,MAAM,GAC3B,OAAO,CAAC,YAAY,CAAC,CAYvB;AAED;;;;;;GAMG;AACH,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,SAAS,EAAE,UAAU,GACpB,OAAO,CAAC,OAAO,CAAC,CAalB;AAID;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAG5E"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Aroha Protocol — Layer 3 Signing
|
|
3
|
+
*
|
|
4
|
+
* Implements the signing rule from the spec:
|
|
5
|
+
* "The proof.proofValue MUST be the Ed25519 signature over the canonical
|
|
6
|
+
* JSON of the message with the proof field omitted, keys sorted
|
|
7
|
+
* lexicographically."
|
|
8
|
+
*
|
|
9
|
+
* This module is pure protocol infrastructure. It knows nothing about
|
|
10
|
+
* what the message body contains or what the agent does with it.
|
|
11
|
+
*/
|
|
12
|
+
import * as ed from "@noble/ed25519";
|
|
13
|
+
import { sha512 } from "@noble/hashes/sha512";
|
|
14
|
+
ed.etc.sha512Sync = (...m) => sha512(...m);
|
|
15
|
+
// ─── Signing ──────────────────────────────────────────────────────────────────
|
|
16
|
+
/**
|
|
17
|
+
* Sign a Aroha message.
|
|
18
|
+
* Returns a proof object to embed in the message envelope.
|
|
19
|
+
*
|
|
20
|
+
* @param message Full message object (proof field will be excluded before signing)
|
|
21
|
+
* @param privateKey Ed25519 private key (32 bytes)
|
|
22
|
+
* @param verificationMethodId e.g. "did:aroha:my-agent#key-1"
|
|
23
|
+
*/
|
|
24
|
+
export async function signMessage(message, privateKey, verificationMethodId) {
|
|
25
|
+
const canonical = canonicalizeMessage(message);
|
|
26
|
+
const bytes = new TextEncoder().encode(canonical);
|
|
27
|
+
const signature = await ed.signAsync(bytes, privateKey);
|
|
28
|
+
return {
|
|
29
|
+
type: "Ed25519Signature2020",
|
|
30
|
+
created: new Date().toISOString(),
|
|
31
|
+
verificationMethod: verificationMethodId,
|
|
32
|
+
proofPurpose: "authentication",
|
|
33
|
+
proofValue: Buffer.from(signature).toString("base64url"),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Verify a Aroha message signature.
|
|
38
|
+
*
|
|
39
|
+
* @param message Full message object including the proof field
|
|
40
|
+
* @param publicKey Ed25519 public key (32 bytes) of the claimed sender
|
|
41
|
+
* @returns true if signature is valid, false otherwise
|
|
42
|
+
*/
|
|
43
|
+
export async function verifyMessageSignature(message, publicKey) {
|
|
44
|
+
const proof = message.proof;
|
|
45
|
+
if (!proof?.proofValue)
|
|
46
|
+
return false;
|
|
47
|
+
const canonical = canonicalizeMessage(message); // excludes proof
|
|
48
|
+
const bytes = new TextEncoder().encode(canonical);
|
|
49
|
+
try {
|
|
50
|
+
const signature = Buffer.from(proof.proofValue, "base64url");
|
|
51
|
+
return await ed.verifyAsync(signature, bytes, publicKey);
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
// ─── Canonicalization ─────────────────────────────────────────────────────────
|
|
58
|
+
/**
|
|
59
|
+
* Produce the canonical JSON string of a message for signing/verification.
|
|
60
|
+
*
|
|
61
|
+
* Per spec: exclude the "proof" field, sort all keys lexicographically
|
|
62
|
+
* at every level of nesting.
|
|
63
|
+
*/
|
|
64
|
+
export function canonicalizeMessage(message) {
|
|
65
|
+
const { proof: _excluded, ...rest } = message;
|
|
66
|
+
return JSON.stringify(sortKeysDeep(rest));
|
|
67
|
+
}
|
|
68
|
+
function sortKeysDeep(value) {
|
|
69
|
+
if (Array.isArray(value))
|
|
70
|
+
return value.map(sortKeysDeep);
|
|
71
|
+
if (value !== null && typeof value === "object") {
|
|
72
|
+
const sorted = {};
|
|
73
|
+
for (const key of Object.keys(value).sort()) {
|
|
74
|
+
sorted[key] = sortKeysDeep(value[key]);
|
|
75
|
+
}
|
|
76
|
+
return sorted;
|
|
77
|
+
}
|
|
78
|
+
return value;
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=signing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signing.js","sourceRoot":"","sources":["../../src/crypto/signing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,MAAM,gBAAgB,CAAC;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAE9C,EAAE,CAAC,GAAG,CAAC,UAAU,GAAG,CAAC,GAAG,CAA4B,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;AAYtE,iFAAiF;AAEjF;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,OAAgC,EAChC,UAAsB,EACtB,oBAA4B;IAE5B,MAAM,SAAS,GAAG,mBAAmB,CAAC,OAAO,CAAC,CAAC;IAC/C,MAAM,KAAK,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAClD,MAAM,SAAS,GAAG,MAAM,EAAE,CAAC,SAAS,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;IAExD,OAAO;QACL,IAAI,EAAE,sBAAsB;QAC5B,OAAO,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACjC,kBAAkB,EAAE,oBAAoB;QACxC,YAAY,EAAE,gBAAgB;QAC9B,UAAU,EAAE,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC;KACzD,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,OAAgC,EAChC,SAAqB;IAErB,MAAM,KAAK,GAAG,OAAO,CAAC,KAAiC,CAAC;IACxD,IAAI,CAAC,KAAK,EAAE,UAAU;QAAE,OAAO,KAAK,CAAC;IAErC,MAAM,SAAS,GAAG,mBAAmB,CAAC,OAAO,CAAC,CAAC,CAAC,iBAAiB;IACjE,MAAM,KAAK,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAElD,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;QAC7D,OAAO,MAAM,EAAE,CAAC,WAAW,CAAC,SAAS,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC;IAC3D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,iFAAiF;AAEjF;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,OAAgC;IAClE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,IAAI,EAAE,GAAG,OAAO,CAAC;IAC9C,OAAO,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC;AAC5C,CAAC;AAED,SAAS,YAAY,CAAC,KAAc;IAClC,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IACzD,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAChD,MAAM,MAAM,GAA4B,EAAE,CAAC;QAC3C,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,KAAe,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;YACtD,MAAM,CAAC,GAAG,CAAC,GAAG,YAAY,CAAE,KAAiC,CAAC,GAAG,CAAC,CAAC,CAAC;QACtE,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Aroha Verifiable Credentials (VCs)
|
|
3
|
+
*
|
|
4
|
+
* Based on W3C Verifiable Credentials Data Model 2.0.
|
|
5
|
+
* VCs allow agents to prove claims about themselves (corporate identity,
|
|
6
|
+
* compliance certifications, capability authorization) without revealing
|
|
7
|
+
* more than necessary (selective disclosure via ZKP proofs).
|
|
8
|
+
*
|
|
9
|
+
* Issuance flow:
|
|
10
|
+
* Trust Anchor (e.g. Expedia Corp) issues a VC to its agent.
|
|
11
|
+
* The VC is signed with the issuer's private key.
|
|
12
|
+
* The agent presents the VC during negotiation.
|
|
13
|
+
* The counterpart verifies the VC signature.
|
|
14
|
+
*/
|
|
15
|
+
export type TrustLevel = 0 | 1 | 2 | 3 | 4;
|
|
16
|
+
export declare const TRUST_LEVEL_DESCRIPTIONS: Record<TrustLevel, string>;
|
|
17
|
+
export interface CredentialSubject {
|
|
18
|
+
id: string;
|
|
19
|
+
[key: string]: unknown;
|
|
20
|
+
}
|
|
21
|
+
export interface VerifiableCredential {
|
|
22
|
+
"@context": string[];
|
|
23
|
+
id: string;
|
|
24
|
+
type: string[];
|
|
25
|
+
issuer: string;
|
|
26
|
+
issuanceDate: string;
|
|
27
|
+
expirationDate?: string;
|
|
28
|
+
credentialSubject: CredentialSubject;
|
|
29
|
+
proof?: VCProof;
|
|
30
|
+
}
|
|
31
|
+
export interface VCProof {
|
|
32
|
+
type: "Ed25519Signature2020";
|
|
33
|
+
created: string;
|
|
34
|
+
verificationMethod: string;
|
|
35
|
+
proofPurpose: "assertionMethod";
|
|
36
|
+
proofValue: string;
|
|
37
|
+
}
|
|
38
|
+
/** Issued by a company to vouch that an agent is operated by them. */
|
|
39
|
+
export interface CorporateIdentityCredential extends VerifiableCredential {
|
|
40
|
+
credentialSubject: {
|
|
41
|
+
id: string;
|
|
42
|
+
companyName: string;
|
|
43
|
+
companyDomain: string;
|
|
44
|
+
registeredCountry: string;
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/** Issued by a compliance body (e.g. PCI-DSS, HIPAA auditor). */
|
|
48
|
+
export interface ComplianceCertificationCredential extends VerifiableCredential {
|
|
49
|
+
credentialSubject: {
|
|
50
|
+
id: string;
|
|
51
|
+
standard: string;
|
|
52
|
+
certifiedUntil: string;
|
|
53
|
+
scope: string;
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
/** Issued by a platform operator to authorize an agent to act. */
|
|
57
|
+
export interface CapabilityAuthorizationCredential extends VerifiableCredential {
|
|
58
|
+
credentialSubject: {
|
|
59
|
+
id: string;
|
|
60
|
+
authorizedCapabilities: string[];
|
|
61
|
+
maxTransactionValue?: {
|
|
62
|
+
amount: number;
|
|
63
|
+
currency: string;
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Issue a Verifiable Credential.
|
|
69
|
+
* The issuer signs the credential's canonical JSON with their Ed25519 key.
|
|
70
|
+
*/
|
|
71
|
+
export declare function issueCredential(credential: Omit<VerifiableCredential, "proof" | "id">, issuerPrivateKey: Uint8Array, issuerKeyId: string): Promise<VerifiableCredential>;
|
|
72
|
+
/**
|
|
73
|
+
* Verify a Verifiable Credential's signature.
|
|
74
|
+
* Returns true if the signature is valid.
|
|
75
|
+
*/
|
|
76
|
+
export declare function verifyCredential(credential: VerifiableCredential, issuerPublicKey: Uint8Array): Promise<boolean>;
|
|
77
|
+
/**
|
|
78
|
+
* Check if a credential is expired.
|
|
79
|
+
*/
|
|
80
|
+
export declare function isCredentialExpired(credential: VerifiableCredential): boolean;
|
|
81
|
+
//# sourceMappingURL=credentials.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credentials.d.ts","sourceRoot":"","sources":["../../src/identity/credentials.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAUH,MAAM,MAAM,UAAU,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAE3C,eAAO,MAAM,wBAAwB,EAAE,MAAM,CAAC,UAAU,EAAE,MAAM,CAM/D,CAAC;AAEF,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iBAAiB,EAAE,iBAAiB,CAAC;IACrC,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,sBAAsB,CAAC;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,YAAY,EAAE,iBAAiB,CAAC;IAChC,UAAU,EAAE,MAAM,CAAC;CACpB;AAID,sEAAsE;AACtE,MAAM,WAAW,2BAA4B,SAAQ,oBAAoB;IACvE,iBAAiB,EAAE;QACjB,EAAE,EAAE,MAAM,CAAC;QACX,WAAW,EAAE,MAAM,CAAC;QACpB,aAAa,EAAE,MAAM,CAAC;QACtB,iBAAiB,EAAE,MAAM,CAAC;KAC3B,CAAC;CACH;AAED,iEAAiE;AACjE,MAAM,WAAW,iCAAkC,SAAQ,oBAAoB;IAC7E,iBAAiB,EAAE;QACjB,EAAE,EAAE,MAAM,CAAC;QACX,QAAQ,EAAE,MAAM,CAAC;QACjB,cAAc,EAAE,MAAM,CAAC;QACvB,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;CACH;AAED,kEAAkE;AAClE,MAAM,WAAW,iCAAkC,SAAQ,oBAAoB;IAC7E,iBAAiB,EAAE;QACjB,EAAE,EAAE,MAAM,CAAC;QACX,sBAAsB,EAAE,MAAM,EAAE,CAAC;QACjC,mBAAmB,CAAC,EAAE;YAAE,MAAM,EAAE,MAAM,CAAC;YAAC,QAAQ,EAAE,MAAM,CAAA;SAAE,CAAC;KAC5D,CAAC;CACH;AAID;;;GAGG;AACH,wBAAsB,eAAe,CACnC,UAAU,EAAE,IAAI,CAAC,oBAAoB,EAAE,OAAO,GAAG,IAAI,CAAC,EACtD,gBAAgB,EAAE,UAAU,EAC5B,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,oBAAoB,CAAC,CAmB/B;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CACpC,UAAU,EAAE,oBAAoB,EAChC,eAAe,EAAE,UAAU,GAC1B,OAAO,CAAC,OAAO,CAAC,CASlB;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,oBAAoB,GAAG,OAAO,CAG7E"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Aroha Verifiable Credentials (VCs)
|
|
3
|
+
*
|
|
4
|
+
* Based on W3C Verifiable Credentials Data Model 2.0.
|
|
5
|
+
* VCs allow agents to prove claims about themselves (corporate identity,
|
|
6
|
+
* compliance certifications, capability authorization) without revealing
|
|
7
|
+
* more than necessary (selective disclosure via ZKP proofs).
|
|
8
|
+
*
|
|
9
|
+
* Issuance flow:
|
|
10
|
+
* Trust Anchor (e.g. Expedia Corp) issues a VC to its agent.
|
|
11
|
+
* The VC is signed with the issuer's private key.
|
|
12
|
+
* The agent presents the VC during negotiation.
|
|
13
|
+
* The counterpart verifies the VC signature.
|
|
14
|
+
*/
|
|
15
|
+
import * as ed from "@noble/ed25519";
|
|
16
|
+
import { sha512 } from "@noble/hashes/sha512";
|
|
17
|
+
import { v4 as uuidv4 } from "uuid";
|
|
18
|
+
ed.etc.sha512Sync = (...m) => sha512(...m);
|
|
19
|
+
export const TRUST_LEVEL_DESCRIPTIONS = {
|
|
20
|
+
0: "Public — read capability manifests only",
|
|
21
|
+
1: "Registered — on-chain registration + stake",
|
|
22
|
+
2: "Verified — VC from recognized trust anchor",
|
|
23
|
+
3: "Reputable — reputation score >= 0.8",
|
|
24
|
+
4: "User-trusted — explicit user authorization",
|
|
25
|
+
};
|
|
26
|
+
// ─── Issue / Verify ───────────────────────────────────────────────────────────
|
|
27
|
+
/**
|
|
28
|
+
* Issue a Verifiable Credential.
|
|
29
|
+
* The issuer signs the credential's canonical JSON with their Ed25519 key.
|
|
30
|
+
*/
|
|
31
|
+
export async function issueCredential(credential, issuerPrivateKey, issuerKeyId) {
|
|
32
|
+
const id = `urn:uuid:${uuidv4()}`;
|
|
33
|
+
const unsigned = { ...credential, id };
|
|
34
|
+
const payload = JSON.stringify(canonicalize(unsigned));
|
|
35
|
+
const payloadBytes = new TextEncoder().encode(payload);
|
|
36
|
+
const signature = await ed.signAsync(payloadBytes, issuerPrivateKey);
|
|
37
|
+
const proofValue = Buffer.from(signature).toString("base64url");
|
|
38
|
+
const proof = {
|
|
39
|
+
type: "Ed25519Signature2020",
|
|
40
|
+
created: new Date().toISOString(),
|
|
41
|
+
verificationMethod: issuerKeyId,
|
|
42
|
+
proofPurpose: "assertionMethod",
|
|
43
|
+
proofValue,
|
|
44
|
+
};
|
|
45
|
+
return { ...unsigned, proof };
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Verify a Verifiable Credential's signature.
|
|
49
|
+
* Returns true if the signature is valid.
|
|
50
|
+
*/
|
|
51
|
+
export async function verifyCredential(credential, issuerPublicKey) {
|
|
52
|
+
if (!credential.proof)
|
|
53
|
+
return false;
|
|
54
|
+
const { proof, ...unsigned } = credential;
|
|
55
|
+
const payload = JSON.stringify(canonicalize(unsigned));
|
|
56
|
+
const payloadBytes = new TextEncoder().encode(payload);
|
|
57
|
+
const signature = Buffer.from(proof.proofValue, "base64url");
|
|
58
|
+
return ed.verifyAsync(signature, payloadBytes, issuerPublicKey);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Check if a credential is expired.
|
|
62
|
+
*/
|
|
63
|
+
export function isCredentialExpired(credential) {
|
|
64
|
+
if (!credential.expirationDate)
|
|
65
|
+
return false;
|
|
66
|
+
return new Date(credential.expirationDate) < new Date();
|
|
67
|
+
}
|
|
68
|
+
// ─── Deterministic JSON (canonical form for signing) ──────────────────────────
|
|
69
|
+
function canonicalize(obj) {
|
|
70
|
+
if (Array.isArray(obj))
|
|
71
|
+
return obj.map(canonicalize);
|
|
72
|
+
if (obj !== null && typeof obj === "object") {
|
|
73
|
+
return Object.keys(obj)
|
|
74
|
+
.sort()
|
|
75
|
+
.reduce((acc, key) => {
|
|
76
|
+
acc[key] = canonicalize(obj[key]);
|
|
77
|
+
return acc;
|
|
78
|
+
}, {});
|
|
79
|
+
}
|
|
80
|
+
return obj;
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=credentials.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credentials.js","sourceRoot":"","sources":["../../src/identity/credentials.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DID Resolution Cache
|
|
3
|
+
*
|
|
4
|
+
* Wraps any PublicKeyResolver with an in-memory cache.
|
|
5
|
+
*
|
|
6
|
+
* Cache strategy by DID method:
|
|
7
|
+
* did:aroha: Permanent — the public key IS the DID (base58 of key bytes).
|
|
8
|
+
* The key can never change without changing the DID itself.
|
|
9
|
+
* did:aroha-web: TTL-based — keys rotate with a 24-hour cooldown per spec.
|
|
10
|
+
* Default TTL: 23h to stay just inside the rotation window.
|
|
11
|
+
* Other methods: TTL-based with configurable default.
|
|
12
|
+
*
|
|
13
|
+
* At 1000 messages/second resolving 20 known agents, this eliminates
|
|
14
|
+
* ~50,000 redundant base58 decodes and ~1,000 DNS+HTTPS fetches per second.
|
|
15
|
+
*/
|
|
16
|
+
export interface DidCacheConfig {
|
|
17
|
+
/** TTL for did:aroha-web: entries in ms. Default: 82_800_000 (23 hours) */
|
|
18
|
+
webDidTtlMs?: number;
|
|
19
|
+
/** TTL for unknown DID methods. Default: 300_000 (5 minutes) */
|
|
20
|
+
defaultTtlMs?: number;
|
|
21
|
+
/** Maximum number of entries before LRU eviction. Default: 1000 */
|
|
22
|
+
maxSize?: number;
|
|
23
|
+
}
|
|
24
|
+
export type PublicKeyResolver = (senderDID: string) => Promise<Uint8Array | null>;
|
|
25
|
+
export declare class DidResolutionCache {
|
|
26
|
+
private readonly webDidTtlMs;
|
|
27
|
+
private readonly defaultTtlMs;
|
|
28
|
+
private readonly maxSize;
|
|
29
|
+
private readonly cache;
|
|
30
|
+
constructor(config?: DidCacheConfig);
|
|
31
|
+
/**
|
|
32
|
+
* Wrap a resolver function with cache semantics.
|
|
33
|
+
* The returned resolver is a drop-in replacement.
|
|
34
|
+
*/
|
|
35
|
+
wrap(resolver: PublicKeyResolver): PublicKeyResolver;
|
|
36
|
+
/** Manually populate the cache (e.g. from known agent registry). */
|
|
37
|
+
set(did: string, key: Uint8Array | null): void;
|
|
38
|
+
/** Returns undefined on cache miss or expiry. */
|
|
39
|
+
get(did: string): Uint8Array | null | undefined;
|
|
40
|
+
/** Invalidate a specific DID (e.g. after a key rotation event). */
|
|
41
|
+
invalidate(did: string): void;
|
|
42
|
+
get size(): number;
|
|
43
|
+
private ttlFor;
|
|
44
|
+
private evictLru;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=did-cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"did-cache.d.ts","sourceRoot":"","sources":["../../src/identity/did-cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,MAAM,WAAW,cAAc;IAC7B,2EAA2E;IAC3E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gEAAgE;IAChE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,mEAAmE;IACnE,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,MAAM,iBAAiB,GAAG,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;AAQlF,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAiC;gBAE3C,MAAM,GAAE,cAAmB;IAMvC;;;OAGG;IACH,IAAI,CAAC,QAAQ,EAAE,iBAAiB,GAAG,iBAAiB;IAWpD,oEAAoE;IACpE,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,GAAG,IAAI,GAAG,IAAI;IAW9C,iDAAiD;IACjD,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,GAAG,SAAS;IAW/C,mEAAmE;IACnE,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAI7B,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,OAAO,CAAC,MAAM;IAUd,OAAO,CAAC,QAAQ;CASjB"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DID Resolution Cache
|
|
3
|
+
*
|
|
4
|
+
* Wraps any PublicKeyResolver with an in-memory cache.
|
|
5
|
+
*
|
|
6
|
+
* Cache strategy by DID method:
|
|
7
|
+
* did:aroha: Permanent — the public key IS the DID (base58 of key bytes).
|
|
8
|
+
* The key can never change without changing the DID itself.
|
|
9
|
+
* did:aroha-web: TTL-based — keys rotate with a 24-hour cooldown per spec.
|
|
10
|
+
* Default TTL: 23h to stay just inside the rotation window.
|
|
11
|
+
* Other methods: TTL-based with configurable default.
|
|
12
|
+
*
|
|
13
|
+
* At 1000 messages/second resolving 20 known agents, this eliminates
|
|
14
|
+
* ~50,000 redundant base58 decodes and ~1,000 DNS+HTTPS fetches per second.
|
|
15
|
+
*/
|
|
16
|
+
export class DidResolutionCache {
|
|
17
|
+
webDidTtlMs;
|
|
18
|
+
defaultTtlMs;
|
|
19
|
+
maxSize;
|
|
20
|
+
cache = new Map();
|
|
21
|
+
constructor(config = {}) {
|
|
22
|
+
this.webDidTtlMs = config.webDidTtlMs ?? 82_800_000; // 23h
|
|
23
|
+
this.defaultTtlMs = config.defaultTtlMs ?? 300_000; // 5m
|
|
24
|
+
this.maxSize = config.maxSize ?? 1_000;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Wrap a resolver function with cache semantics.
|
|
28
|
+
* The returned resolver is a drop-in replacement.
|
|
29
|
+
*/
|
|
30
|
+
wrap(resolver) {
|
|
31
|
+
return async (did) => {
|
|
32
|
+
const cached = this.get(did);
|
|
33
|
+
if (cached !== undefined)
|
|
34
|
+
return cached;
|
|
35
|
+
const key = await resolver(did);
|
|
36
|
+
this.set(did, key);
|
|
37
|
+
return key;
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
/** Manually populate the cache (e.g. from known agent registry). */
|
|
41
|
+
set(did, key) {
|
|
42
|
+
if (this.cache.size >= this.maxSize)
|
|
43
|
+
this.evictLru();
|
|
44
|
+
const ttl = this.ttlFor(did);
|
|
45
|
+
this.cache.set(did, {
|
|
46
|
+
key,
|
|
47
|
+
expiresAt: ttl === Infinity ? Infinity : Date.now() + ttl,
|
|
48
|
+
lastUsed: Date.now(),
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
/** Returns undefined on cache miss or expiry. */
|
|
52
|
+
get(did) {
|
|
53
|
+
const entry = this.cache.get(did);
|
|
54
|
+
if (!entry)
|
|
55
|
+
return undefined;
|
|
56
|
+
if (entry.expiresAt !== Infinity && Date.now() > entry.expiresAt) {
|
|
57
|
+
this.cache.delete(did);
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
entry.lastUsed = Date.now();
|
|
61
|
+
return entry.key;
|
|
62
|
+
}
|
|
63
|
+
/** Invalidate a specific DID (e.g. after a key rotation event). */
|
|
64
|
+
invalidate(did) {
|
|
65
|
+
this.cache.delete(did);
|
|
66
|
+
}
|
|
67
|
+
get size() {
|
|
68
|
+
return this.cache.size;
|
|
69
|
+
}
|
|
70
|
+
ttlFor(did) {
|
|
71
|
+
if (did.startsWith("did:aroha:") && !did.startsWith("did:aroha-web:")) {
|
|
72
|
+
return Infinity; // key is encoded in the DID itself — never rotates
|
|
73
|
+
}
|
|
74
|
+
if (did.startsWith("did:aroha-web:")) {
|
|
75
|
+
return this.webDidTtlMs;
|
|
76
|
+
}
|
|
77
|
+
return this.defaultTtlMs;
|
|
78
|
+
}
|
|
79
|
+
evictLru() {
|
|
80
|
+
let oldest = null;
|
|
81
|
+
for (const entry of this.cache.entries()) {
|
|
82
|
+
if (!oldest || entry[1].lastUsed < oldest[1].lastUsed) {
|
|
83
|
+
oldest = entry;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
if (oldest)
|
|
87
|
+
this.cache.delete(oldest[0]);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=did-cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"did-cache.js","sourceRoot":"","sources":["../../src/identity/did-cache.ts"],"names":[],"mappings":"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"}
|