65 lines
1.9 KiB
Python
65 lines
1.9 KiB
Python
"""Flask web layer for the syscall monitor."""
|
|
|
|
import json
|
|
import threading
|
|
from pathlib import Path
|
|
|
|
from flask import Flask, jsonify, redirect, render_template, request, url_for
|
|
|
|
from collector.syscall_tracer import get_tracer
|
|
|
|
|
|
BASE_DIR = Path(__file__).resolve().parent.parent
|
|
CONFIG_PATH = BASE_DIR / "config" / "monitors.json"
|
|
_config_lock = threading.Lock()
|
|
|
|
|
|
def _read_config() -> dict:
|
|
if not CONFIG_PATH.exists():
|
|
return {"syscalls": []}
|
|
with CONFIG_PATH.open("r", encoding="utf-8") as f:
|
|
return json.load(f)
|
|
|
|
|
|
def _write_config(data: dict) -> None:
|
|
CONFIG_PATH.parent.mkdir(parents=True, exist_ok=True)
|
|
tmp = CONFIG_PATH.with_suffix(".json.tmp")
|
|
with tmp.open("w", encoding="utf-8") as f:
|
|
json.dump(data, f, indent=2, ensure_ascii=False)
|
|
tmp.replace(CONFIG_PATH)
|
|
|
|
|
|
def create_app() -> Flask:
|
|
app = Flask(__name__, template_folder="templates", static_folder="static")
|
|
tracer = get_tracer(CONFIG_PATH)
|
|
|
|
@app.get("/")
|
|
def index():
|
|
cfg = _read_config()
|
|
return render_template("index.html", syscalls=cfg.get("syscalls", []))
|
|
|
|
@app.get("/api/counts")
|
|
def api_counts():
|
|
return jsonify(tracer.get_counts())
|
|
|
|
@app.route("/config", methods=["GET", "POST"])
|
|
def config_page():
|
|
with _config_lock:
|
|
cfg = _read_config()
|
|
syscalls = list(cfg.get("syscalls", []))
|
|
|
|
if request.method == "POST":
|
|
action = request.form.get("action", "")
|
|
name = (request.form.get("name") or "").strip()
|
|
if action == "add" and name and name not in syscalls:
|
|
syscalls.append(name)
|
|
elif action == "remove" and name in syscalls:
|
|
syscalls.remove(name)
|
|
cfg["syscalls"] = syscalls
|
|
_write_config(cfg)
|
|
return redirect(url_for("config_page"))
|
|
|
|
return render_template("config.html", syscalls=syscalls)
|
|
|
|
return app
|