~sircmpwn/himitsu-devel

This thread contains a patchset. You're looking at the original emails, but you may wish to use the patch review UI. Review patch

[PATCH hiprompt-gtk-py] Async password feedback

Details
Message ID
<20220815231036.376-1-krystian@krystianch.com>
DKIM signature
pass
Download raw message
Patch: +83 -32
Introduces Gio to tell the user that their password is being verified
instead of just freezing the GUI.
---
 hiprompt_gtk/proto.py  | 66 ++++++++++++++++++++++++++++++++----------
 hiprompt_gtk/window.py | 49 ++++++++++++++++++++-----------
 2 files changed, 83 insertions(+), 32 deletions(-)

diff --git a/hiprompt_gtk/proto.py b/hiprompt_gtk/proto.py
index 5f4749f..fecaf6a 100644
--- a/hiprompt_gtk/proto.py
+++ b/hiprompt_gtk/proto.py
@@ -1,8 +1,39 @@
import sys
from enum import Enum
from gi.repository import GLib, Gio
from .key import Key


def gio_lines(stream):
    line = bytearray()

    while not stream.is_closed():
        byte = stream.read_bytes(1).get_data()
        if not byte:
            return
        line += byte
        if line[-1] == ord("\n"):
            yield line.decode()
            line.clear()

def gio_lines_async(stream, callback):
    line = bytearray()

    def _callback(source, result):
        nonlocal line
        byte = source.read_bytes_finish(result).get_data() if result else b""
        line += byte
        if line and line[-1] == ord("\n"):
            more = callback(line.decode())
            if not more:
                return
            line.clear()

        stream.read_bytes_async(1, GLib.PRIORITY_DEFAULT, None, _callback)

    _callback(stream, None)


class PromptMode(Enum):
    disclose = "disclose"
    delete = "delete"
@@ -14,10 +45,11 @@ class Session:
        self.unlock = False
        self.status = 127
        self.mode = None
        self.stream = Gio.UnixInputStream.new(sys.stdin.fileno(), False)
        self.parse()

    def parse(self):
        for line in sys.stdin:
        for line in gio_lines(self.stream):
            parts = line.strip().partition(" ")
            cmd = parts[0]
            args = parts[2]
@@ -44,22 +76,26 @@ class Session:
        self.mode = PromptMode(args)
        return False

    def password(self, pw):
    def password(self, pw, callback):
        """
        Sends a password to the daemon in response to an unlock command. Blocks
        until the daemon answers regarding the password's validity, returning
        True if it was correct and False otherwise.
        Sends a password to the daemon in response to an unlock command and
        returns immediately. When the daemon answers regarding the password's
        validity, calls the callback function with one argument: True if it was
        correct and False otherwise.
        """
        sys.stdout.write(f"password {pw}\n")
        sys.stdout.flush()
        # TODO: Don't block
        line = sys.stdin.readline()
        if line == "password incorrect\n":

        def _callback(line):
            if line == "password incorrect\n":
                callback(False)
            elif line == "password correct\n":
                self.unlock = False
                self.parse()
                callback(True)
            else:
                sys.stderr.write(f"Unexpected command '{line}'\n")
                exit(127)
            return False
        elif line == "password correct\n":
            self.unlock = False
            self.parse()
            return True
        else:
            sys.stderr.write(f"Unexpected command '{line}'\n")
            exit(127)

        gio_lines_async(self.stream, _callback)
diff --git a/hiprompt_gtk/window.py b/hiprompt_gtk/window.py
index 1f80ae4..4afed53 100644
--- a/hiprompt_gtk/window.py
+++ b/hiprompt_gtk/window.py
@@ -23,6 +23,8 @@ class Window:
        self.box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        self.window.add(self.box)

        self.deny = None
        self.grant = None
        self.entry = None
        self.buttons = []

@@ -63,17 +65,30 @@ class Window:

    def on_unlock_grant(self, *args):
        password = self.entry.get_text()
        self.deny.set_sensitive(False)
        self.grant.set_sensitive(False)
        self.entry.set_sensitive(False)
        self.entry.set_text("Verifying...")
        self.entry.set_visibility(True)
        self.window.remove_accel_group(self.accel)
        confirmed = len(self.session.keys) > 0
        if self.session.password(password):
            if not self.session.mode or confirmed:
                self.session.status = 0
                Gtk.main_quit()

        def _callback(status):
            if status:
                if not self.session.mode or confirmed:
                    self.session.status = 0
                    Gtk.main_quit()
                else:
                    self.make_ui()
            else:
                self.make_ui()
        else:
            self.entry.set_text("")
            self.entry.set_sensitive(True)
                self.entry.set_text("")
                self.entry.set_visibility(False)
                self.entry.set_sensitive(True)
                self.grant.set_sensitive(True)
                self.window.add_accel_group(self.accel)
                self.entry.grab_focus()

        self.session.password(password, _callback)

    def on_disclose_grant(self, *args):
        self.session.status = 0
@@ -88,16 +103,16 @@ class Window:
        self.header.set_title("Unlock keyring")

        if len(self.session.keys) == 0:
            deny = Gtk.Button("Cancel")
            self.deny = Gtk.Button("Cancel")
        else:
            deny = Gtk.Button("Deny access")
        deny.connect("clicked", self.on_deny)
        self.header.pack_start(deny)

        grant = Gtk.Button("Grant access")
        grant.get_style_context().add_class("destructive-action")
        grant.connect("clicked", self.on_unlock_grant)
        self.header.pack_end(grant)
            self.deny = Gtk.Button("Deny access")
        self.deny.connect("clicked", self.on_deny)
        self.header.pack_start(self.deny)

        self.grant = Gtk.Button("Grant access")
        self.grant.get_style_context().add_class("destructive-action")
        self.grant.connect("clicked", self.on_unlock_grant)
        self.header.pack_end(self.grant)

        scroller = Gtk.ScrolledWindow()
        scroller.set_propagate_natural_height(True)
-- 
2.36.2
Reply to thread Export thread (mbox)