Exemplo n.º 1
0
class PasswordView(Gtk.Grid):
    def __init__(self, user, greeter):
        Gtk.Grid.__init__(self)

        self.get_style_context().add_class('password')
        self.set_row_spacing(10)

        self.greeter = greeter

        self.user = user
        self.title = self._set_title()

        self.attach(self.title.container, 0, 0, 1, 1)
        self.label = Gtk.Label(user)
        self.label.get_style_context().add_class('login')
        self.attach(self.label, 0, 1, 1, 1)
        self.password = Gtk.Entry()
        self.password.set_visibility(False)
        self.password.set_alignment(0.5)
        self.password.connect('activate', self._login_cb)
        self.attach(self.password, 0, 2, 1, 1)

        self.login_btn = KanoButton(_('Login').upper())
        self.login_btn.connect('clicked', self._login_cb)
        self.attach(self.login_btn, 0, 3, 1, 1)

        # Protect against removing the last Kano user
        # so you do not get locked out from logging into the Kit
        system_users = KanoUserList().get_users()
        if len(system_users) > 1:
            delete_account_btn = OrangeButton(_('Remove Account'))
            delete_account_btn.connect('clicked', self.delete_user)
            self.attach(delete_account_btn, 0, 4, 1, 1)

    def _set_title(self, create=True):
        '''
        Creates a Heading text widget, or updates it
        with the currently selected username.
        '''
        text_title = _('{}: Enter your password').format(self.user)
        text_description = _(
            'If you haven\'t changed your\npassword, use "kano"')

        if create:
            title = Heading(text_title, text_description)
            return title
        else:
            self.title.set_text(text_title, text_description)
            return self.title

    def _reset_greeter(self):
        # connect signal handlers to LightDM
        self.cb_one = self.greeter.connect('show-prompt',
                                           self._send_password_cb)
        self.cb_two = self.greeter.connect('authentication-complete',
                                           self._authentication_complete_cb)
        self.cb_three = self.greeter.connect('show-message',
                                             self._auth_error_cb)

        self.greeter.connect_sync()
        return (self.cb_one, self.cb_two, self.cb_three)

    def _login_cb(self, event=None, button=None):
        logger.debug('Sending username to LightDM')

        self.login_btn.start_spinner()
        Gtk.main_iteration_do(True)

        self.greeter.authenticate(self.user)

        if self.greeter.get_is_authenticated():
            logger.debug('User is already authenticated, starting session')
            start_session()

    def _send_password_cb(self, _greeter, text, prompt_type):
        logger.debug('Need to show prompt: {}'.format(text))

        if _greeter.get_in_authentication():
            logger.debug('Sending password to LightDM')
            _greeter.respond(self.password.get_text())

    def _authentication_complete_cb(self, _greeter):
        logger.debug('Authentication process is complete')

        if not _greeter.get_is_authenticated():
            logger.warn('Could not authenticate user {}'.format(self.user))
            self._auth_error_cb(
                _('Incorrect password (The default is "kano")'))

            return

        logger.info(
            'The user {} is authenticated. Starting LightDM X Session'.format(
                self.user))

        set_last_user(self.user)

        if not _greeter.start_session_sync('lightdm-xsession'):
            logger.error('Failed to start session')
        else:
            logger.info('Login failed')

    def _auth_error_cb(self, text, message_type=None):
        logger.info('There was an error logging in: {}'.format(text))

        self.greeter.cancel_authentication()

        self.login_btn.stop_spinner()
        self.password.set_text('')

        win = self.get_toplevel()
        error = KanoDialog(title_text=_('Error Logging In'),
                           description_text=text,
                           parent_window=win)
        error.dialog.set_position(Gtk.WindowPosition.CENTER_ALWAYS)
        error.run()
        win.go_to_users()

    def grab_focus(self, user):
        '''
        Update username title, clear previous password,
        and give focus to password entry field.
        '''
        self.user = user
        self._set_title(create=False)

        self.password.set_text('')
        self.password.grab_focus()

    def delete_user(self, *args):
        import pam

        password_input = Gtk.Entry()
        password_input.set_visibility(False)
        password_input.set_alignment(0.5)

        confirm = KanoDialog(
            title_text=_('Are you sure you want to delete this account?'),
            description_text=_(
                'Enter {}\'s password - A reboot will be required'.format(
                    self.user)),
            widget=password_input,
            has_entry=True,
            button_dict=[{
                'label': _('Cancel').upper(),
                'color': 'red',
                'return_value': False
            }, {
                'label': _('Ok').upper(),
                'color': 'green',
                'return_value': True
            }])

        confirm.dialog.set_position(Gtk.WindowPosition.CENTER_ALWAYS)

        # Kano Dialog will return False if cancel button is clicked, or text from the entry field if Ok
        response = confirm.run()
        if response == False:
            return
        elif type(response) == str and not len(response):
            error = KanoDialog(title_text=_(
                'Please enter the password for user {}'.format(self.user)))
            error.dialog.set_position(Gtk.WindowPosition.CENTER_ALWAYS)
            error.run()
            return
        else:
            password = response

        # Authenticate user and schedule removal. Protect against unknown troubles.
        try:
            if pam.authenticate(self.user, password):
                info = KanoDialog(title_text = _('User {} scheduled for removal'.format(self.user)), \
                                  description_text = _('Press OK to reboot'))
                info.dialog.set_position(Gtk.WindowPosition.CENTER_ALWAYS)
                info.run()

                os.system('sudo kano-init schedule delete-user "{}"'.format(
                    self.user))
                LightDM.restart()
            else:
                error = KanoDialog(title_text=_(
                    'Incorrect password for user {}'.format(self.user)))
                error.dialog.set_position(Gtk.WindowPosition.CENTER_ALWAYS)
                error.run()
        except Exception as e:
            logger.error('Error deleting account {} - {}'.format(
                self.user, str(e)))
            error = KanoDialog(
                title_text=_('Could not delete account {}'.format(self.user)))
            error.dialog.set_position(Gtk.WindowPosition.CENTER_ALWAYS)
            error.run()
