mirror of
https://github.com/hoernschen/dendrite.git
synced 2025-07-30 04:52:46 +00:00
Join room support in federation sender (#989)
* Implement PerformJoinRequest * Rename perform functions * Check send join response * Temporary wiring to test federation sender room joins * Actually pass through the config * Make sure membership content shows join
This commit is contained in:
parent
a308e61331
commit
64e94e9a6f
14 changed files with 265 additions and 135 deletions
|
@ -27,12 +27,11 @@ import (
|
|||
"github.com/matrix-org/dendrite/clientapi/producers"
|
||||
"github.com/matrix-org/dendrite/common"
|
||||
"github.com/matrix-org/dendrite/common/config"
|
||||
"github.com/matrix-org/dendrite/roomserver/api"
|
||||
federationSenderAPI "github.com/matrix-org/dendrite/federationsender/api"
|
||||
roomserverAPI "github.com/matrix-org/dendrite/roomserver/api"
|
||||
"github.com/matrix-org/gomatrix"
|
||||
"github.com/matrix-org/gomatrixserverlib"
|
||||
"github.com/matrix-org/util"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// JoinRoomByIDOrAlias implements the "/join/{roomIDOrAlias}" API.
|
||||
|
@ -46,6 +45,7 @@ func JoinRoomByIDOrAlias(
|
|||
producer *producers.RoomserverProducer,
|
||||
queryAPI roomserverAPI.RoomserverQueryAPI,
|
||||
aliasAPI roomserverAPI.RoomserverAliasAPI,
|
||||
fsAPI federationSenderAPI.FederationSenderInternalAPI,
|
||||
keyRing gomatrixserverlib.KeyRing,
|
||||
accountDB accounts.Database,
|
||||
) util.JSONResponse {
|
||||
|
@ -79,7 +79,8 @@ func JoinRoomByIDOrAlias(
|
|||
content["avatar_url"] = profile.AvatarURL
|
||||
|
||||
r := joinRoomReq{
|
||||
req, evTime, content, device.UserID, cfg, federation, producer, queryAPI, aliasAPI, keyRing,
|
||||
req, evTime, content, device.UserID, cfg, federation, producer,
|
||||
queryAPI, aliasAPI, fsAPI, keyRing,
|
||||
}
|
||||
|
||||
if strings.HasPrefix(roomIDOrAlias, "!") {
|
||||
|
@ -107,6 +108,7 @@ type joinRoomReq struct {
|
|||
producer *producers.RoomserverProducer
|
||||
queryAPI roomserverAPI.RoomserverQueryAPI
|
||||
aliasAPI roomserverAPI.RoomserverAliasAPI
|
||||
fsAPI federationSenderAPI.FederationSenderInternalAPI
|
||||
keyRing gomatrixserverlib.KeyRing
|
||||
}
|
||||
|
||||
|
@ -326,71 +328,15 @@ func (r joinRoomReq) joinRoomUsingServers(
|
|||
// server was invalid this returns an error.
|
||||
// Otherwise this returns a JSONResponse.
|
||||
func (r joinRoomReq) joinRoomUsingServer(roomID string, server gomatrixserverlib.ServerName) (*util.JSONResponse, error) {
|
||||
// Ask the room server for information about room versions.
|
||||
var request api.QueryRoomVersionCapabilitiesRequest
|
||||
var response api.QueryRoomVersionCapabilitiesResponse
|
||||
if err := r.queryAPI.QueryRoomVersionCapabilities(r.req.Context(), &request, &response); err != nil {
|
||||
fedJoinReq := federationSenderAPI.PerformJoinRequest{
|
||||
RoomID: roomID,
|
||||
UserID: r.userID,
|
||||
ServerName: server,
|
||||
}
|
||||
fedJoinRes := federationSenderAPI.PerformJoinResponse{}
|
||||
if err := r.fsAPI.PerformJoin(r.req.Context(), &fedJoinReq, &fedJoinRes); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var supportedVersions []gomatrixserverlib.RoomVersion
|
||||
for version := range response.AvailableRoomVersions {
|
||||
supportedVersions = append(supportedVersions, version)
|
||||
}
|
||||
respMakeJoin, err := r.federation.MakeJoin(r.req.Context(), server, roomID, r.userID, supportedVersions)
|
||||
if err != nil {
|
||||
// TODO: Check if the user was not allowed to join the room.
|
||||
return nil, 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"
|
||||
err = r.writeToBuilder(&respMakeJoin.JoinEvent, roomID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("r.writeToBuilder: %w", err)
|
||||
}
|
||||
|
||||
if respMakeJoin.RoomVersion == "" {
|
||||
respMakeJoin.RoomVersion = gomatrixserverlib.RoomVersionV1
|
||||
}
|
||||
if _, err = respMakeJoin.RoomVersion.EventFormat(); err != nil {
|
||||
return &util.JSONResponse{
|
||||
Code: http.StatusBadRequest,
|
||||
JSON: jsonerror.UnsupportedRoomVersion(
|
||||
fmt.Sprintf("Room version '%s' is not supported", respMakeJoin.RoomVersion),
|
||||
),
|
||||
}, nil
|
||||
}
|
||||
|
||||
event, err := respMakeJoin.JoinEvent.Build(
|
||||
r.evTime, r.cfg.Matrix.ServerName, r.cfg.Matrix.KeyID,
|
||||
r.cfg.Matrix.PrivateKey, respMakeJoin.RoomVersion,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("respMakeJoin.JoinEvent.Build: %w", err)
|
||||
}
|
||||
|
||||
respSendJoin, err := r.federation.SendJoin(r.req.Context(), server, event, respMakeJoin.RoomVersion)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("r.federation.SendJoin: %w", err)
|
||||
}
|
||||
|
||||
if err = r.checkSendJoinResponse(event, server, respMakeJoin, respSendJoin); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
util.GetLogger(r.req.Context()).WithFields(logrus.Fields{
|
||||
"room_id": roomID,
|
||||
"num_auth_events": len(respSendJoin.AuthEvents),
|
||||
"num_state_events": len(respSendJoin.StateEvents),
|
||||
}).Info("Room join signature and auth verification passed")
|
||||
|
||||
if err = r.producer.SendEventWithState(
|
||||
r.req.Context(),
|
||||
respSendJoin.ToRespState(),
|
||||
event.Headered(respMakeJoin.RoomVersion),
|
||||
); err != nil {
|
||||
util.GetLogger(r.req.Context()).WithError(err).Error("r.producer.SendEventWithState")
|
||||
}
|
||||
|
||||
return &util.JSONResponse{
|
||||
Code: http.StatusOK,
|
||||
|
@ -400,49 +346,3 @@ func (r joinRoomReq) joinRoomUsingServer(roomID string, server gomatrixserverlib
|
|||
}{roomID},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// checkSendJoinResponse checks that all of the signatures are correct
|
||||
// and that the join is allowed by the supplied state.
|
||||
func (r joinRoomReq) checkSendJoinResponse(
|
||||
event gomatrixserverlib.Event,
|
||||
server gomatrixserverlib.ServerName,
|
||||
respMakeJoin gomatrixserverlib.RespMakeJoin,
|
||||
respSendJoin gomatrixserverlib.RespSendJoin,
|
||||
) error {
|
||||
// A list of events that we have retried, if they were not included in
|
||||
// the auth events supplied in the send_join.
|
||||
retries := map[string]bool{}
|
||||
|
||||
retryCheck:
|
||||
// TODO: Can we expand Check here to return a list of missing auth
|
||||
// events rather than failing one at a time?
|
||||
if err := respSendJoin.Check(r.req.Context(), r.keyRing, event); err != nil {
|
||||
switch e := err.(type) {
|
||||
case gomatrixserverlib.MissingAuthEventError:
|
||||
// Check that we haven't already retried for this event, prevents
|
||||
// us from ending up in endless loops
|
||||
if !retries[e.AuthEventID] {
|
||||
// Ask the server that we're talking to right now for the event
|
||||
tx, txerr := r.federation.GetEvent(r.req.Context(), server, e.AuthEventID)
|
||||
if txerr != nil {
|
||||
return fmt.Errorf("r.federation.GetEvent: %w", txerr)
|
||||
}
|
||||
// For each event returned, add it to the auth events.
|
||||
for _, pdu := range tx.PDUs {
|
||||
ev, everr := gomatrixserverlib.NewEventFromUntrustedJSON(pdu, respMakeJoin.RoomVersion)
|
||||
if everr != nil {
|
||||
return fmt.Errorf("gomatrixserverlib.NewEventFromUntrustedJSON: %w", everr)
|
||||
}
|
||||
respSendJoin.AuthEvents = append(respSendJoin.AuthEvents, ev)
|
||||
}
|
||||
// Mark the event as retried and then give the check another go.
|
||||
retries[e.AuthEventID] = true
|
||||
goto retryCheck
|
||||
}
|
||||
return fmt.Errorf("respSendJoin (after retries): %w", e)
|
||||
default:
|
||||
return fmt.Errorf("respSendJoin: %w", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -101,7 +101,8 @@ func Setup(
|
|||
return util.ErrorResponse(err)
|
||||
}
|
||||
return JoinRoomByIDOrAlias(
|
||||
req, device, vars["roomIDOrAlias"], cfg, federation, producer, queryAPI, aliasAPI, keyRing, accountDB,
|
||||
req, device, vars["roomIDOrAlias"], cfg, federation, producer,
|
||||
queryAPI, aliasAPI, federationSender, keyRing, accountDB,
|
||||
)
|
||||
}),
|
||||
).Methods(http.MethodPost, http.MethodOptions)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue