ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Joplin E2EE 同步快照解析:一个加密 Resource 同步项的字段、密文格式与测试用途

2026/9/10 11:30:10 拓冰建站 浏览量
Joplin E2EE 同步快照解析:一个加密 Resource 同步项的字段、密文格式与测试用途 Joplin E2EE 同步快照解析一个加密 Resource 同步项的字段、密文格式与测试用途【免费下载链接】joplinJoplin - the privacy-focused note taking app with sync capabilities for Windows, macOS, Linux, Android and iOS.项目地址: https://gitcode.com/GitHub_Trending/jo/joplin在 Joplin 的端到端加密E2EE同步体系中同步目标sync target上的每个对象都会以「同步项」的形式落盘本文以仓库中一个真实的测试快照 bda6d120223140afbe7f03ef1d876400.md 为样本逐字段拆解一个启用端到端加密后的 Resource资源同步项它是如何表示的、encryption_cipher_text里的密文由哪些参数构成、以及这类快照文件在 app-cli 的同步测试流程中扮演什么角色。读完后你可以独立解读 Joplin E2EE 同步目录中的任意.md同步项文件并复现快照的生成与部署流程。快照目录的整体结构这个样本文件位于同步目标快照目录的版本 2 下完整路径为 packages/app-cli/tests/support/syncTargetSnapshots/2/e2ee/bda6d120223140afbe7f03ef1d876400.md。同目录下还存在一个平行的normal未加密目录两者结构相同均包含一组以对象 ID 命名的.md文件、一个info.json和一个locks/目录e2ee 目录20 个加密同步项 info.json内容为{version:2}声明该快照对应的同步协议版本normal 目录对应的未加密快照便于对照加密与否时的字段差异。这些快照并非手工维护的示例而是由测试工具自动生成、再回放到其它测试中。packages/lib/testing/syncTargetUtils.ts 中的deploySyncTargetSnapshot会把syncTargetSnapshots/{版本}/{normal|e2ee}整个目录拷贝到测试用的同步目录syncDir模拟一个「远端服务器已经存有这些对象」的状态其配套函数mainL119-L147则反向工作创建测试数据、按需开启加密setEncryptionEnabled(true) 加载主密钥、执行一次同步再把同步目录内容固化回快照目录。官方服务规范 readme/dev/spec/server_items.md 也明确引用了该目录作为「序列化 Joplin 同步项」的示例来源供PUT /api/items接口的实现方参考。字段逐行解读一个加密 Resource 同步项样本文件全文只有 14 行是典型的「Joplin 同步项序列化格式」——以字段名: 值逐行排列。对照未加密的normal快照即可看出加密模式下敏感字段的值被清空由密文字段替代。逐字段说明如下字段样本值含义idbda6d120223140afbe7f03ef1d876400同步项的全局唯一 ID32 位十六进制文件名即取自它mime空资源的 MIME 类型。E2EE 模式下该字段被加密远端可见部分为空filename空资源的原始文件名同上密文加密后不对外暴露created_time/updated_time后者为2020-07-25T10:55:20.778Z服务端时间戳updated_time用于同步时判断冲突与版本先后user_created_time/user_updated_time空客户端本地记录的用户时间戳file_extension空文件扩展名同样是可被加密的字段encryption_cipher_textJED0100002...见下文上述敏感字段的密文这是整个文件的技术核心encryption_applied1标记「本对象已应用端到端加密」同步器据此决定解密路径encryption_blob_encrypted空用于大体积加密 blob 的分块场景本样本未使用size空资源字节大小加密后对外隐藏is_shared空是否共享资源的标志位type_4对象类型。对照 packages/lib/BaseModel.ts 中ItemType枚举的Resource 4可确认这是一个「笔记资源」类型对象如笔记中嵌入的图片或附件而非 Note 或 Foldertype_字段本身不参与加密——同步协议需要它来路由处理逻辑。packages/lib/Synchronizer.ts 中同步器正是通过content.type_ BaseModel.TYPE_RESOURCE判断是否处于「创建或更新资源」的分支进而走资源的特殊处理如 blob 传输这解释了为什么即使mime、filename、size全部加密为空同步器依然能正确识别并处理这个对象。encryption_cipher_textJED 前缀与 libsodium 密封盒参数密文字段的完整取值形如JED0100002205a1a0987e82cc400c90582492f814c23c000308{iv:zyEI38ZCb2UGn3cy0Ejjjg,v:1,iter:101,ks:128,ts:64,mode:ccm,adata:,cipher:aes,salt:Gyo7bQeqz2w,ct:vqxf3Ul0liOt86X6uiY3/...}可以把它拆成「前缀 序列化 JSON 密文」两部分JED前缀Joplin 对序列化加密对象Encrypted object Data的标识。后续字符包含版本号01与加密对象自身的 ID000002205a1a0987e82cc400c90582492f814c23c000308中可辨识出与a1a0987e82cc400c90582492f814c23c相关的对象标识用于区分未加密的普通数据与加密数据。libsodium 密封盒secretbox序列化结构{iv:...,v:1,iter:101,ks:128,ts:64,mode:ccm,adata:,cipher:aes,salt:...,ct:...}是libsodium-wrappers的crypto_secretbox_easy序列化输出的标准字段集v: 1序列化格式版本iter: 101、ks: 128、ts: 64KDF 迭代次数 101 次、密钥长度 128 位、标签长度 64 位mode: ccm、cipher: aes底层为 AES-CCM 认证加密iv/salt随机初始向量与盐每次加密都重新生成保证同一明文产生不同密文adata附加认证数据此处为空ctBase64 编码的实际密文内部封装的是被加密的原始对象 JSON含mime、filename、size等明文值。结合 packages/lib/testing/syncTargetUtils.ts 中 e2ee 分支的逻辑——先setEncryptionEnabled(true)再loadEncryptionMasterKey()后才执行同步——可以确认解密这一层密文需要客户端主密钥派生出的密钥只有持有主密钥或 Joplin Cloud 中托管的密钥材料的客户端才能还原出mime: image/jpeg之类的明文元数据。这正是 E2EE 的语义服务端本例中是快照目录模拟的远端只保存密文与encryption_applied: 1标志元数据本身不出现在任何明文字段中。encryption_blob_encrypted在本样本中为空从源码结构看它是为资源文件体blob分块加密传输预留的字段元数据小、直接内联进encryption_cipher_text而 blob 体积大会走独立的加密通道并记录在此处。快照如何驱动同步回归测试理解了这个文件的来龙去脉就能明白 Joplin 如何用「快照回放」做跨版本、跨实现的同步回归生成main(e2ee)以客户端 1 初始化数据库与同步器按 testData 描述的结构folder1 → subFolder1/subFolder2(note1resource, tag1) …共 5 个文件夹、5 篇笔记、2 个资源、2 个标签创建对象开启 E2EE 并加载主密钥同步一次再把同步目录内容写回syncTargetSnapshots/{syncVersion}/e2ee/L138-L146。本样本中info.json的version: 2即同步协议版本对应目录2/。回放其它测试如协议升级/迁移相关测试 synchronizer_MigrationHandler.test.ts调用deploySyncTargetSnapshot(e2ee, 2)将快照拷入syncDir随后让同步器与之同步验证客户端能正确解密元数据、识别type_ 4的资源对象、完成 blob 下载等全链路行为。校验checkTestDataL75-L111会逐条断言每篇笔记可按标题加载、父文件夹存在、笔记中的资源图片 URL 能解析出可加载的 Resource 对象、标签与笔记的关联完整——这正对应快照中note1/note5携带resource: true的两类 Resource 同步项本样本即其中之一。小结从一份快照文件看 Joplin E2EE 同步项格式一个同步项 id 元数据字段 type_ 加密时encryption_cipher_text与encryption_applied本样本是一个type_ 4的 Resource 对象元数据mime、filename、size、file_extension全部被 AES-CCM 密封盒密文替代仅id、时间戳与类型号保持明文以支撑同步协议运行。密文为 libsodiumcrypto_secretbox_easy序列化格式v/iter/ks/ts/mode/cipher/iv/salt/ct由JED前缀标识加密序列化对象与 BaseModel.ts 中的类型枚举、Synchronizer.ts 中的资源分支处理相互印证。快照目录是「生成—固化—回放」的闭环syncTargetUtils.ts 负责双向流转normal与e2ee两套目录支持明文/加密路径的对照回归server_items.md 则把它作为服务端PUT /api/items接口的序列化示例来源。需要说明的前提syncTargetSnapshots是版本 2 同步协议的测试数据字段格式随协议版本演进可能变化本文解析以该仓库当前快照内容及其配套测试工具为准。【免费下载链接】joplinJoplin - the privacy-focused note taking app with sync capabilities for Windows, macOS, Linux, Android and iOS.项目地址: https://gitcode.com/GitHub_Trending/jo/joplin创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考