diff --git a/app/Gulag.py b/app/Gulag.py index 5866d3f..fe2a86e 100644 --- a/app/Gulag.py +++ b/app/Gulag.py @@ -263,14 +263,16 @@ class Gulag: except(GulagException,GulagDBException) as e: logging.warning(whoami(self) + e.message) raise GulagException(whoami(self) + e.message) from e - if 'rfc822_message' not in args: + if 'rfc822_message' not in args and 'headers' not in args: return { 'quarmails': qms_db, - 'rfc822_messages': {} + 'rfc822_messages': {}, + 'headers': {} } # recognize all IMAP mailboxes to read from # and store rfc822-messages under it mailboxes = {} + headers = {} for qm in qms_db: if qm['mailbox_id'] not in mailboxes: mailboxes[qm['mailbox_id']] = {} @@ -290,18 +292,29 @@ class Gulag: for qm_db in qms_db: if qm_db['imap_uid'] not in mailboxes[mailbox_id]: try: - mailboxes[mailbox_id][qm_db['imap_uid']] = imap_mb.get_message( - qm_db['imap_uid'] - ).decode("utf-8") + if 'rfc822_message' in args: + mailboxes[mailbox_id][qm_db['imap_uid']] = imap_mb.get_message( + qm_db['imap_uid'] + ).decode("utf-8") + elif 'headers' in args: + mailboxes[mailbox_id][qm_db['imap_uid']] = imap_mb.get_headers( + qm_db['imap_uid'] + ).decode("utf-8") except IMAPmailboxException as e: logging.warning(whoami(self) + e.message) raise GulagException(whoami(self) + e.message) from e imap_mb.close() # end for mailboxes - return { - "quarmails": qms_db, - "rfc822_messages": mailboxes - } + if 'rfc822_message' in args: + return { + "quarmails": qms_db, + "rfc822_messages": mailboxes + } + elif 'headers' in args: + return { + "quarmails": qms_db, + "headers": mailboxes + } def get_quarmail(self,args): qm_db = None @@ -312,7 +325,7 @@ class Gulag: except GulagDBException as e: logging.warning(whoami(self) + e.message) raise GulagException(whoami(self) + e.message) from e - if 'rfc822_message' not in args: + if 'rfc822_message' not in args and 'headers' not in args: return qm_db # pull full RFC822 message from IMAP mailbox mailbox = None @@ -326,29 +339,20 @@ class Gulag: imap_mb = None try: imap_mb = IMAPmailbox(mailbox) - qm_db['rfc822_message'] = imap_mb.get_message( - qm_db['imap_uid'] - ).decode("utf-8") + if 'rfc822_message' in args: + qm_db['rfc822_message'] = imap_mb.get_message( + qm_db['imap_uid'] + ).decode("utf-8") + elif 'headers' in args: + qm_db['headers'] = imap_mb.get_headers( + qmat_db['imap_uid'] + ) imap_mb.close() return qm_db except IMAPmailboxException as e: logging.warning(whoami(self) + e.message) raise GulagException(whoami(self) + e.message) from e - def release_quarmail(self,args): - try: - quarmail = self.get_quarmail({ - "quarmail_id": args['quarmail_id'], - "rfc822_message": True - }) - # - # TODO: re-send quarmail to original env_rcpt - # TODO: self.delete_quarmail() if arg['purge'] - except GulagNotFoundException as e: - raise GulagNotFoundException(whoami(self) + e.message) from e - except GulagException as e: - raise GulagException(whoami(self) + e.message) from e - def delete_quarmail(self, args): qm_db = None try: @@ -394,6 +398,44 @@ class Gulag: imap_mb.close() return + def release_quarmail(self,args): + try: + quarmail = self.get_quarmail({ + "quarmail_id": args['quarmail_id'], + "rfc822_message": True + }) + # TODO: re-send quarmail to original env_rcpt + # TODO: self.delete_quarmail() if arg['purge'] + except GulagNotFoundException as e: + raise GulagNotFoundException(whoami(self) + e.message) from e + except GulagException as e: + raise GulagException(whoami(self) + e.message) from e + + def bounce_quarmail(self,args): + try: + quarmail = self.get_quarmail({ + "quarmail_id": args['quarmail_id'], + "rfc822_message": True + }) + # TODO: bounce quarmail headers-only to quarmail['env_from'] + # TODO: self.delete_quarmail() if arg['purge'] + except GulagNotFoundException as e: + raise GulagNotFoundException(whoami(self) + e.message) from e + except GulagException as e: + raise GulagException(whoami(self) + e.message) from e + + def forward_quarmail(self,args): + try: + quarmail = self.get_quarmail({ + "quarmail_id": args['quarmail_id'], + "rfc822_message": True + }) + # TODO: send quarmail to args['env_rcpt'] + except GulagNotFoundException as e: + raise GulagNotFoundException(whoami(self) + e.message) from e + except GulagException as e: + raise GulagException(whoami(self) + e.message) from e + def get_quarmail_attachments(self,args): try: return self.db.get_quarmail_attachments(args['quarmail_id']) diff --git a/app/GulagMailbox.py b/app/GulagMailbox.py index c04c051..3018814 100644 --- a/app/GulagMailbox.py +++ b/app/GulagMailbox.py @@ -1,6 +1,7 @@ import imaplib import email import email.header +from email.parser import HeaderParser import time import re from GulagUtils import whoami @@ -103,6 +104,14 @@ class IMAPmailbox: ) return True + def get_headers(self,imap_uid): + rv, data = self.mailbox.uid('FETCH', str(imap_uid), '(BODY[HEADER])') + if rv != 'OK': + raise IMAPmailboxException(whoami(self) + + "ERROR getting headers: %s", str(imap_uid) + ) + return data[0][1] + def get_attachment(self,imap_uid,filename): msg = email.message_from_bytes(self.get_message(imap_uid)) for part in msg.walk(): diff --git a/app/Resources.py b/app/Resources.py index 93251a9..ecd695a 100644 --- a/app/Resources.py +++ b/app/Resources.py @@ -71,6 +71,8 @@ class ResQuarMail(GulagResource): abort(404, message=e.message) except GulagException as e: abort(500, message=e.message) + def delete(self,quarmail_id): + pass def delete(self,quarmail_id): args = {"quarmail_id": quarmail_id} try: @@ -93,6 +95,18 @@ class ResQuarMailRelease(GulagResource): except GulagException as e: abort(500, message=e.message) +class ResQuarMailBounce(GulagResource): + def get(self,quarmail_id): + args = {"quarmail_id": quarmail_id} + if(request.args.get('purge')): + args['purge'] = True + try: + return self.gulag.bounce_quarmail(args) + except GulagNotFoundException as e: + abort(404, message=e.message) + except GulagException as e: + abort(500, message=e.message) + class ResQuarMailAttachments(GulagResource): def get(self,quarmail_id): args = {"quarmail_id": quarmail_id} diff --git a/docker/gulag-server/debian/Dockerfile b/docker/gulag-server/debian/Dockerfile index d5af9c1..762673f 100644 --- a/docker/gulag-server/debian/Dockerfile +++ b/docker/gulag-server/debian/Dockerfile @@ -17,3 +17,5 @@ RUN env; set -ex ; \ && /bin/mkdir /config /socket /app COPY app/*.py /app/ + +CMD ["/usr/bin/uwsgi","--emperor","/config/vassals"] diff --git a/gulag-openapi-2.0.yaml b/gulag-openapi-2.0.yaml index 804602d..27f03c6 100644 --- a/gulag-openapi-2.0.yaml +++ b/gulag-openapi-2.0.yaml @@ -50,6 +50,10 @@ paths: type: string required: false description: get full RFC822 email message for each QuarMail object + - in: query + name: headers + description: get all email headers for each QuarMail object + required: false - in: query name: filters type: string @@ -81,9 +85,13 @@ paths: type: integer - in: query name: rfc822_message - description: if set to a (random) value, full RFC822 email message will be returned as well + description: if set to a (random) value, full RFC822 email message will be returned type: string required: false + - in: query + name: headers + description: if set to a (random) value, all email headers will be returned + required: false responses: 200: description: quarantined email object @@ -311,6 +319,9 @@ definitions: rfc822_message: type: string description: full RFC822 email message + headers: + type: string + description: email headers Attachment: type: object required: