Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 40 additions & 6 deletions components/guards/SetupMFA.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,12 @@ const SetupMFA = () => {
const userVerifiedEmail = useTypedSelector((state) => state.user.verifiedEmail);

const [phoneNumber, setPhoneNumber] = useState('');
const [storedPhoneNumber, setStoredPhoneNumber] = useState('');
const [verificationId, setVerificationId] = useState('');
const [verificationCode, setVerificationCode] = useState('');
const [error, setError] = useState('');
const [emailVerificationSent, setEmailVerificationSent] = useState(false);
const [emailVerificationSuccess, setEmailVerificationSuccess] = useState('');
const [showReauth, setShowReauth] = useState(false);
const [password, setPassword] = useState('');
const [isReauthenticating, setIsReauthenticating] = useState(false);
Expand All @@ -51,6 +54,20 @@ const SetupMFA = () => {
};
}, []);

// Store phone number when user enters it
useEffect(() => {
if (phoneNumber && !storedPhoneNumber) {
setStoredPhoneNumber(phoneNumber);
}
}, [phoneNumber, storedPhoneNumber]);

// Restore phone number after reauthentication
useEffect(() => {
if (!showReauth && storedPhoneNumber && !phoneNumber) {
setPhoneNumber(storedPhoneNumber);
}
}, [showReauth, storedPhoneNumber, phoneNumber]);

