diff --git a/apps/server/src/lib/auth.ts b/apps/server/src/lib/auth.ts index 4626ed25..ea9aa42a 100644 --- a/apps/server/src/lib/auth.ts +++ b/apps/server/src/lib/auth.ts @@ -320,6 +320,15 @@ function checkAuthentication( return { authenticated: false, errorType: 'invalid_api_key' }; } + // Check for session token in query parameter (web mode - needed for image loads) + const queryToken = query.token; + if (queryToken) { + if (validateSession(queryToken)) { + return { authenticated: true }; + } + return { authenticated: false, errorType: 'invalid_session' }; + } + // Check for session cookie (web mode) const sessionToken = cookies[SESSION_COOKIE_NAME]; if (sessionToken && validateSession(sessionToken)) { @@ -335,8 +344,9 @@ function checkAuthentication( * Accepts either: * 1. X-API-Key header (for Electron mode) * 2. X-Session-Token header (for web mode with explicit token) - * 3. apiKey query parameter (fallback for cases where headers can't be set) - * 4. Session cookie (for web mode) + * 3. apiKey query parameter (fallback for Electron, cases where headers can't be set) + * 4. token query parameter (fallback for web mode, needed for image loads via CSS/img tags) + * 5. Session cookie (for web mode) */ export function authMiddleware(req: Request, res: Response, next: NextFunction): void { const result = checkAuthentication( diff --git a/apps/server/src/routes/fs/routes/image.ts b/apps/server/src/routes/fs/routes/image.ts index 97187528..32f3b3cb 100644 --- a/apps/server/src/routes/fs/routes/image.ts +++ b/apps/server/src/routes/fs/routes/image.ts @@ -1,7 +1,7 @@ /** * GET /image endpoint - Serve image files * - * Requires authentication via: + * Requires authentication via auth middleware: * - apiKey query parameter (Electron mode) * - token query parameter (web mode) * - session cookie (web mode) @@ -13,21 +13,11 @@ import type { Request, Response } from 'express'; import * as secureFs from '../../../lib/secure-fs.js'; import path from 'path'; import { PathNotAllowedError } from '@automaker/platform'; -import { validateApiKey, validateSession } from '../../../lib/auth.js'; import { getErrorMessage, logError } from '../common.js'; -const SESSION_COOKIE_NAME = 'automaker_session'; - export function createImageHandler() { return async (req: Request, res: Response): Promise => { try { - // Authenticate the request - const isAuthenticated = checkImageAuthentication(req); - if (!isAuthenticated) { - res.status(401).json({ success: false, error: 'Authentication required' }); - return; - } - const { path: imagePath, projectPath } = req.query as { path?: string; projectPath?: string; @@ -81,41 +71,3 @@ export function createImageHandler() { } }; } - -/** - * Check if image request is authenticated - * Supports multiple authentication methods - */ -function checkImageAuthentication(req: Request): boolean { - // Check for API key in header (Electron mode) - const headerKey = req.get('x-api-key'); - if (headerKey && validateApiKey(headerKey)) { - return true; - } - - // Check for session token in header (web mode) - const sessionTokenHeader = req.get('x-session-token'); - if (sessionTokenHeader && validateSession(sessionTokenHeader)) { - return true; - } - - // Check for API key in query parameter (fallback) - const queryKey = req.query.apiKey as string | undefined; - if (queryKey && validateApiKey(queryKey)) { - return true; - } - - // Check for session token in query parameter (web mode with token) - const queryToken = req.query.token as string | undefined; - if (queryToken && validateSession(queryToken)) { - return true; - } - - // Check for session cookie (web mode) - const sessionCookie = req.cookies?.[SESSION_COOKIE_NAME]; - if (sessionCookie && validateSession(sessionCookie)) { - return true; - } - - return false; -}