Skip to content

Commit 18d5d9e

Browse files
committed
Added examples
Added OTA/HTTP update example Added cookieAuth example Minor changes Added decryption error 6 for empty key
1 parent dae90a5 commit 18d5d9e

8 files changed

Lines changed: 232 additions & 18 deletions

File tree

README.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,9 @@ It's meant to be an universal, secure toolbox.
2424
* OTAUpdateConfiguration - how to configure OTA update service
2525
* saveToSPIFFS - saving and loading settings
2626
* setUpAP - configure Access Point
27-
* updateServerConfiguration - how to configure default HTTP update server
27+
* updateServerConfiguration - how to configure default HTTP update server
28+
29+
## Known issues
30+
* Cookie auth works best with Firefox
31+
* encryptKey takes values >=1 because of how key verification works
32+
* Using a function without configuring it (or loading settings) may cause crash
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#include <settingsManager.h>
2+
3+
/* Settings */
4+
const char* _name = "Workbench";
5+
const char* _login = "admin";
6+
const char* _pass = "admin";
7+
8+
/* WiFi */
9+
const char* _ssid = "";
10+
const char* _stapass = "";
11+
12+
settingsManager settings;
13+
14+
void setup() {
15+
Serial.begin(115200);
16+
pinMode(D0, OUTPUT);
17+
18+
settings.name(_name);
19+
settings.configUser(_login, _pass);
20+
settings.configSTA(_ssid, _stapass);
21+
22+
if (settings.beginSTA()) {
23+
Serial.print("Connected to ");
24+
Serial.println(settings.ssid());
25+
Serial.print(WiFi.localIP());
26+
} else {
27+
Serial.println("Unable to connect to WiFi\r\nRebooting");
28+
delay(1000);
29+
ESP.reset();
30+
}
31+
32+
settings.beginOTA();
33+
}
34+
35+
void loop() {
36+
while (millis() % 1000 != 0)
37+
ArduinoOTA.handle();
38+
digitalWrite(D0, !digitalRead(D0));
39+
}

