@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.
- package/dist/cjs/index.cjs +0 -2
- package/dist/cjs/keymaster-client.cjs +26 -26
- package/dist/cjs/keymaster.cjs +279 -218
- package/dist/cjs/node.cjs +0 -2
- package/dist/esm/index.js +0 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/keymaster-client.js +26 -26
- package/dist/esm/keymaster-client.js.map +1 -1
- package/dist/esm/keymaster.js +220 -183
- package/dist/esm/keymaster.js.map +1 -1
- package/dist/types/index.d.ts +0 -1
- package/dist/types/keymaster-client.d.ts +16 -14
- package/dist/types/keymaster.d.ts +22 -21
- package/dist/types/types.d.ts +26 -31
- package/package.json +2 -10
- package/dist/cjs/search-client.cjs +0 -87
- package/dist/esm/search-client.js +0 -81
- package/dist/esm/search-client.js.map +0 -1
- package/dist/types/search-client.d.ts +0 -9
package/dist/cjs/keymaster.cjs
CHANGED
|
@@ -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
|
|
1390
|
+
const signatureHex = this.cipher.signHash(msgHash, keypair.privateJwk);
|
|
1363
1391
|
const signed = {
|
|
1364
1392
|
...operation,
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
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
|
|
1419
|
+
const signatureHex = this.cipher.signHash(msgHash, keypair.privateJwk);
|
|
1390
1420
|
const signed = {
|
|
1391
1421
|
...operation,
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
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
|
|
1452
|
+
const signatureHex = this.cipher.signHash(msgHash, keypair.privateJwk);
|
|
1422
1453
|
const signed = {
|
|
1423
1454
|
...operation,
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
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.
|
|
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
|
|
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('
|
|
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
|
|
1845
|
+
const signatureHex = this.cipher.signHash(msgHash, keypair.privateJwk);
|
|
1846
|
+
const proofValue = hexToBase64url(signatureHex);
|
|
1811
1847
|
return {
|
|
1812
1848
|
...obj,
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
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
|
|
1826
|
-
if (!obj?.
|
|
1862
|
+
async verifyProof(obj) {
|
|
1863
|
+
if (!obj?.proof) {
|
|
1827
1864
|
return false;
|
|
1828
1865
|
}
|
|
1829
|
-
const {
|
|
1830
|
-
if (
|
|
1866
|
+
const { proof } = obj;
|
|
1867
|
+
if (proof.type !== "EcdsaSecp256k1Signature2019") {
|
|
1831
1868
|
return false;
|
|
1832
1869
|
}
|
|
1833
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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
|
-
//
|
|
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
|
|
2138
|
+
const signatureHex = this.cipher.signHash(msgHash, keypair.privateJwk);
|
|
2095
2139
|
const signed = {
|
|
2096
2140
|
...operation,
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
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
|
|
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,
|
|
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.
|
|
2168
|
-
throw new InvalidDIDError('didDocumentData missing
|
|
2213
|
+
if (!docData.backupStore) {
|
|
2214
|
+
throw new InvalidDIDError('didDocumentData missing backupStore');
|
|
2169
2215
|
}
|
|
2170
|
-
const
|
|
2171
|
-
if (typeof
|
|
2172
|
-
throw new InvalidDIDError('backup not found in
|
|
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,
|
|
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(
|
|
2269
|
-
let { validFrom, validUntil,
|
|
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
|
-
|
|
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",
|
|
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.
|
|
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.
|
|
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.
|
|
2339
|
-
const signed = await this.
|
|
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
|
|
2434
|
-
vc.
|
|
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.
|
|
2493
|
-
// Wrong
|
|
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.
|
|
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.
|
|
2627
|
-
const schema = vp.
|
|
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
|
|
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
|
|
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(
|
|
3151
|
-
return this.createAsset({
|
|
3214
|
+
await this.addMemberKey(vault, id.did, vaultKeypair.privateJwk);
|
|
3215
|
+
return this.createAsset({ vault }, options);
|
|
3152
3216
|
}
|
|
3153
|
-
async
|
|
3154
|
-
const asset = await this.resolveAsset(
|
|
3155
|
-
if (!asset.
|
|
3156
|
-
throw new InvalidParameterError('
|
|
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.
|
|
3222
|
+
return asset.vault;
|
|
3159
3223
|
}
|
|
3160
|
-
async
|
|
3224
|
+
async testVault(id, options) {
|
|
3161
3225
|
try {
|
|
3162
|
-
const
|
|
3163
|
-
return
|
|
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(
|
|
3170
|
-
if (!
|
|
3171
|
-
return this.cipher.hashMessage(
|
|
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(
|
|
3238
|
+
return this.cipher.hashMessage(vault.salt + suffix);
|
|
3175
3239
|
}
|
|
3176
|
-
async
|
|
3240
|
+
async decryptVault(vault) {
|
|
3177
3241
|
const wallet = await this.loadWallet();
|
|
3178
3242
|
const id = await this.fetchIdInfo();
|
|
3179
|
-
const myMemberId = this.generateSaltedId(
|
|
3180
|
-
const myVaultKey =
|
|
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
|
|
3246
|
+
throw new KeymasterError('No access to vault');
|
|
3183
3247
|
}
|
|
3184
|
-
const privKeyJSON = await this.decryptWithDerivedKeys(wallet, id,
|
|
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,
|
|
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,
|
|
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(
|
|
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(
|
|
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
|
|
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(
|
|
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(
|
|
3237
|
-
|
|
3300
|
+
const memberKeyId = this.generateSaltedId(vault, memberDID);
|
|
3301
|
+
vault.keys[memberKeyId] = memberKey;
|
|
3238
3302
|
}
|
|
3239
|
-
async checkVaultVersion(vaultId,
|
|
3240
|
-
if (
|
|
3303
|
+
async checkVaultVersion(vaultId, vault) {
|
|
3304
|
+
if (vault.version === 1) {
|
|
3241
3305
|
return;
|
|
3242
3306
|
}
|
|
3243
|
-
if (!
|
|
3307
|
+
if (!vault.version) {
|
|
3244
3308
|
const id = await this.fetchIdInfo();
|
|
3245
|
-
const { privateJwk, members } = await this.
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
await this.addMemberKey(
|
|
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(
|
|
3314
|
+
await this.addMemberKey(vault, memberDID, privateJwk);
|
|
3251
3315
|
}
|
|
3252
|
-
await this.updateAsset(vaultId, {
|
|
3316
|
+
await this.updateAsset(vaultId, { vault });
|
|
3253
3317
|
return;
|
|
3254
3318
|
}
|
|
3255
|
-
throw new KeymasterError('Unsupported
|
|
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
|
|
3268
|
-
const owner = await this.
|
|
3331
|
+
async addVaultMember(vaultId, memberId) {
|
|
3332
|
+
const owner = await this.checkVaultOwner(vaultId);
|
|
3269
3333
|
const idKeypair = await this.fetchKeyPair();
|
|
3270
|
-
const
|
|
3271
|
-
const { privateJwk, config, members } = await this.
|
|
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 :
|
|
3280
|
-
|
|
3281
|
-
await this.addMemberKey(
|
|
3282
|
-
return this.updateAsset(vaultId, {
|
|
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
|
|
3285
|
-
const owner = await this.
|
|
3348
|
+
async removeVaultMember(vaultId, memberId) {
|
|
3349
|
+
const owner = await this.checkVaultOwner(vaultId);
|
|
3286
3350
|
const idKeypair = await this.fetchKeyPair();
|
|
3287
|
-
const
|
|
3288
|
-
const { privateJwk, config, members } = await this.
|
|
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 :
|
|
3297
|
-
|
|
3298
|
-
const memberKeyId = this.generateSaltedId(
|
|
3299
|
-
delete
|
|
3300
|
-
return this.updateAsset(vaultId, {
|
|
3301
|
-
}
|
|
3302
|
-
async
|
|
3303
|
-
const
|
|
3304
|
-
const { members, isOwner } = await this.
|
|
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,
|
|
3370
|
+
await this.checkVaultVersion(vaultId, vault);
|
|
3307
3371
|
}
|
|
3308
3372
|
return members;
|
|
3309
3373
|
}
|
|
3310
|
-
async
|
|
3311
|
-
await this.
|
|
3312
|
-
const
|
|
3313
|
-
const { privateJwk, items } = await this.
|
|
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(
|
|
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
|
-
|
|
3329
|
-
|
|
3330
|
-
return this.updateAsset(vaultId, {
|
|
3331
|
-
}
|
|
3332
|
-
async
|
|
3333
|
-
await this.
|
|
3334
|
-
const
|
|
3335
|
-
const { privateJwk, items } = await this.
|
|
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
|
-
|
|
3338
|
-
|
|
3339
|
-
return this.updateAsset(vaultId, {
|
|
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
|
|
3342
|
-
const
|
|
3343
|
-
const { items } = await this.
|
|
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
|
|
3410
|
+
async getVaultItem(vaultId, name, options) {
|
|
3347
3411
|
try {
|
|
3348
|
-
const
|
|
3349
|
-
const { privateJwk, items } = await this.
|
|
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(
|
|
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.
|
|
3546
|
+
const did = await this.createVault(options);
|
|
3483
3547
|
for (const toDID of dmail.to) {
|
|
3484
|
-
await this.
|
|
3548
|
+
await this.addVaultMember(did, toDID);
|
|
3485
3549
|
}
|
|
3486
3550
|
for (const ccDID of dmail.cc) {
|
|
3487
|
-
await this.
|
|
3551
|
+
await this.addVaultMember(did, ccDID);
|
|
3488
3552
|
}
|
|
3489
3553
|
const buffer = Buffer.from(JSON.stringify({ dmail }), 'utf-8');
|
|
3490
|
-
await this.
|
|
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.
|
|
3561
|
+
await this.addVaultMember(did, toDID);
|
|
3498
3562
|
}
|
|
3499
3563
|
for (const ccDID of dmail.cc) {
|
|
3500
|
-
await this.
|
|
3564
|
+
await this.addVaultMember(did, ccDID);
|
|
3501
3565
|
}
|
|
3502
3566
|
const buffer = Buffer.from(JSON.stringify({ dmail }), 'utf-8');
|
|
3503
|
-
return this.
|
|
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
|
|
3524
|
-
if (!
|
|
3587
|
+
const isVault = await this.testVault(did, options);
|
|
3588
|
+
if (!isVault) {
|
|
3525
3589
|
return null;
|
|
3526
3590
|
}
|
|
3527
|
-
const buffer = await this.
|
|
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.
|
|
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.
|
|
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.
|
|
3618
|
+
return this.removeVaultItem(did, name);
|
|
3555
3619
|
}
|
|
3556
3620
|
async getDmailAttachment(did, name) {
|
|
3557
|
-
return this.
|
|
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
|
-
"
|
|
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.
|
|
3736
|
+
notices = await this.gatekeeper.search({ where });
|
|
3676
3737
|
}
|
|
3677
3738
|
catch (error) {
|
|
3678
3739
|
throw new KeymasterError('Failed to search for notices');
|