added sample and prettier conf
parent
2937b3ae21
commit
00a1618807
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"trailingComma": "es5",
|
||||||
|
"tabWidth": 4,
|
||||||
|
"semi": false,
|
||||||
|
"singleQuote": true
|
||||||
|
}
|
@ -0,0 +1,110 @@
|
|||||||
|
# Howdy's config file: https://github.com/boltgolt/howdy/blob/beta/howdy/src/config.ini
|
||||||
|
# Press CTRL + X to save in the nano editor
|
||||||
|
|
||||||
|
[core]
|
||||||
|
# Print that face detection is being attempted
|
||||||
|
detection_notice = false
|
||||||
|
|
||||||
|
# Print that face detection has timed out
|
||||||
|
timeout_notice = true
|
||||||
|
|
||||||
|
# Do not print anything when a face verification succeeds
|
||||||
|
no_confirmation = false
|
||||||
|
|
||||||
|
# When a user without a known face model tries to use this script, don't
|
||||||
|
# show an error but fail silently
|
||||||
|
suppress_unknown = false
|
||||||
|
|
||||||
|
# Disable Howdy in remote shells
|
||||||
|
abort_if_ssh = true
|
||||||
|
|
||||||
|
# Disable Howdy if lid is closed
|
||||||
|
abort_if_lid_closed = true
|
||||||
|
|
||||||
|
# Disable howdy in the PAM
|
||||||
|
# The howdy command will still function
|
||||||
|
disabled = false
|
||||||
|
|
||||||
|
# Use CNN instead of HOG
|
||||||
|
# CNN model is much more accurate than the HOG based model, but takes much more
|
||||||
|
# computational power to run, and is meant to be executed on a GPU to attain reasonable speed.
|
||||||
|
use_cnn = false
|
||||||
|
|
||||||
|
[video]
|
||||||
|
# The certainty of the detected face belonging to the user of the account
|
||||||
|
# On a scale from 1 to 10, values above 5 are not recommended
|
||||||
|
# Lower is better
|
||||||
|
certainty = 3.5
|
||||||
|
|
||||||
|
# The number of seconds to search before timing out
|
||||||
|
timeout = 4
|
||||||
|
|
||||||
|
# The path of the device to capture frames from
|
||||||
|
# Should be set automatically by an installer if your distro has one
|
||||||
|
device_path = none
|
||||||
|
|
||||||
|
# Print a warning if the the video device is not found
|
||||||
|
warn_no_device = true
|
||||||
|
|
||||||
|
# Scale down the video feed to this maximum height
|
||||||
|
# Speeds up face recognition but can make it less precise
|
||||||
|
max_height = 320
|
||||||
|
|
||||||
|
# Set the camera input profile to this width and height
|
||||||
|
# The largest profile will be used if set to -1
|
||||||
|
# Automatically ignored if not a valid profile
|
||||||
|
frame_width = -1
|
||||||
|
frame_height = -1
|
||||||
|
|
||||||
|
# Because of flashing IR emitters, some frames can be completely unlit
|
||||||
|
# Skip the frame if the lowest 1/8 of the histogram is above this percentage
|
||||||
|
# of the total
|
||||||
|
# The lower this setting is, the more dark frames are ignored
|
||||||
|
dark_threshold = 50
|
||||||
|
|
||||||
|
# The recorder to use. Can be either opencv (default), ffmpeg or pyv4l2.
|
||||||
|
# Switching from the default opencv to ffmpeg can help with grayscale issues.
|
||||||
|
recording_plugin = opencv
|
||||||
|
|
||||||
|
# Video format used by ffmpeg. Options include vfwcap or v4l2.
|
||||||
|
# FFMPEG only.
|
||||||
|
device_format = v4l2
|
||||||
|
|
||||||
|
# Force the use of Motion JPEG when decoding frames, fixes issues with YUYV
|
||||||
|
# raw frame decoding.
|
||||||
|
# OPENCV only.
|
||||||
|
force_mjpeg = false
|
||||||
|
|
||||||
|
# Specify exposure value explicitly. This disables autoexposure.
|
||||||
|
# Use qv4l2 to determine an appropriate value.
|
||||||
|
# OPENCV only.
|
||||||
|
exposure = -1
|
||||||
|
|
||||||
|
[snapshots]
|
||||||
|
# Capture snapshots of failed login attempts and save them to disk with metadata
|
||||||
|
# Snapshots are saved to the "snapshots" folder
|
||||||
|
save_failed = false
|
||||||
|
|
||||||
|
# Do the same as the option above but for successful attempts
|
||||||
|
save_successful = false
|
||||||
|
|
||||||
|
[rubberstamps]
|
||||||
|
# Enable specific extra checks after the user has been recognised
|
||||||
|
enabled = false
|
||||||
|
|
||||||
|
# What type of stamps to run and with what options. The type, timeout and
|
||||||
|
# failure mode are required. One line per stamp. Rule syntax:
|
||||||
|
# stamptype timeout (failsafe | faildeadly) [extra_argument=value]
|
||||||
|
stamp_rules =
|
||||||
|
nod 5s failsafe min_distance=12
|
||||||
|
|
||||||
|
[debug]
|
||||||
|
# Show a short but detailed diagnostic report in console
|
||||||
|
# Enabling this can cause some UI apps to fail, only enable it to debug
|
||||||
|
end_report = false
|
||||||
|
|
||||||
|
# More verbose logging from the rubberstamps system
|
||||||
|
verbose_stamps = false
|
||||||
|
|
||||||
|
# Pass output of the GTK auth window to the terminal
|
||||||
|
gtk_stdout = false
|
@ -0,0 +1,179 @@
|
|||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
|
||||||
|
from i18n import _
|
||||||
|
|
||||||
|
from importlib.machinery import SourceFileLoader
|
||||||
|
|
||||||
|
|
||||||
|
class RubberStamp:
|
||||||
|
"""Howdy rubber stamp"""
|
||||||
|
|
||||||
|
UI_TEXT = "ui_text"
|
||||||
|
UI_SUBTEXT = "ui_subtext"
|
||||||
|
|
||||||
|
def set_ui_text(self, text, type=None):
|
||||||
|
"""Convert an ui string to input howdy-gtk understands"""
|
||||||
|
typedec = "M"
|
||||||
|
|
||||||
|
if type == self.UI_SUBTEXT:
|
||||||
|
typedec = "S"
|
||||||
|
|
||||||
|
return self.send_ui_raw(typedec + "=" + text)
|
||||||
|
|
||||||
|
def send_ui_raw(self, command):
|
||||||
|
"""Write raw command to howdy-gtk stdin"""
|
||||||
|
if self.config.getboolean("debug", "verbose_stamps", fallback=False):
|
||||||
|
print("Sending command to howdy-gtk: " + command)
|
||||||
|
|
||||||
|
# Add a newline because the ui reads per line
|
||||||
|
command += " \n"
|
||||||
|
|
||||||
|
# If we're connected to the ui
|
||||||
|
if self.gtk_proc:
|
||||||
|
# Send the command as bytes
|
||||||
|
self.gtk_proc.stdin.write(bytearray(command.encode("utf-8")))
|
||||||
|
self.gtk_proc.stdin.flush()
|
||||||
|
|
||||||
|
# Write a padding line to force the command through any buffers
|
||||||
|
self.gtk_proc.stdin.write(bytearray("P=_PADDING \n".encode("utf-8")))
|
||||||
|
self.gtk_proc.stdin.flush()
|
||||||
|
|
||||||
|
|
||||||
|
def execute(config, gtk_proc, opencv):
|
||||||
|
verbose = config.getboolean("debug", "verbose_stamps", fallback=False)
|
||||||
|
dir_path = os.path.dirname(os.path.realpath(__file__))
|
||||||
|
installed_stamps = []
|
||||||
|
|
||||||
|
# Go through each file in the rubberstamp folder
|
||||||
|
for filename in os.listdir(dir_path):
|
||||||
|
# Remove non-readable file or directories
|
||||||
|
if not os.path.isfile(dir_path + "/" + filename):
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Remove meta files
|
||||||
|
if filename in ["__init__.py", ".gitignore"]:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Add the found file to the list of enabled rubberstamps
|
||||||
|
installed_stamps.append(filename.split(".")[0])
|
||||||
|
|
||||||
|
if verbose: print("Installed rubberstamps: " + ", ".join(installed_stamps))
|
||||||
|
|
||||||
|
# Get the rules defined in the config
|
||||||
|
raw_rules = config.get("rubberstamps", "stamp_rules")
|
||||||
|
rules = raw_rules.split("\n")
|
||||||
|
|
||||||
|
# Go through the rules one by one
|
||||||
|
for rule in rules:
|
||||||
|
rule = rule.strip()
|
||||||
|
|
||||||
|
if len(rule) <= 1:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Parse the rule with regex
|
||||||
|
regex_result = re.search("^(\w+)\s+([\w\.]+)\s+([a-z]+)(.*)?$", rule, re.IGNORECASE)
|
||||||
|
|
||||||
|
# Error out if the regex did not match (invalid line)
|
||||||
|
if not regex_result:
|
||||||
|
print(_("Error parsing rubberstamp rule: {}").format(rule))
|
||||||
|
continue
|
||||||
|
|
||||||
|
type = regex_result.group(1)
|
||||||
|
|
||||||
|
# Error out if the stamp name in the rule is not a file
|
||||||
|
if type not in installed_stamps:
|
||||||
|
print(_("Stamp not installed: {}").format(type))
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Load the module from file
|
||||||
|
module = SourceFileLoader(type, dir_path + "/" + type + ".py").load_module()
|
||||||
|
|
||||||
|
# Try to get the class with the same name
|
||||||
|
try:
|
||||||
|
constructor = getattr(module, type)
|
||||||
|
except AttributeError:
|
||||||
|
print(_("Stamp error: Class {} not found").format(type))
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Init the class and set common values
|
||||||
|
instance = constructor()
|
||||||
|
instance.verbose = verbose
|
||||||
|
instance.config = config
|
||||||
|
instance.gtk_proc = gtk_proc
|
||||||
|
instance.opencv = opencv
|
||||||
|
|
||||||
|
# Set some opensv shorthands
|
||||||
|
instance.video_capture = opencv["video_capture"]
|
||||||
|
instance.face_detector = opencv["face_detector"]
|
||||||
|
instance.pose_predictor = opencv["pose_predictor"]
|
||||||
|
instance.clahe = opencv["clahe"]
|
||||||
|
|
||||||
|
# Parse and set the 2 required options for all rubberstamps
|
||||||
|
instance.options = {
|
||||||
|
"timeout": float(re.sub("[a-zA-Z]", "", regex_result.group(2))),
|
||||||
|
"failsafe": regex_result.group(3) != "faildeadly"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Try to get the class do declare its other config variables
|
||||||
|
try:
|
||||||
|
instance.declare_config()
|
||||||
|
except Exception:
|
||||||
|
print(_("Internal error in rubberstamp configuration declaration:"))
|
||||||
|
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Split the optional arguments at the end of the rule by spaces
|
||||||
|
raw_options = regex_result.group(4).split()
|
||||||
|
|
||||||
|
# For each of those aoptional arguments
|
||||||
|
for option in raw_options:
|
||||||
|
# Get the key to the left, and the value to the right of the equal sign
|
||||||
|
key, value = option.split("=")
|
||||||
|
|
||||||
|
# Error out if a key has been set that was not declared by the module before
|
||||||
|
if key not in instance.options:
|
||||||
|
print("Unknow config option for rubberstamp " + type + ": " + key)
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Convert the argument string to an int or float if the declared option has that type
|
||||||
|
if isinstance(instance.options[key], int):
|
||||||
|
value = int(value)
|
||||||
|
elif isinstance(instance.options[key], float):
|
||||||
|
value = float(value)
|
||||||
|
|
||||||
|
instance.options[key] = value
|
||||||
|
|
||||||
|
if verbose:
|
||||||
|
print("Stamp \"" + type + "\" options parsed:")
|
||||||
|
print(instance.options)
|
||||||
|
print("Executing stamp")
|
||||||
|
|
||||||
|
# Make the stamp fail by default
|
||||||
|
result = False
|
||||||
|
|
||||||
|
# Run the stamp code
|
||||||
|
try:
|
||||||
|
result = instance.run()
|
||||||
|
except Exception:
|
||||||
|
print(_("Internal error in rubberstamp:"))
|
||||||
|
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
continue
|
||||||
|
|
||||||
|
if verbose: print("Stamp \"" + type + "\" returned: " + str(result))
|
||||||
|
|
||||||
|
# Abort authentication if the stamp returned false
|
||||||
|
if result is False:
|
||||||
|
if verbose: print("Authentication aborted by rubber stamp")
|
||||||
|
sys.exit(14)
|
||||||
|
|
||||||
|
# This is outside the for loop, so we've run all the rules
|
||||||
|
if verbose: print("All rubberstamps processed, authentication successful")
|
||||||
|
|
||||||
|
# Exit with no errors
|
||||||
|
sys.exit(0)
|
Loading…
Reference in New Issue