From 6f02fbe13bcd0261baa0bb99e09155aec545620d Mon Sep 17 00:00:00 2001 From: Peer Richelsen Date: Thu, 4 Dec 2025 06:36:24 +0100 Subject: [PATCH] fix: expand Intercom allowed URLs and prevent double-prefixing (#25181) Co-authored-by: peer@cal.com Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- packages/app-store/intercom/api/get.ts | 28 +++++++++++++++++-- packages/app-store/intercom/api/initialize.ts | 2 +- .../app-store/intercom/lib/isValidCalURL.ts | 2 +- 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/packages/app-store/intercom/api/get.ts b/packages/app-store/intercom/api/get.ts index f06012a89c..87a92872df 100644 --- a/packages/app-store/intercom/api/get.ts +++ b/packages/app-store/intercom/api/get.ts @@ -13,6 +13,30 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) res.setHeader("Content-Type", "text/html"); + let origin = WEBAPP_URL; + let calLink = url; + + if (/^https?:\/\//i.test(url)) { + try { + const parsedUrl = new URL(url); + const hostname = parsedUrl.hostname.toLowerCase(); + + if (hostname === "cal.com" || hostname.endsWith(".cal.com")) { + origin = parsedUrl.origin; + calLink = parsedUrl.pathname + parsedUrl.search; + if (calLink.startsWith("/")) { + calLink = calLink.substring(1); + } + } else { + return res.status(400).json({ message: "URL must be for cal.com or a subdomain of cal.com" }); + } + } catch { + return res.status(400).json({ message: "Invalid URL format" }); + } + } else { + calLink = url.replace(`${WEBAPP_URL}/`, ""); + } + // Generate HTML with embedded Cal component const htmlResponse = ` @@ -56,11 +80,11 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) }; })(window, "https://app.cal.com/embed/embed.js", "init"); - Cal("init", { origin: "${WEBAPP_URL}" }); + Cal("init", { origin: "${origin}" }); Cal("inline", { elementOrSelector: "#my-cal-inline", - calLink: "${url.replace(`${WEBAPP_URL}/`, "")}", + calLink: "${calLink}", config: { theme: "light", }, diff --git a/packages/app-store/intercom/api/initialize.ts b/packages/app-store/intercom/api/initialize.ts index 49cbf9102d..5edb8adffc 100644 --- a/packages/app-store/intercom/api/initialize.ts +++ b/packages/app-store/intercom/api/initialize.ts @@ -9,7 +9,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) if (!card_creation_options) return res.status(400).json({ message: "Missing card_creation_options" }); - const URL = `${WEBAPP_URL}/api/integrations/intercom/get?url=${card_creation_options.submit_booking_url}`; + const URL = `${WEBAPP_URL}/api/integrations/intercom/get?url=${encodeURIComponent(card_creation_options.submit_booking_url)}`; const canvasData: NewCanvas = { canvas: { diff --git a/packages/app-store/intercom/lib/isValidCalURL.ts b/packages/app-store/intercom/lib/isValidCalURL.ts index 9d961b91e5..836cdebf1f 100644 --- a/packages/app-store/intercom/lib/isValidCalURL.ts +++ b/packages/app-store/intercom/lib/isValidCalURL.ts @@ -9,7 +9,7 @@ import type { TextComponent } from "../lib"; */ export async function isValidCalURL(url: string) { const regex = new RegExp( - `^https://(?:[a-zA-Z0-9-]+\\.)?${CAL_URL.replace("https://", "")}/(team/)?(org/)?`, + `^https://(?:[a-zA-Z0-9-]+\\.)?${CAL_URL.replace("https://", "")}/`, "i" );