Skip to content

Commit

Permalink
Merge pull request #370 from boltgolt/dev
Browse files Browse the repository at this point in the history
Version 2.6.0
  • Loading branch information
boltgolt authored Jun 22, 2020
2 parents d001f0f + c3b11d1 commit e495bda
Show file tree
Hide file tree
Showing 22 changed files with 573 additions and 220 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,9 @@ ENV/
# generated models
/src/models

# snapshots
/src/snapshots

# build files
debian/howdy.substvars
debian/files
Expand Down
7 changes: 6 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
sudo: required
dist: xenial
language: python
python: "3.6"
python:
- "3.4"
- "3.6"
- "3.7"
- "3.8-dev"

script:
# Build the binary (.deb)
Expand Down
24 changes: 24 additions & 0 deletions debian/changelog
Original file line number Diff line number Diff line change
@@ -1,3 +1,27 @@
howdy (2.6.0) xenial; urgency=medium

* Added new options to capture a snapshot of failed or even successful logins
* Added command that creates a new snapshot and saves it
* Added version command
* Added question to automatically set certainty value on installation
* Added automatic logging to system-wide auth.log
* Added clearer feedback when login is rejected due to dark frames (thanks @andrewmv!)
* Refactored video capture logic (thanks @AnthonyWharton!)
* Reordered the editor priorities for the config command
* Fixed gstreamer warnings showing up in console (thanks @ajnart!)
* Fixed issue where add command would never end
* Fixed test command overlay not being in color (thanks @PetePriority!)
* Fixed typo preventing timeout config option from working (thanks @Ajayneethikannan!)
* Fixed old numpy installation failure (thanks @rushabh-v!)
* Fixed issue where no PAM response would be returned
* Fixed CLAHE not being applied equally to all video commands (thanks @PetePriority!)
* Fixed an incorrect suggested command (thanks @TheButlah!)
* Fixed missing release method in video capture class
* Removed deprecated dlib flags (thanks @rhysperry111!)
* Removed streamer as a required dependency

-- boltgolt <[email protected]> Mon, 22 Jun 2020 16:11:46 +0200

howdy (2.5.1) xenial; urgency=medium

* Removed dismiss_lockscreen as it could lock users out of their system (thanks @ujjwalbe, @ju916 and many others!)
Expand Down
4 changes: 2 additions & 2 deletions debian/control
Original file line number Diff line number Diff line change
Expand Up @@ -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, streamer
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
Expand Down
12 changes: 11 additions & 1 deletion debian/postinst
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,12 @@ log("Upgrading pip to the latest version")
# Update pip
handleStatus(sc(["pip3", "install", "--upgrade", "pip"]))


log("Upgrading numpy to the lateset version")

# Update numpy
handleStatus(subprocess.call(["pip3", "install", "--upgrade", "numpy"]))

log("Downloading and unpacking data files")

# Run the bash script to download and unpack the .dat files needed
Expand Down Expand Up @@ -190,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="")

Expand Down
126 changes: 84 additions & 42 deletions debian/preinst
Original file line number Diff line number Diff line change
Expand Up @@ -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"


Expand Down Expand Up @@ -38,70 +39,111 @@ 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:
print(col(2) + "AUTOMATED INSTALL, YOU WILL NOT BE ASKED FOR INPUT AND CHECKS WILL BE SKIPPED" + col(0))

# 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)

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))

# Get all devices
devices = os.listdir("/dev/v4l/by-path")

# Loop though all devices
for dev in devices:
time.sleep(.5)

# 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")

# 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(
["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)

# Loop though all devices
for dev in devices:
time.sleep(.5)
# 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))

# 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")
# Abort if no camera was picked
if picked == "none":
print(col(3) + "No suitable IR camera found, aborting install." + col(0))
sys.exit(23)

# 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) + '"'
cert = 3.5

# Show what device we're using
print("Trying " + device_name)
# Give time to read
time.sleep(.5)

# 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)
print(col(1) + "\nStarting certainty auto config..." + col(0))

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
# 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.")

# The user has answered, kill fswebcam
os.killpg(os.getpgid(sub.pid), signal.SIGTERM)
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.")

# 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))
print("\nYou can always change this setting in the config.")
prof = input("What profile would you like to use? [f/b/s]: ")

# Abort if no camera was picked
if picked == "none":
print(col(3) + "No suitable IR camera found, aborting install." + col(0))
sys.exit(23)
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("")
1 change: 1 addition & 0 deletions debian/source/options
Original file line number Diff line number Diff line change
Expand Up @@ -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"
9 changes: 3 additions & 6 deletions fedora/howdy.spec
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Version: 2.5.1
%if %{with_snapshot}
Release: 0.1.git.%{date}%{shortcommit}%{?dist}
%else
Release: 3%{?dist}
Release: 4%{?dist}
%endif
Summary: Windows Hello™ style authentication for Linux

Expand All @@ -27,12 +27,9 @@ BuildRequires: polkit-devel
%if 0%{?fedora}
# We need python3-devel for pathfix.py
BuildRequires: python3-devel
Requires: python3dist(dlib) >= 6.0
Requires: python3dist(v4l2)
Requires: python3-face_recognition
Supplements: python3-face_recognition_models
Requires: python3dist(dlib) >= 6.0
Requires: python3-opencv
Requires: python3-pam
Requires: pam_python
%endif


Expand Down
54 changes: 32 additions & 22 deletions src/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,38 +26,44 @@
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 or test.",
metavar="command",
choices=["add", "clear", "config", "disable", "list", "remove", "test"])
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:
Expand Down Expand Up @@ -97,5 +103,9 @@
import cli.list
elif args.command == "remove":
import cli.remove
elif args.command == "snapshot":
import cli.snap
elif args.command == "test":
import cli.test
else:
print("Howdy 2.6.0")
Loading

0 comments on commit e495bda

Please sign in to comment.