diff --git a/howdy-gtk/debian/postinst b/howdy-gtk/debian/postinst new file mode 100644 index 0000000..1351668 --- /dev/null +++ b/howdy-gtk/debian/postinst @@ -0,0 +1,2 @@ +#!/bin/sh +pip3 install elevate diff --git a/howdy-gtk/src/authsticky.py b/howdy-gtk/src/authsticky.py index 8c4d964..3f21d07 100644 --- a/howdy-gtk/src/authsticky.py +++ b/howdy-gtk/src/authsticky.py @@ -76,7 +76,6 @@ class StickyWindow(gtk.Window): # Start GTK main loop gtk.main() - def draw(self, widget, ctx): """Draw the UI""" # Change cursor to the kill icon @@ -123,7 +122,6 @@ class StickyWindow(gtk.Window): ctx.select_font_face("Arial", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL) ctx.show_text(subtext) - def catch_stdin(self): """Catch input from stdin and redraw""" global message, subtext @@ -146,11 +144,11 @@ class StickyWindow(gtk.Window): # Fire this function again in 10ms, as we're waiting on IO in readline anyway gobject.timeout_add(10, self.catch_stdin) - def exit(self, widget, context): """Cleanly exit""" gtk.main_quit() + # Make sure we quit on a SIGINT signal.signal(signal.SIGINT, signal.SIG_DFL) diff --git a/howdy-gtk/src/ui.glade b/howdy-gtk/src/ui.glade index 29df8f1..9ed587b 100644 --- a/howdy-gtk/src/ui.glade +++ b/howdy-gtk/src/ui.glade @@ -4,6 +4,7 @@ False + 5 Howdy Configuration center logo.png @@ -11,24 +12,26 @@ True True + False - + True - True + False vertical - + True False + 5 + 5 5 - 10 + 5 True False center - 10 - Active user: + Showing saved models for: False @@ -40,6 +43,7 @@ True False + False @@ -47,22 +51,6 @@ 1 - - - Add new model - True - True - True - 10 - 0.46000000834465027 - - - False - False - end - 2 - - Add new user @@ -80,19 +68,23 @@ - False - True + False + True + 0 True False + 5 + 5 vertical True False + 5 5 @@ -101,35 +93,74 @@ 0 + + + False + True + 1 + + + + + True + False + 5 + 7 + 5 - + + + + + gtk-add True True - - - + True + True + 0.5899999737739563 + True + False True + end 1 + + + gtk-delete + True + True + True + 5 + True + True + + + + False + True + end + 2 + + - True - True + False + True + end + 2 - - True - True False + 2 Models @@ -185,80 +216,4 @@ - - True - False - 10 - 10 - 5 - 5 - vertical - 5 - - - True - False - - - True - False - vertical - - - True - False - label - 3 - - - - - - False - True - 0 - - - - - True - False - label - - - False - True - 1 - - - - - False - True - 0 - - - - - Delete - True - True - True - True - - - False - True - end - 1 - - - - - False - True - 0 - - - diff --git a/howdy-gtk/src/window.py b/howdy-gtk/src/window.py index a6d780f..e0911d0 100644 --- a/howdy-gtk/src/window.py +++ b/howdy-gtk/src/window.py @@ -5,6 +5,7 @@ import signal import sys import os import subprocess +import elevate # Make sure we have the libs we need gi.require_version("Gtk", "3.0") @@ -31,6 +32,19 @@ class MainWindow(gtk.Window): self.userlist = self.builder.get_object("userlist") self.modellistbox = self.builder.get_object("modellistbox") + # Create a treeview that will list the model data + self.treeview = gtk.TreeView() + + # Set the coloums + for i, column in enumerate(["ID", "Created", "Label"]): + cell = gtk.CellRendererText() + col = gtk.TreeViewColumn(column, cell, text=i) + + self.treeview.append_column(col) + + # Add the treeview + self.modellistbox.add(self.treeview) + filelist = os.listdir("/lib/security/howdy/models") self.active_user = "" @@ -42,8 +56,6 @@ class MainWindow(gtk.Window): self.userlist.set_active(0) - self.load_model_list() - self.window.show_all() # self.resize(300, 300) @@ -51,21 +63,94 @@ class MainWindow(gtk.Window): gtk.main() def load_model_list(self): - output = subprocess.check_output(["howdy", "list", "-U", self.active_user]) + """(Re)load the model list""" - lines = output.decode("utf-8") .split("\n")[3:-2] - print(lines) + # Execute the list commond to get the models + output = subprocess.check_output(["howdy", "list", "--plain", "-U", self.active_user]) - newrow = self.builder.get_object("modelrow") + # Split the output per line + # lines = output.decode("utf-8").split("\n") + lines = output.split("\n") - print(newrow.set_name("wat")) + # Create a datamodel + self.listmodel = gtk.ListStore(str, str, str) - self.modellistbox.add(newrow) - newrow2 = self.builder.get_object("modelrow") + # Add the models to the datamodel + for i in range(len(lines)): + self.listmodel.append(lines[i].split(",")) - # print(newrow.get_object("modelrowname")) + self.treeview.set_model(self.listmodel) - self.modellistbox.add(newrow2) + def on_user_change(self, select): + self.active_user = select.get_active_text() + self.load_model_list() + + def on_model_add(self, select): + dialog = gtk.MessageDialog(parent=self, flags=gtk.DialogFlags.MODAL, type=gtk.MessageType.QUESTION, buttons=gtk.ButtonsType.OK_CANCEL) + dialog.props.text = "Please enter a name for the new model, 24 characters max" + dialog.set_title("Confirm Model Creation") + # create the text input field + entry = gtk.Entry() + # create a horizontal box to pack the entry and a label + hbox = gtk.HBox() + hbox.pack_start(gtk.Label("Model name:"), False, 5, 5) + hbox.pack_end(entry, True, True, 5) + # some secondary text + # add it and show it + dialog.vbox.pack_end(hbox, True, True, 0) + dialog.show_all() + # go go go + response = dialog.run() + + text = entry.get_text() + dialog.destroy() + + if response == gtk.ResponseType.OK: + dialog = gtk.MessageDialog(parent=self, flags=gtk.DialogFlags.MODAL) + dialog.props.text = "Please look directly into the camera" + dialog.set_title("Creating Model") + dialog.show_all() + + status, output = subprocess.getstatusoutput(["howdy add -y -U " + self.active_user]) + + dialog.destroy() + + if status != 1: + dialog = gtk.MessageDialog(parent=self, flags=gtk.DialogFlags.MODAL, type=gtk.MessageType.ERROR, buttons=gtk.ButtonsType.CLOSE) + dialog.props.text = "Error while adding model, error code " + str(status) + ": \n\n" + dialog.format_secondary_text(output) + dialog.set_title("Howdy Error") + dialog.run() + dialog.destroy() + + self.load_model_list() + + def on_model_delete(self, select): + selection = self.treeview.get_selection() + (listmodel, rowlist) = selection.get_selected_rows() + + if len(rowlist) == 1: + id = listmodel.get_value(listmodel.get_iter(rowlist[0]), 0) + name = listmodel.get_value(listmodel.get_iter(rowlist[0]), 2) + + dialog = gtk.MessageDialog(parent=self, flags=gtk.DialogFlags.MODAL, buttons=gtk.ButtonsType.OK_CANCEL) + dialog.props.text = "Are you sure you want to delete model " + id + " (" + name + ")?" + dialog.set_title("Confirm Model Deletion") + response = dialog.run() + dialog.destroy() + + if response == gtk.ResponseType.OK: + status, output = subprocess.getstatusoutput(["howdy remove " + id + " -y -U " + self.active_user]) + + if status != 0: + dialog = gtk.MessageDialog(parent=self, flags=gtk.DialogFlags.MODAL, type=gtk.MessageType.ERROR, buttons=gtk.ButtonsType.CLOSE) + dialog.props.text = "Error while deleting model, error code " + str(status) + ": \n\n" + dialog.format_secondary_text(output) + dialog.set_title("Howdy Error") + dialog.run() + dialog.destroy() + + self.load_model_list() def exit(self, widget, context): """Cleanly exit""" @@ -76,5 +161,8 @@ class MainWindow(gtk.Window): # Make sure we quit on a SIGINT signal.signal(signal.SIGINT, signal.SIG_DFL) +# Make sure we run as sudo +elevate.elevate() + # Open the GTK window window = MainWindow() diff --git a/src/cli/remove.py b/src/cli/remove.py index 45e2036..49b8bce 100644 --- a/src/cli/remove.py +++ b/src/cli/remove.py @@ -61,7 +61,7 @@ for enc in encodings: # Abort if no matching id was found if not found: print("No model with ID " + builtins.howdy_args.argument + " exists for " + user) - sys.exit() + sys.exit(1) # Remove the entire file if this encoding is the only one if len(encodings) == 1: