@adobe/helix-config-storage 1.3.2 → 1.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 CHANGED
@@ -1,3 +1,17 @@
1
+ # [1.5.0](https://github.com/adobe/helix-config-storage/compare/v1.4.0...v1.5.0) (2024-09-02)
2
+
3
+
4
+ ### Features
5
+
6
+ * restructure transient-site-tokens ([#15](https://github.com/adobe/helix-config-storage/issues/15)) ([bec495c](https://github.com/adobe/helix-config-storage/commit/bec495cf3b594d38f0f2586fc3addba457be684f))
7
+
8
+ # [1.4.0](https://github.com/adobe/helix-config-storage/compare/v1.3.2...v1.4.0) (2024-08-31)
9
+
10
+
11
+ ### Features
12
+
13
+ * allow adding several users ([cc0722d](https://github.com/adobe/helix-config-storage/commit/cc0722d35b7dc75e78926922c9e9b1a55bbc8377))
14
+
1
15
  ## [1.3.2](https://github.com/adobe/helix-config-storage/compare/v1.3.1...v1.3.2) (2024-08-31)
2
16
 
3
17
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adobe/helix-config-storage",
3
- "version": "1.3.2",
3
+ "version": "1.5.0",
4
4
  "description": "Helix Config Storage",
5
5
  "main": "src/index.js",
6
6
  "types": "src/index.d.ts",
@@ -68,6 +68,13 @@ const FRAGMENTS = {
68
68
  },
69
69
  profiles: FRAGMENTS_COMMON,
70
70
  org: {
71
+ tokens: {
72
+ '.': 'tokens',
73
+ '.param': {
74
+ name: 'id',
75
+ '.': 'token',
76
+ },
77
+ },
71
78
  users: {
72
79
  '.': 'users',
73
80
  '.param': {
@@ -353,17 +360,28 @@ export class ConfigStore {
353
360
  // don't expose hash in return value
354
361
  delete ret.hash;
355
362
  } else if (frag.type === 'users') {
356
- const user = createUser();
357
- data = {
358
- ...data,
359
- ...user,
360
- };
361
- relPath = ['users', user.id];
362
- frag.type = 'user';
363
363
  // todo: define via "schema"
364
364
  if (!old.users) {
365
365
  old.users = [];
366
366
  }
367
+ if (Array.isArray(data)) {
368
+ const users = [...old.users];
369
+ for (const userData of data) {
370
+ users.push({
371
+ ...createUser(),
372
+ ...userData,
373
+ });
374
+ }
375
+ data = users;
376
+ } else {
377
+ const user = createUser();
378
+ data = {
379
+ ...data,
380
+ ...user,
381
+ };
382
+ relPath = ['users', user.id];
383
+ frag.type = 'user';
384
+ }
367
385
  } else if (frag.type === 'user') {
368
386
  const user = deepGetOrCreate(old, relPath);
369
387
  if (!user) {
@@ -17,6 +17,9 @@
17
17
  },
18
18
  "groups": {
19
19
  "$ref": "https://ns.adobe.com/helix/config/groups"
20
+ },
21
+ "tokens": {
22
+ "$ref": "https://ns.adobe.com/helix/config/tokens"
20
23
  }
21
24
  },
22
25
  "required": [
@@ -14,9 +14,7 @@
14
14
  * @typedef Token
15
15
  * @property {string} id
16
16
  * @property {string} value
17
- * @property {string} hash
18
17
  * @property {Date} created
19
- * @property {Date} expires
20
18
  */
21
19
 
22
20
  /**
@@ -25,20 +23,8 @@
25
23
  * @property {Token} live
26
24
  */
27
25
 
28
- /**
29
- * @typedef SiteTokensData
30
- * @property {Token[]} preview
31
- * @property {Token[]} live
32
- */
33
-
26
+ import crypto from 'crypto';
34
27
  import { HelixStorage } from '@adobe/helix-shared-storage';
35
- import { createToken } from './utils.js';
36
-
37
- /**
38
- * Default expiry time for transient site tokens (24 hours)
39
- * @type {number}
40
- */
41
- const DEFAULT_EXPIRY_TIME = 24 * 60 * 60 * 1000;
42
28
 
43
29
  /**
44
30
  * Store to manage transient site tokens.
@@ -80,12 +66,12 @@ export class TransientTokenStore {
80
66
  this.org = org;
81
67
  this.site = site;
82
68
  this.#key = `orgs/${this.org}/sites/${this.site}/transient-site-tokens.json`;
83
- this.#now = Date.now();
69
+ this.#now = new Date();
84
70
  }
85
71
 
86
72
  /**
87
73
  * Returns the current time (mainly used for tests)
88
- * @returns {number}
74
+ * @returns {Date}
89
75
  */
90
76
  now() {
91
77
  return this.#now;
@@ -94,22 +80,21 @@ export class TransientTokenStore {
94
80
  /**
95
81
  * Loads the transient site tokens from the storage
96
82
  * @param ctx
97
- * @returns {Promise<SiteTokensData>}
83
+ * @returns {Promise<SiteTokens>}
98
84
  */
99
85
  async #load(ctx) {
100
86
  if (!this.#tokens) {
101
87
  this.#tokens = {
102
- preview: [],
103
- live: [],
88
+ preview: undefined,
89
+ live: undefined,
104
90
  };
105
91
  this.#modified = false;
106
92
  const storage = HelixStorage.fromContext(ctx).configBus();
107
93
  const buf = await storage.get(this.#key);
108
94
  if (buf) {
109
95
  const data = JSON.parse(buf.toString('utf-8'));
110
- const isValid = (t) => Date.parse(t.expires) > this.#now;
111
- this.#tokens.preview = data.tokens.preview.filter(isValid);
112
- this.#tokens.live = data.tokens.live.filter(isValid);
96
+ this.#tokens.preview = data.tokens.preview;
97
+ this.#tokens.live = data.tokens.live;
113
98
  }
114
99
  }
115
100
  return this.#tokens;
@@ -140,12 +125,17 @@ export class TransientTokenStore {
140
125
  throw new Error(`Invalid partition: ${partition}`);
141
126
  }
142
127
  const tokens = await this.#load(ctx);
143
- let token = tokens[partition][0];
128
+ let token = tokens[partition];
144
129
  if (!token) {
145
- token = createToken(this.org, 'hlxtst');
146
- token.created = new Date(this.#now).toUTCString();
147
- token.expires = new Date(this.#now + DEFAULT_EXPIRY_TIME).toUTCString();
148
- tokens[partition].push(token);
130
+ const value = crypto.randomBytes(32).toString('base64url');
131
+ const id = crypto.createHash('sha256').update(value).digest().toString('base64url');
132
+ const created = this.#now.toUTCString();
133
+ token = {
134
+ id,
135
+ value,
136
+ created,
137
+ };
138
+ tokens[partition] = token;
149
139
  this.#modified = true;
150
140
  }
151
141
  await this.#save(ctx);
@@ -153,15 +143,31 @@ export class TransientTokenStore {
153
143
  }
154
144
 
155
145
  /**
156
- * Returns the transient site tokens for the given context
146
+ * Returns the token header values for the given user id.
147
+ * @param ctx
148
+ * @param partition
149
+ * @param userid
150
+ * @returns {Promise<string>}
151
+ */
152
+ async getTokenHeader(ctx, partition, userid) {
153
+ const token = await this.getOrCreateToken(ctx, partition);
154
+ const user64 = Buffer.from(userid)
155
+ .toString('base64url');
156
+ const key = `${user64};${this.#now.toISOString().split('T')[0]}`;
157
+ const hash = crypto
158
+ .createHmac('sha512', key)
159
+ .update(token.value, 'utf-8')
160
+ .digest()
161
+ .toString('base64url');
162
+ return `hlxtst_${hash};${user64}`;
163
+ }
164
+
165
+ /**
166
+ * Returns the transient site tokens
157
167
  * @param ctx
158
168
  * @returns {Promise<SiteTokens>}
159
169
  */
160
170
  async getSiteTokens(ctx) {
161
- const tokens = await this.#load(ctx);
162
- return {
163
- preview: tokens.preview[0],
164
- live: tokens.live[0],
165
- };
171
+ return this.#load(ctx);
166
172
  }
167
173
  }
@@ -26,6 +26,7 @@ export interface HelixOrgConfig {
26
26
  description?: string;
27
27
  users?: Users;
28
28
  groups?: Groups;
29
+ tokens?: Tokens;
29
30
  }
30
31
  export interface User {
31
32
  id: string;
@@ -49,3 +50,14 @@ export interface Group {
49
50
  [k: string]: unknown;
50
51
  }[];
51
52
  }
53
+ export interface Tokens {
54
+ /**
55
+ * This interface was referenced by `Tokens`'s JSON-Schema definition
56
+ * via the `patternProperty` "^[a-zA-Z0-9-_=]+$".
57
+ */
58
+ [k: string]: {
59
+ id?: string;
60
+ hash?: string;
61
+ created?: string;
62
+ };
63
+ }
@@ -49,6 +49,7 @@ export interface ContentSource {
49
49
  description?: string;
50
50
  contentBusId: string;
51
51
  source: GoogleContentSource | OnedriveContentSource | MarkupContentSource;
52
+ overlay?: MarkupContentSource;
52
53
  }
53
54
  export interface GoogleContentSource {
54
55
  type: 'google';
@@ -56,6 +56,7 @@ export interface ContentSource {
56
56
  description?: string;
57
57
  contentBusId: string;
58
58
  source: GoogleContentSource | OnedriveContentSource | MarkupContentSource;
59
+ overlay?: MarkupContentSource;
59
60
  }
60
61
  export interface GoogleContentSource {
61
62
  type: 'google';
@@ -21,8 +21,8 @@ npx ajv-cli --spec=draft2019 -c ajv-formats compile \
21
21
  -s src/schemas/metadata-source.schema.json \
22
22
  -s src/schemas/user.schema.json \
23
23
  -s src/schemas/users.schema.json \
24
- -s src/schemas/org.schema.json \
25
24
  -s src/schemas/tokens.schema.json \
25
+ -s src/schemas/org.schema.json \
26
26
  -s src/schemas/sidekick.schema.json \
27
27
  -s src/schemas/robots.schema.json \
28
28
  -s src/schemas/public.schema.json \