Skip to content

Commit b4ecafe

Browse files
authored
Merge pull request #94 from boltgolt/dev
Version 2.4.0
2 parents 0f4a116 + 5741357 commit b4ecafe

File tree

15 files changed

+120
-109
lines changed

15 files changed

+120
-109
lines changed

.github/ISSUE_TEMPLATE/bug_report.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ _Please describe the issue in as much detail as possible, including any errors a
1111

1212
----
1313

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

16-
Linux distribution (if applicable):
16+
Linux distribution (if applicable):
1717

18-
Howdy version:
18+
Howdy version:

.travis.yml

+15-8
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,26 @@
11
sudo: required
22
language: python
3-
python:
4-
- "3.4"
5-
- "3.6"
6-
7-
install:
8-
# Install build tools and ack-grep for checks
9-
- sudo apt install devscripts dh-make ack-grep -y
3+
python: "3.6"
104

115
script:
126
# Build the binary (.deb)
137
- debuild -i -us -uc -b
14-
# Install the binary, also fireing the debian scripts
8+
# Install the binary, running the debian scripts in the process
159
- sudo apt install ../*.deb -y
10+
11+
# Confirm the cv2 module has been installed correctly
12+
- sudo /usr/bin/env python3 -c "import cv2; print(cv2.__version__);"
13+
# Confirm the face_recognition module has been installed correctly
14+
- sudo /usr/bin/env python3 -c "import face_recognition; print(face_recognition.__version__);"
15+
1616
# Check if the username passthough works correctly with sudo
1717
- 'howdy | ack-grep --passthru --color "current active user: travis"'
1818
- 'sudo howdy | ack-grep --passthru --color "current active user: travis"'
19+
1920
# Remove howdy from the installation
2021
- sudo apt purge howdy -y
2122

23+
2224
notifications:
2325
email:
2426
on_success: never
@@ -27,3 +29,8 @@ notifications:
2729
addons:
2830
apt:
2931
update: true
32+
packages:
33+
- dh-make
34+
- ack-grep
35+
- devscripts
36+
- fakeroot

debian/changelog

+10
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
howdy (2.4.0) xenial; urgency=medium
2+
3+
* Cameras are now selected by path instead of by video device number (thanks @Rhiyo!)
4+
* Added fallbacks to $EDITOR for the config command (thanks @yassineim!)
5+
* Fixed missing cv2 module after installation (thanks @bendandersen and many others!)
6+
* Fixed file permissions crashing Howdy in some cases (thanks @GJDitchfield!)
7+
* Fixed howdy using python3 from local virtual environment (thanks @EdwardJB!)
8+
9+
-- boltgolt <[email protected]> Fri, 09 Nov 2018 20:59:45 +0100
10+
111
howdy (2.3.1) xenial; urgency=high
212

313
* Fixed issue where `frame_width` and `frame_height` would be completely ignored (thanks @janecz-n!)

debian/control

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@ Source: howdy
22
Section: misc
33
Priority: optional
44
Standards-Version: 3.9.7
5-
Build-Depends: python, dh-python, devscripts, dh-make, debhelper
5+
Build-Depends: python, dh-python, devscripts, dh-make, debhelper, fakeroot
66
Maintainer: boltgolt <[email protected]>
77
Vcs-Git: https://github.com/boltgolt/howdy
88

99
Package: howdy
1010
Homepage: https://github.com/boltgolt/howdy
1111
Architecture: all
12-
Depends: ${misc:Depends}, git, python3, python3-pip, python3-dev, python3-setuptools, build-essential, libpam-python, fswebcam, libopencv-dev, python-opencv, cmake
12+
Depends: ${misc:Depends}, git, python3, python3-pip, python3-dev, python3-setuptools, libpam-python, fswebcam, libopencv-dev, python-opencv, cmake, streamer
1313
Description: Howdy: Windows Hello style authentication for Linux.
1414
Use your built-in IR emitters and camera in combination with face recognition
1515
to prove who you are.

debian/howdy.lintian-overrides

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# W: Don't require ugly linebreaks in last 5 chars
2+
howdy: debian-changelog-line-too-long
3+
4+
# E: Allows the name Howdy to show up in Ubuntu updater
5+
howdy: description-starts-with-package-name
6+
# E: Allows python for installation scripts
7+
howdy: unknown-control-interpreter

debian/postinst

+19-35
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#!/usr/bin/env python3
1+
#!/usr/bin/python3
22
# Installation script to install howdy
33
# Executed after primary apt install
44

@@ -53,6 +53,11 @@ if not os.path.exists("/tmp/howdy_picked_device"):
5353
# Go through every setting in the old config and apply it to the new file
5454
for section in oldConf.sections():
5555
for (key, value) in oldConf.items(section):
56+
# If config is still using the old device_id parameter, convert it to a path
57+
if key == "device_id":
58+
key = "device_path"
59+
value = "/dev/video" + value
60+
5661
try:
5762
newConf.set(section, key, value)
5863
# Add a new section where needed
@@ -98,27 +103,34 @@ print("Temporary dlib files removed")
98103

99104
log("Installing python dependencies")
100105

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

104109
log("Installing face_recognition")
105110

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

114+
try:
115+
import cv2
116+
except Exception as e:
117+
log("Reinstalling opencv2")
118+
handleStatus(subprocess.call(["pip3", "install", "opencv-python"]))
119+
109120
log("Configuring howdy")
110121

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

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

118130
# Allow anyone to execute the python CLI
119131
handleStatus(subprocess.call(["chmod 755 /lib/security/howdy"], shell=True))
120-
handleStatus(subprocess.call(["chmod 744 /lib/security/howdy/cli.py"], shell=True))
121-
handleStatus(subprocess.call(["chmod 744 -R /lib/security/howdy/cli"], shell=True))
132+
handleStatus(subprocess.call(["chmod 755 /lib/security/howdy/cli.py"], shell=True))
133+
handleStatus(subprocess.call(["chmod 755 -R /lib/security/howdy/cli"], shell=True))
122134
print("Permissions set")
123135

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

201-
# From here onwards the installation is complete
202-
# We want to gather more information about the types or IR camera's
203-
# used though, and the following lines are data gathering
204-
# No data is ever uploaded without permission
205-
206-
if "HOWDY_NO_PROMPT" not in os.environ:
207-
# List all video devices
208-
diag_out = "Video devices [IR=" + picked + "]\n"
209-
diag_out += "```\n"
210-
diag_out += subprocess.check_output(['ls /dev/ | grep video'], shell=True).decode("utf-8")
211-
diag_out += "```\n"
212-
213-
# Get some info from the USB kernel listings
214-
diag_out += "Lsusb output\n"
215-
diag_out += "```\n"
216-
diag_out += subprocess.check_output(['lsusb -vvvv | grep -i "Camera\|iFunction"'], shell=True).decode("utf-8")
217-
diag_out += "```\n"
218-
219-
# Get camera information from video4linux
220-
diag_out += "Udevadm\n"
221-
diag_out += "```\n"
222-
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")
223-
diag_out += "```"
224-
225-
# Print it all as a clickable link to a new github issue
226-
print("https://github.com/boltgolt/howdy-reports/issues/new?title=Post-installation%20camera%20information&body=" + urllib.parse.quote_plus(diag_out) + "\n")
227-
228-
# Let the user know what to do with the link
213+
# Sign off
229214
print("Installation complete.")
230-
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))

debian/preinst

+42-44
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#!/usr/bin/env python3
1+
#!/usr/bin/python3
22
# Used to check cameras before commiting to install
33
# Executed before primary apt install of files
44

@@ -35,7 +35,7 @@ if "install" not in sys.argv:
3535
sys.exit(0)
3636

3737
# The default picked video device id
38-
picked = -1
38+
picked = "none"
3939

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

@@ -45,64 +45,62 @@ if "HOWDY_NO_PROMPT" in os.environ:
4545

4646
# Write the default device to disk and exit
4747
with open("/tmp/howdy_picked_device", "w") as out_file:
48-
out_file.write("0")
48+
out_file.write("none")
4949

5050
sys.exit(0)
5151

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

5555
# Loop though all devices
5656
for dev in devices:
57-
# Only use the video devices
58-
if (dev[:5] == "video"):
59-
time.sleep(.5)
60-
61-
# The full path to the device is the default name
62-
device_name = "/dev/" + dev
63-
# Get the udevadm details to try to get a better name
64-
udevadm = subprocess.check_output(["udevadm info -r --query=all -n " + device_name], shell=True).decode("utf-8")
65-
66-
# Loop though udevadm to search for a better name
67-
for line in udevadm.split("\n"):
68-
# Match it and encase it in quotes
69-
re_name = re.search('product.*=(.*)$', line, re.IGNORECASE)
70-
if re_name:
71-
device_name = '"' + re_name.group(1) + '"'
72-
73-
# Show what device we're using
74-
print("Trying " + device_name)
75-
76-
# Let fswebcam keep the camera open in the background
77-
sub = subprocess.Popen(["fswebcam -S 9999999999 -d /dev/" + dev + " /dev/null 2>/dev/null"], shell=True, preexec_fn=os.setsid)
78-
79-
try:
80-
# Ask the user if this is the right one
81-
print(col(2) + "One of your cameras should now be on." + col(0))
82-
ans = input("Did your IR emitters turn on? [y/N]: ")
83-
except KeyboardInterrupt:
84-
# Kill fswebcam if the user aborts
85-
os.killpg(os.getpgid(sub.pid), signal.SIGTERM)
86-
raise
87-
88-
# The user has answered, kill fswebcam
57+
time.sleep(.5)
58+
59+
# The full path to the device is the default name
60+
device_name = "/dev/v4l/by-path/" + dev
61+
# Get the udevadm details to try to get a better name
62+
udevadm = subprocess.check_output(["udevadm info -r --query=all -n " + device_name], shell=True).decode("utf-8")
63+
64+
# Loop though udevadm to search for a better name
65+
for line in udevadm.split("\n"):
66+
# Match it and encase it in quotes
67+
re_name = re.search('product.*=(.*)$', line, re.IGNORECASE)
68+
if re_name:
69+
device_name = '"' + re_name.group(1) + '"'
70+
71+
# Show what device we're using
72+
print("Trying " + device_name)
73+
74+
# Let fswebcam keep the camera open in the background
75+
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)
76+
77+
try:
78+
# Ask the user if this is the right one
79+
print(col(2) + "One of your cameras should now be on." + col(0))
80+
ans = input("Did your IR emitters turn on? [y/N]: ")
81+
except KeyboardInterrupt:
82+
# Kill fswebcam if the user aborts
8983
os.killpg(os.getpgid(sub.pid), signal.SIGTERM)
84+
raise
85+
86+
# The user has answered, kill fswebcam
87+
os.killpg(os.getpgid(sub.pid), signal.SIGTERM)
9088

91-
# Set this camera as picked if the answer was yes, go to the next one if no
92-
if ans.lower().strip() == "y" or ans.lower().strip() == "yes":
93-
picked = dev[5:]
94-
break
95-
else:
96-
print("Interpreting as a " + col(3) + "\"NO\"\n" + col(0))
89+
# Set this camera as picked if the answer was yes, go to the next one if no
90+
if ans.lower().strip() == "y" or ans.lower().strip() == "yes":
91+
picked = dev
92+
break
93+
else:
94+
print("Interpreting as a " + col(3) + "\"NO\"\n" + col(0))
9795

9896
# Abort if no camera was picked
99-
if picked == -1:
97+
if picked == "none":
10098
print(col(3) + "No suitable IR camera found, aborting install." + col(0))
10199
sys.exit(23)
102100

103101
# Write the result to disk so postinst can have a look at it
104102
with open("/tmp/howdy_picked_device", "w") as out_file:
105-
out_file.write(str(picked))
103+
out_file.write("/dev/v4l/by-path/" + picked)
106104

107105
# Add a line break
108106
print("")

debian/prerm

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#!/usr/bin/env python3
1+
#!/usr/bin/python3
22
# Executed on deinstallation
33
# Completely remove howdy from the system
44

debian/rules

-3
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,3 @@ include /usr/share/dpkg/default.mk
66

77
%:
88
dh $@
9-
10-
binary:
11-
dh binary

src/cli/add.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@
7979
}
8080

8181
# Open the camera
82-
video_capture = cv2.VideoCapture(int(config.get("video", "device_id")))
82+
video_capture = cv2.VideoCapture(config.get("video", "device_path"))
8383

8484
# Force MJPEG decoding if true
8585
if config.get("video", "force_mjpeg") == "true":

src/cli/config.py

+12-4
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,20 @@
1-
# Open the config file in gedit
1+
# Open the config file in an editor
22

33
# Import required modules
44
import os
5-
import time
65
import subprocess
76

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

11-
# Open gedit as a subprocess and fork it
12-
subprocess.call(["/etc/alternatives/editor", os.path.dirname(os.path.realpath(__file__)) + "/../config.ini"])
10+
# Default to the nano editor
11+
editor = "/bin/nano"
12+
13+
# Use the user preferred editor if available
14+
if os.path.isfile("/etc/alternatives/editor"):
15+
editor = "/etc/alternatives/editor"
16+
elif "EDITOR" in os.environ:
17+
editor = os.environ["EDITOR"]
18+
19+
# Open the editor as a subprocess and fork it
20+
subprocess.call([editor, os.path.dirname(os.path.realpath(__file__)) + "/../config.ini"])

src/cli/test.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
config.read(path + "/../config.ini")
1919

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

2323
# Force MJPEG decoding if true
2424
if config.get("video", "force_mjpeg") == "true":

src/compare.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ def stop(status):
5858
timings.append(time.time())
5959

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

6363
# Force MJPEG decoding if true
6464
if config.get("video", "force_mjpeg") == "true":

src/config.ini

+2-2
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ certainty = 3.5
2929
# The number of seconds to search before timing out
3030
timout = 4
3131

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

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

0 commit comments

Comments
 (0)