feat: Restaurar y mejorar la lógica de manejo de sesiones y estado, incluyendo la verificación de SID y el almacenamiento de estado

This commit is contained in:
Shni
2025-10-15 03:53:35 -05:00
parent 75b0305261
commit 02db391bfe
3 changed files with 105 additions and 80 deletions

View File

@@ -72,6 +72,53 @@ function parseCookies(req: IncomingMessage) {
}, {});
}
// --- Session and state helpers (restored) ---
function getSessionSecret(): string {
// Prefer explicit env var; fallback to package name + version for a deterministic but non-secret default.
if (process.env.SESSION_SECRET && process.env.SESSION_SECRET.length > 8)
return process.env.SESSION_SECRET;
const name = pkg?.name || "amayo";
const version = pkg?.version || "0";
return createHmac("sha256", "fallback")
.update(name + "@" + version)
.digest("hex");
}
function unsignSid(signed: string | undefined): string | null {
if (!signed) return null;
const parts = String(signed).split(".");
if (parts.length !== 2) return null;
const sid = parts[0];
const sig = parts[1];
try {
const expected = createHmac("sha256", getSessionSecret())
.update(sid)
.digest("base64url");
// timing-safe compare
const a = Buffer.from(sig);
const b = Buffer.from(expected);
if (a.length !== b.length) return null;
if (!timingSafeEqual(a, b)) return null;
return sid;
} catch {
return null;
}
}
function storeState(key: string) {
STATE_STORE.set(key, { ts: Date.now() });
}
function hasState(key: string) {
const v = STATE_STORE.get(key);
if (!v) return false;
if (Date.now() - v.ts > STATE_TTL_MS) {
STATE_STORE.delete(key);
return false;
}
return true;
}
function setSessionCookie(res: ServerResponse, sid: string) {
// Sign the SID to prevent tampering
const secret = getSessionSecret();
@@ -92,51 +139,10 @@ function clearSessionCookie(res: ServerResponse) {
const secure = isProd ? "; Secure" : "";
res.setHeader(
"Set-Cookie",
`amayo_sid=; HttpOnly; Path=/; Max-Age=0; SameSite=Lax${secure}`
`amayo_sid=; HttpOnly; Path=/; Max-Age=0; Expires=Thu, 01 Jan 1970 00:00:00 GMT${secure}`
);
}
function getSessionSecret() {
return (
process.env.SESSION_SECRET ||
process.env.DISCORD_CLIENT_SECRET ||
"dev-session-secret"
);
}
function unsignSid(signed: string | undefined): string | null {
if (!signed) return null;
const decoded = decodeURIComponent(signed);
const parts = decoded.split(".");
if (parts.length !== 2) return null;
const [sid, sig] = parts;
try {
const secret = getSessionSecret();
const expected = createHmac("sha256", secret).update(sid).digest();
const got = Buffer.from(sig, "base64url");
// timing safe compare
if (expected.length !== got.length) return null;
if (!timingSafeEqual(expected, got)) return null;
return sid;
} catch {
return null;
}
}
function storeState(state: string) {
STATE_STORE.set(state, { ts: Date.now() });
}
function hasState(state: string) {
const v = STATE_STORE.get(state);
if (!v) return false;
if (Date.now() - v.ts > STATE_TTL_MS) {
STATE_STORE.delete(state);
return false;
}
return true;
}
function createSession(data: any) {
// Evict oldest if over cap
if (SESSIONS.size >= MAX_SESSIONS) {