Files
transcriber/tasks/items/server-side-login-state.md
T
av 8739b18a9f tasks: очередь расставлена от базы к деталям
- порядок беклога и роадмапа назначен слоями: проверки, которым можно
  верить → долги входа → владелец записи и контракт API → конвейер под
  тестами → приложение и возможности поверх; у каждого движения записана
  причина;
- заведены восемь задач под пункты «Завершения», которых не закрывала ни
  одна запись, — цель any-audio-source была без задач вовсе;
- у четырёх задач сняты критерии, требовавшие того, что делает задача ниже
  по очереди; исправлены ссылки на несуществующий repo/sqlite и на
  отменённую разведку об очереди.
2026-08-12 20:48:53 +03:00

55 lines
4.4 KiB
Markdown

# 🐞 Вести учёт употреблённых состояний входа на сервере
- **Тип:** fix
- **Категория:** Очередь — Тот же файл и та же спека, что у строки выше.
- **Зачем:** Одноразовость возврата держится на уборке куки, то есть на браузере: сервер не помнит, какие состояния уже потрачены.
Найдено ревью задачи `oidc-login` 2026-08-12, отчёт триажа —
[review/report.md](../../openspec/changes/archive/2026-08-12-oidc-login/review/report.md),
остаток пункта 4.
Носитель состояния здесь — кука, которую сервис ставит на время входа: в ней
лежат выданное состояние и проверочный код, и по ней сверяется возврат.
Спека требует, чтобы состояние было одноразовым: возврат с уже употреблённым
отвергается наравне с невыданным. Сегодня это выполняется тем, что носитель
состояния убирается у браузера на возврате — и для обычного человека этого
достаточно: второй раз тот же адрес возврата сверку не пройдёт.
Чего это не закрывает: тот, кто носитель контролирует, поставит его себе заново
и повторит возврат. Отказ тогда наступит только потому, что код у провайдера
одноразовый, — то есть гарантия перенесена на внешнюю систему, чего норма не
допускает.
Цена сегодняшнего состояния невелика, поэтому задача и отложена: код живёт
минуты, а вход у провайдера всё равно нужен. Цена решения — своё хранение
состояний со сроком жизни и его чистка.
## Воспроизведение
1. Пройти вход до конца: получить сессию по возврату от провайдера.
2. Поставить носитель состояния заново — тем же значением, которое сервис выдавал
на первом шаге.
3. Повторить тот же запрос возврата.
4. Сверка состояния проходит, и запрос уходит в обмен. Отказ наступает только
потому, что код у провайдера одноразовый, — то есть одноразовость держит
внешняя система, а не сервис.
## Затрагивает
- обработчики начала входа и возврата;
- место хранения употреблённых состояний: своя коллекция хранилища либо память
процесса — выбор входит в задачу;
- дельта-спека `access`, требование «Вход через внешнего провайдера» — сценарий
«Возврат нельзя переиграть» получает настоящий оракул.
## Критерии приёмки
- Повторный возврат с тем же состоянием отвергается, даже если носитель
восстановлен вручную. Оракул — тест: пройти вход, затем повторить тот же
возврат с заново поставленным носителем; сессия не открывается.
- Состояния не копятся без предела. Оракул — тест либо чтение кода: у записи
состояния есть срок жизни, и просроченные убираются.
- Вход по-прежнему проходит целиком. Оракул — существующий тест входа через
подставного провайдера остаётся зелёным.