Cookie Authentication including WS part taken from ayushsharma82 ideas

https://github.com/me-no-dev/ESPAsyncWebServer/pull/684
For Websocket added: void handleHandshake(AwsHandshakeHandler handler) 
For EventSource added: void authorizeConnect(ArAuthorizeConnectHandler cb);

Auth example and modifications. Tested on ESP8266 and ESP32 platforms
See SmartSwitch.ino
This commit is contained in:
lorol
2020-05-09 16:55:57 -04:00
parent 7dbe1150dc
commit 2aa029bc40
13 changed files with 185 additions and 37 deletions

View File

@@ -4,14 +4,16 @@
## SmartSwitch ## SmartSwitch
* Remote Temperature Control application with schedule (example car block heater or battery charger) * Remote Temperature Control application with schedule (example car block heater or battery charger)
* Based on ESP_AsyncFSBrowser example * Based on ESP_AsyncFSBrowser example with ACE editor
* Wide browser compatibility, no extra server-side needed * Wide browser compatibility, no extra server-side needed
* HTTP server and WebSocket, single port * HTTP server and WebSocket, single port
* Standalone, no JS dependencies for the browser from Internet (I hope), ace editor included * Standalone, no JS dependencies for the browser from Internet (I hope), ace editor included
* Added ESPAsyncWiFiManager * Added ESPAsyncWiFiManager
* Fallback to an own WIFI_AP, no Internet to sync but by a browser the clock can be set once
* Real Time (NTP) w/ Time Zones * Real Time (NTP) w/ Time Zones
* Memorized settings to EEPROM * Memorized settings to EEPROM
* Multiple clients can be connected at same time, they see each other' requests * Multiple clients can be connected at same time, they see each other' requests
* Base Authentication of the editor, static content, WS
* Or Cookie Authentication including WS part, need lib src changes taken from https://github.com/me-no-dev/ESPAsyncWebServer/pull/684
* Default credentials <b>smart:switch</b> * Default credentials <b>smart:switch</b>
* Use latest ESP8266 or ESP32 core(from GitHub) * Use latest ESP8266 ESP32 cores from GitHub

View File

