5.4 KiB
5.4 KiB
accounts-service: исходящая почта, подтверждение email и сброс пароля
Статус: черновик на согласование (2026-10-09).
Решения владельца
- Отправка через внешний SMTP (Resend,
smtp.resend.com, логинresend, пароль = API-ключ), адресnoreply@loki-code.dev. - Неподтверждённый email: логин и обычное использование разрешены, ограничены привязка аккаунта к моду (
/device/confirm) и публикация аддонов. - DNS (Cloudflare) и секреты настраивает владелец. Корневой SPF не нужен (Resend работает на поддомене
send). DMARC безrua:v=DMARC1; p=none;(отчёты на внешний адрес без разрешения принимающего домена не доставляются).
Этап 1: подтверждение email
- Миграция
0005_email_tokens.sql:ALTER TABLE accounts ADD COLUMN email_verified_at TIMESTAMPTZ;email_tokens(id UUID PK, account_id UUID FK ON DELETE CASCADE, purpose TEXT CHECK in ('email_verify','password_reset'), token_hash TEXT UNIQUE, expires_at, used_at, created_at); хранится только SHA-256 токена (какrefresh_tokens).- Существующие аккаунты остаются неподтверждёнными (решение по миграции старых: см. вопросы).
- Модуль
src/mail/: трейтMailer,SmtpMailerнаlettre(rustls),NoopMailer(пишет в лог, еслиSMTP_HOSTпуст: dev и тесты), шаблоны писем. Конфиг:SMTP_HOST,SMTP_PORT(587 STARTTLS по умолчанию, 465 implicit TLS),SMTP_USER,SMTP_PASSWORD,MAIL_FROM,PUBLIC_BASE_URLдля ссылок. Секреты только из env,.env.exampleс пустыми значениями. - Токены:
src/auth/email_tokens.rs: генерация (32 случайных байта, base64url), хеш, TTL (verify 24 ч, reset 1 ч), одноразовость (used_at), при выдаче нового токена того жеpurposeстарые инвалидируются. - Эндпоинты:
POST /auth/verify-email {token}: помечаетemail_verified_at, токен одноразовый.POST /auth/resend-verification(нужен вход): новое письмо, лимит частоты на аккаунт и IP.registerставит отправку в фоновую задачу, ответ не ждёт SMTP; ошибка отправки только логируется.
- Ограничения для неподтверждённых:
/device/confirmвозвращает 403email not verified.- Публикация аддонов: проверка в
addons-registryчерез данные аккаунта из gRPC (полеemail_verifiedдобавить в ответaccounts-service);can_publish_addonsвaccounts-serviceсам по себе нигде не проверяется, проверка живёт на стороне вызывающего сервиса. /meотдаётemail_verified, чтобы сайт и мод показали плашку «подтвердите email».
- Сайт: страница
/verify?token=..., вызывающая эндпоинт, и плашка с кнопкой «выслать письмо снова». - Тесты: чистая логика токенов (хеш, TTL, одноразовость) и флоу на
axum-testпо образцуtests/auth_flow.
Этап 2: сброс пароля
POST /auth/forgot-password {email}: всегда одинаковый ответ (нет перечисления email), письмо только если аккаунт есть; лимит частоты; задержка выравнивается как вlogin.POST /auth/reset-password {token, new_password}: проверка токена, смена хеша пароля, отзыв всех refresh-токенов аккаунта.
Безопасность
- Токены только хешем, сравнение по хешу в БД, одноразовые, с коротким TTL.
- Ответы эндпоинтов не раскрывают, существует ли email.
- Ссылки только на
PUBLIC_BASE_URLиз конфига, не из заголовков запроса (защита от host header injection). - API-ключ Resend: права только на отправку, хранится в
.envна VPS (chmod 600), не в репозитории.
Открытые вопросы
- Старые аккаунты: считать подтверждёнными автоматически (миграция ставит
email_verified_at = now()) или требовать подтверждения? Рекомендую пометить подтверждёнными, чтобы не заблокировать существующих. - Где проверяется публикация аддонов в
addons-registry(нужно прочитать код перед этапом 1, п.5).