mirror of
https://github.com/Dokploy/dokploy
synced 2025-06-26 18:27:59 +00:00
refactor: add 2fa
This commit is contained in:
parent
e1632cbdb3
commit
0e8e92c715
@ -78,7 +78,9 @@ export const ShowUsers = () => {
|
|||||||
<TableHead className="w-[100px]">Email</TableHead>
|
<TableHead className="w-[100px]">Email</TableHead>
|
||||||
<TableHead className="text-center">Role</TableHead>
|
<TableHead className="text-center">Role</TableHead>
|
||||||
<TableHead className="text-center">2FA</TableHead>
|
<TableHead className="text-center">2FA</TableHead>
|
||||||
{/* <TableHead className="text-center">Status</TableHead> */}
|
<TableHead className="text-center">
|
||||||
|
Is Registered
|
||||||
|
</TableHead>
|
||||||
<TableHead className="text-center">
|
<TableHead className="text-center">
|
||||||
Created At
|
Created At
|
||||||
</TableHead>
|
</TableHead>
|
||||||
@ -104,15 +106,15 @@ export const ShowUsers = () => {
|
|||||||
</Badge>
|
</Badge>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell className="text-center">
|
<TableCell className="text-center">
|
||||||
{/* {user.user.is2FAEnabled
|
{user.user.twoFactorEnabled
|
||||||
? "2FA Enabled"
|
? "Enabled"
|
||||||
: "2FA Not Enabled"} */}
|
: "Disabled"}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className="text-center">
|
||||||
|
{user.user.isRegistered || user.role === "owner"
|
||||||
|
? "Registered"
|
||||||
|
: "Not Registered"}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
{/* <TableCell className="text-right">
|
|
||||||
<span className="text-sm text-muted-foreground">
|
|
||||||
{format(new Date(user.createdAt), "PPpp")}
|
|
||||||
</span>
|
|
||||||
</TableCell> */}
|
|
||||||
<TableCell className="text-right">
|
<TableCell className="text-right">
|
||||||
<span className="text-sm text-muted-foreground">
|
<span className="text-sm text-muted-foreground">
|
||||||
{format(new Date(user.createdAt), "PPpp")}
|
{format(new Date(user.createdAt), "PPpp")}
|
||||||
@ -134,29 +136,30 @@ export const ShowUsers = () => {
|
|||||||
<DropdownMenuLabel>
|
<DropdownMenuLabel>
|
||||||
Actions
|
Actions
|
||||||
</DropdownMenuLabel>
|
</DropdownMenuLabel>
|
||||||
{/* {!user.isRegistered && (
|
{!user.user.isRegistered &&
|
||||||
<DropdownMenuItem
|
user.role !== "owner" && (
|
||||||
className="w-full cursor-pointer"
|
<DropdownMenuItem
|
||||||
onSelect={(e) => {
|
className="w-full cursor-pointer"
|
||||||
copy(
|
onSelect={(e) => {
|
||||||
`${origin}/invitation?token=${user.token}`,
|
copy(
|
||||||
);
|
`${origin}/invitation?token=${user.user.token}`,
|
||||||
toast.success(
|
);
|
||||||
"Invitation Copied to clipboard",
|
toast.success(
|
||||||
);
|
"Invitation Copied to clipboard",
|
||||||
}}
|
);
|
||||||
>
|
}}
|
||||||
Copy Invitation
|
>
|
||||||
</DropdownMenuItem>
|
Copy Invitation
|
||||||
)} */}
|
</DropdownMenuItem>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* {user.isRegistered && (
|
{user.user.isRegistered && (
|
||||||
<AddUserPermissions
|
<AddUserPermissions
|
||||||
userId={user.userId}
|
userId={user.userId}
|
||||||
/>
|
/>
|
||||||
)} */}
|
)}
|
||||||
|
|
||||||
{/* {user.role !== "owner" && (
|
{user.role !== "owner" && (
|
||||||
<DialogAction
|
<DialogAction
|
||||||
title="Delete User"
|
title="Delete User"
|
||||||
description="Are you sure you want to delete this user?"
|
description="Are you sure you want to delete this user?"
|
||||||
@ -185,7 +188,7 @@ export const ShowUsers = () => {
|
|||||||
Delete User
|
Delete User
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
</DialogAction>
|
</DialogAction>
|
||||||
)} */}
|
)}
|
||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
|
@ -25,7 +25,8 @@ WITH inserted_users AS (
|
|||||||
"stripeSubscriptionId",
|
"stripeSubscriptionId",
|
||||||
"serversQuantity",
|
"serversQuantity",
|
||||||
"expirationDate",
|
"expirationDate",
|
||||||
"createdAt"
|
"createdAt",
|
||||||
|
"two_factor_enabled"
|
||||||
)
|
)
|
||||||
SELECT
|
SELECT
|
||||||
a."adminId",
|
a."adminId",
|
||||||
@ -50,11 +51,30 @@ WITH inserted_users AS (
|
|||||||
a."stripeSubscriptionId",
|
a."stripeSubscriptionId",
|
||||||
a."serversQuantity",
|
a."serversQuantity",
|
||||||
NOW() + INTERVAL '1 year',
|
NOW() + INTERVAL '1 year',
|
||||||
NOW()
|
NOW(),
|
||||||
|
COALESCE(auth."is2FAEnabled", false)
|
||||||
FROM admin a
|
FROM admin a
|
||||||
JOIN auth ON auth.id = a."authId"
|
JOIN auth ON auth.id = a."authId"
|
||||||
RETURNING *
|
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 (
|
inserted_accounts AS (
|
||||||
-- Insertar cuentas para los admins
|
-- Insertar cuentas para los admins
|
||||||
INSERT INTO account (
|
INSERT INTO account (
|
||||||
@ -120,7 +140,8 @@ inserted_members AS (
|
|||||||
"canDeleteServices",
|
"canDeleteServices",
|
||||||
"accesedProjects",
|
"accesedProjects",
|
||||||
"accesedServices",
|
"accesedServices",
|
||||||
"expirationDate"
|
"expirationDate",
|
||||||
|
"two_factor_enabled"
|
||||||
)
|
)
|
||||||
SELECT
|
SELECT
|
||||||
u."userId",
|
u."userId",
|
||||||
@ -141,7 +162,8 @@ inserted_members AS (
|
|||||||
COALESCE(u."canDeleteServices", false),
|
COALESCE(u."canDeleteServices", false),
|
||||||
COALESCE(u."accesedProjects", '{}'),
|
COALESCE(u."accesedProjects", '{}'),
|
||||||
COALESCE(u."accesedServices", '{}'),
|
COALESCE(u."accesedServices", '{}'),
|
||||||
NOW() + INTERVAL '1 year'
|
NOW() + INTERVAL '1 year',
|
||||||
|
COALESCE(auth."is2FAEnabled", false)
|
||||||
FROM "user" u
|
FROM "user" u
|
||||||
JOIN admin a ON u."adminId" = a."adminId"
|
JOIN admin a ON u."adminId" = a."adminId"
|
||||||
JOIN auth ON auth.id = u."authId"
|
JOIN auth ON auth.id = u."authId"
|
||||||
@ -173,6 +195,25 @@ inserted_member_accounts AS (
|
|||||||
JOIN auth ON auth.id = u."authId"
|
JOIN auth ON auth.id = u."authId"
|
||||||
RETURNING *
|
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 (
|
inserted_admin_members AS (
|
||||||
-- Insertar miembros en las organizaciones (admins como owners)
|
-- Insertar miembros en las organizaciones (admins como owners)
|
||||||
INSERT INTO member (
|
INSERT INTO member (
|
||||||
|
@ -27,6 +27,7 @@ import { type ReactElement, useEffect } from "react";
|
|||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
import superjson from "superjson";
|
||||||
|
|
||||||
const registerSchema = z
|
const registerSchema = z
|
||||||
.object({
|
.object({
|
||||||
@ -98,9 +99,9 @@ const Invitation = ({ token, invitation, isCloud }: Props) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (data?.auth?.email) {
|
if (data?.email) {
|
||||||
form.reset({
|
form.reset({
|
||||||
email: data?.auth?.email || "",
|
email: data?.email || "",
|
||||||
password: "",
|
password: "",
|
||||||
confirmPassword: "",
|
confirmPassword: "",
|
||||||
});
|
});
|
||||||
@ -109,7 +110,7 @@ const Invitation = ({ token, invitation, isCloud }: Props) => {
|
|||||||
|
|
||||||
const onSubmit = async (values: Register) => {
|
const onSubmit = async (values: Register) => {
|
||||||
await mutateAsync({
|
await mutateAsync({
|
||||||
id: data?.authId,
|
id: data?.id,
|
||||||
password: values.password,
|
password: values.password,
|
||||||
token: token,
|
token: token,
|
||||||
})
|
})
|
||||||
@ -254,6 +255,7 @@ export async function getServerSideProps(ctx: GetServerSidePropsContext) {
|
|||||||
const { query } = ctx;
|
const { query } = ctx;
|
||||||
|
|
||||||
const token = query.token;
|
const token = query.token;
|
||||||
|
console.log("query", query);
|
||||||
|
|
||||||
if (typeof token !== "string") {
|
if (typeof token !== "string") {
|
||||||
return {
|
return {
|
||||||
@ -266,6 +268,7 @@ export async function getServerSideProps(ctx: GetServerSidePropsContext) {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const invitation = await getUserByToken(token);
|
const invitation = await getUserByToken(token);
|
||||||
|
console.log("invitation", invitation);
|
||||||
|
|
||||||
if (invitation.isExpired) {
|
if (invitation.isExpired) {
|
||||||
return {
|
return {
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import {
|
import {
|
||||||
|
boolean,
|
||||||
|
integer,
|
||||||
pgTable,
|
pgTable,
|
||||||
text,
|
text,
|
||||||
integer,
|
|
||||||
timestamp,
|
timestamp,
|
||||||
boolean,
|
|
||||||
} from "drizzle-orm/pg-core";
|
} from "drizzle-orm/pg-core";
|
||||||
|
|
||||||
export const users_temp = pgTable("users_temp", {
|
export const users_temp = pgTable("users_temp", {
|
||||||
|
@ -16,7 +16,16 @@ export const auth = betterAuth({
|
|||||||
provider: "pg",
|
provider: "pg",
|
||||||
schema: schema,
|
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: {
|
emailAndPassword: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
|
||||||
|
@ -106,26 +106,25 @@ export const isAdminPresent = async () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const getUserByToken = async (token: string) => {
|
export const getUserByToken = async (token: string) => {
|
||||||
// const user = await db.query.users.findFirst({
|
const user = await db.query.users_temp.findFirst({
|
||||||
// where: eq(users.token, token),
|
where: eq(users_temp.token, token),
|
||||||
// with: {
|
columns: {
|
||||||
// auth: {
|
id: true,
|
||||||
// columns: {
|
email: true,
|
||||||
// password: false,
|
token: true,
|
||||||
// },
|
isRegistered: true,
|
||||||
// },
|
},
|
||||||
// },
|
});
|
||||||
// });
|
if (!user) {
|
||||||
// if (!user) {
|
throw new TRPCError({
|
||||||
// throw new TRPCError({
|
code: "NOT_FOUND",
|
||||||
// code: "NOT_FOUND",
|
message: "Invitation not found",
|
||||||
// message: "Invitation not found",
|
});
|
||||||
// });
|
}
|
||||||
// }
|
return {
|
||||||
// return {
|
...user,
|
||||||
// ...user,
|
isExpired: user.isRegistered,
|
||||||
// isExpired: user.isRegistered,
|
};
|
||||||
// };
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const removeUserById = async (userId: string) => {
|
export const removeUserById = async (userId: string) => {
|
||||||
|
@ -29,16 +29,15 @@ class LogRotationManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async getStateFromDB(): Promise<boolean> {
|
private async getStateFromDB(): Promise<boolean> {
|
||||||
const setting = await db.query.admins.findFirst({});
|
// const setting = await db.query.admins.findFirst({});
|
||||||
return setting?.enableLogRotation ?? false;
|
// return setting?.enableLogRotation ?? false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async setStateInDB(active: boolean): Promise<void> {
|
private async setStateInDB(active: boolean): Promise<void> {
|
||||||
const admin = await db.query.admins.findFirst({});
|
// const admin = await db.query.admins.findFirst({});
|
||||||
|
// if (!admin) {
|
||||||
if (!admin) {
|
// return;
|
||||||
return;
|
// }
|
||||||
}
|
|
||||||
// await updateAdmin(admin?.authId, {
|
// await updateAdmin(admin?.authId, {
|
||||||
// enableLogRotation: active,
|
// enableLogRotation: active,
|
||||||
// });
|
// });
|
||||||
|
Loading…
Reference in New Issue
Block a user