Skip to content

Commit efa45d6

Browse files
Merge pull request #1 from asdfdotdev/development
Refactor to package
2 parents 0fd3f49 + f1da758 commit efa45d6

File tree

17 files changed

+489
-156
lines changed

17 files changed

+489
-156
lines changed

.editorconfig

Lines changed: 3 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -10,32 +10,6 @@ trim_trailing_whitespace = true
1010
end_of_line = lf
1111
charset = utf-8
1212

13-
# Docstrings and comments use max_line_length = 79
14-
[*.py]
15-
max_line_length = 119
16-
17-
# Use 2 spaces for the HTML files
18-
[*.html]
19-
indent_size = 2
20-
21-
# The JSON files contain newlines inconsistently
22-
[*.json]
23-
indent_size = 2
24-
insert_final_newline = ignore
25-
26-
[**/admin/js/vendor/**]
27-
indent_style = ignore
28-
indent_size = ignore
29-
30-
# Minified JavaScript files shouldn't be changed
31-
[**.min.js]
32-
indent_style = ignore
33-
insert_final_newline = ignore
34-
35-
# Makefiles always use tabs for indentation
36-
[Makefile]
37-
indent_style = tab
38-
39-
# Batch files use tabs for indentation
40-
[*.bat]
41-
indent_style = tab
13+
[{*.js,*.json,*.yml,.bablerc}]
14+
indent_style = space
15+
indent_size = 2

.github/ISSUE_TEMPLATE/BUG_REPORT.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
11
---
22
name: Bug report
3-
about: Create a report to help us improve
3+
about: Create a report to help us improve fail2slack
44
title: ''
55
labels: ''
66
assignees: ''
77

88
---
99

1010
**Describe the bug**
11+
1112
A clear and concise description of what the bug is.
1213

1314
**To Reproduce**
15+
1416
Steps to reproduce the behavior:
1517

1618

.gitignore

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
**/.DS_Store
2-
.idea
3-
*config.py
4-
**/*.log
5-
__pycache__/
6-
**/*.pyc
2+
.idea/
3+
**/__pycache__/
4+
**/build/
5+
**/dist/
6+
**/*.egg-info/
7+
.coverage

.travis.yml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
dist: xenial
2+
language: python
3+
4+
python:
5+
- "3.6"
6+
- "3.7"
7+
- "3.7.4"
8+
- "3.8-dev"
9+
10+
install:
11+
- pip install -r requirements.txt
12+
- pip install codecov
13+
- pip install coverage
14+
15+
script:
16+
- python -m unittest discover
17+
- coverage run --source fail2slack -m test.test_fail2slack
18+
19+
after_success:
20+
- codecov
21+

README.md

Lines changed: 26 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,42 @@
1-
# fail2slack
1+
# fail2slack.py
22

3-
A friendly little script that can package up your fail2ban vault statuses and send them to you over slack.
3+
[![Build Status](https://travis-ci.org/asdfdotdev/fail2slack.svg?branch=master)](https://travis-ci.org/asdfdotdev/fail2slack) [![codecov](https://codecov.io/gh/asdfdotdev/fail2slack/branch/master/graph/badge.svg)](https://codecov.io/gh/asdfdotdev/fail2slack)
44

5-
## Setup
5+
A Python package for sending fail2ban jail status updates to Slack.
66

7-
Create fail2slackconfig.py
7+
## Compatibility
88

9-
```
10-
$ cp fail2slackconfig.dist.py fail2slackconfig.py
11-
```
12-
13-
[Setup your Slack webhook](https://api.slack.com/incoming-webhooks) and add it to the config file:
9+
[![Python Version](https://img.shields.io/pypi/pyversions/fail2slack)](https://pypi.org/project/fail2slack) [![Module Version](https://img.shields.io/pypi/v/fail2slack)](https://pypi.org/project/fail2slack)
1410

15-
```
16-
webhook_url = 'https://hooks.slack.com/YOUR/WEBHOOK/URL'
17-
```
11+
fail2slack is developed for, and tested with, recent versions of Python.
1812

19-
Select the vaults you want to report on:
13+
## Installation
2014

2115
```
22-
vaults = [
23-
'apache-auth', 'apache-badbots', 'apache-botsearch',
24-
'apache-fakegooglebot', 'apache-modsecurity', 'apache-nohome',
25-
'apache-noscript', 'apache-overflows', 'apache-shellshock',
26-
'php-url-fopen', 'sshd'
27-
]
16+
pip install fail2slack
2817
```
2918

30-
## Usage
31-
32-
fail2slack should play nicely with Python v2 & v3. It can be run as a file or from the shell.
19+
Install fail2slack using the Python package installer.
3320

34-
35-
## Output
36-
37-
The current failed/banned counts will be compiled for all selected vaults and sent via the webhook.
21+
## Usage
3822

3923
```
40-
vault-name
41-
Failed: CURRENT (TOTAL), Banned: CURRENT (TOTAL)
24+
usage: fail2slack [-h] [-w WEBHOOK] [-d DELIVERY] [-j JAILS [JAILS ...]]
25+
26+
optional arguments:
27+
-h, --help show this help message and exit
28+
-w WEBHOOK, --webhook WEBHOOK
29+
Slack webhook URL. Required if delivery method is 1.
30+
-d DELIVERY, --delivery DELIVERY
31+
Delivery method: 0 = print, 1 = Slack webhook.
32+
-j JAILS [JAILS ...], --jails JAILS [JAILS ...]
33+
Jails to include in status report. Required.
4234
```
4335

44-
## Providing Feedback
36+
## Tests
37+
38+
For instructions on running test check out the [README](./test#readme).
39+
40+
## Contributing
4541

46-
Please reference our [code of conduct](./.github/CODE_OF_CONDUCT.md) and [contributing](./.github/CONTRIBUTING.md) guides.
42+
If you'd like to contribute to fail2slack please reference our [code of conduct](./.github/CODE_OF_CONDUCT.md) and [contributing](./.github/CONTRIBUTING.md) guides.

fail2slack.py

Lines changed: 0 additions & 74 deletions
This file was deleted.

fail2slack/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# -*- coding: utf-8 -*-
2+
3+
__name__ = 'fail2slack'
4+
__version__ = '0.1'

fail2slack/__main__.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#!/usr/bin/env python
2+
# -*- coding: utf-8 -*-
3+
#
4+
# fail2slack
5+
#
6+
# Copyright 2018-present Chris Carlevato (https://github.com/asdfdotdev)
7+
# License http://www.gnu.org/licenses/gpl-2.0.html
8+
#
9+
# This program is free software; you can redistribute it and/or
10+
# modify it under the terms of the GNU General Public License
11+
# as published by the Free Software Foundation; version 2.
12+
#
13+
# This program is distributed in the hope that it will be useful,
14+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+
# GNU General Public License for more details.
17+
18+
import sys
19+
from .jails import *
20+
from .settings import Settings
21+
from .delivery import Delivery
22+
23+
24+
def main():
25+
settings = Settings()
26+
settings.process_args(sys.argv)
27+
delivery = Delivery(settings)
28+
29+
delivery.output(
30+
get_jails_status(
31+
settings.get_jails()
32+
)
33+
)
34+
35+
36+
if __name__ == '__main__':
37+
main()

fail2slack/delivery.py

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# -*- coding: utf-8 -*-
2+
3+
import sys
4+
5+
6+
class Delivery:
7+
8+
def __init__(self, settings):
9+
self._delivery_method = settings.get_delivery_method()
10+
self._webhook_url = settings.get_webhook_url()
11+
12+
def output(self, jail_data):
13+
"""
14+
Output update message based on current settings.
15+
:param jail_data: array of jail data (failed/banned)
16+
:return: void
17+
"""
18+
message = self.generate_message(self, jail_data)
19+
20+
if 1 == self._delivery_method:
21+
self.slack_output(self, message)
22+
else:
23+
self.print_output(self, message)
24+
25+
@staticmethod
26+
def generate_message(self, jail_data):
27+
"""
28+
Generate update message using jail data.
29+
:param jail_data: array of jail data (failed/banned)
30+
:return: string formatting update message
31+
"""
32+
message = ''
33+
34+
for jail in jail_data:
35+
message += "*{0}*\n\tFailed: {1} ({2}), Banned: {3} ({4})\n".format(*jail)
36+
37+
return message
38+
39+
@staticmethod
40+
def print_output(self, message):
41+
"""
42+
Output message to a stream, or to sys.stdout by default.
43+
:param message: string message
44+
:return: void
45+
"""
46+
print(message)
47+
48+
@staticmethod
49+
def slack_output(self, message):
50+
"""
51+
Send message to slack via webhook.
52+
:param message: string message
53+
:return: void
54+
"""
55+
import requests
56+
import json
57+
58+
response = requests.post(
59+
self._webhook_url,
60+
data=json.dumps({'text': message}),
61+
headers={'Content-Type': 'application/json'}
62+
)
63+
64+
if response.status_code != 200:
65+
sys.exit("Slack webhook connection failed with error: {0} ({1})".format(response.text, response.status_code))

fail2slack/jails.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# -*- coding: utf-8 -*-
2+
3+
import re
4+
import subprocess
5+
import sys
6+
7+
8+
def get_jails_status(active_jails):
9+
jails_status = []
10+
11+
try:
12+
for jail in active_jails:
13+
jail_output = subprocess.check_output("fail2ban-client status " + jail, shell=True).decode('utf-8')
14+
15+
current_failed_count = 0
16+
total_failed_count = 0
17+
current_banned_count = 0
18+
total_banned_count = 0
19+
20+
current_failed = re.search(r"Currently failed:(.*\b)", jail_output, re.IGNORECASE | re.MULTILINE)
21+
total_failed = re.search(r"Total failed:(.*\b)", jail_output, re.IGNORECASE | re.MULTILINE)
22+
current_banned = re.search(r"Currently banned:(.*\b)", jail_output, re.IGNORECASE | re.MULTILINE)
23+
total_banned = re.search(r"Total banned:(.*\b)", jail_output, re.IGNORECASE | re.MULTILINE)
24+
25+
if current_failed:
26+
current_failed_count = current_failed.group(1).strip()
27+
28+
if total_failed:
29+
total_failed_count = total_failed.group(1).strip()
30+
31+
if current_banned:
32+
current_banned_count = current_banned.group(1).strip()
33+
34+
if total_banned:
35+
total_banned_count = total_banned.group(1).strip()
36+
37+
jails_status.append([
38+
jail,
39+
current_failed_count,
40+
total_failed_count,
41+
current_banned_count,
42+
total_banned_count
43+
])
44+
except subprocess.CalledProcessError:
45+
sys.exit("Unable to get fail2ban-client status. Confirm it is available and you have permission to use it.")
46+
47+
return jails_status

0 commit comments

Comments
 (0)