Path: blob/trunk/third_party/closure/goog/html/trustedresourceurl.js
2868 views
// Copyright 2013 The Closure Library Authors. All Rights Reserved.1//2// Licensed under the Apache License, Version 2.0 (the "License");3// you may not use this file except in compliance with the License.4// You may obtain a copy of the License at5//6// http://www.apache.org/licenses/LICENSE-2.07//8// Unless required by applicable law or agreed to in writing, software9// distributed under the License is distributed on an "AS-IS" BASIS,10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.11// See the License for the specific language governing permissions and12// limitations under the License.1314/**15* @fileoverview The TrustedResourceUrl type and its builders.16*17* TODO(xtof): Link to document stating type contract.18*/1920goog.provide('goog.html.TrustedResourceUrl');2122goog.require('goog.asserts');23goog.require('goog.i18n.bidi.Dir');24goog.require('goog.i18n.bidi.DirectionalString');25goog.require('goog.string.Const');26goog.require('goog.string.TypedString');27282930/**31* A URL which is under application control and from which script, CSS, and32* other resources that represent executable code, can be fetched.33*34* Given that the URL can only be constructed from strings under application35* control and is used to load resources, bugs resulting in a malformed URL36* should not have a security impact and are likely to be easily detectable37* during testing. Given the wide number of non-RFC compliant URLs in use,38* stricter validation could prevent some applications from being able to use39* this type.40*41* Instances of this type must be created via the factory method,42* ({@code goog.html.TrustedResourceUrl.fromConstant}), and not by invoking its43* constructor. The constructor intentionally takes no parameters and the type44* is immutable; hence only a default instance corresponding to the empty45* string can be obtained via constructor invocation.46*47* @see goog.html.TrustedResourceUrl#fromConstant48* @constructor49* @final50* @struct51* @implements {goog.i18n.bidi.DirectionalString}52* @implements {goog.string.TypedString}53*/54goog.html.TrustedResourceUrl = function() {55/**56* The contained value of this TrustedResourceUrl. The field has a purposely57* ugly name to make (non-compiled) code that attempts to directly access this58* field stand out.59* @private {string}60*/61this.privateDoNotAccessOrElseTrustedResourceUrlWrappedValue_ = '';6263/**64* A type marker used to implement additional run-time type checking.65* @see goog.html.TrustedResourceUrl#unwrap66* @const {!Object}67* @private68*/69this.TRUSTED_RESOURCE_URL_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ =70goog.html.TrustedResourceUrl.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_;71};727374/**75* @override76* @const77*/78goog.html.TrustedResourceUrl.prototype.implementsGoogStringTypedString = true;798081/**82* Returns this TrustedResourceUrl's value as a string.83*84* IMPORTANT: In code where it is security relevant that an object's type is85* indeed {@code TrustedResourceUrl}, use86* {@code goog.html.TrustedResourceUrl.unwrap} instead of this method. If in87* doubt, assume that it's security relevant. In particular, note that88* goog.html functions which return a goog.html type do not guarantee that89* the returned instance is of the right type. For example:90*91* <pre>92* var fakeSafeHtml = new String('fake');93* fakeSafeHtml.__proto__ = goog.html.SafeHtml.prototype;94* var newSafeHtml = goog.html.SafeHtml.htmlEscape(fakeSafeHtml);95* // newSafeHtml is just an alias for fakeSafeHtml, it's passed through by96* // goog.html.SafeHtml.htmlEscape() as fakeSafeHtml instanceof97* // goog.html.SafeHtml.98* </pre>99*100* @see goog.html.TrustedResourceUrl#unwrap101* @override102*/103goog.html.TrustedResourceUrl.prototype.getTypedStringValue = function() {104return this.privateDoNotAccessOrElseTrustedResourceUrlWrappedValue_;105};106107108/**109* @override110* @const111*/112goog.html.TrustedResourceUrl.prototype.implementsGoogI18nBidiDirectionalString =113true;114115116/**117* Returns this URLs directionality, which is always {@code LTR}.118* @override119*/120goog.html.TrustedResourceUrl.prototype.getDirection = function() {121return goog.i18n.bidi.Dir.LTR;122};123124125if (goog.DEBUG) {126/**127* Returns a debug string-representation of this value.128*129* To obtain the actual string value wrapped in a TrustedResourceUrl, use130* {@code goog.html.TrustedResourceUrl.unwrap}.131*132* @see goog.html.TrustedResourceUrl#unwrap133* @override134*/135goog.html.TrustedResourceUrl.prototype.toString = function() {136return 'TrustedResourceUrl{' +137this.privateDoNotAccessOrElseTrustedResourceUrlWrappedValue_ + '}';138};139}140141142/**143* Performs a runtime check that the provided object is indeed a144* TrustedResourceUrl object, and returns its value.145*146* @param {!goog.html.TrustedResourceUrl} trustedResourceUrl The object to147* extract from.148* @return {string} The trustedResourceUrl object's contained string, unless149* the run-time type check fails. In that case, {@code unwrap} returns an150* innocuous string, or, if assertions are enabled, throws151* {@code goog.asserts.AssertionError}.152*/153goog.html.TrustedResourceUrl.unwrap = function(trustedResourceUrl) {154// Perform additional Run-time type-checking to ensure that155// trustedResourceUrl is indeed an instance of the expected type. This156// provides some additional protection against security bugs due to157// application code that disables type checks.158// Specifically, the following checks are performed:159// 1. The object is an instance of the expected type.160// 2. The object is not an instance of a subclass.161// 3. The object carries a type marker for the expected type. "Faking" an162// object requires a reference to the type marker, which has names intended163// to stand out in code reviews.164if (trustedResourceUrl instanceof goog.html.TrustedResourceUrl &&165trustedResourceUrl.constructor === goog.html.TrustedResourceUrl &&166trustedResourceUrl167.TRUSTED_RESOURCE_URL_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ ===168goog.html.TrustedResourceUrl169.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_) {170return trustedResourceUrl171.privateDoNotAccessOrElseTrustedResourceUrlWrappedValue_;172} else {173goog.asserts.fail('expected object of type TrustedResourceUrl, got \'' +174trustedResourceUrl + '\' of type ' + goog.typeOf(trustedResourceUrl));175return 'type_error:TrustedResourceUrl';176}177};178179180/**181* Creates a TrustedResourceUrl from a format string and arguments.182*183* The arguments for interpolation into the format string map labels to values.184* Values of type `goog.string.Const` are interpolated without modifcation.185* Values of other types are cast to string and encoded with186* encodeURIComponent.187*188* `%{<label>}` markers are used in the format string to indicate locations189* to be interpolated with the valued mapped to the given label. `<label>`190* must contain only alphanumeric and `_` characters.191*192* The format string must start with one of the following:193* - `https://<origin>/`194* - `//<origin>/`195* - `/<pathStart>`196* - `about:blank`197*198* `<origin>` must contain only alphanumeric or any of the following: `-.:[]`.199* `<pathStart>` is any character except `/` and `\`.200*201* Example usage:202*203* var url = goog.html.TrustedResourceUrl.format(goog.string.Const.from(204* 'https://www.google.com/search?q=%{query}), {'query': searchTerm});205*206* var url = goog.html.TrustedResourceUrl.format(goog.string.Const.from(207* '//www.youtube.com/v/%{videoId}?hl=en&fs=1%{autoplay}'), {208* 'videoId': videoId,209* 'autoplay': opt_autoplay ?210* goog.string.Const.EMPTY : goog.string.Const.from('autoplay=1')211* });212*213* While this function can be used to create a TrustedResourceUrl from only214* constants, fromConstant() and fromConstants() are generally preferable for215* that purpose.216*217* @param {!goog.string.Const} format The format string.218* @param {!Object<string, (string|number|!goog.string.Const)>} args Mapping219* of labels to values to be interpolated into the format string.220* goog.string.Const values are interpolated without encoding.221* @return {!goog.html.TrustedResourceUrl}222* @throws {!Error} On an invalid format string or if a label used in the223* the format string is not present in args.224*225*/226goog.html.TrustedResourceUrl.format = function(format, args) {227var formatStr = goog.string.Const.unwrap(format);228if (!goog.html.TrustedResourceUrl.BASE_URL_.test(formatStr)) {229throw new Error('Invalid TrustedResourceUrl format: ' + formatStr);230}231var result = formatStr.replace(232goog.html.TrustedResourceUrl.FORMAT_MARKER_, function(match, id) {233if (!Object.prototype.hasOwnProperty.call(args, id)) {234throw new Error(235'Found marker, "' + id + '", in format string, "' + formatStr +236'", but no valid label mapping found ' +237'in args: ' + JSON.stringify(args));238}239var arg = args[id];240if (arg instanceof goog.string.Const) {241return goog.string.Const.unwrap(arg);242} else {243return encodeURIComponent(String(arg));244}245});246return goog.html.TrustedResourceUrl247.createTrustedResourceUrlSecurityPrivateDoNotAccessOrElse(result);248};249250251/**252* @private @const {!RegExp}253*/254goog.html.TrustedResourceUrl.FORMAT_MARKER_ = /%{(\w+)}/g;255256257/**258* The URL must be absolute, scheme-relative or path-absolute. So it must259* start with:260* - https:// followed by allowed origin characters.261* - // followed by allowed origin characters.262* - / not followed by / or \. There will only be an absolute path.263*264* Based on265* https://url.spec.whatwg.org/commit-snapshots/56b74ce7cca8883eab62e9a12666e2fac665d03d/#url-parsing266* an initial / which is not followed by another / or \ will end up in the "path267* state" and from there it can only go to "fragment state" and "query state".268*269* We don't enforce a well-formed domain name. So '.' or '1.2' are valid.270* That's ok because the origin comes from a compile-time constant.271*272* A regular expression is used instead of goog.uri for several reasons:273* - Strictness. E.g. we don't want any userinfo component and we don't274* want '/./, nor \' in the first path component.275* - Small trusted base. goog.uri is generic and might need to change,276* reasoning about all the ways it can parse a URL now and in the future277* is error-prone.278* - Code size. We expect many calls to .format(), many of which might279* not be using goog.uri.280* - Simplicity. Using goog.uri would likely not result in simpler nor shorter281* code.282* @private @const {!RegExp}283*/284goog.html.TrustedResourceUrl.BASE_URL_ =285/^(?:https:)?\/\/[0-9a-z.:[\]-]+\/|^\/[^\/\\]|^about:blank(#|$)/i;286287288/**289* Creates a TrustedResourceUrl object from a compile-time constant string.290*291* Compile-time constant strings are inherently program-controlled and hence292* trusted.293*294* @param {!goog.string.Const} url A compile-time-constant string from which to295* create a TrustedResourceUrl.296* @return {!goog.html.TrustedResourceUrl} A TrustedResourceUrl object297* initialized to {@code url}.298*/299goog.html.TrustedResourceUrl.fromConstant = function(url) {300return goog.html.TrustedResourceUrl301.createTrustedResourceUrlSecurityPrivateDoNotAccessOrElse(302goog.string.Const.unwrap(url));303};304305306/**307* Creates a TrustedResourceUrl object from a compile-time constant strings.308*309* Compile-time constant strings are inherently program-controlled and hence310* trusted.311*312* @param {!Array<!goog.string.Const>} parts Compile-time-constant strings from313* which to create a TrustedResourceUrl.314* @return {!goog.html.TrustedResourceUrl} A TrustedResourceUrl object315* initialized to concatenation of {@code parts}.316*/317goog.html.TrustedResourceUrl.fromConstants = function(parts) {318var unwrapped = '';319for (var i = 0; i < parts.length; i++) {320unwrapped += goog.string.Const.unwrap(parts[i]);321}322return goog.html.TrustedResourceUrl323.createTrustedResourceUrlSecurityPrivateDoNotAccessOrElse(unwrapped);324};325326327/**328* Type marker for the TrustedResourceUrl type, used to implement additional329* run-time type checking.330* @const {!Object}331* @private332*/333goog.html.TrustedResourceUrl.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ = {};334335336/**337* Package-internal utility method to create TrustedResourceUrl instances.338*339* @param {string} url The string to initialize the TrustedResourceUrl object340* with.341* @return {!goog.html.TrustedResourceUrl} The initialized TrustedResourceUrl342* object.343* @package344*/345goog.html.TrustedResourceUrl346.createTrustedResourceUrlSecurityPrivateDoNotAccessOrElse = function(url) {347var trustedResourceUrl = new goog.html.TrustedResourceUrl();348trustedResourceUrl.privateDoNotAccessOrElseTrustedResourceUrlWrappedValue_ =349url;350return trustedResourceUrl;351};352353354