🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

登录网关 ButterHost69/dsh-login-gateway

DeepSeek 客户端
ButterHost6928 天前有提交已提供中文文档扫描:未发现敏感能力兼容 / 相关生态

为 Web 界面加上账号密码与动态验证码登录

30/100
综合分
0
GitHub 星标
—
npm 周下载
—/5
用户评分

数据截至 2026/10/7 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

相关生态插件(非 dsh 原生,按其对应运行时安装)
git clone https://github.com/ButterHost69/dsh-login-gateway.git

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:仅索引
是什么
生态应用
桌面端 / Web 外壳,不以 dsh plugin add 安装
装得上吗
该类项目属生态应用(桌面端 / Web 外壳),不以 dsh plugin add 方式安装,请按仓库说明部署
L4 · 真实安装等级说明 →
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 28 天前
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →
⚠︎ 实装验证未通过(unknown · 2026/11/4) ——可能是验证环境差异,装前建议到 GitHub 仓库确认最近更新与 issue。
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码
v2.7.0
🟢 扫描:未发现敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描未发现敏感能力:最多只发网络请求、读取自身元数据或只读文件,未发现执行命令、文件写入或敏感信息读取。

扫描于 2026/11/3(0 天前) · 范围 全包扫描(包内未声明入口) · 来源 GitHub 仓库

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

依赖的 DSH / Cordis 模块
@deepseek-ai/schemastery@deepseek-ai/cordis
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

功能亮点

  • 用户名密码登录
  • TOTP动态验证码
  • 公网部署防护

README

由 DeepSeek 最新模型翻译生成
dsh-login-gateway 一个 DeepSeek Harness(dsh)插件,在 Web UI 前面加上 用户名 + 密码 + TOTP 登录,这样隧道或反向代理就能对外暴露 harness,而不会暴露一个没有认证的 API。 flowchart LR B[Browser] -->|HTTPS| T[Tunnel / reverse proxy] T -->|HTTP, Host preserved| G[dsh-login-gateway] G -->|session cookie?| L{/login} L -->|password + TOTP| S[signed session cookie] G -->|authenticated| H[dsh web] H -->|launch token exchange| G 为什么需要它 dsh web 通过明文 HTTP 在回环端口上提供 GUI,并用进程启动 token 认证浏览器——token 放在打印出来的 URL 里,再换成签名 cookie。那个 URL 就是一张通行证:谁拿到它,谁就拿到了 harness。在自己机器上这没问题,可一旦端口能从公网访问,就很尴尬。 这个插件加了一层真正的登录——那种你能直接交给别人、或者存进密码管理器的登录——而且不用改动 harness。
展开完整文档(README 剩余 1 节)
dsh-login-gateway

一个 DeepSeek Harness(dsh)插件,在 Web UI 前面加上 用户名 + 密码 + TOTP 登录,这样隧道或反向代理就能对外暴露 harness,而不会暴露一个没有认证的 API。

flowchart LR
B[Browser] -->|HTTPS| T[Tunnel / reverse proxy]
T -->|HTTP, Host preserved| G[dsh-login-gateway]
G -->|session cookie?| L{/login}
L -->|password + TOTP| S[signed session cookie]
G -->|authenticated| H[dsh web]
H -->|launch token exchange| G

为什么需要它

dsh web 通过明文 HTTP 在回环端口上提供 GUI,并用进程启动 token 认证浏览器——token 放在打印出来的 URL 里,再换成签名 cookie。那个 URL 就是一张通行证:谁拿到它,谁就拿到了 harness。在自己机器上这没问题,可一旦端口能从公网访问,就很尴尬。

这个插件加了一层真正的登录——那种你能直接交给别人、或者存进密码管理器的登录——而且不用改动 harness。它监听自己的端口,校验凭据和任意认证器应用生成的一次性验证码,然后把通过认证的流量(包括 WebSocket 流复用)转发给 harness。

它做什么

