Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions AlertsChart.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import React from 'react';
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from 'recharts';

// This component is responsible for rendering the line chart.
// It receives the processed 'data' as a prop from App.js.
const AlertsChart = ({ data }) => {
return (
// ResponsiveContainer makes the chart fill its parent div.
<ResponsiveContainer width="100%" height="100%">
<LineChart
data={data}
margin={{
top: 5,
right: 30,
left: 0,
bottom: 5,
}}
>
{/* CartesianGrid adds the background grid for readability */}
<CartesianGrid strokeDasharray="3 3" stroke="#233554" />

{/* XAxis defines the horizontal axis (our timestamps) */}
<XAxis dataKey="time" stroke="#a8b2d1" />

{/* YAxis defines the vertical axis (number of alerts) */}
{/* allowDecimals={false} ensures we only see whole numbers like 1, 2, 3 */}
<YAxis allowDecimals={false} stroke="#a8b2d1" />

{/* Tooltip shows details when you hover over a data point */}
<Tooltip
contentStyle={{
backgroundColor: '#112240',
borderColor: '#233554'
}}
/>

{/* Legend displays the name of the data line */}
<Legend />

{/* Line defines the actual line on the chart */}
<Line
type="monotone"
dataKey="alerts" // This should match the key in our data objects
stroke="#64ffda" // The accent color for the line
strokeWidth={2}
activeDot={{ r: 8 }}
/>
</LineChart>
</ResponsiveContainer>
);
};

