Passwort ändern #182

Closed
opened 2026-09-20 12:11:15 +02:00 by meleki · 3 comments
Owner

Folge von #177 (User Management). Kleinstes der fünf Folge-Issues und ohne Abhängigkeit zu
#179/#180 baubar.

Stand heute

Die drei Konten aus #177 sind mit Platzhaltern angelegt: admin/admin und user/user
(auf ausdrücklichen Wunsch), dazu e2e mit einem zufälligen Passwort in data/e2e-password.txt
(git-ignoriert). Ein Passwort ändern kann heute nur, wer auf den Server kommt:
make-user.php <name> <pw> setzt für einen bestehenden Namen einfach den neuen Hash.

Eingeordnet: Der User hat am 2026-09-20 gesagt, dass ihm die Platzhalter erstmal egal sind, auf
dem Server läuft nichts Produktives. Das Issue bleibt trotzdem offen — nur eben nicht als
Notfall.

Was gebaut werden soll

Server — POST ?r=auth/password {currentPassword, newPassword} für das eigene Konto:

  • Das alte Passwort wird verlangt und geprüft, auch wenn eine Session da ist — sonst reicht ein
    fremder offener Tab, um ein Konto zu übernehmen.
  • Mindestlänge serverseitig prüfen, dieselbe Regel wie in #178.
  • UserStore::put() kann das Ersetzen schon, es braucht also nur die Route und die Prüfung.
  • Andere Sessions beenden: Nach dem Wechsel sollten alle Logins dieses Kontos ungültig
    werden, außer dem gerade benutzten. Dafür fehlt SessionStore ein
    destroyAllFor(username, außer $token) — dieselbe Ergänzung wie in #179.

