mirror of
https://github.com/Matysh/houseplan-card
synced 2026-07-31 08:28:31 +00:00
v1.46.0: full external audit of v1.45.4 — HP-1454-01 … -10
HP-1454-01 (high, release blocker): an uploaded SVG plan opened directly is a top-level document of Home Assistant's own origin, so a <script> inside it reaches the session's localStorage and API. Uploading needs write access, which by default every authenticated user has. SVG responses now carry a sandbox CSP; only SVG, because a CSP on a PDF can break the browser's viewer and a raster image has nothing to disable. Verified in Chromium both ways: the script runs without the header and does not with it. HP-1454-02: attachment uploads wrote straight to <marker>/<filename>, outside the config transaction — a cancelled dialog or a rejected save left the stored url serving new bytes, and every new icon shared one 'new' folder, so two of them attaching manual.pdf pointed at one file. Uploads take a free name, a new icon gets a per-dialog staging folder promoted on an accepted save, and config/set collects superseded and aged-orphan attachments like it does plans. HP-1454-03: the debounce spaced out the starts of a write, not the writes. A save slower than 500 ms let the next edit go out with the same expected_rev; the server accepted the first, rejected the second, and the conflict handler reloaded over the local copy. Writes are chained now — one in flight, each with the revision the previous returned. HP-1454-04: _openPairsCache keyed on room ids and links only, so an aspect change or a dragged vertex left open boundaries and their glow cuts at old coordinates. It keys on the rendered model object now — the same invalidation the model cache already has, not a second strategy. The fingerprint also gained an O(1) geometry roll-up per room. HP-1454-05: outer collections were capped, inner ones were not. Limits for poly points, open_to, controls, pdfs, text and url lengths, plus a total serialized size cap; legacy is dropped server-side. HP-1454-06: upload streams to a temp file and downloads use FileResponse, so a 50 MB manual no longer costs ~100 MB of RSS per transfer. HP-1454-07: spaceModels() dropped room.settings, so the static card ignored the per-room fill override. HP-1454-08: layout had no revision on point-wise writes and no event, leaving static cards stale forever; it now keeps a revision, returns it and fires houseplan_layout_updated. HP-1454-09: repair cleanup only walked existing spaces, so a deleted space kept its warning. HP-1454-10: serialize-javascript pinned past two advisories. Tests: smoke_svg_sandbox (proves both directions), smoke_config_writer and smoke_render_parity (both verified failing against a v1.45.4 build), six pure tests for attachment collection and inner limits, four HA-harness tests for the CSP, non-overwriting uploads, the size cap and layout revisions. Docs: CHANGELOG.md + CHANGELOG.ru.md + ARCHITECTURE.md + TESTING.md + STATUS.md.
This commit is contained in:
@@ -6,6 +6,81 @@
|
||||
> **Правило проекта:** оба файла пополняются в одном коммите с самим
|
||||
> изменением — как и остальная документация (см. docs/STATUS.md).
|
||||
|
||||
## v1.46.0 — 2026-07-28 (полный внешний аудит v1.45.4: HP-1454-01 … -10)
|
||||
|
||||
**Безопасность**
|
||||
|
||||
- **Загруженный SVG-план больше не является живым документом origin вашего
|
||||
Home Assistant (HP-1454-01, high — блокер релиза).** Внутри карточки план
|
||||
подключён через `<image>`, где скрипты не выполняются; но тот же URL,
|
||||
открытый напрямую, становился документом верхнего уровня в origin самого HA,
|
||||
и `<script>` в нём мог читать `localStorage` сессии и обращаться к API. Для
|
||||
загрузки нужно право записи, а оно по умолчанию есть у каждого
|
||||
аутентифицированного пользователя, и подписанную ссылку несложно передать
|
||||
администратору. Ответы с SVG теперь несут заголовок Content-Security-Policy
|
||||
`sandbox`, который помещает документ в opaque origin. Только SVG — CSP на PDF
|
||||
способен сломать встроенный просмотрщик браузера, а растровая картинка ничего
|
||||
выполнить не может. Для существующих планов ничего не меняется: карточка
|
||||
рисует их ровно как раньше.
|
||||
|
||||
**Целостность данных**
|
||||
|
||||
- **Инструкция, приложенная к устройству, больше не затирает предыдущую
|
||||
(HP-1454-02).** Загрузка писала прямо в `<маркер>/<имя файла>`, вне
|
||||
транзакции конфигурации: отмена диалога или отвергнутое сохранение оставляли
|
||||
сохранённую ссылку указывающей на новые байты. А все новые иконки грузили в
|
||||
одну общую папку, поэтому две с файлом `manual.pdf` начинали ссылаться на
|
||||
один физический файл. Теперь загрузка занимает свободное имя и никогда не
|
||||
перезаписывает, новая иконка получает собственную промежуточную папку, файлы
|
||||
из которой переезжают к настоящей иконке при принятом сохранении, а загрузка,
|
||||
которую никто не сохранил, убирается через час.
|
||||
- **Две быстрые правки больше не теряют вторую (HP-1454-03).** Debounce
|
||||
разносил старты сохранения, а не сами сохранения. Если одно длилось дольше
|
||||
полусекунды — занятый сервер, медленная связь, — следующая правка уходила с
|
||||
той же ревизией, сервер принимал первую и отклонял вторую, а обработчик
|
||||
конфликта перечитывал серверную копию поверх локальной. Правка исчезала, и
|
||||
сообщение винило «другое окно», которого не было. Записи сериализованы: по
|
||||
одной за раз, каждая с ревизией, которую вернула предыдущая.
|
||||
|
||||
**Корректность и пределы**
|
||||
|
||||
- **Открытые границы снова следуют за геометрией (HP-1454-04).** Их кэш
|
||||
ключевался только по id комнат и связям, поэтому смена пропорций
|
||||
пространства или перетаскивание вершины оставляли открытые границы — и свет,
|
||||
который через них проходит, — в старых координатах до перезагрузки. Ключом
|
||||
стала сама отрисованная модель, из которой они и вычисляются.
|
||||
- **Конфигурацию больше нельзя сделать сколь угодно тяжёлой (HP-1454-05).**
|
||||
Внешние коллекции были ограничены, вложенные — нет. Полигон на 150 000 точек
|
||||
или список из 100 000 идентификаторов проходили валидацию, а потом каждый
|
||||
рендер по ним ходил. Появились пределы на вершины полигона, связи открытых
|
||||
границ, управляемые сущности, вложения, длину текста и ссылок, плюс общий
|
||||
предел размера сериализованной конфигурации. Устаревшее поле `segments`
|
||||
отбрасывает сервер, а не надежда на современный клиент.
|
||||
- **Большие файлы передаются потоком, а не через память (HP-1454-06).**
|
||||
Инструкция на 50 МБ целиком читалась в память на приёме и ещё раз на отдаче;
|
||||
пара параллельных скачиваний — заметная нагрузка на слабый хост Home
|
||||
Assistant. Загрузка пишется во временный файл потоком, отдача идёт с диска.
|
||||
|
||||
**Согласованность**
|
||||
|
||||
- **Статическая карточка пространства учитывает настройки заливки комнаты
|
||||
(HP-1454-07).** Она строит модель другой функцией, и настройки комнаты в неё
|
||||
не переносились — комната, которой вы выключили заливку, всё равно
|
||||
закрашивалась.
|
||||
- **Перемещение иконки сразу видно на статической карточке (HP-1454-08).**
|
||||
Layout — отдельное состояние без ревизии и без события: перетаскивание на
|
||||
полной карточке оставляло соседнюю статическую со старой позицией до
|
||||
изменения конфигурации или перезагрузки страницы. Теперь записи layout хранят
|
||||
ревизию, возвращают её и сообщают о себе — заодно оптимистическая блокировка
|
||||
на полной записи layout начала что-то значить, ведь точечная запись раньше
|
||||
сбрасывала счётчик.
|
||||
- **Предупреждение о пропавшем плане исчезает вместе с пространством
|
||||
(HP-1454-09).** Уборка смотрела только на существующие пространства, поэтому
|
||||
удаление или переименование оставляло предупреждение в «Ремонте» навсегда.
|
||||
- Сборка: `serialize-javascript` поднят выше двух advisory (HP-1454-10). В
|
||||
рантайме недостижим, production-зависимости и так были чисты, но это одна
|
||||
строка.
|
||||
|
||||
## v1.45.4 — 2026-07-28 (ревью v1.45.3: R5-1, R5-2)
|
||||
- **Частично успешный ответ на подпись больше не пропускает выдержку (R5-1).**
|
||||
Бэкенд подписывает каждый путь независимо: тот, что подписать не удалось,
|
||||
|
||||
Reference in New Issue
Block a user