add strict rate limit to endpoints that send email

This commit is contained in:
Milo Schwartz 2025-02-05 22:46:33 -05:00
parent 58a084426b
commit 3c7025a327
No known key found for this signature in database
2 changed files with 46 additions and 5 deletions

View file

@ -8,10 +8,8 @@ import { db } from "@server/db";
import { passwordResetTokens, users } from "@server/db/schema";
import { eq } from "drizzle-orm";
import { alphabet, generateRandomString, sha256 } from "oslo/crypto";
import { encodeHex } from "oslo/encoding";
import { createDate } from "oslo";
import logger from "@server/logger";
import { generateIdFromEntropySize } from "@server/auth/sessions/app";
import { TimeSpan } from "oslo";
import config from "@server/lib/config";
import { sendEmail } from "@server/emails";
@ -85,7 +83,9 @@ export async function requestPasswordReset(
const url = `${config.getRawConfig().app.dashboard_url}/auth/reset-password?email=${email}&token=${token}`;
if (!config.getRawConfig().email) {
logger.info(`Password reset requested for ${email}. Token: ${token}.`);
logger.info(
`Password reset requested for ${email}. Token: ${token}.`
);
}
await sendEmail(

View file

@ -27,6 +27,8 @@ import { verifyUserHasAction } from "../middlewares/verifyUserHasAction";
import { ActionsEnum } from "@server/auth/actions";
import { verifyUserIsOrgOwner } from "../middlewares/verifyUserIsOrgOwner";
import { createNewt, getToken } from "./newt";
import rateLimit from "express-rate-limit";
import createHttpError from "http-errors";
// Root routes
export const unauthenticated = Router();
@ -452,22 +454,61 @@ authRouter.post(
);
authRouter.post("/2fa/disable", verifySessionUserMiddleware, auth.disable2fa);
authRouter.post("/verify-email", verifySessionMiddleware, auth.verifyEmail);
authRouter.post(
"/verify-email/request",
verifySessionMiddleware,
rateLimit({
windowMs: 15 * 60 * 1000,
max: 3,
keyGenerator: (req) => `requestEmailVerificationCode:${req.body.email}`,
handler: (req, res, next) => {
const message = `You can only request an email verification code ${3} times every ${15} minutes. Please try again later.`;
return next(createHttpError(HttpCode.TOO_MANY_REQUESTS, message));
}
}),
auth.requestEmailVerificationCode
);
// authRouter.post(
// "/change-password",
// verifySessionUserMiddleware,
// auth.changePassword
// );
authRouter.post("/reset-password/request", auth.requestPasswordReset);
authRouter.post(
"/reset-password/request",
rateLimit({
windowMs: 15 * 60 * 1000,
max: 3,
keyGenerator: (req) => `requestPasswordReset:${req.body.email}`,
handler: (req, res, next) => {
const message = `You can only request a password reset ${3} times every ${15} minutes. Please try again later.`;
return next(createHttpError(HttpCode.TOO_MANY_REQUESTS, message));
}
}),
auth.requestPasswordReset
);
authRouter.post("/reset-password/", auth.resetPassword);
authRouter.post("/resource/:resourceId/password", resource.authWithPassword);
authRouter.post("/resource/:resourceId/pincode", resource.authWithPincode);
authRouter.post("/resource/:resourceId/whitelist", resource.authWithWhitelist);
authRouter.post(
"/resource/:resourceId/whitelist",
rateLimit({
windowMs: 15 * 60 * 1000,
max: 10,
keyGenerator: (req) => `authWithWhitelist:${req.body.email}`,
handler: (req, res, next) => {
const message = `You can only request an email OTP ${10} times every ${15} minutes. Please try again later.`;
return next(createHttpError(HttpCode.TOO_MANY_REQUESTS, message));
}
}),
resource.authWithWhitelist
);
authRouter.post(
"/resource/:resourceId/access-token",
resource.authWithAccessToken