refactor: update

This commit is contained in:
Mauricio Siu
2025-02-16 13:28:29 -06:00
parent 27736c7c97
commit a8d1471b16
14 changed files with 133 additions and 294 deletions

View File

@@ -20,8 +20,6 @@ import {
findUserById, findUserById,
generate2FASecret, generate2FASecret,
getUserByToken, getUserByToken,
lucia,
luciaToken,
removeAdminByAuthId, removeAdminByAuthId,
sendDiscordNotification, sendDiscordNotification,
sendEmailNotification, sendEmailNotification,
@@ -68,11 +66,11 @@ export const authRouter = createTRPCRouter({
type: "cloud", type: "cloud",
}; };
} }
const session = await lucia.createSession(newAdmin.id || "", {}); // const session = await lucia.createSession(newAdmin.id || "", {});
ctx.res.appendHeader( // ctx.res.appendHeader(
"Set-Cookie", // "Set-Cookie",
lucia.createSessionCookie(session.id).serialize(), // lucia.createSessionCookie(session.id).serialize(),
); // );
return { return {
status: "success", status: "success",
type: "selfhosted", type: "selfhosted",
@@ -91,24 +89,24 @@ export const authRouter = createTRPCRouter({
.mutation(async ({ ctx, input }) => { .mutation(async ({ ctx, input }) => {
try { try {
const token = await getUserByToken(input.token); const token = await getUserByToken(input.token);
if (token.isExpired) { // if (token.isExpired) {
throw new TRPCError({ // throw new TRPCError({
code: "BAD_REQUEST", // code: "BAD_REQUEST",
message: "Invalid token", // message: "Invalid token",
}); // });
} // }
const newUser = await createUser(input); // const newUser = await createUser(input);
if (IS_CLOUD) { // if (IS_CLOUD) {
await sendVerificationEmail(token.authId); // await sendVerificationEmail(token.authId);
return true; // return true;
} // }
const session = await lucia.createSession(newUser?.authId || "", {}); // const session = await lucia.createSession(newUser?.authId || "", {});
ctx.res.appendHeader( // ctx.res.appendHeader(
"Set-Cookie", // "Set-Cookie",
lucia.createSessionCookie(session.id).serialize(), // lucia.createSessionCookie(session.id).serialize(),
); // );
return true; return true;
} catch (error) { } catch (error) {
throw new TRPCError({ throw new TRPCError({
@@ -151,12 +149,12 @@ export const authRouter = createTRPCRouter({
}; };
} }
const session = await lucia.createSession(auth?.id || "", {}); // const session = await lucia.createSession(auth?.id || "", {});
ctx.res.appendHeader( // ctx.res.appendHeader(
"Set-Cookie", // "Set-Cookie",
lucia.createSessionCookie(session.id).serialize(), // lucia.createSessionCookie(session.id).serialize(),
); // );
return { return {
is2FAEnabled: false, is2FAEnabled: false,
authId: auth?.id, authId: auth?.id,
@@ -186,11 +184,11 @@ export const authRouter = createTRPCRouter({
logout: protectedProcedure.mutation(async ({ ctx }) => { logout: protectedProcedure.mutation(async ({ ctx }) => {
const { req, res } = ctx; const { req, res } = ctx;
const { session } = await validateRequest(req, res); const { session } = await validateRequest(req);
if (!session) return false; if (!session) return false;
await lucia.invalidateSession(session.id); // await lucia.invalidateSession(session.id);
res.setHeader("Set-Cookie", lucia.createBlankSessionCookie().serialize()); // res.setHeader("Set-Cookie", lucia.createBlankSessionCookie().serialize());
return true; return true;
}), }),
@@ -211,13 +209,13 @@ export const authRouter = createTRPCRouter({
}); });
} }
} }
const auth = await updateAuthById(ctx.user.authId, { // const auth = await updateAuthById(ctx.user.authId, {
...(input.email && { email: input.email.toLowerCase() }), // ...(input.email && { email: input.email.toLowerCase() }),
...(input.password && { // ...(input.password && {
password: bcrypt.hashSync(input.password, 10), // password: bcrypt.hashSync(input.password, 10),
}), // }),
...(input.image && { image: input.image }), // ...(input.image && { image: input.image }),
}); // });
return auth; return auth;
}), }),
@@ -248,17 +246,17 @@ export const authRouter = createTRPCRouter({
}); });
} }
const { req, res } = ctx; const { req, res } = ctx;
const { session } = await validateRequest(req, res); const { session } = await validateRequest(req);
if (!session) return false; if (!session) return false;
await lucia.invalidateSession(session.id); // await lucia.invalidateSession(session.id);
res.setHeader("Set-Cookie", lucia.createBlankSessionCookie().serialize()); // res.setHeader("Set-Cookie", lucia.createBlankSessionCookie().serialize());
if (ctx.user.rol === "owner") { // if (ctx.user.rol === "owner") {
await removeAdminByAuthId(ctx.user.authId); // await removeAdminByAuthId(ctx.user.authId);
} else { // } else {
await removeUserByAuthId(ctx.user.authId); // await removeUserByAuthId(ctx.user.authId);
} // }
return true; return true;
}), }),
@@ -267,9 +265,9 @@ export const authRouter = createTRPCRouter({
const auth = await findUserById(ctx.user.id); const auth = await findUserById(ctx.user.id);
console.log(auth); console.log(auth);
if (auth.token) { // if (auth.token) {
await luciaToken.invalidateSession(auth.token); // await luciaToken.invalidateSession(auth.token);
} // }
// const session = await luciaToken.createSession(auth?.id || "", { // const session = await luciaToken.createSession(auth?.id || "", {
// expiresIn: 60 * 60 * 24 * 30, // expiresIn: 60 * 60 * 24 * 30,
// }); // });
@@ -292,39 +290,38 @@ export const authRouter = createTRPCRouter({
verify2FASetup: protectedProcedure verify2FASetup: protectedProcedure
.input(apiVerify2FA) .input(apiVerify2FA)
.mutation(async ({ ctx, input }) => { .mutation(async ({ ctx, input }) => {
const auth = await findAuthById(ctx.user.authId); // const auth = await findAuthById(ctx.user.authId);
// await verify2FA(auth, input.secret, input.pin);
await verify2FA(auth, input.secret, input.pin); // await updateAuthById(auth.id, {
await updateAuthById(auth.id, { // is2FAEnabled: true,
is2FAEnabled: true, // secret: input.secret,
secret: input.secret, // });
}); // return auth;
return auth;
}), }),
verifyLogin2FA: publicProcedure verifyLogin2FA: publicProcedure
.input(apiVerifyLogin2FA) .input(apiVerifyLogin2FA)
.mutation(async ({ ctx, input }) => { .mutation(async ({ ctx, input }) => {
const auth = await findAuthById(input.id); // const auth = await findAuthById(input.id);
await verify2FA(auth, auth.secret || "", input.pin); // await verify2FA(auth, auth.secret || "", input.pin);
const session = await lucia.createSession(auth.id, {}); // const session = await lucia.createSession(auth.id, {});
ctx.res.appendHeader( // ctx.res.appendHeader(
"Set-Cookie", // "Set-Cookie",
lucia.createSessionCookie(session.id).serialize(), // lucia.createSessionCookie(session.id).serialize(),
); // );
return true; return true;
}), }),
disable2FA: protectedProcedure.mutation(async ({ ctx }) => { disable2FA: protectedProcedure.mutation(async ({ ctx }) => {
const auth = await findAuthById(ctx.user.authId); // const auth = await findAuthById(ctx.user.authId);
await updateAuthById(auth.id, { // await updateAuthById(auth.id, {
is2FAEnabled: false, // is2FAEnabled: false,
secret: null, // secret: null,
}); // });
return auth; // return auth;
}), }),
sendResetPasswordEmail: publicProcedure sendResetPasswordEmail: publicProcedure
.input( .input(

View File

@@ -1,5 +1,5 @@
import { apiFindOneUser, apiFindOneUserByAuth } from "@/server/db/schema"; import { apiFindOneUser, apiFindOneUserByAuth } from "@/server/db/schema";
import { findUserByAuthId, findUserById, findUsers } from "@dokploy/server"; import { findUserByAuthId, findUserById } from "@dokploy/server";
import { db } from "@dokploy/server/db"; import { db } from "@dokploy/server/db";
import { member } from "@dokploy/server/db/schema"; import { member } from "@dokploy/server/db/schema";
import { TRPCError } from "@trpc/server"; import { TRPCError } from "@trpc/server";
@@ -31,16 +31,16 @@ export const userRouter = createTRPCRouter({
// } // }
return user; return user;
}), }),
byUserId: protectedProcedure // byUserId: protectedProcedure
.input(apiFindOneUser) // .input(apiFindOneUser)
.query(async ({ input, ctx }) => { // .query(async ({ input, ctx }) => {
const user = await findUserById(input.userId); // const user = await findUserById(input.userId);
if (user.adminId !== ctx.user.adminId) { // if (user.adminId !== ctx.user.adminId) {
throw new TRPCError({ // throw new TRPCError({
code: "UNAUTHORIZED", // code: "UNAUTHORIZED",
message: "You are not allowed to access this user", // message: "You are not allowed to access this user",
}); // });
} // }
return user; // return user;
}), // }),
}); });

View File

@@ -75,8 +75,8 @@ export const createTRPCContext = async (opts: CreateNextContextOptions) => {
// user = cookieResult.user; // user = cookieResult.user;
// } // }
console.log("session", session); // console.log("session", session);
console.log("user", user); // console.log("user", user);
return createInnerTRPCContext({ return createInnerTRPCContext({
req, req,

View File

@@ -1,41 +0,0 @@
import { DrizzlePostgreSQLAdapter } from "@lucia-auth/adapter-drizzle";
import { TimeSpan } from "lucia";
import { Lucia } from "lucia/dist/core.js";
import type { Session, User } from "lucia/dist/core.js";
import { db } from "../db";
import { type DatabaseUser, auth, session } from "../db/schema";
export const adapter = new DrizzlePostgreSQLAdapter(db, session, auth);
export const lucia = new Lucia(adapter, {
sessionCookie: {
attributes: {
secure: false,
},
},
sessionExpiresIn: new TimeSpan(1, "d"),
getUserAttributes: (attributes) => {
return {
email: attributes.email,
rol: attributes.rol,
secret: attributes.secret !== null,
adminId: attributes.adminId,
};
},
});
declare module "lucia" {
interface Register {
Lucia: typeof lucia;
DatabaseUserAttributes: Omit<DatabaseUser, "id"> & {
authId: string;
adminId: string;
};
}
}
export type ReturnValidateToken = Promise<{
user: (User & { authId: string; adminId: string }) | null;
session: Session | null;
}>;

View File

@@ -1,99 +0,0 @@
import type { IncomingMessage } from "node:http";
import { TimeSpan } from "lucia";
import { Lucia } from "lucia/dist/core.js";
import { findAdminByAuthId } from "../services/admin";
import { findUserByAuthId } from "../services/user";
import { type ReturnValidateToken, adapter } from "./auth";
export const luciaToken = new Lucia(adapter, {
sessionCookie: {
attributes: {
secure: false,
},
},
sessionExpiresIn: new TimeSpan(365, "d"),
getUserAttributes: (attributes) => {
return {
email: attributes.email,
rol: attributes.rol,
secret: attributes.secret !== null,
};
},
});
// export const validateBearerToken = async (
// req: IncomingMessage,
// ): ReturnValidateToken => {
// const authorizationHeader = req.headers.authorization;
// const sessionId = luciaToken.readBearerToken(authorizationHeader ?? "");
// if (!sessionId) {
// return {
// user: null,
// session: null,
// };
// }
// const result = await luciaToken.validateSession(sessionId);
// if (result.user) {
// if (result.user?.rol === "owner") {
// const admin = await findAdminByAuthId(result.user.id);
// result.user.adminId = admin.adminId;
// } else if (result.user?.rol === "member") {
// const userResult = await findUserByAuthId(result.user.id);
// result.user.adminId = userResult.adminId;
// }
// }
// return {
// session: result.session,
// ...((result.user && {
// user: {
// adminId: result.user.adminId,
// authId: result.user.id,
// email: result.user.email,
// rol: result.user.rol,
// id: result.user.id,
// secret: result.user.secret,
// },
// }) || {
// user: null,
// }),
// };
// };
// export const validateBearerTokenAPI = async (
// authorizationHeader: string,
// ): ReturnValidateToken => {
// const sessionId = luciaToken.readBearerToken(authorizationHeader ?? "");
// if (!sessionId) {
// return {
// user: null,
// session: null,
// };
// }
// const result = await luciaToken.validateSession(sessionId);
// if (result.user) {
// if (result.user?.rol === "owner") {
// const admin = await findAdminByAuthId(result.user.id);
// result.user.adminId = admin.adminId;
// } else if (result.user?.rol === "member") {
// const userResult = await findUserByAuthId(result.user.id);
// result.user.adminId = userResult.adminId;
// }
// }
// return {
// session: result.session,
// ...((result.user && {
// user: {
// adminId: result.user.adminId,
// authId: result.user.id,
// email: result.user.email,
// rol: result.user.rol,
// id: result.user.id,
// secret: result.user.secret,
// },
// }) || {
// user: null,
// }),
// };
// };

View File

@@ -1,5 +1,3 @@
export * from "./auth/auth";
export * from "./auth/token";
export * from "./auth/random-password"; export * from "./auth/random-password";
// export * from "./db"; // export * from "./db";
export * from "./services/admin"; export * from "./services/admin";

View File

@@ -143,27 +143,26 @@ export const findAdmin = 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.findFirst({
where: eq(users.token, token), // where: eq(users.token, token),
with: { // with: {
auth: { // auth: {
columns: { // columns: {
password: false, // password: false,
}, // },
}, // },
}, // },
}); // });
// 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) => {
@@ -181,9 +180,9 @@ export const removeAdminByAuthId = async (authId: string) => {
// First delete all associated users // First delete all associated users
const users = admin.users; const users = admin.users;
for (const user of users) { // for (const user of users) {
await removeUserById(user.id); // await removeUserById(user.id);
} // }
// Then delete the auth record which will cascade delete the admin // Then delete the auth record which will cascade delete the admin
return await db return await db
.delete(auth) .delete(auth)

View File

@@ -33,20 +33,6 @@ export const findUserByAuthId = async (authId: string) => {
// return userR; // return userR;
}; };
export const findUsers = async (adminId: string) => {
const currentUsers = await db.query.user.findMany({
where: eq(user.adminId, adminId),
with: {
auth: {
columns: {
secret: false,
},
},
},
});
return currentUsers;
};
export const addNewProject = async (userId: string, projectId: string) => { export const addNewProject = async (userId: string, projectId: string) => {
const userR = await findUserById(userId); const userR = await findUserById(userId);

View File

@@ -1,5 +1,4 @@
import { IS_CLOUD, paths } from "@dokploy/server/constants"; import { IS_CLOUD, paths } from "@dokploy/server/constants";
import { updateAdmin } from "@dokploy/server/services/admin";
import { type RotatingFileStream, createStream } from "rotating-file-stream"; import { type RotatingFileStream, createStream } from "rotating-file-stream";
import { db } from "../../db"; import { db } from "../../db";
import { execAsync } from "../process/execAsync"; import { execAsync } from "../process/execAsync";
@@ -23,27 +22,27 @@ class LogRotationManager {
} }
private async initialize(): Promise<void> { private async initialize(): Promise<void> {
// const isActive = await this.getStateFromDB(); const isActive = await this.getStateFromDB();
// if (isActive) { if (isActive) {
// await this.activateStream(); await this.activateStream();
// } }
} }
// 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,
// }); // });
// } }
private async activateStream(): Promise<void> { private async activateStream(): Promise<void> {
const { DYNAMIC_TRAEFIK_PATH } = paths(); const { DYNAMIC_TRAEFIK_PATH } = paths();

View File

@@ -49,7 +49,7 @@ export const runMariadbBackup = async (
projectName: project.name, projectName: project.name,
databaseType: "mariadb", databaseType: "mariadb",
type: "success", type: "success",
userId: project.userId, organizationId: project.organizationId,
}); });
} catch (error) { } catch (error) {
console.log(error); console.log(error);
@@ -60,7 +60,7 @@ export const runMariadbBackup = async (
type: "error", type: "error",
// @ts-ignore // @ts-ignore
errorMessage: error?.message || "Error message not provided", errorMessage: error?.message || "Error message not provided",
userId: project.userId, organizationId: project.organizationId,
}); });
throw error; throw error;
} }