const handleReauthentication = async () => {
if (!password.trim()) {
setError(t('form.passwordRequired'));
Expand All @@ -67,7 +84,7 @@ const SetupMFA = () => {
// Reset the MFA setup process
setVerificationId('');
setVerificationCode('');
setPhoneNumber('');
// Don't reset phone number - it will be restored from storedPhoneNumber
} catch (error: any) {
rollbar.error('Reauthentication error:', error);
if (error.code === 'auth/wrong-password') {
Expand All @@ -81,6 +98,7 @@ const SetupMFA = () => {
setIsReauthenticating(false);
}
};

const handleEnrollMFA = async () => {
if (!userVerifiedEmail) {
setError(t('form.emailNotVerified'));
Expand Down Expand Up @@ -126,16 +144,20 @@ const SetupMFA = () => {

const handleSendVerificationEmail = async () => {
setError('');
setEmailVerificationSuccess('');
const user = auth.currentUser;
if (user) {
const { error } = await sendVerificationEmail(user);
if (error) {
if (error.code === 'auth/too-many-requests') {
setError(t('form.firebase.tooManyAttempts'));
} else {
setError(t('form.emailVerificationError'));
}
rollbar.error('Send verification email error:', error);
setError(t('form.emailVerificationError'));
} else {
// Show success message instead of error
setError('');
// You might want to show a success state here instead
setEmailVerificationSent(true);
setEmailVerificationSuccess(t('form.emailVerificationSent'));
}
}
};
Expand Down Expand Up @@ -188,19 +210,31 @@ const SetupMFA = () => {
</Box>
);
}

return (
<Box>
<Typography variant="h3">{t('setupMFA.title')}</Typography>
{!userVerifiedEmail ? (
<Box>
<Typography>{t('form.emailNotVerified')}</Typography>
{emailVerificationSuccess && (
<Alert severity="success" sx={{ mt: 2, mb: 2 }}>
{emailVerificationSuccess}
<Typography variant="body2" sx={{ mt: 1 }}>
{t('form.emailVerificationSpamCheck')}
</Typography>
</Alert>
)}
<Button
variant="contained"
color="secondary"
sx={{ ...buttonStyle, mt: 2 }}
onClick={handleSendVerificationEmail}
disabled={emailVerificationSent}
>
{t('form.sendVerificationEmail')}
{emailVerificationSent
? t('form.resendVerificationEmail')
: t('form.sendVerificationEmail')}
</Button>
</Box>
) : !verificationId ? (
Expand Down
29 changes: 5 additions & 24 deletions cypress/integration/tests/superadmin-mfa.cy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,9 @@ describe('Superadmin MFA Flow', () => {
cy.wait('@getUserSuperadmin');

cy.visit('/admin/dashboard');
cy.get('h3').should('contain', 'Set up Two-Factor Authentication');
cy.get('h3').should('contain', 'Set up two-factor authentication');
cy.get('input[type="tel"]').should('exist');
cy.get('button').contains('Send Verification Code').should('exist');
cy.get('button').contains('Send verification code').should('exist');

cy.logout();
});
Expand Down Expand Up @@ -112,39 +112,20 @@ describe('Superadmin MFA Flow', () => {
cy.visit('/admin/dashboard');

// Verify MFA setup form is displayed
cy.get('h3').should('contain', 'Set up Two-Factor Authentication');
cy.get('h3').should('contain', 'Set up two-factor authentication');

// Enter phone number
cy.get('input[type="tel"]').should('be.visible').type(testPhoneNumber);

// Click send verification code button
cy.get('button').contains('Send Verification Code').should('be.visible').click();
cy.get('button').contains('Send verification code').should('be.visible').click();

// We can't mock the reCAPTCHA in Cypress, so we will skip this step that tests the actual sms sending and mfa setup

// Mock Firebase MFA enrollment endpoints
// cy.intercept('POST', '**/identitytoolkit.googleapis.com/v2/accounts/mfaEnrollment:start*', {
// statusCode: 200,
// body: {
// phoneSessionInfo: {
// sessionInfo: 'mock-session-info',
// },
// },
// }).as('mfaEnrollmentStart');

// cy.intercept('POST', '**/identitytoolkit.googleapis.com/v2/accounts/mfaEnrollment:finalize*', {
// statusCode: 200,
// body: {
// idToken: 'mock-id-token',
// refreshToken: 'mock-refresh-token',
// },
// }).as('mfaEnrollmentFinalize');
// // Enter verification code
// cy.get('input[id="verificationCode"]').should('be.visible').type(testVerificationCode);
// cy.get('button').contains('Verify Code').click();

// cy.wait('@mfaEnrollmentFinalize');

// // Should redirect to admin dashboard
// cy.url().should('include', '/admin/dashboard');
// cy.get('h2').should('contain', 'Superadmin dashboard');
Expand Down Expand Up @@ -193,7 +174,7 @@ describe('Superadmin MFA Flow', () => {

// Should show email verification requirement
cy.get('p').should('contain', 'Please verify your email before setting up 2FA');
cy.get('button').contains('Send Verification Email').should('exist');
cy.get('button').contains('Send verification email').should('exist');

cy.logout();
});
Expand Down
16 changes: 6 additions & 10 deletions i18n/messages/auth/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,19 +61,20 @@
"emailNotVerified": "Bitte verifiziere deine E-Mail-Adresse, bevor du die Zwei-Faktor-Authentifizierung einrichtest.",
"emailVerificationError": "Fehler beim Senden der Verifizierungs-E-Mail. Bitte versuche es erneut.",
"emailVerificationSent": "Verifizierungs-E-Mail wurde gesendet. Bitte überprüfe deinen Posteingang.",
"sendVerificationEmail": "Verifizierungs-E-Mail senden",
"emailVerificationSpamCheck": "Wenn du die E-Mail nicht siehst, überprüfe bitte deinen Spam-Ordner.",
"sendVerificationEmail": "Verifizierungs-e-mail senden",
"resendVerificationEmail": "Verifizierungs-e-mail erneut senden",
"passwordRequired": "Passwort ist für die erneute Authentifizierung erforderlich.",
"reauthenticationError": "Erneute Authentifizierung fehlgeschlagen. Bitte versuche es erneut."
},
"verifyMFA": {
"title": "Zwei-Faktor-Authentifizierung verifizieren",
"triggerSMS": "SMS-Code senden",
"title": "Zwei-faktor-authentifizierung verifizieren",
"triggerSMS": "SMS-code senden",
"verifyCode": "Code verifizieren",
"phoneNumber": "Wir senden einen Verifizierungscode an Ihre registrierte Telefonnummer: {phoneNumber}"
},
"setupMFA": {
"title": "Zwei-Faktor-Authentifizierung einrichten",
"pageTitle": "Sichern Sie Ihr Konto",
"title": "Zwei-faktor-authentifizierung einrichten",
"sendCode": "Verifizierungscode senden",
"verifyCode": "Code verifizieren",
"enterCodeHelperText": "Bitte geben Sie den Verifizierungscode ein, den wir an Ihr Telefon gesendet haben:",
Expand All @@ -82,11 +83,6 @@
"cancelReauth": "Abbrechen",
"confirmReauth": "Bestätigen",
"reauthenticating": "Bestätige..."
},
"verifyEmail": {
"pageTitle": "E-Mail-Adresse verifizieren",
"instructions": "Bitte überprüfe deine E-Mails und klicke auf den Verifizierungslink, um fortzufahren.",
"sendButton": "Verifizierungs-E-Mail erneut senden"
}
}
}
26 changes: 11 additions & 15 deletions i18n/messages/auth/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@
"expiredCode": "This reset password link is now expired, please <resetLink>restart the process</resetLink> and try again.",
"getUserError": "There was an error retrieving your account. Try again later and <contactLink>message the Bloom team</contactLink> if you're still getting this error."
},
"phoneNumberLabel": "Phone Number",
"verificationCodeLabel": "Verification Code",
"phoneNumberLabel": "Phone number",
"verificationCodeLabel": "Verification code",
"mfaTriggerError": "Error sending SMS code. Please try again.",
"mfaVerificationIdMissing": "Please request an SMS code first.",
"mfaEnrollError": "Error enrolling in 2FA. Please try again.",
Expand All @@ -61,32 +61,28 @@
"emailNotVerified": "Please verify your email before setting up 2FA.",
"emailVerificationError": "Error sending verification email. Please try again.",
"emailVerificationSent": "Verification email sent. Please check your inbox.",
"sendVerificationEmail": "Send Verification Email",
"emailVerificationSpamCheck": "If you don't see the email, please check your spam folder.",
"sendVerificationEmail": "Send verification email",
"resendVerificationEmail": "Resend verification email",
"passwordRequired": "Password is required for reauthentication.",
"reauthenticationError": "Failed to reauthenticate. Please try again."
},
"verifyMFA": {
"title": "Verify Two-Factor Authentication",
"triggerSMS": "Send SMS Code",
"verifyCode": "Verify Code",
"title": "Verify two-factor authentication",
"triggerSMS": "Send SMS code",
"verifyCode": "Verify code",
"phoneNumber": "We will send a verification code to your registered phone number: {phoneNumber}"
},
"setupMFA": {
"title": "Set up Two-Factor Authentication",
"pageTitle": "Secure Your Account",
"sendCode": "Send Verification Code",
"verifyCode": "Verify Code",
"title": "Set up two-factor authentication",
"sendCode": "Send verification code",
"verifyCode": "Verify code",
"enterCodeHelperText": "Please enter the verification code we sent to your phone:",
"reauthTitle": "Confirm your password",
"reauthDescription": "Please enter your password before continuing",
"cancelReauth": "Cancel",
"confirmReauth": "Confirm",
"reauthenticating": "Confirming..."
},
"verifyEmail": {
"pageTitle": "Verify Your Email",
"instructions": "Please check your email and click the verification link to continue.",
"sendButton": "Resend Verification Email"
}
}
}
8 changes: 2 additions & 6 deletions i18n/messages/auth/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,9 @@
"emailNotVerified": "Por favor, verifica tu email antes de configurar la autenticación de dos factores.",
"emailVerificationError": "Error al enviar el email de verificación. Por favor, inténtalo de nuevo.",
"emailVerificationSent": "Email de verificación enviado. Por favor, revisa tu bandeja de entrada.",
"emailVerificationSpamCheck": "Si no ves el email, por favor revisa tu carpeta de spam.",
"sendVerificationEmail": "Enviar email de verificación",
"resendVerificationEmail": "Reenviar email de verificación",
"passwordRequired": "Se requiere contraseña para la reautenticación.",
"reauthenticationError": "Error al reautenticar. Por favor, inténtalo de nuevo."
},
Expand All @@ -73,7 +75,6 @@
},
"setupMFA": {
"title": "Configurar autenticación de dos factores",
"pageTitle": "Asegura tu cuenta",
"sendCode": "Enviar código de verificación",
"verifyCode": "Verificar código",
"enterCodeHelperText": "Por favor, introduce el código de verificación que hemos enviado a tu teléfono:",
Expand All @@ -82,11 +83,6 @@
"cancelReauth": "Cancelar",
"confirmReauth": "Confirmar",
"reauthenticating": "Confirmando..."
},
"verifyEmail": {
"pageTitle": "Verifica tu email",
"instructions": "Por favor, revisa tu email y haz clic en el enlace de verificación para continuar.",
"sendButton": "Reenviar email de verificación"
}
}
}
8 changes: 2 additions & 6 deletions i18n/messages/auth/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,9 @@
"emailNotVerified": "Veuillez vérifier votre email avant de configurer l'authentification à deux facteurs.",
"emailVerificationError": "Erreur lors de l'envoi de l'email de vérification. Veuillez réessayer.",
"emailVerificationSent": "Email de vérification envoyé. Veuillez vérifier votre boîte de réception.",
"emailVerificationSpamCheck": "Si vous ne voyez pas l'email, veuillez vérifier votre dossier spam.",
"sendVerificationEmail": "Envoyer l'email de vérification",
"resendVerificationEmail": "Renvoyer l'email de vérification",
"passwordRequired": "Le mot de passe est requis pour la réauthentification.",
"reauthenticationError": "Échec de la réauthentification. Veuillez réessayer."
},
Expand All @@ -74,7 +76,6 @@
},
"setupMFA": {
"title": "Configurer l'authentification à deux facteurs",
"pageTitle": "Sécurisez votre compte",
"sendCode": "Envoyer le code de vérification",
"verifyCode": "Vérifier le code",
"enterCodeHelperText": "Veuillez entrer le code de vérification que nous avons envoyé à votre téléphone :",
Expand All @@ -83,11 +84,6 @@
"cancelReauth": "Annuler",
"confirmReauth": "Confirmer",
"reauthenticating": "Confirmation..."
},
"verifyEmail": {
"pageTitle": "Vérifiez votre email",
"instructions": "Veuillez vérifier votre email et cliquer sur le lien de vérification pour continuer.",
"sendButton": "Renvoyer l'email de vérification"
}
}
}
26 changes: 11 additions & 15 deletions i18n/messages/auth/hi.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@
"expiredCode": "This reset password link is now expired, please <resetLink>restart the process</resetLink> and try again.",
"getUserError": "Aapka account retrieve karne mein error aa raha hai. Baad mein dubara prayas kariye aur <contactLink>Bloom team ko message kariye</contactLink> agar aapko fir bhi error aa raha hai. "
},
"phoneNumberLabel": "Phone Number",
"verificationCodeLabel": "Verification Code",
"phoneNumberLabel": "Phone number",
"verificationCodeLabel": "Verification code",
"mfaTriggerError": "SMS code bhejne mein truti. Kripya punah prayaas karein.",
"mfaVerificationIdMissing": "Kripya pehle SMS code ka anuroodh karein.",
"mfaEnrollError": "2FA mein naamaakon karne mein truti. Kripya punah prayaas karein.",
Expand All @@ -61,32 +61,28 @@
"emailNotVerified": "2FA setup karne se pehle kripya apne email ki pushti karein.",
"emailVerificationError": "Satyaapan email bhejne mein truti. Kripya punah prayaas karein.",
"emailVerificationSent": "Satyaapan email bhej diya gaya hai. Kripya apne inbox ki jaanch karein.",
"sendVerificationEmail": "Satyaapan Email Bhejein",
"emailVerificationSpamCheck": "Agar aapko email nahi dikh raha, kripya apne spam folder ki jaanch karein.",
"sendVerificationEmail": "Satyaapan email bhejein",
"resendVerificationEmail": "Satyaapan email punah bhejein",
"passwordRequired": "Punah praman ke liye password aavashyak hai.",
"reauthenticationError": "Punah praman mein asafalta. Kripya punah prayaas karein."
},
"verifyMFA": {
"title": "Do-Charan Praman Verify Karein",
"triggerSMS": "SMS Code Bhejein",
"verifyCode": "Code Verify Karein",
"title": "Do-charan praman verify karein",
"triggerSMS": "SMS code bhejein",
"verifyCode": "Code verify karein",
"phoneNumber": "Hum aapke registered phone number par ek verification code bhejenge: {phoneNumber}"
},
"setupMFA": {
"title": "Do-Charan Praman Setup Karein",
"pageTitle": "Apne Khaate ko Surakshit Karein",
"sendCode": "Verification Code Bhejein",
"verifyCode": "Code Verify Karein",
"title": "Do-charan praman setup karein",
"sendCode": "Verification code bhejein",
"verifyCode": "Code verify karein",
"enterCodeHelperText": "Kripya apne phone par bheje gaye verification code ko darj karein:",
"reauthTitle": "Apni Pehchaan Confirm Karein",
"reauthDescription": "Kripya aage badhne se pehle apna password darj karein",
"cancelReauth": "Cancel Karein",
"confirmReauth": "Confirm Karein",
"reauthenticating": "Confirm kar rahe hain..."
},
"verifyEmail": {
"pageTitle": "Apna Email Verify Karein",
"instructions": "Kripya apne email ki jaanch karein aur jaari rakhne ke liye satyaapan link par click karein.",
"sendButton": "Satyaapan Email Punah Bhejein"
}
}
}
Loading
Loading