From 9f756331c4a33f3bbbdba483266e6bd66b32775e Mon Sep 17 00:00:00 2001 From: zephyrdark Date: Sun, 8 Feb 2026 22:34:32 +0900 Subject: [PATCH] fix: remove passlib dependency and fix FastAPI deprecation warnings - Replace passlib with direct bcrypt usage to eliminate the 'module bcrypt has no attribute __about__' warning - Change Query(regex=) to Query(pattern=) per FastAPI deprecation Co-Authored-By: Claude Opus 4.6 --- backend/app/api/admin.py | 10 +++++----- backend/app/core/security.py | 12 +++++++----- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/backend/app/api/admin.py b/backend/app/api/admin.py index 4b7f57e..f36d3d8 100644 --- a/backend/app/api/admin.py +++ b/backend/app/api/admin.py @@ -43,7 +43,7 @@ class CollectResponse(BaseModel): async def collect_stocks( current_user: CurrentUser, db: Session = Depends(get_db), - biz_day: str = Query(None, regex=r"^\d{8}$", description="Business day in YYYYMMDD format"), + biz_day: str = Query(None, pattern=r"^\d{8}$", description="Business day in YYYYMMDD format"), ): """Collect stock master data from KRX.""" try: @@ -61,7 +61,7 @@ async def collect_stocks( async def collect_sectors( current_user: CurrentUser, db: Session = Depends(get_db), - biz_day: str = Query(None, regex=r"^\d{8}$", description="Business day in YYYYMMDD format"), + biz_day: str = Query(None, pattern=r"^\d{8}$", description="Business day in YYYYMMDD format"), ): """Collect sector classification data from WISEindex.""" try: @@ -79,8 +79,8 @@ async def collect_sectors( async def collect_prices( current_user: CurrentUser, db: Session = Depends(get_db), - start_date: str = Query(None, regex=r"^\d{8}$", description="Start date in YYYYMMDD format"), - end_date: str = Query(None, regex=r"^\d{8}$", description="End date in YYYYMMDD format"), + start_date: str = Query(None, pattern=r"^\d{8}$", description="Start date in YYYYMMDD format"), + end_date: str = Query(None, pattern=r"^\d{8}$", description="End date in YYYYMMDD format"), ): """Collect price data using pykrx.""" try: @@ -98,7 +98,7 @@ async def collect_prices( async def collect_valuations( current_user: CurrentUser, db: Session = Depends(get_db), - biz_day: str = Query(None, regex=r"^\d{8}$", description="Business day in YYYYMMDD format"), + biz_day: str = Query(None, pattern=r"^\d{8}$", description="Business day in YYYYMMDD format"), ): """Collect valuation data from KRX.""" try: diff --git a/backend/app/core/security.py b/backend/app/core/security.py index 8603e85..7b2c687 100644 --- a/backend/app/core/security.py +++ b/backend/app/core/security.py @@ -5,16 +5,14 @@ import hashlib from datetime import datetime, timedelta, timezone from typing import Optional +import bcrypt import jwt from jwt.exceptions import PyJWTError -from passlib.context import CryptContext from app.core.config import get_settings settings = get_settings() -pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") - def sha256_hash(password: str) -> str: """SHA-256 hash a raw password (matches client-side hashing).""" @@ -23,12 +21,16 @@ def sha256_hash(password: str) -> str: def verify_password(sha256_password: str, hashed_password: str) -> bool: """Verify a SHA-256 hashed password against its bcrypt hash.""" - return pwd_context.verify(sha256_password, hashed_password) + return bcrypt.checkpw( + sha256_password.encode(), hashed_password.encode() + ) def get_password_hash(raw_password: str) -> str: """Hash a raw password: SHA-256 then bcrypt.""" - return pwd_context.hash(sha256_hash(raw_password)) + return bcrypt.hashpw( + sha256_hash(raw_password).encode(), bcrypt.gensalt() + ).decode() def create_access_token(data: dict, expires_delta: Optional[timedelta] = None) -> str: