2FA-Login: Prüfung schlägt nicht offen fehl, Fehlversuche vor dem Aufruf zählen

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ClaudeandClaude Opus 5.5 committed 2026-09-30 10:39:24 +00:00
1 parent acc86c267b
commit d7c2027d3f
6 files changed
+48 -5

No files matched your search

+15
View File
@@ -64,6 +64,21 @@ export function appwriteSessionFetch(path, { method = 'GET', body, sessionCookie
})
}
/**
* Braucht die Sitzung noch einen zweiten Faktor (Appwrite-2FA)? Fragt Appwrite selbst statt des
* mfa-Flags aus dem Admin-Abruf, damit ein gestoerter Abruf nicht ohne Code durchlaesst. Andere
* Fehler werden geworfen (fail closed).
*/
export async function sessionNeedsSecondFactor(sessionCookie) {
try {
await appwriteSessionFetch('/account', { sessionCookie })
return false
} catch (err) {
if (err.type === 'user_more_factors_required') return true
throw err
}
}
/**
* Login via Appwrite Auth REST. userId kommt aus der Session – kein users.read nötig.
*/
+7 -3
View File
@@ -51,7 +51,9 @@ export async function startStaffMfa({ userId, email, sessionCookie }) {
/** @returns {Promise<{ok: true, userId: string, email: string} | {ok: false, reason: 'invalid' | 'gone'}>} */
export async function verifyStaffMfa(key, otp) {
const entry = liveEntry(key)
if (!entry) return { ok: false, reason: 'gone' }
if (!entry || entry.attempts >= MAX_ATTEMPTS) return { ok: false, reason: 'gone' }
// Versuch vor dem Appwrite-Aufruf reservieren, sonst zaehlen parallele Anfragen alle als erster Versuch
entry.attempts += 1
try {
await appwriteSessionFetch('/account/mfa/challenges', {
method: 'PUT',
@@ -59,8 +61,10 @@ export async function verifyStaffMfa(key, otp) {
sessionCookie: entry.sessionCookie,
})
} catch (err) {
if (err.type !== 'user_invalid_token') throw err
entry.attempts += 1
if (err.type !== 'user_invalid_token') {
entry.attempts -= 1
throw err
}
if (entry.attempts >= MAX_ATTEMPTS) pending.delete(key)
return { ok: false, reason: 'invalid' }
}