@bedrock/kms-http 14.3.0 → 14.5.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/CHANGELOG.md +19 -0
- package/lib/http.js +3 -1
- package/lib/middleware.js +13 -7
- package/package.json +3 -3
- package/test/mocha/11-keystore-kms-client.js +71 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# bedrock-kms-http ChangeLog
|
|
2
2
|
|
|
3
|
+
## 14.5.0 - 2022-06-19
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
- Use `@bedrock/kms@10.3`.
|
|
7
|
+
- Use `@digitalbazaar/webkms-switch@10.3`.
|
|
8
|
+
|
|
9
|
+
## 14.4.0 - 2022-05-19
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
- Add max age header for CORS, defaulting to the max acceptable time for
|
|
13
|
+
modern browsers of 86400 seconds (24 hours).
|
|
14
|
+
|
|
15
|
+
## 14.3.1 - 2022-05-16
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
- Use `@digitalbazaar/webkms-switch@10.2` to ensure that pre-cached `webkms`
|
|
19
|
+
request meta data is not overwritten and that a custom `getRootController`
|
|
20
|
+
function is used (to enable cache busting on KMS operations).
|
|
21
|
+
|
|
3
22
|
## 14.3.0 - 2022-05-16
|
|
4
23
|
|
|
5
24
|
### Added
|
package/lib/http.js
CHANGED
|
@@ -6,7 +6,6 @@ import * as brZCapStorage from '@bedrock/zcap-storage';
|
|
|
6
6
|
import * as helpers from './helpers.js';
|
|
7
7
|
import * as middleware from './middleware.js';
|
|
8
8
|
import {asyncHandler} from '@bedrock/express';
|
|
9
|
-
import cors from 'cors';
|
|
10
9
|
import {createRequire} from 'node:module';
|
|
11
10
|
import {createValidateMiddleware as validate} from '@bedrock/validation';
|
|
12
11
|
import {
|
|
@@ -24,6 +23,7 @@ const require = createRequire(import.meta.url);
|
|
|
24
23
|
const {generateRandom} = require('@digitalbazaar/webkms-switch');
|
|
25
24
|
|
|
26
25
|
const {config, util: {BedrockError}} = bedrock;
|
|
26
|
+
const {cors} = middleware;
|
|
27
27
|
|
|
28
28
|
bedrock.events.on('bedrock-express.configure.routes', app => {
|
|
29
29
|
const cfg = config['kms-http'];
|
|
@@ -191,6 +191,7 @@ bedrock.events.on('bedrock-express.configure.routes', app => {
|
|
|
191
191
|
app.post(
|
|
192
192
|
routes.keys,
|
|
193
193
|
cors(),
|
|
194
|
+
getKeystoreConfig,
|
|
194
195
|
handleOperation);
|
|
195
196
|
|
|
196
197
|
// invoke KMS operation on an existing key
|
|
@@ -198,6 +199,7 @@ bedrock.events.on('bedrock-express.configure.routes', app => {
|
|
|
198
199
|
app.post(
|
|
199
200
|
routes.key,
|
|
200
201
|
cors(),
|
|
202
|
+
getKeystoreConfig,
|
|
201
203
|
handleOperation);
|
|
202
204
|
|
|
203
205
|
// TODO: consider whether this should be exposed w/o authorization
|
package/lib/middleware.js
CHANGED
|
@@ -7,6 +7,7 @@ import * as helpers from './helpers.js';
|
|
|
7
7
|
import {asyncHandler} from '@bedrock/express';
|
|
8
8
|
import {BedrockKeystoreConfigStorage} from './BedrockKeystoreConfigStorage.js';
|
|
9
9
|
import {createRequire} from 'node:module';
|
|
10
|
+
import {default as _cors} from 'cors';
|
|
10
11
|
import {
|
|
11
12
|
defaultDocumentLoader as documentLoader,
|
|
12
13
|
defaultModuleManager as moduleManager
|
|
@@ -46,7 +47,7 @@ export function createGetKeystoreConfig({routes}) {
|
|
|
46
47
|
id: keystoreId, req, returnRecord: true
|
|
47
48
|
});
|
|
48
49
|
const {config: keystore} = configRecord;
|
|
49
|
-
req.webkms = {keystore, configRecord};
|
|
50
|
+
req.webkms = {...req.webkms, keystore, configRecord};
|
|
50
51
|
}
|
|
51
52
|
next();
|
|
52
53
|
});
|
|
@@ -58,7 +59,10 @@ export function createKmsOperationMiddleware() {
|
|
|
58
59
|
return createOperationMiddleware({
|
|
59
60
|
...kmsOperationOptions,
|
|
60
61
|
storage, moduleManager, documentLoader,
|
|
61
|
-
expectedHost: config.server.host,
|
|
62
|
+
expectedHost: config.server.host,
|
|
63
|
+
// override `getRootController` to provide cache busting capability
|
|
64
|
+
getRootController: getKeystoreController,
|
|
65
|
+
getVerifier,
|
|
62
66
|
inspectCapabilityChain,
|
|
63
67
|
onError, onSuccess: reportOperationUsage, suiteFactory
|
|
64
68
|
});
|
|
@@ -104,6 +108,11 @@ export function authorizeZcapRevocation() {
|
|
|
104
108
|
});
|
|
105
109
|
}
|
|
106
110
|
|
|
111
|
+
export function cors() {
|
|
112
|
+
// `86400` is the max acceptable cache age for modern browsers
|
|
113
|
+
return _cors({maxAge: 86400});
|
|
114
|
+
}
|
|
115
|
+
|
|
107
116
|
async function getKeystoreController({req}) {
|
|
108
117
|
/* The following code is to prevent false-negative authz errors that are the
|
|
109
118
|
result of stale cached keystore configs.
|
|
@@ -185,7 +194,7 @@ async function getKeystoreController({req}) {
|
|
|
185
194
|
id: req.webkms.keystore.id, req, returnRecord: true, fresh: true
|
|
186
195
|
});
|
|
187
196
|
const {config: keystore} = configRecord;
|
|
188
|
-
req.webkms = {keystore, configRecord};
|
|
197
|
+
req.webkms = {...req.webkms, keystore, configRecord};
|
|
189
198
|
logger.debug('Forced fresh keystore config retrieval during zcap check.');
|
|
190
199
|
}
|
|
191
200
|
|
|
@@ -243,10 +252,7 @@ function onError({error}) {
|
|
|
243
252
|
if(!(error instanceof BedrockError)) {
|
|
244
253
|
// always expose cause message and name; expose cause details as
|
|
245
254
|
// BedrockError if error is marked public
|
|
246
|
-
|
|
247
|
-
if(error.details && error.details.public) {
|
|
248
|
-
details = error.details;
|
|
249
|
-
}
|
|
255
|
+
const details = error.details?.public ? error.details : {};
|
|
250
256
|
error = new BedrockError(
|
|
251
257
|
error.message,
|
|
252
258
|
error.name || 'NotAllowedError', {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bedrock/kms-http",
|
|
3
|
-
"version": "14.
|
|
3
|
+
"version": "14.5.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Bedrock KMS HTTP API",
|
|
6
6
|
"main": "./lib/index.js",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"@digitalbazaar/ed25519-signature-2020": "^3.0.0",
|
|
28
28
|
"@digitalbazaar/ed25519-verification-key-2020": "^3.2.0",
|
|
29
29
|
"@digitalbazaar/ezcap-express": "^6.2.0",
|
|
30
|
-
"@digitalbazaar/webkms-switch": "^10.
|
|
30
|
+
"@digitalbazaar/webkms-switch": "^10.3.0",
|
|
31
31
|
"cidr-regex": "^3.1.1",
|
|
32
32
|
"cors": "^2.8.5",
|
|
33
33
|
"crypto-ld": "^6.0.0",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"@bedrock/app-identity": "^3.0.0",
|
|
39
39
|
"@bedrock/core": "^6.0.0",
|
|
40
40
|
"@bedrock/express": "^8.0.0",
|
|
41
|
-
"@bedrock/kms": "^10.
|
|
41
|
+
"@bedrock/kms": "^10.3.0",
|
|
42
42
|
"@bedrock/meter-usage-reporter": "^7.0.0",
|
|
43
43
|
"@bedrock/validation": "^7.0.0",
|
|
44
44
|
"@bedrock/zcap-storage": "^7.0.0"
|
|
@@ -67,7 +67,7 @@ describe('keystore API interactions using webkms-client', () => {
|
|
|
67
67
|
bobKeystoreAgent.keystoreId);
|
|
68
68
|
});
|
|
69
69
|
|
|
70
|
-
it('updates config
|
|
70
|
+
it('updates config and uses key proving cache busting', async () => {
|
|
71
71
|
const keystoreId = aliceKeystoreConfig.id;
|
|
72
72
|
const kmsClient = new KmsClient({httpsAgent});
|
|
73
73
|
|
|
@@ -88,6 +88,9 @@ describe('keystore API interactions using webkms-client', () => {
|
|
|
88
88
|
const agent3KeystoreAgent = new KeystoreAgent(
|
|
89
89
|
{capabilityAgent: agent3, keystoreId, kmsClient});
|
|
90
90
|
|
|
91
|
+
// generate a key for use
|
|
92
|
+
const hmacKey = await aliceKeystoreAgent.generateKey({type: 'hmac'});
|
|
93
|
+
|
|
91
94
|
// delegate zcap for updating config from agent2 to agent3 to test
|
|
92
95
|
// cache busting with delegated zcap
|
|
93
96
|
const rootCapability = ZCAP_ROOT_PREFIX + encodeURIComponent(keystoreId);
|
|
@@ -120,7 +123,7 @@ describe('keystore API interactions using webkms-client', () => {
|
|
|
120
123
|
// disable cache delete functionality on update
|
|
121
124
|
keystores._disableClearCacheOnUpdate(true);
|
|
122
125
|
|
|
123
|
-
// update controller alice => agent1 (no cache busting required
|
|
126
|
+
// update controller alice => agent1 (no cache busting required)
|
|
124
127
|
{
|
|
125
128
|
config.sequence++;
|
|
126
129
|
config.controller = agent1.id;
|
|
@@ -164,6 +167,72 @@ describe('keystore API interactions using webkms-client', () => {
|
|
|
164
167
|
result.config.controller.should.eql(agent1.id);
|
|
165
168
|
({config} = result);
|
|
166
169
|
}
|
|
170
|
+
|
|
171
|
+
// update controller back to alice to test key op cache busting
|
|
172
|
+
{
|
|
173
|
+
config.sequence++;
|
|
174
|
+
config.controller = aliceCapabilityAgent.id;
|
|
175
|
+
const result = await agent1KeystoreAgent.updateConfig({config});
|
|
176
|
+
result.config.id.should.eql(config.id);
|
|
177
|
+
result.config.controller.should.eql(aliceCapabilityAgent.id);
|
|
178
|
+
({config} = result);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// use hmac key as alice (requires cache busting by inspecting root
|
|
182
|
+
// zcap)
|
|
183
|
+
await hmacKey.sign({data: new Uint8Array([0])});
|
|
184
|
+
|
|
185
|
+
// update controller alice => agent1 (no cache busting required)
|
|
186
|
+
{
|
|
187
|
+
config.sequence++;
|
|
188
|
+
config.controller = agent1.id;
|
|
189
|
+
const result = await aliceKeystoreAgent.updateConfig({config});
|
|
190
|
+
result.config.id.should.eql(config.id);
|
|
191
|
+
result.config.controller.should.eql(agent1.id);
|
|
192
|
+
({config} = result);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// use hmac key as agent1 (requires cache busting by
|
|
196
|
+
// inspecting the root zcap)
|
|
197
|
+
hmacKey.invocationSigner = agent1.getSigner();
|
|
198
|
+
// use different data each time to avoid hmac caching
|
|
199
|
+
await hmacKey.sign({data: new Uint8Array([1])});
|
|
200
|
+
|
|
201
|
+
// update controller agent1 => agent2 (requires cache busting by
|
|
202
|
+
// inspecting the root zcap)
|
|
203
|
+
{
|
|
204
|
+
config.sequence++;
|
|
205
|
+
config.controller = agent2.id;
|
|
206
|
+
const result = await agent1KeystoreAgent.updateConfig({config});
|
|
207
|
+
result.config.id.should.eql(config.id);
|
|
208
|
+
result.config.controller.should.eql(agent2.id);
|
|
209
|
+
({config} = result);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// use hmac key as agent3 (requires cache busting by
|
|
213
|
+
// inspecting a delegated zcap)
|
|
214
|
+
hmacKey.capability = agent3Zcap;
|
|
215
|
+
hmacKey.invocationSigner = agent3.getSigner();
|
|
216
|
+
// use different data each time to avoid hmac caching
|
|
217
|
+
await hmacKey.sign({data: new Uint8Array([1])});
|
|
218
|
+
|
|
219
|
+
// update controller agent2 => agent3 (cache should already be fresh)
|
|
220
|
+
{
|
|
221
|
+
config.sequence++;
|
|
222
|
+
config.controller = agent3.id;
|
|
223
|
+
const result = await agent3KeystoreAgent.updateConfig(
|
|
224
|
+
{capability: agent3Zcap, config});
|
|
225
|
+
result.config.id.should.eql(config.id);
|
|
226
|
+
result.config.controller.should.eql(agent3.id);
|
|
227
|
+
({config} = result);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// use hmac key as agent1 (requires cache busting by
|
|
231
|
+
// inspecting a deep delegated zcap)
|
|
232
|
+
hmacKey.capability = agent1Zcap;
|
|
233
|
+
hmacKey.invocationSigner = agent1.getSigner();
|
|
234
|
+
// use different data each time to avoid hmac caching
|
|
235
|
+
await hmacKey.sign({data: new Uint8Array([1])});
|
|
167
236
|
} catch(e) {
|
|
168
237
|
assertNoError(e);
|
|
169
238
|
} finally {
|