diff --git a/backend/src/server.ts b/backend/src/server.ts index 0f7a0db..685ee7e 100644 --- a/backend/src/server.ts +++ b/backend/src/server.ts @@ -22,9 +22,16 @@ export interface ServerOptions { export async function createServer(opts: ServerOptions) { const fastify = Fastify({ logger: true }); - // CORS + // CORS — restrictive origin list await fastify.register(cors, { - origin: true, + origin: (origin: string | undefined, cb: (err: Error | null, allow: boolean) => void) => { + // Allow requests with no origin (same-origin, curl, etc.) + if (!origin) return cb(null, true); + // Allow known origins + const allowed = ['https://web-cad-neu.server.media-on.de', 'http://localhost:5173', 'http://localhost:8082']; + if (allowed.includes(origin)) return cb(null, true); + cb(new Error('Not allowed by CORS'), false); + }, methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'], }); @@ -62,6 +69,26 @@ export async function createServer(opts: ServerOptions) { const authService = new AuthService(opts.db); + // Auth middleware — protect all /api/ routes except auth login/register + fastify.addHook('onRequest', async (request: any, reply: any) => { + const url = request.url; + // Skip auth endpoints and health check + if (url === '/api/auth/login' || url === '/api/auth/register' || url === '/api/health') return; + // Skip non-API routes (static files, WebSocket) + if (!url.startsWith('/api/')) return; + + const auth = request.headers.authorization; + if (!auth || !auth.startsWith('Bearer ')) { + return reply.code(401).send({ error: 'Authentication required' }); + } + const token = auth.slice(7); + const user = authService.getUserFromSession(token); + if (!user) { + return reply.code(401).send({ error: 'Invalid or expired session' }); + } + (request as any).user = user; + }); + registerAuthRoutes(fastify, authService); registerProjectRoutes(fastify, opts.db); registerDrawingRoutes(fastify, opts.db); diff --git a/backend/test_report.md b/backend/test_report.md new file mode 100644 index 0000000..2e3fde5 --- /dev/null +++ b/backend/test_report.md @@ -0,0 +1,85 @@ +# Test Report — Auth Middleware & CORS Fix (Issue #1 + #3) + +**Date:** 2026-06-29 +**Task:** Fix Issue #1 (No Authentication on CRUD Routes) + Issue #3 (CORS) from CODE_ANALYSIS.md +**File modified:** `backend/src/server.ts` + +## Build Verification + +``` +cd /a0/usr/workdir/web-cad-neu/backend && npx tsc --noEmit +``` +**Result:** ✅ PASS — No type errors, exit code 0 + +## Test Results + +### Test 1: Unauthenticated /api/projects → 401 +``` +curl -s -o /dev/null -w '%{http_code}' http://localhost:3001/api/projects +``` +**Expected:** 401 +**Actual:** 401 ✅ + +### Test 2: Health check /api/health → 200 +``` +curl -s -o /dev/null -w '%{http_code}' http://localhost:3001/api/health +``` +**Expected:** 200 +**Actual:** 200 ✅ + +### Test 3: Register endpoint accessible (no auth required) +``` +curl -s -X POST http://localhost:3001/api/auth/register -H 'Content-Type: application/json' \ + -d '{"email":"test@test.de","password":"test1234","name":"Test User"}' +``` +**Expected:** 201 +**Actual:** 201 ✅ (user created, session token returned) + +### Test 4: Login endpoint accessible (no auth required) +``` +curl -s -w '\nHTTP_CODE:%{http_code}' -X POST http://localhost:3001/api/auth/login \ + -H 'Content-Type: application/json' \ + -d '{"email":"test@test.de","password":"test1234"}' +``` +**Expected:** 200 +**Actual:** 200 ✅ (user + session token returned) + +### Test 5: Authenticated /api/projects → 200 +``` +TOKEN= +curl -s -w '\nHTTP_CODE:%{http_code}' http://localhost:3001/api/projects \ + -H "Authorization: Bearer $TOKEN" +``` +**Expected:** 200 +**Actual:** 200 ✅ (project list returned) + +## Smoke Test + +- Backend starts without errors: ✅ +- Server listens on port 3001: ✅ +- Yjs persistence initialized: ✅ +- Auth middleware correctly blocks unauthenticated /api/ requests: ✅ +- Auth middleware correctly skips /api/auth/login, /api/auth/register, /api/health: ✅ +- Auth middleware correctly skips non-/api/ routes (static files): ✅ +- Valid Bearer token grants access to protected routes: ✅ +- CORS restricted to allowed origins (web-cad-neu.server.media-on.de, localhost:5173, localhost:8082): ✅ + +## Changes Summary + +### server.ts — Auth Middleware (Issue #1) +Added `onRequest` hook after `authService` creation, before route registrations: +- Skips `/api/auth/login`, `/api/auth/register`, `/api/health` +- Skips all non-`/api/` routes (static files, WebSocket) +- Extracts Bearer token from Authorization header +- Validates via `authService.getUserFromSession(token)` +- Returns 401 if no token or invalid session +- Attaches user to `(request as any).user` for route handlers + +### server.ts — CORS Fix (Issue #3) +Changed `origin: true` to restrictive config: +- Allows requests with no origin (same-origin, curl) +- Allows known origins: `https://web-cad-neu.server.media-on.de`, `http://localhost:5173`, `http://localhost:8082` +- Rejects all other origins + +## Known Issues +- None