@@ -18,6 +18,9 @@ const getCsps = (html: string) => {
18
18
const ONE_HASH_CSP =
19
19
/ s c r i p t - s r c ' s t r i c t - d y n a m i c ' ' s h a 2 5 6 - [ ^ ' ] + ' h t t p s : ' u n s a f e - i n l i n e ' ; o b j e c t - s r c ' n o n e ' ; b a s e - u r i ' s e l f ' ; / ;
20
20
21
+ const TWO_HASH_CSP =
22
+ / s c r i p t - s r c ' s t r i c t - d y n a m i c ' (?: ' s h a 2 5 6 - [ ^ ' ] + ' ) { 2 } h t t p s : ' u n s a f e - i n l i n e ' ; o b j e c t - s r c ' n o n e ' ; b a s e - u r i ' s e l f ' ; / ;
23
+
21
24
const FOUR_HASH_CSP =
22
25
/ s c r i p t - s r c ' s t r i c t - d y n a m i c ' (?: ' s h a 2 5 6 - [ ^ ' ] + ' ) { 4 } h t t p s : ' u n s a f e - i n l i n e ' ; o b j e c t - s r c ' n o n e ' ; b a s e - u r i ' s e l f ' ; / ;
23
26
@@ -55,7 +58,7 @@ describe('auto-csp', () => {
55
58
const csps = getCsps ( result ) ;
56
59
expect ( csps . length ) . toBe ( 1 ) ;
57
60
expect ( csps [ 0 ] ) . toMatch ( ONE_HASH_CSP ) ;
58
- expect ( result ) . toContain ( `var scripts = [['./main.js', undefined , false, false]];` ) ;
61
+ expect ( result ) . toContain ( `var scripts = [['./main.js', '' , false, false]];` ) ;
59
62
} ) ;
60
63
61
64
it ( 'should rewrite a single source script in place' , async ( ) => {
@@ -75,14 +78,15 @@ describe('auto-csp', () => {
75
78
expect ( csps [ 0 ] ) . toMatch ( ONE_HASH_CSP ) ;
76
79
// Our loader script appears after the HTML text content.
77
80
expect ( result ) . toMatch (
78
- / S o m e t e x t < \/ d i v > \s * < s c r i p t > \s * v a r s c r i p t s = \[ \[ ' .\/ m a i n .j s ' , u n d e f i n e d , f a l s e , f a l s e \] \] ; / ,
81
+ / S o m e t e x t < \/ d i v > \s * < s c r i p t > \s * v a r s c r i p t s = \[ \[ ' .\/ m a i n .j s ' , ' ' , f a l s e , f a l s e \] \] ; / ,
79
82
) ;
80
83
} ) ;
81
84
82
85
it ( 'should rewrite a multiple source scripts with attributes' , async ( ) => {
83
86
const result = await autoCsp ( `
84
87
<html>
85
88
<head>
89
+ <script src="./head.js"></script>
86
90
</head>
87
91
<body>
88
92
<script src="./main1.js"></script>
@@ -96,13 +100,15 @@ describe('auto-csp', () => {
96
100
97
101
const csps = getCsps ( result ) ;
98
102
expect ( csps . length ) . toBe ( 1 ) ;
99
- expect ( csps [ 0 ] ) . toMatch ( ONE_HASH_CSP ) ;
103
+ expect ( csps [ 0 ] ) . toMatch ( TWO_HASH_CSP ) ;
100
104
expect ( result ) . toContain (
101
105
// eslint-disable-next-line max-len
102
- `var scripts = [['./main1.js', undefined , false, false],['./main2.js', undefined , true, false],['./main3.js', 'module', true, true]];` ,
106
+ `var scripts = [['./main1.js', '' , false, false],['./main2.js', '' , true, false],['./main3.js', 'module', true, true]];` ,
103
107
) ;
104
- // Only one loader script is created.
105
- expect ( Array . from ( result . matchAll ( / < s c r i p t > / g) ) . length ) . toEqual ( 1 ) ;
108
+ // Head loader script is in the head.
109
+ expect ( result ) . toContain ( `</script></head>` ) ;
110
+ // Only two loader scripts are created.
111
+ expect ( Array . from ( result . matchAll ( / < s c r i p t > / g) ) . length ) . toEqual ( 2 ) ;
106
112
} ) ;
107
113
108
114
it ( 'should rewrite source scripts with weird URLs' , async ( ) => {
@@ -160,14 +166,40 @@ describe('auto-csp', () => {
160
166
// Loader script for main.js and main2.js appear after 'foo' and before 'bar'.
161
167
expect ( result ) . toMatch (
162
168
// eslint-disable-next-line max-len
163
- / c o n s o l e .l o g \( ' f o o ' \) ; < \/ s c r i p t > \s * < s c r i p t > \s * v a r s c r i p t s = \[ \[ ' .\/ m a i n .j s ' , u n d e f i n e d , f a l s e , f a l s e \] , \[ ' .\/ m a i n 2 .j s ' , u n d e f i n e d , f a l s e , f a l s e \] \] ; [ \s \S ] * c o n s o l e .l o g \( ' b a r ' \) ; / ,
169
+ / c o n s o l e .l o g \( ' f o o ' \) ; < \/ s c r i p t > \s * < s c r i p t > \s * v a r s c r i p t s = \[ \[ ' .\/ m a i n .j s ' , ' ' , f a l s e , f a l s e \] , \[ ' .\/ m a i n 2 .j s ' , ' ' , f a l s e , f a l s e \] \] ; [ \s \S ] * c o n s o l e .l o g \( ' b a r ' \) ; / ,
164
170
) ;
165
171
// Loader script for main3.js and main4.js appear after 'bar'.
166
172
expect ( result ) . toMatch (
167
173
// eslint-disable-next-line max-len
168
- / c o n s o l e .l o g \( ' b a r ' \) ; < \/ s c r i p t > \s * < s c r i p t > \s * v a r s c r i p t s = \[ \[ ' .\/ m a i n 3 .j s ' , u n d e f i n e d , f a l s e , f a l s e \] , \[ ' .\/ m a i n 4 .j s ' , u n d e f i n e d , f a l s e , f a l s e \] \] ; / ,
174
+ / c o n s o l e .l o g \( ' b a r ' \) ; < \/ s c r i p t > \s * < s c r i p t > \s * v a r s c r i p t s = \[ \[ ' .\/ m a i n 3 .j s ' , ' ' , f a l s e , f a l s e \] , \[ ' .\/ m a i n 4 .j s ' , ' ' , f a l s e , f a l s e \] \] ; / ,
169
175
) ;
170
176
// Exactly 4 scripts should be left.
171
177
expect ( Array . from ( result . matchAll ( / < s c r i p t > / g) ) . length ) . toEqual ( 4 ) ;
172
178
} ) ;
179
+
180
+ it ( 'should write a loader script that appends to head' , async ( ) => {
181
+ const result = await autoCsp ( `
182
+ <html>
183
+ <head>
184
+ <script src="./head.js"></script>
185
+ </head>
186
+ <body>
187
+ <div>Some text </div>
188
+ </body>
189
+ </html>
190
+ ` ) ;
191
+
192
+ const csps = getCsps ( result ) ;
193
+ expect ( csps . length ) . toBe ( 1 ) ;
194
+ expect ( csps [ 0 ] ) . toMatch ( ONE_HASH_CSP ) ;
195
+
196
+ expect ( result ) . toContain (
197
+ // eslint-disable-next-line max-len
198
+ `document.lastElementChild.appendChild` ,
199
+ ) ;
200
+ // Head loader script is in the head.
201
+ expect ( result ) . toContain ( `</script></head>` ) ;
202
+ // Only one loader script is created.
203
+ expect ( Array . from ( result . matchAll ( / < s c r i p t > / g) ) . length ) . toEqual ( 1 ) ;
204
+ } ) ;
173
205
} ) ;
0 commit comments