Back to home@pan17

dsh-github-token-injector

DSH Web client plugin: auto-inject GitHub Authorization header on api.github.com requests to defeat shared-IP rate limits.

Stars
1
Language
JavaScript
Created
Aug 24, 2026
Updated
Aug 25, 2026
GitHub repo

Introduction

dsh-github-token-injector

DeepSeek Harness (DSH) Web 客户端插件:自动给所有发往 api.github.com 的浏览器请求 注入 Authorization: Bearer <token> 头,解决共享代理 IP 触发的 GitHub API 限流问题 (匿名访问每小时仅 60 次,配 PAT 后提升至 5000 次/小时)。

免去手动给浏览器扩展或代理工具配置 header。Token 仅保存在浏览器 localStorage, 不上传任何服务端。

dsh-github-token-injector Settings card

为什么需要

  • DSH Web 内的皮肤管理器、插件市场等模块会从 api.github.com 拉元数据判断更新
  • 共享出口 IP 的代理环境容易被 GitHub 限流(HTTP 403),UI 一直显示「无法判断更新」
  • 配一个 GitHub PAT(Personal Access Token)可立刻绕过这个限制

安装

推荐:从 npm 安装

npx @deepseek-ai/dsh plugin --profile web add dsh-github-token-injector

web 换成你的 profile 名。装完 重启 DSH

⚠️ 别用 npx dsh plugin——npm 上 dsh 这个名字早在 2016 年就被一个不相关的 JS shell 包占了(dsh@1.0.1,作者 infusion),它没暴露 CLI bin,会报 could not determine executable to run。DSH 的 CLI 在 scoped 包 @deepseek-ai/dsh 下,必须用完整名。

备选:从 GitHub 装

# 锁定版本
npx @deepseek-ai/dsh plugin --profile web add github:pan17/dsh-github-token-injector#v0.1.0
# 或默认分支最新
npx @deepseek-ai/dsh plugin --profile web add github:pan17/dsh-github-token-injector

本地 link 安装(开发场景)

把插件目录用 link: 装到 web profile:

# 1. 确认插件目录在
#    <your-repo-dir>/dsh-github-token-injector

# 2. 编辑 web profile 的 package.json:
#    a) dependencies 加:
#       "dsh-github-token-injector": "link:<your-repo-dir>/dsh-github-token-injector"
#    b) dsh.profile.bundles 在皮肤管理器之前插入:
#       "dsh-github-token-injector"
# 关键:bundles 顺序决定 cordis loader 创建 entry 的先后,
# 把 token injector 放在皮肤管理器之前能保证 window.fetch 在
# skin-manager 的 githubJson() 调用前已经被 patch。

# 3. 安装并重启
cd $DSH_HOME/profiles/web
pnpm install
npx @deepseek-ai/dsh web --no-open

### 构建脚本授权

如果 pnpm 提示不允许跑构建脚本(`ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED`),在该 profile 的 `pnpm-workspace.yaml` 加上:

