Initial commit: XDL Twitter/X video downloader

This commit is contained in:
mini
2026-02-18 17:15:12 +08:00
commit 7fdd181728
32 changed files with 1230 additions and 0 deletions

42
backend/app/auth.py Normal file
View File

@@ -0,0 +1,42 @@
"""JWT authentication utilities."""
import os
from datetime import datetime, timedelta
from typing import Optional
from jose import JWTError, jwt
from fastapi import Depends, HTTPException, status
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
SECRET_KEY = os.getenv("SECRET_KEY", "dev-secret-key")
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_HOURS = 72
security = HTTPBearer()
def create_access_token(data: dict, expires_delta: Optional[timedelta] = None) -> str:
to_encode = data.copy()
expire = datetime.utcnow() + (expires_delta or timedelta(hours=ACCESS_TOKEN_EXPIRE_HOURS))
to_encode.update({"exp": expire})
return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
def verify_token(token: str) -> dict:
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
return payload
except JWTError:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid token")
async def get_current_user(credentials: HTTPAuthorizationCredentials = Depends(security)) -> dict:
return verify_token(credentials.credentials)
def optional_auth(credentials: Optional[HTTPAuthorizationCredentials] = Depends(HTTPBearer(auto_error=False))) -> Optional[dict]:
"""Optional authentication - returns None if no valid token."""
if credentials is None:
return None
try:
return verify_token(credentials.credentials)
except HTTPException:
return None