Zwei-Faktor-Anmeldung bei Calendarr
Deine Zugangsdaten stimmten. Der Fehler lag im gewählten Endpunkt:
auth_router.py:81 if user.totp_enabled:
raise HTTPException(401, detail="2fa_required")
/api/auth/token nimmt nur ein Formular mit Benutzername und Passwort entgegen
und weist Konten mit zweitem Faktor grundsätzlich ab — mit demselben 401 wie
ein falsches Passwort. Deshalb stand da „Benutzername oder Passwort stimmen
nicht", obwohl beides stimmte.
Angemeldet wird jetzt über /api/auth/login: der Weg nimmt den Code entgegen
und kennt remember_me. Das ist hier keine Bequemlichkeit, sondern die
Bedingung — mit zweitem Faktor kann Onyx sich nicht selbst neu anmelden, den
Code hat nur der Mensch. Ein gewöhnliches Token hielte sieben Tage,
remember_me hält hundertachtzig.
Damit wandert auch das Token in den Schlüsselbund. Bei einem Konto mit
zweitem Faktor ist es das einzige, womit Onyx noch hineinkommt; ginge es beim
Beenden verloren, müsste man sich bei jedem Start neu anmelden.
Die drei Fälle sind jetzt auseinandergehalten und einzeln beschriftet:
falsches Passwort, fehlender Code, falscher Code. Der Unterschied ist der
zwischen „Passwort neu tippen" und „App aufmachen" — und er steckt beim
Server nur im Begleittext eines 401.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -70,6 +70,27 @@ struct CalendarrLiveTests {
|
||||
#expect(CalendarrLiveDecoder.expiry(ofToken: "a.b.c") == nil)
|
||||
}
|
||||
|
||||
@Test("Ein Konto mit zweitem Faktor wird als solches erkannt")
|
||||
func twoFactorIsToldApart() {
|
||||
// Der Fehler, der die erste Fassung unbrauchbar machte: der Server
|
||||
// antwortet auf beides mit 401. Stand da „Passwort falsch", obwohl es
|
||||
// stimmte, sucht man an der falschen Stelle.
|
||||
#expect(CalendarrLiveDecoder.loginFailure(status: 401, detail: "2fa_required")
|
||||
== .twoFactorRequired)
|
||||
#expect(CalendarrLiveDecoder.loginFailure(status: 401, detail: "Ungültiger 2FA-Code")
|
||||
== .twoFactorWrong)
|
||||
#expect(CalendarrLiveDecoder.loginFailure(status: 401,
|
||||
detail: "Benutzername oder Passwort falsch")
|
||||
== .unauthorized)
|
||||
#expect(CalendarrLiveDecoder.loginFailure(status: 401, detail: nil) == .unauthorized)
|
||||
}
|
||||
|
||||
@Test("Andere Antworten bleiben, was sie sind")
|
||||
func otherStatusesPassThrough() {
|
||||
#expect(CalendarrLiveDecoder.loginFailure(status: 200, detail: nil) == nil)
|
||||
#expect(CalendarrLiveDecoder.loginFailure(status: 502, detail: nil) == .status(502))
|
||||
}
|
||||
|
||||
// MARK: - Termine
|
||||
|
||||
private func json(_ object: Any) throws -> Data {
|
||||
|
||||
Reference in New Issue
Block a user