fix(meshcore): stop a spurious "Authentication required" banner for read-only viewers - #4489
Closed
Yeraze wants to merge 2 commits into
Closed
fix(meshcore): stop a spurious "Authentication required" banner for read-only viewers#4489Yeraze wants to merge 2 commits into
Yeraze wants to merge 2 commits into
Conversation
… nothing Two independent pre-existing bugs on the MeshCore channel view, both dating to the per-channel history introduced in #4461. Reported from the running app; neither file was touched by the #4473 nav work. Delete did nothing visible. The stream renders `filtered` = merge(history, messages), but `actions.deleteMessage` only prunes the shared `messages` pool. Anything served from the per-channel backlog — nearly everything on this view — was deleted server-side and then immediately re-rendered from `history`. Confirmed against the live API: the row was already gone from the database while still on screen. `handleDeleteMessage` and `handleClearChannel` now prune `history` (and the count badge) on success, and only on success: a failed delete leaves the row rather than vanishing optimistically. The channel opened at the top instead of the newest message — mobile only, which is why desktop testing missed it. The mobile two-pane layout mounts the conversation but hides it until the operator drills in from the list; measured in that state, scrollHeight 0 / clientHeight 0 / offsetParent null. The entry scroll fired there, `scrollTop = scrollHeight` was `0 = 0` — a silent no-op — but the one shot was already spent, so drilling in left the view pinned at the top of a 17,000px backlog with nothing left to re-trigger it. The scroll no longer spends the shot until the list has real layout, and a ResizeObserver completes it the moment the pane is revealed. This fixes the DM view too, which shares the component. The guard keys off scrollHeight alone, NOT clientHeight: a hidden subtree zeroes both, but jsdom reports clientHeight 0 for everything, so a clientHeight guard would silently disable the entry scroll in every test. Verified on the running container at 390x780 across both MeshCore sources: entry scroll lands at distance 0 from the bottom (was 16774), and deleting removes the row immediately with the server confirming it gone. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L9NzRtqE8eSMS8tvAeodUB
…ead-only viewers
An anonymous viewer with read grants on a MeshCore source got
"Authentication required" splashed over the channel view, which reads as
"you can't view this channel" even though the page was otherwise working.
Reproduced in an anonymous browser session. Two of the four failing calls
were 401s:
config/default-scope 401
saved-regions 401
Both are `requireAuth()` + `configuration: read`, and both exist ONLY to
populate the scope-override datalist — a send-side control a read-only
viewer cannot use. `fetchSavedRegions` then surfaced the raw 401 body via
setError, so the server's "Authentication required" became a page banner.
Two changes, either of which would fix the symptom; both are correct:
- Gate both lookups on `canSend`, so the requests are never made for a
viewer who cannot send rather than made and ignored.
- Drop the setError from fetchSavedRegions, matching getDefaultScope
directly above it. Optional autocomplete suggestions must not be able to
raise a page-level error.
Also moves `connection` to the top of the RESOURCES list and rewords it to
"Required to open a source." MeshCoreSourcePage gates its ENTIRE surface on
connection:read, so without it every other grant on a MeshCore source is
inert and the operator only sees "You do not have permission to view this
MeshCore source" — with no hint which permission is missing. Note the gate is
MeshCore-only; no Meshtastic path checks it, despite the comment there
claiming parity.
Verified anonymously on the running container: banner gone, and neither
auth-only endpoint is requested at all.
Not changed: channel CONTENT still needs `messages: read`, which the server
states explicitly in its 403 body
(required: {resource: "messages", action: "read"}). `channel_0..7` are inert
on MeshCore sources — no MeshCore code path consults them.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L9NzRtqE8eSMS8tvAeodUB
6 tasks
Owner
Author
|
Superseded by #4491, which carries this commit plus the channel-sync guard and the reply/trigger ordering fix. This branch was stacked on the pre-squash version of #4488, so once that merged it went |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
An anonymous viewer with read grants on a MeshCore source got "Authentication required" splashed over the channel view — which reads as "you can't view this channel" even though the page was otherwise working.
Reproduced in an anonymous session
Four calls failed; two of them were the culprit:
config/default-scopesaved-regionsmessages/channel-countsmessages/channel/0Both 401 routes are
requireAuth()+configuration: read, and both exist only to populate the scope-override datalist — a send-side control a read-only viewer cannot use.fetchSavedRegionsthen surfaced the raw 401 body throughsetError, so the server's{"error":"Authentication required"}became a page-level banner.Fix
Two changes, either of which resolves the symptom; both are correct:
canSend— the requests are never made for a viewer who cannot send, rather than made and ignored.setErrorfromfetchSavedRegions, matchinggetDefaultScopeimmediately above it. Optional autocomplete suggestions must not be able to raise a page-level error.Permissions UI
connectionmoves to the top of theRESOURCESlist, reworded to "Required to open a source. Also controls connect/disconnect."MeshCoreSourcePagegates its entire surface onconnection: read, so without it every other grant on a MeshCore source is inert and the operator only sees "You do not have permission to view this MeshCore source" — with no hint which permission is missing. This cost a real user a debugging session.Worth noting for reviewers: that gate is MeshCore-only. No Meshtastic path checks
connection: read(verified by grep), despite the comment there claiming it behaves "just like a Meshtastic source the user can't read".Deliberately NOT changed
Channel content still requires
messages: read. That isn't a bug — the server says so explicitly in its 403 body:{"error":"Insufficient permissions","code":"FORBIDDEN", "required":{"resource":"messages","action":"read"}}Also worth flagging as a separate UX wart, not fixed here:
channel_0..7are offered on MeshCore sources but are inert — no MeshCore code path consultschannel_N(verified by grep). A user grantingchannel_0on a MeshCore source reasonably expects channel access and gets nothing. Hiding those for MeshCore sources would be its own change.Test plan
MeshCoreChannelsView.test.tsx— the auth-only lookups are not called withoutmessages: write, and still are for a viewer who can send.success: true, 12956 passed, 0 failed.npx tsc --noEmitclean;npm run lint:cino FAIL lines.Generated by Claude Code