Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
SeleniumHQ
GitHub Repository: SeleniumHQ/Selenium
Path: blob/trunk/third_party/closure/goog/dom/safe.js
4138 views
1
/**
2
* @license
3
* Copyright The Closure Library Authors.
4
* SPDX-License-Identifier: Apache-2.0
5
*/
6
7
/**
8
* @fileoverview Type-safe wrappers for unsafe DOM APIs.
9
*
10
* This file provides type-safe wrappers for DOM APIs that can result in
11
* cross-site scripting (XSS) vulnerabilities, if the API is supplied with
12
* untrusted (attacker-controlled) input. Instead of plain strings, the type
13
* safe wrappers consume values of types from the goog.html package whose
14
* contract promises that values are safe to use in the corresponding context.
15
*
16
* Hence, a program that exclusively uses the wrappers in this file (i.e., whose
17
* only reference to security-sensitive raw DOM APIs are in this file) is
18
* guaranteed to be free of XSS due to incorrect use of such DOM APIs (modulo
19
* correctness of code that produces values of the respective goog.html types,
20
* and absent code that violates type safety).
21
*
22
* For example, assigning to an element's .innerHTML property a string that is
23
* derived (even partially) from untrusted input typically results in an XSS
24
* vulnerability. The type-safe wrapper goog.dom.safe.setInnerHtml consumes a
25
* value of type goog.html.SafeHtml, whose contract states that using its values
26
* in a HTML context will not result in XSS. Hence a program that is free of
27
* direct assignments to any element's innerHTML property (with the exception of
28
* the assignment to .innerHTML in this file) is guaranteed to be free of XSS
29
* due to assignment of untrusted strings to the innerHTML property.
30
*/
31
32
goog.provide('goog.dom.safe');
33
goog.provide('goog.dom.safe.InsertAdjacentHtmlPosition');
34
35
goog.require('goog.asserts');
36
goog.require('goog.asserts.dom');
37
goog.require('goog.dom.asserts');
38
goog.require('goog.functions');
39
goog.require('goog.html.SafeHtml');
40
goog.require('goog.html.SafeScript');
41
goog.require('goog.html.SafeStyle');
42
goog.require('goog.html.SafeUrl');
43
goog.require('goog.html.TrustedResourceUrl');
44
goog.require('goog.html.uncheckedconversions');
45
goog.require('goog.string.Const');
46
goog.require('goog.string.internal');
47
48
49
/** @enum {string} */
50
goog.dom.safe.InsertAdjacentHtmlPosition = {
51
AFTERBEGIN: 'afterbegin',
52
AFTEREND: 'afterend',
53
BEFOREBEGIN: 'beforebegin',
54
BEFOREEND: 'beforeend'
55
};
56
57
58
/**
59
* Inserts known-safe HTML into a Node, at the specified position.
60
* @param {!Node} node The node on which to call insertAdjacentHTML.
61
* @param {!goog.dom.safe.InsertAdjacentHtmlPosition} position Position where
62
* to insert the HTML.
63
* @param {!goog.html.SafeHtml} html The known-safe HTML to insert.
64
*/
65
goog.dom.safe.insertAdjacentHtml = function(node, position, html) {
66
'use strict';
67
node.insertAdjacentHTML(position, goog.html.SafeHtml.unwrapTrustedHTML(html));
68
};
69
70
71
/**
72
* Tags not allowed in goog.dom.safe.setInnerHtml.
73
* @private @const {!Object<string, boolean>}
74
*/
75
goog.dom.safe.SET_INNER_HTML_DISALLOWED_TAGS_ = {
76
'MATH': true,
77
'SCRIPT': true,
78
'STYLE': true,
79
'SVG': true,
80
'TEMPLATE': true
81
};
82
83
84
/**
85
* Whether assigning to innerHTML results in a non-spec-compliant clean-up. Used
86
* to define goog.dom.safe.unsafeSetInnerHtmlDoNotUseOrElse.
87
*
88
* <p>As mentioned in https://stackoverflow.com/questions/28741528, re-rendering
89
* an element in IE by setting innerHTML causes IE to recursively disconnect all
90
* parent/children connections that were in the previous contents of the
91
* element. Unfortunately, this can unexpectedly result in confusing cases where
92
* a function is run (typically asynchronously) on element that has since
93
* disconnected from the DOM but assumes the presence of its children. A simple
94
* workaround is to remove all children first. Testing on IE11 via
95
* https://jsperf.com/innerhtml-vs-removechild/239, removeChild seems to be
96
* ~10x faster than innerHTML='' for a large number of children (perhaps due
97
* to the latter's recursive behavior), implying that this workaround would
98
* not hurt performance and might actually improve it.
99
* @return {boolean}
100
* @private
101
*/
102
goog.dom.safe.isInnerHtmlCleanupRecursive_ =
103
goog.functions.cacheReturnValue(function() {
104
'use strict';
105
// `document` missing in some test frameworks.
106
if (goog.DEBUG && typeof document === 'undefined') {
107
return false;
108
}
109
// Create 3 nested <div>s without using innerHTML.
110
// We're not chaining the appendChilds in one call, as this breaks
111
// in a DocumentFragment.
112
var div = document.createElement('div');
113
var childDiv = document.createElement('div');
114
childDiv.appendChild(document.createElement('div'));
115
div.appendChild(childDiv);
116
// `firstChild` is null in Google Js Test.
117
if (goog.DEBUG && !div.firstChild) {
118
return false;
119
}
120
var innerChild = div.firstChild.firstChild;
121
div.innerHTML =
122
goog.html.SafeHtml.unwrapTrustedHTML(goog.html.SafeHtml.EMPTY);
123
return !innerChild.parentElement;
124
});
125
126
127
/**
128
* Assigns HTML to an element's innerHTML property. Helper to use only here and
129
* in soy.js.
130
* @param {?Element|?ShadowRoot} elem The element whose innerHTML is to be
131
* assigned to.
132
* @param {!goog.html.SafeHtml} html
133
*/
134
goog.dom.safe.unsafeSetInnerHtmlDoNotUseOrElse = function(elem, html) {
135
'use strict';
136
// See comment above goog.dom.safe.isInnerHtmlCleanupRecursive_.
137
if (goog.dom.safe.isInnerHtmlCleanupRecursive_()) {
138
while (elem.lastChild) {
139
elem.removeChild(elem.lastChild);
140
}
141
}
142
elem.innerHTML = goog.html.SafeHtml.unwrapTrustedHTML(html);
143
};
144
145
146
/**
147
* Assigns known-safe HTML to an element's innerHTML property.
148
* @param {!Element|!ShadowRoot} elem The element whose innerHTML is to be
149
* assigned to.
150
* @param {!goog.html.SafeHtml} html The known-safe HTML to assign.
151
* @throws {Error} If called with one of these tags: math, script, style, svg,
152
* template.
153
*/
154
goog.dom.safe.setInnerHtml = function(elem, html) {
155
'use strict';
156
if (goog.asserts.ENABLE_ASSERTS && /** @type {?} */ (elem).tagName) {
157
var tagName = /** @type {!Element} */ (elem).tagName.toUpperCase();
158
if (goog.dom.safe.SET_INNER_HTML_DISALLOWED_TAGS_[tagName]) {
159
throw new Error(
160
'goog.dom.safe.setInnerHtml cannot be used to set content of ' +
161
/** @type {!Element} */ (elem).tagName + '.');
162
}
163
}
164
165
goog.dom.safe.unsafeSetInnerHtmlDoNotUseOrElse(elem, html);
166
};
167
168
169
/**
170
* Assigns constant HTML to an element's innerHTML property.
171
* @param {!Element} element The element whose innerHTML is to be assigned to.
172
* @param {!goog.string.Const} constHtml The known-safe HTML to assign.
173
* @throws {!Error} If called with one of these tags: math, script, style, svg,
174
* template.
175
*/
176
goog.dom.safe.setInnerHtmlFromConstant = function(element, constHtml) {
177
'use strict';
178
goog.dom.safe.setInnerHtml(
179
element,
180
goog.html.uncheckedconversions
181
.safeHtmlFromStringKnownToSatisfyTypeContract(
182
goog.string.Const.from('Constant HTML to be immediatelly used.'),
183
goog.string.Const.unwrap(constHtml)));
184
};
185
186
187
/**
188
* Assigns known-safe HTML to an element's outerHTML property.
189
* @param {!Element} elem The element whose outerHTML is to be assigned to.
190
* @param {!goog.html.SafeHtml} html The known-safe HTML to assign.
191
*/
192
goog.dom.safe.setOuterHtml = function(elem, html) {
193
'use strict';
194
elem.outerHTML = goog.html.SafeHtml.unwrapTrustedHTML(html);
195
};
196
197
198
/**
199
* Safely assigns a URL a form element's action property.
200
*
201
* If url is of type goog.html.SafeUrl, its value is unwrapped and assigned to
202
* form's action property. If url is of type string however, it is first
203
* sanitized using goog.html.SafeUrl.sanitize.
204
*
205
* Example usage:
206
* goog.dom.safe.setFormElementAction(formEl, url);
207
* which is a safe alternative to
208
* formEl.action = url;
209
* The latter can result in XSS vulnerabilities if url is a
210
* user-/attacker-controlled value.
211
*
212
* @param {!Element} form The form element whose action property
213
* is to be assigned to.
214
* @param {string|!goog.html.SafeUrl} url The URL to assign.
215
* @return {void}
216
* @see goog.html.SafeUrl#sanitize
217
*/
218
goog.dom.safe.setFormElementAction = function(form, url) {
219
'use strict';
220
/** @type {!goog.html.SafeUrl} */
221
var safeUrl;
222
if (url instanceof goog.html.SafeUrl) {
223
safeUrl = url;
224
} else {
225
safeUrl = goog.html.SafeUrl.sanitizeJavascriptUrlAssertUnchanged(url);
226
}
227
goog.asserts.dom.assertIsHtmlFormElement(form).action =
228
goog.html.SafeUrl.unwrap(safeUrl);
229
};
230
231
/**
232
* Safely assigns a URL to a button element's formaction property.
233
*
234
* If url is of type goog.html.SafeUrl, its value is unwrapped and assigned to
235
* button's formaction property. If url is of type string however, it is first
236
* sanitized using goog.html.SafeUrl.sanitize.
237
*
238
* Example usage:
239
* goog.dom.safe.setButtonFormAction(buttonEl, url);
240
* which is a safe alternative to
241
* buttonEl.action = url;
242
* The latter can result in XSS vulnerabilities if url is a
243
* user-/attacker-controlled value.
244
*
245
* @param {!Element} button The button element whose action property
246
* is to be assigned to.
247
* @param {string|!goog.html.SafeUrl} url The URL to assign.
248
* @return {void}
249
* @see goog.html.SafeUrl#sanitize
250
*/
251
goog.dom.safe.setButtonFormAction = function(button, url) {
252
'use strict';
253
/** @type {!goog.html.SafeUrl} */
254
var safeUrl;
255
if (url instanceof goog.html.SafeUrl) {
256
safeUrl = url;
257
} else {
258
safeUrl = goog.html.SafeUrl.sanitizeJavascriptUrlAssertUnchanged(url);
259
}
260
goog.asserts.dom.assertIsHtmlButtonElement(button).formAction =
261
goog.html.SafeUrl.unwrap(safeUrl);
262
};
263
/**
264
* Safely assigns a URL to an input element's formaction property.
265
*
266
* If url is of type goog.html.SafeUrl, its value is unwrapped and assigned to
267
* input's formaction property. If url is of type string however, it is first
268
* sanitized using goog.html.SafeUrl.sanitize.
269
*
270
* Example usage:
271
* goog.dom.safe.setInputFormAction(inputEl, url);
272
* which is a safe alternative to
273
* inputEl.action = url;
274
* The latter can result in XSS vulnerabilities if url is a
275
* user-/attacker-controlled value.
276
*
277
* @param {!Element} input The input element whose action property
278
* is to be assigned to.
279
* @param {string|!goog.html.SafeUrl} url The URL to assign.
280
* @return {void}
281
* @see goog.html.SafeUrl#sanitize
282
*/
283
goog.dom.safe.setInputFormAction = function(input, url) {
284
'use strict';
285
/** @type {!goog.html.SafeUrl} */
286
var safeUrl;
287
if (url instanceof goog.html.SafeUrl) {
288
safeUrl = url;
289
} else {
290
safeUrl = goog.html.SafeUrl.sanitizeJavascriptUrlAssertUnchanged(url);
291
}
292
goog.asserts.dom.assertIsHtmlInputElement(input).formAction =
293
goog.html.SafeUrl.unwrap(safeUrl);
294
};
295
296
/**
297
* Sets the given element's style property to the contents of the provided
298
* SafeStyle object.
299
* @param {!Element} elem
300
* @param {!goog.html.SafeStyle} style
301
* @return {void}
302
*/
303
goog.dom.safe.setStyle = function(elem, style) {
304
'use strict';
305
elem.style.cssText = goog.html.SafeStyle.unwrap(style);
306
};
307
308
309
/**
310
* Writes known-safe HTML to a document.
311
* @param {!Document} doc The document to be written to.
312
* @param {!goog.html.SafeHtml} html The known-safe HTML to assign.
313
* @return {void}
314
*/
315
goog.dom.safe.documentWrite = function(doc, html) {
316
'use strict';
317
doc.write(goog.html.SafeHtml.unwrapTrustedHTML(html));
318
};
319
320
321
/**
322
* Safely assigns a URL to an anchor element's href property.
323
*
324
* If url is of type goog.html.SafeUrl, its value is unwrapped and assigned to
325
* anchor's href property. If url is of type string however, it is first
326
* sanitized using goog.html.SafeUrl.sanitize.
327
*
328
* Example usage:
329
* goog.dom.safe.setAnchorHref(anchorEl, url);
330
* which is a safe alternative to
331
* anchorEl.href = url;
332
* The latter can result in XSS vulnerabilities if url is a
333
* user-/attacker-controlled value.
334
*
335
* @param {!HTMLAnchorElement} anchor The anchor element whose href property
336
* is to be assigned to.
337
* @param {string|!goog.html.SafeUrl} url The URL to assign.
338
* @return {void}
339
* @see goog.html.SafeUrl#sanitize
340
*/
341
goog.dom.safe.setAnchorHref = function(anchor, url) {
342
'use strict';
343
goog.asserts.dom.assertIsHtmlAnchorElement(anchor);
344
/** @type {!goog.html.SafeUrl} */
345
var safeUrl;
346
if (url instanceof goog.html.SafeUrl) {
347
safeUrl = url;
348
} else {
349
safeUrl = goog.html.SafeUrl.sanitizeJavascriptUrlAssertUnchanged(url);
350
}
351
anchor.href = goog.html.SafeUrl.unwrap(safeUrl);
352
};
353
354
355
/**
356
* Safely assigns a URL to a audio element's src property.
357
*
358
* If url is of type goog.html.SafeUrl, its value is unwrapped and assigned to
359
* audio's src property. If url is of type string however, it is first
360
* sanitized using goog.html.SafeUrl.sanitize.
361
*
362
* @param {!HTMLAudioElement} audioElement The audio element whose src property
363
* is to be assigned to.
364
* @param {string|!goog.html.SafeUrl} url The URL to assign.
365
* @return {void}
366
* @see goog.html.SafeUrl#sanitize
367
*/
368
goog.dom.safe.setAudioSrc = function(audioElement, url) {
369
'use strict';
370
goog.asserts.dom.assertIsHtmlAudioElement(audioElement);
371
/** @type {!goog.html.SafeUrl} */
372
var safeUrl;
373
if (url instanceof goog.html.SafeUrl) {
374
safeUrl = url;
375
} else {
376
safeUrl = goog.html.SafeUrl.sanitizeJavascriptUrlAssertUnchanged(url);
377
}
378
audioElement.src = goog.html.SafeUrl.unwrap(safeUrl);
379
};
380
381
/**
382
* Safely assigns a URL to a video element's src property.
383
*
384
* If url is of type goog.html.SafeUrl, its value is unwrapped and assigned to
385
* video's src property. If url is of type string however, it is first
386
* sanitized using goog.html.SafeUrl.sanitize.
387
*
388
* @param {!HTMLVideoElement} videoElement The video element whose src property
389
* is to be assigned to.
390
* @param {string|!goog.html.SafeUrl} url The URL to assign.
391
* @return {void}
392
* @see goog.html.SafeUrl#sanitize
393
*/
394
goog.dom.safe.setVideoSrc = function(videoElement, url) {
395
'use strict';
396
goog.asserts.dom.assertIsHtmlVideoElement(videoElement);
397
/** @type {!goog.html.SafeUrl} */
398
var safeUrl;
399
if (url instanceof goog.html.SafeUrl) {
400
safeUrl = url;
401
} else {
402
safeUrl = goog.html.SafeUrl.sanitizeJavascriptUrlAssertUnchanged(url);
403
}
404
videoElement.src = goog.html.SafeUrl.unwrap(safeUrl);
405
};
406
407
/**
408
* Safely assigns a URL to an embed element's src property.
409
*
410
* Example usage:
411
* goog.dom.safe.setEmbedSrc(embedEl, url);
412
* which is a safe alternative to
413
* embedEl.src = url;
414
* The latter can result in loading untrusted code unless it is ensured that
415
* the URL refers to a trustworthy resource.
416
*
417
* @param {!HTMLEmbedElement} embed The embed element whose src property
418
* is to be assigned to.
419
* @param {!goog.html.TrustedResourceUrl} url The URL to assign.
420
*/
421
goog.dom.safe.setEmbedSrc = function(embed, url) {
422
'use strict';
423
goog.asserts.dom.assertIsHtmlEmbedElement(embed);
424
embed.src = goog.html.TrustedResourceUrl.unwrapTrustedScriptURL(url);
425
};
426
427
428
/**
429
* Safely assigns a URL to a frame element's src property.
430
*
431
* Example usage:
432
* goog.dom.safe.setFrameSrc(frameEl, url);
433
* which is a safe alternative to
434
* frameEl.src = url;
435
* The latter can result in loading untrusted code unless it is ensured that
436
* the URL refers to a trustworthy resource.
437
* @deprecated Use safevalues.dom.safeIframeEl.setSrc instead.
438
* @param {!HTMLFrameElement} frame The frame element whose src property
439
* is to be assigned to.
440
* @param {!goog.html.TrustedResourceUrl} url The URL to assign.
441
* @return {void}
442
*/
443
goog.dom.safe.setFrameSrc = function(frame, url) {
444
'use strict';
445
goog.asserts.dom.assertIsHtmlFrameElement(frame);
446
frame.src = goog.html.TrustedResourceUrl.unwrap(url);
447
};
448
449
450
/**
451
* Safely assigns a URL to an iframe element's src property.
452
*
453
* Example usage:
454
* goog.dom.safe.setIframeSrc(iframeEl, url);
455
* which is a safe alternative to
456
* iframeEl.src = url;
457
* The latter can result in loading untrusted code unless it is ensured that
458
* the URL refers to a trustworthy resource.
459
*
460
* @param {!HTMLIFrameElement} iframe The iframe element whose src property
461
* is to be assigned to.
462
* @param {!goog.html.TrustedResourceUrl} url The URL to assign.
463
* @return {void}
464
*/
465
goog.dom.safe.setIframeSrc = function(iframe, url) {
466
'use strict';
467
goog.asserts.dom.assertIsHtmlIFrameElement(iframe);
468
iframe.src = goog.html.TrustedResourceUrl.unwrap(url);
469
};
470
471
472
/**
473
* Safely assigns HTML to an iframe element's srcdoc property.
474
*
475
* Example usage:
476
* goog.dom.safe.setIframeSrcdoc(iframeEl, safeHtml);
477
* which is a safe alternative to
478
* iframeEl.srcdoc = html;
479
* The latter can result in loading untrusted code.
480
*
481
* @param {!HTMLIFrameElement} iframe The iframe element whose srcdoc property
482
* is to be assigned to.
483
* @param {!goog.html.SafeHtml} html The HTML to assign.
484
* @return {void}
485
*/
486
goog.dom.safe.setIframeSrcdoc = function(iframe, html) {
487
'use strict';
488
goog.asserts.dom.assertIsHtmlIFrameElement(iframe);
489
iframe.srcdoc = goog.html.SafeHtml.unwrapTrustedHTML(html);
490
};
491
492
493
/**
494
* Safely sets a link element's href and rel properties. Whether or not
495
* the URL assigned to href has to be a goog.html.TrustedResourceUrl
496
* depends on the value of the rel property. If rel contains "stylesheet"
497
* then a TrustedResourceUrl is required.
498
*
499
* Example usage:
500
* goog.dom.safe.setLinkHrefAndRel(linkEl, url, 'stylesheet');
501
* which is a safe alternative to
502
* linkEl.rel = 'stylesheet';
503
* linkEl.href = url;
504
* The latter can result in loading untrusted code unless it is ensured that
505
* the URL refers to a trustworthy resource.
506
*
507
* @param {!HTMLLinkElement} link The link element whose href property
508
* is to be assigned to.
509
* @param {string|!goog.html.SafeUrl|!goog.html.TrustedResourceUrl} url The URL
510
* to assign to the href property. Must be a TrustedResourceUrl if the
511
* value assigned to rel contains "stylesheet". A string value is
512
* sanitized with goog.html.SafeUrl.sanitize.
513
* @param {string} rel The value to assign to the rel property.
514
* @return {void}
515
* @throws {Error} if rel contains "stylesheet" and url is not a
516
* TrustedResourceUrl
517
* @see goog.html.SafeUrl#sanitize
518
*/
519
goog.dom.safe.setLinkHrefAndRel = function(link, url, rel) {
520
'use strict';
521
goog.asserts.dom.assertIsHtmlLinkElement(link);
522
link.rel = rel;
523
if (goog.string.internal.caseInsensitiveContains(rel, 'stylesheet')) {
524
goog.asserts.assert(
525
url instanceof goog.html.TrustedResourceUrl,
526
'URL must be TrustedResourceUrl because "rel" contains "stylesheet"');
527
link.href = goog.html.TrustedResourceUrl.unwrap(url);
528
const win = link.ownerDocument && link.ownerDocument.defaultView;
529
const nonce = goog.dom.safe.getStyleNonce(win);
530
if (nonce) {
531
link.setAttribute('nonce', nonce);
532
}
533
} else if (url instanceof goog.html.TrustedResourceUrl) {
534
link.href = goog.html.TrustedResourceUrl.unwrap(url);
535
} else if (url instanceof goog.html.SafeUrl) {
536
link.href = goog.html.SafeUrl.unwrap(url);
537
} else { // string
538
// SafeUrl.sanitize must return legitimate SafeUrl when passed a string.
539
link.href = goog.html.SafeUrl.unwrap(
540
goog.html.SafeUrl.sanitizeJavascriptUrlAssertUnchanged(url));
541
}
542
};
543
544
545
/**
546
* Safely assigns a URL to an object element's data property.
547
*
548
* Example usage:
549
* goog.dom.safe.setObjectData(objectEl, url);
550
* which is a safe alternative to
551
* objectEl.data = url;
552
* The latter can result in loading untrusted code unless setit is ensured that
553
* the URL refers to a trustworthy resource.
554
* @deprecated
555
*
556
* @param {!HTMLObjectElement} object The object element whose data property
557
* is to be assigned to.
558
* @param {!goog.html.TrustedResourceUrl} url The URL to assign.
559
* @return {void}
560
*/
561
goog.dom.safe.setObjectData = function(object, url) {
562
'use strict';
563
goog.asserts.dom.assertIsHtmlObjectElement(object);
564
object.data = goog.html.TrustedResourceUrl.unwrapTrustedScriptURL(url);
565
};
566
567
568
/**
569
* Safely assigns a URL to a script element's src property.
570
*
571
* Example usage:
572
* goog.dom.safe.setScriptSrc(scriptEl, url);
573
* which is a safe alternative to
574
* scriptEl.src = url;
575
* The latter can result in loading untrusted code unless it is ensured that
576
* the URL refers to a trustworthy resource.
577
*
578
* @param {!HTMLScriptElement} script The script element whose src property
579
* is to be assigned to.
580
* @param {!goog.html.TrustedResourceUrl} url The URL to assign.
581
* @return {void}
582
*/
583
goog.dom.safe.setScriptSrc = function(script, url) {
584
'use strict';
585
goog.asserts.dom.assertIsHtmlScriptElement(script);
586
goog.dom.safe.setNonceForScriptElement_(script);
587
script.src = goog.html.TrustedResourceUrl.unwrapTrustedScriptURL(url);
588
};
589
590
591
/**
592
* Safely assigns a value to a script element's content.
593
*
594
* Example usage:
595
* goog.dom.safe.setScriptContent(scriptEl, content);
596
* which is a safe alternative to
597
* scriptEl.text = content;
598
* The latter can result in executing untrusted code unless it is ensured that
599
* the code is loaded from a trustworthy resource.
600
*
601
* @param {!HTMLScriptElement} script The script element whose content is being
602
* set.
603
* @param {!goog.html.SafeScript} content The content to assign.
604
* @return {void}
605
*/
606
goog.dom.safe.setScriptContent = function(script, content) {
607
'use strict';
608
goog.asserts.dom.assertIsHtmlScriptElement(script);
609
goog.dom.safe.setNonceForScriptElement_(script);
610
script.textContent = goog.html.SafeScript.unwrapTrustedScript(content);
611
};
612
613
614
/**
615
* Set nonce-based CSPs to dynamically created scripts.
616
* @param {!HTMLScriptElement} script The script element whose nonce value
617
* is to be calculated
618
* @private
619
*/
620
goog.dom.safe.setNonceForScriptElement_ = function(script) {
621
'use strict';
622
var win = script.ownerDocument && script.ownerDocument.defaultView;
623
const nonce = goog.dom.safe.getScriptNonce(win);
624
if (nonce) {
625
script.setAttribute('nonce', nonce);
626
}
627
};
628
629
630
/**
631
* Safely assigns a URL to a Location object's href property.
632
*
633
* If url is of type goog.html.SafeUrl, its value is unwrapped and assigned to
634
* loc's href property. If url is of type string however, it is first sanitized
635
* using goog.html.SafeUrl.sanitize.
636
*
637
* Example usage:
638
* goog.dom.safe.setLocationHref(document.location, redirectUrl);
639
* which is a safe alternative to
640
* document.location.href = redirectUrl;
641
* The latter can result in XSS vulnerabilities if redirectUrl is a
642
* user-/attacker-controlled value.
643
*
644
* @param {!Location} loc The Location object whose href property is to be
645
* assigned to.
646
* @param {string|!goog.html.SafeUrl} url The URL to assign.
647
* @return {void}
648
* @see goog.html.SafeUrl#sanitize
649
650
*/
651
goog.dom.safe.setLocationHref = function(loc, url) {
652
'use strict';
653
goog.dom.asserts.assertIsLocation(loc);
654
/** @type {!goog.html.SafeUrl} */
655
var safeUrl;
656
if (url instanceof goog.html.SafeUrl) {
657
safeUrl = url;
658
} else {
659
safeUrl = goog.html.SafeUrl.sanitizeJavascriptUrlAssertUnchanged(url);
660
}
661
loc.href = goog.html.SafeUrl.unwrap(safeUrl);
662
};
663
664
/**
665
* Safely assigns the URL of a Location object.
666
*
667
* If url is of type goog.html.SafeUrl, its value is unwrapped and
668
* passed to Location#assign. If url is of type string however, it is
669
* first sanitized using goog.html.SafeUrl.sanitize.
670
*
671
* Example usage:
672
* goog.dom.safe.assignLocation(document.location, newUrl);
673
* which is a safe alternative to
674
* document.location.assign(newUrl);
675
* The latter can result in XSS vulnerabilities if newUrl is a
676
* user-/attacker-controlled value.
677
*
678
* This has the same behaviour as setLocationHref, however some test
679
* mock Location.assign instead of a property assignment.
680
*
681
* @param {!Location} loc The Location object which is to be assigned.
682
* @param {string|!goog.html.SafeUrl} url The URL to assign.
683
* @return {void}
684
* @see goog.html.SafeUrl#sanitize
685
*/
686
goog.dom.safe.assignLocation = function(loc, url) {
687
'use strict';
688
goog.dom.asserts.assertIsLocation(loc);
689
/** @type {!goog.html.SafeUrl} */
690
var safeUrl;
691
if (url instanceof goog.html.SafeUrl) {
692
safeUrl = url;
693
} else {
694
safeUrl = goog.html.SafeUrl.sanitizeJavascriptUrlAssertUnchanged(url);
695
}
696
loc.assign(goog.html.SafeUrl.unwrap(safeUrl));
697
};
698
699
700
/**
701
* Safely replaces the URL of a Location object.
702
*
703
* If url is of type goog.html.SafeUrl, its value is unwrapped and
704
* passed to Location#replace. If url is of type string however, it is
705
* first sanitized using goog.html.SafeUrl.sanitize.
706
*
707
* Example usage:
708
* goog.dom.safe.replaceLocation(document.location, newUrl);
709
* which is a safe alternative to
710
* document.location.replace(newUrl);
711
* The latter can result in XSS vulnerabilities if newUrl is a
712
* user-/attacker-controlled value.
713
*
714
* @param {!Location} loc The Location object which is to be replaced.
715
* @param {string|!goog.html.SafeUrl} url The URL to assign.
716
* @return {void}
717
* @see goog.html.SafeUrl#sanitize
718
*/
719
goog.dom.safe.replaceLocation = function(loc, url) {
720
'use strict';
721
/** @type {!goog.html.SafeUrl} */
722
var safeUrl;
723
if (url instanceof goog.html.SafeUrl) {
724
safeUrl = url;
725
} else {
726
safeUrl = goog.html.SafeUrl.sanitizeJavascriptUrlAssertUnchanged(url);
727
}
728
loc.replace(goog.html.SafeUrl.unwrap(safeUrl));
729
};
730
731
732
/**
733
* Safely opens a URL in a new window (via window.open).
734
*
735
* If url is of type goog.html.SafeUrl, its value is unwrapped and passed in to
736
* window.open. If url is of type string however, it is first sanitized
737
* using goog.html.SafeUrl.sanitize.
738
*
739
* Note that this function does not prevent leakages via the referer that is
740
* sent by window.open. It is advised to only use this to open 1st party URLs.
741
*
742
* Example usage:
743
* goog.dom.safe.openInWindow(url);
744
* which is a safe alternative to
745
* window.open(url);
746
* The latter can result in XSS vulnerabilities if url is a
747
* user-/attacker-controlled value.
748
*
749
* @param {string|!goog.html.SafeUrl} url The URL to open.
750
* @param {Window=} opt_openerWin Window of which to call the .open() method.
751
* Defaults to the global window.
752
* @param {!goog.string.Const|string=} opt_name Name of the window to open in.
753
* Can be _top, etc as allowed by window.open(). This accepts string for
754
* legacy reasons. Pass goog.string.Const if possible.
755
* @param {string=} opt_specs Comma-separated list of specifications, same as
756
* in window.open().
757
* @return {Window} Window the url was opened in.
758
*/
759
goog.dom.safe.openInWindow = function(url, opt_openerWin, opt_name, opt_specs) {
760
'use strict';
761
/** @type {!goog.html.SafeUrl} */
762
var safeUrl;
763
if (url instanceof goog.html.SafeUrl) {
764
safeUrl = url;
765
} else {
766
safeUrl = goog.html.SafeUrl.sanitizeJavascriptUrlAssertUnchanged(url);
767
}
768
var win = opt_openerWin || goog.global;
769
// If opt_name is undefined, simply passing that in to open() causes IE to
770
// reuse the current window instead of opening a new one. Thus we pass '' in
771
// instead, which according to spec opens a new window. See
772
// https://html.spec.whatwg.org/multipage/browsers.html#dom-open .
773
var name = opt_name instanceof goog.string.Const ?
774
goog.string.Const.unwrap(opt_name) :
775
opt_name || '';
776
// Do not pass opt_specs to window.open unless it was provided by the caller.
777
// IE11 will use it as a signal to open a new window rather than a new tab
778
// (even if it is undefined).
779
if (opt_specs !== undefined) {
780
return win.open(goog.html.SafeUrl.unwrap(safeUrl), name, opt_specs);
781
} else {
782
return win.open(goog.html.SafeUrl.unwrap(safeUrl), name);
783
}
784
};
785
786
787
/**
788
* Parses the HTML as 'text/html'.
789
* @param {!DOMParser} parser
790
* @param {!goog.html.SafeHtml} html The HTML to be parsed.
791
* @return {!Document}
792
*/
793
goog.dom.safe.parseFromStringHtml = function(parser, html) {
794
'use strict';
795
return goog.dom.safe.parseFromString(parser, html, 'text/html');
796
};
797
798
799
/**
800
* Parses the string.
801
* @param {!DOMParser} parser
802
* @param {!goog.html.SafeHtml} content Note: We don't have a special type for
803
* XML or SVG supported by this function so we use SafeHtml.
804
* @param {string} type
805
* @return {!Document}
806
*/
807
goog.dom.safe.parseFromString = function(parser, content, type) {
808
'use strict';
809
return parser.parseFromString(
810
goog.html.SafeHtml.unwrapTrustedHTML(content), type);
811
};
812
813
814
/**
815
* Safely creates an HTMLImageElement from a Blob.
816
*
817
* Example usage:
818
* goog.dom.safe.createImageFromBlob(blob);
819
* which is a safe alternative to
820
* image.src = createObjectUrl(blob)
821
* The latter can result in executing malicious same-origin scripts from a bad
822
* Blob.
823
* @param {!Blob} blob The blob to create the image from.
824
* @return {!HTMLImageElement} The image element created from the blob.
825
* @throws {!Error} If called with a Blob with a MIME type other than image/.*.
826
*/
827
goog.dom.safe.createImageFromBlob = function(blob) {
828
'use strict';
829
// Any image/* MIME type is accepted as safe.
830
if (!/^image\/.*/g.test(blob.type)) {
831
throw new Error(
832
'goog.dom.safe.createImageFromBlob only accepts MIME type image/.*.');
833
}
834
var objectUrl = goog.global.URL.createObjectURL(blob);
835
var image = new goog.global.Image();
836
image.onload = function() {
837
'use strict';
838
goog.global.URL.revokeObjectURL(objectUrl);
839
};
840
image.src = objectUrl;
841
return image;
842
};
843
844
/**
845
* Creates a DocumentFragment by parsing html in the context of a Range.
846
* @param {!Range} range The Range object starting from the context node to
847
* create a fragment in.
848
* @param {!goog.html.SafeHtml} html HTML to create a fragment from.
849
* @return {?DocumentFragment}
850
*/
851
goog.dom.safe.createContextualFragment = function(range, html) {
852
'use strict';
853
return range.createContextualFragment(
854
goog.html.SafeHtml.unwrapTrustedHTML(html));
855
};
856
857
/**
858
* Returns CSP script nonce, if set for any <script> tag.
859
* @param {?Window=} opt_window The window context used to retrieve the nonce.
860
* Defaults to global context.
861
* @return {string} CSP nonce or empty string if no nonce is present.
862
*/
863
goog.dom.safe.getScriptNonce = function(opt_window) {
864
return goog.dom.safe.getNonce_('script[nonce]', opt_window);
865
};
866
867
/**
868
* Returns CSP style nonce, if set for any <style> or <link rel="stylesheet">
869
* tag.
870
* @param {?Window=} opt_window The window context used to retrieve the nonce.
871
* Defaults to global context.
872
* @return {string} CSP nonce or empty string if no nonce is present.
873
*/
874
goog.dom.safe.getStyleNonce = function(opt_window) {
875
return goog.dom.safe.getNonce_(
876
'style[nonce],link[rel="stylesheet"][nonce]', opt_window);
877
};
878
879
/**
880
* According to the CSP3 spec a nonce must be a valid base64 string.
881
* @see https://www.w3.org/TR/CSP3/#grammardef-base64-value
882
* @private @const
883
*/
884
goog.dom.safe.NONCE_PATTERN_ = /^[\w+/_-]+[=]{0,2}$/;
885
886
/**
887
* Returns CSP nonce, if set for any tag of given type.
888
* @param {string} selector Selector for locating the element with nonce.
889
* @param {?Window=} win The window context used to retrieve the nonce.
890
* @return {string} CSP nonce or empty string if no nonce is present.
891
* @private
892
*/
893
goog.dom.safe.getNonce_ = function(selector, win) {
894
const doc = (win || goog.global).document;
895
if (!doc.querySelector) {
896
return '';
897
}
898
let el = doc.querySelector(selector);
899
if (el) {
900
// Try to get the nonce from the IDL property first, because browsers that
901
// implement additional nonce protection features (currently only Chrome) to
902
// prevent nonce stealing via CSS do not expose the nonce via attributes.
903
// See https://github.com/whatwg/html/issues/2369
904
const nonce = el['nonce'] || el.getAttribute('nonce');
905
if (nonce && goog.dom.safe.NONCE_PATTERN_.test(nonce)) {
906
return nonce;
907
}
908
}
909
return '';
910
};
911
912