Exemplo n.º 2
0
class SetProxy(Gtk.Box):
    def __init__(self, win):
        Gtk.Box.__init__(self, orientation=Gtk.Orientation.VERTICAL)
        self.kano_button = KanoButton()

        self.win = win
        self.win.set_main_widget(self)

        self.heading = Heading(
            _("Proxy"),
            _("Connect via a friend")
        )

        grid = Gtk.Grid(column_homogeneous=False, column_spacing=10, row_spacing=10)

        self.kano_button.connect('button-release-event', self.apply_changes)
        self.kano_button.connect('key-release-event', self.apply_changes)
        self.win.top_bar.enable_prev()
        self.win.change_prev_callback(self.go_to_wifi)

        self.ip_entry = Gtk.Entry()
        self.ip_entry.props.placeholder_text = _("IP address")
        self.ip_entry.connect('key-release-event', self.proxy_enabled)

        self.username_entry = Gtk.Entry()
        self.username_entry.props.placeholder_text = _("Username")
        self.username_entry.connect('key-release-event', self.proxy_enabled)

        self.port_entry = Gtk.Entry()
        self.port_entry.props.placeholder_text = _("Port")
        self.port_entry.connect('key-release-event', self.proxy_enabled)

        self.password_entry = Gtk.Entry()
        self.password_entry.props.placeholder_text = _("Password")
        self.password_entry.set_visibility(False)
        self.password_entry.connect('key-release-event', self.proxy_enabled)

        password_box = Gtk.Box()
        password_box.add(self.password_entry)

        self.checkbutton = Gtk.CheckButton(_("enable proxy"))
        self.read_config()
        self.checkbutton.connect('clicked', self.proxy_status)
        self.checkbutton.set_can_focus(False)

        bottom_row = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=0)
        bottom_row.pack_start(self.checkbutton, False, False, 0)
        bottom_row.pack_start(self.kano_button, False, False, 60)
        bottom_row.set_margin_bottom(30)
        bottom_row.set_margin_left(70)

        grid.attach(self.ip_entry, 0, 0, 2, 2)
        grid.attach(self.username_entry, 0, 2, 2, 2)
        grid.attach(self.port_entry, 2, 0, 2, 2)
        grid.attach(password_box, 2, 2, 3, 2)

        grid_alignment = Gtk.Alignment(xscale=0, xalign=0.5, yscale=0, yalign=0.2)
        grid_alignment.add(grid)

        self.pack_start(self.heading.container, False, False, 0)
        self.pack_start(grid_alignment, True, True, 0)
        self.pack_end(bottom_row, False, False, 0)

        self.proxy_status(self.checkbutton)
        self.kano_button.set_sensitive(False)

        # Change text of kano button depending on if proxy is enabled
        if self.checkbutton.get_active():
            self.kano_button.set_label(_("ENABLE PROXY"))
        else:
            self.kano_button.set_label(_("DISABLE PROXY"))

        self.win.show_all()

    def clear_entries(self):
        self.ip_entry.set_text("")
        self.username_entry.set_text("")
        self.port_entry.set_text("")
        self.password_entry.set_text("")

    def go_to_wifi(self, widget=None, event=None):
        self.win.clear_win()
        SetWifi(self.win)

    # Update for proxy
    def read_config(self):
        self.enable_proxy, data, _ = get_all_proxies()
        self.enabled_init = self.enable_proxy
        if self.enable_proxy:
            try:
                self.ip_entry.set_text(data['host'])
                self.port_entry.set_text(data['port'])
                if data['username']:
                    self.username_entry.set_text(data['username'])
                if data['password']:
                    self.password_entry.set_text(data['password'])
            except:
                # Something went wrong > disable proxy
                set_all_proxies(False)
                common.proxy_enabled = False
                self.enable_proxy = False
                self.enabled_init = False
                self.clear_entries()
        self.checkbutton.set_active(self.enable_proxy)

    def apply_changes(self, button, event):
        # If enter key is pressed or mouse button is clicked
        if not hasattr(event, 'keyval') or event.keyval == 65293:

            # This is a callback called by the main loop, so it's safe to
            # manipulate GTK objects:
            watch_cursor = Gdk.Cursor(Gdk.CursorType.WATCH)
            self.win.get_window().set_cursor(watch_cursor)
            self.kano_button.start_spinner()
            self.kano_button.set_sensitive(False)

            def lengthy_process():

                if self.enable_proxy:
                    host = self.ip_entry.get_text()
                    port = self.port_entry.get_text()
                    username = self.username_entry.get_text()
                    password = self.password_entry.get_text()
                    set_all_proxies(enable=True, host=host, port=port, username=username, password=password)
                    common.proxy_enabled = True

                    success, text = test_proxy()
                    if not success:
                        title = _("Error with proxy")
                        description = text
                        return_value = 1

                        # disable proxy if we couldn't successfully enable it
                        set_all_proxies(False)
                        common.proxy_enabled = False
                    else:
                        title = _("Successfully enabled proxy")
                        description = ""
                        return_value = 0

                else:
                    set_all_proxies(False)
                    common.proxy_enabled = False
                    title = _("Successfully disabled proxy")
                    description = ""
                    return_value = 0

                def done(title, description, return_value):
                    kdialog = KanoDialog(
                        title,
                        description,
                        [
                            {
                                'label': _("OK"),
                                'color': 'green',
                                'return_value': return_value
                            }
                        ],
                        parent_window=self.win
                    )
                    response = kdialog.run()
                    self.win.get_window().set_cursor(None)
                    self.kano_button.stop_spinner()

                    if response == 0:
                        self.go_to_wifi()
                    elif response == 1:
                        self.checkbutton.set_active(False)
                        self.kano_button.set_sensitive(False)

                GObject.idle_add(done, title, description, return_value)

            thread = threading.Thread(target=lengthy_process)
            thread.start()

    # Validation functions
    # If the "enable proxy" checkbox is checked/uncheckout, this function is activated
    # Disables the text entries if enable proxy is not checked
    def proxy_status(self, widget):
        self.enable_proxy = widget.get_active()
        if self.enable_proxy:
            self.ip_entry.set_sensitive(True)
            self.port_entry.set_sensitive(True)
            self.password_entry.set_sensitive(True)
            self.username_entry.set_sensitive(True)
            # Run to see if it need enabling
            self.proxy_enabled()
            self.kano_button.set_label(_("ENABLE PROXY"))

        else:
            self.ip_entry.set_sensitive(False)
            self.port_entry.set_sensitive(False)
            self.password_entry.set_sensitive(False)
            self.username_entry.set_sensitive(False)
            self.kano_button.set_label(_("DISABLE PROXY"))
            self.kano_button.set_sensitive(True)

    # if proxy enabled: ip address, port are mandatory
    def proxy_enabled(self, widget=None, event=None):
        # Get IP address
        # Get port
        # Get
        # If these entries are non empty, good - else, disable the next button
        ip_text = self.ip_entry.get_text()
        port_text = self.port_entry.get_text()

        if ip_text == "" or port_text == "":
            self.kano_button.set_sensitive(False)
            return False

        else:
            self.kano_button.set_sensitive(True)
            return True

        return False
class LoginWithKanoWorldView(Gtk.Grid):
    def __init__(self, greeter):
        Gtk.Grid.__init__(self)

        self.get_style_context().add_class('password')
        self.set_row_spacing(12)

        self.greeter = greeter

        title = Heading(_('Login with Kano World'),
                        _('Enter your Kano World details.'))
        self.attach(title.container, 0, 0, 1, 1)

        self.username = Gtk.Entry()
        self.username.set_placeholder_text('username')
        self.attach(self.username, 0, 1, 1, 1)

        self.password = Gtk.Entry()
        self.password.set_visibility(False)
        self.password.set_placeholder_text('password')
        self.attach(self.password, 0, 2, 1, 1)

        self.login_btn = KanoButton(_('LOGIN'))
        self.login_btn.connect('clicked', self._btn_login_pressed)
        self.attach(self.login_btn, 0, 3, 1, 1)

    def _btn_login_pressed(self, event=None, button=None):
        '''
        Authenticates against Kano World. If successful synchronizes to a local
        Unix account, and tells lightdm to go forward with local a login.
        '''
        logger.debug('Synchronizing Kano World account')
        self.login_btn.start_spinner()
        self.login_btn.set_sensitive(False)

        t = threading.Thread(target=self._thr_login)
        t.start()

    def _thr_login(self):
        loggedin = False
        reason = ''

        # TODO: Disable the "login" button unless these entry fields are non-empty
        # Collect credentials from the view
        self.unix_password = self.password.get_text()
        self.world_username = self.username.get_text()
        self.unix_username = self.username.get_text()
        atsign = self.unix_username.find('@')
        if atsign != -1:
            # For if we are in "staging" mode (see /etc/kano-world.conf)
            self.unix_username = self.unix_username[:atsign]

        # Now try to login to Kano World
        try:
            logger.debug('Authenticating user: {} to Kano World'.format(
                self.username.get_text()))
            (loggedin,
             reason) = kano_world_authenticate(self.username.get_text(),
                                               self.password.get_text())
            logger.debug('Kano World auth response: {} - {}'.format(
                loggedin, reason))
        except Exception as e:
            reason = str(e)
            logger.debug('Kano World auth Exception: {}'.format(reason))
            pass

        if not loggedin:
            # Kano world auth unauthorized
            # FIXME: Localizing the below string fails with an exception
            GObject.idle_add(self._error_message_box,
                             'Failed to authenticate to Kano World', reason)
            return
        else:
            # We are authenticated to Kano World: proceed with forcing local user
            rc = -1
            try:
                # Create the local unix user, bypass kano-init-flow, login & sync to Kano World
                createuser_cmd = 'sudo /usr/bin/kano-greeter-account {} {} {}'.format(
                    self.unix_username, self.unix_password,
                    self.world_username)
                _, _, rc = run_cmd(createuser_cmd)
                if rc == 0:
                    logger.debug('Local user created correctly: {}'.format(
                        self.unix_username))
                elif rc == 1:
                    logger.debug(
                        'Local user already exists, proceeding with login: {}'.
                        format(self.unix_username))

                created = True
            except:
                created = False

            if not created:
                logger.debug('Error creating new local user: {}'.format(
                    self.unix_username))
                GObject.idle_add(self._error_message_box,
                                 "Could not create local user", rc)
                return

            # Tell Lidghtdm to proceed with login session using the new user
            # We bind LightDM at this point only, this minimizes the number of attempts
            # to bind the Greeter class to a view, which he does not like quite well.
            logger.debug('Scheduling lightdm authentication in math thread')
            GObject.idle_add(self._auth_call)

    def _auth_call(self):
        logger.debug('Starting lightdm authentication')
        self._reset_greeter()
        self.greeter.authenticate(self.unix_username)
        if self.greeter.get_is_authenticated():
            logger.debug('User is already authenticated, starting session')

    def _reset_greeter(self):
        # connect signal handlers to LightDM
        self.cb_one = self.greeter.connect('show-prompt',
                                           self._send_password_cb)
        self.cb_two = self.greeter.connect('authentication-complete',
                                           self._authentication_complete_cb)
        self.cb_three = self.greeter.connect('show-message',
                                             self._auth_error_cb)
        self.greeter.connect_sync()
        return (self.cb_one, self.cb_two, self.cb_three)

    def _send_password_cb(self, _greeter, text, prompt_type):
        logger.debug('Need to show prompt: {}'.format(text))
        if _greeter.get_in_authentication():
            logger.debug('Sending password to LightDM')
            _greeter.respond(self.unix_password)

    def _authentication_complete_cb(self, _greeter):
        logger.debug('Authentication process is complete')

        if not _greeter.get_is_authenticated():
            logger.warn('Could not authenticate user {}'.format(
                self.unix_username))
            self._auth_error_cb(
                _('Incorrect password (The default is "kano")'))
            return

        logger.info(
            'The user {} is authenticated. Starting LightDM X Session'.format(
                self.unix_username))

        set_last_user(self.unix_username)

        if not _greeter.start_session_sync('lightdm-xsession'):
            logger.error('Failed to start session')
        else:
            logger.info('Login failed')

    def _auth_error_cb(self, text, message_type=None):
        logger.info('There was an error logging in: {}'.format(text))

        win = self.get_toplevel()
        win.go_to_users()

        self.login_btn.stop_spinner()
        self.login_btn.set_sensitive(True)
        self.newuser_btn.set_sensitive(True)

        error = KanoDialog(title_text=_('Error Synchronizing account'),
                           description_text=text,
                           parent_window=self.get_toplevel())
        error.dialog.set_position(Gtk.WindowPosition.CENTER_ALWAYS)
        error.run()

    def _error_message_box(self, title, description):
        '''
        Show a standard error message box
        '''
        self.login_btn.stop_spinner()
        self.login_btn.set_sensitive(True)

        errormsg = KanoDialog(title_text=title,
                              description_text=description,
                              button_dict=[{
                                  'label': _('OK').upper(),
                                  'color': 'red',
                                  'return_value': True
                              }])

        errormsg.dialog.set_position(Gtk.WindowPosition.CENTER_ALWAYS)
        errormsg.run()

        # Clean up password field
        self.password.set_text('')
        return

    def grab_focus(self):
        '''
        Clear username and password previous text, and gain focus.
        '''
        self.username.set_text('')
        self.password.set_text('')
