Continuously synchronize counts so displays remain fresh even without web clients
(interval=SYNC_BACKGROUND_INTERVAL)
| 14791 | if key not in seen: |
| 14792 | seen.add(key) |
| 14793 | findings.append({ |
| 14794 | 'type': name, |
| 14795 | 'severity': severity, |
| 14796 | 'ssid': ssid, |
| 14797 | 'bssid': bssid, |
| 14798 | 'signal': signal, |
| 14799 | 'description': desc |
| 14800 | }) |
| 14801 | break |
| 14802 | |
| 14803 | # 3. Suspicious OUI (ESP32/Pi broadcasting as AP) |
| 14804 | oui = bssid[:8] |
| 14805 | if oui in _SUSPICIOUS_AP_OUIS: |
| 14806 | vendor = _SUSPICIOUS_AP_OUIS[oui] |
| 14807 | key = f'sus_oui_{bssid}' |
| 14808 | if key not in seen: |
| 14809 | seen.add(key) |
| 14810 | findings.append({ |
| 14811 | 'type': f'Suspicious {vendor} AP', |
| 14812 | 'severity': 'low', |
| 14813 | 'ssid': ssid, |
| 14814 | 'bssid': bssid, |
| 14815 | 'signal': signal, |
| 14816 | 'description': f'{vendor} device broadcasting as access point — may be rogue' |
| 14817 | }) |
| 14818 | |
| 14819 | # 4. Open network with enticing name |
| 14820 | if security and 'open' in security.lower() and not security.strip().startswith('WPA'): |
| 14821 | if any(w in ssid.lower() for w in ['free', 'guest', 'open', 'public', 'wifi']): |
| 14822 | key = f'open_honey_{bssid}' |
| 14823 | if key not in seen: |
| 14824 | seen.add(key) |
| 14825 | findings.append({ |