-
-
Notifications
You must be signed in to change notification settings - Fork 313
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #3 from Boltgolt/dev
Adding new installer and CLI
- Loading branch information
Showing
16 changed files
with
722 additions
and
142 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,46 +1,41 @@ | ||
# Howdy for Ubuntu | ||
|
||
Windows Hello™ style authentication for Ubuntu. Use your build in IR emitters and camera in combination with face recognition to prove who you are. | ||
Windows Hello™ style authentication for Ubuntu. Use your built-in IR emitters and camera in combination with face recognition to prove who you are. | ||
|
||
Using the central authentication system in Linux (PAM), this works everywhere you would otherwise need your password: Login, lock screen, sudo, su, etc. | ||
|
||
### Installation | ||
|
||
First we need to install pam-python, fswebcam and OpenCV from the Ubuntu repositories: | ||
Run the installer by pasting (`ctrl+shift+V`) the following command into the terminal: | ||
|
||
``` | ||
sudo apt install libpam-python fswebcam libopencv-dev python-opencv | ||
wget -O /tmp/howdy_install.py https://raw.githubusercontent.com/Boltgolt/howdy/master/installer.py && sudo python3 /tmp/howdy_install.py | ||
``` | ||
|
||
After that, install the face_recognition python module. There's an excellent step by step guide on how to do this on [its github page](https://github.com/ageitgey/face_recognition#installation). | ||
|
||
In the root of your cloned repo is a file called `config.ini`. The `device_id` variable in this file is important, make sure it is the IR camera and not your normal webcam. | ||
This will guide you through the installation. When that's done run `howdy USER add` and replace `USER` with your username to add a face model. | ||
|
||
Now it's time to let Howdy learn your face. The learn.py script will make 3 models of your face and store them as an encoded set in the `models` folder. To run the script, open a terminal, navigate to this repository and run: | ||
If nothing went wrong we should be able to run sudo by just showing your face. Open a new terminal and run `sudo -i` to see it in action. | ||
|
||
``` | ||
python3 learn.py | ||
``` | ||
**Note:** The build of dlib can hang on 100% for over a minute, give it time. | ||
|
||
The script should guide you through the process. | ||
### Command line | ||
|
||
Finally we need to tell PAM that there's a new module installed. Open `/etc/pam.d/common-auth` as root (`sudo nano /etc/pam.d/common-auth`) and add the following line to the top of the file: | ||
The installer adds a `howdy` command to manage face models for the current user. Use `howdy help` to list the available options. | ||
|
||
``` | ||
auth sufficient pam_python.so /path/to/pam.py | ||
``` | ||
### Troubleshooting | ||
|
||
Replace the final argument with the full path to pam.py in this repository. The `sufficient` control tells PAM that Howdy is enough to authenticate the user, but if it fails we can fall back on more traditional methods. | ||
Any python errors get logged directly into the console and should indicate what went wrong. If authentication still fails but no errors are printed you could take a look at the last lines in `/var/log/auth.log` to see if anything has been reported there. | ||
|
||
If nothing went wrong we should be able to run sudo by just showing your face. Open a new terminal and run `sudo -i` to see it in action. | ||
|
||
### Troubleshooting | ||
If you encounter an error that hasn't been reported yet, don't be afraid to open a new issue. | ||
|
||
Any errors in the script itself get logged directly into the console and should indicate what went wrong. If authentication still fails but no errors are printed you could take a look at the last lines in `/var/log/auth.log` to see if anything has been reported there. | ||
### Uninstalling | ||
|
||
There is an uninstaller available, run `sudo python3 /lib/security/howdy/uninstall.py` to remove Howdy from your system. | ||
|
||
### A note on security | ||
|
||
This script is in no way as secure as a password and will never be. Although it's harder to fool than normal face recognition, a person who looks similar to you or well-printed photo of you could be enough to do it. | ||
|
||
To minimize the chance of this script being compromised, it's recommend to store this repo in `/etc/pam.d` and to make it read only. | ||
To minimize the chance of this script being compromised, it's recommend to leave this repo in /lib/security and to keep it read only. | ||
|
||
DO NOT USE THIS SCRIPT AS THE SOLE AUTHENTICATION METHOD FOR YOUR SYSTEM. | ||
DO NOT USE HOWDY AS THE SOLE AUTHENTICATION METHOD FOR YOUR SYSTEM. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
# Autocomplete file run in bash | ||
# Will sugest arguments on tab | ||
|
||
_howdy() { | ||
local cur prev opts | ||
COMPREPLY=() | ||
cur="${COMP_WORDS[COMP_CWORD]}" | ||
prev="${COMP_WORDS[COMP_CWORD-1]}" | ||
opts="help list add remove clear" | ||
|
||
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) | ||
return 0 | ||
} | ||
|
||
complete -F _howdy howdy |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
#!/usr/bin/env python3 | ||
|
||
# CLI directly called by running the howdy command | ||
|
||
# Import required modules | ||
import sys | ||
import os | ||
|
||
# Check if the minimum of 3 arugemnts has been met and print help otherwise | ||
if (len(sys.argv) < 3): | ||
print("Howdy IR face recognition help") | ||
import cli.help | ||
sys.exit() | ||
|
||
# The command given | ||
cmd = sys.argv[2] | ||
|
||
# Requre sudo for comamnds that need root rights to read the model files | ||
if cmd in ["list", "add", "remove", "clear"] and os.getenv("SUDO_USER") is None: | ||
print("Please run this command with sudo") | ||
sys.exit() | ||
|
||
# Call the right files for the given command | ||
if cmd == "list": | ||
import cli.list | ||
elif cmd == "help": | ||
print("Howdy IR face recognition") | ||
import cli.help | ||
elif cmd == "add": | ||
import cli.add | ||
elif cmd == "remove": | ||
import cli.remove | ||
elif cmd == "clear": | ||
import cli.clear | ||
else: | ||
# If the comand is invalid, check if the user hasn't swapped the username and command | ||
if sys.argv[1] in ["list", "add", "remove", "clear", "help"]: | ||
print("Usage: howdy <user> <command>") | ||
else: | ||
print('Unknown command "' + cmd + '"') | ||
import cli.help |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
# Clear all models by deleting the whole file | ||
|
||
# Import required modules | ||
import os | ||
import sys | ||
|
||
# Get the full path to this file | ||
path = os.path.dirname(os.path.abspath(__file__)) | ||
# Get the passed user | ||
user = sys.argv[1] | ||
|
||
# Check if the models folder is there | ||
if not os.path.exists(path + "/../models"): | ||
print("No models created yet, can't clear them if they don't exist") | ||
sys.exit() | ||
|
||
# Check if the user has a models file to delete | ||
if not os.path.isfile(path + "/../models/" + user + ".dat"): | ||
print(user + " has no models or they have been cleared already") | ||
sys.exit() | ||
|
||
# Double check with the user | ||
print("This will clear all models for " + user) | ||
ans = input("Do you want to continue [y/N]: ") | ||
|
||
# Abort if they don't answer y or Y | ||
if (ans.lower() != "y"): | ||
print('\nInerpeting as a "NO"') | ||
sys.exit() | ||
|
||
# Delete otherwise | ||
os.remove(path + "/../models/" + user + ".dat") | ||
print("\nModels cleared") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
# Prints a simple help page for the CLI | ||
|
||
print(""" | ||
Usage: | ||
howdy <user> <command> [argument] | ||
Commands: | ||
help Show this help page | ||
list List all saved face models for the current user | ||
add Add a new face model for the current user | ||
remove [id] Remove a specific model | ||
clear Remove all face models for the current user | ||
For support please visit | ||
https://github.com/Boltgolt/howdy\ | ||
""") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
# List all models for a user | ||
|
||
# Import required modules | ||
import sys | ||
import os | ||
import json | ||
import time | ||
|
||
# Get the absolute path and the username | ||
path = os.path.dirname(os.path.realpath(__file__)) + "/.." | ||
user = sys.argv[1] | ||
|
||
# Check if the models file has been created yet | ||
if not os.path.exists(path + "/models"): | ||
print("Face models have not been initialized yet, please run:") | ||
print("\n\thowdy " + user + " add\n") | ||
sys.exit(1) | ||
|
||
# Path to the models file | ||
enc_file = path + "/models/" + user + ".dat" | ||
|
||
# Try to load the models file and abort if the user does not have it yet | ||
try: | ||
encodings = json.load(open(enc_file)) | ||
except FileNotFoundError: | ||
print("No face model known for the user " + user + ", please run:") | ||
print("\n\thowdy " + user + " add\n") | ||
sys.exit(1) | ||
|
||
# Print a header | ||
print("Known face models for " + user + ":") | ||
print("\n\t\033[1;29mID Date Label\033[0m") | ||
|
||
# Loop through all encodings and print info about them | ||
for enc in encodings: | ||
# Start with a tab and print the id | ||
print("\t" + str(enc["id"]), end="") | ||
# Print padding spaces after the id | ||
print((4 - len(str(enc["id"]))) * " ", end="") | ||
# Format the time as ISO in the local timezone | ||
print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(enc["time"])), end="") | ||
# End with the label | ||
print(" " + enc["label"]) | ||
|
||
# Add a closing enter | ||
print() |
Oops, something went wrong.