40 lines
1.5 KiB
JavaScript
40 lines
1.5 KiB
JavaScript
import crypto from "node:crypto";
|
|
|
|
const SECRET = process.env.AUTH_SECRET || "nova-store-dev-secret-change-me";
|
|
|
|
// --- Contraseñas: scrypt (nativo de Node, sin dependencias) ---
|
|
export function hashPassword(password) {
|
|
const salt = crypto.randomBytes(16).toString("hex");
|
|
const hash = crypto.scryptSync(password, salt, 64).toString("hex");
|
|
return `${salt}:${hash}`;
|
|
}
|
|
|
|
export function verifyPassword(password, stored) {
|
|
const [salt, hash] = String(stored).split(":");
|
|
if (!salt || !hash) return false;
|
|
const test = crypto.scryptSync(password, salt, 64).toString("hex");
|
|
const a = Buffer.from(hash, "hex");
|
|
const b = Buffer.from(test, "hex");
|
|
return a.length === b.length && crypto.timingSafeEqual(a, b);
|
|
}
|
|
|
|
// --- Sesión: cookie firmada con HMAC (sin dependencias) ---
|
|
export function signSession(userId) {
|
|
const value = String(userId);
|
|
const sig = crypto.createHmac("sha256", SECRET).update(value).digest("hex");
|
|
return `${value}.${sig}`;
|
|
}
|
|
|
|
export function readSession(cookieValue) {
|
|
if (!cookieValue) return null;
|
|
const i = cookieValue.lastIndexOf(".");
|
|
if (i < 0) return null;
|
|
const value = cookieValue.slice(0, i);
|
|
const sig = cookieValue.slice(i + 1);
|
|
const expected = crypto.createHmac("sha256", SECRET).update(value).digest("hex");
|
|
const a = Buffer.from(sig);
|
|
const b = Buffer.from(expected);
|
|
if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) return null;
|
|
const id = Number(value);
|
|
return Number.isFinite(id) ? id : null;
|
|
}
|