社区讨论LinuxDo 最新
Qoder CN、Trae CN、WorkBuddy免费签到脚本
每天打开 IDE 客户端点一下"签到"领积分,这件事完全可以交给脚本。 最近我同时使用三个 AI 编程工具——Qoder CN、Trae CN、WorkBuddy——它们都提供了签到积分机制,但三种客户端的登录态格式各不相同:有的明文存储,有的自定义加密,有的用了 DPAPI + AES-GCM 双重保护。通过逐一拆解,我找到了一套通用的自动化思路,今天把它整理成文,并在文末附上三个完整可运行的 Python 脚本。 声明:全文基于公开技术分析,接口来自官方客户端同源调用,仅供个人学习研究使用。建议仅在个人电脑上…
内容摘要
作者:#起风了灬
板块:#开发调优
每天打开 IDE 客户端点一下"签到"领积分,这件事完全可以交给脚本。
最近我同时使用三个 AI 编程工具——Qoder CN、Trae CN、WorkBuddy——它们都提供了签到积分机制,但三种客户端的登录态格式各不相同:有的明文存储,有的自定义加密,有的用了 DPAPI + AES-GCM 双重保护。通过逐一拆解,我找到了一套通用的自动化思路,今天把它整理成文,并在文末附上三个完整可运行的 Python 脚本。
声明:全文基于公开技术分析,接口来自官方客户端同源调用,仅供个人学习研究使用。建议仅在个人电脑上运行,勿将 token 相关代码外传。
一、统一思路:只读登录态,直调官方 API
三个工具的底层逻辑完全一致:
只读本地登录态文件
↓
解出 token(或直接使用)
↓
调官方签到 API
↓
写日志,不打印敏感信息
关键设计原则:
只读不改任何登录态文件(避免干扰客户端状态同步)
不打印 token(日志里只留尾 6 字符脱敏)
多账号去重(同一 token 只签到一次)
幂等处理(今天已签则跳过,服务端会返回 replayed:true)
下面分别讲三种格式的差异和坑点。
二、Qoder CN:DPAPI + AES-256-GCM 双重保护
2.1 凭证文件结构
Qoder CN 是 Electron 客户端,登录态拆成两个文件:
文件
路径
内容
保护方式
Local State
%APPDATA%\com.qodercn.app.stable\
32 字节 AES 密钥
DPAPI(用户作用域)
auth.v1.dat
同上目录
token / refreshToken / user
AES-256-GCM
解密链路:
Local State 的 os_crypt.encrypted_key (base64)
→ base64 decode → 前 5 字节 = "DPAPI"
→ CryptUnprotectData(需当前 Windows 用户已登录)
→ 32 字节 AES-256 密钥
→ 解 auth.v1.dat(v10 + 12B nonce + CT + 16B tag)
→ JSON:{token, refreshToken, expiresAt, user}
实测 expiresAt = 2026-10-10T06:49:23Z(约 16 天有效期)。
2.2 抓包定位签到接口
直接抓包这条路走不通:我的 agent 会话 shell 挂在主进程 7544 底下,重启客户端会把自己杀掉;第二实例又会被单实例锁秒退。但客户端自带了一个"抓包器"——main.log 里每一行都是结构化的请求日志:
[INFO] [Campaign] 活动状态请求发出 {"method":"GET","origin":"https://openapi.qoder.com.cn",
"path":"/sash/api/v1/me/campaigns","clientType":10,"forceRefresh":true,
"requestHeaders":{"Accept":"application/json","Authorization":"[redacted]",
"Cosy-ClientType":"10","Cosy-Version":"0.3.4",...}}
用日志 diff 脚本(基线 + 点击窗口对比),毫秒级对齐操作与请求行,三步定位接口。
2.3 签到接口
GET https://openapi.qoder.com.cn/sash/api/v1/me/campaigns
POST https://openapi.qoder.com.cn/sash/api/v1/me/campaigns/{campaignId}/claim
Header 必需:Authorization: Bearer <token> + Cosy-ClientType: 10(缺了这个返回 200 但 campaigns 空数组,是个容易踩的坑)。
签到是幂等的:
{"grantId":"01a0c7f4-79f6-7700-b286-be70d0efb479",
"status":"CLAIMED","replayed":true,
"benefit":{"kind":"CREDITS","amount":100,
"validity":{"mode":"RELATIVE_DAYS","days":30}}}
replayed:true 表示服务端不会重复发权益,乱点无害。
2.4 意外发现:签到其实是"自动"的
通过对比 iframe JS(远端 growth-page/activity-iframe,在 CDN 上)发现:
// iframe 自动 claim 所有 CLAIMABLE 的活动
L = useCallback(() => {
const e = a.flatMap(c =>
"viewDetails" !== c.actionType
? []
: (y.current.add(c.id), [P(c.id)])
);
Promise.allSettled(e.map(...))
}, [a, n, P])
面板一打开就自动把 CLAIMABLE 的条目全部 POST claim 了——所以你看到的"点签到按钮",实际上只是触发了 campaigns 重拉,真签到动作在 Surface 加载时就完成了。
2.5 额度数字接口
面板上展示的 Credits 累计值来自另一组接口(字段名与客户端内部不同,别照 bundle 猜):
GET /sash/api/v1/ai-conversations/credits-summary
→ {totalCredits, peakCredits}
GET /sash/api/v1/ai-conversations/seat-activity
→ {cumulativeActiveDays, currentConsecutiveDays, maxConsecutiveDays, lastActiveDate}
实测字段名是 currentConsecutiveDays,不是 bundle 里的 currentStreakDays。
三、Trae CN / TRAE SOLO CN:iCubeAuthInfo 自定义加密
3.1 凭证文件
%APPDATA%\Trae CN\User\globalStorage\storage.json
{
"iCubeAuthInfo://icube.cloudide": "<base64 密文>"
}
3.2 解密算法
客户端自定义格式(非标准 DPAPI):
t = base64.b64decode(enc)
key = t[6:38] # 32B key
sha = hashlib.sha512(key).digest()
xor = bytes(a ^ b for a, b in zip(URE, DRE)) # URE/DRE 是硬编码常量
h = hashlib.sha512(sha + xor).digest()
aes_key, iv = h[:16], h[16:32]
ct = t[38:]
plain = unpad(AES.new(aes_key, AES.MODE_CBC, iv).decrypt(ct), 16)
return json.loads(plain[64:].decode()) # 去掉 64B HMAC
3.3 签到接口
POST https://api.trae.cn/trae/api/v2/ug/checkin_credits/status
POST https://api.trae.cn/trae/api/v2/ug/checkin_credits/claim
Headers:Authorization: Cloud-IDE-JWT <token> + x-device-id(从 ahanet/tt_net_config.config 自动读取)+ X-User-Region。
设备 ID 的读取顺序:配置 → 最近 5 条 main.log 里的 [ICDRS] did: → 兜底常量(一般留空即可)。
四、WorkBuddy 5.6.0+:$wbEncrypted AES-256-GCM 信封
4.1 5.6.0 变更
5.6.0 之前 accessToken 是明文 JSON,5.6.0 起改为:
{
"auth": {
"accessToken": "$wbEncrypted:<base64>",
"domain": "...",
"expiresAt": 1790783940000
}
}
4
资讯来源
LinuxDo