@tdxvolt/volt-client-grpc 0.17.0 → 0.18.1
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 +334 -216
- 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 +2 -54
- package/src/grpc-call.js +109 -56
- package/src/grpc-utils.js +3 -3
- package/src/rpc-invocation.js +51 -13
- package/src/utils.js +1 -1
- package/src/volt-client-internal.js +39 -26
- package/src/volt-client.js +42 -12
- package/src/volt-connection.js +16 -2
- package/src/volt-credential.js +13 -7
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
|
-
|
|
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
|
-
defaultDIDHostName: "tdxvolt.com",
|
|
32
|
+
defaultDIDHostName: "coreid.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 */
|
|
@@ -194,7 +123,7 @@ function createClient(
|
|
|
194
123
|
) {
|
|
195
124
|
let grpcCredentials;
|
|
196
125
|
if (credentials) {
|
|
197
|
-
const relaying = !!credentials.config?.volt?.relay;
|
|
126
|
+
const relaying = !!credentials.config?.volt?.relay && !Array.isArray(credentials.config?.volt?.relay);
|
|
198
127
|
const ca = relaying
|
|
199
128
|
? credentials.config?.volt?.relay?.ca_pem
|
|
200
129
|
: credentials.cache.ca;
|
|
@@ -202,8 +131,8 @@ function createClient(
|
|
|
202
131
|
const { key } = credentials.cache;
|
|
203
132
|
|
|
204
133
|
if (key && cert) {
|
|
205
|
-
const
|
|
206
|
-
const tlsOptions = createSecureContextOptions(
|
|
134
|
+
const cryptoOptions = { ca, cert, key };
|
|
135
|
+
const tlsOptions = createSecureContextOptions(cryptoOptions);
|
|
207
136
|
grpcCredentials = grpc.credentials.createSsl(
|
|
208
137
|
tlsOptions.ca,
|
|
209
138
|
tlsOptions.key,
|
|
@@ -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) {
|
|
@@ -457,11 +395,11 @@ class VoltCredential {
|
|
|
457
395
|
this._cryptoCache.ca = this._voltConfig.ca_pem;
|
|
458
396
|
}
|
|
459
397
|
|
|
460
|
-
// Extract Volt public key
|
|
398
|
+
// Extract Volt public key.
|
|
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,15 +428,19 @@ 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() {
|
|
497
435
|
return this._voltFingerprint;
|
|
498
436
|
}
|
|
499
437
|
|
|
438
|
+
get key() {
|
|
439
|
+
return this.getKey();
|
|
440
|
+
}
|
|
441
|
+
|
|
500
442
|
getKey() {
|
|
501
|
-
const key =
|
|
443
|
+
const key = keyFromPem$2(this._cryptoCache.key);
|
|
502
444
|
return key;
|
|
503
445
|
}
|
|
504
446
|
|
|
@@ -512,8 +454,8 @@ class VoltCredential {
|
|
|
512
454
|
return Promise.resolve(this.getKey());
|
|
513
455
|
} else {
|
|
514
456
|
log$5("creating key");
|
|
515
|
-
this._cryptoCache.key =
|
|
516
|
-
const key =
|
|
457
|
+
this._cryptoCache.key = JSON.parse(createSigningKey()).private_pem;
|
|
458
|
+
const key = keyFromPem$2(this._cryptoCache.key);
|
|
517
459
|
log$5("successfully created key");
|
|
518
460
|
return Promise.resolve(key);
|
|
519
461
|
}
|
|
@@ -550,9 +492,9 @@ class VoltCredential {
|
|
|
550
492
|
* @returns
|
|
551
493
|
*/
|
|
552
494
|
getIdentityMetadata(grpc, audience, publicKey, tunnelling = false, ttl = 60) {
|
|
553
|
-
const key =
|
|
495
|
+
const key = keyFromPem$2(this._cryptoCache.key);
|
|
554
496
|
|
|
555
|
-
const identityToken =
|
|
497
|
+
const identityToken = getIdentityToken(
|
|
556
498
|
this.sessionId,
|
|
557
499
|
key,
|
|
558
500
|
audience || this._voltConfig.id,
|
|
@@ -568,8 +510,8 @@ class VoltCredential {
|
|
|
568
510
|
const clone = { ...this._config, credential: { ...this._cryptoCache } };
|
|
569
511
|
if (this._config.p) {
|
|
570
512
|
// A passphrase option exists => encrypt the key before writing the cache file.
|
|
571
|
-
const key =
|
|
572
|
-
clone.credential.key =
|
|
513
|
+
const key = keyFromPem$2(this._cryptoCache.key);
|
|
514
|
+
clone.credential.key = privateKeyToPem(key.privateKey, this._config.p);
|
|
573
515
|
}
|
|
574
516
|
|
|
575
517
|
if (this._persistCache) {
|
|
@@ -708,6 +650,20 @@ var protoUtils = /*#__PURE__*/Object.freeze({
|
|
|
708
650
|
|
|
709
651
|
/* eslint-disable no-underscore-dangle */
|
|
710
652
|
|
|
653
|
+
const {
|
|
654
|
+
aesCreateKey,
|
|
655
|
+
aesEncrypt: aesEncrypt$1,
|
|
656
|
+
aesDecrypt: aesDecrypt$1,
|
|
657
|
+
toBase64,
|
|
658
|
+
formatPEM: formatPEM$1,
|
|
659
|
+
keyFromPem: keyFromPem$1,
|
|
660
|
+
verify,
|
|
661
|
+
deriveSharedKey: deriveSharedKey$1,
|
|
662
|
+
x25519: x25519$1
|
|
663
|
+
} = js.voltUtils;
|
|
664
|
+
|
|
665
|
+
const invokeMethod = "Invoke";
|
|
666
|
+
|
|
711
667
|
const log$4 = debug__default["default"]("volt-client-grpc:grpc-call");
|
|
712
668
|
|
|
713
669
|
function _prepareInvokeRequest(
|
|
@@ -719,10 +675,10 @@ function _prepareInvokeRequest(
|
|
|
719
675
|
this._service?.service_description.host_type ===
|
|
720
676
|
"SERVICE_HOST_TYPE_RELAYED";
|
|
721
677
|
|
|
722
|
-
const relaying = this._voltClient.
|
|
678
|
+
const relaying = this._voltClient.isRelayed || isServiceRelayed;
|
|
723
679
|
|
|
724
680
|
let targetDID = [];
|
|
725
|
-
if (this._voltClient.
|
|
681
|
+
if (this._voltClient.isRelayed) {
|
|
726
682
|
targetDID.push(this._voltClient.voltConfig.id);
|
|
727
683
|
}
|
|
728
684
|
|
|
@@ -747,20 +703,23 @@ function _prepareInvokeRequest(
|
|
|
747
703
|
let invokeRequest;
|
|
748
704
|
let callMethod = method;
|
|
749
705
|
|
|
706
|
+
const voltGrpcClient = this._voltClient.getVoltAPIClient();
|
|
707
|
+
|
|
750
708
|
if (relaying) {
|
|
751
709
|
//
|
|
752
710
|
// If the volt connection is via a relay (or the target service is relayed),
|
|
753
711
|
// we wrap the rpc in a RemoteRequest message and send it via a call to Invoke().
|
|
754
712
|
//
|
|
713
|
+
|
|
755
714
|
// Replace the target method with a call to Invoke on the relay Volt.
|
|
756
|
-
|
|
757
|
-
callMethod = "Invoke";
|
|
715
|
+
callMethod = invokeMethod;
|
|
758
716
|
|
|
759
717
|
// But first we need to perform a key exchange with the target service.
|
|
760
|
-
//
|
|
761
718
|
if (!this._encryptionKey) {
|
|
762
719
|
// We haven't exchanged keys yet, so queue the payload.
|
|
763
|
-
|
|
720
|
+
if (request) {
|
|
721
|
+
this._pendingRequests.push(request);
|
|
722
|
+
}
|
|
764
723
|
|
|
765
724
|
if (this._keyExchangePending) {
|
|
766
725
|
// We've already sent the key exchange request, so do nothing.
|
|
@@ -779,6 +738,13 @@ function _prepareInvokeRequest(
|
|
|
779
738
|
: undefined
|
|
780
739
|
};
|
|
781
740
|
|
|
741
|
+
if (this._voltClient.isRelayed) {
|
|
742
|
+
// When tunnelling, we serialise the request using the original serialisation
|
|
743
|
+
// method for Invoke.
|
|
744
|
+
invokeRequest =
|
|
745
|
+
voltGrpcClient.Invoke.requestSerializeOriginal(invokeRequest);
|
|
746
|
+
}
|
|
747
|
+
|
|
782
748
|
return {
|
|
783
749
|
request: invokeRequest,
|
|
784
750
|
method: callMethod,
|
|
@@ -789,41 +755,45 @@ function _prepareInvokeRequest(
|
|
|
789
755
|
|
|
790
756
|
let requestPayload;
|
|
791
757
|
|
|
792
|
-
// Serialise the rpc request.
|
|
758
|
+
// Serialise the rpc request using the original serialisation method.
|
|
793
759
|
if (request) {
|
|
794
|
-
|
|
760
|
+
if (this._voltClient.isRelayed) {
|
|
761
|
+
requestPayload =
|
|
762
|
+
this._grpcClient[method].requestSerializeOriginal(request);
|
|
763
|
+
} else {
|
|
764
|
+
requestPayload = this._grpcClient[method].requestSerialize(request);
|
|
765
|
+
}
|
|
795
766
|
} else if (request !== null) {
|
|
796
767
|
log$4("****************LOOKOUT****************** - empty request");
|
|
797
768
|
} else {
|
|
798
769
|
log$4("explicit empty request payload");
|
|
799
770
|
}
|
|
800
771
|
|
|
801
|
-
//
|
|
802
|
-
const
|
|
803
|
-
const tunnelMethod = voltGrpcClient.Tunnel;
|
|
804
|
-
|
|
805
|
-
const tunnelResp = {
|
|
772
|
+
// Create a tunnel message containing the method call metadata and request payload.
|
|
773
|
+
const tunnelResp = voltGrpcClient.Tunnel.responseSerialize({
|
|
806
774
|
method_invoke: {
|
|
807
775
|
method_name: this._grpcClient[method].path,
|
|
808
776
|
method_type: methodType,
|
|
809
777
|
request: requestPayload
|
|
810
778
|
}
|
|
811
|
-
};
|
|
812
|
-
|
|
813
|
-
let invokePayload;
|
|
814
|
-
const iv = voltClientWeb.aesCreateKey().iv;
|
|
779
|
+
});
|
|
815
780
|
|
|
816
781
|
// When sending via a relay we need to encrypt the payload.
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
iv,
|
|
820
|
-
tunnelMethod.responseSerialize(tunnelResp)
|
|
821
|
-
);
|
|
782
|
+
const iv = aesCreateKey().iv;
|
|
783
|
+
const invokePayload = aesEncrypt$1(this._encryptionKey, iv, tunnelResp);
|
|
822
784
|
|
|
785
|
+
// Construct the Invoke request.
|
|
823
786
|
invokeRequest = {
|
|
824
787
|
iv,
|
|
825
788
|
payload: invokePayload
|
|
826
789
|
};
|
|
790
|
+
|
|
791
|
+
if (this._voltClient.isRelayed) {
|
|
792
|
+
// When tunnelling, we serialise the request using the original serialisation
|
|
793
|
+
// method for Invoke.
|
|
794
|
+
invokeRequest =
|
|
795
|
+
voltGrpcClient.Invoke.requestSerializeOriginal(invokeRequest);
|
|
796
|
+
}
|
|
827
797
|
} else {
|
|
828
798
|
invokeRequest = request;
|
|
829
799
|
}
|
|
@@ -843,32 +813,45 @@ function _preparePayloadRequest(request, invokeInfo) {
|
|
|
843
813
|
this._service?.service_description.host_type ===
|
|
844
814
|
"SERVICE_HOST_TYPE_RELAYED";
|
|
845
815
|
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
816
|
+
if (this._voltClient.isRelayed || isServiceRelayed) {
|
|
817
|
+
let requestPayload;
|
|
818
|
+
if (this._voltClient.isRelayed) {
|
|
819
|
+
// Serialise the rpc request using the original serialisation method.
|
|
820
|
+
requestPayload =
|
|
821
|
+
this._grpcClient[invokeInfo.methodName].requestSerializeOriginal(
|
|
822
|
+
request
|
|
823
|
+
);
|
|
824
|
+
} else {
|
|
825
|
+
requestPayload =
|
|
826
|
+
this._grpcClient[invokeInfo.methodName].requestSerialize(request);
|
|
827
|
+
}
|
|
852
828
|
|
|
829
|
+
// Use the Tunnel method to serialise the relay request wrapper, this
|
|
853
830
|
const voltGrpcClient = this._voltClient.getVoltAPIClient();
|
|
854
|
-
const tunnelMethod = voltGrpcClient.Tunnel;
|
|
855
831
|
|
|
856
|
-
|
|
832
|
+
// Create a tunnel message containing the method call metadata and request payload.
|
|
833
|
+
const tunnelResp = voltGrpcClient.Tunnel.responseSerialize({
|
|
857
834
|
method_payload: {
|
|
858
835
|
payload: requestPayload
|
|
859
836
|
}
|
|
860
|
-
};
|
|
837
|
+
});
|
|
861
838
|
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
tunnelMethod.responseSerialize(tunnelResp)
|
|
866
|
-
);
|
|
839
|
+
// Encrypt the payload using the shared key.
|
|
840
|
+
const iv = aesCreateKey().iv;
|
|
841
|
+
const invokePayload = aesEncrypt$1(this._encryptionKey, iv, tunnelResp);
|
|
867
842
|
|
|
843
|
+
// We then serialise the entire request using the original serialisation method for Invoke.
|
|
868
844
|
payloadRequest = {
|
|
869
845
|
iv,
|
|
870
846
|
payload: invokePayload
|
|
871
847
|
};
|
|
848
|
+
|
|
849
|
+
if (this._voltClient.isRelayed) {
|
|
850
|
+
// When tunnelling, we serialise the request using the original serialisation
|
|
851
|
+
// method for Invoke.
|
|
852
|
+
payloadRequest =
|
|
853
|
+
voltGrpcClient.Invoke.requestSerializeOriginal(payloadRequest);
|
|
854
|
+
}
|
|
872
855
|
} else {
|
|
873
856
|
payloadRequest = request;
|
|
874
857
|
}
|
|
@@ -884,7 +867,14 @@ function _parseResponse(method, meta, response) {
|
|
|
884
867
|
this._service?.service_description.host_type ===
|
|
885
868
|
"SERVICE_HOST_TYPE_RELAYED";
|
|
886
869
|
|
|
887
|
-
|
|
870
|
+
const voltGrpcClient = this._voltClient.getVoltAPIClient();
|
|
871
|
+
|
|
872
|
+
if (this._voltClient.isRelayed || isServiceRelayed) {
|
|
873
|
+
if (this._voltClient.isRelayed) {
|
|
874
|
+
// Deserialise the incoming response using the original deserialisation method for Invoke.
|
|
875
|
+
response = voltGrpcClient.Invoke.responseDeserializeOriginal(response);
|
|
876
|
+
}
|
|
877
|
+
|
|
888
878
|
if (response.key_exchange) {
|
|
889
879
|
const encryptionKey = response.key_exchange.encryption_key;
|
|
890
880
|
const nonce = response.key_exchange.nonce;
|
|
@@ -896,24 +886,24 @@ function _parseResponse(method, meta, response) {
|
|
|
896
886
|
message.set(nonce, encryptionKey.length);
|
|
897
887
|
|
|
898
888
|
// Check the signature using the target service public key.
|
|
899
|
-
const targetKey =
|
|
889
|
+
const targetKey = keyFromPem$1(
|
|
900
890
|
this._service?.service_description?.host_public_key ||
|
|
901
891
|
this._voltClient.credential.voltPublicKey
|
|
902
892
|
).publicKey;
|
|
903
893
|
|
|
904
|
-
if (!
|
|
894
|
+
if (!verify(targetKey, message, signature)) {
|
|
905
895
|
throw new Error("signature verification failed");
|
|
906
896
|
}
|
|
907
897
|
|
|
908
898
|
invokeResponse = {
|
|
909
899
|
key_exchange: {
|
|
910
|
-
encryption_key:
|
|
900
|
+
encryption_key: formatPEM$1(toBase64(encryptionKey), "PUBLIC KEY")
|
|
911
901
|
}
|
|
912
902
|
};
|
|
913
903
|
} else if (response.payload) {
|
|
914
904
|
let decryptedPayload;
|
|
915
905
|
if (this._encryptionKey) {
|
|
916
|
-
decryptedPayload =
|
|
906
|
+
decryptedPayload = aesDecrypt$1(
|
|
917
907
|
this._encryptionKey,
|
|
918
908
|
response.iv,
|
|
919
909
|
response.payload
|
|
@@ -922,13 +912,24 @@ function _parseResponse(method, meta, response) {
|
|
|
922
912
|
decryptedPayload = response.payload;
|
|
923
913
|
}
|
|
924
914
|
|
|
925
|
-
|
|
926
|
-
const responsePayload =
|
|
915
|
+
// Deserialise the decrypted payload using the Tunnel deserialisation method.
|
|
916
|
+
const responsePayload =
|
|
917
|
+
voltGrpcClient.Tunnel.requestDeserialize(decryptedPayload);
|
|
927
918
|
if (responsePayload.payload === "method_payload") {
|
|
928
919
|
try {
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
920
|
+
// Deserialise the method payload.
|
|
921
|
+
if (this._voltClient.isRelayed) {
|
|
922
|
+
// Use the original deserialisation method for the target method.
|
|
923
|
+
invokeResponse.payload = this._grpcClient[
|
|
924
|
+
method
|
|
925
|
+
].responseDeserializeOriginal(
|
|
926
|
+
responsePayload.method_payload.payload
|
|
927
|
+
);
|
|
928
|
+
} else {
|
|
929
|
+
invokeResponse.payload = this._grpcClient[
|
|
930
|
+
method
|
|
931
|
+
].responseDeserialize(responsePayload.method_payload.payload);
|
|
932
|
+
}
|
|
932
933
|
} catch (err) {
|
|
933
934
|
log$4("failure deserialising payload for %s", this._methodName);
|
|
934
935
|
throw new Error(
|
|
@@ -956,16 +957,6 @@ function _parseResponse(method, meta, response) {
|
|
|
956
957
|
invokeResponse.methodId = response.invoke_id;
|
|
957
958
|
log$4("started method %d for %s", invokeResponse.methodId, method);
|
|
958
959
|
}
|
|
959
|
-
} else if (this._voltClient.isRemote && this._encryptionKey) {
|
|
960
|
-
const decryptedPayload = voltClientWeb.aesDecrypt(
|
|
961
|
-
this._encryptionKey,
|
|
962
|
-
meta.sharedKey.iv,
|
|
963
|
-
response
|
|
964
|
-
);
|
|
965
|
-
invokeResponse = {
|
|
966
|
-
payload:
|
|
967
|
-
this._grpcClient[method].responseDeserializeOriginal(decryptedPayload)
|
|
968
|
-
};
|
|
969
960
|
} else {
|
|
970
961
|
invokeResponse = { payload: response };
|
|
971
962
|
}
|
|
@@ -1005,7 +996,7 @@ class GRPCCall extends EventEmitter__default["default"] {
|
|
|
1005
996
|
"SERVICE_HOST_TYPE_RELAYED";
|
|
1006
997
|
|
|
1007
998
|
let callClient;
|
|
1008
|
-
if (this._voltClient.
|
|
999
|
+
if (this._voltClient.isRelayed || isServiceRelayed) {
|
|
1009
1000
|
callClient = this._voltClient.getVoltAPIClient();
|
|
1010
1001
|
} else {
|
|
1011
1002
|
callClient = this._grpcClient;
|
|
@@ -1024,14 +1015,14 @@ class GRPCCall extends EventEmitter__default["default"] {
|
|
|
1024
1015
|
streamResponse
|
|
1025
1016
|
);
|
|
1026
1017
|
if (parsedResponse.key_exchange) {
|
|
1027
|
-
const peerKey =
|
|
1018
|
+
const peerKey = keyFromPem$1(
|
|
1028
1019
|
parsedResponse.key_exchange.encryption_key
|
|
1029
1020
|
).publicKey;
|
|
1030
1021
|
|
|
1031
|
-
this._encryptionKey =
|
|
1022
|
+
this._encryptionKey = deriveSharedKey$1(
|
|
1032
1023
|
this._initialRequest.meta.sharedKey.key,
|
|
1033
1024
|
peerKey,
|
|
1034
|
-
|
|
1025
|
+
x25519$1
|
|
1035
1026
|
);
|
|
1036
1027
|
|
|
1037
1028
|
// We've exchanged keys, so send any queued payloads on the next tick.
|
|
@@ -1072,7 +1063,11 @@ class GRPCCall extends EventEmitter__default["default"] {
|
|
|
1072
1063
|
});
|
|
1073
1064
|
|
|
1074
1065
|
this._call.on("error", (err) => {
|
|
1075
|
-
log$4(
|
|
1066
|
+
log$4(
|
|
1067
|
+
"ERROR - intercepted stream error on %s: %s",
|
|
1068
|
+
this._methodName,
|
|
1069
|
+
err.message
|
|
1070
|
+
);
|
|
1076
1071
|
this.emit("error", err);
|
|
1077
1072
|
});
|
|
1078
1073
|
|
|
@@ -1108,6 +1103,16 @@ class GRPCCall extends EventEmitter__default["default"] {
|
|
|
1108
1103
|
}
|
|
1109
1104
|
}
|
|
1110
1105
|
|
|
1106
|
+
pause() {
|
|
1107
|
+
log$4("pausing call %s", this._methodName);
|
|
1108
|
+
return this._call?.pause();
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
resume() {
|
|
1112
|
+
log$4("resuming call %s", this._methodName);
|
|
1113
|
+
return this._call?.resume();
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1111
1116
|
get writable() {
|
|
1112
1117
|
return this._call?.writable;
|
|
1113
1118
|
}
|
|
@@ -1232,8 +1237,18 @@ function _doConnect(connectHello) {
|
|
|
1232
1237
|
break;
|
|
1233
1238
|
}
|
|
1234
1239
|
case "invoke_request": {
|
|
1235
|
-
log$3("received invoke request");
|
|
1236
|
-
|
|
1240
|
+
log$3("received invoke request %s", response.invoke_request.invoke_id);
|
|
1241
|
+
// Pause the call while we process the invoke request to avoid getting
|
|
1242
|
+
// CANCELLED errors from grpc - we should perhaps leave this to the
|
|
1243
|
+
// client to manage as it may be overkill in some cases.
|
|
1244
|
+
this.call.pause();
|
|
1245
|
+
try {
|
|
1246
|
+
this.emit("invoke_request", response.invoke_request);
|
|
1247
|
+
} catch (err) {
|
|
1248
|
+
log$3("error processing invoke request [%s]", err.message);
|
|
1249
|
+
} finally {
|
|
1250
|
+
this.call.resume();
|
|
1251
|
+
}
|
|
1237
1252
|
break;
|
|
1238
1253
|
}
|
|
1239
1254
|
case "evt": {
|
|
@@ -1305,6 +1320,10 @@ class VoltConnection extends EventEmitter__default["default"] {
|
|
|
1305
1320
|
this._helloPayload = undefined;
|
|
1306
1321
|
}
|
|
1307
1322
|
|
|
1323
|
+
get connectionId() {
|
|
1324
|
+
return this._connectionId;
|
|
1325
|
+
}
|
|
1326
|
+
|
|
1308
1327
|
connect(helloPayload, throwOnFail) {
|
|
1309
1328
|
this._helloPayload = helloPayload;
|
|
1310
1329
|
if (throwOnFail) {
|
|
@@ -1324,19 +1343,38 @@ class VoltConnection extends EventEmitter__default["default"] {
|
|
|
1324
1343
|
}
|
|
1325
1344
|
}
|
|
1326
1345
|
|
|
1327
|
-
const
|
|
1346
|
+
const {
|
|
1347
|
+
aesDecrypt,
|
|
1348
|
+
aesEncrypt,
|
|
1349
|
+
createEncryptionKey,
|
|
1350
|
+
deriveSharedKey,
|
|
1351
|
+
formatPEM,
|
|
1352
|
+
fromBase64,
|
|
1353
|
+
fromBase64Url,
|
|
1354
|
+
keyFromPem,
|
|
1355
|
+
publicKeyToPem: publicKeyToPem$1,
|
|
1356
|
+
randomBytes,
|
|
1357
|
+
signBase64: signBase64$1,
|
|
1358
|
+
stripPemHeaders,
|
|
1359
|
+
x25519
|
|
1360
|
+
} = js.voltUtils;
|
|
1361
|
+
|
|
1362
|
+
const log$2 = debug__default["default"]("volt-client-grpc:rpc-invocation");
|
|
1328
1363
|
|
|
1329
1364
|
class RpcInvocation extends EventEmitter__default["default"] {
|
|
1330
1365
|
#voltClient = null;
|
|
1331
1366
|
#voltConnection = null;
|
|
1332
1367
|
#token = null;
|
|
1368
|
+
#callerPublicKeyPem = null;
|
|
1333
1369
|
#invokeId = null;
|
|
1370
|
+
#serviceId = null;
|
|
1334
1371
|
#payload = null;
|
|
1335
1372
|
#isJSON = false;
|
|
1336
1373
|
#methodDescriptor = null;
|
|
1337
1374
|
#methodName = null;
|
|
1338
1375
|
#derivedKey = null;
|
|
1339
1376
|
#started = false;
|
|
1377
|
+
#endEmitted = false;
|
|
1340
1378
|
|
|
1341
1379
|
constructor(voltClient, voltConnection) {
|
|
1342
1380
|
super();
|
|
@@ -1348,6 +1386,18 @@ class RpcInvocation extends EventEmitter__default["default"] {
|
|
|
1348
1386
|
return this.#invokeId;
|
|
1349
1387
|
}
|
|
1350
1388
|
|
|
1389
|
+
get serviceId() {
|
|
1390
|
+
return this.#serviceId;
|
|
1391
|
+
}
|
|
1392
|
+
|
|
1393
|
+
get token() {
|
|
1394
|
+
return this.#token;
|
|
1395
|
+
}
|
|
1396
|
+
|
|
1397
|
+
get callerPublicKeyPem() {
|
|
1398
|
+
return this.#callerPublicKeyPem;
|
|
1399
|
+
}
|
|
1400
|
+
|
|
1351
1401
|
get payload() {
|
|
1352
1402
|
if (!this.#payload) {
|
|
1353
1403
|
return null;
|
|
@@ -1389,31 +1439,40 @@ class RpcInvocation extends EventEmitter__default["default"] {
|
|
|
1389
1439
|
// The rpc implementation should do the verification using the Volt API (e.g. CanAccessResource).
|
|
1390
1440
|
this.#token = jwt__default["default"].decode(token);
|
|
1391
1441
|
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1442
|
+
if (!this.#token) {
|
|
1443
|
+
log$2("failed to decode token %s", token || "null");
|
|
1444
|
+
return Promise.reject(new Error("failed to decode token"));
|
|
1445
|
+
}
|
|
1395
1446
|
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
const
|
|
1399
|
-
|
|
1447
|
+
// Store the JWT key id (kid) for use in the response.
|
|
1448
|
+
this.#callerPublicKeyPem = formatPEM(this.#token.k, "PUBLIC KEY");
|
|
1449
|
+
const callerKey = keyFromPem(
|
|
1450
|
+
this.#callerPublicKeyPem,
|
|
1451
|
+
"",
|
|
1452
|
+
x25519
|
|
1453
|
+
).publicKey;
|
|
1454
|
+
|
|
1455
|
+
const ephemeralKeyPem = createEncryptionKey();
|
|
1456
|
+
const ephemeralKey = keyFromPem(ephemeralKeyPem, "", x25519);
|
|
1457
|
+
const ephemeralPublicKey = fromBase64(
|
|
1458
|
+
stripPemHeaders(publicKeyToPem$1(ephemeralKey.publicKey, x25519))
|
|
1400
1459
|
);
|
|
1401
1460
|
|
|
1402
|
-
this.#derivedKey =
|
|
1461
|
+
this.#derivedKey = deriveSharedKey(
|
|
1403
1462
|
ephemeralKey.privateKey,
|
|
1404
1463
|
callerKey,
|
|
1405
|
-
|
|
1464
|
+
x25519
|
|
1406
1465
|
);
|
|
1407
1466
|
|
|
1408
|
-
const nonce =
|
|
1467
|
+
const nonce = randomBytes(16);
|
|
1409
1468
|
|
|
1410
1469
|
// The signed message is the encryption key and the nonce.
|
|
1411
1470
|
const message = new Uint8Array(ephemeralPublicKey.length + nonce.length);
|
|
1412
1471
|
message.set(ephemeralPublicKey);
|
|
1413
1472
|
message.set(nonce, ephemeralPublicKey.length);
|
|
1414
1473
|
|
|
1415
|
-
const signature =
|
|
1416
|
-
this.#voltClient.credential.
|
|
1474
|
+
const signature = signBase64$1(
|
|
1475
|
+
this.#voltClient.credential.cache.key,
|
|
1417
1476
|
message
|
|
1418
1477
|
);
|
|
1419
1478
|
|
|
@@ -1422,7 +1481,7 @@ class RpcInvocation extends EventEmitter__default["default"] {
|
|
|
1422
1481
|
key_exchange: {
|
|
1423
1482
|
nonce,
|
|
1424
1483
|
encryption_key: ephemeralPublicKey,
|
|
1425
|
-
signature:
|
|
1484
|
+
signature: fromBase64Url(signature)
|
|
1426
1485
|
}
|
|
1427
1486
|
};
|
|
1428
1487
|
|
|
@@ -1434,7 +1493,10 @@ class RpcInvocation extends EventEmitter__default["default"] {
|
|
|
1434
1493
|
}
|
|
1435
1494
|
|
|
1436
1495
|
initialise(invoke_request) {
|
|
1437
|
-
this.#invokeId
|
|
1496
|
+
if (!this.#invokeId) {
|
|
1497
|
+
this.#invokeId = invoke_request.invoke_id;
|
|
1498
|
+
this.#serviceId = invoke_request.target_service_id;
|
|
1499
|
+
}
|
|
1438
1500
|
|
|
1439
1501
|
if (!this.#derivedKey) {
|
|
1440
1502
|
// We don't have the derived key yet, so we need to perform the key exchange.
|
|
@@ -1456,10 +1518,9 @@ class RpcInvocation extends EventEmitter__default["default"] {
|
|
|
1456
1518
|
|
|
1457
1519
|
if (invoke_request.payload) {
|
|
1458
1520
|
let decryptedPayload;
|
|
1459
|
-
|
|
1460
|
-
if (encryptIV) {
|
|
1521
|
+
if (encryptIV?.length) {
|
|
1461
1522
|
// Decrypt the actual payload using the shared key and iv.
|
|
1462
|
-
decryptedPayload =
|
|
1523
|
+
decryptedPayload = aesDecrypt(
|
|
1463
1524
|
this.#derivedKey,
|
|
1464
1525
|
encryptIV,
|
|
1465
1526
|
invoke_request.payload
|
|
@@ -1500,7 +1561,7 @@ class RpcInvocation extends EventEmitter__default["default"] {
|
|
|
1500
1561
|
|
|
1501
1562
|
if (this.#derivedKey) {
|
|
1502
1563
|
// Decrypt the actual payload using the shared key and iv.
|
|
1503
|
-
decryptedPayload =
|
|
1564
|
+
decryptedPayload = aesDecrypt(
|
|
1504
1565
|
this.#derivedKey,
|
|
1505
1566
|
invoke_request.iv,
|
|
1506
1567
|
Buffer.from(invoke_request.json_payload, "base64")
|
|
@@ -1525,8 +1586,13 @@ class RpcInvocation extends EventEmitter__default["default"] {
|
|
|
1525
1586
|
);
|
|
1526
1587
|
this.emit("payload", this);
|
|
1527
1588
|
} else if (wrappedPayload.method_end) {
|
|
1528
|
-
// We don't need to do anything here, since we notify the client when we receive the client_end.
|
|
1529
1589
|
log$2("method_end received");
|
|
1590
|
+
if (!this.#endEmitted) {
|
|
1591
|
+
this.#endEmitted = true;
|
|
1592
|
+
this.emit("end", this);
|
|
1593
|
+
} else {
|
|
1594
|
+
log$2("method_end: end already emitted");
|
|
1595
|
+
}
|
|
1530
1596
|
}
|
|
1531
1597
|
} catch (err) {
|
|
1532
1598
|
log$2("JSON.parse failure parsing json_payload: %s", err.message);
|
|
@@ -1535,7 +1601,12 @@ class RpcInvocation extends EventEmitter__default["default"] {
|
|
|
1535
1601
|
|
|
1536
1602
|
resolve();
|
|
1537
1603
|
} else if (invoke_request.client_end) {
|
|
1538
|
-
|
|
1604
|
+
if (!this.#endEmitted) {
|
|
1605
|
+
this.#endEmitted = true;
|
|
1606
|
+
this.emit("end", this);
|
|
1607
|
+
} else {
|
|
1608
|
+
log$2("client_end: end already emitted");
|
|
1609
|
+
}
|
|
1539
1610
|
} else {
|
|
1540
1611
|
// Do we need to support json_payload here?
|
|
1541
1612
|
reject(new Error("No payload in invoke request"));
|
|
@@ -1562,10 +1633,10 @@ class RpcInvocation extends EventEmitter__default["default"] {
|
|
|
1562
1633
|
});
|
|
1563
1634
|
}
|
|
1564
1635
|
|
|
1565
|
-
const iv =
|
|
1636
|
+
const iv = randomBytes(16);
|
|
1566
1637
|
if (this.#derivedKey) {
|
|
1567
1638
|
// Encrypt the response using the shared key and iv.
|
|
1568
|
-
responsePayload =
|
|
1639
|
+
responsePayload = aesEncrypt(this.#derivedKey, iv, responsePayload);
|
|
1569
1640
|
}
|
|
1570
1641
|
|
|
1571
1642
|
const invokeResponse = {
|
|
@@ -1605,10 +1676,10 @@ class RpcInvocation extends EventEmitter__default["default"] {
|
|
|
1605
1676
|
endPayload = tunnelMethod.requestSerialize(endPayload);
|
|
1606
1677
|
}
|
|
1607
1678
|
|
|
1608
|
-
const iv =
|
|
1679
|
+
const iv = randomBytes(16);
|
|
1609
1680
|
if (this.#derivedKey) {
|
|
1610
1681
|
// Encrypt the response using the shared key and iv.
|
|
1611
|
-
endPayload =
|
|
1682
|
+
endPayload = aesEncrypt(this.#derivedKey, iv, endPayload);
|
|
1612
1683
|
}
|
|
1613
1684
|
|
|
1614
1685
|
const invokeResponse = {
|
|
@@ -1631,6 +1702,8 @@ class RpcInvocation extends EventEmitter__default["default"] {
|
|
|
1631
1702
|
|
|
1632
1703
|
/* eslint-disable no-underscore-dangle */
|
|
1633
1704
|
|
|
1705
|
+
const { publicKeyToPem, removeCarriageReturn, signBase64 } = js.voltUtils;
|
|
1706
|
+
|
|
1634
1707
|
const { filter, pick } = lodash__default["default"];
|
|
1635
1708
|
|
|
1636
1709
|
const log$1 = debug__default["default"]("volt-client-grpc:volt-client-internal");
|
|
@@ -1763,8 +1836,8 @@ async function authenticateInternal(
|
|
|
1763
1836
|
}
|
|
1764
1837
|
|
|
1765
1838
|
const keyPair = this._credential.getKey();
|
|
1766
|
-
const publicKeyPem =
|
|
1767
|
-
|
|
1839
|
+
const publicKeyPem = removeCarriageReturn(
|
|
1840
|
+
publicKeyToPem(keyPair.publicKey)
|
|
1768
1841
|
);
|
|
1769
1842
|
|
|
1770
1843
|
if (!this._credential.cache.bindIp) {
|
|
@@ -1782,8 +1855,8 @@ async function authenticateInternal(
|
|
|
1782
1855
|
};
|
|
1783
1856
|
|
|
1784
1857
|
if (this._voltConfig.challenge_code) {
|
|
1785
|
-
authenticateRequest.challenge =
|
|
1786
|
-
|
|
1858
|
+
authenticateRequest.challenge = signBase64(
|
|
1859
|
+
this._credential.cache.key,
|
|
1787
1860
|
this._voltConfig.challenge_code
|
|
1788
1861
|
);
|
|
1789
1862
|
} else {
|
|
@@ -1813,16 +1886,18 @@ async function authenticateInternal(
|
|
|
1813
1886
|
// This is because the DID document is signed and the signature
|
|
1814
1887
|
// is over the entire document.
|
|
1815
1888
|
const didDocument = {
|
|
1816
|
-
"@context":
|
|
1889
|
+
"@context": [
|
|
1890
|
+
"https://www.w3.org/ns/did/v1",
|
|
1891
|
+
"https://tdxvolt.com/ns/did/v1"
|
|
1892
|
+
],
|
|
1817
1893
|
authentication: [`${did}#key-1`],
|
|
1818
1894
|
controller: did,
|
|
1819
|
-
description: this._config.client_name,
|
|
1820
1895
|
id: did,
|
|
1821
1896
|
verificationMethod: [
|
|
1822
1897
|
{
|
|
1823
1898
|
id: `${did}#key-1`,
|
|
1824
1899
|
publicKeyPem: publicKeyPem,
|
|
1825
|
-
type: "
|
|
1900
|
+
type: "Ed25519Signature2018"
|
|
1826
1901
|
}
|
|
1827
1902
|
]
|
|
1828
1903
|
};
|
|
@@ -1832,8 +1907,8 @@ async function authenticateInternal(
|
|
|
1832
1907
|
|
|
1833
1908
|
// Now sign the entire DID document, including the proof and set it in the
|
|
1834
1909
|
// bind request. This is required by the Volt to verify that we have the private key for the DID.
|
|
1835
|
-
authenticateRequest.did_document_signature =
|
|
1836
|
-
|
|
1910
|
+
authenticateRequest.did_document_signature = signBase64(
|
|
1911
|
+
this._credential.cache.key,
|
|
1837
1912
|
authenticateRequest.did_document
|
|
1838
1913
|
);
|
|
1839
1914
|
|
|
@@ -1871,7 +1946,7 @@ async function authenticateInternal(
|
|
|
1871
1946
|
|
|
1872
1947
|
return decision === "POLICY_DECISION_PERMIT";
|
|
1873
1948
|
} catch (err) {
|
|
1874
|
-
log$1("failure
|
|
1949
|
+
log$1("failure authenticating with Volt [%s]", err.message);
|
|
1875
1950
|
throw err;
|
|
1876
1951
|
}
|
|
1877
1952
|
}
|
|
@@ -1887,15 +1962,7 @@ function connectInternal(helloPayload) {
|
|
|
1887
1962
|
this._connected = false;
|
|
1888
1963
|
this._session = null;
|
|
1889
1964
|
|
|
1890
|
-
|
|
1891
|
-
this._grpc.closeClient(this._cachedClient);
|
|
1892
|
-
this._cachedClient = null;
|
|
1893
|
-
}
|
|
1894
|
-
|
|
1895
|
-
if (this._cachedRemoteClient) {
|
|
1896
|
-
this._grpc.closeClient(this._cachedRemoteClient);
|
|
1897
|
-
this._cachedRemoteClient = null;
|
|
1898
|
-
}
|
|
1965
|
+
this.close();
|
|
1899
1966
|
};
|
|
1900
1967
|
|
|
1901
1968
|
this._voltConnection = new VoltConnection(this, this._grpc);
|
|
@@ -1984,7 +2051,7 @@ function connectInternal(helloPayload) {
|
|
|
1984
2051
|
|
|
1985
2052
|
function getVoltAPIClientInternal() {
|
|
1986
2053
|
if (!this._cachedClient) {
|
|
1987
|
-
const serviceAddress = this.
|
|
2054
|
+
const serviceAddress = this.isRelayed
|
|
1988
2055
|
? this._voltConfig.relay.address
|
|
1989
2056
|
: this._voltConfig.address;
|
|
1990
2057
|
log$1("creating cached VoltAPI service client on %s", serviceAddress);
|
|
@@ -1999,7 +2066,7 @@ function getVoltAPIClientInternal() {
|
|
|
1999
2066
|
serviceDescriptors,
|
|
2000
2067
|
serviceAddress,
|
|
2001
2068
|
this._credential,
|
|
2002
|
-
this.
|
|
2069
|
+
this.isRelayed,
|
|
2003
2070
|
this._voltConfig?.relay?.cloud ? this._voltConfig.id : "",
|
|
2004
2071
|
this._voltConfig?.relay?.cloud ? this._voltConfig.id : ""
|
|
2005
2072
|
);
|
|
@@ -2010,7 +2077,7 @@ function getVoltAPIClientInternal() {
|
|
|
2010
2077
|
|
|
2011
2078
|
function getAPIClientInternal(service) {
|
|
2012
2079
|
if (!this._cachedService[service.id]) {
|
|
2013
|
-
const serviceAddress = this.
|
|
2080
|
+
const serviceAddress = this.isRelayed
|
|
2014
2081
|
? this._voltConfig.relay.address
|
|
2015
2082
|
: service.service_description.host_address;
|
|
2016
2083
|
|
|
@@ -2033,7 +2100,7 @@ function getAPIClientInternal(service) {
|
|
|
2033
2100
|
serviceDescriptors,
|
|
2034
2101
|
serviceAddress,
|
|
2035
2102
|
this._credential,
|
|
2036
|
-
this.
|
|
2103
|
+
this.isRelayed,
|
|
2037
2104
|
this._voltConfig?.relay?.cloud ? this._voltConfig.id : "",
|
|
2038
2105
|
this._voltConfig?.relay?.cloud ? this._voltConfig.id : ""
|
|
2039
2106
|
);
|
|
@@ -2128,9 +2195,9 @@ async function fetchVoltConfig(discovery_url) {
|
|
|
2128
2195
|
}
|
|
2129
2196
|
}
|
|
2130
2197
|
|
|
2131
|
-
async function
|
|
2198
|
+
async function fetchVoltConfigFromDIDInternal(volt_did, registryUrl) {
|
|
2132
2199
|
try {
|
|
2133
|
-
const didResolution = getDIDResolutionURL(volt_did);
|
|
2200
|
+
const didResolution = getDIDResolutionURL(volt_did, registryUrl);
|
|
2134
2201
|
if (!didResolution) {
|
|
2135
2202
|
throw new Error(`Invalid Volt DID: ${volt_did}`);
|
|
2136
2203
|
}
|
|
@@ -2149,6 +2216,8 @@ async function fetchVoltConfigFromDID(volt_did) {
|
|
|
2149
2216
|
);
|
|
2150
2217
|
}
|
|
2151
2218
|
|
|
2219
|
+
log$1("resolved DID from %s", didResolution);
|
|
2220
|
+
|
|
2152
2221
|
const serviceEndpoint = voltConfigServices[0].serviceEndpoint;
|
|
2153
2222
|
return await fetchVoltConfig.call(this, serviceEndpoint);
|
|
2154
2223
|
} catch (err) {
|
|
@@ -2158,6 +2227,25 @@ async function fetchVoltConfigFromDID(volt_did) {
|
|
|
2158
2227
|
}
|
|
2159
2228
|
}
|
|
2160
2229
|
|
|
2230
|
+
async function fetchVoltConfigFromDID(
|
|
2231
|
+
volt_did,
|
|
2232
|
+
registryList = [constants.defaultDIDHostName]
|
|
2233
|
+
) {
|
|
2234
|
+
for (let registryUrl of registryList) {
|
|
2235
|
+
try {
|
|
2236
|
+
return await fetchVoltConfigFromDIDInternal.call(
|
|
2237
|
+
this,
|
|
2238
|
+
volt_did,
|
|
2239
|
+
registryUrl
|
|
2240
|
+
);
|
|
2241
|
+
} catch (err) {
|
|
2242
|
+
log$1("Failed to fetch Volt config from %s: %s", registryUrl, err.message);
|
|
2243
|
+
}
|
|
2244
|
+
}
|
|
2245
|
+
|
|
2246
|
+
throw new Error("Failed to fetch Volt config from any registry");
|
|
2247
|
+
}
|
|
2248
|
+
|
|
2161
2249
|
const { readFile } = fs__default["default"].promises;
|
|
2162
2250
|
const log = debug__default["default"]("volt-client-grpc:volt-client");
|
|
2163
2251
|
|
|
@@ -2173,7 +2261,6 @@ class VoltClient extends EventEmitter__default["default"] {
|
|
|
2173
2261
|
}
|
|
2174
2262
|
this._grpc = grpc;
|
|
2175
2263
|
this._cachedClient = null;
|
|
2176
|
-
this._cachedRemoteClient = null;
|
|
2177
2264
|
this._session = null;
|
|
2178
2265
|
this._config = null;
|
|
2179
2266
|
this._voltConfig = null;
|
|
@@ -2198,12 +2285,36 @@ class VoltClient extends EventEmitter__default["default"] {
|
|
|
2198
2285
|
return this._voltConfig;
|
|
2199
2286
|
}
|
|
2200
2287
|
|
|
2288
|
+
get connection() {
|
|
2289
|
+
return this._voltConnection;
|
|
2290
|
+
}
|
|
2291
|
+
|
|
2292
|
+
close() {
|
|
2293
|
+
if (this._cachedClient) {
|
|
2294
|
+
this._grpc.closeClient(this._cachedClient);
|
|
2295
|
+
this._cachedClient = null;
|
|
2296
|
+
}
|
|
2297
|
+
|
|
2298
|
+
for (let serviceKey in Object.keys(this._cachedService)) {
|
|
2299
|
+
if (this._cachedService[serviceKey]) {
|
|
2300
|
+
this._grpc.closeClient(this._cachedService[serviceKey]);
|
|
2301
|
+
}
|
|
2302
|
+
}
|
|
2303
|
+
|
|
2304
|
+
this._cachedService = {};
|
|
2305
|
+
}
|
|
2306
|
+
|
|
2201
2307
|
/**
|
|
2202
2308
|
* Initialises a binding and connection to the volt.
|
|
2203
2309
|
* @param {string} [config] - the location of the Volt configuration file, or a configuration object
|
|
2204
2310
|
* @param {object} [extras] - additional configuration properties
|
|
2205
2311
|
*/
|
|
2206
|
-
async initialise(
|
|
2312
|
+
async initialise(
|
|
2313
|
+
config,
|
|
2314
|
+
extras = {},
|
|
2315
|
+
ownDID = false,
|
|
2316
|
+
didRegistryList = undefined
|
|
2317
|
+
) {
|
|
2207
2318
|
try {
|
|
2208
2319
|
if (!config) {
|
|
2209
2320
|
throw new Error(
|
|
@@ -2268,7 +2379,15 @@ class VoltClient extends EventEmitter__default["default"] {
|
|
|
2268
2379
|
}
|
|
2269
2380
|
|
|
2270
2381
|
if (voltDID) {
|
|
2271
|
-
const didConfig = await fetchVoltConfigFromDID.call(
|
|
2382
|
+
const didConfig = await fetchVoltConfigFromDID.call(
|
|
2383
|
+
this,
|
|
2384
|
+
voltDID,
|
|
2385
|
+
didRegistryList
|
|
2386
|
+
);
|
|
2387
|
+
|
|
2388
|
+
// Remove the relay list from the DID config, as it would overwrite the relay in the supplied config.
|
|
2389
|
+
delete didConfig.relay;
|
|
2390
|
+
|
|
2272
2391
|
this._config = { ...this._config, volt: didConfig };
|
|
2273
2392
|
log("resolved config from DID: %s", JSON.stringify(didConfig, null, 2));
|
|
2274
2393
|
} else if (voltHttpAddress && !this._config?.volt?.id) {
|
|
@@ -2298,7 +2417,7 @@ class VoltClient extends EventEmitter__default["default"] {
|
|
|
2298
2417
|
|
|
2299
2418
|
await this._credential.initialise();
|
|
2300
2419
|
|
|
2301
|
-
if (!this.
|
|
2420
|
+
if (!this.isRelayed) {
|
|
2302
2421
|
// If we're not connecting via a Relay, we must have the address and CA.
|
|
2303
2422
|
if (
|
|
2304
2423
|
!this._voltConfig.address ||
|
|
@@ -2321,7 +2440,7 @@ class VoltClient extends EventEmitter__default["default"] {
|
|
|
2321
2440
|
} else {
|
|
2322
2441
|
// No certificate present in the cache yet => we need to authenticate.
|
|
2323
2442
|
try {
|
|
2324
|
-
isBound = await authenticateInternal.call(this);
|
|
2443
|
+
isBound = await authenticateInternal.call(this, false, ownDID);
|
|
2325
2444
|
} catch (bindErr) {
|
|
2326
2445
|
if (bindErr.message === "invalid arguments") {
|
|
2327
2446
|
// This is usually the result of a missing challenge signature or credential.
|
|
@@ -2338,7 +2457,7 @@ class VoltClient extends EventEmitter__default["default"] {
|
|
|
2338
2457
|
throw new Error("Volt authentication failed");
|
|
2339
2458
|
} else {
|
|
2340
2459
|
// Perist the configuration.
|
|
2341
|
-
this.
|
|
2460
|
+
this._credential.saveCache();
|
|
2342
2461
|
}
|
|
2343
2462
|
|
|
2344
2463
|
return Promise.resolve(this._config);
|
|
@@ -2389,7 +2508,7 @@ class VoltClient extends EventEmitter__default["default"] {
|
|
|
2389
2508
|
});
|
|
2390
2509
|
}
|
|
2391
2510
|
|
|
2392
|
-
if (this.
|
|
2511
|
+
if (this.isRelayed) {
|
|
2393
2512
|
if (!this._voltConfig?.relay?.address) {
|
|
2394
2513
|
throw new Error(
|
|
2395
2514
|
"Remote connection enabled but no Relay address - have you called start()?"
|
|
@@ -2416,14 +2535,10 @@ class VoltClient extends EventEmitter__default["default"] {
|
|
|
2416
2535
|
}
|
|
2417
2536
|
}
|
|
2418
2537
|
|
|
2419
|
-
get
|
|
2538
|
+
get isRelayed() {
|
|
2420
2539
|
return !!(this._voltConfig?.relay && this._voltConfig.id);
|
|
2421
2540
|
}
|
|
2422
2541
|
|
|
2423
|
-
get isVoltRelay() {
|
|
2424
|
-
return this.isRemote && !this._voltConfig?.relay.cloud;
|
|
2425
|
-
}
|
|
2426
|
-
|
|
2427
2542
|
connect(helloPayload) {
|
|
2428
2543
|
return connectInternal.call(this, helloPayload);
|
|
2429
2544
|
}
|
|
@@ -2753,6 +2868,9 @@ class VoltClient extends EventEmitter__default["default"] {
|
|
|
2753
2868
|
*/
|
|
2754
2869
|
SqlExecuteJSON(request) {
|
|
2755
2870
|
return new Promise((resolve, reject) => {
|
|
2871
|
+
if (!request.start) {
|
|
2872
|
+
request = { start: request };
|
|
2873
|
+
}
|
|
2756
2874
|
const call = this.SqlExecute(request);
|
|
2757
2875
|
|
|
2758
2876
|
let header;
|