diff --git a/CHANGELOG.md b/CHANGELOG.md index ddd7771..57808dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,12 @@ Versionierung [semantisch](https://semver.org/lang/de/). ## [Unreleased] – 2026-07-21 · Gesamt-Audit: Light Mode, Barrierefreiheit, AP2-Inhalte, DSGVO +### Registrierung & Kontozugang +- **Sofort nutzbare Accounts:** Die Registrierung hängt nicht mehr an der Zustellung + einer Bestätigungs-E-Mail. Neue Accounts können sich direkt anmelden; bereits + wartende Konten werden mit Migration V23 aktiviert. Nicht mehr benötigte + Bestätigungs-Token werden gelöscht. E-Mail bleibt für den Passwort-Reset erhalten. + ### Light Mode & Design - **Browser-Icon:** Das Neural-Emblem wird unter `/favicon.ico` ausgeliefert und direkt auf der Startseite verlinkt. Die Versionierung der Bild-URL ersetzt auch diff --git a/src/main/java/com/example/mindflux/config/SecurityConfig.java b/src/main/java/com/example/mindflux/config/SecurityConfig.java index 6566699..78ccabb 100644 --- a/src/main/java/com/example/mindflux/config/SecurityConfig.java +++ b/src/main/java/com/example/mindflux/config/SecurityConfig.java @@ -75,7 +75,6 @@ public class SecurityConfig { .withUsername(user.getUsername()) .password(user.getPassword()) .roles(user.getRole()) // Achtung: Nur ein String, z.B. "USER" oder "ADMIN" - .disabled(!user.isEmailVerified()) .build(); }; } diff --git a/src/main/java/com/example/mindflux/controller/RegisterController.java b/src/main/java/com/example/mindflux/controller/RegisterController.java index c9072c7..8720dca 100644 --- a/src/main/java/com/example/mindflux/controller/RegisterController.java +++ b/src/main/java/com/example/mindflux/controller/RegisterController.java @@ -1,11 +1,8 @@ package com.example.mindflux.controller; import com.example.mindflux.service.RegistrationResult; -import com.example.mindflux.service.AccountMailService; import com.example.mindflux.service.UserService; import org.springframework.stereotype.Controller; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; @@ -13,14 +10,10 @@ import org.springframework.web.bind.annotation.RequestParam; @Controller public class RegisterController { - private static final Logger log = LoggerFactory.getLogger(RegisterController.class); - private final UserService userService; - private final AccountMailService accountMailService; - public RegisterController(UserService userService, AccountMailService accountMailService) { + public RegisterController(UserService userService) { this.userService = userService; - this.accountMailService = accountMailService; } @GetMapping("/register") @@ -36,18 +29,9 @@ public class RegisterController { @RequestParam(required = false) String confirmPassword) { RegistrationResult result = userService.register(username, email, password, confirmPassword); return switch (result) { - case SUCCESS -> { - try { - var user = userService.findByUsernameIgnoreCase(username.trim()); - yield accountMailService.sendVerificationFor(user) - ? "redirect:/?registerSuccess" - : "redirect:/?registerMailError"; - } catch (RuntimeException e) { - log.warn("mail_event=REGISTRATION_VERIFICATION_FAILED errorType={}", - e.getClass().getSimpleName()); - yield "redirect:/?registerMailError"; - } - } + // Ein SMTP-Problem darf die Nutzung eines neu angelegten Accounts nicht blockieren. + // Die E-Mail-Adresse wird weiterhin für den Passwort-Reset gespeichert. + case SUCCESS -> "redirect:/?registerSuccess"; case PASSWORD_MISMATCH -> "redirect:/?passwordMismatch"; case PASSWORD_TOO_SHORT -> "redirect:/?passwordPolicy"; case EMAIL_INVALID -> "redirect:/?emailInvalid"; diff --git a/src/main/java/com/example/mindflux/service/UserServiceImpl.java b/src/main/java/com/example/mindflux/service/UserServiceImpl.java index 23555bd..b760994 100644 --- a/src/main/java/com/example/mindflux/service/UserServiceImpl.java +++ b/src/main/java/com/example/mindflux/service/UserServiceImpl.java @@ -88,7 +88,9 @@ public class UserServiceImpl implements UserService { return RegistrationResult.EMAIL_TAKEN; } User user = new User(name, passwordEncoder.encode(password), email.trim(), "USER"); - user.setEmailVerified(false); + // Die Registrierung ist bewusst nicht vom Versand oder Empfang einer E-Mail abhängig. + // Damit bleibt der Login auch bei verzögerter bzw. abgewiesener SMTP-Zustellung möglich. + user.setEmailVerified(true); try { userRepository.save(user); } catch (DataIntegrityViolationException e) { diff --git a/src/main/resources/db/migration/V23__activate_existing_accounts.sql b/src/main/resources/db/migration/V23__activate_existing_accounts.sql new file mode 100644 index 0000000..6162e51 --- /dev/null +++ b/src/main/resources/db/migration/V23__activate_existing_accounts.sql @@ -0,0 +1,9 @@ +-- Die Anmeldung ist nicht mehr an die Zustellung einer E-Mail gebunden. +-- Bereits registrierte, bisher noch wartende Accounts werden dadurch nutzbar. +UPDATE users +SET email_verified = TRUE +WHERE email_verified = FALSE; + +-- Verifikations-Links werden nicht mehr benötigt; gespeicherte Hashes entfernen. +DELETE FROM account_email_tokens +WHERE purpose = 'EMAIL_VERIFICATION'; diff --git a/src/main/resources/templates/index.html b/src/main/resources/templates/index.html index f340d00..b3ace48 100644 --- a/src/main/resources/templates/index.html +++ b/src/main/resources/templates/index.html @@ -42,11 +42,9 @@
Benutzername oder Passwort sind falsch.
Du hast dich erfolgreich abgemeldet.
-
Fast geschafft: Wir haben dir einen Bestätigungslink per E-Mail gesendet.
-
Deine E-Mail-Adresse wurde bestätigt. Du kannst dich jetzt anmelden.
+
Dein Account wurde erstellt. Du kannst dich jetzt anmelden.
+
Dein Account ist aktiv. Du kannst dich jetzt anmelden.
Dein Passwort wurde geändert. Du kannst dich jetzt anmelden.
-
Falls ein unbestätigter Account zu dieser Adresse existiert, wurde ein neuer Link versendet.
-
Dieser Bestätigungslink ist ungültig oder abgelaufen.
Dieser Passwort-Link ist ungültig oder abgelaufen.
@@ -81,9 +79,7 @@
Das Passwort muss mindestens 8 Zeichen lang sein.
Bitte gib eine gültige E-Mail-Adresse an.
Diese E-Mail-Adresse wird bereits verwendet.
-
Der Account wurde angelegt, aber die Bestätigungs-E-Mail konnte nicht gesendet werden. Fordere unten einen neuen Link an.
-
Fast geschafft: Wir haben dir einen Bestätigungslink per E-Mail gesendet.
-
Falls ein unbestätigter Account zu dieser Adresse existiert, wurde ein neuer Link versendet.
+
Account erstellt. Du kannst dich sofort anmelden.
@@ -106,20 +102,6 @@ -
- - -
-

Schon dabei? Zum Login

@@ -159,17 +141,6 @@ if (toSignup) toSignup.addEventListener('click', function () { c.classList.add('active'); }); if (toLogin) toLogin.addEventListener('click', function () { c.classList.remove('active'); }); - var resendToggle = document.getElementById('resend-toggle'); - var resendForm = document.getElementById('resend-form'); - if (resendToggle && resendForm) { - resendToggle.addEventListener('click', function () { - var expand = resendForm.hidden; - resendForm.hidden = !expand; - resendToggle.setAttribute('aria-expanded', String(expand)); - if (expand) resendForm.querySelector('input').focus(); - }); - } - document.querySelectorAll('[data-goto="signup"]').forEach(function (el) { el.addEventListener('click', function (e) { e.preventDefault(); c.classList.add('active'); }); }); @@ -179,7 +150,7 @@ // Bei Registrierungs-/Passwortfehler direkt das Signup-Panel öffnen var qp = new URLSearchParams(window.location.search); - if (qp.has('signup') || qp.has('registerError') || qp.has('passwordMismatch') || qp.has('passwordPolicy') || qp.has('emailInvalid') || qp.has('emailTaken') || qp.has('registerMailError') || qp.has('registerSuccess') || qp.has('verificationSent')) { + if (qp.has('signup') || qp.has('registerError') || qp.has('passwordMismatch') || qp.has('passwordPolicy') || qp.has('emailInvalid') || qp.has('emailTaken') || qp.has('registerSuccess')) { c.classList.add('active'); } diff --git a/src/main/resources/templates/legal/datenschutz.html b/src/main/resources/templates/legal/datenschutz.html index 413e465..33434de 100644 --- a/src/main/resources/templates/legal/datenschutz.html +++ b/src/main/resources/templates/legal/datenschutz.html @@ -63,7 +63,7 @@ Nutzungs-/LerndatenSpielstände (Spiel, Deck, Punktzahl, Züge, Dauer, Zeitpunkt) sowie erreichte Erfolge/Achievements Technische DatenSitzungs-Cookie zur Anmeldung, CSRF-Token; serverseitige Protokolldaten (z. B. IP-Adresse, Zeitpunkt, abgerufene Ressource) im Rahmen des technischen Betriebs NeuralNet-Nachrichten (nur bei Aktivierung)Verbindungsanfragen (anfragende und empfangende Person, Status, Zeitpunkt) sowie Nachrichten (Absender, Empfänger, Nachrichteninhalt, Sende- und Lesezeitpunkt/Lesebestätigung) - E-Mail-Bestätigung / Passwort-ResetBestätigungs- bzw. Reset-Token, ausschließlich als SHA-256-Hash gespeichert und 24 Stunden gültig, zur Verifizierung der E-Mail-Adresse bzw. zum Zurücksetzen des Passworts + Passwort-ResetReset-Token, ausschließlich als SHA-256-Hash gespeichert und 24 Stunden gültig, zum Zurücksetzen des Passworts AnmeldeschutzFehlgeschlagene Anmeldeversuche (Benutzername, Zeitpunkt) zum Schutz vor automatisierten Anmeldeangriffen (Brute Force) @@ -73,7 +73,7 @@
  • Technischer Betrieb, Sicherheit und Stabilität (Protokolldaten, Schutz vor Missbrauch) – Art. 6 Abs. 1 lit. f DSGVO (berechtigtes Interesse).
  • Profilbild – auf Grundlage der freiwilligen Bereitstellung durch die Nutzer:in.
  • NeuralNet-Community-Funktion (Verbindungsanfragen und Nachrichten) – nur nach ausdrücklicher Aktivierung (Opt-in, standardmäßig deaktiviert), Art. 6 Abs. 1 lit. a und b DSGVO. Die Funktion lässt sich jederzeit deaktivieren; beim Deaktivieren bzw. beim Löschen des Kontos werden die zugehörigen Nachrichten und Verbindungen per Datenbank-Kaskade mitgelöscht.
  • -
  • E-Mail-Verifizierung und Passwort-Zurücksetzung (Versand von Bestätigungs- und Reset-Links) – Art. 6 Abs. 1 lit. b und f DSGVO.
  • +
  • Passwort-Zurücksetzung (Versand von Reset-Links) – Art. 6 Abs. 1 lit. b und f DSGVO.
  • 5. Cookies

    @@ -88,7 +88,7 @@ @@ -112,7 +112,7 @@

    7. Empfänger und Hosting

    Die Daten werden auf einer vom Anbieter betriebenen Server-Infrastruktur verarbeitet und nicht zu - werblichen Zwecken an Dritte weitergegeben. Für den Versand von Bestätigungs- und Passwort-Reset-E-Mails + werblichen Zwecken an Dritte weitergegeben. Für den Versand von Passwort-Reset-E-Mails wird der Mailserver mail.sysnaptik.de genutzt; dabei werden E-Mail-Adresse und der jeweilige Link übermittelt. Alle statischen Inhalte (einschließlich der Diagramm-Bibliothek) werden ausschließlich von der eigenen Infrastruktur ausgeliefert – es werden keine externen Content-Delivery-Networks oder diff --git a/src/test/java/com/example/mindflux/service/UserServiceImplTest.java b/src/test/java/com/example/mindflux/service/UserServiceImplTest.java index 262ed4f..a60e400 100644 --- a/src/test/java/com/example/mindflux/service/UserServiceImplTest.java +++ b/src/test/java/com/example/mindflux/service/UserServiceImplTest.java @@ -74,6 +74,7 @@ class UserServiceImplTest { assertEquals("alice", saved.getUsername()); assertEquals("a@b.de", saved.getEmail()); assertEquals("USER", saved.getRole()); + assertTrue(saved.isEmailVerified()); assertTrue(encoder.matches("passwort123", saved.getPassword())); }