Better GUI, password reading, translation.
authorOlof-Joachim Frahm <olof@macrolet.net>
Wed, 21 Jan 2015 23:54:07 +0000 (23:54 +0000)
committerOlof-Joachim Frahm <olof@macrolet.net>
Thu, 22 Jan 2015 00:08:53 +0000 (00:08 +0000)
Kinda too big, this commit.  Also has encoding problems.

crypto-install
locale/crypto-install.pot
locale/de/LC_MESSAGES/crypto-install.po

index 6fb3a7c..f0a881c 100755 (executable)
@@ -11,6 +11,7 @@ if sys.version_info[0] == 2:
     from tkMessageBox import *
     from Tix import *
     from ScrolledText import *
+    from ttk import *
     from Queue import *
 
 
@@ -25,6 +26,7 @@ elif sys.version_info[0] > 2:
     from tkinter.messagebox import *
     from tkinter.tix import *
     from tkinter.scrolledtext import *
+    from tkinter.ttk import *
     from queue import *
 
 
@@ -170,8 +172,10 @@ def openssh_exists (arguments):
     return os.path.exists (openssh_config) and os.path.exists (openssh_key)
 
 
-# TODO: verify phrase at least once
-# TODO: use better labels
+def quoted (string):
+    return string.replace ("+", "++").replace (" ", "+")
+
+
 def input_passphrase (arguments):
     batch_passphrase = ldedented ("""
     RESET
@@ -180,6 +184,8 @@ def input_passphrase (arguments):
     """).format (subprocess.check_output ("tty").strip (),
                  os.getenv ("TERM"))
 
+    expected_oks = 3
+
     batch_env = dict (os.environ)
     if arguments.gui:
         batch_passphrase += ldedented ("""
@@ -187,27 +193,65 @@ def input_passphrase (arguments):
         OPTION display={}
         """).format (os.getenv ("XAUTHORITY"),
                      os.getenv ("DISPLAY"))
+        expected_oks += 2
     else:
         del batch_env["DISPLAY"]
 
-    batch_passphrase += \
-        "GET_PASSPHRASE --data --check --qualitybar X X Passphrase X\n"
-
     passphrase_process = subprocess.Popen (["gpg-agent", "--server"],
                                            stdin = subprocess.PIPE,
                                            stdout = subprocess.PIPE,
                                            stderr = subprocess.PIPE,
                                            env = batch_env)
-    (stdout, stderr) = passphrase_process.communicate (batch_passphrase.encode ("UTF-8"))
 
-    if passphrase_process.returncode != 0:
-        raise Exception ("Couldn't read passphrase.")
+    try:
+        line = passphrase_process.stdout.readline ().decode ("UTF-8")
+        if line != "OK Pleased to meet you\n":
+            raise Exception ("Couldn't read expected OK.")
 
-    for line in stdout.splitlines ():
-        if line.decode ("UTF-8").startswith ("D "):
-            return line[2:]
+        passphrase_process.stdin.write (batch_passphrase.encode ("UTF-8"))
 
-    return ""
+        for i in range (expected_oks):
+            line = passphrase_process.stdout.readline ().decode ("UTF-8")
+            if line != "OK\n":
+                raise Exception ("Couldn't read expected OK.")
+
+        error, prompt, description = "", _ ("Passphrase:"), ""
+
+        while True:
+            batch_passphrase = \
+                "GET_PASSPHRASE --data --repeat=1 --qualitybar X {} {} {}\n" \
+                    .format ((error and quoted (error)) or "X",
+                             (prompt and quoted (prompt)) or "X",
+                             (description and quoted (description)) or "X")
+
+            passphrase_process.stdin.write (batch_passphrase.encode ("UTF-8"))
+
+            line = passphrase_process.stdout.readline ().decode ("UTF-8")
+
+            if line == "OK\n":
+                error = _ ("Empty passphrase")
+                continue
+
+            if line.startswith ("D "):
+                passphrase = line[2:-1]
+
+                if len (passphrase) < 8:
+                    error = _ ("Passphrase too short")
+                    description = _ ("Passphrase has to have at least 8 characters.")
+                    continue
+
+                return passphrase
+
+            if line.startswith ("ERR 83886179"):
+                raise Exception ("Operation cancelled.")
+
+            raise Exception ("Unexpected response.")
+    finally:
+        passphrase_process.stdin.close ()
+        passphrase_process.stdout.close ()
+        passphrase_process.stderr.close ()
+
+        passphrase_process.wait ()
 
 
 def redirect_to_stdout (process):
