security: стабилизационный аудит Lua plugin system

Исправления:
- Install: идемпотентность (no duplicates in InstalledPlugins)
- ReloadPlugins: StopSchedulers + CallShutdownHooks перед CloseRuntimes
- StopSchedulers: обнуление scheduler=nil после остановки
- Scheduler.Stop: обнуление tasks после wg.Wait
- Lua sandbox: блокировка package.loadlib/seeall/preload/loaders/loaded/path/cpath/config/searchpath
- Lua sandbox: блокировка load (глобальная функция)
- CallPluginFunction: валидация funcName (regex [a-zA-Z_][a-zA-Z0-9_]*, max 3 segments)
- CallPluginFunction: убрана строковая сборка Lua-кодa, вызов через PCall напрямую
- PluginPage.svelte: проверка e.source === iframeEl.contentWindow
- PluginPage.svelte: type checking для msg.source, msg.action

Тесты:
- security_test.go: 18 новых тестов (sandbox, lifecycle, validation)
- Все существующие тесты проходят

Документация:
- docs/plugins-security.md: модель безопасности, sandbox, протокол, lifecycle
This commit is contained in:
2026-06-07 19:19:44 +08:00
parent c443ca23c5
commit 4df83cd361
9 changed files with 1305 additions and 54 deletions
+7 -2
View File
@@ -35,10 +35,15 @@
}
}
// Handle messages from iframe
// Handle messages from iframe — only accept from our own iframeEl
function handleIframeMessage(e) {
// Verify the message comes from our iframe (srcdoc = same origin)
if (!iframeEl || !iframeEl.contentWindow || e.source !== iframeEl.contentWindow) return
const msg = e.data
if (!msg || !msg.source || msg.source !== 'calendar-plugin') return
if (!msg || typeof msg !== 'object') return
if (!msg.source || msg.source !== 'calendar-plugin') return
if (!msg.action || typeof msg.action !== 'string') return
switch (msg.action) {
case 'ready':