UNPKG

@stacksjs/router

Version:
74 lines (72 loc) 2.06 kB
import { decrypt, encrypt } from "@stacksjs/security"; export class EncryptedSessionStore { inner; opts; constructor(inner, opts = {}) { this.inner = inner; this.opts = opts; } async set(sid, session, ttl) { const envelope = await this.wrap(sid, session); await this.inner.set(sid, envelope, ttl); } async touch(sid, session, ttl) { const envelope = await this.wrap(sid, session); if (this.inner.touch) await this.inner.touch(sid, envelope, ttl); else await this.inner.set(sid, envelope, ttl); } async get(sid) { const stored = await this.inner.get(sid); if (!stored) return null; return this.unwrap(stored); } destroy(sid) { return this.inner.destroy(sid); } async all() { const wrapped = await this.inner.all?.() ?? {}, out = {}; for (const [sid, envelope] of Object.entries(wrapped)) { const decrypted = await this.unwrap(envelope); if (decrypted) out[sid] = decrypted; } return out; } async length() { if (this.inner.length) return this.inner.length(); return Object.keys(await this.all()).length; } async clear() { if (this.inner.clear) return this.inner.clear(); const sessions = await this.inner.all?.() ?? {}; await Promise.all(Object.keys(sessions).map((sid) => this.inner.destroy(sid))); } async wrap(sid, session) { const { id, ...rest } = session, ciphertext = await encrypt(JSON.stringify(rest), this.opts.appKey); return { _enc: !0, id: id ?? sid, data: ciphertext }; } async unwrap(stored) { if (!stored || typeof stored !== "object") return null; const candidate = stored; if (candidate._enc === !0 && typeof candidate.data === "string") try { const decrypted = await decrypt(candidate.data, this.opts.appKey), parsed = JSON.parse(decrypted); if (candidate.id !== void 0) parsed.id = candidate.id; return parsed; } catch { return null; } return candidate; } }