const crypto = require("node:crypto"); const { tokenSecret } = require("./config.cjs"); function nowIso() { return new Date().toISOString(); } function addYears(date, years) { const next = new Date(date); next.setFullYear(next.getFullYear() + years); return next; } function addHours(date, hours) { return new Date(date.getTime() + Number(hours || 0) * 3600000); } function sign(value) { return crypto.createHmac("sha256", tokenSecret).update(value).digest("base64url"); } function createToken(userId) { const payload = Buffer.from(JSON.stringify({ userId, issuedAt: Date.now() })).toString("base64url"); return `${payload}.${sign(payload)}`; } function verifyToken(token) { if (!token || typeof token !== "string" || !token.includes(".")) return null; const [payload, signature] = token.split("."); if (!payload || !signature || sign(payload) !== signature) return null; try { return JSON.parse(Buffer.from(payload, "base64url").toString("utf8")); } catch { return null; } } function passwordHash(password, salt = crypto.randomBytes(16).toString("hex")) { const hash = crypto.pbkdf2Sync(String(password), salt, 120000, 32, "sha256").toString("hex"); return `${salt}:${hash}`; } function checkPassword(password, stored) { const [salt] = String(stored || "").split(":"); if (!salt) return false; return passwordHash(password, salt) === stored; } function daysRemaining(expiresAt) { return Math.max(0, Math.ceil((new Date(expiresAt).getTime() - Date.now()) / 86400000)); } module.exports = { nowIso, addYears, addHours, createToken, verifyToken, passwordHash, checkPassword, daysRemaining, };