/** * Passwort-Policy (Benutzer- & Rollenverwaltung, Querschnitt). Reine Validierung * ohne Server-Abhängigkeiten — auch in Client-Komponenten nutzbar (Hinweistexte). * Werte stammen aus TenantSettings.securityPolicy.password bzw. dem Plattform-Default. */ export interface PasswordPolicy { minLength: number; requireUpper: boolean; requireLower: boolean; requireDigit: boolean; requireSymbol: boolean; } export const DEFAULT_PASSWORD_POLICY: PasswordPolicy = { minLength: 12, requireUpper: true, requireLower: true, requireDigit: true, requireSymbol: false, }; /** Liest die Policy aus einem TenantSettings.securityPolicy-JSON (mit Defaults). */ export function resolvePasswordPolicy(securityPolicy: unknown): PasswordPolicy { const sp = securityPolicy && typeof securityPolicy === "object" ? (securityPolicy as Record) : {}; const p = (sp.password && typeof sp.password === "object" ? (sp.password as Partial) : {}) ?? {}; return { minLength: typeof p.minLength === "number" ? p.minLength : DEFAULT_PASSWORD_POLICY.minLength, requireUpper: p.requireUpper ?? DEFAULT_PASSWORD_POLICY.requireUpper, requireLower: p.requireLower ?? DEFAULT_PASSWORD_POLICY.requireLower, requireDigit: p.requireDigit ?? DEFAULT_PASSWORD_POLICY.requireDigit, requireSymbol: p.requireSymbol ?? DEFAULT_PASSWORD_POLICY.requireSymbol, }; } /** Gibt die verletzten Anforderungen zurück (leeres Array = gültig). */ export function validatePassword(pw: string, policy: PasswordPolicy = DEFAULT_PASSWORD_POLICY): string[] { const missing: string[] = []; if (pw.length < policy.minLength) missing.push(`mindestens ${policy.minLength} Zeichen`); if (policy.requireUpper && !/[A-Z]/.test(pw)) missing.push("einen Großbuchstaben"); if (policy.requireLower && !/[a-z]/.test(pw)) missing.push("einen Kleinbuchstaben"); if (policy.requireDigit && !/\d/.test(pw)) missing.push("eine Ziffer"); if (policy.requireSymbol && !/[^A-Za-z0-9]/.test(pw)) missing.push("ein Sonderzeichen"); return missing; } /** Menschlich lesbare Beschreibung der Anforderungen (für Hinweistexte). */ export function describePasswordPolicy(policy: PasswordPolicy = DEFAULT_PASSWORD_POLICY): string { const parts = [`mind. ${policy.minLength} Zeichen`]; if (policy.requireUpper) parts.push("Großbuchstabe"); if (policy.requireLower) parts.push("Kleinbuchstabe"); if (policy.requireDigit) parts.push("Ziffer"); if (policy.requireSymbol) parts.push("Sonderzeichen"); return parts.join(", "); }