Пример #1
0
    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)
Пример #2
0
    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)
Пример #3
0
 def _reset_message(self):
     # type: () -> None
     self._last_message = tuple_builder()
Пример #4
0
 def test_full(self):
     tup = util.tuple_builder(True, 'Yes')
     assert tup.answer is True
     assert tup.text == 'Yes'
Пример #5
0
 def test_empty(self):
     tup = util.tuple_builder()
     assert tup.answer is None
     assert tup.text == ''
Пример #6
0
    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)