aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordevonh <devon.dmytro@gmail.com>2023-05-31 16:33:49 +0000
committerGitHub <noreply@github.com>2023-05-31 16:33:49 +0000
commitea6b368ad424a3d2e05135afb7fd0c0801b3609b (patch)
tree416132c5bdc525b9ad93911a40813c0dc3fb4439
parentcbdc601f1b6d1c2a648b69ff44b3a49916f4d31a (diff)
Move Invite logic to GMSL (#3086)
This is both the federation receiving & sending side logic (which were previously entangeld in a single function)
-rw-r--r--clientapi/routing/createroom.go1
-rw-r--r--federationapi/api/api.go8
-rw-r--r--federationapi/internal/perform.go47
-rw-r--r--federationapi/routing/invite.go237
-rw-r--r--federationapi/routing/join.go21
-rw-r--r--federationapi/routing/routing.go20
-rw-r--r--go.mod2
-rw-r--r--go.sum4
-rw-r--r--roomserver/api/api.go5
-rw-r--r--roomserver/api/perform.go11
-rw-r--r--roomserver/api/query.go20
-rw-r--r--roomserver/internal/api.go29
-rw-r--r--roomserver/internal/helpers/auth.go38
-rw-r--r--roomserver/internal/perform/perform_create_room.go6
-rw-r--r--roomserver/internal/perform/perform_invite.go318
15 files changed, 342 insertions, 425 deletions
diff --git a/clientapi/routing/createroom.go b/clientapi/routing/createroom.go
index aaa305f0..799fc797 100644
--- a/clientapi/routing/createroom.go
+++ b/clientapi/routing/createroom.go
@@ -135,7 +135,6 @@ func CreateRoom(
// createRoom implements /createRoom
func createRoom(
ctx context.Context,
- // TODO: remove dependency on createRoomRequest
createRequest createRoomRequest, device *api.Device,
cfg *config.ClientAPI,
profileAPI api.ClientUserAPI, rsAPI roomserverAPI.ClientRoomserverAPI,
diff --git a/federationapi/api/api.go b/federationapi/api/api.go
index b53ec3dd..5b49e509 100644
--- a/federationapi/api/api.go
+++ b/federationapi/api/api.go
@@ -62,7 +62,7 @@ type RoomserverFederationAPI interface {
// Handle an instruction to make_leave & send_leave with a remote server.
PerformLeave(ctx context.Context, request *PerformLeaveRequest, response *PerformLeaveResponse) error
// Handle sending an invite to a remote server.
- PerformInvite(ctx context.Context, request *PerformInviteRequest, response *PerformInviteResponse) error
+ SendInvite(ctx context.Context, event gomatrixserverlib.PDU, strippedState []gomatrixserverlib.InviteStrippedState) (gomatrixserverlib.PDU, error)
// Handle an instruction to peek a room on a remote server.
PerformOutboundPeek(ctx context.Context, request *PerformOutboundPeekRequest, response *PerformOutboundPeekResponse) error
// Query the server names of the joined hosts in a room.
@@ -190,9 +190,9 @@ type PerformLeaveResponse struct {
}
type PerformInviteRequest struct {
- RoomVersion gomatrixserverlib.RoomVersion `json:"room_version"`
- Event *rstypes.HeaderedEvent `json:"event"`
- InviteRoomState []fclient.InviteV2StrippedState `json:"invite_room_state"`
+ RoomVersion gomatrixserverlib.RoomVersion `json:"room_version"`
+ Event *rstypes.HeaderedEvent `json:"event"`
+ InviteRoomState []gomatrixserverlib.InviteStrippedState `json:"invite_room_state"`
}
type PerformInviteResponse struct {
diff --git a/federationapi/internal/perform.go b/federationapi/internal/perform.go
index 99943d86..ed800d03 100644
--- a/federationapi/internal/perform.go
+++ b/federationapi/internal/perform.go
@@ -503,60 +503,59 @@ func (r *FederationInternalAPI) PerformLeave(
)
}
-// PerformLeaveRequest implements api.FederationInternalAPI
-func (r *FederationInternalAPI) PerformInvite(
+// SendInvite implements api.FederationInternalAPI
+func (r *FederationInternalAPI) SendInvite(
ctx context.Context,
- request *api.PerformInviteRequest,
- response *api.PerformInviteResponse,
-) (err error) {
- _, origin, err := r.cfg.Matrix.SplitLocalID('@', request.Event.Sender())
+ event gomatrixserverlib.PDU,
+ strippedState []gomatrixserverlib.InviteStrippedState,
+) (gomatrixserverlib.PDU, error) {
+ _, origin, err := r.cfg.Matrix.SplitLocalID('@', event.Sender())
if err != nil {
- return err
+ return nil, err
}
- if request.Event.StateKey() == nil {
- return errors.New("invite must be a state event")
+ if event.StateKey() == nil {
+ return nil, errors.New("invite must be a state event")
}
- _, destination, err := gomatrixserverlib.SplitID('@', *request.Event.StateKey())
+ _, destination, err := gomatrixserverlib.SplitID('@', *event.StateKey())
if err != nil {
- return fmt.Errorf("gomatrixserverlib.SplitID: %w", err)
+ return nil, fmt.Errorf("gomatrixserverlib.SplitID: %w", err)
}
// TODO (devon): This should be allowed via a relay. Currently only transactions
// can be sent to relays. Would need to extend relays to handle invites.
if !r.shouldAttemptDirectFederation(destination) {
- return fmt.Errorf("relay servers have no meaningful response for invite.")
+ return nil, fmt.Errorf("relay servers have no meaningful response for invite.")
}
logrus.WithFields(logrus.Fields{
- "event_id": request.Event.EventID(),
- "user_id": *request.Event.StateKey(),
- "room_id": request.Event.RoomID(),
- "room_version": request.RoomVersion,
+ "event_id": event.EventID(),
+ "user_id": *event.StateKey(),
+ "room_id": event.RoomID(),
+ "room_version": event.Version(),
"destination": destination,
}).Info("Sending invite")
- inviteReq, err := fclient.NewInviteV2Request(request.Event.PDU, request.InviteRoomState)
+ inviteReq, err := fclient.NewInviteV2Request(event, strippedState)
if err != nil {
- return fmt.Errorf("gomatrixserverlib.NewInviteV2Request: %w", err)
+ return nil, fmt.Errorf("gomatrixserverlib.NewInviteV2Request: %w", err)
}
inviteRes, err := r.federation.SendInviteV2(ctx, origin, destination, inviteReq)
if err != nil {
- return fmt.Errorf("r.federation.SendInviteV2: failed to send invite: %w", err)
+ return nil, fmt.Errorf("r.federation.SendInviteV2: failed to send invite: %w", err)
}
- verImpl, err := gomatrixserverlib.GetRoomVersion(request.RoomVersion)
+ verImpl, err := gomatrixserverlib.GetRoomVersion(event.Version())
if err != nil {
- return err
+ return nil, err
}
inviteEvent, err := verImpl.NewEventFromUntrustedJSON(inviteRes.Event)
if err != nil {
- return fmt.Errorf("r.federation.SendInviteV2 failed to decode event response: %w", err)
+ return nil, fmt.Errorf("r.federation.SendInviteV2 failed to decode event response: %w", err)
}
- response.Event = &types.HeaderedEvent{PDU: inviteEvent}
- return nil
+ return inviteEvent, nil
}
// PerformServersAlive implements api.FederationInternalAPI
diff --git a/federationapi/routing/invite.go b/federationapi/routing/invite.go
index 993d4046..78a09d94 100644
--- a/federationapi/routing/invite.go
+++ b/federationapi/routing/invite.go
@@ -20,7 +20,6 @@ import (
"fmt"
"net/http"
- "github.com/getsentry/sentry-go"
"github.com/matrix-org/dendrite/roomserver/api"
"github.com/matrix-org/dendrite/roomserver/types"
"github.com/matrix-org/dendrite/setup/config"
@@ -34,7 +33,7 @@ import (
func InviteV2(
httpReq *http.Request,
request *fclient.FederationRequest,
- roomID string,
+ roomID spec.RoomID,
eventID string,
cfg *config.FederationAPI,
rsAPI api.FederationRoomserverAPI,
@@ -56,9 +55,55 @@ func InviteV2(
JSON: spec.BadJSON(err.Error()),
}
case nil:
- return processInvite(
- httpReq.Context(), true, inviteReq.Event(), inviteReq.RoomVersion(), inviteReq.InviteRoomState(), roomID, eventID, cfg, rsAPI, keys,
- )
+ if inviteReq.Event().StateKey() == nil {
+ return util.JSONResponse{
+ Code: http.StatusBadRequest,
+ JSON: spec.BadJSON("The invite event has no state key"),
+ }
+ }
+
+ invitedUser, userErr := spec.NewUserID(*inviteReq.Event().StateKey(), true)
+ if userErr != nil {
+ return util.JSONResponse{
+ Code: http.StatusBadRequest,
+ JSON: spec.InvalidParam("The user ID is invalid"),
+ }
+ }
+ if !cfg.Matrix.IsLocalServerName(invitedUser.Domain()) {
+ return util.JSONResponse{
+ Code: http.StatusBadRequest,
+ JSON: spec.InvalidParam("The invited user domain does not belong to this server"),
+ }
+ }
+
+ if inviteReq.Event().EventID() != eventID {
+ return util.JSONResponse{
+ Code: http.StatusBadRequest,
+ JSON: spec.BadJSON("The event ID in the request path must match the event ID in the invite event JSON"),
+ }
+ }
+
+ input := gomatrixserverlib.HandleInviteInput{
+ RoomVersion: inviteReq.RoomVersion(),
+ RoomID: roomID,
+ InvitedUser: *invitedUser,
+ KeyID: cfg.Matrix.KeyID,
+ PrivateKey: cfg.Matrix.PrivateKey,
+ Verifier: keys,
+ RoomQuerier: rsAPI,
+ MembershipQuerier: &api.MembershipQuerier{Roomserver: rsAPI},
+ StateQuerier: rsAPI.StateQuerier(),
+ InviteEvent: inviteReq.Event(),
+ StrippedState: inviteReq.InviteRoomState(),
+ }
+ event, jsonErr := handleInvite(httpReq.Context(), input, rsAPI)
+ if jsonErr != nil {
+ return *jsonErr
+ }
+ return util.JSONResponse{
+ Code: http.StatusOK,
+ JSON: fclient.RespInviteV2{Event: event.JSON()},
+ }
default:
return util.JSONResponse{
Code: http.StatusBadRequest,
@@ -71,7 +116,7 @@ func InviteV2(
func InviteV1(
httpReq *http.Request,
request *fclient.FederationRequest,
- roomID string,
+ roomID spec.RoomID,
eventID string,
cfg *config.FederationAPI,
rsAPI api.FederationRoomserverAPI,
@@ -94,55 +139,11 @@ func InviteV1(
JSON: spec.NotJSON("The request body could not be decoded into an invite v1 request. " + err.Error()),
}
}
- var strippedState []fclient.InviteV2StrippedState
- if err := json.Unmarshal(event.Unsigned(), &strippedState); err != nil {
+ var strippedState []gomatrixserverlib.InviteStrippedState
+ if jsonErr := json.Unmarshal(event.Unsigned(), &strippedState); jsonErr != nil {
// just warn, they may not have added any.
util.GetLogger(httpReq.Context()).Warnf("failed to extract stripped state from invite event")
}
- return processInvite(
- httpReq.Context(), false, event, roomVer, strippedState, roomID, eventID, cfg, rsAPI, keys,
- )
-}
-
-func processInvite(
- ctx context.Context,
- isInviteV2 bool,
- event gomatrixserverlib.PDU,
- roomVer gomatrixserverlib.RoomVersion,
- strippedState []fclient.InviteV2StrippedState,
- roomID string,
- eventID string,
- cfg *config.FederationAPI,
- rsAPI api.FederationRoomserverAPI,
- keys gomatrixserverlib.JSONVerifier,
-) util.JSONResponse {
-
- // Check that we can accept invites for this room version.
- verImpl, err := gomatrixserverlib.GetRoomVersion(roomVer)
- if err != nil {
- return util.JSONResponse{
- Code: http.StatusBadRequest,
- JSON: spec.UnsupportedRoomVersion(
- fmt.Sprintf("Room version %q is not supported by this server.", roomVer),
- ),
- }
- }
-
- // Check that the room ID is correct.
- if event.RoomID() != roomID {
- return util.JSONResponse{
- Code: http.StatusBadRequest,
- JSON: spec.BadJSON("The room ID in the request path must match the room ID in the invite event JSON"),
- }
- }
-
- // Check that the event ID is correct.
- if event.EventID() != eventID {
- return util.JSONResponse{
- Code: http.StatusBadRequest,
- JSON: spec.BadJSON("The event ID in the request path must match the event ID in the invite event JSON"),
- }
- }
if event.StateKey() == nil {
return util.JSONResponse{
@@ -151,105 +152,91 @@ func processInvite(
}
}
- _, domain, err := cfg.Matrix.SplitLocalID('@', *event.StateKey())
+ invitedUser, err := spec.NewUserID(*event.StateKey(), true)
if err != nil {
return util.JSONResponse{
Code: http.StatusBadRequest,
- JSON: spec.InvalidParam(fmt.Sprintf("The user ID is invalid or domain %q does not belong to this server", domain)),
+ JSON: spec.InvalidParam("The user ID is invalid"),
}
}
-
- // Check that the event is signed by the server sending the request.
- redacted, err := verImpl.RedactEventJSON(event.JSON())
- if err != nil {
+ if !cfg.Matrix.IsLocalServerName(invitedUser.Domain()) {
return util.JSONResponse{
Code: http.StatusBadRequest,
- JSON: spec.BadJSON("The event JSON could not be redacted"),
+ JSON: spec.InvalidParam("The invited user domain does not belong to this server"),
}
}
- _, serverName, err := gomatrixserverlib.SplitID('@', event.Sender())
- if err != nil {
+
+ if event.EventID() != eventID {
return util.JSONResponse{
Code: http.StatusBadRequest,
- JSON: spec.BadJSON("The event JSON contains an invalid sender"),
+ JSON: spec.BadJSON("The event ID in the request path must match the event ID in the invite event JSON"),
}
}
- verifyRequests := []gomatrixserverlib.VerifyJSONRequest{{
- ServerName: serverName,
- Message: redacted,
- AtTS: event.OriginServerTS(),
- StrictValidityChecking: true,
- }}
- verifyResults, err := keys.VerifyJSONs(ctx, verifyRequests)
- if err != nil {
- util.GetLogger(ctx).WithError(err).Error("keys.VerifyJSONs failed")
- return util.JSONResponse{
- Code: http.StatusInternalServerError,
- JSON: spec.InternalServerError{},
- }
+
+ input := gomatrixserverlib.HandleInviteInput{
+ RoomVersion: roomVer,
+ RoomID: roomID,
+ InvitedUser: *invitedUser,
+ KeyID: cfg.Matrix.KeyID,
+ PrivateKey: cfg.Matrix.PrivateKey,
+ Verifier: keys,
+ RoomQuerier: rsAPI,
+ MembershipQuerier: &api.MembershipQuerier{Roomserver: rsAPI},
+ StateQuerier: rsAPI.StateQuerier(),
+ InviteEvent: event,
+ StrippedState: strippedState,
}
- if verifyResults[0].Error != nil {
- return util.JSONResponse{
- Code: http.StatusForbidden,
- JSON: spec.Forbidden("The invite must be signed by the server it originated on"),
- }
+ event, jsonErr := handleInvite(httpReq.Context(), input, rsAPI)
+ if jsonErr != nil {
+ return *jsonErr
}
-
- // Sign the event so that other servers will know that we have received the invite.
- signedEvent := event.Sign(
- string(domain), cfg.Matrix.KeyID, cfg.Matrix.PrivateKey,
- )
-
- // Add the invite event to the roomserver.
- inviteEvent := &types.HeaderedEvent{PDU: signedEvent}
- request := &api.PerformInviteRequest{
- Event: inviteEvent,
- InviteRoomState: strippedState,
- RoomVersion: inviteEvent.Version(),
- SendAsServer: string(api.DoNotSendToOtherServers),
- TransactionID: nil,
+ return util.JSONResponse{
+ Code: http.StatusOK,
+ JSON: fclient.RespInvite{Event: event.JSON()},
}
+}
- if err = rsAPI.PerformInvite(ctx, request); err != nil {
- util.GetLogger(ctx).WithError(err).Error("PerformInvite failed")
- return util.JSONResponse{
+func handleInvite(ctx context.Context, input gomatrixserverlib.HandleInviteInput, rsAPI api.FederationRoomserverAPI) (gomatrixserverlib.PDU, *util.JSONResponse) {
+ inviteEvent, err := gomatrixserverlib.HandleInvite(ctx, input)
+ switch e := err.(type) {
+ case nil:
+ case spec.InternalServerError:
+ util.GetLogger(ctx).WithError(err)
+ return nil, &util.JSONResponse{
Code: http.StatusInternalServerError,
JSON: spec.InternalServerError{},
}
- }
-
- switch e := err.(type) {
- case api.ErrInvalidID:
- return util.JSONResponse{
- Code: http.StatusBadRequest,
- JSON: spec.Unknown(e.Error()),
+ case spec.MatrixError:
+ util.GetLogger(ctx).WithError(err)
+ code := http.StatusInternalServerError
+ switch e.ErrCode {
+ case spec.ErrorForbidden:
+ code = http.StatusForbidden
+ case spec.ErrorUnsupportedRoomVersion:
+ fallthrough // http.StatusBadRequest
+ case spec.ErrorBadJSON:
+ code = http.StatusBadRequest
}
- case api.ErrNotAllowed:
- return util.JSONResponse{
- Code: http.StatusForbidden,
- JSON: spec.Forbidden(e.Error()),
+
+ return nil, &util.JSONResponse{
+ Code: code,
+ JSON: e,
}
- case nil:
default:
- util.GetLogger(ctx).WithError(err).Error("PerformInvite failed")
- sentry.CaptureException(err)
- return util.JSONResponse{
- Code: http.StatusInternalServerError,
- JSON: spec.InternalServerError{},
+ util.GetLogger(ctx).WithError(err)
+ return nil, &util.JSONResponse{
+ Code: http.StatusBadRequest,
+ JSON: spec.Unknown("unknown error"),
}
}
- // Return the signed event to the originating server, it should then tell
- // the other servers in the room that we have been invited.
- if isInviteV2 {
- return util.JSONResponse{
- Code: http.StatusOK,
- JSON: fclient.RespInviteV2{Event: signedEvent.JSON()},
- }
- } else {
- return util.JSONResponse{
- Code: http.StatusOK,
- JSON: fclient.RespInvite{Event: signedEvent.JSON()},
+ headeredInvite := &types.HeaderedEvent{PDU: inviteEvent}
+ if err = rsAPI.HandleInvite(ctx, headeredInvite); err != nil {
+ util.GetLogger(ctx).WithError(err).Error("HandleInvite failed")
+ return nil, &util.JSONResponse{
+ Code: http.StatusInternalServerError,
+ JSON: spec.InternalServerError{},
}
}
+ return inviteEvent, nil
}
diff --git a/federationapi/routing/join.go b/federationapi/routing/join.go
index 03d3309a..c6f96375 100644
--- a/federationapi/routing/join.go
+++ b/federationapi/routing/join.go
@@ -216,25 +216,6 @@ func MakeJoin(
}
}
-type MembershipQuerier struct {
- roomserver api.FederationRoomserverAPI
-}
-
-func (mq *MembershipQuerier) CurrentMembership(ctx context.Context, roomID spec.RoomID, userID spec.UserID) (string, error) {
- req := api.QueryMembershipForUserRequest{
- RoomID: roomID.String(),
- UserID: userID.String(),
- }
- res := api.QueryMembershipForUserResponse{}
- err := mq.roomserver.QueryMembershipForUser(ctx, &req, &res)
-
- membership := ""
- if err == nil {
- membership = res.Membership
- }
- return membership, err
-}
-
// 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:
@@ -268,7 +249,7 @@ func SendJoin(
KeyID: cfg.Matrix.KeyID,
PrivateKey: cfg.Matrix.PrivateKey,
Verifier: keys,
- MembershipQuerier: &MembershipQuerier{roomserver: rsAPI},
+ MembershipQuerier: &api.MembershipQuerier{Roomserver: rsAPI},
}
response, joinErr := gomatrixserverlib.HandleSendJoin(input)
switch e := joinErr.(type) {
diff --git a/federationapi/routing/routing.go b/federationapi/routing/routing.go
index fad06c1c..8865022f 100644
--- a/federationapi/routing/routing.go
+++ b/federationapi/routing/routing.go
@@ -152,8 +152,16 @@ func Setup(
JSON: spec.Forbidden("Forbidden by server ACLs"),
}
}
+
+ roomID, err := spec.NewRoomID(vars["roomID"])
+ if err != nil {
+ return util.JSONResponse{
+ Code: http.StatusBadRequest,
+ JSON: spec.InvalidParam("Invalid RoomID"),
+ }
+ }
return InviteV1(
- httpReq, request, vars["roomID"], vars["eventID"],
+ httpReq, request, *roomID, vars["eventID"],
cfg, rsAPI, keys,
)
},
@@ -168,8 +176,16 @@ func Setup(
JSON: spec.Forbidden("Forbidden by server ACLs"),
}
}
+
+ roomID, err := spec.NewRoomID(vars["roomID"])
+ if err != nil {
+ return util.JSONResponse{
+ Code: http.StatusBadRequest,
+ JSON: spec.InvalidParam("Invalid RoomID"),
+ }
+ }
return InviteV2(
- httpReq, request, vars["roomID"], vars["eventID"],
+ httpReq, request, *roomID, vars["eventID"],
cfg, rsAPI, keys,
)
},
diff --git a/go.mod b/go.mod
index 0e979de6..a20757bb 100644
--- a/go.mod
+++ b/go.mod
@@ -22,7 +22,7 @@ require (
github.com/matrix-org/dugong v0.0.0-20210921133753-66e6b1c67e2e
github.com/matrix-org/go-sqlite3-js v0.0.0-20220419092513-28aa791a1c91
github.com/matrix-org/gomatrix v0.0.0-20220926102614-ceba4d9f7530
- github.com/matrix-org/gomatrixserverlib v0.0.0-20230531143710-c681a0658246
+ github.com/matrix-org/gomatrixserverlib v0.0.0-20230531155817-0e3adf17bee6
github.com/matrix-org/pinecone v0.11.1-0.20230210171230-8c3b24f2649a
github.com/matrix-org/util v0.0.0-20221111132719-399730281e66
github.com/mattn/go-sqlite3 v1.14.16
diff --git a/go.sum b/go.sum
index 8baa50e8..a1946ada 100644
--- a/go.sum
+++ b/go.sum
@@ -323,8 +323,8 @@ github.com/matrix-org/go-sqlite3-js v0.0.0-20220419092513-28aa791a1c91 h1:s7fexw
github.com/matrix-org/go-sqlite3-js v0.0.0-20220419092513-28aa791a1c91/go.mod h1:e+cg2q7C7yE5QnAXgzo512tgFh1RbQLC0+jozuegKgo=
github.com/matrix-org/gomatrix v0.0.0-20220926102614-ceba4d9f7530 h1:kHKxCOLcHH8r4Fzarl4+Y3K5hjothkVW5z7T1dUM11U=
github.com/matrix-org/gomatrix v0.0.0-20220926102614-ceba4d9f7530/go.mod h1:/gBX06Kw0exX1HrwmoBibFA98yBk/jxKpGVeyQbff+s=
-github.com/matrix-org/gomatrixserverlib v0.0.0-20230531143710-c681a0658246 h1:1sYXx7p9BIf0R7OIV/TZg3SCvNehEQPCKNqwV1ONfwU=
-github.com/matrix-org/gomatrixserverlib v0.0.0-20230531143710-c681a0658246/go.mod h1:H9V9N3Uqn1bBJqYJNGK1noqtgJTaCEhtTdcH/mp50uU=
+github.com/matrix-org/gomatrixserverlib v0.0.0-20230531155817-0e3adf17bee6 h1:Kh1TNvJDhWN5CdgtICNUC4G0wV2km51LGr46Dvl153A=
+github.com/matrix-org/gomatrixserverlib v0.0.0-20230531155817-0e3adf17bee6/go.mod h1:H9V9N3Uqn1bBJqYJNGK1noqtgJTaCEhtTdcH/mp50uU=
github.com/matrix-org/pinecone v0.11.1-0.20230210171230-8c3b24f2649a h1:awrPDf9LEFySxTLKYBMCiObelNx/cBuv/wzllvCCH3A=
github.com/matrix-org/pinecone v0.11.1-0.20230210171230-8c3b24f2649a/go.mod h1:HchJX9oKMXaT2xYFs0Ha/6Zs06mxLU8k6F1ODnrGkeQ=
github.com/matrix-org/util v0.0.0-20221111132719-399730281e66 h1:6z4KxomXSIGWqhHcfzExgkH3Z3UkIXry4ibJS4Aqz2Y=
diff --git a/roomserver/api/api.go b/roomserver/api/api.go
index 571aa40b..7cb3379e 100644
--- a/roomserver/api/api.go
+++ b/roomserver/api/api.go
@@ -225,6 +225,8 @@ type FederationRoomserverAPI interface {
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
+ HandleInvite(ctx context.Context, event *types.HeaderedEvent) error
+
PerformInvite(ctx context.Context, req *PerformInviteRequest) error
// Query a given amount (or less) of events prior to a given set of events.
PerformBackfill(ctx context.Context, req *PerformBackfillRequest, res *PerformBackfillResponse) error
@@ -234,6 +236,9 @@ type FederationRoomserverAPI interface {
QueryRoomInfo(ctx context.Context, roomID spec.RoomID) (*types.RoomInfo, error)
UserJoinedToRoom(ctx context.Context, roomID types.RoomNID, userID spec.UserID) (bool, error)
LocallyJoinedUsers(ctx context.Context, roomVersion gomatrixserverlib.RoomVersion, roomNID types.RoomNID) ([]gomatrixserverlib.PDU, error)
+
+ IsKnownRoom(ctx context.Context, roomID spec.RoomID) (bool, error)
+ StateQuerier() gomatrixserverlib.StateQuerier
}
type KeyserverRoomserverAPI interface {
diff --git a/roomserver/api/perform.go b/roomserver/api/perform.go
index 8d9742c6..6cbaf5b1 100644
--- a/roomserver/api/perform.go
+++ b/roomserver/api/perform.go
@@ -7,7 +7,6 @@ import (
"github.com/matrix-org/dendrite/roomserver/types"
"github.com/matrix-org/gomatrixserverlib"
- "github.com/matrix-org/gomatrixserverlib/fclient"
"github.com/matrix-org/gomatrixserverlib/spec"
"github.com/matrix-org/util"
)
@@ -52,11 +51,11 @@ type PerformLeaveResponse struct {
}
type PerformInviteRequest struct {
- RoomVersion gomatrixserverlib.RoomVersion `json:"room_version"`
- Event *types.HeaderedEvent `json:"event"`
- InviteRoomState []fclient.InviteV2StrippedState `json:"invite_room_state"`
- SendAsServer string `json:"send_as_server"`
- TransactionID *TransactionID `json:"transaction_id"`
+ RoomVersion gomatrixserverlib.RoomVersion `json:"room_version"`
+ Event *types.HeaderedEvent `json:"event"`
+ InviteRoomState []gomatrixserverlib.InviteStrippedState `json:"invite_room_state"`
+ SendAsServer string `json:"send_as_server"`
+ TransactionID *TransactionID `json:"transaction_id"`
}
type PerformPeekRequest struct {
diff --git a/roomserver/api/query.go b/roomserver/api/query.go
index 1726bfe1..b33698c8 100644
--- a/roomserver/api/query.go
+++ b/roomserver/api/query.go
@@ -17,6 +17,7 @@
package api
import (
+ "context"
"encoding/json"
"fmt"
"strings"
@@ -457,3 +458,22 @@ type QueryLeftUsersRequest struct {
type QueryLeftUsersResponse struct {
LeftUsers []string `json:"user_ids"`
}
+
+type MembershipQuerier struct {
+ Roomserver FederationRoomserverAPI
+}
+
+func (mq *MembershipQuerier) CurrentMembership(ctx context.Context, roomID spec.RoomID, userID spec.UserID) (string, error) {
+ req := QueryMembershipForUserRequest{
+ RoomID: roomID.String(),
+ UserID: userID.String(),
+ }
+ res := QueryMembershipForUserResponse{}
+ err := mq.Roomserver.QueryMembershipForUser(ctx, &req, &res)
+
+ membership := ""
+ if err == nil {
+ membership = res.Membership
+ }
+ return membership, err
+}
diff --git a/roomserver/internal/api.go b/roomserver/internal/api.go
index f61f8918..ee433f0d 100644
--- a/roomserver/internal/api.go
+++ b/roomserver/internal/api.go
@@ -20,6 +20,7 @@ import (
"github.com/matrix-org/dendrite/roomserver/internal/query"
"github.com/matrix-org/dendrite/roomserver/producers"
"github.com/matrix-org/dendrite/roomserver/storage"
+ "github.com/matrix-org/dendrite/roomserver/types"
"github.com/matrix-org/dendrite/setup/config"
"github.com/matrix-org/dendrite/setup/jetstream"
"github.com/matrix-org/dendrite/setup/process"
@@ -132,6 +133,7 @@ func (r *RoomserverInternalAPI) SetFederationAPI(fsAPI fsAPI.RoomserverFederatio
DB: r.DB,
Cfg: &r.Cfg.RoomServer,
FSAPI: r.fsAPI,
+ RSAPI: r,
Inputer: r.Inputer,
}
r.Joiner = &perform.Joiner{
@@ -213,6 +215,24 @@ func (r *RoomserverInternalAPI) SetAppserviceAPI(asAPI asAPI.AppServiceInternalA
r.asAPI = asAPI
}
+func (r *RoomserverInternalAPI) IsKnownRoom(ctx context.Context, roomID spec.RoomID) (bool, error) {
+ return r.Inviter.IsKnownRoom(ctx, roomID)
+}
+
+func (r *RoomserverInternalAPI) StateQuerier() gomatrixserverlib.StateQuerier {
+ return r.Inviter.StateQuerier()
+}
+
+func (r *RoomserverInternalAPI) HandleInvite(
+ ctx context.Context, inviteEvent *types.HeaderedEvent,
+) error {
+ outputEvents, err := r.Inviter.ProcessInviteMembership(ctx, inviteEvent)
+ if err != nil {
+ return err
+ }
+ return r.OutputProducer.ProduceRoomEvents(inviteEvent.RoomID(), outputEvents)
+}
+
func (r *RoomserverInternalAPI) PerformCreateRoom(
ctx context.Context, userID spec.UserID, roomID spec.RoomID, createRequest *api.PerformCreateRoomRequest,
) (string, *util.JSONResponse) {
@@ -223,14 +243,7 @@ func (r *RoomserverInternalAPI) PerformInvite(
ctx context.Context,
req *api.PerformInviteRequest,
) error {
- outputEvents, err := r.Inviter.PerformInvite(ctx, req)
- if err != nil {
- return err
- }
- if len(outputEvents) == 0 {
- return nil
- }
- return r.OutputProducer.ProduceRoomEvents(req.Event.RoomID(), outputEvents)
+ return r.Inviter.PerformInvite(ctx, req)
}
func (r *RoomserverInternalAPI) PerformLeave(
diff --git a/roomserver/internal/helpers/auth.go b/roomserver/internal/helpers/auth.go
index 24958091..7ec0892e 100644
--- a/roomserver/internal/helpers/auth.go
+++ b/roomserver/internal/helpers/auth.go
@@ -70,7 +70,7 @@ func CheckForSoftFail(
)
// Load the actual auth events from the database.
- authEvents, err := loadAuthEvents(ctx, db, roomInfo, stateNeeded, authStateEntries)
+ authEvents, err := loadAuthEvents(ctx, db, roomInfo.RoomVersion, stateNeeded, authStateEntries)
if err != nil {
return true, fmt.Errorf("loadAuthEvents: %w", err)
}
@@ -83,15 +83,14 @@ func CheckForSoftFail(
return false, nil
}
-// CheckAuthEvents checks that the event passes authentication checks
-// Returns the numeric IDs for the auth events.
-func CheckAuthEvents(
+// GetAuthEvents returns the numeric IDs for the auth events.
+func GetAuthEvents(
ctx context.Context,
db storage.RoomDatabase,
- roomInfo *types.RoomInfo,
- event *types.HeaderedEvent,
+ roomVersion gomatrixserverlib.RoomVersion,
+ event gomatrixserverlib.PDU,
authEventIDs []string,
-) ([]types.EventNID, error) {
+) (gomatrixserverlib.AuthEventProvider, error) {
// Grab the numeric IDs for the supplied auth state events from the database.
authStateEntries, err := db.StateEntriesForEventIDs(ctx, authEventIDs, true)
if err != nil {
@@ -100,25 +99,14 @@ func CheckAuthEvents(
authStateEntries = types.DeduplicateStateEntries(authStateEntries)
// Work out which of the state events we actually need.
- stateNeeded := gomatrixserverlib.StateNeededForAuth([]gomatrixserverlib.PDU{event.PDU})
+ stateNeeded := gomatrixserverlib.StateNeededForAuth([]gomatrixserverlib.PDU{event})
// Load the actual auth events from the database.
- authEvents, err := loadAuthEvents(ctx, db, roomInfo, stateNeeded, authStateEntries)
+ authEvents, err := loadAuthEvents(ctx, db, roomVersion, stateNeeded, authStateEntries)
if err != nil {
return nil, fmt.Errorf("loadAuthEvents: %w", err)
}
-
- // Check if the event is allowed.
- if err = gomatrixserverlib.Allowed(event.PDU, &authEvents); err != nil {
- return nil, err
- }
-
- // Return the numeric IDs for the auth events.
- result := make([]types.EventNID, len(authStateEntries))
- for i := range authStateEntries {
- result[i] = authStateEntries[i].EventNID
- }
- return result, nil
+ return &authEvents, nil
}
type authEvents struct {
@@ -196,7 +184,7 @@ func (ae *authEvents) lookupEvent(typeNID types.EventTypeNID, stateKey string) g
func loadAuthEvents(
ctx context.Context,
db state.StateResolutionStorage,
- roomInfo *types.RoomInfo,
+ roomVersion gomatrixserverlib.RoomVersion,
needed gomatrixserverlib.StateNeeded,
state []types.StateEntry,
) (result authEvents, err error) {
@@ -220,11 +208,7 @@ func loadAuthEvents(
}
}
- if roomInfo == nil {
- err = types.ErrorInvalidRoomInfo
- return
- }
- if result.events, err = db.Events(ctx, roomInfo.RoomVersion, eventNIDs); err != nil {
+ if result.events, err = db.Events(ctx, roomVersion, eventNIDs); err != nil {
return
}
roomID := ""
diff --git a/roomserver/internal/perform/perform_create_room.go b/roomserver/internal/perform/perform_create_room.go
index 0f917008..41194832 100644
--- a/roomserver/internal/perform/perform_create_room.go
+++ b/roomserver/internal/perform/perform_create_room.go
@@ -376,7 +376,7 @@ func (c *Creator) PerformCreateRoom(ctx context.Context, userID spec.UserID, roo
// If this is a direct message then we should invite the participants.
if len(createRequest.InvitedUsers) > 0 {
// Build some stripped state for the invite.
- var globalStrippedState []fclient.InviteV2StrippedState
+ var globalStrippedState []gomatrixserverlib.InviteStrippedState
for _, event := range builtEvents {
// Chosen events from the spec:
// https://spec.matrix.org/v1.3/client-server-api/#stripped-state
@@ -399,7 +399,7 @@ func (c *Creator) PerformCreateRoom(ctx context.Context, userID spec.UserID, roo
ev := event.PDU
globalStrippedState = append(
globalStrippedState,
- fclient.NewInviteV2StrippedState(ev),
+ gomatrixserverlib.NewInviteStrippedState(ev),
)
}
}
@@ -443,7 +443,7 @@ func (c *Creator) PerformCreateRoom(ctx context.Context, userID spec.UserID, roo
}
inviteStrippedState := append(
globalStrippedState,
- fclient.NewInviteV2StrippedState(inviteEvent.PDU),
+ gomatrixserverlib.NewInviteStrippedState(inviteEvent.PDU),
)
// Send the invite event to the roomserver.
event := inviteEvent
diff --git a/roomserver/internal/perform/perform_invite.go b/roomserver/internal/perform/perform_invite.go
index a3fa2e01..1930b5ac 100644
--- a/roomserver/internal/perform/perform_invite.go
+++ b/roomserver/internal/perform/perform_invite.go
@@ -28,186 +28,149 @@ import (
"github.com/matrix-org/dendrite/roomserver/types"
"github.com/matrix-org/dendrite/setup/config"
"github.com/matrix-org/gomatrixserverlib"
- "github.com/matrix-org/gomatrixserverlib/fclient"
"github.com/matrix-org/gomatrixserverlib/spec"
"github.com/matrix-org/util"
- log "github.com/sirupsen/logrus"
)
+type QueryState struct {
+ storage.Database
+}
+
+func (q *QueryState) GetAuthEvents(ctx context.Context, event gomatrixserverlib.PDU) (gomatrixserverlib.AuthEventProvider, error) {
+ return helpers.GetAuthEvents(ctx, q.Database, event.Version(), event, event.AuthEventIDs())
+}
+
+func (q *QueryState) GetState(ctx context.Context, roomID spec.RoomID, stateWanted []gomatrixserverlib.StateKeyTuple) ([]gomatrixserverlib.PDU, error) {
+ info, err := q.Database.RoomInfo(ctx, roomID.String())
+ if err != nil {
+ return nil, fmt.Errorf("failed to load RoomInfo: %w", err)
+ }
+ if info != nil {
+ roomState := state.NewStateResolution(q.Database, info)
+ stateEntries, err := roomState.LoadStateAtSnapshotForStringTuples(
+ ctx, info.StateSnapshotNID(), stateWanted,
+ )
+ if err != nil {
+ return nil, nil
+ }
+ stateNIDs := []types.EventNID{}
+ for _, stateNID := range stateEntries {
+ stateNIDs = append(stateNIDs, stateNID.EventNID)
+ }
+ stateEvents, err := q.Database.Events(ctx, info.RoomVersion, stateNIDs)
+ if err != nil {
+ return nil, fmt.Errorf("failed to obtain required events: %w", err)
+ }
+
+ events := []gomatrixserverlib.PDU{}
+ for _, event := range stateEvents {
+ events = append(events, event.PDU)
+ }
+ return events, nil
+ }
+
+ return nil, nil
+}
+
type Inviter struct {
DB storage.Database
Cfg *config.RoomServer
FSAPI federationAPI.RoomserverFederationAPI
+ RSAPI api.RoomserverInternalAPI
Inputer *input.Inputer
}
-// nolint:gocyclo
-func (r *Inviter) PerformInvite(
- ctx context.Context,
- req *api.PerformInviteRequest,
-) ([]api.OutputEvent, error) {
- var outputUpdates []api.OutputEvent
- event := req.Event
- if event.StateKey() == nil {
- return nil, fmt.Errorf("invite must be a state event")
- }
- _, senderDomain, err := gomatrixserverlib.SplitID('@', event.Sender())
+func (r *Inviter) IsKnownRoom(ctx context.Context, roomID spec.RoomID) (bool, error) {
+ info, err := r.DB.RoomInfo(ctx, roomID.String())
if err != nil {
- return nil, fmt.Errorf("sender %q is invalid", event.Sender())
+ return false, fmt.Errorf("failed to load RoomInfo: %w", err)
}
+ return (info != nil && !info.IsStub()), nil
+}
- roomID := event.RoomID()
- targetUserID := *event.StateKey()
- info, err := r.DB.RoomInfo(ctx, roomID)
- if err != nil {
- return nil, fmt.Errorf("failed to load RoomInfo: %w", err)
- }
+func (r *Inviter) StateQuerier() gomatrixserverlib.StateQuerier {
+ return &QueryState{Database: r.DB}
+}
- _, domain, err := gomatrixserverlib.SplitID('@', targetUserID)
+func (r *Inviter) ProcessInviteMembership(
+ ctx context.Context, inviteEvent *types.HeaderedEvent,
+) ([]api.OutputEvent, error) {
+ var outputUpdates []api.OutputEvent
+ var updater *shared.MembershipUpdater
+ _, domain, err := gomatrixserverlib.SplitID('@', *inviteEvent.StateKey())
if err != nil {
- return nil, api.ErrInvalidID{Err: fmt.Errorf("the user ID %s is invalid", targetUserID)}
+ return nil, api.ErrInvalidID{Err: fmt.Errorf("the user ID %s is invalid", *inviteEvent.StateKey())}
}
isTargetLocal := r.Cfg.Matrix.IsLocalServerName(domain)
- isOriginLocal := r.Cfg.Matrix.IsLocalServerName(senderDomain)
- if !isOriginLocal && !isTargetLocal {
- return nil, api.ErrInvalidID{Err: fmt.Errorf("the invite must be either from or to a local user")}
+ if updater, err = r.DB.MembershipUpdater(ctx, inviteEvent.RoomID(), *inviteEvent.StateKey(), isTargetLocal, inviteEvent.Version()); err != nil {
+ return nil, fmt.Errorf("r.DB.MembershipUpdater: %w", err)
}
-
- logger := util.GetLogger(ctx).WithFields(map[string]interface{}{
- "inviter": event.Sender(),
- "invitee": *event.StateKey(),
- "room_id": roomID,
- "event_id": event.EventID(),
- })
- logger.WithFields(log.Fields{
- "room_version": req.RoomVersion,
- "room_info_exists": info != nil,
- "target_local": isTargetLocal,
- "origin_local": isOriginLocal,
- }).Debug("processing invite event")
-
- inviteState := req.InviteRoomState
- if len(inviteState) == 0 && info != nil {
- var is []fclient.InviteV2StrippedState
- if is, err = buildInviteStrippedState(ctx, r.DB, info, req); err == nil {
- inviteState = is
- }
+ outputUpdates, err = helpers.UpdateToInviteMembership(updater, &types.Event{
+ EventNID: 0,
+ PDU: inviteEvent.PDU,
+ }, outputUpdates, inviteEvent.Version())
+ if err != nil {
+ return nil, fmt.Errorf("updateToInviteMembership: %w", err)
}
- if len(inviteState) == 0 {
- if err = event.SetUnsignedField("invite_room_state", struct{}{}); err != nil {
- return nil, fmt.Errorf("event.SetUnsignedField: %w", err)
- }
- } else {
- if err = event.SetUnsignedField("invite_room_state", inviteState); err != nil {
- return nil, fmt.Errorf("event.SetUnsignedField: %w", err)
- }
+ if err = updater.Commit(); err != nil {
+ return nil, fmt.Errorf("updater.Commit: %w", err)
}
+ return outputUpdates, nil
+}
- updateMembershipTableManually := func() ([]api.OutputEvent, error) {
- var updater *shared.MembershipUpdater
- if updater, err = r.DB.MembershipUpdater(ctx, roomID, targetUserID, isTargetLocal, req.RoomVersion); err != nil {
- return nil, fmt.Errorf("r.DB.MembershipUpdater: %w", err)
- }
- outputUpdates, err = helpers.UpdateToInviteMembership(updater, &types.Event{
- EventNID: 0,
- PDU: event.PDU,
- }, outputUpdates, req.Event.Version())
- if err != nil {
- return nil, fmt.Errorf("updateToInviteMembership: %w", err)
- }
- if err = updater.Commit(); err != nil {
- return nil, fmt.Errorf("updater.Commit: %w", err)
- }
- logger.Debugf("updated membership to invite and sending invite OutputEvent")
- return outputUpdates, nil
- }
+// nolint:gocyclo
+func (r *Inviter) PerformInvite(
+ ctx context.Context,
+ req *api.PerformInviteRequest,
+) error {
+ event := req.Event
- if (info == nil || info.IsStub()) && !isOriginLocal && isTargetLocal {
- // The invite came in over federation for a room that we don't know about
- // yet. We need to handle this a bit differently to most invites because
- // we don't know the room state, therefore the roomserver can't process
- // an input event. Instead we will update the membership table with the
- // new invite and generate an output event.
- return updateMembershipTableManually()
+ sender, err := spec.NewUserID(event.Sender(), true)
+ if err != nil {
+ return spec.InvalidParam("The user ID is invalid")
+ }
+ if !r.Cfg.Matrix.IsLocalServerName(sender.Domain()) {
+ return api.ErrInvalidID{Err: fmt.Errorf("the invite must be from a local user")}
}
- var isAlreadyJoined bool
- if info != nil {
- _, isAlreadyJoined, _, err = r.DB.GetMembership(ctx, info.RoomNID, *event.StateKey())
- if err != nil {
- return nil, fmt.Errorf("r.DB.GetMembership: %w", err)
- }
+ if event.StateKey() == nil {
+ return fmt.Errorf("invite must be a state event")
}
- if isAlreadyJoined {
- // If the user is joined to the room then that takes precedence over this
- // invite event. It makes little sense to move a user that is already
- // joined to the room into the invite state.
- // This could plausibly happen if an invite request raced with a join
- // request for a user. For example if a user was invited to a public
- // room and they joined the room at the same time as the invite was sent.
- // The other way this could plausibly happen is if an invite raced with
- // a kick. For example if a user was kicked from a room in error and in
- // response someone else in the room re-invited them then it is possible
- // for the invite request to race with the leave event so that the
- // target receives invite before it learns that it has been kicked.
- // There are a few ways this could be plausibly handled in the roomserver.
- // 1) Store the invite, but mark it as retired. That will result in the
- // permanent rejection of that invite event. So even if the target
- // user leaves the room and the invite is retransmitted it will be
- // ignored. However a new invite with a new event ID would still be
- // accepted.
- // 2) Silently discard the invite event. This means that if the event
- // was retransmitted at a later date after the target user had left
- // the room we would accept the invite. However since we hadn't told
- // the sending server that the invite had been discarded it would
- // have no reason to attempt to retry.
- // 3) Signal the sending server that the user is already joined to the
- // room.
- // For now we will implement option 2. Since in the abesence of a retry
- // mechanism it will be equivalent to option 1, and we don't have a
- // signalling mechanism to implement option 3.
- logger.Debugf("user already joined")
- return nil, api.ErrNotAllowed{Err: fmt.Errorf("user is already joined to room")}
+ invitedUser, err := spec.NewUserID(*event.StateKey(), true)
+ if err != nil {
+ return spec.InvalidParam("The user ID is invalid")
}
+ isTargetLocal := r.Cfg.Matrix.IsLocalServerName(invitedUser.Domain())
- // If the invite originated remotely then we can't send an
- // InputRoomEvent for the invite as it will never pass auth checks
- // due to lacking room state, but we still need to tell the client
- // about the invite so we can accept it, hence we return an output
- // event to send to the Sync API.
- if !isOriginLocal {
- return updateMembershipTableManually()
+ validRoomID, err := spec.NewRoomID(event.RoomID())
+ if err != nil {
+ return err
}
- // The invite originated locally. Therefore we have a responsibility to
- // try and see if the user is allowed to make this invite. We can't do
- // this for invites coming in over federation - we have to take those on
- // trust.
- _, err = helpers.CheckAuthEvents(ctx, r.DB, info, event, event.AuthEventIDs())
+ input := gomatrixserverlib.PerformInviteInput{
+ RoomID: *validRoomID,
+ InviteEvent: event.PDU,
+ InvitedUser: *invitedUser,
+ IsTargetLocal: isTargetLocal,
+ StrippedState: req.InviteRoomState,
+ MembershipQuerier: &api.MembershipQuerier{Roomserver: r.RSAPI},
+ StateQuerier: &QueryState{r.DB},
+ }
+ inviteEvent, err := gomatrixserverlib.PerformInvite(ctx, input, r.FSAPI)
if err != nil {
- logger.WithError(err).WithField("event_id", event.EventID()).WithField("auth_event_ids", event.AuthEventIDs()).Error(
- "processInviteEvent.checkAuthEvents failed for event",
- )
- return nil, api.ErrNotAllowed{Err: err}
+ switch e := err.(type) {
+ case spec.MatrixError:
+ if e.ErrCode == spec.ErrorForbidden {
+ return api.ErrNotAllowed{Err: fmt.Errorf("%s", e.Err)}
+ }
+ }
+ return err
}
- // If the invite originated from us and the target isn't local then we
- // should try and send the invite over federation first. It might be
- // that the remote user doesn't exist, in which case we can give up
- // processing here.
- if req.SendAsServer != api.DoNotSendToOtherServers && !isTargetLocal {
- fsReq := &federationAPI.PerformInviteRequest{
- RoomVersion: req.RoomVersion,
- Event: event,
- InviteRoomState: inviteState,
- }
- fsRes := &federationAPI.PerformInviteResponse{}
- if err = r.FSAPI.PerformInvite(ctx, fsReq, fsRes); err != nil {
- logger.WithError(err).WithField("event_id", event.EventID()).Error("r.FSAPI.PerformInvite failed")
- return nil, api.ErrNotAllowed{Err: err}
- }
- event = fsRes.Event
- logger.Debugf("Federated PerformInvite success with event ID %s", event.EventID())
+ // Use the returned event if there was one (due to federation), otherwise
+ // send the original invite event to the roomserver.
+ if inviteEvent == nil {
+ inviteEvent = event
}
// Send the invite event to the roomserver input stream. This will
@@ -219,67 +182,18 @@ func (r *Inviter) PerformInvite(
InputRoomEvents: []api.InputRoomEvent{
{
Kind: api.KindNew,
- Event: event,
- Origin: senderDomain,
+ Event: &types.HeaderedEvent{PDU: inviteEvent},
+ Origin: sender.Domain(),
SendAsServer: req.SendAsServer,
},
},
}
inputRes := &api.InputRoomEventsResponse{}
r.Inputer.InputRoomEvents(context.Background(), inputReq, inputRes)
- if err = inputRes.Err(); err != nil {
- logger.WithError(err).WithField("event_id", event.EventID()).Error("r.InputRoomEvents failed")
- return nil, api.ErrNotAllowed{Err: err}
+ if err := inputRes.Err(); err != nil {
+ util.GetLogger(ctx).WithField("event_id", event.EventID()).Error("r.InputRoomEvents failed")
+ return api.ErrNotAllowed{Err: err}
}
- // Don't notify the sync api of this event in the same way as a federated invite so the invitee
- // gets the invite, as the roomserver will do this when it processes the m.room.member invite.
- return outputUpdates, nil
-}
-
-func buildInviteStrippedState(
- ctx context.Context,
- db storage.Database,
- info *types.RoomInfo,
- input *api.PerformInviteRequest,
-) ([]fclient.InviteV2StrippedState, error) {
- stateWanted := []gomatrixserverlib.StateKeyTuple{}
- // "If they are set on the room, at least the state for m.room.avatar, m.room.canonical_alias, m.room.join_rules, and m.room.name SHOULD be included."
- // https://matrix.org/docs/spec/client_server/r0.6.0#m-room-member
- for _, t := range []string{
- spec.MRoomName, spec.MRoomCanonicalAlias,
- spec.MRoomJoinRules, spec.MRoomAvatar,
- spec.MRoomEncryption, spec.MRoomCreate,
- } {
- stateWanted = append(stateWanted, gomatrixserverlib.StateKeyTuple{
- EventType: t,
- StateKey: "",
- })
- }
- roomState := state.NewStateResolution(db, info)
- stateEntries, err := roomState.LoadStateAtSnapshotForStringTuples(
- ctx, info.StateSnapshotNID(), stateWanted,
- )
- if err != nil {
- return nil, err
- }
- stateNIDs := []types.EventNID{}
- for _, stateNID := range stateEntries {
- stateNIDs = append(stateNIDs, stateNID.EventNID)
- }
- if info == nil {
- return nil, types.ErrorInvalidRoomInfo
- }
- stateEvents, err := db.Events(ctx, info.RoomVersion, stateNIDs)
- if err != nil {
- return nil, err
- }
- inviteState := []fclient.InviteV2StrippedState{
- fclient.NewInviteV2StrippedState(input.Event.PDU),
- }
- stateEvents = append(stateEvents, types.Event{PDU: input.Event.PDU})
- for _, event := range stateEvents {
- inviteState = append(inviteState, fclient.NewInviteV2StrippedState(event.PDU))
- }
- return inviteState, nil
+ return nil
}