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

6.4 KiB
Raw Blame History

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。

// 官方签到接口路径
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)。

// 查询今日签到状态(两条路径依次 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「参与用户太多」)。