Commit Graph
963 Commits
Author SHA1 Message Date
mikecarper b31d942b23 Verify RP2040 capabilities against matching UF2 application 2026-10-18 20:40:06 -07:00
mikecarper 82b8169837 Unify optional hardware variants and add runtime R8 TFT rotation 2026-10-18 20:25:13 -07:00
mikecarper 8268befbdc Keep original Tracker Full neighbor table within its RAM budget 2026-10-18 19:01:35 -07:00
mikecarper 27a5e0d452 Detect manufacturer-supported optional screens on RC32, Tracker V1 and V4 R8 2026-10-18 18:55:38 -07:00
mikecarper f5cdbaa84e Fix V4 button fixture for display presence checks 2026-10-18 18:21:52 -07:00
mikecarper 794f5f7b8c Account for ST7789 framebuffer and scanline heap in firmware gates 2026-10-18 16:32:49 -07:00
mikecarper dcdce7b656 Make T114 screen detection the default firmware and picker choice 2026-10-18 16:20:27 -07:00
mikecarper 71651a3b32 Preprocess complete CLI handlers before native fixture extraction 2026-10-18 15:49:53 -07:00
mikecarper 07edca4cb8 Fix G3 gain transitions, slot commands and radio restore 2026-10-18 14:29:19 -07:00
mikecarper eb00b5370e Restore G3 startup tolerance and G2-compatible flash mode 2026-10-18 13:58:02 -07:00
mikecarper 1147c28b27 Preserve admin password input and clarify reconnect guidance 2026-10-18 13:45:13 -07:00
mikecarper 7ee16000c6 Adapt the Room HTTP fixture to the setup password service
Keep this LAN and stopped-server fixture scoped to Room HTTP, assert that setup mode cannot enter its peripheral stub, and retain the actual AP rekey regressions in the management-password suite. The broader CI job exposed the missing dependency after the new tick hook.

Validated all 43 methods consuming the affected tick paths, all 18 remaining commands in the failed CI step, and 93 additional CLI, routing and persistence regression methods.
2026-10-18 13:23:59 -07:00
mikecarper 22f4c5f5a1 Share the saved admin password across ESP32 management services
Use the committed node credential for setup WiFi, WebConfig and browser OTA. Add persistent ESP32 WiFi Companion management credentials without changing preferences layouts, revoke stale browser sessions on rotation, retain scoped save receipts, and coordinate credential changes with flash uploads. Keep external-service credentials and trusted TCP protocol compatibility independent. Update live join QR codes, failure handling and documentation.

Validated 51 native cases, 158 related host and browser methods, and serial Full V4 Companion, Station G3 Repeater, ESP32-C6 Room Server and V4 Sensor firmware builds.
2026-10-18 13:09:48 -07:00
mikecarper 47b74647fe Recognize nested fail-closed preference guards in CI 2026-10-18 10:04:49 -07:00
mikecarper 60c05168c6 Fit all STM32 Companions with checked fractional preferences
Stage STM32 preference prefixes and checked footers in one atomic image, reject declared tails that encounter premature EOF, and share the typed CLI rollback helper. Use the proven Wio Mini code-layout flags on Wio E5 and Tiny Relay without changing features or memory boundaries. All four STM32 targets and RAK4631 Full pass at the full 1.18.0.1 release version length.
2026-10-18 09:11:51 -07:00
mikecarper 205724600b Keep fractional timezones within constrained flash budgets
Deduplicate validation and preserve the published preference bytes and transactional saves. Correct Ikoka Handheld Companion flash bounds and document QSPI Room migration. Qualify STM32 and RAK4631 at the full 1.18.0.1 release version length.
2026-10-18 08:46:20 -07:00
mikecarper b92198807b Merge upstream dev through 428a95c64
Integrate fractional Companion timezones and conditional Bluetooth pages while preserving the existing preference byte layout, transactional saves, and Full transport selector. Add migration, rollback, invalid-value, and UI profile regressions.
2026-10-18 08:30:50 -07:00
mikecarper 5444c2885d Preserve native USB failures when endpoint cleanup also fails 2026-10-18 02:27:11 -07:00
mikecarper 223b90ff05 Handle Full Companion terminal setup in native USB acceptance 2026-10-18 02:06:27 -07:00
mikecarper 7a5a7993ca Mock serial ownership inspection in Ethernet opener fixtures 2026-10-18 00:56:37 -07:00
mikecarper ebcfa44f16 Add guarded hardware acceptance and restoration tools 2026-10-18 00:24:03 -07:00
mikecarper d52e4e9347 Reduce room board recovery stack use under sustained reads 2026-10-18 00:00:47 -07:00
mikecarper ec9ebc0914 Expose broker acknowledgment diagnostics on Full Companion 2026-10-17 23:54:15 -07:00
mikecarper d3e05abce3 Fix room browser stack overflow and bound response bodies 2026-10-17 23:31:24 -07:00
mikecarper 652289ee82 Expand post-merge regressions and document qualification gaps 2026-10-17 21:41:47 -07:00
mikecarper f49be87c14 Fix ESP32-C6 GPIO hold capability and add cross-platform smoke builds 2026-10-17 21:41:47 -07:00
mikecarper a40b1f662b Merge remote-tracking branch 'origin/pr-21' into codex/integrate-open-prs-17-21 2026-10-17 21:13:27 -07:00
mikecarper 44b019025a Merge remote-tracking branch 'origin/pr-20' into codex/integrate-open-prs-17-21 2026-10-17 21:13:27 -07:00
mikecarper 3fdeac7195 Merge remote-tracking branch 'origin/pr-19' into codex/integrate-open-prs-17-21 2026-10-17 21:13:27 -07:00
mikecarper d911ba9147 Merge remote-tracking branch 'origin/pr-18' into codex/integrate-open-prs-17-21 2026-10-17 21:13:27 -07:00
nullrouten0andClaude Opus 5.5 d9fbe19852 Keep whole contact records ahead of a partial trailing record
Upstream MeshCore, and this fork up to v1.17.1.6 except ESP32 Full
builds, rewrote /contacts3 in place, one record after another. A reset
or a full volume during that save leaves whole records followed by part
of the next one. Upstream reads such a file up to the short read. Here
readableContactFile() treats any size that is not a multiple of 152
bytes as unreadable, and since 2311160a9 the bounded recovery then
deletes /contacts3. On the first boot after an upgrade, three whole
records plus one stray byte became zero contacts.

Invariant: on ESP32, RP2040 and STM32, when /contacts3 holds at least
one whole record followed by part of one, and /contacts3.bak does not
exist, the whole records load and nothing is written or deleted at
boot. The next ordinary save publishes only whole records through the
existing transaction. Unchanged: whole-record images; a backup still
wins over an incomplete primary, including a backup that is unreadable
or of unknown presence at boot, which keeps its retry at the recovery
boundary; read errors keep the bounded recovery; a file with no whole
record is still discarded; nRF52 is not touched.

selectContactFile() makes this check only after the strict checks of
both names fail, through a new partial_tail mode of
readableContactFile(). loadContacts() drops its own size check; its
whole-record loop bound already stops before the tail.

Add test_companion_contact_partial_tail.py, which runs the real load,
recovery and save paths on the uncached ESP32, RP2040 and STM32
harness and on the ESP32 Full cache harness under ASan/UBSan. On the
old code all four fail with zero contacts and /contacts3 deleted. It
catches 14 of 15 mutations of this change, including a full revert;
the other drops a guard whose value is read only when the file handle
is valid. Two cases in the uncached storage fixture used a one-byte
truncation as their unreadable image; they now use a file shorter than
one record, so they still exercise the discard path.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 03:57:09 +00:00
nullrouten0andClaude Opus 5.5 5fbb8d5473 Limit wrong passwords on the room browser
POST /api/room checked the room password on every request with no failure
limit, and a browser may send a new identity token each time. Any host that
reached WebConfig could guess the room admin password, which is also the
radio and /api/login admin password, at main-loop speed.

One budget now covers all browser tokens, with /api/login's numbers: at most
five distinct wrong passwords in each thirty-second window. After that, a
request carrying a password is refused without checking it until the window
ends. Wrong passwords count in read-only rooms too. Empty passwords are never
counted or refused, so public read-only access keeps working. The last four
wrong passwords are remembered by 8-byte SHA-256 digest and not counted
again, so a tab still polling with an old or mistyped password cannot use up
the budget. Successful sign-ins do not refund failures. Radio login is
unchanged.

test_room_web_service.py gains PASSWORD_LIMIT, which runs the real
processRoomRequest: refusal after five failures from five tokens; identical
replies for wrong, guest and admin passwords while refused, with no password
check (calls to authorizeRoomLogin are counted); no lock extension from 300
refused requests; the 29999/30000 ms boundary and the first window after
boot; read-only and empty-password cases; no refund on success; repeated,
rotating and read-only stale passwords; slow distinct failures ageing out;
and a guard that the digest ring stays in bounds. It fails on the previous
processRoomRequest at the sixth guess.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 03:57:09 +00:00
nullrouten0andClaude Opus 5.5 e7f6af591d Lock WebConfig logins per client address with a shared failure cap
/api/login locked every client for 30 s after five failures from anyone.
Anyone who could reach the login page could keep the owner locked out by
failing on purpose. If no login succeeded after a lockout, the lock also
returned from 2^31 to 2^32 ms (about 24.9 to 49.7 days) later, because the
deadline was never cleared and was compared as a signed difference.

Count failures per remote address instead. Five failures lock that address
for 30 s, as before. A shared budget caps failures from all addresses
together, so changing address does not add guesses: it holds six failures
and refills one every 6 s, the old global rate, so one failing address can
never empty it on its own. While it is empty every client waits, as before.
Lock times are measured as elapsed time.

The policy is a pure header, WebConfigLoginThrottle.h.
test_webconfig_login_throttle.py runs it directly (isolation, boundaries,
one-hour rate bounds, millis() half-wrap, saturation, eviction) and runs the
real handleLogin with ArduinoJson under ASan/UBSan. Putting every client on
one key, as the old code did, fails the handler test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 03:57:09 +00:00
nullrouten0andClaude Opus 5.5 fef470de6c Use the node's admin password for the migration bridge AP
The Wi-Fi, LoRa first-stage and Partition Expander bridges serve an
unauthenticated /update behind an AP whose password was fixed and published,
so anyone in range during a migration could upload firmware while the private
key is staged. Use the old node's saved admin password as the WPA2
passphrase, read from /com_prefs or /node_prefs at offset 56 as the firmware
loads it. The operator already used that password to start the old updater.

Fall back to the published password, with a serial warning, when the saved
admin password is missing, unreadable, shorter than 8 characters or not
printable ASCII, so no node becomes unreachable. The legacy filesystem is
mounted without formatting and the password is never printed. Migration
admission, flash sequencing, /update gating and the USB bridge are unchanged.
Update both guides and the package README.

Add a sanitizer-backed host test that compiles the bridge's actual Wi-Fi
block against fake SPIFFS and WiFi: both boots, file precedence, WPA2 length
and terminator bounds, printable characters, stock 1.10/1.11 file sizes,
truncated fields, and mount, seek and partial-read failures. It fails 8 of 8
on the previous code and catches 27 of 27 code mutations. Verified 13 related
host test files and the esp32_s3_4mb_partition_migrator build.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 03:57:09 +00:00
nullrouten0andClaude Opus 5.5 965edde1b0 Keep guest-password room logins out of the durable replay store
On a room server the guest password grants Read/Write, which the login
replay store treats as a role that needs a durable record. Every new
guest-password identity therefore took one of the 128 permanent slots,
and once they were used up the store failed closed for every new
identity, including a new administrator device, until the filesystem was
erased. Rooms often publish the guest password.

