/hierarchy - return public and knockable rooms for authed users (#2578)

When requesting the room hierarchy with an authenticated user, return public and knockable rooms.

According to the spec, https://github.com/matrix-org/matrix-spec-proposals/blob/main/proposals/2946-spaces-summary.md

```
Any child room that the user is joined or is potentially joinable is included in the response.
```

This is currently not the case. See discussion here: https://matrix.to/#/!NasysSDfxKxZBzJJoE:matrix.org/$t2Csj-6y1PVsn8GOnFZfXzeQW13NfqvrFCxB-XI_uhA?via=matrix.org&via=libera.chat&via=element.io and here: https://matrix.to/#/!NasysSDfxKxZBzJJoE:matrix.org/$EHp1x1DY7tnYZtx_PVEb-sKB9lmJajqHx2uGlhrRh6k?via=matrix.org&via=libera.chat&via=element.io

Test Plan:
create and register clients bob and alice
have bob create a public space
have bob create a public room parented to the space
have alice join the space(room)
have alice sync the space
expect alice to see two rooms in the space hierarchy, the space and the child room

Co-authored-by: Neil Alexander <neilalexander@users.noreply.github.com>
This commit is contained in:
texuf 2022-08-12 06:07:45 -07:00 committed by GitHub
parent 6d0d7a0bc3
commit e55cd6ea78
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -479,7 +479,7 @@ func (w *walker) authorised(roomID, parentRoomID string) (authed, isJoinedOrInvi
return w.authorisedServer(roomID), false return w.authorisedServer(roomID), false
} }
// authorisedServer returns true iff the server is joined this room or the room is world_readable // authorisedServer returns true iff the server is joined this room or the room is world_readable, public, or knockable
func (w *walker) authorisedServer(roomID string) bool { func (w *walker) authorisedServer(roomID string) bool {
// Check history visibility / join rules first // Check history visibility / join rules first
hisVisTuple := gomatrixserverlib.StateKeyTuple{ hisVisTuple := gomatrixserverlib.StateKeyTuple{
@ -513,9 +513,22 @@ func (w *walker) authorisedServer(roomID string) bool {
// in addition to the actual room ID (but always do the actual one first as it's quicker in the common case) // in addition to the actual room ID (but always do the actual one first as it's quicker in the common case)
allowJoinedToRoomIDs := []string{roomID} allowJoinedToRoomIDs := []string{roomID}
joinRuleEv := queryRoomRes.StateEvents[joinRuleTuple] joinRuleEv := queryRoomRes.StateEvents[joinRuleTuple]
if joinRuleEv != nil { if joinRuleEv != nil {
rule, ruleErr := joinRuleEv.JoinRule()
if ruleErr != nil {
util.GetLogger(w.ctx).WithError(ruleErr).WithField("parent_room_id", roomID).Warn("failed to get join rule")
return false
}
if rule == gomatrixserverlib.Public || rule == gomatrixserverlib.Knock {
return true
}
if rule == gomatrixserverlib.Restricted {
allowJoinedToRoomIDs = append(allowJoinedToRoomIDs, w.restrictedJoinRuleAllowedRooms(joinRuleEv, "m.room_membership")...) allowJoinedToRoomIDs = append(allowJoinedToRoomIDs, w.restrictedJoinRuleAllowedRooms(joinRuleEv, "m.room_membership")...)
} }
}
// check if server is joined to any allowed room // check if server is joined to any allowed room
for _, allowedRoomID := range allowJoinedToRoomIDs { for _, allowedRoomID := range allowJoinedToRoomIDs {
@ -537,7 +550,8 @@ func (w *walker) authorisedServer(roomID string) bool {
return false return false
} }
// authorisedUser returns true iff the user is invited/joined this room or the room is world_readable. // 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. // Failing that, if the room has a restricted join rule and belongs to the space parent listed, it will return true.
func (w *walker) authorisedUser(roomID, parentRoomID string) (authed bool, isJoinedOrInvited bool) { func (w *walker) authorisedUser(roomID, parentRoomID string) (authed bool, isJoinedOrInvited bool) {
hisVisTuple := gomatrixserverlib.StateKeyTuple{ hisVisTuple := gomatrixserverlib.StateKeyTuple{
@ -579,15 +593,22 @@ func (w *walker) authorisedUser(roomID, parentRoomID string) (authed bool, isJoi
} }
joinRuleEv := queryRes.StateEvents[joinRuleTuple] joinRuleEv := queryRes.StateEvents[joinRuleTuple]
if parentRoomID != "" && joinRuleEv != nil { if parentRoomID != "" && joinRuleEv != nil {
var allowed bool
rule, ruleErr := joinRuleEv.JoinRule()
if ruleErr != nil {
util.GetLogger(w.ctx).WithError(ruleErr).WithField("parent_room_id", parentRoomID).Warn("failed to get join rule")
} else if rule == gomatrixserverlib.Public || rule == gomatrixserverlib.Knock {
allowed = true
} else if rule == gomatrixserverlib.Restricted {
allowedRoomIDs := w.restrictedJoinRuleAllowedRooms(joinRuleEv, "m.room_membership") allowedRoomIDs := w.restrictedJoinRuleAllowedRooms(joinRuleEv, "m.room_membership")
// check parent is in the allowed set // check parent is in the allowed set
var allowed bool
for _, a := range allowedRoomIDs { for _, a := range allowedRoomIDs {
if parentRoomID == a { if parentRoomID == a {
allowed = true allowed = true
break break
} }
} }
}
if allowed { if allowed {
// ensure caller is joined to the parent room // ensure caller is joined to the parent room
var queryRes2 roomserver.QueryCurrentStateResponse var queryRes2 roomserver.QueryCurrentStateResponse
@ -615,7 +636,7 @@ func (w *walker) authorisedUser(roomID, parentRoomID string) (authed bool, isJoi
func (w *walker) restrictedJoinRuleAllowedRooms(joinRuleEv *gomatrixserverlib.HeaderedEvent, allowType string) (allows []string) { func (w *walker) restrictedJoinRuleAllowedRooms(joinRuleEv *gomatrixserverlib.HeaderedEvent, allowType string) (allows []string) {
rule, _ := joinRuleEv.JoinRule() rule, _ := joinRuleEv.JoinRule()
if rule != "restricted" { if rule != gomatrixserverlib.Restricted {
return nil return nil
} }
var jrContent gomatrixserverlib.JoinRuleContent var jrContent gomatrixserverlib.JoinRuleContent