NetworkManager: show portal logins when required

Listen to changes in connectivity, and ask our helper to authenticate
when needed.
We don't have a URL to connect to yet (we will have when
the new NM API lands), so we use the default of trying
www.gnome.org (which is also more reliable because we can
recognize when the login is done)

https://bugzilla.gnome.org/show_bug.cgi?id=704416
This commit is contained in:
Giovanni Campagna 2014-02-17 18:06:35 +01:00
parent 8c67a70db0
commit 47c9243271

View File

@ -44,6 +44,33 @@ const NM80211Mode = NetworkManager['80211Mode'];
const NM80211ApFlags = NetworkManager['80211ApFlags']; const NM80211ApFlags = NetworkManager['80211ApFlags'];
const NM80211ApSecurityFlags = NetworkManager['80211ApSecurityFlags']; const NM80211ApSecurityFlags = NetworkManager['80211ApSecurityFlags'];
const PortalHelperResult = {
CANCELLED: 0,
COMPLETED: 1,
RECHECK: 2
};
const PortalHelperIface = '<node> \
<interface name="org.gnome.Shell.PortalHelper"> \
<method name="Authenticate"> \
<arg type="o" direction="in" name="connection" /> \
<arg type="s" direction="in" name="url" /> \
<arg type="u" direction="in" name="timestamp" /> \
</method> \
<method name="Close"> \
<arg type="o" direction="in" name="connection" /> \
</method> \
<method name="Refresh"> \
<arg type="o" direction="in" name="connection" /> \
</method> \
<signal name="Done"> \
<arg type="o" name="connection" /> \
<arg type="u" name="result" /> \
</signal> \
</interface> \
</node>';
const PortalHelperProxy = Gio.DBusProxy.makeProxyWrapper(PortalHelperIface);
function ssidCompare(one, two) { function ssidCompare(one, two) {
if (!one || !two) if (!one || !two)
return false; return false;
@ -1581,6 +1608,7 @@ const NMApplet = new Lang.Class({
this._activeConnections = [ ]; this._activeConnections = [ ];
this._connections = [ ]; this._connections = [ ];
this._connectivityQueue = [ ];
this._mainConnection = null; this._mainConnection = null;
this._mainConnectionIconChangedId = 0; this._mainConnectionIconChangedId = 0;
@ -1609,6 +1637,7 @@ const NMApplet = new Lang.Class({
this._client.connect('notify::primary-connection', Lang.bind(this, this._syncMainConnection)); this._client.connect('notify::primary-connection', Lang.bind(this, this._syncMainConnection));
this._client.connect('notify::activating-connection', Lang.bind(this, this._syncMainConnection)); this._client.connect('notify::activating-connection', Lang.bind(this, this._syncMainConnection));
this._client.connect('notify::active-connections', Lang.bind(this, this._syncVPNConnections)); this._client.connect('notify::active-connections', Lang.bind(this, this._syncVPNConnections));
this._client.connect('notify::connectivity', Lang.bind(this, this._syncConnectivity));
this._client.connect('device-added', Lang.bind(this, this._deviceAdded)); this._client.connect('device-added', Lang.bind(this, this._deviceAdded));
this._client.connect('device-removed', Lang.bind(this, this._deviceRemoved)); this._client.connect('device-removed', Lang.bind(this, this._deviceRemoved));
this._settings.connect('new-connection', Lang.bind(this, this._newConnection)); this._settings.connect('new-connection', Lang.bind(this, this._newConnection));
@ -1777,6 +1806,7 @@ const NMApplet = new Lang.Class({
} }
this._updateIcon(); this._updateIcon();
this._syncConnectivity();
}, },
_syncVPNConnections: function() { _syncVPNConnections: function() {
@ -1882,6 +1912,97 @@ const NMApplet = new Lang.Class({
_syncNMState: function() { _syncNMState: function() {
this.indicators.visible = this._client.manager_running; this.indicators.visible = this._client.manager_running;
this.menu.actor.visible = this._client.networking_enabled; this.menu.actor.visible = this._client.networking_enabled;
this._syncConnectivity();
},
_flushConnectivityQueue: function() {
if (this._portalHelperProxy) {
for (let item of this._connectivityQueue)
this._portalHelperProxy.CloseRemote(item);
}
this._connectivityQueue = [];
},
_closeConnectivityCheck: function(path) {
let index = this._connectivityQueue.indexOf(path);
if (index >= 0) {
if (this._portalHelperProxy)
this._portalHelperProxy.CloseRemote(path);
this._connectivityQueue.splice(index, 1);
}
},
_portalHelperDone: function(proxy, emitter, 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 he chooses a better connection
// or we get to full connectivity through other means
} else if (result == PortalHelperResult.COMPLETED) {
this._closeConnectivityCheck(path);
return;
} else if (result == PortalHelperResult.RECHECK) {
this._client.check_connectivity_async(null, Lang.bind(this, function(client, result) {
try {
let state = client.check_connectivity_finish(result);
if (state >= NetworkManager.ConnectivityState.FULL)
this._closeConnectivityCheck(path);
} catch(e) { }
}));
} else {
log('Invalid result from portal helper: ' + result);
}
},
_syncConnectivity: function() {
if (this._mainConnection == null ||
this._mainConnection.state != NetworkManager.ActiveConnectionState.ACTIVATED) {
this._flushConnectivityQueue();
return;
}
let isPortal = this._client.connectivity == NetworkManager.ConnectivityState.PORTAL;
// For testing, allow interpreting any value != FULL as PORTAL, because
// LIMITED (no upstream route after the default gateway) is easy to obtain
// with a tethered phone
// NONE is also possible, with a connection configured to force no default route
// (but in general we should only prompt a portal if we know there is a portal)
if (GLib.getenv('GNOME_SHELL_CONNECTIVITY_TEST') != null)
isPortal = isPortal || this._client.connectivity < NetworkManager.ConnectivityState.FULL;
if (!isPortal)
return;
let path = this._mainConnection.get_path();
for (let item of this._connectivityQueue) {
if (item == path)
return;
}
let timestamp = global.get_current_time();
if (this._portalHelperProxy) {
this._portalHelperProxy.AuthenticateRemote(path, '', timestamp);
} else {
new PortalHelperProxy(Gio.DBus.session, 'org.gnome.Shell.PortalHelper',
'/org/gnome/Shell/PortalHelper', Lang.bind(this, function (proxy, error) {
if (error) {
log('Error launching the portal helper: ' + error);
return;
}
this._portalHelperProxy = proxy;
proxy.connectSignal('Done', Lang.bind(this, this._portalHelperDone));
proxy.AuthenticateRemote(path, '', timestamp);
}));
}
this._connectivityQueue.push(path);
}, },
_updateIcon: function() { _updateIcon: function() {