@tdxvolt/volt-client-grpc 0.15.1 → 0.16.0-beta.10

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 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.ssi.v1.SsiAPI",
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, // This must always be greater than `tunnelPingInterval`.
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
- return forge__default["default"].util.encode64(signature);
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
- return forge__default["default"].util.encode64(md.digest().bytes());
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 */
@@ -567,8 +589,16 @@ class VoltCredential {
567
589
  return this._cryptoCache;
568
590
  }
569
591
 
570
- get clientId() {
571
- return this._cryptoCache.client_id;
592
+ get certificate() {
593
+ return this._cryptoCache.cert;
594
+ }
595
+
596
+ get sessionId() {
597
+ return this._cryptoCache.session_id;
598
+ }
599
+
600
+ get identityId() {
601
+ return this._cryptoCache.identity_id;
572
602
  }
573
603
 
574
604
  get voltPublicKey() {
@@ -656,7 +686,7 @@ class VoltCredential {
656
686
  aud: audience,
657
687
  iat: Math.floor(Date.now() / 1000) - ttl,
658
688
  exp: Math.floor(Date.now() / 1000) + ttl,
659
- sub: this._cryptoCache.client_id
689
+ sub: this._cryptoCache.session_id
660
690
  };
661
691
 
662
692
  let sharedKey;
@@ -738,12 +768,13 @@ class VoltCredential {
738
768
  }
739
769
 
740
770
  static rsaEncrypt(key, buffer) {
741
- return crypto__default["default"].publicEncrypt(key, buffer).toString("base64");
771
+ const cipher = crypto__default["default"].publicEncrypt(key, buffer);
772
+ return cipher.toString("base64url");
742
773
  }
743
774
 
744
775
  static rsaDecrypt(key, buffer) {
745
776
  const keyObj = crypto__default["default"].createPrivateKey(key);
746
- const cipher = Buffer.from(buffer, "base64");
777
+ const cipher = Buffer.from(buffer, "base64url");
747
778
  return Buffer.from(crypto__default["default"].privateDecrypt(keyObj, cipher));
748
779
  }
749
780
  }
@@ -881,7 +912,7 @@ const log$4 = debug__default["default"]("volt-client-grpc:grpc-call");
881
912
  function _prepareInvokeRequest(
882
913
  request,
883
914
  method,
884
- methodType = "METHOD_TYPE_UNARY",
915
+ methodType = "METHOD_TYPE_UNARY"
885
916
  ) {
886
917
  const isServiceRelayed =
887
918
  this._service?.service_description.host_type ===
@@ -894,7 +925,7 @@ function _prepareInvokeRequest(
894
925
  this._voltClient.voltConfig.id,
895
926
  this._service?.service_description.host_public_key ||
896
927
  this._voltClient.credential.voltPublicKey,
897
- true,
928
+ true
898
929
  );
899
930
 
900
931
  let invokeRequest;
@@ -925,42 +956,40 @@ function _prepareInvokeRequest(
925
956
  method_name: this._grpcClient[method].path,
926
957
  method_type: methodType,
927
958
  token: methodToken.token,
928
- request: requestPayload,
929
- },
959
+ request: requestPayload
960
+ }
930
961
  };
931
962
 
932
- let targetFingerprint = [];
963
+ let targetDID = [];
933
964
  let invokePayload;
934
965
  if (this._voltClient.isVoltRelay || isServiceRelayed) {
935
966
  // When sending via a relay we need to encrypt the payload.
936
967
  invokePayload = VoltCredential.aesEncrypt(
937
968
  tunnelMethod.responseSerialize(tunnelResp),
938
969
  methodToken.sharedKey.key,
939
- methodToken.sharedKey.iv,
970
+ methodToken.sharedKey.iv
940
971
  );
941
972
  } else {
942
973
  invokePayload = tunnelMethod.responseSerialize(tunnelResp);
943
974
  }
944
975
 
945
976
  if (this._voltClient.isVoltRelay) {
946
- targetFingerprint.push(this._voltClient.credential.voltFingerprint);
977
+ targetDID.push(this._voltClient.voltConfig.id);
947
978
  }
948
979
 
