114 lines
2.7 KiB
Markdown
114 lines
2.7 KiB
Markdown
# Cyber Dashboard
|
||
|
||
Real-time cyber monitoring dashboard: ANSSI/CERT-FR feeds, geopolitical news, Kaspersky live map, and Root-me ranking.
|
||
|
||
## Requirements
|
||
|
||
- Node.js ≥ 18
|
||
- npm
|
||
|
||
## Installation
|
||
|
||
```bash
|
||
npm install
|
||
```
|
||
|
||
## Configuration
|
||
|
||
| Environment variable | Description | Required |
|
||
|---|---|---|
|
||
| `ROOTME_API_KEY` | Root-me API key (Profile → Preferences) | Yes (Root-me widget) |
|
||
| `DASHBOARD_PORT` | Listening port (default: `3000`) | No |
|
||
|
||
## Config files
|
||
|
||
**`logins.txt`** — one numeric Root-me user ID per line:
|
||
```
|
||
546528
|
||
123456
|
||
```
|
||
|
||
The ID can be found in the Root-me profile URL: `root-me.org/Username?inc=score&id_auteur=XXXXXX`
|
||
|
||
## Start
|
||
|
||
```bash
|
||
ROOTME_API_KEY=<key> node server.js
|
||
```
|
||
|
||
Then open `http://localhost:3000`.
|
||
|
||
## Manual alerts
|
||
|
||
```bash
|
||
# Trigger an alert
|
||
./alert.sh "INTRUSION DETECTED"
|
||
|
||
# With custom HTML
|
||
./alert.sh "TITLE" path/to/content.html
|
||
|
||
# Dismiss the alert
|
||
./dismiss.sh
|
||
```
|
||
|
||
## Architecture
|
||
|
||
```
|
||
dashboard/
|
||
├── server.js # Express + WebSocket server
|
||
├── public/
|
||
│ ├── index.html # 2×2 grid with carousel
|
||
│ ├── style.css # Dark cyber theme
|
||
│ └── app.js # WS client + feed polling
|
||
├── logins.txt # Root-me user IDs to track
|
||
├── alert.sh # Triggers an alert via POST
|
||
└── dismiss.sh # Dismisses the alert via DELETE
|
||
```
|
||
|
||
### Endpoints
|
||
|
||
| Method | Route | Description |
|
||
|---|---|---|
|
||
| `GET` | `/api/feeds/anssi` | CERT-FR bulletins (RSS) |
|
||
| `GET` | `/api/feeds/geo` | Geopolitical news (Google News RSS) |
|
||
| `GET` | `/api/rootme` | Root-me ranking (server cache) |
|
||
| `GET` | `/api/alert` | Current alert state |
|
||
| `POST` | `/api/alert` | Trigger an alert `{ message, html, image }` |
|
||
| `DELETE` | `/api/alert` | Dismiss the alert |
|
||
| `GET` | `/proxy?url=` | HTTP proxy (strips X-Frame-Options/CSP) |
|
||
|
||
### WebSocket events
|
||
|
||
The server pushes the following events to all connected clients:
|
||
|
||
| `type` | Payload | Description |
|
||
|---|---|---|
|
||
| `alert` | `{ message, html, image }` | Alert triggered |
|
||
| `dismiss` | — | Alert dismissed |
|
||
| `rootme_update` | `{ ranking[] }` | Updated Root-me ranking |
|
||
| `rootme_flag` | `{ login, gained, newScore }` | A player just flagged a challenge |
|
||
|
||
## Contributing
|
||
|
||
### Commit conventions
|
||
|
||
```
|
||
<scope>: <short description>
|
||
```
|
||
|
||
Examples:
|
||
```
|
||
root-me: basic ranking
|
||
alerts: new alerts
|
||
all: init
|
||
```
|
||
|
||
The scope reflects the component changed (`root-me`, `alerts`, `feeds`, `ui`, `server`, `all` for cross-cutting changes).
|
||
|
||
### Adding a widget
|
||
|
||
1. Add a `<section class="widget" id="widget-xxx">` in `index.html`
|
||
2. Assign its grid cell in `style.css` (`grid-column` / `grid-row`)
|
||
3. Add it to `CAROUSEL_PAGES` in `app.js`
|
||
4. Add the corresponding endpoint in `server.js` if needed
|