class PasswordScreen(Gtk.Box):
    def __init__(
        self,
        win,
        wiface,
        network_name,
        encryption,
        wrong_password=False
    ):

        '''
        Show the screen with the option of adding a password
        and connecting to a network
        '''

        Gtk.Box.__init__(self, orientation=Gtk.Orientation.VERTICAL)

        self._win = win
        self._win.set_main_widget(self)
        self._win.top_bar.enable_prev()
        self._wiface = wiface
        self._network_name = network_name
        self._encryption = encryption

        # Keep track if the user has already entered the wrong password before
        # so that we only pack the "password incorrect" label once
        self._wrong_password_used_before = False

        self._heading = Heading(
            "Connect to the network",
            self._network_name,
            self._win.is_plug(),
            True
        )

        self._heading.set_prev_callback(self._refresh_networks)
        self._heading.container.set_margin_right(20)
        self._heading.container.set_margin_left(20)

        if wrong_password:
            image_path = os.path.join(img_dir, "password-fail.png")
            wrong_password = self._create_wrong_password_label()
            self._heading.container.pack_start(wrong_password, True, True, 0)
        else:
            image_path = os.path.join(img_dir, "password.png")

        self._padlock_image = Gtk.Image.new_from_file(image_path)

        self._password_entry = Gtk.Entry()
        self._password_entry.set_placeholder_text("Password")
        self._password_entry.set_visibility(False)
        self._password_entry.get_style_context().add_class("password_entry")
        self._password_entry.set_margin_left(60)
        self._password_entry.set_margin_right(60)
        self._password_entry.connect("key-release-event",
                                     self._set_button_sensitive)
        # If Enter key is pressed on the password entry, we want to act as
        # though the connect_btn was clicked
        self._password_entry.connect(
            "key-release-event", self._on_connect_key_wrapper
        )

        self._connect_btn = KanoButton("CONNECT")
        self._connect_btn.connect('clicked', self._on_connect)
        self._connect_btn.set_sensitive(False)
        self._connect_btn.set_margin_right(100)
        self._connect_btn.set_margin_left(100)
        self._connect_btn.pack_and_align()

        self._show_password = Gtk.CheckButton.new_with_label("Show password")
        self._show_password.get_style_context().add_class("show_password")
        self._show_password.connect("toggled",
                                    self._change_password_entry_visiblity)
        self._show_password.set_active(True)
        self._show_password.set_margin_left(100)

        vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        self.add(vbox)

        vbox.pack_start(self._heading.container, False, False, 10)
        vbox.pack_start(self._padlock_image, False, False, 10)
        vbox.pack_start(self._password_entry, False, False, 10)
        vbox.pack_start(self._show_password, False, False, 10)
        vbox.pack_end(self._connect_btn.align, False, False, 40)

        # Entry should have the keyboard focus
        self._password_entry.grab_focus()

        self.show_all()

    def _create_wrong_password_label(self):
        label = Gtk.Label("Password incorrect")
        label.get_style_context().add_class("wrong_password_label")
        return label

    def _change_password_entry_visiblity(self, widget):
        '''
        Depending on the checkbox, change the writing in the
        password entry to be readable.
        '''
        visibility = self._show_password.get_active()
        self._password_entry.set_visibility(visibility)

    def _refresh_networks(self, widget=None):
        from kano_wifi_gui.RefreshNetworks import RefreshNetworks
        RefreshNetworks(self._win)

    def _on_connect_key_wrapper(self, widget, event):
        if event.keyval == Gdk.KEY_Return:
            self._on_connect()

    def _on_connect(self, widget=None):
        passphrase = self._password_entry.get_text()
        ConnectToNetwork(
            self._win,
            self._network_name,
            passphrase,
            self._encryption
        )

    def _set_button_sensitive(self, widget, event):
        self._connect_btn.set_sensitive(True)

    def _thread_finish(self, success):

        if success:
            self._success_screen()
        else:
            self._wrong_password_screen()

    def _success_screen(self):
        self._win.remove_main_widget()

        title = "Success!"
        description = "You're connected"
        buttons = [
            {
                "label": "OK",
                "color": "green",
                "type": "KanoButton",
                "callback": Gtk.main_quit
            }
        ]
        img_path = os.path.join(img_dir, "internet.png")

        self._win.set_main_widget(
            Template(
                title,
                description,
                buttons,
                self._win.is_plug(),
                img_path
            )
        )

    def _disable_widgets_start_spinner(self):
        self._connect_btn.start_spinner()
        self._connect_btn.set_sensitive(False)
        self._win.top_bar.prev_button.set_sensitive(False)
        self._password_entry.set_sensitive(False)
        self._show_password.set_sensitive(False)

    def _enable_widgets_stop_spinner(self):
        self._connect_btn.stop_spinner()
        self._connect_btn.set_sensitive(True)
        self._win.top_bar.prev_button.set_sensitive(True)
        self._password_entry.set_sensitive(True)
        self._show_password.set_sensitive(True)
