-
Notifications
You must be signed in to change notification settings - Fork 0
Safety and Security
项目实现了多层安全机制,保护媒体库免受意外数据丢失、网络故障和用户误操作的影响。
任何文件进入 B 区前必须通过血统校验(_verify_b_path_lineage),确保文件来自合法的 A 区源且未越界。
-
_resolve_a_source— 解析 A 区源文件(确定 A/B 根路径、相对路径) -
_check_basic_lineage— 基础层级检查:A/B 目录完全一致时直接放行 -
_check_season_layer_addition— B 区自动添加 Season 层级检查 -
_check_media_name_match— 媒体名称匹配(提取 A/B 路径中的媒体名进行比对) -
_resolve_cloud_and_physical_names— 引擎配置与云端/物理名称解析 -
_check_boundary_files— 越界文件检查(验证 B 区文件是否在合法范围内) -
_check_boundary_mappings— 边界映射匹配检查(比对strm_media_boundary记录) -
_handle_sync_phase_boundary— 同步阶段边界记录(仅同步阶段执行) -
_check_solo_episode— 单集/批量检测(间接触发trigger_delayed_solo_check30 秒观察定时器)
B 区文件被移动到越界位置时启动 30 秒定时器。如果文件在 30 秒内返回原位置则取消(用户误操作),否则物理删除。防止单次误命名级联到云端删除。
| 操作 | 判定 | 说明 |
|---|---|---|
| 加深层级(加子目录) | 合法 | 刮削器添加元数据文件夹 |
| 向上提取一级 | 合法 | 用户简化结构 |
| 批量重命名目录内所有文件 | 合法 | 媒体管理器整理 |
| 单文件移动到不同媒体目录 | 非法 | 可能跨库污染 |
| 文件移动到引擎根目录 | 非法 | 破坏引擎隔离 |
| 单文件改名(同目录其他文件未变) | 非法 | 30 秒观察 → 未恢复则删除 |
B 区文件变动(创建/修改/移动)
│
▼
┌──────────────────────────────────────┐
│ 解析 STRM → 提取 WebDAV 路径 + 指纹 │
└──────────────────────────────────────┘
│
▼
┌──────────────────────────────────────┐
│ 存储映射查找:首级目录 → engine_entry │
└──────────────────────────────────────┘
│
▼
找到映射?
├─ 否 → 【跨库污染】→ 物理删除
└─ 是
│
▼
┌──────────────────────────────────────┐
│ 云端路径前缀核对:是否在 cloud_path 下 │
└──────────────────────────────────────┘
│
▼
前缀匹配?
├─ 否 → 【越界逃逸】→ 物理删除 + A 区恢复
└─ 是
│
▼
层级变化分析
├─ 加深层级 → 【合法】放行
├─ 层级减少/同级重命名
│ ├─ 单集/群体改名 → 【合法】放行
│ └─ 单兵越界 → 【30 秒观察期】
│ ├─ 观察期后仍单兵 → 【物理删除+A 区恢复】
│ └─ 观察期后变群体 → 【合法】放行
└─ 逃逸至引擎根 → 【立即物理删除+A 区恢复】
strm_media_boundary 记录源媒体名与当前媒体名的映射:
| 场景 | source_media_name | current_media_name | 说明 |
|---|---|---|---|
| 首次同步 | 1 |
1 |
初始状态 |
| TMM 刮削改名 | 1 |
[2011] 1 |
用户整理后的标准名 |
| 季目录调整 | 1 |
[2011] 1 |
媒体名不变,只变目录结构 |
| 单兵越界被还原 | [2011] 1 |
[2011] 1 |
还原后保持当前映射 |
防止删除后回灌的竞态条件:
- 用户删除文件(触发云端删除)
- OpenList 引擎重新生成 STRM(因云端文件仍在)
- 重新生成的文件回到 B 区
ghost_protection 表记录被删除文件的 WebDAV 路径和过期时间。在保护期内(默认 300 秒(5 分钟),ghost_protect_seconds),同指纹的新文件被拒绝。
幽灵保护是短期机制(秒级),防止回灌竞态。C 区迁移是长期机制(永久),用于引擎根目录被移除时。
新 STRM 进入 B 区时计算指纹,检查 strm_identity 表。指纹已存在即为重复。
重复文件重命名为 .duplicate 后缀,防止媒体库扫描器读取。定期清理时删除。
决定保留哪个实例时使用元组比较(_b_file_score 方法),而非加法评分:
# 返回 (is_standard_rank, match_count, path_len, name)
return (0 if is_standard else 1, match_count, path_len, name)| 维度 | 说明 | 优先方向 |
|---|---|---|
is_standard_rank |
0 = 标准 S01E01 命名,1 = 非标准 |
越小越优先 |
match_count |
从末尾反向匹配云端路径的段数 | 越大越优先 |
path_len |
路径字符串总长度 | 越短越优先 |
name |
文件名(小写) | 字典序兜底 |
Python 排序使用元组字典序,最高优先实例保持 valid 状态,其余改为 .duplicate。
B 区扫描时检查每个 STRM 文件:
- 文件大小 < 最小阈值 → 损坏
- 内容无法解析为有效 URL → 无效
- WebDAV 路径在服务器上不存在 → 过期
损坏文件:按指纹查找 A 区源,存在则 shutil.copyfile() 恢复,不存在则重命名为 .invalid。
引擎内部删除 B 区文件时(如去重隔离、僵尸清理),watchdog 触发 on_deleted。_engine_internal_markers 集合中的指纹会被 handle_b_deleted 识别为引擎内部操作,跳过云端删除和 A 区删除,仅清理本地 DB 记录。
代际计数器(_engine_internal_generation)防止延迟清理与新的标记发生竞态。
网络故障不应导致媒体库数据丢失。系统内建于主动刷新机制中:
- 引擎管辖路径:完整刷新,允许 B 区清理
- 非引擎路径:只读刷新,扫描目录结构,不清理 B 区
防止云存储离线 → 引擎标记路径不存在 → 程序不会误删 B 区文件。
启动时和定期刷新中:
- 扫描
.duplicate文件 → 删除 - 扫描
.quarantined文件 → 删除 - 扫描
.invalid文件 → 删除 - 扫描空目录 → 删除(保留含
.nfo、.jpg、.png、.srt、.ass等刮削元数据的目录)
每个候选清理文件必须通过三层检查,任一层通过即保留:
-
幽灵保护检查:
ghost_protection表中expire_time > now()时保留 - A 区源存在性检查:A 区仍有对应 STRM 文件时保留(引擎仍在生成)
-
WebDAV 存在性检查:通过
HEAD/GET验证云端文件真实存在时保留
仅三层全不通过才执行物理删除。
以下安全机制在其他章节中未详细介绍:
-
三重防误删(
handle_b_deleted):_restoring_markers(恢复操作标记)→_engine_internal_markers(引擎内部删除标记)→has_other_b_instance+_check_fingerprint_exists_in_b(同指纹其他实例检查)。三重全不通过才执行云端删除。 -
ensure_single_visible_instance(prefer_path)— 同一指纹仅一个实例保持valid状态,其余强制改为.duplicate。 -
get_webdav_lock(namespace)— 命名空间隔离的 WebDAV 操作锁,防止不同引擎/路径的并发冲突。 -
DB 建表幂等性 —
_create_schema使用CREATE TABLE IF NOT EXISTS幂等语句,可安全重复调用,不存在回滚机制。
🏡 返回 Wiki 首页 • 💻 项目源码仓库 • 🐛 提交 Bug / 建议 • 📦 下载最新版本
🚨 安全与自保黄金法则(每页必读)
- 严禁随意重置 OpenList 令牌:播放签名(
?sign=)强依赖服务端密钥。一旦重置,B区所有.strm将瞬间失效报无权播放,只能清库重来!- 调试阶段切勿使用 DELETE:
DELETE会物理删除云端文件,极其危险!建议终身配置为action = "MOVE"(云端一比一树状回收站模式)。- 放心刮削,资产安全:空文件夹清理算法采用严格的零物理文件判定,含有海报图片、
.nfo、外部字幕的目录绝对不会被误删。
本项目遵循 MIT 开源协议。数据无价,请在充分测试后接入生产环境。