import { describe, expect, it } from 'vitest'; import { createStaticArtifactSnapshot, startStaticReleaseServer } from '@electron/services/static-release-server'; function fixture() { const source = [ { path: 'index.html', bytes: Buffer.from('
ok
') }, { path: 'assets/app.js', bytes: Buffer.from('globalThis.ok=true') }, ]; return { snapshot: createStaticArtifactSnapshot(source), source }; } describe('startStaticReleaseServer', () => { it('serves only exact regular files under an unguessable root', async () => { const { snapshot, source } = fixture(); source[0].bytes.fill(0); const server = await startStaticReleaseServer(snapshot); try { const entry = new URL(server.entryUrl); expect(entry.hostname).toBe('127.0.0.1'); expect(entry.pathname).toMatch(/^\/[a-f0-9]{48}\/index\.html$/); const response = await fetch(server.entryUrl); expect(await response.text()).toBe('
ok
'); expect(response.headers.get('cache-control')).toBe('no-store'); expect((await fetch(new URL('missing', server.entryUrl))).status).toBe(404); expect((await fetch(new URL('.', server.entryUrl))).status).toBe(404); expect((await fetch(server.entryUrl, { method: 'POST' })).status).toBe(405); } finally { await server.close(); } await expect(fetch(server.entryUrl)).rejects.toThrow(); }); it('rejects traversal and backslashes while serving GET/HEAD from memory', async () => { const server = await startStaticReleaseServer(fixture().snapshot); try { const entry = new URL(server.entryUrl); const prefix = entry.pathname.slice(0, entry.pathname.lastIndexOf('/') + 1); for (const path of [`${prefix}%2e%2e%2findex.html`, `${prefix}assets%5capp.js`]) { const response = await fetch(`${entry.origin}${path}`); expect(response.status).toBe(404); } const scriptUrl = `${entry.origin}${prefix}assets/app.js`; expect((await fetch(scriptUrl)).headers.get('content-type')).toBe('text/javascript; charset=utf-8'); const head = await fetch(scriptUrl, { method: 'HEAD' }); expect(head.status).toBe(200); expect(head.headers.get('content-length')).toBe(String(Buffer.byteLength('globalThis.ok=true'))); expect(await head.text()).toBe(''); } finally { await server.close(); } }); it('rejects forged, duplicate and unsafe snapshots', async () => { await expect(startStaticReleaseServer({} as never)).rejects.toThrow('Main-owned'); for (const files of [ [{ path: '../index.html', bytes: Buffer.from('bad') }], [{ path: 'index.html', bytes: Buffer.from('a') }, { path: 'INDEX.HTML', bytes: Buffer.from('b') }], ]) { expect(() => createStaticArtifactSnapshot(files)).toThrow(); } }); it.each([ ['source.map', 'application/json; charset=utf-8'], ['sound.ogg', 'audio/ogg'], ['notes.txt', 'text/plain; charset=utf-8'], ])('serves %s with the production media type', async (path, expectedType) => { const snapshot = createStaticArtifactSnapshot([ { path: 'index.html', bytes: Buffer.from('
ok
') }, { path, bytes: Buffer.from('data') }, ]); const server = await startStaticReleaseServer(snapshot); try { const entry = new URL(server.entryUrl); const prefix = entry.pathname.slice(0, entry.pathname.lastIndexOf('/') + 1); const response = await fetch(`${entry.origin}${prefix}${path}`); expect(response.headers.get('content-type')).toBe(expectedType); } finally { await server.close(); } }); });