1实现原理 · 为什么它能做到
三条发布路线共存:官方 API(快、需凭证)、浏览器 CDP(慢、复用登录态)、remote-api(本地渲染 + SSH SOCKS5 隧道让白名单服务器 IP 出站)。
| `scripts/wechat-api.ts` | Article posting via API (文章) |
凭证解析链是显式的多来源优先级:EXTEND.md 账户块 → 带前缀环境变量 → WECHAT_APP_ID/WECHAT_APP_SECRET(process.env、<cwd>/.baoyu-skills/.env、~/.baoyu-skills/.env)。
buildCredentialSource("process.env", process.env, "WECHAT_APP_ID", "WECHAT_APP_SECRET"),
API 路线按微信官方流程四步走:取 access_token → uploadimg(正文图)→ material/add_material(封面素材)→ draft/add(建草稿)。
const DRAFT_URL = "https://api.weixin.qq.com/cgi-bin/draft/add";
正文图片有微信侧硬限制,脚本先转码/压缩再上传,并用 magic bytes 纠正声明格式与实际格式不符的情况。
export const WECHAT_BODY_IMAGE_MAX_SIZE = 1024 * 1024; // 1MB
remote-api 的机制是本地完成渲染/图片处理/草稿组装,只把通往 api.weixin.qq.com 的 HTTPS 出站经 SSH 动态端口转发(SOCKS5)出去。
are tunneled through an SSH SOCKS5 dynamic port forward (`ssh -N -D`)
浏览器路线的登录态来自持久化共享 Chrome profile,且启动参数强制关闭 Chrome 的自动化特征标记(--disable-blink-features=AutomationControlled)——技术性反自动化检测绕过的典型手法。
extraArgs: ['--disable-blink-features=AutomationControlled', '--start-maximized'],
同目录还带一个『真实按键粘贴』助手,其用途被明确写成绕过网站可检测的合成事件。
This bypasses CDP's synthetic events which websites can detect and ignore.
登录态获取有外发通道:未登录时抓取登录二维码,可选经 Telegram Bot 发到指定聊天。
const tgResp = await fetch(`https://api.telegram.org/bot${botToken}/sendPhoto`, {
工程化配套:多账号 EXTEND.md 块与账号解析,外加一个前置环境/权限自检脚本。
EXTEND.md supports an `accounts:` block for managing multiple Official Accounts.
2核心能力
3外部依赖
| 类型 | 依赖 |
|---|---|
| api | 微信公众平台 access_token |
| api | 正文图片上传(uploadimg) |
| api | 永久素材/封面上传(add_material) |
| api | 建草稿(draft/add,含 need_open_comment / only_fans_can_comment 等字段) |
| api | Telegram Bot API(可选:把登录二维码发到指定聊天) |
| network | 浏览器访问 mp.weixin.qq.com(公众号后台登录与发文界面) |
| cli | ssh(-N -D SOCKS5 动态端口转发;仅密钥认证) |
| cli | 本地 Chrome/Chromium(--remote-debugging-port 启动,带 AutomationControlled 关闭参数) |
| cli | 系统剪贴板工具(macOS: swift/osascript;Linux: wl-copy 或 xclip;Windows: powershell.exe) |
| cli | 粘贴按键工具(macOS osascript System Events;Linux xdotool/ydotool;Windows PowerShell SendKeys) |
| package | jimp / @jsquash/webp / socks / baoyu-md / baoyu-chrome-cdp |
| cli | bun(内部以 npx -y bun 调起同目录脚本) |
4风险提醒 风险提醒:红色 · 谨慎使用
- 反自动化检测绕过(判红主因) — 浏览器流程强制关闭 Chrome 自动化特征标记,并配有『真实按键绕过合成事件』的助手脚本(后者在本 commit 未接主流程)。此类行为可能违反平台条款并触发账号风控,后果由使用者承担;建议只在自有账号、自有内容上使用。
- 账号凭证与登录态的高价值接触面 — AppSecret、SSH 私钥、Telegram token 与共享 Chrome profile 登录态集中在本地;共享 profile 同时被同仓其他浏览器类脚本使用,任一环节被篡改都可能影响公众号后台。
- 登录二维码可经 Telegram 外发 — 启用 TELEGRAM_BOT_TOKEN/CHAT_ID 后,未登录时会把公众号登录二维码(等同登录凭证)发到该聊天;若 bot token 泄露,第三方可抢先扫码登录。
- 会真实改动线上账号内容 — API 路线会创建草稿(draft/add);浏览器/图文路线可带 --submit 提交。草稿也会出现在账号内容管理里,误操作需人工清理。
5第二遍独立确认
- [ok] 反自动化检测绕过(判红主因) — scripts/cdp.ts:125 `extraArgs: ['--disable-blink-features=AutomationControlled', '--start-maximized'],` 由 launchChromeBase 传给 Chrome(浏览器脚本共用);scripts/paste-from-clipboard.ts:5-7 明写 'This bypasses CDP's synthetic events which websites can detect and ignore.'
- [ok] 该绕过是否真的在发布路径上 — cdp.ts 的 Chrome 启动函数是 wechat-browser.ts 与 wechat-article.ts 的入口(两者都从 cdp.ts 导入并把自动化参数交给 launchChromeBase);paste 助手本身在本 commit 未被这两个主流程引用,已在 reason/injection_surface 如实标注程度。
- [ok] 凭证读取链 — wechat-extend-config.ts 的 loadCredentials 依次尝试 EXTEND.md account → 前缀 env/.env → WECHAT_APP_ID/WECHAT_APP_SECRET(process.env、cwd .env、home .env),与 SKILL.md 描述一致。
- [ok] 微信 API 端点与 payload 规则 — wechat-api.ts 常量区四个 URL 与 SKILL.md 的 draft/add payload rules(article_type/thumb_media_id/need_open_comment/only_fans_can_comment/content_source_url)逐项对应。
- [ok] remote-api 的隧道实现与承诺 — wechat-remote-publish.ts 组装 `-N -T -D 127.0.0.1:<port>` 等参数且仅用密钥(`if (config.identityFile) args.push("-i", …)`);SKILL.md 承诺不在远端落文件、AppSecret 不出本机——源码内确无远端文件写入路径(只建隧道与本地 SOCKS 出站)。
- [ok] Telegram 二维码外发为可选 — wechat-article.ts sendQrToTelegram 在 `if (!botToken || !chatId) return;` 之后才发请求;未配置即完全不走该路径。
- [ok] 依赖与剪贴板工具链 — package.json/bun.lock 声明 jimp、@jsquash/webp、socks、baoyu-md、baoyu-chrome-cdp;copy-to-clipboard.ts 分别用 swift/osascript、wl-copy/xclip、powershell.exe,与 check-permissions.ts 的检查项一致。
- [ok] 无其他安全降级 — 全目录 grep no-sandbox / rejectUnauthorized / insecure / NODE_TLS_REJECT_UNAUTHORIZED 零命中;Chrome 启动参数仅常规项 + AutomationControlled。
6结论
1f149b01778641d8…1567581c26