.-._ _ _ _ _ _ _ _ _
.-''-.__.-'00 '-' ' ' ' ' ' ' ' '-.
'.___ ' . .--_'-' '-' '-' _'-' '._
DLL : V 'vv-' '_ '. .' _..' '.'.
'=.____.=_.--' :_.__.__:_ '. : :
(((____.-' '-. / : :
(((-'\ .' /
_____..' .'
'-._____.-'
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
I P O V T I C H · b y K R O K O D L L
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Visualise Nmap (XML, gnmap) and tabular host data as an interactive network topology graph. Local-first by default: no cloud, no API key required.
Stack: FastAPI, React, React Flow, TypeScript. UI: English and French.
- Parse scan exports and tables, build a graph in the browser.
- Runs on your machine; optional environment variables harden the API for shared or internet-facing deployments.
- REST API under
/v1(for examplePOST /v1/parse/nmap). OpenAPI UI at/docswhen enabled.
| Tool | Version |
|---|---|
| Python | 3.11+ |
| Node.js | 20 LTS+ |
API
cd backend && python3 -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
uvicorn app.main:app --host 127.0.0.1 --port 8001Web UI
cd frontend && npm ci && npm run devOpen the URL printed by Vite (usually http://127.0.0.1:5173).
Sanity check
curl -s http://127.0.0.1:8001/healthExpect {"status":"ok"}.
Sample input: data/nmap_minimal.xml.
For on-premise installs, copy backend/.env.example to backend/.env and frontend/.env.example to frontend/.env.local (or .env), then set values. Comments in each file list variables; never commit real secrets.
| Variable | Purpose |
|---|---|
MAX_UPLOAD_BYTES |
Upload cap (default 10 MiB, max 100 MiB). |
CORS_ORIGINS |
Comma-separated full origins (e.g. https://app.example.com). * is rejected. Default includes Vite on port 5173. |
IPOVITCH_API_KEY |
Optional static key via Authorization: Bearer or X-Api-Key on /v1/*. Prefer JWT in the browser (no secret in the bundle). |
IPOVITCH_JWT_SECRET |
At least 32 characters. Signs access tokens after login. Use with IPOVITCH_LOGIN_PASSWORD or IPOVITCH_LOGIN_PASSWORD_HASH. |
IPOVITCH_LOGIN_PASSWORD |
Shared password for POST /v1/auth/token (dev / small teams). Production: prefer IPOVITCH_LOGIN_PASSWORD_HASH (bcrypt). |
IPOVITCH_LOGIN_PASSWORD_HASH |
Bcrypt hash of the dashboard password. |
IPOVITCH_JWT_TTL_SECONDS |
Token lifetime (default 8h, min 60s, max 7 days). |
IPOVITCH_OPENAPI_ENABLED |
Set to 0, false, or off to disable /docs, /redoc, and /openapi.json in production. |
IPOVITCH_RATE_LIMIT_PER_MINUTE |
Per-IP limit on all routes (including /health). Omit for unlimited (typical locally). |
IPOVITCH_LOGIN_RATE_PER_MINUTE |
Per-IP limit on POST /v1/auth/token only (default 20). 0 disables (not recommended on the public internet). Max 500. |
IPOVITCH_HSTS_MAX_AGE |
If set (seconds), sends Strict-Transport-Security. Use only when the API is served over HTTPS end-to-end. |
| Variable | Purpose |
|---|---|
VITE_API_BASE |
API origin (no path suffix). The UI calls that host under /v1/.... Must be http:// or https:// without credentials. |
VITE_API_KEY |
Same value as IPOVITCH_API_KEY, embedded at build time (not secret). Prefer UI login and JWT in sessionStorage when the API exposes POST /v1/auth/token. |
The API can issue short-lived JWTs after a password check; the browser stores the token in sessionStorage. That pattern is similar in spirit to SysReptor API tokens. Built-in OIDC or enterprise SSO is not included: use a reverse proxy (Authelia, OAuth2 Proxy, Cloudflare Access, etc.) if you need an IdP.
- Response headers include
X-Content-Type-Options,X-Frame-Options,Referrer-Policy,Permissions-Policy, andCache-Control: no-storeon/v1,/docs, and OpenAPI. - JWTs use fixed
iss/audand required claims. Login password length is capped.POST /v1/auth/tokenis rate-limited per IP. Oversized bodies are rejected early viaContent-Length(also setclient_max_body_sizeon your reverse proxy). - The SPA does not render user graph data with
dangerouslySetInnerHTML. A JWT insessionStorageis still exposed if XSS exists: use CSP and keep dependencies patched for high-threat deployments. - Do not expose the API without TLS on untrusted networks.
- Bind Uvicorn to loopback or a private interface, or terminate TLS at nginx, Caddy, or Traefik.
- Prefer
IPOVITCH_JWT_SECRETandIPOVITCH_LOGIN_PASSWORD_HASH, plusIPOVITCH_OPENAPI_ENABLED=0. SetIPOVITCH_RATE_LIMIT_PER_MINUTE(e.g.120). ReserveIPOVITCH_API_KEYfor non-browser clients if needed. - Set
CORS_ORIGINSto your real UI origins only. - Behind a proxy, configure trusted forwarded headers if rate limits use client IP; otherwise every client may look like the proxy.
- Treat
VITE_API_KEYas a convenience for local automation, not confidentiality.
Backend
cd backend && source .venv/bin/activate && ruff check app tests && pytestapp/ is covered at 100% line coverage when you run pytest locally.
Frontend
cd frontend && npm run lint && npm test && npm run build| Path | Contents |
|---|---|
backend/app/ |
API, parsers, models |
backend/tests/ |
Pytest and fixtures |
frontend/src/ |
UI, graph layout, API client |
Keep package-lock.json committed and review major dependency bumps (React Flow, jsPDF, etc.) explicitly.