├── api
├── data
│ └── .gitkeep
├── first_init.py
├── main.py
├── f2b.py
└── _defs.py
├── static
├── .gitkeep
└── main.css
├── config
├── prod.env.js
├── dev.env.js
└── index.js
├── src
├── assets
│ └── logo.png
├── router
│ └── index.js
├── main.js
├── App.vue
└── components
│ ├── Home.vue
│ ├── Jails.vue
│ └── Jail.vue
├── requirements.txt
├── jail.local.sample
├── index.html
├── package.json
├── .gitignore
└── README.md
/api/data/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/static/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/config/prod.env.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | NODE_ENV: '"production"'
3 | }
4 |
--------------------------------------------------------------------------------
/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dunderrrrrr/Fail2ban-FastAPI/HEAD/src/assets/logo.png
--------------------------------------------------------------------------------
/api/first_init.py:
--------------------------------------------------------------------------------
1 | from f2b import generate_files
2 |
3 | if __name__ == "__main__":
4 | generate_files()
--------------------------------------------------------------------------------
/config/dev.env.js:
--------------------------------------------------------------------------------
1 | var merge = require('webpack-merge')
2 | var prodEnv = require('./prod.env')
3 |
4 | module.exports = merge(prodEnv, {
5 | NODE_ENV: '"development"'
6 | })
7 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | certifi==2019.11.28
2 | chardet==3.0.4
3 | Click==7.0
4 | dataclasses==0.7
5 | fastapi==0.49.0
6 | h11==0.9.0
7 | httptools==0.1.1
8 | idna==2.9
9 | pydantic==1.4
10 | requests==2.23.0
11 | starlette==0.12.9
12 | urllib3==1.25.8
13 | uvicorn==0.11.3
14 | uvloop==0.14.0
15 | websockets==8.1
16 |
--------------------------------------------------------------------------------
/jail.local.sample:
--------------------------------------------------------------------------------
1 | #
2 | # THIS FILE IS LOCATED IN /etc/fail2ban/jail.local
3 | #
4 |
5 |
6 | # DEFAULTS
7 | [DEFAULT]
8 | bantime = 1h
9 | findtime = 15m
10 |
11 | # SSH
12 | [sshd]
13 | enabled = true
14 | port = 22
15 | filter = sshd
16 | logpath = /var/log/auth.log
17 | maxretry = 3
18 |
19 | # NGINX
20 | [nginx-http-auth]
21 | enabled = true
22 | filter = nginx-http-auth
23 | port = http,https
24 | logpath = /var/log/nginx/error.log
25 | /var/log/nginx/site01.com/error.log
26 | /var/log/nginx/site02.com/error.log
27 | maxretry = 3
28 |
--------------------------------------------------------------------------------
/src/router/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Router from 'vue-router'
3 | import Home from '@/components/Home'
4 | import Jails from '@/components/Jails'
5 | import Jail from '@/components/Jail'
6 |
7 | Vue.use(Router)
8 |
9 | export default new Router({
10 | mode: 'history',
11 | routes: [
12 | {
13 | path: '/',
14 | name: 'Home',
15 | component: Home
16 | },
17 | {
18 | path: '/jails',
19 | name: 'Jails',
20 | component: Jails
21 | },
22 | {
23 | path: '/jail/:jailname',
24 | name: 'Jail',
25 | component: Jail
26 | }
27 | ]
28 | })
29 |
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | // The Vue build version to load with the `import` command
2 | // (runtime-only or standalone) has been set in webpack.base.conf with an alias.
3 | import Vue from 'vue'
4 | import App from './App'
5 | import router from './router'
6 | import { library } from '@fortawesome/fontawesome-svg-core'
7 | import { faBookDead, faSkull, faCaretRight, faArchway, faDownload, faSyncAlt } from '@fortawesome/free-solid-svg-icons'
8 | import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
9 | import Notifications from 'vue-notification'
10 |
11 | Vue.config.productionTip = false
12 |
13 | Vue.use(Notifications)
14 |
15 | library.add(
16 | faBookDead,
17 | faSkull,
18 | faCaretRight,
19 | faArchway,
20 | faDownload,
21 | faSyncAlt
22 | )
23 |
24 | Vue.component(
25 | 'font-awesome-icon',
26 | FontAwesomeIcon
27 | )
28 |
29 | /* eslint-disable no-new */
30 | new Vue({
31 | el: '#app',
32 | router,
33 | template: '',
34 | components: { App }
35 | })
36 |
--------------------------------------------------------------------------------
/api/main.py:
--------------------------------------------------------------------------------
1 | import uvicorn
2 | import requests
3 | from fastapi import FastAPI
4 | from pydantic import BaseModel
5 | from starlette.middleware.cors import CORSMiddleware
6 | from _defs import main, get_jail
7 | from f2b import ban_ip, unban_ip, generate_files
8 |
9 | app = FastAPI()
10 | api_host = "localhost"
11 | api_port = 8000
12 |
13 | origins = [
14 | "*"
15 | ]
16 |
17 | app.add_middleware(
18 | CORSMiddleware,
19 | allow_origins=origins,
20 | allow_credentials=True,
21 | allow_methods=["*"],
22 | allow_headers=["*"],
23 | )
24 |
25 | class Item(BaseModel):
26 | ip: str
27 | jail: str
28 |
29 | @app.get("/")
30 | def read_root():
31 | uri = 'http://{}:{}/openapi.json'.format(api_host, api_port)
32 | r = requests.get(uri)
33 | return(r.json()['paths'])
34 |
35 | @app.get("/jails")
36 | def read_jails():
37 | m = main()
38 | return(m)
39 |
40 | @app.get("/jail/{jail}")
41 | def read_jail(jail):
42 | jail_data = get_jail(jail)
43 | return (jail_data)
44 |
45 | @app.post("/ban")
46 | async def ip_ban(item: Item):
47 | ban = ban_ip(item.ip, item.jail)
48 | return item
49 |
50 | @app.post("/unban")
51 | async def ip_unban(item: Item):
52 | unban = unban_ip(item.ip, item.jail)
53 | return item
54 |
55 | @app.get("/refresh")
56 | def refresh():
57 | generate_files()
58 | return "OK"
59 |
60 | if __name__ == "__main__":
61 | uvicorn.run("main:app", host=api_host, port=api_port, reload=True)
--------------------------------------------------------------------------------
/config/index.js:
--------------------------------------------------------------------------------
1 | // see http://vuejs-templates.github.io/webpack for documentation.
2 | var path = require('path')
3 |
4 | module.exports = {
5 | build: {
6 | env: require('./prod.env'),
7 | index: path.resolve(__dirname, '../dist/index.html'),
8 | assetsRoot: path.resolve(__dirname, '../dist'),
9 | assetsSubDirectory: 'static',
10 | assetsPublicPath: '/',
11 | productionSourceMap: true,
12 | // Gzip off by default as many popular static hosts such as
13 | // Surge or Netlify already gzip all static assets for you.
14 | // Before setting to `true`, make sure to:
15 | // npm install --save-dev compression-webpack-plugin
16 | productionGzip: false,
17 | productionGzipExtensions: ['js', 'css'],
18 | // Run the build command with an extra argument to
19 | // View the bundle analyzer report after build finishes:
20 | // `npm run build --report`
21 | // Set to `true` or `false` to always turn it on or off
22 | bundleAnalyzerReport: process.env.npm_config_report
23 | },
24 | dev: {
25 | env: require('./dev.env'),
26 | port: 8080,
27 | autoOpenBrowser: true,
28 | assetsSubDirectory: 'static',
29 | assetsPublicPath: '/',
30 | proxyTable: {},
31 | // CSS Sourcemaps off by default because relative paths are "buggy"
32 | // with this option, according to the CSS-Loader README
33 | // (https://github.com/webpack/css-loader#sourcemaps)
34 | // In our experience, they generally work as expected,
35 | // just be aware of this issue when enabling this option.
36 | cssSourceMap: false
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | Fail2ban FastAPI
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
34 |
35 |
--------------------------------------------------------------------------------
/api/f2b.py:
--------------------------------------------------------------------------------
1 | import os
2 | import time
3 |
4 | data_path = os.path.dirname(os.path.realpath(__file__)) + "/data/"
5 |
6 | def create_status():
7 | print("Running fail2ban-client status")
8 | filename = "jails.txt"
9 | data = os.popen('fail2ban-client status').read()
10 | file = open(data_path + filename, 'w')
11 | file.write(data)
12 | print("Wrote to {}{}\n".format(data_path, filename))
13 |
14 | def get_jails():
15 | f = open(data_path + "jails.txt", "r")
16 | l = []
17 | for line in f:
18 | l.append(line)
19 | jail_names = l[2].split(':')[1].strip()
20 | jails = jail_names.split(', ')
21 | return(jails)
22 |
23 | def create_jail(jail):
24 | print("Running fail2ban-client status {}".format(jail))
25 | data = os.popen('fail2ban-client status {}'.format(jail)).read()
26 | print("JAILDATA: ", data)
27 | file = open(data_path + "jail_" + jail + ".txt", 'w')
28 | file.write(data)
29 | print("wrote to {}jail_{}.txt\n".format(data_path, jail))
30 |
31 | def ban_ip(ip, jail):
32 | print("Banning {} in jail {}".format(ip, jail))
33 | data = os.popen('fail2ban-client set {} banip {}'.format(jail, ip)).read()
34 | print(data)
35 | time.sleep(1.5) # takes time to refresh jail (got diff in vue frontend)
36 | create_jail(jail)
37 |
38 | def unban_ip(ip, jail):
39 | print("Unbanning {} in jail {}".format(ip, jail))
40 | data = os.popen('fail2ban-client set {} unbanip {}'.format(jail, ip)).read()
41 | print(data)
42 | time.sleep(1.5) # takes time to refresh jail (got diff in vue frontend)
43 | create_jail(jail)
44 |
45 | def generate_files():
46 | status = create_status()
47 | jails = get_jails()
48 | for jail in jails:
49 | create_jail(jail)
50 |
51 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "router-app",
3 | "version": "1.0.0",
4 | "description": "A Vue.js project",
5 | "author": "",
6 | "private": true,
7 | "scripts": {
8 | "dev": "node build/dev-server.js",
9 | "start": "node build/dev-server.js",
10 | "build": "node build/build.js"
11 | },
12 | "dependencies": {
13 | "@fortawesome/fontawesome-svg-core": "^1.2.27",
14 | "@fortawesome/free-solid-svg-icons": "^5.12.1",
15 | "@fortawesome/vue-fontawesome": "^0.1.9",
16 | "axios": "^0.16.2",
17 | "vue": "^2.2.6",
18 | "vue-notification": "^1.3.20",
19 | "vue-router": "^2.3.1"
20 | },
21 | "devDependencies": {
22 | "autoprefixer": "^6.7.2",
23 | "babel-core": "^6.22.1",
24 | "babel-loader": "^6.2.10",
25 | "babel-plugin-transform-runtime": "^6.22.0",
26 | "babel-preset-env": "^1.3.2",
27 | "babel-preset-stage-2": "^6.22.0",
28 | "babel-register": "^6.22.0",
29 | "chalk": "^1.1.3",
30 | "connect-history-api-fallback": "^1.3.0",
31 | "copy-webpack-plugin": "^4.0.1",
32 | "css-loader": "^0.28.0",
33 | "eventsource-polyfill": "^0.9.6",
34 | "express": "^4.14.1",
35 | "extract-text-webpack-plugin": "^2.0.0",
36 | "file-loader": "^0.11.1",
37 | "friendly-errors-webpack-plugin": "^1.1.3",
38 | "html-webpack-plugin": "^2.28.0",
39 | "http-proxy-middleware": "^0.17.3",
40 | "webpack-bundle-analyzer": "^2.2.1",
41 | "semver": "^5.3.0",
42 | "shelljs": "^0.7.6",
43 | "opn": "^4.0.2",
44 | "optimize-css-assets-webpack-plugin": "^1.3.0",
45 | "ora": "^1.2.0",
46 | "rimraf": "^2.6.0",
47 | "url-loader": "^0.5.8",
48 | "vue-loader": "^11.3.4",
49 | "vue-style-loader": "^2.0.5",
50 | "vue-template-compiler": "^2.2.6",
51 | "webpack": "^2.3.3",
52 | "webpack-dev-middleware": "^1.10.0",
53 | "webpack-hot-middleware": "^2.18.0",
54 | "webpack-merge": "^4.1.0"
55 | },
56 | "engines": {
57 | "node": ">= 4.0.0",
58 | "npm": ">= 3.0.0"
59 | },
60 | "browserslist": [
61 | "> 1%",
62 | "last 2 versions",
63 | "not ie <= 8"
64 | ]
65 | }
66 |
--------------------------------------------------------------------------------
/src/components/Home.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
Home
5 |
6 |
7 | Cannot connect to API - is it running?
8 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
Active Jails
18 |
{{summary.jail_nums}}
19 |
Total number of active jails.
20 |
Show jails
21 |
22 |
23 |
24 |
25 |
26 |
27 |
Current bans
28 |
{{summary.total_bans_current}}
29 |
Currently banned IPs.
30 |
Manage bans
31 |
32 |
33 |
34 |
35 |
36 |
37 |
Total bans
38 |
{{summary.total_bans_total}}
39 |
Total amount of bans.
40 |
Show bans
41 |
42 |
43 |
44 |
45 |
46 |
78 |
--------------------------------------------------------------------------------
/src/components/Jails.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
Jails
5 |
6 |
7 | Cannot connect to API - is it running?
8 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
{{jail.jail_name}}
18 |
19 |
{{jail.log_file}}
20 |
21 |
22 |
23 |
Current bans: {{jail.bans_current}}
24 |
25 |
26 |
Total bans: {{jail.bans_total}}
27 |
28 |
29 |
Current fails: {{jail.fails_current}}
30 |
31 |
32 |
Total fails: {{jail.fails_total}}
33 |
34 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
80 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | api/data/*.txt
2 | node_modules/
3 | npm-debug.log
4 | # Byte-compiled / optimized / DLL files
5 | __pycache__/
6 | *.py[cod]
7 | *$py.class
8 |
9 | # C extensions
10 | *.so
11 |
12 | # Distribution / packaging
13 | .Python
14 | develop-eggs/
15 | dist/
16 | downloads/
17 | eggs/
18 | .eggs/
19 | lib/
20 | lib64/
21 | parts/
22 | sdist/
23 | var/
24 | wheels/
25 | pip-wheel-metadata/
26 | share/python-wheels/
27 | *.egg-info/
28 | .installed.cfg
29 | *.egg
30 | MANIFEST
31 |
32 | # PyInstaller
33 | # Usually these files are written by a python script from a template
34 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
35 | *.manifest
36 | *.spec
37 |
38 | # Installer logs
39 | pip-log.txt
40 | pip-delete-this-directory.txt
41 |
42 | # Unit test / coverage reports
43 | htmlcov/
44 | .tox/
45 | .nox/
46 | .coverage
47 | .coverage.*
48 | .cache
49 | nosetests.xml
50 | coverage.xml
51 | *.cover
52 | *.py,cover
53 | .hypothesis/
54 | .pytest_cache/
55 | cover/
56 |
57 | # Translations
58 | *.mo
59 | *.pot
60 |
61 | # Django stuff:
62 | *.log
63 | local_settings.py
64 | db.sqlite3
65 | db.sqlite3-journal
66 |
67 | # Flask stuff:
68 | instance/
69 | .webassets-cache
70 |
71 | # Scrapy stuff:
72 | .scrapy
73 |
74 | # Sphinx documentation
75 | docs/_build/
76 |
77 | # PyBuilder
78 | target/
79 |
80 | # Jupyter Notebook
81 | .ipynb_checkpoints
82 |
83 | # IPython
84 | profile_default/
85 | ipython_config.py
86 |
87 | # pyenv
88 | # For a library or package, you might want to ignore these files since the code is
89 | # intended to run in multiple environments; otherwise, check them in:
90 | # .python-version
91 |
92 | # pipenv
93 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
94 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
95 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
96 | # install all needed dependencies.
97 | #Pipfile.lock
98 |
99 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow
100 | __pypackages__/
101 |
102 | # Celery stuff
103 | celerybeat-schedule
104 | celerybeat.pid
105 |
106 | # SageMath parsed files
107 | *.sage.py
108 |
109 | # Environments
110 | .env
111 | .venv
112 | env/
113 | venv/
114 | ENV/
115 | env.bak/
116 | venv.bak/
117 |
118 | # Spyder project settings
119 | .spyderproject
120 | .spyproject
121 |
122 | # Rope project settings
123 | .ropeproject
124 |
125 | # mkdocs documentation
126 | /site
127 |
128 | # mypy
129 | .mypy_cache/
130 | .dmypy.json
131 | dmypy.json
132 |
133 | # Pyre type checker
134 | .pyre/
135 |
136 | # pytype static type analyzer
137 | .pytype/
138 | node_modules
139 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | fail2ban-fastapi
2 | ----------
3 |
4 | Fail2Ban operates by monitoring log files (e.g. `/var/log/auth.log`, `/var/log/apache/access.log`, etc.) for selected entries and running scripts based on them. Most commonly this is used to block selected IP addresses that may belong to hosts that are trying to breach the system's security.
5 |
6 | **What is fail2ban-fastapi?**
7 | Frontend (vuejs) and backend (fastapi). FastAPI reads it's data from files created by this script (since Fail2ban's internal sqlite database is not human readable). The script user must have permissions to execute `$ fail2ban-client` to generate this data.
8 | ```
9 | .
10 | ├── api
11 | │ └── data/
12 | │ └── jails.txt
13 | │ └── jail_.txt
14 | │ └── jail_.txt
15 | ```
16 |
17 | 
18 |
19 | ## Installation
20 |
21 | ### Fail2ban Setup
22 |
23 | First of all, the script needs to be able to run `fail2ban-client` command. This is usually done with root permissions. To solve this, you need to create a new (non-root) user and run fail2ban as this user.
24 |
25 | ```bash
26 | $ sudo apt install fail2ban
27 | $ sudo adduser fail2ban
28 | ```
29 |
30 | Set `User` to "fail2ban" in the [Service] section in `/lib/systemd/system/fail2ban.service`
31 | ```text
32 | ...
33 | [Service]
34 | User=fail2ban
35 | ...
36 | ```
37 |
38 | Change permissions of `/var/run/fail2ban`.
39 | ```bash
40 | $ sudo chown -R fail2ban:root /var/run/fail2ban
41 | ```
42 |
43 | Verify permissions with `sudo ls -la /var/run/fail2ban/`. Make sure fail2ban user can read and write to this location.
44 |
45 | Depending on your jails, the fail2ban user needs to be able read your logfiles (ex. `/var/log/auth.log`). An example configuration can be found in [jail.local.sample](./jail.local.sample).
46 |
47 | So change permisions of your logfiles.
48 | ```bash
49 | $ sudo chown fail2ban:root /var/log/auth.log
50 | ```
51 |
52 | Now you should be all set to reload `systemctl daemon` and restart fail2ban.
53 |
54 | ```bash
55 | $ sudo systemctl daemon-reload
56 | $ sudo systemctl restart fail2ban.service
57 | ```
58 |
59 | Check status of fail2ban.service to make sure we're all set and you have no errors.
60 |
61 | ## Install Fail2ban-FastAPI
62 |
63 | Clone rep, create virtualenv and install requirements.
64 | ```bash
65 | $ git clone git@github.com:dunderrrrrr/fail2ban-fastapi.git
66 | $ mkvirtualenv --python=/usr/bin/python3 fail2ban-fastapi
67 | $ pip install -r requirements.txt
68 | ```
69 |
70 | Before starting FastAPI backend we'll need to generate some Fail2ban data. This will only be necessary once when setting up Fail2ban-FastAPI for the first time on.
71 | ```bash
72 | $ cd api/
73 | $ python first_init.py
74 | ```
75 |
76 | Start FastAPI backend.
77 | ```bash
78 | $ python main.py
79 | ```
80 |
81 | Start vuejs frontend.
82 | ```bash
83 | $ npm install
84 | $ npm run dev
85 | ```
86 |
87 | FastAPI backend can be access at `http://localhost:8000`.
88 | Frontend access at `http://localhost:8080`.
--------------------------------------------------------------------------------
/api/_defs.py:
--------------------------------------------------------------------------------
1 | import re
2 |
3 | data_path = 'data/'
4 | data_format = '.txt'
5 | files = {
6 | "jails": "{}jails{}".format(data_path, data_format)
7 | }
8 |
9 | def get_jaildata(jail, jail_path):
10 | data = {}
11 | f = open(jail_path, "r")
12 | l = []
13 | for line in f:
14 | l.append(line)
15 | data['fail_current'] = re.findall(r'\d+', l[2])[0]
16 | data['fail_total'] = re.findall(r'\d+', l[3])[0]
17 | data['bans_current'] = re.findall(r'\d+', l[6])[0]
18 | data['bans_total'] = re.findall(r'\d+', l[7])[0]
19 | data['log_file'] = l[4].split(':')[1].strip()
20 | data['bans_iplist'] = l[8].split(':')[1].strip().split(' ')
21 | return(data)
22 |
23 | def summary(obj_jails, jailnums):
24 | tot_bans_current = []
25 | tot_bans_total = []
26 | for k,v in obj_jails['jail'].items():
27 | tot_bans_current.append(int(v['bans_current']))
28 | tot_bans_total.append(int(v['bans_total']))
29 | obj_jails['sum'] = {}
30 | obj_jails['sum']['jail_nums'] = int(jailnums)
31 | obj_jails['sum']['total_bans_current'] = sum(tot_bans_current)
32 | obj_jails['sum']['total_bans_total'] = sum(tot_bans_total)
33 | return(obj_jails)
34 |
35 | def main():
36 | obj_jails = {}
37 | f = open(files['jails'], "r")
38 | l = []
39 | for line in f:
40 | l.append(line)
41 | jailnums = re.findall(r'\d+', l[1])[0]
42 | jail_names = l[2].split(':')[1].strip()
43 | obj_jails['jail'] = {}
44 | for jail in jail_names.split(', '):
45 | jail_path = data_path + 'jail_' + jail + data_format
46 | jail_data = get_jaildata(jail, jail_path)
47 | obj_jails['jail'][jail] = {
48 | "jail_name": jail,
49 | "fails_current": jail_data['fail_current'],
50 | "fails_total": jail_data['fail_total'],
51 | "bans_current": jail_data['bans_current'],
52 | "bans_total": jail_data['bans_total'],
53 | "log_file": jail_data['log_file'],
54 | "bans_iplist": jail_data['bans_iplist']
55 | }
56 | data = summary(obj_jails, jailnums)
57 | return(data)
58 |
59 | def get_jail(jail):
60 | f = open(files['jails'], "r")
61 | l = []
62 | for line in f:
63 | l.append(line)
64 | jail_names = l[2].split(':')[1].strip().split(', ')
65 | if jail in jail_names:
66 | obj_jail = {
67 | jail: {}
68 | }
69 | jail_path = data_path + 'jail_' + jail + data_format
70 | jail_data = get_jaildata(jail, jail_path)
71 | obj_jail[jail] = {
72 | "fails_current": jail_data['fail_current'],
73 | "fails_total": jail_data['fail_total'],
74 | "bans_current": jail_data['bans_current'],
75 | "bans_total": jail_data['bans_total'],
76 | "log_file": jail_data['log_file'],
77 | "bans_iplist": jail_data['bans_iplist']
78 | }
79 | return(obj_jail)
80 | else:
81 | return {"error": 404, "msg": "Jail name '{}' not found".format(jail)}
--------------------------------------------------------------------------------
/static/main.css:
--------------------------------------------------------------------------------
1 | @import "https://fonts.googleapis.com/css?family=Poppins:300,400,500,600,700";
2 | body {
3 | font-family: 'Poppins', sans-serif;
4 | background: #fafafa;
5 | }
6 |
7 | p {
8 | font-family: 'Poppins', sans-serif;
9 | font-size: 1.1em;
10 | font-weight: 300;
11 | line-height: 1.7em;
12 | color: #999;
13 | }
14 |
15 | a,
16 | a:hover,
17 | a:focus {
18 | color: inherit;
19 | text-decoration: none;
20 | transition: all 0.3s;
21 | }
22 |
23 | .navbar {
24 | padding: 15px 10px;
25 | background: #fff;
26 | border: none;
27 | border-radius: 0;
28 | margin-bottom: 40px;
29 | box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.1);
30 | }
31 |
32 | .navbar-btn {
33 | box-shadow: none;
34 | outline: none !important;
35 | border: none;
36 | }
37 |
38 | .line {
39 | width: 100%;
40 | height: 1px;
41 | border-bottom: 1px dashed #ddd;
42 | margin: 40px 0;
43 | }
44 |
45 | .wrapper {
46 | display: flex;
47 | width: 100%;
48 | align-items: stretch;
49 | }
50 |
51 | #sidebar {
52 | min-width: 250px;
53 | max-width: 250px;
54 | background: #7386D5;
55 | color: #fff;
56 | transition: all 0.3s;
57 | }
58 |
59 | #sidebar.active {
60 | margin-left: -250px;
61 | }
62 |
63 | #sidebar .sidebar-header {
64 | padding: 20px;
65 | background: #6d7fcc;
66 | }
67 |
68 | #sidebar ul.components {
69 | padding: 20px 0;
70 | border-bottom: 1px solid #47748b;
71 | }
72 |
73 | #sidebar ul p {
74 | color: #fff;
75 | padding: 10px;
76 | }
77 |
78 | #sidebar ul li a {
79 | padding: 10px;
80 | font-size: 1.1em;
81 | display: block;
82 | }
83 |
84 | #sidebar ul li a:hover {
85 | color: #7386D5;
86 | background: #fff;
87 | }
88 |
89 | #sidebar ul li.active>a,
90 | a[aria-expanded="true"] {
91 | color: #fff;
92 | background: #6d7fcc;
93 | }
94 |
95 | a[data-toggle="collapse"] {
96 | position: relative;
97 | }
98 |
99 | .dropdown-toggle::after {
100 | display: block;
101 | position: absolute;
102 | top: 50%;
103 | right: 20px;
104 | transform: translateY(-50%);
105 | }
106 |
107 | ul ul a {
108 | font-size: 0.9em !important;
109 | padding-left: 30px !important;
110 | background: #6d7fcc;
111 | }
112 |
113 | ul.CTAs {
114 | padding: 20px;
115 | }
116 |
117 | ul.CTAs a {
118 | text-align: center;
119 | font-size: 0.9em !important;
120 | display: block;
121 | border-radius: 5px;
122 | margin-bottom: 5px;
123 | }
124 |
125 | a.download {
126 | background: #fff;
127 | color: #7386D5;
128 | }
129 |
130 | a.article,
131 | a.article:hover {
132 | background: #6d7fcc !important;
133 | color: #fff !important;
134 | }
135 |
136 | #content {
137 | width: 100%;
138 | padding: 20px;
139 | min-height: 100vh;
140 | transition: all 0.3s;
141 | }
142 |
143 | .delObjects {
144 | float:left;
145 | border:1px solid #CCC;
146 | }
147 | .delObjects:hover {
148 | background-color:#FFF;
149 | border:1px solid #999;
150 |
151 | }
152 | .logPath {
153 | font-size:12px;
154 | }
155 | .clearBoth {
156 | clear:both;
157 | }
158 | @media (max-width: 768px) {
159 | #sidebar {
160 | margin-left: -250px;
161 | }
162 | #sidebar.active {
163 | margin-left: 0;
164 | }
165 | #sidebarCollapse span {
166 | display: none;
167 | }
168 | }
--------------------------------------------------------------------------------
/src/components/Jail.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
Jail [{{jail_name}}]
5 |
6 |
7 | Cannot connect to API - is it running?
8 |
11 |
12 |
13 |
14 |
15 |
{{data.log_file}}
16 |
17 |
18 |
19 |
20 |
21 |
22 |
Current bans
23 | {{data.bans_current}}
24 |
25 |
26 |
27 |
28 |
29 |
30 |
Total bans
31 | {{data.bans_total}}
32 |
33 |
34 |
35 |
36 |
37 |
38 |
Current fails
39 | {{data.fails_current}}
40 |
41 |
42 |
43 |
44 |
45 |
46 |
Total fails
47 | {{data.fails_total}}
48 |
49 |
50 |
51 |
52 |
Banned IPs
53 |
54 |
55 |
60 |
61 |
62 |
Ban IP
63 |
64 |
68 |
69 |
70 |
71 |
--------------------------------------------------------------------------------