diff --git a/syncapi/internal/history_visibility.go b/syncapi/internal/history_visibility.go index f5cb4b48b..3fbb24052 100644 --- a/syncapi/internal/history_visibility.go +++ b/syncapi/internal/history_visibility.go @@ -97,6 +97,7 @@ func ApplyHistoryVisibilityFilter( ctx context.Context, syncDB storage.Database, events []*gomatrixserverlib.HeaderedEvent, + alwaysIncludeEventIDs map[string]struct{}, userID string, ) ([]*gomatrixserverlib.HeaderedEvent, error) { eventsFiltered := make([]*gomatrixserverlib.HeaderedEvent, 0, len(events)) @@ -105,8 +106,15 @@ func ApplyHistoryVisibilityFilter( return eventsFiltered, err } for _, ev := range events { + // Always include specific state events for /sync responses + if alwaysIncludeEventIDs != nil { + if _, ok := alwaysIncludeEventIDs[ev.EventID()]; ok { + eventsFiltered = append(eventsFiltered, ev) + continue + } + } // NOTSPEC: Always allow user to see their own membership events (spec contains more "rules") - if _, err = ev.Membership(); err == nil && ev.Sender() == userID { + if ev.Type() == gomatrixserverlib.MRoomMember && ev.StateKey() != nil && *ev.StateKey() == userID { eventsFiltered = append(eventsFiltered, ev) continue } @@ -123,6 +131,7 @@ func ApplyHistoryVisibilityFilter( } } } + // do the actual check if stateForEvents.allowed(ev.EventID()) { eventsFiltered = append(eventsFiltered, ev) } diff --git a/syncapi/routing/context.go b/syncapi/routing/context.go index 5f1aed007..88d869187 100644 --- a/syncapi/routing/context.go +++ b/syncapi/routing/context.go @@ -107,7 +107,7 @@ func Context( } // verify the user is allowed to see the context for this room/event - filteredEvent, err := internal.ApplyHistoryVisibilityFilter(ctx, syncDB, []*gomatrixserverlib.HeaderedEvent{&requestedEvent}, device.UserID) + filteredEvent, err := internal.ApplyHistoryVisibilityFilter(ctx, syncDB, []*gomatrixserverlib.HeaderedEvent{&requestedEvent}, nil, device.UserID) if err != nil { logrus.WithError(err).Error("unable to apply history visibility filter") return jsonerror.InternalServerError() @@ -131,12 +131,12 @@ func Context( return jsonerror.InternalServerError() } - eventsBeforeFiltered, err := internal.ApplyHistoryVisibilityFilter(ctx, syncDB, eventsBefore, device.UserID) + eventsBeforeFiltered, err := internal.ApplyHistoryVisibilityFilter(ctx, syncDB, eventsBefore, nil, device.UserID) if err != nil { logrus.WithError(err).Error("unable to apply history visibility filter") return jsonerror.InternalServerError() } - eventsAfterFiltered, err := internal.ApplyHistoryVisibilityFilter(ctx, syncDB, eventsAfter, device.UserID) + eventsAfterFiltered, err := internal.ApplyHistoryVisibilityFilter(ctx, syncDB, eventsAfter, nil, device.UserID) if err != nil { logrus.WithError(err).Error("unable to apply history visibility filter") return jsonerror.InternalServerError() diff --git a/syncapi/routing/messages.go b/syncapi/routing/messages.go index fd25a22b9..56350c01a 100644 --- a/syncapi/routing/messages.go +++ b/syncapi/routing/messages.go @@ -329,7 +329,7 @@ func (r *messagesReq) retrieveEvents() ( } // Apply room history visibility filter - filteredEvents, err := internal.ApplyHistoryVisibilityFilter(r.ctx, r.db, events, r.device.UserID) + filteredEvents, err := internal.ApplyHistoryVisibilityFilter(r.ctx, r.db, events, nil, r.device.UserID) return gomatrixserverlib.HeaderedToClientEvents(filteredEvents, gomatrixserverlib.FormatAll), start, end, err } diff --git a/syncapi/streams/stream_pdu.go b/syncapi/streams/stream_pdu.go index 216b200e3..6c2271e68 100644 --- a/syncapi/streams/stream_pdu.go +++ b/syncapi/streams/stream_pdu.go @@ -298,26 +298,50 @@ func (p *PDUStreamProvider) addRoomDeltaToResponse( switch delta.Membership { case gomatrixserverlib.Join: + // We need to make sure we always include the latest states events, if they are in the timeline + stateEvents, err := p.DB.CurrentState(ctx, delta.RoomID, &gomatrixserverlib.StateFilter{Limit: 1000}, nil) + if err != nil { + logrus.WithError(err).Warnf("failed to get current state") + } + alwaysIncludeIDs := make(map[string]struct{}, len(stateEvents)) + for _, ev := range stateEvents { + alwaysIncludeIDs[ev.EventID()] = struct{}{} + } + + events, err := internal.ApplyHistoryVisibilityFilter(ctx, p.DB, recentEvents, alwaysIncludeIDs, device.UserID) + if err != nil { + logrus.WithError(err).Error("unable to apply history visibility filter") + return r.From, err + } jr := types.NewJoinResponse() if hasMembershipChange { p.addRoomSummary(ctx, jr, delta.RoomID, device.UserID, latestPosition) } jr.Timeline.PrevBatch = &prevBatch - events, err := internal.ApplyHistoryVisibilityFilter(ctx, p.DB, recentEvents, device.UserID) - if err != nil { - logrus.WithError(err).Error("unable to apply history visibility filter") - return r.From, err - } jr.Timeline.Events = gomatrixserverlib.HeaderedToClientEvents(events, gomatrixserverlib.FormatSync) jr.Timeline.Limited = limited && len(events) == len(recentEvents) jr.State.Events = gomatrixserverlib.HeaderedToClientEvents(delta.StateEvents, gomatrixserverlib.FormatSync) res.Rooms.Join[delta.RoomID] = *jr case gomatrixserverlib.Peek: + // We need to make sure we always include the latest states events, if they are in the timeline + stateEvents, err := p.DB.CurrentState(ctx, delta.RoomID, &gomatrixserverlib.StateFilter{Limit: 1000}, nil) + if err != nil { + logrus.WithError(err).Warnf("failed to get current state") + } + alwaysIncludeIDs := make(map[string]struct{}, len(stateEvents)) + for _, ev := range stateEvents { + alwaysIncludeIDs[ev.EventID()] = struct{}{} + } + events, err := internal.ApplyHistoryVisibilityFilter(ctx, p.DB, recentEvents, alwaysIncludeIDs, device.UserID) + if err != nil { + logrus.WithError(err).Error("unable to apply history visibility filter") + return r.From, err + } jr := types.NewJoinResponse() jr.Timeline.PrevBatch = &prevBatch - jr.Timeline.Events = gomatrixserverlib.HeaderedToClientEvents(recentEvents, gomatrixserverlib.FormatSync) - jr.Timeline.Limited = limited + jr.Timeline.Events = gomatrixserverlib.HeaderedToClientEvents(events, gomatrixserverlib.FormatSync) + jr.Timeline.Limited = limited && len(events) == len(recentEvents) jr.State.Events = gomatrixserverlib.HeaderedToClientEvents(delta.StateEvents, gomatrixserverlib.FormatSync) res.Rooms.Peek[delta.RoomID] = *jr @@ -442,7 +466,15 @@ func (p *PDUStreamProvider) getJoinResponseForCompleteSync( recentEvents := p.DB.StreamEventsToEvents(device, recentStreamEvents) stateEvents = removeDuplicates(stateEvents, recentEvents) - events, err := internal.ApplyHistoryVisibilityFilter(ctx, p.DB, recentEvents, device.UserID) + fullStateEvents, err := p.DB.CurrentState(ctx, roomID, &gomatrixserverlib.StateFilter{Limit: 1000}, nil) + if err != nil { + return + } + alwaysIncludeIDs := make(map[string]struct{}, len(fullStateEvents)) + for _, ev := range stateEvents { + alwaysIncludeIDs[ev.EventID()] = struct{}{} + } + events, err := internal.ApplyHistoryVisibilityFilter(ctx, p.DB, recentEvents, alwaysIncludeIDs, device.UserID) if err != nil { return nil, err } diff --git a/sytest-whitelist b/sytest-whitelist index 69cd2cd52..88b747748 100644 --- a/sytest-whitelist +++ b/sytest-whitelist @@ -734,4 +734,6 @@ Real users can sync from shared guest_access rooms if joined Real users can sync from invited guest_access rooms if joined Real users can sync from joined guest_access rooms if joined Real users can sync from default guest_access rooms if joined -Only see history_visibility changes on boundaries \ No newline at end of file +Only see history_visibility changes on boundaries +Current state appears in timeline in private history +Current state appears in timeline in private history with many messages before \ No newline at end of file