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

@@ -25,6 +25,7 @@ import {
UserRole,
} from '../../lib/types';
import { api, setCurrentSharingMode, triggerHaptic } from '../../lib/api';
import { passwordProblem } from '../../lib/password';
import { UserAvatar } from '../../components/UserAvatar';
import { ToggleSwitch } from '../../components/ToggleSwitch';
import { CountBadge } from '../../components/CountBadge';
@@ -151,6 +152,11 @@ export const AdminSettingsView: React.FC<AdminSettingsViewProps> = ({
const handleCreateUser = async (e: React.FormEvent) => {
e.preventDefault();
setStatusMsg(null);
const problem = passwordProblem(newUserPassword);
if (problem) {
setStatusMsg({ type: 'err', text: problem });
return;
}
triggerHaptic(15);
try {
const created = await api.adminCreateUser({
@@ -235,8 +241,14 @@ export const AdminSettingsView: React.FC<AdminSettingsViewProps> = ({
const handleConfirmResetPassword = async (userId: string) => {
if (!resetPwdVal.trim()) return;
setStatusMsg(null);
const problem = passwordProblem(resetPwdVal);
if (problem) {
setStatusMsg({ type: 'err', text: problem });
return;
}
try {
await api.adminResetPassword(userId, resetPwdVal.trim());
// Not trimmed: login compares the password exactly as typed
await api.adminResetPassword(userId, resetPwdVal);
setResetPwdUserId(null);
setResetPwdVal('');
setStatusMsg({ type: 'ok', text: 'Passwort erfolgreich zurückgesetzt.' });
@@ -555,8 +567,7 @@ export const AdminSettingsView: React.FC<AdminSettingsViewProps> = ({
type="password"
value={newUserPassword}
onChange={(e) => setNewUserPassword(e.target.value)}
placeholder="Mind. 4 Zeichen"
minLength={4}
placeholder="Mind. 8 Zeichen"
required
className="w-full min-w-0 h-8 px-2.5 input-field"
/>
@@ -843,7 +854,7 @@ export const AdminSettingsView: React.FC<AdminSettingsViewProps> = ({
type="password"
value={resetPwdVal}
onChange={(e) => setResetPwdVal(e.target.value)}
placeholder="Neues Passwort eingeben…"
placeholder="Neues Passwort (mind. 8 Zeichen)…"
className="flex-1 h-7 px-2 input-field"
/>
<button