From 9096bfcee8b22b99b4ddd1f1f56ee7aa59280268 Mon Sep 17 00:00:00 2001 From: Kegsay Date: Sat, 10 Oct 2020 00:21:15 +0100 Subject: [PATCH] Validate m.room.create events in send_join responses (#1505) * Validate m.room.create events in send_join responses For sytest compliance, refs #1315 and #1317 Fixes #1317 * Linting --- federationsender/internal/perform.go | 58 +++++++++++++++++++++++++++- sytest-whitelist | 2 + 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/federationsender/internal/perform.go b/federationsender/internal/perform.go index d014ca5c..bff6833c 100644 --- a/federationsender/internal/perform.go +++ b/federationsender/internal/perform.go @@ -2,6 +2,7 @@ package internal import ( "context" + "encoding/json" "errors" "fmt" "time" @@ -174,8 +175,10 @@ func (r *FederationSenderInternalAPI) performJoinUsingServer( // Work out if we support the room version that has been supplied in // the make_join response. + // "If not provided, the room version is assumed to be either "1" or "2"." + // https://matrix.org/docs/spec/server_server/unstable#get-matrix-federation-v1-make-join-roomid-userid if respMakeJoin.RoomVersion == "" { - respMakeJoin.RoomVersion = gomatrixserverlib.RoomVersionV1 + respMakeJoin.RoomVersion = setDefaultRoomVersionFromJoinEvent(respMakeJoin.JoinEvent) } if _, err = respMakeJoin.RoomVersion.EventFormat(); err != nil { return fmt.Errorf("respMakeJoin.RoomVersion.EventFormat: %w", err) @@ -205,6 +208,9 @@ func (r *FederationSenderInternalAPI) performJoinUsingServer( return fmt.Errorf("r.federation.SendJoin: %w", err) } r.statistics.ForServer(serverName).Success() + if err := sanityCheckSendJoinResponse(respSendJoin); err != nil { + return err + } // Process the join response in a goroutine. The idea here is // that we'll try and wait for as long as possible for the work @@ -424,3 +430,53 @@ func (r *FederationSenderInternalAPI) PerformBroadcastEDU( return nil } + +func sanityCheckSendJoinResponse(respSendJoin gomatrixserverlib.RespSendJoin) error { + // sanity check we have a create event and it has a known room version + for _, ev := range respSendJoin.AuthEvents { + if ev.Type() == gomatrixserverlib.MRoomCreate && ev.StateKeyEquals("") { + // make sure the room version is known + content := ev.Content() + verBody := struct { + Version string `json:"room_version"` + }{} + err := json.Unmarshal(content, &verBody) + if err != nil { + return err + } + if verBody.Version == "" { + // https://matrix.org/docs/spec/client_server/r0.6.0#m-room-create + // The version of the room. Defaults to "1" if the key does not exist. + verBody.Version = "1" + } + knownVersions := gomatrixserverlib.RoomVersions() + if _, ok := knownVersions[gomatrixserverlib.RoomVersion(verBody.Version)]; !ok { + return fmt.Errorf("send_join m.room.create event has an unknown room version: %s", verBody.Version) + } + return nil + } + } + return fmt.Errorf("send_join response is missing m.room.create event") +} + +func setDefaultRoomVersionFromJoinEvent(joinEvent gomatrixserverlib.EventBuilder) gomatrixserverlib.RoomVersion { + // if auth events are not event references we know it must be v3+ + // we have to do these shenanigans to satisfy sytest, specifically for: + // "Outbound federation rejects m.room.create events with an unknown room version" + hasEventRefs := true + authEvents, ok := joinEvent.AuthEvents.([]interface{}) + if ok { + if len(authEvents) > 0 { + _, ok = authEvents[0].(string) + if ok { + // event refs are objects, not strings, so we know we must be dealing with a v3+ room. + hasEventRefs = false + } + } + } + + if hasEventRefs { + return gomatrixserverlib.RoomVersionV1 + } + return gomatrixserverlib.RoomVersionV4 +} diff --git a/sytest-whitelist b/sytest-whitelist index 099fc6cb..805f0e4d 100644 --- a/sytest-whitelist +++ b/sytest-whitelist @@ -68,6 +68,8 @@ Request to logout with invalid an access token is rejected Request to logout without an access token is rejected Room creation reports m.room.create to myself Room creation reports m.room.member to myself +Outbound federation rejects send_join responses with no m.room.create event +Outbound federation rejects m.room.create events with an unknown room version Invited user can see room metadata # Blacklisted because these tests call /r0/events which we don't implement # New room members see their own join event