@@ -3,51 +3,52 @@ import { type SecHeaders } from "./types.js";
3
3
import crypto from "node:crypto" ;
4
4
import { appendHeader } from "vinxi/http" ;
5
5
import { DEFAULT_HEADERS , HEADER_NAMES } from "./defaults.js" ;
6
- import { keyIsHeader } from "./utils.js" ;
7
- import { generateCSP } from "./lib/csp.js" ;
6
+ import { deepFallbackMerge , keyIsHeader } from "./utils.js" ;
7
+ import { chooseCSP , generateCSP } from "./lib/csp.js" ;
8
8
9
- export const secureRequest = ( options ?: SecHeaders ) => ( event : FetchEvent ) => {
10
- const settings : SecHeaders = { ...DEFAULT_HEADERS , ...options } ;
11
-
12
- const chooseCSP = ( ) => {
13
- if ( ! settings . csp ) {
14
- return ;
15
- }
16
- if ( process . env . NODE_ENV === "development" ) {
17
- return settings . csp . dev || settings . csp . prod ;
18
- } else {
19
- return settings . csp . prod ;
20
- }
9
+ const h3Attacher =
10
+ ( event : FetchEvent [ "nativeEvent" ] ) => ( key : string , headerValue : string ) => {
11
+ appendHeader ( event , key , headerValue ) ;
21
12
} ;
22
13
23
- const nonce = crypto . randomBytes ( 16 ) . toString ( "base64" ) ;
24
- event . locals . nonce = nonce ;
25
-
14
+ function attachSecHeaders (
15
+ settings : SecHeaders ,
16
+ attacher : ReturnType < typeof h3Attacher > ,
17
+ ) {
26
18
const entries = Object . entries ( settings ) as Array <
27
19
[ keyof SecHeaders , string | null ]
28
20
> ;
29
-
30
- entries . forEach ( ( [ configKey , headerValue ] ) => {
21
+ for ( const [ configKey , headerValue ] of entries ) {
31
22
if ( headerValue === null ) {
32
23
return ;
33
24
}
34
25
35
26
if ( keyIsHeader ( configKey ) ) {
36
- const key = HEADER_NAMES [ configKey ] ;
37
-
38
- appendHeader ( event . nativeEvent , key , headerValue ) ;
27
+ attacher ( HEADER_NAMES [ configKey ] , headerValue ) ;
39
28
}
40
- } ) ;
41
-
42
- const csp = chooseCSP ( ) ;
43
-
44
- if ( csp ) {
45
- appendHeader (
46
- event . nativeEvent ,
47
- csp . cspBlock || ! csp . cspReportOnly
48
- ? "Content-Security-Policy"
49
- : "Content-Security-Policy-Report-Only" ,
50
- generateCSP ( csp . value , nonce ) ,
51
- ) ;
52
29
}
53
- } ;
30
+ }
31
+
32
+ // SolidStart FetchEvent is H3Event["context"]
33
+ export const secureRequest =
34
+ ( options ?: Partial < SecHeaders > ) => ( event : FetchEvent ) => {
35
+ const settings = options
36
+ ? deepFallbackMerge < SecHeaders > ( options , DEFAULT_HEADERS )
37
+ : DEFAULT_HEADERS ;
38
+ const addHeader = h3Attacher ( event . nativeEvent ) ;
39
+ const csp = chooseCSP ( settings ) ;
40
+
41
+ const nonce = crypto . randomBytes ( 16 ) . toString ( "base64" ) ;
42
+ event . locals . nonce = nonce ;
43
+
44
+ attachSecHeaders ( settings , addHeader ) ;
45
+
46
+ if ( csp ) {
47
+ addHeader (
48
+ csp . cspBlock || ! csp . cspReportOnly
49
+ ? "Content-Security-Policy"
50
+ : "Content-Security-Policy-Report-Only" ,
51
+ generateCSP ( csp . value , nonce ) ,
52
+ ) ;
53
+ }
54
+ } ;
0 commit comments