Skip to content

Commit 15142c0

Browse files
authored
Merge pull request #429 from Baroshem/feat/unified-router-context
feat(core): unified router context
2 parents 15bc896 + ea7d63a commit 15142c0

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

71 files changed

+4683
-3879
lines changed

docs/components/content/Illustration.vue

+28-6
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,10 @@
227227
filterUnits="userSpaceOnUse"
228228
color-interpolation-filters="sRGB"
229229
>
230-
<feFlood flood-opacity="0" result="BackgroundImageFix" />
230+
<feFlood
231+
flood-opacity="0"
232+
result="BackgroundImageFix"
233+
/>
231234
<feColorMatrix
232235
in="SourceAlpha"
233236
type="matrix"
@@ -236,7 +239,10 @@
236239
/>
237240
<feOffset dy="4" />
238241
<feGaussianBlur stdDeviation="2" />
239-
<feComposite in2="hardAlpha" operator="out" />
242+
<feComposite
243+
in2="hardAlpha"
244+
operator="out"
245+
/>
240246
<feColorMatrix
241247
type="matrix"
242248
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.44 0"
@@ -262,7 +268,11 @@
262268
gradientUnits="userSpaceOnUse"
263269
>
264270
<stop stop-color="white" />
265-
<stop offset="1" stop-color="white" stop-opacity="0" />
271+
<stop
272+
offset="1"
273+
stop-color="white"
274+
stop-opacity="0"
275+
/>
266276
</linearGradient>
267277
<linearGradient
268278
id="paint1_linear_1180_138"
@@ -273,7 +283,11 @@
273283
gradientUnits="userSpaceOnUse"
274284
>
275285
<stop stop-color="white" />
276-
<stop offset="1" stop-color="white" stop-opacity="0" />
286+
<stop
287+
offset="1"
288+
stop-color="white"
289+
stop-opacity="0"
290+
/>
277291
</linearGradient>
278292
<linearGradient
279293
id="paint2_linear_1180_138"
@@ -284,10 +298,18 @@
284298
gradientUnits="userSpaceOnUse"
285299
>
286300
<stop stop-color="white" />
287-
<stop offset="1" stop-color="white" stop-opacity="0" />
301+
<stop
302+
offset="1"
303+
stop-color="white"
304+
stop-opacity="0"
305+
/>
288306
</linearGradient>
289307
<clipPath id="clip0_1180_138">
290-
<rect width="403" height="226" fill="white" />
308+
<rect
309+
width="403"
310+
height="226"
311+
fill="white"
312+
/>
291313
</clipPath>
292314
</defs>
293315
</svg>

docs/components/content/Releases.vue

+6-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
<template>
22
<GithubReleases v-slot="{ releases }">
3-
<div v-for="release in releases" :key="release.name">
3+
<div
4+
v-for="release in releases"
5+
:key="release.name"
6+
>
47
<ProseH2 :id="release.name">
58
<Badge :type="release.prerelease ? 'warning' : 'info'">
6-
{{ release.prerelease ? "Pre-release" : "Release" }} </Badge
7-
>{{ release.name }}
9+
{{ release.prerelease ? "Pre-release" : "Release" }}
10+
</Badge>{{ release.name }}
811
</ProseH2>
912
<details>
1013
<summary>

docs/content/1.documentation/1.getting-started/3.usage.md

+114-37
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ Nuxt Security by default registers a set of **global** Nuxt `routeRules` that wi
1414

1515
## Global configuration
1616

17-
To override default behavior for Nuxt Security globally, follow this pattern:
17+
To override the default behavior for Nuxt Security globally, follow this pattern:
1818

