@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,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Aroha DID (Decentralized Identifier) implementation.
|
|
3
|
+
*
|
|
4
|
+
* DID format: did:aroha:<unique-id>
|
|
5
|
+
* Spec: W3C DID Core 1.0 (https://www.w3.org/TR/did-core/)
|
|
6
|
+
*
|
|
7
|
+
* A DID Document contains:
|
|
8
|
+
* - Verification methods (public keys)
|
|
9
|
+
* - Authentication references
|
|
10
|
+
* - Service endpoints (Aroha agent endpoint)
|
|
11
|
+
*/
|
|
12
|
+
export interface VerificationMethod {
|
|
13
|
+
id: string;
|
|
14
|
+
type: "Ed25519VerificationKey2020";
|
|
15
|
+
controller: string;
|
|
16
|
+
/** Base58-encoded public key with multibase prefix 'z' */
|
|
17
|
+
publicKeyMultibase: string;
|
|
18
|
+
}
|
|
19
|
+
export interface ServiceEndpoint {
|
|
20
|
+
id: string;
|
|
21
|
+
type: "ArohaEndpoint";
|
|
22
|
+
serviceEndpoint: string;
|
|
23
|
+
}
|
|
24
|
+
export interface KeyRotationRecord {
|
|
25
|
+
/** ISO8601 — when the rotation was announced. */
|
|
26
|
+
rotatedAt: string;
|
|
27
|
+
/** ISO8601 — earliest time the new key becomes trusted (rotatedAt + coolDownHours). */
|
|
28
|
+
trustAfter: string;
|
|
29
|
+
/** Multibase pubkey of the replaced (predecessor) key. */
|
|
30
|
+
predecessorKey: string;
|
|
31
|
+
/** SHA-256 hex of the new key. */
|
|
32
|
+
newKeyHash: string;
|
|
33
|
+
/**
|
|
34
|
+
* Ed25519 signature over `predecessorKey || newKeyHash || rotatedAt`,
|
|
35
|
+
* signed by the predecessor key. Proves voluntary key rotation.
|
|
36
|
+
*/
|
|
37
|
+
predecessorSignature: string;
|
|
38
|
+
}
|
|
39
|
+
export interface RevokedKeyRecord {
|
|
40
|
+
/** Multibase public key that was revoked. */
|
|
41
|
+
keyMultibase: string;
|
|
42
|
+
/** ISO8601 — when revocation was announced. */
|
|
43
|
+
revokedAt: string;
|
|
44
|
+
/** Human-readable reason (e.g. "Compromised — see incident #42"). */
|
|
45
|
+
reason: string;
|
|
46
|
+
/**
|
|
47
|
+
* Ed25519 signature over `keyMultibase || revokedAt || reason`
|
|
48
|
+
* signed by the key being revoked. Proves intentional revocation.
|
|
49
|
+
*/
|
|
50
|
+
selfSignature?: string;
|
|
51
|
+
}
|
|
52
|
+
export interface DIDDocument {
|
|
53
|
+
"@context": string[];
|
|
54
|
+
id: string;
|
|
55
|
+
verificationMethod: VerificationMethod[];
|
|
56
|
+
authentication: string[];
|
|
57
|
+
assertionMethod: string[];
|
|
58
|
+
keyAgreement: string[];
|
|
59
|
+
service: ServiceEndpoint[];
|
|
60
|
+
created: string;
|
|
61
|
+
updated: string;
|
|
62
|
+
/** Rotation history (newest-first). Present only after at least one rotation. */
|
|
63
|
+
keyHistory?: KeyRotationRecord[];
|
|
64
|
+
/** Keys that have been explicitly revoked and must never be trusted. */
|
|
65
|
+
revokedKeys?: RevokedKeyRecord[];
|
|
66
|
+
}
|
|
67
|
+
export interface AgentKeyPair {
|
|
68
|
+
did: string;
|
|
69
|
+
privateKey: Uint8Array;
|
|
70
|
+
publicKey: Uint8Array;
|
|
71
|
+
document: DIDDocument;
|
|
72
|
+
}
|
|
73
|
+
export declare function toMultibase(bytes: Uint8Array): string;
|
|
74
|
+
export declare function fromMultibase(multibase: string): Uint8Array;
|
|
75
|
+
export interface GenerateDIDOptions {
|
|
76
|
+
/**
|
|
77
|
+
* Optional tenant namespace — produces did:aroha:<namespace>.<agentId>.
|
|
78
|
+
* Must match /^[a-z0-9-]+$/.
|
|
79
|
+
*/
|
|
80
|
+
namespace?: string;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Generate a new Aroha DID with a fresh Ed25519 keypair.
|
|
84
|
+
*
|
|
85
|
+
* @param agentId Human-readable identifier (e.g. "expedia-flights-v2")
|
|
86
|
+
* @param endpoint Aroha endpoint URL for the agent
|
|
87
|
+
* @param options Optional generation options (e.g. namespace for multi-tenancy)
|
|
88
|
+
*/
|
|
89
|
+
export declare function generateDID(agentId: string, endpoint: string, options?: GenerateDIDOptions): Promise<AgentKeyPair>;
|
|
90
|
+
/**
|
|
91
|
+
* Reconstruct a DID Document from an existing keypair.
|
|
92
|
+
* Used when loading a saved agent identity from storage.
|
|
93
|
+
*/
|
|
94
|
+
export declare function buildDIDDocument(agentId: string, publicKey: Uint8Array, endpoint: string, created: string): DIDDocument;
|
|
95
|
+
/**
|
|
96
|
+
* Extract public key bytes from a DID Document's first verification method.
|
|
97
|
+
* Throws if a key rotation cool-down window is still active.
|
|
98
|
+
*/
|
|
99
|
+
export declare function extractPublicKey(doc: DIDDocument): Uint8Array;
|
|
100
|
+
/**
|
|
101
|
+
* Extract the Aroha service endpoint URL from a DID Document.
|
|
102
|
+
*/
|
|
103
|
+
export declare function extractEndpoint(doc: DIDDocument): string;
|
|
104
|
+
/**
|
|
105
|
+
* Rotate to a new keypair for a did:aroha: identity.
|
|
106
|
+
* The predecessor key signs the rotation record.
|
|
107
|
+
* The new key is not trusted until coolDownHours have elapsed.
|
|
108
|
+
*/
|
|
109
|
+
export declare function rotateDIDKey(current: AgentKeyPair, coolDownHours?: number): Promise<AgentKeyPair>;
|
|
110
|
+
/**
|
|
111
|
+
* Emergency key revocation — immediately marks the current key as revoked
|
|
112
|
+
* and rotates to a new keypair with NO cooldown period.
|
|
113
|
+
*
|
|
114
|
+
* Use when a private key is known or suspected to be compromised.
|
|
115
|
+
* After calling this, publish the updated DID Document immediately.
|
|
116
|
+
*
|
|
117
|
+
* @param current The current agent keypair (needed to sign the revocation)
|
|
118
|
+
* @param reason Human-readable reason for revocation
|
|
119
|
+
*/
|
|
120
|
+
export declare function revokeKey(current: AgentKeyPair, reason: string): Promise<AgentKeyPair>;
|
|
121
|
+
/**
|
|
122
|
+
* Verify a revocation record's self-signature.
|
|
123
|
+
* Returns true if the signature is valid — i.e., the holder of the revoked
|
|
124
|
+
* key intentionally created this record.
|
|
125
|
+
*
|
|
126
|
+
* @param record The RevokedKeyRecord to verify
|
|
127
|
+
* @param publicKey The public key that was revoked (to verify against)
|
|
128
|
+
*/
|
|
129
|
+
export declare function verifyRevocation(record: RevokedKeyRecord, publicKey: Uint8Array): Promise<boolean>;
|
|
130
|
+
/**
|
|
131
|
+
* Extract the namespace from a namespaced DID.
|
|
132
|
+
* Returns null for un-namespaced DIDs.
|
|
133
|
+
*
|
|
134
|
+
* Example:
|
|
135
|
+
* extractNamespace("did:aroha:acme-corp.invoice-processor") → "acme-corp"
|
|
136
|
+
* extractNamespace("did:aroha:flight-agent") → null
|
|
137
|
+
*/
|
|
138
|
+
export declare function extractNamespace(did: string): string | null;
|
|
139
|
+
//# sourceMappingURL=did.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"did.d.ts","sourceRoot":"","sources":["../../src/identity/did.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Aroha DID (Decentralized Identifier) implementation.
|
|
3
|
+
*
|
|
4
|
+
* DID format: did:aroha:<unique-id>
|
|
5
|
+
* Spec: W3C DID Core 1.0 (https://www.w3.org/TR/did-core/)
|
|
6
|
+
*
|
|
7
|
+
* A DID Document contains:
|
|
8
|
+
* - Verification methods (public keys)
|
|
9
|
+
* - Authentication references
|
|
10
|
+
* - Service endpoints (Aroha agent endpoint)
|
|
11
|
+
*/
|
|
12
|
+
import * as ed from "@noble/ed25519";
|
|
13
|
+
import { sha256 } from "@noble/hashes/sha256";
|
|
14
|
+
import { sha512 } from "@noble/hashes/sha512";
|
|
15
|
+
import { bytesToHex } from "@noble/hashes/utils";
|
|
16
|
+
// noble/ed25519 v2 requires sha512 sync
|
|
17
|
+
ed.etc.sha512Sync = (...m) => sha512(...m);
|
|
18
|
+
// ─── Base58 encoding (multibase 'z' prefix) ───────────────────────────────────
|
|
19
|
+
const BASE58_ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
|
20
|
+
function encodeBase58(bytes) {
|
|
21
|
+
let num = BigInt("0x" + bytesToHex(bytes));
|
|
22
|
+
const digits = [];
|
|
23
|
+
while (num > 0n) {
|
|
24
|
+
digits.push(Number(num % 58n));
|
|
25
|
+
num /= 58n;
|
|
26
|
+
}
|
|
27
|
+
// leading zeros
|
|
28
|
+
for (const b of bytes) {
|
|
29
|
+
if (b !== 0)
|
|
30
|
+
break;
|
|
31
|
+
digits.push(0);
|
|
32
|
+
}
|
|
33
|
+
return digits
|
|
34
|
+
.reverse()
|
|
35
|
+
.map((d) => BASE58_ALPHABET[d])
|
|
36
|
+
.join("");
|
|
37
|
+
}
|
|
38
|
+
function decodeBase58(s) {
|
|
39
|
+
let num = 0n;
|
|
40
|
+
for (const c of s) {
|
|
41
|
+
const idx = BASE58_ALPHABET.indexOf(c);
|
|
42
|
+
if (idx < 0)
|
|
43
|
+
throw new Error(`Invalid base58 character: ${c}`);
|
|
44
|
+
num = num * 58n + BigInt(idx);
|
|
45
|
+
}
|
|
46
|
+
const hex = num.toString(16).padStart(64, "0");
|
|
47
|
+
return Uint8Array.from(Buffer.from(hex, "hex"));
|
|
48
|
+
}
|
|
49
|
+
export function toMultibase(bytes) {
|
|
50
|
+
return "z" + encodeBase58(bytes);
|
|
51
|
+
}
|
|
52
|
+
export function fromMultibase(multibase) {
|
|
53
|
+
if (!multibase.startsWith("z")) {
|
|
54
|
+
throw new Error("Only base58btc multibase (prefix 'z') is supported");
|
|
55
|
+
}
|
|
56
|
+
return decodeBase58(multibase.slice(1));
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Generate a new Aroha DID with a fresh Ed25519 keypair.
|
|
60
|
+
*
|
|
61
|
+
* @param agentId Human-readable identifier (e.g. "expedia-flights-v2")
|
|
62
|
+
* @param endpoint Aroha endpoint URL for the agent
|
|
63
|
+
* @param options Optional generation options (e.g. namespace for multi-tenancy)
|
|
64
|
+
*/
|
|
65
|
+
export async function generateDID(agentId, endpoint, options = {}) {
|
|
66
|
+
const { namespace } = options;
|
|
67
|
+
if (namespace && !/^[a-z0-9-]+$/.test(namespace)) {
|
|
68
|
+
throw new Error(`Invalid namespace "${namespace}" — must match /^[a-z0-9-]+$/`);
|
|
69
|
+
}
|
|
70
|
+
const qualifiedId = namespace ? `${namespace}.${agentId}` : agentId;
|
|
71
|
+
const privateKey = ed.utils.randomPrivateKey();
|
|
72
|
+
const publicKey = await ed.getPublicKeyAsync(privateKey);
|
|
73
|
+
const did = `did:aroha:${qualifiedId}`;
|
|
74
|
+
const now = new Date().toISOString();
|
|
75
|
+
const keyId = `${did}#key-1`;
|
|
76
|
+
const document = {
|
|
77
|
+
"@context": [
|
|
78
|
+
"https://www.w3.org/ns/did/v1",
|
|
79
|
+
"https://w3id.org/security/suites/ed25519-2020/v1",
|
|
80
|
+
],
|
|
81
|
+
id: did,
|
|
82
|
+
verificationMethod: [
|
|
83
|
+
{
|
|
84
|
+
id: keyId,
|
|
85
|
+
type: "Ed25519VerificationKey2020",
|
|
86
|
+
controller: did,
|
|
87
|
+
publicKeyMultibase: toMultibase(publicKey),
|
|
88
|
+
},
|
|
89
|
+
],
|
|
90
|
+
authentication: [keyId],
|
|
91
|
+
assertionMethod: [keyId],
|
|
92
|
+
keyAgreement: [keyId],
|
|
93
|
+
service: [
|
|
94
|
+
{
|
|
95
|
+
id: `${did}#aroha`,
|
|
96
|
+
type: "ArohaEndpoint",
|
|
97
|
+
serviceEndpoint: endpoint,
|
|
98
|
+
},
|
|
99
|
+
],
|
|
100
|
+
created: now,
|
|
101
|
+
updated: now,
|
|
102
|
+
};
|
|
103
|
+
return { did, privateKey, publicKey, document };
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Reconstruct a DID Document from an existing keypair.
|
|
107
|
+
* Used when loading a saved agent identity from storage.
|
|
108
|
+
*/
|
|
109
|
+
export function buildDIDDocument(agentId, publicKey, endpoint, created) {
|
|
110
|
+
const did = `did:aroha:${agentId}`;
|
|
111
|
+
const keyId = `${did}#key-1`;
|
|
112
|
+
const now = new Date().toISOString();
|
|
113
|
+
return {
|
|
114
|
+
"@context": [
|
|
115
|
+
"https://www.w3.org/ns/did/v1",
|
|
116
|
+
"https://w3id.org/security/suites/ed25519-2020/v1",
|
|
117
|
+
],
|
|
118
|
+
id: did,
|
|
119
|
+
verificationMethod: [
|
|
120
|
+
{
|
|
121
|
+
id: keyId,
|
|
122
|
+
type: "Ed25519VerificationKey2020",
|
|
123
|
+
controller: did,
|
|
124
|
+
publicKeyMultibase: toMultibase(publicKey),
|
|
125
|
+
},
|
|
126
|
+
],
|
|
127
|
+
authentication: [keyId],
|
|
128
|
+
assertionMethod: [keyId],
|
|
129
|
+
keyAgreement: [keyId],
|
|
130
|
+
service: [
|
|
131
|
+
{
|
|
132
|
+
id: `${did}#aroha`,
|
|
133
|
+
type: "ArohaEndpoint",
|
|
134
|
+
serviceEndpoint: endpoint,
|
|
135
|
+
},
|
|
136
|
+
],
|
|
137
|
+
created,
|
|
138
|
+
updated: now,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Extract public key bytes from a DID Document's first verification method.
|
|
143
|
+
* Throws if a key rotation cool-down window is still active.
|
|
144
|
+
*/
|
|
145
|
+
export function extractPublicKey(doc) {
|
|
146
|
+
const vm = doc.verificationMethod[0];
|
|
147
|
+
if (!vm)
|
|
148
|
+
throw new Error(`DID ${doc.id} has no verification methods`);
|
|
149
|
+
// Check if the current key has been explicitly revoked
|
|
150
|
+
if (doc.revokedKeys && doc.revokedKeys.length > 0) {
|
|
151
|
+
const currentKeyMultibase = vm.publicKeyMultibase;
|
|
152
|
+
const revoked = doc.revokedKeys.find(r => r.keyMultibase === currentKeyMultibase);
|
|
153
|
+
if (revoked) {
|
|
154
|
+
throw new Error(`DID ${doc.id} key ${currentKeyMultibase.slice(0, 12)}... was revoked at ${revoked.revokedAt}: ${revoked.reason}`);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
if (doc.keyHistory && doc.keyHistory.length > 0) {
|
|
158
|
+
const latest = doc.keyHistory[0];
|
|
159
|
+
if (new Date() < new Date(latest.trustAfter)) {
|
|
160
|
+
throw new Error(`DID ${doc.id} key rotation cool-down active until ${latest.trustAfter}`);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return fromMultibase(vm.publicKeyMultibase);
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Extract the Aroha service endpoint URL from a DID Document.
|
|
167
|
+
*/
|
|
168
|
+
export function extractEndpoint(doc) {
|
|
169
|
+
const svc = doc.service.find((s) => s.type === "ArohaEndpoint");
|
|
170
|
+
if (!svc)
|
|
171
|
+
throw new Error(`DID ${doc.id} has no ArohaEndpoint service`);
|
|
172
|
+
return svc.serviceEndpoint;
|
|
173
|
+
}
|
|
174
|
+
// ─── Key rotation ─────────────────────────────────────────────────────────────
|
|
175
|
+
function keyCommitmentHash(publicKey) {
|
|
176
|
+
return bytesToHex(sha256(publicKey));
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Rotate to a new keypair for a did:aroha: identity.
|
|
180
|
+
* The predecessor key signs the rotation record.
|
|
181
|
+
* The new key is not trusted until coolDownHours have elapsed.
|
|
182
|
+
*/
|
|
183
|
+
export async function rotateDIDKey(current, coolDownHours = 24) {
|
|
184
|
+
const newPrivateKey = ed.utils.randomPrivateKey();
|
|
185
|
+
const newPublicKey = await ed.getPublicKeyAsync(newPrivateKey);
|
|
186
|
+
const oldPubMultibase = toMultibase(current.publicKey);
|
|
187
|
+
const now = new Date();
|
|
188
|
+
const trustAfter = new Date(now.getTime() + coolDownHours * 3_600_000);
|
|
189
|
+
const newKeyHash = keyCommitmentHash(newPublicKey);
|
|
190
|
+
// Payload format matches verifyKeyRotation in web-did.ts:
|
|
191
|
+
// predecessorKey (multibase) + newKeyHash (hex) + rotatedAt (ISO8601)
|
|
192
|
+
const payload = new TextEncoder().encode(oldPubMultibase + newKeyHash + now.toISOString());
|
|
193
|
+
const sig = await ed.signAsync(payload, current.privateKey);
|
|
194
|
+
const rotation = {
|
|
195
|
+
rotatedAt: now.toISOString(),
|
|
196
|
+
trustAfter: trustAfter.toISOString(),
|
|
197
|
+
predecessorKey: oldPubMultibase,
|
|
198
|
+
newKeyHash,
|
|
199
|
+
predecessorSignature: Buffer.from(sig).toString("base64url"),
|
|
200
|
+
};
|
|
201
|
+
const keyId = `${current.did}#key-1`;
|
|
202
|
+
const newDoc = {
|
|
203
|
+
...current.document,
|
|
204
|
+
verificationMethod: [
|
|
205
|
+
{
|
|
206
|
+
id: keyId,
|
|
207
|
+
type: "Ed25519VerificationKey2020",
|
|
208
|
+
controller: current.did,
|
|
209
|
+
publicKeyMultibase: toMultibase(newPublicKey),
|
|
210
|
+
},
|
|
211
|
+
],
|
|
212
|
+
updated: now.toISOString(),
|
|
213
|
+
keyHistory: [rotation, ...(current.document.keyHistory ?? [])],
|
|
214
|
+
};
|
|
215
|
+
return { did: current.did, privateKey: newPrivateKey, publicKey: newPublicKey, document: newDoc };
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Emergency key revocation — immediately marks the current key as revoked
|
|
219
|
+
* and rotates to a new keypair with NO cooldown period.
|
|
220
|
+
*
|
|
221
|
+
* Use when a private key is known or suspected to be compromised.
|
|
222
|
+
* After calling this, publish the updated DID Document immediately.
|
|
223
|
+
*
|
|
224
|
+
* @param current The current agent keypair (needed to sign the revocation)
|
|
225
|
+
* @param reason Human-readable reason for revocation
|
|
226
|
+
*/
|
|
227
|
+
export async function revokeKey(current, reason) {
|
|
228
|
+
const newPrivateKey = ed.utils.randomPrivateKey();
|
|
229
|
+
const newPublicKey = await ed.getPublicKeyAsync(newPrivateKey);
|
|
230
|
+
const now = new Date().toISOString();
|
|
231
|
+
const oldKeyMultibase = toMultibase(current.publicKey);
|
|
232
|
+
// Sign revocation with the key being revoked (proves intentional)
|
|
233
|
+
const payload = new TextEncoder().encode(oldKeyMultibase + now + reason);
|
|
234
|
+
const sig = await ed.signAsync(payload, current.privateKey);
|
|
235
|
+
const revokedRecord = {
|
|
236
|
+
keyMultibase: oldKeyMultibase,
|
|
237
|
+
revokedAt: now,
|
|
238
|
+
reason,
|
|
239
|
+
selfSignature: Buffer.from(sig).toString("base64url"),
|
|
240
|
+
};
|
|
241
|
+
const keyId = `${current.did}#key-1`;
|
|
242
|
+
const newDoc = {
|
|
243
|
+
...current.document,
|
|
244
|
+
verificationMethod: [
|
|
245
|
+
{
|
|
246
|
+
id: keyId,
|
|
247
|
+
type: "Ed25519VerificationKey2020",
|
|
248
|
+
controller: current.did,
|
|
249
|
+
publicKeyMultibase: toMultibase(newPublicKey),
|
|
250
|
+
},
|
|
251
|
+
],
|
|
252
|
+
updated: now,
|
|
253
|
+
// No keyHistory entry — no cooldown, immediate trust of new key
|
|
254
|
+
revokedKeys: [revokedRecord, ...(current.document.revokedKeys ?? [])],
|
|
255
|
+
};
|
|
256
|
+
return { did: current.did, privateKey: newPrivateKey, publicKey: newPublicKey, document: newDoc };
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Verify a revocation record's self-signature.
|
|
260
|
+
* Returns true if the signature is valid — i.e., the holder of the revoked
|
|
261
|
+
* key intentionally created this record.
|
|
262
|
+
*
|
|
263
|
+
* @param record The RevokedKeyRecord to verify
|
|
264
|
+
* @param publicKey The public key that was revoked (to verify against)
|
|
265
|
+
*/
|
|
266
|
+
export async function verifyRevocation(record, publicKey) {
|
|
267
|
+
if (!record.selfSignature)
|
|
268
|
+
return false;
|
|
269
|
+
try {
|
|
270
|
+
const payload = new TextEncoder().encode(record.keyMultibase + record.revokedAt + record.reason);
|
|
271
|
+
const sig = Buffer.from(record.selfSignature, "base64url");
|
|
272
|
+
return await ed.verifyAsync(sig, payload, publicKey);
|
|
273
|
+
}
|
|
274
|
+
catch {
|
|
275
|
+
return false;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Extract the namespace from a namespaced DID.
|
|
280
|
+
* Returns null for un-namespaced DIDs.
|
|
281
|
+
*
|
|
282
|
+
* Example:
|
|
283
|
+
* extractNamespace("did:aroha:acme-corp.invoice-processor") → "acme-corp"
|
|
284
|
+
* extractNamespace("did:aroha:flight-agent") → null
|
|
285
|
+
*/
|
|
286
|
+
export function extractNamespace(did) {
|
|
287
|
+
const suffix = did.replace("did:aroha:", "");
|
|
288
|
+
const dotIndex = suffix.indexOf(".");
|
|
289
|
+
return dotIndex >= 0 ? suffix.slice(0, dotIndex) : null;
|
|
290
|
+
}
|
|
291
|
+
//# sourceMappingURL=did.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"did.js","sourceRoot":"","sources":["../../src/identity/did.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;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;AAE9D,wCAAwC;AACxC,EAAE,CAAC,GAAG,CAAC,UAAU,GAAG,CAAC,GAAG,CAA4B,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;AAuEtE,iFAAiF;AAEjF,MAAM,eAAe,GACnB,4DAA4D,CAAC;AAE/D,SAAS,YAAY,CAAC,KAAiB;IACrC,IAAI,GAAG,GAAG,MAAM,CAAC,IAAI,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC;IAC3C,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,OAAO,GAAG,GAAG,EAAE,EAAE,CAAC;QAChB,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC;QAC/B,GAAG,IAAI,GAAG,CAAC;IACb,CAAC;IACD,gBAAgB;IAChB,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,IAAI,CAAC,KAAK,CAAC;YAAE,MAAM;QACnB,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACjB,CAAC;IACD,OAAO,MAAM;SACV,OAAO,EAAE;SACT,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;SAC9B,IAAI,CAAC,EAAE,CAAC,CAAC;AACd,CAAC;AAED,SAAS,YAAY,CAAC,CAAS;IAC7B,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,KAAK,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;QAClB,MAAM,GAAG,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QACvC,IAAI,GAAG,GAAG,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,EAAE,CAAC,CAAC;QAC/D,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;IAChC,CAAC;IACD,MAAM,GAAG,GAAG,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;IAC/C,OAAO,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC;AAClD,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,KAAiB;IAC3C,OAAO,GAAG,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,SAAiB;IAC7C,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QAC/B,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;IACxE,CAAC;IACD,OAAO,YAAY,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1C,CAAC;AAYD;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,OAAe,EACf,QAAgB,EAChB,UAA8B,EAAE;IAEhC,MAAM,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC;IAC9B,IAAI,SAAS,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;QACjD,MAAM,IAAI,KAAK,CAAC,sBAAsB,SAAS,+BAA+B,CAAC,CAAC;IAClF,CAAC;IACD,MAAM,WAAW,GAAG,SAAS,CAAC,CAAC,CAAC,GAAG,SAAS,IAAI,OAAO,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;IAEpE,MAAM,UAAU,GAAG,EAAE,CAAC,KAAK,CAAC,gBAAgB,EAAE,CAAC;IAC/C,MAAM,SAAS,GAAG,MAAM,EAAE,CAAC,iBAAiB,CAAC,UAAU,CAAC,CAAC;IAEzD,MAAM,GAAG,GAAG,aAAa,WAAW,EAAE,CAAC;IACvC,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACrC,MAAM,KAAK,GAAG,GAAG,GAAG,QAAQ,CAAC;IAE7B,MAAM,QAAQ,GAAgB;QAC5B,UAAU,EAAE;YACV,8BAA8B;YAC9B,kDAAkD;SACnD;QACD,EAAE,EAAE,GAAG;QACP,kBAAkB,EAAE;YAClB;gBACE,EAAE,EAAE,KAAK;gBACT,IAAI,EAAE,4BAA4B;gBAClC,UAAU,EAAE,GAAG;gBACf,kBAAkB,EAAE,WAAW,CAAC,SAAS,CAAC;aAC3C;SACF;QACD,cAAc,EAAE,CAAC,KAAK,CAAC;QACvB,eAAe,EAAE,CAAC,KAAK,CAAC;QACxB,YAAY,EAAE,CAAC,KAAK,CAAC;QACrB,OAAO,EAAE;YACP;gBACE,EAAE,EAAE,GAAG,GAAG,QAAQ;gBAClB,IAAI,EAAE,eAAe;gBACrB,eAAe,EAAE,QAAQ;aAC1B;SACF;QACD,OAAO,EAAE,GAAG;QACZ,OAAO,EAAE,GAAG;KACb,CAAC;IAEF,OAAO,EAAE,GAAG,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC;AAClD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAC9B,OAAe,EACf,SAAqB,EACrB,QAAgB,EAChB,OAAe;IAEf,MAAM,GAAG,GAAG,aAAa,OAAO,EAAE,CAAC;IACnC,MAAM,KAAK,GAAG,GAAG,GAAG,QAAQ,CAAC;IAC7B,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAErC,OAAO;QACL,UAAU,EAAE;YACV,8BAA8B;YAC9B,kDAAkD;SACnD;QACD,EAAE,EAAE,GAAG;QACP,kBAAkB,EAAE;YAClB;gBACE,EAAE,EAAE,KAAK;gBACT,IAAI,EAAE,4BAA4B;gBAClC,UAAU,EAAE,GAAG;gBACf,kBAAkB,EAAE,WAAW,CAAC,SAAS,CAAC;aAC3C;SACF;QACD,cAAc,EAAE,CAAC,KAAK,CAAC;QACvB,eAAe,EAAE,CAAC,KAAK,CAAC;QACxB,YAAY,EAAE,CAAC,KAAK,CAAC;QACrB,OAAO,EAAE;YACP;gBACE,EAAE,EAAE,GAAG,GAAG,QAAQ;gBAClB,IAAI,EAAE,eAAe;gBACrB,eAAe,EAAE,QAAQ;aAC1B;SACF;QACD,OAAO;QACP,OAAO,EAAE,GAAG;KACb,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,GAAgB;IAC/C,MAAM,EAAE,GAAG,GAAG,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC;IACrC,IAAI,CAAC,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,OAAO,GAAG,CAAC,EAAE,8BAA8B,CAAC,CAAC;IAEtE,uDAAuD;IACvD,IAAI,GAAG,CAAC,WAAW,IAAI,GAAG,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAClD,MAAM,mBAAmB,GAAG,EAAE,CAAC,kBAAkB,CAAC;QAClD,MAAM,OAAO,GAAG,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,YAAY,KAAK,mBAAmB,CAAC,CAAC;QAClF,IAAI,OAAO,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CACb,OAAO,GAAG,CAAC,EAAE,QAAQ,mBAAmB,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,sBAAsB,OAAO,CAAC,SAAS,KAAK,OAAO,CAAC,MAAM,EAAE,CAClH,CAAC;QACJ,CAAC;IACH,CAAC;IAED,IAAI,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAChD,MAAM,MAAM,GAAG,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QACjC,IAAI,IAAI,IAAI,EAAE,GAAG,IAAI,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC;YAC7C,MAAM,IAAI,KAAK,CACb,OAAO,GAAG,CAAC,EAAE,wCAAwC,MAAM,CAAC,UAAU,EAAE,CACzE,CAAC;QACJ,CAAC;IACH,CAAC;IAED,OAAO,aAAa,CAAC,EAAE,CAAC,kBAAkB,CAAC,CAAC;AAC9C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,GAAgB;IAC9C,MAAM,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,eAAe,CAAC,CAAC;IAChE,IAAI,CAAC,GAAG;QAAE,MAAM,IAAI,KAAK,CAAC,OAAO,GAAG,CAAC,EAAE,+BAA+B,CAAC,CAAC;IACxE,OAAO,GAAG,CAAC,eAAe,CAAC;AAC7B,CAAC;AAED,iFAAiF;AAEjF,SAAS,iBAAiB,CAAC,SAAqB;IAC9C,OAAO,UAAU,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC;AACvC,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,OAAqB,EACrB,aAAa,GAAG,EAAE;IAElB,MAAM,aAAa,GAAG,EAAE,CAAC,KAAK,CAAC,gBAAgB,EAAE,CAAC;IAClD,MAAM,YAAY,GAAG,MAAM,EAAE,CAAC,iBAAiB,CAAC,aAAa,CAAC,CAAC;IAE/D,MAAM,eAAe,GAAG,WAAW,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACvD,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;IACvB,MAAM,UAAU,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,aAAa,GAAG,SAAS,CAAC,CAAC;IAEvE,MAAM,UAAU,GAAG,iBAAiB,CAAC,YAAY,CAAC,CAAC;IACnD,0DAA0D;IAC1D,sEAAsE;IACtE,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CACtC,eAAe,GAAG,UAAU,GAAG,GAAG,CAAC,WAAW,EAAE,CACjD,CAAC;IACF,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;IAE5D,MAAM,QAAQ,GAAsB;QAClC,SAAS,EAAE,GAAG,CAAC,WAAW,EAAE;QAC5B,UAAU,EAAE,UAAU,CAAC,WAAW,EAAE;QACpC,cAAc,EAAE,eAAe;QAC/B,UAAU;QACV,oBAAoB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC;KAC7D,CAAC;IAEF,MAAM,KAAK,GAAG,GAAG,OAAO,CAAC,GAAG,QAAQ,CAAC;IACrC,MAAM,MAAM,GAAgB;QAC1B,GAAG,OAAO,CAAC,QAAQ;QACnB,kBAAkB,EAAE;YAClB;gBACE,EAAE,EAAE,KAAK;gBACT,IAAI,EAAE,4BAA4B;gBAClC,UAAU,EAAE,OAAO,CAAC,GAAG;gBACvB,kBAAkB,EAAE,WAAW,CAAC,YAAY,CAAC;aAC9C;SACF;QACD,OAAO,EAAE,GAAG,CAAC,WAAW,EAAE;QAC1B,UAAU,EAAE,CAAC,QAAQ,EAAE,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC;KAC/D,CAAC;IAEF,OAAO,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,UAAU,EAAE,aAAa,EAAE,SAAS,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;AACpG,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,OAAqB,EACrB,MAAc;IAEd,MAAM,aAAa,GAAG,EAAE,CAAC,KAAK,CAAC,gBAAgB,EAAE,CAAC;IAClD,MAAM,YAAY,GAAG,MAAM,EAAE,CAAC,iBAAiB,CAAC,aAAa,CAAC,CAAC;IAE/D,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACrC,MAAM,eAAe,GAAG,WAAW,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAEvD,kEAAkE;IAClE,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,eAAe,GAAG,GAAG,GAAG,MAAM,CAAC,CAAC;IACzE,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;IAE5D,MAAM,aAAa,GAAqB;QACtC,YAAY,EAAE,eAAe;QAC7B,SAAS,EAAE,GAAG;QACd,MAAM;QACN,aAAa,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC;KACtD,CAAC;IAEF,MAAM,KAAK,GAAG,GAAG,OAAO,CAAC,GAAG,QAAQ,CAAC;IACrC,MAAM,MAAM,GAAgB;QAC1B,GAAG,OAAO,CAAC,QAAQ;QACnB,kBAAkB,EAAE;YAClB;gBACE,EAAE,EAAE,KAAK;gBACT,IAAI,EAAE,4BAA4B;gBAClC,UAAU,EAAE,OAAO,CAAC,GAAG;gBACvB,kBAAkB,EAAE,WAAW,CAAC,YAAY,CAAC;aAC9C;SACF;QACD,OAAO,EAAE,GAAG;QACZ,gEAAgE;QAChE,WAAW,EAAE,CAAC,aAAa,EAAE,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC;KACtE,CAAC;IAEF,OAAO,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,UAAU,EAAE,aAAa,EAAE,SAAS,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;AACpG,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,MAAwB,EACxB,SAAqB;IAErB,IAAI,CAAC,MAAM,CAAC,aAAa;QAAE,OAAO,KAAK,CAAC;IACxC,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CACtC,MAAM,CAAC,YAAY,GAAG,MAAM,CAAC,SAAS,GAAG,MAAM,CAAC,MAAM,CACvD,CAAC;QACF,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,EAAE,WAAW,CAAC,CAAC;QAC3D,OAAO,MAAM,EAAE,CAAC,WAAW,CAAC,GAAG,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;IACvD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,gBAAgB,CAAC,GAAW;IAC1C,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;IAC7C,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACrC,OAAO,QAAQ,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAC1D,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/identity/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,kBAAkB,CAAC;AACjC,cAAc,cAAc,CAAC;AAC7B,cAAc,gBAAgB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/identity/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,kBAAkB,CAAC;AACjC,cAAc,cAAc,CAAC;AAC7B,cAAc,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,131 @@
|
|
|
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 { type DIDDocument, type AgentKeyPair, type KeyRotationRecord } from "./did.js";
|
|
32
|
+
export interface WebDIDDocument extends DIDDocument {
|
|
33
|
+
/** Two-factor verification metadata. */
|
|
34
|
+
arohaWeb: {
|
|
35
|
+
domain: string;
|
|
36
|
+
path: string;
|
|
37
|
+
/** SHA-256 hex of the active public key — must match DNS TXT. */
|
|
38
|
+
keyCommitmentHash: string;
|
|
39
|
+
/** Rotation chain (newest-first). Null if this is the genesis key. */
|
|
40
|
+
keyHistory: KeyRotationRecord[];
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
export { type KeyRotationRecord } from "./did.js";
|
|
44
|
+
export interface WebAgentKeyPair extends AgentKeyPair {
|
|
45
|
+
/** The DNS TXT record value to publish at _aroha.{domain}. */
|
|
46
|
+
dnsTXTRecord: string;
|
|
47
|
+
/** The URL where the DID Document should be served. */
|
|
48
|
+
wellKnownUrl: string;
|
|
49
|
+
/** The full typed document (superset of DIDDocument). */
|
|
50
|
+
webDocument: WebDIDDocument;
|
|
51
|
+
}
|
|
52
|
+
export interface WebDIDResolutionResult {
|
|
53
|
+
document: WebDIDDocument;
|
|
54
|
+
/** True if DNS TXT key-commitment matched the document. */
|
|
55
|
+
dnsVerified: boolean;
|
|
56
|
+
/** True if the active key's cool-down window has passed. */
|
|
57
|
+
keyTrusted: boolean;
|
|
58
|
+
/** Reason if keyTrusted is false. */
|
|
59
|
+
trustReason?: string;
|
|
60
|
+
}
|
|
61
|
+
/** Parse `did:aroha-web:domain[:path]` into its components. */
|
|
62
|
+
export declare function parseWebDID(did: string): {
|
|
63
|
+
domain: string;
|
|
64
|
+
path: string;
|
|
65
|
+
};
|
|
66
|
+
export declare function buildWebDID(domain: string, path: string): string;
|
|
67
|
+
export declare function isWebDID(did: string): boolean;
|
|
68
|
+
/**
|
|
69
|
+
* The HTTP path at which the DID Document should be served.
|
|
70
|
+
* e.g. `did:aroha-web:stripe.com:payments` → `/.well-known/aroha/agents/payments/did.json`
|
|
71
|
+
*/
|
|
72
|
+
export declare function wellKnownPath(did: string): string;
|
|
73
|
+
/**
|
|
74
|
+
* The full HTTPS URL for a given did:aroha-web: identifier.
|
|
75
|
+
*/
|
|
76
|
+
export declare function wellKnownUrl(did: string): string;
|
|
77
|
+
/**
|
|
78
|
+
* Returns the DNS TXT record VALUE (not the full DNS record) for the
|
|
79
|
+
* key-commitment. Publish at: `_aroha.{domain} IN TXT "{this value}"`
|
|
80
|
+
*
|
|
81
|
+
* Format: `v=aroha1; path={path}; keyhash={sha256hex}`
|
|
82
|
+
*/
|
|
83
|
+
export declare function dnsTXTValue(did: string, publicKey: Uint8Array): string;
|
|
84
|
+
/** Parse a DNS TXT value back to its fields. Returns null if invalid. */
|
|
85
|
+
export declare function parseDNSTXT(txt: string): {
|
|
86
|
+
path: string;
|
|
87
|
+
keyhash: string;
|
|
88
|
+
} | null;
|
|
89
|
+
export declare function keyCommitmentHash(publicKey: Uint8Array): string;
|
|
90
|
+
/**
|
|
91
|
+
* Generate a new did:aroha-web: identity.
|
|
92
|
+
*
|
|
93
|
+
* Returns the key pair, the DID Document to serve at the well-known path,
|
|
94
|
+
* the DNS TXT value to publish, and the well-known URL.
|
|
95
|
+
*
|
|
96
|
+
* @param domain The company domain (e.g. "stripe.com")
|
|
97
|
+
* @param path Agent identifier within the domain (e.g. "payments-agent")
|
|
98
|
+
* @param endpoint The Aroha HTTP endpoint URL (e.g. "https://agents.stripe.com/aroha/v1")
|
|
99
|
+
*/
|
|
100
|
+
export declare function generateWebAgent(domain: string, path: string, endpoint?: string): Promise<WebAgentKeyPair>;
|
|
101
|
+
/**
|
|
102
|
+
* Rotate to a new key pair. The old key signs a rotation record that is
|
|
103
|
+
* embedded in the new DID Document. The new key is not trusted until
|
|
104
|
+
* `coolDownHours` (default 24h) after the rotation is announced.
|
|
105
|
+
*
|
|
106
|
+
* Publish the returned `webDocument` at the well-known URL and update the
|
|
107
|
+
* DNS TXT record with `dnsTXTRecord` to complete the rotation.
|
|
108
|
+
*/
|
|
109
|
+
export declare function rotateKey(current: WebAgentKeyPair, coolDownHours?: number): Promise<WebAgentKeyPair>;
|
|
110
|
+
/**
|
|
111
|
+
* Resolve a did:aroha-web: identifier.
|
|
112
|
+
*
|
|
113
|
+
* Fetches the DID Document over HTTPS and, if `verifyDNS` is true,
|
|
114
|
+
* also verifies the DNS TXT key-commitment. Both must match for full
|
|
115
|
+
* two-factor verification.
|
|
116
|
+
*
|
|
117
|
+
* In Node.js server environments, pass a custom `dnsResolver` to perform
|
|
118
|
+
* the DNS TXT lookup. In browser or edge environments, set `verifyDNS: false`
|
|
119
|
+
* (single-channel HTTPS-only, same security as did:wba).
|
|
120
|
+
*
|
|
121
|
+
* @param did The did:aroha-web: identifier to resolve
|
|
122
|
+
* @param verifyDNS Whether to check the DNS TXT record (default: true)
|
|
123
|
+
* @param dnsResolver Optional custom DNS TXT resolver
|
|
124
|
+
*/
|
|
125
|
+
export declare function resolveWebDID(did: string, verifyDNS?: boolean, dnsResolver?: (domain: string) => Promise<string[]>, fetchTimeoutMs?: number): Promise<WebDIDResolutionResult>;
|
|
126
|
+
/**
|
|
127
|
+
* Verify a key rotation record — confirms the predecessor key signed the
|
|
128
|
+
* rotation event voluntarily (prevents unauthorized key replacement).
|
|
129
|
+
*/
|
|
130
|
+
export declare function verifyKeyRotation(rotation: KeyRotationRecord): Promise<boolean>;
|
|
131
|
+
//# sourceMappingURL=web-did.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"web-did.d.ts","sourceRoot":"","sources":["../../src/identity/web-did.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAMH,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,YAAY,EAEjB,KAAK,iBAAiB,EAGvB,MAAM,UAAU,CAAC;AAMlB,MAAM,WAAW,cAAe,SAAQ,WAAW;IACjD,wCAAwC;IACxC,QAAQ,EAAE;QACR,MAAM,EAAE,MAAM,CAAC;QACf,IAAI,EAAE,MAAM,CAAC;QACb,iEAAiE;QACjE,iBAAiB,EAAE,MAAM,CAAC;QAC1B,sEAAsE;QACtE,UAAU,EAAE,iBAAiB,EAAE,CAAC;KACjC,CAAC;CACH;AAED,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAElD,MAAM,WAAW,eAAgB,SAAQ,YAAY;IACnD,8DAA8D;IAC9D,YAAY,EAAE,MAAM,CAAC;IACrB,uDAAuD;IACvD,YAAY,EAAE,MAAM,CAAC;IACrB,yDAAyD;IACzD,WAAW,EAAE,cAAc,CAAC;CAC7B;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,cAAc,CAAC;IACzB,2DAA2D;IAC3D,WAAW,EAAE,OAAO,CAAC;IACrB,4DAA4D;IAC5D,UAAU,EAAE,OAAO,CAAC;IACpB,qCAAqC;IACrC,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAID,+DAA+D;AAC/D,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAczE;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAGhE;AAED,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAE7C;AAID;;;GAGG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAGjD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAGhD;AAID;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,GAAG,MAAM,CAItE;AAED,yEAAyE;AACzE,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAUjF;AAID,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,UAAU,GAAG,MAAM,CAE/D;AAID;;;;;;;;;GASG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,eAAe,CAAC,CAwD1B;AAID;;;;;;;GAOG;AACH,wBAAsB,SAAS,CAC7B,OAAO,EAAE,eAAe,EACxB,aAAa,SAAK,GACjB,OAAO,CAAC,eAAe,CAAC,CAuD1B;AAID;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,aAAa,CACjC,GAAG,EAAE,MAAM,EACX,SAAS,UAAO,EAChB,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,EACnD,cAAc,SAAS,GACtB,OAAO,CAAC,sBAAsB,CAAC,CAiFjC;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CAAC,QAAQ,EAAE,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC,CAYrF"}
|