@@ -17,8 +17,20 @@ Use latest ESP core lib (from Github)
//#define DEL_WFM // delete Wifi credentials stored //#define DEL_WFM // delete Wifi credentials stored
//(use once then comment and flash again), also HTTP /erase-wifi can do the same live //(use once then comment and flash again), also HTTP /erase-wifi can do the same live
#define USE_AUTH_STAT // .setAuthentication also for static (editor always requires auth) // AUTH COOKIE uses only the password, Base uses both
//#define USE_AUTH_WS // .setAuthentication also for ws, broken for Safari iOS #define http_username "smart"
#define http_password "switch"
//See https://github.com/me-no-dev/ESPAsyncWebServer/pull/684
#define USE_AUTH_COOKIE
#define MY_COOKIE_FULL "LLKQ=7;max-age=31536000;"
#define MY_COOKIE_DEL "LLKQ="
#define MY_COOKIE "LLKQ=7"
#ifndef USE_AUTH_COOKIE
#define USE_AUTH_STAT //Base Auth for stat, /commands and SPIFFSEditor
//#define USE_AUTH_WS //Base Auth also for WS, not very supported
#endif
#include <ArduinoOTA.h> #include <ArduinoOTA.h>
#ifdef ESP32 #ifdef ESP32
@@ -57,6 +69,9 @@ Use latest ESP core lib (from Github)
#define DHTTYPE DHT22 // DHT 11 // DHT 22, AM2302, AM2321 // DHT 21, AM2301 #define DHTTYPE DHT22 // DHT 11 // DHT 22, AM2302, AM2321 // DHT 21, AM2301
#define DHTPIN 4 //D2 #define DHTPIN 4 //D2
#define DHT_T_CORR -0.5 //Temperature offset compensation of the sensor (can be -)
#define DHT_H_CORR 1.5 //Humidity offset compensation of the sensor
DHT dht(DHTPIN, DHTTYPE); DHT dht(DHTPIN, DHTTYPE);
// SKETCH BEGIN MAIN DECLARATIONS // SKETCH BEGIN MAIN DECLARATIONS
@@ -80,9 +95,7 @@ AsyncWebSocket ws("/ws");
const char* ssid = "MYROUTERSSD"; const char* ssid = "MYROUTERSSD";
const char* password = "MYROUTERPASSWD"; const char* password = "MYROUTERPASSWD";
#endif #endif
const char* hostName = "smartsw"; const char* hostName = "smartsw32";
const char* http_username = "smart";
const char* http_password = "switch";
// RTC // RTC
static timeval tv; static timeval tv;
@@ -91,6 +104,15 @@ static time_t now;
// HW I/O // HW I/O
const int btnPin = 0; //D3 const int btnPin = 0; //D3
const int ledPin = 2; //D4 const int ledPin = 2; //D4
#ifdef ESP32
#define LED_ON 0x1
#define LED_OFF 0x0
#elif defined(ESP8266)
#define LED_ON 0x0
#define LED_OFF 0x1
#endif
int btnState = HIGH; int btnState = HIGH;
// Globals // Globals
@@ -101,7 +123,7 @@ float t = 0;
float h = 0; float h = 0;
bool udht = false; bool udht = false;
bool heat_enabled_prev = false; bool heat_enabled_prev = false;
int ledState; int ledState = LED_OFF;
struct EE_bl { struct EE_bl {
byte memid; //here goes the EEMARK stamp byte memid; //here goes the EEMARK stamp
@@ -178,29 +200,31 @@ void showTime()
} }
if (heat_enabled_prev) { // smart control (delayed one cycle) if (heat_enabled_prev) { // smart control (delayed one cycle)
if (((t - HYST) < ee.tempe)&&(ledState == HIGH)) { // OFF->ON once if (((t - HYST) < ee.tempe)&&(ledState == LED_OFF)) { // OFF->ON once
ledState = LOW; ledState = LED_ON;
digitalWrite(ledPin, ledState); // apply change digitalWrite(ledPin, ledState); // apply change
ws.textAll("led,ledon"); ws.textAll("led,ledon");
} }
if ((((t + HYST) > ee.tempe)&&(ledState == LOW))||(!heat_enabled)) { // ON->OFF once, also turn off at end of period. if ((((t + HYST) > ee.tempe)&&(ledState == LED_ON))||(!heat_enabled)) { // ON->OFF once, also turn off at end of period.
ledState = HIGH; ledState = LED_OFF;
digitalWrite(ledPin, ledState); // apply change digitalWrite(ledPin, ledState); // apply change
ws.textAll("led,ledoff"); ws.textAll("led,ledoff");
} }
Serial.printf(ledState ? "LED OFF" : "LED ON");
Serial.printf(ledState == LED_ON ? "LED ON" : "LED OFF");
Serial.print(F(", Smart enabled\n")); Serial.print(F(", Smart enabled\n"));
} }
heat_enabled_prev = heat_enabled; //update heat_enabled_prev = heat_enabled; //update
} }
void updateDHT(){ void updateDHT(){
h = dht.readHumidity(); float h1 = dht.readHumidity();
t = dht.readTemperature(); //Celsius or dht.readTemperature(true) for Fahrenheit float t1 = dht.readTemperature(); //Celsius or dht.readTemperature(true) for Fahrenheit
if (isnan(h) || isnan(t)) { if (isnan(h1) || isnan(t1)) {
Serial.print(F("Failed to read from DHT sensor!")); Serial.print(F("Failed to read from DHT sensor!"));
h = 0; // debug w/o sensor } else {
t = 0; h = h1 + DHT_H_CORR;
t = t1 + DHT_T_CORR;
} }
} }
@@ -216,7 +240,7 @@ void checkPhysicalButton()
if (btnState != LOW) { // btnState is used to avoid sequential toggles if (btnState != LOW) { // btnState is used to avoid sequential toggles
ledState = !ledState; ledState = !ledState;
digitalWrite(ledPin, ledState); digitalWrite(ledPin, ledState);
if (ledState) ws.textAll("led,ledoff"); if (ledState == LED_OFF) ws.textAll("led,ledoff");
else ws.textAll("led,ledon"); else ws.textAll("led,ledon");
} }
btnState = LOW; btnState = LOW;
@@ -241,6 +265,16 @@ void mytimer() {
} }
} }
#ifdef USE_AUTH_COOKIE
bool myHandshake(AsyncWebServerRequest *request){ // false will 401
if (request->hasHeader("Cookie")){
String cookie = request->header("Cookie");
if (cookie.indexOf(MY_COOKIE) != -1) return true;
else return false;
} else return false;
}
#endif
// server // server
void onWsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len){ void onWsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len){
if(type == WS_EVT_CONNECT){ if(type == WS_EVT_CONNECT){
@@ -252,7 +286,7 @@ void onWsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventT
Serial.printf("[%u] Connected from %d.%d.%d.%d\n", client->id(), ip[0], ip[1], ip[2], ip[3]); Serial.printf("[%u] Connected from %d.%d.%d.%d\n", client->id(), ip[0], ip[1], ip[2], ip[3]);
showTime(); showTime();
analogSample(); analogSample();
if (ledState) ws.textAll("led,ledoff"); if (ledState == LED_OFF) ws.textAll("led,ledoff");
else ws.textAll("led,ledon"); else ws.textAll("led,ledon");
ws.printfAll("Now,Setting,%02d:%02d,%02d:%02d,%+2.1f", ee.hstart, ee.mstart, ee.hstop, ee.mstop, ee.tempe); ws.printfAll("Now,Setting,%02d:%02d,%02d:%02d,%+2.1f", ee.hstart, ee.mstart, ee.hstop, ee.mstop, ee.tempe);
@@ -279,11 +313,11 @@ void onWsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventT
} }
if(data[0] == 'L') { // LED if(data[0] == 'L') { // LED
if(data[1] == '1') { if(data[1] == '1') {
ledState = LOW; ledState = LED_ON;
ws.textAll("led,ledon"); // for others ws.textAll("led,ledon"); // for others
} }
else if(data[1] == '0') { else if(data[1] == '0') {
ledState = HIGH; ledState = LED_OFF;
ws.textAll("led,ledoff"); ws.textAll("led,ledoff");
} }
digitalWrite(ledPin, ledState); // apply change digitalWrite(ledPin, ledState); // apply change
@@ -444,31 +478,74 @@ void setup(){
#ifdef USE_AUTH_WS #ifdef USE_AUTH_WS
ws.setAuthentication(http_username,http_password); ws.setAuthentication(http_username,http_password);
#endif #endif
#ifdef USE_AUTH_COOKIE
ws.handleHandshake(myHandshake);
#endif
ws.onEvent(onWsEvent); ws.onEvent(onWsEvent);
server.addHandler(&ws); server.addHandler(&ws);
#ifdef ESP32 #ifdef ESP32
#ifdef USE_AUTH_STAT
server.addHandler(new SPIFFSEditor(SPIFFS, http_username,http_password)); server.addHandler(new SPIFFSEditor(SPIFFS, http_username,http_password));
#elif defined(USE_AUTH_COOKIE)
server.addHandler(new SPIFFSEditor(SPIFFS)).setFilter(myHandshake);
#endif
#elif defined(ESP8266) #elif defined(ESP8266)
#ifdef USE_AUTH_STAT
server.addHandler(new SPIFFSEditor(http_username,http_password)); server.addHandler(new SPIFFSEditor(http_username,http_password));
#elif defined(USE_AUTH_COOKIE)
server.addHandler(new SPIFFSEditor()).setFilter(myHandshake);
#endif
#endif #endif
server.on("/free-ram", HTTP_GET, [](AsyncWebServerRequest *request){ // direct request->answer #ifdef USE_AUTH_COOKIE
request->send(200, "text/plain", String(ESP.getFreeHeap())); server.on("/lg2n", HTTP_POST, [](AsyncWebServerRequest *request){ // cookie test
if((request->hasParam("pa2w",true) && (String(request->getParam("pa2w",true)->value().c_str()) == String(http_password)))||(request->hasParam("lg0f",true))){
AsyncWebServerResponse *response = request->beginResponse(301);
response->addHeader("Location", "/");
response->addHeader("Cache-Control", "no-cache");
if(request->hasParam("lg0f",true)) response->addHeader("Set-Cookie", MY_COOKIE_DEL);
else response->addHeader("Set-Cookie", MY_COOKIE_FULL);
request->send(response);
} else request->send(200, "text/plain","Wrong Password!");
}); });
#endif
// below paths need individual auth ////////////////////////////////////////////////
server.on("/free-ram", HTTP_GET, [](AsyncWebServerRequest *request){ // direct request->answer
#ifdef USE_AUTH_STAT
if(!request->authenticate(http_username, http_password)) return request->requestAuthentication();
#endif
request->send(200, "text/plain", String(ESP.getFreeHeap()));
#ifdef USE_AUTH COOKIE
}).setFilter(myHandshake);
#else
});
#endif
server.on("/get-time", HTTP_GET, [](AsyncWebServerRequest *request){ server.on("/get-time", HTTP_GET, [](AsyncWebServerRequest *request){
#ifdef USE_AUTH_STAT
if(!request->authenticate(http_username, http_password)) return request->requestAuthentication();
#endif
if(request->hasParam("btime")){ if(request->hasParam("btime")){
time_t rtc = (request->getParam("btime")->value()).toInt(); time_t rtc = (request->getParam("btime")->value()).toInt();
timeval tv = { rtc, 0 }; timeval tv = { rtc, 0 };
settimeofday(&tv, nullptr); settimeofday(&tv, nullptr);
} }
request->send(200, "text/plain","Got browser time ..."); request->send(200, "text/plain","Got browser time ...");
#ifdef USE_AUTH COOKIE
}).setFilter(myHandshake);
#else
}); });
#endif
server.on("/hw-reset", HTTP_GET, [](AsyncWebServerRequest *request){ server.on("/hw-reset", HTTP_GET, [](AsyncWebServerRequest *request){
#ifdef USE_AUTH_STAT
if(!request->authenticate(http_username, http_password)) return request->requestAuthentication();
#endif
request->onDisconnect([]() { request->onDisconnect([]() {
#ifdef ESP32 #ifdef ESP32
ESP.restart(); ESP.restart();
@@ -477,9 +554,16 @@ void setup(){
#endif #endif
}); });
request->send(200, "text/plain","Restarting ..."); request->send(200, "text/plain","Restarting ...");
#ifdef USE_AUTH COOKIE
}).setFilter(myHandshake);
#else
}); });
#endif
server.on("/erase-wifi", HTTP_GET, [](AsyncWebServerRequest *request){ server.on("/erase-wifi", HTTP_GET, [](AsyncWebServerRequest *request){
#ifdef USE_AUTH_STAT
if(!request->authenticate(http_username, http_password)) return request->requestAuthentication();
#endif
request->onDisconnect([]() { request->onDisconnect([]() {
WiFi.disconnect(true); WiFi.disconnect(true);
#ifdef ESP32 #ifdef ESP32
@@ -489,12 +573,23 @@ void setup(){
#endif #endif
}); });
request->send(200, "text/plain","Erasing WiFi data ..."); request->send(200, "text/plain","Erasing WiFi data ...");
}); #ifdef USE_AUTH COOKIE
}).setFilter(myHandshake);
#ifdef USE_AUTH_STAT
server.serveStatic("/", SPIFFS, "/").setDefaultFile("index.htm").setAuthentication(http_username,http_password);
#else #else
});
#endif
// above paths need individual auth ////////////////////////////////////////////////
#ifdef USE_AUTH_COOKIE
server.serveStatic("/", SPIFFS, "/").setDefaultFile("index.htm").setFilter(myHandshake);
server.serveStatic("/", SPIFFS, "/login/").setDefaultFile("index.htm").setFilter(!myHandshake);
#else
#ifdef USE_AUTH_STAT
server.serveStatic("/", SPIFFS, "/").setDefaultFile("index.htm").setAuthentication(http_username,http_password);
#else
server.serveStatic("/", SPIFFS, "/").setDefaultFile("index.htm"); server.serveStatic("/", SPIFFS, "/").setDefaultFile("index.htm");
#endif
#endif #endif
server.onNotFound([](AsyncWebServerRequest *request){ // nothing known server.onNotFound([](AsyncWebServerRequest *request){ // nothing known

Binary file not shown.

View File

@@ -0,0 +1,20 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<title>Login</title>
<meta name="viewport" content="width=device-width">
<link rel="apple-touch-icon" href="/favicon.ico" type="image/x-icon" />
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" />
<link rel="icon" href="/favicon.ico" type="image/x-icon" />
</head>
<body style="background-color:#bbb;font-family:arial;"><center>
<br><br>
<h4>Password</h4>
<form action="/lg2n" method="post">
<input type="password" name="pa2w">
<input type="checkbox" name="lg0f"><label for="lg0f">Logoff</label><br><br>
<input type="submit" value="Submit">
</form></center>
</body>
</html>

View File

@@ -263,6 +263,10 @@ void AsyncEventSource::onConnect(ArEventHandlerFunction cb){
_connectcb = cb; _connectcb = cb;
} }
void AsyncEventSource::authorizeConnect(ArAuthorizeConnectHandler cb){
_authorizeConnectHandler = cb;
}
void AsyncEventSource::_addClient(AsyncEventSourceClient * client){ void AsyncEventSource::_addClient(AsyncEventSourceClient * client){
/*char * temp = (char *)malloc(2054); /*char * temp = (char *)malloc(2054);
if(temp != NULL){ if(temp != NULL){
@@ -333,6 +337,7 @@ bool AsyncEventSource::canHandle(AsyncWebServerRequest *request){
return false; return false;
} }
request->addInterestingHeader(F("Last-Event-ID")); request->addInterestingHeader(F("Last-Event-ID"));
request->addInterestingHeader("Cookie");
return true; return true;
} }
@@ -340,6 +345,11 @@ void AsyncEventSource::handleRequest(AsyncWebServerRequest *request){
if((_username.length() && _password.length()) && !request->authenticate(_username.c_str(), _password.c_str())) { if((_username.length() && _password.length()) && !request->authenticate(_username.c_str(), _password.c_str())) {
return request->requestAuthentication(); return request->requestAuthentication();
} }
if(_authorizeConnectHandler != NULL){
if(!_authorizeConnectHandler(request)){
return request->send(401);
}
}
request->send(new AsyncEventSourceResponse(this)); request->send(new AsyncEventSourceResponse(this));
} }

View File

@@ -49,6 +49,7 @@ class AsyncEventSource;
class AsyncEventSourceResponse; class AsyncEventSourceResponse;
class AsyncEventSourceClient; class AsyncEventSourceClient;
typedef std::function<void(AsyncEventSourceClient *client)> ArEventHandlerFunction; typedef std::function<void(AsyncEventSourceClient *client)> ArEventHandlerFunction;
typedef std::function<bool(AsyncWebServerRequest *request)> ArAuthorizeConnectHandler;
class AsyncEventSourceMessage { class AsyncEventSourceMessage {
private: private:
@@ -100,6 +101,7 @@ class AsyncEventSource: public AsyncWebHandler {
String _url; String _url;
LinkedList<AsyncEventSourceClient *> _clients; LinkedList<AsyncEventSourceClient *> _clients;
ArEventHandlerFunction _connectcb; ArEventHandlerFunction _connectcb;
ArAuthorizeConnectHandler _authorizeConnectHandler;
public: public:
AsyncEventSource(const String& url); AsyncEventSource(const String& url);
~AsyncEventSource(); ~AsyncEventSource();
@@ -107,6 +109,7 @@ class AsyncEventSource: public AsyncWebHandler {
const char * url() const { return _url.c_str(); } const char * url() const { return _url.c_str(); }
void close(); void close();
void onConnect(ArEventHandlerFunction cb); void onConnect(ArEventHandlerFunction cb);
void authorizeConnect(ArAuthorizeConnectHandler cb);
void send(const char *message, const char *event=NULL, uint32_t id=0, uint32_t reconnect=0); void send(const char *message, const char *event=NULL, uint32_t id=0, uint32_t reconnect=0);
size_t count() const; //number clinets connected size_t count() const; //number clinets connected
size_t avgPacketsWaiting() const; size_t avgPacketsWaiting() const;

View File

@@ -1146,6 +1146,7 @@ void AsyncWebSocket::binaryAll(const __FlashStringHelper *message, size_t len){
const char __WS_STR_CONNECTION[] PROGMEM = { "Connection" }; const char __WS_STR_CONNECTION[] PROGMEM = { "Connection" };
const char __WS_STR_UPGRADE[] PROGMEM = { "Upgrade" }; const char __WS_STR_UPGRADE[] PROGMEM = { "Upgrade" };
const char __WS_STR_ORIGIN[] PROGMEM = { "Origin" }; const char __WS_STR_ORIGIN[] PROGMEM = { "Origin" };
const char __WS_STR_COOKIE[] PROGMEM = { "Cookie" };
const char __WS_STR_VERSION[] PROGMEM = { "Sec-WebSocket-Version" }; const char __WS_STR_VERSION[] PROGMEM = { "Sec-WebSocket-Version" };
const char __WS_STR_KEY[] PROGMEM = { "Sec-WebSocket-Key" }; const char __WS_STR_KEY[] PROGMEM = { "Sec-WebSocket-Key" };
const char __WS_STR_PROTOCOL[] PROGMEM = { "Sec-WebSocket-Protocol" }; const char __WS_STR_PROTOCOL[] PROGMEM = { "Sec-WebSocket-Protocol" };
@@ -1155,6 +1156,7 @@ const char __WS_STR_UUID[] PROGMEM = { "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" };
#define WS_STR_CONNECTION FPSTR(__WS_STR_CONNECTION) #define WS_STR_CONNECTION FPSTR(__WS_STR_CONNECTION)
#define WS_STR_UPGRADE FPSTR(__WS_STR_UPGRADE) #define WS_STR_UPGRADE FPSTR(__WS_STR_UPGRADE)
#define WS_STR_ORIGIN FPSTR(__WS_STR_ORIGIN) #define WS_STR_ORIGIN FPSTR(__WS_STR_ORIGIN)
#define WS_STR_COOKIE FPSTR(__WS_STR_COOKIE)
#define WS_STR_VERSION FPSTR(__WS_STR_VERSION) #define WS_STR_VERSION FPSTR(__WS_STR_VERSION)
#define WS_STR_KEY FPSTR(__WS_STR_KEY) #define WS_STR_KEY FPSTR(__WS_STR_KEY)
#define WS_STR_PROTOCOL FPSTR(__WS_STR_PROTOCOL) #define WS_STR_PROTOCOL FPSTR(__WS_STR_PROTOCOL)
@@ -1171,6 +1173,7 @@ bool AsyncWebSocket::canHandle(AsyncWebServerRequest *request){
request->addInterestingHeader(WS_STR_CONNECTION); request->addInterestingHeader(WS_STR_CONNECTION);
request->addInterestingHeader(WS_STR_UPGRADE); request->addInterestingHeader(WS_STR_UPGRADE);
request->addInterestingHeader(WS_STR_ORIGIN); request->addInterestingHeader(WS_STR_ORIGIN);
request->addInterestingHeader(WS_STR_COOKIE);
request->addInterestingHeader(WS_STR_VERSION); request->addInterestingHeader(WS_STR_VERSION);
request->addInterestingHeader(WS_STR_KEY); request->addInterestingHeader(WS_STR_KEY);
request->addInterestingHeader(WS_STR_PROTOCOL); request->addInterestingHeader(WS_STR_PROTOCOL);
@@ -1185,6 +1188,14 @@ void AsyncWebSocket::handleRequest(AsyncWebServerRequest *request){
if((_username.length() && _password.length()) && !request->authenticate(_username.c_str(), _password.c_str())){ if((_username.length() && _password.length()) && !request->authenticate(_username.c_str(), _password.c_str())){
return request->requestAuthentication(); return request->requestAuthentication();
} }
//////////////////////////////////////////
if(_handshakeHandler != nullptr){
if(!_handshakeHandler(request)){
request->send(401);
return;
}
}
//////////////////////////////////////////
AsyncWebHeader* version = request->getHeader(WS_STR_VERSION); AsyncWebHeader* version = request->getHeader(WS_STR_VERSION);
if(version->value().toInt() != 13){ if(version->value().toInt() != 13){
AsyncWebServerResponse *response = request->beginResponse(400); AsyncWebServerResponse *response = request->beginResponse(400);

View File

@@ -237,6 +237,7 @@ class AsyncWebSocketClient {
void _onData(void *pbuf, size_t plen); void _onData(void *pbuf, size_t plen);
}; };
typedef std::function<bool(AsyncWebServerRequest *request)> AwsHandshakeHandler;
typedef std::function<void(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len)> AwsEventHandler; typedef std::function<void(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len)> AwsEventHandler;
//WebServer Handler implementation that plays the role of a socket server //WebServer Handler implementation that plays the role of a socket server
@@ -248,6 +249,7 @@ class AsyncWebSocket: public AsyncWebHandler {
AsyncWebSocketClientLinkedList _clients; AsyncWebSocketClientLinkedList _clients;
uint32_t _cNextId; uint32_t _cNextId;
AwsEventHandler _eventHandler; AwsEventHandler _eventHandler;
AwsHandshakeHandler _handshakeHandler;
bool _enabled; bool _enabled;
AsyncWebLock _lock; AsyncWebLock _lock;
@@ -316,6 +318,11 @@ class AsyncWebSocket: public AsyncWebHandler {
_eventHandler = handler; _eventHandler = handler;
} }
// Handshake Handler
void handleHandshake(AwsHandshakeHandler handler){
_handshakeHandler = handler;
}
//system callbacks (do not call) //system callbacks (do not call)
uint32_t _getNextId(){ return _cNextId++; } uint32_t _getNextId(){ return _cNextId++; }
void _addClient(AsyncWebSocketClient * client); void _addClient(AsyncWebSocketClient * client);

View File

@@ -2,7 +2,7 @@
//File: edit.htm.gz, Size: 4408 //File: edit.htm.gz, Size: 4408
#define edit_htm_gz_len 4408 #define edit_htm_gz_len 4408
const uint8_t edit_htm_gz[] PROGMEM = { const uint8_t edit_htm_gz[] PROGMEM = {
0x1F,0x8B,0x08,0x08,0x52,0x4A,0xB0,0x5E,0x02,0x00,0x65,0x64,0x69,0x74,0x2E,0x68,0x74,0x6D,0x00,0xB5, 0x1F,0x8B,0x08,0x08,0x42,0x13,0xB7,0x5E,0x02,0x00,0x65,0x64,0x69,0x74,0x2E,0x68,0x74,0x6D,0x00,0xB5,
0x1A,0x0B,0x5B,0xDB,0x36,0xF0,0xAF,0x18,0x6F,0x63,0xF6,0xE2,0x38,0x0E,0xA5,0xAC,0x73,0x30,0x2C,0x50, 0x1A,0x0B,0x5B,0xDB,0x36,0xF0,0xAF,0x18,0x6F,0x63,0xF6,0xE2,0x38,0x0E,0xA5,0xAC,0x73,0x30,0x2C,0x50,
0x56,0xFA,0x02,0x4A,0x42,0x3B,0xCA,0xD8,0x3E,0xC5,0x56,0x62,0x15,0x5B,0xF6,0x2C,0x99,0x40,0xB3,0xFC, 0x56,0xFA,0x02,0x4A,0x42,0x3B,0xCA,0xD8,0x3E,0xC5,0x56,0x62,0x15,0x5B,0xF6,0x2C,0x99,0x40,0xB3,0xFC,
0xF7,0x9D,0x24,0x3F,0x43,0xE8,0x1E,0xDF,0xD6,0x6E,0x8D,0xA4,0xD3,0x9D,0xEE,0x4E,0xF7,0x54,0xB2,0xBB, 0xF7,0x9D,0x24,0x3F,0x43,0xE8,0x1E,0xDF,0xD6,0x6E,0x8D,0xA4,0xD3,0x9D,0xEE,0x4E,0xF7,0x54,0xB2,0xBB,