From f33e2258f6ba3ccb22541146b48cb7f2b02a7c2e Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Tue, 17 Nov 2020 14:34:27 +0000 Subject: [PATCH] Add relationship_room_id|servers to the unsigned section of events --- federationsender/api/api.go | 1 + federationsender/internal/query.go | 11 +-- internal/hooks/hooks.go | 9 +++ internal/mscs/msc2836/msc2836.go | 120 ++++++++++++++++++++++------- internal/mscs/mscs.go | 2 +- roomserver/internal/input/input.go | 1 + 6 files changed, 105 insertions(+), 39 deletions(-) diff --git a/federationsender/api/api.go b/federationsender/api/api.go index 5ae419be4..0952329b4 100644 --- a/federationsender/api/api.go +++ b/federationsender/api/api.go @@ -48,6 +48,7 @@ type FederationSenderInternalAPI interface { // Query the server names of the joined hosts in a room. // Unlike QueryJoinedHostsInRoom, this function returns a de-duplicated slice // containing only the server names (without information for membership events). + // The response will include this server if they are joined to the room. QueryJoinedHostServerNamesInRoom( ctx context.Context, request *QueryJoinedHostServerNamesInRoomRequest, diff --git a/federationsender/internal/query.go b/federationsender/internal/query.go index 253400a2d..8ba228d1b 100644 --- a/federationsender/internal/query.go +++ b/federationsender/internal/query.go @@ -4,7 +4,6 @@ import ( "context" "github.com/matrix-org/dendrite/federationsender/api" - "github.com/matrix-org/gomatrixserverlib" ) // QueryJoinedHostServerNamesInRoom implements api.FederationSenderInternalAPI @@ -13,17 +12,11 @@ func (f *FederationSenderInternalAPI) QueryJoinedHostServerNamesInRoom( request *api.QueryJoinedHostServerNamesInRoomRequest, response *api.QueryJoinedHostServerNamesInRoomResponse, ) (err error) { - joinedHosts, err := f.db.GetJoinedHosts(ctx, request.RoomID) + joinedHosts, err := f.db.GetJoinedHostsForRooms(ctx, []string{request.RoomID}) if err != nil { return } - - response.ServerNames = make([]gomatrixserverlib.ServerName, 0, len(joinedHosts)) - for _, host := range joinedHosts { - response.ServerNames = append(response.ServerNames, host.ServerName) - } - - // TODO: remove duplicates? + response.ServerNames = joinedHosts return } diff --git a/internal/hooks/hooks.go b/internal/hooks/hooks.go index 307911ef1..cf7d5c569 100644 --- a/internal/hooks/hooks.go +++ b/internal/hooks/hooks.go @@ -24,6 +24,15 @@ const ( // Usage: // hooks.Attach(hooks.KindNewEvent, func(headeredEvent interface{}) { ... }) KindNewEvent = "new_event" + // KindModifyNewEvent is a hook which is called with *gomatrixserverlib.HeaderedEvent + // It is run before a new event is processed by the roomserver. This hook can be used + // to modify the event before it is persisted by adding data to `unsigned`. + // Usage: + // hooks.Attach(hooks.KindModifyNewEvent, func(headeredEvent interface{}) { + // ev := headeredEvent.(*gomatrixserverlib.HeaderedEvent) + // _ = ev.SetUnsignedField("key", "val") + // }) + KindModifyNewEvent = "modify_new_event" ) var ( diff --git a/internal/mscs/msc2836/msc2836.go b/internal/mscs/msc2836/msc2836.go index cbf01c07d..76d7459e8 100644 --- a/internal/mscs/msc2836/msc2836.go +++ b/internal/mscs/msc2836/msc2836.go @@ -22,6 +22,7 @@ import ( "net/http" "github.com/matrix-org/dendrite/clientapi/jsonerror" + fs "github.com/matrix-org/dendrite/federationsender/api" "github.com/matrix-org/dendrite/internal/hooks" "github.com/matrix-org/dendrite/internal/httputil" "github.com/matrix-org/dendrite/internal/setup" @@ -31,7 +32,11 @@ import ( "github.com/matrix-org/util" ) -const constRelType = "m.reference" +const ( + constRelType = "m.reference" + constRoomIDKey = "relationship_room_id" + constRoomServers = "relationship_servers" +) type EventRelationshipRequest struct { EventID string `json:"event_id"` @@ -83,7 +88,7 @@ type EventRelationshipResponse struct { } // Enable this MSC -func Enable(base *setup.BaseDendrite, rsAPI roomserver.RoomserverInternalAPI, userAPI userapi.UserInternalAPI) error { +func Enable(base *setup.BaseDendrite, rsAPI roomserver.RoomserverInternalAPI, fsAPI fs.FederationSenderInternalAPI, userAPI userapi.UserInternalAPI) error { db, err := NewDatabase(&base.Cfg.MSCs.Database) if err != nil { return fmt.Errorf("Cannot enable MSC2836: %w", err) @@ -98,6 +103,55 @@ func Enable(base *setup.BaseDendrite, rsAPI roomserver.RoomserverInternalAPI, us ) } }) + hooks.Attach(hooks.KindModifyNewEvent, func(headeredEvent interface{}) { + he := headeredEvent.(*gomatrixserverlib.HeaderedEvent) + ctx := context.Background() + // we only inject metadata for events our server sends + userID := he.Sender() + _, domain, err := gomatrixserverlib.SplitID('@', userID) + if err != nil { + return + } + if domain != base.Cfg.Global.ServerName { + return + } + // if this event has an m.relationship, add on the room_id and servers to unsigned + parent, child, relType := parentChildEventIDs(he) + if parent == "" || child == "" || relType == "" { + return + } + event, joinedToRoom := getEventIfVisible(ctx, rsAPI, parent, userID) + if !joinedToRoom { + return + } + err = he.SetUnsignedField(constRoomIDKey, event.RoomID()) + if err != nil { + util.GetLogger(context.Background()).WithError(err).Warn("Failed to SetUnsignedField") + return + } + + var servers []gomatrixserverlib.ServerName + if fsAPI != nil { + var res fs.QueryJoinedHostServerNamesInRoomResponse + err = fsAPI.QueryJoinedHostServerNamesInRoom(ctx, &fs.QueryJoinedHostServerNamesInRoomRequest{ + RoomID: event.RoomID(), + }, &res) + if err != nil { + util.GetLogger(context.Background()).WithError(err).Warn("Failed to QueryJoinedHostServerNamesInRoom") + return + } + servers = res.ServerNames + } else { + servers = []gomatrixserverlib.ServerName{ + base.Cfg.Global.ServerName, + } + } + err = he.SetUnsignedField(constRoomServers, servers) + if err != nil { + util.GetLogger(context.Background()).WithError(err).Warn("Failed to SetUnsignedField") + return + } + }) base.PublicClientAPIMux.Handle("/unstable/event_relationships", httputil.MakeAuthAPI("eventRelationships", userAPI, eventRelationshipHandler(db, rsAPI)), @@ -264,34 +318,12 @@ func walkThread( } func (rc *reqCtx) getEventIfVisible(eventID string) *gomatrixserverlib.HeaderedEvent { - var queryEventsRes roomserver.QueryEventsByIDResponse - err := rc.rsAPI.QueryEventsByID(rc.ctx, &roomserver.QueryEventsByIDRequest{ - EventIDs: []string{eventID}, - }, &queryEventsRes) - if err != nil { - util.GetLogger(rc.ctx).WithError(err).Error("getEventIfVisible: failed to QueryEventsByID") + event, joinedToRoom := getEventIfVisible(rc.ctx, rc.rsAPI, eventID, rc.userID) + if event == nil { return nil } - if len(queryEventsRes.Events) == 0 { - util.GetLogger(rc.ctx).Infof("event does not exist") - return nil // event does not exist - } - event := queryEventsRes.Events[0] - - // Allow events if the member is in the room - // TODO: This does not honour history_visibility - // TODO: This does not honour m.room.create content - var queryMembershipRes roomserver.QueryMembershipForUserResponse - err = rc.rsAPI.QueryMembershipForUser(rc.ctx, &roomserver.QueryMembershipForUserRequest{ - RoomID: event.RoomID(), - UserID: rc.userID, - }, &queryMembershipRes) - if err != nil { - util.GetLogger(rc.ctx).WithError(err).Error("getEventIfVisible: failed to QueryMembershipForUser") - return nil - } - if queryMembershipRes.IsInRoom { - return &event + if joinedToRoom { + return event } if rc.req.AutoJoin { var joinRes roomserver.PerformJoinResponse @@ -305,12 +337,42 @@ func (rc *reqCtx) getEventIfVisible(eventID string) *gomatrixserverlib.HeaderedE util.GetLogger(rc.ctx).WithError(joinRes.Error).WithField("room_id", event.RoomID()).Error("Failed to auto-join room") return nil } - return &event + return event } util.GetLogger(rc.ctx).Infof("user not in room and auto_join disabled") return nil } +func getEventIfVisible(ctx context.Context, rsAPI roomserver.RoomserverInternalAPI, eventID, userID string) (*gomatrixserverlib.HeaderedEvent, bool) { + var queryEventsRes roomserver.QueryEventsByIDResponse + err := rsAPI.QueryEventsByID(ctx, &roomserver.QueryEventsByIDRequest{ + EventIDs: []string{eventID}, + }, &queryEventsRes) + if err != nil { + util.GetLogger(ctx).WithError(err).Error("getEventIfVisible: failed to QueryEventsByID") + return nil, false + } + if len(queryEventsRes.Events) == 0 { + util.GetLogger(ctx).Infof("event does not exist") + return nil, false // event does not exist + } + event := queryEventsRes.Events[0] + + // Allow events if the member is in the room + // TODO: This does not honour history_visibility + // TODO: This does not honour m.room.create content + var queryMembershipRes roomserver.QueryMembershipForUserResponse + err = rsAPI.QueryMembershipForUser(ctx, &roomserver.QueryMembershipForUserRequest{ + RoomID: event.RoomID(), + UserID: userID, + }, &queryMembershipRes) + if err != nil { + util.GetLogger(ctx).WithError(err).Error("getEventIfVisible: failed to QueryMembershipForUser") + return nil, false + } + return &event, queryMembershipRes.IsInRoom +} + type walkInfo struct { eventInfo SiblingNumber int diff --git a/internal/mscs/mscs.go b/internal/mscs/mscs.go index a1c358cfe..41384a6a2 100644 --- a/internal/mscs/mscs.go +++ b/internal/mscs/mscs.go @@ -35,7 +35,7 @@ func Enable(base *setup.BaseDendrite, monolith *setup.Monolith) error { func EnableMSC(base *setup.BaseDendrite, monolith *setup.Monolith, msc string) error { switch msc { case "msc2836": - return msc2836.Enable(base, monolith.RoomserverAPI, monolith.UserAPI) + return msc2836.Enable(base, monolith.RoomserverAPI, monolith.FederationSenderAPI, monolith.UserAPI) default: return fmt.Errorf("EnableMSC: unknown msc '%s'", msc) } diff --git a/roomserver/internal/input/input.go b/roomserver/internal/input/input.go index d25030a3c..d1b03ae50 100644 --- a/roomserver/internal/input/input.go +++ b/roomserver/internal/input/input.go @@ -62,6 +62,7 @@ func (w *inputWorker) start() { for { select { case task := <-w.input: + hooks.Run(hooks.KindModifyNewEvent, &task.event.Event) _, task.err = w.r.processRoomEvent(task.ctx, task.event) if task.err == nil { hooks.Run(hooks.KindNewEvent, &task.event.Event)