diff -rup ubiquity-16.10.14.orig/debian/control ubiquity-16.10.14/debian/control --- ubiquity-16.10.14.orig/debian/control 2016-10-10 11:28:21.000000000 -0600 +++ ubiquity-16.10.14/debian/control 2017-02-22 13:36:05.075646832 -0700 @@ -3,7 +3,7 @@ Section: admin Priority: optional Maintainer: Ubuntu Installer Team Uploaders: Colin Watson , Evan Dandrea -Build-Depends: adwaita-icon-theme, apt, autopoint, bf-utf-source, check, dctrl-tools, debconf (>= 1.5.43), debconf-utils, debhelper (>= 9), devio, dh-autoreconf, dh-di (>= 3), dh-systemd, dpkg-dev (>= 1.15.7), gir1.2-soup-2.4, gir1.2-timezonemap-1.0, gir1.2-webkit2-4.0, gir1.2-xkl-1.0, gobject-introspection, imagemagick, intltool (>= 0.40.0), intltool-debian (>= 0.30+20040212), iso-codes, isoquery, keymapper (>= 0.5.3-7), libbogl-dev, libcairo2-dev, libdebconfclient0-dev (>= 0.68), libdebian-installer4-dev (>= 0.76), libgirepository1.0-dev, libglib2.0-dev, libgtk-3-dev (>= 3.20), libido3-0.1-dev, libindicator3-dev, libiw-dev (>= 27+28pre9), liblocale-gettext-perl, libparted-dev (>= 2.2), librsvg2-bin, libsubunit-dev, locales, pep8, pkg-config, po-debconf (>= 1.0), pyflakes3 (>= 0.7.2), python-gi-dev, python-scour, python3-all (>= 3.1), python3-apt (>= 0.7.100.3~), python3-cairo, python3-dbus, python3-gi, python3-gi-cairo, python3-icu (>= 1.0), python3-mock (>= 0.7.0), python3-pam, tzdata, ubuntu-artwork, udev, wget, xkb-data (>= 0.9), xkb-data-i18n, xvfb +Build-Depends: adwaita-icon-theme, apt, autopoint, bf-utf-source, check, dctrl-tools, debconf (>= 1.5.43), debconf-utils, debhelper (>= 9), devio, dh-autoreconf, dh-di (>= 3), dh-systemd, dpkg-dev (>= 1.15.7), gir1.2-soup-2.4, gir1.2-timezonemap-1.0, gir1.2-webkit2-4.0, gir1.2-xkl-1.0, gobject-introspection, imagemagick, intltool (>= 0.40.0), intltool-debian (>= 0.30+20040212), iso-codes, isoquery, keymapper (>= 0.5.3-7), libbogl-dev, libcairo2-dev, libdebconfclient0-dev (>= 0.68), libdebian-installer4-dev (>= 0.76), libgirepository1.0-dev, libglib2.0-dev, libgtk-3-dev (>= 3.20), libido3-0.1-dev, libindicator3-dev, libiw-dev (>= 27+28pre9), liblocale-gettext-perl, libnm-gtk-dev, libparted-dev (>= 2.2), librsvg2-bin, libsubunit-dev, locales, pep8, pkg-config, po-debconf (>= 1.0), pyflakes3 (>= 0.7.2), python-gi-dev, python-scour, python3-all (>= 3.1), python3-apt (>= 0.7.100.3~), python3-cairo, python3-dbus, python3-gi, python3-gi-cairo, python3-icu (>= 1.0), python3-mock (>= 0.7.0), python3-pam, tzdata, ubuntu-artwork, udev, wget, xkb-data (>= 0.9), xkb-data-i18n, xvfb Standards-Version: 3.9.4 X-Python3-Version: >= 3.1 XS-Testsuite: autopkgtest @@ -45,7 +45,7 @@ Description: Ubuntu artwork for Ubiquity Package: ubiquity-frontend-gtk Architecture: amd64 arm64 armhf i386 powerpc ppc64el Pre-Depends: ${misc:Pre-Depends} -Depends: ${shlibs:Depends}, ${misc:Depends}, ${python3:Depends}, ubiquity (= ${binary:Version}), python3-dbus, gir1.2-gtk-3.0 (>= 3.20), gir1.2-pango-1.0, gir1.2-soup-2.4, gir1.2-vte-2.91, gir1.2-webkit2-4.0, iso-codes, metacity | marco | xfwm4 | matchbox-window-manager | lubuntu-default-settings | openbox | gnome-shell, gir1.2-xkl-1.0, gir1.2-timezonemap-1.0, python3-gi, python3-cairo, python3-gi-cairo, gir1.2-appindicator3-0.1, busybox-static | busybox +Depends: ${shlibs:Depends}, ${misc:Depends}, ${python3:Depends}, ubiquity (= ${binary:Version}), python3-dbus, gir1.2-gtk-3.0 (>= 3.20), gir1.2-nmgtk-1.0, gir1.2-pango-1.0, gir1.2-soup-2.4, gir1.2-vte-2.91, gir1.2-webkit2-4.0, iso-codes, metacity | marco | xfwm4 | matchbox-window-manager | lubuntu-default-settings | openbox | gnome-shell, gir1.2-xkl-1.0, gir1.2-timezonemap-1.0, python3-gi, python3-cairo, python3-gi-cairo, gir1.2-appindicator3-0.1, busybox-static | busybox Suggests: gnome-control-center | feh Conflicts: ubuntu-express-frontend-gtk, espresso-frontend-gtk, ubiquity (<< 2.4.3) Replaces: ubuntu-express-frontend-gtk, espresso-frontend-gtk, ubiquity (<< 2.4.3) diff -rup ubiquity-16.10.14.orig/tests/test_gtkwidgets.py ubiquity-16.10.14/tests/test_gtkwidgets.py --- ubiquity-16.10.14.orig/tests/test_gtkwidgets.py 2016-09-08 14:06:44.000000000 -0600 +++ ubiquity-16.10.14/tests/test_gtkwidgets.py 2017-02-21 14:49:32.405999181 -0700 @@ -229,13 +229,13 @@ class NetworkManagerTests(unittest.TestC self.assertEqual(nm.decode_ssid(ssid), 'R\ufffdseau') def test_pixbuf_func(self): - iterator = self.model.append(None, ['/foo', 'Intel', 'Wireless']) + iterator = self.model.append(None, ['/foo', 'Intel', 'Wireless', None]) mock_cell = mock.Mock() tv = nmwidgets.NetworkManagerTreeView() tv.pixbuf_func(None, mock_cell, self.model, iterator, None) mock_cell.set_property.assert_called_with('pixbuf', None) # 0% strength, protected network - i = self.model.append(iterator, ['Orange', True, 0]) + i = self.model.append(iterator, ['Orange', True, 0, False]) tv.pixbuf_func(None, mock_cell, self.model, i, None) mock_cell.set_property.assert_called_with('pixbuf', tv.icons[5]) # 30% strength, protected network @@ -249,12 +249,12 @@ class NetworkManagerTests(unittest.TestC mock_cell.set_property.assert_called_with('pixbuf', tv.icons[4]) def test_data_func(self): - iterator = self.model.append(None, ['/foo', 'Intel', 'Wireless']) + iterator = self.model.append(None, ['/foo', 'Intel', 'Wireless', None]) mock_cell = mock.Mock() tv = nmwidgets.NetworkManagerTreeView() tv.data_func(None, mock_cell, self.model, iterator, None) mock_cell.set_property.assert_called_with('text', 'Intel Wireless') - i = self.model.append(iterator, ['Orange', True, 0]) + i = self.model.append(iterator, ['Orange', True, 0, False]) tv.data_func(None, mock_cell, self.model, i, None) mock_cell.set_property.assert_called_with('text', 'Orange') diff -rup ubiquity-16.10.14.orig/tests/test_wireless.py ubiquity-16.10.14/tests/test_wireless.py --- ubiquity-16.10.14.orig/tests/test_wireless.py 2016-09-08 14:06:44.000000000 -0600 +++ ubiquity-16.10.14/tests/test_wireless.py 2017-02-20 09:50:23.810731260 -0700 @@ -26,9 +26,11 @@ class WirelessTests(unittest.TestCase): @mock.patch('ubiquity.nm.NetworkManager.is_connected') def test_secure_ap_can_enter_password(self, is_connected): is_connected.return_value = False - iterator = self.model.append(None, ['/foo', 'Intel', 'Wireless']) - iterator_insecure = self.model.append(iterator, ['Insecure', False, 0]) - iterator_secure = self.model.append(iterator, ['Secure', True, 0]) + iterator = self.model.append(None, ['/foo', 'Intel', 'Wireless', None]) + iterator_insecure = self.model.append(iterator, ['Insecure', False, 0, + False]) + iterator_secure = self.model.append(iterator, ['Secure', True, 0, + False]) gtkwidgets.refresh() self.assertFalse(self.nmwidget.hbox.get_sensitive()) self.nmwidget.view.set_cursor( diff -rup ubiquity-16.10.14.orig/ubiquity/frontend/gtk_components/nmwidgets.py ubiquity-16.10.14/ubiquity/frontend/gtk_components/nmwidgets.py --- ubiquity-16.10.14.orig/ubiquity/frontend/gtk_components/nmwidgets.py 2016-10-06 10:01:12.000000000 -0600 +++ ubiquity-16.10.14/ubiquity/frontend/gtk_components/nmwidgets.py 2017-02-22 13:12:55.147666534 -0700 @@ -4,8 +4,9 @@ from dbus.mainloop.glib import DBusGMain DBusGMainLoop(set_as_default=True) from gi.repository import Gtk, GObject, GLib +from gi.repository import NetworkManager as NM, NMClient, NMGtk -from ubiquity.nm import QueuedCaller, NetworkStore, NetworkManager +from ubiquity.nm import decode_ssid, QueuedCaller, NetworkStore, NetworkManager class GLibQueuedCaller(QueuedCaller): @@ -22,7 +23,7 @@ class GLibQueuedCaller(QueuedCaller): class GtkNetworkStore(NetworkStore, Gtk.TreeStore): def __init__(self): NetworkStore.__init__(self) - Gtk.TreeStore.__init__(self, str, object, object) + Gtk.TreeStore.__init__(self, str, object, object, object) def get_device_ids(self): it = self.get_iter_first() @@ -33,7 +34,7 @@ class GtkNetworkStore(NetworkStore, Gtk. return lst def add_device(self, devid, vendor, model): - self.append(None, [devid, vendor, model]) + self.append(None, [devid, vendor, model, None]) def has_device(self, devid): return self._it_for_device(devid) is not None @@ -41,10 +42,10 @@ class GtkNetworkStore(NetworkStore, Gtk. def remove_devices_not_in(self, devids): self._remove_rows_not_in(None, devids) - def add_ap(self, devid, ssid, secure, strength): + def add_ap(self, devid, ssid, secure, strength, enterprise=False): dev_it = self._it_for_device(devid) assert dev_it - self.append(dev_it, [ssid, secure, strength]) + self.append(dev_it, [ssid, secure, strength, enterprise]) def has_ap(self, devid, ssid): return self._it_for_ap(devid, ssid) is not None @@ -98,6 +99,7 @@ class NetworkManagerTreeView(Gtk.TreeVie self.configure_icons() model = GtkNetworkStore() model.set_sort_column_id(0, Gtk.SortType.ASCENDING) + self.nm_client = NMClient.Client() # TODO eventually this will subclass GenericTreeModel. self.wifi_model = NetworkManager(model, GLibQueuedCaller, @@ -244,12 +246,63 @@ class NetworkManagerTreeView(Gtk.TreeVie else: return False + def find_ap(self, device, ssid): + for ap in device.get_access_points(): + if decode_ssid(ap.get_ssid()) == ssid: + return ap + return None + + def connect_with_dialog_response(self, dialog, response): + if response == Gtk.ResponseType.OK: + conn, dev, ap = dialog.get_connection() + self.nm_client.add_and_activate_connection( + conn, dev, None, None, None + ) + dialog.hide() + + def connect_with_dialog(self, dev_path, ssid): + device = self.nm_client.get_device_by_path(dev_path) + ap = self.find_ap(device, ssid) + + connection = NM.Connection() + connection.add_setting(NM.SettingConnection( + uuid=NM.utils_uuid_generate() + )) + connection.add_setting(NM.SettingWireless()) + + dialog = NMGtk.WifiDialog.new( + self.nm_client, + NMClient.RemoteSettings(), + connection, + device, + ap, + False + ) + dialog.connect("response", self.connect_with_dialog_response) + dialog.run() + def connect_to_selection(self, passphrase): model, iterator = self.get_selection().get_selected() + if iterator is None: + return ssid = model[iterator][0] parent = model.iter_parent(iterator) if parent: - self.wifi_model.connect_to_ap(model[parent][0], ssid, passphrase) + try: + if model[iterator][3]: + # If enterprise, show NMGtk dialog + self.connect_with_dialog(model[parent][0], ssid) + else: + self.wifi_model.connect_to_ap(model[parent][0], ssid, + passphrase) + except Exception as e: + dialog = Gtk.MessageDialog( + None, Gtk.DialogFlags.MODAL, + Gtk.MessageType.ERROR, Gtk.ButtonsType.CLOSE, + "Failed to connect to wireless network: {}".format(e) + ) + dialog.run() + dialog.hide() GObject.type_register(NetworkManagerTreeView) @@ -311,6 +364,9 @@ class NetworkManagerWidget(Gtk.Box): def select_usable_row(self): self.selection.select_path('0:0') + def reselect_current_row(self): + self.changed(self.selection) + def state_changed(self, state): self.emit('connection', state) @@ -327,9 +383,8 @@ class NetworkManagerWidget(Gtk.Box): return False def connect_to_ap(self, *args): - if self.password_is_valid(): - passphrase = self.password_entry.get_text() - self.view.connect_to_selection(passphrase) + passphrase = self.password_entry.get_text() + self.view.connect_to_selection(passphrase) def disconnect_from_ap(self): self.view.disconnect_from_ap() @@ -345,9 +400,14 @@ class NetworkManagerWidget(Gtk.Box): if not iterator: return row = selection.get_tree_view().get_model()[iterator] + enterprise = row[3] secure = row[1] ssid = row[0] - if secure: + if enterprise: + self.hbox.set_sensitive(False) + self.password_entry.set_text('') + self.emit('pw_validated', True) + elif secure: self.hbox.set_sensitive(True) passphrase = self.view.get_passphrase(ssid) self.password_entry.set_text(passphrase) diff -rup ubiquity-16.10.14.orig/ubiquity/nm.py ubiquity-16.10.14/ubiquity/nm.py --- ubiquity-16.10.14.orig/ubiquity/nm.py 2016-09-08 14:06:44.000000000 -0600 +++ ubiquity-16.10.14/ubiquity/nm.py 2017-02-21 14:30:48.398111517 -0700 @@ -15,6 +15,7 @@ DEVICE_TYPE_WIFI = 2 NM_STATE_DISCONNECTED = 20 NM_STATE_CONNECTING = 40 NM_STATE_CONNECTED_GLOBAL = 70 +NM_WPA_FLAGS_ENTERPRISE = 0x200 # TODO: DBus exceptions. Catch 'em all. @@ -100,7 +101,7 @@ class NetworkStore(object): def remove_devices_not_in(self, devids): raise NotImplementedError - def add_ap(self, devid, ssid, secure, strength): + def add_ap(self, devid, ssid, secure, strength, enterprise=False): raise NotImplementedError def has_ap(self, devid, ssid): @@ -155,7 +156,7 @@ class NetworkManager: else: return False - def connect_to_ap(self, device, ap, passphrase=None): + def connect_to_ap(self, device, ap, passphrase=None, enterprise=False): device_obj = self.bus.get_object(NM, device) ap_list = device_obj.GetAccessPoints(dbus_interface=NM_DEVICE_WIFI) saved_strength = 0 @@ -173,8 +174,12 @@ class NetworkManager: return obj = dbus.Dictionary(signature='sa{sv}') - if passphrase: + if enterprise: + # TODO: Show enterprise setup modal + pass + elif passphrase: obj['802-11-wireless-security'] = {'psk': passphrase} + self.active_conn, self.active_connection = ( self.manager.AddAndActivateConnection( obj, dbus.ObjectPath(device), dbus.ObjectPath(saved_path), @@ -245,13 +250,18 @@ class NetworkManager: ssid = get_prop(ap_obj, NM_AP, 'Ssid') if ssid: ssid = decode_ssid(ssid) + wpa_flags = get_prop(ap_obj, NM_AP, 'WpaFlags') + rsn_flags = get_prop(ap_obj, NM_AP, 'RsnFlags') strength = int(get_prop(ap_obj, NM_AP, 'Strength') or 0) - secure = (get_prop(ap_obj, NM_AP, 'WpaFlags') != 0 or - get_prop(ap_obj, NM_AP, 'RsnFlags') != 0) + secure = (wpa_flags != 0 or rsn_flags != 0) + enterprise = (wpa_flags & NM_WPA_FLAGS_ENTERPRISE != 0 or + rsn_flags & NM_WPA_FLAGS_ENTERPRISE != 0) + if self.model.has_ap(device_path, ssid): self.model.set_ap_strength(device_path, ssid, strength) else: - self.model.add_ap(device_path, ssid, secure, strength) + self.model.add_ap(device_path, ssid, secure, strength, + enterprise) ssids.append(ssid) self.model.remove_aps_not_in(device_path, ssids) self.model.remove_devices_not_in(devices) diff -rup ubiquity-16.10.14.orig/ubiquity/plugins/ubi-wireless.py ubiquity-16.10.14/ubiquity/plugins/ubi-wireless.py --- ubiquity-16.10.14.orig/ubiquity/plugins/ubi-wireless.py 2016-10-05 19:49:24.000000000 -0600 +++ ubiquity-16.10.14/ubiquity/plugins/ubi-wireless.py 2017-02-20 12:58:23.956002376 -0700 @@ -135,6 +135,8 @@ class PageGtk(WirelessPageBase): if self.use_wireless.get_active(): if not self.have_selection: self.nmwidget.select_usable_row() + else: + self.nmwidget.reselect_current_row() self.state_changed(None, self.state) else: frontend.connecting_spinner.hide() @@ -179,7 +181,6 @@ class PageGtk(WirelessPageBase): frontend.connecting_spinner.hide() frontend.connecting_spinner.stop() frontend.connecting_label.hide() - self.controller.allow_go_forward(True) frontend.translate_widget(frontend.back) self.back_normal = True