@didcid/keymaster 0.1.3 → 0.3.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.
@@ -8,41 +8,6 @@ var db_typeGuards = require('./db/typeGuards.cjs');
8
8
  require('crypto');
9
9
  var encryption = require('./encryption.cjs');
10
10
 
11
- class ArchonError extends Error {
12
- type;
13
- detail;
14
- constructor(type, detail) {
15
- const message = detail ? `${type}: ${detail}` : type;
16
- super(message);
17
- this.type = type;
18
- this.detail = detail;
19
- }
20
- }
21
- class InvalidDIDError extends ArchonError {
22
- static type = 'Invalid DID';
23
- constructor(detail) {
24
- super(InvalidDIDError.type, detail);
25
- }
26
- }
27
- class InvalidParameterError extends ArchonError {
28
- static type = 'Invalid parameter';
29
- constructor(detail) {
30
- super(InvalidParameterError.type, detail);
31
- }
32
- }
33
- class KeymasterError extends ArchonError {
34
- static type = 'Keymaster';
35
- constructor(detail) {
36
- super(KeymasterError.type, detail);
37
- }
38
- }
39
- class UnknownIDError extends ArchonError {
40
- static type = 'Unknown ID';
41
- constructor(detail) {
42
- super(UnknownIDError.type, detail);
43
- }
44
- }
45
-
46
11
  function equals$1(aa, bb) {
47
12
  if (aa === bb) {
48
13
  return true;
@@ -443,6 +408,66 @@ function rfc4648({ name, prefix, bitsPerChar, alphabet }) {
443
408
  });
444
409
  }
445
410
 