@@ -349,22 +393,6 @@ def _state (value):
     return NORMAL if value else DISABLED
 
 
-def _valid (value):
-    return "black" if value else "red"
-
-
-def setitem (object, name, value):
-    return object.__setitem__ (name, value)
-
-
-def setitems (name, value, objects):
-    return map (lambda object: setitem (object, name, value), objects)
-
-
-def _fg (value, *objects):
-    setitems ("fg", value, objects)
-
-
 # http://www.blog.pythonlibrary.org/2014/07/14/tkinter-redirecting-stdout-stderr/
 # http://www.virtualroadside.com/blog/index.php/2012/11/10/glib-idle_add-for-tkinter-in-python/
 class RedirectText (object):
@@ -400,21 +428,37 @@ class CryptoInstallProgress (Toplevel):
 
         self._quit = Button (self,
                              text = _ ("Quit"),
-                             command = self.quit)
+                             command = self.maybe_quit)
         self.balloon.bind_widget (self._quit,
                                   msg = _ ("Quit the program immediately"))
         self._quit.pack ()
 
+    def update_widgets (self):
+        if self.parent.state () == "normal":
+            self._quit["text"] = _ ("Close")
+            self.balloon.bind_widget (self._quit,
+                                      msg = _ ("Close this window"))
+
+    def maybe_quit (self):
+        (self.quit if self.parent.state () != "normal" else self.destroy) ()
+
 
 class CryptoInstall (Tk):
     def __init__ (self, arguments):
         Tk.__init__ (self)
 
+        self.style = Style ()
+        self.style.theme_use ("clam")
+        self.style.configure ("Invalid.TLabel", foreground = "red")
+        self.style.configure ("Invalid.TEntry", foreground = "red")
+
         self.arguments = arguments
 
         self.resizable (width = False, height = False)
         self.title (_ ("Crypto Install Wizard"))
 
+        self.progress = None
+
         self.create_widgets ()
 
     def create_widgets (self):
@@ -580,7 +624,10 @@ class CryptoInstall (Tk):
     def update_field (self, name):
         field = self.fields[name]
 
-        _fg (_valid (field[1] (field[0].get ())), field[2], field[3])
+        valid = field[1] (field[0].get ())
+
+        field[2]["style"] = "" if valid else "Invalid.TEntry"
+        field[3]["style"] = "" if valid else "Invalid.TLabel"
 
     def update_widgets (self, *args):
         self._generate["state"] = _state (self.valid_state ())
@@ -633,7 +680,16 @@ class CryptoInstall (Tk):
                 openssh_setup (self.arguments, comment)
                 # TODO: put update into queue
                 self.update_widgets ()
+        except Exception as exception:
+            self.deiconify ()
+
+            sys.stdout.write (exception)
+            sys.stdout.write ("\n")
+
+            raise
         finally:
+            # TODO: put update into queue
+            self.progress.update_widgets ()
             sys.stdout = stdout
 
     def _on_idle ():
@@ -645,7 +701,11 @@ class CryptoInstall (Tk):
             pass
 
     def generate (self):
-        self.progress = CryptoInstallProgress (self)
+        self.withdraw ()
+
+        if not self.progress or self.progress.winfo_exists () == 0:
+            self.progress = CryptoInstallProgress (self)
+        self.progress.text.delete ("0.0", "end")
 
         self.bind ("<<Idle>>", self._on_idle)
 
