diff --git a/imagecreator/backend/app/core/security.py b/imagecreator/backend/app/core/security.py index 97e5022..97edd01 100644 --- a/imagecreator/backend/app/core/security.py +++ b/imagecreator/backend/app/core/security.py @@ -1 +1,32 @@ -"""Security utilities placeholder.""" +from datetime import datetime, timedelta +from typing import Optional, Any +from types import SimpleNamespace +from jose import JWTError, jwt +from passlib.context import CryptContext + +from app.config import settings + +pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") + +def hash_password(password: str) -> str: + return pwd_context.hash(password) + +def verify_password(plain_password: str, hashed_password: str) -> bool: + return pwd_context.verify(plain_password, hashed_password) + +def create_access_token(data: dict, expires_delta: Optional[timedelta] = None) -> str: + to_encode = data.copy() + if expires_delta: + expire = datetime.utcnow() + expires_delta + else: + expire = datetime.utcnow() + timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES) + to_encode.update({"exp": expire}) + encoded_jwt = jwt.encode(to_encode, settings.SECRET_KEY, algorithm=settings.ALGORITHM) + return encoded_jwt + +def decode_access_token(token: str) -> Optional[SimpleNamespace]: + try: + payload = jwt.decode(token, settings.SECRET_KEY, algorithms=[settings.ALGORITHM]) + return SimpleNamespace(**payload) + except JWTError: + return None \ No newline at end of file diff --git a/imagecreator/backend/tests/test_security.py b/imagecreator/backend/tests/test_security.py new file mode 100644 index 0000000..4eaa90a --- /dev/null +++ b/imagecreator/backend/tests/test_security.py @@ -0,0 +1,19 @@ +import pytest +from app.core.security import verify_password, hash_password, create_access_token, decode_access_token + +def test_password_hash_and_verify(): + password = "testpassword123" + hashed = hash_password(password) + + assert hashed != password + assert verify_password(password, hashed) is True + assert verify_password("wrongpassword", hashed) is False + +def test_access_token_creation_and_decode(): + token = create_access_token({"sub": "testuser"}) + + assert token is not None + payload = decode_access_token(token) + + assert payload is not None + assert payload.sub == "testuser" \ No newline at end of file