@tdxvolt/volt-client-grpc 0.14.61 → 0.15.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/lib/index.cjs +785 -224
- package/package.json +1 -1
- package/protobuf/tdx/volt_api/volt/v1/file_api.proto +1 -1
- package/protobuf/tdx/volt_api/volt/v1/volt_api.proto +2 -0
- package/protobuf/tdx/volt_api/volt/v1/wire_api.proto +1 -1
- package/src/grpc-call.js +110 -49
- package/src/grpc-utils.js +9 -9
- package/src/proto-utils.js +37 -5
- package/src/rpc-invocation.js +277 -0
- package/src/utils.js +43 -2
- package/src/volt-client-internal.js +155 -58
- package/src/volt-client.js +95 -46
- package/src/volt-connection.js +16 -5
- package/src/volt-credential.js +32 -26
package/lib/index.cjs
CHANGED
|
@@ -114,7 +114,7 @@ const createSecureContextOptions = (cryptoOptions) => {
|
|
|
114
114
|
const tlsOptions = {
|
|
115
115
|
cert: Buffer.from(cryptoOptions.cert),
|
|
116
116
|
ca: Buffer.from(cryptoOptions.ca),
|
|
117
|
-
key: Buffer.from(cryptoOptions.key)
|
|
117
|
+
key: Buffer.from(cryptoOptions.key)
|
|
118
118
|
};
|
|
119
119
|
return tlsOptions;
|
|
120
120
|
};
|
|
@@ -130,7 +130,7 @@ const getServiceAddress = (mdnsService) => {
|
|
|
130
130
|
const ipv4 = lodash__default["default"].find(mdnsService.addresses, (addy) => ip__default["default"].isV4Format(addy));
|
|
131
131
|
const serviceDetails = {
|
|
132
132
|
host: ipv4,
|
|
133
|
-
port: mdnsService.port
|
|
133
|
+
port: mdnsService.port
|
|
134
134
|
};
|
|
135
135
|
|
|
136
136
|
address = `${serviceDetails.host}:${serviceDetails.port}`;
|
|
@@ -207,6 +207,47 @@ const getDIDResolutionURL = (didIn) => {
|
|
|
207
207
|
return `https://${hostName}/api/identity/${didGUID}`;
|
|
208
208
|
};
|
|
209
209
|
|
|
210
|
+
const forgePrivateKeyToPem = (decryptedKey) => {
|
|
211
|
+
// Convert a Forge private key to an ASN.1 RSAPrivateKey
|
|
212
|
+
const asnPrivateKey = pki$2.privateKeyToAsn1(decryptedKey);
|
|
213
|
+
|
|
214
|
+
// Wrap an RSAPrivateKey ASN.1 object in a PKCS#8 ASN.1 PrivateKeyInfo
|
|
215
|
+
const privateKeyInfo = pki$2.wrapRsaPrivateKey(asnPrivateKey);
|
|
216
|
+
|
|
217
|
+
// Convert a PKCS#8 ASN.1 PrivateKeyInfo to PEM
|
|
218
|
+
return pki$2.privateKeyInfoToPem(privateKeyInfo);
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
const createRSAKey = (passphrase = "") => {
|
|
222
|
+
return new Promise((resolve, reject) => {
|
|
223
|
+
pki$2.rsa.generateKeyPair({ bits: 2048, workers: -1 }, (err, keypair) => {
|
|
224
|
+
if (err) {
|
|
225
|
+
reject(err);
|
|
226
|
+
} else {
|
|
227
|
+
let pem;
|
|
228
|
+
if (passphrase) {
|
|
229
|
+
pem = pki$2.encryptRsaPrivateKey(keypair.privateKey, passphrase);
|
|
230
|
+
} else {
|
|
231
|
+
pem = forgePrivateKeyToPem(keypair.privateKey);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
resolve({ keypair, pem });
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
});
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
const sha256Base64 = (msg) => {
|
|
241
|
+
const md = forge__default["default"].md.sha256.create();
|
|
242
|
+
md.update(msg);
|
|
243
|
+
return forge__default["default"].util.encode64(md.digest().bytes());
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
const decryptPrivateKey = (pem, passphrase) => {
|
|
247
|
+
const decryptedKey = pki$2.decryptRsaPrivateKey(pem, passphrase);
|
|
248
|
+
return forgePrivateKeyToPem(decryptedKey);
|
|
249
|
+
};
|
|
250
|
+
|
|
210
251
|
var utils = /*#__PURE__*/Object.freeze({
|
|
211
252
|
__proto__: null,
|
|
212
253
|
createSecureContextOptions: createSecureContextOptions,
|
|
@@ -219,7 +260,10 @@ var utils = /*#__PURE__*/Object.freeze({
|
|
|
219
260
|
createPublicKeyFingerprint: createPublicKeyFingerprint,
|
|
220
261
|
signBase64: signBase64,
|
|
221
262
|
verifyBase64: verifyBase64,
|
|
222
|
-
getDIDResolutionURL: getDIDResolutionURL
|
|
263
|
+
getDIDResolutionURL: getDIDResolutionURL,
|
|
264
|
+
createRSAKey: createRSAKey,
|
|
265
|
+
sha256Base64: sha256Base64,
|
|
266
|
+
decryptPrivateKey: decryptPrivateKey
|
|
223
267
|
});
|
|
224
268
|
|
|
225
269
|
/* eslint-disable no-underscore-dangle */
|
|
@@ -237,7 +281,7 @@ function createClient(
|
|
|
237
281
|
credentials,
|
|
238
282
|
noSerialise,
|
|
239
283
|
voltId,
|
|
240
|
-
serviceId
|
|
284
|
+
serviceId
|
|
241
285
|
) {
|
|
242
286
|
let grpcCredentials;
|
|
243
287
|
if (credentials) {
|
|
@@ -251,7 +295,7 @@ function createClient(
|
|
|
251
295
|
grpcCredentials = grpc.credentials.createSsl(
|
|
252
296
|
tlsOptions.ca,
|
|
253
297
|
tlsOptions.key,
|
|
254
|
-
tlsOptions.cert
|
|
298
|
+
tlsOptions.cert
|
|
255
299
|
);
|
|
256
300
|
} else {
|
|
257
301
|
// Cache has no private key, this implies we are connecting without supplying a client certificate.
|
|
@@ -313,7 +357,7 @@ const grpcWrap = (api) => {
|
|
|
313
357
|
// Support class instances and PoJos
|
|
314
358
|
const isClass = api.constructor !== Object;
|
|
315
359
|
const iterate = Object.getOwnPropertyNames(
|
|
316
|
-
isClass ? api.constructor.prototype : api
|
|
360
|
+
isClass ? api.constructor.prototype : api
|
|
317
361
|
);
|
|
318
362
|
|
|
319
363
|
// Wrap each method on the api.
|
|
@@ -327,7 +371,7 @@ const grpcWrap = (api) => {
|
|
|
327
371
|
// Enforce promise results.
|
|
328
372
|
if (!(resultPromise?.then && resultPromise?.catch)) {
|
|
329
373
|
throw new Error(
|
|
330
|
-
`implementation methods must return a Promise [${name}]
|
|
374
|
+
`implementation methods must return a Promise [${name}]`
|
|
331
375
|
);
|
|
332
376
|
}
|
|
333
377
|
|
|
@@ -364,7 +408,7 @@ class GrpcServer {
|
|
|
364
408
|
"grpc.http2.max_pings_without_data": 0,
|
|
365
409
|
"grpc.keepalive_permit_without_calls": 1,
|
|
366
410
|
"grpc.http2.min_ping_interval_without_data_ms": 250,
|
|
367
|
-
"grpc.http2.max_ping_strikes": 0
|
|
411
|
+
"grpc.http2.max_ping_strikes": 0
|
|
368
412
|
});
|
|
369
413
|
|
|
370
414
|
if (tlsOptions) {
|
|
@@ -374,7 +418,7 @@ class GrpcServer {
|
|
|
374
418
|
caList.push(tlsOption.ca);
|
|
375
419
|
certChains.push({
|
|
376
420
|
private_key: tlsOption.key,
|
|
377
|
-
cert_chain: tlsOption.cert
|
|
421
|
+
cert_chain: tlsOption.cert
|
|
378
422
|
});
|
|
379
423
|
});
|
|
380
424
|
|
|
@@ -385,7 +429,7 @@ class GrpcServer {
|
|
|
385
429
|
// The certificate chain(s) we present to the client.
|
|
386
430
|
certChains,
|
|
387
431
|
// Flag indicating if we insist on a client certificate.
|
|
388
|
-
requireClientCert
|
|
432
|
+
requireClientCert
|
|
389
433
|
);
|
|
390
434
|
} else {
|
|
391
435
|
this._credentials = grpc.ServerCredentials.createInsecure();
|
|
@@ -437,7 +481,7 @@ function createServer(
|
|
|
437
481
|
serviceDescriptors,
|
|
438
482
|
routes,
|
|
439
483
|
cryptoCache,
|
|
440
|
-
requireClientCert
|
|
484
|
+
requireClientCert
|
|
441
485
|
) {
|
|
442
486
|
let tlsOptions;
|
|
443
487
|
if (cryptoCache) {
|
|
@@ -448,7 +492,7 @@ function createServer(
|
|
|
448
492
|
serviceDescriptors,
|
|
449
493
|
routes,
|
|
450
494
|
tlsOptions,
|
|
451
|
-
requireClientCert
|
|
495
|
+
requireClientCert
|
|
452
496
|
};
|
|
453
497
|
return new GrpcServer(serverArgs);
|
|
454
498
|
}
|
|
@@ -462,7 +506,7 @@ var grpcUtils = /*#__PURE__*/Object.freeze({
|
|
|
462
506
|
/* eslint-disable no-underscore-dangle */
|
|
463
507
|
|
|
464
508
|
const { pki: pki$1 } = forge__default["default"];
|
|
465
|
-
const log$
|
|
509
|
+
const log$5 = debug__default["default"]("volt-client-grpc:volt-credential");
|
|
466
510
|
const aesAlgorithm = "aes-256-cbc";
|
|
467
511
|
const rs256Algorithm = "RS256";
|
|
468
512
|
|
|
@@ -490,7 +534,7 @@ class VoltCredential {
|
|
|
490
534
|
// Need to unencrypt the private key.
|
|
491
535
|
const decrypted = pki$1.decryptRsaPrivateKey(
|
|
492
536
|
this._cryptoCache.key,
|
|
493
|
-
config.p
|
|
537
|
+
config.p
|
|
494
538
|
);
|
|
495
539
|
if (!decrypted) {
|
|
496
540
|
throw new Error("failed to decrypt key - check passphrase");
|
|
@@ -510,7 +554,7 @@ class VoltCredential {
|
|
|
510
554
|
// Extract Volt public key (used for encrypting Relay payloads).
|
|
511
555
|
this._voltPublicKey = forge__default["default"].pki.publicKeyToPem(voltCert.publicKey);
|
|
512
556
|
this._voltFingerprint = createPublicKeyFingerprint(
|
|
513
|
-
this._voltPublicKey
|
|
557
|
+
this._voltPublicKey
|
|
514
558
|
);
|
|
515
559
|
}
|
|
516
560
|
}
|
|
@@ -527,6 +571,10 @@ class VoltCredential {
|
|
|
527
571
|
return this._cryptoCache.client_id;
|
|
528
572
|
}
|
|
529
573
|
|
|
574
|
+
get voltPublicKey() {
|
|
575
|
+
return this._voltPublicKey;
|
|
576
|
+
}
|
|
577
|
+
|
|
530
578
|
get publicKey() {
|
|
531
579
|
return pki$1.publicKeyToPem(this.getKey().publicKey);
|
|
532
580
|
}
|
|
@@ -547,23 +595,20 @@ class VoltCredential {
|
|
|
547
595
|
createKey() {
|
|
548
596
|
if (this._cryptoCache.key) {
|
|
549
597
|
// Already have key data in the cache in pem format => create fully-formed pki instances.
|
|
550
|
-
log$
|
|
598
|
+
log$5("createKey - key already exists");
|
|
551
599
|
return Promise.resolve(this.getKey());
|
|
552
600
|
} else {
|
|
553
|
-
log$
|
|
554
|
-
return
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
resolve(keypair);
|
|
564
|
-
}
|
|
601
|
+
log$5("creating key");
|
|
602
|
+
return createRSAKey()
|
|
603
|
+
.then((keyInfo) => {
|
|
604
|
+
log$5("successfully created key");
|
|
605
|
+
this._cryptoCache.key = keyInfo.pem;
|
|
606
|
+
return keyInfo.keypair;
|
|
607
|
+
})
|
|
608
|
+
.catch((err) => {
|
|
609
|
+
log$5("failure creating key [%s]", err.message);
|
|
610
|
+
return Promise.reject(err);
|
|
565
611
|
});
|
|
566
|
-
});
|
|
567
612
|
}
|
|
568
613
|
}
|
|
569
614
|
|
|
@@ -579,7 +624,7 @@ class VoltCredential {
|
|
|
579
624
|
return this._cryptoCache;
|
|
580
625
|
})
|
|
581
626
|
.catch((err) => {
|
|
582
|
-
log$
|
|
627
|
+
log$5("failure initialising crypto [%s]", err.message);
|
|
583
628
|
return Promise.reject(err);
|
|
584
629
|
});
|
|
585
630
|
}
|
|
@@ -594,7 +639,7 @@ class VoltCredential {
|
|
|
594
639
|
* @param {*} tunnelling flag indicating if the token is required for a tunnelled connection
|
|
595
640
|
* @param {*} ttl time to live in seconds (default to 1 minute)
|
|
596
641
|
*/
|
|
597
|
-
getIdentityToken(audience, tunnelling = false, ttl = 60) {
|
|
642
|
+
getIdentityToken(audience, publicKey, tunnelling = false, ttl = 60) {
|
|
598
643
|
if (!this._cryptoCache.key) {
|
|
599
644
|
throw new Error("crypto cache invalid");
|
|
600
645
|
}
|
|
@@ -603,7 +648,7 @@ class VoltCredential {
|
|
|
603
648
|
const publicKeyPem = pki$1.publicKeyToPem(keyPair.publicKey);
|
|
604
649
|
const base58Key = createPublicKeyFingerprint(publicKeyPem);
|
|
605
650
|
|
|
606
|
-
log$
|
|
651
|
+
log$5("base58 key is %s", base58Key);
|
|
607
652
|
|
|
608
653
|
// Allow TTL either side of the current time.
|
|
609
654
|
// @todo - fix with server time sync on volt connection.
|
|
@@ -611,7 +656,7 @@ class VoltCredential {
|
|
|
611
656
|
aud: audience,
|
|
612
657
|
iat: Math.floor(Date.now() / 1000) - ttl,
|
|
613
658
|
exp: Math.floor(Date.now() / 1000) + ttl,
|
|
614
|
-
sub: this._cryptoCache.client_id
|
|
659
|
+
sub: this._cryptoCache.client_id
|
|
615
660
|
};
|
|
616
661
|
|
|
617
662
|
let sharedKey;
|
|
@@ -620,23 +665,20 @@ class VoltCredential {
|
|
|
620
665
|
sharedKey = VoltCredential.aesCreateKey();
|
|
621
666
|
|
|
622
667
|
// Encrypt the key details using the target Volt public key and include this in the JWT payload.
|
|
623
|
-
payload.sk = VoltCredential.rsaEncrypt(
|
|
624
|
-
|
|
625
|
-
sharedKey.key,
|
|
626
|
-
);
|
|
627
|
-
payload.iv = VoltCredential.rsaEncrypt(this._voltPublicKey, sharedKey.iv);
|
|
668
|
+
payload.sk = VoltCredential.rsaEncrypt(publicKey, sharedKey.key);
|
|
669
|
+
payload.iv = VoltCredential.rsaEncrypt(publicKey, sharedKey.iv);
|
|
628
670
|
}
|
|
629
671
|
|
|
630
672
|
// Sign synchronously.
|
|
631
673
|
const token = jwt__default["default"].sign(payload, this._cryptoCache.key, {
|
|
632
674
|
algorithm: rs256Algorithm,
|
|
633
|
-
keyid: base58Key
|
|
675
|
+
keyid: base58Key
|
|
634
676
|
});
|
|
635
677
|
|
|
636
678
|
// Return the token along with any encryption key details.
|
|
637
679
|
return {
|
|
638
680
|
token,
|
|
639
|
-
sharedKey
|
|
681
|
+
sharedKey
|
|
640
682
|
};
|
|
641
683
|
}
|
|
642
684
|
|
|
@@ -649,11 +691,12 @@ class VoltCredential {
|
|
|
649
691
|
* @param {*} ttl
|
|
650
692
|
* @returns
|
|
651
693
|
*/
|
|
652
|
-
getIdentityMetadata(grpc, audience, tunnelling = false, ttl = 60) {
|
|
694
|
+
getIdentityMetadata(grpc, audience, publicKey, tunnelling = false, ttl = 60) {
|
|
653
695
|
const identityToken = this.getIdentityToken(
|
|
654
696
|
audience || this._voltConfig.id,
|
|
697
|
+
publicKey,
|
|
655
698
|
tunnelling,
|
|
656
|
-
ttl
|
|
699
|
+
ttl
|
|
657
700
|
);
|
|
658
701
|
const metadata = new grpc.Metadata();
|
|
659
702
|
metadata.add(constants.authTokenName, identityToken.token);
|
|
@@ -668,7 +711,7 @@ class VoltCredential {
|
|
|
668
711
|
const privateKey = pki$1.privateKeyFromPem(this._cryptoCache.key);
|
|
669
712
|
clone.credential.key = pki$1.encryptRsaPrivateKey(
|
|
670
713
|
privateKey,
|
|
671
|
-
this._config.p
|
|
714
|
+
this._config.p
|
|
672
715
|
);
|
|
673
716
|
}
|
|
674
717
|
fs__default["default"].writeFileSync(this._configPath, JSON.stringify(clone, null, 2));
|
|
@@ -697,6 +740,12 @@ class VoltCredential {
|
|
|
697
740
|
static rsaEncrypt(key, buffer) {
|
|
698
741
|
return crypto__default["default"].publicEncrypt(key, buffer).toString("base64");
|
|
699
742
|
}
|
|
743
|
+
|
|
744
|
+
static rsaDecrypt(key, buffer) {
|
|
745
|
+
const keyObj = crypto__default["default"].createPrivateKey(key);
|
|
746
|
+
const cipher = Buffer.from(buffer, "base64");
|
|
747
|
+
return Buffer.from(crypto__default["default"].privateDecrypt(keyObj, cipher));
|
|
748
|
+
}
|
|
700
749
|
}
|
|
701
750
|
|
|
702
751
|
const { get: getProp, snakeCase } = lodash__default["default"];
|
|
@@ -713,23 +762,23 @@ const defaultLoaderOptions = {
|
|
|
713
762
|
includeDirs: [defaultProtoPath],
|
|
714
763
|
};
|
|
715
764
|
|
|
716
|
-
|
|
765
|
+
function getProtoDescriptors(grpc, protoPath, opts) {
|
|
717
766
|
const definition = protoLoader__default["default"].loadSync(
|
|
718
767
|
protoPath,
|
|
719
768
|
opts || defaultLoaderOptions,
|
|
720
769
|
);
|
|
721
770
|
const descriptors = grpc.loadPackageDefinition(definition);
|
|
722
771
|
return descriptors;
|
|
723
|
-
}
|
|
772
|
+
}
|
|
724
773
|
|
|
725
|
-
|
|
774
|
+
function getProtoService(descriptors, servicePath) {
|
|
726
775
|
const serviceDef = getProp(descriptors, servicePath);
|
|
727
776
|
if (serviceDef?.service) {
|
|
728
777
|
return serviceDef.service;
|
|
729
778
|
} else {
|
|
730
779
|
return null;
|
|
731
780
|
}
|
|
732
|
-
}
|
|
781
|
+
}
|
|
733
782
|
|
|
734
783
|
function getServiceDescriptorsFromPath(
|
|
735
784
|
grpc,
|
|
@@ -737,8 +786,30 @@ function getServiceDescriptorsFromPath(
|
|
|
737
786
|
servicePackageName,
|
|
738
787
|
opts,
|
|
739
788
|
) {
|
|
789
|
+
if (!opts) {
|
|
790
|
+
opts = { ...defaultLoaderOptions };
|
|
791
|
+
opts.includeDirs = [protoPath];
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
// Extract the package components of the service proto package. The package name should be of the
|
|
795
|
+
// fully qualified proto path, e.g. tdx.volt_api.webcam.v1.WebcamControlAPI.
|
|
796
|
+
const protoServiceComponents = servicePackageName.split(".");
|
|
797
|
+
|
|
798
|
+
// The service name is the last component of the path.
|
|
799
|
+
const protoServiceName = protoServiceComponents.pop();
|
|
800
|
+
|
|
801
|
+
// The actual file name should match the snake case of the service name.
|
|
802
|
+
const protoFileName = `${snakeCase(protoServiceName).toLowerCase()}.proto`;
|
|
803
|
+
|
|
804
|
+
// The path to the proto file should match each component of the package name.
|
|
805
|
+
const serviceProtoPath = path.join(
|
|
806
|
+
protoPath,
|
|
807
|
+
...protoServiceComponents,
|
|
808
|
+
protoFileName,
|
|
809
|
+
);
|
|
810
|
+
|
|
740
811
|
let serviceDescriptors;
|
|
741
|
-
const descriptors = getProtoDescriptors(grpc,
|
|
812
|
+
const descriptors = getProtoDescriptors(grpc, serviceProtoPath, opts);
|
|
742
813
|
if (descriptors) {
|
|
743
814
|
serviceDescriptors = getProtoService(descriptors, servicePackageName);
|
|
744
815
|
}
|
|
@@ -786,8 +857,17 @@ function getProtoDescriptorMethods(protoDescriptor) {
|
|
|
786
857
|
return methods;
|
|
787
858
|
}
|
|
788
859
|
|
|
860
|
+
function createServiceProtobufFiles(service, protoPath) {
|
|
861
|
+
for (let protoFile of service.service_description.proto_file) {
|
|
862
|
+
const filePath = path.join(protoPath, protoFile.file_path);
|
|
863
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
864
|
+
fs.writeFileSync(filePath, protoFile.protobuf);
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
|
|
789
868
|
var protoUtils = /*#__PURE__*/Object.freeze({
|
|
790
869
|
__proto__: null,
|
|
870
|
+
createServiceProtobufFiles: createServiceProtobufFiles,
|
|
791
871
|
getServiceDescriptors: getServiceDescriptors,
|
|
792
872
|
getProtoDescriptors: getProtoDescriptors,
|
|
793
873
|
getProtoDescriptorMethods: getProtoDescriptorMethods,
|
|
@@ -796,70 +876,101 @@ var protoUtils = /*#__PURE__*/Object.freeze({
|
|
|
796
876
|
|
|
797
877
|
/* eslint-disable no-underscore-dangle */
|
|
798
878
|
|
|
799
|
-
const log$
|
|
879
|
+
const log$4 = debug__default["default"]("volt-client-grpc:grpc-call");
|
|
800
880
|
|
|
801
881
|
function _prepareInvokeRequest(
|
|
802
882
|
request,
|
|
803
883
|
method,
|
|
804
884
|
methodType = "METHOD_TYPE_UNARY",
|
|
805
885
|
) {
|
|
806
|
-
const
|
|
886
|
+
const isServiceRelayed =
|
|
887
|
+
this._service?.service_description.host_type ===
|
|
888
|
+
"SERVICE_HOST_TYPE_RELAYED";
|
|
889
|
+
|
|
890
|
+
// Use the service's host client id and public key if the service is relayed.
|
|
891
|
+
const methodToken = this._voltClient.credential.getIdentityMetadata(
|
|
807
892
|
this._voltClient.grpc,
|
|
808
|
-
this.
|
|
809
|
-
|
|
893
|
+
this._service?.service_description.host_client_id ||
|
|
894
|
+
this._voltClient.voltConfig.id,
|
|
895
|
+
this._service?.service_description.host_public_key ||
|
|
896
|
+
this._voltClient.credential.voltPublicKey,
|
|
897
|
+
true,
|
|
810
898
|
);
|
|
899
|
+
|
|
811
900
|
let invokeRequest;
|
|
812
901
|
let callMethod = method;
|
|
813
902
|
|
|
814
|
-
if (this._voltClient.isVoltRelay) {
|
|
903
|
+
if (this._voltClient.isVoltRelay || isServiceRelayed) {
|
|
904
|
+
//
|
|
905
|
+
// If the volt connection is via a relay (or the target service is relayed),
|
|
906
|
+
// we wrap the rpc in a RemoteRequest message and send it via a call to Invoke().
|
|
907
|
+
//
|
|
815
908
|
let requestPayload;
|
|
909
|
+
|
|
910
|
+
// Serialise the rpc request.
|
|
816
911
|
if (request) {
|
|
817
912
|
requestPayload = this._grpcClient[method].requestSerialize(request);
|
|
818
913
|
} else if (request !== null) {
|
|
819
|
-
log$
|
|
914
|
+
log$4("****************LOOKOUT****************** - empty request");
|
|
820
915
|
} else {
|
|
821
|
-
log$
|
|
916
|
+
log$4("explicit empty request payload");
|
|
822
917
|
}
|
|
823
918
|
|
|
824
|
-
|
|
919
|
+
// Use this placeholder to serialise the relay request wrapper.
|
|
920
|
+
const voltGrpcClient = this._voltClient.getVoltAPIClient();
|
|
921
|
+
const tunnelMethod = voltGrpcClient.Tunnel;
|
|
825
922
|
|
|
826
923
|
const tunnelResp = {
|
|
827
924
|
method_invoke: {
|
|
828
925
|
method_name: this._grpcClient[method].path,
|
|
829
926
|
method_type: methodType,
|
|
830
|
-
token:
|
|
927
|
+
token: methodToken.token,
|
|
831
928
|
request: requestPayload,
|
|
832
929
|
},
|
|
833
930
|
};
|
|
834
931
|
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
932
|
+
let targetFingerprint = [];
|
|
933
|
+
let invokePayload;
|
|
934
|
+
if (this._voltClient.isVoltRelay || isServiceRelayed) {
|
|
935
|
+
// When sending via a relay we need to encrypt the payload.
|
|
936
|
+
invokePayload = VoltCredential.aesEncrypt(
|
|
937
|
+
tunnelMethod.responseSerialize(tunnelResp),
|
|
938
|
+
methodToken.sharedKey.key,
|
|
939
|
+
methodToken.sharedKey.iv,
|
|
940
|
+
);
|
|
941
|
+
} else {
|
|
942
|
+
invokePayload = tunnelMethod.responseSerialize(tunnelResp);
|
|
943
|
+
}
|
|
840
944
|
|
|
841
|
-
|
|
945
|
+
if (this._voltClient.isVoltRelay) {
|
|
946
|
+
targetFingerprint.push(this._voltClient.credential.voltFingerprint);
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
if (isServiceRelayed) {
|
|
950
|
+
// Add another relay hop if the target service is relayed.
|
|
951
|
+
log$4("target service is relayed");
|
|
952
|
+
targetFingerprint.push(
|
|
953
|
+
this._service.service_description.host_fingerprint,
|
|
954
|
+
);
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
log$4("target is %j", targetFingerprint);
|
|
842
958
|
|
|
843
959
|
invokeRequest = {
|
|
844
|
-
|
|
960
|
+
target_fingerprint: targetFingerprint,
|
|
961
|
+
token: methodToken.token,
|
|
845
962
|
payload: invokePayload,
|
|
963
|
+
target_service_id: isServiceRelayed ? this._service.id : undefined,
|
|
846
964
|
};
|
|
847
965
|
|
|
966
|
+
// Replace the target method with a call to Invoke on the relay Volt.
|
|
848
967
|
callMethod = "Invoke";
|
|
849
|
-
} else if (this._voltClient.isRemote && meta.sharedKey.key) {
|
|
850
|
-
const requestPayload =
|
|
851
|
-
this._grpcClient[method].requestSerializeOriginal(request);
|
|
852
|
-
invokeRequest = VoltCredential.aesEncrypt(
|
|
853
|
-
requestPayload,
|
|
854
|
-
meta.sharedKey.key,
|
|
855
|
-
meta.sharedKey.iv,
|
|
856
|
-
);
|
|
857
968
|
} else {
|
|
858
969
|
invokeRequest = request;
|
|
859
970
|
}
|
|
860
971
|
|
|
861
972
|
return {
|
|
862
|
-
meta,
|
|
973
|
+
meta: methodToken,
|
|
863
974
|
method: callMethod,
|
|
864
975
|
methodName: method,
|
|
865
976
|
request: invokeRequest,
|
|
@@ -869,10 +980,16 @@ function _prepareInvokeRequest(
|
|
|
869
980
|
function _preparePayloadRequest(request, invokeInfo) {
|
|
870
981
|
let payloadRequest;
|
|
871
982
|
|
|
872
|
-
|
|
983
|
+
const isServiceRelayed =
|
|
984
|
+
this._service?.service_description.host_type ===
|
|
985
|
+
"SERVICE_HOST_TYPE_RELAYED";
|
|
986
|
+
|
|
987
|
+
if (this._voltClient.isVoltRelay || isServiceRelayed) {
|
|
873
988
|
const requestPayload =
|
|
874
989
|
this._grpcClient[invokeInfo.methodName].requestSerialize(request);
|
|
875
|
-
|
|
990
|
+
|
|
991
|
+
const voltGrpcClient = this._voltClient.getVoltAPIClient();
|
|
992
|
+
const tunnelMethod = voltGrpcClient.Tunnel;
|
|
876
993
|
|
|
877
994
|
const tunnelResp = {
|
|
878
995
|
method_payload: {
|
|
@@ -889,14 +1006,6 @@ function _preparePayloadRequest(request, invokeInfo) {
|
|
|
889
1006
|
payloadRequest = {
|
|
890
1007
|
payload: invokePayload,
|
|
891
1008
|
};
|
|
892
|
-
} else if (this._voltClient.isRemote && invokeInfo.meta.sharedKey.key) {
|
|
893
|
-
const requestPayload =
|
|
894
|
-
this._grpcClient[invokeInfo.methodName].requestSerializeOriginal(request);
|
|
895
|
-
payloadRequest = VoltCredential.aesEncrypt(
|
|
896
|
-
requestPayload,
|
|
897
|
-
invokeInfo.meta.sharedKey.key,
|
|
898
|
-
invokeInfo.meta.sharedKey.iv,
|
|
899
|
-
);
|
|
900
1009
|
} else {
|
|
901
1010
|
payloadRequest = request;
|
|
902
1011
|
}
|
|
@@ -905,29 +1014,47 @@ function _preparePayloadRequest(request, invokeInfo) {
|
|
|
905
1014
|
}
|
|
906
1015
|
|
|
907
1016
|
function _parseResponse(method, meta, response) {
|
|
1017
|
+
// log("parseResponse for %s", this._methodName);
|
|
908
1018
|
let invokeResponse = {};
|
|
909
1019
|
|
|
910
|
-
|
|
1020
|
+
const isServiceRelayed =
|
|
1021
|
+
this._service?.service_description.host_type ===
|
|
1022
|
+
"SERVICE_HOST_TYPE_RELAYED";
|
|
1023
|
+
|
|
1024
|
+
if (this._voltClient.isVoltRelay || isServiceRelayed) {
|
|
911
1025
|
if (response.payload) {
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
1026
|
+
let decryptedPayload;
|
|
1027
|
+
if (meta.sharedKey.key) {
|
|
1028
|
+
decryptedPayload = VoltCredential.aesDecrypt(
|
|
1029
|
+
response.payload,
|
|
1030
|
+
meta.sharedKey.key,
|
|
1031
|
+
meta.sharedKey.iv,
|
|
1032
|
+
);
|
|
1033
|
+
} else {
|
|
1034
|
+
decryptedPayload = response.payload;
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
const tunnelMethod = this._voltClient.getVoltAPIClient().Tunnel;
|
|
918
1038
|
const responsePayload = tunnelMethod.requestDeserialize(decryptedPayload);
|
|
919
1039
|
if (responsePayload.payload === "method_payload") {
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
1040
|
+
try {
|
|
1041
|
+
invokeResponse.payload = this._grpcClient[method].responseDeserialize(
|
|
1042
|
+
responsePayload.method_payload.payload,
|
|
1043
|
+
);
|
|
1044
|
+
} catch (err) {
|
|
1045
|
+
log$4("failure deserialising payload for %s", this._methodName);
|
|
1046
|
+
throw new Error(
|
|
1047
|
+
"failure deserialising payload - check protobuf definition matches with data being sent",
|
|
1048
|
+
);
|
|
1049
|
+
}
|
|
923
1050
|
} else if (responsePayload.payload === "method_end") {
|
|
924
1051
|
invokeResponse = responsePayload.method_end;
|
|
925
1052
|
} else {
|
|
926
|
-
log$
|
|
1053
|
+
log$4("unexpected tunnel payload type: %s", responsePayload.payload);
|
|
927
1054
|
}
|
|
928
1055
|
} else if (response.status?.message) {
|
|
929
1056
|
// There's been an error in the tunnel.
|
|
930
|
-
log$
|
|
1057
|
+
log$4(
|
|
931
1058
|
"Tunnel status received: %s, code %d, description: %s",
|
|
932
1059
|
response.status.message,
|
|
933
1060
|
response.status.code,
|
|
@@ -939,7 +1066,7 @@ function _parseResponse(method, meta, response) {
|
|
|
939
1066
|
};
|
|
940
1067
|
} else {
|
|
941
1068
|
invokeResponse.methodId = response.invoke_id;
|
|
942
|
-
log$
|
|
1069
|
+
log$4("started method %d for %s", invokeResponse.methodId, method);
|
|
943
1070
|
}
|
|
944
1071
|
} else if (this._voltClient.isRemote && meta.sharedKey.key) {
|
|
945
1072
|
const decryptedPayload = VoltCredential.aesDecrypt(
|
|
@@ -959,17 +1086,22 @@ function _parseResponse(method, meta, response) {
|
|
|
959
1086
|
}
|
|
960
1087
|
|
|
961
1088
|
class GRPCCall extends EventEmitter__default["default"] {
|
|
962
|
-
constructor(voltClient, methodName, methodType) {
|
|
1089
|
+
constructor(voltClient, methodName, methodType, service = undefined) {
|
|
963
1090
|
super();
|
|
964
1091
|
this._methodName = methodName;
|
|
965
1092
|
this._methodType = methodType;
|
|
966
1093
|
this._call = null;
|
|
967
1094
|
this._voltClient = voltClient;
|
|
1095
|
+
this._service = service;
|
|
968
1096
|
}
|
|
969
1097
|
|
|
970
1098
|
start(grpcClient, request) {
|
|
971
1099
|
this._grpcClient = grpcClient;
|
|
972
1100
|
|
|
1101
|
+
if (typeof this._grpcClient[this._methodName] !== "function") {
|
|
1102
|
+
throw new Error(`method not found: '${this._methodName}'`);
|
|
1103
|
+
}
|
|
1104
|
+
|
|
973
1105
|
this._initialRequest = _prepareInvokeRequest.call(
|
|
974
1106
|
this,
|
|
975
1107
|
request,
|
|
@@ -977,13 +1109,18 @@ class GRPCCall extends EventEmitter__default["default"] {
|
|
|
977
1109
|
this._methodType,
|
|
978
1110
|
);
|
|
979
1111
|
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
1112
|
+
const isServiceRelayed =
|
|
1113
|
+
this._service?.service_description.host_type ===
|
|
1114
|
+
"SERVICE_HOST_TYPE_RELAYED";
|
|
1115
|
+
|
|
1116
|
+
let callClient;
|
|
1117
|
+
if (this._voltClient.isVoltRelay || isServiceRelayed) {
|
|
1118
|
+
callClient = this._voltClient.getVoltAPIClient();
|
|
1119
|
+
} else {
|
|
1120
|
+
callClient = this._grpcClient;
|
|
984
1121
|
}
|
|
985
1122
|
|
|
986
|
-
this._call =
|
|
1123
|
+
this._call = callClient[this._initialRequest.method](
|
|
987
1124
|
this._initialRequest.meta.metadata,
|
|
988
1125
|
);
|
|
989
1126
|
|
|
@@ -1013,28 +1150,32 @@ class GRPCCall extends EventEmitter__default["default"] {
|
|
|
1013
1150
|
this.emit("end");
|
|
1014
1151
|
}
|
|
1015
1152
|
} else {
|
|
1016
|
-
log$
|
|
1153
|
+
log$4("method id is %s", parsedResponse.methodId);
|
|
1017
1154
|
}
|
|
1018
1155
|
} catch (err) {
|
|
1019
|
-
log$
|
|
1156
|
+
log$4(
|
|
1157
|
+
"failure processing %s call response: %s",
|
|
1158
|
+
this._methodName,
|
|
1159
|
+
err.message,
|
|
1160
|
+
);
|
|
1020
1161
|
this.emit("error", err);
|
|
1021
1162
|
}
|
|
1022
1163
|
});
|
|
1023
1164
|
|
|
1024
1165
|
this._call.on("error", (err) => {
|
|
1025
|
-
log$
|
|
1166
|
+
log$4("ERROR - intercepted stream error %s", err.message);
|
|
1026
1167
|
this.emit("error", err);
|
|
1027
1168
|
});
|
|
1028
1169
|
|
|
1029
1170
|
this._call.on("finish", () => {
|
|
1030
1171
|
// The read side has ended (i.e. we called end()).
|
|
1031
|
-
log$
|
|
1172
|
+
log$4("finished call %s", this._methodName);
|
|
1032
1173
|
this.emit("finish");
|
|
1033
1174
|
});
|
|
1034
1175
|
|
|
1035
1176
|
this._call.on("end", () => {
|
|
1036
1177
|
// The remote peer ended the stream.
|
|
1037
|
-
log$
|
|
1178
|
+
log$4(
|
|
1038
1179
|
"ended call %s, method id: %s",
|
|
1039
1180
|
this._methodName,
|
|
1040
1181
|
this._initialRequest.methodId || "n/a - not tunnelling",
|
|
@@ -1064,7 +1205,7 @@ class GRPCCall extends EventEmitter__default["default"] {
|
|
|
1064
1205
|
|
|
1065
1206
|
write(request) {
|
|
1066
1207
|
if (!this._call) {
|
|
1067
|
-
log$
|
|
1208
|
+
log$4("ERROR - call not initialised");
|
|
1068
1209
|
throw new Error("call not initialised");
|
|
1069
1210
|
} else if (this._initialRequest) {
|
|
1070
1211
|
const payloadRequest = _preparePayloadRequest.call(
|
|
@@ -1088,7 +1229,7 @@ class GRPCCall extends EventEmitter__default["default"] {
|
|
|
1088
1229
|
|
|
1089
1230
|
/* eslint-disable no-use-before-define */
|
|
1090
1231
|
|
|
1091
|
-
const log$
|
|
1232
|
+
const log$3 = debug__default["default"]("volt-client-grpc:volt-connection");
|
|
1092
1233
|
|
|
1093
1234
|
function _cleanUp(immediateReconnect) {
|
|
1094
1235
|
this._connectionId = "";
|
|
@@ -1112,7 +1253,7 @@ function _cleanUp(immediateReconnect) {
|
|
|
1112
1253
|
this._reconnectTimer = 0;
|
|
1113
1254
|
_doConnect.call(this, this._helloPayload);
|
|
1114
1255
|
},
|
|
1115
|
-
immediateReconnect ? 0 : this._reconnectInterval
|
|
1256
|
+
immediateReconnect ? 0 : this._reconnectInterval
|
|
1116
1257
|
);
|
|
1117
1258
|
}
|
|
1118
1259
|
|
|
@@ -1122,7 +1263,7 @@ function _cleanUp(immediateReconnect) {
|
|
|
1122
1263
|
}
|
|
1123
1264
|
|
|
1124
1265
|
function _connectionTimeoutHandler() {
|
|
1125
|
-
log$
|
|
1266
|
+
log$3("server timed out");
|
|
1126
1267
|
this.emit("connected", false);
|
|
1127
1268
|
_cleanUp.call(this);
|
|
1128
1269
|
}
|
|
@@ -1133,15 +1274,15 @@ function _doConnect(connectHello) {
|
|
|
1133
1274
|
const grpcClient = this._voltClient.getVoltAPIClient();
|
|
1134
1275
|
|
|
1135
1276
|
let helloPayload = connectHello;
|
|
1136
|
-
if (!
|
|
1137
|
-
log$
|
|
1277
|
+
if (!helloPayload) {
|
|
1278
|
+
log$3("defaulting hello payload");
|
|
1138
1279
|
helloPayload = {
|
|
1139
|
-
hello: {}
|
|
1280
|
+
hello: {}
|
|
1140
1281
|
};
|
|
1141
1282
|
}
|
|
1142
1283
|
|
|
1143
1284
|
this.call.on("error", (err) => {
|
|
1144
|
-
log$
|
|
1285
|
+
log$3("error on connection stream [%s]", err.message);
|
|
1145
1286
|
_cleanUp.call(this);
|
|
1146
1287
|
this.emit("error", err);
|
|
1147
1288
|
});
|
|
@@ -1149,7 +1290,7 @@ function _doConnect(connectHello) {
|
|
|
1149
1290
|
this.call.on("data", (response) => {
|
|
1150
1291
|
switch (response.payload) {
|
|
1151
1292
|
case "ping": {
|
|
1152
|
-
log$
|
|
1293
|
+
log$3("pinged");
|
|
1153
1294
|
|
|
1154
1295
|
// Received ping response from server => clear timeout.
|
|
1155
1296
|
if (this._pingTimeoutTimer) {
|
|
@@ -1158,23 +1299,30 @@ function _doConnect(connectHello) {
|
|
|
1158
1299
|
|
|
1159
1300
|
// Schedule the next ping.
|
|
1160
1301
|
_startPingTimer.call(this);
|
|
1302
|
+
|
|
1303
|
+
this.emit("ping", response.ping.timestamp);
|
|
1161
1304
|
break;
|
|
1162
1305
|
}
|
|
1163
1306
|
case "acknowledge": {
|
|
1164
1307
|
if (!this._connectionId) {
|
|
1165
1308
|
this._connectionId = response.acknowledge.connection_id;
|
|
1166
|
-
log$
|
|
1309
|
+
log$3("connection id is %s", this._connectionId);
|
|
1167
1310
|
this.emit("connected", this._connectionId);
|
|
1168
1311
|
}
|
|
1169
1312
|
break;
|
|
1170
1313
|
}
|
|
1314
|
+
case "invoke_request": {
|
|
1315
|
+
log$3("received invoke request");
|
|
1316
|
+
this.emit("invoke_request", response.invoke_request);
|
|
1317
|
+
break;
|
|
1318
|
+
}
|
|
1171
1319
|
case "evt": {
|
|
1172
|
-
log$
|
|
1320
|
+
log$3("received event %s", Object.keys(response.evt)[0]);
|
|
1173
1321
|
this.emit("evt", response.evt);
|
|
1174
1322
|
break;
|
|
1175
1323
|
}
|
|
1176
1324
|
default:
|
|
1177
|
-
log$
|
|
1325
|
+
log$3("unimplemented connect response payload: %s", response.payload);
|
|
1178
1326
|
break;
|
|
1179
1327
|
}
|
|
1180
1328
|
});
|
|
@@ -1193,7 +1341,7 @@ function _doConnect(connectHello) {
|
|
|
1193
1341
|
|
|
1194
1342
|
function _startPingTimer() {
|
|
1195
1343
|
if (this._pingTimer) {
|
|
1196
|
-
log$
|
|
1344
|
+
log$3("ping timer running");
|
|
1197
1345
|
return;
|
|
1198
1346
|
}
|
|
1199
1347
|
|
|
@@ -1201,7 +1349,7 @@ function _startPingTimer() {
|
|
|
1201
1349
|
// Send next ping to server.
|
|
1202
1350
|
const request = { ping: { timestamp: Date.now() } };
|
|
1203
1351
|
|
|
1204
|
-
log$
|
|
1352
|
+
log$3("pinging Volt");
|
|
1205
1353
|
this.call.write(request);
|
|
1206
1354
|
|
|
1207
1355
|
this._pingTimer = 0;
|
|
@@ -1213,7 +1361,7 @@ function _startPingTimer() {
|
|
|
1213
1361
|
|
|
1214
1362
|
this._pingTimeoutTimer = setTimeout(
|
|
1215
1363
|
_connectionTimeoutHandler.bind(this),
|
|
1216
|
-
this._timeoutInterval
|
|
1364
|
+
this._timeoutInterval
|
|
1217
1365
|
);
|
|
1218
1366
|
}, this._pingInterval);
|
|
1219
1367
|
}
|
|
@@ -1250,6 +1398,281 @@ class VoltConnection extends EventEmitter__default["default"] {
|
|
|
1250
1398
|
this._dying = true;
|
|
1251
1399
|
_cleanUp.call(this);
|
|
1252
1400
|
}
|
|
1401
|
+
|
|
1402
|
+
send(request) {
|
|
1403
|
+
this.call.write(request);
|
|
1404
|
+
}
|
|
1405
|
+
}
|
|
1406
|
+
|
|
1407
|
+
const log$2 = debug__default["default"]("rpc-invocation");
|
|
1408
|
+
|
|
1409
|
+
class RpcInvocation extends EventEmitter__default["default"] {
|
|
1410
|
+
#voltClient = null;
|
|
1411
|
+
#voltConnection = null;
|
|
1412
|
+
#token = null;
|
|
1413
|
+
#encryptKey = null;
|
|
1414
|
+
#encryptIV = null;
|
|
1415
|
+
#invokeId = null;
|
|
1416
|
+
#payload = null;
|
|
1417
|
+
#isJSON = false;
|
|
1418
|
+
#methodDescriptor = null;
|
|
1419
|
+
#methodName = null;
|
|
1420
|
+
|
|
1421
|
+
constructor(voltClient, voltConnection) {
|
|
1422
|
+
super();
|
|
1423
|
+
this.#voltClient = voltClient;
|
|
1424
|
+
this.#voltConnection = voltConnection;
|
|
1425
|
+
}
|
|
1426
|
+
|
|
1427
|
+
get id() {
|
|
1428
|
+
return this.#invokeId;
|
|
1429
|
+
}
|
|
1430
|
+
|
|
1431
|
+
get payload() {
|
|
1432
|
+
if (!this.#payload) {
|
|
1433
|
+
return null;
|
|
1434
|
+
}
|
|
1435
|
+
|
|
1436
|
+
let deserialisedPayload = null;
|
|
1437
|
+
|
|
1438
|
+
if (this.#isJSON) {
|
|
1439
|
+
// Don't need to deserialise JSON payload.
|
|
1440
|
+
deserialisedPayload = this.#payload;
|
|
1441
|
+
} else if (this.#methodDescriptor) {
|
|
1442
|
+
deserialisedPayload = this.#methodDescriptor.requestDeserialize(
|
|
1443
|
+
this.#payload
|
|
1444
|
+
);
|
|
1445
|
+
} else {
|
|
1446
|
+
log$2("unexpected: no method descriptor");
|
|
1447
|
+
throw new Error(
|
|
1448
|
+
"no method descriptor - set this before accessing payload"
|
|
1449
|
+
);
|
|
1450
|
+
}
|
|
1451
|
+
|
|
1452
|
+
return deserialisedPayload;
|
|
1453
|
+
}
|
|
1454
|
+
|
|
1455
|
+
get methodName() {
|
|
1456
|
+
return this.#methodName;
|
|
1457
|
+
}
|
|
1458
|
+
|
|
1459
|
+
set methodDescriptor(methodDescriptor) {
|
|
1460
|
+
this.#methodDescriptor = methodDescriptor;
|
|
1461
|
+
}
|
|
1462
|
+
|
|
1463
|
+
#decodeToken(token) {
|
|
1464
|
+
// We don't verify the token at this point, as we don't know the public key.
|
|
1465
|
+
// The rpc implementation should do the verification using the Volt API (e.g. CanAccessResource).
|
|
1466
|
+
this.#token = jwt__default["default"].decode(token);
|
|
1467
|
+
|
|
1468
|
+
if (this.#token.sk) {
|
|
1469
|
+
// Decrypt the shared key and iv using the private key.
|
|
1470
|
+
this.#encryptKey = VoltCredential.rsaDecrypt(
|
|
1471
|
+
this.#voltClient.credential.cache.key,
|
|
1472
|
+
this.#token.sk
|
|
1473
|
+
);
|
|
1474
|
+
this.#encryptIV = VoltCredential.rsaDecrypt(
|
|
1475
|
+
this.#voltClient.credential.cache.key,
|
|
1476
|
+
this.#token.iv
|
|
1477
|
+
);
|
|
1478
|
+
}
|
|
1479
|
+
|
|
1480
|
+
return Promise.resolve(this.#token);
|
|
1481
|
+
}
|
|
1482
|
+
|
|
1483
|
+
initialise(invoke_request) {
|
|
1484
|
+
this.#invokeId = invoke_request.invoke_id;
|
|
1485
|
+
|
|
1486
|
+
return this.#decodeToken(invoke_request.token)
|
|
1487
|
+
.then(() => {
|
|
1488
|
+
// Parse the initial payload.
|
|
1489
|
+
return this.parsePayload(invoke_request);
|
|
1490
|
+
})
|
|
1491
|
+
.catch((err) => {
|
|
1492
|
+
log$2("failure initialising invocation: %s", err.message);
|
|
1493
|
+
return Promise.reject(err);
|
|
1494
|
+
});
|
|
1495
|
+
}
|
|
1496
|
+
|
|
1497
|
+
parsePayload(invoke_request) {
|
|
1498
|
+
return new Promise((resolve, reject) => {
|
|
1499
|
+
if (invoke_request.payload) {
|
|
1500
|
+
let decryptedPayload;
|
|
1501
|
+
|
|
1502
|
+
if (this.#encryptKey) {
|
|
1503
|
+
// Decrypt the actual payload using the shared key and iv.
|
|
1504
|
+
decryptedPayload = VoltCredential.aesDecrypt(
|
|
1505
|
+
invoke_request.payload,
|
|
1506
|
+
this.#encryptKey,
|
|
1507
|
+
this.#encryptIV
|
|
1508
|
+
);
|
|
1509
|
+
} else {
|
|
1510
|
+
// No encryption => just use the payload.
|
|
1511
|
+
decryptedPayload = invoke_request.payload;
|
|
1512
|
+
}
|
|
1513
|
+
|
|
1514
|
+
const tunnelMethod = this.#voltClient.getVoltAPIClient().Tunnel;
|
|
1515
|
+
const wrappedPayload =
|
|
1516
|
+
tunnelMethod.responseDeserialize(decryptedPayload);
|
|
1517
|
+
|
|
1518
|
+
if (wrappedPayload.method_invoke) {
|
|
1519
|
+
// This is the initial request payload.
|
|
1520
|
+
this.#methodName = wrappedPayload.method_invoke.method_name;
|
|
1521
|
+
this.#payload = wrappedPayload.method_invoke.request;
|
|
1522
|
+
this.emit("payload", this);
|
|
1523
|
+
} else if (wrappedPayload.method_payload) {
|
|
1524
|
+
// This is a subsequent payload, e.g. for streaming rpcs.
|
|
1525
|
+
this.#payload = wrappedPayload.method_payload.payload;
|
|
1526
|
+
this.emit("payload", this);
|
|
1527
|
+
} else if (wrappedPayload.method_end) {
|
|
1528
|
+
this.#payload = wrappedPayload.method_end;
|
|
1529
|
+
if (wrappedPayload.method_end.error) {
|
|
1530
|
+
// The client has sent an error.
|
|
1531
|
+
this.emit("error", this);
|
|
1532
|
+
} else {
|
|
1533
|
+
this.emit("end", this);
|
|
1534
|
+
}
|
|
1535
|
+
}
|
|
1536
|
+
|
|
1537
|
+
resolve();
|
|
1538
|
+
} else if (invoke_request.json_payload) {
|
|
1539
|
+
let decryptedPayload;
|
|
1540
|
+
|
|
1541
|
+
this.#isJSON = true;
|
|
1542
|
+
|
|
1543
|
+
if (this.#encryptKey) {
|
|
1544
|
+
// Decrypt the actual payload using the shared key and iv.
|
|
1545
|
+
decryptedPayload = VoltCredential.aesDecrypt(
|
|
1546
|
+
Buffer.from(invoke_request.json_payload, "base64"),
|
|
1547
|
+
this.#encryptKey,
|
|
1548
|
+
this.#encryptIV
|
|
1549
|
+
);
|
|
1550
|
+
} else {
|
|
1551
|
+
// No encryption => just use the payload.
|
|
1552
|
+
decryptedPayload = invoke_request.json_payload;
|
|
1553
|
+
}
|
|
1554
|
+
|
|
1555
|
+
try {
|
|
1556
|
+
const wrappedPayload = JSON.parse(decryptedPayload.toString());
|
|
1557
|
+
|
|
1558
|
+
if (wrappedPayload.method_invoke) {
|
|
1559
|
+
this.#methodName = wrappedPayload.method_invoke.method_name;
|
|
1560
|
+
this.#payload = JSON.parse(
|
|
1561
|
+
wrappedPayload.method_invoke.json_request
|
|
1562
|
+
);
|
|
1563
|
+
this.emit("payload", this);
|
|
1564
|
+
} else if (wrappedPayload.method_payload) {
|
|
1565
|
+
this.#payload = JSON.parse(
|
|
1566
|
+
wrappedPayload.method_payload.json_payload
|
|
1567
|
+
);
|
|
1568
|
+
this.emit("payload", this);
|
|
1569
|
+
} else if (wrappedPayload.method_end) {
|
|
1570
|
+
// We don't need to do anything here, since we notify the client when we receive the client_end.
|
|
1571
|
+
log$2("method_end received");
|
|
1572
|
+
}
|
|
1573
|
+
} catch (err) {
|
|
1574
|
+
log$2("JSON.parse failure parsing json_payload: %s", err.message);
|
|
1575
|
+
reject(err);
|
|
1576
|
+
}
|
|
1577
|
+
|
|
1578
|
+
resolve();
|
|
1579
|
+
} else if (invoke_request.client_end) {
|
|
1580
|
+
this.emit("end", this);
|
|
1581
|
+
} else {
|
|
1582
|
+
// Do we need to support json_payload here?
|
|
1583
|
+
reject(new Error("No payload in invoke request"));
|
|
1584
|
+
}
|
|
1585
|
+
}).catch((err) => {
|
|
1586
|
+
log$2("failure parsing payload: %s", err.message);
|
|
1587
|
+
return Promise.reject(err);
|
|
1588
|
+
});
|
|
1589
|
+
}
|
|
1590
|
+
|
|
1591
|
+
sendResponse(response) {
|
|
1592
|
+
let responsePayload;
|
|
1593
|
+
if (this.#isJSON) {
|
|
1594
|
+
responsePayload = JSON.stringify({
|
|
1595
|
+
method_payload: { json_payload: JSON.stringify(response) }
|
|
1596
|
+
});
|
|
1597
|
+
} else {
|
|
1598
|
+
// We need to serialise the response, and then wrap it in a RemoteRequest.
|
|
1599
|
+
const serialisedResponse =
|
|
1600
|
+
this.#methodDescriptor.responseSerialize(response);
|
|
1601
|
+
const tunnelMethod = this.#voltClient.getVoltAPIClient().Tunnel;
|
|
1602
|
+
responsePayload = tunnelMethod.requestSerialize({
|
|
1603
|
+
method_payload: { payload: serialisedResponse }
|
|
1604
|
+
});
|
|
1605
|
+
}
|
|
1606
|
+
|
|
1607
|
+
if (this.#token.sk) {
|
|
1608
|
+
// Encrypt the response using the shared key and iv.
|
|
1609
|
+
responsePayload = VoltCredential.aesEncrypt(
|
|
1610
|
+
responsePayload,
|
|
1611
|
+
this.#encryptKey,
|
|
1612
|
+
this.#encryptIV
|
|
1613
|
+
);
|
|
1614
|
+
}
|
|
1615
|
+
|
|
1616
|
+
const invokeResponse = {
|
|
1617
|
+
invoke_id: this.#invokeId
|
|
1618
|
+
};
|
|
1619
|
+
|
|
1620
|
+
if (this.#isJSON) {
|
|
1621
|
+
invokeResponse.json_payload =
|
|
1622
|
+
Buffer.from(responsePayload).toString("base64");
|
|
1623
|
+
} else {
|
|
1624
|
+
invokeResponse.payload = responsePayload;
|
|
1625
|
+
}
|
|
1626
|
+
|
|
1627
|
+
this.#voltConnection.send({
|
|
1628
|
+
invoke_response: invokeResponse
|
|
1629
|
+
});
|
|
1630
|
+
}
|
|
1631
|
+
|
|
1632
|
+
sendEnd(errorMessage) {
|
|
1633
|
+
const tunnelMethod = this.#voltClient.getVoltAPIClient().Tunnel;
|
|
1634
|
+
|
|
1635
|
+
let endPayload;
|
|
1636
|
+
if (errorMessage) {
|
|
1637
|
+
endPayload = {
|
|
1638
|
+
method_end: { error: errorMessage, ended: true }
|
|
1639
|
+
};
|
|
1640
|
+
} else {
|
|
1641
|
+
endPayload = {
|
|
1642
|
+
method_end: { ended: true }
|
|
1643
|
+
};
|
|
1644
|
+
}
|
|
1645
|
+
|
|
1646
|
+
if (this.#isJSON) {
|
|
1647
|
+
endPayload = JSON.stringify(endPayload);
|
|
1648
|
+
} else {
|
|
1649
|
+
endPayload = tunnelMethod.requestSerialize(endPayload);
|
|
1650
|
+
}
|
|
1651
|
+
|
|
1652
|
+
if (this.#token.sk) {
|
|
1653
|
+
// Encrypt the response using the shared key and iv.
|
|
1654
|
+
endPayload = VoltCredential.aesEncrypt(
|
|
1655
|
+
endPayload,
|
|
1656
|
+
this.#encryptKey,
|
|
1657
|
+
this.#encryptIV
|
|
1658
|
+
);
|
|
1659
|
+
}
|
|
1660
|
+
|
|
1661
|
+
const invokeResponse = {
|
|
1662
|
+
invoke_id: this.#invokeId,
|
|
1663
|
+
server_end: true
|
|
1664
|
+
};
|
|
1665
|
+
|
|
1666
|
+
if (this.#isJSON) {
|
|
1667
|
+
invokeResponse.json_payload = Buffer.from(endPayload).toString("base64");
|
|
1668
|
+
} else {
|
|
1669
|
+
invokeResponse.payload = endPayload;
|
|
1670
|
+
}
|
|
1671
|
+
|
|
1672
|
+
this.#voltConnection.send({
|
|
1673
|
+
invoke_response: invokeResponse
|
|
1674
|
+
});
|
|
1675
|
+
}
|
|
1253
1676
|
}
|
|
1254
1677
|
|
|
1255
1678
|
/* eslint-disable no-underscore-dangle */
|
|
@@ -1265,51 +1688,53 @@ const voltServices = [
|
|
|
1265
1688
|
constants.serviceType.sqliteServerAPI,
|
|
1266
1689
|
constants.serviceType.ssiAPI,
|
|
1267
1690
|
constants.serviceType.relayAPI,
|
|
1268
|
-
constants.serviceType.wireAPI
|
|
1691
|
+
constants.serviceType.wireAPI
|
|
1269
1692
|
];
|
|
1270
1693
|
|
|
1271
1694
|
function issueBind(bindRequest, ttl) {
|
|
1272
1695
|
// eslint-disable-next-line no-use-before-define
|
|
1273
|
-
return
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
log$1("
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1696
|
+
return unaryCallInternal
|
|
1697
|
+
.call(this, "Bind", bindRequest)
|
|
1698
|
+
.then((bindResponse) => {
|
|
1699
|
+
log$1("got binding request response %j", bindResponse);
|
|
1700
|
+
if (bindResponse.status?.code) {
|
|
1701
|
+
log$1("error in bind response: %s", bindResponse.status.message);
|
|
1702
|
+
return Promise.reject(new Error(bindResponse.status.message));
|
|
1703
|
+
} else {
|
|
1704
|
+
switch (bindResponse.decision) {
|
|
1705
|
+
case "POLICY_DECISION_PERMIT": {
|
|
1706
|
+
//
|
|
1707
|
+
// The request status is permit => cache the bind response info.
|
|
1708
|
+
//
|
|
1709
|
+
|
|
1710
|
+
// This is the certificate assigned to us by the volt.
|
|
1711
|
+
this._credential.cache.cert = bindResponse.cert;
|
|
1712
|
+
|
|
1713
|
+
// This is the signing CA used by the volt.
|
|
1714
|
+
this._credential.cache.ca = bindResponse.chain;
|
|
1715
|
+
|
|
1716
|
+
// Identity resource id is assigned by the volt.
|
|
1717
|
+
this._credential.cache.client_id = bindResponse.identity_id;
|
|
1718
|
+
this._credential.saveCache();
|
|
1719
|
+
break;
|
|
1720
|
+
}
|
|
1721
|
+
case "POLICY_DECISION_DENY": {
|
|
1722
|
+
log$1(">>>>>>>>>>>>>>> access request is DENIED <<<<<<<<<<<<<<<<<<<");
|
|
1723
|
+
break;
|
|
1724
|
+
}
|
|
1725
|
+
case "POLICY_DECISION_PROMPT":
|
|
1726
|
+
case "POLICY_DECISION_PENDING": {
|
|
1727
|
+
log$1("access pending approval - waiting...");
|
|
1728
|
+
break;
|
|
1729
|
+
}
|
|
1730
|
+
default:
|
|
1731
|
+
log$1("ignoring unknown bind descision %s", bindResponse.status);
|
|
1732
|
+
break;
|
|
1304
1733
|
}
|
|
1305
|
-
default:
|
|
1306
|
-
log$1("ignoring unknown bind descision %s", bindResponse.status);
|
|
1307
|
-
break;
|
|
1308
1734
|
}
|
|
1309
|
-
}
|
|
1310
1735
|
|
|
1311
|
-
|
|
1312
|
-
|
|
1736
|
+
return bindResponse.decision;
|
|
1737
|
+
});
|
|
1313
1738
|
}
|
|
1314
1739
|
|
|
1315
1740
|
function findDIDDocumentService(document, serviceType) {
|
|
@@ -1333,13 +1758,13 @@ async function bindInternal() {
|
|
|
1333
1758
|
log$1("attempting to retrieve Relay information from %s", relayURL);
|
|
1334
1759
|
this._voltConfig.relay = await fetchVoltConfig.call(
|
|
1335
1760
|
this,
|
|
1336
|
-
`${relayURL}/discovery
|
|
1761
|
+
`${relayURL}/discovery`
|
|
1337
1762
|
);
|
|
1338
1763
|
if (this._voltConfig.relay.ca_pem) {
|
|
1339
1764
|
log$1(
|
|
1340
1765
|
"Auto-fetched Relay CA %s, remote address %s",
|
|
1341
1766
|
this._voltConfig.relay.ca_pem,
|
|
1342
|
-
this._voltConfig.relay.address
|
|
1767
|
+
this._voltConfig.relay.address
|
|
1343
1768
|
);
|
|
1344
1769
|
} else {
|
|
1345
1770
|
throw new Error("Unable to fetch Relay CA - cannot securely connect.");
|
|
@@ -1352,7 +1777,7 @@ async function bindInternal() {
|
|
|
1352
1777
|
|
|
1353
1778
|
if (!this._credential.cache.ca) {
|
|
1354
1779
|
throw new Error(
|
|
1355
|
-
"No certificate authority found in configuration for target Volt - check configuration"
|
|
1780
|
+
"No certificate authority found in configuration for target Volt - check configuration"
|
|
1356
1781
|
);
|
|
1357
1782
|
}
|
|
1358
1783
|
|
|
@@ -1372,30 +1797,30 @@ async function bindInternal() {
|
|
|
1372
1797
|
binding_name: this._config.client_name,
|
|
1373
1798
|
public_key: publicKeyPem,
|
|
1374
1799
|
host: this._credential.cache.bindIp,
|
|
1375
|
-
x509_credential: []
|
|
1800
|
+
x509_credential: []
|
|
1376
1801
|
};
|
|
1377
1802
|
|
|
1378
1803
|
if (this._credential.cache.cert) {
|
|
1379
1804
|
bindRequest.x509_credential = [
|
|
1380
|
-
this._credential.cache.cert + this._credential.cache.ca
|
|
1805
|
+
this._credential.cache.cert + this._credential.cache.ca
|
|
1381
1806
|
];
|
|
1382
1807
|
}
|
|
1383
1808
|
|
|
1384
1809
|
if (this._voltConfig.challenge_code) {
|
|
1385
1810
|
bindRequest.challenge = signBase64(
|
|
1386
1811
|
keyPair.privateKey,
|
|
1387
|
-
this._voltConfig.challenge_code
|
|
1812
|
+
this._voltConfig.challenge_code
|
|
1388
1813
|
);
|
|
1389
1814
|
} else {
|
|
1390
1815
|
log$1(
|
|
1391
|
-
"****no Volt challenge code available**** => not sending challenge signature"
|
|
1816
|
+
"****no Volt challenge code available**** => not sending challenge signature"
|
|
1392
1817
|
);
|
|
1393
1818
|
}
|
|
1394
1819
|
|
|
1395
1820
|
// For remote connections, add our cloud-issued certificate as an additional credential.
|
|
1396
1821
|
if (this._voltConfig?.relay?.ca_pem && this._credential.cache.cloud_cert) {
|
|
1397
1822
|
bindRequest.x509_credential = bindRequest.x509_credential.concat(
|
|
1398
|
-
this._credential.cache.cloud_cert + this._voltConfig.relay.ca_pem
|
|
1823
|
+
this._credential.cache.cloud_cert + this._voltConfig.relay.ca_pem
|
|
1399
1824
|
);
|
|
1400
1825
|
}
|
|
1401
1826
|
|
|
@@ -1415,7 +1840,7 @@ async function bindInternal() {
|
|
|
1415
1840
|
decision = await issueBind.call(
|
|
1416
1841
|
this,
|
|
1417
1842
|
bindRequest,
|
|
1418
|
-
this._voltConfig.bindRequestTTL
|
|
1843
|
+
this._voltConfig.bindRequestTTL
|
|
1419
1844
|
);
|
|
1420
1845
|
log$1("binding decision: %s", decision);
|
|
1421
1846
|
} while (
|
|
@@ -1476,6 +1901,34 @@ function connectInternal(helloPayload) {
|
|
|
1476
1901
|
this.emit("evt", evt);
|
|
1477
1902
|
});
|
|
1478
1903
|
|
|
1904
|
+
this._voltConnection.on("ping", (ping) => {
|
|
1905
|
+
this.emit("ping", ping);
|
|
1906
|
+
});
|
|
1907
|
+
|
|
1908
|
+
this._voltConnection.on("invoke_request", (invoke_request) => {
|
|
1909
|
+
const invokeId = invoke_request.invoke_id;
|
|
1910
|
+
if (this._activeRPC[invokeId]) {
|
|
1911
|
+
this._activeRPC[invokeId].parsePayload(invoke_request);
|
|
1912
|
+
} else {
|
|
1913
|
+
const rpcInvocation = new RpcInvocation(this, this._voltConnection);
|
|
1914
|
+
|
|
1915
|
+
rpcInvocation.on("end", () => {
|
|
1916
|
+
log$1("removing active RPC [%s]", invokeId);
|
|
1917
|
+
this._activeRPC[invokeId] = undefined;
|
|
1918
|
+
});
|
|
1919
|
+
|
|
1920
|
+
rpcInvocation
|
|
1921
|
+
.initialise(invoke_request)
|
|
1922
|
+
.then(() => {
|
|
1923
|
+
this._activeRPC[invokeId] = rpcInvocation;
|
|
1924
|
+
this.emit("invoke_request", rpcInvocation);
|
|
1925
|
+
})
|
|
1926
|
+
.catch((err) => {
|
|
1927
|
+
log$1("invoke_request - error [%s]", err.message);
|
|
1928
|
+
});
|
|
1929
|
+
}
|
|
1930
|
+
});
|
|
1931
|
+
|
|
1479
1932
|
return this._voltConnection.connect(helloPayload);
|
|
1480
1933
|
} catch (err) {
|
|
1481
1934
|
log$1("connect - error [%s]", err.message);
|
|
@@ -1502,18 +1955,68 @@ function getVoltAPIClientInternal() {
|
|
|
1502
1955
|
this._credential,
|
|
1503
1956
|
this.isRemote && !this.isVoltRelay,
|
|
1504
1957
|
this._voltConfig?.relay?.cloud ? this._voltConfig.id : "",
|
|
1505
|
-
this._voltConfig?.relay?.cloud ? this._voltConfig.id : ""
|
|
1958
|
+
this._voltConfig?.relay?.cloud ? this._voltConfig.id : ""
|
|
1506
1959
|
);
|
|
1507
1960
|
}
|
|
1508
1961
|
|
|
1509
1962
|
return this._cachedClient;
|
|
1510
1963
|
}
|
|
1511
1964
|
|
|
1512
|
-
function
|
|
1513
|
-
|
|
1514
|
-
|
|
1965
|
+
function getAPIClientInternal(service) {
|
|
1966
|
+
if (!this._cachedService[service.id]) {
|
|
1967
|
+
service.service_description.host_type === "SERVICE_HOST_TYPE_RELAYED";
|
|
1968
|
+
|
|
1969
|
+
const serviceAddress = this.isRemote
|
|
1970
|
+
? this._voltConfig.relay.address
|
|
1971
|
+
: service.service_description.host_address;
|
|
1972
|
+
|
|
1973
|
+
createServiceProtobufFiles(service, "./service-proto");
|
|
1974
|
+
|
|
1975
|
+
log$1("creating API service client on %s", serviceAddress);
|
|
1976
|
+
let serviceDescriptors = {};
|
|
1977
|
+
const fullProtoPath = path.join(process.cwd(), "./service-proto");
|
|
1978
|
+
for (let api of service.service_description.service_api) {
|
|
1979
|
+
const packageDescriptors = getServiceDescriptorsFromPath(
|
|
1980
|
+
this._grpc,
|
|
1981
|
+
fullProtoPath,
|
|
1982
|
+
api
|
|
1983
|
+
);
|
|
1984
|
+
serviceDescriptors = { ...serviceDescriptors, ...packageDescriptors };
|
|
1985
|
+
}
|
|
1986
|
+
|
|
1987
|
+
this._cachedService[service.id] = createClient(
|
|
1988
|
+
this._grpc,
|
|
1989
|
+
serviceDescriptors,
|
|
1990
|
+
serviceAddress,
|
|
1991
|
+
this._credential,
|
|
1992
|
+
this.isRemote && !this.isVoltRelay,
|
|
1993
|
+
this._voltConfig?.relay?.cloud ? this._voltConfig.id : "",
|
|
1994
|
+
this._voltConfig?.relay?.cloud ? this._voltConfig.id : ""
|
|
1995
|
+
);
|
|
1996
|
+
}
|
|
1997
|
+
|
|
1998
|
+
return this._cachedService[service.id];
|
|
1999
|
+
}
|
|
2000
|
+
|
|
2001
|
+
function getServiceClient(service) {
|
|
2002
|
+
let grpcClient;
|
|
2003
|
+
if (
|
|
2004
|
+
service &&
|
|
2005
|
+
service?.service_description.host_type !== "SERVICE_HOST_TYPE_BUILTIN"
|
|
2006
|
+
) {
|
|
2007
|
+
grpcClient = getAPIClientInternal.call(this, service);
|
|
2008
|
+
} else {
|
|
2009
|
+
grpcClient = getVoltAPIClientInternal.call(this);
|
|
2010
|
+
}
|
|
2011
|
+
|
|
2012
|
+
return grpcClient;
|
|
2013
|
+
}
|
|
1515
2014
|
|
|
1516
|
-
|
|
2015
|
+
function unaryCallInternal(method, request, service) {
|
|
2016
|
+
const grpcClient = getServiceClient.call(this, service);
|
|
2017
|
+
|
|
2018
|
+
return new Promise((resolve, reject) => {
|
|
2019
|
+
const call = new GRPCCall(this, method, "METHOD_TYPE_UNARY", service);
|
|
1517
2020
|
|
|
1518
2021
|
let response = null;
|
|
1519
2022
|
|
|
@@ -1541,6 +2044,16 @@ function unaryCall(method, request) {
|
|
|
1541
2044
|
});
|
|
1542
2045
|
}
|
|
1543
2046
|
|
|
2047
|
+
function streamingCallInternal(methodType, method, request, service) {
|
|
2048
|
+
const grpcClient = getServiceClient.call(this, service);
|
|
2049
|
+
|
|
2050
|
+
const call = new GRPCCall(this, method, methodType, service);
|
|
2051
|
+
|
|
2052
|
+
call.start(grpcClient, request);
|
|
2053
|
+
|
|
2054
|
+
return call;
|
|
2055
|
+
}
|
|
2056
|
+
|
|
1544
2057
|
async function fetchVoltConfig(discovery_url) {
|
|
1545
2058
|
try {
|
|
1546
2059
|
const getJSON = bent__default["default"]("json");
|
|
@@ -1560,13 +2073,13 @@ async function fetchVoltConfig(discovery_url) {
|
|
|
1560
2073
|
"ca_pem",
|
|
1561
2074
|
"challenge_code",
|
|
1562
2075
|
"cloud",
|
|
1563
|
-
"relay"
|
|
2076
|
+
"relay"
|
|
1564
2077
|
);
|
|
1565
2078
|
|
|
1566
2079
|
return voltConfig;
|
|
1567
2080
|
} catch (err) {
|
|
1568
2081
|
throw new Error(
|
|
1569
|
-
`Failure loading config from ${discovery_url}: ${err.message}
|
|
2082
|
+
`Failure loading config from ${discovery_url}: ${err.message}`
|
|
1570
2083
|
);
|
|
1571
2084
|
}
|
|
1572
2085
|
}
|
|
@@ -1582,13 +2095,13 @@ async function fetchVoltConfigFromDID(volt_did) {
|
|
|
1582
2095
|
const didDocument = await getJSON(didResolution);
|
|
1583
2096
|
const voltConfigServices = findDIDDocumentService(
|
|
1584
2097
|
didDocument,
|
|
1585
|
-
constants.didServiceType.voltConfig
|
|
2098
|
+
constants.didServiceType.voltConfig
|
|
1586
2099
|
);
|
|
1587
2100
|
if (voltConfigServices.length !== 1) {
|
|
1588
2101
|
log$1(
|
|
1589
2102
|
"Unexpected number of Volt configuration endpoints found in DID document for %s, services found: %d",
|
|
1590
2103
|
volt_did,
|
|
1591
|
-
voltConfigServices.length
|
|
2104
|
+
voltConfigServices.length
|
|
1592
2105
|
);
|
|
1593
2106
|
}
|
|
1594
2107
|
|
|
@@ -1596,7 +2109,7 @@ async function fetchVoltConfigFromDID(volt_did) {
|
|
|
1596
2109
|
return await fetchVoltConfig.call(this, serviceEndpoint);
|
|
1597
2110
|
} catch (err) {
|
|
1598
2111
|
throw new Error(
|
|
1599
|
-
`Failure fetching Volt config from DID document ${volt_did}: ${err.message}
|
|
2112
|
+
`Failure fetching Volt config from DID document ${volt_did}: ${err.message}`
|
|
1600
2113
|
);
|
|
1601
2114
|
}
|
|
1602
2115
|
}
|
|
@@ -1621,6 +2134,8 @@ class VoltClient extends EventEmitter__default["default"] {
|
|
|
1621
2134
|
this._config = null;
|
|
1622
2135
|
this._voltConfig = null;
|
|
1623
2136
|
this._voltConnection = null;
|
|
2137
|
+
this._cachedService = {};
|
|
2138
|
+
this._activeRPC = {};
|
|
1624
2139
|
}
|
|
1625
2140
|
|
|
1626
2141
|
get config() {
|
|
@@ -1647,7 +2162,7 @@ class VoltClient extends EventEmitter__default["default"] {
|
|
|
1647
2162
|
try {
|
|
1648
2163
|
if (!config) {
|
|
1649
2164
|
throw new Error(
|
|
1650
|
-
"configPath argument is required to be a non-empty string"
|
|
2165
|
+
"configPath argument is required to be a non-empty string"
|
|
1651
2166
|
);
|
|
1652
2167
|
}
|
|
1653
2168
|
|
|
@@ -1658,13 +2173,13 @@ class VoltClient extends EventEmitter__default["default"] {
|
|
|
1658
2173
|
log("Attempt to load config from file %s", configPath);
|
|
1659
2174
|
try {
|
|
1660
2175
|
const configContents = await readFile(
|
|
1661
|
-
new URL(configPath, (typeof document === 'undefined' ? new (require('u' + 'rl').URL)('file:' + __filename).href : (document.currentScript && document.currentScript.src || new URL('index.cjs', document.baseURI).href)))
|
|
2176
|
+
new URL(configPath, (typeof document === 'undefined' ? new (require('u' + 'rl').URL)('file:' + __filename).href : (document.currentScript && document.currentScript.src || new URL('index.cjs', document.baseURI).href)))
|
|
1662
2177
|
);
|
|
1663
2178
|
configJSON = JSON.parse(configContents);
|
|
1664
2179
|
} catch (err) {
|
|
1665
2180
|
log("failure loading config file %s [%s]", configPath, err.message);
|
|
1666
2181
|
throw new Error(
|
|
1667
|
-
`failed to load configuration - check JSON format in ${configPath}
|
|
2182
|
+
`failed to load configuration - check JSON format in ${configPath}`
|
|
1668
2183
|
);
|
|
1669
2184
|
}
|
|
1670
2185
|
} else if (typeof config === "object") {
|
|
@@ -1705,14 +2220,14 @@ class VoltClient extends EventEmitter__default["default"] {
|
|
|
1705
2220
|
const didConfig = await fetchVoltConfigFromDID.call(this, voltDID);
|
|
1706
2221
|
this._config = { ...this._config, volt: didConfig };
|
|
1707
2222
|
log("resolved config from DID: %s", JSON.stringify(didConfig, null, 2));
|
|
1708
|
-
} else if (voltHttpAddress) {
|
|
2223
|
+
} else if (voltHttpAddress && !this._config?.volt?.id) {
|
|
1709
2224
|
const discoConfig = await fetchVoltConfig.call(
|
|
1710
2225
|
this,
|
|
1711
|
-
`${voltHttpAddress}/discovery
|
|
2226
|
+
`${voltHttpAddress}/discovery`
|
|
1712
2227
|
);
|
|
1713
2228
|
this._config = {
|
|
1714
2229
|
...this._config,
|
|
1715
|
-
volt: { ...this._config.volt, ...discoConfig }
|
|
2230
|
+
volt: { ...this._config.volt, ...discoConfig }
|
|
1716
2231
|
};
|
|
1717
2232
|
}
|
|
1718
2233
|
|
|
@@ -1756,7 +2271,7 @@ class VoltClient extends EventEmitter__default["default"] {
|
|
|
1756
2271
|
if (bindErr.message === "invalid arguments") {
|
|
1757
2272
|
// This is usually the result of a missing challenge signature or credential.
|
|
1758
2273
|
log(
|
|
1759
|
-
"failure binding to Volt - did you supply a challenge code or verified credential?"
|
|
2274
|
+
"failure binding to Volt - did you supply a challenge code or verified credential?"
|
|
1760
2275
|
);
|
|
1761
2276
|
throw bindErr;
|
|
1762
2277
|
}
|
|
@@ -1819,7 +2334,7 @@ class VoltClient extends EventEmitter__default["default"] {
|
|
|
1819
2334
|
if (this.isRemote) {
|
|
1820
2335
|
if (!this._voltConfig?.relay?.address) {
|
|
1821
2336
|
throw new Error(
|
|
1822
|
-
"Remote connection enabled but no Relay address - have you called start()?"
|
|
2337
|
+
"Remote connection enabled but no Relay address - have you called start()?"
|
|
1823
2338
|
);
|
|
1824
2339
|
}
|
|
1825
2340
|
|
|
@@ -1831,14 +2346,14 @@ class VoltClient extends EventEmitter__default["default"] {
|
|
|
1831
2346
|
this._credential,
|
|
1832
2347
|
false,
|
|
1833
2348
|
service.volt_id,
|
|
1834
|
-
service.id
|
|
2349
|
+
service.id
|
|
1835
2350
|
);
|
|
1836
2351
|
} else {
|
|
1837
2352
|
return createClient(
|
|
1838
2353
|
this._grpc,
|
|
1839
2354
|
serviceDescriptors,
|
|
1840
2355
|
service.service_description.address,
|
|
1841
|
-
this._credential
|
|
2356
|
+
this._credential
|
|
1842
2357
|
);
|
|
1843
2358
|
}
|
|
1844
2359
|
}
|
|
@@ -1866,6 +2381,40 @@ class VoltClient extends EventEmitter__default["default"] {
|
|
|
1866
2381
|
return getVoltAPIClientInternal.call(this);
|
|
1867
2382
|
}
|
|
1868
2383
|
|
|
2384
|
+
unaryCall(method, request, service) {
|
|
2385
|
+
return unaryCallInternal.call(this, method, request, service);
|
|
2386
|
+
}
|
|
2387
|
+
|
|
2388
|
+
bidiStreamingCall(method, request, service) {
|
|
2389
|
+
return streamingCallInternal.call(
|
|
2390
|
+
this,
|
|
2391
|
+
"METHOD_TYPE_BIDI",
|
|
2392
|
+
method,
|
|
2393
|
+
request,
|
|
2394
|
+
service
|
|
2395
|
+
);
|
|
2396
|
+
}
|
|
2397
|
+
|
|
2398
|
+
clientStreamingCall(method, request, service) {
|
|
2399
|
+
return streamingCallInternal.call(
|
|
2400
|
+
this,
|
|
2401
|
+
"METHOD_TYPE_CLIENT_STREAM",
|
|
2402
|
+
method,
|
|
2403
|
+
request,
|
|
2404
|
+
service
|
|
2405
|
+
);
|
|
2406
|
+
}
|
|
2407
|
+
|
|
2408
|
+
serverStreamingCall(method, request, service) {
|
|
2409
|
+
return streamingCallInternal.call(
|
|
2410
|
+
this,
|
|
2411
|
+
"METHOD_TYPE_SERVER_STREAM",
|
|
2412
|
+
method,
|
|
2413
|
+
request,
|
|
2414
|
+
service
|
|
2415
|
+
);
|
|
2416
|
+
}
|
|
2417
|
+
|
|
1869
2418
|
/**
|
|
1870
2419
|
* Request resource access.
|
|
1871
2420
|
* @param {*} targetResourceId
|
|
@@ -1873,12 +2422,12 @@ class VoltClient extends EventEmitter__default["default"] {
|
|
|
1873
2422
|
*/
|
|
1874
2423
|
async RequestAccessBlocking(
|
|
1875
2424
|
targetResourceId,
|
|
1876
|
-
accessType = "VOLT_ACCESS_READ"
|
|
2425
|
+
accessType = "VOLT_ACCESS_READ"
|
|
1877
2426
|
) {
|
|
1878
2427
|
try {
|
|
1879
2428
|
const accessRequest = {
|
|
1880
2429
|
access: accessType,
|
|
1881
|
-
resource_id: targetResourceId
|
|
2430
|
+
resource_id: targetResourceId
|
|
1882
2431
|
};
|
|
1883
2432
|
|
|
1884
2433
|
// This will block while the request is pending.
|
|
@@ -1910,47 +2459,47 @@ class VoltClient extends EventEmitter__default["default"] {
|
|
|
1910
2459
|
*/
|
|
1911
2460
|
|
|
1912
2461
|
CanAccessResource(request) {
|
|
1913
|
-
return
|
|
2462
|
+
return unaryCallInternal.call(this, "CanAccessResource", request);
|
|
1914
2463
|
}
|
|
1915
2464
|
|
|
1916
2465
|
DeleteResource(request) {
|
|
1917
|
-
return
|
|
2466
|
+
return unaryCallInternal.call(this, "DeleteResource", request);
|
|
1918
2467
|
}
|
|
1919
2468
|
|
|
1920
2469
|
DiscoverServices(request) {
|
|
1921
|
-
return
|
|
2470
|
+
return unaryCallInternal.call(this, "DiscoverServices", request);
|
|
1922
2471
|
}
|
|
1923
2472
|
|
|
1924
2473
|
GetResource(request) {
|
|
1925
|
-
return
|
|
2474
|
+
return unaryCallInternal.call(this, "GetResource", request);
|
|
1926
2475
|
}
|
|
1927
2476
|
|
|
1928
2477
|
GetResources(request) {
|
|
1929
|
-
return
|
|
2478
|
+
return unaryCallInternal.call(this, "GetResources", request);
|
|
1930
2479
|
}
|
|
1931
2480
|
|
|
1932
2481
|
GetResourceAncestors(request) {
|
|
1933
|
-
return
|
|
2482
|
+
return unaryCallInternal.call(this, "GetResourceAncestors", request);
|
|
1934
2483
|
}
|
|
1935
2484
|
|
|
1936
2485
|
GetResourceDescendants(request) {
|
|
1937
|
-
return
|
|
2486
|
+
return unaryCallInternal.call(this, "GetResourceDescendants", request);
|
|
1938
2487
|
}
|
|
1939
2488
|
|
|
1940
2489
|
RequestAccess(request) {
|
|
1941
|
-
return
|
|
2490
|
+
return unaryCallInternal.call(this, "RequestAccess", request);
|
|
1942
2491
|
}
|
|
1943
2492
|
|
|
1944
2493
|
SaveResource(request) {
|
|
1945
|
-
return
|
|
2494
|
+
return unaryCallInternal.call(this, "SaveResource", request);
|
|
1946
2495
|
}
|
|
1947
2496
|
|
|
1948
2497
|
SaveResourceAttribute(request) {
|
|
1949
|
-
return
|
|
2498
|
+
return unaryCallInternal.call(this, "SaveResourceAttribute", request);
|
|
1950
2499
|
}
|
|
1951
2500
|
|
|
1952
2501
|
SetServiceStatus(request) {
|
|
1953
|
-
return
|
|
2502
|
+
return unaryCallInternal.call(this, "SetServiceStatus", request);
|
|
1954
2503
|
}
|
|
1955
2504
|
|
|
1956
2505
|
/**
|
|
@@ -1958,82 +2507,82 @@ class VoltClient extends EventEmitter__default["default"] {
|
|
|
1958
2507
|
*/
|
|
1959
2508
|
|
|
1960
2509
|
Bind(request) {
|
|
1961
|
-
return
|
|
2510
|
+
return unaryCallInternal.call(this, "Bind", request);
|
|
1962
2511
|
}
|
|
1963
2512
|
|
|
1964
2513
|
DeleteAccess(request) {
|
|
1965
|
-
return
|
|
2514
|
+
return unaryCallInternal.call(this, "DeleteAccess", request);
|
|
1966
2515
|
}
|
|
1967
2516
|
|
|
1968
2517
|
DeleteVolt(request) {
|
|
1969
|
-
return
|
|
2518
|
+
return unaryCallInternal.call(this, "DeleteVolt", request);
|
|
1970
2519
|
}
|
|
1971
2520
|
|
|
1972
2521
|
GetAccess(request) {
|
|
1973
|
-
return
|
|
2522
|
+
return unaryCallInternal.call(this, "GetAccess", request);
|
|
1974
2523
|
}
|
|
1975
2524
|
|
|
1976
2525
|
GetBindings(request) {
|
|
1977
|
-
return
|
|
2526
|
+
return unaryCallInternal.call(this, "GetBindings", request);
|
|
1978
2527
|
}
|
|
1979
2528
|
|
|
1980
2529
|
GetIdentities(request) {
|
|
1981
|
-
return
|
|
2530
|
+
return unaryCallInternal.call(this, "GetIdentities", request);
|
|
1982
2531
|
}
|
|
1983
2532
|
|
|
1984
2533
|
GetIdentity(request) {
|
|
1985
|
-
return
|
|
2534
|
+
return unaryCallInternal.call(this, "GetIdentity", request);
|
|
1986
2535
|
}
|
|
1987
2536
|
|
|
1988
2537
|
GetIdentityToken(request) {
|
|
1989
|
-
return
|
|
2538
|
+
return unaryCallInternal.call(this, "GetIdentityToken", request);
|
|
1990
2539
|
}
|
|
1991
2540
|
|
|
1992
2541
|
GetPolicy(request) {
|
|
1993
|
-
return
|
|
2542
|
+
return unaryCallInternal.call(this, "GetPolicy", request);
|
|
1994
2543
|
}
|
|
1995
2544
|
|
|
1996
2545
|
GetSettings(request) {
|
|
1997
|
-
return
|
|
2546
|
+
return unaryCallInternal.call(this, "GetSettings", request);
|
|
1998
2547
|
}
|
|
1999
2548
|
|
|
2000
2549
|
SaveAccess(request) {
|
|
2001
|
-
return
|
|
2550
|
+
return unaryCallInternal.call(this, "SaveAccess", request);
|
|
2002
2551
|
}
|
|
2003
2552
|
|
|
2004
2553
|
SaveCloudConnection(request) {
|
|
2005
|
-
return
|
|
2554
|
+
return unaryCallInternal.call(this, "SaveCloudConnection", request);
|
|
2006
2555
|
}
|
|
2007
2556
|
|
|
2008
2557
|
SaveIdentity(request) {
|
|
2009
|
-
return
|
|
2558
|
+
return unaryCallInternal.call(this, "SaveIdentity", request);
|
|
2010
2559
|
}
|
|
2011
2560
|
|
|
2012
2561
|
SaveSettings(request) {
|
|
2013
|
-
return
|
|
2562
|
+
return unaryCallInternal.call(this, "SaveSettings", request);
|
|
2014
2563
|
}
|
|
2015
2564
|
|
|
2016
2565
|
SetAccessRequestDecision(request) {
|
|
2017
|
-
return
|
|
2566
|
+
return unaryCallInternal.call(this, "SetAccessRequestDecision", request);
|
|
2018
2567
|
}
|
|
2019
2568
|
|
|
2020
2569
|
SetBindingDecision(request) {
|
|
2021
|
-
return
|
|
2570
|
+
return unaryCallInternal.call(this, "SetBindingDecision", request);
|
|
2022
2571
|
}
|
|
2023
2572
|
|
|
2024
2573
|
Shutdown(request) {
|
|
2025
|
-
return
|
|
2574
|
+
return unaryCallInternal.call(this, "Shutdown", request);
|
|
2026
2575
|
}
|
|
2027
2576
|
|
|
2028
2577
|
SignVerify(request) {
|
|
2029
|
-
return
|
|
2578
|
+
return unaryCallInternal.call(this, "SignVerify", request);
|
|
2030
2579
|
}
|
|
2031
2580
|
|
|
2032
2581
|
/**
|
|
2033
2582
|
* FileAPI
|
|
2034
2583
|
*/
|
|
2035
2584
|
GetFileDescendants(request) {
|
|
2036
|
-
return
|
|
2585
|
+
return unaryCallInternal.call(this, "GetFileDescendants", request);
|
|
2037
2586
|
}
|
|
2038
2587
|
|
|
2039
2588
|
/**
|
|
@@ -2047,11 +2596,19 @@ class VoltClient extends EventEmitter__default["default"] {
|
|
|
2047
2596
|
const downloadCall = new GRPCCall(
|
|
2048
2597
|
this,
|
|
2049
2598
|
"DownloadFile",
|
|
2050
|
-
"METHOD_TYPE_SERVER_STREAM"
|
|
2599
|
+
"METHOD_TYPE_SERVER_STREAM"
|
|
2051
2600
|
);
|
|
2052
2601
|
return downloadCall.start(grpcClient, request);
|
|
2053
2602
|
}
|
|
2054
2603
|
|
|
2604
|
+
GetFileContent(request) {
|
|
2605
|
+
return unaryCallInternal.call(this, "GetFileContent", request);
|
|
2606
|
+
}
|
|
2607
|
+
|
|
2608
|
+
SetFileContent(request) {
|
|
2609
|
+
return unaryCallInternal.call(this, "SetFileContent", request);
|
|
2610
|
+
}
|
|
2611
|
+
|
|
2055
2612
|
UploadFile(request) {
|
|
2056
2613
|
const grpcClient = this.getVoltAPIClient();
|
|
2057
2614
|
|
|
@@ -2073,7 +2630,7 @@ class VoltClient extends EventEmitter__default["default"] {
|
|
|
2073
2630
|
const call = new GRPCCall(
|
|
2074
2631
|
this,
|
|
2075
2632
|
"DownloadFile",
|
|
2076
|
-
"METHOD_TYPE_SERVER_STREAM"
|
|
2633
|
+
"METHOD_TYPE_SERVER_STREAM"
|
|
2077
2634
|
);
|
|
2078
2635
|
|
|
2079
2636
|
call.on("data", (response) => {
|
|
@@ -2111,6 +2668,10 @@ class VoltClient extends EventEmitter__default["default"] {
|
|
|
2111
2668
|
/**
|
|
2112
2669
|
* SqliteDatabaseAPI
|
|
2113
2670
|
*/
|
|
2671
|
+
BulkUpdate(request) {
|
|
2672
|
+
return unaryCallInternal.call(this, "BulkUpdate", request);
|
|
2673
|
+
}
|
|
2674
|
+
|
|
2114
2675
|
SqlExecute(request) {
|
|
2115
2676
|
const grpcClient = this.getVoltAPIClient();
|
|
2116
2677
|
|
|
@@ -2194,7 +2755,7 @@ class VoltClient extends EventEmitter__default["default"] {
|
|
|
2194
2755
|
const subscribeCall = new GRPCCall(
|
|
2195
2756
|
this,
|
|
2196
2757
|
"SubscribeWire",
|
|
2197
|
-
"METHOD_TYPE_BIDI"
|
|
2758
|
+
"METHOD_TYPE_BIDI"
|
|
2198
2759
|
);
|
|
2199
2760
|
return subscribeCall.start(grpcClient, request);
|
|
2200
2761
|
}
|