@tdxvolt/volt-client-grpc 0.17.0 → 0.18.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/README.md +39 -3
- package/lib/index.cjs +334 -216
- package/package.json +2 -2
- package/protobuf/tdx/volt_api/volt/v1/ssi_api.proto +5 -5
- package/protobuf/tdx/volt_api/volt/v1/volt.proto +6 -1
- package/protobuf/tdx/volt_api/volt/v1/volt_api.proto +3 -0
- package/protobuf/tdx/volt_api/volt/v1/wire_api.proto +4 -0
- package/src/constants.js +2 -54
- package/src/grpc-call.js +109 -56
- package/src/grpc-utils.js +3 -3
- package/src/rpc-invocation.js +51 -13
- package/src/utils.js +1 -1
- package/src/volt-client-internal.js +39 -26
- package/src/volt-client.js +42 -12
- package/src/volt-connection.js +16 -2
- package/src/volt-credential.js +13 -7
|
@@ -16,11 +16,9 @@ import { constants } from "./constants.js";
|
|
|
16
16
|
import GRPCCall from "./grpc-call.js";
|
|
17
17
|
import RpcInvocation from "./rpc-invocation.js";
|
|
18
18
|
import { v4 as generateId } from "uuid";
|
|
19
|
-
import {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
signBase64
|
|
23
|
-
} from "@tdxvolt/volt-client-web";
|
|
19
|
+
import { voltUtils as voltClientUtils } from "@tdxvolt/volt-client-web/js";
|
|
20
|
+
|
|
21
|
+
const { publicKeyToPem, removeCarriageReturn, signBase64 } = voltClientUtils;
|
|
24
22
|
|
|
25
23
|
const { filter, pick } = lodash;
|
|
26
24
|
|
|
@@ -174,7 +172,7 @@ export async function authenticateInternal(
|
|
|
174
172
|
|
|
175
173
|
if (this._voltConfig.challenge_code) {
|
|
176
174
|
authenticateRequest.challenge = signBase64(
|
|
177
|
-
|
|
175
|
+
this._credential.cache.key,
|
|
178
176
|
this._voltConfig.challenge_code
|
|
179
177
|
);
|
|
180
178
|
} else {
|
|
@@ -204,16 +202,18 @@ export async function authenticateInternal(
|
|
|
204
202
|
// This is because the DID document is signed and the signature
|
|
205
203
|
// is over the entire document.
|
|
206
204
|
const didDocument = {
|
|
207
|
-
"@context":
|
|
205
|
+
"@context": [
|
|
206
|
+
"https://www.w3.org/ns/did/v1",
|
|
207
|
+
"https://tdxvolt.com/ns/did/v1"
|
|
208
|
+
],
|
|
208
209
|
authentication: [`${did}#key-1`],
|
|
209
210
|
controller: did,
|
|
210
|
-
description: this._config.client_name,
|
|
211
211
|
id: did,
|
|
212
212
|
verificationMethod: [
|
|
213
213
|
{
|
|
214
214
|
id: `${did}#key-1`,
|
|
215
215
|
publicKeyPem: publicKeyPem,
|
|
216
|
-
type: "
|
|
216
|
+
type: "Ed25519Signature2018"
|
|
217
217
|
}
|
|
218
218
|
]
|
|
219
219
|
};
|
|
@@ -224,7 +224,7 @@ export async function authenticateInternal(
|
|
|
224
224
|
// Now sign the entire DID document, including the proof and set it in the
|
|
225
225
|
// bind request. This is required by the Volt to verify that we have the private key for the DID.
|
|
226
226
|
authenticateRequest.did_document_signature = signBase64(
|
|
227
|
-
|
|
227
|
+
this._credential.cache.key,
|
|
228
228
|
authenticateRequest.did_document
|
|
229
229
|
);
|
|
230
230
|
|
|
@@ -262,7 +262,7 @@ export async function authenticateInternal(
|
|
|
262
262
|
|
|
263
263
|
return decision === "POLICY_DECISION_PERMIT";
|
|
264
264
|
} catch (err) {
|
|
265
|
-
log("failure
|
|
265
|
+
log("failure authenticating with Volt [%s]", err.message);
|
|
266
266
|
throw err;
|
|
267
267
|
}
|
|
268
268
|
}
|
|
@@ -278,15 +278,7 @@ export function connectInternal(helloPayload) {
|
|
|
278
278
|
this._connected = false;
|
|
279
279
|
this._session = null;
|
|
280
280
|
|
|
281
|
-
|
|
282
|
-
this._grpc.closeClient(this._cachedClient);
|
|
283
|
-
this._cachedClient = null;
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
if (this._cachedRemoteClient) {
|
|
287
|
-
this._grpc.closeClient(this._cachedRemoteClient);
|
|
288
|
-
this._cachedRemoteClient = null;
|
|
289
|
-
}
|
|
281
|
+
this.close();
|
|
290
282
|
};
|
|
291
283
|
|
|
292
284
|
this._voltConnection = new VoltConnection(this, this._grpc);
|
|
@@ -375,7 +367,7 @@ export function connectInternal(helloPayload) {
|
|
|
375
367
|
|
|
376
368
|
export function getVoltAPIClientInternal() {
|
|
377
369
|
if (!this._cachedClient) {
|
|
378
|
-
const serviceAddress = this.
|
|
370
|
+
const serviceAddress = this.isRelayed
|
|
379
371
|
? this._voltConfig.relay.address
|
|
380
372
|
: this._voltConfig.address;
|
|
381
373
|
log("creating cached VoltAPI service client on %s", serviceAddress);
|
|
@@ -390,7 +382,7 @@ export function getVoltAPIClientInternal() {
|
|
|
390
382
|
serviceDescriptors,
|
|
391
383
|
serviceAddress,
|
|
392
384
|
this._credential,
|
|
393
|
-
this.
|
|
385
|
+
this.isRelayed,
|
|
394
386
|
this._voltConfig?.relay?.cloud ? this._voltConfig.id : "",
|
|
395
387
|
this._voltConfig?.relay?.cloud ? this._voltConfig.id : ""
|
|
396
388
|
);
|
|
@@ -401,7 +393,7 @@ export function getVoltAPIClientInternal() {
|
|
|
401
393
|
|
|
402
394
|
export function getAPIClientInternal(service) {
|
|
403
395
|
if (!this._cachedService[service.id]) {
|
|
404
|
-
const serviceAddress = this.
|
|
396
|
+
const serviceAddress = this.isRelayed
|
|
405
397
|
? this._voltConfig.relay.address
|
|
406
398
|
: service.service_description.host_address;
|
|
407
399
|
|
|
@@ -424,7 +416,7 @@ export function getAPIClientInternal(service) {
|
|
|
424
416
|
serviceDescriptors,
|
|
425
417
|
serviceAddress,
|
|
426
418
|
this._credential,
|
|
427
|
-
this.
|
|
419
|
+
this.isRelayed,
|
|
428
420
|
this._voltConfig?.relay?.cloud ? this._voltConfig.id : "",
|
|
429
421
|
this._voltConfig?.relay?.cloud ? this._voltConfig.id : ""
|
|
430
422
|
);
|
|
@@ -519,9 +511,9 @@ export async function fetchVoltConfig(discovery_url) {
|
|
|
519
511
|
}
|
|
520
512
|
}
|
|
521
513
|
|
|
522
|
-
|
|
514
|
+
async function fetchVoltConfigFromDIDInternal(volt_did, registryUrl) {
|
|
523
515
|
try {
|
|
524
|
-
const didResolution = voltUtils.getDIDResolutionURL(volt_did);
|
|
516
|
+
const didResolution = voltUtils.getDIDResolutionURL(volt_did, registryUrl);
|
|
525
517
|
if (!didResolution) {
|
|
526
518
|
throw new Error(`Invalid Volt DID: ${volt_did}`);
|
|
527
519
|
}
|
|
@@ -540,6 +532,8 @@ export async function fetchVoltConfigFromDID(volt_did) {
|
|
|
540
532
|
);
|
|
541
533
|
}
|
|
542
534
|
|
|
535
|
+
log("resolved DID from %s", didResolution);
|
|
536
|
+
|
|
543
537
|
const serviceEndpoint = voltConfigServices[0].serviceEndpoint;
|
|
544
538
|
return await fetchVoltConfig.call(this, serviceEndpoint);
|
|
545
539
|
} catch (err) {
|
|
@@ -548,3 +542,22 @@ export async function fetchVoltConfigFromDID(volt_did) {
|
|
|
548
542
|
);
|
|
549
543
|
}
|
|
550
544
|
}
|
|
545
|
+
|
|
546
|
+
export async function fetchVoltConfigFromDID(
|
|
547
|
+
volt_did,
|
|
548
|
+
registryList = [constants.defaultDIDHostName]
|
|
549
|
+
) {
|
|
550
|
+
for (let registryUrl of registryList) {
|
|
551
|
+
try {
|
|
552
|
+
return await fetchVoltConfigFromDIDInternal.call(
|
|
553
|
+
this,
|
|
554
|
+
volt_did,
|
|
555
|
+
registryUrl
|
|
556
|
+
);
|
|
557
|
+
} catch (err) {
|
|
558
|
+
log("Failed to fetch Volt config from %s: %s", registryUrl, err.message);
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
throw new Error("Failed to fetch Volt config from any registry");
|
|
563
|
+
}
|
package/src/volt-client.js
CHANGED
|
@@ -31,7 +31,6 @@ export class VoltClient extends EventEmitter {
|
|
|
31
31
|
}
|
|
32
32
|
this._grpc = grpc;
|
|
33
33
|
this._cachedClient = null;
|
|
34
|
-
this._cachedRemoteClient = null;
|
|
35
34
|
this._session = null;
|
|
36
35
|
this._config = null;
|
|
37
36
|
this._voltConfig = null;
|
|
@@ -56,12 +55,36 @@ export class VoltClient extends EventEmitter {
|
|
|
56
55
|
return this._voltConfig;
|
|
57
56
|
}
|
|
58
57
|
|
|
58
|
+
get connection() {
|
|
59
|
+
return this._voltConnection;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
close() {
|
|
63
|
+
if (this._cachedClient) {
|
|
64
|
+
this._grpc.closeClient(this._cachedClient);
|
|
65
|
+
this._cachedClient = null;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
for (let serviceKey in Object.keys(this._cachedService)) {
|
|
69
|
+
if (this._cachedService[serviceKey]) {
|
|
70
|
+
this._grpc.closeClient(this._cachedService[serviceKey]);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
this._cachedService = {};
|
|
75
|
+
}
|
|
76
|
+
|
|
59
77
|
/**
|
|
60
78
|
* Initialises a binding and connection to the volt.
|
|
61
79
|
* @param {string} [config] - the location of the Volt configuration file, or a configuration object
|
|
62
80
|
* @param {object} [extras] - additional configuration properties
|
|
63
81
|
*/
|
|
64
|
-
async initialise(
|
|
82
|
+
async initialise(
|
|
83
|
+
config,
|
|
84
|
+
extras = {},
|
|
85
|
+
ownDID = false,
|
|
86
|
+
didRegistryList = undefined
|
|
87
|
+
) {
|
|
65
88
|
try {
|
|
66
89
|
if (!config) {
|
|
67
90
|
throw new Error(
|
|
@@ -126,7 +149,15 @@ export class VoltClient extends EventEmitter {
|
|
|
126
149
|
}
|
|
127
150
|
|
|
128
151
|
if (voltDID) {
|
|
129
|
-
const didConfig = await fetchVoltConfigFromDID.call(
|
|
152
|
+
const didConfig = await fetchVoltConfigFromDID.call(
|
|
153
|
+
this,
|
|
154
|
+
voltDID,
|
|
155
|
+
didRegistryList
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
// Remove the relay list from the DID config, as it would overwrite the relay in the supplied config.
|
|
159
|
+
delete didConfig.relay;
|
|
160
|
+
|
|
130
161
|
this._config = { ...this._config, volt: didConfig };
|
|
131
162
|
log("resolved config from DID: %s", JSON.stringify(didConfig, null, 2));
|
|
132
163
|
} else if (voltHttpAddress && !this._config?.volt?.id) {
|
|
@@ -156,7 +187,7 @@ export class VoltClient extends EventEmitter {
|
|
|
156
187
|
|
|
157
188
|
await this._credential.initialise();
|
|
158
189
|
|
|
159
|
-
if (!this.
|
|
190
|
+
if (!this.isRelayed) {
|
|
160
191
|
// If we're not connecting via a Relay, we must have the address and CA.
|
|
161
192
|
if (
|
|
162
193
|
!this._voltConfig.address ||
|
|
@@ -179,7 +210,7 @@ export class VoltClient extends EventEmitter {
|
|
|
179
210
|
} else {
|
|
180
211
|
// No certificate present in the cache yet => we need to authenticate.
|
|
181
212
|
try {
|
|
182
|
-
isBound = await authenticateInternal.call(this);
|
|
213
|
+
isBound = await authenticateInternal.call(this, false, ownDID);
|
|
183
214
|
} catch (bindErr) {
|
|
184
215
|
if (bindErr.message === "invalid arguments") {
|
|
185
216
|
// This is usually the result of a missing challenge signature or credential.
|
|
@@ -196,7 +227,7 @@ export class VoltClient extends EventEmitter {
|
|
|
196
227
|
throw new Error("Volt authentication failed");
|
|
197
228
|
} else {
|
|
198
229
|
// Perist the configuration.
|
|
199
|
-
this.
|
|
230
|
+
this._credential.saveCache();
|
|
200
231
|
}
|
|
201
232
|
|
|
202
233
|
return Promise.resolve(this._config);
|
|
@@ -247,7 +278,7 @@ export class VoltClient extends EventEmitter {
|
|
|
247
278
|
});
|
|
248
279
|
}
|
|
249
280
|
|
|
250
|
-
if (this.
|
|
281
|
+
if (this.isRelayed) {
|
|
251
282
|
if (!this._voltConfig?.relay?.address) {
|
|
252
283
|
throw new Error(
|
|
253
284
|
"Remote connection enabled but no Relay address - have you called start()?"
|
|
@@ -274,14 +305,10 @@ export class VoltClient extends EventEmitter {
|
|
|
274
305
|
}
|
|
275
306
|
}
|
|
276
307
|
|
|
277
|
-
get
|
|
308
|
+
get isRelayed() {
|
|
278
309
|
return !!(this._voltConfig?.relay && this._voltConfig.id);
|
|
279
310
|
}
|
|
280
311
|
|
|
281
|
-
get isVoltRelay() {
|
|
282
|
-
return this.isRemote && !this._voltConfig?.relay.cloud;
|
|
283
|
-
}
|
|
284
|
-
|
|
285
312
|
connect(helloPayload) {
|
|
286
313
|
return connectInternal.call(this, helloPayload);
|
|
287
314
|
}
|
|
@@ -613,6 +640,9 @@ export class VoltClient extends EventEmitter {
|
|
|
613
640
|
*/
|
|
614
641
|
SqlExecuteJSON(request) {
|
|
615
642
|
return new Promise((resolve, reject) => {
|
|
643
|
+
if (!request.start) {
|
|
644
|
+
request = { start: request };
|
|
645
|
+
}
|
|
616
646
|
const call = this.SqlExecute(request);
|
|
617
647
|
|
|
618
648
|
let header;
|
package/src/volt-connection.js
CHANGED
|
@@ -96,8 +96,18 @@ function _doConnect(connectHello) {
|
|
|
96
96
|
break;
|
|
97
97
|
}
|
|
98
98
|
case "invoke_request": {
|
|
99
|
-
log("received invoke request");
|
|
100
|
-
|
|
99
|
+
log("received invoke request %s", response.invoke_request.invoke_id);
|
|
100
|
+
// Pause the call while we process the invoke request to avoid getting
|
|
101
|
+
// CANCELLED errors from grpc - we should perhaps leave this to the
|
|
102
|
+
// client to manage as it may be overkill in some cases.
|
|
103
|
+
this.call.pause();
|
|
104
|
+
try {
|
|
105
|
+
this.emit("invoke_request", response.invoke_request);
|
|
106
|
+
} catch (err) {
|
|
107
|
+
log("error processing invoke request [%s]", err.message);
|
|
108
|
+
} finally {
|
|
109
|
+
this.call.resume();
|
|
110
|
+
}
|
|
101
111
|
break;
|
|
102
112
|
}
|
|
103
113
|
case "evt": {
|
|
@@ -169,6 +179,10 @@ export default class VoltConnection extends EventEmitter {
|
|
|
169
179
|
this._helloPayload = undefined;
|
|
170
180
|
}
|
|
171
181
|
|
|
182
|
+
get connectionId() {
|
|
183
|
+
return this._connectionId;
|
|
184
|
+
}
|
|
185
|
+
|
|
172
186
|
connect(helloPayload, throwOnFail) {
|
|
173
187
|
this._helloPayload = helloPayload;
|
|
174
188
|
if (throwOnFail) {
|
package/src/volt-credential.js
CHANGED
|
@@ -2,14 +2,16 @@
|
|
|
2
2
|
import debug from "debug";
|
|
3
3
|
import fs from "fs";
|
|
4
4
|
import { constants } from "./constants.js";
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
import { voltUtils as voltClientUtils } from "@tdxvolt/volt-client-web/js";
|
|
6
|
+
|
|
7
|
+
const {
|
|
8
|
+
createSigningKey,
|
|
9
|
+
fingerprintFromPem,
|
|
8
10
|
getIdentityToken,
|
|
9
11
|
keyFromPem,
|
|
10
12
|
privateKeyToPem,
|
|
11
13
|
publicKeyToPem
|
|
12
|
-
}
|
|
14
|
+
} = voltClientUtils;
|
|
13
15
|
|
|
14
16
|
const log = debug("volt-client-grpc:volt-credential");
|
|
15
17
|
|
|
@@ -50,11 +52,11 @@ export class VoltCredential {
|
|
|
50
52
|
this._cryptoCache.ca = this._voltConfig.ca_pem;
|
|
51
53
|
}
|
|
52
54
|
|
|
53
|
-
// Extract Volt public key
|
|
55
|
+
// Extract Volt public key.
|
|
54
56
|
this._voltPublicKey = this._voltConfig.public_key;
|
|
55
57
|
|
|
56
58
|
const voltKey = keyFromPem(this._voltPublicKey).publicKey;
|
|
57
|
-
this._voltFingerprint =
|
|
59
|
+
this._voltFingerprint = fingerprintFromPem(voltKey);
|
|
58
60
|
}
|
|
59
61
|
}
|
|
60
62
|
|
|
@@ -90,6 +92,10 @@ export class VoltCredential {
|
|
|
90
92
|
return this._voltFingerprint;
|
|
91
93
|
}
|
|
92
94
|
|
|
95
|
+
get key() {
|
|
96
|
+
return this.getKey();
|
|
97
|
+
}
|
|
98
|
+
|
|
93
99
|
getKey() {
|
|
94
100
|
const key = keyFromPem(this._cryptoCache.key);
|
|
95
101
|
return key;
|
|
@@ -105,7 +111,7 @@ export class VoltCredential {
|
|
|
105
111
|
return Promise.resolve(this.getKey());
|
|
106
112
|
} else {
|
|
107
113
|
log("creating key");
|
|
108
|
-
this._cryptoCache.key =
|
|
114
|
+
this._cryptoCache.key = JSON.parse(createSigningKey()).private_pem;
|
|
109
115
|
const key = keyFromPem(this._cryptoCache.key);
|
|
110
116
|
log("successfully created key");
|
|
111
117
|
return Promise.resolve(key);
|