Phase 4 enhancements: WebSocket auth, HTTPS UI, plugin hooks, build fixes

Security:
- Add token-based WebSocket authentication (closes critical security gap)
  - In-memory token store with 24h TTL (token_store.py)
  - POST /api/auth/token exchanges Basic Auth for WS token
  - GET /api/auth/status public endpoint for auth check
  - WebSocket validates token query param, rejects with close code 4401
  - Frontend LoginPrompt modal for credential entry
  - WebSocket manager handles full auth flow with auth_required state
  - No-op when AUTH_ENABLED=false (preserves existing behavior)

HTTPS:
- Wire HTTPS toggle in Settings UI (POST /api/system/ssl/toggle)
- Add certificate regeneration button
- Display SSL info (expiration, SANs, SHA256 fingerprint)

Plugins:
- Wire trigger_hook("pm3_command") in PM3 service
- Wire trigger_hook("update_check") in update manager

Build/Infrastructure:
- Enable NetworkManager in pi-gen AP setup stage
- Add HF booster board detection patch for Proxmark3
- Update LED PWM control patch
- Fix BLE adapter, UPS drivers, WiFi manager improvements
- Update HTTPS support stage script

Documentation:
- Update PROJECT_STATUS.md and IMPLEMENTATION_PRIORITIES.md

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
michael
2026-03-03 11:45:11 -08:00
parent 4f35df1781
commit 2ec89041ef
24 changed files with 1249 additions and 362 deletions

View File

@@ -384,6 +384,8 @@ async def get_power_restrictions():
class PiModelResponse(BaseModel):
"""Pi model information response."""
model_config = {"protected_namespaces": ()} # Allow model_* field names
model: str
model_short: str
total_cores: int
@@ -793,6 +795,93 @@ async def regenerate_ssl_certificate(request: SSLRegenerateRequest):
)
class SSLToggleRequest(BaseModel):
"""Request to enable or disable HTTPS."""
enabled: bool
@router.post("/ssl/toggle")
async def toggle_https(request: SSLToggleRequest):
"""Enable or disable HTTPS.
Updates the HTTPS_ENABLED setting in the .env file and runs
configure-nginx.sh to switch nginx between HTTP and HTTPS configs.
Reloads nginx to apply the change immediately.
Args:
enabled: True to enable HTTPS, False to disable
Returns:
Success status and current HTTPS state
"""
import subprocess
import os
env_file = os.getenv("ENV_FILE", "/opt/dangerous-pi/.env")
configure_script = "/opt/dangerous-pi/scripts/configure-nginx.sh"
# Update .env file
try:
lines = []
found = False
if os.path.exists(env_file):
with open(env_file, "r") as f:
lines = f.readlines()
new_lines = []
for line in lines:
if line.strip().startswith("HTTPS_ENABLED="):
new_lines.append(f"HTTPS_ENABLED={'true' if request.enabled else 'false'}\n")
found = True
else:
new_lines.append(line)
if not found:
new_lines.append(f"HTTPS_ENABLED={'true' if request.enabled else 'false'}\n")
with open(env_file, "w") as f:
f.writelines(new_lines)
except PermissionError:
raise HTTPException(
status_code=500,
detail="Cannot write to .env file - check permissions"
)
# Update runtime config
from .. import config as app_config
app_config.HTTPS_ENABLED = request.enabled
# Run configure-nginx.sh to switch nginx config
nginx_configured = False
if os.path.exists(configure_script):
try:
result = subprocess.run(
[configure_script],
capture_output=True,
text=True,
timeout=15,
env={**os.environ, "HTTPS_ENABLED": "true" if request.enabled else "false"}
)
if result.returncode == 0:
# Reload nginx
subprocess.run(
["systemctl", "reload", "nginx"],
capture_output=True,
timeout=10
)
nginx_configured = True
except Exception:
pass # Non-fatal, .env was still updated
return {
"success": True,
"enabled": request.enabled,
"nginx_configured": nginx_configured,
"message": f"HTTPS {'enabled' if request.enabled else 'disabled'}"
}
# -----------------------------------------------------------------------------
# Header Widgets API
# -----------------------------------------------------------------------------