major: kestrel is now a tak server (#6)
All checks were successful
ci/woodpecker/push/push Pipeline was successful

## Added

- CoT (Cursor on Target) server on port 8089 enabling ATAK/iTAK device connectivity
- Support for TAK stream protocol and traditional XML CoT messages
- TLS/SSL support with automatic fallback to plain TCP
- Username/password authentication for CoT connections
- Real-time device position tracking with TTL-based expiration (90s default)
- API endpoints: `/api/cot/config`, `/api/cot/server-package`, `/api/cot/truststore`, `/api/me/cot-password`
- TAK Server section in Settings with QR code for iTAK setup
- ATAK password management in Account page for OIDC users
- CoT device markers on map showing real-time positions
- Comprehensive documentation in `docs/` directory
- Environment variables: `COT_PORT`, `COT_TTL_MS`, `COT_REQUIRE_AUTH`, `COT_SSL_CERT`, `COT_SSL_KEY`, `COT_DEBUG`
- Dependencies: `fast-xml-parser`, `jszip`, `qrcode`

## Changed

- Authentication system supports CoT password management for OIDC users
- Database schema includes `cot_password_hash` field
- Test suite refactored to follow functional design principles

## Removed

- Consolidated utility modules: `authConfig.js`, `authSkipPaths.js`, `bootstrap.js`, `poiConstants.js`, `session.js`

## Security

- XML entity expansion protection in CoT parser
- Enhanced input validation and SQL injection prevention
- Authentication timeout to prevent hanging connections

## Breaking Changes

- Port 8089 must be exposed for CoT server. Update firewall rules and Docker/Kubernetes configurations.

## Migration Notes

- OIDC users must set ATAK password via Account settings before connecting
- Docker: expose port 8089 (`-p 8089:8089`)
- Kubernetes: update Helm values to expose port 8089

Co-authored-by: Madison Grubb <madison@elastiflow.com>
Reviewed-on: #6
This commit was merged in pull request #6.
This commit is contained in:
2026-02-17 16:41:41 +00:00
parent b18283d3b3
commit e61e6bc7e3
117 changed files with 5329 additions and 1040 deletions

11
docs/README.md Normal file
View File

@@ -0,0 +1,11 @@
# KestrelOS Documentation
Tactical Operations Center (TOC) for OSINT feeds: map view, cameras/devices, live sharing, and ATAK/iTAK integration.
## Quick Start
1. [Installation](installation.md) - npm, Docker, or Helm
2. [Authentication](auth.md) - First login (bootstrap admin or OIDC)
3. [Map and cameras](map-and-cameras.md) - Add devices and view streams
4. [ATAK and iTAK](atak-itak.md) - Connect TAK clients (port 8089)
5. [Share live](live-streaming.md) - Stream from mobile device (HTTPS required)

79
docs/atak-itak.md Normal file
View File

@@ -0,0 +1,79 @@
# ATAK and iTAK
KestrelOS acts as a **TAK Server**. ATAK (Android) and iTAK (iOS) connect on **port 8089** (CoT). Devices relay positions to each other and appear on the KestrelOS map.
## Connection
**Host:** KestrelOS hostname/IP
**Port:** `8089` (CoT)
**SSL:** Enable if server uses TLS (`.dev-certs/` or production cert)
**Authentication:**
- **Username:** KestrelOS identifier
- **Password:** Login password (local) or ATAK password (OIDC; set in **Account**)
## ATAK (Android)
1. **Settings****Network****Connections** → Add **TAK Server**
2. Set **Host** and **Port** (`8089`)
3. Enable **Use Authentication**, enter username/password
4. Save and connect
## iTAK (iOS)
**Option A - QR code (easiest):**
1. KestrelOS **Settings****TAK Server** → Scan QR with iTAK
2. Enter username/password when prompted
**Option B - Manual:**
1. **Settings****Network** → Add **TAK Server**
2. Set **Host**, **Port** (`8089`), enable SSL if needed
3. Enable **Use Authentication**, enter username/password
4. Save and connect
## Self-Signed Certificate (iTAK)
If server uses self-signed cert (`.dev-certs/`):
**Upload server package:**
1. KestrelOS **Settings****TAK Server****Download server package (zip)**
2. Transfer to iPhone (AirDrop, email, Safari)
3. iTAK: **Settings****Network****Servers****+** → **Upload server package**
4. Enter username/password
**Or use plain TCP:**
1. Stop KestrelOS, remove `.dev-certs/`, restart
2. Add server with **SSL disabled**
**ATAK (Android):** Download trust store from `https://your-server/api/cot/truststore`, import `.p12` (password: `kestrelos`), or use server package/plain TCP.
## OIDC Users
OIDC users must set an **ATAK password** first:
1. Sign in with OIDC
2. **Account****ATAK / device password** → set password
3. Use KestrelOS username + ATAK password in TAK client
## Configuration
| Variable | Default | Description |
|----------|---------|-------------|
| `COT_PORT` | `8089` | CoT server port |
| `COT_TTL_MS` | `90000` | Device timeout (~90s) |
| `COT_REQUIRE_AUTH` | `true` | Require authentication |
| `COT_SSL_CERT` | `.dev-certs/cert.pem` | TLS cert path |
| `COT_SSL_KEY` | `.dev-certs/key.pem` | TLS key path |
## Troubleshooting
**"Error authenticating" with no `[cot]` logs:**
- Connection not reaching server (TLS handshake failed or firewall blocking)
- Check server logs show `[cot] CoT server listening on 0.0.0.0:8089`
- Verify port `8089` (not `3000`) and firewall allows it
- For TLS: trust cert (server package) or use plain TCP
**"Error authenticating" with `[cot]` logs:**
- Username must be KestrelOS identifier
- Password must match (local: login password; OIDC: ATAK password)
**Devices not on map:** They appear only while sending updates; drop off after TTL (~90s).

39
docs/auth.md Normal file
View File

@@ -0,0 +1,39 @@
# Authentication
KestrelOS supports **local login** (username/email + password) and optional **OIDC** (SSO). All users must sign in.
## Local Login
**First run:** On first start, KestrelOS creates an admin account:
- If `BOOTSTRAP_EMAIL` and `BOOTSTRAP_PASSWORD` are set → that account is created
- Otherwise → default admin (`admin`) with random password printed in terminal
**Sign in:** Open `/login`, enter identifier and password. Change password or add users via **Members** (admin only).
## OIDC (SSO)
**Enable:** Set `OIDC_ISSUER`, `OIDC_CLIENT_ID`, `OIDC_CLIENT_SECRET`. Optional: `OIDC_LABEL`, `OIDC_REDIRECT_URI`, `OIDC_SCOPES`.
**IdP setup:**
1. Create OIDC client in your IdP (Keycloak, Auth0, etc.)
2. Set redirect URI: `https://<your-host>/api/auth/oidc/callback`
3. Copy Client ID and Secret to env vars
**Sign up:** Users sign up at the IdP. First OIDC login in KestrelOS creates their account automatically.
**Redirect URI:** Defaults to `{APP_URL}/api/auth/oidc/callback` (uses `NUXT_APP_URL`/`APP_URL` or falls back to `HOST`/`PORT`).
## OIDC Users and ATAK/iTAK
OIDC users don't have a KestrelOS password. To use ATAK/iTAK:
1. Sign in with OIDC
2. Go to **Account** → set **ATAK password**
3. Use KestrelOS username + ATAK password in TAK client
## Roles
- **Admin** - Manage users, edit POIs, add/edit devices (API)
- **Leader** - Edit POIs, add/edit devices (API)
- **Member** - View map/cameras/POIs, use Share live
Only admins can change roles (Members page).

61
docs/installation.md Normal file
View File

@@ -0,0 +1,61 @@
# Installation
Run KestrelOS from source (npm), Docker, or Kubernetes (Helm).
## npm (from source)
```bash
git clone <repository-url> kestrelos
cd kestrelos
npm install
npm run dev
```
Open **http://localhost:3000**. First run creates `data/kestrelos.db` and bootstraps an admin (see [Authentication](auth.md)).
**Production:**
```bash
npm run build
npm run preview
# or
node .output/server/index.mjs
```
Set `HOST=0.0.0.0` and `PORT` for production.
## Docker
```bash
docker build -t kestrelos:latest .
docker run -p 3000:3000 -p 8089:8089 \
-v kestrelos-data:/app/data \
kestrelos:latest
```
Expose ports **3000** (web/API) and **8089** (CoT for ATAK/iTAK).
## Helm (Kubernetes)
**From registry:**
```bash
helm repo add keligrubb --username USER --password TOKEN \
https://git.keligrubb.com/api/packages/keligrubb/helm
helm install kestrelos keligrubb/kestrelos
```
**From source:**
```bash
helm install kestrelos ./helm/kestrelos
```
Configure in `helm/kestrelos/values.yaml`. Health: `GET /health`, `/health/live`, `/health/ready`.
## Environment Variables
| Variable | Default | Description |
|----------|---------|-------------|
| `HOST` | Nuxt default | Bind address (use `0.0.0.0` for all interfaces) |
| `PORT` | `3000` | Web/API port |
| `DB_PATH` | `data/kestrelos.db` | SQLite database path |
See [Authentication](auth.md) for auth variables. See [ATAK and iTAK](atak-itak.md) for CoT options.

44
docs/live-streaming.md Normal file
View File

@@ -0,0 +1,44 @@
# Share Live
Stream your phone's camera and location to KestrelOS. Appears as a **live session** on the map and in **Cameras**. Uses **WebRTC** (Mediasoup) and requires **HTTPS** on mobile.
## Usage
1. Open **Share live** (sidebar → **Share live** or `/share-live`)
2. Tap **Start sharing**, allow camera/location permissions
3. Device appears on map and in **Cameras**
4. Tap **Stop sharing** to end
**Permissions:** Admin/leader can start sharing. All users can view live sessions.
## Requirements
- **HTTPS** (browsers require secure context for camera/geolocation)
- **Camera and location permissions**
- **WebRTC ports:** UDP/TCP `40000-49999` open on server
## Local Development
**Generate self-signed cert:**
```bash
chmod +x scripts/gen-dev-cert.sh
./scripts/gen-dev-cert.sh 192.168.1.123 # Your LAN IP
npm run dev
```
**On phone:** Open `https://192.168.1.123:3000`, accept cert warning, sign in, use Share live.
## WebRTC Configuration
- Server auto-detects LAN IP for WebRTC
- **Docker/multiple NICs:** Set `MEDIASOUP_ANNOUNCED_IP` to client-reachable IP/hostname
- **"Wrong host" error:** Use same URL on phone/server, or set `MEDIASOUP_ANNOUNCED_IP`
## Troubleshooting
| Issue | Fix |
|-------|-----|
| "HTTPS required" | Use `https://` (not `http://`) |
| "Media devices not available" | Ensure HTTPS and browser permissions |
| "WebRTC: failed" / "Wrong host" | Set `MEDIASOUP_ANNOUNCED_IP`, open firewall ports `40000-49999` |
| Stream not visible | Check server reachability and firewall |

52
docs/map-and-cameras.md Normal file
View File

@@ -0,0 +1,52 @@
# Map and Cameras
KestrelOS shows a **map** with devices, POIs, live sessions (Share live), and ATAK/iTAK positions. Click markers or use **Cameras** page to view streams.
## Map Layers
- **Devices** - Fixed feeds (IPTV, ALPR, CCTV, NVR, etc.) added via API
- **POIs** - Points of interest (admin/leader can edit)
- **Live sessions** - Mobile devices streaming via Share live
- **CoT (ATAK/iTAK)** - Amber markers for connected TAK devices (position only)
## Cameras
A **camera** is either:
1. A **device** - Fixed feed with stream URL
2. A **live session** - Mobile device streaming via Share live
View via map markers or **Cameras** page (sidebar).
## Device Types
| device_type | Use case |
|-------------|----------|
| `alpr`, `nvr`, `doorbell`, `feed`, `traffic`, `ip`, `drone` | Labeling/filtering |
**source_type:** `mjpeg` (MJPEG over HTTP) or `hls` (HLS `.m3u8` playlist)
Stream URLs must be `http://` or `https://`.
## API: Devices
**Create:** `POST /api/devices` (admin/leader)
```json
{
"name": "Main gate ALPR",
"device_type": "alpr",
"lat": 37.7749,
"lng": -122.4194,
"stream_url": "https://alpr.example.com/stream.m3u8",
"source_type": "hls"
}
```
**List:** `GET /api/devices`
**Update:** `PATCH /api/devices/:id`
**Delete:** `DELETE /api/devices/:id`
**Cameras endpoint:** `GET /api/cameras` returns devices + live sessions + CoT entities.
## POIs
Admins/leaders add/edit from **POI** page (sidebar). POIs appear as map pins (reference only, no stream).

BIN
docs/screenshot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 KiB