From 0e8e92c71574e2bb8e5609fedcf8a5f8fb8405c6 Mon Sep 17 00:00:00 2001
From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com>
Date: Sun, 16 Feb 2025 20:56:50 -0600
Subject: [PATCH] refactor: add 2fa
---
.../dashboard/settings/users/show-users.tsx | 59 ++++++++++---------
apps/dokploy/drizzle/0067_migrate-data.sql | 49 +++++++++++++--
apps/dokploy/pages/invitation.tsx | 9 ++-
packages/server/auth-schema.ts | 4 +-
packages/server/src/lib/auth.ts | 11 +++-
packages/server/src/services/admin.ts | 39 ++++++------
.../server/src/utils/access-log/handler.ts | 13 ++--
7 files changed, 119 insertions(+), 65 deletions(-)
diff --git a/apps/dokploy/components/dashboard/settings/users/show-users.tsx b/apps/dokploy/components/dashboard/settings/users/show-users.tsx
index e0ffac13..7e3ed6f1 100644
--- a/apps/dokploy/components/dashboard/settings/users/show-users.tsx
+++ b/apps/dokploy/components/dashboard/settings/users/show-users.tsx
@@ -78,7 +78,9 @@ export const ShowUsers = () => {
Email
Role
2FA
- {/* Status */}
+
+ Is Registered
+
Created At
@@ -104,15 +106,15 @@ export const ShowUsers = () => {
- {/* {user.user.is2FAEnabled
- ? "2FA Enabled"
- : "2FA Not Enabled"} */}
+ {user.user.twoFactorEnabled
+ ? "Enabled"
+ : "Disabled"}
+
+
+ {user.user.isRegistered || user.role === "owner"
+ ? "Registered"
+ : "Not Registered"}
- {/*
-
- {format(new Date(user.createdAt), "PPpp")}
-
- */}
{format(new Date(user.createdAt), "PPpp")}
@@ -134,29 +136,30 @@ export const ShowUsers = () => {
Actions
- {/* {!user.isRegistered && (
- {
- copy(
- `${origin}/invitation?token=${user.token}`,
- );
- toast.success(
- "Invitation Copied to clipboard",
- );
- }}
- >
- Copy Invitation
-
- )} */}
+ {!user.user.isRegistered &&
+ user.role !== "owner" && (
+ {
+ copy(
+ `${origin}/invitation?token=${user.user.token}`,
+ );
+ toast.success(
+ "Invitation Copied to clipboard",
+ );
+ }}
+ >
+ Copy Invitation
+
+ )}
- {/* {user.isRegistered && (
+ {user.user.isRegistered && (
- )} */}
+ )}
- {/* {user.role !== "owner" && (
+ {user.role !== "owner" && (
{
Delete User
- )} */}
+ )}
diff --git a/apps/dokploy/drizzle/0067_migrate-data.sql b/apps/dokploy/drizzle/0067_migrate-data.sql
index 074de9fa..4b860a32 100644
--- a/apps/dokploy/drizzle/0067_migrate-data.sql
+++ b/apps/dokploy/drizzle/0067_migrate-data.sql
@@ -25,7 +25,8 @@ WITH inserted_users AS (
"stripeSubscriptionId",
"serversQuantity",
"expirationDate",
- "createdAt"
+ "createdAt",
+ "two_factor_enabled"
)
SELECT
a."adminId",
@@ -50,11 +51,30 @@ WITH inserted_users AS (
a."stripeSubscriptionId",
a."serversQuantity",
NOW() + INTERVAL '1 year',
- NOW()
+ NOW(),
+ COALESCE(auth."is2FAEnabled", false)
FROM admin a
JOIN auth ON auth.id = a."authId"
RETURNING *
),
+inserted_two_factor_admin AS (
+ -- Insertar registros en two_factor para admins con 2FA habilitado
+ INSERT INTO two_factor (
+ id,
+ secret,
+ backup_codes,
+ user_id
+ )
+ SELECT
+ gen_random_uuid(),
+ auth.secret,
+ gen_random_uuid()::text,
+ a."adminId"
+ FROM admin a
+ JOIN auth ON auth.id = a."authId"
+ WHERE auth."is2FAEnabled" = true
+ RETURNING *
+),
inserted_accounts AS (
-- Insertar cuentas para los admins
INSERT INTO account (
@@ -120,7 +140,8 @@ inserted_members AS (
"canDeleteServices",
"accesedProjects",
"accesedServices",
- "expirationDate"
+ "expirationDate",
+ "two_factor_enabled"
)
SELECT
u."userId",
@@ -141,7 +162,8 @@ inserted_members AS (
COALESCE(u."canDeleteServices", false),
COALESCE(u."accesedProjects", '{}'),
COALESCE(u."accesedServices", '{}'),
- NOW() + INTERVAL '1 year'
+ NOW() + INTERVAL '1 year',
+ COALESCE(auth."is2FAEnabled", false)
FROM "user" u
JOIN admin a ON u."adminId" = a."adminId"
JOIN auth ON auth.id = u."authId"
@@ -173,6 +195,25 @@ inserted_member_accounts AS (
JOIN auth ON auth.id = u."authId"
RETURNING *
),
+inserted_two_factor_members AS (
+ -- Insertar registros en two_factor para miembros con 2FA habilitado
+ INSERT INTO two_factor (
+ id,
+ secret,
+ backup_codes,
+ user_id
+ )
+ SELECT
+ gen_random_uuid(),
+ auth.secret,
+ gen_random_uuid()::text,
+ u."userId"
+ FROM "user" u
+ JOIN admin a ON u."adminId" = a."adminId"
+ JOIN auth ON auth.id = u."authId"
+ WHERE auth."is2FAEnabled" = true
+ RETURNING *
+),
inserted_admin_members AS (
-- Insertar miembros en las organizaciones (admins como owners)
INSERT INTO member (
diff --git a/apps/dokploy/pages/invitation.tsx b/apps/dokploy/pages/invitation.tsx
index 77f9f249..e8bfc3fc 100644
--- a/apps/dokploy/pages/invitation.tsx
+++ b/apps/dokploy/pages/invitation.tsx
@@ -27,6 +27,7 @@ import { type ReactElement, useEffect } from "react";
import { useForm } from "react-hook-form";
import { toast } from "sonner";
import { z } from "zod";
+import superjson from "superjson";
const registerSchema = z
.object({
@@ -98,9 +99,9 @@ const Invitation = ({ token, invitation, isCloud }: Props) => {
});
useEffect(() => {
- if (data?.auth?.email) {
+ if (data?.email) {
form.reset({
- email: data?.auth?.email || "",
+ email: data?.email || "",
password: "",
confirmPassword: "",
});
@@ -109,7 +110,7 @@ const Invitation = ({ token, invitation, isCloud }: Props) => {
const onSubmit = async (values: Register) => {
await mutateAsync({
- id: data?.authId,
+ id: data?.id,
password: values.password,
token: token,
})
@@ -254,6 +255,7 @@ export async function getServerSideProps(ctx: GetServerSidePropsContext) {
const { query } = ctx;
const token = query.token;
+ console.log("query", query);
if (typeof token !== "string") {
return {
@@ -266,6 +268,7 @@ export async function getServerSideProps(ctx: GetServerSidePropsContext) {
try {
const invitation = await getUserByToken(token);
+ console.log("invitation", invitation);
if (invitation.isExpired) {
return {
diff --git a/packages/server/auth-schema.ts b/packages/server/auth-schema.ts
index 045a7523..2500b615 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", {
diff --git a/packages/server/src/lib/auth.ts b/packages/server/src/lib/auth.ts
index fece335b..cc144345 100644
--- a/packages/server/src/lib/auth.ts
+++ b/packages/server/src/lib/auth.ts
@@ -16,7 +16,16 @@ export const auth = betterAuth({
provider: "pg",
schema: schema,
}),
-
+ socialProviders: {
+ github: {
+ clientId: process.env.GITHUB_CLIENT_ID as string,
+ clientSecret: process.env.GITHUB_CLIENT_SECRET as string,
+ },
+ google: {
+ clientId: process.env.GOOGLE_CLIENT_ID as string,
+ clientSecret: process.env.GOOGLE_CLIENT_SECRET as string,
+ },
+ },
emailAndPassword: {
enabled: true,
diff --git a/packages/server/src/services/admin.ts b/packages/server/src/services/admin.ts
index 53de805e..eee6bb37 100644
--- a/packages/server/src/services/admin.ts
+++ b/packages/server/src/services/admin.ts
@@ -106,26 +106,25 @@ export const isAdminPresent = async () => {
};
export const getUserByToken = async (token: string) => {
- // const user = await db.query.users.findFirst({
- // where: eq(users.token, token),
- // with: {
- // auth: {
- // columns: {
- // password: false,
- // },
- // },
- // },
- // });
- // if (!user) {
- // throw new TRPCError({
- // code: "NOT_FOUND",
- // message: "Invitation not found",
- // });
- // }
- // return {
- // ...user,
- // isExpired: user.isRegistered,
- // };
+ const user = await db.query.users_temp.findFirst({
+ where: eq(users_temp.token, token),
+ columns: {
+ id: true,
+ email: true,
+ token: true,
+ isRegistered: true,
+ },
+ });
+ if (!user) {
+ throw new TRPCError({
+ code: "NOT_FOUND",
+ message: "Invitation not found",
+ });
+ }
+ return {
+ ...user,
+ isExpired: user.isRegistered,
+ };
};
export const removeUserById = async (userId: string) => {
diff --git a/packages/server/src/utils/access-log/handler.ts b/packages/server/src/utils/access-log/handler.ts
index 57471732..30b18ea4 100644
--- a/packages/server/src/utils/access-log/handler.ts
+++ b/packages/server/src/utils/access-log/handler.ts
@@ -29,16 +29,15 @@ class LogRotationManager {
}
private async getStateFromDB(): Promise {
- const setting = await db.query.admins.findFirst({});
- return setting?.enableLogRotation ?? false;
+ // const setting = await db.query.admins.findFirst({});
+ // return setting?.enableLogRotation ?? false;
}
private async setStateInDB(active: boolean): Promise {
- const admin = await db.query.admins.findFirst({});
-
- if (!admin) {
- return;
- }
+ // const admin = await db.query.admins.findFirst({});
+ // if (!admin) {
+ // return;
+ // }
// await updateAdmin(admin?.authId, {
// enableLogRotation: active,
// });