@adobe/helix-config 2.9.0 → 2.10.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/.husky/pre-commit +1 -0
- package/CHANGELOG.md +7 -0
- package/package.json +3 -2
- package/src/config-view.js +5 -1
- package/src/storage/config-store.js +11 -3
- package/src/storage/utils.js +37 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
npx lint-staged
|
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
# [2.10.0](https://github.com/adobe/helix-config/compare/v2.9.0...v2.10.0) (2024-04-26)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* add support to migrate jwt api keys ([#59](https://github.com/adobe/helix-config/issues/59)) ([04adf04](https://github.com/adobe/helix-config/commit/04adf04c975ee38840a56f81aac8a1609959298a))
|
|
7
|
+
|
|
1
8
|
# [2.9.0](https://github.com/adobe/helix-config/compare/v2.8.0...v2.9.0) (2024-04-25)
|
|
2
9
|
|
|
3
10
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adobe/helix-config",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.10.0",
|
|
4
4
|
"description": "Helix Config",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"types": "src/index.d.ts",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"docs:types": "node ./test/dev/generate-types.js",
|
|
16
16
|
"semantic-release": "semantic-release",
|
|
17
17
|
"semantic-release-dry": "semantic-release --dry-run --branches $CI_BRANCH",
|
|
18
|
-
"prepare": "husky
|
|
18
|
+
"prepare": "husky"
|
|
19
19
|
},
|
|
20
20
|
"repository": {
|
|
21
21
|
"type": "git",
|
|
@@ -68,6 +68,7 @@
|
|
|
68
68
|
"@smithy/node-http-handler": "2.5.0",
|
|
69
69
|
"ajv": "8.12.0",
|
|
70
70
|
"ajv-formats": "3.0.1",
|
|
71
|
+
"jose": "5.2.4",
|
|
71
72
|
"mime": "4.0.1"
|
|
72
73
|
}
|
|
73
74
|
}
|
package/src/config-view.js
CHANGED
|
@@ -78,7 +78,11 @@ export function getAccessConfig(config, partition) {
|
|
|
78
78
|
const cfg = {
|
|
79
79
|
allow: toArray(access[partition]?.allow ?? access.allow),
|
|
80
80
|
apiKeyId,
|
|
81
|
-
tokenHash: apiKeyId
|
|
81
|
+
tokenHash: apiKeyId
|
|
82
|
+
// token ids are always stored in base64url format, but legacy apiKeyIds are not
|
|
83
|
+
.map((jti) => jti.replaceAll('/', '_').replaceAll('+', '-'))
|
|
84
|
+
.map((id) => tokens[id]?.hash)
|
|
85
|
+
.filter((hash) => !!hash),
|
|
82
86
|
clientCertDN: toArray(access[partition]?.clientCertDN ?? access.clientCertDN),
|
|
83
87
|
};
|
|
84
88
|
// if an allow is defined but no apiKeyId, create a fake one so that auth is still
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
createToken,
|
|
17
17
|
jsonGet,
|
|
18
18
|
jsonPut,
|
|
19
|
+
migrateToken,
|
|
19
20
|
updateCodeSource,
|
|
20
21
|
updateContentSource,
|
|
21
22
|
} from './utils.js';
|
|
@@ -198,14 +199,21 @@ export class ConfigStore {
|
|
|
198
199
|
// don't allow to update individual token
|
|
199
200
|
throw new StatusCodeError(400, 'invalid object path.');
|
|
200
201
|
} else if (frag.type === 'tokens') {
|
|
201
|
-
//
|
|
202
|
-
|
|
202
|
+
// TODO: remove support after all helix4 projects are migrated
|
|
203
|
+
let token;
|
|
204
|
+
if (data.jwt) {
|
|
205
|
+
token = await migrateToken(this.org, data.jwt);
|
|
206
|
+
} else {
|
|
207
|
+
// create new token
|
|
208
|
+
token = createToken(this.org);
|
|
209
|
+
}
|
|
210
|
+
|
|
203
211
|
data = {
|
|
204
212
|
...token,
|
|
205
213
|
};
|
|
206
214
|
// don't store token value in the config
|
|
207
215
|
delete data.value;
|
|
208
|
-
relPath =
|
|
216
|
+
relPath = ['tokens', token.id];
|
|
209
217
|
frag.type = 'token';
|
|
210
218
|
ret = token;
|
|
211
219
|
// don't expose hash in return value
|
package/src/storage/utils.js
CHANGED
|
@@ -12,13 +12,15 @@
|
|
|
12
12
|
/* eslint-disable no-param-reassign */
|
|
13
13
|
import crypto from 'crypto';
|
|
14
14
|
import { GitUrl } from '@adobe/helix-shared-git';
|
|
15
|
+
import { decodeJwt } from 'jose';
|
|
16
|
+
import { StatusCodeError } from './status-code-error.js';
|
|
15
17
|
|
|
16
18
|
export function jsonGet(obj, path) {
|
|
17
19
|
return path.split('/').reduce((o, p) => o[p], obj);
|
|
18
20
|
}
|
|
19
21
|
|
|
20
22
|
export function jsonPut(obj, path, value) {
|
|
21
|
-
const parts = path.split('/');
|
|
23
|
+
const parts = Array.isArray(path) ? path : path.split('/');
|
|
22
24
|
const last = parts.pop();
|
|
23
25
|
const parent = parts.reduce((o, p) => {
|
|
24
26
|
if (!(p in o)) {
|
|
@@ -134,3 +136,37 @@ export function createToken(key) {
|
|
|
134
136
|
created,
|
|
135
137
|
};
|
|
136
138
|
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* migrates an existing jwt token
|
|
142
|
+
* @param key
|
|
143
|
+
* @param jwt
|
|
144
|
+
* @returns {Promise<object>}
|
|
145
|
+
*/
|
|
146
|
+
export async function migrateToken(key, jwt) {
|
|
147
|
+
let payload;
|
|
148
|
+
try {
|
|
149
|
+
payload = await decodeJwt(jwt);
|
|
150
|
+
} catch (e) {
|
|
151
|
+
throw new StatusCodeError(400, `unable to migrate jwt: ${e.message}`);
|
|
152
|
+
}
|
|
153
|
+
const { jti } = payload;
|
|
154
|
+
if (!jti) {
|
|
155
|
+
throw new StatusCodeError(400, 'unable to migrate jwt: missing jti claim.');
|
|
156
|
+
}
|
|
157
|
+
const id = jti
|
|
158
|
+
.replaceAll('/', '_')
|
|
159
|
+
.replaceAll('+', '-');
|
|
160
|
+
const hash = crypto
|
|
161
|
+
.createHmac('sha512', key)
|
|
162
|
+
.update(jwt, 'utf-8')
|
|
163
|
+
.digest()
|
|
164
|
+
.toString('base64url');
|
|
165
|
+
const created = new Date().toISOString();
|
|
166
|
+
return {
|
|
167
|
+
id,
|
|
168
|
+
value: jwt,
|
|
169
|
+
hash,
|
|
170
|
+
created,
|
|
171
|
+
};
|
|
172
|
+
}
|