refactor(cloud): add validation to prevent execute in cloud version

This commit is contained in:
Mauricio Siu
2024-10-04 01:12:14 -06:00
parent ab4677ac0e
commit 3747db08d4
5 changed files with 268 additions and 25 deletions

View File

@@ -7,24 +7,49 @@ import {
findAllDeploymentsByApplicationId,
findAllDeploymentsByComposeId,
findAllDeploymentsByServerId,
findApplicationById,
findComposeById,
findServerById,
} from "@dokploy/builders";
import { createTRPCRouter, protectedProcedure } from "../trpc";
import { TRPCError } from "@trpc/server";
export const deploymentRouter = createTRPCRouter({
all: protectedProcedure
.input(apiFindAllByApplication)
.query(async ({ input }) => {
.query(async ({ input, ctx }) => {
const application = await findApplicationById(input.applicationId);
if (application.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this application",
});
}
return await findAllDeploymentsByApplicationId(input.applicationId);
}),
allByCompose: protectedProcedure
.input(apiFindAllByCompose)
.query(async ({ input }) => {
.query(async ({ input, ctx }) => {
const compose = await findComposeById(input.composeId);
if (compose.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this compose",
});
}
return await findAllDeploymentsByComposeId(input.composeId);
}),
allByServer: protectedProcedure
.input(apiFindAllByServer)
.query(async ({ input }) => {
.query(async ({ input, ctx }) => {
const server = await findServerById(input.serverId);
if (server.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this server",
});
}
return await findAllDeploymentsByServerId(input.serverId);
}),
});

View File

