dsh-remote-control-plugin 0.0.0-stage → 0.3.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/INSTALL.md +38 -0
- package/LICENSE +21 -0
- package/README.md +96 -2
- package/client.js +563 -0
- package/cordis.patch.yml +3 -0
- package/host/fabric.js +595 -0
- package/host/relay-core.js +189 -0
- package/host/relay-link.js +335 -0
- package/icon.svg +15 -0
- package/index.js +1011 -0
- package/locale/en.json +6 -0
- package/locale/zh.json +6 -0
- package/package.json +46 -4
- package/web/app.css +420 -0
- package/web/app.js +594 -0
- package/web/icon.svg +15 -0
- package/web/index.html +85 -0
package/INSTALL.md
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Install on another desktop
|
|
2
|
+
|
|
3
|
+
Published as `dsh-remote-control-plugin`. The package is self-contained — no dependencies, no
|
|
4
|
+
build step, no postinstall script.
|
|
5
|
+
|
|
6
|
+
## 1. Install it
|
|
7
|
+
|
|
8
|
+
In the Web GUI: **Plugins → Add plugin**, enter `dsh-remote-control-plugin@0.3.1`, keep the
|
|
9
|
+
official npm registry selected, then **Install** and **Enable now**. Restart DSH.
|
|
10
|
+
|
|
11
|
+
A **Devices** icon appears in the sidebar.
|
|
12
|
+
|
|
13
|
+
From a chat, the same install works where the plugin tool is enabled (Standard or Creator
|
|
14
|
+
preset — PTC disables `tool-plugin-manager`):
|
|
15
|
+
|
|
16
|
+
> Install the DSH plugin bundle `dsh-remote-control-plugin@0.3.1` with plugin_manager, then tell me when it is applied.
|
|
17
|
+
|
|
18
|
+
## 2. Connect two machines
|
|
19
|
+
|
|
20
|
+
Pick the machine with a reachable address (same LAN, VPN, or a forwarded port):
|
|
21
|
+
|
|
22
|
+
1. On that machine: **Devices → Relay → Create relay here**, then **Copy** the invite.
|
|
23
|
+
2. On the other machine: **Devices → Relay**, paste the invite into the URL field, **Connect**.
|
|
24
|
+
3. Either machine: **Request** next to the peer, then **Allow** on the target.
|
|
25
|
+
|
|
26
|
+
Two machines on the same LAN need no relay at all — LAN discovery lists them directly.
|
|
27
|
+
|
|
28
|
+
No reachable machine? Run a relay anywhere both can reach (`PORT=8787 node relay/server.js`) and
|
|
29
|
+
paste `http://<host>:8787 <workspace key>` into both panels.
|
|
30
|
+
|
|
31
|
+
## Notes
|
|
32
|
+
|
|
33
|
+
- The account label is cosmetic; trust comes from the one-time **Allow** on the target device.
|
|
34
|
+
- Approvals persist in `$DSH_HOME/remote-control-peers.json`; deleting it revokes every peer.
|
|
35
|
+
- The relay and the control API share one port (default `57330`), so one forwarded port is enough.
|
|
36
|
+
- Peer traffic is signed but not encrypted. Use a private network or TLS in front of the port.
|
|
37
|
+
- 0.3.1 fixes two relay bugs: peers no longer linger as `503 relay-offline` after a relay goes
|
|
38
|
+
away, and a failed Connect no longer tears down a working hosted relay.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 hkrds1996
|
|
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,97 @@
|
|
|
1
|
-
#
|
|
1
|
+
# dsh-remote-control-plugin
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Control other DSH desktops from the one you are using.
|
|
4
|
+
|
|
5
|
+
Two surfaces share one Host plugin:
|
|
6
|
+
|
|
7
|
+
- **Devices panel** (Web GUI) — discovers other DSH desktops on the same network, asks the
|
|
8
|
+
target for access once, then lists that device's sessions and lets you read the live
|
|
9
|
+
transcript, send prompts, and stop a turn.
|
|
10
|
+
- **Browser page** (phone / any browser) — the same control surface as a small standalone
|
|
11
|
+
page, unlocked with a pairing code. Useful when the other end is a phone rather than a DSH
|
|
12
|
+
desktop.
|
|
13
|
+
|
|
14
|
+
Both drive `ctx.sessionController` in-process, so neither depends on the GUI's boot payload.
|
|
15
|
+
|
|
16
|
+
## How device trust works
|
|
17
|
+
|
|
18
|
+
1. Each Host announces itself on UDP `discoveryPort` with its device id, display name, and
|
|
19
|
+
account id (when signed in).
|
|
20
|
+
2. To control a peer, this Host sends `POST /peer/hello`. The **target** shows a pending
|
|
21
|
+
request in its own Devices panel; nothing is granted until a person there presses **Allow**.
|
|
22
|
+
3. On approval the target issues a random per-peer secret. Every later call is signed
|
|
23
|
+
`HMAC-SHA256(secret, deviceId + method + path + timestamp + body)`, valid for 5 minutes of
|
|
24
|
+
clock skew.
|
|
25
|
+
4. Approvals persist in `$DSH_HOME/remote-control-peers.json`. Deleting that file revokes
|
|
26
|
+
every device.
|
|
27
|
+
|
|
28
|
+
There is deliberately no "same account implies trust" shortcut: two devices holding grants for
|
|
29
|
+
the same account share no secret, so account id alone cannot authenticate a peer. The panel
|
|
30
|
+
shows the account id of each candidate and flags a different account, but a person approves.
|
|
31
|
+
|
|
32
|
+
## Across networks (relay)
|
|
33
|
+
|
|
34
|
+
LAN discovery only reaches one subnet. Devices on different networks meet through a relay, and
|
|
35
|
+
there are two ways to get one.
|
|
36
|
+
|
|
37
|
+
**Create it on a device.** In **Devices → Relay**, press **Create relay here**. That Host serves
|
|
38
|
+
the relay on its own listener and shows a ready-to-paste invite — one line holding the URL and
|
|
39
|
+
the workspace key. Paste it into the other device's Relay panel.
|
|
40
|
+
|
|
41
|
+
This only reaches other networks if that device is reachable there: the same LAN, a forwarded
|
|
42
|
+
port, a VPN address, or a configured `publicUrl`. The invite carries the address the panel can
|
|
43
|
+
see, so forward that port (or set `publicUrl`) before sharing it.
|
|
44
|
+
|
|
45
|
+
**Or run a relay on a machine that is always reachable:**
|
|
46
|
+
|
|
47
|
+
```sh
|
|
48
|
+
PORT=8787 node relay/server.js
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Host it on a VPS, NAS, or any always-on machine, put it behind TLS or a VPN, and paste
|
|
52
|
+
`http://host:8787 <workspace key>` into every device.
|
|
53
|
+
|
|
54
|
+
Either way the workspace key never leaves the devices: the relay only receives its SHA-256 as a
|
|
55
|
+
group id. It forwards opaque `/peer/*` calls that stay signed end to end, so a compromised relay
|
|
56
|
+
can drop or delay traffic but cannot forge a control command. Group membership alone grants
|
|
57
|
+
nothing — the target still requires the one-time approval before any session call is accepted.
|
|
58
|
+
Treat the relay as private: whoever holds the group id can join the group and *request* access.
|
|
59
|
+
|
|
60
|
+
## Configuration
|
|
61
|
+
|
|
62
|
+
Defaults work on a LAN. Override the row in `$DSH_HOME/profiles/<profile>/cordis.patch.yml`:
|
|
63
|
+
|
|
64
|
+
```yaml
|
|
65
|
+
- id: remote-control
|
|
66
|
+
name: 'dsh-remote-control-plugin'
|
|
67
|
+
config:
|
|
68
|
+
host: 0.0.0.0 # any interface (default); use one LAN IP to narrow exposure
|
|
69
|
+
port: 57330 # browser page + peer API
|
|
70
|
+
discovery: true
|
|
71
|
+
discoveryPort: 57331 # UDP discovery
|
|
72
|
+
relayUrl: '' # e.g. https://relay.example.com for cross-network control
|
|
73
|
+
relayKey: '' # shared workspace key; required when relayUrl is set
|
|
74
|
+
deviceName: Desk PC # defaults to the OS hostname
|
|
75
|
+
publicUrl: '' # e.g. https://dsh.example.com for a tunnel/proxy
|
|
76
|
+
trustedHosts: [] # extra accepted authorities for the browser page
|
|
77
|
+
code: '' # fixed pairing code; empty = generated and persisted
|
|
78
|
+
cookieDays: 30
|
|
79
|
+
defaultCwd: ''
|
|
80
|
+
tls: { certFile: '', keyFile: '' }
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
The browser page and the peer API share the listener. When `host` is a wildcard, any IP literal
|
|
84
|
+
is accepted and domain-name Hosts are refused unless they appear in `publicUrl` or
|
|
85
|
+
`trustedHosts`; this blocks DNS-rebinding. Requests without a same-origin `Sec-Fetch-Site` must
|
|
86
|
+
come from loopback.
|
|
87
|
+
|
|
88
|
+
## Threat model / limits
|
|
89
|
+
|
|
90
|
+
- Approval is manual on purpose. A peer on the LAN can prompt for access; it cannot grant it.
|
|
91
|
+
- Prompts sent from a peer run with this Host's tools and permissions. Approve devices you
|
|
92
|
+
control.
|
|
93
|
+
- Peer transport is plain HTTP. The peer secret crosses the LAN once, at approval time. Use a
|
|
94
|
+
private network or VPN, or set `tls` and front the port with a proxy.
|
|
95
|
+
- The pairing code protects the browser page only; it is printed at activation and stored in
|
|
96
|
+
`$DSH_HOME/remote-control.json`.
|
|
97
|
+
- Approvals that arrive while no Devices panel is open stay pending for up to 10 minutes.
|