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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: chrome/renderer/resources/extensions/platform_app.js
diff --git a/chrome/renderer/resources/extensions/platform_app.js b/chrome/renderer/resources/extensions/platform_app.js
index 78a13ffe01e51ea4049d8abccc37a02f59f24695..0982a6a18ea0b4371208292f1fd14f6ed4d3b921 100644
--- a/chrome/renderer/resources/extensions/platform_app.js
+++ b/chrome/renderer/resources/extensions/platform_app.js
@@ -2,22 +2,59 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+var $console = window.console;
+
/**
- * Returns a function that throws a 'not available' exception when called.
+ * Returns a function that logs a 'not available' error to the console and
+ * returns undefined.
*
* @param {string} messagePrefix text to prepend to the exception message.
*/
function generateDisabledMethodStub(messagePrefix, opt_messageSuffix) {
+ var message = messagePrefix + ' is not available in packaged apps.';
+ if (opt_messageSuffix) message = message + ' ' + opt_messageSuffix;
return function() {
- var message = messagePrefix + ' is not available in packaged apps.';
- if (opt_messageSuffix) message = message + ' ' + opt_messageSuffix;
- throw message;
+ $console.error(message);
+ return;
};
}
/**
- * Replaces the given methods of the passed in object with stubs that throw
- * 'not available' exceptions when called.
+ * Returns a function that throws a 'not available' error.
+ *
+ * @param {string} messagePrefix text to prepend to the exception message.
+ */
+function generateThrowingMethodStub(messagePrefix, opt_messageSuffix) {
+ var message = messagePrefix + ' is not available in packaged apps.';
+ if (opt_messageSuffix) message = message + ' ' + opt_messageSuffix;
+ return function() {
+ throw new Error(message);
+ };
+}
+
+/**
+ * Replaces the given methods of the passed in object with stubs that log
+ * 'not available' errors to the console and return undefined.
+ *
+ * This should be used on methods attached via non-configurable properties,
+ * such as window.alert. disableGetters should be used when possible, because
+ * it is friendlier towards feature detection.
+ *
+ * In most cases, the useThrowingStubs should be false, so the stubs used to
+ * replace the methods log an error to the console, but allow the calling code
+ * to continue. We shouldn't break library code that uses feature detection
+ * responsibly, such as:
+ * if(window.confirm) {
+ * var result = window.confirm('Are you sure you want to delete ...?');
+ * ...
+ * }
+ *
+ * useThrowingStubs should only be true for methods that are deprecated in the
+ * Web platform, and should not be used by a responsible library, even in
+ * conjunction with feature detection. A great example is document.write(), as
+ * the HTML5 specification recommends against using it, and says that its
+ * behavior is unreliable. No reasonable library code should ever use it.
+ * HTML5 spec: http://www.w3.org/TR/html5/dom.html#dom-document-write
*
* @param {Object} object The object with methods to disable. The prototype is
* preferred.
@@ -25,18 +62,23 @@ function generateDisabledMethodStub(messagePrefix, opt_messageSuffix) {
* thrown by the stub (this is the name that the object is commonly referred
* to by web developers, e.g. "document" instead of "HTMLDocument").
* @param {Array.<string>} methodNames names of methods to disable.
+ * @param {Boolean} useThrowingStubs if true, the replaced methods will throw
+ * an error instead of silently returning undefined
*/
-function disableMethods(object, objectName, methodNames) {
+function disableMethods(object, objectName, methodNames, useThrowingStubs) {
$Array.forEach(methodNames, function(methodName) {
- object[methodName] =
- generateDisabledMethodStub(objectName + '.' + methodName + '()');
+ var messagePrefix = objectName + '.' + methodName + '()';
+ object[methodName] = useThrowingStubs ?
+ generateThrowingMethodStub(messagePrefix) :
+ generateDisabledMethodStub(messagePrefix);
});
}
/**
- * Replaces the given properties of the passed in object with stubs that throw
- * 'not available' exceptions when gotten. If a property's setter is later
- * invoked, the getter and setter are restored to default behaviors.
+ * Replaces the given properties of the passed in object with stubs that log
+ * 'not available' warnings to the console and return undefined when gotten. If
+ * a property's setter is later invoked, the getter and setter are restored to
+ * default behaviors.
*
* @param {Object} object The object with properties to disable. The prototype
* is preferred.
@@ -51,36 +93,67 @@ function disableGetters(object, objectName, propertyNames, opt_messageSuffix) {
var stub = generateDisabledMethodStub(objectName + '.' + propertyName,
opt_messageSuffix);
stub._is_platform_app_disabled_getter = true;
- object.__defineGetter__(propertyName, stub);
-
- object.__defineSetter__(propertyName, function(value) {
- var getter = this.__lookupGetter__(propertyName);
- if (!getter || getter._is_platform_app_disabled_getter) {
- // The stub getter is still defined. Blow-away the property to restore
- // default getter/setter behaviors and re-create it with the given
- // value.
- delete this[propertyName];
- this[propertyName] = value;
- } else {
- // Do nothing. If some custom getter (not ours) has been defined, there
- // would be no way to read back the value stored by a default setter.
- // Also, the only way to clear a custom getter is to first delete the
- // property. Therefore, the value we have here should just go into a
- // black hole.
+ $Object.defineProperty(object, propertyName, {
+ configurable: true,
+ enumerable: false,
+ get: stub,
+ set: function(value) {
+ var descriptor = $Object.getOwnPropertyDescriptor(this, propertyName);
+ if (!descriptor || !descriptor.get ||
+ descriptor.get._is_platform_app_disabled_getter) {
+ // The stub getter is still defined. Blow-away the property to
+ // restore default getter/setter behaviors and re-create it with the
+ // given value.
+ delete this[propertyName];
+ this[propertyName] = value;
+ } else {
+ // Do nothing. If some custom getter (not ours) has been defined,
+ // there would be no way to read back the value stored by a default
+ // setter. Also, the only way to clear a custom getter is to first
+ // delete the property. Therefore, the value we have here should
+ // just go into a black hole.
+ }
}
});
});
}
-// Disable document.open|close|write|etc.
-disableMethods(HTMLDocument.prototype, 'document',
- ['open', 'clear', 'close', 'write', 'writeln']);
+/**
+ * Replaces the given properties of the passed in object with stubs that log
+ * 'not available' warnings to the console when set.
+ *
+ * @param {Object} object The object with properties to disable. The prototype
+ * is preferred.
+ * @param {string} objectName The display name to use in the error message
+ * thrown by the setter stub (this is the name that the object is commonly
+ * referred to by web developers, e.g. "document" instead of
+ * "HTMLDocument").
+ * @param {Array.<string>} propertyNames names of properties to disable.
+ */
+function disableSetters(object, objectName, propertyNames, opt_messageSuffix) {
+ $Array.forEach(propertyNames, function(propertyName) {
+ var stub = generateDisabledMethodStub(objectName + '.' + propertyName,
+ opt_messageSuffix);
+ $Object.defineProperty(object, propertyName, {
+ configurable: true,
+ enumerable: false,
+ get: function() {
+ return;
+ },
+ set: stub
+ });
+ });
+}
+
+// Disable benign Document methods.
+disableMethods(HTMLDocument.prototype, 'document', ['open', 'clear', 'close']);
+
+// Replace evil Document methods with exception-throwing stubs.
+disableMethods(HTMLDocument.prototype, 'document', ['write', 'writeln'], true);
// Disable history.
window.history = {};
-disableMethods(window.history, 'history',
- ['back', 'forward', 'go']);
-disableGetters(window.history, 'history', ['length']);
+disableGetters(window.history, 'history', ['back', 'forward', 'go', 'length']);
// Disable find.
disableMethods(Window.prototype, 'window', ['find']);
@@ -120,15 +193,11 @@ window.addEventListener('readystatechange', function(event) {
// it first to 'undefined' to avoid this.
document.all = undefined;
disableGetters(document, 'document',
- ['alinkColor', 'all', 'bgColor', 'fgColor', 'linkColor',
- 'vlinkColor']);
+ ['alinkColor', 'all', 'bgColor', 'fgColor', 'linkColor', 'vlinkColor']);
}, true);
// Disable onunload, onbeforeunload.
-Window.prototype.__defineSetter__(
- 'onbeforeunload', generateDisabledMethodStub('onbeforeunload'));
-Window.prototype.__defineSetter__(
- 'onunload', generateDisabledMethodStub('onunload'));
+disableSetters(Window.prototype, 'window', ['onbeforeunload', 'onunload']);
var windowAddEventListener = Window.prototype.addEventListener;
Window.prototype.addEventListener = function(type) {
if (type === 'unload' || type === 'beforeunload')

Powered by Google App Engine
This is Rietveld 408576698