examples/cookieAuth/cookieAuth.ino

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
#include <ESP8266WebServer.h>
2+
#include <settingsManager.h>
3+
4+
/*
5+
Cookie based authentication mechanism
6+
Handles timeouts and login page
7+
*/
8+
9+
settingsManager settings;
10+
ESP8266WebServer server;
11+
12+
/* Settings */
13+
const char* _name = "Workbench";
14+
const char* _login = "admin";
15+
const char* _pass = "admin";
16+
17+
/* WiFi */
18+
const char* _ssid = "";
19+
const char* _stapass = "";
20+
21+
/* Server must collect cookies */
22+
const char* headerkeys[] = {"Cookie"};
23+
24+
/* Valid init timebase */
25+
uint32_t timebase;
26+
27+
void setup() {
28+
Serial.begin(115200);
29+
settings.name(_name);
30+
settings.configUser(_login, _pass);
31+
settings.configSTA(_ssid, _stapass);
32+
/* Token will be valid for 3 minutes */
33+
/* Depends what is used as counter */
34+
settings.tokenLifespan = 180;
35+
36+
/* Configure server */
37+
server.collectHeaders(headerkeys, sizeof(headerkeys) / sizeof(char*));
38+
server.on("/login", handleLogin);
39+
server.on("/logout", handleLogout);
40+
server.on("/", handleRoot);
41+
server.begin();
42+
43+
if (settings.beginSTA()) {
44+
Serial.print("Connected to ");
45+
Serial.println(settings.ssid());
46+
Serial.println(WiFi.localIP());
47+
} else {
48+
Serial.println("Unable to connect to WiFi\r\nRebooting");
49+
delay(1000);
50+
ESP.reset();
51+
}
52+
}
53+
54+
void loop() {
55+
server.handleClient();
56+
timebase = millis() / 1000;
57+
}
58+
59+
void handleLogin() {
60+
Serial.println("Log in");
61+
if (server.method() == HTTP_GET) {
62+
String content = "<html><body><form action='/login' method='POST'>";
63+
content += "User:<input type='text' name='USERNAME' placeholder='username'><br>";
64+
content += "Password:<input type='password' name='PASSWORD' placeholder='password'><br>";
65+
content += "<input type='submit' name='SUBMIT' value='Submit'></form><br>";
66+
content += "</body></html>";
67+
server.send(200, "text/html", content);
68+
} else if (server.method() == HTTP_POST) {
69+
if (!verifyLogin()) {
70+
redirectToLogin();
71+
return;
72+
}
73+
Serial.println("Everything is correct");
74+
/* Redirect to root */
75+
server.sendHeader("Location", "/");
76+
server.send(301);
77+
}
78+
}
79+
80+
void handleRoot() {
81+
/* Must be checked on every page */
82+
if (!verifyLogin())
83+
redirectToLogin();
84+
85+
server.sendContent(F("<html><head><title>ESP8266 Server</title></he"));
86+
server.sendContent(F("ad><body><a href=\"/logout\"><input type=\"bu"));
87+
server.sendContent(F("tton\" value=\"Logout\" /></a><h1>You have su"));
88+
server.sendContent(F("ccessfully logged in!</h1></body></html>"));
89+
}
90+
91+
void handleLogout() {
92+
/* Send incorrect cookie to avoid restoring session */
93+
server.sendHeader("Set-Cookie", settings.encryptKey(1));
94+
redirectToLogin();
95+
}
96+
97+
bool verifyLogin() {
98+
String toVerify = server.header("Cookie");
99+
uint8_t status = settings.verifyEncryptedKey(toVerify, timebase);
100+
Serial.print("Cookie verification status: ");
101+
Serial.println(status);
102+
/* No cookie or it's expired */
103+
if (status >= 5) {
104+
/* Check if clients wants to authenticate */
105+
if (!server.hasArg("USERNAME") || !server.hasArg("PASSWORD"))
106+
return false;
107+
if (!settings.authenticate(server.arg("USERNAME").c_str(), server.arg("PASSWORD").c_str()))
108+
return false;
109+
} else if (status > 0)
110+
return false;
111+
/* Codes 1-4 are invalid */
112+
/* Clear cookies if you can't log in */
113+
114+
/* Sending a cookie anyway to hold up the session */
115+
server.sendHeader("Set-Cookie", settings.encryptKey(timebase));
116+
return true;
117+
}
118+
119+
void redirectToLogin() {
120+
server.sendHeader("Location", "/login");
121+
server.send(301);
122+
return void();
123+
}

