diff --git a/.gitignore b/.gitignore index 351b699..5d85369 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -SOURCES/gnome-shell-40.9.tar.xz +SOURCES/gnome-shell-40.10.tar.xz diff --git a/.gnome-shell.metadata b/.gnome-shell.metadata index 89c206d..780dfaf 100644 --- a/.gnome-shell.metadata +++ b/.gnome-shell.metadata @@ -1 +1 @@ -83b12b5c9ca17de4e1d6e3c8d7371369957976c1 SOURCES/gnome-shell-40.9.tar.xz +c955a004fb650a83863d1151e3adbbd6758b1c2e SOURCES/gnome-shell-40.10.tar.xz diff --git a/SOURCES/0001-Revert-dash-Subtract-vertical-margins-from-availHeig.patch b/SOURCES/0001-Revert-dash-Subtract-vertical-margins-from-availHeig.patch new file mode 100644 index 0000000..a62d76e --- /dev/null +++ b/SOURCES/0001-Revert-dash-Subtract-vertical-margins-from-availHeig.patch @@ -0,0 +1,25 @@ +From a8c8b7ef31f7219157b94148b771f6f663928dea Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Tue, 19 Apr 2022 19:17:48 +0200 +Subject: [PATCH] Revert "dash: Subtract vertical margins from availHeight" + +This reverts commit 0de0a1f5940784eb4a7ca9ecf5e92f5277ceb0d8. +--- + js/ui/dash.js | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/js/ui/dash.js b/js/ui/dash.js +index f35cc2e25..0f1ca2c4c 100644 +--- a/js/ui/dash.js ++++ b/js/ui/dash.js +@@ -610,7 +610,6 @@ var Dash = GObject.registerClass({ + (iconChildren.length - 1) * spacing; + + let availHeight = this._maxHeight; +- availHeight -= this.margin_top + this.margin_bottom; + availHeight -= this._background.get_theme_node().get_vertical_padding(); + availHeight -= themeNode.get_vertical_padding(); + availHeight -= buttonHeight - iconHeight; +-- +2.35.1 + diff --git a/SOURCES/0001-kbdA11yDialog-Use-MetaKeyboardA11yFlags.patch b/SOURCES/0001-kbdA11yDialog-Use-MetaKeyboardA11yFlags.patch new file mode 100644 index 0000000..2ff43aa --- /dev/null +++ b/SOURCES/0001-kbdA11yDialog-Use-MetaKeyboardA11yFlags.patch @@ -0,0 +1,51 @@ +From bd4fef8354ff0730c1e96a47d77adbb4a4d7beaa Mon Sep 17 00:00:00 2001 +From: Olivier Fourdan +Date: Tue, 14 Jun 2022 16:38:27 +0200 +Subject: [PATCH] kbdA11yDialog: Use MetaKeyboardA11yFlags + +The change in mutter to move keyboard accessibility into backends needs +to be applied in gnome-shell as well, otherwise the keyboard +accessibility dialog cannot work. + +Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/2306 +Part-of: +--- + js/ui/kbdA11yDialog.js | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/js/ui/kbdA11yDialog.js b/js/ui/kbdA11yDialog.js +index a45e02443..60ec161a6 100644 +--- a/js/ui/kbdA11yDialog.js ++++ b/js/ui/kbdA11yDialog.js +@@ -1,5 +1,5 @@ + /* exported KbdA11yDialog */ +-const { Clutter, Gio, GObject } = imports.gi; ++const { Clutter, Gio, GObject, Meta } = imports.gi; + + const Dialog = imports.ui.dialog; + const ModalDialog = imports.ui.modalDialog; +@@ -25,17 +25,17 @@ class KbdA11yDialog extends GObject.Object { + let title, description; + let key, enabled; + +- if (whatChanged & Clutter.KeyboardA11yFlags.SLOW_KEYS_ENABLED) { ++ if (whatChanged & Meta.KeyboardA11yFlags.SLOW_KEYS_ENABLED) { + key = KEY_SLOW_KEYS_ENABLED; +- enabled = (newFlags & Clutter.KeyboardA11yFlags.SLOW_KEYS_ENABLED) > 0; ++ enabled = (newFlags & Meta.KeyboardA11yFlags.SLOW_KEYS_ENABLED) > 0; + title = enabled + ? _("Slow Keys Turned On") + : _("Slow Keys Turned Off"); + description = _('You just held down the Shift key for 8 seconds. This is the shortcut ' + + 'for the Slow Keys feature, which affects the way your keyboard works.'); +- } else if (whatChanged & Clutter.KeyboardA11yFlags.STICKY_KEYS_ENABLED) { ++ } else if (whatChanged & Meta.KeyboardA11yFlags.STICKY_KEYS_ENABLED) { + key = KEY_STICKY_KEYS_ENABLED; +- enabled = (newFlags & Clutter.KeyboardA11yFlags.STICKY_KEYS_ENABLED) > 0; ++ enabled = (newFlags & Meta.KeyboardA11yFlags.STICKY_KEYS_ENABLED) > 0; + title = enabled + ? _("Sticky Keys Turned On") + : _("Sticky Keys Turned Off"); +-- +2.36.1 + diff --git a/SOURCES/0001-status-volume-Hide-sliders-initially.patch b/SOURCES/0001-status-volume-Hide-sliders-initially.patch new file mode 100644 index 0000000..1600ab9 --- /dev/null +++ b/SOURCES/0001-status-volume-Hide-sliders-initially.patch @@ -0,0 +1,30 @@ +From b212b973175be1cbefa1da2c5ed4f58fae032c73 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Wed, 11 May 2022 02:34:21 +0200 +Subject: [PATCH] status/volume: Hide sliders initially + +We update the visibility on state or stream changes, but those +changes may never happen if pipewire-pulse/pulseaudio isn't +available (for example when running as root). + +Hiding the sliders is preferable in that case to showing non-working +controls. +--- + js/ui/status/volume.js | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/js/ui/status/volume.js b/js/ui/status/volume.js +index 7164e1054..f623ee680 100644 +--- a/js/ui/status/volume.js ++++ b/js/ui/status/volume.js +@@ -34,6 +34,7 @@ var StreamSlider = class { + this._control = control; + + this.item = new PopupMenu.PopupBaseMenuItem({ activate: false }); ++ this.item.hide(); + + this._inDrag = false; + this._notifyVolumeChangeId = 0; +-- +2.35.1 + diff --git a/SOURCES/fix-markup-in-highlighter.patch b/SOURCES/fix-markup-in-highlighter.patch new file mode 100644 index 0000000..b7509f6 --- /dev/null +++ b/SOURCES/fix-markup-in-highlighter.patch @@ -0,0 +1,334 @@ +From 49a950b9e0dc262fd20c28e21ee4815ea8efe758 Mon Sep 17 00:00:00 2001 +From: Sebastian Keller +Date: Tue, 16 Nov 2021 18:57:26 +0100 +Subject: [PATCH 1/3] search: Split out the description highlighter into its + own class + +No functional change yet, only preparation to allow adding a unit test +later on. + +Part-of: +--- + js/misc/util.js | 38 +++++++++++++++++++++++++++++++++++++- + js/ui/search.js | 12 +++++------- + 2 files changed, 42 insertions(+), 8 deletions(-) + +diff --git a/js/misc/util.js b/js/misc/util.js +index 8139d3f47..d1a702960 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, ++ Highlighter */ + + const { Clutter, Gio, GLib, Shell, St, GnomeDesktop } = imports.gi; + const Gettext = imports.gettext; +@@ -477,3 +478,38 @@ function GNOMEversionCompare(version1, version2) { + + return 0; + } ++ ++/* @class Highlighter Highlight given terms in text using markup. */ ++var Highlighter = class { ++ /** ++ * @param {?string[]} terms - list of terms to highlight ++ */ ++ constructor(terms) { ++ if (!terms) ++ return; ++ ++ const escapedTerms = terms ++ .map(term => Shell.util_regex_escape(term)) ++ .filter(term => term.length > 0); ++ ++ if (escapedTerms.length === 0) ++ return; ++ ++ this._highlightRegex = new RegExp('(%s)'.format( ++ escapedTerms.join('|')), 'gi'); ++ } ++ ++ /** ++ * Highlight all occurences of the terms defined for this ++ * highlighter in the provided text using markup. ++ * ++ * @param {string} text - text to highlight the defined terms in ++ * @returns {string} ++ */ ++ highlight(text) { ++ if (!this._highlightRegex) ++ return text; ++ ++ return text.replace(this._highlightRegex, '$1'); ++ } ++}; +diff --git a/js/ui/search.js b/js/ui/search.js +index 7300b053e..b1e76c46d 100644 +--- a/js/ui/search.js ++++ b/js/ui/search.js +@@ -10,6 +10,8 @@ const ParentalControlsManager = imports.misc.parentalControlsManager; + const RemoteSearch = imports.ui.remoteSearch; + const Util = imports.misc.util; + ++const { Highlighter } = imports.misc.util; ++ + const SEARCH_PROVIDERS_SCHEMA = 'org.gnome.desktop.search-providers'; + + var MAX_LIST_SEARCH_RESULTS_ROWS = 5; +@@ -596,7 +598,7 @@ var SearchResultsView = GObject.registerClass({ + + this._providers = []; + +- this._highlightRegex = null; ++ this._highlighter = new Highlighter(); + + this._searchSettings = new Gio.Settings({ schema_id: SEARCH_PROVIDERS_SCHEMA }); + this._searchSettings.connect('changed::disabled', this._reloadRemoteProviders.bind(this)); +@@ -739,8 +741,7 @@ var SearchResultsView = GObject.registerClass({ + if (this._searchTimeoutId == 0) + this._searchTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 150, this._onSearchTimeout.bind(this)); + +- let escapedTerms = this._terms.map(term => Shell.util_regex_escape(term)); +- this._highlightRegex = new RegExp('(%s)'.format(escapedTerms.join('|')), 'gi'); ++ this._highlighter = new Highlighter(this._terms); + + this.emit('terms-changed'); + } +@@ -894,10 +895,7 @@ var SearchResultsView = GObject.registerClass({ + if (!description) + return ''; + +- if (!this._highlightRegex) +- return description; +- +- return description.replace(this._highlightRegex, '$1'); ++ return this._highlighter.highlight(description); + } + }); + +-- +2.35.1 + + +From 7c1abe1bd91ecf274d81e122035cbeeef6fd58d4 Mon Sep 17 00:00:00 2001 +From: Sebastian Keller +Date: Wed, 17 Nov 2021 02:50:39 +0100 +Subject: [PATCH 2/3] util: Properly handle markup in highlighter + +The code to highlight matches did not properly escape the passed in text +as for markup before adding its highlighting markup. This lead to some +search result descriptions not showing up, because their descriptions +contained characters, such as "<", that would have to be escaped when +used in markup or otherwise lead to invalid markup. + +To work around this some search providers wrongly started escaping the +description on their end before sending them to gnome-shell. This lead +to another issue. Now if the highlighter was trying to highlight the +term "a", and the escaped description contained "'", the "a" in +that would be considered a match and surrounded by "". This +however would also generate invalid markup, again leading to an error +and the description not being shown. + +Fix this by always escaping the passed in string before applying the +highlights in such a way that there are no matches within entities. + +This also means that search providers that escaped their description +strings will now show up with the markup syntax. This will have to be +fixed separately in the affected search providers. + +Fixes: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/4791 +Part-of: +--- + js/misc/util.js | 21 +++++++++++++++++++-- + 1 file changed, 19 insertions(+), 2 deletions(-) + +diff --git a/js/misc/util.js b/js/misc/util.js +index d1a702960..802398d18 100644 +--- a/js/misc/util.js ++++ b/js/misc/util.js +@@ -508,8 +508,25 @@ var Highlighter = class { + */ + highlight(text) { + if (!this._highlightRegex) +- return text; ++ return GLib.markup_escape_text(text, -1); ++ ++ let escaped = []; ++ let lastMatchEnd = 0; ++ let match; ++ while ((match = this._highlightRegex.exec(text))) { ++ if (match.index > lastMatchEnd) { ++ let unmatched = GLib.markup_escape_text( ++ text.slice(lastMatchEnd, match.index), -1); ++ escaped.push(unmatched); ++ } ++ let matched = GLib.markup_escape_text(match[0], -1); ++ escaped.push('%s'.format(matched)); ++ lastMatchEnd = match.index + match[0].length; ++ } ++ let unmatched = GLib.markup_escape_text( ++ text.slice(lastMatchEnd), -1); ++ escaped.push(unmatched); + +- return text.replace(this._highlightRegex, '$1'); ++ return escaped.join(''); + } + }; +-- +2.35.1 + + +From 82e2a6dcfabc2f82efbf468175d16c303f0c73da Mon Sep 17 00:00:00 2001 +From: Sebastian Keller +Date: Wed, 17 Nov 2021 03:05:05 +0100 +Subject: [PATCH 3/3] tests: Add unit test for highlighter + +Part-of: +--- + tests/meson.build | 12 ++++- + tests/unit/highlighter.js | 106 ++++++++++++++++++++++++++++++++++++++ + 2 files changed, 117 insertions(+), 1 deletion(-) + create mode 100644 tests/unit/highlighter.js + +diff --git a/tests/meson.build b/tests/meson.build +index c0431631f..50fb601e9 100644 +--- a/tests/meson.build ++++ b/tests/meson.build +@@ -10,7 +10,17 @@ run_test = configure_file( + testenv = environment() + testenv.set('GSETTINGS_SCHEMA_DIR', join_paths(meson.build_root(), 'data')) + +-foreach test : ['insertSorted', 'jsParse', 'markup', 'params', 'url', 'versionCompare'] ++tests = [ ++ 'highlighter', ++ 'insertSorted', ++ 'jsParse', ++ 'markup', ++ 'params', ++ 'url', ++ 'versionCompare', ++] ++ ++foreach test : tests + test(test, run_test, + args: 'unit/@0@.js'.format(test), + env: testenv, +diff --git a/tests/unit/highlighter.js b/tests/unit/highlighter.js +new file mode 100644 +index 000000000..d582d38e3 +--- /dev/null ++++ b/tests/unit/highlighter.js +@@ -0,0 +1,106 @@ ++// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- ++ ++// Test cases for SearchResult description match highlighter ++ ++const JsUnit = imports.jsUnit; ++const Pango = imports.gi.Pango; ++ ++const Environment = imports.ui.environment; ++Environment.init(); ++ ++const Util = imports.misc.util; ++ ++const tests = [ ++ { input: 'abc cba', ++ terms: null, ++ output: 'abc cba' }, ++ { input: 'abc cba', ++ terms: [], ++ output: 'abc cba' }, ++ { input: 'abc cba', ++ terms: [''], ++ output: 'abc cba' }, ++ { input: 'abc cba', ++ terms: ['a'], ++ output: 'abc cba' }, ++ { input: 'abc cba', ++ terms: ['a', 'a'], ++ output: 'abc cba' }, ++ { input: 'CaSe InSenSiTiVe', ++ terms: ['cas', 'sens'], ++ output: 'CaSe InSenSiTiVe' }, ++ { input: 'This contains the < character', ++ terms: null, ++ output: 'This contains the < character' }, ++ { input: 'Don\'t', ++ terms: ['t'], ++ output: 'Don't' }, ++ { input: 'Don\'t', ++ terms: ['n\'t'], ++ output: 'Don't' }, ++ { input: 'Don\'t', ++ terms: ['o', 't'], ++ output: 'Don't' }, ++ { input: 'salt&pepper', ++ terms: ['salt'], ++ output: 'salt&pepper' }, ++ { input: 'salt&pepper', ++ terms: ['salt', 'alt'], ++ output: 'salt&pepper' }, ++ { input: 'salt&pepper', ++ terms: ['pepper'], ++ output: 'salt&pepper' }, ++ { input: 'salt&pepper', ++ terms: ['salt', 'pepper'], ++ output: 'salt&pepper' }, ++ { input: 'salt&pepper', ++ terms: ['t', 'p'], ++ output: 'salt&pepper' }, ++ { input: 'salt&pepper', ++ terms: ['t', '&', 'p'], ++ output: 'salt&pepper' }, ++ { input: 'salt&pepper', ++ terms: ['e'], ++ output: 'salt&pepper' }, ++ { input: 'salt&pepper', ++ terms: ['&a', '&am', '&', '&'], ++ output: 'salt&pepper' }, ++ { input: '&&&&&', ++ terms: ['a'], ++ output: '&&&&&' }, ++ { input: '&;&;&;&;&;', ++ terms: ['a'], ++ output: '&;&;&;&;&;' }, ++ { input: '&;&;&;&;&;', ++ terms: [';'], ++ output: '&;&;&;&;&;' }, ++ { input: '&', ++ terms: ['a'], ++ output: '&amp;' } ++]; ++ ++try { ++ for (let i = 0; i < tests.length; i++) { ++ let highlighter = new Util.Highlighter(tests[i].terms); ++ let output = highlighter.highlight(tests[i].input); ++ ++ JsUnit.assertEquals(`Test ${i + 1} highlight ` + ++ `"${tests[i].terms}" in "${tests[i].input}"`, ++ output, tests[i].output); ++ ++ let parsed = false; ++ try { ++ Pango.parse_markup(output, -1, ''); ++ parsed = true; ++ } catch (e) {} ++ JsUnit.assertEquals(`Test ${i + 1} is valid markup`, true, parsed); ++ } ++} catch (e) { ++ if (typeof(e.isJsUnitException) != 'undefined' ++ && e.isJsUnitException) ++ { ++ if (e.comment) ++ log(`Error in: ${e.comment}`); ++ } ++ throw e; ++} +-- +2.35.1 + diff --git a/SOURCES/restrict-dbus-callers.patch b/SOURCES/restrict-dbus-callers.patch new file mode 100644 index 0000000..914adcd --- /dev/null +++ b/SOURCES/restrict-dbus-callers.patch @@ -0,0 +1,1353 @@ +From eb26ea5e1bb0c6fc978aae5db99ed3427b34175b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Fri, 1 Apr 2022 19:40:31 +0200 +Subject: [PATCH 01/12] shell/global: Expose shim context property + +Parts of the following commits rely on the ShellGlobal:context +property that was added in GNOME 41 to expose the MetaContext +(likewise a GNOME 41 addition). + +To prepare for that, expose a small shim object as context +property that mimicks the expected upstream API. +--- + src/shell-global.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 92 insertions(+) + +diff --git a/src/shell-global.c b/src/shell-global.c +index 24e771f52..805c73145 100644 +--- a/src/shell-global.c ++++ b/src/shell-global.c +@@ -47,6 +47,9 @@ + + static ShellGlobal *the_object = NULL; + ++#define SHIM_TYPE_META_CONTEXT shim_meta_context_get_type () ++G_DECLARE_FINAL_TYPE (ShimMetaContext, shim_meta_context, SHIM, META_CONTEXT, GObject) ++ + struct _ShellGlobal { + GObject parent; + +@@ -54,6 +57,7 @@ struct _ShellGlobal { + + MetaBackend *backend; + MetaDisplay *meta_display; ++ ShimMetaContext *meta_context; + MetaWorkspaceManager *workspace_manager; + Display *xdisplay; + +@@ -92,6 +96,7 @@ enum { + + PROP_SESSION_MODE, + PROP_BACKEND, ++ PROP_CONTEXT, + PROP_DISPLAY, + PROP_WORKSPACE_MANAGER, + PROP_SCREEN_WIDTH, +@@ -235,6 +240,9 @@ shell_global_get_property(GObject *object, + case PROP_BACKEND: + g_value_set_object (value, global->backend); + break; ++ case PROP_CONTEXT: ++ g_value_set_object (value, global->meta_context); ++ break; + case PROP_DISPLAY: + g_value_set_object (value, global->meta_display); + break; +@@ -514,6 +522,13 @@ shell_global_class_init (ShellGlobalClass *klass) + "MetaBackend object", + META_TYPE_BACKEND, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); ++ g_object_class_install_property (gobject_class, ++ PROP_CONTEXT, ++ g_param_spec_object ("context", ++ "Context", ++ "MetaContext object", ++ G_TYPE_OBJECT, ++ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, + PROP_DISPLAY, + g_param_spec_object ("display", +@@ -996,6 +1011,7 @@ _shell_global_set_plugin (ShellGlobal *global, + + display = meta_plugin_get_display (plugin); + global->meta_display = display; ++ global->meta_context = g_object_new (SHIM_TYPE_META_CONTEXT, NULL); + global->workspace_manager = meta_display_get_workspace_manager (display); + + global->stage = CLUTTER_STAGE (meta_get_stage_for_display (display)); +@@ -1888,3 +1904,79 @@ _shell_global_locate_pointer (ShellGlobal *global) + { + g_signal_emit (global, shell_global_signals[LOCATE_POINTER], 0); + } ++ ++enum { ++ SHIM_PROP_0, ++ ++ SHIM_PROP_UNSAFE_MODE, ++ ++ N_SHIM_PROPS ++}; ++ ++static GParamSpec *shim_obj_props [N_SHIM_PROPS]; ++ ++struct _ShimMetaContext ++{ ++ GObject parent_instance; ++}; ++ ++G_DEFINE_TYPE (ShimMetaContext, shim_meta_context, G_TYPE_OBJECT); ++ ++static void ++shim_meta_context_get_property (GObject *object, ++ guint prop_id, ++ GValue *value, ++ GParamSpec *pspec) ++{ ++ switch (prop_id) ++ { ++ case SHIM_PROP_UNSAFE_MODE: ++ { ++ gboolean unsafe_mode; ++ ++ g_object_get (meta_get_backend (), "unsafe-mode", &unsafe_mode, NULL); ++ g_value_set_boolean (value, unsafe_mode); ++ } ++ break; ++ default: ++ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); ++ } ++} ++ ++static void ++shim_meta_context_set_property (GObject *object, ++ guint prop_id, ++ const GValue *value, ++ GParamSpec *pspec) ++{ ++ switch (prop_id) ++ { ++ case SHIM_PROP_UNSAFE_MODE: ++ g_object_set_property (G_OBJECT (meta_get_backend ()), "unsafe-mode", value); ++ break; ++ default: ++ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); ++ } ++} ++ ++static void ++shim_meta_context_class_init (ShimMetaContextClass *klass) ++{ ++ GObjectClass *object_class = G_OBJECT_CLASS (klass); ++ ++ object_class->get_property = shim_meta_context_get_property; ++ object_class->set_property = shim_meta_context_set_property; ++ ++ shim_obj_props[SHIM_PROP_UNSAFE_MODE] = ++ g_param_spec_boolean ("unsafe-mode", ++ "unsafe mode", ++ "Unsafe mode", ++ FALSE, ++ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); ++ g_object_class_install_properties (object_class, N_SHIM_PROPS, shim_obj_props); ++} ++ ++static void ++shim_meta_context_init (ShimMetaContext *self) ++{ ++} +-- +2.35.1 + + +From 20fcc7bc78a3c227304e89deddc57266e560175c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Thu, 2 Sep 2021 17:15:36 +0200 +Subject: [PATCH 02/12] panel: Show warning indicator when unsafe-mode is on + +MetaContext added an unsafe-mode property, which we will use to restrict +a number of privileged operations unless it is enabled. It is meant to +only be enabled temporarily for development/debugging purposes, so add +a scary icon to the top bar as a reminder to turn it off again. + +https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/3943 + +Part-of: +--- + js/ui/panel.js | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/js/ui/panel.js b/js/ui/panel.js +index 380480744..c57c3ba8e 100644 +--- a/js/ui/panel.js ++++ b/js/ui/panel.js +@@ -641,6 +641,20 @@ class PanelCorner extends St.DrawingArea { + } + }); + ++const UnsafeModeIndicator = GObject.registerClass( ++class UnsafeModeIndicator extends PanelMenu.SystemIndicator { ++ _init() { ++ super._init(); ++ ++ this._indicator = this._addIndicator(); ++ this._indicator.icon_name = 'channel-insecure-symbolic'; ++ ++ global.context.bind_property('unsafe-mode', ++ this._indicator, 'visible', ++ GObject.BindingFlags.SYNC_CREATE); ++ } ++}); ++ + var AggregateLayout = GObject.registerClass( + class AggregateLayout extends Clutter.BoxLayout { + _init(params = {}) { +@@ -702,6 +716,7 @@ class AggregateMenu extends PanelMenu.Button { + this._location = new imports.ui.status.location.Indicator(); + this._nightLight = new imports.ui.status.nightLight.Indicator(); + this._thunderbolt = new imports.ui.status.thunderbolt.Indicator(); ++ this._unsafeMode = new UnsafeModeIndicator(); + + this._indicators.add_child(this._remoteAccess); + this._indicators.add_child(this._thunderbolt); +@@ -713,6 +728,7 @@ class AggregateMenu extends PanelMenu.Button { + this._indicators.add_child(this._bluetooth); + this._indicators.add_child(this._rfkill); + this._indicators.add_child(this._volume); ++ this._indicators.add_child(this._unsafeMode); + this._indicators.add_child(this._power); + this._indicators.add_child(this._powerProfiles); + +-- +2.35.1 + + +From 158eeebc1d3a243e75de550cf5711e38a9f77f7f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Thu, 17 Jun 2021 01:50:50 +0200 +Subject: [PATCH 03/12] shellDBus: Use MetaContext:unsafe-mode to restrict + Eval() + +The Eval() method is unarguably the most sensitive D-Bus method +we expose, since it allows running arbitrary code in the compositor. + +It is currently tied to the `development-tools` settings that is +enabled by default. As users have become accustomed to the built-in +commands that are enabled by the same setting (restart, lg, ...), +that default cannot easily be changed. + +In order to restrict the method without affecting the rather harmless +commands, guard it by the new MetaContext:unsafe-mode property instead +of the setting. + +https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/3943 + +Part-of: +--- + js/ui/shellDBus.js | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/js/ui/shellDBus.js b/js/ui/shellDBus.js +index 734ca4fc7..5a6edec74 100644 +--- a/js/ui/shellDBus.js ++++ b/js/ui/shellDBus.js +@@ -54,7 +54,7 @@ var GnomeShell = class { + * + */ + Eval(code) { +- if (!global.settings.get_boolean('development-tools')) ++ if (!global.context.unsafe_mode) + return [false, '']; + + let returnValue; +-- +2.35.1 + + +From 0882e04a11fe8db7abf05a5d7c786664dc54ad4f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Thu, 2 Sep 2021 16:23:38 +0200 +Subject: [PATCH 04/12] introspect: Make invocation check error-based + +If we throw an error when the invocation isn't allowed instead of +returning false, we can simply return that error instead of duplicating +the error handling. + +Part-of: +--- + js/misc/introspect.js | 26 ++++++++++++++------------ + 1 file changed, 14 insertions(+), 12 deletions(-) + +diff --git a/js/misc/introspect.js b/js/misc/introspect.js +index e46a7e8c5..318955be2 100644 +--- a/js/misc/introspect.js ++++ b/js/misc/introspect.js +@@ -134,21 +134,23 @@ var IntrospectService = class { + type == Meta.WindowType.UTILITY; + } + +- _isInvocationAllowed(invocation) { ++ _checkInvocation(invocation) { + if (this._isIntrospectEnabled()) +- return true; ++ return; + + if (this._isSenderAllowed(invocation.get_sender())) +- return true; ++ return; + +- return false; ++ throw new GLib.Error(Gio.DBusError, ++ Gio.DBusError.ACCESS_DENIED, ++ 'App introspection not allowed'); + } + + GetRunningApplicationsAsync(params, invocation) { +- if (!this._isInvocationAllowed(invocation)) { +- invocation.return_error_literal(Gio.DBusError, +- Gio.DBusError.ACCESS_DENIED, +- 'App introspection not allowed'); ++ try { ++ this._checkInvocation(invocation); ++ } catch (e) { ++ invocation.return_gerror(e); + return; + } + +@@ -160,10 +162,10 @@ var IntrospectService = class { + let apps = this._appSystem.get_running(); + let windowsList = {}; + +- if (!this._isInvocationAllowed(invocation)) { +- invocation.return_error_literal(Gio.DBusError, +- Gio.DBusError.ACCESS_DENIED, +- 'App introspection not allowed'); ++ try { ++ this._checkInvocation(invocation); ++ } catch (e) { ++ invocation.return_gerror(e); + return; + } + +-- +2.35.1 + + +From 33c3c3846f62cc4737f0029455f9dcd838876bca Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Wed, 1 Sep 2021 21:18:42 +0200 +Subject: [PATCH 05/12] introspect: Use MetaContext:unsafe-mode instead of + setting + +The property was added precisely for this purpose, except that its +name isn't tied to the introspect API. + +https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/3943 + +Part-of: +--- + js/misc/introspect.js | 12 +----------- + 1 file changed, 1 insertion(+), 11 deletions(-) + +diff --git a/js/misc/introspect.js b/js/misc/introspect.js +index 318955be2..967e7b830 100644 +--- a/js/misc/introspect.js ++++ b/js/misc/introspect.js +@@ -1,8 +1,6 @@ + /* exported IntrospectService */ + const { Gio, GLib, Meta, Shell, St } = imports.gi; + +-const INTROSPECT_SCHEMA = 'org.gnome.shell'; +-const INTROSPECT_KEY = 'introspect'; + const APP_ALLOWLIST = ['org.freedesktop.impl.portal.desktop.gtk']; + + const INTROSPECT_DBUS_API_VERSION = 3; +@@ -33,10 +31,6 @@ var IntrospectService = class { + this._syncRunningApplications(); + }); + +- this._introspectSettings = new Gio.Settings({ +- schema_id: INTROSPECT_SCHEMA, +- }); +- + let tracker = Shell.WindowTracker.get_default(); + tracker.connect('notify::focus-app', + () => { +@@ -70,10 +64,6 @@ var IntrospectService = class { + return app.get_windows().some(w => w.transient_for == null); + } + +- _isIntrospectEnabled() { +- return this._introspectSettings.get_boolean(INTROSPECT_KEY); +- } +- + _isSenderAllowed(sender) { + return [...this._allowlistMap.values()].includes(sender); + } +@@ -135,7 +125,7 @@ var IntrospectService = class { + } + + _checkInvocation(invocation) { +- if (this._isIntrospectEnabled()) ++ if (global.context.unsafe_mode) + return; + + if (this._isSenderAllowed(invocation.get_sender())) +-- +2.35.1 + + +From 4238128ba403da2cc788b0b249ee34acbea5d743 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Wed, 1 Sep 2021 21:25:26 +0200 +Subject: [PATCH 06/12] data: Remove now unused "introspect" setting + +https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/3943 + +Part-of: +--- + data/org.gnome.shell.gschema.xml.in | 8 -------- + 1 file changed, 8 deletions(-) + +diff --git a/data/org.gnome.shell.gschema.xml.in b/data/org.gnome.shell.gschema.xml.in +index d5ea1e35f..6f1c424ba 100644 +--- a/data/org.gnome.shell.gschema.xml.in ++++ b/data/org.gnome.shell.gschema.xml.in +@@ -104,14 +104,6 @@ + number can be used to effectively disable the dialog. + + +- +- false +- Enable introspection API +- +- Enables a D-Bus API that allows to introspect the application state of +- the shell. +- +- + + +Date: Wed, 16 Jun 2021 19:09:42 +0200 +Subject: [PATCH 07/12] 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: +--- + js/misc/introspect.js | 30 ++++------------------- + js/misc/util.js | 56 ++++++++++++++++++++++++++++++++++++++++++- + 2 files changed, 59 insertions(+), 27 deletions(-) + +diff --git a/js/misc/introspect.js b/js/misc/introspect.js +index 967e7b830..e9d9260c0 100644 +--- a/js/misc/introspect.js ++++ b/js/misc/introspect.js +@@ -6,6 +6,7 @@ const APP_ALLOWLIST = ['org.freedesktop.impl.portal.desktop.gtk']; + const INTROSPECT_DBUS_API_VERSION = 3; + + const { loadInterfaceXML } = imports.misc.fileUtils; ++const { DBusSenderChecker } = imports.misc.util; + + const IntrospectDBusIface = loadInterfaceXML('org.gnome.Shell.Introspect'); + +@@ -40,14 +41,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', +@@ -64,10 +58,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); +@@ -124,21 +114,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; +@@ -153,7 +131,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 802398d18..e6c183fbf 100644 +--- a/js/misc/util.js ++++ b/js/misc/util.js +@@ -2,7 +2,7 @@ + /* exported findUrls, spawn, spawnCommandLine, spawnApp, trySpawnCommandLine, + formatTime, formatTimeSpan, createTimeLabel, insertSorted, + ensureActorVisibleInScrollView, wiggle, lerp, GNOMEversionCompare, +- Highlighter */ ++ DBusSenderChecker, Highlighter */ + + const { Clutter, Gio, GLib, Shell, St, GnomeDesktop } = imports.gi; + const Gettext = imports.gettext; +@@ -479,6 +479,60 @@ 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 = []; ++ } ++}; ++ + /* @class Highlighter Highlight given terms in text using markup. */ + var Highlighter = class { + /** +-- +2.35.1 + + +From c6679a876a3c73c2c691333a5b987e27965231f3 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Thu, 17 Jun 2021 15:29:42 +0200 +Subject: [PATCH 08/12] shellDBus: Implement all methods asynchronously + +In order to restrict callers, we will need access to the invocation, +not just the unpacked method parameters. + +https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/3943 + +Part-of: +--- + js/ui/shellDBus.js | 31 ++++++++++++++++++++++++++++--- + 1 file changed, 28 insertions(+), 3 deletions(-) + +diff --git a/js/ui/shellDBus.js b/js/ui/shellDBus.js +index 5a6edec74..aa5b4dc3c 100644 +--- a/js/ui/shellDBus.js ++++ b/js/ui/shellDBus.js +@@ -72,11 +72,26 @@ var GnomeShell = class { + return [success, returnValue]; + } + +- FocusSearch() { ++ /** ++ * Focus the overview's search entry ++ * ++ * @param {...any} params - method parameters ++ * @param {Gio.DBusMethodInvocation} invocation - the invocation ++ * @returns {void} ++ */ ++ FocusSearchAsync(params, invocation) { + Main.overview.focusSearch(); ++ invocation.return_value(null); + } + +- ShowOSD(params) { ++ /** ++ * Show OSD with the specified parameters ++ * ++ * @param {...any} params - method parameters ++ * @param {Gio.DBusMethodInvocation} invocation - the invocation ++ * @returns {void} ++ */ ++ ShowOSDAsync([params], invocation) { + for (let param in params) + params[param] = params[param].deep_unpack(); + +@@ -97,6 +112,7 @@ var GnomeShell = class { + icon = Gio.Icon.new_for_string(serializedIcon); + + Main.osdWindowManager.show(monitorIndex, icon, label, level, maxLevel); ++ invocation.return_value(null); + } + + /** +@@ -118,10 +134,19 @@ var GnomeShell = class { + } + + Main.overview.selectApp(id); ++ invocation.return_value(null); + } + +- ShowApplications() { ++ /** ++ * Show the overview's app grid ++ * ++ * @param {...any} params - method parameters ++ * @param {Gio.DBusMethodInvocation} invocation - the invocation ++ * @returns {void} ++ */ ++ ShowApplicationsAsync(params, invocation) { + Main.overview.show(ControlsState.APP_GRID); ++ invocation.return_value(null); + } + + GrabAcceleratorAsync(params, invocation) { +-- +2.35.1 + + +From 3ad733997eecb069be543f1a4452d7a7916a0962 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Thu, 17 Jun 2021 15:29:42 +0200 +Subject: [PATCH 09/12] shellDBus: Restrict callers + +The org.gnome.Shell interface provides a private API to other core +components to implement desktop functionalities like Settings or +global keybindings. It is not meant as a public API, so limit it +to a set of expected callers. + +https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/3943 + +Part-of: +--- + js/ui/shellDBus.js | 76 ++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 76 insertions(+) + +diff --git a/js/ui/shellDBus.js b/js/ui/shellDBus.js +index aa5b4dc3c..c511314f9 100644 +--- a/js/ui/shellDBus.js ++++ b/js/ui/shellDBus.js +@@ -10,6 +10,7 @@ const Main = imports.ui.main; + const Screenshot = imports.ui.screenshot; + + const { loadInterfaceXML } = imports.misc.fileUtils; ++const { DBusSenderChecker } = imports.misc.util; + const { ControlsState } = imports.ui.overviewControls; + + const GnomeShellIface = loadInterfaceXML('org.gnome.Shell'); +@@ -20,6 +21,11 @@ var GnomeShell = class { + this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(GnomeShellIface, this); + this._dbusImpl.export(Gio.DBus.session, '/org/gnome/Shell'); + ++ this._senderChecker = new DBusSenderChecker([ ++ 'org.gnome.ControlCenter', ++ 'org.gnome.SettingsDaemon.MediaKeys', ++ ]); ++ + this._extensionsService = new GnomeShellExtensions(); + this._screenshotService = new Screenshot.ScreenshotService(); + +@@ -80,6 +86,13 @@ var GnomeShell = class { + * @returns {void} + */ + FocusSearchAsync(params, invocation) { ++ try { ++ this._senderChecker.checkInvocation(invocation); ++ } catch (e) { ++ invocation.return_gerror(e); ++ return; ++ } ++ + Main.overview.focusSearch(); + invocation.return_value(null); + } +@@ -92,6 +105,13 @@ var GnomeShell = class { + * @returns {void} + */ + ShowOSDAsync([params], invocation) { ++ try { ++ this._senderChecker.checkInvocation(invocation); ++ } catch (e) { ++ invocation.return_gerror(e); ++ return; ++ } ++ + for (let param in params) + params[param] = params[param].deep_unpack(); + +@@ -124,6 +144,13 @@ var GnomeShell = class { + * @returns {void} + */ + FocusAppAsync([id], invocation) { ++ try { ++ this._senderChecker.checkInvocation(invocation); ++ } catch (e) { ++ invocation.return_gerror(e); ++ return; ++ } ++ + const appSys = Shell.AppSystem.get_default(); + if (appSys.lookup_app(id) === null) { + invocation.return_error_literal( +@@ -145,11 +172,25 @@ var GnomeShell = class { + * @returns {void} + */ + ShowApplicationsAsync(params, invocation) { ++ try { ++ this._senderChecker.checkInvocation(invocation); ++ } catch (e) { ++ invocation.return_gerror(e); ++ return; ++ } ++ + Main.overview.show(ControlsState.APP_GRID); + invocation.return_value(null); + } + + GrabAcceleratorAsync(params, invocation) { ++ try { ++ this._senderChecker.checkInvocation(invocation); ++ } catch (e) { ++ invocation.return_gerror(e); ++ return; ++ } ++ + let [accel, modeFlags, grabFlags] = params; + let sender = invocation.get_sender(); + let bindingAction = this._grabAcceleratorForSender(accel, modeFlags, grabFlags, sender); +@@ -157,6 +198,13 @@ var GnomeShell = class { + } + + GrabAcceleratorsAsync(params, invocation) { ++ try { ++ this._senderChecker.checkInvocation(invocation); ++ } catch (e) { ++ invocation.return_gerror(e); ++ return; ++ } ++ + let [accels] = params; + let sender = invocation.get_sender(); + let bindingActions = []; +@@ -168,6 +216,13 @@ var GnomeShell = class { + } + + UngrabAcceleratorAsync(params, invocation) { ++ try { ++ this._senderChecker.checkInvocation(invocation); ++ } catch (e) { ++ invocation.return_gerror(e); ++ return; ++ } ++ + let [action] = params; + let sender = invocation.get_sender(); + let ungrabSucceeded = this._ungrabAcceleratorForSender(action, sender); +@@ -176,6 +231,13 @@ var GnomeShell = class { + } + + UngrabAcceleratorsAsync(params, invocation) { ++ try { ++ this._senderChecker.checkInvocation(invocation); ++ } catch (e) { ++ invocation.return_gerror(e); ++ return; ++ } ++ + let [actions] = params; + let sender = invocation.get_sender(); + let ungrabSucceeded = true; +@@ -256,6 +318,13 @@ var GnomeShell = class { + } + + ShowMonitorLabelsAsync(params, invocation) { ++ try { ++ this._senderChecker.checkInvocation(invocation); ++ } catch (e) { ++ invocation.return_gerror(e); ++ return; ++ } ++ + let sender = invocation.get_sender(); + let [dict] = params; + Main.osdMonitorLabeler.show(sender, dict); +@@ -263,6 +332,13 @@ var GnomeShell = class { + } + + HideMonitorLabelsAsync(params, invocation) { ++ try { ++ this._senderChecker.checkInvocation(invocation); ++ } catch (e) { ++ invocation.return_gerror(e); ++ return; ++ } ++ + let sender = invocation.get_sender(); + Main.osdMonitorLabeler.hide(sender); + invocation.return_value(null); +-- +2.35.1 + + +From 5b87782b4950742b6ae1b29777e7812c93892ad7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Wed, 16 Jun 2021 22:11:50 +0200 +Subject: [PATCH 10/12] screenshot: Restrict callers + +The shell D-Bus API was always meant as a private API for core +components, so enforce that by limiting caller to a list of +allowed well-known names. + +Applications that want to request a screenshot can use the corresponding +desktop portal. + +https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/3943 + +Part-of: +--- + js/ui/screenshot.js | 28 ++++++++++++++++++++++++++++ + 1 file changed, 28 insertions(+) + +diff --git a/js/ui/screenshot.js b/js/ui/screenshot.js +index 81ab516b1..bf537b7d6 100644 +--- a/js/ui/screenshot.js ++++ b/js/ui/screenshot.js +@@ -15,6 +15,7 @@ Gio._promisify(Shell.Screenshot.prototype, + 'screenshot_area', 'screenshot_area_finish'); + + const { loadInterfaceXML } = imports.misc.fileUtils; ++const { DBusSenderChecker } = imports.misc.util; + + const ScreenshotIface = loadInterfaceXML('org.gnome.Shell.Screenshot'); + +@@ -24,6 +25,12 @@ var ScreenshotService = class { + this._dbusImpl.export(Gio.DBus.session, '/org/gnome/Shell/Screenshot'); + + this._screenShooter = new Map(); ++ this._senderChecker = new DBusSenderChecker([ ++ 'org.gnome.SettingsDaemon.MediaKeys', ++ 'org.freedesktop.impl.portal.desktop.gtk', ++ 'org.freedesktop.impl.portal.desktop.gnome', ++ 'org.gnome.Screenshot', ++ ]); + + this._lockdownSettings = new Gio.Settings({ schema_id: 'org.gnome.desktop.lockdown' }); + +@@ -46,6 +53,13 @@ var ScreenshotService = class { + Gio.IOErrorEnum, Gio.IOErrorEnum.PERMISSION_DENIED, + 'Saving to disk is disabled'); + return null; ++ } else { ++ try { ++ this._senderChecker.checkInvocation(invocation); ++ } catch (e) { ++ invocation.return_gerror(e); ++ return null; ++ } + } + + let shooter = new Shell.Screenshot(); +@@ -254,6 +268,13 @@ var ScreenshotService = class { + } + + async SelectAreaAsync(params, invocation) { ++ try { ++ this._senderChecker.checkInvocation(invocation); ++ } catch (e) { ++ invocation.return_gerror(e); ++ return; ++ } ++ + let selectArea = new SelectArea(); + try { + let areaRectangle = await selectArea.selectAsync(); +@@ -269,6 +290,13 @@ var ScreenshotService = class { + } + + FlashAreaAsync(params, invocation) { ++ try { ++ this._senderChecker.checkInvocation(invocation); ++ } catch (e) { ++ invocation.return_gerror(e); ++ return; ++ } ++ + let [x, y, width, height] = params; + [x, y, width, height] = this._scaleArea(x, y, width, height); + if (!this._checkArea(x, y, width, height)) { +-- +2.35.1 + + +From b02e721663ed1481ff7b4cf40cae3a34d059d90c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Sat, 25 Sep 2021 14:15:32 +0200 +Subject: [PATCH 11/12] screenshot: Unrestrict PickColor + +Commit dd2cd6286cd3 restricted callers of the screenshot methods to +portal implementations, gnome-settings-daemon and gnome-screenshot. + +That restriction does make sense for the actual screenshot methods, +but `PickColor` is actually used by GTK in its color picker (and +therefore may be called from arbitrary applications). + +Fix this by unrestricting access to `PickColor` again. Considering that +the method is always interactive, it's not very privacy/security-sensitive +anyway. + +https://gitlab.gnome.org/GNOME/gtk/-/issues/4283 + +Part-of: +--- + js/ui/screenshot.js | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/js/ui/screenshot.js b/js/ui/screenshot.js +index bf537b7d6..ae1156f47 100644 +--- a/js/ui/screenshot.js ++++ b/js/ui/screenshot.js +@@ -37,7 +37,7 @@ var ScreenshotService = class { + Gio.DBus.session.own_name('org.gnome.Shell.Screenshot', Gio.BusNameOwnerFlags.REPLACE, null, null); + } + +- _createScreenshot(invocation, needsDisk = true) { ++ _createScreenshot(invocation, needsDisk = true, restrictCallers = true) { + let lockedDown = false; + if (needsDisk) + lockedDown = this._lockdownSettings.get_boolean('disable-save-to-disk'); +@@ -53,7 +53,7 @@ var ScreenshotService = class { + Gio.IOErrorEnum, Gio.IOErrorEnum.PERMISSION_DENIED, + 'Saving to disk is disabled'); + return null; +- } else { ++ } else if (restrictCallers) { + try { + this._senderChecker.checkInvocation(invocation); + } catch (e) { +@@ -311,7 +311,7 @@ var ScreenshotService = class { + } + + async PickColorAsync(params, invocation) { +- const screenshot = this._createScreenshot(invocation, false); ++ const screenshot = this._createScreenshot(invocation, false, false); + if (!screenshot) + return; + +-- +2.35.1 + + +From 9e8073afbf30aaea87aefd8201fc5e04f94edaf8 Mon Sep 17 00:00:00 2001 +From: Sebastian Keller +Date: Tue, 23 Nov 2021 02:48:04 +0100 +Subject: [PATCH 12/12] util: Wait for initial name owners in DBusSenderCheck + before checking + +Otherwise an allowed caller might get rejected if the call is right +after a gnome-shell restart and the watchers have not finished running +their callbacks yet. + +Fixes: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/4813 +Part-of: +(cherry picked from commit 85609a232d4088b058f23f4922b9a993dea95199) +--- + js/misc/introspect.js | 8 ++++---- + js/misc/util.js | 33 ++++++++++++++++++++++++++++----- + js/ui/screenshot.js | 18 +++++++++--------- + js/ui/shellDBus.js | 43 +++++++++++++++++++++++-------------------- + 4 files changed, 64 insertions(+), 38 deletions(-) + +diff --git a/js/misc/introspect.js b/js/misc/introspect.js +index e9d9260c0..f3c938af9 100644 +--- a/js/misc/introspect.js ++++ b/js/misc/introspect.js +@@ -114,9 +114,9 @@ var IntrospectService = class { + type == Meta.WindowType.UTILITY; + } + +- GetRunningApplicationsAsync(params, invocation) { ++ async GetRunningApplicationsAsync(params, invocation) { + try { +- this._senderChecker.checkInvocation(invocation); ++ await this._senderChecker.checkInvocation(invocation); + } catch (e) { + invocation.return_gerror(e); + return; +@@ -125,13 +125,13 @@ var IntrospectService = class { + invocation.return_value(new GLib.Variant('(a{sa{sv}})', [this._runningApplications])); + } + +- GetWindowsAsync(params, invocation) { ++ async GetWindowsAsync(params, invocation) { + let focusWindow = global.display.get_focus_window(); + let apps = this._appSystem.get_running(); + let windowsList = {}; + + try { +- this._senderChecker.checkInvocation(invocation); ++ await this._senderChecker.checkInvocation(invocation); + } catch (e) { + invocation.return_gerror(e); + return; +diff --git a/js/misc/util.js b/js/misc/util.js +index e6c183fbf..6a0f6f641 100644 +--- a/js/misc/util.js ++++ b/js/misc/util.js +@@ -486,20 +486,42 @@ var DBusSenderChecker = class { + constructor(allowList) { + this._allowlistMap = new Map(); + ++ this._uninitializedNames = new Set(allowList); ++ this._initializedPromise = new Promise(resolve => { ++ this._resolveInitialized = resolve; ++ }); ++ + 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)); ++ (conn_, name_, owner) => { ++ this._allowlistMap.set(name, owner); ++ this._checkAndResolveInitialized(name); ++ }, ++ () => { ++ this._allowlistMap.delete(name); ++ this._checkAndResolveInitialized(name); ++ }); + }); + } + + /** ++ * @param {string} name - bus name for which the watcher got initialized ++ */ ++ _checkAndResolveInitialized(name) { ++ if (this._uninitializedNames.delete(name) && ++ this._uninitializedNames.size === 0) ++ this._resolveInitialized(); ++ } ++ ++ /** ++ * @async + * @param {string} sender - the bus name that invoked the checked method + * @returns {bool} + */ +- _isSenderAllowed(sender) { ++ async _isSenderAllowed(sender) { ++ await this._initializedPromise; + return [...this._allowlistMap.values()].includes(sender); + } + +@@ -507,15 +529,16 @@ var DBusSenderChecker = class { + * Check whether the bus name that invoked @invocation maps + * to an entry in the allow list. + * ++ * @async + * @throws + * @param {Gio.DBusMethodInvocation} invocation - the invocation + * @returns {void} + */ +- checkInvocation(invocation) { ++ async checkInvocation(invocation) { + if (global.context.unsafe_mode) + return; + +- if (this._isSenderAllowed(invocation.get_sender())) ++ if (await this._isSenderAllowed(invocation.get_sender())) + return; + + throw new GLib.Error(Gio.DBusError, +diff --git a/js/ui/screenshot.js b/js/ui/screenshot.js +index ae1156f47..97fcfacd0 100644 +--- a/js/ui/screenshot.js ++++ b/js/ui/screenshot.js +@@ -37,7 +37,7 @@ var ScreenshotService = class { + Gio.DBus.session.own_name('org.gnome.Shell.Screenshot', Gio.BusNameOwnerFlags.REPLACE, null, null); + } + +- _createScreenshot(invocation, needsDisk = true, restrictCallers = true) { ++ async _createScreenshot(invocation, needsDisk = true, restrictCallers = true) { + let lockedDown = false; + if (needsDisk) + lockedDown = this._lockdownSettings.get_boolean('disable-save-to-disk'); +@@ -55,7 +55,7 @@ var ScreenshotService = class { + return null; + } else if (restrictCallers) { + try { +- this._senderChecker.checkInvocation(invocation); ++ await this._senderChecker.checkInvocation(invocation); + } catch (e) { + invocation.return_gerror(e); + return null; +@@ -200,7 +200,7 @@ var ScreenshotService = class { + "Invalid params"); + return; + } +- let screenshot = this._createScreenshot(invocation); ++ let screenshot = await this._createScreenshot(invocation); + if (!screenshot) + return; + +@@ -223,7 +223,7 @@ var ScreenshotService = class { + + async ScreenshotWindowAsync(params, invocation) { + let [includeFrame, includeCursor, flash, filename] = params; +- let screenshot = this._createScreenshot(invocation); ++ let screenshot = await this._createScreenshot(invocation); + if (!screenshot) + return; + +@@ -246,7 +246,7 @@ var ScreenshotService = class { + + async ScreenshotAsync(params, invocation) { + let [includeCursor, flash, filename] = params; +- let screenshot = this._createScreenshot(invocation); ++ let screenshot = await this._createScreenshot(invocation); + if (!screenshot) + return; + +@@ -269,7 +269,7 @@ var ScreenshotService = class { + + async SelectAreaAsync(params, invocation) { + try { +- this._senderChecker.checkInvocation(invocation); ++ await this._senderChecker.checkInvocation(invocation); + } catch (e) { + invocation.return_gerror(e); + return; +@@ -289,9 +289,9 @@ var ScreenshotService = class { + } + } + +- FlashAreaAsync(params, invocation) { ++ async FlashAreaAsync(params, invocation) { + try { +- this._senderChecker.checkInvocation(invocation); ++ await this._senderChecker.checkInvocation(invocation); + } catch (e) { + invocation.return_gerror(e); + return; +@@ -311,7 +311,7 @@ var ScreenshotService = class { + } + + async PickColorAsync(params, invocation) { +- const screenshot = this._createScreenshot(invocation, false, false); ++ const screenshot = await this._createScreenshot(invocation, false, false); + if (!screenshot) + return; + +diff --git a/js/ui/shellDBus.js b/js/ui/shellDBus.js +index c511314f9..39bba7aa3 100644 +--- a/js/ui/shellDBus.js ++++ b/js/ui/shellDBus.js +@@ -81,13 +81,14 @@ var GnomeShell = class { + /** + * Focus the overview's search entry + * ++ * @async + * @param {...any} params - method parameters + * @param {Gio.DBusMethodInvocation} invocation - the invocation + * @returns {void} + */ +- FocusSearchAsync(params, invocation) { ++ async FocusSearchAsync(params, invocation) { + try { +- this._senderChecker.checkInvocation(invocation); ++ await this._senderChecker.checkInvocation(invocation); + } catch (e) { + invocation.return_gerror(e); + return; +@@ -100,13 +101,14 @@ var GnomeShell = class { + /** + * Show OSD with the specified parameters + * ++ * @async + * @param {...any} params - method parameters + * @param {Gio.DBusMethodInvocation} invocation - the invocation + * @returns {void} + */ +- ShowOSDAsync([params], invocation) { ++ async ShowOSDAsync([params], invocation) { + try { +- this._senderChecker.checkInvocation(invocation); ++ await this._senderChecker.checkInvocation(invocation); + } catch (e) { + invocation.return_gerror(e); + return; +@@ -143,9 +145,9 @@ var GnomeShell = class { + * @param {Gio.DBusMethodInvocation} invocation - the invocation + * @returns {void} + */ +- FocusAppAsync([id], invocation) { ++ async FocusAppAsync([id], invocation) { + try { +- this._senderChecker.checkInvocation(invocation); ++ await this._senderChecker.checkInvocation(invocation); + } catch (e) { + invocation.return_gerror(e); + return; +@@ -167,13 +169,14 @@ var GnomeShell = class { + /** + * Show the overview's app grid + * ++ * @async + * @param {...any} params - method parameters + * @param {Gio.DBusMethodInvocation} invocation - the invocation + * @returns {void} + */ +- ShowApplicationsAsync(params, invocation) { ++ async ShowApplicationsAsync(params, invocation) { + try { +- this._senderChecker.checkInvocation(invocation); ++ await this._senderChecker.checkInvocation(invocation); + } catch (e) { + invocation.return_gerror(e); + return; +@@ -183,9 +186,9 @@ var GnomeShell = class { + invocation.return_value(null); + } + +- GrabAcceleratorAsync(params, invocation) { ++ async GrabAcceleratorAsync(params, invocation) { + try { +- this._senderChecker.checkInvocation(invocation); ++ await this._senderChecker.checkInvocation(invocation); + } catch (e) { + invocation.return_gerror(e); + return; +@@ -197,9 +200,9 @@ var GnomeShell = class { + invocation.return_value(GLib.Variant.new('(u)', [bindingAction])); + } + +- GrabAcceleratorsAsync(params, invocation) { ++ async GrabAcceleratorsAsync(params, invocation) { + try { +- this._senderChecker.checkInvocation(invocation); ++ await this._senderChecker.checkInvocation(invocation); + } catch (e) { + invocation.return_gerror(e); + return; +@@ -215,9 +218,9 @@ var GnomeShell = class { + invocation.return_value(GLib.Variant.new('(au)', [bindingActions])); + } + +- UngrabAcceleratorAsync(params, invocation) { ++ async UngrabAcceleratorAsync(params, invocation) { + try { +- this._senderChecker.checkInvocation(invocation); ++ await this._senderChecker.checkInvocation(invocation); + } catch (e) { + invocation.return_gerror(e); + return; +@@ -230,9 +233,9 @@ var GnomeShell = class { + invocation.return_value(GLib.Variant.new('(b)', [ungrabSucceeded])); + } + +- UngrabAcceleratorsAsync(params, invocation) { ++ async UngrabAcceleratorsAsync(params, invocation) { + try { +- this._senderChecker.checkInvocation(invocation); ++ await this._senderChecker.checkInvocation(invocation); + } catch (e) { + invocation.return_gerror(e); + return; +@@ -317,9 +320,9 @@ var GnomeShell = class { + this._grabbers.delete(name); + } + +- ShowMonitorLabelsAsync(params, invocation) { ++ async ShowMonitorLabelsAsync(params, invocation) { + try { +- this._senderChecker.checkInvocation(invocation); ++ await this._senderChecker.checkInvocation(invocation); + } catch (e) { + invocation.return_gerror(e); + return; +@@ -331,9 +334,9 @@ var GnomeShell = class { + invocation.return_value(null); + } + +- HideMonitorLabelsAsync(params, invocation) { ++ async HideMonitorLabelsAsync(params, invocation) { + try { +- this._senderChecker.checkInvocation(invocation); ++ await this._senderChecker.checkInvocation(invocation); + } catch (e) { + invocation.return_gerror(e); + return; +-- +2.35.1 + diff --git a/SPECS/gnome-shell.spec b/SPECS/gnome-shell.spec index bc17abd..4c92db5 100644 --- a/SPECS/gnome-shell.spec +++ b/SPECS/gnome-shell.spec @@ -1,8 +1,8 @@ %global tarball_version %%(echo %{version} | tr '~' '.') Name: gnome-shell -Version: 40.9 -Release: 2%{?dist} +Version: 40.10 +Release: 3%{?dist} Summary: Window management and application launching for GNOME License: GPLv2+ @@ -40,6 +40,11 @@ Patch38: add-power-profiles-menu.patch Patch39: 0001-status-network-Use-wwan-settings-panel-for-GSM-LTE-M.patch Patch40: 0001-welcomeDialog-Adapt-dialog-title.patch Patch41: 0001-main-Leak-the-GJS-context-and-ShellGlobal.patch +Patch42: fix-markup-in-highlighter.patch +Patch43: restrict-dbus-callers.patch +Patch44: 0001-Revert-dash-Subtract-vertical-margins-from-availHeig.patch +Patch45: 0001-status-volume-Hide-sliders-initially.patch +Patch46: 0001-kbdA11yDialog-Use-MetaKeyboardA11yFlags.patch %define eds_version 3.33.1 %define gnome_desktop_version 3.35.91 @@ -258,6 +263,32 @@ desktop-file-validate %{buildroot}%{_datadir}/applications/evolution-calendar.de %{_mandir}/man1/gnome-shell.1* %changelog +* Mon Jun 20 2022 Florian Müllner - 40.10-3 +- Fix keyboard a11y confirmation dialog + Resolves: #2047644 + +* Wed May 11 2022 Florian Müllner - 40.10-2 +- Hide volume sliders initially + Related: #2052808 + +* Tue Apr 19 2022 Florian Müllner - 40.10-1 +- Update to 40.10 + Related: #2066169 + +* Tue Apr 05 2022 Florian Müllner - 40.9-5 +- Keep new ShimMetaContext type private + Related: #2055366 + +* Fri Apr 01 2022 Florian Müllner - 40.9-4 +- Restrict D-Bus callers + Resolves: #2055366 + +* Wed Mar 30 2022 Florian Müllner - 40.9-3 +- Fix markup handling in highlighter + Resolves: #2049194 +- Fix warning on restacking + Resolves: #2053638 + * Mon Feb 28 2022 Ray Strode - 40.9-2 - Depend on and use background extension Related: #2057150