- 监听自己的主机和端口,提供 /login、/logout 和 /_dsh-login-gateway/health。
- 校验用户名、scrypt 哈希后的密码和 TOTP 验证码,然后签发自己的 HMAC 签名会话 cookie。
- 把其他所有请求和 WebSocket 升级转发给正在运行的 harness,并保留面向浏览器的 Host。
- 在服务端完成 harness 自己的启动 token → cookie 交换,所以启动 token 和 harness 的 cookie 都不会到达浏览器。
- 没有配置时,索要第一个用户名和密码,生成 TOTP 密钥,把账号存成凭据记录。
- 按客户端地址和用户名限制失败登录。

要求

- dsh 0.2.1-alpha.1(已验证)或兼容版本。
- Node.js ^22.19 || >=24。
- 一个 Web 配置档(dsh web),它会挂载首次运行设置写入的凭据存储。

安装

从 GitHub 安装(git 安装会在安装过程中构建包):

dsh plugin --profile web add -w github:ButterHost69/dsh-login-gateway

pnpm ≥ 10 在获得允许之前,会拒绝运行 git 依赖的 prepare 脚本。如果第一次 add 失败,把 pnpm 打印出来的确切包键复制到配置档的 pnpm-workspace.yaml 里的 allowBuilds:

allowBuilds:
dsh-login-gateway: true

然后重新运行 add。把这条允许当成授权:允许这个包在你的机器上运行构建。

从本地检出安装:

dsh plugin --profile web add -w /absolute/path/to/dsh-login-gateway
安装时会选中 bundle,插入插件行。该行一开始没有任何用户,所以插件会进入首次运行设置:它提供一个表单,要求填写第一个用户名和密码,生成 TOTP 密钥,并把账号存进 harness 凭据存储。

dsh-login-gateway: set up at http://127.0.0.1:8080/login (forwarding to http://127.0.0.1:3080)
dsh-login-gateway: no account exists yet; open that URL on this machine, or use http://127.0.0.1:8080/login?setup=… once to set one up through a tunnel

首次运行

打开打印出来的 URL。在运行 harness 的机器上,http://127.0.0.1:8080/login 就够了。走隧道的话,打开一次 ?setup=… URL:token 按进程生成,只有它能允许非 loopback 的对端创建第一个账号。

设置表单要求填写用户名、密码和密码确认:

- 用户名会成为凭据记录的 id,所以必须是 2–32 个字符,只能用小写字母、数字和连字符,且以字母开头。
- 密码至少 12 个字符。

提交后会创建账号,并只显示一次注册页面:一个 base32 密钥和一个 otpauth:// URI。把它添加到 Google Authenticator、1Password、Aegis 或任何其他 TOTP 应用,然后用验证码登录以确认注册。密钥不会再显示——服务器会保留它来验证验证码,但之后没有任何页面能再把它显示出来。

在账号存在之前,其他所有路径都返回 503,也无法通过网关访问 harness。只有第一个账号能这样创建;后续账号请按下文用声明式方式添加。

在配置档中配置账号

要做可复现的部署,或在第一个账号之后添加账号,就在配置里声明用户。脚本会用 scrypt 对密码做哈希,并生成新的 base32 TOTP 密钥:

cd /path/to/dsh-login-gateway
npm install
npm run build
node scripts/enroll.mjs --username alice

它会打印一段可直接粘贴的配置块和一个 otpauth:// URI。把配置块粘贴到 $DSH_HOME/profiles/web/cordis.patch.yml:

- id: login-gateway
config:
listenHost: '127.0.0.1'
listenPort: 8080
users:
- username: alice
passwordHash: 'scrypt$16384$8$1$…$…'
totpSecret: 'NOVJ3ZLTORZGK6LQ…'

配置的用户总是优先于同名的已存储记录。把 otpauth:// URI 添加到你的验证器应用,然后重启 dsh web(或让 HMR 重新加载配置档)。启动输出会给出登录 URL:

dsh-login-gateway: sign in at http://127.0.0.1:8080/login (forwarding to http://127.0.0.1:3080)

对外暴露

把隧道或反向代理指向网关端口,而不是 harness 端口。让 harness 保持在 loopback 上。

如果公网 authority 不是 loopback,就用 --trusted-host 启动 dsh,让 harness 自己的 Host 防护放行转发过来的 Host:

dsh web --trusted-host harness.example.com