@@ -19,13 +19,31 @@ import {
generateTraefikMeDomain,
removeDomainById,
updateDomainById,
findComposeById,
} from "@dokploy/builders";
export const domainRouter = createTRPCRouter({
create: protectedProcedure
.input(apiCreateDomain)
.mutation(async ({ input }) => {
.mutation(async ({ input, ctx }) => {
try {
if (input.domainType === "compose" && input.composeId) {
const compose = await findComposeById(input.composeId);
if (compose.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this compose",
});
}
} else if (input.domainType === "application" && input.applicationId) {
const application = await findApplicationById(input.applicationId);
if (application.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this application",
});
}
}
return await createDomain(input);
} catch (error) {
throw new TRPCError({
@@ -37,12 +55,26 @@ export const domainRouter = createTRPCRouter({
}),
byApplicationId: protectedProcedure
.input(apiFindOneApplication)
.query(async ({ input }) => {
.query(async ({ input, ctx }) => {
const application = await findApplicationById(input.applicationId);
if (application.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this application",
});
}
return await findDomainsByApplicationId(input.applicationId);
}),
byComposeId: protectedProcedure
.input(apiFindCompose)
.query(async ({ input }) => {
.query(async ({ input, ctx }) => {
const compose = await findComposeById(input.composeId);
if (compose.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this compose",
});
}
return await findDomainsByComposeId(input.composeId);
}),
generateDomain: protectedProcedure
@@ -57,7 +89,26 @@ export const domainRouter = createTRPCRouter({
update: protectedProcedure
.input(apiUpdateDomain)
.mutation(async ({ input }) => {
.mutation(async ({ input, ctx }) => {
const currentDomain = await findDomainById(input.domainId);
if (currentDomain.applicationId) {
const newApp = await findApplicationById(currentDomain.applicationId);
if (newApp.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this application",
});
}
} else if (currentDomain.composeId) {
const newCompose = await findComposeById(currentDomain.composeId);
if (newCompose.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this compose",
});
}
}
const result = await updateDomainById(input.domainId, input);
const domain = await findDomainById(input.domainId);
if (domain.applicationId) {
@@ -66,13 +117,48 @@ export const domainRouter = createTRPCRouter({
}
return result;
}),
one: protectedProcedure.input(apiFindDomain).query(async ({ input }) => {
one: protectedProcedure.input(apiFindDomain).query(async ({ input, ctx }) => {
const domain = await findDomainById(input.domainId);
if (domain.applicationId) {
const application = await findApplicationById(domain.applicationId);
if (application.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this application",
});
}
} else if (domain.composeId) {
const compose = await findComposeById(domain.composeId);
if (compose.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this compose",
});
}
}
return await findDomainById(input.domainId);
}),
delete: protectedProcedure
.input(apiFindDomain)
.mutation(async ({ input }) => {
.mutation(async ({ input, ctx }) => {
const domain = await findDomainById(input.domainId);
if (domain.applicationId) {
const application = await findApplicationById(domain.applicationId);
if (application.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this application",
});
}
} else if (domain.composeId) {
const compose = await findComposeById(domain.composeId);
if (compose.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this compose",
});
}
}
const result = await removeDomainById(input.domainId);
if (domain.applicationId) {

View File

@@ -5,29 +5,64 @@ import {
} from "@/server/db/schema";
import {
createRedirect,
findApplicationById,
findRedirectById,
removeRedirectById,
updateRedirectById,
} from "@dokploy/builders";
import { createTRPCRouter, protectedProcedure } from "../trpc";
import { TRPCError } from "@trpc/server";
export const redirectsRouter = createTRPCRouter({
create: protectedProcedure
.input(apiCreateRedirect)
.mutation(async ({ input }) => {
.mutation(async ({ input, ctx }) => {
const application = await findApplicationById(input.applicationId);
if (application.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this application",
});
}
return await createRedirect(input);
}),
one: protectedProcedure.input(apiFindOneRedirect).query(async ({ input }) => {
return findRedirectById(input.redirectId);
}),
one: protectedProcedure
.input(apiFindOneRedirect)
.query(async ({ input, ctx }) => {
const redirect = await findRedirectById(input.redirectId);
const application = await findApplicationById(redirect.applicationId);
if (application.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this application",
});
}
return findRedirectById(input.redirectId);
}),
delete: protectedProcedure
.input(apiFindOneRedirect)
.mutation(async ({ input }) => {
.mutation(async ({ input, ctx }) => {
const redirect = await findRedirectById(input.redirectId);
const application = await findApplicationById(redirect.applicationId);
if (application.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this application",
});
}
return removeRedirectById(input.redirectId);
}),
update: protectedProcedure
.input(apiUpdateRedirect)
.mutation(async ({ input }) => {
.mutation(async ({ input, ctx }) => {
const redirect = await findRedirectById(input.redirectId);
const application = await findApplicationById(redirect.applicationId);
if (application.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this application",
});
}
return updateRedirectById(input.redirectId, input);
}),
});

View File

@@ -6,28 +6,63 @@ import {
import {
createSecurity,
deleteSecurityById,
findApplicationById,
findSecurityById,
updateSecurityById,
} from "@dokploy/builders";
import { createTRPCRouter, protectedProcedure } from "../trpc";
import { TRPCError } from "@trpc/server";
export const securityRouter = createTRPCRouter({
create: protectedProcedure
.input(apiCreateSecurity)
.mutation(async ({ input }) => {
.mutation(async ({ input, ctx }) => {
const application = await findApplicationById(input.applicationId);
if (application.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this application",
});
}
return await createSecurity(input);
}),
one: protectedProcedure.input(apiFindOneSecurity).query(async ({ input }) => {
return await findSecurityById(input.securityId);
}),
one: protectedProcedure
.input(apiFindOneSecurity)
.query(async ({ input, ctx }) => {
const security = await findSecurityById(input.securityId);
const application = await findApplicationById(security.applicationId);
if (application.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this application",
});
}
return await findSecurityById(input.securityId);
}),
delete: protectedProcedure
.input(apiFindOneSecurity)
.mutation(async ({ input }) => {
.mutation(async ({ input, ctx }) => {
const security = await findSecurityById(input.securityId);
const application = await findApplicationById(security.applicationId);
if (application.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this application",
});
}
return await deleteSecurityById(input.securityId);
}),
update: protectedProcedure
.input(apiUpdateSecurity)
.mutation(async ({ input }) => {
.mutation(async ({ input, ctx }) => {
const security = await findSecurityById(input.securityId);
const application = await findApplicationById(security.applicationId);
if (application.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this application",
});
}
return await updateSecurityById(input.securityId, input);
}),
});

View File

@@ -60,6 +60,9 @@ import { adminProcedure, createTRPCRouter, protectedProcedure } from "../trpc";
export const settingsRouter = createTRPCRouter({
reloadServer: adminProcedure.mutation(async () => {
if (IS_CLOUD) {
return true;
}
const { stdout } = await execAsync(
"docker service inspect dokploy --format '{{.ID}}'",
);
@@ -73,7 +76,7 @@ export const settingsRouter = createTRPCRouter({
if (input?.serverId) {
await stopServiceRemote(input.serverId, "dokploy-traefik");
await startServiceRemote(input.serverId, "dokploy-traefik");
} else {
} else if (!IS_CLOUD) {
await stopService("dokploy-traefik");
await startService("dokploy-traefik");
}
@@ -135,6 +138,9 @@ export const settingsRouter = createTRPCRouter({
return true;
}),
cleanMonitoring: adminProcedure.mutation(async () => {
if (IS_CLOUD) {
return true;
}
const { MONITORING_PATH } = paths();
await recreateDirectory(MONITORING_PATH);
return true;
@@ -142,6 +148,9 @@ export const settingsRouter = createTRPCRouter({
saveSSHPrivateKey: adminProcedure
.input(apiSaveSSHKey)
.mutation(async ({ input, ctx }) => {
if (IS_CLOUD) {
return true;
}
await updateAdmin(ctx.user.authId, {
sshPrivateKey: input.sshPrivateKey,
});
@@ -151,6 +160,9 @@ export const settingsRouter = createTRPCRouter({
assignDomainServer: adminProcedure
.input(apiAssignDomain)
.mutation(async ({ ctx, input }) => {
if (IS_CLOUD) {
return true;
}
const admin = await updateAdmin(ctx.user.authId, {
host: input.host,
letsEncryptEmail: input.letsEncryptEmail,
@@ -169,6 +181,9 @@ export const settingsRouter = createTRPCRouter({
return admin;
}),
cleanSSHPrivateKey: adminProcedure.mutation(async ({ ctx }) => {
if (IS_CLOUD) {
return true;
}
await updateAdmin(ctx.user.authId, {
sshPrivateKey: null,
});
@@ -194,7 +209,7 @@ export const settingsRouter = createTRPCRouter({
await sendDockerCleanupNotifications();
});
}
} else {
} else if (!IS_CLOUD) {
await updateAdmin(ctx.user.authId, {
enableDockerCleanup: input.enableDockerCleanup,
});
@@ -220,6 +235,9 @@ export const settingsRouter = createTRPCRouter({
}),
readTraefikConfig: adminProcedure.query(() => {
if (IS_CLOUD) {
return true;
}
const traefikConfig = readMainConfig();
return traefikConfig;
}),
@@ -227,22 +245,34 @@ export const settingsRouter = createTRPCRouter({
updateTraefikConfig: adminProcedure
.input(apiTraefikConfig)
.mutation(async ({ input }) => {
if (IS_CLOUD) {
return true;
}
writeMainConfig(input.traefikConfig);
return true;
}),
readWebServerTraefikConfig: adminProcedure.query(() => {
if (IS_CLOUD) {
return true;
}
const traefikConfig = readConfig("dokploy");
return traefikConfig;
}),
updateWebServerTraefikConfig: adminProcedure
.input(apiTraefikConfig)
.mutation(async ({ input }) => {
if (IS_CLOUD) {
return true;
}
writeConfig("dokploy", input.traefikConfig);
return true;
}),
readMiddlewareTraefikConfig: adminProcedure.query(() => {
if (IS_CLOUD) {
return true;
}
const traefikConfig = readConfig("middlewares");
return traefikConfig;
}),
@@ -250,14 +280,23 @@ export const settingsRouter = createTRPCRouter({
updateMiddlewareTraefikConfig: adminProcedure
.input(apiTraefikConfig)
.mutation(async ({ input }) => {
if (IS_CLOUD) {
return true;
}
writeConfig("middlewares", input.traefikConfig);
return true;
}),
checkAndUpdateImage: adminProcedure.mutation(async () => {
if (IS_CLOUD) {
return true;
}
return await pullLatestRelease();
}),
updateServer: adminProcedure.mutation(async () => {
if (IS_CLOUD) {
return true;
}
await spawnAsync("docker", [
"service",
"update",
@@ -322,6 +361,9 @@ export const settingsRouter = createTRPCRouter({
return readConfigInPath(input.path, input.serverId);
}),
getIp: protectedProcedure.query(async () => {
if (IS_CLOUD) {
return true;
}
const admin = await findAdmin();
return admin.serverIp;
}),
@@ -387,8 +429,10 @@ export const settingsRouter = createTRPCRouter({
const result = await execAsyncRemote(input.serverId, command);
return result.stdout.trim();
}
const result = await execAsync(command);
return result.stdout.trim();
if (!IS_CLOUD) {
const result = await execAsync(command);
return result.stdout.trim();
}
}),
writeTraefikEnv: adminProcedure
@@ -439,6 +483,9 @@ export const settingsRouter = createTRPCRouter({
})
.input(apiReadStatsLogs)
.query(({ input }) => {
if (IS_CLOUD) {
return true;
}
const rawConfig = readMonitoringConfig();
const parsedConfig = parseRawConfig(
rawConfig as string,
@@ -451,11 +498,17 @@ export const settingsRouter = createTRPCRouter({
return parsedConfig;
}),
readStats: adminProcedure.query(() => {
if (IS_CLOUD) {
return true;
}
const rawConfig = readMonitoringConfig();
const processedLogs = processLogs(rawConfig as string);
return processedLogs || [];
}),
getLogRotateStatus: adminProcedure.query(async () => {
if (IS_CLOUD) {
return true;
}
return await logRotationManager.getStatus();
}),
toggleLogRotate: adminProcedure
@@ -465,6 +518,9 @@ export const settingsRouter = createTRPCRouter({
}),
)
.mutation(async ({ input }) => {
if (IS_CLOUD) {
return true;
}
if (input.enable) {
await logRotationManager.activate();
} else {
@@ -474,6 +530,9 @@ export const settingsRouter = createTRPCRouter({
return true;
}),
haveActivateRequests: adminProcedure.query(async () => {
if (IS_CLOUD) {
return true;
}
const config = readMainConfig();
if (!config) return false;
@@ -492,6 +551,9 @@ export const settingsRouter = createTRPCRouter({
}),
)
.mutation(async ({ input }) => {
if (IS_CLOUD) {
return true;
}
const mainConfig = readMainConfig();
if (!mainConfig) return false;