hono-sessions 0.1.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.
Files changed (41) hide show
  1. package/LICENSE +7 -0
  2. package/README.md +113 -0
  3. package/esm/deps/deno.land/std@0.198.0/encoding/base64.d.ts +11 -0
  4. package/esm/deps/deno.land/std@0.198.0/encoding/base64.js +140 -0
  5. package/esm/deps.d.ts +4 -0
  6. package/esm/deps.js +2 -0
  7. package/esm/mod.d.ts +9 -0
  8. package/esm/mod.js +6 -0
  9. package/esm/package.json +3 -0
  10. package/esm/src/Crypto.d.ts +3 -0
  11. package/esm/src/Crypto.js +29 -0
  12. package/esm/src/Middleware.d.ts +13 -0
  13. package/esm/src/Middleware.js +85 -0
  14. package/esm/src/Session.d.ts +25 -0
  15. package/esm/src/Session.js +64 -0
  16. package/esm/src/store/CookieStore.d.ts +18 -0
  17. package/esm/src/store/CookieStore.js +52 -0
  18. package/esm/src/store/MemoryStore.d.ts +11 -0
  19. package/esm/src/store/MemoryStore.js +24 -0
  20. package/esm/src/store/Store.d.ts +7 -0
  21. package/esm/src/store/Store.js +1 -0
  22. package/package.json +31 -0
  23. package/script/deps/deno.land/std@0.198.0/encoding/base64.d.ts +11 -0
  24. package/script/deps/deno.land/std@0.198.0/encoding/base64.js +145 -0
  25. package/script/deps.d.ts +4 -0
  26. package/script/deps.js +8 -0
  27. package/script/mod.d.ts +9 -0
  28. package/script/mod.js +18 -0
  29. package/script/package.json +3 -0
  30. package/script/src/Crypto.d.ts +3 -0
  31. package/script/src/Crypto.js +35 -0
  32. package/script/src/Middleware.d.ts +13 -0
  33. package/script/src/Middleware.js +92 -0
  34. package/script/src/Session.d.ts +25 -0
  35. package/script/src/Session.js +68 -0
  36. package/script/src/store/CookieStore.d.ts +18 -0
  37. package/script/src/store/CookieStore.js +54 -0
  38. package/script/src/store/MemoryStore.d.ts +11 -0
  39. package/script/src/store/MemoryStore.js +26 -0
  40. package/script/src/store/Store.d.ts +7 -0
  41. package/script/src/store/Store.js +2 -0
