mirror of
https://github.com/hoernschen/dendrite.git
synced 2024-12-27 07:28:27 +00:00
Add some roomserver UTs (#3067)
Adds tests for `QueryRestrictedJoinAllowed`, `IsServerAllowed` and `PerformRoomUpgrade`. Refactors the `QueryRoomVersionForRoom` method to accept a string and return a `gmsl.RoomVersion` instead of req/resp structs. Adds some more caching for `GetStateEvent` This should also fix #2912 by ignoring state events belonging to other users.
This commit is contained in:
parent
dd5e47a9a7
commit
2475cf4b61
20 changed files with 705 additions and 135 deletions
|
@ -48,7 +48,6 @@ type createRoomRequest struct {
|
||||||
CreationContent json.RawMessage `json:"creation_content"`
|
CreationContent json.RawMessage `json:"creation_content"`
|
||||||
InitialState []fledglingEvent `json:"initial_state"`
|
InitialState []fledglingEvent `json:"initial_state"`
|
||||||
RoomAliasName string `json:"room_alias_name"`
|
RoomAliasName string `json:"room_alias_name"`
|
||||||
GuestCanJoin bool `json:"guest_can_join"`
|
|
||||||
RoomVersion gomatrixserverlib.RoomVersion `json:"room_version"`
|
RoomVersion gomatrixserverlib.RoomVersion `json:"room_version"`
|
||||||
PowerLevelContentOverride json.RawMessage `json:"power_level_content_override"`
|
PowerLevelContentOverride json.RawMessage `json:"power_level_content_override"`
|
||||||
IsDirect bool `json:"is_direct"`
|
IsDirect bool `json:"is_direct"`
|
||||||
|
@ -253,16 +252,19 @@ func createRoom(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var guestsCanJoin bool
|
||||||
switch r.Preset {
|
switch r.Preset {
|
||||||
case presetPrivateChat:
|
case presetPrivateChat:
|
||||||
joinRuleContent.JoinRule = spec.Invite
|
joinRuleContent.JoinRule = spec.Invite
|
||||||
historyVisibilityContent.HistoryVisibility = historyVisibilityShared
|
historyVisibilityContent.HistoryVisibility = historyVisibilityShared
|
||||||
|
guestsCanJoin = true
|
||||||
case presetTrustedPrivateChat:
|
case presetTrustedPrivateChat:
|
||||||
joinRuleContent.JoinRule = spec.Invite
|
joinRuleContent.JoinRule = spec.Invite
|
||||||
historyVisibilityContent.HistoryVisibility = historyVisibilityShared
|
historyVisibilityContent.HistoryVisibility = historyVisibilityShared
|
||||||
for _, invitee := range r.Invite {
|
for _, invitee := range r.Invite {
|
||||||
powerLevelContent.Users[invitee] = 100
|
powerLevelContent.Users[invitee] = 100
|
||||||
}
|
}
|
||||||
|
guestsCanJoin = true
|
||||||
case presetPublicChat:
|
case presetPublicChat:
|
||||||
joinRuleContent.JoinRule = spec.Public
|
joinRuleContent.JoinRule = spec.Public
|
||||||
historyVisibilityContent.HistoryVisibility = historyVisibilityShared
|
historyVisibilityContent.HistoryVisibility = historyVisibilityShared
|
||||||
|
@ -317,7 +319,7 @@ func createRoom(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.GuestCanJoin {
|
if guestsCanJoin {
|
||||||
guestAccessEvent = &fledglingEvent{
|
guestAccessEvent = &fledglingEvent{
|
||||||
Type: spec.MRoomGuestAccess,
|
Type: spec.MRoomGuestAccess,
|
||||||
Content: eventutil.GuestAccessContent{
|
Content: eventutil.GuestAccessContent{
|
||||||
|
|
|
@ -66,7 +66,6 @@ func TestJoinRoomByIDOrAlias(t *testing.T) {
|
||||||
Preset: presetPublicChat,
|
Preset: presetPublicChat,
|
||||||
RoomAliasName: "alias",
|
RoomAliasName: "alias",
|
||||||
Invite: []string{bob.ID},
|
Invite: []string{bob.ID},
|
||||||
GuestCanJoin: false,
|
|
||||||
}, aliceDev, &cfg.ClientAPI, userAPI, rsAPI, asAPI, time.Now())
|
}, aliceDev, &cfg.ClientAPI, userAPI, rsAPI, asAPI, time.Now())
|
||||||
crResp, ok := resp.JSON.(createRoomResponse)
|
crResp, ok := resp.JSON.(createRoomResponse)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -75,13 +74,12 @@ func TestJoinRoomByIDOrAlias(t *testing.T) {
|
||||||
|
|
||||||
// create a room with guest access enabled and invite Charlie
|
// create a room with guest access enabled and invite Charlie
|
||||||
resp = createRoom(ctx, createRoomRequest{
|
resp = createRoom(ctx, createRoomRequest{
|
||||||
Name: "testing",
|
Name: "testing",
|
||||||
IsDirect: true,
|
IsDirect: true,
|
||||||
Topic: "testing",
|
Topic: "testing",
|
||||||
Visibility: "public",
|
Visibility: "public",
|
||||||
Preset: presetPublicChat,
|
Preset: presetPublicChat,
|
||||||
Invite: []string{charlie.ID},
|
Invite: []string{charlie.ID},
|
||||||
GuestCanJoin: true,
|
|
||||||
}, aliceDev, &cfg.ClientAPI, userAPI, rsAPI, asAPI, time.Now())
|
}, aliceDev, &cfg.ClientAPI, userAPI, rsAPI, asAPI, time.Now())
|
||||||
crRespWithGuestAccess, ok := resp.JSON.(createRoomResponse)
|
crRespWithGuestAccess, ok := resp.JSON.(createRoomResponse)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|
|
@ -338,9 +338,8 @@ func buildMembershipEvents(
|
||||||
evs := []*gomatrixserverlib.HeaderedEvent{}
|
evs := []*gomatrixserverlib.HeaderedEvent{}
|
||||||
|
|
||||||
for _, roomID := range roomIDs {
|
for _, roomID := range roomIDs {
|
||||||
verReq := api.QueryRoomVersionForRoomRequest{RoomID: roomID}
|
roomVersion, err := rsAPI.QueryRoomVersionForRoom(ctx, roomID)
|
||||||
verRes := api.QueryRoomVersionForRoomResponse{}
|
if err != nil {
|
||||||
if err := rsAPI.QueryRoomVersionForRoom(ctx, &verReq, &verRes); err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -358,7 +357,7 @@ func buildMembershipEvents(
|
||||||
content.DisplayName = newProfile.DisplayName
|
content.DisplayName = newProfile.DisplayName
|
||||||
content.AvatarURL = newProfile.AvatarURL
|
content.AvatarURL = newProfile.AvatarURL
|
||||||
|
|
||||||
if err := builder.SetContent(content); err != nil {
|
if err = builder.SetContent(content); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -372,7 +371,7 @@ func buildMembershipEvents(
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
evs = append(evs, event.Headered(verRes.RoomVersion))
|
evs = append(evs, event.Headered(roomVersion))
|
||||||
}
|
}
|
||||||
|
|
||||||
return evs, nil
|
return evs, nil
|
||||||
|
|
|
@ -76,9 +76,8 @@ func SendEvent(
|
||||||
rsAPI api.ClientRoomserverAPI,
|
rsAPI api.ClientRoomserverAPI,
|
||||||
txnCache *transactions.Cache,
|
txnCache *transactions.Cache,
|
||||||
) util.JSONResponse {
|
) util.JSONResponse {
|
||||||
verReq := api.QueryRoomVersionForRoomRequest{RoomID: roomID}
|
roomVersion, err := rsAPI.QueryRoomVersionForRoom(req.Context(), roomID)
|
||||||
verRes := api.QueryRoomVersionForRoomResponse{}
|
if err != nil {
|
||||||
if err := rsAPI.QueryRoomVersionForRoom(req.Context(), &verReq, &verRes); err != nil {
|
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusBadRequest,
|
Code: http.StatusBadRequest,
|
||||||
JSON: jsonerror.UnsupportedRoomVersion(err.Error()),
|
JSON: jsonerror.UnsupportedRoomVersion(err.Error()),
|
||||||
|
@ -185,7 +184,7 @@ func SendEvent(
|
||||||
req.Context(), rsAPI,
|
req.Context(), rsAPI,
|
||||||
api.KindNew,
|
api.KindNew,
|
||||||
[]*gomatrixserverlib.HeaderedEvent{
|
[]*gomatrixserverlib.HeaderedEvent{
|
||||||
e.Headered(verRes.RoomVersion),
|
e.Headered(roomVersion),
|
||||||
},
|
},
|
||||||
device.UserDomain(),
|
device.UserDomain(),
|
||||||
domain,
|
domain,
|
||||||
|
@ -200,7 +199,7 @@ func SendEvent(
|
||||||
util.GetLogger(req.Context()).WithFields(logrus.Fields{
|
util.GetLogger(req.Context()).WithFields(logrus.Fields{
|
||||||
"event_id": e.EventID(),
|
"event_id": e.EventID(),
|
||||||
"room_id": roomID,
|
"room_id": roomID,
|
||||||
"room_version": verRes.RoomVersion,
|
"room_version": roomVersion,
|
||||||
}).Info("Sent event to roomserver")
|
}).Info("Sent event to roomserver")
|
||||||
|
|
||||||
res := util.JSONResponse{
|
res := util.JSONResponse{
|
||||||
|
|
|
@ -157,7 +157,6 @@ func SendServerNotice(
|
||||||
Visibility: "private",
|
Visibility: "private",
|
||||||
Preset: presetPrivateChat,
|
Preset: presetPrivateChat,
|
||||||
CreationContent: cc,
|
CreationContent: cc,
|
||||||
GuestCanJoin: false,
|
|
||||||
RoomVersion: roomVersion,
|
RoomVersion: roomVersion,
|
||||||
PowerLevelContentOverride: pl,
|
PowerLevelContentOverride: pl,
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,9 +42,8 @@ func MakeJoin(
|
||||||
roomID, userID string,
|
roomID, userID string,
|
||||||
remoteVersions []gomatrixserverlib.RoomVersion,
|
remoteVersions []gomatrixserverlib.RoomVersion,
|
||||||
) util.JSONResponse {
|
) util.JSONResponse {
|
||||||
verReq := api.QueryRoomVersionForRoomRequest{RoomID: roomID}
|
roomVersion, err := rsAPI.QueryRoomVersionForRoom(httpReq.Context(), roomID)
|
||||||
verRes := api.QueryRoomVersionForRoomResponse{}
|
if err != nil {
|
||||||
if err := rsAPI.QueryRoomVersionForRoom(httpReq.Context(), &verReq, &verRes); err != nil {
|
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusInternalServerError,
|
Code: http.StatusInternalServerError,
|
||||||
JSON: jsonerror.InternalServerError(),
|
JSON: jsonerror.InternalServerError(),
|
||||||
|
@ -57,7 +56,7 @@ func MakeJoin(
|
||||||
// https://matrix.org/docs/spec/server_server/r0.1.3#get-matrix-federation-v1-make-join-roomid-userid
|
// https://matrix.org/docs/spec/server_server/r0.1.3#get-matrix-federation-v1-make-join-roomid-userid
|
||||||
remoteSupportsVersion := false
|
remoteSupportsVersion := false
|
||||||
for _, v := range remoteVersions {
|
for _, v := range remoteVersions {
|
||||||
if v == verRes.RoomVersion {
|
if v == roomVersion {
|
||||||
remoteSupportsVersion = true
|
remoteSupportsVersion = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -66,7 +65,7 @@ func MakeJoin(
|
||||||
if !remoteSupportsVersion {
|
if !remoteSupportsVersion {
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusBadRequest,
|
Code: http.StatusBadRequest,
|
||||||
JSON: jsonerror.IncompatibleRoomVersion(verRes.RoomVersion),
|
JSON: jsonerror.IncompatibleRoomVersion(roomVersion),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,7 +108,7 @@ func MakeJoin(
|
||||||
|
|
||||||
// Check if the restricted join is allowed. If the room doesn't
|
// Check if the restricted join is allowed. If the room doesn't
|
||||||
// support restricted joins then this is effectively a no-op.
|
// support restricted joins then this is effectively a no-op.
|
||||||
res, authorisedVia, err := checkRestrictedJoin(httpReq, rsAPI, verRes.RoomVersion, roomID, userID)
|
res, authorisedVia, err := checkRestrictedJoin(httpReq, rsAPI, roomVersion, roomID, userID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
util.GetLogger(httpReq.Context()).WithError(err).Error("checkRestrictedJoin failed")
|
util.GetLogger(httpReq.Context()).WithError(err).Error("checkRestrictedJoin failed")
|
||||||
return jsonerror.InternalServerError()
|
return jsonerror.InternalServerError()
|
||||||
|
@ -144,7 +143,7 @@ func MakeJoin(
|
||||||
}
|
}
|
||||||
|
|
||||||
queryRes := api.QueryLatestEventsAndStateResponse{
|
queryRes := api.QueryLatestEventsAndStateResponse{
|
||||||
RoomVersion: verRes.RoomVersion,
|
RoomVersion: roomVersion,
|
||||||
}
|
}
|
||||||
event, err := eventutil.QueryAndBuildEvent(httpReq.Context(), &builder, cfg.Matrix, identity, time.Now(), rsAPI, &queryRes)
|
event, err := eventutil.QueryAndBuildEvent(httpReq.Context(), &builder, cfg.Matrix, identity, time.Now(), rsAPI, &queryRes)
|
||||||
if err == eventutil.ErrRoomNoExists {
|
if err == eventutil.ErrRoomNoExists {
|
||||||
|
@ -180,7 +179,7 @@ func MakeJoin(
|
||||||
Code: http.StatusOK,
|
Code: http.StatusOK,
|
||||||
JSON: map[string]interface{}{
|
JSON: map[string]interface{}{
|
||||||
"event": builder,
|
"event": builder,
|
||||||
"room_version": verRes.RoomVersion,
|
"room_version": roomVersion,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -197,21 +196,20 @@ func SendJoin(
|
||||||
keys gomatrixserverlib.JSONVerifier,
|
keys gomatrixserverlib.JSONVerifier,
|
||||||
roomID, eventID string,
|
roomID, eventID string,
|
||||||
) util.JSONResponse {
|
) util.JSONResponse {
|
||||||
verReq := api.QueryRoomVersionForRoomRequest{RoomID: roomID}
|
roomVersion, err := rsAPI.QueryRoomVersionForRoom(httpReq.Context(), roomID)
|
||||||
verRes := api.QueryRoomVersionForRoomResponse{}
|
if err != nil {
|
||||||
if err := rsAPI.QueryRoomVersionForRoom(httpReq.Context(), &verReq, &verRes); err != nil {
|
|
||||||
util.GetLogger(httpReq.Context()).WithError(err).Error("rsAPI.QueryRoomVersionForRoom failed")
|
util.GetLogger(httpReq.Context()).WithError(err).Error("rsAPI.QueryRoomVersionForRoom failed")
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusInternalServerError,
|
Code: http.StatusInternalServerError,
|
||||||
JSON: jsonerror.InternalServerError(),
|
JSON: jsonerror.InternalServerError(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
verImpl, err := gomatrixserverlib.GetRoomVersion(verRes.RoomVersion)
|
verImpl, err := gomatrixserverlib.GetRoomVersion(roomVersion)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusInternalServerError,
|
Code: http.StatusInternalServerError,
|
||||||
JSON: jsonerror.UnsupportedRoomVersion(
|
JSON: jsonerror.UnsupportedRoomVersion(
|
||||||
fmt.Sprintf("QueryRoomVersionForRoom returned unknown room version: %s", verRes.RoomVersion),
|
fmt.Sprintf("QueryRoomVersionForRoom returned unknown room version: %s", roomVersion),
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -140,21 +140,20 @@ func SendLeave(
|
||||||
keys gomatrixserverlib.JSONVerifier,
|
keys gomatrixserverlib.JSONVerifier,
|
||||||
roomID, eventID string,
|
roomID, eventID string,
|
||||||
) util.JSONResponse {
|
) util.JSONResponse {
|
||||||
verReq := api.QueryRoomVersionForRoomRequest{RoomID: roomID}
|
roomVersion, err := rsAPI.QueryRoomVersionForRoom(httpReq.Context(), roomID)
|
||||||
verRes := api.QueryRoomVersionForRoomResponse{}
|
if err != nil {
|
||||||
if err := rsAPI.QueryRoomVersionForRoom(httpReq.Context(), &verReq, &verRes); err != nil {
|
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusBadRequest,
|
Code: http.StatusBadRequest,
|
||||||
JSON: jsonerror.UnsupportedRoomVersion(err.Error()),
|
JSON: jsonerror.UnsupportedRoomVersion(err.Error()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
verImpl, err := gomatrixserverlib.GetRoomVersion(verRes.RoomVersion)
|
verImpl, err := gomatrixserverlib.GetRoomVersion(roomVersion)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusInternalServerError,
|
Code: http.StatusInternalServerError,
|
||||||
JSON: jsonerror.UnsupportedRoomVersion(
|
JSON: jsonerror.UnsupportedRoomVersion(
|
||||||
fmt.Sprintf("QueryRoomVersionForRoom returned unknown version: %s", verRes.RoomVersion),
|
fmt.Sprintf("QueryRoomVersionForRoom returned unknown version: %s", roomVersion),
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -313,7 +312,7 @@ func SendLeave(
|
||||||
InputRoomEvents: []api.InputRoomEvent{
|
InputRoomEvents: []api.InputRoomEvent{
|
||||||
{
|
{
|
||||||
Kind: api.KindNew,
|
Kind: api.KindNew,
|
||||||
Event: event.Headered(verRes.RoomVersion),
|
Event: event.Headered(roomVersion),
|
||||||
SendAsServer: string(cfg.Matrix.ServerName),
|
SendAsServer: string(cfg.Matrix.ServerName),
|
||||||
TransactionID: nil,
|
TransactionID: nil,
|
||||||
},
|
},
|
||||||
|
|
|
@ -35,10 +35,8 @@ func Peek(
|
||||||
remoteVersions []gomatrixserverlib.RoomVersion,
|
remoteVersions []gomatrixserverlib.RoomVersion,
|
||||||
) util.JSONResponse {
|
) util.JSONResponse {
|
||||||
// TODO: check if we're just refreshing an existing peek by querying the federationapi
|
// TODO: check if we're just refreshing an existing peek by querying the federationapi
|
||||||
|
roomVersion, err := rsAPI.QueryRoomVersionForRoom(httpReq.Context(), roomID)
|
||||||
verReq := api.QueryRoomVersionForRoomRequest{RoomID: roomID}
|
if err != nil {
|
||||||
verRes := api.QueryRoomVersionForRoomResponse{}
|
|
||||||
if err := rsAPI.QueryRoomVersionForRoom(httpReq.Context(), &verReq, &verRes); err != nil {
|
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusInternalServerError,
|
Code: http.StatusInternalServerError,
|
||||||
JSON: jsonerror.InternalServerError(),
|
JSON: jsonerror.InternalServerError(),
|
||||||
|
@ -50,7 +48,7 @@ func Peek(
|
||||||
// the peek URL.
|
// the peek URL.
|
||||||
remoteSupportsVersion := false
|
remoteSupportsVersion := false
|
||||||
for _, v := range remoteVersions {
|
for _, v := range remoteVersions {
|
||||||
if v == verRes.RoomVersion {
|
if v == roomVersion {
|
||||||
remoteSupportsVersion = true
|
remoteSupportsVersion = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -59,7 +57,7 @@ func Peek(
|
||||||
if !remoteSupportsVersion {
|
if !remoteSupportsVersion {
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusBadRequest,
|
Code: http.StatusBadRequest,
|
||||||
JSON: jsonerror.IncompatibleRoomVersion(verRes.RoomVersion),
|
JSON: jsonerror.IncompatibleRoomVersion(roomVersion),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,7 +67,7 @@ func Peek(
|
||||||
renewalInterval := int64(60 * 60 * 1000 * 1000)
|
renewalInterval := int64(60 * 60 * 1000 * 1000)
|
||||||
|
|
||||||
var response api.PerformInboundPeekResponse
|
var response api.PerformInboundPeekResponse
|
||||||
err := rsAPI.PerformInboundPeek(
|
err = rsAPI.PerformInboundPeek(
|
||||||
httpReq.Context(),
|
httpReq.Context(),
|
||||||
&api.PerformInboundPeekRequest{
|
&api.PerformInboundPeekRequest{
|
||||||
RoomID: roomID,
|
RoomID: roomID,
|
||||||
|
|
|
@ -69,9 +69,8 @@ func CreateInvitesFrom3PIDInvites(
|
||||||
|
|
||||||
evs := []*gomatrixserverlib.HeaderedEvent{}
|
evs := []*gomatrixserverlib.HeaderedEvent{}
|
||||||
for _, inv := range body.Invites {
|
for _, inv := range body.Invites {
|
||||||
verReq := api.QueryRoomVersionForRoomRequest{RoomID: inv.RoomID}
|
roomVersion, err := rsAPI.QueryRoomVersionForRoom(req.Context(), inv.RoomID)
|
||||||
verRes := api.QueryRoomVersionForRoomResponse{}
|
if err != nil {
|
||||||
if err := rsAPI.QueryRoomVersionForRoom(req.Context(), &verReq, &verRes); err != nil {
|
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusBadRequest,
|
Code: http.StatusBadRequest,
|
||||||
JSON: jsonerror.UnsupportedRoomVersion(err.Error()),
|
JSON: jsonerror.UnsupportedRoomVersion(err.Error()),
|
||||||
|
@ -86,7 +85,7 @@ func CreateInvitesFrom3PIDInvites(
|
||||||
return jsonerror.InternalServerError()
|
return jsonerror.InternalServerError()
|
||||||
}
|
}
|
||||||
if event != nil {
|
if event != nil {
|
||||||
evs = append(evs, event.Headered(verRes.RoomVersion))
|
evs = append(evs, event.Headered(roomVersion))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,9 +161,8 @@ func ExchangeThirdPartyInvite(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
verReq := api.QueryRoomVersionForRoomRequest{RoomID: roomID}
|
roomVersion, err := rsAPI.QueryRoomVersionForRoom(httpReq.Context(), roomID)
|
||||||
verRes := api.QueryRoomVersionForRoomResponse{}
|
if err != nil {
|
||||||
if err = rsAPI.QueryRoomVersionForRoom(httpReq.Context(), &verReq, &verRes); err != nil {
|
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusBadRequest,
|
Code: http.StatusBadRequest,
|
||||||
JSON: jsonerror.UnsupportedRoomVersion(err.Error()),
|
JSON: jsonerror.UnsupportedRoomVersion(err.Error()),
|
||||||
|
@ -185,7 +183,7 @@ func ExchangeThirdPartyInvite(
|
||||||
|
|
||||||
// Ask the requesting server to sign the newly created event so we know it
|
// Ask the requesting server to sign the newly created event so we know it
|
||||||
// acknowledged it
|
// acknowledged it
|
||||||
inviteReq, err := fclient.NewInviteV2Request(event.Headered(verRes.RoomVersion), nil)
|
inviteReq, err := fclient.NewInviteV2Request(event.Headered(roomVersion), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
util.GetLogger(httpReq.Context()).WithError(err).Error("failed to make invite v2 request")
|
util.GetLogger(httpReq.Context()).WithError(err).Error("failed to make invite v2 request")
|
||||||
return jsonerror.InternalServerError()
|
return jsonerror.InternalServerError()
|
||||||
|
@ -195,9 +193,9 @@ func ExchangeThirdPartyInvite(
|
||||||
util.GetLogger(httpReq.Context()).WithError(err).Error("federation.SendInvite failed")
|
util.GetLogger(httpReq.Context()).WithError(err).Error("federation.SendInvite failed")
|
||||||
return jsonerror.InternalServerError()
|
return jsonerror.InternalServerError()
|
||||||
}
|
}
|
||||||
verImpl, err := gomatrixserverlib.GetRoomVersion(verRes.RoomVersion)
|
verImpl, err := gomatrixserverlib.GetRoomVersion(roomVersion)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
util.GetLogger(httpReq.Context()).WithError(err).Errorf("unknown room version: %s", verRes.RoomVersion)
|
util.GetLogger(httpReq.Context()).WithError(err).Errorf("unknown room version: %s", roomVersion)
|
||||||
return jsonerror.InternalServerError()
|
return jsonerror.InternalServerError()
|
||||||
}
|
}
|
||||||
inviteEvent, err := verImpl.NewEventFromUntrustedJSON(signedEvent.Event)
|
inviteEvent, err := verImpl.NewEventFromUntrustedJSON(signedEvent.Event)
|
||||||
|
@ -211,7 +209,7 @@ func ExchangeThirdPartyInvite(
|
||||||
httpReq.Context(), rsAPI,
|
httpReq.Context(), rsAPI,
|
||||||
api.KindNew,
|
api.KindNew,
|
||||||
[]*gomatrixserverlib.HeaderedEvent{
|
[]*gomatrixserverlib.HeaderedEvent{
|
||||||
inviteEvent.Headered(verRes.RoomVersion),
|
inviteEvent.Headered(roomVersion),
|
||||||
},
|
},
|
||||||
request.Destination(),
|
request.Destination(),
|
||||||
request.Origin(),
|
request.Origin(),
|
||||||
|
@ -239,12 +237,6 @@ func createInviteFrom3PIDInvite(
|
||||||
inv invite, federation fclient.FederationClient,
|
inv invite, federation fclient.FederationClient,
|
||||||
userAPI userapi.FederationUserAPI,
|
userAPI userapi.FederationUserAPI,
|
||||||
) (*gomatrixserverlib.Event, error) {
|
) (*gomatrixserverlib.Event, error) {
|
||||||
verReq := api.QueryRoomVersionForRoomRequest{RoomID: inv.RoomID}
|
|
||||||
verRes := api.QueryRoomVersionForRoomResponse{}
|
|
||||||
if err := rsAPI.QueryRoomVersionForRoom(ctx, &verReq, &verRes); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, server, err := gomatrixserverlib.SplitID('@', inv.MXID)
|
_, server, err := gomatrixserverlib.SplitID('@', inv.MXID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -115,14 +115,13 @@ func (t *TxnReq) ProcessTransaction(ctx context.Context) (*fclient.RespSend, *ut
|
||||||
if v, ok := roomVersions[roomID]; ok {
|
if v, ok := roomVersions[roomID]; ok {
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
verReq := api.QueryRoomVersionForRoomRequest{RoomID: roomID}
|
roomVersion, err := t.rsAPI.QueryRoomVersionForRoom(ctx, roomID)
|
||||||
verRes := api.QueryRoomVersionForRoomResponse{}
|
if err != nil {
|
||||||
if err := t.rsAPI.QueryRoomVersionForRoom(ctx, &verReq, &verRes); err != nil {
|
util.GetLogger(ctx).WithError(err).Debug("Transaction: Failed to query room version for room", roomID)
|
||||||
util.GetLogger(ctx).WithError(err).Debug("Transaction: Failed to query room version for room", verReq.RoomID)
|
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
roomVersions[roomID] = verRes.RoomVersion
|
roomVersions[roomID] = roomVersion
|
||||||
return verRes.RoomVersion
|
return roomVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, pdu := range t.PDUs {
|
for _, pdu := range t.PDUs {
|
||||||
|
|
|
@ -72,14 +72,12 @@ type FakeRsAPI struct {
|
||||||
|
|
||||||
func (r *FakeRsAPI) QueryRoomVersionForRoom(
|
func (r *FakeRsAPI) QueryRoomVersionForRoom(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
req *rsAPI.QueryRoomVersionForRoomRequest,
|
roomID string,
|
||||||
res *rsAPI.QueryRoomVersionForRoomResponse,
|
) (gomatrixserverlib.RoomVersion, error) {
|
||||||
) error {
|
|
||||||
if r.shouldFailQuery {
|
if r.shouldFailQuery {
|
||||||
return fmt.Errorf("Failure")
|
return "", fmt.Errorf("Failure")
|
||||||
}
|
}
|
||||||
res.RoomVersion = gomatrixserverlib.RoomVersionV10
|
return gomatrixserverlib.RoomVersionV10, nil
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *FakeRsAPI) QueryServerBannedFromRoom(
|
func (r *FakeRsAPI) QueryServerBannedFromRoom(
|
||||||
|
@ -722,11 +720,9 @@ func (t *testRoomserverAPI) QueryServerJoinedToRoom(
|
||||||
// Asks for the room version for a given room.
|
// Asks for the room version for a given room.
|
||||||
func (t *testRoomserverAPI) QueryRoomVersionForRoom(
|
func (t *testRoomserverAPI) QueryRoomVersionForRoom(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
request *rsAPI.QueryRoomVersionForRoomRequest,
|
roomID string,
|
||||||
response *rsAPI.QueryRoomVersionForRoomResponse,
|
) (gomatrixserverlib.RoomVersion, error) {
|
||||||
) error {
|
return testRoomVersion, nil
|
||||||
response.RoomVersion = testRoomVersion
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *testRoomserverAPI) QueryServerBannedFromRoom(
|
func (t *testRoomserverAPI) QueryServerBannedFromRoom(
|
||||||
|
|
|
@ -143,7 +143,7 @@ type ClientRoomserverAPI interface {
|
||||||
QueryStateAfterEvents(ctx context.Context, req *QueryStateAfterEventsRequest, res *QueryStateAfterEventsResponse) error
|
QueryStateAfterEvents(ctx context.Context, req *QueryStateAfterEventsRequest, res *QueryStateAfterEventsResponse) error
|
||||||
// QueryKnownUsers returns a list of users that we know about from our joined rooms.
|
// QueryKnownUsers returns a list of users that we know about from our joined rooms.
|
||||||
QueryKnownUsers(ctx context.Context, req *QueryKnownUsersRequest, res *QueryKnownUsersResponse) error
|
QueryKnownUsers(ctx context.Context, req *QueryKnownUsersRequest, res *QueryKnownUsersResponse) error
|
||||||
QueryRoomVersionForRoom(ctx context.Context, req *QueryRoomVersionForRoomRequest, res *QueryRoomVersionForRoomResponse) error
|
QueryRoomVersionForRoom(ctx context.Context, roomID string) (gomatrixserverlib.RoomVersion, error)
|
||||||
QueryPublishedRooms(ctx context.Context, req *QueryPublishedRoomsRequest, res *QueryPublishedRoomsResponse) error
|
QueryPublishedRooms(ctx context.Context, req *QueryPublishedRoomsRequest, res *QueryPublishedRoomsResponse) error
|
||||||
|
|
||||||
GetRoomIDForAlias(ctx context.Context, req *GetRoomIDForAliasRequest, res *GetRoomIDForAliasResponse) error
|
GetRoomIDForAlias(ctx context.Context, req *GetRoomIDForAliasRequest, res *GetRoomIDForAliasResponse) error
|
||||||
|
@ -183,7 +183,7 @@ type FederationRoomserverAPI interface {
|
||||||
// QueryServerBannedFromRoom returns whether a server is banned from a room by server ACLs.
|
// QueryServerBannedFromRoom returns whether a server is banned from a room by server ACLs.
|
||||||
QueryServerBannedFromRoom(ctx context.Context, req *QueryServerBannedFromRoomRequest, res *QueryServerBannedFromRoomResponse) error
|
QueryServerBannedFromRoom(ctx context.Context, req *QueryServerBannedFromRoomRequest, res *QueryServerBannedFromRoomResponse) error
|
||||||
QueryMembershipsForRoom(ctx context.Context, req *QueryMembershipsForRoomRequest, res *QueryMembershipsForRoomResponse) error
|
QueryMembershipsForRoom(ctx context.Context, req *QueryMembershipsForRoomRequest, res *QueryMembershipsForRoomResponse) error
|
||||||
QueryRoomVersionForRoom(ctx context.Context, req *QueryRoomVersionForRoomRequest, res *QueryRoomVersionForRoomResponse) error
|
QueryRoomVersionForRoom(ctx context.Context, roomID string) (gomatrixserverlib.RoomVersion, error)
|
||||||
GetRoomIDForAlias(ctx context.Context, req *GetRoomIDForAliasRequest, res *GetRoomIDForAliasResponse) error
|
GetRoomIDForAlias(ctx context.Context, req *GetRoomIDForAliasRequest, res *GetRoomIDForAliasResponse) error
|
||||||
// QueryEventsByID queries a list of events by event ID for one room. If no room is specified, it will try to determine
|
// QueryEventsByID queries a list of events by event ID for one room. If no room is specified, it will try to determine
|
||||||
// which room to use by querying the first events roomID.
|
// which room to use by querying the first events roomID.
|
||||||
|
|
|
@ -26,6 +26,10 @@ func IsServerAllowed(
|
||||||
serverCurrentlyInRoom bool,
|
serverCurrentlyInRoom bool,
|
||||||
authEvents []*gomatrixserverlib.Event,
|
authEvents []*gomatrixserverlib.Event,
|
||||||
) bool {
|
) bool {
|
||||||
|
// In practice should not happen, but avoids unneeded CPU cycles
|
||||||
|
if serverName == "" || len(authEvents) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
historyVisibility := HistoryVisibilityForRoom(authEvents)
|
historyVisibility := HistoryVisibilityForRoom(authEvents)
|
||||||
|
|
||||||
// 1. If the history_visibility was set to world_readable, allow.
|
// 1. If the history_visibility was set to world_readable, allow.
|
||||||
|
|
85
roomserver/auth/auth_test.go
Normal file
85
roomserver/auth/auth_test.go
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
package auth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/matrix-org/dendrite/test"
|
||||||
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
"github.com/matrix-org/gomatrixserverlib/spec"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestIsServerAllowed(t *testing.T) {
|
||||||
|
alice := test.NewUser(t)
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
want bool
|
||||||
|
roomFunc func() *test.Room
|
||||||
|
serverName spec.ServerName
|
||||||
|
serverCurrentlyInRoom bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "no servername specified",
|
||||||
|
roomFunc: func() *test.Room { return test.NewRoom(t, alice) },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no authEvents specified",
|
||||||
|
serverName: "test",
|
||||||
|
roomFunc: func() *test.Room { return &test.Room{} },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "default denied",
|
||||||
|
serverName: "test2",
|
||||||
|
roomFunc: func() *test.Room { return test.NewRoom(t, alice) },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "world readable room",
|
||||||
|
serverName: "test",
|
||||||
|
roomFunc: func() *test.Room {
|
||||||
|
return test.NewRoom(t, alice, test.RoomHistoryVisibility(gomatrixserverlib.HistoryVisibilityWorldReadable))
|
||||||
|
},
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "allowed due to alice being joined",
|
||||||
|
serverName: "test",
|
||||||
|
roomFunc: func() *test.Room { return test.NewRoom(t, alice) },
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "allowed due to 'serverCurrentlyInRoom'",
|
||||||
|
serverName: "test2",
|
||||||
|
roomFunc: func() *test.Room { return test.NewRoom(t, alice) },
|
||||||
|
want: true,
|
||||||
|
serverCurrentlyInRoom: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "allowed due to pending invite",
|
||||||
|
serverName: "test2",
|
||||||
|
roomFunc: func() *test.Room {
|
||||||
|
bob := test.User{ID: "@bob:test2"}
|
||||||
|
r := test.NewRoom(t, alice, test.RoomHistoryVisibility(gomatrixserverlib.HistoryVisibilityInvited))
|
||||||
|
r.CreateAndInsert(t, alice, spec.MRoomMember, map[string]interface{}{
|
||||||
|
"membership": spec.Invite,
|
||||||
|
}, test.WithStateKey(bob.ID))
|
||||||
|
return r
|
||||||
|
},
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
if tt.roomFunc == nil {
|
||||||
|
t.Fatalf("missing roomFunc")
|
||||||
|
}
|
||||||
|
var authEvents []*gomatrixserverlib.Event
|
||||||
|
for _, ev := range tt.roomFunc().Events() {
|
||||||
|
authEvents = append(authEvents, ev.Event)
|
||||||
|
}
|
||||||
|
|
||||||
|
if got := IsServerAllowed(tt.serverName, tt.serverCurrentlyInRoom, authEvents); got != tt.want {
|
||||||
|
t.Errorf("IsServerAllowed() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -478,7 +478,7 @@ func (r *Inputer) processRoomEvent(
|
||||||
|
|
||||||
// If guest_access changed and is not can_join, kick all guest users.
|
// If guest_access changed and is not can_join, kick all guest users.
|
||||||
if event.Type() == spec.MRoomGuestAccess && gjson.GetBytes(event.Content(), "guest_access").Str != "can_join" {
|
if event.Type() == spec.MRoomGuestAccess && gjson.GetBytes(event.Content(), "guest_access").Str != "can_join" {
|
||||||
if err = r.kickGuests(ctx, event, roomInfo); err != nil {
|
if err = r.kickGuests(ctx, event, roomInfo); err != nil && err != sql.ErrNoRows {
|
||||||
logrus.WithError(err).Error("failed to kick guest users on m.room.guest_access revocation")
|
logrus.WithError(err).Error("failed to kick guest users on m.room.guest_access revocation")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -319,9 +319,7 @@ func publishNewRoomAndUnpublishOldRoom(
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Upgrader) validateRoomExists(ctx context.Context, roomID string) error {
|
func (r *Upgrader) validateRoomExists(ctx context.Context, roomID string) error {
|
||||||
verReq := api.QueryRoomVersionForRoomRequest{RoomID: roomID}
|
if _, err := r.URSAPI.QueryRoomVersionForRoom(ctx, roomID); err != nil {
|
||||||
verRes := api.QueryRoomVersionForRoomResponse{}
|
|
||||||
if err := r.URSAPI.QueryRoomVersionForRoom(ctx, &verReq, &verRes); err != nil {
|
|
||||||
return &api.PerformError{
|
return &api.PerformError{
|
||||||
Code: api.PerformErrorNoRoom,
|
Code: api.PerformErrorNoRoom,
|
||||||
Msg: "Room does not exist",
|
Msg: "Room does not exist",
|
||||||
|
@ -357,7 +355,7 @@ func (r *Upgrader) generateInitialEvents(ctx context.Context, oldRoom *api.Query
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if event.Type() == spec.MRoomMember && !event.StateKeyEquals(userID) {
|
if event.Type() == spec.MRoomMember && !event.StateKeyEquals(userID) {
|
||||||
// With the exception of bans and invites which we do want to copy, we
|
// With the exception of bans which we do want to copy, we
|
||||||
// should ignore membership events that aren't our own, as event auth will
|
// should ignore membership events that aren't our own, as event auth will
|
||||||
// prevent us from being able to create membership events on behalf of other
|
// prevent us from being able to create membership events on behalf of other
|
||||||
// users anyway unless they are invites or bans.
|
// users anyway unless they are invites or bans.
|
||||||
|
@ -367,11 +365,15 @@ func (r *Upgrader) generateInitialEvents(ctx context.Context, oldRoom *api.Query
|
||||||
}
|
}
|
||||||
switch membership {
|
switch membership {
|
||||||
case spec.Ban:
|
case spec.Ban:
|
||||||
case spec.Invite:
|
|
||||||
default:
|
default:
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// skip events that rely on a specific user being present
|
||||||
|
sKey := *event.StateKey()
|
||||||
|
if event.Type() != spec.MRoomMember && len(sKey) > 0 && sKey[:1] == "@" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
state[gomatrixserverlib.StateKeyTuple{EventType: event.Type(), StateKey: *event.StateKey()}] = event
|
state[gomatrixserverlib.StateKeyTuple{EventType: event.Type(), StateKey: *event.StateKey()}] = event
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -521,14 +521,10 @@ func (r *Queryer) QueryMissingEvents(
|
||||||
response.Events = make([]*gomatrixserverlib.HeaderedEvent, 0, len(loadedEvents)-len(eventsToFilter))
|
response.Events = make([]*gomatrixserverlib.HeaderedEvent, 0, len(loadedEvents)-len(eventsToFilter))
|
||||||
for _, event := range loadedEvents {
|
for _, event := range loadedEvents {
|
||||||
if !eventsToFilter[event.EventID()] {
|
if !eventsToFilter[event.EventID()] {
|
||||||
roomVersion, verr := r.roomVersion(event.RoomID())
|
|
||||||
if verr != nil {
|
|
||||||
return verr
|
|
||||||
}
|
|
||||||
if _, ok := redactEventIDs[event.EventID()]; ok {
|
if _, ok := redactEventIDs[event.EventID()]; ok {
|
||||||
event.Redact()
|
event.Redact()
|
||||||
}
|
}
|
||||||
response.Events = append(response.Events, event.Headered(roomVersion))
|
response.Events = append(response.Events, event.Headered(info.RoomVersion))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -696,34 +692,20 @@ func GetAuthChain(
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueryRoomVersionForRoom implements api.RoomserverInternalAPI
|
// QueryRoomVersionForRoom implements api.RoomserverInternalAPI
|
||||||
func (r *Queryer) QueryRoomVersionForRoom(
|
func (r *Queryer) QueryRoomVersionForRoom(ctx context.Context, roomID string) (gomatrixserverlib.RoomVersion, error) {
|
||||||
ctx context.Context,
|
if roomVersion, ok := r.Cache.GetRoomVersion(roomID); ok {
|
||||||
request *api.QueryRoomVersionForRoomRequest,
|
return roomVersion, nil
|
||||||
response *api.QueryRoomVersionForRoomResponse,
|
|
||||||
) error {
|
|
||||||
if roomVersion, ok := r.Cache.GetRoomVersion(request.RoomID); ok {
|
|
||||||
response.RoomVersion = roomVersion
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
info, err := r.DB.RoomInfo(ctx, request.RoomID)
|
info, err := r.DB.RoomInfo(ctx, roomID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return "", err
|
||||||
}
|
}
|
||||||
if info == nil {
|
if info == nil {
|
||||||
return fmt.Errorf("QueryRoomVersionForRoom: missing room info for room %s", request.RoomID)
|
return "", fmt.Errorf("QueryRoomVersionForRoom: missing room info for room %s", roomID)
|
||||||
}
|
}
|
||||||
response.RoomVersion = info.RoomVersion
|
r.Cache.StoreRoomVersion(roomID, info.RoomVersion)
|
||||||
r.Cache.StoreRoomVersion(request.RoomID, response.RoomVersion)
|
return info.RoomVersion, nil
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Queryer) roomVersion(roomID string) (gomatrixserverlib.RoomVersion, error) {
|
|
||||||
var res api.QueryRoomVersionForRoomResponse
|
|
||||||
err := r.QueryRoomVersionForRoom(context.Background(), &api.QueryRoomVersionForRoomRequest{
|
|
||||||
RoomID: roomID,
|
|
||||||
}, &res)
|
|
||||||
return res.RoomVersion, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Queryer) QueryPublishedRooms(
|
func (r *Queryer) QueryPublishedRooms(
|
||||||
|
@ -910,8 +892,8 @@ func (r *Queryer) QueryRestrictedJoinAllowed(ctx context.Context, req *api.Query
|
||||||
if err = json.Unmarshal(joinRulesEvent.Content(), &joinRules); err != nil {
|
if err = json.Unmarshal(joinRulesEvent.Content(), &joinRules); err != nil {
|
||||||
return fmt.Errorf("json.Unmarshal: %w", err)
|
return fmt.Errorf("json.Unmarshal: %w", err)
|
||||||
}
|
}
|
||||||
// If the join rule isn't "restricted" then there's nothing more to do.
|
// If the join rule isn't "restricted" or "knock_restricted" then there's nothing more to do.
|
||||||
res.Restricted = joinRules.JoinRule == spec.Restricted
|
res.Restricted = joinRules.JoinRule == spec.Restricted || joinRules.JoinRule == spec.KnockRestricted
|
||||||
if !res.Restricted {
|
if !res.Restricted {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -932,9 +914,9 @@ func (r *Queryer) QueryRestrictedJoinAllowed(ctx context.Context, req *api.Query
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("r.DB.GetStateEvent: %w", err)
|
return fmt.Errorf("r.DB.GetStateEvent: %w", err)
|
||||||
}
|
}
|
||||||
var powerLevels gomatrixserverlib.PowerLevelContent
|
powerLevels, err := powerLevelsEvent.PowerLevels()
|
||||||
if err = json.Unmarshal(powerLevelsEvent.Content(), &powerLevels); err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("json.Unmarshal: %w", err)
|
return fmt.Errorf("unable to get powerlevels: %w", err)
|
||||||
}
|
}
|
||||||
// Step through the join rules and see if the user matches any of them.
|
// Step through the join rules and see if the user matches any of them.
|
||||||
for _, rule := range joinRules.Allow {
|
for _, rule := range joinRules.Allow {
|
||||||
|
|
|
@ -8,10 +8,13 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/matrix-org/dendrite/internal/caching"
|
"github.com/matrix-org/dendrite/internal/caching"
|
||||||
|
"github.com/matrix-org/dendrite/internal/eventutil"
|
||||||
"github.com/matrix-org/dendrite/internal/httputil"
|
"github.com/matrix-org/dendrite/internal/httputil"
|
||||||
"github.com/matrix-org/dendrite/internal/sqlutil"
|
"github.com/matrix-org/dendrite/internal/sqlutil"
|
||||||
|
"github.com/matrix-org/dendrite/roomserver/version"
|
||||||
"github.com/matrix-org/gomatrixserverlib/spec"
|
"github.com/matrix-org/gomatrixserverlib/spec"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/tidwall/gjson"
|
||||||
|
|
||||||
"github.com/matrix-org/dendrite/roomserver/state"
|
"github.com/matrix-org/dendrite/roomserver/state"
|
||||||
"github.com/matrix-org/dendrite/roomserver/types"
|
"github.com/matrix-org/dendrite/roomserver/types"
|
||||||
|
@ -582,3 +585,512 @@ func TestRedaction(t *testing.T) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestQueryRestrictedJoinAllowed(t *testing.T) {
|
||||||
|
alice := test.NewUser(t)
|
||||||
|
bob := test.NewUser(t)
|
||||||
|
|
||||||
|
// a room we don't create in the database
|
||||||
|
allowedByRoomNotExists := test.NewRoom(t, alice)
|
||||||
|
|
||||||
|
// a room we create in the database, used for authorisation
|
||||||
|
allowedByRoomExists := test.NewRoom(t, alice)
|
||||||
|
allowedByRoomExists.CreateAndInsert(t, bob, spec.MRoomMember, map[string]interface{}{
|
||||||
|
"membership": spec.Join,
|
||||||
|
}, test.WithStateKey(bob.ID))
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
prepareRoomFunc func(t *testing.T) *test.Room
|
||||||
|
wantResponse api.QueryRestrictedJoinAllowedResponse
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "public room unrestricted",
|
||||||
|
prepareRoomFunc: func(t *testing.T) *test.Room {
|
||||||
|
return test.NewRoom(t, alice)
|
||||||
|
},
|
||||||
|
wantResponse: api.QueryRestrictedJoinAllowedResponse{
|
||||||
|
Resident: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "room version without restrictions",
|
||||||
|
prepareRoomFunc: func(t *testing.T) *test.Room {
|
||||||
|
return test.NewRoom(t, alice, test.RoomVersion(gomatrixserverlib.RoomVersionV7))
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "restricted only", // bob is not allowed to join
|
||||||
|
prepareRoomFunc: func(t *testing.T) *test.Room {
|
||||||
|
r := test.NewRoom(t, alice, test.RoomVersion(gomatrixserverlib.RoomVersionV8))
|
||||||
|
r.CreateAndInsert(t, alice, spec.MRoomJoinRules, map[string]interface{}{
|
||||||
|
"join_rule": spec.Restricted,
|
||||||
|
}, test.WithStateKey(""))
|
||||||
|
return r
|
||||||
|
},
|
||||||
|
wantResponse: api.QueryRestrictedJoinAllowedResponse{
|
||||||
|
Resident: true,
|
||||||
|
Restricted: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "knock_restricted",
|
||||||
|
prepareRoomFunc: func(t *testing.T) *test.Room {
|
||||||
|
r := test.NewRoom(t, alice, test.RoomVersion(gomatrixserverlib.RoomVersionV8))
|
||||||
|
r.CreateAndInsert(t, alice, spec.MRoomJoinRules, map[string]interface{}{
|
||||||
|
"join_rule": spec.KnockRestricted,
|
||||||
|
}, test.WithStateKey(""))
|
||||||
|
return r
|
||||||
|
},
|
||||||
|
wantResponse: api.QueryRestrictedJoinAllowedResponse{
|
||||||
|
Resident: true,
|
||||||
|
Restricted: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "restricted with pending invite", // bob should be allowed to join
|
||||||
|
prepareRoomFunc: func(t *testing.T) *test.Room {
|
||||||
|
r := test.NewRoom(t, alice, test.RoomVersion(gomatrixserverlib.RoomVersionV8))
|
||||||
|
r.CreateAndInsert(t, alice, spec.MRoomJoinRules, map[string]interface{}{
|
||||||
|
"join_rule": spec.Restricted,
|
||||||
|
}, test.WithStateKey(""))
|
||||||
|
r.CreateAndInsert(t, alice, spec.MRoomMember, map[string]interface{}{
|
||||||
|
"membership": spec.Invite,
|
||||||
|
}, test.WithStateKey(bob.ID))
|
||||||
|
return r
|
||||||
|
},
|
||||||
|
wantResponse: api.QueryRestrictedJoinAllowedResponse{
|
||||||
|
Resident: true,
|
||||||
|
Restricted: true,
|
||||||
|
Allowed: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "restricted with allowed room_id, but missing room", // bob should not be allowed to join, as we don't know about the room
|
||||||
|
prepareRoomFunc: func(t *testing.T) *test.Room {
|
||||||
|
r := test.NewRoom(t, alice, test.RoomVersion(gomatrixserverlib.RoomVersionV10))
|
||||||
|
r.CreateAndInsert(t, alice, spec.MRoomJoinRules, map[string]interface{}{
|
||||||
|
"join_rule": spec.KnockRestricted,
|
||||||
|
"allow": []map[string]interface{}{
|
||||||
|
{
|
||||||
|
"room_id": allowedByRoomNotExists.ID,
|
||||||
|
"type": spec.MRoomMembership,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, test.WithStateKey(""))
|
||||||
|
r.CreateAndInsert(t, bob, spec.MRoomMember, map[string]interface{}{
|
||||||
|
"membership": spec.Join,
|
||||||
|
"join_authorised_via_users_server": alice.ID,
|
||||||
|
}, test.WithStateKey(bob.ID))
|
||||||
|
return r
|
||||||
|
},
|
||||||
|
wantResponse: api.QueryRestrictedJoinAllowedResponse{
|
||||||
|
Restricted: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "restricted with allowed room_id", // bob should be allowed to join, as we know about the room
|
||||||
|
prepareRoomFunc: func(t *testing.T) *test.Room {
|
||||||
|
r := test.NewRoom(t, alice, test.RoomVersion(gomatrixserverlib.RoomVersionV10))
|
||||||
|
r.CreateAndInsert(t, alice, spec.MRoomJoinRules, map[string]interface{}{
|
||||||
|
"join_rule": spec.KnockRestricted,
|
||||||
|
"allow": []map[string]interface{}{
|
||||||
|
{
|
||||||
|
"room_id": allowedByRoomExists.ID,
|
||||||
|
"type": spec.MRoomMembership,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, test.WithStateKey(""))
|
||||||
|
r.CreateAndInsert(t, bob, spec.MRoomMember, map[string]interface{}{
|
||||||
|
"membership": spec.Join,
|
||||||
|
"join_authorised_via_users_server": alice.ID,
|
||||||
|
}, test.WithStateKey(bob.ID))
|
||||||
|
return r
|
||||||
|
},
|
||||||
|
wantResponse: api.QueryRestrictedJoinAllowedResponse{
|
||||||
|
Resident: true,
|
||||||
|
Restricted: true,
|
||||||
|
Allowed: true,
|
||||||
|
AuthorisedVia: alice.ID,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
|
||||||
|
cfg, processCtx, close := testrig.CreateConfig(t, dbType)
|
||||||
|
natsInstance := jetstream.NATSInstance{}
|
||||||
|
defer close()
|
||||||
|
|
||||||
|
cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
|
||||||
|
caches := caching.NewRistrettoCache(128*1024*1024, time.Hour, caching.DisableMetrics)
|
||||||
|
|
||||||
|
rsAPI := roomserver.NewInternalAPI(processCtx, cfg, cm, &natsInstance, caches, caching.DisableMetrics)
|
||||||
|
rsAPI.SetFederationAPI(nil, nil)
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
if tc.prepareRoomFunc == nil {
|
||||||
|
t.Fatal("missing prepareRoomFunc")
|
||||||
|
}
|
||||||
|
testRoom := tc.prepareRoomFunc(t)
|
||||||
|
// Create the room
|
||||||
|
if err := api.SendEvents(processCtx.Context(), rsAPI, api.KindNew, testRoom.Events(), "test", "test", "test", nil, false); err != nil {
|
||||||
|
t.Errorf("failed to send events: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := api.SendEvents(processCtx.Context(), rsAPI, api.KindNew, allowedByRoomExists.Events(), "test", "test", "test", nil, false); err != nil {
|
||||||
|
t.Errorf("failed to send events: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
req := api.QueryRestrictedJoinAllowedRequest{
|
||||||
|
UserID: bob.ID,
|
||||||
|
RoomID: testRoom.ID,
|
||||||
|
}
|
||||||
|
res := api.QueryRestrictedJoinAllowedResponse{}
|
||||||
|
if err := rsAPI.QueryRestrictedJoinAllowed(processCtx.Context(), &req, &res); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(tc.wantResponse, res) {
|
||||||
|
t.Fatalf("unexpected response, want %#v - got %#v", tc.wantResponse, res)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUpgrade(t *testing.T) {
|
||||||
|
alice := test.NewUser(t)
|
||||||
|
bob := test.NewUser(t)
|
||||||
|
charlie := test.NewUser(t)
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
spaceChild := test.NewRoom(t, alice)
|
||||||
|
validateTuples := []gomatrixserverlib.StateKeyTuple{
|
||||||
|
{EventType: spec.MRoomCreate},
|
||||||
|
{EventType: spec.MRoomPowerLevels},
|
||||||
|
{EventType: spec.MRoomJoinRules},
|
||||||
|
{EventType: spec.MRoomName},
|
||||||
|
{EventType: spec.MRoomCanonicalAlias},
|
||||||
|
{EventType: "m.room.tombstone"},
|
||||||
|
{EventType: "m.custom.event"},
|
||||||
|
{EventType: "m.space.child", StateKey: spaceChild.ID},
|
||||||
|
{EventType: "m.custom.event", StateKey: alice.ID},
|
||||||
|
{EventType: spec.MRoomMember, StateKey: charlie.ID}, // ban should be transferred
|
||||||
|
}
|
||||||
|
|
||||||
|
validate := func(t *testing.T, oldRoomID, newRoomID string, rsAPI api.RoomserverInternalAPI) {
|
||||||
|
|
||||||
|
oldRoomState := &api.QueryCurrentStateResponse{}
|
||||||
|
if err := rsAPI.QueryCurrentState(ctx, &api.QueryCurrentStateRequest{
|
||||||
|
RoomID: oldRoomID,
|
||||||
|
StateTuples: validateTuples,
|
||||||
|
}, oldRoomState); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
newRoomState := &api.QueryCurrentStateResponse{}
|
||||||
|
if err := rsAPI.QueryCurrentState(ctx, &api.QueryCurrentStateRequest{
|
||||||
|
RoomID: newRoomID,
|
||||||
|
StateTuples: validateTuples,
|
||||||
|
}, newRoomState); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// the old room should have a tombstone event
|
||||||
|
ev := oldRoomState.StateEvents[gomatrixserverlib.StateKeyTuple{EventType: "m.room.tombstone"}]
|
||||||
|
replacementRoom := gjson.GetBytes(ev.Content(), "replacement_room").Str
|
||||||
|
if replacementRoom != newRoomID {
|
||||||
|
t.Fatalf("tombstone event has replacement_room '%s', expected '%s'", replacementRoom, newRoomID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// the new room should have a predecessor equal to the old room
|
||||||
|
ev = newRoomState.StateEvents[gomatrixserverlib.StateKeyTuple{EventType: spec.MRoomCreate}]
|
||||||
|
predecessor := gjson.GetBytes(ev.Content(), "predecessor.room_id").Str
|
||||||
|
if predecessor != oldRoomID {
|
||||||
|
t.Fatalf("got predecessor room '%s', expected '%s'", predecessor, oldRoomID)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tuple := range validateTuples {
|
||||||
|
// Skip create and powerlevel event (new room has e.g. predecessor event, old room has restricted powerlevels)
|
||||||
|
switch tuple.EventType {
|
||||||
|
case spec.MRoomCreate, spec.MRoomPowerLevels, spec.MRoomCanonicalAlias:
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
oldEv, ok := oldRoomState.StateEvents[tuple]
|
||||||
|
if !ok {
|
||||||
|
t.Logf("skipping tuple %#v as it doesn't exist in the old room", tuple)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
newEv, ok := newRoomState.StateEvents[tuple]
|
||||||
|
if !ok {
|
||||||
|
t.Logf("skipping tuple %#v as it doesn't exist in the new room", tuple)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(oldEv.Content(), newEv.Content()) {
|
||||||
|
t.Logf("OldEvent QueryCurrentState: %s", string(oldEv.Content()))
|
||||||
|
t.Logf("NewEvent QueryCurrentState: %s", string(newEv.Content()))
|
||||||
|
t.Errorf("event content mismatch")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
upgradeUser string
|
||||||
|
roomFunc func(rsAPI api.RoomserverInternalAPI) string
|
||||||
|
validateFunc func(t *testing.T, oldRoomID, newRoomID string, rsAPI api.RoomserverInternalAPI)
|
||||||
|
wantNewRoom bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "invalid userID",
|
||||||
|
upgradeUser: "!notvalid:test",
|
||||||
|
roomFunc: func(rsAPI api.RoomserverInternalAPI) string {
|
||||||
|
room := test.NewRoom(t, alice)
|
||||||
|
if err := api.SendEvents(ctx, rsAPI, api.KindNew, room.Events(), "test", "test", "test", nil, false); err != nil {
|
||||||
|
t.Errorf("failed to send events: %v", err)
|
||||||
|
}
|
||||||
|
return room.ID
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid roomID",
|
||||||
|
upgradeUser: alice.ID,
|
||||||
|
roomFunc: func(rsAPI api.RoomserverInternalAPI) string {
|
||||||
|
return "!doesnotexist:test"
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "powerlevel too low",
|
||||||
|
upgradeUser: bob.ID,
|
||||||
|
roomFunc: func(rsAPI api.RoomserverInternalAPI) string {
|
||||||
|
room := test.NewRoom(t, alice)
|
||||||
|
if err := api.SendEvents(ctx, rsAPI, api.KindNew, room.Events(), "test", "test", "test", nil, false); err != nil {
|
||||||
|
t.Errorf("failed to send events: %v", err)
|
||||||
|
}
|
||||||
|
return room.ID
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "successful upgrade on new room",
|
||||||
|
upgradeUser: alice.ID,
|
||||||
|
roomFunc: func(rsAPI api.RoomserverInternalAPI) string {
|
||||||
|
room := test.NewRoom(t, alice)
|
||||||
|
if err := api.SendEvents(ctx, rsAPI, api.KindNew, room.Events(), "test", "test", "test", nil, false); err != nil {
|
||||||
|
t.Errorf("failed to send events: %v", err)
|
||||||
|
}
|
||||||
|
return room.ID
|
||||||
|
},
|
||||||
|
wantNewRoom: true,
|
||||||
|
validateFunc: validate,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "successful upgrade on new room with other state events",
|
||||||
|
upgradeUser: alice.ID,
|
||||||
|
roomFunc: func(rsAPI api.RoomserverInternalAPI) string {
|
||||||
|
r := test.NewRoom(t, alice)
|
||||||
|
r.CreateAndInsert(t, alice, spec.MRoomName, map[string]interface{}{
|
||||||
|
"name": "my new name",
|
||||||
|
}, test.WithStateKey(""))
|
||||||
|
r.CreateAndInsert(t, alice, spec.MRoomCanonicalAlias, eventutil.CanonicalAliasContent{
|
||||||
|
Alias: "#myalias:test",
|
||||||
|
}, test.WithStateKey(""))
|
||||||
|
|
||||||
|
// this will be transferred
|
||||||
|
r.CreateAndInsert(t, alice, "m.custom.event", map[string]interface{}{
|
||||||
|
"random": "i should exist",
|
||||||
|
}, test.WithStateKey(""))
|
||||||
|
|
||||||
|
// the following will be ignored
|
||||||
|
r.CreateAndInsert(t, alice, "m.custom.event", map[string]interface{}{
|
||||||
|
"random": "i will be ignored",
|
||||||
|
}, test.WithStateKey(alice.ID))
|
||||||
|
|
||||||
|
if err := api.SendEvents(ctx, rsAPI, api.KindNew, r.Events(), "test", "test", "test", nil, false); err != nil {
|
||||||
|
t.Errorf("failed to send events: %v", err)
|
||||||
|
}
|
||||||
|
return r.ID
|
||||||
|
},
|
||||||
|
wantNewRoom: true,
|
||||||
|
validateFunc: validate,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "with published room",
|
||||||
|
upgradeUser: alice.ID,
|
||||||
|
roomFunc: func(rsAPI api.RoomserverInternalAPI) string {
|
||||||
|
r := test.NewRoom(t, alice)
|
||||||
|
if err := api.SendEvents(ctx, rsAPI, api.KindNew, r.Events(), "test", "test", "test", nil, false); err != nil {
|
||||||
|
t.Errorf("failed to send events: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := rsAPI.PerformPublish(ctx, &api.PerformPublishRequest{
|
||||||
|
RoomID: r.ID,
|
||||||
|
Visibility: spec.Public,
|
||||||
|
}, &api.PerformPublishResponse{}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.ID
|
||||||
|
},
|
||||||
|
wantNewRoom: true,
|
||||||
|
validateFunc: func(t *testing.T, oldRoomID, newRoomID string, rsAPI api.RoomserverInternalAPI) {
|
||||||
|
validate(t, oldRoomID, newRoomID, rsAPI)
|
||||||
|
// check that the new room is published
|
||||||
|
res := &api.QueryPublishedRoomsResponse{}
|
||||||
|
if err := rsAPI.QueryPublishedRooms(ctx, &api.QueryPublishedRoomsRequest{RoomID: newRoomID}, res); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(res.RoomIDs) == 0 {
|
||||||
|
t.Fatalf("expected room to be published, but wasn't: %#v", res.RoomIDs)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "with alias",
|
||||||
|
upgradeUser: alice.ID,
|
||||||
|
roomFunc: func(rsAPI api.RoomserverInternalAPI) string {
|
||||||
|
r := test.NewRoom(t, alice)
|
||||||
|
if err := api.SendEvents(ctx, rsAPI, api.KindNew, r.Events(), "test", "test", "test", nil, false); err != nil {
|
||||||
|
t.Errorf("failed to send events: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := rsAPI.SetRoomAlias(ctx, &api.SetRoomAliasRequest{
|
||||||
|
RoomID: r.ID,
|
||||||
|
Alias: "#myroomalias:test",
|
||||||
|
}, &api.SetRoomAliasResponse{}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.ID
|
||||||
|
},
|
||||||
|
wantNewRoom: true,
|
||||||
|
validateFunc: func(t *testing.T, oldRoomID, newRoomID string, rsAPI api.RoomserverInternalAPI) {
|
||||||
|
validate(t, oldRoomID, newRoomID, rsAPI)
|
||||||
|
// check that the old room has no aliases
|
||||||
|
res := &api.GetAliasesForRoomIDResponse{}
|
||||||
|
if err := rsAPI.GetAliasesForRoomID(ctx, &api.GetAliasesForRoomIDRequest{RoomID: oldRoomID}, res); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(res.Aliases) != 0 {
|
||||||
|
t.Fatalf("expected old room aliases to be empty, but wasn't: %#v", res.Aliases)
|
||||||
|
}
|
||||||
|
|
||||||
|
// check that the new room has aliases
|
||||||
|
if err := rsAPI.GetAliasesForRoomID(ctx, &api.GetAliasesForRoomIDRequest{RoomID: newRoomID}, res); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(res.Aliases) == 0 {
|
||||||
|
t.Fatalf("expected room aliases to be transferred, but wasn't: %#v", res.Aliases)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "bans are transferred",
|
||||||
|
upgradeUser: alice.ID,
|
||||||
|
roomFunc: func(rsAPI api.RoomserverInternalAPI) string {
|
||||||
|
r := test.NewRoom(t, alice)
|
||||||
|
r.CreateAndInsert(t, alice, spec.MRoomMember, map[string]interface{}{
|
||||||
|
"membership": spec.Ban,
|
||||||
|
}, test.WithStateKey(charlie.ID))
|
||||||
|
if err := api.SendEvents(ctx, rsAPI, api.KindNew, r.Events(), "test", "test", "test", nil, false); err != nil {
|
||||||
|
t.Errorf("failed to send events: %v", err)
|
||||||
|
}
|
||||||
|
return r.ID
|
||||||
|
},
|
||||||
|
wantNewRoom: true,
|
||||||
|
validateFunc: validate,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "space childs are transferred",
|
||||||
|
upgradeUser: alice.ID,
|
||||||
|
roomFunc: func(rsAPI api.RoomserverInternalAPI) string {
|
||||||
|
r := test.NewRoom(t, alice)
|
||||||
|
|
||||||
|
r.CreateAndInsert(t, alice, "m.space.child", map[string]interface{}{}, test.WithStateKey(spaceChild.ID))
|
||||||
|
if err := api.SendEvents(ctx, rsAPI, api.KindNew, r.Events(), "test", "test", "test", nil, false); err != nil {
|
||||||
|
t.Errorf("failed to send events: %v", err)
|
||||||
|
}
|
||||||
|
return r.ID
|
||||||
|
},
|
||||||
|
wantNewRoom: true,
|
||||||
|
validateFunc: validate,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "custom state is not taken to the new room", // https://github.com/matrix-org/dendrite/issues/2912
|
||||||
|
upgradeUser: charlie.ID,
|
||||||
|
roomFunc: func(rsAPI api.RoomserverInternalAPI) string {
|
||||||
|
r := test.NewRoom(t, alice, test.RoomVersion(gomatrixserverlib.RoomVersionV6))
|
||||||
|
// Bob and Charlie join
|
||||||
|
r.CreateAndInsert(t, bob, spec.MRoomMember, map[string]interface{}{"membership": spec.Join}, test.WithStateKey(bob.ID))
|
||||||
|
r.CreateAndInsert(t, charlie, spec.MRoomMember, map[string]interface{}{"membership": spec.Join}, test.WithStateKey(charlie.ID))
|
||||||
|
|
||||||
|
// make Charlie an admin so the room can be upgraded
|
||||||
|
r.CreateAndInsert(t, alice, spec.MRoomPowerLevels, gomatrixserverlib.PowerLevelContent{
|
||||||
|
Users: map[string]int64{
|
||||||
|
charlie.ID: 100,
|
||||||
|
},
|
||||||
|
}, test.WithStateKey(""))
|
||||||
|
|
||||||
|
// Alice creates a custom event
|
||||||
|
r.CreateAndInsert(t, alice, "m.custom.event", map[string]interface{}{
|
||||||
|
"random": "data",
|
||||||
|
}, test.WithStateKey(alice.ID))
|
||||||
|
r.CreateAndInsert(t, alice, spec.MRoomMember, map[string]interface{}{"membership": spec.Leave}, test.WithStateKey(alice.ID))
|
||||||
|
|
||||||
|
if err := api.SendEvents(ctx, rsAPI, api.KindNew, r.Events(), "test", "test", "test", nil, false); err != nil {
|
||||||
|
t.Errorf("failed to send events: %v", err)
|
||||||
|
}
|
||||||
|
return r.ID
|
||||||
|
},
|
||||||
|
wantNewRoom: true,
|
||||||
|
validateFunc: validate,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
|
||||||
|
cfg, processCtx, close := testrig.CreateConfig(t, dbType)
|
||||||
|
natsInstance := jetstream.NATSInstance{}
|
||||||
|
defer close()
|
||||||
|
|
||||||
|
cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
|
||||||
|
caches := caching.NewRistrettoCache(128*1024*1024, time.Hour, caching.DisableMetrics)
|
||||||
|
|
||||||
|
rsAPI := roomserver.NewInternalAPI(processCtx, cfg, cm, &natsInstance, caches, caching.DisableMetrics)
|
||||||
|
userAPI := userapi.NewInternalAPI(processCtx, cfg, cm, &natsInstance, rsAPI, nil)
|
||||||
|
rsAPI.SetFederationAPI(nil, nil)
|
||||||
|
rsAPI.SetUserAPI(userAPI)
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
if tc.roomFunc == nil {
|
||||||
|
t.Fatalf("missing roomFunc")
|
||||||
|
}
|
||||||
|
if tc.upgradeUser == "" {
|
||||||
|
tc.upgradeUser = alice.ID
|
||||||
|
}
|
||||||
|
roomID := tc.roomFunc(rsAPI)
|
||||||
|
|
||||||
|
upgradeReq := api.PerformRoomUpgradeRequest{
|
||||||
|
RoomID: roomID,
|
||||||
|
UserID: tc.upgradeUser,
|
||||||
|
RoomVersion: version.DefaultRoomVersion(), // always upgrade to the latest version
|
||||||
|
}
|
||||||
|
upgradeRes := api.PerformRoomUpgradeResponse{}
|
||||||
|
|
||||||
|
if err := rsAPI.PerformRoomUpgrade(processCtx.Context(), &upgradeReq, &upgradeRes); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if tc.wantNewRoom && upgradeRes.NewRoomID == "" {
|
||||||
|
t.Fatalf("expected a new room, but the upgrade failed")
|
||||||
|
}
|
||||||
|
if !tc.wantNewRoom && upgradeRes.NewRoomID != "" {
|
||||||
|
t.Fatalf("expected no new room, but the upgrade succeeded")
|
||||||
|
}
|
||||||
|
if tc.validateFunc != nil {
|
||||||
|
tc.validateFunc(t, roomID, upgradeRes.NewRoomID, rsAPI)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -669,13 +669,17 @@ func (d *Database) GetOrCreateRoomInfo(ctx context.Context, event *gomatrixserve
|
||||||
if roomVersion, err = extractRoomVersionFromCreateEvent(event); err != nil {
|
if roomVersion, err = extractRoomVersionFromCreateEvent(event); err != nil {
|
||||||
return nil, fmt.Errorf("extractRoomVersionFromCreateEvent: %w", err)
|
return nil, fmt.Errorf("extractRoomVersionFromCreateEvent: %w", err)
|
||||||
}
|
}
|
||||||
if roomVersion == "" {
|
|
||||||
rv, ok := d.Cache.GetRoomVersion(event.RoomID())
|
roomNID, nidOK := d.Cache.GetRoomServerRoomNID(event.RoomID())
|
||||||
if ok {
|
cachedRoomVersion, versionOK := d.Cache.GetRoomVersion(event.RoomID())
|
||||||
roomVersion = rv
|
// if we found both, the roomNID and version in our cache, no need to query the database
|
||||||
}
|
if nidOK && versionOK {
|
||||||
|
return &types.RoomInfo{
|
||||||
|
RoomNID: roomNID,
|
||||||
|
RoomVersion: cachedRoomVersion,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
var roomNID types.RoomNID
|
|
||||||
err = d.Writer.Do(d.DB, nil, func(txn *sql.Tx) error {
|
err = d.Writer.Do(d.DB, nil, func(txn *sql.Tx) error {
|
||||||
roomNID, err = d.assignRoomNID(ctx, txn, event.RoomID(), roomVersion)
|
roomNID, err = d.assignRoomNID(ctx, txn, event.RoomID(), roomVersion)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1164,7 +1168,7 @@ func (d *Database) GetStateEvent(ctx context.Context, roomID, evType, stateKey s
|
||||||
if roomInfo.IsStub() {
|
if roomInfo.IsStub() {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
eventTypeNID, err := d.EventTypesTable.SelectEventTypeNID(ctx, nil, evType)
|
eventTypeNID, err := d.GetOrCreateEventTypeNID(ctx, evType)
|
||||||
if err == sql.ErrNoRows {
|
if err == sql.ErrNoRows {
|
||||||
// No rooms have an event of this type, otherwise we'd have an event type NID
|
// No rooms have an event of this type, otherwise we'd have an event type NID
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
@ -1172,7 +1176,7 @@ func (d *Database) GetStateEvent(ctx context.Context, roomID, evType, stateKey s
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
stateKeyNID, err := d.EventStateKeysTable.SelectEventStateKeyNID(ctx, nil, stateKey)
|
stateKeyNID, err := d.GetOrCreateEventStateKeyNID(ctx, &stateKey)
|
||||||
if err == sql.ErrNoRows {
|
if err == sql.ErrNoRows {
|
||||||
// No rooms have a state event with this state key, otherwise we'd have an state key NID
|
// No rooms have a state event with this state key, otherwise we'd have an state key NID
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
@ -1201,6 +1205,10 @@ func (d *Database) GetStateEvent(ctx context.Context, roomID, evType, stateKey s
|
||||||
// return the event requested
|
// return the event requested
|
||||||
for _, e := range entries {
|
for _, e := range entries {
|
||||||
if e.EventTypeNID == eventTypeNID && e.EventStateKeyNID == stateKeyNID {
|
if e.EventTypeNID == eventTypeNID && e.EventStateKeyNID == stateKeyNID {
|
||||||
|
cachedEvent, ok := d.Cache.GetRoomServerEvent(e.EventNID)
|
||||||
|
if ok {
|
||||||
|
return cachedEvent.Headered(roomInfo.RoomVersion), nil
|
||||||
|
}
|
||||||
data, err := d.EventJSONTable.BulkSelectEventJSON(ctx, nil, []types.EventNID{e.EventNID})
|
data, err := d.EventJSONTable.BulkSelectEventJSON(ctx, nil, []types.EventNID{e.EventNID})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -1324,7 +1332,7 @@ func (d *Database) GetBulkStateContent(ctx context.Context, roomIDs []string, tu
|
||||||
}
|
}
|
||||||
// we don't bother failing the request if we get asked for event types we don't know about, as all that would result in is no matches which
|
// we don't bother failing the request if we get asked for event types we don't know about, as all that would result in is no matches which
|
||||||
// isn't a failure.
|
// isn't a failure.
|
||||||
eventTypeNIDMap, err := d.EventTypesTable.BulkSelectEventTypeNID(ctx, nil, eventTypes)
|
eventTypeNIDMap, err := d.eventTypeNIDs(ctx, nil, eventTypes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("GetBulkStateContent: failed to map event type nids: %w", err)
|
return nil, fmt.Errorf("GetBulkStateContent: failed to map event type nids: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -325,10 +325,8 @@ func (rc *reqCtx) fetchUnknownEvent(eventID, roomID string) *gomatrixserverlib.H
|
||||||
}
|
}
|
||||||
logger := util.GetLogger(rc.ctx).WithField("room_id", roomID)
|
logger := util.GetLogger(rc.ctx).WithField("room_id", roomID)
|
||||||
// if they supplied a room_id, check the room exists.
|
// if they supplied a room_id, check the room exists.
|
||||||
var queryVerRes roomserver.QueryRoomVersionForRoomResponse
|
|
||||||
err := rc.rsAPI.QueryRoomVersionForRoom(rc.ctx, &roomserver.QueryRoomVersionForRoomRequest{
|
roomVersion, err := rc.rsAPI.QueryRoomVersionForRoom(rc.ctx, roomID)
|
||||||
RoomID: roomID,
|
|
||||||
}, &queryVerRes)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.WithError(err).Warn("failed to query room version for room, does this room exist?")
|
logger.WithError(err).Warn("failed to query room version for room, does this room exist?")
|
||||||
return nil
|
return nil
|
||||||
|
@ -367,7 +365,7 @@ func (rc *reqCtx) fetchUnknownEvent(eventID, roomID string) *gomatrixserverlib.H
|
||||||
// Inject the response into the roomserver to remember the event across multiple calls and to set
|
// Inject the response into the roomserver to remember the event across multiple calls and to set
|
||||||
// unexplored flags correctly.
|
// unexplored flags correctly.
|
||||||
for _, srv := range serversToQuery {
|
for _, srv := range serversToQuery {
|
||||||
res, err := rc.MSC2836EventRelationships(eventID, srv, queryVerRes.RoomVersion)
|
res, err := rc.MSC2836EventRelationships(eventID, srv, roomVersion)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue