Skip to content

Safety and Security

tanmoumou252 edited this page Jul 19, 2026 · 2 revisions

六、安全与自保机制

项目实现了多层安全机制,保护媒体库免受意外数据丢失、网络故障和用户误操作的影响。

1. 血统验证(9 步管线)

任何文件进入 B 区前必须通过血统校验(_verify_b_path_lineage),确保文件来自合法的 A 区源且未越界。

9 步流程

  1. _resolve_a_source — 解析 A 区源文件(确定 A/B 根路径、相对路径)
  2. _check_basic_lineage — 基础层级检查:A/B 目录完全一致时直接放行
  3. _check_season_layer_addition — B 区自动添加 Season 层级检查
  4. _check_media_name_match — 媒体名称匹配(提取 A/B 路径中的媒体名进行比对)
  5. _resolve_cloud_and_physical_names — 引擎配置与云端/物理名称解析
  6. _check_boundary_files — 越界文件检查(验证 B 区文件是否在合法范围内)
  7. _check_boundary_mappings — 边界映射匹配检查(比对 strm_media_boundary 记录)
  8. _handle_sync_phase_boundary — 同步阶段边界记录(仅同步阶段执行)
  9. _check_solo_episode — 单集/批量检测(间接触发 trigger_delayed_solo_check 30 秒观察定时器)

30 秒观察期

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 还原后保持当前映射

2. 幽灵保护

用途

防止删除后回灌的竞态条件:

  1. 用户删除文件(触发云端删除)
  2. OpenList 引擎重新生成 STRM(因云端文件仍在)
  3. 重新生成的文件回到 B 区

实现

ghost_protection 表记录被删除文件的 WebDAV 路径和过期时间。在保护期内(默认 300 秒(5 分钟),ghost_protect_seconds),同指纹的新文件被拒绝。

幽灵 vs C 区迁移

幽灵保护是短期机制(秒级),防止回灌竞态。C 区迁移是长期机制(永久),用于引擎根目录被移除时。

3. 重复文件隔离

检测

新 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

4. 隔离系统

损坏文件检测

B 区扫描时检查每个 STRM 文件:

  • 文件大小 < 最小阈值 → 损坏
  • 内容无法解析为有效 URL → 无效
  • WebDAV 路径在服务器上不存在 → 过期

恢复

损坏文件:按指纹查找 A 区源,存在则 shutil.copyfile() 恢复,不存在则重命名为 .invalid

5. 引擎内部标记(B-7)

引擎内部删除 B 区文件时(如去重隔离、僵尸清理),watchdog 触发 on_deleted_engine_internal_markers 集合中的指纹会被 handle_b_deleted 识别为引擎内部操作,跳过云端删除和 A 区删除,仅清理本地 DB 记录。

代际计数器(_engine_internal_generation)防止延迟清理与新的标记发生竞态。

6. 故障安全断路器

网络故障不应导致媒体库数据丢失。系统内建于主动刷新机制中:

  • 引擎管辖路径:完整刷新,允许 B 区清理
  • 非引擎路径:只读刷新,扫描目录结构,不清理 B 区

防止云存储离线 → 引擎标记路径不存在 → 程序不会误删 B 区文件。

7. 冗余清理

启动时和定期刷新中:

  1. 扫描 .duplicate 文件 → 删除
  2. 扫描 .quarantined 文件 → 删除
  3. 扫描 .invalid 文件 → 删除
  4. 扫描空目录 → 删除(保留含 .nfo.jpg.png.srt.ass 等刮削元数据的目录)

三层验证清理

每个候选清理文件必须通过三层检查,任一层通过即保留:

  1. 幽灵保护检查ghost_protection 表中 expire_time > now() 时保留
  2. A 区源存在性检查:A 区仍有对应 STRM 文件时保留(引擎仍在生成)
  3. WebDAV 存在性检查:通过 HEAD/GET 验证云端文件真实存在时保留

仅三层全不通过才执行物理删除。

8. 未文档化安全机制补全

以下安全机制在其他章节中未详细介绍:

  • 三重防误删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 幂等语句,可安全重复调用,不存在回滚机制。

Clone this wiki locally