Skip to content

security: derive group verification tone from member state, not a hardcoded ok - #78

Open
konkomaji wants to merge 1 commit into
ni5arga:mainfrom
konkomaji:fix/group-verification-tone-31
Open

security: derive group verification tone from member state, not a hardcoded ok#78
konkomaji wants to merge 1 commit into
ni5arga:mainfrom
konkomaji:fix/group-verification-tone-31

Conversation

@konkomaji

Copy link
Copy Markdown

Why

describeConversation() hardcodes tone: 'ok' for every group (src/lib/conversation.ts:63-73), so the mode notice, its eyebrow, and the home-screen tag (src/app/index.tsx:137) show the same green "Private" treatment whether every member is verified or one of them is a MITM impersonator who slipped in at introduction. A direct chat already carries a persistent "Not verified" caution until the safety number is compared (ctx.verified); a group — which is N independent chances of a bad key, the mode with the most exposure — got no persistent warning at all. This contradicts conversation.ts's own stated invariant that "the single most dangerous failure this app can have is someone misreading the mode."

What changed

  • src/lib/conversation.ts: describeConversation now takes an optional contacts list and derives group tone/warning from member verification — any unverified member, or a member with no matching contact record yet, turns tone caution and switches the warning to a new plural string naming how many members are unverified. A contact-less member is treated as unverified (absence of proof is not proof of safety).
  • src/components/mode-notice.tsx: the group eyebrow now reads "NOT ALL VERIFIED" (reusing the same word as the direct-chat case) when tone is caution, instead of always "ENCRYPTED TO MEMBERS".
  • src/app/index.tsx: the home-screen group tag switches from a static green "Private" to the same amber "N unverified member(s)" tag already used at group-creation time (group.unverifiedTitle), so the list view doesn't contradict the chat screen.
  • src/app/chat/[id].tsx: passes contacts (already in scope) through to describeConversation.
  • New i18n keys (conversation.groupWarningUnverified.{one,other}, mode.notVerifiedMembers) added to all six locales — hi/bn/mr/te/ta translations are a best-effort pass and should get the same native-speaker review already flagged for the rest of the i18n work.
  • docs/THREAT-MODEL.md Fixed section updated.

Re-derives automatically on verification change since it's computed from contacts + groups on every render, no separate invalidation needed.

Test plan

  • New src/lib/__tests__/conversation.test.ts: all-verified → ok/green; any unverified → caution/amber with correct count; member with no contact record → treated as unverified; count is exact across multiple unverified members
  • npm test (235 tests; 1 pre-existing unrelated flaky perf-timing test in forward-secrecy.test.ts on this machine, not touched by this change)
  • npm run typecheck
  • npm run lint (0 errors; pre-existing warnings unrelated to this change)
  • npm run i18n:check
  • Manual: create a group with an unverified member, confirm amber notice + home tag; verify the member, confirm it turns green without navigating away

Closes #31

…dcoded ok (ni5arga#31)

describeConversation() always returned tone: 'ok' for groups, so the chat
notice, the eyebrow, and the home-screen tag all showed the same green
"Private" treatment whether every member was verified or one of them was
a MITM impersonator slipped in at introduction. Direct chats already gate
this on ctx.verified; groups now gate on whether any member (including
one with no contact record yet) is unverified, and name the count the
same way the existing group-creation warning does.

Closes ni5arga#31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Medium] Groups shown as "Private" (green) even with unverified members

1 participant