mirror of
https://github.com/EKKOLearnAI/hermes-web-ui.git
synced 2026-07-11 03:00:49 +00:00
75 lines
3.1 KiB
TypeScript
75 lines
3.1 KiB
TypeScript
import http from 'http'
|
|
import Koa from 'koa'
|
|
import { afterEach, describe, expect, it } from 'vitest'
|
|
import {
|
|
createCorsOriginResolver,
|
|
isOriginAllowed,
|
|
securityHeaders,
|
|
shouldRejectUpgradeOrigin,
|
|
} from '../../packages/server/src/security'
|
|
|
|
function fakeCtx(origin: string, host: string) {
|
|
return {
|
|
host,
|
|
get(name: string) {
|
|
return name.toLowerCase() === 'origin' ? origin : ''
|
|
},
|
|
} as any
|
|
}
|
|
|
|
describe('server security policy', () => {
|
|
let servers: http.Server[] = []
|
|
|
|
afterEach(async () => {
|
|
const closing = servers.map(server => new Promise<void>((resolve) => server.close(() => resolve())))
|
|
servers = []
|
|
await Promise.all(closing)
|
|
})
|
|
|
|
it('allows same-host browser origins without enabling wildcard CORS', async () => {
|
|
const resolveOrigin = createCorsOriginResolver('')
|
|
|
|
await expect(resolveOrigin(fakeCtx('http://127.0.0.1:8648', '127.0.0.1:8648'))).resolves.toBe('http://127.0.0.1:8648')
|
|
await expect(resolveOrigin(fakeCtx('https://evil.example', '127.0.0.1:8648'))).resolves.toBe('')
|
|
})
|
|
|
|
it('allows configured origins and explicit wildcard opt-in only', () => {
|
|
expect(isOriginAllowed('https://app.example', '127.0.0.1:8648', 'https://app.example')).toBe(true)
|
|
expect(isOriginAllowed('https://evil.example', '127.0.0.1:8648', 'https://app.example')).toBe(false)
|
|
expect(isOriginAllowed('null', '127.0.0.1:8648', '')).toBe(false)
|
|
expect(isOriginAllowed('null', '127.0.0.1:8648', '*')).toBe(true)
|
|
expect(isOriginAllowed('https://evil.example', '127.0.0.1:8648', '*')).toBe(true)
|
|
})
|
|
|
|
it('rejects disallowed browser websocket upgrade origins', () => {
|
|
expect(shouldRejectUpgradeOrigin({ headers: { origin: 'https://evil.example', host: '127.0.0.1:8648' } } as any, '')).toBe(true)
|
|
expect(shouldRejectUpgradeOrigin({ headers: { origin: 'null', host: '127.0.0.1:8648' } } as any, '')).toBe(true)
|
|
expect(shouldRejectUpgradeOrigin({ headers: { origin: 'http://127.0.0.1:8648', host: '127.0.0.1:8648' } } as any, '')).toBe(false)
|
|
expect(shouldRejectUpgradeOrigin({ headers: { host: '127.0.0.1:8648' } } as any, '')).toBe(false)
|
|
})
|
|
|
|
it('adds baseline browser security headers', async () => {
|
|
const app = new Koa()
|
|
app.use(securityHeaders())
|
|
app.use((ctx) => {
|
|
ctx.body = { ok: true }
|
|
})
|
|
const server = app.listen(0)
|
|
servers.push(server)
|
|
await new Promise<void>((resolve) => server.once('listening', () => resolve()))
|
|
const address = server.address()
|
|
if (!address || typeof address === 'string') throw new Error('expected tcp server')
|
|
|
|
const response = await fetch(`http://127.0.0.1:${address.port}/health`, {
|
|
headers: { 'x-forwarded-proto': 'https' },
|
|
})
|
|
|
|
expect(response.headers.get('x-content-type-options')).toBe('nosniff')
|
|
expect(response.headers.get('x-frame-options')).toBe('DENY')
|
|
expect(response.headers.get('referrer-policy')).toBe('no-referrer')
|
|
expect(response.headers.get('cross-origin-opener-policy')).toBe('same-origin-allow-popups')
|
|
expect(response.headers.get('content-security-policy')).toContain("default-src 'self'")
|
|
expect(response.headers.get('strict-transport-security')).toContain('max-age=31536000')
|
|
})
|
|
})
|