@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.
@@ -5,11 +5,17 @@ import bent from "bent";
5
5
  import forge from "node-forge";
6
6
  import lodash from "lodash";
7
7
  import VoltConnection from "./volt-connection.js";
8
- import { getServiceDescriptors } from "./proto-utils.js";
8
+ import { join } from "path";
9
+ import {
10
+ createServiceProtobufFiles,
11
+ getServiceDescriptors,
12
+ getServiceDescriptorsFromPath,
13
+ } from "./proto-utils.js";
9
14
  import { createClient as createGrpcClient } from "./grpc-utils.js";
10
15
  import * as voltUtils from "./utils.js";
11
16
  import { constants } from "./constants.js";
12
17
  import GRPCCall from "./grpc-call.js";
18
+ import RpcInvocation from "./rpc-invocation.js";
13
19
 
14
20
  const { pki } = forge;
15
21
  const { filter, pick } = lodash;
@@ -27,46 +33,48 @@ const voltServices = [
27
33
 
28
34
  function issueBind(bindRequest, ttl) {
29
35
  // eslint-disable-next-line no-use-before-define
30
- return unaryCall.call(this, "Bind", bindRequest).then((bindResponse) => {
31
- log("got binding request response %j", bindResponse);
32
- if (bindResponse.status?.code) {
33
- log("error in bind response: %s", bindResponse.status.message);
34
- return Promise.reject(new Error(bindResponse.status.message));
35
- } else {
36
- switch (bindResponse.decision) {
37
- case "POLICY_DECISION_PERMIT": {
38
- //
39
- // The request status is permit => cache the bind response info.
40
- //
41
-
42
- // This is the certificate assigned to us by the volt.
43
- this._credential.cache.cert = bindResponse.cert;
44
-
45
- // This is the signing CA used by the volt.
46
- this._credential.cache.ca = bindResponse.chain;
47
-
48
- // Identity resource id is assigned by the volt.
49
- this._credential.cache.client_id = bindResponse.identity_id;
50
- this._credential.saveCache();
51
- break;
52
- }
53
- case "POLICY_DECISION_DENY": {
54
- log(">>>>>>>>>>>>>>> access request is DENIED <<<<<<<<<<<<<<<<<<<");
55
- break;
56
- }
57
- case "POLICY_DECISION_PROMPT":
58
- case "POLICY_DECISION_PENDING": {
59
- log("access pending approval - waiting...");
60
- break;
36
+ return unaryCallInternal
37
+ .call(this, "Bind", bindRequest)
38
+ .then((bindResponse) => {
39
+ log("got binding request response %j", bindResponse);
40
+ if (bindResponse.status?.code) {
41
+ log("error in bind response: %s", bindResponse.status.message);
42
+ return Promise.reject(new Error(bindResponse.status.message));
43
+ } else {
44
+ switch (bindResponse.decision) {
45
+ case "POLICY_DECISION_PERMIT": {
46
+ //
47
+ // The request status is permit => cache the bind response info.
48
+ //
49
+
50
+ // This is the certificate assigned to us by the volt.
51
+ this._credential.cache.cert = bindResponse.cert;
52
+
53
+ // This is the signing CA used by the volt.
54
+ this._credential.cache.ca = bindResponse.chain;
55
+
56
+ // Identity resource id is assigned by the volt.
57
+ this._credential.cache.client_id = bindResponse.identity_id;
58
+ this._credential.saveCache();
59
+ break;
60
+ }
61
+ case "POLICY_DECISION_DENY": {
62
+ log(">>>>>>>>>>>>>>> access request is DENIED <<<<<<<<<<<<<<<<<<<");
63
+ break;
64
+ }
65
+ case "POLICY_DECISION_PROMPT":
66
+ case "POLICY_DECISION_PENDING": {
67
+ log("access pending approval - waiting...");
68
+ break;
69
+ }
70
+ default:
71
+ log("ignoring unknown bind descision %s", bindResponse.status);
72
+ break;
61
73
  }
62
- default:
63
- log("ignoring unknown bind descision %s", bindResponse.status);
64
- break;
65
74
  }
66
- }
67
75
 
68
- return bindResponse.decision;
69
- });
76
+ return bindResponse.decision;
77
+ });
70
78
  }
71
79
 
72
80
  function findDIDDocumentService(document, serviceType) {
@@ -233,6 +241,30 @@ export function connectInternal(helloPayload) {
233
241
  this.emit("evt", evt);
234
242
  });
235
243
 
244
+ this._voltConnection.on("invoke_request", (invoke_request) => {
245
+ const invokeId = invoke_request.invoke_id;
246
+ if (this._activeRPC[invokeId]) {
247
+ this._activeRPC[invokeId].parsePayload(invoke_request);
248
+ } else {
249
+ const rpcInvocation = new RpcInvocation(this, this._voltConnection);
250
+
251
+ rpcInvocation.on("end", () => {
252
+ log("removing active RPC [%s]", invokeId);
253
+ this._activeRPC[invokeId] = undefined;
254
+ });
255
+
256
+ rpcInvocation
257
+ .initialise(invoke_request)
258
+ .then(() => {
259
+ this._activeRPC[invokeId] = rpcInvocation;
260
+ this.emit("invoke_request", rpcInvocation);
261
+ })
262
+ .catch((err) => {
263
+ log("invoke_request - error [%s]", err.message);
264
+ });
265
+ }
266
+ });
267
+
236
268
  return this._voltConnection.connect(helloPayload);
237
269
  } catch (err) {
238
270
  log("connect - error [%s]", err.message);
@@ -266,11 +298,62 @@ export function getVoltAPIClientInternal() {
266
298
  return this._cachedClient;
267
299
  }
268
300
 
269
- export function unaryCall(method, request) {
270
- return new Promise((resolve, reject) => {
271
- const grpcClient = this.getVoltAPIClient();
301
+ export function getAPIClientInternal(service) {
302
+ if (!this._cachedService[service.id]) {
303
+ const isRelayedService =
304
+ service.service_description.host_type === "SERVICE_HOST_TYPE_RELAYED";
305
+
306
+ const serviceAddress = this.isRemote
307
+ ? this._voltConfig.relay.address
308
+ : service.service_description.host_address;
309
+
310
+ createServiceProtobufFiles(service, "./service-proto");
311
+
312
+ log("creating API service client on %s", serviceAddress);
313
+ let serviceDescriptors = {};
314
+ const fullProtoPath = join(process.cwd(), "./service-proto");
315
+ for (let api of service.service_description.service_api) {
316
+ const packageDescriptors = getServiceDescriptorsFromPath(
317
+ this._grpc,
318
+ fullProtoPath,
319
+ api,
320
+ );
321
+ serviceDescriptors = { ...serviceDescriptors, ...packageDescriptors };
322
+ }
323
+
324
+ this._cachedService[service.id] = createGrpcClient(
325
+ this._grpc,
326
+ serviceDescriptors,
327
+ serviceAddress,
328
+ this._credential,
329
+ this.isRemote && !this.isVoltRelay,
330
+ this._voltConfig?.relay?.cloud ? this._voltConfig.id : "",
331
+ this._voltConfig?.relay?.cloud ? this._voltConfig.id : "",
332
+ );
333
+ }
334
+
335
+ return this._cachedService[service.id];
336
+ }
272
337
 
273
- const call = new GRPCCall(this, method, "METHOD_TYPE_UNARY");
338
+ export function getServiceClient(service) {
339
+ let grpcClient;
340
+ if (
341
+ service &&
342
+ service?.service_description.host_type !== "SERVICE_HOST_TYPE_BUILTIN"
343
+ ) {
344
+ grpcClient = getAPIClientInternal.call(this, service);
345
+ } else {
346
+ grpcClient = getVoltAPIClientInternal.call(this);
347
+ }
348
+
349
+ return grpcClient;
350
+ }
351
+
352
+ export function unaryCallInternal(method, request, service) {
353
+ const grpcClient = getServiceClient.call(this, service);
354
+
355
+ return new Promise((resolve, reject) => {
356
+ const call = new GRPCCall(this, method, "METHOD_TYPE_UNARY", service);
274
357
 
275
358
  let response = null;
276
359
 
@@ -298,6 +381,16 @@ export function unaryCall(method, request) {
298
381
  });
299
382
  }
300
383
 
384
+ export function streamingCallInternal(methodType, method, request, service) {
385
+ const grpcClient = getServiceClient.call(this, service);
386
+
387
+ const call = new GRPCCall(this, method, methodType, service);
388
+
389
+ call.start(grpcClient, request);
390
+
391
+ return call;
392
+ }
393
+
301
394
  export async function fetchVoltConfig(discovery_url) {
302
395
  try {
303
396
  const getJSON = bent("json");
@@ -10,7 +10,8 @@ import {
10
10
  fetchVoltConfig,
11
11
  fetchVoltConfigFromDID,
12
12
  getVoltAPIClientInternal,
13
- unaryCall,
13
+ unaryCallInternal,
14
+ streamingCallInternal,
14
15
  } from "./volt-client-internal.js";
15
16
  import fs from "fs";
16
17
  import GRPCCall from "./grpc-call.js";
@@ -35,6 +36,8 @@ export class VoltClient extends EventEmitter {
35
36
  this._config = null;
36
37
  this._voltConfig = null;
37
38
  this._voltConnection = null;
39
+ this._cachedService = {};
40
+ this._activeRPC = {};
38
41
  }
39
42
 
40
43
  get config() {
@@ -280,6 +283,40 @@ export class VoltClient extends EventEmitter {
280
283
  return getVoltAPIClientInternal.call(this);
281
284
  }
282
285
 
286
+ unaryCall(method, request, service) {
287
+ return unaryCallInternal.call(this, method, request, service);
288
+ }
289
+
290
+ bidiStreamingCall(method, request, service) {
291
+ return streamingCallInternal.call(
292
+ this,
293
+ "METHOD_TYPE_BIDI",
294
+ method,
295
+ request,
296
+ service,
297
+ );
298
+ }
299
+
300
+ clientStreamingCall(method, request, service) {
301
+ return streamingCallInternal.call(
302
+ this,
303
+ "METHOD_TYPE_CLIENT_STREAM",
304
+ method,
305
+ request,
306
+ service,
307
+ );
308
+ }
309
+
310
+ serverStreamingCall(method, request, service) {
311
+ return streamingCallInternal.call(
312
+ this,
313
+ "METHOD_TYPE_SERVER_STREAM",
314
+ method,
315
+ request,
316
+ service,
317
+ );
318
+ }
319
+
283
320
  /**
284
321
  * Request resource access.
285
322
  * @param {*} targetResourceId
@@ -324,47 +361,47 @@ export class VoltClient extends EventEmitter {
324
361
  */
325
362
 
326
363
  CanAccessResource(request) {
327
- return unaryCall.call(this, "CanAccessResource", request);
364
+ return unaryCallInternal.call(this, "CanAccessResource", request);
328
365
  }
329
366
 
330
367
  DeleteResource(request) {
331
- return unaryCall.call(this, "DeleteResource", request);
368
+ return unaryCallInternal.call(this, "DeleteResource", request);
332
369
  }
333
370
 
334
371
  DiscoverServices(request) {
335
- return unaryCall.call(this, "DiscoverServices", request);
372
+ return unaryCallInternal.call(this, "DiscoverServices", request);
336
373
  }
337
374
 
338
375
  GetResource(request) {
339
- return unaryCall.call(this, "GetResource", request);
376
+ return unaryCallInternal.call(this, "GetResource", request);
340
377
  }
341
378
 
342
379
  GetResources(request) {
343
- return unaryCall.call(this, "GetResources", request);
380
+ return unaryCallInternal.call(this, "GetResources", request);
344
381
  }
345
382
 
346
383
  GetResourceAncestors(request) {
347
- return unaryCall.call(this, "GetResourceAncestors", request);
384
+ return unaryCallInternal.call(this, "GetResourceAncestors", request);
348
385
  }
349
386
 
350
387
  GetResourceDescendants(request) {
351
- return unaryCall.call(this, "GetResourceDescendants", request);
388
+ return unaryCallInternal.call(this, "GetResourceDescendants", request);
352
389
  }
353
390
 
354
391
  RequestAccess(request) {
355
- return unaryCall.call(this, "RequestAccess", request);
392
+ return unaryCallInternal.call(this, "RequestAccess", request);
356
393
  }
357
394
 
358
395
  SaveResource(request) {
359
- return unaryCall.call(this, "SaveResource", request);
396
+ return unaryCallInternal.call(this, "SaveResource", request);
360
397
  }
361
398
 
362
399
  SaveResourceAttribute(request) {
363
- return unaryCall.call(this, "SaveResourceAttribute", request);
400
+ return unaryCallInternal.call(this, "SaveResourceAttribute", request);
364
401
  }
365
402
 
366
403
  SetServiceStatus(request) {
367
- return unaryCall.call(this, "SetServiceStatus", request);
404
+ return unaryCallInternal.call(this, "SetServiceStatus", request);
368
405
  }
369
406
 
370
407
  /**
@@ -372,82 +409,82 @@ export class VoltClient extends EventEmitter {
372
409
  */
373
410
 
374
411
  Bind(request) {
375
- return unaryCall.call(this, "Bind", request);
412
+ return unaryCallInternal.call(this, "Bind", request);
376
413
  }
377
414
 
378
415
  DeleteAccess(request) {
379
- return unaryCall.call(this, "DeleteAccess", request);
416
+ return unaryCallInternal.call(this, "DeleteAccess", request);
380
417
  }
381
418
 
382
419
  DeleteVolt(request) {
383
- return unaryCall.call(this, "DeleteVolt", request);
420
+ return unaryCallInternal.call(this, "DeleteVolt", request);
384
421
  }
385
422
 
386
423
  GetAccess(request) {
387
- return unaryCall.call(this, "GetAccess", request);
424
+ return unaryCallInternal.call(this, "GetAccess", request);
388
425
  }
389
426
 
390
427
  GetBindings(request) {
391
- return unaryCall.call(this, "GetBindings", request);
428
+ return unaryCallInternal.call(this, "GetBindings", request);
392
429
  }
393
430
 
394
431
  GetIdentities(request) {
395
- return unaryCall.call(this, "GetIdentities", request);
432
+ return unaryCallInternal.call(this, "GetIdentities", request);
396
433
  }
397
434
 
398
435
  GetIdentity(request) {
399
- return unaryCall.call(this, "GetIdentity", request);
436
+ return unaryCallInternal.call(this, "GetIdentity", request);
400
437
  }
401
438
 
402
439
  GetIdentityToken(request) {
403
- return unaryCall.call(this, "GetIdentityToken", request);
440
+ return unaryCallInternal.call(this, "GetIdentityToken", request);
404
441
  }
405
442
 
406
443
  GetPolicy(request) {
407
- return unaryCall.call(this, "GetPolicy", request);
444
+ return unaryCallInternal.call(this, "GetPolicy", request);
408
445
  }
409
446
 
410
447
  GetSettings(request) {
411
- return unaryCall.call(this, "GetSettings", request);
448
+ return unaryCallInternal.call(this, "GetSettings", request);
412
449
  }
413
450
 
414
451
  SaveAccess(request) {
415
- return unaryCall.call(this, "SaveAccess", request);
452
+ return unaryCallInternal.call(this, "SaveAccess", request);
416
453
  }
417
454
 
418
455
  SaveCloudConnection(request) {
419
- return unaryCall.call(this, "SaveCloudConnection", request);
456
+ return unaryCallInternal.call(this, "SaveCloudConnection", request);
420
457
  }
421
458
 
422
459
  SaveIdentity(request) {
423
- return unaryCall.call(this, "SaveIdentity", request);
460
+ return unaryCallInternal.call(this, "SaveIdentity", request);
424
461
  }
425
462
 
426
463
  SaveSettings(request) {
427
- return unaryCall.call(this, "SaveSettings", request);
464
+ return unaryCallInternal.call(this, "SaveSettings", request);
428
465
  }
429
466
 
430
467
  SetAccessRequestDecision(request) {
431
- return unaryCall.call(this, "SetAccessRequestDecision", request);
468
+ return unaryCallInternal.call(this, "SetAccessRequestDecision", request);
432
469
  }
433
470
 
434
471
  SetBindingDecision(request) {
435
- return unaryCall.call(this, "SetBindingDecision", request);
472
+ return unaryCallInternal.call(this, "SetBindingDecision", request);
436
473
  }
437
474
 
438
475
  Shutdown(request) {
439
- return unaryCall.call(this, "Shutdown", request);
476
+ return unaryCallInternal.call(this, "Shutdown", request);
440
477
  }
441
478
 
442
479
  SignVerify(request) {
443
- return unaryCall.call(this, "SignVerify", request);
480
+ return unaryCallInternal.call(this, "SignVerify", request);
444
481
  }
445
482
 
446
483
  /**
447
484
  * FileAPI
448
485
  */
449
486
  GetFileDescendants(request) {
450
- return unaryCall.call(this, "GetFileDescendants", request);
487
+ return unaryCallInternal.call(this, "GetFileDescendants", request);
451
488
  }
452
489
 
453
490
  /**
@@ -527,6 +564,10 @@ export class VoltClient extends EventEmitter {
527
564
  /**
528
565
  * SqliteDatabaseAPI
529
566
  */
567
+ BulkUpdate(request) {
568
+ return unaryCallInternal.call(this, "BulkUpdate", request);
569
+ }
570
+
530
571
  SqlExecute(request) {
531
572
  const grpcClient = this.getVoltAPIClient();
532
573
 
@@ -84,6 +84,11 @@ function _doConnect(connectHello) {
84
84
  }
85
85
  break;
86
86
  }
87
+ case "invoke_request": {
88
+ log("received invoke request");
89
+ this.emit("invoke_request", response.invoke_request);
90
+ break;
91
+ }
87
92
  case "evt": {
88
93
  log("received event %s", response.evt.event_type);
89
94
  this.emit("evt", response.evt);
@@ -166,4 +171,8 @@ export default class VoltConnection extends EventEmitter {
166
171
  this._dying = true;
167
172
  _cleanUp.call(this);
168
173
  }
174
+
175
+ send(request) {
176
+ this.call.write(request);
177
+ }
169
178
  }
@@ -73,6 +73,10 @@ export class VoltCredential {
73
73
  return this._cryptoCache.client_id;
74
74
  }
75
75
 
76
+ get voltPublicKey() {
77
+ return this._voltPublicKey;
78
+ }
79
+
76
80
  get publicKey() {
77
81
  return pki.publicKeyToPem(this.getKey().publicKey);
78
82
  }
@@ -140,7 +144,7 @@ export class VoltCredential {
140
144
  * @param {*} tunnelling flag indicating if the token is required for a tunnelled connection
141
145
  * @param {*} ttl time to live in seconds (default to 1 minute)
142
146
  */
143
- getIdentityToken(audience, tunnelling = false, ttl = 60) {
147
+ getIdentityToken(audience, publicKey, tunnelling = false, ttl = 60) {
144
148
  if (!this._cryptoCache.key) {
145
149
  throw new Error("crypto cache invalid");
146
150
  }
@@ -166,11 +170,8 @@ export class VoltCredential {
166
170
  sharedKey = VoltCredential.aesCreateKey();
167
171
 
168
172
  // Encrypt the key details using the target Volt public key and include this in the JWT payload.
169
- payload.sk = VoltCredential.rsaEncrypt(
170
- this._voltPublicKey,
171
- sharedKey.key,
172
- );
173
- payload.iv = VoltCredential.rsaEncrypt(this._voltPublicKey, sharedKey.iv);
173
+ payload.sk = VoltCredential.rsaEncrypt(publicKey, sharedKey.key);
174
+ payload.iv = VoltCredential.rsaEncrypt(publicKey, sharedKey.iv);
174
175
  }
175
176
 
176
177
  // Sign synchronously.
@@ -195,9 +196,10 @@ export class VoltCredential {
195
196
  * @param {*} ttl
196
197
  * @returns
197
198
  */
198
- getIdentityMetadata(grpc, audience, tunnelling = false, ttl = 60) {
199
+ getIdentityMetadata(grpc, audience, publicKey, tunnelling = false, ttl = 60) {
199
200
  const identityToken = this.getIdentityToken(
200
201
  audience || this._voltConfig.id,
202
+ publicKey,
201
203
  tunnelling,
202
204
  ttl,
203
205
  );
@@ -243,4 +245,10 @@ export class VoltCredential {
243
245
  static rsaEncrypt(key, buffer) {
244
246
  return crypto.publicEncrypt(key, buffer).toString("base64");
245
247
  }
248
+
249
+ static rsaDecrypt(key, buffer) {
250
+ const keyObj = crypto.createPrivateKey(key);
251
+ const cipher = Buffer.from(buffer, "base64");
252
+ return Buffer.from(crypto.privateDecrypt(keyObj, cipher));
253
+ }
246
254
  }