@scayle/h3-session 0.5.0 → 0.6.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 +13 -0
- package/dist/index.mjs +53 -23
- package/package.json +11 -10
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# @scayle/h3-session
|
|
2
2
|
|
|
3
|
+
## 0.6.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [Performance] Reduce the calls to `importKey` to improve performance.
|
|
8
|
+
|
|
9
|
+
## 0.5.1
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- When a sessionID exists, but there is no session data, re-use the sessionID instead of generating both new data and a new ID. This enables proper functioning of the `saveUnitialized` configuration.
|
|
14
|
+
- Fix the `clear()` method on `UnstorageSessionStore` not clearing sessions
|
|
15
|
+
|
|
3
16
|
## 0.5.0
|
|
4
17
|
|
|
5
18
|
### Minor Changes
|
package/dist/index.mjs
CHANGED
|
@@ -3,6 +3,41 @@ import { getCookie, setCookie } from 'h3';
|
|
|
3
3
|
import { defu } from 'defu';
|
|
4
4
|
import { subtle, randomUUID } from 'uncrypto';
|
|
5
5
|
|
|
6
|
+
const _signKeys = {};
|
|
7
|
+
async function getCryptoSignKey(secret) {
|
|
8
|
+
if (_signKeys[secret]) {
|
|
9
|
+
return _signKeys[secret];
|
|
10
|
+
}
|
|
11
|
+
const encoder = new TextEncoder();
|
|
12
|
+
const keyUint8Array = encoder.encode(secret);
|
|
13
|
+
const cryptoKey = await subtle.importKey(
|
|
14
|
+
"raw",
|
|
15
|
+
keyUint8Array,
|
|
16
|
+
{ name: "HMAC", hash: "SHA-256" },
|
|
17
|
+
false,
|
|
18
|
+
["sign"]
|
|
19
|
+
);
|
|
20
|
+
_signKeys[secret] = cryptoKey;
|
|
21
|
+
return cryptoKey;
|
|
22
|
+
}
|
|
23
|
+
const _verifyKeys = {};
|
|
24
|
+
async function getCryptoVerifyKey(secret) {
|
|
25
|
+
if (_verifyKeys[secret]) {
|
|
26
|
+
return _verifyKeys[secret];
|
|
27
|
+
}
|
|
28
|
+
const encoder = new TextEncoder();
|
|
29
|
+
const keyUint8Array = encoder.encode(secret);
|
|
30
|
+
const cryptoKey = await subtle.importKey(
|
|
31
|
+
"raw",
|
|
32
|
+
keyUint8Array,
|
|
33
|
+
{ name: "HMAC", hash: "SHA-256" },
|
|
34
|
+
false,
|
|
35
|
+
["verify"]
|
|
36
|
+
);
|
|
37
|
+
_verifyKeys[secret] = cryptoKey;
|
|
38
|
+
return cryptoKey;
|
|
39
|
+
}
|
|
40
|
+
|
|
6
41
|
class Session {
|
|
7
42
|
#id;
|
|
8
43
|
#store;
|
|
@@ -60,7 +95,7 @@ class UnstorageSessionStore {
|
|
|
60
95
|
*/
|
|
61
96
|
async get(sid) {
|
|
62
97
|
const item = await this.storage.getItem(this.getKey(sid));
|
|
63
|
-
return item ??
|
|
98
|
+
return item ?? undefined;
|
|
64
99
|
}
|
|
65
100
|
/**
|
|
66
101
|
* Save the session with the specified session ID
|
|
@@ -88,7 +123,8 @@ class UnstorageSessionStore {
|
|
|
88
123
|
* Remove all saved sessions
|
|
89
124
|
*/
|
|
90
125
|
async clear() {
|
|
91
|
-
|
|
126
|
+
const keys = await this.getAllKeys();
|
|
127
|
+
await Promise.all(keys.map((k) => this.storage.removeItem(k)));
|
|
92
128
|
}
|
|
93
129
|
/**
|
|
94
130
|
* Fetch all saved sessions.
|
|
@@ -130,11 +166,11 @@ class UnstorageSessionStore {
|
|
|
130
166
|
const signatureLength = 43;
|
|
131
167
|
function parseCookieValue(value) {
|
|
132
168
|
if (value.length < signatureLength + 3) {
|
|
133
|
-
return
|
|
169
|
+
return undefined;
|
|
134
170
|
}
|
|
135
171
|
const separatorIndex = value.length - signatureLength - 1;
|
|
136
172
|
if (value.charAt(0) !== "s" || value.charAt(1) !== ":" || value.charAt(separatorIndex) !== ".") {
|
|
137
|
-
return
|
|
173
|
+
return undefined;
|
|
138
174
|
}
|
|
139
175
|
return [
|
|
140
176
|
value.substring(2, separatorIndex),
|
|
@@ -151,14 +187,7 @@ async function unsignCookie(value, secrets) {
|
|
|
151
187
|
const messageUint8Array = encoder.encode(message);
|
|
152
188
|
const signatureUint8Array = Uint8Array.from(Buffer.from(signature, "base64"));
|
|
153
189
|
for (let i = 0; i < secrets.length; i++) {
|
|
154
|
-
const
|
|
155
|
-
const cryptoKey = await subtle.importKey(
|
|
156
|
-
"raw",
|
|
157
|
-
keyUint8Array,
|
|
158
|
-
{ name: "HMAC", hash: "SHA-256" },
|
|
159
|
-
false,
|
|
160
|
-
["verify"]
|
|
161
|
-
);
|
|
190
|
+
const cryptoKey = await getCryptoVerifyKey(secrets[i]);
|
|
162
191
|
const result = await subtle.verify(
|
|
163
192
|
"HMAC",
|
|
164
193
|
cryptoKey,
|
|
@@ -180,14 +209,7 @@ async function signCookie(value, secret) {
|
|
|
180
209
|
}
|
|
181
210
|
const encoder = new TextEncoder();
|
|
182
211
|
const messageUint8Array = encoder.encode(value);
|
|
183
|
-
const
|
|
184
|
-
const cryptoKey = await subtle.importKey(
|
|
185
|
-
"raw",
|
|
186
|
-
keyUint8Array,
|
|
187
|
-
{ name: "HMAC", hash: "SHA-256" },
|
|
188
|
-
false,
|
|
189
|
-
["sign"]
|
|
190
|
-
);
|
|
212
|
+
const cryptoKey = await getCryptoSignKey(secret);
|
|
191
213
|
const signature = await subtle.sign("HMAC", cryptoKey, messageUint8Array);
|
|
192
214
|
const b64Signature = Buffer.from(signature).toString("base64").replace(/=+$/, "");
|
|
193
215
|
return `s:${value}.${b64Signature}`;
|
|
@@ -262,14 +284,22 @@ async function useSession(event, config) {
|
|
|
262
284
|
}
|
|
263
285
|
async function createExistingSession(id, data) {
|
|
264
286
|
const cookie = await createSessionCookie(id);
|
|
265
|
-
if (store.touch) {
|
|
287
|
+
if (store.touch && data) {
|
|
266
288
|
await store.touch(id, data);
|
|
267
289
|
}
|
|
268
|
-
event.context.session = new Session(
|
|
290
|
+
event.context.session = new Session(
|
|
291
|
+
id,
|
|
292
|
+
data ?? sessionConfig.generate(),
|
|
293
|
+
store,
|
|
294
|
+
generate,
|
|
295
|
+
cookie
|
|
296
|
+
);
|
|
269
297
|
event.context.sessionId = id;
|
|
270
298
|
}
|
|
271
|
-
if (!sessionId
|
|
299
|
+
if (!sessionId) {
|
|
272
300
|
await createNewSession();
|
|
301
|
+
} else if (!sessionData) {
|
|
302
|
+
await createExistingSession(sessionId);
|
|
273
303
|
} else {
|
|
274
304
|
await createExistingSession(sessionId, sessionData);
|
|
275
305
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scayle/h3-session",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Persistent sessions for h3",
|
|
5
5
|
"author": "SCAYLE Commerce Engine",
|
|
6
6
|
"license": "MIT",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"lint": "eslint . --format gitlab",
|
|
25
25
|
"lint:fix": "eslint . --fix",
|
|
26
26
|
"test": "vitest run",
|
|
27
|
-
"test:ci": "vitest --run --coverage --reporter=default --reporter=junit --outputFile=./junit.xml",
|
|
27
|
+
"test:ci": "vitest --run --coverage --reporter=default --reporter=junit --outputFile=./coverage/junit.xml",
|
|
28
28
|
"test:watch": "vitest watch",
|
|
29
29
|
"typecheck": "tsc --noEmit -p tsconfig.json"
|
|
30
30
|
},
|
|
@@ -37,17 +37,18 @@
|
|
|
37
37
|
"unstorage": "^1.10.2"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
|
-
"@arethetypeswrong/cli": "0.17.
|
|
41
|
-
"@scayle/eslint-config-storefront": "4.4.
|
|
42
|
-
"
|
|
43
|
-
"
|
|
40
|
+
"@arethetypeswrong/cli": "0.17.3",
|
|
41
|
+
"@scayle/eslint-config-storefront": "4.4.1",
|
|
42
|
+
"cookie-es": "1.2.2",
|
|
43
|
+
"dprint": "0.48.0",
|
|
44
|
+
"eslint": "9.18.0",
|
|
44
45
|
"eslint-formatter-gitlab": "5.1.0",
|
|
45
|
-
"h3": "1.13.
|
|
46
|
-
"typescript": "5.
|
|
47
|
-
"unbuild": "3.
|
|
46
|
+
"h3": "1.13.1",
|
|
47
|
+
"typescript": "5.7.3",
|
|
48
|
+
"unbuild": "3.3.1",
|
|
48
49
|
"vitest": "2.1.8"
|
|
49
50
|
},
|
|
50
51
|
"volta": {
|
|
51
|
-
"node": "22.
|
|
52
|
+
"node": "22.13.0"
|
|
52
53
|
}
|
|
53
54
|
}
|