From 79701929128702fe5fbce86a129d100628daa52e Mon Sep 17 00:00:00 2001 From: James Perkins Date: Fri, 29 Aug 2025 09:20:07 -0400 Subject: [PATCH] Adds CRUD checks Adds CRUD checks to certain tRPC routes to make sure the current user is able to do the action. --- apps/dashboard/lib/trpc/routers/org/getInvitationList.ts | 8 +++++++- apps/dashboard/lib/trpc/routers/org/inviteMember.ts | 8 +++++++- apps/dashboard/lib/trpc/routers/org/removeMembership.ts | 8 +++++++- apps/dashboard/lib/trpc/routers/org/revokeInvitation.ts | 8 +++++++- apps/dashboard/lib/trpc/routers/org/updateMembership.ts | 8 +++++++- apps/dashboard/lib/trpc/routers/workspace/changeName.ts | 6 ++++++ apps/dashboard/next.config.js | 1 + 7 files changed, 42 insertions(+), 5 deletions(-) diff --git a/apps/dashboard/lib/trpc/routers/org/getInvitationList.ts b/apps/dashboard/lib/trpc/routers/org/getInvitationList.ts index bf7a6e0e50..883a115f84 100644 --- a/apps/dashboard/lib/trpc/routers/org/getInvitationList.ts +++ b/apps/dashboard/lib/trpc/routers/org/getInvitationList.ts @@ -7,8 +7,14 @@ export const getInvitationList = t.procedure .use(requireUser) .use(requireOrgAdmin) .input(z.string()) - .query(async ({ input: orgId }) => { + .query(async ({ ctx, input: orgId }) => { try { + if (orgId !== ctx.workspace?.orgId) { + throw new TRPCError({ + code: "BAD_REQUEST", + message: "Invalid organization ID", + }); + } return await authProvider.getInvitationList(orgId); } catch (error) { console.error("Error retrieving organization member list:", error); diff --git a/apps/dashboard/lib/trpc/routers/org/inviteMember.ts b/apps/dashboard/lib/trpc/routers/org/inviteMember.ts index 131ad26986..d73c3ec42e 100644 --- a/apps/dashboard/lib/trpc/routers/org/inviteMember.ts +++ b/apps/dashboard/lib/trpc/routers/org/inviteMember.ts @@ -13,8 +13,14 @@ export const inviteMember = t.procedure role: z.enum(["basic_member", "admin"]), }), ) - .mutation(async ({ input }) => { + .mutation(async ({ ctx, input }) => { try { + if (input.orgId !== ctx.workspace?.orgId) { + throw new TRPCError({ + code: "BAD_REQUEST", + message: "Invalid organization ID", + }); + } return await authProvider.inviteMember({ email: input.email, role: input.role, diff --git a/apps/dashboard/lib/trpc/routers/org/removeMembership.ts b/apps/dashboard/lib/trpc/routers/org/removeMembership.ts index 14d80bfcae..092f574f80 100644 --- a/apps/dashboard/lib/trpc/routers/org/removeMembership.ts +++ b/apps/dashboard/lib/trpc/routers/org/removeMembership.ts @@ -12,8 +12,14 @@ export const removeMembership = t.procedure orgId: z.string(), // needed for the requireOrgAdmin middleware }), ) - .mutation(async ({ input }) => { + .mutation(async ({ ctx, input }) => { try { + if (input.orgId !== ctx.workspace?.orgId) { + throw new TRPCError({ + code: "BAD_REQUEST", + message: "Invalid organization ID", + }); + } return await authProvider.removeMembership(input.membershipId); } catch (error) { throw new TRPCError({ diff --git a/apps/dashboard/lib/trpc/routers/org/revokeInvitation.ts b/apps/dashboard/lib/trpc/routers/org/revokeInvitation.ts index b1c108dea8..58a2ef47fe 100644 --- a/apps/dashboard/lib/trpc/routers/org/revokeInvitation.ts +++ b/apps/dashboard/lib/trpc/routers/org/revokeInvitation.ts @@ -12,8 +12,14 @@ export const revokeInvitation = t.procedure orgId: z.string(), // needed for the requireOrgAdmin middleware }), ) - .mutation(async ({ input }) => { + .mutation(async ({ ctx, input }) => { try { + if (input.orgId !== ctx.workspace?.orgId) { + throw new TRPCError({ + code: "BAD_REQUEST", + message: "Invalid organization ID", + }); + } return await authProvider.revokeOrgInvitation(input.invitationId); } catch (error) { throw new TRPCError({ diff --git a/apps/dashboard/lib/trpc/routers/org/updateMembership.ts b/apps/dashboard/lib/trpc/routers/org/updateMembership.ts index 0cdbe8fde6..95e2157634 100644 --- a/apps/dashboard/lib/trpc/routers/org/updateMembership.ts +++ b/apps/dashboard/lib/trpc/routers/org/updateMembership.ts @@ -13,8 +13,14 @@ export const updateMembership = t.procedure role: z.string(), }), ) - .mutation(async ({ input }) => { + .mutation(async ({ ctx, input }) => { try { + if (input.orgId !== ctx.workspace?.orgId) { + throw new TRPCError({ + code: "BAD_REQUEST", + message: "Invalid organization ID", + }); + } return await authProvider.updateMembership({ membershipId: input.membershipId, role: input.role, diff --git a/apps/dashboard/lib/trpc/routers/workspace/changeName.ts b/apps/dashboard/lib/trpc/routers/workspace/changeName.ts index 328b8bbd1b..44d50af1f5 100644 --- a/apps/dashboard/lib/trpc/routers/workspace/changeName.ts +++ b/apps/dashboard/lib/trpc/routers/workspace/changeName.ts @@ -17,6 +17,12 @@ export const changeWorkspaceName = t.procedure }), ) .mutation(async ({ ctx, input }) => { + if (input.workspaceId !== ctx.workspace.id) { + throw new TRPCError({ + code: "BAD_REQUEST", + message: "Invalid workspace ID", + }); + } await db .transaction(async (tx) => { await tx diff --git a/apps/dashboard/next.config.js b/apps/dashboard/next.config.js index ec4ddf3cd1..79c6ae01aa 100644 --- a/apps/dashboard/next.config.js +++ b/apps/dashboard/next.config.js @@ -13,6 +13,7 @@ const nextConfig = { experimental: { esmExternals: "loose", }, + poweredByHeader: false, webpack: (config) => { config.cache = Object.freeze({ type: "memory",