123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233 |
- // Copyright 2014 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- var logging = requireNative('logging');
- /**
- * Returns a function that logs a 'not available' error to the console and
- * returns undefined.
- *
- * @param {string} messagePrefix text to prepend to the exception message.
- */
- function generateDisabledMethodStub(messagePrefix, opt_messageSuffix) {
- var message = messagePrefix + ' is not available in packaged apps.';
- if (opt_messageSuffix) message = message + ' ' + opt_messageSuffix;
- return function() {
- console.error(message);
- return;
- };
- }
- /**
- * Returns a function that throws a 'not available' error.
- *
- * @param {string} messagePrefix text to prepend to the exception message.
- */
- function generateThrowingMethodStub(messagePrefix, opt_messageSuffix) {
- var message = messagePrefix + ' is not available in packaged apps.';
- if (opt_messageSuffix) message = message + ' ' + opt_messageSuffix;
- return function() {
- throw new Error(message);
- };
- }
- /**
- * Replaces the given methods of the passed in object with stubs that log
- * 'not available' errors to the console and return undefined.
- *
- * This should be used on methods attached via non-configurable properties,
- * such as window.alert. disableGetters should be used when possible, because
- * it is friendlier towards feature detection.
- *
- * In most cases, the useThrowingStubs should be false, so the stubs used to
- * replace the methods log an error to the console, but allow the calling code
- * to continue. We shouldn't break library code that uses feature detection
- * responsibly, such as:
- * if(window.confirm) {
- * var result = window.confirm('Are you sure you want to delete ...?');
- * ...
- * }
- *
- * useThrowingStubs should only be true for methods that are deprecated in the
- * Web platform, and should not be used by a responsible library, even in
- * conjunction with feature detection. A great example is document.write(), as
- * the HTML5 specification recommends against using it, and says that its
- * behavior is unreliable. No reasonable library code should ever use it.
- * HTML5 spec: http://www.w3.org/TR/html5/dom.html#dom-document-write
- *
- * @param {Object} object The object with methods to disable. The prototype is
- * preferred.
- * @param {string} objectName The display name to use in the error message
- * thrown by the stub (this is the name that the object is commonly referred
- * to by web developers, e.g. "document" instead of "HTMLDocument").
- * @param {Array<string>} methodNames names of methods to disable.
- * @param {Boolean} useThrowingStubs if true, the replaced methods will throw
- * an error instead of silently returning undefined
- */
- function disableMethods(object, objectName, methodNames, useThrowingStubs) {
- $Array.forEach(methodNames, function(methodName) {
- logging.DCHECK($Object.getOwnPropertyDescriptor(object, methodName),
- objectName + ': ' + methodName);
- var messagePrefix = objectName + '.' + methodName + '()';
- $Object.defineProperty(object, methodName, {
- configurable: false,
- enumerable: false,
- value: useThrowingStubs ?
- generateThrowingMethodStub(messagePrefix) :
- generateDisabledMethodStub(messagePrefix)
- });
- });
- }
- /**
- * Replaces the given properties of the passed in object with stubs that log
- * 'not available' warnings to the console and return undefined when gotten. If
- * a property's setter is later invoked, the getter and setter are restored to
- * default behaviors.
- *
- * @param {Object} object The object with properties to disable. The prototype
- * is preferred.
- * @param {string} objectName The display name to use in the error message
- * thrown by the getter stub (this is the name that the object is commonly
- * referred to by web developers, e.g. "document" instead of
- * "HTMLDocument").
- * @param {Array<string>} propertyNames names of properties to disable.
- * @param {?string=} opt_messageSuffix An optional suffix for the message.
- * @param {boolean=} opt_ignoreMissingProperty True if we allow disabling
- * getters for non-existent properties.
- */
- function disableGetters(object, objectName, propertyNames, opt_messageSuffix,
- opt_ignoreMissingProperty) {
- $Array.forEach(propertyNames, function(propertyName) {
- logging.DCHECK(opt_ignoreMissingProperty ||
- $Object.getOwnPropertyDescriptor(object, propertyName),
- objectName + ': ' + propertyName);
- var stub = generateDisabledMethodStub(objectName + '.' + propertyName,
- opt_messageSuffix);
- stub._is_platform_app_disabled_getter = true;
- $Object.defineProperty(object, propertyName, {
- configurable: true,
- enumerable: false,
- get: stub,
- set: function(value) {
- var descriptor = $Object.getOwnPropertyDescriptor(this, propertyName);
- if (!descriptor || !descriptor.get ||
- descriptor.get._is_platform_app_disabled_getter) {
- // The stub getter is still defined. Blow-away the property to
- // restore default getter/setter behaviors and re-create it with the
- // given value.
- delete this[propertyName];
- this[propertyName] = value;
- } else {
- // Do nothing. If some custom getter (not ours) has been defined,
- // there would be no way to read back the value stored by a default
- // setter. Also, the only way to clear a custom getter is to first
- // delete the property. Therefore, the value we have here should
- // just go into a black hole.
- }
- }
- });
- });
- }
- /**
- * Replaces the given properties of the passed in object with stubs that log
- * 'not available' warnings to the console when set.
- *
- * @param {Object} object The object with properties to disable. The prototype
- * is preferred.
- * @param {string} objectName The display name to use in the error message
- * thrown by the setter stub (this is the name that the object is commonly
- * referred to by web developers, e.g. "document" instead of
- * "HTMLDocument").
- * @param {Array<string>} propertyNames names of properties to disable.
- */
- function disableSetters(object, objectName, propertyNames, opt_messageSuffix) {
- $Array.forEach(propertyNames, function(propertyName) {
- logging.DCHECK($Object.getOwnPropertyDescriptor(object, propertyName),
- objectName + ': ' + propertyName);
- var stub = generateDisabledMethodStub(objectName + '.' + propertyName,
- opt_messageSuffix);
- $Object.defineProperty(object, propertyName, {
- configurable: false,
- enumerable: false,
- get: function() {
- return;
- },
- set: stub
- });
- });
- }
- // Disable benign Document methods.
- disableMethods(Document.prototype, 'document', ['open', 'close']);
- disableMethods(Document.prototype, 'document', ['clear']);
- // Replace evil Document methods with exception-throwing stubs.
- disableMethods(Document.prototype, 'document', ['write', 'writeln'], true);
- // Disable history.
- Object.defineProperty(window, "history", { value: {} });
- // Note: we just blew away the history object, so we need to ignore the fact
- // that these properties aren't defined on the object.
- disableGetters(window.history, 'history',
- ['back', 'forward', 'go', 'length', 'pushState', 'replaceState', 'state'],
- null, true);
- // Disable find.
- disableMethods(window, 'window', ['find']);
- // Disable modal dialogs. Shell windows disable these anyway, but it's nice to
- // warn.
- disableMethods(window, 'window', ['alert', 'confirm', 'prompt']);
- // Disable window.*bar.
- disableGetters(window, 'window',
- ['locationbar', 'menubar', 'personalbar', 'scrollbars', 'statusbar',
- 'toolbar']);
- // Disable window.localStorage.
- // Sometimes DOM security policy prevents us from doing this (e.g. for data:
- // URLs) so wrap in try-catch.
- try {
- disableGetters(window, 'window',
- ['localStorage'],
- 'Use chrome.storage.local instead.');
- } catch (e) {}
- function disableDeprectatedDocumentFunction() {
- // Deprecated document properties from
- // https://developer.mozilla.org/en/DOM/document.
- // Disable document.all so that platform apps can not access.
- delete Document.prototype.all
- disableGetters(document, 'document',
- ['alinkColor', 'all', 'bgColor', 'fgColor', 'linkColor', 'vlinkColor'],
- null, true);
- }
- // The new document may or may not already have been created when this script is
- // executed. In the second case, the current document is still the initial empty
- // document. There are no way to know whether 'document' refers to the old one
- // or the new one. That's why, the deprecated document properties needs to be
- // disabled on the current document and potentially on the new one, if it gets
- // created.
- disableDeprectatedDocumentFunction();
- window.addEventListener('readystatechange', function(event) {
- if (document.readyState == 'loading')
- disableDeprectatedDocumentFunction();
- }, true);
- // Disable onunload, onbeforeunload.
- disableSetters(window, 'window', ['onbeforeunload', 'onunload']);
- var eventTargetAddEventListener = EventTarget.prototype.addEventListener;
- EventTarget.prototype.addEventListener = function(type) {
- var args = $Array.slice(arguments);
- // Note: Force conversion to a string in order to catch any funny attempts
- // to pass in something that evals to 'unload' but wouldn't === 'unload'.
- var type = (args[0] += '');
- if (type === 'unload' || type === 'beforeunload')
- generateDisabledMethodStub(type)();
- else
- return $Function.apply(eventTargetAddEventListener, this, args);
- };
|