aboutsummaryrefslogtreecommitdiff
path: root/syncapi/routing
diff options
context:
space:
mode:
authorKegsay <kegan@matrix.org>2020-10-02 17:08:13 +0100
committerGitHub <noreply@github.com>2020-10-02 17:08:13 +0100
commit279044cd90722ba98b018b0aa277285113454822 (patch)
tree1e314a235663692dd48e99a345f00f216282004a /syncapi/routing
parentc870435c17676d2b0272420242c1b0761c38fe35 (diff)
Add history visibility guards (#1470)
* Add history visibility guards Default to 'joined' visibility to avoid leaking events, until we get around to implementing history visibility completely. Related #617 * Don't apply his vis checks on shared rooms * Fix order of checks * Linting and remove another misleading check * Update whitelist
Diffstat (limited to 'syncapi/routing')
-rw-r--r--syncapi/routing/messages.go93
-rw-r--r--syncapi/routing/routing.go2
2 files changed, 93 insertions, 2 deletions
diff --git a/syncapi/routing/messages.go b/syncapi/routing/messages.go
index 6447e5d5..9c6c6a80 100644
--- a/syncapi/routing/messages.go
+++ b/syncapi/routing/messages.go
@@ -26,6 +26,7 @@ import (
"github.com/matrix-org/dendrite/roomserver/api"
"github.com/matrix-org/dendrite/syncapi/storage"
"github.com/matrix-org/dendrite/syncapi/types"
+ userapi "github.com/matrix-org/dendrite/userapi/api"
"github.com/matrix-org/gomatrixserverlib"
"github.com/matrix-org/util"
"github.com/sirupsen/logrus"
@@ -41,6 +42,7 @@ type messagesReq struct {
from *types.TopologyToken
to *types.TopologyToken
fromStream *types.StreamingToken
+ device *userapi.Device
wasToProvided bool
limit int
backwardOrdering bool
@@ -58,7 +60,7 @@ const defaultMessagesLimit = 10
// client-server API.
// See: https://matrix.org/docs/spec/client_server/latest.html#get-matrix-client-r0-rooms-roomid-messages
func OnIncomingMessagesRequest(
- req *http.Request, db storage.Database, roomID string,
+ req *http.Request, db storage.Database, roomID string, device *userapi.Device,
federation *gomatrixserverlib.FederationClient,
rsAPI api.RoomserverInternalAPI,
cfg *config.SyncAPI,
@@ -151,6 +153,7 @@ func OnIncomingMessagesRequest(
wasToProvided: wasToProvided,
limit: limit,
backwardOrdering: backwardOrdering,
+ device: device,
}
clientEvents, start, end, err := mReq.retrieveEvents()
@@ -238,6 +241,10 @@ func (r *messagesReq) retrieveEvents() (
}
events = reversed(events)
}
+ events = r.filterHistoryVisible(events)
+ if len(events) == 0 {
+ return []gomatrixserverlib.ClientEvent{}, *r.from, *r.to, nil
+ }
// Convert all of the events into client events.
clientEvents = gomatrixserverlib.HeaderedToClientEvents(events, gomatrixserverlib.FormatAll)
@@ -252,6 +259,90 @@ func (r *messagesReq) retrieveEvents() (
return clientEvents, start, end, err
}
+// nolint:gocyclo
+func (r *messagesReq) filterHistoryVisible(events []gomatrixserverlib.HeaderedEvent) []gomatrixserverlib.HeaderedEvent {
+ // TODO FIXME: We don't fully implement history visibility yet. To avoid leaking events which the
+ // user shouldn't see, we check the recent events and remove any prior to the join event of the user
+ // which is equiv to history_visibility: joined
+ joinEventIndex := -1
+ for i, ev := range events {
+ if ev.Type() == gomatrixserverlib.MRoomMember && ev.StateKeyEquals(r.device.UserID) {
+ membership, _ := ev.Membership()
+ if membership == "join" {
+ joinEventIndex = i
+ break
+ }
+ }
+ }
+
+ var result []gomatrixserverlib.HeaderedEvent
+ var eventsToCheck []gomatrixserverlib.HeaderedEvent
+ if joinEventIndex != -1 {
+ if r.backwardOrdering {
+ result = events[:joinEventIndex+1]
+ eventsToCheck = append(eventsToCheck, result[0])
+ } else {
+ result = events[joinEventIndex:]
+ eventsToCheck = append(eventsToCheck, result[len(result)-1])
+ }
+ } else {
+ eventsToCheck = []gomatrixserverlib.HeaderedEvent{events[0], events[len(events)-1]}
+ result = events
+ }
+ // make sure the user was in the room for both the earliest and latest events, we need this because
+ // some backpagination results will not have the join event (e.g if they hit /messages at the join event itself)
+ wasJoined := true
+ for _, ev := range eventsToCheck {
+ var queryRes api.QueryStateAfterEventsResponse
+ err := r.rsAPI.QueryStateAfterEvents(r.ctx, &api.QueryStateAfterEventsRequest{
+ RoomID: ev.RoomID(),
+ PrevEventIDs: ev.PrevEventIDs(),
+ StateToFetch: []gomatrixserverlib.StateKeyTuple{
+ {EventType: gomatrixserverlib.MRoomMember, StateKey: r.device.UserID},
+ {EventType: gomatrixserverlib.MRoomHistoryVisibility, StateKey: ""},
+ },
+ }, &queryRes)
+ if err != nil {
+ wasJoined = false
+ break
+ }
+ var hisVisEvent, membershipEvent *gomatrixserverlib.HeaderedEvent
+ for i := range queryRes.StateEvents {
+ switch queryRes.StateEvents[i].Type() {
+ case gomatrixserverlib.MRoomMember:
+ membershipEvent = &queryRes.StateEvents[i]
+ case gomatrixserverlib.MRoomHistoryVisibility:
+ hisVisEvent = &queryRes.StateEvents[i]
+ }
+ }
+ if hisVisEvent == nil {
+ return events // apply no filtering as it defaults to Shared.
+ }
+ hisVis, _ := hisVisEvent.HistoryVisibility()
+ if hisVis == "shared" {
+ return events // apply no filtering
+ }
+ if membershipEvent == nil {
+ wasJoined = false
+ break
+ }
+ membership, err := membershipEvent.Membership()
+ if err != nil {
+ wasJoined = false
+ break
+ }
+ if membership != "join" {
+ wasJoined = false
+ break
+ }
+ }
+ if !wasJoined {
+ util.GetLogger(r.ctx).WithField("num_events", len(events)).Warnf("%s was not joined to room during these events, omitting them", r.device.UserID)
+ return []gomatrixserverlib.HeaderedEvent{}
+ }
+ return result
+}
+
func (r *messagesReq) getStartEnd(events []gomatrixserverlib.HeaderedEvent) (start, end types.TopologyToken, err error) {
start, err = r.db.EventPositionInTopology(
r.ctx, events[0].EventID(),
diff --git a/syncapi/routing/routing.go b/syncapi/routing/routing.go
index f42679c6..141eec79 100644
--- a/syncapi/routing/routing.go
+++ b/syncapi/routing/routing.go
@@ -51,7 +51,7 @@ func Setup(
if err != nil {
return util.ErrorResponse(err)
}
- return OnIncomingMessagesRequest(req, syncDB, vars["roomID"], federation, rsAPI, cfg)
+ return OnIncomingMessagesRequest(req, syncDB, vars["roomID"], device, federation, rsAPI, cfg)
})).Methods(http.MethodGet, http.MethodOptions)
r0mux.Handle("/user/{userId}/filter",