gnome-shell/portal-notify.patch
2024-07-23 10:29:02 -06:00

512 lines
18 KiB
Diff
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

From d77ed9ad5fdadcdefcc41fecf8200bd2bf47282d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Wed, 12 Jun 2024 13:13:41 +0200
Subject: [PATCH 1/3] network: Split out CaptivePortalHandler class
The handling of captive portals is going to be extended a bit,
so split out a proper class instead of mixing it in with the
indicator code.
---
js/ui/status/network.js | 151 +++++++++++++++++++++++-----------------
1 file changed, 87 insertions(+), 64 deletions(-)
diff --git a/js/ui/status/network.js b/js/ui/status/network.js
index 404733b74c..d34e947073 100644
--- a/js/ui/status/network.js
+++ b/js/ui/status/network.js
@@ -14,6 +14,7 @@ import * as Main from '../main.js';
import * as PopupMenu from '../popupMenu.js';
import * as MessageTray from '../messageTray.js';
import * as ModemManager from '../../misc/modemManager.js';
+import * as Signals from '../../misc/signals.js';
import * as Util from '../../misc/util.js';
import {Spinner} from '../animation.js';
@@ -1944,12 +1945,84 @@ class NMModemToggle extends NMDeviceToggle {
}
});
+class CaptivePortalHandler extends Signals.EventEmitter {
+ constructor(checkUri) {
+ super();
+
+ this._checkUri = checkUri;
+ this._connectivityQueue = new Set();
+ this._portalHelperProxy = null;
+ }
+
+ addConnection(path) {
+ if (this._connectivityQueue.has(path))
+ return;
+
+ this._launchPortalHelper(path).catch(logError);
+ }
+
+ removeConnection(path) {
+ if (this._connectivityQueue.delete(path))
+ this._portalHelperProxy?.CloseAsync(path);
+ }
+
+ _portalHelperDone(parameters) {
+ const [path, result] = parameters;
+
+ if (result === PortalHelperResult.CANCELLED) {
+ // Keep the connection in the queue, so the user is not
+ // spammed with more logins until we next flush the queue,
+ // which will happen once they choose a better connection
+ // or we get to full connectivity through other means
+ } else if (result === PortalHelperResult.COMPLETED) {
+ this.removeConnection(path);
+ } else if (result === PortalHelperResult.RECHECK) {
+ this.emit('recheck', path);
+ } else {
+ log(`Invalid result from portal helper: ${result}`);
+ }
+ }
+
+ async _launchPortalHelper(path) {
+ const timestamp = global.get_current_time();
+ if (!this._portalHelperProxy) {
+ this._portalHelperProxy = new Gio.DBusProxy({
+ g_connection: Gio.DBus.session,
+ g_name: 'org.gnome.Shell.PortalHelper',
+ g_object_path: '/org/gnome/Shell/PortalHelper',
+ g_interface_name: PortalHelperInfo.name,
+ g_interface_info: PortalHelperInfo,
+ });
+ this._portalHelperProxy.connectSignal('Done',
+ (proxy, emitter, params) => {
+ this._portalHelperDone(params);
+ });
+
+ try {
+ await this._portalHelperProxy.init_async(
+ GLib.PRIORITY_DEFAULT, null);
+ } catch (e) {
+ console.error(`Error launching the portal helper: ${e.message}`);
+ }
+ }
+
+ this._portalHelperProxy?.AuthenticateAsync(path, this._checkUri, timestamp).catch(logError);
+ this._connectivityQueue.add(path);
+ }
+
+ clear() {
+ for (const item of this._connectivityQueue)
+ this._portalHelperProxy?.CloseAsync(item);
+ this._connectivityQueue.clear();
+ }
+}
+
export const Indicator = GObject.registerClass(
class Indicator extends SystemIndicator {
_init() {
super._init();
- this._connectivityQueue = new Set();
+ this._portalHandler = null;
this._mainConnection = null;
@@ -2004,6 +2077,16 @@ class Indicator extends SystemIndicator {
this, 'visible',
GObject.BindingFlags.SYNC_CREATE);
+ const {connectivityCheckUri} = this._client;
+ this._portalHandler = new CaptivePortalHandler(connectivityCheckUri);
+ this._portalHandler.connect('recheck', async (o, path) => {
+ try {
+ const state = await this._client.check_connectivity_async(null);
+ if (state >= NM.ConnectivityState.FULL)
+ this._portalHandler.removeConnection(path);
+ } catch (e) { }
+ });
+
this._client.connectObject(
'notify::primary-connection', () => this._syncMainConnection(),
'notify::activating-connection', () => this._syncMainConnection(),
@@ -2066,42 +2149,10 @@ class Indicator extends SystemIndicator {
this._notification?.destroy();
}
- _flushConnectivityQueue() {
- for (let item of this._connectivityQueue)
- this._portalHelperProxy?.CloseAsync(item);
- this._connectivityQueue.clear();
- }
-
- _closeConnectivityCheck(path) {
- if (this._connectivityQueue.delete(path))
- this._portalHelperProxy?.CloseAsync(path);
- }
-
- async _portalHelperDone(parameters) {
- let [path, result] = parameters;
-
- if (result === PortalHelperResult.CANCELLED) {
- // Keep the connection in the queue, so the user is not
- // spammed with more logins until we next flush the queue,
- // which will happen once they choose a better connection
- // or we get to full connectivity through other means
- } else if (result === PortalHelperResult.COMPLETED) {
- this._closeConnectivityCheck(path);
- } else if (result === PortalHelperResult.RECHECK) {
- try {
- const state = await this._client.check_connectivity_async(null);
- if (state >= NM.ConnectivityState.FULL)
- this._closeConnectivityCheck(path);
- } catch (e) { }
- } else {
- log(`Invalid result from portal helper: ${result}`);
- }
- }
-
- async _syncConnectivity() {
+ _syncConnectivity() {
if (this._mainConnection == null ||
this._mainConnection.state !== NM.ActiveConnectionState.ACTIVATED) {
- this._flushConnectivityQueue();
+ this._portalHandler.clear();
return;
}
@@ -2116,35 +2167,7 @@ class Indicator extends SystemIndicator {
if (!isPortal || Main.sessionMode.isGreeter)
return;
- let path = this._mainConnection.get_path();
- if (this._connectivityQueue.has(path))
- return;
-
- let timestamp = global.get_current_time();
- if (!this._portalHelperProxy) {
- this._portalHelperProxy = new Gio.DBusProxy({
- g_connection: Gio.DBus.session,
- g_name: 'org.gnome.Shell.PortalHelper',
- g_object_path: '/org/gnome/Shell/PortalHelper',
- g_interface_name: PortalHelperInfo.name,
- g_interface_info: PortalHelperInfo,
- });
- this._portalHelperProxy.connectSignal('Done',
- (proxy, emitter, params) => {
- this._portalHelperDone(params).catch(logError);
- });
-
- try {
- await this._portalHelperProxy.init_async(
- GLib.PRIORITY_DEFAULT, null);
- } catch (e) {
- console.error(`Error launching the portal helper: ${e.message}`);
- }
- }
-
- this._portalHelperProxy?.AuthenticateAsync(path, this._client.connectivity_check_uri, timestamp).catch(logError);
-
- this._connectivityQueue.add(path);
+ this._portalHandler.addConnection(this._mainConnection.get_path());
}
_updateIcon() {
--
2.45.2
From cd489e54948e3f2900a1f4e354fd4bb43c62db6d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Wed, 12 Jun 2024 13:13:41 +0200
Subject: [PATCH 2/3] status/network: Show notification when detecting captive
portal
When NetworkManager detects limited connectivity, we currently
pop up the portal helper window immediately. This can both be
disruptive when it happens unexpectedly, and unnoticeable
when it happens during screen lock.
In any case, it seems better to not pop up a window without
explicit user action, so instead show a notification that
launches the portal window when activated.
Closes: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/7688
---
js/ui/status/network.js | 38 ++++++++++++++++++++++++++++++++++----
1 file changed, 34 insertions(+), 4 deletions(-)
diff --git a/js/ui/status/network.js b/js/ui/status/network.js
index d34e947073..5d1e168fb5 100644
--- a/js/ui/status/network.js
+++ b/js/ui/status/network.js
@@ -1951,19 +1951,43 @@ class CaptivePortalHandler extends Signals.EventEmitter {
this._checkUri = checkUri;
this._connectivityQueue = new Set();
+ this._notifications = new Map();
this._portalHelperProxy = null;
}
- addConnection(path) {
- if (this._connectivityQueue.has(path))
+ addConnection(name, path) {
+ if (this._connectivityQueue.has(path) || this._notifications.has(path))
return;
- this._launchPortalHelper(path).catch(logError);
+ const source = MessageTray.getSystemSource();
+
+ const notification = new MessageTray.Notification({
+ title: _('Sign Into WiFi Network'),
+ body: name,
+ source,
+ });
+ notification.connect('activated',
+ () => this._onNotificationActivated(path).catch(logError));
+ notification.connect('destroy',
+ () => this._notifications.delete(path));
+ this._notifications.set(path, notification);
+ source.addNotification(notification);
}
+
removeConnection(path) {
if (this._connectivityQueue.delete(path))
this._portalHelperProxy?.CloseAsync(path);
+ this._notifications.get(path)?.destroy(
+ MessageTray.NotificationDestroyedReason.SOURCE_CLOSED);
+ this._notifications.delete(path);
+ }
+
+ _onNotificationActivated(path) {
+ this._launchPortalHelper(path).catch(logError);
+
+ Main.overview.hide();
+ Main.panel.closeCalendar();
}
_portalHelperDone(parameters) {
@@ -2014,6 +2038,10 @@ class CaptivePortalHandler extends Signals.EventEmitter {
for (const item of this._connectivityQueue)
this._portalHelperProxy?.CloseAsync(item);
this._connectivityQueue.clear();
+
+ for (const n of this._notifications.values())
+ n.destroy(MessageTray.NotificationDestroyedReason.SOURCE_CLOSED);
+ this._notifications.clear();
}
}
@@ -2167,7 +2195,9 @@ class Indicator extends SystemIndicator {
if (!isPortal || Main.sessionMode.isGreeter)
return;
- this._portalHandler.addConnection(this._mainConnection.get_path());
+ this._portalHandler.addConnection(
+ this._mainConnection.get_id(),
+ this._mainConnection.get_path());
}
_updateIcon() {
--
2.45.2
From 52b8a150dd96086a48ba2ac7668b22e6429767fd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Wed, 12 Jun 2024 13:13:41 +0200
Subject: [PATCH 3/3] build: Add option to disable portal-helper
The portal login window uses WebKit, which is a security-sensitive
component that not all vendors want to support.
Support that case with a build option, and update the captive
portal handler to use the user's default browser if the portal-helper
is disabled.
---
data/icons/meson.build | 10 +++++++++-
data/meson.build | 2 +-
js/meson.build | 14 ++++++++------
js/misc/config.js.in | 2 ++
js/misc/meson.build | 1 +
js/ui/status/network.js | 15 +++++++++++----
meson.build | 5 +++++
meson_options.txt | 6 ++++++
src/meson.build | 2 +-
9 files changed, 44 insertions(+), 13 deletions(-)
diff --git a/data/icons/meson.build b/data/icons/meson.build
index eff6e4b530..277df017b2 100644
--- a/data/icons/meson.build
+++ b/data/icons/meson.build
@@ -1 +1,9 @@
-install_subdir('hicolor', install_dir: icondir)
+excluded_icons=[]
+if not have_portal_helper
+ excluded_icons += [
+ 'scalable/apps/org.gnome.Shell.CaptivePortal.svg',
+ 'symbolic/apps/org.gnome.Shell.CaptivePortal-symbolic.svg',
+ ]
+endif
+install_subdir('hicolor',
+ install_dir: icondir, exclude_files: excluded_icons)
diff --git a/data/meson.build b/data/meson.build
index 8654dfeca7..ed13b6baea 100644
--- a/data/meson.build
+++ b/data/meson.build
@@ -6,7 +6,7 @@ desktop_files = [
]
service_files = []
-if have_networkmanager
+if have_portal_helper
desktop_files += 'org.gnome.Shell.PortalHelper.desktop'
service_files += 'org.gnome.Shell.PortalHelper.service'
endif
diff --git a/js/meson.build b/js/meson.build
index 4809f82b83..e594e23627 100644
--- a/js/meson.build
+++ b/js/meson.build
@@ -8,9 +8,11 @@ js_resources = gnome.compile_resources(
dependencies: [config_js]
)
-portal_resources = gnome.compile_resources(
- 'portal-resources', 'portal-resources.gresource.xml',
- source_dir: ['.', meson.current_build_dir()],
- c_name: 'portal_js_resources',
- dependencies: [config_js]
-)
+if have_portal_helper
+ portal_resources = gnome.compile_resources(
+ 'portal-resources', 'portal-resources.gresource.xml',
+ source_dir: ['.', meson.current_build_dir()],
+ c_name: 'portal_js_resources',
+ dependencies: [config_js]
+ )
+endif
diff --git a/js/misc/config.js.in b/js/misc/config.js.in
index ad8d46d841..ce319e0f84 100644
--- a/js/misc/config.js.in
+++ b/js/misc/config.js.in
@@ -7,6 +7,8 @@ export const PACKAGE_NAME = '@PACKAGE_NAME@';
export const PACKAGE_VERSION = '@PACKAGE_VERSION@';
/* 1 if networkmanager is available, 0 otherwise */
export const HAVE_NETWORKMANAGER = @HAVE_NETWORKMANAGER@;
+/* 1 if portal helper is enabled, 0 otherwise */
+export const HAVE_PORTAL_HELPER = @HAVE_PORTAL_HELPER@;
/* gettext package */
export const GETTEXT_PACKAGE = '@GETTEXT_PACKAGE@';
/* locale dir */
diff --git a/js/misc/meson.build b/js/misc/meson.build
index 5aceefac42..5fc8ca433f 100644
--- a/js/misc/meson.build
+++ b/js/misc/meson.build
@@ -4,6 +4,7 @@ jsconf.set('PACKAGE_VERSION', meson.project_version())
jsconf.set('GETTEXT_PACKAGE', meson.project_name())
jsconf.set('LIBMUTTER_API_VERSION', mutter_api_version)
jsconf.set10('HAVE_NETWORKMANAGER', have_networkmanager)
+jsconf.set10('HAVE_PORTAL_HELPER', have_portal_helper)
jsconf.set('datadir', datadir)
jsconf.set('libexecdir', libexecdir)
diff --git a/js/ui/status/network.js b/js/ui/status/network.js
index 5d1e168fb5..cdc9ba8928 100644
--- a/js/ui/status/network.js
+++ b/js/ui/status/network.js
@@ -10,6 +10,7 @@ import Polkit from 'gi://Polkit';
import Shell from 'gi://Shell';
import St from 'gi://St';
+import * as Config from '../../misc/config.js';
import * as Main from '../main.js';
import * as PopupMenu from '../popupMenu.js';
import * as MessageTray from '../messageTray.js';
@@ -1967,7 +1968,7 @@ class CaptivePortalHandler extends Signals.EventEmitter {
source,
});
notification.connect('activated',
- () => this._onNotificationActivated(path).catch(logError));
+ () => this._onNotificationActivated(path));
notification.connect('destroy',
() => this._notifications.delete(path));
this._notifications.set(path, notification);
@@ -1984,7 +1985,13 @@ class CaptivePortalHandler extends Signals.EventEmitter {
}
_onNotificationActivated(path) {
- this._launchPortalHelper(path).catch(logError);
+ const context = global.create_app_launch_context(
+ global.get_current_time(), -1);
+
+ if (Config.HAVE_PORTAL_HELPER)
+ this._launchPortalHelper(path, context).catch(logError);
+ else
+ Gio.AppInfo.launch_default_for_uri(this._checkUri, context);
Main.overview.hide();
Main.panel.closeCalendar();
@@ -2007,8 +2014,7 @@ class CaptivePortalHandler extends Signals.EventEmitter {
}
}
- async _launchPortalHelper(path) {
- const timestamp = global.get_current_time();
+ async _launchPortalHelper(path, context) {
if (!this._portalHelperProxy) {
this._portalHelperProxy = new Gio.DBusProxy({
g_connection: Gio.DBus.session,
@@ -2030,6 +2036,7 @@ class CaptivePortalHandler extends Signals.EventEmitter {
}
}
+ const {timestamp} = context;
this._portalHelperProxy?.AuthenticateAsync(path, this._checkUri, timestamp).catch(logError);
this._connectivityQueue.add(path);
}
diff --git a/meson.build b/meson.build
index 035f54732a..4721bd6017 100644
--- a/meson.build
+++ b/meson.build
@@ -107,6 +107,11 @@ else
have_networkmanager = false
endif
+have_portal_helper = get_option('portal_helper')
+if have_portal_helper and not have_networkmanager
+ error('Portal helper requires networkmanager support')
+endif
+
if get_option('camera_monitor')
libpipewire_dep = dependency('libpipewire-0.3', version: pipewire_req)
have_pipewire = true
diff --git a/meson_options.txt b/meson_options.txt
index 6e83d92f2e..01e0d5803b 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -40,6 +40,12 @@ option('networkmanager',
description: 'Enable NetworkManager support'
)
+option('portal_helper',
+ type: 'boolean',
+ value: true,
+ description: 'Enable build-in network portal login'
+)
+
option('systemd',
type: 'boolean',
value: true,
diff --git a/src/meson.build b/src/meson.build
index 752104e120..a3bf542480 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -286,7 +286,7 @@ executable('gnome-shell', 'main.c',
install: true
)
-if have_networkmanager
+if have_portal_helper
executable('gnome-shell-portal-helper',
'gnome-shell-portal-helper.c', portal_resources,
c_args: tools_cflags,
--
2.45.2