Browse Source

Merge branch 'main' of https://github.com/fosrl/pangolin

Owen Schwartz 9 tháng trước cách đây
mục cha
commit
a875b65e5b
39 tập tin đã thay đổi với 235 bổ sung168 xóa
  1. 2 2
      package.json
  2. 0 1
      scripts/hydrate.ts
  3. 2 2
      server/auth/2fa.ts
  4. 2 3
      server/auth/actions.ts
  5. 111 40
      server/auth/index.ts
  6. 3 3
      server/auth/verifySession.ts
  7. 16 23
      server/db/schema.ts
  8. 1 1
      server/middlewares/verifySession.ts
  9. 1 1
      server/middlewares/verifyUser.ts
  10. 4 4
      server/routers/auth/changePassword.ts
  11. 3 3
      server/routers/auth/disable2fa.ts
  12. 2 2
      server/routers/auth/getUserOrgs.ts
  13. 11 8
      server/routers/auth/login.ts
  14. 8 7
      server/routers/auth/logout.ts
  15. 1 1
      server/routers/auth/requestEmailVerificationCode.ts
  16. 5 4
      server/routers/auth/requestPasswordReset.ts
  17. 1 1
      server/routers/auth/requestTotpSecret.ts
  18. 5 5
      server/routers/auth/resetPassword.ts
  19. 12 9
      server/routers/auth/signup.ts
  20. 3 3
      server/routers/auth/verifyEmail.ts
  21. 1 1
      server/routers/auth/verifyOrgAccess.ts
  22. 2 2
      server/routers/auth/verifyResourceAccess.ts
  23. 2 2
      server/routers/auth/verifyRoleAccess.ts
  24. 2 2
      server/routers/auth/verifySiteAccess.ts
  25. 4 4
      server/routers/auth/verifySuperuser.ts
  26. 2 2
      server/routers/auth/verifyTargetAccess.ts
  27. 3 3
      server/routers/auth/verifyTotp.ts
  28. 3 3
      server/routers/auth/verifyUserAccess.ts
  29. 2 3
      server/routers/badger/verifyUser.ts
  30. 1 1
      server/routers/resource/createResource.ts
  31. 2 2
      server/routers/resource/listResources.ts
  32. 6 6
      server/routers/site/createSite.ts
  33. 2 2
      server/routers/site/listSites.ts
  34. 2 2
      server/routers/user/addUserAction.ts
  35. 2 2
      server/routers/user/addUserOrg.ts
  36. 2 2
      server/routers/user/getUser.ts
  37. 3 3
      server/routers/user/listUsers.ts
  38. 1 1
      server/types/Auth.ts
  39. 0 2
      src/app/page.tsx

+ 2 - 2
package.json

@@ -16,8 +16,9 @@
     "dependencies": {
         "@esbuild-plugins/tsconfig-paths": "0.1.2",
         "@hookform/resolvers": "3.9.0",
-        "@lucia-auth/adapter-drizzle": "1.1.0",
         "@node-rs/argon2": "1.8.3",
+        "@oslojs/crypto": "1.0.1",
+        "@oslojs/encoding": "1.1.0",
         "@radix-ui/react-checkbox": "1.1.2",
         "@radix-ui/react-dialog": "1.1.2",
         "@radix-ui/react-icons": "1.3.0",
@@ -48,7 +49,6 @@
         "http-errors": "2.0.0",
         "input-otp": "1.2.4",
         "js-yaml": "4.1.0",
-        "lucia": "3.2.0",
         "lucide-react": "0.447.0",
         "moment": "2.30.1",
         "next": "14.2.13",

+ 0 - 1
scripts/hydrate.ts

@@ -1,6 +1,5 @@
 import {
     orgs,
-    users,
     sites,
     resources,
     exitNodes,

+ 2 - 2
server/auth/2fa.ts

@@ -45,14 +45,14 @@ export async function verifyBackUpCode(
             parallelism: 1,
         });
         if (validCode) {
-            validId = hashedCode.id;
+            validId = hashedCode.codeId;
         }
     }
 
     if (validId) {
         await db
             .delete(twoFactorBackupCodes)
-            .where(eq(twoFactorBackupCodes.id, validId));
+            .where(eq(twoFactorBackupCodes.codeId, validId));
     }
 
     return validId ? true : false;

+ 2 - 3
server/auth/actions.ts

@@ -55,8 +55,7 @@ export enum ActionsEnum {
 }
 
 export async function checkUserActionPermission(actionId: string, req: Request): Promise<boolean> {
-    const userId = req.user?.id;
-
+    const userId = req.user?.userId;
     if (!userId) {
         throw createHttpError(HttpCode.UNAUTHORIZED, 'User not authenticated');
     }
@@ -116,4 +115,4 @@ export async function checkUserActionPermission(actionId: string, req: Request):
         console.error('Error checking user action permission:', error);
         throw createHttpError(HttpCode.INTERNAL_SERVER_ERROR, 'Error checking action permission');
     }
-}
+}

+ 111 - 40
server/auth/index.ts

@@ -1,51 +1,122 @@
-export * from "./unauthorizedResponse";
 export * from "./verifySession";
+export * from "./unauthorizedResponse";
 
-import { Lucia, TimeSpan } from "lucia";
-import { DrizzleSQLiteAdapter } from "@lucia-auth/adapter-drizzle";
+import {
+    encodeBase32LowerCaseNoPadding,
+    encodeHexLowerCase,
+} from "@oslojs/encoding";
+import { sha256 } from "@oslojs/crypto/sha2";
+import { Session, sessions, User, users } from "@server/db/schema";
 import db from "@server/db";
-import { sessions, users } from "@server/db/schema";
+import { eq } from "drizzle-orm";
 import config from "@server/config";
