Beispiel #1
0
 def test_has_mail_data(self) -> None:
     state = State()
     state.greeted = True
     state.mail_data = ""
     code, message = handle_mail(state, "FROM:<*****@*****.**>")
     assert code == SMTPStatus.BAD_SEQUENCE
     assert message == "Bad command sequence"
Beispiel #2
0
 def test_empty_path(self) -> None:
     state = State()
     state.greeted = True
     code, message = handle_mail(state, "FROM:<>")
     assert code == SMTPStatus.OK
     assert message == "Sender OK"
     assert state.reverse_path == ""
Beispiel #3
0
 def test_no_reverse_path(self) -> None:
     state = State()
     state.greeted = True
     state.reverse_path = None
     code, message = handle_rcpt(state, "TO:<*****@*****.**>")
     assert code == SMTPStatus.BAD_SEQUENCE
     assert message == "Bad command sequence"
Beispiel #4
0
 def test_forward_paths_added(self) -> None:
     state = State()
     state.greeted = True
     state.reverse_path = "*****@*****.**"
     handle_rcpt(state, "TO:<*****@*****.**>")
     handle_rcpt(state, "TO:<*****@*****.**>")
     assert state.forward_path == ["*****@*****.**", "*****@*****.**"]
Beispiel #5
0
 def test_with_mailbox(self) -> None:
     state = State()
     state.greeted = True
     code, message = handle_mail(state, "FROM:<*****@*****.**>")
     assert code == SMTPStatus.OK
     assert message == "Sender OK"
     assert state.reverse_path == "*****@*****.**"
Beispiel #6
0
 def test_has_forward_path(self) -> None:
     state = State()
     state.greeted = True
     state.forward_path = ["*****@*****.**"]
     code, message = handle_mail(state, "FROM:<*****@*****.**>")
     assert code == SMTPStatus.BAD_SEQUENCE
     assert message == "Bad command sequence"
Beispiel #7
0
 def test_response(self) -> None:
     state = State()
     state.greeted = True
     state.reverse_path = "*****@*****.**"
     code, message = handle_rcpt(state, "TO:<*****@*****.**>")
     assert code == SMTPStatus.OK
     assert message == "Receiver OK"
Beispiel #8
0
 def test_mail_data(self) -> None:
     state = State()
     state.greeted = True
     state.reverse_path = "*****@*****.**"
     state.mail_data = ""
     code, message = handle_rcpt(state, "TO:<*****@*****.**>")
     assert code == SMTPStatus.BAD_SEQUENCE
     assert message == "Bad command sequence"
Beispiel #9
0
 def test_with_arguments(self) -> None:
     state = State()
     state.greeted = True
     state.reverse_path = "*****@*****.**"
     code, message = handle_rcpt(state, "TO:<*****@*****.**> foo=bar baz")
     assert code == SMTPStatus.OK
     assert message == "Receiver OK"
     assert state.forward_path == ["*****@*****.**"]
Beispiel #10
0
 def test_domain(self, getfqdn: Mock) -> None:
     state = State()
     state.greeted = False
     getfqdn.return_value = "smtp.example.org"
     code, message = handle_ehlo(state, "example.com")
     assert code == SMTPStatus.OK
     assert message == "smtp.example.org Hello example.com"
     assert state.greeted
Beispiel #11
0
 def test_address_literal(self, getfqdn: Mock) -> None:
     state = State()
     state.greeted = False
     getfqdn.return_value = "smtp.example.org"
     code, message = handle_ehlo(state, "[192.168.99.22]")
     assert code == SMTPStatus.OK
     assert message == "smtp.example.org Hello [192.168.99.22]"
     assert state.greeted
Beispiel #12
0
 def test_postmaster(self) -> None:
     state = State()
     state.greeted = True
     state.reverse_path = "*****@*****.**"
     code, message = handle_rcpt(state, "TO:<postMaster> foo")
     assert code == SMTPStatus.OK
     assert message == "Receiver OK"
     assert state.forward_path == ["postMaster"]
Beispiel #13
0
 def test_with_arguments_and_quoted_local_part(self) -> None:
     state = State()
     state.greeted = True
     code, message = handle_mail(
         state, 'FROM:<"foo bar"@example.com> foo=bar'
     )
     assert code == SMTPStatus.OK
     assert message == "Sender OK"
     assert state.reverse_path == '"foo bar"@example.com'
Beispiel #14
0
 def __init__(
     self,
     reader: _StreamReaderProto,
     writer: _StreamWriterProto,
     print_mail: Callable[[State], None],
 ) -> None:
     self.reader = reader
     self.writer = writer
     self.print_mail = print_mail
     self.state = State()
Beispiel #15
0
def handle_rcpt(state: State, arguments: str) -> Reply:
    if arguments[:3].upper() != "TO:":
        return handle_wrong_arguments()
    try:
        path, rest = parse_receiver(arguments[3:])
    except ValueError as exc:
        return handle_wrong_arguments(str(exc))
    if not is_valid_smtp_arguments(rest):
        return handle_wrong_arguments()
    if not state.rcpt_allowed:
        return handle_bad_command_sequence()
    state.add_forward_path(path)
    return SMTPStatus.OK, "Receiver OK"
