initial commit
This commit is contained in:
Executable
+1085
File diff suppressed because it is too large
Load Diff
Executable
+238
@@ -0,0 +1,238 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright The Closure Library Authors.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview The SafeScript type and its builders.
|
||||
*
|
||||
* TODO(xtof): Link to document stating type contract.
|
||||
*/
|
||||
|
||||
goog.module('goog.html.SafeScript');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
const Const = goog.require('goog.string.Const');
|
||||
const TypedString = goog.require('goog.string.TypedString');
|
||||
const trustedtypes = goog.require('goog.html.trustedtypes');
|
||||
const {fail} = goog.require('goog.asserts');
|
||||
|
||||
/**
|
||||
* Token used to ensure that object is created only from this file. No code
|
||||
* outside of this file can access this token.
|
||||
* @const {!Object}
|
||||
*/
|
||||
const CONSTRUCTOR_TOKEN_PRIVATE = {};
|
||||
|
||||
/**
|
||||
* A string-like object which represents JavaScript code and that carries the
|
||||
* security type contract that its value, as a string, will not cause execution
|
||||
* of unconstrained attacker controlled code (XSS) when evaluated as JavaScript
|
||||
* in a browser.
|
||||
*
|
||||
* Instances of this type must be created via the factory method
|
||||
* `SafeScript.fromConstant` and not by invoking its constructor. The
|
||||
* constructor intentionally takes an extra parameter that cannot be constructed
|
||||
* outside of this file and the type is immutable; hence only a default instance
|
||||
* corresponding to the empty string can be obtained via constructor invocation.
|
||||
*
|
||||
* A SafeScript's string representation can safely be interpolated as the
|
||||
* content of a script element within HTML. The SafeScript string should not be
|
||||
* escaped before interpolation.
|
||||
*
|
||||
* Note that the SafeScript might contain text that is attacker-controlled but
|
||||
* that text should have been interpolated with appropriate escaping,
|
||||
* sanitization and/or validation into the right location in the script, such
|
||||
* that it is highly constrained in its effect (for example, it had to match a
|
||||
* set of whitelisted words).
|
||||
*
|
||||
* A SafeScript can be constructed via security-reviewed unchecked
|
||||
* conversions. In this case producers of SafeScript must ensure themselves that
|
||||
* the SafeScript does not contain unsafe script. Note in particular that
|
||||
* `<` is dangerous, even when inside JavaScript strings, and so should
|
||||
* always be forbidden or JavaScript escaped in user controlled input. For
|
||||
* example, if `</script><script>evil</script>"` were
|
||||
* interpolated inside a JavaScript string, it would break out of the context
|
||||
* of the original script element and `evil` would execute. Also note
|
||||
* that within an HTML script (raw text) element, HTML character references,
|
||||
* such as "<" are not allowed. See
|
||||
* http://www.w3.org/TR/html5/scripting-1.html#restrictions-for-contents-of-script-elements.
|
||||
* Creating SafeScript objects HAS SIDE-EFFECTS due to calling Trusted Types Web
|
||||
* API.
|
||||
*
|
||||
* @see SafeScript#fromConstant
|
||||
* @final
|
||||
* @implements {TypedString}
|
||||
*/
|
||||
class SafeScript {
|
||||
/**
|
||||
* @param {!TrustedScript|string} value
|
||||
* @param {!Object} token package-internal implementation detail.
|
||||
*/
|
||||
constructor(value, token) {
|
||||
/**
|
||||
* The contained value of this SafeScript. The field has a purposely ugly
|
||||
* name to make (non-compiled) code that attempts to directly access this
|
||||
* field stand out.
|
||||
* @private {!TrustedScript|string}
|
||||
*/
|
||||
this.privateDoNotAccessOrElseSafeScriptWrappedValue_ =
|
||||
(token === CONSTRUCTOR_TOKEN_PRIVATE) ? value : '';
|
||||
|
||||
/**
|
||||
* @override
|
||||
* @const
|
||||
*/
|
||||
this.implementsGoogStringTypedString = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a SafeScript object from a compile-time constant string.
|
||||
*
|
||||
* @param {!Const} script A compile-time-constant string from which to create
|
||||
* a SafeScript.
|
||||
* @return {!SafeScript} A SafeScript object initialized to `script`.
|
||||
*/
|
||||
static fromConstant(script) {
|
||||
const scriptString = Const.unwrap(script);
|
||||
if (scriptString.length === 0) {
|
||||
return SafeScript.EMPTY;
|
||||
}
|
||||
return SafeScript.createSafeScriptSecurityPrivateDoNotAccessOrElse(
|
||||
scriptString);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a SafeScript JSON representation from anything that could be passed
|
||||
* to JSON.stringify.
|
||||
* @param {*} val
|
||||
* @return {!SafeScript}
|
||||
*/
|
||||
static fromJson(val) {
|
||||
return SafeScript.createSafeScriptSecurityPrivateDoNotAccessOrElse(
|
||||
SafeScript.stringify_(val));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns this SafeScript's value as a string.
|
||||
*
|
||||
* IMPORTANT: In code where it is security relevant that an object's type is
|
||||
* indeed `SafeScript`, use `SafeScript.unwrap` instead of
|
||||
* this method. If in doubt, assume that it's security relevant. In
|
||||
* particular, note that goog.html functions which return a goog.html type do
|
||||
* not guarantee the returned instance is of the right type. For example:
|
||||
*
|
||||
* <pre>
|
||||
* var fakeSafeHtml = new String('fake');
|
||||
* fakeSafeHtml.__proto__ = goog.html.SafeHtml.prototype;
|
||||
* var newSafeHtml = goog.html.SafeHtml.htmlEscape(fakeSafeHtml);
|
||||
* // newSafeHtml is just an alias for fakeSafeHtml, it's passed through by
|
||||
* // goog.html.SafeHtml.htmlEscape() as fakeSafeHtml
|
||||
* // instanceof goog.html.SafeHtml.
|
||||
* </pre>
|
||||
*
|
||||
* @see SafeScript#unwrap
|
||||
* @override
|
||||
*/
|
||||
getTypedStringValue() {
|
||||
return this.privateDoNotAccessOrElseSafeScriptWrappedValue_.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a runtime check that the provided object is indeed a
|
||||
* SafeScript object, and returns its value.
|
||||
*
|
||||
* @param {!SafeScript} safeScript The object to extract from.
|
||||
* @return {string} The safeScript object's contained string, unless
|
||||
* the run-time type check fails. In that case, `unwrap` returns an
|
||||
* innocuous string, or, if assertions are enabled, throws
|
||||
* `asserts.AssertionError`.
|
||||
*/
|
||||
static unwrap(safeScript) {
|
||||
return SafeScript.unwrapTrustedScript(safeScript).toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Unwraps value as TrustedScript if supported or as a string if not.
|
||||
* @param {!SafeScript} safeScript
|
||||
* @return {!TrustedScript|string}
|
||||
* @see SafeScript.unwrap
|
||||
*/
|
||||
static unwrapTrustedScript(safeScript) {
|
||||
// Perform additional Run-time type-checking to ensure that
|
||||
// safeScript is indeed an instance of the expected type. This
|
||||
// provides some additional protection against security bugs due to
|
||||
// application code that disables type checks.
|
||||
// Specifically, the following checks are performed:
|
||||
// 1. The object is an instance of the expected type.
|
||||
// 2. The object is not an instance of a subclass.
|
||||
if (safeScript instanceof SafeScript &&
|
||||
safeScript.constructor === SafeScript) {
|
||||
return safeScript.privateDoNotAccessOrElseSafeScriptWrappedValue_;
|
||||
} else {
|
||||
fail(
|
||||
'expected object of type SafeScript, got \'' + safeScript +
|
||||
'\' of type ' + goog.typeOf(safeScript));
|
||||
return 'type_error:SafeScript';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the given value to an embeddable JSON string and returns it. The
|
||||
* resulting string can be embedded in HTML because the '<' character is
|
||||
* encoded.
|
||||
*
|
||||
* @param {*} val
|
||||
* @return {string}
|
||||
* @private
|
||||
*/
|
||||
static stringify_(val) {
|
||||
const json = JSON.stringify(val);
|
||||
return json.replace(/</g, '\\x3c');
|
||||
}
|
||||
|
||||
/**
|
||||
* Package-internal utility method to create SafeScript instances.
|
||||
*
|
||||
* @param {string} script The string to initialize the SafeScript object with.
|
||||
* @return {!SafeScript} The initialized SafeScript object.
|
||||
* @package
|
||||
*/
|
||||
static createSafeScriptSecurityPrivateDoNotAccessOrElse(script) {
|
||||
const policy = trustedtypes.getPolicyPrivateDoNotAccessOrElse();
|
||||
const trustedScript = policy ? policy.createScript(script) : script;
|
||||
return new SafeScript(trustedScript, CONSTRUCTOR_TOKEN_PRIVATE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string-representation of this value.
|
||||
*
|
||||
* To obtain the actual string value wrapped in a SafeScript, use
|
||||
* `SafeScript.unwrap`.
|
||||
*
|
||||
* @return {string}
|
||||
* @see SafeScript#unwrap
|
||||
* @override
|
||||
*/
|
||||
SafeScript.prototype.toString = function() {
|
||||
return this.privateDoNotAccessOrElseSafeScriptWrappedValue_.toString();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A SafeScript instance corresponding to the empty string.
|
||||
* @const {!SafeScript}
|
||||
*/
|
||||
SafeScript.EMPTY = /** @type {!SafeScript} */ ({
|
||||
// NOTE: this compiles to nothing, but hides the possible side effect of
|
||||
// SafeScript creation (due to calling trustedTypes.createPolicy) from the
|
||||
// compiler so that the entire call can be removed if the result is not used.
|
||||
valueOf: function() {
|
||||
return SafeScript.createSafeScriptSecurityPrivateDoNotAccessOrElse('');
|
||||
},
|
||||
}.valueOf());
|
||||
|
||||
|
||||
exports = SafeScript;
|
||||
Executable
+585
@@ -0,0 +1,585 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright The Closure Library Authors.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview The SafeStyle type and its builders.
|
||||
*
|
||||
* TODO(xtof): Link to document stating type contract.
|
||||
*/
|
||||
|
||||
goog.module('goog.html.SafeStyle');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
const Const = goog.require('goog.string.Const');
|
||||
const SafeUrl = goog.require('goog.html.SafeUrl');
|
||||
const TypedString = goog.require('goog.string.TypedString');
|
||||
const {AssertionError, assert, fail} = goog.require('goog.asserts');
|
||||
const {contains, endsWith} = goog.require('goog.string.internal');
|
||||
|
||||
/**
|
||||
* Token used to ensure that object is created only from this file. No code
|
||||
* outside of this file can access this token.
|
||||
* @type {!Object}
|
||||
* @const
|
||||
*/
|
||||
const CONSTRUCTOR_TOKEN_PRIVATE = {};
|
||||
|
||||
/**
|
||||
* A string-like object which represents a sequence of CSS declarations
|
||||
* (`propertyName1: propertyvalue1; propertyName2: propertyValue2; ...`)
|
||||
* and that carries the security type contract that its value, as a string,
|
||||
* will not cause untrusted script execution (XSS) when evaluated as CSS in a
|
||||
* browser.
|
||||
*
|
||||
* Instances of this type must be created via the factory methods
|
||||
* (`SafeStyle.create` or `SafeStyle.fromConstant`)
|
||||
* and not by invoking its constructor. The constructor intentionally takes an
|
||||
* extra parameter that cannot be constructed outside of this file and the type
|
||||
* is immutable; hence only a default instance corresponding to the empty string
|
||||
* can be obtained via constructor invocation.
|
||||
*
|
||||
* SafeStyle's string representation can safely be:
|
||||
* <ul>
|
||||
* <li>Interpolated as the content of a *quoted* HTML style attribute.
|
||||
* However, the SafeStyle string *must be HTML-attribute-escaped* before
|
||||
* interpolation.
|
||||
* <li>Interpolated as the content of a {}-wrapped block within a stylesheet.
|
||||
* '<' characters in the SafeStyle string *must be CSS-escaped* before
|
||||
* interpolation. The SafeStyle string is also guaranteed not to be able
|
||||
* to introduce new properties or elide existing ones.
|
||||
* <li>Interpolated as the content of a {}-wrapped block within an HTML
|
||||
* <style> element. '<' characters in the SafeStyle string
|
||||
* *must be CSS-escaped* before interpolation.
|
||||
* <li>Assigned to the style property of a DOM node. The SafeStyle string
|
||||
* should not be escaped before being assigned to the property.
|
||||
* </ul>
|
||||
*
|
||||
* A SafeStyle may never contain literal angle brackets. Otherwise, it could
|
||||
* be unsafe to place a SafeStyle into a <style> tag (where it can't
|
||||
* be HTML escaped). For example, if the SafeStyle containing
|
||||
* `font: 'foo <style/><script>evil</script>'` were
|
||||
* interpolated within a <style> tag, this would then break out of the
|
||||
* style context into HTML.
|
||||
*
|
||||
* A SafeStyle may contain literal single or double quotes, and as such the
|
||||
* entire style string must be escaped when used in a style attribute (if
|
||||
* this were not the case, the string could contain a matching quote that
|
||||
* would escape from the style attribute).
|
||||
*
|
||||
* Values of this type must be composable, i.e. for any two values
|
||||
* `style1` and `style2` of this type,
|
||||
* `SafeStyle.unwrap(style1) +
|
||||
* SafeStyle.unwrap(style2)` must itself be a value that satisfies
|
||||
* the SafeStyle type constraint. This requirement implies that for any value
|
||||
* `style` of this type, `SafeStyle.unwrap(style)` must
|
||||
* not end in a "property value" or "property name" context. For example,
|
||||
* a value of `background:url("` or `font-` would not satisfy the
|
||||
* SafeStyle contract. This is because concatenating such strings with a
|
||||
* second value that itself does not contain unsafe CSS can result in an
|
||||
* overall string that does. For example, if `javascript:evil())"` is
|
||||
* appended to `background:url("}, the resulting string may result in
|
||||
* the execution of a malicious script.
|
||||
*
|
||||
* TODO(mlourenco): Consider whether we should implement UTF-8 interchange
|
||||
* validity checks and blacklisting of newlines (including Unicode ones) and
|
||||
* other whitespace characters (\t, \f). Document here if so and also update
|
||||
* SafeStyle.fromConstant().
|
||||
*
|
||||
* The following example values comply with this type's contract:
|
||||
* <ul>
|
||||
* <li><pre>width: 1em;</pre>
|
||||
* <li><pre>height:1em;</pre>
|
||||
* <li><pre>width: 1em;height: 1em;</pre>
|
||||
* <li><pre>background:url('http://url');</pre>
|
||||
* </ul>
|
||||
* In addition, the empty string is safe for use in a CSS attribute.
|
||||
*
|
||||
* The following example values do NOT comply with this type's contract:
|
||||
* <ul>
|
||||
* <li><pre>background: red</pre> (missing a trailing semi-colon)
|
||||
* <li><pre>background:</pre> (missing a value and a trailing semi-colon)
|
||||
* <li><pre>1em</pre> (missing an attribute name, which provides context for
|
||||
* the value)
|
||||
* </ul>
|
||||
*
|
||||
* @see SafeStyle#create
|
||||
* @see SafeStyle#fromConstant
|
||||
* @see http://www.w3.org/TR/css3-syntax/
|
||||
* @final
|
||||
* @struct
|
||||
* @implements {TypedString}
|
||||
*/
|
||||
class SafeStyle {
|
||||
/**
|
||||
* @param {string} value
|
||||
* @param {!Object} token package-internal implementation detail.
|
||||
*/
|
||||
constructor(value, token) {
|
||||
/**
|
||||
* The contained value of this SafeStyle. The field has a purposely
|
||||
* ugly name to make (non-compiled) code that attempts to directly access
|
||||
* this field stand out.
|
||||
* @private {string}
|
||||
*/
|
||||
this.privateDoNotAccessOrElseSafeStyleWrappedValue_ =
|
||||
(token === CONSTRUCTOR_TOKEN_PRIVATE) ? value : '';
|
||||
|
||||
/**
|
||||
* @override
|
||||
* @const {boolean}
|
||||
*/
|
||||
this.implementsGoogStringTypedString = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a SafeStyle object from a compile-time constant string.
|
||||
*
|
||||
* `style` should be in the format
|
||||
* `name: value; [name: value; ...]` and must not have any < or >
|
||||
* characters in it. This is so that SafeStyle's contract is preserved,
|
||||
* allowing the SafeStyle to correctly be interpreted as a sequence of CSS
|
||||
* declarations and without affecting the syntactic structure of any
|
||||
* surrounding CSS and HTML.
|
||||
*
|
||||
* This method performs basic sanity checks on the format of `style`
|
||||
* but does not constrain the format of `name` and `value`, except
|
||||
* for disallowing tag characters.
|
||||
*
|
||||
* @param {!Const} style A compile-time-constant string from which
|
||||
* to create a SafeStyle.
|
||||
* @return {!SafeStyle} A SafeStyle object initialized to
|
||||
* `style`.
|
||||
*/
|
||||
static fromConstant(style) {
|
||||
'use strict';
|
||||
const styleString = Const.unwrap(style);
|
||||
if (styleString.length === 0) {
|
||||
return SafeStyle.EMPTY;
|
||||
}
|
||||
assert(
|
||||
endsWith(styleString, ';'),
|
||||
`Last character of style string is not ';': ${styleString}`);
|
||||
assert(
|
||||
contains(styleString, ':'),
|
||||
'Style string must contain at least one \':\', to ' +
|
||||
'specify a "name: value" pair: ' + styleString);
|
||||
return SafeStyle.createSafeStyleSecurityPrivateDoNotAccessOrElse(
|
||||
styleString);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns this SafeStyle's value as a string.
|
||||
*
|
||||
* IMPORTANT: In code where it is security relevant that an object's type is
|
||||
* indeed `SafeStyle`, use `SafeStyle.unwrap` instead of
|
||||
* this method. If in doubt, assume that it's security relevant. In
|
||||
* particular, note that goog.html functions which return a goog.html type do
|
||||
* not guarantee the returned instance is of the right type. For example:
|
||||
*
|
||||
* <pre>
|
||||
* var fakeSafeHtml = new String('fake');
|
||||
* fakeSafeHtml.__proto__ = goog.html.SafeHtml.prototype;
|
||||
* var newSafeHtml = goog.html.SafeHtml.htmlEscape(fakeSafeHtml);
|
||||
* // newSafeHtml is just an alias for fakeSafeHtml, it's passed through by
|
||||
* // goog.html.SafeHtml.htmlEscape() as fakeSafeHtml
|
||||
* // instanceof goog.html.SafeHtml.
|
||||
* </pre>
|
||||
*
|
||||
* @return {string}
|
||||
* @see SafeStyle#unwrap
|
||||
* @override
|
||||
*/
|
||||
getTypedStringValue() {
|
||||
'use strict';
|
||||
return this.privateDoNotAccessOrElseSafeStyleWrappedValue_;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a string-representation of this value.
|
||||
*
|
||||
* To obtain the actual string value wrapped in a SafeStyle, use
|
||||
* `SafeStyle.unwrap`.
|
||||
*
|
||||
* @return {string}
|
||||
* @see SafeStyle#unwrap
|
||||
* @override
|
||||
*/
|
||||
toString() {
|
||||
'use strict';
|
||||
return this.privateDoNotAccessOrElseSafeStyleWrappedValue_.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Performs a runtime check that the provided object is indeed a
|
||||
* SafeStyle object, and returns its value.
|
||||
*
|
||||
* @param {!SafeStyle} safeStyle The object to extract from.
|
||||
* @return {string} The safeStyle object's contained string, unless
|
||||
* the run-time type check fails. In that case, `unwrap` returns an
|
||||
* innocuous string, or, if assertions are enabled, throws
|
||||
* `AssertionError`.
|
||||
*/
|
||||
static unwrap(safeStyle) {
|
||||
'use strict';
|
||||
// Perform additional Run-time type-checking to ensure that
|
||||
// safeStyle is indeed an instance of the expected type. This
|
||||
// provides some additional protection against security bugs due to
|
||||
// application code that disables type checks.
|
||||
// Specifically, the following checks are performed:
|
||||
// 1. The object is an instance of the expected type.
|
||||
// 2. The object is not an instance of a subclass.
|
||||
if (safeStyle instanceof SafeStyle && safeStyle.constructor === SafeStyle) {
|
||||
return safeStyle.privateDoNotAccessOrElseSafeStyleWrappedValue_;
|
||||
} else {
|
||||
fail(
|
||||
`expected object of type SafeStyle, got '${safeStyle}` +
|
||||
'\' of type ' + goog.typeOf(safeStyle));
|
||||
return 'type_error:SafeStyle';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Package-internal utility method to create SafeStyle instances.
|
||||
*
|
||||
* @param {string} style The string to initialize the SafeStyle object with.
|
||||
* @return {!SafeStyle} The initialized SafeStyle object.
|
||||
* @package
|
||||
*/
|
||||
static createSafeStyleSecurityPrivateDoNotAccessOrElse(style) {
|
||||
'use strict';
|
||||
return new SafeStyle(style, CONSTRUCTOR_TOKEN_PRIVATE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new SafeStyle object from the properties specified in the map.
|
||||
* @param {!SafeStyle.PropertyMap} map Mapping of property names to
|
||||
* their values, for example {'margin': '1px'}. Names must consist of
|
||||
* [-_a-zA-Z0-9]. Values might be strings consisting of
|
||||
* [-,.'"%_!# a-zA-Z0-9[\]], where ", ', and [] must be properly balanced.
|
||||
* We also allow simple functions like rgb() and url() which sanitizes its
|
||||
* contents. Other values must be wrapped in Const. URLs might
|
||||
* be passed as SafeUrl which will be wrapped into url(""). We
|
||||
* also support array whose elements are joined with ' '. Null value
|
||||
* causes skipping the property.
|
||||
* @return {!SafeStyle}
|
||||
* @throws {!Error} If invalid name is provided.
|
||||
* @throws {!AssertionError} If invalid value is provided. With
|
||||
* disabled assertions, invalid value is replaced by
|
||||
* SafeStyle.INNOCUOUS_STRING.
|
||||
*/
|
||||
static create(map) {
|
||||
'use strict';
|
||||
let style = '';
|
||||
for (let name in map) {
|
||||
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty#Using_hasOwnProperty_as_a_property_name
|
||||
if (Object.prototype.hasOwnProperty.call(map, name)) {
|
||||
if (!/^[-_a-zA-Z0-9]+$/.test(name)) {
|
||||
throw new Error(`Name allows only [-_a-zA-Z0-9], got: ${name}`);
|
||||
}
|
||||
let value = map[name];
|
||||
if (value == null) {
|
||||
continue;
|
||||
}
|
||||
if (Array.isArray(value)) {
|
||||
value = value.map(sanitizePropertyValue).join(' ');
|
||||
} else {
|
||||
value = sanitizePropertyValue(value);
|
||||
}
|
||||
style += `${name}:${value};`;
|
||||
}
|
||||
}
|
||||
if (!style) {
|
||||
return SafeStyle.EMPTY;
|
||||
}
|
||||
return SafeStyle.createSafeStyleSecurityPrivateDoNotAccessOrElse(style);
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a new SafeStyle object by concatenating the values.
|
||||
* @param {...(!SafeStyle|!Array<!SafeStyle>)} var_args
|
||||
* SafeStyles to concatenate.
|
||||
* @return {!SafeStyle}
|
||||
*/
|
||||
static concat(var_args) {
|
||||
'use strict';
|
||||
let style = '';
|
||||
|
||||
/**
|
||||
* @param {!SafeStyle|!Array<!SafeStyle>} argument
|
||||
*/
|
||||
const addArgument = argument => {
|
||||
'use strict';
|
||||
if (Array.isArray(argument)) {
|
||||
argument.forEach(addArgument);
|
||||
} else {
|
||||
style += SafeStyle.unwrap(argument);
|
||||
}
|
||||
};
|
||||
|
||||
Array.prototype.forEach.call(arguments, addArgument);
|
||||
if (!style) {
|
||||
return SafeStyle.EMPTY;
|
||||
}
|
||||
return SafeStyle.createSafeStyleSecurityPrivateDoNotAccessOrElse(style);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* A SafeStyle instance corresponding to the empty string.
|
||||
* @const {!SafeStyle}
|
||||
*/
|
||||
SafeStyle.EMPTY = SafeStyle.createSafeStyleSecurityPrivateDoNotAccessOrElse('');
|
||||
|
||||
|
||||
/**
|
||||
* The innocuous string generated by SafeStyle.create when passed
|
||||
* an unsafe value.
|
||||
* @const {string}
|
||||
*/
|
||||
SafeStyle.INNOCUOUS_STRING = 'zClosurez';
|
||||
|
||||
|
||||
/**
|
||||
* A single property value.
|
||||
* @typedef {string|!Const|!SafeUrl}
|
||||
*/
|
||||
SafeStyle.PropertyValue;
|
||||
|
||||
|
||||
/**
|
||||
* Mapping of property names to their values.
|
||||
* We don't support numbers even though some values might be numbers (e.g.
|
||||
* line-height or 0 for any length). The reason is that most numeric values need
|
||||
* units (e.g. '1px') and allowing numbers could cause users forgetting about
|
||||
* them.
|
||||
* @typedef {!Object<string, ?SafeStyle.PropertyValue|
|
||||
* ?Array<!SafeStyle.PropertyValue>>}
|
||||
*/
|
||||
SafeStyle.PropertyMap;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Checks and converts value to string.
|
||||
* @param {!SafeStyle.PropertyValue} value
|
||||
* @return {string}
|
||||
*/
|
||||
function sanitizePropertyValue(value) {
|
||||
'use strict';
|
||||
if (value instanceof SafeUrl) {
|
||||
const url = SafeUrl.unwrap(value);
|
||||
return 'url("' + url.replace(/</g, '%3c').replace(/[\\"]/g, '\\$&') + '")';
|
||||
}
|
||||
const result = value instanceof Const ?
|
||||
Const.unwrap(value) :
|
||||
sanitizePropertyValueString(String(value));
|
||||
// These characters can be used to change context and we don't want that even
|
||||
// with const values.
|
||||
if (/[{;}]/.test(result)) {
|
||||
throw new AssertionError('Value does not allow [{;}], got: %s.', [result]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks string value.
|
||||
* @param {string} value
|
||||
* @return {string}
|
||||
*/
|
||||
function sanitizePropertyValueString(value) {
|
||||
'use strict';
|
||||
// Some CSS property values permit nested functions. We allow one level of
|
||||
// nesting, and all nested functions must also be in the FUNCTIONS_RE_ list.
|
||||
const valueWithoutFunctions = value.replace(FUNCTIONS_RE, '$1')
|
||||
.replace(FUNCTIONS_RE, '$1')
|
||||
.replace(URL_RE, 'url');
|
||||
if (!VALUE_RE.test(valueWithoutFunctions)) {
|
||||
fail(
|
||||
`String value allows only ${VALUE_ALLOWED_CHARS}` +
|
||||
' and simple functions, got: ' + value);
|
||||
return SafeStyle.INNOCUOUS_STRING;
|
||||
} else if (COMMENT_RE.test(value)) {
|
||||
fail(`String value disallows comments, got: ${value}`);
|
||||
return SafeStyle.INNOCUOUS_STRING;
|
||||
} else if (!hasBalancedQuotes(value)) {
|
||||
fail(`String value requires balanced quotes, got: ${value}`);
|
||||
return SafeStyle.INNOCUOUS_STRING;
|
||||
} else if (!hasBalancedSquareBrackets(value)) {
|
||||
fail(
|
||||
'String value requires balanced square brackets and one' +
|
||||
' identifier per pair of brackets, got: ' + value);
|
||||
return SafeStyle.INNOCUOUS_STRING;
|
||||
}
|
||||
return sanitizeUrl(value);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks that quotes (" and ') are properly balanced inside a string. Assumes
|
||||
* that neither escape (\) nor any other character that could result in
|
||||
* breaking out of a string parsing context are allowed;
|
||||
* see http://www.w3.org/TR/css3-syntax/#string-token-diagram.
|
||||
* @param {string} value Untrusted CSS property value.
|
||||
* @return {boolean} True if property value is safe with respect to quote
|
||||
* balancedness.
|
||||
*/
|
||||
function hasBalancedQuotes(value) {
|
||||
'use strict';
|
||||
let outsideSingle = true;
|
||||
let outsideDouble = true;
|
||||
for (let i = 0; i < value.length; i++) {
|
||||
const c = value.charAt(i);
|
||||
if (c == '\'' && outsideDouble) {
|
||||
outsideSingle = !outsideSingle;
|
||||
} else if (c == '"' && outsideSingle) {
|
||||
outsideDouble = !outsideDouble;
|
||||
}
|
||||
}
|
||||
return outsideSingle && outsideDouble;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks that square brackets ([ and ]) are properly balanced inside a string,
|
||||
* and that the content in the square brackets is one ident-token;
|
||||
* see https://www.w3.org/TR/css-syntax-3/#ident-token-diagram.
|
||||
* For practicality, and in line with other restrictions posed on SafeStyle
|
||||
* strings, we restrict the character set allowable in the ident-token to
|
||||
* [-_a-zA-Z0-9].
|
||||
* @param {string} value Untrusted CSS property value.
|
||||
* @return {boolean} True if property value is safe with respect to square
|
||||
* bracket balancedness.
|
||||
*/
|
||||
function hasBalancedSquareBrackets(value) {
|
||||
'use strict';
|
||||
let outside = true;
|
||||
const tokenRe = /^[-_a-zA-Z0-9]$/;
|
||||
for (let i = 0; i < value.length; i++) {
|
||||
const c = value.charAt(i);
|
||||
if (c == ']') {
|
||||
if (outside) return false; // Unbalanced ].
|
||||
outside = true;
|
||||
} else if (c == '[') {
|
||||
if (!outside) return false; // No nesting.
|
||||
outside = false;
|
||||
} else if (!outside && !tokenRe.test(c)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return outside;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Characters allowed in VALUE_RE.
|
||||
* @type {string}
|
||||
*/
|
||||
const VALUE_ALLOWED_CHARS = '[-,."\'%_!# a-zA-Z0-9\\[\\]]';
|
||||
|
||||
|
||||
/**
|
||||
* Regular expression for safe values.
|
||||
* Quotes (" and ') are allowed, but a check must be done elsewhere to ensure
|
||||
* they're balanced.
|
||||
* Square brackets ([ and ]) are allowed, but a check must be done elsewhere
|
||||
* to ensure they're balanced. The content inside a pair of square brackets must
|
||||
* be one alphanumeric identifier.
|
||||
* ',' allows multiple values to be assigned to the same property
|
||||
* (e.g. background-attachment or font-family) and hence could allow
|
||||
* multiple values to get injected, but that should pose no risk of XSS.
|
||||
* The expression checks only for XSS safety, not for CSS validity.
|
||||
* @const {!RegExp}
|
||||
*/
|
||||
const VALUE_RE = new RegExp(`^${VALUE_ALLOWED_CHARS}+\$`);
|
||||
|
||||
|
||||
/**
|
||||
* Regular expression for url(). We support URLs allowed by
|
||||
* https://www.w3.org/TR/css-syntax-3/#url-token-diagram without using escape
|
||||
* sequences. Use percent-encoding if you need to use special characters like
|
||||
* backslash.
|
||||
* @const {!RegExp}
|
||||
*/
|
||||
const URL_RE = new RegExp(
|
||||
'\\b(url\\([ \t\n]*)(' +
|
||||
'\'[ -&(-\\[\\]-~]*\'' + // Printable characters except ' and \.
|
||||
'|"[ !#-\\[\\]-~]*"' + // Printable characters except " and \.
|
||||
'|[!#-&*-\\[\\]-~]*' + // Printable characters except [ "'()\\].
|
||||
')([ \t\n]*\\))',
|
||||
'g');
|
||||
|
||||
/**
|
||||
* Names of functions allowed in FUNCTIONS_RE.
|
||||
* @const {!Array<string>}
|
||||
*/
|
||||
const ALLOWED_FUNCTIONS = [
|
||||
'calc',
|
||||
'cubic-bezier',
|
||||
'fit-content',
|
||||
'hsl',
|
||||
'hsla',
|
||||
'linear-gradient',
|
||||
'matrix',
|
||||
'minmax',
|
||||
'repeat',
|
||||
'rgb',
|
||||
'rgba',
|
||||
'(rotate|scale|translate)(X|Y|Z|3d)?',
|
||||
'var',
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* Regular expression for simple functions.
|
||||
* @const {!RegExp}
|
||||
*/
|
||||
const FUNCTIONS_RE = new RegExp(
|
||||
'\\b(' + ALLOWED_FUNCTIONS.join('|') + ')' +
|
||||
'\\([-+*/0-9a-z.%#\\[\\], ]+\\)',
|
||||
'g');
|
||||
|
||||
|
||||
/**
|
||||
* Regular expression for comments. These are disallowed in CSS property values.
|
||||
* @const {!RegExp}
|
||||
*/
|
||||
const COMMENT_RE = /\/\*/;
|
||||
|
||||
|
||||
/**
|
||||
* Sanitize URLs inside url().
|
||||
* NOTE: We could also consider using CSS.escape once that's available in the
|
||||
* browsers. However, loosely matching URL e.g. with url\(.*\) and then escaping
|
||||
* the contents would result in a slightly different language than CSS leading
|
||||
* to confusion of users. E.g. url(")") is valid in CSS but it would be invalid
|
||||
* as seen by our parser. On the other hand, url(\) is invalid in CSS but our
|
||||
* parser would be fine with it.
|
||||
* @param {string} value Untrusted CSS property value.
|
||||
* @return {string}
|
||||
*/
|
||||
function sanitizeUrl(value) {
|
||||
'use strict';
|
||||
return value.replace(URL_RE, (match, before, url, after) => {
|
||||
'use strict';
|
||||
let quote = '';
|
||||
url = url.replace(/^(['"])(.*)\1$/, (match, start, inside) => {
|
||||
'use strict';
|
||||
quote = start;
|
||||
return inside;
|
||||
});
|
||||
const sanitized = SafeUrl.sanitize(url).getTypedStringValue();
|
||||
return before + quote + sanitized + quote + after;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
exports = SafeStyle;
|
||||
Executable
+297
@@ -0,0 +1,297 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright The Closure Library Authors.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview The SafeStyleSheet type and its builders.
|
||||
*
|
||||
* TODO(xtof): Link to document stating type contract.
|
||||
*/
|
||||
|
||||
goog.module('goog.html.SafeStyleSheet');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
const Const = goog.require('goog.string.Const');
|
||||
const SafeStyle = goog.require('goog.html.SafeStyle');
|
||||
const TypedString = goog.require('goog.string.TypedString');
|
||||
const googObject = goog.require('goog.object');
|
||||
const {assert, fail} = goog.require('goog.asserts');
|
||||
const {contains} = goog.require('goog.string.internal');
|
||||
|
||||
/**
|
||||
* Token used to ensure that object is created only from this file. No code
|
||||
* outside of this file can access this token.
|
||||
* @const {!Object}
|
||||
*/
|
||||
const CONSTRUCTOR_TOKEN_PRIVATE = {};
|
||||
|
||||
/**
|
||||
* A string-like object which represents a CSS style sheet and that carries the
|
||||
* security type contract that its value, as a string, will not cause untrusted
|
||||
* script execution (XSS) when evaluated as CSS in a browser.
|
||||
*
|
||||
* Instances of this type must be created via the factory method
|
||||
* `SafeStyleSheet.fromConstant` and not by invoking its constructor. The
|
||||
* constructor intentionally takes an extra parameter that cannot be constructed
|
||||
* outside of this file and the type is immutable; hence only a default instance
|
||||
* corresponding to the empty string can be obtained via constructor invocation.
|
||||
*
|
||||
* A SafeStyleSheet's string representation can safely be interpolated as the
|
||||
* content of a style element within HTML. The SafeStyleSheet string should
|
||||
* not be escaped before interpolation.
|
||||
*
|
||||
* Values of this type must be composable, i.e. for any two values
|
||||
* `styleSheet1` and `styleSheet2` of this type,
|
||||
* `SafeStyleSheet.unwrap(styleSheet1) + SafeStyleSheet.unwrap(styleSheet2)`
|
||||
* must itself be a value that satisfies the SafeStyleSheet type constraint.
|
||||
* This requirement implies that for any value `styleSheet` of this type,
|
||||
* `SafeStyleSheet.unwrap(styleSheet1)` must end in
|
||||
* "beginning of rule" context.
|
||||
*
|
||||
* A SafeStyleSheet can be constructed via security-reviewed unchecked
|
||||
* conversions. In this case producers of SafeStyleSheet must ensure themselves
|
||||
* that the SafeStyleSheet does not contain unsafe script. Note in particular
|
||||
* that `<` is dangerous, even when inside CSS strings, and so should
|
||||
* always be forbidden or CSS-escaped in user controlled input. For example, if
|
||||
* `</style><script>evil</script>"` were interpolated
|
||||
* inside a CSS string, it would break out of the context of the original
|
||||
* style element and `evil` would execute. Also note that within an HTML
|
||||
* style (raw text) element, HTML character references, such as
|
||||
* `&lt;`, are not allowed. See
|
||||
* http://www.w3.org/TR/html5/scripting-1.html#restrictions-for-contents-of-script-elements
|
||||
* (similar considerations apply to the style element).
|
||||
*
|
||||
* @see SafeStyleSheet#fromConstant
|
||||
* @final
|
||||
* @implements {TypedString}
|
||||
*/
|
||||
class SafeStyleSheet {
|
||||
/**
|
||||
* @param {string} value
|
||||
* @param {!Object} token package-internal implementation detail.
|
||||
*/
|
||||
constructor(value, token) {
|
||||
/**
|
||||
* The contained value of this SafeStyleSheet. The field has a purposely
|
||||
* ugly name to make (non-compiled) code that attempts to directly access
|
||||
* this field stand out.
|
||||
* @private {string}
|
||||
*/
|
||||
this.privateDoNotAccessOrElseSafeStyleSheetWrappedValue_ =
|
||||
(token === CONSTRUCTOR_TOKEN_PRIVATE) ? value : '';
|
||||
|
||||
/**
|
||||
* @override
|
||||
* @const
|
||||
*/
|
||||
this.implementsGoogStringTypedString = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a style sheet consisting of one selector and one style definition.
|
||||
* Use {@link SafeStyleSheet.concat} to create longer style sheets.
|
||||
* This function doesn't support @import, @media and similar constructs.
|
||||
* @param {string} selector CSS selector, e.g. '#id' or 'tag .class, #id'. We
|
||||
* support CSS3 selectors: https://w3.org/TR/css3-selectors/#selectors.
|
||||
* @param {!SafeStyle.PropertyMap|!SafeStyle} style Style
|
||||
* definition associated with the selector.
|
||||
* @return {!SafeStyleSheet}
|
||||
* @throws {!Error} If invalid selector is provided.
|
||||
*/
|
||||
static createRule(selector, style) {
|
||||
if (contains(selector, '<')) {
|
||||
throw new Error(`Selector does not allow '<', got: ${selector}`);
|
||||
}
|
||||
|
||||
// Remove strings.
|
||||
const selectorToCheck =
|
||||
selector.replace(/('|")((?!\1)[^\r\n\f\\]|\\[\s\S])*\1/g, '');
|
||||
|
||||
// Check characters allowed in CSS3 selectors.
|
||||
if (!/^[-_a-zA-Z0-9#.:* ,>+~[\]()=^$|]+$/.test(selectorToCheck)) {
|
||||
throw new Error(
|
||||
'Selector allows only [-_a-zA-Z0-9#.:* ,>+~[\\]()=^$|] and ' +
|
||||
'strings, got: ' + selector);
|
||||
}
|
||||
|
||||
// Check balanced () and [].
|
||||
if (!SafeStyleSheet.hasBalancedBrackets_(selectorToCheck)) {
|
||||
throw new Error(
|
||||
'() and [] in selector must be balanced, got: ' + selector);
|
||||
}
|
||||
|
||||
if (!(style instanceof SafeStyle)) {
|
||||
style = SafeStyle.create(style);
|
||||
}
|
||||
const styleSheet =
|
||||
`${selector}{` + SafeStyle.unwrap(style).replace(/</g, '\\3C ') + '}';
|
||||
return SafeStyleSheet.createSafeStyleSheetSecurityPrivateDoNotAccessOrElse(
|
||||
styleSheet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a string has balanced () and [] brackets.
|
||||
* @param {string} s String to check.
|
||||
* @return {boolean}
|
||||
* @private
|
||||
*/
|
||||
static hasBalancedBrackets_(s) {
|
||||
const brackets = {'(': ')', '[': ']'};
|
||||
const expectedBrackets = [];
|
||||
for (let i = 0; i < s.length; i++) {
|
||||
const ch = s[i];
|
||||
if (brackets[ch]) {
|
||||
expectedBrackets.push(brackets[ch]);
|
||||
} else if (googObject.contains(brackets, ch)) {
|
||||
if (expectedBrackets.pop() != ch) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return expectedBrackets.length == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new SafeStyleSheet object by concatenating values.
|
||||
* @param {...(!SafeStyleSheet|!Array<!SafeStyleSheet>)}
|
||||
* var_args Values to concatenate.
|
||||
* @return {!SafeStyleSheet}
|
||||
*/
|
||||
static concat(var_args) {
|
||||
let result = '';
|
||||
|
||||
/**
|
||||
* @param {!SafeStyleSheet|!Array<!SafeStyleSheet>}
|
||||
* argument
|
||||
*/
|
||||
const addArgument = argument => {
|
||||
if (Array.isArray(argument)) {
|
||||
argument.forEach(addArgument);
|
||||
} else {
|
||||
result += SafeStyleSheet.unwrap(argument);
|
||||
}
|
||||
};
|
||||
|
||||
Array.prototype.forEach.call(arguments, addArgument);
|
||||
return SafeStyleSheet.createSafeStyleSheetSecurityPrivateDoNotAccessOrElse(
|
||||
result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a SafeStyleSheet object from a compile-time constant string.
|
||||
*
|
||||
* `styleSheet` must not have any < characters in it, so that
|
||||
* the syntactic structure of the surrounding HTML is not affected.
|
||||
*
|
||||
* @param {!Const} styleSheet A compile-time-constant string from
|
||||
* which to create a SafeStyleSheet.
|
||||
* @return {!SafeStyleSheet} A SafeStyleSheet object initialized to
|
||||
* `styleSheet`.
|
||||
*/
|
||||
static fromConstant(styleSheet) {
|
||||
const styleSheetString = Const.unwrap(styleSheet);
|
||||
if (styleSheetString.length === 0) {
|
||||
return SafeStyleSheet.EMPTY;
|
||||
}
|
||||
// > is a valid character in CSS selectors and there's no strict need to
|
||||
// block it if we already block <.
|
||||
assert(
|
||||
!contains(styleSheetString, '<'),
|
||||
`Forbidden '<' character in style sheet string: ${styleSheetString}`);
|
||||
return SafeStyleSheet.createSafeStyleSheetSecurityPrivateDoNotAccessOrElse(
|
||||
styleSheetString);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns this SafeStyleSheet's value as a string.
|
||||
*
|
||||
* IMPORTANT: In code where it is security relevant that an object's type is
|
||||
* indeed `SafeStyleSheet`, use `SafeStyleSheet.unwrap`
|
||||
* instead of this method. If in doubt, assume that it's security relevant. In
|
||||
* particular, note that goog.html functions which return a goog.html type do
|
||||
* not guarantee the returned instance is of the right type. For example:
|
||||
*
|
||||
* <pre>
|
||||
* var fakeSafeHtml = new String('fake');
|
||||
* fakeSafeHtml.__proto__ = goog.html.SafeHtml.prototype;
|
||||
* var newSafeHtml = goog.html.SafeHtml.htmlEscape(fakeSafeHtml);
|
||||
* // newSafeHtml is just an alias for fakeSafeHtml, it's passed through by
|
||||
* // goog.html.SafeHtml.htmlEscape() as fakeSafeHtml
|
||||
* // instanceof goog.html.SafeHtml.
|
||||
* </pre>
|
||||
*
|
||||
* @see SafeStyleSheet#unwrap
|
||||
* @override
|
||||
*/
|
||||
getTypedStringValue() {
|
||||
return this.privateDoNotAccessOrElseSafeStyleSheetWrappedValue_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a runtime check that the provided object is indeed a
|
||||
* SafeStyleSheet object, and returns its value.
|
||||
*
|
||||
* @param {!SafeStyleSheet} safeStyleSheet The object to extract from.
|
||||
* @return {string} The safeStyleSheet object's contained string, unless
|
||||
* the run-time type check fails. In that case, `unwrap` returns an
|
||||
* innocuous string, or, if assertions are enabled, throws
|
||||
* `asserts.AssertionError`.
|
||||
*/
|
||||
static unwrap(safeStyleSheet) {
|
||||
// Perform additional Run-time type-checking to ensure that
|
||||
// safeStyleSheet is indeed an instance of the expected type. This
|
||||
// provides some additional protection against security bugs due to
|
||||
// application code that disables type checks.
|
||||
// Specifically, the following checks are performed:
|
||||
// 1. The object is an instance of the expected type.
|
||||
// 2. The object is not an instance of a subclass.
|
||||
if (safeStyleSheet instanceof SafeStyleSheet &&
|
||||
safeStyleSheet.constructor === SafeStyleSheet) {
|
||||
return safeStyleSheet.privateDoNotAccessOrElseSafeStyleSheetWrappedValue_;
|
||||
} else {
|
||||
fail(
|
||||
'expected object of type SafeStyleSheet, got \'' + safeStyleSheet +
|
||||
'\' of type ' + goog.typeOf(safeStyleSheet));
|
||||
return 'type_error:SafeStyleSheet';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Package-internal utility method to create SafeStyleSheet instances.
|
||||
*
|
||||
* @param {string} styleSheet The string to initialize the SafeStyleSheet
|
||||
* object with.
|
||||
* @return {!SafeStyleSheet} The initialized SafeStyleSheet object.
|
||||
* @package
|
||||
*/
|
||||
static createSafeStyleSheetSecurityPrivateDoNotAccessOrElse(styleSheet) {
|
||||
return new SafeStyleSheet(styleSheet, CONSTRUCTOR_TOKEN_PRIVATE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string-representation of this value.
|
||||
*
|
||||
* To obtain the actual string value wrapped in a SafeStyleSheet, use
|
||||
* `SafeStyleSheet.unwrap`.
|
||||
*
|
||||
* @return {string}
|
||||
* @see SafeStyleSheet#unwrap
|
||||
* @override
|
||||
*/
|
||||
SafeStyleSheet.prototype.toString = function() {
|
||||
return this.privateDoNotAccessOrElseSafeStyleSheetWrappedValue_.toString();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A SafeStyleSheet instance corresponding to the empty string.
|
||||
* @const {!SafeStyleSheet}
|
||||
*/
|
||||
SafeStyleSheet.EMPTY =
|
||||
SafeStyleSheet.createSafeStyleSheetSecurityPrivateDoNotAccessOrElse('');
|
||||
|
||||
|
||||
exports = SafeStyleSheet;
|
||||
Executable
+807
@@ -0,0 +1,807 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright The Closure Library Authors.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview The SafeUrl type and its builders.
|
||||
*
|
||||
* TODO(xtof): Link to document stating type contract.
|
||||
*/
|
||||
|
||||
goog.provide('goog.html.SafeUrl');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.fs.url');
|
||||
goog.require('goog.html.TrustedResourceUrl');
|
||||
goog.require('goog.i18n.bidi.Dir');
|
||||
goog.require('goog.i18n.bidi.DirectionalString');
|
||||
goog.require('goog.string.Const');
|
||||
goog.require('goog.string.TypedString');
|
||||
goog.require('goog.string.internal');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A string that is safe to use in URL context in DOM APIs and HTML documents.
|
||||
*
|
||||
* A SafeUrl is a string-like object that carries the security type contract
|
||||
* that its value as a string will not cause untrusted script execution
|
||||
* when evaluated as a hyperlink URL in a browser.
|
||||
*
|
||||
* Values of this type are guaranteed to be safe to use in URL/hyperlink
|
||||
* contexts, such as assignment to URL-valued DOM properties, in the sense that
|
||||
* the use will not result in a Cross-Site-Scripting vulnerability. Similarly,
|
||||
* SafeUrls can be interpolated into the URL context of an HTML template (e.g.,
|
||||
* inside a href attribute). However, appropriate HTML-escaping must still be
|
||||
* applied.
|
||||
*
|
||||
* Note that, as documented in `goog.html.SafeUrl.unwrap`, this type's
|
||||
* contract does not guarantee that instances are safe to interpolate into HTML
|
||||
* without appropriate escaping.
|
||||
*
|
||||
* Note also that this type's contract does not imply any guarantees regarding
|
||||
* the resource the URL refers to. In particular, SafeUrls are <b>not</b>
|
||||
* safe to use in a context where the referred-to resource is interpreted as
|
||||
* trusted code, e.g., as the src of a script tag.
|
||||
*
|
||||
* Instances of this type must be created via the factory methods
|
||||
* (`goog.html.SafeUrl.fromConstant`, `goog.html.SafeUrl.sanitize`),
|
||||
* etc and not by invoking its constructor. The constructor intentionally takes
|
||||
* an extra parameter that cannot be constructed outside of this file and the
|
||||
* type is immutable; hence only a default instance corresponding to the empty
|
||||
* string can be obtained via constructor invocation.
|
||||
*
|
||||
* @see goog.html.SafeUrl#fromConstant
|
||||
* @see goog.html.SafeUrl#from
|
||||
* @see goog.html.SafeUrl#sanitize
|
||||
* @final
|
||||
* @struct
|
||||
* @implements {goog.i18n.bidi.DirectionalString}
|
||||
* @implements {goog.string.TypedString}
|
||||
*/
|
||||
goog.html.SafeUrl = class {
|
||||
/**
|
||||
* @param {string} value
|
||||
* @param {!Object} token package-internal implementation detail.
|
||||
*/
|
||||
constructor(value, token) {
|
||||
/**
|
||||
* The contained value of this SafeUrl. The field has a purposely ugly
|
||||
* name to make (non-compiled) code that attempts to directly access this
|
||||
* field stand out.
|
||||
* @private {string}
|
||||
*/
|
||||
this.privateDoNotAccessOrElseSafeUrlWrappedValue_ =
|
||||
(token === goog.html.SafeUrl.CONSTRUCTOR_TOKEN_PRIVATE_) ? value : '';
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The innocuous string generated by goog.html.SafeUrl.sanitize when passed
|
||||
* an unsafe URL.
|
||||
*
|
||||
* about:invalid is registered in
|
||||
* http://www.w3.org/TR/css3-values/#about-invalid.
|
||||
* http://tools.ietf.org/html/rfc6694#section-2.2.1 permits about URLs to
|
||||
* contain a fragment, which is not to be considered when determining if an
|
||||
* about URL is well-known.
|
||||
*
|
||||
* Using about:invalid seems preferable to using a fixed data URL, since
|
||||
* browsers might choose to not report CSP violations on it, as legitimate
|
||||
* CSS function calls to attr() can result in this URL being produced. It is
|
||||
* also a standard URL which matches exactly the semantics we need:
|
||||
* "The about:invalid URI references a non-existent document with a generic
|
||||
* error condition. It can be used when a URI is necessary, but the default
|
||||
* value shouldn't be resolveable as any type of document".
|
||||
*
|
||||
* @const {string}
|
||||
*/
|
||||
goog.html.SafeUrl.INNOCUOUS_STRING = 'about:invalid#zClosurez';
|
||||
|
||||
|
||||
/**
|
||||
* @override
|
||||
* @const
|
||||
*/
|
||||
goog.html.SafeUrl.prototype.implementsGoogStringTypedString = true;
|
||||
|
||||
|
||||
/**
|
||||
* Returns this SafeUrl's value as a string.
|
||||
*
|
||||
* IMPORTANT: In code where it is security relevant that an object's type is
|
||||
* indeed `SafeUrl`, use `goog.html.SafeUrl.unwrap` instead of this
|
||||
* method. If in doubt, assume that it's security relevant. In particular, note
|
||||
* that goog.html functions which return a goog.html type do not guarantee that
|
||||
* the returned instance is of the right type.
|
||||
*
|
||||
* IMPORTANT: The guarantees of the SafeUrl type contract only extend to the
|
||||
* behavior of browsers when interpreting URLs. Values of SafeUrl objects MUST
|
||||
* be appropriately escaped before embedding in a HTML document. Note that the
|
||||
* required escaping is context-sensitive (e.g. a different escaping is
|
||||
* required for embedding a URL in a style property within a style
|
||||
* attribute, as opposed to embedding in a href attribute).
|
||||
*
|
||||
* @see goog.html.SafeUrl#unwrap
|
||||
* @override
|
||||
*/
|
||||
goog.html.SafeUrl.prototype.getTypedStringValue = function() {
|
||||
'use strict';
|
||||
return this.privateDoNotAccessOrElseSafeUrlWrappedValue_.toString();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @override
|
||||
* @const {boolean}
|
||||
*/
|
||||
goog.html.SafeUrl.prototype.implementsGoogI18nBidiDirectionalString = true;
|
||||
|
||||
|
||||
/**
|
||||
* Returns this URLs directionality, which is always `LTR`.
|
||||
* @override
|
||||
* @return {!goog.i18n.bidi.Dir}
|
||||
*/
|
||||
goog.html.SafeUrl.prototype.getDirection = function() {
|
||||
'use strict';
|
||||
return goog.i18n.bidi.Dir.LTR;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns a string-representation of this value.
|
||||
*
|
||||
* To obtain the actual string value wrapped in a SafeUrl, use
|
||||
* `goog.html.SafeUrl.unwrap`.
|
||||
*
|
||||
* @return {string}
|
||||
* @see goog.html.SafeUrl#unwrap
|
||||
* @override
|
||||
*/
|
||||
goog.html.SafeUrl.prototype.toString = function() {
|
||||
'use strict';
|
||||
return this.privateDoNotAccessOrElseSafeUrlWrappedValue_.toString();
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Performs a runtime check that the provided object is indeed a SafeUrl
|
||||
* object, and returns its value.
|
||||
*
|
||||
* IMPORTANT: The guarantees of the SafeUrl type contract only extend to the
|
||||
* behavior of browsers when interpreting URLs. Values of SafeUrl objects MUST
|
||||
* be appropriately escaped before embedding in a HTML document. Note that the
|
||||
* required escaping is context-sensitive (e.g. a different escaping is
|
||||
* required for embedding a URL in a style property within a style
|
||||
* attribute, as opposed to embedding in a href attribute).
|
||||
*
|
||||
* @param {!goog.html.SafeUrl} safeUrl The object to extract from.
|
||||
* @return {string} The SafeUrl object's contained string, unless the run-time
|
||||
* type check fails. In that case, `unwrap` returns an innocuous
|
||||
* string, or, if assertions are enabled, throws
|
||||
* `goog.asserts.AssertionError`.
|
||||
*/
|
||||
goog.html.SafeUrl.unwrap = function(safeUrl) {
|
||||
'use strict';
|
||||
// Perform additional Run-time type-checking to ensure that safeUrl is indeed
|
||||
// an instance of the expected type. This provides some additional protection
|
||||
// against security bugs due to application code that disables type checks.
|
||||
// Specifically, the following checks are performed:
|
||||
// 1. The object is an instance of the expected type.
|
||||
// 2. The object is not an instance of a subclass.
|
||||
if (safeUrl instanceof goog.html.SafeUrl &&
|
||||
safeUrl.constructor === goog.html.SafeUrl) {
|
||||
return safeUrl.privateDoNotAccessOrElseSafeUrlWrappedValue_;
|
||||
} else {
|
||||
goog.asserts.fail('expected object of type SafeUrl, got \'' +
|
||||
safeUrl + '\' of type ' + goog.typeOf(safeUrl));
|
||||
return 'type_error:SafeUrl';
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a SafeUrl object from a compile-time constant string.
|
||||
*
|
||||
* Compile-time constant strings are inherently program-controlled and hence
|
||||
* trusted.
|
||||
*
|
||||
* @param {!goog.string.Const} url A compile-time-constant string from which to
|
||||
* create a SafeUrl.
|
||||
* @return {!goog.html.SafeUrl} A SafeUrl object initialized to `url`.
|
||||
*/
|
||||
goog.html.SafeUrl.fromConstant = function(url) {
|
||||
'use strict';
|
||||
return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(
|
||||
goog.string.Const.unwrap(url));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A pattern that matches Blob or data types that can have SafeUrls created
|
||||
* from URL.createObjectURL(blob) or via a data: URI.
|
||||
*
|
||||
* This has some parameter support (most notably, we haven't implemented the
|
||||
* more complex parts like %-encoded characters or non-alphanumerical ones for
|
||||
* simplicity's sake). The specs are fairly complex, and they don't
|
||||
* always match Chrome's behavior: we settled on a subset where we're confident
|
||||
* all parties involved agree.
|
||||
*
|
||||
* The spec is available at https://mimesniff.spec.whatwg.org/ (and see
|
||||
* https://tools.ietf.org/html/rfc2397 for data: urls, which override some of
|
||||
* it).
|
||||
* @const
|
||||
* @private
|
||||
*/
|
||||
goog.html.SAFE_MIME_TYPE_PATTERN_ = new RegExp(
|
||||
// Note: Due to content-sniffing concerns, only add MIME types for
|
||||
// media formats.
|
||||
'^(?:audio/(?:3gpp2|3gpp|aac|L16|midi|mp3|mp4|mpeg|oga|ogg|opus|x-m4a|x-matroska|x-wav|wav|webm)|' +
|
||||
'font/\\w+|' +
|
||||
'image/(?:bmp|gif|jpeg|jpg|png|tiff|webp|x-icon)|' +
|
||||
'video/(?:mpeg|mp4|ogg|webm|quicktime|x-matroska))' +
|
||||
'(?:;\\w+=(?:\\w+|"[\\w;,= ]+"))*$', // MIME type parameters
|
||||
'i');
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} mimeType The MIME type to check if safe.
|
||||
* @return {boolean} True if the MIME type is safe and creating a Blob via
|
||||
* `SafeUrl.fromBlob()` with that type will not fail due to the type. False
|
||||
* otherwise.
|
||||
*/
|
||||
goog.html.SafeUrl.isSafeMimeType = function(mimeType) {
|
||||
'use strict';
|
||||
return goog.html.SAFE_MIME_TYPE_PATTERN_.test(mimeType);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a SafeUrl wrapping a blob URL for the given `blob`.
|
||||
*
|
||||
* The blob URL is created with `URL.createObjectURL`. If the MIME type
|
||||
* for `blob` is not of a known safe audio, image or video MIME type,
|
||||
* then the SafeUrl will wrap {@link #INNOCUOUS_STRING}.
|
||||
*
|
||||
* Note: Call {@link revokeObjectUrl} on the URL after it's used
|
||||
* to prevent memory leaks.
|
||||
*
|
||||
* @see http://www.w3.org/TR/FileAPI/#url
|
||||
* @param {!Blob} blob
|
||||
* @return {!goog.html.SafeUrl} The blob URL, or an innocuous string wrapped
|
||||
* as a SafeUrl.
|
||||
*/
|
||||
goog.html.SafeUrl.fromBlob = function(blob) {
|
||||
'use strict';
|
||||
var url = goog.html.SafeUrl.isSafeMimeType(blob.type) ?
|
||||
goog.fs.url.createObjectUrl(blob) :
|
||||
goog.html.SafeUrl.INNOCUOUS_STRING;
|
||||
return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(url);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Revokes an object URL created for a safe URL created {@link fromBlob()}.
|
||||
* @param {!goog.html.SafeUrl} safeUrl SafeUrl wrapping a blob object.
|
||||
* @return {void}
|
||||
*/
|
||||
goog.html.SafeUrl.revokeObjectUrl = function(safeUrl) {
|
||||
'use strict';
|
||||
var url = safeUrl.getTypedStringValue();
|
||||
if (url !== goog.html.SafeUrl.INNOCUOUS_STRING) {
|
||||
goog.fs.url.revokeObjectUrl(url);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a SafeUrl wrapping a blob URL created for a MediaSource.
|
||||
* @param {!MediaSource} mediaSource
|
||||
* @return {!goog.html.SafeUrl} The blob URL.
|
||||
*/
|
||||
goog.html.SafeUrl.fromMediaSource = function(mediaSource) {
|
||||
'use strict';
|
||||
goog.asserts.assert(
|
||||
'MediaSource' in goog.global, 'No support for MediaSource');
|
||||
const url = mediaSource instanceof MediaSource ?
|
||||
goog.fs.url.createObjectUrl(mediaSource) :
|
||||
goog.html.SafeUrl.INNOCUOUS_STRING;
|
||||
return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(url);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Matches a base-64 data URL, with the first match group being the MIME type.
|
||||
* @const
|
||||
* @private
|
||||
*/
|
||||
goog.html.DATA_URL_PATTERN_ = /^data:(.*);base64,[a-z0-9+\/]+=*$/i;
|
||||
|
||||
|
||||
/**
|
||||
* Attempts to create a SafeUrl wrapping a `data:` URL, after validating it
|
||||
* matches a known-safe media MIME type. If it doesn't match, return `null`.
|
||||
*
|
||||
* @param {string} dataUrl A valid base64 data URL with one of the whitelisted
|
||||
* media MIME types.
|
||||
* @return {?goog.html.SafeUrl} A matching safe URL, or `null` if it does not
|
||||
* pass.
|
||||
*/
|
||||
goog.html.SafeUrl.tryFromDataUrl = function(dataUrl) {
|
||||
'use strict';
|
||||
// For defensive purposes, in case users cast around the parameter type.
|
||||
dataUrl = String(dataUrl);
|
||||
// RFC4648 suggest to ignore CRLF in base64 encoding.
|
||||
// See https://tools.ietf.org/html/rfc4648.
|
||||
// Remove the CR (%0D) and LF (%0A) from the dataUrl.
|
||||
var filteredDataUrl = dataUrl.replace(/(%0A|%0D)/g, '');
|
||||
var match = filteredDataUrl.match(goog.html.DATA_URL_PATTERN_);
|
||||
// Note: The only risk of XSS here is if the `data:` URL results in a
|
||||
// same-origin document. In which case content-sniffing might cause the
|
||||
// browser to interpret the contents as html.
|
||||
// All modern browsers consider `data:` URL documents to have unique empty
|
||||
// origins. Only Firefox for versions prior to v57 behaves differently:
|
||||
// https://blog.mozilla.org/security/2017/10/04/treating-data-urls-unique-origins-firefox-57/
|
||||
// Older versions of IE don't understand `data:` urls, so it is not an issue.
|
||||
var valid = match && goog.html.SafeUrl.isSafeMimeType(match[1]);
|
||||
if (valid) {
|
||||
return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(
|
||||
filteredDataUrl);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a SafeUrl wrapping a `data:` URL, after validating it matches a
|
||||
* known-safe media MIME type. If it doesn't match, return
|
||||
* `goog.html.SafeUrl.INNOCUOUS_URL`.
|
||||
*
|
||||
* @param {string} dataUrl A valid base64 data URL with one of the whitelisted
|
||||
* media MIME types.
|
||||
* @return {!goog.html.SafeUrl} A matching safe URL, or
|
||||
* `goog.html.SafeUrl.INNOCUOUS_URL` if it does not pass.
|
||||
*/
|
||||
goog.html.SafeUrl.fromDataUrl = function(dataUrl) {
|
||||
'use strict';
|
||||
return goog.html.SafeUrl.tryFromDataUrl(dataUrl) ||
|
||||
goog.html.SafeUrl.INNOCUOUS_URL;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a SafeUrl wrapping a tel: URL.
|
||||
*
|
||||
* @param {string} telUrl A tel URL.
|
||||
* @return {!goog.html.SafeUrl} A matching safe URL, or {@link INNOCUOUS_STRING}
|
||||
* wrapped as a SafeUrl if it does not pass.
|
||||
*/
|
||||
goog.html.SafeUrl.fromTelUrl = function(telUrl) {
|
||||
'use strict';
|
||||
// There's a risk that a tel: URL could immediately place a call once
|
||||
// clicked, without requiring user confirmation. For that reason it is
|
||||
// handled in this separate function.
|
||||
if (!goog.string.internal.caseInsensitiveStartsWith(telUrl, 'tel:')) {
|
||||
telUrl = goog.html.SafeUrl.INNOCUOUS_STRING;
|
||||
}
|
||||
return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(
|
||||
telUrl);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Matches a sip/sips URL. We only allow urls that consist of an email address.
|
||||
* The characters '?' and '#' are not allowed in the local part of the email
|
||||
* address.
|
||||
* @const
|
||||
* @private
|
||||
*/
|
||||
goog.html.SIP_URL_PATTERN_ = new RegExp(
|
||||
'^sip[s]?:[+a-z0-9_.!$%&\'*\\/=^`{|}~-]+@([a-z0-9-]+\\.)+[a-z0-9]{2,63}$',
|
||||
'i');
|
||||
|
||||
|
||||
/**
|
||||
* Creates a SafeUrl wrapping a sip: URL. We only allow urls that consist of an
|
||||
* email address. The characters '?' and '#' are not allowed in the local part
|
||||
* of the email address.
|
||||
*
|
||||
* @param {string} sipUrl A sip URL.
|
||||
* @return {!goog.html.SafeUrl} A matching safe URL, or {@link INNOCUOUS_STRING}
|
||||
* wrapped as a SafeUrl if it does not pass.
|
||||
*/
|
||||
goog.html.SafeUrl.fromSipUrl = function(sipUrl) {
|
||||
'use strict';
|
||||
if (!goog.html.SIP_URL_PATTERN_.test(decodeURIComponent(sipUrl))) {
|
||||
sipUrl = goog.html.SafeUrl.INNOCUOUS_STRING;
|
||||
}
|
||||
return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(
|
||||
sipUrl);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a SafeUrl wrapping a fb-messenger://share URL.
|
||||
*
|
||||
* @param {string} facebookMessengerUrl A facebook messenger URL.
|
||||
* @return {!goog.html.SafeUrl} A matching safe URL, or {@link INNOCUOUS_STRING}
|
||||
* wrapped as a SafeUrl if it does not pass.
|
||||
*/
|
||||
goog.html.SafeUrl.fromFacebookMessengerUrl = function(facebookMessengerUrl) {
|
||||
'use strict';
|
||||
if (!goog.string.internal.caseInsensitiveStartsWith(
|
||||
facebookMessengerUrl, 'fb-messenger://share')) {
|
||||
facebookMessengerUrl = goog.html.SafeUrl.INNOCUOUS_STRING;
|
||||
}
|
||||
return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(
|
||||
facebookMessengerUrl);
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a SafeUrl wrapping a whatsapp://send URL.
|
||||
*
|
||||
* @param {string} whatsAppUrl A WhatsApp URL.
|
||||
* @return {!goog.html.SafeUrl} A matching safe URL, or {@link INNOCUOUS_STRING}
|
||||
* wrapped as a SafeUrl if it does not pass.
|
||||
*/
|
||||
goog.html.SafeUrl.fromWhatsAppUrl = function(whatsAppUrl) {
|
||||
'use strict';
|
||||
if (!goog.string.internal.caseInsensitiveStartsWith(
|
||||
whatsAppUrl, 'whatsapp://send')) {
|
||||
whatsAppUrl = goog.html.SafeUrl.INNOCUOUS_STRING;
|
||||
}
|
||||
return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(
|
||||
whatsAppUrl);
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a SafeUrl wrapping a sms: URL.
|
||||
*
|
||||
* @param {string} smsUrl A sms URL.
|
||||
* @return {!goog.html.SafeUrl} A matching safe URL, or {@link INNOCUOUS_STRING}
|
||||
* wrapped as a SafeUrl if it does not pass.
|
||||
*/
|
||||
goog.html.SafeUrl.fromSmsUrl = function(smsUrl) {
|
||||
'use strict';
|
||||
if (!goog.string.internal.caseInsensitiveStartsWith(smsUrl, 'sms:') ||
|
||||
!goog.html.SafeUrl.isSmsUrlBodyValid_(smsUrl)) {
|
||||
smsUrl = goog.html.SafeUrl.INNOCUOUS_STRING;
|
||||
}
|
||||
return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(
|
||||
smsUrl);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Validates SMS URL `body` parameter, which is optional and should appear at
|
||||
* most once and should be percent-encoded if present. Rejects many malformed
|
||||
* bodies, but may spuriously reject some URLs and does not reject all malformed
|
||||
* sms: URLs.
|
||||
*
|
||||
* @param {string} smsUrl A sms URL.
|
||||
* @return {boolean} Whether SMS URL has a valid `body` parameter if it exists.
|
||||
* @private
|
||||
*/
|
||||
goog.html.SafeUrl.isSmsUrlBodyValid_ = function(smsUrl) {
|
||||
'use strict';
|
||||
var hash = smsUrl.indexOf('#');
|
||||
if (hash > 0) {
|
||||
smsUrl = smsUrl.substring(0, hash);
|
||||
}
|
||||
var bodyParams = smsUrl.match(/[?&]body=/gi);
|
||||
// "body" param is optional
|
||||
if (!bodyParams) {
|
||||
return true;
|
||||
}
|
||||
// "body" MUST only appear once
|
||||
if (bodyParams.length > 1) {
|
||||
return false;
|
||||
}
|
||||
// Get the encoded `body` parameter value.
|
||||
var bodyValue = smsUrl.match(/[?&]body=([^&]*)/)[1];
|
||||
if (!bodyValue) {
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
decodeURIComponent(bodyValue);
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
return /^(?:[a-z0-9\-_.~]|%[0-9a-f]{2})+$/i.test(bodyValue);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a SafeUrl wrapping a ssh: URL.
|
||||
*
|
||||
* @param {string} sshUrl A ssh URL.
|
||||
* @return {!goog.html.SafeUrl} A matching safe URL, or {@link INNOCUOUS_STRING}
|
||||
* wrapped as a SafeUrl if it does not pass.
|
||||
*/
|
||||
goog.html.SafeUrl.fromSshUrl = function(sshUrl) {
|
||||
'use strict';
|
||||
if (!goog.string.internal.caseInsensitiveStartsWith(sshUrl, 'ssh://')) {
|
||||
sshUrl = goog.html.SafeUrl.INNOCUOUS_STRING;
|
||||
}
|
||||
return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(
|
||||
sshUrl);
|
||||
};
|
||||
|
||||
/**
|
||||
* Sanitizes a Chrome extension URL to SafeUrl, given a compile-time-constant
|
||||
* extension identifier. Can also be restricted to chrome extensions.
|
||||
*
|
||||
* @param {string} url The url to sanitize. Should start with the extension
|
||||
* scheme and the extension identifier.
|
||||
* @param {!goog.string.Const|!Array<!goog.string.Const>} extensionId The
|
||||
* extension id to accept, as a compile-time constant or an array of those.
|
||||
*
|
||||
* @return {!goog.html.SafeUrl} Either `url` if it's deemed safe, or
|
||||
* `INNOCUOUS_STRING` if it's not.
|
||||
*/
|
||||
goog.html.SafeUrl.sanitizeChromeExtensionUrl = function(url, extensionId) {
|
||||
'use strict';
|
||||
return goog.html.SafeUrl.sanitizeExtensionUrl_(
|
||||
/^chrome-extension:\/\/([^\/]+)\//, url, extensionId);
|
||||
};
|
||||
|
||||
/**
|
||||
* Sanitizes a Firefox extension URL to SafeUrl, given a compile-time-constant
|
||||
* extension identifier. Can also be restricted to chrome extensions.
|
||||
*
|
||||
* @param {string} url The url to sanitize. Should start with the extension
|
||||
* scheme and the extension identifier.
|
||||
* @param {!goog.string.Const|!Array<!goog.string.Const>} extensionId The
|
||||
* extension id to accept, as a compile-time constant or an array of those.
|
||||
*
|
||||
* @return {!goog.html.SafeUrl} Either `url` if it's deemed safe, or
|
||||
* `INNOCUOUS_STRING` if it's not.
|
||||
*/
|
||||
goog.html.SafeUrl.sanitizeFirefoxExtensionUrl = function(url, extensionId) {
|
||||
'use strict';
|
||||
return goog.html.SafeUrl.sanitizeExtensionUrl_(
|
||||
/^moz-extension:\/\/([^\/]+)\//, url, extensionId);
|
||||
};
|
||||
|
||||
/**
|
||||
* Sanitizes a Edge extension URL to SafeUrl, given a compile-time-constant
|
||||
* extension identifier. Can also be restricted to chrome extensions.
|
||||
*
|
||||
* @param {string} url The url to sanitize. Should start with the extension
|
||||
* scheme and the extension identifier.
|
||||
* @param {!goog.string.Const|!Array<!goog.string.Const>} extensionId The
|
||||
* extension id to accept, as a compile-time constant or an array of those.
|
||||
*
|
||||
* @return {!goog.html.SafeUrl} Either `url` if it's deemed safe, or
|
||||
* `INNOCUOUS_STRING` if it's not.
|
||||
*/
|
||||
goog.html.SafeUrl.sanitizeEdgeExtensionUrl = function(url, extensionId) {
|
||||
'use strict';
|
||||
return goog.html.SafeUrl.sanitizeExtensionUrl_(
|
||||
/^ms-browser-extension:\/\/([^\/]+)\//, url, extensionId);
|
||||
};
|
||||
|
||||
/**
|
||||
* Private helper for converting extension URLs to SafeUrl, given the scheme for
|
||||
* that particular extension type. Use the sanitizeFirefoxExtensionUrl,
|
||||
* sanitizeChromeExtensionUrl or sanitizeEdgeExtensionUrl unless you're building
|
||||
* new helpers.
|
||||
*
|
||||
* @private
|
||||
* @param {!RegExp} scheme The scheme to accept as a RegExp extracting the
|
||||
* extension identifier.
|
||||
* @param {string} url The url to sanitize. Should start with the extension
|
||||
* scheme and the extension identifier.
|
||||
* @param {!goog.string.Const|!Array<!goog.string.Const>} extensionId The
|
||||
* extension id to accept, as a compile-time constant or an array of those.
|
||||
*
|
||||
* @return {!goog.html.SafeUrl} Either `url` if it's deemed safe, or
|
||||
* `INNOCUOUS_STRING` if it's not.
|
||||
*/
|
||||
goog.html.SafeUrl.sanitizeExtensionUrl_ = function(scheme, url, extensionId) {
|
||||
'use strict';
|
||||
var matches = scheme.exec(url);
|
||||
if (!matches) {
|
||||
url = goog.html.SafeUrl.INNOCUOUS_STRING;
|
||||
} else {
|
||||
var extractedExtensionId = matches[1];
|
||||
var acceptedExtensionIds;
|
||||
if (extensionId instanceof goog.string.Const) {
|
||||
acceptedExtensionIds = [goog.string.Const.unwrap(extensionId)];
|
||||
} else {
|
||||
acceptedExtensionIds = extensionId.map(function unwrap(x) {
|
||||
'use strict';
|
||||
return goog.string.Const.unwrap(x);
|
||||
});
|
||||
}
|
||||
if (acceptedExtensionIds.indexOf(extractedExtensionId) == -1) {
|
||||
url = goog.html.SafeUrl.INNOCUOUS_STRING;
|
||||
}
|
||||
}
|
||||
return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(url);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a SafeUrl from TrustedResourceUrl. This is safe because
|
||||
* TrustedResourceUrl is more tightly restricted than SafeUrl.
|
||||
*
|
||||
* @param {!goog.html.TrustedResourceUrl} trustedResourceUrl
|
||||
* @return {!goog.html.SafeUrl}
|
||||
*/
|
||||
goog.html.SafeUrl.fromTrustedResourceUrl = function(trustedResourceUrl) {
|
||||
'use strict';
|
||||
return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(
|
||||
goog.html.TrustedResourceUrl.unwrap(trustedResourceUrl));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A pattern that recognizes a commonly useful subset of URLs that satisfy
|
||||
* the SafeUrl contract.
|
||||
*
|
||||
* This regular expression matches a subset of URLs that will not cause script
|
||||
* execution if used in URL context within a HTML document. Specifically, this
|
||||
* regular expression matches if (comment from here on and regex copied from
|
||||
* Soy's EscapingConventions):
|
||||
* (1) Either a protocol in a whitelist (http, https, mailto or ftp).
|
||||
* (2) or no protocol. A protocol must be followed by a colon. The below
|
||||
* allows that by allowing colons only after one of the characters [/?#].
|
||||
* A colon after a hash (#) must be in the fragment.
|
||||
* Otherwise, a colon after a (?) must be in a query.
|
||||
* Otherwise, a colon after a single solidus (/) must be in a path.
|
||||
* Otherwise, a colon after a double solidus (//) must be in the authority
|
||||
* (before port).
|
||||
*
|
||||
* @private
|
||||
* @const {!RegExp}
|
||||
*/
|
||||
goog.html.SAFE_URL_PATTERN_ =
|
||||
/^(?:(?:https?|mailto|ftp):|[^:/?#]*(?:[/?#]|$))/i;
|
||||
|
||||
/**
|
||||
* Public version of goog.html.SAFE_URL_PATTERN_. Updating
|
||||
* goog.html.SAFE_URL_PATTERN_ doesn't seem to be backward compatible.
|
||||
* Namespace is also changed to goog.html.SafeUrl so it can be imported using
|
||||
* goog.require('goog.dom.SafeUrl').
|
||||
*
|
||||
* TODO(bangert): Remove SAFE_URL_PATTERN_
|
||||
* @const {!RegExp}
|
||||
*/
|
||||
goog.html.SafeUrl.SAFE_URL_PATTERN = goog.html.SAFE_URL_PATTERN_;
|
||||
|
||||
/**
|
||||
* Attempts to create a SafeUrl object from `url`. The input string is validated
|
||||
* to match a pattern of commonly used safe URLs. If validation fails, `null` is
|
||||
* returned.
|
||||
*
|
||||
* `url` may be a URL with the `http:`, `https:`, `mailto:`, `ftp:` or `data`
|
||||
* scheme, or a relative URL (i.e., a URL without a scheme; specifically, a
|
||||
* scheme-relative, absolute-path-relative, or path-relative URL).
|
||||
*
|
||||
* @see http://url.spec.whatwg.org/#concept-relative-url
|
||||
* @param {string|!goog.string.TypedString} url The URL to validate.
|
||||
* @return {?goog.html.SafeUrl} The validated URL, wrapped as a SafeUrl, or null
|
||||
* if validation fails.
|
||||
*/
|
||||
goog.html.SafeUrl.trySanitize = function(url) {
|
||||
'use strict';
|
||||
if (url instanceof goog.html.SafeUrl) {
|
||||
return url;
|
||||
}
|
||||
if (typeof url == 'object' && url.implementsGoogStringTypedString) {
|
||||
url = /** @type {!goog.string.TypedString} */ (url).getTypedStringValue();
|
||||
} else {
|
||||
// For defensive purposes, in case users cast around the parameter type.
|
||||
url = String(url);
|
||||
}
|
||||
if (!goog.html.SAFE_URL_PATTERN_.test(url)) {
|
||||
return goog.html.SafeUrl.tryFromDataUrl(url);
|
||||
}
|
||||
return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(url);
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a SafeUrl object from `url`. If `url` is a
|
||||
* `goog.html.SafeUrl` then it is simply returned. Otherwise the input string is
|
||||
* validated to match a pattern of commonly used safe URLs. If validation fails,
|
||||
* `goog.html.SafeUrl.INNOCUOUS_URL` is returned.
|
||||
*
|
||||
* `url` may be a URL with the `http:`, `https:`, `mailto:`, `ftp:` or `data`
|
||||
* scheme, or a relative URL (i.e., a URL without a scheme; specifically, a
|
||||
* scheme-relative, absolute-path-relative, or path-relative URL).
|
||||
*
|
||||
* @see http://url.spec.whatwg.org/#concept-relative-url
|
||||
* @param {string|!goog.string.TypedString} url The URL to validate.
|
||||
* @return {!goog.html.SafeUrl} The validated URL, wrapped as a SafeUrl.
|
||||
*/
|
||||
goog.html.SafeUrl.sanitize = function(url) {
|
||||
'use strict';
|
||||
return goog.html.SafeUrl.trySanitize(url) || goog.html.SafeUrl.INNOCUOUS_URL;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a SafeUrl object from `url`. If `url` is a
|
||||
* `goog.html.SafeUrl` then it is simply returned. Otherwise the input string is
|
||||
* validated to match a pattern of commonly used safe URLs.
|
||||
*
|
||||
* `url` may be a URL with the http, https, mailto or ftp scheme,
|
||||
* or a relative URL (i.e., a URL without a scheme; specifically, a
|
||||
* scheme-relative, absolute-path-relative, or path-relative URL).
|
||||
*
|
||||
* This function asserts (using goog.asserts) that the URL matches this pattern.
|
||||
* If it does not, in addition to failing the assert, an innocuous URL will be
|
||||
* returned.
|
||||
*
|
||||
* @see http://url.spec.whatwg.org/#concept-relative-url
|
||||
* @param {string|!goog.string.TypedString} url The URL to validate.
|
||||
* @param {boolean=} opt_allowDataUrl Whether to allow valid data: URLs.
|
||||
* @return {!goog.html.SafeUrl} The validated URL, wrapped as a SafeUrl.
|
||||
*/
|
||||
goog.html.SafeUrl.sanitizeAssertUnchanged = function(url, opt_allowDataUrl) {
|
||||
'use strict';
|
||||
if (url instanceof goog.html.SafeUrl) {
|
||||
return url;
|
||||
} else if (typeof url == 'object' && url.implementsGoogStringTypedString) {
|
||||
url = /** @type {!goog.string.TypedString} */ (url).getTypedStringValue();
|
||||
} else {
|
||||
url = String(url);
|
||||
}
|
||||
if (opt_allowDataUrl && /^data:/i.test(url)) {
|
||||
var safeUrl = goog.html.SafeUrl.fromDataUrl(url);
|
||||
if (safeUrl.getTypedStringValue() == url) {
|
||||
return safeUrl;
|
||||
}
|
||||
}
|
||||
if (!goog.asserts.assert(
|
||||
goog.html.SAFE_URL_PATTERN_.test(url),
|
||||
'%s does not match the safe URL pattern', url)) {
|
||||
url = goog.html.SafeUrl.INNOCUOUS_STRING;
|
||||
}
|
||||
return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(url);
|
||||
};
|
||||
|
||||
/**
|
||||
* Token used to ensure that object is created only from this file. No code
|
||||
* outside of this file can access this token.
|
||||
* @private {!Object}
|
||||
* @const
|
||||
*/
|
||||
goog.html.SafeUrl.CONSTRUCTOR_TOKEN_PRIVATE_ = {};
|
||||
|
||||
/**
|
||||
* Package-internal utility method to create SafeUrl instances.
|
||||
*
|
||||
* @param {string} url The string to initialize the SafeUrl object with.
|
||||
* @return {!goog.html.SafeUrl} The initialized SafeUrl object.
|
||||
* @package
|
||||
*/
|
||||
goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse = function(
|
||||
url) {
|
||||
'use strict';
|
||||
return new goog.html.SafeUrl(
|
||||
url, goog.html.SafeUrl.CONSTRUCTOR_TOKEN_PRIVATE_);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* `INNOCUOUS_STRING` wrapped in a `SafeUrl`.
|
||||
* @const {!goog.html.SafeUrl}
|
||||
*/
|
||||
goog.html.SafeUrl.INNOCUOUS_URL =
|
||||
goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(
|
||||
goog.html.SafeUrl.INNOCUOUS_STRING);
|
||||
|
||||
|
||||
/**
|
||||
* A SafeUrl corresponding to the special about:blank url.
|
||||
* @const {!goog.html.SafeUrl}
|
||||
*/
|
||||
goog.html.SafeUrl.ABOUT_BLANK =
|
||||
goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(
|
||||
'about:blank');
|
||||
Executable
+524
@@ -0,0 +1,524 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright The Closure Library Authors.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview The TrustedResourceUrl type and its builders.
|
||||
*
|
||||
* TODO(xtof): Link to document stating type contract.
|
||||
*/
|
||||
|
||||
goog.provide('goog.html.TrustedResourceUrl');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.fs.blob');
|
||||
goog.require('goog.fs.url');
|
||||
goog.require('goog.html.SafeScript');
|
||||
goog.require('goog.html.trustedtypes');
|
||||
goog.require('goog.i18n.bidi.Dir');
|
||||
goog.require('goog.i18n.bidi.DirectionalString');
|
||||
goog.require('goog.string.Const');
|
||||
goog.require('goog.string.TypedString');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A URL which is under application control and from which script, CSS, and
|
||||
* other resources that represent executable code, can be fetched.
|
||||
*
|
||||
* Given that the URL can only be constructed from strings under application
|
||||
* control and is used to load resources, bugs resulting in a malformed URL
|
||||
* should not have a security impact and are likely to be easily detectable
|
||||
* during testing. Given the wide number of non-RFC compliant URLs in use,
|
||||
* stricter validation could prevent some applications from being able to use
|
||||
* this type.
|
||||
*
|
||||
* Instances of this type must be created via the factory method,
|
||||
* (`fromConstant`, `fromConstants`, `format` or `formatWithParams`), and not by
|
||||
* invoking its constructor. The constructor intentionally takes an extra
|
||||
* parameter that cannot be constructed outside of this file and the type is
|
||||
* immutable; hence only a default instance corresponding to the empty string
|
||||
* can be obtained via constructor invocation.
|
||||
*
|
||||
* Creating TrustedResourceUrl objects HAS SIDE-EFFECTS due to calling
|
||||
* Trusted Types Web API.
|
||||
*
|
||||
* @see goog.html.TrustedResourceUrl#fromConstant
|
||||
* @final
|
||||
* @struct
|
||||
* @implements {goog.i18n.bidi.DirectionalString}
|
||||
* @implements {goog.string.TypedString}
|
||||
*/
|
||||
goog.html.TrustedResourceUrl = class {
|
||||
/**
|
||||
* @param {!TrustedScriptURL|string} value
|
||||
* @param {!Object} token package-internal implementation detail.
|
||||
*/
|
||||
constructor(value, token) {
|
||||
/**
|
||||
* The contained value of this TrustedResourceUrl. The field has a
|
||||
* purposely ugly name to make (non-compiled) code that attempts to directly
|
||||
* access this field stand out.
|
||||
* @const
|
||||
* @private {!TrustedScriptURL|string}
|
||||
*/
|
||||
this.privateDoNotAccessOrElseTrustedResourceUrlWrappedValue_ =
|
||||
(token === goog.html.TrustedResourceUrl.CONSTRUCTOR_TOKEN_PRIVATE_) ?
|
||||
value :
|
||||
'';
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @override
|
||||
* @const
|
||||
*/
|
||||
goog.html.TrustedResourceUrl.prototype.implementsGoogStringTypedString = true;
|
||||
|
||||
|
||||
/**
|
||||
* Returns this TrustedResourceUrl's value as a string.
|
||||
*
|
||||
* IMPORTANT: In code where it is security relevant that an object's type is
|
||||
* indeed `TrustedResourceUrl`, use
|
||||
* `goog.html.TrustedResourceUrl.unwrap` instead of this method. If in
|
||||
* doubt, assume that it's security relevant. In particular, note that
|
||||
* goog.html functions which return a goog.html type do not guarantee that
|
||||
* the returned instance is of the right type. For example:
|
||||
*
|
||||
* <pre>
|
||||
* var fakeSafeHtml = new String('fake');
|
||||
* fakeSafeHtml.__proto__ = goog.html.SafeHtml.prototype;
|
||||
* var newSafeHtml = goog.html.SafeHtml.htmlEscape(fakeSafeHtml);
|
||||
* // newSafeHtml is just an alias for fakeSafeHtml, it's passed through by
|
||||
* // goog.html.SafeHtml.htmlEscape() as fakeSafeHtml instanceof
|
||||
* // goog.html.SafeHtml.
|
||||
* </pre>
|
||||
*
|
||||
* @see goog.html.TrustedResourceUrl#unwrap
|
||||
* @override
|
||||
*/
|
||||
goog.html.TrustedResourceUrl.prototype.getTypedStringValue = function() {
|
||||
'use strict';
|
||||
return this.privateDoNotAccessOrElseTrustedResourceUrlWrappedValue_
|
||||
.toString();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @override
|
||||
* @const
|
||||
*/
|
||||
goog.html.TrustedResourceUrl.prototype.implementsGoogI18nBidiDirectionalString =
|
||||
true;
|
||||
|
||||
|
||||
/**
|
||||
* Returns this URLs directionality, which is always `LTR`.
|
||||
* @override
|
||||
* @return {!goog.i18n.bidi.Dir}
|
||||
*/
|
||||
goog.html.TrustedResourceUrl.prototype.getDirection = function() {
|
||||
'use strict';
|
||||
return goog.i18n.bidi.Dir.LTR;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new TrustedResourceUrl with params added to URL. Both search and
|
||||
* hash params can be specified.
|
||||
*
|
||||
* @param {string|?Object<string, *>|undefined} searchParams Search parameters
|
||||
* to add to URL. See goog.html.TrustedResourceUrl.stringifyParams_ for
|
||||
* exact format definition.
|
||||
* @param {(string|?Object<string, *>)=} opt_hashParams Hash parameters to add
|
||||
* to URL. See goog.html.TrustedResourceUrl.stringifyParams_ for exact
|
||||
* format definition.
|
||||
* @return {!goog.html.TrustedResourceUrl} New TrustedResourceUrl with params.
|
||||
*/
|
||||
goog.html.TrustedResourceUrl.prototype.cloneWithParams = function(
|
||||
searchParams, opt_hashParams) {
|
||||
'use strict';
|
||||
var url = goog.html.TrustedResourceUrl.unwrap(this);
|
||||
var parts = goog.html.TrustedResourceUrl.URL_PARAM_PARSER_.exec(url);
|
||||
var urlBase = parts[1];
|
||||
var urlSearch = parts[2] || '';
|
||||
var urlHash = parts[3] || '';
|
||||
|
||||
return goog.html.TrustedResourceUrl
|
||||
.createTrustedResourceUrlSecurityPrivateDoNotAccessOrElse(
|
||||
urlBase +
|
||||
goog.html.TrustedResourceUrl.stringifyParams_(
|
||||
'?', urlSearch, searchParams) +
|
||||
goog.html.TrustedResourceUrl.stringifyParams_(
|
||||
'#', urlHash, opt_hashParams));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns a string-representation of this value.
|
||||
*
|
||||
* To obtain the actual string value wrapped in a TrustedResourceUrl, use
|
||||
* `goog.html.TrustedResourceUrl.unwrap`.
|
||||
*
|
||||
* @return {string}
|
||||
* @see goog.html.TrustedResourceUrl#unwrap
|
||||
* @override
|
||||
*/
|
||||
goog.html.TrustedResourceUrl.prototype.toString = function() {
|
||||
'use strict';
|
||||
return this.privateDoNotAccessOrElseTrustedResourceUrlWrappedValue_ + '';
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Performs a runtime check that the provided object is indeed a
|
||||
* TrustedResourceUrl object, and returns its value.
|
||||
*
|
||||
* @param {!goog.html.TrustedResourceUrl} trustedResourceUrl The object to
|
||||
* extract from.
|
||||
* @return {string} The trustedResourceUrl object's contained string, unless
|
||||
* the run-time type check fails. In that case, `unwrap` returns an
|
||||
* innocuous string, or, if assertions are enabled, throws
|
||||
* `goog.asserts.AssertionError`.
|
||||
*/
|
||||
goog.html.TrustedResourceUrl.unwrap = function(trustedResourceUrl) {
|
||||
'use strict';
|
||||
return goog.html.TrustedResourceUrl.unwrapTrustedScriptURL(trustedResourceUrl)
|
||||
.toString();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Unwraps value as TrustedScriptURL if supported or as a string if not.
|
||||
* @param {!goog.html.TrustedResourceUrl} trustedResourceUrl
|
||||
* @return {!TrustedScriptURL|string}
|
||||
* @see goog.html.TrustedResourceUrl.unwrap
|
||||
*/
|
||||
goog.html.TrustedResourceUrl.unwrapTrustedScriptURL = function(
|
||||
trustedResourceUrl) {
|
||||
'use strict';
|
||||
// Perform additional Run-time type-checking to ensure that
|
||||
// trustedResourceUrl is indeed an instance of the expected type. This
|
||||
// provides some additional protection against security bugs due to
|
||||
// application code that disables type checks.
|
||||
// Specifically, the following checks are performed:
|
||||
// 1. The object is an instance of the expected type.
|
||||
// 2. The object is not an instance of a subclass.
|
||||
if (trustedResourceUrl instanceof goog.html.TrustedResourceUrl &&
|
||||
trustedResourceUrl.constructor === goog.html.TrustedResourceUrl) {
|
||||
return trustedResourceUrl
|
||||
.privateDoNotAccessOrElseTrustedResourceUrlWrappedValue_;
|
||||
} else {
|
||||
goog.asserts.fail('expected object of type TrustedResourceUrl, got \'' +
|
||||
trustedResourceUrl + '\' of type ' + goog.typeOf(trustedResourceUrl));
|
||||
return 'type_error:TrustedResourceUrl';
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a TrustedResourceUrl from a format string and arguments.
|
||||
*
|
||||
* The arguments for interpolation into the format string map labels to values.
|
||||
* Values of type `goog.string.Const` are interpolated without modifcation.
|
||||
* Values of other types are cast to string and encoded with
|
||||
* encodeURIComponent.
|
||||
*
|
||||
* `%{<label>}` markers are used in the format string to indicate locations
|
||||
* to be interpolated with the valued mapped to the given label. `<label>`
|
||||
* must contain only alphanumeric and `_` characters.
|
||||
*
|
||||
* The format string must match goog.html.TrustedResourceUrl.BASE_URL_.
|
||||
*
|
||||
* Example usage:
|
||||
*
|
||||
* var url = goog.html.TrustedResourceUrl.format(goog.string.Const.from(
|
||||
* 'https://www.google.com/search?q=%{query}'), {'query': searchTerm});
|
||||
*
|
||||
* var url = goog.html.TrustedResourceUrl.format(goog.string.Const.from(
|
||||
* '//www.youtube.com/v/%{videoId}?hl=en&fs=1%{autoplay}'), {
|
||||
* 'videoId': videoId,
|
||||
* 'autoplay': opt_autoplay ?
|
||||
* goog.string.Const.from('&autoplay=1') : goog.string.Const.EMPTY
|
||||
* });
|
||||
*
|
||||
* While this function can be used to create a TrustedResourceUrl from only
|
||||
* constants, fromConstant() and fromConstants() are generally preferable for
|
||||
* that purpose.
|
||||
*
|
||||
* @param {!goog.string.Const} format The format string.
|
||||
* @param {!Object<string, (string|number|!goog.string.Const)>} args Mapping
|
||||
* of labels to values to be interpolated into the format string.
|
||||
* goog.string.Const values are interpolated without encoding.
|
||||
* @return {!goog.html.TrustedResourceUrl}
|
||||
* @throws {!Error} On an invalid format string or if a label used in the
|
||||
* the format string is not present in args.
|
||||
*/
|
||||
goog.html.TrustedResourceUrl.format = function(format, args) {
|
||||
'use strict';
|
||||
var formatStr = goog.string.Const.unwrap(format);
|
||||
if (!goog.html.TrustedResourceUrl.BASE_URL_.test(formatStr)) {
|
||||
throw new Error('Invalid TrustedResourceUrl format: ' + formatStr);
|
||||
}
|
||||
var result = formatStr.replace(
|
||||
goog.html.TrustedResourceUrl.FORMAT_MARKER_, function(match, id) {
|
||||
'use strict';
|
||||
if (!Object.prototype.hasOwnProperty.call(args, id)) {
|
||||
throw new Error(
|
||||
'Found marker, "' + id + '", in format string, "' + formatStr +
|
||||
'", but no valid label mapping found ' +
|
||||
'in args: ' + JSON.stringify(args));
|
||||
}
|
||||
var arg = args[id];
|
||||
if (arg instanceof goog.string.Const) {
|
||||
return goog.string.Const.unwrap(arg);
|
||||
} else {
|
||||
return encodeURIComponent(String(arg));
|
||||
}
|
||||
});
|
||||
return goog.html.TrustedResourceUrl
|
||||
.createTrustedResourceUrlSecurityPrivateDoNotAccessOrElse(result);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @private @const {!RegExp}
|
||||
*/
|
||||
goog.html.TrustedResourceUrl.FORMAT_MARKER_ = /%{(\w+)}/g;
|
||||
|
||||
|
||||
/**
|
||||
* The URL must be absolute, scheme-relative or path-absolute. So it must
|
||||
* start with:
|
||||
* - https:// followed by allowed origin characters.
|
||||
* - // followed by allowed origin characters.
|
||||
* - Any absolute or relative path.
|
||||
*
|
||||
* Based on
|
||||
* https://url.spec.whatwg.org/commit-snapshots/56b74ce7cca8883eab62e9a12666e2fac665d03d/#url-parsing
|
||||
* an initial / which is not followed by another / or \ will end up in the "path
|
||||
* state" and from there it can only go to "fragment state" and "query state".
|
||||
*
|
||||
* We don't enforce a well-formed domain name. So '.' or '1.2' are valid.
|
||||
* That's ok because the origin comes from a compile-time constant.
|
||||
*
|
||||
* A regular expression is used instead of goog.uri for several reasons:
|
||||
* - Strictness. E.g. we don't want any userinfo component and we don't
|
||||
* want '/./, nor \' in the first path component.
|
||||
* - Small trusted base. goog.uri is generic and might need to change,
|
||||
* reasoning about all the ways it can parse a URL now and in the future
|
||||
* is error-prone.
|
||||
* - Code size. We expect many calls to .format(), many of which might
|
||||
* not be using goog.uri.
|
||||
* - Simplicity. Using goog.uri would likely not result in simpler nor shorter
|
||||
* code.
|
||||
* @private @const {!RegExp}
|
||||
*/
|
||||
goog.html.TrustedResourceUrl.BASE_URL_ = new RegExp(
|
||||
'^((https:)?//[0-9a-z.:[\\]-]+/' // Origin.
|
||||
+ '|/[^/\\\\]' // Absolute path.
|
||||
+ '|[^:/\\\\%]+/' // Relative path.
|
||||
+ '|[^:/\\\\%]*[?#]' // Query string or fragment.
|
||||
+ '|about:blank#' // about:blank with fragment.
|
||||
+ ')',
|
||||
'i');
|
||||
|
||||
/**
|
||||
* RegExp for splitting a URL into the base, search field, and hash field.
|
||||
*
|
||||
* @private @const {!RegExp}
|
||||
*/
|
||||
goog.html.TrustedResourceUrl.URL_PARAM_PARSER_ =
|
||||
/^([^?#]*)(\?[^#]*)?(#[\s\S]*)?/;
|
||||
|
||||
|
||||
/**
|
||||
* Formats the URL same as TrustedResourceUrl.format and then adds extra URL
|
||||
* parameters.
|
||||
*
|
||||
* Example usage:
|
||||
*
|
||||
* // Creates '//www.youtube.com/v/abc?autoplay=1' for videoId='abc' and
|
||||
* // opt_autoplay=1. Creates '//www.youtube.com/v/abc' for videoId='abc'
|
||||
* // and opt_autoplay=undefined.
|
||||
* var url = goog.html.TrustedResourceUrl.formatWithParams(
|
||||
* goog.string.Const.from('//www.youtube.com/v/%{videoId}'),
|
||||
* {'videoId': videoId},
|
||||
* {'autoplay': opt_autoplay});
|
||||
*
|
||||
* @param {!goog.string.Const} format The format string.
|
||||
* @param {!Object<string, (string|number|!goog.string.Const)>} args Mapping
|
||||
* of labels to values to be interpolated into the format string.
|
||||
* goog.string.Const values are interpolated without encoding.
|
||||
* @param {string|?Object<string, *>|undefined} searchParams Parameters to add
|
||||
* to URL. See goog.html.TrustedResourceUrl.stringifyParams_ for exact
|
||||
* format definition.
|
||||
* @param {(string|?Object<string, *>)=} opt_hashParams Hash parameters to add
|
||||
* to URL. See goog.html.TrustedResourceUrl.stringifyParams_ for exact
|
||||
* format definition.
|
||||
* @return {!goog.html.TrustedResourceUrl}
|
||||
* @throws {!Error} On an invalid format string or if a label used in the
|
||||
* the format string is not present in args.
|
||||
*/
|
||||
goog.html.TrustedResourceUrl.formatWithParams = function(
|
||||
format, args, searchParams, opt_hashParams) {
|
||||
'use strict';
|
||||
var url = goog.html.TrustedResourceUrl.format(format, args);
|
||||
return url.cloneWithParams(searchParams, opt_hashParams);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a TrustedResourceUrl object from a compile-time constant string.
|
||||
*
|
||||
* Compile-time constant strings are inherently program-controlled and hence
|
||||
* trusted.
|
||||
*
|
||||
* @param {!goog.string.Const} url A compile-time-constant string from which to
|
||||
* create a TrustedResourceUrl.
|
||||
* @return {!goog.html.TrustedResourceUrl} A TrustedResourceUrl object
|
||||
* initialized to `url`.
|
||||
*/
|
||||
goog.html.TrustedResourceUrl.fromConstant = function(url) {
|
||||
'use strict';
|
||||
return goog.html.TrustedResourceUrl
|
||||
.createTrustedResourceUrlSecurityPrivateDoNotAccessOrElse(
|
||||
goog.string.Const.unwrap(url));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a TrustedResourceUrl object from a compile-time constant strings.
|
||||
*
|
||||
* Compile-time constant strings are inherently program-controlled and hence
|
||||
* trusted.
|
||||
*
|
||||
* @param {!Array<!goog.string.Const>} parts Compile-time-constant strings from
|
||||
* which to create a TrustedResourceUrl.
|
||||
* @return {!goog.html.TrustedResourceUrl} A TrustedResourceUrl object
|
||||
* initialized to concatenation of `parts`.
|
||||
*/
|
||||
goog.html.TrustedResourceUrl.fromConstants = function(parts) {
|
||||
'use strict';
|
||||
var unwrapped = '';
|
||||
for (var i = 0; i < parts.length; i++) {
|
||||
unwrapped += goog.string.Const.unwrap(parts[i]);
|
||||
}
|
||||
return goog.html.TrustedResourceUrl
|
||||
.createTrustedResourceUrlSecurityPrivateDoNotAccessOrElse(unwrapped);
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a TrustedResourceUrl object by generating a Blob from a SafeScript
|
||||
* object and then calling createObjectURL with that blob.
|
||||
*
|
||||
* SafeScript objects are trusted to contain executable JavaScript code.
|
||||
*
|
||||
* Caller must call goog.fs.url.revokeObjectUrl() on the unwrapped url to
|
||||
* release the underlying blob.
|
||||
*
|
||||
* Throws if browser doesn't support blob construction.
|
||||
*
|
||||
* @param {!goog.html.SafeScript} safeScript A script from which to create a
|
||||
* TrustedResourceUrl.
|
||||
* @return {!goog.html.TrustedResourceUrl} A TrustedResourceUrl object
|
||||
* initialized to a new blob URL.
|
||||
*/
|
||||
goog.html.TrustedResourceUrl.fromSafeScript = function(safeScript) {
|
||||
'use strict';
|
||||
var blob = goog.fs.blob.getBlobWithProperties(
|
||||
[goog.html.SafeScript.unwrap(safeScript)], 'text/javascript');
|
||||
var url = goog.fs.url.createObjectUrl(blob);
|
||||
return goog.html.TrustedResourceUrl
|
||||
.createTrustedResourceUrlSecurityPrivateDoNotAccessOrElse(url);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Token used to ensure that object is created only from this file. No code
|
||||
* outside of this file can access this token.
|
||||
* @private {!Object}
|
||||
* @const
|
||||
*/
|
||||
goog.html.TrustedResourceUrl.CONSTRUCTOR_TOKEN_PRIVATE_ = {};
|
||||
|
||||
|
||||
/**
|
||||
* Package-internal utility method to create TrustedResourceUrl instances.
|
||||
*
|
||||
* @param {string} url The string to initialize the TrustedResourceUrl object
|
||||
* with.
|
||||
* @return {!goog.html.TrustedResourceUrl} The initialized TrustedResourceUrl
|
||||
* object.
|
||||
* @package
|
||||
*/
|
||||
goog.html.TrustedResourceUrl
|
||||
.createTrustedResourceUrlSecurityPrivateDoNotAccessOrElse = function(url) {
|
||||
'use strict';
|
||||
const policy = goog.html.trustedtypes.getPolicyPrivateDoNotAccessOrElse();
|
||||
var value = policy ? policy.createScriptURL(url) : url;
|
||||
return new goog.html.TrustedResourceUrl(
|
||||
value, goog.html.TrustedResourceUrl.CONSTRUCTOR_TOKEN_PRIVATE_);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Stringifies the passed params to be used as either a search or hash field of
|
||||
* a URL.
|
||||
*
|
||||
* @param {string} prefix The prefix character for the given field ('?' or '#').
|
||||
* @param {string} currentString The existing field value (including the prefix
|
||||
* character, if the field is present).
|
||||
* @param {string|?Object<string, *>|undefined} params The params to set or
|
||||
* append to the field.
|
||||
* - If `undefined` or `null`, the field remains unchanged.
|
||||
* - If a string, then the string will be escaped and the field will be
|
||||
* overwritten with that value.
|
||||
* - If an Object, that object is treated as a set of key-value pairs to be
|
||||
* appended to the current field. Note that JavaScript doesn't guarantee the
|
||||
* order of values in an object which might result in non-deterministic order
|
||||
* of the parameters. However, browsers currently preserve the order. The
|
||||
* rules for each entry:
|
||||
* - If an array, it will be processed as if each entry were an additional
|
||||
* parameter with exactly the same key, following the same logic below.
|
||||
* - If `undefined` or `null`, it will be skipped.
|
||||
* - Otherwise, it will be turned into a string, escaped, and appended.
|
||||
* @return {string}
|
||||
* @private
|
||||
*/
|
||||
goog.html.TrustedResourceUrl.stringifyParams_ = function(
|
||||
prefix, currentString, params) {
|
||||
'use strict';
|
||||
if (params == null) {
|
||||
// Do not modify the field.
|
||||
return currentString;
|
||||
}
|
||||
if (typeof params === 'string') {
|
||||
// Set field to the passed string.
|
||||
return params ? prefix + encodeURIComponent(params) : '';
|
||||
}
|
||||
// Add on parameters to field from key-value object.
|
||||
for (var key in params) {
|
||||
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty#Using_hasOwnProperty_as_a_property_name
|
||||
if (Object.prototype.hasOwnProperty.call(params, key)) {
|
||||
var value = params[key];
|
||||
var outputValues = Array.isArray(value) ? value : [value];
|
||||
for (var i = 0; i < outputValues.length; i++) {
|
||||
var outputValue = outputValues[i];
|
||||
if (outputValue != null) {
|
||||
if (!currentString) {
|
||||
currentString = prefix;
|
||||
}
|
||||
currentString += (currentString.length > prefix.length ? '&' : '') +
|
||||
encodeURIComponent(key) + '=' +
|
||||
encodeURIComponent(String(outputValue));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return currentString;
|
||||
};
|
||||
Executable
+41
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright The Closure Library Authors.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Policy to convert strings to Trusted Types. See
|
||||
* https://github.com/WICG/trusted-types for details.
|
||||
*/
|
||||
|
||||
goog.provide('goog.html.trustedtypes');
|
||||
|
||||
|
||||
/**
|
||||
* Cached result of goog.createTrustedTypesPolicy.
|
||||
* @type {?TrustedTypePolicy|undefined}
|
||||
* @private
|
||||
*/
|
||||
goog.html.trustedtypes.cachedPolicy_;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a (singleton) Trusted Type Policy for Safe HTML Types.
|
||||
* @return {?TrustedTypePolicy}
|
||||
* @package
|
||||
*/
|
||||
goog.html.trustedtypes.getPolicyPrivateDoNotAccessOrElse = function() {
|
||||
'use strict';
|
||||
if (!goog.TRUSTED_TYPES_POLICY_NAME) {
|
||||
// Binary not configured for Trusted Types.
|
||||
return null;
|
||||
}
|
||||
|
||||
if (goog.html.trustedtypes.cachedPolicy_ === undefined) {
|
||||
goog.html.trustedtypes.cachedPolicy_ =
|
||||
goog.createTrustedTypesPolicy(goog.TRUSTED_TYPES_POLICY_NAME + '#html');
|
||||
}
|
||||
|
||||
return goog.html.trustedtypes.cachedPolicy_;
|
||||
};
|
||||
Executable
+230
@@ -0,0 +1,230 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright The Closure Library Authors.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Unchecked conversions to create values of goog.html types from
|
||||
* plain strings. Use of these functions could potentially result in instances
|
||||
* of goog.html types that violate their type contracts, and hence result in
|
||||
* security vulnerabilties.
|
||||
*
|
||||
* Therefore, all uses of the methods herein must be carefully security
|
||||
* reviewed. Avoid use of the methods in this file whenever possible; instead
|
||||
* prefer to create instances of goog.html types using inherently safe builders
|
||||
* or template systems.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
goog.provide('goog.html.uncheckedconversions');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.html.SafeHtml');
|
||||
goog.require('goog.html.SafeScript');
|
||||
goog.require('goog.html.SafeStyle');
|
||||
goog.require('goog.html.SafeStyleSheet');
|
||||
goog.require('goog.html.SafeUrl');
|
||||
goog.require('goog.html.TrustedResourceUrl');
|
||||
goog.require('goog.string.Const');
|
||||
goog.require('goog.string.internal');
|
||||
goog.requireType('goog.i18n.bidi.Dir');
|
||||
|
||||
|
||||
/**
|
||||
* Performs an "unchecked conversion" to SafeHtml from a plain string that is
|
||||
* known to satisfy the SafeHtml type contract.
|
||||
*
|
||||
* IMPORTANT: Uses of this method must be carefully security-reviewed to ensure
|
||||
* that the value of `html` satisfies the SafeHtml type contract in all
|
||||
* possible program states.
|
||||
*
|
||||
*
|
||||
* @param {!goog.string.Const} justification A constant string explaining why
|
||||
* this use of this method is safe. May include a security review ticket
|
||||
* number.
|
||||
* @param {string} html A string that is claimed to adhere to the SafeHtml
|
||||
* contract.
|
||||
* @param {?goog.i18n.bidi.Dir=} opt_dir The optional directionality of the
|
||||
* SafeHtml to be constructed. A null or undefined value signifies an
|
||||
* unknown directionality.
|
||||
* @return {!goog.html.SafeHtml} The value of html, wrapped in a SafeHtml
|
||||
* object.
|
||||
*/
|
||||
goog.html.uncheckedconversions.safeHtmlFromStringKnownToSatisfyTypeContract =
|
||||
function(justification, html, opt_dir) {
|
||||
'use strict';
|
||||
// unwrap() called inside an assert so that justification can be optimized
|
||||
// away in production code.
|
||||
goog.asserts.assertString(
|
||||
goog.string.Const.unwrap(justification), 'must provide justification');
|
||||
goog.asserts.assert(
|
||||
!goog.string.internal.isEmptyOrWhitespace(
|
||||
goog.string.Const.unwrap(justification)),
|
||||
'must provide non-empty justification');
|
||||
return goog.html.SafeHtml.createSafeHtmlSecurityPrivateDoNotAccessOrElse(
|
||||
html, opt_dir || null);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Performs an "unchecked conversion" to SafeScript from a plain string that is
|
||||
* known to satisfy the SafeScript type contract.
|
||||
*
|
||||
* IMPORTANT: Uses of this method must be carefully security-reviewed to ensure
|
||||
* that the value of `script` satisfies the SafeScript type contract in
|
||||
* all possible program states.
|
||||
*
|
||||
*
|
||||
* @param {!goog.string.Const} justification A constant string explaining why
|
||||
* this use of this method is safe. May include a security review ticket
|
||||
* number.
|
||||
* @param {string} script The string to wrap as a SafeScript.
|
||||
* @return {!goog.html.SafeScript} The value of `script`, wrapped in a
|
||||
* SafeScript object.
|
||||
*/
|
||||
goog.html.uncheckedconversions.safeScriptFromStringKnownToSatisfyTypeContract =
|
||||
function(justification, script) {
|
||||
'use strict';
|
||||
// unwrap() called inside an assert so that justification can be optimized
|
||||
// away in production code.
|
||||
goog.asserts.assertString(
|
||||
goog.string.Const.unwrap(justification), 'must provide justification');
|
||||
goog.asserts.assert(
|
||||
!goog.string.internal.isEmptyOrWhitespace(
|
||||
goog.string.Const.unwrap(justification)),
|
||||
'must provide non-empty justification');
|
||||
return goog.html.SafeScript.createSafeScriptSecurityPrivateDoNotAccessOrElse(
|
||||
script);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Performs an "unchecked conversion" to SafeStyle from a plain string that is
|
||||
* known to satisfy the SafeStyle type contract.
|
||||
*
|
||||
* IMPORTANT: Uses of this method must be carefully security-reviewed to ensure
|
||||
* that the value of `style` satisfies the SafeStyle type contract in all
|
||||
* possible program states.
|
||||
*
|
||||
*
|
||||
* @param {!goog.string.Const} justification A constant string explaining why
|
||||
* this use of this method is safe. May include a security review ticket
|
||||
* number.
|
||||
* @param {string} style The string to wrap as a SafeStyle.
|
||||
* @return {!goog.html.SafeStyle} The value of `style`, wrapped in a
|
||||
* SafeStyle object.
|
||||
*/
|
||||
goog.html.uncheckedconversions.safeStyleFromStringKnownToSatisfyTypeContract =
|
||||
function(justification, style) {
|
||||
'use strict';
|
||||
// unwrap() called inside an assert so that justification can be optimized
|
||||
// away in production code.
|
||||
goog.asserts.assertString(
|
||||
goog.string.Const.unwrap(justification), 'must provide justification');
|
||||
goog.asserts.assert(
|
||||
!goog.string.internal.isEmptyOrWhitespace(
|
||||
goog.string.Const.unwrap(justification)),
|
||||
'must provide non-empty justification');
|
||||
return goog.html.SafeStyle.createSafeStyleSecurityPrivateDoNotAccessOrElse(
|
||||
style);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Performs an "unchecked conversion" to SafeStyleSheet from a plain string
|
||||
* that is known to satisfy the SafeStyleSheet type contract.
|
||||
*
|
||||
* IMPORTANT: Uses of this method must be carefully security-reviewed to ensure
|
||||
* that the value of `styleSheet` satisfies the SafeStyleSheet type
|
||||
* contract in all possible program states.
|
||||
*
|
||||
*
|
||||
* @param {!goog.string.Const} justification A constant string explaining why
|
||||
* this use of this method is safe. May include a security review ticket
|
||||
* number.
|
||||
* @param {string} styleSheet The string to wrap as a SafeStyleSheet.
|
||||
* @return {!goog.html.SafeStyleSheet} The value of `styleSheet`, wrapped
|
||||
* in a SafeStyleSheet object.
|
||||
*/
|
||||
goog.html.uncheckedconversions
|
||||
.safeStyleSheetFromStringKnownToSatisfyTypeContract = function(
|
||||
justification, styleSheet) {
|
||||
'use strict';
|
||||
// unwrap() called inside an assert so that justification can be optimized
|
||||
// away in production code.
|
||||
goog.asserts.assertString(
|
||||
goog.string.Const.unwrap(justification), 'must provide justification');
|
||||
goog.asserts.assert(
|
||||
!goog.string.internal.isEmptyOrWhitespace(
|
||||
goog.string.Const.unwrap(justification)),
|
||||
'must provide non-empty justification');
|
||||
return goog.html.SafeStyleSheet
|
||||
.createSafeStyleSheetSecurityPrivateDoNotAccessOrElse(styleSheet);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Performs an "unchecked conversion" to SafeUrl from a plain string that is
|
||||
* known to satisfy the SafeUrl type contract.
|
||||
*
|
||||
* IMPORTANT: Uses of this method must be carefully security-reviewed to ensure
|
||||
* that the value of `url` satisfies the SafeUrl type contract in all
|
||||
* possible program states.
|
||||
*
|
||||
*
|
||||
* @param {!goog.string.Const} justification A constant string explaining why
|
||||
* this use of this method is safe. May include a security review ticket
|
||||
* number.
|
||||
* @param {string} url The string to wrap as a SafeUrl.
|
||||
* @return {!goog.html.SafeUrl} The value of `url`, wrapped in a SafeUrl
|
||||
* object.
|
||||
*/
|
||||
goog.html.uncheckedconversions.safeUrlFromStringKnownToSatisfyTypeContract =
|
||||
function(justification, url) {
|
||||
'use strict';
|
||||
// unwrap() called inside an assert so that justification can be optimized
|
||||
// away in production code.
|
||||
goog.asserts.assertString(
|
||||
goog.string.Const.unwrap(justification), 'must provide justification');
|
||||
goog.asserts.assert(
|
||||
!goog.string.internal.isEmptyOrWhitespace(
|
||||
goog.string.Const.unwrap(justification)),
|
||||
'must provide non-empty justification');
|
||||
return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(url);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Performs an "unchecked conversion" to TrustedResourceUrl from a plain string
|
||||
* that is known to satisfy the TrustedResourceUrl type contract.
|
||||
*
|
||||
* IMPORTANT: Uses of this method must be carefully security-reviewed to ensure
|
||||
* that the value of `url` satisfies the TrustedResourceUrl type contract
|
||||
* in all possible program states.
|
||||
*
|
||||
*
|
||||
* @param {!goog.string.Const} justification A constant string explaining why
|
||||
* this use of this method is safe. May include a security review ticket
|
||||
* number.
|
||||
* @param {string} url The string to wrap as a TrustedResourceUrl.
|
||||
* @return {!goog.html.TrustedResourceUrl} The value of `url`, wrapped in
|
||||
* a TrustedResourceUrl object.
|
||||
*/
|
||||
goog.html.uncheckedconversions
|
||||
.trustedResourceUrlFromStringKnownToSatisfyTypeContract = function(
|
||||
justification, url) {
|
||||
'use strict';
|
||||
// unwrap() called inside an assert so that justification can be optimized
|
||||
// away in production code.
|
||||
goog.asserts.assertString(
|
||||
goog.string.Const.unwrap(justification), 'must provide justification');
|
||||
goog.asserts.assert(
|
||||
!goog.string.internal.isEmptyOrWhitespace(
|
||||
goog.string.Const.unwrap(justification)),
|
||||
'must provide non-empty justification');
|
||||
return goog.html.TrustedResourceUrl
|
||||
.createTrustedResourceUrlSecurityPrivateDoNotAccessOrElse(url);
|
||||
};
|
||||
Reference in New Issue
Block a user