feat(PROJ-25): User-Profil & Einstellungen — Passwort, E-Mail, 2FA
Backend: - PATCH /api/auth/password — Passwort ändern (bcrypt, LDAP-Guard, Audit-Log) - PATCH /api/auth/email — E-Mail ändern (Unique-Check, LDAP-Guard, Audit-Log) - userstore: UpdatePassword, UpdateEmail, GetPasswordHash Frontend: - UserNav.tsx: Dropdown-Menü (Profil & Einstellungen, Abmelden) - navbar.tsx: UserNav eingebunden - /settings: Passwort ändern, E-Mail ändern, 2FA verwalten (QR-Code + Deaktivieren) - api.ts: changePassword, changeEmail, getTOTPSetup, confirmTOTPSetup, disableTOTP Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -453,6 +453,36 @@ func (s *Store) ResetTOTP(ctx context.Context, userID int64, resetBy string) err
|
||||
return nil
|
||||
}
|
||||
|
||||
// ── PROJ-25: Profile Update Methods ───────────────────────────────────────
|
||||
|
||||
// GetPasswordHash returns the bcrypt password hash for a user by ID.
|
||||
func (s *Store) GetPasswordHash(ctx context.Context, userID int64) (string, error) {
|
||||
var hash string
|
||||
err := s.pool.QueryRow(ctx, `SELECT password_hash FROM users WHERE id = $1`, userID).Scan(&hash)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("userstore: get password hash: %w", err)
|
||||
}
|
||||
return hash, nil
|
||||
}
|
||||
|
||||
// UpdatePassword sets a new password hash for the given user.
|
||||
func (s *Store) UpdatePassword(ctx context.Context, userID int64, passwordHash string) error {
|
||||
_, err := s.pool.Exec(ctx, `UPDATE users SET password_hash = $1 WHERE id = $2`, passwordHash, userID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("userstore: update password: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateEmail sets a new email address for the given user.
|
||||
func (s *Store) UpdateEmail(ctx context.Context, userID int64, email string) error {
|
||||
_, err := s.pool.Exec(ctx, `UPDATE users SET email = $1 WHERE id = $2`, email, userID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("userstore: update email: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetTOTPSecret returns the encrypted TOTP secret and enabled status for a user.
|
||||
func (s *Store) GetTOTPSecret(ctx context.Context, userID int64) (secret []byte, enabled bool, err error) {
|
||||
err = s.pool.QueryRow(ctx,
|
||||
|
||||
Reference in New Issue
Block a user