1
0
Fork 0
mirror of https://github.com/ethauvin/fail2ban-digest.git synced 2025-04-26 10:58:12 -07:00

Added --html argument and templates.

This commit is contained in:
Erik C. Thauvin 2019-03-05 23:47:30 -08:00
parent e5981669d8
commit e8eafc027b

View file

@ -45,6 +45,63 @@ Regards,
Fail2ban Digest Fail2ban Digest
''') ''')
default_html_template = Template('''<!DOCTYPE html>
<html>
<head>
<style>
body {
font-family: 'Helvetica Neue', Helvetica, Arial, 'Lucida Grande', sans-serif;
}
table {
border-collapse: collapse;
}
td, th {
border: 1px solid darkgrey;
text-align: left;
padding: 6px;
}
td {
vertical-align: top;
}
td:last-child {
width: 1px;
white-space: nowrap;
}
th {
background-color: #dddddd;
}
</style>
</head>
<body>
<p>Hi,</p>
<p>This is a digest email of banned IPs since <b>${creation_date}</b> and <b>${date_now}</b>:</p>
<table>
<tr>
<th style="text-align: center">#</th>
<th style="text-align: center">IPs</th>
<th>When</th>
</tr>
${digest}
</table>
<p>Regards,</p>
<p><a href="https://github.com/enricotagliavini/fail2ban-digest">Fail2Ban Digest</a><p>
</body>
<html>
''')
html_tr_template = Template(''' <tr>
<td style="text-align: center">${count}</td>
<td style="text-align: right">${ip}</td>
<td>${events}</td>
</tr>
''')
html_error_template = Template(''' <tr>
<td colspan="3"><em>${error_msg}</em></td>
</tr>''')
class Ban: class Ban:
def __init__(self, ip, events): def __init__(self, ip, events):
self.ip = ip self.ip = ip
@ -127,7 +184,7 @@ def add(db, ip):
close_db(db) close_db(db)
return return
def digest(db, delete): def digest(db, delete, sort):
db_file = db_location + '/' + db + '.dbm' db_file = db_location + '/' + db + '.dbm'
new_db_file = db_location + '/.' + db + '.dbm' new_db_file = db_location + '/.' + db + '.dbm'
try: try:
@ -158,22 +215,31 @@ def digest(db, delete):
msg = '' msg = ''
msg_html = '' msg_html = ''
for ban in events_list: for ban in events_list:
msg_html += html_tr_template.substitute(count = len(ban.events), ip = ban.ip, events = '<br>'.join(ban.events))
msg += '%3d event(s) for IP %-42s: %s\n' %(len(ban.events), ban.ip, ', '.join(ban.events)) msg += '%3d event(s) for IP %-42s: %s\n' %(len(ban.events), ban.ip, ', '.join(ban.events))
return (db_creation_date, msg, msg_html)
def mail_digest(db, mail_to, mail_from, delete, quiet): def mail_digest(db, mail_to, mail_from, delete, html, quiet, sort):
msg = EmailMessage() msg = EmailMessage()
date_now = datetime.now().strftime(db_date_format) date_now = datetime.now().strftime(db_date_format)
creation_date, dgst = digest(db, delete) creation_date, dgst, dgst_html = digest(db, delete, sort)
if dgst == '': if dgst == '':
if quiet: if quiet:
return return
else: else:
dgst = ' No ban event recorded for the named time frame.' dgst = ' No ban event recorded for the named time frame.'
dgst_html = html_error_template.substitute(error_msg = dgst)
msg.set_content(default_mail_template.substitute( msg.set_content(default_mail_template.substitute(
creation_date = creation_date, creation_date = creation_date,
date_now = date_now, date_now = date_now,
digest = dgst digest = dgst
)) ))
if html:
msg.add_alternative(default_html_template.substitute(
creation_date = creation_date,
date_now = date_now,
digest = dgst_html
), subtype = 'html')
msg['To'] = mail_to msg['To'] = mail_to
msg['From'] = mail_from msg['From'] = mail_from
msg['Subject'] = '[Fail2Ban] %s: digest for %s %s' % (db, socket.gethostname(), date_now) msg['Subject'] = '[Fail2Ban] %s: digest for %s %s' % (db, socket.gethostname(), date_now)
@ -186,9 +252,9 @@ def main(args):
if args.cmd == 'add': if args.cmd == 'add':
add(args.database, args.ip) add(args.database, args.ip)
elif args.cmd == 'digest': elif args.cmd == 'digest':
print(digest(args.database, args.delete)[1]) print(digest(args.database, args.delete, args.sort)[1])
elif args.cmd == 'maildigest': elif args.cmd == 'maildigest':
mail_digest(args.database, args.to, args.mail_from, args.delete, args.quiet) mail_digest(args.database, args.to, args.mail_from, args.html, args.delete, args.quiet, args.sort)
elif args.cmd is None: elif args.cmd is None:
print('No action specified') print('No action specified')
return return
@ -259,6 +325,12 @@ if __name__ == '__main__':
default = True, default = True,
help = 'do / don\'t delete current database, next call to add will create a new empty one' help = 'do / don\'t delete current database, next call to add will create a new empty one'
) )
subcommands[sc].add_argument(
'--html', '--no-html',
action = store_yesno,
default = False,
help = 'do / don\'t send the digest in HTML format.'
)
subcommands[sc].add_argument( subcommands[sc].add_argument(
'--mail-from', '--mail-from',
action = 'store', action = 'store',
@ -271,6 +343,12 @@ if __name__ == '__main__':
default = False, default = False,
help = 'do / don\'t send digest if there are no ban events recorded for the named time frame' help = 'do / don\'t send digest if there are no ban events recorded for the named time frame'
) )
subcommands[sc].add_argument(
'--sort', '--no-sort',
action = store_yesno,
default = True,
help = 'do / don\'t sort the digest by repeat event occurrences.'
)
subcommands[sc].add_argument( subcommands[sc].add_argument(
'--to', '--to',
action = 'store', action = 'store',