Exemplo n.º 5
0
class PasswordView(Gtk.Grid):

    def __init__(self, user, greeter):
        Gtk.Grid.__init__(self)

        self.get_style_context().add_class('password')
        self.set_row_spacing(10)

        self.greeter = greeter

        self.user = user
        self.title = self._set_title()

        self.attach(self.title.container, 0, 0, 1, 1)
        self.label = Gtk.Label(user)
        self.label.get_style_context().add_class('login')
        self.attach(self.label, 0, 1, 1, 1)
        self.password = Gtk.Entry()
        self.password.set_visibility(False)
        self.password.set_alignment(0.5)
        self.password.connect('activate', self._login_cb)
        self.attach(self.password, 0, 2, 1, 1)

        self.login_btn = KanoButton(_('Login').upper())
        self.login_btn.connect('clicked', self._login_cb)
        self.attach(self.login_btn, 0, 3, 1, 1)

        # Protect against removing the last Kano user
        # so you do not get locked out from logging into the Kit
        system_users = KanoUserList().get_users()
        if len(system_users) > 1:
            delete_account_btn = OrangeButton(_('Remove Account'))
            delete_account_btn.connect('clicked', self.delete_user)
            self.attach(delete_account_btn, 0, 4, 1, 1)

    def _set_title(self, create=True):
        '''
        Creates a Heading text widget, or updates it
        with the currently selected username.
        '''
        text_title = _('{}: Enter your password').format(self.user)
        text_description = _('If you haven\'t changed your\npassword, use "kano"')

        if create:
            title = Heading(text_title, text_description)
            return title
        else:
            self.title.set_text(text_title, text_description)
            return self.title

    def _reset_greeter(self):
        # connect signal handlers to LightDM
        self.cb_one = self.greeter.connect('show-prompt', self._send_password_cb)
        self.cb_two = self.greeter.connect('authentication-complete',
                                           self._authentication_complete_cb)
        self.cb_three = self.greeter.connect('show-message', self._auth_error_cb)

        self.greeter.connect_sync()
        return (self.cb_one, self.cb_two, self.cb_three)

    def _login_cb(self, event=None, button=None):
        logger.debug('Sending username to LightDM')

        self.login_btn.start_spinner()
        Gtk.main_iteration_do(True)

        # The call below will simply initiate the login flow.
        # The greeter library will inform us through callbacks
        # See: http://web.mit.edu/Source/debathena/config/lightdm-config/debian/debathena-lightdm-greeter
        self.greeter.authenticate(self.user)

    def _send_password_cb(self, _greeter, text, prompt_type):
        logger.debug(u'Need to show prompt: {}'.format(text))

        if _greeter.get_in_authentication():
            logger.debug('Sending password to LightDM')
            _greeter.respond(self.password.get_text())

    def _authentication_complete_cb(self, _greeter):
        logger.debug('Authentication process is complete')

        if not _greeter.get_is_authenticated():
            logger.warn('Could not authenticate user {}'.format(self.user))
            self._auth_error_cb(_('Incorrect password (The default is "kano")'))
            return

        logger.info(
            'The user {} is authenticated. Starting LightDM X Session'
            .format(self.user))

        set_last_user(self.user)

        if not _greeter.start_session_sync('lightdm-xsession'):
            logger.error('Failed to start session')
        else:
            logger.info('Login failed')

    def _auth_error_cb(self, text, message_type=None):
        logger.info(u'There was an error logging in: {}'.format(text))

        self.greeter.cancel_authentication()

        self.login_btn.stop_spinner()
        self.password.set_text('')

        win = self.get_toplevel()
        error = KanoDialog(
            title_text=_('Error Logging In'),
            description_text=text,
            parent_window=win
        )
        error.dialog.set_position(Gtk.WindowPosition.CENTER_ALWAYS)
        error.run()
        win.go_to_users()

    def grab_focus(self, user):
        '''
        Update username title, clear previous password,
        and give focus to password entry field.
        '''
        self.user = user
        self._set_title(create=False)

        self.password.set_text('')
        self.password.grab_focus()

    def delete_user(self, *args):
        import pam

        password_input = Gtk.Entry()
        password_input.set_visibility(False)
        password_input.set_alignment(0.5)

        confirm = KanoDialog(
            title_text = _('Are you sure you want to delete this account?'),
            description_text = _('Enter {}\'s password - A reboot will be required'.format(self.user)),
            widget=password_input,
            has_entry=True,
            button_dict = [
                {
                    'label': _('Cancel').upper(),
                    'color': 'red',
                    'return_value': False
                },
                {
                    'label': _('Ok').upper(),
                    'color': 'green',
                    'return_value': True
                }
            ])

        confirm.dialog.set_position(Gtk.WindowPosition.CENTER_ALWAYS)

        # Kano Dialog will return False if cancel button is clicked, or text
        # from the entry field if Ok
        response = confirm.run()
        if not response:
            return
        elif type(response) == str and not len(response):
            error = KanoDialog(
                title_text=_('Please enter the password for user {}'.format(self.user))
            )
            error.dialog.set_position(Gtk.WindowPosition.CENTER_ALWAYS)
            error.run()
            return
        else:
            password = response

        # Authenticate user and schedule removal. Protect against unknown troubles.
        try:
            if pam.authenticate(self.user, password):
                info = KanoDialog(
                    title_text=_('User {} scheduled for removal'.format(self.user)),
                    description_text=_('Press OK to reboot')
                )
                info.dialog.set_position(Gtk.WindowPosition.CENTER_ALWAYS)
                info.run()

                os.system('sudo kano-init schedule delete-user "{}"'.format(self.user))
                LightDM.restart()
            else:
                error = KanoDialog(
                    title_text=_('Incorrect password for user {}'.format(self.user))
                )
                error.dialog.set_position(Gtk.WindowPosition.CENTER_ALWAYS)
                error.run()
        except Exception as e:
            logger.error(u'Error deleting account {} - {}'.format(self.user, str(e)))
            error = KanoDialog(
                title_text=_('Could not delete account {}'.format(self.user))
            )
            error.dialog.set_position(Gtk.WindowPosition.CENTER_ALWAYS)
            error.run()
