Ctrl K
ComunidadGuías…

README.md

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# MynetworK - Multi-Source Network Dashboard

<div align="center">

<img src="src/icons/logo_mynetwork.svg" alt="MynetworK" width="96" height="96" />

![MynetworK](https://img.shields.io/badge/MynetworK-0.13.12-111827?style=for-the-badge)
![Status](https://img.shields.io/badge/Status-PRODUCTION-374151?style=for-the-badge)
[![GHCR](https://img.shields.io/badge/GHCR-mynetwork-0ea5e9?style=for-the-badge&logo=docker&logoColor=white)](https://github.com/Erreur32/MynetworK/pkgs/container/mynetwork)
![React](https://img.shields.io/badge/React-19-111827?style=for-the-badge&logo=react&logoColor=38bdf8)
![TypeScript](https://img.shields.io/badge/TypeScript-5.8-111827?style=for-the-badge&logo=typescript&logoColor=60a5fa)

![Docker](https://img.shields.io/badge/Docker-Ready-1f2937?style=for-the-badge&logo=docker&logoColor=38bdf8)
[![OSSF Scorecard](https://img.shields.io/ossf-scorecard/github.com/Erreur32/MynetworK?style=for-the-badge&label=Scorecard)](https://scorecard.dev/viewer/?uri=github.com/Erreur32/MynetworK)
[![CodeQL](https://img.shields.io/badge/CodeQL-active-brightgreen?style=for-the-badge&logo=github)](https://github.com/Erreur32/MynetworK/security/code-scanning)
[![SonarCloud](https://img.shields.io/sonar/quality_gate/Erreur32_MynetworK?server=https%3A%2F%2Fsonarcloud.io&style=for-the-badge&logo=sonarcloud&logoColor=white&label=Sonar)](https://sonarcloud.io/summary/overall?id=Erreur32_MynetworK)

![License](https://img.shields.io/badge/License-MIT-111827?style=for-the-badge&color=111827&logoColor=white)


<h1 align="center">MynetworK</h1>
<p align="center">
  Unified Freebox + UniFi management + Network Scanner.
</p>

**📖 [Read in French (Lire en français)](README.fr.md)**



<p align="center">
  <sub>Powered by</sub><br/>
  <img src="img-capture/free-sas.png" alt="Freebox" height="32" />
  &nbsp;&nbsp;
  <img src="img-capture/ubiquiti-networks.svg" alt="Ubiquiti Unifi" height="32" />
</p>

**A multi-source network dashboard to manage Freebox, UniFi  and  Network Scanner**

[Installation](#installation) | [Features](#features) | [Configuration](#configuration) | [MCP](#mcp-model-context-protocol) | [Home Assistant](#home-assistant)

</div>


---


## Overview

**MynetworK** is a unified dashboard to manage and monitor multiple local network data sources:

![Capture Dashboard](https://github.com/Erreur32/MynetworK/blob/main/img-capture/dashboard.png?raw=true)

- **Freebox** - Full management of your Freebox (Ultra, Delta, Pop)
- **UniFi Controller** - Monitor and manage your UniFi infrastructure
- **Network Scan** - Device discovery and analysis with automatic vendor detection




## Features

- 🔐 **User authentication** - JWT system with role management (admin, user, viewer)
- 🔌 **Plugin system** - Modular architecture to easily add new data sources
- 📊 **Unified dashboard** - Centralized view of all plugin data
- 📝 **Full logging** - Traceability of all actions with advanced filters
- 👥 **User management** - Administration interface to manage access
- 🐳 **Docker ready** - Simplified deployment with Docker Compose
- 🌐 **Internationalization (i18n)** - English (default) and French; language switcher in header. See [Docs/INTERNATIONALIZATION.md](Docs/INTERNATIONALIZATION.md).
- 🤖 **MCP server** - Native [Model Context Protocol](https://modelcontextprotocol.io) server for Freebox, UniFi and the network scanner, LAN-only. See [MCP](#mcp-model-context-protocol) below.

> [!TIP]
>  
> <details>
> <summary> 🖼️ Click to view other screenshots</summary>
> 
> ![Search Ip](https://github.com/Erreur32/MynetworK/blob/main/img-capture/search_ip.png?raw=true)
>
> ![MyNetwork Scan](https://github.com/Erreur32/MynetworK/blob/main/img-capture/Scan_network.png?raw=true)
>
> ![Unifi Tab](https://github.com/Erreur32/MynetworK/blob/main/img-capture/unifi_tab.png?raw=true)
>
> ![Topology](https://github.com/Erreur32/MynetworK/blob/main/img-capture/mynetwork_topology.png?raw=true)
> 
> </details>

 
> [!NOTE]
> A dedicated and **fully functional** version for **Home Assistant** is available here:   [https://github.com/Erreur32/HA_mynetwork](https://github.com/Erreur32/HA_mynetwork)
> 


## Installation

### Prerequisites

- Docker and Docker Compose
- Local network access to Freebox/UniFi

### docker-compose.yml

```yaml
services:
  mynetwork:
    image: ghcr.io/erreur32/mynetwork:latest
    restart: unless-stopped

    ports:
      # Dashboard external port (default: 7505)
      - "${DASHBOARD_PORT:-7505}:3000"

    environment:
      # Required secret (no fallback in production)
      JWT_SECRET: ${JWT_SECRET}

      # Configuration
      CONFIG_FILE_PATH: ${CONFIG_FILE_PATH:-/app/config/mynetwork.conf}
      FREEBOX_HOST: ${FREEBOX_HOST:-mafreebox.freebox.fr}
      FREEBOX_TOKEN_FILE: /app/data/freebox_token.json

      # Host metrics access
      HOST_ROOT_PATH: ${HOST_ROOT_PATH:-/host}

      # PUBLIC_URL (optional, only with reverse proxy)
      # PUBLIC_URL: https://dashboard.example.com

    volumes:
      # Persistent data (Freebox token, local DB, etc.)
      - ./data:/app/data

      # Host metrics (read-only) — CPU, RAM, network, ARP table, hostname
      - /proc:/host/proc:ro
      - /sys:/host/sys:ro
      - /etc/hostname:/host/etc/hostname:ro
      - /etc/hosts:/host/etc/hosts:ro

    # Network capabilities for scan (ping / ARP)
    cap_add:
      - NET_RAW
      - NET_ADMIN
      - SETUID
      - SETGID
    cap_drop:
      - ALL

    healthcheck:
      test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:3000/api/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s

```

> [!IMPORTANT]
> **v0.7.80 Breaking Change:** Docker volumes have changed. `/:/host:ro` and `docker.sock` mounts removed for security. See [CHANGELOG](CHANGELOG.md#0780---2026-04-15) for migration instructions.

**Launch:**

```bash
# Start with Docker Compose
docker-compose up -d

# View logs
docker-compose logs -f

# Stop
docker-compose down

# Update image
docker-compose pull
docker-compose up -d
```

**Recommendation:** Use the **[.env file](#secure-jwt_secret-configuration)** (`.env` at project root); Docker Compose reads it automatically and injects `JWT_SECRET` into the container.

> For more details, see the [Secure JWT_SECRET configuration](#secure-jwt_secret-configuration) section for all configuration methods, security best practices and verification.

The dashboard will be available at:
- **http://localhost:7505** - from the host machine
- **http://SERVER_IP:7505** - from another device on the network

<details>
<summary><strong>Advanced configuration</strong></summary>

### Optional: External configuration file (`.conf`)

You can use an external `.conf` file for configuration:

1. **Create the config file:**
   ```bash
   cp config/mynetwork.conf.example config/mynetwork.conf
   # Edit config/mynetwork.conf to your needs
   ```

2. **Mount the file in Docker:**  
   Uncomment the line in `docker-compose.yml`:
   ```yaml
   volumes:
     - mynetwork_data:/app/data
     - ./config/mynetwork.conf:/app/config/mynetwork.conf:ro
   ```

3. **Automatic sync:**
   - On startup, if the `.conf` file exists → import into the database
   - If the file does not exist → export current configuration

4. **API endpoints:**
   - `GET /api/config/export` - Export current configuration
   - `POST /api/config/import` - Import from file
   - `GET /api/config/file` - Check file status
   - `POST /api/config/sync` - Manual sync

#### Nginx (reverse proxy)

If you use **nginx** as a reverse proxy in front of MynetworK, set `PUBLIC_URL` to the public URL (via nginx), not the Docker container URL.

**Case 1: Without nginx (direct access)**  
No `PUBLIC_URL` needed. The app works on the mapped port (e.g. `http://YOUR_IP:7505`).

**Case 2: With nginx (reverse proxy)**

1. **Nginx config:** See `Docs/nginx.example.conf` for a full example.
2. **docker-compose.yml:**
   ```yaml
   environment:
     - PUBLIC_URL=http://mynetwork.example.com
     # Or with HTTPS:
     # - PUBLIC_URL=https://mynetwork.example.com
   ```
3. **Minimal nginx example:**
   ```nginx
   server {
       listen 80;
       server_name mynetwork.example.com;
       location / {
           proxy_pass http://192.168.1.150:7505;
           proxy_http_version 1.1;
           proxy_set_header Upgrade $http_upgrade;
           proxy_set_header Connection 'upgrade';
           proxy_set_header Host $host;
           proxy_set_header X-Real-IP $remote_addr;
           proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
           proxy_set_header X-Forwarded-Proto $scheme;
           proxy_cache_bypass $http_upgrade;
       }
   }
   ```
4. **Benefits of nginx:** SSL/HTTPS (e.g. Let's Encrypt), multiple services on one server, caching, clean URLs.

See `Docs/nginx.example.conf` for a complete HTTP/HTTPS setup.

</details>

<details id="secure-jwt_secret-configuration">
<summary><strong>Secure JWT_SECRET configuration</strong></summary>

**Critical – Security:** The default JWT secret (`change-me-in-production-please-use-strong-secret`) is for **development only**. In production you **must** set the `JWT_SECRET` environment variable to a unique, strong value.

#### Why it matters

`JWT_SECRET` is used to sign and verify JWT authentication tokens. A weak or default secret allows an attacker to:
- Forge valid JWTs and impersonate any user
- Access the system without authentication (full admin access)
- Compromise all users and their data
- Change permissions and access restricted features

#### Where it is used

`JWT_SECRET` is loaded at server startup in `server/services/authService.ts` from `process.env.JWT_SECRET`. If unset, the default value is used and a warning is logged. The secret is used to sign tokens on login and verify them on authenticated requests.

## Dependencies & supply-chain

MynetworK runs entirely on your machine and only talks to the network equipment you configure (Freebox / UniFi / your LAN). It never phones home. The full list of npm packages it ships is in [`package.json`](./package.json); below is what's important to know.

### Runtime — backend (Node / Express)

| Package | Used for | Notes |
| --- | --- | --- |
| `express` | HTTP server | Stable, widely audited |
| `helmet` | Security headers (CSP, HSTS, X-Frame-Options…) | Defense-in-depth |
| `express-rate-limit` | API and write-route throttling, IPv6-aware | |
| `compression` | gzip responses | |
| `cors` | CORS rules | Tight defaults |
| `bcrypt` | Password hashing | |
| `jsonwebtoken` | Issue / verify JWTs | See `JWT_SECRET` above |
| `better-sqlite3` | Local DB (data, sessions, scans, topology snapshots, manual placements) | Database file lives in the mounted `./data` volume — back it up like any DB |
| `node-cron` | Daily topology refresh + scheduled scans | Local only, no internet |
| `ws` | WebSockets for live UI updates | Listens on the same port as the HTTP server |

### Runtime — frontend (React / Vite)

| Package | Used for | Notes |
| --- | --- | --- |
| `react` / `react-dom` | UI framework | |
| `react-router-dom` | Client-side routing | |
| `zustand` | State management | |
| `i18next` / `react-i18next` | English / French translations | |
| `recharts` | Bar / line charts on the dashboard | Brings `d3-shape`, `d3-scale`, `d3-array`, etc. as transitive deps |
| `@xyflow/react` (React Flow) | Interactive topology graph (`/topology`) | Brings `d3-zoom`, `d3-drag`, `d3-selection`, `d3-interpolate` |
| `dagre` | Tree / hierarchical layout for the topology | |
| `html-to-image` | PNG / SVG export of the topology | Runs entirely in the browser, no upload |
| `jspdf` | PDF export of the topology (A4, raster) | Browser-only |
| `lucide-react` | Icon set | |
| `react-markdown` + `remark-gfm` | Render the in-app changelog | Sanitised |
| `leaflet` + `leaflet.markercluster` | Map view | |
| `sonner` | Toast notifications | |

### Security considerations

- **No telemetry.** None of these packages call out to a third-party server when the app runs. The Docker container does not need outbound internet to function — it only reaches the LAN equipment you configure.
- **Export libraries (`html-to-image`, `jspdf`)** are 100 % client-side. Generated PNG / PDF / SVG files stay in your browser; nothing is uploaded.
- **Topology stack (`@xyflow/react`, `dagre`)** runs in the browser and on a SQLite-backed snapshot. The snapshot only contains data your active plugins already have access to (Freebox / UniFi devices on your LAN).
- **Charts stack (`recharts`)** renders local data only.
- **Supply chain.** Dependabot is enabled on this repo and proposes weekly updates. Snyk runs on every push (`Snyk Security` in CI). SonarCloud runs on every push to flag suspicious changes.
- **Reproducible builds.** `package-lock.json` is committed. The published Docker image is built from a tagged commit by GitHub Actions (`Build & Push Docker Image` workflow) and pushed to GHCR, so you can verify what's running.
- **Updating.** Pull the new image from GHCR (`docker compose pull && docker compose up -d`). The version that's running is shown in the UI footer and at startup in the container logs.

If you spot a security issue, please open a private GitHub security advisory rather than a public issue.

## Configuration 

#### Configuration methods (recommended order)

##### 1. **`.env` file (recommended for production)**

Docker Compose automatically reads `.env` at project root.

1. **Generate a strong secret** (at least 32 characters):
   ```bash
   # Linux/macOS:
   openssl rand -base64 32
   
   # Windows PowerShell:
   [Convert]::ToBase64String((1..32 | ForEach-Object { Get-Random -Maximum 256 }))
   ```

2. **Create a `.env` file** at project root:
   ```bash
   # .env
   JWT_SECRET=your_generated_secret_here_minimum_32_chars
   
   DASHBOARD_PORT=7505
   FREEBOX_HOST=mafreebox.freebox.fr
   PUBLIC_URL=https://mynetwork.example.com
   ```

3. **Restrict permissions:**
   ```bash
   chmod 600 .env
   ```

4. **Start with Docker Compose:**
   ```bash
   docker-compose up -d
   ```

##### 2. **`.env` with `--env-file`**

```bash
echo "JWT_SECRET=$(openssl rand -base64 32)" > .env.production
docker-compose --env-file .env.production up -d
```

#### Verification

After startup, check that a custom secret is in use:

```bash
docker-compose logs | grep -i "jwt\|secret"
```

If you see a warning like: *"Using default JWT secret. Please set JWT_SECRET..."*, then `JWT_SECRET` was not set correctly.

**In the web UI:** Administration → Security → JWT configuration section shows whether the default secret is used.

#### Security best practices

1. **Length:** At least **32 characters** (64 recommended)
2. **Random:** Use random data, not predictable passwords
3. **Unique:** Each production instance should have its own secret
4. **Storage:** Restrict `.env` permissions (`chmod 600`), add `.env` to `.gitignore`, use a secrets manager for critical deployments
5. **Rotation:** Change the secret periodically (e.g. every 6–12 months) or if compromise is suspected
6. **Dev vs prod:** Use different secrets for development and production

#### JWT secret rotation

1. Generate a new secret: `openssl rand -base64 32`
2. Update `.env`: `JWT_SECRET=new_secret`
3. Restart: `docker-compose restart`
4. All users will need to log in again (existing tokens are invalidated).

#### Example `.env`

```bash
# .env – Production

JWT_SECRET=your_openssl_generated_secret_here

DASHBOARD_PORT=7505
FREEBOX_HOST=mafreebox.freebox.fr
PUBLIC_URL=https://mynetwork.example.com
```

</details>


## First login

1. Open the dashboard (http://localhost:7505 or your server IP).
2. Log in with default credentials:
   - **Username:** `admin`
   - **Password:** `admin123`
3. **Change the password immediately after first login.**
4. Configure your plugins in the **Plugins** page.

<details>
<summary><strong>Features</strong></summary>

### Main dashboard
- **Multi-source statistics** - Unified view of all plugin data
- **Real-time charts** - Throughput, connections, stats
- **Network overview** - Global state of your infrastructure

### Plugin management
- **Centralized configuration** - UI to configure each plugin
- **Enable/disable** - Fine-grained control of each data source
- **Connection status** - Check each plugin’s state

### Freebox (plugin)
- **Full dashboard** - All Freebox features (WiFi, LAN, Downloads, VMs, TV, Phone)
- **Compatibility** - Ultra, Delta, Pop
- **Native API** - Official Freebox OS API

### UniFi Controller (plugin)
- **Network monitoring** - AP stats, clients, traffic
- **Multi-site** - Multiple UniFi sites
- **Real-time data** - Automatic stats updates
- **Dual API** - Local Controller (node-unifi) and Site Manager API (cloud)
- **Stats badges** - System stats in header (throughput, uptime, devices)

### Network Scan (plugin)
- **Auto discovery** - Full local network scan (IPs, MAC, hostnames)
- **Vendor detection** - Automatic manufacturer identification (Wireshark DB, Freebox/UniFi, or external API)
- **Scheduled scans** - Periodic full scan and refresh
- **History** - Device evolution over time with charts
- **Wireshark vendor DB** - Full integration with Wireshark `manuf` and auto-update
- **Priority system** - Hostname/vendor detection order (Freebox, UniFi, Scanner)
- **Modern UI** - Interactive table with sort, filters, search and inline hostname editing

### User management (admin)
- **Full CRUD** - Create, edit, delete users
- **Roles** - Permissions (admin, user, viewer)
- **Security** - Passwords hashed with bcrypt

### Activity logs (admin)
- **Full traceability** - All actions logged
- **Advanced filters** - By user, plugin, action, level, period
- **Export** - Log export (planned)

</details>

<details>
<summary><strong>Architecture</strong></summary>

MynetworK uses a modular architecture:
- **React frontend** (TypeScript) - Modern UI
- **Express backend** (TypeScript) - REST API and WebSocket
- **SQLite database** - Configuration and data storage
- **Plugin system** - Extensible architecture for new data sources

See [DEV/ARCHITECTURE_PLUGINS.md](DEV/ARCHITECTURE_PLUGINS.md) for details.

</details>

<details>
<summary><strong>Documentation</strong></summary>

### For users
- **[CHANGELOG.md](CHANGELOG.md)** - Change log and new features

### For developers
See **[DEV/README-DEV.md](DEV/README-DEV.md)** for development documentation.

**Main docs:**
- **[DEV/DOCUMENTATION.md](DEV/DOCUMENTATION.md)** - Documentation index
- **[DEV/GUIDE_DEVELOPPEMENT.md](DEV/GUIDE_DEVELOPPEMENT.md)** - Developer guide
- **[DEV/ARCHITECTURE_PLUGINS.md](DEV/ARCHITECTURE_PLUGINS.md)** - Plugin architecture

**Docs folder ([Docs/](Docs/)):** Setup and production guides (UniFi, Freebox, env vars, Nginx, troubleshooting, reset). Key docs have **English** and **French** versions (see [Docs/README.md](Docs/README.md)).

</details>

## Home Assistant

> [!IMPORTANT]
> A dedicated **fully functional** version for **Home Assistant** is available:  
> [![HA Repo](https://img.shields.io/badge/Home%20Assistant-Dedicated%20Version-41C483?style=for-the-badge&logo=homeassistant&logoColor=white)](https://github.com/Erreur32/HA_mynetwork)  
> 
> - **HACS integration** ready
> - **Add-on** support
> - **Optimized** for HA Supervisor/Docker
> - **Auto-discovery** of Freebox/UniFi networks

See [HA Repo](https://github.com/Erreur32/HA_mynetwork) for installation.



## MCP (Model Context Protocol)

MynetworK ships a native [MCP](https://modelcontextprotocol.io) server, so an MCP client (e.g. Claude Desktop, Claude Code) can query and control your Freebox, UniFi controller and network scanner directly, no need to go through the web UI.

- **LAN-only** - not exposed through the reverse proxy; gated by an IP allowlist (RFC1918 + loopback + Tailscale 100.64.0.0/10) in addition to a dedicated bearer token
- **Behind a reverse proxy** - the allowlist checks the TCP peer address and ignores `X-Forwarded-For` by default. If a proxy is the only path to the app and you want the real client checked, list it in `MCP_TRUSTED_PROXIES` (IPv4/CIDR, comma-separated); the same setting covers API tokens and the Prometheus export
- **Named, multi-token auth** - separate from the JWT web session; create as many named tokens as you need (one per client/device), each with its own optional expiry, from the admin panel
- **Managed from the admin UI** - the "MCP" tab lets you create tokens (shown once), revoke them individually, and shows whether MCP is enabled, the endpoint, active sessions and each token's status/last-used time

### 1. Generate an access token

From the admin panel: Settings > MCP > General tab > "New token". Name it, pick a duration (or unlimited), and copy the token shown: it is never displayed again.

A CLI fallback also exists, for when the admin panel is unreachable (see [Docs/MCP_DEV_SETUP.md](Docs/MCP_DEV_SETUP.md) for the full explanation):

```bash
# Docker (production, default deployment, container name is "mynetwork")
docker exec -it -u node mynetwork node_modules/.bin/tsx scripts/mcp-token.ts

# Local / dev (bare npm run dev, no container)
npm run mcp:token
```

Each CLI run creates a new token named "CLI" with no expiry, without touching tokens created from the admin UI.

### 2. Connect a client

The server speaks the standard MCP **Streamable HTTP** transport at `http://<LAN-IP>:<PORT>/api/mcp`: swap in the LAN IP and port printed above, and the token, for any client below.

**Claude Code (CLI)**

```bash
claude mcp add --transport http mynetwork http://<LAN-IP>:<PORT>/api/mcp \
  --header "Authorization: Bearer <token>"
```

Or add it to a project's `.mcp.json`:

```json
{
  "mcpServers": {
    "mynetwork": {
      "type": "http",
      "url": "http://<LAN-IP>:<PORT>/api/mcp",
      "headers": { "Authorization": "Bearer <token>" }
    }
  }
}
```

**Claude Desktop**

Paid plans (Pro/Max/Team/Enterprise) can add it directly under Settings → Connectors, which speaks Streamable HTTP natively. On the free plan, or for any stdio-only client, bridge it with [`mcp-remote`](https://www.npmjs.com/package/mcp-remote) in `claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "mynetwork": {
      "command": "npx",
      "args": [
        "mcp-remote@latest",
        "http://<LAN-IP>:<PORT>/api/mcp",
        "--header",
        "Authorization: Bearer <token>"
      ]
    }
  }
}
```

**Other agents / clients**

Any MCP client with Streamable HTTP support (Cursor, Continue, custom agents built on the MCP SDK, ...) only needs the URL and the bearer header above. For a stdio-only client, the same `mcp-remote` bridge shown for Claude Desktop applies.

### Available tools

| Source | Read | Write |
|---|---|---|
| **Freebox** | system info, connection status, WiFi status/stations, LAN hosts, DHCP config/leases, switch ports, call log, contacts | reboot, toggle WiFi/BSS, add a DHCP static lease |
| **UniFi** | devices, clients, WLANs, network config, port forwarding rules, bandwidth report, system info, sites | block/unblock a client, enable/disable a WLAN, restart a device |
| **Network scanner** | stats, devices, device by IP, blacklist | trigger/rescan a scan, add a manual IP, rename a host, blacklist add/remove |

Write actions are limited to non-destructive operations (nothing deletes data), though some are disruptive by nature (a reboot or a device restart briefly interrupts connectivity — tool descriptions flag this explicitly).

### Examples

What a tool call looks like from an MCP client, and the kind of response it gets back (values below are illustrative, not real data).

**Freebox — read: which devices are currently on WiFi**

```
> freebox_get_wifi_stations
```
```json
{
  "success": true,
  "result": [
    {
      "mac": "AA:BB:CC:11:22:33",
      "hostname": "laptop-julien",
      "ip": "192.168.1.42",
      "band": "5G",
      "rssi": -52,
      "connected_since": 3841
    },
    {
      "mac": "AA:BB:CC:44:55:66",
      "hostname": "iphone-julien",
      "ip": "192.168.1.57",
      "band": "2G4",
      "rssi": -67,
      "connected_since": 120
    }
  ]
}
```

**UniFi — write: block a client from the network**

```
> unifi_block_client { "mac": "AA:BB:CC:77:88:99" }
```
```json
{
  "success": true,
  "result": {
    "mac": "AA:BB:CC:77:88:99",
    "blocked": true
  }
}
```

## Security

- **JWT authentication** - Secure tokens with expiration
- **Password hashing** - bcrypt with salt rounds
- **Auth middleware** - Protection of sensitive routes
- **Action logging** - Full traceability
- **Role-based access** - Granular permissions

## Contributing

Contributions are welcome.

### Guidelines

- Follow existing code style (4 spaces, camelCase, comments in English)
- Add TypeScript types for new code
- Test changes before submitting
- Document new features
- Follow project rule files

## License

This project is licensed under the MIT License. See [LICENSE](LICENSE) for details.

## Acknowledgments

### Original project

This project is heavily inspired by **Freebox OS Ultra Dashboard** by [HGHugo](https://github.com/HGHugo/FreeboxOS-Ultra-Dashboard). Many thanks to the original author for the work that served as a base for MynetworK.

**Original project:** [FreeboxOS-Ultra-Dashboard](https://github.com/HGHugo/FreeboxOS-Ultra-Dashboard)

### Others

- [Free](https://www.free.fr) for the Freebox and its open API
- [Freebox SDK](https://dev.freebox.fr) for API documentation
- [Ubiquiti](https://www.ui.com) for UniFi
- The open-source community for the libraries used

---

<div align="center">

**Made with ❤️ for multi-source network management**

**MynetworK - Multi-Source Network Dashboard**

</div>