@dshn/agent 0.1.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/LICENSE +21 -0
- package/README.md +155 -0
- package/client.js +811 -0
- package/cordis.patch.yml +25 -0
- package/lib/index.js +5407 -0
- package/package.json +51 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 jsdvjx (DeepSeek Harness Network contributors)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# dshn — DeepSeek Harness Network
|
|
2
|
+
|
|
3
|
+
[](./LICENSE)
|
|
4
|
+
[](https://awesome-dsh-plugin.com/)
|
|
5
|
+
|
|
6
|
+
Expose a locally-running **DeepSeek Harness** (`dsh`) web UI to the public
|
|
7
|
+
internet under a `*.ds.hn` subdomain, gated by a login. Install the plugin, open
|
|
8
|
+
dsh locally, and a form in Settings asks for a **subdomain prefix** and a
|
|
9
|
+
**password** — those two *are* the credential. No tokens, no env vars, no
|
|
10
|
+
provisioning. An optional **end-to-end password** encrypts the traffic so even
|
|
11
|
+
the relay operator sees only ciphertext.
|
|
12
|
+
|
|
13
|
+
> ⚠️ **dsh ships bash and filesystem tools. A publicly reachable dsh UI is a
|
|
14
|
+
> remote shell.** The relay's login gate is not optional; do not disable it. Use
|
|
15
|
+
> a strong password, and prefer end-to-end encryption for anything sensitive.
|
|
16
|
+
|
|
17
|
+
## Features
|
|
18
|
+
|
|
19
|
+
- **Zero-config credential.** `(subdomain, password)` set once in dsh's Settings
|
|
20
|
+
→ the plugin claims the subdomain and connects. Persists to dsh's own
|
|
21
|
+
`~/.dsh/settings.yaml` and reconnects on restart.
|
|
22
|
+
- **Trust-on-first-use claim.** The first agent to present a free subdomain sets
|
|
23
|
+
its password (scrypt-hashed on the relay). Later connects and every browser
|
|
24
|
+
login must match it — squatting-protected.
|
|
25
|
+
- **Optional end-to-end encryption** (off by default). A *separate* e2e password,
|
|
26
|
+
never sent to the relay, encrypts `/api` bodies and the event stream:
|
|
27
|
+
PBKDF2-SHA256 (210k) → AES-256-GCM. Visitors enter it once in the browser; it
|
|
28
|
+
can be remembered per-device in `localStorage` (never transmitted).
|
|
29
|
+
- **Native UI.** Config lives in dsh's own Settings ("公网转发" / *Public
|
|
30
|
+
forwarding*); a footer row shows live latency and links to it.
|
|
31
|
+
- **Self-hosted data plane.** Traffic rides Cloudflare's edge to *your* server —
|
|
32
|
+
no per-user Cloudflare account, no NS delegation.
|
|
33
|
+
|
|
34
|
+
## Architecture
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
browser alice.ds.hn
|
|
38
|
+
│ HTTPS
|
|
39
|
+
▼
|
|
40
|
+
Cloudflare edge (*.ds.hn proxied / orange-cloud) free DDoS, WAF, TLS,
|
|
41
|
+
│ origin pull anycast, hidden origin
|
|
42
|
+
▼
|
|
43
|
+
relay (your server, @dshn/relay) login gate + subdomain
|
|
44
|
+
│ one WSS per device (multiplexed) claim store; moves bytes
|
|
45
|
+
▼
|
|
46
|
+
dshn (the dsh plugin, on the user's machine) replays HTTP + WS to dsh,
|
|
47
|
+
│ http://127.0.0.1:<dsh port> Host/Origin rewritten to loopback
|
|
48
|
+
▼
|
|
49
|
+
dsh (local web server) fence sees a loopback request
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
- **No trustedHosts patch.** The agent rewrites each forwarded request's
|
|
53
|
+
Host/Origin to loopback, so dsh's `/api` browser-trust fence accepts it as a
|
|
54
|
+
local same-origin request for *any* runtime-chosen subdomain — which is what
|
|
55
|
+
lets the subdomain come from a form instead of the composition. Access is gated
|
|
56
|
+
by the relay login, not the fence.
|
|
57
|
+
- **End-to-end mode** seals request/response bodies at the agent and opens them
|
|
58
|
+
in the browser; the relay stays a blind byte-mover. The app shell and plugin
|
|
59
|
+
bundles are left in the clear so the browser can bootstrap and show the unlock
|
|
60
|
+
gate. It defeats a passive/curious relay and a data-at-rest breach — not an
|
|
61
|
+
actively malicious relay that tampers with the served JS.
|
|
62
|
+
|
|
63
|
+
## Packages
|
|
64
|
+
|
|
65
|
+
| package | what it is | runs where |
|
|
66
|
+
|---|---|---|
|
|
67
|
+
| `@dshn/protocol` | the WSS frame contract both ends compile against | shared |
|
|
68
|
+
| `dshn` | the dsh plugin: setup form + outbound tunnel + status widget + e2e | user's machine, inside dsh |
|
|
69
|
+
| `@dshn/relay` | login gate + claim store + subdomain router + HTTP/WS bridge | your server, behind Cloudflare |
|
|
70
|
+
|
|
71
|
+
The claim store (`packages/relay/src/claims.ts`) is trust-on-first-use for now;
|
|
72
|
+
an account-backed control plane replaces it later.
|
|
73
|
+
|
|
74
|
+
## Install the agent (user's machine)
|
|
75
|
+
|
|
76
|
+
From npm (recommended — one command, fully self-contained):
|
|
77
|
+
|
|
78
|
+
```sh
|
|
79
|
+
dsh plugin --profile web add @dshn/agent
|
|
80
|
+
dsh --profile web
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Or a prebuilt tarball from the latest GitHub release:
|
|
84
|
+
|
|
85
|
+
```sh
|
|
86
|
+
curl -L -o dshn.tgz \
|
|
87
|
+
https://github.com/jsdvjx/dshn/releases/latest/download/dshn.tgz
|
|
88
|
+
dsh plugin --profile web add ./dshn.tgz
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Or build from source:
|
|
92
|
+
|
|
93
|
+
```sh
|
|
94
|
+
pnpm install && node scripts/build-dist.mjs
|
|
95
|
+
dsh plugin --profile web add ./dist/dshn
|
|
96
|
+
dsh --profile web
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Then open dsh locally, go to **Settings → 公网转发 (Public forwarding)**, pick a
|
|
100
|
+
subdomain prefix and a password (optionally an end-to-end password), and click
|
|
101
|
+
**Connect**. Use the same access password to log in from a phone. Run at most
|
|
102
|
+
**one** agent per subdomain — two agents with the same credential fight over it.
|
|
103
|
+
|
|
104
|
+
Agent environment (all optional; sensible defaults):
|
|
105
|
+
|
|
106
|
+
| var | default | purpose |
|
|
107
|
+
|---|---|---|
|
|
108
|
+
| `DSHN_ENABLED` | `1` | set `0` to load the plugin inert |
|
|
109
|
+
| `DSHN_RELAY_HOST` | `relay.ds.hn` | relay authority; `wss://origin.ds.hn:8787` for a direct off-Cloudflare path |
|
|
110
|
+
| `DSHN_ORIGIN_CA` | — | PEM to pin a self-signed direct-origin cert |
|
|
111
|
+
| `DSHN_STATE` | `~/.dsh/dshn-agent.json` | legacy state file (creds now live in `settings.yaml`) |
|
|
112
|
+
| `DSH_HOME` | `~/.dsh` | dsh home directory |
|
|
113
|
+
|
|
114
|
+
## Run the relay (your server)
|
|
115
|
+
|
|
116
|
+
```sh
|
|
117
|
+
pnpm install && pnpm build
|
|
118
|
+
DSHN_COOKIE_SECRET=$(openssl rand -hex 32) \
|
|
119
|
+
DSHN_APEX=ds.hn \
|
|
120
|
+
DSHN_RELAY_PORT=8787 \
|
|
121
|
+
DSHN_CLAIMS=./claims.json \
|
|
122
|
+
DSHN_TLS_CERT=./cert.pem DSHN_TLS_KEY=./key.pem \
|
|
123
|
+
node packages/relay/lib/index.js
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
| var | required | purpose |
|
|
127
|
+
|---|---|---|
|
|
128
|
+
| `DSHN_COOKIE_SECRET` | ✅ | HMAC secret for session cookies (rotating it logs everyone out) |
|
|
129
|
+
| `DSHN_APEX` | — (`ds.hn`) | apex domain the wildcard hangs off |
|
|
130
|
+
| `DSHN_RELAY_PORT` | — (`8787`) | listen port |
|
|
131
|
+
| `DSHN_CLAIMS` | — | JSON file the relay creates/maintains (subdomain → scrypt hash) |
|
|
132
|
+
| `DSHN_TLS_CERT` / `DSHN_TLS_KEY` | — | PEM paths to serve HTTPS directly (else plain HTTP behind CF) |
|
|
133
|
+
| `DSHN_SITE` | — | apex landing-page HTML |
|
|
134
|
+
|
|
135
|
+
Cloudflare: proxy `*.ds.hn` (orange cloud) to the relay's origin. Harden the
|
|
136
|
+
origin to accept only Cloudflare — firewall to the
|
|
137
|
+
[Cloudflare IP ranges](https://www.cloudflare.com/ips/) and enable Authenticated
|
|
138
|
+
Origin Pulls (mTLS). Because Cloudflare closes a proxied WebSocket after ~100s
|
|
139
|
+
idle, both ends heartbeat every 25s — already built in. For a direct
|
|
140
|
+
(off-Cloudflare) tunnel that survives sustained heavy throughput, add a
|
|
141
|
+
grey-cloud (DNS-only) `origin.ds.hn` A record and point agents at it with
|
|
142
|
+
`DSHN_RELAY_HOST` + `DSHN_ORIGIN_CA`.
|
|
143
|
+
|
|
144
|
+
## Status
|
|
145
|
+
|
|
146
|
+
Working end-to-end. Known gaps: an occasional tunnel-socket drop fails that
|
|
147
|
+
connection's in-flight requests (no request replay yet); Cloudflare can reset the
|
|
148
|
+
tunnel under sustained heavy throughput (use the direct-origin option); the CF
|
|
149
|
+
free-plan 100 MB request cap can clip large dsh image uploads; the claim store is
|
|
150
|
+
trust-on-first-use with no account layer; and the relay origin should be locked
|
|
151
|
+
to Cloudflare IPs + Authenticated Origin Pulls in production.
|
|
152
|
+
|
|
153
|
+
## License
|
|
154
|
+
|
|
155
|
+
[MIT](./LICENSE)
|