mirror of
https://github.com/Dokploy/dokploy.git
synced 2026-07-05 22:15:22 +02:00
feat: add accessedServers permission handling and server access validation
- Introduced `accessedServers` field in user permissions schema and member table. - Implemented server access validation across various API routers to ensure users can only access permitted servers. - Added a new query to fetch accessible server IDs based on user roles and licenses. - Updated UI components to support server selection in user permissions.
This commit is contained in:
@@ -26,6 +26,7 @@ import {
|
||||
updateDeploymentStatus,
|
||||
writeConfig,
|
||||
writeConfigRemote,
|
||||
getAccessibleServerIds,
|
||||
} from "@dokploy/server";
|
||||
import { db } from "@dokploy/server/db";
|
||||
import {
|
||||
@@ -99,6 +100,16 @@ export const applicationRouter = createTRPCRouter({
|
||||
});
|
||||
}
|
||||
|
||||
if (input.serverId) {
|
||||
const accessibleIds = await getAccessibleServerIds(ctx.session);
|
||||
if (!accessibleIds.has(input.serverId)) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to access this server",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const newApplication = await createApplication(input);
|
||||
|
||||
await addNewService(ctx, newApplication.applicationId);
|
||||
@@ -630,6 +641,17 @@ export const applicationRouter = createTRPCRouter({
|
||||
await checkServicePermissionAndAccess(ctx, input.applicationId, {
|
||||
service: ["create"],
|
||||
});
|
||||
|
||||
if (input.buildServerId) {
|
||||
const accessibleIds = await getAccessibleServerIds(ctx.session);
|
||||
if (!accessibleIds.has(input.buildServerId)) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to access this build server",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const { applicationId, ...rest } = input;
|
||||
const updateApp = await updateApplication(applicationId, {
|
||||
...rest,
|
||||
|
||||
@@ -30,6 +30,7 @@ import {
|
||||
stopCompose,
|
||||
updateCompose,
|
||||
updateDeploymentStatus,
|
||||
getAccessibleServerIds,
|
||||
} from "@dokploy/server";
|
||||
import { db } from "@dokploy/server/db";
|
||||
import {
|
||||
@@ -100,6 +101,17 @@ export const composeRouter = createTRPCRouter({
|
||||
message: "You are not authorized to access this project",
|
||||
});
|
||||
}
|
||||
|
||||
if (input.serverId) {
|
||||
const accessibleIds = await getAccessibleServerIds(ctx.session);
|
||||
if (!accessibleIds.has(input.serverId)) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to access this server",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const newService = await createCompose({
|
||||
...input,
|
||||
});
|
||||
@@ -553,6 +565,16 @@ export const composeRouter = createTRPCRouter({
|
||||
});
|
||||
}
|
||||
|
||||
if (input.serverId) {
|
||||
const accessibleIds = await getAccessibleServerIds(ctx.session);
|
||||
if (!accessibleIds.has(input.serverId)) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to access this server",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const template = await fetchTemplateFiles(input.id, input.baseUrl);
|
||||
|
||||
let serverIp = "127.0.0.1";
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
stopService,
|
||||
stopServiceRemote,
|
||||
updateLibsqlById,
|
||||
getAccessibleServerIds,
|
||||
} from "@dokploy/server";
|
||||
import {
|
||||
addNewService,
|
||||
@@ -62,6 +63,17 @@ export const libsqlRouter = createTRPCRouter({
|
||||
message: "You are not authorized to access this project",
|
||||
});
|
||||
}
|
||||
|
||||
if (input.serverId) {
|
||||
const accessibleIds = await getAccessibleServerIds(ctx.session);
|
||||
if (!accessibleIds.has(input.serverId)) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to access this server",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const newLibsql = await createLibsql({
|
||||
...input,
|
||||
});
|
||||
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
stopService,
|
||||
stopServiceRemote,
|
||||
updateMariadbById,
|
||||
getAccessibleServerIds,
|
||||
} from "@dokploy/server";
|
||||
import { db } from "@dokploy/server/db";
|
||||
import {
|
||||
@@ -73,6 +74,17 @@ export const mariadbRouter = createTRPCRouter({
|
||||
message: "You are not authorized to access this project",
|
||||
});
|
||||
}
|
||||
|
||||
if (input.serverId) {
|
||||
const accessibleIds = await getAccessibleServerIds(ctx.session);
|
||||
if (!accessibleIds.has(input.serverId)) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to access this server",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const newMariadb = await createMariadb({
|
||||
...input,
|
||||
});
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
findEnvironmentById,
|
||||
findMongoById,
|
||||
findProjectById,
|
||||
getAccessibleServerIds,
|
||||
getServiceContainerCommand,
|
||||
IS_CLOUD,
|
||||
rebuildDatabase,
|
||||
@@ -72,6 +73,17 @@ export const mongoRouter = createTRPCRouter({
|
||||
message: "You are not authorized to access this project",
|
||||
});
|
||||
}
|
||||
|
||||
if (input.serverId) {
|
||||
const accessibleIds = await getAccessibleServerIds(ctx.session);
|
||||
if (!accessibleIds.has(input.serverId)) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to access this server",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const newMongo = await createMongo({
|
||||
...input,
|
||||
});
|
||||
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
stopService,
|
||||
stopServiceRemote,
|
||||
updateMySqlById,
|
||||
getAccessibleServerIds,
|
||||
} from "@dokploy/server";
|
||||
import { db } from "@dokploy/server/db";
|
||||
import {
|
||||
@@ -74,6 +75,16 @@ export const mysqlRouter = createTRPCRouter({
|
||||
});
|
||||
}
|
||||
|
||||
if (input.serverId) {
|
||||
const accessibleIds = await getAccessibleServerIds(ctx.session);
|
||||
if (!accessibleIds.has(input.serverId)) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to access this server",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const newMysql = await createMysql({
|
||||
...input,
|
||||
});
|
||||
|
||||
@@ -20,6 +20,7 @@ import {
|
||||
stopService,
|
||||
stopServiceRemote,
|
||||
updatePostgresById,
|
||||
getAccessibleServerIds,
|
||||
} from "@dokploy/server";
|
||||
import { db } from "@dokploy/server/db";
|
||||
import {
|
||||
@@ -74,6 +75,17 @@ export const postgresRouter = createTRPCRouter({
|
||||
message: "You are not authorized to access this project",
|
||||
});
|
||||
}
|
||||
|
||||
if (input.serverId) {
|
||||
const accessibleIds = await getAccessibleServerIds(ctx.session);
|
||||
if (!accessibleIds.has(input.serverId)) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to access this server",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const newPostgres = await createPostgres({
|
||||
...input,
|
||||
});
|
||||
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
stopService,
|
||||
stopServiceRemote,
|
||||
updateRedisById,
|
||||
getAccessibleServerIds,
|
||||
} from "@dokploy/server";
|
||||
import { db } from "@dokploy/server/db";
|
||||
import {
|
||||
@@ -70,6 +71,17 @@ export const redisRouter = createTRPCRouter({
|
||||
message: "You are not authorized to access this project",
|
||||
});
|
||||
}
|
||||
|
||||
if (input.serverId) {
|
||||
const accessibleIds = await getAccessibleServerIds(ctx.session);
|
||||
if (!accessibleIds.has(input.serverId)) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to access this server",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const newRedis = await createRedis({
|
||||
...input,
|
||||
});
|
||||
|
||||
@@ -14,8 +14,10 @@ import {
|
||||
serverValidate,
|
||||
setupMonitoring,
|
||||
updateServerById,
|
||||
getAccessibleServerIds,
|
||||
} from "@dokploy/server";
|
||||
import { db } from "@dokploy/server/db";
|
||||
import { hasValidLicense } from "@dokploy/server/services/proprietary/license-key";
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import { observable } from "@trpc/server/observable";
|
||||
import { and, desc, eq, getTableColumns, isNotNull, sql } from "drizzle-orm";
|
||||
@@ -88,6 +90,14 @@ export const serverRouter = createTRPCRouter({
|
||||
});
|
||||
}
|
||||
|
||||
const accessibleIds = await getAccessibleServerIds(ctx.session);
|
||||
if (!accessibleIds.has(input.serverId)) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to access this server",
|
||||
});
|
||||
}
|
||||
|
||||
return server;
|
||||
}),
|
||||
getDefaultCommand: withPermission("server", "read")
|
||||
@@ -98,6 +108,8 @@ export const serverRouter = createTRPCRouter({
|
||||
return defaultCommand(isBuildServer);
|
||||
}),
|
||||
all: withPermission("server", "read").query(async ({ ctx }) => {
|
||||
const accessibleIds = await getAccessibleServerIds(ctx.session);
|
||||
|
||||
const result = await db
|
||||
.select({
|
||||
...getTableColumns(server),
|
||||
@@ -115,8 +127,31 @@ export const serverRouter = createTRPCRouter({
|
||||
.orderBy(desc(server.createdAt))
|
||||
.groupBy(server.serverId);
|
||||
|
||||
return result;
|
||||
return result.filter((s) => accessibleIds.has(s.serverId));
|
||||
}),
|
||||
allForPermissions: withPermission("member", "update")
|
||||
.use(async ({ ctx, next }) => {
|
||||
const licensed = await hasValidLicense(ctx.session.activeOrganizationId);
|
||||
if (!licensed) {
|
||||
throw new TRPCError({
|
||||
code: "FORBIDDEN",
|
||||
message: "Valid enterprise license required",
|
||||
});
|
||||
}
|
||||
return next();
|
||||
})
|
||||
.query(async ({ ctx }) => {
|
||||
return await db.query.server.findMany({
|
||||
columns: {
|
||||
serverId: true,
|
||||
name: true,
|
||||
ipAddress: true,
|
||||
serverType: true,
|
||||
},
|
||||
orderBy: desc(server.createdAt),
|
||||
where: eq(server.organizationId, ctx.session.activeOrganizationId),
|
||||
});
|
||||
}),
|
||||
count: protectedProcedure.query(async ({ ctx }) => {
|
||||
const organizations = await db.query.organization.findMany({
|
||||
where: eq(organization.ownerId, ctx.user.id),
|
||||
@@ -130,6 +165,8 @@ export const serverRouter = createTRPCRouter({
|
||||
return servers.length ?? 0;
|
||||
}),
|
||||
withSSHKey: withPermission("server", "read").query(async ({ ctx }) => {
|
||||
const accessibleIds = await getAccessibleServerIds(ctx.session);
|
||||
|
||||
const result = await db.query.server.findMany({
|
||||
orderBy: desc(server.createdAt),
|
||||
where: IS_CLOUD
|
||||
@@ -145,9 +182,11 @@ export const serverRouter = createTRPCRouter({
|
||||
eq(server.serverType, "deploy"),
|
||||
),
|
||||
});
|
||||
return result;
|
||||
return result.filter((s) => accessibleIds.has(s.serverId));
|
||||
}),
|
||||
buildServers: withPermission("server", "read").query(async ({ ctx }) => {
|
||||
const accessibleIds = await getAccessibleServerIds(ctx.session);
|
||||
|
||||
const result = await db.query.server.findMany({
|
||||
orderBy: desc(server.createdAt),
|
||||
where: IS_CLOUD
|
||||
@@ -163,7 +202,7 @@ export const serverRouter = createTRPCRouter({
|
||||
eq(server.serverType, "build"),
|
||||
),
|
||||
});
|
||||
return result;
|
||||
return result.filter((s) => accessibleIds.has(s.serverId));
|
||||
}),
|
||||
setup: withPermission("server", "create")
|
||||
.input(apiFindOneServer)
|
||||
|
||||
@@ -347,7 +347,7 @@ export const userRouter = createTRPCRouter({
|
||||
});
|
||||
}
|
||||
|
||||
const { id, accessedGitProviders, ...rest } = input;
|
||||
const { id, accessedGitProviders, accessedServers, ...rest } = input;
|
||||
|
||||
const licensed = await hasValidLicense(
|
||||
ctx.session?.activeOrganizationId || "",
|
||||
@@ -360,6 +360,9 @@ export const userRouter = createTRPCRouter({
|
||||
...(licensed && accessedGitProviders !== undefined
|
||||
? { accessedGitProviders }
|
||||
: {}),
|
||||
...(licensed && accessedServers !== undefined
|
||||
? { accessedServers }
|
||||
: {}),
|
||||
})
|
||||
.where(
|
||||
and(
|
||||
|
||||
Reference in New Issue
Block a user