export default AlertsChart;
7 changes: 7 additions & 0 deletions App.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.App {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
text-align: center;
padding: 40px 20px;
background: linear-gradient(120deg, #e0eafc, #cfdef3);
min-height: 100vh;
}
213 changes: 213 additions & 0 deletions App.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
import React, { useState, useEffect } from 'react';

// --- MOCK DATA ---
const initialAlerts = [
{
id: 'a1',
ip: '81.2.69.142',
timestamp: '2025-09-25T23:40:15Z',
country: 'United Kingdom',
city: 'London',
device: 'Desktop',
os: 'Windows 10',
browser: 'Chrome 115',
rtt: 120,
riskLevel: 'High',
isAttack: true,
reason: 'Login from a known malicious IP address and unusual location for this user.'
},
{
id: 'a2',
ip: '103.27.132.190',
timestamp: '2025-09-25T23:39:55Z',
country: 'India',
city: 'Mumbai',
device: 'Mobile',
os: 'Android 13',
browser: 'Firefox 112',
rtt: 85,
riskLevel: 'Medium',
isAttack: false,
reason: 'Successful login but with a significantly higher RTT than usual for this region.'
},
{
id: 'a3',
ip: '197.210.65.112',
timestamp: '2025-09-25T23:39:21Z',
country: 'Nigeria',
city: 'Lagos',
device: 'Desktop',
os: 'Linux',
browser: 'Chrome 114',
rtt: 250,
riskLevel: 'High',
isAttack: true,
reason: 'Impossible travel scenario. User logged in from Norway 20 minutes prior.'
},
{
id: 'a4',
ip: '47.91.68.231',
timestamp: '2025-09-25T23:38:40Z',
country: 'Norway',
city: 'Oslo',
device: 'Desktop',
os: 'macOS',
browser: 'Safari 16.5',
rtt: 15,
riskLevel: 'Low',
isAttack: false,
reason: 'Typical login from a recognized device and location.'
}
];

// --- COMPONENTS (These are unchanged) ---

const Header = () => (
<header className="header">
<h1>Cyberattack Detection System</h1>
<div className="status-indicator">
<div className="dot"></div>
<span>Real-time Monitoring</span>
</div>
</header>
);

const KeyMetrics = ({ alerts }) => {
const totalLogins = 53201 + alerts.length - initialAlerts.length; // Now dynamic!
const suspiciousCount = alerts.filter(a => a.riskLevel !== 'Low').length;
const accountsAtRisk = alerts.filter(a => a.isAttack).length;

return (
<div className="key-metrics-card">
<div className="metric-item">
<h3>Total Logins (24h)</h3>
<div className="value">{totalLogins.toLocaleString()}</div>
</div>
<div className="metric-item">
<h3>Suspicious Activity</h3>
<div className="value">{suspiciousCount}</div>
</div>
<div className="metric-item">
<h3>Accounts At Risk</h3>
<div className="value" style={{ color: 'var(--red-accent)' }}>{accountsAtRisk}</div>
</div>
</div>
);
};

const AlertsFeed = ({ alerts, onSelectAlert, selectedAlert }) => (
<div className="dashboard-card alerts-feed">
<h2>Real-time Alerts</h2>
<div className="alerts-list">
{alerts.map(alert => (
<div
key={alert.id}
className={`alert-item ${selectedAlert?.id === alert.id ? 'selected' : ''}`}
onClick={() => onSelectAlert(alert)}
>
<div className="alert-info">
<div className="ip">{alert.ip}</div>
<div className="location">{`${alert.city}, ${alert.country}`}</div>
</div>
<div className={`risk-level ${alert.riskLevel}`}>{alert.riskLevel}</div>
</div>
))}
</div>
</div>
);

const AlertDetails = ({ alert }) => {
if (!alert) {
return (
<div className="dashboard-card alert-details" style={{ display: 'grid', placeContent: 'center' }}>
<p>Select an alert to view details</p>
</div>
);
}

return (
<div className="dashboard-card alert-details">
<h2>Alert Details: {alert.ip}</h2>
<div className="detail-grid">
<div className="detail-item"><strong>Geolocation</strong> {`${alert.city}, ${alert.country}`}</div>
<div className="detail-item"><strong>Device Type</strong> {alert.device}</div>
<div className="detail-item"><strong>Operating System</strong> {alert.os}</div>
<div className="detail-item"><strong>Browser</strong> {alert.browser}</div>
<div className="detail-item"><strong>Round-Trip Time</strong> {alert.rtt} ms</div>
<div className="detail-item"><strong>Timestamp</strong> {new Date(alert.timestamp).toLocaleString()}</div>
<div className="detail-item" style={{ gridColumn: 'span 2' }}>
<strong>Risk Analysis</strong>
<span style={{ color: alert.isAttack ? 'var(--red-accent)' : 'var(--lightest-slate)'}}>
{alert.reason}
</span>
</div>
</div>
</div>
);
};


// --- MAIN APP ---
function App() {
const [alerts, setAlerts] = useState(initialAlerts);
const [selectedAlert, setSelectedAlert] = useState(null);

// --- NEW: Simulate real-time data arriving every 5 seconds ---
useEffect(() => {
const interval = setInterval(() => {
// Create a new mock alert
const newAlert = {
id: `a${Date.now()}`, // Unique ID based on timestamp
ip: '203.0.113.25',
timestamp: new Date().toISOString(),
country: 'Japan',
city: 'Tokyo',
device: 'Mobile',
os: 'iOS 17',
browser: 'Safari 17.0',
rtt: 150,
riskLevel: 'Medium',
isAttack: false,
reason: 'Suspicious login from a new device for this user account.'
};

// Add the new alert to the top of the list
// This uses the 'setAlerts' function we talked about!
setAlerts(currentAlerts => [newAlert, ...currentAlerts]);

}, 5000); // 5000 milliseconds = 5 seconds

// Cleanup the interval when the component unmounts to prevent memory leaks
return () => clearInterval(interval);
}, []); // The empty array [] means this effect runs only once when the app starts

// On first load, select the highest priority alert
useEffect(() => {
if (!selectedAlert && alerts.length > 0) {
const highPriorityAlert = alerts.find(a => a.riskLevel === 'High');
setSelectedAlert(highPriorityAlert || alerts[0]);
}
}, [alerts, selectedAlert]);


return (
<div className="app-container">
<Header />
<div className="dashboard-grid">
<div className="key-metrics-card" style={{ gridColumn: 'span 12' }}>
<KeyMetrics alerts={alerts} />
</div>

<AlertsFeed
alerts={alerts}
selectedAlert={selectedAlert}
onSelectAlert={setSelectedAlert}
/>

<AlertDetails alert={selectedAlert} />
</div>
</div>
);
}

export default App;
15 changes: 15 additions & 0 deletions components/Button.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
.btn {
padding: 12px 25px;
background: linear-gradient(90deg, #ff416c, #ff4b2b);
color: white;
border: none;
border-radius: 8px;
font-weight: bold;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 5px 15px rgba(0,0,0,0.2);
}
.btn:hover {
transform: translateY(-3px);
box-shadow: 0 8px 20px rgba(0,0,0,0.3);
}
12 changes: 12 additions & 0 deletions components/Button.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import React from 'react';
import './Button.css';

function Button({ text, onClick }) {
return (
<button className="btn" onClick={onClick}>
{text}
</button>
);
}

export default Button;
7 changes: 7 additions & 0 deletions components/Dashboard.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.dashboard {
display: flex;
justify-content: center;
gap: 20px;
margin-bottom: 25px;
flex-wrap: wrap;
}
15 changes: 15 additions & 0 deletions components/Dashboard.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from 'react';
import Button from './Button';
import './Dashboard.css';

function Dashboard({ handleAction }) {
return (
<div className="dashboard">
<Button text="Start Detection" onClick={() => handleAction("Detection Started")} />
<Button text="Stop Detection" onClick={() => handleAction("Detection Stopped")} />
<Button text="View Reports" onClick={() => handleAction("Viewing Reports")} />
</div>
);
}

export default Dashboard;
16 changes: 16 additions & 0 deletions components/Header.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
.header {
background: linear-gradient(90deg, #1f1c2c, #928dab);
color: white;
padding: 25px;
border-radius: 12px;
margin-bottom: 30px;
box-shadow: 0 4px 10px rgba(0,0,0,0.3);
}
.header h1 {
font-size: 2rem;
margin-bottom: 5px;
}
.header p {
font-size: 1.1rem;
opacity: 0.8;
}
13 changes: 13 additions & 0 deletions components/Header.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React from 'react';
import './Header.css';

function Header() {
return (
<header className="header">
<h1>🛡️ Cyberattack Detection System</h1>
<p>Monitor unusual login activity in real-time</p>
</header>
);
}

export default Header;
24 changes: 24 additions & 0 deletions components/Logs.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
.logs-container {
max-width: 600px;
margin: 0 auto;
background-color: #f5f5f5;
padding: 20px;
border-radius: 12px;
box-shadow: 0 5px 15px rgba(0,0,0,0.1);
}
.logs-container h2 {
text-align: center;
margin-bottom: 15px;
color: #333;
}
.logs-container ul {
list-style-type: none;
padding-left: 0;
}
.logs-container li {
padding: 8px 10px;
margin-bottom: 8px;
background: #fff;
border-radius: 5px;
box-shadow: 0 2px 5px rgba(0,0,0,0.05);
}
Loading