Files
Bonchellon 3954082e8d v0.3.2 — commit/submit progress, cancel, thumbnails, waitlist landing+admin
Client:
- Commit: batch `p4 reopen` so huge changelists (63k+) no longer blow the
  Windows command-line limit; live "N / total" progress + spinner during commit.
- Submit dialog: white arrow, "N of total" + % bar, running file log,
  Cancel button (aborts pre-commit; changelist stays pending).
- Disk scan: streaming reconcile with a live "found N files" counter + Cancel.
- Thumbnails: only decode browser-renderable image formats; glyph fallback
  (+ onError) instead of a broken-image icon for bmp/tga/dds/etc.

Landing + waitlist:
- waitlist-server: Express + SQLite email collector (dedup) with a secure
  admin panel (scrypt auth, rate-limited login, signed cookies) and CSV export.
- landing form now POSTs signups to the waitlist API.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 20:40:53 +03:00

52 lines
2.1 KiB
Markdown

# Exbyte Depot — Waitlist server + admin
Collects waitlist emails from the landing page (deduplicated) and gives you a
password-protected admin panel to browse them and export to CSV.
## Stack
- **express** — HTTP + static landing
- **better-sqlite3** — storage; `UNIQUE COLLATE NOCASE` on email → no duplicates, ever
- **express-rate-limit** — brute-force protection on the login endpoint
- **node:crypto** — scrypt password hashing + HMAC-signed session cookies (no extra deps)
## Setup
```bash
cd waitlist-server
npm install
cp .env.example .env
npm run gen-secret # → paste into SESSION_SECRET in .env
npm run set-password # type a password → paste the ADMIN_PASS_HASH line into .env
# set ADMIN_USER in .env (default: admin)
npm start
```
- Landing: http://localhost:8787/
- Admin: http://localhost:8787/admin
## How it works
- The landing form POSTs `{ email }` to **`POST /api/waitlist`**.
- Invalid emails are rejected; a repeat email is silently deduped (no dup row).
- A hidden honeypot field (`website`) traps bots.
- **`/admin`** requires login. Session is a signed, HttpOnly, SameSite=Strict cookie
(Secure in production), valid 8h. Wrong logins are rate-limited (8 / 15 min / IP).
- **Export CSV**: `GET /admin/export.csv` streams all signups (UTF-8 + BOM for Excel).
## Security notes
- No plaintext password anywhere — only a scrypt hash in `.env` (git-ignored).
- Refuses to start without `ADMIN_USER`, `ADMIN_PASS_HASH`, and a strong `SESSION_SECRET`.
- Security headers set (CSP, X-Frame-Options: DENY, nosniff, no-referrer).
- Behind a reverse proxy, set `TRUST_PROXY=1` so rate-limiting and stored IPs are correct,
and terminate TLS at the proxy (cookies become `Secure` when `NODE_ENV=production`).
## Deploy (Linux VPS, sketch)
1. `NODE_ENV=production`, real `.env`, `npm ci --omit=dev`.
2. Run under systemd (or pm2); put nginx/Caddy in front for TLS + `TRUST_PROXY=1`.
3. Point your domain at it; the landing is served from `../landing` (or set `LANDING_DIR`).
## Data
SQLite file at `data/waitlist.db` (git-ignored). Back it up to keep your list.