# Dokumentasi API

Ada dua API: **Engine (FastAPI, port 8000)** untuk sensor, dan **Dashboard API (PHP, `api.php`)** untuk antarmuka web.

## 1. Engine — `POST /api/v1/ingest`
Dipakai sensor. Header: `X-Sensor-Key: <kunci sensor>`. Kunci dibuat di dashboard (Sensor Management) dan hanya
disimpan sebagai hash SHA-256. Batas: 1 MB per request, 500 event per batch.

```json
{
  "sensor_code": "sim-linux-01",
  "hostname": "web-01",
  "os": "linux",
  "events": [
    {"type": "http_request", "ip": "203.0.113.9", "method": "GET", "path": "/p.php", "query": "id=1", "body": ""},
    {"type": "login", "ip": "198.51.100.7", "username": "admin", "success": false},
    {"type": "firewall", "ip": "192.0.2.50", "dst_port": 22},
    {"type": "metrics", "metrics": {"cpu": 40, "mem": 55, "disk": 60}, "services": {"nginx": "running"}},
    {"type": "file_integrity", "files": [{"path": "/etc/hosts", "hash": "<sha256 atau null jika hilang>"}]},
    {"type": "syslog", "os": "linux", "message": "Failed password for ..."},
    {"type": "admin_action", "action": "delete_user", "ip": "10.0.0.2"},
    {"type": "heartbeat"}
  ]
}
```
Respon `200`: `{"status":"accepted","processed":N,"findings":M}`. Kode lain: `401` (sensor/kunci salah),
`413` (terlalu besar), `422` (tipe/ukuran field tidak valid).

`GET /health` → `{"status":"ok"}`. Dokumentasi interaktif `/docs` hanya aktif bila `APP_ENV` bukan `production`.

### Aturan deteksi (dapat diatur di Settings)
| Kategori | Pemicu | Risiko |
|---|---|---|
| brute_force | ≥ `brute_force_threshold` login gagal per IP dalam `brute_force_window_min` | high / critical (≥3× ambang) |
| sql_injection, xss | pola pada path/query/body (URL-decode berlapis) | warning (1 indikator) / high (>1) |
| path_traversal | `../`, berkas sistem sensitif, null byte | high |
| port_scan | ≥ `port_scan_threshold` port berbeda per IP dalam `port_scan_window_sec` | high |
| file_tampering | hash berbeda dari baseline / berkas hilang | critical / high |
| unusual_admin | di luar jam kerja atau IP baru | warning |
| traffic_spike | menit terakhir ≥ `traffic_spike_factor` × rata-rata (min `traffic_spike_min`) | warning |
| sensor_failure | tidak ada data > `sensor_offline_sec` | high |

Semua temuan berstatus **suspected (dugaan)**. Hanya analis yang dapat mengubahnya menjadi *confirmed* atau
*false_positive*. Temuan `high`/`critical` otomatis membuat alert; alert yang sama (kategori+IP) tidak diulang dalam 10 menit.

## 2. Dashboard API — `api.php?action=...`
Wajib login (cookie sesi). Metode `POST` wajib header `X-CSRF-Token` (token ada di `<meta name="csrf">`) dan body JSON.
Semua respons JSON; waktu dalam UTC (ISO 8601 dengan `Z`).

**GET** (viewer ke atas): `overview`, `events`, `attacks`, `logins`, `network`, `fim`, `health`, `alerts`, `incidents`, `reports?period=daily|weekly|monthly`, `me`.
Filter (query string): `from`, `to` (YYYY-MM-DD), `category`, `risk`, `ip`, `source`, `status`, `limit` (≤200), `offset`.
**GET** analyst: `sensors`. **GET** admin: `users`, `audit`, `settings`.

**POST**
| action | role | body |
|---|---|---|
| `alert_read` | analyst | `{"id":1}` atau `{"all":true}` |
| `event_status` | analyst | `{"id":1,"status":"new|investigating|resolved|false_positive"}` |
| `attack_verify` | analyst | `{"id":1,"status":"suspected|confirmed|false_positive"}` |
| `incident_create` | analyst | `{"event_id":1,"title":"...","chronology":"..."}` |
| `incident_update` | analyst | `{"id":1,"status":"open|investigating|resolved|closed","chronology":"","actions_taken":""}` |
| `fim_accept` | admin | `{"id":<id baris file_integrity_logs>}` — jadikan hash terbaru sebagai baseline |
| `user_create` | admin | `{"username","email","password","role"}` |
| `user_toggle` | admin | `{"id":2}` |
| `sensor_create` | admin | `{"sensor_code","os","hostname","sensor_type"}` → `api_key` hanya tampil sekali |
| `settings_update` | admin | `{"settings":{"brute_force_threshold":"5"}}` (divalidasi rentangnya; memicu alert perubahan konfigurasi) |

Kode kesalahan: `401` belum login, `403` role/CSRF, `404`, `409` duplikat, `422` validasi, `429` (login), `500` (tanpa detail internal).
