fix(auth): new passwords need at least 8 characters (FLAW-09)

auth.ValidatePassword checks every way a password is set: setup,
registration, profile, admin create and reset, reset by mail. Same rule
in the browser before sending (lib/password.ts), with our own German
message instead of the browser popup. Existing shorter passwords still
log in. Profile and admin reset no longer trim the password, which made
passwords with surrounding spaces unusable for login.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
sandrodachandClaude Opus 5.5 committed 2026-10-29 12:20:46 +01:00
1 parent f8989d0c44
commit b5f926bcf7
13 files changed
+142 -26

No files matched your search

@@ -15,6 +15,7 @@ import { AuthStatus, SharingMode, User } from '../../lib/types';
import { api, triggerHaptic } from '../../lib/api';
import { ToggleSwitch } from '../../components/ToggleSwitch';
import { LegalLinks } from '../../components/LegalLinks';
import { passwordProblem } from '../../lib/password';
interface SetupAndAuthViewProps {
authStatus: AuthStatus;
@@ -74,6 +75,12 @@ export const SetupAndAuthView: React.FC<SetupAndAuthViewProps> = ({
const handleResetPassword = async (e: React.FormEvent) => {
e.preventDefault();
setError(null);
const resetProblem = passwordProblem(newPassword);
if (resetProblem) {
setError(resetProblem);
triggerHaptic(25);
return;
}
if (newPassword !== newPasswordConfirm) {
setError('Die eingegebenen Passwörter stimmen nicht überein.');
triggerHaptic(25);
@@ -99,6 +106,12 @@ export const SetupAndAuthView: React.FC<SetupAndAuthViewProps> = ({
e.preventDefault();
setError(null);
const setupProblem = passwordProblem(setupPassword);
if (setupProblem) {
setError(setupProblem);
triggerHaptic(25);
return;
}
if (setupPassword !== setupPasswordConfirm) {
setError('Die eingegebenen Passwörter stimmen nicht überein.');
triggerHaptic(25);
@@ -143,6 +156,12 @@ export const SetupAndAuthView: React.FC<SetupAndAuthViewProps> = ({
const handleRegisterOrInvite = async (e: React.FormEvent) => {
e.preventDefault();
setError(null);
const registerProblem = passwordProblem(password);
if (registerProblem) {
setError(registerProblem);
triggerHaptic(25);
return;
}
setSubmitting(true);
triggerHaptic(15);
try {
@@ -235,8 +254,7 @@ export const SetupAndAuthView: React.FC<SetupAndAuthViewProps> = ({
type="password"
value={setupPassword}
onChange={(e) => setSetupPassword(e.target.value)}
placeholder="Mindestens 4 Zeichen"
minLength={4}
placeholder="Mindestens 8 Zeichen"
required
className="w-full h-8 px-2.5 input-field"
/>
@@ -248,7 +266,6 @@ export const SetupAndAuthView: React.FC<SetupAndAuthViewProps> = ({
value={setupPasswordConfirm}
onChange={(e) => setSetupPasswordConfirm(e.target.value)}
placeholder="Passwort erneut eingeben"
minLength={4}
required
className={`w-full h-8 px-2.5 input-field ${
setupPasswordConfirm && setupPassword !== setupPasswordConfirm
@@ -529,7 +546,7 @@ export const SetupAndAuthView: React.FC<SetupAndAuthViewProps> = ({
type="password"
value={newPassword}
onChange={(e) => setNewPassword(e.target.value)}
minLength={4}
placeholder="Mindestens 8 Zeichen"
required
autoFocus
autoComplete="new-password"
@@ -542,7 +559,6 @@ export const SetupAndAuthView: React.FC<SetupAndAuthViewProps> = ({
type="password"
value={newPasswordConfirm}
onChange={(e) => setNewPasswordConfirm(e.target.value)}
minLength={4}
required
autoComplete="new-password"
className="w-full h-11 sm:h-8 px-2.5 input-field text-base sm:text-xs"
@@ -716,8 +732,7 @@ export const SetupAndAuthView: React.FC<SetupAndAuthViewProps> = ({
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="Mindestens 4 Zeichen"
minLength={4}
placeholder="Mindestens 8 Zeichen"
required
className="w-full h-8 px-2.5 input-field"
/>