Skip to content

Commit

Permalink
Merge pull request #94 from boltgolt/dev
Browse files Browse the repository at this point in the history
Version 2.4.0
  • Loading branch information
boltgolt authored Nov 9, 2018
2 parents 0f4a116 + 5741357 commit b4ecafe
Show file tree
Hide file tree
Showing 15 changed files with 120 additions and 109 deletions.
6 changes: 3 additions & 3 deletions .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ _Please describe the issue in as much detail as possible, including any errors a

----

- [ ] I've searched for similar issues already, and my issue has not been reported yet.
I've searched for similar issues already, and my issue has not been reported yet.

Linux distribution (if applicable):
Linux distribution (if applicable):

Howdy version:
Howdy version:
23 changes: 15 additions & 8 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,24 +1,26 @@
sudo: required
language: python
python:
- "3.4"
- "3.6"

install:
# Install build tools and ack-grep for checks
- sudo apt install devscripts dh-make ack-grep -y
python: "3.6"

script:
# Build the binary (.deb)
- debuild -i -us -uc -b
# Install the binary, also fireing the debian scripts
# Install the binary, running the debian scripts in the process
- sudo apt install ../*.deb -y

# Confirm the cv2 module has been installed correctly
- sudo /usr/bin/env python3 -c "import cv2; print(cv2.__version__);"
# Confirm the face_recognition module has been installed correctly
- sudo /usr/bin/env python3 -c "import face_recognition; print(face_recognition.__version__);"

# Check if the username passthough works correctly with sudo
- 'howdy | ack-grep --passthru --color "current active user: travis"'
- 'sudo howdy | ack-grep --passthru --color "current active user: travis"'

# Remove howdy from the installation
- sudo apt purge howdy -y


notifications:
email:
on_success: never
Expand All @@ -27,3 +29,8 @@ notifications:
addons:
apt:
update: true
packages:
- dh-make
- ack-grep
- devscripts
- fakeroot
10 changes: 10 additions & 0 deletions debian/changelog
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
howdy (2.4.0) xenial; urgency=medium

* Cameras are now selected by path instead of by video device number (thanks @Rhiyo!)
* Added fallbacks to $EDITOR for the config command (thanks @yassineim!)
* Fixed missing cv2 module after installation (thanks @bendandersen and many others!)
* Fixed file permissions crashing Howdy in some cases (thanks @GJDitchfield!)
* Fixed howdy using python3 from local virtual environment (thanks @EdwardJB!)

-- boltgolt <[email protected]> Fri, 09 Nov 2018 20:59:45 +0100

howdy (2.3.1) xenial; urgency=high

* Fixed issue where `frame_width` and `frame_height` would be completely ignored (thanks @janecz-n!)
Expand Down
4 changes: 2 additions & 2 deletions debian/control
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ Source: howdy
Section: misc
Priority: optional
Standards-Version: 3.9.7
Build-Depends: python, dh-python, devscripts, dh-make, debhelper
Build-Depends: python, dh-python, devscripts, dh-make, debhelper, fakeroot
Maintainer: boltgolt <[email protected]>
Vcs-Git: https://github.com/boltgolt/howdy

Package: howdy
Homepage: https://github.com/boltgolt/howdy
Architecture: all
Depends: ${misc:Depends}, git, python3, python3-pip, python3-dev, python3-setuptools, build-essential, libpam-python, fswebcam, libopencv-dev, python-opencv, cmake
Depends: ${misc:Depends}, git, python3, python3-pip, python3-dev, python3-setuptools, libpam-python, fswebcam, libopencv-dev, python-opencv, cmake, streamer
Description: Howdy: Windows Hello style authentication for Linux.
Use your built-in IR emitters and camera in combination with face recognition
to prove who you are.
7 changes: 7 additions & 0 deletions debian/howdy.lintian-overrides
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# W: Don't require ugly linebreaks in last 5 chars
howdy: debian-changelog-line-too-long

# E: Allows the name Howdy to show up in Ubuntu updater
howdy: description-starts-with-package-name
# E: Allows python for installation scripts
howdy: unknown-control-interpreter
54 changes: 19 additions & 35 deletions debian/postinst
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/usr/bin/env python3
#!/usr/bin/python3
# Installation script to install howdy
# Executed after primary apt install

Expand Down Expand Up @@ -53,6 +53,11 @@ if not os.path.exists("/tmp/howdy_picked_device"):
# Go through every setting in the old config and apply it to the new file
for section in oldConf.sections():
for (key, value) in oldConf.items(section):
# If config is still using the old device_id parameter, convert it to a path
if key == "device_id":
key = "device_path"
value = "/dev/video" + value

try:
newConf.set(section, key, value)
# Add a new section where needed
Expand Down Expand Up @@ -98,27 +103,34 @@ print("Temporary dlib files removed")

log("Installing python dependencies")

# Install face_recognition though pip
# Install direct dependencies so pip does not freak out with the manual dlib install
handleStatus(subprocess.call(["pip3", "install", "--cache-dir", "/tmp/pip_howdy", "face_recognition_models==0.3.0", "Click>=6.0", "numpy", "Pillow"]))

log("Installing face_recognition")

# Install face_recognition though pip
handleStatus(subprocess.call(["pip3", "install", "--cache-dir", "/tmp/pip_howdy", "--no-deps", "face_recognition==1.2.2"]))

try:
import cv2
except Exception as e:
log("Reinstalling opencv2")
handleStatus(subprocess.call(["pip3", "install", "opencv-python"]))

log("Configuring howdy")

# Manually change the camera id to the one picked
for line in fileinput.input(["/lib/security/howdy/config.ini"], inplace = 1):
print(line.replace("device_id = 1", "device_id = " + picked), end="")
print(line.replace("device_path = none", "device_path = " + picked), end="")
print("Camera ID saved")

# Secure the howdy folder
handleStatus(subprocess.call(["chmod 600 -R /lib/security/howdy/"], shell=True))
handleStatus(subprocess.call(["chmod 744 -R /lib/security/howdy/"], shell=True))

# Allow anyone to execute the python CLI
handleStatus(subprocess.call(["chmod 755 /lib/security/howdy"], shell=True))
handleStatus(subprocess.call(["chmod 744 /lib/security/howdy/cli.py"], shell=True))
handleStatus(subprocess.call(["chmod 744 -R /lib/security/howdy/cli"], shell=True))
handleStatus(subprocess.call(["chmod 755 /lib/security/howdy/cli.py"], shell=True))
handleStatus(subprocess.call(["chmod 755 -R /lib/security/howdy/cli"], shell=True))
print("Permissions set")

# Make the CLI executable as howdy
Expand Down Expand Up @@ -198,33 +210,5 @@ common_auth = open("/etc/pam.d/common-auth", "w")
common_auth.write("".join(outlines))
common_auth.close()

# From here onwards the installation is complete
# We want to gather more information about the types or IR camera's
# used though, and the following lines are data gathering
# No data is ever uploaded without permission

if "HOWDY_NO_PROMPT" not in os.environ:
# List all video devices
diag_out = "Video devices [IR=" + picked + "]\n"
diag_out += "```\n"
diag_out += subprocess.check_output(['ls /dev/ | grep video'], shell=True).decode("utf-8")
diag_out += "```\n"

# Get some info from the USB kernel listings
diag_out += "Lsusb output\n"
diag_out += "```\n"
diag_out += subprocess.check_output(['lsusb -vvvv | grep -i "Camera\|iFunction"'], shell=True).decode("utf-8")
diag_out += "```\n"

# Get camera information from video4linux
diag_out += "Udevadm\n"
diag_out += "```\n"
diag_out += subprocess.check_output(['udevadm info -r --query=all -n /dev/video' + picked + ' | grep -i "ID_BUS\|ID_MODEL_ID\|ID_VENDOR_ID\|ID_V4L_PRODUCT\|ID_MODEL"'], shell=True).decode("utf-8")
diag_out += "```"

# Print it all as a clickable link to a new github issue
print("https://github.com/boltgolt/howdy-reports/issues/new?title=Post-installation%20camera%20information&body=" + urllib.parse.quote_plus(diag_out) + "\n")

# Let the user know what to do with the link
# Sign off
print("Installation complete.")
print(col(2) + "If you want to help the development, please use the link above to post some camera-related information to github!" + col(0))
86 changes: 42 additions & 44 deletions debian/preinst
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/usr/bin/env python3
#!/usr/bin/python3
# Used to check cameras before commiting to install
# Executed before primary apt install of files

Expand Down Expand Up @@ -35,7 +35,7 @@ if "install" not in sys.argv:
sys.exit(0)

# The default picked video device id
picked = -1
picked = "none"

print(col(1) + "Starting IR camera check...\n" + col(0))

Expand All @@ -45,64 +45,62 @@ 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("0")
out_file.write("none")

sys.exit(0)

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

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

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().strip() == "y" or ans.lower().strip() == "yes":
picked = dev[5:]
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 == -1:
if picked == "none":
print(col(3) + "No suitable IR camera found, aborting install." + col(0))
sys.exit(23)

# 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(str(picked))
out_file.write("/dev/v4l/by-path/" + picked)

# Add a line break
print("")
2 changes: 1 addition & 1 deletion debian/prerm
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/usr/bin/env python3
#!/usr/bin/python3
# Executed on deinstallation
# Completely remove howdy from the system

Expand Down
3 changes: 0 additions & 3 deletions debian/rules
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,3 @@ include /usr/share/dpkg/default.mk

%:
dh $@

binary:
dh binary
2 changes: 1 addition & 1 deletion src/cli/add.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@
}

# Open the camera
video_capture = cv2.VideoCapture(int(config.get("video", "device_id")))
video_capture = cv2.VideoCapture(config.get("video", "device_path"))

# Force MJPEG decoding if true
if config.get("video", "force_mjpeg") == "true":
Expand Down
16 changes: 12 additions & 4 deletions src/cli/config.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
# Open the config file in gedit
# Open the config file in an editor

# Import required modules
import os
import time
import subprocess

# Let the user know what we're doing
print("Opening config.ini in the default editor")

# Open gedit as a subprocess and fork it
subprocess.call(["/etc/alternatives/editor", os.path.dirname(os.path.realpath(__file__)) + "/../config.ini"])
# Default to the nano editor
editor = "/bin/nano"

# Use the user preferred editor if available
if os.path.isfile("/etc/alternatives/editor"):
editor = "/etc/alternatives/editor"
elif "EDITOR" in os.environ:
editor = os.environ["EDITOR"]

# Open the editor as a subprocess and fork it
subprocess.call([editor, os.path.dirname(os.path.realpath(__file__)) + "/../config.ini"])
2 changes: 1 addition & 1 deletion src/cli/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
config.read(path + "/../config.ini")

# Start capturing from the configured webcam
video_capture = cv2.VideoCapture(int(config.get("video", "device_id")))
video_capture = cv2.VideoCapture(config.get("video", "device_path"))

# Force MJPEG decoding if true
if config.get("video", "force_mjpeg") == "true":
Expand Down
2 changes: 1 addition & 1 deletion src/compare.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def stop(status):
timings.append(time.time())

# Start video capture on the IR camera
video_capture = cv2.VideoCapture(int(config.get("video", "device_id")))
video_capture = cv2.VideoCapture(config.get("video", "device_path"))

# Force MJPEG decoding if true
if config.get("video", "force_mjpeg") == "true":
Expand Down
4 changes: 2 additions & 2 deletions src/config.ini
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ certainty = 3.5
# The number of seconds to search before timing out
timout = 4

# The /dev/videoX id to capture frames from
# The path of the device to capture frames from
# Should be set automatically by the installer
device_id = 1
device_path = none

# Scale down the video feed to this maximum height
# Speeds up face recognition but can make it less precise
Expand Down
Loading

0 comments on commit b4ecafe

Please sign in to comment.