dsh-mobile 0.4.0 → 0.4.1
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/CHANGELOG.md +19 -5
- package/README.en.md +29 -11
- package/README.md +22 -11
- package/SECURITY.md +2 -0
- package/docs/SELF_HOSTED_FRP.en.md +75 -0
- package/docs/SELF_HOSTED_FRP.md +3 -1
- package/lib/cli.js +3 -1
- package/lib/cli.js.map +1 -1
- package/lib/client.js +72 -14
- package/lib/client.js.map +1 -1
- package/lib/index.d.mts +3 -1
- package/lib/index.mjs +84 -18
- package/lib/index.mjs.map +1 -1
- package/package.json +18 -9
package/CHANGELOG.md
CHANGED
|
@@ -4,7 +4,21 @@ Notable changes to DSH Mobile are recorded here. GitHub Releases remain the sour
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
No unreleased changes.
|
|
8
|
+
|
|
9
|
+
## 0.4.1 - 2026-09-15
|
|
10
|
+
|
|
11
|
+
- Allow the desktop Mobile access admin API and sidebar control on RFC1918 and IPv4 link-local Host values when the TCP peer remains loopback, so headless Linux hosts and LAN reverse proxies can open DSH Web without a localhost-only browser. Public IPs, CGNAT, and arbitrary DNS names stay rejected. The dedicated Mobile HTTPS listener remains the phone surface (thanks @xingleiwu for PR #79).
|
|
12
|
+
- Let the proxied DSH GUI frame its own same-origin surfaces and embed external http(s) and blob: pages, so the right-sidebar browser tab, the HTML/diff previews, and the PDF preview work over LAN and remote access; gateway-owned login, pairing, and JSON responses keep refusing every frame (thanks @idoall for PR #77).
|
|
13
|
+
- Bound advisory operating-system route inspection so a slow Windows network query falls back to explicit network selection instead of holding the local setup page open.
|
|
14
|
+
- Keep Android CI and release setup limited to currently available SDK packages so APK verification is not blocked by the retired `tools` package.
|
|
15
|
+
- Require a same-origin `Origin` header on every mutating desktop management request, including clients that omit Fetch Metadata, so private-Host reverse proxies cannot bypass the browser CSRF check.
|
|
16
|
+
- Accept the DSH conversation scroll marker wherever it lives under the conversation skeleton, keeping the compatibility gate valid when upstream extracts the body into a separate component.
|
|
17
|
+
- Allow HTTP iframe sources for compatibility while showing a localized warning that unencrypted pages can be altered and should not be used for sensitive work.
|
|
18
|
+
- Fix mobile extension Host actions that sent JSON without an explicit content type, which caused every `api.host.invoke()` call to return `415 unsupported_media_type`.
|
|
19
|
+
- Accept callable Schemastery input schemas as well as existing `parse(value)` adapters for extension actions, so documented `api.schema.object(...)` inputs are validated and normalized before `run()`.
|
|
20
|
+
- Update the development peers and source compatibility gate for DeepSeek Harness `0.1.6-alpha.1`: the checker follows extracted conversation/composer markers and the named global transport hook without weakening the Host-trust or authenticated RPC checks.
|
|
21
|
+
- Correct bilingual navigation and historical issue links, clarify Android task-reminder versus browser-notification behavior, and add a complete English self-hosted FRP guide without changing runtime behavior.
|
|
8
22
|
|
|
9
23
|
## 0.4.0 - 2026-09-14
|
|
10
24
|
|
|
@@ -93,7 +107,7 @@ Future changes will be recorded here.
|
|
|
93
107
|
|
|
94
108
|
## 0.3.7 - 2026-09-02
|
|
95
109
|
|
|
96
|
-
- Fix the Windows DSH Desktop startup failure reported in [#22
|
|
110
|
+
- Fix the Windows DSH Desktop startup failure reported in [#22](https://github.com/saya-ch/dsh-mobile/issues/22): capture subprocess output through the callback API instead of relying on `execFile` promisify metadata that a host wrapper may omit. Thanks @XChen446 for the precise 0.3.6 stack trace.
|
|
97
111
|
- Apply the same output handling to Windows SID resolution, private-file ACLs, route selection, and firewall diagnostics/setup. Invalid SID output and ACL failures still reject the operation; a failed SID lookup can be retried and Windows permission commands have bounded execution time.
|
|
98
112
|
- Retain the 0.3.6 removal of the exact DSH version allowlist. Existing 0.3.3-0.3.6 Android apps and paired devices remain compatible; the 0.3.7 APK updates version metadata only.
|
|
99
113
|
|
|
@@ -105,7 +119,7 @@ Future changes will be recorded here.
|
|
|
105
119
|
|
|
106
120
|
## 0.3.5 - 2026-09-01
|
|
107
121
|
|
|
108
|
-
- Fix [#26
|
|
122
|
+
- Fix [#26](https://github.com/saya-ch/dsh-mobile/issues/26): prevent mobile startup from remaining on “Loading plugins” over LAN or remote access when DSH sends the WebSocket upgrade response and initial snapshot together. The gateway now preserves that snapshot without relaxing its 16 KiB response-header limit. Thanks @oliverwan97 for the detailed report.
|
|
109
123
|
|
|
110
124
|
## 0.3.4 - 2026-08-31
|
|
111
125
|
|
|
@@ -128,7 +142,7 @@ Future changes will be recorded here.
|
|
|
128
142
|
|
|
129
143
|
## 0.3.2 - 2026-08-29
|
|
130
144
|
|
|
131
|
-
- Special thanks to @JackRushante for [#16
|
|
145
|
+
- Special thanks to @JackRushante for [#16](https://github.com/saya-ch/dsh-mobile/pull/16): the secure Android media bridge, image attachments, localization foundation, bounded extension requests, and Funnel lifecycle hardening. This release retains all four original commits and their author metadata.
|
|
132
146
|
- Move image selection and camera capture into a dedicated top row of the composer command menu, without focusing the message editor.
|
|
133
147
|
- Push extension and `/mobile` changes to authenticated phones immediately, while retaining bounded polling as a network-recovery fallback.
|
|
134
148
|
- Bind each mobile UI to its matching Host, script, style, and asset generation; retain the previous Host through a bounded refresh window, fail closed on client activation errors, and tighten scoped requests against encoded path traversal.
|
|
@@ -138,7 +152,7 @@ Future changes will be recorded here.
|
|
|
138
152
|
|
|
139
153
|
## 0.3.1 - 2026-08-28
|
|
140
154
|
|
|
141
|
-
- Credit @BlueandwhiteXD ([#15
|
|
155
|
+
- Credit @BlueandwhiteXD ([#15](https://github.com/saya-ch/dsh-mobile/pull/15)) for the Android keyboard inset report and fix incorporated into the 0.3 mobile layout.
|
|
142
156
|
|
|
143
157
|
## 0.3.0 - 2026-08-28
|
|
144
158
|
|
package/README.en.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
<h1 align="center">DSH Mobile</h1>
|
|
6
6
|
|
|
7
|
-
<p align="center">Secure, live
|
|
7
|
+
<p align="center">Secure, live access to DeepSeek Harness from a phone.</p>
|
|
8
8
|
|
|
9
9
|
<p align="center">
|
|
10
10
|
<a href="https://www.npmjs.com/package/dsh-mobile"><img src="https://img.shields.io/npm/v/dsh-mobile?label=npm&color=CB3837" alt="npm version"></a>
|
|
@@ -15,18 +15,29 @@
|
|
|
15
15
|
<a href="https://github.com/awesome-dsh-plugin/awesome-dsh-plugin"><img src="https://awesome-dsh-plugin.com/badge.svg" alt="Awesome DSH Plugin"></a>
|
|
16
16
|
</p>
|
|
17
17
|
|
|
18
|
-
<p align="center"
|
|
18
|
+
<p align="center">
|
|
19
|
+
<a href="#what-it-does">What it does</a> ·
|
|
20
|
+
<a href="#quick-start">Quick start</a> ·
|
|
21
|
+
<a href="#connection-guide">Connection guide</a> ·
|
|
22
|
+
<a href="#extend-and-customize">Extend and customize</a> ·
|
|
23
|
+
<a href="#device-management">Device management</a> ·
|
|
24
|
+
<a href="#third-party-plugin-compatibility">Third-party plugins</a> ·
|
|
25
|
+
<a href="#security">Security</a> ·
|
|
26
|
+
<a href="#compatibility">Compatibility</a> ·
|
|
27
|
+
<a href="CHANGELOG.md">Changelog</a> ·
|
|
28
|
+
<a href="README.md">简体中文</a>
|
|
29
|
+
</p>
|
|
19
30
|
|
|
20
31
|
> DSH Mobile is a DeepSeek Harness community plugin; the native app supports Android only.
|
|
21
32
|
>
|
|
22
|
-
> **0.4.
|
|
33
|
+
> **0.4.1 update**: adapts to DeepSeek Harness 0.1.6-alpha.1, fixes extension action requests and LAN route inspection, hardens admin CSRF checks, HTTP iframe warnings, and the frontend compatibility gate, and adds a complete English self-hosted FRP guide. [Details](CHANGELOG.md).
|
|
23
34
|
>
|
|
24
|
-
> **Upgrade reminder**: 0.4.
|
|
35
|
+
> **Upgrade reminder**: the 0.4.1 plugin continues to work with the 0.4.0 Android app and existing devices do not need re-pairing. Install the 0.4.1 app as well if you want this Android build. [Compatibility notes](#compatibility).
|
|
25
36
|
|
|
26
37
|
<p align="center">
|
|
27
|
-
<a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.4.
|
|
28
|
-
<a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.4.
|
|
29
|
-
<sub><a href="https://github.com/saya-ch/dsh-mobile/releases/tag/v0.4.
|
|
38
|
+
<a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.4.1/dsh-mobile-android-v0.4.1.apk"><img src="assets/brand/app-icon-rounded.svg" alt="DSH Mobile Android app icon" width="72" height="72"></a><br>
|
|
39
|
+
<a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.4.1/dsh-mobile-android-v0.4.1.apk"><strong>Download Android app 0.4.1</strong></a><br>
|
|
40
|
+
<sub><a href="https://github.com/saya-ch/dsh-mobile/releases/tag/v0.4.1">Release notes and checksums</a></sub>
|
|
30
41
|
</p>
|
|
31
42
|
|
|
32
43
|
DSH Mobile is a DeepSeek Harness plugin that lets a mobile browser or the Android app connect over a protected LAN or an optional Tailscale Funnel, cpolar, or self-hosted FRP remote path. Local and remote access keep the same sessions, Workspaces, messages, and tools while using separate switches and paired-device stores without modifying DeepSeek Harness source.
|
|
@@ -80,7 +91,7 @@ Restart DSH, then search for **dsh-mobile** under **Settings → Plugin Market**
|
|
|
80
91
|
|
|
81
92
|
After installation, start DSH and use the connection guide below to choose LAN or remote access.
|
|
82
93
|
|
|
83
|
-
Registry-installed plugins check for updates when the desktop UI loads and show “Update plugin” beside the access-panel title when a newer release is available. Restart DSH after installation. The app download entry shows the latest version; local development packages are not overwritten, and Android does not
|
|
94
|
+
Registry-installed plugins check for updates when the desktop UI loads and show “Update plugin” beside the access-panel title when a newer release is available. Restart DSH after installation. The app download entry shows the latest version; local development packages are not overwritten, and Android does not check for or push app-version updates.
|
|
84
95
|
|
|
85
96
|
## Connection guide
|
|
86
97
|
|
|
@@ -101,6 +112,8 @@ Use this when the phone and computer share Wi-Fi, Ethernet, or a phone hotspot.
|
|
|
101
112
|
|
|
102
113
|
Port note: `dsh web --port` changes the DSH Web upstream port (3080 by default), which the plugin follows automatically. `dsh-mobile setup --port` changes the Mobile HTTPS listener (3443 by default), and the pairing QR code includes the selected port.
|
|
103
114
|
|
|
115
|
+
Headless Linux hosts, and browsers that open DSH Web through a LAN IP or reverse proxy, can use the same **Mobile access** control in the lower-left corner. The admin API still requires a loopback TCP peer (for example a local `socat` or reverse proxy to `127.0.0.1`) so the plugin itself is not LAN-exposed. The browser Host may be `localhost`, RFC1918, or an IPv4 link-local address; public IPs and arbitrary DNS names still return 403. The reverse proxy must be limited to trusted local or LAN callers and must not publicly forward `/api/mobile-access`. The dedicated Mobile HTTPS listener (3443 by default) remains the phone surface and does not become the desktop admin panel.
|
|
116
|
+
|
|
104
117
|
The app is optional: select **Copy pairing link** and open it in a mobile browser. The browser must manually trust the plugin certificate on the first visit.
|
|
105
118
|
|
|
106
119
|
Browser pairing and reauthentication pages use the browser's `Accept-Language` to show Simplified Chinese, English, or Italian. Android screens follow the system language, while the DSH plugin control panel follows the language selected by DSH.
|
|
@@ -118,12 +131,12 @@ Remote providers may impose bandwidth and connection limits: the [cpolar Free pl
|
|
|
118
131
|
1. Open **Mobile Access → Remote** in the lower-left corner of DeepSeek Harness and choose a provider:
|
|
119
132
|
- **Tailscale Funnel**: select **Enable remote access**, complete the one-time Tailscale sign-in on the official page, follow the panel prompt to allow Funnel, then return to DSH and wait until the connection is ready.
|
|
120
133
|
- **cpolar**: select **Install official component**, sign in to the cpolar dashboard and obtain an Authtoken, paste it, then select **Save and connect**. The component is downloaded into the plugin's private directory only after confirmation; free temporary addresses may change after DSH or cpolar restarts.
|
|
121
|
-
- **Self-hosted FRP (advanced)**: expand **Self-hosted connection**, enter the VPS, frps port, shared token, and public HTTPS origin. The origin may use your domain or the VPS public IPv4 address (for example, `https://203.0.113.10` — substitute your own real address; documentation ranges are rejected). Apply the restricted template manually or enter an SSH user, port, and local private-key path for automatic deployment. Automatic deployment supports Ubuntu/Debian with systemd, uses OpenSSH keys or an agent, refuses password auth, and does not overwrite Caddy configuration it does not manage; both deployment and server cleanup display the SSH host keys for verification against the VPS console before continuing. IPv4 mode obtains a roughly six-day Let's Encrypt IP certificate and installs daily automatic renewal. Install the official `frpc` on demand and verify the path afterward. A reviewable uninstall script or one-click server cleanup removes only DSH Mobile-owned services and configs. This requires Android app 0.3.3 or later.
|
|
134
|
+
- **Self-hosted FRP (advanced)**: expand **Self-hosted connection**, enter the VPS, frps port, shared token, and public HTTPS origin. The origin may use your domain or the VPS public IPv4 address (for example, `https://203.0.113.10` — substitute your own real address; documentation ranges are rejected). Apply the restricted template manually or enter an SSH user, port, and local private-key path for automatic deployment. Automatic deployment supports Ubuntu/Debian with systemd, uses OpenSSH keys or an agent, refuses password auth, and does not overwrite Caddy configuration it does not manage; both deployment and server cleanup display the SSH host keys for verification against the VPS console before continuing. IPv4 mode obtains a roughly six-day Let's Encrypt IP certificate and installs daily automatic renewal. Install the official `frpc` on demand and verify the path afterward. A reviewable uninstall script or one-click server cleanup removes only DSH Mobile-owned services and configs. This requires Android app 0.3.3 or later. See the [English self-hosted FRP guide](docs/SELF_HOSTED_FRP.en.md) for the complete procedure.
|
|
122
135
|
2. When the panel reports that remote access is ready, select **Create remote pairing QR code**.
|
|
123
136
|
3. In the Android app, open **Remote access** and scan the QR code to create its separate pairing.
|
|
124
137
|
4. The app saves the current address and device credential for automatic reconnection. If a free cpolar address changes, scan the computer's current remote QR code to verify the connection again; clearing app data is unnecessary. A stored device token is sent only to its exact saved Origin, never to a new QR-code domain.
|
|
125
138
|
|
|
126
|
-
> **Remote notifications**: browser
|
|
139
|
+
> **Remote notifications**: browser `Notification` permission is granted per Origin, and a web-page system toast appears only on the device running that page. Android task reminders are a separate 0.4.0 feature: enable them from the app's foreground menu, and keep the WebView page alive; they are not a general background push service. For reliable background delivery, use a server-side webhook or bot channel you have configured.
|
|
127
140
|
|
|
128
141
|
Tailscale Funnel has broad reach but may be unreliable from mainland China. Its runtime ties the public listener to the parent process and a bounded control channel; parent exit, channel closure, or an explicit stop ends the current generation and cleans up its resources. cpolar is better suited to mainland networks, while self-hosted FRP fits users who already have a VPS and want to avoid public-provider bandwidth quotas. An unregistered domain on a mainland-China VPS may be intercepted by the cloud provider; public IPv4 mode avoids that dependency. The plugin validates pinned on-demand components, stores their configuration and programs entirely under `$DSH_HOME/mobile-access/`, and can remove them completely from the panel.
|
|
129
142
|
|
|
@@ -149,6 +162,8 @@ Two kinds of changes are supported: the phone UI itself (theme, layout, buttons)
|
|
|
149
162
|
|
|
150
163
|
Extension manifests, scripts, styles, and assets are revisioned. When the plugin observes a `/mobile` or extension-file change, it notifies authenticated phones to refresh immediately; 45-second visible and 5-minute hidden checks remain only as recovery fallbacks. A failed Host staging pass keeps the current version; if the Host has changed but the new phone UI cannot activate, that extension closes and retries instead of mixing generations.
|
|
151
164
|
|
|
165
|
+
An extension action's `input` may use a callable Schemastery schema such as `api.schema.object(...)` or an adapter with `parse(value)`; mobile `api.host.invoke()` sends JSON explicitly, and the input is validated and normalized before the computer-side action runs.
|
|
166
|
+
|
|
152
167
|
<sub>You can even use an extension to connect to SillyTavern running on the same computer, give it a lightweight mobile frontend, and open it from the same app.</sub>
|
|
153
168
|
|
|
154
169
|
> `host.mjs` has the same privileges as a local program. Create and run only computer-side extensions that you understand and trust.
|
|
@@ -192,7 +207,9 @@ The mobile adaptation keeps DSH's existing Workspace, task-management, terminal,
|
|
|
192
207
|
|
|
193
208
|
Compatibility and WebSocket rules:
|
|
194
209
|
|
|
195
|
-
|
|
210
|
+
Proxied pages allow HTTP frames for compatibility with some community plugins; those pages are unencrypted and can be altered, and browsers may still block them as mixed content. Use HTTPS for sensitive work. The same warning appears at the top of the remote panel when it is opened over HTTPS.
|
|
211
|
+
|
|
212
|
+
- The released 0.4.0 is contract-checked against DSH `0.1.5-rc.2` (renderer-v2) and retains the `0.1.5-rc.1` LAN verification. The DSH page must expose the standard session, `main`/`panelInfo`, and `rightbar` slots; the community plugin must register its panel or sidebar content through DSH's standard entry points.
|
|
196
213
|
- The gateway allows first-party DSH WebSocket paths by default, including `/sidebar/ws/terminal`. Other paths used by community sidebar plugins are blocked by default and appear in Diagnostics; the `/sidebar/ws/agent-opens` and `/sidebar/ws/agent-terminals` paths in the image are examples that must be reviewed for the actual plugin.
|
|
197
214
|
- In **Connection diagnostics → Third-party WebSocket paths**, select **Allow** only for an exact path you have verified. Query strings and fuzzy prefixes are rejected; **Allow all** is not recommended. Approved paths can be removed at any time, and the same policy applies to LAN and remote connections.
|
|
198
215
|
- Approval only lets that path pass through the authenticated, same-origin DSH Mobile gateway. It does not open arbitrary TCP/UDP ports or bypass device pairing. If a community plugin still fails, check the path recorded by Diagnostics and approve one path at a time.
|
|
@@ -253,6 +270,7 @@ The table below lists, for each plugin version, the DeepSeek Harness version it
|
|
|
253
270
|
|
|
254
271
|
| DSH Mobile plugin | Verified DeepSeek Harness version |
|
|
255
272
|
| --- | --- |
|
|
273
|
+
| `0.4.1` | `0.1.6-alpha.1` (local source and renderer-v2 contract check) |
|
|
256
274
|
| `0.3.15`, `0.3.16`, `0.4.0` | `0.1.5-rc.2` (contract check); `0.1.5-rc.1` (@idoall LAN verification) |
|
|
257
275
|
| `0.3.14` | `0.1.3-alpha.2` |
|
|
258
276
|
| `0.3.9`-`0.3.12` | `0.1.3-alpha.1` |
|
package/README.md
CHANGED
|
@@ -20,20 +20,24 @@
|
|
|
20
20
|
<a href="#快速开始">快速开始</a> ·
|
|
21
21
|
<a href="#连接教程">连接教程</a> ·
|
|
22
22
|
<a href="#扩展与自定义">扩展与自定义</a> ·
|
|
23
|
+
<a href="#设备管理">设备管理</a> ·
|
|
24
|
+
<a href="#第三方插件适配">第三方插件适配</a> ·
|
|
25
|
+
<a href="#安全">安全</a> ·
|
|
26
|
+
<a href="#兼容性">兼容性</a> ·
|
|
23
27
|
<a href="CHANGELOG.md">更新记录</a> ·
|
|
24
28
|
<a href="README.en.md">English</a>
|
|
25
29
|
</p>
|
|
26
30
|
|
|
27
31
|
> DSH Mobile 是 DeepSeek Harness 社区插件,原生 App 仅支持 Android。
|
|
28
32
|
>
|
|
29
|
-
> **0.4.0
|
|
33
|
+
> **0.4.1 更新**:适配 DeepSeek Harness 0.1.6-alpha.1,修复扩展动作请求和局域网路由检测,强化管理请求 CSRF、HTTP iframe 警告与前端兼容性检查,并补齐中英文 FRP 文档。[详细记录](CHANGELOG.md)。
|
|
30
34
|
>
|
|
31
|
-
> **升级提醒**:0.4.0
|
|
35
|
+
> **升级提醒**:0.4.1 插件可继续使用 0.4.0 Android App;已有设备无需重新配对。若要使用本次 Android 构建,请同时安装 0.4.1 App。[兼容说明](#兼容性)。
|
|
32
36
|
|
|
33
37
|
<p align="center">
|
|
34
|
-
<a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.4.
|
|
35
|
-
<a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.4.
|
|
36
|
-
<sub><a href="https://github.com/saya-ch/dsh-mobile/releases/tag/v0.4.
|
|
38
|
+
<a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.4.1/dsh-mobile-android-v0.4.1.apk"><img src="assets/brand/app-icon-rounded.svg" alt="DSH Mobile 安卓应用图标" width="72" height="72"></a><br>
|
|
39
|
+
<a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.4.1/dsh-mobile-android-v0.4.1.apk"><strong>下载 Android App 0.4.1</strong></a><br>
|
|
40
|
+
<sub><a href="https://github.com/saya-ch/dsh-mobile/releases/tag/v0.4.1">版本说明与校验文件</a></sub>
|
|
37
41
|
</p>
|
|
38
42
|
|
|
39
43
|
DSH Mobile 是一个 DeepSeek Harness 插件,让手机浏览器或 Android App 通过局域网,或可选的 Tailscale Funnel、cpolar、自建 FRP 远程通道连接电脑,继续使用同一份会话、工作区、消息和工具。局域网与远程访问分别启停、分别管理设备,且都不修改 DeepSeek Harness 源码。
|
|
@@ -87,7 +91,7 @@ dsh plugin --profile web add dshmarket
|
|
|
87
91
|
|
|
88
92
|
安装并启动 DSH 后,按照下一节选择局域网或远程连接。
|
|
89
93
|
|
|
90
|
-
通过 npm 安装的插件会在桌面界面加载时检查新版本,有更新时在访问面板标题右侧显示“更新插件”,安装后需重启 DSH。App 下载入口展示最新版本;本地开发包不会被自动覆盖,Android App
|
|
94
|
+
通过 npm 安装的插件会在桌面界面加载时检查新版本,有更新时在访问面板标题右侧显示“更新插件”,安装后需重启 DSH。App 下载入口展示最新版本;本地开发包不会被自动覆盖,Android App 不会主动检查或推送版本更新。
|
|
91
95
|
|
|
92
96
|
## 连接教程
|
|
93
97
|
|
|
@@ -108,6 +112,8 @@ dsh plugin --profile web add dshmarket
|
|
|
108
112
|
|
|
109
113
|
端口说明:`dsh web --port` 修改 DSH Web 上游端口(默认 3080),插件会自动跟随;`dsh-mobile setup --port` 修改 Mobile HTTPS 监听端口(默认 3443),配对二维码会包含实际端口。
|
|
110
114
|
|
|
115
|
+
无图形界面的 Linux 主机,或通过局域网 IP / 反向代理打开 DSH Web 时,左下角 **移动访问** 管理口同样可用。管理 API 仍要求 TCP 对端是本机回环(例如本机 `socat` / 反向代理连到 `127.0.0.1`),不会把插件自己暴露到公网;浏览器 Host 可以是 `localhost`、RFC1918 或 IPv4 链路本地地址,公网 IP 和任意域名仍会返回 403。反向代理必须只对可信的本机或内网请求开放,不能把 `/api/mobile-access` 管理路径公开转发到互联网。手机走的独立 HTTPS 入口(默认 3443)仍是移动端界面,不会变成桌面管理口。
|
|
116
|
+
|
|
111
117
|
不安装 App 也可以访问:点击 **复制配对链接**,在手机浏览器中打开;首次访问需要按浏览器提示手动信任插件证书。
|
|
112
118
|
|
|
113
119
|
手机浏览器中的配对和重新连接页面会按浏览器的 `Accept-Language` 显示简体中文、英文或意大利文;Android App 则跟随系统语言。DSH 内的插件控制面板继续跟随 DSH 当前语言。
|
|
@@ -125,12 +131,12 @@ dsh plugin --profile web add dshmarket
|
|
|
125
131
|
1. 在 DeepSeek Harness 左下角打开 **移动访问 → 远程**,选择一种连接方式:
|
|
126
132
|
- **Tailscale Funnel**:点击 **启用远程访问**,在打开的官方页面完成一次 Tailscale 登录;按面板提示继续允许 Funnel,然后返回 DSH 等待连接就绪。
|
|
127
133
|
- **cpolar**:点击 **安装官方组件**,登录 cpolar 控制台取得 Authtoken,粘贴后点击 **保存并连接**。组件只会在确认后下载到插件私有目录;免费临时地址可能在 DSH 或 cpolar 重启后变化。
|
|
128
|
-
- **自建 FRP(高级)**:展开 **自建连接**,填写 VPS、frps 端口、共享 Token 和公开 HTTPS 地址;公开地址可以是自己的域名,也可以直接是 VPS 公网 IPv4(例如 `https://203.0.113.10`,请换成你自己的真实地址,文档示例网段会被拒绝)。可以复制受限模板手动部署,也可以填写 SSH 用户、SSH 端口和本机私钥路径,点击 **部署 frps + Caddy** 自动部署。自动部署支持 Ubuntu/Debian + systemd,使用 OpenSSH 密钥或 ssh-agent,不接受密码,也不会覆盖非 DSH Mobile 管理的 Caddyfile;部署与清理前都会展示服务器主机指纹,需到 VPS 控制台核对后才能继续。公网 IP 模式会申请约 6 天有效的 Let’s Encrypt IP 证书并配置每日自动续期。部署完成后再安装官方 `frpc` 并验证连接。不再需要服务器时可用“复制 VPS 卸载脚本”或一键清理,只删除 DSH Mobile 自己的服务与配置。需要 Android App 0.3.3 或更高版本。详见[自建 FRP 使用指南](docs/SELF_HOSTED_FRP.md)。
|
|
134
|
+
- **自建 FRP(高级)**:展开 **自建连接**,填写 VPS、frps 端口、共享 Token 和公开 HTTPS 地址;公开地址可以是自己的域名,也可以直接是 VPS 公网 IPv4(例如 `https://203.0.113.10`,请换成你自己的真实地址,文档示例网段会被拒绝)。可以复制受限模板手动部署,也可以填写 SSH 用户、SSH 端口和本机私钥路径,点击 **部署 frps + Caddy** 自动部署。自动部署支持 Ubuntu/Debian + systemd,使用 OpenSSH 密钥或 ssh-agent,不接受密码,也不会覆盖非 DSH Mobile 管理的 Caddyfile;部署与清理前都会展示服务器主机指纹,需到 VPS 控制台核对后才能继续。公网 IP 模式会申请约 6 天有效的 Let’s Encrypt IP 证书并配置每日自动续期。部署完成后再安装官方 `frpc` 并验证连接。不再需要服务器时可用“复制 VPS 卸载脚本”或一键清理,只删除 DSH Mobile 自己的服务与配置。需要 Android App 0.3.3 或更高版本。详见 [自建 FRP 使用指南](docs/SELF_HOSTED_FRP.md)。
|
|
129
135
|
2. 状态变为“远程访问已就绪”后,点击 **生成远程配对二维码**。
|
|
130
136
|
3. 在 Android App 中进入 **远程访问**,扫描二维码完成独立配对。
|
|
131
137
|
4. 此后 App 会保存当前地址和设备凭据并自动重连。若 cpolar 免费临时地址发生变化,请扫描电脑端当前远程二维码重新验证连接;无需清除 App 数据。旧设备 token 只会发送到原先保存的精确 Origin,不会发送给二维码中的新域名。
|
|
132
138
|
|
|
133
|
-
>
|
|
139
|
+
> **远程通知说明**:浏览器的 `Notification` 权限按 Origin 分别授权,网页系统通知只显示在运行该网页的设备上。Android App 的任务提醒是独立的 0.4.0 功能,需要在 App 前台菜单中主动开启,且依赖 WebView 页面仍存活;它不是通用的后台推送。需要可靠的后台推送时,请使用你已配置的服务端 webhook 或机器人通道。
|
|
134
140
|
|
|
135
141
|
Tailscale Funnel 覆盖范围广,但在中国大陆网络下可能不稳定。其运行组件把公开监听生命周期绑定到父进程和受限控制通道;父进程退出、控制通道关闭或显式停止时会结束当前代次并清理资源。cpolar 更适合国内网络;自建 FRP 适合已有 VPS、希望避开公共服务带宽限制的用户。中国大陆 VPS 上的未备案域名可能被云厂商拦截,此时可使用公网 IPv4 模式。插件会校验按需下载的固定版本组件,配置与程序均保存在 `$DSH_HOME/mobile-access/`,可随时在面板中彻底清除。
|
|
136
142
|
|
|
@@ -156,7 +162,9 @@ Tailscale Funnel 覆盖范围广,但在中国大陆网络下可能不稳定。
|
|
|
156
162
|
|
|
157
163
|
扩展清单及其脚本、样式和资源按版本标识刷新。插件监听到 `/mobile` 或扩展文件变化后,会通过已认证连接通知手机立即更新;页面可见时每 45 秒、隐藏时每 5 分钟的检查只作为断线兜底。Host 暂存失败会继续使用现有版本;若 Host 已更新但新手机界面激活失败,则关闭该扩展并自动重试,避免混用新旧能力。
|
|
158
164
|
|
|
159
|
-
|
|
165
|
+
扩展动作的 `input` 可以直接使用 `api.schema.object(...)` 等 Schemastery schema,也可以使用带 `parse(value)` 的适配器;手机端 `api.host.invoke()` 会按 JSON 请求发送,输入会在电脑端动作执行前完成校验和规范化。
|
|
166
|
+
|
|
167
|
+
<sub>你甚至可以通过扩展连接电脑上运行的酒馆,并从同一 App 打开它的简易移动前端。</sub>
|
|
160
168
|
|
|
161
169
|
> `host.mjs` 与本机程序拥有相同权限;仅创建和运行你理解并信任的电脑端扩展。
|
|
162
170
|
|
|
@@ -199,8 +207,10 @@ Android App 将局域网、cpolar、Tailscale Funnel 和自建 FRP 统一整理
|
|
|
199
207
|
|
|
200
208
|
兼容条件与 WebSocket 放行规则:
|
|
201
209
|
|
|
202
|
-
|
|
203
|
-
|
|
210
|
+
代理页面为兼容部分社区插件允许嵌入 HTTP 页面;这类内容未加密,可能被篡改,浏览器也可能因混合内容策略拦截。处理敏感内容时请使用 HTTPS。通过 HTTPS 管理入口打开远程面板时,页面顶部会显示相同提醒。
|
|
211
|
+
|
|
212
|
+
- 已发布的 0.4.0 按 DSH `0.1.5-rc.2` 做过 renderer-v2 合同检查,并保留对 `0.1.5-rc.1` 局域网路径的验证。DSH 页面需要提供标准的会话、`main`/`panelInfo` 和 `rightbar` 插槽;插件自身需要通过 DSH 的标准面板或侧边栏入口注册内容。
|
|
213
|
+
- 网关默认只允许 DSH 内置的第一方 WebSocket 路径。社区侧边栏插件使用的其他路径默认拦截,通常会在诊断页显示为待处理项目;截图中的`/sidebar/ws/agent-opens` 和`/sidebar/ws/agent-terminals` 就属于这类需要按实际插件确认的路径。
|
|
204
214
|
- 在 **连接诊断 → 第三方 WebSocket 路径** 中,只对确认过的精确路径点击 **允许**。系统不接受带查询字符串或模糊前缀的路径;不建议使用“全部允许”。已允许的路径可以随时移除,局域网和远程连接使用同一套规则。
|
|
205
215
|
- 放行只代表该路径可以通过已认证、同源的 DSH Mobile 网关,不会开放任意 TCP/UDP 端口,也不会绕过设备配对。若社区插件仍然连接失败,先看诊断页的实际拦截路径,再按一条路径放行。
|
|
206
216
|
|
|
@@ -263,6 +273,7 @@ flowchart LR
|
|
|
263
273
|
|
|
264
274
|
| DSH Mobile 插件 | 验证支持的 DeepSeek Harness 版本 |
|
|
265
275
|
| ----------------------------------------- | -------------------------------------------------------------- |
|
|
276
|
+
| `0.4.1` | `0.1.6-alpha.1`(本机源码与 renderer-v2 契约检查) |
|
|
266
277
|
| `0.3.15`、`0.3.16`、`0.4.0` | `0.1.5-rc.2`(契约检查);`0.1.5-rc.1`(@idoall 局域网实测) |
|
|
267
278
|
| `0.3.14` | `0.1.3-alpha.2` |
|
|
268
279
|
| `0.3.9`-`0.3.12` | `0.1.3-alpha.1` |
|
package/SECURITY.md
CHANGED
|
@@ -16,6 +16,7 @@ The maintainer will acknowledge a complete report within seven days. Publication
|
|
|
16
16
|
|
|
17
17
|
- Keep the ordinary DSH Web listener on loopback.
|
|
18
18
|
- Expose only the plugin-owned HTTPS listener to the LAN.
|
|
19
|
+
- The desktop admin API may accept an RFC1918 or IPv4 link-local Host only when the TCP peer is loopback, for a trusted local reverse proxy or headless host. Do not publicly forward `/api/mobile-access`; Host and loopback checks are not a replacement for proxy access control. Mutating admin requests must carry a same-origin `Origin` header.
|
|
19
20
|
- DNS-SD/mDNS, periodic UDP announcements, active UDP query replies, and HTTPS discovery return only the device name, public HTTPS origin, port, protocol version, and stable non-secret installation identifier. Discovery never returns the CA, a pairing key, a device token, Cookies, credentials, or private configuration.
|
|
20
21
|
- For LAN pairing, only after a user selects a device and enters the fingerprint-bound pairing key may Android fetch the public CA from that exact HTTPS origin. The bootstrap GET sends no key or credential. The app retains the CA in its encrypted credential record and never adds it to Android's system trust settings. Native requests use a private trust store; WebView accepts only the otherwise-untrusted leaf signed by that CA, for the exact origin and validity period. Every other TLS error is cancelled.
|
|
21
22
|
- Public remote origins provided by Funnel, cpolar, or self-hosted FRP use platform-trusted HTTPS. Android stores no private CA for those credentials and cancels every TLS error. It sends a persisted device token only to the exact Origin that previously received it; a changed remote Origin requires a current one-time pairing token before the app replaces the saved credential. A QR-provided installation identifier alone never authorizes credential renewal. Browser clients likewise require a certificate trusted by their platform.
|
|
@@ -33,6 +34,7 @@ The maintainer will acknowledge a complete report within seven days. Publication
|
|
|
33
34
|
- Treat `mobile.js` as application code with the paired page's same-origin authority. Restrict write access to trusted host-side DSH sessions and review generated API calls or browser-permission use.
|
|
34
35
|
- Treat every extension `host.mjs` as a local program with the desktop user's Node.js privileges. It is never sandboxed and is not editable through the mobile gateway; only place code there that you trust.
|
|
35
36
|
- Extension Actions and Routes receive filtered request data, a device identifier, and an abort signal. They cannot set proxy security headers or access the gateway's cookies, device tokens, CSRF tokens, or internal request headers.
|
|
37
|
+
- Proxied GUI responses allow HTTP iframe sources for compatibility with community surfaces. HTTP content is unauthenticated and unencrypted; use HTTPS for sensitive work, and do not treat the compatibility allowance as a transport-security guarantee.
|
|
36
38
|
|
|
37
39
|
## Known limitation
|
|
38
40
|
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Self-hosted FRP guide
|
|
2
|
+
|
|
3
|
+
Self-hosted FRP is for users who already operate a VPS and want to avoid the bandwidth limits of public tunnels. The phone reaches Caddy on the VPS over HTTPS, crosses the encrypted FRP tunnel, and then reaches DSH on the computer. FRP only transports the request; DSH pairing is still required.
|
|
4
|
+
|
|
5
|
+
```text
|
|
6
|
+
Android app
|
|
7
|
+
-> HTTPS (domain or public IPv4)
|
|
8
|
+
-> Caddy on the VPS
|
|
9
|
+
-> 127.0.0.1:7080 (frps HTTP vhost, loopback only)
|
|
10
|
+
-> encrypted FRP tunnel
|
|
11
|
+
-> computer running DSH
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Two entry modes
|
|
15
|
+
|
|
16
|
+
- **Domain mode**: use your own public domain; Caddy obtains and renews the certificate automatically.
|
|
17
|
+
- **Public IPv4 mode**: use the VPS public IPv4 address directly. The plugin uses Certbot to request a roughly six-day Let's Encrypt IP certificate and installs a daily renewal timer. Documentation ranges such as `203.0.113.10`, private addresses, and other reserved addresses are rejected; enter a real routable public IP.
|
|
18
|
+
|
|
19
|
+
The custom remote-origin flow requires Android app 0.3.3 or later. Older supported apps continue to work with LAN, cpolar, and Tailscale.
|
|
20
|
+
|
|
21
|
+
## Manual deployment vs automatic deployment
|
|
22
|
+
|
|
23
|
+
- **Manual deployment**: copy the restricted template from the panel. Save the frps section as `/etc/dsh-mobile/frps.toml`, save the Caddy snippet as `/etc/caddy/dsh-mobile-dsh.caddy`, and add exactly this line to the main Caddyfile: `import /etc/caddy/dsh-mobile-dsh.caddy`. If the Caddyfile does not exist, create one containing only that line. Copying the template changes nothing by itself. Public IPv4 mode also requires the Certbot steps in the template because Caddy cannot issue an IP certificate; domain mode is automatic.
|
|
24
|
+
- **Automatic deployment**: enter an SSH user, port, and local private-key path (leave the path empty to use ssh-agent or SSH configuration), then select the one-click deployment action. The VPS must run Ubuntu or Debian with systemd. Only key-based login is accepted; passwords are not supported.
|
|
25
|
+
|
|
26
|
+
Before deployment, the panel lists every VPS change. It installs Caddy from its official APT source; public IPv4 mode additionally installs a Python virtual environment, Certbot, and the renewal timer. It creates or reuses the `dsh-mobile` system user, the frps service and configuration, the Caddy snippet and one import line, and—when UFW is active—allows the FRP control port plus 80/tcp and 443/tcp. **Your existing Caddy content is never merged or overwritten**: an existing DSH Mobile import is only normalized to one line; another non-empty configuration stops the deployment and asks you to add the import manually.
|
|
27
|
+
|
|
28
|
+
## Verify the host keys every time
|
|
29
|
+
|
|
30
|
+
Automatic deployment and one-click cleanup read the VPS host keys before opening an authenticated SSH connection:
|
|
31
|
+
|
|
32
|
+
1. Select deployment or cleanup. The panel shows the current `KEYTYPE SHA256:…` fingerprints.
|
|
33
|
+
2. Compare every fingerprint with the VPS provider console or the information supplied when the server was created.
|
|
34
|
+
3. Continue only when every key matches. Cancel when a key cannot be verified. The plugin never accepts an unknown host key silently, and a key change during the operation aborts it.
|
|
35
|
+
|
|
36
|
+
The SSH user, port, and private-key path are kept only in this browser's `localStorage` under `dsh-mobile.frp-vps-form.v1` for convenience. The shared token never enters `localStorage`, and the private-key file is never uploaded.
|
|
37
|
+
|
|
38
|
+
## Clean up the VPS
|
|
39
|
+
|
|
40
|
+
The local **Remove FRP completely** action removes only the computer's managed frpc, token, and configuration; it does not touch the VPS. Server cleanup has two equivalent paths, and both remove only DSH Mobile-owned files, services, and tagged firewall rules:
|
|
41
|
+
|
|
42
|
+
1. **Copy the uninstall script**: select **Copy VPS uninstall script**, review it, and run it as root on the VPS. The script stops and removes the frps service and certificate-renewal timer, deletes DSH Mobile configuration, binaries, certificates, and the Caddy snippet, removes the import line from the main Caddyfile while preserving your content, and removes UFW rules carrying the DSH Mobile marker. It deletes the `dsh-mobile` system user only when this deployment created it; an existing user is kept and reported.
|
|
43
|
+
2. **One-click cleanup**: select **Remove DSH Mobile from the VPS**. The panel verifies the host keys again and runs the same script over pinned SSH after confirmation.
|
|
44
|
+
|
|
45
|
+
Public IPv4 mode also removes the corresponding Let's Encrypt IP certificate. Domain-mode certificates remain managed by Caddy.
|
|
46
|
+
|
|
47
|
+
## Operations and troubleshooting
|
|
48
|
+
|
|
49
|
+
On the VPS:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
sudo systemctl status dsh-mobile-frps.service caddy dsh-mobile-cert-renew.timer
|
|
53
|
+
sudo journalctl -u dsh-mobile-frps.service -u caddy -n 200 --no-pager
|
|
54
|
+
sudo ss -lntp
|
|
55
|
+
curl -vk https://PUBLIC_HOST/
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
On the computer, start with the plugin log at `$DSH_HOME/mobile-access/logs/dsh-mobile.log` (JSONL, 5 MB rotation, tokens and keys redacted) and the panel diagnostic report. Windows antivirus software can quarantine frpc; if it does, create the smallest possible exception for the verified component directory only.
|
|
59
|
+
|
|
60
|
+
## Limits
|
|
61
|
+
|
|
62
|
+
- An unregistered domain on a mainland-China VPS may be intercepted by the cloud provider; use public IPv4 mode in that case.
|
|
63
|
+
- An IPv4 certificate is short-lived; keep its renewal timer and Caddy service running.
|
|
64
|
+
- SSH form values are browser-profile state. Changing browsers or clearing site data requires entering them again; private keys and passwords are never stored.
|
|
65
|
+
- VPS SSH targets currently cannot use IPv6.
|
|
66
|
+
- The frps plaintext vhost must bind to `127.0.0.1`. The plugin rejects a publicly reachable plaintext port and reports readiness only after public discovery identifies the current computer.
|
|
67
|
+
|
|
68
|
+
## Manual end-to-end checklist (before release)
|
|
69
|
+
|
|
70
|
+
- [x] Ubuntu IP mode: one-click redeploy on a VPS → public IPv4 ready → App discovery returned this computer (2026-09-03, Tencent Cloud).
|
|
71
|
+
- [ ] Ubuntu domain mode: fresh VPS deployment → public domain ready → App pairing → send and receive messages.
|
|
72
|
+
- [x] Existing Caddy coexistence: deploy into a Caddyfile containing an existing site and import line; verify user content is byte-for-byte preserved, the import occurs exactly once, and validation passes (2026-09-03, Tencent Cloud; concurrent writes use `flock`).
|
|
73
|
+
- [x] Host-key change abort: an unconfirmed key set stops deployment/cleanup with `vps_host_key_mismatch` before network authentication (unit-test coverage plus full device fingerprint review).
|
|
74
|
+
- [x] One-click cleanup: after deployment, services, files, timers, marked firewall rules, the owned system user, and the LE certificate were removed while the user's Caddy installation remained (2026-09-03, Tencent Cloud).
|
|
75
|
+
- [x] Uninstall-script review: only DSH Mobile-owned paths and rules are touched (unit assertions plus device review).
|
package/docs/SELF_HOSTED_FRP.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# 自建 FRP 使用指南
|
|
2
2
|
|
|
3
|
+
[English guide](SELF_HOSTED_FRP.en.md)
|
|
4
|
+
|
|
3
5
|
自建 FRP 适合已有 VPS、希望避开公共隧道带宽限制的用户。手机经 VPS 上的 Caddy 进入加密 FRP 隧道,再到达电脑上的 DSH;FRP 只负责传输,仍需完成 DSH 配对才能进入。
|
|
4
6
|
|
|
5
7
|
```text
|
|
@@ -23,7 +25,7 @@
|
|
|
23
25
|
- **手动部署**:在面板复制受限模板,把 frps 部分存为 `/etc/dsh-mobile/frps.toml`,把 Caddy 片段存为 `/etc/caddy/dsh-mobile-dsh.caddy`,并确保主 Caddyfile 里有且仅需这一行:`import /etc/caddy/dsh-mobile-dsh.caddy`(没有 Caddyfile 就新建一个只写这一行)。复制操作本身不改变任何东西。公网 IPv4 还需要按模板里的注释步骤用 Certbot 申请一次 IP 证书(Caddy 自己签发不了 IP 证书);域名模式 Caddy 全自动。
|
|
24
26
|
- **自动部署**:填写 SSH 用户、端口和本机私钥路径(留空则用 ssh-agent 或 SSH 配置),点击一键部署。要求 Ubuntu/Debian + systemd,只接受密钥登录,不接受密码。
|
|
25
27
|
|
|
26
|
-
点部署按钮前,面板会列出自动部署将在 VPS 上做的全部改动:从官方 APT 源安装 Caddy
|
|
28
|
+
点部署按钮前,面板会列出自动部署将在 VPS 上做的全部改动:从官方 APT 源安装 Caddy;仅在公网 IPv4 模式安装 Python venv、Certbot 和证书续期定时器;创建 `dsh-mobile` 系统用户(已存在则复用,卸载时保留)、frps 配置与服务、Caddy 片段和主文件里的一行 import;如果 UFW 已启用,则放行 FRP 控制端口与 80/443。**主 Caddyfile 里你自己的内容永远不会被改写或合并**:没有 Caddyfile、空文件或官方默认文件时才写入这一行 import;已有 DSH Mobile import 时只整理为一行,其他非空配置会停止部署并告诉你手动加这一行。
|
|
27
29
|
|
|
28
30
|
## 主机指纹核对(每次必做)
|
|
29
31
|
|
package/lib/cli.js
CHANGED
|
@@ -96,6 +96,8 @@ const VIRTUAL_INTERFACE_MARKERS = [
|
|
|
96
96
|
"wsl",
|
|
97
97
|
"zerotier"
|
|
98
98
|
];
|
|
99
|
+
/** Route inspection is advisory; never let a system command hold setup open indefinitely. */
|
|
100
|
+
const ROUTE_COMMAND_TIMEOUT_MS = 5e3;
|
|
99
101
|
function privateIpv4(value) {
|
|
100
102
|
const parts = value.split(".").map(Number);
|
|
101
103
|
return parts.length === 4 && parts.every((part) => Number.isInteger(part) && part >= 0 && part <= 255) && (parts[0] === 10 || parts[0] === 172 && parts[1] >= 16 && parts[1] <= 31 || parts[0] === 192 && parts[1] === 168);
|
|
@@ -126,7 +128,7 @@ function likelyVirtualInterface(name) {
|
|
|
126
128
|
async function runRouteCommand(file, args) {
|
|
127
129
|
return (await execFileText(file, [...args], {
|
|
128
130
|
encoding: "utf8",
|
|
129
|
-
|
|
131
|
+
timeout: ROUTE_COMMAND_TIMEOUT_MS
|
|
130
132
|
})).stdout;
|
|
131
133
|
}
|
|
132
134
|
function uniqueLines(output) {
|