Files
Deep-Package-Inspection/backend/routes/dashboard/devices.js
T

207 lines
7.1 KiB
JavaScript

const express = require('express');
const router = express.Router();
const mongoose = require('mongoose');
const { DeviceStat, CustomDeviceLabel, Flow } = require('../../models/Schemas');
const { getTimeFilter, getBaseFilter, getCustomLabelsMap } = require('./helpers');
const { generateMacFromIp, resolveDeviceTypeFromIp, resolveOSFromIp, resolveVendorFromIp, generateAutoLabel } = require('../../deviceResolver');
// GET /api/dashboard/devices
router.get('/devices', async (req, res) => {
try {
const limit = req.query.limit !== undefined ? parseInt(req.query.limit) : 0;
const skip = parseInt(req.query.skip ?? 0);
const timeFilter = getTimeFilter(req);
const query = getBaseFilter(req, timeFilter);
const pipeline = [
{ $match: query },
{ $sort: { timestamp: -1 } },
{ $group: { _id: "$ip_address", doc: { $first: "$$ROOT" } } },
{ $replaceRoot: { newRoot: "$doc" } },
{ $sort: { timestamp: -1, download: -1 } }
];
if (skip > 0) pipeline.push({ $skip: skip });
if (limit > 0) pipeline.push({ $limit: limit });
const [data, customLabelsMap] = await Promise.all([
DeviceStat.aggregate(pipeline),
getCustomLabelsMap()
]);
const mapped = data.map(obj => {
const ip = obj.ip_address;
const mac = obj.mac_address && obj.mac_address !== '-' ? obj.mac_address : generateMacFromIp(ip);
const type = obj.device_type && obj.device_type !== '-' && obj.device_type !== 'Unknown' ? obj.device_type : resolveDeviceTypeFromIp(ip);
const os = obj.os_label && obj.os_label !== '-' && obj.os_label !== 'Unknown' ? obj.os_label : resolveOSFromIp(ip);
const man = obj.manufacturer && obj.manufacturer !== '-' && obj.manufacturer !== 'Unknown' ? obj.manufacturer : resolveVendorFromIp(ip);
const lastSeen = obj.last_seen || obj.timestamp || new Date().toISOString();
const baseLabel = customLabelsMap[mac] || obj.device_label;
const label = baseLabel && baseLabel !== '-' && baseLabel !== 'Unknown' && baseLabel !== 'Generic Client'
? baseLabel
: generateAutoLabel(ip, mac, man, type);
return {
...obj,
id: obj._id.toString(),
mac_address: mac,
device_label: label,
device_type: type,
os_label: os,
manufacturer: man,
last_seen: lastSeen
};
});
res.json({ ok: true, data: mapped });
} catch (err) {
res.status(500).json({ ok: false, error: err.message });
}
});
// GET /api/dashboard/mac-bandwidth
router.get('/mac-bandwidth', async (req, res) => {
try {
const limit = parseInt(req.query.limit ?? 50);
const timeFilter = getTimeFilter(req);
const matchBase = getBaseFilter(req, timeFilter);
const raw = await DeviceStat.aggregate([
{ $match: { ...matchBase } },
{ $group: {
_id: { $ifNull: [ '$mac_address', '$ip_address' ] },
download: { $sum: '$download' },
upload: { $sum: '$upload' },
ip: { $last: '$ip_address' },
mac_address: { $last: '$mac_address' },
label: { $last: '$device_label' },
manufacturer: { $last: '$manufacturer' }
}},
{ $project: {
mac_address: 1,
download: 1,
upload: 1,
ip: 1,
label: 1,
manufacturer: { $ifNull: [ '$manufacturer', 'Intel Corporation' ] },
total: { $add: [ '$download', '$upload' ] },
_id: 0
}},
{ $sort: { total: -1 } },
{ $limit: limit },
]);
const data = raw.map(d => {
const mac = d.mac_address && d.mac_address !== '-' ? d.mac_address : generateMacFromIp(d.ip);
const man = d.manufacturer && d.manufacturer !== '-' && d.manufacturer !== 'Unknown' ? d.manufacturer : resolveVendorFromIp(d.ip);
return {
...d,
mac_address: mac,
manufacturer: man
};
});
res.json({ ok: true, data });
} catch (err) {
res.status(500).json({ ok: false, error: err.message });
}
});
// GET /api/dashboard/security-devices
router.get('/security-devices', async (req, res) => {
try {
const timeFilter = getTimeFilter(req);
const baseFilter = getBaseFilter(req, timeFilter);
const uniqueDevices = await DeviceStat.aggregate([
{ $match: baseFilter },
{ $sort: { timestamp: -1 } },
{ $group: {
_id: '$ip_address',
latestDoc: { $first: '$$ROOT' }
}}
]);
const flowStats = await Flow.aggregate([
{ $match: baseFilter },
{ $group: {
_id: '$src_ip',
total_bytes: { $sum: { $add: ['$download', '$upload'] } },
encrypted_bytes: {
$sum: {
$cond: [
{ $in: ['$dst_port', [443, 8443, 853, 465, 989, 990, 587]] },
{ $add: ['$download', '$upload'] },
0
]
}
}
}}
]);
const flowMap = {};
flowStats.forEach(fs => {
if (fs._id) {
flowMap[fs._id] = {
total: fs.total_bytes || 0,
encrypted: fs.encrypted_bytes || 0
};
}
});
const customLabelsMap = await getCustomLabelsMap();
const mapped = uniqueDevices.map(d => {
const obj = d.latestDoc;
const ip = obj.ip_address;
const mac = obj.mac_address && obj.mac_address !== '-' ? obj.mac_address : generateMacFromIp(ip);
const type = obj.device_type && obj.device_type !== '-' && obj.device_type !== 'Unknown' ? obj.device_type : resolveDeviceTypeFromIp(ip);
const os = obj.os_label && obj.os_label !== '-' && obj.os_label !== 'Unknown' ? obj.os_label : resolveOSFromIp(ip);
const man = obj.manufacturer && obj.manufacturer !== '-' && obj.manufacturer !== 'Unknown' ? obj.manufacturer : resolveVendorFromIp(ip);
const baseLabel = customLabelsMap[mac] || obj.device_label;
const label = baseLabel && baseLabel !== '-' && baseLabel !== 'Unknown' && baseLabel !== 'Generic Client'
? baseLabel
: generateAutoLabel(ip, mac, man, type);
const lastSeen = obj.last_seen || obj.timestamp || new Date().toISOString();
const fStat = flowMap[ip] || { total: 0, encrypted: 0 };
const encrypted = fStat.encrypted;
const unencrypted = Math.max(0, fStat.total - encrypted);
const encrypted_pct = fStat.total > 0 ? (encrypted / fStat.total) * 100 : 0;
let risk_level = 'Safe';
if (fStat.total > 0) {
if (encrypted_pct < 50) risk_level = 'Vulnerable';
else if (encrypted_pct < 80) risk_level = 'Moderate';
}
return {
_id: obj._id.toString(),
ip_address: ip,
mac_address: mac,
device_label: label,
device_type: type,
os_label: os,
manufacturer: man,
encrypted,
unencrypted,
encrypted_pct,
risk_level,
has_insecure: unencrypted > encrypted * 2,
timestamp: lastSeen
};
});
res.json({ ok: true, data: mapped });
} catch (err) {
res.status(500).json({ ok: false, message: err.message });
}
});
module.exports = router;