feat: аккаунты по почте с подтверждением, сбросом пароля и синхронизацией прогресса
API аккаунтов на чистой стандартной библиотеке Python (server/splitapi): - регистрация по почте: пароль задаётся по ссылке из письма, аккаунт создаётся только после подтверждения - вход, выход, сброс пароля по почте (токены одноразовые, в базе только SHA-256), удаление аккаунта - пароли scrypt, лимиты попыток по паре «адрес + IP», IP и аккаунту, защита от CSRF - хранение прогресса пользователя с оптимистичной блокировкой версии - SMTP через переменные окружения; без SMTP на публичном адресе API не стартует Клиент: public/auth.js (вход, регистрация, сброс, синхронизация), public/sync.js (чистое слияние прогресса). Без API сайт работает как раньше. Развёртывание: Dockerfile.api, сервис splitapi в docker-compose, проксирование /api/ в nginx с ограничением частоты, deploy/install-api-debian.sh (systemd), .env.example. Тесты: 216 для бэкенда (unittest, покрытие около 97%), 16 для клиентского слияния. Документация: раздел «Аккаунты и почта» в docs/DEPLOY.md, раздел 9 в docs/ИНСТРУКЦИЯ.md.
This commit is contained in:
@@ -301,3 +301,17 @@ td.r, th.r { text-align: right; }
|
||||
.nm input { font: inherit; color: var(--fg); background: var(--panel2); border: 1px solid var(--line); border-radius: 8px; padding: 5px 9px; width: 150px; }
|
||||
.card.locked { opacity: .55; }
|
||||
.sec-head .btn { padding: 3px 12px; font-size: 13px; }
|
||||
|
||||
/* ---------- Аккаунт ---------- */
|
||||
.authbox { max-width: 520px; display: grid; gap: 16px; }
|
||||
.authbox .form { max-width: none; }
|
||||
.text {
|
||||
width: 100%; font: inherit; color: var(--fg); background: var(--panel2); border: 1px solid var(--line); border-radius: 10px; padding: 10px 12px;
|
||||
}
|
||||
.text:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
|
||||
.msg { padding: 10px 14px; border-radius: 10px; font-weight: 550; border: 1px solid transparent; }
|
||||
.msg.ok { background: color-mix(in srgb, var(--ok) 16%, transparent); border-color: var(--ok); }
|
||||
.msg.err { background: color-mix(in srgb, var(--bad) 16%, transparent); border-color: var(--bad); }
|
||||
.linkbtn { border: 0; background: none; padding: 0; color: var(--accent); font: inherit; font-weight: 600; cursor: pointer; text-decoration: underline; }
|
||||
.linkbtn:hover { filter: brightness(1.15); }
|
||||
.danger-zone { border-color: var(--bad); }
|
||||
|
||||
Reference in New Issue
Block a user