Skip to content

Prevent Range Test from running on public/default channel#5986

Merged
jamesarich merged 3 commits into
meshtastic:mainfrom
dubsector:feature/range-test-public-channel-guard
Jun 27, 2026
Merged

Prevent Range Test from running on public/default channel#5986
jamesarich merged 3 commits into
meshtastic:mainfrom
dubsector:feature/range-test-public-channel-guard

Conversation

@dubsector

Copy link
Copy Markdown
Contributor

Summary

  • Blocks enabling Range Test in the app UI when the primary channel is unencrypted (empty PSK) or uses the well-known 1-byte default shortstring key. Both are effectively public channels that would flood the shared mesh with test traffic.
  • Users who intentionally want Range Test on a public channel can still enable it via the Meshtastic CLI — this is by design, making it a deliberate power-user action rather than an accidental tap.
  • Backend enforcement on save forces \enabled = false\ when a public channel is detected, so even a UI bypass cannot persist the setting.

Changes from previous PR #3816

  • Deduplication: Hoisted \state.connected && !isPublicPrimaryChannel\ into a single \canConfigure\ val — no repeated expression across 4 call sites
  • Already-enabled fix: Kept screen-level \enabled = state.connected\ (not \canConfigure) so the save footer remains reachable. Added \�dditionalDirtyCheck = { isPublicPrimaryChannel && formState.value.enabled }\ — this surfaces the Save/Discard buttons when a device already has Range Test enabled on a public channel (e.g. set via CLI), letting the user push the corrective \enabled = false\ through the app.
  • Updated to current codebase: Migrated to \src/commonMain\ path, \core.resources\ imports, Wire data-class \copy()\ syntax, and \ModuleConfig(range_test = ...)\ constructor — matches the KMP refactor that landed after Prevent Range Test from running on public/default channel #3816 was closed.

Test plan

  • On a device with default channel (1-byte PSK): Range Test controls are grayed out; Save does not appear unless Range Test was already enabled
  • On a device with default channel and Range Test already enabled (set via CLI): Save/Discard footer appears; tapping Save pushes \enabled = false\ to device
  • On a device with a private channel (PSK ≥ 2 bytes): Range Test controls work normally

Blocks enabling Range Test when the primary channel is unencrypted or
using the well-known default key (PSK < 2 bytes). Users who intentionally
want Range Test on a public channel can still do so via the CLI.

Addresses reviewer feedback:
- Hoist repeated condition into canConfigure val (no more duplication)
- Keep save enabled so a CLI-enabled Range Test can still be turned off
  through the app via additionalDirtyCheck forcing the footer visible
Blocks enabling Range Test when the primary channel uses an empty PSK
(cleartext) or the well-known 1-byte default shortstring code. Both are
effectively public channels that would flood the shared mesh with test
traffic. Users who intentionally want Range Test on a public channel
can still enable it via the Meshtastic CLI.

Addresses reviewer feedback:
- Deduplicate repeated condition; hoist into canConfigure val
- Keep screen-level enabled=connected so a CLI-enabled Range Test can
  still be cleared through the app (additionalDirtyCheck surfaces the
  save footer when the device has enabled=true on a public channel)
@github-actions github-actions Bot added the enhancement New feature or request label Jun 27, 2026

@jamesarich jamesarich left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PSK < 2 heuristic and the save-time enforcement are correct, and the dedup into canConfigure reads well. One UX change before merge — see the inline suggestion.

The corrective flow (device with Range Test enabled via CLI on a public channel) routes the user through a control that doesn't behave like one: the Enabled switch is grayed on, and the only way to disable is tapping Save, which silently forces enabled = false. That hidden side effect is the issue.

title = stringResource(Res.string.range_test_enabled),
checked = formState.value.enabled,
enabled = state.connected,
enabled = canConfigure,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let the Enabled switch turn off on a public channel (just not on), so the corrective action is the obvious one — flip the switch — instead of a Save button that silently disables:

Suggested change
enabled = canConfigure,
enabled = canConfigure || formState.value.enabled,

Behavior with this:

  • public + off → grayed off, can't enable ✅
  • public + on (CLI-set) → switch is live; flipping it off makes the form dirty → footer Save persists false
  • after toggling off it re-grays (can't flip back on) ✅

The footer then appears naturally via isDirty, so additionalDirtyCheck (line 56) can be dropped. I'd keep the onSave force-false as cheap defense-in-depth — it also covers the brief load race where channelList is empty and isPublicPrimaryChannel is transiently true.

When a device has Range Test enabled via CLI on a public channel, the
Enabled switch is now live (canConfigure || formState.value.enabled) so
the user can flip it off directly. The save footer appears naturally via
isDirty; additionalDirtyCheck is no longer needed and is removed.

The onSave force-false is kept as cheap defense-in-depth to cover the
brief load race where channelList is empty and isPublicPrimaryChannel
is transiently true.
@dubsector

dubsector commented Jun 27, 2026

Copy link
Copy Markdown
Contributor Author

Applied, thank you for the reccomendation. Changed the Enabled switch to enabled = canConfigure || formState.value.enabled and dropped additionalDirtyCheck. The corrective flow now works as you described: switch is live when it's on, user flips it off, form goes dirty naturally, Save persists the change. Kept the onSave force-false for the load-race edge case as you suggested.

@jamesarich jamesarich added this pull request to the merge queue Jun 27, 2026
Merged via the queue into meshtastic:main with commit 03009c4 Jun 27, 2026
22 checks passed
@dubsector dubsector deleted the feature/range-test-public-channel-guard branch June 27, 2026 22:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants