Add a hack to block calls to certain introspected functions

This is useful for keeping people from using methods that only fail in
certain circumstances, by making them fail in all circumstances
instead.

https://bugzilla.gnome.org/show_bug.cgi?id=618918
This commit is contained in:
Dan Winship 2010-03-26 16:38:03 -04:00
parent 91319d5da2
commit fe542f8732
3 changed files with 115 additions and 2 deletions

View File

@ -1,5 +1,6 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */ /* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Shell = imports.gi.Shell;
const St = imports.gi.St; const St = imports.gi.St;
const Gettext_gtk20 = imports.gettext.domain('gtk20'); const Gettext_gtk20 = imports.gettext.domain('gtk20');
@ -28,8 +29,34 @@ function _patchContainerClass(containerClass) {
}; };
} }
_patchContainerClass(St.BoxLayout); // Replace @method with something that throws an error instead
_patchContainerClass(St.Table); function _blockMethod(method, replacement, reason) {
let match = method.match(/^(.+)\.([^.]+)$/);
if (!match)
throw new Error('Bad method name "' + method + '"');
let proto = 'imports.gi.' + match[1] + '.prototype';
let property = match[2];
if (!global.set_property_mutable(proto, property, true))
throw new Error('Bad method name "' + method + '"');
// eval() is evil in general, but we know it's safe here since
// set_property_mutable() would have failed if proto was
// malformed.
let node = eval(proto);
let msg = 'Do not use "' + method + '".';
if (replacement)
msg += ' Use "' + replacement + '" instead.';
if (reason)
msg += ' (' + reason + ')';
node[property] = function() {
throw new Error(msg);
};
global.set_property_mutable(proto, property, false);
}
function init() { function init() {
Tweener.init(); Tweener.init();
@ -39,4 +66,20 @@ function init() {
if (Gettext_gtk20.gettext('default:LTR') == 'default:RTL') { if (Gettext_gtk20.gettext('default:LTR') == 'default:RTL') {
St.Widget.set_default_direction(St.TextDirection.RTL); St.Widget.set_default_direction(St.TextDirection.RTL);
} }
_patchContainerClass(St.BoxLayout);
_patchContainerClass(St.Table);
_blockMethod('Clutter.Event.get_state', 'Shell.get_event_state',
'gjs\'s handling of Clutter.ModifierType is broken. See bug 597292.');
_blockMethod('Gdk.Display.get_pointer', 'global.get_pointer',
'gjs\'s handling of Gdk.ModifierType is broken. See bug 597292.');
_blockMethod('Gdk.Window.get_pointer', 'global.get_pointer',
'gjs\'s handling of Gdk.ModifierType is broken. See bug 597292.');
// Now close the back door to prevent extensions from trying to
// abuse it. We can't actually delete it since
// Shell.Global.prototype itself is read-only.
global.set_property_mutable('imports.gi.Shell.Global.prototype', 'set_property_mutable', true);
Shell.Global.prototype.set_property_mutable = undefined;
} }

View File

@ -1327,3 +1327,68 @@ shell_global_create_app_launch_context (ShellGlobal *global)
return (GAppLaunchContext *)context; return (GAppLaunchContext *)context;
} }
/**
* shell_global_set_property_mutable:
* @global: the #ShellGlobal
* @object: the "path" to a JS object, starting from the root object.
* (Eg, "global.stage" or "imports.gi.Gtk.Window.prototype")
* @property: a property on @object
* @mutable: %TRUE or %FALSE
*
* If @mutable is %TRUE, this clears the "permanent" and "readonly" flags
* on @property of @object. If @mutable is %FALSE, it sets them.
*
* You can use this to make it possible to modify properties that
* would otherwise be read-only from JavaScript.
*
* Return value: success or failure.
*/
gboolean
shell_global_set_property_mutable (ShellGlobal *global,
const char *object,
const char *property,
gboolean mutable)
{
JSContext *context = gjs_context_get_native_context (global->js_context);
char **parts;
JSObject *obj;
jsval val = JSVAL_VOID;
int i;
jsuint attrs;
JSBool found;
JS_AddRoot (context, &val);
parts = g_strsplit (object, ".", -1);
obj = JS_GetGlobalObject (context);
for (i = 0; parts[i]; i++)
{
if (!JS_GetProperty (context, obj, parts[i], &val))
{
g_strfreev (parts);
JS_RemoveRoot (context, &val);
gjs_log_exception (context, NULL);
return FALSE;
}
obj = JSVAL_TO_OBJECT (val);
}
g_strfreev (parts);
if (!JS_GetPropertyAttributes (context, obj, property, &attrs, &found) || !found)
{
JS_RemoveRoot (context, &val);
gjs_log_exception (context, NULL);
return FALSE;
}
if (mutable)
attrs &= ~(JSPROP_PERMANENT | JSPROP_READONLY);
else
attrs |= (JSPROP_PERMANENT | JSPROP_READONLY);
JS_SetPropertyAttributes (context, obj, property, attrs, &found);
JS_RemoveRoot (context, &val);
return !gjs_log_exception (context, NULL);
}

View File

@ -96,6 +96,11 @@ guint32 shell_global_get_current_time (ShellGlobal *global);
GAppLaunchContext *shell_global_create_app_launch_context (ShellGlobal *global); GAppLaunchContext *shell_global_create_app_launch_context (ShellGlobal *global);
gboolean shell_global_set_property_mutable (ShellGlobal *global,
const char *object,
const char *property,
gboolean mutable);
G_END_DECLS G_END_DECLS
#endif /* __SHELL_GLOBAL_H__ */ #endif /* __SHELL_GLOBAL_H__ */