@bedrock/kms-http 14.5.0 → 15.0.0
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 +3 -3
- package/lib/BedrockKeystoreConfigStorage.js +1 -3
- package/lib/helpers.js +14 -11
- package/lib/http.js +8 -10
- package/lib/metering.js +3 -3
- package/lib/middleware.js +13 -15
- package/package.json +21 -16
- package/schemas/bedrock-kms-http.js +1 -1
- package/.eslintrc.cjs +0 -12
- package/.github/workflows/main.yml +0 -77
- package/CHANGELOG.md +0 -386
- package/test/mocha/.eslintrc +0 -9
- package/test/mocha/10-keystore.js +0 -670
- package/test/mocha/11-keystore-kms-client.js +0 -242
- package/test/mocha/20-revocation.js +0 -545
- package/test/mocha/21-revocation-ip-allow-list.js +0 -143
- package/test/mocha/30-operations-generate-key.js +0 -180
- package/test/mocha/31-operations-hmac.js +0 -176
- package/test/mocha/helpers.js +0 -163
- package/test/mocha/mock.data.js +0 -40
- package/test/package.json +0 -64
- package/test/test.config.js +0 -36
- package/test/test.js +0 -31
- package/test/web/.eslintrc +0 -9
- package/test/web/10-api.js +0 -108
- package/test/web/helpers.js +0 -84
|
@@ -1,670 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright (c) 2019-2022 Digital Bazaar, Inc. All rights reserved.
|
|
3
|
-
*/
|
|
4
|
-
import * as bedrock from '@bedrock/core';
|
|
5
|
-
import * as helpers from './helpers.js';
|
|
6
|
-
import {agent} from '@bedrock/https-agent';
|
|
7
|
-
import {createRequire} from 'node:module';
|
|
8
|
-
import {httpClient, DEFAULT_HEADERS} from '@digitalbazaar/http-client';
|
|
9
|
-
import {mockData} from './mock.data.js';
|
|
10
|
-
const require = createRequire(import.meta.url);
|
|
11
|
-
const {CapabilityAgent} = require('@digitalbazaar/webkms-client');
|
|
12
|
-
const {signCapabilityInvocation} = require(
|
|
13
|
-
'@digitalbazaar/http-signature-zcap-invoke');
|
|
14
|
-
const {ZcapClient} = require('@digitalbazaar/ezcap');
|
|
15
|
-
const {Ed25519Signature2020} = require('@digitalbazaar/ed25519-signature-2020');
|
|
16
|
-
|
|
17
|
-
describe('bedrock-kms-http API', () => {
|
|
18
|
-
describe('keystores', () => {
|
|
19
|
-
it('creates a keystore', async () => {
|
|
20
|
-
const secret = 'b07e6b31-d910-438e-9a5f-08d945a5f676';
|
|
21
|
-
const handle = 'testKey1';
|
|
22
|
-
const capabilityAgent = await CapabilityAgent.fromSecret(
|
|
23
|
-
{secret, handle});
|
|
24
|
-
|
|
25
|
-
let err;
|
|
26
|
-
let result;
|
|
27
|
-
try {
|
|
28
|
-
result = await helpers.createKeystore({capabilityAgent});
|
|
29
|
-
} catch(e) {
|
|
30
|
-
err = e;
|
|
31
|
-
}
|
|
32
|
-
assertNoError(err);
|
|
33
|
-
should.exist(result);
|
|
34
|
-
result.should.have.keys([
|
|
35
|
-
'controller', 'id', 'sequence', 'kmsModule', 'meterId'
|
|
36
|
-
]);
|
|
37
|
-
result.sequence.should.equal(0);
|
|
38
|
-
const {id: capabilityAgentId} = capabilityAgent;
|
|
39
|
-
result.controller.should.equal(capabilityAgentId);
|
|
40
|
-
});
|
|
41
|
-
it('creates a keystore including proper ipAllowList', async () => {
|
|
42
|
-
const secret = 'b07e6b31-d910-438e-9a5f-08d945a5f676';
|
|
43
|
-
const handle = 'testKey1';
|
|
44
|
-
const capabilityAgent = await CapabilityAgent.fromSecret(
|
|
45
|
-
{secret, handle});
|
|
46
|
-
|
|
47
|
-
const ipAllowList = ['127.0.0.1/32'];
|
|
48
|
-
|
|
49
|
-
let err;
|
|
50
|
-
let result;
|
|
51
|
-
try {
|
|
52
|
-
result = await helpers.createKeystore({capabilityAgent, ipAllowList});
|
|
53
|
-
} catch(e) {
|
|
54
|
-
err = e;
|
|
55
|
-
}
|
|
56
|
-
assertNoError(err);
|
|
57
|
-
should.exist(result);
|
|
58
|
-
result.should.have.keys([
|
|
59
|
-
'controller', 'id', 'ipAllowList', 'sequence', 'kmsModule', 'meterId'
|
|
60
|
-
]);
|
|
61
|
-
result.sequence.should.equal(0);
|
|
62
|
-
const {id: capabilityAgentId} = capabilityAgent;
|
|
63
|
-
result.controller.should.equal(capabilityAgentId);
|
|
64
|
-
result.ipAllowList.should.eql(ipAllowList);
|
|
65
|
-
});
|
|
66
|
-
it('returns error on invalid ipAllowList', async () => {
|
|
67
|
-
const secret = 'b07e6b31-d910-438e-9a5f-08d945a5f676';
|
|
68
|
-
const handle = 'testKey1';
|
|
69
|
-
const capabilityAgent = await CapabilityAgent.fromSecret(
|
|
70
|
-
{secret, handle});
|
|
71
|
-
|
|
72
|
-
// this is not a valid CIDR
|
|
73
|
-
const ipAllowList = ['127.0.0.1/33'];
|
|
74
|
-
|
|
75
|
-
let err;
|
|
76
|
-
let result;
|
|
77
|
-
try {
|
|
78
|
-
result = await helpers.createKeystore({capabilityAgent, ipAllowList});
|
|
79
|
-
} catch(e) {
|
|
80
|
-
err = e;
|
|
81
|
-
}
|
|
82
|
-
should.exist(err);
|
|
83
|
-
should.not.exist(result);
|
|
84
|
-
err.data.details.errors.should.have.length(1);
|
|
85
|
-
const [error] = err.data.details.errors;
|
|
86
|
-
error.name.should.equal('ValidationError');
|
|
87
|
-
error.message.should.contain('should match pattern');
|
|
88
|
-
error.details.path.should.equal('.ipAllowList[0]');
|
|
89
|
-
});
|
|
90
|
-
it('returns error on invalid ipAllowList', async () => {
|
|
91
|
-
const secret = 'b07e6b31-d910-438e-9a5f-08d945a5f676';
|
|
92
|
-
const handle = 'testKey1';
|
|
93
|
-
const capabilityAgent = await CapabilityAgent.fromSecret(
|
|
94
|
-
{secret, handle});
|
|
95
|
-
|
|
96
|
-
// an empty allow list is invalid
|
|
97
|
-
const ipAllowList = [];
|
|
98
|
-
|
|
99
|
-
let err;
|
|
100
|
-
let result;
|
|
101
|
-
try {
|
|
102
|
-
result = await helpers.createKeystore({capabilityAgent, ipAllowList});
|
|
103
|
-
} catch(e) {
|
|
104
|
-
err = e;
|
|
105
|
-
}
|
|
106
|
-
should.exist(err);
|
|
107
|
-
should.not.exist(result);
|
|
108
|
-
err.data.details.errors.should.have.length(1);
|
|
109
|
-
const [error] = err.data.details.errors;
|
|
110
|
-
error.name.should.equal('ValidationError');
|
|
111
|
-
error.message.should.contain('should NOT have fewer than 1 items');
|
|
112
|
-
error.details.path.should.equal('.ipAllowList');
|
|
113
|
-
});
|
|
114
|
-
it('throws error on no sequence in postKeystoreBody validation',
|
|
115
|
-
async () => {
|
|
116
|
-
const secret = 'b07e6b31-d910-438e-9a5f-08d945a5f676';
|
|
117
|
-
const handle = 'testKey1';
|
|
118
|
-
const capabilityAgent = await CapabilityAgent.fromSecret(
|
|
119
|
-
{secret, handle});
|
|
120
|
-
|
|
121
|
-
const kmsBaseUrl = `${bedrock.config.server.baseUri}/kms`;
|
|
122
|
-
const url = `${kmsBaseUrl}/keystores`;
|
|
123
|
-
const config = {
|
|
124
|
-
controller: capabilityAgent.id
|
|
125
|
-
};
|
|
126
|
-
|
|
127
|
-
let err;
|
|
128
|
-
let result;
|
|
129
|
-
try {
|
|
130
|
-
result = await httpClient.post(url, {agent, json: config});
|
|
131
|
-
} catch(e) {
|
|
132
|
-
err = e;
|
|
133
|
-
}
|
|
134
|
-
should.exist(err);
|
|
135
|
-
should.not.exist(result);
|
|
136
|
-
err.data.type.should.equal('ValidationError');
|
|
137
|
-
err.data.message.should.equal(
|
|
138
|
-
'A validation error occured in the \'postKeystoreBody\' validator.');
|
|
139
|
-
});
|
|
140
|
-
it('throws error with no controller in zcap validation', async () => {
|
|
141
|
-
const secret = ' b07e6b31-d910-438e-9a5f-08d945a5f676';
|
|
142
|
-
const handle = 'testKey1';
|
|
143
|
-
const capabilityAgent = await CapabilityAgent.fromSecret(
|
|
144
|
-
{secret, handle});
|
|
145
|
-
|
|
146
|
-
const keystore = await helpers.createKeystore({capabilityAgent});
|
|
147
|
-
|
|
148
|
-
const zcap = mockData.zcaps.zero;
|
|
149
|
-
delete zcap.controller;
|
|
150
|
-
|
|
151
|
-
const url =
|
|
152
|
-
`${keystore.id}/zcaps/revocations/${encodeURIComponent(zcap.id)}`;
|
|
153
|
-
|
|
154
|
-
let err;
|
|
155
|
-
let result;
|
|
156
|
-
try {
|
|
157
|
-
result = await httpClient.post(url, {agent, json: zcap});
|
|
158
|
-
} catch(e) {
|
|
159
|
-
err = e;
|
|
160
|
-
}
|
|
161
|
-
should.exist(err);
|
|
162
|
-
should.not.exist(result);
|
|
163
|
-
err.data.type.should.equal('ValidationError');
|
|
164
|
-
err.data.message.should.equal(
|
|
165
|
-
'A validation error occured in the \'delegatedZcap\' validator.');
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
describe('get keystore config', () => {
|
|
169
|
-
it('gets a keystore', async () => {
|
|
170
|
-
const secret = 'b07e6b31-d910-438e-9a5f-08d945a5f676';
|
|
171
|
-
const handle = 'testKey1';
|
|
172
|
-
const capabilityAgent = await CapabilityAgent.fromSecret(
|
|
173
|
-
{secret, handle});
|
|
174
|
-
|
|
175
|
-
const keystore = await helpers.createKeystore({capabilityAgent});
|
|
176
|
-
let err;
|
|
177
|
-
let result;
|
|
178
|
-
try {
|
|
179
|
-
result = await helpers.getKeystore(
|
|
180
|
-
{id: keystore.id, capabilityAgent});
|
|
181
|
-
} catch(e) {
|
|
182
|
-
err = e;
|
|
183
|
-
}
|
|
184
|
-
assertNoError(err);
|
|
185
|
-
should.exist(result);
|
|
186
|
-
result.should.have.keys([
|
|
187
|
-
'controller', 'id', 'sequence', 'kmsModule', 'meterId'
|
|
188
|
-
]);
|
|
189
|
-
result.id.should.equal(keystore.id);
|
|
190
|
-
});
|
|
191
|
-
it('gets a keystore with ipAllowList', async () => {
|
|
192
|
-
const secret = 'b07e6b31-d910-438e-9a5f-08d945a5f676';
|
|
193
|
-
const handle = 'testKey1';
|
|
194
|
-
const capabilityAgent = await CapabilityAgent.fromSecret(
|
|
195
|
-
{secret, handle});
|
|
196
|
-
|
|
197
|
-
const ipAllowList = ['127.0.0.1/32'];
|
|
198
|
-
|
|
199
|
-
const keystore = await helpers.createKeystore(
|
|
200
|
-
{capabilityAgent, ipAllowList});
|
|
201
|
-
let err;
|
|
202
|
-
let result;
|
|
203
|
-
try {
|
|
204
|
-
result = await helpers.getKeystore(
|
|
205
|
-
{id: keystore.id, capabilityAgent});
|
|
206
|
-
} catch(e) {
|
|
207
|
-
err = e;
|
|
208
|
-
}
|
|
209
|
-
assertNoError(err);
|
|
210
|
-
should.exist(result);
|
|
211
|
-
result.should.have.keys([
|
|
212
|
-
'controller', 'id', 'ipAllowList', 'sequence', 'kmsModule', 'meterId'
|
|
213
|
-
]);
|
|
214
|
-
result.should.have.property('id');
|
|
215
|
-
result.id.should.equal(keystore.id);
|
|
216
|
-
result.ipAllowList.should.eql(ipAllowList);
|
|
217
|
-
});
|
|
218
|
-
it('returns NotAllowedError for invalid source IP', async () => {
|
|
219
|
-
const secret = ' b07e6b31-d910-438e-9a5f-08d945a5f676';
|
|
220
|
-
const handle = 'testKey1';
|
|
221
|
-
const capabilityAgent = await CapabilityAgent.fromSecret(
|
|
222
|
-
{secret, handle});
|
|
223
|
-
|
|
224
|
-
const ipAllowList = ['8.8.8.8/32'];
|
|
225
|
-
|
|
226
|
-
const keystore = await helpers.createKeystore(
|
|
227
|
-
{capabilityAgent, ipAllowList});
|
|
228
|
-
let err;
|
|
229
|
-
let result;
|
|
230
|
-
try {
|
|
231
|
-
result = await helpers.getKeystore(
|
|
232
|
-
{id: keystore.id, capabilityAgent});
|
|
233
|
-
} catch(e) {
|
|
234
|
-
err = e;
|
|
235
|
-
}
|
|
236
|
-
should.not.exist(result);
|
|
237
|
-
should.exist(err);
|
|
238
|
-
err.status.should.equal(403);
|
|
239
|
-
err.data.type.should.equal('NotAllowedError');
|
|
240
|
-
});
|
|
241
|
-
}); // get keystore config
|
|
242
|
-
|
|
243
|
-
describe('update keystore config', () => {
|
|
244
|
-
it('updates a keystore config', async () => {
|
|
245
|
-
const secret = '69ae7dc3-1d6d-4ff9-9cc0-c07b43d2006b';
|
|
246
|
-
const handle = 'testKeyUpdate';
|
|
247
|
-
const capabilityAgent = await CapabilityAgent.fromSecret(
|
|
248
|
-
{secret, handle});
|
|
249
|
-
|
|
250
|
-
const secret2 = 'ac36ef8e-560b-4f6c-a454-6bfcb4e31a76';
|
|
251
|
-
const handle2 = 'testKeyUpdate2';
|
|
252
|
-
const capabilityAgent2 = await CapabilityAgent.fromSecret(
|
|
253
|
-
{secret: secret2, handle: handle2});
|
|
254
|
-
|
|
255
|
-
let err;
|
|
256
|
-
let result;
|
|
257
|
-
let existingConfig;
|
|
258
|
-
try {
|
|
259
|
-
existingConfig = result = await helpers.createKeystore(
|
|
260
|
-
{capabilityAgent});
|
|
261
|
-
} catch(e) {
|
|
262
|
-
err = e;
|
|
263
|
-
}
|
|
264
|
-
assertNoError(err);
|
|
265
|
-
should.exist(result);
|
|
266
|
-
result.should.have.property('id');
|
|
267
|
-
result.should.have.property('sequence');
|
|
268
|
-
result.sequence.should.equal(0);
|
|
269
|
-
const {id: capabilityAgentId} = capabilityAgent;
|
|
270
|
-
result.should.have.property('controller');
|
|
271
|
-
result.controller.should.equal(capabilityAgentId);
|
|
272
|
-
|
|
273
|
-
// this update does not change the `meterId`
|
|
274
|
-
const {id: url} = result;
|
|
275
|
-
const newConfig = {
|
|
276
|
-
// did:key:z6MknP29cPcQ7G76MWmnsuEEdeFya8ij3fXvJcTJYLXadmp9
|
|
277
|
-
controller: capabilityAgent2.id,
|
|
278
|
-
id: url,
|
|
279
|
-
sequence: 1,
|
|
280
|
-
};
|
|
281
|
-
|
|
282
|
-
const headers = await signCapabilityInvocation({
|
|
283
|
-
url, method: 'post',
|
|
284
|
-
headers: DEFAULT_HEADERS,
|
|
285
|
-
json: newConfig,
|
|
286
|
-
capability: 'urn:zcap:root:' + encodeURIComponent(url),
|
|
287
|
-
invocationSigner: capabilityAgent.getSigner(),
|
|
288
|
-
capabilityAction: 'write'
|
|
289
|
-
});
|
|
290
|
-
|
|
291
|
-
err = null;
|
|
292
|
-
result = null;
|
|
293
|
-
try {
|
|
294
|
-
result = await httpClient.post(
|
|
295
|
-
url, {agent, headers, json: newConfig});
|
|
296
|
-
} catch(e) {
|
|
297
|
-
err = e;
|
|
298
|
-
}
|
|
299
|
-
assertNoError(err);
|
|
300
|
-
should.exist(result.data);
|
|
301
|
-
result.status.should.equal(200);
|
|
302
|
-
result.data.should.have.keys(['config']);
|
|
303
|
-
const expectedConfig = {
|
|
304
|
-
...existingConfig,
|
|
305
|
-
...newConfig
|
|
306
|
-
};
|
|
307
|
-
result.data.config.should.eql(expectedConfig);
|
|
308
|
-
|
|
309
|
-
// should fail to retrieve the keystore config now that controller
|
|
310
|
-
// has changed
|
|
311
|
-
err = null;
|
|
312
|
-
result = null;
|
|
313
|
-
try {
|
|
314
|
-
result = await helpers.getKeystore(
|
|
315
|
-
{id: newConfig.id, capabilityAgent});
|
|
316
|
-
} catch(e) {
|
|
317
|
-
err = e;
|
|
318
|
-
}
|
|
319
|
-
should.exist(err);
|
|
320
|
-
should.not.exist(result);
|
|
321
|
-
err.status.should.equal(403);
|
|
322
|
-
err.data.type.should.equal('NotAllowedError');
|
|
323
|
-
|
|
324
|
-
// retrieve the keystore config to confirm update was effective
|
|
325
|
-
err = null;
|
|
326
|
-
result = null;
|
|
327
|
-
try {
|
|
328
|
-
result = await helpers.getKeystore(
|
|
329
|
-
{id: newConfig.id, capabilityAgent: capabilityAgent2});
|
|
330
|
-
} catch(e) {
|
|
331
|
-
err = e;
|
|
332
|
-
}
|
|
333
|
-
assertNoError(err);
|
|
334
|
-
should.exist(result);
|
|
335
|
-
result.should.eql(expectedConfig);
|
|
336
|
-
});
|
|
337
|
-
it('throw operation error when attempting to update "meterId"',
|
|
338
|
-
async () => {
|
|
339
|
-
// TODO: Remove or update this test when the following is fixed
|
|
340
|
-
// eslint-disable-next-line max-len
|
|
341
|
-
// https://github.com/digitalbazaar/bedrock-kms-http/blob/main/lib/http.js#L182
|
|
342
|
-
const secret = '69ae7dc3-1d6d-4ff9-9cc0-c07b43d2006b';
|
|
343
|
-
const handle = 'testKeyUpdate';
|
|
344
|
-
const capabilityAgent = await CapabilityAgent.fromSecret(
|
|
345
|
-
{secret, handle});
|
|
346
|
-
|
|
347
|
-
let err;
|
|
348
|
-
let existingConfig;
|
|
349
|
-
try {
|
|
350
|
-
existingConfig = await helpers.createKeystore(
|
|
351
|
-
{capabilityAgent});
|
|
352
|
-
} catch(e) {
|
|
353
|
-
err = e;
|
|
354
|
-
}
|
|
355
|
-
assertNoError(err);
|
|
356
|
-
should.exist(existingConfig);
|
|
357
|
-
existingConfig.should.have.property('id');
|
|
358
|
-
existingConfig.should.have.property('sequence');
|
|
359
|
-
existingConfig.sequence.should.equal(0);
|
|
360
|
-
const {id: capabilityAgentId} = capabilityAgent;
|
|
361
|
-
existingConfig.should.have.property('controller');
|
|
362
|
-
existingConfig.controller.should.equal(capabilityAgentId);
|
|
363
|
-
|
|
364
|
-
const {id: url} = existingConfig;
|
|
365
|
-
const newConfig = {
|
|
366
|
-
controller: capabilityAgent.id,
|
|
367
|
-
id: url,
|
|
368
|
-
sequence: 1,
|
|
369
|
-
// try updating meterId
|
|
370
|
-
meterId: 'meterId-not-equal-to-meterId-in-existing-config'
|
|
371
|
-
};
|
|
372
|
-
|
|
373
|
-
const zcapClient = new ZcapClient({
|
|
374
|
-
agent,
|
|
375
|
-
invocationSigner: capabilityAgent.getSigner(),
|
|
376
|
-
SuiteClass: Ed25519Signature2020
|
|
377
|
-
});
|
|
378
|
-
err = null;
|
|
379
|
-
let result = null;
|
|
380
|
-
try {
|
|
381
|
-
result = await zcapClient.write({url, json: newConfig});
|
|
382
|
-
} catch(e) {
|
|
383
|
-
err = e;
|
|
384
|
-
}
|
|
385
|
-
should.not.exist(result);
|
|
386
|
-
should.exist(err);
|
|
387
|
-
err.status.should.equal(500);
|
|
388
|
-
err.data.type.should.equal('OperationError');
|
|
389
|
-
});
|
|
390
|
-
it('rejects config update for an invalid zcap', async () => {
|
|
391
|
-
const secret = 'd852a72d-013f-4dd6-8ba2-588aaf601b66';
|
|
392
|
-
const handle = 'testKeyUpdate';
|
|
393
|
-
const capabilityAgent = await CapabilityAgent.fromSecret(
|
|
394
|
-
{secret, handle});
|
|
395
|
-
|
|
396
|
-
const secret2 = '4decd824-50e6-45bf-a79e-41af397f499f';
|
|
397
|
-
const handle2 = 'testKeyUpdate2';
|
|
398
|
-
const capabilityAgent2 = await CapabilityAgent.fromSecret(
|
|
399
|
-
{secret: secret2, handle: handle2});
|
|
400
|
-
|
|
401
|
-
let err;
|
|
402
|
-
let result;
|
|
403
|
-
try {
|
|
404
|
-
result = await helpers.createKeystore({capabilityAgent});
|
|
405
|
-
} catch(e) {
|
|
406
|
-
err = e;
|
|
407
|
-
}
|
|
408
|
-
assertNoError(err);
|
|
409
|
-
should.exist(result);
|
|
410
|
-
result.should.have.property('id');
|
|
411
|
-
result.should.have.property('sequence');
|
|
412
|
-
result.sequence.should.equal(0);
|
|
413
|
-
const {id: capabilityAgentId} = capabilityAgent;
|
|
414
|
-
result.should.have.property('controller');
|
|
415
|
-
result.controller.should.equal(capabilityAgentId);
|
|
416
|
-
|
|
417
|
-
const {id: url} = result;
|
|
418
|
-
const newConfig = {
|
|
419
|
-
controller: capabilityAgent2.id,
|
|
420
|
-
id: url,
|
|
421
|
-
sequence: 1,
|
|
422
|
-
};
|
|
423
|
-
|
|
424
|
-
// the capability invocation here is signed by capabilityAgent2 which
|
|
425
|
-
// is not the controller of the keystore
|
|
426
|
-
const headers = await signCapabilityInvocation({
|
|
427
|
-
url, method: 'post',
|
|
428
|
-
headers: DEFAULT_HEADERS,
|
|
429
|
-
json: newConfig,
|
|
430
|
-
capability: 'urn:zcap:root:' + encodeURIComponent(url),
|
|
431
|
-
invocationSigner: capabilityAgent2.signer,
|
|
432
|
-
capabilityAction: 'write'
|
|
433
|
-
});
|
|
434
|
-
|
|
435
|
-
err = null;
|
|
436
|
-
result = null;
|
|
437
|
-
try {
|
|
438
|
-
result = await httpClient.post(
|
|
439
|
-
url, {agent, headers, json: newConfig});
|
|
440
|
-
} catch(e) {
|
|
441
|
-
err = e;
|
|
442
|
-
}
|
|
443
|
-
should.exist(err);
|
|
444
|
-
should.not.exist(result);
|
|
445
|
-
err.status.should.equal(403);
|
|
446
|
-
err.data.type.should.equal('NotAllowedError');
|
|
447
|
-
err.data.cause.message.should.contain(
|
|
448
|
-
'capability controller does not match');
|
|
449
|
-
});
|
|
450
|
-
|
|
451
|
-
it('rejects config update with an invalid sequence', async () => {
|
|
452
|
-
const secret = 'a8256be9-beea-4b05-9fc2-7ad4c1a391e4';
|
|
453
|
-
const handle = 'testKeyUpdate';
|
|
454
|
-
const capabilityAgent = await CapabilityAgent.fromSecret(
|
|
455
|
-
{secret, handle});
|
|
456
|
-
|
|
457
|
-
const secret2 = 'd2896f13-fed0-4122-b984-326dc29c927a';
|
|
458
|
-
const handle2 = 'testKeyUpdate2';
|
|
459
|
-
const capabilityAgent2 = await CapabilityAgent.fromSecret(
|
|
460
|
-
{secret: secret2, handle: handle2});
|
|
461
|
-
|
|
462
|
-
let err;
|
|
463
|
-
let result;
|
|
464
|
-
try {
|
|
465
|
-
result = await helpers.createKeystore({capabilityAgent});
|
|
466
|
-
} catch(e) {
|
|
467
|
-
err = e;
|
|
468
|
-
}
|
|
469
|
-
assertNoError(err);
|
|
470
|
-
should.exist(result);
|
|
471
|
-
result.should.have.property('id');
|
|
472
|
-
result.should.have.property('sequence');
|
|
473
|
-
result.sequence.should.equal(0);
|
|
474
|
-
const {id: capabilityAgentId} = capabilityAgent;
|
|
475
|
-
result.should.have.property('controller');
|
|
476
|
-
result.controller.should.equal(capabilityAgentId);
|
|
477
|
-
|
|
478
|
-
const {id: url} = result;
|
|
479
|
-
const newConfig = {
|
|
480
|
-
// did:key:z6MknP29cPcQ7G76MWmnsuEEdeFya8ij3fXvJcTJYLXadmp9
|
|
481
|
-
controller: capabilityAgent2.id,
|
|
482
|
-
id: url,
|
|
483
|
-
// the proper sequence would be 1
|
|
484
|
-
sequence: 10,
|
|
485
|
-
};
|
|
486
|
-
|
|
487
|
-
const headers = await signCapabilityInvocation({
|
|
488
|
-
url, method: 'post',
|
|
489
|
-
headers: DEFAULT_HEADERS,
|
|
490
|
-
json: newConfig,
|
|
491
|
-
capability: 'urn:zcap:root:' + encodeURIComponent(url),
|
|
492
|
-
invocationSigner: capabilityAgent.getSigner(),
|
|
493
|
-
capabilityAction: 'write'
|
|
494
|
-
});
|
|
495
|
-
|
|
496
|
-
err = null;
|
|
497
|
-
result = null;
|
|
498
|
-
try {
|
|
499
|
-
result = await httpClient.post(
|
|
500
|
-
url, {agent, headers, json: newConfig});
|
|
501
|
-
} catch(e) {
|
|
502
|
-
err = e;
|
|
503
|
-
}
|
|
504
|
-
should.exist(err);
|
|
505
|
-
should.not.exist(result);
|
|
506
|
-
err.status.should.equal(409);
|
|
507
|
-
err.data.type.should.equal('InvalidStateError');
|
|
508
|
-
err.data.details.should.have.keys(['id', 'sequence', 'httpStatusCode']);
|
|
509
|
-
});
|
|
510
|
-
describe('updates with ipAllowList', () => {
|
|
511
|
-
it('updates a keystore config with ipAllowList', async () => {
|
|
512
|
-
const secret = 'e44c4869-2fd7-4f7f-a123-addb05ec9c2a';
|
|
513
|
-
const handle = 'testKeyUpdate';
|
|
514
|
-
const capabilityAgent = await CapabilityAgent.fromSecret(
|
|
515
|
-
{secret, handle});
|
|
516
|
-
|
|
517
|
-
const secret2 = '82ef7805-21ed-43bb-a604-4ccc7a06eacc';
|
|
518
|
-
const handle2 = 'testKeyUpdate2';
|
|
519
|
-
const capabilityAgent2 = await CapabilityAgent.fromSecret(
|
|
520
|
-
{secret: secret2, handle: handle2});
|
|
521
|
-
|
|
522
|
-
const ipAllowList = ['127.0.0.1/32'];
|
|
523
|
-
|
|
524
|
-
let err;
|
|
525
|
-
let result;
|
|
526
|
-
let existingConfig;
|
|
527
|
-
try {
|
|
528
|
-
existingConfig = result = await helpers.createKeystore(
|
|
529
|
-
{capabilityAgent, ipAllowList});
|
|
530
|
-
} catch(e) {
|
|
531
|
-
err = e;
|
|
532
|
-
}
|
|
533
|
-
assertNoError(err);
|
|
534
|
-
should.exist(result);
|
|
535
|
-
result.should.have.property('id');
|
|
536
|
-
result.should.have.property('sequence');
|
|
537
|
-
result.sequence.should.equal(0);
|
|
538
|
-
const {id: capabilityAgentId} = capabilityAgent;
|
|
539
|
-
result.should.have.property('controller');
|
|
540
|
-
result.controller.should.equal(capabilityAgentId);
|
|
541
|
-
|
|
542
|
-
const {id: url} = result;
|
|
543
|
-
const newConfig = {
|
|
544
|
-
// did:key:z6MknP29cPcQ7G76MWmnsuEEdeFya8ij3fXvJcTJYLXadmp9
|
|
545
|
-
controller: capabilityAgent2.id,
|
|
546
|
-
id: url,
|
|
547
|
-
ipAllowList,
|
|
548
|
-
sequence: 1,
|
|
549
|
-
};
|
|
550
|
-
|
|
551
|
-
const headers = await signCapabilityInvocation({
|
|
552
|
-
url, method: 'post',
|
|
553
|
-
headers: DEFAULT_HEADERS,
|
|
554
|
-
json: newConfig,
|
|
555
|
-
capability: 'urn:zcap:root:' + encodeURIComponent(url),
|
|
556
|
-
invocationSigner: capabilityAgent.getSigner(),
|
|
557
|
-
capabilityAction: 'write'
|
|
558
|
-
});
|
|
559
|
-
|
|
560
|
-
err = null;
|
|
561
|
-
result = null;
|
|
562
|
-
try {
|
|
563
|
-
result = await httpClient.post(
|
|
564
|
-
url, {agent, headers, json: newConfig});
|
|
565
|
-
} catch(e) {
|
|
566
|
-
err = e;
|
|
567
|
-
}
|
|
568
|
-
assertNoError(err);
|
|
569
|
-
should.exist(result.data);
|
|
570
|
-
result.status.should.equal(200);
|
|
571
|
-
result.data.should.have.keys(['config']);
|
|
572
|
-
const expectedConfig = {
|
|
573
|
-
...existingConfig,
|
|
574
|
-
...newConfig
|
|
575
|
-
};
|
|
576
|
-
result.data.config.should.eql(expectedConfig);
|
|
577
|
-
|
|
578
|
-
// should fail to retrieve the keystore config now that controller
|
|
579
|
-
// has changed
|
|
580
|
-
err = null;
|
|
581
|
-
result = null;
|
|
582
|
-
try {
|
|
583
|
-
result = await helpers.getKeystore(
|
|
584
|
-
{id: newConfig.id, capabilityAgent});
|
|
585
|
-
} catch(e) {
|
|
586
|
-
err = e;
|
|
587
|
-
}
|
|
588
|
-
should.exist(err);
|
|
589
|
-
should.not.exist(result);
|
|
590
|
-
err.status.should.equal(403);
|
|
591
|
-
err.data.type.should.equal('NotAllowedError');
|
|
592
|
-
|
|
593
|
-
// retrieve the keystore config to confirm update was effective
|
|
594
|
-
err = null;
|
|
595
|
-
result = null;
|
|
596
|
-
try {
|
|
597
|
-
result = await helpers.getKeystore(
|
|
598
|
-
{id: newConfig.id, capabilityAgent: capabilityAgent2});
|
|
599
|
-
} catch(e) {
|
|
600
|
-
err = e;
|
|
601
|
-
}
|
|
602
|
-
assertNoError(err);
|
|
603
|
-
should.exist(result);
|
|
604
|
-
result.should.eql(expectedConfig);
|
|
605
|
-
});
|
|
606
|
-
it('returns NotAllowedError for invalid source IP', async () => {
|
|
607
|
-
const secret = '481f41a0-af87-407f-b7ec-38f1fbb10d12';
|
|
608
|
-
const handle = 'testKeyUpdate';
|
|
609
|
-
const capabilityAgent = await CapabilityAgent.fromSecret(
|
|
610
|
-
{secret, handle});
|
|
611
|
-
|
|
612
|
-
const secret2 = 'ddbbbc38-eb27-4238-8b84-382ada29b8c0';
|
|
613
|
-
const handle2 = 'testKeyUpdate2';
|
|
614
|
-
const capabilityAgent2 = await CapabilityAgent.fromSecret(
|
|
615
|
-
{secret: secret2, handle: handle2});
|
|
616
|
-
|
|
617
|
-
const ipAllowList = ['8.8.8.8/32'];
|
|
618
|
-
|
|
619
|
-
let err;
|
|
620
|
-
let result;
|
|
621
|
-
try {
|
|
622
|
-
result = await helpers.createKeystore(
|
|
623
|
-
{capabilityAgent, ipAllowList});
|
|
624
|
-
} catch(e) {
|
|
625
|
-
err = e;
|
|
626
|
-
}
|
|
627
|
-
assertNoError(err);
|
|
628
|
-
should.exist(result);
|
|
629
|
-
result.should.have.property('id');
|
|
630
|
-
result.should.have.property('sequence');
|
|
631
|
-
result.sequence.should.equal(0);
|
|
632
|
-
const {id: capabilityAgentId} = capabilityAgent;
|
|
633
|
-
result.should.have.property('controller');
|
|
634
|
-
result.controller.should.equal(capabilityAgentId);
|
|
635
|
-
|
|
636
|
-
const {id: url} = result;
|
|
637
|
-
const newConfig = {
|
|
638
|
-
// did:key:z6MknP29cPcQ7G76MWmnsuEEdeFya8ij3fXvJcTJYLXadmp9
|
|
639
|
-
controller: capabilityAgent2.id,
|
|
640
|
-
id: url,
|
|
641
|
-
ipAllowList,
|
|
642
|
-
sequence: 1,
|
|
643
|
-
};
|
|
644
|
-
|
|
645
|
-
const headers = await signCapabilityInvocation({
|
|
646
|
-
url, method: 'post',
|
|
647
|
-
headers: DEFAULT_HEADERS,
|
|
648
|
-
json: newConfig,
|
|
649
|
-
capability: 'urn:zcap:root:' + encodeURIComponent(url),
|
|
650
|
-
invocationSigner: capabilityAgent.getSigner(),
|
|
651
|
-
capabilityAction: 'write'
|
|
652
|
-
});
|
|
653
|
-
|
|
654
|
-
err = null;
|
|
655
|
-
result = null;
|
|
656
|
-
try {
|
|
657
|
-
result = await httpClient.post(
|
|
658
|
-
url, {agent, headers, json: newConfig});
|
|
659
|
-
} catch(e) {
|
|
660
|
-
err = e;
|
|
661
|
-
}
|
|
662
|
-
should.not.exist(result);
|
|
663
|
-
should.exist(err);
|
|
664
|
-
err.status.should.equal(403);
|
|
665
|
-
err.data.type.should.equal('NotAllowedError');
|
|
666
|
-
});
|
|
667
|
-
}); // updates with ipAllowList
|
|
668
|
-
}); // end update keystore config
|
|
669
|
-
});
|
|
670
|
-
});
|