diff --git a/app/Gulag.py b/app/Gulag.py index 8167db1..c1cd43a 100644 --- a/app/Gulag.py +++ b/app/Gulag.py @@ -1,4 +1,4 @@ -import json,sys +import json,sys,os,logging import email,email.header,email.message from GulagDB import GulagDB,GulagDBException from GulagMailbox import IMAPmailbox,IMAPmailboxException @@ -23,13 +23,32 @@ class Gulag: f.close() except: raise GulagException(whoami(self) + str(sys.exc_info())) + # logging +# logging_level = logging.INFO +# if 'level' in self.config['logging']: + if 'logging' not in self.config: + raise GulagException(whoami(self) + "Logging not configured!") + if('filename' in self.config['logging'] and + len(self.config['logging']['filename']) > 0): + logging.basicConfig( + filename=self.config['logging']['filename'], + format='%(asctime)s %(levelname)s %(message)s', + level=self.config['logging']['level'] + ) + else: + logging.basicConfig( + format='%(asctime)s %(levelname)s %(message)s', + level=self.config['logging']['level'] + ) try: self.db = GulagDB(self.config['db'],self.config['uri_prefixes']) self.fields['Mailboxes'] = self.db.get_fields('Mailboxes') self.fields['QuarMails'] = self.db.get_fields('QuarMails') self.fields['Attachments'] = self.db.get_fields('Attachments') except GulagDBException as e: + logging.warning(whoami(self) + e.message) raise GulagException(whoami(self) + e.message) from e + logging.info('Gulag core initialized by ' + os.path.basename(__file__)) def check_fields(self,fields_target,args): if fields_target not in self.fields: @@ -54,7 +73,7 @@ class Gulag: try: imap_mb = IMAPmailbox(mailbox) except IMAPmailboxException as e: - print(e.message) + logging.warning(whoami(self) + e.message) continue for unseen in imap_mb.get_unseen_messages(): quarmail_ids = [] @@ -70,13 +89,17 @@ class Gulag: try: r5321_rcpts = email.header.decode_header(msg['X-Envelope-To-Blocked'])[0][0] except: - print("Failed to extract envelope recipients! Skipping mail") + logging.warning(whoami(self) + + "Failed to extract envelope recipients! Skipping mail" + ) continue r5322_from = None try: r5322_from = email.header.decode_header(msg['From'])[0][0] except: - print("Failed to extract from header! Skipping mail") + logging.warning(whoami(self) + + "Failed to extract from header! Skipping mail" + ) continue subject = email.header.decode_header(msg['Subject'])[0][0] msg_id = None @@ -109,7 +132,7 @@ class Gulag: 'hdr_msgid': msg_id, 'hdr_date': date, 'cf_meta': 'cf_meta', 'mailbox_id': 'quarantine@zwackl.de', 'imap_uid': uid, 'msg_size': msg_size }) - print("QuarMail (%s) imported" % (quarmail_id)) + logging.info(whoami(self) + "QuarMail (%s) imported" % (quarmail_id)) quarmail_ids.append(quarmail_id) # Ende for rcpts # Alle MIME-Parts durchiterieren und Attachments @@ -142,16 +165,15 @@ class Gulag: # Ende for get_mailboxes def cleanup_quarmails(self): - print("Mails to expunge: " + - str(len( - self.db.get_deprecated_mails(self.config['cleaner']['retention_period']) - )) - ) + logging.info(whoami(self) + "QuarMails to purge: " + str(len( + self.db.get_deprecated_mails(self.config['cleaner']['retention_period']) + ))) def get_mailboxes(self): try: return self.db.get_mailboxes() except GulagDBException as e: + logging.warning(whoami(self) + e.message) raise GulagException(whoami(self) + e.message) from e def get_quarmails(self,args): @@ -159,6 +181,7 @@ class Gulag: self.check_fields('QuarMails',args) return self.db.get_quarmails(args) except(GulagException,GulagDBException) as e: + logging.warning(whoami(self) + e.message) raise GulagException( whoami(self) + e.message ) from e @@ -168,6 +191,7 @@ class Gulag: try: qm_db = self.db.get_quarmail({"id": args['quarmail_id']}) except GulagDBException as e: + logging.warning(whoami(self) + e.message) raise GulagException(whoami(self) + e.message) from e if 'rfc822_message' not in args: return qm_db @@ -176,6 +200,7 @@ class Gulag: try: mailbox = self.db.get_mailbox(qm_db['mailbox_id']) except GulagDBException as e: + logging.warning(whoami(self) + e.message) raise GulagException(whoami(self) + e.message) from e imap_mb = None try: @@ -183,14 +208,14 @@ class Gulag: qm_db['rfc822_message'] = imap_mb.get_message(qm_db['imap_uid']).decode("utf-8") return qm_db except IMAPmailboxException as e: - print(e.message) + logging.warning(whoami(self) + e.message) raise GulagException(whoami(self) + e.message) from e def get_quarmail_attachments(self,args): try: return self.db.get_quarmail_attachments(args['quarmail_id']) except GulagDBException as e: - print(e.message) + logging.warning(whoami(self) + e.message) raise GulagException(whoami(self) + e.message) from e def get_quarmail_attachment(self,args): @@ -200,7 +225,7 @@ class Gulag: args['quarmail_id'],args['attachment_id'] ) except GulagDBException as e: - print(e.message) + logging.warning(whoami(self) + e.message) raise GulagException(whoami(self) + e.message) from e if 'data' not in args: return qmat_db @@ -209,6 +234,7 @@ class Gulag: try: mailbox = self.db.get_mailbox(qmat_db['mailbox_id']) except GulagDBException as e: + logging.warning(whoami(self) + e.message) raise GulagException(whoami(self) + e.message) from e imap_mb = None try: @@ -218,7 +244,7 @@ class Gulag: ) return qmat_db except IMAPmailboxException as e: - print(e.message) + logging.warning(whoami(self) + e.message) raise GulagException(whoami(self) + e.message) from e def get_attachment(self,args): @@ -243,19 +269,52 @@ class Gulag: # check if the request comes really from rspamd´s metadata_exporter # default metadata_header prefix 'X-Rspamd' will be expected if('X-Rspamd-From' not in args['req_headers']): - raise GulagException(whoami(self) - + "Missing Rspamd-specific headers (e.g. X-Rspamd-From)!" + err = str(whoami(self) + + "Missing Rspamd-specific request header X-Rspamd-From!" ) + logging.error(err) + raise GulagException(err) # Prepend Gulag-specific headers to rejected mail # before pushing into quarantine mailbox msg = None try: + if('X-Rspamd-From' not in args['req_headers']): + err = str(whoami(self) + + "Missing Rspamd-specific request header X-Rspamd-From!" + ) + logging.error(err) + raise GulagException(err) + if('X-Rspamd-Rcpt' not in args['req_headers']): + err = str(whoami(self) + + "Missing Rspamd-specific request header X-Rspamd-Rcpt!" + ) + logging.error(err) + raise GulagException(err) + if('X-Rspamd-Symbols' not in args['req_headers']): + err = str(whoami(self) + + "Missing Rspamd-specific request header X-Rspamd-Symbols!" + ) + logging.error(err) + raise GulagException(err) + if('X-Rspamd-Qid' not in args['req_headers']): + err = str(whoami(self) + + "Missing Rspamd-specific request header X-Rspamd-Qid!" + ) + logging.error(err) + raise GulagException(err) + if('rfc822_message' not in args['rfc822_message']): + err = str(whoami(self) + + "Missing rfc822_message!" + ) + logging.error(err) + raise GulagException(err) + # all mandatory request headers and body are present rcpts_hdr = "" for rcpt in json.loads(str(args['req_headers']['X-Rspamd-Rcpt'])): if(len(rcpts_hdr) > 0): rcpts_hdr += "," + rcpt else: - rcpts_hdr = rcpt + rcpts_hdr = rcpt msg = "Return-Path: <" + args['req_headers']['X-Rspamd-From'] + ">\r\n" msg += "Received: from rspamd_http2imap relay by gulag-mailbox " msg += args['mailbox_id'] + "\r\n" @@ -264,6 +323,8 @@ class Gulag: msg += "X-Spam-QID: " + args['req_headers']['X-Rspamd-Qid'] + "\r\n" # append original mail msg += args['rfc822_message'] + except GulagException as e: + raise GulagException(e.message) from e except: raise GulagException(whoami(self) + str(sys.exc_info())) imap_mb = None diff --git a/app/GulagUtils.py b/app/GulagUtils.py index 63b81de..cc9e05c 100644 --- a/app/GulagUtils.py +++ b/app/GulagUtils.py @@ -1,7 +1,6 @@ import sys from smtplib import SMTP - def whoami(obj): return type(obj).__name__ + "::" + sys._getframe(1).f_code.co_name + "(): " diff --git a/app/Resources.py b/app/Resources.py index 4e5efbd..ba5c8e8 100644 --- a/app/Resources.py +++ b/app/Resources.py @@ -103,6 +103,7 @@ class ResRSPAMDImporter(GulagResource): "rfc822_message": request.get_data(as_text=True) }) # TODO: Response mit Location-Header? + # https://stackoverflow.com/a/22707491 return {"resource: ": "HTTP2IMAP for RSPAMD"} except GulagException as e: abort(400, message=e.message) diff --git a/config/gulag-config.json b/config/gulag-config.json index b07b300..1f906c9 100644 --- a/config/gulag-config.json +++ b/config/gulag-config.json @@ -1,4 +1,10 @@ { + "logging": { + "__level": "default: WARNING. Possible: INFO,ERROR,CRITICAL,DEBUG", + "level": "DEBUG", + "__filename": "default: empty string (stdout).", + "filename": "" + }, "daemon":{ "listen_host": "127.0.0.1", "listen_port": 5001 @@ -17,10 +23,10 @@ } }, "uri_prefixes": { - "root": "https://gulag.example.org/api/v1/", - "mailboxes": "https://gulag.example.org/api/v1/mailboxes/", - "quarmails": "https://gulag.example.org/api/v1/quarmails/", - "attachments": "https://gulag.example.org/api/v1/attachments/" + "root": "http://127.0.0.1:9090/api/v1/", + "mailboxes": "http://127.0.0.1:9090/api/v1/mailboxes/", + "quarmails": "http://127.0.0.1:9090/api/v1/quarmails/", + "attachments": "http://127.0.0.1:9090/api/v1/attachments/" }, "db":{ "unix_socket": "/mysqld/mysqld.sock",