SFM/app/opencloud_token_store.py
2026-09-17 13:04:35 +03:00

86 lines
3.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from __future__ import annotations
from cryptography.fernet import Fernet, InvalidToken
from sqlalchemy import select
from app.core.config import settings
from app.db.base import SessionLocal
from app.db.models.opencloud_token import OpenCloudToken
class OpenCloudTokenStoreError(RuntimeError):
"""Ошибка при работе с таблицей токенов OpenCloud (шифрование/БД)."""
def _get_fernet() -> Fernet:
if not settings.FERNET_KEY:
raise OpenCloudTokenStoreError(
"Не задан OPENBAO__SETTINGS__FERNET_KEY — шифрование токенов "
"OpenCloud недоступно."
)
try:
return Fernet(settings.FERNET_KEY.encode())
except (ValueError, TypeError) as exc:
raise OpenCloudTokenStoreError(
f"OPENBAO__SETTINGS__FERNET_KEY некорректен: {exc}"
) from exc
async def add_token(username: str, token: str, added_by: str | None = None) -> None:
"""Сохраняет (или перезаписывает) App Token заказчика, зашифровав его."""
if not username:
raise OpenCloudTokenStoreError("Не задан username для сохранения токена.")
if not token:
raise OpenCloudTokenStoreError("Не задан токен для сохранения.")
encrypted = _get_fernet().encrypt(token.encode()).decode()
async with SessionLocal() as session:
obj = await session.get(OpenCloudToken, username)
if obj is not None:
obj.encrypted_token = encrypted
if added_by:
obj.added_by = added_by
else:
session.add(
OpenCloudToken(
username=username, encrypted_token=encrypted, added_by=added_by
)
)
await session.commit()
async def get_token(username: str) -> str | None:
"""username -> расшифрованный App Token, либо None, если записи нет."""
if not username:
return None
async with SessionLocal() as session:
obj = await session.get(OpenCloudToken, username)
if obj is None:
return None
try:
return _get_fernet().decrypt(obj.encrypted_token.encode()).decode()
except InvalidToken as exc:
raise OpenCloudTokenStoreError(
f"Не удалось расшифровать токен для '{username}' — "
"проверьте OPENBAO__SETTINGS__FERNET_KEY."
) from exc
async def remove_token(username: str) -> bool:
"""Удаляет запись пользователя. Возвращает True, если запись была найдена."""
async with SessionLocal() as session:
obj = await session.get(OpenCloudToken, username)
if obj is None:
return False
await session.delete(obj)
await session.commit()
return True
async def list_usernames() -> list[str]:
"""Список username, для которых сохранён токен (без расшифровки)."""
async with SessionLocal() as session:
result = await session.execute(select(OpenCloudToken.username))
return list(result.scalars().all())