-
-
Notifications
You must be signed in to change notification settings - Fork 424
Expand file tree
/
Copy pathsecurity-headers.spec.ts
More file actions
120 lines (104 loc) · 2.98 KB
/
security-headers.spec.ts
File metadata and controls
120 lines (104 loc) · 2.98 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
import { beforeEach, describe, expect, it, vi } from 'vitest'
const { useNuxt } = vi.hoisted(() => ({
useNuxt: vi.fn(),
}))
vi.mock('nuxt/kit', () => ({
defineNuxtModule: <T>(module: T) => module,
useNuxt,
}))
import securityHeadersModule from '../../../modules/security-headers'
type RouteRule = {
headers?: Record<string, string>
redirect?: string
}
type MockNuxt = {
options: {
app: {
head?: {
meta?: Array<Record<string, string>>
}
}
dev: boolean
devtools?: boolean | { enabled?: boolean }
routeRules: Record<string, RouteRule>
}
}
function createNuxt(options: Partial<MockNuxt['options']> = {}): MockNuxt {
return {
options: {
app: {},
dev: false,
devtools: false,
routeRules: {},
...options,
},
}
}
function getCsp(nuxt: MockNuxt) {
return nuxt.options.app.head?.meta?.find(meta => meta['http-equiv'] === 'Content-Security-Policy')
?.content
}
describe('security headers module', () => {
beforeEach(() => {
delete process.env.TEST
useNuxt.mockReset()
})
it('keeps security headers and only relaxes devtools-specific bits in dev', () => {
const nuxt = createNuxt({
dev: true,
devtools: { enabled: true },
routeRules: {
'/**': {
headers: {
'Permissions-Policy': 'camera=()',
},
},
'/__nuxt_devtools__/**': {
headers: {
'Cache-Control': 'no-store',
},
redirect: '/devtools',
},
},
})
useNuxt.mockReturnValue(nuxt)
securityHeadersModule.setup()
const csp = getCsp(nuxt)
expect(csp).toContain('ws://localhost:*')
expect(csp).toContain(
"frame-src https://bsky.app https://pdsmoover.com https://www.youtube-nocookie.com/ 'self'",
)
expect(nuxt.options.routeRules['/**']?.headers).toEqual(
expect.objectContaining({
'Permissions-Policy': 'camera=()',
'Referrer-Policy': 'strict-origin-when-cross-origin',
'X-Content-Type-Options': 'nosniff',
'X-Frame-Options': 'DENY',
}),
)
expect(nuxt.options.routeRules['/__nuxt_devtools__/**']).toEqual({
headers: {
'Cache-Control': 'no-store',
'Permissions-Policy': 'camera=()',
'Referrer-Policy': 'strict-origin-when-cross-origin',
'X-Content-Type-Options': 'nosniff',
'X-Frame-Options': 'SAMEORIGIN',
},
redirect: '/devtools',
})
})
it('does not apply devtools relaxations when devtools are disabled via object config', () => {
const nuxt = createNuxt({
dev: true,
devtools: { enabled: false },
})
useNuxt.mockReturnValue(nuxt)
securityHeadersModule.setup()
const csp = getCsp(nuxt)
expect(csp).not.toContain('ws://localhost:*')
expect(csp).not.toContain(
"frame-src https://bsky.app https://pdsmoover.com https://www.youtube-nocookie.com/ 'self'",
)
expect(nuxt.options.routeRules['/__nuxt_devtools__/**']).toBeUndefined()
})
})