fix(core): use Trusted Types policy in inert DOM builder (#39208)

When Angular is used in an environment that enforces Trusted Types, the
inert DOM builder raises a Trusted Types violation due to its use of
DOMParser and element.innerHTML with plain strings. Since it is only
used internally (in the HTML sanitizer and for i18n ICU parsing), we
update it to use Angular's Trusted Types policy to promote the provided
HTML to TrustedHTML.

PR Close #39208
This commit is contained in:
Bjarki 2020-10-07 00:04:32 +00:00 committed by atscott
parent b642f0bf45
commit 7d4929918d
1 changed files with 9 additions and 5 deletions

View File

@ -6,6 +6,8 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {trustedHTMLFromString} from '../util/security/trusted_types';
/** /**
* This helper is used to get hold of an inert tree of DOM elements containing dirty HTML * This helper is used to get hold of an inert tree of DOM elements containing dirty HTML
* that needs sanitizing. * that needs sanitizing.
@ -36,8 +38,9 @@ class DOMParserHelper implements InertBodyHelper {
// in `html` from consuming the otherwise explicit `</body>` tag. // in `html` from consuming the otherwise explicit `</body>` tag.
html = '<body><remove></remove>' + html; html = '<body><remove></remove>' + html;
try { try {
const body = new (window as any).DOMParser().parseFromString(html, 'text/html').body as const body = new window.DOMParser()
HTMLBodyElement; .parseFromString(trustedHTMLFromString(html) as string, 'text/html')
.body as HTMLBodyElement;
body.removeChild(body.firstChild!); body.removeChild(body.firstChild!);
return body; return body;
} catch { } catch {
@ -71,7 +74,7 @@ class InertDocumentHelper implements InertBodyHelper {
// Prefer using <template> element if supported. // Prefer using <template> element if supported.
const templateEl = this.inertDocument.createElement('template'); const templateEl = this.inertDocument.createElement('template');
if ('content' in templateEl) { if ('content' in templateEl) {
templateEl.innerHTML = html; templateEl.innerHTML = trustedHTMLFromString(html) as string;
return templateEl; return templateEl;
} }
@ -83,7 +86,7 @@ class InertDocumentHelper implements InertBodyHelper {
// down the line. This has been worked around by creating a new inert `body` and using it as // down the line. This has been worked around by creating a new inert `body` and using it as
// the root node in which we insert the HTML. // the root node in which we insert the HTML.
const inertBody = this.inertDocument.createElement('body'); const inertBody = this.inertDocument.createElement('body');
inertBody.innerHTML = html; inertBody.innerHTML = trustedHTMLFromString(html) as string;
// Support: IE 9-11 only // Support: IE 9-11 only
// strip custom-namespaced attributes on IE<=11 // strip custom-namespaced attributes on IE<=11
@ -129,7 +132,8 @@ class InertDocumentHelper implements InertBodyHelper {
*/ */
export function isDOMParserAvailable() { export function isDOMParserAvailable() {
try { try {
return !!new (window as any).DOMParser().parseFromString('', 'text/html'); return !!new window.DOMParser().parseFromString(
trustedHTMLFromString('') as string, 'text/html');
} catch { } catch {
return false; return false;
} }