dsh-web-search-ddg
aooyoo
Zero-token DuckDuckGo search provider for the DeepSeek Harness (DSH) web seam — local headless browser, no API key, no m…
PROJECT TOPICS
PROJECT README
English | 简体中文
LAN / remote access support for the DeepSeek Harness Web UI.
The Web UI calls crypto.randomUUID() in boot-critical paths (RPC id minting, message ids, draft attachments). That Web API exists only in secure contexts (HTTPS, or http://localhost / http://127.0.0.1). When the UI is served over plain HTTP from a non-loopback address — a LAN IP, a Tailscale IP, or a hostname — crypto.randomUUID is undefined, every RPC throws, and sessions and models never render.
A host-side plugin that uses the webserver's official index-tap extension point (webServer.tapIndex) to inject a small polyfill (RFC 4122 v4 built on crypto.getRandomValues, which is available on insecure origins) as the first script in <head>, before the boot manifest and the shell entry. On secure origins the polyfill is a no-op.
index.html)Installed from npm:
dsh plugin --profile web add dsh-web-lan-access
(No npm / local development — point pnpm at the repo instead:
dsh plugin --profile web add github:AcidGr/dsh-web-lan-access
)
Restart dsh web, then hard-refresh the browser.
PROFILE="$DSH_HOME/profiles/web" # adjust DSH_HOME and profile name
mkdir -p "$PROFILE/plugins" "$PROFILE/node_modules/@dsh-profile"
cp -r dsh-web-lan-access "$PROFILE/plugins/lan-access"
ln -sfn ../../plugins/lan-access "$PROFILE/node_modules/@dsh-profile/lan-access"
# append to $PROFILE/cordis.patch.yml:
# - insert:
# - id: lan-access
# name: '@dsh-profile/lan-access'
The plugin is self-contained: its bundle patch sets the webserver bind host to 0.0.0.0 directly (the CLI flag --host 0.0.0.0 is hard-rejected for safety on newer harness versions, but the webserver config still accepts it — so no source changes and no --host flag are needed; the CLI --port flag still works).
Install the plugin, then start normally — without --host:
dsh --profile web --port 3080
When bound to 0.0.0.0, the harness automatically adds every local non-internal IPv4 to the /api trust fence (resolveLanTrust) — LAN IP access needs no extra config.
If you prefer NOT to let the plugin take over the bind host (e.g. you want loopback + a port forward), keep the
webserverrow override out of your tree and instead forward a port (socat / rinetd / Tailscale serve) from127.0.0.1:3080, adding the forwarded address totrustedHostsmanually.
Domains / remote (e.g. Tailscale) — add your own authorities to trustedHosts:
- id: web-runtime
config:
trustedHosts:
- <short-name> # e.g. myhost — MUST be listed separately!
- <name>.tailXXXX.ts.net # full domain
- 100.x.x.x # tailnet IP
⚠️ The fence compares the Host header literally: a MagicDNS short name (http://myhost:3080) is not the full domain — list the short name on its own line, or every /api call returns 403 (page shell loads, sessions/models absent).
On unmodified harness builds, a small set of sensitive API methods (settings.*, credentials.*, llm.discoverModels) is pinned to loopback regardless of trustedHosts (isTrustedApiRequest(request, []) in packages/client/connection/src/index.ts). From a remote origin those calls return 403: chat/sessions/models still work, but the Settings pages (including the plugin-config cards) and credentials UI show empty/errors. The polyfill cannot change that — it is a product-side policy. A one-line upstream change (isTrustedApiRequest(request, trustedHosts)) makes them follow the deployment's trusted hosts; until then, edit that line locally or manage those settings from http://127.0.0.1:3080.
curl http://127.0.0.1:3080/ | grep lan-access-polyfill # must match
Then open http://<server-ip>:3080 from another device — sessions and models must load.
Binding 0.0.0.0 makes the agent reachable without authentication by anyone on the same network (/api is an origin fence, not a login). On a server with a public IP this means the whole internet. Use only on trusted networks, restrict with a firewall (e.g. ufw allow from 192.168.0.0/16), or expose through Tailscale / an authenticated reverse proxy instead. A TLS reverse proxy also removes the need for this polyfill entirely.
dsh plugin --profile web remove dsh-web-lan-accesslan-access insert block from cordis.patch.yml; optionally start without --host 0.0.0.0MIT
CLASSIFICATION EVIDENCE
系统优先读取 GitHub Topics,再与站内分类词典和词根规则比对。