cicy-desktop 2.1.245 → 2.1.246
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/e2e-sync.md +68 -0
- package/package.json +1 -1
- package/src/backends/homepage-react/assets/index-BGms-POH.js +379 -0
- package/src/backends/homepage-react/assets/index-CJVu2wMT.css +1 -0
- package/src/backends/homepage-react/index.html +2 -2
- package/src/backends/local-teams.js +80 -43
- package/src/i18n/locales/en.json +22 -1
- package/src/i18n/locales/fr.json +22 -1
- package/src/i18n/locales/ja.json +22 -1
- package/src/i18n/locales/zh-CN.json +22 -1
- package/src/main.js +10 -7
- package/workers/render/package-lock.json +7 -0
- package/workers/render/package.json +1 -0
- package/workers/render/src/App.css +11 -0
- package/workers/render/src/App.jsx +255 -5
- package/src/backends/homepage-react/assets/index-C6Zrdgc0.css +0 -1
- package/src/backends/homepage-react/assets/index-DqFJ0g1T.js +0 -377
package/docs/e2e-sync.md
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# E2E 跨端同步 · 服务端零明文
|
|
2
|
+
|
|
3
|
+
> 目标(三条):①运营后台**只看用户活跃**;②服务端**不存任何敏感明文**;③用户数据**跨端同步**(desktop / mobile / 未来 web)。
|
|
4
|
+
> 结论:活跃走非敏感心跳;敏感数据(团队 `host_url`、内嵌 `?token=`、api_token 等)**客户端加密 → 服务端只存密文 → 各设备本地解密**。
|
|
5
|
+
|
|
6
|
+
## 0. 边界:什么加密、什么不加密
|
|
7
|
+
|
|
8
|
+
| 数据 | 敏感? | 存法 |
|
|
9
|
+
|---|---|---|
|
|
10
|
+
| deviceId + last_seen(活跃心跳) | 否 | 服务端**明文**(POST /api/device/register 已做) |
|
|
11
|
+
| 账号 tier / plan | 否 | 服务端明文 |
|
|
12
|
+
| 团队 `host_url`(含 `?token=`)、api_token、团队名等用户数据 | **是** | 客户端 E2E 加密,服务端**只存密文 + 盲索引** |
|
|
13
|
+
|
|
14
|
+
前提成立的原因:服务端**不需要** host_url 明文(不代理、不解析,只当同步 blob + 去重键)。
|
|
15
|
+
|
|
16
|
+
## 1. 密码学原语(三端统一 libsodium)
|
|
17
|
+
|
|
18
|
+
desktop=Node(`sodium-native`/`libsodium-wrappers`)、mobile=RN(`react-native-libsodium`/expo)、cloud 只转发不解密(如需校验有 Go 版)。原语一一对应:
|
|
19
|
+
|
|
20
|
+
| 用途 | libsodium |
|
|
21
|
+
|---|---|
|
|
22
|
+
| 数据加密 | `crypto_aead_xchacha20poly1305_ietf`(AEK + 随机 24B nonce) |
|
|
23
|
+
| 盲索引(去重/查找,不泄原文) | `crypto_generichash`(BLAKE2b keyed,key=HKDF(AEK,"idx")) |
|
|
24
|
+
| 给某设备包 AEK | `crypto_box_seal`(匿名密封盒,只需对方公钥) |
|
|
25
|
+
| 设备密钥对 | `crypto_box_keypair`(X25519) |
|
|
26
|
+
| 口令找回(纯单设备兜底) | `crypto_pwhash`(Argon2id) |
|
|
27
|
+
|
|
28
|
+
## 2. 密钥体系
|
|
29
|
+
|
|
30
|
+
- **AEK**:账号级随机 256bit 数据密钥,**永不明文上云**。所有敏感数据用它加密。
|
|
31
|
+
- **设备密钥对**:每台设备一对 X25519,**公钥**注册到云端(公钥不敏感);私钥进安全区(desktop=OS keychain;mobile=expo-secure-store;**禁明文存**)。
|
|
32
|
+
- **wrappedAEK**:AEK 用**每台设备公钥各密封一份**存云端(云端解不开)。
|
|
33
|
+
- **口令找回(可选但纯 mobile 用户必需)**:`wrappedAEK_pw = aead(Argon2id(口令,salt), AEK)`,存云端。
|
|
34
|
+
|
|
35
|
+
### 谁先谁后都行(first-device)
|
|
36
|
+
任一端都可能是"第一台":它生成 AEK + 给自己密封一份。之后新设备上线 → 注册公钥 → **一台在线老设备**把 AEK 密封给新设备公钥,云端转发。**不能假设 desktop 先**。
|
|
37
|
+
纯 mobile 用户(永远只一台)没有第二设备互包 → **口令找回是必需**,否则换机=数据全丢。
|
|
38
|
+
|
|
39
|
+
## 3. 同步流程
|
|
40
|
+
|
|
41
|
+
**写(加/改团队):**
|
|
42
|
+
1. `enc = aead(AEK, nonce, JSON{host_url, name, ...})`
|
|
43
|
+
2. `idx = blake2b_keyed(idxKey, normalize(host_url))`
|
|
44
|
+
3. `POST /api/teams { kind, host_url_enc: {n,ct}, host_url_idx: idx }`(**不再发 host_url 明文**)
|
|
45
|
+
4. 云端按 `owner + host_url_idx` get-or-create(去重),存密文。
|
|
46
|
+
|
|
47
|
+
**读(拉团队):**
|
|
48
|
+
1. `GET /api/teams` → 每条 `{host_url_enc, host_url_idx, ...}`
|
|
49
|
+
2. 客户端 `aead_open(AEK, enc)` → 明文 URL/字段;解不开(AEK 还没拿到)→ 显示"待解锁"。
|
|
50
|
+
|
|
51
|
+
**新设备上线(拿 AEK):**
|
|
52
|
+
1. 生成密钥对,`POST /api/device/register { …, pubkey }`
|
|
53
|
+
2. 轮询/推送:云端有给我的 `wrappedAEK`? 有 → `box_seal_open(privkey, wrappedAEK)` → AEK。
|
|
54
|
+
3. 没有 → 提示"在另一台已登录设备上批准此设备" → 老设备 `box_seal(newPub, AEK)` → `POST /api/device/grant`;或走口令找回。
|
|
55
|
+
|
|
56
|
+
## 4. 迁移
|
|
57
|
+
- 云端历史 `host_url` 明文:客户端下次同步补发 `host_url_enc + idx`,服务端回填后**删明文列 / 清历史明文**。
|
|
58
|
+
- 过渡期:两端字段并存,客户端优先读 enc,回落明文;全部设备升级后云端下线明文。
|
|
59
|
+
|
|
60
|
+
## 5. 必然代价(E2E 固有)
|
|
61
|
+
- 云端**看不到也搜不到** URL(运营后台不能展示 URL —— 但活跃、tier 等非敏感照常)。
|
|
62
|
+
- AEK 全丢(所有设备 + 无口令)= 同步数据不可恢复。
|
|
63
|
+
- 新设备无老设备在线时,靠口令找回。
|
|
64
|
+
|
|
65
|
+
## 6. 三端分工
|
|
66
|
+
- **cicy-desktop**:libsodium 加解密 + 盲索引 + seal/unseal;私钥 OS keychain;registerCustomTeam 改发 enc+idx、GET 后解密;first-device/grant 逻辑。
|
|
67
|
+
- **cicy-mobile(w-10036)**:同一套 libsodium;私钥 expo-secure-store;grant/口令找回;确认 custom 团队本地化不外泄。
|
|
68
|
+
- **cicy-cloud(w-10122)**:schema `host_url → host_url_enc + host_url_idx`;按 idx 去重;device 表加 `pubkey`;存/转发 `wrappedAEK`(register/grant/找回);**服务端零明文使用**;清历史 host_url 明文。心跳活跃保持。
|