Beispiel #1
0
 async def do_greeting(self) -> Response:
     preauth_creds = self.config.preauth_credentials
     if preauth_creds:
         self._session = await self.login(preauth_creds, self.config)
     elif socket_info.get().from_localhost:
         self.auth = self.config.insecure_auth
     resp_cls = ResponsePreAuth if preauth_creds else ResponseOk
     return resp_cls(b'*', self.config.greeting, self.capability)
Beispiel #2
0
 async def do_greeting(self) -> CommandResponse:
     preauth_creds = self.config.preauth_credentials
     if preauth_creds:
         self._session = await self._login(preauth_creds)
     elif socket_info.get().from_localhost:
         self.auth = self.config.insecure_auth
     resp_cls = ResponsePreAuth if preauth_creds else ResponseOk
     return resp_cls(b'*', self.config.greeting, self.capability)
Beispiel #3
0
 def _print(cls, log_format: str, output: bytes) -> None:
     if _log.isEnabledFor(logging.DEBUG):
         fd = socket_info.get().socket.fileno()
         lines = cls._lines.split(output)
         if not lines[-1]:
             lines = lines[:-1]
         for line in lines:
             line_str = str(line, 'utf-8', 'replace')
             _log.debug(log_format, fd, line_str)
Beispiel #4
0
 def _print(cls, log_format: str, output: bytes) -> None:
     if _log.isEnabledFor(logging.DEBUG):
         fd = socket_info.get().socket.fileno()
         lines = cls._lines.split(output)
         if not lines[-1]:
             lines = lines[:-1]
         for line in lines:
             line_str = str(line, 'utf-8', 'replace')
             _log.debug(log_format, fd, line_str)
Beispiel #5
0
    async def run(self, login: LoginProtocol):
        """Start the socket communication with the server greeting, and then
        enter the command/response cycle.

        Args:
            login: The login/authentication function.

        """
        self._print('%d +++| %s', bytes(socket_info.get()))
        await self._do_greeting(login)
        while True:
            resp: Response
            try:
                cmd = await self._read_command()
            except (ConnectionError, EOFError):
                break
            except NotParseable as exc:
                resp = BadCommandResponse(exc)
            else:
                try:
                    if isinstance(cmd, NoOpCommand):
                        resp = NoOpResponse(cmd.tag)
                    elif isinstance(cmd, LogoutCommand):
                        resp = Response(Condition.BYE)
                    elif isinstance(cmd, CapabilityCommand):
                        resp = CapabilitiesResponse(self.capabilities)
                    elif self._session is None:
                        if isinstance(cmd, AuthenticateCommand):
                            resp = await self._do_authenticate(login, cmd)
                        elif isinstance(cmd, StartTLSCommand):
                            resp = await self._do_starttls()
                        else:
                            resp = Response(Condition.NO, text='Bad command.')
                    else:
                        if isinstance(cmd, UnauthenticateCommand):
                            resp = await self._do_unauthenticate()
                        else:
                            assert self._session.filter_set is not None
                            state = FilterState(self._session.filter_set,
                                                self.config)
                            resp = await state.run(cmd)
                except Exception:
                    _log.exception('Unhandled exception')
                    resp = Response(Condition.NO, text='Server error.')
            await self._write_response(resp)
            if resp.is_bye:
                break
        self._print('%d ---| %s', b'<disconnected>')
Beispiel #6
0
    async def run(self) -> None:
        """Start the socket communication with the server greeting, and then
        enter the command/response cycle.

        """
        self._print('%d +++| %s', bytes(socket_info.get()))
        greeting = await self._do_greeting()
        await self._write_response(greeting)
        while True:
            resp: Response
            try:
                cmd = await self._read_command()
            except (ConnectionError, EOFError):
                break
            except NotParseable as exc:
                resp = BadCommandResponse(exc)
            else:
                try:
                    if isinstance(cmd, NoOpCommand):
                        resp = NoOpResponse(cmd.tag)
                    elif isinstance(cmd, LogoutCommand):
                        resp = Response(Condition.BYE)
                    elif isinstance(cmd, CapabilityCommand):
                        resp = CapabilitiesResponse(self.capabilities)
                    elif self._state is None:
                        if isinstance(cmd, AuthenticateCommand):
                            resp = await self._do_authenticate(cmd)
                        elif isinstance(cmd, StartTLSCommand):
                            resp = await self._do_starttls()
                        else:
                            resp = Response(Condition.NO, text='Bad command.')
                    else:
                        if isinstance(cmd, UnauthenticateCommand):
                            resp = await self._do_unauthenticate()
                        else:
                            resp = await self._state.run(cmd)
                except Exception:
                    _log.exception('Unhandled exception')
                    resp = Response(Condition.NO, text='Server error.')
            await self._write_response(resp)
            if resp.is_bye:
                break
        self._print('%d ---| %s', b'<disconnected>')