package/LICENSE ADDED
@@ -0,0 +1,7 @@
1
+ Copyright 2023 Joe Sweeney
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,113 @@
1
+ # Hono Sessions Middleware
2
+ Use cookie-based sessions with the [Hono](https://hono.dev/) framework. Currently tested to work with Cloudflare Workers and Deno.
3
+
4
+ ## Usage
5
+
6
+ ### Cloudflare Workers
7
+
8
+ ```ts
9
+ import { Hono } from 'hono'
10
+ import { sessionMiddleware, CookieStore, Session } from 'hono-sessions'
11
+
12
+ const store = new CookieStore()
13
+
14
+ const app = new Hono()
15
+
16
+ const sessionRoutes = new Hono<{
17
+ Variables: {
18
+ session: Session,
19
+ session_key_rotation: boolean
20
+ }
21
+ }>()
22
+
23
+ sessionRoutes.use('*', session({
24
+ store,
25
+ expireAfterSeconds: 900 // delete session after 15 minutes of inactivity
26
+ }))
27
+
28
+ sessionRoutes.post('/login', async (c) => {
29
+ const session = c.get('session')
30
+
31
+ const { email, password } = await c.req.parseBody()
32
+
33
+ if (password === 'correct') {
34
+ c.set('session_key_rotation', true)
35
+ session.set('email', email)
36
+ session.set('failed-login-attempts', null)
37
+ session.flash('message', 'Login Successful')
38
+ } else {
39
+ const failedLoginAttempts = (await session.get('failed-login-attempts') || 0) as number
40
+ session.set('failed-login-attempts', failedLoginAttempts + 1)
41
+ session.flash('error', 'Incorrect username or password')
42
+ }
43
+
44
+ return c.redirect('/')
45
+ })
46
+
47
+ sessionRoutes.post('/logout', async (c) => {
48
+ await c.get('session').deleteSession()
49
+ return c.redirect('/')
50
+ })
51
+
52
+ sessionRoutes.get('/', async (c) => {
53
+ const session = c.get('session')
54
+
55
+ const message = await session.get('message') || ''
56
+ const error = await session.get('error') || ''
57
+ const failedLoginAttempts = await session.get('failed-login-attempts')
58
+ const email = await session.get('email')
59
+
60
+ return c.html(`<!DOCTYPE html>
61
+ <html lang="en">
62
+ <head>
63
+ <meta charset="UTF-8">
64
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
65
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
66
+ <title>Hono Sessions</title>
67
+ </head>
68
+ <body>
69
+ <p>
70
+ ${message}
71
+ </p>
72
+ <p>
73
+ ${error}
74
+ </p>
75
+ <p>
76
+ ${failedLoginAttempts ? `Failed login attempts: ${failedLoginAttempts}` : ''}
77
+ </p>
78
+
79
+ ${email ?
80
+ `<form id="logout" action="/logout" method="post">
81
+ <button name="logout" type="submit">Log out ${email}</button>
82
+ </form>`
83
+ :
84
+ `<form id="login" action="/login" method="post">
85
+ <p>
86
+ <input id="email" name="email" type="text" placeholder="you@email.com">
87
+ </p>
88
+ <p>
89
+ <input id="password" name="password" type="password" placeholder="password">
90
+ </p>
91
+ <button name="login" type="submit">Log in</button>
92
+ </form>`
93
+ }
94
+ </body>
95
+ </html>`)
96
+ })
97
+
98
+ app.route('/', sessionRoutes)
99
+
100
+ export default app
101
+ ```
102
+
103
+ ### Deno
104
+ ```ts
105
+ import { Hono } from 'https://deno.land/x/hono/mod.ts'
106
+ import { sessionMiddleware, CookieStore, Session } from 'https://deno.land/x/hono_sessions/mod.ts'
107
+
108
+ // Same as CF Workers, however instead of:
109
+ // export default app
110
+ // use:
111
+
112
+ Deno.serve(app.fetch)
113
+ ```
@@ -0,0 +1,11 @@
1
+ /**
2
+ * CREDIT: https://gist.github.com/enepomnyaschih/72c423f727d395eeaa09697058238727
3
+ * Encodes a given Uint8Array, ArrayBuffer or string into RFC4648 base64 representation
4
+ * @param data
5
+ */
6
+ export declare function encode(data: ArrayBuffer | string): string;
7
+ /**
8
+ * Decodes a given RFC4648 base64 encoded string
9
+ * @param b64
10
+ */
11
+ export declare function decode(b64: string): Uint8Array;
@@ -0,0 +1,140 @@
1
+ // Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
2
+ // This module is browser compatible.
3
+ /**
4
+ * {@linkcode encode} and {@linkcode decode} for
5
+ * [base64](https://en.wikipedia.org/wiki/Base64) encoding.
6
+ *
7
+ * This module is browser compatible.
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * import {
12
+ * decode,
13
+ * encode,
14
+ * } from "https://deno.land/std@$STD_VERSION/encoding/base64.ts";
15
+ *
16
+ * const b64Repr = "Zm9vYg==";
17
+ *
18
+ * const binaryData = decode(b64Repr);
19
+ * console.log(binaryData);
20
+ * // => Uint8Array [ 102, 111, 111, 98 ]
21
+ *
22
+ * console.log(encode(binaryData));
23
+ * // => Zm9vYg==
24
+ * ```
25
+ *
26
+ * @module
27
+ */
28
+ const base64abc = [
29
+ "A",
30
+ "B",
31
+ "C",
32
+ "D",
33
+ "E",
34
+ "F",
35
+ "G",
36
+ "H",
37
+ "I",
38
+ "J",
39
+ "K",
40
+ "L",
41
+ "M",
42
+ "N",
43
+ "O",
44
+ "P",
45
+ "Q",
46
+ "R",
47
+ "S",
48
+ "T",
49
+ "U",
50
+ "V",
51
+ "W",
52
+ "X",
53
+ "Y",
54
+ "Z",
55
+ "a",
56
+ "b",
57
+ "c",
58
+ "d",
59
+ "e",
60
+ "f",
61
+ "g",
62
+ "h",
63
+ "i",
64
+ "j",
65
+ "k",
66
+ "l",
67
+ "m",
68
+ "n",
69
+ "o",
70
+ "p",
71
+ "q",
72
+ "r",
73
+ "s",
74
+ "t",
75
+ "u",
76
+ "v",
77
+ "w",
78
+ "x",
79
+ "y",
80
+ "z",
81
+ "0",
82
+ "1",
83
+ "2",
84
+ "3",
85
+ "4",
86
+ "5",
87
+ "6",
88
+ "7",
89
+ "8",
90
+ "9",
91
+ "+",
92
+ "/",
93
+ ];
94
+ /**
95
+ * CREDIT: https://gist.github.com/enepomnyaschih/72c423f727d395eeaa09697058238727
96
+ * Encodes a given Uint8Array, ArrayBuffer or string into RFC4648 base64 representation
97
+ * @param data
98
+ */
99
+ export function encode(data) {
100
+ const uint8 = typeof data === "string"
101
+ ? new TextEncoder().encode(data)
102
+ : data instanceof Uint8Array
103
+ ? data
104
+ : new Uint8Array(data);
105
+ let result = "", i;
106
+ const l = uint8.length;
107
+ for (i = 2; i < l; i += 3) {
108
+ result += base64abc[uint8[i - 2] >> 2];
109
+ result += base64abc[((uint8[i - 2] & 0x03) << 4) | (uint8[i - 1] >> 4)];
110
+ result += base64abc[((uint8[i - 1] & 0x0f) << 2) | (uint8[i] >> 6)];
111
+ result += base64abc[uint8[i] & 0x3f];
112
+ }
113
+ if (i === l + 1) {
114
+ // 1 octet yet to write
115
+ result += base64abc[uint8[i - 2] >> 2];
116
+ result += base64abc[(uint8[i - 2] & 0x03) << 4];
117
+ result += "==";
118
+ }
119
+ if (i === l) {
120
+ // 2 octets yet to write
121
+ result += base64abc[uint8[i - 2] >> 2];
122
+ result += base64abc[((uint8[i - 2] & 0x03) << 4) | (uint8[i - 1] >> 4)];
123
+ result += base64abc[(uint8[i - 1] & 0x0f) << 2];
124
+ result += "=";
125
+ }
126
+ return result;
127
+ }
128
+ /**
129
+ * Decodes a given RFC4648 base64 encoded string
130
+ * @param b64
131
+ */
132
+ export function decode(b64) {
133
+ const binString = atob(b64);
134
+ const size = binString.length;
135
+ const bytes = new Uint8Array(size);
136
+ for (let i = 0; i < size; i++) {
137
+ bytes[i] = binString.charCodeAt(i);
138
+ }
139
+ return bytes;
140
+ }
package/esm/deps.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ export { nanoid } from 'nanoid/async';
2
+ export type { MiddlewareHandler, Context } from 'hono';
3
+ export { getCookie, setCookie } from 'hono/cookie';
4
+ export type { CookieOptions } from 'hono/utils/cookie';
package/esm/deps.js ADDED
@@ -0,0 +1,2 @@
1
+ export { nanoid } from 'nanoid/async';
2
+ export { getCookie, setCookie } from 'hono/cookie';
package/esm/mod.d.ts ADDED
@@ -0,0 +1,9 @@
1
+ import MemoryStore from './src/store/MemoryStore.js';
2
+ import CookieStore from './src/store/CookieStore.js';
3
+ import { createKeyFromBase64, encryptToBase64, decryptFromBase64 } from './src/Crypto.js';
4
+ import { sessionMiddleware } from './src/Middleware.js';
5
+ import { Session } from './src/Session.js';
6
+ import type { SessionData } from './src/Session.js';
7
+ import Store from './src/store/Store.js';
8
+ export { MemoryStore, CookieStore, sessionMiddleware, createKeyFromBase64, encryptToBase64, decryptFromBase64, Session, };
9
+ export type { SessionData, Store };
package/esm/mod.js ADDED
@@ -0,0 +1,6 @@
1
+ import MemoryStore from './src/store/MemoryStore.js';
2
+ import CookieStore from './src/store/CookieStore.js';
3
+ import { createKeyFromBase64, encryptToBase64, decryptFromBase64 } from './src/Crypto.js';
4
+ import { sessionMiddleware } from './src/Middleware.js';
5
+ import { Session } from './src/Session.js';
6
+ export { MemoryStore, CookieStore, sessionMiddleware, createKeyFromBase64, encryptToBase64, decryptFromBase64, Session, };
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "module"
3
+ }
@@ -0,0 +1,3 @@
1
+ export declare function createKeyFromBase64(key_string: string): Promise<CryptoKey>;
2
+ export declare function decryptFromBase64(key: CryptoKey, base64_string: string): Promise<string>;
3
+ export declare function encryptToBase64(key: CryptoKey, raw_string: string): Promise<string>;
@@ -0,0 +1,29 @@
1
+ import { decode, encode, } from "../deps/deno.land/std@0.198.0/encoding/base64.js";
2
+ export async function createKeyFromBase64(key_string) {
3
+ const key_decoded = decode(key_string);
4
+ const key = await crypto.subtle.importKey('raw', key_decoded, 'AES-GCM', true, ['encrypt', 'decrypt']);
5
+ return key;
6
+ }
7
+ export async function decryptFromBase64(key, base64_string) {
8
+ const payload_bytes = decode(base64_string);
9
+ const iv = payload_bytes.slice(0, 12);
10
+ const encrypted_payload_bytes = payload_bytes.slice(12, payload_bytes.length);
11
+ const decrypted_payload = await crypto.subtle.decrypt({
12
+ 'name': key.algorithm.name,
13
+ iv
14
+ }, key, encrypted_payload_bytes);
15
+ return (new TextDecoder).decode(decrypted_payload);
16
+ }
17
+ export async function encryptToBase64(key, raw_string) {
18
+ const iv = crypto.getRandomValues(new Uint8Array(12));
19
+ const encrypted_payload = await crypto.subtle.encrypt({
20
+ name: key.algorithm.name,
21
+ iv
22
+ }, key, (new TextEncoder).encode(raw_string));
23
+ const encrypted_payload_bytes = new Uint8Array(encrypted_payload);
24
+ const payload_bytes = new Uint8Array(encrypted_payload_bytes.length + iv.length);
25
+ payload_bytes.set(iv);
26
+ payload_bytes.set(encrypted_payload_bytes, iv.length);
27
+ const payload_string = encode(payload_bytes);
28
+ return payload_string;
29
+ }
@@ -0,0 +1,13 @@
1
+ import { MiddlewareHandler } from '../deps.js';
2
+ import Store from './store/Store.js';
3
+ import CookieStore from './store/CookieStore.js';
4
+ import { CookieOptions } from '../deps.js';
5
+ interface SessionOptions {
6
+ store: Store | CookieStore;
7
+ encryptionKey?: CryptoKey;
8
+ expireAfterSeconds?: number;
9
+ cookieOptions?: CookieOptions;
10
+ sessionCookieName?: string;
11
+ }
12
+ export declare function sessionMiddleware(options: SessionOptions): MiddlewareHandler;
13
+ export {};
@@ -0,0 +1,85 @@
1
+ import { nanoid } from '../deps.js';
2
+ import { getCookie, setCookie } from '../deps.js';
3
+ import CookieStore from './store/CookieStore.js';
4
+ import { Session, decryptFromBase64, encryptToBase64 } from '../mod.js';
5
+ export function sessionMiddleware(options) {
6
+ const store = options.store;
7
+ const encryptionKey = options.encryptionKey;
8
+ const expireAfterSeconds = options.expireAfterSeconds;
9
+ const cookieOptions = options.cookieOptions;
10
+ const sessionCookieName = options.sessionCookieName || 'session';
11
+ if (store instanceof CookieStore) {
12
+ store.sessionCookieName = sessionCookieName;
13
+ if (encryptionKey) {
14
+ store.encryptionKey = encryptionKey;
15
+ }
16
+ if (cookieOptions) {
17
+ store.cookieOptions = cookieOptions;
18
+ }
19
+ }
20
+ const middleware = async (c, next) => {
21
+ const session = new Session;
22
+ let sid = '';
23
+ let session_data;
24
+ let createNewSession = false;
25
+ const sessionCookie = getCookie(c, sessionCookieName);
26
+ if (sessionCookie) { // If there is a session cookie present...
27
+ if (store instanceof CookieStore) {
28
+ session_data = await store.getSession(c);
29
+ }
30
+ else {
31
+ sid = encryptionKey ? await decryptFromBase64(encryptionKey, sessionCookie) : sessionCookie;
32
+ session_data = await store.getSessionById(sid);
33
+ }
34
+ if (session_data) {
35
+ session.setCache(session_data);
36
+ if (session.sessionValid()) {
37
+ session.reupSession(expireAfterSeconds);
38
+ }
39
+ else {
40
+ store instanceof CookieStore ? await store.deleteSession(c) : await store.deleteSession(sid);
41
+ createNewSession = true;
42
+ }
43
+ }
44
+ else {
45
+ createNewSession = true;
46
+ }
47
+ }
48
+ else {
49
+ createNewSession = true;
50
+ }
51
+ if (createNewSession) {
52
+ const defaultData = {
53
+ _data: {},
54
+ _expire: null,
55
+ _delete: false,
56
+ _accessed: null,
57
+ };
58
+ if (store instanceof CookieStore) {
59
+ await store.createSession(c, defaultData);
60
+ }
61
+ else {
62
+ sid = await nanoid(21);
63
+ await store.createSession(sid, defaultData);
64
+ }
65
+ session.setCache(defaultData);
66
+ }
67
+ if (!(store instanceof CookieStore)) {
68
+ setCookie(c, sessionCookieName, encryptionKey ? await encryptToBase64(encryptionKey, sid) : sid, cookieOptions);
69
+ }
70
+ session.updateAccess();
71
+ c.set('session', session);
72
+ await next();
73
+ if (c.get('session_key_rotation') === true && !(store instanceof CookieStore)) {
74
+ await store.deleteSession(sid);
75
+ sid = await nanoid(21);
76
+ await store.createSession(sid, session.getCache());
77
+ setCookie(c, sessionCookieName, encryptionKey ? await encryptToBase64(encryptionKey, sid) : sid, cookieOptions);
78
+ }
79
+ store instanceof CookieStore ? await store.persistSessionData(c, session.getCache()) : store.persistSessionData(sid, session.getCache());
80
+ if (session.getCache()._delete) {
81
+ store instanceof CookieStore ? await store.deleteSession(c) : await store.deleteSession(sid);
82
+ }
83
+ };
84
+ return middleware;
85
+ }
@@ -0,0 +1,25 @@
1
+ interface SessionDataEntry {
2
+ value: unknown;
3
+ flash: boolean;
4
+ }
5
+ export interface SessionData {
6
+ _data: Record<string, SessionDataEntry>;
7
+ _expire: string | null;
8
+ _delete: boolean;
9
+ _accessed: string | null;
10
+ }
11
+ export declare class Session {
12
+ private cache;
13
+ constructor();
14
+ setCache(cache_data: SessionData): void;
15
+ getCache(): SessionData;
16
+ setExpiration(expiration: string): void;
17
+ reupSession(expiration: number | null | undefined): void;
18
+ deleteSession(): void;
19
+ sessionValid(): boolean;
20
+ updateAccess(): void;
21
+ get(key: string): unknown;
22
+ set(key: string, value: unknown): void;
23
+ flash(key: string, value: unknown): void;
24
+ }
25
+ export {};
@@ -0,0 +1,64 @@
1
+ export class Session {
2
+ constructor() {
3
+ Object.defineProperty(this, "cache", {
4
+ enumerable: true,
5
+ configurable: true,
6
+ writable: true,
7
+ value: void 0
8
+ });
9
+ this.cache = {
10
+ _data: {},
11
+ _expire: null,
12
+ _delete: false,
13
+ _accessed: null,
14
+ };
15
+ }
16
+ setCache(cache_data) {
17
+ this.cache = cache_data;
18
+ }
19
+ getCache() {
20
+ return this.cache;
21
+ }
22
+ setExpiration(expiration) {
23
+ this.cache._expire = expiration;
24
+ }
25
+ reupSession(expiration) {
26
+ if (expiration) {
27
+ this.setExpiration(new Date(Date.now() + expiration * 1000).toISOString());
28
+ }
29
+ }
30
+ deleteSession() {
31
+ this.cache._delete = true;
32
+ }
33
+ sessionValid() {
34
+ return this.cache._expire == null || Date.now() < new Date(this.cache._expire).getTime();
35
+ }
36
+ updateAccess() {
37
+ this.cache._accessed = new Date().toISOString();
38
+ }
39
+ get(key) {
40
+ const entry = this.cache._data[key];
41
+ if (entry) {
42
+ const value = entry.value;
43
+ if (entry.flash) {
44
+ delete this.cache._data[key];
45
+ }
46
+ return value;
47
+ }
48
+ else {
49
+ return null;
50
+ }
51
+ }
52
+ set(key, value) {
53
+ this.cache._data[key] = {
54
+ value,
55
+ flash: false
56
+ };
57
+ }
58
+ flash(key, value) {
59
+ this.cache._data[key] = {
60
+ value,
61
+ flash: true
62
+ };
63
+ }
64
+ }
@@ -0,0 +1,18 @@
1
+ import { Context, CookieOptions } from '../../deps.js';
2
+ import { SessionData } from '../../mod.js';
3
+ interface CookieStoreOptions {
4
+ encryptionKey?: CryptoKey | null;
5
+ cookieOptions?: CookieOptions;
6
+ sessionCookieName: string;
7
+ }
8
+ declare class CookieStore {
9
+ encryptionKey: CryptoKey | null | undefined;
10
+ cookieOptions: CookieOptions | undefined;
11
+ sessionCookieName: string;
12
+ constructor(options?: CookieStoreOptions);
13
+ getSession(c: Context): Promise<any>;
14
+ createSession(c: Context, initial_data: SessionData): Promise<void>;
15
+ deleteSession(c: Context): Promise<void>;
16
+ persistSessionData(c: Context, session_data: SessionData): Promise<void>;
17
+ }
18
+ export default CookieStore;
@@ -0,0 +1,52 @@
1
+ import { getCookie, setCookie } from '../../deps.js';
2
+ import { decryptFromBase64, encryptToBase64 } from '../../mod.js';
3
+ class CookieStore {
4
+ constructor(options) {
5
+ Object.defineProperty(this, "encryptionKey", {
6
+ enumerable: true,
7
+ configurable: true,
8
+ writable: true,
9
+ value: void 0
10
+ });
11
+ Object.defineProperty(this, "cookieOptions", {
12
+ enumerable: true,
13
+ configurable: true,
14
+ writable: true,
15
+ value: void 0
16
+ });
17
+ Object.defineProperty(this, "sessionCookieName", {
18
+ enumerable: true,
19
+ configurable: true,
20
+ writable: true,
21
+ value: void 0
22
+ });
23
+ this.encryptionKey = options?.encryptionKey;
24
+ this.cookieOptions = options?.cookieOptions;
25
+ this.sessionCookieName = options?.sessionCookieName || 'session';
26
+ }
27
+ async getSession(c) {
28
+ let session_data;
29
+ const sessionCookie = getCookie(c, this.sessionCookieName);
30
+ if (this.encryptionKey && sessionCookie) {
31
+ session_data = await decryptFromBase64(this.encryptionKey, sessionCookie);
32
+ if (session_data) {
33
+ return JSON.parse(session_data);
34
+ }
35
+ }
36
+ else {
37
+ return null;
38
+ }
39
+ }
40
+ async createSession(c, initial_data) {
41
+ const stringified_data = JSON.stringify(initial_data);
42
+ setCookie(c, this.sessionCookieName, this.encryptionKey ? await encryptToBase64(this.encryptionKey, stringified_data) : stringified_data, this.cookieOptions);
43
+ }
44
+ async deleteSession(c) {
45
+ setCookie(c, this.sessionCookieName, this.encryptionKey ? await encryptToBase64(this.encryptionKey, '') : '', this.cookieOptions);
46
+ }
47
+ async persistSessionData(c, session_data) {
48
+ const stringified_data = JSON.stringify(session_data);
49
+ setCookie(c, this.sessionCookieName, this.encryptionKey ? await encryptToBase64(this.encryptionKey, stringified_data) : stringified_data, this.cookieOptions);
50
+ }
51
+ }
52
+ export default CookieStore;
@@ -0,0 +1,11 @@
1
+ import Store from './Store.js';
2
+ import { SessionData } from '../../mod.js';
3
+ declare class MemoryStore implements Store {
4
+ private data;
5
+ constructor();
6
+ getSessionById(sid: string): SessionData | null | undefined;
7
+ createSession(sid: string, initial_data: SessionData): void;
8
+ deleteSession(sid: string): void;
9
+ persistSessionData(sid: string, session_data: SessionData): void;
10
+ }
11
+ export default MemoryStore;
@@ -0,0 +1,24 @@
1
+ class MemoryStore {
2
+ constructor() {
3
+ Object.defineProperty(this, "data", {
4
+ enumerable: true,
5
+ configurable: true,
6
+ writable: true,
7
+ value: void 0
8
+ });
9
+ this.data = new Map;
10
+ }
11
+ getSessionById(sid) {
12
+ return this.data.has(sid) ? this.data.get(sid) : null;
13
+ }
14
+ createSession(sid, initial_data) {
15
+ this.data.set(sid, initial_data);
16
+ }
17
+ deleteSession(sid) {
18
+ this.data.delete(sid);
19
+ }
20
+ persistSessionData(sid, session_data) {
21
+ this.data.set(sid, session_data);
22
+ }
23
+ }
24
+ export default MemoryStore;
@@ -0,0 +1,7 @@
1
+ import { SessionData } from "../../mod.js";
2
+ export default interface Store {
3
+ getSessionById(sessionId?: string): SessionData | null | undefined | Promise<SessionData | null | undefined>;
4
+ createSession(sessionId: string, initialData: SessionData): Promise<void> | void;
5
+ persistSessionData(sessionId: string, sessionData: SessionData): Promise<void> | void;
6
+ deleteSession(sessionId: string): Promise<void> | void;
7
+ }
@@ -0,0 +1 @@
1
+ export {};
package/package.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "module": "./esm/mod.js",
3
+ "main": "./script/mod.js",
4
+ "name": "hono-sessions",
5
+ "version": "0.1.0",
6
+ "description": "Cookie-based sessions for Hono web framework",
7
+ "license": "MIT",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/jcs224/hono_sessions.git"
11
+ },
12
+ "bugs": {
13
+ "url": "https://github.com/jcs224/hono_sessions/issues"
14
+ },
15
+ "exports": {
16
+ ".": {
17
+ "import": "./esm/mod.js",
18
+ "require": "./script/mod.js"
19
+ }
20
+ },
21
+ "scripts": {
22
+ "test": "node test_runner.js"
23
+ },
24
+ "dependencies": {
25
+ "hono": "^3.5.1",
26
+ "nanoid": "4.0.0"
27
+ },
28
+ "devDependencies": {
29
+ "picocolors": "^1.0.0"
30
+ }
31
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * CREDIT: https://gist.github.com/enepomnyaschih/72c423f727d395eeaa09697058238727
3
+ * Encodes a given Uint8Array, ArrayBuffer or string into RFC4648 base64 representation
4
+ * @param data
5
+ */
6
+ export declare function encode(data: ArrayBuffer | string): string;
7
+ /**
8
+ * Decodes a given RFC4648 base64 encoded string
9
+ * @param b64
10
+ */
11
+ export declare function decode(b64: string): Uint8Array;
@@ -0,0 +1,145 @@
1
+ "use strict";
2
+ // Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
3
+ // This module is browser compatible.
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.decode = exports.encode = void 0;
6
+ /**
7
+ * {@linkcode encode} and {@linkcode decode} for
8
+ * [base64](https://en.wikipedia.org/wiki/Base64) encoding.
9
+ *
10
+ * This module is browser compatible.
11
+ *
12
+ * @example
13
+ * ```ts
14
+ * import {
15
+ * decode,
16
+ * encode,
17
+ * } from "https://deno.land/std@$STD_VERSION/encoding/base64.ts";
18
+ *
19
+ * const b64Repr = "Zm9vYg==";
20
+ *
21
+ * const binaryData = decode(b64Repr);
22
+ * console.log(binaryData);
23
+ * // => Uint8Array [ 102, 111, 111, 98 ]
24
+ *
25
+ * console.log(encode(binaryData));
26
+ * // => Zm9vYg==
27
+ * ```
28
+ *
29
+ * @module
30
+ */
31
+ const base64abc = [
32
+ "A",
33
+ "B",
34
+ "C",
35
+ "D",
36
+ "E",
37
+ "F",
38
+ "G",
39
+ "H",
40
+ "I",
41
+ "J",
42
+ "K",
43
+ "L",
44
+ "M",
45
+ "N",
46
+ "O",
47
+ "P",
48
+ "Q",
49
+ "R",
50
+ "S",
51
+ "T",
52
+ "U",
53
+ "V",
54
+ "W",
55
+ "X",
56
+ "Y",
57
+ "Z",
58
+ "a",
59
+ "b",
60
+ "c",
61
+ "d",
62
+ "e",
63
+ "f",
64
+ "g",
65
+ "h",
66
+ "i",
67
+ "j",
68
+ "k",
69
+ "l",
70
+ "m",
71
+ "n",
72
+ "o",
73
+ "p",
74
+ "q",
75
+ "r",
76
+ "s",
77
+ "t",
78
+ "u",
79
+ "v",
80
+ "w",
81
+ "x",
82
+ "y",
83
+ "z",
84
+ "0",
85
+ "1",
86
+ "2",
87
+ "3",
88
+ "4",
89
+ "5",
90
+ "6",
91
+ "7",
92
+ "8",
93
+ "9",
94
+ "+",
95
+ "/",
96
+ ];
97
+ /**
98
+ * CREDIT: https://gist.github.com/enepomnyaschih/72c423f727d395eeaa09697058238727
99
+ * Encodes a given Uint8Array, ArrayBuffer or string into RFC4648 base64 representation
100
+ * @param data
101
+ */
102
+ function encode(data) {
103
+ const uint8 = typeof data === "string"
104
+ ? new TextEncoder().encode(data)
105
+ : data instanceof Uint8Array
106
+ ? data
107
+ : new Uint8Array(data);
108
+ let result = "", i;
109
+ const l = uint8.length;
110
+ for (i = 2; i < l; i += 3) {
111
+ result += base64abc[uint8[i - 2] >> 2];
112
+ result += base64abc[((uint8[i - 2] & 0x03) << 4) | (uint8[i - 1] >> 4)];
113
+ result += base64abc[((uint8[i - 1] & 0x0f) << 2) | (uint8[i] >> 6)];
114
+ result += base64abc[uint8[i] & 0x3f];
115
+ }
116
+ if (i === l + 1) {
117
+ // 1 octet yet to write
118
+ result += base64abc[uint8[i - 2] >> 2];
119
+ result += base64abc[(uint8[i - 2] & 0x03) << 4];
120
+ result += "==";
121
+ }
122
+ if (i === l) {
123
+ // 2 octets yet to write
124
+ result += base64abc[uint8[i - 2] >> 2];
125
+ result += base64abc[((uint8[i - 2] & 0x03) << 4) | (uint8[i - 1] >> 4)];
126
+ result += base64abc[(uint8[i - 1] & 0x0f) << 2];
127
+ result += "=";
128
+ }
129
+ return result;
130
+ }
131
+ exports.encode = encode;
132
+ /**
133
+ * Decodes a given RFC4648 base64 encoded string
134
+ * @param b64
135
+ */
136
+ function decode(b64) {
137
+ const binString = atob(b64);
138
+ const size = binString.length;
139
+ const bytes = new Uint8Array(size);
140
+ for (let i = 0; i < size; i++) {
141
+ bytes[i] = binString.charCodeAt(i);
142
+ }
143
+ return bytes;
144
+ }
145
+ exports.decode = decode;
@@ -0,0 +1,4 @@
1
+ export { nanoid } from 'nanoid/async';
2
+ export type { MiddlewareHandler, Context } from 'hono';
3
+ export { getCookie, setCookie } from 'hono/cookie';
4
+ export type { CookieOptions } from 'hono/utils/cookie';
package/script/deps.js ADDED
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.setCookie = exports.getCookie = exports.nanoid = void 0;
4
+ var async_1 = require("nanoid/async");
5
+ Object.defineProperty(exports, "nanoid", { enumerable: true, get: function () { return async_1.nanoid; } });
6
+ var cookie_1 = require("hono/cookie");
7
+ Object.defineProperty(exports, "getCookie", { enumerable: true, get: function () { return cookie_1.getCookie; } });
8
+ Object.defineProperty(exports, "setCookie", { enumerable: true, get: function () { return cookie_1.setCookie; } });
@@ -0,0 +1,9 @@
1
+ import MemoryStore from './src/store/MemoryStore.js';
2
+ import CookieStore from './src/store/CookieStore.js';
3
+ import { createKeyFromBase64, encryptToBase64, decryptFromBase64 } from './src/Crypto.js';
4
+ import { sessionMiddleware } from './src/Middleware.js';
5
+ import { Session } from './src/Session.js';
6
+ import type { SessionData } from './src/Session.js';
7
+ import Store from './src/store/Store.js';
8
+ export { MemoryStore, CookieStore, sessionMiddleware, createKeyFromBase64, encryptToBase64, decryptFromBase64, Session, };
9
+ export type { SessionData, Store };
package/script/mod.js ADDED
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.Session = exports.decryptFromBase64 = exports.encryptToBase64 = exports.createKeyFromBase64 = exports.sessionMiddleware = exports.CookieStore = exports.MemoryStore = void 0;
7
+ const MemoryStore_js_1 = __importDefault(require("./src/store/MemoryStore.js"));
8
+ exports.MemoryStore = MemoryStore_js_1.default;
9
+ const CookieStore_js_1 = __importDefault(require("./src/store/CookieStore.js"));
10
+ exports.CookieStore = CookieStore_js_1.default;
11
+ const Crypto_js_1 = require("./src/Crypto.js");
12
+ Object.defineProperty(exports, "createKeyFromBase64", { enumerable: true, get: function () { return Crypto_js_1.createKeyFromBase64; } });
13
+ Object.defineProperty(exports, "encryptToBase64", { enumerable: true, get: function () { return Crypto_js_1.encryptToBase64; } });
14
+ Object.defineProperty(exports, "decryptFromBase64", { enumerable: true, get: function () { return Crypto_js_1.decryptFromBase64; } });
15
+ const Middleware_js_1 = require("./src/Middleware.js");
16
+ Object.defineProperty(exports, "sessionMiddleware", { enumerable: true, get: function () { return Middleware_js_1.sessionMiddleware; } });
17
+ const Session_js_1 = require("./src/Session.js");
18
+ Object.defineProperty(exports, "Session", { enumerable: true, get: function () { return Session_js_1.Session; } });
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "commonjs"
3
+ }
@@ -0,0 +1,3 @@
1
+ export declare function createKeyFromBase64(key_string: string): Promise<CryptoKey>;
2
+ export declare function decryptFromBase64(key: CryptoKey, base64_string: string): Promise<string>;
3
+ export declare function encryptToBase64(key: CryptoKey, raw_string: string): Promise<string>;
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.encryptToBase64 = exports.decryptFromBase64 = exports.createKeyFromBase64 = void 0;
4
+ const base64_js_1 = require("../deps/deno.land/std@0.198.0/encoding/base64.js");
5
+ async function createKeyFromBase64(key_string) {
6
+ const key_decoded = (0, base64_js_1.decode)(key_string);
7
+ const key = await crypto.subtle.importKey('raw', key_decoded, 'AES-GCM', true, ['encrypt', 'decrypt']);
8
+ return key;
9
+ }
10
+ exports.createKeyFromBase64 = createKeyFromBase64;
11
+ async function decryptFromBase64(key, base64_string) {
12
+ const payload_bytes = (0, base64_js_1.decode)(base64_string);
13
+ const iv = payload_bytes.slice(0, 12);
14
+ const encrypted_payload_bytes = payload_bytes.slice(12, payload_bytes.length);
15
+ const decrypted_payload = await crypto.subtle.decrypt({
16
+ 'name': key.algorithm.name,
17
+ iv
18
+ }, key, encrypted_payload_bytes);
19
+ return (new TextDecoder).decode(decrypted_payload);
20
+ }
21
+ exports.decryptFromBase64 = decryptFromBase64;
22
+ async function encryptToBase64(key, raw_string) {
23
+ const iv = crypto.getRandomValues(new Uint8Array(12));
24
+ const encrypted_payload = await crypto.subtle.encrypt({
25
+ name: key.algorithm.name,
26
+ iv
27
+ }, key, (new TextEncoder).encode(raw_string));
28
+ const encrypted_payload_bytes = new Uint8Array(encrypted_payload);
29
+ const payload_bytes = new Uint8Array(encrypted_payload_bytes.length + iv.length);
30
+ payload_bytes.set(iv);
31
+ payload_bytes.set(encrypted_payload_bytes, iv.length);
32
+ const payload_string = (0, base64_js_1.encode)(payload_bytes);
33
+ return payload_string;
34
+ }
35
+ exports.encryptToBase64 = encryptToBase64;
@@ -0,0 +1,13 @@
1
+ import { MiddlewareHandler } from '../deps.js';
2
+ import Store from './store/Store.js';
3
+ import CookieStore from './store/CookieStore.js';
4
+ import { CookieOptions } from '../deps.js';
5
+ interface SessionOptions {
6
+ store: Store | CookieStore;
7
+ encryptionKey?: CryptoKey;
8
+ expireAfterSeconds?: number;
9
+ cookieOptions?: CookieOptions;
10
+ sessionCookieName?: string;
11
+ }
12
+ export declare function sessionMiddleware(options: SessionOptions): MiddlewareHandler;
13
+ export {};
@@ -0,0 +1,92 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.sessionMiddleware = void 0;
7
+ const deps_js_1 = require("../deps.js");
8
+ const deps_js_2 = require("../deps.js");
9
+ const CookieStore_js_1 = __importDefault(require("./store/CookieStore.js"));
10
+ const mod_js_1 = require("../mod.js");
11
+ function sessionMiddleware(options) {
12
+ const store = options.store;
13
+ const encryptionKey = options.encryptionKey;
14
+ const expireAfterSeconds = options.expireAfterSeconds;
15
+ const cookieOptions = options.cookieOptions;
16
+ const sessionCookieName = options.sessionCookieName || 'session';
17
+ if (store instanceof CookieStore_js_1.default) {
18
+ store.sessionCookieName = sessionCookieName;
19
+ if (encryptionKey) {
20
+ store.encryptionKey = encryptionKey;
21
+ }
22
+ if (cookieOptions) {
23
+ store.cookieOptions = cookieOptions;
24
+ }
25
+ }
26
+ const middleware = async (c, next) => {
27
+ const session = new mod_js_1.Session;
28
+ let sid = '';
29
+ let session_data;
30
+ let createNewSession = false;
31
+ const sessionCookie = (0, deps_js_2.getCookie)(c, sessionCookieName);
32
+ if (sessionCookie) { // If there is a session cookie present...
33
+ if (store instanceof CookieStore_js_1.default) {
34
+ session_data = await store.getSession(c);
35
+ }
36
+ else {
37
+ sid = encryptionKey ? await (0, mod_js_1.decryptFromBase64)(encryptionKey, sessionCookie) : sessionCookie;
38
+ session_data = await store.getSessionById(sid);
39
+ }
40
+ if (session_data) {
41
+ session.setCache(session_data);
42
+ if (session.sessionValid()) {
43
+ session.reupSession(expireAfterSeconds);
44
+ }
45
+ else {
46
+ store instanceof CookieStore_js_1.default ? await store.deleteSession(c) : await store.deleteSession(sid);
47
+ createNewSession = true;
48
+ }
49
+ }
50
+ else {
51
+ createNewSession = true;
52
+ }
53
+ }
54
+ else {
55
+ createNewSession = true;
56
+ }
57
+ if (createNewSession) {
58
+ const defaultData = {
59
+ _data: {},
60
+ _expire: null,
61
+ _delete: false,
62
+ _accessed: null,
63
+ };
64
+ if (store instanceof CookieStore_js_1.default) {
65
+ await store.createSession(c, defaultData);
66
+ }
67
+ else {
68
+ sid = await (0, deps_js_1.nanoid)(21);
69
+ await store.createSession(sid, defaultData);
70
+ }
71
+ session.setCache(defaultData);
72
+ }
73
+ if (!(store instanceof CookieStore_js_1.default)) {
74
+ (0, deps_js_2.setCookie)(c, sessionCookieName, encryptionKey ? await (0, mod_js_1.encryptToBase64)(encryptionKey, sid) : sid, cookieOptions);
75
+ }
76
+ session.updateAccess();
77
+ c.set('session', session);
78
+ await next();
79
+ if (c.get('session_key_rotation') === true && !(store instanceof CookieStore_js_1.default)) {
80
+ await store.deleteSession(sid);
81
+ sid = await (0, deps_js_1.nanoid)(21);
82
+ await store.createSession(sid, session.getCache());
83
+ (0, deps_js_2.setCookie)(c, sessionCookieName, encryptionKey ? await (0, mod_js_1.encryptToBase64)(encryptionKey, sid) : sid, cookieOptions);
84
+ }
85
+ store instanceof CookieStore_js_1.default ? await store.persistSessionData(c, session.getCache()) : store.persistSessionData(sid, session.getCache());
86
+ if (session.getCache()._delete) {
87
+ store instanceof CookieStore_js_1.default ? await store.deleteSession(c) : await store.deleteSession(sid);
88
+ }
89
+ };
90
+ return middleware;
91
+ }
92
+ exports.sessionMiddleware = sessionMiddleware;
@@ -0,0 +1,25 @@
1
+ interface SessionDataEntry {
2
+ value: unknown;
3
+ flash: boolean;
4
+ }
5
+ export interface SessionData {
6
+ _data: Record<string, SessionDataEntry>;
7
+ _expire: string | null;
8
+ _delete: boolean;
9
+ _accessed: string | null;
10
+ }
11
+ export declare class Session {
12
+ private cache;
13
+ constructor();
14
+ setCache(cache_data: SessionData): void;
15
+ getCache(): SessionData;
16
+ setExpiration(expiration: string): void;
17
+ reupSession(expiration: number | null | undefined): void;
18
+ deleteSession(): void;
19
+ sessionValid(): boolean;
20
+ updateAccess(): void;
21
+ get(key: string): unknown;
22
+ set(key: string, value: unknown): void;
23
+ flash(key: string, value: unknown): void;
24
+ }
25
+ export {};
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Session = void 0;
4
+ class Session {
5
+ constructor() {
6
+ Object.defineProperty(this, "cache", {
7
+ enumerable: true,
8
+ configurable: true,
9
+ writable: true,
10
+ value: void 0
11
+ });
12
+ this.cache = {
13
+ _data: {},
14
+ _expire: null,
15
+ _delete: false,
16
+ _accessed: null,
17
+ };
18
+ }
19
+ setCache(cache_data) {
20
+ this.cache = cache_data;
21
+ }
22
+ getCache() {
23
+ return this.cache;
24
+ }
25
+ setExpiration(expiration) {
26
+ this.cache._expire = expiration;
27
+ }
28
+ reupSession(expiration) {
29
+ if (expiration) {
30
+ this.setExpiration(new Date(Date.now() + expiration * 1000).toISOString());
31
+ }
32
+ }
33
+ deleteSession() {
34
+ this.cache._delete = true;
35
+ }
36
+ sessionValid() {
37
+ return this.cache._expire == null || Date.now() < new Date(this.cache._expire).getTime();
38
+ }
39
+ updateAccess() {
40
+ this.cache._accessed = new Date().toISOString();
41
+ }
42
+ get(key) {
43
+ const entry = this.cache._data[key];
44
+ if (entry) {
45
+ const value = entry.value;
46
+ if (entry.flash) {
47
+ delete this.cache._data[key];
48
+ }
49
+ return value;
50
+ }
51
+ else {
52
+ return null;
53
+ }
54
+ }
55
+ set(key, value) {
56
+ this.cache._data[key] = {
57
+ value,
58
+ flash: false
59
+ };
60
+ }
61
+ flash(key, value) {
62
+ this.cache._data[key] = {
63
+ value,
64
+ flash: true
65
+ };
66
+ }
67
+ }
68
+ exports.Session = Session;
@@ -0,0 +1,18 @@
1
+ import { Context, CookieOptions } from '../../deps.js';
2
+ import { SessionData } from '../../mod.js';
3
+ interface CookieStoreOptions {
4
+ encryptionKey?: CryptoKey | null;
5
+ cookieOptions?: CookieOptions;
6
+ sessionCookieName: string;
7
+ }
8
+ declare class CookieStore {
9
+ encryptionKey: CryptoKey | null | undefined;
10
+ cookieOptions: CookieOptions | undefined;
11
+ sessionCookieName: string;
12
+ constructor(options?: CookieStoreOptions);
13
+ getSession(c: Context): Promise<any>;
14
+ createSession(c: Context, initial_data: SessionData): Promise<void>;
15
+ deleteSession(c: Context): Promise<void>;
16
+ persistSessionData(c: Context, session_data: SessionData): Promise<void>;
17
+ }
18
+ export default CookieStore;
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const deps_js_1 = require("../../deps.js");
4
+ const mod_js_1 = require("../../mod.js");
5
+ class CookieStore {
6
+ constructor(options) {
7
+ Object.defineProperty(this, "encryptionKey", {
8
+ enumerable: true,
9
+ configurable: true,
10
+ writable: true,
11
+ value: void 0
12
+ });
13
+ Object.defineProperty(this, "cookieOptions", {
14
+ enumerable: true,
15
+ configurable: true,
16
+ writable: true,
17
+ value: void 0
18
+ });
19
+ Object.defineProperty(this, "sessionCookieName", {
20
+ enumerable: true,
21
+ configurable: true,
22
+ writable: true,
23
+ value: void 0
24
+ });
25
+ this.encryptionKey = options?.encryptionKey;
26
+ this.cookieOptions = options?.cookieOptions;
27
+ this.sessionCookieName = options?.sessionCookieName || 'session';
28
+ }
29
+ async getSession(c) {
30
+ let session_data;
31
+ const sessionCookie = (0, deps_js_1.getCookie)(c, this.sessionCookieName);
32
+ if (this.encryptionKey && sessionCookie) {
33
+ session_data = await (0, mod_js_1.decryptFromBase64)(this.encryptionKey, sessionCookie);
34
+ if (session_data) {
35
+ return JSON.parse(session_data);
36
+ }
37
+ }
38
+ else {
39
+ return null;
40
+ }
41
+ }
42
+ async createSession(c, initial_data) {
43
+ const stringified_data = JSON.stringify(initial_data);
44
+ (0, deps_js_1.setCookie)(c, this.sessionCookieName, this.encryptionKey ? await (0, mod_js_1.encryptToBase64)(this.encryptionKey, stringified_data) : stringified_data, this.cookieOptions);
45
+ }
46
+ async deleteSession(c) {
47
+ (0, deps_js_1.setCookie)(c, this.sessionCookieName, this.encryptionKey ? await (0, mod_js_1.encryptToBase64)(this.encryptionKey, '') : '', this.cookieOptions);
48
+ }
49
+ async persistSessionData(c, session_data) {
50
+ const stringified_data = JSON.stringify(session_data);
51
+ (0, deps_js_1.setCookie)(c, this.sessionCookieName, this.encryptionKey ? await (0, mod_js_1.encryptToBase64)(this.encryptionKey, stringified_data) : stringified_data, this.cookieOptions);
52
+ }
53
+ }
54
+ exports.default = CookieStore;
@@ -0,0 +1,11 @@
1
+ import Store from './Store.js';
2
+ import { SessionData } from '../../mod.js';
3
+ declare class MemoryStore implements Store {
4
+ private data;
5
+ constructor();
6
+ getSessionById(sid: string): SessionData | null | undefined;
7
+ createSession(sid: string, initial_data: SessionData): void;
8
+ deleteSession(sid: string): void;
9
+ persistSessionData(sid: string, session_data: SessionData): void;
10
+ }
11
+ export default MemoryStore;
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ class MemoryStore {
4
+ constructor() {
5
+ Object.defineProperty(this, "data", {
6
+ enumerable: true,
7
+ configurable: true,
8
+ writable: true,
9
+ value: void 0
10
+ });
11
+ this.data = new Map;
12
+ }
13
+ getSessionById(sid) {
14
+ return this.data.has(sid) ? this.data.get(sid) : null;
15
+ }
16
+ createSession(sid, initial_data) {
17
+ this.data.set(sid, initial_data);
18
+ }
19
+ deleteSession(sid) {
20
+ this.data.delete(sid);
21
+ }
22
+ persistSessionData(sid, session_data) {
23
+ this.data.set(sid, session_data);
24
+ }
25
+ }
26
+ exports.default = MemoryStore;
@@ -0,0 +1,7 @@
1
+ import { SessionData } from "../../mod.js";
2
+ export default interface Store {
3
+ getSessionById(sessionId?: string): SessionData | null | undefined | Promise<SessionData | null | undefined>;
4
+ createSession(sessionId: string, initialData: SessionData): Promise<void> | void;
5
+ persistSessionData(sessionId: string, sessionData: SessionData): Promise<void> | void;
6
+ deleteSession(sessionId: string): Promise<void> | void;
7
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });