diff --git a/actions/login.ts b/actions/login.ts index fd1b1b6..a27ff1f 100644 --- a/actions/login.ts +++ b/actions/login.ts @@ -1,7 +1,7 @@ "use server"; import { signIn } from "@/auth"; -import redis from "@/lib/redis"; +import { redis } from "@/lib/redis"; import prismadb from "@/lib/prisma"; import { AuthError } from "next-auth"; import { headers } from "next/headers"; @@ -16,13 +16,21 @@ import { getTwoFactorConfirmationByUserId } from "@/data/two-factor-confirmation const ratelimit = new Ratelimit({ redis, - limiter: Ratelimit.slidingWindow(5, "60s"), + limiter: Ratelimit.slidingWindow(5, "5 m"), }); export const login = async ( values: LoginValidator, callbackUrl?: string | null ) => { + const ip = headers().get("x-forwarded-for") ?? "127.0.0.1"; + + const { success } = await ratelimit.limit(ip); + + if (!success && process.env.VERCEL_ENV === "production") { + return { error: "Too Many Requests! try again in 5 min" }; + } + const validatedFields = LoginSchema.safeParse(values); if (!validatedFields.success) { @@ -112,21 +120,8 @@ export const login = async ( } try { - if (process.env.VERCEL_ENV === "production") { - const forwardedIps = headers() - .get("x-forwarded-for") - ?.split(",") - .map((ip) => ip.trim()); - - const ip = - forwardedIps && forwardedIps?.length > 0 ? forwardedIps[0] : ""; - - const { success } = await ratelimit.limit(ip); - - if (!success) { - return { error: "Too Many Requests! try again in 1 min" }; - } - } + // if (process.env.VERCEL_ENV === "production") { + // } await signIn("credentials", { email, diff --git a/actions/register.ts b/actions/register.ts index 0908469..c5e540a 100644 --- a/actions/register.ts +++ b/actions/register.ts @@ -1,13 +1,29 @@ "use server"; import bcrypt from "bcryptjs"; +import { redis } from "@/lib/redis"; import prismadb from "@/lib/prisma"; +import { headers } from "next/headers"; import { getUserByEmail } from "@/data/user"; +import { Ratelimit } from "@upstash/ratelimit"; import { sendVerificationEmail } from "@/lib/mail"; import { generateVerificationToken } from "@/lib/token"; import { RegisterValidator, RegisterSchema } from "@/lib/validators/register"; +const ratelimit = new Ratelimit({ + redis, + limiter: Ratelimit.slidingWindow(5, "5 m"), +}); + export const register = async (values: RegisterValidator) => { + const ip = headers().get("x-forwarded-for") ?? "127.0.0.1"; + + const { success } = await ratelimit.limit(ip); + + if (!success && process.env.VERCEL_ENV === "production") { + return { error: "Too Many Requests! try again in 5 min" }; + } + const validatedFields = RegisterSchema.safeParse(values); if (!validatedFields.success) { diff --git a/app/api/stores/[storeId]/products/[productId]/route.ts b/app/api/stores/[storeId]/products/[productId]/route.ts index bfa8b83..a2d536d 100644 --- a/app/api/stores/[storeId]/products/[productId]/route.ts +++ b/app/api/stores/[storeId]/products/[productId]/route.ts @@ -1,15 +1,37 @@ import prismadb from "@/lib/prisma"; +import { redis } from "@/lib/redis"; import { NextResponse } from "next/server"; import { getCurrentPrice } from "@/lib/utils"; +import { Ratelimit } from "@upstash/ratelimit"; import { UserRole, storeStatus } from "@prisma/client"; import { currentRole, currentUser } from "@/lib/auth"; import { ProductSchema } from "@/lib/validators/product"; +const ratelimit = new Ratelimit({ + redis, + limiter: Ratelimit.slidingWindow(5, "60 s"), +}); + export async function PATCH( request: Request, { params }: { params: { storeId: string; productId: string } } ) { try { + //Check if there is a current user + const { user } = await currentUser(); + + if (!user) { + return new NextResponse("Unauthorized", { status: 401 }); + } + + const { success } = await ratelimit.limit(user.id); + + if (!success && process.env.VERCEL_ENV === "production") { + return new NextResponse("Too Many Requests! try again in 1 min", { + status: 429, + }); + } + const { storeId, productId } = params; if (!storeId) { @@ -20,13 +42,6 @@ export async function PATCH( return new NextResponse("Product Id is required", { status: 400 }); } - //Check if there is a current user - const { user } = await currentUser(); - - if (!user) { - return new NextResponse("Unauthorized", { status: 401 }); - } - //Check if user is a seller const { role } = await currentRole(); diff --git a/app/api/stores/[storeId]/products/new/route.ts b/app/api/stores/[storeId]/products/new/route.ts index b797e3c..18e8db8 100644 --- a/app/api/stores/[storeId]/products/new/route.ts +++ b/app/api/stores/[storeId]/products/new/route.ts @@ -1,10 +1,17 @@ import prismadb from "@/lib/prisma"; +import { redis } from "@/lib/redis"; import { NextResponse } from "next/server"; -import { UserRole, storeStatus } from "@prisma/client"; import { getCurrentPrice } from "@/lib/utils"; +import { Ratelimit } from "@upstash/ratelimit"; +import { UserRole, storeStatus } from "@prisma/client"; import { currentRole, currentUser } from "@/lib/auth"; import { ProductSchema } from "@/lib/validators/product"; +const ratelimit = new Ratelimit({ + redis, + limiter: Ratelimit.slidingWindow(5, "60 s"), +}); + export async function POST( request: Request, { params }: { params: { storeId: string } } @@ -23,6 +30,14 @@ export async function POST( return new NextResponse("Unauthorized", { status: 401 }); } + const { success } = await ratelimit.limit(user.id); + + if (!success && process.env.VERCEL_ENV === "production") { + return new NextResponse("Too Many Requests! try again in 1 min", { + status: 429, + }); + } + //Check if user is a seller const { role } = await currentRole(); diff --git a/lib/redis.ts b/lib/redis.ts index cfe50ad..6c477ff 100644 --- a/lib/redis.ts +++ b/lib/redis.ts @@ -1,8 +1,7 @@ import { Redis } from "@upstash/redis"; +import { Ratelimit } from "@upstash/ratelimit"; -const redis = new Redis({ +export const redis = new Redis({ url: process.env.UPSTASH_REDIS_REST_URL as string, token: process.env.UPSTASH_REDIS_REST_TOKEN as string, }); - -export default redis;