diff --git a/clientapi/jsonerror/jsonerror.go b/clientapi/jsonerror/jsonerror.go index 1fc1c0c01..70bac61dc 100644 --- a/clientapi/jsonerror/jsonerror.go +++ b/clientapi/jsonerror/jsonerror.go @@ -154,6 +154,12 @@ func MissingParam(msg string) *MatrixError { return &MatrixError{"M_MISSING_PARAM", msg} } +// UnableToAuthoriseJoin is an error that is returned when a server can't +// determine whether to allow a restricted join or not. +func UnableToAuthoriseJoin(msg string) *MatrixError { + return &MatrixError{"M_UNABLE_TO_AUTHORISE_JOIN", msg} +} + // LeaveServerNoticeError is an error returned when trying to reject an invite // for a server notice room. func LeaveServerNoticeError() *MatrixError { diff --git a/federationapi/routing/join.go b/federationapi/routing/join.go index 767699728..68ea1e8ac 100644 --- a/federationapi/routing/join.go +++ b/federationapi/routing/join.go @@ -103,6 +103,15 @@ func MakeJoin( } } + // Check if the restricted join is allowed. If the room doesn't + // support restricted joins then this is effectively a no-op. + if res, rerr := checkRestrictedJoin(httpReq, rsAPI, verRes.RoomVersion, roomID, userID); rerr != nil { + util.GetLogger(httpReq.Context()).WithError(err).Error("checkRestrictedJoin failed") + return jsonerror.InternalServerError() + } else if res != nil { + return *res + } + // Try building an event for the server builder := gomatrixserverlib.EventBuilder{ Sender: userID, @@ -358,6 +367,41 @@ func SendJoin( } } +func checkRestrictedJoin( + httpReq *http.Request, + rsAPI api.FederationRoomserverAPI, + roomVersion gomatrixserverlib.RoomVersion, + roomID, userID string, +) (*util.JSONResponse, error) { + if allowRestricted, err := roomVersion.AllowRestrictedJoinsInEventAuth(); err != nil { + return nil, err + } else if !allowRestricted { + return nil, nil + } + req := &api.QueryRestrictedJoinAllowedRequest{ + RoomID: roomID, + UserID: userID, + } + res := &api.QueryRestrictedJoinAllowedResponse{} + if err := rsAPI.QueryRestrictedJoinAllowed(httpReq.Context(), req, res); err != nil { + return nil, err + } + switch { + case !res.Resident: + return &util.JSONResponse{ + Code: http.StatusBadRequest, + JSON: jsonerror.UnableToAuthoriseJoin("This server cannot authorise the join."), + }, nil + case !res.Allowed: + return &util.JSONResponse{ + Code: http.StatusForbidden, + JSON: jsonerror.Forbidden("You are not joined to any matching rooms."), + }, nil + default: + return nil, nil + } +} + type eventsByDepth []*gomatrixserverlib.HeaderedEvent func (e eventsByDepth) Len() int { diff --git a/roomserver/api/api.go b/roomserver/api/api.go index 6d28a79e2..01479bec8 100644 --- a/roomserver/api/api.go +++ b/roomserver/api/api.go @@ -185,6 +185,7 @@ type FederationRoomserverAPI interface { // Query whether a server is allowed to see an event QueryServerAllowedToSeeEvent(ctx context.Context, req *QueryServerAllowedToSeeEventRequest, res *QueryServerAllowedToSeeEventResponse) error QueryRoomsForUser(ctx context.Context, req *QueryRoomsForUserRequest, res *QueryRoomsForUserResponse) error + QueryRestrictedJoinAllowed(ctx context.Context, req *QueryRestrictedJoinAllowedRequest, res *QueryRestrictedJoinAllowedResponse) error PerformInboundPeek(ctx context.Context, req *PerformInboundPeekRequest, res *PerformInboundPeekResponse) error PerformInvite(ctx context.Context, req *PerformInviteRequest, res *PerformInviteResponse) error // Query a given amount (or less) of events prior to a given set of events.