+class CryptoInstall (Tk):
+ def __init__ (self, arguments):
+ Tk.__init__ (self)
+
+ self.arguments = arguments
+
+ self.resizable (width = False, height = False)
+ self.title ("Crypto Install Wizard")
+
+ self.create_widgets ()
+
+
+ def create_widgets (self):
+ self.balloon = Balloon (self, initwait = 250)
+
+
+ self.info_frame = Frame (self)
+ self.info_frame.pack (fill = X)
+
+
+ self.user_label = Label (self.info_frame)
+ self.user_label["text"] = "Username"
+ self.user_label.grid ()
+
+ self.user_var = StringVar ()
+ self.user_var.set (default_username ())
+ self.user_var.trace ("w", self.update_widgets)
+
+ self.user = Entry (self.info_frame, textvariable = self.user_var,
+ state = DISABLED)
+ self.balloon.bind_widget (self.user, msg = dedented ("""
+ Username on the local machine (e.g. 'user')
+ """))
+ self.user.grid (row = 0, column = 1)
+
+
+ self.host_label = Label (self.info_frame)
+ self.host_label["text"] = "Host Name"
+ self.host_label.grid ()
+
+ self.host_var = StringVar ()
+ self.host_var.set (default_hostname ())
+ self.host_var.trace ("w", self.update_widgets)
+
+ self.host = Entry (self.info_frame, textvariable = self.host_var,
+ state = DISABLED)
+ self.balloon.bind_widget (self.host, msg = dedented ("""
+ Host name of the local machine (e.g. 'mycomputer')
+ """))
+ self.host.grid (row = 1, column = 1)
+
+
+ self.name_label = Label (self.info_frame)
+ self.name_label["text"] = "Full Name"
+ self.name_label.grid ()
+
+ self.name_var = StringVar ()
+ self.name_var.set (default_name ())
+ self.name_var.trace ("w", self.update_widgets)
+
+ self.name = Entry (self.info_frame, textvariable = self.name_var)
+ self.balloon.bind_widget (self.name, msg = dedented ("""
+ Full name as it should appear in the key description (e.g. 'John Doe')
+ """))
+ self.name.grid (row = 2, column = 1)
+
+
+ self.email_label = Label (self.info_frame)
+ self.email_label["text"] = "Email address"
+ self.email_label.grid ()
+
+ self.email_var = StringVar ()
+ self.email_var.set (default_email ())
+ self.email_var.trace ("w", self.update_widgets)
+
+ self.email = Entry (self.info_frame, textvariable = self.email_var)
+ self.balloon.bind_widget (self.email, msg = dedented ("""
+ Email address associated with the name (e.g. '<test@example.com>')
+ """))
+ self.email.grid (row = 3, column = 1)
+
+
+ self.comment_label = Label (self.info_frame)
+ self.comment_label["text"] = "Comment phrase"
+ self.comment_label.grid ()
+
+ self.comment_var = StringVar ()
+ self.comment_var.set (default_comment ())
+ self.comment_var.trace ("w", self.update_widgets)
+
+ self.comment = Entry (self.info_frame, textvariable = self.comment_var)
+ self.balloon.bind_widget (self.comment, msg = dedented ("""
+ Comment phrase for the GnuPG key, if any (e.g. 'key for 2014')
+ """))
+ self.comment.grid (row = 4, column = 1)
+
+
+ self.options_frame = Frame (self)
+ self.options_frame.pack (fill = X)
+
+ self.gnupg_label = Label (self.options_frame)
+ self.gnupg_label["text"] = "Generate GnuPG key"
+ self.gnupg_label.grid ()
+
+ self.gnupg_var = IntVar ()
+ self.gnupg_var.set (1 if self.arguments.gnupg else 0)
+ self.gnupg_var.trace ("w", self.update_widgets)
+
+ self.gnupg = Checkbutton (self.options_frame, variable = self.gnupg_var)
+ self.gnupg.grid (row = 0, column = 1)
+
+ self.openssh_label = Label (self.options_frame)
+ self.openssh_label["text"] = "Generate OpenSSH key"
+ self.openssh_label.grid ()
+
+ self.openssh_var = IntVar ()
+ self.openssh_var.set (1 if self.arguments.openssh else 0)
+ self.openssh_var.trace ("w", self.update_widgets)
+
+ self.openssh = Checkbutton (self.options_frame,
+ variable = self.openssh_var)
+ self.openssh.grid (row = 1, column = 1)
+
+
+ self.button_frame = Frame (self)
+ self.button_frame.pack (fill = X)
+
+ self._generate = Button (self.button_frame)
+ self._generate["text"] = "Generate Keys"
+ self._generate["command"] = self.generate
+ self.balloon.bind_widget (self._generate,
+ msg = "Generate the keys as configured above")
+ self._generate.pack (side = LEFT, fill = Y)
+
+ self._quit = Button (self.button_frame)
+ self._quit["text"] = "Quit"
+ self._quit["command"] = self.quit
+ self.balloon.bind_widget (self._quit,
+ msg = "Quit the program immediately")
+ self._quit.pack (side = LEFT)
+
+ self.update_widgets ()
+
+
+ def valid_state (self):
+ if not self.openssh_var.get () and not self.gnupg_var.get ():
+ return False
+
+ if gnupg_exists (self.arguments) and openssh_exists (self.arguments):
+ return False
+
+ if not valid_email (self.email_var.get ()):
+ return False
+
+ if not valid_name (self.name_var.get ()):
+ return False
+
+ if not valid_comment (self.comment_var.get ()):
+ return False
+
+ return True
+
+
+ def update_widgets (self, *args):
+ valid = self.valid_state ()
+
+ self._generate["state"] = NORMAL if valid else DISABLED
+
+ name = self.name_var.get ()
+
+ valid = valid_name (name)
+ self.name["fg"] = "black" if valid else "red"
+ self.name_label["fg"] = "black" if valid else "red"
+
+ email = self.email_var.get ()
+
+ valid = valid_email (email)
+ self.email["fg"] = "black" if valid else "red"
+ self.email_label["fg"] = "black" if valid else "red"
+
+ comment = self.comment_var.get ()
+
+ valid = valid_comment (comment)
+ self.comment["fg"] = "black" if valid else "red"
+ self.comment_label["fg"] = "black" if valid else "red"
+
+ exists = gnupg_exists (self.arguments)
+ self.gnupg["state"] = NORMAL if not exists else DISABLED
+
+ exists = openssh_exists (self.arguments)
+ self.openssh["state"] = NORMAL if not exists else DISABLED
+
+ gnupg_key = name
+ if comment.strip () != "":
+ gnupg_key + " ({}) ".format (comment)
+ gnupg_key += "<{}>".format (email)
+
+ user = self.user_var.get ()
+ host = self.host_var.get ()
+
+ openssh_key = "{}@{}".format (user, host)
+
+ msg = dedented ("""
+ Generate a GnuPG key for '{}' and configure a default setup for it
+ """).format (gnupg_key)
+
+ self.balloon.bind_widget (self.gnupg, msg = msg)
+ self.balloon.bind_widget (self.gnupg_label, msg = msg)
+
+ msg = dedented ("""
+ Generate an OpenSSH key for '{}' and configure a default setup for it
+ """).format (openssh_key)
+
+ self.balloon.bind_widget (self.openssh, msg = msg)
+ self.balloon.bind_widget (self.openssh_label, msg = msg)
+
+
+ def generate (self):
+ # TODO: capture and show stdout and stderr
+ if self.gnupg_var.get ():
+ gnupg_setup (self.arguments,
+ self.name_var.get (),
+ self.email_var.get (),
+ self.comment_var.get ())
+
+ if self.openssh_var.get ():
+ comment = "{}@{}".format (self.user_var.get (),
+ self.host_var.get ())
+ openssh_setup (self.arguments, comment)
+
+ # TODO: show summary before exiting
+ self.quit ()
+
+
+# TODO: use gtk instead? would be more consistent with the pinentry style
+# (assuming it's using gtk)
+def gui (arguments):
+ app = CryptoInstall (arguments)
+ app.mainloop ()
+
+