diff --git a/frontend/db.json b/frontend/db.json
new file mode 100644
index 0000000..03689fa
--- /dev/null
+++ b/frontend/db.json
@@ -0,0 +1,323 @@
+{
+ "monitoringStatus": {
+ "active": true,
+ "uptime": 145200,
+ "packets_captured": 2847392,
+ "active_sessions": 12,
+ "threats_detected": 23,
+ "last_updated": "2025-11-14T20:00:00.000Z"
+ },
+
+ "trafficStats": {
+ "total_packets": 2847392,
+ "suspicious_packets": 1247,
+ "blocked_packets": 342,
+ "data_transferred": "1.2TB",
+ "hourly_data": [
+ { "hour": "00:00", "packets": 12000, "suspicious": 45, "blocked": 12 },
+ { "hour": "01:00", "packets": 8500, "suspicious": 32, "blocked": 8 },
+ { "hour": "02:00", "packets": 6200, "suspicious": 28, "blocked": 5 },
+ { "hour": "03:00", "packets": 5800, "suspicious": 15, "blocked": 3 },
+ { "hour": "04:00", "packets": 7200, "suspicious": 22, "blocked": 7 },
+ { "hour": "05:00", "packets": 9800, "suspicious": 38, "blocked": 11 },
+ { "hour": "06:00", "packets": 15200, "suspicious": 52, "blocked": 18 },
+ { "hour": "07:00", "packets": 22400, "suspicious": 78, "blocked": 25 },
+ { "hour": "08:00", "packets": 28600, "suspicious": 95, "blocked": 32 },
+ { "hour": "09:00", "packets": 35200, "suspicious": 112, "blocked": 41 },
+ { "hour": "10:00", "packets": 42800, "suspicious": 134, "blocked": 48 },
+ { "hour": "11:00", "packets": 38900, "suspicious": 128, "blocked": 44 },
+ { "hour": "12:00", "packets": 45200, "suspicious": 145, "blocked": 52 },
+ { "hour": "13:00", "packets": 41600, "suspicious": 138, "blocked": 49 },
+ { "hour": "14:00", "packets": 39800, "suspicious": 132, "blocked": 46 },
+ { "hour": "15:00", "packets": 44200, "suspicious": 141, "blocked": 51 },
+ { "hour": "16:00", "packets": 47800, "suspicious": 152, "blocked": 56 },
+ { "hour": "17:00", "packets": 52400, "suspicious": 168, "blocked": 62 },
+ { "hour": "18:00", "packets": 48900, "suspicious": 159, "blocked": 58 },
+ { "hour": "19:00", "packets": 45600, "suspicious": 147, "blocked": 53 },
+ { "hour": "20:00", "packets": 42200, "suspicious": 139, "blocked": 50 },
+ { "hour": "21:00", "packets": 38800, "suspicious": 129, "blocked": 45 },
+ { "hour": "22:00", "packets": 32400, "suspicious": 108, "blocked": 37 },
+ { "hour": "23:00", "packets": 26200, "suspicious": 89, "blocked": 29 }
+ ]
+ },
+
+ "alerts": [
+ {
+ "id": 1,
+ "type": "critical",
+ "title": "Suspicious Data Exfiltration Detected",
+ "description": "Large volume of data transfer detected to unknown external IP 185.199.108.153",
+ "timestamp": "2025-11-14T19:55:00.000Z",
+ "source_ip": "192.168.1.45",
+ "destination_ip": "185.199.108.153",
+ "severity": "high",
+ "status": "open",
+ "packets": 15420,
+ "data_size": "847MB"
+ },
+ {
+ "id": 2,
+ "type": "warning",
+ "title": "Unauthorized VNC Access Attempt",
+ "description": "Multiple failed VNC authentication attempts from external IP",
+ "timestamp": "2025-11-14T19:45:00.000Z",
+ "source_ip": "203.0.113.42",
+ "destination_ip": "192.168.1.100",
+ "severity": "medium",
+ "status": "investigating",
+ "packets": 342,
+ "data_size": "12KB"
+ },
+ {
+ "id": 3,
+ "type": "info",
+ "title": "VNC Session Established",
+ "description": "New VNC session established for legitimate user",
+ "timestamp": "2025-11-14T19:00:00.000Z",
+ "source_ip": "192.168.1.25",
+ "destination_ip": "192.168.1.100",
+ "severity": "low",
+ "status": "resolved",
+ "packets": 1205,
+ "data_size": "2.1MB"
+ },
+ {
+ "id": 4,
+ "type": "critical",
+ "title": "Potential Malware Communication",
+ "description": "Suspicious network pattern detected - possible C&C communication",
+ "timestamp": "2025-11-14T18:00:00.000Z",
+ "source_ip": "192.168.1.67",
+ "destination_ip": "198.51.100.89",
+ "severity": "high",
+ "status": "open",
+ "packets": 8930,
+ "data_size": "156MB"
+ },
+ {
+ "id": 5,
+ "type": "warning",
+ "title": "Unusual Port Activity",
+ "description": "High traffic detected on non-standard port 8447",
+ "timestamp": "2025-11-14T17:00:00.000Z",
+ "source_ip": "192.168.1.33",
+ "destination_ip": "172.16.254.1",
+ "severity": "medium",
+ "status": "investigating",
+ "packets": 2847,
+ "data_size": "45MB"
+ }
+ ],
+
+ "alertSummary": {
+ "total": 147,
+ "critical": 23,
+ "high": 45,
+ "medium": 52,
+ "low": 27,
+ "last_24h": 18,
+ "last_week": 89,
+ "resolved": 124,
+ "open": 23
+ },
+
+ "vncSessions": [
+ {
+ "id": 1,
+ "name": "Production Server Monitor",
+ "host": "192.168.1.100",
+ "port": 5901,
+ "status": "active",
+ "created_at": "2025-11-14T18:00:00.000Z",
+ "last_activity": "2025-11-14T19:58:00.000Z",
+ "user": "admin",
+ "vnc_type": "TigerVNC",
+ "screen_resolution": "1920x1080",
+ "active_connections": 2,
+ "data_transferred": "847MB",
+ "session_duration": 3600
+ },
+ {
+ "id": 2,
+ "name": "Development Environment",
+ "host": "192.168.1.101",
+ "port": 5902,
+ "status": "active",
+ "created_at": "2025-11-14T16:00:00.000Z",
+ "last_activity": "2025-11-14T19:45:00.000Z",
+ "user": "developer",
+ "vnc_type": "RealVNC",
+ "screen_resolution": "1366x768",
+ "active_connections": 1,
+ "data_transferred": "234MB",
+ "session_duration": 7200
+ },
+ {
+ "id": 3,
+ "name": "Database Server Access",
+ "host": "192.168.1.102",
+ "port": 5903,
+ "status": "inactive",
+ "created_at": "2025-11-13T20:00:00.000Z",
+ "last_activity": "2025-11-14T18:00:00.000Z",
+ "user": "dbadmin",
+ "vnc_type": "TigerVNC",
+ "screen_resolution": "1024x768",
+ "active_connections": 0,
+ "data_transferred": "1.2GB",
+ "session_duration": 14400
+ },
+ {
+ "id": 4,
+ "name": "Test Server",
+ "host": "192.168.1.103",
+ "port": 5904,
+ "status": "stopped",
+ "created_at": "2025-11-12T20:00:00.000Z",
+ "last_activity": "2025-11-13T20:00:00.000Z",
+ "user": "tester",
+ "vnc_type": "RealVNC",
+ "screen_resolution": "1920x1200",
+ "active_connections": 0,
+ "data_transferred": "567MB",
+ "session_duration": 0
+ }
+ ],
+
+ "firewallRules": [
+ {
+ "id": 1,
+ "name": "Block Suspicious IPs",
+ "action": "BLOCK",
+ "protocol": "TCP",
+ "source_ip": "185.199.108.0/24",
+ "destination_port": "*",
+ "enabled": true,
+ "priority": 100,
+ "created_at": "2025-11-13T20:00:00.000Z",
+ "hits": 1247,
+ "last_hit": "2025-11-14T19:55:00.000Z"
+ },
+ {
+ "id": 2,
+ "name": "Allow VNC Traffic",
+ "action": "ALLOW",
+ "protocol": "TCP",
+ "source_ip": "192.168.1.0/24",
+ "destination_port": "590x",
+ "enabled": true,
+ "priority": 50,
+ "created_at": "2025-11-12T20:00:00.000Z",
+ "hits": 15420,
+ "last_hit": "2025-11-14T19:58:00.000Z"
+ },
+ {
+ "id": 3,
+ "name": "Block Port 8447",
+ "action": "BLOCK",
+ "protocol": "TCP",
+ "source_ip": "*",
+ "destination_port": "8447",
+ "enabled": true,
+ "priority": 75,
+ "created_at": "2025-11-14T17:00:00.000Z",
+ "hits": 342,
+ "last_hit": "2025-11-14T18:00:00.000Z"
+ },
+ {
+ "id": 4,
+ "name": "Allow HTTP/HTTPS",
+ "action": "ALLOW",
+ "protocol": "TCP",
+ "source_ip": "*",
+ "destination_port": "80,443",
+ "enabled": true,
+ "priority": 10,
+ "created_at": "2025-11-11T20:00:00.000Z",
+ "hits": 234789,
+ "last_hit": "2025-11-14T20:00:00.000Z"
+ }
+ ],
+
+ "networkData": {
+ "interfaces": [
+ {
+ "name": "eth0",
+ "status": "up",
+ "rx_bytes": 2847392000,
+ "tx_bytes": 1847392000,
+ "rx_packets": 2847392,
+ "tx_packets": 1847392,
+ "errors": 0,
+ "drops": 12
+ },
+ {
+ "name": "eth1",
+ "status": "up",
+ "rx_bytes": 847392000,
+ "tx_bytes": 647392000,
+ "rx_packets": 847392,
+ "tx_packets": 647392,
+ "errors": 2,
+ "drops": 5
+ }
+ ],
+ "protocols": {
+ "TCP": 65,
+ "UDP": 25,
+ "ICMP": 8,
+ "Other": 2
+ },
+ "top_talkers": [
+ { "ip": "192.168.1.100", "bytes": 847392000, "packets": 847392 },
+ { "ip": "192.168.1.101", "bytes": 234789000, "packets": 234789 },
+ { "ip": "192.168.1.102", "bytes": 156423000, "packets": 156423 },
+ { "ip": "185.199.108.153", "bytes": 89456000, "packets": 89456 },
+ { "ip": "203.0.113.42", "bytes": 34567000, "packets": 34567 }
+ ]
+ },
+
+ "users": [
+ {
+ "id": 1,
+ "username": "admin",
+ "email": "admin@exfilsentry.com",
+ "role": "Administrator",
+ "status": "active",
+ "last_login": "2025-11-14T19:00:00.000Z",
+ "created_at": "2025-10-14T20:00:00.000Z",
+ "permissions": ["all"]
+ },
+ {
+ "id": 2,
+ "username": "analyst",
+ "email": "analyst@exfilsentry.com",
+ "role": "Security Analyst",
+ "status": "active",
+ "last_login": "2025-11-14T18:00:00.000Z",
+ "created_at": "2025-11-01T20:00:00.000Z",
+ "permissions": ["view_alerts", "manage_alerts", "view_monitoring"]
+ },
+ {
+ "id": 3,
+ "username": "operator",
+ "email": "operator@exfilsentry.com",
+ "role": "Network Operator",
+ "status": "active",
+ "last_login": "2025-11-14T17:00:00.000Z",
+ "created_at": "2025-11-05T20:00:00.000Z",
+ "permissions": ["view_monitoring", "manage_vnc"]
+ }
+ ],
+
+ "systemInfo": {
+ "version": "2.1.0",
+ "uptime": 2592000,
+ "cpu_usage": 23.5,
+ "memory_usage": 67.2,
+ "disk_usage": 45.8,
+ "network_interfaces": 2,
+ "active_rules": 4,
+ "total_sessions": 4
+ }
+}
diff --git a/frontend/src/data/JSON_SERVER_SETUP.md b/frontend/src/data/JSON_SERVER_SETUP.md
new file mode 100644
index 0000000..b6c8bdd
--- /dev/null
+++ b/frontend/src/data/JSON_SERVER_SETUP.md
@@ -0,0 +1,109 @@
+# JSON Server Setup Guide
+
+## Overview
+All frontend pages now fetch data from a JSON Server instance instead of using hardcoded mock data. This allows for dynamic data updates and real-time API integration testing.
+
+## Setup Instructions
+
+### 1. Start JSON Server
+Navigate to the `frontend` directory and run:
+
+```bash
+cd frontend
+npx json-server --watch db.json --port 4000
+```
+
+The server will start on `http://localhost:4000` and provide REST endpoints for all data in `db.json`.
+
+### 2. Start React Development Server
+In a new terminal:
+
+```bash
+cd frontend
+npm start
+```
+
+The React app will connect to JSON Server and fetch data on component mount.
+
+## API Endpoints Available
+
+All endpoints are served at `http://localhost:4000`:
+
+- **GET** `/monitoringStatus` - Monitoring status data
+- **GET** `/trafficStats` - Traffic statistics and hourly data
+- **GET** `/alerts` - Security alerts
+- **GET** `/alertSummary` - Summary of alert counts
+- **GET** `/vncSessions` - VNC session data
+- **GET** `/firewallRules` - Firewall rules
+- **GET** `/networkData` - Network interface and protocol data
+- **GET** `/users` - User data
+- **GET** `/systemInfo` - System information
+
+### Modify Endpoints (Create, Update, Delete)
+
+**POST** - Create new records
+```bash
+curl -X POST http://localhost:4000/alerts \
+ -H "Content-Type: application/json" \
+ -d '{"id": 6, "title": "New Alert", ...}'
+```
+
+**PUT** - Update existing records
+```bash
+curl -X PUT http://localhost:4000/alerts/1 \
+ -H "Content-Type: application/json" \
+ -d '{"status": "resolved"}'
+```
+
+**DELETE** - Remove records
+```bash
+curl -X DELETE http://localhost:4000/alerts/1
+```
+
+## Pages Updated
+
+All pages now use the API service and fetch data from JSON Server:
+
+1. **Dashboard.js** - Fetches monitoring status, traffic stats, alert summary, VNC sessions, system info
+2. **Monitoring.js** - Fetches traffic stats and network data
+3. **SecurityAlerts.js** - Fetches alerts list and provides filtering/search
+4. **VNCSessions.js** - Fetches active VNC sessions
+5. **Firewall.js** - Fetches firewall rules
+
+## API Service
+
+The `src/services/api.js` file contains all API calls. Example usage:
+
+```javascript
+import { api } from '../services/api';
+
+// Fetch data
+const alerts = await api.getAlerts();
+const sessions = await api.getVncSessions();
+
+// Update data
+await api.updateAlert(1, { status: 'resolved' });
+await api.deleteAlert(2);
+```
+
+## Troubleshooting
+
+### Connection Error: "Cannot reach http://localhost:4000"
+- Ensure JSON Server is running in a terminal window
+- Check that port 4000 is not blocked by firewall
+- Verify `db.json` exists in the `frontend` directory
+
+### CORS Errors
+JSON Server has CORS enabled by default, but if you encounter issues, restart the server or ensure both servers are running on localhost.
+
+### Data Not Loading
+- Check browser console for fetch errors
+- Verify `db.json` is valid JSON using `jsonlint`
+- Ensure the endpoint names match the keys in `db.json`
+
+## Next Steps
+
+1. Run `npx json-server --watch db.json --port 4000` in the `frontend` directory
+2. Start React with `npm start`
+3. All pages will now display data from JSON Server
+4. Modify `db.json` to update mock data in real-time
diff --git a/frontend/src/data/mockData.js b/frontend/src/data/mockData.js
deleted file mode 100644
index 4303f51..0000000
--- a/frontend/src/data/mockData.js
+++ /dev/null
@@ -1,341 +0,0 @@
-// Mock data for static frontend
-export const mockData = {
- // Monitoring Status
- monitoringStatus: {
- active: true,
- uptime: 145200, // 40 hours in seconds
- packets_captured: 2847392,
- active_sessions: 12,
- threats_detected: 23,
- last_updated: new Date().toISOString()
- },
-
- // Traffic Statistics
- trafficStats: {
- total_packets: 2847392,
- suspicious_packets: 1247,
- blocked_packets: 342,
- data_transferred: "1.2TB",
- hourly_data: [
- { hour: '00:00', packets: 12000, suspicious: 45, blocked: 12 },
- { hour: '01:00', packets: 8500, suspicious: 32, blocked: 8 },
- { hour: '02:00', packets: 6200, suspicious: 28, blocked: 5 },
- { hour: '03:00', packets: 5800, suspicious: 15, blocked: 3 },
- { hour: '04:00', packets: 7200, suspicious: 22, blocked: 7 },
- { hour: '05:00', packets: 9800, suspicious: 38, blocked: 11 },
- { hour: '06:00', packets: 15200, suspicious: 52, blocked: 18 },
- { hour: '07:00', packets: 22400, suspicious: 78, blocked: 25 },
- { hour: '08:00', packets: 28600, suspicious: 95, blocked: 32 },
- { hour: '09:00', packets: 35200, suspicious: 112, blocked: 41 },
- { hour: '10:00', packets: 42800, suspicious: 134, blocked: 48 },
- { hour: '11:00', packets: 38900, suspicious: 128, blocked: 44 },
- { hour: '12:00', packets: 45200, suspicious: 145, blocked: 52 },
- { hour: '13:00', packets: 41600, suspicious: 138, blocked: 49 },
- { hour: '14:00', packets: 39800, suspicious: 132, blocked: 46 },
- { hour: '15:00', packets: 44200, suspicious: 141, blocked: 51 },
- { hour: '16:00', packets: 47800, suspicious: 152, blocked: 56 },
- { hour: '17:00', packets: 52400, suspicious: 168, blocked: 62 },
- { hour: '18:00', packets: 48900, suspicious: 159, blocked: 58 },
- { hour: '19:00', packets: 45600, suspicious: 147, blocked: 53 },
- { hour: '20:00', packets: 42200, suspicious: 139, blocked: 50 },
- { hour: '21:00', packets: 38800, suspicious: 129, blocked: 45 },
- { hour: '22:00', packets: 32400, suspicious: 108, blocked: 37 },
- { hour: '23:00', packets: 26200, suspicious: 89, blocked: 29 }
- ]
- },
-
- // Security Alerts
- alerts: [
- {
- id: 1,
- type: 'critical',
- title: 'Suspicious Data Exfiltration Detected',
- description: 'Large volume of data transfer detected to unknown external IP 185.199.108.153',
- timestamp: new Date(Date.now() - 300000).toISOString(),
- source_ip: '192.168.1.45',
- destination_ip: '185.199.108.153',
- severity: 'high',
- status: 'open',
- packets: 15420,
- data_size: '847MB'
- },
- {
- id: 2,
- type: 'warning',
- title: 'Unauthorized VNC Access Attempt',
- description: 'Multiple failed VNC authentication attempts from external IP',
- timestamp: new Date(Date.now() - 900000).toISOString(),
- source_ip: '203.0.113.42',
- destination_ip: '192.168.1.100',
- severity: 'medium',
- status: 'investigating',
- packets: 342,
- data_size: '12KB'
- },
- {
- id: 3,
- type: 'info',
- title: 'VNC Session Established',
- description: 'New VNC session established for legitimate user',
- timestamp: new Date(Date.now() - 1800000).toISOString(),
- source_ip: '192.168.1.25',
- destination_ip: '192.168.1.100',
- severity: 'low',
- status: 'resolved',
- packets: 1205,
- data_size: '2.1MB'
- },
- {
- id: 4,
- type: 'critical',
- title: 'Potential Malware Communication',
- description: 'Suspicious network pattern detected - possible C&C communication',
- timestamp: new Date(Date.now() - 3600000).toISOString(),
- source_ip: '192.168.1.67',
- destination_ip: '198.51.100.89',
- severity: 'high',
- status: 'open',
- packets: 8930,
- data_size: '156MB'
- },
- {
- id: 5,
- type: 'warning',
- title: 'Unusual Port Activity',
- description: 'High traffic detected on non-standard port 8447',
- timestamp: new Date(Date.now() - 7200000).toISOString(),
- source_ip: '192.168.1.33',
- destination_ip: '172.16.254.1',
- severity: 'medium',
- status: 'investigating',
- packets: 2847,
- data_size: '45MB'
- }
- ],
-
- // Alert Summary
- alertSummary: {
- total: 147,
- critical: 23,
- high: 45,
- medium: 52,
- low: 27,
- last_24h: 18,
- last_week: 89,
- resolved: 124,
- open: 23
- },
-
- // VNC Sessions
- vncSessions: [
- {
- id: 1,
- name: 'Production Server Monitor',
- host: '192.168.1.100',
- port: 5901,
- status: 'active',
- created_at: new Date(Date.now() - 3600000).toISOString(),
- last_activity: new Date(Date.now() - 120000).toISOString(),
- user: 'admin',
- vnc_type: 'TigerVNC',
- screen_resolution: '1920x1080',
- active_connections: 2,
- data_transferred: '847MB',
- session_duration: 3600
- },
- {
- id: 2,
- name: 'Development Environment',
- host: '192.168.1.101',
- port: 5902,
- status: 'active',
- created_at: new Date(Date.now() - 7200000).toISOString(),
- last_activity: new Date(Date.now() - 300000).toISOString(),
- user: 'developer',
- vnc_type: 'RealVNC',
- screen_resolution: '1366x768',
- active_connections: 1,
- data_transferred: '234MB',
- session_duration: 7200
- },
- {
- id: 3,
- name: 'Database Server Access',
- host: '192.168.1.102',
- port: 5903,
- status: 'inactive',
- created_at: new Date(Date.now() - 86400000).toISOString(),
- last_activity: new Date(Date.now() - 3600000).toISOString(),
- user: 'dbadmin',
- vnc_type: 'TigerVNC',
- screen_resolution: '1024x768',
- active_connections: 0,
- data_transferred: '1.2GB',
- session_duration: 14400
- },
- {
- id: 4,
- name: 'Test Server',
- host: '192.168.1.103',
- port: 5904,
- status: 'stopped',
- created_at: new Date(Date.now() - 172800000).toISOString(),
- last_activity: new Date(Date.now() - 86400000).toISOString(),
- user: 'tester',
- vnc_type: 'RealVNC',
- screen_resolution: '1920x1200',
- active_connections: 0,
- data_transferred: '567MB',
- session_duration: 0
- }
- ],
-
- // Firewall Rules
- firewallRules: [
- {
- id: 1,
- name: 'Block Suspicious IPs',
- action: 'BLOCK',
- protocol: 'TCP',
- source_ip: '185.199.108.0/24',
- destination_port: '*',
- enabled: true,
- priority: 100,
- created_at: new Date(Date.now() - 86400000).toISOString(),
- hits: 1247,
- last_hit: new Date(Date.now() - 300000).toISOString()
- },
- {
- id: 2,
- name: 'Allow VNC Traffic',
- action: 'ALLOW',
- protocol: 'TCP',
- source_ip: '192.168.1.0/24',
- destination_port: '590x',
- enabled: true,
- priority: 50,
- created_at: new Date(Date.now() - 172800000).toISOString(),
- hits: 15420,
- last_hit: new Date(Date.now() - 120000).toISOString()
- },
- {
- id: 3,
- name: 'Block Port 8447',
- action: 'BLOCK',
- protocol: 'TCP',
- source_ip: '*',
- destination_port: '8447',
- enabled: true,
- priority: 75,
- created_at: new Date(Date.now() - 7200000).toISOString(),
- hits: 342,
- last_hit: new Date(Date.now() - 1800000).toISOString()
- },
- {
- id: 4,
- name: 'Allow HTTP/HTTPS',
- action: 'ALLOW',
- protocol: 'TCP',
- source_ip: '*',
- destination_port: '80,443',
- enabled: true,
- priority: 10,
- created_at: new Date(Date.now() - 259200000).toISOString(),
- hits: 234789,
- last_hit: new Date(Date.now() - 10000).toISOString()
- }
- ],
-
- // Network Monitoring Data
- networkData: {
- interfaces: [
- {
- name: 'eth0',
- status: 'up',
- rx_bytes: 2847392000,
- tx_bytes: 1847392000,
- rx_packets: 2847392,
- tx_packets: 1847392,
- errors: 0,
- drops: 12
- },
- {
- name: 'eth1',
- status: 'up',
- rx_bytes: 847392000,
- tx_bytes: 647392000,
- rx_packets: 847392,
- tx_packets: 647392,
- errors: 2,
- drops: 5
- }
- ],
- protocols: {
- TCP: 65,
- UDP: 25,
- ICMP: 8,
- Other: 2
- },
- top_talkers: [
- { ip: '192.168.1.100', bytes: 847392000, packets: 847392 },
- { ip: '192.168.1.101', bytes: 234789000, packets: 234789 },
- { ip: '192.168.1.102', bytes: 156423000, packets: 156423 },
- { ip: '185.199.108.153', bytes: 89456000, packets: 89456 },
- { ip: '203.0.113.42', bytes: 34567000, packets: 34567 }
- ]
- },
-
- // User Management
- users: [
- {
- id: 1,
- username: 'admin',
- email: 'admin@exfilsentry.com',
- role: 'Administrator',
- status: 'active',
- last_login: new Date(Date.now() - 1800000).toISOString(),
- created_at: new Date(Date.now() - 2592000000).toISOString(),
- permissions: ['all']
- },
- {
- id: 2,
- username: 'analyst',
- email: 'analyst@exfilsentry.com',
- role: 'Security Analyst',
- status: 'active',
- last_login: new Date(Date.now() - 3600000).toISOString(),
- created_at: new Date(Date.now() - 1296000000).toISOString(),
- permissions: ['view_alerts', 'manage_alerts', 'view_monitoring']
- },
- {
- id: 3,
- username: 'operator',
- email: 'operator@exfilsentry.com',
- role: 'Network Operator',
- status: 'active',
- last_login: new Date(Date.now() - 7200000).toISOString(),
- created_at: new Date(Date.now() - 864000000).toISOString(),
- permissions: ['view_monitoring', 'manage_vnc']
- }
- ],
-
- // System Information
- systemInfo: {
- version: '2.1.0',
- uptime: 2592000,
- cpu_usage: 23.5,
- memory_usage: 67.2,
- disk_usage: 45.8,
- network_interfaces: 2,
- active_rules: 4,
- total_sessions: 4
- }
-};
-
-// Helper functions to simulate API calls
-export const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
-
-export const mockApiCall = async (data, delayMs = 100) => {
- await delay(delayMs);
- return data;
-};
\ No newline at end of file
diff --git a/frontend/src/pages/Dashboard.js b/frontend/src/pages/Dashboard.js
index 8f76f35..592fafa 100644
--- a/frontend/src/pages/Dashboard.js
+++ b/frontend/src/pages/Dashboard.js
@@ -18,17 +18,44 @@ import {
Block,
} from '@mui/icons-material';
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip as RechartsTooltip, ResponsiveContainer, BarChart, Bar } from 'recharts';
-import { mockData } from '../data/mockData';
+import { api } from '../services/api';
const Dashboard = () => {
const [data, setData] = useState({
- monitoringStatus: mockData.monitoringStatus,
- trafficStats: mockData.trafficStats,
- alertSummary: mockData.alertSummary,
- vncSessions: mockData.vncSessions,
- systemInfo: mockData.systemInfo,
+ monitoringStatus: null,
+ trafficStats: null,
+ alertSummary: null,
+ vncSessions: [],
+ systemInfo: null,
});
+ // Fetch all dashboard data from json-server
+ useEffect(() => {
+ const fetchDashboardData = async () => {
+ try {
+ const [monitoringStatus, trafficStats, alertSummary, vncSessions, systemInfo] = await Promise.all([
+ api.getMonitoringStatus(),
+ api.getTrafficStats(),
+ api.getAlertSummary(),
+ api.getVncSessions(),
+ api.getSystemInfo(),
+ ]);
+
+ setData({
+ monitoringStatus,
+ trafficStats,
+ alertSummary,
+ vncSessions,
+ systemInfo,
+ });
+ } catch (error) {
+ console.error('Failed to fetch dashboard data:', error);
+ }
+ };
+
+ fetchDashboardData();
+ }, []);
+
// Destructure data for easier access
const { monitoringStatus, trafficStats, alertSummary, vncSessions } = data;
diff --git a/frontend/src/pages/Firewall.js b/frontend/src/pages/Firewall.js
index 9ba473f..11bee27 100644
--- a/frontend/src/pages/Firewall.js
+++ b/frontend/src/pages/Firewall.js
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import React, { useState, useEffect } from 'react';
import {
Box,
Typography,
@@ -40,10 +40,10 @@ import {
PlayArrow,
Stop,
} from '@mui/icons-material';
-import { mockData } from '../data/mockData';
+import { api } from '../services/api';
const Firewall = () => {
- const [rules, setRules] = useState(mockData.firewallRules);
+ const [rules, setRules] = useState([]);
const [openDialog, setOpenDialog] = useState(false);
const [selectedRule, setSelectedRule] = useState(null);
const [dialogType, setDialogType] = useState('create'); // 'create', 'edit', 'view'
@@ -57,6 +57,20 @@ const Firewall = () => {
enabled: true
});
+ // Fetch firewall rules from json-server
+ useEffect(() => {
+ const fetchRules = async () => {
+ try {
+ const data = await api.getFirewallRules();
+ setRules(data);
+ } catch (error) {
+ console.error('Failed to fetch firewall rules:', error);
+ }
+ };
+
+ fetchRules();
+ }, []);
+
const handleCreateRule = () => {
setDialogType('create');
setSelectedRule(null);
diff --git a/frontend/src/pages/Monitoring.js b/frontend/src/pages/Monitoring.js
index ffca932..4bb4091 100644
--- a/frontend/src/pages/Monitoring.js
+++ b/frontend/src/pages/Monitoring.js
@@ -39,14 +39,43 @@ import {
Timeline,
} from '@mui/icons-material';
import { AreaChart, Area, BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip as RechartsTooltip, ResponsiveContainer } from 'recharts';
-import { mockData } from '../data/mockData';
+import { api } from '../services/api';
const Monitoring = () => {
const [isMonitoring, setIsMonitoring] = useState(true);
- const [trafficData, setTrafficData] = useState(mockData.trafficStats.hourly_data);
- const [networkData] = useState(mockData.networkData);
+ const [trafficData, setTrafficData] = useState([]);
+ const [trafficStats, setTrafficStats] = useState({
+ total_packets: 0,
+ suspicious_packets: 0,
+ blocked_packets: 0,
+ data_transferred: '0TB'
+ });
+ const [networkData, setNetworkData] = useState(null);
const [lastUpdated, setLastUpdated] = useState(new Date());
+ // Fetch monitoring data from json-server
+ useEffect(() => {
+ const fetchMonitoringData = async () => {
+ try {
+ const trafficStatsData = await api.getTrafficStats();
+ const netData = await api.getNetworkData();
+
+ setTrafficStats({
+ total_packets: trafficStatsData.total_packets || 0,
+ suspicious_packets: trafficStatsData.suspicious_packets || 0,
+ blocked_packets: trafficStatsData.blocked_packets || 0,
+ data_transferred: trafficStatsData.data_transferred || '0TB'
+ });
+ setTrafficData(trafficStatsData.hourly_data || []);
+ setNetworkData(netData);
+ } catch (error) {
+ console.error('Failed to fetch monitoring data:', error);
+ }
+ };
+
+ fetchMonitoringData();
+ }, []);
+
useEffect(() => {
// Simulate real-time data updates
const interval = setInterval(() => {
@@ -66,16 +95,18 @@ const Monitoring = () => {
setIsMonitoring(prev => !prev);
};
- const protocolData = Object.entries(networkData.protocols).map(([protocol, percentage]) => ({
- protocol,
- percentage,
- color: {
- TCP: '#9c27b0',
- UDP: '#e91e63',
- ICMP: '#2196f3',
- Other: '#ff9800'
- }[protocol]
- }));
+ const protocolData = networkData && networkData.protocols
+ ? Object.entries(networkData.protocols).map(([protocol, percentage]) => ({
+ protocol,
+ percentage,
+ color: {
+ TCP: '#9c27b0',
+ UDP: '#e91e63',
+ ICMP: '#2196f3',
+ Other: '#ff9800'
+ }[protocol]
+ }))
+ : [];
return (
@@ -162,7 +193,7 @@ const Monitoring = () => {
Total Packets
- {mockData.trafficStats.total_packets.toLocaleString()}
+ {trafficStats.total_packets.toLocaleString()}
Last 24 hours
@@ -200,10 +231,10 @@ const Monitoring = () => {
Suspicious
- {mockData.trafficStats.suspicious_packets.toLocaleString()}
+ {trafficStats.suspicious_packets.toLocaleString()}
- {((mockData.trafficStats.suspicious_packets / mockData.trafficStats.total_packets) * 100).toFixed(2)}% of total
+ {trafficStats.total_packets > 0 ? ((trafficStats.suspicious_packets / trafficStats.total_packets) * 100).toFixed(2) : '0'}% of total
@@ -238,7 +269,7 @@ const Monitoring = () => {
Blocked
- {mockData.trafficStats.blocked_packets.toLocaleString()}
+ {trafficStats.blocked_packets.toLocaleString()}
Automatically blocked
@@ -276,7 +307,7 @@ const Monitoring = () => {
Data Volume
- {mockData.trafficStats.data_transferred}
+ {trafficStats.data_transferred}
Total transferred
@@ -358,7 +389,7 @@ const Monitoring = () => {
- {networkData.interfaces.map((iface) => (
+ {networkData && networkData.interfaces ? networkData.interfaces.map((iface) => (
{iface.name}
@@ -373,7 +404,13 @@ const Monitoring = () => {
{iface.tx_packets.toLocaleString()}
{iface.errors}
- ))}
+ )) : (
+
+
+ Loading network interfaces...
+
+
+ )}
@@ -387,7 +424,7 @@ const Monitoring = () => {
Top Traffic Sources
- {networkData.top_talkers.map((talker, index) => (
+ {networkData && networkData.top_talkers ? networkData.top_talkers.map((talker, index) => (
@@ -440,7 +477,11 @@ const Monitoring = () => {
{index < networkData.top_talkers.length - 1 && }
- ))}
+ )) : (
+
+
+
+ )}
diff --git a/frontend/src/pages/SecurityAlerts.js b/frontend/src/pages/SecurityAlerts.js
index c4632a8..1e807a9 100644
--- a/frontend/src/pages/SecurityAlerts.js
+++ b/frontend/src/pages/SecurityAlerts.js
@@ -43,11 +43,26 @@ import {
Timeline,
Shield,
} from '@mui/icons-material';
-import { mockData } from '../data/mockData';
+import { api } from '../services/api';
const SecurityAlerts = () => {
- const [alerts, setAlerts] = useState(mockData.alerts);
- const [filteredAlerts, setFilteredAlerts] = useState(mockData.alerts);
+ const [alerts, setAlerts] = useState([]);
+ const [filteredAlerts, setFilteredAlerts] = useState([]);
+
+ // Fetch alerts from json-server
+ useEffect(() => {
+ const fetchAlerts = async () => {
+ try {
+ const data = await api.getAlerts();
+ setAlerts(data);
+ setFilteredAlerts(data);
+ } catch (error) {
+ console.error('Failed to fetch alerts:', error);
+ }
+ };
+
+ fetchAlerts();
+ }, []);
const [selectedAlert, setSelectedAlert] = useState(null);
const [openDialog, setOpenDialog] = useState(false);
const [filterSeverity, setFilterSeverity] = useState('all');
diff --git a/frontend/src/pages/VNCSessions.js b/frontend/src/pages/VNCSessions.js
index 8750264..568141e 100644
--- a/frontend/src/pages/VNCSessions.js
+++ b/frontend/src/pages/VNCSessions.js
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import React, { useState, useEffect } from 'react';
import {
Box,
Typography,
@@ -36,14 +36,28 @@ import {
Storage,
People,
} from '@mui/icons-material';
-import { mockData } from '../data/mockData';
+import { api } from '../services/api';
const VNCSessions = () => {
- const [sessions, setSessions] = useState(mockData.vncSessions);
+ const [sessions, setSessions] = useState([]);
const [openDialog, setOpenDialog] = useState(false);
const [selectedSession, setSelectedSession] = useState(null);
const [dialogType, setDialogType] = useState('create'); // 'create', 'edit', 'view'
+ // Fetch VNC sessions from json-server
+ useEffect(() => {
+ const fetchSessions = async () => {
+ try {
+ const data = await api.getVncSessions();
+ setSessions(data);
+ } catch (error) {
+ console.error('Failed to fetch VNC sessions:', error);
+ }
+ };
+
+ fetchSessions();
+ }, []);
+
const handleCreateSession = () => {
setDialogType('create');
setSelectedSession(null);
diff --git a/frontend/src/services/api.js b/frontend/src/services/api.js
new file mode 100644
index 0000000..f144848
--- /dev/null
+++ b/frontend/src/services/api.js
@@ -0,0 +1,98 @@
+// API service for json-server
+const API_BASE_URL = 'http://localhost:4000';
+
+export const api = {
+ // Monitoring endpoints
+ getMonitoringStatus: async () => {
+ const response = await fetch(`${API_BASE_URL}/monitoringStatus`);
+ return response.json();
+ },
+
+ getTrafficStats: async () => {
+ const response = await fetch(`${API_BASE_URL}/trafficStats`);
+ return response.json();
+ },
+
+ // Alerts endpoints
+ getAlerts: async () => {
+ const response = await fetch(`${API_BASE_URL}/alerts`);
+ return response.json();
+ },
+
+ getAlertSummary: async () => {
+ const response = await fetch(`${API_BASE_URL}/alertSummary`);
+ return response.json();
+ },
+
+ // VNC Sessions endpoints
+ getVncSessions: async () => {
+ const response = await fetch(`${API_BASE_URL}/vncSessions`);
+ return response.json();
+ },
+
+ // Firewall endpoints
+ getFirewallRules: async () => {
+ const response = await fetch(`${API_BASE_URL}/firewallRules`);
+ return response.json();
+ },
+
+ // Network Data endpoints
+ getNetworkData: async () => {
+ const response = await fetch(`${API_BASE_URL}/networkData`);
+ return response.json();
+ },
+
+ // Users endpoints
+ getUsers: async () => {
+ const response = await fetch(`${API_BASE_URL}/users`);
+ return response.json();
+ },
+
+ // System Info endpoints
+ getSystemInfo: async () => {
+ const response = await fetch(`${API_BASE_URL}/systemInfo`);
+ return response.json();
+ },
+
+ // Update endpoints (POST, PUT, DELETE)
+ updateAlert: async (id, data) => {
+ const response = await fetch(`${API_BASE_URL}/alerts/${id}`, {
+ method: 'PUT',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify(data),
+ });
+ return response.json();
+ },
+
+ deleteAlert: async (id) => {
+ const response = await fetch(`${API_BASE_URL}/alerts/${id}`, {
+ method: 'DELETE',
+ });
+ return response.json();
+ },
+
+ createFirewallRule: async (data) => {
+ const response = await fetch(`${API_BASE_URL}/firewallRules`, {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify(data),
+ });
+ return response.json();
+ },
+
+ updateFirewallRule: async (id, data) => {
+ const response = await fetch(`${API_BASE_URL}/firewallRules/${id}`, {
+ method: 'PUT',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify(data),
+ });
+ return response.json();
+ },
+
+ deleteFirewallRule: async (id) => {
+ const response = await fetch(`${API_BASE_URL}/firewallRules/${id}`, {
+ method: 'DELETE',
+ });
+ return response.json();
+ },
+};
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..2d66234
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,501 @@
+{
+ "name": "Exfil-Sentry",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "devDependencies": {
+ "json-server": "^1.0.0-beta.3"
+ }
+ },
+ "node_modules/@polka/url": {
+ "version": "1.0.0-next.29",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@tinyhttp/accepts": {
+ "version": "2.2.3",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "mime": "4.0.4",
+ "negotiator": "^0.6.3"
+ },
+ "engines": {
+ "node": ">=12.20.0"
+ },
+ "funding": {
+ "type": "individual",
+ "url": "https://github.com/tinyhttp/tinyhttp?sponsor=1"
+ }
+ },
+ "node_modules/@tinyhttp/app": {
+ "version": "2.5.2",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@tinyhttp/cookie": "2.1.1",
+ "@tinyhttp/proxy-addr": "2.2.1",
+ "@tinyhttp/req": "2.2.5",
+ "@tinyhttp/res": "2.2.5",
+ "@tinyhttp/router": "2.2.3",
+ "header-range-parser": "1.1.3",
+ "regexparam": "^2.0.2"
+ },
+ "engines": {
+ "node": ">=14.21.3"
+ },
+ "funding": {
+ "type": "individual",
+ "url": "https://github.com/tinyhttp/tinyhttp?sponsor=1"
+ }
+ },
+ "node_modules/@tinyhttp/content-disposition": {
+ "version": "2.2.2",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.20.0"
+ },
+ "funding": {
+ "type": "individual",
+ "url": "https://github.com/tinyhttp/tinyhttp?sponsor=1"
+ }
+ },
+ "node_modules/@tinyhttp/content-type": {
+ "version": "0.1.4",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.4"
+ }
+ },
+ "node_modules/@tinyhttp/cookie": {
+ "version": "2.1.1",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.20.0"
+ },
+ "funding": {
+ "type": "individual",
+ "url": "https://github.com/tinyhttp/tinyhttp?sponsor=1"
+ }
+ },
+ "node_modules/@tinyhttp/cookie-signature": {
+ "version": "2.1.1",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.20.0"
+ }
+ },
+ "node_modules/@tinyhttp/cors": {
+ "version": "2.0.1",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@tinyhttp/vary": "^0.1.3"
+ },
+ "engines": {
+ "node": ">=12.20 || 14.x || >=16"
+ }
+ },
+ "node_modules/@tinyhttp/encode-url": {
+ "version": "2.1.1",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.20.0"
+ }
+ },
+ "node_modules/@tinyhttp/etag": {
+ "version": "2.1.2",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.20.0"
+ }
+ },
+ "node_modules/@tinyhttp/forwarded": {
+ "version": "2.1.2",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.20.0"
+ }
+ },
+ "node_modules/@tinyhttp/logger": {
+ "version": "2.1.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "colorette": "^2.0.20",
+ "dayjs": "^1.11.13",
+ "http-status-emojis": "^2.2.0"
+ },
+ "engines": {
+ "node": ">=14.18 || >=16.20"
+ }
+ },
+ "node_modules/@tinyhttp/proxy-addr": {
+ "version": "2.2.1",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@tinyhttp/forwarded": "2.1.2",
+ "ipaddr.js": "^2.2.0"
+ },
+ "engines": {
+ "node": ">=12.20.0"
+ }
+ },
+ "node_modules/@tinyhttp/req": {
+ "version": "2.2.5",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@tinyhttp/accepts": "2.2.3",
+ "@tinyhttp/type-is": "2.2.4",
+ "@tinyhttp/url": "2.1.1",
+ "header-range-parser": "^1.1.3"
+ },
+ "engines": {
+ "node": ">=12.20.0"
+ }
+ },
+ "node_modules/@tinyhttp/res": {
+ "version": "2.2.5",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@tinyhttp/content-disposition": "2.2.2",
+ "@tinyhttp/cookie": "2.1.1",
+ "@tinyhttp/cookie-signature": "2.1.1",
+ "@tinyhttp/encode-url": "2.1.1",
+ "@tinyhttp/req": "2.2.5",
+ "@tinyhttp/send": "2.2.3",
+ "@tinyhttp/vary": "^0.1.3",
+ "es-escape-html": "^0.1.1",
+ "mime": "4.0.4"
+ },
+ "engines": {
+ "node": ">=12.20.0"
+ }
+ },
+ "node_modules/@tinyhttp/router": {
+ "version": "2.2.3",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.20.0"
+ }
+ },
+ "node_modules/@tinyhttp/send": {
+ "version": "2.2.3",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@tinyhttp/content-type": "^0.1.4",
+ "@tinyhttp/etag": "2.1.2",
+ "mime": "4.0.4"
+ },
+ "engines": {
+ "node": ">=12.20.0"
+ }
+ },
+ "node_modules/@tinyhttp/type-is": {
+ "version": "2.2.4",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@tinyhttp/content-type": "^0.1.4",
+ "mime": "4.0.4"
+ },
+ "engines": {
+ "node": ">=12.20.0"
+ }
+ },
+ "node_modules/@tinyhttp/url": {
+ "version": "2.1.1",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.20.0"
+ }
+ },
+ "node_modules/@tinyhttp/vary": {
+ "version": "0.1.3",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.20"
+ }
+ },
+ "node_modules/chalk": {
+ "version": "5.6.2",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^12.17.0 || ^14.13 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/chokidar": {
+ "version": "4.0.3",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "readdirp": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 14.16.0"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
+ "node_modules/colorette": {
+ "version": "2.0.20",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/dayjs": {
+ "version": "1.11.19",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/dot-prop": {
+ "version": "9.0.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "type-fest": "^4.18.2"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/es-escape-html": {
+ "version": "0.1.1",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.x"
+ }
+ },
+ "node_modules/eta": {
+ "version": "3.5.0",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/eta-dev/eta?sponsor=1"
+ }
+ },
+ "node_modules/header-range-parser": {
+ "version": "1.1.3",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.22.0"
+ }
+ },
+ "node_modules/http-status-emojis": {
+ "version": "2.2.0",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/inflection": {
+ "version": "3.0.2",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "node_modules/ipaddr.js": {
+ "version": "2.2.0",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/json-server": {
+ "version": "1.0.0-beta.3",
+ "resolved": "https://registry.npmjs.org/json-server/-/json-server-1.0.0-beta.3.tgz",
+ "integrity": "sha512-DwE69Ep5ccwIJZBUIWEENC30Yj8bwr4Ax9W9VoIWAYnB8Sj4ReptscO8/DRHv/nXwVlmb3Bk73Ls86+VZdYkkA==",
+ "dev": true,
+ "license": "SEE LICENSE IN ./LICENSE",
+ "dependencies": {
+ "@tinyhttp/app": "^2.4.0",
+ "@tinyhttp/cors": "^2.0.1",
+ "@tinyhttp/logger": "^2.0.0",
+ "chalk": "^5.3.0",
+ "chokidar": "^4.0.1",
+ "dot-prop": "^9.0.0",
+ "eta": "^3.5.0",
+ "inflection": "^3.0.0",
+ "json5": "^2.2.3",
+ "lowdb": "^7.0.1",
+ "milliparsec": "^4.0.0",
+ "sirv": "^2.0.4",
+ "sort-on": "^6.1.0"
+ },
+ "bin": {
+ "json-server": "lib/bin.js"
+ },
+ "engines": {
+ "node": ">=18.3"
+ }
+ },
+ "node_modules/json5": {
+ "version": "2.2.3",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "json5": "lib/cli.js"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/lowdb": {
+ "version": "7.0.1",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "steno": "^4.0.2"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/typicode"
+ }
+ },
+ "node_modules/milliparsec": {
+ "version": "4.0.0",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=20"
+ }
+ },
+ "node_modules/mime": {
+ "version": "4.0.4",
+ "dev": true,
+ "funding": [
+ "https://github.com/sponsors/broofa"
+ ],
+ "license": "MIT",
+ "bin": {
+ "mime": "bin/cli.js"
+ },
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/mrmime": {
+ "version": "2.0.1",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/negotiator": {
+ "version": "0.6.4",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/readdirp": {
+ "version": "4.1.2",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 14.18.0"
+ },
+ "funding": {
+ "type": "individual",
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
+ "node_modules/regexparam": {
+ "version": "2.0.2",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/sirv": {
+ "version": "2.0.4",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@polka/url": "^1.0.0-next.24",
+ "mrmime": "^2.0.0",
+ "totalist": "^3.0.0"
+ },
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/sort-on": {
+ "version": "6.1.1",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "dot-prop": "^9.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/steno": {
+ "version": "4.0.2",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/typicode"
+ }
+ },
+ "node_modules/totalist": {
+ "version": "3.0.1",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/type-fest": {
+ "version": "4.41.0",
+ "dev": true,
+ "license": "(MIT OR CC0-1.0)",
+ "engines": {
+ "node": ">=16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ }
+ }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..8e2b528
--- /dev/null
+++ b/package.json
@@ -0,0 +1,5 @@
+{
+ "devDependencies": {
+ "json-server": "^1.0.0-beta.3"
+ }
+}