Spaces:
Running
Running
| import uuid | |
| import datetime | |
| import hashlib | |
| import os | |
| from fastapi import APIRouter, Depends, HTTPException | |
| from sqlalchemy.orm import Session | |
| from jose import jwt | |
| from app.database import get_db | |
| from app.models.user import User | |
| from app.models.apikey import APIKey | |
| from app.dependencies import hash_api_key, get_current_user | |
| from app.schemas import UserRegister, UserLogin, TokenResponse, APIKeyResponse | |
| from app.config import get_settings | |
| router = APIRouter(prefix="/v1/auth", tags=["auth"]) | |
| settings = get_settings() | |
| def hash_password(password: str) -> str: | |
| salt = os.urandom(16).hex() | |
| h = hashlib.sha256((password + salt).encode()).hexdigest() | |
| return f"{salt}${h}" | |
| def verify_password(password: str, hashed: str) -> bool: | |
| salt, h = hashed.split("$", 1) | |
| return hashlib.sha256((password + salt).encode()).hexdigest() == h | |
| def generate_api_key() -> tuple: | |
| raw = f"revai_live_{uuid.uuid4().hex}{uuid.uuid4().hex[:8]}" | |
| return raw, hash_api_key(raw) | |
| def create_token(user: User) -> str: | |
| payload = { | |
| "sub": user.id, | |
| "email": user.email, | |
| "tier": user.tier, | |
| "exp": datetime.datetime.utcnow() + datetime.timedelta(minutes=settings.access_token_expire_minutes), | |
| } | |
| return jwt.encode(payload, settings.secret_key, algorithm=settings.algorithm) | |
| def register(body: UserRegister, db: Session = Depends(get_db)): | |
| existing = db.query(User).filter(User.email == body.email).first() | |
| if existing: | |
| raise HTTPException(status_code=409, detail="Email already registered") | |
| user = User( | |
| email=body.email, | |
| hashed_password=hash_password(body.password), | |
| name=body.name, | |
| ) | |
| db.add(user) | |
| db.flush() | |
| raw_key, key_hash = generate_api_key() | |
| api_key = APIKey( | |
| user_id=user.id, | |
| key_hash=key_hash, | |
| prefix=raw_key[:20] + "...", | |
| ) | |
| db.add(api_key) | |
| db.commit() | |
| token = create_token(user) | |
| return TokenResponse( | |
| access_token=token, | |
| user_id=user.id, | |
| email=user.email, | |
| tier=user.tier, | |
| api_key=raw_key, | |
| ) | |
| def login(body: UserLogin, db: Session = Depends(get_db)): | |
| user = db.query(User).filter(User.email == body.email).first() | |
| if not user or not verify_password(body.password, user.hashed_password): | |
| raise HTTPException(status_code=401, detail="Invalid email or password") | |
| # Return existing active key or create new one | |
| api_key = db.query(APIKey).filter( | |
| APIKey.user_id == user.id, APIKey.is_active == True | |
| ).first() | |
| raw_key = None | |
| if not api_key: | |
| raw_key, key_hash = generate_api_key() | |
| api_key = APIKey(user_id=user.id, key_hash=key_hash, prefix=raw_key[:20] + "...") | |
| db.add(api_key) | |
| db.commit() | |
| raw_key = raw_key | |
| token = create_token(user) | |
| return TokenResponse( | |
| access_token=token, | |
| user_id=user.id, | |
| email=user.email, | |
| tier=user.tier, | |
| api_key=raw_key, | |
| ) | |
| def list_api_keys(user: User = Depends(get_current_user), | |
| db: Session = Depends(get_db)): | |
| keys = db.query(APIKey).filter(APIKey.user_id == user.id).all() | |
| return [APIKeyResponse( | |
| id=k.id, prefix=k.prefix, name=k.name, | |
| is_active=k.is_active, created_at=k.created_at, | |
| last_used_at=k.last_used_at | |
| ) for k in keys] | |