dsh-remote-access-proxy 0.0.0-stage → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 dsh-remote-access-proxy contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,162 @@
1
- # Temporary Holding Version
1
+ # dsh-remote-access-proxy
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ [English](README.md) · [简体中文](README.zh-CN.md)
4
+
5
+ [![Release](https://img.shields.io/github/v/tag/citydirector/dsh-remote-access-proxy?sort=semver&label=release)](https://github.com/citydirector/dsh-remote-access-proxy/releases) [![License: MIT](https://img.shields.io/badge/license-MIT-green)](LICENSE) [![DSH plugin](https://img.shields.io/badge/DSH%20plugin-%E2%89%A50.2.2--alpha.2-blue)](https://github.com/topics/dsh-plugin)
6
+
7
+ Use DSH (DeepSeek Harness) from your phone, tablet, or another computer's browser.
8
+
9
+ The plugin runs a small reverse proxy inside DSH. A remote device opens one address with a random path and gets the full Web GUI, without ever needing the launch token DSH changes on every start. Anything can sit in front: a LAN IP, easytier, ZeroTier, Tailscale, nginx, Caddy, Cloudflare Tunnel.
10
+
11
+ Requires **DSH 0.2.2-alpha.2 or newer 0.2.x**.
12
+
13
+ ## npm installation and updates
14
+
15
+ Requires DSH 0.2.2-alpha.2 or a newer 0.2.x and Node.js 24.9+. Enter `dsh-remote-access-proxy` in **Plugins → Add plugin**, or run:
16
+
17
+ ```sh
18
+ dsh plugin --profile web add dsh-remote-access-proxy
19
+ ```
20
+
21
+ For an existing GitHub installation, back up the profile's `cordis.patch.yml`, remove the old package in Plugins, and add the npm package above in the same profile. Keep the configuration row IDs and verify the saved settings after reinstalling. Subsequent updates use DSH's version list and update operation. The plugin no longer polls GitHub or provides its own install/rollback buttons; an old `updateCheck` setting has no effect.
22
+
23
+ ## Quick start
24
+
25
+ 1. **Install**: sidebar **Plugins** → Add plugin, and give it
26
+ ```
27
+ dsh-remote-access-proxy
28
+ ```
29
+ Switch it on.
30
+ 2. **Get the address**: open **Remote Access Proxy** in the plugin list, then the **Remote Access Proxy** component under it. The top of the page shows whether it is running and the **entry addresses**. Click **Copy**.
31
+ 3. **Open it remotely**: on a device on the same network, open the address in a browser, e.g. `http://192.168.1.20:13337/k3x9q2m7p1zt/`. Bookmark it or add it to the home screen.
32
+
33
+ Nothing needs configuring: port 13337 on every interface, with the random path generated and saved on first start. Add a password or limit who may connect whenever you like.
34
+
35
+ > **Set your API key on this machine first.** Some DSH settings can only be changed from a page on the host (DSH's own rule, not this plugin's; on 0.2.0 remote pages cannot change settings at all), so set the API key in DSH on the host. Remote pages can create sessions, chat, and pick workspaces normally.
36
+
37
+ From the command line:
38
+
39
+ ```bash
40
+ dsh plugin --profile web add dsh-remote-access-proxy
41
+ ```
42
+
43
+ ## The configuration page
44
+
45
+ ![Configuration page](docs/config-page.en.png)
46
+
47
+ - **Status**: running, off, or not running — and when it failed, why and what to do ("Port 13337 is already in use", "The certificate could not be loaded"), instead of a line buried in a log.
48
+ - **Entry addresses**: one per network interface, each with a copy button.
49
+ - **Allowed client addresses**: which devices may connect — IPs, CIDR blocks or ranges, e.g. `192.168.1.0/24, 100.64.0.0/10`. **LAN and VPN only** fills in every private range in one click; empty means anyone. Connections from elsewhere are dropped before a byte is exchanged, and the page tells you the last address it turned away, so you can add your own device if you locked it out. This machine itself is always allowed.
50
+ - **Access password** (optional): the entry then shows a sign-in page. A signed-in device is remembered for 30 days; changing the password signs every device out. Five wrong tries lock that address for a few minutes. `<entry>/__rap/logout` signs a device out.
51
+ - **Regenerate the entry path**: after saving, the old address stops working — use it if the address may have leaked.
52
+ - On/off settings are switches. A save applies at once: the proxy restarts in place, DSH does not.
53
+
54
+ On DSH 0.2.0 the page appears on the host only; from 0.2.1 remote pages can open it too, but **one-click updates are offered on the host only**.
55
+
56
+ ## Do I need TLS?
57
+
58
+ No. DSH 0.2 works over plain http.
59
+
60
+ - **VPN / home LAN**: http is fine; the traffic is already on a private network.
61
+ - **Internet**: turn TLS on, or put the proxy behind an HTTPS reverse proxy (Caddy, nginx, Cloudflare Tunnel).
62
+
63
+ TLS needs a `.pfx` certificate. A self-signed one on Windows (PowerShell):
64
+
65
+ ```powershell
66
+ $cert = New-SelfSignedCertificate -DnsName "dsh.local" -CertStoreLocation Cert:\CurrentUser\My -NotAfter (Get-Date).AddYears(5)
67
+ Export-PfxCertificate -Cert $cert -FilePath .\data\certs\dsh-proxy.pfx -Password (ConvertTo-SecureString "your-passphrase" -AsPlainText -Force)
68
+ ```
69
+
70
+ On macOS / Linux (openssl):
71
+
72
+ ```bash
73
+ openssl req -x509 -newkey rsa:2048 -nodes -days 1825 -subj "/CN=dsh.local" -keyout key.pem -out cert.pem
74
+ openssl pkcs12 -export -inkey key.pem -in cert.pem -out dsh-proxy.pfx -passout pass:your-passphrase
75
+ ```
76
+
77
+ Then switch on "Enable TLS" in the page, fill in the path and passphrase, and save. Browsers ask you to accept the certificate once. With TLS the gate cookie also gets the `Secure` flag.
78
+
79
+ ## Troubleshooting
80
+
81
+ | The page says | Do this |
82
+ |---|---|
83
+ | Port … is already in use | Pick another port, or close what holds it. Two DSH apps sharing one `data` directory (portable + desktop) do this too — see below |
84
+ | These client addresses aren't valid | Write an IP (`10.0.0.5`), a CIDR block (`10.0.0.0/24`) or a range (`10.0.0.5-10.0.0.9`) |
85
+ | The certificate could not be loaded | Check the path (relative to DSH's working directory) and the passphrase |
86
+ | Can't read the proxy status | The plugin isn't running: check both the plugin's and the component's switches |
87
+
88
+ - **The remote device can't connect at all** (connection reset): its address isn't in the allow list. The page shows the address it turned away; add it, or click **LAN and VPN only**.
89
+ - **`forbidden` on the remote device**: the path is wrong. Open the full entry address again.
90
+ - **A plain-text `bad gateway`**: the proxy could not reach the upstream DSH. The status card's **Upstream** line shows the address it is using, and `access.log` records the reason (usually `ECONNREFUSED`). Leave `upstreamHost` / `upstreamPort` at empty / `0` so the address follows the running instance. Before 1.4.1 the desktop app was unusable this way: it starts its host with `--port 0`, the plugin read the *requested* `0` from `webStartup` instead of the port the OS bound on `webServer`, and fell back to 3080.
91
+ - **Two DSH apps sharing one `$DSH_HOME`** read the same profile and fight over one port. Switch "Enabled" off in one of them, or give each its own port.
92
+
93
+ ## Security
94
+
95
+ Access control is entirely the proxy's gate:
96
+
97
+ - **Allow list**: a client outside `allowFrom` is dropped at the TCP level (before TLS), like a firewall rule. Loopback is always allowed, so a local HTTPS reverse proxy keeps working;
98
+ - **Random path**: the entry is `<address>:<port>/<secretPath>/`, generated from the OS CSPRNG;
99
+ - **Password** (optional): without it the path alone opens the site; with it the entry shows a sign-in form, failed tries are slowed and rate-limited per address;
100
+ - **Remembered device**: entering (or signing in) sets `dsh_et_gate`, a signed value that expires after 30 days (`Path=/; Max-Age=2592000; HttpOnly; SameSite=Strict`, plus `Secure` with TLS). It is signed with a server secret over the path and the password, so changing either — or regenerating the path — revokes every device. Nobody ever edits it by hand.
101
+
102
+ The proxy forwards to DSH as loopback (Host rewritten to `127.0.0.1:<port>`, Origin stripped) and **performs the launch-token exchange itself, holding the `dsh-auth-*` cookie**, so remote users never see the per-start token. On an upstream 401 it drops that cookie and exchanges again.
103
+
104
+ The path is the key: treat the entry address like a password. The `access.log` startup line records it too.
105
+
106
+ ## Configuration
107
+
108
+ Every field is a `.volatile()` field of the plugin's Cordis `Config`, stored in the active profile's `cordis.patch.yml`. Edit them in the page, or by hand from [`config/cordis.patch.example.yml`](config/cordis.patch.example.yml).
109
+
110
+ | Field | Description |
111
+ |---|---|
112
+ | `enabled` | Stop listening when off |
113
+ | `listenPort` | Port (default `13337`); the proxy listens on every interface, IPv4 and IPv6 |
114
+ | `allowFrom` | Client addresses allowed to connect: IPs, CIDR blocks, `a-b` ranges, separated by commas or spaces. Empty = anyone; loopback always |
115
+ | `secretPath` | Gate path (4–32 letters, digits, `-`, `_`; generated when empty) |
116
+ | `password` | Optional access password (empty = none) |
117
+ | `cookieValue` | Server secret that signs remembered devices (generated; not shown on the page) |
118
+ | `upstreamHost` / `upstreamPort` | Upstream DSH. Empty / `0` follows the running instance: the bound port from its `webServer` service, then `webStartup` (3080 under `dsh web`; a desktop launch passes `--port 0`, so its real port exists only on `webServer`) |
119
+ | `tlsEnabled` / `tlsPfxPath` / `tlsPassphrase` | TLS (pfx certificate) |
120
+ | `logMaxBytes` / `logKeep` | `access.log` rotation: rotate past the cap (default 1 MiB), keep this many old files (default 3); `0` turns rotation / history off |
121
+
122
+ ## Updating
123
+
124
+ Use the DSH Plugins page to list npm versions and apply a compatible update. The plugin no longer checks GitHub or performs its own installation. See [PUBLISHING.md](PUBLISHING.md) for automatic publishing.
125
+
126
+ ## Upgrading from older versions
127
+
128
+ Follow the npm migration instructions above. Keep the same profile and row IDs; the proxy heals old absolute module paths at startup.
129
+
130
+ ## Development
131
+
132
+ ```
133
+ dsh-remote-access-proxy/
134
+ ├── package.json # bundle manifest + dsh.client; "." = proxy, "./client" = page
135
+ ├── cordis.patch.yml # the one row this bundle inserts (by package name)
136
+ ├── plugin/dsh-remote-access-proxy.mjs # host: gate + forwarding + status route
137
+ ├── client/index.js # browser: the configuration page
138
+ ├── config/cordis.patch.example.yml # hand-configuration template
139
+ ├── locale/{en,zh}.json # Plugins-page title and description
140
+ └── test-remote-access-proxy.mjs # end-to-end tests against a mock DSH
141
+ ```
142
+
143
+ ```bash
144
+ pnpm install
145
+ node test-remote-access-proxy.mjs # Expected: 78 passed, 0 failed
146
+ ```
147
+
148
+ The tests mock a DSH upstream (launch-token exchange + `dsh-auth` cookie gate) and the host contract the plugin relies on, and cover the gate, cookie injection, token stripping, 303 rewrite, 401 self-heal, WS upgrade, log rotation, secret generation and write-back, the status route, failure reasons (invalid path, busy port, bad allow-list entry), the password sign-in (deep links, lockout, logout, revocation), the allow list (drop, loopback, reporting), the 1.1 → 1.2 migration, upstream auto-detect, closing every connection on a hot swap and rebinding the port at once, and the package layout.
149
+
150
+ ### Release convention
151
+
152
+ Bump package.json and package-lock.json together and push main. GitHub Actions tests and publishes the new npm version automatically. Version tags and manual dispatch are also supported. See [PUBLISHING.md](PUBLISHING.md) for the one-time Trusted Publisher setup.
153
+
154
+ ## Related projects
155
+
156
+ - [deepinfra-fusion-proxy](https://github.com/citydirector/deepinfra-fusion-proxy): DeepInfra Standard / Flex switching with automatic fallback, per session
157
+ - [dsh-loop-rescue](https://github.com/citydirector/dsh-loop-rescue): Cut model repetition loops mid-stream, prune them from the log, and resume
158
+ - [dsh-session-manager](https://github.com/citydirector/dsh-session-manager): Offline session manager: upgrade, archive, trash, loop cleanup, broken-tail repair
159
+
160
+ ## License
161
+
162
+ [MIT](LICENSE)
@@ -0,0 +1,164 @@
1
+ # dsh-remote-access-proxy
2
+
3
+ [English](README.md) · [简体中文](README.zh-CN.md)
4
+
5
+ [![Release](https://img.shields.io/github/v/tag/citydirector/dsh-remote-access-proxy?sort=semver&label=release)](https://github.com/citydirector/dsh-remote-access-proxy/releases) [![License: MIT](https://img.shields.io/badge/license-MIT-green)](LICENSE) [![DSH plugin](https://img.shields.io/badge/DSH%20plugin-%E2%89%A50.2.2--alpha.2-blue)](https://github.com/topics/dsh-plugin)
6
+
7
+ 在手机、平板或另一台电脑上用浏览器使用 DSH(DeepSeek Harness)。
8
+
9
+ 插件在 DSH 里起一个小型反向代理:远程设备只要打开一个带随机路径的地址,就能用完整的 Web GUI,不用知道 DSH 每次启动都会变的 launch token。前面接什么都行:局域网 IP、easytier、ZeroTier、Tailscale、nginx、Caddy、Cloudflare Tunnel。
10
+
11
+ 需要 **DSH 0.1.7-rc.1 或更新**(已在 0.2.0-rc.2 和 0.2.1-alpha.3 上实测)。
12
+
13
+ ## npm 安装与更新
14
+
15
+ 需要 DSH 0.2.2-alpha.2 或更新的 0.2.x,以及 Node.js 24.9+。在 DSH「插件 → 添加插件」输入 `dsh-remote-access-proxy`,或运行:
16
+
17
+ ```sh
18
+ dsh plugin --profile web add dsh-remote-access-proxy
19
+ ```
20
+
21
+ 旧版从 GitHub 安装的用户:先备份 profile 的 `cordis.patch.yml`,在插件页移除旧包并用上述 npm 包名重新添加,保持原 profile 与配置行 ID。配置仍由 profile 保存;重新添加后检查已保存的值。此后统一使用 DSH 插件页的版本列表与更新功能。插件不再轮询 GitHub、不再提供独立安装或回退按钮,旧 `updateCheck` 设置不再生效。
22
+
23
+ ## 快速开始
24
+
25
+ 1. **安装**:侧边栏 **插件** → 添加插件,填入
26
+ ```
27
+ dsh-remote-access-proxy
28
+ ```
29
+ 装完打开开关。
30
+ 2. **拿地址**:在插件列表打开 **远程访问代理**,再点它下面的 **远程访问代理** 组件。页面顶部显示运行状态和**入口地址**,点 **复制**。
31
+ 3. **在远程设备上打开**:在同一网络的设备上用浏览器打开这个地址,例如 `http://192.168.1.20:13337/k3x9q2m7p1zt/`。存成书签或添加到主屏幕即可。
32
+
33
+ 默认什么都不用配:端口 13337、监听所有网卡、随机路径首次启动自动生成并保存。需要时再加访问密码,或限制哪些设备能连。
34
+
35
+ > **先在本机配好 API Key。** DSH 的部分设置只能在本机页面修改(这是 DSH 自己的规则,不是插件限制;0.2.0 上远程页面完全不能改设置),所以 API Key 等要在本机的 DSH 里填。远程页面可以正常新建会话、聊天、选择工作区。
36
+
37
+ 命令行安装:
38
+
39
+ ```bash
40
+ dsh plugin --profile web add dsh-remote-access-proxy
41
+ ```
42
+
43
+ git 依赖由 profile 的 `pnpm-lock.yaml` 钉在某个提交上。命令行安装建议直接带 tag(`dsh-remote-access-proxy`)。DSH 运行中请用配置页或插件页更新;DSH 没有运行时,也可以在 profile 目录里用新的 tag 再执行一次 `pnpm add`。
44
+
45
+ ## 配置页
46
+
47
+ ![配置页](docs/config-page.png)
48
+
49
+ - **状态**:运行中 / 已关闭 / 未能启动。启动失败会直接写出原因和改法,例如「端口 13337 已被占用」「证书读不出来」,不用再去翻日志。
50
+ - **入口地址**:每块网卡一行,附复制按钮。
51
+ - **允许的来源地址**:哪些设备可以连进来,写 IP、网段或范围,例如 `192.168.1.0/24, 100.64.0.0/10`。点「只允许局域网和 VPN」一键填好所有私有网段;留空表示不限制。其它地址的连接在交换任何数据之前就会被断开,配置页会显示最近被拒绝的地址,把自己锁在外面时照着加回来即可。本机始终允许。
52
+ - **访问密码**(可选):设置后入口会先显示登录页。登录过的设备记住 30 天;改密码会让所有设备重新登录。同一地址连续输错 5 次会被锁几分钟。打开 `<入口>/__rap/logout` 可以退出当前设备。
53
+ - **重新生成入口路径**:保存后旧地址立即失效,适合怀疑地址泄露的时候用。
54
+ - 开关类设置显示为开关;保存后立即生效,代理原地重启,不用重启 DSH。
55
+
56
+ 在 DSH 0.2.0 上配置页只在本机页面出现;0.2.1 起远程页面也能打开它,但**一键更新只在本机页面提供**。
57
+
58
+ ## 要不要开 TLS
59
+
60
+ 不是必须的。DSH 0.2 在明文 http 下也能正常工作。
61
+
62
+ - **VPN / 家庭局域网**:用 http 就行,流量本身已经在私有网络里。
63
+ - **公网**:请开 TLS,或者把代理放在 HTTPS 反代(Caddy、nginx、Cloudflare Tunnel)后面。
64
+
65
+ 开 TLS 需要一个 `.pfx` 证书。Windows 上用 PowerShell 生成自签证书:
66
+
67
+ ```powershell
68
+ $cert = New-SelfSignedCertificate -DnsName "dsh.local" -CertStoreLocation Cert:\CurrentUser\My -NotAfter (Get-Date).AddYears(5)
69
+ Export-PfxCertificate -Cert $cert -FilePath .\data\certs\dsh-proxy.pfx -Password (ConvertTo-SecureString "换成你的口令" -AsPlainText -Force)
70
+ ```
71
+
72
+ macOS / Linux 用 openssl:
73
+
74
+ ```bash
75
+ openssl req -x509 -newkey rsa:2048 -nodes -days 1825 -subj "/CN=dsh.local" -keyout key.pem -out cert.pem
76
+ openssl pkcs12 -export -inkey key.pem -in cert.pem -out dsh-proxy.pfx -passout pass:换成你的口令
77
+ ```
78
+
79
+ 然后在配置页打开「启用 TLS」,填证书路径和口令,保存。浏览器第一次访问时需要接受一次证书警告。开启 TLS 后门禁 Cookie 会带上 `Secure` 标记。
80
+
81
+ ## 常见问题
82
+
83
+ | 配置页显示 | 怎么办 |
84
+ |---|---|
85
+ | 端口 … 已被占用 | 换个端口,或关掉占用它的程序。两个 DSH(例如便携版和桌面版)共用同一个 `data` 目录时也会这样,见下文 |
86
+ | 这些来源地址写法不对 | 写 IP(`10.0.0.5`)、网段(`10.0.0.0/24`)或范围(`10.0.0.5-10.0.0.9`) |
87
+ | 证书读不出来 | 检查证书路径(相对路径相对 DSH 的工作目录)和口令 |
88
+ | 读不到代理状态 | 插件没在运行:确认插件和组件的开关都是开的 |
89
+
90
+ - **远程设备完全连不上**(连接被重置):它的地址不在白名单里。配置页会显示被拒绝的地址,把它加进去,或点「只允许局域网和 VPN」。
91
+ - **远程打开显示 `forbidden`**:随机路径不对。重新打开完整的入口地址。
92
+ - **页面只有一行纯文本 `bad gateway`**:代理连不上上游 DSH。状态卡的「上游」一行显示它正在用的地址,`access.log` 里记着原因(通常是 `ECONNREFUSED`)。把 `upstreamHost` / `upstreamPort` 留空 / `0`,让地址自动跟随当前实例。1.4.1 之前的桌面端必然踩这个坑:桌面启动器传的是 `--port 0`,而插件读的是 `webStartup` 上那个**请求值** `0`,没读 `webServer` 实际绑定的端口,于是掉到 3080。
93
+ - **两个 DSH 共用一个 `$DSH_HOME`**:它们读同一份 profile,会抢同一个端口。在其中一个的配置页关掉「启用」,或者给两边设不同的端口。
94
+
95
+ ## 安全
96
+
97
+ 访问控制完全由代理的门禁承担:
98
+
99
+ - **随机路径**:入口是 `<地址>:<端口>/<随机路径>/`,随机路径用系统 CSPRNG 生成;
100
+ - **来源白名单**:不在 `allowFrom` 里的客户端在 TCP 层(TLS 握手之前)就被断开,效果和防火墙规则一样。本机回环始终允许,所以本机的 HTTPS 反代照常可用;
101
+ - **访问密码**(可选):不设时只靠随机路径;设置后入口显示登录表单,输错会延迟并按地址限流;
102
+ - **记住设备**:进入(或登录)后写入 `dsh_et_gate`,这是一个 30 天后过期的签名值(`Path=/; Max-Age=2592000; HttpOnly; SameSite=Strict`,开 TLS 时再加 `Secure`)。签名覆盖随机路径和密码,所以改其中任意一个、或重新生成路径,所有设备都会失效。用户不需要手动管理它。
103
+
104
+ 代理以回环身份转发给 DSH(Host 改写为 `127.0.0.1:<端口>`,去掉 Origin),并**自己完成 launch token 交换、持有 `dsh-auth-*` Cookie**,所以远程用户永远看不到每次启动都会变的 token。DSH 返回 401 时,代理丢弃旧 Cookie 并重新交换。
105
+
106
+ 随机路径就是钥匙:把入口地址当密码对待。`access.log` 的启动行也会记录它。
107
+
108
+ ## 配置
109
+
110
+ 所有字段都是插件 Cordis `Config` 的 `.volatile()` 字段,保存在当前 profile 的 `cordis.patch.yml` 里。可以在配置页修改,也可以参照 [`config/cordis.patch.example.yml`](config/cordis.patch.example.yml) 手动编辑。
111
+
112
+ | 字段 | 说明 |
113
+ |---|---|
114
+ | `enabled` | 关闭后停止监听 |
115
+ | `listenPort` | 端口(默认 `13337`);固定监听所有网卡,IPv4 和 IPv6 |
116
+ | `secretPath` | 随机路径(4–32 位字母、数字、`-`、`_`;留空自动生成) |
117
+ | `allowFrom` | 允许连接的客户端地址:IP、网段、`a-b` 范围,用逗号或空格分隔。留空 = 不限制;本机始终允许 |
118
+ | `password` | 可选的访问密码(留空 = 不需要) |
119
+ | `cookieValue` | 给「记住设备」签名的服务端密钥(自动生成,配置页不显示) |
120
+ | `upstreamHost` / `upstreamPort` | 上游 DSH。留空 / `0` 时自动跟随当前实例:先读 `webServer` 已绑定的端口,再退到 `webStartup`(`dsh web` 为 3080;桌面端传的是 `--port 0`,真实端口只在 `webServer` 上) |
121
+ | `tlsEnabled` / `tlsPfxPath` / `tlsPassphrase` | TLS(pfx 证书) |
122
+ | `logMaxBytes` / `logKeep` | `access.log` 轮转:超过上限(默认 1 MiB)就轮转,保留若干份旧文件(默认 3);`0` 分别表示不轮转、不留历史 |
123
+
124
+ ## 更新
125
+
126
+ 更新由 DSH「插件」页统一管理:查看 npm 版本列表、选择兼容版本并更新。插件自身不再检查 GitHub 或执行安装。发布配置见 [PUBLISHING.md](PUBLISHING.md)。
127
+
128
+ ## 从旧版本升级
129
+
130
+ 从 GitHub 来源迁移的步骤见本页开头的 npm 安装说明。保留原 profile 与配置行 ID;代理的旧绝对路径配置会在启动时修正。
131
+
132
+ ## 开发与测试
133
+
134
+ ```
135
+ dsh-remote-access-proxy/
136
+ ├── package.json # bundle 清单 + dsh.client;"." = 代理,"./client" = 配置页
137
+ ├── cordis.patch.yml # 插件插入的那一行(按包名加载)
138
+ ├── plugin/dsh-remote-access-proxy.mjs # 宿主侧:门禁 + 转发 + 状态接口
139
+ ├── client/index.js # 浏览器侧:配置页
140
+ ├── config/cordis.patch.example.yml # 手动配置模板
141
+ ├── locale/{en,zh}.json # 插件页标题与描述
142
+ └── test-remote-access-proxy.mjs # 端到端测试(模拟 DSH)
143
+ ```
144
+
145
+ ```bash
146
+ pnpm install
147
+ node test-remote-access-proxy.mjs # 期望:78 passed, 0 failed
148
+ ```
149
+
150
+ 测试会模拟 DSH 上游(launch token 交换 + `dsh-auth` Cookie 门禁)以及插件依赖的宿主契约,覆盖:门禁、Cookie 注入、token 剥离、303 改写、401 自愈、WS 升级、日志轮转、密钥生成与写回、状态接口、错误原因(非法路径、端口占用、白名单写法错误)、密码登录(深链接、锁定、退出、失效)、来源白名单(断开、回环、上报)、1.1 → 1.2 迁移、上游自动探测、热替换时关闭全部连接并立即重新绑定端口,以及包结构。
151
+
152
+ ### 发版约定
153
+
154
+ 更新 package.json 与 package-lock.json 的版本后推送 main,GitHub Actions 会测试并自动发布 npm。也支持版本 tag 或手动触发。一次性 Trusted Publisher 配置见 [PUBLISHING.md](PUBLISHING.md)。
155
+
156
+ ## 相关项目
157
+
158
+ - [deepinfra-fusion-proxy](https://github.com/citydirector/deepinfra-fusion-proxy):DeepInfra Standard / Flex 按会话切换与自动回退
159
+ - [dsh-loop-rescue](https://github.com/citydirector/dsh-loop-rescue):模型复读时从流内切断、剪掉循环并自动续跑
160
+ - [dsh-session-manager](https://github.com/citydirector/dsh-session-manager):离线会话管理器,可升级、归档、清洗循环、修复烂尾会话
161
+
162
+ ## 许可证
163
+
164
+ [MIT](LICENSE)