fix: load configuration from config.json and fix authentication

- Load anime_directory and master_password_hash from config.json on startup
- Sync configuration from config.json to settings object in fastapi_app.py
- Update dependencies.py to load config from JSON if not in environment
- Fix app.js to use makeAuthenticatedRequest() for all authenticated API calls
- Fix API endpoint paths from /api/v1/anime to /api/anime
- Update auth_service.py to load master_password_hash from config.json
- Update auth.py setup endpoint to save master_password_hash to config
- Fix rate limiting code to satisfy type checker
- Update config.json with test master password hash

Fixes:
- 401 Unauthorized errors on /api/anime endpoint
- 503 Service Unavailable errors on /api/anime/process/locks
- Configuration not being loaded from config.json file
- Authentication flow now works end-to-end with JWT tokens
This commit is contained in:
2025-10-24 20:55:10 +02:00
parent 4e08d81bb0
commit a3651e0e47
6 changed files with 148 additions and 36 deletions

View File

@@ -68,6 +68,17 @@ def get_series_app() -> SeriesApp:
"""
global _series_app
# Try to load anime_directory from config.json if not in settings
if not settings.anime_directory:
try:
from src.server.services.config_service import get_config_service
config_service = get_config_service()
config = config_service.load_config()
if config.other and config.other.get("anime_directory"):
settings.anime_directory = str(config.other["anime_directory"])
except Exception:
pass # Will raise 503 below if still not configured
if not settings.anime_directory:
raise HTTPException(
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
@@ -104,6 +115,17 @@ def get_optional_series_app() -> Optional[SeriesApp]:
"""
global _series_app
# Try to load anime_directory from config.json if not in settings
if not settings.anime_directory:
try:
from src.server.services.config_service import get_config_service
config_service = get_config_service()
config = config_service.load_config()
if config.other and config.other.get("anime_directory"):
settings.anime_directory = str(config.other["anime_directory"])
except Exception:
return None
if not settings.anime_directory:
return None
@@ -283,20 +305,27 @@ async def rate_limit_dependency(request: Request) -> None:
async with _rate_limit_lock:
record = _RATE_LIMIT_BUCKETS.get(client_id)
if not record or now - record.window_start >= _RATE_LIMIT_WINDOW_SECONDS:
window_expired = (
not record
or now - record.window_start >= _RATE_LIMIT_WINDOW_SECONDS
)
if window_expired:
_RATE_LIMIT_BUCKETS[client_id] = RateLimitRecord(
count=1,
window_start=now,
)
return
record.count += 1
if record.count > max_requests:
logger.warning("Rate limit exceeded", extra={"client": client_id})
raise HTTPException(
status_code=status.HTTP_429_TOO_MANY_REQUESTS,
detail="Too many requests. Please slow down.",
)
if record: # Type guard to satisfy mypy
record.count += 1
if record.count > max_requests:
logger.warning(
"Rate limit exceeded", extra={"client": client_id}
)
raise HTTPException(
status_code=status.HTTP_429_TOO_MANY_REQUESTS,
detail="Too many requests. Please slow down.",
)
# Dependency for request logging (placeholder)