Merge pull request #36 from gnh1201/smtp

SMTP fix #35 / SMTP 서버 수정
This commit is contained in:
Namhyeon Go 2024-07-13 21:03:55 +09:00 committed by GitHub
commit feb7cff398
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 58 additions and 43 deletions

14
base.py
View File

@ -8,9 +8,8 @@
# Euiseo Cha (Wonkwang University) <zeroday0619_dev@outlook.com>
# https://github.com/gnh1201/caterpillar
# Created at: 2024-05-20
# Updated at: 2024-07-11
# Updated at: 2024-07-12
#
import logging
import hashlib
import json
@ -48,10 +47,18 @@ def jsonrpc2_create_id(data):
def jsonrpc2_encode(method, params=None):
data = {"jsonrpc": "2.0", "method": method, "params": params}
id = jsonrpc2_create_id(data)
data["id"] = id
id = data.get('id')
return (id, json.dumps(data))
def jsonrpc2_decode(text):
data = json.loads(text)
type = 'error' if 'error' in data else 'result' if 'result' in data else None
id = data.get('id')
rpcdata = data.get(type) if type else None
return type, id, rpcdata
def jsonrpc2_result_encode(result, id=""):
data = {"jsonrpc": "2.0", "result": result, "id": id}
return json.dumps(data)
@ -61,7 +68,6 @@ def jsonrpc2_error_encode(error, id=""):
data = {"jsonrpc": "2.0", "error": error, "id": id}
return json.dumps(data)
def find_openssl_binpath():
system = platform.system()

View File

@ -1,2 +1,3 @@
python-decouple
requests
aiosmtpd

86
smtp.py
View File

@ -1,23 +1,23 @@
#!/usr/bin/python3
#
# smtp.py
# SMTP over HTTP gateway
# SMTP mail sender over HTTP/S
#
# Caterpillar Proxy - The simple web debugging proxy (formerly, php-httpproxy)
# Namyheon Go (Catswords Research) <gnh1201@gmail.com>
# https://github.com/gnh1201/caterpillar
# Created at: 2024-03-01
# Updated at: 2024-05-20
# Updated at: 2024-07-12
#
import asyncore
from smtpd import SMTPServer
import asyncio
from aiosmtpd.controller import Controller
from aiosmtpd.handlers import Message
from email.message import EmailMessage
import re
import sys
import json
import requests
from platform import python_version
from decouple import config
from requests.auth import HTTPBasicAuth
from base import (
@ -45,28 +45,22 @@ auth = None
if _username:
auth = HTTPBasicAuth(_username, _password)
class CaterpillarSMTPHandler:
def __init__(self):
self.smtpd_hostname = "CaterpillarSMTPServer"
self.smtp_version = "0.1.6"
class CaterpillarSMTPServer(SMTPServer):
def __init__(self, localaddr, remoteaddr):
self.__class__.smtpd_hostname = "CaterpillarSMTPServer"
self.__class__.smtp_version = "0.1.6"
super().__init__(localaddr, remoteaddr)
async def handle_DATA(self, server, session, envelope):
mailfrom = envelope.mail_from
rcpttos = envelope.rcpt_tos
data = envelope.content
def process_message(self, peer, mailfrom, rcpttos, data, **kwargs):
message_lines = data.decode("utf-8").split("\n")
subject = ""
to = ""
for line in message_lines:
pos = line.find(":")
if pos > -1:
k = line[0:pos]
v = line[pos + 1 :]
if k == "Subject":
subject = v
elif k == "To":
to = v
message = EmailMessage()
message.set_content(data)
subject = message.get('Subject', '')
to = message.get('To', '')
# build a data
proxy_data = {
"headers": {
"User-Agent": "php-httpproxy/0.1.6 (Client; Python "
@ -82,27 +76,41 @@ class CaterpillarSMTPServer(SMTPServer):
}
_, raw_data = jsonrpc2_encode("relay_sendmail", proxy_data["data"])
# send HTTP POST request
try:
response = requests.post(
server_url, headers=proxy_data["headers"], data=raw_data, auth=auth
response = await asyncio.to_thread(
requests.post,
server_url,
headers=proxy_data['headers'],
data=raw_data,
auth=auth
)
if response.status_code == 200:
type, id, method, rpcdata = jsonrpc2_decode(response.text)
if rpcdata["success"]:
type, id, rpcdata = jsonrpc2_decode(response.text)
if rpcdata['success']:
logger.info("[*] Email sent successfully.")
else:
raise Exception(
"(%s) %s" % (str(rpcdata["code"]), rpcdata["message"])
)
raise Exception(f"({rpcdata['code']}) {rpcdata['message']}")
else:
raise Exception("Status %s" % (str(response.status_code)))
raise Exception(f"Status {response.status_code}")
except Exception as e:
logger.error("[*] Failed to send email", exc_info=e)
return '500 Could not process your message. ' + str(e)
return '250 OK'
# Start SMTP server
smtp_server = CaterpillarSMTPServer((smtp_host, smtp_port), None)
# https://aiosmtpd-pepoluan.readthedocs.io/en/latest/migrating.html
def main():
handler = CaterpillarSMTPHandler()
controller = Controller(handler, hostname=smtp_host, port=smtp_port)
# Run the event loop in a separate thread.
controller.start()
# Wait for the user to press Return.
input('SMTP server running. Press Return to stop server and exit.')
controller.stop()
logger.warning("[*] User has requested an interrupt")
logger.warning("[*] Application Exiting.....")
sys.exit()
# Start asynchronous event loop
asyncore.loop()
if __name__ == "__main__":
main()