dsh-remote-hub 0.2.1 → 0.2.2
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/README.md +3 -3
- package/lib/index.js +1 -1
- package/lib/pairing-routes.js +16 -7
- package/lib/supervisor.js +6 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -19,9 +19,9 @@ Kotlin/Compose 直连 DSH 自带的 HTTP API + WebSocket 网关。
|
|
|
19
19
|
|
|
20
20
|
## 下载手机端 App
|
|
21
21
|
|
|
22
|
-
**DSH Remote v4.
|
|
22
|
+
**DSH Remote v4.20.0** · Android 8.0 (API 26) 及以上 · 2.8 MB
|
|
23
23
|
|
|
24
|
-
[⬇️ 下载 APK](https://github.com/liaoguogang-hub/dsh-remote-public/releases/download/v4.
|
|
24
|
+
[⬇️ 下载 APK](https://github.com/liaoguogang-hub/dsh-remote-public/releases/download/v4.20.0/DSH-Remote-v4.20.0.apk) ·
|
|
25
25
|
[全部版本](https://github.com/liaoguogang-hub/dsh-remote-public/releases)
|
|
26
26
|
|
|
27
27
|
安装后应用名「DSH Remote」,包名 `com.dsh.remote.ngrok`(可与作者的 `DSH` 自用版共存)。
|
|
@@ -233,7 +233,7 @@ dsh-remote qr
|
|
|
233
233
|
浏览器会打开 `http://127.0.0.1:6300/_dsh-remote/pair`,显示一个二维码。手机 DSH Remote 里点
|
|
234
234
|
「扫码配对」,扫完自动填入地址并换取登录凭据,直接连上。
|
|
235
235
|
|
|
236
|
-
|
|
236
|
+
扫码一次会同时写入「局域网」和「ngrok」两档地址;连接时优先局域网(同 WiFi 最快),局域网不通才走 ngrok。扫码后即保存,之后不用再扫。
|
|
237
237
|
|
|
238
238
|
安全设计:
|
|
239
239
|
- 二维码里**不含 Cookie**,只含一个 **10 分钟有效的一次性配对码**(`{"v":1,"u":"<地址>","c":"<配对码>","e":<过期时间>}`);
|
package/lib/index.js
CHANGED
|
@@ -16,7 +16,7 @@ import { start } from './supervisor.js'
|
|
|
16
16
|
|
|
17
17
|
export const name = 'dsh-remote-hub'
|
|
18
18
|
|
|
19
|
-
export const version = '0.2.
|
|
19
|
+
export const version = '0.2.2'
|
|
20
20
|
|
|
21
21
|
/** No host services are required: the plugin only needs Node builtins. */
|
|
22
22
|
export const inject = []
|
package/lib/pairing-routes.js
CHANGED
|
@@ -15,9 +15,15 @@ import QRCode from 'qrcode'
|
|
|
15
15
|
|
|
16
16
|
export const PAIR_PREFIX = '/_dsh-remote/pair'
|
|
17
17
|
|
|
18
|
-
/**
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
/**
|
|
19
|
+
* Build the payload the phone parses.
|
|
20
|
+
*
|
|
21
|
+
* Both addresses are shipped together so one scan can fill both tabs and the phone can pick the
|
|
22
|
+
* fastest one at connect time: `l` = LAN (private address), `u` = public tunnel. Either may be null
|
|
23
|
+
* when that transport is unavailable that moment.
|
|
24
|
+
*/
|
|
25
|
+
export function buildPairPayload({ lan, publicUrl, code, expiresAt }) {
|
|
26
|
+
return JSON.stringify({ v: 1, l: lan ?? null, u: publicUrl ?? null, c: code, e: expiresAt })
|
|
21
27
|
}
|
|
22
28
|
|
|
23
29
|
/**
|
|
@@ -67,7 +73,10 @@ export async function handlePairing({ req, res, current, store }) {
|
|
|
67
73
|
res.end(
|
|
68
74
|
JSON.stringify({
|
|
69
75
|
ok: true,
|
|
70
|
-
url
|
|
76
|
+
// `url` keeps the old single-address shape working; new clients read lan/public.
|
|
77
|
+
url: snapshot.public ?? snapshot.lan ?? null,
|
|
78
|
+
lan: snapshot.lan ?? null,
|
|
79
|
+
public: snapshot.public ?? null,
|
|
71
80
|
cookie: result.cookie,
|
|
72
81
|
issuedAt: result.issuedAt,
|
|
73
82
|
}),
|
|
@@ -77,7 +86,7 @@ export async function handlePairing({ req, res, current, store }) {
|
|
|
77
86
|
|
|
78
87
|
// Any other GET under the prefix hands out a fresh code.
|
|
79
88
|
const { code, expiresAt, ttlMs } = store.issue(snapshot.cookie)
|
|
80
|
-
const payload = buildPairPayload({
|
|
89
|
+
const payload = buildPairPayload({ lan: snapshot.lan, publicUrl: snapshot.public, code, expiresAt })
|
|
81
90
|
|
|
82
91
|
if (url === PAIR_PREFIX + '/svg') {
|
|
83
92
|
const svg = await QRCode.toString(payload, { type: 'svg', margin: 1, width: 320, errorCorrectionLevel: 'M' })
|
|
@@ -110,8 +119,8 @@ export async function handlePairing({ req, res, current, store }) {
|
|
|
110
119
|
<p>配对码 <code>${code}</code> · ${minutes} 分钟内有效,且只能用一次</p>
|
|
111
120
|
<div class="qr">${svg}</div>
|
|
112
121
|
<p class="ok">扫码后自动填入地址并换取登录凭据</p>
|
|
113
|
-
<p class="addr"
|
|
114
|
-
<p class="addr"
|
|
122
|
+
<p class="addr">${snapshot.lan ? `局域网:${snapshot.lan}<br>` : ''}${snapshot.public ? `公网:${snapshot.public}` : ''}</p>
|
|
123
|
+
<p class="addr">扫一次会同时存下局域网与公网地址,之后自动优先走局域网</p>
|
|
115
124
|
</div></body></html>`
|
|
116
125
|
res.writeHead(200, { 'content-type': 'text/html; charset=utf-8', 'cache-control': 'no-store' })
|
|
117
126
|
res.end(html)
|
package/lib/supervisor.js
CHANGED
|
@@ -164,9 +164,12 @@ export async function start(config = {}) {
|
|
|
164
164
|
const pairingStore = createPairingStore()
|
|
165
165
|
const pairing = {
|
|
166
166
|
store: pairingStore,
|
|
167
|
-
//
|
|
168
|
-
|
|
169
|
-
|
|
167
|
+
// Read at redeem time so a tunnel URL that appears later is still handed to the phone.
|
|
168
|
+
current: () => ({
|
|
169
|
+
lan: ipForPairing ? `http://${ipForPairing}:${Number(port) || 6300}` : null,
|
|
170
|
+
public: lastPublicUrl ?? null,
|
|
171
|
+
cookie,
|
|
172
|
+
}),
|
|
170
173
|
}
|
|
171
174
|
|
|
172
175
|
const ipForPairing = lanAddress()
|
package/package.json
CHANGED