Download internal/syncer/cred.go from a3216/gcli2api: direct link, hf CLI and curl.
- Browser
- Download file 3.67 kB
-
https://huggingface.co/spaces/a3216/gcli2api/resolve/main/internal/syncer/cred.go
- Command line
-
hf download hf://spaces/a3216/gcli2api/internal/syncer/cred.go
-
curl -L -o cred.go https://huggingface.co/spaces/a3216/gcli2api/resolve/main/internal/syncer/cred.go
3.67 kB
| package syncer | |
| import ( | |
| "encoding/json" | |
| "strings" | |
| ) | |
| // credential 是从一个 auth 文件里抽出来的、同步对账需要的**最小字段集**。 | |
| // | |
| // 为什么只留这几个:冲突裁决只需要回答"哪一端的 accessToken 更新", | |
| // 判据就是 expiresAt(外加 refreshToken 有无)。没必要把整份凭证建模一遍—— | |
| // 少建模就少一处会被上游改动作废的地方。 | |
| type credential struct { | |
| UID string | |
| Nickname string | |
| ExpiresAt int64 | |
| HasRefresh bool | |
| Realm string | |
| Domain string | |
| } | |
| // parseCredential 解析 auth 文件的两种磁盘形态,返回 (凭证, 是否为可用凭证)。 | |
| // | |
| // 形态(与网关 auth.Parse 同口径): | |
| // | |
| // 嵌套形 {"auth":{...},"account":{...}} —— 插件 OAuth 输出 | |
| // 扁平形 {"accessToken":...,"uid":...} —— 手写 / 旧版 | |
| // | |
| // ⚠️ 这里**刻意不复用 internal/auth**,尽管那是网关自己的解析器。 | |
| // 原因:本工具要做成**独立 exe**(用户换掉上游新版的 wb2api.exe 时,启动器不受影响), | |
| // 一旦 import 网关内部包,启动器和网关的源码目录就绑死了——上游重构 internal/auth | |
| // 会让启动器连编译都过不去。自带一份容错解析,代价是几十行,换来的是两边解耦。 | |
| // | |
| // 容错原则:解析不出来**不是错误**。返回 false 表示"这只是一堆字节",对账会退化成 | |
| // 按内容哈希直接比较(仍能正确同步,只是失去了 expiresAt 这档更精细的裁决能力)。 | |
| func parseCredential(raw []byte) (credential, bool) { | |
| var probe map[string]json.RawMessage | |
| if len(raw) == 0 || json.Unmarshal(raw, &probe) != nil { | |
| return credential{}, false | |
| } | |
| var c credential | |
| if _, nested := probe["auth"]; nested { | |
| var n struct { | |
| Auth struct { | |
| AccessToken string `json:"accessToken"` | |
| RefreshToken string `json:"refreshToken"` | |
| ExpiresAt int64 `json:"expiresAt"` | |
| Domain string `json:"domain"` | |
| Realm string `json:"realm"` | |
| } `json:"auth"` | |
| Account struct { | |
| UID string `json:"uid"` | |
| Nickname string `json:"nickname"` | |
| } `json:"account"` | |
| } | |
| if json.Unmarshal(raw, &n) != nil { | |
| return credential{}, false | |
| } | |
| if strings.TrimSpace(n.Auth.AccessToken) == "" { | |
| return credential{}, false | |
| } | |
| c = credential{ | |
| UID: n.Account.UID, | |
| Nickname: n.Account.Nickname, | |
| ExpiresAt: n.Auth.ExpiresAt, | |
| HasRefresh: strings.TrimSpace(n.Auth.RefreshToken) != "", | |
| Realm: n.Auth.Realm, | |
| Domain: n.Auth.Domain, | |
| } | |
| } else { | |
| var f struct { | |
| AccessToken string `json:"accessToken"` | |
| RefreshToken string `json:"refreshToken"` | |
| ExpiresAt int64 `json:"expiresAt"` | |
| Domain string `json:"domain"` | |
| Realm string `json:"realm"` | |
| UID string `json:"uid"` | |
| Nickname string `json:"nickname"` | |
| } | |
| if json.Unmarshal(raw, &f) != nil { | |
| return credential{}, false | |
| } | |
| if strings.TrimSpace(f.AccessToken) == "" { | |
| return credential{}, false | |
| } | |
| c = credential{ | |
| UID: f.UID, | |
| Nickname: f.Nickname, | |
| ExpiresAt: f.ExpiresAt, | |
| HasRefresh: strings.TrimSpace(f.RefreshToken) != "", | |
| Realm: f.Realm, | |
| Domain: f.Domain, | |
| } | |
| } | |
| c.Realm = resolveRealm(c.Realm, c.Domain) | |
| return c, true | |
| } | |
| // resolveRealm 归一化 realm:显式非空优先,否则按 domain 后缀推断,最后回落 "cn"。 | |
| func resolveRealm(explicit, domain string) string { | |
| if r := strings.TrimSpace(explicit); r != "" { | |
| return r | |
| } | |
| d := strings.ToLower(strings.TrimSpace(domain)) | |
| if d == "workbuddy.ai" || strings.HasSuffix(d, ".workbuddy.ai") { | |
| return "global" | |
| } | |
| return "cn" | |
| } | |