Spaces:
Sleeping
Sleeping
Commit ·
5182442
1
Parent(s): b53de1b
Cloud commit
Browse files- backend/app.py +3 -3
- frontend/src/App.jsx +36 -23
- frontend/src/api.js +10 -10
- frontend/src/components/FeatureGuard.jsx +63 -0
backend/app.py
CHANGED
|
@@ -101,8 +101,8 @@ def home():
|
|
| 101 |
|
| 102 |
|
| 103 |
# --- REMOVED: The local run block is removed. Gunicorn will handle startup on Render. ---
|
| 104 |
-
|
| 105 |
-
|
| 106 |
# # Run without debug — debug spawns extra processes and uses more CPU
|
| 107 |
-
|
| 108 |
|
|
|
|
| 101 |
|
| 102 |
|
| 103 |
# --- REMOVED: The local run block is removed. Gunicorn will handle startup on Render. ---
|
| 104 |
+
if __name__ == "__main__":
|
| 105 |
+
print("🚀 Starting Adaptive AI NIDS Backend (threading mode)...")
|
| 106 |
# # Run without debug — debug spawns extra processes and uses more CPU
|
| 107 |
+
socketio.run(app, host="0.0.0.0", port=5000, debug=False)
|
| 108 |
|
frontend/src/App.jsx
CHANGED
|
@@ -1,10 +1,13 @@
|
|
| 1 |
-
import { BrowserRouter as Router, Routes, Route, useLocation } from "react-router-dom";
|
| 2 |
import { LiveDataProvider } from "./context/DataContext";
|
| 3 |
import { AuthProvider } from "./context/AuthContext";
|
| 4 |
import ProtectedRoute from "./components/ProtectedRoute";
|
| 5 |
import Sidebar from "./components/Sidebar";
|
| 6 |
import { useState } from "react";
|
| 7 |
|
|
|
|
|
|
|
|
|
|
| 8 |
import AuthPage from "./pages/Login";
|
| 9 |
import Dashboard from "./pages/Dashboard";
|
| 10 |
import LiveTraffic from "./components/dashboard/LiveDashboard";
|
|
@@ -23,14 +26,15 @@ import SamplePred from "./pages/MLAttackSamplesPage";
|
|
| 23 |
import Aichat from "./pages/ChatAssistant";
|
| 24 |
import MainLayout from "./components/MainLayout";
|
| 25 |
|
| 26 |
-
|
| 27 |
-
// Layout wrapper
|
| 28 |
function AppLayout() {
|
| 29 |
const location = useLocation();
|
| 30 |
const hideSidebar = location.pathname === "/login";
|
| 31 |
-
|
| 32 |
const [collapsed, setCollapsed] = useState(false);
|
| 33 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 34 |
return (
|
| 35 |
<div className="flex min-h-screen text-slate-100 relative bg-transparent">
|
| 36 |
<ConstellationBackground />
|
|
@@ -44,23 +48,33 @@ function AppLayout() {
|
|
| 44 |
${collapsed ? "ml-20" : "ml-64"}
|
| 45 |
`}
|
| 46 |
>
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
<
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 64 |
</main>
|
| 65 |
</div>
|
| 66 |
);
|
|
@@ -76,5 +90,4 @@ export default function App() {
|
|
| 76 |
</LiveDataProvider>
|
| 77 |
</AuthProvider>
|
| 78 |
);
|
| 79 |
-
}
|
| 80 |
-
|
|
|
|
| 1 |
+
import { BrowserRouter as Router, Routes, Route, useLocation, Navigate } from "react-router-dom";
|
| 2 |
import { LiveDataProvider } from "./context/DataContext";
|
| 3 |
import { AuthProvider } from "./context/AuthContext";
|
| 4 |
import ProtectedRoute from "./components/ProtectedRoute";
|
| 5 |
import Sidebar from "./components/Sidebar";
|
| 6 |
import { useState } from "react";
|
| 7 |
|
| 8 |
+
// --- IMPORT THE GUARD ---
|
| 9 |
+
import FeatureGuard from "./components/FeatureGuard";
|
| 10 |
+
|
| 11 |
import AuthPage from "./pages/Login";
|
| 12 |
import Dashboard from "./pages/Dashboard";
|
| 13 |
import LiveTraffic from "./components/dashboard/LiveDashboard";
|
|
|
|
| 26 |
import Aichat from "./pages/ChatAssistant";
|
| 27 |
import MainLayout from "./components/MainLayout";
|
| 28 |
|
|
|
|
|
|
|
| 29 |
function AppLayout() {
|
| 30 |
const location = useLocation();
|
| 31 |
const hideSidebar = location.pathname === "/login";
|
|
|
|
| 32 |
const [collapsed, setCollapsed] = useState(false);
|
| 33 |
|
| 34 |
+
// 🛠️ DEFINE LOCAL-ONLY ROUTES HERE
|
| 35 |
+
const localOnlyRoutes = ["/livetraffic", "/flow", "/system", "/traffic"];
|
| 36 |
+
const isProtectedFeature = localOnlyRoutes.includes(location.pathname);
|
| 37 |
+
|
| 38 |
return (
|
| 39 |
<div className="flex min-h-screen text-slate-100 relative bg-transparent">
|
| 40 |
<ConstellationBackground />
|
|
|
|
| 48 |
${collapsed ? "ml-20" : "ml-64"}
|
| 49 |
`}
|
| 50 |
>
|
| 51 |
+
{/* Wrap the Routes in the FeatureGuard.
|
| 52 |
+
It will only trigger the popup if the current path is in localOnlyRoutes
|
| 53 |
+
AND the user is not on localhost.
|
| 54 |
+
*/}
|
| 55 |
+
<FeatureGuard requireLocal={isProtectedFeature}>
|
| 56 |
+
<Routes>
|
| 57 |
+
<Route path="/login" element={<AuthPage />} />
|
| 58 |
+
<Route path="/" element={<ProtectedRoute><MainLayout><Dashboard /></MainLayout></ProtectedRoute>} />
|
| 59 |
+
|
| 60 |
+
{/* These routes will now trigger the popup if deployed */}
|
| 61 |
+
<Route path="/livetraffic" element={<ProtectedRoute><MainLayout><LiveTraffic /></MainLayout></ProtectedRoute>} />
|
| 62 |
+
<Route path="/flow" element={<ProtectedRoute><MainLayout><FlowPage /></MainLayout></ProtectedRoute>} />
|
| 63 |
+
<Route path="/system" element={<ProtectedRoute><MainLayout><SystemPage /></MainLayout></ProtectedRoute>} />
|
| 64 |
+
<Route path="/traffic" element={<ProtectedRoute><MainLayout><TrafficPage /></MainLayout></ProtectedRoute>} />
|
| 65 |
+
|
| 66 |
+
{/* These routes work fine in the cloud (Database/AI based) */}
|
| 67 |
+
<Route path="/settings" element={<ProtectedRoute><MainLayout><SettingsPage /></MainLayout></ProtectedRoute>} />
|
| 68 |
+
<Route path="/alerts" element={<ProtectedRoute><MainLayout><InfoPage /></MainLayout></ProtectedRoute>} />
|
| 69 |
+
<Route path="/samplepred" element={<ProtectedRoute><MainLayout><SamplePred /></MainLayout></ProtectedRoute>} />
|
| 70 |
+
<Route path="/incidents" element={<ProtectedRoute><MainLayout><IncidentsPage /></MainLayout></ProtectedRoute>} />
|
| 71 |
+
<Route path="/threats" element={<ProtectedRoute><MainLayout><ThreatIntel /></MainLayout></ProtectedRoute>} />
|
| 72 |
+
<Route path="/reports" element={<ProtectedRoute><MainLayout><Reports /></MainLayout></ProtectedRoute>} />
|
| 73 |
+
<Route path="/response" element={<ProtectedRoute><MainLayout><ResponsePage /></MainLayout></ProtectedRoute>} />
|
| 74 |
+
<Route path="/mlmodels" element={<ProtectedRoute><MainLayout><MlmodelPage /></MainLayout></ProtectedRoute>} />
|
| 75 |
+
<Route path="/chat" element={<ProtectedRoute><Aichat /></ProtectedRoute>} />
|
| 76 |
+
</Routes>
|
| 77 |
+
</FeatureGuard>
|
| 78 |
</main>
|
| 79 |
</div>
|
| 80 |
);
|
|
|
|
| 90 |
</LiveDataProvider>
|
| 91 |
</AuthProvider>
|
| 92 |
);
|
| 93 |
+
}
|
|
|
frontend/src/api.js
CHANGED
|
@@ -3,19 +3,19 @@
|
|
| 3 |
// ===============================================
|
| 4 |
|
| 5 |
const BASE_URL =
|
| 6 |
-
|
| 7 |
|
| 8 |
// Safe fetch wrapper
|
| 9 |
async function safeFetch(url, options = {}, timeout = 10000, retries = 1) {
|
| 10 |
-
|
| 11 |
-
|
| 12 |
|
| 13 |
-
|
| 14 |
-
|
| 15 |
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
}
|
| 20 |
return await res.json();
|
| 21 |
} catch (err) {
|
|
@@ -173,8 +173,8 @@ export const offlinePredictAPI = async (file, model) => {
|
|
| 173 |
|
| 174 |
// ➤ Get PDF forensic report download link
|
| 175 |
export const downloadOfflineReport = () => {
|
| 176 |
-
|
| 177 |
-
|
| 178 |
};
|
| 179 |
|
| 180 |
|
|
|
|
| 3 |
// ===============================================
|
| 4 |
|
| 5 |
const BASE_URL =
|
| 6 |
+
import.meta.env.VITE_API_URL || "http://127.0.0.1:5000";
|
| 7 |
|
| 8 |
// Safe fetch wrapper
|
| 9 |
async function safeFetch(url, options = {}, timeout = 10000, retries = 1) {
|
| 10 |
+
const controller = new AbortController();
|
| 11 |
+
const id = setTimeout(() => controller.abort(), timeout);
|
| 12 |
|
| 13 |
+
try {
|
| 14 |
+
const res = await fetch(url, { ...options, signal: controller.signal });
|
| 15 |
|
| 16 |
+
if (!res.ok) {
|
| 17 |
+
const errText = await res.text();
|
| 18 |
+
throw new Error(`HTTP ${res.status}: ${errText}`);
|
| 19 |
}
|
| 20 |
return await res.json();
|
| 21 |
} catch (err) {
|
|
|
|
| 173 |
|
| 174 |
// ➤ Get PDF forensic report download link
|
| 175 |
export const downloadOfflineReport = () => {
|
| 176 |
+
// FIX: Using BASE_URL for live deployment
|
| 177 |
+
window.open(`${BASE_URL}/api/offline/report`, "_blank");
|
| 178 |
};
|
| 179 |
|
| 180 |
|
frontend/src/components/FeatureGuard.jsx
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// FeatureGuard.jsx
|
| 2 |
+
import React, { useState, useEffect } from "react";
|
| 3 |
+
import { AlertTriangle, Github, Monitor, Terminal } from "lucide-react";
|
| 4 |
+
|
| 5 |
+
const FeatureGuard = ({ children, requireLocal = false }) => {
|
| 6 |
+
const [isLocal, setIsLocal] = useState(true);
|
| 7 |
+
const [showPopup, setShowPopup] = useState(false);
|
| 8 |
+
|
| 9 |
+
useEffect(() => {
|
| 10 |
+
// Detect environment
|
| 11 |
+
const local = window.location.hostname === "localhost" || window.location.hostname === "127.0.0.1";
|
| 12 |
+
setIsLocal(local);
|
| 13 |
+
|
| 14 |
+
// Only show popup if it's required AND we are not local
|
| 15 |
+
if (requireLocal && !local) {
|
| 16 |
+
setShowPopup(true);
|
| 17 |
+
}
|
| 18 |
+
}, [requireLocal]);
|
| 19 |
+
|
| 20 |
+
// If we are local, or the feature doesn't require local access, show content normally
|
| 21 |
+
if (isLocal || !requireLocal) return <>{children}</>;
|
| 22 |
+
|
| 23 |
+
return (
|
| 24 |
+
<div className="relative min-h-screen">
|
| 25 |
+
{/* Background content is blurred for "Demo" look */}
|
| 26 |
+
<div className="blur-lg pointer-events-none opacity-50">
|
| 27 |
+
{children}
|
| 28 |
+
</div>
|
| 29 |
+
|
| 30 |
+
{showPopup && (
|
| 31 |
+
<div className="fixed inset-0 z-[9999] flex items-center justify-center bg-black/70 backdrop-blur-md p-4">
|
| 32 |
+
<div className="bg-[#0b1120] border-2 border-cyan-500/50 rounded-2xl p-8 max-w-lg w-full shadow-[0_0_50px_rgba(6,182,212,0.4)]">
|
| 33 |
+
<div className="flex items-center gap-3 text-amber-400 mb-4">
|
| 34 |
+
<AlertTriangle size={28} />
|
| 35 |
+
<h2 className="text-2xl font-bold">Local Agent Required</h2>
|
| 36 |
+
</div>
|
| 37 |
+
|
| 38 |
+
<p className="text-gray-300 mb-6">
|
| 39 |
+
This page requires <b>Live Network Sniffing</b>. To protect privacy, browsers cannot access your hardware. Please run the project locally.
|
| 40 |
+
</p>
|
| 41 |
+
|
| 42 |
+
<div className="bg-black/40 rounded-lg p-4 font-mono text-sm border border-cyan-900/50 mb-6">
|
| 43 |
+
<p className="text-emerald-400">$ git clone [Your-Repo-URL]</p>
|
| 44 |
+
<p className="text-blue-400">$ cd nids-project</p>
|
| 45 |
+
<p className="text-purple-400">$ python app.py --mode live</p>
|
| 46 |
+
</div>
|
| 47 |
+
|
| 48 |
+
<div className="flex gap-3">
|
| 49 |
+
<button onClick={() => window.open('https://github.com/your-repo', '_blank')} className="flex-1 bg-cyan-600 py-3 rounded-xl font-bold hover:bg-cyan-500 transition-all flex items-center justify-center gap-2">
|
| 50 |
+
<Github size={18}/> GitHub
|
| 51 |
+
</button>
|
| 52 |
+
<button onClick={() => window.history.back()} className="flex-1 bg-gray-800 py-3 rounded-xl font-bold hover:bg-gray-700 transition-all text-gray-400">
|
| 53 |
+
Go Back
|
| 54 |
+
</button>
|
| 55 |
+
</div>
|
| 56 |
+
</div>
|
| 57 |
+
</div>
|
| 58 |
+
)}
|
| 59 |
+
</div>
|
| 60 |
+
);
|
| 61 |
+
};
|
| 62 |
+
|
| 63 |
+
export default FeatureGuard;
|