feat: extract advanced_metrics, analytics, test_templates, and auth to services (Tier 1 complete)
This commit is contained in:
@@ -9,7 +9,7 @@ cannot use cookies (e.g. Swagger UI).
|
||||
|
||||
import os
|
||||
|
||||
from fastapi import APIRouter, Cookie, Depends, HTTPException, Request, Response, status
|
||||
from fastapi import APIRouter, Cookie, Depends, Request, Response
|
||||
from fastapi.security import OAuth2PasswordRequestForm
|
||||
from slowapi import Limiter
|
||||
from slowapi.util import get_remote_address
|
||||
@@ -17,11 +17,13 @@ from sqlalchemy.orm import Session
|
||||
|
||||
from jose import jwt, JWTError
|
||||
|
||||
from app.auth import verify_password, hash_password, create_access_token, blacklist_token
|
||||
from app.auth import create_access_token, blacklist_token
|
||||
from app.config import settings
|
||||
from app.database import get_db
|
||||
from app.dependencies.auth import get_current_user
|
||||
from app.domain.unit_of_work import UnitOfWork
|
||||
from app.models.user import User
|
||||
from app.services.auth_service import authenticate_user, change_password as auth_change_password
|
||||
from app.schemas.auth import TokenResponse, UserOut
|
||||
from app.schemas.user import PasswordChange
|
||||
|
||||
@@ -56,25 +58,11 @@ def login(
|
||||
attacks. The token is set as an HttpOnly cookie **and** returned in the
|
||||
JSON body for API/Swagger compatibility.
|
||||
"""
|
||||
user = db.query(User).filter(User.username == form_data.username).first()
|
||||
|
||||
# Constant-time comparison: always run bcrypt verify to prevent
|
||||
# timing-based user enumeration (SEC-005).
|
||||
_DUMMY_HASH = "$2b$12$LJ3m4ys3Lg3dMO/NpNmOaeVwFpWJMxlB2FLmEAo9fZr.S8H1vC4Wy"
|
||||
hashed = user.hashed_password if user else _DUMMY_HASH
|
||||
password_valid = verify_password(form_data.password, hashed)
|
||||
|
||||
if user is None or not password_valid:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail="Incorrect username or password",
|
||||
)
|
||||
|
||||
if not user.is_active:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
detail="Account is disabled. Contact an administrator.",
|
||||
)
|
||||
user = authenticate_user(
|
||||
db,
|
||||
username=form_data.username,
|
||||
password=form_data.password,
|
||||
)
|
||||
|
||||
access_token = create_access_token(data={"sub": user.username})
|
||||
|
||||
@@ -163,14 +151,13 @@ def change_password(
|
||||
``must_change_password`` flag is cleared so the user can proceed
|
||||
normally.
|
||||
"""
|
||||
if not verify_password(body.current_password, current_user.hashed_password):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail="Current password is incorrect",
|
||||
)
|
||||
|
||||
current_user.hashed_password = hash_password(body.new_password)
|
||||
current_user.must_change_password = False
|
||||
db.commit()
|
||||
auth_change_password(
|
||||
db,
|
||||
current_user,
|
||||
current_password=body.current_password,
|
||||
new_password=body.new_password,
|
||||
)
|
||||
with UnitOfWork(db) as uow:
|
||||
uow.commit()
|
||||
|
||||
return {"detail": "Password changed successfully"}
|
||||
|
||||
Reference in New Issue
Block a user