refactor: overhaul daemon server, client, and handlers
This commit is contained in:
+43
-18
@@ -8,6 +8,20 @@ from typing import Any
|
||||
|
||||
from jinja2 import Environment, FileSystemLoader
|
||||
|
||||
from daemon.iface import (
|
||||
DELETE_NGINX_DOMAINS_REMOVE,
|
||||
GET_NGINX_CONFIG,
|
||||
GET_NGINX_DOMAINS,
|
||||
PATCH_NGINX_CONFIG,
|
||||
POST_NGINX_APPLY,
|
||||
POST_NGINX_CONFIG,
|
||||
POST_NGINX_DOMAINS_ADD,
|
||||
POST_NGINX_DOMAINS_UPDATE,
|
||||
POST_NGINX_MANAGEMENT,
|
||||
POST_NGINX_RELOAD,
|
||||
POST_NGINX_SSL_APPLY,
|
||||
POST_NGINX_TEST,
|
||||
)
|
||||
from daemon.server import NotFoundError, refresh_state, registry
|
||||
from lib.common import ensure_dirs, load_json, run, run_proc, save_json
|
||||
|
||||
@@ -125,7 +139,7 @@ def _write_include_file() -> None:
|
||||
"""Write the system include file that references all per-site configs."""
|
||||
tmpl = ENV.get_template("nginx/include.conf")
|
||||
content = tmpl.render(sites_glob=str(SITES_DIR / "*.conf"))
|
||||
tmp = INCLUDE_FILE.with_suffix(".tmp")
|
||||
tmp = Path("/tmp") / "vacuum-wall-include.tmp"
|
||||
with open(tmp, "w") as f:
|
||||
f.write(content)
|
||||
os.chmod(tmp, 0o644)
|
||||
@@ -143,7 +157,7 @@ def _write_ssl_snippet() -> None:
|
||||
ssl_cfg.setdefault("ciphers", DEFAULT_SSL["ciphers"])
|
||||
tmpl = ENV.get_template("nginx/ssl_snippet.conf")
|
||||
content = tmpl.render(ssl=ssl_cfg)
|
||||
tmp = SSL_SNIPPET.with_suffix(".tmp")
|
||||
tmp = Path("/tmp") / "vacuum-wall-ssl-snippet.tmp"
|
||||
with open(tmp, "w") as f:
|
||||
f.write(content)
|
||||
os.chmod(tmp, 0o644)
|
||||
@@ -225,6 +239,20 @@ def _write_all_sites() -> None:
|
||||
os.replace(tmp, site)
|
||||
|
||||
|
||||
def _hash_password(password: str) -> str:
|
||||
"""Hash *password* using SHA-256 crypt via passlib.
|
||||
|
||||
Args:
|
||||
password: Plain-text password to hash.
|
||||
|
||||
Returns:
|
||||
The hashed password string suitable for ``.htpasswd``.
|
||||
"""
|
||||
from passlib.hash import sha256_crypt
|
||||
|
||||
return sha256_crypt.hash(password)
|
||||
|
||||
|
||||
def _write_htpasswd(user: str, password: str) -> None:
|
||||
"""Add or update a user entry in the .htpasswd file using SHA-256 hashing.
|
||||
|
||||
@@ -233,10 +261,7 @@ def _write_htpasswd(user: str, password: str) -> None:
|
||||
password: Plain-text password to hash.
|
||||
"""
|
||||
ensure_dirs(DATA_DIR)
|
||||
import crypt
|
||||
|
||||
salt = os.urandom(16).hex()[:16]
|
||||
hashed = crypt.crypt(password, f"$5${salt}")
|
||||
hashed = _hash_password(password)
|
||||
existing: dict[str, str] = {}
|
||||
if HTPASSWD_FILE.exists():
|
||||
with open(HTPASSWD_FILE) as f:
|
||||
@@ -268,7 +293,7 @@ def _get_nginx_state() -> dict[str, Any]:
|
||||
# Routes
|
||||
|
||||
|
||||
@registry.register("GET", "/nginx/config")
|
||||
@registry.register(GET_NGINX_CONFIG)
|
||||
def get_config(_request: Any, _body: Any) -> dict[str, Any]:
|
||||
"""GET /nginx/config — return current nginx config.
|
||||
|
||||
@@ -281,7 +306,7 @@ def get_config(_request: Any, _body: Any) -> dict[str, Any]:
|
||||
return _get_config()
|
||||
|
||||
|
||||
@registry.register("POST", "/nginx/config")
|
||||
@registry.register(POST_NGINX_CONFIG)
|
||||
def save_config_handler(_request: Any, body: dict[str, Any] | None) -> dict[str, Any]:
|
||||
"""POST /nginx/config — replace the entire nginx config and refresh state.
|
||||
|
||||
@@ -295,7 +320,7 @@ def save_config_handler(_request: Any, body: dict[str, Any] | None) -> dict[str,
|
||||
return {"config_saved": True}
|
||||
|
||||
|
||||
@registry.register("PATCH", "/nginx/config")
|
||||
@registry.register(PATCH_NGINX_CONFIG)
|
||||
def patch_config(_request: Any, body: dict[str, Any] | None) -> dict[str, Any]:
|
||||
"""PATCH /nginx/config — deep-merge partial updates into current config.
|
||||
|
||||
@@ -313,7 +338,7 @@ def patch_config(_request: Any, body: dict[str, Any] | None) -> dict[str, Any]:
|
||||
return {"config_saved": True}
|
||||
|
||||
|
||||
@registry.register("GET", "/nginx/domains")
|
||||
@registry.register(GET_NGINX_DOMAINS)
|
||||
def get_domains(_request: Any, _body: Any) -> list[dict[str, Any]]:
|
||||
"""GET /nginx/domains — return the list of configured proxy domains.
|
||||
|
||||
@@ -326,7 +351,7 @@ def get_domains(_request: Any, _body: Any) -> list[dict[str, Any]]:
|
||||
return []
|
||||
|
||||
|
||||
@registry.register("POST", "/nginx/domains/add")
|
||||
@registry.register(POST_NGINX_DOMAINS_ADD)
|
||||
def add_domain(_request: Any, body: dict[str, Any] | None) -> dict[str, Any]:
|
||||
"""POST /nginx/domains/add — add a new reverse-proxy domain entry.
|
||||
|
||||
@@ -369,7 +394,7 @@ def add_domain(_request: Any, body: dict[str, Any] | None) -> dict[str, Any]:
|
||||
return {"domain": domain}
|
||||
|
||||
|
||||
@registry.register("DELETE", "/nginx/domains/remove")
|
||||
@registry.register(DELETE_NGINX_DOMAINS_REMOVE)
|
||||
def remove_domain(_request: Any, body: dict[str, Any] | None) -> dict[str, Any]:
|
||||
"""DELETE /nginx/domains/remove — remove a domain from the proxy config.
|
||||
|
||||
@@ -394,7 +419,7 @@ def remove_domain(_request: Any, body: dict[str, Any] | None) -> dict[str, Any]:
|
||||
return {"domain": domain}
|
||||
|
||||
|
||||
@registry.register("POST", "/nginx/domains/update")
|
||||
@registry.register(POST_NGINX_DOMAINS_UPDATE)
|
||||
def update_domain(_request: Any, body: dict[str, Any] | None) -> dict[str, Any]:
|
||||
"""POST /nginx/domains/update — patch fields of an existing domain entry.
|
||||
|
||||
@@ -422,7 +447,7 @@ def update_domain(_request: Any, body: dict[str, Any] | None) -> dict[str, Any]:
|
||||
return {"domain": domain}
|
||||
|
||||
|
||||
@registry.register("POST", "/nginx/apply")
|
||||
@registry.register(POST_NGINX_APPLY)
|
||||
def apply(_request: Any, _body: Any) -> dict[str, Any]:
|
||||
"""POST /nginx/apply — render all configs, test, and reload nginx.
|
||||
|
||||
@@ -440,7 +465,7 @@ def apply(_request: Any, _body: Any) -> dict[str, Any]:
|
||||
return {"applied": True}
|
||||
|
||||
|
||||
@registry.register("POST", "/nginx/test")
|
||||
@registry.register(POST_NGINX_TEST)
|
||||
def test(_request: Any, _body: Any) -> dict[str, Any]:
|
||||
"""POST /nginx/test — dry-run validate the live nginx config without applying.
|
||||
|
||||
@@ -451,7 +476,7 @@ def test(_request: Any, _body: Any) -> dict[str, Any]:
|
||||
return {"valid": valid, "output": output}
|
||||
|
||||
|
||||
@registry.register("POST", "/nginx/ssl-apply")
|
||||
@registry.register(POST_NGINX_SSL_APPLY)
|
||||
def ssl_apply(_request: Any, _body: Any) -> dict[str, Any]:
|
||||
"""POST /nginx/ssl-apply — re-render and install only the SSL snippet."""
|
||||
_write_ssl_snippet()
|
||||
@@ -459,7 +484,7 @@ def ssl_apply(_request: Any, _body: Any) -> dict[str, Any]:
|
||||
return {"applied": True}
|
||||
|
||||
|
||||
@registry.register("POST", "/nginx/management")
|
||||
@registry.register(POST_NGINX_MANAGEMENT)
|
||||
def set_management_proxy(_request: Any, body: dict[str, Any] | None) -> dict[str, Any]:
|
||||
"""POST /nginx/management — configure the management UI reverse proxy.
|
||||
|
||||
@@ -490,7 +515,7 @@ def set_management_proxy(_request: Any, body: dict[str, Any] | None) -> dict[str
|
||||
return {"domain": domain}
|
||||
|
||||
|
||||
@registry.register("POST", "/nginx/reload")
|
||||
@registry.register(POST_NGINX_RELOAD)
|
||||
def reload_nginx(_request: Any, _body: Any) -> dict[str, Any]:
|
||||
"""POST /nginx/reload — trigger an nginx reload (SIGHUP)."""
|
||||
_reload_nginx()
|
||||
|
||||
Reference in New Issue
Block a user