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>
501 lines
12 KiB
Plaintext
501 lines
12 KiB
Plaintext
{
|
||
"sourceLanguage": "en",
|
||
"strings": {
|
||
"": {},
|
||
"%lld": {
|
||
"comment": "A day of the month. The argument is the day of the month.",
|
||
"isCommentAutoGenerated": true,
|
||
"localizations": {
|
||
"de": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "%lld"
|
||
}
|
||
},
|
||
"en": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "%lld"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"calendar.source.apple": {
|
||
"localizations": {
|
||
"de": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Apple Kalender"
|
||
}
|
||
},
|
||
"en": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Apple Calendar"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"calendar.source.both": {
|
||
"localizations": {
|
||
"de": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Beide"
|
||
}
|
||
},
|
||
"en": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Both"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"calendar.source.calendarr": {
|
||
"localizations": {
|
||
"de": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Calendarr"
|
||
}
|
||
},
|
||
"en": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Calendarr"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"calendar.source.readOnly": {
|
||
"localizations": {
|
||
"de": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Onyx liest nur. Es meldet sich nie selbst an und schreibt nie nach Calendarr."
|
||
}
|
||
},
|
||
"en": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Onyx only reads. It never signs in and never writes to Calendarr."
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"calendar.source.status.coverage": {
|
||
"extractionState": "stale",
|
||
"localizations": {
|
||
"de": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Bekannt bis %@"
|
||
}
|
||
},
|
||
"en": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Known through %@"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"calendar.source.status.coverage %@": {
|
||
"comment": "A footnote in the Calendarr settings, indicating the end of the coverage window.",
|
||
"isCommentAutoGenerated": true,
|
||
"localizations": {
|
||
"de": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Bekannt bis %@"
|
||
}
|
||
},
|
||
"en": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Known through %@"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"calendar.source.status.incompatible": {
|
||
"localizations": {
|
||
"de": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Calendarr schreibt ein neueres Format. Bitte Onyx aktualisieren."
|
||
}
|
||
},
|
||
"en": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Calendarr writes a newer format. Please update Onyx."
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"calendar.source.status.loggedOut": {
|
||
"localizations": {
|
||
"de": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "In Calendarr nicht angemeldet. Alte Termine werden nicht gezeigt."
|
||
}
|
||
},
|
||
"en": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Not signed in to Calendarr. Old events are not shown."
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"calendar.source.status.neverWritten": {
|
||
"localizations": {
|
||
"de": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Calendarr einmal öffnen, damit ein Schnappschuss geschrieben wird."
|
||
}
|
||
},
|
||
"en": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Open Calendarr once so it can write a snapshot."
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"calendar.source.status.ready": {
|
||
"extractionState": "stale",
|
||
"localizations": {
|
||
"de": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "%@ Termine, Stand %@"
|
||
}
|
||
},
|
||
"en": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "%@ events, as of %@"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"calendar.source.status.ready %@ %@": {
|
||
"comment": "Die Anzahl der Termine in der The argument is the string “–”.",
|
||
"isCommentAutoGenerated": true,
|
||
"localizations": {
|
||
"en": {
|
||
"stringUnit": {
|
||
"state": "new",
|
||
"value": "calendar.source.status.ready %1$@ %2$@"
|
||
}
|
||
},
|
||
"de": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "%@ Termine, Stand %@"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"calendar.source.status.unreadable": {
|
||
"extractionState": "stale",
|
||
"localizations": {
|
||
"de": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Schnappschuss unlesbar: %@"
|
||
}
|
||
},
|
||
"en": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Snapshot unreadable: %@"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"calendar.source.status.unreadable %@": {
|
||
"comment": "A warning message explaining that a Calendarr source is not readable. The argument is a human-readable description of the problem.",
|
||
"isCommentAutoGenerated": true,
|
||
"localizations": {
|
||
"de": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Schnappschuss unlesbar: %@"
|
||
}
|
||
},
|
||
"en": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Snapshot unreadable: %@"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"calendar.source.title": {
|
||
"localizations": {
|
||
"de": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Terminquelle"
|
||
}
|
||
},
|
||
"en": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Calendar source"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"calendarr.live.error.credentials": {
|
||
"localizations": {
|
||
"de": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Benutzername oder Passwort stimmen nicht."
|
||
}
|
||
},
|
||
"en": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Wrong username or password."
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"calendarr.live.error.response": {
|
||
"localizations": {
|
||
"de": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Der Server hat geantwortet, aber nicht verständlich."
|
||
}
|
||
},
|
||
"en": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "The server replied, but not intelligibly."
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"calendarr.live.error.server": {
|
||
"localizations": {
|
||
"de": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Diese Adresse ergibt keinen Server."
|
||
}
|
||
},
|
||
"en": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "That address doesn’t resolve to a server."
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"calendarr.live.error.status %lld": {
|
||
"localizations": {
|
||
"de": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Der Server meldet Fehler %lld."
|
||
}
|
||
},
|
||
"en": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "The server reports error %lld."
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"calendarr.live.error.twoFactor": {
|
||
"localizations": {
|
||
"de": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Dieses Konto verlangt einen Zwei-Faktor-Code."
|
||
}
|
||
},
|
||
"en": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "This account requires a two-factor code."
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"calendarr.live.error.twoFactorWrong": {
|
||
"localizations": {
|
||
"de": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Der Zwei-Faktor-Code stimmt nicht — er gilt nur eine halbe Minute."
|
||
}
|
||
},
|
||
"en": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Wrong two-factor code — it’s only valid for half a minute."
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"widget.calendar.allDay": {
|
||
"localizations": {
|
||
"de": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Ganztägig"
|
||
}
|
||
},
|
||
"en": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "All day"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"widget.calendar.day.unknown": {
|
||
"comment": "Erklärt einen ausgegrauten Tag: keine Information, nicht keine Termine",
|
||
"localizations": {
|
||
"de": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Für diesen Tag liegen keine Daten vor"
|
||
}
|
||
},
|
||
"en": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "No data available for this day"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"widget.calendar.denied": {
|
||
"localizations": {
|
||
"de": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Kein Kalenderzugriff.\nIn den Systemeinstellungen erlauben."
|
||
}
|
||
},
|
||
"en": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "No calendar access.\nAllow it in System Settings."
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"widget.calendar.incompatible": {
|
||
"localizations": {
|
||
"de": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Onyx ist zu alt für diese\nCalendarr-Version. Bitte aktualisieren."
|
||
}
|
||
},
|
||
"en": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Onyx is too old for this\nCalendarr version. Please update."
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"widget.calendar.loggedOut": {
|
||
"localizations": {
|
||
"de": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "In Calendarr anmelden"
|
||
}
|
||
},
|
||
"en": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Sign in to Calendarr"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"widget.calendar.name": {
|
||
"localizations": {
|
||
"de": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Kalender"
|
||
}
|
||
},
|
||
"en": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Calendar"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"widget.calendar.neverWritten": {
|
||
"localizations": {
|
||
"de": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Calendarr einmal öffnen,\ndamit Termine bereitstehen."
|
||
}
|
||
},
|
||
"en": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Open Calendarr once\nso events become available."
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"widget.calendar.noUpcoming": {
|
||
"comment": "Nur zeigen, wenn der Zeitraum wirklich abgedeckt ist",
|
||
"localizations": {
|
||
"de": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Nichts mehr für heute"
|
||
}
|
||
},
|
||
"en": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Nothing left today"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"widget.calendar.unreadable": {
|
||
"localizations": {
|
||
"de": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Termine nicht lesbar.\nKonfigurationsfehler."
|
||
}
|
||
},
|
||
"en": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Events unreadable.\nConfiguration error."
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"version": "1.1"
|
||
}
|