Build IP Sentinel operations console

This commit is contained in:
Codex
2026-08-09 15:22:28 +03:00
commit cf8c51e3e8
28 changed files with 7068 additions and 0 deletions

93
app/page.tsx Normal file
View File

@@ -0,0 +1,93 @@
"use client";
import { useMemo, useState } from "react";
type Event = { ip: string; country: string; city: string; network: string; score: number; status: "Review" | "Blocked" | "Allowed"; seen: string; requests: string };
const initialEvents: Event[] = [
{ ip: "185.220.101.42", country: "Germany", city: "Falkenstein", network: "AS60729 · Zwiebelfreunde", score: 96, status: "Review", seen: "12 sec ago", requests: "842" },
{ ip: "45.134.26.91", country: "Netherlands", city: "Amsterdam", network: "AS9009 · M247 Europe", score: 88, status: "Blocked", seen: "1 min ago", requests: "391" },
{ ip: "104.28.208.87", country: "United States", city: "San Francisco", network: "AS13335 · Cloudflare", score: 18, status: "Allowed", seen: "3 min ago", requests: "126" },
{ ip: "193.32.162.14", country: "Romania", city: "Bucharest", network: "AS209605 · UAB Host Baltic", score: 73, status: "Review", seen: "7 min ago", requests: "214" },
{ ip: "34.160.111.145", country: "United States", city: "Mountain View", network: "AS396982 · Google Cloud", score: 7, status: "Allowed", seen: "11 min ago", requests: "98" },
];
function riskLabel(score: number) { return score >= 80 ? "Critical" : score >= 60 ? "Elevated" : "Low"; }
export default function Home() {
const [query, setQuery] = useState("");
const [filter, setFilter] = useState("All traffic");
const [events, setEvents] = useState(initialEvents);
const [selected, setSelected] = useState<Event>(initialEvents[0]);
const [notice, setNotice] = useState("");
const visible = useMemo(() => events.filter((e) => filter === "All traffic" || e.status === filter), [events, filter]);
const inspect = () => {
const value = query.trim();
if (!value) return;
const found = events.find((e) => e.ip === value);
if (found) setSelected(found);
else setSelected({ ip: value, country: "Unknown", city: "Unresolved", network: "No network record", score: 42, status: "Review", seen: "Just now", requests: "1" });
setNotice(`Inspection opened for ${value}`);
setTimeout(() => setNotice(""), 2400);
};
const decide = (status: "Blocked" | "Allowed") => {
setSelected((current) => ({ ...current, status }));
setEvents((current) => current.map((event) => event.ip === selected.ip ? { ...event, status } : event));
setNotice(`${selected.ip} ${status.toLowerCase()}`);
setTimeout(() => setNotice(""), 2400);
};
return (
<main>
<header className="topbar">
<div className="brand"><span className="brandMark">IP</span><span>Sentinel</span></div>
<nav aria-label="Primary navigation">
<button className="navActive">Overview</button><button>Investigations</button><button>Rules</button><button>Reports</button>
</nav>
<div className="topActions"><button className="iconButton" aria-label="Notifications"></button><div className="avatar">MK</div><div><strong>Maya Kim</strong><small>Security Ops</small></div></div>
</header>
<div className="workspace">
<section className="hero">
<div><p className="eyebrow">NETWORK INTELLIGENCE</p><h1>Good morning, Maya.</h1><p>Heres what your perimeter has seen in the last 24 hours.</p></div>
<div className="health"><span className="pulse"/><div><strong>All systems operational</strong><small>Last sync 18 seconds ago</small></div></div>
</section>
<section className="lookup" aria-label="IP address lookup">
<div className="lookupIcon"></div><div className="lookupCopy"><label htmlFor="ip">Inspect an IP address</label><span>Reputation, location, network and recent activity</span></div>
<input id="ip" value={query} onChange={(e) => setQuery(e.target.value)} onKeyDown={(e) => e.key === "Enter" && inspect()} placeholder="Enter IPv4 or IPv6 address" />
<button className="primary" onClick={inspect}>Inspect IP <span></span></button>
</section>
<section className="metrics" aria-label="Traffic summary">
<article><div className="metricTop"><span>REQUESTS SCANNED</span><i className="blue"></i></div><strong>2.48M</strong><p><b>+12.4%</b> from yesterday</p></article>
<article><div className="metricTop"><span>UNIQUE ADDRESSES</span><i className="violet"></i></div><strong>18,294</strong><p><b>+3.1%</b> from yesterday</p></article>
<article><div className="metricTop"><span>THREATS BLOCKED</span><i className="red">!</i></div><strong>1,847</strong><p><em>8.2%</em> from yesterday</p></article>
<article><div className="metricTop"><span>REVIEW QUEUE</span><i className="amber"></i></div><strong>24</strong><p><b>7 critical</b> need attention</p></article>
</section>
<div className="mainGrid">
<section className="panel activity">
<div className="panelHead"><div><h2>Recent activity</h2><p>Addresses with notable behavior</p></div><div className="filters">{["All traffic","Review","Blocked","Allowed"].map((name) => <button key={name} className={filter === name ? "active" : ""} onClick={() => setFilter(name)}>{name}</button>)}</div></div>
<div className="tableWrap"><table><thead><tr><th>IP ADDRESS</th><th>LOCATION / NETWORK</th><th>REQUESTS</th><th>RISK</th><th>STATUS</th><th></th></tr></thead><tbody>{visible.map((event) => <tr key={event.ip} className={selected.ip === event.ip ? "selected" : ""} onClick={() => setSelected(event)}><td><code>{event.ip}</code><small>{event.seen}</small></td><td><strong>{event.city}, {event.country}</strong><small>{event.network}</small></td><td>{event.requests}</td><td><span className={`score ${riskLabel(event.score).toLowerCase()}`}>{event.score}</span></td><td><span className={`status ${event.status.toLowerCase()}`}>{event.status}</span></td><td></td></tr>)}</tbody></table></div>
<button className="viewAll">View all investigations </button>
</section>
<aside className="panel detail">
<div className="detailHead"><div><p>SELECTED ADDRESS</p><code>{selected.ip}</code></div><span className={`status ${selected.status.toLowerCase()}`}>{selected.status}</span></div>
<div className="riskBlock"><div className={`riskRing ${riskLabel(selected.score).toLowerCase()}`}><strong>{selected.score}</strong><span>/100</span></div><div><p>Risk assessment</p><h3>{riskLabel(selected.score)} risk</h3><small>Based on 14 intelligence signals</small></div></div>
<div className="signal"><span>TOR EXIT NODE</span><strong>{selected.score > 80 ? "Detected" : "Not detected"}</strong></div>
<div className="signal"><span>ABUSE REPORTS</span><strong>{selected.score > 80 ? "47 in 30 days" : "None recent"}</strong></div>
<div className="signal"><span>NETWORK</span><strong>{selected.network.split(" · ")[0]}</strong></div>
<div className="signal"><span>LOCATION</span><strong>{selected.city}, {selected.country}</strong></div>
<div className="actions"><button className="danger" onClick={() => decide("Blocked")}>Block address</button><button onClick={() => decide("Allowed")}>Add to allowlist</button></div>
<button className="fullReport">Open full investigation </button>
</aside>
</div>
</div>
{notice && <div className="toast" role="status"><span></span>{notice}</div>}
</main>
);
}