Client — ein Dialog "Passwort ändern" mit altem Passwort, neuem und Wiederholung, alle drei
als Bullets (TextField kann das seit #177). Erreichbar aus der Toolbar, neben oder statt dem
Logout-Knopf; siehe Rückfrage 2. Die Regeln (leer, ungleich, zu kurz, neu gleich alt) gehören als
reine Funktion neben loginProblem() in src/editor/auth/loginRules.ts.

Tests

  • Unit: die Regeln der Maske, HttpAuthStore für "altes Passwort falsch" gegen "Server kaputt".
  • API direkt gemessen: mit falschem alten Passwort abgelehnt, danach meldet das alte Passwort
    nicht mehr an und das neue schon.
  • e2e: in Modul 45 ändern und mit dem neuen Passwort neu anmelden. Achtung Aufräumen — das
    Konto e2e steht im nächsten Lauf sonst mit dem falschen Passwort da (data/e2e-password.txt
    bzw. GAME_MAKER_E2E_PASSWORD). Entweder am Ende zurücksetzen oder den Check an einem
    Wegwerfkonto fahren; das hängt mit an #178.

Rückfragen

  1. Sollen die Platzhalter beim Bau dieses Issues gleich mit geändert werden, oder bleiben sie
    bewusst so, bis du es sagst? Nach deiner Ansage vom 2026-09-20 gehe ich von "bleiben" aus.
  2. Wo soll der Einstieg sitzen? In der Toolbar ist rechts nur der Logout-Knopf; der
    Benutzername steht seit #177 im Fenstertitel, weil die Leiste bei 1280 px sonst zu breit wird.
    Vorschlag: aus dem Logout-Knopf ein kleines Konto-Menü machen (Name, "Passwort ändern",
    "Logout") — das kostet keinen zusätzlichen Platz und hat gleich einen Ort für spätere
    Kontosachen.
  3. Mindestlänge? Vorschlag wie in #178: 8 Zeichen.
  4. Soll das Ändern die anderen Sitzungen wirklich abmelden? Das ist das saubere Verhalten,
    trifft hier aber vor allem dich selbst in einem zweiten Tab.
Folge von #177 (User Management). Kleinstes der fünf Folge-Issues und ohne Abhängigkeit zu #179/#180 baubar. ## Stand heute Die drei Konten aus #177 sind mit Platzhaltern angelegt: `admin`/`admin` und `user`/`user` (auf ausdrücklichen Wunsch), dazu `e2e` mit einem zufälligen Passwort in `data/e2e-password.txt` (git-ignoriert). Ein Passwort ändern kann heute nur, wer auf den Server kommt: `make-user.php <name> <pw>` setzt für einen bestehenden Namen einfach den neuen Hash. Eingeordnet: Der User hat am 2026-09-20 gesagt, dass ihm die Platzhalter erstmal egal sind, auf dem Server läuft nichts Produktives. Das Issue bleibt trotzdem offen — nur eben nicht als Notfall. ## Was gebaut werden soll **Server** — `POST ?r=auth/password` `{currentPassword, newPassword}` für das **eigene** Konto: - Das alte Passwort wird verlangt und geprüft, auch wenn eine Session da ist — sonst reicht ein fremder offener Tab, um ein Konto zu übernehmen. - Mindestlänge serverseitig prüfen, dieselbe Regel wie in #178. - `UserStore::put()` kann das Ersetzen schon, es braucht also nur die Route und die Prüfung. - **Andere Sessions beenden:** Nach dem Wechsel sollten alle Logins dieses Kontos ungültig werden, außer dem gerade benutzten. Dafür fehlt `SessionStore` ein `destroyAllFor(username, außer $token)` — dieselbe Ergänzung wie in #179. **Client** — ein Dialog "Passwort ändern" mit altem Passwort, neuem und Wiederholung, alle drei als Bullets (`TextField` kann das seit #177). Erreichbar aus der Toolbar, neben oder statt dem Logout-Knopf; siehe Rückfrage 2. Die Regeln (leer, ungleich, zu kurz, neu gleich alt) gehören als reine Funktion neben `loginProblem()` in `src/editor/auth/loginRules.ts`. **Tests** - Unit: die Regeln der Maske, `HttpAuthStore` für "altes Passwort falsch" gegen "Server kaputt". - API direkt gemessen: mit falschem alten Passwort abgelehnt, danach meldet das alte Passwort nicht mehr an und das neue schon. - e2e: in Modul 45 ändern und mit dem neuen Passwort neu anmelden. **Achtung Aufräumen** — das Konto `e2e` steht im nächsten Lauf sonst mit dem falschen Passwort da (`data/e2e-password.txt` bzw. `GAME_MAKER_E2E_PASSWORD`). Entweder am Ende zurücksetzen oder den Check an einem Wegwerfkonto fahren; das hängt mit an #178. ## Rückfragen 1. **Sollen die Platzhalter beim Bau dieses Issues gleich mit geändert werden,** oder bleiben sie bewusst so, bis du es sagst? Nach deiner Ansage vom 2026-09-20 gehe ich von "bleiben" aus. 2. **Wo soll der Einstieg sitzen?** In der Toolbar ist rechts nur der Logout-Knopf; der Benutzername steht seit #177 im Fenstertitel, weil die Leiste bei 1280 px sonst zu breit wird. Vorschlag: aus dem Logout-Knopf ein kleines Konto-Menü machen (Name, "Passwort ändern", "Logout") — das kostet keinen zusätzlichen Platz und hat gleich einen Ort für spätere Kontosachen. 3. **Mindestlänge?** Vorschlag wie in #178: 8 Zeichen. 4. **Soll das Ändern die anderen Sitzungen wirklich abmelden?** Das ist das saubere Verhalten, trifft hier aber vor allem dich selbst in einem zweiten Tab.
admin added this to the Development project 2026-09-20 13:13:39 +02:00
meleki changed title from Passwort aendern to Passwort ändern 2026-09-20 13:30:54 +02:00
  1. die platzhalter (= admin, user und e2e oder?) sollen bleiben ja
  2. dein vorschlag passt
  3. passt auch
  4. wenn es nicht zu umständlich ist, dann ja, andere sitzungen abmelden bei passwortänderung
1. die platzhalter (= admin, user und e2e oder?) sollen bleiben ja 2. dein vorschlag passt 3. passt auch 4. wenn es nicht zu umständlich ist, dann ja, andere sitzungen abmelden bei passwortänderung
Author
Owner

Umgesetzt in c830c7a, Wiki in 3310139.

Was gebaut ist

Kontomenü statt Logout-Knopf (Rückfrage 2, dein „passt auch"): Ganz rechts in der Toolbar steht Account. Darin „Signed in as <name>" als Eintrag, der nicht anklickbar ist, darunter Change password… und Logout.

Dialog src/editor/auth/PasswordDialog.ts: aktuelles Passwort, neues, Wiederholung, alle drei als Bullets. Anders als die übrigen Formulardialoge bleibt er bei einer Ablehnung stehen — sonst könnte er nicht sagen, warum. Die Regeln (leer, zu kurz, neu gleich alt, Wiederholung abweichend) liegen als reine Funktion passwordProblem() neben loginProblem().

Server: POST ?r=auth/password {currentPassword,newPassword} → 204. Das alte Passwort wird verlangt, obwohl eine Session da ist; 401 bei falschem alten Passwort, 422 unter der Mindestlänge. Die Route ist die einzige unter auth/, die eine Session braucht. Mindestlänge 8 in UserStore::MIN_PASSWORD_LENGTH und noch einmal im Client, damit die Maske ohne Serverfrage antworten kann.

Andere Sitzungen enden (Rückfrage 4): neu ist SessionStore::destroyAllFor($user, $keep) — alle übrigen Logins des Kontos werden beendet, die des Tabs, der ändert, bleibt. War nicht umständlich, die Sessions liegen ohnehin als Dateien vor.

Platzhalter bleiben (Rückfrage 1). Eine Klarstellung zu deiner Rückfrage: admin/admin und user/user sind die Platzhalter, e2e hat seit #177 ein zufälliges Passwort in data/e2e-password.txt. Angefasst wurde keines. Dass die beiden kürzer als 8 Zeichen sind, stört nicht: geprüft wird die Länge nur beim Setzen über die API, nicht beim Anmelden.

Tests

./check.sh                       -> 118 Files, 1711 Tests, CHECK EXIT 0
npm run build                    -> BUILD EXIT 0
GM_STEPS=45 (frisch geseedet)    -> ALL PASSED - 19 checks   (vorher 11)
  • 8 neue e2e-Checks in Modul 45: Kontomenü mit dem nicht wählbaren Namen, Dialog geht auf, zu kurzes Passwort ohne Serverfrage abgelehnt, falsches aktuelles Passwort abgelehnt (Dialog bleibt stehen), Änderung geht durch, altes Passwort meldet nicht mehr an, neues schon, am Ende Rücksetzen auf das Originalpasswort.
  • 6 neue Unit-Tests in tests/core/auth.test.ts: die Regeln der Maske und HttpAuthStore.changePassword samt der Unterscheidung 401 (falsches altes Passwort) gegen 422 (neues zu kurz) — letzteres darf gerade nicht als „falsches Passwort" erscheinen.
  • API direkt gemessen über https://nockal.com mit einem Wegwerfkonto: ohne Session 401, GET 405, falsches altes Passwort 401, zu kurzes neues 422, richtige Angabe 204 — danach zweite Sitzung des Kontos {"user":null}, eigene weiter gültig, altes Passwort 401, neues 200. data/users.json danach aus der Sicherung zurückgelegt, Sessions des Wegwerfkontos gelöscht, make-user.php --list zeigt wieder genau admin, e2e, user.
  • Gegenprobe mit eingebautem Fehler: In Auth::changePassword die Prüfung des alten Passworts ausgehebelt → genau ein Check fällt (18 PASS, 1 FAIL). Original per cmp zurückgeprüft.
  • Check-Summe 1126 = 1118 + 8. Die 1118 ist von CI an 1ef497f bestätigt, die 1126 ist gerechnet; der Lauf zu c830c7a bestätigt sie.

Ein Punkt, der bleibt

Modul 45 fasst das echte Passwort des e2e-Kontos an und setzt es am Ende zurück. Stirbt ein Lauf genau dazwischen, steht das Konto auf <passwort>-tmp und jedes Tool scheitert am Anmelden. Die Reparatur (ein make-user.php-Aufruf) steht als Kommentar im Modul. Sauberer wäre ein Wegwerfkonto — das hängt an #178.

Doku

Wiki: Accounts (neuer Abschnitt Changing the password, Kontomenü statt Logout-Knopf), API (die Route mit 401/422 und dem Abmelden der anderen Sitzungen), Architecture (PasswordDialog), Concepts (Kontomenü), Development (Check-Summe).

Umgesetzt in `c830c7a`, Wiki in `3310139`. ## Was gebaut ist **Kontomenü statt Logout-Knopf** (Rückfrage 2, dein „passt auch"): Ganz rechts in der Toolbar steht **Account**. Darin „Signed in as &lt;name&gt;" als Eintrag, der nicht anklickbar ist, darunter **Change password…** und **Logout**. **Dialog** `src/editor/auth/PasswordDialog.ts`: aktuelles Passwort, neues, Wiederholung, alle drei als Bullets. Anders als die übrigen Formulardialoge bleibt er bei einer Ablehnung stehen — sonst könnte er nicht sagen, warum. Die Regeln (leer, zu kurz, neu gleich alt, Wiederholung abweichend) liegen als reine Funktion `passwordProblem()` neben `loginProblem()`. **Server:** `POST ?r=auth/password` `{currentPassword,newPassword}` → 204. Das alte Passwort wird verlangt, obwohl eine Session da ist; 401 bei falschem alten Passwort, 422 unter der Mindestlänge. Die Route ist die einzige unter `auth/`, die eine Session braucht. Mindestlänge **8** in `UserStore::MIN_PASSWORD_LENGTH` und noch einmal im Client, damit die Maske ohne Serverfrage antworten kann. **Andere Sitzungen enden** (Rückfrage 4): neu ist `SessionStore::destroyAllFor($user, $keep)` — alle übrigen Logins des Kontos werden beendet, die des Tabs, der ändert, bleibt. War nicht umständlich, die Sessions liegen ohnehin als Dateien vor. **Platzhalter bleiben** (Rückfrage 1). Eine Klarstellung zu deiner Rückfrage: `admin`/`admin` und `user`/`user` sind die Platzhalter, `e2e` hat seit #177 ein zufälliges Passwort in `data/e2e-password.txt`. Angefasst wurde keines. Dass die beiden kürzer als 8 Zeichen sind, stört nicht: geprüft wird die Länge nur beim *Setzen* über die API, nicht beim Anmelden. ## Tests ``` ./check.sh -> 118 Files, 1711 Tests, CHECK EXIT 0 npm run build -> BUILD EXIT 0 GM_STEPS=45 (frisch geseedet) -> ALL PASSED - 19 checks (vorher 11) ``` - **8 neue e2e-Checks in Modul 45:** Kontomenü mit dem nicht wählbaren Namen, Dialog geht auf, zu kurzes Passwort ohne Serverfrage abgelehnt, falsches aktuelles Passwort abgelehnt (Dialog bleibt stehen), Änderung geht durch, altes Passwort meldet nicht mehr an, neues schon, am Ende Rücksetzen auf das Originalpasswort. - **6 neue Unit-Tests** in `tests/core/auth.test.ts`: die Regeln der Maske und `HttpAuthStore.changePassword` samt der Unterscheidung 401 (falsches altes Passwort) gegen 422 (neues zu kurz) — letzteres darf gerade nicht als „falsches Passwort" erscheinen. - **API direkt gemessen** über `https://nockal.com` mit einem Wegwerfkonto: ohne Session 401, `GET` 405, falsches altes Passwort 401, zu kurzes neues 422, richtige Angabe 204 — danach zweite Sitzung des Kontos `{"user":null}`, eigene weiter gültig, altes Passwort 401, neues 200. `data/users.json` danach aus der Sicherung zurückgelegt, Sessions des Wegwerfkontos gelöscht, `make-user.php --list` zeigt wieder genau `admin`, `e2e`, `user`. - **Gegenprobe mit eingebautem Fehler:** In `Auth::changePassword` die Prüfung des alten Passworts ausgehebelt → genau ein Check fällt (18 PASS, 1 FAIL). Original per `cmp` zurückgeprüft. - **Check-Summe 1126** = 1118 + 8. Die 1118 ist von CI an `1ef497f` bestätigt, die 1126 ist gerechnet; der Lauf zu `c830c7a` bestätigt sie. ## Ein Punkt, der bleibt Modul 45 fasst das echte Passwort des `e2e`-Kontos an und setzt es am Ende zurück. Stirbt ein Lauf genau dazwischen, steht das Konto auf `<passwort>-tmp` und jedes Tool scheitert am Anmelden. Die Reparatur (ein `make-user.php`-Aufruf) steht als Kommentar im Modul. Sauberer wäre ein Wegwerfkonto — das hängt an #178. ## Doku Wiki: **Accounts** (neuer Abschnitt *Changing the password*, Kontomenü statt Logout-Knopf), **API** (die Route mit 401/422 und dem Abmelden der anderen Sitzungen), **Architecture** (`PasswordDialog`), **Concepts** (Kontomenü), **Development** (Check-Summe).
admin moved this to Done in Development on 2026-09-20 13:48:41 +02:00
Author
Owner

CI-Nachtrag zu c830c7a: grün. Gate (Task 172) 118 Testdateien, CHECK EXIT 0; Suite (Task 173) ALL PASSED – 1126 checks, Smokes 24 / 19 / 21. Die Check-Summe 1126 ist damit bestätigt.

CI-Nachtrag zu `c830c7a`: grün. Gate (Task 172) 118 Testdateien, `CHECK EXIT 0`; Suite (Task 173) `ALL PASSED – 1126 checks`, Smokes 24 / 19 / 21. Die Check-Summe 1126 ist damit bestätigt.
meleki referenced this issue from a commit 2026-09-20 17:24:47 +02:00
Refactoring round 5 covers the code since round 4 without changing behaviour: four identical copies of dot() and three of "nearest point on a segment" stood in the collision math, in the hit area of the collider outlines and in the polygon handles, so they moved into the new module src/core/util/vec.ts; the warning line, the busy state, info() and the caret reset were written out line by line in both the sign-in screen and the password dialog and are now FormStatus; the closing row "Cancel plus a confirming button, optionally one on the left" was built by hand in FormDialog, FilePicker, OpenProjectDialog and PasswordDialog and is now dialogButtons(); the header bar was drawn by the toolbar, the TabHeader and the Breadcrumb each on its own and is now drawHeaderBar(); AddColliderCommand and AddRigidbodyCommand share a base, each subclass only builds its own asset; Editor.ts derives the panes from assetEditors instead of repeating eight entries and clamps its splitters with clamp(); jscpd over src falls from 0.19 % to 0.14 %; dead code is gone - listScenes() has been orphaned since the Scene picker fell away (#183), DEFAULT_FILTER (#152) was never used, the two test hooks projectPickerRowAt/rowPosition and particleCompiles are read by no tool, and four functions lost an export they did not need; seven comments that told history ("used to", "no longer", "since #...") describe the state of things now, and that this changed nothing was proved by a rebuild - the bundle is md5 identical, b4ad0dfe... before and after; the README said Logout sits at the far right of the toolbar, which has been the Account menu since #182, and wiki/Architecture.md was missing src/core/util/ altogether; 4 new unit tests cover vec.ts, and switching the clamp on the segment off makes exactly one of them fail while none of the 76 neighbouring tests notice, so that clamping was covered nowhere before (#85)
Sign in to join this conversation.
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: meleki/feuerwerk#182