security: Sprint 00 — critical security fixes (OPC WS auth, Transmission creds, SECRET_KEY, passkey rate limit)

- Add JWT token auth to OPC WebSocket (unauthenticated → 403, per-user tracking)
- Externalize Transmission RPC credentials to TRANSMISSION_USER/PASS env vars
- Remove hardcoded SECRET_KEY fallback from dev compose
- Rate-limit passkey register options endpoint at 5/minute
- Add PDD (docs/improvement-plan.md) and sprint specs (specs/)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Gan, Jimmy
2026-05-03 13:31:25 +08:00
parent 5c7d185953
commit ddaf3c6cee
16 changed files with 987 additions and 21 deletions
+6 -4
View File
@@ -4,6 +4,8 @@ from typing import Any, Dict, List
import httpx
from fastapi import APIRouter, HTTPException
import config
router = APIRouter(prefix="/api/transmission", tags=["transmission"])
@@ -12,8 +14,8 @@ def get_session_id() -> str:
try:
with httpx.Client(timeout=5.0) as client:
response = client.get(
"http://host.docker.internal:9091/transmission/rpc",
auth=("admin", "admin")
config.TRANSMISSION_URL,
auth=(config.TRANSMISSION_USER, config.TRANSMISSION_PASS)
)
session_id = response.headers.get("X-Transmission-Session-Id")
if not session_id:
@@ -35,9 +37,9 @@ def transmission_rpc(method: str, arguments: Dict[str, Any] = None) -> Dict[str,
# Use httpx to make the request
with httpx.Client(timeout=10.0) as client:
response = client.post(
"http://host.docker.internal:9091/transmission/rpc",
config.TRANSMISSION_URL,
json=payload,
auth=("admin", "admin"),
auth=(config.TRANSMISSION_USER, config.TRANSMISSION_PASS),
headers={"X-Transmission-Session-Id": session_id}
)