Repository navigation
指纹绕过方案:纯 JS 生成有效 fingerprint(无需 opencode CLI / MITM) #1
jcleng
started this conversation in
Show and tell
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
指纹绕过方案:纯 JS 生成有效 fingerprint(无需 opencode CLI / MITM)
1. 背景:为什么会 403 FreeTierError
opencode.ai/inference/v1服务端有一道 client-fingerprint gate。裸请求会被拒绝:服务端要求请求必须同时携带:
User-Agentopencode/<版本>(小写,版本 ≥ 1.18;老版本 →426,非 opencode →403)x-opencode-sessionses_+ 12 位小写 hex + 14 位 base62(见下)streamtrue(否则403)toolsbash/glob/grep/read(缺任意一个 →403)AuthorizationBearer public(服务端不校验,仅作对齐)2. 关键结论:session id 可以在纯 JS 里算出来
最容易踩坑的是
x-opencode-session。早期版本以为它带校验和、只能由 opencode 二进制生成——这是错的。它其实就是 opencode 普通的 descending 标识符,结构完全公开。2.1 算法来自 opencode 源码
SessionID.create()="ses_" + descending()(packages/schema/src/session-id.ts),而descending()(packages/schema/src/identifier.ts)就是:所以真实 id 的形状是
ses_+ 12 位小写 hex + 14 位 base62(共 30 字符)。(同理,message id =
"msg_" + ascending(),即不带取反。)2.2 服务端到底校验什么(ablation 实测)
对真实端点逐位消融,得到的确切规则:
0xfff - counter,要求 counter ≤ 63(counter 0–63 → 200,64–4095 → 403);x-opencode-session-id若存在,必须等于x-opencode-session(不一致 → 403);x-opencode-client/x-opencode-project/x-opencode-request/x-session-affinity/X-Session-Id都是装饰性的(乱填也 200)。没有任何校验和。 只要按上面的算法生成、并保证 counter ∈ [1,63],就一定通过。
3. 方案:纯 JS 生成,不再需要 opencode
src/fingerprint.js现在直接复刻上面的算法:encodeIdentifier(timestamp, { descending }):复刻 opencode 的descending()/ascending();newSessionId()=ses_+ descending id;newMessageId()=msg_+ ascending id;buildFingerprintHeaders():生成完整 header 组(
user-agent、x-opencode-session、x-opencode-session-id(与前者相同)、x-opencode-request、x-opencode-client: cli、x-opencode-project: global)。没有
child_process,没有 MITM / TLS 拦截,没有openssl,没有一次性 CA。UA 仍默认
opencode/latest/2.0.22/cli,可用OPENCODE_UA覆盖。4. 集成点
src/fingerprint.jsdescending()/ascending()算法、session 模式(per-request/sticky)、header 构造、指纹状态src/config.jssrc/fingerprint.jsre-export 指纹 API(单一来源);UA / 工具常量 / 环境变量 / 端点(getZenEndpoints()默认inference/v1)src/upstream.jsfingerprintHeaders()注入生成的指纹 + 解析出的Authorization;relayChatCompletions()汇聚上游 SSEserver.jsfingerprint source: generated)src/routes.js//__sessiongenerated= 纯 JS 计算)5. Docker:不再需要装 opencode
原来的
Dockerfile为了 spawn opencode + MITM,必须用 glibc 基础镜像(node:24-bookworm-slim)并安装@opencode/cli(约 200MB 的原生二进制)+openssl,镜像约 2.4GB。现在指纹是纯 JS 算的,所以:
opencode,不再安装openssl;验证:
curl http://127.0.0.1:8791/__session # 期望 fingerprint.source == "generated"6. 环境变量
ZEN_SESSION_MODEper-requestper-request(每次请求新ses_,最稳)或sticky(进程内复用)ZEN_SESSION_ROTATE_SECONDS0sticky模式下每隔 N 秒轮换 sessionOPENCODE_UAopencode/latest/2.0.22/cliOPENCODE_BASE_OVERRIDEhttps://opencode.ai/inference/v1)/zen/v1(已被拒 403),跑旧镜像时用它指向/inference/v1ZEN_MODELS_TTL_SECONDS600ZEN_MODELS_TIMEOUT_MS5000/models发现超时NODE_USE_ENV_PROXY1(容器内,检测到 http(s) 代理时自动开)fetch读https_proxy(Node ≥ 24)。SOCKS5 不支持7. 验证结果
opencode.ai/inference/v1/chat/completions→ HTTP 200(同一合法 body/headers,/zen/v1则 403)。fingerprint.source == "generated",非流式与流式(以[DONE]收尾)均正常返回。ghcr.io/jcleng/opencode-free-provider:latest)实测:容器内同样是generated,端到端 200。/zen/v1时 403)通过加OPENCODE_BASE_OVERRIDE='https://opencode.ai/inference/v1'重建容器后恢复正常。8. 后续维护
上游若再次收紧检测、又开始
403,几乎总是集中在 fingerprint 或端点,而不是代理管道:/zen/v1切到/inference/v1);改OPENCODE_BASE_OVERRIDE或src/config.js的getZenEndpoints()。src/fingerprint.js(算法、UA、MAX_COUNTER)。OPENCODE_UA(默认opencode/latest/2.0.22/cli,本身带latest,可先观察是否自动兼容)。8d25b65。All reactions