summary refs log tree commit diff
path: root/src/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/util')
-rw-r--r--src/util/schemas/RegisterSchema.ts4
-rw-r--r--src/util/util/Token.ts130
2 files changed, 55 insertions, 79 deletions
diff --git a/src/util/schemas/RegisterSchema.ts b/src/util/schemas/RegisterSchema.ts
index f6c99b18..7b7de9c7 100644
--- a/src/util/schemas/RegisterSchema.ts
+++ b/src/util/schemas/RegisterSchema.ts
@@ -42,4 +42,8 @@ export interface RegisterSchema {
 	captcha_key?: string;
 
 	promotional_email_opt_in?: boolean;
+
+	// part of pomelo
+	unique_username_registration?: boolean;
+	global_name?: string;
 }
diff --git a/src/util/util/Token.ts b/src/util/util/Token.ts
index 90310176..eec72522 100644
--- a/src/util/util/Token.ts
+++ b/src/util/util/Token.ts
@@ -19,94 +19,66 @@
 import jwt, { VerifyOptions } from "jsonwebtoken";
 import { Config } from "./Config";
 import { User } from "../entities";
+// TODO: dont use deprecated APIs lol
+import {
+	FindOptionsRelationByString,
+	FindOptionsSelectByString,
+} from "typeorm";
 
 export const JWTOptions: VerifyOptions = { algorithms: ["HS256"] };
 
 export type UserTokenData = {
 	user: User;
-	decoded: { id: string; iat: number };
+	decoded: { id: string; iat: number; email?: string };
 };
 
-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,
-			},
-			select: [
-				"email",
-				"id",
-				"verified",
-				"deleted",
-				"disabled",
-				"username",
-				"data",
-			],
-		});
-
-		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(
+export const checkToken = (
 	token: string,
-	jwtSecret: string,
-	isEmailVerification = false,
-): Promise<UserTokenData> {
-	return new Promise((res, rej) => {
-		token = token.replace("Bot ", "");
-		token = token.replace("Bearer ", "");
-		/**
-		in spacebar, even with instances that have bot distinction; we won't enforce "Bot" prefix,
-		as we don't really have separate pathways for bots 
-		**/
-
-		jwt.verify(token, jwtSecret, JWTOptions, async (err, decoded) => {
-			if (err || !decoded) return rej("Invalid Token");
-			if (
-				typeof decoded == "string" ||
-				!("id" in decoded) ||
-				!decoded.iat
-			)
-				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"],
-			});
-
-			if (!user) return rej("Invalid Token");
-
-			// we need to round it to seconds as it saved as seconds in jwt iat and valid_tokens_since is stored in milliseconds
-			if (
-				decoded.iat * 1000 <
-				new Date(user.data.valid_tokens_since).setSeconds(0, 0)
-			)
-				return rej("Invalid Token");
-
-			if (user.disabled) return rej("User disabled");
-			if (user.deleted) return rej("User not found");
-
-			// 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);
-		});
+	opts?: {
+		select?: FindOptionsSelectByString<User>;
+		relations?: FindOptionsRelationByString;
+	},
+): Promise<UserTokenData> =>
+	new Promise((resolve, reject) => {
+		jwt.verify(
+			token,
+			Config.get().security.jwtSecret,
+			JWTOptions,
+			async (err, out) => {
+				const decoded = out as UserTokenData["decoded"];
+				if (err || !decoded) return reject("Invalid Token");
+
+				const user = await User.findOne({
+					where: decoded.email
+						? { email: decoded.email }
+						: { id: decoded.id },
+					select: [
+						...(opts?.select || []),
+						"bot",
+						"disabled",
+						"deleted",
+						"rights",
+						"data",
+					],
+					relations: opts?.relations,
+				});
+
+				if (!user) return reject("User not found");
+
+				// we need to round it to seconds as it saved as seconds in jwt iat and valid_tokens_since is stored in milliseconds
+				if (
+					decoded.iat * 1000 <
+					new Date(user.data.valid_tokens_since).setSeconds(0, 0)
+				)
+					return reject("Invalid Token");
+
+				if (user.disabled) return reject("User disabled");
+				if (user.deleted) return reject("User not found");
+
+				return resolve({ decoded, user });
+			},
+		);
 	});
-}
 
 export async function generateToken(id: string, email?: string) {
 	const iat = Math.floor(Date.now() / 1000);