From 72425430170980ebf4c6f096939d782b581f5638 Mon Sep 17 00:00:00 2001 From: Stefan Kremser Date: Fri, 12 Oct 2018 13:41:26 +0200 Subject: [PATCH] New string functions & better seperation of display functions --- esp8266_deauther/Accesspoints.cpp | 18 +- esp8266_deauther/Accesspoints.h | 2 +- esp8266_deauther/DisplayUI.cpp | 1720 +++++++++++++++-------------- esp8266_deauther/DisplayUI.h | 24 +- esp8266_deauther/Names.cpp | 14 +- esp8266_deauther/Names.h | 208 ++-- esp8266_deauther/SSIDs.cpp | 6 +- esp8266_deauther/SSIDs.h | 174 +-- esp8266_deauther/Scan.cpp | 869 ++++++++------- esp8266_deauther/Scan.h | 197 ++-- esp8266_deauther/Stations.cpp | 18 +- esp8266_deauther/functions.h | 1537 +++++++++++++------------- esp8266_deauther/language.h | 22 +- 13 files changed, 2452 insertions(+), 2357 deletions(-) diff --git a/esp8266_deauther/Accesspoints.cpp b/esp8266_deauther/Accesspoints.cpp index 132dcd2..c9aa389 100644 --- a/esp8266_deauther/Accesspoints.cpp +++ b/esp8266_deauther/Accesspoints.cpp @@ -68,15 +68,15 @@ void Accesspoints::print(int num, bool header, bool footer) { prntln(AP_TABLE_HEADER); prntln(AP_TABLE_DIVIDER); } - prnt(buildString(String(), (String)num, 2)); - prnt(buildString(String(SPACE) + getSSID(num), String(), 33)); - prnt(buildString(String(SPACE) + getNameStr(num), String(), 17)); - prnt(buildString(String(SPACE), (String)getCh(num), 3)); - prnt(buildString(String(SPACE), (String)getRSSI(num), 5)); - prnt(buildString(String(SPACE), getEncStr(num), 5)); - prnt(buildString(String(SPACE) + getMacStr(num), String(), 18)); - prnt(buildString(String(SPACE) + getVendorStr(num), String(), 9)); - prntln(buildString(String(SPACE) + getSelectedStr(num), String(), 9)); + prnt(leftRight(String(), (String)num, 2)); + prnt(leftRight(String(SPACE) + getSSID(num), String(), 33)); + prnt(leftRight(String(SPACE) + getNameStr(num), String(), 17)); + prnt(leftRight(String(SPACE), (String)getCh(num), 3)); + prnt(leftRight(String(SPACE), (String)getRSSI(num), 5)); + prnt(leftRight(String(SPACE), getEncStr(num), 5)); + prnt(leftRight(String(SPACE) + getMacStr(num), String(), 18)); + prnt(leftRight(String(SPACE) + getVendorStr(num), String(), 9)); + prntln(leftRight(String(SPACE) + getSelectedStr(num), String(), 9)); if (footer) { prntln(AP_TABLE_DIVIDER); diff --git a/esp8266_deauther/Accesspoints.h b/esp8266_deauther/Accesspoints.h index d59cfee..fca2ffa 100644 --- a/esp8266_deauther/Accesspoints.h +++ b/esp8266_deauther/Accesspoints.h @@ -13,7 +13,7 @@ extern "C" { extern Names names; extern String searchVendor(uint8_t* mac); -extern String buildString(String left, String right, int maxLen); +extern String leftRight(String a, String b, int len); extern String fixUtf8(String str); extern String bytesToStr(uint8_t* b, uint32_t size); diff --git a/esp8266_deauther/DisplayUI.cpp b/esp8266_deauther/DisplayUI.cpp index db30596..835d3bd 100644 --- a/esp8266_deauther/DisplayUI.cpp +++ b/esp8266_deauther/DisplayUI.cpp @@ -3,23 +3,7 @@ DisplayUI::DisplayUI() {} void DisplayUI::setupDisplay() { - // ===== adjustable ===== // - // initialize display - display.init(); - - /* - In case of a compiler (conversion char/uint8_t) error, - make sure to have version 4 of the display library installed - https://github.com/ThingPulse/esp8266-oled-ssd1306/releases/tag/4.0.0 - */ - display.setFont(DejaVu_Sans_Mono_12); - display.setContrast(255); -#ifndef FLIP_DIPLAY - display.flipScreenVertically(); -#endif // ifndef FLIP_DIPLAY - display.clear(); - display.display(); - // ====================== // + configInit(); } #ifdef HIGHLIGHT_LED @@ -30,918 +14,944 @@ void DisplayUI::setupLED() { } #endif -void DisplayUI::on() { - // ===== adjustable ===== // - if (enabled) { - display.displayOn(); - mode = SCREEN_MODE_MENU; - buttonUp.time = currentTime; // update a button time to keep display on - prntln(D_MSG_DISPLAY_ON); - } else { - prntln(D_ERROR_NOT_ENABLED); - } - // ====================== // + +// ===== adjustable ===== // +void DisplayUI::configInit() { + // initialize display + display.init(); + + /* + In case of a compiler (conversion char/uint8_t) error, + make sure to have version 4 of the display library installed + https://github.com/ThingPulse/esp8266-oled-ssd1306/releases/tag/4.0.0 + */ + display.setFont(DejaVu_Sans_Mono_12); + + display.setContrast(255); + +#ifndef FLIP_DIPLAY + display.flipScreenVertically(); +#endif // ifndef FLIP_DIPLAY + + display.clear(); + display.display(); } -void DisplayUI::off() { - // ===== adjustable ===== // - if (enabled) { - display.displayOff(); - mode = SCREEN_MODE_OFF; - prntln(D_MSG_DISPLAY_OFF); - } else { - prntln(D_ERROR_NOT_ENABLED); - } - // ====================== // +void DisplayUI::configOn() { + display.displayOn(); } -void DisplayUI::setupButtons() { - // ===== adjustable ===== // - -#ifdef BUTTON_UP - buttonUp.enabled = true; - buttonUp.gpio = BUTTON_UP; -#else // ifdef BUTTON_UP - buttonUp.enabled = false; -#endif // ifdef BUTTON_UP - -#ifdef BUTTON_DOWN - buttonDown.enabled = true; - buttonDown.gpio = BUTTON_DOWN; -#else // ifdef BUTTON_DOWN - buttonDown.enabled = false; -#endif // ifdef BUTTON_DOWN - -#ifdef BUTTON_LEFT - buttonLeft.enabled = true; - buttonLeft.gpio = BUTTON_LEFT; -#else // ifdef BUTTON_LEFT - buttonLeft.enabled = false; -#endif // ifdef BUTTON_LEFT - -#ifdef BUTTON_RIGHT - buttonRight.enabled = true; - buttonRight.gpio = BUTTON_RIGHT; -#else // ifdef BUTTON_RIGHT - buttonRight.enabled = false; -#endif // ifdef BUTTON_RIGHT - -#ifdef BUTTON_A - buttonA.enabled = true; - buttonA.gpio = BUTTON_A; -#else // ifdef BUTTON_A - buttonA.enabled = false; -#endif // ifdef BUTTON_A - -#ifdef BUTTON_B - buttonB.enabled = true; - buttonB.gpio = BUTTON_B; -#else // ifdef BUTTON_B - buttonB.enabled = false; -#endif // ifdef BUTTON_B - - // ====================== // - // setup and read functions - // ====================== // - buttonUp.setup = [this]() { - if (buttonUp.gpio != 2) pinMode(buttonUp.gpio, INPUT_PULLUP); - buttonUp.time = currentTime; - }; - buttonUp.read = [this]() { - return !digitalRead(buttonUp.gpio); - }; - - buttonDown.setup = [this]() { - if (buttonDown.gpio != 2) pinMode(buttonDown.gpio, INPUT_PULLUP); - buttonDown.time = currentTime; - }; - buttonDown.read = [this]() { - return !digitalRead(buttonDown.gpio); - }; - - buttonLeft.setup = [this]() { - if (buttonLeft.gpio != 2) pinMode(buttonLeft.gpio, INPUT_PULLUP); - buttonLeft.time = currentTime; - }; - buttonLeft.read = [this]() { - return !digitalRead(buttonLeft.gpio); - }; - - buttonRight.setup = [this]() { - if (buttonRight.gpio != 2) pinMode(buttonRight.gpio, INPUT_PULLUP); - buttonRight.time = currentTime; - }; - buttonRight.read = [this]() { - return !digitalRead(buttonRight.gpio); - }; - - buttonA.setup = [this]() { - if (buttonA.gpio != 2) pinMode(buttonA.gpio, INPUT_PULLUP); - buttonA.time = currentTime; - }; - buttonA.read = [this]() { - return !digitalRead(buttonA.gpio); - }; - - buttonB.setup = [this]() { - if (buttonB.gpio != 2) pinMode(buttonB.gpio, INPUT_PULLUP); - buttonB.time = currentTime; - }; - buttonB.read = [this]() { - return !digitalRead(buttonB.gpio); - }; - - // ====================== // +void DisplayUI::configOff() { + display.displayOff(); } -void DisplayUI::setup() { - setupDisplay(); - setupButtons(); - - // ===== PUSH AND RELEASE FUNCTIONS ===== // - - // === BUTTON UP === // - buttonUp.push = [this]() { - if (buttonUp.time > currentTime - BUTTON_DELAY) return; - - buttonUp.pushed = true; - buttonUp.time = currentTime; - scrollCounter = 0; - - if (mode == SCREEN_MODE_MENU) { // when in menu, go up or down with cursor - if (currentMenu->selected > 0) currentMenu->selected--; - else currentMenu->selected = currentMenu->list->size() - 1; - } else if (mode == SCREEN_MODE_PACKETMONITOR) { // when in packet monitor, change channel - scan.setChannel(wifi_channel + 1); - } - }; - - buttonUp.release = [this]() { - if (!buttonUp.pushed) return; - - buttonUp.pushed = false; - }; - - // === BUTTON DOWN === // - buttonDown.push = [this]() { - if (buttonDown.time > currentTime - BUTTON_DELAY) return; - - buttonDown.pushed = true; - buttonDown.time = currentTime; - scrollCounter = 0; - - if (mode == SCREEN_MODE_MENU) { // when in menu, go up or down with cursor - if (currentMenu->selected < currentMenu->list->size() - 1) currentMenu->selected++; - else currentMenu->selected = 0; - } else if (mode == SCREEN_MODE_PACKETMONITOR) { // when in packet monitor, change channel - scan.setChannel(wifi_channel - 1); - } - }; - - buttonDown.release = [this]() { - if (!buttonDown.pushed) return; - - buttonDown.pushed = false; - }; - - // === BUTTON LEFT === // - buttonLeft.push = [this]() { - if (buttonLeft.time > currentTime - BUTTON_DELAY) return; - - buttonLeft.pushed = true; - buttonLeft.time = currentTime; - scrollCounter = 0; - }; - - buttonLeft.release = [this]() { - if (!buttonLeft.pushed) return; - - buttonLeft.pushed = false; - }; - - // === BUTTON RIGHT === // - buttonRight.push = [this]() { - if (buttonRight.time > currentTime - BUTTON_DELAY) return; - - buttonRight.pushed = true; - buttonRight.time = currentTime; - scrollCounter = 0; - }; - - buttonRight.release = [this]() { - if (!buttonRight.pushed) return; - - buttonRight.pushed = false; - }; - - // === BUTTON A === // - buttonA.push = [this]() { - if (!buttonA.pushed) { // first push - buttonA.pushed = true; - buttonA.time = currentTime; - scrollCounter = 0; - } else { // holding button - if ((currentTime - buttonA.time > 800) && !buttonA.hold) { - if (currentMenu->list->get(currentMenu->selected).hold) currentMenu->list->get( - currentMenu->selected).hold(); - buttonA.hold = true; - } - } - }; - - buttonA.release = [this]() { - if (!buttonA.pushed) return; // exit when button wasn't pushed before - - if (!buttonA.hold && (currentTime - buttonA.time > 80)) { - switch (mode) { - case SCREEN_MODE_MENU: - - if (currentMenu->list->get(currentMenu->selected).click) { - currentMenu->list->get(currentMenu->selected).click(); - } - break; - - case SCREEN_MODE_PACKETMONITOR: - case SCREEN_MODE_LOADSCAN: - scan.stop(); - mode = SCREEN_MODE_MENU; - break; - } - } - - buttonA.pushed = false; - buttonA.hold = false; - }; - - // === BUTTON B === // - buttonB.push = [this]() { - if (!buttonB.pushed && (buttonB.time > currentTime - BUTTON_DELAY)) return; - - buttonB.pushed = true; - buttonB.time = currentTime; - scrollCounter = 0; - }; - - buttonB.release = [this]() { - if (!buttonB.pushed) return; - - switch (mode) { - case SCREEN_MODE_MENU: - goBack(); - break; - - case SCREEN_MODE_PACKETMONITOR: - case SCREEN_MODE_LOADSCAN: - scan.stop(); - mode = SCREEN_MODE_MENU; - break; - } - - buttonB.pushed = false; - }; - - // === RUN SETUPS === // - // setting pin modes for buttons - if (buttonUp.enabled && buttonUp.setup) buttonUp.setup(); - - if (buttonDown.enabled && buttonDown.setup) buttonDown.setup(); - - if (buttonLeft.enabled && buttonLeft.setup) buttonLeft.setup(); - - if (buttonRight.enabled && buttonRight.setup) buttonRight.setup(); - - if (buttonA.enabled && buttonA.setup) buttonA.setup(); - - if (buttonB.enabled && buttonB.setup) buttonB.setup(); - - // ===== MENUS ===== // - - // MAIN MENU - createMenu(&mainMenu, NULL, [this]() { - addMenuNode(&mainMenu, D_SCAN, &scanMenu); /// SCAN - addMenuNode(&mainMenu, D_SHOW, &showMenu); // SHOW - addMenuNode(&mainMenu, D_ATTACK, &attackMenu); // ATTACK - addMenuNode(&mainMenu, D_PACKET_MONITOR, [this]() { // PACKET MONITOR - scan.start(SCAN_MODE_SNIFFER, 0, SCAN_MODE_OFF, 0, false, wifi_channel); - mode = SCREEN_MODE_PACKETMONITOR; - }); -#ifdef HIGHLIGHT_LED - addMenuNode(&mainMenu, D_LED, [this]() { // LED - highlightLED = !highlightLED; - digitalWrite(HIGHLIGHT_LED, highlightLED); - }); -#endif - }); - - // SCAN MENU - createMenu(&scanMenu, &mainMenu, [this]() { - addMenuNode(&scanMenu, D_SCAN_APST, [this]() { // SCAN AP + ST - scan.start(SCAN_MODE_ALL, 15000, SCAN_MODE_OFF, 0, true, wifi_channel); - mode = SCREEN_MODE_LOADSCAN; - }); - addMenuNode(&scanMenu, D_SCAN_AP, [this]() { // SCAN AP - scan.start(SCAN_MODE_APS, 0, SCAN_MODE_OFF, 0, true, wifi_channel); - mode = SCREEN_MODE_LOADSCAN; - }); - addMenuNode(&scanMenu, D_SCAN_ST, [this]() { // SCAN ST - scan.start(SCAN_MODE_STATIONS, 30000, SCAN_MODE_OFF, 0, true, wifi_channel); - mode = SCREEN_MODE_LOADSCAN; - }); - }); - - // SHOW MENU - createMenu(&showMenu, &mainMenu, [this]() { - addMenuNode(&showMenu, []() { // Accesspoints 0 [0] - return buildString(str(D_ACCESSPOINTS), (String)accesspoints.count(), CHARS_PER_LINE); - }, &apListMenu); - addMenuNode(&showMenu, []() { // Stations 0 [0] - return buildString(str(D_STATIONS), (String)stations.count(), CHARS_PER_LINE); - }, &stationListMenu); - addMenuNode(&showMenu, []() { // Names 0 [0] - return buildString(str(D_NAMES), (String)names.count(), CHARS_PER_LINE); - }, &nameListMenu); - addMenuNode(&showMenu, []() { // SSIDs 0 - return buildString(str(D_SSIDS), (String)ssids.count(), CHARS_PER_LINE); - }, &ssidListMenu); - }); - - // AP LIST MENU - createMenu(&apListMenu, &showMenu, [this]() { - // add APs to list - int c = accesspoints.count(); - - for (int i = 0; i < c; i++) { - addMenuNode(&apListMenu, [i]() { - return b2a(accesspoints.getSelected(i)) + accesspoints.getSSID(i); - }, [this, i]() { - accesspoints.getSelected(i) ? accesspoints.deselect(i) : accesspoints.select(i); - }, [this, i]() { - selectedID = i; - changeMenu(&apMenu); - }); - } - addMenuNode(&apListMenu, D_SELECT_ALL, [this]() { // SELECT ALL - accesspoints.selectAll(); - changeMenu(&apListMenu); - }); - addMenuNode(&apListMenu, D_DESELECT_ALL, [this]() { // DESELECT ALL - accesspoints.deselectAll(); - changeMenu(&apListMenu); - }); - addMenuNode(&apListMenu, D_REMOVE_ALL, [this]() { // REMOVE ALL - accesspoints.removeAll(); - goBack(); - }); - }); - - // STATION LIST MENU - createMenu(&stationListMenu, &showMenu, [this]() { - // add stations to list - int c = stations.count(); - - for (int i = 0; i < c; i++) { - addMenuNode(&stationListMenu, [i]() { - return b2a(stations.getSelected(i)) + - (stations.hasName(i) ? stations.getNameStr(i) : stations.getMacVendorStr(i)); - }, [this, i]() { - stations.getSelected(i) ? stations.deselect(i) : stations.select(i); - }, [this, i]() { - selectedID = i; - changeMenu(&stationMenu); - }); - } - - addMenuNode(&stationListMenu, D_SELECT_ALL, [this]() { // SELECT ALL - stations.selectAll(); - changeMenu(&stationListMenu); - }); - addMenuNode(&stationListMenu, D_DESELECT_ALL, [this]() { // DESELECT ALL - stations.deselectAll(); - changeMenu(&stationListMenu); - }); - addMenuNode(&stationListMenu, D_REMOVE_ALL, [this]() { // REMOVE ALL - stations.removeAll(); - goBack(); - }); - }); - - // NAME LIST MENU - createMenu(&nameListMenu, &showMenu, [this]() { - // add device names to list - int c = names.count(); - - for (int i = 0; i < c; i++) { - addMenuNode(&nameListMenu, [i]() { - return names.getSelectedStr(i) + names.getName(i); - }, [this, i]() { - names.getSelected(i) ? names.deselect(i) : names.select(i); - }, [this, i]() { - selectedID = i; - changeMenu(&nameMenu); - }); - } - addMenuNode(&nameListMenu, D_SELECT_ALL, [this]() { // SELECT ALL - names.selectAll(); - changeMenu(&nameListMenu); - }); - addMenuNode(&nameListMenu, D_DESELECT_ALL, [this]() { // DESELECT ALL - names.deselectAll(); - changeMenu(&nameListMenu); - }); - addMenuNode(&nameListMenu, D_REMOVE_ALL, [this]() { // REMOVE ALL - names.removeAll(); - goBack(); - }); - }); - - // SSID LIST MENU - createMenu(&ssidListMenu, &showMenu, [this]() { - addMenuNode(&ssidListMenu, D_CLONE_APS, [this]() { // CLONE APs - ssids.cloneSelected(true); - changeMenu(&ssidListMenu); - ssids.save(false); - }); - addMenuNode(&ssidListMenu, [this]() { - return b2a(ssids.getRandom()) + str(D_RANDOM_MODE); // *RANDOM MODE - }, [this]() { - if (ssids.getRandom()) ssids.disableRandom(); - else ssids.enableRandom(10); - changeMenu(&ssidListMenu); - }); - - // add ssids to list - int c = ssids.count(); - - for (int i = 0; i < c; i++) { - addMenuNode(&ssidListMenu, [i]() { - return ssids.getName(i).substring(0, ssids.getLen(i)); - }, [this, i]() { - selectedID = i; - changeMenu(&ssidMenu); - }, [this, i]() { - ssids.remove(i); - changeMenu(&ssidListMenu); - ssidListMenu.selected = i; - }); - } - - addMenuNode(&ssidListMenu, D_REMOVE_ALL, [this]() { // REMOVE ALL - ssids.removeAll(); - goBack(); - }); - }); - - // AP MENU - createMenu(&apMenu, &apListMenu, [this]() { - addMenuNode(&apMenu, [this]() { - return accesspoints.getSelectedStr(selectedID) + accesspoints.getSSID(selectedID); // * - }, [this]() { - accesspoints.getSelected(selectedID) ? accesspoints.deselect(selectedID) : accesspoints.select(selectedID); - }); - addMenuNode(&apMenu, [this]() { - return str(D_ENCRYPTION) + accesspoints.getEncStr(selectedID); - }, NULL); // Encryption: -/WPA2 - addMenuNode(&apMenu, [this]() { - return str(D_RSSI) + (String)accesspoints.getRSSI(selectedID); - }, NULL); // RSSI: -90 - addMenuNode(&apMenu, [this]() { - return str(D_CHANNEL) + (String)accesspoints.getCh(selectedID); - }, NULL); // Channel: 11 - addMenuNode(&apMenu, [this]() { - return accesspoints.getMacStr(selectedID); - }, NULL); // 00:11:22:00:11:22 - addMenuNode(&apMenu, [this]() { - return str(D_VENDOR) + accesspoints.getVendorStr(selectedID); - }, NULL); // Vendor: INTEL - addMenuNode(&apMenu, [this]() { - return accesspoints.getSelected(selectedID) ? str(D_DESELECT) : str(D_SELECT); // SELECT/DESELECT - }, [this]() { - accesspoints.getSelected(selectedID) ? accesspoints.deselect(selectedID) : accesspoints.select(selectedID); - }); - addMenuNode(&apMenu, D_CLONE, [this]() { // CLONE - ssids.add(accesspoints.getSSID(selectedID), accesspoints.getEnc(selectedID) != ENC_TYPE_NONE, 60, true); - changeMenu(&showMenu); - ssids.save(false); - }); - addMenuNode(&apMenu, D_REMOVE, [this]() { // REMOVE - accesspoints.remove(selectedID); - apListMenu.list->remove(apListMenu.selected); - goBack(); - }); - }); - - // STATION MENU - createMenu(&stationMenu, &stationListMenu, [this]() { - addMenuNode(&stationMenu, [this]() { - return stations.getSelectedStr(selectedID) + - (stations.hasName(selectedID) ? stations.getNameStr(selectedID) : stations.getMacVendorStr(selectedID)); // - }, [this]() { - stations.getSelected(selectedID) ? stations.deselect(selectedID) : stations.select(selectedID); - }); - addMenuNode(&stationMenu, [this]() { - return stations.getMacStr(selectedID); - }, NULL); // 00:11:22:00:11:22 - addMenuNode(&stationMenu, [this]() { - return str(D_VENDOR) + stations.getVendorStr(selectedID); - }, NULL); // Vendor: INTEL - addMenuNode(&stationMenu, [this]() { - return str(D_AP) + stations.getAPStr(selectedID); // AP: someAP - }, [this]() { - int apID = accesspoints.find(stations.getAP(selectedID)); - - if (apID >= 0) { - selectedID = apID; - changeMenu(&apMenu); - } - }); - addMenuNode(&stationMenu, [this]() { - return str(D_PKTS) + String(*stations.getPkts(selectedID)); - }, NULL); // Pkts: 12 - addMenuNode(&stationMenu, [this]() { - return str(D_CHANNEL) + String(stations.getCh(selectedID)); - }, NULL); // Channel: 11 - addMenuNode(&stationMenu, [this]() { - return str(D_SEEN) + stations.getTimeStr(selectedID); - }, NULL); // Seen: <1min - - addMenuNode(&stationMenu, [this]() { - return stations.getSelected(selectedID) ? str(D_DESELECT) : str(D_SELECT); // SELECT/DESELECT - }, [this]() { - stations.getSelected(selectedID) ? stations.deselect(selectedID) : stations.select(selectedID); - }); - addMenuNode(&stationMenu, D_REMOVE, [this]() { // REMOVE - stations.remove(selectedID); - stationListMenu.list->remove(stationListMenu.selected); - goBack(); - }); - }); - - // NAME MENU - createMenu(&nameMenu, &nameListMenu, [this]() { - addMenuNode(&nameMenu, [this]() { - return names.getSelectedStr(selectedID) + names.getName(selectedID); // - }, [this]() { - names.getSelected(selectedID) ? names.deselect(selectedID) : names.select(selectedID); - }); - addMenuNode(&nameMenu, [this]() { - return names.getMacStr(selectedID); - }, NULL); // 00:11:22:00:11:22 - addMenuNode(&nameMenu, [this]() { - return str(D_VENDOR) + names.getVendorStr(selectedID); - }, NULL); // Vendor: INTEL - addMenuNode(&nameMenu, [this]() { - return str(D_AP) + names.getBssidStr(selectedID); - }, NULL); // AP: 00:11:22:00:11:22 - addMenuNode(&nameMenu, [this]() { - return str(D_CHANNEL) + (String)names.getCh(selectedID); - }, NULL); // Channel: 11 - - addMenuNode(&nameMenu, [this]() { - return names.getSelected(selectedID) ? str(D_DESELECT) : str(D_SELECT); // SELECT/DESELECT - }, [this]() { - names.getSelected(selectedID) ? names.deselect(selectedID) : names.select(selectedID); - }); - addMenuNode(&nameMenu, D_REMOVE, [this]() { // REMOVE - names.remove(selectedID); - nameListMenu.list->remove(nameListMenu.selected); - goBack(); - }); - }); - - // SSID MENU - createMenu(&ssidMenu, &ssidListMenu, [this]() { - addMenuNode(&ssidMenu, [this]() { - return ssids.getName(selectedID).substring(0, ssids.getLen(selectedID)); - }, NULL); // SSID - addMenuNode(&ssidMenu, [this]() { - return str(D_ENCRYPTION) + ssids.getEncStr(selectedID); // WPA2 - }, [this]() { - ssids.setWPA2(selectedID, !ssids.getWPA2(selectedID)); - }); - addMenuNode(&ssidMenu, D_REMOVE, [this]() { // REMOVE - ssids.remove(selectedID); - ssidListMenu.list->remove(ssidListMenu.selected); - goBack(); - }); - }); - - // ATTACK MENU - createMenu(&attackMenu, &mainMenu, [this]() { - addMenuNode(&attackMenu, [this]() { // *DEAUTH 0/0 - if (attack.isRunning()) return buildString(b2a(deauthSelected) + str(D_DEAUTH), - (String)attack.getDeauthPkts() + SLASH + - (String)attack.getDeauthMaxPkts(), CHARS_PER_LINE); - else return buildString(b2a(deauthSelected) + str(D_DEAUTH), (String)scan.countSelected(), CHARS_PER_LINE); - }, [this]() { // deauth - deauthSelected = !deauthSelected; - - if (attack.isRunning()) { - attack.start(beaconSelected, deauthSelected, false, probeSelected, true, - settings.getAttackTimeout() * 1000); - } - }); - addMenuNode(&attackMenu, [this]() { // *BEACON 0/0 - if (attack.isRunning()) return buildString(b2a(beaconSelected) + str(D_BEACON), - (String)attack.getBeaconPkts() + SLASH + - (String)attack.getBeaconMaxPkts(), CHARS_PER_LINE); - else return buildString(b2a(beaconSelected) + str(D_BEACON), (String)ssids.count(), CHARS_PER_LINE); - }, [this]() { // beacon - beaconSelected = !beaconSelected; - - if (attack.isRunning()) { - attack.start(beaconSelected, deauthSelected, false, probeSelected, true, - settings.getAttackTimeout() * 1000); - } - }); - addMenuNode(&attackMenu, [this]() { // *PROBE 0/0 - if (attack.isRunning()) return buildString(b2a(probeSelected) + str(D_PROBE), - (String)attack.getProbePkts() + SLASH + - (String)attack.getProbeMaxPkts(), CHARS_PER_LINE); - else return buildString(b2a(probeSelected) + str(D_PROBE), (String)ssids.count(), CHARS_PER_LINE); - }, [this]() { // probe - probeSelected = !probeSelected; - - if (attack.isRunning()) { - attack.start(beaconSelected, deauthSelected, false, probeSelected, true, - settings.getAttackTimeout() * 1000); - } - }); - addMenuNode(&attackMenu, []() { // START - return buildString(str(attack.isRunning() ? D_STOP_ATTACK : D_START_ATTACK), - attack.getPacketRate() > 0 ? (String)attack.getPacketRate() : String(), CHARS_PER_LINE); - }, [this]() { - if (attack.isRunning()) attack.stop(); - else attack.start(beaconSelected, deauthSelected, false, probeSelected, true, - settings.getAttackTimeout() * 1000); - }); - }); - - // ===================== // - - // set current menu to main menu - changeMenu(&mainMenu); - enabled = true; - startTime = currentTime; +void DisplayUI::updatePrefix() { + display.clear(); // clear display + display.setTextAlignment(TEXT_ALIGN_LEFT); // reset text alignment just in case ;) } -void DisplayUI::update() { - if (!enabled) return; - - // when display is off - if (mode == SCREEN_MODE_OFF) { - if (updateButton(&buttonA)) { - on(); - buttonA.hold = true; // to make sure you don't double click - } - } - - else { - // timeout to save display life - if ((mode == SCREEN_MODE_MENU) && (settings.getDisplayTimeout() > 0) && - (currentTime > settings.getDisplayTimeout() * 1000)) { - uint32_t buttonTimeout = currentTime - settings.getDisplayTimeout() * 1000; - - if ((buttonUp.time < buttonTimeout) - && (buttonDown.time < buttonTimeout) - && (buttonLeft.time < buttonTimeout) - && (buttonRight.time < buttonTimeout) - && (buttonA.time < buttonTimeout) - && (buttonB.time < buttonTimeout)) { - off(); - } - } - - // only one button can be pressed at a time - if (updateButton(&buttonB)) draw(); - else if (updateButton(&buttonA)) draw(); - else if (updateButton(&buttonUp)) draw(); - else if (updateButton(&buttonDown)) draw(); - else if (updateButton(&buttonLeft)) draw(); - else if (updateButton(&buttonRight)) draw(); - else draw(); - } -} - -void DisplayUI::draw() { - if ((currentTime - drawTime > DRAW_INTERVAL) && currentMenu) { - drawTime = currentTime; - - // ===== adjustable ===== // - display.clear(); // clear display - display.setTextAlignment(TEXT_ALIGN_LEFT); // reset text alignment just in case ;) - // ====================== // - - switch (mode) { - case SCREEN_MODE_BUTTON_TEST: - drawButtonTest(); - break; - - case SCREEN_MODE_MENU: - drawMenu(); - break; - - case SCREEN_MODE_LOADSCAN: - drawLoadingScan(); - break; - - case SCREEN_MODE_PACKETMONITOR: - drawPacketMonitor(); - break; - - case SCREEN_MODE_INTRO: - - if (currentTime - startTime >= SCREEN_INTRO_TIME) { - mode = SCREEN_MODE_MENU; - } - drawIntro(); - break; - } - - // ===== adjustable ===== // - display.display(); // draw changes - // ====================== // - } +void DisplayUI::updateSuffix() { + display.display(); // draw changes } void DisplayUI::drawString(int x, int y, String str) { - // ===== adjustable ===== // - display.drawString(x, y, replaceUtf8(str, String(QUESTIONMARK))); - // ====================== // + display.drawString(x, y, replaceUtf8(str, String(QUESTIONMARK))); +} + +void DisplayUI::drawString(int row, String str) { + drawString(0, row * lineHeight, str); +} + +void DisplayUI::drawLine(int x1, int y1, int x2, int y2) { + display.drawLine(x1, y1, x2, y2); +} +// ====================== // + +void DisplayUI::on() { + if (enabled) { + configOn(); + mode = SCREEN_MODE_MENU; + buttonUp.time = currentTime; // update a button time to keep display on + prntln(D_MSG_DISPLAY_ON); + } else { + prntln(D_ERROR_NOT_ENABLED); + } +} + +void DisplayUI::off() { + if (enabled) { + configOff(); + mode = SCREEN_MODE_OFF; + prntln(D_MSG_DISPLAY_OFF); + } else { + prntln(D_ERROR_NOT_ENABLED); + } +} + +void DisplayUI::setupButtons() { +#ifdef BUTTON_UP + buttonUp.enabled = true; + buttonUp.gpio = BUTTON_UP; +#else // ifdef BUTTON_UP + buttonUp.enabled = false; +#endif // ifdef BUTTON_UP + +#ifdef BUTTON_DOWN + buttonDown.enabled = true; + buttonDown.gpio = BUTTON_DOWN; +#else // ifdef BUTTON_DOWN + buttonDown.enabled = false; +#endif // ifdef BUTTON_DOWN + +#ifdef BUTTON_LEFT + buttonLeft.enabled = true; + buttonLeft.gpio = BUTTON_LEFT; +#else // ifdef BUTTON_LEFT + buttonLeft.enabled = false; +#endif // ifdef BUTTON_LEFT + +#ifdef BUTTON_RIGHT + buttonRight.enabled = true; + buttonRight.gpio = BUTTON_RIGHT; +#else // ifdef BUTTON_RIGHT + buttonRight.enabled = false; +#endif // ifdef BUTTON_RIGHT + +#ifdef BUTTON_A + buttonA.enabled = true; + buttonA.gpio = BUTTON_A; +#else // ifdef BUTTON_A + buttonA.enabled = false; +#endif // ifdef BUTTON_A + +#ifdef BUTTON_B + buttonB.enabled = true; + buttonB.gpio = BUTTON_B; +#else // ifdef BUTTON_B + buttonB.enabled = false; +#endif // ifdef BUTTON_B + + // ====================== // + // setup and read functions + // ====================== // + buttonUp.setup = [this]() { + if (buttonUp.gpio != 2) pinMode(buttonUp.gpio, INPUT_PULLUP); + buttonUp.time = currentTime; + }; + buttonUp.read = [this]() { + return !digitalRead(buttonUp.gpio); + }; + + buttonDown.setup = [this]() { + if (buttonDown.gpio != 2) pinMode(buttonDown.gpio, INPUT_PULLUP); + buttonDown.time = currentTime; + }; + buttonDown.read = [this]() { + return !digitalRead(buttonDown.gpio); + }; + + buttonLeft.setup = [this]() { + if (buttonLeft.gpio != 2) pinMode(buttonLeft.gpio, INPUT_PULLUP); + buttonLeft.time = currentTime; + }; + buttonLeft.read = [this]() { + return !digitalRead(buttonLeft.gpio); + }; + + buttonRight.setup = [this]() { + if (buttonRight.gpio != 2) pinMode(buttonRight.gpio, INPUT_PULLUP); + buttonRight.time = currentTime; + }; + buttonRight.read = [this]() { + return !digitalRead(buttonRight.gpio); + }; + + buttonA.setup = [this]() { + if (buttonA.gpio != 2) pinMode(buttonA.gpio, INPUT_PULLUP); + buttonA.time = currentTime; + }; + buttonA.read = [this]() { + return !digitalRead(buttonA.gpio); + }; + + buttonB.setup = [this]() { + if (buttonB.gpio != 2) pinMode(buttonB.gpio, INPUT_PULLUP); + buttonB.time = currentTime; + }; + buttonB.read = [this]() { + return !digitalRead(buttonB.gpio); + }; +} + +void DisplayUI::setup() { + setupDisplay(); + setupButtons(); + + // ===== PUSH AND RELEASE FUNCTIONS ===== // + + // === BUTTON UP === // + buttonUp.push = [this]() { + if (buttonUp.time > currentTime - BUTTON_DELAY) return; + + buttonUp.pushed = true; + buttonUp.time = currentTime; + scrollCounter = 0; + + if (mode == SCREEN_MODE_MENU) { // when in menu, go up or down with cursor + if (currentMenu->selected > 0) currentMenu->selected--; + else currentMenu->selected = currentMenu->list->size() - 1; + } else if (mode == SCREEN_MODE_PACKETMONITOR) { // when in packet monitor, change channel + scan.setChannel(wifi_channel + 1); + } + }; + + buttonUp.release = [this]() { + if (!buttonUp.pushed) return; + + buttonUp.pushed = false; + }; + + // === BUTTON DOWN === // + buttonDown.push = [this]() { + if (buttonDown.time > currentTime - BUTTON_DELAY) return; + + buttonDown.pushed = true; + buttonDown.time = currentTime; + scrollCounter = 0; + + if (mode == SCREEN_MODE_MENU) { // when in menu, go up or down with cursor + if (currentMenu->selected < currentMenu->list->size() - 1) currentMenu->selected++; + else currentMenu->selected = 0; + } else if (mode == SCREEN_MODE_PACKETMONITOR) { // when in packet monitor, change channel + scan.setChannel(wifi_channel - 1); + } + }; + + buttonDown.release = [this]() { + if (!buttonDown.pushed) return; + + buttonDown.pushed = false; + }; + + // === BUTTON LEFT === // + buttonLeft.push = [this]() { + if (buttonLeft.time > currentTime - BUTTON_DELAY) return; + + buttonLeft.pushed = true; + buttonLeft.time = currentTime; + scrollCounter = 0; + }; + + buttonLeft.release = [this]() { + if (!buttonLeft.pushed) return; + + buttonLeft.pushed = false; + }; + + // === BUTTON RIGHT === // + buttonRight.push = [this]() { + if (buttonRight.time > currentTime - BUTTON_DELAY) return; + + buttonRight.pushed = true; + buttonRight.time = currentTime; + scrollCounter = 0; + }; + + buttonRight.release = [this]() { + if (!buttonRight.pushed) return; + + buttonRight.pushed = false; + }; + + // === BUTTON A === // + buttonA.push = [this]() { + if (!buttonA.pushed) { // first push + buttonA.pushed = true; + buttonA.time = currentTime; + scrollCounter = 0; + } else { // holding button + if ((currentTime - buttonA.time > 800) && !buttonA.hold) { + if (currentMenu->list->get(currentMenu->selected).hold) currentMenu->list->get( + currentMenu->selected).hold(); + buttonA.hold = true; + } + } + }; + + buttonA.release = [this]() { + if (!buttonA.pushed) return; // exit when button wasn't pushed before + + if (!buttonA.hold && (currentTime - buttonA.time > 80)) { + switch (mode) { + case SCREEN_MODE_MENU: + + if (currentMenu->list->get(currentMenu->selected).click) { + currentMenu->list->get(currentMenu->selected).click(); + } + break; + + case SCREEN_MODE_PACKETMONITOR: + case SCREEN_MODE_LOADSCAN: + scan.stop(); + mode = SCREEN_MODE_MENU; + break; + } + } + + buttonA.pushed = false; + buttonA.hold = false; + }; + + // === BUTTON B === // + buttonB.push = [this]() { + if (!buttonB.pushed && (buttonB.time > currentTime - BUTTON_DELAY)) return; + + buttonB.pushed = true; + buttonB.time = currentTime; + scrollCounter = 0; + }; + + buttonB.release = [this]() { + if (!buttonB.pushed) return; + + switch (mode) { + case SCREEN_MODE_MENU: + goBack(); + break; + + case SCREEN_MODE_PACKETMONITOR: + case SCREEN_MODE_LOADSCAN: + scan.stop(); + mode = SCREEN_MODE_MENU; + break; + } + + buttonB.pushed = false; + }; + + // === RUN SETUPS === // + // setting pin modes for buttons + if (buttonUp.enabled && buttonUp.setup) buttonUp.setup(); + + if (buttonDown.enabled && buttonDown.setup) buttonDown.setup(); + + if (buttonLeft.enabled && buttonLeft.setup) buttonLeft.setup(); + + if (buttonRight.enabled && buttonRight.setup) buttonRight.setup(); + + if (buttonA.enabled && buttonA.setup) buttonA.setup(); + + if (buttonB.enabled && buttonB.setup) buttonB.setup(); + + // ===== MENUS ===== // + + // MAIN MENU + createMenu(&mainMenu, NULL, [this]() { + addMenuNode(&mainMenu, D_SCAN, &scanMenu); /// SCAN + addMenuNode(&mainMenu, D_SHOW, &showMenu); // SHOW + addMenuNode(&mainMenu, D_ATTACK, &attackMenu); // ATTACK + addMenuNode(&mainMenu, D_PACKET_MONITOR, [this]() { // PACKET MONITOR + scan.start(SCAN_MODE_SNIFFER, 0, SCAN_MODE_OFF, 0, false, wifi_channel); + mode = SCREEN_MODE_PACKETMONITOR; + }); +#ifdef HIGHLIGHT_LED + addMenuNode(&mainMenu, D_LED, [this]() { // LED + highlightLED = !highlightLED; + digitalWrite(HIGHLIGHT_LED, highlightLED); + }); +#endif + }); + + // SCAN MENU + createMenu(&scanMenu, &mainMenu, [this]() { + addMenuNode(&scanMenu, D_SCAN_APST, [this]() { // SCAN AP + ST + scan.start(SCAN_MODE_ALL, 15000, SCAN_MODE_OFF, 0, true, wifi_channel); + mode = SCREEN_MODE_LOADSCAN; + }); + addMenuNode(&scanMenu, D_SCAN_AP, [this]() { // SCAN AP + scan.start(SCAN_MODE_APS, 0, SCAN_MODE_OFF, 0, true, wifi_channel); + mode = SCREEN_MODE_LOADSCAN; + }); + addMenuNode(&scanMenu, D_SCAN_ST, [this]() { // SCAN ST + scan.start(SCAN_MODE_STATIONS, 30000, SCAN_MODE_OFF, 0, true, wifi_channel); + mode = SCREEN_MODE_LOADSCAN; + }); + }); + + // SHOW MENU + createMenu(&showMenu, &mainMenu, [this]() { + addMenuNode(&showMenu, []() { // Accesspoints 0 [0] + return leftRight(str(D_ACCESSPOINTS), (String)accesspoints.count(), CHARS_PER_LINE); + }, &apListMenu); + addMenuNode(&showMenu, []() { // Stations 0 [0] + return leftRight(str(D_STATIONS), (String)stations.count(), CHARS_PER_LINE); + }, &stationListMenu); + addMenuNode(&showMenu, []() { // Names 0 [0] + return leftRight(str(D_NAMES), (String)names.count(), CHARS_PER_LINE); + }, &nameListMenu); + addMenuNode(&showMenu, []() { // SSIDs 0 + return leftRight(str(D_SSIDS), (String)ssids.count(), CHARS_PER_LINE); + }, &ssidListMenu); + }); + + // AP LIST MENU + createMenu(&apListMenu, &showMenu, [this]() { + // add APs to list + int c = accesspoints.count(); + + for (int i = 0; i < c; i++) { + addMenuNode(&apListMenu, [i]() { + return b2a(accesspoints.getSelected(i)) + accesspoints.getSSID(i); + }, [this, i]() { + accesspoints.getSelected(i) ? accesspoints.deselect(i) : accesspoints.select(i); + }, [this, i]() { + selectedID = i; + changeMenu(&apMenu); + }); + } + addMenuNode(&apListMenu, D_SELECT_ALL, [this]() { // SELECT ALL + accesspoints.selectAll(); + changeMenu(&apListMenu); + }); + addMenuNode(&apListMenu, D_DESELECT_ALL, [this]() { // DESELECT ALL + accesspoints.deselectAll(); + changeMenu(&apListMenu); + }); + addMenuNode(&apListMenu, D_REMOVE_ALL, [this]() { // REMOVE ALL + accesspoints.removeAll(); + goBack(); + }); + }); + + // STATION LIST MENU + createMenu(&stationListMenu, &showMenu, [this]() { + // add stations to list + int c = stations.count(); + + for (int i = 0; i < c; i++) { + addMenuNode(&stationListMenu, [i]() { + return b2a(stations.getSelected(i)) + + (stations.hasName(i) ? stations.getNameStr(i) : stations.getMacVendorStr(i)); + }, [this, i]() { + stations.getSelected(i) ? stations.deselect(i) : stations.select(i); + }, [this, i]() { + selectedID = i; + changeMenu(&stationMenu); + }); + } + + addMenuNode(&stationListMenu, D_SELECT_ALL, [this]() { // SELECT ALL + stations.selectAll(); + changeMenu(&stationListMenu); + }); + addMenuNode(&stationListMenu, D_DESELECT_ALL, [this]() { // DESELECT ALL + stations.deselectAll(); + changeMenu(&stationListMenu); + }); + addMenuNode(&stationListMenu, D_REMOVE_ALL, [this]() { // REMOVE ALL + stations.removeAll(); + goBack(); + }); + }); + + // NAME LIST MENU + createMenu(&nameListMenu, &showMenu, [this]() { + // add device names to list + int c = names.count(); + + for (int i = 0; i < c; i++) { + addMenuNode(&nameListMenu, [i]() { + return names.getSelectedStr(i) + names.getName(i); + }, [this, i]() { + names.getSelected(i) ? names.deselect(i) : names.select(i); + }, [this, i]() { + selectedID = i; + changeMenu(&nameMenu); + }); + } + addMenuNode(&nameListMenu, D_SELECT_ALL, [this]() { // SELECT ALL + names.selectAll(); + changeMenu(&nameListMenu); + }); + addMenuNode(&nameListMenu, D_DESELECT_ALL, [this]() { // DESELECT ALL + names.deselectAll(); + changeMenu(&nameListMenu); + }); + addMenuNode(&nameListMenu, D_REMOVE_ALL, [this]() { // REMOVE ALL + names.removeAll(); + goBack(); + }); + }); + + // SSID LIST MENU + createMenu(&ssidListMenu, &showMenu, [this]() { + addMenuNode(&ssidListMenu, D_CLONE_APS, [this]() { // CLONE APs + ssids.cloneSelected(true); + changeMenu(&ssidListMenu); + ssids.save(false); + }); + addMenuNode(&ssidListMenu, [this]() { + return b2a(ssids.getRandom()) + str(D_RANDOM_MODE); // *RANDOM MODE + }, [this]() { + if (ssids.getRandom()) ssids.disableRandom(); + else ssids.enableRandom(10); + changeMenu(&ssidListMenu); + }); + + // add ssids to list + int c = ssids.count(); + + for (int i = 0; i < c; i++) { + addMenuNode(&ssidListMenu, [i]() { + return ssids.getName(i).substring(0, ssids.getLen(i)); + }, [this, i]() { + selectedID = i; + changeMenu(&ssidMenu); + }, [this, i]() { + ssids.remove(i); + changeMenu(&ssidListMenu); + ssidListMenu.selected = i; + }); + } + + addMenuNode(&ssidListMenu, D_REMOVE_ALL, [this]() { // REMOVE ALL + ssids.removeAll(); + goBack(); + }); + }); + + // AP MENU + createMenu(&apMenu, &apListMenu, [this]() { + addMenuNode(&apMenu, [this]() { + return accesspoints.getSelectedStr(selectedID) + accesspoints.getSSID(selectedID); // * + }, [this]() { + accesspoints.getSelected(selectedID) ? accesspoints.deselect(selectedID) : accesspoints.select(selectedID); + }); + addMenuNode(&apMenu, [this]() { + return str(D_ENCRYPTION) + accesspoints.getEncStr(selectedID); + }, NULL); // Encryption: -/WPA2 + addMenuNode(&apMenu, [this]() { + return str(D_RSSI) + (String)accesspoints.getRSSI(selectedID); + }, NULL); // RSSI: -90 + addMenuNode(&apMenu, [this]() { + return str(D_CHANNEL) + (String)accesspoints.getCh(selectedID); + }, NULL); // Channel: 11 + addMenuNode(&apMenu, [this]() { + return accesspoints.getMacStr(selectedID); + }, NULL); // 00:11:22:00:11:22 + addMenuNode(&apMenu, [this]() { + return str(D_VENDOR) + accesspoints.getVendorStr(selectedID); + }, NULL); // Vendor: INTEL + addMenuNode(&apMenu, [this]() { + return accesspoints.getSelected(selectedID) ? str(D_DESELECT) : str(D_SELECT); // SELECT/DESELECT + }, [this]() { + accesspoints.getSelected(selectedID) ? accesspoints.deselect(selectedID) : accesspoints.select(selectedID); + }); + addMenuNode(&apMenu, D_CLONE, [this]() { // CLONE + ssids.add(accesspoints.getSSID(selectedID), accesspoints.getEnc(selectedID) != ENC_TYPE_NONE, 60, true); + changeMenu(&showMenu); + ssids.save(false); + }); + addMenuNode(&apMenu, D_REMOVE, [this]() { // REMOVE + accesspoints.remove(selectedID); + apListMenu.list->remove(apListMenu.selected); + goBack(); + }); + }); + + // STATION MENU + createMenu(&stationMenu, &stationListMenu, [this]() { + addMenuNode(&stationMenu, [this]() { + return stations.getSelectedStr(selectedID) + + (stations.hasName(selectedID) ? stations.getNameStr(selectedID) : stations.getMacVendorStr(selectedID)); // + }, [this]() { + stations.getSelected(selectedID) ? stations.deselect(selectedID) : stations.select(selectedID); + }); + addMenuNode(&stationMenu, [this]() { + return stations.getMacStr(selectedID); + }, NULL); // 00:11:22:00:11:22 + addMenuNode(&stationMenu, [this]() { + return str(D_VENDOR) + stations.getVendorStr(selectedID); + }, NULL); // Vendor: INTEL + addMenuNode(&stationMenu, [this]() { + return str(D_AP) + stations.getAPStr(selectedID); // AP: someAP + }, [this]() { + int apID = accesspoints.find(stations.getAP(selectedID)); + + if (apID >= 0) { + selectedID = apID; + changeMenu(&apMenu); + } + }); + addMenuNode(&stationMenu, [this]() { + return str(D_PKTS) + String(*stations.getPkts(selectedID)); + }, NULL); // Pkts: 12 + addMenuNode(&stationMenu, [this]() { + return str(D_CHANNEL) + String(stations.getCh(selectedID)); + }, NULL); // Channel: 11 + addMenuNode(&stationMenu, [this]() { + return str(D_SEEN) + stations.getTimeStr(selectedID); + }, NULL); // Seen: <1min + + addMenuNode(&stationMenu, [this]() { + return stations.getSelected(selectedID) ? str(D_DESELECT) : str(D_SELECT); // SELECT/DESELECT + }, [this]() { + stations.getSelected(selectedID) ? stations.deselect(selectedID) : stations.select(selectedID); + }); + addMenuNode(&stationMenu, D_REMOVE, [this]() { // REMOVE + stations.remove(selectedID); + stationListMenu.list->remove(stationListMenu.selected); + goBack(); + }); + }); + + // NAME MENU + createMenu(&nameMenu, &nameListMenu, [this]() { + addMenuNode(&nameMenu, [this]() { + return names.getSelectedStr(selectedID) + names.getName(selectedID); // + }, [this]() { + names.getSelected(selectedID) ? names.deselect(selectedID) : names.select(selectedID); + }); + addMenuNode(&nameMenu, [this]() { + return names.getMacStr(selectedID); + }, NULL); // 00:11:22:00:11:22 + addMenuNode(&nameMenu, [this]() { + return str(D_VENDOR) + names.getVendorStr(selectedID); + }, NULL); // Vendor: INTEL + addMenuNode(&nameMenu, [this]() { + return str(D_AP) + names.getBssidStr(selectedID); + }, NULL); // AP: 00:11:22:00:11:22 + addMenuNode(&nameMenu, [this]() { + return str(D_CHANNEL) + (String)names.getCh(selectedID); + }, NULL); // Channel: 11 + + addMenuNode(&nameMenu, [this]() { + return names.getSelected(selectedID) ? str(D_DESELECT) : str(D_SELECT); // SELECT/DESELECT + }, [this]() { + names.getSelected(selectedID) ? names.deselect(selectedID) : names.select(selectedID); + }); + addMenuNode(&nameMenu, D_REMOVE, [this]() { // REMOVE + names.remove(selectedID); + nameListMenu.list->remove(nameListMenu.selected); + goBack(); + }); + }); + + // SSID MENU + createMenu(&ssidMenu, &ssidListMenu, [this]() { + addMenuNode(&ssidMenu, [this]() { + return ssids.getName(selectedID).substring(0, ssids.getLen(selectedID)); + }, NULL); // SSID + addMenuNode(&ssidMenu, [this]() { + return str(D_ENCRYPTION) + ssids.getEncStr(selectedID); // WPA2 + }, [this]() { + ssids.setWPA2(selectedID, !ssids.getWPA2(selectedID)); + }); + addMenuNode(&ssidMenu, D_REMOVE, [this]() { // REMOVE + ssids.remove(selectedID); + ssidListMenu.list->remove(ssidListMenu.selected); + goBack(); + }); + }); + + // ATTACK MENU + createMenu(&attackMenu, &mainMenu, [this]() { + addMenuNode(&attackMenu, [this]() { // *DEAUTH 0/0 + if (attack.isRunning()) return leftRight(b2a(deauthSelected) + str(D_DEAUTH), + (String)attack.getDeauthPkts() + SLASH + + (String)attack.getDeauthMaxPkts(), CHARS_PER_LINE); + else return leftRight(b2a(deauthSelected) + str(D_DEAUTH), (String)scan.countSelected(), CHARS_PER_LINE); + }, [this]() { // deauth + deauthSelected = !deauthSelected; + + if (attack.isRunning()) { + attack.start(beaconSelected, deauthSelected, false, probeSelected, true, + settings.getAttackTimeout() * 1000); + } + }); + addMenuNode(&attackMenu, [this]() { // *BEACON 0/0 + if (attack.isRunning()) return leftRight(b2a(beaconSelected) + str(D_BEACON), + (String)attack.getBeaconPkts() + SLASH + + (String)attack.getBeaconMaxPkts(), CHARS_PER_LINE); + else return leftRight(b2a(beaconSelected) + str(D_BEACON), (String)ssids.count(), CHARS_PER_LINE); + }, [this]() { // beacon + beaconSelected = !beaconSelected; + + if (attack.isRunning()) { + attack.start(beaconSelected, deauthSelected, false, probeSelected, true, + settings.getAttackTimeout() * 1000); + } + }); + addMenuNode(&attackMenu, [this]() { // *PROBE 0/0 + if (attack.isRunning()) return leftRight(b2a(probeSelected) + str(D_PROBE), + (String)attack.getProbePkts() + SLASH + + (String)attack.getProbeMaxPkts(), CHARS_PER_LINE); + else return leftRight(b2a(probeSelected) + str(D_PROBE), (String)ssids.count(), CHARS_PER_LINE); + }, [this]() { // probe + probeSelected = !probeSelected; + + if (attack.isRunning()) { + attack.start(beaconSelected, deauthSelected, false, probeSelected, true, + settings.getAttackTimeout() * 1000); + } + }); + addMenuNode(&attackMenu, []() { // START + return leftRight(str(attack.isRunning() ? D_STOP_ATTACK : D_START_ATTACK), + attack.getPacketRate() > 0 ? (String)attack.getPacketRate() : String(), CHARS_PER_LINE); + }, [this]() { + if (attack.isRunning()) attack.stop(); + else attack.start(beaconSelected, deauthSelected, false, probeSelected, true, + settings.getAttackTimeout() * 1000); + }); + }); + + // ===================== // + + // set current menu to main menu + changeMenu(&mainMenu); + enabled = true; + startTime = currentTime; +} + +void DisplayUI::update() { + if (!enabled) return; + + // when display is off + if (mode == SCREEN_MODE_OFF) { + if (updateButton(&buttonA)) { + on(); + buttonA.hold = true; // to make sure you don't double click + } + } + + else { + // timeout to save display life + if ((mode == SCREEN_MODE_MENU) && (settings.getDisplayTimeout() > 0) && + (currentTime > settings.getDisplayTimeout() * 1000)) { + uint32_t buttonTimeout = currentTime - settings.getDisplayTimeout() * 1000; + + if ((buttonUp.time < buttonTimeout) + && (buttonDown.time < buttonTimeout) + && (buttonLeft.time < buttonTimeout) + && (buttonRight.time < buttonTimeout) + && (buttonA.time < buttonTimeout) + && (buttonB.time < buttonTimeout)) { + off(); + } + } + + // only one button can be pressed at a time + if (updateButton(&buttonB)) draw(); + else if (updateButton(&buttonA)) draw(); + else if (updateButton(&buttonUp)) draw(); + else if (updateButton(&buttonDown)) draw(); + else if (updateButton(&buttonLeft)) draw(); + else if (updateButton(&buttonRight)) draw(); + else draw(); + } +} + +void DisplayUI::draw() { + if ((currentTime - drawTime > DRAW_INTERVAL) && currentMenu) { + drawTime = currentTime; + + updatePrefix(); + + switch (mode) { + case SCREEN_MODE_BUTTON_TEST: + drawButtonTest(); + break; + + case SCREEN_MODE_MENU: + drawMenu(); + break; + + case SCREEN_MODE_LOADSCAN: + drawLoadingScan(); + break; + + case SCREEN_MODE_PACKETMONITOR: + drawPacketMonitor(); + break; + + case SCREEN_MODE_INTRO: + + if (currentTime - startTime >= SCREEN_INTRO_TIME) { + mode = SCREEN_MODE_MENU; + } + drawIntro(); + break; + } + + updateSuffix(); + } } void DisplayUI::drawButtonTest() { - // ===== adjustable ===== // - if (buttonUp.enabled) display.drawString(0, 0, str(D_UP) + b2s(buttonUp.pushed)); + if (buttonUp.enabled) drawString(0, 0, str(D_UP) + b2s(buttonUp.pushed)); - if (buttonDown.enabled) display.drawString(0, 9, str(D_DOWN) + b2s(buttonDown.pushed)); + if (buttonDown.enabled) drawString(0, 9, str(D_DOWN) + b2s(buttonDown.pushed)); - if (buttonLeft.enabled) display.drawString(0, 18, str(D_LEFT) + b2s(buttonLeft.pushed)); + if (buttonLeft.enabled) drawString(0, 18, str(D_LEFT) + b2s(buttonLeft.pushed)); - if (buttonRight.enabled) display.drawString(0, 27, str(D_RIGHT) + b2s(buttonRight.pushed)); + if (buttonRight.enabled) drawString(0, 27, str(D_RIGHT) + b2s(buttonRight.pushed)); - if (buttonA.enabled) display.drawString(0, 36, str(D_A) + b2s(buttonA.pushed)); + if (buttonA.enabled) drawString(0, 36, str(D_A) + b2s(buttonA.pushed)); - if (buttonB.enabled) display.drawString(0, 45, str(D_B) + b2s(buttonB.pushed)); - // ====================== // + if (buttonB.enabled) drawString(0, 45, str(D_B) + b2s(buttonB.pushed)); } void DisplayUI::drawMenu() { - String tmp; - int tmpLen; - int row = (currentMenu->selected / 5) * 5; + String tmp; + int tmpLen; + int row = (currentMenu->selected / 5) * 5; - // correct selected if it's off - if (currentMenu->selected < 0) currentMenu->selected = 0; - else if (currentMenu->selected >= currentMenu->list->size()) currentMenu->selected = currentMenu->list->size() - 1; + // correct selected if it's off + if (currentMenu->selected < 0) currentMenu->selected = 0; + else if (currentMenu->selected >= currentMenu->list->size()) currentMenu->selected = currentMenu->list->size() - 1; - // draw menu entries - for (int i = row; i < currentMenu->list->size() && i < row + 5; i++) { - tmp = currentMenu->list->get(i).getStr(); - tmpLen = tmp.length(); + // draw menu entries + for (int i = row; i < currentMenu->list->size() && i < row + 5; i++) { + tmp = currentMenu->list->get(i).getStr(); + tmpLen = tmp.length(); - // horizontal scrolling - if ((currentMenu->selected == i) && (tmpLen > CHARS_PER_LINE)) { - tmp = tmp.substring(scrollCounter / SCROLL_SPEED); - scrollCounter++; + // horizontal scrolling + if ((currentMenu->selected == i) && (tmpLen > CHARS_PER_LINE)) { + tmp = tmp.substring(scrollCounter / SCROLL_SPEED); + scrollCounter++; - if (scrollCounter / SCROLL_SPEED > tmpLen - CHARS_PER_LINE) scrollCounter = 0; - } - - tmp = (currentMenu->selected == i ? CURSOR : SPACE) + tmp; - drawString(0, (i - row) * 12, tmp); + if (scrollCounter / SCROLL_SPEED > tmpLen - CHARS_PER_LINE) scrollCounter = 0; } + + tmp = (currentMenu->selected == i ? CURSOR : SPACE) + tmp; + drawString(0, (i - row) * 12, tmp); + } } void DisplayUI::drawLoadingScan() { - // ===== adjustable ===== // + String percentage; + if (scan.isScanning()) { - if (scan.isSniffing()) { // Scanning for Stations - display.drawString(2, 0, - buildString(str(D_LOADING_SCREEN_0), (String)scan.getPercentage() + PERCENT, - CHARS_PER_LINE)); - display.drawProgressBar(5, 22, 118, 8, scan.getPercentage()); - display.drawString(2, 36, str(D_LOADING_SCREEN_1) + (String)accesspoints.count()); - display.drawString(2, 50, str(D_LOADING_SCREEN_2) + (String)stations.count()); - } else { // Scanning for APs - display.drawString(2, 10, str(D_LOADING_SCREEN_3)); - display.drawString(2, 24, str(D_LOADING_SCREEN_4)); - } + percentage = String(scan.getPercentage()) + '%'; } else { - mode = SCREEN_MODE_MENU; - changeMenu(&showMenu); + percentage = String(DSP_SCAN_DONE); } - // ====================== // + + drawString(0, leftRight(String(DSP_SCAN_FOR), scan.getMode(), maxLen)); + drawString(1, leftRight(String(DSP_APS), String(accesspoints.count()), maxLen)); + drawString(2, leftRight(String(DSP_STS), String(stations.count()), maxLen)); + drawString(3, leftRight(String(DSP_PKTS), String(scan.getPacketRate()) + String(DSP_S), maxLen)); + drawString(4, center(percentage, maxLen)); +} + +String DisplayUI::getChannel() { + String ch = String(wifi_channel); + if(ch.length() < 2) ch = ' ' + ch; + return ch; } void DisplayUI::drawPacketMonitor() { - // ===== adjustable ===== // - double scale = scan.getScaleFactor(50); + double scale = scan.getScaleFactor(50); - display.drawString(0, 0, str(D_CH) + String(wifi_channel)); - display.drawString(40, 0, str(D_PKTS) + String(scan.getPacketRate())); - display.setTextAlignment(TEXT_ALIGN_RIGHT); - display.drawString(128, 0, String(scan.deauths)); - display.setTextAlignment(TEXT_ALIGN_LEFT); + String headline = leftRight(str(D_CH) + getChannel() + String(' ') + String('[') + String(scan.deauths) + String(']'), String(scan.getPacketRate()) + str(D_PKTS) , maxLen); + drawString(0, 0, headline); - if (scan.getMaxPacket() > 0) { - for (int i = 0; i < SCAN_PACKET_LIST_SIZE * 2; i += 2) { - display.drawLine(i, 64, i, 64 - scan.getPackets(i / 2) * scale); - display.drawLine(i + 1, 64, i + 1, 64 - scan.getPackets(i / 2) * scale); - } + if (scan.getMaxPacket() > 0) { + for (int i = 0; i < SCAN_PACKET_LIST_SIZE * 2; i += 2) { + drawLine(i, 64, i, 64 - scan.getPackets(i / 2) * scale); + drawLine(i + 1, 64, i + 1, 64 - scan.getPackets(i / 2) * scale); } - // ====================== // + } } void DisplayUI::drawIntro() { - // ===== adjustable ===== // - display.setTextAlignment(TEXT_ALIGN_CENTER); - display.drawString(64, 6, String(F("ESP8266 Deauther"))); - display.drawString(64, 20, String(F("by @Spacehuhn"))); - display.drawString(64, 34, String(F(""))); - display.drawString(64, 48, settings.getVersion()); - // ====================== // + drawString(0, lineHeight*0, center(String(F("")), maxLen)); + drawString(0, lineHeight*1, center(String(F("ESP8266 Deauther")), maxLen)); + drawString(0, lineHeight*2, center(String(F("by @Spacehuhn")), maxLen)); + drawString(0, lineHeight*3, center(String(F("")), maxLen)); + drawString(0, lineHeight*4, center(settings.getVersion(), maxLen)); } bool DisplayUI::updateButton(Button* button) { - // direct exit when button is disabled or has no read function - if (!button->enabled || !button->read) return false; + // direct exit when button is disabled or has no read function + if (!button->enabled || !button->read) return false; - // read pin - if (button->read()) { - if (button->push) button->push(); - } else { - if (button->release) button->release(); - } + // read pin + if (button->read()) { + if (button->push) button->push(); + } else { + if (button->release) button->release(); + } - return button->pushed; + return button->pushed; } void DisplayUI::clearMenu(Menu* menu) { - while (menu->list->size() > 0) { - menu->list->remove(0); - } + while (menu->list->size() > 0) { + menu->list->remove(0); + } } void DisplayUI::changeMenu(Menu* menu) { - if (menu) { - // only open list menu if it has nodes - if (((menu == &apListMenu) && (accesspoints.count() == 0)) || - ((menu == &stationListMenu) && (stations.count() == 0)) || - ((menu == &nameListMenu) && (names.count() == 0))) { - return; - } - - if (currentMenu) clearMenu(currentMenu); - currentMenu = menu; - currentMenu->selected = 0; - buttonA.time = currentTime; - - if (selectedID < 0) selectedID = 0; - - if (currentMenu->parentMenu) { - addMenuNode(currentMenu, D_BACK, currentMenu->parentMenu); // add [BACK] - currentMenu->selected = 1; - } - - if (currentMenu->build) currentMenu->build(); + if (menu) { + // only open list menu if it has nodes + if (((menu == &apListMenu) && (accesspoints.count() == 0)) || + ((menu == &stationListMenu) && (stations.count() == 0)) || + ((menu == &nameListMenu) && (names.count() == 0))) { + return; } + + if (currentMenu) clearMenu(currentMenu); + currentMenu = menu; + currentMenu->selected = 0; + buttonA.time = currentTime; + + if (selectedID < 0) selectedID = 0; + + if (currentMenu->parentMenu) { + addMenuNode(currentMenu, D_BACK, currentMenu->parentMenu); // add [BACK] + currentMenu->selected = 1; + } + + if (currentMenu->build) currentMenu->build(); + } } void DisplayUI::goBack() { - if (currentMenu->parentMenu) changeMenu(currentMenu->parentMenu); + if (currentMenu->parentMenu) changeMenu(currentMenu->parentMenu); } void DisplayUI::createMenu(Menu* menu, Menu* parent, std::functionbuild) { - menu->list = new SimpleList; - menu->parentMenu = parent; - menu->selected = 0; - menu->build = build; + menu->list = new SimpleList; + menu->parentMenu = parent; + menu->selected = 0; + menu->build = build; } void DisplayUI::addMenuNode(Menu* menu, std::functiongetStr, std::functionclick, std::functionhold) { - menu->list->add(MenuNode{ getStr, click, hold }); + menu->list->add(MenuNode{ getStr, click, hold }); } void DisplayUI::addMenuNode(Menu* menu, std::functiongetStr, std::functionclick) { - addMenuNode(menu, getStr, click, NULL); + addMenuNode(menu, getStr, click, NULL); } void DisplayUI::addMenuNode(Menu* menu, std::functiongetStr, Menu* next) { - addMenuNode(menu, getStr, [this, next]() { - changeMenu(next); - }); + addMenuNode(menu, getStr, [this, next]() { + changeMenu(next); + }); } void DisplayUI::addMenuNode(Menu* menu, const char* ptr, std::functionclick) { - addMenuNode(menu, [ptr]() { - return str(ptr); - }, click); + addMenuNode(menu, [ptr]() { + return str(ptr); + }, click); } void DisplayUI::addMenuNode(Menu* menu, const char* ptr, Menu* next) { - addMenuNode(menu, [ptr]() { - return str(ptr); - }, next); + addMenuNode(menu, [ptr]() { + return str(ptr); + }, next); } diff --git a/esp8266_deauther/DisplayUI.h b/esp8266_deauther/DisplayUI.h index a875d20..762c86e 100644 --- a/esp8266_deauther/DisplayUI.h +++ b/esp8266_deauther/DisplayUI.h @@ -24,7 +24,11 @@ extern Scan scan; extern Attack attack; extern uint32_t currentTime; -extern String buildString(String left, String right, int maxLen); +extern String leftRight(String a, String b, int len); +extern String center(String a, int len); +extern String left(String a, int len); +extern String right(String a, int len); +extern String leftRight(String a, String b, int len); extern String replaceUtf8(String str, String r); // different display modes @@ -82,6 +86,19 @@ class DisplayUI { bool highlightLED = false; #endif + // ===== adjustable ===== // + void configInit(); + void configOn(); + void configOff(); + void updatePrefix(); + void updateSuffix(); + void drawString(int x, int y, String str); + void drawString(int row, String str); + void drawLine(int x1, int y1, int x2, int y2); + uint8_t maxLen = 18; + uint8_t lineHeight = 12; + // ====================== // + void update(); void on(); void off(); @@ -112,12 +129,13 @@ class DisplayUI { bool deauthSelected = false; bool probeSelected = false; + String getChannel(); + // functions for buttons bool updateButton(Button* button); // read and update - + // draw functions void draw(); - void drawString(int x, int y, String str); void drawButtonTest(); void drawMenu(); void drawLoadingScan(); diff --git a/esp8266_deauther/Names.cpp b/esp8266_deauther/Names.cpp index 1d1badf..f709c88 100644 --- a/esp8266_deauther/Names.cpp +++ b/esp8266_deauther/Names.cpp @@ -143,13 +143,13 @@ void Names::print(int num, bool header, bool footer) { prntln(N_TABLE_DIVIDER); } - prnt(buildString(String(), (String)num, 2)); - prnt(buildString(String(SPACE) + getMacStr(num), String(), 18)); - prnt(buildString(String(SPACE) + getVendorStr(num), String(), 9)); - prnt(buildString(String(SPACE) + getName(num), String(), 17)); - prnt(buildString(String(SPACE) + getBssidStr(num), String(), 18)); - prnt(buildString(String(SPACE), (String)getCh(num), 3)); - prntln(buildString(String(SPACE) + getSelectedStr(num), String(), 9)); + prnt(leftRight(String(), (String)num, 2)); + prnt(leftRight(String(SPACE) + getMacStr(num), String(), 18)); + prnt(leftRight(String(SPACE) + getVendorStr(num), String(), 9)); + prnt(leftRight(String(SPACE) + getName(num), String(), 17)); + prnt(leftRight(String(SPACE) + getBssidStr(num), String(), 18)); + prnt(leftRight(String(SPACE), (String)getCh(num), 3)); + prntln(leftRight(String(SPACE) + getSelectedStr(num), String(), 9)); if (footer) prntln(N_TABLE_DIVIDER); } diff --git a/esp8266_deauther/Names.h b/esp8266_deauther/Names.h index 4de2bf0..f182780 100644 --- a/esp8266_deauther/Names.h +++ b/esp8266_deauther/Names.h @@ -1,104 +1,104 @@ -#ifndef Names_h -#define Names_h - -#include "Arduino.h" -#include -#include -extern "C" { - #include "user_interface.h" -} -#include "ArduinoJson.h" -#include "language.h" -#include "SimpleList.h" - -#define NAME_LIST_SIZE 25 -#define NAME_MAX_LENGTH 16 - -extern void checkFile(String path, String data); -extern JsonVariant parseJSONFile(String path, DynamicJsonBuffer& jsonBuffer); -extern bool writeFile(String path, String& buf); -extern bool appendFile(String path, String& buf); -extern bool strToMac(String macStr, uint8_t* mac); -extern String searchVendor(uint8_t* mac); -extern String fixUtf8(String str); -extern String buildString(String left, String right, int maxLen); -extern String escape(String str); -extern String bytesToStr(uint8_t* b, uint32_t size); - -class Names { - public: - Names(); - - void load(); - void load(String filepath); - void save(bool force); - void save(bool force, String filepath); - void sort(); - - String find(uint8_t* mac); - int findID(uint8_t* mac); - - void print(int num); - void print(int num, bool header, bool footer); - void select(int num); - void select(String name); - void deselect(int num); - void deselect(String name); - void add(uint8_t* mac, String name, uint8_t* bssid, uint8_t ch, bool selected, bool force); - void add(String macStr, String name, String bssidStr, uint8_t ch, bool selected, bool force); - void replace(int num, String macStr, String name, String bssidStr, uint8_t ch, bool selected); - void remove(int num); - - void printAll(); - void printSelected(); - void selectAll(); - void deselectAll(); - void removeAll(); - - uint8_t* getMac(int num); - uint8_t* getBssid(int num); - String getMacStr(int num); - String getBssidStr(int num); - String getName(int num); - String getVendorStr(int num); - String getSelectedStr(int num); - uint8_t getCh(int num); - bool getSelected(int num); - bool isStation(int num); - - void setName(int num, String name); - void setMac(int num, String macStr); - void setCh(int num, uint8_t ch); - void setBSSID(int num, String bssidStr); - - int count(); - int selected(); - int stations(); - - bool check(int num); - - private: - String FILE_PATH = "/names.json"; - bool changed = false; - - struct Device { - uint8_t* mac; // mac address - char * name; // name of saved device - uint8_t* apBssid; // mac address of AP (if saved device is a station) - uint8_t ch; // Wi-Fi channel of Device - bool selected; // select for attacking - }; - - SimpleList* list; - - int binSearch(uint8_t* searchBytes, int lowerEnd, int upperEnd); - bool internal_check(int num); - void internal_select(int num); - void internal_deselect(int num); - void internal_add(uint8_t* mac, String name, uint8_t* bssid, uint8_t ch, bool selected); - void internal_add(String macStr, String name, String bssidStr, uint8_t ch, bool selected); - void internal_remove(int num); - void internal_removeAll(); -}; - -#endif // ifndef Names_h \ No newline at end of file +#ifndef Names_h +#define Names_h + +#include "Arduino.h" +#include +#include +extern "C" { + #include "user_interface.h" +} +#include "ArduinoJson.h" +#include "language.h" +#include "SimpleList.h" + +#define NAME_LIST_SIZE 25 +#define NAME_MAX_LENGTH 16 + +extern void checkFile(String path, String data); +extern JsonVariant parseJSONFile(String path, DynamicJsonBuffer& jsonBuffer); +extern bool writeFile(String path, String& buf); +extern bool appendFile(String path, String& buf); +extern bool strToMac(String macStr, uint8_t* mac); +extern String searchVendor(uint8_t* mac); +extern String fixUtf8(String str); +extern String leftRight(String a, String b, int len); +extern String escape(String str); +extern String bytesToStr(uint8_t* b, uint32_t size); + +class Names { + public: + Names(); + + void load(); + void load(String filepath); + void save(bool force); + void save(bool force, String filepath); + void sort(); + + String find(uint8_t* mac); + int findID(uint8_t* mac); + + void print(int num); + void print(int num, bool header, bool footer); + void select(int num); + void select(String name); + void deselect(int num); + void deselect(String name); + void add(uint8_t* mac, String name, uint8_t* bssid, uint8_t ch, bool selected, bool force); + void add(String macStr, String name, String bssidStr, uint8_t ch, bool selected, bool force); + void replace(int num, String macStr, String name, String bssidStr, uint8_t ch, bool selected); + void remove(int num); + + void printAll(); + void printSelected(); + void selectAll(); + void deselectAll(); + void removeAll(); + + uint8_t* getMac(int num); + uint8_t* getBssid(int num); + String getMacStr(int num); + String getBssidStr(int num); + String getName(int num); + String getVendorStr(int num); + String getSelectedStr(int num); + uint8_t getCh(int num); + bool getSelected(int num); + bool isStation(int num); + + void setName(int num, String name); + void setMac(int num, String macStr); + void setCh(int num, uint8_t ch); + void setBSSID(int num, String bssidStr); + + int count(); + int selected(); + int stations(); + + bool check(int num); + + private: + String FILE_PATH = "/names.json"; + bool changed = false; + + struct Device { + uint8_t* mac; // mac address + char * name; // name of saved device + uint8_t* apBssid; // mac address of AP (if saved device is a station) + uint8_t ch; // Wi-Fi channel of Device + bool selected; // select for attacking + }; + + SimpleList* list; + + int binSearch(uint8_t* searchBytes, int lowerEnd, int upperEnd); + bool internal_check(int num); + void internal_select(int num); + void internal_deselect(int num); + void internal_add(uint8_t* mac, String name, uint8_t* bssid, uint8_t ch, bool selected); + void internal_add(String macStr, String name, String bssidStr, uint8_t ch, bool selected); + void internal_remove(int num); + void internal_removeAll(); +}; + +#endif // ifndef Names_h diff --git a/esp8266_deauther/SSIDs.cpp b/esp8266_deauther/SSIDs.cpp index 3464c7d..1cd8329 100644 --- a/esp8266_deauther/SSIDs.cpp +++ b/esp8266_deauther/SSIDs.cpp @@ -254,9 +254,9 @@ void SSIDs::print(int num, bool header, bool footer) { prntln(SS_TABLE_DIVIDER); } - prnt(buildString(String(), (String)num, 2)); - prnt(buildString(String(SPACE), getEncStr(num), 5)); - prntln(buildString(String(SPACE) + getName(num), String(), 33)); + prnt(leftRight(String(), (String)num, 2)); + prnt(leftRight(String(SPACE), getEncStr(num), 5)); + prntln(leftRight(String(SPACE) + getName(num), String(), 33)); if (footer) prntln(SS_TABLE_DIVIDER); } diff --git a/esp8266_deauther/SSIDs.h b/esp8266_deauther/SSIDs.h index ba78461..dc0d187 100644 --- a/esp8266_deauther/SSIDs.h +++ b/esp8266_deauther/SSIDs.h @@ -1,87 +1,87 @@ -#ifndef SSIDs_h -#define SSIDs_h - -#include "Arduino.h" -#include -#include -extern "C" { - #include "user_interface.h" -} -#include "ArduinoJson.h" -#include "language.h" -#include "SimpleList.h" -#include "Settings.h" -#include "Accesspoints.h" - -#define SSID_LIST_SIZE 60 - -extern Settings settings; -extern uint32_t currentTime; -extern Accesspoints accesspoints; - -extern void checkFile(String path, String data); -extern JsonVariant parseJSONFile(String path, DynamicJsonBuffer& jsonBuffer); -extern bool appendFile(String path, String& buf); -extern bool writeFile(String path, String& buf); -extern void readFileToSerial(String path); -extern String fixUtf8(String str); -extern String buildString(String left, String right, int maxLen); -extern String escape(String str); - -class SSIDs { - public: - SSIDs(); - - void load(); - void load(String filepath); - void save(bool force); - void save(bool force, String filepath); - void update(); - - void print(int num); - void print(int num, bool header, bool footer); - void add(String name, bool wpa2, int clones, bool force); - void cloneSelected(bool force); - void remove(int num); - void enableRandom(uint32_t randomInterval); - void disableRandom(); - bool getRandom(); - - String getName(int num); - bool getWPA2(int num); - String getEncStr(int num); - int getLen(int num); - - void setWPA2(int num, bool wpa2); - void replace(int num, String name, bool wpa2); - - void printAll(); - void removeAll(); - - int count(); - - private: - bool changed = false; - bool randomMode = false; - uint32_t randomInterval = 2000; - uint32_t randomTime = 0; - - struct SSID { - String name; // SSID - bool wpa2; // WPA2 encrypted or not - uint8_t len; // original length (before editing it to be 32 characters) - }; - - String FILE_PATH = "/ssids.json"; - - SimpleList* list; - - bool check(int num); - String randomize(String name); - - void internal_add(String name, bool wpa2, int add); - void internal_remove(int num); - void internal_removeAll(); -}; - -#endif // ifndef SSIDs_h \ No newline at end of file +#ifndef SSIDs_h +#define SSIDs_h + +#include "Arduino.h" +#include +#include +extern "C" { + #include "user_interface.h" +} +#include "ArduinoJson.h" +#include "language.h" +#include "SimpleList.h" +#include "Settings.h" +#include "Accesspoints.h" + +#define SSID_LIST_SIZE 60 + +extern Settings settings; +extern uint32_t currentTime; +extern Accesspoints accesspoints; + +extern void checkFile(String path, String data); +extern JsonVariant parseJSONFile(String path, DynamicJsonBuffer& jsonBuffer); +extern bool appendFile(String path, String& buf); +extern bool writeFile(String path, String& buf); +extern void readFileToSerial(String path); +extern String fixUtf8(String str); +extern String leftRight(String a, String b, int len); +extern String escape(String str); + +class SSIDs { + public: + SSIDs(); + + void load(); + void load(String filepath); + void save(bool force); + void save(bool force, String filepath); + void update(); + + void print(int num); + void print(int num, bool header, bool footer); + void add(String name, bool wpa2, int clones, bool force); + void cloneSelected(bool force); + void remove(int num); + void enableRandom(uint32_t randomInterval); + void disableRandom(); + bool getRandom(); + + String getName(int num); + bool getWPA2(int num); + String getEncStr(int num); + int getLen(int num); + + void setWPA2(int num, bool wpa2); + void replace(int num, String name, bool wpa2); + + void printAll(); + void removeAll(); + + int count(); + + private: + bool changed = false; + bool randomMode = false; + uint32_t randomInterval = 2000; + uint32_t randomTime = 0; + + struct SSID { + String name; // SSID + bool wpa2; // WPA2 encrypted or not + uint8_t len; // original length (before editing it to be 32 characters) + }; + + String FILE_PATH = "/ssids.json"; + + SimpleList* list; + + bool check(int num); + String randomize(String name); + + void internal_add(String name, bool wpa2, int add); + void internal_remove(int num); + void internal_removeAll(); +}; + +#endif // ifndef SSIDs_h diff --git a/esp8266_deauther/Scan.cpp b/esp8266_deauther/Scan.cpp index df60207..d7f2b4c 100644 --- a/esp8266_deauther/Scan.cpp +++ b/esp8266_deauther/Scan.cpp @@ -1,426 +1,443 @@ -#include "Scan.h" - -Scan::Scan() { - list = new SimpleList; -} - -void Scan::sniffer(uint8_t* buf, uint16_t len) { - if (!isSniffing()) return; - - packets++; - - if (len < 28) return; // drop frames that are too short to have a valid MAC header - - if ((buf[12] == 0xc0) || (buf[12] == 0xa0)) { - tmpDeauths++; - return; - } - - // drop beacon frames, probe requests/responses and deauth/disassociation frames - if ((buf[12] == 0x80) || (buf[12] == 0x40) || (buf[12] == 0x50) /* || buf[12] == 0xc0 || buf[12] == 0xa0*/) return; - - // only allow data frames - // if(buf[12] != 0x08 && buf[12] != 0x88) return; - - uint8_t* macTo = &buf[16]; - uint8_t* macFrom = &buf[22]; - - if (macBroadcast(macTo) || macBroadcast(macFrom) || !macValid(macTo) || !macValid(macFrom) || macMulticast(macTo) || - macMulticast(macFrom)) return; - - int accesspointNum = findAccesspoint(macFrom); - - if (accesspointNum >= 0) { - stations.add(macTo, accesspoints.getID(accesspointNum)); - } else { - accesspointNum = findAccesspoint(macTo); - - if (accesspointNum >= 0) { - stations.add(macFrom, accesspoints.getID(accesspointNum)); - } - } -} - -int Scan::findAccesspoint(uint8_t* mac) { - for (int i = 0; i < accesspoints.count(); i++) { - if (memcmp(accesspoints.getMac(i), mac, 6) == 0) return i; - } - return -1; -} - -void Scan::start(uint8_t mode) { - start(mode, sniffTime, scan_continue_mode, continueTime, channelHop, wifi_channel); -} - -void Scan::start(uint8_t mode, uint32_t time, uint8_t nextmode, uint32_t continueTime, bool channelHop, - uint8_t channel) { - if (mode != SCAN_MODE_OFF) stop(); - - setWifiChannel(channel); - Scan::continueStartTime = currentTime; - Scan::snifferPacketTime = continueStartTime; - Scan::snifferOutputTime = continueStartTime; - Scan::continueTime = continueTime; - Scan::sniffTime = time; - Scan::channelHop = channelHop; - Scan::scanMode = mode; - Scan::scan_continue_mode = nextmode; - - if ((sniffTime > 0) && (sniffTime < 1000)) sniffTime = 1000; - - // Serial.printf("mode: %u, time: %u, continue-mode: %u, continueTime: %u, channelHop: %u, channel: %u\r\n", mode, - // time, scan_continue_mode, continueTime, channelHop, channel); - - /* AP Scan */ - if ((mode == SCAN_MODE_APS) || (mode == SCAN_MODE_ALL)) { - // remove old results - accesspoints.removeAll(); - stations.removeAll(); - // start AP scan - prntln(SC_START_AP); - WiFi.scanNetworks(true, true); - } - - /* Station Scan */ - else if (mode == SCAN_MODE_STATIONS) { - // start station scan - if (accesspoints.count() < 1) { - start(SCAN_MODE_ALL); - // Serial.println(str(SC_ERROR_NO_AP)); - return; - } - snifferStartTime = currentTime; - prnt(SC_START_CLIENT); - - if (sniffTime > 0) prnt(String(sniffTime / 1000) + S); - else prnt(SC_INFINITELY); - - if (!channelHop) { - prnt(SC_ON_CHANNEL); - prnt(wifi_channel); - } - prntln(); - - // enable sniffer - stopAP(); - wifi_promiscuous_enable(true); - } - - else if (mode == SCAN_MODE_SNIFFER) { - deauths = tmpDeauths; - tmpDeauths = 0; - snifferStartTime = currentTime; - prnt(SS_START_SNIFFER); - - if (sniffTime > 0) prnt(String(sniffTime / 1000) + S); - else prnt(SC_INFINITELY); - prnt(SC_ON_CHANNEL); - prntln(channelHop ? str(SC_ONE_TO) + (String)settings.getMaxCh() : (String)wifi_channel); - - // enable sniffer - stopAP(); - wifi_promiscuous_enable(true); - } - - /* Stop scan */ - else if (mode == SCAN_MODE_OFF) { - wifi_promiscuous_enable(false); - - if (settings.getWebInterface()) resumeAP(); - prntln(SC_STOPPED); - save(true); - - if (scan_continue_mode != SCAN_MODE_OFF) { - prnt(SC_RESTART); - prnt(int(continueTime / 1000)); - prntln(SC_CONTINUE); - } - } - - /* ERROR */ - else { - prnt(SC_ERROR_MODE); - prntln(mode); - return; - } -} - -void Scan::update() { - if (scanMode == SCAN_MODE_OFF) { - // restart scan if it is continuous - if (scan_continue_mode != SCAN_MODE_OFF) { - if (currentTime - continueStartTime > continueTime) start(scan_continue_mode); - } - return; - } - - // sniffer - if (isSniffing()) { - // update packet list every 1s - if (currentTime - snifferPacketTime > 1000) { - snifferPacketTime = currentTime; - list->add(packets); - - if (list->size() > SCAN_PACKET_LIST_SIZE) list->remove(0); - deauths = tmpDeauths; - tmpDeauths = 0; - packets = 0; - } - - // print status every 3s - if (currentTime - snifferOutputTime > 3000) { - char s[100]; - - if (sniffTime > 0) { - sprintf(s, str(SC_OUTPUT_A).c_str(), getPercentage(), packets, stations.count(), deauths); - } else { - sprintf(s, str(SC_OUTPUT_B).c_str(), packets, stations.count(), deauths); - } - prnt(String(s)); - snifferOutputTime = currentTime; - } - - // channel hopping - if (channelHop && (currentTime - snifferChannelTime > settings.getChTime())) { - snifferChannelTime = currentTime; - - if (scanMode == SCAN_MODE_STATIONS) nextChannel(); // go to next channel an AP is on - else setChannel(wifi_channel + 1); // go to next channel - } - } - - // APs - if ((scanMode == SCAN_MODE_APS) || (scanMode == SCAN_MODE_ALL)) { - int16_t results = WiFi.scanComplete(); - - if (results >= 0) { - for (int16_t i = 0; i < results && i < 256; i++) { - if (channelHop || (WiFi.channel(i) == wifi_channel)) accesspoints.add(i, false); - } - accesspoints.sort(); - accesspoints.printAll(); - - if (scanMode == SCAN_MODE_ALL) { - delay(30); - start(SCAN_MODE_STATIONS); - } - else start(SCAN_MODE_OFF); - } - } - - // Stations - else if ((sniffTime > 0) && (currentTime > snifferStartTime + sniffTime)) { - wifi_promiscuous_enable(false); - - if (scanMode == SCAN_MODE_STATIONS) { - stations.sort(); - stations.printAll(); - } - start(SCAN_MODE_OFF); - } -} - -void Scan::setup() { - save(true); -} - -void Scan::stop() { - scan_continue_mode = SCAN_MODE_OFF; - start(SCAN_MODE_OFF); -} - -void Scan::setChannel(uint8_t ch) { - if (ch > settings.getMaxCh()) ch = 1; - else if (ch < 1) ch = settings.getMaxCh(); - - wifi_promiscuous_enable(0); - setWifiChannel(ch); - wifi_promiscuous_enable(1); -} - -void Scan::nextChannel() { - if (accesspoints.count() > 1) { - uint8_t ch = wifi_channel; - - do { - ch++; - - if (ch > settings.getMaxCh()) ch = 1; - } while (!apWithChannel(ch)); - setChannel(ch); - } -} - -bool Scan::apWithChannel(uint8_t ch) { - for (int i = 0; i < accesspoints.count(); i++) - if (accesspoints.getCh(i) == ch) return true; - - return false; -} - -void Scan::save(bool force, String filePath) { - String tmp = FILE_PATH; - - FILE_PATH = filePath; - save(true); - FILE_PATH = tmp; -} - -void Scan::save(bool force) { - if (!(accesspoints.changed || stations.changed) && !force) return; - - // Accesspoints - String buf = String(OPEN_CURLY_BRACKET) + String(DOUBLEQUOTES) + str(SC_JSON_APS) + String(DOUBLEQUOTES) + String( - DOUBLEPOINT) + String(OPEN_BRACKET); // {"aps":[ - - if (!writeFile(FILE_PATH, buf)) { // overwrite old file - prnt(F_ERROR_SAVING); - prntln(FILE_PATH); - return; - } - - buf = String(); // clear buffer - uint32_t apCount = accesspoints.count(); - - for (uint32_t i = 0; i < apCount; i++) { - buf += String(OPEN_BRACKET) + String(DOUBLEQUOTES) + escape(accesspoints.getSSID(i)) + String(DOUBLEQUOTES) + - String(COMMA); // ["ssid", - buf += String(DOUBLEQUOTES) + escape(accesspoints.getNameStr(i)) + String(DOUBLEQUOTES) + String(COMMA); // "name", - buf += String(accesspoints.getCh(i)) + String(COMMA); // 1, - buf += String(accesspoints.getRSSI(i)) + String(COMMA); // -30, - buf += String(DOUBLEQUOTES) + accesspoints.getEncStr(i) + String(DOUBLEQUOTES) + String(COMMA); // "wpa2", - buf += String(DOUBLEQUOTES) + accesspoints.getMacStr(i) + String(DOUBLEQUOTES) + String(COMMA); // "00:11:22:00:11:22", - buf += String(DOUBLEQUOTES) + accesspoints.getVendorStr(i) + String(DOUBLEQUOTES) + String(COMMA); // "vendor", - buf += b2s(accesspoints.getSelected(i)) + String(CLOSE_BRACKET); // false] - - if (i < apCount - 1) buf += String(COMMA); // , - - if (buf.length() >= 1024) { - if (!appendFile(FILE_PATH, buf)) { - prnt(F_ERROR_SAVING); - prntln(FILE_PATH); - return; - } - - buf = String(); // clear buffer - } - } - - // Stations - buf += String(CLOSE_BRACKET) + String(COMMA) + String(DOUBLEQUOTES) + str(SC_JSON_STATIONS) + String(DOUBLEQUOTES) + - String(DOUBLEPOINT) + String(OPEN_BRACKET); // ],"stations":[; - uint32_t stationCount = stations.count(); - - for (uint32_t i = 0; i < stationCount; i++) { - buf += String(OPEN_BRACKET) + String(DOUBLEQUOTES) + stations.getMacStr(i) + String(DOUBLEQUOTES) + - String(COMMA); // ["00:11:22:00:11:22", - buf += String(stations.getCh(i)) + String(COMMA); // 1, - buf += String(DOUBLEQUOTES) + stations.getNameStr(i) + String(DOUBLEQUOTES) + String(COMMA); // "name", - buf += String(DOUBLEQUOTES) + stations.getVendorStr(i) + String(DOUBLEQUOTES) + String(COMMA); // "vendor", - buf += String(*stations.getPkts(i)) + String(COMMA); // 123, - buf += String(stations.getAP(i)) + String(COMMA); // 0, - buf += String(DOUBLEQUOTES) + stations.getTimeStr(i) + String(DOUBLEQUOTES) + String(COMMA); // "<1min", - buf += b2s(stations.getSelected(i)) + String(CLOSE_BRACKET); // false] - - if (i < stationCount - 1) buf += String(COMMA); // , - - if (buf.length() >= 1024) { - if (!appendFile(FILE_PATH, buf)) { - prnt(F_ERROR_SAVING); - prntln(FILE_PATH); - return; - } - - buf = String(); // clear buffer - } - } - - buf += String(CLOSE_BRACKET) + String(CLOSE_CURLY_BRACKET); // ]} - - if (!appendFile(FILE_PATH, buf)) { - prnt(F_ERROR_SAVING); - prntln(FILE_PATH); - return; - } - - accesspoints.changed = false; - stations.changed = false; - prnt(SC_SAVED_IN); - prntln(FILE_PATH); -} - -uint32_t Scan::countSelected() { - return accesspoints.selected() + stations.selected() + names.selected(); -} - -uint32_t Scan::countAll() { - return accesspoints.count() + stations.count() + names.count(); -} - -bool Scan::isScanning() { - return scanMode != SCAN_MODE_OFF; -} - -bool Scan::isSniffing() { - return scanMode == SCAN_MODE_STATIONS || scanMode == SCAN_MODE_SNIFFER; -} - -uint8_t Scan::getPercentage() { - if (!isSniffing()) return 0; - - return (currentTime - snifferStartTime) / (sniffTime / 100); -} - -void Scan::selectAll() { - accesspoints.selectAll(); - stations.selectAll(); - names.selectAll(); -} - -void Scan::deselectAll() { - accesspoints.deselectAll(); - stations.deselectAll(); - names.deselectAll(); -} - -void Scan::printAll() { - accesspoints.printAll(); - stations.printAll(); - names.printAll(); - ssids.printAll(); -} - -void Scan::printSelected() { - accesspoints.printSelected(); - stations.printSelected(); - names.printSelected(); -} - -uint32_t Scan::getPackets(int i) { - if (list->size() < SCAN_PACKET_LIST_SIZE) { - uint8_t translatedNum = SCAN_PACKET_LIST_SIZE - list->size(); - - if (i >= translatedNum) return list->get(i - translatedNum); - - return 0; - } else { - return list->get(i); - } -} - -double Scan::getScaleFactor(uint8_t height) { - return (double)height / (double)getMaxPacket(); -} - -uint32_t Scan::getMaxPacket() { - uint16_t max = 0; - - for (uint8_t i = 0; i < list->size(); i++) { - if (list->get(i) > max) max = list->get(i); - } - return max; -} - -uint32_t Scan::getPacketRate() { - return list->get(list->size() - 1); -} \ No newline at end of file +#include "Scan.h" + +Scan::Scan() { + list = new SimpleList; +} + +void Scan::sniffer(uint8_t* buf, uint16_t len) { + if (!isSniffing()) return; + + packets++; + + if (len < 28) return; // drop frames that are too short to have a valid MAC header + + if ((buf[12] == 0xc0) || (buf[12] == 0xa0)) { + tmpDeauths++; + return; + } + + // drop beacon frames, probe requests/responses and deauth/disassociation frames + if ((buf[12] == 0x80) || (buf[12] == 0x40) || (buf[12] == 0x50) /* || buf[12] == 0xc0 || buf[12] == 0xa0*/) return; + + // only allow data frames + // if(buf[12] != 0x08 && buf[12] != 0x88) return; + + uint8_t* macTo = &buf[16]; + uint8_t* macFrom = &buf[22]; + + if (macBroadcast(macTo) || macBroadcast(macFrom) || !macValid(macTo) || !macValid(macFrom) || macMulticast(macTo) || + macMulticast(macFrom)) return; + + int accesspointNum = findAccesspoint(macFrom); + + if (accesspointNum >= 0) { + stations.add(macTo, accesspoints.getID(accesspointNum)); + } else { + accesspointNum = findAccesspoint(macTo); + + if (accesspointNum >= 0) { + stations.add(macFrom, accesspoints.getID(accesspointNum)); + } + } +} + +int Scan::findAccesspoint(uint8_t* mac) { + for (int i = 0; i < accesspoints.count(); i++) { + if (memcmp(accesspoints.getMac(i), mac, 6) == 0) return i; + } + return -1; +} + +void Scan::start(uint8_t mode) { + start(mode, sniffTime, scan_continue_mode, continueTime, channelHop, wifi_channel); +} + +void Scan::start(uint8_t mode, uint32_t time, uint8_t nextmode, uint32_t continueTime, bool channelHop, + uint8_t channel) { + if (mode != SCAN_MODE_OFF) stop(); + + setWifiChannel(channel); + Scan::continueStartTime = currentTime; + Scan::snifferPacketTime = continueStartTime; + Scan::snifferOutputTime = continueStartTime; + Scan::continueTime = continueTime; + Scan::sniffTime = time; + Scan::channelHop = channelHop; + Scan::scanMode = mode; + Scan::scan_continue_mode = nextmode; + + if ((sniffTime > 0) && (sniffTime < 1000)) sniffTime = 1000; + + // Serial.printf("mode: %u, time: %u, continue-mode: %u, continueTime: %u, channelHop: %u, channel: %u\r\n", mode, + // time, scan_continue_mode, continueTime, channelHop, channel); + + /* AP Scan */ + if ((mode == SCAN_MODE_APS) || (mode == SCAN_MODE_ALL)) { + // remove old results + accesspoints.removeAll(); + stations.removeAll(); + // start AP scan + prntln(SC_START_AP); + WiFi.scanNetworks(true, true); + } + + /* Station Scan */ + else if (mode == SCAN_MODE_STATIONS) { + // start station scan + if (accesspoints.count() < 1) { + start(SCAN_MODE_ALL); + // Serial.println(str(SC_ERROR_NO_AP)); + return; + } + snifferStartTime = currentTime; + prnt(SC_START_CLIENT); + + if (sniffTime > 0) prnt(String(sniffTime / 1000) + S); + else prnt(SC_INFINITELY); + + if (!channelHop) { + prnt(SC_ON_CHANNEL); + prnt(wifi_channel); + } + prntln(); + + // enable sniffer + stopAP(); + wifi_promiscuous_enable(true); + } + + else if (mode == SCAN_MODE_SNIFFER) { + deauths = tmpDeauths; + tmpDeauths = 0; + snifferStartTime = currentTime; + prnt(SS_START_SNIFFER); + + if (sniffTime > 0) prnt(String(sniffTime / 1000) + S); + else prnt(SC_INFINITELY); + prnt(SC_ON_CHANNEL); + prntln(channelHop ? str(SC_ONE_TO) + (String)14 : (String)wifi_channel); + + // enable sniffer + stopAP(); + wifi_promiscuous_enable(true); + } + + /* Stop scan */ + else if (mode == SCAN_MODE_OFF) { + wifi_promiscuous_enable(false); + + if (settings.getWebInterface()) resumeAP(); + prntln(SC_STOPPED); + save(true); + + if (scan_continue_mode != SCAN_MODE_OFF) { + prnt(SC_RESTART); + prnt(int(continueTime / 1000)); + prntln(SC_CONTINUE); + } + } + + /* ERROR */ + else { + prnt(SC_ERROR_MODE); + prntln(mode); + return; + } +} + +void Scan::update() { + if (scanMode == SCAN_MODE_OFF) { + // restart scan if it is continuous + if (scan_continue_mode != SCAN_MODE_OFF) { + if (currentTime - continueStartTime > continueTime) start(scan_continue_mode); + } + return; + } + + // sniffer + if (isSniffing()) { + // update packet list every 1s + if (currentTime - snifferPacketTime > 1000) { + snifferPacketTime = currentTime; + list->add(packets); + + if (list->size() > SCAN_PACKET_LIST_SIZE) list->remove(0); + deauths = tmpDeauths; + tmpDeauths = 0; + packets = 0; + } + + // print status every 3s + if (currentTime - snifferOutputTime > 3000) { + char s[100]; + + if (sniffTime > 0) { + sprintf(s, str(SC_OUTPUT_A).c_str(), getPercentage(), packets, stations.count(), deauths); + } else { + sprintf(s, str(SC_OUTPUT_B).c_str(), packets, stations.count(), deauths); + } + prnt(String(s)); + snifferOutputTime = currentTime; + } + + // channel hopping + if (channelHop && (currentTime - snifferChannelTime > settings.getChTime())) { + snifferChannelTime = currentTime; + + if (scanMode == SCAN_MODE_STATIONS) nextChannel(); // go to next channel an AP is on + else setChannel(wifi_channel + 1); // go to next channel + } + } + + // APs + if ((scanMode == SCAN_MODE_APS) || (scanMode == SCAN_MODE_ALL)) { + int16_t results = WiFi.scanComplete(); + + if (results >= 0) { + for (int16_t i = 0; i < results && i < 256; i++) { + if (channelHop || (WiFi.channel(i) == wifi_channel)) accesspoints.add(i, false); + } + accesspoints.sort(); + accesspoints.printAll(); + + if (scanMode == SCAN_MODE_ALL) { + delay(30); + start(SCAN_MODE_STATIONS); + } + else start(SCAN_MODE_OFF); + } + } + + // Stations + else if ((sniffTime > 0) && (currentTime > snifferStartTime + sniffTime)) { + wifi_promiscuous_enable(false); + + if (scanMode == SCAN_MODE_STATIONS) { + stations.sort(); + stations.printAll(); + } + start(SCAN_MODE_OFF); + } +} + +void Scan::setup() { + save(true); +} + +void Scan::stop() { + scan_continue_mode = SCAN_MODE_OFF; + start(SCAN_MODE_OFF); +} + +void Scan::setChannel(uint8_t ch) { + if (ch > 14) ch = 1; + else if (ch < 1) ch = 14; + + wifi_promiscuous_enable(0); + setWifiChannel(ch); + wifi_promiscuous_enable(1); +} + +void Scan::nextChannel() { + if (accesspoints.count() > 1) { + uint8_t ch = wifi_channel; + + do { + ch++; + + if (ch > 14) ch = 1; + } while (!apWithChannel(ch)); + setChannel(ch); + } +} + +bool Scan::apWithChannel(uint8_t ch) { + for (int i = 0; i < accesspoints.count(); i++) + if (accesspoints.getCh(i) == ch) return true; + + return false; +} + +void Scan::save(bool force, String filePath) { + String tmp = FILE_PATH; + + FILE_PATH = filePath; + save(true); + FILE_PATH = tmp; +} + +void Scan::save(bool force) { + if (!(accesspoints.changed || stations.changed) && !force) return; + + // Accesspoints + String buf = String(OPEN_CURLY_BRACKET) + String(DOUBLEQUOTES) + str(SC_JSON_APS) + String(DOUBLEQUOTES) + String( + DOUBLEPOINT) + String(OPEN_BRACKET); // {"aps":[ + + if (!writeFile(FILE_PATH, buf)) { // overwrite old file + prnt(F_ERROR_SAVING); + prntln(FILE_PATH); + return; + } + + buf = String(); // clear buffer + uint32_t apCount = accesspoints.count(); + + for (uint32_t i = 0; i < apCount; i++) { + buf += String(OPEN_BRACKET) + String(DOUBLEQUOTES) + escape(accesspoints.getSSID(i)) + String(DOUBLEQUOTES) + + String(COMMA); // ["ssid", + buf += String(DOUBLEQUOTES) + escape(accesspoints.getNameStr(i)) + String(DOUBLEQUOTES) + String(COMMA); // "name", + buf += String(accesspoints.getCh(i)) + String(COMMA); // 1, + buf += String(accesspoints.getRSSI(i)) + String(COMMA); // -30, + buf += String(DOUBLEQUOTES) + accesspoints.getEncStr(i) + String(DOUBLEQUOTES) + String(COMMA); // "wpa2", + buf += String(DOUBLEQUOTES) + accesspoints.getMacStr(i) + String(DOUBLEQUOTES) + String(COMMA); // "00:11:22:00:11:22", + buf += String(DOUBLEQUOTES) + accesspoints.getVendorStr(i) + String(DOUBLEQUOTES) + String(COMMA); // "vendor", + buf += b2s(accesspoints.getSelected(i)) + String(CLOSE_BRACKET); // false] + + if (i < apCount - 1) buf += String(COMMA); // , + + if (buf.length() >= 1024) { + if (!appendFile(FILE_PATH, buf)) { + prnt(F_ERROR_SAVING); + prntln(FILE_PATH); + return; + } + + buf = String(); // clear buffer + } + } + + // Stations + buf += String(CLOSE_BRACKET) + String(COMMA) + String(DOUBLEQUOTES) + str(SC_JSON_STATIONS) + String(DOUBLEQUOTES) + + String(DOUBLEPOINT) + String(OPEN_BRACKET); // ],"stations":[; + uint32_t stationCount = stations.count(); + + for (uint32_t i = 0; i < stationCount; i++) { + buf += String(OPEN_BRACKET) + String(DOUBLEQUOTES) + stations.getMacStr(i) + String(DOUBLEQUOTES) + + String(COMMA); // ["00:11:22:00:11:22", + buf += String(stations.getCh(i)) + String(COMMA); // 1, + buf += String(DOUBLEQUOTES) + stations.getNameStr(i) + String(DOUBLEQUOTES) + String(COMMA); // "name", + buf += String(DOUBLEQUOTES) + stations.getVendorStr(i) + String(DOUBLEQUOTES) + String(COMMA); // "vendor", + buf += String(*stations.getPkts(i)) + String(COMMA); // 123, + buf += String(stations.getAP(i)) + String(COMMA); // 0, + buf += String(DOUBLEQUOTES) + stations.getTimeStr(i) + String(DOUBLEQUOTES) + String(COMMA); // "<1min", + buf += b2s(stations.getSelected(i)) + String(CLOSE_BRACKET); // false] + + if (i < stationCount - 1) buf += String(COMMA); // , + + if (buf.length() >= 1024) { + if (!appendFile(FILE_PATH, buf)) { + prnt(F_ERROR_SAVING); + prntln(FILE_PATH); + return; + } + + buf = String(); // clear buffer + } + } + + buf += String(CLOSE_BRACKET) + String(CLOSE_CURLY_BRACKET); // ]} + + if (!appendFile(FILE_PATH, buf)) { + prnt(F_ERROR_SAVING); + prntln(FILE_PATH); + return; + } + + accesspoints.changed = false; + stations.changed = false; + prnt(SC_SAVED_IN); + prntln(FILE_PATH); +} + +uint32_t Scan::countSelected() { + return accesspoints.selected() + stations.selected() + names.selected(); +} + +uint32_t Scan::countAll() { + return accesspoints.count() + stations.count() + names.count(); +} + +bool Scan::isScanning() { + return scanMode != SCAN_MODE_OFF; +} + +bool Scan::isSniffing() { + return scanMode == SCAN_MODE_STATIONS || scanMode == SCAN_MODE_SNIFFER; +} + +uint8_t Scan::getPercentage() { + if (!isSniffing()) return 0; + + return (currentTime - snifferStartTime) / (sniffTime / 100); +} + +void Scan::selectAll() { + accesspoints.selectAll(); + stations.selectAll(); + names.selectAll(); +} + +void Scan::deselectAll() { + accesspoints.deselectAll(); + stations.deselectAll(); + names.deselectAll(); +} + +void Scan::printAll() { + accesspoints.printAll(); + stations.printAll(); + names.printAll(); + ssids.printAll(); +} + +void Scan::printSelected() { + accesspoints.printSelected(); + stations.printSelected(); + names.printSelected(); +} + +uint32_t Scan::getPackets(int i) { + if (list->size() < SCAN_PACKET_LIST_SIZE) { + uint8_t translatedNum = SCAN_PACKET_LIST_SIZE - list->size(); + + if (i >= translatedNum) return list->get(i - translatedNum); + + return 0; + } else { + return list->get(i); + } +} + +String Scan::getMode(){ + switch(scanMode) { + case SCAN_MODE_OFF: + return String(SC_MODE_OFF); + case SCAN_MODE_APS: + return String(SC_MODE_AP); + case SCAN_MODE_STATIONS: + return String(SC_MODE_ST); + case SCAN_MODE_ALL: + return String(SC_MODE_ALL); + case SCAN_MODE_SNIFFER: + return String(SC_MODE_SNIFFER); + default: + return String(); + } +} + +double Scan::getScaleFactor(uint8_t height) { + return (double)height / (double)getMaxPacket(); +} + +uint32_t Scan::getMaxPacket() { + uint16_t max = 0; + + for (uint8_t i = 0; i < list->size(); i++) { + if (list->get(i) > max) max = list->get(i); + } + return max; +} + +uint32_t Scan::getPacketRate() { + return list->get(list->size() - 1); +} diff --git a/esp8266_deauther/Scan.h b/esp8266_deauther/Scan.h index 7d5d44e..85b979d 100644 --- a/esp8266_deauther/Scan.h +++ b/esp8266_deauther/Scan.h @@ -1,98 +1,99 @@ -#ifndef Scan_h -#define Scan_h - -#include "Arduino.h" -#include "Accesspoints.h" -#include "Stations.h" -#include "Names.h" -#include "SSIDs.h" -#include "Settings.h" -#include "language.h" -#include "SimpleList.h" - -#define SCAN_MODE_OFF 0 -#define SCAN_MODE_APS 1 -#define SCAN_MODE_STATIONS 2 -#define SCAN_MODE_ALL 3 -#define SCAN_MODE_SNIFFER 4 -#define SCAN_DEFAULT_TIME 15000 -#define SCAN_DEFAULT_CONTINUE_TIME 10000 -#define SCAN_PACKET_LIST_SIZE 64 - -extern Accesspoints accesspoints; -extern Stations stations; -extern Names names; -extern SSIDs ssids; -extern Settings settings; -extern uint8_t wifiMode; - -extern void setWifiChannel(uint8_t ch); -extern bool appendFile(String path, String& buf); -extern bool writeFile(String path, String& buf); -extern void readFileToSerial(const String path); -extern void resumeAP(); -extern void stopAP(); -extern String escape(String str); - -class Scan { - public: - Scan(); - - void sniffer(uint8_t* buf, uint16_t len); - void start(uint8_t mode, uint32_t time, uint8_t nextmode, uint32_t continueTime, bool channelHop, - uint8_t channel); - void start(uint8_t mode); - - void setup(); - void update(); - void stop(); - void save(bool force); - void save(bool force, String filePath); - - void selectAll(); - void deselectAll(); - void printAll(); - void printSelected(); - - uint8_t getPercentage(); - uint32_t getPackets(int i); - uint32_t countAll(); - uint32_t countSelected(); - bool isScanning(); - bool isSniffing(); - - void nextChannel(); - void setChannel(uint8_t newChannel); - - double getScaleFactor(uint8_t height); - uint32_t getMaxPacket(); - uint32_t getPacketRate(); - - uint16_t deauths = 0; - uint16_t packets = 0; - - private: - SimpleList* list; // packet list - - uint32_t sniffTime = SCAN_DEFAULT_TIME; // how long the scan runs - uint32_t snifferStartTime = 0; // when the scan started - uint32_t snifferOutputTime = 0; // last info output (every 3s) - uint32_t snifferChannelTime = 0; // last time the channel was changed - uint32_t snifferPacketTime = 0; // last time the packet rate was reseted (every 1s) - - uint8_t scanMode = 0; - - uint8_t scan_continue_mode = 0; // restart mode after scan stopped - uint32_t continueTime = SCAN_DEFAULT_CONTINUE_TIME; // time in ms to wait until scan restarts - uint32_t continueStartTime = 0; // when scan restarted - - bool channelHop = true; - uint16_t tmpDeauths = 0; - - bool apWithChannel(uint8_t ch); - int findAccesspoint(uint8_t* mac); - - String FILE_PATH = "/scan.json"; -}; - -#endif // ifndef Scan_h \ No newline at end of file +#ifndef Scan_h +#define Scan_h + +#include "Arduino.h" +#include "Accesspoints.h" +#include "Stations.h" +#include "Names.h" +#include "SSIDs.h" +#include "Settings.h" +#include "language.h" +#include "SimpleList.h" + +#define SCAN_MODE_OFF 0 +#define SCAN_MODE_APS 1 +#define SCAN_MODE_STATIONS 2 +#define SCAN_MODE_ALL 3 +#define SCAN_MODE_SNIFFER 4 +#define SCAN_DEFAULT_TIME 15000 +#define SCAN_DEFAULT_CONTINUE_TIME 10000 +#define SCAN_PACKET_LIST_SIZE 64 + +extern Accesspoints accesspoints; +extern Stations stations; +extern Names names; +extern SSIDs ssids; +extern Settings settings; +extern uint8_t wifiMode; + +extern void setWifiChannel(uint8_t ch); +extern bool appendFile(String path, String& buf); +extern bool writeFile(String path, String& buf); +extern void readFileToSerial(const String path); +extern void resumeAP(); +extern void stopAP(); +extern String escape(String str); + +class Scan { + public: + Scan(); + + void sniffer(uint8_t* buf, uint16_t len); + void start(uint8_t mode, uint32_t time, uint8_t nextmode, uint32_t continueTime, bool channelHop, + uint8_t channel); + void start(uint8_t mode); + + void setup(); + void update(); + void stop(); + void save(bool force); + void save(bool force, String filePath); + + void selectAll(); + void deselectAll(); + void printAll(); + void printSelected(); + + uint8_t getPercentage(); + uint32_t getPackets(int i); + uint32_t countAll(); + uint32_t countSelected(); + bool isScanning(); + bool isSniffing(); + + void nextChannel(); + void setChannel(uint8_t newChannel); + + String getMode(); + double getScaleFactor(uint8_t height); + uint32_t getMaxPacket(); + uint32_t getPacketRate(); + + uint16_t deauths = 0; + uint16_t packets = 0; + + private: + SimpleList* list; // packet list + + uint32_t sniffTime = SCAN_DEFAULT_TIME; // how long the scan runs + uint32_t snifferStartTime = 0; // when the scan started + uint32_t snifferOutputTime = 0; // last info output (every 3s) + uint32_t snifferChannelTime = 0; // last time the channel was changed + uint32_t snifferPacketTime = 0; // last time the packet rate was reseted (every 1s) + + uint8_t scanMode = 0; + + uint8_t scan_continue_mode = 0; // restart mode after scan stopped + uint32_t continueTime = SCAN_DEFAULT_CONTINUE_TIME; // time in ms to wait until scan restarts + uint32_t continueStartTime = 0; // when scan restarted + + bool channelHop = true; + uint16_t tmpDeauths = 0; + + bool apWithChannel(uint8_t ch); + int findAccesspoint(uint8_t* mac); + + String FILE_PATH = "/scan.json"; +}; + +#endif // ifndef Scan_h diff --git a/esp8266_deauther/Stations.cpp b/esp8266_deauther/Stations.cpp index 91fe73c..512c18c 100644 --- a/esp8266_deauther/Stations.cpp +++ b/esp8266_deauther/Stations.cpp @@ -100,15 +100,15 @@ void Stations::print(int num, bool header, bool footer) { prntln(ST_TABLE_DIVIDER); } - prnt(buildString(String(), (String)num, 2)); - prnt(buildString(String(SPACE) + getMacStr(num), String(), 18)); - prnt(buildString(String(SPACE), (String)getCh(num), 3)); - prnt(buildString(String(SPACE) + getNameStr(num), String(), 17)); - prnt(buildString(String(SPACE) + getVendorStr(num), String(), 9)); - prnt(buildString(String(SPACE), (String) * getPkts(num), 9)); - prnt(buildString(String(SPACE) + getAPStr(num), String(), 33)); - prnt(buildString(String(SPACE) + getTimeStr(num), String(), 10)); - prntln(buildString(String(SPACE) + getSelectedStr(num), String(), 9)); + prnt(leftRight(String(), (String)num, 2)); + prnt(leftRight(String(SPACE) + getMacStr(num), String(), 18)); + prnt(leftRight(String(SPACE), (String)getCh(num), 3)); + prnt(leftRight(String(SPACE) + getNameStr(num), String(), 17)); + prnt(leftRight(String(SPACE) + getVendorStr(num), String(), 9)); + prnt(leftRight(String(SPACE), (String) * getPkts(num), 9)); + prnt(leftRight(String(SPACE) + getAPStr(num), String(), 33)); + prnt(leftRight(String(SPACE) + getTimeStr(num), String(), 10)); + prntln(leftRight(String(SPACE) + getSelectedStr(num), String(), 9)); if (footer) prntln(ST_TABLE_DIVIDER); } diff --git a/esp8266_deauther/functions.h b/esp8266_deauther/functions.h index 0703033..b19496a 100644 --- a/esp8266_deauther/functions.h +++ b/esp8266_deauther/functions.h @@ -1,747 +1,790 @@ -#ifndef functions_h -#define functions_h - -#include "Arduino.h" -#include -extern "C" { - #include "user_interface.h" -} -#include "ArduinoJson.h" - -/* - Here is a collection of useful functions and variables. - They are used globally via an 'extern' reference in every class. - Making everything static will lead to problems with the Arduino ESP8266 2.0.0 SDK, - there were some fixed in later version but we need to use the old version for injecting deauth packets. - */ - -uint8_t broadcast[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; -uint8_t wifi_channel = 1; - -// ===== UTF8 FIX ===== // -String escape(String str) { - str.replace(String(BACKSLASH), String(BACKSLASH) + String(BACKSLASH)); - str.replace(String(DOUBLEQUOTES), String(BACKSLASH) + String(DOUBLEQUOTES)); - return str; -} - -bool ascii(char c) { - return c >= 0 && c <= 127; -} - -bool printableAscii(char c) { - return c >= 32 && c <= 126; -} - -bool getBit(uint8_t b, uint8_t n) { - return (b >> n) % 2 != 0; -} - -uint8_t utf8(uint8_t c) { - if (!getBit(c, 7)) return 1; - - if (getBit(c, 7) && getBit(c, 6) && !getBit(c, 5)) return 2; - - if (getBit(c, 7) && getBit(c, 6) && getBit(c, 5) && !getBit(c, 4)) return 3; - - if (getBit(c, 7) && getBit(c, 6) && getBit(c, 5) && getBit(c, 4) && !getBit(c, 3)) return 4; - - return 0; -} - -bool utf8Part(uint8_t c) { - return getBit(c, 7) && !getBit(c, 6); -} - -String fixUtf8(String str) { - int size = str.length(); - - String result = String(); - char c; - uint8_t len; - bool ok; - - for (int i = 0; i < size; i++) { - c = str.charAt(i); // get character - len = utf8(c); // get utf8 char len - - if (len <= 1) { - result += c; // when 1 byte char, add it :) - } - else if (i + len > size) { // when char bigger than remaining string, end loop - i = size + 1; - } - else { - ok = true; - - for (int j = 1; j < len && ok; j++) { - ok = utf8Part(str.charAt(i + j)); // if following char is compliant or not - } - - if (ok) result += c; // everything is ok, add char and continue - else { // utf8 char is broken - for (int j = 1; j < len; j++) { // go through the next bytes - c = str.charAt(i + j); - - if (utf8(c) == 1) result += c; // when byte is ascii, add it :) - } - i += len - 1; // skip utf8 char because we already managed it - } - } - } - return result; -} - -String removeUtf8(String str) { - str = fixUtf8(str); // fix it in case a utf char is broken - int size = str.length(); - - String result = String(); - char c; - uint8_t len; - - for (int i = 0; i < size; i++) { - c = str.charAt(i); // get character - len = utf8(c); // get utf8 char len - - if (len <= 1) result += c; // when 1 byte char, add it :) - else i += len - 1; // skip other chars - } - - return result; -} - -int utf8Len(String str) { - int size = str.length(); - - int result = 0; - char c; - uint8_t len; - - for (int i = 0; i < size; i++) { - c = str.charAt(i); // get character - len = utf8(c); // get utf8 char len - - if (len <= 1) result++; // when 1 byte char, add 1 :) - else { - result++; - - for (int j = 1; j < len; j++) { - c = str.charAt(i + j); - - if (!utf8Part(c) && (utf8(c) == 1)) { - Serial.println(c, HEX); - result++; // if following char is compliant or not - } - } - i += len - 1; - } - } - - return result; -} - -String replaceUtf8(String str, String r) { - str = fixUtf8(str); // fix it in case a utf char is broken - int size = str.length(); - - String result = String(); - char c; - uint8_t len; - - for (int i = 0; i < size; i++) { - c = str.charAt(i); // get character - len = utf8(c); // get utf8 char len - - if (len <= 1) result += c; // when 1 byte char, add it :) - else { - result += r; - i += len - 1; // skip other chars - } - } - - return result; -} - -// ===== LANGUAGE STRING FUNCTIONS ===== // - -// for reading Strings from the PROGMEM -String str(const char* ptr) { - char keyword[strlen_P(ptr)]; - - strcpy_P(keyword, ptr); - return String(keyword); -} - -// for converting keywords -String keyword(const char* keywordPtr) { - char keyword[strlen_P(keywordPtr)]; - - strcpy_P(keyword, keywordPtr); - - String str = ""; - uint8_t len = strlen(keyword); - uint8_t i = 0; - - while (i < len && keyword[i] != SLASH && keyword[i] != COMMA) { - str += keyword[i]; - i++; - } - - return str; -} - -// equals function -bool eqls(const char* str, const char* keywordPtr) { - if (strlen(str) > 255) return false; // when string too long - - char keyword[strlen_P(keywordPtr) + 1]; - strcpy_P(keyword, keywordPtr); - - uint8_t lenStr = strlen(str); - uint8_t lenKeyword = strlen(keyword); - - if (lenStr > lenKeyword) return false; // string can't be longer than keyword (but can be smaller because of '/' - // and ',') - - uint8_t a = 0; - uint8_t b = 0; - bool result = true; - - while (a < lenStr && b < lenKeyword) { - if ((keyword[b] == SLASH) || (keyword[b] == COMMA)) b++; - - if (tolower(str[a]) != tolower(keyword[b])) result = false; - - if (((a == lenStr) && !result) || !result) { // fast forward to next comma - while (b < lenKeyword && keyword[b] != COMMA) b++; - result = true; - a = 0; - } else { - a++; - b++; - } - } - // comparison correct AND string checked until the end AND keyword checked until the end - return result && a == lenStr && (keyword[b] == COMMA || keyword[b] == SLASH || keyword[b] == ENDOFLINE); -} - -bool eqls(String str, const char* keywordPtr) { - return eqls(str.c_str(), keywordPtr); -} - -// boolean to string -String b2s(bool input) { - return str(input ? STR_TRUE : STR_FALSE); -} - -// boolean to asterix * -String b2a(bool input) { - return input ? String(ASTERIX) : String(SPACE); -} - -// string to boolean -bool s2b(String input) { - return eqls(input, STR_TRUE); -} - -// ===== PRINT FUNCTIONS ===== // -void prnt(String s) { - Serial.print(s); -} - -void prnt(bool b) { - Serial.print(b2s(b)); -} - -void prnt(char c) { - Serial.print(c); -} - -void prnt(const char* ptr) { - Serial.print(FPSTR(ptr)); -} - -void prnt(int i) { - Serial.print((String)i); -} - -void prntln() { - Serial.println(); -} - -void prntln(String s) { - Serial.println(s); -} - -void prntln(bool b) { - Serial.println(b2s(b)); -} - -void prntln(char c) { - Serial.println(c); -} - -void prntln(const char* ptr) { - Serial.println(FPSTR(ptr)); -} - -void prntln(int i) { - Serial.println((String)i); -} - -/* ===== WiFi ===== */ -void setWifiChannel(uint8_t ch) { - if ((ch != wifi_channel) && (ch > 0) && (ch < 15)) { - wifi_channel = ch; - wifi_set_channel(wifi_channel); - } -} - -void setOutputPower(float dBm) { - if (dBm > 20.5) { - dBm = 20.5; - } else if (dBm < 0) { - dBm = 0; - } - - uint8_t val = (dBm * 4.0f); - system_phy_set_max_tpw(val); -} - -/* ===== MAC ADDRESSES ===== */ -bool macBroadcast(uint8_t* mac) { - for (uint8_t i = 0; i < 6; i++) - if (mac[i] != broadcast[i]) return false; - - return true; -} - -bool macValid(uint8_t* mac) { - for (uint8_t i = 0; i < 6; i++) - if (mac[i] != 0x00) return true; - - return false; -} - -bool macMulticast(uint8_t* mac) { - // see https://en.wikipedia.org/wiki/Multicast_address - if ((mac[0] == 0x33) && (mac[1] == 0x33)) return true; - - if ((mac[0] == 0x01) && (mac[1] == 0x80) && (mac[2] == 0xC2)) return true; - - if ((mac[0] == 0x01) && (mac[1] == 0x00) && ((mac[2] == 0x5E) || (mac[2] == 0x0C))) return true; - - if ((mac[0] == 0x01) && (mac[1] == 0x0C) && (mac[2] == 0xCD) && - ((mac[3] == 0x01) || (mac[3] == 0x02) || (mac[3] == 0x04)) && - ((mac[4] == 0x00) || (mac[4] == 0x01))) return true; - - if ((mac[0] == 0x01) && (mac[1] == 0x00) && (mac[2] == 0x0C) && (mac[3] == 0xCC) && (mac[4] == 0xCC) && - ((mac[5] == 0xCC) || (mac[5] == 0xCD))) return true; - - if ((mac[0] == 0x01) && (mac[1] == 0x1B) && (mac[2] == 0x19) && (mac[3] == 0x00) && (mac[4] == 0x00) && - (mac[5] == 0x00)) return true; - - return false; -} - -/* ===== VENDOR LIST (oui.h) ===== */ -void getRandomMac(uint8_t* mac) { - int num = random(sizeof(data_vendors) / 11 - 1); - uint8_t i; - - for (i = 0; i < 3; i++) mac[i] = pgm_read_byte_near(data_macs + num * 5 + i); - - for (i = 3; i < 6; i++) mac[i] = random(256); -} - -int binSearchVendors(uint8_t* searchBytes, int lowerEnd, int upperEnd) { - uint8_t listBytes[3]; - int res; - int mid = (lowerEnd + upperEnd) / 2; - - while (lowerEnd <= upperEnd) { - listBytes[0] = pgm_read_byte_near(data_macs + mid * 5); - listBytes[1] = pgm_read_byte_near(data_macs + mid * 5 + 1); - listBytes[2] = pgm_read_byte_near(data_macs + mid * 5 + 2); - - res = memcmp(searchBytes, listBytes, 3); - - if (res == 0) { - return mid; - } else if (res < 0) { - upperEnd = mid - 1; - mid = (lowerEnd + upperEnd) / 2; - } else if (res > 0) { - lowerEnd = mid + 1; - mid = (lowerEnd + upperEnd) / 2; - } - } - - return -1; -} - -String searchVendor(uint8_t* mac) { - String vendorName = String(); - int pos = binSearchVendors(mac, 0, sizeof(data_macs) / 5 - 1); - int realPos = pgm_read_byte_near(data_macs + pos * 5 + 3) | pgm_read_byte_near(data_macs + pos * 5 + 4) << 8; - - if (pos >= 0) { - char tmp; - - for (int i = 0; i < 8; i++) { - tmp = (char)pgm_read_byte_near(data_vendors + realPos * 8 + i); - - if (tmp != ENDOFLINE) vendorName += tmp; - tmp += SPACE; - } - } - - return vendorName; -} - -/* ===== STRING ===== */ -String bytesToStr(uint8_t* b, uint32_t size) { - String str; - - for (uint32_t i = 0; i < size; i++) { - if (b[i] < 0x10) str += ZERO; - str += String(b[i], HEX); - - if (i < size - 1) str += DOUBLEPOINT; - } - return str; -} - -String macToStr(uint8_t* mac) { - return bytesToStr(mac, 6); -} - -bool strToMac(String macStr, uint8_t* mac) { - macStr.replace(String(DOUBLEPOINT), String()); // ":" -> "" - macStr.replace("0x", String()); // "0x" -> "" - macStr.replace(String(COMMA), String()); // "," -> "" - macStr.replace(String(DOUBLEQUOTES), String()); // "\"" -> "" - macStr.toUpperCase(); - - if (macStr.length() != 12) { - prntln(F_ERROR_MAC); - return false; - } - - for (uint8_t i = 0; i < 6; i++) mac[i] = strtoul((macStr.substring(i * 2, i * 2 + 2)).c_str(), NULL, 16); - - return true; -} - -void strToColor(String str, uint8_t* buf) { - str.replace(":", ""); - str.replace("0x", ""); - str.replace(",", ""); - str.replace("#", ""); - str.toUpperCase(); - - if (str.length() != 6) { - prntln(F_COLOR_INVALID); - return; - } - - for (uint8_t i = 0; i < 3; i++) buf[i] = strtoul((str.substring(i * 2, i * 2 + 2)).c_str(), NULL, 16); -} - -String buildString(String left, String right, int maxLen) { - String result = left; - int spacesToAdd = maxLen - left.length() /*utf8Len(left)*/ - right.length() /*utf8Len(right)*/; - - for (int i = 0; i < spacesToAdd; i++) { - result += SPACE; - } - result += right; - return result; -} - -/* ===== SPIFFS ===== */ -bool progmemToSpiffs(const char* adr, int len, String path) { - prnt(str(SETUP_COPYING) + path + str(SETUP_PROGMEM_TO_SPIFFS)); - File f = SPIFFS.open(path, "w+"); - - if (!f) { - prntln(SETUP_ERROR); - return false; - } - - for (int i = 0; i < len; i++) { - f.write(pgm_read_byte_near(adr + i)); - } - f.close(); - - prntln(SETUP_OK); - - return true; -} - -bool readFile(String path, String& buf) { - if (path.charAt(0) != SLASH) path = String(SLASH) + path; - File f = SPIFFS.open(path, "r"); - - if (!f) return false; - - if (f.size() == 0) return false; - - while (f.available()) buf += (char)f.read(); - - f.close(); - - return true; -} - -void readFileToSerial(String path, bool showLineNum) { - if (path.charAt(0) != SLASH) path = String(SLASH) + path; - File f = SPIFFS.open(path, "r"); - - if (!f) { - prnt(F_ERROR_READING_FILE); - prntln(path); - return; - } - - uint32_t c = 0; - char tmp; - - if (showLineNum) { - prnt(buildString(String(), (String)c + String(VERTICALBAR), 6)); - } - - while (f.available()) { - tmp = f.read(); - prnt(tmp); - - if ((tmp == NEWLINE) && showLineNum) { - c++; - prnt(buildString(String(), (String)c + String(VERTICALBAR), 6)); - } - } - - f.close(); -} - -bool copyFile(String pathFrom, String pathTo) { - if (pathFrom.charAt(0) != SLASH) pathFrom = String(SLASH) + pathFrom; - - if (pathTo.charAt(0) != SLASH) pathTo = String(SLASH) + pathTo; - - if (!SPIFFS.exists(pathFrom)) { - prnt(F_ERROR_FILE); - prntln(pathFrom); - return false; - } - - File f1 = SPIFFS.open(pathFrom, "r"); - File f2 = SPIFFS.open(pathTo, "w+"); - - if (!f1 || !f2) return false; - - while (f1.available()) { - f2.write(f1.read()); - } - - return true; -} - -bool renameFile(String pathFrom, String pathTo) { - if (pathFrom.charAt(0) != SLASH) pathFrom = String(SLASH) + pathFrom; - - if (pathTo.charAt(0) != SLASH) pathTo = String(SLASH) + pathTo; - - if (!SPIFFS.exists(pathFrom)) { - prnt(F_ERROR_FILE); - prntln(pathFrom); - return false; - } - - SPIFFS.rename(pathFrom, pathTo); - return true; -} - -bool writeFile(String path, String& buf) { - if (path.charAt(0) != SLASH) path = String(SLASH) + path; - File f = SPIFFS.open(path, "w+"); - - if (!f) return false; - - uint32_t len = buf.length(); - - for (uint32_t i = 0; i < len; i++) f.write(buf.charAt(i)); - f.close(); - - return true; -} - -bool appendFile(String path, String& buf) { - if (path.charAt(0) != SLASH) path = String(SLASH) + path; - File f = SPIFFS.open(path, "a+"); - - if (!f) return false; - - uint32_t len = buf.length(); - - for (uint32_t i = 0; i < len; i++) f.write(buf[i]); - f.close(); - - return true; -} - -void checkFile(String path, String data) { - if (path.charAt(0) != SLASH) path = String(SLASH) + path; - - if (!SPIFFS.exists(path)) writeFile(path, data); -} - -bool removeLines(String path, int lineFrom, int lineTo) { - int c = 0; - char tmp; - - if (path.charAt(0) != SLASH) path = String(SLASH) + path; - - String tmpPath = str(F_TMP) + path + str(F_COPY); - - File f = SPIFFS.open(path, "r"); - File f2 = SPIFFS.open(tmpPath, "w"); - - if (!f || !f2) return false; - - while (f.available()) { - tmp = f.read(); - - if ((c < lineFrom) || (c > lineTo)) f2.write(tmp); - - if (tmp == NEWLINE) c++; - } - - f.close(); - f2.close(); - SPIFFS.remove(path); - SPIFFS.rename(tmpPath, path); - - return true; -} - -bool replaceLine(String path, int line, String& buf) { - int c = 0; - char tmp; - - if (path.charAt(0) != SLASH) path = String(SLASH) + path; - - String tmpPath = "/tmp" + path + "_copy"; - - File f = SPIFFS.open(path, "r"); - File f2 = SPIFFS.open(tmpPath, "w"); - - if (!f || !f2) return false; - - while (f.available()) { - tmp = f.read(); - - if (c != line) f2.write(tmp); - else { - f2.println(buf); - - while (f.read() != NEWLINE && f.available()) {} - c++; - } - - if (tmp == NEWLINE) c++; - } - - f.close(); - f2.close(); - SPIFFS.remove(path); - SPIFFS.rename(tmpPath, path); - - return true; -} - -JsonVariant parseJSONFile(String path, DynamicJsonBuffer& jsonBuffer) { - if (path.charAt(0) != SLASH) path = String(SLASH) + path; - - // create JSON Variant - JsonVariant root; - - // create buffer - String buf = ""; - - // read file into buffer - if (!readFile(path, buf)) { // if file couldn't be opened, send 404 error - prnt(F_ERROR_OPEN); - prntln(path); - buf = "{}"; - } - - // parse file-buffer into a JSON Variant - root = jsonBuffer.parse(buf); - - // if parsing unsuccessful - if (!root.success()) { - prnt(F_ERROR_PARSING_JSON); - prntln(path); - prntln(buf); - } - - return root; -} - -bool removeFile(String path) { - if (path.charAt(0) != SLASH) path = String(SLASH) + path; - return SPIFFS.remove(path); -} - -void saveJSONFile(String path, JsonObject& root) { - if (path.charAt(0) != SLASH) path = String(SLASH) + path; - - // create buffer - String buf; - - // convert JSON object into string and write it into buffer - root.printTo(buf); - - // if buffer too big - if (buf.length() > 2048) { - prntln(F_ERROR_TO_BIG); - prntln(path); - prntln(buf); - return; - } - - // write buffer into SPIFFS file - writeFile(path, buf); -} - -void saveJSONFile(String path, JsonArray& root) { - if (path.charAt(0) != SLASH) path = String(SLASH) + path; - - // create buffer - String buf; - - // convert JSON object into string and write it into buffer - root.printTo(buf); - - // if buffer too big - if (buf.length() > 2048) { - prntln(F_ERROR_TO_BIG); - prntln(path); - prntln(buf); - return; - } - - // write buffer into SPIFFS file - writeFile(path, buf); -} - -String formatBytes(size_t bytes) { - if (bytes < 1024) return String(bytes) + "B"; - else if (bytes < (1024 * 1024)) return String(bytes / 1024.0) + "KB"; - else if (bytes < (1024 * 1024 * 1024)) return String(bytes / 1024.0 / 1024.0) + "MB"; - else return String(bytes / 1024.0 / 1024.0 / 1024.0) + "GB"; -} - -#endif // ifndef functions_h \ No newline at end of file +#ifndef functions_h +#define functions_h + +#include "Arduino.h" +#include +extern "C" { + #include "user_interface.h" +} +#include "ArduinoJson.h" + +/* + Here is a collection of useful functions and variables. + They are used globally via an 'extern' reference in every class. + Making everything static will lead to problems with the Arduino ESP8266 2.0.0 SDK, + there were some fixed in later version but we need to use the old version for injecting deauth packets. + */ + +uint8_t broadcast[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; +uint8_t wifi_channel = 1; + +// ===== UTF8 FIX ===== // +String escape(String str) { + str.replace(String(BACKSLASH), String(BACKSLASH) + String(BACKSLASH)); + str.replace(String(DOUBLEQUOTES), String(BACKSLASH) + String(DOUBLEQUOTES)); + return str; +} + +bool ascii(char c) { + return c >= 0 && c <= 127; +} + +bool printableAscii(char c) { + return c >= 32 && c <= 126; +} + +bool getBit(uint8_t b, uint8_t n) { + return (b >> n) % 2 != 0; +} + +uint8_t utf8(uint8_t c) { + if (!getBit(c, 7)) return 1; + + if (getBit(c, 7) && getBit(c, 6) && !getBit(c, 5)) return 2; + + if (getBit(c, 7) && getBit(c, 6) && getBit(c, 5) && !getBit(c, 4)) return 3; + + if (getBit(c, 7) && getBit(c, 6) && getBit(c, 5) && getBit(c, 4) && !getBit(c, 3)) return 4; + + return 0; +} + +bool utf8Part(uint8_t c) { + return getBit(c, 7) && !getBit(c, 6); +} + +String fixUtf8(String str) { + int size = str.length(); + + String result = String(); + char c; + uint8_t len; + bool ok; + + for (int i = 0; i < size; i++) { + c = str.charAt(i); // get character + len = utf8(c); // get utf8 char len + + if (len <= 1) { + result += c; // when 1 byte char, add it :) + } + else if (i + len > size) { // when char bigger than remaining string, end loop + i = size + 1; + } + else { + ok = true; + + for (int j = 1; j < len && ok; j++) { + ok = utf8Part(str.charAt(i + j)); // if following char is compliant or not + } + + if (ok) result += c; // everything is ok, add char and continue + else { // utf8 char is broken + for (int j = 1; j < len; j++) { // go through the next bytes + c = str.charAt(i + j); + + if (utf8(c) == 1) result += c; // when byte is ascii, add it :) + } + i += len - 1; // skip utf8 char because we already managed it + } + } + } + return result; +} + +String removeUtf8(String str) { + str = fixUtf8(str); // fix it in case a utf char is broken + int size = str.length(); + + String result = String(); + char c; + uint8_t len; + + for (int i = 0; i < size; i++) { + c = str.charAt(i); // get character + len = utf8(c); // get utf8 char len + + if (len <= 1) result += c; // when 1 byte char, add it :) + else i += len - 1; // skip other chars + } + + return result; +} + +int utf8Len(String str) { + int size = str.length(); + + int result = 0; + char c; + uint8_t len; + + for (int i = 0; i < size; i++) { + c = str.charAt(i); // get character + len = utf8(c); // get utf8 char len + + if (len <= 1) result++; // when 1 byte char, add 1 :) + else { + result++; + + for (int j = 1; j < len; j++) { + c = str.charAt(i + j); + + if (!utf8Part(c) && (utf8(c) == 1)) { + Serial.println(c, HEX); + result++; // if following char is compliant or not + } + } + i += len - 1; + } + } + + return result; +} + +String replaceUtf8(String str, String r) { + str = fixUtf8(str); // fix it in case a utf char is broken + int size = str.length(); + + String result = String(); + char c; + uint8_t len; + + for (int i = 0; i < size; i++) { + c = str.charAt(i); // get character + len = utf8(c); // get utf8 char len + + if (len <= 1) result += c; // when 1 byte char, add it :) + else { + result += r; + i += len - 1; // skip other chars + } + } + + return result; +} + +// ===== LANGUAGE STRING FUNCTIONS ===== // + +// for reading Strings from the PROGMEM +String str(const char* ptr) { + char keyword[strlen_P(ptr)]; + + strcpy_P(keyword, ptr); + return String(keyword); +} + +// for converting keywords +String keyword(const char* keywordPtr) { + char keyword[strlen_P(keywordPtr)]; + + strcpy_P(keyword, keywordPtr); + + String str = ""; + uint8_t len = strlen(keyword); + uint8_t i = 0; + + while (i < len && keyword[i] != SLASH && keyword[i] != COMMA) { + str += keyword[i]; + i++; + } + + return str; +} + +// equals function +bool eqls(const char* str, const char* keywordPtr) { + if (strlen(str) > 255) return false; // when string too long + + char keyword[strlen_P(keywordPtr) + 1]; + strcpy_P(keyword, keywordPtr); + + uint8_t lenStr = strlen(str); + uint8_t lenKeyword = strlen(keyword); + + if (lenStr > lenKeyword) return false; // string can't be longer than keyword (but can be smaller because of '/' + // and ',') + + uint8_t a = 0; + uint8_t b = 0; + bool result = true; + + while (a < lenStr && b < lenKeyword) { + if ((keyword[b] == SLASH) || (keyword[b] == COMMA)) b++; + + if (tolower(str[a]) != tolower(keyword[b])) result = false; + + if (((a == lenStr) && !result) || !result) { // fast forward to next comma + while (b < lenKeyword && keyword[b] != COMMA) b++; + result = true; + a = 0; + } else { + a++; + b++; + } + } + // comparison correct AND string checked until the end AND keyword checked until the end + return result && a == lenStr && (keyword[b] == COMMA || keyword[b] == SLASH || keyword[b] == ENDOFLINE); +} + +bool eqls(String str, const char* keywordPtr) { + return eqls(str.c_str(), keywordPtr); +} + +// boolean to string +String b2s(bool input) { + return str(input ? STR_TRUE : STR_FALSE); +} + +// boolean to asterix * +String b2a(bool input) { + return input ? String(ASTERIX) : String(SPACE); +} + +// string to boolean +bool s2b(String input) { + return eqls(input, STR_TRUE); +} + +// ===== PRINT FUNCTIONS ===== // +void prnt(String s) { + Serial.print(s); +} + +void prnt(bool b) { + Serial.print(b2s(b)); +} + +void prnt(char c) { + Serial.print(c); +} + +void prnt(const char* ptr) { + Serial.print(FPSTR(ptr)); +} + +void prnt(int i) { + Serial.print((String)i); +} + +void prntln() { + Serial.println(); +} + +void prntln(String s) { + Serial.println(s); +} + +void prntln(bool b) { + Serial.println(b2s(b)); +} + +void prntln(char c) { + Serial.println(c); +} + +void prntln(const char* ptr) { + Serial.println(FPSTR(ptr)); +} + +void prntln(int i) { + Serial.println((String)i); +} + +/* ===== WiFi ===== */ +void setWifiChannel(uint8_t ch) { + if ((ch != wifi_channel) && (ch > 0) && (ch < 15)) { + wifi_channel = ch; + wifi_set_channel(wifi_channel); + } +} + +void setOutputPower(float dBm) { + if (dBm > 20.5) { + dBm = 20.5; + } else if (dBm < 0) { + dBm = 0; + } + + uint8_t val = (dBm * 4.0f); + system_phy_set_max_tpw(val); +} + +/* ===== MAC ADDRESSES ===== */ +bool macBroadcast(uint8_t* mac) { + for (uint8_t i = 0; i < 6; i++) + if (mac[i] != broadcast[i]) return false; + + return true; +} + +bool macValid(uint8_t* mac) { + for (uint8_t i = 0; i < 6; i++) + if (mac[i] != 0x00) return true; + + return false; +} + +bool macMulticast(uint8_t* mac) { + // see https://en.wikipedia.org/wiki/Multicast_address + if ((mac[0] == 0x33) && (mac[1] == 0x33)) return true; + + if ((mac[0] == 0x01) && (mac[1] == 0x80) && (mac[2] == 0xC2)) return true; + + if ((mac[0] == 0x01) && (mac[1] == 0x00) && ((mac[2] == 0x5E) || (mac[2] == 0x0C))) return true; + + if ((mac[0] == 0x01) && (mac[1] == 0x0C) && (mac[2] == 0xCD) && + ((mac[3] == 0x01) || (mac[3] == 0x02) || (mac[3] == 0x04)) && + ((mac[4] == 0x00) || (mac[4] == 0x01))) return true; + + if ((mac[0] == 0x01) && (mac[1] == 0x00) && (mac[2] == 0x0C) && (mac[3] == 0xCC) && (mac[4] == 0xCC) && + ((mac[5] == 0xCC) || (mac[5] == 0xCD))) return true; + + if ((mac[0] == 0x01) && (mac[1] == 0x1B) && (mac[2] == 0x19) && (mac[3] == 0x00) && (mac[4] == 0x00) && + (mac[5] == 0x00)) return true; + + return false; +} + +/* ===== VENDOR LIST (oui.h) ===== */ +void getRandomMac(uint8_t* mac) { + int num = random(sizeof(data_vendors) / 11 - 1); + uint8_t i; + + for (i = 0; i < 3; i++) mac[i] = pgm_read_byte_near(data_macs + num * 5 + i); + + for (i = 3; i < 6; i++) mac[i] = random(256); +} + +int binSearchVendors(uint8_t* searchBytes, int lowerEnd, int upperEnd) { + uint8_t listBytes[3]; + int res; + int mid = (lowerEnd + upperEnd) / 2; + + while (lowerEnd <= upperEnd) { + listBytes[0] = pgm_read_byte_near(data_macs + mid * 5); + listBytes[1] = pgm_read_byte_near(data_macs + mid * 5 + 1); + listBytes[2] = pgm_read_byte_near(data_macs + mid * 5 + 2); + + res = memcmp(searchBytes, listBytes, 3); + + if (res == 0) { + return mid; + } else if (res < 0) { + upperEnd = mid - 1; + mid = (lowerEnd + upperEnd) / 2; + } else if (res > 0) { + lowerEnd = mid + 1; + mid = (lowerEnd + upperEnd) / 2; + } + } + + return -1; +} + +String searchVendor(uint8_t* mac) { + String vendorName = String(); + int pos = binSearchVendors(mac, 0, sizeof(data_macs) / 5 - 1); + int realPos = pgm_read_byte_near(data_macs + pos * 5 + 3) | pgm_read_byte_near(data_macs + pos * 5 + 4) << 8; + + if (pos >= 0) { + char tmp; + + for (int i = 0; i < 8; i++) { + tmp = (char)pgm_read_byte_near(data_vendors + realPos * 8 + i); + + if (tmp != ENDOFLINE) vendorName += tmp; + tmp += SPACE; + } + } + + return vendorName; +} + +/* ===== STRING ===== */ +String bytesToStr(uint8_t* b, uint32_t size) { + String str; + + for (uint32_t i = 0; i < size; i++) { + if (b[i] < 0x10) str += ZERO; + str += String(b[i], HEX); + + if (i < size - 1) str += DOUBLEPOINT; + } + return str; +} + +String macToStr(uint8_t* mac) { + return bytesToStr(mac, 6); +} + +bool strToMac(String macStr, uint8_t* mac) { + macStr.replace(String(DOUBLEPOINT), String()); // ":" -> "" + macStr.replace("0x", String()); // "0x" -> "" + macStr.replace(String(COMMA), String()); // "," -> "" + macStr.replace(String(DOUBLEQUOTES), String()); // "\"" -> "" + macStr.toUpperCase(); + + if (macStr.length() != 12) { + prntln(F_ERROR_MAC); + return false; + } + + for (uint8_t i = 0; i < 6; i++) mac[i] = strtoul((macStr.substring(i * 2, i * 2 + 2)).c_str(), NULL, 16); + + return true; +} + +void strToColor(String str, uint8_t* buf) { + str.replace(":", ""); + str.replace("0x", ""); + str.replace(",", ""); + str.replace("#", ""); + str.toUpperCase(); + + if (str.length() != 6) { + prntln(F_COLOR_INVALID); + return; + } + + for (uint8_t i = 0; i < 3; i++) buf[i] = strtoul((str.substring(i * 2, i * 2 + 2)).c_str(), NULL, 16); +} + + +String center(String a, int len) { + int spaces = len - a.length(); + + for (int i = 0; i < spaces; i+=2) { + a = ' ' + a + ' '; + } + + a = a.substring(0, len); + + return a; +} + +String left(String a, int len) { + int spaces = len - a.length(); + + while (spaces > 0) { + a = a + ' '; + spaces--; + } + + a = a.substring(0, len); + + return a; +} + +String right(String a, int len) { + int spaces = len - a.length(); + + while (spaces > 0) { + a = ' ' + a; + spaces--; + } + + a = a.substring(0, len); + + return a; +} + +String leftRight(String a, String b, int len) { + int spaces = len - a.length() - b.length(); + + while (spaces > 0) { + a = a + ' '; + spaces--; + } + + a = a + b; + + a = a.substring(0, len); + + return a; +} + +/* ===== SPIFFS ===== */ +bool progmemToSpiffs(const char* adr, int len, String path) { + prnt(str(SETUP_COPYING) + path + str(SETUP_PROGMEM_TO_SPIFFS)); + File f = SPIFFS.open(path, "w+"); + + if (!f) { + prntln(SETUP_ERROR); + return false; + } + + for (int i = 0; i < len; i++) { + f.write(pgm_read_byte_near(adr + i)); + } + f.close(); + + prntln(SETUP_OK); + + return true; +} + +bool readFile(String path, String& buf) { + if (path.charAt(0) != SLASH) path = String(SLASH) + path; + File f = SPIFFS.open(path, "r"); + + if (!f) return false; + + if (f.size() == 0) return false; + + while (f.available()) buf += (char)f.read(); + + f.close(); + + return true; +} + +void readFileToSerial(String path, bool showLineNum) { + if (path.charAt(0) != SLASH) path = String(SLASH) + path; + File f = SPIFFS.open(path, "r"); + + if (!f) { + prnt(F_ERROR_READING_FILE); + prntln(path); + return; + } + + uint32_t c = 0; + char tmp; + + if (showLineNum) { + prnt(leftRight(String(), (String)c + String(VERTICALBAR), 6)); + } + + while (f.available()) { + tmp = f.read(); + prnt(tmp); + + if ((tmp == NEWLINE) && showLineNum) { + c++; + prnt(leftRight(String(), (String)c + String(VERTICALBAR), 6)); + } + } + + f.close(); +} + +bool copyFile(String pathFrom, String pathTo) { + if (pathFrom.charAt(0) != SLASH) pathFrom = String(SLASH) + pathFrom; + + if (pathTo.charAt(0) != SLASH) pathTo = String(SLASH) + pathTo; + + if (!SPIFFS.exists(pathFrom)) { + prnt(F_ERROR_FILE); + prntln(pathFrom); + return false; + } + + File f1 = SPIFFS.open(pathFrom, "r"); + File f2 = SPIFFS.open(pathTo, "w+"); + + if (!f1 || !f2) return false; + + while (f1.available()) { + f2.write(f1.read()); + } + + return true; +} + +bool renameFile(String pathFrom, String pathTo) { + if (pathFrom.charAt(0) != SLASH) pathFrom = String(SLASH) + pathFrom; + + if (pathTo.charAt(0) != SLASH) pathTo = String(SLASH) + pathTo; + + if (!SPIFFS.exists(pathFrom)) { + prnt(F_ERROR_FILE); + prntln(pathFrom); + return false; + } + + SPIFFS.rename(pathFrom, pathTo); + return true; +} + +bool writeFile(String path, String& buf) { + if (path.charAt(0) != SLASH) path = String(SLASH) + path; + File f = SPIFFS.open(path, "w+"); + + if (!f) return false; + + uint32_t len = buf.length(); + + for (uint32_t i = 0; i < len; i++) f.write(buf.charAt(i)); + f.close(); + + return true; +} + +bool appendFile(String path, String& buf) { + if (path.charAt(0) != SLASH) path = String(SLASH) + path; + File f = SPIFFS.open(path, "a+"); + + if (!f) return false; + + uint32_t len = buf.length(); + + for (uint32_t i = 0; i < len; i++) f.write(buf[i]); + f.close(); + + return true; +} + +void checkFile(String path, String data) { + if (path.charAt(0) != SLASH) path = String(SLASH) + path; + + if (!SPIFFS.exists(path)) writeFile(path, data); +} + +bool removeLines(String path, int lineFrom, int lineTo) { + int c = 0; + char tmp; + + if (path.charAt(0) != SLASH) path = String(SLASH) + path; + + String tmpPath = str(F_TMP) + path + str(F_COPY); + + File f = SPIFFS.open(path, "r"); + File f2 = SPIFFS.open(tmpPath, "w"); + + if (!f || !f2) return false; + + while (f.available()) { + tmp = f.read(); + + if ((c < lineFrom) || (c > lineTo)) f2.write(tmp); + + if (tmp == NEWLINE) c++; + } + + f.close(); + f2.close(); + SPIFFS.remove(path); + SPIFFS.rename(tmpPath, path); + + return true; +} + +bool replaceLine(String path, int line, String& buf) { + int c = 0; + char tmp; + + if (path.charAt(0) != SLASH) path = String(SLASH) + path; + + String tmpPath = "/tmp" + path + "_copy"; + + File f = SPIFFS.open(path, "r"); + File f2 = SPIFFS.open(tmpPath, "w"); + + if (!f || !f2) return false; + + while (f.available()) { + tmp = f.read(); + + if (c != line) f2.write(tmp); + else { + f2.println(buf); + + while (f.read() != NEWLINE && f.available()) {} + c++; + } + + if (tmp == NEWLINE) c++; + } + + f.close(); + f2.close(); + SPIFFS.remove(path); + SPIFFS.rename(tmpPath, path); + + return true; +} + +JsonVariant parseJSONFile(String path, DynamicJsonBuffer& jsonBuffer) { + if (path.charAt(0) != SLASH) path = String(SLASH) + path; + + // create JSON Variant + JsonVariant root; + + // create buffer + String buf = ""; + + // read file into buffer + if (!readFile(path, buf)) { // if file couldn't be opened, send 404 error + prnt(F_ERROR_OPEN); + prntln(path); + buf = "{}"; + } + + // parse file-buffer into a JSON Variant + root = jsonBuffer.parse(buf); + + // if parsing unsuccessful + if (!root.success()) { + prnt(F_ERROR_PARSING_JSON); + prntln(path); + prntln(buf); + } + + return root; +} + +bool removeFile(String path) { + if (path.charAt(0) != SLASH) path = String(SLASH) + path; + return SPIFFS.remove(path); +} + +void saveJSONFile(String path, JsonObject& root) { + if (path.charAt(0) != SLASH) path = String(SLASH) + path; + + // create buffer + String buf; + + // convert JSON object into string and write it into buffer + root.printTo(buf); + + // if buffer too big + if (buf.length() > 2048) { + prntln(F_ERROR_TO_BIG); + prntln(path); + prntln(buf); + return; + } + + // write buffer into SPIFFS file + writeFile(path, buf); +} + +void saveJSONFile(String path, JsonArray& root) { + if (path.charAt(0) != SLASH) path = String(SLASH) + path; + + // create buffer + String buf; + + // convert JSON object into string and write it into buffer + root.printTo(buf); + + // if buffer too big + if (buf.length() > 2048) { + prntln(F_ERROR_TO_BIG); + prntln(path); + prntln(buf); + return; + } + + // write buffer into SPIFFS file + writeFile(path, buf); +} + +String formatBytes(size_t bytes) { + if (bytes < 1024) return String(bytes) + "B"; + else if (bytes < (1024 * 1024)) return String(bytes / 1024.0) + "KB"; + else if (bytes < (1024 * 1024 * 1024)) return String(bytes / 1024.0 / 1024.0) + "MB"; + else return String(bytes / 1024.0 / 1024.0 / 1024.0) + "GB"; +} + +#endif // ifndef functions_h diff --git a/esp8266_deauther/language.h b/esp8266_deauther/language.h index 139a084..dc1455d 100644 --- a/esp8266_deauther/language.h +++ b/esp8266_deauther/language.h @@ -268,11 +268,12 @@ const char D_MSG_DISPLAY_OFF[] PROGMEM = "Turned display off"; const char D_MSG_DISPLAY_ON[] PROGMEM = "Turned display on"; // LOADING SCREEN -const char D_LOADING_SCREEN_0[] PROGMEM = "Scanning..."; -const char D_LOADING_SCREEN_1[] PROGMEM = "APs: "; -const char D_LOADING_SCREEN_2[] PROGMEM = "Stations: "; -const char D_LOADING_SCREEN_3[] PROGMEM = "Searching for"; -const char D_LOADING_SCREEN_4[] PROGMEM = "Access Points..."; +const char DSP_SCAN_FOR[] PROGMEM = "Scan for"; +const char DSP_APS[] PROGMEM = "APs"; +const char DSP_STS[] PROGMEM = "STs"; +const char DSP_PKTS[] PROGMEM = "Pkts"; +const char DSP_S[] PROGMEM = "/s"; +const char DSP_SCAN_DONE[] PROGMEM = "Done"; // ALL MENUS const char D_BACK[] PROGMEM = "[BACK]"; @@ -325,10 +326,10 @@ const char D_STOP_ATTACK[] PROGMEM = "STOP"; const char D_ENCRYPTION[] PROGMEM = "Encryption:"; const char D_RSSI[] PROGMEM = "RSSI:"; const char D_CHANNEL[] PROGMEM = "Channel:"; -const char D_CH[] PROGMEM = "CH:"; +const char D_CH[] PROGMEM = "Ch"; const char D_VENDOR[] PROGMEM = "Vendor:"; const char D_AP[] PROGMEM = "AP:"; -const char D_PKTS[] PROGMEM = "Pkts:"; +const char D_PKTS[] PROGMEM = "pkts"; const char D_SEEN[] PROGMEM = "Seen:"; // ===== STATIONS ===== // @@ -388,7 +389,7 @@ const char S_ERROR_VERSION[] PROGMEM = "Sorry, you can't change the version numb const char S_ERROR_NOT_FOUND[] PROGMEM = "ERROR: No setting found for "; const char S_CHANGED_SETTING[] PROGMEM = "Changed setting "; const char S_CHANNEL_CHANGE[] PROGMEM = "Switched to Channel "; -const char S_CHANNEL_ERROR[] PROGMEM = "ERROR: Channel must be between 1 and "; +const char S_CHANNEL_ERROR[] PROGMEM = "ERROR: Channel must be between 1 and 14"; const char S_ERROR_SSID_LEN[] PROGMEM = "ERROR: SSID must be between 1 and 32 characters"; const char S_ERROR_PASSWORD_LEN[] PROGMEM = "ERROR: Password must be between 8 and 32 characters"; const char S_RANDOM[] PROGMEM = "random"; @@ -492,6 +493,11 @@ const char SC_JSON_STATIONS[] PROGMEM = "stations"; const char SC_JSON_NAMES[] PROGMEM = "names"; const char SC_SAVED[] PROGMEM = "Saved scan results"; const char SC_SAVED_IN[] PROGMEM = "Scan results saved in "; +const char SC_MODE_OFF[] PROGMEM = "-"; +const char SC_MODE_AP[] PROGMEM = "APs"; +const char SC_MODE_ST[] PROGMEM = "STs"; +const char SC_MODE_ALL[] PROGMEM = "AP+ST"; +const char SC_MODE_SNIFFER[] PROGMEM = "Sniffer"; // ===== FUNCTIONS ===== // const char F_ERROR_MAC[] PROGMEM = "ERROR: MAC address invalid";