diff --git a/apps/dokploy/components/dashboard/settings/users/add-permissions.tsx b/apps/dokploy/components/dashboard/settings/users/add-permissions.tsx
index 7c1f50375..bde2e71ca 100644
--- a/apps/dokploy/components/dashboard/settings/users/add-permissions.tsx
+++ b/apps/dokploy/components/dashboard/settings/users/add-permissions.tsx
@@ -52,7 +52,7 @@ interface Props {
export const AddUserPermissions = ({ userId }: Props) => {
const { data: projects } = api.project.all.useQuery();
- const { data, refetch } = api.user.byUserId.useQuery(
+ const { data, refetch } = api.auth.one.useQuery(
{
userId,
},
@@ -92,7 +92,7 @@ export const AddUserPermissions = ({ userId }: Props) => {
const onSubmit = async (data: AddPermissions) => {
await mutateAsync({
- userId,
+ id: userId,
canCreateServices: data.canCreateServices,
canCreateProjects: data.canCreateProjects,
canDeleteServices: data.canDeleteServices,
diff --git a/apps/dokploy/components/dashboard/settings/users/show-users.tsx b/apps/dokploy/components/dashboard/settings/users/show-users.tsx
index 8aa2a37b4..e0ffac139 100644
--- a/apps/dokploy/components/dashboard/settings/users/show-users.tsx
+++ b/apps/dokploy/components/dashboard/settings/users/show-users.tsx
@@ -104,9 +104,9 @@ export const ShowUsers = () => {
- {user.user.is2FAEnabled
+ {/* {user.user.is2FAEnabled
? "2FA Enabled"
- : "2FA Not Enabled"}
+ : "2FA Not Enabled"} */}
{/*
@@ -156,7 +156,7 @@ export const ShowUsers = () => {
/>
)} */}
- {user.role !== "owner" && (
+ {/* {user.role !== "owner" && (
{
Delete User
- )}
+ )} */}
diff --git a/apps/dokploy/components/dashboard/settings/web-server/update-server-ip.tsx b/apps/dokploy/components/dashboard/settings/web-server/update-server-ip.tsx
index dd3f81fdc..07103d5ba 100644
--- a/apps/dokploy/components/dashboard/settings/web-server/update-server-ip.tsx
+++ b/apps/dokploy/components/dashboard/settings/web-server/update-server-ip.tsx
@@ -1,5 +1,4 @@
import { AlertBlock } from "@/components/shared/alert-block";
-import { CodeEditor } from "@/components/shared/code-editor";
import { Button } from "@/components/ui/button";
import {
Dialog,
@@ -47,11 +46,11 @@ interface Props {
export const UpdateServerIp = ({ children, serverId }: Props) => {
const [isOpen, setIsOpen] = useState(false);
- const { data } = api.admin.one.useQuery();
+ const { data } = api.user.get.useQuery();
const { data: ip } = api.server.publicIp.useQuery();
const { mutateAsync, isLoading, error, isError } =
- api.admin.update.useMutation();
+ api.user.update.useMutation();
const form = useForm({
defaultValues: {
diff --git a/apps/dokploy/drizzle/0066_yielding_echo.sql b/apps/dokploy/drizzle/0066_yielding_echo.sql
index c66e2318b..d69a4c659 100644
--- a/apps/dokploy/drizzle/0066_yielding_echo.sql
+++ b/apps/dokploy/drizzle/0066_yielding_echo.sql
@@ -16,6 +16,7 @@ CREATE TABLE "user_temp" (
"canAccessToTraefikFiles" boolean DEFAULT false NOT NULL,
"accesedProjects" text[] DEFAULT ARRAY[]::text[] NOT NULL,
"accesedServices" text[] DEFAULT ARRAY[]::text[] NOT NULL,
+ "two_factor_enabled" boolean DEFAULT false NOT NULL,
"email" text NOT NULL,
"email_verified" boolean NOT NULL,
"image" text,
@@ -113,6 +114,13 @@ CREATE TABLE "verification" (
"created_at" timestamp,
"updated_at" timestamp
);
+
+CREATE TABLE "two_factor" (
+ "id" text PRIMARY KEY NOT NULL,
+ "secret" text NOT NULL,
+ "backup_codes" text NOT NULL,
+ "user_id" text NOT NULL
+);
--> statement-breakpoint
ALTER TABLE "certificate" ALTER COLUMN "adminId" SET NOT NULL;--> statement-breakpoint
ALTER TABLE "notification" ALTER COLUMN "adminId" SET NOT NULL;--> statement-breakpoint
@@ -124,4 +132,5 @@ ALTER TABLE "invitation" ADD CONSTRAINT "invitation_organization_id_organization
ALTER TABLE "invitation" ADD CONSTRAINT "invitation_inviter_id_user_temp_id_fk" FOREIGN KEY ("inviter_id") REFERENCES "public"."user_temp"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "member" ADD CONSTRAINT "member_organization_id_organization_id_fk" FOREIGN KEY ("organization_id") REFERENCES "public"."organization"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "member" ADD CONSTRAINT "member_user_id_user_temp_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user_temp"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
-ALTER TABLE "organization" ADD CONSTRAINT "organization_owner_id_user_temp_id_fk" FOREIGN KEY ("owner_id") REFERENCES "public"."user_temp"("id") ON DELETE no action ON UPDATE no action;
\ No newline at end of file
+ALTER TABLE "organization" ADD CONSTRAINT "organization_owner_id_user_temp_id_fk" FOREIGN KEY ("owner_id") REFERENCES "public"."user_temp"("id") ON DELETE no action ON UPDATE no action;
+ALTER TABLE "two_factor" ADD CONSTRAINT "two_factor_user_id_user_temp_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user_temp"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
diff --git a/apps/dokploy/drizzle/0073_brave_wolfpack.sql b/apps/dokploy/drizzle/0073_polite_miss_america.sql
similarity index 90%
rename from apps/dokploy/drizzle/0073_brave_wolfpack.sql
rename to apps/dokploy/drizzle/0073_polite_miss_america.sql
index 05bf5cb47..030f8a883 100644
--- a/apps/dokploy/drizzle/0073_brave_wolfpack.sql
+++ b/apps/dokploy/drizzle/0073_polite_miss_america.sql
@@ -1,3 +1,4 @@
+--> statement-breakpoint
DROP TABLE "user" CASCADE;--> statement-breakpoint
DROP TABLE "admin" CASCADE;--> statement-breakpoint
DROP TABLE "auth" CASCADE;--> statement-breakpoint
diff --git a/apps/dokploy/drizzle/meta/0066_snapshot.json b/apps/dokploy/drizzle/meta/0066_snapshot.json
index bcb7807a7..06b899346 100644
--- a/apps/dokploy/drizzle/meta/0066_snapshot.json
+++ b/apps/dokploy/drizzle/meta/0066_snapshot.json
@@ -1010,6 +1010,12 @@
"notNull": true,
"default": "ARRAY[]::text[]"
},
+ "two_factor_enabled": {
+ "name": "two_factor_enabled",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false
+ },
"email": {
"name": "email",
"type": "text",
@@ -5045,6 +5051,57 @@
"checkConstraints": {},
"isRLSEnabled": false
},
+ "public.two_factor": {
+ "name": "two_factor",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "secret": {
+ "name": "secret",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "backup_codes": {
+ "name": "backup_codes",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "two_factor_user_id_user_temp_id_fk": {
+ "name": "two_factor_user_id_user_temp_id_fk",
+ "tableFrom": "two_factor",
+ "tableTo": "user_temp",
+ "columnsFrom": [
+ "user_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
"public.verification": {
"name": "verification",
"schema": "",
diff --git a/apps/dokploy/drizzle/meta/0067_snapshot.json b/apps/dokploy/drizzle/meta/0067_snapshot.json
index 69d4a4ee8..be43b406b 100644
--- a/apps/dokploy/drizzle/meta/0067_snapshot.json
+++ b/apps/dokploy/drizzle/meta/0067_snapshot.json
@@ -1010,6 +1010,12 @@
"notNull": true,
"default": "ARRAY[]::text[]"
},
+ "two_factor_enabled": {
+ "name": "two_factor_enabled",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false
+ },
"email": {
"name": "email",
"type": "text",
@@ -5045,6 +5051,57 @@
"checkConstraints": {},
"isRLSEnabled": false
},
+ "public.two_factor": {
+ "name": "two_factor",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "secret": {
+ "name": "secret",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "backup_codes": {
+ "name": "backup_codes",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "two_factor_user_id_user_temp_id_fk": {
+ "name": "two_factor_user_id_user_temp_id_fk",
+ "tableFrom": "two_factor",
+ "tableTo": "user_temp",
+ "columnsFrom": [
+ "user_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
"public.verification": {
"name": "verification",
"schema": "",
diff --git a/apps/dokploy/drizzle/meta/0068_snapshot.json b/apps/dokploy/drizzle/meta/0068_snapshot.json
index 02e33084f..2139b1321 100644
--- a/apps/dokploy/drizzle/meta/0068_snapshot.json
+++ b/apps/dokploy/drizzle/meta/0068_snapshot.json
@@ -1010,6 +1010,12 @@
"notNull": true,
"default": "ARRAY[]::text[]"
},
+ "two_factor_enabled": {
+ "name": "two_factor_enabled",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false
+ },
"email": {
"name": "email",
"type": "text",
@@ -5045,6 +5051,57 @@
"checkConstraints": {},
"isRLSEnabled": false
},
+ "public.two_factor": {
+ "name": "two_factor",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "secret": {
+ "name": "secret",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "backup_codes": {
+ "name": "backup_codes",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "two_factor_user_id_user_temp_id_fk": {
+ "name": "two_factor_user_id_user_temp_id_fk",
+ "tableFrom": "two_factor",
+ "tableTo": "user_temp",
+ "columnsFrom": [
+ "user_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
"public.verification": {
"name": "verification",
"schema": "",
diff --git a/apps/dokploy/drizzle/meta/0069_snapshot.json b/apps/dokploy/drizzle/meta/0069_snapshot.json
index 41b53582e..d3e5be98b 100644
--- a/apps/dokploy/drizzle/meta/0069_snapshot.json
+++ b/apps/dokploy/drizzle/meta/0069_snapshot.json
@@ -1018,6 +1018,12 @@
"notNull": true,
"default": "ARRAY[]::text[]"
},
+ "two_factor_enabled": {
+ "name": "two_factor_enabled",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false
+ },
"email": {
"name": "email",
"type": "text",
@@ -5053,6 +5059,57 @@
"checkConstraints": {},
"isRLSEnabled": false
},
+ "public.two_factor": {
+ "name": "two_factor",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "secret": {
+ "name": "secret",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "backup_codes": {
+ "name": "backup_codes",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "two_factor_user_id_user_temp_id_fk": {
+ "name": "two_factor_user_id_user_temp_id_fk",
+ "tableFrom": "two_factor",
+ "tableTo": "user_temp",
+ "columnsFrom": [
+ "user_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
"public.verification": {
"name": "verification",
"schema": "",
diff --git a/apps/dokploy/drizzle/meta/0070_snapshot.json b/apps/dokploy/drizzle/meta/0070_snapshot.json
index 681bded7e..e3864a19c 100644
--- a/apps/dokploy/drizzle/meta/0070_snapshot.json
+++ b/apps/dokploy/drizzle/meta/0070_snapshot.json
@@ -1018,6 +1018,12 @@
"notNull": true,
"default": "ARRAY[]::text[]"
},
+ "two_factor_enabled": {
+ "name": "two_factor_enabled",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false
+ },
"email": {
"name": "email",
"type": "text",
@@ -5205,6 +5211,57 @@
"checkConstraints": {},
"isRLSEnabled": false
},
+ "public.two_factor": {
+ "name": "two_factor",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "secret": {
+ "name": "secret",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "backup_codes": {
+ "name": "backup_codes",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "two_factor_user_id_user_temp_id_fk": {
+ "name": "two_factor_user_id_user_temp_id_fk",
+ "tableFrom": "two_factor",
+ "tableTo": "user_temp",
+ "columnsFrom": [
+ "user_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
"public.verification": {
"name": "verification",
"schema": "",
diff --git a/apps/dokploy/drizzle/meta/0071_snapshot.json b/apps/dokploy/drizzle/meta/0071_snapshot.json
index 4214343a0..cce94ce93 100644
--- a/apps/dokploy/drizzle/meta/0071_snapshot.json
+++ b/apps/dokploy/drizzle/meta/0071_snapshot.json
@@ -1018,6 +1018,12 @@
"notNull": true,
"default": "ARRAY[]::text[]"
},
+ "two_factor_enabled": {
+ "name": "two_factor_enabled",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false
+ },
"email": {
"name": "email",
"type": "text",
@@ -5205,6 +5211,57 @@
"checkConstraints": {},
"isRLSEnabled": false
},
+ "public.two_factor": {
+ "name": "two_factor",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "secret": {
+ "name": "secret",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "backup_codes": {
+ "name": "backup_codes",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "two_factor_user_id_user_temp_id_fk": {
+ "name": "two_factor_user_id_user_temp_id_fk",
+ "tableFrom": "two_factor",
+ "tableTo": "user_temp",
+ "columnsFrom": [
+ "user_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
"public.verification": {
"name": "verification",
"schema": "",
diff --git a/apps/dokploy/drizzle/meta/0072_snapshot.json b/apps/dokploy/drizzle/meta/0072_snapshot.json
index 2f38d98d9..53797c0b9 100644
--- a/apps/dokploy/drizzle/meta/0072_snapshot.json
+++ b/apps/dokploy/drizzle/meta/0072_snapshot.json
@@ -1018,6 +1018,12 @@
"notNull": true,
"default": "ARRAY[]::text[]"
},
+ "two_factor_enabled": {
+ "name": "two_factor_enabled",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false
+ },
"email": {
"name": "email",
"type": "text",
@@ -5053,6 +5059,57 @@
"checkConstraints": {},
"isRLSEnabled": false
},
+ "public.two_factor": {
+ "name": "two_factor",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "secret": {
+ "name": "secret",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "backup_codes": {
+ "name": "backup_codes",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "two_factor_user_id_user_temp_id_fk": {
+ "name": "two_factor_user_id_user_temp_id_fk",
+ "tableFrom": "two_factor",
+ "tableTo": "user_temp",
+ "columnsFrom": [
+ "user_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
"public.verification": {
"name": "verification",
"schema": "",
diff --git a/apps/dokploy/drizzle/meta/0073_snapshot.json b/apps/dokploy/drizzle/meta/0073_snapshot.json
index e61b447ca..6b65df2f7 100644
--- a/apps/dokploy/drizzle/meta/0073_snapshot.json
+++ b/apps/dokploy/drizzle/meta/0073_snapshot.json
@@ -1,5 +1,5 @@
{
- "id": "07170d9f-4d67-48f5-890f-393043396973",
+ "id": "e357a19a-dd1e-4843-b567-0c0243ade7a8",
"prevId": "4eb71c0e-5bdb-427b-b198-39b1059dcd16",
"version": "7",
"dialect": "postgresql",
@@ -858,6 +858,12 @@
"notNull": true,
"default": "ARRAY[]::text[]"
},
+ "two_factor_enabled": {
+ "name": "two_factor_enabled",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false
+ },
"email": {
"name": "email",
"type": "text",
@@ -4602,6 +4608,57 @@
"checkConstraints": {},
"isRLSEnabled": false
},
+ "public.two_factor": {
+ "name": "two_factor",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "secret": {
+ "name": "secret",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "backup_codes": {
+ "name": "backup_codes",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "two_factor_user_id_user_temp_id_fk": {
+ "name": "two_factor_user_id_user_temp_id_fk",
+ "tableFrom": "two_factor",
+ "tableTo": "user_temp",
+ "columnsFrom": [
+ "user_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
"public.verification": {
"name": "verification",
"schema": "",
diff --git a/apps/dokploy/drizzle/meta/_journal.json b/apps/dokploy/drizzle/meta/_journal.json
index b591cceda..39903f65a 100644
--- a/apps/dokploy/drizzle/meta/_journal.json
+++ b/apps/dokploy/drizzle/meta/_journal.json
@@ -516,8 +516,8 @@
{
"idx": 73,
"version": "7",
- "when": 1739735739336,
- "tag": "0073_brave_wolfpack",
+ "when": 1739740193879,
+ "tag": "0073_polite_miss_america",
"breakpoints": true
}
]
diff --git a/apps/dokploy/pages/dashboard/docker.tsx b/apps/dokploy/pages/dashboard/docker.tsx
index 202935aa6..fee202fce 100644
--- a/apps/dokploy/pages/dashboard/docker.tsx
+++ b/apps/dokploy/pages/dashboard/docker.tsx
@@ -54,7 +54,7 @@ export async function getServerSideProps(
await helpers.project.all.prefetch();
if (user.role === "member") {
- const userR = await helpers.user.get.fetch({
+ const userR = await helpers.user.one.fetch({
userId: user.id,
});
diff --git a/apps/dokploy/pages/dashboard/settings/git-providers.tsx b/apps/dokploy/pages/dashboard/settings/git-providers.tsx
index d0d9ca7f1..cfded9915 100644
--- a/apps/dokploy/pages/dashboard/settings/git-providers.tsx
+++ b/apps/dokploy/pages/dashboard/settings/git-providers.tsx
@@ -50,7 +50,7 @@ export async function getServerSideProps(
await helpers.project.all.prefetch();
await helpers.settings.isCloud.prefetch();
if (user.role === "member") {
- const userR = await helpers.user.get.fetch({
+ const userR = await helpers.user.one.fetch({
userId: user.id,
});
diff --git a/apps/dokploy/pages/dashboard/settings/profile.tsx b/apps/dokploy/pages/dashboard/settings/profile.tsx
index bfae14e62..a84fb4dba 100644
--- a/apps/dokploy/pages/dashboard/settings/profile.tsx
+++ b/apps/dokploy/pages/dashboard/settings/profile.tsx
@@ -57,7 +57,7 @@ export async function getServerSideProps(
await helpers.settings.isCloud.prefetch();
await helpers.auth.get.prefetch();
if (user?.role === "member") {
- // const userR = await helpers.user.get.fetch({
+ // const userR = await helpers.user.one.fetch({
// userId: user.id,
// });
// await helpers.user.byAuthId.prefetch({
diff --git a/apps/dokploy/pages/dashboard/settings/ssh-keys.tsx b/apps/dokploy/pages/dashboard/settings/ssh-keys.tsx
index f3b9cf1b8..c97df7ba1 100644
--- a/apps/dokploy/pages/dashboard/settings/ssh-keys.tsx
+++ b/apps/dokploy/pages/dashboard/settings/ssh-keys.tsx
@@ -51,7 +51,7 @@ export async function getServerSideProps(
await helpers.settings.isCloud.prefetch();
if (user.role === "member") {
- const userR = await helpers.user.get.fetch({
+ const userR = await helpers.user.one.fetch({
userId: user.id,
});
diff --git a/apps/dokploy/pages/dashboard/swarm.tsx b/apps/dokploy/pages/dashboard/swarm.tsx
index 8278ed181..3b59c47b0 100644
--- a/apps/dokploy/pages/dashboard/swarm.tsx
+++ b/apps/dokploy/pages/dashboard/swarm.tsx
@@ -54,7 +54,7 @@ export async function getServerSideProps(
await helpers.project.all.prefetch();
if (user.role === "member") {
- const userR = await helpers.user.get.fetch({
+ const userR = await helpers.user.one.fetch({
userId: user.id,
});
diff --git a/apps/dokploy/pages/dashboard/traefik.tsx b/apps/dokploy/pages/dashboard/traefik.tsx
index 6939eabdf..8dcd3f084 100644
--- a/apps/dokploy/pages/dashboard/traefik.tsx
+++ b/apps/dokploy/pages/dashboard/traefik.tsx
@@ -54,7 +54,7 @@ export async function getServerSideProps(
await helpers.project.all.prefetch();
if (user.role === "member") {
- const userR = await helpers.user.get.fetch({
+ const userR = await helpers.user.one.fetch({
userId: user.id,
});
diff --git a/apps/dokploy/pages/swagger.tsx b/apps/dokploy/pages/swagger.tsx
index 765194f1c..e4a6fac8d 100644
--- a/apps/dokploy/pages/swagger.tsx
+++ b/apps/dokploy/pages/swagger.tsx
@@ -38,7 +38,7 @@ const Home: NextPage = () => {
export default Home;
export async function getServerSideProps(context: GetServerSidePropsContext) {
const { req, res } = context;
- const { user, session } = await validateRequest(context.req, context.res);
+ const { user, session } = await validateRequest(context.req);
if (!user) {
return {
redirect: {
@@ -53,17 +53,17 @@ export async function getServerSideProps(context: GetServerSidePropsContext) {
req: req as any,
res: res as any,
db: null as any,
- session: session,
- user: user,
+ session: session as any,
+ user: user as any,
},
transformer: superjson,
});
if (user.role === "member") {
- const result = await helpers.user.byAuthId.fetch({
- authId: user.id,
+ const userR = await helpers.user.one.fetch({
+ userId: user.id,
});
- if (!result.canAccessToAPI) {
+ if (!userR.canAccessToAPI) {
return {
redirect: {
permanent: true,
diff --git a/apps/dokploy/server/api/routers/admin.ts b/apps/dokploy/server/api/routers/admin.ts
index 695cdb336..97e3a1fa4 100644
--- a/apps/dokploy/server/api/routers/admin.ts
+++ b/apps/dokploy/server/api/routers/admin.ts
@@ -35,17 +35,22 @@ export const adminRouter = createTRPCRouter({
...rest,
};
}),
- update: adminProcedure.mutation(async ({ input, ctx }) => {
- if (ctx.user.rol === "member") {
- throw new TRPCError({
- code: "UNAUTHORIZED",
- message: "You are not allowed to update this admin",
- });
- }
- const { id } = await findUserById(ctx.user.id);
- // @ts-ignore
- return updateAdmin(id, input);
- }),
+ update: adminProcedure
+ .input(
+ z.object({
+ enableDockerCleanup: z.boolean(),
+ }),
+ )
+ .mutation(async ({ input, ctx }) => {
+ if (ctx.user.rol === "member") {
+ throw new TRPCError({
+ code: "UNAUTHORIZED",
+ message: "You are not allowed to update this admin",
+ });
+ }
+ const user = await findUserById(ctx.user.ownerId);
+ return updateUser(user.id, {});
+ }),
createUserInvitation: adminProcedure
.input(apiCreateUserInvitation)
.mutation(async ({ input, ctx }) => {
diff --git a/apps/dokploy/server/api/routers/auth.ts b/apps/dokploy/server/api/routers/auth.ts
index ad2fab07e..4cfbe71a2 100644
--- a/apps/dokploy/server/api/routers/auth.ts
+++ b/apps/dokploy/server/api/routers/auth.ts
@@ -266,10 +266,13 @@ export const authRouter = createTRPCRouter({
verifyToken: protectedProcedure.mutation(async () => {
return true;
}),
- one: adminProcedure.query(async ({ input }) => {
- const auth = await findAuthById(input.id);
- return auth;
- }),
+ one: adminProcedure
+ .input(z.object({ userId: z.string().min(1) }))
+ .query(async ({ input }) => {
+ // TODO: Check if the user is admin or member
+ const user = await findUserById(input.userId);
+ return user;
+ }),
generate2FASecret: protectedProcedure.query(async ({ ctx }) => {
return await generate2FASecret(ctx.user.id);
diff --git a/apps/dokploy/server/api/routers/settings.ts b/apps/dokploy/server/api/routers/settings.ts
index cd1f8bd3b..ee69da22d 100644
--- a/apps/dokploy/server/api/routers/settings.ts
+++ b/apps/dokploy/server/api/routers/settings.ts
@@ -22,9 +22,8 @@ import {
cleanUpUnusedVolumes,
execAsync,
execAsyncRemote,
- findAdmin,
- findAdminById,
findServerById,
+ findUserById,
getDokployImage,
getDokployImageTag,
getUpdateData,
@@ -50,6 +49,7 @@ import {
updateLetsEncryptEmail,
updateServerById,
updateServerTraefik,
+ updateUser,
writeConfig,
writeMainConfig,
writeTraefikConfigInPath,
@@ -163,7 +163,7 @@ export const settingsRouter = createTRPCRouter({
if (IS_CLOUD) {
return true;
}
- await updateAdmin(ctx.user.authId, {
+ await updateUser(ctx.user.id, {
sshPrivateKey: input.sshPrivateKey,
});
@@ -175,7 +175,7 @@ export const settingsRouter = createTRPCRouter({
if (IS_CLOUD) {
return true;
}
- const admin = await updateAdmin(ctx.user.authId, {
+ const user = await updateUser(ctx.user.id, {
host: input.host,
...(input.letsEncryptEmail && {
letsEncryptEmail: input.letsEncryptEmail,
@@ -183,25 +183,25 @@ export const settingsRouter = createTRPCRouter({
certificateType: input.certificateType,
});
- if (!admin) {
+ if (!user) {
throw new TRPCError({
code: "NOT_FOUND",
- message: "Admin not found",
+ message: "User not found",
});
}
- updateServerTraefik(admin, input.host);
+ updateServerTraefik(user, input.host);
if (input.letsEncryptEmail) {
updateLetsEncryptEmail(input.letsEncryptEmail);
}
- return admin;
+ return user;
}),
cleanSSHPrivateKey: adminProcedure.mutation(async ({ ctx }) => {
if (IS_CLOUD) {
return true;
}
- await updateAdmin(ctx.user.authId, {
+ await updateUser(ctx.user.id, {
sshPrivateKey: null,
});
return true;
@@ -216,7 +216,7 @@ export const settingsRouter = createTRPCRouter({
const server = await findServerById(input.serverId);
- if (server.adminId !== ctx.user.adminId) {
+ if (server.organizationId !== ctx.session?.activeOrganizationId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this server",
@@ -245,7 +245,7 @@ export const settingsRouter = createTRPCRouter({
await cleanUpUnusedImages(server.serverId);
await cleanUpDockerBuilder(server.serverId);
await cleanUpSystemPrune(server.serverId);
- await sendDockerCleanupNotifications(server.adminId);
+ await sendDockerCleanupNotifications(server.organizationId);
});
}
} else {
@@ -261,19 +261,11 @@ export const settingsRouter = createTRPCRouter({
}
}
} else if (!IS_CLOUD) {
- const admin = await findAdminById(ctx.user.adminId);
-
- if (admin.adminId !== ctx.user.adminId) {
- throw new TRPCError({
- code: "UNAUTHORIZED",
- message: "You are not authorized to access this admin",
- });
- }
- const adminUpdated = await updateAdmin(ctx.user.authId, {
+ const userUpdated = await updateUser(ctx.user.id, {
enableDockerCleanup: input.enableDockerCleanup,
});
- if (adminUpdated?.enableDockerCleanup) {
+ if (userUpdated?.enableDockerCleanup) {
scheduleJob("docker-cleanup", "0 0 * * *", async () => {
console.log(
`Docker Cleanup ${new Date().toLocaleString()}] Running...`,
@@ -281,7 +273,9 @@ export const settingsRouter = createTRPCRouter({
await cleanUpUnusedImages();
await cleanUpDockerBuilder();
await cleanUpSystemPrune();
- await sendDockerCleanupNotifications(admin.adminId);
+ await sendDockerCleanupNotifications(
+ ctx.session.activeOrganizationId,
+ );
});
} else {
const currentJob = scheduledJobs["docker-cleanup"];
@@ -383,7 +377,7 @@ export const settingsRouter = createTRPCRouter({
.query(async ({ ctx, input }) => {
try {
if (ctx.user.rol === "member") {
- const canAccess = await canAccessToTraefikFiles(ctx.user.authId);
+ const canAccess = await canAccessToTraefikFiles(ctx.user.id);
if (!canAccess) {
throw new TRPCError({ code: "UNAUTHORIZED" });
@@ -401,7 +395,7 @@ export const settingsRouter = createTRPCRouter({
.input(apiModifyTraefikConfig)
.mutation(async ({ input, ctx }) => {
if (ctx.user.rol === "member") {
- const canAccess = await canAccessToTraefikFiles(ctx.user.authId);
+ const canAccess = await canAccessToTraefikFiles(ctx.user.id);
if (!canAccess) {
throw new TRPCError({ code: "UNAUTHORIZED" });
@@ -419,7 +413,7 @@ export const settingsRouter = createTRPCRouter({
.input(apiReadTraefikConfig)
.query(async ({ input, ctx }) => {
if (ctx.user.rol === "member") {
- const canAccess = await canAccessToTraefikFiles(ctx.user.authId);
+ const canAccess = await canAccessToTraefikFiles(ctx.user.id);
if (!canAccess) {
throw new TRPCError({ code: "UNAUTHORIZED" });
@@ -427,12 +421,12 @@ export const settingsRouter = createTRPCRouter({
}
return readConfigInPath(input.path, input.serverId);
}),
- getIp: protectedProcedure.query(async () => {
+ getIp: protectedProcedure.query(async ({ ctx }) => {
if (IS_CLOUD) {
return true;
}
- const admin = await findAdmin();
- return admin.serverIp;
+ const user = await findUserById(ctx.user.ownerId);
+ return user.serverIp;
}),
getOpenApiDocument: protectedProcedure.query(
diff --git a/apps/dokploy/server/api/routers/user.ts b/apps/dokploy/server/api/routers/user.ts
index f4de4d9f7..addbdb23c 100644
--- a/apps/dokploy/server/api/routers/user.ts
+++ b/apps/dokploy/server/api/routers/user.ts
@@ -1,7 +1,12 @@
import { apiFindOneUser, apiFindOneUserByAuth } from "@/server/db/schema";
-import { findUserByAuthId, findUserById } from "@dokploy/server";
+import {
+ findUserByAuthId,
+ findUserById,
+ updateUser,
+ verify2FA,
+} from "@dokploy/server";
import { db } from "@dokploy/server/db";
-import { member } from "@dokploy/server/db/schema";
+import { apiUpdateUser, member } from "@dokploy/server/db/schema";
import { TRPCError } from "@trpc/server";
import { eq } from "drizzle-orm";
import { z } from "zod";
@@ -15,7 +20,7 @@ export const userRouter = createTRPCRouter({
},
});
}),
- get: protectedProcedure
+ one: protectedProcedure
.input(
z.object({
userId: z.string(),
@@ -31,16 +36,27 @@ export const userRouter = createTRPCRouter({
// }
return user;
}),
- // byUserId: protectedProcedure
- // .input(apiFindOneUser)
- // .query(async ({ input, ctx }) => {
- // const user = await findUserById(input.userId);
- // if (user.adminId !== ctx.user.adminId) {
- // throw new TRPCError({
- // code: "UNAUTHORIZED",
- // message: "You are not allowed to access this user",
- // });
- // }
- // return user;
- // }),
+ get: protectedProcedure.query(async ({ ctx }) => {
+ return await findUserById(ctx.user.id);
+ }),
+ update: protectedProcedure
+ .input(apiUpdateUser)
+ .mutation(async ({ input, ctx }) => {
+ return await updateUser(ctx.user.id, input);
+ }),
+ verify2FASetup: protectedProcedure
+ .input(
+ z.object({
+ secret: z.string(),
+ pin: z.string(),
+ }),
+ )
+ .mutation(async ({ ctx, input }) => {
+ const user = await findUserById(ctx.user.id);
+ await verify2FA(user, input.secret, input.pin);
+ await updateUser(user.id, {
+ secret: input.secret,
+ });
+ return user;
+ }),
});
diff --git a/packages/server/auth-schema.ts b/packages/server/auth-schema.ts
index 38839afbf..045a75235 100644
--- a/packages/server/auth-schema.ts
+++ b/packages/server/auth-schema.ts
@@ -1,9 +1,9 @@
import {
- boolean,
- integer,
pgTable,
text,
+ integer,
timestamp,
+ boolean,
} from "drizzle-orm/pg-core";
export const users_temp = pgTable("users_temp", {
@@ -14,6 +14,7 @@ export const users_temp = pgTable("users_temp", {
image: text("image"),
createdAt: timestamp("created_at").notNull(),
updatedAt: timestamp("updated_at").notNull(),
+ twoFactorEnabled: boolean("two_factor_enabled"),
role: text("role").notNull(),
ownerId: text("owner_id").notNull(),
});
@@ -59,6 +60,15 @@ export const verification = pgTable("verification", {
updatedAt: timestamp("updated_at"),
});
+export const twoFactor = pgTable("two_factor", {
+ id: text("id").primaryKey(),
+ secret: text("secret").notNull(),
+ backupCodes: text("backup_codes").notNull(),
+ userId: text("user_id")
+ .notNull()
+ .references(() => users_temp.id, { onDelete: "cascade" }),
+});
+
export const organization = pgTable("organization", {
id: text("id").primaryKey(),
name: text("name").notNull(),
diff --git a/packages/server/src/db/schema/account.ts b/packages/server/src/db/schema/account.ts
index 3bb7dcfca..1c0b10e9a 100644
--- a/packages/server/src/db/schema/account.ts
+++ b/packages/server/src/db/schema/account.ts
@@ -119,3 +119,12 @@ export const invitationRelations = relations(invitation, ({ one }) => ({
references: [organization.id],
}),
}));
+
+export const twoFactor = pgTable("two_factor", {
+ id: text("id").primaryKey(),
+ secret: text("secret").notNull(),
+ backupCodes: text("backup_codes").notNull(),
+ userId: text("user_id")
+ .notNull()
+ .references(() => users_temp.id, { onDelete: "cascade" }),
+});
diff --git a/packages/server/src/db/schema/user.ts b/packages/server/src/db/schema/user.ts
index 33e9e4fcd..a8f4cbcf0 100644
--- a/packages/server/src/db/schema/user.ts
+++ b/packages/server/src/db/schema/user.ts
@@ -59,10 +59,12 @@ export const users_temp = pgTable("user_temp", {
.array()
.notNull()
.default(sql`ARRAY[]::text[]`),
+
// authId: text("authId")
// .notNull()
// .references(() => auth.id, { onDelete: "cascade" }),
// Auth
+ twoFactorEnabled: boolean("two_factor_enabled"),
email: text("email").notNull().unique(),
emailVerified: boolean("email_verified").notNull(),
image: text("image"),
@@ -151,10 +153,8 @@ export const usersRelations = relations(users_temp, ({ one, many }) => ({
const createSchema = createInsertSchema(users_temp, {
id: z.string().min(1),
- // authId: z.string().min(1),
token: z.string().min(1),
isRegistered: z.boolean().optional(),
- // adminId: z.string(),
accessedProjects: z.array(z.string()).optional(),
accessedServices: z.array(z.string()).optional(),
canCreateProjects: z.boolean().optional(),
@@ -297,3 +297,30 @@ export const apiUpdateWebServerMonitoring = z.object({
})
.required(),
});
+
+export const apiUpdateUser = createSchema.partial().extend({
+ metricsConfig: z
+ .object({
+ server: z.object({
+ type: z.enum(["Dokploy", "Remote"]),
+ refreshRate: z.number(),
+ port: z.number(),
+ token: z.string(),
+ urlCallback: z.string(),
+ retentionDays: z.number(),
+ cronJob: z.string(),
+ thresholds: z.object({
+ cpu: z.number(),
+ memory: z.number(),
+ }),
+ }),
+ containers: z.object({
+ refreshRate: z.number(),
+ services: z.object({
+ include: z.array(z.string()),
+ exclude: z.array(z.string()),
+ }),
+ }),
+ })
+ .optional(),
+});
diff --git a/packages/server/src/lib/auth.ts b/packages/server/src/lib/auth.ts
index a7fbde9a5..fece335b2 100644
--- a/packages/server/src/lib/auth.ts
+++ b/packages/server/src/lib/auth.ts
@@ -2,7 +2,11 @@ import type { IncomingMessage } from "node:http";
import * as bcrypt from "bcrypt";
import { betterAuth } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle";
-import { createAuthMiddleware, organization } from "better-auth/plugins";
+import {
+ createAuthMiddleware,
+ organization,
+ twoFactor,
+} from "better-auth/plugins";
import { desc, eq } from "drizzle-orm";
import { db } from "../db";
import * as schema from "../db/schema";
@@ -85,6 +89,7 @@ export const auth = betterAuth({
},
plugins: [
+ twoFactor(),
organization({
async sendInvitationEmail(data, request) {
const inviteLink = `https://example.com/accept-invitation/${data.id}`;
diff --git a/packages/server/src/services/admin.ts b/packages/server/src/services/admin.ts
index 4e1b1bb33..53de805e9 100644
--- a/packages/server/src/services/admin.ts
+++ b/packages/server/src/services/admin.ts
@@ -12,41 +12,40 @@ import * as bcrypt from "bcrypt";
import { eq } from "drizzle-orm";
import { IS_CLOUD } from "../constants";
-export type Admin = typeof users_temp.$inferSelect;
+export type User = typeof users_temp.$inferSelect;
export const createInvitation = async (
input: typeof apiCreateUserInvitation._type,
adminId: string,
) => {
- await db.transaction(async (tx) => {
- const result = await tx
- .insert(auth)
- .values({
- email: input.email.toLowerCase(),
- rol: "user",
- password: bcrypt.hashSync("01231203012312", 10),
- })
- .returning()
- .then((res) => res[0]);
-
- if (!result) {
- throw new TRPCError({
- code: "BAD_REQUEST",
- message: "Error creating the user",
- });
- }
- const expiresIn24Hours = new Date();
- expiresIn24Hours.setDate(expiresIn24Hours.getDate() + 1);
- const token = randomBytes(32).toString("hex");
- // await tx
- // .insert(users)
- // .values({
- // adminId: adminId,
- // authId: result.id,
- // token,
- // expirationDate: expiresIn24Hours.toISOString(),
- // })
- // .returning();
- });
+ // await db.transaction(async (tx) => {
+ // const result = await tx
+ // .insert(auth)
+ // .values({
+ // email: input.email.toLowerCase(),
+ // rol: "user",
+ // password: bcrypt.hashSync("01231203012312", 10),
+ // })
+ // .returning()
+ // .then((res) => res[0]);
+ // if (!result) {
+ // throw new TRPCError({
+ // code: "BAD_REQUEST",
+ // message: "Error creating the user",
+ // });
+ // }
+ // const expiresIn24Hours = new Date();
+ // expiresIn24Hours.setDate(expiresIn24Hours.getDate() + 1);
+ // const token = randomBytes(32).toString("hex");
+ // await tx
+ // .insert(users)
+ // .values({
+ // adminId: adminId,
+ // authId: result.id,
+ // token,
+ // expirationDate: expiresIn24Hours.toISOString(),
+ // })
+ // .returning();
+ // });
};
export const findUserById = async (userId: string) => {
@@ -65,7 +64,7 @@ export const findUserById = async (userId: string) => {
return user;
};
-export const updateUser = async (userId: string, userData: Partial) => {
+export const updateUser = async (userId: string, userData: Partial) => {
const user = await db
.update(users_temp)
.set({
@@ -80,7 +79,7 @@ export const updateUser = async (userId: string, userData: Partial) => {
export const updateAdminById = async (
adminId: string,
- adminData: Partial,
+ adminData: Partial,
) => {
// const admin = await db
// .update(admins)
@@ -93,13 +92,6 @@ export const updateAdminById = async (
// return admin;
};
-export const findAdminById = async (userId: string) => {
- const admin = await db.query.admins.findFirst({
- // where: eq(admins.userId, userId),
- });
- return admin;
-};
-
export const isAdminPresent = async () => {
const admin = await db.query.member.findFirst({
where: eq(member.role, "owner"),
@@ -113,33 +105,6 @@ export const isAdminPresent = async () => {
return true;
};
-export const findAdminByAuthId = async (authId: string) => {
- const admin = await db.query.admins.findFirst({
- where: eq(admins.authId, authId),
- with: {
- users: true,
- },
- });
- if (!admin) {
- throw new TRPCError({
- code: "NOT_FOUND",
- message: "Admin not found",
- });
- }
- return admin;
-};
-
-export const findAdmin = async () => {
- const admin = await db.query.admins.findFirst({});
- if (!admin) {
- throw new TRPCError({
- code: "NOT_FOUND",
- message: "Admin not found",
- });
- }
- return admin;
-};
-
export const getUserByToken = async (token: string) => {
// const user = await db.query.users.findFirst({
// where: eq(users.token, token),
@@ -171,24 +136,6 @@ export const removeUserById = async (userId: string) => {
.then((res) => res[0]);
};
-export const removeAdminByAuthId = async (authId: string) => {
- const admin = await findAdminByAuthId(authId);
- if (!admin) return null;
-
- // First delete all associated users
- const users = admin.users;
-
- // for (const user of users) {
- // await removeUserById(user.id);
- // }
- // Then delete the auth record which will cascade delete the admin
- return await db
- .delete(auth)
- .where(eq(auth.id, authId))
- .returning()
- .then((res) => res[0]);
-};
-
export const getDokployUrl = async () => {
if (IS_CLOUD) {
return "https://app.dokploy.com";
diff --git a/packages/server/src/services/auth.ts b/packages/server/src/services/auth.ts
index dbdf538b8..8f3564be9 100644
--- a/packages/server/src/services/auth.ts
+++ b/packages/server/src/services/auth.ts
@@ -10,6 +10,7 @@ import { TOTP } from "otpauth";
import QRCode from "qrcode";
import { IS_CLOUD } from "../constants";
import { findUserById } from "./admin";
+import type { User } from "./user";
export const findAuthById = async (authId: string) => {
const result = await db.query.users_temp.findFirst({
@@ -51,11 +52,7 @@ export const generate2FASecret = async (userId: string) => {
};
};
-export const verify2FA = async (
- auth: Omit,
- secret: string,
- pin: string,
-) => {
+export const verify2FA = async (auth: User, secret: string, pin: string) => {
const totp = new TOTP({
issuer: "Dokploy",
label: `${auth?.email}`,
diff --git a/packages/server/src/utils/backups/index.ts b/packages/server/src/utils/backups/index.ts
index 922232a0c..d1b87d692 100644
--- a/packages/server/src/utils/backups/index.ts
+++ b/packages/server/src/utils/backups/index.ts
@@ -1,4 +1,3 @@
-import { findAdmin } from "@dokploy/server/services/admin";
import { getAllServers } from "@dokploy/server/services/server";
import { scheduleJob } from "node-schedule";
import { db } from "../../db/index";
diff --git a/packages/server/src/utils/traefik/web-server.ts b/packages/server/src/utils/traefik/web-server.ts
index 76733e751..78046c673 100644
--- a/packages/server/src/utils/traefik/web-server.ts
+++ b/packages/server/src/utils/traefik/web-server.ts
@@ -1,11 +1,11 @@
import { existsSync, readFileSync, writeFileSync } from "node:fs";
import { join } from "node:path";
import { paths } from "@dokploy/server/constants";
+import type { User } from "@dokploy/server/services/user";
import { dump, load } from "js-yaml";
import { loadOrCreateConfig, writeTraefikConfig } from "./application";
import type { FileConfig } from "./file-types";
import type { MainTraefikConfig } from "./types";
-import type { User } from "@dokploy/server/services/user";
export const updateServerTraefik = (
user: User | null,