- Rename source module from RDReaderView to RDEpubReaderView - Move all source files from Sources/RDReaderView/ to Sources/RDEpubReaderView/ - Update podspec: RDReaderView.podspec -> RDEpubReaderView.podspec - Update Podfile, demo project, and CocoaPods config for new pod name - Delete old RDReaderView pod support files from ReadViewDemo/Pods - Add new RDEpubReaderView pod support files - Update documentation (API ref, architecture, UML, conventions, etc.) - Add FixedLayoutRotationTests - Update .gitignore: exclude .DS_Store, manual unpack backups, _ssoft-output
122 lines
7.9 KiB
Markdown
122 lines
7.9 KiB
Markdown
# 代码库风险与关注点
|
||
|
||
**分析日期:** 2026-05-21
|
||
|
||
## 高风险:安全与隐私
|
||
|
||
### 1) CocoaPods 构建关闭了 User Script Sandboxing
|
||
- **问题:** `post_install` hook 将 Pods *以及* 用户工程的 `ENABLE_USER_SCRIPT_SANDBOXING` 强制设置为 `NO`。
|
||
- **影响:** 削弱对内嵌 Web 内容的纵深防御;增加 `WKWebView` 相关功能的风险面,并可能不符合组织/审核(含 App Store)安全基线。
|
||
- **建议缓解:**
|
||
- 移除全局覆盖,保持系统默认的 sandboxing。
|
||
- 如确有依赖需要 workaround,仅对具体 Pod target 做最小范围的设置,并记录原因。
|
||
- 在 CI 中增加校验:出现 `ENABLE_USER_SCRIPT_SANDBOXING=NO` 时告警/失败。
|
||
|
||
### 2) 外链打开未做 allowlist(scheme/host)
|
||
- **问题:** EPUB 内容中的外部 URL 通过 `UIApplication.shared.open(...)` 打开时,未对 scheme/host 做校验,也未强制用户二次确认。
|
||
- **影响:** 恶意 EPUB 可能触发钓鱼、隐私泄露,或打开意外的 URL scheme(包含跳转到其他 App 的 deep link)。
|
||
- **建议缓解:**
|
||
- 强制 allowlist(默认仅允许 `https`;如需 `mailto`/`tel` 等应在明确 UI 提示后允许)。
|
||
- 弹出确认对话框,展示目标 host。
|
||
- 对 bridge 消息与导航行为中的非 HTTP(S) scheme 做拒绝/过滤。
|
||
|
||
### 3) EPUB 解压未显式做 Zip Slip(路径穿越)加固
|
||
- **问题:** 解压逻辑构造 `destinationURL = extractionURL.appendingPathComponent(entry.path)` 并解压 entry,但未显式验证标准化后的目标路径是否仍在 `extractionURL` 之内。
|
||
- **影响:** 构造的 EPUB 可能尝试通过 `../...` 路径穿越覆盖目标目录外的文件(实际危害与 ZIPFoundation 行为及权限有关,但建议显式防护)。
|
||
- **建议缓解:**
|
||
- 解压前计算 `standardizedDestination = destinationURL.standardizedFileURL`,并确保其前缀位于 `extractionURL.standardizedFileURL.path + "/"` 之下。
|
||
- 拒绝包含 `..`、绝对路径、或异常路径分隔符形式的 entry。
|
||
- 考虑先解压到新的随机 UUID 目录,仅将校验通过的内容移动到最终目录。
|
||
|
||
### 4) 选中文本/高亮内容明文写入 UserDefaults
|
||
- **问题:** 选中文本与高亮 payload 以 JSON 编码写入 `UserDefaults`(包含“新”持久化与 legacy 路径)。
|
||
- **影响:** 可能将书籍敏感内容(高亮、选择文本)存入默认不加密的持久化位置,可能进入备份;同时数据量可能无限增长(性能与隐私风险)。
|
||
- **建议缓解:**
|
||
- 仅持久化稳定标识/范围(例如 CFI / rangeInfo),运行时再派生文本。
|
||
- 如必须持久化文本,存入加密存储(例如 Keychain 或使用 `NSFileProtectionComplete` 的加密文件)并设置大小上限。
|
||
- 增加数据保留策略,并提供 “Clear reading data” API。
|
||
|
||
## 性能与稳定性风险
|
||
|
||
### 5) Scheme handler 将整文件一次性读入内存(无流式)
|
||
- **问题:** `WKURLSchemeHandler` 使用 `Data(contentsOf:)` 读取资源并一次性返回。
|
||
- **影响:** EPUB 内的大图/字体/媒体资源可能导致内存峰值、加载变慢,甚至在内存压力下被系统终止。
|
||
- **建议缓解:**
|
||
- 尽可能改为基于 `InputStream` 的流式传输,并使用增量 `didReceive(...)`。
|
||
- 对单个资源增加大小上限,超过则优雅失败并提示。
|
||
|
||
### 6) 隐藏的分页 WKWebView 可能加载外部资源
|
||
- **问题:** `RDEPUBPaginator` 使用 `loadFileURL(...allowingReadAccessTo:)`,但未看到对 `navigationAction` 的 allowlist(例如仅允许 `file://` 或自定义 `ss-reader://`)。
|
||
- **影响:** 分页测量阶段可能产生意外网络请求,引发隐私泄露与不可控性能波动。
|
||
- **建议缓解:**
|
||
- 在 paginator 场景加入导航策略:默认仅允许 `file://`(以及必要的自定义 scheme),对 `http(s)` 直接取消。
|
||
- 视需求考虑内容拦截规则或禁用分页阶段的网络加载。
|
||
|
||
### 7) EPUB 解压缓存目录可能无限累积
|
||
- **问题:** 解压路径基于文件名/大小/mtime 的确定性签名;若目录已存在则直接复用,且无清理策略。
|
||
- **影响:** 书籍数量多或频繁更新时磁盘占用持续增长,造成存储压力与潜在卡顿。
|
||
- **建议缓解:**
|
||
- 为 `ssreaderview-epub` 缓存目录实现淘汰策略(LRU/按时间)。
|
||
- 提供显式清理 API,并在低存储信号时触发清理。
|
||
|
||
## 可维护性与技术债
|
||
|
||
### 8) DEBUG 下日志与 Web Inspector 可能泄露内容
|
||
- **问题:** Debug 辅助会打印导航/消息体;selection payload 可能包含用户选中文本;且 DEBUG 下可能默认开启 inspectable。
|
||
- **影响:** 在 debug 构建(含内部测试/QA)中,日志可能包含敏感内容并被导出/分享。
|
||
- **建议缓解:**
|
||
- 默认对消息体做脱敏(仅记录类型/大小),需要时再显式 opt-in 输出内容。
|
||
- 将 `isInspectable` 受控于 app 级 debug 开关,而不是在 DEBUG 下默认启用。
|
||
|
||
## 构建与依赖脆弱性
|
||
|
||
### 9) 仓库中包含 vendored 的 `Pods/` 目录
|
||
- **问题:** 仓库根目录有 `Pods/`,示例工程内也有 `ReadViewDemo/Pods/`。
|
||
- **影响:** diff 体积大、clone 慢、易产生 merge 冲突,也容易出现依赖陈旧导致的构建不一致。
|
||
- **建议缓解:**
|
||
- 通常建议不要提交 Pods,仅提交 `Podfile.lock`,在 CI 中执行 `pod install`。
|
||
- 如确有 vendoring 政策,需文档化并提供同步/校验工具,避免漂移。
|
||
|
||
### 10) Podfile 与 podspec 的部署版本不一致
|
||
- **问题:** `Podfile` 设为 `platform :ios, '15.6'`,而 podspec 声明 `s.platform = :ios, "15.0"`。
|
||
- **影响:** 对外承诺与本地构建基线不一致,容易造成集成方预期偏差。
|
||
- **建议缓解:**
|
||
- 对齐 `Podfile`、`*.podspec`、Xcode project 的 deployment target。
|
||
- 在 CI 中增加漂移检查,防止版本被无意改动。
|
||
|
||
### 11) podspec 将 Swift 版本钉死为 5.10
|
||
- **问题:** `s.swift_versions = ["5.10"]` 将 pod 与特定 Swift 版本强绑定。
|
||
- **影响:** 旧工具链的集成方无法使用;未来升级可能出现“突然不兼容”,尤其当依赖未同步时。
|
||
- **建议缓解:**
|
||
- 如兼容性允许,可声明更多支持版本(或范围),并在 CI 中覆盖多个 Xcode/Swift 版本构建验证。
|
||
- 在文档中明确最低支持的 Xcode/Swift 版本。
|
||
|
||
## 不清晰/容易踩坑的契约
|
||
|
||
### 12) 默认的持久化协议实现可能静默丢失数据
|
||
- **问题:** `RDEPUBReaderPersistence` 通过 protocol extension 提供了 bookmarks/settings 的默认 no-op 实现。
|
||
- **影响:** 集成方可能误以为这些能力默认会持久化,但实际数据会被静默丢弃,且不易排查。
|
||
- **建议缓解:**
|
||
- 将关键方法改为必须实现(移除 no-op 默认实现);或在未实现且功能启用时输出日志/assert。
|
||
- 提供并文档化 “最小持久化” 与 “完整持久化” 的参考实现。
|
||
|
||
---
|
||
|
||
## Evidence(仓库路径)
|
||
|
||
- Build flags:`Podfile`
|
||
- Pod metadata/toolchain:`RDEpubReaderView.podspec`
|
||
- Archive extraction:`Sources/RDEpubReaderView/EPUBCore/RDEPUBParser+Archive.swift`
|
||
- Resource path validation(post-extraction):`Sources/RDEpubReaderView/EPUBCore/RDEPUBParser+Resources.swift`
|
||
- Scheme handler reads full file bytes:`Sources/RDEpubReaderView/EPUBCore/RDEPUBResourceURLSchemeHandler.swift`
|
||
- WebView bridge + message handling:`Sources/RDEpubReaderView/EPUBCore/RDEPUBWebView+JavaScriptBridge.swift`
|
||
- External link opening:`Sources/RDEpubReaderView/EPUBUI/RDEPUBReaderController.swift`
|
||
- UserDefaults persistence implementation:`Sources/RDEpubReaderView/EPUBUI/RDEPUBReaderPersistence.swift`
|
||
- Hidden paginator web view:`Sources/RDEpubReaderView/EPUBCore/RDEPUBPaginator.swift`
|
||
- Debug logging:`Sources/RDEpubReaderView/EPUBCore/RDEPUBWebViewDebug.swift`
|
||
- Vendored dependencies:`Pods/`、`ReadViewDemo/Pods/`
|
||
|
||
---
|
||
|
||
*风险与关注点审计:2026-05-21*
|