mirror of
https://github.com/chillout2k/gulag.git
synced 2025-12-13 16:00:18 +00:00
HTTP2SMTP relay for Rspamd :)
This commit is contained in:
parent
6c23eda022
commit
71d6b0b200
@ -9,12 +9,18 @@ class Mailbox:
|
|||||||
email_address = None
|
email_address = None
|
||||||
name = None
|
name = None
|
||||||
imap_server = None
|
imap_server = None
|
||||||
|
imap_port = None
|
||||||
imap_security = None
|
imap_security = None
|
||||||
imap_user = None
|
imap_user = None
|
||||||
imap_pass = None
|
imap_pass = None
|
||||||
imap_mailbox = None
|
imap_mailbox = None
|
||||||
imap_mailbox_fp = None
|
imap_mailbox_fp = None
|
||||||
imap_separator = None
|
imap_separator = None
|
||||||
|
smtp_server = None
|
||||||
|
smtp_port = None
|
||||||
|
smtp_security = None
|
||||||
|
smtp_user = None
|
||||||
|
smtp_pass = None
|
||||||
comment = None
|
comment = None
|
||||||
href = None
|
href = None
|
||||||
|
|
||||||
@ -37,6 +43,8 @@ class Mailbox:
|
|||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
raise MailboxException("'imap_security' is a mandatory!")
|
raise MailboxException("'imap_security' is a mandatory!")
|
||||||
|
if 'imap_port' in mb_ref:
|
||||||
|
self.imap_port = mb_ref['imap_port']
|
||||||
if 'imap_user' not in mb_ref:
|
if 'imap_user' not in mb_ref:
|
||||||
raise MailboxException("'imap_user' is mandatory!")
|
raise MailboxException("'imap_user' is mandatory!")
|
||||||
self.imap_user = mb_ref['imap_user']
|
self.imap_user = mb_ref['imap_user']
|
||||||
@ -52,6 +60,16 @@ class Mailbox:
|
|||||||
if 'imap_separator' not in mb_ref:
|
if 'imap_separator' not in mb_ref:
|
||||||
raise MailboxException("'imap_separator' is mandatory!")
|
raise MailboxException("'imap_separator' is mandatory!")
|
||||||
self.imap_seperator = mb_ref['imap_separator']
|
self.imap_seperator = mb_ref['imap_separator']
|
||||||
|
if 'smtp_server' in mb_ref:
|
||||||
|
self.smtp_server = mb_ref['smtp_server']
|
||||||
|
if 'smtp_port' in mb_ref:
|
||||||
|
self.smtp_port = mb_ref['smtp_port']
|
||||||
|
if 'smtp_security' in mb_ref:
|
||||||
|
self.smtp_security = mb_ref['smtp_security']
|
||||||
|
if 'smtp_user' in mb_ref:
|
||||||
|
self.smtp_user = mb_ref['smtp_user']
|
||||||
|
if 'smtp_pass' in mb_ref:
|
||||||
|
self.smtp_pass = mb_ref['smtp_pass']
|
||||||
if 'comment' in mb_ref:
|
if 'comment' in mb_ref:
|
||||||
self.comment = mb_ref['comment']
|
self.comment = mb_ref['comment']
|
||||||
if 'href' in mb_ref:
|
if 'href' in mb_ref:
|
||||||
|
|||||||
41
app/Gulag.py
41
app/Gulag.py
@ -1,5 +1,7 @@
|
|||||||
import json,sys
|
import json,sys
|
||||||
import email,email.header
|
import email,email.header,email.message
|
||||||
|
from flask import request
|
||||||
|
from smtplib import SMTP
|
||||||
from GulagDB import GulagDB,GulagDBException
|
from GulagDB import GulagDB,GulagDBException
|
||||||
from GulagMailbox import IMAPmailbox,IMAPmailboxException
|
from GulagMailbox import IMAPmailbox,IMAPmailboxException
|
||||||
|
|
||||||
@ -140,3 +142,40 @@ class Gulag:
|
|||||||
except GulagDBException as e:
|
except GulagDBException as e:
|
||||||
raise GulagException("GulagDBException: " + e.message) from e
|
raise GulagException("GulagDBException: " + e.message) from e
|
||||||
|
|
||||||
|
def rspamd_http2smtp(self,mailbox_id):
|
||||||
|
mailbox = None
|
||||||
|
try:
|
||||||
|
mailbox = self.db.get_mailbox(mailbox_id)
|
||||||
|
except GulagDBException as e:
|
||||||
|
raise GulagException(e.message) from e
|
||||||
|
|
||||||
|
if(request.headers.get('X-Rspamd-From') == None):
|
||||||
|
raise GulagException("Missing Rspamd-specific headers (e.g. X-Rspamd-From)!")
|
||||||
|
|
||||||
|
# recompose rejected mail that will be sent to quarantine mailbox
|
||||||
|
#FIXME: print("mx_queue_id: " + request.headers.get('X-Rspamd-Qid'))
|
||||||
|
msg = None
|
||||||
|
try:
|
||||||
|
msg = email.message_from_string(request.get_data(as_text=True))
|
||||||
|
rcpts_hdr = str(request.headers.get('X-Rspamd-Rcpt'))
|
||||||
|
# FIXME: special chars []" rausstrippen! -> JSON!!!
|
||||||
|
print("RCPTs neu: " + rcpts_hdr)
|
||||||
|
msg.add_header("X-Envelope-To-Blocked", rcpts_hdr)
|
||||||
|
msg.add_header("X-Spam-Status", request.headers.get('X-Rspamd-Symbols'))
|
||||||
|
# except email.errors.* as e:
|
||||||
|
except:
|
||||||
|
raise GulagException(str(sys.exc_info()))
|
||||||
|
|
||||||
|
try:
|
||||||
|
with SMTP(host=mailbox['smtp_server'],port=mailbox['smtp_port']) as smtp:
|
||||||
|
try:
|
||||||
|
smtp.sendmail(
|
||||||
|
request.headers.get('X-Rspamd-From'),
|
||||||
|
mailbox_id,
|
||||||
|
msg.as_string()
|
||||||
|
)
|
||||||
|
except (SMTPRecipientsRefused,SMTPHeloError,SMTPSenderRefused,SMTPDataError) as e:
|
||||||
|
raise GulagException(str(e)) from e
|
||||||
|
except TimeoutError as e:
|
||||||
|
raise GulagException(str(e)) from e
|
||||||
|
|
||||||
|
|||||||
@ -49,6 +49,28 @@ class GulagDB:
|
|||||||
except mariadb.Error as e:
|
except mariadb.Error as e:
|
||||||
raise GulagDBException(e) from e
|
raise GulagDBException(e) from e
|
||||||
|
|
||||||
|
def get_mailbox(self,mailbox_id):
|
||||||
|
try:
|
||||||
|
cursor = self.conn.cursor()
|
||||||
|
cursor.execute(
|
||||||
|
"select * from Mailboxes where email_address='" + mailbox_id + "' limit 1;"
|
||||||
|
)
|
||||||
|
data = cursor.fetchall()
|
||||||
|
if data == None:
|
||||||
|
raise GulagDBException("Mailbox '" + mailbox_id + "' does not exist!")
|
||||||
|
desc = cursor.description
|
||||||
|
tuple = data[0]
|
||||||
|
dict = {}
|
||||||
|
for (name, value) in zip(desc, tuple):
|
||||||
|
dict[name[0]] = value
|
||||||
|
dict['href'] = self.uri_prefixes['mailboxes'] + dict['email_address']
|
||||||
|
try:
|
||||||
|
return Mailbox(dict).__dict__
|
||||||
|
except MailboxException as e:
|
||||||
|
raise GulagDBException(e.message) from e
|
||||||
|
except mariadb.Error as e:
|
||||||
|
raise GulagDBException(e) from e
|
||||||
|
|
||||||
def add_quarmail(self, quarmail):
|
def add_quarmail(self, quarmail):
|
||||||
try:
|
try:
|
||||||
cursor = self.conn.cursor()
|
cursor = self.conn.cursor()
|
||||||
@ -121,7 +143,7 @@ class GulagDB:
|
|||||||
dict = {}
|
dict = {}
|
||||||
for (name, value) in zip(desc, tuple):
|
for (name, value) in zip(desc, tuple):
|
||||||
dict[name[0]] = value
|
dict[name[0]] = value
|
||||||
results.append(QuarMail(dict).__dict__)
|
results.append(dict)
|
||||||
return results
|
return results
|
||||||
except mariadb.Error as e:
|
except mariadb.Error as e:
|
||||||
raise GulagDBException(e) from e
|
raise GulagDBException(e) from e
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
from flask import request
|
#from flask import request
|
||||||
from flask_restful import Resource, abort
|
from flask_restful import Resource, abort, reqparse
|
||||||
from Entities import Mailbox,MailboxException,QuarMail,QuarMailException,Attachment,AttachmentException
|
|
||||||
from Gulag import GulagException
|
from Gulag import GulagException
|
||||||
|
|
||||||
class GulagResource(Resource):
|
class GulagResource(Resource):
|
||||||
@ -62,3 +61,12 @@ class ResAttachment(GulagResource):
|
|||||||
def get(self,id):
|
def get(self,id):
|
||||||
return {"resource": "Attachment by ID"}
|
return {"resource": "Attachment by ID"}
|
||||||
|
|
||||||
|
class ResRSPAMDImporter(GulagResource):
|
||||||
|
def post(self,mailbox_id):
|
||||||
|
try:
|
||||||
|
self.gulag.rspamd_http2smtp(mailbox_id)
|
||||||
|
# TODO: Response mit Location-Header?
|
||||||
|
return {"resource: ": "HTTP2SMTP for RSPAMD"}
|
||||||
|
except GulagException as e:
|
||||||
|
abort(400, message=e.message)
|
||||||
|
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import argparse,sys
|
|||||||
from flask import Flask
|
from flask import Flask
|
||||||
from flask_restful import Api
|
from flask_restful import Api
|
||||||
from Gulag import Gulag,GulagException
|
from Gulag import Gulag,GulagException
|
||||||
from Resources import ResRoot,ResMailboxes,ResQuarMails,ResAttachments
|
from Resources import ResRoot,ResMailboxes,ResQuarMails,ResAttachments,ResRSPAMDImporter
|
||||||
|
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.add_argument('--config', required=True, help="Path to config file")
|
parser.add_argument('--config', required=True, help="Path to config file")
|
||||||
@ -33,6 +33,10 @@ try:
|
|||||||
'/api/v1/attachments/',
|
'/api/v1/attachments/',
|
||||||
resource_class_kwargs={'gulag_object': gulag}
|
resource_class_kwargs={'gulag_object': gulag}
|
||||||
)
|
)
|
||||||
|
api.add_resource(ResRSPAMDImporter,
|
||||||
|
'/api/v1/mailboxes/<string:mailbox_id>/rspamdimporter/',
|
||||||
|
resource_class_kwargs={'gulag_object': gulag}
|
||||||
|
)
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
app.run(debug=False,
|
app.run(debug=False,
|
||||||
# will be overriden by uwsgi.ini
|
# will be overriden by uwsgi.ini
|
||||||
|
|||||||
@ -6,12 +6,18 @@ create table Mailboxes(
|
|||||||
email_address varchar(767) not null primary key collate 'ascii_general_ci',
|
email_address varchar(767) not null primary key collate 'ascii_general_ci',
|
||||||
name varchar(256) not null,
|
name varchar(256) not null,
|
||||||
imap_server varchar(256) not null default '127.0.0.1',
|
imap_server varchar(256) not null default '127.0.0.1',
|
||||||
|
imap_port smallint unsigned not null default 143,
|
||||||
imap_security varchar(32) not null default 'plain',
|
imap_security varchar(32) not null default 'plain',
|
||||||
imap_user varchar(256) not null,
|
imap_user varchar(256) not null,
|
||||||
imap_pass varchar(256) not null,
|
imap_pass varchar(256) not null,
|
||||||
imap_mailbox varchar(256) not null default 'INBOX',
|
imap_mailbox varchar(256) not null default 'INBOX',
|
||||||
imap_mailbox_fp varchar(256) not null default 'false-positives',
|
imap_mailbox_fp varchar(256) not null default 'false-positives',
|
||||||
imap_separator varchar(4) not null default '/',
|
imap_separator varchar(4) not null default '/',
|
||||||
|
smtp_server varchar(256) default null,
|
||||||
|
smtp_port smallint unsigned not null default 25,
|
||||||
|
smtp_security varchar(32) not null default 'plain',
|
||||||
|
smtp_user varchar(256) default null,
|
||||||
|
smtp_pass varchar(2048) default null,
|
||||||
comment varchar(256) default null
|
comment varchar(256) default null
|
||||||
)ENGINE = InnoDB;
|
)ENGINE = InnoDB;
|
||||||
insert into Mailboxes (email_address,name,imap_user,imap_pass)
|
insert into Mailboxes (email_address,name,imap_user,imap_pass)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user