#!/usr/bin/env python3
"""
SecuBox Control Panel - Grand-Mamy KISS Edition v4
FIXED: Reads service status from cache files (works inside LXC)
"""
import streamlit as st
import json
import time
from datetime import datetime
st.set_page_config(page_title="SecuBox Control", page_icon="🛡️", layout="wide", initial_sidebar_state="collapsed")
PRIORITY_LEVELS = {
0: ("DESACTIVE", "#404050"), 3: ("NORMAL", "#00d4aa"), 6: ("CRITIQUE", "#ffa500"),
7: ("URGENT", "#ff8c00"), 8: ("ALERTE", "#ff6b6b"), 9: ("DANGER", "#ff4d4d"), 10: ("PERMANENT", "#ff0000"),
}
st.markdown("""
""", unsafe_allow_html=True)
def read_cache(path):
try:
with open(path, "r") as f:
return json.load(f)
except:
return {}
def rgb_hex(r, g, b):
return f"#{r:02x}{g:02x}{b:02x}"
def badge(level):
name, color = PRIORITY_LEVELS.get(level, ("NORMAL", "#00d4aa"))
return f'{name}'
def progress(val):
pct = min(100, int(val))
c = "progress-green" if pct < 60 else "progress-yellow" if pct < 85 else "progress-red"
return f'
'
@st.cache_data(ttl=5)
def get_data():
d = {"time": datetime.now().strftime("%H:%M:%S"), "date": datetime.now().strftime("%d/%m/%Y")}
health = read_cache("/tmp/secubox/health.json")
threat = read_cache("/tmp/secubox/threat.json")
capacity = read_cache("/tmp/secubox/capacity.json")
status = read_cache("/tmp/secubox/health-status.json")
cs = read_cache("/tmp/secubox/crowdsec.json")
mitm = read_cache("/tmp/secubox/mitmproxy.json")
netif = read_cache("/tmp/secubox/netifyd.json")
waf = read_cache("/tmp/secubox/waf-stats.json")
cs_detail = read_cache("/tmp/secubox/crowdsec-overview.json")
modules = status.get("modules", {})
resources = status.get("resources", {})
d["score"] = health.get("score", 100)
d["svc_ok"] = modules.get("active", health.get("services_ok", 0))
d["svc_total"] = modules.get("enabled", health.get("services_total", 0))
d["threat"] = threat.get("level", 0)
d["cpu"] = capacity.get("cpu_pct", 0)
d["mem"] = resources.get("memory_percent", 50)
d["disk"] = resources.get("storage_percent", 0)
d["load"] = resources.get("cpu_load", "0")
d["haproxy"] = modules.get("active", 0) > 0
d["crowdsec"] = cs.get("running", 0) == 1
d["cs_alerts"] = cs.get("alerts", 0)
d["cs_bans"] = cs.get("bans", 0)
d["mitmproxy"] = mitm.get("running", 0) == 1
d["mitm_threats"] = mitm.get("threats_today", 0)
d["netifyd"] = netif.get("running", 0) == 1
# Enhanced WAF/threat stats
d["waf_threats"] = waf.get("threats_today", 0)
d["waf_autobans"] = waf.get("autobans_total", 0)
d["waf_pending"] = waf.get("autobans_pending", 0)
d["active_bans"] = cs_detail.get("active_bans", 0)
d["total_decisions"] = cs_detail.get("total_decisions", 0)
# DPI Dual-Stream stats
dpi_buffer = read_cache("/tmp/secubox/dpi-buffer.json")
dpi_flows = read_cache("/tmp/secubox/dpi-flows.json")
d["dpi_buffer_entries"] = dpi_buffer.get("entries", 0)
d["dpi_threats"] = dpi_buffer.get("threats_detected", 0)
d["dpi_blocked"] = dpi_buffer.get("blocked_count", 0)
d["dpi_flows"] = dpi_flows.get("flows_1min", 0)
d["dpi_rx"] = dpi_flows.get("rx_bytes", 0)
d["dpi_tx"] = dpi_flows.get("tx_bytes", 0)
d["p_haproxy"] = 3 if d["haproxy"] else 10
d["p_crowdsec"] = 3 if d["crowdsec"] and d["cs_alerts"] == 0 else 7 if d["cs_alerts"] > 0 else 10
d["p_mitmproxy"] = 3 if d["mitmproxy"] else 6
d["led1"] = rgb_hex(0, 255 if d["score"] > 50 else 0, 0) if d["score"] > 80 else rgb_hex(255, 165, 0) if d["score"] > 50 else rgb_hex(255, 0, 0)
d["led2"] = rgb_hex(0, 255, 0) if d["threat"] < 10 else rgb_hex(255, 165, 0) if d["threat"] < 50 else rgb_hex(255, 0, 0)
d["led3"] = rgb_hex(0, 255, 0) if d["cpu"] < 60 else rgb_hex(255, 165, 0) if d["cpu"] < 85 else rgb_hex(255, 0, 0)
# LED4: Bans indicator
d["led4"] = rgb_hex(255, 0, 0) if d["active_bans"] > 5 else rgb_hex(255, 165, 0) if d["active_bans"] > 0 else rgb_hex(0, 255, 0)
return d
def main():
d = get_data()
st.markdown('SecuBox Control Panel
', unsafe_allow_html=True)
st.markdown(f'💚 {d["time"]} - {d["date"]} 💚
', unsafe_allow_html=True)
st.markdown(f'''
Health
Score: {d['score']}
Threat
Level: {d['threat']}
🚫
Bans: {d['active_bans']}
''', unsafe_allow_html=True)
st.markdown('SERVICES
', unsafe_allow_html=True)
c1, c2, c3, c4 = st.columns(4)
with c1:
st.markdown(f'''
{'ON' if d['haproxy'] else 'OFF'}
Status
''', unsafe_allow_html=True)
with c2:
st.markdown(f'''
''', unsafe_allow_html=True)
with c3:
st.markdown(f'''
{d['waf_threats']}
Threats
{d['waf_autobans']}
AutoBans
''', unsafe_allow_html=True)
dpi_color = "#00d4aa" if d["dpi_buffer_entries"] > 0 else "#808090"
with c4:
st.markdown(f'''
{d['dpi_flows']}
Flows/min
{d['dpi_threats']}
Threats
{d['dpi_blocked']}
Blocked
''', unsafe_allow_html=True)
st.markdown('SYSTEM
', unsafe_allow_html=True)
c1, c2, c3, c4 = st.columns(4)
with c1:
st.markdown(f'{progress(d["cpu"])}
', unsafe_allow_html=True)
with c2:
st.markdown(f'{progress(d["mem"])}
', unsafe_allow_html=True)
with c3:
st.markdown(f'{progress(d["disk"])}
', unsafe_allow_html=True)
with c4:
st.markdown(f'''
{d['svc_ok']}/{d['svc_total']}
Running
''', unsafe_allow_html=True)
score_color = "#00d4aa" if d["score"] >= 80 else "#ffa500" if d["score"] >= 50 else "#ff4d4d"
st.markdown(f'''
{d['score']}
SECURITY SCORE
''', unsafe_allow_html=True)
time.sleep(10)
st.rerun()
if __name__ == "__main__":
main()