Browse Source
Arduinojson6 (#8)
Arduinojson6 (#8)
* Remove redundant AuthSettingsService. Will re-implement properly soon using JWT. * Support ArduinoJson >= 6.0.0 * Fix ArduinoJson version to 6.x.xmaster
rjwats
5 years ago
committed by
GitHub
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 226 additions and 186 deletions
-
2platformio.ini
-
4src/APStatus.cpp
-
3src/APStatus.h
-
167src/AsyncArduinoJson6.h
-
31src/AsyncJsonCallbackResponse.h
-
10src/AsyncJsonRequestWebHandler.h
-
47src/AuthSettingsService.cpp
-
56src/AuthSettingsService.h
-
4src/NTPStatus.cpp
-
3src/NTPStatus.h
-
22src/SettingsPersistence.h
-
21src/SettingsService.h
-
23src/SimpleService.h
-
8src/WiFiScanner.cpp
-
4src/WiFiScanner.h
-
4src/WiFiStatus.cpp
-
3src/WiFiStatus.h
@ -0,0 +1,167 @@ |
|||
|
|||
/** |
|||
* A copy of AsyncJson.h from ESPAsyncWebServer, updated for ArduinoJson6. |
|||
*/ |
|||
|
|||
#ifndef ASYNC_ARDUINO_JSON_6_H |
|||
#define ASYNC_ARDUINO_JSON_6_H |
|||
|
|||
#include <ArduinoJson.h> |
|||
#include <WebResponseImpl.h> |
|||
#include <ESPAsyncWebServer.h> |
|||
|
|||
constexpr const char* JSON_MIMETYPE = "application/json"; |
|||
|
|||
class ChunkPrint : public Print { |
|||
private: |
|||
uint8_t* _destination; |
|||
size_t _to_skip; |
|||
size_t _to_write; |
|||
size_t _pos; |
|||
public: |
|||
ChunkPrint(uint8_t* destination, size_t from, size_t len) |
|||
: _destination(destination), _to_skip(from), _to_write(len), _pos{0} {} |
|||
virtual ~ChunkPrint(){} |
|||
size_t write(uint8_t c){ |
|||
if (_to_skip > 0) { |
|||
_to_skip--; |
|||
return 1; |
|||
} else if (_to_write > 0) { |
|||
_to_write--; |
|||
_destination[_pos++] = c; |
|||
return 1; |
|||
} |
|||
return 0; |
|||
} |
|||
size_t write(const uint8_t *buffer, size_t size) { |
|||
size_t written = 0; |
|||
while (written < size && write(buffer[written])) { |
|||
written++; |
|||
} |
|||
return written; |
|||
} |
|||
}; |
|||
|
|||
class AsyncJsonResponse: public AsyncAbstractResponse { |
|||
private: |
|||
DynamicJsonDocument _jsonDocument; |
|||
bool _isValid; |
|||
JsonObject _root; |
|||
|
|||
public: |
|||
AsyncJsonResponse(int maxSize): _jsonDocument(maxSize), _isValid{false} { |
|||
_code = 200; |
|||
_contentType = JSON_MIMETYPE; |
|||
_root = _jsonDocument.to<JsonObject>(); |
|||
} |
|||
~AsyncJsonResponse() {} |
|||
JsonObject getRoot() { |
|||
return _root; |
|||
} |
|||
bool _sourceValid() const { |
|||
return _isValid; |
|||
} |
|||
size_t setLength() { |
|||
_contentLength = measureJson(_jsonDocument); |
|||
if (_contentLength) { _isValid = true; } |
|||
return _contentLength; |
|||
} |
|||
size_t getSize() { |
|||
return _jsonDocument.size(); |
|||
} |
|||
size_t _fillBuffer(uint8_t *data, size_t len){ |
|||
ChunkPrint dest(data, _sentLength, len); |
|||
serializeJson(_jsonDocument, dest); |
|||
return len; |
|||
} |
|||
}; |
|||
|
|||
typedef std::function<void(AsyncWebServerRequest *request, JsonVariant json)> ArJsonRequestHandlerFunction; |
|||
|
|||
class AsyncCallbackJsonWebHandler: public AsyncWebHandler { |
|||
private: |
|||
protected: |
|||
const String _uri; |
|||
WebRequestMethodComposite _method; |
|||
ArJsonRequestHandlerFunction _onRequest; |
|||
size_t _contentLength; |
|||
size_t _maxContentLength; |
|||
public: |
|||
AsyncCallbackJsonWebHandler(const String& uri, ArJsonRequestHandlerFunction onRequest) : _uri(uri), _method(HTTP_POST|HTTP_PUT|HTTP_PATCH), _onRequest(onRequest), _maxContentLength(16384) {} |
|||
void setMethod(WebRequestMethodComposite method){ _method = method; } |
|||
void setMaxContentLength(int maxContentLength){ _maxContentLength = maxContentLength; } |
|||
void onRequest(ArJsonRequestHandlerFunction fn){ _onRequest = fn; } |
|||
virtual bool canHandle(AsyncWebServerRequest *request) override final{ |
|||
if(!_onRequest) |
|||
return false; |
|||
|
|||
if(!(_method & request->method())) |
|||
return false; |
|||
|
|||
if(_uri.length() && (_uri != request->url() && !request->url().startsWith(_uri+"/"))) |
|||
return false; |
|||
|
|||
if (!request->contentType().equalsIgnoreCase(JSON_MIMETYPE)) |
|||
return false; |
|||
|
|||
request->addInterestingHeader("ANY"); |
|||
return true; |
|||
} |
|||
virtual void handleRequest(AsyncWebServerRequest *request) override final { |
|||
if(_onRequest) { |
|||
if (request->_tempObject != NULL) { |
|||
DynamicJsonDocument _jsonDocument(_maxContentLength); |
|||
DeserializationError err = deserializeJson(_jsonDocument, (uint8_t*)(request->_tempObject)); |
|||
if (err == DeserializationError::Ok) { |
|||
_onRequest(request, _jsonDocument.as<JsonVariant>()); |
|||
return; |
|||
} |
|||
} |
|||
request->send(_contentLength > _maxContentLength ? 413 : 400); |
|||
} else { |
|||
request->send(500); |
|||
} |
|||
} |
|||
virtual void handleUpload(AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final) override final { |
|||
} |
|||
virtual void handleBody(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total) override final { |
|||
if (_onRequest) { |
|||
_contentLength = total; |
|||
if (total > 0 && request->_tempObject == NULL && total < _maxContentLength) { |
|||
request->_tempObject = malloc(total); |
|||
} |
|||
if (request->_tempObject != NULL) { |
|||
memcpy((uint8_t*)(request->_tempObject) + index, data, len); |
|||
} |
|||
} |
|||
} |
|||
virtual bool isRequestHandlerTrivial() override final {return _onRequest ? false : true;} |
|||
}; |
|||
|
|||
|
|||
/* |
|||
* Listens for a response being destroyed and calls a callback during said distruction. |
|||
* |
|||
* Used so we can take action after the response has been rendered to the client. |
|||
* |
|||
* Avoids having to fork ESPAsyncWebServer with a callback feature - still not a nice use of a destructor! |
|||
*/ |
|||
|
|||
typedef std::function<void()> AsyncJsonCallback; |
|||
|
|||
class AsyncJsonCallbackResponse: public AsyncJsonResponse { |
|||
|
|||
private: |
|||
|
|||
AsyncJsonCallback _callback; |
|||
|
|||
public: |
|||
|
|||
AsyncJsonCallbackResponse(AsyncJsonCallback callback, int maxSize) : AsyncJsonResponse(maxSize), _callback{callback} {} |
|||
~AsyncJsonCallbackResponse() { |
|||
_callback(); |
|||
} |
|||
|
|||
}; |
|||
|
|||
#endif |
@ -1,31 +0,0 @@ |
|||
#ifndef _AsyncJsonCallbackResponse_H_ |
|||
#define _AsyncJsonCallbackResponse_H_ |
|||
|
|||
#include <ESPAsyncWebServer.h> |
|||
#include <AsyncJson.h> |
|||
|
|||
/* |
|||
* Listens for a response being destroyed and calls a callback during said distruction. |
|||
* used so we can take action after the response has been rendered to the client. |
|||
* |
|||
* Avoids having to fork ESPAsyncWebServer with a callback feature, but not nice! |
|||
*/ |
|||
|
|||
typedef std::function<void()> AsyncJsonCallback; |
|||
|
|||
class AsyncJsonCallbackResponse: public AsyncJsonResponse { |
|||
|
|||
private: |
|||
|
|||
AsyncJsonCallback _callback; |
|||
|
|||
public: |
|||
|
|||
AsyncJsonCallbackResponse(AsyncJsonCallback callback, bool isArray=false) : AsyncJsonResponse(isArray), _callback{callback} {} |
|||
~AsyncJsonCallbackResponse() { |
|||
_callback(); |
|||
} |
|||
|
|||
}; |
|||
|
|||
#endif // end _AsyncJsonCallbackResponse_H_ |
@ -1,47 +0,0 @@ |
|||
#include <AuthSettingsService.h>
|
|||
|
|||
AuthSettingsService::AuthSettingsService(AsyncWebServer* server, FS* fs) : SettingsService(server, fs, AUTH_SETTINGS_SERVICE_PATH, AUTH_SETTINGS_FILE) { |
|||
_server->on(AUTH_LOGOUT_SERVICE_PATH, HTTP_GET, std::bind(&AuthSettingsService::logout, this, std::placeholders::_1)); |
|||
|
|||
// configure authentication handler
|
|||
_authenticationHandler.setUri(AUTH_AUTHENTICATE_SERVICE_PATH); |
|||
_authenticationHandler.setMethod(HTTP_POST); |
|||
_authenticationHandler.onRequest(std::bind(&AuthSettingsService::authenticate, this, std::placeholders::_1, std::placeholders::_2)); |
|||
_server->addHandler(&_authenticationHandler); |
|||
} |
|||
|
|||
AuthSettingsService::~AuthSettingsService() {} |
|||
|
|||
// checks the session is authenticated, refreshes the sessions timeout if so
|
|||
bool AuthSettingsService::authenticated(AsyncWebServerRequest *request){ |
|||
request->send(400); |
|||
return false; |
|||
} |
|||
|
|||
void AuthSettingsService::readFromJsonObject(JsonObject& root){ |
|||
_username = root["username"] | AUTH_DEFAULT_USERNAME; |
|||
_password = root["password"] | AUTH_DEFAULT_PASSWORD; |
|||
_sessionTimeout= root["session_timeout"] | AUTH_DEFAULT_SESSION_TIMEOUT; |
|||
} |
|||
|
|||
void AuthSettingsService::writeToJsonObject(JsonObject& root){ |
|||
root["username"] = _username; |
|||
root["password"] = _password; |
|||
root["session_timeout"] = _sessionTimeout; |
|||
} |
|||
|
|||
void AuthSettingsService::logout(AsyncWebServerRequest *request){ |
|||
// revoke the current requests session
|
|||
} |
|||
|
|||
void AuthSettingsService::authenticate(AsyncWebServerRequest *request, JsonVariant &json){ |
|||
if (json.is<JsonObject>()){ |
|||
JsonObject& credentials = json.as<JsonObject>(); |
|||
if (credentials["username"] == _username && credentials["password"] == _password){ |
|||
// store cookie and write to response
|
|||
} |
|||
request->send(401); |
|||
} else{ |
|||
request->send(400); |
|||
} |
|||
} |
@ -1,56 +0,0 @@ |
|||
#ifndef AuthSettingsService_h |
|||
#define AuthSettingsService_h |
|||
|
|||
#include <SettingsService.h> |
|||
|
|||
#define AUTH_DEFAULT_USERNAME "admin" |
|||
#define AUTH_DEFAULT_PASSWORD "admin" |
|||
#define AUTH_DEFAULT_SESSION_TIMEOUT 3600 |
|||
|
|||
#define AUTH_SETTINGS_FILE "/config/authSettings.json" |
|||
|
|||
#define AUTH_SETTINGS_SERVICE_PATH "/rest/authSettings" |
|||
#define AUTH_LOGOUT_SERVICE_PATH "/rest/logout" |
|||
#define AUTH_AUTHENTICATE_SERVICE_PATH "/rest/authenticate" |
|||
|
|||
// max number of concurrently authenticated clients |
|||
#define AUTH_MAX_CLIENTS 10 |
|||
|
|||
/* |
|||
* TODO: Will protect services with a cookie based authentication service. |
|||
*/ |
|||
|
|||
class AuthSettingsService : public SettingsService { |
|||
|
|||
public: |
|||
|
|||
AuthSettingsService(AsyncWebServer* server, FS* fs); |
|||
~AuthSettingsService(); |
|||
|
|||
// checks the session is authenticated, |
|||
// refreshes the sessions timeout if found |
|||
bool authenticated(AsyncWebServerRequest *request); |
|||
|
|||
protected: |
|||
|
|||
void readFromJsonObject(JsonObject& root); |
|||
void writeToJsonObject(JsonObject& root); |
|||
|
|||
private: |
|||
|
|||
// callback handler for authentication endpoint |
|||
AsyncJsonRequestWebHandler _authenticationHandler; |
|||
|
|||
// only supporting one username at the moment |
|||
String _username; |
|||
String _password; |
|||
|
|||
// session timeout in seconds |
|||
unsigned int _sessionTimeout; |
|||
|
|||
void logout(AsyncWebServerRequest *request); |
|||
void authenticate(AsyncWebServerRequest *request, JsonVariant &json); |
|||
|
|||
}; |
|||
|
|||
#endif // end AuthSettingsService_h |
Write
Preview
Loading…
Cancel
Save
Reference in new issue