A guest-password Read/Write session (one without explicitly assigned
permissions) now uses the policy public readers already use: it must
beat its in-boot timestamp and any record the identity already has,
which is still advanced, but it never creates a new record.
Administrator logins and explicitly assigned roles keep the durable
reservation and still fail closed on a full store.

Tests: test_room_login_replay_capacity.py runs the real room login
handler against the real ClientACL replay store with ASan/UBSan: guest
churn cannot lock out a new admin or assigned writer, a former admin's
record still binds guest-password logins, and a store full of privileged
records still refuses a new admin. It fails 2 of 3 on the previous code.
Two expectations in test_room_login_integration.py and the login profile
contract follow the new policy.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 03:57:09 +00:00
mikecarper d6ed62c186 Align tracker GPS clock assertions with advancing RMC samples 2026-10-17 20:52:50 -07:00
mikecarper c88f3469b4 Fix bridge runtime harness extraction around packet logging guards 2026-10-17 20:23:30 -07:00
mikecarperandnullrouten0 9d7140bbdd Integrate upstream GPS PRs 3624, 3625 and 3626
Port the guarded NMEA buffer, validated RMC clock samples and coordinate bounds from meshcore-dev/MeshCore#3624, #3625 and #3626. Adapt clock admission to retain this branch's signed date limits, bounded loop work, tracker acquisitions, sample consumption, diagnostics and periodic settings.

Upstream-PR: https://github.com/meshcore-dev/MeshCore/pull/3624
Upstream-Commit: 1ac389bbef0084623a3115c526156ae8f414d3ea
Upstream-PR: https://github.com/meshcore-dev/MeshCore/pull/3625
Upstream-Commit: 72ed4dcf08869c6900ef579e7af1b28471a86895
Upstream-PR: https://github.com/meshcore-dev/MeshCore/pull/3626
Upstream-Commit: 499727a71c564a7b5d451b8f480d940e185fe742

Co-authored-by: nullrouten0 <201262769+nullrouten0@users.noreply.github.com>
2026-10-17 19:53:08 -07:00
mikecarper fd1d80ef6d Fit Mini Repeater with approved optional service cuts 2026-10-17 19:35:05 -07:00
mikecarper 29787c0b2d Bound SH1106 retry allocations and verify ESP32 Full RAM 2026-10-17 17:59:33 -07:00
mikecarper 2ae109fea7 Check all small STM32 Companions at release version length in CI 2026-10-17 17:47:21 -07:00
mikecarper 3059d79945 Fit Tiny Relay Companion while retaining GPIO and storage 2026-10-17 17:40:40 -07:00
mikecarper 9755216451 Fit Wio-E5 Companion without reducing storage or contacts 2026-10-17 17:39:04 -07:00
mikecarper 060119af8e Sleep unused onboard SX1262 in RAK13302 builds
Adapt the optional onboard-radio probe for RAK3401 and RAK4631 cores using the external RAK13302 image. Preserve SPI1 radio ownership, external FEM startup, and ordinary RAK4631 primary-radio operation.

Probe before boot voltage protection, bound missing-chip waits, release temporary pads, and confirm cold sleep without waking the chip. Add sanitizer-backed host regression tests and CI coverage.
2026-10-17 17:02:54 -07:00
mikecarper a843b1d00f Expose read-only RX power-saving diagnostics through framed CLI 2026-10-17 15:56:43 -07:00
mikecarper aa2cfaba62 Retain USB packet logging in canonical nRF sensor OTA pairs 2026-10-17 15:50:19 -07:00
mikecarper 50873b97b3 Recover nRF OTA RAM without reducing catalog or staging capacity 2026-10-17 15:50:17 -07:00
mikecarper baad17a1fe Protect nRF SD OTA authorization RAM from source-only stores 2026-10-17 15:35:34 -07:00
mikecarper f2f17aedb9 Honor periodic OTA cadence after the four-beacon startup burst 2026-10-17 15:12:59 -07:00
mikecarper 29f6ffa2be Delay displayed radio preamble advice for two minutes 2026-10-17 14:45:33 -07:00