"""Генерация номера и постоянной ссылки конференции (ADR-001, п.4). Оба идентификатора неизменны всё время жизни конференции и не переиспользуются; уникальность в БД обеспечивают constraint'ы `conferences.number`/`conferences.slug`, коллизии (крайне маловероятные при выбранной энтропии) обрабатываются повторной генерацией на уровне репозитория/сервиса, создающего конференцию. """ import secrets # Длина номера конференции в десятичных цифрах. NUMBER_LENGTH = 9 # Длина slug в байтах энтропии (до base64url-кодирования); 8 байт = 64 бита, # что даёт 11 символов base64url без padding. SLUG_ENTROPY_BYTES = 8 def generate_number() -> str: """Сгенерировать 9-значный номер конференции. Первая цифра — 1..9 (число не начинается с нуля), остальные 8 — 0..9. Используется `secrets.randbelow` — криптографически стойкий генератор, подбор номера должен быть неугадываем (оценка энтропии — ADR-001, п.4). """ first_digit = str(secrets.randbelow(9) + 1) rest_digits = "".join(str(secrets.randbelow(10)) for _ in range(NUMBER_LENGTH - 1)) return first_digit + rest_digits def generate_slug() -> str: """Сгенерировать slug постоянной ссылки конференции (`/j/{slug}`). `secrets.token_urlsafe(8)` — 8 байт (64 бита) энтропии, 11 символов base64url; также используется как имя LiveKit-комнаты. """ return secrets.token_urlsafe(SLUG_ENTROPY_BYTES)