949
980
  if (isServiceRelayed) {
950
981
  // Add another relay hop if the target service is relayed.
951
982
  log$4("target service is relayed");
952
- targetFingerprint.push(
953
- this._service.service_description.host_fingerprint,
954
- );
983
+ targetDID.push(this._service.service_description.host_client_id);
955
984
  }
956
985
 
957
- log$4("target is %j", targetFingerprint);
986
+ log$4("target is %j", targetDID);
958
987
 
959
988
  invokeRequest = {
960
- target_fingerprint: targetFingerprint,
989
+ target_did: targetDID,
961
990
  token: methodToken.token,
962
991
  payload: invokePayload,
963
- target_service_id: isServiceRelayed ? this._service.id : undefined,
992
+ target_service_id: isServiceRelayed ? this._service.id : undefined
964
993
  };
965
994
 
966
995
  // Replace the target method with a call to Invoke on the relay Volt.
@@ -973,7 +1002,7 @@ function _prepareInvokeRequest(
973
1002
  meta: methodToken,
974
1003
  method: callMethod,
975
1004
  methodName: method,
976
- request: invokeRequest,
1005
+ request: invokeRequest
977
1006
  };
978
1007
  }
979
1008
 
@@ -993,18 +1022,18 @@ function _preparePayloadRequest(request, invokeInfo) {
993
1022
 
994
1023
  const tunnelResp = {
995
1024
  method_payload: {
996
- payload: requestPayload,
997
- },
1025
+ payload: requestPayload
1026
+ }
998
1027
  };
999
1028
 
1000
1029
  const invokePayload = VoltCredential.aesEncrypt(
1001
1030
  tunnelMethod.responseSerialize(tunnelResp),
1002
1031
  invokeInfo.meta.sharedKey.key,
1003
- invokeInfo.meta.sharedKey.iv,
1032
+ invokeInfo.meta.sharedKey.iv
1004
1033
  );
1005
1034
 
1006
1035
  payloadRequest = {
1007
- payload: invokePayload,
1036
+ payload: invokePayload
1008
1037
  };
