🛡️ refactor: enhance email verification process (#5485)

This commit is contained in:
Marco Beretta 2025-01-27 02:57:03 +01:00 committed by GitHub
parent 12a9a07eb0
commit e7de9c1576
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 36 additions and 29 deletions

View file

@ -108,31 +108,46 @@ const sendVerificationEmail = async (user) => {
*/ */
const verifyEmail = async (req) => { const verifyEmail = async (req) => {
const { email, token } = req.body; const { email, token } = req.body;
let emailVerificationData = await findToken({ email: decodeURIComponent(email) }); const decodedEmail = decodeURIComponent(email);
const user = await findUser({ email: decodedEmail }, 'email _id emailVerified');
if (!user) {
logger.warn(`[verifyEmail] [User not found] [Email: ${decodedEmail}]`);
return new Error('User not found');
}
if (user.emailVerified) {
logger.info(`[verifyEmail] Email already verified [Email: ${decodedEmail}]`);
return { message: 'Email already verified', status: 'success' };
}
let emailVerificationData = await findToken({ email: decodedEmail });
if (!emailVerificationData) { if (!emailVerificationData) {
logger.warn(`[verifyEmail] [No email verification data found] [Email: ${email}]`); logger.warn(`[verifyEmail] [No email verification data found] [Email: ${decodedEmail}]`);
return new Error('Invalid or expired password reset token'); return new Error('Invalid or expired password reset token');
} }
const isValid = bcrypt.compareSync(token, emailVerificationData.token); const isValid = bcrypt.compareSync(token, emailVerificationData.token);
if (!isValid) { if (!isValid) {
logger.warn(`[verifyEmail] [Invalid or expired email verification token] [Email: ${email}]`); logger.warn(
`[verifyEmail] [Invalid or expired email verification token] [Email: ${decodedEmail}]`,
);
return new Error('Invalid or expired email verification token'); return new Error('Invalid or expired email verification token');
} }
const updatedUser = await updateUser(emailVerificationData.userId, { emailVerified: true }); const updatedUser = await updateUser(emailVerificationData.userId, { emailVerified: true });
if (!updatedUser) { if (!updatedUser) {
logger.warn(`[verifyEmail] [User not found] [Email: ${email}]`); logger.warn(`[verifyEmail] [User update failed] [Email: ${decodedEmail}]`);
return new Error('User not found'); return new Error('Failed to update user verification status');
} }
await deleteTokens({ token: emailVerificationData.token }); await deleteTokens({ token: emailVerificationData.token });
logger.info(`[verifyEmail] Email verification successful. [Email: ${email}]`); logger.info(`[verifyEmail] Email verification successful [Email: ${decodedEmail}]`);
return { message: 'Email verification was successful' }; return { message: 'Email verification was successful', status: 'success' };
}; };
/** /**
* Register a new user. * Register a new user.
* @param {MongoUser} user <email, password, name, username> * @param {MongoUser} user <email, password, name, username>

View file

@ -14,7 +14,6 @@ function RequestPasswordReset() {
const [headerText, setHeaderText] = useState<string>(''); const [headerText, setHeaderText] = useState<string>('');
const [showResendLink, setShowResendLink] = useState<boolean>(false); const [showResendLink, setShowResendLink] = useState<boolean>(false);
const [verificationStatus, setVerificationStatus] = useState<boolean>(false); const [verificationStatus, setVerificationStatus] = useState<boolean>(false);
const token = useMemo(() => params.get('token') || '', [params]); const token = useMemo(() => params.get('token') || '', [params]);
const email = useMemo(() => params.get('email') || '', [params]); const email = useMemo(() => params.get('email') || '', [params]);
@ -26,9 +25,8 @@ function RequestPasswordReset() {
clearInterval(timer); clearInterval(timer);
navigate('/c/new', { replace: true }); navigate('/c/new', { replace: true });
return 0; return 0;
} else {
return prevCountdown - 1;
} }
return prevCountdown - 1;
}); });
}, 1000); }, 1000);
}, [navigate]); }, [navigate]);
@ -39,11 +37,10 @@ function RequestPasswordReset() {
setVerificationStatus(true); setVerificationStatus(true);
countdownRedirect(); countdownRedirect();
}, },
onError: () => { onError: (error: unknown) => {
setHeaderText(localize('com_auth_email_verification_failed') + ' 😢');
setShowResendLink(true); setShowResendLink(true);
setVerificationStatus(true); setVerificationStatus(true);
setHeaderText(localize('com_auth_email_verification_failed') + ' 😢');
setCountdown(0);
}, },
}); });
@ -54,7 +51,6 @@ function RequestPasswordReset() {
}, },
onError: () => { onError: () => {
setHeaderText(localize('com_auth_email_resent_failed') + ' 😢'); setHeaderText(localize('com_auth_email_resent_failed') + ' 😢');
countdownRedirect();
}, },
onMutate: () => setShowResendLink(false), onMutate: () => setShowResendLink(false),
}); });
@ -64,26 +60,22 @@ function RequestPasswordReset() {
}; };
useEffect(() => { useEffect(() => {
if (verifyEmailMutation.isLoading || verificationStatus) { if (verificationStatus || verifyEmailMutation.isLoading) {
return; return;
} }
if (token && email) { if (token && email) {
verifyEmailMutation.mutate({ verifyEmailMutation.mutate({ email, token });
email,
token,
});
return;
} else if (email) {
setHeaderText(localize('com_auth_email_verification_failed_token_missing') + ' 😢');
} else { } else {
setHeaderText(localize('com_auth_email_verification_invalid') + ' 🤨'); if (email) {
setHeaderText(localize('com_auth_email_verification_failed_token_missing') + ' 😢');
} else {
setHeaderText(localize('com_auth_email_verification_invalid') + ' 🤨');
}
setShowResendLink(true);
setVerificationStatus(true);
} }
}, [token, email, verificationStatus, verifyEmailMutation]);
setShowResendLink(true);
setVerificationStatus(true);
setCountdown(0);
}, [localize, token, email, verificationStatus, verifyEmailMutation]);
const VerificationSuccess = () => ( const VerificationSuccess = () => (
<div className="flex flex-col items-center justify-center"> <div className="flex flex-col items-center justify-center">