Beispiel #16
0
 async def _handle_mail_text(self) -> None:
     try:
         await self._read_mail_text()
     except UnexpectedEOFError:
         pass
     except ValueError:
         self._write_reply(SMTPStatus.SYNTAX_ERROR, "Line too long.")
     else:
         self._write_reply(SMTPStatus.OK, "OK")
         self.state.date = datetime.datetime.utcnow()
         state = self.state
         self.print_mail(state)
         self.state = State()
         self.state.greeted = state.greeted
Beispiel #17
0
def handle_helo(state: State, arguments: str) -> Reply:
    if not arguments.strip():
        return handle_missing_arguments()
    if not is_valid_domain(arguments):
        return handle_wrong_arguments()
    state.greeted = True
    return SMTPStatus.OK, f"{getfqdn()} Hello {arguments}"
Beispiel #18
0
def handle_mail(state: State, arguments: str) -> Reply:
    if arguments[:5].upper() != "FROM:":
        return handle_wrong_arguments()
    try:
        path, rest = parse_reverse_path(arguments[5:])
    except ValueError as exc:
        return handle_wrong_arguments(str(exc))
    if not is_valid_smtp_arguments(rest):
        return handle_wrong_arguments()
    if not state.greeted:
        return handle_no_greeting()
    if not state.mail_allowed:
        return handle_bad_command_sequence()
    state.clear()
    state.reverse_path = path
    return SMTPStatus.OK, "Sender OK"
Beispiel #19
0
 def test_print(self) -> None:
     out = StringIO()
     state = State()
     state.date = datetime.datetime(2017, 6, 4, 14, 34, 15)
     state.reverse_path = "*****@*****.**"
     state.forward_path = ["*****@*****.**", "*****@*****.**"]
     state.mail_data = "Subject: Foo\r\n\r\nText\r\n"
     write_mbox_mail(out, state)
     assert out.getvalue() == (
         "From [email protected] Sun Jun  4 14:34:15 2017\n"
         "X-FakeSMTPd-Receiver: [email protected]\n"
         "X-FakeSMTPd-Receiver: [email protected]\n"
         "Subject: Foo\n"
         "\n"
         "Text\n"
         "\n"
     )
Beispiel #20
0
 def test_not_greeted(self) -> None:
     state = State()
     state.greeted = False
     code, message = handle_mail(state, "FROM:<*****@*****.**>")
     assert code == SMTPStatus.BAD_SEQUENCE
     assert message == "No EHLO sent"
Beispiel #21
0
 def test_local_part_too_long(self) -> None:
     code, message = handle_rcpt(
         State(), f"TO:<{'a' * (SMTP_LOCAL_PART_LIMIT + 1)}@example.com>"
     )
     assert code == SMTPStatus.SYNTAX_ERROR_IN_PARAMETERS
     assert message == "Path too long"
Beispiel #22
0
 def test_invalid_domain(self) -> None:
     code, message = handle_helo(State(), "*")
     assert code == SMTPStatus.SYNTAX_ERROR_IN_PARAMETERS
     assert message == "Syntax error in arguments"
Beispiel #23
0
 def test_empty_path(self) -> None:
     code, message = handle_rcpt(State(), "TO:<>")
     assert code == SMTPStatus.SYNTAX_ERROR_IN_PARAMETERS
     assert message == "Syntax error in arguments"
Beispiel #24
0
 def test_response(self, getfqdn: Mock) -> None:
     getfqdn.return_value = "smtp.example.org"
     code, message = handle_helo(State(), "example.com")
     assert code == SMTPStatus.OK
     assert message == "smtp.example.org Hello example.com"
Beispiel #25
0
 def test_no_argument(self) -> None:
     code, message = handle_helo(State(), "")
     assert code == SMTPStatus.SYNTAX_ERROR_IN_PARAMETERS
     assert message == "Missing arguments"
Beispiel #26
0
 def test_set_greeted(self) -> None:
     state = State()
     state.greeted = False
     handle_helo(state, "example.com")
     assert state.greeted
Beispiel #27
0
 def test_path_too_long(self) -> None:
     code, message = handle_rcpt(
         State(), f"TO:<{'a' * 60}@{'a' * (SMTP_PATH_LIMIT - 61)}>"
     )
     assert code == SMTPStatus.SYNTAX_ERROR_IN_PARAMETERS
     assert message == "Path too long"
Beispiel #28
0
 def test_domain_too_long(self) -> None:
     code, message = handle_rcpt(
         State(), f"TO:<foo@{'a' * (SMTP_DOMAIN_LIMIT + 1)}>"
     )
     assert code == SMTPStatus.SYNTAX_ERROR_IN_PARAMETERS
     assert message == "Path too long"
Beispiel #29
0
 def test_path_with_trailing_chars(self) -> None:
     code, message = handle_rcpt(State(), "TO:<*****@*****.**>foo=bar")
     assert code == SMTPStatus.SYNTAX_ERROR_IN_PARAMETERS
     assert message == "Syntax error in arguments"
Beispiel #30
0
 def test_invalid_argument(self) -> None:
     code, message = handle_rcpt(State(), "TO:<*****@*****.**> -foo")
     assert code == SMTPStatus.SYNTAX_ERROR_IN_PARAMETERS
     assert message == "Syntax error in arguments"