feat(web): Herkunft der Fehlermeldung — Cookie tessera_desktop_client und Client-Felder in der Nutzlast

Die Middleware liest jetzt zusaetzlich dv/dc/dos aus der Anfrage und legt
daraus das Cookie tessera_desktop_client an (bereinigt per Muster, nur
wenn alle drei Werte gueltig sind); desktop-client.ts liest es zurueck.
Der Fehler-melden-Dialog fuellt daraus vier neue Nutzlastfelder
(clientKind/clientOs/clientVersion/clientCommit), damit die API die
Herkunft der Meldung ausweisen kann. Ohne das zweite Cookie (alter
Client) bleibt es bei "Desktop-App (unbekannt)".

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016g2npLxzH5gZpg8s2S6vKh
This commit is contained in:
2026-09-18 12:36:19 +02:00
parent b03cb211b3
commit f2457113a2
8 changed files with 376 additions and 10 deletions
+48
View File
@@ -65,4 +65,52 @@ describe('middleware — Desktop-Client-Cookie (260917-h2s)', () => {
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');
});
});