summary refs log tree commit diff
diff options
context:
space:
mode:
authorPuyodead1 <puyodead@proton.me>2023-01-31 09:15:18 -0500
committerPuyodead1 <puyodead@protonmail.com>2023-02-23 22:49:55 -0500
commit1aba7d591cf6641c77571c8ce46e036021502152 (patch)
tree638e6545cd26ab461bbca60fa1f290c3a223a882
parentfix: verification required for login not working correctly (diff)
downloadserver-1aba7d591cf6641c77571c8ce46e036021502152.tar.xz
fix: email verification
-rw-r--r--src/api/routes/auth/verify/index.ts28
-rw-r--r--src/api/routes/auth/verify/resend.ts2
-rw-r--r--src/util/util/Token.ts27
3 files changed, 42 insertions, 15 deletions
diff --git a/src/api/routes/auth/verify/index.ts b/src/api/routes/auth/verify/index.ts
index 14cc3f95..91ff9b93 100644
--- a/src/api/routes/auth/verify/index.ts
+++ b/src/api/routes/auth/verify/index.ts
@@ -17,11 +17,21 @@
 */
 
 import { route, verifyCaptcha } from "@fosscord/api";
-import { checkToken, Config, FieldErrors, User } from "@fosscord/util";
+import { checkToken, Config, generateToken, User } from "@fosscord/util";
 import { Request, Response, Router } from "express";
 import { HTTPError } from "lambert-server";
 const router = Router();
 
+async function getToken(user: User) {
+	const token = await generateToken(user.id);
+
+	// Notice this will have a different token structure, than discord
+	// Discord header is just the user id as string, which is not possible with npm-jsonwebtoken package
+	// https://user-images.githubusercontent.com/6506416/81051916-dd8c9900-8ec2-11ea-8794-daf12d6f31f0.png
+
+	return { token };
+}
+
 router.post(
 	"/",
 	route({ body: "VerifyEmailSchema" }),
@@ -43,23 +53,13 @@ router.post(
 		try {
 			const { jwtSecret } = Config.get().security;
 
-			const { decoded, user } = await checkToken(token, jwtSecret);
-
-			// toksn should last for 24 hours from the time they were issued
-			if (new Date().getTime() > decoded.iat * 1000 + 86400 * 1000) {
-				throw FieldErrors({
-					token: {
-						code: "TOKEN_INVALID",
-						message: "Invalid token", // TODO: add translation
-					},
-				});
-			}
+			const { user } = await checkToken(token, jwtSecret, true);
 
-			if (user.verified) return res.send(user);
+			if (user.verified) return res.json(await getToken(user));
 
 			await User.update({ id: user.id }, { verified: true });
 
-			return res.send(user);
+			return res.json(await getToken(user));
 		} catch (error) {
 			throw new HTTPError((error as Error).toString(), 400);
 		}
diff --git a/src/api/routes/auth/verify/resend.ts b/src/api/routes/auth/verify/resend.ts
index d9a9cda5..a798a3d9 100644
--- a/src/api/routes/auth/verify/resend.ts
+++ b/src/api/routes/auth/verify/resend.ts
@@ -25,7 +25,7 @@ const router = Router();
 router.post("/", route({}), async (req: Request, res: Response) => {
 	const user = await User.findOneOrFail({
 		where: { id: req.user_id },
-		select: ["email"],
+		select: ["username", "email"],
 	});
 
 	if (!user.email) {
diff --git a/src/util/util/Token.ts b/src/util/util/Token.ts
index 12e4a79a..e7b2006d 100644
--- a/src/util/util/Token.ts
+++ b/src/util/util/Token.ts
@@ -27,9 +27,34 @@ export type UserTokenData = {
 	decoded: { id: string; iat: number };
 };
 
+async function checkEmailToken(
+	decoded: jwt.JwtPayload,
+): Promise<UserTokenData> {
+	// eslint-disable-next-line no-async-promise-executor
+	return new Promise(async (res, rej) => {
+		if (!decoded.iat) return rej("Invalid Token"); // will never happen, just for typings.
+
+		const user = await User.findOne({
+			where: {
+				email: decoded.email,
+			},
+		});
+
+		if (!user) return rej("Invalid Token");
+
+		if (new Date().getTime() > decoded.iat * 1000 + 86400 * 1000)
+			return rej("Invalid Token");
+
+		// Using as here because we assert `id` and `iat` are in decoded.
+		// TS just doesn't want to assume its there, though.
+		return res({ decoded, user } as UserTokenData);
+	});
+}
+
 export function checkToken(
 	token: string,
 	jwtSecret: string,
+	isEmailVerification = false,
 ): Promise<UserTokenData> {
 	return new Promise((res, rej) => {
 		token = token.replace("Bot ", "");
@@ -48,6 +73,8 @@ export function checkToken(
 			)
 				return rej("Invalid Token"); // will never happen, just for typings.
 
+			if (isEmailVerification) return res(checkEmailToken(decoded));
+
 			const user = await User.findOne({
 				where: { id: decoded.id },
 				select: ["data", "bot", "disabled", "deleted", "rights"],