View File

@@ -46,7 +46,7 @@ export const runMongoBackup = async (mongo: Mongo, backup: BackupSchedule) => {
projectName: project.name, projectName: project.name,
databaseType: "mongodb", databaseType: "mongodb",
type: "success", type: "success",
userId: project.userId, organizationId: project.organizationId,
}); });
} catch (error) { } catch (error) {
console.log(error); console.log(error);
@@ -57,7 +57,7 @@ export const runMongoBackup = async (mongo: Mongo, backup: BackupSchedule) => {
type: "error", type: "error",
// @ts-ignore // @ts-ignore
errorMessage: error?.message || "Error message not provided", errorMessage: error?.message || "Error message not provided",
userId: project.userId, organizationId: project.organizationId,
}); });
throw error; throw error;
} }

View File

@@ -46,7 +46,7 @@ export const runMySqlBackup = async (mysql: MySql, backup: BackupSchedule) => {
projectName: project.name, projectName: project.name,
databaseType: "mysql", databaseType: "mysql",
type: "success", type: "success",
userId: project.userId, organizationId: project.organizationId,
}); });
} catch (error) { } catch (error) {
console.log(error); console.log(error);
@@ -57,7 +57,7 @@ export const runMySqlBackup = async (mysql: MySql, backup: BackupSchedule) => {
type: "error", type: "error",
// @ts-ignore // @ts-ignore
errorMessage: error?.message || "Error message not provided", errorMessage: error?.message || "Error message not provided",
userId: project.userId, organizationId: project.organizationId,
}); });
throw error; throw error;
} }

