Chromium Code Reviews| 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. | |
| 21 * | 42 * |
| 22 * @param {Object} object The object with methods to disable. The prototype is | 43 * @param {Object} object The object with methods to disable. The prototype is |
| 23 * preferred. | 44 * preferred. |
| 24 * @param {string} objectName The display name to use in the error message | 45 * @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 | 46 * 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"). | 47 * to by web developers, e.g. "document" instead of "HTMLDocument"). |
| 27 * @param {Array.<string>} methodNames names of methods to disable. | 48 * @param {Array.<string>} methodNames names of methods to disable. |
| 49 * @param {Boolean} useThrowingStubs if true, the replaced methods will throw | |
| 50 * an error instead of silently returning undefined | |
| 28 */ | 51 */ |
| 29 function disableMethods(object, objectName, methodNames) { | 52 function disableMethods(object, objectName, methodNames, useThrowingStubs) { |
|
Jeffrey Yasskin
2014/01/08 22:49:17
It seems like it would make sense for a *call* to
pwnall-personal
2014/01/08 23:20:46
Completely agreed, if getting the method from the
Jeffrey Yasskin
2014/01/09 00:44:19
Oh, right. Yes, your change makes sense. Maybe com
pwnall-personal
2014/01/09 05:47:26
Done.
Thank you very much for the suggestion!
I a
| |
| 30 $Array.forEach(methodNames, function(methodName) { | 53 $Array.forEach(methodNames, function(methodName) { |
| 31 object[methodName] = | 54 var messagePrefix = objectName + '.' + methodName + '()'; |
| 32 generateDisabledMethodStub(objectName + '.' + methodName + '()'); | 55 object[methodName] = useThrowingStubs ? |
| 56 generateThrowingMethodStub(messagePrefix) : | |
| 57 generateDisabledMethodStub(messagePrefix); | |
| 33 }); | 58 }); |
| 34 } | 59 } |
| 35 | 60 |
| 36 /** | 61 /** |
| 37 * Replaces the given properties of the passed in object with stubs that throw | 62 * 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 | 63 * 'not available' warnings to the console and return undefined when gotten. If |
| 39 * invoked, the getter and setter are restored to default behaviors. | 64 * a property's setter is later invoked, the getter and setter are restored to |
| 65 * default behaviors. | |
| 40 * | 66 * |
| 41 * @param {Object} object The object with properties to disable. The prototype | 67 * @param {Object} object The object with properties to disable. The prototype |
| 42 * is preferred. | 68 * is preferred. |
| 43 * @param {string} objectName The display name to use in the error message | 69 * @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 | 70 * 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 | 71 * referred to by web developers, e.g. "document" instead of |
| 46 * "HTMLDocument"). | 72 * "HTMLDocument"). |
| 47 * @param {Array.<string>} propertyNames names of properties to disable. | 73 * @param {Array.<string>} propertyNames names of properties to disable. |
| 48 */ | 74 */ |
| 49 function disableGetters(object, objectName, propertyNames, opt_messageSuffix) { | 75 function disableGetters(object, objectName, propertyNames, opt_messageSuffix) { |
| 50 $Array.forEach(propertyNames, function(propertyName) { | 76 $Array.forEach(propertyNames, function(propertyName) { |
| 51 var stub = generateDisabledMethodStub(objectName + '.' + propertyName, | 77 var stub = generateDisabledMethodStub(objectName + '.' + propertyName, |
| 52 opt_messageSuffix); | 78 opt_messageSuffix); |
| 53 stub._is_platform_app_disabled_getter = true; | 79 stub._is_platform_app_disabled_getter = true; |
| 54 object.__defineGetter__(propertyName, stub); | 80 $Object.defineProperty(object, propertyName, { |
| 81 configurable: true, | |
| 82 enumerable: false, | |
| 83 get: stub, | |
| 84 set: function(value) { | |
| 85 var descriptor = $Object.getOwnPropertyDescriptor(this, propertyName); | |
| 86 if (!descriptor || !descriptor.get || | |
| 87 descriptor.get._is_platform_app_disabled_getter) { | |
| 88 // The stub getter is still defined. Blow-away the property to | |
| 89 // restore default getter/setter behaviors and re-create it with the | |
| 90 // given value. | |
| 91 delete this[propertyName]; | |
| 92 this[propertyName] = value; | |
| 93 } else { | |
| 94 // Do nothing. If some custom getter (not ours) has been defined, | |
| 95 // there would be no way to read back the value stored by a default | |
| 96 // setter. Also, the only way to clear a custom getter is to first | |
| 97 // delete the property. Therefore, the value we have here should | |
| 98 // just go into a black hole. | |
| 99 } | |
| 100 } | |
| 101 }); | |
| 102 }); | |
| 103 } | |
| 55 | 104 |
| 56 object.__defineSetter__(propertyName, function(value) { | 105 /** |
| 57 var getter = this.__lookupGetter__(propertyName); | 106 * Replaces the given properties of the passed in object with stubs that log |
| 58 if (!getter || getter._is_platform_app_disabled_getter) { | 107 * 'not available' warnings to the console when set. |
| 59 // The stub getter is still defined. Blow-away the property to restore | 108 * |
| 60 // default getter/setter behaviors and re-create it with the given | 109 * @param {Object} object The object with properties to disable. |
| 61 // value. | 110 * is preferred. |
|
Jeffrey Yasskin
2014/01/08 22:49:17
What "is preferred."?
pwnall-personal
2014/01/08 23:20:46
More care when copy-pasting is definitely preferre
| |
| 62 delete this[propertyName]; | 111 * @param {string} objectName The display name to use in the error message |
| 63 this[propertyName] = value; | 112 * thrown by the setter stub (this is the name that the object is commonly |
| 64 } else { | 113 * referred to by web developers, e.g. "document" instead of |
| 65 // Do nothing. If some custom getter (not ours) has been defined, there | 114 * "HTMLDocument"). |
| 66 // would be no way to read back the value stored by a default setter. | 115 * @param {Array.<string>} propertyNames names of properties to disable. |
| 67 // Also, the only way to clear a custom getter is to first delete the | 116 */ |
| 68 // property. Therefore, the value we have here should just go into a | 117 function disableSetters(object, objectName, propertyNames, opt_messageSuffix) { |
| 69 // black hole. | 118 $Array.forEach(propertyNames, function(propertyName) { |
| 70 } | 119 var stub = generateDisabledMethodStub(objectName + '.' + propertyName, |
| 120 opt_messageSuffix); | |
| 121 $Object.defineProperty(object, propertyName, { | |
| 122 configurable: true, | |
| 123 enumerable: false, | |
| 124 get: function() { | |
| 125 return; | |
| 126 }, | |
| 127 set: stub | |
| 71 }); | 128 }); |
| 72 }); | 129 }); |
| 73 } | 130 } |
| 74 | 131 |
| 75 // Disable document.open|close|write|etc. | 132 // Disable document.open|close|write|etc. |
| 76 disableMethods(HTMLDocument.prototype, 'document', | 133 disableMethods(HTMLDocument.prototype, 'document', |
| 77 ['open', 'clear', 'close', 'write', 'writeln']); | 134 ['open', 'clear', 'close', 'write', 'writeln'], |
| 135 true); | |
|
Jeffrey Yasskin
2014/01/08 22:49:17
Why does document get throwing method stubs, but w
pwnall-personal
2014/01/08 23:20:46
I treated the document methods differently because
Jeffrey Yasskin
2014/01/09 00:44:19
I don't have a strong opinion here at all (i.e. do
pwnall-personal
2014/01/09 05:47:26
That makes perfect sense, thank you!
I updated th
| |
| 78 | 136 |
| 79 // Disable history. | 137 // Disable history. |
| 80 window.history = {}; | 138 window.history = {}; |
| 81 disableMethods(window.history, 'history', | 139 disableGetters(window.history, 'history', ['back', 'forward', 'go', 'length']); |
| 82 ['back', 'forward', 'go']); | |
| 83 disableGetters(window.history, 'history', ['length']); | |
| 84 | 140 |
| 85 // Disable find. | 141 // Disable find. |
| 86 disableMethods(Window.prototype, 'window', ['find']); | 142 disableMethods(Window.prototype, 'window', ['find']); |
| 87 | 143 |
| 88 // Disable modal dialogs. Shell windows disable these anyway, but it's nice to | 144 // Disable modal dialogs. Shell windows disable these anyway, but it's nice to |
| 89 // warn. | 145 // warn. |
| 90 disableMethods(Window.prototype, 'window', ['alert', 'confirm', 'prompt']); | 146 disableMethods(Window.prototype, 'window', ['alert', 'confirm', 'prompt']); |
| 91 | 147 |
| 92 // Disable window.*bar. | 148 // Disable window.*bar. |
| 93 disableGetters(window, 'window', | 149 disableGetters(window, 'window', |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 118 // To deprecate document.all, simply changing its getter and setter would | 174 // To deprecate document.all, simply changing its getter and setter would |
| 119 // activate its cache mechanism, and degrade the performance. Here we assign | 175 // activate its cache mechanism, and degrade the performance. Here we assign |
| 120 // it first to 'undefined' to avoid this. | 176 // it first to 'undefined' to avoid this. |
| 121 document.all = undefined; | 177 document.all = undefined; |
| 122 disableGetters(document, 'document', | 178 disableGetters(document, 'document', |
| 123 ['alinkColor', 'all', 'bgColor', 'fgColor', 'linkColor', | 179 ['alinkColor', 'all', 'bgColor', 'fgColor', 'linkColor', |
| 124 'vlinkColor']); | 180 'vlinkColor']); |
| 125 }, true); | 181 }, true); |
| 126 | 182 |
| 127 // Disable onunload, onbeforeunload. | 183 // Disable onunload, onbeforeunload. |
| 128 Window.prototype.__defineSetter__( | 184 disableSetters(Window.prototype, 'window', ['onbeforeunload', 'onunload']); |
| 129 'onbeforeunload', generateDisabledMethodStub('onbeforeunload')); | |
| 130 Window.prototype.__defineSetter__( | |
| 131 'onunload', generateDisabledMethodStub('onunload')); | |
| 132 var windowAddEventListener = Window.prototype.addEventListener; | 185 var windowAddEventListener = Window.prototype.addEventListener; |
| 133 Window.prototype.addEventListener = function(type) { | 186 Window.prototype.addEventListener = function(type) { |
| 134 if (type === 'unload' || type === 'beforeunload') | 187 if (type === 'unload' || type === 'beforeunload') |
| 135 generateDisabledMethodStub(type)(); | 188 generateDisabledMethodStub(type)(); |
| 136 else | 189 else |
| 137 return $Function.apply(windowAddEventListener, window, arguments); | 190 return $Function.apply(windowAddEventListener, window, arguments); |
| 138 }; | 191 }; |
| OLD | NEW |