Initial Commit3

This commit is contained in:
2026-05-25 10:39:32 +08:00
parent 65df324fe3
commit 6fc2dc42aa
22 changed files with 21679 additions and 1 deletions

108
PatchProbe.Server/README.md Normal file
View File

@@ -0,0 +1,108 @@
# 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`.