Exemplo n.º 6
0
class LoginWithKanoWorldView(Gtk.Grid):

    def __init__(self, greeter):
        Gtk.Grid.__init__(self)

        self.get_style_context().add_class('password')
        self.set_row_spacing(12)

        self.greeter = greeter

        title = Heading(_('Login with Kano World'),
                        _('Enter your Kano World details.'))
        self.attach(title.container, 0, 0, 1, 1)

        self.username = Gtk.Entry()
        self.username.set_placeholder_text('username')
        self.attach(self.username, 0, 1, 1, 1)

        self.password = Gtk.Entry()
        self.password.set_visibility(False)
        self.password.set_placeholder_text('password')
        self.attach(self.password, 0, 2, 1, 1)

        self.login_btn = KanoButton(_('LOGIN'))
        self.login_btn.connect('clicked', self._btn_login_pressed)
        self.attach(self.login_btn, 0, 3, 1, 1)

    def _btn_login_pressed(self, event=None, button=None):
        '''
        Authenticates against Kano World. If successful synchronizes to a local
        Unix account, and tells lightdm to go forward with local a login.
        '''
        logger.debug('Synchronizing Kano World account')
        self.login_btn.start_spinner()
        self.login_btn.set_sensitive(False)

        t = threading.Thread(target=self._thr_login)
        t.start()

    def _thr_login(self):
        loggedin = False
        reason = ''

        # TODO: Disable the "login" button unless these entry fields are non-empty
        # Collect credentials from the view
        self.unix_password = self.password.get_text()
        self.world_username = self.username.get_text()
        self.unix_username = self.username.get_text()
        atsign = self.unix_username.find('@')
        if atsign != -1:
            # For if we are in "staging" mode (see /etc/kano-world.conf)
            self.unix_username = self.unix_username[:atsign]

        # Now try to login to Kano World
        try:
            logger.debug('Authenticating user: {} to Kano World'.format(self.username.get_text()))
            (loggedin, reason) = kano_world_authenticate(self.username.get_text(), self.password.get_text())
            logger.debug('Kano World auth response: {} - {}'.format(loggedin, reason))
        except Exception as e:
            reason = str(e)
            logger.debug('Kano World auth Exception: {}'.format(reason))
            pass

        if not loggedin:
            # Kano world auth unauthorized
            # FIXME: Localizing the below string fails with an exception
            GObject.idle_add(self._error_message_box, 'Failed to authenticate to Kano World', reason)
            return
        else:
            # We are authenticated to Kano World: proceed with forcing local user
            rc = -1
            try:
                # Create the local unix user, bypass kano-init-flow, login & sync to Kano World
                createuser_cmd = 'sudo /usr/bin/kano-greeter-account {} {} {}'.format(
                    self.unix_username, self.unix_password, self.world_username)
                _, _, rc = run_cmd(createuser_cmd)
                if rc == 0:
                    logger.debug('Local user created correctly: {}'.format(self.unix_username))
                elif rc == 1:
                    logger.debug('Local user already exists, proceeding with login: {}'.format(self.unix_username))

                created = True
            except:
                created = False

            if not created:
                logger.debug('Error creating new local user: {}'.format(self.unix_username))
                GObject.idle_add(self._error_message_box, "Could not create local user", rc)
                return

            # Tell Lidghtdm to proceed with login session using the new user
            # We bind LightDM at this point only, this minimizes the number of attempts
            # to bind the Greeter class to a view, which he does not like quite well.
            logger.debug('Scheduling lightdm authentication in math thread')
            GObject.idle_add(self._auth_call)

    def _auth_call(self):
        logger.debug('Starting lightdm authentication')
        self._reset_greeter()
        self.greeter.authenticate(self.unix_username)
        if self.greeter.get_is_authenticated():
            logger.debug('User is already authenticated, starting session')

    def _reset_greeter(self):
        # connect signal handlers to LightDM
        self.cb_one = self.greeter.connect('show-prompt', self._send_password_cb)
        self.cb_two = self.greeter.connect('authentication-complete',
                                           self._authentication_complete_cb)
        self.cb_three = self.greeter.connect('show-message', self._auth_error_cb)
        self.greeter.connect_sync()
        return (self.cb_one, self.cb_two, self.cb_three)

    def _send_password_cb(self, _greeter, text, prompt_type):
        logger.debug('Need to show prompt: {}'.format(text))
        if _greeter.get_in_authentication():
            logger.debug('Sending password to LightDM')
            _greeter.respond(self.unix_password)

    def _authentication_complete_cb(self, _greeter):
        logger.debug('Authentication process is complete')

        if not _greeter.get_is_authenticated():
            logger.warn('Could not authenticate user {}'.format(self.unix_username))
            self._auth_error_cb(_('Incorrect password (The default is "kano")'))
            return

        logger.info(
            'The user {} is authenticated. Starting LightDM X Session'
            .format(self.unix_username))

        set_last_user(self.unix_username)

        if not _greeter.start_session_sync('lightdm-xsession'):
            logger.error('Failed to start session')
        else:
            logger.info('Login failed')

    def _auth_error_cb(self, text, message_type=None):
        logger.info('There was an error logging in: {}'.format(text))

        win = self.get_toplevel()
        win.go_to_users()

        self.login_btn.stop_spinner()
        self.login_btn.set_sensitive(True)
        self.newuser_btn.set_sensitive(True)

        error = KanoDialog(title_text=_('Error Synchronizing account'),
                           description_text=text,
                           parent_window=self.get_toplevel())
        error.dialog.set_position(Gtk.WindowPosition.CENTER_ALWAYS)
        error.run()

    def _error_message_box(self, title, description):
        '''
        Show a standard error message box
        '''
        self.login_btn.stop_spinner()
        self.login_btn.set_sensitive(True)

        errormsg = KanoDialog(title_text=title,
                              description_text=description,
                              button_dict=[
                                  {
                                      'label': _('OK').upper(),
                                      'color': 'red',
                                      'return_value': True
                                  }])

        errormsg.dialog.set_position(Gtk.WindowPosition.CENTER_ALWAYS)
        errormsg.run()

        # Clean up password field
        self.password.set_text('')
        return

    def grab_focus(self):
        '''
        Clear username and password previous text, and gain focus.
        '''
        self.username.set_text('')
        self.password.set_text('')
Exemplo n.º 7
0
class PasswordScreen(Gtk.Box):
    def __init__(self,
                 win,
                 wiface,
                 network_name,
                 encryption,
                 wrong_password=False):
        '''
        Show the screen with the option of adding a password
        and connecting to a network
        '''

        Gtk.Box.__init__(self, orientation=Gtk.Orientation.VERTICAL)

        self._win = win
        self._win.set_main_widget(self)
        self._win.top_bar.enable_prev()
        self._wiface = wiface
        self._network_name = network_name
        self._encryption = encryption

        # Keep track if the user has already entered the wrong password before
        # so that we only pack the "password incorrect" label once
        self._wrong_password_used_before = False

        self._heading = Heading(_("Connect to the network"),
                                self._network_name, self._win.is_plug(), True)

        self._heading.set_prev_callback(self._refresh_networks)
        self._heading.container.set_margin_right(20)
        self._heading.container.set_margin_left(20)

        if wrong_password:
            image_path = os.path.join(img_dir, "password-fail.png")
            wrong_password = self._create_wrong_password_label()
            self._heading.container.pack_start(wrong_password, True, True, 0)
        else:
            image_path = os.path.join(img_dir, "password.png")

        self._padlock_image = Gtk.Image.new_from_file(image_path)

        self._password_entry = Gtk.Entry()
        self._password_entry.set_placeholder_text(_("Password"))
        self._password_entry.set_visibility(False)
        self._password_entry.get_style_context().add_class('password_entry')
        self._password_entry.set_margin_left(60)
        self._password_entry.set_margin_right(60)
        self._password_entry.connect('key-release-event',
                                     self._set_button_sensitive)
        # If Enter key is pressed on the password entry, we want to act as
        # though the connect_btn was clicked
        self._password_entry.connect('key-release-event',
                                     self._on_connect_key_wrapper)

        self._connect_btn = KanoButton(_("CONNECT"))
        self._connect_btn.connect('clicked', self._on_connect)
        self._connect_btn.set_sensitive(False)
        self._connect_btn.set_margin_right(100)
        self._connect_btn.set_margin_left(100)
        self._connect_btn.pack_and_align()

        self._show_password = Gtk.CheckButton.new_with_label(
            _("Show password"))
        self._show_password.get_style_context().add_class('show_password')
        self._show_password.connect('toggled',
                                    self._change_password_entry_visiblity)
        self._show_password.set_active(True)
        self._show_password.set_margin_left(100)

        vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        self.add(vbox)

        vbox.pack_start(self._heading.container, False, False, 10)
        vbox.pack_start(self._padlock_image, False, False, 10)
        vbox.pack_start(self._password_entry, False, False, 10)
        vbox.pack_start(self._show_password, False, False, 10)
        vbox.pack_end(self._connect_btn.align, False, False, 40)

        # Entry should have the keyboard focus
        self._password_entry.grab_focus()

        self.show_all()

    def _create_wrong_password_label(self):
        label = Gtk.Label(_("Password incorrect"))
        label.get_style_context().add_class('wrong_password_label')
        return label

    def _change_password_entry_visiblity(self, widget):
        '''
        Depending on the checkbox, change the writing in the
        password entry to be readable.
        '''
        visibility = self._show_password.get_active()
        self._password_entry.set_visibility(visibility)

    def _refresh_networks(self, widget=None):
        from kano_wifi_gui.RefreshNetworks import RefreshNetworks
        RefreshNetworks(self._win)

    def _on_connect_key_wrapper(self, widget, event):
        if event.keyval == Gdk.KEY_Return:
            self._on_connect()

    def _on_connect(self, widget=None):
        passphrase = self._password_entry.get_text()
        ConnectToNetwork(self._win, self._network_name, passphrase,
                         self._encryption)

    def _set_button_sensitive(self, widget, event):
        '''
        Enable the Connect button only if the passphrase is non empty
        '''
        self._connect_btn.set_sensitive(widget.get_text_length() > 0)

    def _thread_finish(self, success):

        if success:
            self._success_screen()
        else:
            self._wrong_password_screen()

    def _success_screen(self):
        self._win.remove_main_widget()

        title = _("Success!")
        description = _("You're connected")
        buttons = [{
            'label': _("OK"),
            'color': 'green',
            'type': 'KanoButton',
            'callback': Gtk.main_quit
        }]
        img_path = os.path.join(img_dir, "internet.png")

        # Track that user connected online
        track_action('internet-connection-established')

        self._win.set_main_widget(
            Template(title, description, buttons, self._win.is_plug(),
                     img_path))

    def _disable_widgets_start_spinner(self):
        self._connect_btn.start_spinner()
        self._connect_btn.set_sensitive(False)
        self._win.top_bar.prev_button.set_sensitive(False)
        self._password_entry.set_sensitive(False)
        self._show_password.set_sensitive(False)

    def _enable_widgets_stop_spinner(self):
        self._connect_btn.stop_spinner()
        self._connect_btn.set_sensitive(True)
        self._win.top_bar.prev_button.set_sensitive(True)
        self._password_entry.set_sensitive(True)
        self._show_password.set_sensitive(True)