index 5773c40..43bf3dd 100644 (file)
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2015-01-18 22:56+0000\n"
+"POT-Creation-Date: 2015-01-21 23:50+0000\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -17,138 +17,162 @@ msgstr ""
 "Content-Type: text/plain; charset=CHARSET\n"
 "Content-Transfer-Encoding: 8bit\n"
 
-#: crypto-install:76
+#: crypto-install:75
 msgid "Display version."
 msgstr ""
 
-#: crypto-install:81
+#: crypto-install:80
 msgid "Disable GUI, use text interface."
 msgstr ""
 
-#: crypto-install:83
+#: crypto-install:82
 msgid "GnuPG"
 msgstr ""
 
-#: crypto-install:84
+#: crypto-install:83
 msgid "Options related to the GnuPG setup."
 msgstr ""
 
-#: crypto-install:89
+#: crypto-install:88
 msgid "Disable GnuPG setup."
 msgstr ""
 
-#: crypto-install:94 crypto-install:108
+#: crypto-install:93 crypto-install:107
 msgid "PATH"
 msgstr ""
 
-#: crypto-install:95
+#: crypto-install:94
 msgid "Default directory for GnuPG files."
 msgstr ""
 
-#: crypto-install:97
+#: crypto-install:96
 msgid "OpenSSH"
 msgstr ""
 
-#: crypto-install:98
+#: crypto-install:97
 msgid "Options related to the OpenSSH setup."
 msgstr ""
 
-#: crypto-install:103
+#: crypto-install:102
 msgid "Disable OpenSSH setup."
 msgstr ""
 
-#: crypto-install:109
+#: crypto-install:108
 msgid "Default directory for OpenSSH files."
 msgstr ""
 
-#: crypto-install:234
-msgid "GnuPG secret keyring already exists at '{}'."
+#: crypto-install:218
+msgid "Passphrase:"
+msgstr ""
+
+#: crypto-install:232
+msgid "Empty passphrase"
 msgstr ""
 
 #: crypto-install:239
+msgid "Passphrase too short"
+msgstr ""
+
+#: crypto-install:240
+msgid "Passphrase has to have at least 8 characters."
+msgstr ""
+
+#: crypto-install:275
+msgid "GnuPG secret keyring already exists at '{}'."
+msgstr ""
+
+#: crypto-install:280
 msgid ""
 "\n"
 "        No default GnuPG key available.  Please enter your information to\n"
 "        create a new key."
 msgstr ""
 
-#: crypto-install:243
+#: crypto-install:284
 msgid "What is your name (e.g. 'John Doe')? "
 msgstr ""
 
-#: crypto-install:246
+#: crypto-install:287
 msgid ""
 "\n"
 "        What is your email address (e.g. 'test@example.com')? "
 msgstr ""
 
-#: crypto-install:250
+#: crypto-install:291
 msgid ""
 "\n"
 "        What is your comment phrase, if any (e.g. 'key for 2014')? "
 msgstr ""
 
-#: crypto-install:255
+#: crypto-install:296
 msgid "Creating GnuPG directory at '{}'."
 msgstr ""
 
-#: crypto-install:299
+#: crypto-install:340
 msgid "Creating OpenSSH directory at '{}'."
 msgstr ""
 
-#: crypto-install:302
+#: crypto-install:343
 msgid "Creating OpenSSH configuration at '{}'."
 msgstr ""
 
-#: crypto-install:313 crypto-install:319
+#: crypto-install:354 crypto-install:360
 msgid "OpenSSH key already exists at '{}'."
 msgstr ""
 
-#: crypto-install:322
+#: crypto-install:363
 msgid "No OpenSSH key available.  Generating new key."
 msgstr ""
 
-#: crypto-install:326
+#: crypto-install:367
 msgid ""
 "\n"
 "        What is your comment phrase (e.g. 'user@mycomputer')? "
 msgstr ""
 
-#: crypto-install:405 crypto-install:551
+#: crypto-install:430 crypto-install:592
 msgid "Quit"
 msgstr ""
 
-#: crypto-install:408 crypto-install:554
+#: crypto-install:433 crypto-install:595
 msgid "Quit the program immediately"
 msgstr ""
 
