Repository navigation
feat(chat): open invite key bundles and store the invite grant - #1868
Merged
Merged
Conversation
This was referenced Oct 28, 2026
bmc08gt
force-pushed
the
feat/group-invites-key-bundle
branch
from
October 28, 2026 17:31
2686aba to
27f1322
Compare
Bind DefaultInviteCipher for injection and convert invite envelopes between the transport models and the chat-cipher types. The cipher implements one scheme per message and leaves the check to the caller, so an envelope in any other scheme maps to null. FakeInviteCipher stands in for it in JVM tests, since libsodium can't load there, and rejects a bundle at the same step the real one would.
A member who joined with an invite link gets GetKeyEnvelope's invite_key_bundle until they store their own envelope, and GroupKeyEnvelopes returned it as a failure, so that member never had a key. It now opens the bundle with InviteCipher.openInviteKeyBundle, wraps the chat key for this device and calls SetKeyEnvelope, the same way it handles an envelope the creator wrapped. The creator's key comes from the Resolver, falling back to the wrapped_by_public_key the server reports. A bundle that fails a check, or uses a scheme this build doesn't know, marks the chat in WrongKeyChats and returns UntrustedEnvelope, so messages show as undecryptable instead of waiting for a key. Other failures stay uncached, so opening the chat retries the fetch.
ViewerState.Permissions.canInvite arrived with flipcash2-client-protocol 0.22.0, but chat_metadata had no column for it, so a host lost the grant whenever a chat loaded from the database and the invite entry points couldn't be gated on it. v46 adds chat_metadata.can_invite (default 0), written and cleared alongside can_edit. Migration45To46 zeroes viewer_state_version for the reason Migration36To37 gives: the next fetch reports the version the row already holds, and without the re-arm the gate drops it and the grant stays 0 on every chat that predates the upgrade. Also adds a round-trip test for MemberJoined's invitedBy, which the System JSON already carries.
An invite envelope in a scheme this build doesn't implement says nothing about whether the key is right, so it now fails as UntrustedEnvelope the way an unsupported KeyEnvelope does, and the chat isn't shown as wrong-key. Adds tests for the fallback to wrapped_by_public_key when the creator's key can't be looked up, ALREADY_SET after an invite bundle opens, and a rejected bundle being fetched again on the next open.
WrongKeyChats is keyed by chat id alone, so a chat marked under one account stayed marked for the next account to sign in on the device.
bmc08gt
force-pushed
the
feat/group-invites-key-bundle
branch
from
October 29, 2026 04:05
27f1322 to
3712305
Compare
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.
A member who joined a private group with an invite link has no key envelope of their own yet. GetKeyEnvelope returns the invite's copy of the chat key instead, and the app had no handling for that, so the chat stayed undecryptable.
GroupKeyEnvelopesnow opens that copy withInviteCipher.openInviteKeyBundle. It gets the creator's public key from the Resolver and falls back to thewrapped_by_public_keythe server reports when the lookup fails, as theInviteKeyEnvelopecomment in model.proto allows. Then:WrongKeyChats, a new in-memory store that the joiner UI will render as the wrong-key banner. Logout clears it.UntrustedEnvelopewithout the wrong-key mark.chat_metadatagainscan_invite, fromViewerState.permissions.can_invite. It is migration 45→46, and the migration spec resetsviewer_state_versionso existing chats pick up the grant on their next GetChat, as 36→37 did forcan_edit.invitedByon the MemberJoined system message already came in with #1863, so this PR doesn't touch it.Stacks on #1866, which is merged. Targets
code/cash. The host and joiner screens follow in separate PRs.