mirror of
https://github.com/smittix/intercept.git
synced 2026-04-24 22:59:59 -07:00
- Extract signal-timeline into configurable activity-timeline.js - Add visual modes: compact, enriched, summary - Create data adapters for RF, Bluetooth, WiFi normalization - Integrate timeline into Listening Post, Bluetooth, WiFi modes - Preserve backward compatibility for existing TSCM code - Add mode-specific configuration presets via adapters Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
320 lines
9.9 KiB
JavaScript
320 lines
9.9 KiB
JavaScript
/**
|
|
* WiFi Timeline Adapter
|
|
* Normalizes WiFi network data for the Activity Timeline component
|
|
* Used by: WiFi mode, TSCM (WiFi detections)
|
|
*/
|
|
|
|
const WiFiTimelineAdapter = (function() {
|
|
'use strict';
|
|
|
|
/**
|
|
* RSSI to strength category mapping for WiFi
|
|
*/
|
|
const RSSI_THRESHOLDS = {
|
|
EXCELLENT: -50, // 5 - excellent signal
|
|
GOOD: -60, // 4 - good signal
|
|
FAIR: -70, // 3 - fair signal
|
|
WEAK: -80, // 2 - weak signal
|
|
POOR: -90 // 1 - very weak
|
|
};
|
|
|
|
/**
|
|
* WiFi channel to frequency band mapping
|
|
*/
|
|
const CHANNEL_BANDS = {
|
|
// 2.4 GHz (channels 1-14)
|
|
'2.4GHz': { min: 1, max: 14 },
|
|
// 5 GHz (channels 32-177)
|
|
'5GHz': { min: 32, max: 177 },
|
|
// 6 GHz (channels 1-233, WiFi 6E)
|
|
'6GHz': { min: 1, max: 233, is6e: true }
|
|
};
|
|
|
|
/**
|
|
* Security type classifications
|
|
*/
|
|
const SECURITY_TYPES = {
|
|
OPEN: 'open',
|
|
WEP: 'wep',
|
|
WPA: 'wpa',
|
|
WPA2: 'wpa2',
|
|
WPA3: 'wpa3',
|
|
ENTERPRISE: 'enterprise'
|
|
};
|
|
|
|
/**
|
|
* Convert RSSI to strength category
|
|
*/
|
|
function rssiToStrength(rssi) {
|
|
if (rssi === null || rssi === undefined) return 3;
|
|
|
|
const r = parseFloat(rssi);
|
|
if (isNaN(r)) return 3;
|
|
|
|
if (r > RSSI_THRESHOLDS.EXCELLENT) return 5;
|
|
if (r > RSSI_THRESHOLDS.GOOD) return 4;
|
|
if (r > RSSI_THRESHOLDS.FAIR) return 3;
|
|
if (r > RSSI_THRESHOLDS.WEAK) return 2;
|
|
return 1;
|
|
}
|
|
|
|
/**
|
|
* Determine frequency band from channel
|
|
*/
|
|
function getBandFromChannel(channel, frequency) {
|
|
if (frequency) {
|
|
const f = parseFloat(frequency);
|
|
if (f >= 5925) return '6GHz';
|
|
if (f >= 5000) return '5GHz';
|
|
if (f >= 2400) return '2.4GHz';
|
|
}
|
|
|
|
const ch = parseInt(channel);
|
|
if (isNaN(ch)) return 'unknown';
|
|
|
|
// This is simplified - in practice 6GHz also uses channels 1+
|
|
// but typically reported with frequency
|
|
if (ch <= 14) return '2.4GHz';
|
|
if (ch >= 32 && ch <= 177) return '5GHz';
|
|
|
|
return 'unknown';
|
|
}
|
|
|
|
/**
|
|
* Classify security type
|
|
*/
|
|
function classifySecurity(network) {
|
|
const security = (network.security || network.encryption || '').toLowerCase();
|
|
const auth = (network.auth || '').toLowerCase();
|
|
|
|
if (!security || security === 'none' || security === 'open') {
|
|
return SECURITY_TYPES.OPEN;
|
|
}
|
|
if (security.includes('wep')) return SECURITY_TYPES.WEP;
|
|
if (security.includes('wpa3')) return SECURITY_TYPES.WPA3;
|
|
if (security.includes('wpa2') || security.includes('rsn')) {
|
|
if (auth.includes('eap') || auth.includes('802.1x') || auth.includes('enterprise')) {
|
|
return SECURITY_TYPES.ENTERPRISE;
|
|
}
|
|
return SECURITY_TYPES.WPA2;
|
|
}
|
|
if (security.includes('wpa')) return SECURITY_TYPES.WPA;
|
|
|
|
return 'unknown';
|
|
}
|
|
|
|
/**
|
|
* Truncate SSID for display
|
|
*/
|
|
function formatSsid(ssid, maxLength = 20) {
|
|
if (!ssid) return '[Hidden]';
|
|
if (ssid.length <= maxLength) return ssid;
|
|
return ssid.substring(0, maxLength - 3) + '...';
|
|
}
|
|
|
|
/**
|
|
* Identify potentially interesting network characteristics
|
|
*/
|
|
function identifyCharacteristics(network) {
|
|
const characteristics = [];
|
|
const ssid = (network.ssid || '').toLowerCase();
|
|
|
|
// Hidden network
|
|
if (!network.ssid || network.is_hidden) {
|
|
characteristics.push('hidden');
|
|
}
|
|
|
|
// Open network
|
|
if (classifySecurity(network) === SECURITY_TYPES.OPEN) {
|
|
characteristics.push('open');
|
|
}
|
|
|
|
// Weak security
|
|
if (classifySecurity(network) === SECURITY_TYPES.WEP) {
|
|
characteristics.push('weak-security');
|
|
}
|
|
|
|
// Potential hotspot
|
|
if (/hotspot|mobile|tether|android|iphone/i.test(ssid)) {
|
|
characteristics.push('hotspot');
|
|
}
|
|
|
|
// Guest network
|
|
if (/guest|visitor|public/i.test(ssid)) {
|
|
characteristics.push('guest');
|
|
}
|
|
|
|
// IoT device
|
|
if (/ring|nest|ecobee|smartthings|wyze|arlo|hue|lifx/i.test(ssid)) {
|
|
characteristics.push('iot');
|
|
}
|
|
|
|
return characteristics;
|
|
}
|
|
|
|
/**
|
|
* Normalize a WiFi network detection for the timeline
|
|
*/
|
|
function normalizeNetwork(network) {
|
|
const ssid = network.ssid || network.essid || '';
|
|
const bssid = network.bssid || network.mac || '';
|
|
const band = getBandFromChannel(network.channel, network.frequency);
|
|
const security = classifySecurity(network);
|
|
const characteristics = identifyCharacteristics(network);
|
|
|
|
const tags = [band, security, ...characteristics];
|
|
|
|
return {
|
|
id: bssid || ssid,
|
|
label: formatSsid(ssid) || formatMac(bssid),
|
|
strength: rssiToStrength(network.rssi || network.signal),
|
|
duration: network.duration || 1000,
|
|
type: 'wifi',
|
|
tags: tags.filter(Boolean),
|
|
metadata: {
|
|
ssid: ssid,
|
|
bssid: bssid,
|
|
channel: network.channel,
|
|
frequency: network.frequency,
|
|
rssi: network.rssi || network.signal,
|
|
security: security,
|
|
band: band,
|
|
characteristics: characteristics
|
|
}
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Normalize for TSCM context
|
|
*/
|
|
function normalizeTscmNetwork(network) {
|
|
const normalized = normalizeNetwork(network);
|
|
|
|
// Add TSCM-specific tags
|
|
if (network.is_new) normalized.tags.push('new');
|
|
if (network.threat_level) normalized.tags.push(`threat-${network.threat_level}`);
|
|
if (network.is_rogue) normalized.tags.push('rogue');
|
|
if (network.is_deauth_target) normalized.tags.push('targeted');
|
|
|
|
normalized.metadata.threat_level = network.threat_level;
|
|
normalized.metadata.first_seen = network.first_seen;
|
|
normalized.metadata.client_count = network.client_count;
|
|
|
|
return normalized;
|
|
}
|
|
|
|
/**
|
|
* Format MAC/BSSID for display
|
|
*/
|
|
function formatMac(mac) {
|
|
if (!mac) return 'Unknown';
|
|
return mac.toUpperCase();
|
|
}
|
|
|
|
/**
|
|
* Batch normalize multiple networks
|
|
*/
|
|
function normalizeNetworks(networks, context = 'scan') {
|
|
const normalizer = context === 'tscm' ? normalizeTscmNetwork : normalizeNetwork;
|
|
return networks.map(normalizer);
|
|
}
|
|
|
|
/**
|
|
* Create timeline configuration for WiFi mode
|
|
*/
|
|
function getWiFiConfig() {
|
|
return {
|
|
title: 'Network Activity',
|
|
mode: 'wifi',
|
|
visualMode: 'enriched',
|
|
collapsed: false,
|
|
showAnnotations: true,
|
|
showLegend: true,
|
|
defaultWindow: '15m',
|
|
availableWindows: ['5m', '15m', '30m', '1h'],
|
|
filters: {
|
|
hideBaseline: { enabled: true, label: 'Hide Known', default: false },
|
|
showOnlyNew: { enabled: true, label: 'New Only', default: false },
|
|
showOnlyBurst: { enabled: false, label: 'Bursts', default: false }
|
|
},
|
|
customFilters: [
|
|
{
|
|
key: 'showOnlyOpen',
|
|
label: 'Open Only',
|
|
default: false,
|
|
predicate: (item) => item.tags.includes('open')
|
|
},
|
|
{
|
|
key: 'hideHidden',
|
|
label: 'Hide Hidden',
|
|
default: false,
|
|
predicate: (item) => !item.tags.includes('hidden')
|
|
},
|
|
{
|
|
key: 'show5GHz',
|
|
label: '5GHz Only',
|
|
default: false,
|
|
predicate: (item) => item.tags.includes('5GHz')
|
|
}
|
|
],
|
|
maxItems: 100,
|
|
maxDisplayedLanes: 15,
|
|
labelGenerator: (id) => formatSsid(id)
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Create compact configuration for sidebar
|
|
*/
|
|
function getCompactConfig() {
|
|
return {
|
|
title: 'Networks',
|
|
mode: 'wifi',
|
|
visualMode: 'compact',
|
|
collapsed: false,
|
|
showAnnotations: false,
|
|
showLegend: false,
|
|
defaultWindow: '15m',
|
|
availableWindows: ['5m', '15m', '30m'],
|
|
filters: {
|
|
hideBaseline: { enabled: false },
|
|
showOnlyNew: { enabled: true, label: 'New', default: false },
|
|
showOnlyBurst: { enabled: false }
|
|
},
|
|
customFilters: [],
|
|
maxItems: 30,
|
|
maxDisplayedLanes: 8
|
|
};
|
|
}
|
|
|
|
// Public API
|
|
return {
|
|
// Normalization
|
|
normalizeNetwork: normalizeNetwork,
|
|
normalizeTscmNetwork: normalizeTscmNetwork,
|
|
normalizeNetworks: normalizeNetworks,
|
|
|
|
// Utilities
|
|
rssiToStrength: rssiToStrength,
|
|
getBandFromChannel: getBandFromChannel,
|
|
classifySecurity: classifySecurity,
|
|
formatSsid: formatSsid,
|
|
identifyCharacteristics: identifyCharacteristics,
|
|
|
|
// Configuration presets
|
|
getWiFiConfig: getWiFiConfig,
|
|
getCompactConfig: getCompactConfig,
|
|
|
|
// Constants
|
|
RSSI_THRESHOLDS: RSSI_THRESHOLDS,
|
|
SECURITY_TYPES: SECURITY_TYPES
|
|
};
|
|
})();
|
|
|
|
// Export for module systems
|
|
if (typeof module !== 'undefined' && module.exports) {
|
|
module.exports = WiFiTimelineAdapter;
|
|
}
|
|
|
|
window.WiFiTimelineAdapter = WiFiTimelineAdapter;
|