Files
crosspoint-reader/src/WifiCredentialStore.cpp

163 lines
5.3 KiB
C++
Raw Normal View History

Add connect to Wifi and File Manager Webserver (#41) ## Summary - **What is the goal of this PR?** Implements wireless EPUB file management via a built-in web server, enabling users to upload, browse, organize, and delete EPUB files from any device on the same WiFi network without needing a computer cable connection. - **What changes are included?** - **New Web Server** ([`CrossPointWebServer.cpp`](src/CrossPointWebServer.cpp), [`CrossPointWebServer.h`](src/CrossPointWebServer.h)): - HTTP server on port 80 with a responsive HTML/CSS interface - Home page showing device status (version, IP, free memory) - File Manager with folder navigation and breadcrumb support - EPUB file upload with progress tracking - Folder creation and file/folder deletion - XSS protection via HTML escaping - Hidden system folders (`.` prefixed, "System Volume Information", "XTCache") - **WiFi Screen** ([`WifiScreen.cpp`](src/screens/WifiScreen.cpp), [`WifiScreen.h`](src/screens/WifiScreen.h)): - Network scanning with signal strength indicators - Visual indicators for encrypted (`*`) and saved (`+`) networks - State machine managing: scanning, network selection, password entry, connecting, save/forget prompts - 15-second connection timeout handling - Integration with web server (starts on connect, stops on exit) - **WiFi Credential Storage** ([`WifiCredentialStore.cpp`](src/WifiCredentialStore.cpp), [`WifiCredentialStore.h`](src/WifiCredentialStore.h)): - Persistent storage in `/sd/.crosspoint/wifi.bin` - XOR obfuscation for stored passwords (basic protection against casual reading) - Up to 8 saved networks with add/remove/update operations - **On-Screen Keyboard** ([`OnScreenKeyboard.cpp`](src/screens/OnScreenKeyboard.cpp), [`OnScreenKeyboard.h`](src/screens/OnScreenKeyboard.h)): - Reusable QWERTY keyboard component with shift support - Special keys: Shift, Space, Backspace, Done - Support for password masking mode - **Settings Screen Integration** ([`SettingsScreen.h`](src/screens/SettingsScreen.h)): - Added WiFi action to navigate to the new WiFi screen - **Documentation** ([`docs/webserver.md`](docs/webserver.md)): - Comprehensive user guide covering WiFi setup, web interface usage, file management, troubleshooting, and security notes - See this for more screenshots! - Working "displays the right way in GitHub" on my repo: https://github.com/olearycrew/crosspoint-reader/blob/feature/connect-to-wifi/docs/webserver.md **Video demo** https://github.com/user-attachments/assets/283e32dc-2d9f-4ae2-848e-01f41166a731 ## Additional Context - **Security considerations**: The web server has no authentication—anyone on the same WiFi network can access files. This is documented as a limitation, recommending use only on trusted private networks. Password obfuscation in the credential store is XOR-based, not cryptographically secure. - **Memory implications**: The web server and WiFi stack consume significant memory. The implementation properly cleans up (stops server, disconnects WiFi, sets `WIFI_OFF` mode) when exiting the WiFi screen to free resources. - **Async operations**: Network scanning and connection use async patterns with FreeRTOS tasks to prevent blocking the UI. The display task handles rendering on a dedicated thread with mutex protection. - **Browser compatibility**: The web interface uses standard HTML5/CSS3/JavaScript and is tested to work with all modern browsers on desktop and mobile. --------- Co-authored-by: Dave Allie <dave@daveallie.com>
2025-12-19 09:05:43 -05:00
#include "WifiCredentialStore.h"
#include <HardwareSerial.h>
#include <SD.h>
#include <Serialization.h>
#include <fstream>
// Initialize the static instance
WifiCredentialStore WifiCredentialStore::instance;
namespace {
// File format version
constexpr uint8_t WIFI_FILE_VERSION = 1;
// WiFi credentials file path
constexpr char WIFI_FILE[] = "/sd/.crosspoint/wifi.bin";
// Obfuscation key - "CrossPoint" in ASCII
// This is NOT cryptographic security, just prevents casual file reading
constexpr uint8_t OBFUSCATION_KEY[] = {0x43, 0x72, 0x6F, 0x73, 0x73, 0x50, 0x6F, 0x69, 0x6E, 0x74};
constexpr size_t KEY_LENGTH = sizeof(OBFUSCATION_KEY);
} // namespace
void WifiCredentialStore::obfuscate(std::string& data) const {
Serial.printf("[%lu] [WCS] Obfuscating/deobfuscating %zu bytes\n", millis(), data.size());
for (size_t i = 0; i < data.size(); i++) {
data[i] ^= OBFUSCATION_KEY[i % KEY_LENGTH];
}
}
bool WifiCredentialStore::saveToFile() const {
// Make sure the directory exists
SD.mkdir("/.crosspoint");
std::ofstream file(WIFI_FILE, std::ios::binary);
if (!file) {
Serial.printf("[%lu] [WCS] Failed to open wifi.bin for writing\n", millis());
return false;
}
// Write header
serialization::writePod(file, WIFI_FILE_VERSION);
serialization::writePod(file, static_cast<uint8_t>(credentials.size()));
// Write each credential
for (const auto& cred : credentials) {
// Write SSID (plaintext - not sensitive)
serialization::writeString(file, cred.ssid);
Serial.printf("[%lu] [WCS] Saving SSID: %s, password length: %zu\n", millis(), cred.ssid.c_str(),
cred.password.size());
// Write password (obfuscated)
std::string obfuscatedPwd = cred.password;
obfuscate(obfuscatedPwd);
serialization::writeString(file, obfuscatedPwd);
}
file.close();
Serial.printf("[%lu] [WCS] Saved %zu WiFi credentials to file\n", millis(), credentials.size());
return true;
}
bool WifiCredentialStore::loadFromFile() {
if (!SD.exists(WIFI_FILE + 3)) { // +3 to skip "/sd" prefix
Serial.printf("[%lu] [WCS] WiFi credentials file does not exist\n", millis());
return false;
}
std::ifstream file(WIFI_FILE, std::ios::binary);
if (!file) {
Serial.printf("[%lu] [WCS] Failed to open wifi.bin for reading\n", millis());
return false;
}
// Read and verify version
uint8_t version;
serialization::readPod(file, version);
if (version != WIFI_FILE_VERSION) {
Serial.printf("[%lu] [WCS] Unknown file version: %u\n", millis(), version);
file.close();
return false;
}
// Read credential count
uint8_t count;
serialization::readPod(file, count);
// Read credentials
credentials.clear();
for (uint8_t i = 0; i < count && i < MAX_NETWORKS; i++) {
WifiCredential cred;
// Read SSID
serialization::readString(file, cred.ssid);
// Read and deobfuscate password
serialization::readString(file, cred.password);
Serial.printf("[%lu] [WCS] Loaded SSID: %s, obfuscated password length: %zu\n", millis(), cred.ssid.c_str(),
cred.password.size());
obfuscate(cred.password); // XOR is symmetric, so same function deobfuscates
Serial.printf("[%lu] [WCS] After deobfuscation, password length: %zu\n", millis(), cred.password.size());
credentials.push_back(cred);
}
file.close();
Serial.printf("[%lu] [WCS] Loaded %zu WiFi credentials from file\n", millis(), credentials.size());
return true;
}
bool WifiCredentialStore::addCredential(const std::string& ssid, const std::string& password) {
// Check if this SSID already exists and update it
const auto cred = find_if(credentials.begin(), credentials.end(),
[&ssid](const WifiCredential& cred) { return cred.ssid == ssid; });
if (cred != credentials.end()) {
cred->password = password;
Serial.printf("[%lu] [WCS] Updated credentials for: %s\n", millis(), ssid.c_str());
return saveToFile();
Add connect to Wifi and File Manager Webserver (#41) ## Summary - **What is the goal of this PR?** Implements wireless EPUB file management via a built-in web server, enabling users to upload, browse, organize, and delete EPUB files from any device on the same WiFi network without needing a computer cable connection. - **What changes are included?** - **New Web Server** ([`CrossPointWebServer.cpp`](src/CrossPointWebServer.cpp), [`CrossPointWebServer.h`](src/CrossPointWebServer.h)): - HTTP server on port 80 with a responsive HTML/CSS interface - Home page showing device status (version, IP, free memory) - File Manager with folder navigation and breadcrumb support - EPUB file upload with progress tracking - Folder creation and file/folder deletion - XSS protection via HTML escaping - Hidden system folders (`.` prefixed, "System Volume Information", "XTCache") - **WiFi Screen** ([`WifiScreen.cpp`](src/screens/WifiScreen.cpp), [`WifiScreen.h`](src/screens/WifiScreen.h)): - Network scanning with signal strength indicators - Visual indicators for encrypted (`*`) and saved (`+`) networks - State machine managing: scanning, network selection, password entry, connecting, save/forget prompts - 15-second connection timeout handling - Integration with web server (starts on connect, stops on exit) - **WiFi Credential Storage** ([`WifiCredentialStore.cpp`](src/WifiCredentialStore.cpp), [`WifiCredentialStore.h`](src/WifiCredentialStore.h)): - Persistent storage in `/sd/.crosspoint/wifi.bin` - XOR obfuscation for stored passwords (basic protection against casual reading) - Up to 8 saved networks with add/remove/update operations - **On-Screen Keyboard** ([`OnScreenKeyboard.cpp`](src/screens/OnScreenKeyboard.cpp), [`OnScreenKeyboard.h`](src/screens/OnScreenKeyboard.h)): - Reusable QWERTY keyboard component with shift support - Special keys: Shift, Space, Backspace, Done - Support for password masking mode - **Settings Screen Integration** ([`SettingsScreen.h`](src/screens/SettingsScreen.h)): - Added WiFi action to navigate to the new WiFi screen - **Documentation** ([`docs/webserver.md`](docs/webserver.md)): - Comprehensive user guide covering WiFi setup, web interface usage, file management, troubleshooting, and security notes - See this for more screenshots! - Working "displays the right way in GitHub" on my repo: https://github.com/olearycrew/crosspoint-reader/blob/feature/connect-to-wifi/docs/webserver.md **Video demo** https://github.com/user-attachments/assets/283e32dc-2d9f-4ae2-848e-01f41166a731 ## Additional Context - **Security considerations**: The web server has no authentication—anyone on the same WiFi network can access files. This is documented as a limitation, recommending use only on trusted private networks. Password obfuscation in the credential store is XOR-based, not cryptographically secure. - **Memory implications**: The web server and WiFi stack consume significant memory. The implementation properly cleans up (stops server, disconnects WiFi, sets `WIFI_OFF` mode) when exiting the WiFi screen to free resources. - **Async operations**: Network scanning and connection use async patterns with FreeRTOS tasks to prevent blocking the UI. The display task handles rendering on a dedicated thread with mutex protection. - **Browser compatibility**: The web interface uses standard HTML5/CSS3/JavaScript and is tested to work with all modern browsers on desktop and mobile. --------- Co-authored-by: Dave Allie <dave@daveallie.com>
2025-12-19 09:05:43 -05:00
}
// Check if we've reached the limit
if (credentials.size() >= MAX_NETWORKS) {
Serial.printf("[%lu] [WCS] Cannot add more networks, limit of %zu reached\n", millis(), MAX_NETWORKS);
return false;
}
// Add new credential
credentials.push_back({ssid, password});
Serial.printf("[%lu] [WCS] Added credentials for: %s\n", millis(), ssid.c_str());
return saveToFile();
}
bool WifiCredentialStore::removeCredential(const std::string& ssid) {
const auto cred = find_if(credentials.begin(), credentials.end(),
[&ssid](const WifiCredential& cred) { return cred.ssid == ssid; });
if (cred != credentials.end()) {
credentials.erase(cred);
Serial.printf("[%lu] [WCS] Removed credentials for: %s\n", millis(), ssid.c_str());
return saveToFile();
Add connect to Wifi and File Manager Webserver (#41) ## Summary - **What is the goal of this PR?** Implements wireless EPUB file management via a built-in web server, enabling users to upload, browse, organize, and delete EPUB files from any device on the same WiFi network without needing a computer cable connection. - **What changes are included?** - **New Web Server** ([`CrossPointWebServer.cpp`](src/CrossPointWebServer.cpp), [`CrossPointWebServer.h`](src/CrossPointWebServer.h)): - HTTP server on port 80 with a responsive HTML/CSS interface - Home page showing device status (version, IP, free memory) - File Manager with folder navigation and breadcrumb support - EPUB file upload with progress tracking - Folder creation and file/folder deletion - XSS protection via HTML escaping - Hidden system folders (`.` prefixed, "System Volume Information", "XTCache") - **WiFi Screen** ([`WifiScreen.cpp`](src/screens/WifiScreen.cpp), [`WifiScreen.h`](src/screens/WifiScreen.h)): - Network scanning with signal strength indicators - Visual indicators for encrypted (`*`) and saved (`+`) networks - State machine managing: scanning, network selection, password entry, connecting, save/forget prompts - 15-second connection timeout handling - Integration with web server (starts on connect, stops on exit) - **WiFi Credential Storage** ([`WifiCredentialStore.cpp`](src/WifiCredentialStore.cpp), [`WifiCredentialStore.h`](src/WifiCredentialStore.h)): - Persistent storage in `/sd/.crosspoint/wifi.bin` - XOR obfuscation for stored passwords (basic protection against casual reading) - Up to 8 saved networks with add/remove/update operations - **On-Screen Keyboard** ([`OnScreenKeyboard.cpp`](src/screens/OnScreenKeyboard.cpp), [`OnScreenKeyboard.h`](src/screens/OnScreenKeyboard.h)): - Reusable QWERTY keyboard component with shift support - Special keys: Shift, Space, Backspace, Done - Support for password masking mode - **Settings Screen Integration** ([`SettingsScreen.h`](src/screens/SettingsScreen.h)): - Added WiFi action to navigate to the new WiFi screen - **Documentation** ([`docs/webserver.md`](docs/webserver.md)): - Comprehensive user guide covering WiFi setup, web interface usage, file management, troubleshooting, and security notes - See this for more screenshots! - Working "displays the right way in GitHub" on my repo: https://github.com/olearycrew/crosspoint-reader/blob/feature/connect-to-wifi/docs/webserver.md **Video demo** https://github.com/user-attachments/assets/283e32dc-2d9f-4ae2-848e-01f41166a731 ## Additional Context - **Security considerations**: The web server has no authentication—anyone on the same WiFi network can access files. This is documented as a limitation, recommending use only on trusted private networks. Password obfuscation in the credential store is XOR-based, not cryptographically secure. - **Memory implications**: The web server and WiFi stack consume significant memory. The implementation properly cleans up (stops server, disconnects WiFi, sets `WIFI_OFF` mode) when exiting the WiFi screen to free resources. - **Async operations**: Network scanning and connection use async patterns with FreeRTOS tasks to prevent blocking the UI. The display task handles rendering on a dedicated thread with mutex protection. - **Browser compatibility**: The web interface uses standard HTML5/CSS3/JavaScript and is tested to work with all modern browsers on desktop and mobile. --------- Co-authored-by: Dave Allie <dave@daveallie.com>
2025-12-19 09:05:43 -05:00
}
return false; // Not found
}
const WifiCredential* WifiCredentialStore::findCredential(const std::string& ssid) const {
const auto cred = find_if(credentials.begin(), credentials.end(),
[&ssid](const WifiCredential& cred) { return cred.ssid == ssid; });
if (cred != credentials.end()) {
return &*cred;
Add connect to Wifi and File Manager Webserver (#41) ## Summary - **What is the goal of this PR?** Implements wireless EPUB file management via a built-in web server, enabling users to upload, browse, organize, and delete EPUB files from any device on the same WiFi network without needing a computer cable connection. - **What changes are included?** - **New Web Server** ([`CrossPointWebServer.cpp`](src/CrossPointWebServer.cpp), [`CrossPointWebServer.h`](src/CrossPointWebServer.h)): - HTTP server on port 80 with a responsive HTML/CSS interface - Home page showing device status (version, IP, free memory) - File Manager with folder navigation and breadcrumb support - EPUB file upload with progress tracking - Folder creation and file/folder deletion - XSS protection via HTML escaping - Hidden system folders (`.` prefixed, "System Volume Information", "XTCache") - **WiFi Screen** ([`WifiScreen.cpp`](src/screens/WifiScreen.cpp), [`WifiScreen.h`](src/screens/WifiScreen.h)): - Network scanning with signal strength indicators - Visual indicators for encrypted (`*`) and saved (`+`) networks - State machine managing: scanning, network selection, password entry, connecting, save/forget prompts - 15-second connection timeout handling - Integration with web server (starts on connect, stops on exit) - **WiFi Credential Storage** ([`WifiCredentialStore.cpp`](src/WifiCredentialStore.cpp), [`WifiCredentialStore.h`](src/WifiCredentialStore.h)): - Persistent storage in `/sd/.crosspoint/wifi.bin` - XOR obfuscation for stored passwords (basic protection against casual reading) - Up to 8 saved networks with add/remove/update operations - **On-Screen Keyboard** ([`OnScreenKeyboard.cpp`](src/screens/OnScreenKeyboard.cpp), [`OnScreenKeyboard.h`](src/screens/OnScreenKeyboard.h)): - Reusable QWERTY keyboard component with shift support - Special keys: Shift, Space, Backspace, Done - Support for password masking mode - **Settings Screen Integration** ([`SettingsScreen.h`](src/screens/SettingsScreen.h)): - Added WiFi action to navigate to the new WiFi screen - **Documentation** ([`docs/webserver.md`](docs/webserver.md)): - Comprehensive user guide covering WiFi setup, web interface usage, file management, troubleshooting, and security notes - See this for more screenshots! - Working "displays the right way in GitHub" on my repo: https://github.com/olearycrew/crosspoint-reader/blob/feature/connect-to-wifi/docs/webserver.md **Video demo** https://github.com/user-attachments/assets/283e32dc-2d9f-4ae2-848e-01f41166a731 ## Additional Context - **Security considerations**: The web server has no authentication—anyone on the same WiFi network can access files. This is documented as a limitation, recommending use only on trusted private networks. Password obfuscation in the credential store is XOR-based, not cryptographically secure. - **Memory implications**: The web server and WiFi stack consume significant memory. The implementation properly cleans up (stops server, disconnects WiFi, sets `WIFI_OFF` mode) when exiting the WiFi screen to free resources. - **Async operations**: Network scanning and connection use async patterns with FreeRTOS tasks to prevent blocking the UI. The display task handles rendering on a dedicated thread with mutex protection. - **Browser compatibility**: The web interface uses standard HTML5/CSS3/JavaScript and is tested to work with all modern browsers on desktop and mobile. --------- Co-authored-by: Dave Allie <dave@daveallie.com>
2025-12-19 09:05:43 -05:00
}
Add connect to Wifi and File Manager Webserver (#41) ## Summary - **What is the goal of this PR?** Implements wireless EPUB file management via a built-in web server, enabling users to upload, browse, organize, and delete EPUB files from any device on the same WiFi network without needing a computer cable connection. - **What changes are included?** - **New Web Server** ([`CrossPointWebServer.cpp`](src/CrossPointWebServer.cpp), [`CrossPointWebServer.h`](src/CrossPointWebServer.h)): - HTTP server on port 80 with a responsive HTML/CSS interface - Home page showing device status (version, IP, free memory) - File Manager with folder navigation and breadcrumb support - EPUB file upload with progress tracking - Folder creation and file/folder deletion - XSS protection via HTML escaping - Hidden system folders (`.` prefixed, "System Volume Information", "XTCache") - **WiFi Screen** ([`WifiScreen.cpp`](src/screens/WifiScreen.cpp), [`WifiScreen.h`](src/screens/WifiScreen.h)): - Network scanning with signal strength indicators - Visual indicators for encrypted (`*`) and saved (`+`) networks - State machine managing: scanning, network selection, password entry, connecting, save/forget prompts - 15-second connection timeout handling - Integration with web server (starts on connect, stops on exit) - **WiFi Credential Storage** ([`WifiCredentialStore.cpp`](src/WifiCredentialStore.cpp), [`WifiCredentialStore.h`](src/WifiCredentialStore.h)): - Persistent storage in `/sd/.crosspoint/wifi.bin` - XOR obfuscation for stored passwords (basic protection against casual reading) - Up to 8 saved networks with add/remove/update operations - **On-Screen Keyboard** ([`OnScreenKeyboard.cpp`](src/screens/OnScreenKeyboard.cpp), [`OnScreenKeyboard.h`](src/screens/OnScreenKeyboard.h)): - Reusable QWERTY keyboard component with shift support - Special keys: Shift, Space, Backspace, Done - Support for password masking mode - **Settings Screen Integration** ([`SettingsScreen.h`](src/screens/SettingsScreen.h)): - Added WiFi action to navigate to the new WiFi screen - **Documentation** ([`docs/webserver.md`](docs/webserver.md)): - Comprehensive user guide covering WiFi setup, web interface usage, file management, troubleshooting, and security notes - See this for more screenshots! - Working "displays the right way in GitHub" on my repo: https://github.com/olearycrew/crosspoint-reader/blob/feature/connect-to-wifi/docs/webserver.md **Video demo** https://github.com/user-attachments/assets/283e32dc-2d9f-4ae2-848e-01f41166a731 ## Additional Context - **Security considerations**: The web server has no authentication—anyone on the same WiFi network can access files. This is documented as a limitation, recommending use only on trusted private networks. Password obfuscation in the credential store is XOR-based, not cryptographically secure. - **Memory implications**: The web server and WiFi stack consume significant memory. The implementation properly cleans up (stops server, disconnects WiFi, sets `WIFI_OFF` mode) when exiting the WiFi screen to free resources. - **Async operations**: Network scanning and connection use async patterns with FreeRTOS tasks to prevent blocking the UI. The display task handles rendering on a dedicated thread with mutex protection. - **Browser compatibility**: The web interface uses standard HTML5/CSS3/JavaScript and is tested to work with all modern browsers on desktop and mobile. --------- Co-authored-by: Dave Allie <dave@daveallie.com>
2025-12-19 09:05:43 -05:00
return nullptr;
}
bool WifiCredentialStore::hasSavedCredential(const std::string& ssid) const { return findCredential(ssid) != nullptr; }
void WifiCredentialStore::clearAll() {
credentials.clear();
saveToFile();
Serial.printf("[%lu] [WCS] Cleared all WiFi credentials\n", millis());
}