+import type { RandomReader } from "@oslojs/crypto/random";
+import { generateRandomString } from "@oslojs/crypto/random";
 
-const adapter = new DrizzleSQLiteAdapter(db, sessions, users);
-
-export const lucia = new Lucia(adapter, {
-    getUserAttributes: (attributes) => {
-        return {
-            email: attributes.email,
-            twoFactorEnabled: attributes.twoFactorEnabled,
-            twoFactorSecret: attributes.twoFactorSecret,
-            emailVerified: attributes.emailVerified,
-            dateCreated: attributes.dateCreated,
-        };
-    },
-    sessionCookie: {
-        name: "session",
-        expires: false,
-        attributes: {
-            sameSite: "strict",
-            secure: config.server.secure_cookies || false,
-            domain:
-                "." + new URL(config.app.base_url).hostname.split(".").slice(-2).join("."),
-        },
-    },
-    sessionExpiresIn: new TimeSpan(2, "w"),
-});
+export const SESSION_COOKIE_NAME = "session";
+export const SESSION_COOKIE_EXPIRES = 1000 * 60 * 60 * 24 * 30;
+export const SECURE_COOKIES = config.server.secure_cookies;
+export const COOKIE_DOMAIN =
+    "." + new URL(config.app.base_url).hostname.split(".").slice(-2).join(".");
+
+export function generateSessionToken(): string {
+    const bytes = new Uint8Array(20);
+    crypto.getRandomValues(bytes);
+    const token = encodeBase32LowerCaseNoPadding(bytes);
+    return token;
+}
+
+export async function createSession(
+    token: string,
+    userId: string,
+): Promise<Session> {
+    const sessionId = encodeHexLowerCase(
+        sha256(new TextEncoder().encode(token)),
+    );
+    const session: Session = {
+        sessionId: sessionId,
+        userId,
+        expiresAt: new Date(Date.now() + SESSION_COOKIE_EXPIRES).getTime(),
+    };
+    await db.insert(sessions).values(session);
+    return session;
+}
+
+export async function validateSessionToken(
+    token: string,
+): Promise<SessionValidationResult> {
+    const sessionId = encodeHexLowerCase(
+        sha256(new TextEncoder().encode(token)),
+    );
+    const result = await db
+        .select({ user: users, session: sessions })
+        .from(sessions)
+        .innerJoin(users, eq(sessions.userId, users.userId))
+        .where(eq(sessions.sessionId, sessionId));
+    if (result.length < 1) {
+        return { session: null, user: null };
+    }
+    const { user, session } = result[0];
+    if (Date.now() >= session.expiresAt) {
+        await db
+            .delete(sessions)
+            .where(eq(sessions.sessionId, session.sessionId));
+        return { session: null, user: null };
+    }
+    if (Date.now() >= session.expiresAt - (SESSION_COOKIE_EXPIRES / 2)) {
+        session.expiresAt = new Date(
+            Date.now() + SESSION_COOKIE_EXPIRES,
+        ).getTime();
+        await db
+            .update(sessions)
+            .set({
+                expiresAt: session.expiresAt,
+            })
+            .where(eq(sessions.sessionId, session.sessionId));
+    }
+    return { session, user };
+}
+
+export async function invalidateSession(sessionId: string): Promise<void> {
+    await db.delete(sessions).where(eq(sessions.sessionId, sessionId));
+}
 
-export default lucia;
+export async function invalidateAllSessions(userId: string): Promise<void> {
+    await db.delete(sessions).where(eq(sessions.userId, userId));
+}
+
+export function serializeSessionCookie(token: string): string {
+    if (SECURE_COOKIES) {
+        return `${SESSION_COOKIE_NAME}=${token}; HttpOnly; SameSite=Lax; Max-Age=${SESSION_COOKIE_EXPIRES}; Path=/; Secure; Domain=${COOKIE_DOMAIN}`;
+    } else {
+        return `${SESSION_COOKIE_NAME}=${token}; HttpOnly; SameSite=Lax; Max-Age=${SESSION_COOKIE_EXPIRES}; Path=/; Domain=${COOKIE_DOMAIN}`;
+    }
+}
 
