refactor: unify project structure, improve security, and enhance deployment

- Fix WireGuard private key leak in API responses and config updates
- Update systemd service to serve from repo root with adjusted sandbox
- Add CLI flags, idempotency, and dev mode to install.sh
- Extract common utilities to lib/common.py and webui/api/common.py
- Migrate frontend to htmx for simpler, more maintainable UI
- Update docs to reflect current architecture and deployment model
- Vendor htmx dependencies per project requirements
This commit is contained in:
2026-05-25 00:53:32 +00:00
parent 8829ac579d
commit d1ab717c0f
36 changed files with 857 additions and 626 deletions
+7 -27
View File
@@ -6,8 +6,9 @@ Exposed at /api/dhcp/* and delegates all operations to lib.dnsmasq.
import logging
from flask import Blueprint, jsonify, request
from flask import Blueprint, request
from lib.common import deep_merge
from lib.dnsmasq import (
add_dns_record,
add_static_lease,
@@ -20,34 +21,15 @@ from lib.dnsmasq import (
save_config,
set_dhcp_range,
)
from lib.dnsmasq import (
get_status as dnsmasq_status,
)
from webui.api.common import _error, _ok
logger = logging.getLogger(__name__)
bp = Blueprint("dhcp", __name__)
# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------
def _error(msg, code=400):
return jsonify({"ok": False, "error": msg}), code
def _ok(data=None):
return jsonify({"ok": True, "data": data})
def _deep_merge(base, overrides):
result = dict(base)
for k, v in overrides.items():
if k in result and isinstance(result[k], dict) and isinstance(v, dict):
result[k] = _deep_merge(result[k], v)
else:
result[k] = v
return result
# ---------------------------------------------------------------------------
# Config
# ---------------------------------------------------------------------------
@@ -82,7 +64,7 @@ def patch_config():
return _error("Request body must be a JSON object", 400)
try:
current = get_config()
merged = _deep_merge(current, body)
merged = deep_merge(current, body)
save_config(merged)
return _ok(None)
except RuntimeError as exc:
@@ -109,8 +91,6 @@ def apply_bp():
@bp.route("/status", methods=["GET"])
def status_bp():
try:
from lib.dnsmasq import get_status as dnsmasq_status
return _ok(dnsmasq_status())
except RuntimeError as exc:
logger.error("Failed to get DHCP status: %s", exc)