def negative_response(self, text): # type: (str) -> None ''' Registers a negative response having been received. Args: text (str): Some message accompanying the response. ''' self._last_message = tuple_builder(False, text)
def __init__(self, user, auth, parent): # type: (Dict[str, Any], Any, Any) -> None ''' Args: user (dict): Chat information about a user. auth (Auth): The authentication object to use. parent (Bot): The bot object that spawned this user. ''' self._user = user # type: Dict[str, Any] self.tasks = [] # type: List[Task] self.pending_task = None # type: Task # Authetnication object specific to this user self.auth = auth # Parent pointer to bot self.parent = parent # Last parsed message from this user self._last_message = tuple_builder() # Last authorization status self._last_auth = AUTH_STATES.NONE # Task auto-escalation time self._escalation_time = datetime.max.replace(tzinfo=pytz.utc) self._start = datetime.now(tz=pytz.utc) # Build state hierarchy states = [ 'need_task', 'action_performed_check', 'auth_permission_check', 'waiting_on_auth', 'task_finished', ] transitions = [ # Handle new tasks { 'source': 'need_task', 'dest': 'action_performed_check', 'condition': self._has_tasks, 'action': self._start_timer, }, # Finish task if user says action was performed and recently authorized { 'source': 'action_performed_check', 'dest': 'task_finished', 'condition': self._already_authed, }, # Finish task if user says action was performed and no 2FA capability exists { 'source': 'action_performed_check', 'dest': 'task_finished', 'condition': self._cannot_2fa, 'action': lambda: self.send_message('no_2fa') }, # Ask for 2FA if user says action was performed and can do 2FA { 'source': 'action_performed_check', 'dest': 'auth_permission_check', 'condition': self._performed_action, }, # Finish task if user says action wasn't performed { 'source': 'action_performed_check', 'dest': 'task_finished', 'condition': self._did_not_perform_action, 'action': self._act_on_not_performed, }, # Silently escalate and wait after some time goes by { 'source': 'action_performed_check', 'dest': 'task_finished', 'condition': self._slow_response_time, 'action': self._auto_escalate, }, # Perform 2FA if permission is granted { 'source': 'auth_permission_check', 'dest': 'waiting_on_auth', 'condition': self._allows_authorization, }, # Don't perform 2FA if permission is not granted { 'source': 'auth_permission_check', 'dest': 'task_finished', 'condition': self._denies_authorization, 'action': lambda: self.send_message('escalated'), }, # Silently escalate and wait after some time goes by again { 'source': 'auth_permission_check', 'dest': 'task_finished', 'condition': self._slow_response_time, 'action': self._auto_escalate, }, # Wait for authorization response then finish the task { 'source': 'waiting_on_auth', 'dest': 'task_finished', 'condition': self._auth_completed, }, # Go to the first needed task, possibly quitting, when task is completed { 'source': 'task_finished', 'dest': 'need_task', }, ] during = { 'waiting_on_auth': self._update_auth, } on_enter = { 'auth_permission_check': lambda: self.send_message('2fa'), 'waiting_on_auth': lambda: self.begin_auth(), } on_exit = { 'need_task': self._next_task, 'action_performed_check': self._update_task_response, 'auth_permission_check': self._reset_message, 'waiting_on_auth': self._update_task_auth, 'task_finished': self._complete_task, } self._fsm = StateMachine(states, transitions, 'need_task', during=during, on_enter=on_enter, on_exit=on_exit)
def _reset_message(self): # type: () -> None self._last_message = tuple_builder()
def test_full(self): tup = util.tuple_builder(True, 'Yes') assert tup.answer is True assert tup.text == 'Yes'
def test_empty(self): tup = util.tuple_builder() assert tup.answer is None assert tup.text == ''
def __init__(self, user, auth, dbclient, parent): ''' Args: user (dict): Chat information about a user. auth (AuthClient): The authentication client to use. parent (Bot): The bot object that spawned this user. ''' self._user = user self.tasks = [] self.pending_task = None # Authentication object specific to this user self._authclient = auth self._dbclient = dbclient # Parent pointer to bot self._bot = parent # Last parsed message from this user self._last_message = tuple_builder() # Last authorization details self._last_auth_state = AuthStates.NONE self._last_auth_time = datetime.min # Task auto-escalation time self._escalation_time = datetime.max.replace(tzinfo=pytz.utc) # If user is enrolled in MFA self._can_auth = self._authclient.can_auth(self) # Factor to be used for MFA if self._can_auth is not False: self._factor_id = self._can_auth self._can_auth = True # Build state hierarchy states = [ 'need_task', 'action_performed_check', 'auth_permission_check', 'waiting_on_auth', 'task_finished', ] transitions = [ # Handle new tasks { 'source': 'need_task', 'dest': 'action_performed_check', 'condition': self._has_tasks }, # Finish task if user says action was # performed and recently authorized { 'source': 'action_performed_check', 'dest': 'task_finished', 'condition': self._already_authed, }, # Finish task if user says action was performed # and no 2FA capability exists { 'source': 'action_performed_check', 'dest': 'task_finished', 'condition': self._cannot_2fa, 'action': lambda: self.send_message('no_2fa') }, # Ask for 2FA if user says action was performed and can do 2FA { 'source': 'action_performed_check', 'dest': 'auth_permission_check', 'condition': self._performed_action, }, # Finish task if user says action wasn't performed { 'source': 'action_performed_check', 'dest': 'task_finished', 'condition': self._did_not_perform_action, 'action': self._act_on_not_performed, }, # Silently escalate and wait after some time goes by { 'source': 'action_performed_check', 'dest': 'task_finished', 'condition': self._slow_response_time, 'action': self._auto_escalate, }, # Perform 2FA if permission is granted { 'source': 'auth_permission_check', 'dest': 'waiting_on_auth', 'condition': self._allows_authorization, }, # Don't perform 2FA if permission is not granted { 'source': 'auth_permission_check', 'dest': 'task_finished', 'condition': self._denies_authorization, 'action': self._act_on_denied_mfa }, # Silently escalate and wait after some time goes by again { 'source': 'auth_permission_check', 'dest': 'task_finished', 'condition': self._slow_response_time, 'action': self._auto_escalate, }, # Wait for authorization response then finish the task { 'source': 'waiting_on_auth', 'dest': 'task_finished', 'condition': self._auth_completed, }, # Go to the first needed task, possibly quitting, # when task is completed { 'source': 'task_finished', 'dest': 'need_task', }, ] during = { 'waiting_on_auth': self._update_auth, } on_enter = { 'auth_permission_check': lambda: self.send_message('2fa'), 'waiting_on_auth': lambda: self.begin_auth(), } on_exit = { 'need_task': self._next_task, 'action_performed_check': self._update_task_response, 'auth_permission_check': self._reset_message, 'waiting_on_auth': self._update_task_auth, 'task_finished': self._complete_task, } self._fsm = StateMachine(states, transitions, 'need_task', during=during, on_enter=on_enter, on_exit=on_exit)