代理必须:
- 保留面向浏览器的 Host。 网关原样转发,harness 的防护栏拿它和已接受的 authority 比对。
- 转发 WebSocket 升级(Upgrade 和 Connection 头保持原样),这样 harness 的流多路复用才能工作。
- 在外侧链路上设置 X-Forwarded-Proto: https。 网关看到 https 就会把会话 cookie 标为 Secure,并把该头透传给 harness。
- 设置 X-Forwarded-For(Cloudflare Tunnel 和 Caddy 默认就会做),并设置 trustProxy: true。不设的话,每个请求看起来都来自代理,一个攻击者的失败尝试就会限流所有人。
- 终止 TLS。 网关只讲明文 HTTP,和 harness 完全一样。

重写 Host 的隧道会弄坏 harness API,不只是这个网关。 网关能容忍——它检查浏览器的 Fetch Metadata,所以自己的设置页和登录页两种情况都能用——但 dsh 的 /api 防护栏会拿浏览器的 Origin 和收到的 Host 比对。如果隧道转发的是 Host: 127.0.0.1:8080,每次 API 调用都会拿到 403。对于 Cloudflare 面板托管的隧道,编辑公开主机名,打开 Additional application settings → HTTP Settings,把 HTTP Host Header 设为该主机名;然后启动 dsh web --trusted-host <hostname>,因为 authority 不再是回环地址。Caddy 和大多数配置文件式代理本来就会保留 Host。

对于 Cloudflare Tunnel,源站服务就是 http://127.0.0.1:8080。如果前端是 Caddy:

harness.example.com {
reverse_proxy 127.0.0.1:8080
}

配置参考

每个字段都可选,每个值都有默认值:

| 字段 | 默认值 | 含义 |
| listenHost | '127.0.0.1' | 网关的绑定主机。'0.0.0.0' 会把明文 HTTP 链路暴露到网络;优先用回环加隧道。 |
| listenPort | 8080 | 网关端口。0 让操作系统分配空闲端口。 |
| upstreamHost | '127.0.0.1' | harness web 服务器的主机。 |
| upstreamPort | 正在运行的 web 服务器端口 | 只有当 harness 监听的位置插件读不到时才覆盖。 |
| loginPath | '/login' | 登录表单路径;还没有账号时也是设置表单路径。 |
| logoutPath | '/logout' | 退出路径。 |
| users | [] | 声明的账号,每个为 { username, passwordHash, totpSecret }。空列表表示首次运行设置。 |
| branding.issuer | 'DeepSeek Harness' | 登录页上的产品名。 |
| totp.digits | 6 | 验证码长度(6 或 8)。 |
| totp.periodSeconds | 30 | 每个时间步的秒数。 |
| totp.algorithm | 'sha1' | 'sha1'、'sha256' 或 'sha512'。 |
| totp.windowSteps | 1 | 当前步前后各接受几步。 |
| session.maxAgeSeconds | 43200(12 小时) | 会话有效期。 |
| session.cookieName | 'dsh_login_session' | 会话 cookie 名称。 |
| session.secure | 'auto' | 'auto' 在 HTTPS 下把 cookie 标为 Secure;'always' 或 'never' 强制指定。 |
| rateLimit.maxFailures | 5 | 窗口内触发锁定的失败次数。 |
| rateLimit.windowSeconds | 300 | 滑动窗口长度。 |
| rateLimit.lockoutSeconds | 300 | 锁定时长。 |
| trustProxy | false | 限流时,把 X-Forwarded-For 的第一跳当作客户端地址。 |

安全说明

