@bedrock/kms-http 13.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.
@@ -0,0 +1,670 @@
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 'module';
8
+ import {mockData} from './mock.data.js';
9
+ const require = createRequire(import.meta.url);
10
+ const {CapabilityAgent} = require('@digitalbazaar/webkms-client');
11
+ const {httpClient, DEFAULT_HEADERS} = require('@digitalbazaar/http-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 internal server 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('bedrock.InternalServerError');
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
+ });