107 lines
3.8 KiB
JavaScript
107 lines
3.8 KiB
JavaScript
// backend/routes/remoteIpDetailsHandler.js
|
|
const { Flow, Threat } = require('../models/Schemas');
|
|
|
|
module.exports = async function remoteIpDetailsHandler(req, res, helpers) {
|
|
try {
|
|
const { getTimeFilter } = helpers;
|
|
const ip = String(req.query.ip ?? '');
|
|
if (!ip) return res.status(400).json({ ok: false, message: 'ip required' });
|
|
|
|
const flowFilter = {};
|
|
if (req.user?.site_uuid) flowFilter.site_uuid = req.user.site_uuid;
|
|
|
|
// Agent scope if viewer or query param
|
|
if (req.user?.role === 'AGENT_VIEWER' && req.user?.agent_uuid) {
|
|
flowFilter.agent_uuid = req.user.agent_uuid;
|
|
} else if (req.query?.agent_uuid) {
|
|
flowFilter.agent_uuid = req.query.agent_uuid;
|
|
}
|
|
|
|
const rawTimeRange = String(req.query.timeRange ?? 'all');
|
|
if (rawTimeRange !== 'all') {
|
|
const tf = getTimeFilter(req);
|
|
if (tf) flowFilter.timestamp = tf;
|
|
}
|
|
|
|
// Parallel queries
|
|
const [flowsQuery, rawThreats] = await Promise.all([
|
|
Flow.find({ ...flowFilter, $or: [{ src_ip: ip }, { dst_ip: ip }] }).sort({ timestamp: -1 }).limit(2000).lean(),
|
|
Threat.find({ ip_address: ip, ...flowFilter }).sort({ detected_at: -1 }).lean(),
|
|
]);
|
|
|
|
// Data maps
|
|
const protocolsMap = {};
|
|
const domainsMap = {};
|
|
const localDevicesMap = {};
|
|
|
|
let totalDownload = 0;
|
|
let totalUpload = 0;
|
|
let lastSeen = null;
|
|
let firstSeen = null;
|
|
|
|
const bump = (map, key, down, up, ls) => {
|
|
if (!map[key]) map[key] = { app_label: key, download: 0, upload: 0, last_seen: ls, first_seen: ls };
|
|
else {
|
|
if (new Date(ls) > new Date(map[key].last_seen)) map[key].last_seen = ls;
|
|
if (new Date(ls) < new Date(map[key].first_seen)) map[key].first_seen = ls;
|
|
}
|
|
map[key].download += down;
|
|
map[key].upload += up;
|
|
};
|
|
|
|
for (const f of flowsQuery) {
|
|
let localIp = '';
|
|
let down = f.download || 0;
|
|
let up = f.upload || 0;
|
|
let remoteDown = 0;
|
|
let remoteUp = 0;
|
|
|
|
if (f.dst_ip === ip) {
|
|
localIp = f.src_ip;
|
|
remoteDown = up; // Remote received what local sent
|
|
remoteUp = down; // Remote sent what local received
|
|
} else if (f.src_ip === ip) {
|
|
localIp = f.dst_ip;
|
|
remoteDown = down;
|
|
remoteUp = up;
|
|
}
|
|
|
|
totalDownload += remoteDown;
|
|
totalUpload += remoteUp;
|
|
|
|
const ls = f.last_seen || (f.timestamp ? new Date(f.timestamp).toISOString() : new Date().toISOString());
|
|
|
|
if (!lastSeen || new Date(ls) > new Date(lastSeen)) lastSeen = ls;
|
|
if (!firstSeen || new Date(ls) < new Date(firstSeen)) firstSeen = ls;
|
|
|
|
if (localIp) bump(localDevicesMap, localIp, remoteDown, remoteUp, ls);
|
|
|
|
if (f.app_label) bump(protocolsMap, f.app_label, remoteDown, remoteUp, ls);
|
|
else if (f.protocol) bump(protocolsMap, f.protocol, remoteDown, remoteUp, ls);
|
|
|
|
const domainVal = f.sni_hostname || f.domain;
|
|
if (domainVal) bump(domainsMap, domainVal, remoteDown, remoteUp, ls);
|
|
}
|
|
|
|
res.json({
|
|
ok: true,
|
|
data: {
|
|
ip_address: ip,
|
|
ip_version: ip.includes(':') ? 6 : 4,
|
|
total_download: totalDownload,
|
|
total_upload: totalUpload,
|
|
last_seen: lastSeen,
|
|
first_seen: firstSeen,
|
|
protocols: Object.values(protocolsMap).sort((a, b) => b.download + b.upload - (a.download + a.upload)),
|
|
domains: Object.values(domainsMap).sort((a, b) => b.download + b.upload - (a.download + a.upload)),
|
|
local_devices: Object.values(localDevicesMap).sort((a, b) => b.download + b.upload - (a.download + a.upload)),
|
|
flows: flowsQuery.slice(0, 100), // top 100 recent flows
|
|
threats: rawThreats
|
|
}
|
|
});
|
|
} catch (err) {
|
|
console.error('Remote IP Details Error:', err);
|
|
res.status(500).json({ ok: false, error: err.message });
|
|
}
|
|
};
|