fix: login via code

Signed-off-by: Sebastian Krupinski <krupinski01@gmail.com>
This commit is contained in:
2026-07-18 21:25:51 -04:00
parent 03713df716
commit 1ddd49d6d7
4 changed files with 20 additions and 10 deletions
+8 -1
View File
@@ -128,7 +128,7 @@ class EnrollmentController extends ControllerAbstract
/** /**
* Remove TOTP enrollment (disable 2FA) * Remove TOTP enrollment (disable 2FA)
*/ */
#[AuthenticatedRoute('/totp/enroll', name: 'totp.enroll.remove', methods: ['DELETE'])] #[AuthenticatedRoute('/totp/enroll/remove', name: 'totp.enroll.remove', methods: ['POST'])]
public function removeEnrollment(string $code): JsonResponse public function removeEnrollment(string $code): JsonResponse
{ {
$userId = $this->userIdentity->identifier(); $userId = $this->userIdentity->identifier();
@@ -139,6 +139,13 @@ class EnrollmentController extends ControllerAbstract
); );
} }
if (empty($code)) {
return new JsonResponse(
['error' => 'Verification code is required', 'error_code' => 'invalid_request'],
JsonResponse::HTTP_BAD_REQUEST
);
}
// Verify current code before removing // Verify current code before removing
$verifyResult = $this->enrollmentService->verifyCode($userId, $code); $verifyResult = $this->enrollmentService->verifyCode($userId, $code);
if (!$verifyResult['success']) { if (!$verifyResult['success']) {
+1 -1
View File
@@ -128,7 +128,7 @@ class EnrollmentService
} }
// Verify the code // Verify the code
if (!$this->verifyCode($enrollment['secret'], $code)) { if (!$this->verifyTotpCode($enrollment['secret'], $code)) {
return [ return [
'success' => false, 'success' => false,
'error' => 'Invalid verification code', 'error' => 'Invalid verification code',
+7 -6
View File
@@ -116,9 +116,9 @@ class EnrollmentStore
} }
/** /**
* Get unused recovery codes for a user * Get unused recovery codes for a user, keyed by their original index
* *
* @return array<string> Unused recovery codes * @return array<int, string> Unused recovery codes
*/ */
public function getRecoveryCodes(string $tenantId, string $userId): array public function getRecoveryCodes(string $tenantId, string $userId): array
{ {
@@ -130,14 +130,15 @@ class EnrollmentStore
$codes = $enrollment['recovery_codes'] ?? []; $codes = $enrollment['recovery_codes'] ?? [];
$usedIndices = $enrollment['used_recovery_codes'] ?? []; $usedIndices = $enrollment['used_recovery_codes'] ?? [];
// Filter out used codes // Filter out used codes, preserving original indices so callers
// can mark the correct code as used
$result = []; $result = [];
foreach ($codes as $index => $code) { foreach ($codes as $index => $code) {
if (!in_array($index, $usedIndices, true)) { if (!in_array($index, $usedIndices, true)) {
$result[] = $code; $result[$index] = $code;
} }
} }
return $result; return $result;
} }
+4 -2
View File
@@ -140,9 +140,11 @@ async function disableTotp() {
disableError.value = '' disableError.value = ''
try { try {
const response = await fetch(`${apiBase}/totp/enroll?code=${encodeURIComponent(disableCode.value)}`, { const response = await fetch(`${apiBase}/totp/enroll/remove`, {
method: 'DELETE', method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'include', credentials: 'include',
body: JSON.stringify({ code: disableCode.value }),
}) })
const data = await response.json() const data = await response.json()