diff --git a/apps/dokploy/server/api/routers/environment.ts b/apps/dokploy/server/api/routers/environment.ts index 334f40995..823b5419e 100644 --- a/apps/dokploy/server/api/routers/environment.ts +++ b/apps/dokploy/server/api/routers/environment.ts @@ -39,9 +39,18 @@ export const environmentRouter = createTRPCRouter({ one: protectedProcedure .input(apiFindOneEnvironment) - .query(async ({ input }) => { + .query(async ({ input, ctx }) => { try { const environment = await findEnvironmentById(input.environmentId); + if ( + environment.project.organizationId !== + ctx.session.activeOrganizationId + ) { + throw new TRPCError({ + code: "FORBIDDEN", + message: "You are not allowed to access this environment", + }); + } return environment; } catch (error) { throw new TRPCError({ @@ -53,9 +62,21 @@ export const environmentRouter = createTRPCRouter({ byProjectId: protectedProcedure .input(z.object({ projectId: z.string() })) - .query(async ({ input }) => { + .query(async ({ input, ctx }) => { try { const environments = await findEnvironmentsByProjectId(input.projectId); + if ( + environments.some( + (environment) => + environment.project.organizationId !== + ctx.session.activeOrganizationId, + ) + ) { + throw new TRPCError({ + code: "FORBIDDEN", + message: "You are not allowed to access this environment", + }); + } return environments; } catch (error) { throw new TRPCError({ @@ -67,8 +88,18 @@ export const environmentRouter = createTRPCRouter({ remove: protectedProcedure .input(apiRemoveEnvironment) - .mutation(async ({ input }) => { + .mutation(async ({ input, ctx }) => { try { + const environment = await findEnvironmentById(input.environmentId); + if ( + environment.project.organizationId !== + ctx.session.activeOrganizationId + ) { + throw new TRPCError({ + code: "FORBIDDEN", + message: "You are not allowed to access this environment", + }); + } const deletedEnvironment = await deleteEnvironment(input.environmentId); return deletedEnvironment; } catch (error) { @@ -81,9 +112,19 @@ export const environmentRouter = createTRPCRouter({ update: protectedProcedure .input(apiUpdateEnvironment) - .mutation(async ({ input }) => { + .mutation(async ({ input, ctx }) => { try { const { environmentId, ...updateData } = input; + const currentEnvironment = await findEnvironmentById(environmentId); + if ( + currentEnvironment.project.organizationId !== + ctx.session.activeOrganizationId + ) { + throw new TRPCError({ + code: "FORBIDDEN", + message: "You are not allowed to access this environment", + }); + } const environment = await updateEnvironmentById( environmentId, updateData, @@ -99,8 +140,18 @@ export const environmentRouter = createTRPCRouter({ duplicate: protectedProcedure .input(apiDuplicateEnvironment) - .mutation(async ({ input }) => { + .mutation(async ({ input, ctx }) => { try { + const environment = await findEnvironmentById(input.environmentId); + if ( + environment.project.organizationId !== + ctx.session.activeOrganizationId + ) { + throw new TRPCError({ + code: "FORBIDDEN", + message: "You are not allowed to access this environment", + }); + } const duplicatedEnvironment = await duplicateEnvironment(input); return duplicatedEnvironment; } catch (error) { diff --git a/apps/dokploy/server/api/routers/mount.ts b/apps/dokploy/server/api/routers/mount.ts index 4ffec8c19..814d3d392 100644 --- a/apps/dokploy/server/api/routers/mount.ts +++ b/apps/dokploy/server/api/routers/mount.ts @@ -3,9 +3,11 @@ import { deleteMount, findApplicationById, findMountById, + findMountOrganizationId, getServiceContainer, updateMount, } from "@dokploy/server"; +import { TRPCError } from "@trpc/server"; import { z } from "zod"; import { apiCreateMount, @@ -24,16 +26,39 @@ export const mountRouter = createTRPCRouter({ }), remove: protectedProcedure .input(apiRemoveMount) - .mutation(async ({ input }) => { + .mutation(async ({ input, ctx }) => { + const organizationId = await findMountOrganizationId(input.mountId); + if (organizationId !== ctx.session.activeOrganizationId) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You are not authorized to delete this mount", + }); + } return await deleteMount(input.mountId); }), - one: protectedProcedure.input(apiFindOneMount).query(async ({ input }) => { - return await findMountById(input.mountId); - }), + one: protectedProcedure + .input(apiFindOneMount) + .query(async ({ input, ctx }) => { + const organizationId = await findMountOrganizationId(input.mountId); + if (organizationId !== ctx.session.activeOrganizationId) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You are not authorized to access this mount", + }); + } + return await findMountById(input.mountId); + }), update: protectedProcedure .input(apiUpdateMount) - .mutation(async ({ input }) => { + .mutation(async ({ input, ctx }) => { + const organizationId = await findMountOrganizationId(input.mountId); + if (organizationId !== ctx.session.activeOrganizationId) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You are not authorized to update this mount", + }); + } return await updateMount(input.mountId, input); }), allNamedByApplicationId: protectedProcedure diff --git a/apps/dokploy/server/api/routers/port.ts b/apps/dokploy/server/api/routers/port.ts index 40ba23d91..bbd949804 100644 --- a/apps/dokploy/server/api/routers/port.ts +++ b/apps/dokploy/server/api/routers/port.ts @@ -27,22 +27,44 @@ export const portRouter = createTRPCRouter({ }); } }), - one: protectedProcedure.input(apiFindOnePort).query(async ({ input }) => { - try { - return await finPortById(input.portId); - } catch (error) { - throw new TRPCError({ - code: "BAD_REQUEST", - message: "Port not found", - cause: error, - }); - } - }), + one: protectedProcedure + .input(apiFindOnePort) + .query(async ({ input, ctx }) => { + try { + const port = await finPortById(input.portId); + if ( + port.application.environment.project.organizationId !== + ctx.session.activeOrganizationId + ) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You are not authorized to access this port", + }); + } + return port; + } catch (error) { + throw new TRPCError({ + code: "BAD_REQUEST", + message: "Port not found", + cause: error, + }); + } + }), delete: protectedProcedure .input(apiFindOnePort) - .mutation(async ({ input }) => { + .mutation(async ({ input, ctx }) => { + const port = await finPortById(input.portId); + if ( + port.application.environment.project.organizationId !== + ctx.session.activeOrganizationId + ) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You are not authorized to delete this port", + }); + } try { - return removePortById(input.portId); + return await removePortById(input.portId); } catch (error) { const message = error instanceof Error ? error.message : "Error input: Deleting port"; @@ -54,9 +76,19 @@ export const portRouter = createTRPCRouter({ }), update: protectedProcedure .input(apiUpdatePort) - .mutation(async ({ input }) => { + .mutation(async ({ input, ctx }) => { + const port = await finPortById(input.portId); + if ( + port.application.environment.project.organizationId !== + ctx.session.activeOrganizationId + ) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You are not authorized to update this port", + }); + } try { - return updatePortById(input.portId, input); + return await updatePortById(input.portId, input); } catch (error) { const message = error instanceof Error ? error.message : "Error updating the port"; diff --git a/apps/dokploy/server/api/routers/rollbacks.ts b/apps/dokploy/server/api/routers/rollbacks.ts index b8b904172..d9e6180fb 100644 --- a/apps/dokploy/server/api/routers/rollbacks.ts +++ b/apps/dokploy/server/api/routers/rollbacks.ts @@ -1,4 +1,8 @@ -import { removeRollbackById, rollback } from "@dokploy/server"; +import { + findRollbackById, + removeRollbackById, + rollback, +} from "@dokploy/server"; import { TRPCError } from "@trpc/server"; import { createTRPCRouter, protectedProcedure } from "@/server/api/trpc"; import { apiFindOneRollback } from "@/server/db/schema"; @@ -22,8 +26,18 @@ export const rollbackRouter = createTRPCRouter({ }), rollback: protectedProcedure .input(apiFindOneRollback) - .mutation(async ({ input }) => { + .mutation(async ({ input, ctx }) => { try { + const currentRollback = await findRollbackById(input.rollbackId); + if ( + currentRollback?.deployment?.application?.environment?.project + .organizationId !== ctx.session.activeOrganizationId + ) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You are not authorized to rollback this deployment", + }); + } return await rollback(input.rollbackId); } catch (error) { console.error(error); diff --git a/packages/server/src/services/mount.ts b/packages/server/src/services/mount.ts index d64fef6f1..f08a32312 100644 --- a/packages/server/src/services/mount.ts +++ b/packages/server/src/services/mount.ts @@ -105,13 +105,69 @@ export const findMountById = async (mountId: string) => { const mount = await db.query.mounts.findFirst({ where: eq(mounts.mountId, mountId), with: { - application: true, - postgres: true, - mariadb: true, - mongo: true, - mysql: true, - redis: true, - compose: true, + application: { + with: { + environment: { + with: { + project: true, + }, + }, + }, + }, + postgres: { + with: { + environment: { + with: { + project: true, + }, + }, + }, + }, + mariadb: { + with: { + environment: { + with: { + project: true, + }, + }, + }, + }, + mongo: { + with: { + environment: { + with: { + project: true, + }, + }, + }, + }, + mysql: { + with: { + environment: { + with: { + project: true, + }, + }, + }, + }, + redis: { + with: { + environment: { + with: { + project: true, + }, + }, + }, + }, + compose: { + with: { + environment: { + with: { + project: true, + }, + }, + }, + }, }, }); if (!mount) { @@ -123,6 +179,34 @@ export const findMountById = async (mountId: string) => { return mount; }; +export const findMountOrganizationId = async (mountId: string) => { + const mount = await findMountById(mountId); + + if (mount.application) { + return mount.application.environment.project.organizationId; + } + if (mount.postgres) { + return mount.postgres.environment.project.organizationId; + } + if (mount.mariadb) { + return mount.mariadb.environment.project.organizationId; + } + if (mount.mongo) { + return mount.mongo.environment.project.organizationId; + } + if (mount.mysql) { + return mount.mysql.environment.project.organizationId; + } + if (mount.redis) { + return mount.redis.environment.project.organizationId; + } + + if (mount.compose) { + return mount.compose.environment.project.organizationId; + } + return null; +}; + export const updateMount = async ( mountId: string, mountData: Partial, diff --git a/packages/server/src/services/port.ts b/packages/server/src/services/port.ts index 1f66c0143..afafba29b 100644 --- a/packages/server/src/services/port.ts +++ b/packages/server/src/services/port.ts @@ -27,6 +27,17 @@ export const createPort = async (input: typeof apiCreatePort._type) => { export const finPortById = async (portId: string) => { const result = await db.query.ports.findFirst({ where: eq(ports.portId, portId), + with: { + application: { + with: { + environment: { + with: { + project: true, + }, + }, + }, + }, + }, }); if (!result) { throw new TRPCError({ diff --git a/packages/server/src/services/rollbacks.ts b/packages/server/src/services/rollbacks.ts index 16060eaa8..16877e7d9 100644 --- a/packages/server/src/services/rollbacks.ts +++ b/packages/server/src/services/rollbacks.ts @@ -76,9 +76,24 @@ export const createRollback = async ( }); }; -const findRollbackById = async (rollbackId: string) => { +export const findRollbackById = async (rollbackId: string) => { const result = await db.query.rollbacks.findFirst({ where: eq(rollbacks.rollbackId, rollbackId), + with: { + deployment: { + with: { + application: { + with: { + environment: { + with: { + project: true, + }, + }, + }, + }, + }, + }, + }, }); if (!result) { diff --git a/packages/server/src/services/schedule.ts b/packages/server/src/services/schedule.ts index b311ba760..4dace4b67 100644 --- a/packages/server/src/services/schedule.ts +++ b/packages/server/src/services/schedule.ts @@ -35,9 +35,29 @@ export const findScheduleById = async (scheduleId: string) => { const schedule = await db.query.schedules.findFirst({ where: eq(schedules.scheduleId, scheduleId), with: { - application: true, - compose: true, - server: true, + application: { + with: { + environment: { + with: { + project: true, + }, + }, + }, + }, + compose: { + with: { + environment: { + with: { + project: true, + }, + }, + }, + }, + server: { + with: { + organization: true, + }, + }, }, }); @@ -50,6 +70,21 @@ export const findScheduleById = async (scheduleId: string) => { return schedule; }; +export const findScheduleOrganizationId = async (scheduleId: string) => { + const schedule = await findScheduleById(scheduleId); + + if (schedule?.application) { + return schedule?.application?.environment?.project?.organizationId; + } + if (schedule?.compose) { + return schedule?.compose?.environment?.project?.organizationId; + } + if (schedule?.server) { + return schedule?.server?.organization?.id; + } + return null; +}; + export const deleteSchedule = async (scheduleId: string) => { const schedule = await findScheduleById(scheduleId); const serverId =