Initial commit - frontend
This commit is contained in:
213
src/context/DeviceContext.tsx
Normal file
213
src/context/DeviceContext.tsx
Normal file
@@ -0,0 +1,213 @@
|
||||
'use client';
|
||||
|
||||
import React, { createContext, useContext, useState, useEffect } from 'react';
|
||||
import api from '@/lib/axios';
|
||||
import { useAuth } from '@/context/AuthContext';
|
||||
import { DetailedDevice } from '@/types/devices';
|
||||
import { disableConsoleInProd } from '@/lib/disableConsole';
|
||||
disableConsoleInProd();
|
||||
|
||||
|
||||
|
||||
interface DriveInfo {
|
||||
name: string;
|
||||
driveType: string;
|
||||
totalSizeGB: number;
|
||||
freeSpaceGB: number;
|
||||
}
|
||||
|
||||
interface IpAddress {
|
||||
interfaceName: string;
|
||||
ipAddress: string;
|
||||
}
|
||||
|
||||
interface MacAddress {
|
||||
interfaceName: string;
|
||||
macAddress: string;
|
||||
}
|
||||
|
||||
interface InstalledApp {
|
||||
app_name: string;
|
||||
app_version: string;
|
||||
publisher: string;
|
||||
}
|
||||
|
||||
|
||||
interface DeviceVulnerability {
|
||||
cveId: string;
|
||||
title: string;
|
||||
severity: string;
|
||||
score?: number;
|
||||
publishedDate: string;
|
||||
lastModifiedDate: string;
|
||||
}
|
||||
|
||||
interface CachedSoftwareEntry {
|
||||
id: number;
|
||||
softwareName: string;
|
||||
hostname: string;
|
||||
version: string;
|
||||
deviceId: number;
|
||||
totalCves: number;
|
||||
lastUpdated: string;
|
||||
}
|
||||
|
||||
interface DeviceContextType {
|
||||
devices: DetailedDevice[];
|
||||
deviceVulns: { [deviceId: string]: DeviceVulnerability[] };
|
||||
cachedSoftware: CachedSoftwareEntry[];
|
||||
detailedCveLookup: { [cveId: string]: DeviceVulnerability }; // 🔥 New
|
||||
setDevices: React.Dispatch<React.SetStateAction<DetailedDevice[]>>;
|
||||
setDeviceVulns: React.Dispatch<React.SetStateAction<{ [deviceId: string]: DeviceVulnerability[] }>>;
|
||||
setCachedSoftware: React.Dispatch<React.SetStateAction<CachedSoftwareEntry[]>>;
|
||||
setDetailedCveLookup: React.Dispatch<React.SetStateAction<{ [cveId: string]: DeviceVulnerability }>>;
|
||||
loading: boolean;
|
||||
}
|
||||
|
||||
|
||||
const DeviceContext = createContext<DeviceContextType | undefined>(undefined);
|
||||
|
||||
|
||||
export const useDeviceContext = () => {
|
||||
const context = useContext(DeviceContext);
|
||||
if (!context) {
|
||||
throw new Error('useDeviceContext must be used within a DeviceProvider');
|
||||
}
|
||||
return context;
|
||||
};
|
||||
|
||||
export const DeviceProvider = ({
|
||||
children,
|
||||
initialData,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
initialData?: {
|
||||
devices: DetailedDevice[];
|
||||
vulnerabilitiesByDevice: { [deviceId: string]: DeviceVulnerability[] };
|
||||
};
|
||||
}) => {
|
||||
const [devices, setDevices] = useState<DetailedDevice[]>(() => {
|
||||
if (initialData?.devices?.length) return initialData.devices;
|
||||
return [];
|
||||
});
|
||||
|
||||
const [deviceVulns, setDeviceVulns] = useState<{ [deviceId: string]: DeviceVulnerability[] }>(
|
||||
initialData?.vulnerabilitiesByDevice ?? {}
|
||||
);
|
||||
|
||||
const [detailedCveLookup, setDetailedCveLookup] = useState<{ [cveId: string]: DeviceVulnerability }>({});
|
||||
|
||||
const [cachedSoftware, setCachedSoftware] = useState<CachedSoftwareEntry[]>([]); // ⬅️ NEW
|
||||
|
||||
const [loading, setLoading] = useState<boolean>(!initialData);
|
||||
|
||||
const { username, roles, loading: authLoading } = useAuth();
|
||||
|
||||
useEffect(() => {
|
||||
if (devices.length > 0 || initialData || authLoading || !username) return;
|
||||
|
||||
const fetchDevicesVulnsAndSoftware = async () => {
|
||||
try {
|
||||
const isAdmin = roles?.includes('ADMIN');
|
||||
const devicesEndpoint = isAdmin
|
||||
? '/cached/devices/with-vulns/all'
|
||||
: '/cached/devices/with-vulns';
|
||||
const softwareEndpoint = '/cached/software/summary';
|
||||
|
||||
console.group('📡 Fetching Devices, Vulnerabilities, and Software');
|
||||
|
||||
const [devicesRes, softwareRes] = await Promise.all([
|
||||
api.get(devicesEndpoint, { withCredentials: true }),
|
||||
api.get(softwareEndpoint, { withCredentials: true }),
|
||||
]);
|
||||
|
||||
console.log('✅ Devices fetched:', devicesRes.data);
|
||||
console.log('✅ Software fetched:', softwareRes.data);
|
||||
console.groupEnd();
|
||||
|
||||
// STEP 1: Set basic data
|
||||
setDevices(devicesRes.data.devices);
|
||||
setDeviceVulns(devicesRes.data.vulnerabilitiesByDevice);
|
||||
setCachedSoftware(softwareRes.data);
|
||||
|
||||
// STEP 2: Extract all unique CVE IDs
|
||||
const uniqueCveIds = new Set<string>();
|
||||
(Object.values(devicesRes.data.vulnerabilitiesByDevice) as DeviceVulnerability[][]).forEach((vulns) => {
|
||||
vulns.forEach((vuln) => {
|
||||
if (vuln.cveId) {
|
||||
uniqueCveIds.add(vuln.cveId);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// STEP 3: Fetch detailed CVE data
|
||||
if (uniqueCveIds.size > 0) {
|
||||
console.log('🔎 Fetching detailed CVEs for:', Array.from(uniqueCveIds));
|
||||
const params = new URLSearchParams();
|
||||
Array.from(uniqueCveIds).forEach(cveId => {
|
||||
params.append('cveIds', cveId);
|
||||
});
|
||||
|
||||
const cveDetailsRes = await api.get<DeviceVulnerability[]>('/vuln/cves/lookup', {
|
||||
params,
|
||||
withCredentials: true,
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
const lookupMap: { [cveId: string]: DeviceVulnerability } = {};
|
||||
cveDetailsRes.data.forEach((cve) => {
|
||||
lookupMap[cve.cveId] = cve;
|
||||
});
|
||||
|
||||
setDetailedCveLookup(lookupMap);
|
||||
}
|
||||
|
||||
} catch (error: any) {
|
||||
console.group('❌ Device fetch failed');
|
||||
console.error('🔴 Axios Error Message:', error.message);
|
||||
console.error('🧾 Axios Error Config:', error.config);
|
||||
if (error.response) {
|
||||
console.error('📉 Status:', error.response.status);
|
||||
console.error('📄 Response Headers:', error.response.headers);
|
||||
console.error('📄 Response Data:', error.response.data);
|
||||
} else if (error.request) {
|
||||
console.error('🛑 No response received:', error.request);
|
||||
}
|
||||
console.groupEnd();
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
fetchDevicesVulnsAndSoftware();
|
||||
}, [devices.length, initialData, username, authLoading]);
|
||||
|
||||
useEffect(() => {
|
||||
console.log("🧠 Devices updated:", devices);
|
||||
}, [devices]);
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
(window as any).__debug_devices = devices;
|
||||
}
|
||||
|
||||
return (
|
||||
<DeviceContext.Provider value={{
|
||||
devices,
|
||||
deviceVulns,
|
||||
cachedSoftware,
|
||||
detailedCveLookup, // ✅ provide it!
|
||||
setDevices,
|
||||
setDeviceVulns,
|
||||
setCachedSoftware,
|
||||
setDetailedCveLookup, // ✅ provide this too!
|
||||
loading,
|
||||
}}>
|
||||
|
||||
{children}
|
||||
</DeviceContext.Provider>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user