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 @@
-
- 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: