refactor+fix v1.10.0: аудит — гонки записи (asyncio.Lock, атомарный rev), точечный layout/update вместо layout/set (анти last-writer-wins), layout/delete, safeUrl против XSS в link/pdfs, fetchWithAuth, KEY_HASS, стриминговый лимит upload, модульность (styles/types/devices), динамические пространства в GUI-редакторе, чистка мёртвого кода (file/set, GROUP_TITLES)

This commit is contained in:
Matysh
2026-07-05 20:58:33 +03:00
parent 7cd9a56f5a
commit e7cf0416be
16 changed files with 1991 additions and 1874 deletions
+16 -1
View File
@@ -2,7 +2,7 @@ import test from 'node:test';
import assert from 'node:assert/strict';
import {
lqiColor, snapToGrid, segKey, samePoint, pointInPolygon, markerIdForBinding, averageLqi,
fitView, declump,
fitView, declump, safeUrl,
} from '../test-build/logic.js';
import { iconFor } from '../test-build/rules.js';
@@ -112,3 +112,18 @@ test('averageLqi: пусто → null, иначе округлённое сре
assert.equal(averageLqi([100, 200]), 150);
assert.equal(averageLqi([1, 2, 2]), 2);
});
test('safeUrl: допускает http(s) и относительные, режет опасные схемы', () => {
assert.equal(safeUrl('https://example.com/a?b=1'), 'https://example.com/a?b=1');
assert.equal(safeUrl('http://x.ru'), 'http://x.ru');
assert.equal(safeUrl('//cdn.x.ru/f.pdf'), '//cdn.x.ru/f.pdf');
assert.equal(safeUrl('/houseplan_files/files/m1/doc.pdf?v=1'), '/houseplan_files/files/m1/doc.pdf?v=1');
assert.equal(safeUrl('docs/manual.pdf'), 'docs/manual.pdf');
assert.equal(safeUrl('javascript:alert(1)'), null);
assert.equal(safeUrl('data:text/html,<script>'), null);
assert.equal(safeUrl('vbscript:x'), null);
assert.equal(safeUrl(''), null);
assert.equal(safeUrl(null), null);
assert.equal(safeUrl(undefined), null);
assert.equal(safeUrl(' https://x.ru '), 'https://x.ru');
});