feat: rate limit per user per env sync user identification endpoint (#2090)

Co-authored-by: review-agent-prime[bot] <147289438+review-agent-prime[bot]@users.noreply.github.com>
This commit is contained in:
Shubham Palriwala
2024-02-19 16:28:30 +05:30
committed by GitHub
parent 6ae782b984
commit 2425dc5459
4 changed files with 27 additions and 0 deletions

View File

@@ -5,6 +5,7 @@ import {
LOGIN_RATE_LIMIT,
SHARE_RATE_LIMIT,
SIGNUP_RATE_LIMIT,
SYNC_USER_IDENTIFICATION_RATE_LIMIT,
} from "@formbricks/lib/constants";
export const signUpLimiter = rateLimit({
@@ -24,3 +25,8 @@ export const shareUrlLimiter = rateLimit({
interval: SHARE_RATE_LIMIT.interval,
allowedPerInterval: SHARE_RATE_LIMIT.allowedPerInterval,
});
export const syncUserIdentificationLimiter = rateLimit({
interval: SYNC_USER_IDENTIFICATION_RATE_LIMIT.interval,
allowedPerInterval: SYNC_USER_IDENTIFICATION_RATE_LIMIT.allowedPerInterval,
});

View File

@@ -16,3 +16,11 @@ export const shareUrlRoute = (url: string): boolean => {
export const isWebAppRoute = (url: string): boolean =>
url.startsWith("/environments") && url !== "/api/auth/signout";
export const isSyncWithUserIdentificationEndpoint = (
url: string
): { environmentId: string; userId: string } | false => {
const regex = /\/api\/v1\/client\/([^/]+)\/in-app\/sync\/([^/]+)/;
const match = url.match(regex);
return match ? { environmentId: match[1], userId: match[2] } : false;
};

View File

@@ -3,9 +3,11 @@ import {
loginLimiter,
shareUrlLimiter,
signUpLimiter,
syncUserIdentificationLimiter,
} from "@/app/middleware/bucket";
import {
clientSideApiRoute,
isSyncWithUserIdentificationEndpoint,
isWebAppRoute,
loginRoute,
shareUrlRoute,
@@ -52,6 +54,12 @@ export async function middleware(request: NextRequest) {
await signUpLimiter.check(ip);
} else if (clientSideApiRoute(request.nextUrl.pathname)) {
await clientSideApiEndpointsLimiter.check(ip);
const envIdAndUserId = isSyncWithUserIdentificationEndpoint(request.nextUrl.pathname);
if (envIdAndUserId) {
const { environmentId, userId } = envIdAndUserId;
await syncUserIdentificationLimiter.check(`${environmentId}-${userId}`);
}
} else if (shareUrlRoute(request.nextUrl.pathname)) {
await shareUrlLimiter.check(ip);
}

View File

@@ -135,6 +135,11 @@ export const SHARE_RATE_LIMIT = {
allowedPerInterval: 30,
};
export const SYNC_USER_IDENTIFICATION_RATE_LIMIT = {
interval: 60 * 1000, // 1 minute
allowedPerInterval: 5,
};
export const DEBUG = process.env.DEBUG === "1";
// Enterprise License constant