web/README.md
The croc web client is a React/Vite app that sends and receives files with ordinary
croc CLI peers. Its production build and WebAssembly runtime are embedded in
the separate croc-web binary. croc-web serves the website, runtime
configuration, health check, and opaque WebSocket-to-TCP bridge from one HTTP
address. File metadata and contents remain encrypted between the browser and
the other croc client.
When the server is started with --store-dir, the UI also offers an explicit
Store for 24 hours mode. It encrypts file names, metadata, and 4 MiB chunks
in the browser, uploads only ciphertext, and produces both a browser link and a
CLI token. The transfer is deleted after one fully verified download or 24
hours, whichever comes first. The normal direct-transfer mode remains the
default.
Both send modes can display a QR code for the browser receive URL. Direct-mode codes open the receive page with the croc code filled in and connecting, while stored-mode codes contain the complete encrypted share link.
The security-sensitive protocol operations are compiled from this repository's Go packages into WebAssembly:
Active sends and receives show total and per-file progress, measured bytes per
second, and an ETA calculated with arrival-time.
From this directory:
npm install
npm run dev:stack
This builds and embeds the complete client, then runs:
croc-web localhost:5173
The local shortcut binds directly to localhost:5173; both the website and
WebSocket relay are available there. For frontend hot reloading, run:
npm run dev:hot
Useful checks:
npm test
npm run test:e2e
npm run typecheck
npm run build
npm run embed
make build-web
go test ./...
npm run embed builds the WASM and Vite client and copies the result into
the ignored src/webassets/dist directory, where Go's embed package includes
it only in croc-web. The generated files are not committed. A deployed
croc-web binary does not need this directory or any external static files.
The Playwright suite builds real croc and croc-web binaries, starts an
isolated local croc relay and unified embedded server on temporary ports, then
verifies CLI → Web, Web → CLI, Web → Web, CLI stored → Web, and Web stored →
CLI transfers byte-for-byte. Install its browser once with
npx playwright install chromium. Test processes use an isolated
CROC_CONFIG_DIR and storage directory and do not read or change remembered
croc settings.
The server fixes one upstream host and allowlists every TCP port so /ws
cannot be used as an arbitrary network proxy:
croc-web --pass YOUR_RELAY_PASSWORD \
--bind 127.0.0.1:9014 \
--relay relay.example.com \
--ports 9009,9010,9011,9012,9013,9014,9015,9016,9017 \
files.example.com
The server injects the selected relay address and password as browser defaults
through /config.js. Users can still override them from the advanced settings
panel.
The unified server exposes:
GET / and embedded static client assets; curl and wget receive the
installer script at / while browsers receive the web clientGET /config.jsGET /healthzGET /ws?port=<allowlisted-port> upgraded to a binary WebSocket/api/v1/store/transfers and its descendants when --store-dir is setRun croc-web behind an HTTPS reverse proxy:
croc-web --bind 127.0.0.1:9014 getcroc.com
Optional Umami analytics are enabled only when both runtime variables are set:
UMAMI_URL=https://umami.schollz.com \
UMAMI_WEBSITE_ID=website-uuid \
croc-web --bind 127.0.0.1:9014 getcroc.com
Successful browser transfers emit the custom events send-direct,
send-with-storage, and receive. When Umami is not configured, event
tracking is disabled and transfers behave identically. The browser receives
only inert analytics configuration from the server: the Umami script is loaded
after an explicit opt-in in the first-visit privacy dialog. Automatic
pageviews are disabled, and custom transfer events remove query strings and
fragments from the reported URL.
Proxy the complete origin—including WebSocket upgrades—to
127.0.0.1:9014, preserving the original Host header. The server returns the
site at / and the WebSocket bridge at /ws, so no split routing or external
static file deployment is required. TLS certificates remain at the reverse
proxy.
Temporary storage is disabled unless a directory is explicitly configured:
croc-web \
--bind 127.0.0.1:9014 \
--store-dir /var/lib/croc/store \
--store-max-transfer 1GiB \
--store-quota 5GiB \
--store-min-free 512MiB \
getcroc.com
The store directory is locked to one server process and should be persistent,
private, writable only by the croc service account, and excluded from backups.
If a trusted reverse proxy supplies X-Forwarded-For, identify its network
with repeatable --store-trusted-proxy CIDR flags; untrusted forwarding
headers are ignored. See
src/docs/STORED_TRANSFERS.md for all
limits and operational details.
--bind defaults to 127.0.0.1:9014. When an explicit loopback website
address with a port is used, such as localhost:5173, the local shortcut binds
there unless --bind is explicitly provided.