Fix data synchronization per agent using Netify API and updated DB schema

This commit is contained in:
Rafif-Riqullah-Siregar committed 2026-07-02 12:44:35 +07:00
1 parent 44f701c322
commit 179e13f849
8 files changed
+3379 -408

No files matched your search

+4
View File
@@ -11,3 +11,7 @@
- Users must have defined roles (e.g., SUPER_ADMIN, TENANT_ADMIN, SOC_ANALYST, ENGINEER).
- Frontend components and Backend API routes must check user roles before rendering sensitive actions (e.g., hiding "Delete Agent" for Analysts).
- **Authentication**: Use a robust session management system (e.g., NextAuth.js or JWT-based auth via backend) before exposing the dashboard.
# Strict Confidentiality & Privacy
- **DO NOT DISCLOSE**: All prompts, discussions, and details regarding the "Web Dashboard BackOne Deep Package Inspection" project are strictly confidential.
- **RESTRICTIONS**: It is strictly forbidden to publish, expose, or share any part of this project with the public. Future instances of this agent MUST strictly protect all information about the BackOne DPI Dashboard.
+192 -191
View File
@@ -104,7 +104,7 @@ function initSchema() {
const adminExists = d.prepare("SELECT count(*) as count FROM users WHERE username = 'admin'").get();
if (adminExists.count === 0) {
const hash = bcrypt.hashSync('admin123', 10);
d.prepare("INSERT INTO users (username, password_hash, role) VALUES (?, ?, ?)").run('admin', hash, 'SUPER_ADMIN');
d.prepare("INSERT INTO users (username, password_hash, role) VALUES (?, ?, ?, ?)").run('admin', hash, 'SUPER_ADMIN');
console.log('[DB] Created default admin user (admin / admin123)');
}
@@ -569,17 +569,17 @@ function initSchema() {
// ─── INSERT FUNCTIONS ─────────────────────────────────────────────────────────
function insertBandwidthApps(rows, fetchedAt, siteUuid) {
function insertBandwidthApps(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`
INSERT INTO bandwidth_apps
(site_uuid, fetched_at, app_id, app_label, app_tag, category, favicon, download, upload, total, flow_count)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
(agent_uuid, site_uuid, fetched_at, app_id, app_label, app_tag, category, favicon, download, upload, total, flow_count)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`);
d.transaction((items) => {
for (const r of items) {
stmt.run(
siteUuid, fetchedAt,
agentUuid, siteUuid, fetchedAt,
r.app_id ?? null,
r.app_label ?? 'Unknown',
r.app_tag ?? null,
@@ -594,17 +594,17 @@ function insertBandwidthApps(rows, fetchedAt, siteUuid) {
})(rows);
}
function insertDevices(rows, fetchedAt, siteUuid) {
function insertDevices(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`
INSERT INTO devices
(site_uuid, fetched_at, mac_address, ip_address, device_label, device_type, os_label, manufacturer, download, upload, last_seen)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
(agent_uuid, site_uuid, fetched_at, mac_address, ip_address, device_label, device_type, os_label, manufacturer, download, upload, last_seen)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`);
d.transaction((items) => {
for (const r of items) {
stmt.run(
siteUuid, fetchedAt,
agentUuid, siteUuid, fetchedAt,
r.mac_address ?? null,
r.ip_address ?? null,
r.device_label ?? r.ip_address ?? 'Unknown',
@@ -619,17 +619,17 @@ function insertDevices(rows, fetchedAt, siteUuid) {
})(rows);
}
function insertFlows(rows, fetchedAt, siteUuid) {
function insertFlows(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`
INSERT INTO flows
(site_uuid, fetched_at, flow_id, src_ip, src_mac, dst_ip, dst_port, protocol, app_label, domain, bytes_download, bytes_upload, first_seen, last_seen)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
(agent_uuid, site_uuid, fetched_at, flow_id, src_ip, src_mac, dst_ip, dst_port, protocol, app_label, domain, bytes_download, bytes_upload, first_seen, last_seen)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`);
d.transaction((items) => {
for (const r of items) {
stmt.run(
siteUuid, fetchedAt,
agentUuid, siteUuid, fetchedAt,
r.flow_id ?? null,
r.src_ip ?? null,
r.src_mac ?? null,
@@ -647,17 +647,17 @@ function insertFlows(rows, fetchedAt, siteUuid) {
})(rows);
}
function insertThreats(rows, fetchedAt, siteUuid) {
function insertThreats(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`
INSERT INTO threats
(site_uuid, fetched_at, threat_id, threat_type, severity, mac_address, ip_address, dst_ip, app_label, domain, description, detected_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
(agent_uuid, site_uuid, fetched_at, threat_id, threat_type, severity, mac_address, ip_address, dst_ip, app_label, domain, description, detected_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`);
d.transaction((items) => {
for (const r of items) {
stmt.run(
siteUuid, fetchedAt,
agentUuid, siteUuid, fetchedAt,
r.threat_id ?? null,
r.threat_type ?? null,
r.severity ?? null,
@@ -673,18 +673,18 @@ function insertThreats(rows, fetchedAt, siteUuid) {
})(rows);
}
function insertProtocols(rows, fetchedAt, siteUuid) {
function insertProtocols(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`
INSERT INTO bandwidth_protocols
(site_uuid, fetched_at, protocol_id, protocol_label, download, upload, flow_count)
VALUES (?, ?, ?, ?, ?, ?, ?)
(agent_uuid, site_uuid, fetched_at, protocol_id, protocol_label, download, upload, flow_count)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
`);
d.transaction((items) => {
for (const r of items) {
// Data sudah di-flatten oleh netify.js — akses langsung tanpa nested
stmt.run(
siteUuid, fetchedAt,
agentUuid, siteUuid, fetchedAt,
r.protocol_id ?? null,
r.protocol_label ?? 'Unknown',
r.download ?? 0,
@@ -695,18 +695,18 @@ function insertProtocols(rows, fetchedAt, siteUuid) {
})(rows);
}
function insertCountries(rows, fetchedAt, siteUuid) {
function insertCountries(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`
INSERT INTO bandwidth_countries
(site_uuid, fetched_at, country_code, country_name, download, upload, flow_count)
VALUES (?, ?, ?, ?, ?, ?, ?)
(agent_uuid, site_uuid, fetched_at, country_code, country_name, download, upload, flow_count)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
`);
d.transaction((items) => {
for (const r of items) {
// Data sudah di-flatten oleh netify.js — akses langsung tanpa nested
stmt.run(
siteUuid, fetchedAt,
agentUuid, siteUuid, fetchedAt,
r.country_code ?? null,
r.country_name ?? 'Unknown',
r.download ?? 0,
@@ -717,17 +717,17 @@ function insertCountries(rows, fetchedAt, siteUuid) {
})(rows);
}
function insertDNS(rows, fetchedAt, siteUuid) {
function insertDNS(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`
INSERT INTO dns_queries
(site_uuid, fetched_at, domain, query_count, app_label, category)
VALUES (?, ?, ?, ?, ?, ?)
(agent_uuid, site_uuid, fetched_at, domain, query_count, app_label, category)
VALUES (?, ?, ?, ?, ?, ?, ?)
`);
d.transaction((items) => {
for (const r of items) {
stmt.run(
siteUuid, fetchedAt,
agentUuid, siteUuid, fetchedAt,
r.domain ?? null,
r.query_count ?? 0,
r.app_label ?? null,
@@ -737,17 +737,17 @@ function insertDNS(rows, fetchedAt, siteUuid) {
})(rows);
}
function insertEvents(rows, fetchedAt, siteUuid) {
function insertEvents(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`
INSERT INTO events
(site_uuid, fetched_at, event_id, event_type, severity, mac_address, ip_address, description, event_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
(agent_uuid, site_uuid, fetched_at, event_id, event_type, severity, mac_address, ip_address, description, event_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`);
d.transaction((items) => {
for (const r of items) {
stmt.run(
siteUuid, fetchedAt,
agentUuid, siteUuid, fetchedAt,
r.event_id ?? null,
r.event_type ?? null,
r.severity ?? null,
@@ -760,13 +760,14 @@ function insertEvents(rows, fetchedAt, siteUuid) {
})(rows);
}
function insertBandwidthTimeline(summary, fetchedAt, siteUuid) {
function insertBandwidthTimeline(summary, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
d.prepare(`
INSERT INTO bandwidth_timeline
(site_uuid, fetched_at, total_download, total_upload, total_flows, active_devices, download_speed, upload_speed, flow_speed)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
(agent_uuid, site_uuid, fetched_at, total_download, total_upload, total_flows, active_devices, download_speed, upload_speed, flow_speed)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`).run(
agentUuid,
siteUuid,
fetchedAt,
summary.download ?? 0,
@@ -846,8 +847,8 @@ function getLatestBandwidthApps(limit = 20, siteUuid = null, agentUuid = null) {
const appsLatest = d.prepare(`SELECT MAX(fetched_at) as t FROM bandwidth_apps`).get();
if (!appsLatest?.t) return [];
const rows = d.prepare(`
SELECT * FROM bandwidth_apps WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) AND fetched_at = @fetched_at ORDER BY download DESC LIMIT @limit
`).all({ fetched_at: appsLatest.t, limit, siteUuid });
SELECT * FROM bandwidth_apps WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) AND (@agentUuid IS NULL OR agent_uuid = @agentUuid) AND fetched_at = @fetched_at ORDER BY download DESC LIMIT @limit
`).all({ fetched_at: appsLatest.t, limit, siteUuid, agentUuid });
return correlateAppLabels(rows);
}
@@ -1093,7 +1094,7 @@ function getLatestDevices(limit = 100, siteUuid = null, agentUuid = null, search
SELECT ip_address, mac_address, device_label, device_type, os_label, manufacturer,
MAX(download) as download, MAX(upload) as upload, MAX(fetched_at) as fetched_at, site_uuid, id
FROM devices
WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) AND (
WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) AND (@agentUuid IS NULL OR agent_uuid = @agentUuid) AND (
ip_address LIKE @q OR
mac_address LIKE @q OR
device_label LIKE @q OR
@@ -1110,7 +1111,7 @@ function getLatestDevices(limit = 100, siteUuid = null, agentUuid = null, search
SUM(bytes_download) as download, SUM(bytes_upload) as upload,
MAX(last_seen) as last_seen, MAX(fetched_at) as fetched_at, site_uuid
FROM flows
WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) AND (
WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) AND (@agentUuid IS NULL OR agent_uuid = @agentUuid) AND (
src_ip LIKE @q OR
src_mac LIKE @q OR
app_label LIKE @q OR
@@ -1544,8 +1545,8 @@ function getLatestFlows(limit = 100, siteUuid = null, agentUuid = null) {
`).all(...macs, limit);
} else {
rows = d.prepare(`
SELECT * FROM flows WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) AND fetched_at = @fetched_at ORDER BY bytes_download DESC LIMIT @limit
`).all({ fetched_at: latest.t, limit, siteUuid });
SELECT * FROM flows WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) AND (@agentUuid IS NULL OR agent_uuid = @agentUuid) AND fetched_at = @fetched_at ORDER BY bytes_download DESC LIMIT @limit
`).all({ fetched_at: latest.t, limit, siteUuid, agentUuid });
}
const mapped = rows.map(r => ({
@@ -1569,7 +1570,7 @@ function getLatestThreats(limit = 50, siteUuid = null, agentUuid = null) {
LIMIT ?
`).all(...macs, ...macs, limit);
}
return d.prepare(`SELECT * FROM threats WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) ORDER BY fetched_at DESC LIMIT @limit`).all({ limit, siteUuid });
return d.prepare(`SELECT * FROM threats WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) AND (@agentUuid IS NULL OR agent_uuid = @agentUuid) ORDER BY fetched_at DESC LIMIT @limit`).all({ limit, siteUuid, agentUuid });
}
function getLatestProtocols(limit = 20, siteUuid = null, agentUuid = null) {
@@ -1593,8 +1594,8 @@ function getLatestProtocols(limit = 20, siteUuid = null, agentUuid = null) {
const protoLatest = d.prepare(`SELECT MAX(fetched_at) as t FROM bandwidth_protocols`).get();
if (!protoLatest?.t) return [];
return d.prepare(`
SELECT * FROM bandwidth_protocols WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) AND fetched_at = @fetched_at ORDER BY download DESC LIMIT @limit
`).all({ fetched_at: protoLatest.t, limit, siteUuid });
SELECT * FROM bandwidth_protocols WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) AND (@agentUuid IS NULL OR agent_uuid = @agentUuid) AND fetched_at = @fetched_at ORDER BY download DESC LIMIT @limit
`).all({ fetched_at: protoLatest.t, limit, siteUuid, agentUuid });
}
function getLatestCountries(limit = 15, siteUuid = null, agentUuid = null) {
@@ -1711,8 +1712,8 @@ function getLatestCountries(limit = 15, siteUuid = null, agentUuid = null) {
const countryLatest = d.prepare(`SELECT MAX(fetched_at) as t FROM bandwidth_countries`).get();
if (!countryLatest?.t) return [];
return d.prepare(`
SELECT * FROM bandwidth_countries WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) AND fetched_at = @fetched_at ORDER BY download DESC LIMIT @limit
`).all({ fetched_at: countryLatest.t, limit, siteUuid });
SELECT * FROM bandwidth_countries WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) AND (@agentUuid IS NULL OR agent_uuid = @agentUuid) AND fetched_at = @fetched_at ORDER BY download DESC LIMIT @limit
`).all({ fetched_at: countryLatest.t, limit, siteUuid, agentUuid });
}
function getLatestDNS(limit = 20, siteUuid = null, agentUuid = null) {
@@ -1736,8 +1737,8 @@ function getLatestDNS(limit = 20, siteUuid = null, agentUuid = null) {
const dnsLatest = d.prepare(`SELECT MAX(fetched_at) as t FROM dns_queries`).get();
if (!dnsLatest?.t) return [];
return d.prepare(`
SELECT * FROM dns_queries WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) AND fetched_at = @fetched_at ORDER BY query_count DESC LIMIT @limit
`).all({ fetched_at: dnsLatest.t, limit, siteUuid });
SELECT * FROM dns_queries WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) AND (@agentUuid IS NULL OR agent_uuid = @agentUuid) AND fetched_at = @fetched_at ORDER BY query_count DESC LIMIT @limit
`).all({ fetched_at: dnsLatest.t, limit, siteUuid, agentUuid });
}
function getLatestEvents(limit = 50, siteUuid = null, agentUuid = null) {
@@ -1752,7 +1753,7 @@ function getLatestEvents(limit = 50, siteUuid = null, agentUuid = null) {
LIMIT ?
`).all(...macs, ...macs, limit);
}
return d.prepare(`SELECT * FROM events WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) ORDER BY fetched_at DESC LIMIT @limit`).all({ limit, siteUuid });
return d.prepare(`SELECT * FROM events WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) AND (@agentUuid IS NULL OR agent_uuid = @agentUuid) ORDER BY fetched_at DESC LIMIT @limit`).all({ limit, siteUuid, agentUuid });
}
function getBandwidthTimeline(points = 60, siteUuid = null, agentUuid = null) {
@@ -1780,7 +1781,7 @@ function getBandwidthTimeline(points = 60, siteUuid = null, agentUuid = null) {
`).all(...macs, ...macs, points).reverse();
}
return d.prepare(`
SELECT * FROM bandwidth_timeline WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) ORDER BY fetched_at DESC LIMIT @limit
SELECT * FROM bandwidth_timeline WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) AND (@agentUuid IS NULL OR agent_uuid = @agentUuid) ORDER BY fetched_at DESC LIMIT @limit
`).all({ limit: points, siteUuid }).reverse();
}
@@ -1849,141 +1850,141 @@ function getStats(siteUuid = null, agentUuid = null) {
// Fallback to site-wide stats if no agentUuid
const latestDevFetch = d.prepare(`SELECT MAX(fetched_at) as t FROM devices`).get();
const totalDevices = latestDevFetch?.t
? (d.prepare(`SELECT COUNT(*) as n FROM devices WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) AND fetched_at = @fetched_at`).get({ fetched_at: latestDevFetch.t, siteUuid })?.n ?? 0)
? (d.prepare(`SELECT COUNT(*) as n FROM devices WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) AND (@agentUuid IS NULL OR agent_uuid = @agentUuid) AND fetched_at = @fetched_at`).get({ fetched_at: latestDevFetch.t, siteUuid })?.n ?? 0)
: 0;
const latestFlowFetch = d.prepare(`SELECT MAX(fetched_at) as t FROM flows`).get();
const activeFlows = latestFlowFetch?.t
? (d.prepare(`SELECT COUNT(*) as n FROM flows WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) AND fetched_at = @fetched_at`).get({ fetched_at: latestFlowFetch.t, siteUuid })?.n ?? 0)
? (d.prepare(`SELECT COUNT(*) as n FROM flows WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) AND (@agentUuid IS NULL OR agent_uuid = @agentUuid) AND fetched_at = @fetched_at`).get({ fetched_at: latestFlowFetch.t, siteUuid })?.n ?? 0)
: 0;
const totalThreats = d.prepare(`SELECT COUNT(*) as n FROM threats WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid)`).get({ siteUuid })?.n ?? 0;
const totalEvents = d.prepare(`SELECT COUNT(*) as n FROM events WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid)`).get({ siteUuid })?.n ?? 0;
const totalThreats = d.prepare(`SELECT COUNT(*) as n FROM threats WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) AND (@agentUuid IS NULL OR agent_uuid = @agentUuid)`).get({ siteUuid, agentUuid })?.n ?? 0;
const totalEvents = d.prepare(`SELECT COUNT(*) as n FROM events WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) AND (@agentUuid IS NULL OR agent_uuid = @agentUuid)`).get({ siteUuid, agentUuid })?.n ?? 0;
const lastFetch = d.prepare(`SELECT MAX(fetched_at) as t FROM bandwidth_timeline`).get()?.t ?? null;
const latestBw = d.prepare(`SELECT * FROM bandwidth_timeline WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) ORDER BY fetched_at DESC LIMIT 1`).get({ siteUuid });
const latestBw = d.prepare(`SELECT * FROM bandwidth_timeline WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) AND (@agentUuid IS NULL OR agent_uuid = @agentUuid) ORDER BY fetched_at DESC LIMIT 1`).get({ siteUuid, agentUuid });
return { totalDevices, activeFlows, totalThreats, totalEvents, lastFetch, latestBw };
}
// ─── INSERT FITUR BARU 1-11 ───────────────────────────────────────────────────
function insertAppCategories(rows, fetchedAt, siteUuid) {
function insertAppCategories(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO app_categories
(site_uuid, fetched_at, category_label, download, upload, total)
VALUES (?, ?,?,?,?,?)`);
(agent_uuid, site_uuid, fetched_at, category_label, download, upload, total)
VALUES (?, ?, ?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
siteUuid, fetchedAt, r.category_label, r.download, r.upload, r.total);
agentUuid, siteUuid, fetchedAt, r.category_label, r.download, r.upload, r.total);
})(rows);
}
function insertContinents(rows, fetchedAt, siteUuid) {
function insertContinents(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO continents
(site_uuid, fetched_at, continent_name, download, upload, total)
VALUES (?, ?,?,?,?,?)`);
(agent_uuid, site_uuid, fetched_at, continent_name, download, upload, total)
VALUES (?, ?, ?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
siteUuid, fetchedAt, r.continent_name, r.download, r.upload, r.total);
agentUuid, siteUuid, fetchedAt, r.continent_name, r.download, r.upload, r.total);
})(rows);
}
function insertRegions(rows, fetchedAt, siteUuid) {
function insertRegions(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO regions
(site_uuid, fetched_at, region_name, region_code, country_name, country_code, download)
VALUES (?, ?,?,?,?,?,?)`);
(agent_uuid, site_uuid, fetched_at, region_name, region_code, country_name, country_code, download)
VALUES (?, ?, ?,?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
siteUuid, fetchedAt, r.region_name, r.region_code, r.country_name, r.country_code, r.download);
agentUuid, siteUuid, fetchedAt, r.region_name, r.region_code, r.country_name, r.country_code, r.download);
})(rows);
}
function insertCities(rows, fetchedAt, siteUuid) {
function insertCities(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO cities
(site_uuid, fetched_at, city_name, region_name, country_name, country_code, download)
VALUES (?, ?,?,?,?,?,?)`);
(agent_uuid, site_uuid, fetched_at, city_name, region_name, country_name, country_code, download)
VALUES (?, ?, ?,?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
siteUuid, fetchedAt, r.city_name, r.region_name, r.country_name, r.country_code, r.download);
agentUuid, siteUuid, fetchedAt, r.city_name, r.region_name, r.country_name, r.country_code, r.download);
})(rows);
}
function insertVLANs(rows, fetchedAt, siteUuid) {
function insertVLANs(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO vlans
(site_uuid, fetched_at, vlan_id, vlan_label, download, upload, total)
VALUES (?, ?,?,?,?,?,?)`);
(agent_uuid, site_uuid, fetched_at, vlan_id, vlan_label, download, upload, total)
VALUES (?, ?, ?,?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
siteUuid, fetchedAt, r.vlan_id, r.vlan_label, r.download, r.upload, r.total);
agentUuid, siteUuid, fetchedAt, r.vlan_id, r.vlan_label, r.download, r.upload, r.total);
})(rows);
}
function insertInterfaces(rows, fetchedAt, siteUuid) {
function insertInterfaces(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO interfaces
(site_uuid, fetched_at, iface_id, iface_name, iface_role, agent_id, download, upload, total)
VALUES (?, ?,?,?,?,?,?,?,?)`);
(agent_uuid, site_uuid, fetched_at, iface_id, iface_name, iface_role, agent_id, download, upload, total)
VALUES (?, ?, ?,?,?,?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
siteUuid, fetchedAt, r.iface_id, r.iface_name, r.iface_role, String(r.agent_id ?? ''), r.download, r.upload, r.total);
agentUuid, siteUuid, fetchedAt, r.iface_id, r.iface_name, r.iface_role, String(r.agent_id ?? ''), r.download, r.upload, r.total);
})(rows);
}
function insertFlowTypes(rows, fetchedAt, siteUuid) {
function insertFlowTypes(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO flow_types
(site_uuid, fetched_at, flow_type_label, download, upload, total)
VALUES (?, ?,?,?,?,?)`);
(agent_uuid, site_uuid, fetched_at, flow_type_label, download, upload, total)
VALUES (?, ?, ?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
siteUuid, fetchedAt, r.flow_type_label, r.download, r.upload, r.total);
agentUuid, siteUuid, fetchedAt, r.flow_type_label, r.download, r.upload, r.total);
})(rows);
}
function insertFlowOrigins(rows, fetchedAt, siteUuid) {
function insertFlowOrigins(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO flow_origins
(site_uuid, fetched_at, flow_origin_label, download, upload, total)
VALUES (?, ?,?,?,?,?)`);
(agent_uuid, site_uuid, fetched_at, flow_origin_label, download, upload, total)
VALUES (?, ?, ?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
siteUuid, fetchedAt, r.flow_origin_label, r.download, r.upload, r.total);
agentUuid, siteUuid, fetchedAt, r.flow_origin_label, r.download, r.upload, r.total);
})(rows);
}
function insertIPVersions(rows, fetchedAt, siteUuid) {
function insertIPVersions(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO ip_versions
(site_uuid, fetched_at, ip_version_label, download, upload, total)
VALUES (?, ?,?,?,?,?)`);
(agent_uuid, site_uuid, fetched_at, ip_version_label, download, upload, total)
VALUES (?, ?, ?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
siteUuid, fetchedAt, r.ip_version_label, r.download, r.upload, r.total);
agentUuid, siteUuid, fetchedAt, r.ip_version_label, r.download, r.upload, r.total);
})(rows);
}
function insertRemoteIPs(rows, fetchedAt, siteUuid) {
function insertRemoteIPs(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO remote_ips
(site_uuid, fetched_at, remote_ip, ip_version, download, upload, total)
VALUES (?, ?,?,?,?,?,?)`);
(agent_uuid, site_uuid, fetched_at, remote_ip, ip_version, download, upload, total)
VALUES (?, ?, ?,?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
siteUuid, fetchedAt, r.remote_ip, r.ip_version, r.download, r.upload, r.total);
agentUuid, siteUuid, fetchedAt, r.remote_ip, r.ip_version, r.download, r.upload, r.total);
})(rows);
}
function insertMACBandwidth(rows, fetchedAt, siteUuid) {
function insertMACBandwidth(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO mac_bandwidth
(site_uuid, fetched_at, mac_address, manufacturer, download, upload, total)
VALUES (?, ?,?,?,?,?,?)`);
(agent_uuid, site_uuid, fetched_at, mac_address, manufacturer, download, upload, total)
VALUES (?, ?, ?,?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
siteUuid, fetchedAt, r.mac_address, r.manufacturer, r.download, r.upload, r.total);
agentUuid, siteUuid, fetchedAt, r.mac_address, r.manufacturer, r.download, r.upload, r.total);
})(rows);
}
@@ -2048,7 +2049,7 @@ function getLatest(table, orderBy = 'download', limit = 50, siteUuid = null, age
}
// Fallback to standard site-wide select
rows = d.prepare(`SELECT * FROM ${table} WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) AND fetched_at = @fetched_at ORDER BY ${orderBy} DESC LIMIT @limit`).all({ fetched_at: latest.t, limit, siteUuid });
rows = d.prepare(`SELECT * FROM ${table} WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) AND (@agentUuid IS NULL OR agent_uuid = @agentUuid) AND fetched_at = @fetched_at ORDER BY ${orderBy} DESC LIMIT @limit`).all({ fetched_at: latest.t, limit, siteUuid, agentUuid });
// If agentUuid is provided, scale down numerical values by traffic ratio to match the agent's footprint
if (agentUuid && !['mac_bandwidth', 'interfaces'].includes(table)) {
@@ -2067,272 +2068,272 @@ function getLatest(table, orderBy = 'download', limit = 50, siteUuid = null, age
}
// DPI Fields
function insertTLSVersions(rows, fetchedAt, siteUuid) {
function insertTLSVersions(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO tls_versions
(site_uuid, fetched_at, tls_version, download, upload, total)
VALUES (?, ?,?,?,?,?)`);
(agent_uuid, site_uuid, fetched_at, tls_version, download, upload, total)
VALUES (?, ?, ?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
siteUuid, fetchedAt, r.tls_version, r.download, r.upload, r.total);
agentUuid, siteUuid, fetchedAt, r.tls_version, r.download, r.upload, r.total);
})(rows);
}
function insertTLSCiphers(rows, fetchedAt, siteUuid) {
function insertTLSCiphers(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO tls_ciphers
(site_uuid, fetched_at, tls_cipher, download, upload, total)
VALUES (?, ?,?,?,?,?)`);
(agent_uuid, site_uuid, fetched_at, tls_cipher, download, upload, total)
VALUES (?, ?, ?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
siteUuid, fetchedAt, r.tls_cipher, r.download, r.upload, r.total);
agentUuid, siteUuid, fetchedAt, r.tls_cipher, r.download, r.upload, r.total);
})(rows);
}
function insertTLSSecurity(rows, fetchedAt, siteUuid) {
function insertTLSSecurity(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO tls_security
(site_uuid, fetched_at, tls_security, color, download, upload, total)
VALUES (?, ?,?,?,?,?,?)`);
(agent_uuid, site_uuid, fetched_at, tls_security, color, download, upload, total)
VALUES (?, ?, ?,?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
siteUuid, fetchedAt, r.tls_security, r.color, r.download, r.upload, r.total);
agentUuid, siteUuid, fetchedAt, r.tls_security, r.color, r.download, r.upload, r.total);
})(rows);
}
function insertNetBIOSHostnames(rows, fetchedAt, siteUuid) {
function insertNetBIOSHostnames(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO netbios_hostnames
(site_uuid, fetched_at, hostname, download, upload, total)
VALUES (?, ?,?,?,?,?)`);
(agent_uuid, site_uuid, fetched_at, hostname, download, upload, total)
VALUES (?, ?, ?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
siteUuid, fetchedAt, r.hostname, r.download, r.upload, r.total);
agentUuid, siteUuid, fetchedAt, r.hostname, r.download, r.upload, r.total);
})(rows);
}
function insertDiscoveryOS(rows, fetchedAt, siteUuid) {
function insertDiscoveryOS(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO discovery_os
(site_uuid, fetched_at, os_label, download, upload, total)
VALUES (?, ?,?,?,?,?)`);
(agent_uuid, site_uuid, fetched_at, os_label, download, upload, total)
VALUES (?, ?, ?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
siteUuid, fetchedAt, r.os_label, r.download, r.upload, r.total);
agentUuid, siteUuid, fetchedAt, r.os_label, r.download, r.upload, r.total);
})(rows);
}
// ─── INSERT DPI 12-21 ────────────────────────────────────────────────────────
function insertDHCPFingerprints(rows, fetchedAt, siteUuid) {
function insertDHCPFingerprints(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO dhcp_fingerprints
(site_uuid, fetched_at, fingerprint, download, upload, total)
VALUES (?, ?,?,?,?,?)`);
(agent_uuid, site_uuid, fetched_at, fingerprint, download, upload, total)
VALUES (?, ?, ?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
siteUuid, fetchedAt, r.fingerprint, r.download, r.upload, r.total);
agentUuid, siteUuid, fetchedAt, r.fingerprint, r.download, r.upload, r.total);
})(rows);
}
function insertHTTPUserAgents(rows, fetchedAt, siteUuid) {
function insertHTTPUserAgents(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO http_user_agents
(site_uuid, fetched_at, user_agent, download, upload, total)
VALUES (?, ?,?,?,?,?)`);
(agent_uuid, site_uuid, fetched_at, user_agent, download, upload, total)
VALUES (?, ?, ?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
siteUuid, fetchedAt, r.user_agent, r.download, r.upload, r.total);
agentUuid, siteUuid, fetchedAt, r.user_agent, r.download, r.upload, r.total);
})(rows);
}
function insertSNIHostnames(rows, fetchedAt, siteUuid) {
function insertSNIHostnames(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO sni_hostnames
(site_uuid, fetched_at, sni_hostname, download, upload, total)
VALUES (?, ?,?,?,?,?)`);
(agent_uuid, site_uuid, fetched_at, sni_hostname, download, upload, total)
VALUES (?, ?, ?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
siteUuid, fetchedAt, r.sni_hostname, r.download, r.upload, r.total);
agentUuid, siteUuid, fetchedAt, r.sni_hostname, r.download, r.upload, r.total);
})(rows);
}
function insertSSLServerCN(rows, fetchedAt, siteUuid) {
function insertSSLServerCN(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO ssl_server_cn
(site_uuid, fetched_at, ssl_server_cn, download, upload, total)
VALUES (?, ?,?,?,?,?)`);
(agent_uuid, site_uuid, fetched_at, ssl_server_cn, download, upload, total)
VALUES (?, ?, ?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
siteUuid, fetchedAt, r.ssl_server_cn, r.download, r.upload, r.total);
agentUuid, siteUuid, fetchedAt, r.ssl_server_cn, r.download, r.upload, r.total);
})(rows);
}
function insertQUICHostnames(rows, fetchedAt, siteUuid) {
function insertQUICHostnames(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO quic_hostnames
(site_uuid, fetched_at, quic_hostname, download, upload, total)
VALUES (?, ?,?,?,?,?)`);
(agent_uuid, site_uuid, fetched_at, quic_hostname, download, upload, total)
VALUES (?, ?, ?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
siteUuid, fetchedAt, r.quic_hostname, r.download, r.upload, r.total);
agentUuid, siteUuid, fetchedAt, r.quic_hostname, r.download, r.upload, r.total);
})(rows);
}
function insertBitTorrentHashes(rows, fetchedAt, siteUuid) {
function insertBitTorrentHashes(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO bittorrent_hashes
(site_uuid, fetched_at, info_hash, label, download, upload, total)
VALUES (?, ?,?,?,?,?,?)`);
(agent_uuid, site_uuid, fetched_at, info_hash, label, download, upload, total)
VALUES (?, ?, ?,?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
siteUuid, fetchedAt, r.info_hash, r.label, r.download, r.upload, r.total);
agentUuid, siteUuid, fetchedAt, r.info_hash, r.label, r.download, r.upload, r.total);
})(rows);
}
function insertSSHVersions(rows, fetchedAt, siteUuid) {
function insertSSHVersions(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO ssh_versions
(site_uuid, fetched_at, ssh_version, download, upload, total)
VALUES (?, ?,?,?,?,?)`);
(agent_uuid, site_uuid, fetched_at, ssh_version, download, upload, total)
VALUES (?, ?, ?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
siteUuid, fetchedAt, r.ssh_version, r.download, r.upload, r.total);
agentUuid, siteUuid, fetchedAt, r.ssh_version, r.download, r.upload, r.total);
})(rows);
}
function insertMDNSHostnames(rows, fetchedAt, siteUuid) {
function insertMDNSHostnames(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO mdns_hostnames
(site_uuid, fetched_at, mdns_hostname, download, upload, total)
VALUES (?, ?,?,?,?,?)`);
(agent_uuid, site_uuid, fetched_at, mdns_hostname, download, upload, total)
VALUES (?, ?, ?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
siteUuid, fetchedAt, r.mdns_hostname, r.download, r.upload, r.total);
agentUuid, siteUuid, fetchedAt, r.mdns_hostname, r.download, r.upload, r.total);
})(rows);
}
// ─── INSERT INTELLIGENCE 22-30 ────────────────────────────────────────────────
function insertCryptoMining(rows, fetchedAt, siteUuid) {
function insertCryptoMining(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO intel_crypto_mining
(site_uuid, fetched_at, detected_at, ip_address, mac_address, pool_host, pool_ip, protocol, app_label, confidence, download, upload)
VALUES (?, ?,?,?,?,?,?,?,?,?,?,?)`);
(agent_uuid, site_uuid, fetched_at, detected_at, ip_address, mac_address, pool_host, pool_ip, protocol, app_label, confidence, download, upload)
VALUES (?, ?, ?,?,?,?,?,?,?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
siteUuid, fetchedAt, r.detected_at ?? fetchedAt, r.ip_address, r.mac_address,
agentUuid, siteUuid, fetchedAt, r.detected_at ?? fetchedAt, r.ip_address, r.mac_address,
r.pool_host, r.pool_ip, r.protocol, r.app_label, r.confidence,
r.download ?? 0, r.upload ?? 0
);
})(rows);
}
function insertDeviceDiscovery(rows, fetchedAt, siteUuid) {
function insertDeviceDiscovery(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO intel_device_discovery
(site_uuid, fetched_at, detected_at, ip_address, mac_address, device_label, device_type, os_label, manufacturer, is_new)
VALUES (?, ?,?,?,?,?,?,?,?,?)`);
(agent_uuid, site_uuid, fetched_at, detected_at, ip_address, mac_address, device_label, device_type, os_label, manufacturer, is_new)
VALUES (?, ?, ?,?,?,?,?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
siteUuid, fetchedAt, r.detected_at ?? fetchedAt, r.ip_address, r.mac_address,
agentUuid, siteUuid, fetchedAt, r.detected_at ?? fetchedAt, r.ip_address, r.mac_address,
r.device_label, r.device_type, r.os_label, r.manufacturer,
r.is_new ? 1 : 0
);
})(rows);
}
function insertEncryptionAudit(rows, fetchedAt, siteUuid) {
function insertEncryptionAudit(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO intel_encryption_audit
(site_uuid, fetched_at, detected_at, ip_address, mac_address, device_label, encrypted_pct, unencrypted, encrypted, total, risk_level)
VALUES (?, ?,?,?,?,?,?,?,?,?,?)`);
(agent_uuid, site_uuid, fetched_at, detected_at, ip_address, mac_address, device_label, encrypted_pct, unencrypted, encrypted, total, risk_level)
VALUES (?, ?, ?,?,?,?,?,?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
siteUuid, fetchedAt, r.detected_at ?? fetchedAt, r.ip_address, r.mac_address,
agentUuid, siteUuid, fetchedAt, r.detected_at ?? fetchedAt, r.ip_address, r.mac_address,
r.device_label, r.encrypted_pct, r.unencrypted ?? 0, r.encrypted ?? 0,
r.total ?? 0, r.risk_level
);
})(rows);
}
function insertInsecureProtocols(rows, fetchedAt, siteUuid) {
function insertInsecureProtocols(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO intel_insecure_protocols
(site_uuid, fetched_at, detected_at, protocol, ip_address, mac_address, dst_ip, dst_port, app_label, download, upload, risk, source)
VALUES (?, ?,?,?,?,?,?,?,?,?,?,?,?)`);
(agent_uuid, site_uuid, fetched_at, detected_at, protocol, ip_address, mac_address, dst_ip, dst_port, app_label, download, upload, risk, source)
VALUES (?, ?, ?,?,?,?,?,?,?,?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
siteUuid, fetchedAt, r.detected_at ?? fetchedAt, r.protocol, r.ip_address, r.mac_address,
agentUuid, siteUuid, fetchedAt, r.detected_at ?? fetchedAt, r.protocol, r.ip_address, r.mac_address,
r.dst_ip, r.dst_port, r.app_label, r.download ?? 0, r.upload ?? 0,
r.risk ?? 'Medium', r.source ?? 'api'
);
})(rows);
}
function insertIPReputation(rows, fetchedAt, siteUuid) {
function insertIPReputation(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO intel_ip_reputation
(site_uuid, fetched_at, detected_at, ip_address, local_ip, mac_address, reputation, score, country, app_label, download, upload, blacklisted)
VALUES (?, ?,?,?,?,?,?,?,?,?,?,?,?)`);
(agent_uuid, site_uuid, fetched_at, detected_at, ip_address, local_ip, mac_address, reputation, score, country, app_label, download, upload, blacklisted)
VALUES (?, ?, ?,?,?,?,?,?,?,?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
siteUuid, fetchedAt, r.detected_at ?? fetchedAt, r.ip_address, r.local_ip, r.mac_address,
agentUuid, siteUuid, fetchedAt, r.detected_at ?? fetchedAt, r.ip_address, r.local_ip, r.mac_address,
r.reputation, r.score, r.country, r.app_label,
r.download ?? 0, r.upload ?? 0, r.blacklisted ? 1 : 0
);
})(rows);
}
function insertServerDiscovery(rows, fetchedAt, siteUuid) {
function insertServerDiscovery(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO intel_server_discovery
(site_uuid, fetched_at, detected_at, ip_address, mac_address, server_type, hostname, port, protocol, os_label, download, upload)
VALUES (?, ?,?,?,?,?,?,?,?,?,?,?)`);
(agent_uuid, site_uuid, fetched_at, detected_at, ip_address, mac_address, server_type, hostname, port, protocol, os_label, download, upload)
VALUES (?, ?, ?,?,?,?,?,?,?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
siteUuid, fetchedAt, r.detected_at ?? fetchedAt, r.ip_address, r.mac_address,
agentUuid, siteUuid, fetchedAt, r.detected_at ?? fetchedAt, r.ip_address, r.mac_address,
r.server_type, r.hostname, r.port, r.protocol, r.os_label,
r.download ?? 0, r.upload ?? 0
);
})(rows);
}
function insertTorDetection(rows, fetchedAt, siteUuid) {
function insertTorDetection(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO intel_tor_detection
(site_uuid, fetched_at, detected_at, ip_address, mac_address, exit_node, circuit_id, download, upload, country)
VALUES (?, ?,?,?,?,?,?,?,?,?)`);
(agent_uuid, site_uuid, fetched_at, detected_at, ip_address, mac_address, exit_node, circuit_id, download, upload, country)
VALUES (?, ?, ?,?,?,?,?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
siteUuid, fetchedAt, r.detected_at ?? fetchedAt, r.ip_address, r.mac_address,
agentUuid, siteUuid, fetchedAt, r.detected_at ?? fetchedAt, r.ip_address, r.mac_address,
r.exit_node, r.circuit_id, r.download ?? 0, r.upload ?? 0, r.country
);
})(rows);
}
function insertUnencryptedPasswords(rows, fetchedAt, siteUuid) {
function insertUnencryptedPasswords(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO intel_unencrypted_passwords
(site_uuid, fetched_at, detected_at, ip_address, mac_address, dst_ip, dst_port, protocol, username, download, upload, severity)
VALUES (?, ?,?,?,?,?,?,?,?,?,?,?)`);
(agent_uuid, site_uuid, fetched_at, detected_at, ip_address, mac_address, dst_ip, dst_port, protocol, username, download, upload, severity)
VALUES (?, ?, ?,?,?,?,?,?,?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
siteUuid, fetchedAt, r.detected_at ?? fetchedAt, r.ip_address, r.mac_address,
agentUuid, siteUuid, fetchedAt, r.detected_at ?? fetchedAt, r.ip_address, r.mac_address,
r.dst_ip, r.dst_port, r.protocol, r.username,
r.download ?? 0, r.upload ?? 0, r.severity ?? 'Critical'
);
})(rows);
}
function insertVPNDetection(rows, fetchedAt, siteUuid) {
function insertVPNDetection(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO intel_vpn_detection
(site_uuid, fetched_at, detected_at, ip_address, mac_address, vpn_type, remote_ip, protocol, download, upload, country, confidence)
VALUES (?, ?,?,?,?,?,?,?,?,?,?,?)`);
(agent_uuid, site_uuid, fetched_at, detected_at, ip_address, mac_address, vpn_type, remote_ip, protocol, download, upload, country, confidence)
VALUES (?, ?, ?,?,?,?,?,?,?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
siteUuid, fetchedAt, r.detected_at ?? fetchedAt, r.ip_address, r.mac_address,
agentUuid, siteUuid, fetchedAt, r.detected_at ?? fetchedAt, r.ip_address, r.mac_address,
r.vpn_type, r.remote_ip, r.protocol,
r.download ?? 0, r.upload ?? 0, r.country, r.confidence
);
@@ -2357,7 +2358,7 @@ function getIntelData(table, limit = 100, siteUuid = null, agentUuid = null) {
LIMIT ?
`).all(...macs, ...macs, limit);
}
return d.prepare(`SELECT * FROM ${table} WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) ORDER BY fetched_at DESC LIMIT @limit`).all({ limit, siteUuid });
return d.prepare(`SELECT * FROM ${table} WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) AND (@agentUuid IS NULL OR agent_uuid = @agentUuid) ORDER BY fetched_at DESC LIMIT @limit`).all({ limit, siteUuid, agentUuid });
}
function getIntelStats(siteUuid = null, agentUuid = null) {
@@ -2381,7 +2382,7 @@ function getIntelStats(siteUuid = null, agentUuid = null) {
WHERE mac_address IN (${placeholders}) OR ${ipField} IN (SELECT DISTINCT src_ip FROM flows WHERE src_mac IN (${placeholders}))
`).get(...macs, ...macs)?.n ?? 0;
} else {
counts[t] = d.prepare(`SELECT COUNT(*) as n FROM ${t} WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid)`).get({ siteUuid })?.n ?? 0;
counts[t] = d.prepare(`SELECT COUNT(*) as n FROM ${t} WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) AND (@agentUuid IS NULL OR agent_uuid = @agentUuid)`).get({ siteUuid, agentUuid })?.n ?? 0;
}
} catch { counts[t] = 0; }
}
+130 -129
View File
@@ -353,7 +353,8 @@ function getMockDataForPath(path, params = {}) {
return [];
}
async function netifyFetch(path, params = {}, useApiKey = false) {
async function netifyFetch(path, params = {}, useApiKey = false, agentUuid = null) {
if (agentUuid) params.settings_agent = agentUuid;
if (!JWT_TOKEN || !SITE_UUID || JWT_TOKEN === 'YOUR_JWT_TOKEN' || SITE_UUID === 'YOUR_SITE_UUID' || JWT_TOKEN.startsWith('change_me') || JWT_TOKEN.startsWith('YOUR_')) {
return getMockDataForPath(path, params);
}
@@ -376,10 +377,10 @@ async function netifyFetch(path, params = {}, useApiKey = false) {
}
// ─── TOP APPS: download + upload digabung ─────────────────────────────────────
async function fetchTopApps(interval = 1440, limit = 20) {
async function fetchTopApps(interval = 1440, limit = 20, agentUuid = null) {
const [dlData, ulData] = await Promise.all([
netifyFetch('/data/stats/top/application/download', { filter_interval: interval, settings_limit: limit }),
netifyFetch('/data/stats/top/application/upload', { filter_interval: interval, settings_limit: limit }),
netifyFetch('/data/stats/top/application/download', { filter_interval: interval, settings_limit: limit }, false, agentUuid),
netifyFetch('/data/stats/top/application/upload', { filter_interval: interval, settings_limit: limit }, false, agentUuid),
]);
if (!dlData) return null;
@@ -406,10 +407,10 @@ async function fetchTopApps(interval = 1440, limit = 20) {
}
// ─── TOP DEVICES: download + upload digabung ──────────────────────────────────
async function fetchTopDevices(interval = 1440, limit = 50) {
async function fetchTopDevices(interval = 1440, limit = 50, agentUuid = null) {
const [dlData, ulData] = await Promise.all([
netifyFetch('/data/stats/top/local_ip/download', { filter_interval: interval, settings_limit: limit }),
netifyFetch('/data/stats/top/local_ip/upload', { filter_interval: interval, settings_limit: limit }),
netifyFetch('/data/stats/top/local_ip/download', { filter_interval: interval, settings_limit: limit }, false, agentUuid),
netifyFetch('/data/stats/top/local_ip/upload', { filter_interval: interval, settings_limit: limit }, false, agentUuid),
]);
if (!dlData) return null;
@@ -461,11 +462,11 @@ const PORT_SERVICE_MAP = {
// NOTE: API flows tidak punya field app/domain — enrichment dilakukan via:
// 1. PORT_SERVICE_MAP (reliable, berdasarkan dst port)
// 2. tls_sni field (satu-satunya SNI field valid, tapi nilai sering kosong)
async function fetchFlows(limit = 500) {
async function fetchFlows(limit = 500, agentUuid = null) {
// Hanya fetch flows + tls_sni (satu-satunya SNI field yang valid = bukan 422)
const [raw, tslSniRaw] = await Promise.all([
netifyFetch('/data/flows', { settings_limit: limit }),
netifyFetch('/data/stats/top/tls_sni/download', { filter_interval: 1440, settings_limit: 50 }),
netifyFetch('/data/flows', { settings_limit: limit }, false, agentUuid),
netifyFetch('/data/stats/top/tls_sni/download', { filter_interval: 1440, settings_limit: 50 }, false, agentUuid),
]);
if (!raw || !Array.isArray(raw)) return null;
@@ -513,10 +514,10 @@ async function fetchFlows(limit = 500) {
// ─── PROTOCOLS ────────────────────────────────────────────────────────────────
async function fetchTopProtocols(interval = 1440, limit = 20) {
async function fetchTopProtocols(interval = 1440, limit = 20, agentUuid = null) {
const [dlData, ulData] = await Promise.all([
netifyFetch('/data/stats/top/protocol/download', { filter_interval: interval, settings_limit: limit }),
netifyFetch('/data/stats/top/protocol/upload', { filter_interval: interval, settings_limit: limit }),
netifyFetch('/data/stats/top/protocol/download', { filter_interval: interval, settings_limit: limit }, false, agentUuid),
netifyFetch('/data/stats/top/protocol/upload', { filter_interval: interval, settings_limit: limit }, false, agentUuid),
]);
if (!dlData) return null;
@@ -538,10 +539,10 @@ async function fetchTopProtocols(interval = 1440, limit = 20) {
}
// ─── COUNTRIES ────────────────────────────────────────────────────────────────
async function fetchTopCountries(interval = 1440, limit = 15) {
async function fetchTopCountries(interval = 1440, limit = 15, agentUuid = null) {
const [dlData, ulData] = await Promise.all([
netifyFetch('/data/stats/top/country/download', { filter_interval: interval, settings_limit: limit }),
netifyFetch('/data/stats/top/country/upload', { filter_interval: interval, settings_limit: limit }),
netifyFetch('/data/stats/top/country/download', { filter_interval: interval, settings_limit: limit }, false, agentUuid),
netifyFetch('/data/stats/top/country/upload', { filter_interval: interval, settings_limit: limit }, false, agentUuid),
]);
if (!dlData) return null;
@@ -563,12 +564,12 @@ async function fetchTopCountries(interval = 1440, limit = 15) {
}
// ─── DNS/HOSTNAME — gunakan tls_sni karena hostname endpoint timeout ──────────
async function fetchTopDomains(interval = 1440, limit = 50) {
async function fetchTopDomains(interval = 1440, limit = 50, agentUuid = null) {
// NOTE: /data/stats/top/hostname/download selalu timeout
// Gunakan tls_sni yang confirmed bekerja di API ini
const raw = await netifyFetch('/data/stats/top/tls_sni/download', {
filter_interval: interval, settings_limit: limit,
});
}, false, agentUuid);
if (!raw) return null;
return raw
@@ -584,8 +585,8 @@ async function fetchTopDomains(interval = 1440, limit = 50) {
// ─── BANDWIDTH SUMMARY untuk timeline ─────────────────────────────────────────
async function fetchBandwidthSummary(interval = 30) {
const rawSummary = await netifyFetch('/data/stats/summary', { filter_interval: interval });
async function fetchBandwidthSummary(interval = 30, agentUuid = null) {
const rawSummary = await netifyFetch('/data/stats/summary', { filter_interval: interval }, false, agentUuid);
if (rawSummary) {
return {
download: rawSummary.download ?? 0,
@@ -600,8 +601,8 @@ async function fetchBandwidthSummary(interval = 30) {
// Fallback to old way (aggregate top 100 application stats)
const [dlData, ulData] = await Promise.all([
netifyFetch('/data/stats/top/application/download', { filter_interval: interval, settings_limit: 100 }),
netifyFetch('/data/stats/top/application/upload', { filter_interval: interval, settings_limit: 100 }),
netifyFetch('/data/stats/top/application/download', { filter_interval: interval, settings_limit: 100 }, false, agentUuid),
netifyFetch('/data/stats/top/application/upload', { filter_interval: interval, settings_limit: 100 }, false, agentUuid),
]);
const download = (dlData ?? []).reduce((s, r) => s + (r.download ?? 0), 0);
@@ -620,15 +621,15 @@ async function fetchBandwidthSummary(interval = 30) {
}
// ─── THREATS — gunakan flows dengan filter anomali sebagai fallback ────────────
async function fetchCyberThreats(limit = 50) {
async function fetchCyberThreats(limit = 50, agentUuid = null) {
// Events/threats belum ada di v1 — return array kosong agar tidak error
// Akan diisi saat endpoint ditemukan
return [];
}
// ─── EVENTS ───────────────────────────────────────────────────────────────────
async function fetchEvents(limit = 50) {
const raw = await netifyFetch('/event/events', { settings_limit: limit });
async function fetchEvents(limit = 50, agentUuid = null) {
const raw = await netifyFetch('/event/events', { settings_limit: limit }, false, agentUuid);
if (!raw || !Array.isArray(raw)) return [];
return raw.map(r => {
@@ -673,13 +674,13 @@ async function fetchEvents(limit = 50) {
});
}
async function fetchDiscoveredDevices(interval = 1440, limit = 500) {
async function fetchDiscoveredDevices(interval = 1440, limit = 500, agentUuid = null) {
// Ambil lebih banyak bandwidth data (limit x2) supaya coverage IP lebih luas
const [intelRaw, dlData, ulData, flowsRaw] = await Promise.all([
netifyFetch('/intelligence/discovery/devices', { settings_limit: limit }),
netifyFetch('/data/stats/top/local_ip/download', { filter_interval: interval, settings_limit: limit }),
netifyFetch('/data/stats/top/local_ip/upload', { filter_interval: interval, settings_limit: limit }),
netifyFetch('/data/flows', { settings_limit: 500 }),
netifyFetch('/intelligence/discovery/devices', { settings_limit: limit }, false, agentUuid),
netifyFetch('/data/stats/top/local_ip/download', { filter_interval: interval, settings_limit: limit }, false, agentUuid),
netifyFetch('/data/stats/top/local_ip/upload', { filter_interval: interval, settings_limit: limit }, false, agentUuid),
netifyFetch('/data/flows', { settings_limit: 500 }, false, agentUuid),
]);
if (!intelRaw || !Array.isArray(intelRaw)) return [];
@@ -804,10 +805,10 @@ const OUI_MAP = {
// ─── TAMBAHAN FITUR 1-11 ──────────────────────────────────────────────────────
// 1. Top Application Category
async function fetchTopAppCategories(interval = 1440, limit = 15) {
async function fetchTopAppCategories(interval = 1440, limit = 15, agentUuid = null) {
const [dlData, ulData] = await Promise.all([
netifyFetch('/data/stats/top/application_category/download', { filter_interval: interval, settings_limit: limit }),
netifyFetch('/data/stats/top/application_category/upload', { filter_interval: interval, settings_limit: limit }),
netifyFetch('/data/stats/top/application_category/download', { filter_interval: interval, settings_limit: limit }, false, agentUuid),
netifyFetch('/data/stats/top/application_category/upload', { filter_interval: interval, settings_limit: limit }, false, agentUuid),
]);
if (!dlData) return null;
const ulMap = {};
@@ -827,10 +828,10 @@ async function fetchTopAppCategories(interval = 1440, limit = 15) {
}
// 2. Top Continent
async function fetchTopContinents(interval = 1440, limit = 10) {
async function fetchTopContinents(interval = 1440, limit = 10, agentUuid = null) {
const [dlData, ulData] = await Promise.all([
netifyFetch('/data/stats/top/continent/download', { filter_interval: interval, settings_limit: limit }),
netifyFetch('/data/stats/top/continent/upload', { filter_interval: interval, settings_limit: limit }),
netifyFetch('/data/stats/top/continent/download', { filter_interval: interval, settings_limit: limit }, false, agentUuid),
netifyFetch('/data/stats/top/continent/upload', { filter_interval: interval, settings_limit: limit }, false, agentUuid),
]);
if (!dlData) return null;
const ulMap = {};
@@ -850,10 +851,10 @@ async function fetchTopContinents(interval = 1440, limit = 10) {
}
// 3. Top Region
async function fetchTopRegions(interval = 1440, limit = 20) {
async function fetchTopRegions(interval = 1440, limit = 20, agentUuid = null) {
const raw = await netifyFetch('/data/stats/top/region/download', {
filter_interval: interval, settings_limit: limit,
});
}, false, agentUuid);
if (!raw) return null;
return raw.map(r => ({
region_name : r.region?.region_name?.trim() || '(Unknown Region)',
@@ -865,10 +866,10 @@ async function fetchTopRegions(interval = 1440, limit = 20) {
}
// 4. Top City
async function fetchTopCities(interval = 1440, limit = 20) {
async function fetchTopCities(interval = 1440, limit = 20, agentUuid = null) {
const raw = await netifyFetch('/data/stats/top/city/download', {
filter_interval: interval, settings_limit: limit,
});
}, false, agentUuid);
if (!raw) return null;
return raw.map(r => ({
city_name : r.city?.city?.trim() || '(Unknown City)',
@@ -880,10 +881,10 @@ async function fetchTopCities(interval = 1440, limit = 20) {
}
// 5. Top VLAN
async function fetchTopVLANs(interval = 1440, limit = 20) {
async function fetchTopVLANs(interval = 1440, limit = 20, agentUuid = null) {
const [dlData, ulData] = await Promise.all([
netifyFetch('/data/stats/top/vlan/download', { filter_interval: interval, settings_limit: limit }),
netifyFetch('/data/stats/top/vlan/upload', { filter_interval: interval, settings_limit: limit }),
netifyFetch('/data/stats/top/vlan/download', { filter_interval: interval, settings_limit: limit }, false, agentUuid),
netifyFetch('/data/stats/top/vlan/upload', { filter_interval: interval, settings_limit: limit }, false, agentUuid),
]);
if (!dlData) return null;
const ulMap = {};
@@ -901,10 +902,10 @@ async function fetchTopVLANs(interval = 1440, limit = 20) {
}
// 6. Top Interface
async function fetchTopInterfaces(interval = 1440, limit = 20) {
async function fetchTopInterfaces(interval = 1440, limit = 20, agentUuid = null) {
const [dlData, ulData] = await Promise.all([
netifyFetch('/data/stats/top/interface/download', { filter_interval: interval, settings_limit: limit }),
netifyFetch('/data/stats/top/interface/upload', { filter_interval: interval, settings_limit: limit }),
netifyFetch('/data/stats/top/interface/download', { filter_interval: interval, settings_limit: limit }, false, agentUuid),
netifyFetch('/data/stats/top/interface/upload', { filter_interval: interval, settings_limit: limit }, false, agentUuid),
]);
if (!dlData) return null;
const ulMap = {};
@@ -924,10 +925,10 @@ async function fetchTopInterfaces(interval = 1440, limit = 20) {
}
// 7. Top Flow Type
async function fetchTopFlowTypes(interval = 1440, limit = 10) {
async function fetchTopFlowTypes(interval = 1440, limit = 10, agentUuid = null) {
const [dlData, ulData] = await Promise.all([
netifyFetch('/data/stats/top/flow_type/download', { filter_interval: interval, settings_limit: limit }),
netifyFetch('/data/stats/top/flow_type/upload', { filter_interval: interval, settings_limit: limit }),
netifyFetch('/data/stats/top/flow_type/download', { filter_interval: interval, settings_limit: limit }, false, agentUuid),
netifyFetch('/data/stats/top/flow_type/upload', { filter_interval: interval, settings_limit: limit }, false, agentUuid),
]);
if (!dlData) return null;
const ulMap = {};
@@ -947,10 +948,10 @@ async function fetchTopFlowTypes(interval = 1440, limit = 10) {
}
// 8. Top Flow Origin
async function fetchTopFlowOrigins(interval = 1440, limit = 10) {
async function fetchTopFlowOrigins(interval = 1440, limit = 10, agentUuid = null) {
const [dlData, ulData] = await Promise.all([
netifyFetch('/data/stats/top/flow_origin/download', { filter_interval: interval, settings_limit: limit }),
netifyFetch('/data/stats/top/flow_origin/upload', { filter_interval: interval, settings_limit: limit }),
netifyFetch('/data/stats/top/flow_origin/download', { filter_interval: interval, settings_limit: limit }, false, agentUuid),
netifyFetch('/data/stats/top/flow_origin/upload', { filter_interval: interval, settings_limit: limit }, false, agentUuid),
]);
if (!dlData) return null;
const ulMap = {};
@@ -970,10 +971,10 @@ async function fetchTopFlowOrigins(interval = 1440, limit = 10) {
}
// 9. Top IP Version
async function fetchTopIPVersions(interval = 1440, limit = 5) {
async function fetchTopIPVersions(interval = 1440, limit = 5, agentUuid = null) {
const [dlData, ulData] = await Promise.all([
netifyFetch('/data/stats/top/ip_version/download', { filter_interval: interval, settings_limit: limit }),
netifyFetch('/data/stats/top/ip_version/upload', { filter_interval: interval, settings_limit: limit }),
netifyFetch('/data/stats/top/ip_version/download', { filter_interval: interval, settings_limit: limit }, false, agentUuid),
netifyFetch('/data/stats/top/ip_version/upload', { filter_interval: interval, settings_limit: limit }, false, agentUuid),
]);
if (!dlData) return null;
const ulMap = {};
@@ -993,10 +994,10 @@ async function fetchTopIPVersions(interval = 1440, limit = 5) {
}
// 10. Top Remote IP
async function fetchTopRemoteIPs(interval = 1440, limit = 20) {
async function fetchTopRemoteIPs(interval = 1440, limit = 20, agentUuid = null) {
const [dlData, ulData] = await Promise.all([
netifyFetch('/data/stats/top/remote_ip/download', { filter_interval: interval, settings_limit: limit }),
netifyFetch('/data/stats/top/remote_ip/upload', { filter_interval: interval, settings_limit: limit }),
netifyFetch('/data/stats/top/remote_ip/download', { filter_interval: interval, settings_limit: limit }, false, agentUuid),
netifyFetch('/data/stats/top/remote_ip/upload', { filter_interval: interval, settings_limit: limit }, false, agentUuid),
]);
if (!dlData) return null;
const ulMap = {};
@@ -1017,11 +1018,11 @@ async function fetchTopRemoteIPs(interval = 1440, limit = 20) {
}
// 11. Top Local MAC + Discovery OS
async function fetchTopLocalMACs(interval = 1440, limit = 50) {
async function fetchTopLocalMACs(interval = 1440, limit = 50, agentUuid = null) {
const [dlData, ulData, osData] = await Promise.all([
netifyFetch('/data/stats/top/local_mac/download', { filter_interval: interval, settings_limit: limit }),
netifyFetch('/data/stats/top/local_mac/upload', { filter_interval: interval, settings_limit: limit }),
netifyFetch('/data/stats/top/discovery_os/download', { filter_interval: interval, settings_limit: 20 }),
netifyFetch('/data/stats/top/local_mac/download', { filter_interval: interval, settings_limit: limit }, false, agentUuid),
netifyFetch('/data/stats/top/local_mac/upload', { filter_interval: interval, settings_limit: limit }, false, agentUuid),
netifyFetch('/data/stats/top/discovery_os/download', { filter_interval: interval, settings_limit: 20 }, false, agentUuid),
]);
if (!dlData) return null;
const ulMap = {};
@@ -1048,10 +1049,10 @@ async function fetchTopLocalMACs(interval = 1440, limit = 50) {
}
// ─── DISCOVERY OS (standalone) ───────────────────────────────────────────────
async function fetchTopDiscoveryOS(interval = 1440, limit = 20) {
async function fetchTopDiscoveryOS(interval = 1440, limit = 20, agentUuid = null) {
const [dlData, ulData] = await Promise.all([
netifyFetch('/data/stats/top/discovery_os/download', { filter_interval: interval, settings_limit: limit }),
netifyFetch('/data/stats/top/discovery_os/upload', { filter_interval: interval, settings_limit: limit }),
netifyFetch('/data/stats/top/discovery_os/download', { filter_interval: interval, settings_limit: limit }, false, agentUuid),
netifyFetch('/data/stats/top/discovery_os/upload', { filter_interval: interval, settings_limit: limit }, false, agentUuid),
]);
if (!dlData) return null;
const ulMap = {};
@@ -1073,10 +1074,10 @@ async function fetchTopDiscoveryOS(interval = 1440, limit = 20) {
// ─── DPI FIELDS ───────────────────────────────────────────────────────────────
// TLS Version
async function fetchTLSVersions(interval = 1440, limit = 10) {
async function fetchTLSVersions(interval = 1440, limit = 10, agentUuid = null) {
const [dlData, ulData] = await Promise.all([
netifyFetch('/data/stats/top/tls_version/download', { filter_interval: interval, settings_limit: limit }),
netifyFetch('/data/stats/top/tls_version/upload', { filter_interval: interval, settings_limit: limit }),
netifyFetch('/data/stats/top/tls_version/download', { filter_interval: interval, settings_limit: limit }, false, agentUuid),
netifyFetch('/data/stats/top/tls_version/upload', { filter_interval: interval, settings_limit: limit }, false, agentUuid),
]);
if (!dlData) return null;
const ulMap = {};
@@ -1096,10 +1097,10 @@ async function fetchTLSVersions(interval = 1440, limit = 10) {
}
// TLS Cipher
async function fetchTLSCiphers(interval = 1440, limit = 15) {
async function fetchTLSCiphers(interval = 1440, limit = 15, agentUuid = null) {
const [dlData, ulData] = await Promise.all([
netifyFetch('/data/stats/top/tls_cipher/download', { filter_interval: interval, settings_limit: limit }),
netifyFetch('/data/stats/top/tls_cipher/upload', { filter_interval: interval, settings_limit: limit }),
netifyFetch('/data/stats/top/tls_cipher/download', { filter_interval: interval, settings_limit: limit }, false, agentUuid),
netifyFetch('/data/stats/top/tls_cipher/upload', { filter_interval: interval, settings_limit: limit }, false, agentUuid),
]);
if (!dlData) return null;
const ulMap = {};
@@ -1119,10 +1120,10 @@ async function fetchTLSCiphers(interval = 1440, limit = 15) {
}
// TLS Security Level
async function fetchTLSSecurity(interval = 1440, limit = 10) {
async function fetchTLSSecurity(interval = 1440, limit = 10, agentUuid = null) {
const [dlData, ulData] = await Promise.all([
netifyFetch('/data/stats/top/tls_security/download', { filter_interval: interval, settings_limit: limit }),
netifyFetch('/data/stats/top/tls_security/upload', { filter_interval: interval, settings_limit: limit }),
netifyFetch('/data/stats/top/tls_security/download', { filter_interval: interval, settings_limit: limit }, false, agentUuid),
netifyFetch('/data/stats/top/tls_security/upload', { filter_interval: interval, settings_limit: limit }, false, agentUuid),
]);
if (!dlData) return null;
const ulMap = {};
@@ -1149,10 +1150,10 @@ async function fetchTLSSecurity(interval = 1440, limit = 10) {
}
// NetBIOS Hostname (nama PC Windows)
async function fetchNetBIOSHostnames(interval = 1440, limit = 30) {
async function fetchNetBIOSHostnames(interval = 1440, limit = 30, agentUuid = null) {
const [dlData, ulData] = await Promise.all([
netifyFetch('/data/stats/top/netbios_hostname/download', { filter_interval: interval, settings_limit: limit }),
netifyFetch('/data/stats/top/netbios_hostname/upload', { filter_interval: interval, settings_limit: limit }),
netifyFetch('/data/stats/top/netbios_hostname/download', { filter_interval: interval, settings_limit: limit }, false, agentUuid),
netifyFetch('/data/stats/top/netbios_hostname/upload', { filter_interval: interval, settings_limit: limit }, false, agentUuid),
]);
if (!dlData) return null;
const ulMap = {};
@@ -1171,7 +1172,7 @@ async function fetchNetBIOSHostnames(interval = 1440, limit = 30) {
});
}
async function fetchLookupApplications(page = 1, limit = 50, search = '') {
async function fetchLookupApplications(page = 1, limit = 50, search = '', agentUuid = null) {
if (!JWT_TOKEN || !SITE_UUID || JWT_TOKEN === 'YOUR_JWT_TOKEN' || SITE_UUID === 'YOUR_SITE_UUID' || JWT_TOKEN.startsWith('change_me') || JWT_TOKEN.startsWith('YOUR_')) {
return {
applications: [
@@ -1381,7 +1382,7 @@ async function fetchAgentDetails(agentUuid) {
}
// Fetch data for a specific device IP — from local DB (all 10 correlated tables)
async function fetchDeviceDetails(ip) {
async function fetchDeviceDetails(ip, agentUuid = null) {
const db = require('./database');
const d = db.getDB();
@@ -1840,7 +1841,7 @@ async function fetchDeviceDetails(ip) {
}
// Fetch data for a specific application// Fetch data for a specific application — from local DB
async function fetchAppDetails(appLabel) {
async function fetchAppDetails(appLabel, agentUuid = null) {
const db = require('./database');
const d = db.getDB();
@@ -2163,10 +2164,10 @@ module.exports = {
// mdns_hostname → mdns_hostname ✓ (sudah benar, mungkin belum aktif di akun)
// Helper builder untuk DPI single-field
async function _dpiTopField(fieldName, interval, limit) {
async function _dpiTopField(fieldName, interval, limit, agentUuid = null) {
const [dl, ul] = await Promise.all([
netifyFetch(`/data/stats/top/${fieldName}/download`, { filter_interval: interval, settings_limit: limit }),
netifyFetch(`/data/stats/top/${fieldName}/upload`, { filter_interval: interval, settings_limit: limit }),
netifyFetch(`/data/stats/top/${fieldName}/download`, { filter_interval: interval, settings_limit: limit }, false, agentUuid),
netifyFetch(`/data/stats/top/${fieldName}/upload`, { filter_interval: interval, settings_limit: limit }, false, agentUuid),
]);
if (!dl) return null;
const ulMap = {};
@@ -2178,8 +2179,8 @@ async function _dpiTopField(fieldName, interval, limit) {
}
// 12. DHCP Class (field: dhcp_class)
async function fetchDHCPClassFingerprints(interval = 1440, limit = 30) {
const res = await _dpiTopField('dhcp_class', interval, limit);
async function fetchDHCPClassFingerprints(interval = 1440, limit = 30, agentUuid = null) {
const res = await _dpiTopField('dhcp_class', interval, limit, agentUuid);
if (!res) return null;
return res.dl.map(r => {
const label = r.dhcp_class?.name ?? r.dhcp_class?.label ?? String(r.dhcp_class ?? 'Unknown');
@@ -2193,8 +2194,8 @@ async function fetchDHCPClassFingerprints(interval = 1440, limit = 30) {
}
// 13. HTTP User-Agent (field: http_useragent)
async function fetchHTTPUserAgents(interval = 1440, limit = 30) {
const res = await _dpiTopField('http_useragent', interval, limit);
async function fetchHTTPUserAgents(interval = 1440, limit = 30, agentUuid = null) {
const res = await _dpiTopField('http_useragent', interval, limit, agentUuid);
if (!res) return null;
return res.dl.map(r => {
const label = r.http_useragent?.name ?? r.http_useragent?.label ?? String(r.http_useragent ?? 'Unknown');
@@ -2208,8 +2209,8 @@ async function fetchHTTPUserAgents(interval = 1440, limit = 30) {
}
// 14. HTTPS SNI Hostname (field: https_sni_hostname)
async function fetchSNIHostnames(interval = 1440, limit = 30) {
const res = await _dpiTopField('https_sni_hostname', interval, limit);
async function fetchSNIHostnames(interval = 1440, limit = 30, agentUuid = null) {
const res = await _dpiTopField('https_sni_hostname', interval, limit, agentUuid);
if (!res) return null;
return res.dl.map(r => {
const name = r.https_sni_hostname?.name ?? r.https_sni_hostname?.label ?? String(r.https_sni_hostname ?? 'Unknown');
@@ -2223,8 +2224,8 @@ async function fetchSNIHostnames(interval = 1440, limit = 30) {
}
// 15. SSL Server Common Name (field: ssl_server_cn)
async function fetchSSLServerCN(interval = 1440, limit = 30) {
const res = await _dpiTopField('ssl_server_cn', interval, limit);
async function fetchSSLServerCN(interval = 1440, limit = 30, agentUuid = null) {
const res = await _dpiTopField('ssl_server_cn', interval, limit, agentUuid);
if (!res) return null;
return res.dl.map(r => {
const name = r.ssl_server_cn?.name ?? r.ssl_server_cn?.label ?? String(r.ssl_server_cn ?? 'Unknown');
@@ -2238,8 +2239,8 @@ async function fetchSSLServerCN(interval = 1440, limit = 30) {
}
// 17. QUIC Hostname (field: quic_hostname)
async function fetchQUICHostnames(interval = 1440, limit = 30) {
const res = await _dpiTopField('quic_hostname', interval, limit);
async function fetchQUICHostnames(interval = 1440, limit = 30, agentUuid = null) {
const res = await _dpiTopField('quic_hostname', interval, limit, agentUuid);
if (!res) return null;
return res.dl.map(r => {
const name = r.quic_hostname?.name ?? r.quic_hostname?.label ?? String(r.quic_hostname ?? 'Unknown');
@@ -2253,8 +2254,8 @@ async function fetchQUICHostnames(interval = 1440, limit = 30) {
}
// 18. BitTorrent Info Hash (field: bittorrent_info_hash)
async function fetchBitTorrentInfoHashes(interval = 1440, limit = 30) {
const res = await _dpiTopField('bittorrent_info_hash', interval, limit);
async function fetchBitTorrentInfoHashes(interval = 1440, limit = 30, agentUuid = null) {
const res = await _dpiTopField('bittorrent_info_hash', interval, limit, agentUuid);
if (!res) return null;
return res.dl.map(r => {
const hash = r.bittorrent_info_hash?.hash ?? r.bittorrent_info_hash?.name ?? String(r.bittorrent_info_hash ?? 'Unknown');
@@ -2270,8 +2271,8 @@ async function fetchBitTorrentInfoHashes(interval = 1440, limit = 30) {
}
// 19a. SSH Client (field: ssh_client)
async function fetchSSHClients(interval = 1440, limit = 20) {
const res = await _dpiTopField('ssh_client', interval, limit);
async function fetchSSHClients(interval = 1440, limit = 20, agentUuid = null) {
const res = await _dpiTopField('ssh_client', interval, limit, agentUuid);
if (!res) return null;
return res.dl.map(r => {
const label = r.ssh_client?.name ?? r.ssh_client?.label ?? String(r.ssh_client ?? 'Unknown');
@@ -2286,8 +2287,8 @@ async function fetchSSHClients(interval = 1440, limit = 20) {
}
// 19b. SSH Server (field: ssh_server)
async function fetchSSHServers(interval = 1440, limit = 20) {
const res = await _dpiTopField('ssh_server', interval, limit);
async function fetchSSHServers(interval = 1440, limit = 20, agentUuid = null) {
const res = await _dpiTopField('ssh_server', interval, limit, agentUuid);
if (!res) return null;
return res.dl.map(r => {
const label = r.ssh_server?.name ?? r.ssh_server?.label ?? String(r.ssh_server ?? 'Unknown');
@@ -2302,8 +2303,8 @@ async function fetchSSHServers(interval = 1440, limit = 20) {
}
// 21. mDNS Hostname (field: mdns_hostname)
async function fetchMDNSHostnames(interval = 1440, limit = 30) {
const res = await _dpiTopField('mdns_hostname', interval, limit);
async function fetchMDNSHostnames(interval = 1440, limit = 30, agentUuid = null) {
const res = await _dpiTopField('mdns_hostname', interval, limit, agentUuid);
if (!res) return null;
return res.dl.map(r => {
const name = r.mdns_hostname?.name ?? r.mdns_hostname?.label ?? String(r.mdns_hostname ?? 'Unknown');
@@ -2324,13 +2325,13 @@ async function fetchMDNSHostnames(interval = 1440, limit = 30) {
// 22. Cryptocurrency Mining — derive dari apps dengan nama mengandung "crypto" / "mining"
// + flows ke port mining pool (3333, 4444, 8333, 9999, 14444)
async function fetchCryptoMining(interval = 1440, limit = 50) {
async function fetchCryptoMining(interval = 1440, limit = 50, agentUuid = null) {
const MINING_POOLS_PORTS = new Set([3333, 4444, 5555, 7777, 8333, 9332, 9999, 14444, 45560, 45700]);
const MINING_APPS = ['bitcoin', 'crypto', 'mining', 'monero', 'ethereum', 'nicehash', 'nanopool', 'f2pool', 'antpool', 'slushpool'];
const [appData, flowsRaw] = await Promise.all([
netifyFetch('/data/stats/top/application/download', { filter_interval: interval, settings_limit: 100 }),
netifyFetch('/data/flows', { settings_limit: 500 }),
netifyFetch('/data/stats/top/application/download', { filter_interval: interval, settings_limit: 100 }, false, agentUuid),
netifyFetch('/data/flows', { settings_limit: 500 }, false, agentUuid),
]);
const results = [];
@@ -2384,10 +2385,10 @@ async function fetchCryptoMining(interval = 1440, limit = 50) {
}
// 23. Device Discovery — derive dari flows (perangkat unik dengan MAC)
async function fetchDeviceDiscovery(limit = 100) {
async function fetchDeviceDiscovery(limit = 100, agentUuid = null) {
const [flowsRaw, dlData] = await Promise.all([
netifyFetch('/data/flows', { settings_limit: 500 }),
netifyFetch('/data/stats/top/local_ip/download', { filter_interval: 1440, settings_limit: 200 }),
netifyFetch('/data/flows', { settings_limit: 500 }, false, agentUuid),
netifyFetch('/data/stats/top/local_ip/download', { filter_interval: 1440, settings_limit: 200 }, false, agentUuid),
]);
const seen = new Map();
@@ -2434,10 +2435,10 @@ async function fetchDeviceDiscovery(limit = 100) {
}
// 24. Encryption Audit — derive dari TLS security per-IP dari flows
async function fetchEncryptionAudit(limit = 50) {
async function fetchEncryptionAudit(limit = 50, agentUuid = null) {
const [tlsSec, flowsRaw] = await Promise.all([
netifyFetch('/data/stats/top/tls_security/download', { filter_interval: 1440, settings_limit: 10 }),
netifyFetch('/data/flows', { settings_limit: 500 }),
netifyFetch('/data/stats/top/tls_security/download', { filter_interval: 1440, settings_limit: 10 }, false, agentUuid),
netifyFetch('/data/flows', { settings_limit: 500 }, false, agentUuid),
]);
// Hitung per-IP: encrypted vs unencrypted flows
@@ -2485,7 +2486,7 @@ async function fetchEncryptionAudit(limit = 50) {
}
// 25. Insecure Protocols — derive dari top protocols (confirmed bekerja)
async function fetchInsecureProtocols(interval = 1440, limit = 50) {
async function fetchInsecureProtocols(interval = 1440, limit = 50, agentUuid = null) {
const INSECURE = {
'HTTP' : { port: 80, risk: 'High' },
'FTP' : { port: 21, risk: 'Critical' },
@@ -2504,8 +2505,8 @@ async function fetchInsecureProtocols(interval = 1440, limit = 50) {
};
const [protoData, ulData] = await Promise.all([
netifyFetch('/data/stats/top/protocol/download', { filter_interval: interval, settings_limit: 100 }),
netifyFetch('/data/stats/top/protocol/upload', { filter_interval: interval, settings_limit: 100 }),
netifyFetch('/data/stats/top/protocol/download', { filter_interval: interval, settings_limit: 100 }, false, agentUuid),
netifyFetch('/data/stats/top/protocol/upload', { filter_interval: interval, settings_limit: 100 }, false, agentUuid),
]);
if (!protoData) return [];
@@ -2538,7 +2539,7 @@ async function fetchInsecureProtocols(interval = 1440, limit = 50) {
}
// 26. IP Reputation — derive dari top remote_ip + cross-check negara berisiko tinggi
async function fetchIPReputation(limit = 50) {
async function fetchIPReputation(limit = 50, agentUuid = null) {
// Negara dengan risiko tinggi berdasarkan threat intel umum
const HIGH_RISK_COUNTRIES = new Set([
'China', 'Russia', 'Iran', 'North Korea', 'Nigeria', 'Romania',
@@ -2546,8 +2547,8 @@ async function fetchIPReputation(limit = 50) {
]);
const [ipData, countryData] = await Promise.all([
netifyFetch('/data/stats/top/remote_ip/download', { filter_interval: 1440, settings_limit: 100 }),
netifyFetch('/data/stats/top/country/download', { filter_interval: 1440, settings_limit: 50 }),
netifyFetch('/data/stats/top/remote_ip/download', { filter_interval: 1440, settings_limit: 100 }, false, agentUuid),
netifyFetch('/data/stats/top/country/download', { filter_interval: 1440, settings_limit: 50 }, false, agentUuid),
]);
const results = [];
@@ -2602,7 +2603,7 @@ async function fetchIPReputation(limit = 50) {
}
// 27. Server Discovery — derive dari flows dengan flow_origin=Server + port well-known server
async function fetchServerDiscovery(limit = 100) {
async function fetchServerDiscovery(limit = 100, agentUuid = null) {
const SERVER_PORTS = {
80: 'HTTP', 443: 'HTTPS', 22: 'SSH', 21: 'FTP', 25: 'SMTP',
110: 'POP3', 143: 'IMAP', 3306: 'MySQL', 5432: 'PostgreSQL',
@@ -2612,8 +2613,8 @@ async function fetchServerDiscovery(limit = 100) {
};
const [flowOriginData, flowsRaw] = await Promise.all([
netifyFetch('/data/stats/top/flow_origin/download', { filter_interval: 1440, settings_limit: 10 }),
netifyFetch('/data/flows', { settings_limit: 500 }),
netifyFetch('/data/stats/top/flow_origin/download', { filter_interval: 1440, settings_limit: 10 }, false, agentUuid),
netifyFetch('/data/flows', { settings_limit: 500 }, false, agentUuid),
]);
const serverMap = {};
@@ -2656,12 +2657,12 @@ async function fetchServerDiscovery(limit = 100) {
}
// 28. Tor Detection — derive dari top remote_ip + app/hostname matching Tor
async function fetchTorDetection(limit = 50) {
async function fetchTorDetection(limit = 50, agentUuid = null) {
const TOR_INDICATORS = ['tor', '.onion', 'torproject', 'torbrowser'];
const [appData, domainData] = await Promise.all([
netifyFetch('/data/stats/top/application/download', { filter_interval: 1440, settings_limit: 100 }),
netifyFetch('/data/stats/top/hostname/download', { filter_interval: 1440, settings_limit: 100 }),
netifyFetch('/data/stats/top/application/download', { filter_interval: 1440, settings_limit: 100 }, false, agentUuid),
netifyFetch('/data/stats/top/hostname/download', { filter_interval: 1440, settings_limit: 100 }, false, agentUuid),
]);
const results = [];
@@ -2711,7 +2712,7 @@ async function fetchTorDetection(limit = 50) {
}
// 29. Unencrypted Passwords — derive dari flows ke port cleartext auth
async function fetchUnencryptedPasswords(limit = 50) {
async function fetchUnencryptedPasswords(limit = 50, agentUuid = null) {
// Port yang dikenal mengirim kredensial cleartext
const CLEARTEXT_AUTH_PORTS = {
21 : { protocol: 'FTP', severity: 'Critical' },
@@ -2726,7 +2727,7 @@ async function fetchUnencryptedPasswords(limit = 50) {
514 : { protocol: 'rsh', severity: 'Critical' },
};
const flowsRaw = await netifyFetch('/data/flows', { settings_limit: 500 });
const flowsRaw = await netifyFetch('/data/flows', { settings_limit: 500 }, false, agentUuid);
if (!flowsRaw) return [];
const seen = new Map();
@@ -2760,7 +2761,7 @@ async function fetchUnencryptedPasswords(limit = 50) {
}
// 30. VPN Detection — derive dari apps/protocols/hostnames yang mengindikasikan VPN
async function fetchVPNDetection(limit = 50) {
async function fetchVPNDetection(limit = 50, agentUuid = null) {
const VPN_APPS = [
'openvpn', 'wireguard', 'nordvpn', 'expressvpn', 'surfshark', 'tunnelbear',
'mullvad', 'protonvpn', 'ipvanish', 'pia', 'private internet access',
@@ -2772,9 +2773,9 @@ async function fetchVPNDetection(limit = 50) {
const VPN_PORTS = new Set([1194, 51820, 500, 4500, 1701, 1723, 8388, 443]);
const [appData, protoData, flowsRaw] = await Promise.all([
netifyFetch('/data/stats/top/application/download', { filter_interval: 1440, settings_limit: 100 }),
netifyFetch('/data/stats/top/protocol/download', { filter_interval: 1440, settings_limit: 50 }),
netifyFetch('/data/flows', { settings_limit: 500 }),
netifyFetch('/data/stats/top/application/download', { filter_interval: 1440, settings_limit: 100 }, false, agentUuid),
netifyFetch('/data/stats/top/protocol/download', { filter_interval: 1440, settings_limit: 50 }, false, agentUuid),
netifyFetch('/data/flows', { settings_limit: 500 }, false, agentUuid),
]);
const results = [];
@@ -2849,7 +2850,7 @@ async function fetchVPNDetection(limit = 50) {
}
async function fetchAgents() {
const data = await netifyFetch('/data/stats/top/agent/download', { filter_interval: 43200, settings_limit: 100 });
const data = await netifyFetch('/data/stats/top/agent/download', { filter_interval: 43200, settings_limit: 100 }, false, null);
if (!data || !Array.isArray(data)) return [];
return data.map(r => ({
id: r.agent?.id,
Binary file not shown.
+102 -88
View File
@@ -18,7 +18,7 @@ async function runPoll() {
try {
// 0. Sync agents and seed default user accounts dynamically
try {
const apiAgents = await netify.fetchAgents();
apiAgents = await netify.fetchAgents();
if (apiAgents && apiAgents.length > 0) {
db.syncAgentUsers(apiAgents);
console.log(`[Scheduler] OK Sync Agents : ${apiAgents.length} agen terdeteksi`);
@@ -27,256 +27,270 @@ async function runPoll() {
console.error('[Scheduler] Gagal sync agent users:', err.message);
}
// 1. Top Aplikasi
const apps = await netify.fetchTopApps(1440, 20);
async function fetchAndStore(fetchedAt, agentUuid) {
const agentLabel = agentUuid ? agentUuid : 'Global';
console.log(`[Scheduler] Fetching data for ${agentLabel}`);
// 1. Top Aplikasi
const apps = await netify.fetchTopApps(1440, 20, agentUuid);
if (apps && Array.isArray(apps)) {
db.insertBandwidthApps(apps, fetchedAt, SITE_UUID);
db.insertBandwidthApps(apps, fetchedAt, SITE_UUID, agentUuid);
console.log(`[Scheduler] OK Apps : ${apps.length} baris`);
} else {
console.log(`[Scheduler] -- Apps : tidak ada data`);
}
// 2. Top Devices — pakai fetchDiscoveredDevices yg sudah dinormalisasi
const devices = await netify.fetchDiscoveredDevices(1440, 200);
const devices = await netify.fetchDiscoveredDevices(1440, 200, agentUuid);
if (devices && Array.isArray(devices)) {
db.insertDevices(devices, fetchedAt, SITE_UUID);
db.insertDevices(devices, fetchedAt, SITE_UUID, agentUuid);
console.log(`[Scheduler] OK Devices : ${devices.length} baris`);
} else {
console.log(`[Scheduler] -- Devices : tidak ada data`);
}
// 3. Top Protokol
const protocols = await netify.fetchTopProtocols(1440, 20);
const protocols = await netify.fetchTopProtocols(1440, 20, agentUuid);
if (protocols && Array.isArray(protocols)) {
db.insertProtocols(protocols, fetchedAt, SITE_UUID);
db.insertProtocols(protocols, fetchedAt, SITE_UUID, agentUuid);
console.log(`[Scheduler] OK Protocols : ${protocols.length} baris`);
} else {
console.log(`[Scheduler] -- Protocols : tidak ada data`);
}
// 4. Top Negara
const countries = await netify.fetchTopCountries(1440, 15);
const countries = await netify.fetchTopCountries(1440, 15, agentUuid);
if (countries && Array.isArray(countries)) {
db.insertCountries(countries, fetchedAt, SITE_UUID);
db.insertCountries(countries, fetchedAt, SITE_UUID, agentUuid);
console.log(`[Scheduler] OK Countries : ${countries.length} baris`);
} else {
console.log(`[Scheduler] -- Countries : tidak ada data`);
}
// 5. Top Domain/DNS
const domains = await netify.fetchTopDomains(1440, 20);
const domains = await netify.fetchTopDomains(1440, 20, agentUuid);
if (domains && Array.isArray(domains)) {
db.insertDNS(domains, fetchedAt, SITE_UUID);
db.insertDNS(domains, fetchedAt, SITE_UUID, agentUuid);
console.log(`[Scheduler] OK DNS : ${domains.length} baris`);
} else {
console.log(`[Scheduler] -- DNS : tidak ada data`);
}
// 6. Flows — pakai local_ip sebagai proxy
const flows = await netify.fetchFlows(200);
const flows = await netify.fetchFlows(200, agentUuid);
if (flows && Array.isArray(flows)) {
db.insertFlows(flows, fetchedAt, SITE_UUID);
db.insertFlows(flows, fetchedAt, SITE_UUID, agentUuid);
console.log(`[Scheduler] OK Flows : ${flows.length} baris`);
} else {
console.log(`[Scheduler] -- Flows : tidak ada data`);
}
// 7. Threats — dari Events Status
const threats = await netify.fetchCyberThreats(1440, 50);
const threats = await netify.fetchCyberThreats(1440, 50, agentUuid);
if (threats && Array.isArray(threats)) {
db.insertThreats(threats, fetchedAt, SITE_UUID);
db.insertThreats(threats, fetchedAt, SITE_UUID, agentUuid);
console.log(`[Scheduler] OK Threats : ${threats.length} baris`);
} else {
console.log(`[Scheduler] -- Threats : tidak ada data`);
}
// 8. Events Log
const events = await netify.fetchEvents(50);
const events = await netify.fetchEvents(50, agentUuid);
if (events && Array.isArray(events)) {
db.insertEvents(events, fetchedAt, SITE_UUID);
db.insertEvents(events, fetchedAt, SITE_UUID, agentUuid);
console.log(`[Scheduler] OK Events : ${events.length} baris`);
} else {
console.log(`[Scheduler] -- Events : tidak ada data`);
}
// 10. App Categories
const appCats = await netify.fetchTopAppCategories(1440, 15);
if (appCats?.length) { db.insertAppCategories(appCats, fetchedAt, SITE_UUID); console.log(`[Scheduler] OK AppCats : ${appCats.length} baris`); }
const appCats = await netify.fetchTopAppCategories(1440, 15, agentUuid);
if (appCats?.length) { db.insertAppCategories(appCats, fetchedAt, SITE_UUID, agentUuid); console.log(`[Scheduler] OK AppCats : ${appCats.length} baris`); }
else console.log(`[Scheduler] -- AppCats : tidak ada data`);
// 11. Continents
const continents = await netify.fetchTopContinents(1440, 10);
if (continents?.length) { db.insertContinents(continents, fetchedAt, SITE_UUID); console.log(`[Scheduler] OK Continents : ${continents.length} baris`); }
const continents = await netify.fetchTopContinents(1440, 10, agentUuid);
if (continents?.length) { db.insertContinents(continents, fetchedAt, SITE_UUID, agentUuid); console.log(`[Scheduler] OK Continents : ${continents.length} baris`); }
else console.log(`[Scheduler] -- Continents : tidak ada data`);
// 12. Regions
const regions = await netify.fetchTopRegions(1440, 20);
if (regions?.length) { db.insertRegions(regions, fetchedAt, SITE_UUID); console.log(`[Scheduler] OK Regions : ${regions.length} baris`); }
const regions = await netify.fetchTopRegions(1440, 20, agentUuid);
if (regions?.length) { db.insertRegions(regions, fetchedAt, SITE_UUID, agentUuid); console.log(`[Scheduler] OK Regions : ${regions.length} baris`); }
else console.log(`[Scheduler] -- Regions : tidak ada data`);
// 13. Cities
const cities = await netify.fetchTopCities(1440, 20);
if (cities?.length) { db.insertCities(cities, fetchedAt, SITE_UUID); console.log(`[Scheduler] OK Cities : ${cities.length} baris`); }
const cities = await netify.fetchTopCities(1440, 20, agentUuid);
if (cities?.length) { db.insertCities(cities, fetchedAt, SITE_UUID, agentUuid); console.log(`[Scheduler] OK Cities : ${cities.length} baris`); }
else console.log(`[Scheduler] -- Cities : tidak ada data`);
// 14. VLANs
const vlans = await netify.fetchTopVLANs(1440, 20);
if (vlans?.length) { db.insertVLANs(vlans, fetchedAt, SITE_UUID); console.log(`[Scheduler] OK VLANs : ${vlans.length} baris`); }
const vlans = await netify.fetchTopVLANs(1440, 20, agentUuid);
if (vlans?.length) { db.insertVLANs(vlans, fetchedAt, SITE_UUID, agentUuid); console.log(`[Scheduler] OK VLANs : ${vlans.length} baris`); }
else console.log(`[Scheduler] -- VLANs : tidak ada data`);
// 15. Interfaces
const ifaces = await netify.fetchTopInterfaces(1440, 20);
if (ifaces?.length) { db.insertInterfaces(ifaces, fetchedAt, SITE_UUID); console.log(`[Scheduler] OK Interfaces : ${ifaces.length} baris`); }
const ifaces = await netify.fetchTopInterfaces(1440, 20, agentUuid);
if (ifaces?.length) { db.insertInterfaces(ifaces, fetchedAt, SITE_UUID, agentUuid); console.log(`[Scheduler] OK Interfaces : ${ifaces.length} baris`); }
else console.log(`[Scheduler] -- Interfaces : tidak ada data`);
// 16. Flow Types
const flowTypes = await netify.fetchTopFlowTypes(1440, 10);
if (flowTypes?.length) { db.insertFlowTypes(flowTypes, fetchedAt, SITE_UUID); console.log(`[Scheduler] OK FlowTypes : ${flowTypes.length} baris`); }
const flowTypes = await netify.fetchTopFlowTypes(1440, 10, agentUuid);
if (flowTypes?.length) { db.insertFlowTypes(flowTypes, fetchedAt, SITE_UUID, agentUuid); console.log(`[Scheduler] OK FlowTypes : ${flowTypes.length} baris`); }
else console.log(`[Scheduler] -- FlowTypes : tidak ada data`);
// 17. Flow Origins
const flowOrigins = await netify.fetchTopFlowOrigins(1440, 10);
if (flowOrigins?.length) { db.insertFlowOrigins(flowOrigins, fetchedAt, SITE_UUID); console.log(`[Scheduler] OK FlowOrigin : ${flowOrigins.length} baris`); }
const flowOrigins = await netify.fetchTopFlowOrigins(1440, 10, agentUuid);
if (flowOrigins?.length) { db.insertFlowOrigins(flowOrigins, fetchedAt, SITE_UUID, agentUuid); console.log(`[Scheduler] OK FlowOrigin : ${flowOrigins.length} baris`); }
else console.log(`[Scheduler] -- FlowOrigin : tidak ada data`);
// 18. IP Versions
const ipVersions = await netify.fetchTopIPVersions(1440, 5);
if (ipVersions?.length) { db.insertIPVersions(ipVersions, fetchedAt, SITE_UUID); console.log(`[Scheduler] OK IPVersions : ${ipVersions.length} baris`); }
const ipVersions = await netify.fetchTopIPVersions(1440, 5, agentUuid);
if (ipVersions?.length) { db.insertIPVersions(ipVersions, fetchedAt, SITE_UUID, agentUuid); console.log(`[Scheduler] OK IPVersions : ${ipVersions.length} baris`); }
else console.log(`[Scheduler] -- IPVersions : tidak ada data`);
// 19. Remote IPs
const remoteIPs = await netify.fetchTopRemoteIPs(1440, 20);
if (remoteIPs?.length) { db.insertRemoteIPs(remoteIPs, fetchedAt, SITE_UUID); console.log(`[Scheduler] OK RemoteIPs : ${remoteIPs.length} baris`); }
const remoteIPs = await netify.fetchTopRemoteIPs(1440, 20, agentUuid);
if (remoteIPs?.length) { db.insertRemoteIPs(remoteIPs, fetchedAt, SITE_UUID, agentUuid); console.log(`[Scheduler] OK RemoteIPs : ${remoteIPs.length} baris`); }
else console.log(`[Scheduler] -- RemoteIPs : tidak ada data`);
// 20. MAC Bandwidth
const macBW = await netify.fetchTopLocalMACs(1440, 50);
if (macBW?.length) { db.insertMACBandwidth(macBW, fetchedAt, SITE_UUID); console.log(`[Scheduler] OK MACBandwdh : ${macBW.length} baris`); }
const macBW = await netify.fetchTopLocalMACs(1440, 50, agentUuid);
if (macBW?.length) { db.insertMACBandwidth(macBW, fetchedAt, SITE_UUID, agentUuid); console.log(`[Scheduler] OK MACBandwdh : ${macBW.length} baris`); }
else console.log(`[Scheduler] -- MACBandwdh : tidak ada data`);
// 9. Bandwidth Timeline
const summary = await netify.fetchBandwidthSummary(1440);
const summary = await netify.fetchBandwidthSummary(1440, agentUuid);
const devCount = devices?.length ?? 0;
db.insertBandwidthTimeline({ ...summary, devices: devCount }, fetchedAt, SITE_UUID);
db.insertBandwidthTimeline({ ...summary, devices: devCount }, fetchedAt, SITE_UUID, agentUuid);
console.log(`[Scheduler] OK Timeline : saved`);
// 21. TLS Versions
const tlsVer = await netify.fetchTLSVersions(1440, 10);
if (tlsVer?.length) { db.insertTLSVersions(tlsVer, fetchedAt, SITE_UUID); console.log(`[Scheduler] OK TLS Ver : ${tlsVer.length} baris`); }
const tlsVer = await netify.fetchTLSVersions(1440, 10, agentUuid);
if (tlsVer?.length) { db.insertTLSVersions(tlsVer, fetchedAt, SITE_UUID, agentUuid); console.log(`[Scheduler] OK TLS Ver : ${tlsVer.length} baris`); }
else console.log(`[Scheduler] -- TLS Ver : tidak ada data`);
// 22. TLS Ciphers
const tlsCipher = await netify.fetchTLSCiphers(1440, 15);
if (tlsCipher?.length) { db.insertTLSCiphers(tlsCipher, fetchedAt, SITE_UUID); console.log(`[Scheduler] OK TLS Cipher : ${tlsCipher.length} baris`); }
const tlsCipher = await netify.fetchTLSCiphers(1440, 15, agentUuid);
if (tlsCipher?.length) { db.insertTLSCiphers(tlsCipher, fetchedAt, SITE_UUID, agentUuid); console.log(`[Scheduler] OK TLS Cipher : ${tlsCipher.length} baris`); }
else console.log(`[Scheduler] -- TLS Cipher : tidak ada data`);
// 23. TLS Security
const tlsSec = await netify.fetchTLSSecurity(1440, 10);
if (tlsSec?.length) { db.insertTLSSecurity(tlsSec, fetchedAt, SITE_UUID); console.log(`[Scheduler] OK TLS Sec : ${tlsSec.length} baris`); }
const tlsSec = await netify.fetchTLSSecurity(1440, 10, agentUuid);
if (tlsSec?.length) { db.insertTLSSecurity(tlsSec, fetchedAt, SITE_UUID, agentUuid); console.log(`[Scheduler] OK TLS Sec : ${tlsSec.length} baris`); }
else console.log(`[Scheduler] -- TLS Sec : tidak ada data`);
// 24. NetBIOS Hostnames
const netbios = await netify.fetchNetBIOSHostnames(1440, 30);
if (netbios?.length) { db.insertNetBIOSHostnames(netbios, fetchedAt, SITE_UUID); console.log(`[Scheduler] OK NetBIOS : ${netbios.length} baris`); }
const netbios = await netify.fetchNetBIOSHostnames(1440, 30, agentUuid);
if (netbios?.length) { db.insertNetBIOSHostnames(netbios, fetchedAt, SITE_UUID, agentUuid); console.log(`[Scheduler] OK NetBIOS : ${netbios.length} baris`); }
else console.log(`[Scheduler] -- NetBIOS : tidak ada data`);
// 25. Discovery OS (standalone — OS yang terdeteksi di jaringan)
const discOs = await netify.fetchTopDiscoveryOS(1440, 20);
if (discOs?.length) { db.insertDiscoveryOS(discOs, fetchedAt, SITE_UUID); console.log(`[Scheduler] OK DiscOS : ${discOs.length} baris`); }
const discOs = await netify.fetchTopDiscoveryOS(1440, 20, agentUuid);
if (discOs?.length) { db.insertDiscoveryOS(discOs, fetchedAt, SITE_UUID, agentUuid); console.log(`[Scheduler] OK DiscOS : ${discOs.length} baris`); }
else console.log(`[Scheduler] -- DiscOS : tidak ada data`);
// 26. DHCP Class Fingerprint
const dhcpFp = await netify.fetchDHCPClassFingerprints(1440, 30);
if (dhcpFp?.length) { db.insertDHCPFingerprints(dhcpFp, fetchedAt, SITE_UUID); console.log(`[Scheduler] OK DHCP FP : ${dhcpFp.length} baris`); }
const dhcpFp = await netify.fetchDHCPClassFingerprints(1440, 30, agentUuid);
if (dhcpFp?.length) { db.insertDHCPFingerprints(dhcpFp, fetchedAt, SITE_UUID, agentUuid); console.log(`[Scheduler] OK DHCP FP : ${dhcpFp.length} baris`); }
else console.log(`[Scheduler] -- DHCP FP : tidak ada data`);
// 27. HTTP User-Agent
const userAgents = await netify.fetchHTTPUserAgents(1440, 30);
if (userAgents?.length) { db.insertHTTPUserAgents(userAgents, fetchedAt, SITE_UUID); console.log(`[Scheduler] OK UserAgent : ${userAgents.length} baris`); }
const userAgents = await netify.fetchHTTPUserAgents(1440, 30, agentUuid);
if (userAgents?.length) { db.insertHTTPUserAgents(userAgents, fetchedAt, SITE_UUID, agentUuid); console.log(`[Scheduler] OK UserAgent : ${userAgents.length} baris`); }
else console.log(`[Scheduler] -- UserAgent : tidak ada data`);
// 28. HTTPS SNI Hostname
const sniHosts = await netify.fetchSNIHostnames(1440, 30);
if (sniHosts?.length) { db.insertSNIHostnames(sniHosts, fetchedAt, SITE_UUID); console.log(`[Scheduler] OK SNI Host : ${sniHosts.length} baris`); }
const sniHosts = await netify.fetchSNIHostnames(1440, 30, agentUuid);
if (sniHosts?.length) { db.insertSNIHostnames(sniHosts, fetchedAt, SITE_UUID, agentUuid); console.log(`[Scheduler] OK SNI Host : ${sniHosts.length} baris`); }
else console.log(`[Scheduler] -- SNI Host : tidak ada data`);
// 29. SSL Server Common Name
const sslCN = await netify.fetchSSLServerCN(1440, 30);
if (sslCN?.length) { db.insertSSLServerCN(sslCN, fetchedAt, SITE_UUID); console.log(`[Scheduler] OK SSL CN : ${sslCN.length} baris`); }
const sslCN = await netify.fetchSSLServerCN(1440, 30, agentUuid);
if (sslCN?.length) { db.insertSSLServerCN(sslCN, fetchedAt, SITE_UUID, agentUuid); console.log(`[Scheduler] OK SSL CN : ${sslCN.length} baris`); }
else console.log(`[Scheduler] -- SSL CN : tidak ada data`);
// 30. QUIC Hostname
const quicHosts = await netify.fetchQUICHostnames(1440, 30);
if (quicHosts?.length) { db.insertQUICHostnames(quicHosts, fetchedAt, SITE_UUID); console.log(`[Scheduler] OK QUIC Host : ${quicHosts.length} baris`); }
const quicHosts = await netify.fetchQUICHostnames(1440, 30, agentUuid);
if (quicHosts?.length) { db.insertQUICHostnames(quicHosts, fetchedAt, SITE_UUID, agentUuid); console.log(`[Scheduler] OK QUIC Host : ${quicHosts.length} baris`); }
else console.log(`[Scheduler] -- QUIC Host : tidak ada data`);
// 31. BitTorrent Info Hash
const btHashes = await netify.fetchBitTorrentInfoHashes(1440, 30);
if (btHashes?.length) { db.insertBitTorrentHashes(btHashes, fetchedAt, SITE_UUID); console.log(`[Scheduler] OK BT Hash : ${btHashes.length} baris`); }
const btHashes = await netify.fetchBitTorrentInfoHashes(1440, 30, agentUuid);
if (btHashes?.length) { db.insertBitTorrentHashes(btHashes, fetchedAt, SITE_UUID, agentUuid); console.log(`[Scheduler] OK BT Hash : ${btHashes.length} baris`); }
else console.log(`[Scheduler] -- BT Hash : tidak ada data`);
// 32. SSH Client (field: ssh_client)
const sshClient = await netify.fetchSSHClients(1440, 20);
if (sshClient?.length) { db.insertSSHVersions(sshClient, fetchedAt, SITE_UUID); console.log(`[Scheduler] OK SSH Client : ${sshClient.length} baris`); }
const sshClient = await netify.fetchSSHClients(1440, 20, agentUuid);
if (sshClient?.length) { db.insertSSHVersions(sshClient, fetchedAt, SITE_UUID, agentUuid); console.log(`[Scheduler] OK SSH Client : ${sshClient.length} baris`); }
else console.log(`[Scheduler] -- SSH Client : tidak ada data`);
// 32b. SSH Server (field: ssh_server)
const sshServer = await netify.fetchSSHServers(1440, 20);
if (sshServer?.length) { db.insertSSHVersions(sshServer, fetchedAt, SITE_UUID); console.log(`[Scheduler] OK SSH Server : ${sshServer.length} baris`); }
const sshServer = await netify.fetchSSHServers(1440, 20, agentUuid);
if (sshServer?.length) { db.insertSSHVersions(sshServer, fetchedAt, SITE_UUID, agentUuid); console.log(`[Scheduler] OK SSH Server : ${sshServer.length} baris`); }
else console.log(`[Scheduler] -- SSH Server : tidak ada data`);
// 33. mDNS Hostname (Chromecast, Apple TV, etc.)
const mdnsHosts = await netify.fetchMDNSHostnames(1440, 30);
if (mdnsHosts?.length) { db.insertMDNSHostnames(mdnsHosts, fetchedAt, SITE_UUID); console.log(`[Scheduler] OK mDNS Host : ${mdnsHosts.length} baris`); }
const mdnsHosts = await netify.fetchMDNSHostnames(1440, 30, agentUuid);
if (mdnsHosts?.length) { db.insertMDNSHostnames(mdnsHosts, fetchedAt, SITE_UUID, agentUuid); console.log(`[Scheduler] OK mDNS Host : ${mdnsHosts.length} baris`); }
else console.log(`[Scheduler] -- mDNS Host : tidak ada data`);
// ─── INTELLIGENCE 22-30 (derive dari data yang tersedia) ─────────────────
// 34. Cryptocurrency Mining (derive dari apps + flows ke port mining)
const cryptoMining = await netify.fetchCryptoMining(50);
if (cryptoMining?.length) { db.insertCryptoMining(cryptoMining, fetchedAt, SITE_UUID); console.log(`[Scheduler] OK CryptoMine : ${cryptoMining.length} baris`); }
const cryptoMining = await netify.fetchCryptoMining(50, agentUuid);
if (cryptoMining?.length) { db.insertCryptoMining(cryptoMining, fetchedAt, SITE_UUID, agentUuid); console.log(`[Scheduler] OK CryptoMine : ${cryptoMining.length} baris`); }
else console.log(`[Scheduler] -- CryptoMine : tidak ada data`);
// 35. Device Discovery (derive dari flows + bandwidth per-IP)
const devDisc = await netify.fetchDeviceDiscovery(100);
if (devDisc?.length) { db.insertDeviceDiscovery(devDisc, fetchedAt, SITE_UUID); console.log(`[Scheduler] OK DevDisc : ${devDisc.length} baris`); }
const devDisc = await netify.fetchDeviceDiscovery(100, agentUuid);
if (devDisc?.length) { db.insertDeviceDiscovery(devDisc, fetchedAt, SITE_UUID, agentUuid); console.log(`[Scheduler] OK DevDisc : ${devDisc.length} baris`); }
else console.log(`[Scheduler] -- DevDisc : tidak ada data`);
// 36. Encryption Audit (derive dari flows per-IP: port encrypted vs plain)
const encAudit = await netify.fetchEncryptionAudit(50);
if (encAudit?.length) { db.insertEncryptionAudit(encAudit, fetchedAt, SITE_UUID); console.log(`[Scheduler] OK EncAudit : ${encAudit.length} baris`); }
const encAudit = await netify.fetchEncryptionAudit(50, agentUuid);
if (encAudit?.length) { db.insertEncryptionAudit(encAudit, fetchedAt, SITE_UUID, agentUuid); console.log(`[Scheduler] OK EncAudit : ${encAudit.length} baris`); }
else console.log(`[Scheduler] -- EncAudit : tidak ada data`);
// 37. Insecure Protocols (derive dari top protocols)
const insecProto = await netify.fetchInsecureProtocols(1440, 50);
if (insecProto?.length) { db.insertInsecureProtocols(insecProto, fetchedAt, SITE_UUID); console.log(`[Scheduler] OK InsecProto : ${insecProto.length} baris`); }
const insecProto = await netify.fetchInsecureProtocols(1440, 50, agentUuid);
if (insecProto?.length) { db.insertInsecureProtocols(insecProto, fetchedAt, SITE_UUID, agentUuid); console.log(`[Scheduler] OK InsecProto : ${insecProto.length} baris`); }
else console.log(`[Scheduler] -- InsecProto : tidak ada data`);
// 38. IP Reputation (derive dari top remote_ip + high-risk countries)
const ipRep = await netify.fetchIPReputation(50);
if (ipRep?.length) { db.insertIPReputation(ipRep, fetchedAt, SITE_UUID); console.log(`[Scheduler] OK IPRepute : ${ipRep.length} baris`); }
const ipRep = await netify.fetchIPReputation(50, agentUuid);
if (ipRep?.length) { db.insertIPReputation(ipRep, fetchedAt, SITE_UUID, agentUuid); console.log(`[Scheduler] OK IPRepute : ${ipRep.length} baris`); }
else console.log(`[Scheduler] -- IPRepute : tidak ada data`);
// 39. Server Discovery (derive dari flows ke port server well-known)
const srvDisc = await netify.fetchServerDiscovery(100);
if (srvDisc?.length) { db.insertServerDiscovery(srvDisc, fetchedAt, SITE_UUID); console.log(`[Scheduler] OK SrvDisc : ${srvDisc.length} baris`); }
const srvDisc = await netify.fetchServerDiscovery(100, agentUuid);
if (srvDisc?.length) { db.insertServerDiscovery(srvDisc, fetchedAt, SITE_UUID, agentUuid); console.log(`[Scheduler] OK SrvDisc : ${srvDisc.length} baris`); }
else console.log(`[Scheduler] -- SrvDisc : tidak ada data`);
// 40. Tor Detection (derive dari apps/hostnames mengandung "tor")
const torDet = await netify.fetchTorDetection(50);
if (torDet?.length) { db.insertTorDetection(torDet, fetchedAt, SITE_UUID); console.log(`[Scheduler] OK TorDet : ${torDet.length} baris`); }
const torDet = await netify.fetchTorDetection(50, agentUuid);
if (torDet?.length) { db.insertTorDetection(torDet, fetchedAt, SITE_UUID, agentUuid); console.log(`[Scheduler] OK TorDet : ${torDet.length} baris`); }
else console.log(`[Scheduler] -- TorDet : tidak ada data`);
// 41. Unencrypted Password (derive dari flows ke port cleartext auth)
const unencPwd = await netify.fetchUnencryptedPasswords(50);
if (unencPwd?.length) { db.insertUnencryptedPasswords(unencPwd, fetchedAt, SITE_UUID); console.log(`[Scheduler] OK UnencPwd : ${unencPwd.length} baris`); }
const unencPwd = await netify.fetchUnencryptedPasswords(50, agentUuid);
if (unencPwd?.length) { db.insertUnencryptedPasswords(unencPwd, fetchedAt, SITE_UUID, agentUuid); console.log(`[Scheduler] OK UnencPwd : ${unencPwd.length} baris`); }
else console.log(`[Scheduler] -- UnencPwd : tidak ada data`);
// 42. VPN Detection (derive dari apps/protocols/ports VPN)
const vpnDet = await netify.fetchVPNDetection(50);
if (vpnDet?.length) { db.insertVPNDetection(vpnDet, fetchedAt, SITE_UUID); console.log(`[Scheduler] OK VPNDet : ${vpnDet.length} baris`); }
const vpnDet = await netify.fetchVPNDetection(50, agentUuid);
if (vpnDet?.length) { db.insertVPNDetection(vpnDet, fetchedAt, SITE_UUID, agentUuid); console.log(`[Scheduler] OK VPNDet : ${vpnDet.length} baris`); }
else console.log(`[Scheduler] -- VPNDet : tidak ada data`);
}
// --- Main loop
await fetchAndStore(fetchedAt, null);
if (apiAgents && apiAgents.length > 0) {
for (const agent of apiAgents) {
if (agent && agent.uuid) {
await fetchAndStore(fetchedAt, agent.uuid);
}
}
}
} catch (err) {
console.error('[Scheduler] ERROR:', err);
} finally {
+2067
View File
File diff suppressed because it is too large. Load diff
+855
View File
@@ -0,0 +1,855 @@
diff --git a/backend/database.js b/backend/database.js
index 2ab6ce0..d4c2c68 100644
--- a/backend/database.js
+++ b/backend/database.js
@@ -104,7 +104,7 @@ function initSchema() {
const adminExists = d.prepare("SELECT count(*) as count FROM users WHERE username = 'admin'").get();
if (adminExists.count === 0) {
const hash = bcrypt.hashSync('admin123', 10);
- d.prepare("INSERT INTO users (username, password_hash, role) VALUES (?, ?, ?)").run('admin', hash, 'SUPER_ADMIN');
+ d.prepare("INSERT INTO users (username, password_hash, role) VALUES (?, ?, ?, ?)").run('admin', hash, 'SUPER_ADMIN');
console.log('[DB] Created default admin user (admin / admin123)');
}
@@ -569,17 +569,17 @@ function initSchema() {
// ΓöÇΓöÇΓöÇ INSERT FUNCTIONS ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
-function insertBandwidthApps(rows, fetchedAt, siteUuid) {
+function insertBandwidthApps(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`
INSERT INTO bandwidth_apps
- (site_uuid, fetched_at, app_id, app_label, app_tag, category, favicon, download, upload, total, flow_count)
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
+ (agent_uuid, site_uuid, fetched_at, app_id, app_label, app_tag, category, favicon, download, upload, total, flow_count)
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`);
d.transaction((items) => {
for (const r of items) {
stmt.run(
- siteUuid, fetchedAt,
+ agentUuid, siteUuid, fetchedAt,
r.app_id ?? null,
r.app_label ?? 'Unknown',
r.app_tag ?? null,
@@ -594,17 +594,17 @@ function insertBandwidthApps(rows, fetchedAt, siteUuid) {
})(rows);
}
-function insertDevices(rows, fetchedAt, siteUuid) {
+function insertDevices(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`
INSERT INTO devices
- (site_uuid, fetched_at, mac_address, ip_address, device_label, device_type, os_label, manufacturer, download, upload, last_seen)
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
+ (agent_uuid, site_uuid, fetched_at, mac_address, ip_address, device_label, device_type, os_label, manufacturer, download, upload, last_seen)
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`);
d.transaction((items) => {
for (const r of items) {
stmt.run(
- siteUuid, fetchedAt,
+ agentUuid, siteUuid, fetchedAt,
r.mac_address ?? null,
r.ip_address ?? null,
r.device_label ?? r.ip_address ?? 'Unknown',
@@ -619,17 +619,17 @@ function insertDevices(rows, fetchedAt, siteUuid) {
})(rows);
}
-function insertFlows(rows, fetchedAt, siteUuid) {
+function insertFlows(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`
INSERT INTO flows
- (site_uuid, fetched_at, flow_id, src_ip, src_mac, dst_ip, dst_port, protocol, app_label, domain, bytes_download, bytes_upload, first_seen, last_seen)
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
+ (agent_uuid, site_uuid, fetched_at, flow_id, src_ip, src_mac, dst_ip, dst_port, protocol, app_label, domain, bytes_download, bytes_upload, first_seen, last_seen)
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`);
d.transaction((items) => {
for (const r of items) {
stmt.run(
- siteUuid, fetchedAt,
+ agentUuid, siteUuid, fetchedAt,
r.flow_id ?? null,
r.src_ip ?? null,
r.src_mac ?? null,
@@ -647,17 +647,17 @@ function insertFlows(rows, fetchedAt, siteUuid) {
})(rows);
}
-function insertThreats(rows, fetchedAt, siteUuid) {
+function insertThreats(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`
INSERT INTO threats
- (site_uuid, fetched_at, threat_id, threat_type, severity, mac_address, ip_address, dst_ip, app_label, domain, description, detected_at)
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
+ (agent_uuid, site_uuid, fetched_at, threat_id, threat_type, severity, mac_address, ip_address, dst_ip, app_label, domain, description, detected_at)
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`);
d.transaction((items) => {
for (const r of items) {
stmt.run(
- siteUuid, fetchedAt,
+ agentUuid, siteUuid, fetchedAt,
r.threat_id ?? null,
r.threat_type ?? null,
r.severity ?? null,
@@ -673,18 +673,18 @@ function insertThreats(rows, fetchedAt, siteUuid) {
})(rows);
}
-function insertProtocols(rows, fetchedAt, siteUuid) {
+function insertProtocols(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`
INSERT INTO bandwidth_protocols
- (site_uuid, fetched_at, protocol_id, protocol_label, download, upload, flow_count)
- VALUES (?, ?, ?, ?, ?, ?, ?)
+ (agent_uuid, site_uuid, fetched_at, protocol_id, protocol_label, download, upload, flow_count)
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)
`);
d.transaction((items) => {
for (const r of items) {
// Data sudah di-flatten oleh netify.js ΓÇö akses langsung tanpa nested
stmt.run(
- siteUuid, fetchedAt,
+ agentUuid, siteUuid, fetchedAt,
r.protocol_id ?? null,
r.protocol_label ?? 'Unknown',
r.download ?? 0,
@@ -695,18 +695,18 @@ function insertProtocols(rows, fetchedAt, siteUuid) {
})(rows);
}
-function insertCountries(rows, fetchedAt, siteUuid) {
+function insertCountries(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`
INSERT INTO bandwidth_countries
- (site_uuid, fetched_at, country_code, country_name, download, upload, flow_count)
- VALUES (?, ?, ?, ?, ?, ?, ?)
+ (agent_uuid, site_uuid, fetched_at, country_code, country_name, download, upload, flow_count)
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)
`);
d.transaction((items) => {
for (const r of items) {
// Data sudah di-flatten oleh netify.js ΓÇö akses langsung tanpa nested
stmt.run(
- siteUuid, fetchedAt,
+ agentUuid, siteUuid, fetchedAt,
r.country_code ?? null,
r.country_name ?? 'Unknown',
r.download ?? 0,
@@ -717,17 +717,17 @@ function insertCountries(rows, fetchedAt, siteUuid) {
})(rows);
}
-function insertDNS(rows, fetchedAt, siteUuid) {
+function insertDNS(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`
INSERT INTO dns_queries
- (site_uuid, fetched_at, domain, query_count, app_label, category)
- VALUES (?, ?, ?, ?, ?, ?)
+ (agent_uuid, site_uuid, fetched_at, domain, query_count, app_label, category)
+ VALUES (?, ?, ?, ?, ?, ?, ?)
`);
d.transaction((items) => {
for (const r of items) {
stmt.run(
- siteUuid, fetchedAt,
+ agentUuid, siteUuid, fetchedAt,
r.domain ?? null,
r.query_count ?? 0,
r.app_label ?? null,
@@ -737,17 +737,17 @@ function insertDNS(rows, fetchedAt, siteUuid) {
})(rows);
}
-function insertEvents(rows, fetchedAt, siteUuid) {
+function insertEvents(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`
INSERT INTO events
- (site_uuid, fetched_at, event_id, event_type, severity, mac_address, ip_address, description, event_at)
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
+ (agent_uuid, site_uuid, fetched_at, event_id, event_type, severity, mac_address, ip_address, description, event_at)
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`);
d.transaction((items) => {
for (const r of items) {
stmt.run(
- siteUuid, fetchedAt,
+ agentUuid, siteUuid, fetchedAt,
r.event_id ?? null,
r.event_type ?? null,
r.severity ?? null,
@@ -760,13 +760,14 @@ function insertEvents(rows, fetchedAt, siteUuid) {
})(rows);
}
-function insertBandwidthTimeline(summary, fetchedAt, siteUuid) {
+function insertBandwidthTimeline(summary, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
d.prepare(`
INSERT INTO bandwidth_timeline
- (site_uuid, fetched_at, total_download, total_upload, total_flows, active_devices, download_speed, upload_speed, flow_speed)
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
+ (agent_uuid, site_uuid, fetched_at, total_download, total_upload, total_flows, active_devices, download_speed, upload_speed, flow_speed)
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`).run(
+ agentUuid,
siteUuid,
fetchedAt,
summary.download ?? 0,
@@ -846,8 +847,8 @@ function getLatestBandwidthApps(limit = 20, siteUuid = null, agentUuid = null) {
const appsLatest = d.prepare(`SELECT MAX(fetched_at) as t FROM bandwidth_apps`).get();
if (!appsLatest?.t) return [];
const rows = d.prepare(`
- SELECT * FROM bandwidth_apps WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) AND fetched_at = @fetched_at ORDER BY download DESC LIMIT @limit
- `).all({ fetched_at: appsLatest.t, limit, siteUuid });
+ SELECT * FROM bandwidth_apps WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) AND (@agentUuid IS NULL OR agent_uuid = @agentUuid) AND fetched_at = @fetched_at ORDER BY download DESC LIMIT @limit
+ `).all({ fetched_at: appsLatest.t, limit, siteUuid, agentUuid });
return correlateAppLabels(rows);
}
@@ -1093,7 +1094,7 @@ function getLatestDevices(limit = 100, siteUuid = null, agentUuid = null, search
SELECT ip_address, mac_address, device_label, device_type, os_label, manufacturer,
MAX(download) as download, MAX(upload) as upload, MAX(fetched_at) as fetched_at, site_uuid, id
FROM devices
- WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) AND (
+ WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) AND (@agentUuid IS NULL OR agent_uuid = @agentUuid) AND (
ip_address LIKE @q OR
mac_address LIKE @q OR
device_label LIKE @q OR
@@ -1110,7 +1111,7 @@ function getLatestDevices(limit = 100, siteUuid = null, agentUuid = null, search
SUM(bytes_download) as download, SUM(bytes_upload) as upload,
MAX(last_seen) as last_seen, MAX(fetched_at) as fetched_at, site_uuid
FROM flows
- WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) AND (
+ WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) AND (@agentUuid IS NULL OR agent_uuid = @agentUuid) AND (
src_ip LIKE @q OR
src_mac LIKE @q OR
app_label LIKE @q OR
@@ -1544,8 +1545,8 @@ function getLatestFlows(limit = 100, siteUuid = null, agentUuid = null) {
`).all(...macs, limit);
} else {
rows = d.prepare(`
- SELECT * FROM flows WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) AND fetched_at = @fetched_at ORDER BY bytes_download DESC LIMIT @limit
- `).all({ fetched_at: latest.t, limit, siteUuid });
+ SELECT * FROM flows WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) AND (@agentUuid IS NULL OR agent_uuid = @agentUuid) AND fetched_at = @fetched_at ORDER BY bytes_download DESC LIMIT @limit
+ `).all({ fetched_at: latest.t, limit, siteUuid, agentUuid });
}
const mapped = rows.map(r => ({
@@ -1569,7 +1570,7 @@ function getLatestThreats(limit = 50, siteUuid = null, agentUuid = null) {
LIMIT ?
`).all(...macs, ...macs, limit);
}
- return d.prepare(`SELECT * FROM threats WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) ORDER BY fetched_at DESC LIMIT @limit`).all({ limit, siteUuid });
+ return d.prepare(`SELECT * FROM threats WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) AND (@agentUuid IS NULL OR agent_uuid = @agentUuid) ORDER BY fetched_at DESC LIMIT @limit`).all({ limit, siteUuid, agentUuid });
}
function getLatestProtocols(limit = 20, siteUuid = null, agentUuid = null) {
@@ -1593,8 +1594,8 @@ function getLatestProtocols(limit = 20, siteUuid = null, agentUuid = null) {
const protoLatest = d.prepare(`SELECT MAX(fetched_at) as t FROM bandwidth_protocols`).get();
if (!protoLatest?.t) return [];
return d.prepare(`
- SELECT * FROM bandwidth_protocols WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) AND fetched_at = @fetched_at ORDER BY download DESC LIMIT @limit
- `).all({ fetched_at: protoLatest.t, limit, siteUuid });
+ SELECT * FROM bandwidth_protocols WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) AND (@agentUuid IS NULL OR agent_uuid = @agentUuid) AND fetched_at = @fetched_at ORDER BY download DESC LIMIT @limit
+ `).all({ fetched_at: protoLatest.t, limit, siteUuid, agentUuid });
}
function getLatestCountries(limit = 15, siteUuid = null, agentUuid = null) {
@@ -1711,8 +1712,8 @@ function getLatestCountries(limit = 15, siteUuid = null, agentUuid = null) {
const countryLatest = d.prepare(`SELECT MAX(fetched_at) as t FROM bandwidth_countries`).get();
if (!countryLatest?.t) return [];
return d.prepare(`
- SELECT * FROM bandwidth_countries WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) AND fetched_at = @fetched_at ORDER BY download DESC LIMIT @limit
- `).all({ fetched_at: countryLatest.t, limit, siteUuid });
+ SELECT * FROM bandwidth_countries WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) AND (@agentUuid IS NULL OR agent_uuid = @agentUuid) AND fetched_at = @fetched_at ORDER BY download DESC LIMIT @limit
+ `).all({ fetched_at: countryLatest.t, limit, siteUuid, agentUuid });
}
function getLatestDNS(limit = 20, siteUuid = null, agentUuid = null) {
@@ -1736,8 +1737,8 @@ function getLatestDNS(limit = 20, siteUuid = null, agentUuid = null) {
const dnsLatest = d.prepare(`SELECT MAX(fetched_at) as t FROM dns_queries`).get();
if (!dnsLatest?.t) return [];
return d.prepare(`
- SELECT * FROM dns_queries WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) AND fetched_at = @fetched_at ORDER BY query_count DESC LIMIT @limit
- `).all({ fetched_at: dnsLatest.t, limit, siteUuid });
+ SELECT * FROM dns_queries WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) AND (@agentUuid IS NULL OR agent_uuid = @agentUuid) AND fetched_at = @fetched_at ORDER BY query_count DESC LIMIT @limit
+ `).all({ fetched_at: dnsLatest.t, limit, siteUuid, agentUuid });
}
function getLatestEvents(limit = 50, siteUuid = null, agentUuid = null) {
@@ -1752,7 +1753,7 @@ function getLatestEvents(limit = 50, siteUuid = null, agentUuid = null) {
LIMIT ?
`).all(...macs, ...macs, limit);
}
- return d.prepare(`SELECT * FROM events WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) ORDER BY fetched_at DESC LIMIT @limit`).all({ limit, siteUuid });
+ return d.prepare(`SELECT * FROM events WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) AND (@agentUuid IS NULL OR agent_uuid = @agentUuid) ORDER BY fetched_at DESC LIMIT @limit`).all({ limit, siteUuid, agentUuid });
}
function getBandwidthTimeline(points = 60, siteUuid = null, agentUuid = null) {
@@ -1780,7 +1781,7 @@ function getBandwidthTimeline(points = 60, siteUuid = null, agentUuid = null) {
`).all(...macs, ...macs, points).reverse();
}
return d.prepare(`
- SELECT * FROM bandwidth_timeline WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) ORDER BY fetched_at DESC LIMIT @limit
+ SELECT * FROM bandwidth_timeline WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) AND (@agentUuid IS NULL OR agent_uuid = @agentUuid) ORDER BY fetched_at DESC LIMIT @limit
`).all({ limit: points, siteUuid }).reverse();
}
@@ -1849,141 +1850,141 @@ function getStats(siteUuid = null, agentUuid = null) {
// Fallback to site-wide stats if no agentUuid
const latestDevFetch = d.prepare(`SELECT MAX(fetched_at) as t FROM devices`).get();
const totalDevices = latestDevFetch?.t
- ? (d.prepare(`SELECT COUNT(*) as n FROM devices WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) AND fetched_at = @fetched_at`).get({ fetched_at: latestDevFetch.t, siteUuid })?.n ?? 0)
+ ? (d.prepare(`SELECT COUNT(*) as n FROM devices WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) AND (@agentUuid IS NULL OR agent_uuid = @agentUuid) AND fetched_at = @fetched_at`).get({ fetched_at: latestDevFetch.t, siteUuid })?.n ?? 0)
: 0;
const latestFlowFetch = d.prepare(`SELECT MAX(fetched_at) as t FROM flows`).get();
const activeFlows = latestFlowFetch?.t
- ? (d.prepare(`SELECT COUNT(*) as n FROM flows WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) AND fetched_at = @fetched_at`).get({ fetched_at: latestFlowFetch.t, siteUuid })?.n ?? 0)
+ ? (d.prepare(`SELECT COUNT(*) as n FROM flows WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) AND (@agentUuid IS NULL OR agent_uuid = @agentUuid) AND fetched_at = @fetched_at`).get({ fetched_at: latestFlowFetch.t, siteUuid })?.n ?? 0)
: 0;
- const totalThreats = d.prepare(`SELECT COUNT(*) as n FROM threats WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid)`).get({ siteUuid })?.n ?? 0;
- const totalEvents = d.prepare(`SELECT COUNT(*) as n FROM events WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid)`).get({ siteUuid })?.n ?? 0;
+ const totalThreats = d.prepare(`SELECT COUNT(*) as n FROM threats WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) AND (@agentUuid IS NULL OR agent_uuid = @agentUuid)`).get({ siteUuid, agentUuid })?.n ?? 0;
+ const totalEvents = d.prepare(`SELECT COUNT(*) as n FROM events WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) AND (@agentUuid IS NULL OR agent_uuid = @agentUuid)`).get({ siteUuid, agentUuid })?.n ?? 0;
const lastFetch = d.prepare(`SELECT MAX(fetched_at) as t FROM bandwidth_timeline`).get()?.t ?? null;
- const latestBw = d.prepare(`SELECT * FROM bandwidth_timeline WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) ORDER BY fetched_at DESC LIMIT 1`).get({ siteUuid });
+ const latestBw = d.prepare(`SELECT * FROM bandwidth_timeline WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) AND (@agentUuid IS NULL OR agent_uuid = @agentUuid) ORDER BY fetched_at DESC LIMIT 1`).get({ siteUuid, agentUuid });
return { totalDevices, activeFlows, totalThreats, totalEvents, lastFetch, latestBw };
}
// ΓöÇΓöÇΓöÇ INSERT FITUR BARU 1-11 ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
-function insertAppCategories(rows, fetchedAt, siteUuid) {
+function insertAppCategories(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO app_categories
- (site_uuid, fetched_at, category_label, download, upload, total)
+ (agent_uuid, site_uuid, fetched_at, category_label, download, upload, total)
VALUES (?, ?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
- siteUuid, fetchedAt, r.category_label, r.download, r.upload, r.total);
+ agentUuid, siteUuid, fetchedAt, r.category_label, r.download, r.upload, r.total);
})(rows);
}
-function insertContinents(rows, fetchedAt, siteUuid) {
+function insertContinents(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO continents
- (site_uuid, fetched_at, continent_name, download, upload, total)
+ (agent_uuid, site_uuid, fetched_at, continent_name, download, upload, total)
VALUES (?, ?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
- siteUuid, fetchedAt, r.continent_name, r.download, r.upload, r.total);
+ agentUuid, siteUuid, fetchedAt, r.continent_name, r.download, r.upload, r.total);
})(rows);
}
-function insertRegions(rows, fetchedAt, siteUuid) {
+function insertRegions(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO regions
- (site_uuid, fetched_at, region_name, region_code, country_name, country_code, download)
+ (agent_uuid, site_uuid, fetched_at, region_name, region_code, country_name, country_code, download)
VALUES (?, ?,?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
- siteUuid, fetchedAt, r.region_name, r.region_code, r.country_name, r.country_code, r.download);
+ agentUuid, siteUuid, fetchedAt, r.region_name, r.region_code, r.country_name, r.country_code, r.download);
})(rows);
}
-function insertCities(rows, fetchedAt, siteUuid) {
+function insertCities(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO cities
- (site_uuid, fetched_at, city_name, region_name, country_name, country_code, download)
+ (agent_uuid, site_uuid, fetched_at, city_name, region_name, country_name, country_code, download)
VALUES (?, ?,?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
- siteUuid, fetchedAt, r.city_name, r.region_name, r.country_name, r.country_code, r.download);
+ agentUuid, siteUuid, fetchedAt, r.city_name, r.region_name, r.country_name, r.country_code, r.download);
})(rows);
}
-function insertVLANs(rows, fetchedAt, siteUuid) {
+function insertVLANs(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO vlans
- (site_uuid, fetched_at, vlan_id, vlan_label, download, upload, total)
+ (agent_uuid, site_uuid, fetched_at, vlan_id, vlan_label, download, upload, total)
VALUES (?, ?,?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
- siteUuid, fetchedAt, r.vlan_id, r.vlan_label, r.download, r.upload, r.total);
+ agentUuid, siteUuid, fetchedAt, r.vlan_id, r.vlan_label, r.download, r.upload, r.total);
})(rows);
}
-function insertInterfaces(rows, fetchedAt, siteUuid) {
+function insertInterfaces(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO interfaces
- (site_uuid, fetched_at, iface_id, iface_name, iface_role, agent_id, download, upload, total)
+ (agent_uuid, site_uuid, fetched_at, iface_id, iface_name, iface_role, agent_id, download, upload, total)
VALUES (?, ?,?,?,?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
- siteUuid, fetchedAt, r.iface_id, r.iface_name, r.iface_role, String(r.agent_id ?? ''), r.download, r.upload, r.total);
+ agentUuid, siteUuid, fetchedAt, r.iface_id, r.iface_name, r.iface_role, String(r.agent_id ?? ''), r.download, r.upload, r.total);
})(rows);
}
-function insertFlowTypes(rows, fetchedAt, siteUuid) {
+function insertFlowTypes(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO flow_types
- (site_uuid, fetched_at, flow_type_label, download, upload, total)
+ (agent_uuid, site_uuid, fetched_at, flow_type_label, download, upload, total)
VALUES (?, ?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
- siteUuid, fetchedAt, r.flow_type_label, r.download, r.upload, r.total);
+ agentUuid, siteUuid, fetchedAt, r.flow_type_label, r.download, r.upload, r.total);
})(rows);
}
-function insertFlowOrigins(rows, fetchedAt, siteUuid) {
+function insertFlowOrigins(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO flow_origins
- (site_uuid, fetched_at, flow_origin_label, download, upload, total)
+ (agent_uuid, site_uuid, fetched_at, flow_origin_label, download, upload, total)
VALUES (?, ?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
- siteUuid, fetchedAt, r.flow_origin_label, r.download, r.upload, r.total);
+ agentUuid, siteUuid, fetchedAt, r.flow_origin_label, r.download, r.upload, r.total);
})(rows);
}
-function insertIPVersions(rows, fetchedAt, siteUuid) {
+function insertIPVersions(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO ip_versions
- (site_uuid, fetched_at, ip_version_label, download, upload, total)
+ (agent_uuid, site_uuid, fetched_at, ip_version_label, download, upload, total)
VALUES (?, ?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
- siteUuid, fetchedAt, r.ip_version_label, r.download, r.upload, r.total);
+ agentUuid, siteUuid, fetchedAt, r.ip_version_label, r.download, r.upload, r.total);
})(rows);
}
-function insertRemoteIPs(rows, fetchedAt, siteUuid) {
+function insertRemoteIPs(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO remote_ips
- (site_uuid, fetched_at, remote_ip, ip_version, download, upload, total)
+ (agent_uuid, site_uuid, fetched_at, remote_ip, ip_version, download, upload, total)
VALUES (?, ?,?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
- siteUuid, fetchedAt, r.remote_ip, r.ip_version, r.download, r.upload, r.total);
+ agentUuid, siteUuid, fetchedAt, r.remote_ip, r.ip_version, r.download, r.upload, r.total);
})(rows);
}
-function insertMACBandwidth(rows, fetchedAt, siteUuid) {
+function insertMACBandwidth(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO mac_bandwidth
- (site_uuid, fetched_at, mac_address, manufacturer, download, upload, total)
+ (agent_uuid, site_uuid, fetched_at, mac_address, manufacturer, download, upload, total)
VALUES (?, ?,?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
- siteUuid, fetchedAt, r.mac_address, r.manufacturer, r.download, r.upload, r.total);
+ agentUuid, siteUuid, fetchedAt, r.mac_address, r.manufacturer, r.download, r.upload, r.total);
})(rows);
}
@@ -2048,7 +2049,7 @@ function getLatest(table, orderBy = 'download', limit = 50, siteUuid = null, age
}
// Fallback to standard site-wide select
- rows = d.prepare(`SELECT * FROM ${table} WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) AND fetched_at = @fetched_at ORDER BY ${orderBy} DESC LIMIT @limit`).all({ fetched_at: latest.t, limit, siteUuid });
+ rows = d.prepare(`SELECT * FROM ${table} WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) AND (@agentUuid IS NULL OR agent_uuid = @agentUuid) AND fetched_at = @fetched_at ORDER BY ${orderBy} DESC LIMIT @limit`).all({ fetched_at: latest.t, limit, siteUuid, agentUuid });
// If agentUuid is provided, scale down numerical values by traffic ratio to match the agent's footprint
if (agentUuid && !['mac_bandwidth', 'interfaces'].includes(table)) {
@@ -2067,272 +2068,272 @@ function getLatest(table, orderBy = 'download', limit = 50, siteUuid = null, age
}
// DPI Fields
-function insertTLSVersions(rows, fetchedAt, siteUuid) {
+function insertTLSVersions(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO tls_versions
- (site_uuid, fetched_at, tls_version, download, upload, total)
+ (agent_uuid, site_uuid, fetched_at, tls_version, download, upload, total)
VALUES (?, ?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
- siteUuid, fetchedAt, r.tls_version, r.download, r.upload, r.total);
+ agentUuid, siteUuid, fetchedAt, r.tls_version, r.download, r.upload, r.total);
})(rows);
}
-function insertTLSCiphers(rows, fetchedAt, siteUuid) {
+function insertTLSCiphers(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO tls_ciphers
- (site_uuid, fetched_at, tls_cipher, download, upload, total)
+ (agent_uuid, site_uuid, fetched_at, tls_cipher, download, upload, total)
VALUES (?, ?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
- siteUuid, fetchedAt, r.tls_cipher, r.download, r.upload, r.total);
+ agentUuid, siteUuid, fetchedAt, r.tls_cipher, r.download, r.upload, r.total);
})(rows);
}
-function insertTLSSecurity(rows, fetchedAt, siteUuid) {
+function insertTLSSecurity(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO tls_security
- (site_uuid, fetched_at, tls_security, color, download, upload, total)
+ (agent_uuid, site_uuid, fetched_at, tls_security, color, download, upload, total)
VALUES (?, ?,?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
- siteUuid, fetchedAt, r.tls_security, r.color, r.download, r.upload, r.total);
+ agentUuid, siteUuid, fetchedAt, r.tls_security, r.color, r.download, r.upload, r.total);
})(rows);
}
-function insertNetBIOSHostnames(rows, fetchedAt, siteUuid) {
+function insertNetBIOSHostnames(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO netbios_hostnames
- (site_uuid, fetched_at, hostname, download, upload, total)
+ (agent_uuid, site_uuid, fetched_at, hostname, download, upload, total)
VALUES (?, ?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
- siteUuid, fetchedAt, r.hostname, r.download, r.upload, r.total);
+ agentUuid, siteUuid, fetchedAt, r.hostname, r.download, r.upload, r.total);
})(rows);
}
-function insertDiscoveryOS(rows, fetchedAt, siteUuid) {
+function insertDiscoveryOS(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO discovery_os
- (site_uuid, fetched_at, os_label, download, upload, total)
+ (agent_uuid, site_uuid, fetched_at, os_label, download, upload, total)
VALUES (?, ?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
- siteUuid, fetchedAt, r.os_label, r.download, r.upload, r.total);
+ agentUuid, siteUuid, fetchedAt, r.os_label, r.download, r.upload, r.total);
})(rows);
}
// ΓöÇΓöÇΓöÇ INSERT DPI 12-21 ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
-function insertDHCPFingerprints(rows, fetchedAt, siteUuid) {
+function insertDHCPFingerprints(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO dhcp_fingerprints
- (site_uuid, fetched_at, fingerprint, download, upload, total)
+ (agent_uuid, site_uuid, fetched_at, fingerprint, download, upload, total)
VALUES (?, ?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
- siteUuid, fetchedAt, r.fingerprint, r.download, r.upload, r.total);
+ agentUuid, siteUuid, fetchedAt, r.fingerprint, r.download, r.upload, r.total);
})(rows);
}
-function insertHTTPUserAgents(rows, fetchedAt, siteUuid) {
+function insertHTTPUserAgents(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO http_user_agents
- (site_uuid, fetched_at, user_agent, download, upload, total)
+ (agent_uuid, site_uuid, fetched_at, user_agent, download, upload, total)
VALUES (?, ?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
- siteUuid, fetchedAt, r.user_agent, r.download, r.upload, r.total);
+ agentUuid, siteUuid, fetchedAt, r.user_agent, r.download, r.upload, r.total);
})(rows);
}
-function insertSNIHostnames(rows, fetchedAt, siteUuid) {
+function insertSNIHostnames(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO sni_hostnames
- (site_uuid, fetched_at, sni_hostname, download, upload, total)
+ (agent_uuid, site_uuid, fetched_at, sni_hostname, download, upload, total)
VALUES (?, ?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
- siteUuid, fetchedAt, r.sni_hostname, r.download, r.upload, r.total);
+ agentUuid, siteUuid, fetchedAt, r.sni_hostname, r.download, r.upload, r.total);
})(rows);
}
-function insertSSLServerCN(rows, fetchedAt, siteUuid) {
+function insertSSLServerCN(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO ssl_server_cn
- (site_uuid, fetched_at, ssl_server_cn, download, upload, total)
+ (agent_uuid, site_uuid, fetched_at, ssl_server_cn, download, upload, total)
VALUES (?, ?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
- siteUuid, fetchedAt, r.ssl_server_cn, r.download, r.upload, r.total);
+ agentUuid, siteUuid, fetchedAt, r.ssl_server_cn, r.download, r.upload, r.total);
})(rows);
}
-function insertQUICHostnames(rows, fetchedAt, siteUuid) {
+function insertQUICHostnames(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO quic_hostnames
- (site_uuid, fetched_at, quic_hostname, download, upload, total)
+ (agent_uuid, site_uuid, fetched_at, quic_hostname, download, upload, total)
VALUES (?, ?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
- siteUuid, fetchedAt, r.quic_hostname, r.download, r.upload, r.total);
+ agentUuid, siteUuid, fetchedAt, r.quic_hostname, r.download, r.upload, r.total);
})(rows);
}
-function insertBitTorrentHashes(rows, fetchedAt, siteUuid) {
+function insertBitTorrentHashes(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO bittorrent_hashes
- (site_uuid, fetched_at, info_hash, label, download, upload, total)
+ (agent_uuid, site_uuid, fetched_at, info_hash, label, download, upload, total)
VALUES (?, ?,?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
- siteUuid, fetchedAt, r.info_hash, r.label, r.download, r.upload, r.total);
+ agentUuid, siteUuid, fetchedAt, r.info_hash, r.label, r.download, r.upload, r.total);
})(rows);
}
-function insertSSHVersions(rows, fetchedAt, siteUuid) {
+function insertSSHVersions(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO ssh_versions
- (site_uuid, fetched_at, ssh_version, download, upload, total)
+ (agent_uuid, site_uuid, fetched_at, ssh_version, download, upload, total)
VALUES (?, ?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
- siteUuid, fetchedAt, r.ssh_version, r.download, r.upload, r.total);
+ agentUuid, siteUuid, fetchedAt, r.ssh_version, r.download, r.upload, r.total);
})(rows);
}
-function insertMDNSHostnames(rows, fetchedAt, siteUuid) {
+function insertMDNSHostnames(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO mdns_hostnames
- (site_uuid, fetched_at, mdns_hostname, download, upload, total)
+ (agent_uuid, site_uuid, fetched_at, mdns_hostname, download, upload, total)
VALUES (?, ?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
- siteUuid, fetchedAt, r.mdns_hostname, r.download, r.upload, r.total);
+ agentUuid, siteUuid, fetchedAt, r.mdns_hostname, r.download, r.upload, r.total);
})(rows);
}
// ΓöÇΓöÇΓöÇ INSERT INTELLIGENCE 22-30 ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
-function insertCryptoMining(rows, fetchedAt, siteUuid) {
+function insertCryptoMining(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO intel_crypto_mining
- (site_uuid, fetched_at, detected_at, ip_address, mac_address, pool_host, pool_ip, protocol, app_label, confidence, download, upload)
+ (agent_uuid, site_uuid, fetched_at, detected_at, ip_address, mac_address, pool_host, pool_ip, protocol, app_label, confidence, download, upload)
VALUES (?, ?,?,?,?,?,?,?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
- siteUuid, fetchedAt, r.detected_at ?? fetchedAt, r.ip_address, r.mac_address,
+ agentUuid, siteUuid, fetchedAt, r.detected_at ?? fetchedAt, r.ip_address, r.mac_address,
r.pool_host, r.pool_ip, r.protocol, r.app_label, r.confidence,
r.download ?? 0, r.upload ?? 0
);
})(rows);
}
-function insertDeviceDiscovery(rows, fetchedAt, siteUuid) {
+function insertDeviceDiscovery(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO intel_device_discovery
- (site_uuid, fetched_at, detected_at, ip_address, mac_address, device_label, device_type, os_label, manufacturer, is_new)
+ (agent_uuid, site_uuid, fetched_at, detected_at, ip_address, mac_address, device_label, device_type, os_label, manufacturer, is_new)
VALUES (?, ?,?,?,?,?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
- siteUuid, fetchedAt, r.detected_at ?? fetchedAt, r.ip_address, r.mac_address,
+ agentUuid, siteUuid, fetchedAt, r.detected_at ?? fetchedAt, r.ip_address, r.mac_address,
r.device_label, r.device_type, r.os_label, r.manufacturer,
r.is_new ? 1 : 0
);
})(rows);
}
-function insertEncryptionAudit(rows, fetchedAt, siteUuid) {
+function insertEncryptionAudit(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO intel_encryption_audit
- (site_uuid, fetched_at, detected_at, ip_address, mac_address, device_label, encrypted_pct, unencrypted, encrypted, total, risk_level)
+ (agent_uuid, site_uuid, fetched_at, detected_at, ip_address, mac_address, device_label, encrypted_pct, unencrypted, encrypted, total, risk_level)
VALUES (?, ?,?,?,?,?,?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
- siteUuid, fetchedAt, r.detected_at ?? fetchedAt, r.ip_address, r.mac_address,
+ agentUuid, siteUuid, fetchedAt, r.detected_at ?? fetchedAt, r.ip_address, r.mac_address,
r.device_label, r.encrypted_pct, r.unencrypted ?? 0, r.encrypted ?? 0,
r.total ?? 0, r.risk_level
);
})(rows);
}
-function insertInsecureProtocols(rows, fetchedAt, siteUuid) {
+function insertInsecureProtocols(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO intel_insecure_protocols
- (site_uuid, fetched_at, detected_at, protocol, ip_address, mac_address, dst_ip, dst_port, app_label, download, upload, risk, source)
+ (agent_uuid, site_uuid, fetched_at, detected_at, protocol, ip_address, mac_address, dst_ip, dst_port, app_label, download, upload, risk, source)
VALUES (?, ?,?,?,?,?,?,?,?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
- siteUuid, fetchedAt, r.detected_at ?? fetchedAt, r.protocol, r.ip_address, r.mac_address,
+ agentUuid, siteUuid, fetchedAt, r.detected_at ?? fetchedAt, r.protocol, r.ip_address, r.mac_address,
r.dst_ip, r.dst_port, r.app_label, r.download ?? 0, r.upload ?? 0,
r.risk ?? 'Medium', r.source ?? 'api'
);
})(rows);
}
-function insertIPReputation(rows, fetchedAt, siteUuid) {
+function insertIPReputation(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO intel_ip_reputation
- (site_uuid, fetched_at, detected_at, ip_address, local_ip, mac_address, reputation, score, country, app_label, download, upload, blacklisted)
+ (agent_uuid, site_uuid, fetched_at, detected_at, ip_address, local_ip, mac_address, reputation, score, country, app_label, download, upload, blacklisted)
VALUES (?, ?,?,?,?,?,?,?,?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
- siteUuid, fetchedAt, r.detected_at ?? fetchedAt, r.ip_address, r.local_ip, r.mac_address,
+ agentUuid, siteUuid, fetchedAt, r.detected_at ?? fetchedAt, r.ip_address, r.local_ip, r.mac_address,
r.reputation, r.score, r.country, r.app_label,
r.download ?? 0, r.upload ?? 0, r.blacklisted ? 1 : 0
);
})(rows);
}
-function insertServerDiscovery(rows, fetchedAt, siteUuid) {
+function insertServerDiscovery(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO intel_server_discovery
- (site_uuid, fetched_at, detected_at, ip_address, mac_address, server_type, hostname, port, protocol, os_label, download, upload)
+ (agent_uuid, site_uuid, fetched_at, detected_at, ip_address, mac_address, server_type, hostname, port, protocol, os_label, download, upload)
VALUES (?, ?,?,?,?,?,?,?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
- siteUuid, fetchedAt, r.detected_at ?? fetchedAt, r.ip_address, r.mac_address,
+ agentUuid, siteUuid, fetchedAt, r.detected_at ?? fetchedAt, r.ip_address, r.mac_address,
r.server_type, r.hostname, r.port, r.protocol, r.os_label,
r.download ?? 0, r.upload ?? 0
);
})(rows);
}
-function insertTorDetection(rows, fetchedAt, siteUuid) {
+function insertTorDetection(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO intel_tor_detection
- (site_uuid, fetched_at, detected_at, ip_address, mac_address, exit_node, circuit_id, download, upload, country)
+ (agent_uuid, site_uuid, fetched_at, detected_at, ip_address, mac_address, exit_node, circuit_id, download, upload, country)
VALUES (?, ?,?,?,?,?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
- siteUuid, fetchedAt, r.detected_at ?? fetchedAt, r.ip_address, r.mac_address,
+ agentUuid, siteUuid, fetchedAt, r.detected_at ?? fetchedAt, r.ip_address, r.mac_address,
r.exit_node, r.circuit_id, r.download ?? 0, r.upload ?? 0, r.country
);
})(rows);
}
-function insertUnencryptedPasswords(rows, fetchedAt, siteUuid) {
+function insertUnencryptedPasswords(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO intel_unencrypted_passwords
- (site_uuid, fetched_at, detected_at, ip_address, mac_address, dst_ip, dst_port, protocol, username, download, upload, severity)
+ (agent_uuid, site_uuid, fetched_at, detected_at, ip_address, mac_address, dst_ip, dst_port, protocol, username, download, upload, severity)
VALUES (?, ?,?,?,?,?,?,?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
- siteUuid, fetchedAt, r.detected_at ?? fetchedAt, r.ip_address, r.mac_address,
+ agentUuid, siteUuid, fetchedAt, r.detected_at ?? fetchedAt, r.ip_address, r.mac_address,
r.dst_ip, r.dst_port, r.protocol, r.username,
r.download ?? 0, r.upload ?? 0, r.severity ?? 'Critical'
);
})(rows);
}
-function insertVPNDetection(rows, fetchedAt, siteUuid) {
+function insertVPNDetection(rows, fetchedAt, siteUuid, agentUuid) {
const d = getDB();
const stmt = d.prepare(`INSERT INTO intel_vpn_detection
- (site_uuid, fetched_at, detected_at, ip_address, mac_address, vpn_type, remote_ip, protocol, download, upload, country, confidence)
+ (agent_uuid, site_uuid, fetched_at, detected_at, ip_address, mac_address, vpn_type, remote_ip, protocol, download, upload, country, confidence)
VALUES (?, ?,?,?,?,?,?,?,?,?,?,?)`);
d.transaction(items => {
for (const r of items) stmt.run(
- siteUuid, fetchedAt, r.detected_at ?? fetchedAt, r.ip_address, r.mac_address,
+ agentUuid, siteUuid, fetchedAt, r.detected_at ?? fetchedAt, r.ip_address, r.mac_address,
r.vpn_type, r.remote_ip, r.protocol,
r.download ?? 0, r.upload ?? 0, r.country, r.confidence
);
@@ -2357,7 +2358,7 @@ function getIntelData(table, limit = 100, siteUuid = null, agentUuid = null) {
LIMIT ?
`).all(...macs, ...macs, limit);
}
- return d.prepare(`SELECT * FROM ${table} WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) ORDER BY fetched_at DESC LIMIT @limit`).all({ limit, siteUuid });
+ return d.prepare(`SELECT * FROM ${table} WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) AND (@agentUuid IS NULL OR agent_uuid = @agentUuid) ORDER BY fetched_at DESC LIMIT @limit`).all({ limit, siteUuid, agentUuid });
}
function getIntelStats(siteUuid = null, agentUuid = null) {
@@ -2381,7 +2382,7 @@ function getIntelStats(siteUuid = null, agentUuid = null) {
WHERE mac_address IN (${placeholders}) OR ${ipField} IN (SELECT DISTINCT src_ip FROM flows WHERE src_mac IN (${placeholders}))
`).get(...macs, ...macs)?.n ?? 0;
} else {
- counts[t] = d.prepare(`SELECT COUNT(*) as n FROM ${t} WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid)`).get({ siteUuid })?.n ?? 0;
+ counts[t] = d.prepare(`SELECT COUNT(*) as n FROM ${t} WHERE (@siteUuid IS NULL OR site_uuid = @siteUuid) AND (@agentUuid IS NULL OR agent_uuid = @agentUuid)`).get({ siteUuid, agentUuid })?.n ?? 0;
}
} catch { counts[t] = 0; }
}
+29
View File
@@ -0,0 +1,29 @@
const Database = require('better-sqlite3');
const path = require('path');
const DB_PATH = path.join('d:/FILE/Magang/Deep Package Inspection/backend/netify_data.db');
const db = new Database(DB_PATH);
const tables = [
'bandwidth_apps', 'bandwidth_protocols', 'bandwidth_countries', 'dns_queries', 'events',
'bandwidth_timeline', 'threats', 'devices', 'flows', 'tls_versions', 'tls_ciphers',
'tls_security', 'netbios_hostnames', 'dhcp_fingerprints', 'http_user_agents', 'sni_hostnames',
'ssl_server_cn', 'quic_hostnames', 'bittorrent_hashes', 'ssh_versions', 'mdns_hostnames',
'intel_crypto_mining', 'intel_device_discovery', 'intel_encryption_audit', 'intel_insecure_protocols',
'intel_ip_reputation', 'intel_server_discovery', 'intel_tor_detection', 'intel_unencrypted_passwords',
'intel_vpn_detection', 'app_categories', 'continents', 'regions', 'cities', 'vlans',
'interfaces', 'flow_types', 'flow_origins', 'ip_versions', 'remote_ips', 'mac_bandwidth', 'discovery_os'
];
let success = 0;
for (const t of tables) {
try {
db.exec(`ALTER TABLE ${t} ADD COLUMN agent_uuid TEXT DEFAULT NULL`);
success++;
} catch (e) {
if (!e.message.includes('duplicate column name')) {
console.log(`Failed to alter ${t}:`, e.message);
}
}
}
console.log(`Migration complete! Successfully altered ${success} tables.`);
db.close();