Basis: Certvia dev@a48c5fb als Fundament für Craftvia
CI / build-and-check (push) Canceled after 0s
CI / audit (push) Canceled after 0s
CI / sbom (push) Canceled after 0s

Unveränderter Stand von certvia/dev (a48c5fb) plus Craftvia-Spezifikation
und Brandbook unter docs/craftvia/. ISMS-Module werden im Folgecommit entfernt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-14 11:05:39 +02:00
co-authored by Claude Opus 5
commit c8e6f30a27
720 changed files with 140143 additions and 0 deletions
+54
View File
@@ -0,0 +1,54 @@
/**
* 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<string, unknown>) : {};
const p = (sp.password && typeof sp.password === "object" ? (sp.password as Partial<PasswordPolicy>) : {}) ?? {};
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(", ");
}