@tdxvolt/volt-client-grpc 0.14.60 → 0.14.134
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 +670 -160
- 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/proto-utils.js +37 -5
- package/src/rpc-invocation.js +273 -0
- package/src/volt-client-internal.js +135 -42
- package/src/volt-client.js +72 -31
- package/src/volt-connection.js +9 -0
- package/src/volt-credential.js +23 -7
package/lib/index.cjs
CHANGED
|
@@ -462,7 +462,7 @@ var grpcUtils = /*#__PURE__*/Object.freeze({
|
|
|
462
462
|
/* eslint-disable no-underscore-dangle */
|
|
463
463
|
|
|
464
464
|
const { pki: pki$1 } = forge__default["default"];
|
|
465
|
-
const log$
|
|
465
|
+
const log$5 = debug__default["default"]("volt-client-grpc:volt-credential");
|
|
466
466
|
const aesAlgorithm = "aes-256-cbc";
|
|
467
467
|
const rs256Algorithm = "RS256";
|
|
468
468
|
|
|
@@ -523,6 +523,18 @@ class VoltCredential {
|
|
|
523
523
|
return this._cryptoCache;
|
|
524
524
|
}
|
|
525
525
|
|
|
526
|
+
get clientId() {
|
|
527
|
+
return this._cryptoCache.client_id;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
get voltPublicKey() {
|
|
531
|
+
return this._voltPublicKey;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
get publicKey() {
|
|
535
|
+
return pki$1.publicKeyToPem(this.getKey().publicKey);
|
|
536
|
+
}
|
|
537
|
+
|
|
526
538
|
get voltFingerprint() {
|
|
527
539
|
return this._voltFingerprint;
|
|
528
540
|
}
|
|
@@ -539,17 +551,17 @@ class VoltCredential {
|
|
|
539
551
|
createKey() {
|
|
540
552
|
if (this._cryptoCache.key) {
|
|
541
553
|
// Already have key data in the cache in pem format => create fully-formed pki instances.
|
|
542
|
-
log$
|
|
554
|
+
log$5("createKey - key already exists");
|
|
543
555
|
return Promise.resolve(this.getKey());
|
|
544
556
|
} else {
|
|
545
|
-
log$
|
|
557
|
+
log$5("creating key");
|
|
546
558
|
return new Promise((resolve, reject) => {
|
|
547
559
|
pki$1.rsa.generateKeyPair({ bits: 2048, workers: -1 }, (err, keypair) => {
|
|
548
560
|
if (err) {
|
|
549
|
-
log$
|
|
561
|
+
log$5("failure creating key [%s]", err.message);
|
|
550
562
|
reject(err);
|
|
551
563
|
} else {
|
|
552
|
-
log$
|
|
564
|
+
log$5("successfully created key");
|
|
553
565
|
const pem = pki$1.privateKeyToPem(keypair.privateKey);
|
|
554
566
|
this._cryptoCache.key = pem;
|
|
555
567
|
resolve(keypair);
|
|
@@ -571,7 +583,7 @@ class VoltCredential {
|
|
|
571
583
|
return this._cryptoCache;
|
|
572
584
|
})
|
|
573
585
|
.catch((err) => {
|
|
574
|
-
log$
|
|
586
|
+
log$5("failure initialising crypto [%s]", err.message);
|
|
575
587
|
return Promise.reject(err);
|
|
576
588
|
});
|
|
577
589
|
}
|
|
@@ -586,7 +598,7 @@ class VoltCredential {
|
|
|
586
598
|
* @param {*} tunnelling flag indicating if the token is required for a tunnelled connection
|
|
587
599
|
* @param {*} ttl time to live in seconds (default to 1 minute)
|
|
588
600
|
*/
|
|
589
|
-
getIdentityToken(audience, tunnelling = false, ttl = 60) {
|
|
601
|
+
getIdentityToken(audience, publicKey, tunnelling = false, ttl = 60) {
|
|
590
602
|
if (!this._cryptoCache.key) {
|
|
591
603
|
throw new Error("crypto cache invalid");
|
|
592
604
|
}
|
|
@@ -595,7 +607,7 @@ class VoltCredential {
|
|
|
595
607
|
const publicKeyPem = pki$1.publicKeyToPem(keyPair.publicKey);
|
|
596
608
|
const base58Key = createPublicKeyFingerprint(publicKeyPem);
|
|
597
609
|
|
|
598
|
-
log$
|
|
610
|
+
log$5("base58 key is %s", base58Key);
|
|
599
611
|
|
|
600
612
|
// Allow TTL either side of the current time.
|
|
601
613
|
// @todo - fix with server time sync on volt connection.
|
|
@@ -612,11 +624,8 @@ class VoltCredential {
|
|
|
612
624
|
sharedKey = VoltCredential.aesCreateKey();
|
|
613
625
|
|
|
614
626
|
// Encrypt the key details using the target Volt public key and include this in the JWT payload.
|
|
615
|
-
payload.sk = VoltCredential.rsaEncrypt(
|
|
616
|
-
|
|
617
|
-
sharedKey.key,
|
|
618
|
-
);
|
|
619
|
-
payload.iv = VoltCredential.rsaEncrypt(this._voltPublicKey, sharedKey.iv);
|
|
627
|
+
payload.sk = VoltCredential.rsaEncrypt(publicKey, sharedKey.key);
|
|
628
|
+
payload.iv = VoltCredential.rsaEncrypt(publicKey, sharedKey.iv);
|
|
620
629
|
}
|
|
621
630
|
|
|
622
631
|
// Sign synchronously.
|
|
@@ -641,9 +650,10 @@ class VoltCredential {
|
|
|
641
650
|
* @param {*} ttl
|
|
642
651
|
* @returns
|
|
643
652
|
*/
|
|
644
|
-
getIdentityMetadata(grpc, audience, tunnelling = false, ttl = 60) {
|
|
653
|
+
getIdentityMetadata(grpc, audience, publicKey, tunnelling = false, ttl = 60) {
|
|
645
654
|
const identityToken = this.getIdentityToken(
|
|
646
655
|
audience || this._voltConfig.id,
|
|
656
|
+
publicKey,
|
|
647
657
|
tunnelling,
|
|
648
658
|
ttl,
|
|
649
659
|
);
|
|
@@ -689,6 +699,12 @@ class VoltCredential {
|
|
|
689
699
|
static rsaEncrypt(key, buffer) {
|
|
690
700
|
return crypto__default["default"].publicEncrypt(key, buffer).toString("base64");
|
|
691
701
|
}
|
|
702
|
+
|
|
703
|
+
static rsaDecrypt(key, buffer) {
|
|
704
|
+
const keyObj = crypto__default["default"].createPrivateKey(key);
|
|
705
|
+
const cipher = Buffer.from(buffer, "base64");
|
|
706
|
+
return Buffer.from(crypto__default["default"].privateDecrypt(keyObj, cipher));
|
|
707
|
+
}
|
|
692
708
|
}
|
|
693
709
|
|
|
694
710
|
const { get: getProp, snakeCase } = lodash__default["default"];
|
|
@@ -705,23 +721,23 @@ const defaultLoaderOptions = {
|
|
|
705
721
|
includeDirs: [defaultProtoPath],
|
|
706
722
|
};
|
|
707
723
|
|
|
708
|
-
|
|
724
|
+
function getProtoDescriptors(grpc, protoPath, opts) {
|
|
709
725
|
const definition = protoLoader__default["default"].loadSync(
|
|
710
726
|
protoPath,
|
|
711
727
|
opts || defaultLoaderOptions,
|
|
712
728
|
);
|
|
713
729
|
const descriptors = grpc.loadPackageDefinition(definition);
|
|
714
730
|
return descriptors;
|
|
715
|
-
}
|
|
731
|
+
}
|
|
716
732
|
|
|
717
|
-
|
|
733
|
+
function getProtoService(descriptors, servicePath) {
|
|
718
734
|
const serviceDef = getProp(descriptors, servicePath);
|
|
719
735
|
if (serviceDef?.service) {
|
|
720
736
|
return serviceDef.service;
|
|
721
737
|
} else {
|
|
722
738
|
return null;
|
|
723
739
|
}
|
|
724
|
-
}
|
|
740
|
+
}
|
|
725
741
|
|
|
726
742
|
function getServiceDescriptorsFromPath(
|
|
727
743
|
grpc,
|
|
@@ -729,8 +745,30 @@ function getServiceDescriptorsFromPath(
|
|
|
729
745
|
servicePackageName,
|
|
730
746
|
opts,
|
|
731
747
|
) {
|
|
748
|
+
if (!opts) {
|
|
749
|
+
opts = { ...defaultLoaderOptions };
|
|
750
|
+
opts.includeDirs = [protoPath];
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
// Extract the package components of the service proto package. The package name should be of the
|
|
754
|
+
// fully qualified proto path, e.g. tdx.volt_api.webcam.v1.WebcamControlAPI.
|
|
755
|
+
const protoServiceComponents = servicePackageName.split(".");
|
|
756
|
+
|
|
757
|
+
// The service name is the last component of the path.
|
|
758
|
+
const protoServiceName = protoServiceComponents.pop();
|
|
759
|
+
|
|
760
|
+
// The actual file name should match the snake case of the service name.
|
|
761
|
+
const protoFileName = `${snakeCase(protoServiceName).toLowerCase()}.proto`;
|
|
762
|
+
|
|
763
|
+
// The path to the proto file should match each component of the package name.
|
|
764
|
+
const serviceProtoPath = path.join(
|
|
765
|
+
protoPath,
|
|
766
|
+
...protoServiceComponents,
|
|
767
|
+
protoFileName,
|
|
768
|
+
);
|
|
769
|
+
|
|
732
770
|
let serviceDescriptors;
|
|
733
|
-
const descriptors = getProtoDescriptors(grpc,
|
|
771
|
+
const descriptors = getProtoDescriptors(grpc, serviceProtoPath, opts);
|
|
734
772
|
if (descriptors) {
|
|
735
773
|
serviceDescriptors = getProtoService(descriptors, servicePackageName);
|
|
736
774
|
}
|
|
@@ -778,8 +816,17 @@ function getProtoDescriptorMethods(protoDescriptor) {
|
|
|
778
816
|
return methods;
|
|
779
817
|
}
|
|
780
818
|
|
|
819
|
+
function createServiceProtobufFiles(service, protoPath) {
|
|
820
|
+
for (let protoFile of service.service_description.proto_file) {
|
|
821
|
+
const filePath = path.join(protoPath, protoFile.file_path);
|
|
822
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
823
|
+
fs.writeFileSync(filePath, protoFile.protobuf);
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
|
|
781
827
|
var protoUtils = /*#__PURE__*/Object.freeze({
|
|
782
828
|
__proto__: null,
|
|
829
|
+
createServiceProtobufFiles: createServiceProtobufFiles,
|
|
783
830
|
getServiceDescriptors: getServiceDescriptors,
|
|
784
831
|
getProtoDescriptors: getProtoDescriptors,
|
|
785
832
|
getProtoDescriptorMethods: getProtoDescriptorMethods,
|
|
@@ -788,70 +835,101 @@ var protoUtils = /*#__PURE__*/Object.freeze({
|
|
|
788
835
|
|
|
789
836
|
/* eslint-disable no-underscore-dangle */
|
|
790
837
|
|
|
791
|
-
const log$
|
|
838
|
+
const log$4 = debug__default["default"]("volt-client-grpc:grpc-call");
|
|
792
839
|
|
|
793
840
|
function _prepareInvokeRequest(
|
|
794
841
|
request,
|
|
795
842
|
method,
|
|
796
843
|
methodType = "METHOD_TYPE_UNARY",
|
|
797
844
|
) {
|
|
798
|
-
const
|
|
845
|
+
const isServiceRelayed =
|
|
846
|
+
this._service?.service_description.host_type ===
|
|
847
|
+
"SERVICE_HOST_TYPE_RELAYED";
|
|
848
|
+
|
|
849
|
+
// Use the service's host client id and public key if the service is relayed.
|
|
850
|
+
const methodToken = this._voltClient.credential.getIdentityMetadata(
|
|
799
851
|
this._voltClient.grpc,
|
|
800
|
-
this.
|
|
801
|
-
|
|
852
|
+
this._service?.service_description.host_client_id ||
|
|
853
|
+
this._voltClient.voltConfig.id,
|
|
854
|
+
this._service?.service_description.host_public_key ||
|
|
855
|
+
this._voltClient.credential.voltPublicKey,
|
|
856
|
+
true,
|
|
802
857
|
);
|
|
858
|
+
|
|
803
859
|
let invokeRequest;
|
|
804
860
|
let callMethod = method;
|
|
805
861
|
|
|
806
|
-
if (this._voltClient.isVoltRelay) {
|
|
862
|
+
if (this._voltClient.isVoltRelay || isServiceRelayed) {
|
|
863
|
+
//
|
|
864
|
+
// If the volt connection is via a relay (or the target service is relayed),
|
|
865
|
+
// we wrap the rpc in a RemoteRequest message and send it via a call to Invoke().
|
|
866
|
+
//
|
|
807
867
|
let requestPayload;
|
|
868
|
+
|
|
869
|
+
// Serialise the rpc request.
|
|
808
870
|
if (request) {
|
|
809
871
|
requestPayload = this._grpcClient[method].requestSerialize(request);
|
|
810
872
|
} else if (request !== null) {
|
|
811
|
-
log$
|
|
873
|
+
log$4("****************LOOKOUT****************** - empty request");
|
|
812
874
|
} else {
|
|
813
|
-
log$
|
|
875
|
+
log$4("explicit empty request payload");
|
|
814
876
|
}
|
|
815
877
|
|
|
816
|
-
|
|
878
|
+
// Use this placeholder to serialise the relay request wrapper.
|
|
879
|
+
const voltGrpcClient = this._voltClient.getVoltAPIClient();
|
|
880
|
+
const tunnelMethod = voltGrpcClient.Tunnel;
|
|
817
881
|
|
|
818
882
|
const tunnelResp = {
|
|
819
883
|
method_invoke: {
|
|
820
884
|
method_name: this._grpcClient[method].path,
|
|
821
885
|
method_type: methodType,
|
|
822
|
-
token:
|
|
886
|
+
token: methodToken.token,
|
|
823
887
|
request: requestPayload,
|
|
824
888
|
},
|
|
825
889
|
};
|
|
826
890
|
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
891
|
+
let targetFingerprint = [];
|
|
892
|
+
let invokePayload;
|
|
893
|
+
if (this._voltClient.isVoltRelay || isServiceRelayed) {
|
|
894
|
+
// When sending via a relay we need to encrypt the payload.
|
|
895
|
+
invokePayload = VoltCredential.aesEncrypt(
|
|
896
|
+
tunnelMethod.responseSerialize(tunnelResp),
|
|
897
|
+
methodToken.sharedKey.key,
|
|
898
|
+
methodToken.sharedKey.iv,
|
|
899
|
+
);
|
|
900
|
+
} else {
|
|
901
|
+
invokePayload = tunnelMethod.responseSerialize(tunnelResp);
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
if (this._voltClient.isVoltRelay) {
|
|
905
|
+
targetFingerprint.push(this._voltClient.credential.voltFingerprint);
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
if (isServiceRelayed) {
|
|
909
|
+
// Add another relay hop if the target service is relayed.
|
|
910
|
+
log$4("target service is relayed");
|
|
911
|
+
targetFingerprint.push(
|
|
912
|
+
this._service.service_description.host_fingerprint,
|
|
913
|
+
);
|
|
914
|
+
}
|
|
832
915
|
|
|
833
|
-
log$
|
|
916
|
+
log$4("target is %j", targetFingerprint);
|
|
834
917
|
|
|
835
918
|
invokeRequest = {
|
|
836
|
-
|
|
919
|
+
target_fingerprint: targetFingerprint,
|
|
920
|
+
token: methodToken.token,
|
|
837
921
|
payload: invokePayload,
|
|
922
|
+
target_service_id: isServiceRelayed ? this._service.id : undefined,
|
|
838
923
|
};
|
|
839
924
|
|
|
925
|
+
// Replace the target method with a call to Invoke on the relay Volt.
|
|
840
926
|
callMethod = "Invoke";
|
|
841
|
-
} else if (this._voltClient.isRemote && meta.sharedKey.key) {
|
|
842
|
-
const requestPayload =
|
|
843
|
-
this._grpcClient[method].requestSerializeOriginal(request);
|
|
844
|
-
invokeRequest = VoltCredential.aesEncrypt(
|
|
845
|
-
requestPayload,
|
|
846
|
-
meta.sharedKey.key,
|
|
847
|
-
meta.sharedKey.iv,
|
|
848
|
-
);
|
|
849
927
|
} else {
|
|
850
928
|
invokeRequest = request;
|
|
851
929
|
}
|
|
852
930
|
|
|
853
931
|
return {
|
|
854
|
-
meta,
|
|
932
|
+
meta: methodToken,
|
|
855
933
|
method: callMethod,
|
|
856
934
|
methodName: method,
|
|
857
935
|
request: invokeRequest,
|
|
@@ -861,10 +939,16 @@ function _prepareInvokeRequest(
|
|
|
861
939
|
function _preparePayloadRequest(request, invokeInfo) {
|
|
862
940
|
let payloadRequest;
|
|
863
941
|
|
|
864
|
-
|
|
942
|
+
const isServiceRelayed =
|
|
943
|
+
this._service?.service_description.host_type ===
|
|
944
|
+
"SERVICE_HOST_TYPE_RELAYED";
|
|
945
|
+
|
|
946
|
+
if (this._voltClient.isVoltRelay || isServiceRelayed) {
|
|
865
947
|
const requestPayload =
|
|
866
948
|
this._grpcClient[invokeInfo.methodName].requestSerialize(request);
|
|
867
|
-
|
|
949
|
+
|
|
950
|
+
const voltGrpcClient = this._voltClient.getVoltAPIClient();
|
|
951
|
+
const tunnelMethod = voltGrpcClient.Tunnel;
|
|
868
952
|
|
|
869
953
|
const tunnelResp = {
|
|
870
954
|
method_payload: {
|
|
@@ -881,14 +965,6 @@ function _preparePayloadRequest(request, invokeInfo) {
|
|
|
881
965
|
payloadRequest = {
|
|
882
966
|
payload: invokePayload,
|
|
883
967
|
};
|
|
884
|
-
} else if (this._voltClient.isRemote && invokeInfo.meta.sharedKey.key) {
|
|
885
|
-
const requestPayload =
|
|
886
|
-
this._grpcClient[invokeInfo.methodName].requestSerializeOriginal(request);
|
|
887
|
-
payloadRequest = VoltCredential.aesEncrypt(
|
|
888
|
-
requestPayload,
|
|
889
|
-
invokeInfo.meta.sharedKey.key,
|
|
890
|
-
invokeInfo.meta.sharedKey.iv,
|
|
891
|
-
);
|
|
892
968
|
} else {
|
|
893
969
|
payloadRequest = request;
|
|
894
970
|
}
|
|
@@ -897,29 +973,47 @@ function _preparePayloadRequest(request, invokeInfo) {
|
|
|
897
973
|
}
|
|
898
974
|
|
|
899
975
|
function _parseResponse(method, meta, response) {
|
|
976
|
+
// log("parseResponse for %s", this._methodName);
|
|
900
977
|
let invokeResponse = {};
|
|
901
978
|
|
|
902
|
-
|
|
979
|
+
const isServiceRelayed =
|
|
980
|
+
this._service?.service_description.host_type ===
|
|
981
|
+
"SERVICE_HOST_TYPE_RELAYED";
|
|
982
|
+
|
|
983
|
+
if (this._voltClient.isVoltRelay || isServiceRelayed) {
|
|
903
984
|
if (response.payload) {
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
985
|
+
let decryptedPayload;
|
|
986
|
+
if (meta.sharedKey.key) {
|
|
987
|
+
decryptedPayload = VoltCredential.aesDecrypt(
|
|
988
|
+
response.payload,
|
|
989
|
+
meta.sharedKey.key,
|
|
990
|
+
meta.sharedKey.iv,
|
|
991
|
+
);
|
|
992
|
+
} else {
|
|
993
|
+
decryptedPayload = response.payload;
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
const tunnelMethod = this._voltClient.getVoltAPIClient().Tunnel;
|
|
910
997
|
const responsePayload = tunnelMethod.requestDeserialize(decryptedPayload);
|
|
911
998
|
if (responsePayload.payload === "method_payload") {
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
999
|
+
try {
|
|
1000
|
+
invokeResponse.payload = this._grpcClient[method].responseDeserialize(
|
|
1001
|
+
responsePayload.method_payload.payload,
|
|
1002
|
+
);
|
|
1003
|
+
} catch (err) {
|
|
1004
|
+
log$4("failure deserialising payload for %s", this._methodName);
|
|
1005
|
+
throw new Error(
|
|
1006
|
+
"failure deserialising payload - check protobuf definition matches with data being sent",
|
|
1007
|
+
);
|
|
1008
|
+
}
|
|
915
1009
|
} else if (responsePayload.payload === "method_end") {
|
|
916
1010
|
invokeResponse = responsePayload.method_end;
|
|
917
1011
|
} else {
|
|
918
|
-
log$
|
|
1012
|
+
log$4("unexpected tunnel payload type: %s", responsePayload.payload);
|
|
919
1013
|
}
|
|
920
1014
|
} else if (response.status?.message) {
|
|
921
1015
|
// There's been an error in the tunnel.
|
|
922
|
-
log$
|
|
1016
|
+
log$4(
|
|
923
1017
|
"Tunnel status received: %s, code %d, description: %s",
|
|
924
1018
|
response.status.message,
|
|
925
1019
|
response.status.code,
|
|
@@ -931,7 +1025,7 @@ function _parseResponse(method, meta, response) {
|
|
|
931
1025
|
};
|
|
932
1026
|
} else {
|
|
933
1027
|
invokeResponse.methodId = response.invoke_id;
|
|
934
|
-
log$
|
|
1028
|
+
log$4("started method %d for %s", invokeResponse.methodId, method);
|
|
935
1029
|
}
|
|
936
1030
|
} else if (this._voltClient.isRemote && meta.sharedKey.key) {
|
|
937
1031
|
const decryptedPayload = VoltCredential.aesDecrypt(
|
|
@@ -951,17 +1045,22 @@ function _parseResponse(method, meta, response) {
|
|
|
951
1045
|
}
|
|
952
1046
|
|
|
953
1047
|
class GRPCCall extends EventEmitter__default["default"] {
|
|
954
|
-
constructor(voltClient, methodName, methodType) {
|
|
1048
|
+
constructor(voltClient, methodName, methodType, service = undefined) {
|
|
955
1049
|
super();
|
|
956
1050
|
this._methodName = methodName;
|
|
957
1051
|
this._methodType = methodType;
|
|
958
1052
|
this._call = null;
|
|
959
1053
|
this._voltClient = voltClient;
|
|
1054
|
+
this._service = service;
|
|
960
1055
|
}
|
|
961
1056
|
|
|
962
1057
|
start(grpcClient, request) {
|
|
963
1058
|
this._grpcClient = grpcClient;
|
|
964
1059
|
|
|
1060
|
+
if (typeof this._grpcClient[this._methodName] !== "function") {
|
|
1061
|
+
throw new Error(`method not found: '${this._methodName}'`);
|
|
1062
|
+
}
|
|
1063
|
+
|
|
965
1064
|
this._initialRequest = _prepareInvokeRequest.call(
|
|
966
1065
|
this,
|
|
967
1066
|
request,
|
|
@@ -969,13 +1068,18 @@ class GRPCCall extends EventEmitter__default["default"] {
|
|
|
969
1068
|
this._methodType,
|
|
970
1069
|
);
|
|
971
1070
|
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
1071
|
+
const isServiceRelayed =
|
|
1072
|
+
this._service?.service_description.host_type ===
|
|
1073
|
+
"SERVICE_HOST_TYPE_RELAYED";
|
|
1074
|
+
|
|
1075
|
+
let callClient;
|
|
1076
|
+
if (this._voltClient.isVoltRelay || isServiceRelayed) {
|
|
1077
|
+
callClient = this._voltClient.getVoltAPIClient();
|
|
1078
|
+
} else {
|
|
1079
|
+
callClient = this._grpcClient;
|
|
976
1080
|
}
|
|
977
1081
|
|
|
978
|
-
this._call =
|
|
1082
|
+
this._call = callClient[this._initialRequest.method](
|
|
979
1083
|
this._initialRequest.meta.metadata,
|
|
980
1084
|
);
|
|
981
1085
|
|
|
@@ -1005,28 +1109,32 @@ class GRPCCall extends EventEmitter__default["default"] {
|
|
|
1005
1109
|
this.emit("end");
|
|
1006
1110
|
}
|
|
1007
1111
|
} else {
|
|
1008
|
-
log$
|
|
1112
|
+
log$4("method id is %s", parsedResponse.methodId);
|
|
1009
1113
|
}
|
|
1010
1114
|
} catch (err) {
|
|
1011
|
-
log$
|
|
1115
|
+
log$4(
|
|
1116
|
+
"failure processing %s call response: %s",
|
|
1117
|
+
this._methodName,
|
|
1118
|
+
err.message,
|
|
1119
|
+
);
|
|
1012
1120
|
this.emit("error", err);
|
|
1013
1121
|
}
|
|
1014
1122
|
});
|
|
1015
1123
|
|
|
1016
1124
|
this._call.on("error", (err) => {
|
|
1017
|
-
log$
|
|
1125
|
+
log$4("ERROR - intercepted stream error %s", err.message);
|
|
1018
1126
|
this.emit("error", err);
|
|
1019
1127
|
});
|
|
1020
1128
|
|
|
1021
1129
|
this._call.on("finish", () => {
|
|
1022
1130
|
// The read side has ended (i.e. we called end()).
|
|
1023
|
-
log$
|
|
1131
|
+
log$4("finished call %s", this._methodName);
|
|
1024
1132
|
this.emit("finish");
|
|
1025
1133
|
});
|
|
1026
1134
|
|
|
1027
1135
|
this._call.on("end", () => {
|
|
1028
1136
|
// The remote peer ended the stream.
|
|
1029
|
-
log$
|
|
1137
|
+
log$4(
|
|
1030
1138
|
"ended call %s, method id: %s",
|
|
1031
1139
|
this._methodName,
|
|
1032
1140
|
this._initialRequest.methodId || "n/a - not tunnelling",
|
|
@@ -1056,7 +1164,7 @@ class GRPCCall extends EventEmitter__default["default"] {
|
|
|
1056
1164
|
|
|
1057
1165
|
write(request) {
|
|
1058
1166
|
if (!this._call) {
|
|
1059
|
-
log$
|
|
1167
|
+
log$4("ERROR - call not initialised");
|
|
1060
1168
|
throw new Error("call not initialised");
|
|
1061
1169
|
} else if (this._initialRequest) {
|
|
1062
1170
|
const payloadRequest = _preparePayloadRequest.call(
|
|
@@ -1080,7 +1188,7 @@ class GRPCCall extends EventEmitter__default["default"] {
|
|
|
1080
1188
|
|
|
1081
1189
|
/* eslint-disable no-use-before-define */
|
|
1082
1190
|
|
|
1083
|
-
const log$
|
|
1191
|
+
const log$3 = debug__default["default"]("volt-client-grpc:volt-connection");
|
|
1084
1192
|
|
|
1085
1193
|
function _cleanUp(immediateReconnect) {
|
|
1086
1194
|
this._connectionId = "";
|
|
@@ -1114,7 +1222,7 @@ function _cleanUp(immediateReconnect) {
|
|
|
1114
1222
|
}
|
|
1115
1223
|
|
|
1116
1224
|
function _connectionTimeoutHandler() {
|
|
1117
|
-
log$
|
|
1225
|
+
log$3("server timed out");
|
|
1118
1226
|
this.emit("connected", false);
|
|
1119
1227
|
_cleanUp.call(this);
|
|
1120
1228
|
}
|
|
@@ -1126,14 +1234,14 @@ function _doConnect(connectHello) {
|
|
|
1126
1234
|
|
|
1127
1235
|
let helloPayload = connectHello;
|
|
1128
1236
|
if (!connectHello) {
|
|
1129
|
-
log$
|
|
1237
|
+
log$3("defaulting hello payload");
|
|
1130
1238
|
helloPayload = {
|
|
1131
1239
|
hello: {},
|
|
1132
1240
|
};
|
|
1133
1241
|
}
|
|
1134
1242
|
|
|
1135
1243
|
this.call.on("error", (err) => {
|
|
1136
|
-
log$
|
|
1244
|
+
log$3("error on connection stream [%s]", err.message);
|
|
1137
1245
|
_cleanUp.call(this);
|
|
1138
1246
|
this.emit("error", err);
|
|
1139
1247
|
});
|
|
@@ -1141,7 +1249,7 @@ function _doConnect(connectHello) {
|
|
|
1141
1249
|
this.call.on("data", (response) => {
|
|
1142
1250
|
switch (response.payload) {
|
|
1143
1251
|
case "ping": {
|
|
1144
|
-
log$
|
|
1252
|
+
log$3("pinged");
|
|
1145
1253
|
|
|
1146
1254
|
// Received ping response from server => clear timeout.
|
|
1147
1255
|
if (this._pingTimeoutTimer) {
|
|
@@ -1155,18 +1263,23 @@ function _doConnect(connectHello) {
|
|
|
1155
1263
|
case "acknowledge": {
|
|
1156
1264
|
if (!this._connectionId) {
|
|
1157
1265
|
this._connectionId = response.acknowledge.connection_id;
|
|
1158
|
-
log$
|
|
1266
|
+
log$3("connection id is %s", this._connectionId);
|
|
1159
1267
|
this.emit("connected", this._connectionId);
|
|
1160
1268
|
}
|
|
1161
1269
|
break;
|
|
1162
1270
|
}
|
|
1271
|
+
case "invoke_request": {
|
|
1272
|
+
log$3("received invoke request");
|
|
1273
|
+
this.emit("invoke_request", response.invoke_request);
|
|
1274
|
+
break;
|
|
1275
|
+
}
|
|
1163
1276
|
case "evt": {
|
|
1164
|
-
log$
|
|
1277
|
+
log$3("received event %s", response.evt.event_type);
|
|
1165
1278
|
this.emit("evt", response.evt);
|
|
1166
1279
|
break;
|
|
1167
1280
|
}
|
|
1168
1281
|
default:
|
|
1169
|
-
log$
|
|
1282
|
+
log$3("unimplemented connect response payload: %s", response.payload);
|
|
1170
1283
|
break;
|
|
1171
1284
|
}
|
|
1172
1285
|
});
|
|
@@ -1185,7 +1298,7 @@ function _doConnect(connectHello) {
|
|
|
1185
1298
|
|
|
1186
1299
|
function _startPingTimer() {
|
|
1187
1300
|
if (this._pingTimer) {
|
|
1188
|
-
log$
|
|
1301
|
+
log$3("ping timer running");
|
|
1189
1302
|
return;
|
|
1190
1303
|
}
|
|
1191
1304
|
|
|
@@ -1193,7 +1306,7 @@ function _startPingTimer() {
|
|
|
1193
1306
|
// Send next ping to server.
|
|
1194
1307
|
const request = { ping: { timestamp: Date.now() } };
|
|
1195
1308
|
|
|
1196
|
-
log$
|
|
1309
|
+
log$3("pinging Volt");
|
|
1197
1310
|
this.call.write(request);
|
|
1198
1311
|
|
|
1199
1312
|
this._pingTimer = 0;
|
|
@@ -1242,6 +1355,277 @@ class VoltConnection extends EventEmitter__default["default"] {
|
|
|
1242
1355
|
this._dying = true;
|
|
1243
1356
|
_cleanUp.call(this);
|
|
1244
1357
|
}
|
|
1358
|
+
|
|
1359
|
+
send(request) {
|
|
1360
|
+
this.call.write(request);
|
|
1361
|
+
}
|
|
1362
|
+
}
|
|
1363
|
+
|
|
1364
|
+
const log$2 = debug__default["default"]("rpc-invocation");
|
|
1365
|
+
|
|
1366
|
+
class RpcInvocation extends EventEmitter__default["default"] {
|
|
1367
|
+
#voltClient = null;
|
|
1368
|
+
#voltConnection = null;
|
|
1369
|
+
#token = null;
|
|
1370
|
+
#encryptKey = null;
|
|
1371
|
+
#encryptIV = null;
|
|
1372
|
+
#invokeId = null;
|
|
1373
|
+
#payload = null;
|
|
1374
|
+
#isJSON = false;
|
|
1375
|
+
#methodDescriptor = null;
|
|
1376
|
+
#methodName = null;
|
|
1377
|
+
|
|
1378
|
+
constructor(voltClient, voltConnection) {
|
|
1379
|
+
super();
|
|
1380
|
+
this.#voltClient = voltClient;
|
|
1381
|
+
this.#voltConnection = voltConnection;
|
|
1382
|
+
}
|
|
1383
|
+
|
|
1384
|
+
get id() {
|
|
1385
|
+
return this.#invokeId;
|
|
1386
|
+
}
|
|
1387
|
+
|
|
1388
|
+
get payload() {
|
|
1389
|
+
if (!this.#payload) {
|
|
1390
|
+
return null;
|
|
1391
|
+
}
|
|
1392
|
+
|
|
1393
|
+
let deserialisedPayload = null;
|
|
1394
|
+
|
|
1395
|
+
if (this.#isJSON) {
|
|
1396
|
+
// Don't need to deserialise JSON payload.
|
|
1397
|
+
deserialisedPayload = this.#payload;
|
|
1398
|
+
} else if (this.#methodDescriptor) {
|
|
1399
|
+
deserialisedPayload = this.#methodDescriptor.requestDeserialize(
|
|
1400
|
+
this.#payload,
|
|
1401
|
+
);
|
|
1402
|
+
} else {
|
|
1403
|
+
log$2("unexpected: no method descriptor");
|
|
1404
|
+
throw new Error(
|
|
1405
|
+
"no method descriptor - set this before accessing payload",
|
|
1406
|
+
);
|
|
1407
|
+
}
|
|
1408
|
+
|
|
1409
|
+
return deserialisedPayload;
|
|
1410
|
+
}
|
|
1411
|
+
|
|
1412
|
+
get methodName() {
|
|
1413
|
+
return this.#methodName;
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1416
|
+
set methodDescriptor(methodDescriptor) {
|
|
1417
|
+
this.#methodDescriptor = methodDescriptor;
|
|
1418
|
+
}
|
|
1419
|
+
|
|
1420
|
+
#decodeToken(token) {
|
|
1421
|
+
// We don't verify the token at this point, as we don't know the public key.
|
|
1422
|
+
// The rpc implementation should do the verification using the Volt API (e.g. CanAccessResource).
|
|
1423
|
+
this.#token = jwt__default["default"].decode(token);
|
|
1424
|
+
|
|
1425
|
+
if (this.#token.sk) {
|
|
1426
|
+
// Decrypt the shared key and iv using the private key.
|
|
1427
|
+
this.#encryptKey = VoltCredential.rsaDecrypt(
|
|
1428
|
+
this.#voltClient.credential.cache.key,
|
|
1429
|
+
this.#token.sk,
|
|
1430
|
+
);
|
|
1431
|
+
this.#encryptIV = VoltCredential.rsaDecrypt(
|
|
1432
|
+
this.#voltClient.credential.cache.key,
|
|
1433
|
+
this.#token.iv,
|
|
1434
|
+
);
|
|
1435
|
+
}
|
|
1436
|
+
|
|
1437
|
+
return Promise.resolve(this.#token);
|
|
1438
|
+
}
|
|
1439
|
+
|
|
1440
|
+
initialise(invoke_request) {
|
|
1441
|
+
this.#invokeId = invoke_request.invoke_id;
|
|
1442
|
+
|
|
1443
|
+
return this.#decodeToken(invoke_request.token)
|
|
1444
|
+
.then(() => {
|
|
1445
|
+
// Parse the initial payload.
|
|
1446
|
+
return this.parsePayload(invoke_request);
|
|
1447
|
+
})
|
|
1448
|
+
.catch((err) => {
|
|
1449
|
+
log$2("failure initialising invocation: %s", err.message);
|
|
1450
|
+
return Promise.reject(err);
|
|
1451
|
+
});
|
|
1452
|
+
}
|
|
1453
|
+
|
|
1454
|
+
parsePayload(invoke_request) {
|
|
1455
|
+
return new Promise((resolve, reject) => {
|
|
1456
|
+
if (invoke_request.payload) {
|
|
1457
|
+
let decryptedPayload;
|
|
1458
|
+
|
|
1459
|
+
if (this.#encryptKey) {
|
|
1460
|
+
// Decrypt the actual payload using the shared key and iv.
|
|
1461
|
+
decryptedPayload = VoltCredential.aesDecrypt(
|
|
1462
|
+
invoke_request.payload,
|
|
1463
|
+
this.#encryptKey,
|
|
1464
|
+
this.#encryptIV,
|
|
1465
|
+
);
|
|
1466
|
+
} else {
|
|
1467
|
+
// No encryption => just use the payload.
|
|
1468
|
+
decryptedPayload = invoke_request.payload;
|
|
1469
|
+
}
|
|
1470
|
+
|
|
1471
|
+
const tunnelMethod = this.#voltClient.getVoltAPIClient().Tunnel;
|
|
1472
|
+
const wrappedPayload =
|
|
1473
|
+
tunnelMethod.responseDeserialize(decryptedPayload);
|
|
1474
|
+
|
|
1475
|
+
if (wrappedPayload.method_invoke) {
|
|
1476
|
+
// This is the initial request payload.
|
|
1477
|
+
this.#methodName = wrappedPayload.method_invoke.method_name;
|
|
1478
|
+
this.#payload = wrappedPayload.method_invoke.request;
|
|
1479
|
+
this.emit("payload", this);
|
|
1480
|
+
} else if (wrappedPayload.method_payload) {
|
|
1481
|
+
// This is a subsequent payload, e.g. for streaming rpcs.
|
|
1482
|
+
this.#payload = wrappedPayload.method_payload.payload;
|
|
1483
|
+
this.emit("payload", this);
|
|
1484
|
+
} else if (wrappedPayload.method_end) {
|
|
1485
|
+
// This indicates the client has finished sending payloads.
|
|
1486
|
+
// We don't need to do anything here, since we notify the client when we receive the client_end.
|
|
1487
|
+
log$2("method_end received");
|
|
1488
|
+
}
|
|
1489
|
+
|
|
1490
|
+
resolve();
|
|
1491
|
+
} else if (invoke_request.json_payload) {
|
|
1492
|
+
let decryptedPayload;
|
|
1493
|
+
|
|
1494
|
+
this.#isJSON = true;
|
|
1495
|
+
|
|
1496
|
+
if (this.#encryptKey) {
|
|
1497
|
+
// Decrypt the actual payload using the shared key and iv.
|
|
1498
|
+
decryptedPayload = VoltCredential.aesDecrypt(
|
|
1499
|
+
Buffer.from(invoke_request.json_payload, "base64"),
|
|
1500
|
+
this.#encryptKey,
|
|
1501
|
+
this.#encryptIV,
|
|
1502
|
+
);
|
|
1503
|
+
} else {
|
|
1504
|
+
// No encryption => just use the payload.
|
|
1505
|
+
decryptedPayload = invoke_request.json_payload;
|
|
1506
|
+
}
|
|
1507
|
+
|
|
1508
|
+
try {
|
|
1509
|
+
const wrappedPayload = JSON.parse(decryptedPayload.toString());
|
|
1510
|
+
|
|
1511
|
+
if (wrappedPayload.method_invoke) {
|
|
1512
|
+
this.#methodName = wrappedPayload.method_invoke.method_name;
|
|
1513
|
+
this.#payload = JSON.parse(
|
|
1514
|
+
wrappedPayload.method_invoke.json_request,
|
|
1515
|
+
);
|
|
1516
|
+
this.emit("payload", this);
|
|
1517
|
+
} else if (wrappedPayload.method_payload) {
|
|
1518
|
+
this.#payload = JSON.parse(
|
|
1519
|
+
wrappedPayload.method_payload.json_payload,
|
|
1520
|
+
);
|
|
1521
|
+
this.emit("payload", this);
|
|
1522
|
+
} else if (wrappedPayload.method_end) {
|
|
1523
|
+
// We don't need to do anything here, since we notify the client when we receive the client_end.
|
|
1524
|
+
log$2("method_end received");
|
|
1525
|
+
}
|
|
1526
|
+
} catch (err) {
|
|
1527
|
+
log$2("JSON.parse failure parsing json_payload: %s", err.message);
|
|
1528
|
+
reject(err);
|
|
1529
|
+
}
|
|
1530
|
+
|
|
1531
|
+
resolve();
|
|
1532
|
+
} else if (invoke_request.client_end) {
|
|
1533
|
+
this.emit("end", this);
|
|
1534
|
+
} else {
|
|
1535
|
+
// Do we need to support json_payload here?
|
|
1536
|
+
reject(new Error("No payload in invoke request"));
|
|
1537
|
+
}
|
|
1538
|
+
}).catch((err) => {
|
|
1539
|
+
log$2("failure parsing payload: %s", err.message);
|
|
1540
|
+
return Promise.reject(err);
|
|
1541
|
+
});
|
|
1542
|
+
}
|
|
1543
|
+
|
|
1544
|
+
sendResponse(response) {
|
|
1545
|
+
let responsePayload;
|
|
1546
|
+
if (this.#isJSON) {
|
|
1547
|
+
responsePayload = JSON.stringify({
|
|
1548
|
+
method_payload: { json_payload: JSON.stringify(response) },
|
|
1549
|
+
});
|
|
1550
|
+
} else {
|
|
1551
|
+
// We need to serialise the response, and then wrap it in a RemoteRequest.
|
|
1552
|
+
const serialisedResponse =
|
|
1553
|
+
this.#methodDescriptor.responseSerialize(response);
|
|
1554
|
+
const tunnelMethod = this.#voltClient.getVoltAPIClient().Tunnel;
|
|
1555
|
+
responsePayload = tunnelMethod.requestSerialize({
|
|
1556
|
+
method_payload: { payload: serialisedResponse },
|
|
1557
|
+
});
|
|
1558
|
+
}
|
|
1559
|
+
|
|
1560
|
+
if (this.#token.sk) {
|
|
1561
|
+
// Encrypt the response using the shared key and iv.
|
|
1562
|
+
responsePayload = VoltCredential.aesEncrypt(
|
|
1563
|
+
responsePayload,
|
|
1564
|
+
this.#encryptKey,
|
|
1565
|
+
this.#encryptIV,
|
|
1566
|
+
);
|
|
1567
|
+
}
|
|
1568
|
+
|
|
1569
|
+
const invokeResponse = {
|
|
1570
|
+
invoke_id: this.#invokeId,
|
|
1571
|
+
};
|
|
1572
|
+
|
|
1573
|
+
if (this.#isJSON) {
|
|
1574
|
+
invokeResponse.json_payload =
|
|
1575
|
+
Buffer.from(responsePayload).toString("base64");
|
|
1576
|
+
} else {
|
|
1577
|
+
invokeResponse.payload = responsePayload;
|
|
1578
|
+
}
|
|
1579
|
+
|
|
1580
|
+
this.#voltConnection.send({
|
|
1581
|
+
invoke_response: invokeResponse,
|
|
1582
|
+
});
|
|
1583
|
+
}
|
|
1584
|
+
|
|
1585
|
+
sendEnd(errorMessage) {
|
|
1586
|
+
const tunnelMethod = this.#voltClient.getVoltAPIClient().Tunnel;
|
|
1587
|
+
|
|
1588
|
+
let endPayload;
|
|
1589
|
+
if (errorMessage) {
|
|
1590
|
+
endPayload = {
|
|
1591
|
+
method_end: { error: errorMessage, ended: true },
|
|
1592
|
+
};
|
|
1593
|
+
} else {
|
|
1594
|
+
endPayload = {
|
|
1595
|
+
method_end: { ended: true },
|
|
1596
|
+
};
|
|
1597
|
+
}
|
|
1598
|
+
|
|
1599
|
+
if (this.#isJSON) {
|
|
1600
|
+
endPayload = JSON.stringify(endPayload);
|
|
1601
|
+
} else {
|
|
1602
|
+
endPayload = tunnelMethod.requestSerialize(endPayload);
|
|
1603
|
+
}
|
|
1604
|
+
|
|
1605
|
+
if (this.#token.sk) {
|
|
1606
|
+
// Encrypt the response using the shared key and iv.
|
|
1607
|
+
endPayload = VoltCredential.aesEncrypt(
|
|
1608
|
+
endPayload,
|
|
1609
|
+
this.#encryptKey,
|
|
1610
|
+
this.#encryptIV,
|
|
1611
|
+
);
|
|
1612
|
+
}
|
|
1613
|
+
|
|
1614
|
+
const invokeResponse = {
|
|
1615
|
+
invoke_id: this.#invokeId,
|
|
1616
|
+
server_end: true,
|
|
1617
|
+
};
|
|
1618
|
+
|
|
1619
|
+
if (this.#isJSON) {
|
|
1620
|
+
invokeResponse.json_payload = Buffer.from(endPayload).toString("base64");
|
|
1621
|
+
} else {
|
|
1622
|
+
invokeResponse.payload = endPayload;
|
|
1623
|
+
}
|
|
1624
|
+
|
|
1625
|
+
this.#voltConnection.send({
|
|
1626
|
+
invoke_response: invokeResponse,
|
|
1627
|
+
});
|
|
1628
|
+
}
|
|
1245
1629
|
}
|
|
1246
1630
|
|
|
1247
1631
|
/* eslint-disable no-underscore-dangle */
|
|
@@ -1262,46 +1646,48 @@ const voltServices = [
|
|
|
1262
1646
|
|
|
1263
1647
|
function issueBind(bindRequest, ttl) {
|
|
1264
1648
|
// eslint-disable-next-line no-use-before-define
|
|
1265
|
-
return
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
log$1("
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1649
|
+
return unaryCallInternal
|
|
1650
|
+
.call(this, "Bind", bindRequest)
|
|
1651
|
+
.then((bindResponse) => {
|
|
1652
|
+
log$1("got binding request response %j", bindResponse);
|
|
1653
|
+
if (bindResponse.status?.code) {
|
|
1654
|
+
log$1("error in bind response: %s", bindResponse.status.message);
|
|
1655
|
+
return Promise.reject(new Error(bindResponse.status.message));
|
|
1656
|
+
} else {
|
|
1657
|
+
switch (bindResponse.decision) {
|
|
1658
|
+
case "POLICY_DECISION_PERMIT": {
|
|
1659
|
+
//
|
|
1660
|
+
// The request status is permit => cache the bind response info.
|
|
1661
|
+
//
|
|
1662
|
+
|
|
1663
|
+
// This is the certificate assigned to us by the volt.
|
|
1664
|
+
this._credential.cache.cert = bindResponse.cert;
|
|
1665
|
+
|
|
1666
|
+
// This is the signing CA used by the volt.
|
|
1667
|
+
this._credential.cache.ca = bindResponse.chain;
|
|
1668
|
+
|
|
1669
|
+
// Identity resource id is assigned by the volt.
|
|
1670
|
+
this._credential.cache.client_id = bindResponse.identity_id;
|
|
1671
|
+
this._credential.saveCache();
|
|
1672
|
+
break;
|
|
1673
|
+
}
|
|
1674
|
+
case "POLICY_DECISION_DENY": {
|
|
1675
|
+
log$1(">>>>>>>>>>>>>>> access request is DENIED <<<<<<<<<<<<<<<<<<<");
|
|
1676
|
+
break;
|
|
1677
|
+
}
|
|
1678
|
+
case "POLICY_DECISION_PROMPT":
|
|
1679
|
+
case "POLICY_DECISION_PENDING": {
|
|
1680
|
+
log$1("access pending approval - waiting...");
|
|
1681
|
+
break;
|
|
1682
|
+
}
|
|
1683
|
+
default:
|
|
1684
|
+
log$1("ignoring unknown bind descision %s", bindResponse.status);
|
|
1685
|
+
break;
|
|
1296
1686
|
}
|
|
1297
|
-
default:
|
|
1298
|
-
log$1("ignoring unknown bind descision %s", bindResponse.status);
|
|
1299
|
-
break;
|
|
1300
1687
|
}
|
|
1301
|
-
}
|
|
1302
1688
|
|
|
1303
|
-
|
|
1304
|
-
|
|
1689
|
+
return bindResponse.decision;
|
|
1690
|
+
});
|
|
1305
1691
|
}
|
|
1306
1692
|
|
|
1307
1693
|
function findDIDDocumentService(document, serviceType) {
|
|
@@ -1468,6 +1854,30 @@ function connectInternal(helloPayload) {
|
|
|
1468
1854
|
this.emit("evt", evt);
|
|
1469
1855
|
});
|
|
1470
1856
|
|
|
1857
|
+
this._voltConnection.on("invoke_request", (invoke_request) => {
|
|
1858
|
+
const invokeId = invoke_request.invoke_id;
|
|
1859
|
+
if (this._activeRPC[invokeId]) {
|
|
1860
|
+
this._activeRPC[invokeId].parsePayload(invoke_request);
|
|
1861
|
+
} else {
|
|
1862
|
+
const rpcInvocation = new RpcInvocation(this, this._voltConnection);
|
|
1863
|
+
|
|
1864
|
+
rpcInvocation.on("end", () => {
|
|
1865
|
+
log$1("removing active RPC [%s]", invokeId);
|
|
1866
|
+
this._activeRPC[invokeId] = undefined;
|
|
1867
|
+
});
|
|
1868
|
+
|
|
1869
|
+
rpcInvocation
|
|
1870
|
+
.initialise(invoke_request)
|
|
1871
|
+
.then(() => {
|
|
1872
|
+
this._activeRPC[invokeId] = rpcInvocation;
|
|
1873
|
+
this.emit("invoke_request", rpcInvocation);
|
|
1874
|
+
})
|
|
1875
|
+
.catch((err) => {
|
|
1876
|
+
log$1("invoke_request - error [%s]", err.message);
|
|
1877
|
+
});
|
|
1878
|
+
}
|
|
1879
|
+
});
|
|
1880
|
+
|
|
1471
1881
|
return this._voltConnection.connect(helloPayload);
|
|
1472
1882
|
} catch (err) {
|
|
1473
1883
|
log$1("connect - error [%s]", err.message);
|
|
@@ -1501,11 +1911,61 @@ function getVoltAPIClientInternal() {
|
|
|
1501
1911
|
return this._cachedClient;
|
|
1502
1912
|
}
|
|
1503
1913
|
|
|
1504
|
-
function
|
|
1505
|
-
|
|
1506
|
-
|
|
1914
|
+
function getAPIClientInternal(service) {
|
|
1915
|
+
if (!this._cachedService[service.id]) {
|
|
1916
|
+
service.service_description.host_type === "SERVICE_HOST_TYPE_RELAYED";
|
|
1917
|
+
|
|
1918
|
+
const serviceAddress = this.isRemote
|
|
1919
|
+
? this._voltConfig.relay.address
|
|
1920
|
+
: service.service_description.host_address;
|
|
1921
|
+
|
|
1922
|
+
createServiceProtobufFiles(service, "./service-proto");
|
|
1923
|
+
|
|
1924
|
+
log$1("creating API service client on %s", serviceAddress);
|
|
1925
|
+
let serviceDescriptors = {};
|
|
1926
|
+
const fullProtoPath = path.join(process.cwd(), "./service-proto");
|
|
1927
|
+
for (let api of service.service_description.service_api) {
|
|
1928
|
+
const packageDescriptors = getServiceDescriptorsFromPath(
|
|
1929
|
+
this._grpc,
|
|
1930
|
+
fullProtoPath,
|
|
1931
|
+
api,
|
|
1932
|
+
);
|
|
1933
|
+
serviceDescriptors = { ...serviceDescriptors, ...packageDescriptors };
|
|
1934
|
+
}
|
|
1935
|
+
|
|
1936
|
+
this._cachedService[service.id] = createClient(
|
|
1937
|
+
this._grpc,
|
|
1938
|
+
serviceDescriptors,
|
|
1939
|
+
serviceAddress,
|
|
1940
|
+
this._credential,
|
|
1941
|
+
this.isRemote && !this.isVoltRelay,
|
|
1942
|
+
this._voltConfig?.relay?.cloud ? this._voltConfig.id : "",
|
|
1943
|
+
this._voltConfig?.relay?.cloud ? this._voltConfig.id : "",
|
|
1944
|
+
);
|
|
1945
|
+
}
|
|
1946
|
+
|
|
1947
|
+
return this._cachedService[service.id];
|
|
1948
|
+
}
|
|
1949
|
+
|
|
1950
|
+
function getServiceClient(service) {
|
|
1951
|
+
let grpcClient;
|
|
1952
|
+
if (
|
|
1953
|
+
service &&
|
|
1954
|
+
service?.service_description.host_type !== "SERVICE_HOST_TYPE_BUILTIN"
|
|
1955
|
+
) {
|
|
1956
|
+
grpcClient = getAPIClientInternal.call(this, service);
|
|
1957
|
+
} else {
|
|
1958
|
+
grpcClient = getVoltAPIClientInternal.call(this);
|
|
1959
|
+
}
|
|
1507
1960
|
|
|
1508
|
-
|
|
1961
|
+
return grpcClient;
|
|
1962
|
+
}
|
|
1963
|
+
|
|
1964
|
+
function unaryCallInternal(method, request, service) {
|
|
1965
|
+
const grpcClient = getServiceClient.call(this, service);
|
|
1966
|
+
|
|
1967
|
+
return new Promise((resolve, reject) => {
|
|
1968
|
+
const call = new GRPCCall(this, method, "METHOD_TYPE_UNARY", service);
|
|
1509
1969
|
|
|
1510
1970
|
let response = null;
|
|
1511
1971
|
|
|
@@ -1533,6 +1993,16 @@ function unaryCall(method, request) {
|
|
|
1533
1993
|
});
|
|
1534
1994
|
}
|
|
1535
1995
|
|
|
1996
|
+
function streamingCallInternal(methodType, method, request, service) {
|
|
1997
|
+
const grpcClient = getServiceClient.call(this, service);
|
|
1998
|
+
|
|
1999
|
+
const call = new GRPCCall(this, method, methodType, service);
|
|
2000
|
+
|
|
2001
|
+
call.start(grpcClient, request);
|
|
2002
|
+
|
|
2003
|
+
return call;
|
|
2004
|
+
}
|
|
2005
|
+
|
|
1536
2006
|
async function fetchVoltConfig(discovery_url) {
|
|
1537
2007
|
try {
|
|
1538
2008
|
const getJSON = bent__default["default"]("json");
|
|
@@ -1613,6 +2083,8 @@ class VoltClient extends EventEmitter__default["default"] {
|
|
|
1613
2083
|
this._config = null;
|
|
1614
2084
|
this._voltConfig = null;
|
|
1615
2085
|
this._voltConnection = null;
|
|
2086
|
+
this._cachedService = {};
|
|
2087
|
+
this._activeRPC = {};
|
|
1616
2088
|
}
|
|
1617
2089
|
|
|
1618
2090
|
get config() {
|
|
@@ -1858,6 +2330,40 @@ class VoltClient extends EventEmitter__default["default"] {
|
|
|
1858
2330
|
return getVoltAPIClientInternal.call(this);
|
|
1859
2331
|
}
|
|
1860
2332
|
|
|
2333
|
+
unaryCall(method, request, service) {
|
|
2334
|
+
return unaryCallInternal.call(this, method, request, service);
|
|
2335
|
+
}
|
|
2336
|
+
|
|
2337
|
+
bidiStreamingCall(method, request, service) {
|
|
2338
|
+
return streamingCallInternal.call(
|
|
2339
|
+
this,
|
|
2340
|
+
"METHOD_TYPE_BIDI",
|
|
2341
|
+
method,
|
|
2342
|
+
request,
|
|
2343
|
+
service,
|
|
2344
|
+
);
|
|
2345
|
+
}
|
|
2346
|
+
|
|
2347
|
+
clientStreamingCall(method, request, service) {
|
|
2348
|
+
return streamingCallInternal.call(
|
|
2349
|
+
this,
|
|
2350
|
+
"METHOD_TYPE_CLIENT_STREAM",
|
|
2351
|
+
method,
|
|
2352
|
+
request,
|
|
2353
|
+
service,
|
|
2354
|
+
);
|
|
2355
|
+
}
|
|
2356
|
+
|
|
2357
|
+
serverStreamingCall(method, request, service) {
|
|
2358
|
+
return streamingCallInternal.call(
|
|
2359
|
+
this,
|
|
2360
|
+
"METHOD_TYPE_SERVER_STREAM",
|
|
2361
|
+
method,
|
|
2362
|
+
request,
|
|
2363
|
+
service,
|
|
2364
|
+
);
|
|
2365
|
+
}
|
|
2366
|
+
|
|
1861
2367
|
/**
|
|
1862
2368
|
* Request resource access.
|
|
1863
2369
|
* @param {*} targetResourceId
|
|
@@ -1902,47 +2408,47 @@ class VoltClient extends EventEmitter__default["default"] {
|
|
|
1902
2408
|
*/
|
|
1903
2409
|
|
|
1904
2410
|
CanAccessResource(request) {
|
|
1905
|
-
return
|
|
2411
|
+
return unaryCallInternal.call(this, "CanAccessResource", request);
|
|
1906
2412
|
}
|
|
1907
2413
|
|
|
1908
2414
|
DeleteResource(request) {
|
|
1909
|
-
return
|
|
2415
|
+
return unaryCallInternal.call(this, "DeleteResource", request);
|
|
1910
2416
|
}
|
|
1911
2417
|
|
|
1912
2418
|
DiscoverServices(request) {
|
|
1913
|
-
return
|
|
2419
|
+
return unaryCallInternal.call(this, "DiscoverServices", request);
|
|
1914
2420
|
}
|
|
1915
2421
|
|
|
1916
2422
|
GetResource(request) {
|
|
1917
|
-
return
|
|
2423
|
+
return unaryCallInternal.call(this, "GetResource", request);
|
|
1918
2424
|
}
|
|
1919
2425
|
|
|
1920
2426
|
GetResources(request) {
|
|
1921
|
-
return
|
|
2427
|
+
return unaryCallInternal.call(this, "GetResources", request);
|
|
1922
2428
|
}
|
|
1923
2429
|
|
|
1924
2430
|
GetResourceAncestors(request) {
|
|
1925
|
-
return
|
|
2431
|
+
return unaryCallInternal.call(this, "GetResourceAncestors", request);
|
|
1926
2432
|
}
|
|
1927
2433
|
|
|
1928
2434
|
GetResourceDescendants(request) {
|
|
1929
|
-
return
|
|
2435
|
+
return unaryCallInternal.call(this, "GetResourceDescendants", request);
|
|
1930
2436
|
}
|
|
1931
2437
|
|
|
1932
2438
|
RequestAccess(request) {
|
|
1933
|
-
return
|
|
2439
|
+
return unaryCallInternal.call(this, "RequestAccess", request);
|
|
1934
2440
|
}
|
|
1935
2441
|
|
|
1936
2442
|
SaveResource(request) {
|
|
1937
|
-
return
|
|
2443
|
+
return unaryCallInternal.call(this, "SaveResource", request);
|
|
1938
2444
|
}
|
|
1939
2445
|
|
|
1940
2446
|
SaveResourceAttribute(request) {
|
|
1941
|
-
return
|
|
2447
|
+
return unaryCallInternal.call(this, "SaveResourceAttribute", request);
|
|
1942
2448
|
}
|
|
1943
2449
|
|
|
1944
2450
|
SetServiceStatus(request) {
|
|
1945
|
-
return
|
|
2451
|
+
return unaryCallInternal.call(this, "SetServiceStatus", request);
|
|
1946
2452
|
}
|
|
1947
2453
|
|
|
1948
2454
|
/**
|
|
@@ -1950,82 +2456,82 @@ class VoltClient extends EventEmitter__default["default"] {
|
|
|
1950
2456
|
*/
|
|
1951
2457
|
|
|
1952
2458
|
Bind(request) {
|
|
1953
|
-
return
|
|
2459
|
+
return unaryCallInternal.call(this, "Bind", request);
|
|
1954
2460
|
}
|
|
1955
2461
|
|
|
1956
2462
|
DeleteAccess(request) {
|
|
1957
|
-
return
|
|
2463
|
+
return unaryCallInternal.call(this, "DeleteAccess", request);
|
|
1958
2464
|
}
|
|
1959
2465
|
|
|
1960
2466
|
DeleteVolt(request) {
|
|
1961
|
-
return
|
|
2467
|
+
return unaryCallInternal.call(this, "DeleteVolt", request);
|
|
1962
2468
|
}
|
|
1963
2469
|
|
|
1964
2470
|
GetAccess(request) {
|
|
1965
|
-
return
|
|
2471
|
+
return unaryCallInternal.call(this, "GetAccess", request);
|
|
1966
2472
|
}
|
|
1967
2473
|
|
|
1968
2474
|
GetBindings(request) {
|
|
1969
|
-
return
|
|
2475
|
+
return unaryCallInternal.call(this, "GetBindings", request);
|
|
1970
2476
|
}
|
|
1971
2477
|
|
|
1972
2478
|
GetIdentities(request) {
|
|
1973
|
-
return
|
|
2479
|
+
return unaryCallInternal.call(this, "GetIdentities", request);
|
|
1974
2480
|
}
|
|
1975
2481
|
|
|
1976
2482
|
GetIdentity(request) {
|
|
1977
|
-
return
|
|
2483
|
+
return unaryCallInternal.call(this, "GetIdentity", request);
|
|
1978
2484
|
}
|
|
1979
2485
|
|
|
1980
2486
|
GetIdentityToken(request) {
|
|
1981
|
-
return
|
|
2487
|
+
return unaryCallInternal.call(this, "GetIdentityToken", request);
|
|
1982
2488
|
}
|
|
1983
2489
|
|
|
1984
2490
|
GetPolicy(request) {
|
|
1985
|
-
return
|
|
2491
|
+
return unaryCallInternal.call(this, "GetPolicy", request);
|
|
1986
2492
|
}
|
|
1987
2493
|
|
|
1988
2494
|
GetSettings(request) {
|
|
1989
|
-
return
|
|
2495
|
+
return unaryCallInternal.call(this, "GetSettings", request);
|
|
1990
2496
|
}
|
|
1991
2497
|
|
|
1992
2498
|
SaveAccess(request) {
|
|
1993
|
-
return
|
|
2499
|
+
return unaryCallInternal.call(this, "SaveAccess", request);
|
|
1994
2500
|
}
|
|
1995
2501
|
|
|
1996
2502
|
SaveCloudConnection(request) {
|
|
1997
|
-
return
|
|
2503
|
+
return unaryCallInternal.call(this, "SaveCloudConnection", request);
|
|
1998
2504
|
}
|
|
1999
2505
|
|
|
2000
2506
|
SaveIdentity(request) {
|
|
2001
|
-
return
|
|
2507
|
+
return unaryCallInternal.call(this, "SaveIdentity", request);
|
|
2002
2508
|
}
|
|
2003
2509
|
|
|
2004
2510
|
SaveSettings(request) {
|
|
2005
|
-
return
|
|
2511
|
+
return unaryCallInternal.call(this, "SaveSettings", request);
|
|
2006
2512
|
}
|
|
2007
2513
|
|
|
2008
2514
|
SetAccessRequestDecision(request) {
|
|
2009
|
-
return
|
|
2515
|
+
return unaryCallInternal.call(this, "SetAccessRequestDecision", request);
|
|
2010
2516
|
}
|
|
2011
2517
|
|
|
2012
2518
|
SetBindingDecision(request) {
|
|
2013
|
-
return
|
|
2519
|
+
return unaryCallInternal.call(this, "SetBindingDecision", request);
|
|
2014
2520
|
}
|
|
2015
2521
|
|
|
2016
2522
|
Shutdown(request) {
|
|
2017
|
-
return
|
|
2523
|
+
return unaryCallInternal.call(this, "Shutdown", request);
|
|
2018
2524
|
}
|
|
2019
2525
|
|
|
2020
2526
|
SignVerify(request) {
|
|
2021
|
-
return
|
|
2527
|
+
return unaryCallInternal.call(this, "SignVerify", request);
|
|
2022
2528
|
}
|
|
2023
2529
|
|
|
2024
2530
|
/**
|
|
2025
2531
|
* FileAPI
|
|
2026
2532
|
*/
|
|
2027
2533
|
GetFileDescendants(request) {
|
|
2028
|
-
return
|
|
2534
|
+
return unaryCallInternal.call(this, "GetFileDescendants", request);
|
|
2029
2535
|
}
|
|
2030
2536
|
|
|
2031
2537
|
/**
|
|
@@ -2103,6 +2609,10 @@ class VoltClient extends EventEmitter__default["default"] {
|
|
|
2103
2609
|
/**
|
|
2104
2610
|
* SqliteDatabaseAPI
|
|
2105
2611
|
*/
|
|
2612
|
+
BulkUpdate(request) {
|
|
2613
|
+
return unaryCallInternal.call(this, "BulkUpdate", request);
|
|
2614
|
+
}
|
|
2615
|
+
|
|
2106
2616
|
SqlExecute(request) {
|
|
2107
2617
|
const grpcClient = this.getVoltAPIClient();
|
|
2108
2618
|
|