dsh-plugin-login-gate
No description
- Stars
- 1
- Language
- JavaScript
- Created
- Aug 19, 2026
- Updated
- Aug 23, 2026
Introduction
dsh-plugin-login-gate
为 DeepSeek Harness (dsh) Web UI 增加密码登录闸门 + HTTPS 反向代理的 Cordis 插件。
适用场景:dsh Web UI 默认无登录页(仅回环地址访问)。当你需要把 dsh 暴露给局域网 / 内网其他设备时,本插件在 dsh 前置一道登录,未授权设备无法使用 dsh。
特性
- 密码登录:单密码即可(单用户场景),密码文件明文存储、修改即时生效
- HTTPS 自签:自签证书加密传输,首次访问点一次「继续前往」即可(与常见 NAS 体验一致)
- http → https 自动跳转:直接输
IP:端口也能打开 - 会话安全:httpOnly Cookie、浏览器会话级(关浏览器即失效)
- SSE / WebSocket 转发:dsh 的流式输出与实时能力不受影响
- 同端口双协议:一个端口同时处理 HTTP 跳转与 HTTPS
- 零 npm 运行时依赖(仅 peer 依赖
@deepseek-ai/cordis)
安装
1. 获取插件
# 方式 A:Git 克隆
git clone https://github.com/<你的用户名>/dsh-plugin-login-gate.git
# 方式 B:手动下载本仓库 zip 并解压
将插件目录放入 dsh 可访问的位置(如 dsh 安装目录、或任意本地目录)。
2. 注册到 profile
编辑 dsh profile 的 cordis.patch.yml(例如 ~/.dsh/profiles/web/cordis.patch.yml),
或全局用户层 ~/.dsh/cordis.patch.yml,追加:
- insert:
- id: login-gate
name: 'dsh-plugin-login-gate'
config:
port: 3081
passwordFile: 'C:/dsh/login-gate/password.txt'
certFile: 'C:/dsh/login-gate/cert.pem'
keyFile: 'C:/dsh/login-gate/key.pem'
assetsDir: 'C:/dsh/login-gate/assets'
若
dsh-plugin-login-gate未安装到 dsh 能解析的node_modules,可将name指向插件目录的绝对路径(如name: 'C:/dsh/dsh-plugin-login-gate')。
3. 生成证书(一次性)
用本机 openssl 生成自签证书(有效期 10 年,把 <你的局域网IP> 换成实际值):
openssl req -x509 -newkey rsa:2048 \
-keyout key.pem -out cert.pem -days 3650 -nodes \
-subj "/CN=DeepSeek-Harness-Login" \
-addext "subjectAltName=IP:127.0.0.1,DNS:localhost,IP:<你的局域网IP>"
4. 设置密码
创建密码文件,内容为你的登录密码(明文,改完即时生效):
echo '你的密码' > C:/dsh/login-gate/password.txt
5. (可选)自定义素材
插件包内已内置默认素材——assets/logo.svg(dsh 官方鲸鱼图标)和
assets/bg.jpg(晨雾山景背景图),开箱即有完整美观度。
如需替换:在 cordis.patch.yml 的插件行 config 中设置 assetsDir
指向你的自定义目录(直接放 logo.svg / bg.jpg,无需 assets/
子目录,文件名匹配即可)。示例:
config:
assetsDir: 'C:/dsh/login-gate-custom' # 内含 logo.svg、bg.jpg 即可
替换优先级:自定义目录 > 包内默认。
6. 重启 dsh
重启 dsh Web UI 后,插件随 dsh 启动。浏览器访问:
http://<你的局域网IP>:<port> → 自动跳转 https
https://<你的局域网IP>:<port> → 登录页
首次访问自签证书浏览器会提示「连接不是私密连接」,点「高级 → 继续前往」即可, 之后该地址不再提示(每台设备首次各点一次)。
安装常见问题
node-pty 构建脚本被 pnpm 默认拦截(build scripts are blocked)
安装依赖 node-pty(dsh 终端能力)的插件时,pnpm v10+ 默认不执行 build scripts,
安装会报「构建脚本被 pnpm 默认拦截(node-pty)」。在 dsh profile 目录下
(如 ~/.dsh/profiles/web/)的 pnpm-workspace.yaml 里放行即可:
allowBuilds:
node-pty: true
之后重新运行安装(或点击插件商店的「Allow build scripts and retry」)即可通过。
其它原生依赖被拦时同理,把包名加进 allowBuilds。
配置项
| 键 | 必填 | 默认 | 说明 |
|---|---|---|---|
host | 否 | 0.0.0.0 | 监听地址 |
port | 否 | 3081 | 监听端口(登录闸门入口) |
targetHost | 否 | 127.0.0.1 | 转发目标(dsh 所在地址) |
targetPort | 否 | 3080 | 转发目标端口(dsh Web UI 端口) |
passwordFile | 是 | - | 密码文件路径(明文) |
certFile | 是 | - | TLS 证书 PEM 路径 |
keyFile | 是 | - | TLS 私钥 PEM 路径 |
assetsDir | 否 | 包内 assets/ | 登录页素材目录(bg.jpg / logo.svg) |
maxSessions | 否 | 64 | 最大并发登录会话数(多端场景) |
配置缺失或文件不存在时,插件仅记录警告并跳过启动,不影响 dsh 本体。
本插件与 dsh 自身
webserver(默认127.0.0.1:3080)是两回事:插件作为 对外入口(如3081),dsh 本体保持仅本机可访问。建议 dsh 的webserver.host保持127.0.0.1,不要暴露到局域网,由本插件统一对外。
安全说明
- 密码明文存储于你指定的本地文件,请确保该文件仅你可读写(单用户个人工具设计)。
- 使用自签证书时,密码在传输中加密;但自签 CA 不被浏览器信任,请勿将该入口暴露到 公网。仅限受信任的局域网/内网(VPN)环境使用。
- 会话为内存存储:dsh 重启后所有设备需重新登录。
局域网跨设备访问(LAN)修复说明
把 dsh 暴露给局域网 / 内网其他设备时,会出现两类与「跨设备访问」直接相关的 BUG。 本插件对两类都做了处理:服务端在代理层修,浏览器侧在启动时自动打补丁。
BUG 1:模型配置页报 HTTP 403(transport failure for /api/settings.describe)
- 根因:dsh 对
settings.describe等特权接口按请求头Host/Origin做信任判定,只接受回环(loopback)或--trusted-host指定的 authority。 反向代理把请求转发到127.0.0.1:3080时,若Host/Origin仍带着局域网 地址(如192.168.x.x:3081),就会被信任围栏拒绝,返回 403。 注意--trusted-host只覆盖「trusted-host 类」接口,无法覆盖「loopback 类」 接口,所以光加 trusted-host 不够。 - 修复(本插件已在代理层处理):见
lib/index.js的rewriteLoopbackAuthority(), 在把请求(含 WebSocket 升级)转发给 dsh 之前,把Host/Origin重写为目标 回环地址(127.0.0.1:3080)。你无需手动处理。
BUG 2:设置 / 模型配置页报 settings are unavailable in this browser
-
根因:这是纯前端判定,与上面的 403 是两回事。浏览器端
dsh-client-connection的isLoopbackHostname()只认localhost/127.x;connection.isLoopback由页面location.hostname算出。经局域网 IP 访问时isLoopback=false→ 设置镜像persistence="memory"→ 永不发起settings.describe→ 抛该错。 -
修复(本插件在启动时自动打浏览器侧补丁):
dsh-client-connection/lib/client.js的isLoopbackHostname()额外放行 私有网段(10/8、172.16/12、192.168/16、169.254/16)—— 即把局域网 IP 视为回环,使设置镜像改用host持久化、正常加载。dsh-client-ui-settings/lib/client.js把connection.isLoopback ? "host" : "memory"强制为"host"(双保险)。
-
补丁是侵入式的,改在 dsh 自家
node_modules内部文件里:⚠️ dsh 一旦更新 / 重装,这些补丁会失效,设置页会再次报 BUG 2。 因此本插件在
apply()启动时(最佳努力、幂等)自动重打; 若自动探测未命中,或你想手动确认,在 dsh 更新后执行一次即可:# 自动探测 dsh 安装目录(从 cwd / 插件位置向上回溯) node node_modules/dsh-plugin-login-gate/patch-dsh-lan.js # 或显式指定 dsh 根目录(最稳妥) node node_modules/dsh-plugin-login-gate/patch-dsh-lan.js C:/AI/deepseek-dsh # 等价写法: # DSH_ROOT=C:/AI/deepseek-dsh node node_modules/dsh-plugin-login-gate/patch-dsh-lan.js脚本特性:幂等(已打过则跳过)、不写死任何 IP / 密码、匹配不到模式就不动文件、 打前自动留
.lanpatch.bak备份。
BUG 3:跨设备会话列表 / 实时事件流为空(WebSocket 握手失败)
- 根因:作为反向代理转发 WebSocket 升级时,
Upgrade/Connection属 hop-by-hop 头被剥掉且未补回,而 RFC 6455 要求 101 响应必须携带这两个头 → 浏览器端握手校验 失败(控制台报WebSocket is closed before the connection is established), dsh 事件流(/api/events.mux//api/events.host,承载会话列表等实时数据)跨设备 无法建立 → 工作区对话任务 / 会话历史只在本机显示。 - 修复:转发 101 响应前补回
Upgrade: websocket与Connection: Upgrade。 - 关联:旧版网关给转发请求设了 30s idle 超时,会误杀空闲的长连接
(如
/plugins/events热重载 SSE,客户端报ERR_INCOMPLETE_CHUNKED_ENCODING), 现已移除;普通 API 请求由客户端超时兜底。
验证(每次更新 dsh 后建议跑一遍)
# 1) 局域网设备登录后应能打开设置页,不再报 403 / unavailable
# 2) 用 node 直连验证 settings.describe 返回 200:
node -e "const https=require('https');https.get('https://127.0.0.1:3080/api/settings.describe',{rejectUnauthorized:false},r=>{console.log('status',r.statusCode);r.destroy();}).on('error',e=>console.log('err',e.message))"
# 3) 浏览器硬刷新(Ctrl+F5)以加载打了补丁的新 client 模块
完整排查 / 快速修复手册见仓库同级的
dsh-局域网跨设备访问修复手册.md(本地留存文档,不含任何本机 IP / 密码)。
已知限制
- 单密码、无多用户体系(个人工具定位)。
- 无登录失败锁定(如需防暴力破解,可自行在反向代理前加防火墙/限流)。
- 自签证书 10 年有效期,到期需重新生成并更新配置。
Changelog
- v0.2.0 — 修复跨设备访问的两类问题:WebSocket 101 响应补回
Upgrade/Connection头(BUG 3,事件流 / 会话列表跨设备可见);移除转发请求 30s idle 超时(避免误杀/plugins/events等长连接)。新增pnpm allowBuilds放行 node-pty 的安装说明。 - v0.1.0 — 初始版本:密码登录闸门 + HTTPS 自签反向代理、http→https 跳转、SSE / WebSocket 转发、浏览器侧 LAN 补丁(修复设置页 403 /
settings are unavailable)。
License
MIT