39 lines
1.9 KiB
TypeScript
39 lines
1.9 KiB
TypeScript
import { test, expect, env, seedUsers, ApiClient } from '@e2e'
|
|
|
|
// What the backend itself promises about cookies and cross-origin access.
|
|
// (Security headers such as HSTS and CSP come from the host's nginx, which is not
|
|
// in this repo, so they are checked against a deployment, not here.)
|
|
|
|
test.describe('security basics', () => {
|
|
test('sign-in tokens are HttpOnly, Secure cookies @security', async ({ playwright }) => {
|
|
const context = await playwright.request.newContext()
|
|
const response = await context.post(`${env.apiUrl}/users/login`, {
|
|
form: { username: seedUsers.admin.email, password: seedUsers.admin.password },
|
|
})
|
|
expect(response.ok()).toBe(true)
|
|
const cookies = response.headersArray().filter((h) => h.name.toLowerCase() === 'set-cookie').map((h) => h.value)
|
|
for (const name of ['access_token', 'refresh_token']) {
|
|
const cookie = cookies.find((c) => c.startsWith(`${name}=`))
|
|
expect(cookie, `${name} cookie`).toBeDefined()
|
|
expect(cookie).toMatch(/;\s*HttpOnly/i)
|
|
expect(cookie).toMatch(/;\s*Secure/i)
|
|
}
|
|
await context.dispose()
|
|
})
|
|
|
|
test('another website cannot call the API with a visitor\'s credentials @security', async ({ request }) => {
|
|
const response = await new ApiClient(request).raw('OPTIONS', '/users/me', {
|
|
headers: { Origin: 'https://evil.example', 'Access-Control-Request-Method': 'GET' },
|
|
})
|
|
expect(response.headers()['access-control-allow-origin']).toBeUndefined()
|
|
})
|
|
|
|
test('the dashboard\'s own origin is allowed @security', async ({ request }) => {
|
|
const response = await new ApiClient(request).raw('OPTIONS', '/users/me', {
|
|
headers: { Origin: env.frontendUrl, 'Access-Control-Request-Method': 'GET' },
|
|
})
|
|
expect(response.headers()['access-control-allow-origin']).toBe(env.frontendUrl)
|
|
expect(response.headers()['access-control-allow-credentials']).toBe('true')
|
|
})
|
|
})
|