diff --git a/syncapi/storage/postgres/invites_table.go b/syncapi/storage/postgres/invites_table.go index 530dc6452..eed58c158 100644 --- a/syncapi/storage/postgres/invites_table.go +++ b/syncapi/storage/postgres/invites_table.go @@ -139,6 +139,14 @@ func (s *inviteEventsStatements) SelectInviteEventsInRange( return nil, nil, err } + // if we have seen this room before, it has a higher stream position and hence takes priority + // because the query is ORDER BY id DESC so drop them + _, isRetired := retired[roomID] + _, isInvited := result[roomID] + if isRetired || isInvited { + continue + } + var event gomatrixserverlib.HeaderedEvent if err := json.Unmarshal(eventJSON, &event); err != nil { return nil, nil, err diff --git a/syncapi/storage/sqlite3/invites_table.go b/syncapi/storage/sqlite3/invites_table.go index 45862efbb..7da866831 100644 --- a/syncapi/storage/sqlite3/invites_table.go +++ b/syncapi/storage/sqlite3/invites_table.go @@ -150,6 +150,14 @@ func (s *inviteEventsStatements) SelectInviteEventsInRange( return nil, nil, err } + // if we have seen this room before, it has a higher stream position and hence takes priority + // because the query is ORDER BY id DESC so drop them + _, isRetired := retired[roomID] + _, isInvited := result[roomID] + if isRetired || isInvited { + continue + } + var event gomatrixserverlib.HeaderedEvent if err := json.Unmarshal(eventJSON, &event); err != nil { return nil, nil, err diff --git a/syncapi/storage/tables/interface.go b/syncapi/storage/tables/interface.go index 9d239d233..2ff229cbc 100644 --- a/syncapi/storage/tables/interface.go +++ b/syncapi/storage/tables/interface.go @@ -33,7 +33,8 @@ type AccountData interface { type Invites interface { InsertInviteEvent(ctx context.Context, txn *sql.Tx, inviteEvent gomatrixserverlib.HeaderedEvent) (streamPos types.StreamPosition, err error) DeleteInviteEvent(ctx context.Context, inviteEventID string) (types.StreamPosition, error) - // SelectInviteEventsInRange returns a map of room ID to invite events. + // SelectInviteEventsInRange returns a map of room ID to invite events. If multiple invite/retired invites exist in the given range, return the latest value + // for the room. SelectInviteEventsInRange(ctx context.Context, txn *sql.Tx, targetUserID string, r types.Range) (invites map[string]gomatrixserverlib.HeaderedEvent, retired map[string]gomatrixserverlib.HeaderedEvent, err error) SelectMaxInviteID(ctx context.Context, txn *sql.Tx) (id int64, err error) } diff --git a/sytest-whitelist b/sytest-whitelist index 8084bbe39..a17ed8407 100644 --- a/sytest-whitelist +++ b/sytest-whitelist @@ -421,6 +421,7 @@ Remote users may not join unfederated rooms Non-numeric ports in server names are rejected Invited user can reject invite over federation Invited user can reject invite over federation for empty room +Invited user can reject invite over federation several times Can reject invites over federation for rooms with version 1 Can reject invites over federation for rooms with version 2 Can reject invites over federation for rooms with version 3