ticketfrei3/backend/src/kibicara/platforms/email/mda.py

109 lines
3.5 KiB
Python

# Copyright (C) 2020 by Maike <maike@systemli.org>
# Copyright (C) 2020 by Cathy Hu <cathy.hu@fau.de>
# Copyright (C) 2020, 2023 by Thomas Lindner <tom@dl6tom.de>
# Copyright (C) 2020 by Martin Rey <martin.rey@mailbox.org>
#
# SPDX-License-Identifier: 0BSD
from argparse import ArgumentParser
from asyncio import run as asyncio_run
from email.parser import BytesParser
from email.policy import default
from email.utils import parseaddr
from logging import getLogger
from re import sub
from sys import stdin
from fastapi import status
from ormantic import NoMatch
from pytoml import load
from requests import post
from kibicara.config import config
from kibicara.platforms.email.model import Email, EmailSubscribers
logger = getLogger(__name__)
class Main:
def __init__(self):
parser = ArgumentParser()
parser.add_argument(
'-f',
'--config',
dest='configfile',
default='/etc/kibicara.conf',
help='path to config file',
)
# the MDA passes the recipient address as command line argument
parser.add_argument('recipient')
args = parser.parse_args()
try:
with open(args.configfile) as configfile:
config.update(load(configfile))
except FileNotFoundError:
# run with default config
pass
# extract email from the recipient
email_name = args.recipient.lower()
asyncio_run(self.__run(email_name))
async def __run(self, email_name):
try:
email = await Email.objects.get(name=email_name)
except NoMatch:
logger.error('No recipient with this name')
exit(1)
# read mail from STDIN and parse to EmailMessage object
message = BytesParser(policy=default).parsebytes(stdin.buffer.read())
sender = ''
if message.get('sender'):
sender = message.get('sender')
elif message.get('from'):
sender = message.get('from')
else:
logger.error('No Sender of From header')
exit(1)
sender = parseaddr(sender)[1]
if not sender:
logger.error('Could not parse sender')
exit(1)
maybe_subscriber = await EmailSubscribers.objects.filter(email=sender).all()
if len(maybe_subscriber) != 1 or maybe_subscriber[0].hood.id != email.hood.id:
logger.error('Not a subscriber')
exit(1)
# extract relevant data from mail
text = sub(
r'<[^>]*>',
'',
message.get_body(preferencelist=('plain', 'html')).get_content(),
)
response = post(
'{0}/api/hoods/{1}/email/messages/'.format(
config['root_url'], email.hood.pk
),
json={'text': text, 'secret': email.secret},
)
if response.status_code == status.HTTP_201_CREATED:
exit(0)
elif response.status_code == status.HTTP_451_UNAVAILABLE_FOR_LEGAL_REASONS:
logger.error('Message was\'t accepted: {0}'.format(text))
elif response.status_code == status.HTTP_422_UNPROCESSABLE_ENTITY:
logger.error('Malformed request: {0}'.format(response.json()))
elif response.status_code == status.HTTP_401_UNAUTHORIZED:
logger.error('Wrong API secret. kibicara_mda seems to be misconfigured')
else:
logger.error(
'REST-API failed with response status {0}'.format(response.status_code)
)
exit(1)