1009
1038
  } else {
1010
1039
  payloadRequest = request;
@@ -1028,7 +1057,7 @@ function _parseResponse(method, meta, response) {
1028
1057
  decryptedPayload = VoltCredential.aesDecrypt(
1029
1058
  response.payload,
1030
1059
  meta.sharedKey.key,
1031
- meta.sharedKey.iv,
1060
+ meta.sharedKey.iv
1032
1061
  );
1033
1062
  } else {
1034
1063
  decryptedPayload = response.payload;
@@ -1039,12 +1068,12 @@ function _parseResponse(method, meta, response) {
1039
1068
  if (responsePayload.payload === "method_payload") {
1040
1069
  try {
1041
1070
  invokeResponse.payload = this._grpcClient[method].responseDeserialize(
1042
- responsePayload.method_payload.payload,
1071
+ responsePayload.method_payload.payload
1043
1072
  );
1044
1073
  } catch (err) {
1045
1074
  log$4("failure deserialising payload for %s", this._methodName);
1046
1075
  throw new Error(
1047
- "failure deserialising payload - check protobuf definition matches with data being sent",
1076
+ "failure deserialising payload - check protobuf definition matches with data being sent"
1048
1077
  );
1049
1078
  }
1050
1079
  } else if (responsePayload.payload === "method_end") {
@@ -1058,11 +1087,11 @@ function _parseResponse(method, meta, response) {
1058
1087
  "Tunnel status received: %s, code %d, description: %s",
1059
1088
  response.status.message,
1060
1089
  response.status.code,
1061
- response.status.description || "n/a",
1090
+ response.status.description || "n/a"
1062
1091
  );
1063
1092
  invokeResponse = {
1064
1093
  ended: true,
1065
- error: `Error in tunnel: ${response.status.message}`,
1094
+ error: `Error in tunnel: ${response.status.message}`
1066
1095
  };
1067
1096
  } else {
1068
1097
  invokeResponse.methodId = response.invoke_id;
@@ -1072,11 +1101,11 @@ function _parseResponse(method, meta, response) {
1072
1101
  const decryptedPayload = VoltCredential.aesDecrypt(
1073
1102
  response,
1074
1103
  meta.sharedKey.key,
1075
- meta.sharedKey.iv,
1104
+ meta.sharedKey.iv
1076
1105
  );
1077
1106
  invokeResponse = {
1078
1107
  payload:
1079
- this._grpcClient[method].responseDeserializeOriginal(decryptedPayload),
1108
+ this._grpcClient[method].responseDeserializeOriginal(decryptedPayload)
1080
1109
  };
1081
1110
  } else {
1082
1111
  invokeResponse = { payload: response };
@@ -1106,7 +1135,7 @@ class GRPCCall extends EventEmitter__default["default"] {
1106
1135
  this,
1107
1136
  request,
1108
1137
  this._methodName,
1109
- this._methodType,
1138
+ this._methodType
1110
1139
  );
1111
1140
 
1112
1141
  const isServiceRelayed =
@@ -1121,7 +1150,7 @@ class GRPCCall extends EventEmitter__default["default"] {
1121
1150
  }
1122
1151
 
1123
1152
  this._call = callClient[this._initialRequest.method](
1124
- this._initialRequest.meta.metadata,
1153
+ this._initialRequest.meta.metadata
1125
1154
  );
1126
1155
 
1127
1156
  this._call.on("data", (streamResponse) => {
@@ -1130,14 +1159,14 @@ class GRPCCall extends EventEmitter__default["default"] {
1130
1159
  this,
1131
1160
  this._methodName,
1132
1161
  this._initialRequest.meta,
1133
- streamResponse,
1162
+ streamResponse
1134
1163
  );
1135
1164
  if (parsedResponse.payload) {
1136
1165
  // Interpret a non-empty status message as an error.
1137
1166
  if (parsedResponse.payload?.status?.message) {
1138
1167
  this.emit(
1139
1168
  "error",
1140
- new Error(parsedResponse.payload.status.message),
1169
+ new Error(parsedResponse.payload.status.message)
1141
1170
  );
1142
1171
  } else {
1143
1172
  this.emit("data", parsedResponse.payload);
@@ -1156,7 +1185,7 @@ class GRPCCall extends EventEmitter__default["default"] {
1156
1185
  log$4(
1157
1186
  "failure processing %s call response: %s",
1158
1187
  this._methodName,
1159
- err.message,
1188
+ err.message
1160
1189
  );
1161
1190
  this.emit("error", err);
1162
1191
  }
@@ -1178,7 +1207,7 @@ class GRPCCall extends EventEmitter__default["default"] {
1178
1207
  log$4(
1179
1208
  "ended call %s, method id: %s",
1180
1209
  this._methodName,
1181
- this._initialRequest.methodId || "n/a - not tunnelling",
1210
+ this._initialRequest.methodId || "n/a - not tunnelling"
1182
1211
  );
1183
1212
  this.emit("end");
1184
1213
  });
@@ -1211,7 +1240,7 @@ class GRPCCall extends EventEmitter__default["default"] {
1211
1240
  const payloadRequest = _preparePayloadRequest.call(
1212
1241
  this,
1213
1242
  request,
1214
- this._initialRequest,
1243
+ this._initialRequest
1215
1244
  );
1216
1245
  return this._call.write(payloadRequest);
1217
1246
  } else {
@@ -1219,7 +1248,7 @@ class GRPCCall extends EventEmitter__default["default"] {
1219
1248
  this,
1220
1249
  request,
1221
1250
  this._methodName,
1222
- this._methodType,
1251
+ this._methodType
1223
1252
  );
1224
1253
 
1225
1254
  return this._call.write(this._initialRequest.request);
@@ -1244,10 +1273,9 @@ function _cleanUp(immediateReconnect) {
1244
1273
  this._pingTimeoutTimer = 0;
1245
1274
  }
1246
1275
 
1247
- if (
1248
- !this._dying &&
1249
- (immediateReconnect || (this._autoRetry && !this._reconnectTimer))
1250
- ) {
1276
+ if (this._dying) {
1277
+ clearTimeout(this._reconnectTimer);
1278
+ } else if (immediateReconnect || (this._autoRetry && !this._reconnectTimer)) {
1251
1279
  this._reconnectTimer = setTimeout(
1252
1280
  () => {
1253
1281
  this._reconnectTimer = 0;
@@ -1691,30 +1719,31 @@ const voltServices = [
1691
1719
  constants.serviceType.wireAPI
1692
1720
  ];
1693
1721
 
1694
- function issueBind(bindRequest, ttl) {
1722
+ function issueAuthenticate(authenticateRequest, ttl) {
1695
1723
  // eslint-disable-next-line no-use-before-define
1696
1724
  return unaryCallInternal
1697
- .call(this, "Bind", bindRequest)
1698
- .then((bindResponse) => {
1699
- log$1("got binding request response %j", bindResponse);
1700
- if (bindResponse.status?.code) {
1701
- log$1("error in bind response: %s", bindResponse.status.message);
1702
- return Promise.reject(new Error(bindResponse.status.message));
1725
+ .call(this, "Authenticate", authenticateRequest)
1726
+ .then((authenticateResponse) => {
1727
+ log$1("got authenticate response %j", authenticateResponse);
1728
+ if (authenticateResponse.status?.code) {
1729
+ log$1("error in bind response: %s", authenticateResponse.status.message);
1730
+ return Promise.reject(new Error(authenticateResponse.status.message));
1703
1731
  } else {
1704
- switch (bindResponse.decision) {
1732
+ switch (authenticateResponse.decision) {
1705
1733
  case "POLICY_DECISION_PERMIT": {
1706
1734
  //
1707
1735
  // The request status is permit => cache the bind response info.
1708
1736
  //
1709
1737
 
1710
1738
  // This is the certificate assigned to us by the volt.
1711
- this._credential.cache.cert = bindResponse.cert;
1739
+ this._credential.cache.cert = authenticateResponse.cert;
1712
1740
 
1713
1741
  // This is the signing CA used by the volt.
1714
- this._credential.cache.ca = bindResponse.chain;
1742
+ this._credential.cache.ca = authenticateResponse.chain;
1715
1743
 
1716
1744
  // Identity resource id is assigned by the volt.
1717
- this._credential.cache.client_id = bindResponse.identity_id;
1745
+ this._credential.cache.session_id = authenticateResponse.session_id;
1746
+
1718
1747
  this._credential.saveCache();
1719
1748
  break;
1720
1749
  }
@@ -1728,12 +1757,15 @@ function issueBind(bindRequest, ttl) {
1728
1757
  break;
1729
1758
  }
1730
1759
  default:
1731
- log$1("ignoring unknown bind descision %s", bindResponse.status);
1760
+ log$1(
1761
+ "ignoring unknown bind descision %s",
1762
+ authenticateResponse.status
1763
+ );
1732
1764
  break;
1733
1765
  }
1734
1766
  }
1735
1767
 
1736
- return bindResponse.decision;
1768
+ return authenticateResponse.decision;
1737
1769
  });
1738
1770
  }
1739
1771
 
@@ -1746,7 +1778,7 @@ function findDIDDocumentService(document, serviceType) {
1746
1778
  return matches;
1747
1779
  }
1748
1780
 
1749
- async function bindInternal() {
1781
+ async function authenticateInternal(useDID = true) {
1750
1782
  try {
1751
1783
  // Check if we need to resolve a Relay volt.
1752
1784
  if (
@@ -1760,6 +1792,7 @@ async function bindInternal() {
1760
1792
  this,
1761
1793
  `${relayURL}/discovery`
1762
1794
  );
1795
+
1763
1796
  if (this._voltConfig.relay.ca_pem) {
1764
1797
  log$1(
1765
1798
  "Auto-fetched Relay CA %s, remote address %s",
@@ -1782,7 +1815,9 @@ async function bindInternal() {
1782
1815
  }
1783
1816
 
1784
1817
  const keyPair = this._credential.getKey();
1785
- const publicKeyPem = pki.publicKeyToPem(keyPair.publicKey);
1818
+ const publicKeyPem = removeCarriageReturn(
1819
+ pki.publicKeyToPem(keyPair.publicKey)
1820
+ );
1786
1821
 
1787
1822
  if (!this._credential.cache.bindIp) {
1788
1823
  // Default the IP address if none is specified. This is used to set the SAN in the
@@ -1793,21 +1828,13 @@ async function bindInternal() {
1793
1828
  this._credential.saveCache();
1794
1829
 
1795
1830
  // Form the request message.
1796
- const bindRequest = {
1831
+ const authenticateRequest = {
1797
1832
  binding_name: this._config.client_name,
1798
- public_key: publicKeyPem,
1799
- host: this._credential.cache.bindIp,
1800
- x509_credential: []
1833
+ host: this._credential.cache.bindIp
1801
1834
  };
1802
1835
 
1803
- if (this._credential.cache.cert) {
1804
- bindRequest.x509_credential = [
1805
- this._credential.cache.cert + this._credential.cache.ca
1806
- ];
1807
- }
1808
-
1809
1836
  if (this._voltConfig.challenge_code) {
1810
- bindRequest.challenge = signBase64(
1837
+ authenticateRequest.challenge = signBase64(
1811
1838
  keyPair.privateKey,
1812
1839
  this._voltConfig.challenge_code
1813
1840
  );
@@ -1817,15 +1844,71 @@ async function bindInternal() {
1817
1844
  );
1818
1845
  }
1819
1846
 
1820
- // For remote connections, add our cloud-issued certificate as an additional credential.
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
1847
+ if (!useDID) {
1848
+ authenticateRequest.public_key = publicKeyPem;
1849
+ } else if (!this._credential.cache.identity_id) {
1850
+ // If we don't have an identity id, then we need to create a DID.
1851
+ this._credential.cache.identity_id = `did:volt:${uuid.v4()}`;
1852
+
1853
+ const did = this._credential.cache.identity_id;
1854
+
1855
+ // Order of properties in the DID document is important,
1856
+ // they must be in alphabetical order throughout the document.
1857
+ // This is because the DID document is signed and the signature
1858
+ // is over the entire document.
1859
+ const didDocument = {
1860
+ "@context": "https://www.w3.org/ns/did/v1",
1861
+ authentication: [`${did}#key-1`],
1862
+ description: this._config.client_name,
1863
+ id: did,
1864
+ verificationMethod: [
1865
+ {
1866
+ controller: did,
1867
+ id: `${did}#key-1`,
1868
+ publicKeyPem: publicKeyPem,
1869
+ type: "RsaSignature2018"
1870
+ }
1871
+ ]
1872
+ };
1873
+
1874
+ const signDocument = JSON.stringify(didDocument, null, 2);
1875
+ log$1("signing did document");
1876
+ log$1(signDocument);
1877
+
1878
+ // Sign the DID document.
1879
+ const documentDigest = signBase64(
1880
+ keyPair.privateKey,
1881
+ signDocument
1824
1882
  );
1883
+
1884
+ const proofSignature = jwsSignature(documentDigest);
1885
+
1886
+ // Create the DID document proof.
1887
+ didDocument.proof = {
1888
+ created: new Date().toISOString(),
1889
+ jws: proofSignature,
1890
+ proofPurpose: "assertionMethod",
1891
+ type: "RsaSignature2018",
1892
+ verificationMethod: `${did}#key-1`
1893
+ };
1894
+
1895
+ // Set the DID document with proof in the authenticate request.
1896
+ authenticateRequest.did_document = JSON.stringify(didDocument, null, 2);
1897
+
1898
+ // Now sign the entire DID document, including the proof and set it in the
1899
+ // bind request. This is required by the Volt to verify that we have the private key for the DID.
1900
+ authenticateRequest.did_document_signature = signBase64(
1901
+ keyPair.privateKey,
1902
+ authenticateRequest.did_document
1903
+ );
1904
+
1905
+ log$1("did document is %s", authenticateRequest.did_document);
1906
+ log$1("did signature is %s", authenticateRequest.did_document_signature);
1907
+ } else {
1908
+ authenticateRequest.did = this._credential.cache.identity_id;
1825
1909
  }
1826
1910
 
1827
- log$1("sending %d x509 credentials", bindRequest.x509_credential.length);
1828
- log$1("bind TTL is ", this._config.bindRequestTTL);
1911
+ log$1("authenticate TTL is ", this._config.bindRequestTTL);
1829
1912
 
1830
1913
  // This will block while the request is pending.
1831
1914
  const pollInterval = 10000;
@@ -1837,12 +1920,12 @@ async function bindInternal() {
1837
1920
  await new Promise((resolve) => setTimeout(resolve, pollInterval));
1838
1921
  }
1839
1922
  // eslint-disable-next-line no-await-in-loop
1840
- decision = await issueBind.call(
1923
+ decision = await issueAuthenticate.call(
1841
1924
  this,
1842
- bindRequest,
1925
+ authenticateRequest,
1843
1926
  this._voltConfig.bindRequestTTL
1844
1927
  );
1845
- log$1("binding decision: %s", decision);
1928
+ log$1("authenticate decision: %s", decision);
1846
1929
  } while (
1847
1930
  decision === "POLICY_DECISION_PROMPT" ||
1848
1931
  decision === "POLICY_DECISION_PENDING"
@@ -1895,6 +1978,15 @@ function connectInternal(helloPayload) {
1895
1978
  onDisconnected();
1896
1979
  this.emit("connected", false);
1897
1980
  }
1981
+
1982
+ if (err.message.endsWith("session invalid")) {
1983
+ log$1("Volt session invalid - clearing session");
1984
+ delete this._credential.cache.session_id;
1985
+ delete this._credential.cache.cert;
1986
+ this._credential.saveCache();
1987
+ }
1988
+
1989
+ this.emit("connectionError", err);
1898
1990
  });
1899
1991
 
1900
1992
  this._voltConnection.on("evt", (evt) => {
@@ -1964,8 +2056,6 @@ function getVoltAPIClientInternal() {
1964
2056
 
1965
2057
  function getAPIClientInternal(service) {
1966
2058
  if (!this._cachedService[service.id]) {
1967
- service.service_description.host_type === "SERVICE_HOST_TYPE_RELAYED";
1968
-
1969
2059
  const serviceAddress = this.isRemote
1970
2060
  ? this._voltConfig.relay.address
1971
2061
  : service.service_description.host_address;
@@ -2013,9 +2103,8 @@ function getServiceClient(service) {
2013
2103
  }
2014
2104
 
2015
2105
  function unaryCallInternal(method, request, service) {
2016
- const grpcClient = getServiceClient.call(this, service);
2017
-
2018
2106
  return new Promise((resolve, reject) => {
2107
+ const grpcClient = getServiceClient.call(this, service);
2019
2108
  const call = new GRPCCall(this, method, "METHOD_TYPE_UNARY", service);
2020
2109
 
2021
2110
  let response = null;
@@ -2264,14 +2353,14 @@ class VoltClient extends EventEmitter__default["default"] {
2264
2353
  if (this._credential._cryptoCache.cert) {
2265
2354
  isBound = true;
2266
2355
  } else {
2267
- // No certificate present in the cache yet => we need to bind.
2356
+ // No certificate present in the cache yet => we need to authenticate.
2268
2357
  try {
2269
- isBound = await bindInternal.call(this);
2358
+ isBound = await authenticateInternal.call(this);
2270
2359
  } catch (bindErr) {
2271
2360
  if (bindErr.message === "invalid arguments") {
2272
2361
  // This is usually the result of a missing challenge signature or credential.
2273
2362
  log(
2274
- "failure binding to Volt - did you supply a challenge code or verified credential?"
2363
+ "failure authenticating on Volt - did you supply a challenge code or verified credential?"
2275
2364
  );
2276
2365
  throw bindErr;
2277
2366
  }
@@ -2280,7 +2369,7 @@ class VoltClient extends EventEmitter__default["default"] {
2280
2369
 
2281
2370
  if (!isBound) {
2282
2371
  // This is usually because of request being denied.
2283
- throw new Error("Volt binding failed");
2372
+ throw new Error("Volt authentication failed");
2284
2373
  }
2285
2374
 
2286
2375
  return Promise.resolve();
@@ -2506,6 +2595,10 @@ class VoltClient extends EventEmitter__default["default"] {
2506
2595
  * VoltAPI - volt management
2507
2596
  */
2508
2597
 
2598
+ Authenticate(request) {
2599
+ return unaryCallInternal.call(this, "Authenticate", request);
2600
+ }
2601
+
2509
2602
  Bind(request) {
2510
2603
  return unaryCallInternal.call(this, "Bind", request);
2511
2604
  }