Exemplo n.º 8
0
class ResetPassword(Gtk.Box):

    def __init__(self, win):
        Gtk.Box.__init__(self, orientation=Gtk.Orientation.VERTICAL)

        self.win = win
        self.win.set_decorated(False)
        self.win.set_main_widget(self)

        self.heading = Heading(
            _("Reset your password"),
            _("We'll send a new password to your email")
        )
        self.pack_start(self.heading.container, False, False, 10)

        self.labelled_entries = LabelledEntries([
            {"heading": _("Email"), "subheading": ""}
        ])
        align = Gtk.Alignment(xscale=0, xalign=0.5)
        self.pack_start(align, False, False, 15)

        self.labelled_entries.set(0, 0, 1, 1)
        self.labelled_entries.set_hexpand(True)

        align.add(self.labelled_entries)

        # Read email from file
        user_email = get_email()

        self.email_entry = self.labelled_entries.get_entry(0)
        self.email_entry.set_text(user_email)
        self.email_entry.connect("key-release-event", self.activate)

        self.button = KanoButton(_("Reset password").upper())
        self.button.pack_and_align()
        self.button.connect("button-release-event", self.activate)
        self.button.connect("key-release-event", self.activate)
        self.button.set_padding(30, 30, 0, 0)

        self.pack_start(self.button.align, False, False, 0)
        self.win.show_all()

    def activate(self, widget, event):
        if not hasattr(event, 'keyval') or event.keyval == 65293:
            watch_cursor = Gdk.Cursor(Gdk.CursorType.WATCH)
            self.win.get_window().set_cursor(watch_cursor)
            self.button.set_sensitive(False)
            self.button.start_spinner()

            thread = threading.Thread(target=self.send_new_password)
            thread.start()

    def send_new_password(self):
        # User may change email
        email = self.labelled_entries.get_entry(0).get_text()
        success, text = reset_password(email)
        if success:
            title = _("Success!")
            description = _("Sent new password to your email")
            button_dict = {
                _("Go to login screen").upper(): {"return_value": 12},
                _("Quit").upper(): {"return_value": 10, "color": "red"}
            }
        else:
            title = _("Something went wrong!")
            description = text
            button_dict = {
                _("Quit").upper(): {"return_value": 10, "color": "red"},
                _("Try again").upper(): {"return_value": 11}
            }

        GObject.idle_add(
            self.finished_thread_cb,
            title,
            description,
            button_dict
        )

    def finished_thread_cb(self, title, description, button_dict):
        kdialog = KanoDialog(
            title,
            description,
            button_dict=button_dict,
            parent_window=self.win
        )
        response = kdialog.run()

        self.win.get_window().set_cursor(None)
        self.button.stop_spinner()
        self.button.set_sensitive(True)

        if response == 10:
            Gtk.main_quit()
        # stay put
        elif response == 11:
            pass
        elif response == 12:
            self.go_to_login_screen()

    def go_to_login_screen(self):
        self.win.remove_main_widget()
        Login(self.win)
