@tdxvolt/volt-client-grpc 0.15.1 → 0.16.0-beta.2
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 +176 -97
- 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 +89 -39
- package/src/volt-client.js +9 -5
- package/src/volt-credential.js +10 -5
- package/protobuf/tdx/volt_api/ssi/v1/ssi_api.proto +0 -37
|
@@ -4,6 +4,7 @@ package tdx.volt_api.volt.v1;
|
|
|
4
4
|
|
|
5
5
|
import "tdx/volt_api/volt/v1/status.proto";
|
|
6
6
|
import "tdx/volt_api/volt/v1/remote.proto";
|
|
7
|
+
import "tdx/volt_api/volt/v1/ssi.proto";
|
|
7
8
|
import "tdx/volt_api/volt/v1/volt.proto";
|
|
8
9
|
|
|
9
10
|
// The top-level volt management service.
|
|
@@ -11,9 +12,11 @@ import "tdx/volt_api/volt/v1/volt.proto";
|
|
|
11
12
|
// A client certificate can be obtained from the `Bind` method.
|
|
12
13
|
// 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.
|
|
13
14
|
service VoltAPI {
|
|
15
|
+
rpc Authenticate(AuthenticateRequest) returns (AuthenticateResponse);
|
|
16
|
+
|
|
14
17
|
// Issues a request to bind to the volt.
|
|
15
18
|
// All clients must successfully bind to the Volt in order to gain any kind of access.
|
|
16
|
-
// A client certificate is optional for this RPC,
|
|
19
|
+
// A client certificate is optional for this RPC, if omitted a JWT must be provided in the call metadata.
|
|
17
20
|
// If the client plans to register one or more services with the Volt, it should use the 'host' field of the request so that the returned certificate has the appropriate SAN extension in place. Note that if the client IP address changes it will be necessary to re-Bind the client and obtain a new certificate.
|
|
18
21
|
// If the bind decision is 'permit', the bind response contains various details that should be persisted by the client, including the unique identifier assigned by the Volt and a signed client certificate along with the Volt CA certificate.
|
|
19
22
|
rpc Bind(BindRequest) returns (BindResponse);
|
|
@@ -122,9 +125,6 @@ service VoltAPI {
|
|
|
122
125
|
// Save a session.
|
|
123
126
|
rpc SaveSession(SaveSessionRequest) returns (SaveSessionResponse);
|
|
124
127
|
|
|
125
|
-
// Experimental - please ignore.
|
|
126
|
-
rpc Session(SessionRequest) returns (SessionResponse);
|
|
127
|
-
|
|
128
128
|
// Set Volt access request decision.
|
|
129
129
|
// This is a privileged call that requires Volt root access.
|
|
130
130
|
rpc SetAccessRequestDecision(SetAccessRequestDecisionRequest) returns (SetAccessRequestDecisionResponse);
|
|
@@ -133,6 +133,8 @@ service VoltAPI {
|
|
|
133
133
|
// This is a privileged call that requires Volt root access.
|
|
134
134
|
rpc SetBindingDecision(SetBindingDecisionRequest) returns (SetBindingDecisionResponse);
|
|
135
135
|
|
|
136
|
+
rpc SetPolicy(SetPolicyRequest) returns (SetPolicyResponse);
|
|
137
|
+
|
|
136
138
|
// Set the status of a Volt service.
|
|
137
139
|
rpc SetServiceStatus(SetServiceStatusRequest) returns (SetServiceStatusResponse);
|
|
138
140
|
|
|
@@ -145,31 +147,112 @@ service VoltAPI {
|
|
|
145
147
|
}
|
|
146
148
|
|
|
147
149
|
// Describes a request to bind to a volt.
|
|
148
|
-
message
|
|
150
|
+
message AuthenticateRequest {
|
|
151
|
+
|
|
152
|
+
oneof client_identifier {
|
|
153
|
+
// An existing DID owned by the client.
|
|
154
|
+
// The JWT presented with the Bind call must be signed by the private key corresponding to this DID.
|
|
155
|
+
string did = 1;
|
|
156
|
+
|
|
157
|
+
// If the client doesn't have an existing DID, a DID document can be provided here.
|
|
158
|
+
// The document must include a proof that the client owns the public key given in `public_key`.
|
|
159
|
+
// The Volt will register the DID on behalf of the client.
|
|
160
|
+
// The JWT presented with the Bind call must be signed by the private key corresponding to this document.
|
|
161
|
+
string did_document = 2;
|
|
162
|
+
|
|
163
|
+
// The client public key - must be in PEM format. If the client DID is lost or unknown for some reason, providing the public key here will allow the Volt to match it with the previously registered DID.
|
|
164
|
+
// Note this is only valid when a DID has previously been registered using this public key.
|
|
165
|
+
string public_key = 3;
|
|
166
|
+
}
|
|
149
167
|
|
|
150
|
-
//
|
|
151
|
-
string
|
|
168
|
+
// A base64-encoded signature of the DID document, only required if `did_document` is provided above.
|
|
169
|
+
string did_document_signature = 4;
|
|
152
170
|
|
|
153
171
|
// A human-readable name of the entity requesting to bind.
|
|
154
|
-
string binding_name =
|
|
172
|
+
string binding_name = 5;
|
|
155
173
|
|
|
156
174
|
// The volt challenge code, signed by the private key component of the `public_key` field above, and base64 encoded.
|
|
157
175
|
// This is optional.
|
|
158
|
-
string challenge =
|
|
176
|
+
string challenge = 6;
|
|
159
177
|
|
|
160
178
|
// The host name to add as a SAN to the issued certificate.
|
|
161
179
|
// This is optional, if you don't intend to host services with the certificate this can be omitted.
|
|
162
|
-
string host =
|
|
180
|
+
string host = 7;
|
|
181
|
+
|
|
182
|
+
// Optional verifiable credentials describing the client.
|
|
183
|
+
// This is a work in progress.
|
|
184
|
+
repeated VerifiablePresentation verifiable_presentation = 8;
|
|
185
|
+
|
|
186
|
+
// Reserved for internal use.
|
|
187
|
+
bool purge_aliases = 9;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
message AuthenticateResponse {
|
|
191
|
+
// Details of any error that occurred on the call.
|
|
192
|
+
tdx.volt_api.volt.v1.Status status = 1;
|
|
193
|
+
|
|
194
|
+
string session_id = 2;
|
|
195
|
+
|
|
196
|
+
// The identity id assigned to this binding.
|
|
197
|
+
// Only valid for PERMIT bind decisions.
|
|
198
|
+
string identity_id = 3;
|
|
199
|
+
|
|
200
|
+
// A certificate issued by the volt CA, binding the request public key to the identity.
|
|
201
|
+
// Only valid for PERMIT bind decisions.
|
|
202
|
+
string cert = 4;
|
|
203
|
+
|
|
204
|
+
// The volt CA chain. This is used by the client in subsequent API calls to secure the connection.
|
|
205
|
+
string chain = 5;
|
|
206
|
+
|
|
207
|
+
// The bind decision.
|
|
208
|
+
PolicyDecision decision = 6;
|
|
209
|
+
|
|
210
|
+
// Reserved for internal use.
|
|
211
|
+
int64 request_time = 7;
|
|
163
212
|
|
|
164
|
-
//
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
213
|
+
// Reserved for internal use.
|
|
214
|
+
int64 decision_time = 8;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Describes a request to bind to a volt.
|
|
218
|
+
message BindRequest {
|
|
219
|
+
|
|
220
|
+
oneof client_identifier {
|
|
221
|
+
// An existing DID owned by the client.
|
|
222
|
+
// The JWT presented with the Bind call must be signed by the private key corresponding to this DID.
|
|
223
|
+
string did = 1;
|
|
224
|
+
|
|
225
|
+
// If the client doesn't have an existing DID, a DID document can be provided here.
|
|
226
|
+
// The document must include a proof that the client owns the public key given in `public_key`.
|
|
227
|
+
// The Volt will register the DID on behalf of the client.
|
|
228
|
+
// The JWT presented with the Bind call must be signed by the private key corresponding to this document.
|
|
229
|
+
string did_document = 2;
|
|
230
|
+
|
|
231
|
+
// The client public key - must be in PEM format. If the client DID is lost or unknown for some reason, providing the public key here will allow the Volt to match it with the previously registered DID.
|
|
232
|
+
// Note this is only valid when a DID has previously been registered using this public key.
|
|
233
|
+
string public_key = 3;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// A base64-encoded signature of the DID document, only required if `did_document` is provided above.
|
|
237
|
+
string did_document_signature = 4;
|
|
238
|
+
|
|
239
|
+
// A human-readable name of the entity requesting to bind.
|
|
240
|
+
string binding_name = 5;
|
|
241
|
+
|
|
242
|
+
// The volt challenge code, signed by the private key component of the `public_key` field above, and base64 encoded.
|
|
243
|
+
// This is optional.
|
|
244
|
+
string challenge = 6;
|
|
245
|
+
|
|
246
|
+
// The host name to add as a SAN to the issued certificate.
|
|
247
|
+
// This is optional, if you don't intend to host services with the certificate this can be omitted.
|
|
248
|
+
string host = 7;
|
|
169
249
|
|
|
170
250
|
// Optional verifiable credentials describing the client.
|
|
171
251
|
// This is a work in progress.
|
|
172
|
-
repeated VerifiablePresentation verifiable_presentation =
|
|
252
|
+
repeated VerifiablePresentation verifiable_presentation = 8;
|
|
253
|
+
|
|
254
|
+
// Reserved for internal use.
|
|
255
|
+
bool purge_aliases = 9;
|
|
173
256
|
}
|
|
174
257
|
|
|
175
258
|
message BindResponse {
|
|
@@ -278,13 +361,15 @@ message ConnectHello {
|
|
|
278
361
|
bool subscribe_auth_requests = 8;
|
|
279
362
|
|
|
280
363
|
bool accept_invocation = 9;
|
|
364
|
+
|
|
365
|
+
bool subscribe_did_registry_updates = 10;
|
|
281
366
|
}
|
|
282
367
|
|
|
283
368
|
message ConnectAcknowledge {
|
|
284
369
|
string connection_id = 1;
|
|
285
370
|
}
|
|
286
371
|
|
|
287
|
-
// A
|
|
372
|
+
// A connection ping message.
|
|
288
373
|
message ConnectPing {
|
|
289
374
|
// The time on the originating server.
|
|
290
375
|
uint64 timestamp = 1;
|
|
@@ -343,6 +428,7 @@ enum ConnectResourceEvent {
|
|
|
343
428
|
CONNECT_RESOURCE_EVENT_DELETE = 3;
|
|
344
429
|
CONNECT_RESOURCE_EVENT_CREATE_CHILD = 4;
|
|
345
430
|
CONNECT_RESOURCE_EVENT_DELETE_CHILD = 5;
|
|
431
|
+
CONNECT_RESOURCE_EVENT_DATABASE_WRITE = 6;
|
|
346
432
|
}
|
|
347
433
|
|
|
348
434
|
message ConnectResource {
|
|
@@ -363,12 +449,18 @@ message ConnectAuthRequest {
|
|
|
363
449
|
uint64 timestamp = 7;
|
|
364
450
|
}
|
|
365
451
|
|
|
452
|
+
message ConnectDIDRegistryUpdate {
|
|
453
|
+
DIDRegistryUpdate update = 1;
|
|
454
|
+
}
|
|
455
|
+
|
|
366
456
|
message ConnectEvent {
|
|
367
457
|
oneof event {
|
|
368
458
|
ConnectAuthRequest connect_auth_request = 1;
|
|
369
459
|
|
|
370
460
|
// A resource event notification, such as updated or deleted.
|
|
371
461
|
ConnectResource connect_resource = 2;
|
|
462
|
+
|
|
463
|
+
ConnectDIDRegistryUpdate did_registry_update = 3;
|
|
372
464
|
}
|
|
373
465
|
}
|
|
374
466
|
|
|
@@ -620,6 +712,8 @@ message GetParametersResponse {
|
|
|
620
712
|
|
|
621
713
|
// This an empty message.
|
|
622
714
|
message GetPolicyRequest {
|
|
715
|
+
// Set to only retrieve the custom policy document.
|
|
716
|
+
bool custom_policy = 1;
|
|
623
717
|
}
|
|
624
718
|
|
|
625
719
|
message GetPolicyResponse {
|
|
@@ -771,10 +865,9 @@ message InvokeRequest {
|
|
|
771
865
|
// This contains the key and iv used to encrypt the payload, which only the token audience can access because the key and iv are themselves encrypted using the public key of the invocation target.
|
|
772
866
|
string token = 2;
|
|
773
867
|
|
|
774
|
-
//
|
|
868
|
+
// The DID of the target identity hosting the service.
|
|
775
869
|
// This is used by Relays to route the request.
|
|
776
|
-
|
|
777
|
-
repeated string target_fingerprint = 3;
|
|
870
|
+
repeated string target_did = 3;
|
|
778
871
|
|
|
779
872
|
oneof request_payload {
|
|
780
873
|
// A serialised and encrypted instance of `RemoteResponse` in pure binary format.
|
|
@@ -916,6 +1009,17 @@ message SaveIdentityRequest {
|
|
|
916
1009
|
|
|
917
1010
|
// Reserved for system use.
|
|
918
1011
|
string create_in_parent_id = 4;
|
|
1012
|
+
|
|
1013
|
+
// Set to indicate the identity aliases should be purged before saving the identity.
|
|
1014
|
+
// If the `identity` field contains aliases they will be saved after the purge.
|
|
1015
|
+
// If the `identity` field does not contain aliases this effectively deletes all aliases for this identity.
|
|
1016
|
+
// This allows you to selectively update aliases if required, i.e. don't set this flag and include a single alias in the update.
|
|
1017
|
+
bool purge_aliases = 5;
|
|
1018
|
+
|
|
1019
|
+
string did_document = 6;
|
|
1020
|
+
|
|
1021
|
+
// The signature of the identity did document, if present.
|
|
1022
|
+
string did_update_signature = 7;
|
|
919
1023
|
}
|
|
920
1024
|
|
|
921
1025
|
message SaveIdentityResponse {
|
|
@@ -985,19 +1089,13 @@ message SaveSessionResponse {
|
|
|
985
1089
|
Session session = 2;
|
|
986
1090
|
}
|
|
987
1091
|
|
|
988
|
-
message
|
|
989
|
-
string
|
|
990
|
-
oneof payload {
|
|
991
|
-
string fingerprint = 2;
|
|
992
|
-
string signature = 3;
|
|
993
|
-
}
|
|
1092
|
+
message SetPolicyRequest {
|
|
1093
|
+
string custom_policy = 1;
|
|
994
1094
|
}
|
|
995
1095
|
|
|
996
|
-
message
|
|
1096
|
+
message SetPolicyResponse {
|
|
997
1097
|
// Details of any error that occurred on the call.
|
|
998
1098
|
tdx.volt_api.volt.v1.Status status = 1;
|
|
999
|
-
string proof = 2;
|
|
1000
|
-
string session_id = 3;
|
|
1001
1099
|
}
|
|
1002
1100
|
|
|
1003
1101
|
message SetServiceStatusRequest {
|
package/src/constants.js
CHANGED
|
@@ -4,37 +4,37 @@ export const constants = {
|
|
|
4
4
|
collectionOperation: {
|
|
5
5
|
add: "ADD",
|
|
6
6
|
remove: "REMOVE",
|
|
7
|
-
update: "UPDATE"
|
|
7
|
+
update: "UPDATE"
|
|
8
8
|
},
|
|
9
9
|
crypto: {
|
|
10
10
|
subjectDefaults: [
|
|
11
11
|
{
|
|
12
12
|
name: "countryName",
|
|
13
|
-
value: "GB"
|
|
13
|
+
value: "GB"
|
|
14
14
|
},
|
|
15
15
|
{
|
|
16
16
|
name: "localityName",
|
|
17
|
-
value: "Southampton"
|
|
17
|
+
value: "Southampton"
|
|
18
18
|
},
|
|
19
19
|
{
|
|
20
20
|
name: "organizationName",
|
|
21
|
-
value: "nquiringminds Ltd"
|
|
22
|
-
}
|
|
21
|
+
value: "nquiringminds Ltd"
|
|
22
|
+
}
|
|
23
23
|
],
|
|
24
|
-
userIdOID: "0.9.2342.19200300.100.1.1"
|
|
24
|
+
userIdOID: "0.9.2342.19200300.100.1.1"
|
|
25
25
|
},
|
|
26
26
|
defaultDIDHostName: "cloud.tdxvolt.com",
|
|
27
27
|
didServiceType: {
|
|
28
|
-
voltConfig: "tdx-volt-config"
|
|
28
|
+
voltConfig: "tdx-volt-config"
|
|
29
29
|
},
|
|
30
30
|
identityType: {
|
|
31
31
|
did: "did",
|
|
32
|
-
volt: "volt"
|
|
32
|
+
volt: "volt"
|
|
33
33
|
},
|
|
34
34
|
onlineStatus: {
|
|
35
35
|
offline: "offline",
|
|
36
36
|
online: "online",
|
|
37
|
-
unknown: "unknown"
|
|
37
|
+
unknown: "unknown"
|
|
38
38
|
},
|
|
39
39
|
publicKeyPrefix: "-----BEGIN PUBLIC KEY-----",
|
|
40
40
|
privateKeyPrefix: "-----BEGIN RSA PRIVATE KEY-----",
|
|
@@ -45,14 +45,14 @@ export const constants = {
|
|
|
45
45
|
proxy: "proxy",
|
|
46
46
|
proxyView: "proxy-view",
|
|
47
47
|
vc: "vc",
|
|
48
|
-
vcView: "vc-view"
|
|
48
|
+
vcView: "vc-view"
|
|
49
49
|
},
|
|
50
50
|
voltStatus: {
|
|
51
51
|
pending: "",
|
|
52
52
|
online: "online",
|
|
53
53
|
offline: "offline",
|
|
54
54
|
deleted: "deleted",
|
|
55
|
-
revoked: "revoked"
|
|
55
|
+
revoked: "revoked"
|
|
56
56
|
},
|
|
57
57
|
/**
|
|
58
58
|
* These top-level service types should map to a protobuf definition
|
|
@@ -62,14 +62,14 @@ export const constants = {
|
|
|
62
62
|
fileAPI: "tdx.volt_api.volt.v1.FileAPI",
|
|
63
63
|
sqliteServerAPI: "tdx.volt_api.data.v1.SqliteServerAPI",
|
|
64
64
|
sqliteDatabaseAPI: "tdx.volt_api.data.v1.SqliteDatabaseAPI",
|
|
65
|
-
ssiAPI: "tdx.volt_api.
|
|
65
|
+
ssiAPI: "tdx.volt_api.volt.v1.SsiAPI",
|
|
66
66
|
relayAPI: "tdx.volt_api.relay.v1.RelayAPI",
|
|
67
67
|
voltAPI: "tdx.volt_api.volt.v1.VoltAPI",
|
|
68
|
-
wireAPI: "tdx.volt_api.volt.v1.WireAPI"
|
|
68
|
+
wireAPI: "tdx.volt_api.volt.v1.WireAPI"
|
|
69
69
|
},
|
|
70
70
|
tunnelInvokeMethod: "/tdx.volt_api.volt.v1.VoltAPI/Invoke",
|
|
71
71
|
tunnelPingInterval: 10000,
|
|
72
72
|
tunnelPingTimeout: 2500,
|
|
73
73
|
tunnelReconnectAfter: 30000,
|
|
74
|
-
tunnelTimeoutInterval: 10000 * 2
|
|
74
|
+
tunnelTimeoutInterval: 10000 * 2 // This must always be greater than `tunnelPingInterval`.
|
|
75
75
|
};
|
package/src/grpc-call.js
CHANGED
|
@@ -8,7 +8,7 @@ const log = debug("volt-client-grpc:grpc-call");
|
|
|
8
8
|
function _prepareInvokeRequest(
|
|
9
9
|
request,
|
|
10
10
|
method,
|
|
11
|
-
methodType = "METHOD_TYPE_UNARY"
|
|
11
|
+
methodType = "METHOD_TYPE_UNARY"
|
|
12
12
|
) {
|
|
13
13
|
const isServiceRelayed =
|
|
14
14
|
this._service?.service_description.host_type ===
|
|
@@ -21,7 +21,7 @@ function _prepareInvokeRequest(
|
|
|
21
21
|
this._voltClient.voltConfig.id,
|
|
22
22
|
this._service?.service_description.host_public_key ||
|
|
23
23
|
this._voltClient.credential.voltPublicKey,
|
|
24
|
-
true
|
|
24
|
+
true
|
|
25
25
|
);
|
|
26
26
|
|
|
27
27
|
let invokeRequest;
|
|
@@ -52,42 +52,40 @@ function _prepareInvokeRequest(
|
|
|
52
52
|
method_name: this._grpcClient[method].path,
|
|
53
53
|
method_type: methodType,
|
|
54
54
|
token: methodToken.token,
|
|
55
|
-
request: requestPayload
|
|
56
|
-
}
|
|
55
|
+
request: requestPayload
|
|
56
|
+
}
|
|
57
57
|
};
|
|
58
58
|
|
|
59
|
-
let
|
|
59
|
+
let targetDID = [];
|
|
60
60
|
let invokePayload;
|
|
61
61
|
if (this._voltClient.isVoltRelay || isServiceRelayed) {
|
|
62
62
|
// When sending via a relay we need to encrypt the payload.
|
|
63
63
|
invokePayload = VoltCredential.aesEncrypt(
|
|
64
64
|
tunnelMethod.responseSerialize(tunnelResp),
|
|
65
65
|
methodToken.sharedKey.key,
|
|
66
|
-
methodToken.sharedKey.iv
|
|
66
|
+
methodToken.sharedKey.iv
|
|
67
67
|
);
|
|
68
68
|
} else {
|
|
69
69
|
invokePayload = tunnelMethod.responseSerialize(tunnelResp);
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
if (this._voltClient.isVoltRelay) {
|
|
73
|
-
|
|
73
|
+
targetDID.push(this._voltClient.voltConfig.id);
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
if (isServiceRelayed) {
|
|
77
77
|
// Add another relay hop if the target service is relayed.
|
|
78
78
|
log("target service is relayed");
|
|
79
|
-
|
|
80
|
-
this._service.service_description.host_fingerprint,
|
|
81
|
-
);
|
|
79
|
+
targetDID.push(this._service.service_description.host_client_id);
|
|
82
80
|
}
|
|
83
81
|
|
|
84
|
-
log("target is %j",
|
|
82
|
+
log("target is %j", targetDID);
|
|
85
83
|
|
|
86
84
|
invokeRequest = {
|
|
87
|
-
|
|
85
|
+
target_did: targetDID,
|
|
88
86
|
token: methodToken.token,
|
|
89
87
|
payload: invokePayload,
|
|
90
|
-
target_service_id: isServiceRelayed ? this._service.id : undefined
|
|
88
|
+
target_service_id: isServiceRelayed ? this._service.id : undefined
|
|
91
89
|
};
|
|
92
90
|
|
|
93
91
|
// Replace the target method with a call to Invoke on the relay Volt.
|
|
@@ -100,7 +98,7 @@ function _prepareInvokeRequest(
|
|
|
100
98
|
meta: methodToken,
|
|
101
99
|
method: callMethod,
|
|
102
100
|
methodName: method,
|
|
103
|
-
request: invokeRequest
|
|
101
|
+
request: invokeRequest
|
|
104
102
|
};
|
|
105
103
|
}
|
|
106
104
|
|
|
@@ -120,18 +118,18 @@ function _preparePayloadRequest(request, invokeInfo) {
|
|
|
120
118
|
|
|
121
119
|
const tunnelResp = {
|
|
122
120
|
method_payload: {
|
|
123
|
-
payload: requestPayload
|
|
124
|
-
}
|
|
121
|
+
payload: requestPayload
|
|
122
|
+
}
|
|
125
123
|
};
|
|
126
124
|
|
|
127
125
|
const invokePayload = VoltCredential.aesEncrypt(
|
|
128
126
|
tunnelMethod.responseSerialize(tunnelResp),
|
|
129
127
|
invokeInfo.meta.sharedKey.key,
|
|
130
|
-
invokeInfo.meta.sharedKey.iv
|
|
128
|
+
invokeInfo.meta.sharedKey.iv
|
|
131
129
|
);
|
|
132
130
|
|
|
133
131
|
payloadRequest = {
|
|
134
|
-
payload: invokePayload
|
|
132
|
+
payload: invokePayload
|
|
135
133
|
};
|
|
136
134
|
} else {
|
|
137
135
|
payloadRequest = request;
|
|
@@ -155,7 +153,7 @@ function _parseResponse(method, meta, response) {
|
|
|
155
153
|
decryptedPayload = VoltCredential.aesDecrypt(
|
|
156
154
|
response.payload,
|
|
157
155
|
meta.sharedKey.key,
|
|
158
|
-
meta.sharedKey.iv
|
|
156
|
+
meta.sharedKey.iv
|
|
159
157
|
);
|
|
160
158
|
} else {
|
|
161
159
|
decryptedPayload = response.payload;
|
|
@@ -166,12 +164,12 @@ function _parseResponse(method, meta, response) {
|
|
|
166
164
|
if (responsePayload.payload === "method_payload") {
|
|
167
165
|
try {
|
|
168
166
|
invokeResponse.payload = this._grpcClient[method].responseDeserialize(
|
|
169
|
-
responsePayload.method_payload.payload
|
|
167
|
+
responsePayload.method_payload.payload
|
|
170
168
|
);
|
|
171
169
|
} catch (err) {
|
|
172
170
|
log("failure deserialising payload for %s", this._methodName);
|
|
173
171
|
throw new Error(
|
|
174
|
-
"failure deserialising payload - check protobuf definition matches with data being sent"
|
|
172
|
+
"failure deserialising payload - check protobuf definition matches with data being sent"
|
|
175
173
|
);
|
|
176
174
|
}
|
|
177
175
|
} else if (responsePayload.payload === "method_end") {
|
|
@@ -185,11 +183,11 @@ function _parseResponse(method, meta, response) {
|
|
|
185
183
|
"Tunnel status received: %s, code %d, description: %s",
|
|
186
184
|
response.status.message,
|
|
187
185
|
response.status.code,
|
|
188
|
-
response.status.description || "n/a"
|
|
186
|
+
response.status.description || "n/a"
|
|
189
187
|
);
|
|
190
188
|
invokeResponse = {
|
|
191
189
|
ended: true,
|
|
192
|
-
error: `Error in tunnel: ${response.status.message}
|
|
190
|
+
error: `Error in tunnel: ${response.status.message}`
|
|
193
191
|
};
|
|
194
192
|
} else {
|
|
195
193
|
invokeResponse.methodId = response.invoke_id;
|
|
@@ -199,11 +197,11 @@ function _parseResponse(method, meta, response) {
|
|
|
199
197
|
const decryptedPayload = VoltCredential.aesDecrypt(
|
|
200
198
|
response,
|
|
201
199
|
meta.sharedKey.key,
|
|
202
|
-
meta.sharedKey.iv
|
|
200
|
+
meta.sharedKey.iv
|
|
203
201
|
);
|
|
204
202
|
invokeResponse = {
|
|
205
203
|
payload:
|
|
206
|
-
this._grpcClient[method].responseDeserializeOriginal(decryptedPayload)
|
|
204
|
+
this._grpcClient[method].responseDeserializeOriginal(decryptedPayload)
|
|
207
205
|
};
|
|
208
206
|
} else {
|
|
209
207
|
invokeResponse = { payload: response };
|
|
@@ -233,7 +231,7 @@ export default class GRPCCall extends EventEmitter {
|
|
|
233
231
|
this,
|
|
234
232
|
request,
|
|
235
233
|
this._methodName,
|
|
236
|
-
this._methodType
|
|
234
|
+
this._methodType
|
|
237
235
|
);
|
|
238
236
|
|
|
239
237
|
const isServiceRelayed =
|
|
@@ -248,7 +246,7 @@ export default class GRPCCall extends EventEmitter {
|
|
|
248
246
|
}
|
|
249
247
|
|
|
250
248
|
this._call = callClient[this._initialRequest.method](
|
|
251
|
-
this._initialRequest.meta.metadata
|
|
249
|
+
this._initialRequest.meta.metadata
|
|
252
250
|
);
|
|
253
251
|
|
|
254
252
|
this._call.on("data", (streamResponse) => {
|
|
@@ -257,14 +255,14 @@ export default class GRPCCall extends EventEmitter {
|
|
|
257
255
|
this,
|
|
258
256
|
this._methodName,
|
|
259
257
|
this._initialRequest.meta,
|
|
260
|
-
streamResponse
|
|
258
|
+
streamResponse
|
|
261
259
|
);
|
|
262
260
|
if (parsedResponse.payload) {
|
|
263
261
|
// Interpret a non-empty status message as an error.
|
|
264
262
|
if (parsedResponse.payload?.status?.message) {
|
|
265
263
|
this.emit(
|
|
266
264
|
"error",
|
|
267
|
-
new Error(parsedResponse.payload.status.message)
|
|
265
|
+
new Error(parsedResponse.payload.status.message)
|
|
268
266
|
);
|
|
269
267
|
} else {
|
|
270
268
|
this.emit("data", parsedResponse.payload);
|
|
@@ -283,7 +281,7 @@ export default class GRPCCall extends EventEmitter {
|
|
|
283
281
|
log(
|
|
284
282
|
"failure processing %s call response: %s",
|
|
285
283
|
this._methodName,
|
|
286
|
-
err.message
|
|
284
|
+
err.message
|
|
287
285
|
);
|
|
288
286
|
this.emit("error", err);
|
|
289
287
|
}
|
|
@@ -305,7 +303,7 @@ export default class GRPCCall extends EventEmitter {
|
|
|
305
303
|
log(
|
|
306
304
|
"ended call %s, method id: %s",
|
|
307
305
|
this._methodName,
|
|
308
|
-
this._initialRequest.methodId || "n/a - not tunnelling"
|
|
306
|
+
this._initialRequest.methodId || "n/a - not tunnelling"
|
|
309
307
|
);
|
|
310
308
|
this.emit("end");
|
|
311
309
|
});
|
|
@@ -338,7 +336,7 @@ export default class GRPCCall extends EventEmitter {
|
|
|
338
336
|
const payloadRequest = _preparePayloadRequest.call(
|
|
339
337
|
this,
|
|
340
338
|
request,
|
|
341
|
-
this._initialRequest
|
|
339
|
+
this._initialRequest
|
|
342
340
|
);
|
|
343
341
|
return this._call.write(payloadRequest);
|
|
344
342
|
} else {
|
|
@@ -346,7 +344,7 @@ export default class GRPCCall extends EventEmitter {
|
|
|
346
344
|
this,
|
|
347
345
|
request,
|
|
348
346
|
this._methodName,
|
|
349
|
-
this._methodType
|
|
347
|
+
this._methodType
|
|
350
348
|
);
|
|
351
349
|
|
|
352
350
|
return this._call.write(this._initialRequest.request);
|
package/src/utils.js
CHANGED
|
@@ -64,11 +64,16 @@ export const createPublicKeyFingerprint = (key) => {
|
|
|
64
64
|
return createBase58Hash(removeCarriageReturn(key));
|
|
65
65
|
};
|
|
66
66
|
|
|
67
|
+
export const base64ToBase64Url = (base64) => {
|
|
68
|
+
return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
69
|
+
};
|
|
70
|
+
|
|
67
71
|
export const signBase64 = (key, msg) => {
|
|
68
72
|
const md = forge.md.sha256.create();
|
|
69
73
|
md.update(msg);
|
|
70
74
|
const signature = key.sign(md);
|
|
71
|
-
|
|
75
|
+
const base64Standard = forge.util.encode64(signature);
|
|
76
|
+
return base64ToBase64Url(base64Standard);
|
|
72
77
|
};
|
|
73
78
|
|
|
74
79
|
export const verifyBase64 = (key, msg, signature) => {
|
|
@@ -137,10 +142,25 @@ export const createRSAKey = (passphrase = "") => {
|
|
|
137
142
|
export const sha256Base64 = (msg) => {
|
|
138
143
|
const md = forge.md.sha256.create();
|
|
139
144
|
md.update(msg);
|
|
140
|
-
|
|
145
|
+
const base64Standard = forge.util.encode64(md.digest().bytes());
|
|
146
|
+
return base64ToBase64Url(base64Standard);
|
|
141
147
|
};
|
|
142
148
|
|
|
143
149
|
export const decryptPrivateKey = (pem, passphrase) => {
|
|
144
150
|
const decryptedKey = pki.decryptRsaPrivateKey(pem, passphrase);
|
|
145
151
|
return forgePrivateKeyToPem(decryptedKey);
|
|
146
152
|
};
|
|
153
|
+
|
|
154
|
+
export const jwsSignature = (signature) => {
|
|
155
|
+
//
|
|
156
|
+
// Use an unattached payload JWS signature for the DID document proof.
|
|
157
|
+
// This is a JWS with an empty payload and a detached payload digest.
|
|
158
|
+
//
|
|
159
|
+
// (https://tools.ietf.org/html/rfc7797#appendix-F) as used in the VC spec
|
|
160
|
+
// (https://www.w3.org/TR/vc-data-model/).
|
|
161
|
+
//
|
|
162
|
+
const jwsHeader = base64ToBase64Url(
|
|
163
|
+
forge.util.encode64('{"alg":"RS256","b64": false}')
|
|
164
|
+
);
|
|
165
|
+
return jwsHeader + ".." + signature;
|
|
166
|
+
};
|