fix: prevent caching of API key handoff
This commit is contained in:
parent
3456b5a3b0
commit
1c0c985d34
@ -1,7 +1,7 @@
|
||||
"""Settings, TTS routes, routing log, server logs, and voice design presets endpoints."""
|
||||
from __future__ import annotations
|
||||
|
||||
from fastapi import APIRouter, HTTPException, Request
|
||||
from fastapi import APIRouter, HTTPException, Request, Response
|
||||
|
||||
from core.config import _load_settings, _save_settings, _normalize_settings, _SETTINGS_KEYS, _ensure_external_api_key
|
||||
from core.routing import _load_tts_routes, _save_tts_routes
|
||||
@ -19,7 +19,7 @@ _SECRET_MASK = "__configured__"
|
||||
|
||||
|
||||
@router.get("/api/settings")
|
||||
async def get_settings(request: Request):
|
||||
async def get_settings(request: Request, response: Response):
|
||||
s = _load_settings()
|
||||
# Lazily generated on first read, not at server startup — a fresh
|
||||
# install shows a real usable key in Settings immediately without a
|
||||
@ -46,15 +46,19 @@ async def get_settings(request: Request):
|
||||
s[key] = _SECRET_MASK
|
||||
else:
|
||||
s.pop(key, None)
|
||||
response.headers["Cache-Control"] = "no-store, no-cache, max-age=0"
|
||||
response.headers["Pragma"] = "no-cache"
|
||||
return s
|
||||
|
||||
|
||||
@router.post("/api/settings/regenerate-api-key")
|
||||
async def regenerate_api_key():
|
||||
async def regenerate_api_key(response: Response):
|
||||
import secrets
|
||||
s = _load_settings()
|
||||
s["external_api_key"] = secrets.token_urlsafe(32)
|
||||
_save_settings(s)
|
||||
response.headers["Cache-Control"] = "no-store, no-cache, max-age=0"
|
||||
response.headers["Pragma"] = "no-cache"
|
||||
return {"external_api_key": s["external_api_key"]}
|
||||
|
||||
|
||||
|
||||
@ -79,6 +79,7 @@ class SecurityValidationTests(unittest.TestCase):
|
||||
payload = response.json()
|
||||
self.assertEqual(payload.get("llm_api_key"), "__configured__")
|
||||
self.assertEqual(payload.get("engine_api_keys", {}).get("local"), "__configured__")
|
||||
self.assertIn("no-store", response.headers.get("cache-control", ""))
|
||||
self.assertNotIn("provider-secret", response.text)
|
||||
self.assertNotIn("engine-secret", response.text)
|
||||
|
||||
@ -93,6 +94,15 @@ class SecurityValidationTests(unittest.TestCase):
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(_load_settings().get("llm_api_key"), "keep-this-secret")
|
||||
|
||||
def test_explicit_external_key_regeneration_is_not_cacheable(self):
|
||||
from fastapi.testclient import TestClient
|
||||
from server import app
|
||||
with TestClient(app) as client:
|
||||
response = client.post("/api/settings/regenerate-api-key", headers={"origin": "http://testserver"})
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertTrue(response.json().get("external_api_key"))
|
||||
self.assertIn("no-store", response.headers.get("cache-control", ""))
|
||||
|
||||
def test_fish_cache_eviction_is_bounded(self):
|
||||
from pathlib import Path
|
||||
from tempfile import TemporaryDirectory
|
||||
|
||||
Loading…
Reference in New Issue
Block a user