跳到正文

权限系统 ​

涉及文件路径的 Bridge API 会先由 BridgeCore 的路径安全 spec 校验,被拒的请求不会触及文件系统,也不会触发 foobar2000 SDK 的路径副作用。路径被安全策略拒绝返回 PERMISSION_DENIED;参数形状或类型不对返回 INVALID_PARAMS。

权威计数来自当前 src/api/** 中 RegisterApi 路径安全 spec(形态为 { param, SecurityLevel::... }):

级别spec 条数含义
Read10普通文件系统只读校验
Write1严格写入目标(配置/临时目录策略)
MediaRead41媒体上下文只读校验
MediaWrite10媒体上下文写校验
FileWrite11通用文件写入(file.*)
合计7368 个唯一 API

六级权限模型 ​

级别说明校验逻辑
None不涉及文件路径无路径校验
Read只读文件系统操作禁止系统保护目录、设备路径与 .. 遍历
Write严格写入目标仅允许 PathSecurity 接受的配置/临时等写入目标
MediaRead读取媒体元数据/内容先走 Read 规则;媒体库/播放列表信任仅作为 Read 拒绝后的回退
MediaWrite修改媒体文件独立校验链:保护目录黑名单,再按严格写入目标/媒体库或播放列表成员/媒体库监视目录/与受信音频同目录的伴生文件依次放行。仅仅位于非系统盘不构成放行理由
FileWrite通用文件写入(file.*)独立校验链,并非 MediaWrite 超集:黑名单后按严格写入目标/媒体库监视目录/盘符寻址的非系统盘(UNC 不在此列)/媒体库或播放列表成员依次放行——不含伴生文件步。监视目录与非系统盘两步共同让 file.mkdir 与 file.write 能创建新路径

权限层级关系

None < Read < Write 是普通文件系统通道。 None < Read < MediaRead < MediaWrite 是媒体通道。 Write、MediaWrite 与 FileWrite 是三条独立写通道。

FileWrite 比 MediaWrite 宽

FileWrite 接受非系统盘上的任意路径,以及媒体库监视目录内的任意路径(含系统盘),是当前暴露面最宽的写通道。它之所以存在,是因为 file.* 操作的是任意文件而非媒体上下文中的文件,套用媒体写入规则会使新建文件与新建目录完全无法进行。审查主题时应优先审计这条通道。

错误响应 ​

json
{
  "success": false,
  "error": "file.read: path security denied for 'path': Access denied: protected system path",
  "code": "PERMISSION_DENIED"
}

被拒的路径本体不会回显。消息里只有方法名、出问题的参数(数组参数还带下标,形如 items[2].destination)和拒因,调用方据此能判断是哪个参数被拒,而宿主不会把文件系统位置泄漏到一个页面可能转发出去的 payload 里。

json
{
  "success": false,
  "error": "file.read: param 'path' must be a string",
  "code": "INVALID_PARAMS"
}
javascript
const result = await fb2k.invoke('file.read', { path: somePath });
if (!result.success) {
  if (result.code === 'PERMISSION_DENIED') {
    console.warn('路径被安全策略拒绝:', result.error);
  } else if (result.code === 'INVALID_PARAMS') {
    console.warn('参数在进入 handler 前被拒:', result.error);
  }
}

API 权限对照表 ​

Read — 只读文件系统(10 条) ​

API参数数组嵌套键说明
artwork.getFolderImagesdirectory——权威源:ArtworkApi.cpp
clipboard.writeFilespaths是—权威源:ClipboardApi.cpp
file.copysource——权威源:FileApi.cpp
file.copyAsyncitems是source权威源:FileApi.cpp
file.existspath——权威源:FileApi.cpp
file.getInfopath——权威源:FileApi.cpp
file.listpath——权威源:FileApi.cpp
file.readpath——权威源:FileApi.cpp
shell.openWithpath——权威源:ShellApi.cpp
shell.showInExplorerpath——权威源:ShellApi.cpp

Write — 严格写入目标(1 条) ​

API参数数组嵌套键说明
http.downloadsaveTo——权威源:HttpApi.cpp

MediaRead — 读取媒体文件(41 条) ​

API参数数组嵌套键说明
artwork.getAvailableArtworkpath——权威源:ArtworkApi.cpp
artwork.getAvailableTypespath——权威源:ArtworkApi.cpp
artwork.getBatchpaths是—权威源:ArtworkApi.cpp
artwork.getByPathpath——权威源:ArtworkApi.cpp
artwork.getFb2kUrlByPathpath——权威源:ArtworkApi.cpp
artwork.getFb2kUrlByPathBatchpaths是—权威源:ArtworkApi.cpp
artwork.getFb2kUrlByPathBatchitems是path权威源:ArtworkApi.cpp
artwork.getForTrackpath——权威源:ArtworkApi.cpp
artwork.getLyricspath——权威源:ArtworkApi.cpp
artwork.getMetadatapath——权威源:ArtworkApi.cpp
audio.analyzeBPMpath——权威源:AudioApi.cpp
audio.generateFullWaveformpath——权威源:AudioApi.cpp
audio.generateWaveformpath——权威源:AudioApi.cpp
discovery.executeContextMenuByPathtrackPath——权威源:DiscoveryApi.cpp
jitQueue.enqueueNexturl——权威源:QueueApi.cpp
jitQueue.playNowurl——权威源:QueueApi.cpp
jitQueue.preloadBatchurls是—权威源:QueueApi.cpp
library.getByPathpath——权威源:LibraryApi.cpp
lyrics.existspath——权威源:LyricsApi.cpp
lyrics.getpath——权威源:LyricsApi.cpp
metadata.probeBatchAsyncpaths是—权威源:MetadataApi.cpp
metadata.readpath——权威源:MetadataApi.cpp
metadata.readBatchpaths是—权威源:MetadataApi.cpp
metadata.readByPathpath——权威源:MetadataApi.cpp
metadata.readRawpath——权威源:MetadataApi.cpp
playback.playPathpath——权威源:PlaybackApi.cpp
playback.playPathspaths是—权威源:PlaybackApi.cpp
playcount.getpaths是—权威源:PlaycountApi.cpp
playcount.getBatchpaths是—权威源:PlaycountApi.cpp
playlist.addPathspaths是—权威源:PlaylistApi.cpp
playlist.addPathsAsyncpaths是—权威源:PlaylistApi.cpp
playlist.addPathsSequentialpaths是—权威源:PlaylistApi.cpp
playlist.replaceAllAndPlaypaths是—权威源:PlaylistApi.cpp
queue.addPathspaths是—权威源:QueueApi.cpp
rating.getpath——权威源:MetadataApi.cpp
replaygain.getpaths是—权威源:ReplayGainApi.cpp
replaygain.scanpaths是—权威源:ReplayGainApi.cpp
titleformat.evalpath——权威源:TitleformatApi.cpp
titleformat.evalBatchpaths是—权威源:TitleformatApi.cpp
titleformat.evalFieldspath——权威源:TitleformatApi.cpp
titleformat.evalFieldsBatchpaths是—权威源:TitleformatApi.cpp

MediaWrite — 修改媒体文件(10 条) ​

API参数数组嵌套键说明
lyrics.savepath——权威源:LyricsApi.cpp
metadata.embedArtworkpath——权威源:MetadataApi.cpp
metadata.removeEmbeddedArtpath——权威源:MetadataApi.cpp
metadata.removeFieldpath——权威源:MetadataApi.cpp
metadata.removeTagpath——权威源:MetadataApi.cpp
metadata.writepath——权威源:MetadataApi.cpp
metadata.writeBatchitems是path权威源:MetadataApi.cpp
playcount.setpath——权威源:PlaycountApi.cpp
rating.setpath——权威源:MetadataApi.cpp
replaygain.clearpaths是—权威源:ReplayGainApi.cpp

嵌套数组校验

metadata.writeBatch 的 items 是对象数组,系统会提取每个元素的 path 字段进行校验。

FileWrite — 通用文件写入(11 条) ​

API参数数组嵌套键说明
file.copydestination——权威源:FileApi.cpp
file.copyAsyncitems是destination权威源:FileApi.cpp
file.deletepath——权威源:FileApi.cpp
file.deleteAsyncpaths是—权威源:FileApi.cpp
file.mkdirpath——权威源:FileApi.cpp
file.movedestination——权威源:FileApi.cpp
file.movesource——权威源:FileApi.cpp
file.moveAsyncitems是destination权威源:FileApi.cpp
file.moveAsyncitems是source权威源:FileApi.cpp
file.renamepath——权威源:FileApi.cpp
file.writepath——权威源:FileApi.cpp

file.copy 的 source 走 Read、destination 走 FileWrite;file.move 两端均走 FileWrite。异步族沿用同一套分档:file.copyAsync 逐条校验 items[].source(Read)与 items[].destination(FileWrite),file.moveAsync 两个嵌套键都走 FileWrite,file.deleteAsync 的 paths 逐条走 FileWrite。逐条校验是 fail-fast:任一条被拒即整批失败返回 PERMISSION_DENIED,不派工。

自定义策略 API ​

API校验方式
shell.exec无命令白名单;可选 cwd 仍走 PathSecurity
shell.spawn无可执行白名单;绝对可执行路径与 cwd 做路径校验
console.log日志目录限制 + 保留设备名过滤 + .log / .txt 扩展名白名单
playlist.insertTracks参数为 playlist handle,不是原始文件路径

路径安全规则详解 ​

通用拦截 ​

  • 设备路径:\\.\...、\\?\...
  • 目录遍历:包含 ..
  • 空路径 / 相对路径:必须是绝对路径

Read ​

系统盘保护目录包括:

保护目录原因
C:\\Windows\\系统文件
C:\\Program Files\\程序文件
C:\\Program Files (x86)\\32 位程序文件
C:\\ProgramData\\系统配置数据

非系统盘在 Read 下通常放行,以支持 NAS / 便携版场景。

Write ​

仅允许严格写策略接受的目标目录;实践上为 foobar2000 配置目录与系统临时目录。

MediaRead ​

先执行 Read 规则,一旦通过即放行。因此非系统盘路径(含 UNC / NAS 共享)无需 查询媒体库或播放列表即可通过。

媒体上下文信任只是 Read 拒绝后的回退(实际场景为白名单之外的系统盘路径)。以下 任一条件成立即放行:

  • 该路径可被加入 foobar2000 媒体库,或
  • 该路径能解析到媒体库中的曲目,或
  • 该路径匹配某个播放列表中的曲目。该判定由完整覆盖全部播放列表的成员索引 支撑,没有扫描上限,实际存在的匹配总能命中。

MediaWrite ​

MediaWrite 不复用 Read 或 MediaRead 的入口,而是走自己的校验链。在通用拒绝规则 之后,保护目录黑名单始终生效;随后按顺序命中其中任意一条即放行:

  • 严格写入目标(配置目录 / 临时目录),或
  • 位于媒体库 / 播放列表上下文中的路径,或
  • 位于媒体库监视目录之下的路径 —— 覆盖已落盘但尚未扫描入库的文件,或
  • 与受信上下文音频文件同目录的文件 —— .lrc 等附属文件正是据此放行。

MediaWrite 相对 MediaRead 增加的是黑名单:即使目标确实出现在媒体库或播放列表中, 系统保护目录仍禁止写入。

仅仅位于非系统盘不构成 MediaWrite 的放行理由。 读策略允许非系统盘,但把这条 继承到写侧就等于「任何主题都能改写 D: 或 E: 上的任意音频文件」。

FileWrite ​

FileWrite 走自己的校验链,并非 MediaWrite 的超集:通用拒绝与保护目录黑名单之后, 依次按严格写入目标(配置目录 / 临时目录)、媒体库监视目录(is_path_addable—— 判配置而非成员性,因此新建路径与 UNC 监视目录同样放行)、以盘符寻址的非系统盘 (UNC 不在此列)、媒体库 / 播放列表上下文放行;MediaWrite 的伴生文件步在 FileWrite 中不存在。

FileWrite 放行任意非系统盘

这是当前暴露面最宽的写通道,file.delete 与 file.write 因此会接受 D:、E: 等盘上的任意目标。该放行之所以保留,是因为 file.mkdir 与 file.write 创建的 路径按定义不可能预先存在于媒体库或播放列表中,只按成员性放行会拒绝每一次调用。 监视目录不同:is_path_addable 判的是配置而非成员性,监视目录内的新建路径不依 赖本放行即可通过。

判据是 canonical 解析之后的盘符,不是调用方传入路径字面的盘符。 若用户目录被 junction / 符号链接重定向到非系统盘(例如 C:\Users\<user> → E:\Users\<user>, 迁移过用户目录的机器上很常见),该目录整棵子树都以 E: 形态参与判定,从而落入本 放行面 —— 尽管传入的路径以 C: 开头。放行与文件扩展名无关。审查主题时不能只看字 面盘符,需按目标机器的实际重定向情况判断。

本页顶部的 spec 计数为人工维护,以组件源码中的 C++ RegisterApi 路径安全 spec 为准。