- 密码以 scrypt 哈希存储(N=16384, r=8, p=1,16 字节盐,32 字节密钥),比较时使用恒定时间。注册脚本和设置表单都不保留明文。
- TOTP 遵循 RFC 6238,采用验证器应用的默认参数,窗口为 ±1 步,比较时不提前退出。
- 首次运行设置仅限本地。 只有回环对端,或持有启动时打印的进程级设置 token 的对端,才能读取设置表单或创建第一个账户。在账户存在之前,其他所有请求一律以 503 拒绝,因此暴露的端口不会有一刻是敞开的。token 会换成短期 cookie,这样它不会一直留在地址栏里。
- 会话是进程内存中的随机 256 位 id,由 HMAC-SHA256 cookie 携带(HttpOnly、SameSite=Lax、Path=/、HTTPS 下为 Secure)。重启会让所有人退出登录,也没有持久化会话存储可供窃取。SameSite=Lax 让共享链接从其他站点打开时仍能工作;退出登录要求同源请求,因此其他页面无法结束会话。
- 暴力破解按客户端地址和提交的用户名分别限流。未知用户名同样会消耗一次密码派生,因此响应速度不会比密码错误更快。
- 登录和设置的 POST 不得跨站。浏览器的 Sec-Fetch-Site 是权威依据,脚本无法设置它;没有 Fetch Metadata 时,会把 Origin 与 Host 以及代理提供的 X-Forwarded-Host 比较。两个页面都在 default-src 'none' 下发布,没有脚本或第三方资源。
- 丢失最后一个账户会让网关回到设置状态,而不是把所有人锁在外面:当配置和凭据存储中都没有用户时,登录表单会重新变成设置表单。
- harness 凭据留在服务端。 插件在自己的进程内用启动 token 换取 harness cookie,并把该 cookie 附加到转发的请求上;浏览器始终只持有网关的会话 cookie。浏览器提供的 dsh-auth-* cookie 会被剥离。
- 不是开放代理。 网关只转发到配置的上游。

它有意不做的事:

- TLS。 在隧道或反向代理处终止。
- 多用户授权。 每个通过认证的浏览器都代表 harness 的单一操作者 Peer 说话,所以这是单操作者闸门,不是多租户闸门。
- 设置之后的账户管理。 浏览器中只能创建第一个账户;之后的账户在配置中声明。没有密码重置、审计日志或恢复码——丢失验证器就意味着要生成新密钥。
- 保护 harness 端口本身。 如果 dsh web 也绑定到公网接口,那条路径不受影响。让它留在回环地址上,只暴露网关。

限制

- 只支持一个上游,且不做路径重写。harness 提供的是根路径路由;如果你的代理挂载了前缀,请在 dsh 上配置 --public-url,并在代理处剥离前缀——网关转发路径时原样不动。
- 会话和限流存在内存里,重启即丢失;账号不会,因为初始化会把它们写入凭据存储。
- 登录、初始化和注册页面只有英文。

工作原理

| 文件 | 职责 |
| src/index.ts | Cordis 插件:读取 harness 端口,构建用户目录和上游 cookie 服务商,随 fiber 启动和停止网关。 |
| src/gateway.ts | 网关模块:路由、首次运行初始化、登录、登出、限流、会话处理和转发。 |
| src/proxy.ts | HTTP/1.1 和 WebSocket 反向代理:逐跳过滤、流式请求体、升级隧道。 |
| src/upstream-auth.ts | 通过 ctx.connection.authenticatedUrl,按浏览器 authority 生成并缓存 harness 的 cookie。 |
| src/user-store.ts | 合并配置的用户与凭据记录,并写入首次运行初始化创建的账号。 |
| src/session.ts | 内存会话和签名 cookie 值。 |
| src/password.ts | scrypt 哈希、解析和常量时间校验。 |
| src/totp.ts、src/base32.ts | RFC 6238 TOTP 和 RFC 4648 base32。 |
| src/rate-limit.ts | 滑动窗口失败限流。 |
| src/login-page.ts | 服务端渲染的 HTML,内联 CSS。 |
| src/config.ts | 配置 schema 和加载时校验。 |
| src/types.ts | 本插件消费的窄 Host 服务契约。 |

开发

pnpm install
pnpm run build # tsc declarations + tsdown bundle
pnpm test # vitest: crypto units and a real-socket integration suite
pnpm run typecheck

集成测试套件会启动一个替身 harness(token 交换、已认证路由和 WebSocket 升级),并通过真实 socket 驱动网关:未认证重定向、首次运行初始化和注册、完整登录流程、cookie 剥离、流式响应、502 处理、限流和升级隧道。

许可证

MIT
预览分享卡片长什么样 ↓ButterHost69/dsh-login-gateway
分享 · DeepSeek Harness Hub
ButterHost69/dsh-login-gateway

为 Web 界面加上账号密码与动态验证码登录

这是你的仓库?认领条目

回到顶部