mirror of
https://github.com/me-no-dev/ESPAsyncWebServer.git
synced 2025-09-30 08:10:56 +02:00
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:
@@ -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
|
||||||
|
|
||||||
|
@@ -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
|
||||||
server.serveStatic("/", SPIFFS, "/").setDefaultFile("index.htm");
|
});
|
||||||
|
#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");
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
server.onNotFound([](AsyncWebServerRequest *request){ // nothing known
|
server.onNotFound([](AsyncWebServerRequest *request){ // nothing known
|
||||||
|
Binary file not shown.
BIN
examples/SmartSwitch/data/login/favicon.ico.gz
Normal file
BIN
examples/SmartSwitch/data/login/favicon.ico.gz
Normal file
Binary file not shown.
20
examples/SmartSwitch/data/login/index.htm
Normal file
20
examples/SmartSwitch/data/login/index.htm
Normal 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>
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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;
|
||||||
|
@@ -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);
|
||||||
|
@@ -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);
|
||||||
|
@@ -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,
|
||||||
|
Reference in New Issue
Block a user