mirror of
https://github.com/matrix-org/dendrite.git
synced 2025-12-17 03:43:11 -06:00
140 lines
4.4 KiB
Go
140 lines
4.4 KiB
Go
package query
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/matrix-org/dendrite/federationsender/api"
|
|
"github.com/matrix-org/dendrite/federationsender/query/perform"
|
|
"github.com/matrix-org/dendrite/roomserver/version"
|
|
"github.com/matrix-org/gomatrixserverlib"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
// PerformJoinRequest implements api.FederationSenderInternalAPI
|
|
func (r *FederationSenderInternalAPI) PerformJoin(
|
|
ctx context.Context,
|
|
request *api.PerformJoinRequest,
|
|
response *api.PerformJoinResponse,
|
|
) (err error) {
|
|
// Look up the supported room versions.
|
|
var supportedVersions []gomatrixserverlib.RoomVersion
|
|
for version := range version.SupportedRoomVersions() {
|
|
supportedVersions = append(supportedVersions, version)
|
|
}
|
|
|
|
// Try to perform a make_join using the information supplied in the
|
|
// request.
|
|
respMakeJoin, err := r.federation.MakeJoin(
|
|
ctx,
|
|
request.ServerName,
|
|
request.RoomID,
|
|
request.UserID,
|
|
supportedVersions,
|
|
)
|
|
if err != nil {
|
|
// TODO: Check if the user was not allowed to join the room.
|
|
return fmt.Errorf("r.federation.MakeJoin: %w", err)
|
|
}
|
|
|
|
// Set all the fields to be what they should be, this should be a no-op
|
|
// but it's possible that the remote server returned us something "odd"
|
|
respMakeJoin.JoinEvent.Type = "m.room.member"
|
|
respMakeJoin.JoinEvent.Sender = request.UserID
|
|
respMakeJoin.JoinEvent.StateKey = &request.UserID
|
|
respMakeJoin.JoinEvent.RoomID = request.RoomID
|
|
respMakeJoin.JoinEvent.Redacts = ""
|
|
if request.Content == nil {
|
|
request.Content = map[string]interface{}{}
|
|
}
|
|
request.Content["membership"] = "join"
|
|
if err = respMakeJoin.JoinEvent.SetContent(request.Content); err != nil {
|
|
return fmt.Errorf("respMakeJoin.JoinEvent.SetContent: %w", err)
|
|
}
|
|
if err = respMakeJoin.JoinEvent.SetUnsigned(struct{}{}); err != nil {
|
|
return fmt.Errorf("respMakeJoin.JoinEvent.SetUnsigned: %w", err)
|
|
}
|
|
|
|
// Work out if we support the room version that has been supplied in
|
|
// the make_join response.
|
|
if respMakeJoin.RoomVersion == "" {
|
|
respMakeJoin.RoomVersion = gomatrixserverlib.RoomVersionV1
|
|
}
|
|
if _, err = respMakeJoin.RoomVersion.EventFormat(); err != nil {
|
|
return fmt.Errorf("respMakeJoin.RoomVersion.EventFormat: %w", err)
|
|
}
|
|
|
|
// Build the join event.
|
|
event, err := respMakeJoin.JoinEvent.Build(
|
|
time.Now(),
|
|
r.cfg.Matrix.ServerName,
|
|
r.cfg.Matrix.KeyID,
|
|
r.cfg.Matrix.PrivateKey,
|
|
respMakeJoin.RoomVersion,
|
|
)
|
|
if err != nil {
|
|
return fmt.Errorf("respMakeJoin.JoinEvent.Build: %w", err)
|
|
}
|
|
|
|
// Try to perform a send_join using the newly built event.
|
|
respSendJoin, err := r.federation.SendJoin(
|
|
ctx,
|
|
request.ServerName,
|
|
event,
|
|
respMakeJoin.RoomVersion,
|
|
)
|
|
if err != nil {
|
|
return fmt.Errorf("r.federation.SendJoin: %w", err)
|
|
}
|
|
|
|
// At this point, if the above /send_join didn't return an error,
|
|
// then the resident servers think we're in the room. We need
|
|
// to verify the state and auth chain and notify the roomserver
|
|
// but this can take an awful long time in big rooms and there's
|
|
// every possibility that client may give up waiting on this CS
|
|
// API request long before that. Therefore for now, until we
|
|
// have a /confirm_join step, just let the client think that the
|
|
// request succeeded and work it out in our own time. There's
|
|
// every possibility this might fail, and if so, the room will
|
|
// just never appear in the sync stream. That's about the best
|
|
// we can do for now.
|
|
go func() {
|
|
// Don't expire with the original request context.
|
|
ctx := context.Background()
|
|
|
|
// Check that the send_join response was valid.
|
|
joinCtx := perform.JoinContext(r.federation, r.keyRing)
|
|
if err = joinCtx.CheckSendJoinResponse(
|
|
ctx, event, request.ServerName, respMakeJoin, respSendJoin,
|
|
); err != nil {
|
|
logrus.WithError(err).Errorf("perform.JoinRequest.CheckSendJoinResponse failed")
|
|
return
|
|
}
|
|
|
|
// If we successfully performed a send_join above then the other
|
|
// server now thinks we're a part of the room. Send the newly
|
|
// returned state to the roomserver to update our local view.
|
|
if err = r.producer.SendEventWithState(
|
|
ctx,
|
|
respSendJoin.ToRespState(),
|
|
event.Headered(respMakeJoin.RoomVersion),
|
|
); err != nil {
|
|
logrus.WithError(err).Errorf("r.producer.SendEventWithState failed")
|
|
return
|
|
}
|
|
}()
|
|
|
|
// Everything went to plan.
|
|
return nil
|
|
}
|
|
|
|
// PerformLeaveRequest implements api.FederationSenderInternalAPI
|
|
func (r *FederationSenderInternalAPI) PerformLeave(
|
|
ctx context.Context,
|
|
request *api.PerformLeaveRequest,
|
|
response *api.PerformLeaveResponse,
|
|
) (err error) {
|
|
return nil
|
|
}
|