new endpoint to update emailVerified from email-handler

This commit is contained in:
Christian Fehmer 2025-07-14 13:00:26 +02:00
parent e04a7e66cf
commit 995af2b1fa
No known key found for this signature in database
GPG key ID: FE53784A69964062
5 changed files with 46 additions and 2 deletions

View file

@ -158,6 +158,7 @@ export async function sendVerificationEmail(
);
})
).emailVerified;
if (isVerified) {
throw new MonkeyError(400, "Email already verified");
}
@ -240,6 +241,13 @@ export async function sendVerificationEmail(
return new MonkeyResponse("Email sent", null);
}
export async function verifyEmail(req: MonkeyRequest): Promise<MonkeyResponse> {
const { uid, email, emailVerified } = req.ctx.decodedToken;
await UserDAL.updateEmail(uid, email, emailVerified);
return new MonkeyResponse("emailVerify updated.", null);
}
export async function sendForgotPasswordEmail(
req: MonkeyRequest<undefined, ForgotPasswordEmailRequest>
): Promise<MonkeyResponse> {
@ -605,7 +613,7 @@ export async function getUser(req: MonkeyRequest): Promise<GetUserResponse> {
);
delete relevantUserInfo.customThemes;
//update users emailVerified status if it changed
// soft-migrate user.emailVerified for existing users, update status if it has changed
const { email, emailVerified } = req.ctx.decodedToken;
if (emailVerified !== undefined && emailVerified !== userInfo.emailVerified) {
void addImportantLog(

View file

@ -120,6 +120,9 @@ export default s.router(usersContract, {
handler: async (r) =>
callController(UserController.sendVerificationEmail)(r),
},
verifyEmail: {
handler: async (r) => callController(UserController.verifyEmail)(r),
},
forgotPasswordEmail: {
handler: async (r) =>
callController(UserController.sendForgotPasswordEmail)(r),

View file

@ -176,6 +176,8 @@
signInWithEmailAndPassword,
} from "firebase/auth";
import { envConfig } from "./ts/constants/env-config";
function isPasswordStrong(password) {
const hasCapital = !!password.match(/[A-Z]/);
const hasNumber = !!password.match(/[\d]/);
@ -189,8 +191,21 @@
function handleVerifyEmail(actionCode, continueUrl) {
applyActionCode(Auth, actionCode)
.then((resp) => {
.then(async (resp) => {
// Email address has been verified.
const token =
Auth.currentUser !== undefined
? await Auth.currentUser.getIdToken(true)
: undefined;
const url = envConfig.backendUrl + "/users/verifyEmail";
await fetch(url, {
method: "GET",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${token}`,
},
});
$("main .preloader .icon").html(`<i class="fas fa-fw fa-check"></i>`);
$("main .preloader .text").text(

View file

@ -301,6 +301,11 @@ export const limits = {
max: 1,
},
userVerifyEmail: {
window: 15 * 60 * 1000, //15 minutes
max: 1,
},
userForgotPasswordEmail: {
window: "minute",
max: 1,

View file

@ -872,6 +872,19 @@ export const usersContract = c.router(
rateLimit: "userRequestVerificationEmail",
}),
},
verifyEmail: {
summary: "verify email",
description: "Verify the user email",
method: "GET",
path: "/verifyEmail",
responses: {
200: MonkeyResponseSchema,
},
metadata: meta({
authenticationOptions: { noCache: true },
rateLimit: "userVerifyEmail",
}),
},
forgotPasswordEmail: {
summary: "send forgot password email",
description: "Send a forgot password email",