@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.
@@ -1,9 +1,18 @@
1
1
  import { imageSize } from 'image-size';
2
2
  import { fileTypeFromBuffer } from 'file-type';
3
+ import { base64url } from 'multiformats/bases/base64';
3
4
  import { InvalidDIDError, InvalidParameterError, KeymasterError, UnknownIDError } from '@didcid/common/errors';
4
5
  import { isWalletEncFile, isWalletFile } from './db/typeGuards.js';
5
6
  import { isValidDID } from '@didcid/ipfs/utils';
6
7
  import { decMnemonic, encMnemonic } from "./encryption.js";
8
+ function hexToBase64url(hex) {
9
+ const bytes = Buffer.from(hex, 'hex');
10
+ return base64url.baseEncode(bytes);
11
+ }
12
+ function base64urlToHex(b64) {
13
+ const bytes = base64url.baseDecode(b64);
14
+ return Buffer.from(bytes).toString('hex');
15
+ }
7
16
  const DefaultSchema = {
8
17
  "$schema": "http://json-schema.org/draft-07/schema#",
9
18
  "type": "object",
@@ -38,7 +47,6 @@ export default class Keymaster {
38
47
  gatekeeper;
39
48
  db;
40
49
  cipher;
41
- searchEngine;
42
50
  defaultRegistry;
43
51
  ephemeralRegistry;
44
52
  maxNameLength;
@@ -55,9 +63,6 @@ export default class Keymaster {
55
63
  if (!options.cipher || !options.cipher.verifySig) {
56
64
  throw new InvalidParameterError('options.cipher');
57
65
  }
58
- if (options.search && !options.search.search) {
59
- throw new InvalidParameterError('options.search');
60
- }
61
66
  if (!options.passphrase) {
62
67
  throw new InvalidParameterError('options.passphrase');
63
68
  }
@@ -65,7 +70,6 @@ export default class Keymaster {
65
70
  this.gatekeeper = options.gatekeeper;
66
71
  this.db = options.wallet;
67
72
  this.cipher = options.cipher;
68
- this.searchEngine = options.search;
69
73
  this.defaultRegistry = options.defaultRegistry || 'hyperswarm';
70
74
  this.ephemeralRegistry = 'hyperswarm';
71
75
  this.maxNameLength = options.maxNameLength || 32;
@@ -306,13 +310,15 @@ export default class Keymaster {
306
310
  publicJwk: keypair.publicJwk,
307
311
  };
308
312
  const msgHash = this.cipher.hashJSON(operation);
309
- const signature = this.cipher.signHash(msgHash, keypair.privateJwk);
313
+ const signatureHex = this.cipher.signHash(msgHash, keypair.privateJwk);
310
314
  const signed = {
311
315
  ...operation,
312
- signature: {
313
- signed: new Date(0).toISOString(),
314
- hash: msgHash,
315
- value: signature
316
+ proof: {
317
+ type: "EcdsaSecp256k1Signature2019",
318
+ created: new Date(0).toISOString(),
319
+ verificationMethod: "#key-1",
320
+ proofPurpose: "authentication",
321
+ proofValue: hexToBase64url(signatureHex),
316
322
  }
317
323
  };
318
324
  const did = await this.gatekeeper.createDID(signed);
@@ -333,14 +339,15 @@ export default class Keymaster {
333
339
  doc,
334
340
  };
335
341
  const msgHash = this.cipher.hashJSON(operation);
336
- const signature = this.cipher.signHash(msgHash, keypair.privateJwk);
342
+ const signatureHex = this.cipher.signHash(msgHash, keypair.privateJwk);
337
343
  const signed = {
338
344
  ...operation,
339
- signature: {
340
- signer: did,
341
- signed: new Date().toISOString(),
342
- hash: msgHash,
343
- value: signature,
345
+ proof: {
346
+ type: "EcdsaSecp256k1Signature2019",
347
+ created: new Date().toISOString(),
348
+ verificationMethod: `${did}#key-1`,
349
+ proofPurpose: "authentication",
350
+ proofValue: hexToBase64url(signatureHex),
344
351
  }
345
352
  };
346
353
  return await this.gatekeeper.updateDID(signed);
@@ -365,14 +372,15 @@ export default class Keymaster {
365
372
  data: { backup: backup },
366
373
  };
367
374
  const msgHash = this.cipher.hashJSON(operation);
368
- const signature = this.cipher.signHash(msgHash, keypair.privateJwk);
375
+ const signatureHex = this.cipher.signHash(msgHash, keypair.privateJwk);
369
376
  const signed = {
370
377
  ...operation,
371
- signature: {
372
- signer: seedBank.didDocument?.id,
373
- signed: new Date().toISOString(),
374
- hash: msgHash,
375
- value: signature,
378
+ proof: {
379
+ type: "EcdsaSecp256k1Signature2019",
380
+ created: new Date().toISOString(),
381
+ verificationMethod: `${seedBank.didDocument?.id}#key-1`,
382
+ proofPurpose: "authentication",
383
+ proofValue: hexToBase64url(signatureHex),
376
384
  }
377
385
  };
378
386
  const backupDID = await this.gatekeeper.createDID(signed);
@@ -553,7 +561,7 @@ export default class Keymaster {
553
561
  controller: id.did,
554
562
  data,
555
563
  };
556
- const signed = await this.addSignature(operation, controller);
564
+ const signed = await this.addProof(operation, controller, "authentication");
557
565
  const did = await this.gatekeeper.createDID(signed);
558
566
  // Keep assets that will be garbage-collected out of the owned list
559
567
  if (!validUntil) {
@@ -742,7 +750,7 @@ export default class Keymaster {
742
750
  throw new InvalidParameterError('did not encrypted JSON');
743
751
  }
744
752
  }
745
- async addSignature(obj, controller) {
753
+ async addProof(obj, controller, proofPurpose = "assertionMethod") {
746
754
  if (obj == null) {
747
755
  throw new InvalidParameterError('obj');
748
756
  }
@@ -750,18 +758,23 @@ export default class Keymaster {
750
758
  const id = await this.fetchIdInfo(controller);
751
759
  const keypair = await this.fetchKeyPair(controller);
752
760
  if (!keypair) {
753
- throw new KeymasterError('addSignature: no keypair');
761
+ throw new KeymasterError('addProof: no keypair');
754
762
  }
763
+ // Get the key fragment from the DID document
764
+ const doc = await this.resolveDID(id.did, { confirm: true });
765
+ const keyFragment = doc.didDocument?.verificationMethod?.[0]?.id || '#key-1';
755
766
  try {
756
767
  const msgHash = this.cipher.hashJSON(obj);
757
- const signature = this.cipher.signHash(msgHash, keypair.privateJwk);
768
+ const signatureHex = this.cipher.signHash(msgHash, keypair.privateJwk);
769
+ const proofValue = hexToBase64url(signatureHex);
758
770
  return {
759
771
  ...obj,
760
- signature: {
761
- signer: id.did,
762
- signed: new Date().toISOString(),
763
- hash: msgHash,
764
- value: signature,
772
+ proof: {
773
+ type: "EcdsaSecp256k1Signature2019",
774
+ created: new Date().toISOString(),
775
+ verificationMethod: `${id.did}${keyFragment}`,
776
+ proofPurpose,
777
+ proofValue,
765
778
  }
766
779
  };
767
780
  }
@@ -769,24 +782,27 @@ export default class Keymaster {
769
782
  throw new InvalidParameterError('obj');
770
783
  }
771
784
  }
772
- async verifySignature(obj) {
773
- if (!obj?.signature) {
785
+ async verifyProof(obj) {
786
+ if (!obj?.proof) {
774
787
  return false;
775
788
  }
776
- const { signature } = obj;
777
- if (!signature.signer) {
789
+ const { proof } = obj;
790
+ if (proof.type !== "EcdsaSecp256k1Signature2019") {
778
791
  return false;
779
792
  }
780
- const jsonCopy = JSON.parse(JSON.stringify(obj));
781
- delete jsonCopy.signature;
782
- const msgHash = this.cipher.hashJSON(jsonCopy);
783
- if (signature.hash && signature.hash !== msgHash) {
793
+ if (!proof.verificationMethod) {
784
794
  return false;
785
795
  }
786
- const doc = await this.resolveDID(signature.signer, { versionTime: signature.signed });
796
+ // Extract DID from verificationMethod
797
+ const [signerDid] = proof.verificationMethod.split('#');
798
+ const jsonCopy = JSON.parse(JSON.stringify(obj));
799
+ delete jsonCopy.proof;
800
+ const msgHash = this.cipher.hashJSON(jsonCopy);
801
+ const doc = await this.resolveDID(signerDid, { versionTime: proof.created });
787
802
  const publicJwk = this.getPublicKeyJwk(doc);
788
803
  try {
789
- return this.cipher.verifySig(msgHash, signature.value, publicJwk);
804
+ const signatureHex = base64urlToHex(proof.proofValue);
805
+ return this.cipher.verifySig(msgHash, signatureHex, publicJwk);
790
806
  }
791
807
  catch (error) {
792
808
  return false;
@@ -815,7 +831,7 @@ export default class Keymaster {
815
831
  else if (current.didDocumentRegistration?.type === 'asset') {
816
832
  controller = current.didDocument?.controller;
817
833
  }
818
- const signed = await this.addSignature(operation, controller);
834
+ const signed = await this.addProof(operation, controller, "authentication");
819
835
  return this.gatekeeper.updateDID(signed);
820
836
  }
821
837
  async revokeDID(id) {
@@ -837,7 +853,7 @@ export default class Keymaster {
837
853
  else if (current.didDocumentRegistration?.type === 'asset') {
838
854
  controller = current.didDocument?.controller;
839
855
  }
840
- const signed = await this.addSignature(operation, controller);
856
+ const signed = await this.addProof(operation, controller, "authentication");
841
857
  const ok = await this.gatekeeper.deleteDID(signed);
842
858
  if (ok && current.didDocument?.controller) {
843
859
  await this.removeFromOwned(did, current.didDocument.controller);
@@ -917,9 +933,13 @@ export default class Keymaster {
917
933
  }
918
934
  const controller = docs.didDocument?.controller || docs.didDocument?.id;
919
935
  const isOwned = await this.idInWallet(controller);
920
- // Augment the DID document metadata with the DID ownership status
936
+ // Convert versionSequence string to numeric version
937
+ const versionSequence = docs.didDocumentMetadata?.versionSequence;
938
+ const version = versionSequence ? parseInt(versionSequence, 10) : undefined;
939
+ // Augment the DID document metadata with the DID ownership status and numeric version
921
940
  docs.didDocumentMetadata = {
922
941
  ...docs.didDocumentMetadata,
942
+ version,
923
943
  isOwned,
924
944
  };
925
945
  return docs;
@@ -1038,13 +1058,15 @@ export default class Keymaster {
1038
1058
  publicJwk: keypair.publicJwk,
1039
1059
  };
1040
1060
  const msgHash = this.cipher.hashJSON(operation);
1041
- const signature = this.cipher.signHash(msgHash, keypair.privateJwk);
1061
+ const signatureHex = this.cipher.signHash(msgHash, keypair.privateJwk);
1042
1062
  const signed = {
1043
1063
  ...operation,
1044
- signature: {
1045
- signed: new Date().toISOString(),
1046
- hash: msgHash,
1047
- value: signature
1064
+ proof: {
1065
+ type: "EcdsaSecp256k1Signature2019",
1066
+ created: new Date().toISOString(),
1067
+ verificationMethod: "#key-1",
1068
+ proofPurpose: "authentication",
1069
+ proofValue: hexToBase64url(signatureHex),
1048
1070
  },
1049
1071
  };
1050
1072
  return signed;
@@ -1098,10 +1120,10 @@ export default class Keymaster {
1098
1120
  if (!registry) {
1099
1121
  throw new InvalidParameterError('no registry found for agent DID');
1100
1122
  }
1101
- const vaultDid = await this.createAsset({ backup: backup }, { registry, controller: name });
1123
+ const backupStoreDid = await this.createAsset({ backup: backup }, { registry, controller: name });
1102
1124
  if (doc.didDocumentData) {
1103
1125
  const currentData = doc.didDocumentData;
1104
- const updatedData = { ...currentData, vault: vaultDid };
1126
+ const updatedData = { ...currentData, backupStore: backupStoreDid };
1105
1127
  return this.updateDID(name, { didDocumentData: updatedData });
1106
1128
  }
1107
1129
  return false;
@@ -1111,14 +1133,14 @@ export default class Keymaster {
1111
1133
  const keypair = await this.hdKeyPair();
1112
1134
  const doc = await this.resolveDID(did);
1113
1135
  const docData = doc.didDocumentData;
1114
- if (!docData.vault) {
1115
- throw new InvalidDIDError('didDocumentData missing vault');
1136
+ if (!docData.backupStore) {
1137
+ throw new InvalidDIDError('didDocumentData missing backupStore');
1116
1138
  }
1117
- const vault = await this.resolveAsset(docData.vault);
1118
- if (typeof vault.backup !== 'string') {
1119
- throw new InvalidDIDError('backup not found in vault');
1139
+ const backupStore = await this.resolveAsset(docData.backupStore);
1140
+ if (typeof backupStore.backup !== 'string') {
1141
+ throw new InvalidDIDError('backup not found in backupStore');
1120
1142
  }
1121
- const backup = this.cipher.decryptMessage(keypair.publicJwk, keypair.privateJwk, vault.backup);
1143
+ const backup = this.cipher.decryptMessage(keypair.publicJwk, keypair.privateJwk, backupStore.backup);
1122
1144
  const data = JSON.parse(backup);
1123
1145
  await this.mutateWallet((wallet) => {
1124
1146
  if (wallet.ids[data.name]) {
@@ -1162,6 +1184,7 @@ export default class Keymaster {
1162
1184
  ...doc.didDocument,
1163
1185
  verificationMethod: [vmethod],
1164
1186
  authentication: [vmethod.id],
1187
+ assertionMethod: [vmethod.id],
1165
1188
  };
1166
1189
  ok = await this.updateDID(id.did, { didDocument: updatedDidDocument });
1167
1190
  if (!ok) {
@@ -1174,7 +1197,7 @@ export default class Keymaster {
1174
1197
  async listNames(options = {}) {
1175
1198
  const { includeIDs = false } = options;
1176
1199
  const wallet = await this.loadWallet();
1177
- const names = wallet.names || {};
1200
+ const names = { ...(wallet.names || {}) };
1178
1201
  if (includeIDs) {
1179
1202
  for (const [name, id] of Object.entries(wallet.ids || {})) {
1180
1203
  names[name] = id.did;
@@ -1212,42 +1235,60 @@ export default class Keymaster {
1212
1235
  const doc = await this.resolveDID(id);
1213
1236
  return doc.didDocumentRegistration?.type === 'agent';
1214
1237
  }
1215
- async bindCredential(schemaId, subjectId, options = {}) {
1216
- let { validFrom, validUntil, credential } = options;
1238
+ async bindCredential(subjectId, options = {}) {
1239
+ let { schema, validFrom, validUntil, claims, types } = options;
1217
1240
  if (!validFrom) {
1218
1241
  validFrom = new Date().toISOString();
1219
1242
  }
1220
1243
  const id = await this.fetchIdInfo();
1221
- const type = await this.lookupDID(schemaId);
1222
1244
  const subjectDID = await this.lookupDID(subjectId);
1223
- if (!credential) {
1224
- const schema = await this.getSchema(type);
1225
- credential = this.generateSchema(schema);
1226
- }
1227
- return {
1245
+ const vc = {
1228
1246
  "@context": [
1229
1247
  "https://www.w3.org/ns/credentials/v2",
1230
1248
  "https://www.w3.org/ns/credentials/examples/v2"
1231
1249
  ],
1232
- type: ["VerifiableCredential", type],
1250
+ type: ["VerifiableCredential", ...(types || [])],
1233
1251
  issuer: id.did,
1234
1252
  validFrom,
1235
1253
  validUntil,
1236
1254
  credentialSubject: {
1237
1255
  id: subjectDID,
1238
1256
  },
1239
- credential,
1240
1257
  };
1258
+ // If schema provided, add credentialSchema and generate claims from schema
1259
+ if (schema) {
1260
+ const schemaDID = await this.lookupDID(schema);
1261
+ const schemaDoc = await this.getSchema(schemaDID);
1262
+ if (!claims && schemaDoc) {
1263
+ claims = this.generateSchema(schemaDoc);
1264
+ }
1265
+ // If schema has $credentialTypes, add them to credential types (avoiding duplicates)
1266
+ if (schemaDoc?.$credentialTypes) {
1267
+ const newTypes = schemaDoc.$credentialTypes.filter(t => !vc.type.includes(t));
1268
+ vc.type.push(...newTypes);
1269
+ }
1270
+ vc.credentialSchema = {
1271
+ id: schemaDID,
1272
+ type: "JsonSchema",
1273
+ };
1274
+ }
1275
+ if (claims) {
1276
+ vc.credentialSubject = {
1277
+ id: subjectDID,
1278
+ ...claims,
1279
+ };
1280
+ }
1281
+ return vc;
1241
1282
  }
1242
1283
  async issueCredential(credential, options = {}) {
1243
1284
  const id = await this.fetchIdInfo();
1244
1285
  if (options.schema && options.subject) {
1245
- credential = await this.bindCredential(options.schema, options.subject, { credential, ...options });
1286
+ credential = await this.bindCredential(options.subject, { schema: options.schema, claims: options.claims, ...options });
1246
1287
  }
1247
1288
  if (credential.issuer !== id.did) {
1248
1289
  throw new InvalidParameterError('credential.issuer');
1249
1290
  }
1250
- const signed = await this.addSignature(credential);
1291
+ const signed = await this.addProof(credential);
1251
1292
  return this.encryptJSON(signed, credential.credentialSubject.id, { ...options, includeHash: true });
1252
1293
  }
1253
1294
  async sendCredential(did, options = {}) {
@@ -1277,13 +1318,12 @@ export default class Keymaster {
1277
1318
  throw new InvalidParameterError("did is not a credential");
1278
1319
  }
1279
1320
  if (!credential ||
1280
- !credential.credential ||
1281
1321
  !credential.credentialSubject ||
1282
1322
  !credential.credentialSubject.id) {
1283
1323
  throw new InvalidParameterError('credential');
1284
1324
  }
1285
- delete credential.signature;
1286
- const signed = await this.addSignature(credential);
1325
+ delete credential.proof;
1326
+ const signed = await this.addProof(credential);
1287
1327
  const msg = JSON.stringify(signed);
1288
1328
  const id = await this.fetchIdInfo();
1289
1329
  const senderKeypair = await this.fetchKeyPair();
@@ -1377,8 +1417,8 @@ export default class Keymaster {
1377
1417
  data.manifest = {};
1378
1418
  }
1379
1419
  if (!reveal) {
1380
- // Remove the credential values
1381
- vc.credential = null;
1420
+ // Remove the claim values, keep only the subject id
1421
+ vc.credentialSubject = { id: vc.credentialSubject.id };
1382
1422
  }
1383
1423
  data.manifest[credential] = vc;
1384
1424
  const ok = await this.updateDID(id.did, { didDocumentData: doc.didDocumentData });
@@ -1436,8 +1476,8 @@ export default class Keymaster {
1436
1476
  // Attestor not trusted by Verifier
1437
1477
  continue;
1438
1478
  }
1439
- if (doc.type && !doc.type.includes(credential.schema)) {
1440
- // Wrong type
1479
+ if (doc.credentialSchema?.id !== credential.schema) {
1480
+ // Wrong schema
1441
1481
  continue;
1442
1482
  }
1443
1483
  // TBD test for VC expiry too
@@ -1562,7 +1602,7 @@ export default class Keymaster {
1562
1602
  continue;
1563
1603
  }
1564
1604
  const vp = await this.decryptJSON(credential.vp);
1565
- const isValid = await this.verifySignature(vp);
1605
+ const isValid = await this.verifyProof(vp);
1566
1606
  if (!isValid) {
1567
1607
  continue;
1568
1608
  }
@@ -1570,8 +1610,8 @@ export default class Keymaster {
1570
1610
  continue;
1571
1611
  }
1572
1612
  // Check VP against VCs specified in challenge
1573
- if (vp.type.length >= 2 && vp.type[1].startsWith('did:')) {
1574
- const schema = vp.type[1];
1613
+ if (vp.credentialSchema?.id) {
1614
+ const schema = vp.credentialSchema.id;
1575
1615
  const credential = challenge.credentials?.find(item => item.schema === schema);
1576
1616
  if (!credential) {
1577
1617
  continue;
@@ -2069,7 +2109,7 @@ export default class Keymaster {
2069
2109
  delete poll.results;
2070
2110
  return this.updateAsset(pollId, { poll });
2071
2111
  }
2072
- async createGroupVault(options = {}) {
2112
+ async createVault(options = {}) {
2073
2113
  const id = await this.fetchIdInfo();
2074
2114
  const idKeypair = await this.fetchKeyPair();
2075
2115
  // version defaults to 1. To make version undefined (unit testing), set options.version to 0
@@ -2084,7 +2124,7 @@ export default class Keymaster {
2084
2124
  const members = this.cipher.encryptMessage(publicJwk, vaultKeypair.privateJwk, JSON.stringify({}));
2085
2125
  const items = this.cipher.encryptMessage(vaultKeypair.publicJwk, vaultKeypair.privateJwk, JSON.stringify({}));
2086
2126
  const sha256 = this.cipher.hashJSON({});
2087
- const groupVault = {
2127
+ const vault = {
2088
2128
  version,
2089
2129
  publicJwk: vaultKeypair.publicJwk,
2090
2130
  salt,
@@ -2094,46 +2134,46 @@ export default class Keymaster {
2094
2134
  items,
2095
2135
  sha256,
2096
2136
  };
2097
- await this.addMemberKey(groupVault, id.did, vaultKeypair.privateJwk);
2098
- return this.createAsset({ groupVault }, options);
2137
+ await this.addMemberKey(vault, id.did, vaultKeypair.privateJwk);
2138
+ return this.createAsset({ vault }, options);
2099
2139
  }
2100
- async getGroupVault(groupVaultId, options) {
2101
- const asset = await this.resolveAsset(groupVaultId, options);
2102
- if (!asset.groupVault) {
2103
- throw new InvalidParameterError('groupVaultId');
2140
+ async getVault(vaultId, options) {
2141
+ const asset = await this.resolveAsset(vaultId, options);
2142
+ if (!asset.vault) {
2143
+ throw new InvalidParameterError('vaultId');
2104
2144
  }
2105
- return asset.groupVault;
2145
+ return asset.vault;
2106
2146
  }
2107
- async testGroupVault(id, options) {
2147
+ async testVault(id, options) {
2108
2148
  try {
2109
- const groupVault = await this.getGroupVault(id, options);
2110
- return groupVault !== null;
2149
+ const vault = await this.getVault(id, options);
2150
+ return vault !== null;
2111
2151
  }
2112
2152
  catch (error) {
2113
2153
  return false;
2114
2154
  }
2115
2155
  }
2116
- generateSaltedId(groupVault, memberDID) {
2117
- if (!groupVault.version) {
2118
- return this.cipher.hashMessage(groupVault.salt + memberDID);
2156
+ generateSaltedId(vault, memberDID) {
2157
+ if (!vault.version) {
2158
+ return this.cipher.hashMessage(vault.salt + memberDID);
2119
2159
  }
2120
2160
  const suffix = memberDID.split(':').pop();
2121
- return this.cipher.hashMessage(groupVault.salt + suffix);
2161
+ return this.cipher.hashMessage(vault.salt + suffix);
2122
2162
  }
2123
- async decryptGroupVault(groupVault) {
2163
+ async decryptVault(vault) {
2124
2164
  const wallet = await this.loadWallet();
2125
2165
  const id = await this.fetchIdInfo();
2126
- const myMemberId = this.generateSaltedId(groupVault, id.did);
2127
- const myVaultKey = groupVault.keys[myMemberId];
2166
+ const myMemberId = this.generateSaltedId(vault, id.did);
2167
+ const myVaultKey = vault.keys[myMemberId];
2128
2168
  if (!myVaultKey) {
2129
- throw new KeymasterError('No access to group vault');
2169
+ throw new KeymasterError('No access to vault');
2130
2170
  }
2131
- const privKeyJSON = await this.decryptWithDerivedKeys(wallet, id, groupVault.publicJwk, myVaultKey);
2171
+ const privKeyJSON = await this.decryptWithDerivedKeys(wallet, id, vault.publicJwk, myVaultKey);
2132
2172
  const privateJwk = JSON.parse(privKeyJSON);
2133
2173
  let config = {};
2134
2174
  let isOwner = false;
2135
2175
  try {
2136
- const configJSON = await this.decryptWithDerivedKeys(wallet, id, groupVault.publicJwk, groupVault.config);
2176
+ const configJSON = await this.decryptWithDerivedKeys(wallet, id, vault.publicJwk, vault.config);
2137
2177
  config = JSON.parse(configJSON);
2138
2178
  isOwner = true;
2139
2179
  }
@@ -2143,7 +2183,7 @@ export default class Keymaster {
2143
2183
  let members = {};
2144
2184
  if (config.secretMembers) {
2145
2185
  try {
2146
- const membersJSON = await this.decryptWithDerivedKeys(wallet, id, groupVault.publicJwk, groupVault.members);
2186
+ const membersJSON = await this.decryptWithDerivedKeys(wallet, id, vault.publicJwk, vault.members);
2147
2187
  members = JSON.parse(membersJSON);
2148
2188
  }
2149
2189
  catch (error) {
@@ -2151,13 +2191,13 @@ export default class Keymaster {
2151
2191
  }
2152
2192
  else {
2153
2193
  try {
2154
- const membersJSON = this.cipher.decryptMessage(groupVault.publicJwk, privateJwk, groupVault.members);
2194
+ const membersJSON = this.cipher.decryptMessage(vault.publicJwk, privateJwk, vault.members);
2155
2195
  members = JSON.parse(membersJSON);
2156
2196
  }
2157
2197
  catch (error) {
2158
2198
  }
2159
2199
  }
2160
- const itemsJSON = this.cipher.decryptMessage(groupVault.publicJwk, privateJwk, groupVault.items);
2200
+ const itemsJSON = this.cipher.decryptMessage(vault.publicJwk, privateJwk, vault.items);
2161
2201
  const items = JSON.parse(itemsJSON);
2162
2202
  return {
2163
2203
  isOwner,
@@ -2167,7 +2207,7 @@ export default class Keymaster {
2167
2207
  items,
2168
2208
  };
2169
2209
  }
2170
- async checkGroupVaultOwner(vaultId) {
2210
+ async checkVaultOwner(vaultId) {
2171
2211
  const id = await this.fetchIdInfo();
2172
2212
  const vaultDoc = await this.resolveDID(vaultId);
2173
2213
  const controller = vaultDoc.didDocument?.controller;
@@ -2176,30 +2216,30 @@ export default class Keymaster {
2176
2216
  }
2177
2217
  return controller;
2178
2218
  }
2179
- async addMemberKey(groupVault, memberDID, privateJwk) {
2219
+ async addMemberKey(vault, memberDID, privateJwk) {
2180
2220
  const memberDoc = await this.resolveDID(memberDID, { confirm: true });
2181
2221
  const memberPublicJwk = this.getPublicKeyJwk(memberDoc);
2182
2222
  const memberKey = this.cipher.encryptMessage(memberPublicJwk, privateJwk, JSON.stringify(privateJwk));
2183
- const memberKeyId = this.generateSaltedId(groupVault, memberDID);
2184
- groupVault.keys[memberKeyId] = memberKey;
2223
+ const memberKeyId = this.generateSaltedId(vault, memberDID);
2224
+ vault.keys[memberKeyId] = memberKey;
2185
2225
  }
2186
- async checkVaultVersion(vaultId, groupVault) {
2187
- if (groupVault.version === 1) {
2226
+ async checkVaultVersion(vaultId, vault) {
2227
+ if (vault.version === 1) {
2188
2228
  return;
2189
2229
  }
2190
- if (!groupVault.version) {
2230
+ if (!vault.version) {
2191
2231
  const id = await this.fetchIdInfo();
2192
- const { privateJwk, members } = await this.decryptGroupVault(groupVault);
2193
- groupVault.version = 1;
2194
- groupVault.keys = {};
2195
- await this.addMemberKey(groupVault, id.did, privateJwk);
2232
+ const { privateJwk, members } = await this.decryptVault(vault);
2233
+ vault.version = 1;
2234
+ vault.keys = {};
2235
+ await this.addMemberKey(vault, id.did, privateJwk);
2196
2236
  for (const memberDID of Object.keys(members)) {
2197
- await this.addMemberKey(groupVault, memberDID, privateJwk);
2237
+ await this.addMemberKey(vault, memberDID, privateJwk);
2198
2238
  }
2199
- await this.updateAsset(vaultId, { groupVault });
2239
+ await this.updateAsset(vaultId, { vault });
2200
2240
  return;
2201
2241
  }
2202
- throw new KeymasterError('Unsupported group vault version');
2242
+ throw new KeymasterError('Unsupported vault version');
2203
2243
  }
2204
2244
  getAgentDID(doc) {
2205
2245
  if (doc.didDocumentRegistration?.type !== 'agent') {
@@ -2211,11 +2251,11 @@ export default class Keymaster {
2211
2251
  }
2212
2252
  return did;
2213
2253
  }
2214
- async addGroupVaultMember(vaultId, memberId) {
2215
- const owner = await this.checkGroupVaultOwner(vaultId);
2254
+ async addVaultMember(vaultId, memberId) {
2255
+ const owner = await this.checkVaultOwner(vaultId);
2216
2256
  const idKeypair = await this.fetchKeyPair();
2217
- const groupVault = await this.getGroupVault(vaultId);
2218
- const { privateJwk, config, members } = await this.decryptGroupVault(groupVault);
2257
+ const vault = await this.getVault(vaultId);
2258
+ const { privateJwk, config, members } = await this.decryptVault(vault);
2219
2259
  const memberDoc = await this.resolveDID(memberId, { confirm: true });
2220
2260
  const memberDID = this.getAgentDID(memberDoc);
2221
2261
  // Don't allow adding the vault owner
@@ -2223,16 +2263,16 @@ export default class Keymaster {
2223
2263
  return false;
2224
2264
  }
2225
2265
  members[memberDID] = { added: new Date().toISOString() };
2226
- const publicJwk = config.secretMembers ? idKeypair.publicJwk : groupVault.publicJwk;
2227
- groupVault.members = this.cipher.encryptMessage(publicJwk, privateJwk, JSON.stringify(members));
2228
- await this.addMemberKey(groupVault, memberDID, privateJwk);
2229
- return this.updateAsset(vaultId, { groupVault });
2266
+ const publicJwk = config.secretMembers ? idKeypair.publicJwk : vault.publicJwk;
2267
+ vault.members = this.cipher.encryptMessage(publicJwk, privateJwk, JSON.stringify(members));
2268
+ await this.addMemberKey(vault, memberDID, privateJwk);
2269
+ return this.updateAsset(vaultId, { vault });
2230
2270
  }
2231
- async removeGroupVaultMember(vaultId, memberId) {
2232
- const owner = await this.checkGroupVaultOwner(vaultId);
2271
+ async removeVaultMember(vaultId, memberId) {
2272
+ const owner = await this.checkVaultOwner(vaultId);
2233
2273
  const idKeypair = await this.fetchKeyPair();
2234
- const groupVault = await this.getGroupVault(vaultId);
2235
- const { privateJwk, config, members } = await this.decryptGroupVault(groupVault);
2274
+ const vault = await this.getVault(vaultId);
2275
+ const { privateJwk, config, members } = await this.decryptVault(vault);
2236
2276
  const memberDoc = await this.resolveDID(memberId, { confirm: true });
2237
2277
  const memberDID = this.getAgentDID(memberDoc);
2238
2278
  // Don't allow removing the vault owner
@@ -2240,26 +2280,26 @@ export default class Keymaster {
2240
2280
  return false;
2241
2281
  }
2242
2282
  delete members[memberDID];
2243
- const publicJwk = config.secretMembers ? idKeypair.publicJwk : groupVault.publicJwk;
2244
- groupVault.members = this.cipher.encryptMessage(publicJwk, privateJwk, JSON.stringify(members));
2245
- const memberKeyId = this.generateSaltedId(groupVault, memberDID);
2246
- delete groupVault.keys[memberKeyId];
2247
- return this.updateAsset(vaultId, { groupVault });
2248
- }
2249
- async listGroupVaultMembers(vaultId) {
2250
- const groupVault = await this.getGroupVault(vaultId);
2251
- const { members, isOwner } = await this.decryptGroupVault(groupVault);
2283
+ const publicJwk = config.secretMembers ? idKeypair.publicJwk : vault.publicJwk;
2284
+ vault.members = this.cipher.encryptMessage(publicJwk, privateJwk, JSON.stringify(members));
2285
+ const memberKeyId = this.generateSaltedId(vault, memberDID);
2286
+ delete vault.keys[memberKeyId];
2287
+ return this.updateAsset(vaultId, { vault });
2288
+ }
2289
+ async listVaultMembers(vaultId) {
2290
+ const vault = await this.getVault(vaultId);
2291
+ const { members, isOwner } = await this.decryptVault(vault);
2252
2292
  if (isOwner) {
2253
- await this.checkVaultVersion(vaultId, groupVault);
2293
+ await this.checkVaultVersion(vaultId, vault);
2254
2294
  }
2255
2295
  return members;
2256
2296
  }
2257
- async addGroupVaultItem(vaultId, name, buffer) {
2258
- await this.checkGroupVaultOwner(vaultId);
2259
- const groupVault = await this.getGroupVault(vaultId);
2260
- const { privateJwk, items } = await this.decryptGroupVault(groupVault);
2297
+ async addVaultItem(vaultId, name, buffer) {
2298
+ await this.checkVaultOwner(vaultId);
2299
+ const vault = await this.getVault(vaultId);
2300
+ const { privateJwk, items } = await this.decryptVault(vault);
2261
2301
  const validName = this.validateName(name);
2262
- const encryptedData = this.cipher.encryptBytes(groupVault.publicJwk, privateJwk, buffer);
2302
+ const encryptedData = this.cipher.encryptBytes(vault.publicJwk, privateJwk, buffer);
2263
2303
  const cid = await this.gatekeeper.addText(encryptedData);
2264
2304
  const sha256 = this.cipher.hashMessage(buffer);
2265
2305
  const type = await this.getMimeType(buffer);
@@ -2272,32 +2312,32 @@ export default class Keymaster {
2272
2312
  added: new Date().toISOString(),
2273
2313
  data,
2274
2314
  };
2275
- groupVault.items = this.cipher.encryptMessage(groupVault.publicJwk, privateJwk, JSON.stringify(items));
2276
- groupVault.sha256 = this.cipher.hashJSON(items);
2277
- return this.updateAsset(vaultId, { groupVault });
2278
- }
2279
- async removeGroupVaultItem(vaultId, name) {
2280
- await this.checkGroupVaultOwner(vaultId);
2281
- const groupVault = await this.getGroupVault(vaultId);
2282
- const { privateJwk, items } = await this.decryptGroupVault(groupVault);
2315
+ vault.items = this.cipher.encryptMessage(vault.publicJwk, privateJwk, JSON.stringify(items));
2316
+ vault.sha256 = this.cipher.hashJSON(items);
2317
+ return this.updateAsset(vaultId, { vault });
2318
+ }
2319
+ async removeVaultItem(vaultId, name) {
2320
+ await this.checkVaultOwner(vaultId);
2321
+ const vault = await this.getVault(vaultId);
2322
+ const { privateJwk, items } = await this.decryptVault(vault);
2283
2323
  delete items[name];
2284
- groupVault.items = this.cipher.encryptMessage(groupVault.publicJwk, privateJwk, JSON.stringify(items));
2285
- groupVault.sha256 = this.cipher.hashJSON(items);
2286
- return this.updateAsset(vaultId, { groupVault });
2324
+ vault.items = this.cipher.encryptMessage(vault.publicJwk, privateJwk, JSON.stringify(items));
2325
+ vault.sha256 = this.cipher.hashJSON(items);
2326
+ return this.updateAsset(vaultId, { vault });
2287
2327
  }
2288
- async listGroupVaultItems(vaultId, options) {
2289
- const groupVault = await this.getGroupVault(vaultId, options);
2290
- const { items } = await this.decryptGroupVault(groupVault);
2328
+ async listVaultItems(vaultId, options) {
2329
+ const vault = await this.getVault(vaultId, options);
2330
+ const { items } = await this.decryptVault(vault);
2291
2331
  return items;
2292
2332
  }
2293
- async getGroupVaultItem(vaultId, name, options) {
2333
+ async getVaultItem(vaultId, name, options) {
2294
2334
  try {
2295
- const groupVault = await this.getGroupVault(vaultId, options);
2296
- const { privateJwk, items } = await this.decryptGroupVault(groupVault);
2335
+ const vault = await this.getVault(vaultId, options);
2336
+ const { privateJwk, items } = await this.decryptVault(vault);
2297
2337
  if (items[name]) {
2298
2338
  const encryptedData = items[name].data || await this.gatekeeper.getText(items[name].cid);
2299
2339
  if (encryptedData) {
2300
- const bytes = this.cipher.decryptBytes(groupVault.publicJwk, privateJwk, encryptedData);
2340
+ const bytes = this.cipher.decryptBytes(vault.publicJwk, privateJwk, encryptedData);
2301
2341
  return Buffer.from(bytes);
2302
2342
  }
2303
2343
  }
@@ -2426,28 +2466,28 @@ export default class Keymaster {
2426
2466
  }
2427
2467
  async createDmail(message, options = {}) {
2428
2468
  const dmail = await this.verifyDmail(message);
2429
- const did = await this.createGroupVault(options);
2469
+ const did = await this.createVault(options);
2430
2470
  for (const toDID of dmail.to) {
2431
- await this.addGroupVaultMember(did, toDID);
2471
+ await this.addVaultMember(did, toDID);
2432
2472
  }
2433
2473
  for (const ccDID of dmail.cc) {
2434
- await this.addGroupVaultMember(did, ccDID);
2474
+ await this.addVaultMember(did, ccDID);
2435
2475
  }
2436
2476
  const buffer = Buffer.from(JSON.stringify({ dmail }), 'utf-8');
2437
- await this.addGroupVaultItem(did, DmailTags.DMAIL, buffer);
2477
+ await this.addVaultItem(did, DmailTags.DMAIL, buffer);
2438
2478
  await this.fileDmail(did, [DmailTags.DRAFT]);
2439
2479
  return did;
2440
2480
  }
2441
2481
  async updateDmail(did, message) {
2442
2482
  const dmail = await this.verifyDmail(message);
2443
2483
  for (const toDID of dmail.to) {
2444
- await this.addGroupVaultMember(did, toDID);
2484
+ await this.addVaultMember(did, toDID);
2445
2485
  }
2446
2486
  for (const ccDID of dmail.cc) {
2447
- await this.addGroupVaultMember(did, ccDID);
2487
+ await this.addVaultMember(did, ccDID);
2448
2488
  }
2449
2489
  const buffer = Buffer.from(JSON.stringify({ dmail }), 'utf-8');
2450
- return this.addGroupVaultItem(did, DmailTags.DMAIL, buffer);
2490
+ return this.addVaultItem(did, DmailTags.DMAIL, buffer);
2451
2491
  }
2452
2492
  async sendDmail(did) {
2453
2493
  const dmail = await this.getDmailMessage(did);
@@ -2467,11 +2507,11 @@ export default class Keymaster {
2467
2507
  return notice;
2468
2508
  }
2469
2509
  async getDmailMessage(did, options) {
2470
- const isGroupVault = await this.testGroupVault(did, options);
2471
- if (!isGroupVault) {
2510
+ const isVault = await this.testVault(did, options);
2511
+ if (!isVault) {
2472
2512
  return null;
2473
2513
  }
2474
- const buffer = await this.getGroupVaultItem(did, DmailTags.DMAIL, options);
2514
+ const buffer = await this.getVaultItem(did, DmailTags.DMAIL, options);
2475
2515
  if (!buffer) {
2476
2516
  return null;
2477
2517
  }
@@ -2484,7 +2524,7 @@ export default class Keymaster {
2484
2524
  }
2485
2525
  }
2486
2526
  async listDmailAttachments(did, options) {
2487
- let items = await this.listGroupVaultItems(did, options);
2527
+ let items = await this.listVaultItems(did, options);
2488
2528
  delete items[DmailTags.DMAIL]; // Remove the dmail item itself from attachments
2489
2529
  return items;
2490
2530
  }
@@ -2492,16 +2532,16 @@ export default class Keymaster {
2492
2532
  if (name === DmailTags.DMAIL) {
2493
2533
  throw new InvalidParameterError('Cannot add attachment with reserved name "dmail"');
2494
2534
  }
2495
- return this.addGroupVaultItem(did, name, buffer);
2535
+ return this.addVaultItem(did, name, buffer);
2496
2536
  }
2497
2537
  async removeDmailAttachment(did, name) {
2498
2538
  if (name === DmailTags.DMAIL) {
2499
2539
  throw new InvalidParameterError('Cannot remove attachment with reserved name "dmail"');
2500
2540
  }
2501
- return this.removeGroupVaultItem(did, name);
2541
+ return this.removeVaultItem(did, name);
2502
2542
  }
2503
2543
  async getDmailAttachment(did, name) {
2504
- return this.getGroupVaultItem(did, name);
2544
+ return this.getVaultItem(did, name);
2505
2545
  }
2506
2546
  async importDmail(did) {
2507
2547
  const dmail = await this.getDmailMessage(did);
@@ -2603,23 +2643,20 @@ export default class Keymaster {
2603
2643
  return true;
2604
2644
  }
2605
2645
  async searchNotices() {
2606
- if (!this.searchEngine) {
2607
- return false; // Search engine not available
2608
- }
2609
2646
  const id = await this.fetchIdInfo();
2610
2647
  if (!id.notices) {
2611
2648
  id.notices = {};
2612
2649
  }
2613
2650
  // Search for all notice DIDs sent to the current ID
2614
2651
  const where = {
2615
- "didDocumentData.notice.to[*]": {
2652
+ "notice.to[*]": {
2616
2653
  "$in": [id.did]
2617
2654
  }
2618
2655
  };
2619
2656
  let notices;
2620
2657
  try {
2621
2658
  // TBD search engine should not return expired notices
2622
- notices = await this.searchEngine.search({ where });
2659
+ notices = await this.gatekeeper.search({ where });
2623
2660
  }
2624
2661
  catch (error) {
2625
2662
  throw new KeymasterError('Failed to search for notices');