| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 var $console = window.console; |
| 6 |
| 5 /** | 7 /** |
| 6 * Returns a function that throws a 'not available' exception when called. | 8 * Returns a function that logs a 'not available' error to the console and |
| 9 * returns undefined. |
| 7 * | 10 * |
| 8 * @param {string} messagePrefix text to prepend to the exception message. | 11 * @param {string} messagePrefix text to prepend to the exception message. |
| 9 */ | 12 */ |
| 10 function generateDisabledMethodStub(messagePrefix, opt_messageSuffix) { | 13 function generateDisabledMethodStub(messagePrefix, opt_messageSuffix) { |
| 14 var message = messagePrefix + ' is not available in packaged apps.'; |
| 15 if (opt_messageSuffix) message = message + ' ' + opt_messageSuffix; |
| 11 return function() { | 16 return function() { |
| 12 var message = messagePrefix + ' is not available in packaged apps.'; | 17 $console.error(message); |
| 13 if (opt_messageSuffix) message = message + ' ' + opt_messageSuffix; | 18 return; |
| 14 throw message; | |
| 15 }; | 19 }; |
| 16 } | 20 } |
| 17 | 21 |
| 18 /** | 22 /** |
| 19 * Replaces the given methods of the passed in object with stubs that throw | 23 * Returns a function that throws a 'not available' error. |
| 20 * 'not available' exceptions when called. | 24 * |
| 25 * @param {string} messagePrefix text to prepend to the exception message. |
| 26 */ |
| 27 function generateThrowingMethodStub(messagePrefix, opt_messageSuffix) { |
| 28 var message = messagePrefix + ' is not available in packaged apps.'; |
| 29 if (opt_messageSuffix) message = message + ' ' + opt_messageSuffix; |
| 30 return function() { |
| 31 throw new Error(message); |
| 32 }; |
| 33 } |
| 34 |
| 35 /** |
| 36 * Replaces the given methods of the passed in object with stubs that log |
| 37 * 'not available' errors to the console and return undefined. |
| 38 * |
| 39 * This should be used on methods attached via non-configurable properties, |
| 40 * such as window.alert. disableGetters should be used when possible, because |
| 41 * it is friendlier towards feature detection. |
| 42 * |
| 43 * In most cases, the useThrowingStubs should be false, so the stubs used to |
| 44 * replace the methods log an error to the console, but allow the calling code |
| 45 * to continue. We shouldn't break library code that uses feature detection |
| 46 * responsibly, such as: |
| 47 * if(window.confirm) { |
| 48 * var result = window.confirm('Are you sure you want to delete ...?'); |
| 49 * ... |
| 50 * } |
| 51 * |
| 52 * useThrowingStubs should only be true for methods that are deprecated in the |
| 53 * Web platform, and should not be used by a responsible library, even in |
| 54 * conjunction with feature detection. A great example is document.write(), as |
| 55 * the HTML5 specification recommends against using it, and says that its |
| 56 * behavior is unreliable. No reasonable library code should ever use it. |
| 57 * HTML5 spec: http://www.w3.org/TR/html5/dom.html#dom-document-write |
| 21 * | 58 * |
| 22 * @param {Object} object The object with methods to disable. The prototype is | 59 * @param {Object} object The object with methods to disable. The prototype is |
| 23 * preferred. | 60 * preferred. |
| 24 * @param {string} objectName The display name to use in the error message | 61 * @param {string} objectName The display name to use in the error message |
| 25 * thrown by the stub (this is the name that the object is commonly referred | 62 * thrown by the stub (this is the name that the object is commonly referred |
| 26 * to by web developers, e.g. "document" instead of "HTMLDocument"). | 63 * to by web developers, e.g. "document" instead of "HTMLDocument"). |
| 27 * @param {Array.<string>} methodNames names of methods to disable. | 64 * @param {Array.<string>} methodNames names of methods to disable. |
| 65 * @param {Boolean} useThrowingStubs if true, the replaced methods will throw |
| 66 * an error instead of silently returning undefined |
| 28 */ | 67 */ |
| 29 function disableMethods(object, objectName, methodNames) { | 68 function disableMethods(object, objectName, methodNames, useThrowingStubs) { |
| 30 $Array.forEach(methodNames, function(methodName) { | 69 $Array.forEach(methodNames, function(methodName) { |
| 31 object[methodName] = | 70 var messagePrefix = objectName + '.' + methodName + '()'; |
| 32 generateDisabledMethodStub(objectName + '.' + methodName + '()'); | 71 object[methodName] = useThrowingStubs ? |
| 72 generateThrowingMethodStub(messagePrefix) : |
| 73 generateDisabledMethodStub(messagePrefix); |
| 33 }); | 74 }); |
| 34 } | 75 } |
| 35 | 76 |
| 36 /** | 77 /** |
| 37 * Replaces the given properties of the passed in object with stubs that throw | 78 * Replaces the given properties of the passed in object with stubs that log |
| 38 * 'not available' exceptions when gotten. If a property's setter is later | 79 * 'not available' warnings to the console and return undefined when gotten. If |
| 39 * invoked, the getter and setter are restored to default behaviors. | 80 * a property's setter is later invoked, the getter and setter are restored to |
| 81 * default behaviors. |
| 40 * | 82 * |
| 41 * @param {Object} object The object with properties to disable. The prototype | 83 * @param {Object} object The object with properties to disable. The prototype |
| 42 * is preferred. | 84 * is preferred. |
| 43 * @param {string} objectName The display name to use in the error message | 85 * @param {string} objectName The display name to use in the error message |
| 44 * thrown by the getter stub (this is the name that the object is commonly | 86 * thrown by the getter stub (this is the name that the object is commonly |
| 45 * referred to by web developers, e.g. "document" instead of | 87 * referred to by web developers, e.g. "document" instead of |
| 46 * "HTMLDocument"). | 88 * "HTMLDocument"). |
| 47 * @param {Array.<string>} propertyNames names of properties to disable. | 89 * @param {Array.<string>} propertyNames names of properties to disable. |
| 48 */ | 90 */ |
| 49 function disableGetters(object, objectName, propertyNames, opt_messageSuffix) { | 91 function disableGetters(object, objectName, propertyNames, opt_messageSuffix) { |
| 50 $Array.forEach(propertyNames, function(propertyName) { | 92 $Array.forEach(propertyNames, function(propertyName) { |
| 51 var stub = generateDisabledMethodStub(objectName + '.' + propertyName, | 93 var stub = generateDisabledMethodStub(objectName + '.' + propertyName, |
| 52 opt_messageSuffix); | 94 opt_messageSuffix); |
| 53 stub._is_platform_app_disabled_getter = true; | 95 stub._is_platform_app_disabled_getter = true; |
| 54 object.__defineGetter__(propertyName, stub); | 96 $Object.defineProperty(object, propertyName, { |
| 55 | 97 configurable: true, |
| 56 object.__defineSetter__(propertyName, function(value) { | 98 enumerable: false, |
| 57 var getter = this.__lookupGetter__(propertyName); | 99 get: stub, |
| 58 if (!getter || getter._is_platform_app_disabled_getter) { | 100 set: function(value) { |
| 59 // The stub getter is still defined. Blow-away the property to restore | 101 var descriptor = $Object.getOwnPropertyDescriptor(this, propertyName); |
| 60 // default getter/setter behaviors and re-create it with the given | 102 if (!descriptor || !descriptor.get || |
| 61 // value. | 103 descriptor.get._is_platform_app_disabled_getter) { |
| 62 delete this[propertyName]; | 104 // The stub getter is still defined. Blow-away the property to |
| 63 this[propertyName] = value; | 105 // restore default getter/setter behaviors and re-create it with the |
| 64 } else { | 106 // given value. |
| 65 // Do nothing. If some custom getter (not ours) has been defined, there | 107 delete this[propertyName]; |
| 66 // would be no way to read back the value stored by a default setter. | 108 this[propertyName] = value; |
| 67 // Also, the only way to clear a custom getter is to first delete the | 109 } else { |
| 68 // property. Therefore, the value we have here should just go into a | 110 // Do nothing. If some custom getter (not ours) has been defined, |
| 69 // black hole. | 111 // there would be no way to read back the value stored by a default |
| 112 // setter. Also, the only way to clear a custom getter is to first |
| 113 // delete the property. Therefore, the value we have here should |
| 114 // just go into a black hole. |
| 115 } |
| 70 } | 116 } |
| 71 }); | 117 }); |
| 72 }); | 118 }); |
| 73 } | 119 } |
| 74 | 120 |
| 75 // Disable document.open|close|write|etc. | 121 /** |
| 76 disableMethods(HTMLDocument.prototype, 'document', | 122 * Replaces the given properties of the passed in object with stubs that log |
| 77 ['open', 'clear', 'close', 'write', 'writeln']); | 123 * 'not available' warnings to the console when set. |
| 124 * |
| 125 * @param {Object} object The object with properties to disable. The prototype |
| 126 * is preferred. |
| 127 * @param {string} objectName The display name to use in the error message |
| 128 * thrown by the setter stub (this is the name that the object is commonly |
| 129 * referred to by web developers, e.g. "document" instead of |
| 130 * "HTMLDocument"). |
| 131 * @param {Array.<string>} propertyNames names of properties to disable. |
| 132 */ |
| 133 function disableSetters(object, objectName, propertyNames, opt_messageSuffix) { |
| 134 $Array.forEach(propertyNames, function(propertyName) { |
| 135 var stub = generateDisabledMethodStub(objectName + '.' + propertyName, |
| 136 opt_messageSuffix); |
| 137 $Object.defineProperty(object, propertyName, { |
| 138 configurable: true, |
| 139 enumerable: false, |
| 140 get: function() { |
| 141 return; |
| 142 }, |
| 143 set: stub |
| 144 }); |
| 145 }); |
| 146 } |
| 147 |
| 148 // Disable benign Document methods. |
| 149 disableMethods(HTMLDocument.prototype, 'document', ['open', 'clear', 'close']); |
| 150 |
| 151 // Replace evil Document methods with exception-throwing stubs. |
| 152 disableMethods(HTMLDocument.prototype, 'document', ['write', 'writeln'], true); |
| 78 | 153 |
| 79 // Disable history. | 154 // Disable history. |
| 80 window.history = {}; | 155 window.history = {}; |
| 81 disableMethods(window.history, 'history', | 156 disableGetters(window.history, 'history', ['back', 'forward', 'go', 'length']); |
| 82 ['back', 'forward', 'go']); | |
| 83 disableGetters(window.history, 'history', ['length']); | |
| 84 | 157 |
| 85 // Disable find. | 158 // Disable find. |
| 86 disableMethods(Window.prototype, 'window', ['find']); | 159 disableMethods(Window.prototype, 'window', ['find']); |
| 87 | 160 |
| 88 // Disable modal dialogs. Shell windows disable these anyway, but it's nice to | 161 // Disable modal dialogs. Shell windows disable these anyway, but it's nice to |
| 89 // warn. | 162 // warn. |
| 90 disableMethods(Window.prototype, 'window', ['alert', 'confirm', 'prompt']); | 163 disableMethods(Window.prototype, 'window', ['alert', 'confirm', 'prompt']); |
| 91 | 164 |
| 92 // Disable window.*bar. | 165 // Disable window.*bar. |
| 93 disableGetters(window, 'window', | 166 disableGetters(window, 'window', |
| (...skipping 19 matching lines...) Expand all Loading... |
| 113 if (document.readyState != 'loading') | 186 if (document.readyState != 'loading') |
| 114 return; | 187 return; |
| 115 | 188 |
| 116 // Deprecated document properties from | 189 // Deprecated document properties from |
| 117 // https://developer.mozilla.org/en/DOM/document. | 190 // https://developer.mozilla.org/en/DOM/document. |
| 118 // To deprecate document.all, simply changing its getter and setter would | 191 // To deprecate document.all, simply changing its getter and setter would |
| 119 // activate its cache mechanism, and degrade the performance. Here we assign | 192 // activate its cache mechanism, and degrade the performance. Here we assign |
| 120 // it first to 'undefined' to avoid this. | 193 // it first to 'undefined' to avoid this. |
| 121 document.all = undefined; | 194 document.all = undefined; |
| 122 disableGetters(document, 'document', | 195 disableGetters(document, 'document', |
| 123 ['alinkColor', 'all', 'bgColor', 'fgColor', 'linkColor', | 196 ['alinkColor', 'all', 'bgColor', 'fgColor', 'linkColor', 'vlinkColor']); |
| 124 'vlinkColor']); | |
| 125 }, true); | 197 }, true); |
| 126 | 198 |
| 127 // Disable onunload, onbeforeunload. | 199 // Disable onunload, onbeforeunload. |
| 128 Window.prototype.__defineSetter__( | 200 disableSetters(Window.prototype, 'window', ['onbeforeunload', 'onunload']); |
| 129 'onbeforeunload', generateDisabledMethodStub('onbeforeunload')); | |
| 130 Window.prototype.__defineSetter__( | |
| 131 'onunload', generateDisabledMethodStub('onunload')); | |
| 132 var windowAddEventListener = Window.prototype.addEventListener; | 201 var windowAddEventListener = Window.prototype.addEventListener; |
| 133 Window.prototype.addEventListener = function(type) { | 202 Window.prototype.addEventListener = function(type) { |
| 134 if (type === 'unload' || type === 'beforeunload') | 203 if (type === 'unload' || type === 'beforeunload') |
| 135 generateDisabledMethodStub(type)(); | 204 generateDisabledMethodStub(type)(); |
| 136 else | 205 else |
| 137 return $Function.apply(windowAddEventListener, window, arguments); | 206 return $Function.apply(windowAddEventListener, window, arguments); |
| 138 }; | 207 }; |
| OLD | NEW |