examples/keyTesting/keyTesting.ino

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ void setup() {
4646
Serial.println(dec);
4747

4848
Serial.print("Encrypting key:\t\t");
49-
Serial.println(settings.validateEncryptedKey(enc, validityBase) == 0 ? "Pass" : "Fail");
49+
Serial.println(settings.verifyEncryptedKey(enc, validityBase) == 0 ? "Pass" : "Fail");
5050

5151
Serial.print("Decrypting key:\t\t");
5252
Serial.println(performTest(&settings, dec, validityBase, 0) ? "Pass" : "Fail");
@@ -122,7 +122,7 @@ void setup() {
122122

123123
/* Try to use pointers whenever you can. It's really memory-consuming */
124124
bool performTest(settingsManager* set, String test, uint32_t t, uint8_t code) {
125-
return (set->validateKey(test, t) == code);
125+
return (set->verifyKey(test, t) == code);
126126
}
127127

128128
void loop() {}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#include <settingsManager.h>
2+
#include <ESP8266WebServer.h>
3+
#include <ESP8266HTTPUpdateServer.h>
4+
5+
/* Settings */
6+
const char* _name = "Workbench";
7+
const char* _login = "admin";
8+
const char* _pass = "admin";
9+
10+
/* WiFi */
11+
const char* _ssid = "";
12+
const char* _stapass = "";
13+
14+
settingsManager settings;
15+
ESP8266WebServer server;
16+
ESP8266HTTPUpdateServer updServer;
17+
18+
void setup() {
19+
Serial.begin(115200);
20+
pinMode(D0, OUTPUT);
21+
22+
settings.name(_name);
23+
settings.configUser(_login, _pass);
24+
settings.configSTA(_ssid, _stapass);
25+
settings.configUpdateServer(&server, &updServer, "/update");
26+
27+
server.begin();
28+
29+
if (settings.beginSTA()) {
30+
Serial.print("Connected to ");
31+
Serial.println(settings.ssid());
32+
Serial.print(WiFi.localIP());
33+
} else {
34+
Serial.println("Unable to connect to WiFi\r\nRebooting");
35+
delay(1000);
36+
ESP.reset();
37+
}
38+
}
39+
40+
void loop() {
41+
while (millis() % 1000 != 0)
42+
server.handleClient();
43+
digitalWrite(D0, !digitalRead(D0));
44+
}

keywords.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ serialDebug KEYWORD2
3535
printConfigFile KEYWORD2
3636
printConfig KEYWORD2
3737
readInterval KEYWORD2
38-
validateKey KEYWORD2
39-
validateEncryptedKey KEYWORD2
38+
verifyKey KEYWORD2
39+
verifyEncryptedKey KEYWORD2
4040
encryptKey KEYWORD2
4141
decryptKey KEYWORD2
4242
tokenLifespan KEYWORD2

src/settingsManager.cpp

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@ bool settingsManager::beginSTA() {
279279
return false;
280280
}
281281
//if (this->_dhcp == true)
282-
// this->configIP(this->_ip, this->_gw, this->_mask);
282+
// this->configIP(this->_ip, this->_gw, this->_mask);
283283
#ifdef DEBUG_INSECURE
284284
this->_print(F("Connected to "), this->_ssid);
285285
#endif
@@ -466,25 +466,28 @@ void settingsManager::setField(char* _dest, const char* _src, uint8_t _size) {
466466

467467
/*
468468
Return reasons:
469-
0 - valid key
470-
1 - unprintable characters detected
471-
2 - conversion error
472-
3 - invalid name
473-
4 - wrong device
474-
5 - token expired
469+
0 - valid key
470+
1 - unprintable characters detected
471+
2 - conversion error
472+
3 - invalid name
473+
4 - wrong device
474+
5 - token expired
475+
6 - no input
475476
*/
476477

477478
/* todo: rewrite verification using indexOf */
478479

479-
uint8_t settingsManager::validateEncryptedKey(String key, uint32_t time) {
480-
return this->validateKey(this->decryptKey(key), time);
480+
uint8_t settingsManager::verifyEncryptedKey(String key, uint32_t time) {
481+
return this->verifyKey(this->decryptKey(key), time);
481482
}
482483

483-
uint8_t settingsManager::validateKey(String key, uint32_t time) {
484+
uint8_t settingsManager::verifyKey(String key, uint32_t time) {
484485
#ifdef DEBUG_INSECURE
485486
this->_print(F(" CHECKING: "), key.c_str());
486487
#endif
487488

489+
if (key == "") return 6;
490+
488491
/* Checking for invalid characters */
489492
for (uint8_t a = 0; a < key.length(); a++)
490493
if (key[a] < 33 || key[a] > 126) return 1;
@@ -497,7 +500,7 @@ uint8_t settingsManager::validateKey(String key, uint32_t time) {
497500
#ifdef DEBUG_INSECURE
498501
this->_print(F("\t*NAME: "), key.substring(start, end).c_str());
499502
#endif
500-
if (end - start != strlen(this->_name)) return 3;
503+
if ((uint8_t)(end - start) != strlen(this->_name)) return 3;
501504
if (key.substring(start, end) != String(this->_name)) return 3;
502505

503506
/* Extracting timestamp */

src/settingsManager.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,8 @@ class settingsManager {
5757
uint32_t lastUpdate;
5858
int8_t timezone;
5959
uint16_t readInterval;
60-
uint8_t validateKey(String, uint32_t);
61-
uint8_t validateEncryptedKey(String, uint32_t);
60+
uint8_t verifyKey(String, uint32_t);
61+
uint8_t verifyEncryptedKey(String, uint32_t);
6262
String encryptKey(uint32_t);
6363
String decryptKey(String);
6464
uint32_t tokenLifespan;

0 commit comments

Comments
 (0)