[gnome-shell] introspect: Split out DBusSenderChecker



commit 2a3e297218c85dd1d198bdecdd0768ae85e97f09
Author: Florian Müllner <fmuellner gnome org>
Date:   Wed Jun 16 19:09:42 2021 +0200

    introspect: Split out DBusSenderChecker
    
    Restricting callers to a list of allowed senders is useful for
    other D-Bus services as well, so split out the existing code
    into a reusable class.
    
    https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/3943
    
    Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1970>

 js/misc/introspect.js | 30 ++++-----------------------
 js/misc/util.js       | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 60 insertions(+), 27 deletions(-)
---
diff --git a/js/misc/introspect.js b/js/misc/introspect.js
index 8e469fbea3..22bd8319c4 100644
--- a/js/misc/introspect.js
+++ b/js/misc/introspect.js
@@ -9,6 +9,7 @@ const APP_ALLOWLIST = [
 const INTROSPECT_DBUS_API_VERSION = 3;
 
 const { loadInterfaceXML } = imports.misc.fileUtils;
+const { DBusSenderChecker } = imports.misc.util;
 
 const IntrospectDBusIface = loadInterfaceXML('org.gnome.Shell.Introspect');
 
@@ -43,14 +44,7 @@ var IntrospectService = class {
 
         this._syncRunningApplications();
 
-        this._allowlistMap = new Map();
-        APP_ALLOWLIST.forEach(appName => {
-            Gio.DBus.watch_name(Gio.BusType.SESSION,
-                appName,
-                Gio.BusNameWatcherFlags.NONE,
-                (conn, name, owner) => this._allowlistMap.set(name, owner),
-                (conn, name) => this._allowlistMap.delete(name));
-        });
+        this._senderChecker = new DBusSenderChecker(APP_ALLOWLIST);
 
         this._settings = St.Settings.get();
         this._settings.connect('notify::enable-animations',
@@ -67,10 +61,6 @@ var IntrospectService = class {
         return app.get_windows().some(w => w.transient_for == null);
     }
 
-    _isSenderAllowed(sender) {
-        return [...this._allowlistMap.values()].includes(sender);
-    }
-
     _getSandboxedAppId(app) {
         let ids = app.get_windows().map(w => w.get_sandboxed_app_id());
         return ids.find(id => id != null);
@@ -127,21 +117,9 @@ var IntrospectService = class {
                 type == Meta.WindowType.UTILITY;
     }
 
-    _checkInvocation(invocation) {
-        if (global.context.unsafe_mode)
-            return;
-
-        if (this._isSenderAllowed(invocation.get_sender()))
-            return;
-
-        throw new GLib.Error(Gio.DBusError,
-            Gio.DBusError.ACCESS_DENIED,
-            'App introspection not allowed');
-    }
-
     GetRunningApplicationsAsync(params, invocation) {
         try {
-            this._checkInvocation(invocation);
+            this._senderChecker.checkInvocation(invocation);
         } catch (e) {
             invocation.return_gerror(e);
             return;
@@ -156,7 +134,7 @@ var IntrospectService = class {
         let windowsList = {};
 
         try {
-            this._checkInvocation(invocation);
+            this._senderChecker.checkInvocation(invocation);
         } catch (e) {
             invocation.return_gerror(e);
             return;
diff --git a/js/misc/util.js b/js/misc/util.js
index 8139d3f47c..bd57184728 100644
--- a/js/misc/util.js
+++ b/js/misc/util.js
@@ -1,7 +1,8 @@
 // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 /* exported findUrls, spawn, spawnCommandLine, spawnApp, trySpawnCommandLine,
             formatTime, formatTimeSpan, createTimeLabel, insertSorted,
-            ensureActorVisibleInScrollView, wiggle, lerp, GNOMEversionCompare */
+            ensureActorVisibleInScrollView, wiggle, lerp, GNOMEversionCompare,
+            DBusSenderChecker */
 
 const { Clutter, Gio, GLib, Shell, St, GnomeDesktop } = imports.gi;
 const Gettext = imports.gettext;
@@ -477,3 +478,57 @@ function GNOMEversionCompare(version1, version2) {
 
     return 0;
 }
+
+var DBusSenderChecker = class {
+    /**
+     * @param {string[]} allowList - list of allowed well-known names
+     */
+    constructor(allowList) {
+        this._allowlistMap = new Map();
+
+        this._watchList = allowList.map(name => {
+            return Gio.DBus.watch_name(Gio.BusType.SESSION,
+                name,
+                Gio.BusNameWatcherFlags.NONE,
+                (conn_, name_, owner) => this._allowlistMap.set(name, owner),
+                () => this._allowlistMap.delete(name));
+        });
+    }
+
+    /**
+     * @param {string} sender - the bus name that invoked the checked method
+     * @returns {bool}
+     */
+    _isSenderAllowed(sender) {
+        return [...this._allowlistMap.values()].includes(sender);
+    }
+
+    /**
+     * Check whether the bus name that invoked @invocation maps
+     * to an entry in the allow list.
+     *
+     * @throws
+     * @param {Gio.DBusMethodInvocation} invocation - the invocation
+     * @returns {void}
+     */
+    checkInvocation(invocation) {
+        if (global.context.unsafe_mode)
+            return;
+
+        if (this._isSenderAllowed(invocation.get_sender()))
+            return;
+
+        throw new GLib.Error(Gio.DBusError,
+            Gio.DBusError.ACCESS_DENIED,
+            '%s is not allowed'.format(invocation.get_method_name()));
+    }
+
+    /**
+     * @returns {void}
+     */
+    destroy() {
+        for (const id in this._watchList)
+            Gio.DBus.unwatch_name(id);
+        this._watchList = [];
+    }
+};


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]