更新补号机制

This commit is contained in:
2026-06-02 23:44:44 +08:00
parent e6b84aad80
commit 269fbd08ff
21 changed files with 2130 additions and 2112 deletions
+77 -16
View File
@@ -1,9 +1,8 @@
// Package tokenprobe 使用号池内 Token 调用各厂商接口做可用性探测。
// Cursor 走 api2.cursor.sh 的 Connect + protobuf 二进制流(非 JSON 文本接口)。
package tokenprobe
import (
"bytes"
"crypto/tls"
"encoding/base64"
"encoding/json"
"fmt"
@@ -14,9 +13,13 @@ import (
"time"
)
var httpClient = &http.Client{Timeout: 25 * time.Second}
var httpClient = &http.Client{
Timeout: 12 * time.Second,
Transport: &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
},
}
// Result 探测结果(Cursor 会填充 ProbeMessage / Endpoint / BytesRead / RawPreview 等)
type Result struct {
OK bool `json:"ok"`
Detail string `json:"detail"`
@@ -26,12 +29,10 @@ type Result struct {
BytesRead int `json:"bytesRead,omitempty"`
RawPreview string `json:"rawPreview,omitempty"`
RequestBodyPrefixHex string `json:"requestBodyPrefixHex,omitempty"`
// StreamProtocol / StreamNote 仅 Cursor Agent 探测填充,说明二进制流与结论边界
StreamProtocol string `json:"streamProtocol,omitempty"`
StreamNote string `json:"streamNote,omitempty"`
StreamProtocol string `json:"streamProtocol,omitempty"`
StreamNote string `json:"streamNote,omitempty"`
}
// ProbeOfficial 按号池模块探测 Tokencursor / windsurf / krio
func ProbeOfficial(module, rawToken string) Result {
tok := normalizeBearerToken(strings.TrimSpace(rawToken))
if tok == "" {
@@ -58,18 +59,78 @@ func normalizeBearerToken(s string) string {
}
func probeCursor(token string) Result {
return probeCursorHiAgent(token)
url := "https://api2.cursor.sh/auth/full_stripe_profile"
req, err := http.NewRequest(http.MethodGet, url, nil)
if err != nil {
return Result{OK: false, Detail: "构造请求失败: " + err.Error()}
}
req.Header.Set("Authorization", "Bearer "+strings.TrimSpace(token))
req.Header.Set("X-Cursor-Client-Version", "3.0.16")
req.Header.Set("X-New-Onboarding-Completed", "false")
req.Header.Set("X-Ghost-Mode", "true")
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Cursor/3.0.16 Chrome/142.0.7444.265 Electron/39.8.1 Safari/537.36")
req.Header.Set("Accept", "*/*")
req.Header.Set("Origin", "vscode-file://vscode-app")
req.Header.Set("Accept-Encoding", "gzip, deflate, br, zstd")
req.Header.Set("Accept-Language", "zh-CN")
req.Header.Set("Priority", "u=1, i")
resp, err := httpClient.Do(req)
if err != nil {
return Result{OK: false, Detail: "请求官方账单接口超时/网络失败: " + err.Error(), HTTPStatus: 500}
}
defer resp.Body.Close()
body, _ := io.ReadAll(io.LimitReader(resp.Body, 16384))
jsonStr := string(body)
res := Result{
HTTPStatus: resp.StatusCode,
Endpoint: url,
BytesRead: len(body),
RawPreview: jsonStr,
StreamProtocol: "HTTP/2 JSON REST",
StreamNote: "2026型画像探测",
ProbeMessage: "GET full_stripe_profile",
}
if resp.StatusCode != http.StatusOK {
res.OK = false
res.Detail = fmt.Sprintf("Token已失效或被官方拉黑(HTTP %d", resp.StatusCode)
return res
}
if strings.Contains(jsonStr, `"noModelsRemaining":true`) ||
strings.Contains(jsonStr, `"is_usage_limited":true`) ||
strings.Contains(jsonStr, `"hard_limit_reached"`) ||
strings.Contains(jsonStr, `"blocked"`) ||
(strings.Contains(jsonStr, `"membershipType":"free"`) && strings.Contains(jsonStr, `"trialEligible":false`)) {
res.OK = false
res.Detail = "Token存活,但属于无额度Free空壳号(上号必弹付费墙)"
return res
}
if len(jsonStr) < 10 {
res.OK = false
res.Detail = "官方接口返回异常空数据"
return res
}
res.OK = true
res.Detail = "检测成功,高速算力/Agent额度健康"
return res
}
func probeWindsurf(apiKey string) Result {
payload := map[string]interface{}{
"metadata": map[string]string{
"apiKey": apiKey,
"ideName": "windsurf",
"ideVersion": "0.0.0",
"extensionName": "windsurf",
"extensionVersion": "0.0.0",
"locale": "zh",
"apiKey": apiKey,
"ideName": "windsurf",
"ideVersion": "0.0.0",
"extensionName": "windsurf",
"extensionVersion": "0.0.0",
"locale": "zh",
},
}
raw, err := json.Marshal(payload)
@@ -122,7 +183,7 @@ func probeKiro(accessToken string) Result {
if arn == "" {
return Result{
OK: false,
Detail: "无法从 Token 中解析 profileArnKiro 暂无法自动探测(需完整登录 JWT",
Detail: "无法从 Token 中解析 profileArnKiro 暂无法自动探测",
}
}