Rainytoken/docs/签到核心请求.md

137 lines
6.4 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.

# WB(WorkBuddy)与 Trae 每日签到核心请求
> 本文档整理自仓库现有实现(源码为准):
> - `app/src/main/java/com/rainy/token/data/repository/TraeRepository.kt`
> - `app/src/main/java/com/rainy/token/data/repository/WorkBuddyRepository.kt`
>
> 其中 **WB = 腾讯 WorkBuddy**(非微博)。所有请求均为 `POST`,body 默认为 `{}`。
## 一、端点汇总
| 服务 | 用途 | URL | Body |
| --- | --- | --- | --- |
| Trae(CN) | 查询签到状态 | `https://api.trae.cn/trae/api/v2/ug/checkin_credits/status` | `{}` |
| Trae(CN) | 执行签到 | `https://api.trae.cn/trae/api/v2/ug/checkin_credits/claim` | `{}`(9074 时换 `{"req_source":2}` → `{"req_source":1}`) |
| WorkBuddy | 查询签到状态(优先) | `https://www.codebuddy.cn/v2/billing/meter/checkin-activity-status` | `{}` |
| WorkBuddy | 查询签到状态(兜底) | `https://www.codebuddy.cn/v2/billing/meter/checkin-status` | `{}` |
| WorkBuddy | 执行签到 | `https://www.codebuddy.cn/v2/billing/meter/daily-checkin` | `{}` |
| WorkBuddy | accessToken 刷新 | `https://copilot.tencent.com/v2/plugin/auth/token/refresh` | 头 `X-Refresh-Token` |
## 二、Trae 核心请求源码
认证头:`Authorization: Cloud-IDE-JWT <jwt>`,`x-device-id` 必须是账号绑定的官方客户端设备 ID。
```kotlin
// 官方签到接口路径
const val CHECKIN_STATUS_PATH = "/trae/api/v2/ug/checkin_credits/status"
const val CHECKIN_CLAIM_PATH = "/trae/api/v2/ug/checkin_credits/claim"
private fun checkinRequest(
jwt: String,
deviceId: String,
deviceSrc: String,
path: String,
bodyJson: String = "{}"
): Result<String> {
val requestId = java.util.UUID.randomUUID().toString()
val request = Request.Builder()
.url("https://api.trae.cn" + path)
.addHeader("Content-Type", "application/json")
.addHeader("Accept", "*/*")
.addHeader("User-Agent", "VSCode 1.107.1 (TRAE SOLO CN)")
.addHeader("Authorization", "Cloud-IDE-JWT " + jwt)
.addHeader("X-User-Region", "CN")
.addHeader("Accept-Language", "zh-CN")
.addHeader("Package-Type", "stable_cn")
.addHeader("X-Lgw-Req-Sdk-Type", "3")
.addHeader("X-Market-Client-Id", "VSCode 1.107.1")
.addHeader("X-Device-Brand", "83DG")
.addHeader("X-Device-Type", "windows")
.addHeader("X-OS-Version", "Windows 11 Pro")
.addHeader("App-Version", "0.1.61")
.addHeader("X-Request-Id", requestId)
.addHeader("X-TT-Trace-Id", ttTraceId(requestId))
.addHeader("X-Device-Id", deviceId)
.addHeader("Sec-Fetch-Dest", "empty")
.addHeader("Sec-Fetch-Mode", "no-cors")
.addHeader("Sec-Fetch-Site", "none")
.post(bodyJson.toRequestBody("application/json".toMediaType()))
.build()
// ...
}
```
### Trae 签到结果判定
- `code = 0 / 200` → **SUCCESS**(成功)
- `code = 1001 / 10001`,或文案含 `已签到 / 已经签到 / 明日再来 / 今日已完成 / 已领取 / already / checked / claimed` → **ALREADY**(今日已签)
- 文案含 `设备 / device / machine` → **DEVICE_BLOCKED**(设备级拦截)
- 文案含 `参与 / 稍后重试 / 火爆 / 繁忙 / 限流 / 排队 / too many / retry / busy / popular / later` → **RETRYABLE**(临时限流)
- 其余 → **FAILED**
### Trae 注意事项
- UA 必须是 `VSCode 1.107.1 (TRAE SOLO CN)`,这是签到走的 VSCode 插件进程身份;与 IDE 主进程 / Web 混用会触发风控。
- `X-Device-Id` 不可用固定 ClientID `en1oxy7wnw8j9n`(所有用户相同),会按设备风控拒绝。
- 仓库内置默认设备 ID:`ACCOUNT_BOUND_DEVICE_ID = "895482260673817"`,账号级,换设备需更新。
- INTL 区签到接口未实测,仓库实现直接不支持。
## 三、WorkBuddy(WB)核心请求源码
认证头:`Authorization: Bearer <accessToken>`。签到域名是 `www.codebuddy.cn`(余额主查询才是 `www.workbuddy.cn`)。
```kotlin
// 查询今日签到状态(两条路径依次 fallback,共享 token 轮换状态)
suspend fun fetchCheckinStatus(accountId: String? = null): Result<CheckinStatus> {
val body = authedPostFirstSuccessful(
credential,
accountId,
"/v2/billing/meter/checkin-activity-status",
"/v2/billing/meter/checkin-status"
) ?: return Result.failure(RepositoryError.Unknown())
return runCatching { parseCheckin(body) }...
}
// 执行签到
suspend fun checkIn(accountId: String? = null): Result<CheckinStatus> {
val body = when (val r = authedPost(credential, "/v2/billing/meter/daily-checkin")) {
is AuthedPostResult.Ok -> r.body
is AuthedPostResult.Failed -> r.body
// ...
}
// code=0 成功;code=10001 或文案含「已签/今日/already」→ 已签
}
// 带自动 refresh 一次的 POST 核心
private fun authedPost(credential: Credential.WorkBuddyCredential, path: String): AuthedPostResult {
var access = credential.accessToken
var refresh = credential.refreshToken
repeat(2) { attempt ->
val request = Request.Builder()
.url("https://www.codebuddy.cn" + path)
.addHeader("Authorization", "Bearer " + access)
.addHeader("Accept", "application/json")
.addHeader("Content-Type", "application/json")
.post("{}".toRequestBody(jsonMedia))
.build()
// 2xx → Ok
// 401/403 且第一次尝试 → tryRefesh(refresh) 换新 token 后重试
// refresh 请求头携带 X-Refresh-Token <refreshToken>
// 轮换出的新凭据必须先落库再用,否则旧 refreshToken 单次消费后失效
}
}
```
### WorkBuddy 签到结果判定
- `code = 0` → **SUCCESS**
- `code = 10001`,或文案含 `已签 / 已经签到 / 今日 / already / checked / claimed` → **ALREADY**(今日已签)
- 其余 → **FAILED**(HTTP 400 body 也可能携带签到业务语义,需透传解析,不能直接当网络错误丢弃)
## 四、通用约定
1. Trae 用 `Cloud-IDE-JWT`,WorkBuddy 用 `Bearer`,两者凭据类型不同,不能混用。
2. 两者签到都幂等:今日已签时服务端返回已签语义,客户端本地也会记录 `lastCheckinDate` 短路,避免重复请求。
3. 401/403:Trae 直接视为凭据失效;WorkBuddy 会尝试用 refreshToken 轮换一次。
4. 不要随机生成设备 ID(Trae)或篡改客户端头,否则会被风控(Trae 9074「参与用户太多」)。