109 lines
3.2 KiB
Markdown
109 lines
3.2 KiB
Markdown
# PatchProbe Server
|
|
|
|
Node.js / Express server that receives scan payloads from enrolled PatchProbe devices and exposes a management API.
|
|
|
|
---
|
|
|
|
## First-run setup
|
|
|
|
### 1. Configure environment
|
|
|
|
```bash
|
|
cp config.example.env .env
|
|
# Edit .env — at minimum set PATCHPROBE_ADMIN_KEY_HASH (see below)
|
|
```
|
|
|
|
### 2. Generate an admin key
|
|
|
|
```bash
|
|
node server.js --gen-admin-key
|
|
# Prints a random key and its bcrypt hash.
|
|
# Paste the hash into PATCHPROBE_ADMIN_KEY_HASH in .env
|
|
# Store the key itself securely — it is only shown once.
|
|
```
|
|
|
|
### 3. Start the server
|
|
|
|
```bash
|
|
npm start # production
|
|
npm run dev # development (auto-reload, pretty logs)
|
|
```
|
|
|
|
On first start the SQLite database is created automatically at `DB_PATH` (default `./patchprobe.db`).
|
|
|
|
---
|
|
|
|
## Enrolling a device end-to-end
|
|
|
|
### Step 1 — Create an enrollment token (admin)
|
|
|
|
```bash
|
|
curl -X POST http://localhost:3000/api/admin/tokens \
|
|
-H "Authorization: Bearer <admin-key>" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"label": "lab-devices", "expiresInDays": 7, "maxUses": 10}'
|
|
# Response: { "token": "<64-char hex>", ... }
|
|
# The token value is only returned here — copy it now.
|
|
```
|
|
|
|
### Step 2 — Enroll the device (on the endpoint)
|
|
|
|
```bash
|
|
PatchProbe.exe enroll --server-url http://your-server:3000 --enrollment-key <token>
|
|
```
|
|
|
|
The client POSTs to `POST /api/enrollments`, receives a `deviceId`, and stores credentials encrypted on disk.
|
|
|
|
### Step 3 — Run a scan
|
|
|
|
```bash
|
|
PatchProbe.exe scan
|
|
# Collects evidence and POSTs signed payload to POST /api/scans
|
|
```
|
|
|
|
---
|
|
|
|
## Admin API reference
|
|
|
|
All `/api/admin/*` routes require `Authorization: Bearer <admin-key>`.
|
|
|
|
| Method | Path | Description |
|
|
|--------|------|-------------|
|
|
| `POST` | `/api/admin/tokens` | Create enrollment token (`label`, `expiresInDays?`, `maxUses?`) |
|
|
| `GET` | `/api/admin/tokens` | List tokens (value masked as `ab12****`) |
|
|
| `DELETE` | `/api/admin/tokens/:token` | Revoke a token |
|
|
| `GET` | `/api/admin/devices` | List all enrolled devices |
|
|
| `DELETE` | `/api/admin/devices/:id` | Revoke a device (blocks future scan uploads) |
|
|
| `GET` | `/api/admin/devices/:id/scans` | Scan summaries for a device |
|
|
|
|
---
|
|
|
|
## Device API (used by PatchProbe.exe — do not change)
|
|
|
|
| Method | Path | Auth |
|
|
|--------|------|------|
|
|
| `POST` | `/api/enrollments` | Enrollment token in body |
|
|
| `POST` | `/api/scans` | ECDSA device signature headers |
|
|
| `GET` | `/api/scans` | None |
|
|
| `GET` | `/api/scans/:id` | None |
|
|
| `DELETE` | `/api/scans/:id` | None |
|
|
|
|
---
|
|
|
|
## Smoke test
|
|
|
|
```bash
|
|
# Start server first (auth must be enabled, admin key configured)
|
|
node test-auth.js
|
|
```
|
|
|
|
---
|
|
|
|
## Architecture notes
|
|
|
|
- **Persistence**: SQLite via Node.js built-in `node:sqlite` (no native compilation). WAL mode, foreign keys enforced.
|
|
- **Device auth**: ECDSA-P256-SHA256 over `deviceId\ntimestamp\nbase64(sha256(rawBody))`. Raw body bytes are captured before JSON parsing so re-serialization cannot alter the signed content.
|
|
- **Admin auth**: bcrypt-hashed bearer key. bcrypt comparison is async (non-blocking).
|
|
- **Enrollment tokens**: constant-time comparison iterates all active tokens without early exit to prevent timing oracles.
|
|
- **Rate limiting**: 10 req/min on `/api/enrollments`, 60 req/min on `/api/scans`.
|