From bd4053f952344e0a505ab6a5d9eff72d3cedc5ff Mon Sep 17 00:00:00 2001 From: igm Date: Mon, 12 Jan 2026 17:39:07 +0800 Subject: [PATCH] Remove unused auth middleware and utils - Delete src/middleware/auth.ts (createAuthMiddleware, createSuperuserMiddleware) - Delete src/utils/auth.ts (authenticateRequest) These files were never imported or used anywhere in the codebase. Co-Authored-By: Claude Opus 4.5 --- apps/api-server/src/middleware/auth.ts | 181 ------------------------- apps/api-server/src/utils/auth.ts | 75 ---------- 2 files changed, 256 deletions(-) delete mode 100644 apps/api-server/src/middleware/auth.ts delete mode 100644 apps/api-server/src/utils/auth.ts diff --git a/apps/api-server/src/middleware/auth.ts b/apps/api-server/src/middleware/auth.ts deleted file mode 100644 index 72c01d6..0000000 --- a/apps/api-server/src/middleware/auth.ts +++ /dev/null @@ -1,181 +0,0 @@ -/** - * Authentication middleware for oRPC server - * - * Handles authentication via: - * - Session cookie (rev.session_token) - for browser clients - * - API key header (x-api-key) - for CLI and programmatic access - */ - -import type { - APIContext, - AuthenticatedContext, - AuthInfo, - Session, - SessionUser, -} from "../context.js"; -import { ORPCError } from "@orpc/server"; -import { COOKIE_NAMES, getCookie } from "../utils/cookies.js"; -import { hashToken } from "../utils/crypto.js"; - -/** - * Create the auth middleware function - * This returns a middleware handler that can be used with oRPC procedures - */ -export const createAuthMiddleware = () => { - return async ({ - context, - next, - }: { - context: APIContext; - next: (opts: { - context: Omit; - }) => Promise; - }) => { - const { db, reqHeaders } = context; - - // Try session cookie first - let tokenHash: string | undefined; - const sessionToken = getCookie(reqHeaders, COOKIE_NAMES.SESSION_TOKEN); - if (sessionToken) { - tokenHash = await hashToken(sessionToken); - } - - // Fall back to API key header (for CLI) - const apiKey = reqHeaders.get("x-api-key"); - if (!tokenHash && apiKey) { - tokenHash = await hashToken(apiKey); - } - - if (!tokenHash) { - throw new ORPCError("UNAUTHORIZED", { message: "No session or API key" }); - } - - // Look up session (check not expired and not revoked) - const session = await db - .selectFrom("sessions") - .where("token_hash", "=", tokenHash) - .where("expires_at", ">", new Date()) - .where("revoked_at", "is", null) - .selectAll() - .executeTakeFirst(); - - // Fall back to API token if no session found - const apiToken = !session - ? await db - .selectFrom("api_tokens") - .where("token_hash", "=", tokenHash) - .where("expires_at", ">", new Date()) - .selectAll() - .executeTakeFirst() - : undefined; - - const userId = session?.user_id ?? apiToken?.user_id; - if (!userId) { - throw new ORPCError("UNAUTHORIZED", { - message: "Invalid or expired token", - }); - } - - // Update last_used_at for API tokens - if (apiToken) { - await db - .updateTable("api_tokens") - .set({ last_used_at: new Date() }) - .where("id", "=", apiToken.id) - .execute(); - } - - // Fetch user details - const user = await db - .selectFrom("users") - .where("id", "=", userId) - .select([ - "id", - "email", - "display_name", - "email_verified_at", - "is_superuser", - ]) - .executeTakeFirst(); - - if (!user) { - throw new ORPCError("UNAUTHORIZED", { - message: "User not found", - }); - } - - const sessionUser: SessionUser = { - id: user.id, - email: user.email, - displayName: user.display_name, - emailVerifiedAt: user.email_verified_at, - isSuperuser: user.is_superuser, - }; - - // Build session and auth info based on authentication method - let sessionInfo: Session; - let authInfo: AuthInfo; - - if (session) { - sessionInfo = { - id: session.id, - trustedMode: session.trusted_mode, - createdAt: session.created_at, - }; - authInfo = { - method: "session", - sessionId: session.id, - expiresAt: session.expires_at, - createdAt: session.created_at, - }; - } else if (apiToken) { - sessionInfo = { - // For API token auth, create a synthetic session object - id: "0", - trustedMode: true, - createdAt: apiToken.created_at, - }; - authInfo = { - method: "api_token", - tokenId: apiToken.id, - tokenName: apiToken.name, - expiresAt: apiToken.expires_at, - lastUsedAt: apiToken.last_used_at, - createdAt: apiToken.created_at, - }; - } else { - // This should never happen since we checked userId above - throw new ORPCError("UNAUTHORIZED", { - message: "Invalid authentication state", - }); - } - - return next({ - context: { - user: sessionUser, - session: sessionInfo, - auth: authInfo, - }, - }); - }; -}; - -/** - * Middleware to require superuser access - */ -export const createSuperuserMiddleware = () => { - return async ({ - context, - next, - }: { - context: AuthenticatedContext; - next: () => Promise; - }) => { - if (!context.user.isSuperuser) { - throw new ORPCError("FORBIDDEN", { - message: "Superuser access required", - }); - } - return next(); - }; -}; diff --git a/apps/api-server/src/utils/auth.ts b/apps/api-server/src/utils/auth.ts deleted file mode 100644 index d0439cc..0000000 --- a/apps/api-server/src/utils/auth.ts +++ /dev/null @@ -1,75 +0,0 @@ -/** - * Authentication utilities for token handling - */ - -import type { Database } from "@reviq/db-schema"; -import type { Kysely } from "kysely"; -import { hashToken } from "./crypto.js"; - -export interface AuthenticatedUser { - id: number; - email: string; - isSuperuser: boolean; -} - -/** - * Authenticate a request using session token or API key - * Returns the authenticated user or null if not authenticated - */ -export const authenticateRequest = async ( - db: Kysely, - sessionToken?: string, - apiKey?: string, -): Promise => { - // Try session cookie first, then API key - const token = sessionToken ?? apiKey; - if (!token) { - return null; - } - - const tokenHash = await hashToken(token); - - // Check sessions table - const session = await db - .selectFrom("sessions") - .innerJoin("users", "users.id", "sessions.user_id") - .where("sessions.token_hash", "=", tokenHash) - .where("sessions.expires_at", ">", new Date()) - .where("sessions.revoked_at", "is", null) - .select(["users.id", "users.email", "users.is_superuser"]) - .executeTakeFirst(); - - if (session) { - return { - id: session.id, - email: session.email, - isSuperuser: session.is_superuser, - }; - } - - // Check API tokens table - const apiToken = await db - .selectFrom("api_tokens") - .innerJoin("users", "users.id", "api_tokens.user_id") - .where("api_tokens.token_hash", "=", tokenHash) - .where("api_tokens.expires_at", ">", new Date()) - .select(["users.id", "users.email", "users.is_superuser"]) - .executeTakeFirst(); - - if (apiToken) { - // Update last_used_at - await db - .updateTable("api_tokens") - .set({ last_used_at: new Date() }) - .where("token_hash", "=", tokenHash) - .execute(); - - return { - id: apiToken.id, - email: apiToken.email, - isSuperuser: apiToken.is_superuser, - }; - } - - return null; -};