diff --git a/doorlockd b/doorlockd index bd8188a..26f8a3f 100755 --- a/doorlockd +++ b/doorlockd @@ -28,9 +28,10 @@ from subprocess import Popen from threading import Thread from time import sleep -from pydoorlock.Authenticator import Authenticator, AuthMethod, AuthenticationResult +from pydoorlock.Authenticator import Authenticator, AuthMethod from pydoorlock.WebApp import webapp_run, emit_doorstate from pydoorlock.Door import DoorState +from pydoorlock.Doorlock import DoorlockResponse SYSCONFDIR = '.' PREFIX = '.' @@ -106,6 +107,7 @@ def start_hook(script): def sound_helper(old_state, new_state, button): if old_state == new_state: playsound(wave_zonk) + return if button: if new_state == DoorState.Open: @@ -123,40 +125,6 @@ def sound_helper(old_state, new_state, button): playsound(wave_lock) -class LogicResponse(Enum): - Success = 0 - Perm = 1 - AlreadyActive = 2 - # don't break old apps, value 3 is reserved now - RESERVED = 3 - Inval = 4 - - EmergencyUnlock = 10, - ButtonLock = 11, - ButtonUnlock = 12, - ButtonPresent = 13, - - def __str__(self): - if self == LogicResponse.Success: - return 'Yo, passt.' - elif self == LogicResponse.Perm: - return choose_insult() - elif self == LogicResponse.AlreadyActive: - return 'Zustand bereits aktiv' - elif self == LogicResponse.Inval: - return 'Das was du willst geht nicht.' - elif self == LogicResponse.EmergencyUnlock: - return '!!! Emergency Unlock !!!' - elif self == LogicResponse.ButtonLock: - return 'Closed by button' - elif self == LogicResponse.ButtonUnlock: - return 'Opened by button' - elif self == LogicResponse.ButtonPresent: - return 'Present by button' - - return 'Error' - - class DoorHandler: state = DoorState.Closed do_close = False @@ -229,37 +197,41 @@ class DoorHandler: def open(self): if self.state == DoorState.Open: - return LogicResponse.AlreadyActive + return DoorlockResponse.AlreadyActive self.state = DoorState.Open start_hook('post_unlock') - return LogicResponse.Success + return DoorlockResponse.Success def present(self): if self.state == DoorState.Present: - return LogicResponse.AlreadyActive + return DoorlockResponse.AlreadyActive self.state = DoorState.Present start_hook('post_present') - return LogicResponse.Success + return DoorlockResponse.Success def close(self): if self.state == DoorState.Closed: - return LogicResponse.AlreadyActive + return DoorlockResponse.AlreadyActive self.do_close = True self.state = DoorState.Closed start_hook('post_lock') - return LogicResponse.Success + return DoorlockResponse.Success def request(self, state): + old_state = self.state if state == DoorState.Closed: err = self.close() elif state == DoorState.Present: err = self.present() elif state == DoorState.Open: err = self.open() + + sound_helper(old_state, self.state, False) emit_doorstate() + return err class Logic: @@ -267,18 +239,12 @@ class Logic: self.auth = Authenticator(cfg) self.door_handler = DoorHandler(cfg) - def _request(self, state, credentials): - err = self.auth.try_auth(credentials) - if err != AuthenticationResult.Success: - return err - return self.door_handler.request(state) - def request(self, state, credentials): - old_state = self.door_handler.state - err = self._request(state, credentials) - if err == LogicResponse.Success or err == LogicResponse.AlreadyActive: - sound_helper(old_state, self.door_handler.state, False) - return err + err = self.auth.try_auth(credentials) + if err != DoorlockResponse.Success: + return err + + return self.door_handler.request(state) @property def state(self): diff --git a/pydoorlock/Authenticator.py b/pydoorlock/Authenticator.py index 3ac7476..9c4807c 100644 --- a/pydoorlock/Authenticator.py +++ b/pydoorlock/Authenticator.py @@ -20,35 +20,11 @@ import ldap import logging from enum import Enum -from random import sample + +from .Doorlock import DoorlockResponse log = logging.getLogger() -# copied from sudo -eperm_insults = { - 'Wrong! You cheating scum!', - 'And you call yourself a Rocket Scientist!', - 'No soap, honkie-lips.', - 'Where did you learn to type?', - 'Are you on drugs?', - 'My pet ferret can type better than you!', - 'You type like i drive.', - 'Do you think like you type?', - 'Your mind just hasn\'t been the same since the electro-shock, has it?', - 'Maybe if you used more than just two fingers...', - 'BOB says: You seem to have forgotten your passwd, enter another!', - 'stty: unknown mode: doofus', - 'I can\'t hear you -- I\'m using the scrambler.', - 'The more you drive -- the dumber you get.', - 'Listen, broccoli brains, I don\'t have time to listen to this trash.', - 'I\'ve seen penguins that can type better than that.', - 'Have you considered trying to match wits with a rutabaga?', - 'You speak an infinite deal of nothing', -} - -def choose_insult(): - return(sample(eperm_insults, 1)[0]) - class AuthMethod(Enum): LDAP_USER_PW = 1 @@ -62,19 +38,6 @@ class AuthMethod(Enum): return 'Error' -class AuthenticationResult(Enum): - Success = 0 - Perm = 1 - InternalError = 2 - - def __str__(self): - if self == AuthenticationResult.Success: - return 'Yo, passt!' - elif self == AuthenticationResult.Perm: - return choose_insult() - else: - return 'Internal authentication error' - class Authenticator: def __init__(self, cfg): self._simulate = cfg.boolean('SIMULATE_AUTH') @@ -111,14 +74,14 @@ class Authenticator: def _try_auth_local(self, user, password): if user not in self._local_db: - return AuthenticationResult.Perm + return DoorlockResponse.Perm stored_pw = self._local_db[user][0] stored_salt = self._local_db[user][1] if stored_pw == hashlib.sha256(stored_salt.encode() + password.encode()).hexdigest(): - return AuthenticationResult.Success + return DoorlockResponse.Success - return AuthenticationResult.Perm + return DoorlockResponse.Perm def _try_auth_ldap(self, user, password): log.info(' Trying to LDAP auth (user, password) as user %s', user) @@ -129,24 +92,24 @@ class Authenticator: l.unbind_s() except ldap.INVALID_CREDENTIALS: log.info(' Invalid credentials') - return AuthenticationResult.Perm + return DoorlockResponse.Perm except ldap.LDAPError as e: log.info(' LDAP Error: %s' % e) - return AuthenticationResult.InternalError - return AuthenticationResult.Success + return DoorlockResponse.InternalError + return DoorlockResponse.Success def try_auth(self, credentials): if self._simulate: log.info('SIMULATION MODE! ACCEPTING ANYTHING!') - return AuthenticationResult.Success + return DoorlockResponse.Success method = credentials[0] if method not in self._backends: - return AuthenticationResult.InternalError + return DoorlockResponse.InternalError if method == AuthMethod.LDAP_USER_PW: return self._try_auth_ldap(credentials[1], credentials[2]) elif method == AuthMethod.LOCAL_USER_DB: return self._try_auth_local(credentials[1], credentials[2]) - return AuthenticationResult.InternalError + return DoorlockResponse.InternalError diff --git a/pydoorlock/Doorlock.py b/pydoorlock/Doorlock.py new file mode 100644 index 0000000..3426717 --- /dev/null +++ b/pydoorlock/Doorlock.py @@ -0,0 +1,62 @@ +from enum import Enum +from random import sample + +# copied from sudo +eperm_insults = { + 'Wrong! You cheating scum!', + 'And you call yourself a Rocket Scientist!', + 'No soap, honkie-lips.', + 'Where did you learn to type?', + 'Are you on drugs?', + 'My pet ferret can type better than you!', + 'You type like i drive.', + 'Do you think like you type?', + 'Your mind just hasn\'t been the same since the electro-shock, has it?', + 'Maybe if you used more than just two fingers...', + 'BOB says: You seem to have forgotten your passwd, enter another!', + 'stty: unknown mode: doofus', + 'I can\'t hear you -- I\'m using the scrambler.', + 'The more you drive -- the dumber you get.', + 'Listen, broccoli brains, I don\'t have time to listen to this trash.', + 'I\'ve seen penguins that can type better than that.', + 'Have you considered trying to match wits with a rutabaga?', + 'You speak an infinite deal of nothing', +} + + +def choose_insult(): + return(sample(eperm_insults, 1)[0]) + + +class DoorlockResponse(Enum): + Success = 0 + Perm = 1 + AlreadyActive = 2 + # don't break old apps, value 3 is reserved now + RESERVED = 3 + Inval = 4 + + EmergencyUnlock = 10, + ButtonLock = 11, + ButtonUnlock = 12, + ButtonPresent = 13, + + def __str__(self): + if self == DoorlockResponse.Success: + return 'Yo, passt.' + elif self == DoorlockResponse.Perm: + return choose_insult() + elif self == DoorlockResponse.AlreadyActive: + return 'Zustand bereits aktiv' + elif self == DoorlockResponse.Inval: + return 'Das was du willst geht nicht.' + elif self == DoorlockResponse.EmergencyUnlock: + return '!!! Emergency Unlock !!!' + elif self == DoorlockResponse.ButtonLock: + return 'Closed by button' + elif self == DoorlockResponse.ButtonUnlock: + return 'Opened by button' + elif self == DoorlockResponse.ButtonPresent: + return 'Present by button' + + return 'Error'