mirror of
https://github.com/bunkerity/bunkerweb
synced 2026-05-24 09:28:37 +00:00
Add Redis support for bans page in web UI
This commit is contained in:
parent
43cdf98d5a
commit
7b0e986d4a
1 changed files with 103 additions and 2 deletions
105
src/ui/main.py
105
src/ui/main.py
|
|
@ -31,6 +31,7 @@ from jinja2 import Template
|
|||
from kubernetes import client as kube_client
|
||||
from kubernetes import config as kube_config
|
||||
from kubernetes.client.exceptions import ApiException as kube_ApiException
|
||||
from redis import Redis, Sentinel
|
||||
from regex import compile as re_compile, match as regex_match
|
||||
from requests import get
|
||||
from shutil import move, rmtree
|
||||
|
|
@ -1665,6 +1666,76 @@ def reports():
|
|||
@app.route("/bans", methods=["GET", "POST"])
|
||||
@login_required
|
||||
def bans():
|
||||
redis_client = None
|
||||
db_config = app.config["CONFIG"].get_config(methods=False)
|
||||
use_redis = db_config.get("USE_REDIS", "no") == "yes"
|
||||
redis_host = db_config.get("REDIS_HOST")
|
||||
if use_redis and redis_host:
|
||||
redis_port = db_config.get("REDIS_PORT", "6379")
|
||||
if not redis_port.isdigit():
|
||||
redis_port = "6379"
|
||||
redis_port = int(redis_port)
|
||||
|
||||
redis_db = db_config.get("REDIS_DB", "0")
|
||||
if not redis_db.isdigit():
|
||||
redis_db = "0"
|
||||
redis_db = int(redis_db)
|
||||
|
||||
redis_timeout = db_config.get("REDIS_TIMEOUT", "1000.0")
|
||||
try:
|
||||
redis_timeout = float(redis_timeout)
|
||||
except ValueError:
|
||||
redis_timeout = 1000.0
|
||||
|
||||
redis_keepalive_pool = db_config.get("REDIS_KEEPALIVE_POOL", "10")
|
||||
if not redis_keepalive_pool.isdigit():
|
||||
redis_keepalive_pool = "10"
|
||||
redis_keepalive_pool = int(redis_keepalive_pool)
|
||||
|
||||
redis_ssl = db_config.get("REDIS_SSL", "no") == "yes"
|
||||
username = db_config.get("REDIS_USERNAME", None) or None
|
||||
password = db_config.get("REDIS_PASSWORD", None) or None
|
||||
sentinel_hosts = db_config.get("REDIS_SENTINEL_HOSTS", [])
|
||||
|
||||
if isinstance(sentinel_hosts, str):
|
||||
sentinel_hosts = [host.split(":") if ":" in host else host for host in sentinel_hosts.split(" ") if host]
|
||||
|
||||
if sentinel_hosts:
|
||||
sentinel_username = db_config.get("REDIS_SENTINEL_USERNAME", None) or None
|
||||
sentinel_password = db_config.get("REDIS_SENTINEL_PASSWORD", None) or None
|
||||
sentinel_master = db_config.get("REDIS_SENTINEL_MASTER", "")
|
||||
|
||||
sentinel = Sentinel(
|
||||
sentinel_hosts,
|
||||
username=sentinel_username,
|
||||
password=sentinel_password,
|
||||
ssl=redis_ssl,
|
||||
socket_timeout=redis_timeout,
|
||||
socket_connect_timeout=redis_timeout,
|
||||
socket_keepalive=True,
|
||||
max_connections=redis_keepalive_pool,
|
||||
)
|
||||
redis_client = sentinel.slave_for(sentinel_master, db=redis_db, username=username, password=password)
|
||||
else:
|
||||
redis_client = Redis(
|
||||
host=redis_host,
|
||||
port=redis_port,
|
||||
db=redis_db,
|
||||
username=username,
|
||||
password=password,
|
||||
socket_timeout=redis_timeout,
|
||||
socket_connect_timeout=redis_timeout,
|
||||
socket_keepalive=True,
|
||||
max_connections=redis_keepalive_pool,
|
||||
ssl=redis_ssl,
|
||||
)
|
||||
|
||||
try:
|
||||
redis_client.ping()
|
||||
except BaseException:
|
||||
redis_client = None
|
||||
flash("Couldn't connect to redis, ban list might be incomplete", "error")
|
||||
|
||||
if request.method == "POST":
|
||||
# Check variables
|
||||
if not request.form:
|
||||
|
|
@ -1695,9 +1766,15 @@ def bans():
|
|||
flash(f"Invalid unban: {unban}, skipping it ...", "error")
|
||||
app.logger.exception(f"Couldn't unban {unban['ip']}")
|
||||
continue
|
||||
|
||||
if "ip" not in unban:
|
||||
flash(f"Invalid unban: {unban}, skipping it ...", "error")
|
||||
continue
|
||||
|
||||
if redis_client:
|
||||
if not redis_client.delete(f"bans_ip_{unban['ip']}"):
|
||||
flash(f"Couldn't unban {unban['ip']} on redis", "error")
|
||||
|
||||
resp = app.config["INSTANCES"].unban(unban["ip"])
|
||||
if resp:
|
||||
flash(f"Couldn't unban {unban['ip']} on the following instances: {', '.join(resp)}", "error")
|
||||
|
|
@ -1708,6 +1785,8 @@ def bans():
|
|||
if not isinstance(ban, dict) or "ip" not in ban:
|
||||
flash(f"Invalid ban: {ban}, skipping it ...", "error")
|
||||
continue
|
||||
|
||||
reason = ban.get("reason", "ui")
|
||||
ban_end = 86400.0
|
||||
if "ban_end" in ban:
|
||||
try:
|
||||
|
|
@ -1715,7 +1794,14 @@ def bans():
|
|||
except ValueError:
|
||||
continue
|
||||
ban_end = (datetime.fromtimestamp(ban_end) - datetime.now()).total_seconds()
|
||||
resp = app.config["INSTANCES"].ban(ban["ip"], ban_end, ban.get("reason", "ui"))
|
||||
|
||||
if redis_client:
|
||||
ok = redis_client.set(f"bans_ip_{ban['ip']}", dumps({"reason": reason, "date": time()}))
|
||||
if not ok:
|
||||
flash(f"Couldn't ban {ban['ip']} on redis", "error")
|
||||
redis_client.expire(f"bans_ip_{ban['ip']}", int(ban_end))
|
||||
|
||||
resp = app.config["INSTANCES"].ban(ban["ip"], ban_end, reason)
|
||||
if resp:
|
||||
flash(f"Couldn't ban {ban['ip']} on the following instances: {', '.join(resp)}", "error")
|
||||
else:
|
||||
|
|
@ -1726,12 +1812,27 @@ def bans():
|
|||
|
||||
return redirect(url_for("loading", next=url_for("bans"), message="Update bans"))
|
||||
|
||||
bans = app.config["INSTANCES"].get_bans()[:100]
|
||||
bans = []
|
||||
if redis_client:
|
||||
for key in redis_client.scan_iter("bans_ip_*"):
|
||||
ip = key.decode("utf-8").replace("bans_ip_", "")
|
||||
data = redis_client.get(key)
|
||||
if not data:
|
||||
continue
|
||||
exp = redis_client.ttl(key)
|
||||
bans.append({"ip": ip, "exp": exp} | json_loads(data)) # type: ignore
|
||||
instance_bans = app.config["INSTANCES"].get_bans()
|
||||
|
||||
# Prepare data
|
||||
reasons = {}
|
||||
timestamp_now = time()
|
||||
|
||||
for ban in instance_bans:
|
||||
if not any(b["ip"] == ban["ip"] for b in bans):
|
||||
bans.append(ban)
|
||||
|
||||
bans = bans[:100]
|
||||
|
||||
for ban in bans:
|
||||
exp = ban.pop("exp")
|
||||
# Add remain
|
||||
|
|
|
|||
Loading…
Reference in a new issue