учёт: заведён урожай ревью входа по конфигу
- пять задач партии review-2026-08-23: многозначность Remote-Name и Remote-Email, мелочи входа, механизация правила о зависимостях конфига, снятие мёртвого читателя .env, управляющие знаки в расширении - две существующие разведки дополнены находками того же прогона: адрес объекта в тексте отказа SpeechKit и выводимость имени копии из журнала
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
# 🐞 Судить многозначность Remote-Name и Remote-Email тем же правилом, что и логин
|
||||
|
||||
- **Тип:** fix
|
||||
- **Категория:** Очередь — Правило узнавания правится там же, где личность связывается с учётной записью: обе задачи трогают один сбор contract.Identity
|
||||
- **Зачем:** чужой адрес, занятый первым пришедшим, навсегда и молча оставляет без почты настоящего владельца: EnsureUser найденную запись не переписывает, ветвь отката заводит владельца без почты и без строки журнала
|
||||
- **Теги:** review-2026-08-23
|
||||
|
||||
Многозначный `Remote-User` даёт `401` — многозначный `Remote-Email` даёт `200`,
|
||||
и в базу ложится первое значение. Правило узнавания судит логин и не судит
|
||||
остальные заголовки личности.
|
||||
|
||||
Один и тот же адрес почты, занятый чужим логином, достаётся первому пришедшему
|
||||
навсегда: `EnsureUser` найденную запись не переписывает, а ветвь отката
|
||||
уникальности заводит настоящего владельца **без почты** — и делает это молча,
|
||||
без строки журнала.
|
||||
|
||||
Нашёл прогон ревью `config-test-headers-login` 2026-08-23, оракул воспроизведён.
|
||||
|
||||
## Воспроизведение
|
||||
|
||||
Свой падающий сценарий, прогнан на настоящей поверхности сервиса (`setupEnv` +
|
||||
`AppChain`, база SQLite во временном каталоге, маршрут `/app/me`). Два шага:
|
||||
|
||||
1. Запрос с `Remote-User: squatter` и `Remote-Email: victim@corp.example` с
|
||||
доверенного адреса → `200`, `SELECT email FROM users WHERE
|
||||
provider_login='squatter'` → `victim@corp.example`.
|
||||
2. Запрос настоящего владельца `Remote-User: victim`, `Remote-Email:
|
||||
victim@corp.example` → `200`, `SELECT email … WHERE provider_login='victim'`
|
||||
→ `""`, строк журнала о занятом адресе ноль.
|
||||
|
||||
Ожидалось: многозначный заголовок судится тем же правилом, что и логин, а откат
|
||||
по занятому адресу виден владельцу сервиса строкой журнала.
|
||||
|
||||
## Затрагивает
|
||||
|
||||
- `internal/controller/http/identity.go:134-138` — сбор `contract.Identity` из
|
||||
заголовков: `Login` берётся из проверенного перечня значений, `Name` и `Email`
|
||||
— через `Header.Get`, то есть первым значением без суждения;
|
||||
- `internal/adapter/repo/sqlite/identity.go:77-110` — ветвь отката уникальности
|
||||
почты: заводит запись с пустым адресом и не пишет ни строки;
|
||||
- требование спеки `access`: сегодня оно нормирует многозначность только для
|
||||
`Remote-User`;
|
||||
- `docs/security.md`, раздел «Периметр» — что именно сервис принимает от контура
|
||||
на веру.
|
||||
|
||||
## Критерии приёмки
|
||||
|
||||
- Многозначный `Remote-Email` даёт пустое значение, а не первое. **Оракул:**
|
||||
тест на настоящей поверхности сервиса — запрос с двумя значениями `Remote-Email`
|
||||
заводит учётную запись с пустым адресом; тот же тест на `Remote-Name`.
|
||||
- Узнавание принимает однозначные `Remote-Name` и `Remote-Email` по-прежнему.
|
||||
**Оракул:** тот же тест — одно значение доезжает до колонки без изменений.
|
||||
- Ветвь отката уникальности почты оставляет строку журнала видимого уровня.
|
||||
**Оракул:** тест хранилища — второй логин с занятым адресом заводится, и в
|
||||
журнале стоит строка о занятом адресе; значения адреса в ней нет.
|
||||
|
||||
## Рамки
|
||||
|
||||
Правится боевой путь узнавания, а не отладочная подстановка заголовков.
|
||||
Владение адресом почты между учётными записями не пересматривается: занятый
|
||||
адрес по-прежнему достаётся тому, кто завёлся первым, — задача только о том,
|
||||
чтобы это перестало происходить молча и по многозначному заголовку.
|
||||
|
||||
Отдельно: требование к контуру про `X-Forwarded-For` не записано ни в модели
|
||||
угроз, ни в спеке и этой правкой не покрывается — правило «справа налево до
|
||||
первого недоверенного» верно постольку, поскольку правое значение приписал
|
||||
прокси, а шаблон лежит в `files/caddyproxy/Caddyfile.template` репозитория
|
||||
`pet-project-server`. Отдельной записи не заводится — решение владельца.
|
||||
Reference in New Issue
Block a user