@tdxvolt/volt-client-grpc 0.14.61 → 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 +662 -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 +15 -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
|
|
|
@@ -527,6 +527,10 @@ class VoltCredential {
|
|
|
527
527
|
return this._cryptoCache.client_id;
|
|
528
528
|
}
|
|
529
529
|
|
|
530
|
+
get voltPublicKey() {
|
|
531
|
+
return this._voltPublicKey;
|
|
532
|
+
}
|
|
533
|
+
|
|
530
534
|
get publicKey() {
|
|
531
535
|
return pki$1.publicKeyToPem(this.getKey().publicKey);
|
|
532
536
|
}
|
|
@@ -547,17 +551,17 @@ class VoltCredential {
|
|
|
547
551
|
createKey() {
|
|
548
552
|
if (this._cryptoCache.key) {
|
|
549
553
|
// Already have key data in the cache in pem format => create fully-formed pki instances.
|
|
550
|
-
log$
|
|
554
|
+
log$5("createKey - key already exists");
|
|
551
555
|
return Promise.resolve(this.getKey());
|
|
552
556
|
} else {
|
|
553
|
-
log$
|
|
557
|
+
log$5("creating key");
|
|
554
558
|
return new Promise((resolve, reject) => {
|
|
555
559
|
pki$1.rsa.generateKeyPair({ bits: 2048, workers: -1 }, (err, keypair) => {
|
|
556
560
|
if (err) {
|
|
557
|
-
log$
|
|
561
|
+
log$5("failure creating key [%s]", err.message);
|
|
558
562
|
reject(err);
|
|
559
563
|
} else {
|
|
560
|
-
log$
|
|
564
|
+
log$5("successfully created key");
|
|
561
565
|
const pem = pki$1.privateKeyToPem(keypair.privateKey);
|
|
562
566
|
this._cryptoCache.key = pem;
|
|
563
567
|
resolve(keypair);
|
|
@@ -579,7 +583,7 @@ class VoltCredential {
|
|
|
579
583
|
return this._cryptoCache;
|
|
580
584
|
})
|
|
581
585
|
.catch((err) => {
|
|
582
|
-
log$
|
|
586
|
+
log$5("failure initialising crypto [%s]", err.message);
|
|
583
587
|
return Promise.reject(err);
|
|
584
588
|
});
|
|
585
589
|
}
|
|
@@ -594,7 +598,7 @@ class VoltCredential {
|
|
|
594
598
|
* @param {*} tunnelling flag indicating if the token is required for a tunnelled connection
|
|
595
599
|
* @param {*} ttl time to live in seconds (default to 1 minute)
|
|
596
600
|
*/
|
|
597
|
-
getIdentityToken(audience, tunnelling = false, ttl = 60) {
|
|
601
|
+
getIdentityToken(audience, publicKey, tunnelling = false, ttl = 60) {
|
|
598
602
|
if (!this._cryptoCache.key) {
|
|
599
603
|
throw new Error("crypto cache invalid");
|
|
600
604
|
}
|
|
@@ -603,7 +607,7 @@ class VoltCredential {
|
|
|
603
607
|
const publicKeyPem = pki$1.publicKeyToPem(keyPair.publicKey);
|
|
604
608
|
const base58Key = createPublicKeyFingerprint(publicKeyPem);
|
|
605
609
|
|
|
606
|
-
log$
|
|
610
|
+
log$5("base58 key is %s", base58Key);
|
|
607
611
|
|
|
608
612
|
// Allow TTL either side of the current time.
|
|
609
613
|
// @todo - fix with server time sync on volt connection.
|
|
@@ -620,11 +624,8 @@ class VoltCredential {
|
|
|
620
624
|
sharedKey = VoltCredential.aesCreateKey();
|
|
621
625
|
|
|
622
626
|
// 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);
|
|
627
|
+
payload.sk = VoltCredential.rsaEncrypt(publicKey, sharedKey.key);
|
|
628
|
+
payload.iv = VoltCredential.rsaEncrypt(publicKey, sharedKey.iv);
|
|
628
629
|
}
|
|
629
630
|
|
|
630
631
|
// Sign synchronously.
|
|
@@ -649,9 +650,10 @@ class VoltCredential {
|
|
|
649
650
|
* @param {*} ttl
|
|
650
651
|
* @returns
|
|
651
652
|
*/
|
|
652
|
-
getIdentityMetadata(grpc, audience, tunnelling = false, ttl = 60) {
|
|
653
|
+
getIdentityMetadata(grpc, audience, publicKey, tunnelling = false, ttl = 60) {
|
|
653
654
|
const identityToken = this.getIdentityToken(
|
|
654
655
|
audience || this._voltConfig.id,
|
|
656
|
+
publicKey,
|
|
655
657
|
tunnelling,
|
|
656
658
|
ttl,
|
|
657
659
|
);
|
|
@@ -697,6 +699,12 @@ class VoltCredential {
|
|
|
697
699
|
static rsaEncrypt(key, buffer) {
|
|
698
700
|
return crypto__default["default"].publicEncrypt(key, buffer).toString("base64");
|
|
699
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
|
+
}
|
|
700
708
|
}
|
|
701
709
|
|
|
702
710
|
const { get: getProp, snakeCase } = lodash__default["default"];
|
|
@@ -713,23 +721,23 @@ const defaultLoaderOptions = {
|
|
|
713
721
|
includeDirs: [defaultProtoPath],
|
|
714
722
|
};
|
|
715
723
|
|
|
716
|
-
|
|
724
|
+
function getProtoDescriptors(grpc, protoPath, opts) {
|
|
717
725
|
const definition = protoLoader__default["default"].loadSync(
|
|
718
726
|
protoPath,
|
|
719
727
|
opts || defaultLoaderOptions,
|
|
720
728
|
);
|
|
721
729
|
const descriptors = grpc.loadPackageDefinition(definition);
|
|
722
730
|
return descriptors;
|
|
723
|
-
}
|
|
731
|
+
}
|
|
724
732
|
|
|
725
|
-
|
|
733
|
+
function getProtoService(descriptors, servicePath) {
|
|
726
734
|
const serviceDef = getProp(descriptors, servicePath);
|
|
727
735
|
if (serviceDef?.service) {
|
|
728
736
|
return serviceDef.service;
|
|
729
737
|
} else {
|
|
730
738
|
return null;
|
|
731
739
|
}
|
|
732
|
-
}
|
|
740
|
+
}
|
|
733
741
|
|
|
734
742
|
function getServiceDescriptorsFromPath(
|
|
735
743
|
grpc,
|
|
@@ -737,8 +745,30 @@ function getServiceDescriptorsFromPath(
|
|
|
737
745
|
servicePackageName,
|
|
738
746
|
opts,
|
|
739
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
|
+
|
|
740
770
|
let serviceDescriptors;
|
|
741
|
-
const descriptors = getProtoDescriptors(grpc,
|
|
771
|
+
const descriptors = getProtoDescriptors(grpc, serviceProtoPath, opts);
|
|
742
772
|
if (descriptors) {
|
|
743
773
|
serviceDescriptors = getProtoService(descriptors, servicePackageName);
|
|
744
774
|
}
|
|
@@ -786,8 +816,17 @@ function getProtoDescriptorMethods(protoDescriptor) {
|
|
|
786
816
|
return methods;
|
|
787
817
|
}
|
|
788
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
|
+
|
|
789
827
|
var protoUtils = /*#__PURE__*/Object.freeze({
|
|
790
828
|
__proto__: null,
|
|
829
|
+
createServiceProtobufFiles: createServiceProtobufFiles,
|
|
791
830
|
getServiceDescriptors: getServiceDescriptors,
|
|
792
831
|
getProtoDescriptors: getProtoDescriptors,
|
|
793
832
|
getProtoDescriptorMethods: getProtoDescriptorMethods,
|
|
@@ -796,70 +835,101 @@ var protoUtils = /*#__PURE__*/Object.freeze({
|
|
|
796
835
|
|
|
797
836
|
/* eslint-disable no-underscore-dangle */
|
|
798
837
|
|
|
799
|
-
const log$
|
|
838
|
+
const log$4 = debug__default["default"]("volt-client-grpc:grpc-call");
|
|
800
839
|
|
|
801
840
|
function _prepareInvokeRequest(
|
|
802
841
|
request,
|
|
803
842
|
method,
|
|
804
843
|
methodType = "METHOD_TYPE_UNARY",
|
|
805
844
|
) {
|
|
806
|
-
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(
|
|
807
851
|
this._voltClient.grpc,
|
|
808
|
-
this.
|
|
809
|
-
|
|
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,
|
|
810
857
|
);
|
|
858
|
+
|
|
811
859
|
let invokeRequest;
|
|
812
860
|
let callMethod = method;
|
|
813
861
|
|
|
814
|
-
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
|
+
//
|
|
815
867
|
let requestPayload;
|
|
868
|
+
|
|
869
|
+
// Serialise the rpc request.
|
|
816
870
|
if (request) {
|
|
817
871
|
requestPayload = this._grpcClient[method].requestSerialize(request);
|
|
818
872
|
} else if (request !== null) {
|
|
819
|
-
log$
|
|
873
|
+
log$4("****************LOOKOUT****************** - empty request");
|
|
820
874
|
} else {
|
|
821
|
-
log$
|
|
875
|
+
log$4("explicit empty request payload");
|
|
822
876
|
}
|
|
823
877
|
|
|
824
|
-
|
|
878
|
+
// Use this placeholder to serialise the relay request wrapper.
|
|
879
|
+
const voltGrpcClient = this._voltClient.getVoltAPIClient();
|
|
880
|
+
const tunnelMethod = voltGrpcClient.Tunnel;
|
|
825
881
|
|
|
826
882
|
const tunnelResp = {
|
|
827
883
|
method_invoke: {
|
|
828
884
|
method_name: this._grpcClient[method].path,
|
|
829
885
|
method_type: methodType,
|
|
830
|
-
token:
|
|
886
|
+
token: methodToken.token,
|
|
831
887
|
request: requestPayload,
|
|
832
888
|
},
|
|
833
889
|
};
|
|
834
890
|
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
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
|
+
}
|
|
840
903
|
|
|
841
|
-
|
|
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
|
+
}
|
|
915
|
+
|
|
916
|
+
log$4("target is %j", targetFingerprint);
|
|
842
917
|
|
|
843
918
|
invokeRequest = {
|
|
844
|
-
|
|
919
|
+
target_fingerprint: targetFingerprint,
|
|
920
|
+
token: methodToken.token,
|
|
845
921
|
payload: invokePayload,
|
|
922
|
+
target_service_id: isServiceRelayed ? this._service.id : undefined,
|
|
846
923
|
};
|
|
847
924
|
|
|
925
|
+
// Replace the target method with a call to Invoke on the relay Volt.
|
|
848
926
|
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
927
|
} else {
|
|
858
928
|
invokeRequest = request;
|
|
859
929
|
}
|
|
860
930
|
|
|
861
931
|
return {
|
|
862
|
-
meta,
|
|
932
|
+
meta: methodToken,
|
|
863
933
|
method: callMethod,
|
|
864
934
|
methodName: method,
|
|
865
935
|
request: invokeRequest,
|
|
@@ -869,10 +939,16 @@ function _prepareInvokeRequest(
|
|
|
869
939
|
function _preparePayloadRequest(request, invokeInfo) {
|
|
870
940
|
let payloadRequest;
|
|
871
941
|
|
|
872
|
-
|
|
942
|
+
const isServiceRelayed =
|
|
943
|
+
this._service?.service_description.host_type ===
|
|
944
|
+
"SERVICE_HOST_TYPE_RELAYED";
|
|
945
|
+
|
|
946
|
+
if (this._voltClient.isVoltRelay || isServiceRelayed) {
|
|
873
947
|
const requestPayload =
|
|
874
948
|
this._grpcClient[invokeInfo.methodName].requestSerialize(request);
|
|
875
|
-
|
|
949
|
+
|
|
950
|
+
const voltGrpcClient = this._voltClient.getVoltAPIClient();
|
|
951
|
+
const tunnelMethod = voltGrpcClient.Tunnel;
|
|
876
952
|
|
|
877
953
|
const tunnelResp = {
|
|
878
954
|
method_payload: {
|
|
@@ -889,14 +965,6 @@ function _preparePayloadRequest(request, invokeInfo) {
|
|
|
889
965
|
payloadRequest = {
|
|
890
966
|
payload: invokePayload,
|
|
891
967
|
};
|
|
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
968
|
} else {
|
|
901
969
|
payloadRequest = request;
|
|
902
970
|
}
|
|
@@ -905,29 +973,47 @@ function _preparePayloadRequest(request, invokeInfo) {
|
|
|
905
973
|
}
|
|
906
974
|
|
|
907
975
|
function _parseResponse(method, meta, response) {
|
|
976
|
+
// log("parseResponse for %s", this._methodName);
|
|
908
977
|
let invokeResponse = {};
|
|
909
978
|
|
|
910
|
-
|
|
979
|
+
const isServiceRelayed =
|
|
980
|
+
this._service?.service_description.host_type ===
|
|
981
|
+
"SERVICE_HOST_TYPE_RELAYED";
|
|
982
|
+
|
|
983
|
+
if (this._voltClient.isVoltRelay || isServiceRelayed) {
|
|
911
984
|
if (response.payload) {
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
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;
|
|
918
997
|
const responsePayload = tunnelMethod.requestDeserialize(decryptedPayload);
|
|
919
998
|
if (responsePayload.payload === "method_payload") {
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
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
|
+
}
|
|
923
1009
|
} else if (responsePayload.payload === "method_end") {
|
|
924
1010
|
invokeResponse = responsePayload.method_end;
|
|
925
1011
|
} else {
|
|
926
|
-
log$
|
|
1012
|
+
log$4("unexpected tunnel payload type: %s", responsePayload.payload);
|
|
927
1013
|
}
|
|
928
1014
|
} else if (response.status?.message) {
|
|
929
1015
|
// There's been an error in the tunnel.
|
|
930
|
-
log$
|
|
1016
|
+
log$4(
|
|
931
1017
|
"Tunnel status received: %s, code %d, description: %s",
|
|
932
1018
|
response.status.message,
|
|
933
1019
|
response.status.code,
|
|
@@ -939,7 +1025,7 @@ function _parseResponse(method, meta, response) {
|
|
|
939
1025
|
};
|
|
940
1026
|
} else {
|
|
941
1027
|
invokeResponse.methodId = response.invoke_id;
|
|
942
|
-
log$
|
|
1028
|
+
log$4("started method %d for %s", invokeResponse.methodId, method);
|
|
943
1029
|
}
|
|
944
1030
|
} else if (this._voltClient.isRemote && meta.sharedKey.key) {
|
|
945
1031
|
const decryptedPayload = VoltCredential.aesDecrypt(
|
|
@@ -959,17 +1045,22 @@ function _parseResponse(method, meta, response) {
|
|
|
959
1045
|
}
|
|
960
1046
|
|
|
961
1047
|
class GRPCCall extends EventEmitter__default["default"] {
|
|
962
|
-
constructor(voltClient, methodName, methodType) {
|
|
1048
|
+
constructor(voltClient, methodName, methodType, service = undefined) {
|
|
963
1049
|
super();
|
|
964
1050
|
this._methodName = methodName;
|
|
965
1051
|
this._methodType = methodType;
|
|
966
1052
|
this._call = null;
|
|
967
1053
|
this._voltClient = voltClient;
|
|
1054
|
+
this._service = service;
|
|
968
1055
|
}
|
|
969
1056
|
|
|
970
1057
|
start(grpcClient, request) {
|
|
971
1058
|
this._grpcClient = grpcClient;
|
|
972
1059
|
|
|
1060
|
+
if (typeof this._grpcClient[this._methodName] !== "function") {
|
|
1061
|
+
throw new Error(`method not found: '${this._methodName}'`);
|
|
1062
|
+
}
|
|
1063
|
+
|
|
973
1064
|
this._initialRequest = _prepareInvokeRequest.call(
|
|
974
1065
|
this,
|
|
975
1066
|
request,
|
|
@@ -977,13 +1068,18 @@ class GRPCCall extends EventEmitter__default["default"] {
|
|
|
977
1068
|
this._methodType,
|
|
978
1069
|
);
|
|
979
1070
|
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
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;
|
|
984
1080
|
}
|
|
985
1081
|
|
|
986
|
-
this._call =
|
|
1082
|
+
this._call = callClient[this._initialRequest.method](
|
|
987
1083
|
this._initialRequest.meta.metadata,
|
|
988
1084
|
);
|
|
989
1085
|
|
|
@@ -1013,28 +1109,32 @@ class GRPCCall extends EventEmitter__default["default"] {
|
|
|
1013
1109
|
this.emit("end");
|
|
1014
1110
|
}
|
|
1015
1111
|
} else {
|
|
1016
|
-
log$
|
|
1112
|
+
log$4("method id is %s", parsedResponse.methodId);
|
|
1017
1113
|
}
|
|
1018
1114
|
} catch (err) {
|
|
1019
|
-
log$
|
|
1115
|
+
log$4(
|
|
1116
|
+
"failure processing %s call response: %s",
|
|
1117
|
+
this._methodName,
|
|
1118
|
+
err.message,
|
|
1119
|
+
);
|
|
1020
1120
|
this.emit("error", err);
|
|
1021
1121
|
}
|
|
1022
1122
|
});
|
|
1023
1123
|
|
|
1024
1124
|
this._call.on("error", (err) => {
|
|
1025
|
-
log$
|
|
1125
|
+
log$4("ERROR - intercepted stream error %s", err.message);
|
|
1026
1126
|
this.emit("error", err);
|
|
1027
1127
|
});
|
|
1028
1128
|
|
|
1029
1129
|
this._call.on("finish", () => {
|
|
1030
1130
|
// The read side has ended (i.e. we called end()).
|
|
1031
|
-
log$
|
|
1131
|
+
log$4("finished call %s", this._methodName);
|
|
1032
1132
|
this.emit("finish");
|
|
1033
1133
|
});
|
|
1034
1134
|
|
|
1035
1135
|
this._call.on("end", () => {
|
|
1036
1136
|
// The remote peer ended the stream.
|
|
1037
|
-
log$
|
|
1137
|
+
log$4(
|
|
1038
1138
|
"ended call %s, method id: %s",
|
|
1039
1139
|
this._methodName,
|
|
1040
1140
|
this._initialRequest.methodId || "n/a - not tunnelling",
|
|
@@ -1064,7 +1164,7 @@ class GRPCCall extends EventEmitter__default["default"] {
|
|
|
1064
1164
|
|
|
1065
1165
|
write(request) {
|
|
1066
1166
|
if (!this._call) {
|
|
1067
|
-
log$
|
|
1167
|
+
log$4("ERROR - call not initialised");
|
|
1068
1168
|
throw new Error("call not initialised");
|
|
1069
1169
|
} else if (this._initialRequest) {
|
|
1070
1170
|
const payloadRequest = _preparePayloadRequest.call(
|
|
@@ -1088,7 +1188,7 @@ class GRPCCall extends EventEmitter__default["default"] {
|
|
|
1088
1188
|
|
|
1089
1189
|
/* eslint-disable no-use-before-define */
|
|
1090
1190
|
|
|
1091
|
-
const log$
|
|
1191
|
+
const log$3 = debug__default["default"]("volt-client-grpc:volt-connection");
|
|
1092
1192
|
|
|
1093
1193
|
function _cleanUp(immediateReconnect) {
|
|
1094
1194
|
this._connectionId = "";
|
|
@@ -1122,7 +1222,7 @@ function _cleanUp(immediateReconnect) {
|
|
|
1122
1222
|
}
|
|
1123
1223
|
|
|
1124
1224
|
function _connectionTimeoutHandler() {
|
|
1125
|
-
log$
|
|
1225
|
+
log$3("server timed out");
|
|
1126
1226
|
this.emit("connected", false);
|
|
1127
1227
|
_cleanUp.call(this);
|
|
1128
1228
|
}
|
|
@@ -1134,14 +1234,14 @@ function _doConnect(connectHello) {
|
|
|
1134
1234
|
|
|
1135
1235
|
let helloPayload = connectHello;
|
|
1136
1236
|
if (!connectHello) {
|
|
1137
|
-
log$
|
|
1237
|
+
log$3("defaulting hello payload");
|
|
1138
1238
|
helloPayload = {
|
|
1139
1239
|
hello: {},
|
|
1140
1240
|
};
|
|
1141
1241
|
}
|
|
1142
1242
|
|
|
1143
1243
|
this.call.on("error", (err) => {
|
|
1144
|
-
log$
|
|
1244
|
+
log$3("error on connection stream [%s]", err.message);
|
|
1145
1245
|
_cleanUp.call(this);
|
|
1146
1246
|
this.emit("error", err);
|
|
1147
1247
|
});
|
|
@@ -1149,7 +1249,7 @@ function _doConnect(connectHello) {
|
|
|
1149
1249
|
this.call.on("data", (response) => {
|
|
1150
1250
|
switch (response.payload) {
|
|
1151
1251
|
case "ping": {
|
|
1152
|
-
log$
|
|
1252
|
+
log$3("pinged");
|
|
1153
1253
|
|
|
1154
1254
|
// Received ping response from server => clear timeout.
|
|
1155
1255
|
if (this._pingTimeoutTimer) {
|
|
@@ -1163,18 +1263,23 @@ function _doConnect(connectHello) {
|
|
|
1163
1263
|
case "acknowledge": {
|
|
1164
1264
|
if (!this._connectionId) {
|
|
1165
1265
|
this._connectionId = response.acknowledge.connection_id;
|
|
1166
|
-
log$
|
|
1266
|
+
log$3("connection id is %s", this._connectionId);
|
|
1167
1267
|
this.emit("connected", this._connectionId);
|
|
1168
1268
|
}
|
|
1169
1269
|
break;
|
|
1170
1270
|
}
|
|
1271
|
+
case "invoke_request": {
|
|
1272
|
+
log$3("received invoke request");
|
|
1273
|
+
this.emit("invoke_request", response.invoke_request);
|
|
1274
|
+
break;
|
|
1275
|
+
}
|
|
1171
1276
|
case "evt": {
|
|
1172
|
-
log$
|
|
1277
|
+
log$3("received event %s", response.evt.event_type);
|
|
1173
1278
|
this.emit("evt", response.evt);
|
|
1174
1279
|
break;
|
|
1175
1280
|
}
|
|
1176
1281
|
default:
|
|
1177
|
-
log$
|
|
1282
|
+
log$3("unimplemented connect response payload: %s", response.payload);
|
|
1178
1283
|
break;
|
|
1179
1284
|
}
|
|
1180
1285
|
});
|
|
@@ -1193,7 +1298,7 @@ function _doConnect(connectHello) {
|
|
|
1193
1298
|
|
|
1194
1299
|
function _startPingTimer() {
|
|
1195
1300
|
if (this._pingTimer) {
|
|
1196
|
-
log$
|
|
1301
|
+
log$3("ping timer running");
|
|
1197
1302
|
return;
|
|
1198
1303
|
}
|
|
1199
1304
|
|
|
@@ -1201,7 +1306,7 @@ function _startPingTimer() {
|
|
|
1201
1306
|
// Send next ping to server.
|
|
1202
1307
|
const request = { ping: { timestamp: Date.now() } };
|
|
1203
1308
|
|
|
1204
|
-
log$
|
|
1309
|
+
log$3("pinging Volt");
|
|
1205
1310
|
this.call.write(request);
|
|
1206
1311
|
|
|
1207
1312
|
this._pingTimer = 0;
|
|
@@ -1250,6 +1355,277 @@ class VoltConnection extends EventEmitter__default["default"] {
|
|
|
1250
1355
|
this._dying = true;
|
|
1251
1356
|
_cleanUp.call(this);
|
|
1252
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
|
+
}
|
|
1253
1629
|
}
|
|
1254
1630
|
|
|
1255
1631
|
/* eslint-disable no-underscore-dangle */
|
|
@@ -1270,46 +1646,48 @@ const voltServices = [
|
|
|
1270
1646
|
|
|
1271
1647
|
function issueBind(bindRequest, ttl) {
|
|
1272
1648
|
// 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
|
-
|
|
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;
|
|
1304
1686
|
}
|
|
1305
|
-
default:
|
|
1306
|
-
log$1("ignoring unknown bind descision %s", bindResponse.status);
|
|
1307
|
-
break;
|
|
1308
1687
|
}
|
|
1309
|
-
}
|
|
1310
1688
|
|
|
1311
|
-
|
|
1312
|
-
|
|
1689
|
+
return bindResponse.decision;
|
|
1690
|
+
});
|
|
1313
1691
|
}
|
|
1314
1692
|
|
|
1315
1693
|
function findDIDDocumentService(document, serviceType) {
|
|
@@ -1476,6 +1854,30 @@ function connectInternal(helloPayload) {
|
|
|
1476
1854
|
this.emit("evt", evt);
|
|
1477
1855
|
});
|
|
1478
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
|
+
|
|
1479
1881
|
return this._voltConnection.connect(helloPayload);
|
|
1480
1882
|
} catch (err) {
|
|
1481
1883
|
log$1("connect - error [%s]", err.message);
|
|
@@ -1509,11 +1911,61 @@ function getVoltAPIClientInternal() {
|
|
|
1509
1911
|
return this._cachedClient;
|
|
1510
1912
|
}
|
|
1511
1913
|
|
|
1512
|
-
function
|
|
1513
|
-
|
|
1514
|
-
|
|
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
|
+
}
|
|
1515
1935
|
|
|
1516
|
-
|
|
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
|
+
}
|
|
1960
|
+
|
|
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);
|
|
1517
1969
|
|
|
1518
1970
|
let response = null;
|
|
1519
1971
|
|
|
@@ -1541,6 +1993,16 @@ function unaryCall(method, request) {
|
|
|
1541
1993
|
});
|
|
1542
1994
|
}
|
|
1543
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
|
+
|
|
1544
2006
|
async function fetchVoltConfig(discovery_url) {
|
|
1545
2007
|
try {
|
|
1546
2008
|
const getJSON = bent__default["default"]("json");
|
|
@@ -1621,6 +2083,8 @@ class VoltClient extends EventEmitter__default["default"] {
|
|
|
1621
2083
|
this._config = null;
|
|
1622
2084
|
this._voltConfig = null;
|
|
1623
2085
|
this._voltConnection = null;
|
|
2086
|
+
this._cachedService = {};
|
|
2087
|
+
this._activeRPC = {};
|
|
1624
2088
|
}
|
|
1625
2089
|
|
|
1626
2090
|
get config() {
|
|
@@ -1866,6 +2330,40 @@ class VoltClient extends EventEmitter__default["default"] {
|
|
|
1866
2330
|
return getVoltAPIClientInternal.call(this);
|
|
1867
2331
|
}
|
|
1868
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
|
+
|
|
1869
2367
|
/**
|
|
1870
2368
|
* Request resource access.
|
|
1871
2369
|
* @param {*} targetResourceId
|
|
@@ -1910,47 +2408,47 @@ class VoltClient extends EventEmitter__default["default"] {
|
|
|
1910
2408
|
*/
|
|
1911
2409
|
|
|
1912
2410
|
CanAccessResource(request) {
|
|
1913
|
-
return
|
|
2411
|
+
return unaryCallInternal.call(this, "CanAccessResource", request);
|
|
1914
2412
|
}
|
|
1915
2413
|
|
|
1916
2414
|
DeleteResource(request) {
|
|
1917
|
-
return
|
|
2415
|
+
return unaryCallInternal.call(this, "DeleteResource", request);
|
|
1918
2416
|
}
|
|
1919
2417
|
|
|
1920
2418
|
DiscoverServices(request) {
|
|
1921
|
-
return
|
|
2419
|
+
return unaryCallInternal.call(this, "DiscoverServices", request);
|
|
1922
2420
|
}
|
|
1923
2421
|
|
|
1924
2422
|
GetResource(request) {
|
|
1925
|
-
return
|
|
2423
|
+
return unaryCallInternal.call(this, "GetResource", request);
|
|
1926
2424
|
}
|
|
1927
2425
|
|
|
1928
2426
|
GetResources(request) {
|
|
1929
|
-
return
|
|
2427
|
+
return unaryCallInternal.call(this, "GetResources", request);
|
|
1930
2428
|
}
|
|
1931
2429
|
|
|
1932
2430
|
GetResourceAncestors(request) {
|
|
1933
|
-
return
|
|
2431
|
+
return unaryCallInternal.call(this, "GetResourceAncestors", request);
|
|
1934
2432
|
}
|
|
1935
2433
|
|
|
1936
2434
|
GetResourceDescendants(request) {
|
|
1937
|
-
return
|
|
2435
|
+
return unaryCallInternal.call(this, "GetResourceDescendants", request);
|
|
1938
2436
|
}
|
|
1939
2437
|
|
|
1940
2438
|
RequestAccess(request) {
|
|
1941
|
-
return
|
|
2439
|
+
return unaryCallInternal.call(this, "RequestAccess", request);
|
|
1942
2440
|
}
|
|
1943
2441
|
|
|
1944
2442
|
SaveResource(request) {
|
|
1945
|
-
return
|
|
2443
|
+
return unaryCallInternal.call(this, "SaveResource", request);
|
|
1946
2444
|
}
|
|
1947
2445
|
|
|
1948
2446
|
SaveResourceAttribute(request) {
|
|
1949
|
-
return
|
|
2447
|
+
return unaryCallInternal.call(this, "SaveResourceAttribute", request);
|
|
1950
2448
|
}
|
|
1951
2449
|
|
|
1952
2450
|
SetServiceStatus(request) {
|
|
1953
|
-
return
|
|
2451
|
+
return unaryCallInternal.call(this, "SetServiceStatus", request);
|
|
1954
2452
|
}
|
|
1955
2453
|
|
|
1956
2454
|
/**
|
|
@@ -1958,82 +2456,82 @@ class VoltClient extends EventEmitter__default["default"] {
|
|
|
1958
2456
|
*/
|
|
1959
2457
|
|
|
1960
2458
|
Bind(request) {
|
|
1961
|
-
return
|
|
2459
|
+
return unaryCallInternal.call(this, "Bind", request);
|
|
1962
2460
|
}
|
|
1963
2461
|
|
|
1964
2462
|
DeleteAccess(request) {
|
|
1965
|
-
return
|
|
2463
|
+
return unaryCallInternal.call(this, "DeleteAccess", request);
|
|
1966
2464
|
}
|
|
1967
2465
|
|
|
1968
2466
|
DeleteVolt(request) {
|
|
1969
|
-
return
|
|
2467
|
+
return unaryCallInternal.call(this, "DeleteVolt", request);
|
|
1970
2468
|
}
|
|
1971
2469
|
|
|
1972
2470
|
GetAccess(request) {
|
|
1973
|
-
return
|
|
2471
|
+
return unaryCallInternal.call(this, "GetAccess", request);
|
|
1974
2472
|
}
|
|
1975
2473
|
|
|
1976
2474
|
GetBindings(request) {
|
|
1977
|
-
return
|
|
2475
|
+
return unaryCallInternal.call(this, "GetBindings", request);
|
|
1978
2476
|
}
|
|
1979
2477
|
|
|
1980
2478
|
GetIdentities(request) {
|
|
1981
|
-
return
|
|
2479
|
+
return unaryCallInternal.call(this, "GetIdentities", request);
|
|
1982
2480
|
}
|
|
1983
2481
|
|
|
1984
2482
|
GetIdentity(request) {
|
|
1985
|
-
return
|
|
2483
|
+
return unaryCallInternal.call(this, "GetIdentity", request);
|
|
1986
2484
|
}
|
|
1987
2485
|
|
|
1988
2486
|
GetIdentityToken(request) {
|
|
1989
|
-
return
|
|
2487
|
+
return unaryCallInternal.call(this, "GetIdentityToken", request);
|
|
1990
2488
|
}
|
|
1991
2489
|
|
|
1992
2490
|
GetPolicy(request) {
|
|
1993
|
-
return
|
|
2491
|
+
return unaryCallInternal.call(this, "GetPolicy", request);
|
|
1994
2492
|
}
|
|
1995
2493
|
|
|
1996
2494
|
GetSettings(request) {
|
|
1997
|
-
return
|
|
2495
|
+
return unaryCallInternal.call(this, "GetSettings", request);
|
|
1998
2496
|
}
|
|
1999
2497
|
|
|
2000
2498
|
SaveAccess(request) {
|
|
2001
|
-
return
|
|
2499
|
+
return unaryCallInternal.call(this, "SaveAccess", request);
|
|
2002
2500
|
}
|
|
2003
2501
|
|
|
2004
2502
|
SaveCloudConnection(request) {
|
|
2005
|
-
return
|
|
2503
|
+
return unaryCallInternal.call(this, "SaveCloudConnection", request);
|
|
2006
2504
|
}
|
|
2007
2505
|
|
|
2008
2506
|
SaveIdentity(request) {
|
|
2009
|
-
return
|
|
2507
|
+
return unaryCallInternal.call(this, "SaveIdentity", request);
|
|
2010
2508
|
}
|
|
2011
2509
|
|
|
2012
2510
|
SaveSettings(request) {
|
|
2013
|
-
return
|
|
2511
|
+
return unaryCallInternal.call(this, "SaveSettings", request);
|
|
2014
2512
|
}
|
|
2015
2513
|
|
|
2016
2514
|
SetAccessRequestDecision(request) {
|
|
2017
|
-
return
|
|
2515
|
+
return unaryCallInternal.call(this, "SetAccessRequestDecision", request);
|
|
2018
2516
|
}
|
|
2019
2517
|
|
|
2020
2518
|
SetBindingDecision(request) {
|
|
2021
|
-
return
|
|
2519
|
+
return unaryCallInternal.call(this, "SetBindingDecision", request);
|
|
2022
2520
|
}
|
|
2023
2521
|
|
|
2024
2522
|
Shutdown(request) {
|
|
2025
|
-
return
|
|
2523
|
+
return unaryCallInternal.call(this, "Shutdown", request);
|
|
2026
2524
|
}
|
|
2027
2525
|
|
|
2028
2526
|
SignVerify(request) {
|
|
2029
|
-
return
|
|
2527
|
+
return unaryCallInternal.call(this, "SignVerify", request);
|
|
2030
2528
|
}
|
|
2031
2529
|
|
|
2032
2530
|
/**
|
|
2033
2531
|
* FileAPI
|
|
2034
2532
|
*/
|
|
2035
2533
|
GetFileDescendants(request) {
|
|
2036
|
-
return
|
|
2534
|
+
return unaryCallInternal.call(this, "GetFileDescendants", request);
|
|
2037
2535
|
}
|
|
2038
2536
|
|
|
2039
2537
|
/**
|
|
@@ -2111,6 +2609,10 @@ class VoltClient extends EventEmitter__default["default"] {
|
|
|
2111
2609
|
/**
|
|
2112
2610
|
* SqliteDatabaseAPI
|
|
2113
2611
|
*/
|
|
2612
|
+
BulkUpdate(request) {
|
|
2613
|
+
return unaryCallInternal.call(this, "BulkUpdate", request);
|
|
2614
|
+
}
|
|
2615
|
+
|
|
2114
2616
|
SqlExecute(request) {
|
|
2115
2617
|
const grpcClient = this.getVoltAPIClient();
|
|
2116
2618
|
|