commit
b4ecafe61c
15 changed files with 115 additions and 104 deletions
6
.github/ISSUE_TEMPLATE/bug_report.md
vendored
6
.github/ISSUE_TEMPLATE/bug_report.md
vendored
|
|
@ -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
.travis.yml
23
.travis.yml
|
|
@ -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
|
||||
|
|
@ -27,3 +29,8 @@ notifications:
|
|||
addons:
|
||||
apt:
|
||||
update: true
|
||||
packages:
|
||||
- dh-make
|
||||
- ack-grep
|
||||
- devscripts
|
||||
- fakeroot
|
||||
|
|
|
|||
10
debian/changelog
vendored
10
debian/changelog
vendored
|
|
@ -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 <boltgolt@gmail.com> 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!)
|
||||
|
|
|
|||
4
debian/control
vendored
4
debian/control
vendored
|
|
@ -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 <boltgolt@gmail.com>
|
||||
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
debian/howdy.lintian-overrides
vendored
Normal file
7
debian/howdy.lintian-overrides
vendored
Normal file
|
|
@ -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
debian/postinst
vendored
54
debian/postinst
vendored
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env python3
|
||||
#!/usr/bin/python3
|
||||
# Installation script to install howdy
|
||||
# Executed after primary apt install
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -98,7 +103,7 @@ 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")
|
||||
|
|
@ -106,19 +111,26 @@ 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
|
||||
|
|
@ -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))
|
||||
|
|
|
|||
76
debian/preinst
vendored
76
debian/preinst
vendored
|
|
@ -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
|
||||
|
||||
|
|
@ -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))
|
||||
|
||||
|
|
@ -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)
|
||||
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")
|
||||
# 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) + '"'
|
||||
# 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)
|
||||
# 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)
|
||||
# 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
|
||||
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
|
||||
|
||||
# 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))
|
||||
# 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))
|
||||
|
||||
# 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
debian/prerm
vendored
2
debian/prerm
vendored
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env python3
|
||||
#!/usr/bin/python3
|
||||
# Executed on deinstallation
|
||||
# Completely remove howdy from the system
|
||||
|
||||
|
|
|
|||
3
debian/rules
vendored
3
debian/rules
vendored
|
|
@ -6,6 +6,3 @@ include /usr/share/dpkg/default.mk
|
|||
|
||||
%:
|
||||
dh $@
|
||||
|
||||
binary:
|
||||
dh binary
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ insert_model = {
|
|||
}
|
||||
|
||||
# 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":
|
||||
|
|
|
|||
|
|
@ -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"])
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ config = configparser.ConfigParser()
|
|||
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":
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ for model in models:
|
|||
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":
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ config = ConfigParser.ConfigParser()
|
|||
config.read(os.path.dirname(os.path.abspath(__file__)) + "/config.ini")
|
||||
|
||||
def doAuth(pamh):
|
||||
"""Start authentication in a seperate process"""
|
||||
"""Starts authentication in a seperate process"""
|
||||
|
||||
# Abort is Howdy is disabled
|
||||
if config.get("core", "disabled") == "true":
|
||||
|
|
@ -25,7 +25,7 @@ def doAuth(pamh):
|
|||
sys.exit(0)
|
||||
|
||||
# Run compare as python3 subprocess to circumvent python version and import issues
|
||||
status = subprocess.call(["python3", os.path.dirname(os.path.abspath(__file__)) + "/compare.py", pamh.get_user()])
|
||||
status = subprocess.call(["/usr/bin/python3", os.path.dirname(os.path.abspath(__file__)) + "/compare.py", pamh.get_user()])
|
||||
|
||||
# Status 10 means we couldn't find any face models
|
||||
if status == 10:
|
||||
|
|
@ -62,9 +62,9 @@ def pam_sm_open_session(pamh, flags, args):
|
|||
return doAuth(pamh)
|
||||
|
||||
def pam_sm_close_session(pamh, flags, argv):
|
||||
"""We don't need to clean anyting up at the end of a session, so return true"""
|
||||
"""We don't need to clean anyting up at the end of a session, so returns true"""
|
||||
return pamh.PAM_SUCCESS
|
||||
|
||||
def pam_sm_setcred(pamh, flags, argv):
|
||||
"""We don't need set any credentials, so return true"""
|
||||
"""We don't need set any credentials, so returns true"""
|
||||
return pamh.PAM_SUCCESS
|
||||
|
|
|
|||
Loading…
Reference in a new issue