Commit Graph
12307 Commits
Author SHA1 Message Date
nomdetom efd620b552 ci: enforce native-suite-count against test/ directories at PR time
platformio test discovers and runs whatever test_* directories exist, so
it never notices when test/native-suite-count drifts from the actual
directory count. That reconciliation lived only in bin/run-tests.sh, which
CI does not invoke - so a stale or unbumped count sailed through PRs
(develop itself shipped 38 dirs against a 37 file).

Add a standalone suite-count-check job to test_native.yml that mirrors
run-tests.sh's exact counting logic and fails on a mismatch. It runs on
every PR via main_matrix's test-native job, with no build step so it fails
fast. Bump native-suite-count to 38 to match the current suites.

clod helped too
2026-07-21 09:39:40 +01:00
Ben MeadorsandGitHub 0165e914a9 fix: gate module replies by request port (#11094) 2026-07-21 10:19:38 +02:00
Thomas GöttgensandGitHub 7bdc2569e8 Budget the admin-key PKI decrypt fallback (#11100) 2026-07-21 09:48:09 +02:00
Thomas GöttgensandGitHub 6bff231d53 Throttle NodeInfo direct responses (#11104) 2026-07-21 09:12:02 +02:00
Thomas GöttgensandGitHub 077c6e72f4 Corroborate traceroute next-hop updates against the relaying node (#11108) 2026-07-21 09:11:05 +02:00
Thomas GöttgensandGitHub 40e583c102 Limit node database churn from unauthenticated packets (#11102) 2026-07-21 09:09:53 +02:00
Thomas GöttgensandGitHub b299cc2427 Honour which_payload_variant on MQTT client-proxy ingress (#11097) 2026-07-21 09:08:46 +02:00
Ben MeadorsandGitHub 8b0f29026a fix: include board PSRAM class in the HybridCompile sdkconfig cache key (#11112) 2026-07-21 08:58:28 +02:00
Jonathan BennettandGitHub bd71ad283c Remove BASEUI_HAS_GAMES flag from portduino.ini (#11113)
Removed BASEUI_HAS_GAMES flag from build configuration.
2026-07-20 20:38:24 -05:00
Jason PandGitHub 65abfaa0c8 Improve user experience with a new GPS icon for Home and Position frames (#11103) 2026-07-20 20:30:57 -05:00
Thomas GöttgensandGitHub 53e510199a Bound remote-initiated key verification sessions (#11101)
* Bound remote-initiated key verification sessions

Opening a session raises a 30 second banner and a client notification and
occupies the only verification slot, all before the peer has authenticated
anything, and nothing limited how often that could happen.

Adds an absolute session cap that incoming packets cannot refresh, a
cooldown between remote-initiated sessions measured from when the previous
one ended, and refreshes the idle deadline only when the protocol actually
advances rather than on any arriving packet.

The busy path now sets ignoreRequest so it no longer answers with a NAK.

Also replaces the getTime() - 60 timeout comparison, which underflowed
before the clock passed 60.

* Use elapsed-time comparison for the session timeout and condense comments
2026-07-20 20:29:56 -05:00
Thomas GöttgensandGitHub d9f8839241 Accept a pending key only for the key-verification exchange (#11107)
perhapsDecode fell back to the not-yet-verified key held during a key
verification handshake for any incoming PKI unicast. That key is supplied
by whoever opened the handshake and proves only that they hold it, not that
they are the node they claim to be, so until the session ended they could
send DMs on any port that decrypted and were marked pki_encrypted.

perhapsEncode already restricts the pending key to KEY_VERIFICATION_APP.
The receive path now applies the same rule.
2026-07-20 20:28:30 -05:00
Ben Meadors 1317176f78 test: accept DECODE_OPAQUE/DECODE_POLICY_REJECT in perhapsDecode fuzz assertion
The packet-auth-policy change extends the DecodeState enum with DECODE_OPAQUE
and DECODE_POLICY_REJECT. test_E1_perhaps_decode_fuzz drives arbitrary
ciphertext through perhapsDecode and asserted the verdict was one of the
original three states; random ciphertext that matches no channel with no PKI
attempt now returns DECODE_OPAQUE, tripping the assertion. Broaden the check to
accept all five valid verdicts, matching the test's stated 'any verdict is
fine' contract.
2026-07-20 19:12:28 -05:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>Ben Meadors
61750d9118 Update meshtastic/device-ui digest to ef573c3 (#11080)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2026-07-20 18:42:01 -05:00
Thomas GöttgensandGitHub b8fb42c065 Fix bell-append off-by-one write past payload buffer (#11099)
The send_bell append writes bytes[size] and bytes[size+1] while the guard only checked size < DATA_PAYLOAD_LEN, overrunning the 233-byte payload array by one when size == DATA_PAYLOAD_LEN - 1. Guard on size + 1.
2026-07-20 18:38:50 -05:00
Thomas GöttgensandGitHub 6f522aad17 Return the secret sentinel for remote admin config gets (#11093)
writeSecret is a setter, so calling it on the NETWORK_CONFIG get path was a no-op: the buffer
already holds the stored psk, never the sentinel. MQTT_CONFIG returned the broker password
verbatim.

Both get paths now return secretReserved when req.from != 0, and the matching set paths call
writeSecret so a read-modify-write round trip keeps the stored value.
2026-07-20 18:38:23 -05:00
Thomas GöttgensandGitHub fb75410e53 Null-check packet allocations in allocForSending and its callers (#11086)
* Null-check packet allocations in allocForSending and its callers

Sibling of 0ae44d701.

* Null-check allocDataProtobuf, allocAckNak and allocErrorResponse callers

Second tier of the same nullable contract.

* Keep telemetry sleep scheduling on allocation failure

Allocation failure now marks the telemetry invalid instead of returning
early, so power-saving SENSOR nodes still arm deep sleep.
2026-07-20 18:37:13 -05:00
HarukiToredaandGitHub 09de848fbe Ignore notification (#11076) 2026-07-20 18:36:36 -05:00
Thomas GöttgensandGitHub 51019b14f4 Hold cryptLock around RNG use in admin and key verification (#11096)
setPassKey drew the session passkey outside cryptLock, unlike the signing
and key verification paths. Also replaces random() for the key verification
nonce with the hardware RNG.
2026-07-20 18:36:06 -05:00
Ben MeadorsandGitHub beb9a3095d Merge branch 'develop' into codex/packet-auth-policy 2026-07-20 17:43:32 -05:00
CopilotGitHubcopilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
67e2012136 fix: declare loop variable sa as const pointer in t5s3_epaper variant (#11111)
* Initial plan

* fix: declare sa as const pointer in t5s3_epaper variant.cpp

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
2026-07-20 17:42:47 -05:00
Thomas GöttgensandGitHub e061335055 Reserve the [Exit] slot when splitting canned messages (#11095)
splitConfiguredMessages capped the split loop at
CANNED_MESSAGE_MODULE_MESSAGE_MAX_COUNT and then appended [Exit]
unconditionally, so messages[] could be written one past its last index
and messagesCount could exceed the array size.
2026-07-20 17:31:21 -05:00
Benjamin Faershtein 08cfb3d683 Merge upstream develop into packet authentication policy 2026-07-20 11:48:59 -07:00
Thomas GöttgensandGitHub 0199a1f3ff Bounds-check detection sensor trigger type (#11091) 2026-07-20 14:49:29 +02:00
Ben MeadorsandGitHub 5cf346311c fix: don't wipe admin keys when regenerating the keypair (#11088)
A client's "regenerate keys" action sends a blank SecurityConfig carrying
only the new private key rather than the config it read from the device,
so assigning it wholesale cleared admin_key, is_managed, serial_enabled,
debug_log_api_enabled, admin_channel_enabled and packet_signature_policy.
Losing the admin keys locks the owner out of remote admin with no recourse
but a physical connection to the node.

Detect that bare-rotation shape and swap in just the keypair, leaving the
rest of the security config intact. Deliberately clearing admin keys still
works through a SET that leaves the private key alone.

Fixes #11073
2026-07-20 07:19:29 -05:00
Thomas GöttgensandGitHub 290967f739 Release packets the interface declines to send (#11087) 2026-07-20 13:42:59 +02:00
Ben MeadorsandGitHub 829ff80a09 fix(t5s3-epaper): 40MHz octal PSRAM; guard EInk init; esp32s3 sw-atomic shim (#11062)
- t5s3-epaper: the board's 3.3V octal (AP_3v3) PSRAM is unreliable at the qio_opi
  default of 80MHz (Total PSRAM reads 0, display dead / boot-loop); clock it at 40MHz.
- EInkParallelDisplay: skip EInk init and no-op display ops when the PSRAM framebuffer
  is unavailable, so the node boots headless instead of hard-faulting on a NULL buffer.
- src/platform/esp32: weak software __atomic_*_{1,2,4} so esp32s3 links on toolchains
  (e.g. macOS) that lack the sized libcalls GCC emits under -mdisable-hardware-atomics.
2026-07-20 12:13:50 +02:00
Thomas GöttgensandGitHub 5ded0ec8c5 Gate identity learning on signature in NodeDB::updateUser (#11084) 2026-07-20 11:56:42 +02:00
Thomas GöttgensandGitHub 405a6bfd8a Strip inner-message padding when sizing unsigned broadcasts (#11083) 2026-07-20 11:55:55 +02:00
Thomas GöttgensandGitHub 023351a979 Remove dead code (#11082)
Removed:
- MessageStore::addFromPacket and addFromString, superseded by
  tryAddFromPacket
- GeoCoord rangeRadiansToMeters, distanceTo, bearingTo
- Router::rawSend, declared virtual with no override and no caller
- ContentHandler handleHotspot, handleFs, handleAdminSettings,
  handleAdminSettingsApply, handleDeleteFsContent and their commented
  route registrations, plus the now unreachable htmlDeleteDir and the
  handleUpdateFs declaration that had no definition
- ContentHelper replaceAll
- OnScreenKeyboardModule popup chain: showPopup, clearPopup, drawPopup,
  drawPopupOverlay and their state, unreachable since the frame based UI
  was replaced by baseUI
- DebugRenderer drawDebugInfoTrampoline, drawDebugInfoSettingsTrampoline
  and the orphaned drawFrameSettings
- NodeListRenderer calculateMaxScroll, drawColumns and a stale extern
  haveGlyphs declaration with no definition
- UIRenderer::haveGlyphs, Screen::blink,
  NotificationRenderer::showKeyboardMessagePopupWithTitle,
  VirtualKeyboard::getInputText
- InkHUD touchNavLeft, touchNavRight, Applet::getActiveNodeCount,
  ThreadedMessageApplet::saveMessagesToFlash
- TwoButton::setHandlerUp, TwoButtonExtended setHandlerUp,
  setJoystickDownHandlers, setJoystickUpHandlers
- CannedMessageModule LaunchRepeatDestination, isCharInputAllowed,
  hasMessages
- TrafficManagementModule resetStats, recordRouterHopPreserved,
  saturatingIncrement
- UnitConversions::MetersPerSecondToMilesPerHour
- EncryptedStorage getSessionRemainingSeconds
- BMI270Sensor::writeRegisters, GPS::hasFlow, FSCommon copyFile,
  SerialConsole consolePrintf, buzz playLongPressLeadUp,
  memGet displayPercentHeapFree
2026-07-20 11:55:17 +02:00
Thomas GöttgensandGitHub ba8b1b1038 Treat backslash as a path separator in XModem filename validation (#11085) 2026-07-20 10:46:33 +02:00
Jonathan BennettandGitHub 19ddadf3ff Check for the SPI bufsize, and throw a useful error when set too small (#11072) 2026-07-20 09:58:58 +02:00
Benjamin Faershtein 59ab12675a Merge develop into packet authentication policy 2026-07-19 15:33:16 -07:00
Thomas GöttgensandGitHub a808e992a1 Add native Windows build of meshtasticd (#11031) 2026-07-19 23:31:19 +02:00
Ben Meadors 4726375282 Update protos 2026-07-19 06:55:26 -05:00
HarukiToredaandGitHub 8c6cc5dbde Don't show messages from Ignored nodes (#11068)
* Honor Node Ignore messages

* Screenless node fix
2026-07-19 06:32:34 -05:00
TomandGitHub b8b5582943 Regioninfo (#11056)
* advertise a superset of EU regional presets to client devices.

* trunk
2026-07-19 06:22:39 -05:00
AustinandGitHub a4ea55f919 Fix renovate comments (#11065)
Fix renovate comments for:
- Crypto
- Adafruit_nRF52_Arduino
- adafruit/Adafruit-MLX90614-Library
- meshtastic/Fusion
2026-07-18 21:34:38 -04:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
b56b35fcbb chore(deps): update platform-native digest to 86c62ed (#11054)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-18 21:12:12 -04:00
TomandGitHub ff951059cf test: correct native-suite-count to 37 (#11059)
native-suite-count drifted from the actual test/test_*/ directory count: #10669
added two suites (test_admin_session_repro, test_pki_admin_fallback) but bumped
the count by only one, and #11037 added test_xmodem without bumping it at all.
The file reads 35 against 37 real suites, which bin/run-tests.sh reports as AMBER
on every full run. Correct it to 37.
2026-07-18 14:20:59 -05:00
oscgonferandGitHub cae27c1764 Add retries for SCD4X data reading (#11058)
* Add retries for SCD4X data reading

* Adds a retry loop with 3 tries by default to get sensor data from the SCD4X

* Fix log and happy path
2026-07-18 13:52:39 -05:00
b20d89974a Stop accelerometer thread when double-tap/wake-on-motion disabled at runtime (#11025)
* Stop accelerometer thread when double-tap/wake-on-motion disabled at runtime

double_tap_as_button_press and wake_on_tap_or_motion are applied live: the
OFF->ON edge calls accelerometerThread->start(), but there was no ON->OFF
branch, so turning either flag off left the sensor thread running (polling
I2C, drawing power) until reboot. Worse, because enabled stayed true, a later
OFF->ON edge was a no-op (the enabled==false guard blocked re-start), leaving
the feature un-restartable without a reboot.

Add the symmetric ON->OFF branch in both handlers. When a flag goes true->off
and the other consumer of the shared thread is also off, call
accelerometerThread->disable() (stops runOnce polling and clears enabled so a
later re-enable can start() again). Each branch checks the other flag first so
disabling one feature never stops the sensor while the other still needs it.

* Keep accelerometer thread running when its sensor drives the compass

* Guard accelerometer thread config toggles against a null thread pointer

* AdminModule: factor shared accelerometer start/stop into a helper

The device and display config handlers had mirror-image blocks reconciling the
shared accelerometer thread. Extract reconcileAccelerometerThread(wasOn, nowOn,
otherFeatureOn) so the null guard, edge logic, compass (providesHeading) guard,
and rationale live in one place; each call site is now a single call. Behavior
is unchanged. Also drops the redundant per-field assignment that the
whole-struct `config.device = ...` / `config.display = ...` overwrites anyway.

---------

Co-authored-by: Thomas Göttgens <tgoettgens@gmail.com>
2026-07-18 06:26:20 -05:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
40d0d80f35 chore(deps): update adafruit pct2075 to v1.3.1 (#11055)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-18 06:13:49 -05:00
37fdbb49bf Add RAK WisMesh Pod variant and fix Tag LPCOMP wake on user shutdown (#11049)
* Add RAK WisMesh Pod variant and fix Tag LPCOMP wake on user shutdown

* chore: trunk fmt - replace Unicode em-dash in Pod comment

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-18 06:13:20 -05:00
d4aa7760cc Use hardware RNG for session passkey and PKC extra nonce (#11047)
* Use hardware RNG for session passkey and PKC extra nonce

The admin session passkey and the Curve25519 extra nonce were drawn
from Arduino random(), which is not a CSPRNG. Source them from
HardwareRNG::fill, mirroring the signing path, and fall back to the
seeded CSPRNG (CryptRNG) only when no hardware source is available.

* AdminModule: make session passkey expiry rollover-safe

session_time was compared as millis()/1000 seconds with additive
thresholds, which breaks across the millis() wrap and could keep a stale
admin session key valid. Store session_time in millis() and use
Throttle::isWithinTimespanMs for the 150s refresh and 300s validity
windows.

* AdminModule: track session passkey validity with an explicit flag

session_time == 0 was used as the uninitialized sentinel, but millis()
is legitimately 0 in the first millisecond of uptime, so a passkey
issued then would be treated as no session. Use a dedicated
session_passkey_valid flag instead.

* AdminModule: camelCase the session passkey validity flag

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2026-07-17 15:49:00 -05:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
ac027ec5ca chore(deps): update meshtastic-esp8266-oled-ssd1306 digest to 9d9ba7e (#11053)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-17 15:18:23 -05:00
oscgonferandGitHub 73180141b3 Add userprefs for telemetry screen settings (#11051)
* Add telemetry update interval to userprefs

* Add telemetry screen configs to userprefs

* Removed duped code from cherry-pick
2026-07-17 15:08:06 -05:00
985b983f67 TrafficManagement: gate role/NodeInfo cache writes on signer authenticity (#11048)
* TrafficManagement: gate role/NodeInfo cache writes on signer authenticity

The tier-3 role cache and the PSRAM NodeInfo response cache were updated
from any received NodeInfo with no authenticity check, so a spoofed
NodeInfo could set a node's cached role (granting dedup exceptions) or
poison the cached user served in direct responses. Skip both cache
writes when a known signer's NodeInfo arrives unsigned, matching the
identity-update gate on the direct-response path.

* TrafficManagement: hoist shared NodeInfo signer lookup

Compute the sender node lookup and unauthenticated-signer check once per
NodeInfo packet and reuse it for both the cache-refresh gate and the
direct-response identity gate, avoiding a second O(N) getMeshNode scan.

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2026-07-17 16:32:01 +01:00
Ben Meadors 6e0e9c174d Protobufs 2026-07-17 09:45:56 -05:00
Thomas GöttgensandGitHub cfecef5376 Channels: fix off-by-one bound in decryptForHash (#11046)
decryptForHash accepted chIndex == getNumChannels() before reading
getHash(chIndex), which indexes one past hashes[MAX_NUM_CHANNELS].
Use >= so an out-of-range index is rejected before the array read.
2026-07-17 08:15:19 -05:00