aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNeil Alexander <neilalexander@users.noreply.github.com>2022-05-25 10:05:30 +0100
committerGitHub <noreply@github.com>2022-05-25 10:05:30 +0100
commit81843e8836e6f8f334c7b5fd1433c427c10a9443 (patch)
treeda86bc862d46103b955431961df95fab90c199b6
parentd621dd2986fa0b8cce9d164a7249456d0be47c81 (diff)
Restricted join support on `/make_join`, `/send_join` (#2478)
* Add `QueryRestrictedJoinAllowed` * Add `Resident` flag to `QueryRestrictedJoinAllowedResponse` * Check restricted joins on federation API * Return `Restricted` to determine if the room was restricted or not * Populate `AuthorisedVia` properly * Sign the event on `/send_join`, return it in the `/send_join` response in the `"event"` key * Kick back joins with invalid authorising user IDs, use event from `"event"` key if returned in `RespSendJoin` * Use invite helper in `QueryRestrictedJoinAllowed` * Only use users with the power to invite, change error bubbling a bit * Placate the almighty linter One day I will nuke `gocyclo` from orbit and everything in the world will be much better for it. * Review comments
-rw-r--r--clientapi/jsonerror/jsonerror.go6
-rw-r--r--federationapi/internal/perform.go30
-rw-r--r--federationapi/routing/join.go122
-rw-r--r--roomserver/api/api.go1
-rw-r--r--roomserver/api/api_trace.go10
-rw-r--r--roomserver/api/query.go20
-rw-r--r--roomserver/internal/perform/perform_join.go34
-rw-r--r--roomserver/internal/query/query.go126
-rw-r--r--roomserver/inthttp/client.go11
-rw-r--r--roomserver/inthttp/server.go13
10 files changed, 369 insertions, 4 deletions
diff --git a/clientapi/jsonerror/jsonerror.go b/clientapi/jsonerror/jsonerror.go
index 1fc1c0c0..70bac61d 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/internal/perform.go b/federationapi/internal/perform.go
index c176a6ea..970a6465 100644
--- a/federationapi/internal/perform.go
+++ b/federationapi/internal/perform.go
@@ -210,10 +210,18 @@ func (r *FederationInternalAPI) performJoinUsingServer(
}
r.statistics.ForServer(serverName).Success()
- authEvents := respSendJoin.AuthEvents.UntrustedEvents(respMakeJoin.RoomVersion)
+ // If the remote server returned an event in the "event" key of
+ // the send_join request then we should use that instead. It may
+ // contain signatures that we don't know about.
+ if respSendJoin.Event != nil && isWellFormedMembershipEvent(
+ respSendJoin.Event, roomID, userID, r.cfg.Matrix.ServerName,
+ ) {
+ event = respSendJoin.Event
+ }
// Sanity-check the join response to ensure that it has a create
// event, that the room version is known, etc.
+ authEvents := respSendJoin.AuthEvents.UntrustedEvents(respMakeJoin.RoomVersion)
if err = sanityCheckAuthChain(authEvents); err != nil {
return fmt.Errorf("sanityCheckAuthChain: %w", err)
}
@@ -271,6 +279,26 @@ func (r *FederationInternalAPI) performJoinUsingServer(
return nil
}
+// isWellFormedMembershipEvent returns true if the event looks like a legitimate
+// membership event.
+func isWellFormedMembershipEvent(event *gomatrixserverlib.Event, roomID, userID string, origin gomatrixserverlib.ServerName) bool {
+ if membership, err := event.Membership(); err != nil {
+ return false
+ } else if membership != gomatrixserverlib.Join {
+ return false
+ }
+ if event.RoomID() != roomID {
+ return false
+ }
+ if event.Origin() != origin {
+ return false
+ }
+ if !event.StateKeyEquals(userID) {
+ return false
+ }
+ return true
+}
+
// PerformOutboundPeekRequest implements api.FederationInternalAPI
func (r *FederationInternalAPI) PerformOutboundPeek(
ctx context.Context,
diff --git a/federationapi/routing/join.go b/federationapi/routing/join.go
index 76769972..9f8d9410 100644
--- a/federationapi/routing/join.go
+++ b/federationapi/routing/join.go
@@ -15,6 +15,7 @@
package routing
import (
+ "encoding/json"
"fmt"
"net/http"
"sort"
@@ -103,6 +104,16 @@ func MakeJoin(
}
}
+ // Check if the restricted join is allowed. If the room doesn't
+ // support restricted joins then this is effectively a no-op.
+ res, authorisedVia, err := checkRestrictedJoin(httpReq, rsAPI, verRes.RoomVersion, roomID, userID)
+ if err != 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,
@@ -110,8 +121,11 @@ func MakeJoin(
Type: "m.room.member",
StateKey: &userID,
}
- err = builder.SetContent(map[string]interface{}{"membership": gomatrixserverlib.Join})
- if err != nil {
+ content := gomatrixserverlib.MemberContent{
+ Membership: gomatrixserverlib.Join,
+ AuthorisedVia: authorisedVia,
+ }
+ if err = builder.SetContent(content); err != nil {
util.GetLogger(httpReq.Context()).WithError(err).Error("builder.SetContent failed")
return jsonerror.InternalServerError()
}
@@ -161,6 +175,7 @@ func MakeJoin(
// SendJoin implements the /send_join API
// The make-join send-join dance makes much more sense as a single
// flow so the cyclomatic complexity is high:
+// nolint:gocyclo
func SendJoin(
httpReq *http.Request,
request *gomatrixserverlib.FederationRequest,
@@ -314,6 +329,40 @@ func SendJoin(
}
}
+ // If the membership content contains a user ID for a server that is not
+ // ours then we should kick it back.
+ var memberContent gomatrixserverlib.MemberContent
+ if err := json.Unmarshal(event.Content(), &memberContent); err != nil {
+ return util.JSONResponse{
+ Code: http.StatusBadRequest,
+ JSON: jsonerror.BadJSON(err.Error()),
+ }
+ }
+ if memberContent.AuthorisedVia != "" {
+ _, domain, err := gomatrixserverlib.SplitID('@', memberContent.AuthorisedVia)
+ if err != nil {
+ return util.JSONResponse{
+ Code: http.StatusBadRequest,
+ JSON: jsonerror.BadJSON(fmt.Sprintf("The authorising username %q is invalid.", memberContent.AuthorisedVia)),
+ }
+ }
+ if domain != cfg.Matrix.ServerName {
+ return util.JSONResponse{
+ Code: http.StatusBadRequest,
+ JSON: jsonerror.BadJSON(fmt.Sprintf("The authorising username %q does not belong to this server.", memberContent.AuthorisedVia)),
+ }
+ }
+ }
+
+ // Sign the membership event. This is required for restricted joins to work
+ // in the case that the authorised via user is one of our own users. It also
+ // doesn't hurt to do it even if it isn't a restricted join.
+ signed := event.Sign(
+ string(cfg.Matrix.ServerName),
+ cfg.Matrix.KeyID,
+ cfg.Matrix.PrivateKey,
+ )
+
// Send the events to the room server.
// We are responsible for notifying other servers that the user has joined
// the room, so set SendAsServer to cfg.Matrix.ServerName
@@ -323,7 +372,7 @@ func SendJoin(
InputRoomEvents: []api.InputRoomEvent{
{
Kind: api.KindNew,
- Event: event.Headered(stateAndAuthChainResponse.RoomVersion),
+ Event: signed.Headered(stateAndAuthChainResponse.RoomVersion),
SendAsServer: string(cfg.Matrix.ServerName),
TransactionID: nil,
},
@@ -354,10 +403,77 @@ func SendJoin(
StateEvents: gomatrixserverlib.NewEventJSONsFromHeaderedEvents(stateAndAuthChainResponse.StateEvents),
AuthEvents: gomatrixserverlib.NewEventJSONsFromHeaderedEvents(stateAndAuthChainResponse.AuthChainEvents),
Origin: cfg.Matrix.ServerName,
+ Event: &signed,
},
}
}
+// checkRestrictedJoin finds out whether or not we can assist in processing
+// a restricted room join. If the room version does not support restricted
+// joins then this function returns with no side effects. This returns three
+// values:
+// * an optional JSON response body (i.e. M_UNABLE_TO_AUTHORISE_JOIN) which
+// should always be sent back to the client if one is specified
+// * a user ID of an authorising user, typically a user that has power to
+// issue invites in the room, if one has been found
+// * an error if there was a problem finding out if this was allowable,
+// like if the room version isn't known or a problem happened talking to
+// the roomserver
+func checkRestrictedJoin(
+ httpReq *http.Request,
+ rsAPI api.FederationRoomserverAPI,
+ roomVersion gomatrixserverlib.RoomVersion,
+ roomID, userID string,
+) (*util.JSONResponse, string, 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.Restricted:
+ // The join rules for the room don't restrict membership.
+ return nil, "", nil
+
+ case !res.Resident:
+ // The join rules restrict membership but our server isn't currently
+ // joined to all of the allowed rooms, so we can't actually decide
+ // whether or not to allow the user to join. This error code should
+ // tell the joining server to try joining via another resident server
+ // instead.
+ return &util.JSONResponse{
+ Code: http.StatusBadRequest,
+ JSON: jsonerror.UnableToAuthoriseJoin("This server cannot authorise the join."),
+ }, "", nil
+
+ case !res.Allowed:
+ // The join rules restrict membership, our server is in the relevant
+ // rooms and the user wasn't joined to join any of the allowed rooms
+ // and therefore can't join this room.
+ return &util.JSONResponse{
+ Code: http.StatusForbidden,
+ JSON: jsonerror.Forbidden("You are not joined to any matching rooms."),
+ }, "", nil
+
+ default:
+ // The join rules restrict membership, our server is in the relevant
+ // rooms and the user was allowed to join because they belong to one
+ // of the allowed rooms. We now need to pick one of our own local users
+ // from within the room to use as the authorising user ID, so that it
+ // can be referred to from within the membership content.
+ return nil, res.AuthorisedVia, nil
+ }
+}
+
type eventsByDepth []*gomatrixserverlib.HeaderedEvent
func (e eventsByDepth) Len() int {
diff --git a/roomserver/api/api.go b/roomserver/api/api.go
index 80e7aed6..f87ff296 100644
--- a/roomserver/api/api.go
+++ b/roomserver/api/api.go
@@ -184,6 +184,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.
diff --git a/roomserver/api/api_trace.go b/roomserver/api/api_trace.go
index 71132464..92c5c1b1 100644
--- a/roomserver/api/api_trace.go
+++ b/roomserver/api/api_trace.go
@@ -354,6 +354,16 @@ func (t *RoomserverInternalAPITrace) QueryAuthChain(
return err
}
+func (t *RoomserverInternalAPITrace) QueryRestrictedJoinAllowed(
+ ctx context.Context,
+ request *QueryRestrictedJoinAllowedRequest,
+ response *QueryRestrictedJoinAllowedResponse,
+) error {
+ err := t.Impl.QueryRestrictedJoinAllowed(ctx, request, response)
+ util.GetLogger(ctx).WithError(err).Infof("QueryRestrictedJoinAllowed req=%+v res=%+v", js(request), js(response))
+ return err
+}
+
func js(thing interface{}) string {
b, err := json.Marshal(thing)
if err != nil {
diff --git a/roomserver/api/query.go b/roomserver/api/query.go
index afafb87c..f157a902 100644
--- a/roomserver/api/query.go
+++ b/roomserver/api/query.go
@@ -348,6 +348,26 @@ type QueryServerBannedFromRoomResponse struct {
Banned bool `json:"banned"`
}
+type QueryRestrictedJoinAllowedRequest struct {
+ UserID string `json:"user_id"`
+ RoomID string `json:"room_id"`
+}
+
+type QueryRestrictedJoinAllowedResponse struct {
+ // True if the room membership is restricted by the join rule being set to "restricted"
+ Restricted bool `json:"restricted"`
+ // True if our local server is joined to all of the allowed rooms specified in the "allow"
+ // key of the join rule, false if we are missing from some of them and therefore can't
+ // reliably decide whether or not we can satisfy the join
+ Resident bool `json:"resident"`
+ // True if the restricted join is allowed because we found the membership in one of the
+ // allowed rooms from the join rule, false if not
+ Allowed bool `json:"allowed"`
+ // Contains the user ID of the selected user ID that has power to issue invites, this will
+ // get populated into the "join_authorised_via_users_server" content in the membership
+ AuthorisedVia string `json:"authorised_via,omitempty"`
+}
+
// MarshalJSON stringifies the room ID and StateKeyTuple keys so they can be sent over the wire in HTTP API mode.
func (r *QueryBulkStateContentResponse) MarshalJSON() ([]byte, error) {
se := make(map[string]string)
diff --git a/roomserver/internal/perform/perform_join.go b/roomserver/internal/perform/perform_join.go
index 61a0206e..c9e83919 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"
@@ -160,6 +161,7 @@ func (r *Joiner) performJoinRoomByAlias(
}
// TODO: Break this function up a bit
+// nolint:gocyclo
func (r *Joiner) performJoinRoomByID(
ctx context.Context,
req *rsAPI.PerformJoinRequest,
@@ -210,6 +212,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 +357,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 d25bdc37..70613baa 100644
--- a/roomserver/internal/query/query.go
+++ b/roomserver/internal/query/query.go
@@ -16,6 +16,7 @@ package query
import (
"context"
+ "encoding/json"
"errors"
"fmt"
@@ -757,3 +758,128 @@ func (r *Queryer) QueryAuthChain(ctx context.Context, req *api.QueryAuthChainReq
res.AuthChain = hchain
return nil
}
+
+// nolint:gocyclo
+func (r *Queryer) QueryRestrictedJoinAllowed(ctx context.Context, req *api.QueryRestrictedJoinAllowedRequest, res *api.QueryRestrictedJoinAllowedResponse) error {
+ // Look up if we know anything about the room. If it doesn't exist
+ // or is a stub entry then we can't do anything.
+ roomInfo, err := r.DB.RoomInfo(ctx, req.RoomID)
+ if err != nil {
+ return fmt.Errorf("r.DB.RoomInfo: %w", err)
+ }
+ if roomInfo == nil || roomInfo.IsStub {
+ 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.
+ allowRestrictedJoins, err := roomInfo.RoomVersion.AllowRestrictedJoinsInEventAuth()
+ if err != nil {
+ return fmt.Errorf("roomInfo.RoomVersion.AllowRestrictedJoinsInEventAuth: %w", err)
+ } else if !allowRestrictedJoins {
+ return nil
+ }
+ // Get the join rules to work out if the join rule is "restricted".
+ joinRulesEvent, err := r.DB.GetStateEvent(ctx, req.RoomID, gomatrixserverlib.MRoomJoinRules, "")
+ if err != nil {
+ return fmt.Errorf("r.DB.GetStateEvent: %w", err)
+ }
+ var joinRules gomatrixserverlib.JoinRuleContent
+ if err = json.Unmarshal(joinRulesEvent.Content(), &joinRules); err != nil {
+ return fmt.Errorf("json.Unmarshal: %w", err)
+ }
+ // If the join rule isn't "restricted" then there's nothing more to do.
+ res.Restricted = joinRules.JoinRule == gomatrixserverlib.Restricted
+ if !res.Restricted {
+ return nil
+ }
+ // Start off by populating the "resident" flag in the response. If we
+ // come across any rooms in the request that are missing, we will unset
+ // the flag.
+ res.Resident = true
+ // If the user is already invited to the room then the join is allowed
+ // but we don't specify an authorised via user, since the event auth
+ // will allow the join anyway.
+ var pending bool
+ if pending, _, _, err = helpers.IsInvitePending(ctx, r.DB, req.RoomID, req.UserID); err != nil {
+ return fmt.Errorf("helpers.IsInvitePending: %w", err)
+ } else if pending {
+ 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.
+ 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
+ // time, so skip any rule that doesn't match those.
+ if rule.Type != gomatrixserverlib.MRoomMembership {
+ continue
+ }
+ // See if the room exists. If it doesn't exist or if it's a stub
+ // room entry then we can't check memberships.
+ targetRoomInfo, err := r.DB.RoomInfo(ctx, rule.RoomID)
+ if err != nil || targetRoomInfo == nil || targetRoomInfo.IsStub {
+ res.Resident = false
+ continue
+ }
+ // First of all work out if *we* are still in the room, otherwise
+ // it's possible that the memberships will be out of date.
+ isIn, err := r.DB.GetLocalServerInRoom(ctx, targetRoomInfo.RoomNID)
+ if err != nil || !isIn {
+ // If we aren't in the room, we can no longer tell if the room
+ // memberships are up-to-date.
+ res.Resident = false
+ continue
+ }
+ // At this point we're happy that we are in the room, so now let's
+ // see if the target user is in the room.
+ _, isIn, _, err = r.DB.GetMembership(ctx, targetRoomInfo.RoomNID, req.UserID)
+ if err != nil {
+ continue
+ }
+ // If the user is not in the room then we will skip them.
+ if !isIn {
+ continue
+ }
+ // The user is in the room, so now we will need to authorise the
+ // join using the user ID of one of our own users in the room. Pick
+ // one.
+ joinNIDs, err := r.DB.GetMembershipEventNIDsForRoom(ctx, targetRoomInfo.RoomNID, true, true)
+ if err != nil || len(joinNIDs) == 0 {
+ // There should always be more than one join NID at this point
+ // because we are gated behind GetLocalServerInRoom, but y'know,
+ // sometimes strange things happen.
+ continue
+ }
+ // For each of the joined users, let's see if we can get a valid
+ // membership event.
+ for _, joinNID := range joinNIDs {
+ events, err := r.DB.Events(ctx, []types.EventNID{joinNID})
+ if err != nil || len(events) != 1 {
+ continue
+ }
+ event := events[0]
+ 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()
+ return nil
+ }
+ }
+ return nil
+}
diff --git a/roomserver/inthttp/client.go b/roomserver/inthttp/client.go
index 09358001..7b10ae65 100644
--- a/roomserver/inthttp/client.go
+++ b/roomserver/inthttp/client.go
@@ -61,6 +61,7 @@ const (
RoomserverQueryKnownUsersPath = "/roomserver/queryKnownUsers"
RoomserverQueryServerBannedFromRoomPath = "/roomserver/queryServerBannedFromRoom"
RoomserverQueryAuthChainPath = "/roomserver/queryAuthChain"
+ RoomserverQueryRestrictedJoinAllowed = "/roomserver/queryRestrictedJoinAllowed"
)
type httpRoomserverInternalAPI struct {
@@ -557,6 +558,16 @@ func (h *httpRoomserverInternalAPI) QueryServerBannedFromRoom(
return httputil.PostJSON(ctx, span, h.httpClient, apiURL, req, res)
}
+func (h *httpRoomserverInternalAPI) QueryRestrictedJoinAllowed(
+ ctx context.Context, req *api.QueryRestrictedJoinAllowedRequest, res *api.QueryRestrictedJoinAllowedResponse,
+) error {
+ span, ctx := opentracing.StartSpanFromContext(ctx, "QueryRestrictedJoinAllowed")
+ defer span.Finish()
+
+ apiURL := h.roomserverURL + RoomserverQueryRestrictedJoinAllowed
+ return httputil.PostJSON(ctx, span, h.httpClient, apiURL, req, res)
+}
+
func (h *httpRoomserverInternalAPI) PerformForget(ctx context.Context, req *api.PerformForgetRequest, res *api.PerformForgetResponse) error {
span, ctx := opentracing.StartSpanFromContext(ctx, "PerformForget")
defer span.Finish()
diff --git a/roomserver/inthttp/server.go b/roomserver/inthttp/server.go
index 9042e341..ad4fdc46 100644
--- a/roomserver/inthttp/server.go
+++ b/roomserver/inthttp/server.go
@@ -472,4 +472,17 @@ func AddRoutes(r api.RoomserverInternalAPI, internalAPIMux *mux.Router) {
return util.JSONResponse{Code: http.StatusOK, JSON: &response}
}),
)
+ internalAPIMux.Handle(RoomserverQueryRestrictedJoinAllowed,
+ httputil.MakeInternalAPI("queryRestrictedJoinAllowed", func(req *http.Request) util.JSONResponse {
+ request := api.QueryRestrictedJoinAllowedRequest{}
+ response := api.QueryRestrictedJoinAllowedResponse{}
+ if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
+ return util.MessageResponse(http.StatusBadRequest, err.Error())
+ }
+ if err := r.QueryRestrictedJoinAllowed(req.Context(), &request, &response); err != nil {
+ return util.ErrorResponse(err)
+ }
+ return util.JSONResponse{Code: http.StatusOK, JSON: &response}
+ }),
+ )
}