@tdxvolt/volt-client-grpc 0.15.1 → 0.16.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.cjs +107 -95
- package/package.json +3 -3
- package/protobuf/tdx/volt_api/data/v1/sqlite_database_api.proto +2 -2
- package/protobuf/tdx/volt_api/volt/v1/file_api.proto +2 -0
- package/protobuf/tdx/volt_api/volt/v1/ssi.proto +40 -0
- package/protobuf/tdx/volt_api/volt/v1/ssi_api.proto +126 -0
- package/protobuf/tdx/volt_api/volt/v1/volt.proto +117 -60
- package/protobuf/tdx/volt_api/volt/v1/volt_api.proto +127 -29
- package/src/constants.js +14 -14
- package/src/grpc-call.js +31 -33
- package/src/utils.js +22 -2
- package/src/volt-client-internal.js +205 -18
- package/src/volt-client.js +9 -4
- package/src/volt-credential.js +3 -2
- package/protobuf/tdx/volt_api/ssi/v1/ssi_api.proto +0 -37
package/lib/index.cjs
CHANGED
|
@@ -38,37 +38,37 @@ const constants = {
|
|
|
38
38
|
collectionOperation: {
|
|
39
39
|
add: "ADD",
|
|
40
40
|
remove: "REMOVE",
|
|
41
|
-
update: "UPDATE"
|
|
41
|
+
update: "UPDATE"
|
|
42
42
|
},
|
|
43
43
|
crypto: {
|
|
44
44
|
subjectDefaults: [
|
|
45
45
|
{
|
|
46
46
|
name: "countryName",
|
|
47
|
-
value: "GB"
|
|
47
|
+
value: "GB"
|
|
48
48
|
},
|
|
49
49
|
{
|
|
50
50
|
name: "localityName",
|
|
51
|
-
value: "Southampton"
|
|
51
|
+
value: "Southampton"
|
|
52
52
|
},
|
|
53
53
|
{
|
|
54
54
|
name: "organizationName",
|
|
55
|
-
value: "nquiringminds Ltd"
|
|
56
|
-
}
|
|
55
|
+
value: "nquiringminds Ltd"
|
|
56
|
+
}
|
|
57
57
|
],
|
|
58
|
-
userIdOID: "0.9.2342.19200300.100.1.1"
|
|
58
|
+
userIdOID: "0.9.2342.19200300.100.1.1"
|
|
59
59
|
},
|
|
60
60
|
defaultDIDHostName: "cloud.tdxvolt.com",
|
|
61
61
|
didServiceType: {
|
|
62
|
-
voltConfig: "tdx-volt-config"
|
|
62
|
+
voltConfig: "tdx-volt-config"
|
|
63
63
|
},
|
|
64
64
|
identityType: {
|
|
65
65
|
did: "did",
|
|
66
|
-
volt: "volt"
|
|
66
|
+
volt: "volt"
|
|
67
67
|
},
|
|
68
68
|
onlineStatus: {
|
|
69
69
|
offline: "offline",
|
|
70
70
|
online: "online",
|
|
71
|
-
unknown: "unknown"
|
|
71
|
+
unknown: "unknown"
|
|
72
72
|
},
|
|
73
73
|
publicKeyPrefix: "-----BEGIN PUBLIC KEY-----",
|
|
74
74
|
privateKeyPrefix: "-----BEGIN RSA PRIVATE KEY-----",
|
|
@@ -79,14 +79,14 @@ const constants = {
|
|
|
79
79
|
proxy: "proxy",
|
|
80
80
|
proxyView: "proxy-view",
|
|
81
81
|
vc: "vc",
|
|
82
|
-
vcView: "vc-view"
|
|
82
|
+
vcView: "vc-view"
|
|
83
83
|
},
|
|
84
84
|
voltStatus: {
|
|
85
85
|
pending: "",
|
|
86
86
|
online: "online",
|
|
87
87
|
offline: "offline",
|
|
88
88
|
deleted: "deleted",
|
|
89
|
-
revoked: "revoked"
|
|
89
|
+
revoked: "revoked"
|
|
90
90
|
},
|
|
91
91
|
/**
|
|
92
92
|
* These top-level service types should map to a protobuf definition
|
|
@@ -96,16 +96,16 @@ const constants = {
|
|
|
96
96
|
fileAPI: "tdx.volt_api.volt.v1.FileAPI",
|
|
97
97
|
sqliteServerAPI: "tdx.volt_api.data.v1.SqliteServerAPI",
|
|
98
98
|
sqliteDatabaseAPI: "tdx.volt_api.data.v1.SqliteDatabaseAPI",
|
|
99
|
-
ssiAPI: "tdx.volt_api.
|
|
99
|
+
ssiAPI: "tdx.volt_api.volt.v1.SsiAPI",
|
|
100
100
|
relayAPI: "tdx.volt_api.relay.v1.RelayAPI",
|
|
101
101
|
voltAPI: "tdx.volt_api.volt.v1.VoltAPI",
|
|
102
|
-
wireAPI: "tdx.volt_api.volt.v1.WireAPI"
|
|
102
|
+
wireAPI: "tdx.volt_api.volt.v1.WireAPI"
|
|
103
103
|
},
|
|
104
104
|
tunnelInvokeMethod: "/tdx.volt_api.volt.v1.VoltAPI/Invoke",
|
|
105
105
|
tunnelPingInterval: 10000,
|
|
106
106
|
tunnelPingTimeout: 2500,
|
|
107
107
|
tunnelReconnectAfter: 30000,
|
|
108
|
-
tunnelTimeoutInterval: 10000 * 2
|
|
108
|
+
tunnelTimeoutInterval: 10000 * 2 // This must always be greater than `tunnelPingInterval`.
|
|
109
109
|
};
|
|
110
110
|
|
|
111
111
|
const { pki: pki$2 } = forge__default["default"];
|
|
@@ -167,11 +167,16 @@ const createPublicKeyFingerprint = (key) => {
|
|
|
167
167
|
return createBase58Hash(removeCarriageReturn(key));
|
|
168
168
|
};
|
|
169
169
|
|
|
170
|
+
const base64ToBase64Url = (base64) => {
|
|
171
|
+
return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
172
|
+
};
|
|
173
|
+
|
|
170
174
|
const signBase64 = (key, msg) => {
|
|
171
175
|
const md = forge__default["default"].md.sha256.create();
|
|
172
176
|
md.update(msg);
|
|
173
177
|
const signature = key.sign(md);
|
|
174
|
-
|
|
178
|
+
const base64Standard = forge__default["default"].util.encode64(signature);
|
|
179
|
+
return base64ToBase64Url(base64Standard);
|
|
175
180
|
};
|
|
176
181
|
|
|
177
182
|
const verifyBase64 = (key, msg, signature) => {
|
|
@@ -240,7 +245,8 @@ const createRSAKey = (passphrase = "") => {
|
|
|
240
245
|
const sha256Base64 = (msg) => {
|
|
241
246
|
const md = forge__default["default"].md.sha256.create();
|
|
242
247
|
md.update(msg);
|
|
243
|
-
|
|
248
|
+
const base64Standard = forge__default["default"].util.encode64(md.digest().bytes());
|
|
249
|
+
return base64ToBase64Url(base64Standard);
|
|
244
250
|
};
|
|
245
251
|
|
|
246
252
|
const decryptPrivateKey = (pem, passphrase) => {
|
|
@@ -248,6 +254,20 @@ const decryptPrivateKey = (pem, passphrase) => {
|
|
|
248
254
|
return forgePrivateKeyToPem(decryptedKey);
|
|
249
255
|
};
|
|
250
256
|
|
|
257
|
+
const jwsSignature = (signature) => {
|
|
258
|
+
//
|
|
259
|
+
// Use an unattached payload JWS signature for the DID document proof.
|
|
260
|
+
// This is a JWS with an empty payload and a detached payload digest.
|
|
261
|
+
//
|
|
262
|
+
// (https://tools.ietf.org/html/rfc7797#appendix-F) as used in the VC spec
|
|
263
|
+
// (https://www.w3.org/TR/vc-data-model/).
|
|
264
|
+
//
|
|
265
|
+
const jwsHeader = base64ToBase64Url(
|
|
266
|
+
forge__default["default"].util.encode64('{"alg":"RS256","b64": false}')
|
|
267
|
+
);
|
|
268
|
+
return jwsHeader + ".." + signature;
|
|
269
|
+
};
|
|
270
|
+
|
|
251
271
|
var utils = /*#__PURE__*/Object.freeze({
|
|
252
272
|
__proto__: null,
|
|
253
273
|
createSecureContextOptions: createSecureContextOptions,
|
|
@@ -258,12 +278,14 @@ var utils = /*#__PURE__*/Object.freeze({
|
|
|
258
278
|
removeCarriageReturn: removeCarriageReturn,
|
|
259
279
|
createBase58Hash: createBase58Hash,
|
|
260
280
|
createPublicKeyFingerprint: createPublicKeyFingerprint,
|
|
281
|
+
base64ToBase64Url: base64ToBase64Url,
|
|
261
282
|
signBase64: signBase64,
|
|
262
283
|
verifyBase64: verifyBase64,
|
|
263
284
|
getDIDResolutionURL: getDIDResolutionURL,
|
|
264
285
|
createRSAKey: createRSAKey,
|
|
265
286
|
sha256Base64: sha256Base64,
|
|
266
|
-
decryptPrivateKey: decryptPrivateKey
|
|
287
|
+
decryptPrivateKey: decryptPrivateKey,
|
|
288
|
+
jwsSignature: jwsSignature
|
|
267
289
|
});
|
|
268
290
|
|
|
269
291
|
/* eslint-disable no-underscore-dangle */
|
|
@@ -738,12 +760,13 @@ class VoltCredential {
|
|
|
738
760
|
}
|
|
739
761
|
|
|
740
762
|
static rsaEncrypt(key, buffer) {
|
|
741
|
-
|
|
763
|
+
const cipher = crypto__default["default"].publicEncrypt(key, buffer);
|
|
764
|
+
return cipher.toString("base64url");
|
|
742
765
|
}
|
|
743
766
|
|
|
744
767
|
static rsaDecrypt(key, buffer) {
|
|
745
768
|
const keyObj = crypto__default["default"].createPrivateKey(key);
|
|
746
|
-
const cipher = Buffer.from(buffer, "
|
|
769
|
+
const cipher = Buffer.from(buffer, "base64url");
|
|
747
770
|
return Buffer.from(crypto__default["default"].privateDecrypt(keyObj, cipher));
|
|
748
771
|
}
|
|
749
772
|
}
|
|
@@ -881,7 +904,7 @@ const log$4 = debug__default["default"]("volt-client-grpc:grpc-call");
|
|
|
881
904
|
function _prepareInvokeRequest(
|
|
882
905
|
request,
|
|
883
906
|
method,
|
|
884
|
-
methodType = "METHOD_TYPE_UNARY"
|
|
907
|
+
methodType = "METHOD_TYPE_UNARY"
|
|
885
908
|
) {
|
|
886
909
|
const isServiceRelayed =
|
|
887
910
|
this._service?.service_description.host_type ===
|
|
@@ -894,7 +917,7 @@ function _prepareInvokeRequest(
|
|
|
894
917
|
this._voltClient.voltConfig.id,
|
|
895
918
|
this._service?.service_description.host_public_key ||
|
|
896
919
|
this._voltClient.credential.voltPublicKey,
|
|
897
|
-
true
|
|
920
|
+
true
|
|
898
921
|
);
|
|
899
922
|
|
|
900
923
|
let invokeRequest;
|
|
@@ -925,42 +948,40 @@ function _prepareInvokeRequest(
|
|
|
925
948
|
method_name: this._grpcClient[method].path,
|
|
926
949
|
method_type: methodType,
|
|
927
950
|
token: methodToken.token,
|
|
928
|
-
request: requestPayload
|
|
929
|
-
}
|
|
951
|
+
request: requestPayload
|
|
952
|
+
}
|
|
930
953
|
};
|
|
931
954
|
|
|
932
|
-
let
|
|
955
|
+
let targetDID = [];
|
|
933
956
|
let invokePayload;
|
|
934
957
|
if (this._voltClient.isVoltRelay || isServiceRelayed) {
|
|
935
958
|
// When sending via a relay we need to encrypt the payload.
|
|
936
959
|
invokePayload = VoltCredential.aesEncrypt(
|
|
937
960
|
tunnelMethod.responseSerialize(tunnelResp),
|
|
938
961
|
methodToken.sharedKey.key,
|
|
939
|
-
methodToken.sharedKey.iv
|
|
962
|
+
methodToken.sharedKey.iv
|
|
940
963
|
);
|
|
941
964
|
} else {
|
|
942
965
|
invokePayload = tunnelMethod.responseSerialize(tunnelResp);
|
|
943
966
|
}
|
|
944
967
|
|
|
945
968
|
if (this._voltClient.isVoltRelay) {
|
|
946
|
-
|
|
969
|
+
targetDID.push(this._voltClient.voltConfig.id);
|
|
947
970
|
}
|
|
948
971
|
|
|
949
972
|
if (isServiceRelayed) {
|
|
950
973
|
// Add another relay hop if the target service is relayed.
|
|
951
974
|
log$4("target service is relayed");
|
|
952
|
-
|
|
953
|
-
this._service.service_description.host_fingerprint,
|
|
954
|
-
);
|
|
975
|
+
targetDID.push(this._service.service_description.host_client_id);
|
|
955
976
|
}
|
|
956
977
|
|
|
957
|
-
log$4("target is %j",
|
|
978
|
+
log$4("target is %j", targetDID);
|
|
958
979
|
|
|
959
980
|
invokeRequest = {
|
|
960
|
-
|
|
981
|
+
target_did: targetDID,
|
|
961
982
|
token: methodToken.token,
|
|
962
983
|
payload: invokePayload,
|
|
963
|
-
target_service_id: isServiceRelayed ? this._service.id : undefined
|
|
984
|
+
target_service_id: isServiceRelayed ? this._service.id : undefined
|
|
964
985
|
};
|
|
965
986
|
|
|
966
987
|
// Replace the target method with a call to Invoke on the relay Volt.
|
|
@@ -973,7 +994,7 @@ function _prepareInvokeRequest(
|
|
|
973
994
|
meta: methodToken,
|
|
974
995
|
method: callMethod,
|
|
975
996
|
methodName: method,
|
|
976
|
-
request: invokeRequest
|
|
997
|
+
request: invokeRequest
|
|
977
998
|
};
|
|
978
999
|
}
|
|
979
1000
|
|
|
@@ -993,18 +1014,18 @@ function _preparePayloadRequest(request, invokeInfo) {
|
|
|
993
1014
|
|
|
994
1015
|
const tunnelResp = {
|
|
995
1016
|
method_payload: {
|
|
996
|
-
payload: requestPayload
|
|
997
|
-
}
|
|
1017
|
+
payload: requestPayload
|
|
1018
|
+
}
|
|
998
1019
|
};
|
|
999
1020
|
|
|
1000
1021
|
const invokePayload = VoltCredential.aesEncrypt(
|
|
1001
1022
|
tunnelMethod.responseSerialize(tunnelResp),
|
|
1002
1023
|
invokeInfo.meta.sharedKey.key,
|
|
1003
|
-
invokeInfo.meta.sharedKey.iv
|
|
1024
|
+
invokeInfo.meta.sharedKey.iv
|
|
1004
1025
|
);
|
|
1005
1026
|
|
|
1006
1027
|
payloadRequest = {
|
|
1007
|
-
payload: invokePayload
|
|
1028
|
+
payload: invokePayload
|
|
1008
1029
|
};
|
|
1009
1030
|
} else {
|
|
1010
1031
|
payloadRequest = request;
|
|
@@ -1028,7 +1049,7 @@ function _parseResponse(method, meta, response) {
|
|
|
1028
1049
|
decryptedPayload = VoltCredential.aesDecrypt(
|
|
1029
1050
|
response.payload,
|
|
1030
1051
|
meta.sharedKey.key,
|
|
1031
|
-
meta.sharedKey.iv
|
|
1052
|
+
meta.sharedKey.iv
|
|
1032
1053
|
);
|
|
1033
1054
|
} else {
|
|
1034
1055
|
decryptedPayload = response.payload;
|
|
@@ -1039,12 +1060,12 @@ function _parseResponse(method, meta, response) {
|
|
|
1039
1060
|
if (responsePayload.payload === "method_payload") {
|
|
1040
1061
|
try {
|
|
1041
1062
|
invokeResponse.payload = this._grpcClient[method].responseDeserialize(
|
|
1042
|
-
responsePayload.method_payload.payload
|
|
1063
|
+
responsePayload.method_payload.payload
|
|
1043
1064
|
);
|
|
1044
1065
|
} catch (err) {
|
|
1045
1066
|
log$4("failure deserialising payload for %s", this._methodName);
|
|
1046
1067
|
throw new Error(
|
|
1047
|
-
"failure deserialising payload - check protobuf definition matches with data being sent"
|
|
1068
|
+
"failure deserialising payload - check protobuf definition matches with data being sent"
|
|
1048
1069
|
);
|
|
1049
1070
|
}
|
|
1050
1071
|
} else if (responsePayload.payload === "method_end") {
|
|
@@ -1058,11 +1079,11 @@ function _parseResponse(method, meta, response) {
|
|
|
1058
1079
|
"Tunnel status received: %s, code %d, description: %s",
|
|
1059
1080
|
response.status.message,
|
|
1060
1081
|
response.status.code,
|
|
1061
|
-
response.status.description || "n/a"
|
|
1082
|
+
response.status.description || "n/a"
|
|
1062
1083
|
);
|
|
1063
1084
|
invokeResponse = {
|
|
1064
1085
|
ended: true,
|
|
1065
|
-
error: `Error in tunnel: ${response.status.message}
|
|
1086
|
+
error: `Error in tunnel: ${response.status.message}`
|
|
1066
1087
|
};
|
|
1067
1088
|
} else {
|
|
1068
1089
|
invokeResponse.methodId = response.invoke_id;
|
|
@@ -1072,11 +1093,11 @@ function _parseResponse(method, meta, response) {
|
|
|
1072
1093
|
const decryptedPayload = VoltCredential.aesDecrypt(
|
|
1073
1094
|
response,
|
|
1074
1095
|
meta.sharedKey.key,
|
|
1075
|
-
meta.sharedKey.iv
|
|
1096
|
+
meta.sharedKey.iv
|
|
1076
1097
|
);
|
|
1077
1098
|
invokeResponse = {
|
|
1078
1099
|
payload:
|
|
1079
|
-
this._grpcClient[method].responseDeserializeOriginal(decryptedPayload)
|
|
1100
|
+
this._grpcClient[method].responseDeserializeOriginal(decryptedPayload)
|
|
1080
1101
|
};
|
|
1081
1102
|
} else {
|
|
1082
1103
|
invokeResponse = { payload: response };
|
|
@@ -1106,7 +1127,7 @@ class GRPCCall extends EventEmitter__default["default"] {
|
|
|
1106
1127
|
this,
|
|
1107
1128
|
request,
|
|
1108
1129
|
this._methodName,
|
|
1109
|
-
this._methodType
|
|
1130
|
+
this._methodType
|
|
1110
1131
|
);
|
|
1111
1132
|
|
|
1112
1133
|
const isServiceRelayed =
|
|
@@ -1121,7 +1142,7 @@ class GRPCCall extends EventEmitter__default["default"] {
|
|
|
1121
1142
|
}
|
|
1122
1143
|
|
|
1123
1144
|
this._call = callClient[this._initialRequest.method](
|
|
1124
|
-
this._initialRequest.meta.metadata
|
|
1145
|
+
this._initialRequest.meta.metadata
|
|
1125
1146
|
);
|
|
1126
1147
|
|
|
1127
1148
|
this._call.on("data", (streamResponse) => {
|
|
@@ -1130,14 +1151,14 @@ class GRPCCall extends EventEmitter__default["default"] {
|
|
|
1130
1151
|
this,
|
|
1131
1152
|
this._methodName,
|
|
1132
1153
|
this._initialRequest.meta,
|
|
1133
|
-
streamResponse
|
|
1154
|
+
streamResponse
|
|
1134
1155
|
);
|
|
1135
1156
|
if (parsedResponse.payload) {
|
|
1136
1157
|
// Interpret a non-empty status message as an error.
|
|
1137
1158
|
if (parsedResponse.payload?.status?.message) {
|
|
1138
1159
|
this.emit(
|
|
1139
1160
|
"error",
|
|
1140
|
-
new Error(parsedResponse.payload.status.message)
|
|
1161
|
+
new Error(parsedResponse.payload.status.message)
|
|
1141
1162
|
);
|
|
1142
1163
|
} else {
|
|
1143
1164
|
this.emit("data", parsedResponse.payload);
|
|
@@ -1156,7 +1177,7 @@ class GRPCCall extends EventEmitter__default["default"] {
|
|
|
1156
1177
|
log$4(
|
|
1157
1178
|
"failure processing %s call response: %s",
|
|
1158
1179
|
this._methodName,
|
|
1159
|
-
err.message
|
|
1180
|
+
err.message
|
|
1160
1181
|
);
|
|
1161
1182
|
this.emit("error", err);
|
|
1162
1183
|
}
|
|
@@ -1178,7 +1199,7 @@ class GRPCCall extends EventEmitter__default["default"] {
|
|
|
1178
1199
|
log$4(
|
|
1179
1200
|
"ended call %s, method id: %s",
|
|
1180
1201
|
this._methodName,
|
|
1181
|
-
this._initialRequest.methodId || "n/a - not tunnelling"
|
|
1202
|
+
this._initialRequest.methodId || "n/a - not tunnelling"
|
|
1182
1203
|
);
|
|
1183
1204
|
this.emit("end");
|
|
1184
1205
|
});
|
|
@@ -1211,7 +1232,7 @@ class GRPCCall extends EventEmitter__default["default"] {
|
|
|
1211
1232
|
const payloadRequest = _preparePayloadRequest.call(
|
|
1212
1233
|
this,
|
|
1213
1234
|
request,
|
|
1214
|
-
this._initialRequest
|
|
1235
|
+
this._initialRequest
|
|
1215
1236
|
);
|
|
1216
1237
|
return this._call.write(payloadRequest);
|
|
1217
1238
|
} else {
|
|
@@ -1219,7 +1240,7 @@ class GRPCCall extends EventEmitter__default["default"] {
|
|
|
1219
1240
|
this,
|
|
1220
1241
|
request,
|
|
1221
1242
|
this._methodName,
|
|
1222
|
-
this._methodType
|
|
1243
|
+
this._methodType
|
|
1223
1244
|
);
|
|
1224
1245
|
|
|
1225
1246
|
return this._call.write(this._initialRequest.request);
|
|
@@ -1691,30 +1712,30 @@ const voltServices = [
|
|
|
1691
1712
|
constants.serviceType.wireAPI
|
|
1692
1713
|
];
|
|
1693
1714
|
|
|
1694
|
-
function
|
|
1715
|
+
function issueAuthenticate(authenticateRequest, ttl) {
|
|
1695
1716
|
// eslint-disable-next-line no-use-before-define
|
|
1696
1717
|
return unaryCallInternal
|
|
1697
|
-
.call(this, "
|
|
1698
|
-
.then((
|
|
1699
|
-
log$1("got
|
|
1700
|
-
if (
|
|
1701
|
-
log$1("error in bind response: %s",
|
|
1702
|
-
return Promise.reject(new Error(
|
|
1718
|
+
.call(this, "Authenticate", authenticateRequest)
|
|
1719
|
+
.then((authenticateResponse) => {
|
|
1720
|
+
log$1("got authenticate response %j", authenticateResponse);
|
|
1721
|
+
if (authenticateResponse.status?.code) {
|
|
1722
|
+
log$1("error in bind response: %s", authenticateResponse.status.message);
|
|
1723
|
+
return Promise.reject(new Error(authenticateResponse.status.message));
|
|
1703
1724
|
} else {
|
|
1704
|
-
switch (
|
|
1725
|
+
switch (authenticateResponse.decision) {
|
|
1705
1726
|
case "POLICY_DECISION_PERMIT": {
|
|
1706
1727
|
//
|
|
1707
1728
|
// The request status is permit => cache the bind response info.
|
|
1708
1729
|
//
|
|
1709
1730
|
|
|
1710
1731
|
// This is the certificate assigned to us by the volt.
|
|
1711
|
-
this._credential.cache.cert =
|
|
1732
|
+
this._credential.cache.cert = authenticateResponse.cert;
|
|
1712
1733
|
|
|
1713
1734
|
// This is the signing CA used by the volt.
|
|
1714
|
-
this._credential.cache.ca =
|
|
1735
|
+
this._credential.cache.ca = authenticateResponse.chain;
|
|
1715
1736
|
|
|
1716
1737
|
// Identity resource id is assigned by the volt.
|
|
1717
|
-
this._credential.cache.client_id =
|
|
1738
|
+
this._credential.cache.client_id = authenticateResponse.session_id;
|
|
1718
1739
|
this._credential.saveCache();
|
|
1719
1740
|
break;
|
|
1720
1741
|
}
|
|
@@ -1728,12 +1749,15 @@ function issueBind(bindRequest, ttl) {
|
|
|
1728
1749
|
break;
|
|
1729
1750
|
}
|
|
1730
1751
|
default:
|
|
1731
|
-
log$1(
|
|
1752
|
+
log$1(
|
|
1753
|
+
"ignoring unknown bind descision %s",
|
|
1754
|
+
authenticateResponse.status
|
|
1755
|
+
);
|
|
1732
1756
|
break;
|
|
1733
1757
|
}
|
|
1734
1758
|
}
|
|
1735
1759
|
|
|
1736
|
-
return
|
|
1760
|
+
return authenticateResponse.decision;
|
|
1737
1761
|
});
|
|
1738
1762
|
}
|
|
1739
1763
|
|
|
@@ -1746,7 +1770,8 @@ function findDIDDocumentService(document, serviceType) {
|
|
|
1746
1770
|
return matches;
|
|
1747
1771
|
}
|
|
1748
1772
|
|
|
1749
|
-
|
|
1773
|
+
|
|
1774
|
+
async function authenticateInternal() {
|
|
1750
1775
|
try {
|
|
1751
1776
|
// Check if we need to resolve a Relay volt.
|
|
1752
1777
|
if (
|
|
@@ -1760,6 +1785,7 @@ async function bindInternal() {
|
|
|
1760
1785
|
this,
|
|
1761
1786
|
`${relayURL}/discovery`
|
|
1762
1787
|
);
|
|
1788
|
+
|
|
1763
1789
|
if (this._voltConfig.relay.ca_pem) {
|
|
1764
1790
|
log$1(
|
|
1765
1791
|
"Auto-fetched Relay CA %s, remote address %s",
|
|
@@ -1793,21 +1819,14 @@ async function bindInternal() {
|
|
|
1793
1819
|
this._credential.saveCache();
|
|
1794
1820
|
|
|
1795
1821
|
// Form the request message.
|
|
1796
|
-
const
|
|
1822
|
+
const authenticateRequest = {
|
|
1797
1823
|
binding_name: this._config.client_name,
|
|
1798
1824
|
public_key: publicKeyPem,
|
|
1799
1825
|
host: this._credential.cache.bindIp,
|
|
1800
|
-
x509_credential: []
|
|
1801
1826
|
};
|
|
1802
1827
|
|
|
1803
|
-
if (this._credential.cache.cert) {
|
|
1804
|
-
bindRequest.x509_credential = [
|
|
1805
|
-
this._credential.cache.cert + this._credential.cache.ca
|
|
1806
|
-
];
|
|
1807
|
-
}
|
|
1808
|
-
|
|
1809
1828
|
if (this._voltConfig.challenge_code) {
|
|
1810
|
-
|
|
1829
|
+
authenticateRequest.challenge = signBase64(
|
|
1811
1830
|
keyPair.privateKey,
|
|
1812
1831
|
this._voltConfig.challenge_code
|
|
1813
1832
|
);
|
|
@@ -1817,15 +1836,7 @@ async function bindInternal() {
|
|
|
1817
1836
|
);
|
|
1818
1837
|
}
|
|
1819
1838
|
|
|
1820
|
-
|
|
1821
|
-
if (this._voltConfig?.relay?.ca_pem && this._credential.cache.cloud_cert) {
|
|
1822
|
-
bindRequest.x509_credential = bindRequest.x509_credential.concat(
|
|
1823
|
-
this._credential.cache.cloud_cert + this._voltConfig.relay.ca_pem
|
|
1824
|
-
);
|
|
1825
|
-
}
|
|
1826
|
-
|
|
1827
|
-
log$1("sending %d x509 credentials", bindRequest.x509_credential.length);
|
|
1828
|
-
log$1("bind TTL is ", this._config.bindRequestTTL);
|
|
1839
|
+
log$1("authenticate TTL is ", this._config.bindRequestTTL);
|
|
1829
1840
|
|
|
1830
1841
|
// This will block while the request is pending.
|
|
1831
1842
|
const pollInterval = 10000;
|
|
@@ -1837,12 +1848,12 @@ async function bindInternal() {
|
|
|
1837
1848
|
await new Promise((resolve) => setTimeout(resolve, pollInterval));
|
|
1838
1849
|
}
|
|
1839
1850
|
// eslint-disable-next-line no-await-in-loop
|
|
1840
|
-
decision = await
|
|
1851
|
+
decision = await issueAuthenticate.call(
|
|
1841
1852
|
this,
|
|
1842
|
-
|
|
1853
|
+
authenticateRequest,
|
|
1843
1854
|
this._voltConfig.bindRequestTTL
|
|
1844
1855
|
);
|
|
1845
|
-
log$1("
|
|
1856
|
+
log$1("authenticate decision: %s", decision);
|
|
1846
1857
|
} while (
|
|
1847
1858
|
decision === "POLICY_DECISION_PROMPT" ||
|
|
1848
1859
|
decision === "POLICY_DECISION_PENDING"
|
|
@@ -1964,8 +1975,6 @@ function getVoltAPIClientInternal() {
|
|
|
1964
1975
|
|
|
1965
1976
|
function getAPIClientInternal(service) {
|
|
1966
1977
|
if (!this._cachedService[service.id]) {
|
|
1967
|
-
service.service_description.host_type === "SERVICE_HOST_TYPE_RELAYED";
|
|
1968
|
-
|
|
1969
1978
|
const serviceAddress = this.isRemote
|
|
1970
1979
|
? this._voltConfig.relay.address
|
|
1971
1980
|
: service.service_description.host_address;
|
|
@@ -2013,9 +2022,8 @@ function getServiceClient(service) {
|
|
|
2013
2022
|
}
|
|
2014
2023
|
|
|
2015
2024
|
function unaryCallInternal(method, request, service) {
|
|
2016
|
-
const grpcClient = getServiceClient.call(this, service);
|
|
2017
|
-
|
|
2018
2025
|
return new Promise((resolve, reject) => {
|
|
2026
|
+
const grpcClient = getServiceClient.call(this, service);
|
|
2019
2027
|
const call = new GRPCCall(this, method, "METHOD_TYPE_UNARY", service);
|
|
2020
2028
|
|
|
2021
2029
|
let response = null;
|
|
@@ -2264,14 +2272,14 @@ class VoltClient extends EventEmitter__default["default"] {
|
|
|
2264
2272
|
if (this._credential._cryptoCache.cert) {
|
|
2265
2273
|
isBound = true;
|
|
2266
2274
|
} else {
|
|
2267
|
-
// No certificate present in the cache yet => we need to
|
|
2275
|
+
// No certificate present in the cache yet => we need to authenticate.
|
|
2268
2276
|
try {
|
|
2269
|
-
isBound = await
|
|
2277
|
+
isBound = await authenticateInternal.call(this);
|
|
2270
2278
|
} catch (bindErr) {
|
|
2271
2279
|
if (bindErr.message === "invalid arguments") {
|
|
2272
2280
|
// This is usually the result of a missing challenge signature or credential.
|
|
2273
2281
|
log(
|
|
2274
|
-
"failure
|
|
2282
|
+
"failure authenticating on Volt - did you supply a challenge code or verified credential?"
|
|
2275
2283
|
);
|
|
2276
2284
|
throw bindErr;
|
|
2277
2285
|
}
|
|
@@ -2280,7 +2288,7 @@ class VoltClient extends EventEmitter__default["default"] {
|
|
|
2280
2288
|
|
|
2281
2289
|
if (!isBound) {
|
|
2282
2290
|
// This is usually because of request being denied.
|
|
2283
|
-
throw new Error("Volt
|
|
2291
|
+
throw new Error("Volt authentication failed");
|
|
2284
2292
|
}
|
|
2285
2293
|
|
|
2286
2294
|
return Promise.resolve();
|
|
@@ -2506,6 +2514,10 @@ class VoltClient extends EventEmitter__default["default"] {
|
|
|
2506
2514
|
* VoltAPI - volt management
|
|
2507
2515
|
*/
|
|
2508
2516
|
|
|
2517
|
+
Authenticate(request) {
|
|
2518
|
+
return unaryCallInternal.call(this, "Authenticate", request);
|
|
2519
|
+
}
|
|
2520
|
+
|
|
2509
2521
|
Bind(request) {
|
|
2510
2522
|
return unaryCallInternal.call(this, "Bind", request);
|
|
2511
2523
|
}
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "0.
|
|
6
|
+
"version": "0.16.0-beta.1",
|
|
7
7
|
"description": "tdx Volt library for nodejs clients",
|
|
8
8
|
"type": "module",
|
|
9
9
|
"exports": {
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"jsonwebtoken": "^8.5.1",
|
|
46
46
|
"lodash": "^4.17.15",
|
|
47
47
|
"minimist": "^1.2.0",
|
|
48
|
-
"node-forge": "^
|
|
48
|
+
"node-forge": "^1.3.1",
|
|
49
49
|
"uuid": "^8.1.0"
|
|
50
50
|
}
|
|
51
|
-
}
|
|
51
|
+
}
|
|
@@ -50,9 +50,9 @@ message SqlExecuteRequest {
|
|
|
50
50
|
// This can be used to limit the number of rows returned by `SELECT` statements to avoid overloading a client. It is similar to using 'LIMIT/OFFSET' clauses on the 'SELECT' statement, but this method is easier to manage and the entire result set will be prepared on the Volt, and the client can then page through it by sending successive messages.
|
|
51
51
|
uint32 page_size = 3;
|
|
52
52
|
|
|
53
|
-
// The
|
|
53
|
+
// The values to set for each parameter defined in a database query.
|
|
54
54
|
// This field is only relevant to 'query' databases, i.e. those with kind `tdx:sqlite-query`.
|
|
55
|
-
// The values in the
|
|
55
|
+
// The values in the map should be keyed by parameter name.
|
|
56
56
|
// A query may have no parameters defined, in which case leave this field empty.
|
|
57
57
|
map<string, tdx.volt_api.volt.v1.AttributeValue> parameter = 4;
|
|
58
58
|
}
|
|
@@ -37,6 +37,8 @@ message DownloadFileRequest {
|
|
|
37
37
|
string file_path = 2;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
// The response stream will contain one or more of the following messages.
|
|
41
|
+
// Each response message will contain one of the following fields.
|
|
40
42
|
message DownloadFileResponse {
|
|
41
43
|
oneof payload {
|
|
42
44
|
// A chunk of file data.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
syntax = "proto3";
|
|
2
|
+
|
|
3
|
+
package tdx.volt_api.volt.v1;
|
|
4
|
+
|
|
5
|
+
message DIDRegistryUpdate {
|
|
6
|
+
// The id of the update.
|
|
7
|
+
// This is populated and maintained by the Volt.
|
|
8
|
+
uint64 id = 1;
|
|
9
|
+
|
|
10
|
+
// The id of the identity.
|
|
11
|
+
string did = 2;
|
|
12
|
+
|
|
13
|
+
// The type of update.
|
|
14
|
+
string operation = 3;
|
|
15
|
+
|
|
16
|
+
// The DID document contained in the update.
|
|
17
|
+
string document = 4;
|
|
18
|
+
|
|
19
|
+
// The signature extracted from the DID document.
|
|
20
|
+
string signature = 5;
|
|
21
|
+
|
|
22
|
+
// The signature of the update.
|
|
23
|
+
string update_signature = 6;
|
|
24
|
+
|
|
25
|
+
uint64 timestamp = 7;
|
|
26
|
+
|
|
27
|
+
// The vector clocks for this DID.
|
|
28
|
+
// The vector clocks are a map of the peer ID to the id of the last update received for this DID.
|
|
29
|
+
map<string, uint64> vector_clock = 8;
|
|
30
|
+
|
|
31
|
+
string origin_volt = 9;
|
|
32
|
+
|
|
33
|
+
string description = 10;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
message VerifiablePresentation {
|
|
37
|
+
string credential = 1;
|
|
38
|
+
string signature = 2;
|
|
39
|
+
}
|
|
40
|
+
|