diff --git a/.travis.yml b/.travis.yml index c4959e3..d27dc7f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,4 +13,4 @@ script: - sudo apt purge howdy -y notifications: - email: false + email: true diff --git a/README.md b/README.md index 3b76ee9..3094fa0 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Howdy for Ubuntu [![Build Status](https://travis-ci.org/Boltgolt/howdy.svg?branch=dev)](https://travis-ci.org/Boltgolt/howdy) +# Howdy for Ubuntu [![](https://travis-ci.org/Boltgolt/howdy.svg?branch=dev)](https://travis-ci.org/Boltgolt/howdy) Windows Helloâ„¢ style authentication for Ubuntu. Use your built-in IR emitters and camera in combination with face recognition to prove who you are. @@ -24,16 +24,21 @@ If nothing went wrong we should be able to run sudo by just showing your face. O The installer adds a `howdy` command to manage face models for the current user. Use `howdy help` to list the available options. -| Command | Description | Needs user | -|-----------|-----------------------------------------------|------------| -| `add` | Add a new face model for the given user | Yes | -| `clear` | Remove all face models for the given user | Yes | -| `config` | Open the config file in nano | No | -| `disable` | Disable or enable howdy | No | -| `help` | Show a help page | No | -| `list` | List all saved face models for the given user | Yes | -| `remove` | Remove a specific model for the given user | Yes | -| `test` | Test the camera and recognition methods | No | +Usage: +``` +howdy [user] [argument] +``` + +| Command | Description | User required | +|-----------|-----------------------------------------------|---------------| +| `add` | Add a new face model for the given user | Yes | +| `clear` | Remove all face models for the given user | Yes | +| `config` | Open the config file in nano | No | +| `disable` | Disable or enable howdy | No | +| `help` | Show a help page | No | +| `list` | List all saved face models for the given user | Yes | +| `remove` | Remove a specific model for the given user | Yes | +| `test` | Test the camera and recognition methods | No | ### Troubleshooting diff --git a/debian/postinst b/debian/postinst index ba50e14..2b764a1 100755 --- a/debian/postinst +++ b/debian/postinst @@ -12,6 +12,9 @@ import signal import fileinput import urllib.parse +if "configure" not in sys.argv: + sys.exit(0) + def log(text): """Print a nicely formatted line to stdout""" print("\n>>> \033[32m" + text + "\033[0m\n") @@ -22,77 +25,21 @@ def handleStatus(status): print("\033[31mError while running last command\033[0m") sys.exit(1) -# Check if we're running as root -user = os.getenv("SUDO_USER") -if user is None: - print("Can't continue installation without root rights.") - sys.exit(1) - log("Upgrading pip to the latest version") +# We're not in fresh configuration mode, so exit +if not os.path.exists("/tmp/howdy_picked_device"): + sys.exit(0) + +in_file = open("/tmp/howdy_picked_device", "r") +picked = int(in_file.read()) +in_file.close() + +subprocess.call(["rm /tmp/howdy_picked_device"], shell=True) + # Update pip handleStatus(subprocess.call(["pip3 install --upgrade pip"], shell=True)) -log("Starting camera check") - -# Get all devices -devices = os.listdir("/dev") -# The picked video device id -picked = -1 - -# If prompting has been disabled, skip camera check -if "HOWDY_NO_PROMPT" in os.environ: - print("\033[33mAUTOMATED INSTALL, YOU WILL NOT BE ASKED FOR INPUT AND CHECKS WILL BE SKIPPED\033[0m") - picked = "0" -else: - # Loop though all devices - for dev in devices: - # Only use the video devices - if (dev[:5] == "video"): - time.sleep(.5) - - # The full path to the device is the default name - device_name = "/dev/" + dev - # Get the udevadm details to try to get a better name - udevadm = subprocess.check_output(["udevadm info -r --query=all -n " + device_name], shell=True).decode("utf-8") - - # Loop though udevadm to search for a better name - for line in udevadm.split("\n"): - # Match it and encase it in quotes - re_name = re.search('product.*=(.*)$', line, re.IGNORECASE) - if re_name: - device_name = '"' + re_name.group(1) + '"' - - # Show what device we're using - print("Trying " + device_name) - - # Let fswebcam keep the camera open in the background - sub = subprocess.Popen(["fswebcam -S 9999999999 -d /dev/" + dev + " /dev/null 2>/dev/null"], shell=True, preexec_fn=os.setsid) - - try: - # Ask the user if this is the right one - print("\033[33mOne of your cameras should now be on.\033[0m") - ans = input("Did your IR emitters turn on? [y/N]: ") - except KeyboardInterrupt: - # Kill fswebcam if the user aborts - os.killpg(os.getpgid(sub.pid), signal.SIGTERM) - raise - - # The user has answered, kill fswebcam - os.killpg(os.getpgid(sub.pid), signal.SIGTERM) - - # Set this camera as picked if the answer was yes, go to the next one if no - if (ans.lower() == "y"): - picked = dev[5:] - break - else: - print("Inerpeting as a \"NO\"\n") - -# Abort if no camera was picked -if (picked == -1): - print("\033[31mNo suitable IR camera found\033[0m") - sys.exit(1) - log("Cloning dlib") # Clone the git to /tmp diff --git a/debian/preinst b/debian/preinst new file mode 100644 index 0000000..1fabc77 --- /dev/null +++ b/debian/preinst @@ -0,0 +1,89 @@ +#!/usr/bin/env python3 +# Used to check cameras before commiting to install +# Executed before primary apt install of files + +def col(id): + if id == 1: return "\033[32m" + if id == 2: return "\033[33m" + if id == 3: return "\033[31m" + return "\033[0m" + +import subprocess +import time +import sys +import os +import re +import signal + +if "install" not in sys.argv: + sys.exit(0) + +# The picked video device id +picked = -1 + +print(col(1) + "Starting IR camera check...\n" + col(0)) + +# If prompting has been disabled, skip camera check +if "HOWDY_NO_PROMPT" in os.environ: + print(col(2) + "AUTOMATED INSTALL, YOU WILL NOT BE ASKED FOR INPUT AND CHECKS WILL BE SKIPPED" + col(0)) + + with open("/tmp/howdy_picked_device", "w") as out_file: + out_file.write("0") + + sys.exit(0) + +# Get all devices +devices = os.listdir("/dev") + +# Loop though all devices +for dev in devices: + # Only use the video devices + if (dev[:5] == "video"): + time.sleep(.5) + + # The full path to the device is the default name + device_name = "/dev/" + dev + # Get the udevadm details to try to get a better name + udevadm = subprocess.check_output(["udevadm info -r --query=all -n " + device_name], shell=True).decode("utf-8") + + # Loop though udevadm to search for a better name + for line in udevadm.split("\n"): + # Match it and encase it in quotes + re_name = re.search('product.*=(.*)$', line, re.IGNORECASE) + if re_name: + device_name = '"' + re_name.group(1) + '"' + + # Show what device we're using + print("Trying " + device_name) + + # Let fswebcam keep the camera open in the background + sub = subprocess.Popen(["fswebcam -S 9999999999 -d /dev/" + dev + " /dev/null 2>/dev/null"], shell=True, preexec_fn=os.setsid) + + try: + # Ask the user if this is the right one + print(col(2) + "One of your cameras should now be on." + col(0)) + ans = input("Did your IR emitters turn on? [y/N]: ") + except KeyboardInterrupt: + # Kill fswebcam if the user aborts + os.killpg(os.getpgid(sub.pid), signal.SIGTERM) + raise + + # The user has answered, kill fswebcam + os.killpg(os.getpgid(sub.pid), signal.SIGTERM) + + # Set this camera as picked if the answer was yes, go to the next one if no + if ans.lower() == "y" or ans.lower() == "yes": + picked = dev[5:] + break + else: + print("Interpreting as a " + col(3) + "\"NO\"\n" + col(0)) + +# Abort if no camera was picked +if picked == -1: + print(col(3) + "No suitable IR camera found, aborting install." + col(0)) + sys.exit(23) + +with open("/tmp/howdy_picked_device", "w") as out_file: + out_file.write(str(picked)) + +print("") diff --git a/debian/prerm b/debian/prerm index e1600f3..910bd88 100755 --- a/debian/prerm +++ b/debian/prerm @@ -2,28 +2,27 @@ # Executed on deinstallation # Completely remove howdy from the system +def col(id): + if id == 1: return "\033[32m" + if id == 2: return "\033[33m" + if id == 3: return "\033[31m" + return "\033[0m" + # Import required modules import subprocess # Remove files and symlinks -try: - subprocess.call(["rm -rf /lib/security/howdy/"], shell=True) -except e: - pass try: subprocess.call(["rm /usr/share/bash-completion/completions/howdy"], shell=True) except e: + print("Can't remove autocompletion script") pass -subprocess.call(["rm /usr/bin/howdy"], shell=True) - # Remove face_recognition and dlib subprocess.call(["pip3 uninstall face_recognition dlib -y --no-cache-dir"], shell=True) # Print a tearbending message -print(""" -Howdy has been uninstalled :'( - +print(col(2) + """ There are still lines in /etc/pam.d/common-auth that can't be removed automatically Run "nano /etc/pam.d/common-auth" to remove them by hand\ -""") +""" + col(0))