dsh-zen-remote 1.1.16 → 2.0.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/AGENTS.md +54 -9
- package/README.md +249 -190
- package/README.zh-CN.md +247 -201
- package/assets/home.png +0 -0
- package/assets/info.png +0 -0
- package/assets/pairing.png +0 -0
- package/assets/session.png +0 -0
- package/assets/sheet.png +0 -0
- package/cordis.patch.yml +12 -11
- package/cordis.patch.yml.example +24 -9
- package/docs/interface.md +57 -2
- package/docs/remote-access.en.md +99 -58
- package/docs/remote-access.md +99 -42
- package/dsh-push.mjs +67 -54
- package/lan-gate.mjs +88 -20
- package/lib/activity.js +168 -0
- package/lib/activity.js.map +1 -0
- package/lib/admin-routes.js +526 -0
- package/lib/admin-routes.js.map +1 -0
- package/lib/client-pairing.js +224 -0
- package/lib/client-pairing.js.map +1 -0
- package/lib/client-routes.js +674 -0
- package/lib/client-routes.js.map +1 -0
- package/lib/client.js +10051 -4777
- package/lib/config.js +346 -0
- package/lib/config.js.map +1 -0
- package/lib/fetch-route-intercept.js +418 -0
- package/lib/fetch-route-intercept.js.map +1 -0
- package/lib/fingerprint.js +363 -0
- package/lib/fingerprint.js.map +1 -0
- package/lib/http.js +69 -0
- package/lib/http.js.map +1 -0
- package/lib/index.js +675 -54
- package/lib/index.js.map +1 -1
- package/lib/intercept-shape.js +81 -0
- package/lib/intercept-shape.js.map +1 -0
- package/lib/intercept.js +3040 -0
- package/lib/intercept.js.map +1 -0
- package/lib/lan-gate-server.cjs +532 -121
- package/lib/merge-streams.js +1165 -0
- package/lib/merge-streams.js.map +1 -0
- package/lib/relay-access.js +496 -0
- package/lib/relay-access.js.map +1 -0
- package/lib/relay-client.js +1303 -0
- package/lib/relay-client.js.map +1 -0
- package/lib/relay-filter.js +282 -0
- package/lib/relay-filter.js.map +1 -0
- package/lib/relay-server.js +1792 -0
- package/lib/relay-server.js.map +1 -0
- package/lib/restart-fields.js +34 -0
- package/lib/restart-fields.js.map +1 -0
- package/lib/restart-watcher.js +106 -0
- package/lib/restart-watcher.js.map +1 -0
- package/lib/session-reference.js +157 -0
- package/lib/session-reference.js.map +1 -0
- package/lib/share-export.js +16 -1
- package/lib/share-export.js.map +1 -1
- package/lib/share-ops.js +86 -0
- package/lib/share-ops.js.map +1 -0
- package/lib/share-store.js +294 -0
- package/lib/share-store.js.map +1 -0
- package/lib/types/activity.d.ts +99 -0
- package/lib/types/activity.d.ts.map +1 -0
- package/lib/types/admin-routes.d.ts +129 -0
- package/lib/types/admin-routes.d.ts.map +1 -0
- package/lib/types/client/MobileDrawerFooter.d.ts.map +1 -1
- package/lib/types/client/MobileHome.d.ts +1 -1
- package/lib/types/client/MobileHome.d.ts.map +1 -1
- package/lib/types/client/MobileHomeChips.d.ts +1 -1
- package/lib/types/client/MobileHomeChips.d.ts.map +1 -1
- package/lib/types/client/MobileSessionHeader.d.ts +13 -2
- package/lib/types/client/MobileSessionHeader.d.ts.map +1 -1
- package/lib/types/client/MobileSessionInfo.d.ts +20 -3
- package/lib/types/client/MobileSessionInfo.d.ts.map +1 -1
- package/lib/types/client/RemoteComposerBanner.d.ts +42 -0
- package/lib/types/client/RemoteComposerBanner.d.ts.map +1 -0
- package/lib/types/client/RemoteHeaderIcon.d.ts +37 -0
- package/lib/types/client/RemoteHeaderIcon.d.ts.map +1 -0
- package/lib/types/client/RemoteShareMenu.d.ts +28 -0
- package/lib/types/client/RemoteShareMenu.d.ts.map +1 -0
- package/lib/types/client/RemoteStatusIcon.d.ts +36 -0
- package/lib/types/client/RemoteStatusIcon.d.ts.map +1 -0
- package/lib/types/client/compat/desktop.d.ts +21 -0
- package/lib/types/client/compat/desktop.d.ts.map +1 -0
- package/lib/types/client/compat/types.d.ts +57 -0
- package/lib/types/client/compat/types.d.ts.map +1 -1
- package/lib/types/client/current-session-report.d.ts +37 -0
- package/lib/types/client/current-session-report.d.ts.map +1 -0
- package/lib/types/client/effects/header-status.d.ts.map +1 -1
- package/lib/types/client/effects/keyboard-guard.d.ts.map +1 -1
- package/lib/types/client/effects/permission-sheet.d.ts +39 -0
- package/lib/types/client/effects/permission-sheet.d.ts.map +1 -0
- package/lib/types/client/effects/remote-session.d.ts +25 -0
- package/lib/types/client/effects/remote-session.d.ts.map +1 -0
- package/lib/types/client/effects/turn-fold.d.ts +9 -0
- package/lib/types/client/effects/turn-fold.d.ts.map +1 -1
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/client/locales.d.ts +187 -2
- package/lib/types/client/locales.d.ts.map +1 -1
- package/lib/types/client/remote-fetch.d.ts +51 -0
- package/lib/types/client/remote-fetch.d.ts.map +1 -0
- package/lib/types/client/remote-group-expansion.d.ts +41 -0
- package/lib/types/client/remote-group-expansion.d.ts.map +1 -0
- package/lib/types/client/remote-share-css.d.ts +19 -0
- package/lib/types/client/remote-share-css.d.ts.map +1 -0
- package/lib/types/client/remote-share-register.d.ts +113 -0
- package/lib/types/client/remote-share-register.d.ts.map +1 -0
- package/lib/types/client/remote-status-css.d.ts +15 -0
- package/lib/types/client/remote-status-css.d.ts.map +1 -0
- package/lib/types/client/remote-status-register.d.ts +46 -0
- package/lib/types/client/remote-status-register.d.ts.map +1 -0
- package/lib/types/client/settings/SettingsSection.d.ts +46 -0
- package/lib/types/client/settings/SettingsSection.d.ts.map +1 -0
- package/lib/types/client/settings/register-settings.d.ts +58 -0
- package/lib/types/client/settings/register-settings.d.ts.map +1 -0
- package/lib/types/client/settings/settings-css.d.ts +10 -0
- package/lib/types/client/settings/settings-css.d.ts.map +1 -0
- package/lib/types/client/share/share-preview.d.ts.map +1 -1
- package/lib/types/client/styles/composer.css.d.ts +1 -1
- package/lib/types/client/styles/composer.css.d.ts.map +1 -1
- package/lib/types/client/styles/header.css.d.ts +1 -1
- package/lib/types/client/styles/header.css.d.ts.map +1 -1
- package/lib/types/client/styles/info.css.d.ts +1 -1
- package/lib/types/client/styles/info.css.d.ts.map +1 -1
- package/lib/types/client/styles/remote-session.css.d.ts +2 -0
- package/lib/types/client/styles/remote-session.css.d.ts.map +1 -0
- package/lib/types/client-data/current-session.d.ts +41 -0
- package/lib/types/client-data/current-session.d.ts.map +1 -0
- package/lib/types/client-data/remote-group-expansion.d.ts +76 -0
- package/lib/types/client-data/remote-group-expansion.d.ts.map +1 -0
- package/lib/types/client-data/remote-status.d.ts +148 -0
- package/lib/types/client-data/remote-status.d.ts.map +1 -0
- package/lib/types/client-data/settings-form.d.ts +774 -0
- package/lib/types/client-data/settings-form.d.ts.map +1 -0
- package/lib/types/client-data/shares.d.ts +211 -0
- package/lib/types/client-data/shares.d.ts.map +1 -0
- package/lib/types/client-pairing.d.ts +114 -0
- package/lib/types/client-pairing.d.ts.map +1 -0
- package/lib/types/client-routes.d.ts +112 -0
- package/lib/types/client-routes.d.ts.map +1 -0
- package/lib/types/config.d.ts +200 -0
- package/lib/types/config.d.ts.map +1 -0
- package/lib/types/fetch-route-intercept.d.ts +156 -0
- package/lib/types/fetch-route-intercept.d.ts.map +1 -0
- package/lib/types/fingerprint.d.ts +164 -0
- package/lib/types/fingerprint.d.ts.map +1 -0
- package/lib/types/http.d.ts +41 -0
- package/lib/types/http.d.ts.map +1 -0
- package/lib/types/index.d.ts +56 -24
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/intercept-shape.d.ts +32 -0
- package/lib/types/intercept-shape.d.ts.map +1 -0
- package/lib/types/intercept.d.ts +432 -0
- package/lib/types/intercept.d.ts.map +1 -0
- package/lib/types/merge-streams.d.ts +393 -0
- package/lib/types/merge-streams.d.ts.map +1 -0
- package/lib/types/relay-access.d.ts +310 -0
- package/lib/types/relay-access.d.ts.map +1 -0
- package/lib/types/relay-client.d.ts +274 -0
- package/lib/types/relay-client.d.ts.map +1 -0
- package/lib/types/relay-filter.d.ts +103 -0
- package/lib/types/relay-filter.d.ts.map +1 -0
- package/lib/types/relay-server.d.ts +208 -0
- package/lib/types/relay-server.d.ts.map +1 -0
- package/lib/types/restart-fields.d.ts +22 -0
- package/lib/types/restart-fields.d.ts.map +1 -0
- package/lib/types/restart-watcher.d.ts +83 -0
- package/lib/types/restart-watcher.d.ts.map +1 -0
- package/lib/types/session-reference.d.ts +66 -0
- package/lib/types/session-reference.d.ts.map +1 -0
- package/lib/types/share-export.d.ts +14 -1
- package/lib/types/share-export.d.ts.map +1 -1
- package/lib/types/share-ops.d.ts +79 -0
- package/lib/types/share-ops.d.ts.map +1 -0
- package/lib/types/share-store.d.ts +87 -0
- package/lib/types/share-store.d.ts.map +1 -0
- package/lib/types/virtual-id.d.ts +38 -0
- package/lib/types/virtual-id.d.ts.map +1 -0
- package/lib/virtual-id.js +52 -0
- package/lib/virtual-id.js.map +1 -0
- package/llms.txt +17 -14
- package/package.json +60 -50
- package/scripts/build-client.mjs +5 -3
- package/scripts/check-host-shadow.mjs +19 -2
- package/scripts/check-settings-form.mjs +933 -0
- package/scripts/check-shares.mjs +397 -0
- package/scripts/check-upload-endpoint.mjs +59 -3
- package/scripts/sync-doc-version.mjs +8 -15
- package/scripts/verify-fingerprint-live.mjs +111 -0
- package/src/activity.ts +218 -0
- package/src/admin-routes.ts +627 -0
- package/src/client/MobileAttachButton.tsx +2 -2
- package/src/client/MobileAttachChips.tsx +3 -3
- package/src/client/MobileDrawerFooter.tsx +7 -4
- package/src/client/MobileHome.tsx +20 -16
- package/src/client/MobileHomeChips.tsx +16 -16
- package/src/client/MobileNavOverlay.tsx +2 -2
- package/src/client/MobileNavToggle.tsx +3 -3
- package/src/client/MobileSessionHeader.tsx +63 -42
- package/src/client/MobileSessionInfo.tsx +118 -17
- package/src/client/RemoteComposerBanner.tsx +76 -0
- package/src/client/RemoteHeaderIcon.tsx +103 -0
- package/src/client/RemoteShareMenu.tsx +57 -0
- package/src/client/RemoteStatusIcon.tsx +91 -0
- package/src/client/compat/desktop.ts +22 -0
- package/src/client/compat/types.ts +62 -0
- package/src/client/current-session-report.ts +164 -0
- package/src/client/effects/header-status.ts +21 -17
- package/src/client/effects/keyboard-guard.ts +65 -1
- package/src/client/effects/permission-sheet.ts +149 -0
- package/src/client/effects/remote-session.ts +68 -0
- package/src/client/effects/turn-fold.ts +52 -0
- package/src/client/index.tsx +151 -36
- package/src/client/locales.ts +396 -2
- package/src/client/remote-fetch.ts +125 -0
- package/src/client/remote-group-expansion.ts +190 -0
- package/src/client/remote-share-css.ts +54 -0
- package/src/client/remote-share-register.ts +244 -0
- package/src/client/remote-status-css.ts +64 -0
- package/src/client/remote-status-register.ts +107 -0
- package/src/client/settings/SettingsSection.tsx +1229 -0
- package/src/client/settings/register-settings.ts +116 -0
- package/src/client/settings/settings-css.ts +236 -0
- package/src/client/share/share-preview.tsx +6 -3
- package/src/client/share/share-sheet.tsx +3 -3
- package/src/client/styles/composer.css.ts +119 -26
- package/src/client/styles/header.css.ts +7 -7
- package/src/client/styles/info.css.ts +74 -0
- package/src/client/styles/remote-session.css.ts +251 -0
- package/src/client-data/current-session.ts +57 -0
- package/src/client-data/remote-group-expansion.ts +145 -0
- package/src/client-data/remote-status.ts +374 -0
- package/src/client-data/settings-form.ts +1371 -0
- package/src/client-data/shares.ts +467 -0
- package/src/client-pairing.ts +244 -0
- package/src/client-routes.ts +732 -0
- package/src/config.ts +447 -0
- package/src/fetch-route-intercept.ts +510 -0
- package/src/fingerprint.ts +408 -0
- package/src/http.ts +68 -0
- package/src/index.ts +719 -62
- package/src/intercept-shape.ts +87 -0
- package/src/intercept.ts +3362 -0
- package/src/merge-streams.ts +1272 -0
- package/src/relay-access.ts +669 -0
- package/src/relay-client.ts +1514 -0
- package/src/relay-filter.ts +291 -0
- package/src/relay-server.ts +2025 -0
- package/src/restart-fields.ts +36 -0
- package/src/restart-watcher.ts +140 -0
- package/src/session-reference.ts +156 -0
- package/src/share-export.ts +26 -1
- package/src/share-ops.ts +114 -0
- package/src/share-store.ts +373 -0
- package/src/virtual-id.ts +59 -0
|
@@ -0,0 +1,526 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin routes for the 2.0.0 settings surface (T14): pairing, device
|
|
3
|
+
* management and a push test, driven from the DSH plugin page's settings
|
|
4
|
+
* block (the T15 client half) instead of the gateway's own admin page.
|
|
5
|
+
*
|
|
6
|
+
* Why these live in the HOST process rather than the gateway: the gateway's
|
|
7
|
+
* admin API is loopback-only by design (isLocalDirect — loopback peer, no
|
|
8
|
+
* X-Forwarded-* headers), while a browser page runs on DSH's origin, never
|
|
9
|
+
* on the gateway's. So the browser talks to THESE same-origin routes and
|
|
10
|
+
* this module then calls the gateway AS the local machine — a bare
|
|
11
|
+
* `http://127.0.0.1:<port>` request with hand-built headers (no cookies, no
|
|
12
|
+
* Origin, no forwarded anything) that `isLocalDirect` admits.
|
|
13
|
+
*
|
|
14
|
+
* Two walls every route applies, in order:
|
|
15
|
+
*
|
|
16
|
+
* 1. `admit` — routes registered via webServer.register do NOT pass
|
|
17
|
+
* through DSH's `/api` authentication, so each request must ask the
|
|
18
|
+
* connection service itself; its rejection is relayed verbatim.
|
|
19
|
+
* 2. The gateway marker. A request wearing `x-zen-remote-via` arrived
|
|
20
|
+
* THROUGH the gateway from a remote device (the gateway strips
|
|
21
|
+
* client-forged copies before stamping its own). POSTs are refused —
|
|
22
|
+
* pairing and device management are server-side acts. GET status is
|
|
23
|
+
* answered, but with the live pairing code stripped. The marker wall
|
|
24
|
+
* runs BEFORE same-origin because a forwarded request presents as
|
|
25
|
+
* same-origin (the gateway rewrites Origin/Host), so the marker is the
|
|
26
|
+
* only thing identifying it.
|
|
27
|
+
*
|
|
28
|
+
* The ONE deliberate exception is the shares route (T33a): toggling session
|
|
29
|
+
* sharing is exactly what the spec grants the Web application端 (devices
|
|
30
|
+
* behind the gateway have full server permissions), so there the marker wall
|
|
31
|
+
* is skipped and a forwarded POST passes once it clears admit and
|
|
32
|
+
* same-origin. Desktop application clients can never reach any admin route —
|
|
33
|
+
* the gateway only forwards them into the relay prefix.
|
|
34
|
+
*
|
|
35
|
+
* Every POST additionally passes sameOriginPost, and bodies are capped at
|
|
36
|
+
* 16 KiB of JSON object. The handler is built by a factory so the tests can
|
|
37
|
+
* drive it over a real socket with a mock gateway and a mock admit.
|
|
38
|
+
*/
|
|
39
|
+
import { request as httpRequest } from 'node:http';
|
|
40
|
+
import { responseJson, sameOriginPost } from './http.js';
|
|
41
|
+
import { restoreBusy } from './share-ops.js';
|
|
42
|
+
/** Prefix all admin routes live under (one webServer prefix registration). */
|
|
43
|
+
export const ADMIN_ROUTE_PREFIX = '/_dsh/zen-remote/admin';
|
|
44
|
+
/** GET: the gateway's status verbatim plus the effective config; remote
|
|
45
|
+
* callers get the live pairing code stripped. */
|
|
46
|
+
export const ADMIN_STATUS_ROUTE = `${ADMIN_ROUTE_PREFIX}/status`;
|
|
47
|
+
/** POST `{role}`: mint a pairing code. */
|
|
48
|
+
export const ADMIN_PAIR_ROUTE = `${ADMIN_ROUTE_PREFIX}/pair`;
|
|
49
|
+
/** POST `{action, id?, role?, kind?, name?}`: device management, whitelist below. */
|
|
50
|
+
export const ADMIN_ACTION_ROUTE = `${ADMIN_ROUTE_PREFIX}/action`;
|
|
51
|
+
/** POST: fire one fixed test notification through the gateway. */
|
|
52
|
+
export const ADMIN_PUSH_TEST_ROUTE = `${ADMIN_ROUTE_PREFIX}/push-test`;
|
|
53
|
+
/** GET: every shared session with its clocks, viewers and titles.
|
|
54
|
+
* POST `{action, sessionId?}`: share / unshare / unshare-all (T33a). */
|
|
55
|
+
export const ADMIN_SHARES_ROUTE = `${ADMIN_ROUTE_PREFIX}/shares`;
|
|
56
|
+
/** Longest wait for one gateway round-trip. */
|
|
57
|
+
const GATEWAY_TIMEOUT_MS = 5000;
|
|
58
|
+
/** Inbound admin body cap — the settings forms send a few hundred bytes. */
|
|
59
|
+
const MAX_BODY_BYTES = 16 * 1024;
|
|
60
|
+
/** Tag every test notification carries, so the phone can spot and sweep them. */
|
|
61
|
+
const TEST_PUSH_TAG = 'dsh-zen-remote-test';
|
|
62
|
+
/** The device-management verbs this surface forwards. `new-code` is
|
|
63
|
+
* deliberately absent: minting codes is the pair route's job, and forwarding
|
|
64
|
+
* it twice would only blur which surface created the live code. */
|
|
65
|
+
const FORWARDABLE_ACTIONS = new Set(['set-role', 'set-kind', 'rename', 'revoke', 'revoke-all']);
|
|
66
|
+
/** The share-toggle verbs POST shares understands (T33a). */
|
|
67
|
+
const SHARE_ACTIONS = new Set(['share', 'unshare', 'unshare-all']);
|
|
68
|
+
/** Longest wait for one session/projections call (titles, share existence).
|
|
69
|
+
* A hung typert gateway must not hold a route open forever. */
|
|
70
|
+
const PROJECTION_TIMEOUT_MS = 5000;
|
|
71
|
+
/** Fixed test-push copy — Chinese by default, English for `lang: 'en'`
|
|
72
|
+
* (`'auto'` has no requester signal here, so it falls to Chinese). */
|
|
73
|
+
const TEST_PUSH_COPY = {
|
|
74
|
+
zh: { title: 'DSH 测试推送', body: '这是一条来自 dsh-zen-remote 设置页的测试通知' },
|
|
75
|
+
en: { title: 'DSH Test Push', body: 'This is a test notification from the dsh-zen-remote settings page' },
|
|
76
|
+
};
|
|
77
|
+
/**
|
|
78
|
+
* One rejection carrying the status the client should see.
|
|
79
|
+
*
|
|
80
|
+
* Fields are assigned in the body rather than declared as constructor
|
|
81
|
+
* parameter properties: check scripts import these modules through Node's
|
|
82
|
+
* strip-only type stripping, which rejects that syntax (same reason as
|
|
83
|
+
* UploadError in index.ts).
|
|
84
|
+
*/
|
|
85
|
+
class AdminError extends Error {
|
|
86
|
+
status;
|
|
87
|
+
code;
|
|
88
|
+
constructor(status, code, message) {
|
|
89
|
+
super(message);
|
|
90
|
+
this.name = 'AdminError';
|
|
91
|
+
this.status = status;
|
|
92
|
+
this.code = code;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Read the whole body under the cap and demand one JSON object. An empty
|
|
97
|
+
* body counts as `{}` — the gateway's own reader treats absence the same
|
|
98
|
+
* way, and the push-test button posts no body at all.
|
|
99
|
+
*/
|
|
100
|
+
async function readJsonBody(req) {
|
|
101
|
+
// A declared oversized body is refused before a byte is read, so the client
|
|
102
|
+
// gets its 400 without the server (or the phone) spending the whole body on
|
|
103
|
+
// the wire. The streaming cap below remains as the chunked-body guard.
|
|
104
|
+
const declared = req.headers['content-length'];
|
|
105
|
+
const expected = declared === undefined ? undefined : Number(declared);
|
|
106
|
+
if (expected !== undefined && Number.isSafeInteger(expected) && expected > MAX_BODY_BYTES) {
|
|
107
|
+
throw new AdminError(400, 'bad-request', `request body exceeds the ${MAX_BODY_BYTES}-byte limit`);
|
|
108
|
+
}
|
|
109
|
+
const chunks = [];
|
|
110
|
+
let size = 0;
|
|
111
|
+
for await (const chunk of req) {
|
|
112
|
+
const bytes = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
113
|
+
size += bytes.length;
|
|
114
|
+
if (size > MAX_BODY_BYTES) {
|
|
115
|
+
throw new AdminError(400, 'bad-request', `request body exceeds the ${MAX_BODY_BYTES}-byte limit`);
|
|
116
|
+
}
|
|
117
|
+
chunks.push(bytes);
|
|
118
|
+
}
|
|
119
|
+
const text = Buffer.concat(chunks).toString('utf8');
|
|
120
|
+
if (text.trim() === '')
|
|
121
|
+
return {};
|
|
122
|
+
let parsed;
|
|
123
|
+
try {
|
|
124
|
+
parsed = JSON.parse(text);
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
throw new AdminError(400, 'bad-request', 'request body must be valid JSON');
|
|
128
|
+
}
|
|
129
|
+
if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
130
|
+
throw new AdminError(400, 'bad-request', 'request body must be a JSON object');
|
|
131
|
+
}
|
|
132
|
+
return parsed;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* One call to the gateway AS the local machine: a fresh loopback connection
|
|
136
|
+
* with only the headers this call needs. No cookie, no Origin, and above all
|
|
137
|
+
* no X-Forwarded-* — any of those would make the gateway's isLocalDirect
|
|
138
|
+
* classify the call as proxied/remote and refuse the local-only surface.
|
|
139
|
+
* Resolves with whatever parsable JSON the gateway returned, at any status;
|
|
140
|
+
* deciding what that means for the route is the caller's job.
|
|
141
|
+
*/
|
|
142
|
+
async function callGateway(options, method, path, payload) {
|
|
143
|
+
const body = payload === undefined ? undefined : JSON.stringify(payload);
|
|
144
|
+
return await new Promise((resolve, reject) => {
|
|
145
|
+
const request = httpRequest(new URL(path, options.gatewayBase), {
|
|
146
|
+
method,
|
|
147
|
+
headers: body === undefined
|
|
148
|
+
? undefined
|
|
149
|
+
: { 'Content-Type': 'application/json; charset=utf-8', 'Content-Length': String(Buffer.byteLength(body)) },
|
|
150
|
+
signal: AbortSignal.timeout(options.timeoutMs ?? GATEWAY_TIMEOUT_MS),
|
|
151
|
+
}, (response) => {
|
|
152
|
+
const chunks = [];
|
|
153
|
+
response.on('data', (chunk) => {
|
|
154
|
+
chunks.push(chunk);
|
|
155
|
+
});
|
|
156
|
+
response.on('error', () => {
|
|
157
|
+
reject(new AdminError(502, 'gateway-unreachable', 'The gateway response failed'));
|
|
158
|
+
});
|
|
159
|
+
response.on('end', () => {
|
|
160
|
+
try {
|
|
161
|
+
resolve({ status: response.statusCode ?? 0, body: JSON.parse(Buffer.concat(chunks).toString('utf8')) });
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
reject(new AdminError(502, 'gateway-unreachable', 'The gateway returned an unparsable response'));
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
request.on('error', () => {
|
|
169
|
+
reject(new AdminError(502, 'gateway-unreachable', 'The gateway did not answer'));
|
|
170
|
+
});
|
|
171
|
+
request.end(body);
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* One gateway round-trip for a state-changing route. A 2xx reply relays to
|
|
176
|
+
* the browser verbatim; anything else becomes a 502 error envelope — the
|
|
177
|
+
* gateway DID answer, but with a refusal the settings page must not mistake
|
|
178
|
+
* for success (and must not see raw, since the envelope shape is ours).
|
|
179
|
+
*/
|
|
180
|
+
async function relay(options, method, path, payload, res) {
|
|
181
|
+
const reply = await callGateway(options, method, path, payload);
|
|
182
|
+
if (reply.status < 200 || reply.status >= 300) {
|
|
183
|
+
responseJson(res, 502, { ok: false, error: { code: 'gateway-error', status: reply.status } });
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
responseJson(res, reply.status, reply.body);
|
|
187
|
+
}
|
|
188
|
+
function testPushPayload(lang) {
|
|
189
|
+
return { ...(lang === 'en' ? TEST_PUSH_COPY.en : TEST_PUSH_COPY.zh), tag: TEST_PUSH_TAG };
|
|
190
|
+
}
|
|
191
|
+
/** GET status: the gateway payload plus the live config. Recomputed per
|
|
192
|
+
* request — volatile row fields (serverName, idleHours, …) change without a
|
|
193
|
+
* plugin restart, so an apply-time snapshot would go stale. */
|
|
194
|
+
async function respondStatus(options, req, res) {
|
|
195
|
+
const viaGateway = req.headers['x-zen-remote-via'] !== undefined;
|
|
196
|
+
const config = options.getConfig();
|
|
197
|
+
let gateway = null;
|
|
198
|
+
let gatewayStatus = null;
|
|
199
|
+
let gatewayReachable = false;
|
|
200
|
+
try {
|
|
201
|
+
const reply = await callGateway(options, 'GET', '/lan-gate/status');
|
|
202
|
+
gatewayStatus = reply.status;
|
|
203
|
+
// A parsable JSON reply is not automatically a healthy gateway: an error
|
|
204
|
+
// envelope (403, 500) must not surface as "reachable".
|
|
205
|
+
if (reply.status >= 200 && reply.status < 300) {
|
|
206
|
+
gateway = reply.body;
|
|
207
|
+
gatewayReachable = true;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
catch {
|
|
211
|
+
// No answer at all (refused, reset, timeout, non-JSON): gatewayStatus
|
|
212
|
+
// stays null and the settings page renders from config alone.
|
|
213
|
+
}
|
|
214
|
+
// A remote device may see the device list but never the live pairing code.
|
|
215
|
+
if (viaGateway && gateway !== null && typeof gateway === 'object') {
|
|
216
|
+
;
|
|
217
|
+
gateway.pairing = null;
|
|
218
|
+
}
|
|
219
|
+
responseJson(res, 200, { ok: true, gateway, gatewayReachable, gatewayStatus, config, viaGateway });
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* One call to the typert gateway's `session/projections`, under the per-call
|
|
223
|
+
* timeout. Every failure mode the route can survive is a VALUE here — only
|
|
224
|
+
* a transport failure or a timeout throws, and the caller decides what those
|
|
225
|
+
* mean (titles: null; existence: 502). The typert lookup runs INSIDE the
|
|
226
|
+
* guard: a throwing lookup is a degraded composition, not a route failure.
|
|
227
|
+
* The timeout rides the call's cancellation signal (`AbortSignal.timeout`,
|
|
228
|
+
* the same shape the relay passes into gateway calls), so a timed-out
|
|
229
|
+
* invocation is actually STOPPED, not merely abandoned by the waiter.
|
|
230
|
+
*/
|
|
231
|
+
async function projectionOf(options, sessionId) {
|
|
232
|
+
let gateway;
|
|
233
|
+
try {
|
|
234
|
+
gateway = options.typert?.();
|
|
235
|
+
}
|
|
236
|
+
catch {
|
|
237
|
+
return { kind: 'no-gateway' };
|
|
238
|
+
}
|
|
239
|
+
if (gateway === undefined)
|
|
240
|
+
return { kind: 'no-gateway' };
|
|
241
|
+
const value = await gateway.invoke({
|
|
242
|
+
namespace: 'session',
|
|
243
|
+
method: 'projections',
|
|
244
|
+
args: { request: { sessionId } },
|
|
245
|
+
signal: AbortSignal.timeout(options.projectionTimeoutMs ?? PROJECTION_TIMEOUT_MS),
|
|
246
|
+
});
|
|
247
|
+
if (value === null || value === undefined)
|
|
248
|
+
return { kind: 'no-session' };
|
|
249
|
+
const values = value.values;
|
|
250
|
+
return {
|
|
251
|
+
kind: 'values',
|
|
252
|
+
values: values !== null && typeof values === 'object' ? values : {},
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* One session title through `session/projections`. Anything other than a
|
|
257
|
+
* string answer — a null projection (session gone), a service-less or
|
|
258
|
+
* degraded composition, a transport failure, a timeout — is `null`, and one
|
|
259
|
+
* failed title must never fail the listing around it.
|
|
260
|
+
*/
|
|
261
|
+
async function titleOf(options, sessionId) {
|
|
262
|
+
try {
|
|
263
|
+
const outcome = await projectionOf(options, sessionId);
|
|
264
|
+
if (outcome.kind !== 'values')
|
|
265
|
+
return null;
|
|
266
|
+
const title = outcome.values.title;
|
|
267
|
+
return typeof title === 'string' ? title : null;
|
|
268
|
+
}
|
|
269
|
+
catch {
|
|
270
|
+
return null;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Prove a session exists before `share` enters it into the table, and hand
|
|
275
|
+
* back its projection values for the caller's follow-up checks. The same
|
|
276
|
+
* `session/projections` call the titles use, where a `null` projection IS
|
|
277
|
+
* the "no such live session" answer. A transport failure or timeout is NOT
|
|
278
|
+
* a null — it refuses with 502 rather than quietly sharing a session nobody
|
|
279
|
+
* could see. Without a typert gateway there is nothing to ask, and the table
|
|
280
|
+
* alone is the truth available (empty values, no objection).
|
|
281
|
+
*/
|
|
282
|
+
async function requireSession(options, sessionId) {
|
|
283
|
+
let outcome;
|
|
284
|
+
try {
|
|
285
|
+
outcome = await projectionOf(options, sessionId);
|
|
286
|
+
}
|
|
287
|
+
catch {
|
|
288
|
+
throw new AdminError(502, 'gateway-unreachable', 'The session lookup failed');
|
|
289
|
+
}
|
|
290
|
+
if (outcome.kind === 'no-gateway')
|
|
291
|
+
return {};
|
|
292
|
+
if (outcome.kind === 'no-session')
|
|
293
|
+
throw new AdminError(404, 'no-session', `no live session "${sessionId}"`);
|
|
294
|
+
return outcome.values;
|
|
295
|
+
}
|
|
296
|
+
/** Release one sessionQuery lease: the observation is a plain
|
|
297
|
+
* `Symbol.dispose` carrier (RT dsh-session-query SessionObservationReader —
|
|
298
|
+
* every lease pins a cold-cache entry until released). */
|
|
299
|
+
function releaseObservation(observation) {
|
|
300
|
+
const disposable = observation;
|
|
301
|
+
disposable[Symbol.dispose]?.();
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Whether the session is a subagent child, judged off the DURABLE HEADER
|
|
305
|
+
* first: `sessionQuery.observeSession` reads the live-or-persisted session's
|
|
306
|
+
* immutable header (released immediately), and `origin === 'subagent'` is
|
|
307
|
+
* authoritative — per dsh-session's `validateSessionHeader` that marker is
|
|
308
|
+
* the one subagent signal, and a header WITHOUT it is an ordinary session
|
|
309
|
+
* (top-level or fork), full stop.
|
|
310
|
+
*
|
|
311
|
+
* Why the header wins over the projection's `subagent` identity: a fork of a
|
|
312
|
+
* subagent session REPLAYS the source's `subagent/descriptor` events, so the
|
|
313
|
+
* projection would wrongly condemn an ordinary fork — while a child whose
|
|
314
|
+
* descriptor turned corrupt projects null and would slip through.
|
|
315
|
+
*
|
|
316
|
+
* The projection identity stays as the fallback for compositions without
|
|
317
|
+
* sessionQuery and for reads that fail (session gone between the two
|
|
318
|
+
* lookups, unreadable log) — degraded knowledge beats none.
|
|
319
|
+
*/
|
|
320
|
+
async function isSubagentSession(options, sessionId, projectionValues) {
|
|
321
|
+
let query;
|
|
322
|
+
try {
|
|
323
|
+
query = options.sessionQuery?.();
|
|
324
|
+
}
|
|
325
|
+
catch {
|
|
326
|
+
query = undefined;
|
|
327
|
+
}
|
|
328
|
+
if (query !== undefined) {
|
|
329
|
+
let observation;
|
|
330
|
+
try {
|
|
331
|
+
observation = await query.observeSession(sessionId);
|
|
332
|
+
}
|
|
333
|
+
catch {
|
|
334
|
+
observation = undefined;
|
|
335
|
+
}
|
|
336
|
+
if (observation !== undefined) {
|
|
337
|
+
try {
|
|
338
|
+
return observation.header?.origin === 'subagent';
|
|
339
|
+
}
|
|
340
|
+
finally {
|
|
341
|
+
releaseObservation(observation);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
return projectionValues.subagent !== null && typeof projectionValues.subagent === 'object';
|
|
346
|
+
}
|
|
347
|
+
/** GET shares: the table verbatim, plus the derived fields the settings page
|
|
348
|
+
* renders — the idle countdown (busy reads `Infinity` from the store, `null`
|
|
349
|
+
* on the wire), the current viewer count, and the session titles, fetched
|
|
350
|
+
* concurrently so one slow or failing lookup delays nobody else. */
|
|
351
|
+
async function respondShares(options, res) {
|
|
352
|
+
const store = options.store;
|
|
353
|
+
const viewerCount = options.viewerCount ?? (() => 0);
|
|
354
|
+
const shares = store.list().map((entry) => {
|
|
355
|
+
const remaining = store.remainingMs(entry.sessionId);
|
|
356
|
+
return {
|
|
357
|
+
sessionId: entry.sessionId,
|
|
358
|
+
sharedAt: entry.sharedAt,
|
|
359
|
+
lastActivityAt: entry.lastActivityAt,
|
|
360
|
+
busy: entry.busy,
|
|
361
|
+
remainingMs: remaining === Infinity ? null : remaining,
|
|
362
|
+
viewers: viewerCount(entry.sessionId),
|
|
363
|
+
title: null,
|
|
364
|
+
};
|
|
365
|
+
});
|
|
366
|
+
await Promise.all(shares.map(async (row) => {
|
|
367
|
+
row.title = await titleOf(options, row.sessionId);
|
|
368
|
+
}));
|
|
369
|
+
responseJson(res, 200, { ok: true, shares });
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* Build the admin route handler for one plugin row. The returned handler
|
|
373
|
+
* owns the full response lifecycle of every request under
|
|
374
|
+
* {@link ADMIN_ROUTE_PREFIX} and never throws.
|
|
375
|
+
*/
|
|
376
|
+
export function createAdminHandler(options) {
|
|
377
|
+
return async (req, res) => {
|
|
378
|
+
// Wall 1 first: DSH's own admission (webServer routes skip /api auth).
|
|
379
|
+
const admission = options.admit(req);
|
|
380
|
+
if ('rejection' in admission) {
|
|
381
|
+
responseJson(res, admission.rejection, {
|
|
382
|
+
ok: false,
|
|
383
|
+
error: { code: admission.rejection === 401 ? 'unauthorized' : 'forbidden' },
|
|
384
|
+
});
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
387
|
+
const url = new URL(req.url ?? '/', 'http://dsh.internal');
|
|
388
|
+
const route = url.pathname;
|
|
389
|
+
const method = req.method ?? 'GET';
|
|
390
|
+
try {
|
|
391
|
+
if (route === ADMIN_STATUS_ROUTE) {
|
|
392
|
+
if (method !== 'GET') {
|
|
393
|
+
res.setHeader('Allow', 'GET');
|
|
394
|
+
responseJson(res, 405, { ok: false, error: { code: 'method-not-allowed', message: 'Use GET' } });
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
await respondStatus(options, req, res);
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
if (route === ADMIN_SHARES_ROUTE) {
|
|
401
|
+
// No table, no route: a composition that never built the share store
|
|
402
|
+
// answers like any unknown admin path.
|
|
403
|
+
if (options.store === undefined) {
|
|
404
|
+
responseJson(res, 404, { ok: false, error: { code: 'not-found', message: 'Unknown admin route' } });
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
if (method === 'GET') {
|
|
408
|
+
await respondShares(options, res);
|
|
409
|
+
return;
|
|
410
|
+
}
|
|
411
|
+
if (method === 'POST') {
|
|
412
|
+
// The deliberate exception to the marker wall (see the module
|
|
413
|
+
// comment): the Web application端 behind the gateway may toggle
|
|
414
|
+
// sharing, so a via-gateway POST is NOT refused here. Same-origin
|
|
415
|
+
// still applies — a forwarded request passes it because the
|
|
416
|
+
// gateway rewrites Origin/Host onto the upstream origin.
|
|
417
|
+
if (!sameOriginPost(req)) {
|
|
418
|
+
responseJson(res, 403, {
|
|
419
|
+
ok: false,
|
|
420
|
+
error: { code: 'origin-rejected', message: 'The request must originate from this DSH Web application' },
|
|
421
|
+
});
|
|
422
|
+
return;
|
|
423
|
+
}
|
|
424
|
+
const body = await readJsonBody(req);
|
|
425
|
+
const action = body.action;
|
|
426
|
+
if (typeof action !== 'string' || !SHARE_ACTIONS.has(action)) {
|
|
427
|
+
responseJson(res, 400, {
|
|
428
|
+
ok: false,
|
|
429
|
+
error: { code: 'bad-action', message: `action must be one of ${[...SHARE_ACTIONS].join(', ')}` },
|
|
430
|
+
});
|
|
431
|
+
return;
|
|
432
|
+
}
|
|
433
|
+
const store = options.store;
|
|
434
|
+
if (action === 'unshare-all') {
|
|
435
|
+
for (const entry of store.list())
|
|
436
|
+
store.unshare(entry.sessionId, 'manual');
|
|
437
|
+
responseJson(res, 200, { ok: true });
|
|
438
|
+
return;
|
|
439
|
+
}
|
|
440
|
+
const sessionId = body.sessionId;
|
|
441
|
+
if (typeof sessionId !== 'string' || sessionId === '') {
|
|
442
|
+
responseJson(res, 400, { ok: false, error: { code: 'bad-request', message: 'sessionId is required' } });
|
|
443
|
+
return;
|
|
444
|
+
}
|
|
445
|
+
if (action === 'share') {
|
|
446
|
+
const values = await requireSession(options, sessionId);
|
|
447
|
+
// Subagent children never enter the table — they inherit
|
|
448
|
+
// reachability through the parent chain. Judged off the durable
|
|
449
|
+
// header when sessionQuery is reachable (a fork of a subagent
|
|
450
|
+
// replays the descriptor events, so the projection alone would
|
|
451
|
+
// both over- and under-reject — see isSubagentSession).
|
|
452
|
+
if (await isSubagentSession(options, sessionId, values)) {
|
|
453
|
+
responseJson(res, 400, {
|
|
454
|
+
ok: false,
|
|
455
|
+
error: { code: 'subagent-session', message: 'subagent sessions are reachable through their parent and cannot be shared alone' },
|
|
456
|
+
});
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
459
|
+
store.share(sessionId);
|
|
460
|
+
// A session whose agent is mid-turn must not look idle: the same
|
|
461
|
+
// restore a restart runs, scoped to whatever runs right now.
|
|
462
|
+
restoreBusy(store, options.listAgents ?? (() => []));
|
|
463
|
+
responseJson(res, 200, { ok: true });
|
|
464
|
+
return;
|
|
465
|
+
}
|
|
466
|
+
store.unshare(sessionId, 'manual');
|
|
467
|
+
responseJson(res, 200, { ok: true });
|
|
468
|
+
return;
|
|
469
|
+
}
|
|
470
|
+
res.setHeader('Allow', 'GET, POST');
|
|
471
|
+
responseJson(res, 405, { ok: false, error: { code: 'method-not-allowed', message: 'Use GET or POST' } });
|
|
472
|
+
return;
|
|
473
|
+
}
|
|
474
|
+
if (route === ADMIN_PAIR_ROUTE || route === ADMIN_ACTION_ROUTE || route === ADMIN_PUSH_TEST_ROUTE) {
|
|
475
|
+
if (method !== 'POST') {
|
|
476
|
+
res.setHeader('Allow', 'POST');
|
|
477
|
+
responseJson(res, 405, { ok: false, error: { code: 'method-not-allowed', message: 'Use POST' } });
|
|
478
|
+
return;
|
|
479
|
+
}
|
|
480
|
+
// Wall 2, BEFORE same-origin: a forwarded remote request presents as
|
|
481
|
+
// same-origin (the gateway rewrites Origin/Host), so the marker is
|
|
482
|
+
// the only signal that says "this did not start on this machine".
|
|
483
|
+
if (req.headers['x-zen-remote-via'] !== undefined) {
|
|
484
|
+
responseJson(res, 403, {
|
|
485
|
+
ok: false,
|
|
486
|
+
error: { code: 'via-gateway', message: '配对与设备管理只能在服务端本机操作' },
|
|
487
|
+
});
|
|
488
|
+
return;
|
|
489
|
+
}
|
|
490
|
+
if (!sameOriginPost(req)) {
|
|
491
|
+
responseJson(res, 403, {
|
|
492
|
+
ok: false,
|
|
493
|
+
error: { code: 'origin-rejected', message: 'The request must originate from this DSH Web application' },
|
|
494
|
+
});
|
|
495
|
+
return;
|
|
496
|
+
}
|
|
497
|
+
if (route === ADMIN_PUSH_TEST_ROUTE) {
|
|
498
|
+
await readJsonBody(req); // drained and validated; the copy is fixed
|
|
499
|
+
// The copy language is read HERE, not at apply time: a lang edit on
|
|
500
|
+
// the row applies live, and getConfig() re-resolves per request.
|
|
501
|
+
await relay(options, 'POST', '/pwa/push/send', testPushPayload(options.getConfig().values.lang), res);
|
|
502
|
+
return;
|
|
503
|
+
}
|
|
504
|
+
const body = await readJsonBody(req);
|
|
505
|
+
if (route === ADMIN_ACTION_ROUTE && (typeof body.action !== 'string' || !FORWARDABLE_ACTIONS.has(body.action))) {
|
|
506
|
+
responseJson(res, 400, {
|
|
507
|
+
ok: false,
|
|
508
|
+
error: { code: 'bad-action', message: `action must be one of ${[...FORWARDABLE_ACTIONS].join(', ')}` },
|
|
509
|
+
});
|
|
510
|
+
return;
|
|
511
|
+
}
|
|
512
|
+
await relay(options, 'POST', route === ADMIN_PAIR_ROUTE ? '/lan-gate/pair' : '/lan-gate/action', body, res);
|
|
513
|
+
return;
|
|
514
|
+
}
|
|
515
|
+
responseJson(res, 404, { ok: false, error: { code: 'not-found', message: 'Unknown admin route' } });
|
|
516
|
+
}
|
|
517
|
+
catch (error) {
|
|
518
|
+
if (error instanceof AdminError) {
|
|
519
|
+
responseJson(res, error.status, { ok: false, error: { code: error.code, message: error.message } });
|
|
520
|
+
return;
|
|
521
|
+
}
|
|
522
|
+
responseJson(res, 500, { ok: false, error: { code: 'internal', message: 'The admin route failed' } });
|
|
523
|
+
}
|
|
524
|
+
};
|
|
525
|
+
}
|
|
526
|
+
//# sourceMappingURL=admin-routes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin-routes.js","sourceRoot":"","sources":["../src/admin-routes.ts"],"names":[],"mappings":"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"}
|