Registrierung: E-Mail-Bestätigung per Einmalcode vor dem Zugangscode

Nutzer-Wunsch 21.08.2026: "bei der ersten registrierung sollen die eine
email bekommen mit einem einmaligen code damit wir auch wissen dass
email stimmt und danach wenn sie den code eingegeben haben sollen die
erst ihren zugangscode auswählen/eintippen können."

Damit wird eine echte Lücke geschlossen: registerSupporter() hat bisher
`email_verified = 1` gesetzt, OHNE dass irgendetwas geprüft wurde -- man
konnte sich mit einer fremden oder erfundenen Adresse registrieren und
kam sofort rein.

Neuer Ablauf in drei Schritten:
1. Name/TikTok/E-Mail -> Konto wird als UNBESTÄTIGT angelegt
   (email_verified = 0, noch kein Zugangscode). Es kommt bewusst KEIN
   Session-Token zurück -- eingeloggt ist man hier noch nicht.
2. Einmalcode aus der E-Mail eingeben -> verify-email bestätigt und
   loggt ein. Die Willkommens-Mail wandert hierher, sie ging vorher an
   eine noch ungeprüfte Adresse.
3. Erst jetzt den eigenen Zugangscode festlegen.

Serverseitig abgesichert: setSupporterAccessCode() lehnt ab, solange die
E-Mail nicht bestätigt ist -- der Schritt ist damit nicht nur im
Formular versteckt, sondern auch per Direktaufruf nicht überspringbar.