-declare module "lucia" {
-    interface Register {
-        Lucia: typeof lucia;
-        DatabaseUserAttributes: DatabaseUserAttributes;
+export function createBlankSessionTokenCookie(): string {
+    if (SECURE_COOKIES) {
+        return `${SESSION_COOKIE_NAME}=; HttpOnly; SameSite=Lax; Max-Age=0; Path=/; Secure; Domain=${COOKIE_DOMAIN}`;
+    } else {
+        return `${SESSION_COOKIE_NAME}=; HttpOnly; SameSite=Lax; Max-Age=0; Path=/; Domain=${COOKIE_DOMAIN}`;
     }
 }
 
-interface DatabaseUserAttributes {
-    email: string;
-    passwordHash: string;
-    twoFactorEnabled: boolean;
-    twoFactorSecret?: string;
-    emailVerified: boolean;
-    dateCreated: string;
+const random: RandomReader = {
+    read(bytes: Uint8Array): void {
+        crypto.getRandomValues(bytes);
+    },
+};
+
+export function generateId(length: number): string {
+    const alphabet = "abcdefghijklmnopqrstuvwxyz0123456789";
+    return generateRandomString(random, alphabet, length);
+}
+
+export function generateIdFromEntropySize(size: number): string {
+    const buffer = crypto.getRandomValues(new Uint8Array(size));
+    return encodeBase32LowerCaseNoPadding(buffer);
 }
+
+export type SessionValidationResult =
+    | { session: Session; user: User }
+    | { session: null; user: null };

+ 3 - 3
server/auth/verifySession.ts

@@ -1,9 +1,9 @@
 import { Request } from "express";
-import { lucia } from "@server/auth";
+import { validateSessionToken, SESSION_COOKIE_NAME } from "@server/auth";
 
 export async function verifySession(req: Request) {
-    const res = await lucia.validateSession(
-        req.cookies[lucia.sessionCookieName],
+    const res = await validateSessionToken(
+        req.cookies[SESSION_COOKIE_NAME] ?? "",
     );
     return res;
 }

+ 16 - 23
server/db/schema.ts

@@ -1,14 +1,12 @@
 import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core";
 import { InferSelectModel } from "drizzle-orm";
 
-// Orgs table
 export const orgs = sqliteTable("orgs", {
     orgId: integer("orgId").primaryKey({ autoIncrement: true }),
     name: text("name").notNull(),
     domain: text("domain").notNull(),
 });
 
-// Sites table
 export const sites = sqliteTable("sites", {
     siteId: integer("siteId").primaryKey({ autoIncrement: true }),
     orgId: integer("orgId").references(() => orgs.orgId, {
@@ -25,7 +23,6 @@ export const sites = sqliteTable("sites", {
     megabytesOut: integer("bytesOut"),
 });
 
-// Resources table
 export const resources = sqliteTable("resources", {
     resourceId: text("resourceId", { length: 2048 }).primaryKey(),
     siteId: integer("siteId").references(() => sites.siteId, {
@@ -38,7 +35,6 @@ export const resources = sqliteTable("resources", {
     subdomain: text("subdomain"),
 });
 
-// Targets table
 export const targets = sqliteTable("targets", {
     targetId: integer("targetId").primaryKey({ autoIncrement: true }),
     resourceId: text("resourceId").references(() => resources.resourceId, {
@@ -51,7 +47,6 @@ export const targets = sqliteTable("targets", {
     enabled: integer("enabled", { mode: "boolean" }).notNull().default(true),
 });
 
-// Exit Nodes table
 export const exitNodes = sqliteTable("exitNodes", {
     exitNodeId: integer("exitNodeId").primaryKey({ autoIncrement: true }),
     name: text("name").notNull(),
@@ -60,7 +55,6 @@ export const exitNodes = sqliteTable("exitNodes", {
     listenPort: integer("listenPort"),
 });
 
-// Routes table
 export const routes = sqliteTable("routes", {
     routeId: integer("routeId").primaryKey({ autoIncrement: true }),
     exitNodeId: integer("exitNodeId").references(() => exitNodes.exitNodeId, {
@@ -69,9 +63,8 @@ export const routes = sqliteTable("routes", {
     subnet: text("subnet").notNull(),
 });
 
-// Users table
 export const users = sqliteTable("user", {
-    id: text("id").primaryKey(), // has to be id not userId for lucia
+    userId: text("id").primaryKey(),
     email: text("email").notNull().unique(),
     passwordHash: text("passwordHash").notNull(),
     twoFactorEnabled: integer("twoFactorEnabled", { mode: "boolean" })
@@ -85,26 +78,25 @@ export const users = sqliteTable("user", {
 });
 
 export const twoFactorBackupCodes = sqliteTable("twoFactorBackupCodes", {
-    id: integer("id").primaryKey({ autoIncrement: true }),
+    codeId: integer("id").primaryKey({ autoIncrement: true }),
     userId: text("userId")
         .notNull()
-        .references(() => users.id, { onDelete: "cascade" }),
+        .references(() => users.userId, { onDelete: "cascade" }),
     codeHash: text("codeHash").notNull(),
 });
 
-// Sessions table
 export const sessions = sqliteTable("session", {
-    id: text("id").primaryKey(), // has to be id not sessionId for lucia
+    sessionId: text("id").primaryKey(),
     userId: text("userId")
         .notNull()
-        .references(() => users.id, { onDelete: "cascade" }),
+        .references(() => users.userId, { onDelete: "cascade" }),
     expiresAt: integer("expiresAt").notNull(),
 });
 
 export const userOrgs = sqliteTable("userOrgs", {
     userId: text("userId")
         .notNull()
-        .references(() => users.id),
+        .references(() => users.userId),
     orgId: integer("orgId")
         .notNull()
         .references(() => orgs.orgId),
@@ -114,20 +106,20 @@ export const userOrgs = sqliteTable("userOrgs", {
 });
 
 export const emailVerificationCodes = sqliteTable("emailVerificationCodes", {
-    id: integer("id").primaryKey({ autoIncrement: true }),
+    codeId: integer("id").primaryKey({ autoIncrement: true }),
     userId: text("userId")
         .notNull()
-        .references(() => users.id, { onDelete: "cascade" }),
+        .references(() => users.userId, { onDelete: "cascade" }),
     email: text("email").notNull(),
     code: text("code").notNull(),
     expiresAt: integer("expiresAt").notNull(),
 });
 
 export const passwordResetTokens = sqliteTable("passwordResetTokens", {
-    id: integer("id").primaryKey({ autoIncrement: true }),
+    tokenId: integer("id").primaryKey({ autoIncrement: true }),
     userId: text("userId")
         .notNull()
-        .references(() => users.id, { onDelete: "cascade" }),
+        .references(() => users.userId, { onDelete: "cascade" }),
     tokenHash: text("tokenHash").notNull(),
     expiresAt: integer("expiresAt").notNull(),
 });
@@ -140,7 +132,9 @@ export const actions = sqliteTable("actions", {
 
 export const roles = sqliteTable("roles", {
     roleId: integer("roleId").primaryKey({ autoIncrement: true }),
-    orgId: integer("orgId").references(() => orgs.orgId, { onDelete: "cascade" }),
+    orgId: integer("orgId").references(() => orgs.orgId, {
+        onDelete: "cascade",
+    }),
     isSuperuserRole: integer("isSuperuserRole", { mode: "boolean" }),
     name: text("name").notNull(),
     description: text("description"),
@@ -161,7 +155,7 @@ export const roleActions = sqliteTable("roleActions", {
 export const userActions = sqliteTable("userActions", {
     userId: text("userId")
         .notNull()
-        .references(() => users.id, { onDelete: "cascade" }),
+        .references(() => users.userId, { onDelete: "cascade" }),
     actionId: text("actionId")
         .notNull()
         .references(() => actions.actionId, { onDelete: "cascade" }),
@@ -182,7 +176,7 @@ export const roleSites = sqliteTable("roleSites", {
 export const userSites = sqliteTable("userSites", {
     userId: text("userId")
         .notNull()
-        .references(() => users.id, { onDelete: "cascade" }),
+        .references(() => users.userId, { onDelete: "cascade" }),
     siteId: integer("siteId")
         .notNull()
         .references(() => sites.siteId, { onDelete: "cascade" }),
@@ -200,7 +194,7 @@ export const roleResources = sqliteTable("roleResources", {
 export const userResources = sqliteTable("userResources", {
     userId: text("userId")
         .notNull()
-        .references(() => users.id, { onDelete: "cascade" }),
+        .references(() => users.userId, { onDelete: "cascade" }),
     resourceId: text("resourceId")
         .notNull()
         .references(() => resources.resourceId, { onDelete: "cascade" }),
@@ -216,7 +210,6 @@ export const limitsTable = sqliteTable("limits", {
     description: text("description"),
 });
 
-// Define the model types for type inference
 export type Org = InferSelectModel<typeof orgs>;
 export type User = InferSelectModel<typeof users>;
 export type Site = InferSelectModel<typeof sites>;

+ 1 - 1
server/middlewares/verifySession.ts

@@ -20,7 +20,7 @@ export const verifySessionMiddleware = async (
     const existingUser = await db
         .select()
         .from(users)
-        .where(eq(users.id, user.id));
+        .where(eq(users.userId, user.userId));
 
     if (!existingUser || !existingUser[0]) {
         return next(

+ 1 - 1
server/middlewares/verifyUser.ts

@@ -20,7 +20,7 @@ export const verifySessionUserMiddleware = async (
     const existingUser = await db
         .select()
         .from(users)
-        .where(eq(users.id, user.id));
+        .where(eq(users.userId, user.userId));
 
     if (!existingUser || !existingUser[0]) {
         return next(

+ 4 - 4
server/routers/auth/changePassword.ts

@@ -2,7 +2,7 @@ import { Request, Response, NextFunction } from "express";
 import createHttpError from "http-errors";
 import HttpCode from "@server/types/HttpCode";
 import { fromError } from "zod-validation-error";
-import lucia, { unauthorized } from "@server/auth";
+import { unauthorized, invalidateAllSessions } from "@server/auth";
 import { z } from "zod";
 import { db } from "@server/db";
 import { User, users } from "@server/db/schema";
@@ -74,7 +74,7 @@ export async function changePassword(
             const validOTP = await verifyTotpCode(
                 code!,
                 user.twoFactorSecret!,
-                user.id,
+                user.userId,
             );
 
             if (!validOTP) {
@@ -94,9 +94,9 @@ export async function changePassword(
             .set({
                 passwordHash: hash,
             })
-            .where(eq(users.id, user.id));
+            .where(eq(users.userId, user.userId));
 
-        await lucia.invalidateUserSessions(user.id);
+        await invalidateAllSessions(user.userId);
 
         // TODO: send email to user confirming password change
 

+ 3 - 3
server/routers/auth/disable2fa.ts

@@ -69,7 +69,7 @@ export async function disable2fa(
         const validOTP = await verifyTotpCode(
             code,
             user.twoFactorSecret!,
-            user.id,
+            user.userId,
         );
 
         if (!validOTP) {
@@ -84,11 +84,11 @@ export async function disable2fa(
         await db
             .update(users)
             .set({ twoFactorEnabled: false })
-            .where(eq(users.id, user.id));
+            .where(eq(users.userId, user.userId));
 
         await db
             .delete(twoFactorBackupCodes)
-            .where(eq(twoFactorBackupCodes.userId, user.id));
+            .where(eq(twoFactorBackupCodes.userId, user.userId));
 
         // TODO: send email to user confirming two-factor authentication is disabled
 

+ 2 - 2
server/routers/auth/getUserOrgs.ts

@@ -6,7 +6,7 @@ import createHttpError from 'http-errors';
 import HttpCode from '@server/types/HttpCode';
 
 export async function getUserOrgs(req: Request, res: Response, next: NextFunction) {
-    const userId = req.user?.id; // Assuming you have user information in the request
+    const userId = req.user?.userId; // Assuming you have user information in the request
 
     if (!userId) {
         return next(createHttpError(HttpCode.UNAUTHORIZED, 'User not authenticated'));
@@ -30,4 +30,4 @@ export async function getUserOrgs(req: Request, res: Response, next: NextFunctio
     } catch (error) {
         next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, 'Error retrieving user organizations'));
     }
-}
+}

+ 11 - 8
server/routers/auth/login.ts

@@ -1,5 +1,10 @@
 import { verify } from "@node-rs/argon2";
-import lucia, { verifySession } from "@server/auth";
+import {
+    createSession,
+    generateSessionToken,
+    serializeSessionCookie,
+    verifySession,
+} from "@server/auth";
 import db from "@server/db";
 import { users } from "@server/db/schema";
 import HttpCode from "@server/types/HttpCode";
@@ -102,7 +107,7 @@ export async function login(
             const validOTP = await verifyTotpCode(
                 code,
                 existingUser.twoFactorSecret!,
-                existingUser.id,
+                existingUser.userId,
             );
 
             if (!validOTP) {
@@ -115,13 +120,11 @@ export async function login(
             }
         }
 
-        const session = await lucia.createSession(existingUser.id, {});
-        const cookie = lucia.createSessionCookie(session.id).serialize();
+        const token = generateSessionToken();
+        await createSession(token, existingUser.userId);
+        const cookie = serializeSessionCookie(token);
 
-        res.appendHeader(
-            "Set-Cookie",
-            cookie
-        );
+        res.appendHeader("Set-Cookie", cookie);
 
         if (!existingUser.emailVerified) {
             return response<LoginResponse>(res, {

+ 8 - 7
server/routers/auth/logout.ts

@@ -1,16 +1,20 @@
 import { Request, Response, NextFunction } from "express";
-import { lucia } from "@server/auth";
 import createHttpError from "http-errors";
 import HttpCode from "@server/types/HttpCode";
 import response from "@server/utils/response";
 import logger from "@server/logger";
+import {
+    createBlankSessionTokenCookie,
+    invalidateSession,
+    SESSION_COOKIE_NAME,
+} from "@server/auth";
 
 export async function logout(
     req: Request,
     res: Response,
     next: NextFunction,
 ): Promise<any> {
-    const sessionId = req.cookies[lucia.sessionCookieName];
+    const sessionId = req.cookies[SESSION_COOKIE_NAME];
 
     if (!sessionId) {
         return next(
@@ -22,11 +26,8 @@ export async function logout(
     }
 
     try {
-        await lucia.invalidateSession(sessionId);
-        res.setHeader(
-            "Set-Cookie",
-            lucia.createBlankSessionCookie().serialize(),
-        );
+        await invalidateSession(sessionId);
+        res.setHeader("Set-Cookie", createBlankSessionTokenCookie());
 
         return response<null>(res, {
             data: null,

+ 1 - 1
server/routers/auth/requestEmailVerificationCode.ts

@@ -26,7 +26,7 @@ export async function requestEmailVerificationCode(
             );
         }
 
-        await sendEmailVerificationCode(user.email, user.id);
+        await sendEmailVerificationCode(user.email, user.userId);
 
         return response<RequestEmailVerificationCodeResponse>(res, {
             data: {

+ 5 - 4
server/routers/auth/requestPasswordReset.ts

@@ -8,10 +8,11 @@ import { db } from "@server/db";
 import { passwordResetTokens, users } from "@server/db/schema";
 import { eq } from "drizzle-orm";
 import { sha256 } from "oslo/crypto";
-import { generateIdFromEntropySize, TimeSpan } from "lucia";
 import { encodeHex } from "oslo/encoding";
 import { createDate } from "oslo";
 import logger from "@server/logger";
+import { generateIdFromEntropySize } from "@server/auth";
+import { TimeSpan } from "oslo";
 
 export const requestPasswordResetBody = z.object({
     email: z.string().email(),
@@ -58,7 +59,7 @@ export async function requestPasswordReset(
 
         await db
             .delete(passwordResetTokens)
-            .where(eq(passwordResetTokens.userId, existingUser[0].id));
+            .where(eq(passwordResetTokens.userId, existingUser[0].userId));
 
         const token = generateIdFromEntropySize(25);
         const tokenHash = encodeHex(
@@ -66,7 +67,7 @@ export async function requestPasswordReset(
         );
 
         await db.insert(passwordResetTokens).values({
-            userId: existingUser[0].id,
+            userId: existingUser[0].userId,
             tokenHash,
             expiresAt: createDate(new TimeSpan(2, "h")).getTime(),
         });
@@ -89,7 +90,7 @@ export async function requestPasswordReset(
         return next(
             createHttpError(
                 HttpCode.INTERNAL_SERVER_ERROR,
-                "Failed to process password reset request"
+                "Failed to process password reset request",
             ),
         );
     }

+ 1 - 1
server/routers/auth/requestTotpSecret.ts

@@ -72,7 +72,7 @@ export async function requestTotpSecret(
             .set({
                 twoFactorSecret: secret,
             })
-            .where(eq(users.id, user.id));
+            .where(eq(users.userId, user.userId));
 
         return response<RequestTotpSecretResponse>(res, {
             data: {

+ 5 - 5
server/routers/auth/resetPassword.ts

@@ -13,7 +13,7 @@ import { verifyTotpCode } from "@server/auth/2fa";
 import { passwordSchema } from "@server/auth/passwordSchema";
 import { encodeHex } from "oslo/encoding";
 import { isWithinExpirationDate } from "oslo";
-import lucia from "@server/auth";
+import { invalidateAllSessions } from "@server/auth";
 
 export const resetPasswordBody = z.object({
     token: z.string(),
@@ -71,7 +71,7 @@ export async function resetPassword(
         const user = await db
             .select()
             .from(users)
-            .where(eq(users.id, resetRequest[0].userId));
+            .where(eq(users.userId, resetRequest[0].userId));
 
         if (!user || !user.length) {
             return next(
@@ -96,7 +96,7 @@ export async function resetPassword(
             const validOTP = await verifyTotpCode(
                 code!,
                 user[0].twoFactorSecret!,
-                user[0].id,
+                user[0].userId,
             );
 
             if (!validOTP) {
@@ -111,12 +111,12 @@ export async function resetPassword(
 
         const passwordHash = await hashPassword(newPassword);
 
-        await lucia.invalidateUserSessions(resetRequest[0].userId);
+        await invalidateAllSessions(resetRequest[0].userId);
 
         await db
             .update(users)
             .set({ passwordHash })
-            .where(eq(users.id, resetRequest[0].userId));
+            .where(eq(users.userId, resetRequest[0].userId));
 
         await db
             .delete(passwordResetTokens)

+ 12 - 9
server/routers/auth/signup.ts

@@ -3,9 +3,7 @@ import db from "@server/db";
 import { hash } from "@node-rs/argon2";
 import HttpCode from "@server/types/HttpCode";
 import { z } from "zod";
-import { generateId } from "lucia";
 import { users } from "@server/db/schema";
-import lucia from "@server/auth";
 import { fromError } from "zod-validation-error";
 import createHttpError from "http-errors";
 import response from "@server/utils/response";
@@ -14,6 +12,12 @@ import { sendEmailVerificationCode } from "./sendEmailVerificationCode";
 import { passwordSchema } from "@server/auth/passwordSchema";
 import { eq } from "drizzle-orm";
 import moment from "moment";
+import {
+    createSession,
+    generateId,
+    generateSessionToken,
+    serializeSessionCookie,
+} from "@server/auth";
 
 export const signupBodySchema = z.object({
     email: z.string().email(),
@@ -85,22 +89,21 @@ export async function signup(
                 );
             } else {
                 // If the user was created more than 2 hours ago, we want to delete the old user and create a new one
-                await db.delete(users).where(eq(users.id, user.id));
+                await db.delete(users).where(eq(users.userId, user.userId));
             }
         }
 
         await db.insert(users).values({
-            id: userId,
+            userId: userId,
             email: email,
             passwordHash,
             dateCreated: moment().toISOString(),
         });
 
-        const session = await lucia.createSession(userId, {});
-        res.appendHeader(
-            "Set-Cookie",
-            lucia.createSessionCookie(session.id).serialize(),
-        );
+        const token = generateSessionToken();
+        await createSession(token, userId);
+        const cookie = serializeSessionCookie(token);
+        res.appendHeader("Set-Cookie", cookie);
 
         sendEmailVerificationCode(email, userId);
 

+ 3 - 3
server/routers/auth/verifyEmail.ts

@@ -51,14 +51,14 @@ export async function verifyEmail(
         if (valid) {
             await db
                 .delete(emailVerificationCodes)
-                .where(eq(emailVerificationCodes.userId, user.id));
+                .where(eq(emailVerificationCodes.userId, user.userId));
 
             await db
                 .update(users)
                 .set({
                     emailVerified: true,
                 })
-                .where(eq(users.id, user.id));
+                .where(eq(users.userId, user.userId));
         } else {
             return next(
                 createHttpError(
@@ -93,7 +93,7 @@ async function isValidCode(user: User, code: string): Promise<boolean> {
     const codeRecord = await db
         .select()
         .from(emailVerificationCodes)
-        .where(eq(emailVerificationCodes.userId, user.id))
+        .where(eq(emailVerificationCodes.userId, user.userId))
         .limit(1);
 
     if (user.email !== codeRecord[0].email) {

+ 1 - 1
server/routers/auth/verifyOrgAccess.ts

@@ -7,7 +7,7 @@ import HttpCode from '@server/types/HttpCode';
 import { AuthenticatedRequest } from '@server/types/Auth';
 
 export function verifyOrgAccess(req: Request, res: Response, next: NextFunction) {
-    const userId = req.user!.id; // Assuming you have user information in the request
+    const userId = req.user!.userId; // Assuming you have user information in the request
     const orgId = parseInt(req.params.orgId);
 
     if (!userId) {

+ 2 - 2
server/routers/auth/verifyResourceAccess.ts

@@ -6,7 +6,7 @@ import createHttpError from 'http-errors';
 import HttpCode from '@server/types/HttpCode';
 
 export async function verifyResourceAccess(req: Request, res: Response, next: NextFunction) {
-    const userId = req.user!.id; // Assuming you have user information in the request
+    const userId = req.user!.userId; // Assuming you have user information in the request
     const resourceId = req.params.resourceId || req.body.resourceId || req.query.resourceId;
 
     if (!userId) {
@@ -75,4 +75,4 @@ export async function verifyResourceAccess(req: Request, res: Response, next: Ne
     } catch (error) {
         return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, 'Error verifying resource access'));
     }
-}
+}

+ 2 - 2
server/routers/auth/verifyRoleAccess.ts

@@ -7,7 +7,7 @@ import HttpCode from '@server/types/HttpCode';
 import logger from '@server/logger';
 
 export async function verifyRoleAccess(req: Request, res: Response, next: NextFunction) {
-    const userId = req.user?.id; // Assuming you have user information in the request
+    const userId = req.user?.userId; // Assuming you have user information in the request
     const roleId = parseInt(req.params.roleId || req.body.roleId || req.query.roleId);
 
     if (!userId) {
@@ -47,4 +47,4 @@ export async function verifyRoleAccess(req: Request, res: Response, next: NextFu
         logger.error('Error verifying role access:', error);
         return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, 'Error verifying role access'));
     }
-}
+}

+ 2 - 2
server/routers/auth/verifySiteAccess.ts

@@ -6,7 +6,7 @@ import createHttpError from 'http-errors';
 import HttpCode from '@server/types/HttpCode';
 
 export async function verifySiteAccess(req: Request, res: Response, next: NextFunction) {
-    const userId = req.user!.id; // Assuming you have user information in the request
+    const userId = req.user!.userId; // Assuming you have user information in the request
     const siteId = parseInt(req.params.siteId || req.body.siteId || req.query.siteId);
 
     if (!userId) {
@@ -76,4 +76,4 @@ export async function verifySiteAccess(req: Request, res: Response, next: NextFu
     } catch (error) {
         return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, 'Error verifying site access'));
     }
-}
+}

+ 4 - 4
server/routers/auth/verifySuperuser.ts

@@ -7,7 +7,7 @@ import HttpCode from '@server/types/HttpCode';
 import logger from '@server/logger';
 
 export async function verifySuperuser(req: Request, res: Response, next: NextFunction) {
-    const userId = req.user?.id; // Assuming you have user information in the request
+    const userId = req.user?.userId; // Assuming you have user information in the request
     const orgId = req.userOrgId;
 
     if (!userId) {
@@ -18,7 +18,7 @@ export async function verifySuperuser(req: Request, res: Response, next: NextFun
         return next(createHttpError(HttpCode.UNAUTHORIZED, 'User not authenticated'));
     }
 
-    try {     
+    try {
         // Check if the user has a role in the organization
         const userOrgRole = await db.select()
             .from(userOrgs)
@@ -35,7 +35,7 @@ export async function verifySuperuser(req: Request, res: Response, next: NextFun
             .from(roles)
             .where(eq(roles.roleId, userOrgRole[0].roleId))
             .limit(1);
-            
+
         if (userRole.length === 0 || !userRole[0].isSuperuserRole) {
             return next(createHttpError(HttpCode.FORBIDDEN, 'User does not have superuser access'));
         }
@@ -45,4 +45,4 @@ export async function verifySuperuser(req: Request, res: Response, next: NextFun
         logger.error('Error verifying role access:', error);
         return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, 'Error verifying role access'));
     }
-}
+}

+ 2 - 2
server/routers/auth/verifyTargetAccess.ts

@@ -6,7 +6,7 @@ import createHttpError from 'http-errors';
 import HttpCode from '@server/types/HttpCode';
 
 export async function verifyTargetAccess(req: Request, res: Response, next: NextFunction) {
-    const userId = req.user!.id; // Assuming you have user information in the request
+    const userId = req.user!.userId; // Assuming you have user information in the request
     const targetId = parseInt(req.params.targetId);
 
     if (!userId) {
@@ -81,4 +81,4 @@ export async function verifyTargetAccess(req: Request, res: Response, next: Next
         .catch((error) => {
             next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, 'Error verifying organization access'));
         });
-}
+}

+ 3 - 3
server/routers/auth/verifyTotp.ts

@@ -61,7 +61,7 @@ export async function verifyTotp(
     }
 
     try {
-        const valid = await verifyTotpCode(code, user.twoFactorSecret, user.id);
+        const valid = await verifyTotpCode(code, user.twoFactorSecret, user.userId);
 
         let codes;
         if (valid) {
@@ -69,7 +69,7 @@ export async function verifyTotp(
             await db
                 .update(users)
                 .set({ twoFactorEnabled: true })
-                .where(eq(users.id, user.id));
+                .where(eq(users.userId, user.userId));
 
             const backupCodes = await generateBackupCodes();
             codes = backupCodes;
@@ -77,7 +77,7 @@ export async function verifyTotp(
                 const hash = await hashPassword(code);
 
                 await db.insert(twoFactorBackupCodes).values({
-                    userId: user.id,
+                    userId: user.userId,
                     codeHash: hash,
                 });
             }

+ 3 - 3
server/routers/auth/verifyUserAccess.ts

@@ -6,7 +6,7 @@ import createHttpError from 'http-errors';
 import HttpCode from '@server/types/HttpCode';
 
 export async function verifyUserAccess(req: Request, res: Response, next: NextFunction) {
-    const userId = req.user!.id; // Assuming you have user information in the request
+    const userId = req.user!.userId; // Assuming you have user information in the request
     const reqUserId = req.params.userId || req.body.userId || req.query.userId;
 
     if (!userId) {
@@ -18,7 +18,7 @@ export async function verifyUserAccess(req: Request, res: Response, next: NextFu
     }
 
     try {
-        
+
         const userOrg = await db.select()
             .from(userOrgs)
             .where(and(eq(userOrgs.userId, userId), eq(userOrgs.orgId, req.userOrgId!)))
@@ -34,4 +34,4 @@ export async function verifyUserAccess(req: Request, res: Response, next: NextFu
     } catch (error) {
         return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, 'Error verifying site access'));
     }
-}
+}

+ 2 - 3
server/routers/badger/verifyUser.ts

@@ -1,11 +1,10 @@
-import lucia from "@server/auth";
 import HttpCode from "@server/types/HttpCode";
 import { NextFunction, Request, Response } from "express";
 import createHttpError from "http-errors";
 import { z } from "zod";
 import { fromError } from "zod-validation-error";
 import { response } from "@server/utils/response";
-import logger from "@server/logger";
+import { validateSessionToken } from "@server/auth";
 
 export const verifyUserBody = z.object({
     sessionId: z.string(),
@@ -36,7 +35,7 @@ export async function verifyUser(
     const { sessionId } = parsedBody.data;
 
     try {
-        const { session, user } = await lucia.validateSession(sessionId);
+        const { session, user } = await validateSessionToken(sessionId);
 
         if (!session || !user) {
             return next(

+ 1 - 1
server/routers/resource/createResource.ts

@@ -95,7 +95,7 @@ export async function createResource(req: Request, res: Response, next: NextFunc
         if (req.userOrgRoleId != superuserRole[0].roleId) {
             // make sure the user can access the resource
             await db.insert(userResources).values({
-                userId: req.user?.id!,
+                userId: req.user?.userId!,
                 resourceId: newResource[0].resourceId,
             });
         }

+ 2 - 2
server/routers/resource/listResources.ts

@@ -57,7 +57,7 @@ export async function listResources(req: RequestWithOrgAndRole, res: Response, n
             .fullJoin(roleResources, eq(userResources.resourceId, roleResources.resourceId))
             .where(
                 or(
-                    eq(userResources.userId, req.user!.id),
+                    eq(userResources.userId, req.user!.userId),
                     eq(roleResources.roleId, req.userOrgRoleId!)
                 )
             );
@@ -111,4 +111,4 @@ export async function listResources(req: RequestWithOrgAndRole, res: Response, n
         logger.error(error);
         return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred..."));
     }
-}
+}

+ 6 - 6
server/routers/site/createSite.ts

@@ -75,7 +75,7 @@ export async function createSite(req: Request, res: Response, next: NextFunction
         .from(roles)
         .where(and(eq(roles.isSuperuserRole, true), eq(roles.orgId, orgId)))
         .limit(1);
-        
+
         if (superuserRole.length === 0) {
             return next(
                 createHttpError(
@@ -84,20 +84,20 @@ export async function createSite(req: Request, res: Response, next: NextFunction
                 )
             );
         }
-        
-        await db.insert(roleSites).values({ 
+
+        await db.insert(roleSites).values({
             roleId: superuserRole[0].roleId,
             siteId: newSite[0].siteId,
         });
 
         if (req.userOrgRoleId != superuserRole[0].roleId) {
             // make sure the user can access the site
-            db.insert(userSites).values({ 
-                userId: req.user?.id!,
+            db.insert(userSites).values({
+                userId: req.user?.userId!,
                 siteId: newSite[0].siteId,
             });
         }
-        
+
         return response(res, {
             data: newSite[0],
             success: true,

+ 2 - 2
server/routers/site/listSites.ts

@@ -49,7 +49,7 @@ export async function listSites(req: Request, res: Response, next: NextFunction)
             .fullJoin(roleSites, eq(userSites.siteId, roleSites.siteId))
             .where(
                 or(
-                    eq(userSites.userId, req.user!.id),
+                    eq(userSites.userId, req.user!.userId),
                     eq(roleSites.roleId, req.userOrgRoleId!)
                 )
             );
@@ -104,4 +104,4 @@ export async function listSites(req: Request, res: Response, next: NextFunction)
         logger.error(error);
         return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred..."));
     }
-}
+}

+ 2 - 2
server/routers/user/addUserAction.ts

@@ -36,7 +36,7 @@ export async function addUserAction(req: Request, res: Response, next: NextFunct
         }
 
         // Check if the user exists
-        const user = await db.select().from(users).where(eq(users.id, userId)).limit(1);
+        const user = await db.select().from(users).where(eq(users.userId, userId)).limit(1);
         if (user.length === 0) {
             return next(createHttpError(HttpCode.NOT_FOUND, `User with ID ${userId} not found`));
         }
@@ -58,4 +58,4 @@ export async function addUserAction(req: Request, res: Response, next: NextFunct
         logger.error(error);
         return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred..."));
     }
-}
+}

+ 2 - 2
server/routers/user/addUserOrg.ts

@@ -51,7 +51,7 @@ export async function addUserOrg(req: Request, res: Response, next: NextFunction
         }
 
         // Check if the user exists
-        const user = await db.select().from(users).where(eq(users.id, userId)).limit(1);
+        const user = await db.select().from(users).where(eq(users.userId, userId)).limit(1);
         if (user.length === 0) {
             return next(createHttpError(HttpCode.NOT_FOUND, `User with ID ${userId} not found`));
         }
@@ -84,4 +84,4 @@ export async function addUserOrg(req: Request, res: Response, next: NextFunction
         logger.error(error);
         return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred..."));
     }
-}
+}

+ 2 - 2
server/routers/user/getUser.ts

@@ -21,7 +21,7 @@ export async function getUser(
     next: NextFunction,
 ): Promise<any> {
     try {
-        const userId = req.user?.id;
+        const userId = req.user?.userId;
 
         if (!userId) {
             return next(
@@ -32,7 +32,7 @@ export async function getUser(
         const user = await db
             .select()
             .from(users)
-            .where(eq(users.id, userId))
+            .where(eq(users.userId, userId))
             .limit(1);
 
         if (user.length === 0) {

+ 3 - 3
server/routers/user/listUsers.ts

@@ -52,7 +52,7 @@ export async function listUsers(req: Request, res: Response, next: NextFunction)
         // Query to join users, userOrgs, and roles tables
         const usersWithRoles = await db
             .select({
-                id: users.id,
+                id: users.userId,
                 email: users.email,
                 emailVerified: users.emailVerified,
                 dateCreated: users.dateCreated,
@@ -61,7 +61,7 @@ export async function listUsers(req: Request, res: Response, next: NextFunction)
                 roleName: roles.name,
             })
             .from(users)
-            .leftJoin(userOrgs, sql`${users.id} = ${userOrgs.userId}`)
+            .leftJoin(userOrgs, sql`${users.userId} = ${userOrgs.userId}`)
             .leftJoin(roles, sql`${userOrgs.roleId} = ${roles.roleId}`)
             .where(sql`${userOrgs.orgId} = ${orgId}`)
             .limit(limit)
@@ -90,4 +90,4 @@ export async function listUsers(req: Request, res: Response, next: NextFunction)
         logger.error(error);
         return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred..."));
     }
-}
+}

+ 1 - 1
server/types/Auth.ts

@@ -1,6 +1,6 @@
 import { Request } from "express";
 import { User } from "@server/db/schema";
-import { Session } from "lucia";
+import { Session } from "@server/db/schema";
 
 export interface AuthenticatedRequest extends Request {
     user: User;

+ 0 - 2
src/app/page.tsx

@@ -9,8 +9,6 @@ export default async function Page() {
         redirect("/auth/login");
     }
 
-    console.log(user);
-
     return (
         <>
             <LandingProvider user={user}>