@@ -40,9 +40,18 @@ class BaseProvider {
40
40
/** @type {import('types').Csp.Source[] } */
41
41
#script_src;
42
42
43
+ /** @type {import('types').Csp.Source[] } */
44
+ #script_src_elem;
45
+
43
46
/** @type {import('types').Csp.Source[] } */
44
47
#style_src;
45
48
49
+ /** @type {import('types').Csp.Source[] } */
50
+ #style_src_attr;
51
+
52
+ /** @type {import('types').Csp.Source[] } */
53
+ #style_src_elem;
54
+
46
55
/** @type {string } */
47
56
#nonce;
48
57
@@ -57,6 +66,18 @@ class BaseProvider {
57
66
58
67
const d = this . #directives;
59
68
69
+ this . #script_src = [ ] ;
70
+ this . #script_src_elem = [ ] ;
71
+ this . #style_src = [ ] ;
72
+ this . #style_src_attr = [ ] ;
73
+ this . #style_src_elem = [ ] ;
74
+
75
+ const effective_script_src = d [ 'script-src' ] || d [ 'default-src' ] ;
76
+ const script_src_elem = d [ 'script-src-elem' ] ;
77
+ const effective_style_src = d [ 'style-src' ] || d [ 'default-src' ] ;
78
+ const style_src_attr = d [ 'style-src-attr' ] ;
79
+ const style_src_elem = d [ 'style-src-elem' ] ;
80
+
60
81
if ( __SVELTEKIT_DEV__ ) {
61
82
// remove strict-dynamic in dev...
62
83
// TODO reinstate this if we can figure out how to make strict-dynamic work
@@ -70,28 +91,34 @@ class BaseProvider {
70
91
// if (d['script-src'].length === 0) delete d['script-src'];
71
92
// }
72
93
73
- const effective_style_src = d [ 'style-src' ] || d [ 'default-src' ] ;
74
-
75
94
// ...and add unsafe-inline so we can inject <style> elements
76
95
if ( effective_style_src && ! effective_style_src . includes ( 'unsafe-inline' ) ) {
77
96
d [ 'style-src' ] = [ ...effective_style_src , 'unsafe-inline' ] ;
78
97
}
79
- }
80
98
81
- this . #script_src = [ ] ;
82
- this . #style_src = [ ] ;
99
+ if ( style_src_attr && ! style_src_attr . includes ( 'unsafe-inline' ) ) {
100
+ d [ 'style-src-attr' ] = [ ...style_src_attr , 'unsafe-inline' ] ;
101
+ }
83
102
84
- const effective_script_src = d [ 'script-src' ] || d [ 'default-src' ] ;
85
- const effective_style_src = d [ 'style-src' ] || d [ 'default-src' ] ;
103
+ if ( style_src_elem && ! style_src_elem . includes ( 'unsafe-inline' ) ) {
104
+ d [ 'style-src-elem' ] = [ ...style_src_elem , 'unsafe-inline' ] ;
105
+ }
106
+ }
86
107
87
108
this . #script_needs_csp =
88
- ! ! effective_script_src &&
89
- effective_script_src . filter ( ( value ) => value !== 'unsafe-inline' ) . length > 0 ;
109
+ ( ! ! effective_script_src &&
110
+ effective_script_src . filter ( ( value ) => value !== 'unsafe-inline' ) . length > 0 ) ||
111
+ ( ! ! script_src_elem &&
112
+ script_src_elem . filter ( ( value ) => value !== 'unsafe-inline' ) . length > 0 ) ;
90
113
91
114
this . #style_needs_csp =
92
115
! __SVELTEKIT_DEV__ &&
93
- ! ! effective_style_src &&
94
- effective_style_src . filter ( ( value ) => value !== 'unsafe-inline' ) . length > 0 ;
116
+ ( ( ! ! effective_style_src &&
117
+ effective_style_src . filter ( ( value ) => value !== 'unsafe-inline' ) . length > 0 ) ||
118
+ ( ! ! style_src_attr &&
119
+ style_src_attr . filter ( ( value ) => value !== 'unsafe-inline' ) . length > 0 ) ||
120
+ ( ! ! style_src_elem &&
121
+ style_src_elem . filter ( ( value ) => value !== 'unsafe-inline' ) . length > 0 ) ) ;
95
122
96
123
this . script_needs_nonce = this . #script_needs_csp && ! this . #use_hashes;
97
124
this . style_needs_nonce = this . #style_needs_csp && ! this . #use_hashes;
@@ -101,21 +128,53 @@ class BaseProvider {
101
128
/** @param {string } content */
102
129
add_script ( content ) {
103
130
if ( this . #script_needs_csp) {
131
+ const d = this . #directives;
132
+
104
133
if ( this . #use_hashes) {
105
- this . #script_src. push ( `sha256-${ sha256 ( content ) } ` ) ;
106
- } else if ( this . #script_src. length === 0 ) {
107
- this . #script_src. push ( `nonce-${ this . #nonce} ` ) ;
134
+ const hash = sha256 ( content ) ;
135
+
136
+ this . #script_src. push ( `sha256-${ hash } ` ) ;
137
+
138
+ if ( d [ 'script-src-elem' ] ?. length ) {
139
+ this . #script_src_elem. push ( `sha256-${ hash } ` ) ;
140
+ }
141
+ } else {
142
+ if ( this . #script_src. length === 0 ) {
143
+ this . #script_src. push ( `nonce-${ this . #nonce} ` ) ;
144
+ }
145
+ if ( d [ 'script-src-elem' ] ?. length ) {
146
+ this . #script_src_elem. push ( `nonce-${ this . #nonce} ` ) ;
147
+ }
108
148
}
109
149
}
110
150
}
111
151
112
152
/** @param {string } content */
113
153
add_style ( content ) {
114
154
if ( this . #style_needs_csp) {
155
+ const d = this . #directives;
156
+
115
157
if ( this . #use_hashes) {
116
- this . #style_src. push ( `sha256-${ sha256 ( content ) } ` ) ;
117
- } else if ( this . #style_src. length === 0 ) {
118
- this . #style_src. push ( `nonce-${ this . #nonce} ` ) ;
158
+ const hash = sha256 ( content ) ;
159
+
160
+ this . #style_src. push ( `sha256-${ hash } ` ) ;
161
+
162
+ if ( d [ 'style-src-attr' ] ?. length ) {
163
+ this . #style_src_attr. push ( `sha256-${ hash } ` ) ;
164
+ }
165
+ if ( d [ 'style-src-elem' ] ?. length ) {
166
+ this . #style_src_elem. push ( `sha256-${ hash } ` ) ;
167
+ }
168
+ } else {
169
+ if ( this . #style_src. length === 0 ) {
170
+ this . #style_src. push ( `nonce-${ this . #nonce} ` ) ;
171
+ }
172
+ if ( d [ 'style-src-attr' ] ?. length ) {
173
+ this . #style_src_attr. push ( `nonce-${ this . #nonce} ` ) ;
174
+ }
175
+ if ( d [ 'style-src-elem' ] ?. length ) {
176
+ this . #style_src_elem. push ( `nonce-${ this . #nonce} ` ) ;
177
+ }
119
178
}
120
179
}
121
180
}
@@ -139,13 +198,34 @@ class BaseProvider {
139
198
] ;
140
199
}
141
200
201
+ if ( this . #style_src_attr. length > 0 ) {
202
+ directives [ 'style-src-attr' ] = [
203
+ ...( directives [ 'style-src-attr' ] || [ ] ) ,
204
+ ...this . #style_src_attr
205
+ ] ;
206
+ }
207
+
208
+ if ( this . #style_src_elem. length > 0 ) {
209
+ directives [ 'style-src-elem' ] = [
210
+ ...( directives [ 'style-src-elem' ] || [ ] ) ,
211
+ ...this . #style_src_elem
212
+ ] ;
213
+ }
214
+
142
215
if ( this . #script_src. length > 0 ) {
143
216
directives [ 'script-src' ] = [
144
217
...( directives [ 'script-src' ] || directives [ 'default-src' ] || [ ] ) ,
145
218
...this . #script_src
146
219
] ;
147
220
}
148
221
222
+ if ( this . #script_src_elem. length > 0 ) {
223
+ directives [ 'script-src-elem' ] = [
224
+ ...( directives [ 'script-src-elem' ] || [ ] ) ,
225
+ ...this . #script_src_elem
226
+ ] ;
227
+ }
228
+
149
229
for ( const key in directives ) {
150
230
if ( is_meta && ( key === 'frame-ancestors' || key === 'report-uri' || key === 'sandbox' ) ) {
151
231
// these values cannot be used with a <meta> tag
0 commit comments