feat: add bounded admin WebSocket backend (Phase 8D.5)
- Require current admin cookie sessions, Origin checks and single-use tickets - Reuse the shared console with session-aware authorization and slot allocation - Add HTTPD-owned I/O, bounded buffering and revocation cleanup - Prevent LRU eviction of serial clients and stale admin socket closure - Reject unsupported web-shell mutations before side effects - Add host regressions, a smoke client and resource accounting Validated by user sign-off after a 15-minute full-client soak at 230400 baud, with a few broker drops under heavy output. Browser UI remains for Phase 8D.6; numeric memory reserves remain open.
This commit is contained in:
@@ -15,6 +15,8 @@
|
||||
#include "web_serial_transport.h"
|
||||
#include "web_server.h"
|
||||
#include "web_cookie_auth.h"
|
||||
#include "web_admin_transport.h"
|
||||
#include "web_admin_tickets.h"
|
||||
|
||||
static void print_usage(void)
|
||||
{
|
||||
@@ -35,6 +37,30 @@ static void print_fingerprint(const uint8_t fingerprint[WEB_SECURITY_SHA256_LENG
|
||||
}
|
||||
}
|
||||
|
||||
static void show_admin_transport(void)
|
||||
{
|
||||
web_admin_transport_snapshot_t admin;
|
||||
web_admin_tickets_snapshot_t tickets;
|
||||
web_admin_transport_get_snapshot(&admin);
|
||||
web_admin_tickets_get_snapshot(&tickets);
|
||||
printf("WebSocket admin: initialized=%s attached=%s active=%s/1 closing=%s init-error=%s\n",
|
||||
admin.initialized ? "yes" : "no", admin.attached ? "yes" : "no",
|
||||
admin.active ? "yes" : "no", admin.closing ? "yes" : "no", esp_err_to_name(admin.last_error));
|
||||
printf(" tickets=%" PRIu32 "/%u issued=%" PRIu32 " consumed=%" PRIu32
|
||||
" rejected=%" PRIu32 " capacity=%" PRIu32 "\n",
|
||||
tickets.active, WEB_ADMIN_TICKET_CAPACITY, tickets.issued, tickets.consumed,
|
||||
tickets.rejected, tickets.capacity_rejections);
|
||||
printf(" connected=%" PRIu32 " disconnected=%" PRIu32 " capacity=%" PRIu32
|
||||
" authorization=%" PRIu32 " protocol=%" PRIu32 " input-backpressure=%" PRIu32 "\n",
|
||||
admin.connections, admin.disconnections, admin.capacity_rejections,
|
||||
admin.authorization_rejections, admin.protocol_errors, admin.input_backpressure);
|
||||
printf(" rx-bytes=%" PRIu32 " tx-bytes=%" PRIu32 " send-failures=%" PRIu32
|
||||
" queue-failures=%" PRIu32 " static=%u ticket-storage=%u PSRAM-payload=%u bytes\n",
|
||||
admin.rx_bytes, admin.tx_bytes, admin.send_failures, admin.queue_failures,
|
||||
(unsigned)admin.static_bytes, (unsigned)tickets.storage_bytes, (unsigned)admin.payload_bytes);
|
||||
printf(" Admin counters are saturating lifetime counts (not reset by web clear-counters).\n");
|
||||
}
|
||||
|
||||
static int show_status(void)
|
||||
{
|
||||
web_server_snapshot_t snapshot;
|
||||
@@ -61,6 +87,8 @@ static int show_status(void)
|
||||
}
|
||||
printf("Endpoints: GET /, GET /api/status, POST /api/ws-ticket, WSS /ws/serial\n");
|
||||
printf("Authentication routes: GET /login, GET /api/login-challenge, POST /api/login, GET /api/session, POST /api/logout\n");
|
||||
printf("Admin-only backend: POST /api/admin/ws-ticket, WSS /ws/admin (no normal UI entry)\n");
|
||||
show_admin_transport();
|
||||
web_cookie_auth_snapshot_t auth;
|
||||
web_cookie_auth_get_snapshot(&auth);
|
||||
web_session_store_snapshot_t sessions;
|
||||
@@ -122,6 +150,7 @@ static int show_counters(void)
|
||||
return 1;
|
||||
}
|
||||
|
||||
show_admin_transport();
|
||||
const web_server_counters_t *counter = &snapshot.counters;
|
||||
printf("Lifecycle: starts=%" PRIu64 " start-failures=%" PRIu64
|
||||
" stops=%" PRIu64 "\n",
|
||||
|
||||
Reference in New Issue
Block a user