From fc70806b106e90b70bb1b61b154082a8778be4f2 Mon Sep 17 00:00:00 2001 From: Avraham Sakal Date: Sun, 21 Sep 2025 17:26:51 -0400 Subject: [PATCH] protect `conversation` trpc routes --- server/trpc/chat.ts | 6 ++++- server/trpc/conversations.ts | 43 +++++++++++++++++++++++++++--------- 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/server/trpc/chat.ts b/server/trpc/chat.ts index af650a8..0d50a93 100644 --- a/server/trpc/chat.ts +++ b/server/trpc/chat.ts @@ -17,7 +17,7 @@ import { createCaller as createCallerMessages } from "./messages.js"; import { createCaller as createCallerFactTriggers } from "./fact-triggers.js"; import { factTriggers } from "./fact-triggers.js"; import { MODEL_NAME } from "../provider.js"; -import type { Fact, FactTrigger } from "@database/common"; +import type { FactTrigger } from "@database/common"; const mainSystemPrompt = ({ systemPrompt, @@ -70,6 +70,10 @@ export const chat = router({ ctx, }) { const { dbClient, openrouter, jwt } = ctx; + if (!jwt) { + yield { status: "error" as const, message: "Unauthorized" }; + return; + } const factsCaller = createCallerFacts(ctx); const messagesCaller = createCallerMessages(ctx); const factTriggerCaller = createCallerFactTriggers(ctx); diff --git a/server/trpc/conversations.ts b/server/trpc/conversations.ts index d29b107..1b18ee1 100644 --- a/server/trpc/conversations.ts +++ b/server/trpc/conversations.ts @@ -14,30 +14,40 @@ export const conversations = router({ }), fetchOne: publicProcedure .input((x) => x as { id: string }) - .query(async ({ input: { id }, ctx: { dbClient } }) => { + .query(async ({ input: { id }, ctx: { dbClient, jwt } }) => { + const userId = jwt?.id as string | null; + if (!userId) return null; const row = await dbClient .selectFrom("conversations") .selectAll() .where("id", "=", id) + .where("userId", "=", userId) .execute(); return row[0]; }), start: publicProcedure.mutation(async ({ ctx: { dbClient, jwt } }) => { - const row = { - title: "New Conversation", - userId: jwt?.id as string, - }; + const userId = jwt?.id as string | null; + if (!userId) return null; const insertedRows = await dbClient .insertInto("conversations") - .values(row) + .values({ + title: "New Conversation", + userId: jwt?.id as string, + }) .returningAll() .execute(); return insertedRows[0]; }), deleteOne: publicProcedure .input((x) => x as { id: string }) - .mutation(async ({ input: { id }, ctx: { dbClient } }) => { - await dbClient.deleteFrom("conversations").where("id", "=", id).execute(); + .mutation(async ({ input: { id }, ctx: { dbClient, jwt } }) => { + const userId = jwt?.id as string | null; + if (!userId) return { ok: false }; + await dbClient + .deleteFrom("conversations") + .where("id", "=", id) + .where("userId", "=", userId) + .execute(); return { ok: true }; }), updateTitle: publicProcedure @@ -48,21 +58,32 @@ export const conversations = router({ title: string; } ) - .mutation(async ({ input: { id, title }, ctx: { dbClient } }) => { + .mutation(async ({ input: { id, title }, ctx: { dbClient, jwt } }) => { + const userId = jwt?.id as string | null; + if (!userId) return { ok: false }; await dbClient .updateTable("conversations") .set({ title }) .where("id", "=", id) + .where("userId", "=", userId) .execute(); return { ok: true }; }), fetchMessages: publicProcedure .input((x) => x as { conversationId: string }) - .query(async ({ input: { conversationId }, ctx: { dbClient } }) => { + .query(async ({ input: { conversationId }, ctx: { dbClient, jwt } }) => { + const userId = jwt?.id as string | null; + if (!userId) return []; const rows = await dbClient .selectFrom("messages") - .selectAll() + .innerJoin( + "conversations", + "conversations.id", + "messages.conversationId" + ) + .selectAll("messages") .where("conversationId", "=", conversationId) + .where("conversations.userId", "=", userId) .execute(); return rows as Array; }),