mirror of
https://github.com/matrix-org/dendrite.git
synced 2024-11-22 14:21:55 -06:00
Synchronous invites (#1273)
* Refactor invites to be synchronous * Fix synchronous invites * Fix client API return type for send invite error * Linter * Restore PerformError on rsAPI.PerformInvite * Update sytest-whitelist * Don't override PerformError with normal errors * Fix error passing * Un-whitelist a couple of tests * Update sytest-whitelist * Try to handle multiple invite rejections better * nolint * Update gomatrixserverlib * Fix /v1/invite test * Remove replace from go.mod
This commit is contained in:
parent
6820b3e024
commit
6cb1a65809
|
@ -386,8 +386,12 @@ func createRoom(
|
||||||
var strippedState []gomatrixserverlib.InviteV2StrippedState
|
var strippedState []gomatrixserverlib.InviteV2StrippedState
|
||||||
for _, event := range candidates {
|
for _, event := range candidates {
|
||||||
switch event.Type() {
|
switch event.Type() {
|
||||||
// TODO: case gomatrixserverlib.MRoomEncryption:
|
case gomatrixserverlib.MRoomName:
|
||||||
// fallthrough
|
fallthrough
|
||||||
|
case gomatrixserverlib.MRoomCanonicalAlias:
|
||||||
|
fallthrough
|
||||||
|
case "m.room.encryption": // TODO: move this to gmsl
|
||||||
|
fallthrough
|
||||||
case gomatrixserverlib.MRoomMember:
|
case gomatrixserverlib.MRoomMember:
|
||||||
fallthrough
|
fallthrough
|
||||||
case gomatrixserverlib.MRoomJoinRules:
|
case gomatrixserverlib.MRoomJoinRules:
|
||||||
|
@ -398,15 +402,23 @@ func createRoom(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Send the invite event to the roomserver.
|
// Send the invite event to the roomserver.
|
||||||
if perr := roomserverAPI.SendInvite(
|
err = roomserverAPI.SendInvite(
|
||||||
req.Context(), rsAPI,
|
req.Context(), rsAPI,
|
||||||
inviteEvent.Headered(roomVersion),
|
inviteEvent.Headered(roomVersion),
|
||||||
strippedState, // invite room state
|
strippedState, // invite room state
|
||||||
cfg.Matrix.ServerName, // send as server
|
cfg.Matrix.ServerName, // send as server
|
||||||
nil, // transaction ID
|
nil, // transaction ID
|
||||||
); perr != nil {
|
)
|
||||||
util.GetLogger(req.Context()).WithError(perr).Error("SendInvite failed")
|
switch e := err.(type) {
|
||||||
return perr.JSONResponse()
|
case *roomserverAPI.PerformError:
|
||||||
|
return e.JSONResponse()
|
||||||
|
case nil:
|
||||||
|
default:
|
||||||
|
util.GetLogger(req.Context()).WithError(err).Error("roomserverAPI.SendInvite failed")
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: http.StatusInternalServerError,
|
||||||
|
JSON: jsonerror.InternalServerError(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -173,7 +173,7 @@ func SendInvite(
|
||||||
roomID string, cfg *config.ClientAPI,
|
roomID string, cfg *config.ClientAPI,
|
||||||
rsAPI roomserverAPI.RoomserverInternalAPI, asAPI appserviceAPI.AppServiceQueryAPI,
|
rsAPI roomserverAPI.RoomserverInternalAPI, asAPI appserviceAPI.AppServiceQueryAPI,
|
||||||
) util.JSONResponse {
|
) util.JSONResponse {
|
||||||
body, evTime, roomVer, reqErr := extractRequestData(req, roomID, rsAPI)
|
body, evTime, _, reqErr := extractRequestData(req, roomID, rsAPI)
|
||||||
if reqErr != nil {
|
if reqErr != nil {
|
||||||
return *reqErr
|
return *reqErr
|
||||||
}
|
}
|
||||||
|
@ -214,21 +214,28 @@ func SendInvite(
|
||||||
return jsonerror.InternalServerError()
|
return jsonerror.InternalServerError()
|
||||||
}
|
}
|
||||||
|
|
||||||
perr := roomserverAPI.SendInvite(
|
err = roomserverAPI.SendInvite(
|
||||||
req.Context(), rsAPI,
|
req.Context(), rsAPI,
|
||||||
event.Event.Headered(roomVer),
|
*event,
|
||||||
nil, // ask the roomserver to draw up invite room state for us
|
nil, // ask the roomserver to draw up invite room state for us
|
||||||
cfg.Matrix.ServerName,
|
cfg.Matrix.ServerName,
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
if perr != nil {
|
switch e := err.(type) {
|
||||||
util.GetLogger(req.Context()).WithError(perr).Error("producer.SendInvite failed")
|
case *roomserverAPI.PerformError:
|
||||||
return perr.JSONResponse()
|
return e.JSONResponse()
|
||||||
}
|
case nil:
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusOK,
|
Code: http.StatusOK,
|
||||||
JSON: struct{}{},
|
JSON: struct{}{},
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
|
util.GetLogger(req.Context()).WithError(err).Error("roomserverAPI.SendInvite failed")
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: http.StatusInternalServerError,
|
||||||
|
JSON: jsonerror.InternalServerError(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildMembershipEvent(
|
func buildMembershipEvent(
|
||||||
|
|
|
@ -46,7 +46,7 @@ func InviteV2(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return processInvite(
|
return processInvite(
|
||||||
httpReq.Context(), inviteReq.Event(), inviteReq.RoomVersion(), inviteReq.InviteRoomState(), roomID, eventID, cfg, rsAPI, keys,
|
httpReq.Context(), true, inviteReq.Event(), inviteReq.RoomVersion(), inviteReq.InviteRoomState(), roomID, eventID, cfg, rsAPI, keys,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,12 +75,13 @@ func InviteV1(
|
||||||
util.GetLogger(httpReq.Context()).Warnf("failed to extract stripped state from invite event")
|
util.GetLogger(httpReq.Context()).Warnf("failed to extract stripped state from invite event")
|
||||||
}
|
}
|
||||||
return processInvite(
|
return processInvite(
|
||||||
httpReq.Context(), event, roomVer, strippedState, roomID, eventID, cfg, rsAPI, keys,
|
httpReq.Context(), false, event, roomVer, strippedState, roomID, eventID, cfg, rsAPI, keys,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func processInvite(
|
func processInvite(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
|
isInviteV2 bool,
|
||||||
event gomatrixserverlib.Event,
|
event gomatrixserverlib.Event,
|
||||||
roomVer gomatrixserverlib.RoomVersion,
|
roomVer gomatrixserverlib.RoomVersion,
|
||||||
strippedState []gomatrixserverlib.InviteV2StrippedState,
|
strippedState []gomatrixserverlib.InviteV2StrippedState,
|
||||||
|
@ -143,17 +144,31 @@ func processInvite(
|
||||||
)
|
)
|
||||||
|
|
||||||
// Add the invite event to the roomserver.
|
// Add the invite event to the roomserver.
|
||||||
if perr := api.SendInvite(
|
err = api.SendInvite(
|
||||||
ctx, rsAPI, signedEvent.Headered(roomVer), strippedState, event.Origin(), nil,
|
ctx, rsAPI, signedEvent.Headered(roomVer), strippedState, api.DoNotSendToOtherServers, nil,
|
||||||
); perr != nil {
|
)
|
||||||
util.GetLogger(ctx).WithError(err).Error("producer.SendInvite failed")
|
switch e := err.(type) {
|
||||||
return perr.JSONResponse()
|
case *api.PerformError:
|
||||||
}
|
return e.JSONResponse()
|
||||||
|
case nil:
|
||||||
// Return the signed event to the originating server, it should then tell
|
// Return the signed event to the originating server, it should then tell
|
||||||
// the other servers in the room that we have been invited.
|
// the other servers in the room that we have been invited.
|
||||||
|
if isInviteV2 {
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusOK,
|
Code: http.StatusOK,
|
||||||
JSON: gomatrixserverlib.RespInviteV2{Event: signedEvent},
|
JSON: gomatrixserverlib.RespInviteV2{Event: signedEvent},
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: http.StatusOK,
|
||||||
|
JSON: gomatrixserverlib.RespInvite{Event: signedEvent},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
util.GetLogger(ctx).WithError(err).Error("api.SendInvite failed")
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: http.StatusInternalServerError,
|
||||||
|
JSON: jsonerror.InternalServerError(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// MakeLeave implements the /make_leave API
|
// MakeLeave implements the /make_leave API
|
||||||
|
// nolint:gocyclo
|
||||||
func MakeLeave(
|
func MakeLeave(
|
||||||
httpReq *http.Request,
|
httpReq *http.Request,
|
||||||
request *gomatrixserverlib.FederationRequest,
|
request *gomatrixserverlib.FederationRequest,
|
||||||
|
@ -76,6 +77,23 @@ func MakeLeave(
|
||||||
return jsonerror.InternalServerError()
|
return jsonerror.InternalServerError()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the user has already left then just return their last leave
|
||||||
|
// event. This means that /send_leave will be a no-op, which helps
|
||||||
|
// to reject invites multiple times - hopefully.
|
||||||
|
for _, state := range queryRes.StateEvents {
|
||||||
|
if state.Type() == gomatrixserverlib.MRoomMember && state.StateKeyEquals(userID) {
|
||||||
|
if mem, merr := state.Membership(); merr == nil && mem == gomatrixserverlib.Leave {
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: http.StatusOK,
|
||||||
|
JSON: map[string]interface{}{
|
||||||
|
"room_version": event.RoomVersion,
|
||||||
|
"event": state,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check that the leave is allowed or not
|
// Check that the leave is allowed or not
|
||||||
stateEvents := make([]*gomatrixserverlib.Event, len(queryRes.StateEvents))
|
stateEvents := make([]*gomatrixserverlib.Event, len(queryRes.StateEvents))
|
||||||
for i := range queryRes.StateEvents {
|
for i := range queryRes.StateEvents {
|
||||||
|
@ -99,6 +117,7 @@ func MakeLeave(
|
||||||
}
|
}
|
||||||
|
|
||||||
// SendLeave implements the /send_leave API
|
// SendLeave implements the /send_leave API
|
||||||
|
// nolint:gocyclo
|
||||||
func SendLeave(
|
func SendLeave(
|
||||||
httpReq *http.Request,
|
httpReq *http.Request,
|
||||||
request *gomatrixserverlib.FederationRequest,
|
request *gomatrixserverlib.FederationRequest,
|
||||||
|
@ -149,6 +168,48 @@ func SendLeave(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if the user has already left. If so, no-op!
|
||||||
|
queryReq := &api.QueryLatestEventsAndStateRequest{
|
||||||
|
RoomID: roomID,
|
||||||
|
StateToFetch: []gomatrixserverlib.StateKeyTuple{
|
||||||
|
{
|
||||||
|
EventType: gomatrixserverlib.MRoomMember,
|
||||||
|
StateKey: *event.StateKey(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
queryRes := &api.QueryLatestEventsAndStateResponse{}
|
||||||
|
err = rsAPI.QueryLatestEventsAndState(httpReq.Context(), queryReq, queryRes)
|
||||||
|
if err != nil {
|
||||||
|
util.GetLogger(httpReq.Context()).WithError(err).Error("rsAPI.QueryLatestEventsAndState failed")
|
||||||
|
return jsonerror.InternalServerError()
|
||||||
|
}
|
||||||
|
// The room doesn't exist or we weren't ever joined to it. Might as well
|
||||||
|
// no-op here.
|
||||||
|
if !queryRes.RoomExists || len(queryRes.StateEvents) == 0 {
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: http.StatusOK,
|
||||||
|
JSON: struct{}{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Check if we're recycling a previous leave event.
|
||||||
|
if event.EventID() == queryRes.StateEvents[0].EventID() {
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: http.StatusOK,
|
||||||
|
JSON: struct{}{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// We are/were joined/invited/banned or something. Check if
|
||||||
|
// we can no-op here.
|
||||||
|
if len(queryRes.StateEvents) == 1 {
|
||||||
|
if mem, merr := queryRes.StateEvents[0].Membership(); merr == nil && mem == gomatrixserverlib.Leave {
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: http.StatusOK,
|
||||||
|
JSON: struct{}{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check that the event is signed by the server sending the request.
|
// Check that the event is signed by the server sending the request.
|
||||||
redacted := event.Redact()
|
redacted := event.Redact()
|
||||||
verifyRequests := []gomatrixserverlib.VerifyJSONRequest{{
|
verifyRequests := []gomatrixserverlib.VerifyJSONRequest{{
|
||||||
|
@ -174,7 +235,8 @@ func SendLeave(
|
||||||
if err != nil {
|
if err != nil {
|
||||||
util.GetLogger(httpReq.Context()).WithError(err).Error("event.Membership failed")
|
util.GetLogger(httpReq.Context()).WithError(err).Error("event.Membership failed")
|
||||||
return jsonerror.InternalServerError()
|
return jsonerror.InternalServerError()
|
||||||
} else if mem != gomatrixserverlib.Leave {
|
}
|
||||||
|
if mem != gomatrixserverlib.Leave {
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusBadRequest,
|
Code: http.StatusBadRequest,
|
||||||
JSON: jsonerror.BadJSON("The membership in the event content must be set to leave"),
|
JSON: jsonerror.BadJSON("The membership in the event content must be set to leave"),
|
||||||
|
|
|
@ -90,16 +90,10 @@ func Setup(
|
||||||
JSON: jsonerror.Forbidden("Forbidden by server ACLs"),
|
JSON: jsonerror.Forbidden("Forbidden by server ACLs"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
res := InviteV1(
|
return InviteV1(
|
||||||
httpReq, request, vars["roomID"], vars["eventID"],
|
httpReq, request, vars["roomID"], vars["eventID"],
|
||||||
cfg, rsAPI, keys,
|
cfg, rsAPI, keys,
|
||||||
)
|
)
|
||||||
return util.JSONResponse{
|
|
||||||
Code: res.Code,
|
|
||||||
JSON: []interface{}{
|
|
||||||
res.Code, res.JSON,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
)).Methods(http.MethodPut, http.MethodOptions)
|
)).Methods(http.MethodPut, http.MethodOptions)
|
||||||
|
|
||||||
|
|
|
@ -102,7 +102,8 @@ func (t *testRoomserverAPI) PerformInvite(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
req *api.PerformInviteRequest,
|
req *api.PerformInviteRequest,
|
||||||
res *api.PerformInviteResponse,
|
res *api.PerformInviteResponse,
|
||||||
) {
|
) error {
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *testRoomserverAPI) PerformJoin(
|
func (t *testRoomserverAPI) PerformJoin(
|
||||||
|
|
|
@ -36,6 +36,12 @@ type FederationSenderInternalAPI interface {
|
||||||
request *PerformLeaveRequest,
|
request *PerformLeaveRequest,
|
||||||
response *PerformLeaveResponse,
|
response *PerformLeaveResponse,
|
||||||
) error
|
) error
|
||||||
|
// Handle sending an invite to a remote server.
|
||||||
|
PerformInvite(
|
||||||
|
ctx context.Context,
|
||||||
|
request *PerformInviteRequest,
|
||||||
|
response *PerformInviteResponse,
|
||||||
|
) error
|
||||||
// Notifies the federation sender that these servers may be online and to retry sending messages.
|
// Notifies the federation sender that these servers may be online and to retry sending messages.
|
||||||
PerformServersAlive(
|
PerformServersAlive(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
|
@ -81,6 +87,16 @@ type PerformLeaveRequest struct {
|
||||||
type PerformLeaveResponse struct {
|
type PerformLeaveResponse struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type PerformInviteRequest struct {
|
||||||
|
RoomVersion gomatrixserverlib.RoomVersion `json:"room_version"`
|
||||||
|
Event gomatrixserverlib.HeaderedEvent `json:"event"`
|
||||||
|
InviteRoomState []gomatrixserverlib.InviteV2StrippedState `json:"invite_room_state"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PerformInviteResponse struct {
|
||||||
|
Event gomatrixserverlib.HeaderedEvent `json:"event"`
|
||||||
|
}
|
||||||
|
|
||||||
type PerformServersAliveRequest struct {
|
type PerformServersAliveRequest struct {
|
||||||
Servers []gomatrixserverlib.ServerName
|
Servers []gomatrixserverlib.ServerName
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,6 @@ import (
|
||||||
"github.com/matrix-org/dendrite/roomserver/api"
|
"github.com/matrix-org/dendrite/roomserver/api"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"github.com/tidwall/gjson"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// OutputRoomEventConsumer consumes events that originated in the room server.
|
// OutputRoomEventConsumer consumes events that originated in the room server.
|
||||||
|
@ -97,22 +96,6 @@ func (s *OutputRoomEventConsumer) onMessage(msg *sarama.ConsumerMessage) error {
|
||||||
}).Panicf("roomserver output log: write room event failure")
|
}).Panicf("roomserver output log: write room event failure")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
case api.OutputTypeNewInviteEvent:
|
|
||||||
ev := &output.NewInviteEvent.Event
|
|
||||||
log.WithFields(log.Fields{
|
|
||||||
"event_id": ev.EventID(),
|
|
||||||
"room_id": ev.RoomID(),
|
|
||||||
"state_key": ev.StateKey(),
|
|
||||||
}).Info("received invite event from roomserver")
|
|
||||||
|
|
||||||
if err := s.processInvite(*output.NewInviteEvent); err != nil {
|
|
||||||
// panic rather than continue with an inconsistent database
|
|
||||||
log.WithFields(log.Fields{
|
|
||||||
"event": string(ev.JSON()),
|
|
||||||
log.ErrorKey: err,
|
|
||||||
}).Panicf("roomserver output log: write invite event failure")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
log.WithField("type", output.Type).Debug(
|
log.WithField("type", output.Type).Debug(
|
||||||
"roomserver output log: ignoring unknown output type",
|
"roomserver output log: ignoring unknown output type",
|
||||||
|
@ -172,51 +155,6 @@ func (s *OutputRoomEventConsumer) processMessage(ore api.OutputNewRoomEvent) err
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// processInvite handles an invite event for sending over federation.
|
|
||||||
func (s *OutputRoomEventConsumer) processInvite(oie api.OutputNewInviteEvent) error {
|
|
||||||
// Don't try to reflect and resend invites that didn't originate from us.
|
|
||||||
if s.cfg.Matrix.ServerName != oie.Event.Origin() {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ignore invites that don't have state keys - they are invalid.
|
|
||||||
if oie.Event.StateKey() == nil {
|
|
||||||
return fmt.Errorf("event %q doesn't have state key", oie.Event.EventID())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't try to handle events that are actually destined for us.
|
|
||||||
stateKey := *oie.Event.StateKey()
|
|
||||||
_, destination, err := gomatrixserverlib.SplitID('@', stateKey)
|
|
||||||
if err != nil {
|
|
||||||
log.WithFields(log.Fields{
|
|
||||||
"event_id": oie.Event.EventID(),
|
|
||||||
"state_key": stateKey,
|
|
||||||
}).Info("failed to split destination from state key")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if s.cfg.Matrix.ServerName == destination {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to extract the room invite state. The roomserver will have stashed
|
|
||||||
// this for us in invite_room_state if it didn't already exist.
|
|
||||||
strippedState := []gomatrixserverlib.InviteV2StrippedState{}
|
|
||||||
if inviteRoomState := gjson.GetBytes(oie.Event.Unsigned(), "invite_room_state"); inviteRoomState.Exists() {
|
|
||||||
if err = json.Unmarshal([]byte(inviteRoomState.Raw), &strippedState); err != nil {
|
|
||||||
log.WithError(err).Warn("failed to extract invite_room_state from event unsigned")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build the invite request with the info we've got.
|
|
||||||
inviteReq, err := gomatrixserverlib.NewInviteV2Request(&oie.Event, strippedState)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("gomatrixserverlib.NewInviteV2Request: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send the event.
|
|
||||||
return s.queues.SendInvite(&inviteReq)
|
|
||||||
}
|
|
||||||
|
|
||||||
// joinedHostsAtEvent works out a list of matrix servers that were joined to
|
// joinedHostsAtEvent works out a list of matrix servers that were joined to
|
||||||
// the room at the event.
|
// the room at the event.
|
||||||
// It is important to use the state at the event for sending messages because:
|
// It is important to use the state at the event for sending messages because:
|
||||||
|
|
|
@ -296,6 +296,43 @@ func (r *FederationSenderInternalAPI) PerformLeave(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PerformLeaveRequest implements api.FederationSenderInternalAPI
|
||||||
|
func (r *FederationSenderInternalAPI) PerformInvite(
|
||||||
|
ctx context.Context,
|
||||||
|
request *api.PerformInviteRequest,
|
||||||
|
response *api.PerformInviteResponse,
|
||||||
|
) (err error) {
|
||||||
|
if request.Event.StateKey() == nil {
|
||||||
|
return errors.New("invite must be a state event")
|
||||||
|
}
|
||||||
|
|
||||||
|
_, destination, err := gomatrixserverlib.SplitID('@', *request.Event.StateKey())
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("gomatrixserverlib.SplitID: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.WithFields(logrus.Fields{
|
||||||
|
"event_id": request.Event.EventID(),
|
||||||
|
"user_id": *request.Event.StateKey(),
|
||||||
|
"room_id": request.Event.RoomID(),
|
||||||
|
"room_version": request.RoomVersion,
|
||||||
|
"destination": destination,
|
||||||
|
}).Info("Sending invite")
|
||||||
|
|
||||||
|
inviteReq, err := gomatrixserverlib.NewInviteV2Request(&request.Event, request.InviteRoomState)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("gomatrixserverlib.NewInviteV2Request: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
inviteRes, err := r.federation.SendInviteV2(ctx, destination, inviteReq)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("r.federation.SendInviteV2: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
response.Event = inviteRes.Event.Headered(request.RoomVersion)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// PerformServersAlive implements api.FederationSenderInternalAPI
|
// PerformServersAlive implements api.FederationSenderInternalAPI
|
||||||
func (r *FederationSenderInternalAPI) PerformServersAlive(
|
func (r *FederationSenderInternalAPI) PerformServersAlive(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
|
|
|
@ -18,6 +18,7 @@ const (
|
||||||
FederationSenderPerformDirectoryLookupRequestPath = "/federationsender/performDirectoryLookup"
|
FederationSenderPerformDirectoryLookupRequestPath = "/federationsender/performDirectoryLookup"
|
||||||
FederationSenderPerformJoinRequestPath = "/federationsender/performJoinRequest"
|
FederationSenderPerformJoinRequestPath = "/federationsender/performJoinRequest"
|
||||||
FederationSenderPerformLeaveRequestPath = "/federationsender/performLeaveRequest"
|
FederationSenderPerformLeaveRequestPath = "/federationsender/performLeaveRequest"
|
||||||
|
FederationSenderPerformInviteRequestPath = "/federationsender/performInviteRequest"
|
||||||
FederationSenderPerformServersAlivePath = "/federationsender/performServersAlive"
|
FederationSenderPerformServersAlivePath = "/federationsender/performServersAlive"
|
||||||
FederationSenderPerformBroadcastEDUPath = "/federationsender/performBroadcastEDU"
|
FederationSenderPerformBroadcastEDUPath = "/federationsender/performBroadcastEDU"
|
||||||
)
|
)
|
||||||
|
@ -49,6 +50,19 @@ func (h *httpFederationSenderInternalAPI) PerformLeave(
|
||||||
return httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response)
|
return httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle sending an invite to a remote server.
|
||||||
|
func (h *httpFederationSenderInternalAPI) PerformInvite(
|
||||||
|
ctx context.Context,
|
||||||
|
request *api.PerformInviteRequest,
|
||||||
|
response *api.PerformInviteResponse,
|
||||||
|
) error {
|
||||||
|
span, ctx := opentracing.StartSpanFromContext(ctx, "PerformInviteRequest")
|
||||||
|
defer span.Finish()
|
||||||
|
|
||||||
|
apiURL := h.federationSenderURL + FederationSenderPerformInviteRequestPath
|
||||||
|
return httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response)
|
||||||
|
}
|
||||||
|
|
||||||
func (h *httpFederationSenderInternalAPI) PerformServersAlive(
|
func (h *httpFederationSenderInternalAPI) PerformServersAlive(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
request *api.PerformServersAliveRequest,
|
request *api.PerformServersAliveRequest,
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// AddRoutes adds the FederationSenderInternalAPI handlers to the http.ServeMux.
|
// AddRoutes adds the FederationSenderInternalAPI handlers to the http.ServeMux.
|
||||||
|
// nolint:gocyclo
|
||||||
func AddRoutes(intAPI api.FederationSenderInternalAPI, internalAPIMux *mux.Router) {
|
func AddRoutes(intAPI api.FederationSenderInternalAPI, internalAPIMux *mux.Router) {
|
||||||
internalAPIMux.Handle(
|
internalAPIMux.Handle(
|
||||||
FederationSenderQueryJoinedHostServerNamesInRoomPath,
|
FederationSenderQueryJoinedHostServerNamesInRoomPath,
|
||||||
|
@ -52,6 +53,20 @@ func AddRoutes(intAPI api.FederationSenderInternalAPI, internalAPIMux *mux.Route
|
||||||
return util.JSONResponse{Code: http.StatusOK, JSON: &response}
|
return util.JSONResponse{Code: http.StatusOK, JSON: &response}
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
internalAPIMux.Handle(
|
||||||
|
FederationSenderPerformInviteRequestPath,
|
||||||
|
httputil.MakeInternalAPI("PerformInviteRequest", func(req *http.Request) util.JSONResponse {
|
||||||
|
var request api.PerformInviteRequest
|
||||||
|
var response api.PerformInviteResponse
|
||||||
|
if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
|
||||||
|
return util.MessageResponse(http.StatusBadRequest, err.Error())
|
||||||
|
}
|
||||||
|
if err := intAPI.PerformInvite(req.Context(), &request, &response); err != nil {
|
||||||
|
return util.ErrorResponse(err)
|
||||||
|
}
|
||||||
|
return util.JSONResponse{Code: http.StatusOK, JSON: &response}
|
||||||
|
}),
|
||||||
|
)
|
||||||
internalAPIMux.Handle(
|
internalAPIMux.Handle(
|
||||||
FederationSenderPerformDirectoryLookupRequestPath,
|
FederationSenderPerformDirectoryLookupRequestPath,
|
||||||
httputil.MakeInternalAPI("PerformDirectoryLookupRequest", func(req *http.Request) util.JSONResponse {
|
httputil.MakeInternalAPI("PerformDirectoryLookupRequest", func(req *http.Request) util.JSONResponse {
|
||||||
|
|
|
@ -52,11 +52,9 @@ type destinationQueue struct {
|
||||||
running atomic.Bool // is the queue worker running?
|
running atomic.Bool // is the queue worker running?
|
||||||
backingOff atomic.Bool // true if we're backing off
|
backingOff atomic.Bool // true if we're backing off
|
||||||
statistics *statistics.ServerStatistics // statistics about this remote server
|
statistics *statistics.ServerStatistics // statistics about this remote server
|
||||||
incomingInvites chan *gomatrixserverlib.InviteV2Request // invites to send
|
|
||||||
transactionIDMutex sync.Mutex // protects transactionID
|
transactionIDMutex sync.Mutex // protects transactionID
|
||||||
transactionID gomatrixserverlib.TransactionID // last transaction ID
|
transactionID gomatrixserverlib.TransactionID // last transaction ID
|
||||||
transactionCount atomic.Int32 // how many events in this transaction so far
|
transactionCount atomic.Int32 // how many events in this transaction so far
|
||||||
pendingInvites []*gomatrixserverlib.InviteV2Request // owned by backgroundSend
|
|
||||||
notifyPDUs chan bool // interrupts idle wait for PDUs
|
notifyPDUs chan bool // interrupts idle wait for PDUs
|
||||||
notifyEDUs chan bool // interrupts idle wait for EDUs
|
notifyEDUs chan bool // interrupts idle wait for EDUs
|
||||||
interruptBackoff chan bool // interrupts backoff
|
interruptBackoff chan bool // interrupts backoff
|
||||||
|
@ -138,18 +136,6 @@ func (oq *destinationQueue) sendEDU(receipt *shared.Receipt) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// sendInvite adds the invite event to the pending queue for the
|
|
||||||
// destination. If the queue is empty then it starts a background
|
|
||||||
// goroutine to start sending events to that destination.
|
|
||||||
func (oq *destinationQueue) sendInvite(ev *gomatrixserverlib.InviteV2Request) {
|
|
||||||
if oq.statistics.Blacklisted() {
|
|
||||||
// If the destination is blacklisted then drop the event.
|
|
||||||
return
|
|
||||||
}
|
|
||||||
oq.wakeQueueIfNeeded()
|
|
||||||
oq.incomingInvites <- ev
|
|
||||||
}
|
|
||||||
|
|
||||||
// wakeQueueIfNeeded will wake up the destination queue if it is
|
// wakeQueueIfNeeded will wake up the destination queue if it is
|
||||||
// not already running. If it is running but it is backing off
|
// not already running. If it is running but it is backing off
|
||||||
// then we will interrupt the backoff, causing any federation
|
// then we will interrupt the backoff, causing any federation
|
||||||
|
@ -234,23 +220,6 @@ func (oq *destinationQueue) backgroundSend() {
|
||||||
// We were woken up because there are new PDUs waiting in the
|
// We were woken up because there are new PDUs waiting in the
|
||||||
// database.
|
// database.
|
||||||
pendingEDUs = true
|
pendingEDUs = true
|
||||||
case invite := <-oq.incomingInvites:
|
|
||||||
// There's no strict ordering requirement for invites like
|
|
||||||
// there is for transactions, so we put the invite onto the
|
|
||||||
// front of the queue. This means that if an invite that is
|
|
||||||
// stuck failing already, that it won't block our new invite
|
|
||||||
// from being sent.
|
|
||||||
oq.pendingInvites = append(
|
|
||||||
[]*gomatrixserverlib.InviteV2Request{invite},
|
|
||||||
oq.pendingInvites...,
|
|
||||||
)
|
|
||||||
// If there are any more things waiting in the channel queue
|
|
||||||
// then read them. This is safe because we guarantee only
|
|
||||||
// having one goroutine per destination queue, so the channel
|
|
||||||
// isn't being consumed anywhere else.
|
|
||||||
for len(oq.incomingInvites) > 0 {
|
|
||||||
oq.pendingInvites = append(oq.pendingInvites, <-oq.incomingInvites)
|
|
||||||
}
|
|
||||||
case <-time.After(queueIdleTimeout):
|
case <-time.After(queueIdleTimeout):
|
||||||
// The worker is idle so stop the goroutine. It'll get
|
// The worker is idle so stop the goroutine. It'll get
|
||||||
// restarted automatically the next time we have an event to
|
// restarted automatically the next time we have an event to
|
||||||
|
@ -266,7 +235,6 @@ func (oq *destinationQueue) backgroundSend() {
|
||||||
// It's been suggested that we should give up because the backoff
|
// It's been suggested that we should give up because the backoff
|
||||||
// has exceeded a maximum allowable value. Clean up the in-memory
|
// has exceeded a maximum allowable value. Clean up the in-memory
|
||||||
// buffers at this point. The PDU clean-up is already on a defer.
|
// buffers at this point. The PDU clean-up is already on a defer.
|
||||||
oq.cleanPendingInvites()
|
|
||||||
log.Warnf("Blacklisting %q due to exceeding backoff threshold", oq.destination)
|
log.Warnf("Blacklisting %q due to exceeding backoff threshold", oq.destination)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -284,33 +252,7 @@ func (oq *destinationQueue) backgroundSend() {
|
||||||
oq.statistics.Success()
|
oq.statistics.Success()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try sending the next invite and see what happens.
|
|
||||||
if len(oq.pendingInvites) > 0 {
|
|
||||||
sent, ierr := oq.nextInvites(oq.pendingInvites)
|
|
||||||
if ierr != nil {
|
|
||||||
// We failed to send the transaction. Mark it as a failure.
|
|
||||||
oq.statistics.Failure()
|
|
||||||
} else if sent > 0 {
|
|
||||||
// If we successfully sent the invites then clear out
|
|
||||||
// the pending invites.
|
|
||||||
oq.statistics.Success()
|
|
||||||
// Reallocate so that the underlying array can be GC'd, as
|
|
||||||
// opposed to growing forever.
|
|
||||||
oq.cleanPendingInvites()
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// cleanPendingInvites cleans out the pending invite buffer,
|
|
||||||
// removing all references so that the underlying objects can
|
|
||||||
// be GC'd.
|
|
||||||
func (oq *destinationQueue) cleanPendingInvites() {
|
|
||||||
for i := 0; i < len(oq.pendingInvites); i++ {
|
|
||||||
oq.pendingInvites[i] = nil
|
|
||||||
}
|
|
||||||
oq.pendingInvites = []*gomatrixserverlib.InviteV2Request{}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// nextTransaction creates a new transaction from the pending event
|
// nextTransaction creates a new transaction from the pending event
|
||||||
|
@ -427,66 +369,3 @@ func (oq *destinationQueue) nextTransaction() (bool, error) {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// nextInvite takes pending invite events from the queue and sends
|
|
||||||
// them. Returns true if a transaction was sent or false otherwise.
|
|
||||||
func (oq *destinationQueue) nextInvites(
|
|
||||||
pendingInvites []*gomatrixserverlib.InviteV2Request,
|
|
||||||
) (int, error) {
|
|
||||||
done := 0
|
|
||||||
for _, inviteReq := range pendingInvites {
|
|
||||||
ev, roomVersion := inviteReq.Event(), inviteReq.RoomVersion()
|
|
||||||
|
|
||||||
log.WithFields(log.Fields{
|
|
||||||
"event_id": ev.EventID(),
|
|
||||||
"room_version": roomVersion,
|
|
||||||
"destination": oq.destination,
|
|
||||||
}).Info("sending invite")
|
|
||||||
|
|
||||||
inviteRes, err := oq.client.SendInviteV2(
|
|
||||||
context.TODO(),
|
|
||||||
oq.destination,
|
|
||||||
*inviteReq,
|
|
||||||
)
|
|
||||||
switch e := err.(type) {
|
|
||||||
case nil:
|
|
||||||
done++
|
|
||||||
case gomatrix.HTTPError:
|
|
||||||
log.WithFields(log.Fields{
|
|
||||||
"event_id": ev.EventID(),
|
|
||||||
"state_key": ev.StateKey(),
|
|
||||||
"destination": oq.destination,
|
|
||||||
"status_code": e.Code,
|
|
||||||
}).WithError(err).Error("failed to send invite due to HTTP error")
|
|
||||||
// Check whether we should do something about the error or
|
|
||||||
// just accept it as unavoidable.
|
|
||||||
if e.Code >= 400 && e.Code <= 499 {
|
|
||||||
// We tried but the remote side has sent back a client error.
|
|
||||||
// It's no use retrying because it will happen again.
|
|
||||||
done++
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
return done, err
|
|
||||||
default:
|
|
||||||
log.WithFields(log.Fields{
|
|
||||||
"event_id": ev.EventID(),
|
|
||||||
"state_key": ev.StateKey(),
|
|
||||||
"destination": oq.destination,
|
|
||||||
}).WithError(err).Error("failed to send invite")
|
|
||||||
return done, err
|
|
||||||
}
|
|
||||||
|
|
||||||
invEv := inviteRes.Event.Sign(string(oq.signing.ServerName), oq.signing.KeyID, oq.signing.PrivateKey).Headered(roomVersion)
|
|
||||||
_, err = api.SendEvents(context.TODO(), oq.rsAPI, []gomatrixserverlib.HeaderedEvent{invEv}, oq.signing.ServerName, nil)
|
|
||||||
if err != nil {
|
|
||||||
log.WithFields(log.Fields{
|
|
||||||
"event_id": ev.EventID(),
|
|
||||||
"state_key": ev.StateKey(),
|
|
||||||
"destination": oq.destination,
|
|
||||||
}).WithError(err).Error("failed to return signed invite to roomserver")
|
|
||||||
return done, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return done, nil
|
|
||||||
}
|
|
||||||
|
|
|
@ -108,7 +108,6 @@ func (oqs *OutgoingQueues) getQueue(destination gomatrixserverlib.ServerName) *d
|
||||||
destination: destination,
|
destination: destination,
|
||||||
client: oqs.client,
|
client: oqs.client,
|
||||||
statistics: oqs.statistics.ForServer(destination),
|
statistics: oqs.statistics.ForServer(destination),
|
||||||
incomingInvites: make(chan *gomatrixserverlib.InviteV2Request, 128),
|
|
||||||
notifyPDUs: make(chan bool, 1),
|
notifyPDUs: make(chan bool, 1),
|
||||||
notifyEDUs: make(chan bool, 1),
|
notifyEDUs: make(chan bool, 1),
|
||||||
interruptBackoff: make(chan bool),
|
interruptBackoff: make(chan bool),
|
||||||
|
@ -178,51 +177,6 @@ func (oqs *OutgoingQueues) SendEvent(
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SendEvent sends an event to the destinations
|
|
||||||
func (oqs *OutgoingQueues) SendInvite(
|
|
||||||
inviteReq *gomatrixserverlib.InviteV2Request,
|
|
||||||
) error {
|
|
||||||
ev := inviteReq.Event()
|
|
||||||
stateKey := ev.StateKey()
|
|
||||||
if stateKey == nil {
|
|
||||||
log.WithFields(log.Fields{
|
|
||||||
"event_id": ev.EventID(),
|
|
||||||
}).Info("Invite had no state key, dropping")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
_, destination, err := gomatrixserverlib.SplitID('@', *stateKey)
|
|
||||||
if err != nil {
|
|
||||||
log.WithFields(log.Fields{
|
|
||||||
"event_id": ev.EventID(),
|
|
||||||
"state_key": stateKey,
|
|
||||||
}).Info("Failed to split destination from state key")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if stateapi.IsServerBannedFromRoom(
|
|
||||||
context.TODO(),
|
|
||||||
oqs.stateAPI,
|
|
||||||
ev.RoomID(),
|
|
||||||
destination,
|
|
||||||
) {
|
|
||||||
log.WithFields(log.Fields{
|
|
||||||
"room_id": ev.RoomID(),
|
|
||||||
"destination": destination,
|
|
||||||
}).Info("Dropping invite to server which is prohibited by ACLs")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
log.WithFields(log.Fields{
|
|
||||||
"event_id": ev.EventID(),
|
|
||||||
"server_name": destination,
|
|
||||||
}).Info("Sending invite")
|
|
||||||
|
|
||||||
oqs.getQueue(destination).sendInvite(inviteReq)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SendEDU sends an EDU event to the destinations.
|
// SendEDU sends an EDU event to the destinations.
|
||||||
func (oqs *OutgoingQueues) SendEDU(
|
func (oqs *OutgoingQueues) SendEDU(
|
||||||
e *gomatrixserverlib.EDU, origin gomatrixserverlib.ServerName,
|
e *gomatrixserverlib.EDU, origin gomatrixserverlib.ServerName,
|
||||||
|
|
4
go.mod
4
go.mod
|
@ -2,9 +2,7 @@ module github.com/matrix-org/dendrite
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/Shopify/sarama v1.26.1
|
github.com/Shopify/sarama v1.26.1
|
||||||
github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible
|
|
||||||
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd // indirect
|
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd // indirect
|
||||||
github.com/ghodss/yaml v1.0.0
|
|
||||||
github.com/gologme/log v1.2.0
|
github.com/gologme/log v1.2.0
|
||||||
github.com/gorilla/mux v1.7.3
|
github.com/gorilla/mux v1.7.3
|
||||||
github.com/hashicorp/golang-lru v0.5.4
|
github.com/hashicorp/golang-lru v0.5.4
|
||||||
|
@ -23,7 +21,7 @@ require (
|
||||||
github.com/matrix-org/go-http-js-libp2p v0.0.0-20200518170932-783164aeeda4
|
github.com/matrix-org/go-http-js-libp2p v0.0.0-20200518170932-783164aeeda4
|
||||||
github.com/matrix-org/go-sqlite3-js v0.0.0-20200522092705-bc8506ccbcf3
|
github.com/matrix-org/go-sqlite3-js v0.0.0-20200522092705-bc8506ccbcf3
|
||||||
github.com/matrix-org/gomatrix v0.0.0-20190528120928-7df988a63f26
|
github.com/matrix-org/gomatrix v0.0.0-20190528120928-7df988a63f26
|
||||||
github.com/matrix-org/gomatrixserverlib v0.0.0-20200807145008-79c173b65786
|
github.com/matrix-org/gomatrixserverlib v0.0.0-20200817100842-9d02141812f2
|
||||||
github.com/matrix-org/naffka v0.0.0-20200422140631-181f1ee7401f
|
github.com/matrix-org/naffka v0.0.0-20200422140631-181f1ee7401f
|
||||||
github.com/matrix-org/util v0.0.0-20200807132607-55161520e1d4
|
github.com/matrix-org/util v0.0.0-20200807132607-55161520e1d4
|
||||||
github.com/mattn/go-sqlite3 v2.0.2+incompatible
|
github.com/mattn/go-sqlite3 v2.0.2+incompatible
|
||||||
|
|
7
go.sum
7
go.sum
|
@ -51,9 +51,6 @@ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL
|
||||||
github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE=
|
github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE=
|
||||||
github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=
|
github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=
|
||||||
github.com/cheggaaa/pb/v3 v3.0.4/go.mod h1:7rgWxLrAUcFMkvJuv09+DYi7mMUYi8nO9iOWcvGJPfw=
|
github.com/cheggaaa/pb/v3 v3.0.4/go.mod h1:7rgWxLrAUcFMkvJuv09+DYi7mMUYi8nO9iOWcvGJPfw=
|
||||||
github.com/circonus-labs/circonus-gometrics v1.2.0 h1:Kqa/+nIJhqFJ12B07aeekgC6F95J7yYgEtpD57NQzrE=
|
|
||||||
github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible h1:C29Ae4G5GtYyYMm1aztcyj/J5ckgJm2zwdDajFbx1NY=
|
|
||||||
github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
|
|
||||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd h1:qMd81Ts1T2OTKmB4acZcyKaMtRnY5Y44NuXGX2GFJ1w=
|
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd h1:qMd81Ts1T2OTKmB4acZcyKaMtRnY5Y44NuXGX2GFJ1w=
|
||||||
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
|
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
|
||||||
|
@ -425,8 +422,8 @@ github.com/matrix-org/go-sqlite3-js v0.0.0-20200522092705-bc8506ccbcf3 h1:Yb+Wlf
|
||||||
github.com/matrix-org/go-sqlite3-js v0.0.0-20200522092705-bc8506ccbcf3/go.mod h1:e+cg2q7C7yE5QnAXgzo512tgFh1RbQLC0+jozuegKgo=
|
github.com/matrix-org/go-sqlite3-js v0.0.0-20200522092705-bc8506ccbcf3/go.mod h1:e+cg2q7C7yE5QnAXgzo512tgFh1RbQLC0+jozuegKgo=
|
||||||
github.com/matrix-org/gomatrix v0.0.0-20190528120928-7df988a63f26 h1:Hr3zjRsq2bhrnp3Ky1qgx/fzCtCALOoGYylh2tpS9K4=
|
github.com/matrix-org/gomatrix v0.0.0-20190528120928-7df988a63f26 h1:Hr3zjRsq2bhrnp3Ky1qgx/fzCtCALOoGYylh2tpS9K4=
|
||||||
github.com/matrix-org/gomatrix v0.0.0-20190528120928-7df988a63f26/go.mod h1:3fxX6gUjWyI/2Bt7J1OLhpCzOfO/bB3AiX0cJtEKud0=
|
github.com/matrix-org/gomatrix v0.0.0-20190528120928-7df988a63f26/go.mod h1:3fxX6gUjWyI/2Bt7J1OLhpCzOfO/bB3AiX0cJtEKud0=
|
||||||
github.com/matrix-org/gomatrixserverlib v0.0.0-20200807145008-79c173b65786 h1:HQclx5J2CrCBqP88t5Di9IkVDJZn5+h4ZL48viY4FJ4=
|
github.com/matrix-org/gomatrixserverlib v0.0.0-20200817100842-9d02141812f2 h1:9wKwfd5KDcXuqZ7/kAaYe0QM4DGM+2awjjvXQtrDa6k=
|
||||||
github.com/matrix-org/gomatrixserverlib v0.0.0-20200807145008-79c173b65786/go.mod h1:JsAzE1Ll3+gDWS9JSUHPJiiyAksvOOnGWF2nXdg4ZzU=
|
github.com/matrix-org/gomatrixserverlib v0.0.0-20200817100842-9d02141812f2/go.mod h1:JsAzE1Ll3+gDWS9JSUHPJiiyAksvOOnGWF2nXdg4ZzU=
|
||||||
github.com/matrix-org/naffka v0.0.0-20200422140631-181f1ee7401f h1:pRz4VTiRCO4zPlEMc3ESdUOcW4PXHH4Kj+YDz1XyE+Y=
|
github.com/matrix-org/naffka v0.0.0-20200422140631-181f1ee7401f h1:pRz4VTiRCO4zPlEMc3ESdUOcW4PXHH4Kj+YDz1XyE+Y=
|
||||||
github.com/matrix-org/naffka v0.0.0-20200422140631-181f1ee7401f/go.mod h1:y0oDTjZDv5SM9a2rp3bl+CU+bvTRINQsdb7YlDql5Go=
|
github.com/matrix-org/naffka v0.0.0-20200422140631-181f1ee7401f/go.mod h1:y0oDTjZDv5SM9a2rp3bl+CU+bvTRINQsdb7YlDql5Go=
|
||||||
github.com/matrix-org/util v0.0.0-20190711121626-527ce5ddefc7 h1:ntrLa/8xVzeSs8vHFHK25k0C+NV74sYMJnNSg5NoSRo=
|
github.com/matrix-org/util v0.0.0-20190711121626-527ce5ddefc7 h1:ntrLa/8xVzeSs8vHFHK25k0C+NV74sYMJnNSg5NoSRo=
|
||||||
|
|
|
@ -22,7 +22,7 @@ type RoomserverInternalAPI interface {
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
req *PerformInviteRequest,
|
req *PerformInviteRequest,
|
||||||
res *PerformInviteResponse,
|
res *PerformInviteResponse,
|
||||||
)
|
) error
|
||||||
|
|
||||||
PerformJoin(
|
PerformJoin(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
|
|
|
@ -33,9 +33,9 @@ func (t *RoomserverInternalAPITrace) PerformInvite(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
req *PerformInviteRequest,
|
req *PerformInviteRequest,
|
||||||
res *PerformInviteResponse,
|
res *PerformInviteResponse,
|
||||||
) {
|
) error {
|
||||||
t.Impl.PerformInvite(ctx, req, res)
|
|
||||||
util.GetLogger(ctx).Infof("PerformInvite req=%+v res=%+v", js(req), js(res))
|
util.GetLogger(ctx).Infof("PerformInvite req=%+v res=%+v", js(req), js(res))
|
||||||
|
return t.Impl.PerformInvite(ctx, req, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *RoomserverInternalAPITrace) PerformJoin(
|
func (t *RoomserverInternalAPITrace) PerformJoin(
|
||||||
|
|
|
@ -105,7 +105,6 @@ type PerformInviteRequest struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type PerformInviteResponse struct {
|
type PerformInviteResponse struct {
|
||||||
// If non-nil, the invite request failed. Contains more information why it failed.
|
|
||||||
Error *PerformError
|
Error *PerformError
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@ package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
"github.com/matrix-org/util"
|
"github.com/matrix-org/util"
|
||||||
|
@ -99,21 +100,41 @@ func SendInvite(
|
||||||
rsAPI RoomserverInternalAPI, inviteEvent gomatrixserverlib.HeaderedEvent,
|
rsAPI RoomserverInternalAPI, inviteEvent gomatrixserverlib.HeaderedEvent,
|
||||||
inviteRoomState []gomatrixserverlib.InviteV2StrippedState,
|
inviteRoomState []gomatrixserverlib.InviteV2StrippedState,
|
||||||
sendAsServer gomatrixserverlib.ServerName, txnID *TransactionID,
|
sendAsServer gomatrixserverlib.ServerName, txnID *TransactionID,
|
||||||
) *PerformError {
|
) error {
|
||||||
request := PerformInviteRequest{
|
// Start by sending the invite request into the roomserver. This will
|
||||||
|
// trigger the federation request amongst other things if needed.
|
||||||
|
request := &PerformInviteRequest{
|
||||||
Event: inviteEvent,
|
Event: inviteEvent,
|
||||||
InviteRoomState: inviteRoomState,
|
InviteRoomState: inviteRoomState,
|
||||||
RoomVersion: inviteEvent.RoomVersion,
|
RoomVersion: inviteEvent.RoomVersion,
|
||||||
SendAsServer: string(sendAsServer),
|
SendAsServer: string(sendAsServer),
|
||||||
TransactionID: txnID,
|
TransactionID: txnID,
|
||||||
}
|
}
|
||||||
var response PerformInviteResponse
|
response := &PerformInviteResponse{}
|
||||||
rsAPI.PerformInvite(ctx, &request, &response)
|
if err := rsAPI.PerformInvite(ctx, request, response); err != nil {
|
||||||
// we need to do this because many places people will use `var err error` as the return
|
return fmt.Errorf("rsAPI.PerformInvite: %w", err)
|
||||||
// arg and a nil interface != nil pointer to a concrete interface (in this case PerformError)
|
}
|
||||||
if response.Error != nil && response.Error.Msg != "" {
|
if response.Error != nil {
|
||||||
return response.Error
|
return response.Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Now send the invite event into the roomserver. If the room is known
|
||||||
|
// locally then this will succeed, notifying existing users in the room
|
||||||
|
// about the new invite. If the room isn't known locally then this will
|
||||||
|
// fail - and that's also OK.
|
||||||
|
inputReq := &InputRoomEventsRequest{
|
||||||
|
InputRoomEvents: []InputRoomEvent{
|
||||||
|
{
|
||||||
|
Kind: KindNew,
|
||||||
|
Event: inviteEvent,
|
||||||
|
AuthEventIDs: inviteEvent.AuthEventIDs(),
|
||||||
|
SendAsServer: string(sendAsServer),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
inputRes := &InputRoomEventsResponse{}
|
||||||
|
_ = rsAPI.InputRoomEvents(ctx, inputReq, inputRes)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,9 +2,9 @@ package internal
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
federationSenderAPI "github.com/matrix-org/dendrite/federationsender/api"
|
||||||
"github.com/matrix-org/dendrite/internal/sqlutil"
|
"github.com/matrix-org/dendrite/internal/sqlutil"
|
||||||
"github.com/matrix-org/dendrite/roomserver/api"
|
"github.com/matrix-org/dendrite/roomserver/api"
|
||||||
"github.com/matrix-org/dendrite/roomserver/state"
|
"github.com/matrix-org/dendrite/roomserver/state"
|
||||||
|
@ -14,73 +14,50 @@ import (
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PerformInvite handles inviting to matrix rooms, including over federation by talking to the federationsender.
|
// nolint:gocyclo
|
||||||
func (r *RoomserverInternalAPI) PerformInvite(
|
func (r *RoomserverInternalAPI) PerformInvite(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
req *api.PerformInviteRequest,
|
req *api.PerformInviteRequest,
|
||||||
res *api.PerformInviteResponse,
|
res *api.PerformInviteResponse,
|
||||||
) {
|
|
||||||
err := r.performInvite(ctx, req)
|
|
||||||
if err != nil {
|
|
||||||
perr, ok := err.(*api.PerformError)
|
|
||||||
if ok {
|
|
||||||
res.Error = perr
|
|
||||||
} else {
|
|
||||||
res.Error = &api.PerformError{
|
|
||||||
Msg: err.Error(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *RoomserverInternalAPI) performInvite(ctx context.Context,
|
|
||||||
req *api.PerformInviteRequest,
|
|
||||||
) error {
|
) error {
|
||||||
loopback, err := r.processInviteEvent(ctx, r, req)
|
event := req.Event
|
||||||
if err != nil {
|
if event.StateKey() == nil {
|
||||||
return err
|
return fmt.Errorf("invite must be a state event")
|
||||||
}
|
|
||||||
// The processInviteEvent function can optionally return a
|
|
||||||
// loopback room event containing the invite, for local invites.
|
|
||||||
// If it does, we should process it with the room events below.
|
|
||||||
if loopback != nil {
|
|
||||||
var loopbackRes api.InputRoomEventsResponse
|
|
||||||
err := r.InputRoomEvents(ctx, &api.InputRoomEventsRequest{
|
|
||||||
InputRoomEvents: []api.InputRoomEvent{*loopback},
|
|
||||||
}, &loopbackRes)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// nolint:gocyclo
|
|
||||||
func (r *RoomserverInternalAPI) processInviteEvent(
|
|
||||||
ctx context.Context,
|
|
||||||
ow *RoomserverInternalAPI,
|
|
||||||
input *api.PerformInviteRequest,
|
|
||||||
) (*api.InputRoomEvent, error) {
|
|
||||||
if input.Event.StateKey() == nil {
|
|
||||||
return nil, fmt.Errorf("invite must be a state event")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
roomID := input.Event.RoomID()
|
roomID := event.RoomID()
|
||||||
targetUserID := *input.Event.StateKey()
|
targetUserID := *event.StateKey()
|
||||||
|
|
||||||
log.WithFields(log.Fields{
|
log.WithFields(log.Fields{
|
||||||
"event_id": input.Event.EventID(),
|
"event_id": event.EventID(),
|
||||||
"room_id": roomID,
|
"room_id": roomID,
|
||||||
"room_version": input.RoomVersion,
|
"room_version": req.RoomVersion,
|
||||||
"target_user_id": targetUserID,
|
"target_user_id": targetUserID,
|
||||||
}).Info("processing invite event")
|
}).Info("processing invite event")
|
||||||
|
|
||||||
_, domain, _ := gomatrixserverlib.SplitID('@', targetUserID)
|
_, domain, _ := gomatrixserverlib.SplitID('@', targetUserID)
|
||||||
isTargetLocalUser := domain == r.Cfg.Matrix.ServerName
|
isTargetLocal := domain == r.Cfg.Matrix.ServerName
|
||||||
|
isOriginLocal := event.Origin() == r.Cfg.Matrix.ServerName
|
||||||
|
|
||||||
updater, err := r.DB.MembershipUpdater(ctx, roomID, targetUserID, isTargetLocalUser, input.RoomVersion)
|
inviteState := req.InviteRoomState
|
||||||
|
if len(inviteState) == 0 {
|
||||||
|
if is, err := buildInviteStrippedState(ctx, r.DB, req); err == nil {
|
||||||
|
inviteState = is
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(inviteState) == 0 {
|
||||||
|
if err := event.SetUnsignedField("invite_room_state", struct{}{}); err != nil {
|
||||||
|
return fmt.Errorf("event.SetUnsignedField: %w", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err := event.SetUnsignedField("invite_room_state", inviteState); err != nil {
|
||||||
|
return fmt.Errorf("event.SetUnsignedField: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updater, err := r.DB.MembershipUpdater(ctx, roomID, targetUserID, isTargetLocal, req.RoomVersion)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return fmt.Errorf("r.DB.MembershipUpdater: %w", err)
|
||||||
}
|
}
|
||||||
succeeded := false
|
succeeded := false
|
||||||
defer func() {
|
defer func() {
|
||||||
|
@ -118,109 +95,66 @@ func (r *RoomserverInternalAPI) processInviteEvent(
|
||||||
// For now we will implement option 2. Since in the abesence of a retry
|
// 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
|
// mechanism it will be equivalent to option 1, and we don't have a
|
||||||
// signalling mechanism to implement option 3.
|
// signalling mechanism to implement option 3.
|
||||||
return nil, &api.PerformError{
|
res.Error = &api.PerformError{
|
||||||
Code: api.PerformErrorNoOperation,
|
Code: api.PerformErrorNotAllowed,
|
||||||
Msg: "user is already joined to room",
|
Msg: "User is already joined to room",
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Normally, with a federated invite, the federation sender would do
|
if isOriginLocal {
|
||||||
// the /v2/invite request (in which the remote server signs the invite)
|
|
||||||
// and then the signed event gets sent back to the roomserver as an input
|
|
||||||
// event. When the invite is local, we don't interact with the federation
|
|
||||||
// sender therefore we need to generate the loopback invite event for
|
|
||||||
// the room ourselves.
|
|
||||||
loopback, err := localInviteLoopback(ow, input)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
event := input.Event.Unwrap()
|
|
||||||
|
|
||||||
// check that the user is allowed to do this. We can only do this check if it is
|
// check that the user is allowed to do this. We can only do this check if it is
|
||||||
// a local invite as we have the auth events, else we have to take it on trust.
|
// a local invite as we have the auth events, else we have to take it on trust.
|
||||||
if loopback != nil {
|
_, err = checkAuthEvents(ctx, r.DB, req.Event, req.Event.AuthEventIDs())
|
||||||
_, err = checkAuthEvents(ctx, r.DB, input.Event, input.Event.AuthEventIDs())
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.WithError(err).WithField("event_id", event.EventID()).WithField("auth_event_ids", event.AuthEventIDs()).Error(
|
log.WithError(err).WithField("event_id", event.EventID()).WithField("auth_event_ids", event.AuthEventIDs()).Error(
|
||||||
"processInviteEvent.checkAuthEvents failed for event",
|
"processInviteEvent.checkAuthEvents failed for event",
|
||||||
)
|
)
|
||||||
if _, ok := err.(*gomatrixserverlib.NotAllowed); ok {
|
if _, ok := err.(*gomatrixserverlib.NotAllowed); ok {
|
||||||
return nil, &api.PerformError{
|
res.Error = &api.PerformError{
|
||||||
Msg: err.Error(),
|
Msg: err.Error(),
|
||||||
Code: api.PerformErrorNotAllowed,
|
Code: api.PerformErrorNotAllowed,
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
return nil, err
|
return fmt.Errorf("checkAuthEvents: %w", 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 := &federationSenderAPI.PerformInviteRequest{
|
||||||
|
RoomVersion: req.RoomVersion,
|
||||||
|
Event: req.Event,
|
||||||
|
InviteRoomState: inviteState,
|
||||||
|
}
|
||||||
|
fsRes := &federationSenderAPI.PerformInviteResponse{}
|
||||||
|
if err = r.fsAPI.PerformInvite(ctx, fsReq, fsRes); err != nil {
|
||||||
|
res.Error = &api.PerformError{
|
||||||
|
Msg: err.Error(),
|
||||||
|
Code: api.PerformErrorNoOperation,
|
||||||
|
}
|
||||||
|
log.WithError(err).WithField("event_id", event.EventID()).Error("r.fsAPI.PerformInvite failed")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
event = fsRes.Event
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(input.InviteRoomState) > 0 {
|
unwrapped := event.Unwrap()
|
||||||
// If we were supplied with some invite room state already (which is
|
outputUpdates, err := updateToInviteMembership(updater, &unwrapped, nil, req.Event.RoomVersion)
|
||||||
// most likely to be if the event came in over federation) then use
|
|
||||||
// that.
|
|
||||||
if err = event.SetUnsignedField("invite_room_state", input.InviteRoomState); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// There's no invite room state, so let's have a go at building it
|
|
||||||
// up from local data (which is most likely to be if the event came
|
|
||||||
// from the CS API). If we know about the room then we can insert
|
|
||||||
// the invite room state, if we don't then we just fail quietly.
|
|
||||||
if irs, ierr := buildInviteStrippedState(ctx, r.DB, input); ierr == nil {
|
|
||||||
if err = event.SetUnsignedField("invite_room_state", irs); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log.WithError(ierr).Error("failed to build invite stripped state")
|
|
||||||
// still set the field else synapse deployments don't process the invite
|
|
||||||
if err = event.SetUnsignedField("invite_room_state", struct{}{}); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
outputUpdates, err := updateToInviteMembership(updater, &event, nil, input.Event.RoomVersion)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return fmt.Errorf("updateToInviteMembership: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = ow.WriteOutputEvents(roomID, outputUpdates); err != nil {
|
if err = r.WriteOutputEvents(roomID, outputUpdates); err != nil {
|
||||||
return nil, err
|
return fmt.Errorf("r.WriteOutputEvents: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
succeeded = true
|
succeeded = true
|
||||||
return loopback, nil
|
return nil
|
||||||
}
|
|
||||||
|
|
||||||
func localInviteLoopback(
|
|
||||||
ow *RoomserverInternalAPI,
|
|
||||||
input *api.PerformInviteRequest,
|
|
||||||
) (ire *api.InputRoomEvent, err error) {
|
|
||||||
if input.Event.StateKey() == nil {
|
|
||||||
return nil, errors.New("no state key on invite event")
|
|
||||||
}
|
|
||||||
ourServerName := string(ow.Cfg.Matrix.ServerName)
|
|
||||||
_, theirServerName, err := gomatrixserverlib.SplitID('@', *input.Event.StateKey())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// Check if the invite originated locally and is destined locally.
|
|
||||||
if input.Event.Origin() == ow.Cfg.Matrix.ServerName && string(theirServerName) == ourServerName {
|
|
||||||
rsEvent := input.Event.Sign(
|
|
||||||
ourServerName,
|
|
||||||
ow.Cfg.Matrix.KeyID,
|
|
||||||
ow.Cfg.Matrix.PrivateKey,
|
|
||||||
).Headered(input.RoomVersion)
|
|
||||||
ire = &api.InputRoomEvent{
|
|
||||||
Kind: api.KindNew,
|
|
||||||
Event: rsEvent,
|
|
||||||
AuthEventIDs: rsEvent.AuthEventIDs(),
|
|
||||||
SendAsServer: ourServerName,
|
|
||||||
TransactionID: nil,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ire, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildInviteStrippedState(
|
func buildInviteStrippedState(
|
||||||
|
@ -238,7 +172,7 @@ func buildInviteStrippedState(
|
||||||
for _, t := range []string{
|
for _, t := range []string{
|
||||||
gomatrixserverlib.MRoomName, gomatrixserverlib.MRoomCanonicalAlias,
|
gomatrixserverlib.MRoomName, gomatrixserverlib.MRoomCanonicalAlias,
|
||||||
gomatrixserverlib.MRoomAliases, gomatrixserverlib.MRoomJoinRules,
|
gomatrixserverlib.MRoomAliases, gomatrixserverlib.MRoomJoinRules,
|
||||||
"m.room.avatar",
|
"m.room.avatar", "m.room.encryption",
|
||||||
} {
|
} {
|
||||||
stateWanted = append(stateWanted, gomatrixserverlib.StateKeyTuple{
|
stateWanted = append(stateWanted, gomatrixserverlib.StateKeyTuple{
|
||||||
EventType: t,
|
EventType: t,
|
||||||
|
|
|
@ -154,17 +154,12 @@ func (h *httpRoomserverInternalAPI) PerformInvite(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
request *api.PerformInviteRequest,
|
request *api.PerformInviteRequest,
|
||||||
response *api.PerformInviteResponse,
|
response *api.PerformInviteResponse,
|
||||||
) {
|
) error {
|
||||||
span, ctx := opentracing.StartSpanFromContext(ctx, "PerformInvite")
|
span, ctx := opentracing.StartSpanFromContext(ctx, "PerformInvite")
|
||||||
defer span.Finish()
|
defer span.Finish()
|
||||||
|
|
||||||
apiURL := h.roomserverURL + RoomserverPerformInvitePath
|
apiURL := h.roomserverURL + RoomserverPerformInvitePath
|
||||||
err := httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response)
|
return httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response)
|
||||||
if err != nil {
|
|
||||||
response.Error = &api.PerformError{
|
|
||||||
Msg: fmt.Sprintf("failed to communicate with roomserver: %s", err),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *httpRoomserverInternalAPI) PerformJoin(
|
func (h *httpRoomserverInternalAPI) PerformJoin(
|
||||||
|
|
|
@ -33,7 +33,9 @@ func AddRoutes(r api.RoomserverInternalAPI, internalAPIMux *mux.Router) {
|
||||||
if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
|
if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
|
||||||
return util.MessageResponse(http.StatusBadRequest, err.Error())
|
return util.MessageResponse(http.StatusBadRequest, err.Error())
|
||||||
}
|
}
|
||||||
r.PerformInvite(req.Context(), &request, &response)
|
if err := r.PerformInvite(req.Context(), &request, &response); err != nil {
|
||||||
|
return util.ErrorResponse(err)
|
||||||
|
}
|
||||||
return util.JSONResponse{Code: http.StatusOK, JSON: &response}
|
return util.JSONResponse{Code: http.StatusOK, JSON: &response}
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
|
@ -418,7 +418,6 @@ Inbound federation rejects attempts to join v2 rooms from servers only supportin
|
||||||
Outbound federation passes make_join failures through to the client
|
Outbound federation passes make_join failures through to the client
|
||||||
Outbound federation correctly handles unsupported room versions
|
Outbound federation correctly handles unsupported room versions
|
||||||
Remote users may not join unfederated rooms
|
Remote users may not join unfederated rooms
|
||||||
Guest users denied access over federation if guest access prohibited
|
|
||||||
Non-numeric ports in server names are rejected
|
Non-numeric ports in server names are rejected
|
||||||
Invited user can reject invite over federation
|
Invited user can reject invite over federation
|
||||||
Invited user can reject invite over federation for empty room
|
Invited user can reject invite over federation for empty room
|
||||||
|
@ -454,3 +453,5 @@ Banned servers cannot get missing events
|
||||||
Banned servers cannot get room state ids
|
Banned servers cannot get room state ids
|
||||||
Banned servers cannot backfill
|
Banned servers cannot backfill
|
||||||
Inbound /v1/send_leave rejects leaves from other servers
|
Inbound /v1/send_leave rejects leaves from other servers
|
||||||
|
Guest users can accept invites to private rooms over federation
|
||||||
|
AS user (not ghost) can join room without registering
|
||||||
|
|
Loading…
Reference in a new issue