init auth and main function
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
import asyncio
|
||||
import hashlib
|
||||
import secrets
|
||||
import logging
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Dict, Optional
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class AuthManager:
|
||||
"""Управляет авторизацией: хеширование паролей, сессии, верификация."""
|
||||
|
||||
def __init__(self, session_timeout_minutes: int = 120):
|
||||
self._sessions: Dict[int, datetime] = {}
|
||||
self._failed_attempts: Dict[int, list] = {}
|
||||
self._max_attempts = 5
|
||||
self._lockout_duration = 300 # 5 минут блокировки
|
||||
self._session_timeout = timedelta(minutes=session_timeout_minutes)
|
||||
|
||||
@staticmethod
|
||||
def _hash_password(password: str, salt: str = None) -> tuple:
|
||||
if salt is None:
|
||||
salt = secrets.token_hex(16)
|
||||
result = hashlib.sha256((salt + password).encode()).hexdigest()
|
||||
return result, salt
|
||||
|
||||
def verify_password(self, password: str, password_hash: str, salt: str) -> bool:
|
||||
computed, _ = self._hash_password(password, salt)
|
||||
return secrets.compare_digest(computed, password_hash)
|
||||
|
||||
def is_authenticated(self, user_id: int) -> bool:
|
||||
if user_id not in self._sessions:
|
||||
return False
|
||||
if datetime.now() - self._sessions[user_id] > self._session_timeout:
|
||||
self.logout(user_id)
|
||||
return False
|
||||
return True
|
||||
|
||||
def login(self, user_id: int):
|
||||
self._sessions[user_id] = datetime.now()
|
||||
self._failed_attempts.pop(user_id, None)
|
||||
logger.info(f"User {user_id} logged in")
|
||||
|
||||
def logout(self, user_id: int):
|
||||
self._sessions.pop(user_id, None)
|
||||
self._failed_attempts.pop(user_id, None)
|
||||
logger.info(f"User {user_id} logged out")
|
||||
|
||||
def is_locked_out(self, user_id: int) -> bool:
|
||||
if user_id not in self._failed_attempts:
|
||||
return False
|
||||
attempts = self._failed_attempts[user_id]
|
||||
recent = [t for t in attempts if datetime.now() - t < timedelta(minutes=5)]
|
||||
self._failed_attempts[user_id] = recent
|
||||
if len(recent) >= self._max_attempts:
|
||||
return True
|
||||
return False
|
||||
|
||||
def record_failed_attempt(self, user_id: int):
|
||||
if user_id not in self._failed_attempts:
|
||||
self._failed_attempts[user_id] = []
|
||||
self._failed_attempts[user_id].append(datetime.now())
|
||||
|
||||
def get_session_info(self, user_id: int) -> Optional[dict]:
|
||||
if user_id not in self._sessions:
|
||||
return None
|
||||
login_time = self._sessions[user_id]
|
||||
elapsed = datetime.now() - login_time
|
||||
return {
|
||||
"user_id": user_id,
|
||||
"login_time": login_time.isoformat(),
|
||||
"elapsed_minutes": int(elapsed.total_seconds() // 60),
|
||||
}
|
||||
Reference in New Issue
Block a user