| OLD | NEW |
| (Empty) |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 var $console = window.console; | |
| 6 | |
| 7 /** | |
| 8 * Returns a function that logs a 'not available' error to the console and | |
| 9 * returns undefined. | |
| 10 * | |
| 11 * @param {string} messagePrefix text to prepend to the exception message. | |
| 12 */ | |
| 13 function generateDisabledMethodStub(messagePrefix, opt_messageSuffix) { | |
| 14 var message = messagePrefix + ' is not available in packaged apps.'; | |
| 15 if (opt_messageSuffix) message = message + ' ' + opt_messageSuffix; | |
| 16 return function() { | |
| 17 $console.error(message); | |
| 18 return; | |
| 19 }; | |
| 20 } | |
| 21 | |
| 22 /** | |
| 23 * Returns a function that throws a 'not available' error. | |
| 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 | |
| 58 * | |
| 59 * @param {Object} object The object with methods to disable. The prototype is | |
| 60 * preferred. | |
| 61 * @param {string} objectName The display name to use in the error message | |
| 62 * thrown by the stub (this is the name that the object is commonly referred | |
| 63 * to by web developers, e.g. "document" instead of "HTMLDocument"). | |
| 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 | |
| 67 */ | |
| 68 function disableMethods(object, objectName, methodNames, useThrowingStubs) { | |
| 69 $Array.forEach(methodNames, function(methodName) { | |
| 70 var messagePrefix = objectName + '.' + methodName + '()'; | |
| 71 object[methodName] = useThrowingStubs ? | |
| 72 generateThrowingMethodStub(messagePrefix) : | |
| 73 generateDisabledMethodStub(messagePrefix); | |
| 74 }); | |
| 75 } | |
| 76 | |
| 77 /** | |
| 78 * Replaces the given properties of the passed in object with stubs that log | |
| 79 * 'not available' warnings to the console and return undefined when gotten. If | |
| 80 * a property's setter is later invoked, the getter and setter are restored to | |
| 81 * default behaviors. | |
| 82 * | |
| 83 * @param {Object} object The object with properties to disable. The prototype | |
| 84 * is preferred. | |
| 85 * @param {string} objectName The display name to use in the error message | |
| 86 * thrown by the getter stub (this is the name that the object is commonly | |
| 87 * referred to by web developers, e.g. "document" instead of | |
| 88 * "HTMLDocument"). | |
| 89 * @param {Array.<string>} propertyNames names of properties to disable. | |
| 90 */ | |
| 91 function disableGetters(object, objectName, propertyNames, opt_messageSuffix) { | |
| 92 $Array.forEach(propertyNames, function(propertyName) { | |
| 93 var stub = generateDisabledMethodStub(objectName + '.' + propertyName, | |
| 94 opt_messageSuffix); | |
| 95 stub._is_platform_app_disabled_getter = true; | |
| 96 $Object.defineProperty(object, propertyName, { | |
| 97 configurable: true, | |
| 98 enumerable: false, | |
| 99 get: stub, | |
| 100 set: function(value) { | |
| 101 var descriptor = $Object.getOwnPropertyDescriptor(this, propertyName); | |
| 102 if (!descriptor || !descriptor.get || | |
| 103 descriptor.get._is_platform_app_disabled_getter) { | |
| 104 // The stub getter is still defined. Blow-away the property to | |
| 105 // restore default getter/setter behaviors and re-create it with the | |
| 106 // given value. | |
| 107 delete this[propertyName]; | |
| 108 this[propertyName] = value; | |
| 109 } else { | |
| 110 // Do nothing. If some custom getter (not ours) has been defined, | |
| 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 } | |
| 116 } | |
| 117 }); | |
| 118 }); | |
| 119 } | |
| 120 | |
| 121 /** | |
| 122 * Replaces the given properties of the passed in object with stubs that log | |
| 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); | |
| 153 | |
| 154 // Disable history. | |
| 155 Object.defineProperty(window, "history", { value: {} }); | |
| 156 disableGetters(window.history, 'history', ['back', 'forward', 'go', 'length']); | |
| 157 | |
| 158 // Disable find. | |
| 159 disableMethods(Window.prototype, 'window', ['find']); | |
| 160 | |
| 161 // Disable modal dialogs. Shell windows disable these anyway, but it's nice to | |
| 162 // warn. | |
| 163 disableMethods(Window.prototype, 'window', ['alert', 'confirm', 'prompt']); | |
| 164 | |
| 165 // Disable window.*bar. | |
| 166 disableGetters(window, 'window', | |
| 167 ['locationbar', 'menubar', 'personalbar', 'scrollbars', 'statusbar', | |
| 168 'toolbar']); | |
| 169 | |
| 170 // Disable window.localStorage. | |
| 171 // Sometimes DOM security policy prevents us from doing this (e.g. for data: | |
| 172 // URLs) so wrap in try-catch. | |
| 173 try { | |
| 174 disableGetters(window, 'window', | |
| 175 ['localStorage'], | |
| 176 'Use chrome.storage.local instead.'); | |
| 177 } catch (e) {} | |
| 178 | |
| 179 // Document instance properties that we wish to disable need to be set when | |
| 180 // the document begins loading, since only then will the "document" reference | |
| 181 // point to the page's document (it will be reset between now and then). | |
| 182 // We can't listen for the "readystatechange" event on the document (because | |
| 183 // the object that it's dispatched on doesn't exist yet), but we can instead | |
| 184 // do it at the window level in the capturing phase. | |
| 185 window.addEventListener('readystatechange', function(event) { | |
| 186 if (document.readyState != 'loading') | |
| 187 return; | |
| 188 | |
| 189 // Deprecated document properties from | |
| 190 // https://developer.mozilla.org/en/DOM/document. | |
| 191 // To deprecate document.all, simply changing its getter and setter would | |
| 192 // activate its cache mechanism, and degrade the performance. Here we assign | |
| 193 // it first to 'undefined' to avoid this. | |
| 194 document.all = undefined; | |
| 195 disableGetters(document, 'document', | |
| 196 ['alinkColor', 'all', 'bgColor', 'fgColor', 'linkColor', 'vlinkColor']); | |
| 197 }, true); | |
| 198 | |
| 199 // Disable onunload, onbeforeunload. | |
| 200 disableSetters(Window.prototype, 'window', ['onbeforeunload', 'onunload']); | |
| 201 var windowAddEventListener = Window.prototype.addEventListener; | |
| 202 Window.prototype.addEventListener = function(type) { | |
| 203 if (type === 'unload' || type === 'beforeunload') | |
| 204 generateDisabledMethodStub(type)(); | |
| 205 else | |
| 206 return $Function.apply(windowAddEventListener, window, arguments); | |
| 207 }; | |
| OLD | NEW |