Exemplo n.º 9
0
class NetworkScreen(Gtk.Box):

    def __init__(self, win, network_list):

        Gtk.Box.__init__(self, orientation=Gtk.Orientation.VERTICAL)
        self._win = win
        self._wiface = self._win.wiface

        # The network that the user selects
        self._selected_network = {}

        # Setting new window here
        self._win.set_main_widget(self)
        self._win.top_bar.disable_prev()

        box = self._create_main_box(network_list)
        self.add(box)

        self._win.show_all()

    def _create_main_box(self, network_list):
        '''Show the screen with the different WiFi networks
        '''

        heading = Heading(
            _("Connect to WiFi"),
            _("Choose a network"),
            self._win.is_plug(),
            back_btn=False
        )

        # This box is to pack everything in the window
        vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)

        # For now, pack the network into a scrolled window
        sw = ScrolledWindow()
        sw.apply_styling_to_widget()
        sw.set_size_request(-1, 215)
        sw.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)

        self._network_box = self._create_network_box(network_list)
        sw.add(self._network_box)

        # Pack the scrolled window into an event box to give the illusion of a
        # border
        sw_border = self._add_border_to_widget(sw)
        sw_border.set_margin_right(30)
        sw_border.set_margin_left(30)
        sw_border.set_margin_bottom(20)
        sw_border.set_margin_top(10)

        # Then pack all the elements into the vbox
        vbox.pack_start(heading.container, False, False, 0)
        vbox.pack_start(sw_border, False, False, 0)

        # Pack in the refresh connect buttons
        button_box = self._create_refresh_connect_buttons()
        vbox.pack_end(button_box, False, False, 30)

        return vbox

    def _create_network_box(self, network_list):
        '''Create the box containing the list of networks
        '''
        # Setting up the box in which the network elements are to be positioned
        network_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)

        # Are these used anywhere?
        self._network_btns = []
        network_connection = is_connected(self._wiface)

        # The network connection
        network_name = network_connection[0]
        connected = network_connection[3]

        image_path = os.path.join(img_dir, "padlock.png")

        # If the network list is empty, display a message to show it's not
        # broken
        if not len(network_list):
            no_networks_label = Gtk.Label(_("No networks detected!"))
            no_networks_label.get_style_context().add_class('no_networks_label')
            no_networks_label.set_margin_top(80)
            network_box.pack_start(no_networks_label, False, False, 0)
            return network_box

        # Otherwise, pack the networks into the scrolled window
        for network in network_list:

            # Network selection must be able to receive events
            network_btn = Gtk.Button()

            # Needs a box packed into it for the label and possibly
            # an icon
            box = Gtk.Box()
            network_btn.add(box)
            network_btn.get_style_context().add_class('network_btn')
            attach_cursor_events(network_btn)

            # Box must contain label of the network name
            label = Gtk.Label(network['essid'])
            box.pack_start(label, False, False, 0)

            # If the network name of the button matches the last attempted
            # connection, and we're connected to the internet, then
            # put a tick next to the name.

            # TODO: Since connected shows if you're connected to internet
            # you can be connected to ethernet and thus be shown to be
            # connected to the wrong network.
            if network['essid'] == network_name and \
                    connected:
                tick = tick_icon()
                box.pack_start(tick, False, False, 0)

            network_btn.connect(
                'clicked', self._select_network, network, network_connection
            )

            # Add padlock to the items that require a password
            if network['encryption'] != 'off':
                padlock_image = Gtk.Image.new_from_file(image_path)
                box.pack_end(padlock_image, False, False, 0)

            # Pack into the GUI for the networks
            network_box.pack_start(network_btn, False, False, 0)
            self._network_btns.append(network_btn)

        return network_box

    def _add_border_to_widget(self, widget):
        '''Add a grey border to the widget that is entered as an argument.
        This is done by creating a grey event box and packing a white box with
        a margin in it.
        '''

        white_foreground = Gtk.EventBox()
        white_foreground.get_style_context().add_class('white')
        white_foreground.set_margin_left(3)
        white_foreground.set_margin_bottom(3)
        white_foreground.set_margin_top(3)
        white_foreground.set_margin_right(3)

        # Pack the scrolled window into an event box to give the illusion of a
        # border
        grey_border = Gtk.EventBox()
        grey_border.get_style_context().add_class('grey')
        grey_border.add(white_foreground)

        white_foreground.add(widget)

        return grey_border

    def _create_refresh_connect_buttons(self):
        '''Create the buttons used for the refresh button and the
        to connect to a network, and pack them into a button box.
        Returns the button box.
        '''

        self._connect_btn = KanoButton(_("CONNECT"))
        self._connect_btn.pack_and_align()
        self.connect_handler = self._connect_btn.connect(
            'clicked', self._first_time_connect
        )
        self._connect_btn.set_sensitive(False)
        self._refresh_btn = self._create_refresh_button()

        # For now, show both connect and refresh buttons
        buttonbox = Gtk.ButtonBox()
        buttonbox.set_layout(Gtk.ButtonBoxStyle.CENTER)
        buttonbox.set_spacing(10)
        buttonbox.pack_start(self._refresh_btn, False, False, 0)
        buttonbox.pack_start(self._connect_btn.align, False, False, 0)

        if self._win.is_plug():
            self._skip_btn = WhiteButton(_("Skip"))
            buttonbox.pack_start(self._skip_btn, False, False, 0)
            self._skip_btn.connect('clicked', self.skip)
        else:
            blank_label = Gtk.Label("")
            buttonbox.pack_start(blank_label, False, False, 0)

        return buttonbox

    # Attached to a callback, hence the extra argument
    def skip(self, skip_btn=None):
        # Exit with an extreme exit code so the init-flow knows the user
        # pressed SKIP
        sys.exit(100)

    def _set_connect_btn_status(self, connect=True):
        self._connect_btn.disconnect(self.connect_handler)

        if connect:
            self.connect_handler = self._connect_btn.connect(
                'clicked', self._first_time_connect
            )
            self._connect_btn.set_color('green')
            self._connect_btn.set_label(_("CONNECT"))

        else:
            self.connect_handler = self._connect_btn.connect(
                'clicked', self._launch_disconnect_thread
            )
            self._connect_btn.set_color('red')
            self._connect_btn.set_label(_("DISCONNECT"))

    def _launch_disconnect_thread(self, widget=None):
        watch_cursor = Gdk.Cursor(Gdk.CursorType.WATCH)
        self._win.get_window().set_cursor(watch_cursor)
        self._connect_btn.start_spinner()
        self._connect_btn.set_sensitive(False)

        # Force the spinner to show on the window.
        while Gtk.events_pending():
            Gtk.main_iteration()

        t = threading.Thread(target=self._threaded_disconnect)
        t.start()

    def _disconnect_screen(self):
        self._win.remove_main_widget()
        title = _("Disconnect complete.")
        description = _("You're now offline")
        buttons = [
            {
                'label': _("CLOSE"),
                'type': 'KanoButton',
                'color': 'red',
                'callback': Gtk.main_quit
            },
            {
                'label': _("CONNECT"),
                'type': 'KanoButton',
                'color': 'green',
                'callback': self._go_to_spinner_screen
            }
        ]
        img_path = os.path.join(img_dir, "no-wifi.png")
        self._win.set_main_widget(
            Template(
                title,
                description,
                buttons,
                self._win.is_plug(),
                img_path
            )
        )

    def _threaded_disconnect(self):
        '''
        This is needed so we can show a spinner while the user is
        disconnecting
        '''
        disconnect(self._wiface)

        def done():
            self._disconnect_screen()
            self._win.get_window().set_cursor(None)
            self._connect_btn.stop_spinner()
            self._connect_btn.set_sensitive(True)

        GObject.idle_add(done)

    def _create_refresh_button(self):
        '''Create the refresh button. This it quite involved as you have
        to pack an image into the button which need to change when the
        cursor hovers over it, and change the cursor to be a
        hand over it.
        '''
        refresh_icon_filepath = os.path.join(img_dir, "refresh.png")
        refresh_icon = Gtk.Image.new_from_file(refresh_icon_filepath)
        refresh_btn = Gtk.Button()
        refresh_btn.get_style_context().add_class('refresh_btn')
        refresh_btn.set_image(refresh_icon)
        attach_cursor_events(refresh_btn)

        # These are here in case we want to change the icon on mouse over
        refresh_btn.connect('enter-notify-event', self._set_refresh_hover_icon)
        refresh_btn.connect('leave-notify-event', self._set_refresh_normal_icon)

        refresh_btn.connect('clicked', self._go_to_spinner_screen)
        return refresh_btn

    # This is linked to enter-notify-event, hence the extra arguments
    def _set_refresh_hover_icon(self, widget=None, event=None):
        '''Change the refresh button's icon to the hover icon.
        '''
        selected_path = os.path.join(img_dir, "rescan-hover.png")
        image = Gtk.Image.new_from_file(selected_path)
        self._refresh_btn.set_image(image)

    # This is linked to leave-notify-event, hence the extra arguments
    def _set_refresh_normal_icon(self, widget=None, event=None):
        '''Change the refresh button's icon to the normal icon.
        '''
        unselected_path = os.path.join(img_dir, "refresh.png")
        image = Gtk.Image.new_from_file(unselected_path)
        self._refresh_btn.set_image(image)

    def _first_time_connect(self, widget=None):
        '''Check the selected network.  If a password is needed,
        take the user to the password screen.  Otherwise, try and connect.
        '''
        if self._selected_network['encryption'] == "off":
            essid = self._selected_network['essid']
            encryption = 'off'
            passphrase = ''
            ConnectToNetwork(self._win, essid, passphrase, encryption)
        else:
            self._go_to_password_screen()

    def _go_to_spinner_screen(self, button=None, event=None):
        '''Loading networks and showing the spinner screen.
        '''

        from kano_wifi_gui.RefreshNetworks import RefreshNetworks
        RefreshNetworks(self._win)

    def _go_to_password_screen(self):
        self._win.remove_main_widget()
        PasswordScreen(self._win, self._wiface,
                       self._selected_network["essid"],
                       self._selected_network["encryption"])

    def _select_network(self, button, network, network_connection):
        for network_btn in self._network_btns:
            network_btn.get_style_context().remove_class('selected')

        network_name = network_connection[0]
        connected = network_connection[3]

        self._selected_network = network
        button.get_style_context().add_class('selected')

        # If we are already connected to this network,
        # offer option to disconnect.
        if network['essid'] == network_name and connected:
            self._set_connect_btn_status(connect=False)
        else:
            self._set_connect_btn_status(connect=True)

        self._connect_btn.set_sensitive(True)

    def _disable_widgets_start_spinner(self):
        self._connect_btn.start_spinner()
        self._disable_widgets()

    def _enable_widgets_stop_spinner(self):
        self._connect_btn.stop_spinner()
        self._enable_widgets()

    def _disable_widgets(self):
        self._set_sensitivity_of_buttons(False)

    def _enable_widgets(self):
        self._connect_btn.stop_spinner()
        self._set_sensitivity_of_buttons(True)

    def _set_sensitivity_of_buttons(self, sensitivity):
        self._connect_btn.set_sensitive(sensitivity)
        self._refresh_btn.set_sensitive(sensitivity)

        # Do we want to block this? Or just make sure the application doesn't
        # fall over afterwards
        if hasattr(self, '_skip_btn'):
            # Skip button should be defined
            self._skip_btn.set_sensitive(sensitivity)
