aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--clientapi/routing/capabilities.go2
-rw-r--r--clientapi/routing/joinroom.go23
-rw-r--r--common/events.go42
-rw-r--r--federationapi/routing/join.go38
-rw-r--r--federationapi/routing/routing.go38
-rw-r--r--federationapi/routing/state.go3
-rw-r--r--go.mod6
-rw-r--r--go.sum15
-rw-r--r--roomserver/api/query.go3
-rw-r--r--roomserver/query/query.go10
-rw-r--r--roomserver/state/state.go80
-rw-r--r--roomserver/version/version.go8
-rw-r--r--sytest-blacklist5
-rw-r--r--sytest-whitelist17
14 files changed, 235 insertions, 55 deletions
diff --git a/clientapi/routing/capabilities.go b/clientapi/routing/capabilities.go
index 0c583055..1792c630 100644
--- a/clientapi/routing/capabilities.go
+++ b/clientapi/routing/capabilities.go
@@ -29,7 +29,7 @@ func GetCapabilities(
req *http.Request, queryAPI roomserverAPI.RoomserverQueryAPI,
) util.JSONResponse {
roomVersionsQueryReq := roomserverAPI.QueryRoomVersionCapabilitiesRequest{}
- var roomVersionsQueryRes roomserverAPI.QueryRoomVersionCapabilitiesResponse
+ roomVersionsQueryRes := roomserverAPI.QueryRoomVersionCapabilitiesResponse{}
if err := queryAPI.QueryRoomVersionCapabilities(
req.Context(),
&roomVersionsQueryReq,
diff --git a/clientapi/routing/joinroom.go b/clientapi/routing/joinroom.go
index 3ca7d052..0f1a9ba4 100644
--- a/clientapi/routing/joinroom.go
+++ b/clientapi/routing/joinroom.go
@@ -242,6 +242,9 @@ func (r joinRoomReq) joinRoomUsingServers(
queryRes := roomserverAPI.QueryLatestEventsAndStateResponse{}
event, err := common.BuildEvent(r.req.Context(), &eb, r.cfg, r.evTime, r.queryAPI, &queryRes)
if err == nil {
+ // If we have successfully built an event at this point then we can
+ // assert that the room is a local room, as BuildEvent was able to
+ // add prev_events etc successfully.
if _, err = r.producer.SendEvents(
r.req.Context(),
[]gomatrixserverlib.HeaderedEvent{
@@ -260,6 +263,10 @@ func (r joinRoomReq) joinRoomUsingServers(
}{roomID},
}
}
+
+ // Otherwise, if we've reached here, then we haven't been able to populate
+ // prev_events etc for the room, therefore the room is probably federated.
+
// TODO: This needs to be re-thought, as in the case of an invite, the room
// will exist in the database in roomserver_rooms but won't have any state
// events, therefore this below check fails.
@@ -323,14 +330,14 @@ func (r joinRoomReq) joinRoomUsingServer(roomID string, server gomatrixserverlib
respMakeJoin, err := r.federation.MakeJoin(r.req.Context(), server, roomID, r.userID, supportedVersions)
if err != nil {
// TODO: Check if the user was not allowed to join the room.
- return nil, err
+ return nil, fmt.Errorf("r.federation.MakeJoin: %w", err)
}
// Set all the fields to be what they should be, this should be a no-op
// but it's possible that the remote server returned us something "odd"
err = r.writeToBuilder(&respMakeJoin.JoinEvent, roomID)
if err != nil {
- return nil, err
+ return nil, fmt.Errorf("r.writeToBuilder: %w", err)
}
if respMakeJoin.RoomVersion == "" {
@@ -350,18 +357,16 @@ func (r joinRoomReq) joinRoomUsingServer(roomID string, server gomatrixserverlib
r.cfg.Matrix.PrivateKey, respMakeJoin.RoomVersion,
)
if err != nil {
- util.GetLogger(r.req.Context()).WithError(err).Error("respMakeJoin.JoinEvent.Build failed")
- res := jsonerror.InternalServerError()
- return &res, nil
+ return nil, fmt.Errorf("respMakeJoin.JoinEvent.Build: %w", err)
}
respSendJoin, err := r.federation.SendJoin(r.req.Context(), server, event, respMakeJoin.RoomVersion)
if err != nil {
- return nil, err
+ return nil, fmt.Errorf("r.federation.SendJoin: %w", err)
}
if err = respSendJoin.Check(r.req.Context(), r.keyRing, event); err != nil {
- return nil, err
+ return nil, fmt.Errorf("respSendJoin: %w", err)
}
if err = r.producer.SendEventWithState(
@@ -369,9 +374,7 @@ func (r joinRoomReq) joinRoomUsingServer(roomID string, server gomatrixserverlib
gomatrixserverlib.RespState(respSendJoin.RespState),
event.Headered(respMakeJoin.RoomVersion),
); err != nil {
- util.GetLogger(r.req.Context()).WithError(err).Error("gomatrixserverlib.RespState failed")
- res := jsonerror.InternalServerError()
- return &res, nil
+ return nil, fmt.Errorf("r.producer.SendEventWithState: %w", err)
}
return &util.JSONResponse{
diff --git a/common/events.go b/common/events.go
index b79998a7..adbdf338 100644
--- a/common/events.go
+++ b/common/events.go
@@ -17,6 +17,7 @@ package common
import (
"context"
"errors"
+ "fmt"
"time"
"github.com/matrix-org/dendrite/common/config"
@@ -46,6 +47,7 @@ func BuildEvent(
err := AddPrevEventsToEvent(ctx, builder, queryAPI, queryRes)
if err != nil {
+ // This can pass through a ErrRoomNoExists to the caller
return nil, err
}
@@ -68,7 +70,7 @@ func AddPrevEventsToEvent(
) error {
eventsNeeded, err := gomatrixserverlib.StateNeededForEventBuilder(builder)
if err != nil {
- return err
+ return fmt.Errorf("gomatrixserverlib.StateNeededForEventBuilder: %w", err)
}
// Ask the roomserver for information about this room
@@ -77,7 +79,7 @@ func AddPrevEventsToEvent(
StateToFetch: eventsNeeded.Tuples(),
}
if err = queryAPI.QueryLatestEventsAndState(ctx, &queryReq, queryRes); err != nil {
- return err
+ return fmt.Errorf("queryAPI.QueryLatestEventsAndState: %w", err)
}
if !queryRes.RoomExists {
@@ -86,7 +88,7 @@ func AddPrevEventsToEvent(
eventFormat, err := queryRes.RoomVersion.EventFormat()
if err != nil {
- return err
+ return fmt.Errorf("queryRes.RoomVersion.EventFormat: %w", err)
}
builder.Depth = queryRes.Depth
@@ -96,26 +98,26 @@ func AddPrevEventsToEvent(
for i := range queryRes.StateEvents {
err = authEvents.AddEvent(&queryRes.StateEvents[i].Event)
if err != nil {
- return err
+ return fmt.Errorf("authEvents.AddEvent: %w", err)
}
}
refs, err := eventsNeeded.AuthEventReferences(&authEvents)
if err != nil {
- return err
+ return fmt.Errorf("eventsNeeded.AuthEventReferences: %w", err)
}
+ truncAuth, truncPrev := truncateAuthAndPrevEvents(refs, queryRes.LatestEvents)
switch eventFormat {
case gomatrixserverlib.EventFormatV1:
- builder.AuthEvents = refs
- builder.PrevEvents = queryRes.LatestEvents
+ builder.AuthEvents = truncAuth
+ builder.PrevEvents = truncPrev
case gomatrixserverlib.EventFormatV2:
- v2AuthRefs := []string{}
- v2PrevRefs := []string{}
- for _, ref := range refs {
+ v2AuthRefs, v2PrevRefs := []string{}, []string{}
+ for _, ref := range truncAuth {
v2AuthRefs = append(v2AuthRefs, ref.EventID)
}
- for _, ref := range queryRes.LatestEvents {
+ for _, ref := range truncPrev {
v2PrevRefs = append(v2PrevRefs, ref.EventID)
}
builder.AuthEvents = v2AuthRefs
@@ -124,3 +126,21 @@ func AddPrevEventsToEvent(
return nil
}
+
+// truncateAuthAndPrevEvents limits the number of events we add into
+// an event as prev_events or auth_events.
+// NOTSPEC: The limits here feel a bit arbitrary but they are currently
+// here because of https://github.com/matrix-org/matrix-doc/issues/2307
+// and because Synapse will just drop events that don't comply.
+func truncateAuthAndPrevEvents(auth, prev []gomatrixserverlib.EventReference) (
+ truncAuth, truncPrev []gomatrixserverlib.EventReference,
+) {
+ truncAuth, truncPrev = auth, prev
+ if len(truncAuth) > 10 {
+ truncAuth = truncAuth[:10]
+ }
+ if len(truncPrev) > 20 {
+ truncPrev = truncPrev[:20]
+ }
+ return
+}
diff --git a/federationapi/routing/join.go b/federationapi/routing/join.go
index a39ff639..0a7b2300 100644
--- a/federationapi/routing/join.go
+++ b/federationapi/routing/join.go
@@ -15,6 +15,7 @@
package routing
import (
+ "fmt"
"net/http"
"time"
@@ -34,6 +35,7 @@ func MakeJoin(
cfg *config.Dendrite,
query api.RoomserverQueryAPI,
roomID, userID string,
+ remoteVersions []gomatrixserverlib.RoomVersion,
) util.JSONResponse {
verReq := api.QueryRoomVersionForRoomRequest{RoomID: roomID}
verRes := api.QueryRoomVersionForRoomResponse{}
@@ -44,6 +46,27 @@ func MakeJoin(
}
}
+ // Check that the room that the remote side is trying to join is actually
+ // one of the room versions that they listed in their supported ?ver= in
+ // the make_join URL.
+ // https://matrix.org/docs/spec/server_server/r0.1.3#get-matrix-federation-v1-make-join-roomid-userid
+ remoteSupportsVersion := false
+ for _, v := range remoteVersions {
+ if v == verRes.RoomVersion {
+ remoteSupportsVersion = true
+ break
+ }
+ }
+ // If it isn't, stop trying to join the room.
+ if !remoteSupportsVersion {
+ return util.JSONResponse{
+ Code: http.StatusBadRequest,
+ JSON: jsonerror.UnsupportedRoomVersion(
+ fmt.Sprintf("Joining server does not support room version %s", verRes.RoomVersion),
+ ),
+ }
+ }
+
_, domain, err := gomatrixserverlib.SplitID('@', userID)
if err != nil {
return util.JSONResponse{
@@ -140,7 +163,12 @@ func SendJoin(
if event.RoomID() != roomID {
return util.JSONResponse{
Code: http.StatusBadRequest,
- JSON: jsonerror.BadJSON("The room ID in the request path must match the room ID in the join event JSON"),
+ JSON: jsonerror.BadJSON(
+ fmt.Sprintf(
+ "The room ID in the request path (%q) must match the room ID in the join event JSON (%q)",
+ roomID, event.RoomID(),
+ ),
+ ),
}
}
@@ -148,7 +176,12 @@ func SendJoin(
if event.EventID() != eventID {
return util.JSONResponse{
Code: http.StatusBadRequest,
- JSON: jsonerror.BadJSON("The event ID in the request path must match the event ID in the join event JSON"),
+ JSON: jsonerror.BadJSON(
+ fmt.Sprintf(
+ "The event ID in the request path (%q) must match the event ID in the join event JSON (%q)",
+ eventID, event.EventID(),
+ ),
+ ),
}
}
@@ -186,6 +219,7 @@ func SendJoin(
PrevEventIDs: event.PrevEventIDs(),
AuthEventIDs: event.AuthEventIDs(),
RoomID: roomID,
+ ResolveState: true,
}, &stateAndAuthChainResponse)
if err != nil {
util.GetLogger(httpReq.Context()).WithError(err).Error("query.QueryStateAndAuthChain failed")
diff --git a/federationapi/routing/routing.go b/federationapi/routing/routing.go
index a2b9dc21..83bac555 100644
--- a/federationapi/routing/routing.go
+++ b/federationapi/routing/routing.go
@@ -198,7 +198,7 @@ func Setup(
},
)).Methods(http.MethodGet)
- v1fedmux.Handle("/make_join/{roomID}/{userID}", common.MakeFedAPI(
+ v1fedmux.Handle("/make_join/{roomID}/{eventID}", common.MakeFedAPI(
"federation_make_join", cfg.Matrix.ServerName, keys,
func(httpReq *http.Request, request *gomatrixserverlib.FederationRequest) util.JSONResponse {
vars, err := common.URLDecodeMapValues(mux.Vars(httpReq))
@@ -206,14 +206,28 @@ func Setup(
return util.ErrorResponse(err)
}
roomID := vars["roomID"]
- userID := vars["userID"]
+ eventID := vars["eventID"]
+ queryVars := httpReq.URL.Query()
+ remoteVersions := []gomatrixserverlib.RoomVersion{}
+ if vers, ok := queryVars["ver"]; ok {
+ // The remote side supplied a ?=ver so use that to build up the list
+ // of supported room versions
+ for _, v := range vers {
+ remoteVersions = append(remoteVersions, gomatrixserverlib.RoomVersion(v))
+ }
+ } else {
+ // The remote side didn't supply a ?ver= so just assume that they only
+ // support room version 1, as per the spec
+ // https://matrix.org/docs/spec/server_server/r0.1.3#get-matrix-federation-v1-make-join-roomid-userid
+ remoteVersions = append(remoteVersions, gomatrixserverlib.RoomVersionV1)
+ }
return MakeJoin(
- httpReq, request, cfg, query, roomID, userID,
+ httpReq, request, cfg, query, roomID, eventID, remoteVersions,
)
},
)).Methods(http.MethodGet)
- v2fedmux.Handle("/send_join/{roomID}/{userID}", common.MakeFedAPI(
+ v2fedmux.Handle("/send_join/{roomID}/{eventID}", common.MakeFedAPI(
"federation_send_join", cfg.Matrix.ServerName, keys,
func(httpReq *http.Request, request *gomatrixserverlib.FederationRequest) util.JSONResponse {
vars, err := common.URLDecodeMapValues(mux.Vars(httpReq))
@@ -221,14 +235,14 @@ func Setup(
return util.ErrorResponse(err)
}
roomID := vars["roomID"]
- userID := vars["userID"]
+ eventID := vars["eventID"]
return SendJoin(
- httpReq, request, cfg, query, producer, keys, roomID, userID,
+ httpReq, request, cfg, query, producer, keys, roomID, eventID,
)
},
)).Methods(http.MethodPut)
- v1fedmux.Handle("/make_leave/{roomID}/{userID}", common.MakeFedAPI(
+ v1fedmux.Handle("/make_leave/{roomID}/{eventID}", common.MakeFedAPI(
"federation_make_leave", cfg.Matrix.ServerName, keys,
func(httpReq *http.Request, request *gomatrixserverlib.FederationRequest) util.JSONResponse {
vars, err := common.URLDecodeMapValues(mux.Vars(httpReq))
@@ -236,14 +250,14 @@ func Setup(
return util.ErrorResponse(err)
}
roomID := vars["roomID"]
- userID := vars["userID"]
+ eventID := vars["eventID"]
return MakeLeave(
- httpReq, request, cfg, query, roomID, userID,
+ httpReq, request, cfg, query, roomID, eventID,
)
},
)).Methods(http.MethodGet)
- v2fedmux.Handle("/send_leave/{roomID}/{userID}", common.MakeFedAPI(
+ v2fedmux.Handle("/send_leave/{roomID}/{eventID}", common.MakeFedAPI(
"federation_send_leave", cfg.Matrix.ServerName, keys,
func(httpReq *http.Request, request *gomatrixserverlib.FederationRequest) util.JSONResponse {
vars, err := common.URLDecodeMapValues(mux.Vars(httpReq))
@@ -251,9 +265,9 @@ func Setup(
return util.ErrorResponse(err)
}
roomID := vars["roomID"]
- userID := vars["userID"]
+ eventID := vars["eventID"]
return SendLeave(
- httpReq, request, cfg, producer, keys, roomID, userID,
+ httpReq, request, cfg, producer, keys, roomID, eventID,
)
},
)).Methods(http.MethodPut)
diff --git a/federationapi/routing/state.go b/federationapi/routing/state.go
index 6a47882b..548598dd 100644
--- a/federationapi/routing/state.go
+++ b/federationapi/routing/state.go
@@ -107,7 +107,6 @@ func getState(
return nil, &util.JSONResponse{Code: http.StatusNotFound, JSON: nil}
}
- prevEventIDs := getIDsFromEventRef(event.PrevEvents())
authEventIDs := getIDsFromEventRef(event.AuthEvents())
var response api.QueryStateAndAuthChainResponse
@@ -115,7 +114,7 @@ func getState(
ctx,
&api.QueryStateAndAuthChainRequest{
RoomID: roomID,
- PrevEventIDs: prevEventIDs,
+ PrevEventIDs: []string{eventID},
AuthEventIDs: authEventIDs,
},
&response,
diff --git a/go.mod b/go.mod
index 16350bb9..5854e552 100644
--- a/go.mod
+++ b/go.mod
@@ -9,7 +9,7 @@ require (
github.com/matrix-org/go-http-js-libp2p v0.0.0-20200318135427-31631a9ef51f
github.com/matrix-org/go-sqlite3-js v0.0.0-20200325174927-327088cdef10
github.com/matrix-org/gomatrix v0.0.0-20190528120928-7df988a63f26
- github.com/matrix-org/gomatrixserverlib v0.0.0-20200402141635-4a6e1ade46f8
+ github.com/matrix-org/gomatrixserverlib v0.0.0-20200409140603-8b9a51fe9b89
github.com/matrix-org/naffka v0.0.0-20200127221512-0716baaabaf1
github.com/matrix-org/util v0.0.0-20190711121626-527ce5ddefc7
github.com/mattn/go-sqlite3 v2.0.2+incompatible
@@ -23,9 +23,9 @@ require (
github.com/tidwall/pretty v1.0.1 // indirect
github.com/uber/jaeger-client-go v2.22.1+incompatible
github.com/uber/jaeger-lib v2.2.0+incompatible
- go.uber.org/atomic v1.6.0 // indirect
+ go.uber.org/atomic v1.6.0
golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d
- golang.org/x/net v0.0.0-20190909003024-a7b16738d86b // indirect
+ golang.org/x/tools v0.0.0-20200402223321-bcf690261a44 // indirect
gopkg.in/Shopify/sarama.v1 v1.20.1
gopkg.in/h2non/bimg.v1 v1.0.18
gopkg.in/yaml.v2 v2.2.5
diff --git a/go.sum b/go.sum
index f6b268c4..b1f5ac2f 100644
--- a/go.sum
+++ b/go.sum
@@ -130,8 +130,8 @@ github.com/matrix-org/gomatrix v0.0.0-20190528120928-7df988a63f26 h1:Hr3zjRsq2bh
github.com/matrix-org/gomatrix v0.0.0-20190528120928-7df988a63f26/go.mod h1:3fxX6gUjWyI/2Bt7J1OLhpCzOfO/bB3AiX0cJtEKud0=
github.com/matrix-org/gomatrixserverlib v0.0.0-20200124100636-0c2ec91d1df5 h1:kmRjpmFOenVpOaV/DRlo9p6z/IbOKlUC+hhKsAAh8Qg=
github.com/matrix-org/gomatrixserverlib v0.0.0-20200124100636-0c2ec91d1df5/go.mod h1:FsKa2pWE/bpQql9H7U4boOPXFoJX/QcqaZZ6ijLkaZI=
-github.com/matrix-org/gomatrixserverlib v0.0.0-20200402141635-4a6e1ade46f8 h1:VZ7xGklSuzU9geMekuxKO4FvUBUaPjP+8IkcwzQtqOI=
-github.com/matrix-org/gomatrixserverlib v0.0.0-20200402141635-4a6e1ade46f8/go.mod h1:FsKa2pWE/bpQql9H7U4boOPXFoJX/QcqaZZ6ijLkaZI=
+github.com/matrix-org/gomatrixserverlib v0.0.0-20200409140603-8b9a51fe9b89 h1:YAlUJK/Ty2ZrP/DL41CiR0Cp3pteshnyIS420KVs220=
+github.com/matrix-org/gomatrixserverlib v0.0.0-20200409140603-8b9a51fe9b89/go.mod h1:FsKa2pWE/bpQql9H7U4boOPXFoJX/QcqaZZ6ijLkaZI=
github.com/matrix-org/naffka v0.0.0-20200127221512-0716baaabaf1 h1:osLoFdOy+ChQqVUn2PeTDETFftVkl4w9t/OW18g3lnk=
github.com/matrix-org/naffka v0.0.0-20200127221512-0716baaabaf1/go.mod h1:cXoYQIENbdWIQHt1SyCo6Bl3C3raHwJ0wgVrXHSqf+A=
github.com/matrix-org/util v0.0.0-20171127121716-2e2df66af2f5 h1:W7l5CP4V7wPyPb4tYE11dbmeAOwtFQBTW0rf4OonOS8=
@@ -253,6 +253,7 @@ github.com/uber/jaeger-lib v1.5.0/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/Aaua
github.com/uber/jaeger-lib v2.2.0+incompatible h1:MxZXOiR2JuoANZ3J6DE/U0kSFv/eJ/GfSYVCjK7dyaw=
github.com/uber/jaeger-lib v2.2.0+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE=
+github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.uber.org/atomic v1.3.0 h1:vs7fgriifsPbGdK3bNuMWapNn3qnZhCRXc19NRdq010=
go.uber.org/atomic v1.3.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
@@ -276,6 +277,8 @@ golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvx
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ=
+golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -288,8 +291,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20190909003024-a7b16738d86b h1:XfVGCX+0T4WOStkaOsJRllbsiImhB2jgVBGc9L0lPGc=
-golang.org/x/net v0.0.0-20190909003024-a7b16738d86b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200226121028-0de0cce0169b h1:0mm1VjtFUOIlE1SbDlwjYaDxZVDP2S5ou6y0gSgXHu8=
+golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -324,7 +327,11 @@ golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c h1:IGkKhmfzcztjm6gYkykvu/NiS8kaqbCWAEWWAyf8J5U=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20200402223321-bcf690261a44 h1:bMm0eoDiGkM5VfIyKjxDvoflW5GLp7+VCo+60n8F+TE=
+golang.org/x/tools v0.0.0-20200402223321-bcf690261a44/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
diff --git a/roomserver/api/query.go b/roomserver/api/query.go
index 9120da4b..5f024d26 100644
--- a/roomserver/api/query.go
+++ b/roomserver/api/query.go
@@ -203,6 +203,9 @@ type QueryStateAndAuthChainRequest struct {
PrevEventIDs []string `json:"prev_event_ids"`
// The list of auth events for the event. Used to calculate the auth chain
AuthEventIDs []string `json:"auth_event_ids"`
+ // Should state resolution be ran on the result events?
+ // TODO: check call sites and remove if we always want to do state res
+ ResolveState bool `json:"resolve_state"`
}
// QueryStateAndAuthChainResponse is a response to QueryStateAndAuthChain
diff --git a/roomserver/query/query.go b/roomserver/query/query.go
index b7cdf150..7e05fe36 100644
--- a/roomserver/query/query.go
+++ b/roomserver/query/query.go
@@ -132,7 +132,7 @@ func (r *RoomserverQueryAPI) QueryLatestEventsAndState(
return err
}
- // Look up the currrent state for the requested tuples.
+ // Look up the current state for the requested tuples.
stateEntries, err := roomState.LoadStateAtSnapshotForStringTuples(
ctx, currentStateSnapshotNID, request.StateToFetch,
)
@@ -736,6 +736,14 @@ func (r *RoomserverQueryAPI) QueryStateAndAuthChain(
return err
}
+ if request.ResolveState {
+ if stateEvents, err = state.ResolveConflictsAdhoc(
+ roomVersion, stateEvents, authEvents,
+ ); err != nil {
+ return err
+ }
+ }
+
for _, event := range stateEvents {
response.StateEvents = append(response.StateEvents, event.Headered(roomVersion))
}
diff --git a/roomserver/state/state.go b/roomserver/state/state.go
index 94873dbe..3f68e074 100644
--- a/roomserver/state/state.go
+++ b/roomserver/state/state.go
@@ -18,7 +18,6 @@ package state
import (
"context"
- "errors"
"fmt"
"sort"
"time"
@@ -681,6 +680,83 @@ func (v StateResolution) calculateStateAfterManyEvents(
return
}
+// ResolveConflictsAdhoc is a helper function to assist the query API in
+// performing state resolution when requested. This is a different code
+// path to the rest of state.go because this assumes you already have
+// gomatrixserverlib.Event objects and not just a bunch of NIDs like
+// elsewhere in the state resolution.
+// TODO: Some of this can possibly be deduplicated
+func ResolveConflictsAdhoc(
+ version gomatrixserverlib.RoomVersion,
+ events []gomatrixserverlib.Event,
+ authEvents []gomatrixserverlib.Event,
+) ([]gomatrixserverlib.Event, error) {
+ type stateKeyTuple struct {
+ Type string
+ StateKey string
+ }
+
+ // Prepare our data structures.
+ eventMap := make(map[stateKeyTuple][]gomatrixserverlib.Event)
+ var conflicted, notConflicted, resolved []gomatrixserverlib.Event
+
+ // Run through all of the events that we were given and sort them
+ // into a map, sorted by (event_type, state_key) tuple. This means
+ // that we can easily spot events that are "conflicted", e.g.
+ // there are duplicate values for the same tuple key.
+ for _, event := range events {
+ if event.StateKey() == nil {
+ // Ignore events that are not state events.
+ continue
+ }
+ // Append the events if there is already a conflicted list for
+ // this tuple key, create it if not.
+ tuple := stateKeyTuple{event.Type(), *event.StateKey()}
+ if _, ok := eventMap[tuple]; ok {
+ eventMap[tuple] = append(eventMap[tuple], event)
+ } else {
+ eventMap[tuple] = []gomatrixserverlib.Event{event}
+ }
+ }
+
+ // Split out the events in the map into conflicted and unconflicted
+ // buckets. The conflicted events will be ran through state res,
+ // whereas unconfliced events will always going to appear in the
+ // final resolved state.
+ for _, list := range eventMap {
+ if len(list) > 1 {
+ conflicted = append(conflicted, list...)
+ } else {
+ notConflicted = append(notConflicted, list...)
+ }
+ }
+
+ // Work out which state resolution algorithm we want to run for
+ // the room version.
+ stateResAlgo, err := version.StateResAlgorithm()
+ if err != nil {
+ return nil, err
+ }
+ switch stateResAlgo {
+ case gomatrixserverlib.StateResV1:
+ // Currently state res v1 doesn't handle unconflicted events
+ // for us, like state res v2 does, so we will need to add the
+ // unconflicted events into the state ourselves.
+ // TODO: Fix state res v1 so this is handled for the caller.
+ resolved = gomatrixserverlib.ResolveStateConflicts(conflicted, authEvents)
+ resolved = append(resolved, notConflicted...)
+ case gomatrixserverlib.StateResV2:
+ // TODO: auth difference here?
+ resolved = gomatrixserverlib.ResolveStateConflictsV2(conflicted, notConflicted, authEvents, authEvents)
+ default:
+ return nil, fmt.Errorf("unsupported state resolution algorithm %v", stateResAlgo)
+ }
+
+ // Return the final resolved state events, including both the
+ // resolved set of conflicted events, and the unconflicted events.
+ return resolved, nil
+}
+
func (v StateResolution) resolveConflicts(
ctx context.Context, version gomatrixserverlib.RoomVersion,
notConflicted, conflicted []types.StateEntry,
@@ -695,7 +771,7 @@ func (v StateResolution) resolveConflicts(
case gomatrixserverlib.StateResV2:
return v.resolveConflictsV2(ctx, notConflicted, conflicted)
}
- return nil, errors.New("unsupported state resolution algorithm")
+ return nil, fmt.Errorf("unsupported state resolution algorithm %v", stateResAlgo)
}
// resolveConflicts resolves a list of conflicted state entries. It takes two lists.
diff --git a/roomserver/version/version.go b/roomserver/version/version.go
index ed16ecca..e60b5ef7 100644
--- a/roomserver/version/version.go
+++ b/roomserver/version/version.go
@@ -43,12 +43,12 @@ var roomVersions = map[gomatrixserverlib.RoomVersion]RoomVersionDescription{
Stable: true,
},
gomatrixserverlib.RoomVersionV3: RoomVersionDescription{
- Supported: false,
- Stable: false,
+ Supported: true,
+ Stable: true,
},
gomatrixserverlib.RoomVersionV4: RoomVersionDescription{
- Supported: false,
- Stable: false,
+ Supported: true,
+ Stable: true,
},
gomatrixserverlib.RoomVersionV5: RoomVersionDescription{
Supported: false,
diff --git a/sytest-blacklist b/sytest-blacklist
index 2e6f2057..da0667a1 100644
--- a/sytest-blacklist
+++ b/sytest-blacklist
@@ -31,4 +31,7 @@ Alias creators can delete canonical alias with no ops
# Blacklisted because we need to implement v2 invite endpoints for room versions
# to be supported (currently fails with M_UNSUPPORTED_ROOM_VERSION)
-Inbound federation rejects invites which are not signed by the sender \ No newline at end of file
+Inbound federation rejects invites which are not signed by the sender
+
+# Blacklisted because we don't support ignores yet
+Ignore invite in incremental sync
diff --git a/sytest-whitelist b/sytest-whitelist
index 38062bb5..97ded9bb 100644
--- a/sytest-whitelist
+++ b/sytest-whitelist
@@ -215,7 +215,6 @@ Guest users can sync from default guest_access rooms if joined
Real non-joined users cannot room initalSync for non-world_readable rooms
Push rules come down in an initial /sync
Regular users can add and delete aliases in the default room configuration
-Regular users can add and delete aliases when m.room.aliases is restricted
GET /r0/capabilities is not public
GET /joined_rooms lists newly-created room
/joined_rooms returns only joined rooms
@@ -225,10 +224,24 @@ Remote user can backfill in a room with version 1
POST /createRoom creates a room with the given version
POST /createRoom rejects attempts to create rooms with numeric versions
POST /createRoom rejects attempts to create rooms with unknown versions
+Regular users can add and delete aliases when m.room.aliases is restricted
User can create and send/receive messages in a room with version 2
local user can join room with version 2
remote user can join room with version 2
User can invite local user to room with version 2
Remote user can backfill in a room with version 2
Inbound federation accepts attempts to join v2 rooms from servers with support
-Outbound federation can send invites via v2 API \ No newline at end of file
+Outbound federation can send invites via v2 API
+User can create and send/receive messages in a room with version 3
+local user can join room with version 3
+Remote user can backfill in a room with version 3
+User can create and send/receive messages in a room with version 4
+local user can join room with version 4
+remote user can join room with version 3
+remote user can join room with version 4
+Remote user can backfill in a room with version 4
+# We don't support ignores yet, so ignore this for now - ha ha.
+# Ignore invite in incremental sync
+Outbound federation can send invites via v2 API
+User can invite local user to room with version 3
+User can invite local user to room with version 4