0ed275835d
Refresh/logout and token robustness - drop the post-rotation refresh_tokens row delete in auth_refresh so logout blacklists the current (rotated) refresh token; remove the dead _clear_refresh_token_after_rotation helper and clear_active_refresh_token - reject non-object JWT payloads in _extract_unverified_sub so crafted Authorization headers return 401 instead of crashing with 500 SQLite user store - make builtin-admin seeding idempotent: on a concurrent first start the losing seeder re-checks, finds the winner, and returns instead of raising IntegrityError - per-thread sqlite connections + busy_timeout so Flask worker threads don't hit cross-thread ProgrammingError / SQLITE_BUSY - add LogsDirectory + /var/log/vacuum-wall to ReadWritePaths in both systemd units so the fallback admin password actually lands on disk Frontend - skip apiFetch 401-recovery for public auth endpoints so a failed login no longer logs out a valid session - add /passkeys to the nav (passkey registration was unreachable); remove the dead checkWebAuthnCapable export - drop the CSP-blocked inline WS-URL script and the __WS_URL_PLACEHOLDER__ plumbing; the WS URL is derived from location Daemon / WS - parse Sec-WebSocket-Protocol manually (web.Request.get_subprotocols does not exist in aiohttp 3.13); X-Auth-Token is a custom-nginx fallback only — docstring and security docs corrected Install / system - bootstrap_auth.py is now idempotent: preserves existing auth config and syncs the admin password on re-runs (new reset_password helper) - WebUI server block renders auth_basic off (the UI is JWT-protected) - install.sh chown/chmod skips .git to avoid git dubious-ownership breakage - tolerate unreadable /etc/wireguard during system import Contracts / docs - create_user returns 409 on duplicate username per docs/api.md - correct docs/api.md response shapes, docs/security.md blacklist cleanup wording + one-refresh-per-user caveat, stale WS-URL references, and the .htpasswd description Tests: +7 regression tests (rotation/logout revocation, crafted-token 401, concurrent seeding); placeholder-substitution tests replaced with serve-as-is SPA root tests.
46 lines
1.2 KiB
Desktop File
46 lines
1.2 KiB
Desktop File
[Unit]
|
|
Description=Vacuum Wall Management WebUI
|
|
Documentation=https://github.com/wall/vacuum-wall
|
|
Requires=vacuum-walld.service
|
|
After=network.target firewalld.service nginx.service dnsmasq.service vacuum-walld.service
|
|
Wants=firewalld.service
|
|
|
|
[Service]
|
|
Type=simple
|
|
User={{ USER_NAME }}
|
|
Group={{ USER_GROUP }}
|
|
WorkingDirectory={{ PROJECT_DIR }}
|
|
ExecStart={{ PROJECT_DIR }}/.venv/bin/python webui/server.py
|
|
ExecReload=/bin/kill -HUP $MAINPID
|
|
Restart=always
|
|
RestartSec=2
|
|
Environment=PATH=/usr/local/bin:/usr/bin
|
|
Environment=PYTHONUNBUFFERED=1
|
|
Environment=ACME_HOME={{ PROJECT_DIR }}/data/acme
|
|
Environment=HOME={{ PROJECT_DIR }}
|
|
|
|
# Security hardening
|
|
NoNewPrivileges=yes
|
|
ProtectSystem=strict
|
|
ReadWritePaths={{ PROJECT_DIR }} {{ PROJECT_DIR }}/config {{ PROJECT_DIR }}/data /tmp /var/log/vacuum-wall
|
|
LogsDirectory=vacuum-wall
|
|
PrivateTmp=yes
|
|
ProtectKernelTunables=yes
|
|
ProtectKernelModules=yes
|
|
ProtectControlGroups=yes
|
|
ProtectHostname=yes
|
|
RestrictSUIDSGID=yes
|
|
MemoryDenyWriteExecute=yes
|
|
RestrictRealtime=yes
|
|
RestrictNamespaces=yes
|
|
LockPersonality=yes
|
|
SystemCallFilter=@system-service
|
|
PrivateDevices=yes
|
|
|
|
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
|
|
IPAddressDeny=any
|
|
IPAddressAllow=localhost
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|