19-
```ts
19+
```ts{}[nuxt.config.ts]
2020
export default defineNuxtConfig({
2121
security: {
2222
headers: {
@@ -36,7 +36,7 @@ export default defineNuxtConfig({
3636

3737
To enable per-route configuration, use the `routeRules` like following:
3838

39-
```ts
39+
```ts{}[nuxt.config.ts]
4040
export default defineNuxtConfig({
4141
routeRules: {
4242
'/custom-route': {
@@ -74,11 +74,96 @@ If your application defines conflicting headers at both levels, the `security` p
7474

7575
For more information on `routeRules` please see the [Nuxt documentation](https://nuxt.com/docs/guide/concepts/rendering#hybrid-rendering)
7676

77-
## Nested route configuration
7877

79-
Nuxt Security will recursively resolve nested routes using your `routeRules` definitions:
78+
## Runtime hooks
8079

81-
```ts
80+
If you need to change the configuration at runtime, it is possible to do it through the `nuxt-security:routeRules` hook.
81+
82+
In order to use the runtime hooks feature, you will need to create a Nitro plugin.
83+
84+
In the `server/plugins` directory, create a new file with the name of your choice:
85+
86+
```ts{}[server/plugins/filename.ts]
87+
export default defineNitroPlugin((nitroApp) => {
88+
nitroApp.hooks.hook('nuxt-security:routeRules', async(routeRules) => {
89+
// You can fetch configuration data asynchronously from an external source
90+
const validDomain = await $fetch('https://some-site.com/rules')
91+
// You can then override the security options of any route
92+
routeRules['/some/route'] = {
93+
headers: {
94+
contentSecurityPolicy: {
95+
"connect-src": ["'self'", validDomain]
96+
},
97+
xFrameOptions: false
98+
},
99+
hidePoweredBy: false
100+
}
101+
})
102+
})
103+
```
104+
105+
## Configuration priority order
106+
107+
Nuxt-Security applies your rules in the following prority order:
108+
109+
110+
1. Default rules
111+
112+
Nuxt-Security default values.
113+
See [here](/documentation/getting-started/configuration#default)
114+
115+
116+
2. Inline module options
117+
118+
```ts{}[nuxt.config.ts]
119+
export default defineNuxtConfig({
120+
modules: [
121+
['nuxt-security', { /* Inline Options */ }]
122+
]
123+
})
124+
```
125+
126+
127+
3. Global module options
128+
129+
```ts{}[nuxt.config.ts]
130+
export default defineNuxtConfig({
131+
security: {
132+
// Global Options
133+
}
134+
})
135+
```
136+
137+
4. Per-route options
138+
139+
```ts{}[nuxt.config.ts]
140+
export default defineNuxtConfig({
141+
routeRules: {
142+
'/some-route': {
143+
security: {
144+
// Per-route Options
145+
}
146+
}
147+
}
148+
})
149+
```
150+
151+
5. Runtime-hook options
152+
153+
```ts{}[server/plugins/filename.ts]
154+
export default defineNitroPlugin((nitroApp) => {
155+
nitroApp.hooks.hook('nuxt-security:routeRules', routeRules => {
156+
// Runtime Options
157+
})
158+
})
159+
```
160+
161+
162+
## Route merging strategy (nested router)
163+
164+
If you define nested route rules in your `routeRules` definitions, Nuxt Security will recursively merge the options to resolve the security rules of a given route:
165+
166+
```ts{}[nuxt.config.ts]
82167
export default defineNuxtConfig({
83168
// Global
84169
security: {
@@ -146,7 +231,7 @@ experimental: {
146231

147232
To disable certain middleware or headers, follow this pattern:
148233

149-
```ts
234+
```ts{}[nuxt.config.ts]
150235
export default defineNuxtConfig({
151236
// global
152237
security: {
@@ -170,40 +255,32 @@ export default defineNuxtConfig({
170255
})
171256
```
172257

173-
## Runtime configuration
174258

175-
If you need to change the headers configuration at runtime, it is possible to do it through `nuxt-security:headers` hook.
259+
## Overwriting or modifying existing values
176260

177-
### Enabling the option
261+
Within your runtime hooks, you can either overwrite or modify the existing values for any security option.
262+
One of the easiest way to merge existing rules with your own is to use `defu`:
178263

179-
This feature is optional, you can enable it with
264+
```ts{}[server/plugins/filename.ts]
265+
import defu from 'defu'
180266
181-
```ts
182-
export default defineNuxtConfig({
183-
modules: ['nuxt-security'],
184-
security: {
185-
runtimeHooks: true
186-
}
187-
})
188-
```
189-
190-
### Usage
191-
192-
Within your nitro plugin. You can override the previous configuration of a route with `nuxt-security:headers`.
193-
194-
```ts
195267
export default defineNitroPlugin((nitroApp) => {
196-
nitroApp.hooks.hook('nuxt-security:ready', () => {
197-
nitroApp.hooks.callHook('nuxt-security:headers',
198-
{
199-
route: '/**',
200-
headers: {
201-
contentSecurityPolicy: {
202-
"script-src": ["'self'", "'unsafe-inline'"],
203-
},
204-
xFrameOptions: false
205-
}
206-
})
207-
})
268+
nitroApp.hooks.hook('nuxt-security:routeRules', async(routeRules) => {
269+
// You can fetch configuration data asynchronously from an external source
270+
const validDomain = await $fetch('https://some-site.com/rules')
271+
// You can then override the security options of any route
272+
routeRules['/some/route'] = defu(
273+
{
274+
headers: {
275+
contentSecurityPolicy: {
276+
"connect-src": ["'self'", validDomain]
277+
},
278+
xFrameOptions: false
279+
},
280+
hidePoweredBy: false
281+
},
282+
routeRules['/some/route']
283+
)
284+
})
208285
})
209286
```

docs/content/1.documentation/2.headers/1.csp.md

+31-47
Original file line numberDiff line numberDiff line change
@@ -54,46 +54,34 @@ The `contentSecurityPolicy` header can be configured with following values.
5454

5555
```ts
5656
contentSecurityPolicy: {
57-
'child-src'?: CSPSourceValue[] | string | false;
58-
'connect-src'?: CSPSourceValue[] | string | false;
59-
'default-src'?: CSPSourceValue[] | string | false;
60-
'font-src'?: CSPSourceValue[] | string | false;
61-
'frame-src'?: CSPSourceValue[] | string | false;
62-
'img-src'?: CSPSourceValue[] | string | false;
63-
'manifest-src'?: CSPSourceValue[] | string | false;
64-
'media-src'?: CSPSourceValue[] | string | false;
65-
'object-src'?: CSPSourceValue[] | string | false;
66-
'prefetch-src'?: CSPSourceValue[] | string | false;
67-
'script-src'?: CSPSourceValue[] | string | false;
68-
'script-src-elem'?: CSPSourceValue[] | string | false;
69-
'script-src-attr'?: CSPSourceValue[] | string | false;
70-
'style-src'?: CSPSourceValue[] | string | false;
71-
'style-src-elem'?: CSPSourceValue[] | string | false;
72-
'style-src-attr'?: CSPSourceValue[] | string | false;
73-
'worker-src'?: CSPSourceValue[] | string | false;
74-
'base-uri'?: CSPSourceValue[] | string | false;
75-
'sandbox'?: CSPSandboxValue[] | string | false;
76-
'form-action'?: CSPSourceValue[] | string | false;
77-
'frame-ancestors'?: ("'self'" | "'none'" | string)[] | string | false;
78-
'navigate-to'?: ("'self'" | "'none'" | "'unsafe-allow-redirects'" | string)[] | string | false;
79-
'report-uri'?: string[] | string | false;
57+
'child-src'?: CSPSourceValue[] false;
58+
'connect-src'?: CSPSourceValue[] | false;
59+
'default-src'?: CSPSourceValue[] | false;
60+
'font-src'?: CSPSourceValue[] | false;
61+
'frame-src'?: CSPSourceValue[] | false;
62+
'img-src'?: CSPSourceValue[] | false;
63+
'manifest-src'?: CSPSourceValue[] | false;
64+
'media-src'?: CSPSourceValue[] | false;
65+
'object-src'?: CSPSourceValue[] | false;
66+
'prefetch-src'?: CSPSourceValue[] | false;
67+
'script-src'?: CSPSourceValue[] | false;
68+
'script-src-elem'?: CSPSourceValue[] | false;
69+
'script-src-attr'?: CSPSourceValue[] | false;
70+
'style-src'?: CSPSourceValue[] | false;
71+
'style-src-elem'?: CSPSourceValue[] | false;
72+
'style-src-attr'?: CSPSourceValue[] | false;
73+
'worker-src'?: CSPSourceValue[] | false;
74+
'base-uri'?: CSPSourceValue[] | false;
75+
'sandbox'?: CSPSandboxValue[] | false;
76+
'form-action'?: CSPSourceValue[] | false;
77+
'frame-ancestors'?: ("'self'" | "'none'" | string)[] | false;
78+
'navigate-to'?: ("'self'" | "'none'" | "'unsafe-allow-redirects'" | string)[] | false;
79+
'report-uri'?: string[] | false;
8080
'report-to'?: string | false;
8181
'upgrade-insecure-requests'?: boolean;
8282
} | false
8383
```
8484

85-
::callout
86-
#summary
87-
Array and String syntaxes
88-
#content
89-
Directives can be written using the array syntax or the string syntax.
90-
91-
- Array syntax for clear definition of policies: `"script-src": ["'self'", "https:", "'unsafe-inline'"]`
92-
- String syntax if you prefer to stick with native MDN syntax: `"script-src": "'self' https: 'unsafe-inline'"`
93-
94-
Please note that these two syntaxes behave differently for deeply nested route definitions: see [Per-route Configuration](#per-route-configuration)
95-
::
96-
9785
::callout
9886
#summary
9987
CSPSourceValue type
@@ -342,7 +330,10 @@ Note that this is not necessary if you use our default configuration settings.
342330

343331
## Per-route configuration
344332

345-
All Content Security Policy options can be defined on a per-route level.
333+
All Content Security Policy options can be defined on a per-route level.
334+
335+
As examplified below, Nuxt Security resolves the `contentSecurityPolicy` options substitutively at each nested level.
336+
346337
```ts
347338
export default defineNuxtConfig({
348339
// Global
@@ -367,17 +358,17 @@ export default defineNuxtConfig({
367358
'/some-prefix/some-route/**': {
368359
security: {
369360
headers: {
370-
contentSecurityPolicy: { // With array syntax : additive
371-
'img-src': ["https:"] // Self-hosted AND https: images can be loaded for routes beginning with /some-prefix/some-route/
361+
contentSecurityPolicy: {
362+
'img-src': ["'self'", "https:"] // Self-hosted AND https: images can be loaded for routes beginning with /some-prefix/some-route/
372363
}
373364
}
374365
}
375366
},
376367
'/some-prefix/some-route/some-page': {
377368
security: {
378369
headers: {
379-
contentSecurityPolicy: { // With string syntax : substitutive
380-
'img-src': 'self' // ONLY self-hosted images can be loaded on /some-prefix/some-route/some-page
370+
contentSecurityPolicy: {
371+
'img-src': ["'self'"] // ONLY self-hosted images can be loaded on /some-prefix/some-route/some-page
381372
}
382373
}
383374
}
@@ -386,13 +377,6 @@ export default defineNuxtConfig({
386377
})
387378
```
388379

389-
Nuxt Security resolves the `contentSecurityPolicy` options using the native Nitro router strategy:
390-
- **Additive merging** with the array syntax: If you write your rules with the array syntax (e.g. `"img-src": ["'self'", "https:"]`), the new route policies will be added to the policies defined for higher-level routes.
391-
Use this strategy if you need to add specific policy values to your route without deleting the existing ones.
392-
393-
- **Substitutive merging** with the string syntax: If you write your rules with the string syntax (e.g. `"img-src": "'self' https:"`), the new route policies will be substituted to the policies defined for higher-level routes.
394-
Use this strategy if you need to delete existing policies before setting your specific route policies.
395-
396380

397381
## Including External Scripts
398382

0 commit comments

Comments
 (0)