mirror of
https://github.com/Polymer/polymer.git
synced 2024-07-07 04:43:03 -05:00
Add support for TrustedTypes (#5692)
* Add support for TrustedTypes to html-tag.js This avoids setting innerHTML to a string. * Comment on why .slice() the XMLSerializer output * Handle data binding Trusted Types into attributes Fixes #5648 * Lint clean
This commit is contained in:
parent
1c0153d97b
commit
10220c9af1
|
@ -40,6 +40,7 @@
|
|||
"Polymer": true,
|
||||
"ShadyDOM": true,
|
||||
"ShadyCSS": true,
|
||||
"JSCompiler_renameProperty": true
|
||||
"JSCompiler_renameProperty": true,
|
||||
"trustedTypes": true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,14 @@ while (proto) {
|
|||
proto = Object.getPrototypeOf(proto);
|
||||
}
|
||||
|
||||
const isTrustedType = (() => {
|
||||
if (!window.trustedTypes) {
|
||||
return () => false;
|
||||
}
|
||||
return (val) => trustedTypes.isHTML(val) ||
|
||||
trustedTypes.isScript(val) || trustedTypes.isScriptURL(val);
|
||||
})();
|
||||
|
||||
/**
|
||||
* Used to save the value of a property that will be overridden with
|
||||
* an accessor. If the `model` is a prototype, the values will be saved
|
||||
|
@ -215,6 +223,14 @@ export const PropertyAccessors = dedupingMixin(superClass => {
|
|||
if (value instanceof Date) {
|
||||
return value.toString();
|
||||
} else if (value) {
|
||||
if (isTrustedType(value)) {
|
||||
/**
|
||||
* Here `value` isn't actually a string, but it should be
|
||||
* passed into APIs that normally expect a string, like
|
||||
* elem.setAttribute.
|
||||
*/
|
||||
return /** @type {?} */ (value);
|
||||
}
|
||||
try {
|
||||
return JSON.stringify(value);
|
||||
} catch(x) {
|
||||
|
|
|
@ -9,13 +9,33 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
|||
*/
|
||||
import './boot.js';
|
||||
|
||||
/**
|
||||
* Our TrustedTypePolicy for HTML which is declared using the Polymer html
|
||||
* template tag function.
|
||||
*
|
||||
* That HTML is a developer-authored constant, and is parsed with innerHTML
|
||||
* before any untrusted expressions have been mixed in. Therefor it is
|
||||
* considered safe by construction.
|
||||
*
|
||||
* @type {!TrustedTypePolicy|undefined}
|
||||
*/
|
||||
const policy = window.trustedTypes &&
|
||||
trustedTypes.createPolicy('polymer-html-literal', {createHTML: (s) => s});
|
||||
|
||||
/**
|
||||
* Class representing a static string value which can be used to filter
|
||||
* strings by asseting that they have been created via this class. The
|
||||
* `value` property returns the string passed to the constructor.
|
||||
*/
|
||||
class LiteralString {
|
||||
constructor(string) {
|
||||
/**
|
||||
* @param {!ITemplateArray} strings Constant parts of tagged template literal
|
||||
* @param {!Array<*>} values Variable parts of tagged template literal
|
||||
*/
|
||||
constructor(strings, values) {
|
||||
assertValidTemplateStringParameters(strings, values);
|
||||
const string = values.reduce(
|
||||
(acc, v, idx) => acc + literalValue(v) + strings[idx + 1], strings[0]);
|
||||
/** @type {string} */
|
||||
this.value = string.toString();
|
||||
}
|
||||
|
@ -48,7 +68,15 @@ function literalValue(value) {
|
|||
*/
|
||||
function htmlValue(value) {
|
||||
if (value instanceof HTMLTemplateElement) {
|
||||
return /** @type {!HTMLTemplateElement } */(value).innerHTML;
|
||||
// Use the XML serializer to avoid xMSS attacks from browsers' sometimes
|
||||
// unexpected formatting / cleanup of innerHTML.
|
||||
const serializedNewTree = new XMLSerializer().serializeToString(
|
||||
/** @type {!HTMLTemplateElement } */ (value));
|
||||
// The XMLSerializer is similar to .outerHTML, so slice off the leading
|
||||
// and trailing parts of the <template> wrapper tag.
|
||||
return serializedNewTree.slice(
|
||||
serializedNewTree.indexOf('>') + 1,
|
||||
serializedNewTree.lastIndexOf('</'));
|
||||
} else if (value instanceof LiteralString) {
|
||||
return literalValue(value);
|
||||
} else {
|
||||
|
@ -92,12 +120,35 @@ function htmlValue(value) {
|
|||
* @return {!HTMLTemplateElement} Constructed HTMLTemplateElement
|
||||
*/
|
||||
export const html = function html(strings, ...values) {
|
||||
const template = /** @type {!HTMLTemplateElement} */(document.createElement('template'));
|
||||
template.innerHTML = values.reduce((acc, v, idx) =>
|
||||
acc + htmlValue(v) + strings[idx + 1], strings[0]);
|
||||
assertValidTemplateStringParameters(strings, values);
|
||||
const template =
|
||||
/** @type {!HTMLTemplateElement} */ (document.createElement('template'));
|
||||
let value = values.reduce(
|
||||
(acc, v, idx) => acc + htmlValue(v) + strings[idx + 1], strings[0]);
|
||||
if (policy) {
|
||||
value = policy.createHTML(value);
|
||||
}
|
||||
template.innerHTML = value;
|
||||
return template;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {!ITemplateArray} strings Constant parts of tagged template literal
|
||||
* @param {!Array<*>} values Array of values from quasis
|
||||
*/
|
||||
const assertValidTemplateStringParameters = (strings, values) => {
|
||||
// Note: if/when https://github.com/tc39/proposal-array-is-template-object
|
||||
// is standardized, use that instead when available, as it can perform an
|
||||
// unforgable check (though of course, the function itself can be forged).
|
||||
if (!Array.isArray(strings) || !Array.isArray(strings.raw) ||
|
||||
(values.length !== strings.length - 1)) {
|
||||
// This is either caused by a browser bug, a compiler bug, or someone
|
||||
// calling the html template tag function as a regular function.
|
||||
//
|
||||
throw new TypeError('Invalid call to the html template tag');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* An html literal tag that can be used with `html` to compose.
|
||||
* a literal string.
|
||||
|
@ -123,6 +174,5 @@ export const html = function html(strings, ...values) {
|
|||
* @return {!LiteralString} Constructed literal string
|
||||
*/
|
||||
export const htmlLiteral = function(strings, ...values) {
|
||||
return new LiteralString(values.reduce((acc, v, idx) =>
|
||||
acc + literalValue(v) + strings[idx + 1], strings[0]));
|
||||
return new LiteralString(strings, values);
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue
Block a user