411
+ rfc4648({
412
+ prefix: 'm',
413
+ name: 'base64',
414
+ alphabet: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
415
+ bitsPerChar: 6
416
+ });
417
+ rfc4648({
418
+ prefix: 'M',
419
+ name: 'base64pad',
420
+ alphabet: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=',
421
+ bitsPerChar: 6
422
+ });
423
+ const base64url = rfc4648({
424
+ prefix: 'u',
425
+ name: 'base64url',
426
+ alphabet: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_',
427
+ bitsPerChar: 6
428
+ });
429
+ rfc4648({
430
+ prefix: 'U',
431
+ name: 'base64urlpad',
432
+ alphabet: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_=',
433
+ bitsPerChar: 6
434
+ });
435
+
436
+ class ArchonError extends Error {
437
+ type;
438
+ detail;
439
+ constructor(type, detail) {
440
+ const message = detail ? `${type}: ${detail}` : type;
441
+ super(message);
442
+ this.type = type;
443
+ this.detail = detail;
444
+ }
445
+ }
446
+ class InvalidDIDError extends ArchonError {
447
+ static type = 'Invalid DID';
448
+ constructor(detail) {
449
+ super(InvalidDIDError.type, detail);
450
+ }
451
+ }
452
+ class InvalidParameterError extends ArchonError {
453
+ static type = 'Invalid parameter';
454
+ constructor(detail) {
455
+ super(InvalidParameterError.type, detail);
456
+ }
457
+ }
458
+ class KeymasterError extends ArchonError {
459
+ static type = 'Keymaster';
460
+ constructor(detail) {
461
+ super(KeymasterError.type, detail);
462
+ }
463
+ }
464
+ class UnknownIDError extends ArchonError {
465
+ static type = 'Unknown ID';
466
+ constructor(detail) {
467
+ super(UnknownIDError.type, detail);
468
+ }
469
+ }
470
+
446
471
  const base32 = rfc4648({
447
472
  prefix: 'b',
448
473
  name: 'base32',
@@ -1057,6 +1082,14 @@ function isValidDID(did) {
1057
1082
  return isValidCID(suffix);
1058
1083
  }
1059
1084
 
1085
+ function hexToBase64url(hex) {
1086
+ const bytes = Buffer.from(hex, 'hex');
1087
+ return base64url.baseEncode(bytes);
1088
+ }
1089
+ function base64urlToHex(b64) {
1090
+ const bytes = base64url.baseDecode(b64);
1091
+ return Buffer.from(bytes).toString('hex');
1092
+ }
1060
1093
  const DefaultSchema = {
1061
1094
  "$schema": "http://json-schema.org/draft-07/schema#",
1062
1095
  "type": "object",
@@ -1091,7 +1124,6 @@ class Keymaster {
1091
1124
  gatekeeper;
1092
1125
  db;
1093
1126
  cipher;
1094
- searchEngine;
1095
1127
  defaultRegistry;
1096
1128
  ephemeralRegistry;
1097
1129
  maxNameLength;
@@ -1108,9 +1140,6 @@ class Keymaster {
1108
1140
  if (!options.cipher || !options.cipher.verifySig) {
1109
1141
  throw new InvalidParameterError('options.cipher');
1110
1142
  }
1111
- if (options.search && !options.search.search) {
1112
- throw new InvalidParameterError('options.search');
1113
- }
1114
1143
  if (!options.passphrase) {
1115
1144
  throw new InvalidParameterError('options.passphrase');
1116
1145
  }
@@ -1118,7 +1147,6 @@ class Keymaster {
1118
1147
  this.gatekeeper = options.gatekeeper;
1119
1148
  this.db = options.wallet;
1120
1149
  this.cipher = options.cipher;
1121
- this.searchEngine = options.search;
1122
1150
  this.defaultRegistry = options.defaultRegistry || 'hyperswarm';
1123
1151
  this.ephemeralRegistry = 'hyperswarm';
1124
1152
  this.maxNameLength = options.maxNameLength || 32;
@@ -1359,13 +1387,15 @@ class Keymaster {
1359
1387
  publicJwk: keypair.publicJwk,
1360
1388
  };
1361
1389
  const msgHash = this.cipher.hashJSON(operation);
1362
- const signature = this.cipher.signHash(msgHash, keypair.privateJwk);
1390
+ const signatureHex = this.cipher.signHash(msgHash, keypair.privateJwk);
1363
1391
  const signed = {
1364
1392
  ...operation,
1365
- signature: {
1366
- signed: new Date(0).toISOString(),
1367
- hash: msgHash,
1368
- value: signature
1393
+ proof: {
1394
+ type: "EcdsaSecp256k1Signature2019",
1395
+ created: new Date(0).toISOString(),
1396
+ verificationMethod: "#key-1",
1397
+ proofPurpose: "authentication",
1398
+ proofValue: hexToBase64url(signatureHex),
1369
1399
  }
1370
1400
  };
1371
1401
  const did = await this.gatekeeper.createDID(signed);
@@ -1386,14 +1416,15 @@ class Keymaster {
1386
1416
  doc,
1387
1417
  };
1388
1418
  const msgHash = this.cipher.hashJSON(operation);
1389
- const signature = this.cipher.signHash(msgHash, keypair.privateJwk);
1419
+ const signatureHex = this.cipher.signHash(msgHash, keypair.privateJwk);
1390
1420
  const signed = {
1391
1421
  ...operation,
1392
- signature: {
1393
- signer: did,
1394
- signed: new Date().toISOString(),
1395
- hash: msgHash,
1396
- value: signature,
1422
+ proof: {
1423
+ type: "EcdsaSecp256k1Signature2019",
1424
+ created: new Date().toISOString(),
1425
+ verificationMethod: `${did}#key-1`,
1426
+ proofPurpose: "authentication",
1427
+ proofValue: hexToBase64url(signatureHex),
1397
1428
  }
1398
1429
  };
1399
1430
  return await this.gatekeeper.updateDID(signed);
@@ -1418,14 +1449,15 @@ class Keymaster {
1418
1449
  data: { backup: backup },
1419
1450
  };
1420
1451
  const msgHash = this.cipher.hashJSON(operation);
1421
- const signature = this.cipher.signHash(msgHash, keypair.privateJwk);
1452
+ const signatureHex = this.cipher.signHash(msgHash, keypair.privateJwk);
1422
1453
  const signed = {
1423
1454
  ...operation,
1424
- signature: {
1425
- signer: seedBank.didDocument?.id,
1426
- signed: new Date().toISOString(),
1427
- hash: msgHash,
1428
- value: signature,
1455
+ proof: {
1456
+ type: "EcdsaSecp256k1Signature2019",
1457
+ created: new Date().toISOString(),
1458
+ verificationMethod: `${seedBank.didDocument?.id}#key-1`,
1459
+ proofPurpose: "authentication",
1460
+ proofValue: hexToBase64url(signatureHex),
1429
1461
  }
1430
1462
  };
1431
1463
  const backupDID = await this.gatekeeper.createDID(signed);
@@ -1606,7 +1638,7 @@ class Keymaster {
1606
1638
  controller: id.did,
1607
1639
  data,
1608
1640
  };
1609
- const signed = await this.addSignature(operation, controller);
1641
+ const signed = await this.addProof(operation, controller, "authentication");
1610
1642
  const did = await this.gatekeeper.createDID(signed);
1611
1643
  // Keep assets that will be garbage-collected out of the owned list
1612
1644
  if (!validUntil) {
@@ -1795,7 +1827,7 @@ class Keymaster {
1795
1827
  throw new InvalidParameterError('did not encrypted JSON');
1796
1828
  }
1797
1829
  }
1798
- async addSignature(obj, controller) {
1830
+ async addProof(obj, controller, proofPurpose = "assertionMethod") {
1799
1831
  if (obj == null) {
1800
1832
  throw new InvalidParameterError('obj');
1801
1833
  }
@@ -1803,18 +1835,23 @@ class Keymaster {
1803
1835
  const id = await this.fetchIdInfo(controller);
1804
1836
  const keypair = await this.fetchKeyPair(controller);
1805
1837
  if (!keypair) {
1806
- throw new KeymasterError('addSignature: no keypair');
1838
+ throw new KeymasterError('addProof: no keypair');
1807
1839
  }
1840
+ // Get the key fragment from the DID document
1841
+ const doc = await this.resolveDID(id.did, { confirm: true });
1842
+ const keyFragment = doc.didDocument?.verificationMethod?.[0]?.id || '#key-1';
1808
1843
  try {
1809
1844
  const msgHash = this.cipher.hashJSON(obj);
1810
- const signature = this.cipher.signHash(msgHash, keypair.privateJwk);
1845
+ const signatureHex = this.cipher.signHash(msgHash, keypair.privateJwk);
1846
+ const proofValue = hexToBase64url(signatureHex);
1811
1847
  return {
1812
1848
  ...obj,
1813
- signature: {
1814
- signer: id.did,
1815
- signed: new Date().toISOString(),
1816
- hash: msgHash,
1817
- value: signature,
1849
+ proof: {
1850
+ type: "EcdsaSecp256k1Signature2019",
1851
+ created: new Date().toISOString(),
1852
+ verificationMethod: `${id.did}${keyFragment}`,
1853
+ proofPurpose,
1854
+ proofValue,
1818
1855
  }
1819
1856
  };
1820
1857
  }
@@ -1822,24 +1859,27 @@ class Keymaster {
1822
1859
  throw new InvalidParameterError('obj');
1823
1860
  }
1824
1861
  }
1825
- async verifySignature(obj) {
1826
- if (!obj?.signature) {
1862
+ async verifyProof(obj) {
1863
+ if (!obj?.proof) {
1827
1864
  return false;
1828
1865
  }
1829
- const { signature } = obj;
1830
- if (!signature.signer) {
1866
+ const { proof } = obj;
1867
+ if (proof.type !== "EcdsaSecp256k1Signature2019") {
1831
1868
  return false;
1832
1869
  }
1833
- const jsonCopy = JSON.parse(JSON.stringify(obj));
1834
- delete jsonCopy.signature;
1835
- const msgHash = this.cipher.hashJSON(jsonCopy);
1836
- if (signature.hash && signature.hash !== msgHash) {
1870
+ if (!proof.verificationMethod) {
1837
1871
  return false;
1838
1872
  }
1839
- const doc = await this.resolveDID(signature.signer, { versionTime: signature.signed });
1873
+ // Extract DID from verificationMethod
1874
+ const [signerDid] = proof.verificationMethod.split('#');
1875
+ const jsonCopy = JSON.parse(JSON.stringify(obj));
1876
+ delete jsonCopy.proof;
1877
+ const msgHash = this.cipher.hashJSON(jsonCopy);
1878
+ const doc = await this.resolveDID(signerDid, { versionTime: proof.created });
1840
1879
  const publicJwk = this.getPublicKeyJwk(doc);
1841
1880
  try {
1842
- return this.cipher.verifySig(msgHash, signature.value, publicJwk);
1881
+ const signatureHex = base64urlToHex(proof.proofValue);
1882
+ return this.cipher.verifySig(msgHash, signatureHex, publicJwk);
1843
1883
  }
1844
1884
  catch (error) {
1845
1885
  return false;
@@ -1868,7 +1908,7 @@ class Keymaster {
1868
1908
  else if (current.didDocumentRegistration?.type === 'asset') {
1869
1909
  controller = current.didDocument?.controller;
1870
1910
  }
1871
- const signed = await this.addSignature(operation, controller);
1911
+ const signed = await this.addProof(operation, controller, "authentication");
1872
1912
  return this.gatekeeper.updateDID(signed);
1873
1913
  }
1874
1914
  async revokeDID(id) {
@@ -1890,7 +1930,7 @@ class Keymaster {
1890
1930
  else if (current.didDocumentRegistration?.type === 'asset') {
1891
1931
  controller = current.didDocument?.controller;
1892
1932
  }
1893
- const signed = await this.addSignature(operation, controller);
1933
+ const signed = await this.addProof(operation, controller, "authentication");
1894
1934
  const ok = await this.gatekeeper.deleteDID(signed);
1895
1935
  if (ok && current.didDocument?.controller) {
1896
1936
  await this.removeFromOwned(did, current.didDocument.controller);
@@ -1970,9 +2010,13 @@ class Keymaster {
1970
2010
  }
1971
2011
  const controller = docs.didDocument?.controller || docs.didDocument?.id;
1972
2012
  const isOwned = await this.idInWallet(controller);
1973
- // Augment the DID document metadata with the DID ownership status
2013
+ // Convert versionSequence string to numeric version
2014
+ const versionSequence = docs.didDocumentMetadata?.versionSequence;
2015
+ const version = versionSequence ? parseInt(versionSequence, 10) : undefined;
2016
+ // Augment the DID document metadata with the DID ownership status and numeric version
1974
2017
  docs.didDocumentMetadata = {
1975
2018
  ...docs.didDocumentMetadata,
2019
+ version,
1976
2020
  isOwned,
1977
2021
  };
1978
2022
  return docs;
@@ -2091,13 +2135,15 @@ class Keymaster {
2091
2135
  publicJwk: keypair.publicJwk,
2092
2136
  };
2093
2137
  const msgHash = this.cipher.hashJSON(operation);
2094
- const signature = this.cipher.signHash(msgHash, keypair.privateJwk);
2138
+ const signatureHex = this.cipher.signHash(msgHash, keypair.privateJwk);
2095
2139
  const signed = {
2096
2140
  ...operation,
2097
- signature: {
2098
- signed: new Date().toISOString(),
2099
- hash: msgHash,
2100
- value: signature
2141
+ proof: {
2142
+ type: "EcdsaSecp256k1Signature2019",
2143
+ created: new Date().toISOString(),
2144
+ verificationMethod: "#key-1",
2145
+ proofPurpose: "authentication",
2146
+ proofValue: hexToBase64url(signatureHex),
2101
2147
  },
2102
2148
  };
2103
2149
  return signed;
@@ -2151,10 +2197,10 @@ class Keymaster {
2151
2197
  if (!registry) {
2152
2198
  throw new InvalidParameterError('no registry found for agent DID');
2153
2199
  }
2154
- const vaultDid = await this.createAsset({ backup: backup }, { registry, controller: name });
2200
+ const backupStoreDid = await this.createAsset({ backup: backup }, { registry, controller: name });
2155
2201
  if (doc.didDocumentData) {
2156
2202
  const currentData = doc.didDocumentData;
2157
- const updatedData = { ...currentData, vault: vaultDid };
2203
+ const updatedData = { ...currentData, backupStore: backupStoreDid };
2158
2204
  return this.updateDID(name, { didDocumentData: updatedData });
2159
2205
  }
2160
2206
  return false;
@@ -2164,14 +2210,14 @@ class Keymaster {
2164
2210
  const keypair = await this.hdKeyPair();
2165
2211
  const doc = await this.resolveDID(did);
2166
2212
  const docData = doc.didDocumentData;
2167
- if (!docData.vault) {
2168
- throw new InvalidDIDError('didDocumentData missing vault');
2213
+ if (!docData.backupStore) {
2214
+ throw new InvalidDIDError('didDocumentData missing backupStore');
2169
2215
  }
2170
- const vault = await this.resolveAsset(docData.vault);
2171
- if (typeof vault.backup !== 'string') {
2172
- throw new InvalidDIDError('backup not found in vault');
2216
+ const backupStore = await this.resolveAsset(docData.backupStore);
2217
+ if (typeof backupStore.backup !== 'string') {
2218
+ throw new InvalidDIDError('backup not found in backupStore');
2173
2219
  }
2174
- const backup = this.cipher.decryptMessage(keypair.publicJwk, keypair.privateJwk, vault.backup);
2220
+ const backup = this.cipher.decryptMessage(keypair.publicJwk, keypair.privateJwk, backupStore.backup);
2175
2221
  const data = JSON.parse(backup);
2176
2222
  await this.mutateWallet((wallet) => {
2177
2223
  if (wallet.ids[data.name]) {
@@ -2215,6 +2261,7 @@ class Keymaster {
2215
2261
  ...doc.didDocument,
2216
2262
  verificationMethod: [vmethod],
2217
2263
  authentication: [vmethod.id],
2264
+ assertionMethod: [vmethod.id],
2218
2265
  };
2219
2266
  ok = await this.updateDID(id.did, { didDocument: updatedDidDocument });
2220
2267
  if (!ok) {
@@ -2227,7 +2274,7 @@ class Keymaster {
2227
2274
  async listNames(options = {}) {
2228
2275
  const { includeIDs = false } = options;
2229
2276
  const wallet = await this.loadWallet();
2230
- const names = wallet.names || {};
2277
+ const names = { ...(wallet.names || {}) };
2231
2278
  if (includeIDs) {
2232
2279
  for (const [name, id] of Object.entries(wallet.ids || {})) {
2233
2280
  names[name] = id.did;
@@ -2265,42 +2312,60 @@ class Keymaster {
2265
2312
  const doc = await this.resolveDID(id);
2266
2313
  return doc.didDocumentRegistration?.type === 'agent';
2267
2314
  }
2268
- async bindCredential(schemaId, subjectId, options = {}) {
2269
- let { validFrom, validUntil, credential } = options;
2315
+ async bindCredential(subjectId, options = {}) {
2316
+ let { schema, validFrom, validUntil, claims, types } = options;
2270
2317
  if (!validFrom) {
2271
2318
  validFrom = new Date().toISOString();
2272
2319
  }
2273
2320
  const id = await this.fetchIdInfo();
2274
- const type = await this.lookupDID(schemaId);
2275
2321
  const subjectDID = await this.lookupDID(subjectId);
2276
- if (!credential) {
2277
- const schema = await this.getSchema(type);
2278
- credential = this.generateSchema(schema);
2279
- }
2280
- return {
2322
+ const vc = {
2281
2323
  "@context": [
2282
2324
  "https://www.w3.org/ns/credentials/v2",
2283
2325
  "https://www.w3.org/ns/credentials/examples/v2"
2284
2326
  ],
2285
- type: ["VerifiableCredential", type],
2327
+ type: ["VerifiableCredential", ...(types || [])],
2286
2328
  issuer: id.did,
2287
2329
  validFrom,
2288
2330
  validUntil,
2289
2331
  credentialSubject: {
2290
2332
  id: subjectDID,
2291
2333
  },
2292
- credential,
2293
2334
  };
2335
+ // If schema provided, add credentialSchema and generate claims from schema
2336
+ if (schema) {
2337
+ const schemaDID = await this.lookupDID(schema);
2338
+ const schemaDoc = await this.getSchema(schemaDID);
2339
+ if (!claims && schemaDoc) {
2340
+ claims = this.generateSchema(schemaDoc);
2341
+ }
2342
+ // If schema has $credentialTypes, add them to credential types (avoiding duplicates)
2343
+ if (schemaDoc?.$credentialTypes) {
2344
+ const newTypes = schemaDoc.$credentialTypes.filter(t => !vc.type.includes(t));
2345
+ vc.type.push(...newTypes);
2346
+ }
2347
+ vc.credentialSchema = {
2348
+ id: schemaDID,
2349
+ type: "JsonSchema",
2350
+ };
2351
+ }
2352
+ if (claims) {
2353
+ vc.credentialSubject = {
2354
+ id: subjectDID,
2355
+ ...claims,
2356
+ };
2357
+ }
2358
+ return vc;
2294
2359
  }
2295
2360
  async issueCredential(credential, options = {}) {
2296
2361
  const id = await this.fetchIdInfo();
2297
2362
  if (options.schema && options.subject) {
2298
- credential = await this.bindCredential(options.schema, options.subject, { credential, ...options });
2363
+ credential = await this.bindCredential(options.subject, { schema: options.schema, claims: options.claims, ...options });
2299
2364
  }
2300
2365
  if (credential.issuer !== id.did) {
2301
2366
  throw new InvalidParameterError('credential.issuer');
2302
2367
  }
2303
- const signed = await this.addSignature(credential);
2368
+ const signed = await this.addProof(credential);
2304
2369
  return this.encryptJSON(signed, credential.credentialSubject.id, { ...options, includeHash: true });
2305
2370
  }
2306
2371
  async sendCredential(did, options = {}) {
@@ -2330,13 +2395,12 @@ class Keymaster {
2330
2395
  throw new InvalidParameterError("did is not a credential");
2331
2396
  }
2332
2397
  if (!credential ||
2333
- !credential.credential ||
2334
2398
  !credential.credentialSubject ||
2335
2399
  !credential.credentialSubject.id) {
2336
2400
  throw new InvalidParameterError('credential');
2337
2401
  }
2338
- delete credential.signature;
2339
- const signed = await this.addSignature(credential);
2402
+ delete credential.proof;
2403
+ const signed = await this.addProof(credential);
2340
2404
  const msg = JSON.stringify(signed);
2341
2405
  const id = await this.fetchIdInfo();
2342
2406
  const senderKeypair = await this.fetchKeyPair();
@@ -2430,8 +2494,8 @@ class Keymaster {
2430
2494
  data.manifest = {};
2431
2495
  }
2432
2496
  if (!reveal) {
2433
- // Remove the credential values
2434
- vc.credential = null;
2497
+ // Remove the claim values, keep only the subject id
2498
+ vc.credentialSubject = { id: vc.credentialSubject.id };
2435
2499
  }
2436
2500
  data.manifest[credential] = vc;
2437
2501
  const ok = await this.updateDID(id.did, { didDocumentData: doc.didDocumentData });
@@ -2489,8 +2553,8 @@ class Keymaster {
2489
2553
  // Attestor not trusted by Verifier
2490
2554
  continue;
2491
2555
  }
2492
- if (doc.type && !doc.type.includes(credential.schema)) {
2493
- // Wrong type
2556
+ if (doc.credentialSchema?.id !== credential.schema) {
2557
+ // Wrong schema
2494
2558
  continue;
2495
2559
  }
2496
2560
  // TBD test for VC expiry too
@@ -2615,7 +2679,7 @@ class Keymaster {
2615
2679
  continue;
2616
2680
  }
2617
2681
  const vp = await this.decryptJSON(credential.vp);
2618
- const isValid = await this.verifySignature(vp);
2682
+ const isValid = await this.verifyProof(vp);
2619
2683
  if (!isValid) {
2620
2684
  continue;
2621
2685
  }
@@ -2623,8 +2687,8 @@ class Keymaster {
2623
2687
  continue;
2624
2688
  }
2625
2689
  // Check VP against VCs specified in challenge
2626
- if (vp.type.length >= 2 && vp.type[1].startsWith('did:')) {
2627
- const schema = vp.type[1];
2690
+ if (vp.credentialSchema?.id) {
2691
+ const schema = vp.credentialSchema.id;
2628
2692
  const credential = challenge.credentials?.find(item => item.schema === schema);
2629
2693
  if (!credential) {
2630
2694
  continue;
@@ -3122,7 +3186,7 @@ class Keymaster {
3122
3186
  delete poll.results;
3123
3187
  return this.updateAsset(pollId, { poll });
3124
3188
  }
3125
- async createGroupVault(options = {}) {
3189
+ async createVault(options = {}) {
3126
3190
  const id = await this.fetchIdInfo();
3127
3191
  const idKeypair = await this.fetchKeyPair();
3128
3192
  // version defaults to 1. To make version undefined (unit testing), set options.version to 0
@@ -3137,7 +3201,7 @@ class Keymaster {
3137
3201
  const members = this.cipher.encryptMessage(publicJwk, vaultKeypair.privateJwk, JSON.stringify({}));
3138
3202
  const items = this.cipher.encryptMessage(vaultKeypair.publicJwk, vaultKeypair.privateJwk, JSON.stringify({}));
3139
3203
  const sha256 = this.cipher.hashJSON({});
3140
- const groupVault = {
3204
+ const vault = {
3141
3205
  version,
3142
3206
  publicJwk: vaultKeypair.publicJwk,
3143
3207
  salt,
@@ -3147,46 +3211,46 @@ class Keymaster {
3147
3211
  items,
3148
3212
  sha256,
3149
3213
  };
3150
- await this.addMemberKey(groupVault, id.did, vaultKeypair.privateJwk);
3151
- return this.createAsset({ groupVault }, options);
3214
+ await this.addMemberKey(vault, id.did, vaultKeypair.privateJwk);
3215
+ return this.createAsset({ vault }, options);
3152
3216
  }
3153
- async getGroupVault(groupVaultId, options) {
3154
- const asset = await this.resolveAsset(groupVaultId, options);
3155
- if (!asset.groupVault) {
3156
- throw new InvalidParameterError('groupVaultId');
3217
+ async getVault(vaultId, options) {
3218
+ const asset = await this.resolveAsset(vaultId, options);
3219
+ if (!asset.vault) {
3220
+ throw new InvalidParameterError('vaultId');
3157
3221
  }
3158
- return asset.groupVault;
3222
+ return asset.vault;
3159
3223
  }
3160
- async testGroupVault(id, options) {
3224
+ async testVault(id, options) {
3161
3225
  try {
3162
- const groupVault = await this.getGroupVault(id, options);
3163
- return groupVault !== null;
3226
+ const vault = await this.getVault(id, options);
3227
+ return vault !== null;
3164
3228
  }
3165
3229
  catch (error) {
3166
3230
  return false;
3167
3231
  }
3168
3232
  }
3169
- generateSaltedId(groupVault, memberDID) {
3170
- if (!groupVault.version) {
3171
- return this.cipher.hashMessage(groupVault.salt + memberDID);
3233
+ generateSaltedId(vault, memberDID) {
3234
+ if (!vault.version) {
3235
+ return this.cipher.hashMessage(vault.salt + memberDID);
3172
3236
  }
3173
3237
  const suffix = memberDID.split(':').pop();
3174
- return this.cipher.hashMessage(groupVault.salt + suffix);
3238
+ return this.cipher.hashMessage(vault.salt + suffix);
3175
3239
  }
3176
- async decryptGroupVault(groupVault) {
3240
+ async decryptVault(vault) {
3177
3241
  const wallet = await this.loadWallet();
3178
3242
  const id = await this.fetchIdInfo();
3179
- const myMemberId = this.generateSaltedId(groupVault, id.did);
3180
- const myVaultKey = groupVault.keys[myMemberId];
3243
+ const myMemberId = this.generateSaltedId(vault, id.did);
3244
+ const myVaultKey = vault.keys[myMemberId];
3181
3245
  if (!myVaultKey) {
3182
- throw new KeymasterError('No access to group vault');
3246
+ throw new KeymasterError('No access to vault');
3183
3247
  }
3184
- const privKeyJSON = await this.decryptWithDerivedKeys(wallet, id, groupVault.publicJwk, myVaultKey);
3248
+ const privKeyJSON = await this.decryptWithDerivedKeys(wallet, id, vault.publicJwk, myVaultKey);
3185
3249
  const privateJwk = JSON.parse(privKeyJSON);
3186
3250
  let config = {};
3187
3251
  let isOwner = false;
3188
3252
  try {
3189
- const configJSON = await this.decryptWithDerivedKeys(wallet, id, groupVault.publicJwk, groupVault.config);
3253
+ const configJSON = await this.decryptWithDerivedKeys(wallet, id, vault.publicJwk, vault.config);
3190
3254
  config = JSON.parse(configJSON);
3191
3255
  isOwner = true;
3192
3256
  }
@@ -3196,7 +3260,7 @@ class Keymaster {
3196
3260
  let members = {};
3197
3261
  if (config.secretMembers) {
3198
3262
  try {
3199
- const membersJSON = await this.decryptWithDerivedKeys(wallet, id, groupVault.publicJwk, groupVault.members);
3263
+ const membersJSON = await this.decryptWithDerivedKeys(wallet, id, vault.publicJwk, vault.members);
3200
3264
  members = JSON.parse(membersJSON);
3201
3265
  }
3202
3266
  catch (error) {
@@ -3204,13 +3268,13 @@ class Keymaster {
3204
3268
  }
3205
3269
  else {
3206
3270
  try {
3207
- const membersJSON = this.cipher.decryptMessage(groupVault.publicJwk, privateJwk, groupVault.members);
3271
+ const membersJSON = this.cipher.decryptMessage(vault.publicJwk, privateJwk, vault.members);
3208
3272
  members = JSON.parse(membersJSON);
3209
3273
  }
3210
3274
  catch (error) {
3211
3275
  }
3212
3276
  }
3213
- const itemsJSON = this.cipher.decryptMessage(groupVault.publicJwk, privateJwk, groupVault.items);
3277
+ const itemsJSON = this.cipher.decryptMessage(vault.publicJwk, privateJwk, vault.items);
3214
3278
  const items = JSON.parse(itemsJSON);
3215
3279
  return {
3216
3280
  isOwner,
@@ -3220,7 +3284,7 @@ class Keymaster {
3220
3284
  items,
3221
3285
  };
3222
3286
  }
3223
- async checkGroupVaultOwner(vaultId) {
3287
+ async checkVaultOwner(vaultId) {
3224
3288
  const id = await this.fetchIdInfo();
3225
3289
  const vaultDoc = await this.resolveDID(vaultId);
3226
3290
  const controller = vaultDoc.didDocument?.controller;
@@ -3229,30 +3293,30 @@ class Keymaster {
3229
3293
  }
3230
3294
  return controller;
3231
3295
  }
3232
- async addMemberKey(groupVault, memberDID, privateJwk) {
3296
+ async addMemberKey(vault, memberDID, privateJwk) {
3233
3297
  const memberDoc = await this.resolveDID(memberDID, { confirm: true });
3234
3298
  const memberPublicJwk = this.getPublicKeyJwk(memberDoc);
3235
3299
  const memberKey = this.cipher.encryptMessage(memberPublicJwk, privateJwk, JSON.stringify(privateJwk));
3236
- const memberKeyId = this.generateSaltedId(groupVault, memberDID);
3237
- groupVault.keys[memberKeyId] = memberKey;
3300
+ const memberKeyId = this.generateSaltedId(vault, memberDID);
3301
+ vault.keys[memberKeyId] = memberKey;
3238
3302
  }
3239
- async checkVaultVersion(vaultId, groupVault) {
3240
- if (groupVault.version === 1) {
3303
+ async checkVaultVersion(vaultId, vault) {
3304
+ if (vault.version === 1) {
3241
3305
  return;
3242
3306
  }
3243
- if (!groupVault.version) {
3307
+ if (!vault.version) {
3244
3308
  const id = await this.fetchIdInfo();
3245
- const { privateJwk, members } = await this.decryptGroupVault(groupVault);
3246
- groupVault.version = 1;
3247
- groupVault.keys = {};
3248
- await this.addMemberKey(groupVault, id.did, privateJwk);
3309
+ const { privateJwk, members } = await this.decryptVault(vault);
3310
+ vault.version = 1;
3311
+ vault.keys = {};
3312
+ await this.addMemberKey(vault, id.did, privateJwk);
3249
3313
  for (const memberDID of Object.keys(members)) {
3250
- await this.addMemberKey(groupVault, memberDID, privateJwk);
3314
+ await this.addMemberKey(vault, memberDID, privateJwk);
3251
3315
  }
3252
- await this.updateAsset(vaultId, { groupVault });
3316
+ await this.updateAsset(vaultId, { vault });
3253
3317
  return;
3254
3318
  }
3255
- throw new KeymasterError('Unsupported group vault version');
3319
+ throw new KeymasterError('Unsupported vault version');
3256
3320
  }
3257
3321
  getAgentDID(doc) {
3258
3322
  if (doc.didDocumentRegistration?.type !== 'agent') {
@@ -3264,11 +3328,11 @@ class Keymaster {
3264
3328
  }
3265
3329
  return did;
3266
3330
  }
3267
- async addGroupVaultMember(vaultId, memberId) {
3268
- const owner = await this.checkGroupVaultOwner(vaultId);
3331
+ async addVaultMember(vaultId, memberId) {
3332
+ const owner = await this.checkVaultOwner(vaultId);
3269
3333
  const idKeypair = await this.fetchKeyPair();
3270
- const groupVault = await this.getGroupVault(vaultId);
3271
- const { privateJwk, config, members } = await this.decryptGroupVault(groupVault);
3334
+ const vault = await this.getVault(vaultId);
3335
+ const { privateJwk, config, members } = await this.decryptVault(vault);
3272
3336
  const memberDoc = await this.resolveDID(memberId, { confirm: true });
3273
3337
  const memberDID = this.getAgentDID(memberDoc);
3274
3338
  // Don't allow adding the vault owner
@@ -3276,16 +3340,16 @@ class Keymaster {
3276
3340
  return false;
3277
3341
  }
3278
3342
  members[memberDID] = { added: new Date().toISOString() };
3279
- const publicJwk = config.secretMembers ? idKeypair.publicJwk : groupVault.publicJwk;
3280
- groupVault.members = this.cipher.encryptMessage(publicJwk, privateJwk, JSON.stringify(members));
3281
- await this.addMemberKey(groupVault, memberDID, privateJwk);
3282
- return this.updateAsset(vaultId, { groupVault });
3343
+ const publicJwk = config.secretMembers ? idKeypair.publicJwk : vault.publicJwk;
3344
+ vault.members = this.cipher.encryptMessage(publicJwk, privateJwk, JSON.stringify(members));
3345
+ await this.addMemberKey(vault, memberDID, privateJwk);
3346
+ return this.updateAsset(vaultId, { vault });
3283
3347
  }
3284
- async removeGroupVaultMember(vaultId, memberId) {
3285
- const owner = await this.checkGroupVaultOwner(vaultId);
3348
+ async removeVaultMember(vaultId, memberId) {
3349
+ const owner = await this.checkVaultOwner(vaultId);
3286
3350
  const idKeypair = await this.fetchKeyPair();
3287
- const groupVault = await this.getGroupVault(vaultId);
3288
- const { privateJwk, config, members } = await this.decryptGroupVault(groupVault);
3351
+ const vault = await this.getVault(vaultId);
3352
+ const { privateJwk, config, members } = await this.decryptVault(vault);
3289
3353
  const memberDoc = await this.resolveDID(memberId, { confirm: true });
3290
3354
  const memberDID = this.getAgentDID(memberDoc);
3291
3355
  // Don't allow removing the vault owner
@@ -3293,26 +3357,26 @@ class Keymaster {
3293
3357
  return false;
3294
3358
  }
3295
3359
  delete members[memberDID];
3296
- const publicJwk = config.secretMembers ? idKeypair.publicJwk : groupVault.publicJwk;
3297
- groupVault.members = this.cipher.encryptMessage(publicJwk, privateJwk, JSON.stringify(members));
3298
- const memberKeyId = this.generateSaltedId(groupVault, memberDID);
3299
- delete groupVault.keys[memberKeyId];
3300
- return this.updateAsset(vaultId, { groupVault });
3301
- }
3302
- async listGroupVaultMembers(vaultId) {
3303
- const groupVault = await this.getGroupVault(vaultId);
3304
- const { members, isOwner } = await this.decryptGroupVault(groupVault);
3360
+ const publicJwk = config.secretMembers ? idKeypair.publicJwk : vault.publicJwk;
3361
+ vault.members = this.cipher.encryptMessage(publicJwk, privateJwk, JSON.stringify(members));
3362
+ const memberKeyId = this.generateSaltedId(vault, memberDID);
3363
+ delete vault.keys[memberKeyId];
3364
+ return this.updateAsset(vaultId, { vault });
3365
+ }
3366
+ async listVaultMembers(vaultId) {
3367
+ const vault = await this.getVault(vaultId);
3368
+ const { members, isOwner } = await this.decryptVault(vault);
3305
3369
  if (isOwner) {
3306
- await this.checkVaultVersion(vaultId, groupVault);
3370
+ await this.checkVaultVersion(vaultId, vault);
3307
3371
  }
3308
3372
  return members;
3309
3373
  }
3310
- async addGroupVaultItem(vaultId, name, buffer) {
3311
- await this.checkGroupVaultOwner(vaultId);
3312
- const groupVault = await this.getGroupVault(vaultId);
3313
- const { privateJwk, items } = await this.decryptGroupVault(groupVault);
3374
+ async addVaultItem(vaultId, name, buffer) {
3375
+ await this.checkVaultOwner(vaultId);
3376
+ const vault = await this.getVault(vaultId);
3377
+ const { privateJwk, items } = await this.decryptVault(vault);
3314
3378
  const validName = this.validateName(name);
3315
- const encryptedData = this.cipher.encryptBytes(groupVault.publicJwk, privateJwk, buffer);
3379
+ const encryptedData = this.cipher.encryptBytes(vault.publicJwk, privateJwk, buffer);
3316
3380
  const cid = await this.gatekeeper.addText(encryptedData);
3317
3381
  const sha256 = this.cipher.hashMessage(buffer);
3318
3382
  const type = await this.getMimeType(buffer);
@@ -3325,32 +3389,32 @@ class Keymaster {
3325
3389
  added: new Date().toISOString(),
3326
3390
  data,
3327
3391
  };
3328
- groupVault.items = this.cipher.encryptMessage(groupVault.publicJwk, privateJwk, JSON.stringify(items));
3329
- groupVault.sha256 = this.cipher.hashJSON(items);
3330
- return this.updateAsset(vaultId, { groupVault });
3331
- }
3332
- async removeGroupVaultItem(vaultId, name) {
3333
- await this.checkGroupVaultOwner(vaultId);
3334
- const groupVault = await this.getGroupVault(vaultId);
3335
- const { privateJwk, items } = await this.decryptGroupVault(groupVault);
3392
+ vault.items = this.cipher.encryptMessage(vault.publicJwk, privateJwk, JSON.stringify(items));
3393
+ vault.sha256 = this.cipher.hashJSON(items);
3394
+ return this.updateAsset(vaultId, { vault });
3395
+ }
3396
+ async removeVaultItem(vaultId, name) {
3397
+ await this.checkVaultOwner(vaultId);
3398
+ const vault = await this.getVault(vaultId);
3399
+ const { privateJwk, items } = await this.decryptVault(vault);
3336
3400
  delete items[name];
3337
- groupVault.items = this.cipher.encryptMessage(groupVault.publicJwk, privateJwk, JSON.stringify(items));
3338
- groupVault.sha256 = this.cipher.hashJSON(items);
3339
- return this.updateAsset(vaultId, { groupVault });
3401
+ vault.items = this.cipher.encryptMessage(vault.publicJwk, privateJwk, JSON.stringify(items));
3402
+ vault.sha256 = this.cipher.hashJSON(items);
3403
+ return this.updateAsset(vaultId, { vault });
3340
3404
  }
3341
- async listGroupVaultItems(vaultId, options) {
3342
- const groupVault = await this.getGroupVault(vaultId, options);
3343
- const { items } = await this.decryptGroupVault(groupVault);
3405
+ async listVaultItems(vaultId, options) {
3406
+ const vault = await this.getVault(vaultId, options);
3407
+ const { items } = await this.decryptVault(vault);
3344
3408
  return items;
3345
3409
  }
3346
- async getGroupVaultItem(vaultId, name, options) {
3410
+ async getVaultItem(vaultId, name, options) {
3347
3411
  try {
3348
- const groupVault = await this.getGroupVault(vaultId, options);
3349
- const { privateJwk, items } = await this.decryptGroupVault(groupVault);
3412
+ const vault = await this.getVault(vaultId, options);
3413
+ const { privateJwk, items } = await this.decryptVault(vault);
3350
3414
  if (items[name]) {
3351
3415
  const encryptedData = items[name].data || await this.gatekeeper.getText(items[name].cid);
3352
3416
  if (encryptedData) {
3353
- const bytes = this.cipher.decryptBytes(groupVault.publicJwk, privateJwk, encryptedData);
3417
+ const bytes = this.cipher.decryptBytes(vault.publicJwk, privateJwk, encryptedData);
3354
3418
  return Buffer.from(bytes);
3355
3419
  }
3356
3420
  }
@@ -3479,28 +3543,28 @@ class Keymaster {
3479
3543
  }
3480
3544
  async createDmail(message, options = {}) {
3481
3545
  const dmail = await this.verifyDmail(message);
3482
- const did = await this.createGroupVault(options);
3546
+ const did = await this.createVault(options);
3483
3547
  for (const toDID of dmail.to) {
3484
- await this.addGroupVaultMember(did, toDID);
3548
+ await this.addVaultMember(did, toDID);
3485
3549
  }
3486
3550
  for (const ccDID of dmail.cc) {
3487
- await this.addGroupVaultMember(did, ccDID);
3551
+ await this.addVaultMember(did, ccDID);
3488
3552
  }
3489
3553
  const buffer = Buffer.from(JSON.stringify({ dmail }), 'utf-8');
3490
- await this.addGroupVaultItem(did, exports.DmailTags.DMAIL, buffer);
3554
+ await this.addVaultItem(did, exports.DmailTags.DMAIL, buffer);
3491
3555
  await this.fileDmail(did, [exports.DmailTags.DRAFT]);
3492
3556
  return did;
3493
3557
  }
3494
3558
  async updateDmail(did, message) {
3495
3559
  const dmail = await this.verifyDmail(message);
3496
3560
  for (const toDID of dmail.to) {
3497
- await this.addGroupVaultMember(did, toDID);
3561
+ await this.addVaultMember(did, toDID);
3498
3562
  }
3499
3563
  for (const ccDID of dmail.cc) {
3500
- await this.addGroupVaultMember(did, ccDID);
3564
+ await this.addVaultMember(did, ccDID);
3501
3565
  }
3502
3566
  const buffer = Buffer.from(JSON.stringify({ dmail }), 'utf-8');
3503
- return this.addGroupVaultItem(did, exports.DmailTags.DMAIL, buffer);
3567
+ return this.addVaultItem(did, exports.DmailTags.DMAIL, buffer);
3504
3568
  }
3505
3569
  async sendDmail(did) {
3506
3570
  const dmail = await this.getDmailMessage(did);
@@ -3520,11 +3584,11 @@ class Keymaster {
3520
3584
  return notice;
3521
3585
  }
3522
3586
  async getDmailMessage(did, options) {
3523
- const isGroupVault = await this.testGroupVault(did, options);
3524
- if (!isGroupVault) {
3587
+ const isVault = await this.testVault(did, options);
3588
+ if (!isVault) {
3525
3589
  return null;
3526
3590
  }
3527
- const buffer = await this.getGroupVaultItem(did, exports.DmailTags.DMAIL, options);
3591
+ const buffer = await this.getVaultItem(did, exports.DmailTags.DMAIL, options);
3528
3592
  if (!buffer) {
3529
3593
  return null;
3530
3594
  }
@@ -3537,7 +3601,7 @@ class Keymaster {
3537
3601
  }
3538
3602
  }
3539
3603
  async listDmailAttachments(did, options) {
3540
- let items = await this.listGroupVaultItems(did, options);
3604
+ let items = await this.listVaultItems(did, options);
3541
3605
  delete items[exports.DmailTags.DMAIL]; // Remove the dmail item itself from attachments
3542
3606
  return items;
3543
3607
  }
@@ -3545,16 +3609,16 @@ class Keymaster {
3545
3609
  if (name === exports.DmailTags.DMAIL) {
3546
3610
  throw new InvalidParameterError('Cannot add attachment with reserved name "dmail"');
3547
3611
  }
3548
- return this.addGroupVaultItem(did, name, buffer);
3612
+ return this.addVaultItem(did, name, buffer);
3549
3613
  }
3550
3614
  async removeDmailAttachment(did, name) {
3551
3615
  if (name === exports.DmailTags.DMAIL) {
3552
3616
  throw new InvalidParameterError('Cannot remove attachment with reserved name "dmail"');
3553
3617
  }
3554
- return this.removeGroupVaultItem(did, name);
3618
+ return this.removeVaultItem(did, name);
3555
3619
  }
3556
3620
  async getDmailAttachment(did, name) {
3557
- return this.getGroupVaultItem(did, name);
3621
+ return this.getVaultItem(did, name);
3558
3622
  }
3559
3623
  async importDmail(did) {
3560
3624
  const dmail = await this.getDmailMessage(did);
@@ -3656,23 +3720,20 @@ class Keymaster {
3656
3720
  return true;
3657
3721
  }
3658
3722
  async searchNotices() {
3659
- if (!this.searchEngine) {
3660
- return false; // Search engine not available
3661
- }
3662
3723
  const id = await this.fetchIdInfo();
3663
3724
  if (!id.notices) {
3664
3725
  id.notices = {};
3665
3726
  }
3666
3727
  // Search for all notice DIDs sent to the current ID
3667
3728
  const where = {
3668
- "didDocumentData.notice.to[*]": {
3729
+ "notice.to[*]": {
3669
3730
  "$in": [id.did]
3670
3731
  }
3671
3732
  };
3672
3733
  let notices;
3673
3734
  try {
3674
3735
  // TBD search engine should not return expired notices
3675
- notices = await this.searchEngine.search({ where });
3736
+ notices = await this.gatekeeper.search({ where });
3676
3737
  }
3677
3738
  catch (error) {
3678
3739
  throw new KeymasterError('Failed to search for notices');