Der Aufforderungsbildschirm
Wartungsaufzeichnung zu do=wkidentity_stepup — dem Bildschirm, durch den jeder Zweitfaktor-Ablauf der Plattform läuft. Sie hält fest, warum er so gebaut ist, damit die vier Entscheidungen nicht versehentlich zurückgedreht werden.
Status
Angenommen, live seit dem 9. August 2026.
Kontext
[Live seit 2026-08-09] do=wkidentity_stepup ist der Bildschirm, durch den jeder
Zweitfaktor-Ablauf der Plattform läuft — der eigene ebenso wie die sechs angeschlossenen Pakete.
Was hier an Tastaturbedienung, Beschriftung und Fehlermeldung stimmt oder nicht stimmt, wirkt
überall.
Mechanismus
Die Eingabetaste drückt den Prüfknopf, nicht den Sendeknopf
HTML aktiviert beim Enter in einem Textfeld den ersten Absendeknopf des Formulars, nicht den nächstgelegenen. Solange „Code per E-Mail senden„ und das Codefeld in einem Formular standen, forderte Enter also einen neuen Code an — und weil ein neuer Code den gespeicherten Hash überschreibt, wurde der gerade getippte in demselben Moment ungültig, während der Bildschirm „Code gesendet“ meldete.
Deshalb sind es jetzt zwei Geschwisterformulare: der Sendeknopf steht in einem eigenen, sodass der einzige Absender des Codeformulars derjenige ist, der prüft. Das war zugleich die Antwort auf dieselbe Frage in der Anmeldeschranke.
Das Codefeld kommt aus einer Klasse, nicht aus vier Handschriften
CodeField::html($totp, $name, $opts) ist die eine Stelle, die ein Einmalcode-Feld zeichnet.
Beide Grenzen leitet sie aus der Einstellung digits ab statt sie zu schreiben:
| Eigenschaft | Wert | Warum abgeleitet |
|---|---|---|
pattern | digits Ziffern, Leerzeichen erlaubt | Beide Prüfer entfernen Leerzeichen, bevor sie zählen — das Feld muss annehmen, was der Prüfer annimmt |
maxlength | doppelte digits | 123 456 ist sieben Zeichen lang; ein festes maxlength=6 schnitt daraus 123 45 |
required ist ausdrücklich opt-in. Die Formularprüfung des Browsers läuft bei jedem
Absenden des umgebenden Formulars. Auf den einzweckigen Aufforderungsbildschirmen ist sie richtig;
im Profilformular stünde sie neben „Speichern„ und würde es blockieren. Der Abbrechen-Knopf trägt
zusätzlich formnovalidate — sonst tut er auf einem leeren Formular gar nichts.
Fehler, Nebenaktion, Ausweg
- Ein falscher Code wird am Feld gemeldet, mit
role=„alert“und überaria-describedbyverknüpft — nicht in der allgemeinen Meldungsleiste, wo er von dem Feld getrennt steht, das er betrifft. - Abbrechen und „Code senden“ sind leise. Vorher rechneten alle drei Absendeknöpfe auf denselben Akzentton; „Abbrechen„ war so laut wie „Bestätigen“.
- Eine Sackgasse — ein Konto, das die Anforderung gar nicht erfüllen kann — bietet einen Weg zurück (
stepup_back), den die Anmeldeschranke seit jeher hatte und dieser Bildschirm nicht. code_format_hintnennt die erwartete Stellenzahl, damit die Regel dasteht, statt erraten zu werden.
Die Entscheidung fällt vor der Ausgabe
Bis zum 9. August 2026 traf dieser Bildschirm seine Entscheidung im Renderhaken
(TPL_ACT_UNKNOWN), und dort wirkt keine Weiterleitung: der Haken feuert aus
tpl_content() heraus, also aus einer Seite, die die Vorlage bereits schreibt. Die Folge war
schlimmer als eine Warnung — ein korrekter Code wurde angenommen, die Assurance vermerkt, und
der Rücksprung scheiterte still, sodass der Mensch auf einer halb gezeichneten Seite stehen blieb.
In der Anmeldeschranke war es der Anmeldekeks, der nicht gesetzt wurde.
Entschieden wird jetzt in ACTION_ACT_PREPROCESS, das tatsächlich vor jeder Ausgabe liegt; der
Renderhaken zeichnet nur noch, was bereits entschieden ist. Dieselbe Verlagerung haben alle sechs
angeschlossenen Pakete bekommen.
Konsequenzen
- Sende- und Prüfknopf bleiben in getrennten Formularen. Stehen sie wieder in einem, fordert die Eingabetaste einen neuen Code an und entwertet damit den gerade getippten.
- Das Codefeld bleibt
CodeField::html().patternundmaxlengthwerden aus der Einstellungdigitsabgeleitet, nie geschrieben — ein festesmaxlengthschneidet den Code mit Leerzeichen ab. - Die Entscheidung bleibt in
ACTION_ACT_PREPROCESS. Im Renderhaken wirkt keine Weiterleitung, und der Fehler ist still: ein korrekter Code wird angenommen und der Rücksprung scheitert trotzdem.