mirror of
https://github.com/mblanke/ThreatHunt.git
synced 2026-03-01 14:00:20 -05:00
EOD.
This commit is contained in:
16
frontend/index.html
Normal file
16
frontend/index.html
Normal file
@@ -0,0 +1,16 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" class="dark">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Velo Threat Hunter</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="stylesheet" href="/src/index.css" />
|
||||
</head>
|
||||
|
||||
<body class="text-white">
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.jsx"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
3200
frontend/package-lock.json
generated
Normal file
3200
frontend/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
30
frontend/package.json
Normal file
30
frontend/package.json
Normal file
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"name": "velo-threat-hunter-ui",
|
||||
"version": "0.1.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@emotion/react": "^11.14.0",
|
||||
"@emotion/styled": "^11.14.0",
|
||||
"@mui/icons-material": "^6.4.8",
|
||||
"@mui/material": "^6.4.8",
|
||||
"@tailwindcss/vite": "^4.1.7",
|
||||
"axios": "^1.10.0",
|
||||
"lucide-react": "^0.515.0",
|
||||
"react": "^18.0.0",
|
||||
"react-dom": "^18.0.0",
|
||||
"react-router": "^7.6.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react-router": "^5.1.20",
|
||||
"@vitejs/plugin-react": "^4.4.1",
|
||||
"autoprefixer": "^10.4.21",
|
||||
"postcss": "^8.5.5",
|
||||
"tailwindcss": "^4.1.10",
|
||||
"vite": "^6.3.5"
|
||||
}
|
||||
}
|
||||
39
frontend/src/App.jsx
Normal file
39
frontend/src/App.jsx
Normal file
@@ -0,0 +1,39 @@
|
||||
import React, { Suspense, useMemo } from "react";
|
||||
import { createTheme, ThemeProvider } from "@mui/material/styles";
|
||||
import { CssBaseline } from "@mui/material";
|
||||
import { BrowserRouter, Routes, Route } from "react-router";
|
||||
|
||||
import Sidebar from "./components/Sidebar";
|
||||
import Baseline from "./components/Baseline";
|
||||
|
||||
function App() {
|
||||
|
||||
const theme = useMemo(
|
||||
() =>
|
||||
createTheme({
|
||||
palette: {
|
||||
mode: "dark",
|
||||
},
|
||||
}),
|
||||
[]
|
||||
);
|
||||
|
||||
return (
|
||||
<ThemeProvider theme={theme}>
|
||||
<CssBaseline />
|
||||
<div className="flex h-screen text-white">
|
||||
<Sidebar />
|
||||
<div className="flex-1 p-6 overflow-auto">
|
||||
<BrowserRouter>
|
||||
<Suspense fallback={<div>Loading...</div>}>
|
||||
<Routes>
|
||||
<Route path="/baseline" element={<Baseline />} />
|
||||
</Routes>
|
||||
</Suspense>
|
||||
</BrowserRouter>
|
||||
</div>
|
||||
</div>
|
||||
</ThemeProvider>
|
||||
);
|
||||
}
|
||||
export default App;
|
||||
80
frontend/src/components/Baseline.jsx
Normal file
80
frontend/src/components/Baseline.jsx
Normal file
@@ -0,0 +1,80 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import axios from "axios";
|
||||
|
||||
const Baseline = () => {
|
||||
const [data, setData] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
axios
|
||||
.get("/uploaded/baseline.csv")
|
||||
.then((res) => {
|
||||
const csv = res.data;
|
||||
const lines = csv.trim().split("\n");
|
||||
const headers = lines[0].split(",");
|
||||
const rows = lines.slice(1).map((line) => {
|
||||
const values = line.split(",");
|
||||
return headers.reduce((obj, h, i) => {
|
||||
obj[h.trim()] = values[i].trim();
|
||||
return obj;
|
||||
}, {});
|
||||
});
|
||||
setData(rows);
|
||||
})
|
||||
.catch((err) => console.error("Error loading baseline CSV:", err));
|
||||
}, []);
|
||||
|
||||
const countByType = (pattern) =>
|
||||
data.filter((row) => row["Operating System"]?.toLowerCase().includes(pattern)).length;
|
||||
|
||||
return (
|
||||
<div className="p-6 text-white">
|
||||
<h1 className="text-3xl font-bold mb-4">Network Baseline</h1>
|
||||
|
||||
{/* Summary Cards */}
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-4 mb-6">
|
||||
{[
|
||||
{ label: "Windows", color: "bg-blue-600", pattern: "windows" },
|
||||
{ label: "Linux", color: "bg-green-600", pattern: "ubuntu" },
|
||||
{ label: "Servers", color: "bg-red-600", pattern: "server" },
|
||||
{ label: "Workstations", color: "bg-yellow-500", pattern: "workstation" },
|
||||
].map(({ label, color, pattern }) => (
|
||||
<div
|
||||
key={label}
|
||||
className={`flex items-center justify-center ${color} rounded-full h-24 w-24 mx-auto shadow-lg`}
|
||||
>
|
||||
<div className="text-center">
|
||||
<div className="text-xl font-bold">{countByType(pattern)}</div>
|
||||
<div className="text-sm">{label}</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Table */}
|
||||
<div className="overflow-x-auto rounded-lg border border-zinc-700">
|
||||
<table className="min-w-full text-left text-sm">
|
||||
<thead className="bg-zinc-800 text-zinc-300">
|
||||
<tr>
|
||||
<th className="p-3">Host Name</th>
|
||||
<th className="p-3">Operating System</th>
|
||||
<th className="p-3">IP Address</th>
|
||||
<th className="p-3">FQDN</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y divide-zinc-700">
|
||||
{data.map((row, i) => (
|
||||
<tr key={i} className="hover:bg-zinc-800">
|
||||
<td className="p-3">{row["Host Name"]}</td>
|
||||
<td className="p-3">{row["Operating System"]}</td>
|
||||
<td className="p-3">{row["IP Address"]}</td>
|
||||
<td className="p-3">{row["Fdqn"]}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Baseline;
|
||||
53
frontend/src/components/Sidebar.jsx
Normal file
53
frontend/src/components/Sidebar.jsx
Normal file
@@ -0,0 +1,53 @@
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
ShieldCheck, Server, Bug, Lock, Globe, Settings,
|
||||
ChevronDown, ChevronRight, Folder
|
||||
} from 'lucide-react';
|
||||
import AddIcon from '@mui/icons-material/Add';
|
||||
|
||||
const SidebarItem = ({ icon: Icon, label, children }) => {
|
||||
const [open, setOpen] = useState(false);
|
||||
const hasChildren = !!children;
|
||||
|
||||
return (
|
||||
<div className="text-sm w-full">
|
||||
<div
|
||||
className="flex items-center justify-between px-4 py-2 cursor-pointer rounded hover:bg-zinc-800 text-white transition-all"
|
||||
onClick={() => hasChildren && setOpen(!open)}
|
||||
>
|
||||
<div className="flex items-center space-x-3">
|
||||
<Icon className="w-5 h-5 text-cyan-400" />
|
||||
<span>{label}</span>
|
||||
{hasChildren &&
|
||||
(open ? <AddIcon className="w-4 h-4" /> : <ChevronRight className="w-4 h-4" />)}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{hasChildren && open && (
|
||||
<div className="ml-8 mt-1 space-y-1 text-zinc-400">
|
||||
{children}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const Sidebar = () => (
|
||||
<div className="h-screen w-64 shadow-lg p-4 flex flex-col space-y-2">
|
||||
<h2 className="text-xl font-bold text-white mb-4">Velo Dashboard</h2>
|
||||
<SidebarItem icon={ShieldCheck} label="HomePage" />
|
||||
<SidebarItem icon={Server} label="Baseline" />
|
||||
<SidebarItem icon={Bug} label="Networking" />
|
||||
<SidebarItem icon={Folder} label="Applications" />
|
||||
<SidebarItem icon={Globe} label="CSV Processing" />
|
||||
<SidebarItem icon={Settings} label="Security Tools">
|
||||
<div>Anti Virus</div>
|
||||
<div>Endpoint Detection & Response</div>
|
||||
<div>Virtual Private Networks</div>
|
||||
</SidebarItem>
|
||||
<SidebarItem icon={Globe} label="Virus Totals" />
|
||||
<SidebarItem icon={Globe} label="Configuration & Settings" />
|
||||
</div>
|
||||
);
|
||||
|
||||
export default Sidebar;
|
||||
1
frontend/src/index.css
Normal file
1
frontend/src/index.css
Normal file
@@ -0,0 +1 @@
|
||||
@import "tailwindcss";
|
||||
10
frontend/src/main.jsx
Normal file
10
frontend/src/main.jsx
Normal file
@@ -0,0 +1,10 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom/client';
|
||||
import App from './App';
|
||||
import './index.css';
|
||||
|
||||
ReactDOM.createRoot(document.getElementById('root')).render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>
|
||||
);
|
||||
10
frontend/vite.config.js
Normal file
10
frontend/vite.config.js
Normal file
@@ -0,0 +1,10 @@
|
||||
import { defineConfig } from "vite";
|
||||
import react from "@vitejs/plugin-react";
|
||||
import tailwindcss from "@tailwindcss/vite";
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
react(),
|
||||
tailwindcss(),
|
||||
],
|
||||
});
|
||||
Reference in New Issue
Block a user