Skip to content

Commit 2cb2f6a

Browse files
abwugejames-6-23
andauthored
Feat/session token account (#155)
* feat: add session token account import * feat: use uTLS Chrome fingerprint for session token refresh * fix: remove session token from refresh token form --------- Co-authored-by: KYX <kyxjames23@gmail.com>
1 parent b8f0783 commit 2cb2f6a

7 files changed

Lines changed: 474 additions & 39 deletions

File tree

admin/handler.go

Lines changed: 50 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1102,10 +1102,26 @@ func (h *Handler) getAccountUsageWindows(ctx context.Context) (map[int64]*databa
11021102
type addAccountReq struct {
11031103
Name string `json:"name"`
11041104
RefreshToken string `json:"refresh_token"`
1105+
SessionToken string `json:"session_token"`
11051106
ProxyURL string `json:"proxy_url"`
11061107
}
11071108

1108-
// AddAccount 添加新账号(支持批量:refresh_token 按行分割)
1109+
func splitAccountCredentialLines(raw string, sanitize bool) []string {
1110+
lines := strings.Split(raw, "\n")
1111+
tokens := make([]string, 0, len(lines))
1112+
for _, line := range lines {
1113+
token := strings.TrimSpace(line)
1114+
if sanitize {
1115+
token = strings.TrimSpace(security.SanitizeInput(token))
1116+
}
1117+
if token != "" {
1118+
tokens = append(tokens, token)
1119+
}
1120+
}
1121+
return tokens
1122+
}
1123+
1124+
// AddAccount 添加新账号(支持批量:refresh_token/session_token 按行分割)
11091125
func (h *Handler) AddAccount(c *gin.Context) {
11101126
var req addAccountReq
11111127
if err := c.ShouldBindJSON(&req); err != nil {
@@ -1117,8 +1133,8 @@ func (h *Handler) AddAccount(c *gin.Context) {
11171133
req.Name = security.SanitizeInput(req.Name)
11181134
req.ProxyURL = security.SanitizeInput(req.ProxyURL)
11191135

1120-
if req.RefreshToken == "" {
1121-
writeError(c, http.StatusBadRequest, "refresh_token 是必填字段")
1136+
if strings.TrimSpace(req.RefreshToken) == "" && strings.TrimSpace(req.SessionToken) == "" {
1137+
writeError(c, http.StatusBadRequest, "refresh_token 或 session_token 是必填字段")
11221138
return
11231139
}
11241140

@@ -1140,23 +1156,40 @@ func (h *Handler) AddAccount(c *gin.Context) {
11401156
return
11411157
}
11421158

1143-
// 按行分割,支持批量添加
1144-
lines := strings.Split(req.RefreshToken, "\n")
1145-
var tokens []string
1146-
for _, line := range lines {
1147-
t := strings.TrimSpace(security.SanitizeInput(line))
1148-
if t != "" {
1149-
tokens = append(tokens, t)
1159+
// 按行分割,支持批量添加。refresh_token 与 session_token 同时填写时,
1160+
// session_token 可填写一行应用到所有 RT,也可与 RT 行数一一对应。
1161+
refreshTokens := splitAccountCredentialLines(req.RefreshToken, true)
1162+
sessionTokens := splitAccountCredentialLines(req.SessionToken, true)
1163+
total := len(refreshTokens)
1164+
if total == 0 {
1165+
total = len(sessionTokens)
1166+
}
1167+
if len(refreshTokens) > 0 && len(sessionTokens) > 1 && len(sessionTokens) != len(refreshTokens) {
1168+
writeError(c, http.StatusBadRequest, "session_token 行数需为 1 或与 refresh_token 行数一致")
1169+
return
1170+
}
1171+
1172+
var seeds []tokenCredentialSeed
1173+
for i := 0; i < total; i++ {
1174+
seed := tokenCredentialSeed{}
1175+
if len(refreshTokens) > 0 {
1176+
seed.refreshToken = refreshTokens[i]
1177+
}
1178+
if len(sessionTokens) == 1 {
1179+
seed.sessionToken = sessionTokens[0]
1180+
} else if len(sessionTokens) > 1 {
1181+
seed.sessionToken = sessionTokens[i]
11501182
}
1183+
seeds = append(seeds, seed)
11511184
}
11521185

1153-
if len(tokens) == 0 {
1154-
writeError(c, http.StatusBadRequest, "未找到有效的 Refresh Token")
1186+
if len(seeds) == 0 {
1187+
writeError(c, http.StatusBadRequest, "未找到有效的 Refresh Token 或 Session Token")
11551188
return
11561189
}
11571190

11581191
// 限制批量添加数量
1159-
if len(tokens) > 100 {
1192+
if len(seeds) > 100 {
11601193
writeError(c, http.StatusBadRequest, "单次最多添加100个账号")
11611194
return
11621195
}
@@ -1167,15 +1200,15 @@ func (h *Handler) AddAccount(c *gin.Context) {
11671200
successCount := 0
11681201
failCount := 0
11691202

1170-
for i, rt := range tokens {
1203+
for i, seed := range seeds {
11711204
name := req.Name
11721205
if name == "" {
11731206
name = fmt.Sprintf("account-%d", i+1)
1174-
} else if len(tokens) > 1 {
1207+
} else if len(seeds) > 1 {
11751208
name = fmt.Sprintf("%s-%d", req.Name, i+1)
11761209
}
11771210

1178-
id, err := h.db.InsertAccount(ctx, name, rt, req.ProxyURL)
1211+
id, err := h.db.InsertAccountWithCredentials(ctx, name, tokenCredentialMap(seed), req.ProxyURL)
11791212
if err != nil {
11801213
log.Printf("批量添加账号 %d 失败: %v", i+1, err)
11811214
failCount++
@@ -1186,11 +1219,7 @@ func (h *Handler) AddAccount(c *gin.Context) {
11861219
h.db.InsertAccountEventAsync(id, "added", "manual")
11871220

11881221
// 热加载:直接加入内存池
1189-
newAcc := &auth.Account{
1190-
DBID: id,
1191-
RefreshToken: rt,
1192-
ProxyURL: req.ProxyURL,
1193-
}
1222+
newAcc := accountFromCredentialSeed(id, req.ProxyURL, seed)
11941223
h.store.AddAccount(newAcc)
11951224

11961225
if !h.store.GetLazyMode() {

auth/token.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,11 @@ func RefreshWithSessionToken(ctx context.Context, sessionToken string, proxyURL
205205
return nil, nil, fmt.Errorf("创建 session 请求失败: %w", err)
206206
}
207207
req.Header.Set("Accept", "application/json")
208-
req.Header.Set("User-Agent", "CodexProxy/1.9")
208+
req.Header.Set("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36")
209+
req.Header.Set("Accept-Language", "en-US,en;q=0.9")
210+
req.Header.Set("Sec-Fetch-Dest", "empty")
211+
req.Header.Set("Sec-Fetch-Mode", "cors")
212+
req.Header.Set("Sec-Fetch-Site", "same-origin")
209213
req.AddCookie(&http.Cookie{Name: "__Secure-next-auth.session-token", Value: sessionToken})
210214
if ResinRequestDecorator != nil && accountID != "" {
211215
req.Header.Set("X-Resin-Account", accountID)
@@ -215,7 +219,7 @@ func RefreshWithSessionToken(ctx context.Context, sessionToken string, proxyURL
215219
if ResinRequestDecorator != nil && accountID != "" {
216220
client = &http.Client{Timeout: 30 * time.Second}
217221
} else {
218-
client = buildHTTPClient(proxyURL)
222+
client = buildUTLSHTTPClient(proxyURL)
219223
}
220224
resp, err := client.Do(req)
221225
if err != nil {

0 commit comments

Comments
 (0)