cameras/README.md
Michael Mainguy 5824db8ea9 Add MediaMTX video bridge: pinned installer and supervised localhost process
- npm run video:install downloads the pinned MediaMTX v1.21.0 for this
  platform, verifies its SHA-256 against checksums committed in
  src/lib/mediamtx-install.ts, and installs it into gitignored bin/.
- On server start, instrumentation launches MediaMTX with a generated
  owner-only config: API and WebRTC signaling on 127.0.0.1, only the ICE
  port (UDP 8189) on the LAN, a hashed per-boot API password, no
  anonymous users, unused protocols off. Restarts on crash with backoff,
  stops with the server; VIDEO_BRIDGE=off skips it.
- Camera streams are added to MediaMTX at runtime, on demand, with the
  stored login; nothing with a password is written to disk or echoed.
- rtspSourceWithLogin() reads a profile's RTSP URI over ONVIF.
- Export vrek log (live video goal, decisions, codec finding).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-19 15:33:55 -05:00

159 lines
6.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Cameras
A web interface for discovering and managing Hikvision and Annke IP cameras on your local network.
## Securing the web interface
The dashboard and its API are protected by a single admin login. The login is stored in a
file, **never** in plain text: the password is hashed with [scrypt](https://nodejs.org/api/crypto.html#cryptoscryptpassword-salt-keylen-options-callback)
(random salt, N=65536, r=8, p=1), so it can't be recovered from the file.
| Setting | Default |
| --- | --- |
| `ADMIN_AUTH_FILE` (environment variable, e.g. in `.env.local`) | `./.data/admin.json` |
If the file doesn't exist, the app starts **unsecured**: anyone who can reach it can view your
cameras and change their logins. To avoid ever running it that way, create the admin file
before the first start (below).
### Setting it up from the browser instead
With no admin file, the server prints a **one-time setup code** in its console at startup:
```
====================================================================
No admin login is set up: the camera dashboard is NOT secured.
To secure it from a browser, open /setup and enter this one-time code:
XLZ7-Q4MB
...
```
Opening the app sends you to `/setup`, which asks for that code plus the new admin username
and password. Only someone who can see the server console can claim the login. After 5 wrong
codes a new one is printed.
You can also choose **Skip for now and run unsecured**. Every page then shows a red warning
banner, the API stays open to anyone on the network, and the setup prompt returns the next
time the browser is restarted.
### Signing in
Once an admin exists, every page and API call needs a session: pages redirect to `/login`,
and the API answers `401`. A session lasts **12 hours from your last activity**. After 10
wrong passwords from one address (or 100 from all addresses) within 15 minutes, logins are
paused for up to 15 minutes. **Sign out** (top right) ends the session in that browser; to
sign out everywhere, change the password.
### Create the admin login (recommended)
```bash
npm run admin:create
```
It asks for a username and a password (at least 12 characters; typing is hidden, and you
confirm it), then writes the file with owner-only permissions (`0600`). Options:
```bash
npm run admin:create -- --username admin # only ask for the password
npm run admin:create -- --force # replace the existing admin (reset the password)
printf '%s\n' "$PW" | npm run admin:create -- --username admin # non-interactive, e.g. provisioning
```
### Without npm: a Node one-liner
Any Node 24+ can produce the same file. The password is read from the terminal without
echoing, so it never appears in your shell history or the process list:
```bash
(read -rs PW && export PW && umask 077 && mkdir -p .data && node -e '
const c = require("node:crypto"), N = 65536, r = 8, p = 1, salt = c.randomBytes(16);
const key = c.scryptSync(process.env.PW, salt, 64, { N, r, p, maxmem: 256 * N * r });
const passwordHash = ["scrypt", N, r, p, salt.toString("base64"), key.toString("base64")].join("$");
console.log(JSON.stringify({ version: 1, username: "admin", passwordHash }, null, 2));
' > .data/admin.json)
```
The parentheses run it in a subshell, so the password variable and the stricter `umask` end
with it.
Change `username: "admin"` to taste. Usernames are 1–64 letters, digits, or `. _ @ -`.
### File format
```json
{
"version": 1,
"username": "admin",
"passwordHash": "scrypt$65536$8$1$<salt, base64>$<64-byte key, base64>"
}
```
A file that exists but is malformed stops the app from authenticating anyone rather than
quietly turning security off; fix it or delete it.
### Forgot the password?
Run `npm run admin:create -- --force` (or delete the file and create it again). Changing the
password signs out every existing session.
## Live video (MediaMTX)
Browsers can't play the cameras' RTSP streams, so live video goes through
[MediaMTX](https://github.com/bluenviron/mediamtx), a single MIT-licensed binary that
the app will run on this machine only (localhost). Install the pinned build with:
```bash
npm run video:install
```
This downloads the MediaMTX release pinned in `src/lib/mediamtx-install.ts` for your
platform (macOS or Linux, Intel or ARM), checks its SHA-256 against the value committed
there, and puts the binary in `./bin/` (not checked in). A download that doesn't match
is refused and nothing is written. Re-running it does nothing if that build is already
installed.
To upgrade, change `version` in `MEDIAMTX_RELEASE` and replace every `sha256` with the
values from that release's `checksums.sha256` on GitHub (cross-check them against the
per-file digests on the release page), then run `npm run video:install` again.
---
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
## Getting Started
First, run the development server:
```bash
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
```
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
## Learn More
To learn more about Next.js, take a look at the following resources:
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
## Deploy on Vercel
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.