From fe542f873240547091e583086341056c062f162c Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Fri, 26 Mar 2010 16:38:03 -0400 Subject: [PATCH] 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 --- js/ui/environment.js | 47 ++++++++++++++++++++++++++++++-- src/shell-global.c | 65 ++++++++++++++++++++++++++++++++++++++++++++ src/shell-global.h | 5 ++++ 3 files changed, 115 insertions(+), 2 deletions(-) diff --git a/js/ui/environment.js b/js/ui/environment.js index 209cdc822..67682d8fe 100644 --- a/js/ui/environment.js +++ b/js/ui/environment.js @@ -1,5 +1,6 @@ /* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */ +const Shell = imports.gi.Shell; const St = imports.gi.St; const Gettext_gtk20 = imports.gettext.domain('gtk20'); @@ -28,8 +29,34 @@ function _patchContainerClass(containerClass) { }; } -_patchContainerClass(St.BoxLayout); -_patchContainerClass(St.Table); +// Replace @method with something that throws an error instead +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() { Tweener.init(); @@ -39,4 +66,20 @@ function init() { if (Gettext_gtk20.gettext('default:LTR') == 'default: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; } diff --git a/src/shell-global.c b/src/shell-global.c index 758af542e..5d61e41e2 100644 --- a/src/shell-global.c +++ b/src/shell-global.c @@ -1327,3 +1327,68 @@ shell_global_create_app_launch_context (ShellGlobal *global) 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); +} diff --git a/src/shell-global.h b/src/shell-global.h index 5ac31d820..27c43be97 100644 --- a/src/shell-global.h +++ b/src/shell-global.h @@ -96,6 +96,11 @@ guint32 shell_global_get_current_time (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 #endif /* __SHELL_GLOBAL_H__ */