import crypto from "crypto"; import bcrypt from "bcryptjs"; import type { NextRequest } from "next/server"; import type { IUser } from "@/lib/server/models/User"; export const INVITE_TTL_MS = 7 * 24 * 60 * 60 * 1000; export function hashInviteToken(token: string): string { return crypto.createHash("sha256").update(token).digest("hex"); } /** A password nobody knows, for an account whose owner has not accepted their invite yet. */ export async function unusablePasswordHash(): Promise { return bcrypt.hash(crypto.randomBytes(32).toString("hex"), 12); } /** * Give the user a fresh invite (any earlier link stops working) and return * the link to send them. The caller saves the user. */ export function issueInvite(user: IUser, req: NextRequest): string { const token = crypto.randomBytes(32).toString("base64url"); user.inviteTokenHash = hashInviteToken(token); user.inviteExpiresAt = new Date(Date.now() + INVITE_TTL_MS); const origin = process.env.APP_URL?.replace(/\/$/, "") || req.nextUrl.origin; return `${origin}/invite/${token}`; }