Skip to content

Commit e239b67

Browse files
chore: Rate limit top level of public booking pages (calcom#25056)
* chore: Rate limit top level of public booking pages * Prefix rateLimit keys * Adding more rate limits --------- Co-authored-by: Keith Williams <keithwillcode@gmail.com>
1 parent fd390f9 commit e239b67

4 files changed

Lines changed: 37 additions & 2 deletions

File tree

apps/web/lib/org/[orgSlug]/[user]/[type]/getServerSideProps.tsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ import type { GetServerSidePropsContext } from "next";
22
import z from "zod";
33

44
import { getSlugOrRequestedSlug } from "@calcom/features/ee/organizations/lib/orgDomains";
5+
import { checkRateLimitAndThrowError } from "@calcom/lib/checkRateLimitAndThrowError";
6+
import getIP from "@calcom/lib/getIP";
7+
import { piiHasher } from "@calcom/lib/server/PiiHasher";
58
import slugify from "@calcom/lib/slugify";
69
import prisma from "@calcom/prisma";
710

@@ -16,6 +19,12 @@ const paramsSchema = z.object({
1619
});
1720

1821
export const getServerSideProps = async (ctx: GetServerSidePropsContext) => {
22+
const requestorIp = getIP(ctx.req as unknown as Request);
23+
await checkRateLimitAndThrowError({
24+
rateLimitingType: "core",
25+
identifier: `[orgSlug]/[user]/[type]-${piiHasher.hash(requestorIp)}`,
26+
});
27+
1928
const { user: teamOrUserSlugOrDynamicGroup, orgSlug, type } = paramsSchema.parse(ctx.params);
2029
const team = await prisma.team.findFirst({
2130
where: {

apps/web/lib/team/[slug]/[type]/getServerSideProps.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ import { getOrganizationSEOSettings } from "@calcom/features/ee/organizations/li
99
import { FeaturesRepository } from "@calcom/features/flags/features.repository";
1010
import { getBrandingForEventType } from "@calcom/features/profile/lib/getBranding";
1111
import { shouldHideBrandingForTeamEvent } from "@calcom/features/profile/lib/hideBranding";
12+
import { checkRateLimitAndThrowError } from "@calcom/lib/checkRateLimitAndThrowError";
1213
import { getPlaceholderAvatar } from "@calcom/lib/defaultAvatarImage";
14+
import getIP from "@calcom/lib/getIP";
15+
import { piiHasher } from "@calcom/lib/server/PiiHasher";
1316
import slugify from "@calcom/lib/slugify";
1417
import { prisma } from "@calcom/prisma";
1518
import type { User } from "@calcom/prisma/client";
@@ -28,6 +31,11 @@ function hasApiV2RouteInEnv() {
2831
}
2932

3033
export const getServerSideProps = async (context: GetServerSidePropsContext) => {
34+
const requestorIp = getIP(context.req as unknown as Request);
35+
await checkRateLimitAndThrowError({
36+
rateLimitingType: "core",
37+
identifier: `team/[slug]/[type]-${piiHasher.hash(requestorIp)}`,
38+
});
3139
const { req, params, query } = context;
3240
const session = await getServerSession({ req });
3341
const { slug: teamSlug, type: meetingSlug } = paramsSchema.parse(params);

apps/web/server/lib/[user]/[type]/getServerSideProps.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ import type { getPublicEvent } from "@calcom/features/eventtypes/lib/getPublicEv
1111
import { EventRepository } from "@calcom/features/eventtypes/repositories/EventRepository";
1212
import { shouldHideBrandingForUserEvent } from "@calcom/features/profile/lib/hideBranding";
1313
import { UserRepository } from "@calcom/features/users/repositories/UserRepository";
14+
import { checkRateLimitAndThrowError } from "@calcom/lib/checkRateLimitAndThrowError";
15+
import getIP from "@calcom/lib/getIP";
16+
import { piiHasher } from "@calcom/lib/server/PiiHasher";
1417
import slugify from "@calcom/lib/slugify";
1518
import { prisma } from "@calcom/prisma";
1619
import { BookingStatus, RedirectType } from "@calcom/prisma/enums";
@@ -63,6 +66,7 @@ async function processReschedule({
6366
(booking?.eventTypeId === props.eventData?.id &&
6467
(booking.status !== BookingStatus.CANCELLED ||
6568
allowRescheduleForCancelledBooking ||
69+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
6670
!!(props.eventData as any)?.allowReschedulingCancelledBookings))
6771
) {
6872
props.booking = booking;
@@ -314,6 +318,12 @@ const paramsSchema = z.object({
314318
// Booker page fetches a tiny bit of data server side, to determine early
315319
// whether the page should show an away state or dynamic booking not allowed.
316320
export const getServerSideProps = async (context: GetServerSidePropsContext) => {
321+
const requestorIp = getIP(context.req as unknown as Request);
322+
await checkRateLimitAndThrowError({
323+
rateLimitingType: "core",
324+
identifier: `[user]/[type]-${piiHasher.hash(requestorIp)}`,
325+
});
326+
317327
const { user } = paramsSchema.parse(context.params);
318328
const isDynamicGroup = user.length > 1;
319329

apps/web/server/lib/[user]/getServerSideProps.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,14 @@ import { getUsernameList } from "@calcom/features/eventtypes/lib/defaultEvents";
88
import { getEventTypesPublic } from "@calcom/features/eventtypes/lib/getEventTypesPublic";
99
import { getBrandingForUser } from "@calcom/features/profile/lib/getBranding";
1010
import { UserRepository } from "@calcom/features/users/repositories/UserRepository";
11+
import { checkRateLimitAndThrowError } from "@calcom/lib/checkRateLimitAndThrowError";
1112
import { DEFAULT_DARK_BRAND_COLOR, DEFAULT_LIGHT_BRAND_COLOR } from "@calcom/lib/constants";
1213
import { getUserAvatarUrl } from "@calcom/lib/getAvatarUrl";
14+
import getIP from "@calcom/lib/getIP";
1315
import logger from "@calcom/lib/logger";
1416
import { markdownToSafeHTML } from "@calcom/lib/markdownToSafeHTML";
1517
import { safeStringify } from "@calcom/lib/safeStringify";
18+
import { piiHasher } from "@calcom/lib/server/PiiHasher";
1619
import { stripMarkdown } from "@calcom/lib/stripMarkdown";
1720
import { prisma } from "@calcom/prisma";
1821
import type { EventType, User } from "@calcom/prisma/client";
@@ -79,6 +82,12 @@ type UserPageProps = {
7982
} & EmbedProps;
8083

8184
export const getServerSideProps: GetServerSideProps<UserPageProps> = async (context) => {
85+
// handle IP based rate limiting
86+
const requestorIp = getIP(context.req as unknown as Request);
87+
await checkRateLimitAndThrowError({
88+
rateLimitingType: "core",
89+
identifier: `[user]-${piiHasher.hash(requestorIp)}`,
90+
});
8291
const { currentOrgDomain, isValidOrgDomain } = orgDomainConfig(context.req, context.params?.orgSlug);
8392
const usernameList = getUsernameList(context.query.user as string);
8493
const isARedirectFromNonOrgLink = context.query.orgRedirection === "true";
@@ -144,8 +153,7 @@ export const getServerSideProps: GetServerSideProps<UserPageProps> = async (cont
144153
theme: branding.theme,
145154
brandColor: branding.brandColor ?? DEFAULT_LIGHT_BRAND_COLOR,
146155
avatarUrl: user.avatarUrl,
147-
darkBrandColor:
148-
branding.darkBrandColor ?? DEFAULT_DARK_BRAND_COLOR,
156+
darkBrandColor: branding.darkBrandColor ?? DEFAULT_DARK_BRAND_COLOR,
149157
allowSEOIndexing: user.allowSEOIndexing ?? true,
150158
username: user.username,
151159
organization: user.profile.organization,

0 commit comments

Comments
 (0)