fix: use ip address in forgot password rate limitation (#7832)

* feat: use IP address for rate limiting

* fix: use mail as the last choice

* fix: fallback to ip

* fix: endpoint

* fix: endpoint
pull/9282/head
Nafees Nazik 2023-05-31 00:56:29 +05:30 committed by GitHub
parent 6cf8083b02
commit 951709edef
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 25 additions and 9 deletions

View File

@ -6,6 +6,7 @@ import dayjs from "@calcom/dayjs";
import { sendPasswordResetEmail } from "@calcom/emails";
import { PASSWORD_RESET_EXPIRY_HOURS } from "@calcom/emails/templates/forgot-password-email";
import rateLimit from "@calcom/lib/rateLimit";
import { defaultHandler } from "@calcom/lib/server";
import { getTranslation } from "@calcom/lib/server/i18n";
import prisma from "@calcom/prisma";
@ -13,28 +14,39 @@ const limiter = rateLimit({
intervalInMs: 60 * 1000, // 1 minute
});
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
async function handler(req: NextApiRequest, res: NextApiResponse) {
const t = await getTranslation(req.body.language ?? "en", "common");
const email = z
.string()
.email()
.transform((val) => val.toLowerCase())
.parse(req.body?.email);
.safeParse(req.body?.email);
const { isRateLimited } = limiter.check(10, email); // 10 requests per minute
if (isRateLimited) {
return res.status(429).json({ message: "Too Many Requests." });
if (!email.success) {
return res.status(400).json({ message: "email is required" });
}
if (req.method !== "POST") {
return res.status(405).end();
// fallback to email if ip is not present
let ip = (req.headers["x-real-ip"] as string) ?? email.data;
const forwardedFor = req.headers["x-forwarded-for"] as string;
if (!ip && forwardedFor) {
ip = forwardedFor?.split(",").at(0) ?? email.data;
}
// 10 requests per minute
try {
limiter.check(10, ip);
} catch (e) {
return res.status(429).json({ message: "Too Many Requests." });
}
try {
const maybeUser = await prisma.user.findUnique({
where: {
email,
email: email.data,
},
select: {
name: true,
@ -97,3 +109,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
return res.status(500).json({ message: "Unable to create password reset request" });
}
}
export default defaultHandler({
POST: Promise.resolve({ default: handler }),
});