verify email workflow working

This commit is contained in:
Milo Schwartz
2024-10-04 23:14:40 -04:00
parent e176295593
commit 76eeb335a3
23 changed files with 16363 additions and 15802 deletions

View File

@@ -11,6 +11,9 @@ export const errorHandlerMiddleware: ErrorRequestHandler = (
next: NextFunction,
) => {
const statusCode = error.statusCode || HttpCode.INTERNAL_SERVER_ERROR;
if (environment.ENVIRONMENT !== "prod") {
logger.error(error);
}
res?.status(statusCode).send({
data: null,
success: false,

View File

@@ -2,3 +2,4 @@ export * from "./notFound";
export * from "./rateLimit";
export * from "./formatError";
export * from "./verifySession";
export * from "./verifyUser";

View File

@@ -3,19 +3,47 @@ import createHttpError from "http-errors";
import { NextFunction, Request, Response } from "express";
import logger from "@server/logger";
import HttpCode from "@server/types/HttpCode";
import environment from "@server/environment";
const limit = environment.RATE_LIMIT_MAX;
const minutes = environment.RATE_LIMIT_WINDOW_MIN;
export const rateLimitMiddleware = rateLimit({
windowMs: minutes * 60 * 1000,
limit,
handler: (req: Request, res: Response, next: NextFunction) => {
const message = `Rate limit exceeded. You can make ${limit} requests every ${minutes} minute(s).`;
logger.warn(`Rate limit exceeded for IP ${req.ip}`);
return next(createHttpError(HttpCode.TOO_MANY_REQUESTS, message));
},
});
export function rateLimitMiddleware({
windowMin,
max,
type,
skipCondition,
}: {
windowMin: number;
max: number;
type: "IP_ONLY" | "IP_AND_PATH";
skipCondition?: (req: Request, res: Response) => boolean;
}) {
if (type === "IP_AND_PATH") {
return rateLimit({
windowMs: windowMin * 60 * 1000,
max,
skip: skipCondition,
keyGenerator: (req: Request) => {
return `${req.ip}-${req.path}`;
},
handler: (req: Request, res: Response, next: NextFunction) => {
const message = `Rate limit exceeded. You can make ${max} requests every ${windowMin} minute(s).`;
logger.warn(
`Rate limit exceeded for IP ${req.ip} on path ${req.path}`,
);
return next(
createHttpError(HttpCode.TOO_MANY_REQUESTS, message),
);
},
});
}
return rateLimit({
windowMs: windowMin * 60 * 1000,
max,
skip: skipCondition,
handler: (req: Request, res: Response, next: NextFunction) => {
const message = `Rate limit exceeded. You can make ${max} requests every ${windowMin} minute(s).`;
logger.warn(`Rate limit exceeded for IP ${req.ip}`);
return next(createHttpError(HttpCode.TOO_MANY_REQUESTS, message));
},
});
}
export default rateLimitMiddleware;

View File

@@ -30,4 +30,6 @@ export const verifySessionMiddleware = async (
req.user = existingUser[0];
req.session = session;
next();
};

View File

@@ -0,0 +1,41 @@
import { NextFunction, Response } from "express";
import ErrorResponse from "@server/types/ErrorResponse";
import { unauthorized, verifySession } from "@server/auth";
import { db } from "@server/db";
import { users } from "@server/db/schema";
import { eq } from "drizzle-orm";
import createHttpError from "http-errors";
import HttpCode from "@server/types/HttpCode";
export const verifySessionUserMiddleware = async (
req: any,
res: Response<ErrorResponse>,
next: NextFunction,
) => {
const { session, user } = await verifySession(req);
if (!session || !user) {
return next(unauthorized());
}
const existingUser = await db
.select()
.from(users)
.where(eq(users.id, user.id));
if (!existingUser || !existingUser[0]) {
return next(
createHttpError(HttpCode.BAD_REQUEST, "User does not exist"),
);
}
req.user = existingUser[0];
req.session = session;
if (!existingUser[0].emailVerified) {
return next(
createHttpError(HttpCode.BAD_REQUEST, "Email is not verified"), // Might need to change the response type?
);
}
next();
};