| OLD | NEW | 
|---|
|  | (Empty) | 
| 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 |  | 
| 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 | 
|---|