View File

@@ -49,7 +49,7 @@ export const runPostgresBackup = async (
projectName: project.name, projectName: project.name,
databaseType: "postgres", databaseType: "postgres",
type: "success", type: "success",
userId: project.userId, organizationId: project.organizationId,
}); });
} catch (error) { } catch (error) {
await sendDatabaseBackupNotifications({ await sendDatabaseBackupNotifications({
@@ -59,7 +59,7 @@ export const runPostgresBackup = async (
type: "error", type: "error",
// @ts-ignore // @ts-ignore
errorMessage: error?.message || "Error message not provided", errorMessage: error?.message || "Error message not provided",
userId: project.userId, organizationId: project.organizationId,
}); });
throw error; throw error;

View File

@@ -19,13 +19,13 @@ export const sendDatabaseBackupNotifications = async ({
databaseType, databaseType,
type, type,
errorMessage, errorMessage,
userId, organizationId,
}: { }: {
projectName: string; projectName: string;
applicationName: string; applicationName: string;
databaseType: "postgres" | "mysql" | "mongodb" | "mariadb"; databaseType: "postgres" | "mysql" | "mongodb" | "mariadb";
type: "error" | "success"; type: "error" | "success";
userId: string; organizationId: string;
errorMessage?: string; errorMessage?: string;
}) => { }) => {
const date = new Date(); const date = new Date();
@@ -33,7 +33,7 @@ export const sendDatabaseBackupNotifications = async ({
const notificationList = await db.query.notifications.findMany({ const notificationList = await db.query.notifications.findMany({
where: and( where: and(
eq(notifications.databaseBackup, true), eq(notifications.databaseBackup, true),
eq(notifications.userId, userId), eq(notifications.organizationId, organizationId),
), ),
with: { with: {
email: true, email: true,