Инициализация в новом репозитории

This commit is contained in:
commit eb1f18f53e
374 changed files with 226678 additions and 0 deletions

0
SRV/storage/__init__.py Normal file
View file

101
SRV/storage/json_storage.py Normal file
View file

@ -0,0 +1,101 @@
# storage/json_storage.py
import json
import os
import logging
from passlib.context import CryptContext
from typing import Optional
from models.auth import UserCreate, UserResponse
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
class JsonStorage:
"""Хранилище пользователей в JSON-файле"""
def __init__(self, file_path: str = "/etc/gonets/users.json"):
self.file_path = file_path
self.pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
self._ensure_file_exists()
def _ensure_file_exists(self):
"""Создаёт JSON-файл, если он не существует"""
try:
logger.info(f"Проверка существования файла {self.file_path}")
if not os.path.exists(self.file_path):
logger.info(f"Создание директории {os.path.dirname(self.file_path)}")
os.makedirs(os.path.dirname(self.file_path), exist_ok=True)
logger.info(f"Создание файла {self.file_path}")
with open(self.file_path, "w") as f:
json.dump({"users": [], "next_id": 1}, f)
os.chmod(self.file_path, 0o600)
logger.info(f"Создан файл {self.file_path}")
else:
logger.info(f"Файл {self.file_path} уже существует")
except Exception as e:
logger.error(f"Ошибка при создании файла {self.file_path}: {type(e).__name__} - {str(e)}")
raise
def _read_data(self) -> dict:
"""Читает данные из JSON-файла"""
try:
with open(self.file_path, "r") as f:
return json.load(f)
except FileNotFoundError:
logger.info(f"Файл {self.file_path} не существует, возвращаем пустую структуру")
return {"users": [], "next_id": 1}
except Exception as e:
logger.error(f"Ошибка при чтении файла {self.file_path}: {type(e).__name__} - {str(e)}")
raise
def _write_data(self, data: dict):
"""Записывает данные в JSON файл"""
try:
with open(self.file_path, "w") as f:
json.dump(data, f, indent=2)
except Exception as e:
logger.error(f"Ошибка при записи файла {self.file_path}: {type(e).__name__} - {str(e)}")
raise
def create_user(self, user: UserCreate) -> UserResponse:
"""Создаёт нового пользователя"""
try:
data = self._read_data()
users = data["users"]
next_id = data["next_id"]
if any(u["username"] == user.username for u in users):
logger.error(f"Пользователь {user.username} уже существует")
raise ValueError("Пользователь уже существует")
password_hash = self.pwd_context.hash(user.password)
new_user = {
"id": next_id,
"username": user.username,
"password_hash": password_hash,
"is_admin": user.is_admin
}
users.append(new_user)
data["next_id"] = next_id + 1
self._write_data(data)
logger.info(f"Пользователь {user.username} успешно зарегистрирован")
return UserResponse(id=new_user["id"], username=new_user["username"], is_admin=new_user["is_admin"])
except Exception as e:
logger.error(f"Ошибка при создании пользователя {user.username}: {type(e).__name__} - {str(e)}")
raise
def get_user_by_username(self, username: str) -> Optional[dict]:
"""Получает пользователя по имени"""
try:
if not os.path.exists(self.file_path):
logger.info(f"Файл {self.file_path} не существует, пользователь {username} не найден")
return None
data = self._read_data()
for user in data["users"]:
if user["username"] == username:
return user
return None
except Exception as e:
logger.error(f"Ошибка при получении пользователя {username}: {type(e).__name__} - {str(e)}")
raise
def verify_password(self, plain_password: str, hashed_password: str) -> bool:
"""Проверяет пароль"""
return self.pwd_context.verify(plain_password, hashed_password)

View file

