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 |