Files
rfid-database/README.md
T
Cursor Agent 7ac7710a23 Fix OIDC enablement: detect config at runtime, drop NEXT_PUBLIC flag
The SSO button required NEXT_PUBLIC_AUTH_OIDC_ENABLED, which is baked
at build time and silently fails under Docker runtime env. Drive the
login button from server-side AUTH_OIDC_* instead, and document IdP
redirect URI + AUTH_URL setup.
2026-08-24 00:10:27 +00:00

160 lines
5.0 KiB
Markdown

# RFID Database
PWA + REST API for storing LF/HF RFID tag dumps organized by site. Use the web UI in the field, or call `/api/v1` from scripts (and a future Proxmark CLI).
## Features
- Sites (A, B, C, …) with tag records (UID, protocol, keys, full dump)
- Multi-user auth (shared workspace, no RBAC yet) — local password + optional OIDC
- Personal API tokens (Settings UI) for Bearer auth
- Export: JSON, Proxmark, MCT, hex
- Import dumps + full JSON backup
- Installable PWA with offline read of cached pages
- Vitest unit/integration tests + GitHub Actions CI
## Quick start
```bash
cp .env.example .env
# set AUTH_SECRET to a long random string
npm install
npm run create-user -- --email [email protected] --password 'changeme' --name You
npm run dev
```
Open http://localhost:3000 and sign in.
## Environment
| Variable | Required | Description |
|----------|----------|-------------|
| `AUTH_SECRET` | yes | NextAuth secret |
| `AUTH_URL` | recommended | Public app URL (e.g. `https://rfid.example.com`) |
| `RFID_DB_PATH` | no | SQLite path (default `./data/rfid.db`) |
| `AUTH_OIDC_ISSUER` | for OIDC | Issuer URL (must expose `/.well-known/openid-configuration`) |
| `AUTH_OIDC_CLIENT_ID` | for OIDC | OIDC client id |
| `AUTH_OIDC_CLIENT_SECRET` | for OIDC | OIDC client secret |
| `AUTH_OIDC_NAME` | no | SSO button label (default `SSO`) |
### Enabling OIDC
1. In your IdP, create a **confidential** OIDC application.
2. Set the redirect / callback URI to:
```
{AUTH_URL}/api/auth/callback/oidc
```
Example: `http://localhost:3000/api/auth/callback/oidc`
3. Put these in `.env` (Docker Compose reads `.env` automatically):
```bash
AUTH_URL=http://localhost:3000
AUTH_SECRET=...long random...
AUTH_OIDC_ISSUER=https://sso.example.com/application/o/rfid/
AUTH_OIDC_CLIENT_ID=...
AUTH_OIDC_CLIENT_SECRET=...
AUTH_OIDC_NAME=Authentik
```
4. Restart the app (`docker compose up -d` or restart `npm run dev`).
5. Open `/login` — you should see **Sign in with Authentik** (or your `AUTH_OIDC_NAME`).
Notes:
- `AUTH_OIDC_ISSUER` must be exactly the issuer value from discovery (trailing slash matters for some IdPs).
- The IdP must return an **email** claim; accounts are created/linked by email.
- Local password login stays available alongside SSO.
## REST API (`/api/v1`)
Authenticate with a session cookie **or** `Authorization: Bearer rfid_…` (create tokens under **Settings → API tokens**).
| Method | Path | Purpose |
|--------|------|---------|
| GET/POST | `/api/v1/sites` | List / create sites |
| GET/PATCH/DELETE | `/api/v1/sites/{id}` | Site detail |
| GET/POST | `/api/v1/tags` | List / create tags |
| GET/PATCH/DELETE | `/api/v1/tags/{id}` | Tag detail |
| PUT | `/api/v1/tags/by-uid/{uid}?siteId=` | Upsert by UID |
| GET | `/api/v1/tags/{id}/export?format=` | `json` \| `proxmark` \| `mct` \| `hex` |
| POST | `/api/v1/tags/import` | Parse dump → create tag |
| GET | `/api/v1/search?q=` | Cross-site search |
| GET/POST | `/api/v1/backup` | Full backup export / import |
| GET/POST | `/api/v1/tokens` | List / create PATs |
| DELETE | `/api/v1/tokens/{id}` | Revoke PAT |
| GET | `/api/v1/me` | Current user |
### curl examples
```bash
# Create a token in the UI first, then:
export TOKEN=rfid_…
export HOST=http://localhost:3000
curl -sH "Authorization: Bearer $TOKEN" "$HOST/api/v1/sites"
curl -sH "Authorization: Bearer $TOKEN" \
"$HOST/api/v1/tags/$ID/export?format=proxmark" -o dump.json
curl -sH "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-X PUT "$HOST/api/v1/tags/by-uid/04A1B2C3?siteId=$SITE" \
-d '{"label":"Dock fob","frequency":"HF","protocol":"MIFARE_CLASSIC_1K","uid":"04A1B2C3","dumpData":{"size":"1K","sectors":[]},"keys":{"A":["FFFFFFFFFFFF"]}}'
```
## Tests & CI
```bash
npm test
npm run lint
npm run typecheck
npm run build
```
GitHub Actions runs on every pull request and push to `main`:
1. **lint / typecheck / test / Next.js build**
2. **`docker build`** — catches Dockerfile parse/build failures (the class of break that conflict markers previously caused)
## Docker
### docker compose (recommended)
```bash
cp .env.example .env
# set AUTH_SECRET to a long random string
# optional first user on boot:
# echo '[email protected]' >> .env
# echo 'CREATE_USER_PASSWORD=changeme' >> .env
docker compose up -d --build
```
App: http://localhost:3000 — SQLite persists in the `rfid-data` volume.
Create a user later (if you skipped bootstrap):
```bash
docker compose exec rfid-database \
npx tsx scripts/create-user.ts --email [email protected] --password 'secret' --name You
```
Stop / remove (keeps volume):
```bash
docker compose down
```
### Plain docker
```bash
docker build -t rfid-database .
docker run --rm -p 3000:3000 \
-e AUTH_SECRET=your-long-secret \
-e [email protected] \
-e CREATE_USER_PASSWORD=changeme \
-v rfid-data:/data \
rfid-database
```
## Security
Tag dumps often include sector keys. Keep the app behind HTTPS, do not expose it publicly without auth, and treat `data/rfid.db` as sensitive.