fix(mqtt): make the accepted NTP epoch authoritative before any JWT work

syncTimeWithNTP() read an epoch over UDP, called configTime(), set _ntp_synced,
and then had the stale-token test and createSlotAuthToken() read time(nullptr) —
without anything having put the accepted epoch there. configTime() restarts SNTP
and returns; the clock lands whenever a packet does.

_rtc->setCurrentTime() looks like it covers this and does not.
AutoDiscoverRTCClock::setCurrentTime() writes a detected DS3231/RV3028/PCF8563/
RX8130CE *instead of* delegating to its fallback, and only that fallback
(ESP32RTCClock) calls settimeofday(). So on every board carrying an RTC chip —
T-Beam Supreme and Station G3 both compile this bridge and both instantiate
AutoDiscoverRTCClock — libc kept the pre-correction time, and the correction path
tested staleness and minted iat claims against exactly the clock it had just
proven wrong. Boards without a chip take the fallback and were unaffected, which
is why the soak rig (Heltec V3/V4, no RTC) never showed it.

settimeofday() with the accepted epoch first, so the invariant downstream code
already assumes actually holds: once _ntp_synced is true, time(nullptr) returns
the epoch we accepted. configTime() still follows, to keep future syncs running.
This commit is contained in:
agessaman
2026-08-14 19:41:04 -07:00
parent b1ceaf01a8
commit 168d4a0a8a
+12
View File
@@ -4013,6 +4013,18 @@ bool MQTTBridge::syncTimeWithNTP(bool force, bool primary_only) {
#endif
if (ntp_ok && ntp_server_used) {
// Take ownership of the system clock here, before anything reads it. configTime()
// only restarts SNTP and returns, and _rtc reaches settimeofday() on exactly one
// path: AutoDiscoverRTCClock writes a detected DS3231/RV3028/PCF8563/RX8130CE chip
// *instead of* its fallback, so on any board carrying one, libc keeps the pre-sync
// time. Everything downstream reads time(nullptr) — the stale-token test below, and
// the iat of every JWT minted from here on — so once _ntp_synced is true that call
// has to already return the epoch we accepted.
struct timeval accepted;
accepted.tv_sec = (time_t)epochTime;
accepted.tv_usec = 0;
settimeofday(&accepted, nullptr);
configTime(0, 0, ntp_server_used);
if (_rtc) {