MattieG4
MattieG4

Reputation: 169

How do I write my own challenge_auth method for aiosmtpd?

I'm trying to connect a wildlife camera to my SMTP server but it keeps dropping the connection after being asked for it's username. I've verified that this server works with other wildlife cameras and email clients but always seems to fail with this specific model of wildlife camera. I've tried with no authentication, basic authentication and TLS but none of them work (The camera works with gmail SMTP though).

enter image description here

This is the simple code I'm using.

It seems like I need to modify the challenge_auth method. My question is how do I do that, do I just add another method to the custom handler with handle_DATA in?

import email
from email.header import decode_header
from email import message_from_bytes
from email.policy import default
from aiosmtpd.controller import Controller
from aiosmtpd.smtp import LoginPassword, AuthResult
import os
import sys
import time
import signal 
import logging

##setting timezone
os.environ['TZ'] = "Europe/London"
time.tzset()

def onExit( sig, func=None):
    print("*************Stopping program*****************")
    controller.stop()
    exit()
 
signal.signal(signal.SIGTERM, onExit)

# removes the spaces and replaces with _ so they're valid folder names
def clean(text):
    return "".join(c if c.isalnum() else "_" for c in text)


log = logging.getLogger('mail.log')

auth_db = {
    b"[email protected]": b"password1",
    b"user2": b"password2",
    b"TestCamera1": b"password1",
}

def authenticator_func(server, session, envelope, mechanism, auth_data):
    #this deliberately lets everything through
    assert isinstance(auth_data, LoginPassword)
    username = auth_data.login
    password = auth_data.password
    return AuthResult(success=True)


def configure_logging():
    file_handler = logging.FileHandler("aiosmtpd.log", "a")
    stderr_handler = logging.StreamHandler(sys.stderr)
    logger = logging.getLogger("mail.log")
    fmt = "[%(asctime)s %(levelname)s] %(message)s"
    datefmt = None
    formatter = logging.Formatter(fmt, datefmt, "%")
    stderr_handler.setFormatter(formatter)
    logger.addHandler(stderr_handler)
    file_handler.setFormatter(formatter)
    logger.addHandler(file_handler)
    logger.setLevel(logging.DEBUG)

class CustomHandler:
    def handle_exception(self, error):
        print("exception occured")
        print(error)
        return '542 Internal Server Error'

    async def handle_DATA(self, server, session, envelope):
        peer = session.peer
        data = envelope.content         # type: bytes
        msg = message_from_bytes(envelope.content, policy=default)
        # decode the email subject
        print("Msg:{}".format(msg))
        print("Data:{}".format(data))
        print("All of the relevant data has been extracted from the email")
        return '250 OK'


if __name__ == '__main__':
    configure_logging()
    handler = CustomHandler()
    #update hostname to your IP
    controller = Controller(handler, hostname='0.0.0.0', port=587, authenticator=authenticator_func, auth_required=True,auth_require_tls=False)    
    # Run the event loop in a separate thread.
    controller.start()
    while True:
        time.sleep(10)

Here's the logs from a reolink go camera that can connect successfully. (I've updated the format 'Username' is being send .e.g from 'User Name:' to 'Username' by editing the library but that hasn't seemed to help with the suntek camera. I thought it might be more pick with the format due to cheaper, less robust firmware.

enter image description here

Upvotes: 0

Views: 184

Answers (0)

Related Questions