摘 要
待办记录工作台(DaibanJilu)是一款面向个人日常事务管理的单页 Web 应用,涵盖待办清单、永久待办、每日记录、日历、搜索、回收站、草稿箱、操作日志等十一大已实现功能模块,并预留了统计面板这一待启用的进阶能力。本文以"记录待办系统"为对象,对该作品进行一次全面、系统的技术论述。论文的主要工作包括:其一,完整阐述其独创的"碎片链 + 路径派生密钥 + 干扰文件"自防护架构——载荷被切分为 8 条链、233 片,散布于 521 个随机命名的目录,混入 322 个干扰文件,加载时按链头清单逐片校验、并发门控、失败重试,约 0.5 秒完成重组;其二,逐层拆解链头二进制清单的字节布局、路径派生密钥的异或编解码、加载器六步流水线与干扰文件成本模型;其三,系统梳理十一大功能模块的信息架构、实体字段、双层持久化(IndexedDB 主存储 + localStorage 元数据)与页面自我保护层(开发者工具检测、水印、右键/复制/保存/打印/拖拽拦截);其四,给出威胁模型与攻击成本分析,并诚实地划定"提高提取成本"而非"绝对防盗"的技术边界。论文旨在为单页应用的源码保护与个人工具产品设计提供一份可复用的研究范本,同时记录这份作品在设计、验证与权衡中的完整思考。
关键词:待办管理;单页应用;碎片化加载;源码防护;二进制清单;SHA-256;IndexedDB;本地持久化;威胁模型
第一章 绪论:为什么需要一件"拿不走"的工作台
1.1 研究背景
过去十年,个人效率工具的形态经历了两轮显著迁移:从桌面客户端走向 Web,再从服务器端应用走向纯前端单页应用(SPA)。浏览器存储 API(localStorage 与 IndexedDB)的成熟,使得一款功能完整的个人工具——待办管理、笔记、记账、习惯打卡——可以完全脱离后端服务器,以"一个 HTML 文件 + 浏览器本地存储"的形式独立运行。这种形态带来了三个立竿见影的好处:零部署成本(扔到任意静态托管即可使用)、零账号摩擦(打开即用,数据留在本机)、零服务器账单(无数据库、无接口、无运维)。
然而,单页形态的代价同样深刻:应用的全部逻辑、模板与数据字典都内联在 HTML 里,任何人按下"查看源代码"或"另存为",一次点击即可整页搬走。对于个人作品而言,这是作者最不希望看到的结果——倾注了大量时间打磨的产品细节、交互语言与视觉设计,变成了一串任何人都能复制粘贴的字符。更现实的场景是:当作品被部署到公开仓库(如 GitHub Pages)时,仓库本身即暴露了全部源码;当作品通过即时通讯工具、群聊或网盘传播时,接收者手中的文件与原版完全等价。个人工具通常没有商业授权体系,也无力建设账号鉴权,因此"保护作品"这一诉求几乎全部落在前端技术本身。
与此同时,一个同样重要但常被忽视的需求是可靠性:单文件应用一旦被意外截断、被即时通讯工具二次转码、被文本编辑器错误保存,就可能整体报废。传统单页应用把所有代码放在一个巨大的文本文件里,换行符、字符集、BOM 头、剪贴板截断等任何一次文本层面的扰动都可能致命。一款理想的个人工具既希望"难被拿走",又希望"不易损坏"。
1.2 问题提出
围绕上述背景,本文以"待办记录工作台"(下称"本系统")为对象,系统回答以下四组问题:
- 产品层面:一款面向个人日常事务的待办工作台应当具备哪些功能维度?其信息架构、交互语言与空态设计如何支撑"从记录到复盘"的完整闭环?
- 工程层面:如何在不引入任何构建工具、服务器与依赖的情况下,把一个约 690KB 的应用设计成"加载时重组、离线可运行、损坏可定位"的自保护结构?碎片链、路径派生密钥、干扰文件等机制各自承担什么角色?
- 数据层面:双层持久化(IndexedDB 主存储 + localStorage 元数据)如何划分职责?跨版本数据迁移、配额监控与回填策略如何设计?
- 安全层面:"防提取"的真实边界在哪里?开发者工具检测、水印、交互拦截等页面自我保护手段的有效性与局限性如何评估?
1.3 论文目标与主要贡献
本文的目标不是复刻或美化一个界面,而是以工程论文的方式完整地、可复核地呈现本系统的设计与实现。具体贡献归纳为以下五点:
- 机制阐释:系统化阐述"魔数清单 + 路径派生密钥异或 + 逐片哈希校验 + 并发门控 + 失败重试 + 干扰文件"的碎片链加载架构,并给出本版本的性能指标与设计取舍。
- 功能测绘:基于界面结构、运行时字符串与行为观察,绘制出包含十一大功能模块、实体字段、操作日志元数据、存储键名的完整功能地图,覆盖全部操作路径。
- 安全评估:建立分层威胁模型,对"查看源代码""一键保存""批量抓取""逆向重组""仓库克隆"五类提取路径逐一评估成本与有效性,并如实划定技术边界。
- 工程方法论:沉淀出一套"自检先行、碎片可验证、错误可定位、诊断可开关"的单页应用交付与运维范式,供同类项目参考。
- 设计思考:记录产品在功能取舍(如统计能力的预留)、数据安全与视觉语言上的决策过程,为个人工具设计提供一份完整的案例。
1.4 研究方法与工具
本文全部基于对作品本身的检查与验证,方法链条如下:
- 静态审查:精读入口页壳层源码,还原 base64 内嵌的 UI 骨架与加载器算法(ROOT、SALT、链头数组、并发门控、重试、清单解析、重组与执行)。
- 自检工具验证:运行
verify_fragments.py,确认 233 个真实碎片与 322 个干扰文件的分布及完整性。 - 重组回归:依据加载器同一套密钥派生规则(SHA-256(SALT + 相对路径) 派生异或密钥)编写重组脚本,将全部碎片解码拼装为明文载荷并逐片比对哈希,作为第四章机制阐释的直接证据。
- 桩环境行为验证:在 Node 沙箱中注入最小 DOM/存储桩,以"译码函数包装 + 调用日志"方式捕获运行时实际使用的全部字符串常量,用于功能测绘与行为验证。
- 交叉核对:将界面文案、解码字符串、存储键名与随包说明相互比对,所有结论均以可追溯的原始材料为据。
1.5 论文组织结构
全文共十一章,另有五个附录。第二章从需求分析入手建立产品的功能与非功能基线;第三章给出系统总体架构与物理布局;第四章是本文的技术核心,逐层拆解碎片防护机制;第五章详尽测绘十一大功能模块;第六章阐述数据模型与双层持久化;第七章讨论独立于加载器之外的页面自我保护层;第八章覆盖用户体验与界面设计;第九章进行安全性与风险分析;第十章给出测试与质量保障方法及验证实验;第十一章总结并展望(含统计预留能力的启用蓝图)。附录 A–E 分别提供术语表、存储键清单、动作日志元数据、关键代码段注释与图表清单,便于读者对照原文核验。
第二章 需求分析与设计理念
2.1 用户画像与典型场景
本系统的目标用户并非"需要协作与提醒的企业用户",而是追求私密、自洽与掌控感的个人用户:数据只属于自己、工具随取随用、不希望被账号体系与服务器绑定。围绕这一画像,可以归纳出四类典型使用场景:
场景一:通勤碎片时间
在地铁或排队间隙随手记下一件待办或一条"报件已送达"式的事务记录,30 秒内完成输入、打标、归位,无需联网。工作台的"每日记录 + 短语快捷填充"正是为这一场景设计。
场景二:工作日的分层管理
把任务分成"今日待办"与"永久待办"两个时间尺度:短期用截止日期、优先级与标签推进;长期用"转为今日待办"完成从永久池到当日池的流转。
场景三:周末复盘与回看
通过日历查看任意一天做了什么,通过操作日志回放本周对数据的所有增删改,形成"记录—执行—复盘"的闭环。
场景四:成果的私人化保存
用户不希望自己的工具界面、交互细节与数据字典被他人一键复制用于"白嫖"或二次分发;也不希望在传阅过程中因文件截断、转码而永久损坏。这正是碎片防护层存在的理由。
2.2 功能需求
依据界面结构与运行时行为,可将系统功能需求归纳为十一大已实现模块,外加一项预留能力。下表列出功能编号(FR)、模块、核心能力与关键交互,构成第五章功能详解的索引:
| 编号 | 模块 | 核心能力 | 关键交互 |
|---|---|---|---|
| FR-01 | 待办清单 | 工作/生活双分区;全部/待办/已完成/已逾期/星标五态筛选;优先级、标签、截止日期、完成时间 | 新增、编辑、完成/取消完成、复制、删除、星标、置顶、拖拽排序、批量清空分区 |
| FR-02 | 永久待办 | 永久池任务;类型(工作/生活)与状态筛选;固定维护习惯性事项 | 新增、编辑、完成、星标、置顶、复制、转为今日待办 |
| FR-03 | 每日记录 | 记录类型(其他/会议/报件/取件等)管理;短语快捷填充 | 新增、编辑、复制、置顶、星标、删除;短语一键带入 |
| FR-04 | 草稿箱 | 未完成输入的自动暂存;草稿独立管理 | 新增、编辑、转待办、转记录、删除;重新打开继续编辑 |
| FR-05 | 回收站 | 删除数据的软删除暂存;可恢复或彻底清除 | 恢复待办/永久待办/记录/草稿;清空回收站 |
| FR-06 | 日历 | 按月视图呈现每日内容密度;按日查看 | 上一月/下一月/回到今天;点击日期查看当日事项 |
| FR-07 | 搜索 | 范围(全部/待办/记录/永久/草稿)+ 类型(工作/生活)+ 日期区间 | 关键词检索、结果跳转、搜索历史 |
| FR-08 | 设置(标签管理) | 标签管理、记录类型管理、便捷短语管理 | 增删改、配色、分组、重名校验 |
| FR-09 | 操作日志 | 全部操作行为留痕(增删改、恢复、导入导出等) | 按分类筛选、清空日志 |
| FR-10 | 数据管理 | 导出 JSON 备份、导入 JSON 恢复、导出 Markdown、复制当天、删除当天、删除全部 | 文件级备份与恢复;剪贴板级日汇总 |
| FR-11 | 页面保护 | 开发者工具检测、水印、交互拦截、锁页 | 检测到调试行为即锁定并提示刷新 |
| FR-12 | 统计(预留) | 统计总览:四格指标瓦片 + 近七天趋势条(代码已就绪,界面入口暂隐藏) | 随版本启用;统计口径由明细实时计算 |
此外,系统内还有着若干功能点:如日期导航顶栏(前一天/后一天/今天快速切换)、复制内容(将当日全部内容格式化后写入剪贴板)、动作菜单(每一条数据项上的"更多"操作聚合)、搜索历史(最近查询词留存)等,均将在第五章相应小节展开。
2.3 非功能需求
- NFR-1 启动性能:全量载荷约 690KB,重组启动约 0.5 秒,且只发起 233 个真实请求(绝不触碰干扰文件),网络失败自动重试至多 3 次。
- NFR-2 抗文本损坏:全部碎片以二进制 + arrayBuffer 读取,免疫换行符转换、字符集错乱、BOM 头、剪贴板截断等文本层损坏;每片以长度 + SHA-256 双重校验,损坏可精确定位到文件名。
- NFR-3 部署成本:产物仅需静态托管(任意静态服务器),无构建、无依赖、无后端;入口页可任意改名,碎片根目录可任意重命名或嵌入既有目录。
- NFR-4 兼容性:以标准浏览器 API(fetch/arrayBuffer/IndexedDB/localStorage/Web Crypto)为依赖面,未使用任何构建产物或运行时框架,理论上任何现代浏览器可直接运行。
- NFR-5 数据不丢失:提供导出/导入 JSON 双通道、草稿自动暂存、回收站软删除、删除当天/全部前的二次确认、配额使用量实时展示。
- NFR-6 可运维性:通过
verify_fragments.py自检工具、页首精确错误提示、?diag=1诊断模式三件套,使"坏了能定位、传前能自检、运行能观测"。
2.4 设计理念:四组贯穿全局的原则
2.4.1 "难拿走"与"不易坏"的统一
传统思路下,防复制(把代码藏起来)与可靠性(把代码摊开可校验)互相矛盾。本系统的解法是把矛盾转移到文件组织层:内容仍然完整存在,但被打散为小片、以随机命名散布、以路径派生密钥加密、以清单哈希校验。对合法用户,浏览器按清单精确取回;对提取者,需要先识别链头、解析清单、派生密钥、重组拼装,成本远高于一次"查看源代码"。
2.4.2 一切从"单文件可运行"出发
产品交付形态始终是"一个 HTML + 一个资源目录",无任何安装步骤。入口页自包含 UI 骨架与加载器,资源目录在加载时按需获取;这种"壳 + 载荷"的二分也天然地把"表现层"与"逻辑层"分开,便于独立演进。
2.4.3 默认本地、始终本地
所有业务数据写入浏览器本地存储,不上传任何服务器;"数据管理"模块的一切操作(导出、导入、复制、删除)均发生在用户设备与剪贴板/文件之间。隐私即默认,这是个人工具最朴素也最坚固的设计承诺。
2.5 与其他个人待办工具的定位差异
市面上主流的个人待办工具大致有三类:在线协作型(如 Trello、Notion、飞书任务)、极简单机型(如系统自带备忘录)与数据自托管型(如 TiddlyWiki、Obsidian 本地库)。本系统的定位与三者均有本质区别,也因此在设计上刻意避开它们的默认路径:
- 不学在线协作型:不引入账号、服务器、多人权限与订阅制。协作是团队场景的答案,而本系统服务的个人场景要的是"打开即用、数据归己";一旦接入服务端,也就同时接入服务端的中断、隐私与续费风险。
- 不满足于极简单机型:系统备忘录只解决"记下来",不解决"记下来之后怎么办"。本系统通过状态机(完成/逾期/星标/置顶)、分区(工作/生活)、流转(待办↔永久待办)、复盘(日志/日历/搜索)补全了"记录—执行—回顾"的后半程。
- 不照搬数据自托管型的复杂度:自托管工具往往要求用户自己管理文件、插件与同步策略,学习成本高。本系统把复杂度收进交付物内部:用户只需要"一个 HTML + 一个目录",迁移靠导出/导入 JSON,没有任何配置负担。
这一差异定位也直接决定了第四章防护设计的必要性:在线协作型靠服务端鉴权保护内容,自托管型靠用户自己的文件权限保护内容,而本系统"纯静态、无后端"的形态决定了内容保护必须由前端技术本身承担——碎片防护正是在这一约束下生长出来的答案。
第三章 系统总体架构
3.1 逻辑分层
整个系统在逻辑上可分为五个层次,自底向上为:数据持久层(IndexedDB 与 localStorage 双层存储)、业务逻辑层(重组后的载荷中实现的全部数据操作与状态管理)、表现层(UI 骨架、模块渲染、toast 与弹窗)、碎片加载层(入口页中的链式加载器,负责取回、校验并重组载荷)、保护层(页面自我保护,独立于加载器运行)。其中加载层与保护层共同构成系统的"防御面",业务与数据层构成系统的"价值面",两者在入口页与载荷中的物理分布如下:
3.2 物理布局与交付物
系统的物理交付物共四件:入口页、碎片目录、自检脚本与说明文档。文件统计如下:
| 交付物 | 大小 / 数量 | 作用 |
|---|---|---|
| DaibanJilu.html | 79,362 B | 入口页:base64 UI 骨架 + 二进制链加载器,不含业务内容 |
| w/ 碎片目录 | 555 个 .bin 文件 521 个目录 | 233 个真实碎片 + 322 个干扰文件;40 个一级随机目录、480 个二级随机目录 |
| verify_fragments.py | 4,297 B | 部署前自检:链头解析、逐片哈希校验、干扰文件清点 |
| README.txt | 约 4.5 KB | 产品说明、使用与排错指引、诚实边界声明 |
碎片目录的目录层级为固定的两层随机结构:w/<一级随机目录>/<二级随机目录>/<随机名>.bin,例如链头之一位于 w/b3/0a/4bb346e5.bin。40 个一级目录与 480 个二级目录的名字均无语义;文件名的 8 位十六进制串亦与内容无关。这种布局让"按名字找规律"的路径彻底失效——任何静态分析都必须从加载器出发,而不是从文件名出发。
碎片包的构成关系如下图所示。需要强调的一点是:干扰文件 322 个多于真实碎片 233 个,这是刻意设计——批量抓取者若以"全部下载然后逐个尝试"为策略,必须试错过半的文件才能触达全部真实数据;而正常加载由于链头清单精确指引,永远只请求 233 个真实碎片,从不触碰干扰文件。
3.3 与常规单页应用的架构对比
将本系统与三类常见单页交付形态横向对比,可以更清楚地看出其在"保护—可靠—成本"三角上的取舍:
| 维度 | 普通单文件 | 单文件 + JS 混淆 | 构建产物 + CDN 鉴权 | 本系统(碎片链) |
|---|---|---|---|---|
| 查看源码即可用 | 是(一次点击) | 部分(需解码) | 否 | 否(需解析链头/密钥/重组) |
| 一键另存为 | 可用 | 可用(可运行) | 需处理资源 | 不可用(碎片缺一即失) |
| 抗批量抓取 | 无 | 弱 | 中(取决于鉴权) | 强(322 干扰 + 逐片校验) |
| 抗文本层损坏 | 弱(整体报废) | 弱 | 中 | 强(二进制 + 逐片定位) |
| 部署依赖 | 任意静态托管 | 任意静态托管 | 需鉴权/CDN 配置 | 任意静态托管 |
| 离线可用 | 是 | 是 | 取决于缓存 | 是 |
| 启动性能 | 最优 | 略损 | 视网络 | ≈0.5s(690KB) |
| 维护成本 | 最低 | 低 | 中 | 低(自检脚本 + 诊断模式) |
3.4 入口页壳层结构解析
作为"看得见的部分",入口页 DaibanJilu.html(79,362 字节)承载着两段职责:UI 骨架与二进制链加载器。其中 UI 骨架以 base64 编码内嵌,解码后是一段完整的表现层模板(顶栏日期导航、模块面板、弹窗体系、toast 容器、FAB 与全部 CSS),它在碎片载荷尚未到达时即渲染出页面外壳,并以"正在加载待办记录工作台…"进度条承接用户的等待;加载器则是紧随其后的一小段紧凑 JavaScript,包含四个核心常量与六个流水线步骤:
- 常量区:
ROOT(碎片根目录 "w")、SALT(密钥派生盐)、HEADS(8 个链头的相对路径数组)、并发门控与重试参数——这是整个碎片体系对外暴露的唯一"钥匙串"; - 算法区:清单解析(魔数校验、碎片计数、记录展开)、密钥派生(SHA-256 同步封装)、异或解码、长度+SHA-256 双重校验、按序拼接、运行时注入执行。
值得注意的是,壳层刻意不包含任何业务内容——即使完全读懂壳层,也拿不到一条数据逻辑;业务代码的全部价值藏在碎片载荷之中。这一"壳层可读、载荷不可读"的刻意不对称,正是碎片防护的精髓:把攻击者的分析对象从"一个文件"拉长为"一个文件 + 一份需要逆向的加载协议"。
第四章 碎片防护技术剖析
4.1 威胁模型:防御对象是谁
任何防护设计的第一步是界定对手。按提取能力从低到高,可将本系统面对的对手分为五层:
| 对手层级 | 典型行为 | 技术能力 | 本系统的主要防御 |
|---|---|---|---|
| T1 顺手党 | 查看源代码、Ctrl+S 另存、复制粘贴 | 无编程 | 碎片化:源码无内容;另存仅得壳层 |
| T2 一键保存党 | 使用浏览器"保存完整网页"、下载器批量抓取静态资源 | 会用工具 | 555 个文件中仅 233 个真实;保存得到的是无法重组的碎片 |
| T3 批量爬虫 | 脚本化抓取全部文件后逐一尝试 | 会写脚本 | 干扰文件多于真实碎片(322 > 233),试错成本过半;路径派生密钥阻挡直读 |
| T4 逆向工程师 | 分析入口页加载器,编写重组程序 | 精通前端/加密 | 加载器本身在壳层中可读;此层对手的成本已接近"重写一个应用" |
| T5 仓库克隆者 | git clone 公开仓库 | 会用 git | 理论上无防御(客户端天然如此);依赖授权/部署策略,见第九章 |
由此可见,碎片防护的核心承诺是:把 T1–T3 的成本抬到"需要编程逆向"的高度,并让 T4 面对的不是一次点击而是完整分析工作。T5 属于部署层问题,不属于客户端技术范畴。
4.2 总体机制
碎片防护机制由五个相互咬合的部分构成:
- 二进制化:全部内容(CSS、HTML 模板、JavaScript 逻辑与数据字典)作为二进制载荷,与入口页文本彻底分离;碎片以 arrayBuffer 读取,避开文本编码问题。
- 碎片化:载荷被切分为 233 个约 3KB 的碎片,按 8 条链组织;入口页只保存每条链第一个碎片的相对路径(链头),其余碎片的路径全部记录在链头的二进制清单中。
- 路径派生密钥:每个碎片的异或密钥由"盐 + 相对路径"的 SHA-256 派生而来;密钥与文件位置绑定,改名或移动即解码失败,天然形成"防搬移"约束。
- 链式校验:链头清单为每个碎片记录路径、长度与 SHA-256 摘要;加载时逐片校验,缺片、篡改、错序都能精确报出文件名。
- 干扰注入:在碎片目录中混入 322 个同构的随机噪声文件,使"全量抓取"策略的信噪比低至 42%(233/555)。
4.3 二进制清单(链头)格式
链头文件本身也是一个被异或加密的碎片,解密后其头部是一份二进制清单。格式如下:
| 偏移 | 字段 | 长度 | 说明 |
|---|---|---|---|
| 0–3 | 魔数 | 4 B | "K7FB"——清单合法性标识,防误读误载 |
| 4–5 | 保留 | 2 B | 版本/扩展位 |
| 6–7 | 碎片计数 n | 2 B(大端) | 本链包含的碎片总数(含链头自身) |
| 8–11 | 链头载荷长度 l0 | 4 B(大端) | 链头自身承载的内容字节数 |
| 12… | 碎片记录 ×(n−1) | 变长 | 每条记录:路径名字节长(1B) + 路径(变长) + 载荷长度(4B 大端) + SHA-256(32B) |
| 末尾 | 链头内容 | l0 B | 链头自身携带的载荷片段 |
8 条链的碎片数分布为:b3/0a 链:30 片其余 7 链:各 29 片,合计 30 + 29×7 = 233 片。链头载荷长度字段的存在使链头自身也能承载内容,不浪费任何一个字节。
4.4 密钥派生与异或编解码
每个碎片的解码密钥由全局盐(koi7frag-2026-10b)与该碎片相对碎片根目录的路径拼接后取 SHA-256 得到:
// 密钥派生(与入口页加载器同一算法) key = SHA256( SALT + "/" + 相对路径 ) // 例:SALT + "/b3/0a/4bb346e5.bin" // 异或编解码(对称,解码即再异或一次) plain[i] = cipher[i] ^ key[i mod key.length]
这一设计有两个精妙之处。其一,密钥不落盘:任何文件本身都不包含密钥,密钥是从"盐 + 路径"现场计算出来的;干扰文件即使被下载也无法直接解密(它们的路径不属于任何清单,即使穷举也无法得到正确的密钥上下文)。其二,改名即失效:密钥与路径绑定,若有人把碎片目录改名或移动碎片,除非同步修改加载器中的 ROOT 常量并保持相对路径不变,否则校验必然失败;而 ROOT 只影响目录前缀,相对路径不变时密钥不受影响——这正是随包文档中"改名安全"承诺的机制基础。
在重组回归实验中,以同一算法对全部 555 个文件进行解码尝试:233 个真实碎片全部命中魔数与哈希校验,322 个干扰文件无一命中——这从实证上验证了"正常加载绝不触碰干扰文件"的声明。
4.5 加载器算法
入口页加载器是一个约 150 行内联 JavaScript 的紧凑实现,核心流水线如下:
算法要点归纳如下:
- 并发门控(gate 20):加载器实现了一个容量为 20 的并发闸,防止一次性发起数百个 fetch 压垮浏览器连接池;队列按链顺序消费。
- 三次重试:每个碎片的请求失败(网络错误/404/校验不符)时自动重试至多 3 次,显著提升弱网或托管服务偶发 5xx 下的加载成功率。
- 进度驱动:每成功解码一片即更新页面顶部的加载进度;全部就绪后一次性拼接并执行,保证 UI 完整、无闪烁。
- 精确报错:失败时在页首输出"校验失败 xxx.bin / 长度不符 xxx.bin / HTTP 404 xxx.bin",直接指向可修复对象。
- 诊断模式:URL 追加
?diag=1后在控制台输出重组字节数与耗时,供开发排障。
4.6 干扰文件策略与提取成本模型
322 个干扰文件并非无意义的填充,它们在提取成本模型中扮演关键角色。设真实碎片数为 R=233,干扰文件数为 D=322,总文件数 T=555。对"全量抓取后逐个猜测"的 T3 类对手,其成功概率曲线随随机尝试次数线性上升:
- 随机试错 1 个文件即命中真实碎片的概率:233/555 ≈ 42.0%;
- 要拿到"全部" 233 个真实碎片,最坏情况下需遍历全部 555 个文件,其中 322 次是无效劳动;
- 即使拿到全部文件,仍需要识别链头(魔数)、解析清单、按路径派生密钥、逐片异或解码并正确拼接,才能得到可运行的载荷——这一工作量已经接近"读一遍加载器代码"。
更重要的是时间维度:对个人作品而言,"防提取"的收益不是绝对封锁,而是让批量爬取者的单位成本超过重建成本。当对手需要投入的分析时间接近"自己重写一个待办工具"时,碎片防护就达成了目标。
4.7 抗损坏与可运维设计
碎片化在带来保护性的同时,天然引入了"文件多、易丢失"的新风险。系统的对策是双重的:一是格式免疫——所有碎片为纯二进制,经由 arrayBuffer 读取,换行符转换、字符集误判、BOM 剥离、文本截断等常见文本损坏对它无效;二是校验与自检——链头清单内置每个碎片的长度与 SHA-256,运行期精确报错;交付物内置 verify_fragments.py,在解压后、上传前先跑一遍,输出"PASS/FAIL + 具体碎片名",把部署事故消灭在发布之前。重组回归实验让 233 个碎片逐一通过长度与哈希校验,零失配,佐证了这套设计的健壮性。
4.8 性能与效率指标
碎片化最容易被质疑的是性能代价:文件数量从"1 个"变成"555 个",加载会不会变慢?本版本的验证数据回答了这个问题——碎片链架构把性能代价压到了可忽略的水平:
| 指标 | 数值 | 设计说明 |
|---|---|---|
| 全量重组耗时 | 约 0.5 s | 233 个碎片并发拉取(门控 20),解压、异或与哈希均为纯计算,无 IO 阻塞 |
| 实际网络请求数 | 233 个 | 链头清单精确指引,绝不触碰 322 个干扰文件 |
| 载荷体量 | 690,845 B | 单片约 3KB,适合 HTTP 缓存与弱网增量传输 |
| 单片解码开销 | SHA-256 + 异或 | 每片仅一次哈希比对与一次异或,总耗时微秒级 |
| 失败恢复 | 重试 ×3 | 网络抖动或单点 5xx 不影响整体加载成功率 |
更关键的是二进制载体带来的性能与健壮性双赢:文本碎片需要处理字符集与转义,解析成本高且易碎;二进制碎片由 arrayBuffer 直达内存,加载器无需任何文本预处理。与此同时,555 个文件中的 322 个干扰文件对合法用户是零成本的——它们从未被请求,只存在于抓取者的世界里。这组数字说明:防护设计的质量不取决于复杂度,而取决于对载体本质的把握——二进制 + 哈希校验 + 并发控制,比堆更多碎片更有效。
4.9 与主流前端保护方案的比较
| 维度 | JS 混淆(obfuscator) | WASM 封装核心 | 服务端鉴权/接口代理 | 碎片链(本系统) |
|---|---|---|---|---|
| 可读性破坏 | 高(源码不可读) | 高(二进制) | 中 | 高(内容整体不可直读) |
| 运行性能损耗 | 中(字符串解码) | 低 | 低 | 低(异或 + 哈希极快) |
| 部署形态 | 单文件 | 多文件 | 需后端 | 静态目录 |
| 抗"另存为" | 弱(可运行副本) | 中 | 强 | 强(碎片无法单独运行) |
| 损坏自愈/定位 | 无 | 无 | — | 强(逐片校验定位) |
| 可维护性 | 需保留映射 | 需工具链 | 常规 | 重组工具 + 自检脚本 |
值得指出,混淆与本系统的碎片链并非互斥:重组后的载荷内部仍可采用字符串数组混淆(本系统载荷中即存在 javascript-obfuscator 风格的字符串数组与译码函数,运行时通过"索引 + 密钥"两参调用还原字符串)。这说明作者采取了文件级碎片 + 代码级混淆的双层纵深,T4 级对手在还原载荷后还需再面对一轮代码级反混淆。
第五章 功能体系详解
5.1 待办清单(FR-01)
待办清单是工作台的核心模块。每条待办携带一组结构化字段:归属分区(工作/生活)、类型(公事/私事)、优先级(高/中/低)、记录类型、发生时间、截止日期、内容、标签、完成状态、星标、置顶与更新时间。模块采用"分区 + 筛选器"的双重组织方式:
- 分区:工作与生活两个区块各自独立渲染,区块可折叠(collapsed),可整体清空("删除全部"),并分别带区块级计数。
- 筛选器:顶部分组按钮提供五态切换——全部 / 待办 / 已完成 / 已逾期 / 星标。其中"已逾期"由当前时间与截止日期实时比较得出;"星标"是独立于完成状态的标记维度,二者正交。
- 列表项:每项渲染类型徽标(公事/私事)、优先级色点、标签徽章、截止日期与逾期药丸(overduePill)、星标图标;右侧"更多"按钮弹出动作菜单。
动作菜单是待办项的操作中枢,可用动作包括:完成待办 / 取消完成、编辑待办、复制内容、置顶待办 / 取消置顶、标记星标 / 取消星标、转为永久待办、移入回收站、彻底删除待办。其中"复制内容"会以相同字段快速新建一条,"转为永久待办"实现待办池向永久池的沉淀,"置顶"影响渲染顺序并即时反馈。状态机如下:
交互细节上还包含:拖拽排序(列表项可拖动换序,拖动中有占位样式)、Enter 快速提交新增、内容/名称非空校验("内容不能为空")、编辑弹窗与原内容回填等。
5.2 永久待办(FR-02)
永久待办模块服务于"不属于今天、但必须持续维护"的事项(如周期性的材料整理、习惯性事务)。其组织维度与待办不同:类型筛选(全部/工作/生活)+ 状态分组 + 折叠,列表项同样支持完成/取消完成、星标、置顶、复制内容、编辑与删除。其最关键的流转动作是"转为今日待办":一键把永久项实例化为今天的待办(可携带截止日期与标签),实现永久池到当日池的桥接;反向的"转为永久待办"在待办模块中提供。这一双向流转使两池在时间尺度上互补而不重复,是产品信息架构中最具巧思的一环。
5.3 每日记录(FR-03)
每日记录面向"不一定是任务、但值得留痕"的事务信息(如"取件送达,转交相关科室")。它的差异化设计有三点:
- 记录类型:系统内置四种默认类型——其他、会议、报件、取件,每种类型配有默认短语库;用户可在设置中增删改记录类型(删除时提示"删除类型「x」",并需确认影响范围)。
- 短语快捷输入:表单内置短语分组,点选即填入内容,把高频事务的录入从"打字"降级为"点一下"。默认短语共 18 条,覆盖生活与工作两类:生活侧如"买菜做饭,打理日常饮食""锻炼身体,保持健康作息""联系家人,问候近况";工作侧如"会议记录,汇总会议纪要""收集核对,补齐报件要件""取件送达,转交相关科室""起草文稿,按时报送材料"等。
- 记录级操作:复制内容、置顶、星标、编辑、删除(移入回收站),与待办共享同构的动作模型。
5.4 草稿箱与自动暂存(FR-04)
草稿箱是"输入过程"的保护层。用户在新增/编辑弹窗中开始输入后,内容会被实时暂存(存在一条提示"内容已暂存,重新打开可继续编辑");若中途关闭弹窗,草稿仍可在"草稿箱"模块中找到并继续编辑。草稿箱支持:新增草稿、编辑草稿、草稿转待办(按待办表单结构落库)、草稿转记录、删除草稿。这一机制把"误关弹窗""刷新页面"从数据丢失事故降级为无感恢复,与回收站共同构成双保险。
5.5 回收站(FR-05)
回收站实现统一的软删除语义:待办、永久待办、每日记录与草稿四类对象的删除一律先进回收站,可分别恢复(动作:恢复待办、恢复永久待办、恢复记录、恢复草稿),也可彻底删除或一键清空。清空与彻底删除均需二次确认。回收站的引入使"误删"有后悔药,同时也让操作日志能完整记录"删除—恢复"的全过程。
5.6 日历与日期导航(FR-06)
日期体系是全部数据的时间主轴。顶部栏提供日期选择器、前一天/后一天切换与"今天"回跳;日历模块按月展示,每个日期格以点状标记当日是否有数据(日历点密度即内容密度)。切换日期后,待办、记录等模块均按该日期重新渲染——"日期即上下文"的设计让用户既能管理"今天",也能回看"任意一天"。
5.7 搜索(FR-07)
搜索模块提供多维检索能力,筛选维度如下:
- 范围:全部 / 待办 / 记录 / 永久 / 草稿——把四类对象纳入统一检索,避免"忘了记在哪一类"的查找困境;
- 类型:全部 / 公事 / 私事——与对象分区正交;
- 日期区间:起始日期与结束日期(sfDateFrom / sfDateTo),支持按发生时间筛选;
- 搜索历史:最近查询词自动留存(存储键
app-search-history-v1),一键回填重复检索。
结果列表逐项展示命中对象的类型徽标与摘要,提供一键清空全部筛选条件。对个人工具而言,搜索的价值不在于"全网检索"的规模,而在于"把一年前的某条记录捞回来"的确定性。
5.8 操作日志(FR-09)
操作日志是系统行为的"黑匣子":每一次数据变更都会以结构化动作写入日志(存储键 app-logs-v1),覆盖的动作元数据(ACTION_META)达五十余种,包括:新增待办、编辑待办、完成待办、取消完成、复制内容、置顶/取消置顶、标记/取消星标、新增/编辑/删除永久待办、转为今日待办、新增/编辑/复制/删除记录、新增/编辑/删除草稿、草稿转待办、草稿转记录、恢复待办/永久待办/记录/草稿、彻底删除待办、清空回收站、清空待办分区、清空当日记录、清空永久待办、导出 JSON 备份、导入 JSON 备份、导出 Markdown、复制当天、删除当天、删除全部数据、标签改名、记录类型改名、删除标签、删除记录类型、新增/编辑/删除便捷短语、迁移历史数据、清空日志等。
日志模块本身提供分类筛选(全部/待办/记录/草稿/回收站/系统)与清空日志(带确认:确定清空全部操作日志吗?)。这套机制让用户能够复盘"我的数据是怎么变成今天这样的",也为故障排查提供了时间线证据。
5.9 设置中心(FR-08)
设置弹窗聚合三类元数据管理:
- 标签管理:新增标签(名称非空校验、重名校验"名称已存在")、改名、删除;删除时二选一——"只删标签,保留事项"或"删除并移除所有事项上的该标签",把"删标签是否连坐数据"的决定权交给用户;标签可配颜色(调色板包含约十余种色值,如 #f0a100、#0e7490、#22a447、#2f6fd0、#e8590c、#0ca678、#8e44ad、#e03131 等)。
- 记录类型管理:增删改记录类型(内置其他/会议/报件/取件),删除需确认,改名即时同步历史记录的类型展示。
- 便捷短语管理:按分组维护短语(新增/编辑/删除),是录入效率的最终调节旋钮。
5.10 数据管理(FR-10)
数据管理模块是"数据主权"的落地窗口,全部操作均在本机完成:
| 操作 | 行为 | 场景价值 |
|---|---|---|
| 导出 JSON 备份 | 将全部数据序列化为 JSON 文件下载 | 换设备/浏览器迁移、历史归档 |
| 导入 JSON 备份 | 读取备份文件并合并/覆盖恢复 | 灾难恢复、跨设备同步的替代通道 |
| 导出 Markdown | 按日把待办/记录格式化为 Markdown 文本下载 | 嵌入笔记、周报、知识库 |
| 复制内容(当天) | 当日全部内容格式化写入剪贴板(toast:当日内容已存入剪贴板) | 快速分享当日安排 |
| 删除本日 / 删除全部 | 按日或全量清空(均需确认) | 数据治理与重置 |
注意"复制内容"与"导出 Markdown"的对象是当日,与日历日期上下文一致;这种"日期即粒度"的设计贯穿导出、复制、删除三类操作,保持心智模型统一。
5.11 辅助交互(跨模块)
- 动作菜单:列表项右侧"更多"弹出上下文菜单(#actionMenu),集中承载该对象的全部动作,避免界面被按钮淹没。
- 悬浮按钮与返回顶部:右下角 FAB 提供新增入口;长页面滚动后出现返回顶部按钮。
- Toast 反馈:所有写操作后给出轻量确认(如"已移入回收站""当日内容已存入剪贴板""类型已改名"),文案与按钮动词保持一致。
- 弹窗体系:统一遮罩 + 居中弹窗承载新增/编辑/设置;弹窗支持遮罩点击关闭与取消按钮,表单回车提交。
- 空态设计:各模块均有专属空态("今日暂无内容""暂无内容""回收站为空""暂无日志"),空态即引导而非空白。
- 响应式:窄屏下模块折叠为单列,表格与长列表横向滚动,核心操作全部可达。
- 键盘快捷键:全局支持 Enter 提交、Esc 关闭弹窗、Tab 自然聚焦顺序;编辑弹窗打开即聚焦内容框,减少鼠标往返。
- 长列表分治:当某日数据量很大时,列表按分区/类型折叠展示,避免单屏堆叠过密;"全部/待办/已完成"筛选器天然承担分页职责。
5.12 端到端用户旅程示例
为把十一大模块串联为可感知的完整体验,本节以一名基层办公人员"小周"的一天为例,演示工作台在各时点的实际用法(以下为示例数据,用于展示操作路径):
打开工作台(约 0.5 秒),在"待办"模块新增:工作分区、公事、高优先级、标签"材料"、截止今天,内容"起草文稿,按时报送材料"——短语库点选即入,全程不到 15 秒。
地铁上想起"取件已送达",在"每日记录"选类型"取件"、短语一键填入并保存,记录自动归入今天。
汇报材料完成,行内点击完成;随后在"永久待办"池把"整理材料,完善台账资料"转为今日待办,永久池与当日池完成桥接。
会议间隙开始写一条待办,内容没打完就被叫走;系统提示"内容已暂存,重新打开可继续编辑"。返回后草稿完好,一键续写完成。
点"复制内容"把今日安排写入剪贴板发到工作群(toast:当日内容已存入剪贴板);需要正式周报时用"导出 Markdown"。
周六打开日历回看一周各日的内容密度;周日执行"导出 JSON 备份"存入私人网盘。换电脑时在新浏览器"导入 JSON 备份",全部数据随行。
误删某条待办:回收站一键恢复;弱网加载:自动重试 3 次仍失败时页首精确报错,按随包说明排查;存储接近配额:面板实时显示已用/可用,导出备份后治理。
这趟旅程覆盖了全部十一大模块,下表逐模块对照"旅程中的体现"与"所属时段",确保覆盖无遗漏:
| 模块(FR) | 在旅程中的体现 | 时段 | 关键动作 |
|---|---|---|---|
| 待办清单(01) | 晨间建计划、上午完成待办、行内完成与进度反馈 | 全天 | 新增 / 完成 / 编辑 |
| 永久待办(02) | 上午把周期性事项"转为今日待办"实例化 | 上午 | 转为今日待办 |
| 每日记录(03) | 通勤用"取件"类型 + 短语记录送达事项 | 通勤 | 类型 + 短语快填 |
| 草稿箱(04) | 午后被打断的输入自动暂存,返回续写 | 午后 | 暂存 / 续写 / 转待办 |
| 回收站(05) | 意外误删某条待办后一键恢复 | 意外 | 恢复 / 清空 |
| 日历(06) | 周末按月回看各日内容密度 | 周末 | 日期导航 / 点击回看 |
| 搜索(07) | 想找"上周那条记录"时按范围检索并跳转 | 随时 | 范围 / 类型 / 日期筛选 |
| 设置·标签(08) | 旅程前为"材料""取件"等建立标签与配色 | 前置 | 标签增删改 / 配色 |
| 操作日志(09) | 周末复盘本周对数据的所有增删改记录 | 周末 | 分类筛选 / 回放 |
| 数据管理(10) | 傍晚复制内容发群;周末导出/导入 JSON 迁移 | 傍晚/周末 | 复制当天 / 导出 / 导入 |
| 页面保护(11) | 全程无感;仅在异常环境触发锁页提示 | 全程 | 调试检测 / 锁页 |
| 统计(预留) | 未来版本启用后可查看"完成率 + 近七天趋势" | 展望 | 见 11.2 启用蓝图 |
这趟旅程覆盖了全部模块,且每个动作都在 5.1–5.11 节中找到对应机制——这说明产品功能不是孤立的按钮堆砌,而是一条可走通的完整工作流。
第六章 数据模型与持久化
6.1 实体模型
系统的业务实体共有六类:待办(todo)、永久待办(permanent)、每日记录(record)、草稿(draft)、标签(tag)、操作日志(log)。六类实体围绕"日期"与"标签"两个公共维度相互关联:
实体间还存在若干转换关系:待办 ↔ 永久待办(双向流转)、草稿 → 待办/记录(转存)、任意实体 → 回收站(软删除)、回收站 → 原实体(恢复)。这一关系网络保证了"任何数据在系统中都有明确的下一站"。
6.2 字段明细
| 字段 | 取值示例 | 说明 |
|---|---|---|
| mode | work / personal | 分区:工作(公事) / 生活(私事),决定列表归属区块 |
| type | 公事 / 私事 | 待办类型展示口径,与 mode 联动 |
| priority | high / medium / low | 优先级:高 / 中 / 低,以颜色与顺序体现 |
| recType | other / meeting / 报件 / 取件 | 每日记录类型,可自定义扩展 |
| time | "HH:mm" | 发生时间 |
| due | "YYYY-MM-DD" | 截止日期;逾期判断依据 |
| content | 任意文本 | 核心内容;短语一键填充 |
| tags | 标签名数组 | 标签引用;删除标签时可选择保留/移除事项上的引用 |
| done / star / pin | 0 / 1 | 完成、星标、置顶三个正交状态 |
| updatedAt | 时间戳 | 最后修改时间,日志与统计的时间依据 |
6.3 双层存储架构
系统的持久化采用IndexedDB 主存储 + localStorage 元数据的双层结构,职责划分如下:
- IndexedDB(主存储):承载结构化的业务数据。库名形如
UzAdbdb、版本号 1,按"日"组织对象仓库(day-* 系列),同时维护元数据仓库;事务以 readwrite 模式写入,写操作走 Promise 封装(openDB / idbTx / idbGet / idbGetAll / idbPut)。按日分仓的设计使"某天的数据"可以在一个仓库内完整读写,天然匹配日历、复制当天、导出当天等按日粒度操作。 - localStorage(元数据/偏好):承载体量小、读频高或需同步操作的配置与记录,键名清单见 6.4。
这种分层的工程理由是:业务主体放 IndexedDB(容量大、结构化、事务化),高频小数据放 localStorage(API 简单、同步读、不占事务开销),两者互补而不过度设计。
6.4 存储键清单
通过运行时解码与行为观察,localStorage 键名如下(均为应用自有前缀 + 版本后缀):
| 键名 | 用途 |
|---|---|
| app-bin-v1 | 回收站数据(软删除对象集合) |
| app-logs-v1 | 操作日志 |
| app-drafts-v1 | 草稿集合 |
| app-tags-v1 | 标签定义(名称 + 配色) |
| app-rectypes-v1 | 记录类型定义 |
| app-phrases-v1 | 便捷短语分组与条目 |
| app-permanent-v1 | 永久待办数据 |
| app-search-history-v1 | 搜索历史 |
| app-ui-v1 | UI 偏好(折叠状态、上次日期等) |
| day-migrated-v1 | 历史数据迁移完成标志(值为 "1") |
键名统一采用 app-<域>-v<版本> 的命名规范,版本号内置于键名而非数据结构中——这一细节让未来升级可以"换键名 + 迁移"优雅演进,避免旧数据与新结构互踩。
6.5 迁移与兼容策略
系统在升级路径上做了两项关键设计。其一,历史数据自动迁移:旧版本将数据存放于 localStorage 的应用曾在其上积累用户数据;新版以 day-migrated-v1 标志位记录迁移状态,检测到未迁移时自动执行"迁移历史数据"并将旧数据搬入 IndexedDB 按日仓库,迁移动作本身也会写入操作日志,全过程对用户无感。其二,备份文件的版本自洽:导出 JSON 包含完整数据字典与版本信息,导入时按结构恢复,可跨浏览器、跨设备完成数据搬家。
6.6 配额监控与回填
6.7 数据生命周期与一致性保障
从数据的一生来看,系统为每条数据定义了清晰的生命周期,并在每个阶段提供对应的保障机制:
- 创建:新增弹窗提交(Enter 快捷提交、非空校验),写入 IndexedDB 对应日仓,同步写操作日志;写入失败(如配额满)时以 toast 明确告知而非静默丢失。
- 使用:读操作走按日聚合的读接口,保证"日历点密度、列表渲染、导出内容"三个视图看到的是同一份数据。
- 编辑:编辑弹窗回填原值,保存即覆盖并更新时间戳;任何修改都留下日志记录,构成可回放的时间线。
- 删除:统一先进回收站(软删除),恢复动作原样找回;彻底删除才真正落库移除——两级删除把误操作成本压到最低。
- 归档:导出 JSON / Markdown 把数据带出系统;导入 JSON 让数据可以"换环境重生",形成不依赖任何厂商的长期归档通道。
一致性保障上还有两个细节:其一,所有写操作通过 Promise 封装的事务接口串行执行,避免并发写互相覆盖;其二,导入 JSON 前会做结构校验(字段合法性、类型一致性),拒绝损坏或不完整的备份文件,杜绝"坏数据污染好数据"。这套"生命周期 + 两级删除 + 校验导入"的组合,让数据在漫长使用中既可靠又可迁移。
第七章 页面自我保护层
7.1 设计动机与总体形态
碎片加载层解决的是"文件被拿走"的问题;而页面自我保护层解决的是"页面被观察/被摆弄"的问题——包括打开开发者工具偷看数据、右键复制、拖动内容、Ctrl+S 保存等。保护层随载荷在重组后注入运行环境,其形态是一段携带配置对象的初始化逻辑,主要动作包括:交互拦截、开发者工具检测、水印注入与锁页。
7.2 保护配置矩阵
| 配置项 | 行为 | 备注 |
|---|---|---|
| enableLock | 总开关:启用整套锁定能力 | 与授权环境判定联动 |
| allowLocal / allowedHosts | 本地 file:// 与白名单域名放行 | 本地预览不被误锁 |
| pathMustContain | URL 路径必须包含指定片段 | 防止搬运到别处直接运行 |
| blockRightClick | 拦截 contextmenu 事件 | 禁用右键菜单 |
| blockCopy / blockCut | 拦截 copy / cut 事件 | 禁用复制剪切(含文案"blockCopy") |
| blockSave / blockPrint | 拦截 Ctrl+S / 打印 | 防止整页另存与打印导出 |
| blockDevtools | 开发者工具检测与锁定 | 见 7.3 |
| blockDrag / dragstart | 拦截拖拽(文本/图片) | 防止拖出内容 |
| watermark / watermarkText | 注入 SVG 水印 | 默认文案"锦鲤未离 · 原创作品,请勿盗用" |
| lockTitle / lockMsg | 锁页标题与说明文案 | "页面已锁定""本页面为受保护的原创作品,当前环境未获授权,无法使用" |
7.3 开发者工具检测
检测采用组合手段而非单一特征,形成纵深:
- debugger 计时:在代码中周期性执行
debugger断点并测量前后时间差;开发者工具打开时调试器会暂停脚本,时间差骤增(阈值约 120ms),据此判定"有人在调试"。 - 窗口尺寸差:比对
outerWidth − innerWidth与outerHeight − innerHeight;Dock 式开发者工具打开时差值显著增大(阈值约 180px)。 - 正则陷阱与死循环诱饵:载荷中嵌入形如
((( .+)+)+)+$的灾难性回溯正则与while(true)片段,干扰调试器单步执行与静态阅读。 - console 污染:对
log / info / error / exception / table / trace / assert等输出方法进行包装重定向,降低控制台日志的取证价值。
7.4 水印系统
水印以 SVG data-URI 背景的方式注入页面(含 __p_wm 动画容器与 __p_foot 页脚水印,动画名形如 __p_wm_a),文本为"锦鲤未离 · 原创作品,请勿盗用",以半透明、低对比度平铺,既不影响阅读,又让截图/翻拍自带可追溯的归属标记。水印不随滚动消失,覆盖全页,是"防君子"式取证手段。
7.5 锁页机制
一旦判定"环境未获授权"(如检测到调试行为),保护层以全屏覆盖层锁死页面(含 PAGE_LOCKED 标记),显示"检测到调试行为,请关闭开发者工具后刷新页面继续使用",并将页面标题切换为"页面已锁定"。解锁路径只有一条:关闭开发者工具并刷新——这与威胁模型一致:合法用户无感,提取者被逼到"必须绕过检测"的逆向赛道。
7.6 有效性评估
客观评价该保护层的价值与局限:其拦截面覆盖了日常取证的全部低成本入口(右键、复制、保存、打印、拖拽、控制台、调试器),且检测手段多样、阈值合理,误伤合法用户的概率低(本地 file:// 与白名单域名被显式放行)。但需要说明的是:开发者工具检测的多种手段均可被成熟的自动化工具(如无头浏览器)规避;水印与锁页属于"威慑 + 取证"而非"封锁";本层的根本约束与碎片层相同——客户端可显示即终究可提取。它真正的价值是把"顺手拿走"升级为"刻意对抗",而这正是个人作品保护最现实的期望。从工程视角看,这一层还带来一个副产品:它在运行期持续校验"页面是否处于预期环境",与加载层的"文件是否完整"形成两条独立的健康检查线,任何一条失守都会显式报错而非静默降级。
7.7 检测与反制的博弈视角
开发者工具检测本质上是一场"猫鼠博弈":任何客户端检测手段都存在对应的规避方案。站在博弈视角审视本系统的检测组合,其设计取向值得注意:
- 不追求"不可绕过",追求"绕过高成本":无头浏览器、远程调试协议等高级工具可以完全绕过 debugger 计时与尺寸差检测,但使用它们需要搭环境、写脚本,这不是"顺手党"的成本量级。本系统的检测目标始终对准 T1–T2 级对手。
- 多信号交叉,降低误报与漏报:计时与尺寸差两种信号独立触发,正常用户几乎不可能同时命中;同时阈值(120ms / 180px)留有合理裕量,避免高负载机器上合法用户被误锁。
- 锁定而非瘫痪:检测命中后的处理是"锁页 + 提示刷新",而非破坏数据或无限循环消耗资源——这保护的是合法用户重新进入的通道,也避免了对共享设备环境的误伤扩散。
这一博弈视角也说明了保护层的合理期望:它不是防御体系的天花板,而是把"取证成本"从零抬到"需要专用工具"的那块台阶。与碎片加载层配合后,两道防线分别对应"文件层面"与"运行层面",即使其中一道被绕过,另一道仍然存在。
第八章 用户体验与界面设计
8.1 信息架构
全站信息架构遵循"顶栏(时间轴)+ 模块抽屉(组织面)"的总体骨架。顶部为日期导航与全局动作;中部为可切换的功能面板;右侧为悬浮新增入口;底部为跨模块动作区域。模块切换通过顶部 Tab 完成,面板由 10 个已启用 Tab 与 1 个预留 Tab 构成:
8.2 视觉语言
产品的视觉基调是"暖色、圆润、轻量":品牌色为暖橙色系(#f0a100 为主色),辅以深青(#0e7490)、薄荷绿(#22a447)、天蓝(#2f6fd0)等功能色;卡片与弹窗采用大圆角、柔和边框与轻阴影,营造亲和而非冷淡的工具感。界面文本全部为中文口语化表达("今日暂无内容""内容已存入剪贴板"),动词与按钮一致("导出 JSON 备份"的按钮和 toast 文案同名)。
字体层级依赖字号、字重与语义断行建立:模块标题(大号粗体)、面板标题(中号)、正文与按钮(常规)、徽标与元信息(小号弱化);所有数字与时间采用等宽数字(tabular-nums),保证列表对齐稳定。空态、加载态、错误态三态齐备:加载时全屏进度条("正在加载待办记录工作台… x/233"),出错时页首红色横幅,空模块各有引导文案。
8.3 交互细节设计
- 键盘:表单 Enter 提交、Esc 关闭弹窗、编辑弹窗自动聚焦输入框;搜索框键盘导航(ArrowDown/Enter 选择历史项)。
- 动效克制:仅折叠/展开、弹窗显隐、进度条更新使用过渡动画,不做无信息量的装饰动画。
- 状态可见性:置顶项排序在前并带图标;星标独立于完成态;逾期项显示"已逾期 x"红色药丸;完成项置灰划线但可随时取消完成。
- 防误操作:删除全部/清空回收站/删除当天/清空日志均有确认弹窗;标签删除提供"保留事项 / 连坐移除"两种语义,把不可逆决定交给用户。
- 移动端适配:窄屏 Tab 可横向滚动、列表卡片化、FAB 保持在拇指热区,宽高断点切换布局。
8.4 体验设计小结
综合来看,本产品的体验设计遵循三条主线:日期为轴(一切内容挂到具体某天,回看与迁移都以此展开)、动作聚拢(行内只放高频操作,低频操作收入动作菜单)、容错优先(草稿暂存、回收站、二次确认、备份导出形成层层兜底)。在"功能密度"与"界面克制"之间,产品选择把复杂度收进抽屉与菜单,把高频路径(新增、完成、记录)压到最短——这正是个人工具"越用越顺手"的来源。
8.5 可访问性与无障碍设计
作为一款需要长期高频使用的工具,可访问性是体验的隐性底线,本系统在以下方面做了工程化处理:
- 对比度与字号:正文文本使用暖墨色与暖米底的组合,对比度满足常规阅读需求;小字号仅用于徽标与元信息,且不以颜色作为唯一信息载体(如优先级同时有位置与色点)。
- 键盘可达:所有弹窗支持 Esc 关闭与 Enter 提交;表单自动聚焦;焦点元素保留可见轮廓,保证无鼠标用户可完整操作。
- 减少动效:尊重 prefers-reduced-motion,用户偏好减少动态时折叠全部过渡动画(含水印动画),页面功能不受影响。
- 语义化结构:模块面板、按钮、列表项使用语义化标签与 aria 标注,toast 与弹窗具备基本读屏可辨识性。
这些工作没有出现在功能清单里,却决定了工具"能不能被长期使用":对一个每天要打开十几次的应用,可访问性的价值不在某一刻,而在每一年。
第九章 安全性与风险分析
9.1 五条提取路径的成本评估
结合第四章的威胁模型,本系统面对的主要提取路径有五条,其成本对比如下("成本"指提取者获得可运行的完整载荷所需投入):
| 提取路径 | 成本量级 | 系统反制 | 残余能力 |
|---|---|---|---|
| 查看源代码 | 1(一次点击) | 源码不包含业务内容 | 仅见壳层与加载器 |
| 一键另存为 | 1(一次点击) | 页面主体为重组产物,另存只得壳 | 无可用副本 |
| 批量抓取全部文件 | 10(工具级) | 322 个干扰文件 + 555 文件全量 | 信噪比 42%,仍需逆向重组 |
| 逆向重组(分析加载器) | 10⁴(人·小时) | 密钥派生 + 异或 + 逐片校验 | 可完成,成本接近重建应用 |
| git clone 公开仓库 | 1(命令级) | 客户端技术无法反制 | 部署层需授权/策略(见 9.3) |
9.2 残余风险与边界声明
必须详细地指出本系统无法覆盖的风险:
- 任何可显示的客户端内容终究可提取:浏览器必须能把载荷解密并执行,故掌握加载器的人理论上可完全重建。碎片防护的目标是抬高成本,不是"绝对防盗"。
- 运行期数据可被观察:页面运行后,业务数据已在浏览器内存与存储中,开发者工具/无头浏览器仍可读取 localStorage 与 IndexedDB 中的明文数据——保护层只能检测与威慑,不能加密业务数据(否则会引入密钥管理难题,且与"数据始终本地、用户随时可取"的产品承诺冲突)。
- 源码混淆非密码学:载荷内的字符串数组 + 译码函数属于混淆(obfuscation)而非加密;其价值在于阻碍阅读,不构成数据安全承诺。
- 部署方式决定最终边界:若作品被上传至公开 git 仓库,clone 即得全部碎片与加载器。客户端技术无法阻止这一路径,只能通过部署策略(私有仓库、受控分发)管理。
边界结论:本系统提供的是一套"提高提取成本 + 运行环境健康检查 + 归属取证"的组合防护。若需求是"绝对不可提取"或"业务数据加密",需要引入服务端授权与加密体系——那将改变产品的"零部署、纯本地"定位,属于不同的架构决策。
9.3 对"仓库克隆"路径的部署建议
对唯一的低成本残余路径(T5),可行的缓解都在部署层:优先使用私有仓库托管;必须公开时,将碎片目录排除出版本控制或用 CI 在发布时才生成碎片包;为受控分发(群聊、网盘)保留一份"按需生成"的流程。这些措施不属于客户端代码的职责,但作为产品作者应当知晓并管理。与此同时,随包 README 中已明确声明"严禁搬运、复制或商用,转载需标注来源",配合水印形成可举证的权益声明。
9.4 常见疑问辨析
围绕"这样真的防得住吗"这一最朴素的问题,结合设计时的取舍,对几类高频疑问给出明确回答:
- "入口页里不是明明白白写着 8 个链头路径吗,照着拼不就行了?"——能看到链头与"能重组"之间隔着三层:清单要解码(密钥来自盐+路径)、每个碎片要逐片异或还原、碎片间要靠清单中的长度与哈希校验才能确认拼接顺序与完整性。链头只是入场券,不是答案。
- "全部 555 个文件都下载下来,挨个试不就好了?"——可以,但这是 T3 级工作量;且干扰文件无法通过密钥校验,逐片试错必须先完成逆向。对个人作品而言,让"批量搬运"退化成"深度逆向",就已经完成了防护的使命。
- "既然客户端一定能显示,那防护不是自欺欺人吗?"——防护的对象从来不是"理论上可提取",而是"实践中轻易可得"。防盗门挡不住爆破,但挡得住顺手牵羊;碎片防护同理。
- "为什么不用服务端授权,一劳永逸?"——因为那会同时牺牲零部署、离线可用与数据本地三大产品承诺。防护方案的选取本质是产品定位的取舍,而非单纯的强度最大化。
这组问答的结论与 9.2 的边界声明一致:本系统承诺的是"把提取成本提高到接近重建的成本"。
第十章 测试与质量保障
10.1 验证策略总览
本系统虽不采用自动化测试框架,但质量保障是成体系的设计,分为三层:交付前自检(verify_fragments.py)、运行期校验(加载器逐片长度+SHA-256 校验、?diag=1 诊断)、回归验证(重组回归 + 桩环境行为验证,即本文取证所用的方法)。三层共同回答三类问题:碎片包是否完整?加载能否成功?重组后的行为是否符合预期?
10.2 verify_fragments.py 自检工具
随包交付的自检脚本是碎片包的"出厂检验"。其工作流为:解析 8 个链头(按 ROOT/SALT 派生密钥解码)→ 展开全部清单记录 → 逐个碎片校验(文件存在性、长度匹配、SHA-256 匹配)→ 清点真实碎片与干扰文件 → 输出汇总。运行结果为:
=== 待办记录工作台 碎片自检 === [+] 碎片链头: 8/8 通过 [+] 真实碎片: 233/233 通过 (长度+哈希) [+] 干扰文件: 322/322 识别 [+] 载荷重组: 690,845 B === PASS ===
脚本既可用于解压后、上传前的发布前检查,也可用于接收方验证文件的完整性——它把"碎片包有没有坏"从玄学变成可复现的一行命令。
10.3 加载期校验与诊断模式
加载器在运行期对每个碎片做长度 + SHA-256 双校验,任何不符都会触发页首精确错误(含文件名与失败类型);网络失败自动重试至多 3 次;若仍失败,提示信息直接指向修复对象(重新上传该文件或重新生成碎片包)。URL 追加 ?diag=1 后,加载器在控制台输出重组字节数与分阶段耗时,供开发者在非标准环境快速定位"慢在哪、错在哪"。此外,file:// 协议下浏览器会拒绝碎片请求(同源策略限制),属预期行为而非缺陷——正式使用应通过任意静态 HTTP 服务打开,随包说明与页首错误提示均已写明。
10.4 回归验证实验
为保证本文论述的可复核性,对系统执行了两类回归验证:
| 实验 | 方法 | 结果 |
|---|---|---|
| 碎片完整性验证 | 运行 verify_fragments.py,解析 8 链头并校验 233 碎片 | 8/8 链头、233/233 碎片全部通过,载荷 690,845 B |
| 重组回归 | 按加载器同一密钥派生算法独立编写重组脚本,逐片解码拼装 | 与自检一致;解码命中恰好 233 片,干扰 322 片零命中 |
| 桩环境行为验证 | Node 最小 DOM/存储桩运行载荷,包装译码函数收集运行时字符串 | 捕获 897 条运行时字符串,与界面文案/键名交叉一致 |
三项实验共同构成对第四章机制阐释与第五章功能测绘的证据链:机制的每一步(魔数、密钥派生、清单、并发、校验)都被独立复现或直接观察;功能测绘的每个模块、键名与文案都可在 897 条运行时字符串中定位到出处。
第十一章 总结与展望
11.1 工作总结
本文以"待办记录工作台"为对象,完成了一次从产品、工程到安全的完整技术论述。总结而言,本系统的设计呈现三个层次的价值:
- 产品层:以"日期为轴、动作聚拢、容错优先"的信息架构,把待办、永久待办、每日记录、草稿、回收站、日历、搜索、日志、设置、数据管理等十一大模块组织为一条可走通的日常闭环;数据始终本地、导出导入双通道,兑现了"个人工具的数据主权"。
- 工程层:以"二进制碎片链 + 路径派生密钥 + 干扰文件"自研出文件级防护架构,在 233 个真实碎片与 322 个干扰文件之间实现精确加载(约 0.5 秒、零干扰请求),并把"坏了能定位、传前能自检、运行能观测"内建为交付标准。
- 安全层:以分层威胁模型与五条提取路径的成本评估,具体地划定了"提高提取成本"的技术边界,同时用页面自我保护层覆盖日常取证入口,实现"威慑 + 检测 + 取证"的组合防御。
值得再次强调的工程经验有三条:其一,二进制载体是防护与健壮性的共同根基——避开文本编码问题,换取免疫损坏与高效解码;其二,干扰文件是"零成本威慑"——对合法用户零请求,对抓取者成倍提升试错成本;其三,自检与诊断不是附加功能,而是交付物的一部分——它们让复杂机制变得可复现、可运维。
11.2 统计预留能力的启用蓝图
系统当前版本在界面层并未设计"统计"入口(数据管理面板中的"统计"按钮被隐藏,display:none),但统计能力的完整代码与样式已预留:面板骨架(标题"统计总览"与"全部日期"计数药丸、#statsBody 渲染容器)、CSS 样式(四列指标网格 .stat-grid、指标瓦片 .stat-tile/.st-num/.st-label/.st-sub、近七天趋势条 .trend-bars/.tb-todo/.tb-rec/.trend-num)以及"统计模块"的注释组均需在后续中进行数据装配与入口显形。
启用路径共分三步:
- 装配数据:实现按日期聚合的统计查询(完成率、计数、连续天数、日均操作),数据源为 IndexedDB 明细与操作日志,口径与"复制当天/导出当天"保持一致;
- 显形入口:移除"统计"按钮的隐藏样式,纳入模块抽屉并补全 11.2 节所述的四瓦片 + 近七天趋势条渲染;
- 回归验证:以真实明细抽查统计口径(如某日新增/完成数),确保数字与明细可逐条对上——统计的价值只在口径可信时存在。
11.3 展望
在统计之上,本系统还有若干清晰且克制的演进方向:
- 加密可选项:为业务数据提供"导出加密 JSON"(如口令派生密钥),在保持纯本地定位的前提下把备份的机密性提升一档——需权衡密钥遗忘的恢复成本。
- 模板与导入增强:支持 JSON 模板批量新建(如每周固定事务),与短语体系衔接。
- 碎片化参数化:将链数、片大小、干扰比例做成可配置(当前为编译期常量),针对不同体积的应用适配;可补充"部分碎片缺失时按 233→n 自适应降级加载"的容错模式。
- 主题与多语言:基于现有 token 体系扩展浅色/深色主题与 i18n 文案表。
- 保护层增强:对高价值场景引入服务端签发的一次性授权(仅对受控分发使用),把 T5 路径也纳入管理。
最后,回到本文开篇的问题——为什么需要一件"拿不走"的工作台?答案在本文的技术论述中逐渐清晰:因为对个人作品而言,"难被拿走"不是对抗,而是尊重。尊重作者投入的时间,也尊重使用者的数据——碎片防护把前者做成工程,双层持久化把后者做成承诺。这正是一件小工具可以承载的最大诚意。
参考文献与资料清单
- 加载中......
附录
附录 A 术语表
| 术语 | 释义 |
|---|---|
| 碎片(fragment) | 载荷被切分后的二进制片段,本版本单片约 3KB,共 233 片 |
| 链(chain) | 由链头 + 若干载荷片构成的逻辑序列,本版本共 8 条 |
| 链头(head) | 每条链的第一个碎片,内含二进制清单;入口页仅知链头路径 |
| ROOT / SALT | 碎片根目录名(w/)与密钥派生盐(koi7frag-2026-10b) |
| 干扰文件 | 混入碎片目录的同构噪声 .bin 文件,本版本 322 个 |
| 异或编解码 | 以路径派生密钥对碎片逐字节异或的对称变换,解码即再异或 |
| 桩环境 | 以最小 DOM/存储桩模拟浏览器运行载荷的 Node 沙箱 |
| 软删除 | 删除后进入回收站、可恢复的删除语义 |
| 双层持久化 | IndexedDB 主存储 + localStorage 元数据的存储架构 |
附录 B 常量与存储键清单
| 名称 / 键名 | 取值与说明 |
|---|---|
| ROOT | "w"——碎片根目录 |
| SALT | "koi7frag-2026-10b"——密钥派生盐 |
| MAGIC | "K7FB"——链头魔数 |
| CONCURRENCY | 20——并发门控上限 |
| RETRY | 3——失败重试次数 |
| HEADS | 8 个链头相对路径(b3/0a/4bb346e5.bin 等) |
| IDB 库名 | 形如 UzAdbdb,版本 1,按日仓库 + 元数据仓库 |
| app-bin-v1 | 回收站数据 |
| app-logs-v1 | 操作日志 |
| app-drafts-v1 | 草稿 |
| app-tags-v1 | 标签(名称 + 配色) |
| app-rectypes-v1 | 记录类型 |
| app-phrases-v1 | 便捷短语 |
| app-permanent-v1 | 永久待办数据 |
| app-search-history-v1 | 搜索历史 |
| app-ui-v1 | UI 偏好 |
| day-migrated-v1 | 历史迁移完成标志("1") |
附录 C 操作日志动作元数据(节选)
| 分类 | 动作示例 |
|---|---|
| 待办 | 新增待办 · 编辑待办 · 完成待办 · 取消完成 · 复制内容 · 置顶/取消置顶 · 星标/取消星标 · 转为永久待办 · 移入回收站 · 彻底删除待办 |
| 永久待办 | 新增永久待办 · 编辑永久待办 · 删除永久待办 · 转为今日待办 |
| 每日记录 | 新增记录 · 编辑记录 · 复制记录 · 删除记录 |
| 草稿 | 新增草稿 · 编辑草稿 · 草稿转待办 · 草稿转记录 · 删除草稿 |
| 回收站 | 恢复待办 · 恢复永久待办 · 恢复记录 · 恢复草稿 · 清空回收站 |
| 数据管理 | 导出 JSON 备份 · 导入 JSON 备份 · 导出 Markdown · 复制当天 · 删除当天 · 删除全部数据 |
| 设置 | 新增/改名/删除标签 · 新增/改名/删除记录类型 · 新增/编辑/删除便捷短语 |
| 系统 | 迁移历史数据 · 清空日志 |
附录 D 关键代码段注释
以下两段为碎片防护机制的最小复现示意(节选,与原始实现等价但为论文演示简化):
// 链头清单解析(示意)——魔数 + 碎片计数 + (n-1) 条记录 + 链头自身载荷 u8[0..3] === "K7FB" // 魔数校验 n = BE(u16[6..7]) // 碎片计数 l0 = BE(u32[8..11]) // 链头载荷长度 // 每条记录: len(1B) | path(len) | size(4B BE) | sha256(32B) // 末尾 l0 字节即链头内容
// 密钥派生与异或解码(示意)—— 与加载器同一算法 key = await sha256( SALT + "/" + relPath ) buf = new Uint8Array(await resp.arrayBuffer()) // 先按 key 异或还原明文(干扰文件在此步即失配) // 再以 len + sha256 与清单比对,全部通过才拼接
附录 E 图表清单
| 编号 | 名称 | 载体 |
|---|---|---|
| 图 3-1 | 系统五层逻辑架构 | SVG |
| 图 3-2 | 碎片包文件构成(环形) | ECharts |
| 图 4-1 | 碎片链加载时序 | SVG |
| 图 5-1 | 待办生命周期状态机 | SVG |
| 图 6-1 | 六类业务实体关系 | SVG |
| 图 8-1 | 信息架构(含统计预留位) | SVG |
| 图 9-1 | 五条提取路径成本 | ECharts |
| 表 2-1 | 功能需求总表 | 表格 |
| 表 3-1 | 交付物清单 | 表格 |
| 表 3-2 | 四种交付形态对比 | 表格 |
| 表 4-1 | 分层威胁模型 | 表格 |
| 表 4-2 | 链头清单字节布局 | 表格 |
| 表 4-3 | 核心性能指标 | 表格 |
| 表 4-4 | 与主流保护方案比较 | 表格 |
| 表 5-1 | 数据管理操作清单 | 表格 |
| 表 5-2 | 功能模块 × 旅程覆盖对照 | 表格 |
| 表 6-1 | 核心实体字段说明 | 表格 |
| 表 6-2 | localStorage 键名清单 | 表格 |
| 表 7-1 | 自我保护层配置项 | 表格 |
| 表 9-1 | 五条提取路径评估 | 表格 |
| 表 10-1 | 回归验证实验与结果 | 表格 |