Добавление всех наработок за период практики.
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
import hashlib
|
||||
import secrets
|
||||
from dataclasses import dataclass
|
||||
from datetime import UTC, datetime, timedelta
|
||||
|
||||
from .database import SiteDatabase
|
||||
from .crypto import TokenCipher
|
||||
|
||||
|
||||
def hash_token(token: str) -> bytes:
|
||||
return hashlib.sha256(token.encode("utf-8")).digest()
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class BindingLink:
|
||||
url: str
|
||||
expires_at: datetime
|
||||
|
||||
|
||||
class SiteBindingRepository:
|
||||
"""Доступ сайта только к функциям выпуска токенов."""
|
||||
|
||||
def __init__(self, database: SiteDatabase) -> None:
|
||||
self.database = database
|
||||
|
||||
def issue(
|
||||
self,
|
||||
member_id: str,
|
||||
domain: str,
|
||||
bitrix_user_id: int,
|
||||
token_hash: bytes,
|
||||
token_expires_at: datetime,
|
||||
access_token: bytes,
|
||||
refresh_token: bytes,
|
||||
oauth_expires_at: datetime,
|
||||
) -> None:
|
||||
"""Сохраняет в БД информацию о токене, выданном пользователю."""
|
||||
query = """
|
||||
SELECT *
|
||||
FROM binding.issue_v1(%s, %s, %s, %s, %s, %s, %s, %s) \
|
||||
"""
|
||||
with self.database.transaction() as connection:
|
||||
connection.execute(
|
||||
query,
|
||||
(
|
||||
member_id,
|
||||
domain,
|
||||
bitrix_user_id,
|
||||
token_hash,
|
||||
token_expires_at,
|
||||
access_token,
|
||||
refresh_token,
|
||||
oauth_expires_at,
|
||||
),
|
||||
).fetchone()
|
||||
|
||||
|
||||
class BindingService:
|
||||
def __init__(
|
||||
self,
|
||||
repository: SiteBindingRepository,
|
||||
cipher: TokenCipher,
|
||||
bot_username: str,
|
||||
ttl_seconds: int,
|
||||
) -> None:
|
||||
self.repository = repository
|
||||
self.cipher = cipher
|
||||
self.bot_username = bot_username
|
||||
self.ttl_seconds = ttl_seconds
|
||||
|
||||
def issue(
|
||||
self,
|
||||
member_id: str,
|
||||
domain: str,
|
||||
bitrix_user_id: int,
|
||||
access_token: str,
|
||||
refresh_token: str,
|
||||
auth_expires_seconds: int,
|
||||
) -> BindingLink:
|
||||
"""Выдает ссылку для привязки аккаунта."""
|
||||
token = secrets.token_urlsafe(32)
|
||||
now = datetime.now(UTC)
|
||||
token_expires_at = now + timedelta(seconds=self.ttl_seconds)
|
||||
oauth_expires_at = now + timedelta(seconds=auth_expires_seconds)
|
||||
self.repository.issue(
|
||||
member_id,
|
||||
domain,
|
||||
bitrix_user_id,
|
||||
hash_token(token),
|
||||
token_expires_at,
|
||||
self.cipher.encrypt(access_token),
|
||||
self.cipher.encrypt(refresh_token),
|
||||
oauth_expires_at,
|
||||
)
|
||||
return BindingLink(
|
||||
url=f"https://t.me/{self.bot_username}?start=bind_{token}",
|
||||
expires_at=token_expires_at,
|
||||
)
|
||||
Reference in New Issue
Block a user