Skip to content

Commit b0a9029

Browse files
committed
make verifyEmail public, use firebase admin
1 parent 995af2b commit b0a9029

File tree

3 files changed

+49
-18
lines changed

3 files changed

+49
-18
lines changed

backend/src/api/controllers/user.ts

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ import {
8585
UpdateUserNameRequest,
8686
UpdateUserProfileRequest,
8787
UpdateUserProfileResponse,
88+
VerifyEmailRequest,
8889
} from "@monkeytype/contracts/users";
8990
import { MILLISECONDS_IN_DAY } from "@monkeytype/util/date-and-time";
9091
import { MonkeyRequest } from "../types";
@@ -241,9 +242,30 @@ export async function sendVerificationEmail(
241242
return new MonkeyResponse("Email sent", null);
242243
}
243244

244-
export async function verifyEmail(req: MonkeyRequest): Promise<MonkeyResponse> {
245-
const { uid, email, emailVerified } = req.ctx.decodedToken;
246-
await UserDAL.updateEmail(uid, email, emailVerified);
245+
export async function verifyEmail(
246+
req: MonkeyRequest<undefined, VerifyEmailRequest>
247+
): Promise<MonkeyResponse> {
248+
const { email } = req.body;
249+
250+
const { data: firebaseUser } = await tryCatch(
251+
FirebaseAdmin().auth().getUserByEmail(email)
252+
);
253+
254+
if (firebaseUser === undefined || firebaseUser === null) {
255+
throw new MonkeyError(404, "not found", "verify email");
256+
}
257+
258+
await UserDAL.updateEmail(
259+
firebaseUser.uid,
260+
email,
261+
firebaseUser.emailVerified
262+
);
263+
264+
void addImportantLog(
265+
"user_verify_email",
266+
`emailVerified changed to ${firebaseUser.emailVerified} for email ${email}`,
267+
firebaseUser.uid
268+
);
247269

248270
return new MonkeyResponse("emailVerify updated.", null);
249271
}
@@ -616,13 +638,13 @@ export async function getUser(req: MonkeyRequest): Promise<GetUserResponse> {
616638
// soft-migrate user.emailVerified for existing users, update status if it has changed
617639
const { email, emailVerified } = req.ctx.decodedToken;
618640
if (emailVerified !== undefined && emailVerified !== userInfo.emailVerified) {
641+
await UserDAL.updateEmail(uid, email, emailVerified);
642+
userInfo.emailVerified = emailVerified;
619643
void addImportantLog(
620644
"user_verify_email",
621-
`emailVerified changed to ${emailVerified} for email ${email}`,
645+
`soft-migrate emailVerified changed to ${emailVerified} for email ${email}`,
622646
uid
623647
);
624-
await UserDAL.updateEmail(uid, email, emailVerified);
625-
userInfo.emailVerified = emailVerified;
626648
}
627649

628650
const userData: User = {

frontend/src/email-handler.html

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -190,20 +190,23 @@
190190
}
191191

192192
function handleVerifyEmail(actionCode, continueUrl) {
193-
applyActionCode(Auth, actionCode)
193+
var email = null;
194+
checkActionCode(Auth, actionCode)
195+
.then((info) => {
196+
// Get the email address
197+
email = info["data"]["email"];
198+
199+
return applyActionCode(Auth, actionCode);
200+
})
201+
194202
.then(async (resp) => {
195203
// Email address has been verified.
196-
const token =
197-
Auth.currentUser !== undefined
198-
? await Auth.currentUser.getIdToken(true)
199-
: undefined;
200-
const url = envConfig.backendUrl + "/users/verifyEmail";
201-
202-
await fetch(url, {
203-
method: "GET",
204+
205+
await fetch(envConfig.backendUrl + "/users/verifyEmail", {
206+
method: "POST",
207+
body: JSON.stringify({ email }),
204208
headers: {
205209
"Content-Type": "application/json",
206-
Authorization: `Bearer ${token}`,
207210
},
208211
});
209212

packages/contracts/src/users.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,11 @@ export const ReportUserRequestSchema = z.object({
308308
});
309309
export type ReportUserRequest = z.infer<typeof ReportUserRequestSchema>;
310310

311+
export const VerifyEmailRequestSchema = z.object({
312+
email: UserEmailSchema,
313+
});
314+
export type VerifyEmailRequest = z.infer<typeof VerifyEmailRequestSchema>;
315+
311316
export const ForgotPasswordEmailRequestSchema = z.object({
312317
captcha: z.string(),
313318
email: UserEmailSchema,
@@ -875,13 +880,14 @@ export const usersContract = c.router(
875880
verifyEmail: {
876881
summary: "verify email",
877882
description: "Verify the user email",
878-
method: "GET",
883+
method: "POST",
879884
path: "/verifyEmail",
885+
body: VerifyEmailRequestSchema.strict(),
880886
responses: {
881887
200: MonkeyResponseSchema,
882888
},
883889
metadata: meta({
884-
authenticationOptions: { noCache: true },
890+
authenticationOptions: { isPublic: true },
885891
rateLimit: "userVerifyEmail",
886892
}),
887893
},

0 commit comments

Comments
 (0)