11
11
import Vue from 'vue'
12
12
13
13
// we don't differentiate between different types of trusted values
14
- const createTrustedValue = ( value ) => `TRUSTED${ value } ` ;
15
- const isTrustedValue = ( value ) => value . startsWith ( 'TRUSTED' ) ;
16
- const unwrapTrustedValue = ( value ) => value . substr ( 'TRUSTED' . length ) ;
14
+ const createTrustedValue = ( value ) => ( { toString : ( ) => value , isTrusted : true } )
15
+ const isTrustedValue = ( value ) => value && value . isTrusted
17
16
18
17
const unsafeHtml = '<img src=x onerror="alert(0)">' ;
19
18
const unsafeScript = 'alert(0)' ;
@@ -27,6 +26,7 @@ describe('rendering with trusted types enforced', () => {
27
26
// thrown by unsafe setAttribute call (e.g. srcdoc in iframe) the rendering fails completely.
28
27
// We log the errors, before throwing so we can be sure that trusted types work.
29
28
let errorLog ;
29
+ let vuePolicyName ;
30
30
31
31
function emulateSetAttribute ( ) {
32
32
// enforce trusted values only on properties in this array
@@ -38,7 +38,7 @@ describe('rendering with trusted types enforced', () => {
38
38
unsafeAttributeList . forEach ( ( attr ) => {
39
39
if ( attr === name ) {
40
40
if ( isTrustedValue ( value ) ) {
41
- args = [ name , unwrapTrustedValue ( value ) ] ;
41
+ args = [ name , value . toString ( ) ] ;
42
42
} else {
43
43
errorLog . push ( createTTErrorMessage ( attr , value ) ) ;
44
44
throw new Error ( value ) ;
@@ -55,8 +55,9 @@ describe('rendering with trusted types enforced', () => {
55
55
descriptorEntries . push ( { object, prop, desc} ) ;
56
56
Object . defineProperty ( object , prop , {
57
57
set : function ( value ) {
58
+ console . log ( 'set' , value , prop ) ;
58
59
if ( isTrustedValue ( value ) ) {
59
- desc . set . apply ( this , [ unwrapTrustedValue ( value ) ] ) ;
60
+ desc . set . apply ( this , [ value . toString ( ) ] ) ;
60
61
} else {
61
62
errorLog . push ( createTTErrorMessage ( prop , value ) ) ;
62
63
throw new Error ( value ) ;
@@ -81,7 +82,12 @@ describe('rendering with trusted types enforced', () => {
81
82
82
83
beforeEach ( ( ) => {
83
84
window . trustedTypes = {
84
- createPolicy : ( ) => {
85
+ createPolicy : ( name ) => {
86
+ // capture the name of the vue policy so we can test it. Relies on fact
87
+ // that there are only 2 policies (for vue and for tests).
88
+ if ( name !== 'test-policy' ) {
89
+ vuePolicyName = name ;
90
+ }
85
91
return {
86
92
createHTML : createTrustedValue ,
87
93
createScript : createTrustedValue ,
@@ -98,9 +104,10 @@ describe('rendering with trusted types enforced', () => {
98
104
emulateSetAttribute ( ) ;
99
105
100
106
// TODO: this needs to be changed once we use trusted types polyfill
101
- policy = window . trustedTypes . createPolicy ( ) ;
107
+ policy = window . trustedTypes . createPolicy ( 'test-policy' ) ;
102
108
103
109
errorLog = [ ] ;
110
+ vuePolicyName = '' ;
104
111
} ) ;
105
112
106
113
afterEach ( ( ) => {
@@ -119,6 +126,100 @@ describe('rendering with trusted types enforced', () => {
119
126
} ) . toThrow ( ) ;
120
127
} ) ;
121
128
129
+ describe ( 'vue policy' , ( ) => {
130
+ let innerHTMLDescriptor ;
131
+
132
+ // simulate svg elements in Internet Explorer which don't have 'innerHTML' property
133
+ beforeEach ( ( ) => {
134
+ innerHTMLDescriptor = Object . getOwnPropertyDescriptor (
135
+ Element . prototype ,
136
+ 'innerHTML' ,
137
+ ) ;
138
+ delete Element . prototype . innerHTML ;
139
+ Object . defineProperty (
140
+ HTMLDivElement . prototype ,
141
+ 'innerHTML' ,
142
+ innerHTMLDescriptor ,
143
+ ) ;
144
+ } ) ;
145
+
146
+ afterEach ( ( ) => {
147
+ Vue . prototype . $clearTrustedTypesPolicy ( ) ;
148
+
149
+ delete HTMLDivElement . prototype . innerHTML ;
150
+ Object . defineProperty (
151
+ Element . prototype ,
152
+ 'innerHTML' ,
153
+ innerHTMLDescriptor ,
154
+ ) ;
155
+ } ) ;
156
+
157
+ it ( 'uses default policy name "vue"' , ( ) => {
158
+ // we need to trigger creation of vue policy
159
+ const vm = new Vue ( {
160
+ render : ( c ) => {
161
+ return c ( 'svg' , {
162
+ domProps : {
163
+ innerHTML : policy . createHTML ( 'safe html' ) ,
164
+ } ,
165
+ } ) ;
166
+ }
167
+ } )
168
+
169
+ vm . $mount ( ) ;
170
+ expect ( vuePolicyName ) . toBe ( 'vue' ) ;
171
+ } ) ;
172
+
173
+ it ( 'policy name can be configured' , ( ) => {
174
+ Vue . config . trustedTypesPolicyName = 'userProvidedPolicyName' ;
175
+
176
+ // we need to trigger creation of vue policy
177
+ const vm = new Vue ( {
178
+ render : ( c ) => {
179
+ return c ( 'svg' , {
180
+ domProps : {
181
+ innerHTML : policy . createHTML ( 'safe html' ) ,
182
+ } ,
183
+ } ) ;
184
+ }
185
+ } )
186
+
187
+ vm . $mount ( ) ;
188
+ expect ( vuePolicyName ) . toBe ( 'userProvidedPolicyName' ) ;
189
+ } ) ;
190
+
191
+ it ( 'will throw an error on untrusted html' , ( ) => {
192
+ const vm = new Vue ( {
193
+ render : ( c ) => {
194
+ return c ( 'svg' , {
195
+ domProps : {
196
+ innerHTML : unsafeHtml ,
197
+ } ,
198
+ } ) ;
199
+ }
200
+ } )
201
+
202
+ expect ( ( ) => {
203
+ vm . $mount ( ) ;
204
+ } ) . toThrowError ( 'Expected svg innerHTML to be TrustedHTML!' ) ;
205
+ } ) ;
206
+
207
+ it ( 'passes if payload is TrustedHTML' , ( ) => {
208
+ const vm = new Vue ( {
209
+ render : ( c ) => {
210
+ return c ( 'svg' , {
211
+ domProps : {
212
+ innerHTML : policy . createHTML ( 'safe html' ) ,
213
+ } ,
214
+ } ) ;
215
+ }
216
+ } )
217
+
218
+ vm . $mount ( ) ;
219
+ expect ( vm . $el . textContent ) . toBe ( 'safe html' ) ;
220
+ } ) ;
221
+ } ) ;
222
+
122
223
// html interpolation is safe because it's put into DOM as text node
123
224
it ( 'interpolation is trusted' , ( ) => {
124
225
const vm = new Vue ( {
0 commit comments