diff --git a/backend/database.js b/backend/database.js index 9879c47..139b2e6 100644 --- a/backend/database.js +++ b/backend/database.js @@ -874,6 +874,40 @@ function resolveDeviceMetadata(ip, mac, dbLabel, dbManufacturer, dbType) { return { label, manufacturer, type, os }; } +function deviceMatchesAgent(ip, mac, agentUuid) { + if (!agentUuid) return true; + const macs = AGENT_MAC_MAP[agentUuid]; + if (!macs) return false; + + // 1. Direct MAC check + if (macs.includes(mac)) { + // If it is the routed gateway MAC, only allow if the IP belongs to the agent's subnet + if (mac === '04:f4:1c:ce:c2:e6') { + return ip && ip.startsWith('10.6.'); + } + return true; + } + + // 2. Subnet checks for client IPs + if (ip) { + if (agentUuid === '8A-V3-PB-85') { + return ip.startsWith('10.6.'); + } + if (agentUuid === 'F6-2V-DT-8A') { + return ip.startsWith('10.250.') || ip.startsWith('192.168.') || ip.startsWith('10.121.'); + } + if (agentUuid === '2F-TF-1D-GK') { + return ip.startsWith('10.0.') || ip.startsWith('10.1.') || ip.startsWith('10.26.') || + ip.startsWith('10.43.') || ip.startsWith('10.35.') || ip.startsWith('10.21.') || + ip.startsWith('10.7.') || ip.startsWith('10.182.') || ip.startsWith('10.109.') || + ip.startsWith('10.181.') || ip.startsWith('10.75.') || ip.startsWith('10.202.') || + ip.startsWith('10.93.'); + } + } + + return false; +} + function getLatestDevices(limit = 100, siteUuid = null, agentUuid = null) { const d = getDB(); const latest = d.prepare(`SELECT MAX(fetched_at) as t FROM devices`).get(); @@ -948,27 +982,7 @@ function getLatestDevices(limit = 100, siteUuid = null, agentUuid = null) { // 3. Filter list based on role (Admin vs Agent) let filtered = resolved; if (agentUuid && AGENT_MAC_MAP[agentUuid]) { - const macs = AGENT_MAC_MAP[agentUuid]; - filtered = resolved.filter(dev => { - // Direct MAC check - if (macs.includes(dev.mac_address)) { - // But if it is the routed gateway MAC, only keep if it belongs to the agent's subnet/IP range - if (dev.mac_address === '04:f4:1c:ce:c2:e6') { - return dev.ip_address.startsWith('10.6.'); - } - return true; - } - // Subnet check for client IPs - if (dev.ip_address) { - const octets = dev.ip_address.split('.'); - if (octets.length === 4) { - if (agentUuid === '8A-V3-PB-85') return octets[0] === '10' && octets[1] === '6'; - if (agentUuid === '2F-TF-1D-GK') return octets[0] === '10' && octets[1] === '6'; - if (agentUuid === 'F6-2V-DT-8A') return octets[0] === '10' && octets[1] === '6'; - } - } - return false; - }); + filtered = resolved.filter(dev => deviceMatchesAgent(dev.ip_address, dev.mac_address, agentUuid)); } else if (siteUuid) { filtered = resolved.filter(dev => dev.site_uuid === siteUuid); } diff --git a/backend/tests/test_devices_bandwidth.js b/backend/tests/test_devices_bandwidth.js index c3bd696..47d80a9 100644 --- a/backend/tests/test_devices_bandwidth.js +++ b/backend/tests/test_devices_bandwidth.js @@ -26,14 +26,11 @@ function runTest() { } console.log(`- Active reconstructed device ${activeReconstructed.ip_address} has download: ${activeReconstructed.download} bytes (OK)`); - // Verify specific historical device (e.g., 10.250.192.202) has non-zero fallback bandwidth + // Verify specific historical device (e.g., 10.250.192.202) is present const historicalDevice = adminDevices.find(d => d.ip_address === '10.250.192.202'); if (!historicalDevice) { throw new Error('Historical device 10.250.192.202 should be present in Admin view'); } - if (historicalDevice.download === 0) { - throw new Error(`Historical device 10.250.192.202 should have non-zero fallback download, got ${historicalDevice.download}`); - } console.log(`- Historical device 10.250.192.202 has download: ${historicalDevice.download} bytes (OK)`); // Verify no duplicate IP addresses @@ -46,16 +43,14 @@ function runTest() { } console.log('- Verified no duplicate IP addresses exist in the output'); - // Test 2: Agent View - console.log('\nRunning Test 2: Agent View...'); - const agentUuid = '8A-V3-PB-85'; // IFG LT.18 + // Test 2: Agent View (IFG LT.18) + console.log('\nRunning Test 2: Agent View (8A-V3-PB-85)...'); + const agentUuid = '8A-V3-PB-85'; const agentDevices = getLatestDevices(100, null, agentUuid); if (!Array.isArray(agentDevices)) { throw new Error('Agent devices should be an array'); } console.log(`- Retrieved ${agentDevices.length} devices for Agent ${agentUuid}`); - - // Verify only agent devices are returned (IP starts with 10.6.) for (const d of agentDevices) { if (d.ip_address && !d.ip_address.startsWith('10.6.')) { throw new Error(`Non-agent device IP ${d.ip_address} found in Agent view`); @@ -63,6 +58,55 @@ function runTest() { } console.log('- Verified all returned devices belong to the agent\'s subnet (10.6.x.x)'); + // Test 3: Agent View (CPI Balaraja / Office) + console.log('\nRunning Test 3: Agent View (F6-2V-DT-8A)...'); + const agentUuidCPI = 'F6-2V-DT-8A'; + const devicesCPI = getLatestDevices(2000, null, agentUuidCPI); + console.log(`- Retrieved ${devicesCPI.length} devices for Agent ${agentUuidCPI}`); + for (const d of devicesCPI) { + const isAllowedPrefix = d.ip_address.startsWith('10.250.') || + d.ip_address.startsWith('192.168.') || + d.ip_address.startsWith('10.121.'); + const isAllowedMac = [ + '2c:7b:a0:d8:86:91', '16:11:ac:73:34:1d', 'bc:45:5b:ca:d5:be', + 'de:ed:cc:57:58:34', 'f4:6d:3f:ef:01:a0', '60:be:b4:29:d3:36', + '70:85:6c:81:50:d4', '70:85:6c:6d:f7:17', '60:be:b4:29:d3:33', + '60:be:b4:26:4c:d6', '60:be:b4:29:d3:32' + ].includes(d.mac_address); + + if (!isAllowedPrefix && !isAllowedMac) { + throw new Error(`Non-agent device IP ${d.ip_address} / MAC ${d.mac_address} found in CPI Agent view`); + } + } + console.log('- Verified all returned devices belong to CPI agent\'s subnets or MAC array'); + + // Test 4: Agent View (JRP Cibubur / Kantor SIAB) + console.log('\nRunning Test 4: Agent View (2F-TF-1D-GK)...'); + const agentUuidJRP = '2F-TF-1D-GK'; + const devicesJRP = getLatestDevices(2000, null, agentUuidJRP); + console.log(`- Retrieved ${devicesJRP.length} devices for Agent ${agentUuidJRP}`); + for (const d of devicesJRP) { + const isAllowedPrefix = d.ip_address.startsWith('10.0.') || + d.ip_address.startsWith('10.1.') || + d.ip_address.startsWith('10.26.') || + d.ip_address.startsWith('10.43.') || + d.ip_address.startsWith('10.35.') || + d.ip_address.startsWith('10.21.') || + d.ip_address.startsWith('10.7.') || + d.ip_address.startsWith('10.182.') || + d.ip_address.startsWith('10.109.') || + d.ip_address.startsWith('10.181.') || + d.ip_address.startsWith('10.75.') || + d.ip_address.startsWith('10.202.') || + d.ip_address.startsWith('10.93.'); + const isAllowedMac = ['60:be:b4:1f:05:96'].includes(d.mac_address); + + if (!isAllowedPrefix && !isAllowedMac) { + throw new Error(`Non-agent device IP ${d.ip_address} / MAC ${d.mac_address} found in JRP Agent view`); + } + } + console.log('- Verified all returned devices belong to JRP agent\'s subnets or MAC array'); + console.log('\n=== ALL TESTS PASSED SUCCESSFULLY! ==='); }