Void Sentry
An AI-driven, real-time Sentry Turret platform leveraging asynchronous I/O and computer vision to deliver high-precision autonomous motion tracking on resource-constrained embedded hardware.
Loading...
Searching...
No Matches
handshake_guard.h
1#pragma once
2
3#include "log_sanitize.h"
4#include "origin_check.h"
5#include <esp32-hal-log.h> // route the refusal log through Arduino's logger (otherwise silenced)
6#include <esp_http_server.h>
7#include <esp_log.h>
8
9// IDF 5.5 never calls a WebSocket URI handler for the handshake: ws_pre_handshake_cb runs before the 101 reply (an
10// error refuses the upgrade) and ws_post_handshake_cb after it. Both are off in the precompiled Arduino libs, so
11// platformio.ini sets them through custom_sdkconfig.
12#if !CONFIG_HTTPD_WS_PRE_HANDSHAKE_CB_SUPPORT || !CONFIG_HTTPD_WS_POST_HANDSHAKE_CB_SUPPORT
13// cppcheck-suppress preprocessorErrorDirective
14#error "needs CONFIG_HTTPD_WS_PRE/POST_HANDSHAKE_CB_SUPPORT=y (custom_sdkconfig in platformio.ini)"
15#endif
16
18enum class HeaderStatus {
19 Absent,
20 TooLong,
21 Ok
22};
23
28inline HeaderStatus read_header(httpd_req_t* req, const char* name, char* buf, size_t cap, size_t* len)
29{
30 *len = 0;
31 const size_t n = httpd_req_get_hdr_value_len(req, name);
32 if (n == 0)
33 {
34 return HeaderStatus::Absent;
35 }
36 if (n >= cap || httpd_req_get_hdr_value_str(req, name, buf, cap) != ESP_OK)
37 {
38 return HeaderStatus::TooLong;
39 }
40 *len = n;
41 return HeaderStatus::Ok;
42}
43
55inline bool handshake_origin_ok(httpd_req_t* req, const char* tag, bool any_port = false)
56{
57 constexpr size_t kHdrBuf = 128;
58 char origin[kHdrBuf];
59 char host[kHdrBuf];
60 size_t origin_len = 0;
61 size_t host_len = 0;
62
63 const bool origin_too_long = read_header(req, "Origin", origin, kHdrBuf, &origin_len) == HeaderStatus::TooLong;
64 if (read_header(req, "Host", host, kHdrBuf, &host_len) != HeaderStatus::Ok)
65 {
66 host_len = 0; // absent or too long both count as empty
67 }
68
69 if (origin_too_long)
70 {
71 ESP_LOGW(tag, "request refused: Origin header too long");
72 return false;
73 }
74 const std::string_view o(origin, origin_len);
75 const std::string_view h(host, host_len);
76 if (!(any_port ? remote::origin_allowed_any_port(o, h) : remote::origin_allowed(o, h)))
77 {
78 char safe[kHdrBuf]; // the Origin is attacker-controlled: no control bytes into the serial log
79 remote::sanitize_for_log(origin, origin_len, safe, sizeof(safe));
80 ESP_LOGW(tag, "request refused: Origin %s", safe);
81 return false;
82 }
83 return true;
84}
@ Ok
out holds exactly the stored bytes
@ Absent
the key does not exist (stored length 0)