Skip to content

Commit e9b8ae6

Browse files
committed
make verifyEmail public, use firebase admin
1 parent 31a20ba commit e9b8ae6

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";
@@ -245,9 +246,30 @@ export async function sendVerificationEmail(
245246
return new MonkeyResponse("Email sent", null);
246247
}
247248

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

252274
return new MonkeyResponse("emailVerify updated.", null);
253275
}
@@ -618,13 +640,13 @@ export async function getUser(req: MonkeyRequest): Promise<GetUserResponse> {
618640
// soft-migrate user.emailVerified for existing users, update status if it has changed
619641
const { email, emailVerified } = req.ctx.decodedToken;
620642
if (emailVerified !== undefined && emailVerified !== userInfo.emailVerified) {
643+
await UserDAL.updateEmail(uid, email, emailVerified);
644+
userInfo.emailVerified = emailVerified;
621645
void addImportantLog(
622646
"user_verify_email",
623-
`emailVerified changed to ${emailVerified} for email ${email}`,
647+
`soft-migrate emailVerified changed to ${emailVerified} for email ${email}`,
624648
uid
625649
);
626-
await UserDAL.updateEmail(uid, email, emailVerified);
627-
userInfo.emailVerified = emailVerified;
628650
}
629651

630652
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
@@ -304,6 +304,11 @@ export const ReportUserRequestSchema = z.object({
304304
});
305305
export type ReportUserRequest = z.infer<typeof ReportUserRequestSchema>;
306306

307+
export const VerifyEmailRequestSchema = z.object({
308+
email: UserEmailSchema,
309+
});
310+
export type VerifyEmailRequest = z.infer<typeof VerifyEmailRequestSchema>;
311+
307312
export const ForgotPasswordEmailRequestSchema = z.object({
308313
captcha: z.string(),
309314
email: UserEmailSchema,
@@ -871,13 +876,14 @@ export const usersContract = c.router(
871876
verifyEmail: {
872877
summary: "verify email",
873878
description: "Verify the user email",
874-
method: "GET",
879+
method: "POST",
875880
path: "/verifyEmail",
881+
body: VerifyEmailRequestSchema.strict(),
876882
responses: {
877883
200: MonkeyResponseSchema,
878884
},
879885
metadata: meta({
880-
authenticationOptions: { noCache: true },
886+
authenticationOptions: { isPublic: true },
881887
rateLimit: "userVerifyEmail",
882888
}),
883889
},

0 commit comments

Comments
 (0)