0
0
Fork 0
mirror of https://github.com/matrix-org/dendrite synced 2024-06-01 03:59:03 +02:00

Fix spaces over federation

This commit is contained in:
Till Faelligen 2024-03-26 19:36:26 +01:00
parent d204c7a17c
commit 8192936c44
No known key found for this signature in database
GPG key ID: 3DF82D8AB9211D4E
2 changed files with 37 additions and 27 deletions

View file

@ -189,7 +189,7 @@ func PopulatePublicRooms(ctx context.Context, roomIDs []string, rsAPI QueryBulkS
RoomID: roomID,
}
joinCount := 0
var joinRule, guestAccess string
var guestAccess string
for tuple, contentVal := range data {
if tuple.EventType == spec.MRoomMember && contentVal == "join" {
joinCount++
@ -210,12 +210,12 @@ func PopulatePublicRooms(ctx context.Context, roomIDs []string, rsAPI QueryBulkS
pub.WorldReadable = contentVal == "world_readable"
// need both of these to determine whether guests can join
case joinRuleTuple:
joinRule = contentVal
pub.JoinRule = contentVal
case guestTuple:
guestAccess = contentVal
}
}
if joinRule == spec.Public && guestAccess == "can_join" {
if pub.JoinRule == spec.Public && guestAccess == "can_join" {
pub.GuestCanJoin = true
}
pub.JoinedMembersCount = joinCount

View file

@ -45,8 +45,8 @@ func (querier *Queryer) QueryNextRoomHierarchyPage(ctx context.Context, walker r
*roomserver.RoomHierarchyWalker,
error,
) {
if authorised, _ := authorised(ctx, querier, walker.Caller, walker.RootRoomID, nil); !authorised {
return nil, []string{}, nil, roomserver.ErrRoomUnknownOrNotAllowed{Err: fmt.Errorf("room is unknown/forbidden")}
if authorised, _, _ := authorised(ctx, querier, walker.Caller, walker.RootRoomID, nil); !authorised {
return nil, []string{walker.RootRoomID.String()}, nil, roomserver.ErrRoomUnknownOrNotAllowed{Err: fmt.Errorf("room is unknown/forbidden")}
}
discoveredRooms := []fclient.RoomHierarchyRoom{}
@ -55,6 +55,7 @@ func (querier *Queryer) QueryNextRoomHierarchyPage(ctx context.Context, walker r
unvisited := make([]roomserver.RoomHierarchyWalkerQueuedRoom, len(walker.Unvisited))
copy(unvisited, walker.Unvisited)
processed := walker.Processed.Copy()
inaccessible := []string{}
// Depth first -> stack data structure
for len(unvisited) > 0 {
@ -113,7 +114,7 @@ func (querier *Queryer) QueryNextRoomHierarchyPage(ctx context.Context, walker r
// as these children may be rooms we do know about.
roomType = spec.MSpace
}
} else if authorised, isJoinedOrInvited := authorised(ctx, querier, walker.Caller, queuedRoom.RoomID, queuedRoom.ParentRoomID); authorised {
} else if authorised, isJoinedOrInvited, allowedRoomIDs := authorised(ctx, querier, walker.Caller, queuedRoom.RoomID, queuedRoom.ParentRoomID); authorised {
// Get all `m.space.child` state events for this room
events, err := childReferences(ctx, querier, walker.SuggestedOnly, queuedRoom.RoomID)
if err != nil {
@ -130,14 +131,17 @@ func (querier *Queryer) QueryNextRoomHierarchyPage(ctx context.Context, walker r
}
discoveredRooms = append(discoveredRooms, fclient.RoomHierarchyRoom{
PublicRoom: *pubRoom,
RoomType: roomType,
ChildrenState: events,
PublicRoom: *pubRoom,
RoomType: roomType,
ChildrenState: events,
AllowedRoomIDs: allowedRoomIDs,
})
// don't walk children if the user is not joined/invited to the space
if !isJoinedOrInvited {
continue
}
} else if !authorised {
inaccessible = append(inaccessible, queuedRoom.RoomID.String())
} else {
// room exists but user is not authorised
continue
@ -178,7 +182,7 @@ func (querier *Queryer) QueryNextRoomHierarchyPage(ctx context.Context, walker r
if len(unvisited) == 0 {
// If no more rooms to walk, then don't return a walker for future pages
return discoveredRooms, []string{}, nil, nil
return discoveredRooms, inaccessible, nil, nil
} else {
// If there are more rooms to walk, then return a new walker to resume walking from (for querying more pages)
newWalker := roomserver.RoomHierarchyWalker{
@ -190,24 +194,25 @@ func (querier *Queryer) QueryNextRoomHierarchyPage(ctx context.Context, walker r
Processed: processed,
}
return discoveredRooms, []string{}, &newWalker, nil
return discoveredRooms, inaccessible, &newWalker, nil
}
}
// authorised returns true iff the user is joined this room or the room is world_readable
func authorised(ctx context.Context, querier *Queryer, caller types.DeviceOrServerName, roomID spec.RoomID, parentRoomID *spec.RoomID) (authed, isJoinedOrInvited bool) {
func authorised(ctx context.Context, querier *Queryer, caller types.DeviceOrServerName, roomID spec.RoomID, parentRoomID *spec.RoomID) (authed, isJoinedOrInvited bool, resultAllowedRoomIDs []string) {
if clientCaller := caller.Device(); clientCaller != nil {
return authorisedUser(ctx, querier, clientCaller, roomID, parentRoomID)
}
if serverCaller := caller.ServerName(); serverCaller != nil {
return authorisedServer(ctx, querier, roomID, *serverCaller), false
authed, resultAllowedRoomIDs = authorisedServer(ctx, querier, roomID, *serverCaller)
return authed, false, resultAllowedRoomIDs
}
return false, false
return false, false, resultAllowedRoomIDs
}
// authorisedServer returns true iff the server is joined this room or the room is world_readable, public, or knockable
func authorisedServer(ctx context.Context, querier *Queryer, roomID spec.RoomID, callerServerName spec.ServerName) bool {
func authorisedServer(ctx context.Context, querier *Queryer, roomID spec.RoomID, callerServerName spec.ServerName) (bool, []string) {
// Check history visibility / join rules first
hisVisTuple := gomatrixserverlib.StateKeyTuple{
EventType: spec.MRoomHistoryVisibility,
@ -226,13 +231,13 @@ func authorisedServer(ctx context.Context, querier *Queryer, roomID spec.RoomID,
}, &queryRoomRes)
if err != nil {
util.GetLogger(ctx).WithError(err).Error("failed to QueryCurrentState")
return false
return false, []string{}
}
hisVisEv := queryRoomRes.StateEvents[hisVisTuple]
if hisVisEv != nil {
hisVis, _ := hisVisEv.HistoryVisibility()
if hisVis == "world_readable" {
return true
return true, []string{}
}
}
@ -245,11 +250,11 @@ func authorisedServer(ctx context.Context, querier *Queryer, roomID spec.RoomID,
rule, ruleErr := joinRuleEv.JoinRule()
if ruleErr != nil {
util.GetLogger(ctx).WithError(ruleErr).WithField("parent_room_id", roomID).Warn("failed to get join rule")
return false
return false, []string{}
}
if rule == spec.Public || rule == spec.Knock {
return true
return true, []string{}
}
if rule == spec.Restricted {
@ -258,6 +263,10 @@ func authorisedServer(ctx context.Context, querier *Queryer, roomID spec.RoomID,
}
// check if server is joined to any allowed room
resultAllowedRoomIDs := make([]string, 0, len(allowJoinedToRoomIDs))
for _, allowedRoomID := range allowJoinedToRoomIDs {
resultAllowedRoomIDs = append(resultAllowedRoomIDs, allowedRoomID.String())
}
for _, allowedRoomID := range allowJoinedToRoomIDs {
var queryRes fs.QueryJoinedHostServerNamesInRoomResponse
err = querier.FSAPI.QueryJoinedHostServerNamesInRoom(ctx, &fs.QueryJoinedHostServerNamesInRoomRequest{
@ -269,18 +278,18 @@ func authorisedServer(ctx context.Context, querier *Queryer, roomID spec.RoomID,
}
for _, srv := range queryRes.ServerNames {
if srv == callerServerName {
return true
return true, resultAllowedRoomIDs[1:]
}
}
}
return false
return false, resultAllowedRoomIDs[1:]
}
// authorisedUser returns true iff the user is invited/joined this room or the room is world_readable
// or if the room has a public or knock join rule.
// Failing that, if the room has a restricted join rule and belongs to the space parent listed, it will return true.
func authorisedUser(ctx context.Context, querier *Queryer, clientCaller *userapi.Device, roomID spec.RoomID, parentRoomID *spec.RoomID) (authed bool, isJoinedOrInvited bool) {
func authorisedUser(ctx context.Context, querier *Queryer, clientCaller *userapi.Device, roomID spec.RoomID, parentRoomID *spec.RoomID) (authed bool, isJoinedOrInvited bool, resultAllowedRoomIDs []string) {
hisVisTuple := gomatrixserverlib.StateKeyTuple{
EventType: spec.MRoomHistoryVisibility,
StateKey: "",
@ -302,20 +311,20 @@ func authorisedUser(ctx context.Context, querier *Queryer, clientCaller *userapi
}, &queryRes)
if err != nil {
util.GetLogger(ctx).WithError(err).Error("failed to QueryCurrentState")
return false, false
return false, false, resultAllowedRoomIDs
}
memberEv := queryRes.StateEvents[roomMemberTuple]
if memberEv != nil {
membership, _ := memberEv.Membership()
if membership == spec.Join || membership == spec.Invite {
return true, true
return true, true, resultAllowedRoomIDs
}
}
hisVisEv := queryRes.StateEvents[hisVisTuple]
if hisVisEv != nil {
hisVis, _ := hisVisEv.HistoryVisibility()
if hisVis == "world_readable" {
return true, false
return true, false, resultAllowedRoomIDs
}
}
joinRuleEv := queryRes.StateEvents[joinRuleTuple]
@ -330,6 +339,7 @@ func authorisedUser(ctx context.Context, querier *Queryer, clientCaller *userapi
allowedRoomIDs := restrictedJoinRuleAllowedRooms(ctx, joinRuleEv)
// check parent is in the allowed set
for _, a := range allowedRoomIDs {
resultAllowedRoomIDs = append(resultAllowedRoomIDs, a.String())
if *parentRoomID == a {
allowed = true
break
@ -352,13 +362,13 @@ func authorisedUser(ctx context.Context, querier *Queryer, clientCaller *userapi
if memberEv != nil {
membership, _ := memberEv.Membership()
if membership == spec.Join {
return true, false
return true, false, resultAllowedRoomIDs
}
}
}
}
}
return false, false
return false, false, resultAllowedRoomIDs
}
// helper function to fetch a state event