@stacksjs/router
Version:
The Stacks framework router.
74 lines (72 loc) • 2.06 kB
JavaScript
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;
}
}