From 7147caebe3688202b00424f5261337cdb3ca20b7 Mon Sep 17 00:00:00 2001 From: Austin Drummond Date: Sat, 26 Apr 2025 23:25:17 -0400 Subject: [PATCH 1/2] replace fetch with axios Inertia uses axios under the hood, which includes automatic CSRF token handling per https://inertiajs.com/csrf-protection --- resources/js/hooks/use-two-factor-auth.tsx | 116 +++++++++------------ resources/views/app.blade.php | 1 - 2 files changed, 50 insertions(+), 67 deletions(-) diff --git a/resources/js/hooks/use-two-factor-auth.tsx b/resources/js/hooks/use-two-factor-auth.tsx index 6652a1d2f..22b002a76 100644 --- a/resources/js/hooks/use-two-factor-auth.tsx +++ b/resources/js/hooks/use-two-factor-auth.tsx @@ -1,4 +1,5 @@ import { useState, useEffect } from 'react'; +import axios, { AxiosError } from 'axios'; interface EnableResponse { qrCode: string; @@ -16,15 +17,6 @@ interface RecoveryCodesResponse { } export function useTwoFactorAuth(initialConfirmed: boolean, initialRecoveryCodes: string[]) { - const csrfToken = - document.querySelector('meta[name="csrf-token"]')?.getAttribute('content') || ''; - - const headers = { - 'Content-Type': 'application/json', - Accept: 'application/json', - 'X-CSRF-TOKEN': csrfToken, - 'X-Requested-With': 'XMLHttpRequest', - }; const [confirmed, setConfirmed] = useState(initialConfirmed); const [qrCodeSvg, setQrCodeSvg] = useState(''); @@ -46,20 +38,19 @@ export function useTwoFactorAuth(initialConfirmed: boolean, initialRecoveryCodes const enable = async () => { try { - const response = await fetch(route('two-factor.enable'), { - method: 'POST', - headers, - }); - - if (response.ok) { - const data: EnableResponse = await response.json(); - setQrCodeSvg(data.qrCode); + const response = await axios.post(route('two-factor.enable')); + + const data: EnableResponse = response.data; + setQrCodeSvg(data.qrCode); setSecretKey(data.secret); - } else { - console.error('Error enabling 2FA:', response.statusText); - } } catch (error) { console.error('Error enabling 2FA:', error); + if (error instanceof AxiosError && error.response?.data) { + const errorData = error.response.data; + console.error('Verification error:', errorData.message); + setError(errorData.message || 'Invalid verification code'); + setPasscode(''); + } } }; @@ -69,71 +60,64 @@ export function useTwoFactorAuth(initialConfirmed: boolean, initialRecoveryCodes const formattedCode = passcode.replace(/\s+/g, '').trim(); try { - const response = await fetch(route('two-factor.confirm'), { - method: 'POST', - headers, - body: JSON.stringify({ code: formattedCode }), - }); - - if (response.ok) { - const responseData: ConfirmResponse = await response.json(); - if (responseData.recovery_codes) { - setRecoveryCodesList(responseData.recovery_codes); - } - - setConfirmed(true); - setVerifyStep(false); - setShowModal(false); - setShowingRecoveryCodes(true); - setPasscode(''); - setError(''); - } else { - const errorData = await response.json(); + const response = await axios.post(route('two-factor.confirm'), { code: formattedCode }); + + const responseData: ConfirmResponse = response.data; + if (responseData.recovery_codes) { + setRecoveryCodesList(responseData.recovery_codes); + } + + setConfirmed(true); + setVerifyStep(false); + setShowModal(false); + setShowingRecoveryCodes(true); + setPasscode(''); + setError(''); + + } catch (error) { + console.error('Error confirming 2FA:', error); + if (error instanceof AxiosError && error.response?.data) { + const errorData = error.response.data; console.error('Verification error:', errorData.message); setError(errorData.message || 'Invalid verification code'); setPasscode(''); + return; } - } catch (error) { - console.error('Error confirming 2FA:', error); setError('An error occurred while confirming 2FA'); } }; const regenerateRecoveryCodes = async () => { try { - const response = await fetch(route('two-factor.regenerate-recovery-codes'), { - method: 'POST', - headers, - }); - - if (response.ok) { - const data: RecoveryCodesResponse = await response.json(); - if (data.recovery_codes) { - setRecoveryCodesList(data.recovery_codes); - } - } else { - console.error('Error regenerating codes:', response.statusText); + const response = await axios.post(route('two-factor.regenerate-recovery-codes')); + const data: RecoveryCodesResponse = await response.data; + if (data.recovery_codes) { + setRecoveryCodesList(data.recovery_codes); } } catch (error) { console.error('Error regenerating codes:', error); + if (error instanceof AxiosError && error.response?.data) { + const errorData = error.response.data; + setError(errorData.message || 'Invalid verification code'); + } } }; const disable = async () => { try { - const response = await fetch(route('two-factor.disable'), { method: 'DELETE', headers }); - - if (response.ok) { - setConfirmed(false); - setShowingRecoveryCodes(false); - setRecoveryCodesList([]); - setQrCodeSvg(''); - setSecretKey(''); - } else { - console.error('Error disabling 2FA:', response.statusText); - } + await axios.delete(route('two-factor.disable')); + + setConfirmed(false); + setShowingRecoveryCodes(false); + setRecoveryCodesList([]); + setQrCodeSvg(''); + setSecretKey(''); } catch (error) { console.error('Error disabling 2FA:', error); + if (error instanceof AxiosError && error.response?.data) { + const errorData = error.response.data; + setError(errorData.message || 'Invalid verification code'); + } } }; @@ -165,4 +149,4 @@ export function useTwoFactorAuth(initialConfirmed: boolean, initialRecoveryCodes disable, copyToClipboard, }; -} \ No newline at end of file +} diff --git a/resources/views/app.blade.php b/resources/views/app.blade.php index 1b8590beb..309383555 100644 --- a/resources/views/app.blade.php +++ b/resources/views/app.blade.php @@ -3,7 +3,6 @@ - {{-- Inline script to detect system dark mode preference and apply it immediately --}}