Exemplo n.º 10
0
class SetProxy(Gtk.Box):
    def __init__(self, win):
        Gtk.Box.__init__(self, orientation=Gtk.Orientation.VERTICAL)
        self.kano_button = KanoButton()

        self.win = win
        self.win.set_main_widget(self)

        self.heading = Heading(_("Proxy"), _("Connect via a friend"))

        grid = Gtk.Grid(column_homogeneous=False,
                        column_spacing=10,
                        row_spacing=10)

        self.kano_button.connect('button-release-event', self.apply_changes)
        self.kano_button.connect('key-release-event', self.apply_changes)
        self.win.top_bar.enable_prev()
        self.win.change_prev_callback(self.go_to_wifi)

        self.ip_entry = Gtk.Entry()
        self.ip_entry.props.placeholder_text = _("IP address")
        self.ip_entry.connect('key-release-event', self.proxy_enabled)

        self.username_entry = Gtk.Entry()
        self.username_entry.props.placeholder_text = _("Username")
        self.username_entry.connect('key-release-event', self.proxy_enabled)

        self.port_entry = Gtk.Entry()
        self.port_entry.props.placeholder_text = _("Port")
        self.port_entry.connect('key-release-event', self.proxy_enabled)

        self.password_entry = Gtk.Entry()
        self.password_entry.props.placeholder_text = _("Password")
        self.password_entry.set_visibility(False)
        self.password_entry.connect('key-release-event', self.proxy_enabled)

        password_box = Gtk.Box()
        password_box.add(self.password_entry)

        self.checkbutton = Gtk.CheckButton(_("enable proxy"))
        self.read_config()
        self.checkbutton.connect('clicked', self.proxy_status)
        self.checkbutton.set_can_focus(False)

        bottom_row = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=0)
        bottom_row.pack_start(self.checkbutton, False, False, 0)
        bottom_row.pack_start(self.kano_button, False, False, 60)
        bottom_row.set_margin_bottom(30)
        bottom_row.set_margin_left(70)

        grid.attach(self.ip_entry, 0, 0, 2, 2)
        grid.attach(self.username_entry, 0, 2, 2, 2)
        grid.attach(self.port_entry, 2, 0, 2, 2)
        grid.attach(password_box, 2, 2, 3, 2)

        grid_alignment = Gtk.Alignment(xscale=0,
                                       xalign=0.5,
                                       yscale=0,
                                       yalign=0.2)
        grid_alignment.add(grid)

        self.pack_start(self.heading.container, False, False, 0)
        self.pack_start(grid_alignment, True, True, 0)
        self.pack_end(bottom_row, False, False, 0)

        self.proxy_status(self.checkbutton)
        self.kano_button.set_sensitive(False)

        # Change text of kano button depending on if proxy is enabled
        if self.checkbutton.get_active():
            self.kano_button.set_label(_("ENABLE PROXY"))
        else:
            self.kano_button.set_label(_("DISABLE PROXY"))

        self.win.show_all()

    def clear_entries(self):
        self.ip_entry.set_text("")
        self.username_entry.set_text("")
        self.port_entry.set_text("")
        self.password_entry.set_text("")

    def go_to_wifi(self, widget=None, event=None):
        self.win.clear_win()
        SetWifi(self.win)

    # Update for proxy
    def read_config(self):
        self.enable_proxy, data, _ = get_all_proxies()
        self.enabled_init = self.enable_proxy
        if self.enable_proxy:
            try:
                self.ip_entry.set_text(data['host'])
                self.port_entry.set_text(data['port'])
                if data['username']:
                    self.username_entry.set_text(data['username'])
                if data['password']:
                    self.password_entry.set_text(data['password'])
            except:
                # Something went wrong > disable proxy
                set_all_proxies(False)
                common.proxy_enabled = False
                self.enable_proxy = False
                self.enabled_init = False
                self.clear_entries()
        self.checkbutton.set_active(self.enable_proxy)

    def apply_changes(self, button, event):
        # If enter key is pressed or mouse button is clicked
        if not hasattr(event, 'keyval') or event.keyval == 65293:

            # This is a callback called by the main loop, so it's safe to
            # manipulate GTK objects:
            watch_cursor = Gdk.Cursor(Gdk.CursorType.WATCH)
            self.win.get_window().set_cursor(watch_cursor)
            self.kano_button.start_spinner()
            self.kano_button.set_sensitive(False)

            def lengthy_process():

                if self.enable_proxy:
                    host = self.ip_entry.get_text()
                    port = self.port_entry.get_text()
                    username = self.username_entry.get_text()
                    password = self.password_entry.get_text()
                    set_all_proxies(enable=True,
                                    host=host,
                                    port=port,
                                    username=username,
                                    password=password)
                    common.proxy_enabled = True

                    success, text = test_proxy()
                    if not success:
                        title = _("Error with proxy")
                        description = text
                        return_value = 1

                        # disable proxy if we couldn't successfully enable it
                        set_all_proxies(False)
                        common.proxy_enabled = False
                    else:
                        title = _("Successfully enabled proxy")
                        description = ""
                        return_value = 0

                else:
                    set_all_proxies(False)
                    common.proxy_enabled = False
                    title = _("Successfully disabled proxy")
                    description = ""
                    return_value = 0

                def done(title, description, return_value):
                    kdialog = KanoDialog(title,
                                         description,
                                         [{
                                             'label': _("OK"),
                                             'color': 'green',
                                             'return_value': return_value
                                         }],
                                         parent_window=self.win)
                    response = kdialog.run()
                    self.win.get_window().set_cursor(None)
                    self.kano_button.stop_spinner()

                    if response == 0:
                        self.go_to_wifi()
                    elif response == 1:
                        self.checkbutton.set_active(False)
                        self.kano_button.set_sensitive(False)

                GObject.idle_add(done, title, description, return_value)

            thread = threading.Thread(target=lengthy_process)
            thread.start()

    # Validation functions
    # If the "enable proxy" checkbox is checked/uncheckout, this function is activated
    # Disables the text entries if enable proxy is not checked
    def proxy_status(self, widget):
        self.enable_proxy = widget.get_active()
        if self.enable_proxy:
            self.ip_entry.set_sensitive(True)
            self.port_entry.set_sensitive(True)
            self.password_entry.set_sensitive(True)
            self.username_entry.set_sensitive(True)
            # Run to see if it need enabling
            self.proxy_enabled()
            self.kano_button.set_label(_("ENABLE PROXY"))

        else:
            self.ip_entry.set_sensitive(False)
            self.port_entry.set_sensitive(False)
            self.password_entry.set_sensitive(False)
            self.username_entry.set_sensitive(False)
            self.kano_button.set_label(_("DISABLE PROXY"))
            self.kano_button.set_sensitive(True)

    # if proxy enabled: ip address, port are mandatory
    def proxy_enabled(self, widget=None, event=None):
        # Get IP address
        # Get port
        # Get
        # If these entries are non empty, good - else, disable the next button
        ip_text = self.ip_entry.get_text()
        port_text = self.port_entry.get_text()

        if ip_text == "" or port_text == "":
            self.kano_button.set_sensitive(False)
            return False

        else:
            self.kano_button.set_sensitive(True)
            return True

        return False
Exemplo n.º 11
0
class RecoverUsername(Gtk.Box):
    def __init__(self, win):
        Gtk.Box.__init__(self, orientation=Gtk.Orientation.VERTICAL)

        self.win = win
        self.win.set_decorated(False)
        self.win.set_main_widget(self)

        self.heading = Heading(_("Forgotten your username"),
                               _("We'll send a reminder to your email"))
        self.pack_start(self.heading.container, False, False, 10)

        self.labelled_entries = LabelledEntries([{
            'heading': _("Email"),
            'subheading': ""
        }])
        align = Gtk.Alignment(xscale=0, xalign=0.5)
        self.pack_start(align, False, False, 15)

        self.labelled_entries.set(0, 0, 1, 1)
        self.labelled_entries.set_hexpand(True)

        align.add(self.labelled_entries)

        self.email_entry = self.labelled_entries.get_entry(0)
        self.email_entry.set_text("")
        self.email_entry.connect('key-release-event', self.activate)

        self.button = KanoButton(_("REQUEST REMINDER"))
        self.button.pack_and_align()
        self.button.connect('button-release-event', self.activate)
        self.button.connect('key-release-event', self.activate)
        self.button.set_padding(30, 30, 0, 0)

        self.pack_start(self.button.align, False, False, 0)
        self.email_entry.grab_focus()
        self.win.show_all()

    def activate(self, widget, event):
        if not hasattr(event, 'keyval') or event.keyval == 65293:
            watch_cursor = Gdk.Cursor(Gdk.CursorType.WATCH)
            self.win.get_window().set_cursor(watch_cursor)
            self.button.set_sensitive(False)
            self.button.start_spinner()

            thread = threading.Thread(target=self.send_new_password)
            thread.start()

    def send_new_password(self):
        # User may change email
        email = self.labelled_entries.get_entry(0).get_text()
        success, text = recover_username(email)
        if success:
            title = _("Success!")
            description = _("Sent a reminder to your email")
            button_dict = {
                _("GO TO LOGIN SCREEN"): {
                    'return_value': 12
                },
                _("QUIT"): {
                    'return_value': 10,
                    'color': 'red'
                }
            }
        else:
            title = _("Something went wrong!")
            description = text
            button_dict = {
                _("QUIT"): {
                    'return_value': 10,
                    'color': 'red'
                },
                _("TRY AGAIN"): {
                    'return_value': 11
                }
            }

        GObject.idle_add(self.finished_thread_cb, title, description,
                         button_dict)

    def finished_thread_cb(self, title, description, button_dict):
        kdialog = KanoDialog(title,
                             description,
                             button_dict=button_dict,
                             parent_window=self.win)
        response = kdialog.run()

        self.win.get_window().set_cursor(None)
        self.button.stop_spinner()
        self.button.set_sensitive(True)

        if response == 10:
            Gtk.main_quit()
        # stay put
        elif response == 11:
            pass
        elif response == 12:
            self.go_to_login_screen()

    def go_to_login_screen(self):
        self.win.remove_main_widget()
        Login(self.win)