-#: crypto-install:419
+#: crypto-install:438
+msgid "Close"
+msgstr ""
+
+#: crypto-install:440
+msgid "Close this window"
+msgstr ""
+
+#: crypto-install:458
 msgid "Crypto Install Wizard"
 msgstr ""
 
-#: crypto-install:431
+#: crypto-install:472
 msgid ""
 "\n"
 "        Username on the local machine (e.g. 'user')\n"
 "        "
 msgstr ""
 
-#: crypto-install:434
+#: crypto-install:475
 msgid "Username"
 msgstr ""
 
-#: crypto-install:448
+#: crypto-install:489
 msgid ""
 "\n"
 "        Host name of the local machine (e.g. 'mycomputer')\n"
 "        "
 msgstr ""
 
-#: crypto-install:451
+#: crypto-install:492
 msgid "Host Name"
 msgstr ""
 
-#: crypto-install:465
+#: crypto-install:506
 msgid ""
 "\n"
 "        Full name as it should appear in the key description (e.g. 'John "
@@ -156,56 +180,56 @@ msgid ""
 "        "
 msgstr ""
 
-#: crypto-install:468
+#: crypto-install:509
 msgid "Full Name"
 msgstr ""
 
-#: crypto-install:482
+#: crypto-install:523
 msgid ""
 "\n"
 "        Email address associated with the name (e.g. '<test@example.com>')\n"
 "        "
 msgstr ""
 
-#: crypto-install:485
+#: crypto-install:526
 msgid "Email address"
 msgstr ""
 
-#: crypto-install:499
+#: crypto-install:540
 msgid ""
 "\n"
 "        Comment phrase for the GnuPG key, if any (e.g. 'key for 2014')\n"
 "        "
 msgstr ""
 
-#: crypto-install:502
+#: crypto-install:543
 msgid "Comment phrase"
 msgstr ""
 
-#: crypto-install:520
+#: crypto-install:561
 msgid "Generate GnuPG key"
 msgstr ""
 
-#: crypto-install:531
+#: crypto-install:572
 msgid "Generate OpenSSH key"
 msgstr ""
 
-#: crypto-install:544
+#: crypto-install:585
 msgid "Generate Keys"
 msgstr ""
 
-#: crypto-install:548
+#: crypto-install:589
 msgid "Generate the keys as configured above"
 msgstr ""
 
-#: crypto-install:608
+#: crypto-install:652
 msgid ""
 "\n"
 "        Generate a GnuPG key for '{}' and configure a default setup for it\n"
 "        "
 msgstr ""
 
-#: crypto-install:615
+#: crypto-install:659
 msgid ""
 "\n"
 "        Generate an OpenSSH key for '{}' and configure a default setup for "
index 423422a..962c77c 100644 (file)
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2015-01-18 22:56+0000\n"
+"POT-Creation-Date: 2015-01-21 23:50+0000\n"
 "PO-Revision-Date: 2015-01-17 12:29+0000\n"
 "Last-Translator: Olof-Joachim Frahm <olof@macrolet.net>\n"
 "Language-Team: German <translation-team-de@lists.sourceforge.net>\n"
@@ -18,67 +18,85 @@ msgstr ""
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
 
-#: crypto-install:76
+#: crypto-install:75
 msgid "Display version."
 msgstr "Version anzeigen."
 
-#: crypto-install:81
+#: crypto-install:80
 msgid "Disable GUI, use text interface."
 msgstr "Schalte GUI ab, benutze das Textinterface."
 
-#: crypto-install:83
+#: crypto-install:82
 msgid "GnuPG"
 msgstr "GnuPG"
 
-#: crypto-install:84
+#: crypto-install:83
 msgid "Options related to the GnuPG setup."
 msgstr "Optionen für das GnuPG-Setup."
 
-#: crypto-install:89
-#, fuzzy
+#: crypto-install:88
 msgid "Disable GnuPG setup."
 msgstr "GnuPG-Setup deaktivieren."
 
-#: crypto-install:94 crypto-install:108
+#: crypto-install:93 crypto-install:107
 msgid "PATH"
 msgstr "PFAD"
 
