@esmeraldoinciso/local-share
v0.1.1
Published
Share files directly over your local network. No cloud, no accounts.
Readme
LocalShare
Share files directly over your local network. No cloud, no accounts.
LocalShare transfers files directly between devices on the local network. It does not upload shared files to a cloud service.
Installation
Requires Node.js 20+.
npm install -g @esmeraldoinciso/local-share
local-share ./photosFrom source:
npm install
npm run build
node ./dist/src/cli/index.js ./photosUsage
Share a folder:
local-share ./photosShare a single file:
local-share photo.jpg --port 8787The terminal prints a LAN URL plus a QR code. Another device on the same Wi-Fi/LAN scans the code (or opens the URL) and downloads from the browser. No account, no app install on the receiver.
Options
--port <number>— port to listen on (default8787; auto-increments unless explicit)--host <address>— bind host (default0.0.0.0for LAN sharing)--password [value]— require a password; prompts hidden twice when no value is given--expires <duration>— e.g.10m,30m,1h,2h(default30m); the server shuts down automatically--no-qr— do not display a QR code--no-browser— do not auto-open the browser on the host--verbose— verbose logging (never includes passwords)--help,--version
Exit codes: 0 success · 2 invalid arguments · 3 path not found · 4 permission denied · 5 port unavailable · 6 configuration error.
Password protection
local-share ./photos --password
local-share ./photos --password s3cretReceivers see a password form; file endpoints return 401 without a valid session cookie (HttpOnly, SameSite=Lax). Sessions live only in memory and die when the server stops. Passwords are stored as scrypt hashes, never plaintext.
Expiration
Sessions expire after --expires (default 30m). On expiry the server prints a notice and shuts down cleanly. Ctrl+C also shuts down cleanly (connections closed, sessions cleared).
Security
- Path traversal blocked (
../,..\, encoded variants, absolute paths) — verified by tests - Symlinks escaping the share root are excluded from listings and blocked on access
- Opaque file IDs (
file_<hex>); absolute paths never reach the browser - Filenames are escaped / transferred via safe headers (Unicode supported, CRLF neutralized)
- Security headers on every response (
nosniff,DENY, CSP, no-store for APIs) - ZIP entries are relative-only; archives stream with no temp files
Network requirements
- Both devices on the same Wi-Fi/LAN.
- The displayed URL uses the host's LAN address (e.g.
http://192.168.1.15:8787); the server binds0.0.0.0. - Windows may prompt to allow Node.js through the firewall — allow it for private networks. LocalShare never modifies firewall rules itself.
Troubleshooting
- Phone cannot connect: same Wi-Fi? Server still running? Correct LAN IP (not
127.0.0.1)? PC firewall allowing Node.js? Guest/AP isolation disabled on the router? - QR doesn't scan: type the printed URL manually.
- Port busy: pick another with
--port 8790, or omit--portto auto-increment. - Password prompt in a script: pass
--password <value>(no TTY needed).
Development
npm install
npm run build
npm run typecheck
npm test
npm run dev -- ./photos --verbosenpm run lint / npm run format are intentionally not configured (dependency-minimal MVP); npm run dev has the same CLI forwarding quirk as below — pass args after --.
Implementation status: CLI → HTTP server → File API → Web UI → QR → password/sessions → expiration → streaming/range/ZIP + progress → npm packaging. See AGENTS.md for the full spec.
License
MIT. See LICENSE.
