From 4d53291c8a0d9296774dadab4e17ffb0bfcd73b5 Mon Sep 17 00:00:00 2001 From: Dhruwang Jariwala <67850763+Dhruwang@users.noreply.github.com> Date: Wed, 13 Aug 2025 12:12:08 +0530 Subject: [PATCH] fix: checks and rate limiting for email verification survey action (#6406) --- .../modules/core/rate-limit/rate-limit-configs.test.ts | 2 +- apps/web/modules/core/rate-limit/rate-limit-configs.ts | 5 +++++ apps/web/modules/survey/link/actions.ts | 10 ++++++++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/apps/web/modules/core/rate-limit/rate-limit-configs.test.ts b/apps/web/modules/core/rate-limit/rate-limit-configs.test.ts index 7df4ff274d..eef3e49033 100644 --- a/apps/web/modules/core/rate-limit/rate-limit-configs.test.ts +++ b/apps/web/modules/core/rate-limit/rate-limit-configs.test.ts @@ -71,7 +71,7 @@ describe("rateLimitConfigs", () => { test("should have all action configurations", () => { const actionConfigs = Object.keys(rateLimitConfigs.actions); - expect(actionConfigs).toEqual(["emailUpdate", "surveyFollowUp"]); + expect(actionConfigs).toEqual(["emailUpdate", "surveyFollowUp", "sendLinkSurveyEmail"]); }); }); diff --git a/apps/web/modules/core/rate-limit/rate-limit-configs.ts b/apps/web/modules/core/rate-limit/rate-limit-configs.ts index c3df9b561a..6792d059c6 100644 --- a/apps/web/modules/core/rate-limit/rate-limit-configs.ts +++ b/apps/web/modules/core/rate-limit/rate-limit-configs.ts @@ -23,5 +23,10 @@ export const rateLimitConfigs = { actions: { emailUpdate: { interval: 3600, allowedPerInterval: 3, namespace: "action:email" }, // 3 per hour surveyFollowUp: { interval: 3600, allowedPerInterval: 50, namespace: "action:followup" }, // 50 per hour + sendLinkSurveyEmail: { + interval: 3600, + allowedPerInterval: 10, + namespace: "action:send-link-survey-email", + }, // 10 per hour }, }; diff --git a/apps/web/modules/survey/link/actions.ts b/apps/web/modules/survey/link/actions.ts index 1fd70134b2..ca321b2e65 100644 --- a/apps/web/modules/survey/link/actions.ts +++ b/apps/web/modules/survey/link/actions.ts @@ -2,6 +2,8 @@ import { actionClient } from "@/lib/utils/action-client"; import { getOrganizationIdFromSurveyId } from "@/lib/utils/helper"; +import { applyIPRateLimit } from "@/modules/core/rate-limit/helpers"; +import { rateLimitConfigs } from "@/modules/core/rate-limit/rate-limit-configs"; import { getOrganizationLogoUrl } from "@/modules/ee/whitelabel/email-customization/lib/organization"; import { sendLinkSurveyToVerifiedEmail } from "@/modules/email"; import { getSurveyWithMetadata, isSurveyResponsePresent } from "@/modules/survey/link/lib/data"; @@ -12,6 +14,14 @@ import { InvalidInputError, ResourceNotFoundError } from "@formbricks/types/erro export const sendLinkSurveyEmailAction = actionClient .schema(ZLinkSurveyEmailData) .action(async ({ parsedInput }) => { + await applyIPRateLimit(rateLimitConfigs.actions.sendLinkSurveyEmail); + + const survey = await getSurveyWithMetadata(parsedInput.surveyId); + + if (!survey.isVerifyEmailEnabled) { + throw new InvalidInputError("EMAIL_VERIFICATION_NOT_ENABLED"); + } + const organizationId = await getOrganizationIdFromSurveyId(parsedInput.surveyId); const organizationLogoUrl = await getOrganizationLogoUrl(organizationId);