Extract room ID and servers from previous events; refactor a bit

This commit is contained in:
Kegan Dougal 2020-11-23 18:38:52 +00:00
parent d3451b1ab8
commit 7bfd7bbeb1

View file

@ -124,7 +124,7 @@ type reqCtx struct {
db Database db Database
req *EventRelationshipRequest req *EventRelationshipRequest
userID string userID string
authorisedRoomIDs map[string]bool // events from these rooms can be returned authorisedRoomIDs map[string]gomatrixserverlib.RoomVersion // events from these rooms can be returned
// federated request args // federated request args
isFederatedRequest bool isFederatedRequest bool
@ -149,6 +149,7 @@ func eventRelationshipHandler(db Database, rsAPI roomserver.RoomserverInternalAP
rsAPI: rsAPI, rsAPI: rsAPI,
isFederatedRequest: false, isFederatedRequest: false,
db: db, db: db,
authorisedRoomIDs: make(map[string]gomatrixserverlib.RoomVersion),
} }
res, resErr := rc.process() res, resErr := rc.process()
if resErr != nil { if resErr != nil {
@ -174,10 +175,11 @@ func federatedEventRelationship(
} }
} }
rc := reqCtx{ rc := reqCtx{
ctx: ctx, ctx: ctx,
req: relation, req: relation,
rsAPI: rsAPI, rsAPI: rsAPI,
db: db, db: db,
authorisedRoomIDs: make(map[string]gomatrixserverlib.RoomVersion),
// federation args // federation args
isFederatedRequest: true, isFederatedRequest: true,
fsAPI: fsAPI, fsAPI: fsAPI,
@ -254,7 +256,7 @@ func (rc *reqCtx) includeParent(childEvent *gomatrixserverlib.HeaderedEvent) (pa
if parentID == "" { if parentID == "" {
return nil return nil
} }
return rc.getLocalEventIfVisible(parentID) return rc.lookForEvent(parentID)
} }
// If include_children: true, lookup all events which have event_id as an m.relationship // If include_children: true, lookup all events which have event_id as an m.relationship
@ -269,7 +271,7 @@ func (rc *reqCtx) includeChildren(db Database, parentID string, limit int, recen
} }
var childEvents []*gomatrixserverlib.HeaderedEvent var childEvents []*gomatrixserverlib.HeaderedEvent
for _, child := range children { for _, child := range children {
childEvent := rc.getLocalEventIfVisible(child.EventID) childEvent := rc.lookForEvent(child.EventID)
if childEvent != nil { if childEvent != nil {
childEvents = append(childEvents, childEvent) childEvents = append(childEvents, childEvent)
} }
@ -307,8 +309,11 @@ func walkThread(
} }
// Process the event. // Process the event.
// TODO: Include edge information: room ID and servers // TODO XXX: if event is not found, use remoteEventRelationships to explore that part of the thread remotely.
event := rc.getLocalEventIfVisible(wi.EventID) // This will probably be easiest if the event relationships response is directly pumped into the database
// so the next walk will do the right thing. This requires those events to be authed and likely injected as
// outliers into the roomserver DB, which will de-dupe appropriately.
event := rc.lookForEvent(wi.EventID)
if event != nil { if event != nil {
result = append(result, event) result = append(result, event)
} }
@ -343,14 +348,12 @@ func (rc *reqCtx) MSC2836EventRelationships(eventID string, srv gomatrixserverli
} }
// TODO: getRemoteEventIfVisible: if event ID is unknown, blindly attempt to join (which room? Origin, via who?) then hit /event_relationships.
// authorisedToSeeEvent authenticates that the user or server is allowed to see this event. Returns true if allowed to // authorisedToSeeEvent authenticates that the user or server is allowed to see this event. Returns true if allowed to
// see this request. // see this request.
func (rc *reqCtx) authorisedToSeeEvent(event *gomatrixserverlib.HeaderedEvent) bool { func (rc *reqCtx) authorisedToSeeEvent(event *gomatrixserverlib.HeaderedEvent) bool {
authorised, ok := rc.authorisedRoomIDs[event.RoomID()] authorised, ok := rc.authorisedRoomIDs[event.RoomID()]
if ok { if ok {
return authorised return len(authorised) > 0
} }
if rc.isFederatedRequest { if rc.isFederatedRequest {
// make sure the server is in this room // make sure the server is in this room
@ -364,7 +367,7 @@ func (rc *reqCtx) authorisedToSeeEvent(event *gomatrixserverlib.HeaderedEvent) b
} }
for _, srv := range res.ServerNames { for _, srv := range res.ServerNames {
if srv == rc.serverName { if srv == rc.serverName {
rc.authorisedRoomIDs[event.RoomID()] = true rc.authorisedRoomIDs[event.RoomID()] = event.Version()
return true return true
} }
} }
@ -375,15 +378,95 @@ func (rc *reqCtx) authorisedToSeeEvent(event *gomatrixserverlib.HeaderedEvent) b
if err != nil || !joinedToRoom { if err != nil || !joinedToRoom {
return false return false
} }
rc.authorisedRoomIDs[event.RoomID()] = true rc.authorisedRoomIDs[event.RoomID()] = event.Version()
return true return true
} }
// getLocalEventIfVisible returns the event for the event ID given, by trying to auto-join rooms if not authorised func (rc *reqCtx) getServersForEventID(eventID string) (string, gomatrixserverlib.RoomVersion, []gomatrixserverlib.ServerName) {
func (rc *reqCtx) getLocalEventIfVisible(eventID string) *gomatrixserverlib.HeaderedEvent { if len(rc.authorisedRoomIDs) != 1 {
util.GetLogger(rc.ctx).WithField("event_id", eventID).Error(
"getServersForEventID: thread exists over multiple rooms and reached unknown event, cannot determine room and hence which servers to query",
)
return "", "", nil
}
var roomID string
var roomVer gomatrixserverlib.RoomVersion
for r, v := range rc.authorisedRoomIDs {
roomID = r
roomVer = v
}
var queryRes fs.QueryJoinedHostServerNamesInRoomResponse
err := rc.fsAPI.QueryJoinedHostServerNamesInRoom(rc.ctx, &fs.QueryJoinedHostServerNamesInRoomRequest{
RoomID: roomID,
}, &queryRes)
if err != nil {
util.GetLogger(rc.ctx).WithError(err).Error("getServersForEventID: failed to QueryJoinedHostServerNamesInRoom")
return "", "", nil
}
// query up to 5 servers
serversToQuery := queryRes.ServerNames
if len(serversToQuery) > 5 {
serversToQuery = serversToQuery[:5]
}
return roomID, roomVer, serversToQuery
}
// remoteEvent queries for the event ID given.
func (rc *reqCtx) remoteEvent(eventID string) *gomatrixserverlib.HeaderedEvent {
if rc.isFederatedRequest {
return nil // we don't query remote servers for remote requests
}
_, roomVer, serversToQuery := rc.getServersForEventID(eventID)
for _, s := range serversToQuery {
txn, err := rc.fsAPI.GetEvent(rc.ctx, s, eventID)
if err != nil {
util.GetLogger(rc.ctx).WithError(err).Warn("remoteEvent: failed to GetEvent")
continue
}
if len(txn.PDUs) != 1 {
continue
}
ev, err := gomatrixserverlib.NewEventFromUntrustedJSON(txn.PDUs[0], roomVer)
if err != nil {
util.GetLogger(rc.ctx).WithError(err).Warn("remoteEvent: failed to NewEventFromUntrustedJSON")
continue
}
// TODO: check sigs on event
// TODO: check auth events on event
return ev.Headered(roomVer)
}
return nil
}
// nolint:unused
func (rc *reqCtx) remoteEventRelationships(eventID string) *gomatrixserverlib.MSC2836EventRelationshipsResponse {
if rc.isFederatedRequest {
return nil // we don't query remote servers for remote requests
}
_, roomVer, serversToQuery := rc.getServersForEventID(eventID)
var res *gomatrixserverlib.MSC2836EventRelationshipsResponse
var err error
for _, srv := range serversToQuery {
res, err = rc.MSC2836EventRelationships(eventID, srv, roomVer)
if err != nil {
util.GetLogger(rc.ctx).WithError(err).WithField("server", srv).Error("remoteEventRelationships: failed to call MSC2836EventRelationships")
} else {
break
}
}
return res
}
// lookForEvent returns the event for the event ID given, by trying to auto-join rooms if not authorised and by querying remote servers
// if the event ID is unknown.
func (rc *reqCtx) lookForEvent(eventID string) *gomatrixserverlib.HeaderedEvent {
event := rc.getLocalEvent(eventID) event := rc.getLocalEvent(eventID)
if event == nil { if event == nil {
return nil // this event may have occurred before we joined the room, so delegate to another server to see if they know anything.
event = rc.remoteEvent(eventID)
if event == nil {
return nil
}
} }
if rc.authorisedToSeeEvent(event) { if rc.authorisedToSeeEvent(event) {
return event return event