Wiederverwendet wird die bereits vorhandene Mechanik (issueAuthCode/
verifyAuthCode mit Zweck "verify_email", sendVerifyEmailCode, die Panels
#panel-code und #panel-neuer-code) -- der "Code vergessen?"-Weg nutzt
dieselbe Code-Eingabe und bleibt unverändert; eine neue Variable
codeZweck unterscheidet, welcher Endpunkt aufgerufen wird.

Mit Playwright end-to-end geprüft (14 Tests): Reihenfolge der Aufrufe,
kein Token vor der Bestätigung, falscher Code kommt nicht weiter,
Zugangscode-Feld erst im letzten Schritt, "Code vergessen?" unberührt.

Cache-Busting-Version auf 20260821o erhöht.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
2026-08-21 17:48:08 +02:00
co-authored by Claude Opus 5
parent 5d0ea11570
commit 5a5912636d
37 changed files with 331 additions and 286 deletions
+34 -35
View File
@@ -19,10 +19,10 @@
<meta name="twitter:description" content="Unterstütze Dogfather dauerhaft mit der DogiCrew 🩵 und sammle exklusive Treueprämien — die Teddy-Kollektion entsteht in Kooperation mit VanVan." />
<meta name="twitter:image" content="https://dogfather-universe.com/assets/img/og-cover.jpg" />
<link rel="stylesheet" href="assets/css/main.css?v=20260821n" />
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260821n" />
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260821n" />
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260821n" />
<link rel="stylesheet" href="assets/css/main.css?v=20260821o" />
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260821o" />
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260821o" />
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260821o" />
<style>
/* =====================================================================
Preis-/Anmelde-Kiste — komplett neu gestaltet (Nutzer-Feedback
@@ -429,25 +429,15 @@
<label for="reg-email" data-i18n="ab_feld_email">E-Mail-Adresse</label>
<input type="email" id="reg-email" maxlength="120" />
</div>
<!-- Eigener, dauerhafter Zugangscode (21.08.2026, Nutzer-Wunsch:
"die leute sollen nach der registrierung einen festen code
erstellen können für sich selbst und fertig, mit dem sie rein
kommen"). type="password" — der Code soll beim Tippen nicht
für Umstehende lesbar sein. -->
<!-- Beschriftung geschärft 21.08.2026 (Nutzer-Rückmeldung: "auf
dieser seite brauch man doch keine zugangsdaten, da kann man
sich ja noch nicht einloggen"). Genau dieser Eindruck entstand,
weil "Dein Zugangscode" wie die Abfrage eines BESTEHENDEN Codes
klang. Jetzt steht als Aufforderung im Text, dass man ihn sich
hier gerade ausdenkt — plus ein Platzhalter im Feld selbst, der
das nochmal zeigt, falls jemand nur auf die Felder schaut. -->
<div class="abo-field">
<label for="reg-code" data-i18n="ab_feld_code_neu">Denk dir jetzt deinen Zugangscode aus (mindestens 6 Zeichen)</label>
<input type="password" id="reg-code" maxlength="200" autocomplete="new-password"
placeholder="Frei wählbar — z. B. DogiCrew2026"
data-i18n-attr="placeholder:ab_feld_code_platzhalter" />
<p class="small muted" style="margin:.45rem 0 0;" data-i18n="ab_code_hinweis_neu">Mit diesem Code loggst du dich künftig ein — merk ihn dir gut.</p>
</div>
<!-- Das Zugangscode-Feld stand bis 21.08.2026 hier, direkt neben den
Stammdaten. Es ist bewusst in einen eigenen, SPÄTEREN Schritt
gewandert (Nutzer-Wunsch: "bei der ersten registrierung sollen
die eine email bekommen mit einem einmaligen code damit wir auch
wissen dass email stimmt und danach wenn sie den code eingegeben
haben sollen die erst ihren zugangscode auswählen/eintippen
können"). Ablauf jetzt: hier Stammdaten -> Einmalcode per Mail
(#panel-code) -> Zugangscode festlegen (#panel-neuer-code). -->
<p class="small muted" style="margin:-.2rem 0 .2rem;" data-i18n="ab_reg_hinweis_bestaetigung">Wir schicken dir gleich einen 6-stelligen Code per E-Mail. Danach legst du deinen eigenen Zugangscode fest.</p>
<!-- Nutzer-Wunsch 21.08.2026: "die leute sollen sich auch schon
registrieren können, aber der abo soll noch zu sein, da soll
dann coming soon stehen." Registrierung/Login sind ab jetzt
@@ -613,9 +603,9 @@
</main>
<div id="site-footer"></div>
<script src="assets/js/i18n-abonnieren.js?v=20260821n"></script>
<script src="assets/js/supporter.js?v=20260821n"></script>
<script src="assets/js/main.js?v=20260821n"></script>
<script src="assets/js/i18n-abonnieren.js?v=20260821o"></script>
<script src="assets/js/supporter.js?v=20260821o"></script>
<script src="assets/js/main.js?v=20260821o"></script>
<script>
(function () {
const S = window.DogiSupporter;
@@ -661,6 +651,10 @@
// Eingabe des Einmalcodes (der frühere codePurpose-Schalter entfiel mit
// der Umstellung 21.08.2026 — es gibt nur noch diesen einen Code-Weg).
let codeEmail = "";
// Merkt sich, WARUM gerade ein Einmalcode eingegeben wird (21.08.2026):
// "register" = Erstbestätigung der E-Mail, "login" = "Code vergessen?".
// Steuert in btn-code-verify, welcher Endpunkt aufgerufen wird.
let codeZweck = "login";
async function pruefeStatus() {
if (!S.getToken()) {
@@ -832,15 +826,15 @@
const displayName = document.getElementById("reg-name").value.trim();
const tiktokUsername = document.getElementById("reg-tiktok").value.trim();
const email = document.getElementById("reg-email").value.trim();
const accessCode = document.getElementById("reg-code").value;
if (!displayName || !email) return fehlerZeigen(el, "Bitte Name und E-Mail-Adresse angeben.");
if (!accessCode) return fehlerZeigen(el, "Bitte leg einen Zugangscode fest.");
try {
// Seit 21.08.2026 liefert /supporter/register direkt ein Token zurück —
// kein Bestätigungscode per E-Mail mehr dazwischen, man ist sofort drin.
const data = await S.apiFetch("/supporter/register", { displayName, tiktokUsername, email, accessCode });
S.setToken(data.token);
await pruefeStatus();
// Schritt 1 von 3 (21.08.2026): /supporter/register legt nur das noch
// unbestätigte Konto an und verschickt einen Einmalcode -- es kommt
// bewusst KEIN Token zurück, eingeloggt ist man erst nach Schritt 2.
await S.apiFetch("/supporter/register", { displayName, tiktokUsername, email });
codeEmail = email;
codeZweck = "register";
zeige("panel-code");
} catch (err) {
fehlerZeigen(el, err.message);
}
@@ -871,6 +865,7 @@
try {
await S.apiFetch("/supporter/login-request", { email });
codeEmail = email;
codeZweck = "login";
zeige("panel-code");
} catch (err) {
fehlerZeigen(el, err.message);
@@ -883,9 +878,13 @@
const code = document.getElementById("code-input").value.trim();
if (!code) return fehlerZeigen(el, "Bitte Code eingeben.");
try {
const data = await S.apiFetch("/supporter/verify-login", { email: codeEmail, code });
// Dieselbe Code-Eingabe bedient zwei Wege (21.08.2026):
// "register" -> Erstbestätigung der E-Mail bei der Registrierung
// "login" -> "Code vergessen?"-Weg für bestehende Konten
// Beide enden gleich: eingeloggt, danach Zugangscode festlegen.
const endpunkt = codeZweck === "register" ? "/supporter/verify-email" : "/supporter/verify-login";
const data = await S.apiFetch(endpunkt, { email: codeEmail, code });
S.setToken(data.token);
// Eingeloggt — jetzt fehlt nur noch der neue dauerhafte Zugangscode.
zeige("panel-neuer-code");
} catch (err) {
fehlerZeigen(el, err.message);