Skip to content

client: GC re-invite for an already-joined GC is silently dropped #770

Description

@karamble

Summary

handleGCInvite rejects any incoming RMGroupInvite for a group chat that
already exists in the local DB - it persists nothing and fires no notification,
only logging an error. This makes it impossible to recover a stale local GC
copy: after a user restores an old backup (or otherwise holds an out-of-date
local copy), an admin re-adds them by re-inviting, but every re-invite is
silently dropped, so the user can never accept and rejoin.

Details

client/client_groupchat.go, in handleGCInvite:

_, err = c.db.GetGC(tx, invite.ID)
if !errors.Is(err, clientdb.ErrNotFound) {
    if err == nil {
        err = fmt.Errorf("can't accept gc invite: gc %q already exists",
            invite.ID.String())
    }
    return err
}

When GetGC finds the GC locally, the early return skips both
AddGCInvite (persist the pending invite) and notifyInvitedToGC (the
OnInvitedToGCNtfn). The user never sees the invite.

Impact

A user whose local GC copy is stale - common after a backup/restore where the
live roster has since dropped them - cannot be re-added: the admin's re-invite
is dropped, so there is no way to accept and refresh the local copy.

Why storing the invite when the GC exists is safe

Accepting the invite triggers the normal join -> RMGroupList flow, and
handleGCList already routes an existing GC to maybeUpdateGC, which refreshes
the roster while validating the sender's admin permission against the local
metadata and rejecting generation backtracks. So storing the invite simply
unblocks the existing, safe recovery path. A forged invite from a non-admin can
at most surface a notification (the invite path has never authenticated the
inviter - same as for new GCs) and cannot alter the GC.

Suggested fix

Only fail handleGCInvite on a real DB error; store the invite and notify even
when the GC already exists. I have a patch that passes the existing GC e2e suite
and can open a PR.

Version

Present on master and v0.2.4.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions