@tdxvolt/volt-client-grpc 0.17.0 → 0.18.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/README.md +39 -3
- package/lib/index.cjs +87 -119
- package/package.json +2 -2
- package/protobuf/tdx/volt_api/volt/v1/ssi_api.proto +5 -5
- package/protobuf/tdx/volt_api/volt/v1/volt.proto +6 -1
- package/protobuf/tdx/volt_api/volt/v1/volt_api.proto +3 -0
- package/protobuf/tdx/volt_api/volt/v1/wire_api.proto +4 -0
- package/src/constants.js +1 -53
- package/src/grpc-call.js +4 -2
- package/src/rpc-invocation.js +4 -2
- package/src/utils.js +1 -1
- package/src/volt-client-internal.js +3 -5
- package/src/volt-credential.js +8 -6
package/README.md
CHANGED
|
@@ -1,5 +1,41 @@
|
|
|
1
|
-
# volt-client-grpc
|
|
1
|
+
# @tdxvolt/volt-client-grpc
|
|
2
2
|
|
|
3
|
-
Javascript client library for accessing Volts.
|
|
3
|
+
Javascript client library for accessing Volts using gRPC.
|
|
4
|
+
|
|
5
|
+
n.b. This is nodejs only - for browser support use [`@tdxvolt/volt-client-web`](https://npmjs.org/@tdxvolt/volt-client-web).
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @tdxvolt/volt-client-grpc
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
```js
|
|
16
|
+
import grpc from "@grpc/grpc-js";
|
|
17
|
+
import { VoltClient } from "@tdxvolt/volt-client-grpc";
|
|
18
|
+
|
|
19
|
+
const configPath = "./volt.config.json";
|
|
20
|
+
|
|
21
|
+
let client = new VoltClient(grpc);
|
|
22
|
+
|
|
23
|
+
client
|
|
24
|
+
.initialise(configPath)
|
|
25
|
+
.then(() => {
|
|
26
|
+
return client.GetResourceDescendants({
|
|
27
|
+
resource_id: client.config.volt.id,
|
|
28
|
+
depth: 1
|
|
29
|
+
});
|
|
30
|
+
})
|
|
31
|
+
.then((response) => {
|
|
32
|
+
console.log(response);
|
|
33
|
+
})
|
|
34
|
+
.catch((err) => {
|
|
35
|
+
console.error("failure in simple-client [%s]", err.message);
|
|
36
|
+
})
|
|
37
|
+
.finally(() => {
|
|
38
|
+
console.log("finished");
|
|
39
|
+
});
|
|
40
|
+
```
|
|
4
41
|
|
|
5
|
-
n.b. This is nodejs only - for browser support use @tdxvolt/volt-client-web.
|
package/lib/index.cjs
CHANGED
|
@@ -4,7 +4,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
4
4
|
|
|
5
5
|
var lodash = require('lodash');
|
|
6
6
|
var ip = require('ip');
|
|
7
|
-
var
|
|
7
|
+
var js = require('@tdxvolt/volt-client-web/js');
|
|
8
8
|
var debug = require('debug');
|
|
9
9
|
var EventEmitter = require('events');
|
|
10
10
|
var fs = require('fs');
|
|
@@ -17,27 +17,8 @@ var uuid = require('uuid');
|
|
|
17
17
|
|
|
18
18
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
19
19
|
|
|
20
|
-
function _interopNamespace(e) {
|
|
21
|
-
if (e && e.__esModule) return e;
|
|
22
|
-
var n = Object.create(null);
|
|
23
|
-
if (e) {
|
|
24
|
-
Object.keys(e).forEach(function (k) {
|
|
25
|
-
if (k !== 'default') {
|
|
26
|
-
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
27
|
-
Object.defineProperty(n, k, d.get ? d : {
|
|
28
|
-
enumerable: true,
|
|
29
|
-
get: function () { return e[k]; }
|
|
30
|
-
});
|
|
31
|
-
}
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
n["default"] = e;
|
|
35
|
-
return Object.freeze(n);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
20
|
var lodash__default = /*#__PURE__*/_interopDefaultLegacy(lodash);
|
|
39
21
|
var ip__default = /*#__PURE__*/_interopDefaultLegacy(ip);
|
|
40
|
-
var voltClientWeb__namespace = /*#__PURE__*/_interopNamespace(voltClientWeb);
|
|
41
22
|
var debug__default = /*#__PURE__*/_interopDefaultLegacy(debug);
|
|
42
23
|
var EventEmitter__default = /*#__PURE__*/_interopDefaultLegacy(EventEmitter);
|
|
43
24
|
var fs__default = /*#__PURE__*/_interopDefaultLegacy(fs);
|
|
@@ -46,60 +27,13 @@ var protoLoader__default = /*#__PURE__*/_interopDefaultLegacy(protoLoader);
|
|
|
46
27
|
var bent__default = /*#__PURE__*/_interopDefaultLegacy(bent);
|
|
47
28
|
var jwt__default = /*#__PURE__*/_interopDefaultLegacy(jwt);
|
|
48
29
|
|
|
49
|
-
// eslint-disable-next-line import/prefer-default-export
|
|
50
30
|
const constants = {
|
|
51
31
|
authTokenName: "volt-token",
|
|
52
|
-
collectionOperation: {
|
|
53
|
-
add: "ADD",
|
|
54
|
-
remove: "REMOVE",
|
|
55
|
-
update: "UPDATE"
|
|
56
|
-
},
|
|
57
|
-
crypto: {
|
|
58
|
-
subjectDefaults: [
|
|
59
|
-
{
|
|
60
|
-
name: "countryName",
|
|
61
|
-
value: "GB"
|
|
62
|
-
},
|
|
63
|
-
{
|
|
64
|
-
name: "localityName",
|
|
65
|
-
value: "Southampton"
|
|
66
|
-
},
|
|
67
|
-
{
|
|
68
|
-
name: "organizationName",
|
|
69
|
-
value: "nquiringminds Ltd"
|
|
70
|
-
}
|
|
71
|
-
],
|
|
72
|
-
userIdOID: "0.9.2342.19200300.100.1.1"
|
|
73
|
-
},
|
|
74
32
|
defaultDIDHostName: "tdxvolt.com",
|
|
75
33
|
didServiceType: {
|
|
76
34
|
voltConfig: "volt-discovery"
|
|
77
35
|
},
|
|
78
|
-
identityType: {
|
|
79
|
-
did: "did",
|
|
80
|
-
volt: "volt"
|
|
81
|
-
},
|
|
82
|
-
onlineStatus: {
|
|
83
|
-
offline: "offline",
|
|
84
|
-
online: "online",
|
|
85
|
-
unknown: "unknown"
|
|
86
|
-
},
|
|
87
36
|
privateEncryptedKeyPrefix: "-----BEGIN ENCRYPTED PRIVATE KEY-----",
|
|
88
|
-
resource: {
|
|
89
|
-
identity: "ident",
|
|
90
|
-
identityView: "ident-view",
|
|
91
|
-
proxy: "proxy",
|
|
92
|
-
proxyView: "proxy-view",
|
|
93
|
-
vc: "vc",
|
|
94
|
-
vcView: "vc-view"
|
|
95
|
-
},
|
|
96
|
-
voltStatus: {
|
|
97
|
-
pending: "",
|
|
98
|
-
online: "online",
|
|
99
|
-
offline: "offline",
|
|
100
|
-
deleted: "deleted",
|
|
101
|
-
revoked: "revoked"
|
|
102
|
-
},
|
|
103
37
|
/**
|
|
104
38
|
* These top-level service types should map to a protobuf definition
|
|
105
39
|
* in @tdxvolt/volt-proto.
|
|
@@ -112,12 +46,7 @@ const constants = {
|
|
|
112
46
|
relayAPI: "tdx.volt_api.relay.v1.RelayAPI",
|
|
113
47
|
voltAPI: "tdx.volt_api.volt.v1.VoltAPI",
|
|
114
48
|
wireAPI: "tdx.volt_api.volt.v1.WireAPI"
|
|
115
|
-
}
|
|
116
|
-
tunnelInvokeMethod: "/tdx.volt_api.volt.v1.VoltAPI/Invoke",
|
|
117
|
-
tunnelPingInterval: 10000,
|
|
118
|
-
tunnelPingTimeout: 2500,
|
|
119
|
-
tunnelReconnectAfter: 30000,
|
|
120
|
-
tunnelTimeoutInterval: 10000 * 2 // This must always be greater than `tunnelPingInterval`.
|
|
49
|
+
}
|
|
121
50
|
};
|
|
122
51
|
|
|
123
52
|
const createSecureContextOptions = (cryptoOptions) => {
|
|
@@ -172,7 +101,7 @@ var utils = /*#__PURE__*/Object.freeze({
|
|
|
172
101
|
createSecureContextOptions: createSecureContextOptions,
|
|
173
102
|
getServiceAddress: getServiceAddress,
|
|
174
103
|
getDIDResolutionURL: getDIDResolutionURL,
|
|
175
|
-
crypto:
|
|
104
|
+
crypto: js.voltUtils
|
|
176
105
|
});
|
|
177
106
|
|
|
178
107
|
/* eslint-disable no-underscore-dangle */
|
|
@@ -418,6 +347,15 @@ var grpcUtils = /*#__PURE__*/Object.freeze({
|
|
|
418
347
|
|
|
419
348
|
/* eslint-disable no-underscore-dangle */
|
|
420
349
|
|
|
350
|
+
const {
|
|
351
|
+
createSigningKey,
|
|
352
|
+
fingerprintFromPem,
|
|
353
|
+
getIdentityToken,
|
|
354
|
+
keyFromPem: keyFromPem$2,
|
|
355
|
+
privateKeyToPem,
|
|
356
|
+
publicKeyToPem: publicKeyToPem$2
|
|
357
|
+
} = js.voltUtils;
|
|
358
|
+
|
|
421
359
|
const log$5 = debug__default["default"]("volt-client-grpc:volt-credential");
|
|
422
360
|
|
|
423
361
|
class VoltCredential {
|
|
@@ -442,13 +380,13 @@ class VoltCredential {
|
|
|
442
380
|
}
|
|
443
381
|
|
|
444
382
|
// Need to unencrypt the private key.
|
|
445
|
-
const decrypted =
|
|
383
|
+
const decrypted = keyFromPem$2(this._cryptoCache.key, config.p);
|
|
446
384
|
|
|
447
385
|
if (!decrypted) {
|
|
448
386
|
throw new Error("failed to decrypt key - check passphrase");
|
|
449
387
|
}
|
|
450
388
|
|
|
451
|
-
this._cryptoCache.key =
|
|
389
|
+
this._cryptoCache.key = privateKeyToPem(decrypted.privateKey);
|
|
452
390
|
}
|
|
453
391
|
|
|
454
392
|
if (this._voltConfig.ca_pem) {
|
|
@@ -460,8 +398,8 @@ class VoltCredential {
|
|
|
460
398
|
// Extract Volt public key (used for encrypting Relay payloads).
|
|
461
399
|
this._voltPublicKey = this._voltConfig.public_key;
|
|
462
400
|
|
|
463
|
-
const voltKey =
|
|
464
|
-
this._voltFingerprint =
|
|
401
|
+
const voltKey = keyFromPem$2(this._voltPublicKey).publicKey;
|
|
402
|
+
this._voltFingerprint = fingerprintFromPem(voltKey);
|
|
465
403
|
}
|
|
466
404
|
}
|
|
467
405
|
|
|
@@ -490,7 +428,7 @@ class VoltCredential {
|
|
|
490
428
|
}
|
|
491
429
|
|
|
492
430
|
get publicKey() {
|
|
493
|
-
return
|
|
431
|
+
return publicKeyToPem$2(this.getKey().publicKey);
|
|
494
432
|
}
|
|
495
433
|
|
|
496
434
|
get voltFingerprint() {
|
|
@@ -498,7 +436,7 @@ class VoltCredential {
|
|
|
498
436
|
}
|
|
499
437
|
|
|
500
438
|
getKey() {
|
|
501
|
-
const key =
|
|
439
|
+
const key = keyFromPem$2(this._cryptoCache.key);
|
|
502
440
|
return key;
|
|
503
441
|
}
|
|
504
442
|
|
|
@@ -512,8 +450,8 @@ class VoltCredential {
|
|
|
512
450
|
return Promise.resolve(this.getKey());
|
|
513
451
|
} else {
|
|
514
452
|
log$5("creating key");
|
|
515
|
-
this._cryptoCache.key =
|
|
516
|
-
const key =
|
|
453
|
+
this._cryptoCache.key = createSigningKey();
|
|
454
|
+
const key = keyFromPem$2(this._cryptoCache.key);
|
|
517
455
|
log$5("successfully created key");
|
|
518
456
|
return Promise.resolve(key);
|
|
519
457
|
}
|
|
@@ -550,9 +488,9 @@ class VoltCredential {
|
|
|
550
488
|
* @returns
|
|
551
489
|
*/
|
|
552
490
|
getIdentityMetadata(grpc, audience, publicKey, tunnelling = false, ttl = 60) {
|
|
553
|
-
const key =
|
|
491
|
+
const key = keyFromPem$2(this._cryptoCache.key);
|
|
554
492
|
|
|
555
|
-
const identityToken =
|
|
493
|
+
const identityToken = getIdentityToken(
|
|
556
494
|
this.sessionId,
|
|
557
495
|
key,
|
|
558
496
|
audience || this._voltConfig.id,
|
|
@@ -568,8 +506,8 @@ class VoltCredential {
|
|
|
568
506
|
const clone = { ...this._config, credential: { ...this._cryptoCache } };
|
|
569
507
|
if (this._config.p) {
|
|
570
508
|
// A passphrase option exists => encrypt the key before writing the cache file.
|
|
571
|
-
const key =
|
|
572
|
-
clone.credential.key =
|
|
509
|
+
const key = keyFromPem$2(this._cryptoCache.key);
|
|
510
|
+
clone.credential.key = privateKeyToPem(key.privateKey, this._config.p);
|
|
573
511
|
}
|
|
574
512
|
|
|
575
513
|
if (this._persistCache) {
|
|
@@ -708,6 +646,18 @@ var protoUtils = /*#__PURE__*/Object.freeze({
|
|
|
708
646
|
|
|
709
647
|
/* eslint-disable no-underscore-dangle */
|
|
710
648
|
|
|
649
|
+
const {
|
|
650
|
+
aesCreateKey,
|
|
651
|
+
aesEncrypt: aesEncrypt$1,
|
|
652
|
+
aesDecrypt: aesDecrypt$1,
|
|
653
|
+
toBase64,
|
|
654
|
+
formatPEM: formatPEM$1,
|
|
655
|
+
keyFromPem: keyFromPem$1,
|
|
656
|
+
verify,
|
|
657
|
+
deriveSharedKey: deriveSharedKey$1,
|
|
658
|
+
x25519: x25519$1
|
|
659
|
+
} = js.voltUtils;
|
|
660
|
+
|
|
711
661
|
const log$4 = debug__default["default"]("volt-client-grpc:grpc-call");
|
|
712
662
|
|
|
713
663
|
function _prepareInvokeRequest(
|
|
@@ -811,10 +761,10 @@ function _prepareInvokeRequest(
|
|
|
811
761
|
};
|
|
812
762
|
|
|
813
763
|
let invokePayload;
|
|
814
|
-
const iv =
|
|
764
|
+
const iv = aesCreateKey().iv;
|
|
815
765
|
|
|
816
766
|
// When sending via a relay we need to encrypt the payload.
|
|
817
|
-
invokePayload =
|
|
767
|
+
invokePayload = aesEncrypt$1(
|
|
818
768
|
this._encryptionKey,
|
|
819
769
|
iv,
|
|
820
770
|
tunnelMethod.responseSerialize(tunnelResp)
|
|
@@ -845,7 +795,7 @@ function _preparePayloadRequest(request, invokeInfo) {
|
|
|
845
795
|
|
|
846
796
|
let iv;
|
|
847
797
|
if (this._voltClient.isVoltRelay || isServiceRelayed) {
|
|
848
|
-
iv =
|
|
798
|
+
iv = aesCreateKey().iv;
|
|
849
799
|
|
|
850
800
|
const requestPayload =
|
|
851
801
|
this._grpcClient[invokeInfo.methodName].requestSerialize(request);
|
|
@@ -859,7 +809,7 @@ function _preparePayloadRequest(request, invokeInfo) {
|
|
|
859
809
|
}
|
|
860
810
|
};
|
|
861
811
|
|
|
862
|
-
const invokePayload =
|
|
812
|
+
const invokePayload = aesEncrypt$1(
|
|
863
813
|
this._encryptionKey,
|
|
864
814
|
iv,
|
|
865
815
|
tunnelMethod.responseSerialize(tunnelResp)
|
|
@@ -896,24 +846,24 @@ function _parseResponse(method, meta, response) {
|
|
|
896
846
|
message.set(nonce, encryptionKey.length);
|
|
897
847
|
|
|
898
848
|
// Check the signature using the target service public key.
|
|
899
|
-
const targetKey =
|
|
849
|
+
const targetKey = keyFromPem$1(
|
|
900
850
|
this._service?.service_description?.host_public_key ||
|
|
901
851
|
this._voltClient.credential.voltPublicKey
|
|
902
852
|
).publicKey;
|
|
903
853
|
|
|
904
|
-
if (!
|
|
854
|
+
if (!verify(targetKey, message, signature)) {
|
|
905
855
|
throw new Error("signature verification failed");
|
|
906
856
|
}
|
|
907
857
|
|
|
908
858
|
invokeResponse = {
|
|
909
859
|
key_exchange: {
|
|
910
|
-
encryption_key:
|
|
860
|
+
encryption_key: formatPEM$1(toBase64(encryptionKey), "PUBLIC KEY")
|
|
911
861
|
}
|
|
912
862
|
};
|
|
913
863
|
} else if (response.payload) {
|
|
914
864
|
let decryptedPayload;
|
|
915
865
|
if (this._encryptionKey) {
|
|
916
|
-
decryptedPayload =
|
|
866
|
+
decryptedPayload = aesDecrypt$1(
|
|
917
867
|
this._encryptionKey,
|
|
918
868
|
response.iv,
|
|
919
869
|
response.payload
|
|
@@ -957,7 +907,7 @@ function _parseResponse(method, meta, response) {
|
|
|
957
907
|
log$4("started method %d for %s", invokeResponse.methodId, method);
|
|
958
908
|
}
|
|
959
909
|
} else if (this._voltClient.isRemote && this._encryptionKey) {
|
|
960
|
-
const decryptedPayload =
|
|
910
|
+
const decryptedPayload = aesDecrypt$1(
|
|
961
911
|
this._encryptionKey,
|
|
962
912
|
meta.sharedKey.iv,
|
|
963
913
|
response
|
|
@@ -1024,14 +974,14 @@ class GRPCCall extends EventEmitter__default["default"] {
|
|
|
1024
974
|
streamResponse
|
|
1025
975
|
);
|
|
1026
976
|
if (parsedResponse.key_exchange) {
|
|
1027
|
-
const peerKey =
|
|
977
|
+
const peerKey = keyFromPem$1(
|
|
1028
978
|
parsedResponse.key_exchange.encryption_key
|
|
1029
979
|
).publicKey;
|
|
1030
980
|
|
|
1031
|
-
this._encryptionKey =
|
|
981
|
+
this._encryptionKey = deriveSharedKey$1(
|
|
1032
982
|
this._initialRequest.meta.sharedKey.key,
|
|
1033
983
|
peerKey,
|
|
1034
|
-
|
|
984
|
+
x25519$1
|
|
1035
985
|
);
|
|
1036
986
|
|
|
1037
987
|
// We've exchanged keys, so send any queued payloads on the next tick.
|
|
@@ -1324,6 +1274,22 @@ class VoltConnection extends EventEmitter__default["default"] {
|
|
|
1324
1274
|
}
|
|
1325
1275
|
}
|
|
1326
1276
|
|
|
1277
|
+
const {
|
|
1278
|
+
aesDecrypt,
|
|
1279
|
+
aesEncrypt,
|
|
1280
|
+
createEncryptionKey,
|
|
1281
|
+
deriveSharedKey,
|
|
1282
|
+
formatPEM,
|
|
1283
|
+
fromBase64,
|
|
1284
|
+
fromBase64Url,
|
|
1285
|
+
keyFromPem,
|
|
1286
|
+
publicKeyToPem: publicKeyToPem$1,
|
|
1287
|
+
randomBytes,
|
|
1288
|
+
signBase64: signBase64$1,
|
|
1289
|
+
stripPEMHeaders,
|
|
1290
|
+
x25519
|
|
1291
|
+
} = js.voltUtils;
|
|
1292
|
+
|
|
1327
1293
|
const log$2 = debug__default["default"]("rpc-invocation");
|
|
1328
1294
|
|
|
1329
1295
|
class RpcInvocation extends EventEmitter__default["default"] {
|
|
@@ -1390,29 +1356,29 @@ class RpcInvocation extends EventEmitter__default["default"] {
|
|
|
1390
1356
|
this.#token = jwt__default["default"].decode(token);
|
|
1391
1357
|
|
|
1392
1358
|
// Store the JWT key id (kid) for use in the response.
|
|
1393
|
-
const callerPublicKeyPem =
|
|
1394
|
-
const callerKey =
|
|
1359
|
+
const callerPublicKeyPem = formatPEM(this.#token.k, "PUBLIC KEY");
|
|
1360
|
+
const callerKey = keyFromPem(callerPublicKeyPem, "", x25519).publicKey;
|
|
1395
1361
|
|
|
1396
|
-
const ephemeralKeyPem =
|
|
1397
|
-
const ephemeralKey =
|
|
1398
|
-
const ephemeralPublicKey =
|
|
1399
|
-
|
|
1362
|
+
const ephemeralKeyPem = createEncryptionKey();
|
|
1363
|
+
const ephemeralKey = keyFromPem(ephemeralKeyPem, "", x25519);
|
|
1364
|
+
const ephemeralPublicKey = fromBase64(
|
|
1365
|
+
stripPEMHeaders(publicKeyToPem$1(ephemeralKey.publicKey, x25519))
|
|
1400
1366
|
);
|
|
1401
1367
|
|
|
1402
|
-
this.#derivedKey =
|
|
1368
|
+
this.#derivedKey = deriveSharedKey(
|
|
1403
1369
|
ephemeralKey.privateKey,
|
|
1404
1370
|
callerKey,
|
|
1405
|
-
|
|
1371
|
+
x25519
|
|
1406
1372
|
);
|
|
1407
1373
|
|
|
1408
|
-
const nonce =
|
|
1374
|
+
const nonce = randomBytes(16);
|
|
1409
1375
|
|
|
1410
1376
|
// The signed message is the encryption key and the nonce.
|
|
1411
1377
|
const message = new Uint8Array(ephemeralPublicKey.length + nonce.length);
|
|
1412
1378
|
message.set(ephemeralPublicKey);
|
|
1413
1379
|
message.set(nonce, ephemeralPublicKey.length);
|
|
1414
1380
|
|
|
1415
|
-
const signature =
|
|
1381
|
+
const signature = signBase64$1(
|
|
1416
1382
|
this.#voltClient.credential.getKey().privateKey,
|
|
1417
1383
|
message
|
|
1418
1384
|
);
|
|
@@ -1422,7 +1388,7 @@ class RpcInvocation extends EventEmitter__default["default"] {
|
|
|
1422
1388
|
key_exchange: {
|
|
1423
1389
|
nonce,
|
|
1424
1390
|
encryption_key: ephemeralPublicKey,
|
|
1425
|
-
signature:
|
|
1391
|
+
signature: fromBase64Url(signature)
|
|
1426
1392
|
}
|
|
1427
1393
|
};
|
|
1428
1394
|
|
|
@@ -1459,7 +1425,7 @@ class RpcInvocation extends EventEmitter__default["default"] {
|
|
|
1459
1425
|
|
|
1460
1426
|
if (encryptIV) {
|
|
1461
1427
|
// Decrypt the actual payload using the shared key and iv.
|
|
1462
|
-
decryptedPayload =
|
|
1428
|
+
decryptedPayload = aesDecrypt(
|
|
1463
1429
|
this.#derivedKey,
|
|
1464
1430
|
encryptIV,
|
|
1465
1431
|
invoke_request.payload
|
|
@@ -1500,7 +1466,7 @@ class RpcInvocation extends EventEmitter__default["default"] {
|
|
|
1500
1466
|
|
|
1501
1467
|
if (this.#derivedKey) {
|
|
1502
1468
|
// Decrypt the actual payload using the shared key and iv.
|
|
1503
|
-
decryptedPayload =
|
|
1469
|
+
decryptedPayload = aesDecrypt(
|
|
1504
1470
|
this.#derivedKey,
|
|
1505
1471
|
invoke_request.iv,
|
|
1506
1472
|
Buffer.from(invoke_request.json_payload, "base64")
|
|
@@ -1562,10 +1528,10 @@ class RpcInvocation extends EventEmitter__default["default"] {
|
|
|
1562
1528
|
});
|
|
1563
1529
|
}
|
|
1564
1530
|
|
|
1565
|
-
const iv =
|
|
1531
|
+
const iv = randomBytes(16);
|
|
1566
1532
|
if (this.#derivedKey) {
|
|
1567
1533
|
// Encrypt the response using the shared key and iv.
|
|
1568
|
-
responsePayload =
|
|
1534
|
+
responsePayload = aesEncrypt(this.#derivedKey, iv, responsePayload);
|
|
1569
1535
|
}
|
|
1570
1536
|
|
|
1571
1537
|
const invokeResponse = {
|
|
@@ -1605,10 +1571,10 @@ class RpcInvocation extends EventEmitter__default["default"] {
|
|
|
1605
1571
|
endPayload = tunnelMethod.requestSerialize(endPayload);
|
|
1606
1572
|
}
|
|
1607
1573
|
|
|
1608
|
-
const iv =
|
|
1574
|
+
const iv = randomBytes(16);
|
|
1609
1575
|
if (this.#derivedKey) {
|
|
1610
1576
|
// Encrypt the response using the shared key and iv.
|
|
1611
|
-
endPayload =
|
|
1577
|
+
endPayload = aesEncrypt(this.#derivedKey, iv, endPayload);
|
|
1612
1578
|
}
|
|
1613
1579
|
|
|
1614
1580
|
const invokeResponse = {
|
|
@@ -1631,6 +1597,8 @@ class RpcInvocation extends EventEmitter__default["default"] {
|
|
|
1631
1597
|
|
|
1632
1598
|
/* eslint-disable no-underscore-dangle */
|
|
1633
1599
|
|
|
1600
|
+
const { publicKeyToPem, removeCarriageReturn, signBase64 } = js.voltUtils;
|
|
1601
|
+
|
|
1634
1602
|
const { filter, pick } = lodash__default["default"];
|
|
1635
1603
|
|
|
1636
1604
|
const log$1 = debug__default["default"]("volt-client-grpc:volt-client-internal");
|
|
@@ -1763,8 +1731,8 @@ async function authenticateInternal(
|
|
|
1763
1731
|
}
|
|
1764
1732
|
|
|
1765
1733
|
const keyPair = this._credential.getKey();
|
|
1766
|
-
const publicKeyPem =
|
|
1767
|
-
|
|
1734
|
+
const publicKeyPem = removeCarriageReturn(
|
|
1735
|
+
publicKeyToPem(keyPair.publicKey)
|
|
1768
1736
|
);
|
|
1769
1737
|
|
|
1770
1738
|
if (!this._credential.cache.bindIp) {
|
|
@@ -1782,7 +1750,7 @@ async function authenticateInternal(
|
|
|
1782
1750
|
};
|
|
1783
1751
|
|
|
1784
1752
|
if (this._voltConfig.challenge_code) {
|
|
1785
|
-
authenticateRequest.challenge =
|
|
1753
|
+
authenticateRequest.challenge = signBase64(
|
|
1786
1754
|
keyPair.privateKey,
|
|
1787
1755
|
this._voltConfig.challenge_code
|
|
1788
1756
|
);
|
|
@@ -1832,7 +1800,7 @@ async function authenticateInternal(
|
|
|
1832
1800
|
|
|
1833
1801
|
// Now sign the entire DID document, including the proof and set it in the
|
|
1834
1802
|
// bind request. This is required by the Volt to verify that we have the private key for the DID.
|
|
1835
|
-
authenticateRequest.did_document_signature =
|
|
1803
|
+
authenticateRequest.did_document_signature = signBase64(
|
|
1836
1804
|
keyPair.privateKey,
|
|
1837
1805
|
authenticateRequest.did_document
|
|
1838
1806
|
);
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "0.
|
|
6
|
+
"version": "0.18.0",
|
|
7
7
|
"description": "tdx Volt library for nodejs clients",
|
|
8
8
|
"type": "module",
|
|
9
9
|
"exports": {
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"license": "ISC",
|
|
38
38
|
"dependencies": {
|
|
39
39
|
"@grpc/proto-loader": "^0.6.4",
|
|
40
|
-
"@tdxvolt/volt-client-web": "^0.
|
|
40
|
+
"@tdxvolt/volt-client-web": "^0.18.0",
|
|
41
41
|
"bent": "^7.3.12",
|
|
42
42
|
"builtin-modules": "^3.3.0",
|
|
43
43
|
"debug": "^4.1.1",
|
|
@@ -2,18 +2,19 @@ syntax = "proto3";
|
|
|
2
2
|
|
|
3
3
|
package tdx.volt_api.volt.v1;
|
|
4
4
|
|
|
5
|
-
import "tdx/volt_api/volt/v1/ssi.proto";
|
|
6
5
|
import "tdx/volt_api/volt/v1/status.proto";
|
|
6
|
+
import "tdx/volt_api/volt/v1/ssi.proto";
|
|
7
7
|
|
|
8
8
|
service SsiAPI {
|
|
9
9
|
// Delete a DID document or all DID documents originating from a given Volt.
|
|
10
|
-
// Requires
|
|
10
|
+
// Requires `volt:delete-did` API privilege.
|
|
11
11
|
rpc DeleteDID(DeleteDIDRequest) returns (DeleteDIDResponse);
|
|
12
12
|
|
|
13
13
|
// Get all updates to the DID registry since the specified timestamp.
|
|
14
14
|
// Internal use only.
|
|
15
15
|
rpc GetDIDRegistryUpdates(GetDIDRegistryUpdatesRequest) returns (GetDIDRegistryUpdatesResponse);
|
|
16
16
|
|
|
17
|
+
// Import a verifiable credential.
|
|
17
18
|
rpc ImportCredential(ImportCredentialRequest) returns (ImportCredentialResponse);
|
|
18
19
|
|
|
19
20
|
// Parse a verifiable credential from a URL or a verifiable presentation.
|
|
@@ -23,8 +24,8 @@ service SsiAPI {
|
|
|
23
24
|
rpc ResolveDID(ResolveDIDRequest) returns (ResolveDIDResponse);
|
|
24
25
|
|
|
25
26
|
// Register a DID document.
|
|
26
|
-
// This is
|
|
27
|
-
// To register a new DID document, use the VoltAPI Authenticate method.
|
|
27
|
+
// This is intended for use by the DID registry when synchronising with other registries.
|
|
28
|
+
// To register a new DID document, it is recommended to use the VoltAPI Authenticate method.
|
|
28
29
|
rpc RegisterDIDDocument(RegisterDIDDocumentRequest) returns (RegisterDIDDocumentResponse);
|
|
29
30
|
|
|
30
31
|
// Save a verifiable credential.
|
|
@@ -153,7 +154,6 @@ message RegisterDIDDocumentRequest {
|
|
|
153
154
|
DIDRegistryUpdate did_update = 2;
|
|
154
155
|
|
|
155
156
|
// When updating an existing DID document, it is necessary to include a signature of the document JSON, signed by the DID document's current owner.
|
|
156
|
-
// This is different from the proof contained in the DID document itself.
|
|
157
157
|
string update_signature = 3;
|
|
158
158
|
}
|
|
159
159
|
|
|
@@ -309,12 +309,17 @@ message VoltEndpoint {
|
|
|
309
309
|
// The online status of the Volt.
|
|
310
310
|
OnlineStatus online_status = 11;
|
|
311
311
|
|
|
312
|
-
//
|
|
312
|
+
// Indicates that this Volt acts as a Relay.
|
|
313
313
|
bool has_relay = 12;
|
|
314
314
|
|
|
315
|
+
// The API version supported by the endpoint.
|
|
315
316
|
Version api_version = 13;
|
|
316
317
|
|
|
318
|
+
// Optional description of the endpoint.
|
|
317
319
|
string description = 14;
|
|
320
|
+
|
|
321
|
+
// The list of DID registries that this Volt trusts.
|
|
322
|
+
repeated string did_registry = 15;
|
|
318
323
|
}
|
|
319
324
|
|
|
320
325
|
// Internal use only.
|
|
@@ -22,6 +22,10 @@ message PublishWireRequest {
|
|
|
22
22
|
|
|
23
23
|
// The chunk of data to publish.
|
|
24
24
|
bytes chunk = 2;
|
|
25
|
+
|
|
26
|
+
// Whether to persist the chunk.
|
|
27
|
+
// This is only valid if the wire is configured to persist messages, i.e. the `volt:wire-persist` attribute is true.
|
|
28
|
+
bool do_not_persist = 3;
|
|
25
29
|
}
|
|
26
30
|
|
|
27
31
|
message PublishWireResponse {
|
package/src/constants.js
CHANGED
|
@@ -1,57 +1,10 @@
|
|
|
1
|
-
// eslint-disable-next-line import/prefer-default-export
|
|
2
1
|
export const constants = {
|
|
3
2
|
authTokenName: "volt-token",
|
|
4
|
-
collectionOperation: {
|
|
5
|
-
add: "ADD",
|
|
6
|
-
remove: "REMOVE",
|
|
7
|
-
update: "UPDATE"
|
|
8
|
-
},
|
|
9
|
-
crypto: {
|
|
10
|
-
subjectDefaults: [
|
|
11
|
-
{
|
|
12
|
-
name: "countryName",
|
|
13
|
-
value: "GB"
|
|
14
|
-
},
|
|
15
|
-
{
|
|
16
|
-
name: "localityName",
|
|
17
|
-
value: "Southampton"
|
|
18
|
-
},
|
|
19
|
-
{
|
|
20
|
-
name: "organizationName",
|
|
21
|
-
value: "nquiringminds Ltd"
|
|
22
|
-
}
|
|
23
|
-
],
|
|
24
|
-
userIdOID: "0.9.2342.19200300.100.1.1"
|
|
25
|
-
},
|
|
26
3
|
defaultDIDHostName: "tdxvolt.com",
|
|
27
4
|
didServiceType: {
|
|
28
5
|
voltConfig: "volt-discovery"
|
|
29
6
|
},
|
|
30
|
-
identityType: {
|
|
31
|
-
did: "did",
|
|
32
|
-
volt: "volt"
|
|
33
|
-
},
|
|
34
|
-
onlineStatus: {
|
|
35
|
-
offline: "offline",
|
|
36
|
-
online: "online",
|
|
37
|
-
unknown: "unknown"
|
|
38
|
-
},
|
|
39
7
|
privateEncryptedKeyPrefix: "-----BEGIN ENCRYPTED PRIVATE KEY-----",
|
|
40
|
-
resource: {
|
|
41
|
-
identity: "ident",
|
|
42
|
-
identityView: "ident-view",
|
|
43
|
-
proxy: "proxy",
|
|
44
|
-
proxyView: "proxy-view",
|
|
45
|
-
vc: "vc",
|
|
46
|
-
vcView: "vc-view"
|
|
47
|
-
},
|
|
48
|
-
voltStatus: {
|
|
49
|
-
pending: "",
|
|
50
|
-
online: "online",
|
|
51
|
-
offline: "offline",
|
|
52
|
-
deleted: "deleted",
|
|
53
|
-
revoked: "revoked"
|
|
54
|
-
},
|
|
55
8
|
/**
|
|
56
9
|
* These top-level service types should map to a protobuf definition
|
|
57
10
|
* in @tdxvolt/volt-proto.
|
|
@@ -64,10 +17,5 @@ export const constants = {
|
|
|
64
17
|
relayAPI: "tdx.volt_api.relay.v1.RelayAPI",
|
|
65
18
|
voltAPI: "tdx.volt_api.volt.v1.VoltAPI",
|
|
66
19
|
wireAPI: "tdx.volt_api.volt.v1.WireAPI"
|
|
67
|
-
}
|
|
68
|
-
tunnelInvokeMethod: "/tdx.volt_api.volt.v1.VoltAPI/Invoke",
|
|
69
|
-
tunnelPingInterval: 10000,
|
|
70
|
-
tunnelPingTimeout: 2500,
|
|
71
|
-
tunnelReconnectAfter: 30000,
|
|
72
|
-
tunnelTimeoutInterval: 10000 * 2 // This must always be greater than `tunnelPingInterval`.
|
|
20
|
+
}
|
|
73
21
|
};
|
package/src/grpc-call.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
/* eslint-disable no-underscore-dangle */
|
|
2
2
|
import debug from "debug";
|
|
3
3
|
import EventEmitter from "events";
|
|
4
|
-
import {
|
|
4
|
+
import { voltUtils as voltClientUtils } from "@tdxvolt/volt-client-web/js";
|
|
5
|
+
|
|
6
|
+
const {
|
|
5
7
|
aesCreateKey,
|
|
6
8
|
aesEncrypt,
|
|
7
9
|
aesDecrypt,
|
|
@@ -11,7 +13,7 @@ import {
|
|
|
11
13
|
verify,
|
|
12
14
|
deriveSharedKey,
|
|
13
15
|
x25519
|
|
14
|
-
}
|
|
16
|
+
} = voltClientUtils;
|
|
15
17
|
|
|
16
18
|
const log = debug("volt-client-grpc:grpc-call");
|
|
17
19
|
|
package/src/rpc-invocation.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import debug from "debug";
|
|
2
2
|
import jwt from "jsonwebtoken";
|
|
3
3
|
import EventEmitter from "events";
|
|
4
|
-
import {
|
|
4
|
+
import { voltUtils as voltClientUtils } from "@tdxvolt/volt-client-web/js";
|
|
5
|
+
|
|
6
|
+
const {
|
|
5
7
|
aesDecrypt,
|
|
6
8
|
aesEncrypt,
|
|
7
9
|
createEncryptionKey,
|
|
@@ -15,7 +17,7 @@ import {
|
|
|
15
17
|
signBase64,
|
|
16
18
|
stripPEMHeaders,
|
|
17
19
|
x25519
|
|
18
|
-
}
|
|
20
|
+
} = voltClientUtils;
|
|
19
21
|
|
|
20
22
|
const log = debug("rpc-invocation");
|
|
21
23
|
|
package/src/utils.js
CHANGED
|
@@ -16,11 +16,9 @@ import { constants } from "./constants.js";
|
|
|
16
16
|
import GRPCCall from "./grpc-call.js";
|
|
17
17
|
import RpcInvocation from "./rpc-invocation.js";
|
|
18
18
|
import { v4 as generateId } from "uuid";
|
|
19
|
-
import {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
signBase64
|
|
23
|
-
} from "@tdxvolt/volt-client-web";
|
|
19
|
+
import { voltUtils as voltClientUtils } from "@tdxvolt/volt-client-web/js";
|
|
20
|
+
|
|
21
|
+
const { publicKeyToPem, removeCarriageReturn, signBase64 } = voltClientUtils;
|
|
24
22
|
|
|
25
23
|
const { filter, pick } = lodash;
|
|
26
24
|
|
package/src/volt-credential.js
CHANGED
|
@@ -2,14 +2,16 @@
|
|
|
2
2
|
import debug from "debug";
|
|
3
3
|
import fs from "fs";
|
|
4
4
|
import { constants } from "./constants.js";
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
import { voltUtils as voltClientUtils } from "@tdxvolt/volt-client-web/js";
|
|
6
|
+
|
|
7
|
+
const {
|
|
8
|
+
createSigningKey,
|
|
9
|
+
fingerprintFromPem,
|
|
8
10
|
getIdentityToken,
|
|
9
11
|
keyFromPem,
|
|
10
12
|
privateKeyToPem,
|
|
11
13
|
publicKeyToPem
|
|
12
|
-
}
|
|
14
|
+
} = voltClientUtils;
|
|
13
15
|
|
|
14
16
|
const log = debug("volt-client-grpc:volt-credential");
|
|
15
17
|
|
|
@@ -54,7 +56,7 @@ export class VoltCredential {
|
|
|
54
56
|
this._voltPublicKey = this._voltConfig.public_key;
|
|
55
57
|
|
|
56
58
|
const voltKey = keyFromPem(this._voltPublicKey).publicKey;
|
|
57
|
-
this._voltFingerprint =
|
|
59
|
+
this._voltFingerprint = fingerprintFromPem(voltKey);
|
|
58
60
|
}
|
|
59
61
|
}
|
|
60
62
|
|
|
@@ -105,7 +107,7 @@ export class VoltCredential {
|
|
|
105
107
|
return Promise.resolve(this.getKey());
|
|
106
108
|
} else {
|
|
107
109
|
log("creating key");
|
|
108
|
-
this._cryptoCache.key =
|
|
110
|
+
this._cryptoCache.key = createSigningKey();
|
|
109
111
|
const key = keyFromPem(this._cryptoCache.key);
|
|
110
112
|
log("successfully created key");
|
|
111
113
|
return Promise.resolve(key);
|