@ -0,0 +1,141 @@
# storage/session_storage.py
import json
import os
import uuid
import logging
from typing import Optional, Dict
from datetime import datetime, timedelta
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
class SessionStorage:
def __init__(self, file_path: str = "/etc/gonets/sessions.json"):
self.file_path = file_path
self._ensure_file_exists()
def _ensure_file_exists(self):
try:
logger.info(f"Проверка существования файла {self.file_path}")
if not os.path.exists(self.file_path):
logger.info(f"Создание директории {os.path.dirname(self.file_path)}")
os.makedirs(os.path.dirname(self.file_path), exist_ok=True)
logger.info(f"Создание файла {self.file_path}")
with open(self.file_path, "w") as f:
json.dump({"sessions": {}}, f)
os.chmod(self.file_path, 0o600)
logger.info(f"Создан файл {self.file_path}")
else:
logger.info(f"Файл {self.file_path} уже существует")
except Exception as e:
logger.error(f"Ошибка при создании файла {self.file_path}: {type(e).__name__} - {str(e)}")
raise
def _read_data(self) -> Dict:
try:
with open(self.file_path, "r") as f:
return json.load(f)
except Exception as e:
logger.error(f"Ошибка при чтении файла {self.file_path}: {type(e).__name__} - {str(e)}")
raise
def _write_data(self, data: Dict):
try:
with open(self.file_path, "w") as f:
json.dump(data, f, indent=2)
except Exception as e:
logger.error(f"Ошибка при записи файла {self.file_path}: {type(e).__name__} - {str(e)}")
raise
def create_session(self, username: str, token: str, client_id: str) -> str:
"""Создаёт новую сессию и возвращает session_id"""
try:
self.clean_expired_sessions()
data = self._read_data()
session_id = str(uuid.uuid4())
created_at = datetime.utcnow().isoformat()
expiry = (datetime.utcnow() + timedelta(minutes=30)).isoformat()
data["sessions"][session_id] = {
"username": username,
"token": token,
"client_id": client_id,
"created_at": created_at,
"expiry": expiry
}
self._write_data(data)
logger.info(f"Сессия создана для пользователя {username} с session_id {session_id}")
return session_id
except Exception as e:
logger.error(f"Ошибка при создании сессии для {username}: {type(e).__name__} - {str(e)}")
raise
def get_latest_session(self, client_id: str) -> Optional[Dict]:
"""Получает последнюю активную сессию для client_id"""
try:
self.clean_expired_sessions()
data = self._read_data()
latest_session = None
latest_time = None
for session_id, session in data["sessions"].items():
if session["client_id"] == client_id:
expiry = datetime.fromisoformat(session["expiry"])
if datetime.utcnow() > expiry:
logger.info(f"Сессия {session_id} истекла")
del data["sessions"][session_id]
continue
created_at = datetime.fromisoformat(session["created_at"])
if latest_time is None or created_at > latest_time:
latest_time = created_at
latest_session = session
latest_session["session_id"] = session_id
if latest_session:
logger.info(f"Найдена сессия для client_id {client_id}")
return latest_session
logger.info(f"Сессия для client_id {client_id} не найдена")
self._write_data(data)
return None
except Exception as e:
logger.error(f"Ошибка при получении сессии для client_id {client_id}: {type(e).__name__} - {str(e)}")
raise
def delete_session(self, session_id: str):
"""Удаляет сессию по session_id"""
try:
self.clean_expired_sessions()
data = self._read_data()
if session_id in data["sessions"]:
del data["sessions"][session_id]
self._write_data(data)
logger.info(f"Сессия с session_id {session_id} удалена")
except Exception as e:
logger.error(f"Ошибка при удалении сессии {session_id}: {type(e).__name__} - {str(e)}")
raise
def clean_expired_sessions(self):
"""Удаляет все истекшие сессии из хранилища"""
try:
data = self._read_data()
expired_sessions = []
current_time = datetime.utcnow()
# Находим истекшие сессии
for session_id, session in list(data["sessions"].items()):
expiry = datetime.fromisoformat(session["expiry"])
if current_time > expiry:
expired_sessions.append(session_id)
# Удаляем истекшие сессии
for session_id in expired_sessions:
del data["sessions"][session_id]
logger.info(f"Удалена истекшая сессия с session_id {session_id}")
# Записываем обновлённые данные
if expired_sessions:
self._write_data(data)
logger.info(f"Удалено {len(expired_sessions)} истекших сессий")
else:
logger.debug("Истекшие сессии не найдены")
except Exception as e:
logger.error(f"Ошибка при очистке истекших сессий: {type(e).__name__} - {str(e)}")
raise