Skip to main content
Home
It is unknown whether this package works with Cloudflare Workers, Node.js, Deno, Bun, Browsers
It is unknown whether this package works with Cloudflare Workers
It is unknown whether this package works with Node.js
It is unknown whether this package works with Deno
It is unknown whether this package works with Bun
It is unknown whether this package works with Browsers
JSR Score
29%
Published
4 months ago (0.0.9)
import { getCookies, setCookie } from "jsr:/@std/http@1.0.13/cookie"; import { generateKey, signJWT, validateJWT } from "jsr:@cross/jwt@0.5.1"; export { signJWT, validateJWT } from "jsr:@cross/jwt@0.5.1" import type { CookieOptions } from "./cookie_option.ts"; import { Session } from "./session.ts"; export type { WithSession } from "./interface.ts"; export type { Session } from "./session.ts"; export function key(): Promise<CryptoKey> { const key = Deno.env.get("APP_KEY"); if (!key) { console.warn( "[FRESH SESSION] Warning: We didn't detect a env variable `APP_KEY`, if you are in production please fix this ASAP to avoid any security issue.", ); } return generateKey(key || "not-secret", { algorithm: "HS512", allowInsecureKeyLengths: true, }); } export function createCookieSessionStorage( cookieOptions?: CookieOptions, ): Promise<CookieSessionStorage> { let cookieOptionsParam = cookieOptions; if (!cookieOptionsParam) { cookieOptionsParam = {}; } return CookieSessionStorage.init(cookieOptionsParam); } export class CookieSessionStorage { #key: CryptoKey; #cookieOptions: CookieOptions; constructor(key: CryptoKey, cookieOptions: CookieOptions) { this.#key = key; this.#cookieOptions = cookieOptions; } static async init( cookieOptions: CookieOptions, ): Promise<CookieSessionStorage> { return new CookieSessionStorage(await key(), cookieOptions); } create(): Session { return new Session(); } exists(sessionId: string): Promise<boolean> { return Promise.resolve(validateJWT(sessionId, this.#key)) .then(() => true) .catch((e) => { console.warn("Invalid JWT token, creating new session..."); return false; }); } async get(sessionId: string): Promise<Session> { const payload = (await validateJWT(sessionId, this.#key)) ?? {}; const { _flash = {}, ...data } = payload as any; return new Session(data as object, _flash); } async persist(response: Response, session: Session): Promise<Response> { if (session.doKeyRotate) { this.keyRotate(); } setCookie(response.headers, { name: "sessionId", value: await signJWT( { ...session.data, _flash: session.flashedData }, this.#key, ), path: "/", ...this.#cookieOptions, }); return response; } /** * Does not work in cookie sessions. */ keyRotate() { console.warn( "%c*****************************************************\n* '.keyRotate' is not supported for cookie sessions *\n*****************************************************", "color: yellow;", ); } } export function cookieSession<T>( cookieOptions: CookieOptions & { apply: (ctx: T, session: Session) => void; get: (ctx: T) => Session; headers: (ctx: T) => Headers; next: (ctx: T) => Response | Promise<Response>; }, ): (ctx: T) => Promise<Response> { return async (ctx) => { const { sessionId } = getCookies(cookieOptions?.headers(ctx)); const cookieSessionStorage = await createCookieSessionStorage( cookieOptions, ); if (sessionId && (await cookieSessionStorage.exists(sessionId))) { cookieOptions?.apply(ctx, await cookieSessionStorage.get(sessionId)); } if (!cookieOptions?.get(ctx)) { cookieOptions?.apply(ctx, cookieSessionStorage.create()); } const response = await cookieOptions.next(ctx); const session = cookieOptions?.get(ctx); return session ? cookieSessionStorage.persist(response, session) : response; }; }