summaryrefslogtreecommitdiff
path: root/assets/viz/2/goog/html
diff options
context:
space:
mode:
Diffstat (limited to 'assets/viz/2/goog/html')
-rw-r--r--assets/viz/2/goog/html/safehtml.js62
-rw-r--r--assets/viz/2/goog/html/safescript.js2
-rw-r--r--assets/viz/2/goog/html/safestyle.js181
-rw-r--r--assets/viz/2/goog/html/safestylesheet.js68
-rw-r--r--assets/viz/2/goog/html/safeurl.js86
-rw-r--r--assets/viz/2/goog/html/trustedresourceurl.js174
-rw-r--r--assets/viz/2/goog/html/uncheckedconversions.js12
7 files changed, 505 insertions, 80 deletions
diff --git a/assets/viz/2/goog/html/safehtml.js b/assets/viz/2/goog/html/safehtml.js
index 704d826..4bffbff 100644
--- a/assets/viz/2/goog/html/safehtml.js
+++ b/assets/viz/2/goog/html/safehtml.js
@@ -25,6 +25,7 @@ goog.require('goog.array');
goog.require('goog.asserts');
goog.require('goog.dom.TagName');
goog.require('goog.dom.tags');
+goog.require('goog.html.SafeScript');
goog.require('goog.html.SafeStyle');
goog.require('goog.html.SafeStyleSheet');
goog.require('goog.html.SafeUrl');
@@ -77,7 +78,7 @@ goog.html.SafeHtml = function() {
/**
* A type marker used to implement additional run-time type checking.
* @see goog.html.SafeHtml#unwrap
- * @const
+ * @const {!Object}
* @private
*/
this.SAFE_HTML_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ =
@@ -319,7 +320,7 @@ goog.html.SafeHtml.NOT_ALLOWED_TAG_NAMES_ = goog.object.createSet(
/**
* @typedef {string|number|goog.string.TypedString|
- * goog.html.SafeStyle.PropertyMap}
+ * goog.html.SafeStyle.PropertyMap|undefined}
*/
goog.html.SafeHtml.AttributeValue;
@@ -360,8 +361,9 @@ goog.html.SafeHtml.AttributeValue;
* which are not supported by this function are applet, base, embed, iframe,
* link, math, object, script, style, svg, and template.
*
- * @param {string} tagName The name of the tag. Only tag names consisting of
- * [a-zA-Z0-9-] are allowed. Tag names documented above are disallowed.
+ * @param {!goog.dom.TagName|string} tagName The name of the tag. Only tag names
+ * consisting of [a-zA-Z0-9-] are allowed. Tag names documented above are
+ * disallowed.
* @param {?Object<string, ?goog.html.SafeHtml.AttributeValue>=} opt_attributes
* Mapping from attribute names to their values. Only attribute names
* consisting of [a-zA-Z0-9-] are allowed. Value of null or undefined causes
@@ -376,9 +378,9 @@ goog.html.SafeHtml.AttributeValue;
* @throws {goog.asserts.AssertionError} If content for void tag is provided.
*/
goog.html.SafeHtml.create = function(tagName, opt_attributes, opt_content) {
- goog.html.SafeHtml.verifyTagName(tagName);
+ goog.html.SafeHtml.verifyTagName(String(tagName));
return goog.html.SafeHtml.createSafeHtmlTagSecurityPrivateDoNotAccessOrElse(
- tagName, opt_attributes, opt_content);
+ String(tagName), opt_attributes, opt_content);
};
@@ -525,6 +527,12 @@ goog.html.SafeHtml.canUseSandboxIframe = function() {
* opt_attributes contains the src attribute.
*/
goog.html.SafeHtml.createScriptSrc = function(src, opt_attributes) {
+ // TODO(mlourenco): The charset attribute should probably be blocked. If
+ // its value is attacker controlled, the script contains attacker controlled
+ // sub-strings (even if properly escaped) and the server does not set charset
+ // then XSS is likely possible.
+ // https://html.spec.whatwg.org/multipage/scripting.html#dom-script-charset
+
// Check whether this is really TrustedResourceUrl.
goog.html.TrustedResourceUrl.unwrap(src);
@@ -538,6 +546,44 @@ goog.html.SafeHtml.createScriptSrc = function(src, opt_attributes) {
/**
+ * Creates a SafeHtml representing a script tag. Does not allow the language,
+ * src, text or type attributes to be set.
+ * @param {!goog.html.SafeScript|!Array<!goog.html.SafeScript>}
+ * script Content to put inside the tag. Array elements are
+ * concatenated.
+ * @param {?Object<string, ?goog.html.SafeHtml.AttributeValue>=} opt_attributes
+ * Mapping from attribute names to their values. Only attribute names
+ * consisting of [a-zA-Z0-9-] are allowed. Value of null or undefined causes
+ * the attribute to be omitted.
+ * @return {!goog.html.SafeHtml} The SafeHtml content with the tag.
+ * @throws {Error} If invalid attribute name or attribute value is provided. If
+ * opt_attributes contains the language, src, text or type attribute.
+ */
+goog.html.SafeHtml.createScript = function(script, opt_attributes) {
+ for (var attr in opt_attributes) {
+ var attrLower = attr.toLowerCase();
+ if (attrLower == 'language' || attrLower == 'src' || attrLower == 'text' ||
+ attrLower == 'type') {
+ throw Error('Cannot set "' + attrLower + '" attribute');
+ }
+ }
+
+ var content = '';
+ script = goog.array.concat(script);
+ for (var i = 0; i < script.length; i++) {
+ content += goog.html.SafeScript.unwrap(script[i]);
+ }
+ // Convert to SafeHtml so that it's not HTML-escaped. This is safe because
+ // as part of its contract, SafeScript should have no dangerous '<'.
+ var htmlContent =
+ goog.html.SafeHtml.createSafeHtmlSecurityPrivateDoNotAccessOrElse(
+ content, goog.i18n.bidi.Dir.NEUTRAL);
+ return goog.html.SafeHtml.createSafeHtmlTagSecurityPrivateDoNotAccessOrElse(
+ 'script', opt_attributes, htmlContent);
+};
+
+
+/**
* Creates a SafeHtml representing a style tag. The type attribute is set
* to "text/css".
* @param {!goog.html.SafeStyleSheet|!Array<!goog.html.SafeStyleSheet>}
@@ -636,7 +682,7 @@ goog.html.SafeHtml.getAttrNameAndValue_ = function(tagName, name, value) {
throw Error(
'Attribute "' + name + '" requires goog.string.Const value, "' + value +
'" given.');
- // URL attributes handled differently accroding to tag.
+ // URL attributes handled differently according to tag.
} else if (name.toLowerCase() in goog.html.SafeHtml.URL_ATTRIBUTES_) {
if (value instanceof goog.html.TrustedResourceUrl) {
value = goog.html.TrustedResourceUrl.unwrap(value);
@@ -881,7 +927,7 @@ goog.html.SafeHtml.stringifyAttributes = function(tagName, opt_attributes) {
/**
- * @param {!Object<string, string>} fixedAttributes
+ * @param {!Object<string, ?goog.html.SafeHtml.AttributeValue>} fixedAttributes
* @param {!Object<string, string>} defaultAttributes
* @param {?Object<string, ?goog.html.SafeHtml.AttributeValue>=} opt_attributes
* Optional attributes passed to create*().
diff --git a/assets/viz/2/goog/html/safescript.js b/assets/viz/2/goog/html/safescript.js
index 26f58f6..7a945eb 100644
--- a/assets/viz/2/goog/html/safescript.js
+++ b/assets/viz/2/goog/html/safescript.js
@@ -78,7 +78,7 @@ goog.html.SafeScript = function() {
/**
* A type marker used to implement additional run-time type checking.
* @see goog.html.SafeScript#unwrap
- * @const
+ * @const {!Object}
* @private
*/
this.SAFE_SCRIPT_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ =
diff --git a/assets/viz/2/goog/html/safestyle.js b/assets/viz/2/goog/html/safestyle.js
index a1f87cb..506a475 100644
--- a/assets/viz/2/goog/html/safestyle.js
+++ b/assets/viz/2/goog/html/safestyle.js
@@ -22,6 +22,7 @@ goog.provide('goog.html.SafeStyle');
goog.require('goog.array');
goog.require('goog.asserts');
+goog.require('goog.html.SafeUrl');
goog.require('goog.string');
goog.require('goog.string.Const');
goog.require('goog.string.TypedString');
@@ -42,19 +43,19 @@ goog.require('goog.string.TypedString');
* is immutable; hence only a default instance corresponding to the empty string
* can be obtained via constructor invocation.
*
- * A SafeStyle's string representation ({@link #getTypedStringValue()}) can
- * safely:
+ * SafeStyle's string representation can safely be:
* <ul>
- * <li>Be interpolated as the entire content of a *quoted* HTML style
- * attribute, or before already existing properties. The SafeStyle string
- * *must be HTML-attribute-escaped* (where " and ' are escaped) before
+ * <li>Interpolated as the content of a *quoted* HTML style attribute.
+ * However, the SafeStyle string *must be HTML-attribute-escaped* before
* interpolation.
- * <li>Be interpolated as the entire content of a {}-wrapped block within a
- * stylesheet, or before already existing properties. The SafeStyle string
- * should not be escaped before interpolation. SafeStyle's contract also
- * guarantees that the string will not be able to introduce new properties
- * or elide existing ones.
- * <li>Be assigned to the style property of a DOM node. The SafeStyle string
+ * <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>
*
@@ -84,7 +85,7 @@ goog.require('goog.string.TypedString');
* appended to {@code background:url("}, the resulting string may result in
* the execution of a malicious script.
*
- * TODO(user): Consider whether we should implement UTF-8 interchange
+ * 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().
@@ -126,7 +127,7 @@ goog.html.SafeStyle = function() {
/**
* A type marker used to implement additional run-time type checking.
* @see goog.html.SafeStyle#unwrap
- * @const
+ * @const {!Object}
* @private
*/
this.SAFE_STYLE_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ =
@@ -312,7 +313,7 @@ goog.html.SafeStyle.EMPTY =
/**
- * The innocuous string generated by goog.html.SafeUrl.create when passed
+ * The innocuous string generated by goog.html.SafeStyle.create when passed
* an unsafe value.
* @const {string}
*/
@@ -320,8 +321,20 @@ goog.html.SafeStyle.INNOCUOUS_STRING = 'zClosurez';
/**
+ * A single property value.
+ * @typedef {string|!goog.string.Const|!goog.html.SafeUrl}
+ */
+goog.html.SafeStyle.PropertyValue;
+
+
+/**
* Mapping of property names to their values.
- * @typedef {!Object<string, goog.string.Const|string>}
+ * 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, ?goog.html.SafeStyle.PropertyValue|
+ * ?Array<!goog.html.SafeStyle.PropertyValue>>}
*/
goog.html.SafeStyle.PropertyMap;
@@ -331,9 +344,12 @@ goog.html.SafeStyle.PropertyMap;
* @param {goog.html.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.
- * Other values must be wrapped in goog.string.Const. Null value causes
- * skipping the property.
+ * [-,.'"%_!# 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 goog.string.Const. URLs might be passed
+ * as goog.html.SafeUrl which will be wrapped into url(""). We also support
+ * array whose elements are joined with ' '. Null value causes skipping the
+ * property.
* @return {!goog.html.SafeStyle}
* @throws {Error} If invalid name is provided.
* @throws {goog.asserts.AssertionError} If invalid value is provided. With
@@ -350,19 +366,11 @@ goog.html.SafeStyle.create = function(map) {
if (value == null) {
continue;
}
- if (value instanceof goog.string.Const) {
- value = goog.string.Const.unwrap(value);
- // These characters can be used to change context and we don't want that
- // even with const values.
- goog.asserts.assert(!/[{;}]/.test(value), 'Value does not allow [{;}].');
- } else if (!goog.html.SafeStyle.VALUE_RE_.test(value)) {
- goog.asserts.fail(
- 'String value allows only [-,."\'%_!# a-zA-Z0-9], rgb() and ' +
- 'rgba(), got: ' + value);
- value = goog.html.SafeStyle.INNOCUOUS_STRING;
- } else if (!goog.html.SafeStyle.hasBalancedQuotes_(value)) {
- goog.asserts.fail('String value requires balanced quotes, got: ' + value);
- value = goog.html.SafeStyle.INNOCUOUS_STRING;
+ if (goog.isArray(value)) {
+ value = goog.array.map(value, goog.html.SafeStyle.sanitizePropertyValue_)
+ .join(' ');
+ } else {
+ value = goog.html.SafeStyle.sanitizePropertyValue_(value);
}
style += name + ':' + value + ';';
}
@@ -376,6 +384,50 @@ goog.html.SafeStyle.create = function(map) {
/**
+ * Checks and converts value to string.
+ * @param {!goog.html.SafeStyle.PropertyValue} value
+ * @return {string}
+ * @private
+ */
+goog.html.SafeStyle.sanitizePropertyValue_ = function(value) {
+ if (value instanceof goog.html.SafeUrl) {
+ var url = goog.html.SafeUrl.unwrap(value);
+ return 'url("' + url.replace(/</g, '%3c').replace(/[\\"]/g, '\\$&') + '")';
+ }
+ var result = value instanceof goog.string.Const ?
+ goog.string.Const.unwrap(value) :
+ goog.html.SafeStyle.sanitizePropertyValueString_(String(value));
+ // These characters can be used to change context and we don't want that even
+ // with const values.
+ goog.asserts.assert(!/[{;}]/.test(result), 'Value does not allow [{;}].');
+ return result;
+};
+
+
+/**
+ * Checks string value.
+ * @param {string} value
+ * @return {string}
+ * @private
+ */
+goog.html.SafeStyle.sanitizePropertyValueString_ = function(value) {
+ var valueWithoutFunctions =
+ value.replace(goog.html.SafeUrl.FUNCTIONS_RE_, '$1')
+ .replace(goog.html.SafeUrl.URL_RE_, 'url');
+ if (!goog.html.SafeStyle.VALUE_RE_.test(valueWithoutFunctions)) {
+ goog.asserts.fail(
+ 'String value allows only ' + goog.html.SafeStyle.VALUE_ALLOWED_CHARS_ +
+ ' and simple functions, got: ' + value);
+ return goog.html.SafeStyle.INNOCUOUS_STRING;
+ } else if (!goog.html.SafeStyle.hasBalancedQuotes_(value)) {
+ goog.asserts.fail('String value requires balanced quotes, got: ' + value);
+ return goog.html.SafeStyle.INNOCUOUS_STRING;
+ }
+ return goog.html.SafeStyle.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;
@@ -400,7 +452,13 @@ goog.html.SafeStyle.hasBalancedQuotes_ = function(value) {
};
-// Keep in sync with the error string in create().
+/**
+ * Characters allowed in goog.html.SafeStyle.VALUE_RE_.
+ * @private {string}
+ */
+goog.html.SafeStyle.VALUE_ALLOWED_CHARS_ = '[-,."\'%_!# a-zA-Z0-9]';
+
+
/**
* Regular expression for safe values.
*
@@ -411,13 +469,66 @@ goog.html.SafeStyle.hasBalancedQuotes_ = function(value) {
* (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 rgb() and rgba() expression checks only for XSS safety, not for CSS
- * validity.
+ * The expression checks only for XSS safety, not for CSS validity.
* @const {!RegExp}
* @private
*/
goog.html.SafeStyle.VALUE_RE_ =
- /^([-,."'%_!# a-zA-Z0-9]+|(?:rgb|hsl)a?\([0-9.%, ]+\))$/;
+ new RegExp('^' + goog.html.SafeStyle.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.
+ * @private @const {!RegExp}
+ */
+goog.html.SafeUrl.URL_RE_ = new RegExp(
+ '\\b(url\\([ \t\n]*)(' +
+ '\'[ -&(-\\[\\]-~]*\'' + // Printable characters except ' and \.
+ '|"[ !#-\\[\\]-~]*"' + // Printable characters except " and \.
+ '|[!#-&*-\\[\\]-~]*' + // Printable characters except [ "'()\\].
+ ')([ \t\n]*\\))',
+ 'g');
+
+
+/**
+ * Regular expression for simple functions.
+ * @private @const {!RegExp}
+ */
+goog.html.SafeUrl.FUNCTIONS_RE_ = new RegExp(
+ '\\b(hsl|hsla|rgb|rgba|(rotate|scale|translate)(X|Y|Z|3d)?)' +
+ '\\([-0-9a-z.%, ]+\\)',
+ 'g');
+
+
+/**
+ * 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}
+ * @private
+ */
+goog.html.SafeStyle.sanitizeUrl_ = function(value) {
+ return value.replace(
+ goog.html.SafeUrl.URL_RE_, function(match, before, url, after) {
+ var quote = '';
+ url = url.replace(/^(['"])(.*)\1$/, function(match, start, inside) {
+ quote = start;
+ return inside;
+ });
+ var sanitized = goog.html.SafeUrl.sanitize(url).getTypedStringValue();
+ return before + quote + sanitized + quote + after;
+ });
+};
/**
diff --git a/assets/viz/2/goog/html/safestylesheet.js b/assets/viz/2/goog/html/safestylesheet.js
index 65a81b0..cdd9e31 100644
--- a/assets/viz/2/goog/html/safestylesheet.js
+++ b/assets/viz/2/goog/html/safestylesheet.js
@@ -22,6 +22,8 @@ goog.provide('goog.html.SafeStyleSheet');
goog.require('goog.array');
goog.require('goog.asserts');
+goog.require('goog.html.SafeStyle');
+goog.require('goog.object');
goog.require('goog.string');
goog.require('goog.string.Const');
goog.require('goog.string.TypedString');
@@ -84,7 +86,7 @@ goog.html.SafeStyleSheet = function() {
/**
* A type marker used to implement additional run-time type checking.
* @see goog.html.SafeStyleSheet#unwrap
- * @const
+ * @const {!Object}
* @private
*/
this.SAFE_STYLE_SHEET_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ =
@@ -109,6 +111,70 @@ goog.html.SafeStyleSheet.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ = {};
/**
+ * Creates a style sheet consisting of one selector and one style definition.
+ * Use {@link goog.html.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 {!goog.html.SafeStyle.PropertyMap|!goog.html.SafeStyle} style Style
+ * definition associated with the selector.
+ * @return {!goog.html.SafeStyleSheet}
+ * @throws {Error} If invalid selector is provided.
+ */
+goog.html.SafeStyleSheet.createRule = function(selector, style) {
+ if (goog.string.contains(selector, '<')) {
+ throw Error('Selector does not allow \'<\', got: ' + selector);
+ }
+
+ // Remove strings.
+ var 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 Error(
+ 'Selector allows only [-_a-zA-Z0-9#.:* ,>+~[\\]()=^$|] and ' +
+ 'strings, got: ' + selector);
+ }
+
+ // Check balanced () and [].
+ if (!goog.html.SafeStyleSheet.hasBalancedBrackets_(selectorToCheck)) {
+ throw Error('() and [] in selector must be balanced, got: ' + selector);
+ }
+
+ if (!(style instanceof goog.html.SafeStyle)) {
+ style = goog.html.SafeStyle.create(style);
+ }
+ var styleSheet = selector + '{' + goog.html.SafeStyle.unwrap(style) + '}';
+ return goog.html.SafeStyleSheet
+ .createSafeStyleSheetSecurityPrivateDoNotAccessOrElse(styleSheet);
+};
+
+
+/**
+ * Checks if a string has balanced () and [] brackets.
+ * @param {string} s String to check.
+ * @return {boolean}
+ * @private
+ */
+goog.html.SafeStyleSheet.hasBalancedBrackets_ = function(s) {
+ var brackets = {'(': ')', '[': ']'};
+ var expectedBrackets = [];
+ for (var i = 0; i < s.length; i++) {
+ var ch = s[i];
+ if (brackets[ch]) {
+ expectedBrackets.push(brackets[ch]);
+ } else if (goog.object.contains(brackets, ch)) {
+ if (expectedBrackets.pop() != ch) {
+ return false;
+ }
+ }
+ }
+ return expectedBrackets.length == 0;
+};
+
+
+/**
* Creates a new SafeStyleSheet object by concatenating values.
* @param {...(!goog.html.SafeStyleSheet|!Array<!goog.html.SafeStyleSheet>)}
* var_args Values to concatenate.
diff --git a/assets/viz/2/goog/html/safeurl.js b/assets/viz/2/goog/html/safeurl.js
index 640a070..3d1ee11 100644
--- a/assets/viz/2/goog/html/safeurl.js
+++ b/assets/viz/2/goog/html/safeurl.js
@@ -22,6 +22,7 @@ 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');
@@ -38,10 +39,11 @@ goog.require('goog.string.TypedString');
* 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, or
- * interpolation into a HTML template in URL context (e.g., inside a href
- * attribute), in the sense that the use will not result in a
- * Cross-Site-Scripting vulnerability.
+ * 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 {@code goog.html.SafeUrl.unwrap}, this type's
* contract does not guarantee that instances are safe to interpolate into HTML
@@ -79,7 +81,7 @@ goog.html.SafeUrl = function() {
/**
* A type marker used to implement additional run-time type checking.
* @see goog.html.SafeUrl#unwrap
- * @const
+ * @const {!Object}
* @private
*/
this.SAFE_URL_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ =
@@ -241,21 +243,24 @@ goog.html.SafeUrl.fromConstant = function(url) {
/**
* A pattern that matches Blob or data types that can have SafeUrls created
- * from URL.createObjectURL(blob) or via a data: URI. Only matches image and
- * video types, currently.
+ * from URL.createObjectURL(blob) or via a data: URI.
* @const
* @private
*/
-goog.html.SAFE_MIME_TYPE_PATTERN_ =
- /^(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm))$/i;
+goog.html.SAFE_MIME_TYPE_PATTERN_ = new RegExp(
+ '^(?:audio/(?:3gpp|3gpp2|aac|midi|mp4|mpeg|ogg|x-m4a|x-wav|webm)|' +
+ 'image/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|' +
+ 'text/csv|' +
+ 'video/(?:mpeg|mp4|ogg|webm))$',
+ 'i');
/**
* Creates a SafeUrl wrapping a blob URL for the given {@code blob}.
*
* The blob URL is created with {@code URL.createObjectURL}. If the MIME type
- * for {@code blob} is not of a known safe image or video MIME type, then the
- * SafeUrl will wrap {@link #INNOCUOUS_STRING}.
+ * for {@code blob} is not of a known safe audio, image or video MIME type,
+ * then the SafeUrl will wrap {@link #INNOCUOUS_STRING}.
*
* @see http://www.w3.org/TR/FileAPI/#url
* @param {!Blob} blob
@@ -280,10 +285,10 @@ goog.html.DATA_URL_PATTERN_ = /^data:([^;,]*);base64,[a-z0-9+\/]+=*$/i;
/**
* Creates a SafeUrl wrapping a data: URL, after validating it matches a
- * known-safe image or video MIME type.
+ * known-safe audio, image or video MIME type.
*
* @param {string} dataUrl A valid base64 data URL with one of the whitelisted
- * image or video MIME types.
+ * audio, image or video MIME types.
* @return {!goog.html.SafeUrl} A matching safe URL, or {@link INNOCUOUS_STRING}
* wrapped as a SafeUrl if it does not pass.
*/
@@ -320,6 +325,19 @@ goog.html.SafeUrl.fromTelUrl = function(telUrl) {
/**
+ * 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) {
+ 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.
*
@@ -336,19 +354,11 @@ goog.html.SafeUrl.fromTelUrl = function(telUrl) {
* Otherwise, a colon after a double solidus (//) must be in the authority
* (before port).
*
- * The pattern disallows &, used in HTML entity declarations before
- * one of the characters in [/?#]. This disallows HTML entities used in the
- * protocol name, which should never happen, e.g. "h&#116;tp" for "http".
- * It also disallows HTML entities in the first path part of a relative path,
- * e.g. "foo&lt;bar/baz". Our existing escaping functions should not produce
- * that. More importantly, it disallows masking of a colon,
- * e.g. "javascript&#58;...".
- *
* @private
* @const {!RegExp}
*/
goog.html.SAFE_URL_PATTERN_ =
- /^(?:(?:https?|mailto|ftp):|[^&:/?#]*(?:[/?#]|$))/i;
+ /^(?:(?:https?|mailto|ftp):|[^:/?#]*(?:[/?#]|$))/i;
/**
@@ -378,6 +388,38 @@ goog.html.SafeUrl.sanitize = function(url) {
return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(url);
};
+/**
+ * Creates a SafeUrl object from {@code url}. If {@code 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.
+ *
+ * {@code 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 innocous URL will be
+ * returned.
+ *
+ * @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.sanitizeAssertUnchanged = function(url) {
+ if (url instanceof goog.html.SafeUrl) {
+ return url;
+ } else if (url.implementsGoogStringTypedString) {
+ url = url.getTypedStringValue();
+ } else {
+ url = String(url);
+ }
+ if (!goog.asserts.assert(goog.html.SAFE_URL_PATTERN_.test(url))) {
+ url = goog.html.SafeUrl.INNOCUOUS_STRING;
+ }
+ return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(url);
+};
+
+
/**
* Type marker for the SafeUrl type, used to implement additional run-time
diff --git a/assets/viz/2/goog/html/trustedresourceurl.js b/assets/viz/2/goog/html/trustedresourceurl.js
index 6e3c0df..c043ef1 100644
--- a/assets/viz/2/goog/html/trustedresourceurl.js
+++ b/assets/viz/2/goog/html/trustedresourceurl.js
@@ -40,10 +40,11 @@ goog.require('goog.string.TypedString');
* this type.
*
* Instances of this type must be created via the factory method,
- * ({@code goog.html.TrustedResourceUrl.fromConstant}), and not by invoking its
- * constructor. The constructor intentionally takes no parameters and the type
- * is immutable; hence only a default instance corresponding to the empty
- * string can be obtained via constructor invocation.
+ * ({@code fromConstant}, {@code fromConstants}, {@code format} or {@code
+ * formatWithParams}), and not by invoking its constructor. The constructor
+ * intentionally takes no parameters and the type is immutable; hence only a
+ * default instance corresponding to the empty string can be obtained via
+ * constructor invocation.
*
* @see goog.html.TrustedResourceUrl#fromConstant
* @constructor
@@ -64,7 +65,7 @@ goog.html.TrustedResourceUrl = function() {
/**
* A type marker used to implement additional run-time type checking.
* @see goog.html.TrustedResourceUrl#unwrap
- * @const
+ * @const {!Object}
* @private
*/
this.TRUSTED_RESOURCE_URL_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ =
@@ -179,6 +180,169 @@ goog.html.TrustedResourceUrl.unwrap = function(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 start with one of the following:
+ * - `https://<origin>/`
+ * - `//<origin>/`
+ * - `/<pathStart>`
+ * - `about:blank`
+ *
+ * `<origin>` must contain only alphanumeric or any of the following: `-.:[]`.
+ * `<pathStart>` is any character except `/` and `\`.
+ *
+ * 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.EMPTY : goog.string.Const.from('&autoplay=1')
+ * });
+ *
+ * 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) {
+ var result = goog.html.TrustedResourceUrl.format_(format, args);
+ return goog.html.TrustedResourceUrl
+ .createTrustedResourceUrlSecurityPrivateDoNotAccessOrElse(result);
+};
+
+
+/**
+ * String version of TrustedResourceUrl.format.
+ * @param {!goog.string.Const} format
+ * @param {!Object<string, (string|number|!goog.string.Const)>} args
+ * @return {string}
+ * @throws {!Error}
+ * @private
+ */
+goog.html.TrustedResourceUrl.format_ = function(format, args) {
+ var formatStr = goog.string.Const.unwrap(format);
+ if (!goog.html.TrustedResourceUrl.BASE_URL_.test(formatStr)) {
+ throw new Error('Invalid TrustedResourceUrl format: ' + formatStr);
+ }
+ return formatStr.replace(
+ goog.html.TrustedResourceUrl.FORMAT_MARKER_, function(match, id) {
+ 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));
+ }
+ });
+};
+
+
+/**
+ * @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.
+ * - / not followed by / or \. There will only be an absolute 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_ =
+ /^(?:https:)?\/\/[0-9a-z.:[\]-]+\/|^\/[^\/\\]|^about:blank(#|$)/i;
+
+
+/**
+ * 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 {!Object<string, *>} params Parameters to add to URL. Parameters with
+ * value {@code null} or {@code undefined} are skipped. Both keys and values
+ * are encoded. 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.
+ * @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, params) {
+ var url = goog.html.TrustedResourceUrl.format_(format, args);
+ var separator = /\?/.test(url) ? '&' : '?';
+ for (var key in params) {
+ if (params[key] == null) {
+ continue;
+ }
+ url += separator + encodeURIComponent(key) + '=' +
+ encodeURIComponent(String(params[key]));
+ separator = '&';
+ }
+ return goog.html.TrustedResourceUrl
+ .createTrustedResourceUrlSecurityPrivateDoNotAccessOrElse(url);
+};
+
+
+/**
* Creates a TrustedResourceUrl object from a compile-time constant string.
*
* Compile-time constant strings are inherently program-controlled and hence
diff --git a/assets/viz/2/goog/html/uncheckedconversions.js b/assets/viz/2/goog/html/uncheckedconversions.js
index 2cef322..e96697c 100644
--- a/assets/viz/2/goog/html/uncheckedconversions.js
+++ b/assets/viz/2/goog/html/uncheckedconversions.js
@@ -62,10 +62,6 @@ goog.require('goog.string.Const');
* unknown directionality.
* @return {!goog.html.SafeHtml} The value of html, wrapped in a SafeHtml
* object.
- * @suppress {visibility} For access to SafeHtml.create... Note that this
- * use is appropriate since this method is intended to be "package private"
- * within goog.html. DO NOT call SafeHtml.create... from outside this
- * package; use appropriate wrappers instead.
*/
goog.html.uncheckedconversions.safeHtmlFromStringKnownToSatisfyTypeContract =
function(justification, html, opt_dir) {
@@ -104,7 +100,7 @@ goog.html.uncheckedconversions.safeScriptFromStringKnownToSatisfyTypeContract =
goog.asserts.assertString(
goog.string.Const.unwrap(justification), 'must provide justification');
goog.asserts.assert(
- !goog.string.isEmpty(goog.string.Const.unwrap(justification)),
+ !goog.string.isEmptyOrWhitespace(goog.string.Const.unwrap(justification)),
'must provide non-empty justification');
return goog.html.SafeScript.createSafeScriptSecurityPrivateDoNotAccessOrElse(
script);
@@ -116,7 +112,7 @@ goog.html.uncheckedconversions.safeScriptFromStringKnownToSatisfyTypeContract =
* known to satisfy the SafeStyle type contract.
*
* IMPORTANT: Uses of this method must be carefully security-reviewed to ensure
- * that the value of {@code style} satisfies the SafeUrl type contract in all
+ * that the value of {@code style} satisfies the SafeStyle type contract in all
* possible program states.
*
*
@@ -146,8 +142,8 @@ goog.html.uncheckedconversions.safeStyleFromStringKnownToSatisfyTypeContract =
* 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 {@code styleSheet} satisfies the SafeUrl type contract in
- * all possible program states.
+ * that the value of {@code styleSheet} satisfies the SafeStyleSheet type
+ * contract in all possible program states.
*
*
* @param {!goog.string.Const} justification A constant string explaining why