Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(99)

Side by Side Diff: chrome/renderer/resources/extensions/platform_app.js

Issue 120733003: Feature detection-friendly restrictions for packaged apps. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Addressed feedback. Created 6 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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 };
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698