Files
MineGeo/shared/password-recovery.ts

42 lines
1.1 KiB
TypeScript

import { createHmac, timingSafeEqual } from "node:crypto";
export const recoveryCookie = "mg_password_recovery";
function signature(value: string, secret: string) {
return createHmac("sha256", secret)
.update("minegeo-password-recovery:" + value)
.digest("hex");
}
export function createRecoveryGrant(
userId: string,
sessionId: string,
secret: string,
now = Date.now(),
) {
const value = `${userId}:${sessionId}:${Math.floor(now / 1000) + 600}`;
return `${value}:${signature(value, secret)}`;
}
export function verifyRecoveryGrant(
token: string | undefined,
userId: string,
sessionId: string,
secret: string,
now = Date.now(),
) {
const parts = token?.split(":");
if (
!parts ||
parts.length !== 4 ||
parts[0] !== userId ||
parts[1] !== sessionId ||
!/^\d+$/.test(parts[2]) ||
!/^[0-9a-f]{64}$/.test(parts[3])
)
return false;
const expires = Number(parts[2]),
time = Math.floor(now / 1000);
if (expires <= time || expires > time + 600) return false;
return timingSafeEqual(
Buffer.from(parts[3], "hex"),
Buffer.from(signature(parts.slice(0, 3).join(":"), secret), "hex"),
);
}