You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

173 lines
4.8 KiB
Python

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 self.gtk_proc:
# Send the command as bytes
self.gtk_proc.stdin.write(bytearray(command.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)