-#: crypto-install:95
+#: crypto-install:94
 msgid "Default directory for GnuPG files."
 msgstr "Standardverzeichnis für GnuPG-Dateien."
 
-#: crypto-install:97
+#: crypto-install:96
 msgid "OpenSSH"
 msgstr "OpenSSH"
 
-#: crypto-install:98
+#: crypto-install:97
 msgid "Options related to the OpenSSH setup."
 msgstr "Optionen für das OpenSSH-Setup."
 
-#: crypto-install:103
+#: crypto-install:102
 msgid "Disable OpenSSH setup."
 msgstr "OpenSSH-Setup deaktivieren."
 
-#: crypto-install:109
+#: crypto-install:108
 msgid "Default directory for OpenSSH files."
 msgstr "Standardverzeichnis für OpenSSH-Dateien."
 
-#: crypto-install:234
+#: crypto-install:218
+msgid "Passphrase:"
+msgstr "Passwort:"
+
+#: crypto-install:232
+msgid "Empty passphrase"
+msgstr "Leeres Passwort"
+
+#: crypto-install:239
+msgid "Passphrase too short"
+msgstr "Passwort zu kurz"
+
+#: crypto-install:240
+msgid "Passphrase has to have at least 8 characters."
+msgstr "Passwort muß mindestens 8 Zeichen lang sein."
+
+#: crypto-install:275
 msgid "GnuPG secret keyring already exists at '{}'."
 msgstr "Geheimer GnuPG-Schlüssel existiert bereits unter '{}'."
 
-#: crypto-install:239
+#: crypto-install:280
 msgid ""
 "\n"
 "        No default GnuPG key available.  Please enter your information to\n"
 "        create a new key."
 msgstr ""
+"\n"
+"        Kein Standard GnuPG-Schlüssel vorhanden.  Bitte gib Deine Informationen um\n"
+"        einen neuen Schlüssel zu erstellen."
 
-#: crypto-install:243
+#: crypto-install:284
 msgid "What is your name (e.g. 'John Doe')? "
 msgstr "Wie heißt Du (z.B. 'Max Mustermann')? "
 
-#: crypto-install:246
+#: crypto-install:287
 msgid ""
 "\n"
 "        What is your email address (e.g. 'test@example.com')? "
@@ -86,7 +104,7 @@ msgstr ""
 "\n"
 "        Was ist Deine Email-Adresse? (z.B. 'test@example.com')? "
 
-#: crypto-install:250
+#: crypto-install:291
 msgid ""
 "\n"
 "        What is your comment phrase, if any (e.g. 'key for 2014')? "
@@ -94,27 +112,27 @@ msgstr ""
 "\n"
 "        Was ist Dein Kommentar, falls gewünscht (z.B. 'Schlüssel für 2014')? "
 
-#: crypto-install:255
+#: crypto-install:296
 msgid "Creating GnuPG directory at '{}'."
 msgstr "Erstelle GnuPG-Verzeichnis unter '{}'."
 
-#: crypto-install:299
+#: crypto-install:340
 msgid "Creating OpenSSH directory at '{}'."
 msgstr "Erstelle OpenSSH-Verzeichnis unter '{}'."
 
-#: crypto-install:302
+#: crypto-install:343
 msgid "Creating OpenSSH configuration at '{}'."
 msgstr "Erstelle OpenSSH-Konfiguration unter '{}'."
 
-#: crypto-install:313 crypto-install:319
+#: crypto-install:354 crypto-install:360
 msgid "OpenSSH key already exists at '{}'."
 msgstr "OpenSSH-Schlüssel existiert bereits unter '{}'."
 
-#: crypto-install:322
+#: crypto-install:363
 msgid "No OpenSSH key available.  Generating new key."
 msgstr "Kein OpenSSH-Schlüssel verfügbar.  Erstelle neuen Schlüssel."
 
-#: crypto-install:326
+#: crypto-install:367
 msgid ""
 "\n"
 "        What is your comment phrase (e.g. 'user@mycomputer')? "
