mirror of
https://github.com/esphome/esphome.git
synced 2024-11-10 01:07:45 +01:00
Merge pull request from GHSA-48mj-p7x2-5jfm
* Move web_server auth to web_server_base * Fix * Fix * Add middleware system
This commit is contained in:
parent
5596751c2c
commit
be965a60eb
5 changed files with 81 additions and 25 deletions
|
@ -34,8 +34,8 @@ CONFIG_SCHEMA = cv.Schema(
|
||||||
cv.Optional(CONF_JS_INCLUDE): cv.file_,
|
cv.Optional(CONF_JS_INCLUDE): cv.file_,
|
||||||
cv.Optional(CONF_AUTH): cv.Schema(
|
cv.Optional(CONF_AUTH): cv.Schema(
|
||||||
{
|
{
|
||||||
cv.Required(CONF_USERNAME): cv.string_strict,
|
cv.Required(CONF_USERNAME): cv.All(cv.string_strict, cv.Length(min=1)),
|
||||||
cv.Required(CONF_PASSWORD): cv.string_strict,
|
cv.Required(CONF_PASSWORD): cv.All(cv.string_strict, cv.Length(min=1)),
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
cv.GenerateID(CONF_WEB_SERVER_BASE_ID): cv.use_id(
|
cv.GenerateID(CONF_WEB_SERVER_BASE_ID): cv.use_id(
|
||||||
|
@ -57,8 +57,8 @@ async def to_code(config):
|
||||||
cg.add(var.set_css_url(config[CONF_CSS_URL]))
|
cg.add(var.set_css_url(config[CONF_CSS_URL]))
|
||||||
cg.add(var.set_js_url(config[CONF_JS_URL]))
|
cg.add(var.set_js_url(config[CONF_JS_URL]))
|
||||||
if CONF_AUTH in config:
|
if CONF_AUTH in config:
|
||||||
cg.add(var.set_username(config[CONF_AUTH][CONF_USERNAME]))
|
cg.add(paren.set_auth_username(config[CONF_AUTH][CONF_USERNAME]))
|
||||||
cg.add(var.set_password(config[CONF_AUTH][CONF_PASSWORD]))
|
cg.add(paren.set_auth_password(config[CONF_AUTH][CONF_PASSWORD]))
|
||||||
if CONF_CSS_INCLUDE in config:
|
if CONF_CSS_INCLUDE in config:
|
||||||
cg.add_define("WEBSERVER_CSS_INCLUDE")
|
cg.add_define("WEBSERVER_CSS_INCLUDE")
|
||||||
path = CORE.relative_config_path(config[CONF_CSS_INCLUDE])
|
path = CORE.relative_config_path(config[CONF_CSS_INCLUDE])
|
||||||
|
|
|
@ -158,9 +158,6 @@ void WebServer::setup() {
|
||||||
void WebServer::dump_config() {
|
void WebServer::dump_config() {
|
||||||
ESP_LOGCONFIG(TAG, "Web Server:");
|
ESP_LOGCONFIG(TAG, "Web Server:");
|
||||||
ESP_LOGCONFIG(TAG, " Address: %s:%u", network::get_use_address().c_str(), this->base_->get_port());
|
ESP_LOGCONFIG(TAG, " Address: %s:%u", network::get_use_address().c_str(), this->base_->get_port());
|
||||||
if (this->using_auth()) {
|
|
||||||
ESP_LOGCONFIG(TAG, " Basic authentication enabled");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
float WebServer::get_setup_priority() const { return setup_priority::WIFI - 1.0f; }
|
float WebServer::get_setup_priority() const { return setup_priority::WIFI - 1.0f; }
|
||||||
|
|
||||||
|
@ -764,10 +761,6 @@ bool WebServer::canHandle(AsyncWebServerRequest *request) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
void WebServer::handleRequest(AsyncWebServerRequest *request) {
|
void WebServer::handleRequest(AsyncWebServerRequest *request) {
|
||||||
if (this->using_auth() && !request->authenticate(this->username_, this->password_)) {
|
|
||||||
return request->requestAuthentication();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (request->url() == "/") {
|
if (request->url() == "/") {
|
||||||
this->handle_index_request(request);
|
this->handle_index_request(request);
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -32,10 +32,6 @@ class WebServer : public Controller, public Component, public AsyncWebHandler {
|
||||||
public:
|
public:
|
||||||
WebServer(web_server_base::WebServerBase *base) : base_(base) {}
|
WebServer(web_server_base::WebServerBase *base) : base_(base) {}
|
||||||
|
|
||||||
void set_username(const char *username) { username_ = username; }
|
|
||||||
|
|
||||||
void set_password(const char *password) { password_ = password; }
|
|
||||||
|
|
||||||
/** Set the URL to the CSS <link> that's sent to each client. Defaults to
|
/** Set the URL to the CSS <link> that's sent to each client. Defaults to
|
||||||
* https://esphome.io/_static/webserver-v1.min.css
|
* https://esphome.io/_static/webserver-v1.min.css
|
||||||
*
|
*
|
||||||
|
@ -85,8 +81,6 @@ class WebServer : public Controller, public Component, public AsyncWebHandler {
|
||||||
void handle_js_request(AsyncWebServerRequest *request);
|
void handle_js_request(AsyncWebServerRequest *request);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool using_auth() { return username_ != nullptr && password_ != nullptr; }
|
|
||||||
|
|
||||||
#ifdef USE_SENSOR
|
#ifdef USE_SENSOR
|
||||||
void on_sensor_update(sensor::Sensor *obj, float state) override;
|
void on_sensor_update(sensor::Sensor *obj, float state) override;
|
||||||
/// Handle a sensor request under '/sensor/<id>'.
|
/// Handle a sensor request under '/sensor/<id>'.
|
||||||
|
@ -184,8 +178,6 @@ class WebServer : public Controller, public Component, public AsyncWebHandler {
|
||||||
protected:
|
protected:
|
||||||
web_server_base::WebServerBase *base_;
|
web_server_base::WebServerBase *base_;
|
||||||
AsyncEventSource events_{"/events"};
|
AsyncEventSource events_{"/events"};
|
||||||
const char *username_{nullptr};
|
|
||||||
const char *password_{nullptr};
|
|
||||||
const char *css_url_{nullptr};
|
const char *css_url_{nullptr};
|
||||||
const char *css_include_{nullptr};
|
const char *css_include_{nullptr};
|
||||||
const char *js_url_{nullptr};
|
const char *js_url_{nullptr};
|
||||||
|
|
|
@ -17,6 +17,17 @@ namespace web_server_base {
|
||||||
|
|
||||||
static const char *const TAG = "web_server_base";
|
static const char *const TAG = "web_server_base";
|
||||||
|
|
||||||
|
void WebServerBase::add_handler(AsyncWebHandler *handler) {
|
||||||
|
// remove all handlers
|
||||||
|
|
||||||
|
if (!credentials_.username.empty()) {
|
||||||
|
handler = new internal::AuthMiddlewareHandler(handler, &credentials_);
|
||||||
|
}
|
||||||
|
this->handlers_.push_back(handler);
|
||||||
|
if (this->server_ != nullptr)
|
||||||
|
this->server_->addHandler(handler);
|
||||||
|
}
|
||||||
|
|
||||||
void report_ota_error() {
|
void report_ota_error() {
|
||||||
StreamString ss;
|
StreamString ss;
|
||||||
Update.printError(ss);
|
Update.printError(ss);
|
||||||
|
|
|
@ -10,6 +10,68 @@
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace web_server_base {
|
namespace web_server_base {
|
||||||
|
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
class MiddlewareHandler : public AsyncWebHandler {
|
||||||
|
public:
|
||||||
|
MiddlewareHandler(AsyncWebHandler *next) : next_(next) {}
|
||||||
|
|
||||||
|
bool canHandle(AsyncWebServerRequest *request) override { return next_->canHandle(request); }
|
||||||
|
void handleRequest(AsyncWebServerRequest *request) override { next_->handleRequest(request); }
|
||||||
|
void handleUpload(AsyncWebServerRequest *request, const String &filename, size_t index, uint8_t *data, size_t len,
|
||||||
|
bool final) override {
|
||||||
|
next_->handleUpload(request, filename, index, data, len, final);
|
||||||
|
}
|
||||||
|
void handleBody(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total) override {
|
||||||
|
next_->handleBody(request, data, len, index, total);
|
||||||
|
}
|
||||||
|
bool isRequestHandlerTrivial() override { return next_->isRequestHandlerTrivial(); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
AsyncWebHandler *next_;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Credentials {
|
||||||
|
std::string username;
|
||||||
|
std::string password;
|
||||||
|
};
|
||||||
|
|
||||||
|
class AuthMiddlewareHandler : public MiddlewareHandler {
|
||||||
|
public:
|
||||||
|
AuthMiddlewareHandler(AsyncWebHandler *next, Credentials *credentials)
|
||||||
|
: MiddlewareHandler(next), credentials_(credentials) {}
|
||||||
|
|
||||||
|
bool check_auth(AsyncWebServerRequest *request) {
|
||||||
|
bool success = request->authenticate(credentials_->username.c_str(), credentials_->password.c_str());
|
||||||
|
if (!success) {
|
||||||
|
request->requestAuthentication();
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleRequest(AsyncWebServerRequest *request) override {
|
||||||
|
if (!check_auth(request))
|
||||||
|
return;
|
||||||
|
MiddlewareHandler::handleRequest(request);
|
||||||
|
}
|
||||||
|
void handleUpload(AsyncWebServerRequest *request, const String &filename, size_t index, uint8_t *data, size_t len,
|
||||||
|
bool final) override {
|
||||||
|
if (!check_auth(request))
|
||||||
|
return;
|
||||||
|
MiddlewareHandler::handleUpload(request, filename, index, data, len, final);
|
||||||
|
}
|
||||||
|
void handleBody(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total) override {
|
||||||
|
if (!check_auth(request))
|
||||||
|
return;
|
||||||
|
MiddlewareHandler::handleBody(request, data, len, index, total);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Credentials *credentials_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
|
||||||
class WebServerBase : public Component {
|
class WebServerBase : public Component {
|
||||||
public:
|
public:
|
||||||
void init() {
|
void init() {
|
||||||
|
@ -34,13 +96,10 @@ class WebServerBase : public Component {
|
||||||
std::shared_ptr<AsyncWebServer> get_server() const { return server_; }
|
std::shared_ptr<AsyncWebServer> get_server() const { return server_; }
|
||||||
float get_setup_priority() const override;
|
float get_setup_priority() const override;
|
||||||
|
|
||||||
void add_handler(AsyncWebHandler *handler) {
|
void set_auth_username(std::string auth_username) { credentials_.username = auth_username; }
|
||||||
// remove all handlers
|
void set_auth_password(std::string auth_password) { credentials_.password = auth_password; }
|
||||||
|
|
||||||
this->handlers_.push_back(handler);
|
void add_handler(AsyncWebHandler *handler);
|
||||||
if (this->server_ != nullptr)
|
|
||||||
this->server_->addHandler(handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
void add_ota_handler();
|
void add_ota_handler();
|
||||||
|
|
||||||
|
@ -54,6 +113,7 @@ class WebServerBase : public Component {
|
||||||
uint16_t port_{80};
|
uint16_t port_{80};
|
||||||
std::shared_ptr<AsyncWebServer> server_{nullptr};
|
std::shared_ptr<AsyncWebServer> server_{nullptr};
|
||||||
std::vector<AsyncWebHandler *> handlers_;
|
std::vector<AsyncWebHandler *> handlers_;
|
||||||
|
internal::Credentials credentials_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class OTARequestHandler : public AsyncWebHandler {
|
class OTARequestHandler : public AsyncWebHandler {
|
||||||
|
|
Loading…
Reference in a new issue