Such Music

安全模型

沙箱隔离、权限声明与敏感操作确认机制

安全模型

Such 插件系统通过沙箱隔离 + 权限声明 + 敏感操作确认三层机制保障用户安全。

沙箱执行机制

插件代码不是直接运行在 Node.js 环境中,而是通过 Function 构造函数在受限作用域中执行:

new Function('window', 'suchmusic', code)(sandboxWindow, suchmusicAPI)

这意味着插件代码中:

  • 无法访问 Node.js 内置模块(fschild_processpath 等)
  • 无法访问 Electron API(ipcRenderershell 等)
  • 无法访问 全局 window 对象(被替换为受限的 sandboxWindow
  • 无法使用 require()import(ESM/CJS 均不可用)

受限 window 对象

插件中可访问的 window 只包含:

属性说明
window.source插件元数据容器,开发者向此赋值注册插件
window.notify(message, type?)向用户发送桌面通知
window.console被拦截的 console(输出转到宿主日志)
// ✅ 可用
window.notify('操作完成', 'success')
console.log('输出到宿主日志')

// ❌ 不可用
// require('fs')
// process.cwd()
// document.querySelector()

敏感操作确认机制

涉及本地系统访问的 API 属于敏感操作,每次调用前都需要用户确认。

哪些 API 是敏感操作?

API原因
execProgram可执行任意本地程序
execTerminal可执行任意终端命令
fileOp可读写/删除任意本地文件
downloadFile可从网络下载文件到本地
writeMeta可修改音乐文件

确认流程

插件调用敏感 API
  → 宿主拦截,暂停执行
  → 向渲染进程发送确认请求
  → 展示确认弹窗(操作类型、详情)
  → 用户选择:确认 / 拒绝
  → 确认:继续执行 API
  → 拒绝:抛出 Error("用户拒绝了敏感操作: xxx")

批量合并 (防抖)

如果插件在短时间内连续调用多个敏感操作(如批量下载文件),宿主会通过 100ms 防抖 将多个操作合并为一次批量确认:

100ms 内调用了 5 个 fileOp('copy', ...)
  → 宿主将 5 个操作合并为 1 个批量确认窗口
  → 用户可逐条确认/拒绝,或一键全部确认/拒绝

"本次会话不再询问"

确认弹窗中提供"本次会话不再询问"选项。勾选后:

  • 该插件的同类操作在当前运行会话中不再弹出确认
  • 重启 Such 后恢复确认(安全设计)
  • 只跳过相同操作类型(如 fileOp),不影响其他类型

超时机制

确认弹窗有 30 秒超时。超时后自动拒绝,返回权限错误。避免因用户长时间不操作导致插件无限挂起。

歌单操作安全

歌单操作(createPlaylistaddToPlaylist 等)虽然不是敏感操作,但通过 IPC 请求-响应模式实现,有 15 秒超时。这种方式确保歌单修改在渲染进程侧执行,主进程只做转发。

开发者注意事项

  • 不要做危险操作:即使通过敏感操作确认,插件也不应执行 rm -rf、修改系统文件等破坏性操作
  • 告知用户操作目的:敏感操作的 detail 会自动显示在确认弹窗中,确保参数信息清晰可读
  • 不要尝试绕过沙箱Function 构造函数的参数已固定,无法通过 arguments.callee 等方式逃逸
  • 异步操作也要确认:每个敏感 API 调用独立确认,批量调用会被合并但不会跳过

On this page