вход переехал на доверенный заголовок Authelia вместо собственного OIDC
- пришедшего называет заголовок Remote-User от прокси, и верят ему только с адреса из перечня trusted_proxies; своего входа у сервиса не осталось — ни корня /auth, ни кук, ни срока сессии, ни секрета клиента в конфиге и в базе - учётная запись заводится первым обращением: EnsureUser в пакете хранилища, шаг схемы 202608220001 с колонкой provider_login и снятыми правилами users - cmd/oidcstub заменён на cmd/devtools с подкомандой proxy; заодно закрыт унаследованный DL3066 — пользователь образа назван числом
This commit is contained in:
@@ -0,0 +1,143 @@
|
||||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: Файл отдаётся ссылкой
|
||||
|
||||
Сервис SHALL отдавать файл записи ссылкой, которую строит хранилище по самой
|
||||
записи, **и только узнанному отправителю**. Поле файла MUST быть помечено
|
||||
защищённым: без этого ссылка открывает запись любому, кто её знает, и знание
|
||||
ссылки становится правом. Отданный файл MUST совпадать с принятым по длине.
|
||||
|
||||
Одной пометки мало: защищённый файл судится **коротким токеном файла**, который
|
||||
узнанный отправитель берёт у хранилища, — и правилом просмотра коллекции.
|
||||
Правило MUST пускать только владельца файла: незаданное означает «только владелец
|
||||
панели», и тогда файла не получит и узнанный, а прежнее «всякий узнанный»
|
||||
отдавало чужое аудио тому, кто знает идентификатор записи.
|
||||
|
||||
Токен файла хранилище выдаёт **на предъявителя**, а не на файл, и о файле при
|
||||
выдаче не спрашивает. Значит владельца судит переход по ссылке, а не выдача
|
||||
токена: отказ наступает там, и требовать его от выдачи значит требовать
|
||||
механизма, которого нет.
|
||||
|
||||
Отсюда порядок для потребителя: узнавание → токен файла → ссылка с этим токеном.
|
||||
Адрес выдачи токена лежит в пространстве хранилища, и узнавание по заголовку MUST
|
||||
на нём работать — иначе файл записи недостижим для браузера вовсе. Одного
|
||||
заголовка при этом мало: без токена ссылка файла не отдаёт, и это свойство
|
||||
хранилища, а не недосмотр.
|
||||
|
||||
Конвейер расшифровки этим не затронут: он читает файл из файловой системы
|
||||
хранилища, а не по ссылке.
|
||||
|
||||
Ссылка на несуществующую запись MUST отвечать отказом, а не пустым файлом.
|
||||
|
||||
**Ссылка сама по себе и есть право пройти по ней**, и потому она MUST не попадать
|
||||
ни в журнал, ни в метку метрики, ни в ответ отправителю. Имя, под которым файл
|
||||
лёг в хранилище, из журнала выводимо быть не должно: журнал уезжает в собранные
|
||||
логи, откуда строку не убрать, и оттуда ссылка на чужую запись работала бы
|
||||
бессрочно.
|
||||
|
||||
Защищённое поле сужает это право, но не отменяет запрета: право пройти теперь
|
||||
требует ещё и узнавания, а строка журнала со ссылкой по-прежнему собирала бы
|
||||
половину ключа.
|
||||
|
||||
Отсюда требование к отказам: сообщение об отказе хранилища MUST не выходить за
|
||||
пределы хранилища дословно. Отказ чтения и отказ укладки называют ключ файла
|
||||
целиком, а отказ выгрузки во внешнее хранилище — полный адрес объекта; и то и
|
||||
другое кончается в журнале и собирает ссылку не хуже успешного пути.
|
||||
|
||||
Что именно журнал приёма пишет ради прослеживаемости, нормирует capability
|
||||
`intake`.
|
||||
|
||||
#### Scenario: Файл забирают по ссылке
|
||||
|
||||
- **GIVEN** запись принята и её файл лежит в хранилище
|
||||
- **AND** забирающий узнан и взял токен файла
|
||||
- **WHEN** ссылку на файл запрашивают с этим токеном
|
||||
- **THEN** приходит тот же файл, и его длина совпадает с длиной принятого
|
||||
|
||||
#### Scenario: Неузнанному файл не отдаётся
|
||||
|
||||
- **GIVEN** запись принята и её файл лежит в хранилище
|
||||
- **WHEN** ссылку на файл запрашивают неузнанным
|
||||
- **THEN** приходит отказ, а содержимого записи в ответе нет
|
||||
|
||||
#### Scenario: Токен файла выдаётся узнанному по заголовку
|
||||
|
||||
- **GIVEN** запрос идёт с доверенного адреса с заголовком `Remote-User`
|
||||
- **WHEN** он просит у хранилища токен файла
|
||||
- **THEN** токен выдаётся
|
||||
|
||||
#### Scenario: Конвейер читает файл без узнавания
|
||||
|
||||
- **GIVEN** запись принята и ждёт расшифровки
|
||||
- **WHEN** шаг конвейера берётся за неё
|
||||
- **THEN** файл читается из файловой системы хранилища и шаг проходит
|
||||
|
||||
#### Scenario: Ссылка ведёт в никуда
|
||||
|
||||
- **WHEN** запрашивают ссылку на запись, которой нет
|
||||
- **THEN** приходит отказ, а не пустой ответ
|
||||
|
||||
#### Scenario: По журналу ссылку не собрать
|
||||
|
||||
- **GIVEN** запись принята и прошла конвейер
|
||||
- **WHEN** читают журнал сервиса целиком
|
||||
- **THEN** имени, под которым файл лёг в хранилище, в нём нет
|
||||
|
||||
#### Scenario: Отказ чтения файла не называет его ключ
|
||||
|
||||
- **GIVEN** файл записи не читается из хранилища
|
||||
- **WHEN** шаг конвейера берётся за эту запись и отказывает
|
||||
- **THEN** отказ называет запись её идентификатором и не несёт имени файла
|
||||
|
||||
### Requirement: Файл записи сужается владельцем наравне с задачей
|
||||
|
||||
Хранилище SHALL держать владельца и у файла записи — той же связью с учётной
|
||||
записью, — и правило просмотра файлов MUST пускать к файлу только его владельца.
|
||||
|
||||
Владелец файла MUST назначаться при приёме, из узнанного предъявителя, а колонка
|
||||
файла MUST не допускать пустого значения наравне с колонкой записи. Прежде пустое
|
||||
значение оставалось у файлов, заведённых конвейером для записи без владельца;
|
||||
таких записей больше не заводится, и разное правило у записи и у её файла
|
||||
читалось бы как недосмотр.
|
||||
|
||||
Файл, заведённый шагом конвейера, — приведённую копию заводит именно он —
|
||||
MUST получать владельца своей записи. Иного источника владельца у файла нет, и
|
||||
шаг, оставивший его пустым, упрётся в отказ сохранения: запись накопит отказы и
|
||||
остановится признаком на первом же приведении.
|
||||
|
||||
Ссылки на файлы у записи две — на принятую копию и на приведённую, — и обе живут
|
||||
до конца, но владелец файла MUST по-прежнему лежать своей колонкой, а не
|
||||
выводиться через запись: файл переживает свою запись, и заведённый шагом до
|
||||
сохранения записи он остаётся с владельцем и без ссылки.
|
||||
|
||||
Отказ наступает **на переходе по ссылке**, а не на выдаче токена файла: токен
|
||||
хранилище выдаёт на предъявителя, а не на файл, и о файле при выдаче не
|
||||
спрашивает вовсе. Требовать отказа при выдаче значит требовать механизма,
|
||||
которого нет, — а проверка, написанная под такое требование, зеленела бы, не
|
||||
касаясь пути, по которому аудио и уходит.
|
||||
|
||||
#### Scenario: Чужой файл не отдаётся
|
||||
|
||||
- **GIVEN** запись принята одним узнанным
|
||||
- **WHEN** другой узнанный идёт по ссылке на файл этой записи со своим токеном
|
||||
- **THEN** содержимого он не получает
|
||||
|
||||
#### Scenario: Свой файл отдаётся
|
||||
|
||||
- **GIVEN** человек принял запись
|
||||
- **WHEN** он идёт по ссылке на файл своей записи со своим токеном
|
||||
- **THEN** содержимое отдаётся
|
||||
|
||||
#### Scenario: Файл без владельца не сохраняется
|
||||
|
||||
- **GIVEN** сервис поднят
|
||||
- **WHEN** файл записи пытаются сохранить с пустым владельцем
|
||||
- **THEN** хранилище его не сохраняет
|
||||
|
||||
#### Scenario: Приведённая копия получает владельца записи
|
||||
|
||||
- **GIVEN** запись с владельцем дошла до приведения
|
||||
- **WHEN** шаг заводит приведённую копию файла
|
||||
- **THEN** владельцем копии стоит владелец записи
|
||||
- **AND** шаг завершается без отказа
|
||||
|
||||
Reference in New Issue
Block a user