@tdxvolt/volt-client-grpc 0.20.7 → 0.20.8

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
@@ -1426,10 +1426,13 @@ message DIDRegistryUpdate {
1426
1426
  }
1427
1427
 
1428
1428
  message VerifiablePresentation {
1429
- // The credential JSON.
1429
+ // DEPRECATED - use 'credential'
1430
1430
  string credential_json = 1;
1431
1431
 
1432
- // A signature of the credential JSON. The signature should usually be that of the credential subject.
1432
+ // Array of credential JSON.
1433
+ repeated string credential = 3;
1434
+
1435
+ // A signature of the credential JSON. The signature should be that of the credential holder over the concatenation of the contents of the \`credential\` array.
1433
1436
  string signature = 2;
1434
1437
  }
1435
1438
 
@@ -1593,7 +1596,7 @@ message ParseCredentialResponse {
1593
1596
  tdx.volt_api.volt.v1.Status status = 1;
1594
1597
 
1595
1598
  // The parsed credential details.
1596
- VerifiableCredential verifiable_credential = 2;
1599
+ repeated VerifiableCredential verifiable_credential = 2;
1597
1600
  }
1598
1601
 
1599
1602
  message ResolveDIDRequest {
@@ -2507,6 +2510,9 @@ message SessionCredential {
2507
2510
 
2508
2511
  // More type-specific data stored with the credential.
2509
2512
  string extra_2 = 16;
2513
+
2514
+ // The verification status of the credential.
2515
+ string status = 17;
2510
2516
  }
2511
2517
 
2512
2518
  message Session {
@@ -2530,7 +2536,6 @@ message Session {
2530
2536
 
2531
2537
  SessionStatus status = 10;
2532
2538
  }
2533
-
2534
2539
  `;
2535
2540
  const volt_api = `syntax = "proto3";
2536
2541
 
@@ -2541,7 +2546,7 @@ import "tdx/volt_api/volt/v1/remote.proto";
2541
2546
  import "tdx/volt_api/volt/v1/ssi.proto";
2542
2547
  import "tdx/volt_api/volt/v1/volt.proto";
2543
2548
 
2544
- // The top-level volt management service.
2549
+ // The top-level volt management service.
2545
2550
  // With the exception of \`Authenticate\`, all RPCs on this service must submit either a valid client certificate signed by the volt CA, or a signed JWT.
2546
2551
  // A client certificate can be obtained from the \`Authenticate\` method.
2547
2552
  // All methods include a \`tdx.volt_api.volt.v1.Status\` in the response. If the status contains a non-OK error code the client should assume the remainder of the message is invalid, unless otherwise indicated in the response documentation.
@@ -2901,9 +2906,19 @@ message ConnectResource {
2901
2906
  Resource resource = 2;
2902
2907
  }
2903
2908
 
2909
+ enum ConnectAuthRequestType {
2910
+ CONNECT_AUTH_REQUEST_TYPE_UNKNOWN = 0;
2911
+ CONNECT_AUTH_REQUEST_TYPE_NEW_SESSION = 1;
2912
+ CONNECT_AUTH_REQUEST_TYPE_UPDATE_SESSION = 2;
2913
+ CONNECT_AUTH_REQUEST_TYPE_DELETE_SESSION = 3;
2914
+ CONNECT_AUTH_REQUEST_TYPE_SIGN_REQUEST = 4;
2915
+ }
2916
+
2904
2917
  message ConnectAuthRequest {
2905
2918
  Session session = 1;
2906
2919
 
2920
+ ConnectAuthRequestType request_type = 2;
2921
+
2907
2922
  string context = 5;
2908
2923
 
2909
2924
  string challenge = 6;
@@ -3313,6 +3328,8 @@ message GetSessionsRequest {
3313
3328
  string identity_name = 3;
3314
3329
 
3315
3330
  SessionStatus status = 4;
3331
+
3332
+ string identity_email_id = 5;
3316
3333
  }
3317
3334
 
3318
3335
  message GetSessionsResponse {
@@ -4842,13 +4859,18 @@ function issueAuthenticate(authenticateRequest, ttl) {
4842
4859
  return Promise.reject(new Error(authenticateResponse.status.message));
4843
4860
  } else {
4844
4861
  switch (authenticateResponse.decision) {
4845
- case "POLICY_DECISION_PERMIT": {
4862
+ case "POLICY_DECISION_PERMIT":
4863
+ case "POLICY_DECISION_PROMPT":
4864
+ case "POLICY_DECISION_PENDING": {
4846
4865
  //
4847
- // The request status is permit => cache the bind response info.
4866
+ // The request status is not deny => cache the bind response info.
4848
4867
  //
4868
+ log$2("decision is %s", authenticateResponse.decision);
4849
4869
 
4850
4870
  // This is the certificate assigned to us by the volt.
4851
- this._credential.cache.cert = authenticateResponse.cert;
4871
+ if (authenticateResponse.cert) {
4872
+ this._credential.cache.cert = authenticateResponse.cert;
4873
+ }
4852
4874
 
4853
4875
  // This is the signing CA used by the volt.
4854
4876
  this._credential.cache.ca = authenticateResponse.chain;
@@ -4862,12 +4884,20 @@ function issueAuthenticate(authenticateRequest, ttl) {
4862
4884
  authenticateResponse.identity_did;
4863
4885
  }
4864
4886
 
4887
+ // Maintain a unique list of verifiable credentials.
4888
+ const uniqueVCs = new Map();
4865
4889
  this._credential.cache.vc = this._credential.cache.vc || [];
4890
+ for (const existingVC of this._credential.cache.vc) {
4891
+ uniqueVCs.set(existingVC.id, existingVC);
4892
+ }
4893
+
4866
4894
  for (const credential of authenticateResponse.credential) {
4867
4895
  const vc = JSON.parse(credential);
4868
- this._credential.cache.vc.push(vc);
4896
+ uniqueVCs.set(vc.id, vc);
4869
4897
  }
4870
4898
 
4899
+ this._credential.cache.vc = Array.from(uniqueVCs.values());
4900
+
4871
4901
  this._credential.saveCache();
4872
4902
  break;
4873
4903
  }
@@ -4875,25 +4905,6 @@ function issueAuthenticate(authenticateRequest, ttl) {
4875
4905
  log$2(">>>>>>>>>>>>>>> access request is DENIED <<<<<<<<<<<<<<<<<<<");
4876
4906
  break;
4877
4907
  }
4878
- case "POLICY_DECISION_PROMPT":
4879
- case "POLICY_DECISION_PENDING": {
4880
- log$2("access pending approval - waiting...");
4881
-
4882
- // This is the signing CA used by the volt.
4883
- this._credential.cache.ca = authenticateResponse.chain;
4884
-
4885
- // The session id is assigned by the volt.
4886
- this._credential.cache.session_id = authenticateResponse.session_id;
4887
-
4888
- if (!this._credential.cache.identity_did) {
4889
- // Identity DID has been assigned by the volt.
4890
- this._credential.cache.identity_did =
4891
- authenticateResponse.identity_did;
4892
- }
4893
-
4894
- this._credential.saveCache();
4895
- break;
4896
- }
4897
4908
  default:
4898
4909
  log$2(
4899
4910
  "ignoring unknown bind descision %s",
@@ -4916,7 +4927,12 @@ function findDIDDocumentService(document, serviceType) {
4916
4927
  return matches;
4917
4928
  }
4918
4929
 
4919
- async function authenticateInternal(noDID = false, ownDID = false, exchangeToken = "") {
4930
+ async function authenticateInternal(
4931
+ noDID = false,
4932
+ ownDID = false,
4933
+ exchangeToken = "",
4934
+ waitForPermit = true
4935
+ ) {
4920
4936
  try {
4921
4937
  if (!this._credential.cache.ca) {
4922
4938
  this._credential.cache.ca = this._voltConfig.ca_pem;
@@ -4947,6 +4963,27 @@ async function authenticateInternal(noDID = false, ownDID = false, exchangeToken
4947
4963
  host: this._credential.cache.bindIp
4948
4964
  };
4949
4965
 
4966
+ if (this._credential.cache.vc?.length > 0) {
4967
+ const presentation = {
4968
+ credential: []
4969
+ };
4970
+
4971
+ let presentationData = "";
4972
+ for (let credential of this._credential.cache.vc) {
4973
+ const vc = JSON.stringify(credential, null, 2);
4974
+ log$2(vc);
4975
+ presentation.credential.push(vc);
4976
+ presentationData += vc;
4977
+ }
4978
+
4979
+ presentation.signature = signBase64(
4980
+ this._credential.cache.key,
4981
+ presentationData
4982
+ );
4983
+
4984
+ authenticateRequest.verifiable_presentation = [presentation];
4985
+ }
4986
+
4950
4987
  if (exchangeToken) {
4951
4988
  log$2("setting request exchange token");
4952
4989
  authenticateRequest.exchange_token = exchangeToken;
@@ -4958,9 +4995,7 @@ async function authenticateInternal(noDID = false, ownDID = false, exchangeToken
4958
4995
  log$2("setting request challenge code");
4959
4996
  authenticateRequest.challenge = this._credential.cache.challenge_code;
4960
4997
  } else {
4961
- log$2(
4962
- "no challenge code in request"
4963
- );
4998
+ log$2("no challenge code in request");
4964
4999
  }
4965
5000
 
4966
5001
  if (noDID) {
@@ -5038,8 +5073,8 @@ async function authenticateInternal(noDID = false, ownDID = false, exchangeToken
5038
5073
  );
5039
5074
  log$2("authenticate decision: %s", decision);
5040
5075
  } while (
5041
- decision === "POLICY_DECISION_PROMPT" ||
5042
- decision === "POLICY_DECISION_PENDING"
5076
+ decision === "POLICY_DECISION_PENDING" ||
5077
+ (waitForPermit && decision === "POLICY_DECISION_PROMPT")
5043
5078
  );
5044
5079
 
5045
5080
  return decision === "POLICY_DECISION_PERMIT";
@@ -5710,9 +5745,14 @@ class VoltClient extends EventEmitter__default["default"] {
5710
5745
  * @param {boolean} [options.noDID] - whether to create a key-based authentication session
5711
5746
  * instead of a DID-based authentication session.
5712
5747
  * @param {string} [options.exchangeToken] - optional token to exchange in return for an authenticated session.
5748
+ * @param {boolean} [options.waitForAuth] - whether to block and poll on 'prompt' authenticate decisions. Default is true.
5713
5749
  */
5714
5750
  async initialise(config, options = {}) {
5715
- const { ownDID, noDID, didRegistryList, exchangeToken, extraConfig } = options;
5751
+ const { ownDID, noDID, didRegistryList, exchangeToken, extraConfig } =
5752
+ options;
5753
+ const waitForAuth =
5754
+ options.waitForAuth === undefined ? true : !!options.waitForAuth;
5755
+
5716
5756
  try {
5717
5757
  if (!config) {
5718
5758
  throw new Error(
@@ -5798,7 +5838,13 @@ class VoltClient extends EventEmitter__default["default"] {
5798
5838
  } else {
5799
5839
  // No certificate present in the cache yet => we need to authenticate.
5800
5840
  try {
5801
- isBound = await authenticateInternal.call(this, noDID, ownDID, exchangeToken);
5841
+ isBound = await authenticateInternal.call(
5842
+ this,
5843
+ noDID,
5844
+ ownDID,
5845
+ exchangeToken,
5846
+ waitForAuth
5847
+ );
5802
5848
  } catch (bindErr) {
5803
5849
  if (bindErr.message === "invalid arguments") {
5804
5850
  // This is usually the result of a missing challenge signature or credential.
@@ -6235,6 +6281,21 @@ class VoltClient extends EventEmitter__default["default"] {
6235
6281
  return call.start(grpcClient, request);
6236
6282
  }
6237
6283
 
6284
+ /**
6285
+ * TerminalAPI
6286
+ */
6287
+ CommandStream(request, service) {
6288
+ const grpcClient = this.getVoltAPIClient();
6289
+
6290
+ const commandStreamCall = new GRPCCall(
6291
+ this,
6292
+ "CommandStream",
6293
+ "METHOD_TYPE_BIDI",
6294
+ service
6295
+ );
6296
+ return commandStreamCall.start(grpcClient, request);
6297
+ }
6298
+
6238
6299
  /**
6239
6300
  * WireAPI
6240
6301
  */
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "0.20.7",
6
+ "version": "0.20.8",
7
7
  "description": "tdx Volt library for nodejs clients",
8
8
  "type": "module",
9
9
  "exports": {
@@ -33,7 +33,7 @@
33
33
  "author": "toby.ealden@gmail.com",
34
34
  "license": "ISC",
35
35
  "dependencies": {
36
- "@tdxvolt/volt-client-web": "^0.20.7",
36
+ "@tdxvolt/volt-client-web": "^0.20.8",
37
37
  "debug": "^4.1.1",
38
38
  "ip": "^1.1.5",
39
39
  "jsonwebtoken": "^8.5.1",
@@ -42,4 +42,4 @@
42
42
  "protobufjs": "^7.4.0",
43
43
  "uuid": "^8.1.0"
44
44
  }
45
- }
45
+ }
@@ -32,13 +32,18 @@ function issueAuthenticate(authenticateRequest, ttl) {
32
32
  return Promise.reject(new Error(authenticateResponse.status.message));
33
33
  } else {
34
34
  switch (authenticateResponse.decision) {
35
- case "POLICY_DECISION_PERMIT": {
35
+ case "POLICY_DECISION_PERMIT":
36
+ case "POLICY_DECISION_PROMPT":
37
+ case "POLICY_DECISION_PENDING": {
36
38
  //
37
- // The request status is permit => cache the bind response info.
39
+ // The request status is not deny => cache the bind response info.
38
40
  //
41
+ log("decision is %s", authenticateResponse.decision);
39
42
 
40
43
  // This is the certificate assigned to us by the volt.
41
- this._credential.cache.cert = authenticateResponse.cert;
44
+ if (authenticateResponse.cert) {
45
+ this._credential.cache.cert = authenticateResponse.cert;
46
+ }
42
47
 
43
48
  // This is the signing CA used by the volt.
44
49
  this._credential.cache.ca = authenticateResponse.chain;
@@ -52,12 +57,20 @@ function issueAuthenticate(authenticateRequest, ttl) {
52
57
  authenticateResponse.identity_did;
53
58
  }
54
59
 
60
+ // Maintain a unique list of verifiable credentials.
61
+ const uniqueVCs = new Map();
55
62
  this._credential.cache.vc = this._credential.cache.vc || [];
63
+ for (const existingVC of this._credential.cache.vc) {
64
+ uniqueVCs.set(existingVC.id, existingVC);
65
+ }
66
+
56
67
  for (const credential of authenticateResponse.credential) {
57
68
  const vc = JSON.parse(credential);
58
- this._credential.cache.vc.push(vc);
69
+ uniqueVCs.set(vc.id, vc);
59
70
  }
60
71
 
72
+ this._credential.cache.vc = Array.from(uniqueVCs.values());
73
+
61
74
  this._credential.saveCache();
62
75
  break;
63
76
  }
@@ -65,25 +78,6 @@ function issueAuthenticate(authenticateRequest, ttl) {
65
78
  log(">>>>>>>>>>>>>>> access request is DENIED <<<<<<<<<<<<<<<<<<<");
66
79
  break;
67
80
  }
68
- case "POLICY_DECISION_PROMPT":
69
- case "POLICY_DECISION_PENDING": {
70
- log("access pending approval - waiting...");
71
-
72
- // This is the signing CA used by the volt.
73
- this._credential.cache.ca = authenticateResponse.chain;
74
-
75
- // The session id is assigned by the volt.
76
- this._credential.cache.session_id = authenticateResponse.session_id;
77
-
78
- if (!this._credential.cache.identity_did) {
79
- // Identity DID has been assigned by the volt.
80
- this._credential.cache.identity_did =
81
- authenticateResponse.identity_did;
82
- }
83
-
84
- this._credential.saveCache();
85
- break;
86
- }
87
81
  default:
88
82
  log(
89
83
  "ignoring unknown bind descision %s",
@@ -106,7 +100,12 @@ function findDIDDocumentService(document, serviceType) {
106
100
  return matches;
107
101
  }
108
102
 
109
- export async function authenticateInternal(noDID = false, ownDID = false, exchangeToken = "") {
103
+ export async function authenticateInternal(
104
+ noDID = false,
105
+ ownDID = false,
106
+ exchangeToken = "",
107
+ waitForPermit = true
108
+ ) {
110
109
  try {
111
110
  if (!this._credential.cache.ca) {
112
111
  this._credential.cache.ca = this._voltConfig.ca_pem;
@@ -137,6 +136,27 @@ export async function authenticateInternal(noDID = false, ownDID = false, exchan
137
136
  host: this._credential.cache.bindIp
138
137
  };
139
138
 
139
+ if (this._credential.cache.vc?.length > 0) {
140
+ const presentation = {
141
+ credential: []
142
+ };
143
+
144
+ let presentationData = "";
145
+ for (let credential of this._credential.cache.vc) {
146
+ const vc = JSON.stringify(credential, null, 2);
147
+ log(vc);
148
+ presentation.credential.push(vc);
149
+ presentationData += vc;
150
+ }
151
+
152
+ presentation.signature = signBase64(
153
+ this._credential.cache.key,
154
+ presentationData
155
+ );
156
+
157
+ authenticateRequest.verifiable_presentation = [presentation];
158
+ }
159
+
140
160
  if (exchangeToken) {
141
161
  log("setting request exchange token");
142
162
  authenticateRequest.exchange_token = exchangeToken;
@@ -148,9 +168,7 @@ export async function authenticateInternal(noDID = false, ownDID = false, exchan
148
168
  log("setting request challenge code");
149
169
  authenticateRequest.challenge = this._credential.cache.challenge_code;
150
170
  } else {
151
- log(
152
- "no challenge code in request"
153
- );
171
+ log("no challenge code in request");
154
172
  }
155
173
 
156
174
  if (noDID) {
@@ -228,8 +246,8 @@ export async function authenticateInternal(noDID = false, ownDID = false, exchan
228
246
  );
229
247
  log("authenticate decision: %s", decision);
230
248
  } while (
231
- decision === "POLICY_DECISION_PROMPT" ||
232
- decision === "POLICY_DECISION_PENDING"
249
+ decision === "POLICY_DECISION_PENDING" ||
250
+ (waitForPermit && decision === "POLICY_DECISION_PROMPT")
233
251
  );
234
252
 
235
253
  return decision === "POLICY_DECISION_PERMIT";
@@ -85,9 +85,14 @@ export class VoltClient extends EventEmitter {
85
85
  * @param {boolean} [options.noDID] - whether to create a key-based authentication session
86
86
  * instead of a DID-based authentication session.
87
87
  * @param {string} [options.exchangeToken] - optional token to exchange in return for an authenticated session.
88
+ * @param {boolean} [options.waitForAuth] - whether to block and poll on 'prompt' authenticate decisions. Default is true.
88
89
  */
89
90
  async initialise(config, options = {}) {
90
- const { ownDID, noDID, didRegistryList, exchangeToken, extraConfig } = options;
91
+ const { ownDID, noDID, didRegistryList, exchangeToken, extraConfig } =
92
+ options;
93
+ const waitForAuth =
94
+ options.waitForAuth === undefined ? true : !!options.waitForAuth;
95
+
91
96
  try {
92
97
  if (!config) {
93
98
  throw new Error(
@@ -173,7 +178,13 @@ export class VoltClient extends EventEmitter {
173
178
  } else {
174
179
  // No certificate present in the cache yet => we need to authenticate.
175
180
  try {
176
- isBound = await authenticateInternal.call(this, noDID, ownDID, exchangeToken);
181
+ isBound = await authenticateInternal.call(
182
+ this,
183
+ noDID,
184
+ ownDID,
185
+ exchangeToken,
186
+ waitForAuth
187
+ );
177
188
  } catch (bindErr) {
178
189
  if (bindErr.message === "invalid arguments") {
179
190
  // This is usually the result of a missing challenge signature or credential.
@@ -612,6 +623,21 @@ export class VoltClient extends EventEmitter {
612
623
  return call.start(grpcClient, request);
613
624
  }
614
625
 
626
+ /**
627
+ * TerminalAPI
628
+ */
629
+ CommandStream(request, service) {
630
+ const grpcClient = this.getVoltAPIClient();
631
+
632
+ const commandStreamCall = new GRPCCall(
633
+ this,
634
+ "CommandStream",
635
+ "METHOD_TYPE_BIDI",
636
+ service
637
+ );
638
+ return commandStreamCall.start(grpcClient, request);
639
+ }
640
+
615
641
  /**
616
642
  * WireAPI
617
643
  */
@@ -881,10 +881,13 @@ message DIDRegistryUpdate {
881
881
  }
882
882
 
883
883
  message VerifiablePresentation {
884
- // The credential JSON.
884
+ // DEPRECATED - use 'credential'
885
885
  string credential_json = 1;
886
886
 
887
- // A signature of the credential JSON. The signature should usually be that of the credential subject.
887
+ // Array of credential JSON.
888
+ repeated string credential = 3;
889
+
890
+ // A signature of the credential JSON. The signature should be that of the credential holder over the concatenation of the contents of the \`credential\` array.
888
891
  string signature = 2;
889
892
  }
890
893
 
@@ -1048,7 +1051,7 @@ message ParseCredentialResponse {
1048
1051
  tdx.volt_api.volt.v1.Status status = 1;
1049
1052
 
1050
1053
  // The parsed credential details.
1051
- VerifiableCredential verifiable_credential = 2;
1054
+ repeated VerifiableCredential verifiable_credential = 2;
1052
1055
  }
1053
1056
 
1054
1057
  message ResolveDIDRequest {
@@ -1962,6 +1965,9 @@ message SessionCredential {
1962
1965
 
1963
1966
  // More type-specific data stored with the credential.
1964
1967
  string extra_2 = 16;
1968
+
1969
+ // The verification status of the credential.
1970
+ string status = 17;
1965
1971
  }
1966
1972
 
1967
1973
  message Session {
@@ -1985,7 +1991,6 @@ message Session {
1985
1991
 
1986
1992
  SessionStatus status = 10;
1987
1993
  }
1988
-
1989
1994
  `;
1990
1995
  export const volt_api = `syntax = "proto3";
1991
1996
 
@@ -1996,7 +2001,7 @@ import "tdx/volt_api/volt/v1/remote.proto";
1996
2001
  import "tdx/volt_api/volt/v1/ssi.proto";
1997
2002
  import "tdx/volt_api/volt/v1/volt.proto";
1998
2003
 
1999
- // The top-level volt management service.
2004
+ // The top-level volt management service.
2000
2005
  // With the exception of \`Authenticate\`, all RPCs on this service must submit either a valid client certificate signed by the volt CA, or a signed JWT.
2001
2006
  // A client certificate can be obtained from the \`Authenticate\` method.
2002
2007
  // All methods include a \`tdx.volt_api.volt.v1.Status\` in the response. If the status contains a non-OK error code the client should assume the remainder of the message is invalid, unless otherwise indicated in the response documentation.
@@ -2356,9 +2361,19 @@ message ConnectResource {
2356
2361
  Resource resource = 2;
2357
2362
  }
2358
2363
 
2364
+ enum ConnectAuthRequestType {
2365
+ CONNECT_AUTH_REQUEST_TYPE_UNKNOWN = 0;
2366
+ CONNECT_AUTH_REQUEST_TYPE_NEW_SESSION = 1;
2367
+ CONNECT_AUTH_REQUEST_TYPE_UPDATE_SESSION = 2;
2368
+ CONNECT_AUTH_REQUEST_TYPE_DELETE_SESSION = 3;
2369
+ CONNECT_AUTH_REQUEST_TYPE_SIGN_REQUEST = 4;
2370
+ }
2371
+
2359
2372
  message ConnectAuthRequest {
2360
2373
  Session session = 1;
2361
2374
 
2375
+ ConnectAuthRequestType request_type = 2;
2376
+
2362
2377
  string context = 5;
2363
2378
 
2364
2379
  string challenge = 6;
@@ -2768,6 +2783,8 @@ message GetSessionsRequest {
2768
2783
  string identity_name = 3;
2769
2784
 
2770
2785
  SessionStatus status = 4;
2786
+
2787
+ string identity_email_id = 5;
2771
2788
  }
2772
2789
 
2773
2790
  message GetSessionsResponse {