mirror of
https://github.com/Matysh/houseplan-card
synced 2026-10-02 04:38:55 +00:00
fix: reject absolute urls in the content resolver, register the mutants
Review CODE-REVIEW-225-r1. M1: urlsplit(url).path was trusted even when the url carried a scheme or an authority, so "https://evil.example/houseplan_files/files/m1/doc.pdf" resolved onto a local file while _looks_internal kept calling it external — the mirror image of the inconsistency this resolver exists to prevent. Only a same-document reference is resolved by its path now. M2: the three mutants the spec described are registered in scripts/mutation-gate.mjs instead of living as a one-off manual run. The traversal entry drops both structural checks at once on purpose: taken one at a time the defence is layered (sanitize_marker_id turns ".." into "misc") and the mutant would be equivalent — established by running it. Issue: #225 User-Visible: no
This commit is contained in:
@@ -703,6 +703,47 @@ export const MUTANTS = [
|
||||
replace: ' .dev:not(.unavail):hover {',
|
||||
}],
|
||||
},
|
||||
{
|
||||
id: 'internal-path-ignores-query',
|
||||
guard: 'node scripts/backend-test-guard.mjs issue_225',
|
||||
because: 'разбор url строкой вместо urlsplit возвращает баг #225: кэш-бастер '
|
||||
+ '?v=… делает имя файла не равным самому себе, ссылка читается как '
|
||||
+ 'внутренняя-но-неканоническая, и бэкап с вложением снова не импортируется',
|
||||
patches: [{
|
||||
file: 'custom_components/houseplan/import_export.py',
|
||||
find: ' parsed = urlsplit(url)\n if parsed.scheme or parsed.netloc:\n return None\n url = parsed.path',
|
||||
replace: ' url = url.split("?", 1)[0]',
|
||||
}],
|
||||
},
|
||||
{
|
||||
id: 'internal-path-trusts-foreign-host',
|
||||
guard: 'node scripts/backend-test-guard.mjs issue_225',
|
||||
because: 'доверие к path при наличии scheme/netloc позволяет '
|
||||
+ '"https://evil.example/houseplan_files/files/m1/doc.pdf" разрешиться в локальный '
|
||||
+ 'файл, хотя _looks_internal считает такую ссылку внешней (ревью r1, M1)',
|
||||
patches: [{
|
||||
file: 'custom_components/houseplan/import_export.py',
|
||||
find: ' if parsed.scheme or parsed.netloc:\n return None',
|
||||
replace: ' if False:\n return None',
|
||||
}],
|
||||
},
|
||||
{
|
||||
id: 'internal-path-allows-traversal',
|
||||
guard: 'node scripts/backend-test-guard.mjs issue_225',
|
||||
because: 'структурные проверки пути — единственное, что режет traversal после '
|
||||
+ 'отделения query; снимать их нельзя. Мутант снимает обе сразу: по одной '
|
||||
+ 'защита эшелонирована (sanitize-сравнение ловит "..") и мутант был бы '
|
||||
+ 'эквивалентным — выяснено прогоном при реализации',
|
||||
patches: [{
|
||||
file: 'custom_components/houseplan/import_export.py',
|
||||
find: ' if not raw_name or "/" in raw_name:\n return None',
|
||||
replace: ' raw_name = raw_name.split("/")[-1]\n if not raw_name:\n return None',
|
||||
}, {
|
||||
file: 'custom_components/houseplan/import_export.py',
|
||||
find: ' tail = url[len(prefix):].split("/")\n if len(tail) != 2:\n return None',
|
||||
replace: ' tail = url[len(prefix):].split("/")[-2:]',
|
||||
}],
|
||||
},
|
||||
];
|
||||
|
||||
// --- механика ---------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user