From 23810ef3c9b7448c458cbf7d5b324a1e0afdb597 Mon Sep 17 00:00:00 2001 From: boltgolt Date: Mon, 22 Jun 2020 17:58:09 +0200 Subject: [PATCH] Added certainty question, fixed streamer dependency --- debian/control | 4 +- debian/postinst | 6 +- debian/preinst | 129 +++++++++++++++++++++++++-------------- debian/source/options | 1 + src/cli.py | 50 ++++++++------- src/cli/list.py | 2 +- src/dlib-data/install.sh | 2 +- 7 files changed, 121 insertions(+), 73 deletions(-) diff --git a/debian/control b/debian/control index efb16a1..0d2ae80 100644 --- a/debian/control +++ b/debian/control @@ -9,8 +9,8 @@ Vcs-Git: https://github.com/boltgolt/howdy Package: howdy Homepage: https://github.com/boltgolt/howdy Architecture: all -Depends: ${misc:Depends}, curl|wget, python3, python3-pip, python3-dev, python3-setuptools, libpam-python, fswebcam, libopencv-dev, cmake, fswebcam -Recommends: libatlas-base-dev | libopenblas-dev | liblapack-dev +Depends: ${misc:Depends}, curl|wget, python3, python3-pip, python3-dev, python3-setuptools, libpam-python, libopencv-dev, cmake +Recommends: libatlas-base-dev | libopenblas-dev | liblapack-dev, streamer Suggests: nvidia-cuda-dev (>= 7.5) Description: Howdy: Windows Hello style authentication for Linux. Use your built-in IR emitters and camera in combination with face recognition diff --git a/debian/postinst b/debian/postinst index 4ede83c..40fc93e 100755 --- a/debian/postinst +++ b/debian/postinst @@ -196,10 +196,14 @@ handleStatus(subprocess.call(["pip3", "install", "--no-cache-dir", "opencv-pytho log("Configuring howdy") +campath = picked.split(";")[0] +cert = picked.split(";")[1] + # Manually change the camera id to the one picked for line in fileinput.input(["/lib/security/howdy/config.ini"], inplace=1): - line = line.replace("device_path = none", "device_path = " + picked) + line = line.replace("device_path = none", "device_path = " + campath) line = line.replace("use_cnn = false", "use_cnn = " + str(cuda_used).lower()) + line = line.replace("certainty = 3.5", "certainty = " + cert) print(line, end="") diff --git a/debian/preinst b/debian/preinst index 8430d4a..9bb5aad 100755 --- a/debian/preinst +++ b/debian/preinst @@ -7,6 +7,7 @@ def col(id): if id == 1: return "\033[32m" if id == 2: return "\033[33m" if id == 3: return "\033[31m" + if id == 4: return "\033[1m" return "\033[0m" @@ -38,7 +39,6 @@ if "install" not in sys.argv: # The default picked video device id picked = "none" -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: @@ -46,67 +46,104 @@ if "HOWDY_NO_PROMPT" in os.environ: # Write the default device to disk and exit with open("/tmp/howdy_picked_device", "w") as out_file: - out_file.write("none") + out_file.write("none;3.5") sys.exit(0) -# Get all devices -devices = os.listdir("/dev/v4l/by-path") +fscheck = subprocess.call(["which", "streamer"], stdout=subprocess.PIPE) -# Loop though all devices -for dev in devices: - time.sleep(.5) +if fscheck == 1: + print(col(2) + "\nWARNING: Could not automatically find the right webcam, manual configuration after installation required\n" + col(0)) +else: + print(col(1) + "Starting IR camera check...\n" + col(0)) - # The full path to the device is the default name - device_name = "/dev/v4l/by-path/" + 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") + # Get all devices + devices = os.listdir("/dev/v4l/by-path") - # 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) + '"' + # Loop though all devices + for dev in devices: + time.sleep(.5) - # Show what device we're using - print("Trying " + device_name) + # The full path to the device is the default name + device_name = "/dev/v4l/by-path/" + 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") - # Let fswebcam keep the camera open in the background - sub = subprocess.Popen( - "fswebcam -l 1 -d /dev/v4l/by-path/%s" % dev, - shell=True, - preexec_fn=os.setsid, - stdout=subprocess.PIPE, - stdin=subprocess.PIPE) + # 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) + '"' - 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 + # Show what device we're using + print("Trying " + device_name) + + # Let fswebcam keep the camera open in the background + sub = subprocess.Popen( + ["streamer -t 1:0:0 -c /dev/v4l/by-path/" + dev + " -b 16 -f rgb24 -o /dev/null 1>/dev/null 2>/dev/null"], + shell=True, + preexec_fn=os.setsid, + stdout=subprocess.PIPE, + stdin=subprocess.PIPE) + + 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) - 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().strip() == "y" or ans.lower().strip() == "yes": + picked = dev + break + else: + print("Interpreting as a " + col(3) + "\"NO\"\n" + col(0)) - # Set this camera as picked if the answer was yes, go to the next one if no - if ans.lower().strip() == "y" or ans.lower().strip() == "yes": - picked = dev - break - else: - print("Interpreting as a " + col(3) + "\"NO\"\n" + col(0)) + # Abort if no camera was picked + if picked == "none": + print(col(3) + "No suitable IR camera found, aborting install." + col(0)) + sys.exit(23) -# Abort if no camera was picked -if picked == "none": - print(col(3) + "No suitable IR camera found, aborting install." + col(0)) - sys.exit(23) +cert = 3.5 + +# Give time to read +time.sleep(.5) + +print(col(1) + "\nStarting certainty auto config..." + col(0)) + +# Give more time to read +time.sleep(.5) + +print("\n\nAfter detection, Howdy knows how certain it is that the match is correct.") +print("How certain Howdy needs to be before authenticating you can be customized.") + +print(col(4) + "\nF: Fast." + col(0)) +print("Allows more fuzzy matches, but speeds up the scanning process greatly.") +print(col(4) + "\nB: Balanced." + col(0)) +print("Still relatively quick detection, but might not log you in when further away.") +print(col(4) + "\nS: Secure." + col(0)) +print("The safest option, but will take much longer to authenticate you.") + +print("\nYou can always change this setting in the config.") +prof = input("What profile would you like to use? [f/b/s]: ") + +if prof.lower().strip() == "f" or prof.lower().strip() == "fast": + cert = 1.5 +elif prof.lower().strip() == "b" or prof.lower().strip() == "balanced": + cert = 2.8 +elif prof.lower().strip() == "s" or prof.lower().strip() == "secure": + cert = 4 # Write the result to disk so postinst can have a look at it with open("/tmp/howdy_picked_device", "w") as out_file: - out_file.write("/dev/v4l/by-path/" + picked) + out_file.write("/dev/v4l/by-path/" + picked + ";" + str(cert)) # Add a line break print("") diff --git a/debian/source/options b/debian/source/options index 1216d00..994eed9 100644 --- a/debian/source/options +++ b/debian/source/options @@ -2,6 +2,7 @@ tar-ignore = ".git" tar-ignore = ".gitignore" tar-ignore = ".github" tar-ignore = "models" +tar-ignore = "snapshots" tar-ignore = "tests" tar-ignore = "README.md" tar-ignore = ".travis.yml" diff --git a/src/cli.py b/src/cli.py index 66793ce..29dadac 100755 --- a/src/cli.py +++ b/src/cli.py @@ -26,38 +26,44 @@ if user == "root" or user is None: user = env_user # Basic command setup -parser = argparse.ArgumentParser(description="Command line interface for Howdy face authentication.", - formatter_class=argparse.RawDescriptionHelpFormatter, - add_help=False, - prog="howdy", - epilog="For support please visit\nhttps://github.com/boltgolt/howdy") +parser = argparse.ArgumentParser( + description="Command line interface for Howdy face authentication.", + formatter_class=argparse.RawDescriptionHelpFormatter, + add_help=False, + prog="howdy", + epilog="For support please visit\nhttps://github.com/boltgolt/howdy") # Add an argument for the command -parser.add_argument("command", - help="The command option to execute, can be one of the following: add, clear, config, disable, list, remove, snapshot, test or version.", - metavar="command", - choices=["add", "clear", "config", "disable", "list", "remove", "snapshot", "test", "version"]) +parser.add_argument( + "command", + help="The command option to execute, can be one of the following: add, clear, config, disable, list, remove, snapshot, test or version.", + metavar="command", + choices=["add", "clear", "config", "disable", "list", "remove", "snapshot", "test", "version"]) # Add an argument for the extra arguments of diable and remove -parser.add_argument("argument", - help="Either 0 (enable) or 1 (disable) for the disable command, or the model ID for the remove command.", - nargs="?") +parser.add_argument( + "argument", + help="Either 0 (enable) or 1 (disable) for the disable command, or the model ID for the remove command.", + nargs="?") # Add the user flag -parser.add_argument("-U", "--user", - default=user, - help="Set the user account to use.") +parser.add_argument( + "-U", "--user", + default=user, + help="Set the user account to use.") # Add the -y flag -parser.add_argument("-y", - help="Skip all questions.", - action="store_true") +parser.add_argument( + "-y", + help="Skip all questions.", + action="store_true") # Overwrite the default help message so we can use a uppercase S -parser.add_argument("-h", "--help", - action="help", - default=argparse.SUPPRESS, - help="Show this help message and exit.") +parser.add_argument( + "-h", "--help", + action="help", + default=argparse.SUPPRESS, + help="Show this help message and exit.") # If we only have 1 argument we print the help text if len(sys.argv) < 2: diff --git a/src/cli/list.py b/src/cli/list.py index 2cc9b9c..fe05d6e 100644 --- a/src/cli/list.py +++ b/src/cli/list.py @@ -25,7 +25,7 @@ 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") + print("\n\tsudo howdy -U " + user + " add\n") sys.exit(1) # Print a header diff --git a/src/dlib-data/install.sh b/src/dlib-data/install.sh index 7fcabe6..5698f01 100755 --- a/src/dlib-data/install.sh +++ b/src/dlib-data/install.sh @@ -22,4 +22,4 @@ fi # Uncompress the data files and delete the original archive echo "Unpacking..." -bzip2 -d *.bz2 +bzip2 -d -f *.bz2