@apache-royale/royale-js
Version:
Apache Royale (formerly FlexJS)
287 lines (233 loc) • 10.3 kB
JavaScript
// Copyright 2013 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @fileoverview Unit tests for goog.html.SafeUrl and its builders.
*/
goog.provide('goog.html.safeUrlTest');
goog.require('goog.html.SafeUrl');
goog.require('goog.html.TrustedResourceUrl');
goog.require('goog.html.safeUrlTestVectors');
goog.require('goog.i18n.bidi.Dir');
goog.require('goog.object');
goog.require('goog.string.Const');
goog.require('goog.testing.jsunit');
goog.require('goog.userAgent');
goog.setTestOnly('goog.html.safeUrlTest');
function testSafeUrl() {
var safeUrl = goog.html.SafeUrl.fromConstant(
goog.string.Const.from('javascript:trusted();'));
var extracted = goog.html.SafeUrl.unwrap(safeUrl);
assertEquals('javascript:trusted();', extracted);
assertEquals('javascript:trusted();', goog.html.SafeUrl.unwrap(safeUrl));
assertEquals('SafeUrl{javascript:trusted();}', String(safeUrl));
// URLs are always LTR.
assertEquals(goog.i18n.bidi.Dir.LTR, safeUrl.getDirection());
// Interface markers are present.
assertTrue(safeUrl.implementsGoogStringTypedString);
assertTrue(safeUrl.implementsGoogI18nBidiDirectionalString);
}
function testSafeUrlFromBlob_withSafeType() {
if (isIE9OrLower()) {
return;
}
assertBlobTypeIsSafe('audio/ogg', true);
assertBlobTypeIsSafe('image/png', true);
assertBlobTypeIsSafe('iMage/pNg', true);
assertBlobTypeIsSafe('video/mpeg', true);
assertBlobTypeIsSafe('video/ogg', true);
assertBlobTypeIsSafe('video/mp4', true);
assertBlobTypeIsSafe('video/ogg', true);
assertBlobTypeIsSafe('video/webm', true);
assertBlobTypeIsSafe('video/quicktime', true);
}
function testSafeUrlFromBlob_withUnsafeType() {
if (isIE9OrLower()) {
return;
}
assertBlobTypeIsSafe('', false);
assertBlobTypeIsSafe('ximage/png', false);
assertBlobTypeIsSafe('image/pngx', false);
assertBlobTypeIsSafe('video/whatever', false);
assertBlobTypeIsSafe('video/', false);
}
/** @return {boolean} True if running on IE9 or lower. */
function isIE9OrLower() {
return goog.userAgent.IE && !goog.userAgent.isVersionOrHigher('10');
}
/**
* Tests creating a SafeUrl from a blob with the given MIME type, asserting
* whether or not the SafeUrl returned is innocuous or not depending on the
* given boolean.
* @param {string} type MIME type to test
* @param {boolean} isSafe Whether the given MIME type should be considered safe
* by {@link SafeUrl.fromBlob}.
*/
function assertBlobTypeIsSafe(type, isSafe) {
var safeUrl = goog.html.SafeUrl.fromBlob(new Blob(['test'], {type: type}));
var extracted = goog.html.SafeUrl.unwrap(safeUrl);
if (isSafe) {
assertEquals('blob:', extracted.substring(0, 5));
} else {
assertEquals(goog.html.SafeUrl.INNOCUOUS_STRING, extracted);
}
}
function testSafeUrlSanitize_sanitizeTelUrl() {
var vectors = goog.html.safeUrlTestVectors.TEL_VECTORS;
for (var i = 0; i < vectors.length; ++i) {
var v = vectors[i];
var observed = goog.html.SafeUrl.fromTelUrl(v.input);
assertEquals(v.expected, goog.html.SafeUrl.unwrap(observed));
}
}
function testSafeUrlSanitize_sipUrlEmail() {
var expected = 'sip:username@example.com';
var observed = goog.html.SafeUrl.fromSipUrl('sip:username@example.com');
assertEquals(expected, goog.html.SafeUrl.unwrap(observed));
}
function testSafeUrlSanitize_sipsUrlEmail() {
var expected = 'sips:username@example.com';
var observed = goog.html.SafeUrl.fromSipUrl('sips:username@example.com');
assertEquals(expected, goog.html.SafeUrl.unwrap(observed));
}
function testSafeUrlSanitize_sipProtocolCase() {
var expected = 'Sip:username@example.com';
var observed = goog.html.SafeUrl.fromSipUrl('Sip:username@example.com');
assertEquals(expected, goog.html.SafeUrl.unwrap(observed));
}
function testSafeUrlSanitize_sipUrlWithPort() {
var observed = goog.html.SafeUrl.fromSipUrl('sip:username@example.com:5000');
assertEquals('about:invalid#zClosurez', goog.html.SafeUrl.unwrap(observed));
}
function testSafeUrlSanitize_sipUrlFragment() {
var observed = goog.html.SafeUrl.fromSipUrl('sip:user#name@example.com');
assertEquals('about:invalid#zClosurez', goog.html.SafeUrl.unwrap(observed));
}
function testSafeUrlSanitize_sipUrlWithPassword() {
var observed =
goog.html.SafeUrl.fromSipUrl('sips:username:password@example.com');
assertEquals('about:invalid#zClosurez', goog.html.SafeUrl.unwrap(observed));
}
function testSafeUrlSanitize_sipUrlWithOptions() {
var observed = goog.html.SafeUrl.fromSipUrl('sips:user;na=me@example.com');
assertEquals('about:invalid#zClosurez', goog.html.SafeUrl.unwrap(observed));
}
function testSafeUrlSanitize_sipUrlWithPercent() {
var observed = goog.html.SafeUrl.fromSipUrl('sip:user%40name@example.com');
assertEquals('about:invalid#zClosurez', goog.html.SafeUrl.unwrap(observed));
}
function testSafeUrlSanitize_sipUrlWithAmbiguousQuery() {
var observed = goog.html.SafeUrl.fromSipUrl('sip:user?name@example.com');
assertEquals('about:invalid#zClosurez', goog.html.SafeUrl.unwrap(observed));
}
function testSafeUrlSanitize_sanitizeSmsUrl() {
var vectors = goog.html.safeUrlTestVectors.SMS_VECTORS;
for (var i = 0; i < vectors.length; ++i) {
var v = vectors[i];
var observed = goog.html.SafeUrl.fromSmsUrl(v.input);
assertEquals(v.expected, goog.html.SafeUrl.unwrap(observed));
}
}
function testFromTrustedResourceUrl() {
var url = goog.string.Const.from('test');
var trustedResourceUrl = goog.html.TrustedResourceUrl.fromConstant(url);
var safeUrl = goog.html.SafeUrl.fromTrustedResourceUrl(trustedResourceUrl);
assertEquals(
goog.string.Const.unwrap(url), goog.html.SafeUrl.unwrap(safeUrl));
}
/** @suppress {checkTypes} */
function testUnwrap() {
var privateFieldName = 'privateDoNotAccessOrElseSafeHtmlWrappedValue_';
var markerFieldName = 'SAFE_URL_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_';
var propNames = goog.object.getKeys(goog.html.SafeUrl.sanitize(''));
assertContains(privateFieldName, propNames);
assertContains(markerFieldName, propNames);
var evil = {};
evil[privateFieldName] = 'javascript:evil()';
evil[markerFieldName] = {};
var exception = assertThrows(function() { goog.html.SafeUrl.unwrap(evil); });
assertContains('expected object of type SafeUrl', exception.message);
}
function testSafeUrlSanitize_sanitizeUrl() {
var vectors = goog.html.safeUrlTestVectors.BASE_VECTORS;
for (var i = 0; i < vectors.length; ++i) {
var v = vectors[i];
if (v.input.match(/^data:/i)) {
var observed = goog.html.SafeUrl.fromDataUrl(v.input);
assertEquals(v.expected, goog.html.SafeUrl.unwrap(observed));
} else {
var observed = goog.html.SafeUrl.sanitize(v.input);
assertEquals(v.expected, goog.html.SafeUrl.unwrap(observed));
if (v.safe) {
var asserted = goog.html.SafeUrl.sanitizeAssertUnchanged(v.input);
assertEquals(v.expected, goog.html.SafeUrl.unwrap(asserted));
} else {
assertThrows(function() {
goog.html.SafeUrl.sanitizeAssertUnchanged(v.input);
});
}
}
}
}
function testSafeUrlSanitize_sanitizeProgramConstants() {
// .sanitize() works on program constants.
var good = goog.string.Const.from('http://example.com/');
var goodOutput = goog.html.SafeUrl.sanitize(good);
assertEquals('http://example.com/', goog.html.SafeUrl.unwrap(goodOutput));
var asserted = goog.html.SafeUrl.sanitizeAssertUnchanged(good);
assertEquals('http://example.com/', goog.html.SafeUrl.unwrap(asserted));
// .sanitize() does not exempt values known to be program constants.
var bad = goog.string.Const.from('data:blah');
var badOutput = goog.html.SafeUrl.sanitize(bad);
assertEquals('about:invalid#zClosurez', goog.html.SafeUrl.unwrap(badOutput));
assertThrows(function() {
goog.html.SafeUrl.sanitizeAssertUnchanged(bad);
});
}
function testSafeUrlSanitize_sanitizePlainStringWithTypedStringProperty() {
// .sanitize() works on plain strings with property that wrongly indicates
// that the text is of a type that implements `goog.string.TypedString`. This
// simulates a property renaming collision with a String property set
// externally (b/80124112).
var plainString = 'http://example.com/';
plainString.implementsGoogStringTypedString = true;
var output = goog.html.SafeUrl.sanitize(plainString);
assertEquals('http://example.com/', goog.html.SafeUrl.unwrap(output));
var asserted = goog.html.SafeUrl.sanitizeAssertUnchanged(plainString);
assertEquals('http://example.com/', goog.html.SafeUrl.unwrap(asserted));
}
function testSafeUrlSanitize_idempotentForSafeUrlArgument() {
// This matches the safe prefix.
var safeUrl = goog.html.SafeUrl.sanitize('https://www.google.com/');
var safeUrl2 = goog.html.SafeUrl.sanitize(safeUrl);
assertEquals(
goog.html.SafeUrl.unwrap(safeUrl), goog.html.SafeUrl.unwrap(safeUrl2));
// This doesn't match the safe prefix, getting converted into an innocuous
// string.
safeUrl = goog.html.SafeUrl.sanitize('disallowed:foo');
safeUrl2 = goog.html.SafeUrl.sanitize(safeUrl);
assertEquals(
goog.html.SafeUrl.unwrap(safeUrl), goog.html.SafeUrl.unwrap(safeUrl2));
}
function testSafeUrlSanitize_base64ImageSrc() {
var dataUrl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAT4AAA';
var safeUrl = goog.html.SafeUrl.fromDataUrl(dataUrl);
assertEquals(goog.html.SafeUrl.unwrap(safeUrl), dataUrl);
}
function testSafeUrlSanitize_base64ImageSrcWithCRLF() {
var dataUrl = 'data:image/png;base64,iVBORw0KGgoA%0AAAANSUhEUgA%0DAAT4AAA%0A';
var safeUrl = goog.html.SafeUrl.fromDataUrl(dataUrl);
assertEquals(
goog.html.SafeUrl.unwrap(safeUrl),
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAT4AAA');
}