Beispiel #7
0
    async def run(self, state: ConnectionState) -> None:
        """Start the socket communication with the IMAP greeting, and then
        enter the command/response cycle.

        Args:
            state: Defines the interaction with the backend plugin.

        """
        self._print('%d +++| %s', bytes(socket_info.get()))
        bad_commands = 0
        try:
            greeting = await self._exec(state.do_greeting())
        except ResponseError as exc:
            resp = exc.get_response(b'*')
            resp.condition = ResponseBye.condition
            await self.write_response(resp)
            return
        else:
            await self.write_response(greeting)
        while True:
            try:
                cmd = await self.read_command()
            except (ConnectionError, EOFError):
                break
            except CancelledError:
                await self.send_error_disconnect()
                break
            except Exception:
                await self.send_error_disconnect()
                raise
            else:
                prev_cmd = current_command.set(cmd)
                try:
                    if isinstance(cmd, AuthenticateCommand):
                        creds = await self.authenticate(state, cmd.mech_name)
                        response, _ = await self._exec(
                            state.do_authenticate(cmd, creds))
                    elif isinstance(cmd, IdleCommand):
                        response = await self.idle(state, cmd)
                    else:
                        response = await self._exec(state.do_command(cmd))
                except ResponseError as exc:
                    resp = exc.get_response(cmd.tag)
                    await self.write_response(resp)
                    if resp.is_terminal:
                        break
                except AuthenticationError as exc:
                    msg = bytes(str(exc), 'utf-8', 'surrogateescape')
                    resp = ResponseBad(cmd.tag, msg)
                    await self.write_response(resp)
                except TimeoutError:
                    resp = ResponseNo(cmd.tag, b'Operation timed out.',
                                      ResponseCode.of(b'TIMEOUT'))
                    await self.write_response(resp)
                except CancelledError:
                    await self.send_error_disconnect()
                    break
                except Exception:
                    await self.send_error_disconnect()
                    raise
                else:
                    await self.write_response(response)
                    if response.is_bad:
                        bad_commands += 1
                        if self.bad_command_limit \
                                and bad_commands >= self.bad_command_limit:
                            msg = b'Too many errors, disconnecting.'
                            response.add_untagged(ResponseBye(msg))
                    else:
                        bad_commands = 0
                    if response.is_terminal:
                        break
                    if isinstance(cmd, StartTLSCommand) and state.ssl_context \
                            and isinstance(response, ResponseOk):
                        await self.start_tls(state.ssl_context)
                finally:
                    await state.do_cleanup()
                    current_command.reset(prev_cmd)
        self._print('%d ---| %s', b'<disconnected>')
Beispiel #8
0
    async def run(self, state: ConnectionState) -> None:
        """Start the socket communication with the IMAP greeting, and then
        enter the command/response cycle.

        Args:
            state: Defines the interaction with the backend plugin.

        """
        self._print('%d +++| %s', bytes(socket_info.get()))
        bad_commands = 0
        try:
            greeting = await self._exec(state.do_greeting())
        except ResponseError as exc:
            resp = exc.get_response(b'*')
            resp.condition = ResponseBye.condition
            await self.write_response(resp)
            return
        else:
            await self.write_response(greeting)
        while True:
            try:
                cmd = await self.read_command(state)
            except (ConnectionError, EOFError):
                break
            except CancelledError:
                await self.send_error_disconnect()
                break
            except Exception:
                await self.send_error_disconnect()
                raise
            else:
                prev_cmd = current_command.set(cmd)
                try:
                    if isinstance(cmd, AuthenticateCommand):
                        creds = await self.authenticate(state, cmd.mech_name)
                        response = await self._exec(
                            state.do_authenticate(cmd, creds))
                    elif isinstance(cmd, IdleCommand):
                        response = await self.idle(state, cmd)
                    else:
                        response = await self._exec(state.do_command(cmd))
                except ResponseError as exc:
                    resp = exc.get_response(cmd.tag)
                    await self.write_response(resp)
                    if resp.is_terminal:
                        break
                except AuthenticationError as exc:
                    msg = bytes(str(exc), 'utf-8', 'surrogateescape')
                    resp = ResponseBad(cmd.tag, msg)
                    await self.write_response(resp)
                except TimeoutError:
                    resp = ResponseNo(cmd.tag, b'Operation timed out.',
                                      ResponseCode.of(b'TIMEOUT'))
                    await self.write_response(resp)
                except CancelledError:
                    await self.send_error_disconnect()
                    break
                except Exception:
                    await self.send_error_disconnect()
                    raise
                else:
                    await self.write_response(response)
                    if response.is_bad:
                        bad_commands += 1
                        if self.bad_command_limit \
                                and bad_commands >= self.bad_command_limit:
                            msg = b'Too many errors, disconnecting.'
                            response.add_untagged(ResponseBye(msg))
                    else:
                        bad_commands = 0
                    if response.is_terminal:
                        break
                    if isinstance(cmd, StartTLSCommand) and state.ssl_context \
                            and isinstance(response, ResponseOk):
                        await self.start_tls(state.ssl_context)
                finally:
                    await state.do_cleanup()
                    current_command.reset(prev_cmd)
        self._print('%d ---| %s', b'<disconnected>')