Initial commit - Phase 3/4
🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
63
app/backend/api/auth.py
Normal file
63
app/backend/api/auth.py
Normal file
@@ -0,0 +1,63 @@
|
||||
"""Authentication module for Dangerous Pi API."""
|
||||
import secrets
|
||||
from fastapi import Depends, HTTPException, status
|
||||
from fastapi.security import HTTPBasic, HTTPBasicCredentials
|
||||
|
||||
from .. import config
|
||||
|
||||
security = HTTPBasic()
|
||||
|
||||
|
||||
def verify_credentials(credentials: HTTPBasicCredentials = Depends(security)) -> str:
|
||||
"""Verify HTTP Basic Auth credentials.
|
||||
|
||||
Args:
|
||||
credentials: HTTP Basic credentials from request
|
||||
|
||||
Returns:
|
||||
Username if authentication successful
|
||||
|
||||
Raises:
|
||||
HTTPException: If authentication fails
|
||||
"""
|
||||
if not config.AUTH_ENABLED:
|
||||
return "anonymous"
|
||||
|
||||
if not config.AUTH_PASSWORD:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail="AUTH_ENABLED is true but AUTH_PASSWORD is not set",
|
||||
)
|
||||
|
||||
# Use constant-time comparison to prevent timing attacks
|
||||
is_correct_username = secrets.compare_digest(
|
||||
credentials.username.encode("utf-8"),
|
||||
config.AUTH_USERNAME.encode("utf-8")
|
||||
)
|
||||
is_correct_password = secrets.compare_digest(
|
||||
credentials.password.encode("utf-8"),
|
||||
config.AUTH_PASSWORD.encode("utf-8")
|
||||
)
|
||||
|
||||
if not (is_correct_username and is_correct_password):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail="Invalid credentials",
|
||||
headers={"WWW-Authenticate": "Basic"},
|
||||
)
|
||||
|
||||
return credentials.username
|
||||
|
||||
|
||||
def get_optional_auth(credentials: HTTPBasicCredentials = Depends(security)) -> str | None:
|
||||
"""Optional authentication - returns username or None.
|
||||
|
||||
Use this for endpoints where auth is optional based on config.
|
||||
"""
|
||||
if not config.AUTH_ENABLED:
|
||||
return None
|
||||
|
||||
try:
|
||||
return verify_credentials(credentials)
|
||||
except HTTPException:
|
||||
return None
|
||||
Reference in New Issue
Block a user