You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The relay server terminates only the browser WebSocket and yamux session. It uses `github.com/gorilla/websocket` for `/__zp/ws-pipe`, disables WebSocket compression, wraps binary WebSocket messages as a stream-oriented `net.Conn`, and either byte-bridges yamux streams to the configured Tor SOCKS5 listener or, when launched with `-socks internal`, parses the kernel's SOCKS5 greeting/auth/CONNECT request itself and directly dials the requested target from the relay process. It does not parse target HTTP, TLS, redirects, cookies, or HTML. Those responsibilities live in the Go WASM kernel and browser runtime. Internal mode is a non-anonymous test/development mode.
37
+
The relay server terminates only the browser WebSocket and yamux session. It uses `github.com/gorilla/websocket` for `/zp/ws-pipe`, disables WebSocket compression, wraps binary WebSocket messages as a stream-oriented `net.Conn`, and either byte-bridges yamux streams to the configured Tor SOCKS5 listener or, when launched with `-socks internal`, parses the kernel's SOCKS5 greeting/auth/CONNECT request itself and directly dials the requested target from the relay process. It does not parse target HTTP, TLS, redirects, cookies, or HTML. Those responsibilities live in the Go WASM kernel and browser runtime. Internal mode is a non-anonymous test/development mode.
37
38
38
39
## Core invariants
39
40
40
-
- Target document navigations use encrypted `/p/<encrypted>#k=<key>` routes on the proxy origin.
41
+
- Target document navigations use encrypted `/zp/p/<encrypted>#k=<key>&server=...` routes on the proxy origin.
41
42
- The `#k` fragment is decrypted in the browser shell, removed with `history.replaceState`, and not sent to the server.
42
43
- Every Service Worker-controlled request is classified. Unknown requests are blocked; there is no native `fetch(event.request)` fallback.
43
44
- Privileged runtime-to-Service-Worker control messages require a per-tab capability token injected into the runtime prelude and removed from target-visible DOM before target code runs.
@@ -51,38 +52,38 @@ The relay server terminates only the browser WebSocket and yamux session. It use
| Share URL envelope |`web/zp-core.js`, `internal/shareurl/*`| Compatible JavaScript and Go implementations of `/p/<encrypted>#k=<key>` using AES-256-CBC, HMAC-SHA256, HKDF, and raw base64url. |
55
-
| Service Worker |`web/sw.js`| Classifies every controlled request, blocks unknowns, manages in-memory tab/entry state, requires per-tab capability tokens on privileged runtime bridge messages, calls the WASM kernel, exposes runtime bridge APIs. |
56
-
| Runtime prelude |`web/runtime-prelude.js`, `web/worker-prelude.js`| Installs target-realm containment hooks before target scripts run. Main-window fetch/XHR/EventSource/WebSocket/sendBeacon, navigation/form/history/location/storage/worker/iframe/device APIs are hooked; main-window and worker `fetch` bridge through `/__zp/api/fetch` to satisfy strict proxy-origin CSP while preserving the Tor/yamux/uTLS transport path. Runtime membrane helpers (`__zp_get`, `__zp_set`, `__zp_call`, `__zp_construct`, `__zp_getOwnPropertyDescriptor`, `__zp_ownKeys`) and dynamic compilation wrappers execute `Function`/`eval`/string timer bodies under the virtual global scope. Patched function source strings, Canvas/Audio extraction, and speech voices receive limited self-fingerprint masking. |
55
+
| Share URL envelope |`web/zp-core.js`, `internal/shareurl/*`| Compatible JavaScript and Go implementations of `/zp/p/<encrypted>#k=<key>` using AES-256-CBC, HMAC-SHA256, HKDF, raw base64url, and inherited relay-server fragments. |
56
+
| Service Worker |`web/sw.js`| Classifies every controlled request under `/zp/`, blocks unknowns, manages in-memory tab/entry state and inherited relay servers, requires per-tab capability tokens on privileged runtime bridge messages, calls the WASM kernel, exposes runtime bridge APIs. |
57
+
| Runtime prelude |`web/runtime-prelude.js`, `web/worker-prelude.js`| Installs target-realm containment hooks before target scripts run. Main-window fetch/XHR/EventSource/WebSocket/sendBeacon, navigation/form/history/location/storage/worker/iframe/device APIs are hooked; main-window and worker `fetch` bridge through `/zp/api/fetch` to satisfy strict proxy-origin CSP while preserving the Tor/yamux/uTLS transport path. Runtime membrane helpers (`__zp_get`, `__zp_set`, `__zp_call`, `__zp_construct`, `__zp_getOwnPropertyDescriptor`, `__zp_ownKeys`) and dynamic compilation wrappers execute `Function`/`eval`/string timer bodies under the virtual global scope. Rust WASM rewrite helpers are loaded before runtime hooks so static and dynamic inline scripts can be rewritten or blocked fail-closed. |
| Relay server |`cmd/zeroproxy-server/main.go`| Serves assets, accepts `/__zp/ws-pipe` with Gorilla WebSocket, and routes yamux streams either to the configured Tor SOCKS5 address or the `-socks internal` SOCKS5 parser/direct dialer. |
| Relay server |`cmd/zeroproxy-server/main.go`| Serves prefixed assets, accepts `/zp/ws-pipe` with Gorilla WebSocket, and routes yamux streams either to the configured Tor SOCKS5 address or the `-socks internal` SOCKS5 parser/direct dialer. |
61
62
62
63
## Request flow
63
64
64
-
1. The shell registers `/sw.js`, waits for a controller, canonicalizes an `http:` or `https:` target, encrypts it, and navigates to `/p/<encrypted>#k=<key>` on the proxy origin.
65
-
2. The shell loaded on `/p/<encrypted>#k=<key>` decrypts the fragment key in window context, validates the HMAC before decryption, removes `#k` with `history.replaceState`, and sends `ZP_OPEN_SHARE` to the Service Worker.
66
-
3. The Service Worker stores the decrypted target in in-memory tab/entry maps and activates `/p/<encrypted>` as a proxy document route.
67
-
4. A `/p/<encrypted>` document request is resolved back to the target URL. The Service Worker calls `__go_jshttp` with `X-ZP-*` internal metadata.
68
-
5. The WASM kernel ensures one long-lived WebSocket connection to `/__zp/ws-pipe`, wraps it in a yamux client, and opens one yamux stream per target TCP connection.
65
+
1. The shell registers `/zp/sw.js` with `scope: '/zp/'`, waits for a controller, canonicalizes an `http:` or `https:` target, encrypts it, and navigates to `/zp/p/<encrypted>#k=<key>` on the proxy origin.
66
+
2. The shell loaded on `/zp/p/<encrypted>#k=<key>` decrypts the fragment key in window context, validates the HMAC before decryption, normalizes repeated `server=` relay fragments, removes the fragment from the visible URL when policy allows, and sends `ZP_OPEN_SHARE` to the Service Worker.
67
+
3. The Service Worker stores the decrypted target plus relay-server list in in-memory tab/entry maps and activates `/zp/p/<encrypted>` as a proxy document route.
68
+
4. A `/zp/p/<encrypted>` document request is resolved back to the target URL. The Service Worker calls `__go_jshttp` with `X-ZP-*` internal metadata plus inherited relay-server headers.
69
+
5. The WASM kernel ensures one long-lived WebSocket connection to the selected relay server or `/zp/ws-pipe`, wraps it in a yamux client, and opens one yamux stream per target TCP connection.
69
70
6. Each target connection performs SOCKS5 `CONNECT` with DOMAINNAME ATYP and a Tor `IsolateSOCKSAuth` username derived from the tab stream-isolation key and target site. In `-socks internal` mode the relay accepts that same binary SOCKS5 handshake locally and direct-dials the requested host:port; no external Tor process is used.
70
71
7. HTTPS fetch targets advertise `h2` and `http/1.1` through uTLS ALPN; target WebSocket connections advertise only `http/1.1`.
71
72
8.`internal/zphttp` dispatches negotiated `h2` connections through `golang.org/x/net/http2.ClientConn`; HTTP/1.1 fallback writes a direct request and reads the response with `http.ReadResponse`.
72
73
9. Redirects are followed inside the kernel so raw `Location` headers are not exposed to browser code.
73
-
10. HTML document responses are transformed: runtime prelude is injected, document navigation URLs are rewritten to encrypted `/p/<encrypted>#k=<key>` routes, risky tags and headers are removed, and the browser receives a same-origin `Response` with ZeroProxy CSP.
74
+
10. HTML document responses are transformed: Rust/JS rewrite assets plus runtime prelude are injected, document navigation URLs are rewritten to encrypted `/zp/p/<encrypted>#k=<key>` routes, risky tags and headers are removed, and the browser receives a same-origin `Response` with ZeroProxy CSP.
`web/zp-core.js` and `internal/shareurl` derive separate HKDF-SHA256 AES-CBC and HMAC keys from the 64-byte seed. The MAC covers a fixed version prefix, IV, and ciphertext. Decryption verifies HMAC first, then decrypts and canonicalizes the target URL. Only `http:` and `https:` targets are accepted for document/fetch traffic; WebSocket wrappers accept only `ws:` and `wss:`.
84
85
85
-
The Go HTML transformer uses `internal/shareurl.New` when laundering document-navigation attributes, so transformed links/forms/frames keep using encrypted `/p` routes instead of legacy virtual URL paths.
86
+
The Go HTML transformer uses `internal/shareurl.New` when laundering document-navigation attributes, so transformed links/forms/frames keep using encrypted `/zp/p` routes instead of legacy virtual URL paths.
0 commit comments