fix: reporter — correct re-buffer on POST failure, NTP guard, TLS note

- reporter_submit_camera/ble: cap batch to REPORTER_MAX_BUFFER before
  POST and assign whole capped batch back to buffer on failure, fixing
  silent record drop when batch > buffer capacity
- post_json: reject sends when ts < 1700000000 (clock not NTP-synced)
- post_json: add comment documenting intentional no-cert-validation

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-14 06:33:00 -07:00
parent 244426ec8b
commit 988443f207

View File

@@ -17,11 +17,17 @@ static uint32_t now_ts() {
static bool post_json(const DeviceConfig& cfg, const char* path, const String& body) { static bool post_json(const DeviceConfig& cfg, const char* path, const String& body) {
uint32_t ts = now_ts(); uint32_t ts = now_ts();
// Reject if NTP hasn't synced yet (timestamp would be near epoch 0)
if (ts < 1700000000UL) return false; // pre-2023 → clock not valid
String sig = hmac_sign(cfg.hmac_secret, cfg.device_id, ts, body); String sig = hmac_sign(cfg.hmac_secret, cfg.device_id, ts, body);
if (sig.isEmpty()) return false; // HMAC failed if (sig.isEmpty()) return false; // HMAC failed
HTTPClient http; HTTPClient http;
String url = String(REPORTER_API_HOST) + path; String url = String(REPORTER_API_HOST) + path;
// NOTE: Certificate validation is disabled — connection is encrypted but
// server identity is not verified. To enable validation, use WiFiClientSecure
// with setCACert() before calling http.begin(client, url).
// Acceptable for this deployment: devices operate on store WiFi, not public internet.
http.begin(url); http.begin(url);
http.addHeader("Content-Type", "application/json"); http.addHeader("Content-Type", "application/json");
http.addHeader("X-Device-Id", cfg.device_id); http.addHeader("X-Device-Id", cfg.device_id);
@@ -87,9 +93,15 @@ void reporter_submit_camera(const DeviceConfig& cfg, const CameraHourlyRecord& r
batch.push_back(rec); batch.push_back(rec);
s_cam_buf.clear(); s_cam_buf.clear();
// Cap to MAX_BUFFER: drop oldest to make room for newest
if ((int)batch.size() > REPORTER_MAX_BUFFER) {
batch.erase(batch.begin(),
batch.begin() + ((int)batch.size() - REPORTER_MAX_BUFFER));
}
String body = build_camera_batch(cfg, batch); String body = build_camera_batch(cfg, batch);
if (!post_json(cfg, "/api/v1/camera/events/batch", body)) { if (!post_json(cfg, "/api/v1/camera/events/batch", body)) {
for (const auto& r : batch) buf_add_cam(r); s_cam_buf = batch; // re-buffer the whole capped batch
} }
} }
@@ -101,9 +113,15 @@ void reporter_submit_ble(const DeviceConfig& cfg, const BLEHourlyRecord& rec) {
batch.push_back(rec); batch.push_back(rec);
s_ble_buf.clear(); s_ble_buf.clear();
// Cap to MAX_BUFFER: drop oldest to make room for newest
if ((int)batch.size() > REPORTER_MAX_BUFFER) {
batch.erase(batch.begin(),
batch.begin() + ((int)batch.size() - REPORTER_MAX_BUFFER));
}
String body = build_ble_batch(cfg, batch); String body = build_ble_batch(cfg, batch);
if (!post_json(cfg, "/api/v1/events/batch", body)) { if (!post_json(cfg, "/api/v1/events/batch", body)) {
for (const auto& r : batch) buf_add_ble(r); s_ble_buf = batch; // re-buffer the whole capped batch
} }
} }