Роадмап: web-access переименована под приложение, которое ставится на телефон; заведена цель ready-notification — уведомление о готовности без открытого приложения. Беклог: десять задач. Многопользовательская цепочка (oidc-login, record-ownership, telegram-account-link), веб (json-api-for-spa, spa-skeleton, upload-and-status-screen, records-list-screen, installable-pwa), уведомления через apprise и ntfy, разведка выбора фреймворка. Очередь: долги, хранилище, вход, приложение. Решение сменилось с htmx на SPA, поэтому conventions/web-ui.md снята целиком и оставлена честной строкой до итога разведки. Открытые вопросы архитектуры, границы паспорта и триггеры метки ревью приведены в соответствие.
51 lines
3.5 KiB
Markdown
51 lines
3.5 KiB
Markdown
# ✨ Пускать в приложение только после входа через OIDC
|
|
|
|
- **Тип:** feature
|
|
- **Категория:** Ядро
|
|
- **Зачем:** HTTP API открыт наружу без аутентификации: любой из интернета заводит задачи за наши деньги и читает чужие расшифровки по идентификатору.
|
|
- **Теги:** goal:multi-user, question
|
|
|
|
Двигает пункт 1 «Завершения» цели: неаутентифицированный запрос к записям не
|
|
проходит ни к странице, ни к API.
|
|
|
|
Провайдер — Authelia по OIDC. Своей регистрации и своих паролей не делаем, это
|
|
граница из [паспорта](../../docs/passport.md). Разграничения записей по владельцу
|
|
здесь ещё нет: после входа видно всё, что видно сейчас, — этим занимается
|
|
`record-ownership`.
|
|
|
|
## Затрагивает
|
|
|
|
- новые эндпоинты входа и выхода, обработка ответа провайдера;
|
|
- `POST /api/audio` и `GET /api/status/:id` — оба уходят за аутентификацию;
|
|
- `GET /health` и `GET /metrics` — решить и записать, остаются ли открытыми;
|
|
- хранение сессии: таблица или подписанная кука;
|
|
- секция конфигурации под провайдера: адрес, идентификатор клиента, секрет;
|
|
- `docs/security.md` — периметр меняется, и первая его строка перестаёт быть
|
|
верной;
|
|
- `config.dist.toml` и `internal/config`.
|
|
|
|
## Критерии приёмки
|
|
|
|
- Запрос к `POST /api/audio` и `GET /api/status/:id` без сессии получает отказ, а
|
|
не заводит задачу и не отдаёт текст. Оракул — тест на обоих эндпоинтах без
|
|
куки: код ответа 401 либо 302 на вход, тело без данных задачи.
|
|
- Сессия переживает перезапуск приложения. Оракул — тест: запрос с прежней кукой
|
|
после пересоздания сервера проходит.
|
|
- Выход из сессии закрывает доступ. Оракул — тест: после выхода тот же запрос
|
|
получает отказ.
|
|
- Секрет провайдера не попадает ни в лог, ни в ответ. Оракул — тест на отсутствие
|
|
значения секрета в записанном выводе логгера.
|
|
- Первая строка `docs/security.md` описывает новый периметр. Оракул — `task
|
|
gate`, шаг `docs.py check`.
|
|
|
|
## Рамки
|
|
|
|
Владельца у записи здесь не заводим и выборку не сужаем: после входа видно
|
|
столько же, сколько сейчас. Инвариант «бот отвечает только тем, кто в белом
|
|
списке» не трогаем — он живёт до `telegram-account-link`.
|
|
|
|
## Вопросы
|
|
|
|
Остаются ли `GET /health` и `GET /metrics` открытыми? Прокси и система сбора
|
|
метрик сессии не имеют, но и наружу их отдавать незачем.
|