```yaml
allowBuilds:
  dsh-github-token-injector: true

配置 Token

⚠️ 每次修改配置后请重启 DSH 并刷新浏览器 — DSH 主进程的 token 缓存不会热更新,必须重启 host 进程才能生效;浏览器刷新一次让客户端 factory 重新把 localStorage 里的 token 推到 host 进程(DSH 重启会清空 host 缓存)。

方式一:Settings UI(推荐)

  1. 打开 Web UI(默认 http://127.0.0.1:3080
  2. 进入 设置 → GitHub Token 卡片
  3. 粘入 PAT,点击「保存」
  4. 点「立即测试」主动验证(状态点变绿 = 有效)

方式二:浏览器 Console

// 设置
localStorage.setItem('DSH_GITHUB_TOKEN', '<your-pat>')

// 读当前 token
window.__githubTokenInjector.getToken()

// 看状态
window.__githubTokenInjector.getStatus()
// → { state: "ok" | "invalid" | "forbidden" | "rate-limited" | "no-token" | "unknown", ... }

// 清空
window.__githubTokenInjector.clearToken()

// 主动触发鉴权探针
window.__githubTokenInjector.forcePrecheck()

方式三:环境变量注入(高级)

任何 DSH 客户端插件在启动时给 window.__DSH_GITHUB_TOKEN__ = '<your-pat>' 即可被读取 (适用于多 profile 共用同一 token 的场景)。

方式四:host 端环境变量(无人值守)

DSH 主进程(Node.js)启动前设:

# Linux / macOS
export DSH_GITHUB_TOKEN='ghp_xxx'
npx @deepseek-ai/dsh web --no-open

# PowerShell
$env:DSH_GITHUB_TOKEN = 'ghp_xxx'
npx @deepseek-ai/dsh web --no-open

也接受 GH_TOKEN 别名。env 优先级高于 UI 配的 token(运维设定优先)。

拿一个 PAT

GitHub 两种 PAT 都接受,patch 只看 Authorization: Bearer <token> 形式,跟前缀无关:

Classic PAT(ghp_ 开头,40 字符)

  1. 打开 https://github.com/settings/tokens
  2. Generate new token → Generate new token (classic)
  3. 选 expiration(90 天或不过期)
  4. 不需要勾选任何 scope——纯公共数据请求
  5. 复制 ghp_xxx...(共 40 字符)

Fine-grained PAT(github_pat_ 开头,约 90+ 字符)—新版 GitHub 默认推荐这种

  1. 打开 https://github.com/settings/personal-access-tokens
  2. Generate new token → Fine-grained, personal access token
  3. Token name 随便填;Expiration 选 90 天或不过期
  4. Resource owner:留默认(你自己)即可——这个 PAT 只用来读你自己的皮肤 / 插件仓库的公开元数据
  5. Permissions → Repository accessPublic Repositories (read-only) 就行。不要勾 "All repositories" 或任何 private 权限——用不到
  6. 生成后复制 github_pat_11XXX_xxx...(约 90+ 字符)

哪种都行。classic 创建快、scope 全空;fine-grained 权限最小化、token 更长更显眼、GitHub 现在主推这种。两者都不需要任何勾选就能解 GitHub API 60次/小时的匿名限流

工作原理

  1. 早期 patch:插件 factory 在 DSH 客户端模块表中第一个物化(依赖 bundles 顺序),立即用 Symbol.for("dsh-github-token-injector.patched") 标记位对 window.fetchXMLHttpRequest 进行 monkey patch
  2. 目标过滤:通过 URL 解析只对 api.github.comraw.githubusercontent.com 起作用,其他域名的 fetch 完全不改动
  3. Header 注入:每次目标请求把 token 写进 Authorization: Bearer xxx,若调用方已自带 Authorization 头则尊重调用方
  4. 响应监控:在 fetch().then() 与 XHR readystatechange=4 里检查 status,401 → invalid,403 + X-RateLimit-Remaining === 0rate-limited
  5. 状态广播:通过 dispatchEvent(new CustomEvent("dsh-github-token-injector:status", { detail })) 让 UI 与其他插件订阅
  6. HMR 安全:cordis ctx.effect() 注册副作用,dispose 时还原原始 window.fetch 引用,不污染全局
  7. Host 端 patchsrc/index.ts 在 DSH 主进程(Node.js)层面同时 patch globalThis.fetch,对发往 api.github.com / raw.githubusercontent.com 的服务端请求(如 skin-manager 的 /api/dsh/skins、插件市场的 update 检查)注入 Authorization,解决共享代理 IP 上 server-side fetches 同样被限流的问题
  8. Token 同步:浏览器侧的 setToken / clearToken 通过 POST /dsh-github-token-injector/api/token 把 token 推到 host 进程内的内存缓存;DSH 重启时 host 清空,浏览器侧的 localStorage 有现成 token 时会在 plugin 启动时主动同步一次

接口

window.__githubTokenInjector

方法用途
getToken()返回当前生效 token(trim 后)或 null
setToken(t)写入 localStorage.DSH_GITHUB_TOKENnull/空串 = 清除
getStatus()返回 { state, checkedAt, message }
clearToken()清掉 token + 重置状态
forcePrecheck()主动发起 /octocat 鉴权探针,返回 Promise<Response | null>

cordis service dsh-github-token-injector

其他插件 inject(['dsh-github-token-injector']) 后可拿到:

interface TokenProvider {
  getToken(): string | null
  getStatus(): { state: TokenStatus; checkedAt: number; message?: string }
  setToken(t: string | null): void
}

CustomEvent dsh-github-token-injector:status

window.addEventListener('dsh-github-token-injector:status', (ev) => {
  console.log(ev.detail) // { state, checkedAt, message }
})

状态机

状态触发条件UI 表现
ok任何 2xx/3xx 响应🟢 绿点 "有效"
invalid401 响应🔴 红点 "已失效"
forbidden403 响应(非限流)🟡 黄点 "无权限"
rate-limited403 + X-RateLimit-Remaining: 0🟡 黄点 "限流"
no-token未配置 token⚪ 灰点 "未配置"
unknown网络错误 / 启动后未发过请求⚪ 灰点 "未知"

安全与隐私

  • Token 存在浏览器 localStorage,不写入 DSH 服务端文件、不上传网络
  • Patch 只对 api.github.com / raw.githubusercontent.com 域名生效,其他请求零改动
  • 卸载插件 / 清浏览器数据会一并删除 token

发布

参见 PUBLISH.md:tag push 触发 GitHub Actions,自动 pack → GitHub Release → 等 CI green → publish 到 npm。

开发

npm install
npm run build       # tsc → dist/index.js + copy src/client.js → dist/client.js
npm test            # vitest

HMR 调试:在 web profile 跑 pnpm run dev:web 同时开新终端跑本插件的 npm run dev, 修改 src/client.js 后浏览器自动 reload。

本地未推送时也可以按路径装:

npx @deepseek-ai/dsh plugin --profile web add /path/to/dsh-github-token-injector