@@ -122,19 +140,27 @@ msgstr ""
 "\n"
 "        Was ist Dein Kommentar (z.B. 'benutzer@meincomputer')? "
 
-#: crypto-install:405 crypto-install:551
+#: crypto-install:430 crypto-install:592
 msgid "Quit"
 msgstr "Beenden"
 
-#: crypto-install:408 crypto-install:554
+#: crypto-install:433 crypto-install:595
 msgid "Quit the program immediately"
 msgstr "Programm sofort beenden"
 
-#: crypto-install:419
+#: crypto-install:438
+msgid "Close"
+msgstr "Schließen"
+
+#: crypto-install:440
+msgid "Close this window"
+msgstr "Schließe dieses Fenster"
+
+#: crypto-install:458
 msgid "Crypto Install Wizard"
 msgstr "Crypto Installationsassistent"
 
-#: crypto-install:431
+#: crypto-install:472
 msgid ""
 "\n"
 "        Username on the local machine (e.g. 'user')\n"
@@ -144,11 +170,11 @@ msgstr ""
 "        Benutzername am lokalen Rechner (z.B. 'benutzer')\n"
 "        "
 
-#: crypto-install:434
+#: crypto-install:475
 msgid "Username"
 msgstr "Benutzername"
 
-#: crypto-install:448
+#: crypto-install:489
 msgid ""
 "\n"
 "        Host name of the local machine (e.g. 'mycomputer')\n"
@@ -158,11 +184,11 @@ msgstr ""
 "        Hostname des lokalen Rechners (z.B. 'meincomputer')\n"
 "        "
 
-#: crypto-install:451
+#: crypto-install:492
 msgid "Host Name"
 msgstr "Hostname"
 
-#: crypto-install:465
+#: crypto-install:506
 msgid ""
 "\n"
 "        Full name as it should appear in the key description (e.g. 'John "
@@ -174,11 +200,11 @@ msgstr ""
 "B. 'Max Mustermann')\n"
 "        "
 
-#: crypto-install:468
+#: crypto-install:509
 msgid "Full Name"
 msgstr "Voller Name"
 
-#: crypto-install:482
+#: crypto-install:523
 msgid ""
 "\n"
 "        Email address associated with the name (e.g. '<test@example.com>')\n"
@@ -188,11 +214,11 @@ msgstr ""
 "        Dem Namen zugeordnete Emailadresse (z.B. '<test@example.com>')\n"
 "        "
 
-#: crypto-install:485
+#: crypto-install:526
 msgid "Email address"
 msgstr "Emailadresse"
 
-#: crypto-install:499
+#: crypto-install:540
 msgid ""
 "\n"
 "        Comment phrase for the GnuPG key, if any (e.g. 'key for 2014')\n"
@@ -203,27 +229,27 @@ msgstr ""
 "für 2014')\n"
 "        "
 
-#: crypto-install:502
+#: crypto-install:543
 msgid "Comment phrase"
 msgstr "Kommentar"
 
-#: crypto-install:520
+#: crypto-install:561
 msgid "Generate GnuPG key"
 msgstr "GnuPG-Schlüssel erstellen"
 
-#: crypto-install:531
+#: crypto-install:572
 msgid "Generate OpenSSH key"
 msgstr "OpenSSH-Schlüssel erstellen"
 
-#: crypto-install:544
+#: crypto-install:585
 msgid "Generate Keys"
 msgstr "Schlüssel erstellen"
 
-#: crypto-install:548
+#: crypto-install:589
 msgid "Generate the keys as configured above"
 msgstr "Schlüssel wie oben konfiguriert erstellen"
 
-#: crypto-install:608
+#: crypto-install:652
 msgid ""
 "\n"
 "        Generate a GnuPG key for '{}' and configure a default setup for it\n"
@@ -234,7 +260,7 @@ msgstr ""
 "Standardsetup dafür\n"
 "        "
 
-#: crypto-install:615
+#: crypto-install:659
 msgid ""
 "\n"
 "        Generate an OpenSSH key for '{}' and configure a default setup for "