mirror of
https://github.com/Dokploy/dokploy
synced 2025-06-26 18:27:59 +00:00
refactor(cloud): add validation to prevent access to resources from another admin
This commit is contained in:
@@ -3,10 +3,10 @@ import { pgEnum, pgTable, text } from "drizzle-orm/pg-core";
|
||||
import { createInsertSchema } from "drizzle-zod";
|
||||
import { nanoid } from "nanoid";
|
||||
import { z } from "zod";
|
||||
import { auth } from "./auth";
|
||||
import { bitbucket } from "./bitbucket";
|
||||
import { github } from "./github";
|
||||
import { gitlab } from "./gitlab";
|
||||
import { admins } from "./admin";
|
||||
|
||||
export const gitProviderType = pgEnum("gitProviderType", [
|
||||
"github",
|
||||
@@ -24,9 +24,9 @@ export const gitProvider = pgTable("git_provider", {
|
||||
createdAt: text("createdAt")
|
||||
.notNull()
|
||||
.$defaultFn(() => new Date().toISOString()),
|
||||
authId: text("authId")
|
||||
.notNull()
|
||||
.references(() => auth.id, { onDelete: "cascade" }),
|
||||
adminId: text("adminId").references(() => admins.adminId, {
|
||||
onDelete: "cascade",
|
||||
}),
|
||||
});
|
||||
|
||||
export const gitProviderRelations = relations(gitProvider, ({ one, many }) => ({
|
||||
@@ -42,9 +42,9 @@ export const gitProviderRelations = relations(gitProvider, ({ one, many }) => ({
|
||||
fields: [gitProvider.gitProviderId],
|
||||
references: [bitbucket.gitProviderId],
|
||||
}),
|
||||
auth: one(auth, {
|
||||
fields: [gitProvider.authId],
|
||||
references: [auth.id],
|
||||
admin: one(admins, {
|
||||
fields: [gitProvider.adminId],
|
||||
references: [admins.adminId],
|
||||
}),
|
||||
}));
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import { boolean, integer, pgEnum, pgTable, text } from "drizzle-orm/pg-core";
|
||||
import { createInsertSchema } from "drizzle-zod";
|
||||
import { nanoid } from "nanoid";
|
||||
import { z } from "zod";
|
||||
import { admins } from "./admin";
|
||||
|
||||
export const notificationType = pgEnum("notificationType", [
|
||||
"slack",
|
||||
@@ -38,6 +39,9 @@ export const notifications = pgTable("notification", {
|
||||
emailId: text("emailId").references(() => email.emailId, {
|
||||
onDelete: "cascade",
|
||||
}),
|
||||
adminId: text("adminId").references(() => admins.adminId, {
|
||||
onDelete: "cascade",
|
||||
}),
|
||||
});
|
||||
|
||||
export const slack = pgTable("slack", {
|
||||
@@ -96,6 +100,10 @@ export const notificationsRelations = relations(notifications, ({ one }) => ({
|
||||
fields: [notifications.emailId],
|
||||
references: [email.emailId],
|
||||
}),
|
||||
admin: one(admins, {
|
||||
fields: [notifications.adminId],
|
||||
references: [admins.adminId],
|
||||
}),
|
||||
}));
|
||||
|
||||
export const notificationsSchema = createInsertSchema(notifications);
|
||||
@@ -118,6 +126,7 @@ export const apiCreateSlack = notificationsSchema
|
||||
export const apiUpdateSlack = apiCreateSlack.partial().extend({
|
||||
notificationId: z.string().min(1),
|
||||
slackId: z.string(),
|
||||
adminId: z.string().optional(),
|
||||
});
|
||||
|
||||
export const apiTestSlackConnection = apiCreateSlack.pick({
|
||||
@@ -143,6 +152,7 @@ export const apiCreateTelegram = notificationsSchema
|
||||
export const apiUpdateTelegram = apiCreateTelegram.partial().extend({
|
||||
notificationId: z.string().min(1),
|
||||
telegramId: z.string().min(1),
|
||||
adminId: z.string().optional(),
|
||||
});
|
||||
|
||||
export const apiTestTelegramConnection = apiCreateTelegram.pick({
|
||||
@@ -167,6 +177,7 @@ export const apiCreateDiscord = notificationsSchema
|
||||
export const apiUpdateDiscord = apiCreateDiscord.partial().extend({
|
||||
notificationId: z.string().min(1),
|
||||
discordId: z.string().min(1),
|
||||
adminId: z.string().optional(),
|
||||
});
|
||||
|
||||
export const apiTestDiscordConnection = apiCreateDiscord.pick({
|
||||
@@ -195,6 +206,7 @@ export const apiCreateEmail = notificationsSchema
|
||||
export const apiUpdateEmail = apiCreateEmail.partial().extend({
|
||||
notificationId: z.string().min(1),
|
||||
emailId: z.string().min(1),
|
||||
adminId: z.string().optional(),
|
||||
});
|
||||
|
||||
export const apiTestEmailConnection = apiCreateEmail.pick({
|
||||
|
||||
@@ -12,13 +12,14 @@ export type Bitbucket = typeof bitbucket.$inferSelect;
|
||||
|
||||
export const createBitbucket = async (
|
||||
input: typeof apiCreateBitbucket._type,
|
||||
adminId: string,
|
||||
) => {
|
||||
return await db.transaction(async (tx) => {
|
||||
const newGitProvider = await tx
|
||||
.insert(gitProvider)
|
||||
.values({
|
||||
providerType: "bitbucket",
|
||||
authId: input.authId,
|
||||
adminId: adminId,
|
||||
name: input.name,
|
||||
})
|
||||
.returning()
|
||||
@@ -73,11 +74,12 @@ export const updateBitbucket = async (
|
||||
.where(eq(bitbucket.bitbucketId, bitbucketId))
|
||||
.returning();
|
||||
|
||||
if (input.name) {
|
||||
if (input.name || input.adminId) {
|
||||
await tx
|
||||
.update(gitProvider)
|
||||
.set({
|
||||
name: input.name,
|
||||
adminId: input.adminId,
|
||||
})
|
||||
.where(eq(gitProvider.gitProviderId, input.gitProviderId))
|
||||
.returning();
|
||||
|
||||
@@ -1,20 +1,19 @@
|
||||
import { db } from "@/server/db";
|
||||
import { type apiCreateDestination, destinations } from "@/server/db/schema";
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import { eq } from "drizzle-orm";
|
||||
import { findAdmin } from "./admin";
|
||||
import { and, eq } from "drizzle-orm";
|
||||
|
||||
export type Destination = typeof destinations.$inferSelect;
|
||||
|
||||
export const createDestintation = async (
|
||||
input: typeof apiCreateDestination._type,
|
||||
adminId: string,
|
||||
) => {
|
||||
const adminResponse = await findAdmin();
|
||||
const newDestination = await db
|
||||
.insert(destinations)
|
||||
.values({
|
||||
...input,
|
||||
adminId: adminResponse.adminId,
|
||||
adminId: adminId,
|
||||
})
|
||||
.returning()
|
||||
.then((value) => value[0]);
|
||||
@@ -31,7 +30,7 @@ export const createDestintation = async (
|
||||
|
||||
export const findDestinationById = async (destinationId: string) => {
|
||||
const destination = await db.query.destinations.findFirst({
|
||||
where: eq(destinations.destinationId, destinationId),
|
||||
where: and(eq(destinations.destinationId, destinationId)),
|
||||
});
|
||||
if (!destination) {
|
||||
throw new TRPCError({
|
||||
@@ -42,10 +41,18 @@ export const findDestinationById = async (destinationId: string) => {
|
||||
return destination;
|
||||
};
|
||||
|
||||
export const removeDestinationById = async (destinationId: string) => {
|
||||
export const removeDestinationById = async (
|
||||
destinationId: string,
|
||||
adminId: string,
|
||||
) => {
|
||||
const result = await db
|
||||
.delete(destinations)
|
||||
.where(eq(destinations.destinationId, destinationId))
|
||||
.where(
|
||||
and(
|
||||
eq(destinations.destinationId, destinationId),
|
||||
eq(destinations.adminId, adminId),
|
||||
),
|
||||
)
|
||||
.returning();
|
||||
|
||||
return result[0];
|
||||
@@ -60,7 +67,12 @@ export const updateDestinationById = async (
|
||||
.set({
|
||||
...destinationData,
|
||||
})
|
||||
.where(eq(destinations.destinationId, destinationId))
|
||||
.where(
|
||||
and(
|
||||
eq(destinations.destinationId, destinationId),
|
||||
eq(destinations.adminId, destinationData.adminId || ""),
|
||||
),
|
||||
)
|
||||
.returning();
|
||||
|
||||
return result[0];
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { db } from "@/server/db";
|
||||
import { type apiCreateGithub, gitProvider, github } from "@/server/db/schema";
|
||||
import { gitProvider } from "@/server/db/schema";
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import { eq } from "drizzle-orm";
|
||||
|
||||
@@ -14,6 +14,20 @@ export const removeGitProvider = async (gitProviderId: string) => {
|
||||
return result[0];
|
||||
};
|
||||
|
||||
export const findGitProviderById = async (gitProviderId: string) => {
|
||||
const result = await db.query.gitProvider.findFirst({
|
||||
where: eq(gitProvider.gitProviderId, gitProviderId),
|
||||
});
|
||||
|
||||
if (!result) {
|
||||
throw new TRPCError({
|
||||
code: "NOT_FOUND",
|
||||
message: "Git Provider not found",
|
||||
});
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
export const updateGitProvider = async (
|
||||
gitProviderId: string,
|
||||
input: Partial<GitProvider>,
|
||||
|
||||
@@ -21,6 +21,7 @@ export type Notification = typeof notifications.$inferSelect;
|
||||
|
||||
export const createSlackNotification = async (
|
||||
input: typeof apiCreateSlack._type,
|
||||
adminId: string,
|
||||
) => {
|
||||
await db.transaction(async (tx) => {
|
||||
const newSlack = await tx
|
||||
@@ -50,6 +51,7 @@ export const createSlackNotification = async (
|
||||
dokployRestart: input.dokployRestart,
|
||||
dockerCleanup: input.dockerCleanup,
|
||||
notificationType: "slack",
|
||||
adminId: adminId,
|
||||
})
|
||||
.returning()
|
||||
.then((value) => value[0]);
|
||||
@@ -78,6 +80,7 @@ export const updateSlackNotification = async (
|
||||
databaseBackup: input.databaseBackup,
|
||||
dokployRestart: input.dokployRestart,
|
||||
dockerCleanup: input.dockerCleanup,
|
||||
adminId: input.adminId,
|
||||
})
|
||||
.where(eq(notifications.notificationId, input.notificationId))
|
||||
.returning()
|
||||
@@ -106,6 +109,7 @@ export const updateSlackNotification = async (
|
||||
|
||||
export const createTelegramNotification = async (
|
||||
input: typeof apiCreateTelegram._type,
|
||||
adminId: string,
|
||||
) => {
|
||||
await db.transaction(async (tx) => {
|
||||
const newTelegram = await tx
|
||||
@@ -135,6 +139,7 @@ export const createTelegramNotification = async (
|
||||
dokployRestart: input.dokployRestart,
|
||||
dockerCleanup: input.dockerCleanup,
|
||||
notificationType: "telegram",
|
||||
adminId: adminId,
|
||||
})
|
||||
.returning()
|
||||
.then((value) => value[0]);
|
||||
@@ -163,6 +168,7 @@ export const updateTelegramNotification = async (
|
||||
databaseBackup: input.databaseBackup,
|
||||
dokployRestart: input.dokployRestart,
|
||||
dockerCleanup: input.dockerCleanup,
|
||||
adminId: input.adminId,
|
||||
})
|
||||
.where(eq(notifications.notificationId, input.notificationId))
|
||||
.returning()
|
||||
@@ -191,6 +197,7 @@ export const updateTelegramNotification = async (
|
||||
|
||||
export const createDiscordNotification = async (
|
||||
input: typeof apiCreateDiscord._type,
|
||||
adminId: string,
|
||||
) => {
|
||||
await db.transaction(async (tx) => {
|
||||
const newDiscord = await tx
|
||||
@@ -219,6 +226,7 @@ export const createDiscordNotification = async (
|
||||
dokployRestart: input.dokployRestart,
|
||||
dockerCleanup: input.dockerCleanup,
|
||||
notificationType: "discord",
|
||||
adminId: adminId,
|
||||
})
|
||||
.returning()
|
||||
.then((value) => value[0]);
|
||||
@@ -247,6 +255,7 @@ export const updateDiscordNotification = async (
|
||||
databaseBackup: input.databaseBackup,
|
||||
dokployRestart: input.dokployRestart,
|
||||
dockerCleanup: input.dockerCleanup,
|
||||
adminId: input.adminId,
|
||||
})
|
||||
.where(eq(notifications.notificationId, input.notificationId))
|
||||
.returning()
|
||||
@@ -274,6 +283,7 @@ export const updateDiscordNotification = async (
|
||||
|
||||
export const createEmailNotification = async (
|
||||
input: typeof apiCreateEmail._type,
|
||||
adminId: string,
|
||||
) => {
|
||||
await db.transaction(async (tx) => {
|
||||
const newEmail = await tx
|
||||
@@ -307,6 +317,7 @@ export const createEmailNotification = async (
|
||||
dokployRestart: input.dokployRestart,
|
||||
dockerCleanup: input.dockerCleanup,
|
||||
notificationType: "email",
|
||||
adminId: adminId,
|
||||
})
|
||||
.returning()
|
||||
.then((value) => value[0]);
|
||||
@@ -335,6 +346,7 @@ export const updateEmailNotification = async (
|
||||
databaseBackup: input.databaseBackup,
|
||||
dokployRestart: input.dokployRestart,
|
||||
dockerCleanup: input.dockerCleanup,
|
||||
adminId: input.adminId,
|
||||
})
|
||||
.where(eq(notifications.notificationId, input.notificationId))
|
||||
.returning()
|
||||
|
||||
Reference in New Issue
Block a user