/** * Invite-System (plan.md Abschnitt 3 und 9). * * - Token wird zufaellig und nicht erratbar erzeugt (crypto.randomBytes). * - In der Datenbank liegt NUR der SHA-256-Hash des Tokens. * - Der Klartext-Token wird genau einmal beim Erstellen zurueckgegeben. */ import { createHash, randomBytes } from 'node:crypto'; /** Laenge des rohen Tokens in Bytes (256 Bit Entropie -> nicht erratbar). */ const TOKEN_BYTE_LENGTH = 32; /** Invite-Links laufen standardmaessig nach 7 Tagen ab. */ export const INVITE_DEFAULT_TTL_DAYS = 7; /** Erzeugt einen neuen, nicht erratbaren Invite-Token (Klartext). */ export function generateInviteToken(): string { return randomBytes(TOKEN_BYTE_LENGTH).toString('base64url'); } /** Berechnet den SHA-256-Hash eines Tokens fuer die Datenbank. */ export function hashInviteToken(token: string): string { return createHash('sha256').update(token).digest('hex'); } /** Standard-Ablaufzeit fuer neue Invites. */ export function defaultInviteExpiry(now: Date = new Date()): Date { const expiry = new Date(now); expiry.setDate(expiry.getDate() + INVITE_DEFAULT_TTL_DAYS); return expiry; } /** Ist ein Invite gueltig (nicht abgelaufen, nicht verwendet)? */ export function isInviteUsable( invite: { expiresAt: Date | null; usedAt: Date | null }, now: Date = new Date(), ): boolean { if (invite.usedAt !== null) { return false; } if (invite.expiresAt !== null && invite.expiresAt <= now) { return false; } return true; }