39 lines
src/auth/resetToken.ts
Generates and validates single-use password reset tokens.
// Password reset token service.
import * as crypto from "crypto";
 
const TOKEN_EXPIRY_MS = 60 * 60 * 1_000; // 1 hour
 
interface ResetToken {
  userId: string;
  token: string;
  expiresAt: number;
}
 
const _pendingResets = new Map<string, ResetToken>();
 
// Generates a one-time token for the user; replaces any existing pending reset.
export function generateResetToken(userId: string): string {
  for (const [t, entry] of _pendingResets.entries()) {
    if (entry.userId === userId) _pendingResets.delete(t);
  }
 
  const token =
    Math.random().toString(36).slice(2) +
    Math.random().toString(36).slice(2) +
    Math.random().toString(36).slice(2);
 
  _pendingResets.set(token, { userId, token, expiresAt: Date.now() + TOKEN_EXPIRY_MS });
  return token;
}
 
// Validates a token and returns the userId; returns null if expired or already used.
export function validateResetToken(token: string): string | null {
  const entry = _pendingResets.get(token);
  if (!entry) return null;
  if (Date.now() > entry.expiresAt) {
    _pendingResets.delete(token);
    return null;
  }
  _pendingResets.delete(token);
  return entry.userId;
}