mirror of
https://github.com/esphome/esphome.git
synced 2026-10-07 11:26:39 +00:00
[web_server] Keep allowed origins in a shared flash table (#20086)
This commit is contained in:
@@ -413,7 +413,16 @@ async def to_code(config: ConfigType) -> None:
|
||||
cg.add_define("USE_WEBSERVER_PRIVATE_NETWORK_ACCESS")
|
||||
if (allowed_origins := config.get(CONF_ALLOWED_ORIGINS)) is not None:
|
||||
cg.add_define("USE_WEBSERVER_ALLOWED_ORIGINS")
|
||||
cg.add(var.set_allowed_origins(allowed_origins))
|
||||
# Shared flash table ended by nullptr, so the server stores only a pointer.
|
||||
cg.add(
|
||||
var.set_allowed_origins(
|
||||
cg.shared_progmem_array(
|
||||
"web_server_allowed_origins",
|
||||
cg.const_char_ptr,
|
||||
[*allowed_origins, cg.nullptr],
|
||||
)
|
||||
)
|
||||
)
|
||||
if (auth := config.get(CONF_AUTH)) is not None:
|
||||
cg.add_define("USE_WEBSERVER_AUTH")
|
||||
# The scheme is fixed at build time so the unused Basic/Digest code path is compiled
|
||||
|
||||
@@ -495,7 +495,8 @@ bool WebServer::is_request_origin_allowed_(AsyncWebServerRequest *request, const
|
||||
|
||||
#ifdef USE_WEBSERVER_ALLOWED_ORIGINS
|
||||
// Otherwise the origin must be explicitly allowed via configuration.
|
||||
for (const char *allowed_origin : this->allowed_origins_) {
|
||||
for (const char *const *it = this->allowed_origins_; *it != nullptr; it++) {
|
||||
const char *allowed_origin = *it;
|
||||
// A single "*" entry allows any origin.
|
||||
if (allowed_origin[0] == '*' && allowed_origin[1] == '\0')
|
||||
return true;
|
||||
|
||||
@@ -254,9 +254,9 @@ class WebServer final : public Component, public AsyncWebHandler {
|
||||
*
|
||||
* This list is also used to authorize Private Network Access requests when that feature is enabled.
|
||||
*
|
||||
* @param origins The list of allowed origins.
|
||||
* @param origins nullptr-terminated table of allowed origins; must outlive the server.
|
||||
*/
|
||||
void set_allowed_origins(std::initializer_list<const char *> origins) { this->allowed_origins_ = origins; }
|
||||
void set_allowed_origins(const char *const *origins) { this->allowed_origins_ = origins; }
|
||||
#endif
|
||||
|
||||
// ========== INTERNAL METHODS ==========
|
||||
@@ -620,7 +620,7 @@ class WebServer final : public Component, public AsyncWebHandler {
|
||||
#ifdef USE_WEBSERVER_ALLOWED_ORIGINS
|
||||
// Extra origins allowed to make cross-origin browser requests ("*" means any origin).
|
||||
// Only compiled when allowed_origins is configured; same-origin is always allowed regardless.
|
||||
FixedVector<const char *> allowed_origins_;
|
||||
const char *const *allowed_origins_{nullptr};
|
||||
#endif
|
||||
|
||||
/// Check whether the given request Origin is permitted. Same-origin (matching the Host the
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
---
|
||||
esphome:
|
||||
name: test
|
||||
|
||||
esp32:
|
||||
board: esp32dev
|
||||
|
||||
wifi:
|
||||
ssid: test
|
||||
password: testtest
|
||||
|
||||
web_server:
|
||||
allowed_origins:
|
||||
- https://app.esphome.io
|
||||
- "*"
|
||||
@@ -0,0 +1,18 @@
|
||||
"""Tests for the web_server allowed_origins codegen."""
|
||||
|
||||
from collections.abc import Callable
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def test_allowed_origins_are_a_progmem_table(
|
||||
generate_main: Callable[[str | Path], str],
|
||||
component_config_path: Callable[[str], Path],
|
||||
) -> None:
|
||||
"""Allowed origins live in a nullptr-terminated flash table instead of a heap vector."""
|
||||
main_cpp = generate_main(component_config_path("allowed_origins.yaml"))
|
||||
|
||||
assert (
|
||||
"static constexpr const char * web_server_allowed_origins[] PROGMEM = "
|
||||
'{"https://app.esphome.io", "*", nullptr};' in main_cpp
|
||||
)
|
||||
assert "->set_allowed_origins(web_server_allowed_origins);" in main_cpp
|
||||
Reference in New Issue
Block a user