From f4b4d65a0d169b422bd9d1c698ee3cb400bc3e72 Mon Sep 17 00:00:00 2001 From: Dominik Chilla Date: Thu, 17 Jan 2019 23:55:50 +0100 Subject: [PATCH] * release_quarmail implemented * attachment mime-type by magic * swagger definition update --- app/Entities.py | 4 ++++ app/Gulag.py | 28 ++++++++++++++++++++++++---- app/GulagDB.py | 8 +++++--- app/GulagMailrelay.py | 4 ++-- app/Resources.py | 9 ++++++++- config/gulag-config.json | 3 +++ db/gulag.sql | 1 + gulag-openapi-2.0.yaml | 35 ++++++++++++++++++++++++++++++++--- 8 files changed, 79 insertions(+), 13 deletions(-) diff --git a/app/Entities.py b/app/Entities.py index ba92d5d..99cff8c 100644 --- a/app/Entities.py +++ b/app/Entities.py @@ -197,6 +197,7 @@ class Attachment: content_type = None content_encoding = None magic = None + mime_type = None comment = None mailbox_id = None imap_uid = None @@ -221,6 +222,9 @@ class Attachment: if 'magic' not in at_ref: raise AttachmentException("'magic' is mandatory!") self.magic = at_ref['magic'] + if 'mime_type' not in at_ref: + raise AttachmentException("'mime_type' is mandatory!") + self.mime_type = at_ref['mime_type'] if 'comment' in at_ref: self.comment = at_ref['comment'] if 'mailbox_id' not in at_ref: diff --git a/app/Gulag.py b/app/Gulag.py index 5f2b38c..97a720c 100644 --- a/app/Gulag.py +++ b/app/Gulag.py @@ -197,6 +197,7 @@ class Gulag: 'content_type': part.get_content_type(), 'content_encoding': part['Content-Transfer-Encoding'], 'magic': magic.from_buffer(attach_decoded), + 'mime_type': magic.from_buffer(attach_decoded, mime=True), 'sha256': hashlib.sha256(attach_decoded).hexdigest(), 'ssdeep': ssdeep.hash(attach_decoded), 'size': len(attach_decoded) @@ -417,12 +418,27 @@ class Gulag: "quarmail_id": args['quarmail_id'], "rfc822_message": True }) - # TODO: re-send quarmail to original env_rcpt - # TODO: self.delete_quarmail() if arg['purge'] + # the mailbox reference holds the appropriate mailrelay_id + mailbox_ref = self.db.get_mailbox(quarmail['mailbox_id']) + mailrelay_ref = self.db.get_mailrelay(mailbox_ref['mailrelay_id']) + mailrelay = GulagMailrelay(mailrelay_ref) + mailrelay.release_quarmail(quarmail) + logging.info(whoami(self) + + "QuarMail("+quarmail['id']+") released. env_rcpt: "+quarmail['env_rcpt'] + ) + if 'purge' in args: + self.delete_quarmail({"quarmail_id": args['quarmail_id']}) + logging.info(whoami(self) + + "QuarMail(" + quarmail['id'] + ") deleted" + ) except GulagNotFoundException as e: raise GulagNotFoundException(whoami(self) + e.message) from e except GulagException as e: raise GulagException(whoami(self) + e.message) from e + except GulagDBNotFoundException as e: + raise GulagNotFoundException(whoami(self) + e.message) from e + except GulagMailrelayException as e: + raise GulagException(whoami(self) + e.message) from e def bounce_quarmail(self,args): try: @@ -433,13 +449,17 @@ class Gulag: }) # the mailbox reference holds the appropriate mailrelay_id mailbox_ref = self.db.get_mailbox(quarmail['mailbox_id']) - logging.info(whoami(self)+"mailrelay_id: "+str(mailbox_ref['mailrelay_id'])) mailrelay_ref = self.db.get_mailrelay(mailbox_ref['mailrelay_id']) - logging.info(whoami(self) + str(mailrelay_ref)) mailrelay = GulagMailrelay(mailrelay_ref) mailrelay.bounce_quarmail(quarmail) + logging.info(whoami(self) + + "QuarMail("+quarmail['id']+") bounced back to "+quarmail['env_from'] + ) if 'purge' in args: self.delete_quarmail({"quarmail_id": args['quarmail_id']}) + logging.info(whoami(self) + + "QuarMail(" + quarmail['id'] + ") deleted" + ) except GulagNotFoundException as e: raise GulagNotFoundException(whoami(self) + e.message) from e except GulagException as e: diff --git a/app/GulagDB.py b/app/GulagDB.py index 0a44575..a57b486 100644 --- a/app/GulagDB.py +++ b/app/GulagDB.py @@ -402,11 +402,13 @@ class GulagDB: try: cursor = self.conn.cursor() cursor.execute("insert into Attachments " + - "(filename,content_type,content_encoding,magic,sha256,ssdeep,size) " + - "values (%s,%s,%s,%s,%s,%s,%s)", + "(filename,content_type,content_encoding,magic,sha256,"+ + "ssdeep,size,mime_type) " + + "values (%s,%s,%s,%s,%s,%s,%s,%s)", (attach['filename'],attach['content_type'], attach['content_encoding'],attach['magic'], - attach['sha256'],attach['ssdeep'],attach['size'] + attach['sha256'],attach['ssdeep'],attach['size'], + attach['mime_type'] ) ) return cursor.lastrowid diff --git a/app/GulagMailrelay.py b/app/GulagMailrelay.py index 6e10a7b..35f3352 100644 --- a/app/GulagMailrelay.py +++ b/app/GulagMailrelay.py @@ -42,12 +42,12 @@ class GulagMailrelay: self.mailrelay.sendmail( quarmail['env_from'], quarmail['env_rcpt'], - quarmail['rfc822_message'] + str(quarmail['rfc822_message']) ) self.mailrelay.quit() except (SMTPRecipientsRefused,SMTPHeloError,SMTPSenderRefused, SMTPDataError,SMTPNotSupportedError) as e: - raise GulagMailrelayException(whoami(self) + e.message) from e + raise GulagMailrelayException(whoami(self) + str(e)) from e except TimeoutError as e: raise GulagMailrelayException(whoami(self) + e.message) from e except ConnectionRefusedError as e: diff --git a/app/Resources.py b/app/Resources.py index 825195d..5e0efa6 100644 --- a/app/Resources.py +++ b/app/Resources.py @@ -31,6 +31,13 @@ class GulagResource(Resource): if api_key not in self.gulag.config['api_keys']: abort(401, message="NOT AUTHORIZED!") + def check_dos(self): + body_len = len(request.get_data(as_text=True)) + if(body_len > self.gulag.config['dos_protection']['max_body_bytes']): + raise GulagBadInputException(whoami(self) + + "Request body max size exceeded" + ) + class ResRoot(GulagResource): def get(self): return {"resource": "Root :)"} @@ -98,7 +105,7 @@ class ResQuarMail(GulagResource): abort(500, message=whoami(self)+e.message) class ResQuarMailRelease(GulagResource): - def get(self,quarmail_id): + def post(self,quarmail_id): args = {"quarmail_id": quarmail_id} if(request.args.get('purge')): args['purge'] = True diff --git a/config/gulag-config.json b/config/gulag-config.json index ca647b7..711843e 100644 --- a/config/gulag-config.json +++ b/config/gulag-config.json @@ -29,6 +29,9 @@ "quarmails": "http://127.0.0.1:9090/api/v1/quarmails/", "attachments": "http://127.0.0.1:9090/api/v1/attachments/" }, + "dos_protection": { + "max_body_bytes": 8388608 + }, "db":{ "unix_socket": "/mysqld/mysqld.sock", "user": "root", diff --git a/db/gulag.sql b/db/gulag.sql index af94dbc..74b448f 100644 --- a/db/gulag.sql +++ b/db/gulag.sql @@ -66,6 +66,7 @@ create table Attachments ( content_type varchar(256) not null collate 'ascii_general_ci', content_encoding varchar(64) collate 'ascii_general_ci', magic varchar(128), + mime_type varchar(128), comment varchar(256), size int unsigned not null, sandbox_results varchar(1024) default null collate 'ascii_general_ci', diff --git a/gulag-openapi-2.0.yaml b/gulag-openapi-2.0.yaml index 9771bde..7fb8f01 100644 --- a/gulag-openapi-2.0.yaml +++ b/gulag-openapi-2.0.yaml @@ -52,6 +52,7 @@ paths: description: get full RFC822 email message for each QuarMail object - in: query name: headers + type: string description: get all email headers for each QuarMail object required: false - in: query @@ -90,6 +91,7 @@ paths: required: false - in: query name: headers + type: string description: if set to a (random) value, all email headers will be returned required: false responses: @@ -117,8 +119,8 @@ paths: - in: body name: quarmail description: quarmail fields to modify. - schema: - $ref: "#/definitions/QuarMail" + schema: + $ref: "#/definitions/QuarMail" responses: 202: description: quarantined email deleted @@ -259,6 +261,7 @@ paths: description: not found 500: description: server error + /quarmails/{quarmail_id}/bounce: post: summary: bounces a quarantined email by quarmail_id @@ -273,7 +276,29 @@ paths: type: string responses: 200: - description: null + description: nothing + 400: + description: bad input parameter + 404: + description: not found + 500: + description: server error + + /quarmails/{quarmail_id}/release: + post: + summary: releases a quarantined email by quarmail_id + operationId: release_quarmail + produces: + - application/json + parameters: + - in: path + name: quarmail_id + description: unique id of quarantined email + required: true + type: string + responses: + 200: + description: nothing 400: description: bad input parameter 404: @@ -373,6 +398,7 @@ definitions: - content_encoding - content_type - magic + - mime_type - mailbox_id - imap_uid - ssdeep @@ -397,6 +423,9 @@ definitions: magic: type: string example: "PDF document, version 1.2" + mime_type: + type: string + example: "application/pdf" href: type: string description: hypermedia