hono-sessions 0.7.2 → 0.8.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/README.md +12 -1
- package/esm/deps.d.ts +1 -0
- package/esm/deps.d.ts.map +1 -1
- package/esm/deps.js +1 -0
- package/esm/src/Middleware.d.ts.map +1 -1
- package/esm/src/Middleware.js +30 -6
- package/esm/src/Session.d.ts +17 -3
- package/esm/src/Session.d.ts.map +1 -1
- package/esm/src/Session.js +36 -5
- package/esm/src/SessionOptions.d.ts +2 -1
- package/esm/src/SessionOptions.d.ts.map +1 -1
- package/package.json +3 -2
- package/script/deps.d.ts +1 -0
- package/script/deps.d.ts.map +1 -1
- package/script/deps.js +3 -1
- package/script/src/Middleware.d.ts.map +1 -1
- package/script/src/Middleware.js +30 -6
- package/script/src/Session.d.ts +17 -3
- package/script/src/Session.d.ts.map +1 -1
- package/script/src/Session.js +36 -5
- package/script/src/SessionOptions.d.ts +2 -1
- package/script/src/SessionOptions.d.ts.map +1 -1
package/README.md
CHANGED
|
@@ -74,8 +74,11 @@ const store = new CookieStore()
|
|
|
74
74
|
|
|
75
75
|
app.use('*', sessionMiddleware({
|
|
76
76
|
store,
|
|
77
|
-
encryptionKey: 'password_at_least_32_characters_long', // Required for CookieStore, recommended for others
|
|
77
|
+
encryptionKey: 'password_at_least_32_characters_long', // Required for CookieStore, recommended for others.
|
|
78
|
+
// You can also supply a function instead of a plain string
|
|
79
|
+
// encryptionKey: () => 'function_that_returns_a_long_string'
|
|
78
80
|
expireAfterSeconds: 900, // Expire session after 15 minutes of inactivity
|
|
81
|
+
autoExtendExpiration: true, // Extend the session expiration time automatically. Defaults to true
|
|
79
82
|
cookieOptions: {
|
|
80
83
|
sameSite: 'Lax', // Recommended for basic CSRF protection in modern browsers
|
|
81
84
|
path: '/', // Required for this library to work properly
|
|
@@ -91,6 +94,14 @@ app.get('/', async (c, next) => {
|
|
|
91
94
|
return c.html(`<h1>You have visited this page ${ session.get('counter') } times</h1>`)
|
|
92
95
|
})
|
|
93
96
|
|
|
97
|
+
app.get('/read', (c) => {
|
|
98
|
+
const session = c.get('session')
|
|
99
|
+
session.touch() // Update the session expiration time
|
|
100
|
+
return c.json({
|
|
101
|
+
counter: session.get('counter')
|
|
102
|
+
})
|
|
103
|
+
})
|
|
104
|
+
|
|
94
105
|
Deno.serve(app.fetch)
|
|
95
106
|
```
|
|
96
107
|
|
package/esm/deps.d.ts
CHANGED
package/esm/deps.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deps.d.ts","sourceRoot":"","sources":["../src/deps.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAA;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAC/C,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAClD,YAAY,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AACtD,OAAO,KAAK,IAAI,MAAM,gBAAgB,CAAA"}
|
|
1
|
+
{"version":3,"file":"deps.d.ts","sourceRoot":"","sources":["../src/deps.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAA;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAC/C,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAClD,YAAY,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AACtD,OAAO,KAAK,IAAI,MAAM,gBAAgB,CAAA;AACtC,OAAO,EAAE,IAAI,EAAE,MAAM,OAAO,CAAA"}
|
package/esm/deps.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Middleware.d.ts","sourceRoot":"","sources":["../../src/src/Middleware.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0C,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAGtF,OAAO,cAAc,MAAM,qBAAqB,CAAA;AAEhD,iEAAiE;AACjE,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,cAAc,GAAG,iBAAiB,
|
|
1
|
+
{"version":3,"file":"Middleware.d.ts","sourceRoot":"","sources":["../../src/src/Middleware.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0C,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAGtF,OAAO,cAAc,MAAM,qBAAqB,CAAA;AAEhD,iEAAiE;AACjE,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,cAAc,GAAG,iBAAiB,CAkK5E"}
|
package/esm/src/Middleware.js
CHANGED
|
@@ -4,10 +4,22 @@ import { Session, encrypt, decrypt } from '../mod.js';
|
|
|
4
4
|
/** Function that returns a Hono-compatible session middleware */
|
|
5
5
|
export function sessionMiddleware(options) {
|
|
6
6
|
const store = options.store;
|
|
7
|
-
|
|
7
|
+
let encryptionKey;
|
|
8
8
|
const expireAfterSeconds = options.expireAfterSeconds;
|
|
9
9
|
const cookieOptions = options.cookieOptions;
|
|
10
10
|
const sessionCookieName = options.sessionCookieName || 'session';
|
|
11
|
+
const autoExtendExpiration = options.autoExtendExpiration ?? true;
|
|
12
|
+
if (options.encryptionKey !== undefined) {
|
|
13
|
+
if (typeof options.encryptionKey === 'function') {
|
|
14
|
+
encryptionKey = options.encryptionKey();
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
encryptionKey = options.encryptionKey;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
encryptionKey = undefined;
|
|
22
|
+
}
|
|
11
23
|
if (store instanceof CookieStore) {
|
|
12
24
|
store.sessionCookieName = sessionCookieName;
|
|
13
25
|
if (encryptionKey) {
|
|
@@ -21,7 +33,7 @@ export function sessionMiddleware(options) {
|
|
|
21
33
|
}
|
|
22
34
|
}
|
|
23
35
|
const middleware = createMiddleware(async (c, next) => {
|
|
24
|
-
const session = new Session;
|
|
36
|
+
const session = new Session(expireAfterSeconds);
|
|
25
37
|
let sid = '';
|
|
26
38
|
let session_data;
|
|
27
39
|
let createNewSession = false;
|
|
@@ -34,6 +46,9 @@ export function sessionMiddleware(options) {
|
|
|
34
46
|
try {
|
|
35
47
|
sid = (encryptionKey ? await decrypt(encryptionKey, sessionCookie) : sessionCookie);
|
|
36
48
|
session_data = await store.getSessionById(sid);
|
|
49
|
+
if (session_data) {
|
|
50
|
+
session_data._id = sid;
|
|
51
|
+
}
|
|
37
52
|
}
|
|
38
53
|
catch {
|
|
39
54
|
createNewSession = true;
|
|
@@ -42,7 +57,9 @@ export function sessionMiddleware(options) {
|
|
|
42
57
|
if (session_data) {
|
|
43
58
|
session.setCache(session_data);
|
|
44
59
|
if (session.sessionValid()) {
|
|
45
|
-
|
|
60
|
+
if (autoExtendExpiration) {
|
|
61
|
+
session.reupSession();
|
|
62
|
+
}
|
|
46
63
|
}
|
|
47
64
|
else {
|
|
48
65
|
store instanceof CookieStore ? await store.deleteSession(c) : await store.deleteSession(sid);
|
|
@@ -68,16 +85,22 @@ export function sessionMiddleware(options) {
|
|
|
68
85
|
}
|
|
69
86
|
else {
|
|
70
87
|
sid = globalThis.crypto.randomUUID();
|
|
88
|
+
defaultData._id = sid;
|
|
71
89
|
await store.createSession(sid, defaultData);
|
|
72
90
|
}
|
|
73
|
-
session.setCache(defaultData);
|
|
91
|
+
session.setCache(defaultData, true);
|
|
74
92
|
}
|
|
75
93
|
if (!(store instanceof CookieStore)) {
|
|
76
94
|
setCookie(c, sessionCookieName, encryptionKey ? await encrypt(encryptionKey, sid) : sid, cookieOptions);
|
|
77
95
|
}
|
|
78
|
-
|
|
96
|
+
if (autoExtendExpiration) {
|
|
97
|
+
session.updateAccess();
|
|
98
|
+
}
|
|
79
99
|
c.set('session', session);
|
|
80
100
|
await next();
|
|
101
|
+
if (session.isStale()) {
|
|
102
|
+
session.touch();
|
|
103
|
+
}
|
|
81
104
|
const shouldDelete = session.getCache()._delete;
|
|
82
105
|
const shouldRotateSessionKey = c.get("session_key_rotation") === true;
|
|
83
106
|
const storeIsCookieStore = store instanceof CookieStore;
|
|
@@ -106,7 +129,8 @@ export function sessionMiddleware(options) {
|
|
|
106
129
|
* or the store is a CookieStore (which does not have its session key rotated)
|
|
107
130
|
*/
|
|
108
131
|
const shouldPersistSession = !shouldDelete &&
|
|
109
|
-
(!shouldRotateSessionKey || storeIsCookieStore)
|
|
132
|
+
(!shouldRotateSessionKey || storeIsCookieStore) &&
|
|
133
|
+
session.isStale();
|
|
110
134
|
if (shouldPersistSession) {
|
|
111
135
|
store instanceof CookieStore
|
|
112
136
|
? await store.persistSessionData(c, session.getCache())
|
package/esm/src/Session.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ interface SessionDataEntry<T> {
|
|
|
3
3
|
flash: boolean;
|
|
4
4
|
}
|
|
5
5
|
export interface SessionData<T = any> {
|
|
6
|
+
_id?: string;
|
|
6
7
|
_data: Record<string, SessionDataEntry<T>>;
|
|
7
8
|
_expire: string | null;
|
|
8
9
|
_delete: boolean;
|
|
@@ -10,13 +11,26 @@ export interface SessionData<T = any> {
|
|
|
10
11
|
}
|
|
11
12
|
export declare class Session<T = any> {
|
|
12
13
|
private cache;
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
private expiration;
|
|
15
|
+
private hash;
|
|
16
|
+
constructor(expiration?: number);
|
|
17
|
+
setCache(cache_data: SessionData<T>, isNew?: boolean): void;
|
|
18
|
+
isStale(): boolean;
|
|
15
19
|
getCache(): SessionData<T>;
|
|
16
20
|
setExpiration(expiration: string): void;
|
|
17
|
-
|
|
21
|
+
/**
|
|
22
|
+
* Extend expiration
|
|
23
|
+
*/
|
|
24
|
+
reupSession(): void;
|
|
25
|
+
/**
|
|
26
|
+
* Extend session expiration and update access time
|
|
27
|
+
*/
|
|
28
|
+
touch(): void;
|
|
18
29
|
deleteSession(): void;
|
|
19
30
|
sessionValid(): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Update the last accessed time
|
|
33
|
+
*/
|
|
20
34
|
updateAccess(): void;
|
|
21
35
|
get<K extends keyof T>(key: K): T[K] | null;
|
|
22
36
|
set<K extends keyof T>(key: K, value: T[K]): void;
|
package/esm/src/Session.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Session.d.ts","sourceRoot":"","sources":["../../src/src/Session.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Session.d.ts","sourceRoot":"","sources":["../../src/src/Session.ts"],"names":[],"mappings":"AAEA,UAAU,gBAAgB,CAAC,CAAC;IAC1B,KAAK,EAAE,CAAC,CAAC;IACT,KAAK,EAAE,OAAO,CAAA;CACf;AAED,MAAM,WAAW,WAAW,CAAC,CAAC,GAAG,GAAG;IAClC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3C,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,qBAAa,OAAO,CAAC,CAAC,GAAG,GAAG;IAE1B,OAAO,CAAC,KAAK,CAAgB;IAC7B,OAAO,CAAC,UAAU,CAAoB;IACtC,OAAO,CAAC,IAAI,CAAsB;gBAEtB,UAAU,CAAC,EAAE,MAAM;IAU/B,QAAQ,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,KAAK,GAAE,OAAe;IAK3D,OAAO,IAAI,OAAO;IAIlB,QAAQ,IAAI,WAAW,CAAC,CAAC,CAAC;IAI1B,aAAa,CAAC,UAAU,EAAE,MAAM;IAIhC;;OAEG;IACH,WAAW;IAMX;;OAEG;IACH,KAAK;IAKL,aAAa;IAIb,YAAY,IAAI,OAAO;IAIvB;;OAEG;IACH,YAAY;IAIZ,GAAG,CAAC,CAAC,SAAS,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI;IAe3C,GAAG,CAAC,CAAC,SAAS,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;IAS1C,MAAM,CAAC,CAAC,SAAS,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC;IAMhC,KAAK,CAAC,CAAC,SAAS,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;CAQ7C"}
|
package/esm/src/Session.js
CHANGED
|
@@ -1,11 +1,25 @@
|
|
|
1
|
+
import { hash } from '../deps.js';
|
|
1
2
|
export class Session {
|
|
2
|
-
constructor() {
|
|
3
|
+
constructor(expiration) {
|
|
3
4
|
Object.defineProperty(this, "cache", {
|
|
4
5
|
enumerable: true,
|
|
5
6
|
configurable: true,
|
|
6
7
|
writable: true,
|
|
7
8
|
value: void 0
|
|
8
9
|
});
|
|
10
|
+
Object.defineProperty(this, "expiration", {
|
|
11
|
+
enumerable: true,
|
|
12
|
+
configurable: true,
|
|
13
|
+
writable: true,
|
|
14
|
+
value: void 0
|
|
15
|
+
});
|
|
16
|
+
Object.defineProperty(this, "hash", {
|
|
17
|
+
enumerable: true,
|
|
18
|
+
configurable: true,
|
|
19
|
+
writable: true,
|
|
20
|
+
value: null
|
|
21
|
+
});
|
|
22
|
+
this.expiration = expiration;
|
|
9
23
|
this.cache = {
|
|
10
24
|
_data: {},
|
|
11
25
|
_expire: null,
|
|
@@ -13,26 +27,43 @@ export class Session {
|
|
|
13
27
|
_accessed: null,
|
|
14
28
|
};
|
|
15
29
|
}
|
|
16
|
-
setCache(cache_data) {
|
|
30
|
+
setCache(cache_data, isNew = false) {
|
|
31
|
+
this.hash = !isNew ? hash(cache_data) : null;
|
|
17
32
|
this.cache = cache_data;
|
|
18
33
|
}
|
|
34
|
+
isStale() {
|
|
35
|
+
return !this.hash || this.hash !== hash(this.cache);
|
|
36
|
+
}
|
|
19
37
|
getCache() {
|
|
20
38
|
return this.cache;
|
|
21
39
|
}
|
|
22
40
|
setExpiration(expiration) {
|
|
23
41
|
this.cache._expire = expiration;
|
|
24
42
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
43
|
+
/**
|
|
44
|
+
* Extend expiration
|
|
45
|
+
*/
|
|
46
|
+
reupSession() {
|
|
47
|
+
if (this.expiration) {
|
|
48
|
+
this.setExpiration(new Date(Date.now() + this.expiration * 1000).toISOString());
|
|
28
49
|
}
|
|
29
50
|
}
|
|
51
|
+
/**
|
|
52
|
+
* Extend session expiration and update access time
|
|
53
|
+
*/
|
|
54
|
+
touch() {
|
|
55
|
+
this.reupSession();
|
|
56
|
+
this.updateAccess();
|
|
57
|
+
}
|
|
30
58
|
deleteSession() {
|
|
31
59
|
this.cache._delete = true;
|
|
32
60
|
}
|
|
33
61
|
sessionValid() {
|
|
34
62
|
return this.cache._expire == null || Date.now() < new Date(this.cache._expire).getTime();
|
|
35
63
|
}
|
|
64
|
+
/**
|
|
65
|
+
* Update the last accessed time
|
|
66
|
+
*/
|
|
36
67
|
updateAccess() {
|
|
37
68
|
this.cache._accessed = new Date().toISOString();
|
|
38
69
|
}
|
|
@@ -3,9 +3,10 @@ import CookieStore from './store/CookieStore.js';
|
|
|
3
3
|
import { CookieOptions } from '../deps.js';
|
|
4
4
|
export default interface SessionOptions {
|
|
5
5
|
store: Store | CookieStore;
|
|
6
|
-
encryptionKey?: string;
|
|
6
|
+
encryptionKey?: string | (() => string);
|
|
7
7
|
expireAfterSeconds?: number;
|
|
8
8
|
cookieOptions?: CookieOptions;
|
|
9
9
|
sessionCookieName?: string;
|
|
10
|
+
autoExtendExpiration?: boolean;
|
|
10
11
|
}
|
|
11
12
|
//# sourceMappingURL=SessionOptions.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SessionOptions.d.ts","sourceRoot":"","sources":["../../src/src/SessionOptions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,kBAAkB,CAAA;AACpC,OAAO,WAAW,MAAM,wBAAwB,CAAA;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE3C,MAAM,CAAC,OAAO,WAAW,cAAc;IACrC,KAAK,EAAE,KAAK,GAAG,WAAW,CAAA;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"SessionOptions.d.ts","sourceRoot":"","sources":["../../src/src/SessionOptions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,kBAAkB,CAAA;AACpC,OAAO,WAAW,MAAM,wBAAwB,CAAA;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE3C,MAAM,CAAC,OAAO,WAAW,cAAc;IACrC,KAAK,EAAE,KAAK,GAAG,WAAW,CAAA;IAC1B,aAAa,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,CAAC;IACxC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,oBAAoB,CAAC,EAAE,OAAO,CAAA;CAC/B"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hono-sessions",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "Cookie-based sessions for Hono web framework",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -24,7 +24,8 @@
|
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"hono": "^4.0.0",
|
|
27
|
-
"iron-webcrypto": "^1.2.1"
|
|
27
|
+
"iron-webcrypto": "^1.2.1",
|
|
28
|
+
"ohash": "^2"
|
|
28
29
|
},
|
|
29
30
|
"_generatedBy": "dnt@dev"
|
|
30
31
|
}
|
package/script/deps.d.ts
CHANGED
package/script/deps.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deps.d.ts","sourceRoot":"","sources":["../src/deps.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAA;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAC/C,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAClD,YAAY,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AACtD,OAAO,KAAK,IAAI,MAAM,gBAAgB,CAAA"}
|
|
1
|
+
{"version":3,"file":"deps.d.ts","sourceRoot":"","sources":["../src/deps.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAA;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAC/C,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAClD,YAAY,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AACtD,OAAO,KAAK,IAAI,MAAM,gBAAgB,CAAA;AACtC,OAAO,EAAE,IAAI,EAAE,MAAM,OAAO,CAAA"}
|
package/script/deps.js
CHANGED
|
@@ -23,10 +23,12 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
23
23
|
return result;
|
|
24
24
|
};
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
-
exports.Iron = exports.setCookie = exports.getCookie = exports.createMiddleware = void 0;
|
|
26
|
+
exports.hash = exports.Iron = exports.setCookie = exports.getCookie = exports.createMiddleware = void 0;
|
|
27
27
|
var factory_1 = require("hono/factory");
|
|
28
28
|
Object.defineProperty(exports, "createMiddleware", { enumerable: true, get: function () { return factory_1.createMiddleware; } });
|
|
29
29
|
var cookie_1 = require("hono/cookie");
|
|
30
30
|
Object.defineProperty(exports, "getCookie", { enumerable: true, get: function () { return cookie_1.getCookie; } });
|
|
31
31
|
Object.defineProperty(exports, "setCookie", { enumerable: true, get: function () { return cookie_1.setCookie; } });
|
|
32
32
|
exports.Iron = __importStar(require("iron-webcrypto"));
|
|
33
|
+
var ohash_1 = require("ohash");
|
|
34
|
+
Object.defineProperty(exports, "hash", { enumerable: true, get: function () { return ohash_1.hash; } });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Middleware.d.ts","sourceRoot":"","sources":["../../src/src/Middleware.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0C,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAGtF,OAAO,cAAc,MAAM,qBAAqB,CAAA;AAEhD,iEAAiE;AACjE,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,cAAc,GAAG,iBAAiB,
|
|
1
|
+
{"version":3,"file":"Middleware.d.ts","sourceRoot":"","sources":["../../src/src/Middleware.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0C,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAGtF,OAAO,cAAc,MAAM,qBAAqB,CAAA;AAEhD,iEAAiE;AACjE,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,cAAc,GAAG,iBAAiB,CAkK5E"}
|
package/script/src/Middleware.js
CHANGED
|
@@ -10,10 +10,22 @@ const mod_js_1 = require("../mod.js");
|
|
|
10
10
|
/** Function that returns a Hono-compatible session middleware */
|
|
11
11
|
function sessionMiddleware(options) {
|
|
12
12
|
const store = options.store;
|
|
13
|
-
|
|
13
|
+
let encryptionKey;
|
|
14
14
|
const expireAfterSeconds = options.expireAfterSeconds;
|
|
15
15
|
const cookieOptions = options.cookieOptions;
|
|
16
16
|
const sessionCookieName = options.sessionCookieName || 'session';
|
|
17
|
+
const autoExtendExpiration = options.autoExtendExpiration ?? true;
|
|
18
|
+
if (options.encryptionKey !== undefined) {
|
|
19
|
+
if (typeof options.encryptionKey === 'function') {
|
|
20
|
+
encryptionKey = options.encryptionKey();
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
encryptionKey = options.encryptionKey;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
encryptionKey = undefined;
|
|
28
|
+
}
|
|
17
29
|
if (store instanceof CookieStore_js_1.default) {
|
|
18
30
|
store.sessionCookieName = sessionCookieName;
|
|
19
31
|
if (encryptionKey) {
|
|
@@ -27,7 +39,7 @@ function sessionMiddleware(options) {
|
|
|
27
39
|
}
|
|
28
40
|
}
|
|
29
41
|
const middleware = (0, deps_js_1.createMiddleware)(async (c, next) => {
|
|
30
|
-
const session = new mod_js_1.Session;
|
|
42
|
+
const session = new mod_js_1.Session(expireAfterSeconds);
|
|
31
43
|
let sid = '';
|
|
32
44
|
let session_data;
|
|
33
45
|
let createNewSession = false;
|
|
@@ -40,6 +52,9 @@ function sessionMiddleware(options) {
|
|
|
40
52
|
try {
|
|
41
53
|
sid = (encryptionKey ? await (0, mod_js_1.decrypt)(encryptionKey, sessionCookie) : sessionCookie);
|
|
42
54
|
session_data = await store.getSessionById(sid);
|
|
55
|
+
if (session_data) {
|
|
56
|
+
session_data._id = sid;
|
|
57
|
+
}
|
|
43
58
|
}
|
|
44
59
|
catch {
|
|
45
60
|
createNewSession = true;
|
|
@@ -48,7 +63,9 @@ function sessionMiddleware(options) {
|
|
|
48
63
|
if (session_data) {
|
|
49
64
|
session.setCache(session_data);
|
|
50
65
|
if (session.sessionValid()) {
|
|
51
|
-
|
|
66
|
+
if (autoExtendExpiration) {
|
|
67
|
+
session.reupSession();
|
|
68
|
+
}
|
|
52
69
|
}
|
|
53
70
|
else {
|
|
54
71
|
store instanceof CookieStore_js_1.default ? await store.deleteSession(c) : await store.deleteSession(sid);
|
|
@@ -74,16 +91,22 @@ function sessionMiddleware(options) {
|
|
|
74
91
|
}
|
|
75
92
|
else {
|
|
76
93
|
sid = globalThis.crypto.randomUUID();
|
|
94
|
+
defaultData._id = sid;
|
|
77
95
|
await store.createSession(sid, defaultData);
|
|
78
96
|
}
|
|
79
|
-
session.setCache(defaultData);
|
|
97
|
+
session.setCache(defaultData, true);
|
|
80
98
|
}
|
|
81
99
|
if (!(store instanceof CookieStore_js_1.default)) {
|
|
82
100
|
(0, deps_js_1.setCookie)(c, sessionCookieName, encryptionKey ? await (0, mod_js_1.encrypt)(encryptionKey, sid) : sid, cookieOptions);
|
|
83
101
|
}
|
|
84
|
-
|
|
102
|
+
if (autoExtendExpiration) {
|
|
103
|
+
session.updateAccess();
|
|
104
|
+
}
|
|
85
105
|
c.set('session', session);
|
|
86
106
|
await next();
|
|
107
|
+
if (session.isStale()) {
|
|
108
|
+
session.touch();
|
|
109
|
+
}
|
|
87
110
|
const shouldDelete = session.getCache()._delete;
|
|
88
111
|
const shouldRotateSessionKey = c.get("session_key_rotation") === true;
|
|
89
112
|
const storeIsCookieStore = store instanceof CookieStore_js_1.default;
|
|
@@ -112,7 +135,8 @@ function sessionMiddleware(options) {
|
|
|
112
135
|
* or the store is a CookieStore (which does not have its session key rotated)
|
|
113
136
|
*/
|
|
114
137
|
const shouldPersistSession = !shouldDelete &&
|
|
115
|
-
(!shouldRotateSessionKey || storeIsCookieStore)
|
|
138
|
+
(!shouldRotateSessionKey || storeIsCookieStore) &&
|
|
139
|
+
session.isStale();
|
|
116
140
|
if (shouldPersistSession) {
|
|
117
141
|
store instanceof CookieStore_js_1.default
|
|
118
142
|
? await store.persistSessionData(c, session.getCache())
|
package/script/src/Session.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ interface SessionDataEntry<T> {
|
|
|
3
3
|
flash: boolean;
|
|
4
4
|
}
|
|
5
5
|
export interface SessionData<T = any> {
|
|
6
|
+
_id?: string;
|
|
6
7
|
_data: Record<string, SessionDataEntry<T>>;
|
|
7
8
|
_expire: string | null;
|
|
8
9
|
_delete: boolean;
|
|
@@ -10,13 +11,26 @@ export interface SessionData<T = any> {
|
|
|
10
11
|
}
|
|
11
12
|
export declare class Session<T = any> {
|
|
12
13
|
private cache;
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
private expiration;
|
|
15
|
+
private hash;
|
|
16
|
+
constructor(expiration?: number);
|
|
17
|
+
setCache(cache_data: SessionData<T>, isNew?: boolean): void;
|
|
18
|
+
isStale(): boolean;
|
|
15
19
|
getCache(): SessionData<T>;
|
|
16
20
|
setExpiration(expiration: string): void;
|
|
17
|
-
|
|
21
|
+
/**
|
|
22
|
+
* Extend expiration
|
|
23
|
+
*/
|
|
24
|
+
reupSession(): void;
|
|
25
|
+
/**
|
|
26
|
+
* Extend session expiration and update access time
|
|
27
|
+
*/
|
|
28
|
+
touch(): void;
|
|
18
29
|
deleteSession(): void;
|
|
19
30
|
sessionValid(): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Update the last accessed time
|
|
33
|
+
*/
|
|
20
34
|
updateAccess(): void;
|
|
21
35
|
get<K extends keyof T>(key: K): T[K] | null;
|
|
22
36
|
set<K extends keyof T>(key: K, value: T[K]): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Session.d.ts","sourceRoot":"","sources":["../../src/src/Session.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Session.d.ts","sourceRoot":"","sources":["../../src/src/Session.ts"],"names":[],"mappings":"AAEA,UAAU,gBAAgB,CAAC,CAAC;IAC1B,KAAK,EAAE,CAAC,CAAC;IACT,KAAK,EAAE,OAAO,CAAA;CACf;AAED,MAAM,WAAW,WAAW,CAAC,CAAC,GAAG,GAAG;IAClC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3C,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,qBAAa,OAAO,CAAC,CAAC,GAAG,GAAG;IAE1B,OAAO,CAAC,KAAK,CAAgB;IAC7B,OAAO,CAAC,UAAU,CAAoB;IACtC,OAAO,CAAC,IAAI,CAAsB;gBAEtB,UAAU,CAAC,EAAE,MAAM;IAU/B,QAAQ,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,KAAK,GAAE,OAAe;IAK3D,OAAO,IAAI,OAAO;IAIlB,QAAQ,IAAI,WAAW,CAAC,CAAC,CAAC;IAI1B,aAAa,CAAC,UAAU,EAAE,MAAM;IAIhC;;OAEG;IACH,WAAW;IAMX;;OAEG;IACH,KAAK;IAKL,aAAa;IAIb,YAAY,IAAI,OAAO;IAIvB;;OAEG;IACH,YAAY;IAIZ,GAAG,CAAC,CAAC,SAAS,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI;IAe3C,GAAG,CAAC,CAAC,SAAS,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;IAS1C,MAAM,CAAC,CAAC,SAAS,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC;IAMhC,KAAK,CAAC,CAAC,SAAS,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;CAQ7C"}
|
package/script/src/Session.js
CHANGED
|
@@ -1,14 +1,28 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Session = void 0;
|
|
4
|
+
const deps_js_1 = require("../deps.js");
|
|
4
5
|
class Session {
|
|
5
|
-
constructor() {
|
|
6
|
+
constructor(expiration) {
|
|
6
7
|
Object.defineProperty(this, "cache", {
|
|
7
8
|
enumerable: true,
|
|
8
9
|
configurable: true,
|
|
9
10
|
writable: true,
|
|
10
11
|
value: void 0
|
|
11
12
|
});
|
|
13
|
+
Object.defineProperty(this, "expiration", {
|
|
14
|
+
enumerable: true,
|
|
15
|
+
configurable: true,
|
|
16
|
+
writable: true,
|
|
17
|
+
value: void 0
|
|
18
|
+
});
|
|
19
|
+
Object.defineProperty(this, "hash", {
|
|
20
|
+
enumerable: true,
|
|
21
|
+
configurable: true,
|
|
22
|
+
writable: true,
|
|
23
|
+
value: null
|
|
24
|
+
});
|
|
25
|
+
this.expiration = expiration;
|
|
12
26
|
this.cache = {
|
|
13
27
|
_data: {},
|
|
14
28
|
_expire: null,
|
|
@@ -16,26 +30,43 @@ class Session {
|
|
|
16
30
|
_accessed: null,
|
|
17
31
|
};
|
|
18
32
|
}
|
|
19
|
-
setCache(cache_data) {
|
|
33
|
+
setCache(cache_data, isNew = false) {
|
|
34
|
+
this.hash = !isNew ? (0, deps_js_1.hash)(cache_data) : null;
|
|
20
35
|
this.cache = cache_data;
|
|
21
36
|
}
|
|
37
|
+
isStale() {
|
|
38
|
+
return !this.hash || this.hash !== (0, deps_js_1.hash)(this.cache);
|
|
39
|
+
}
|
|
22
40
|
getCache() {
|
|
23
41
|
return this.cache;
|
|
24
42
|
}
|
|
25
43
|
setExpiration(expiration) {
|
|
26
44
|
this.cache._expire = expiration;
|
|
27
45
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
46
|
+
/**
|
|
47
|
+
* Extend expiration
|
|
48
|
+
*/
|
|
49
|
+
reupSession() {
|
|
50
|
+
if (this.expiration) {
|
|
51
|
+
this.setExpiration(new Date(Date.now() + this.expiration * 1000).toISOString());
|
|
31
52
|
}
|
|
32
53
|
}
|
|
54
|
+
/**
|
|
55
|
+
* Extend session expiration and update access time
|
|
56
|
+
*/
|
|
57
|
+
touch() {
|
|
58
|
+
this.reupSession();
|
|
59
|
+
this.updateAccess();
|
|
60
|
+
}
|
|
33
61
|
deleteSession() {
|
|
34
62
|
this.cache._delete = true;
|
|
35
63
|
}
|
|
36
64
|
sessionValid() {
|
|
37
65
|
return this.cache._expire == null || Date.now() < new Date(this.cache._expire).getTime();
|
|
38
66
|
}
|
|
67
|
+
/**
|
|
68
|
+
* Update the last accessed time
|
|
69
|
+
*/
|
|
39
70
|
updateAccess() {
|
|
40
71
|
this.cache._accessed = new Date().toISOString();
|
|
41
72
|
}
|
|
@@ -3,9 +3,10 @@ import CookieStore from './store/CookieStore.js';
|
|
|
3
3
|
import { CookieOptions } from '../deps.js';
|
|
4
4
|
export default interface SessionOptions {
|
|
5
5
|
store: Store | CookieStore;
|
|
6
|
-
encryptionKey?: string;
|
|
6
|
+
encryptionKey?: string | (() => string);
|
|
7
7
|
expireAfterSeconds?: number;
|
|
8
8
|
cookieOptions?: CookieOptions;
|
|
9
9
|
sessionCookieName?: string;
|
|
10
|
+
autoExtendExpiration?: boolean;
|
|
10
11
|
}
|
|
11
12
|
//# sourceMappingURL=SessionOptions.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SessionOptions.d.ts","sourceRoot":"","sources":["../../src/src/SessionOptions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,kBAAkB,CAAA;AACpC,OAAO,WAAW,MAAM,wBAAwB,CAAA;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE3C,MAAM,CAAC,OAAO,WAAW,cAAc;IACrC,KAAK,EAAE,KAAK,GAAG,WAAW,CAAA;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"SessionOptions.d.ts","sourceRoot":"","sources":["../../src/src/SessionOptions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,kBAAkB,CAAA;AACpC,OAAO,WAAW,MAAM,wBAAwB,CAAA;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE3C,MAAM,CAAC,OAAO,WAAW,cAAc;IACrC,KAAK,EAAE,KAAK,GAAG,WAAW,CAAA;IAC1B,aAAa,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,CAAC;IACxC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,oBAAoB,CAAC,EAAE,OAAO,CAAA;CAC/B"}
|