security+feat: v1.3.0 — pentest remediation, container reliability, UI overhaul

Security (33 pentest findings addressed):
- CRITICAL: backend binds 127.0.0.1, path traversal in tor.rs/dwn fixed
- HIGH: federation requires signatures, XSS login redirect, RBAC viewer restricted
- HIGH: tar slip prevention, S3 SSRF validation, backup ID validation
- MEDIUM: remember-me random secret, TOTP session rotation, password re-auth
- LOW: CSP unsafe-inline removed, CORS dev-only, onion/webhook validation

Container reliability:
- Memory limits on all 37 containers (OOM prevention)
- Exited vs stopped state distinction with health-aware status badges
- Crash recovery coordination (no more restart cascade)
- User-stopped tracking survives reboots
- Tiered boot recovery (databases → core → services → apps)

UI:
- Wallet TransactionsModal, health-aware app status badges
- Restart button on containers, exited/crashed red state
- Mesh view overhaul, glass button updates, BaseModal/ToggleSwitch
- Apps sticky header removed, dev faucet, mutable mock wallet

Infrastructure:
- LND REST port 8080 exposed over Tor (LND Connect fix)
- Nginx cookie_session fix, deploy script Tor config updated
- Dev environment: podman auto-start, boot mode simulation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-03-19 12:44:31 +00:00
parent d1b48388fb
commit 1a74a930f7
77 changed files with 2485 additions and 966 deletions

View File

@@ -773,6 +773,7 @@ HiddenServicePort 50001 127.0.0.1:50001
HiddenServiceDir $TOR_DIR/hidden_service_lnd
HiddenServicePort 9735 127.0.0.1:9735
HiddenServicePort 8080 127.0.0.1:8080
HiddenServiceDir $TOR_DIR/hidden_service_btcpay
HiddenServicePort 23000 127.0.0.1:23000

View File

@@ -17,7 +17,7 @@ server {
add_header Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=()" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-DNS-Prefetch-Control "off" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; font-src 'self' data:; connect-src 'self' ws: wss: http://$host:* https:; frame-src 'self' http://$host:* https:; frame-ancestors 'self'; base-uri 'self'; form-action 'self';" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; font-src 'self' data:; connect-src 'self' ws: wss: http://$host:* https:; frame-src 'self' http://$host:* https:; frame-ancestors 'self'; base-uri 'self'; form-action 'self';" always;
# AIUI SPA (Chat mode iframe)
# Use =404 fallback instead of index.html to prevent serving HTML with wrong
@@ -37,7 +37,7 @@ server {
# AIUI Claude API proxy — requires valid session cookie
location /aiui/api/claude/ {
if ($cookie_session_id = "") {
if ($cookie_session = "") {
return 401 '{"error":"Unauthorized"}';
}
proxy_pass http://127.0.0.1:3142/;
@@ -54,7 +54,7 @@ server {
# AIUI OpenRouter API proxy — requires valid session cookie
location /aiui/api/openrouter/ {
if ($cookie_session_id = "") {
if ($cookie_session = "") {
return 401 '{"error":"Unauthorized"}';
}
proxy_pass https://openrouter.ai/api/;
@@ -69,7 +69,7 @@ server {
# AIUI Ollama (local AI) proxy — localhost:11434
location /aiui/api/ollama/ {
if ($cookie_session_id = "") {
if ($cookie_session = "") {
return 401 '{"error":"Unauthorized"}';
}
proxy_pass http://127.0.0.1:11434/;
@@ -85,7 +85,7 @@ server {
# AIUI web search proxy — SearXNG on port 8888
location /aiui/api/web-search {
if ($cookie_session_id = "") {
if ($cookie_session = "") {
return 401 '{"error":"Unauthorized"}';
}
proxy_pass http://127.0.0.1:8888/search;
@@ -154,7 +154,7 @@ server {
location /lnd-connect-info {
# Requires authenticated session — exposes LND admin macaroon
if ($cookie_session_id = "") { return 401; }
if ($cookie_session = "") { return 401; }
proxy_pass http://127.0.0.1:5678/lnd-connect-info;
proxy_http_version 1.1;
proxy_set_header Host $host;
@@ -725,7 +725,7 @@ server {
add_header Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=()" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-DNS-Prefetch-Control "off" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; font-src 'self' data:; connect-src 'self' ws: wss: http://$host:* https:; frame-src 'self' http://$host:* https:; frame-ancestors 'self'; base-uri 'self'; form-action 'self';" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; font-src 'self' data:; connect-src 'self' ws: wss: http://$host:* https:; frame-src 'self' http://$host:* https:; frame-ancestors 'self'; base-uri 'self'; form-action 'self';" always;
# AIUI SPA (Chat mode iframe)
location /aiui/ {
@@ -735,7 +735,7 @@ server {
add_header Cache-Control "no-cache, no-store, must-revalidate";
}
location /aiui/api/claude/ {
if ($cookie_session_id = "") {
if ($cookie_session = "") {
return 401 '{"error":"Unauthorized"}';
}
proxy_pass http://127.0.0.1:3142/;
@@ -750,7 +750,7 @@ server {
proxy_send_timeout 120s;
}
location /aiui/api/ollama/ {
if ($cookie_session_id = "") {
if ($cookie_session = "") {
return 401 '{"error":"Unauthorized"}';
}
proxy_pass http://127.0.0.1:11434/;
@@ -764,7 +764,7 @@ server {
# Connection header managed by nginx default
}
location /aiui/api/openrouter/ {
if ($cookie_session_id = "") {
if ($cookie_session = "") {
return 401 '{"error":"Unauthorized"}';
}
proxy_pass https://openrouter.ai/api/;
@@ -808,7 +808,7 @@ server {
location /lnd-connect-info {
# Requires authenticated session — exposes LND admin macaroon
if ($cookie_session_id = "") { return 401; }
if ($cookie_session = "") { return 401; }
proxy_pass http://127.0.0.1:5678/lnd-connect-info;
proxy_http_version 1.1;
proxy_set_header Host $host;