From 553814f810e9fc1a962bb7057b797744b0a733de Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Tue, 24 May 2022 16:45:51 +0100 Subject: [PATCH] Only use users with the power to invite, change error bubbling a bit --- roomserver/internal/perform/perform_join.go | 33 +++++++++++++++++++++ roomserver/internal/query/query.go | 18 ++++++++++- 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/roomserver/internal/perform/perform_join.go b/roomserver/internal/perform/perform_join.go index 61a0206ef..55f65c432 100644 --- a/roomserver/internal/perform/perform_join.go +++ b/roomserver/internal/perform/perform_join.go @@ -24,6 +24,7 @@ import ( "github.com/getsentry/sentry-go" fsAPI "github.com/matrix-org/dendrite/federationapi/api" "github.com/matrix-org/dendrite/internal/eventutil" + "github.com/matrix-org/dendrite/roomserver/api" rsAPI "github.com/matrix-org/dendrite/roomserver/api" "github.com/matrix-org/dendrite/roomserver/internal/helpers" "github.com/matrix-org/dendrite/roomserver/internal/input" @@ -210,6 +211,11 @@ func (r *Joiner) performJoinRoomByID( req.Content = map[string]interface{}{} } req.Content["membership"] = gomatrixserverlib.Join + if authorisedVia, aerr := r.populateAuthorisedViaUserForRestrictedJoin(ctx, req); aerr != nil { + return "", "", aerr + } else if authorisedVia != "" { + req.Content["join_authorised_via_users_server"] = authorisedVia + } if err = eb.SetContent(req.Content); err != nil { return "", "", fmt.Errorf("eb.SetContent: %w", err) } @@ -350,6 +356,33 @@ func (r *Joiner) performFederatedJoinRoomByID( return fedRes.JoinedVia, nil } +func (r *Joiner) populateAuthorisedViaUserForRestrictedJoin( + ctx context.Context, + joinReq *rsAPI.PerformJoinRequest, +) (string, error) { + req := &api.QueryRestrictedJoinAllowedRequest{ + UserID: joinReq.UserID, + RoomID: joinReq.RoomIDOrAlias, + } + res := &api.QueryRestrictedJoinAllowedResponse{} + if err := r.Queryer.QueryRestrictedJoinAllowed(ctx, req, res); err != nil { + return "", fmt.Errorf("r.Queryer.QueryRestrictedJoinAllowed: %w", err) + } + if !res.Restricted { + return "", nil + } + if !res.Resident { + return "", nil + } + if !res.Allowed { + return "", &rsAPI.PerformError{ + Code: rsAPI.PerformErrorNotAllowed, + Msg: fmt.Sprintf("The join to room %s was not allowed.", joinReq.RoomIDOrAlias), + } + } + return res.AuthorisedVia, nil +} + func buildEvent( ctx context.Context, db storage.Database, cfg *config.Global, builder *gomatrixserverlib.EventBuilder, ) (*gomatrixserverlib.HeaderedEvent, *rsAPI.QueryLatestEventsAndStateResponse, error) { diff --git a/roomserver/internal/query/query.go b/roomserver/internal/query/query.go index 4a964528b..1e321d016 100644 --- a/roomserver/internal/query/query.go +++ b/roomserver/internal/query/query.go @@ -768,7 +768,7 @@ func (r *Queryer) QueryRestrictedJoinAllowed(ctx context.Context, req *api.Query return fmt.Errorf("r.DB.RoomInfo: %w", err) } if roomInfo == nil || roomInfo.IsStub { - return fmt.Errorf("room %q doesn't exist or is stub room", req.RoomID) + return nil // fmt.Errorf("room %q doesn't exist or is stub room", req.RoomID) } // If the room version doesn't allow restricted joins then don't // try to process any further. @@ -805,6 +805,18 @@ func (r *Queryer) QueryRestrictedJoinAllowed(ctx context.Context, req *api.Query res.Allowed = true return nil } + // We need to get the power levels content so that we can determine which + // users in the room are entitled to issue invites. We need to use one of + // these users as the authorising user. + // Get the join rules to work out if the join rule is "restricted". + powerLevelsEvent, err := r.DB.GetStateEvent(ctx, req.RoomID, gomatrixserverlib.MRoomPowerLevels, "") + if err != nil { + return fmt.Errorf("r.DB.GetStateEvent: %w", err) + } + var powerLevels gomatrixserverlib.PowerLevelContent + if err = json.Unmarshal(powerLevelsEvent.Content(), &powerLevels); err != nil { + return fmt.Errorf("json.Unmarshal: %w", err) + } // Step through the join rules and see if the user matches any of them. for _, rule := range joinRules.Allow { // We only understand "m.room_membership" rules at this point in @@ -859,6 +871,10 @@ func (r *Queryer) QueryRestrictedJoinAllowed(ctx context.Context, req *api.Query if event.Type() != gomatrixserverlib.MRoomMember || event.StateKey() == nil { continue // shouldn't happen } + // Only users that have the power to invite should be chosen. + if powerLevels.UserLevel(*event.StateKey()) < powerLevels.Invite { + continue + } res.Resident = true res.Allowed = true res.AuthorisedVia = *event.StateKey()