From 389c10fe92f7e47a7f7121c3a7d1b92ad26f09f4 Mon Sep 17 00:00:00 2001 From: Chris Farhood Date: Thu, 14 May 2026 18:22:06 +0000 Subject: [PATCH] fix(GRO-986): add businessId scoping to portal conversation messages query The GET /portal/conversation/messages endpoint was missing businessId scoping, allowing cross-tenant data access. This adds businessId from businessSettings to the conversation lookup in the messages endpoint, matching the existing GET /portal/conversation protection. Also adds missing lt mock to portal test suite. Co-Authored-By: Paperclip --- apps/api/src/__tests__/portal.test.ts | 1 + apps/api/src/routes/portal.ts | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/api/src/__tests__/portal.test.ts b/apps/api/src/__tests__/portal.test.ts index 956d905..6d3518f 100644 --- a/apps/api/src/__tests__/portal.test.ts +++ b/apps/api/src/__tests__/portal.test.ts @@ -143,6 +143,7 @@ vi.mock("@groombook/db", () => { messages, eq: vi.fn(), and: vi.fn(), + lt: vi.fn(), desc: vi.fn((col: unknown) => ({ _name: "desc", col })), }; }); diff --git a/apps/api/src/routes/portal.ts b/apps/api/src/routes/portal.ts index 99e6c5b..d3db583 100644 --- a/apps/api/src/routes/portal.ts +++ b/apps/api/src/routes/portal.ts @@ -212,11 +212,12 @@ portalRouter.get("/conversation/messages", async (c) => { const [settings] = await db.select({ id: businessSettings.id }).from(businessSettings).limit(1); if (!settings) return c.json({ error: "Business not configured" }, 500); + const businessId = settings.id; const [conversation] = await db .select({ id: conversations.id }) .from(conversations) - .where(eq(conversations.clientId, clientId)) + .where(and(eq(conversations.clientId, clientId), eq(conversations.businessId, businessId))) .limit(1); if (!conversation) {