Path: blob/trunk/third_party/closure/goog/dom/safe.js
4138 views
/**1* @license2* Copyright The Closure Library Authors.3* SPDX-License-Identifier: Apache-2.04*/56/**7* @fileoverview Type-safe wrappers for unsafe DOM APIs.8*9* This file provides type-safe wrappers for DOM APIs that can result in10* cross-site scripting (XSS) vulnerabilities, if the API is supplied with11* untrusted (attacker-controlled) input. Instead of plain strings, the type12* safe wrappers consume values of types from the goog.html package whose13* contract promises that values are safe to use in the corresponding context.14*15* Hence, a program that exclusively uses the wrappers in this file (i.e., whose16* only reference to security-sensitive raw DOM APIs are in this file) is17* guaranteed to be free of XSS due to incorrect use of such DOM APIs (modulo18* correctness of code that produces values of the respective goog.html types,19* and absent code that violates type safety).20*21* For example, assigning to an element's .innerHTML property a string that is22* derived (even partially) from untrusted input typically results in an XSS23* vulnerability. The type-safe wrapper goog.dom.safe.setInnerHtml consumes a24* value of type goog.html.SafeHtml, whose contract states that using its values25* in a HTML context will not result in XSS. Hence a program that is free of26* direct assignments to any element's innerHTML property (with the exception of27* the assignment to .innerHTML in this file) is guaranteed to be free of XSS28* due to assignment of untrusted strings to the innerHTML property.29*/3031goog.provide('goog.dom.safe');32goog.provide('goog.dom.safe.InsertAdjacentHtmlPosition');3334goog.require('goog.asserts');35goog.require('goog.asserts.dom');36goog.require('goog.dom.asserts');37goog.require('goog.functions');38goog.require('goog.html.SafeHtml');39goog.require('goog.html.SafeScript');40goog.require('goog.html.SafeStyle');41goog.require('goog.html.SafeUrl');42goog.require('goog.html.TrustedResourceUrl');43goog.require('goog.html.uncheckedconversions');44goog.require('goog.string.Const');45goog.require('goog.string.internal');464748/** @enum {string} */49goog.dom.safe.InsertAdjacentHtmlPosition = {50AFTERBEGIN: 'afterbegin',51AFTEREND: 'afterend',52BEFOREBEGIN: 'beforebegin',53BEFOREEND: 'beforeend'54};555657/**58* Inserts known-safe HTML into a Node, at the specified position.59* @param {!Node} node The node on which to call insertAdjacentHTML.60* @param {!goog.dom.safe.InsertAdjacentHtmlPosition} position Position where61* to insert the HTML.62* @param {!goog.html.SafeHtml} html The known-safe HTML to insert.63*/64goog.dom.safe.insertAdjacentHtml = function(node, position, html) {65'use strict';66node.insertAdjacentHTML(position, goog.html.SafeHtml.unwrapTrustedHTML(html));67};686970/**71* Tags not allowed in goog.dom.safe.setInnerHtml.72* @private @const {!Object<string, boolean>}73*/74goog.dom.safe.SET_INNER_HTML_DISALLOWED_TAGS_ = {75'MATH': true,76'SCRIPT': true,77'STYLE': true,78'SVG': true,79'TEMPLATE': true80};818283/**84* Whether assigning to innerHTML results in a non-spec-compliant clean-up. Used85* to define goog.dom.safe.unsafeSetInnerHtmlDoNotUseOrElse.86*87* <p>As mentioned in https://stackoverflow.com/questions/28741528, re-rendering88* an element in IE by setting innerHTML causes IE to recursively disconnect all89* parent/children connections that were in the previous contents of the90* element. Unfortunately, this can unexpectedly result in confusing cases where91* a function is run (typically asynchronously) on element that has since92* disconnected from the DOM but assumes the presence of its children. A simple93* workaround is to remove all children first. Testing on IE11 via94* https://jsperf.com/innerhtml-vs-removechild/239, removeChild seems to be95* ~10x faster than innerHTML='' for a large number of children (perhaps due96* to the latter's recursive behavior), implying that this workaround would97* not hurt performance and might actually improve it.98* @return {boolean}99* @private100*/101goog.dom.safe.isInnerHtmlCleanupRecursive_ =102goog.functions.cacheReturnValue(function() {103'use strict';104// `document` missing in some test frameworks.105if (goog.DEBUG && typeof document === 'undefined') {106return false;107}108// Create 3 nested <div>s without using innerHTML.109// We're not chaining the appendChilds in one call, as this breaks110// in a DocumentFragment.111var div = document.createElement('div');112var childDiv = document.createElement('div');113childDiv.appendChild(document.createElement('div'));114div.appendChild(childDiv);115// `firstChild` is null in Google Js Test.116if (goog.DEBUG && !div.firstChild) {117return false;118}119var innerChild = div.firstChild.firstChild;120div.innerHTML =121goog.html.SafeHtml.unwrapTrustedHTML(goog.html.SafeHtml.EMPTY);122return !innerChild.parentElement;123});124125126/**127* Assigns HTML to an element's innerHTML property. Helper to use only here and128* in soy.js.129* @param {?Element|?ShadowRoot} elem The element whose innerHTML is to be130* assigned to.131* @param {!goog.html.SafeHtml} html132*/133goog.dom.safe.unsafeSetInnerHtmlDoNotUseOrElse = function(elem, html) {134'use strict';135// See comment above goog.dom.safe.isInnerHtmlCleanupRecursive_.136if (goog.dom.safe.isInnerHtmlCleanupRecursive_()) {137while (elem.lastChild) {138elem.removeChild(elem.lastChild);139}140}141elem.innerHTML = goog.html.SafeHtml.unwrapTrustedHTML(html);142};143144145/**146* Assigns known-safe HTML to an element's innerHTML property.147* @param {!Element|!ShadowRoot} elem The element whose innerHTML is to be148* assigned to.149* @param {!goog.html.SafeHtml} html The known-safe HTML to assign.150* @throws {Error} If called with one of these tags: math, script, style, svg,151* template.152*/153goog.dom.safe.setInnerHtml = function(elem, html) {154'use strict';155if (goog.asserts.ENABLE_ASSERTS && /** @type {?} */ (elem).tagName) {156var tagName = /** @type {!Element} */ (elem).tagName.toUpperCase();157if (goog.dom.safe.SET_INNER_HTML_DISALLOWED_TAGS_[tagName]) {158throw new Error(159'goog.dom.safe.setInnerHtml cannot be used to set content of ' +160/** @type {!Element} */ (elem).tagName + '.');161}162}163164goog.dom.safe.unsafeSetInnerHtmlDoNotUseOrElse(elem, html);165};166167168/**169* Assigns constant HTML to an element's innerHTML property.170* @param {!Element} element The element whose innerHTML is to be assigned to.171* @param {!goog.string.Const} constHtml The known-safe HTML to assign.172* @throws {!Error} If called with one of these tags: math, script, style, svg,173* template.174*/175goog.dom.safe.setInnerHtmlFromConstant = function(element, constHtml) {176'use strict';177goog.dom.safe.setInnerHtml(178element,179goog.html.uncheckedconversions180.safeHtmlFromStringKnownToSatisfyTypeContract(181goog.string.Const.from('Constant HTML to be immediatelly used.'),182goog.string.Const.unwrap(constHtml)));183};184185186/**187* Assigns known-safe HTML to an element's outerHTML property.188* @param {!Element} elem The element whose outerHTML is to be assigned to.189* @param {!goog.html.SafeHtml} html The known-safe HTML to assign.190*/191goog.dom.safe.setOuterHtml = function(elem, html) {192'use strict';193elem.outerHTML = goog.html.SafeHtml.unwrapTrustedHTML(html);194};195196197/**198* Safely assigns a URL a form element's action property.199*200* If url is of type goog.html.SafeUrl, its value is unwrapped and assigned to201* form's action property. If url is of type string however, it is first202* sanitized using goog.html.SafeUrl.sanitize.203*204* Example usage:205* goog.dom.safe.setFormElementAction(formEl, url);206* which is a safe alternative to207* formEl.action = url;208* The latter can result in XSS vulnerabilities if url is a209* user-/attacker-controlled value.210*211* @param {!Element} form The form element whose action property212* is to be assigned to.213* @param {string|!goog.html.SafeUrl} url The URL to assign.214* @return {void}215* @see goog.html.SafeUrl#sanitize216*/217goog.dom.safe.setFormElementAction = function(form, url) {218'use strict';219/** @type {!goog.html.SafeUrl} */220var safeUrl;221if (url instanceof goog.html.SafeUrl) {222safeUrl = url;223} else {224safeUrl = goog.html.SafeUrl.sanitizeJavascriptUrlAssertUnchanged(url);225}226goog.asserts.dom.assertIsHtmlFormElement(form).action =227goog.html.SafeUrl.unwrap(safeUrl);228};229230/**231* Safely assigns a URL to a button element's formaction property.232*233* If url is of type goog.html.SafeUrl, its value is unwrapped and assigned to234* button's formaction property. If url is of type string however, it is first235* sanitized using goog.html.SafeUrl.sanitize.236*237* Example usage:238* goog.dom.safe.setButtonFormAction(buttonEl, url);239* which is a safe alternative to240* buttonEl.action = url;241* The latter can result in XSS vulnerabilities if url is a242* user-/attacker-controlled value.243*244* @param {!Element} button The button element whose action property245* is to be assigned to.246* @param {string|!goog.html.SafeUrl} url The URL to assign.247* @return {void}248* @see goog.html.SafeUrl#sanitize249*/250goog.dom.safe.setButtonFormAction = function(button, url) {251'use strict';252/** @type {!goog.html.SafeUrl} */253var safeUrl;254if (url instanceof goog.html.SafeUrl) {255safeUrl = url;256} else {257safeUrl = goog.html.SafeUrl.sanitizeJavascriptUrlAssertUnchanged(url);258}259goog.asserts.dom.assertIsHtmlButtonElement(button).formAction =260goog.html.SafeUrl.unwrap(safeUrl);261};262/**263* Safely assigns a URL to an input element's formaction property.264*265* If url is of type goog.html.SafeUrl, its value is unwrapped and assigned to266* input's formaction property. If url is of type string however, it is first267* sanitized using goog.html.SafeUrl.sanitize.268*269* Example usage:270* goog.dom.safe.setInputFormAction(inputEl, url);271* which is a safe alternative to272* inputEl.action = url;273* The latter can result in XSS vulnerabilities if url is a274* user-/attacker-controlled value.275*276* @param {!Element} input The input element whose action property277* is to be assigned to.278* @param {string|!goog.html.SafeUrl} url The URL to assign.279* @return {void}280* @see goog.html.SafeUrl#sanitize281*/282goog.dom.safe.setInputFormAction = function(input, url) {283'use strict';284/** @type {!goog.html.SafeUrl} */285var safeUrl;286if (url instanceof goog.html.SafeUrl) {287safeUrl = url;288} else {289safeUrl = goog.html.SafeUrl.sanitizeJavascriptUrlAssertUnchanged(url);290}291goog.asserts.dom.assertIsHtmlInputElement(input).formAction =292goog.html.SafeUrl.unwrap(safeUrl);293};294295/**296* Sets the given element's style property to the contents of the provided297* SafeStyle object.298* @param {!Element} elem299* @param {!goog.html.SafeStyle} style300* @return {void}301*/302goog.dom.safe.setStyle = function(elem, style) {303'use strict';304elem.style.cssText = goog.html.SafeStyle.unwrap(style);305};306307308/**309* Writes known-safe HTML to a document.310* @param {!Document} doc The document to be written to.311* @param {!goog.html.SafeHtml} html The known-safe HTML to assign.312* @return {void}313*/314goog.dom.safe.documentWrite = function(doc, html) {315'use strict';316doc.write(goog.html.SafeHtml.unwrapTrustedHTML(html));317};318319320/**321* Safely assigns a URL to an anchor element's href property.322*323* If url is of type goog.html.SafeUrl, its value is unwrapped and assigned to324* anchor's href property. If url is of type string however, it is first325* sanitized using goog.html.SafeUrl.sanitize.326*327* Example usage:328* goog.dom.safe.setAnchorHref(anchorEl, url);329* which is a safe alternative to330* anchorEl.href = url;331* The latter can result in XSS vulnerabilities if url is a332* user-/attacker-controlled value.333*334* @param {!HTMLAnchorElement} anchor The anchor element whose href property335* is to be assigned to.336* @param {string|!goog.html.SafeUrl} url The URL to assign.337* @return {void}338* @see goog.html.SafeUrl#sanitize339*/340goog.dom.safe.setAnchorHref = function(anchor, url) {341'use strict';342goog.asserts.dom.assertIsHtmlAnchorElement(anchor);343/** @type {!goog.html.SafeUrl} */344var safeUrl;345if (url instanceof goog.html.SafeUrl) {346safeUrl = url;347} else {348safeUrl = goog.html.SafeUrl.sanitizeJavascriptUrlAssertUnchanged(url);349}350anchor.href = goog.html.SafeUrl.unwrap(safeUrl);351};352353354/**355* Safely assigns a URL to a audio element's src property.356*357* If url is of type goog.html.SafeUrl, its value is unwrapped and assigned to358* audio's src property. If url is of type string however, it is first359* sanitized using goog.html.SafeUrl.sanitize.360*361* @param {!HTMLAudioElement} audioElement The audio element whose src property362* is to be assigned to.363* @param {string|!goog.html.SafeUrl} url The URL to assign.364* @return {void}365* @see goog.html.SafeUrl#sanitize366*/367goog.dom.safe.setAudioSrc = function(audioElement, url) {368'use strict';369goog.asserts.dom.assertIsHtmlAudioElement(audioElement);370/** @type {!goog.html.SafeUrl} */371var safeUrl;372if (url instanceof goog.html.SafeUrl) {373safeUrl = url;374} else {375safeUrl = goog.html.SafeUrl.sanitizeJavascriptUrlAssertUnchanged(url);376}377audioElement.src = goog.html.SafeUrl.unwrap(safeUrl);378};379380/**381* Safely assigns a URL to a video element's src property.382*383* If url is of type goog.html.SafeUrl, its value is unwrapped and assigned to384* video's src property. If url is of type string however, it is first385* sanitized using goog.html.SafeUrl.sanitize.386*387* @param {!HTMLVideoElement} videoElement The video element whose src property388* is to be assigned to.389* @param {string|!goog.html.SafeUrl} url The URL to assign.390* @return {void}391* @see goog.html.SafeUrl#sanitize392*/393goog.dom.safe.setVideoSrc = function(videoElement, url) {394'use strict';395goog.asserts.dom.assertIsHtmlVideoElement(videoElement);396/** @type {!goog.html.SafeUrl} */397var safeUrl;398if (url instanceof goog.html.SafeUrl) {399safeUrl = url;400} else {401safeUrl = goog.html.SafeUrl.sanitizeJavascriptUrlAssertUnchanged(url);402}403videoElement.src = goog.html.SafeUrl.unwrap(safeUrl);404};405406/**407* Safely assigns a URL to an embed element's src property.408*409* Example usage:410* goog.dom.safe.setEmbedSrc(embedEl, url);411* which is a safe alternative to412* embedEl.src = url;413* The latter can result in loading untrusted code unless it is ensured that414* the URL refers to a trustworthy resource.415*416* @param {!HTMLEmbedElement} embed The embed element whose src property417* is to be assigned to.418* @param {!goog.html.TrustedResourceUrl} url The URL to assign.419*/420goog.dom.safe.setEmbedSrc = function(embed, url) {421'use strict';422goog.asserts.dom.assertIsHtmlEmbedElement(embed);423embed.src = goog.html.TrustedResourceUrl.unwrapTrustedScriptURL(url);424};425426427/**428* Safely assigns a URL to a frame element's src property.429*430* Example usage:431* goog.dom.safe.setFrameSrc(frameEl, url);432* which is a safe alternative to433* frameEl.src = url;434* The latter can result in loading untrusted code unless it is ensured that435* the URL refers to a trustworthy resource.436* @deprecated Use safevalues.dom.safeIframeEl.setSrc instead.437* @param {!HTMLFrameElement} frame The frame element whose src property438* is to be assigned to.439* @param {!goog.html.TrustedResourceUrl} url The URL to assign.440* @return {void}441*/442goog.dom.safe.setFrameSrc = function(frame, url) {443'use strict';444goog.asserts.dom.assertIsHtmlFrameElement(frame);445frame.src = goog.html.TrustedResourceUrl.unwrap(url);446};447448449/**450* Safely assigns a URL to an iframe element's src property.451*452* Example usage:453* goog.dom.safe.setIframeSrc(iframeEl, url);454* which is a safe alternative to455* iframeEl.src = url;456* The latter can result in loading untrusted code unless it is ensured that457* the URL refers to a trustworthy resource.458*459* @param {!HTMLIFrameElement} iframe The iframe element whose src property460* is to be assigned to.461* @param {!goog.html.TrustedResourceUrl} url The URL to assign.462* @return {void}463*/464goog.dom.safe.setIframeSrc = function(iframe, url) {465'use strict';466goog.asserts.dom.assertIsHtmlIFrameElement(iframe);467iframe.src = goog.html.TrustedResourceUrl.unwrap(url);468};469470471/**472* Safely assigns HTML to an iframe element's srcdoc property.473*474* Example usage:475* goog.dom.safe.setIframeSrcdoc(iframeEl, safeHtml);476* which is a safe alternative to477* iframeEl.srcdoc = html;478* The latter can result in loading untrusted code.479*480* @param {!HTMLIFrameElement} iframe The iframe element whose srcdoc property481* is to be assigned to.482* @param {!goog.html.SafeHtml} html The HTML to assign.483* @return {void}484*/485goog.dom.safe.setIframeSrcdoc = function(iframe, html) {486'use strict';487goog.asserts.dom.assertIsHtmlIFrameElement(iframe);488iframe.srcdoc = goog.html.SafeHtml.unwrapTrustedHTML(html);489};490491492/**493* Safely sets a link element's href and rel properties. Whether or not494* the URL assigned to href has to be a goog.html.TrustedResourceUrl495* depends on the value of the rel property. If rel contains "stylesheet"496* then a TrustedResourceUrl is required.497*498* Example usage:499* goog.dom.safe.setLinkHrefAndRel(linkEl, url, 'stylesheet');500* which is a safe alternative to501* linkEl.rel = 'stylesheet';502* linkEl.href = url;503* The latter can result in loading untrusted code unless it is ensured that504* the URL refers to a trustworthy resource.505*506* @param {!HTMLLinkElement} link The link element whose href property507* is to be assigned to.508* @param {string|!goog.html.SafeUrl|!goog.html.TrustedResourceUrl} url The URL509* to assign to the href property. Must be a TrustedResourceUrl if the510* value assigned to rel contains "stylesheet". A string value is511* sanitized with goog.html.SafeUrl.sanitize.512* @param {string} rel The value to assign to the rel property.513* @return {void}514* @throws {Error} if rel contains "stylesheet" and url is not a515* TrustedResourceUrl516* @see goog.html.SafeUrl#sanitize517*/518goog.dom.safe.setLinkHrefAndRel = function(link, url, rel) {519'use strict';520goog.asserts.dom.assertIsHtmlLinkElement(link);521link.rel = rel;522if (goog.string.internal.caseInsensitiveContains(rel, 'stylesheet')) {523goog.asserts.assert(524url instanceof goog.html.TrustedResourceUrl,525'URL must be TrustedResourceUrl because "rel" contains "stylesheet"');526link.href = goog.html.TrustedResourceUrl.unwrap(url);527const win = link.ownerDocument && link.ownerDocument.defaultView;528const nonce = goog.dom.safe.getStyleNonce(win);529if (nonce) {530link.setAttribute('nonce', nonce);531}532} else if (url instanceof goog.html.TrustedResourceUrl) {533link.href = goog.html.TrustedResourceUrl.unwrap(url);534} else if (url instanceof goog.html.SafeUrl) {535link.href = goog.html.SafeUrl.unwrap(url);536} else { // string537// SafeUrl.sanitize must return legitimate SafeUrl when passed a string.538link.href = goog.html.SafeUrl.unwrap(539goog.html.SafeUrl.sanitizeJavascriptUrlAssertUnchanged(url));540}541};542543544/**545* Safely assigns a URL to an object element's data property.546*547* Example usage:548* goog.dom.safe.setObjectData(objectEl, url);549* which is a safe alternative to550* objectEl.data = url;551* The latter can result in loading untrusted code unless setit is ensured that552* the URL refers to a trustworthy resource.553* @deprecated554*555* @param {!HTMLObjectElement} object The object element whose data property556* is to be assigned to.557* @param {!goog.html.TrustedResourceUrl} url The URL to assign.558* @return {void}559*/560goog.dom.safe.setObjectData = function(object, url) {561'use strict';562goog.asserts.dom.assertIsHtmlObjectElement(object);563object.data = goog.html.TrustedResourceUrl.unwrapTrustedScriptURL(url);564};565566567/**568* Safely assigns a URL to a script element's src property.569*570* Example usage:571* goog.dom.safe.setScriptSrc(scriptEl, url);572* which is a safe alternative to573* scriptEl.src = url;574* The latter can result in loading untrusted code unless it is ensured that575* the URL refers to a trustworthy resource.576*577* @param {!HTMLScriptElement} script The script element whose src property578* is to be assigned to.579* @param {!goog.html.TrustedResourceUrl} url The URL to assign.580* @return {void}581*/582goog.dom.safe.setScriptSrc = function(script, url) {583'use strict';584goog.asserts.dom.assertIsHtmlScriptElement(script);585goog.dom.safe.setNonceForScriptElement_(script);586script.src = goog.html.TrustedResourceUrl.unwrapTrustedScriptURL(url);587};588589590/**591* Safely assigns a value to a script element's content.592*593* Example usage:594* goog.dom.safe.setScriptContent(scriptEl, content);595* which is a safe alternative to596* scriptEl.text = content;597* The latter can result in executing untrusted code unless it is ensured that598* the code is loaded from a trustworthy resource.599*600* @param {!HTMLScriptElement} script The script element whose content is being601* set.602* @param {!goog.html.SafeScript} content The content to assign.603* @return {void}604*/605goog.dom.safe.setScriptContent = function(script, content) {606'use strict';607goog.asserts.dom.assertIsHtmlScriptElement(script);608goog.dom.safe.setNonceForScriptElement_(script);609script.textContent = goog.html.SafeScript.unwrapTrustedScript(content);610};611612613/**614* Set nonce-based CSPs to dynamically created scripts.615* @param {!HTMLScriptElement} script The script element whose nonce value616* is to be calculated617* @private618*/619goog.dom.safe.setNonceForScriptElement_ = function(script) {620'use strict';621var win = script.ownerDocument && script.ownerDocument.defaultView;622const nonce = goog.dom.safe.getScriptNonce(win);623if (nonce) {624script.setAttribute('nonce', nonce);625}626};627628629/**630* Safely assigns a URL to a Location object's href property.631*632* If url is of type goog.html.SafeUrl, its value is unwrapped and assigned to633* loc's href property. If url is of type string however, it is first sanitized634* using goog.html.SafeUrl.sanitize.635*636* Example usage:637* goog.dom.safe.setLocationHref(document.location, redirectUrl);638* which is a safe alternative to639* document.location.href = redirectUrl;640* The latter can result in XSS vulnerabilities if redirectUrl is a641* user-/attacker-controlled value.642*643* @param {!Location} loc The Location object whose href property is to be644* assigned to.645* @param {string|!goog.html.SafeUrl} url The URL to assign.646* @return {void}647* @see goog.html.SafeUrl#sanitize648649*/650goog.dom.safe.setLocationHref = function(loc, url) {651'use strict';652goog.dom.asserts.assertIsLocation(loc);653/** @type {!goog.html.SafeUrl} */654var safeUrl;655if (url instanceof goog.html.SafeUrl) {656safeUrl = url;657} else {658safeUrl = goog.html.SafeUrl.sanitizeJavascriptUrlAssertUnchanged(url);659}660loc.href = goog.html.SafeUrl.unwrap(safeUrl);661};662663/**664* Safely assigns the URL of a Location object.665*666* If url is of type goog.html.SafeUrl, its value is unwrapped and667* passed to Location#assign. If url is of type string however, it is668* first sanitized using goog.html.SafeUrl.sanitize.669*670* Example usage:671* goog.dom.safe.assignLocation(document.location, newUrl);672* which is a safe alternative to673* document.location.assign(newUrl);674* The latter can result in XSS vulnerabilities if newUrl is a675* user-/attacker-controlled value.676*677* This has the same behaviour as setLocationHref, however some test678* mock Location.assign instead of a property assignment.679*680* @param {!Location} loc The Location object which is to be assigned.681* @param {string|!goog.html.SafeUrl} url The URL to assign.682* @return {void}683* @see goog.html.SafeUrl#sanitize684*/685goog.dom.safe.assignLocation = function(loc, url) {686'use strict';687goog.dom.asserts.assertIsLocation(loc);688/** @type {!goog.html.SafeUrl} */689var safeUrl;690if (url instanceof goog.html.SafeUrl) {691safeUrl = url;692} else {693safeUrl = goog.html.SafeUrl.sanitizeJavascriptUrlAssertUnchanged(url);694}695loc.assign(goog.html.SafeUrl.unwrap(safeUrl));696};697698699/**700* Safely replaces the URL of a Location object.701*702* If url is of type goog.html.SafeUrl, its value is unwrapped and703* passed to Location#replace. If url is of type string however, it is704* first sanitized using goog.html.SafeUrl.sanitize.705*706* Example usage:707* goog.dom.safe.replaceLocation(document.location, newUrl);708* which is a safe alternative to709* document.location.replace(newUrl);710* The latter can result in XSS vulnerabilities if newUrl is a711* user-/attacker-controlled value.712*713* @param {!Location} loc The Location object which is to be replaced.714* @param {string|!goog.html.SafeUrl} url The URL to assign.715* @return {void}716* @see goog.html.SafeUrl#sanitize717*/718goog.dom.safe.replaceLocation = function(loc, url) {719'use strict';720/** @type {!goog.html.SafeUrl} */721var safeUrl;722if (url instanceof goog.html.SafeUrl) {723safeUrl = url;724} else {725safeUrl = goog.html.SafeUrl.sanitizeJavascriptUrlAssertUnchanged(url);726}727loc.replace(goog.html.SafeUrl.unwrap(safeUrl));728};729730731/**732* Safely opens a URL in a new window (via window.open).733*734* If url is of type goog.html.SafeUrl, its value is unwrapped and passed in to735* window.open. If url is of type string however, it is first sanitized736* using goog.html.SafeUrl.sanitize.737*738* Note that this function does not prevent leakages via the referer that is739* sent by window.open. It is advised to only use this to open 1st party URLs.740*741* Example usage:742* goog.dom.safe.openInWindow(url);743* which is a safe alternative to744* window.open(url);745* The latter can result in XSS vulnerabilities if url is a746* user-/attacker-controlled value.747*748* @param {string|!goog.html.SafeUrl} url The URL to open.749* @param {Window=} opt_openerWin Window of which to call the .open() method.750* Defaults to the global window.751* @param {!goog.string.Const|string=} opt_name Name of the window to open in.752* Can be _top, etc as allowed by window.open(). This accepts string for753* legacy reasons. Pass goog.string.Const if possible.754* @param {string=} opt_specs Comma-separated list of specifications, same as755* in window.open().756* @return {Window} Window the url was opened in.757*/758goog.dom.safe.openInWindow = function(url, opt_openerWin, opt_name, opt_specs) {759'use strict';760/** @type {!goog.html.SafeUrl} */761var safeUrl;762if (url instanceof goog.html.SafeUrl) {763safeUrl = url;764} else {765safeUrl = goog.html.SafeUrl.sanitizeJavascriptUrlAssertUnchanged(url);766}767var win = opt_openerWin || goog.global;768// If opt_name is undefined, simply passing that in to open() causes IE to769// reuse the current window instead of opening a new one. Thus we pass '' in770// instead, which according to spec opens a new window. See771// https://html.spec.whatwg.org/multipage/browsers.html#dom-open .772var name = opt_name instanceof goog.string.Const ?773goog.string.Const.unwrap(opt_name) :774opt_name || '';775// Do not pass opt_specs to window.open unless it was provided by the caller.776// IE11 will use it as a signal to open a new window rather than a new tab777// (even if it is undefined).778if (opt_specs !== undefined) {779return win.open(goog.html.SafeUrl.unwrap(safeUrl), name, opt_specs);780} else {781return win.open(goog.html.SafeUrl.unwrap(safeUrl), name);782}783};784785786/**787* Parses the HTML as 'text/html'.788* @param {!DOMParser} parser789* @param {!goog.html.SafeHtml} html The HTML to be parsed.790* @return {!Document}791*/792goog.dom.safe.parseFromStringHtml = function(parser, html) {793'use strict';794return goog.dom.safe.parseFromString(parser, html, 'text/html');795};796797798/**799* Parses the string.800* @param {!DOMParser} parser801* @param {!goog.html.SafeHtml} content Note: We don't have a special type for802* XML or SVG supported by this function so we use SafeHtml.803* @param {string} type804* @return {!Document}805*/806goog.dom.safe.parseFromString = function(parser, content, type) {807'use strict';808return parser.parseFromString(809goog.html.SafeHtml.unwrapTrustedHTML(content), type);810};811812813/**814* Safely creates an HTMLImageElement from a Blob.815*816* Example usage:817* goog.dom.safe.createImageFromBlob(blob);818* which is a safe alternative to819* image.src = createObjectUrl(blob)820* The latter can result in executing malicious same-origin scripts from a bad821* Blob.822* @param {!Blob} blob The blob to create the image from.823* @return {!HTMLImageElement} The image element created from the blob.824* @throws {!Error} If called with a Blob with a MIME type other than image/.*.825*/826goog.dom.safe.createImageFromBlob = function(blob) {827'use strict';828// Any image/* MIME type is accepted as safe.829if (!/^image\/.*/g.test(blob.type)) {830throw new Error(831'goog.dom.safe.createImageFromBlob only accepts MIME type image/.*.');832}833var objectUrl = goog.global.URL.createObjectURL(blob);834var image = new goog.global.Image();835image.onload = function() {836'use strict';837goog.global.URL.revokeObjectURL(objectUrl);838};839image.src = objectUrl;840return image;841};842843/**844* Creates a DocumentFragment by parsing html in the context of a Range.845* @param {!Range} range The Range object starting from the context node to846* create a fragment in.847* @param {!goog.html.SafeHtml} html HTML to create a fragment from.848* @return {?DocumentFragment}849*/850goog.dom.safe.createContextualFragment = function(range, html) {851'use strict';852return range.createContextualFragment(853goog.html.SafeHtml.unwrapTrustedHTML(html));854};855856/**857* Returns CSP script nonce, if set for any <script> tag.858* @param {?Window=} opt_window The window context used to retrieve the nonce.859* Defaults to global context.860* @return {string} CSP nonce or empty string if no nonce is present.861*/862goog.dom.safe.getScriptNonce = function(opt_window) {863return goog.dom.safe.getNonce_('script[nonce]', opt_window);864};865866/**867* Returns CSP style nonce, if set for any <style> or <link rel="stylesheet">868* tag.869* @param {?Window=} opt_window The window context used to retrieve the nonce.870* Defaults to global context.871* @return {string} CSP nonce or empty string if no nonce is present.872*/873goog.dom.safe.getStyleNonce = function(opt_window) {874return goog.dom.safe.getNonce_(875'style[nonce],link[rel="stylesheet"][nonce]', opt_window);876};877878/**879* According to the CSP3 spec a nonce must be a valid base64 string.880* @see https://www.w3.org/TR/CSP3/#grammardef-base64-value881* @private @const882*/883goog.dom.safe.NONCE_PATTERN_ = /^[\w+/_-]+[=]{0,2}$/;884885/**886* Returns CSP nonce, if set for any tag of given type.887* @param {string} selector Selector for locating the element with nonce.888* @param {?Window=} win The window context used to retrieve the nonce.889* @return {string} CSP nonce or empty string if no nonce is present.890* @private891*/892goog.dom.safe.getNonce_ = function(selector, win) {893const doc = (win || goog.global).document;894if (!doc.querySelector) {895return '';896}897let el = doc.querySelector(selector);898if (el) {899// Try to get the nonce from the IDL property first, because browsers that900// implement additional nonce protection features (currently only Chrome) to901// prevent nonce stealing via CSS do not expose the nonce via attributes.902// See https://github.com/whatwg/html/issues/2369903const nonce = el['nonce'] || el.getAttribute('nonce');904if (nonce && goog.dom.safe.NONCE_PATTERN_.test(nonce)) {905return nonce;906}907}908return '';909};910911912