Files
yunke/docs/superpowers/specs/phase0-findings.md
T
2026-08-01 13:29:14 +08:00

84 lines
5.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Phase 0 侦察结论(实现期实测补充)
- **日期**:2026-08-01
- **方式**:浏览器实地登录云客 CRM,在页内 `fetch` 真实接口 + 抓包
- **配套**:[数据字典](2026-08-01-yunke-data-dictionary.md)、[设计文档](2026-08-01-yunke-data-mirror-design.md)
- **状态**:关键项全部确认 ✅;少量次要项标注 ⏳
---
## 1. 登录与鉴权 ✅
- **`GET /newuc/login/getSecureKey`**(公开接口,无需登录)返回 RSA 公钥:
```
{"code":10000,"data":{"public_exponent":"10001","modulus":"9a370c33...(hex)"}}
```
→ **密码用 RSA 加密**(PKCS1 v1.5,exponent=0x10001=65537,modulus 为返回的 hex)。
- **`POST /usercenter/login/pcLogin`**:请求体 `{account, password}`(`password`=RSA 加密后的 hex/base64)—— 字段名为推断,实现时若失败尝试 `{username, password}` / `{account, pwd}` 等变体。登录成功返回会话 cookie + `userid`/`company`。
- **数据接口鉴权 = 会话 cookie**:实测在登录后的页内用 `fetch('/wechatweb/...', {credentials:'include'})`(**不带** `userid`/`company` 等自定义头)即可 200 返回数据。自定义请求头(`userid`/`company`/`source:yunkepc`/`channel:4`)是**信息性的,非必需**。
- **影响**:`YunkeClient` 只需持有会话 cookie 即可调所有数据接口;自定义头可继续带(无害)。
- **会话可从 localStorage 重建**:`userid`、`company`、`h5Token`、`userList` 都在 localStorage(冒烟脚本 existing-session 模式可据此 + cookie 运行)。
## 2. 微信消息类型码 ✅(实测枚举)
| type | 含义 | 处理 |
|---|---|---|
| `1` | 文字 | 存 `text` |
| `-2` | 日期分隔符 | **丢弃**(非真实消息) |
| `2` | 图片/表情(webp) | `file`/`fileTh` 为**直接 URL** + `md5` → 下载去重 |
| `3` | 图片(旧格式) | `file` 为**不透明 ID**(如 `07215407292664565911ce5105`)→ 需另解析/下载接口 ⏳ |
| `4` | 视频(mp4) | `file` 直接 URL + `md5` → 下载 |
| `10` | 系统/链接/名片/邀请 | `file` 为 `support.weixin.qq.com/...` URL → **非媒体,跳过下载** |
| `6` `9` `13` `15` `21` `22` | 其他(语音/文件/转账/红包/引用等疑似的码) | ⏳ 实现期按需枚举确认(`raw_json` 已留底) |
> `normalize_wechat_type` 已映射 `1→text`、`-2→divider`;需补 `2→image`、`3→image_legacy`、`4→video`、`10→system` 等。
## 3. 媒体下载机制 ✅
**聊天媒体**(图片/视频/文件):
- 主机:`wx.oss.yunkecn.com`
- 路径:`/wechatMsgFile/{companyCode}/{userId}/ossCallback/{aa}/{bb}/{cc}/{md5}.{ext}`
- 例:`https://wx.oss.yunkecn.com/wechatMsgFile/8m0atd/{userId}/ossCallback/ea/8f/74/ea8f74e7797e63505731e8c51222c554.webp`
- 消息里给 `file`(原图)/`fileTh`(缩略图)/`fileHd`(高清) + `md5`(去重键)
- **直接 GET 即可下载**(公开 OSS,无需鉴权);按 `md5` 去重存储
- 例外:type=`3` 图片的 `file` 是不透明 ID(非 URL)→ 需另找下载接口 ⏳
**通话录音 / 语音通话录音**:
- 主机:`yunke-pcfile.oss-cn-beijing.aliyuncs.com`
- 电话录音:`/callFile/{company}/{userId}/YYYY/MMDD/{callNumber}_{ts}.mp3`(`PhoneCall.recordFile`)
- 微信语音通话录音:`/wechat-call/{company}/{imei}/ossCallback/{ts}_{ts}.mp3`(`voiceCall.ossFileName`)
**头像**:`wx.qlogo.cn`、`mmhead.c2c.wechat.com`、`pc.oss.yunkecn.com`(外链,抓到即下载)
## 4. 语音通话 ✅
- `POST /wechatweb/callRecord/queryWeChatVoiceList`,total=**333**
- 字段:`id`、`userId`/`userName`/`userPhone`/`userWeChatNickName`/`userWeChatHeadImg`(员工)、`talker`/`talkerNickName`/`talkerAlias`/`talkerHeadImg`(客户)、`callType`、`isSend`(0呼入/1呼出)、`callStatus`(1接通有录音/2无应答)、**`ossFileName`(录音URL)**、`ossFileExist`、`duration`(秒,字符串)/`durationFile`(秒,int)、`startTime`/`endTime`、`weChatId`、`remark`(如"通话时长02:31"/"对方无应答")、`isRoom`(群通话?)、`callFileId`
- 归一到 `PhoneCall` 表,`channel='voice_call'`,`record_file`←`ossFileName`
## 5. WhatsApp 联系人 ✅
- `POST /qqweb/WhatsAppUser/businessFriendList`,total=**11292**
- 字段:`uid`(员工 `phone@s.whatsapp.net`)、`userId`/`userName`/`salePhone`/`salesNickName`(员工)、`friendUid`(客户→`friend_id`)、`nickName`、`phone`、`createTime`/`lastUpdate`、`groupNum`/`contactsNum`/`talkerCount`/`messageCount`/`sensitiveWordNum`
- 归一到 `Customer` 表,`channel='whatsapp'`
## 6. WhatsApp 媒体 ⏳
- 消息里给 `mediaName`(文件名,如 `{uid}_{keyId}.jpg`),**非 URL** → 需专门下载接口
- ⏳ 实现期:读 `whatsapp-service-*.js` 或触发一次真实图片加载,找到 `mediaName → 文件` 的下载接口(很可能也是 `wx.oss.yunkecn.com` 或同系 OSS)
## 7. 群成员昵称 ⏳
- `chatroom/getChatroomList` 的 `memberIds` 给的是**分号分隔的 wxid 列表**(不含昵称/头像)
- ⏳ 群内成员的昵称/头像可能需另调接口(实现期确认);本期可先存 wxid,昵称后补
---
## 对实现的影响(解锁项)
- **登录**:`app/session/login.py::encrypt_password` 改为真实 RSA(用 `cryptography` 从 modulus/exponent 构造公钥加密)→ 解锁自动登录 + 真实端到端冒烟
- **媒体下载(M2.6)**:微信 type 2/4 直接 URL 下载、按 md5 去重;type 3 标记待解析;type 10 跳过
- **语音通话(M2.4)**:`queryWeChatVoiceList` 字段已确认,录音直链下载
- **WhatsApp 联系人(M3.3)**:`businessFriendList` 字段已确认
- **鉴权简化**:`YunkeClient` cookie-only 即可(自定义头可选)