// @vitest-environment node import { NextRequest } from 'next/server'; import { SignJWT } from 'jose'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { middleware } from './middleware'; /** * middleware.test — Desktop-Client-Cookie (260917-h2s), eigener describe-Block * neben den bestehenden Redirect-/Session-Faellen. `@vitest-environment node`, * weil `NextRequest`/`NextResponse` node-typische APIs (Headers, URL) nutzen, * die im jsdom-Standardmilieu der Suite nicht gebraucht werden. */ describe('middleware — Desktop-Client-Cookie (260917-h2s)', () => { beforeEach(() => { vi.stubEnv('JWT_SECRET', 'test-secret'); }); afterEach(() => { vi.unstubAllEnvs(); }); it('Test 1: /login?desktop=1 setzt das Cookie tessera_desktop=1', async () => { const req = new NextRequest('http://localhost:3000/login?desktop=1'); const res = await middleware(req); const setCookie = res.headers.get('set-cookie'); expect(setCookie).toContain('tessera_desktop=1'); expect(setCookie).toContain('Path=/'); expect(setCookie).toContain('Max-Age=31536000'); expect(setCookie).toContain('SameSite=lax'); expect(setCookie).not.toContain('Secure'); expect(setCookie).not.toContain('HttpOnly'); }); it('Test 2: /login ohne Parameter setzt kein Cookie', async () => { const req = new NextRequest('http://localhost:3000/login'); const res = await middleware(req); expect(res.headers.get('set-cookie')).toBeNull(); }); it('Test 3: /dashboard?desktop=1 ohne Session leitet um und setzt das Cookie', async () => { const req = new NextRequest('http://localhost:3000/dashboard?desktop=1'); const res = await middleware(req); expect(res.status).toBe(307); expect(res.headers.get('location')).toContain('/login'); expect(res.headers.get('set-cookie')).toContain('tessera_desktop=1'); }); it('Test 4: https setzt Secure', async () => { const req = new NextRequest('https://tessera.example.com/login?desktop=1'); const res = await middleware(req); expect(res.headers.get('set-cookie')).toContain('Secure'); }); it('Test 5: gueltiges JWT laesst die Anfrage durch und setzt trotzdem das Cookie', async () => { const token = await new SignJWT({ sub: 'u1' }) .setProtectedHeader({ alg: 'HS256' }) .setIssuedAt() .setExpirationTime('5m') .sign(new TextEncoder().encode('test-secret')); const req = new NextRequest('http://localhost:3000/dashboard?desktop=1', { headers: { cookie: `session=${token}` }, }); const res = await middleware(req); expect(res.headers.get('set-cookie')).toContain('tessera_desktop=1'); expect(res.headers.get('x-middleware-next')).toBe('1'); }); it('Test 6 (quick-260918-gza): /login mit dv/dc/dos setzt zusaetzlich tessera_desktop_client', async () => { const req = new NextRequest('http://localhost:3000/login?desktop=1&dv=1.2.0&dc=a6d1a64&dos=windows'); const res = await middleware(req); expect(res.cookies.get('tessera_desktop')?.value).toBe('1'); expect(res.cookies.get('tessera_desktop_client')?.value).toBe('1.2.0|a6d1a64|windows'); const setCookie = res.headers.get('set-cookie'); expect(setCookie).toContain('tessera_desktop_client=1.2.0%7Ca6d1a64%7Cwindows'); expect(setCookie).toContain('Max-Age=31536000'); expect(setCookie).toContain('Path=/'); // Kein HttpOnly fuer DIESES Cookie -- der bestehende tessera_desktop // liefert ebenfalls kein HttpOnly, darum genuegt die Wertpruefung oben. }); it('Test 7 (quick-260918-gza, alter Client): /login?desktop=1 ohne dv/dc/dos setzt kein tessera_desktop_client', async () => { const req = new NextRequest('http://localhost:3000/login?desktop=1'); const res = await middleware(req); expect(res.cookies.get('tessera_desktop')?.value).toBe('1'); expect(res.cookies.get('tessera_desktop_client')).toBeUndefined(); }); it('Test 8 (quick-260918-gza, Bereinigung): ungueltige oder fehlende Werte setzen kein tessera_desktop_client', async () => { const angleBrackets = new NextRequest( 'http://localhost:3000/login?desktop=1&dv=1.2.0%3Cscript%3E&dc=a6d1a64&dos=windows', ); expect((await middleware(angleBrackets)).cookies.get('tessera_desktop_client')).toBeUndefined(); const spaceInOs = new NextRequest( 'http://localhost:3000/login?desktop=1&dv=1.2.0&dc=a6d1a64&dos=win%20dows', ); expect((await middleware(spaceInOs)).cookies.get('tessera_desktop_client')).toBeUndefined(); const missingDv = new NextRequest('http://localhost:3000/login?desktop=1&dc=a6d1a64&dos=windows'); expect((await middleware(missingDv)).cookies.get('tessera_desktop_client')).toBeUndefined(); const emptyCommit = new NextRequest('http://localhost:3000/login?desktop=1&dv=1.2.0&dc=&dos=linux'); expect((await middleware(emptyCommit)).cookies.get('tessera_desktop_client')?.value).toBe('1.2.0||linux'); }); it('Test 9 (quick-260918-gza, Redirect-Pfad): /dashboard ohne Session setzt beide Cookies auf dem 307', async () => { const req = new NextRequest('http://localhost:3000/dashboard?desktop=1&dv=1.2.0&dc=a6d1a64&dos=linux'); const res = await middleware(req); expect(res.status).toBe(307); expect(res.headers.get('location')).toContain('/login'); expect(res.cookies.get('tessera_desktop')?.value).toBe('1'); expect(res.cookies.get('tessera_desktop_client')?.value).toBe('1.2.0|a6d1a64|linux'); }); });