1实现原理 · 为什么它能做到
实现基础是一份手写的 Gemini Web 客户端:把开源 gemini_webapi 逐文件移植为 TypeScript(client/types/utils),因此能在没有官方 API Key 的情况下出文本与图像。
| `scripts/gemini-webapi/*` | TypeScript port of `gemini_webapi` (GeminiClient, types, utils) |
端点集中在 constants.ts:INIT 取页面令牌、StreamGenerate 走私有流式接口、ROTATE_COOKIES 轮换会话 cookie、UPLOAD 传参考图、BATCH_EXEC 走 batchexecute。
'https://gemini.google.com/_/BardChatUi/data/assistant.lamda.BardFrontendService/StreamGenerate',
认证第一步是取 access token:init 时用已有 cookie 调 get_access_token,拿不到有效 token 就抛错——所有生成请求都要带上它。
const [token, valid] = await get_access_token(this.cookies, this.proxy, vb);
凭据来源是浏览器会话 cookie:load-browser-cookies 会探测本机调试端口(/json/version,默认 127.0.0.1)并按需 spawn 浏览器进程读取真实登录态。
const res = await fetch_with_timeout(`http://127.0.0.1:${port}/json/version`, { timeout_ms: 5_000 });
cookie 与轮换结果被持久化到本地文件:cookie-file 以 JSON 写盘,另有 rotate-1psidts 把刷新得到的 1PSIDTS 缓存到文件。
await writeFile(p, JSON.stringify(payload, null, 2), 'utf8');
图像能力落在 types/image.ts:下载远端图像并写盘(writeFile(dest, buf)),参考图则经 upload-file 走 content-push 上传通道。
await writeFile(dest, buf);
多轮会话不是服务端会话,而是把 Gemini 的 chat metadata 存进本地 sessions/<id>.json,靠 --sessionId 复用同一 metadata 续聊。
Session files stored in data directory under `sessions/<id>.json`.
逆向使用被显式要求“先同意”:首次必须校验 consent 文件(accepted 且 disclaimerVersion 1.0),拒绝则退出。
1. Check if consent file exists with `accepted: true` and `disclaimerVersion: "1.0"`
请求层带重试装饰器 running:客户端未初始化时自动 init,遇到 APIError 且有剩余重试次数则 sleep 1s 后重试。
if (e instanceof APIError && r > 0) {
2核心能力
3外部依赖
| Kind | Dependency / Endpoint |
|---|---|
| network | gemini.google.com(INIT 页面取令牌 + StreamGenerate 私有生成接口 + batchexecute) |
| network | accounts.google.com(RotateCookies 轮换会话 cookie) |
| network | content-push.googleapis.com(参考图上传) |
| network | lh3.googleusercontent.com(返回图像资源 gg-dl) |
| cli | bun / npx(以 npx -y bun 直接运行脚本,无运行时抽象) |
| cli | 本机 Chrome/Chromium/Edge 可执行文件(按需 spawn 以读取会话 cookie) |
4管控建议与判定依据
- SKILL.md / 脚本: 调用未公开或逆向工程的私有 API / 伪造客户端标识
- SKILL.md / 脚本参数: 包含绕过自动化检测、关闭宿主沙箱或跳过 SSL 证书校验
- SKILL.md / 会话存储: 读取或复用浏览器用户登录态与会话 Cookie
- 本地凭据 / 浏览器配置: 读取用户登录 Cookie/会话/密钥环: 浏览器会话 cookie:__Secure-1PSID / __Secure-1PSIDTS 等(本地 cookies.json,或经本机 Chrom
- scripts/: 执行本地脚本或命令: scripts/main.ts(由 npx -y bun 运行;会按需探测并 spawn 本机浏览器读 cookie)
- 网络端点: 声明外部网络访问: https://gemini.google.com/app(INIT 取页面令牌)
- 本地工作目录: 文件读写与工件输出: cookies.json(凭据落盘:写入会话 cookie)
5第二遍独立确认
- [ok] 逆向 API 而非官方 API(red 主因之一) — constants.ts 直指 gemini.google.com 的 StreamGenerate 私有路径;SKILL.md/description 自述 reverse-engineered,并设 consent 门禁。
- [ok] 读取浏览器会话 cookie(red 主因之二) — load-browser-cookies.ts 探测 127.0.0.1 调试端口并按需 spawn 浏览器;SKILL.md 自述 First run opens browser for Google auth。
- [ok] 凭据落盘 — cookie-file.ts 的 writeFile(p, JSON.stringify(payload, null, 2)) 与 rotate-1psidts.ts 的 writeFile(cachePath, v) 两处写盘,路径由 paths.ts 解析。
- [ok] 无 TLS 降级 / 无 stealth 伪装 / 无任意代码执行 — 相关行为在 bundle 正文与 §3 风险扫描中均零命中;调度只有 init 重试与 sleep。
- [ok] consent 门禁存在但为“软门禁” — SKILL.md 要求先建 consent.json 再使用;但脚本自身不校验该文件,属文档级约束,已写入 risks。
- [ok] 功能声明与实现相符 — 文本/图像/vision/多轮四项在 SKILL.md Options 与 main.ts/client.ts 均有对应实现,未见夸大。
6结论
a98a97c1f7c81879…