@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 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](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE)
4
+ [![dsh-plugin](https://img.shields.io/badge/dsh-plugin-6aa84f.svg)](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)