Temporary fix for remote room joins

This commit is contained in:
Devon Hudson 2023-06-13 08:50:03 +01:00
parent c11e7061f3
commit b647f1f3a1
No known key found for this signature in database
GPG key ID: CD06B18E77F6A628
5 changed files with 66 additions and 56 deletions

View file

@ -159,6 +159,7 @@ type PerformDirectoryLookupResponse struct {
type PerformJoinRequest struct {
RoomID string `json:"room_id"`
UserID string `json:"user_id"`
SenderID spec.SenderID
// The sorted list of servers to try. Servers will be tried sequentially, after de-duplication.
ServerNames types.ServerNames `json:"server_names"`
Content map[string]interface{} `json:"content"`

View file

@ -235,6 +235,7 @@ func testFederationAPIJoinThenKeyUpdate(t *testing.T, dbType test.DBType) {
fsapi.PerformJoin(context.Background(), &api.PerformJoinRequest{
RoomID: room.ID,
UserID: joiningUser.ID,
SenderID: spec.SenderID(joiningUser.ID),
ServerNames: []spec.ServerName{serverA},
}, &resp)
if resp.JoinedVia != serverA {

View file

@ -96,6 +96,7 @@ func (r *FederationInternalAPI) PerformJoin(
ctx,
request.RoomID,
request.UserID,
request.SenderID,
request.Content,
serverName,
request.Unsigned,
@ -137,7 +138,7 @@ func (r *FederationInternalAPI) PerformJoin(
func (r *FederationInternalAPI) performJoinUsingServer(
ctx context.Context,
roomID, userID string,
roomID, userID string, senderID spec.SenderID,
content map[string]interface{},
serverName spec.ServerName,
unsigned map[string]interface{},
@ -154,10 +155,6 @@ func (r *FederationInternalAPI) performJoinUsingServer(
if err != nil {
return err
}
senderID, err := r.rsAPI.QuerySenderIDForUser(ctx, roomID, *user)
if err != nil {
return err
}
joinInput := gomatrixserverlib.PerformJoinInput{
UserID: user,

View file

@ -174,44 +174,6 @@ func (r *Joiner) performJoinRoomByID(
req.ServerNames = append(req.ServerNames, roomID.Domain())
}
// Prepare the template for the join event.
userID, err := spec.NewUserID(req.UserID, true)
if err != nil {
return "", "", rsAPI.ErrInvalidID{Err: fmt.Errorf("user ID %q is invalid: %w", req.UserID, err)}
}
senderID, err := r.RSAPI.QuerySenderIDForUser(ctx, req.RoomIDOrAlias, *userID)
if err != nil {
return "", "", rsAPI.ErrInvalidID{Err: fmt.Errorf("user ID %q is invalid: %w", req.UserID, err)}
}
senderIDString := string(senderID)
userDomain := userID.Domain()
proto := gomatrixserverlib.ProtoEvent{
Type: spec.MRoomMember,
SenderID: senderIDString,
StateKey: &senderIDString,
RoomID: req.RoomIDOrAlias,
Redacts: "",
}
if err = proto.SetUnsigned(struct{}{}); err != nil {
return "", "", fmt.Errorf("eb.SetUnsigned: %w", err)
}
// It is possible for the request to include some "content" for the
// event. We'll always overwrite the "membership" key, but the rest,
// like "display_name" or "avatar_url", will be kept if supplied.
if req.Content == nil {
req.Content = map[string]interface{}{}
}
req.Content["membership"] = spec.Join
if authorisedVia, aerr := r.populateAuthorisedViaUserForRestrictedJoin(ctx, req, senderID); aerr != nil {
return "", "", aerr
} else if authorisedVia != "" {
req.Content["join_authorised_via_users_server"] = authorisedVia
}
if err = proto.SetContent(req.Content); err != nil {
return "", "", fmt.Errorf("eb.SetContent: %w", err)
}
// Force a federated join if we aren't in the room and we've been
// given some server names to try joining by.
inRoomReq := &rsAPI.QueryServerJoinedToRoomRequest{
@ -224,6 +186,31 @@ func (r *Joiner) performJoinRoomByID(
serverInRoom := inRoomRes.IsInRoom
forceFederatedJoin := len(req.ServerNames) > 0 && !serverInRoom
userID, err := spec.NewUserID(req.UserID, true)
if err != nil {
return "", "", rsAPI.ErrInvalidID{Err: fmt.Errorf("user ID %q is invalid: %w", req.UserID, err)}
}
var senderID spec.SenderID
var roomVersion gomatrixserverlib.RoomVersion
if forceFederatedJoin {
// TODO: pseudoIDs - lookup room version kere!
} else {
roomVersion, err = r.RSAPI.QueryRoomVersionForRoom(ctx, roomID.String())
if err != nil {
return "", "", err
}
}
if roomVersion == gomatrixserverlib.RoomVersionPseudoIDs {
// TODO: pseudoIDs - generate senderID kere!
senderID = "pseudo_id.sender.key"
} else {
senderID = spec.SenderID(userID.String())
}
senderIDString := string(senderID)
userDomain := userID.Domain()
// Force a federated join if we're dealing with a pending invite
// and we aren't in the room.
isInvitePending, inviteSender, _, inviteEvent, err := helpers.IsInvitePending(ctx, r.DB, req.RoomIDOrAlias, senderID)
@ -274,7 +261,7 @@ func (r *Joiner) performJoinRoomByID(
// If we should do a forced federated join then do that.
var joinedVia spec.ServerName
if forceFederatedJoin {
joinedVia, err = r.performFederatedJoinRoomByID(ctx, req)
joinedVia, err = r.performFederatedJoinRoomByID(ctx, req, senderID)
return req.RoomIDOrAlias, joinedVia, err
}
@ -289,6 +276,34 @@ func (r *Joiner) performJoinRoomByID(
if err != nil {
return "", "", fmt.Errorf("error joining local room: %q", err)
}
// Prepare the template for the join event.
proto := gomatrixserverlib.ProtoEvent{
Type: spec.MRoomMember,
SenderID: senderIDString,
StateKey: &senderIDString,
RoomID: req.RoomIDOrAlias,
Redacts: "",
}
if err = proto.SetUnsigned(struct{}{}); err != nil {
return "", "", fmt.Errorf("eb.SetUnsigned: %w", err)
}
// It is possible for the request to include some "content" for the
// event. We'll always overwrite the "membership" key, but the rest,
// like "display_name" or "avatar_url", will be kept if supplied.
if req.Content == nil {
req.Content = map[string]interface{}{}
}
req.Content["membership"] = spec.Join
if authorisedVia, aerr := r.populateAuthorisedViaUserForRestrictedJoin(ctx, req, senderID); aerr != nil {
return "", "", aerr
} else if authorisedVia != "" {
req.Content["join_authorised_via_users_server"] = authorisedVia
}
if err = proto.SetContent(req.Content); err != nil {
return "", "", fmt.Errorf("eb.SetContent: %w", err)
}
event, err := eventutil.QueryAndBuildEvent(ctx, &proto, identity, time.Now(), r.RSAPI, &buildRes)
switch err.(type) {
@ -334,7 +349,7 @@ func (r *Joiner) performJoinRoomByID(
}
// Perform a federated room join.
joinedVia, err = r.performFederatedJoinRoomByID(ctx, req)
joinedVia, err = r.performFederatedJoinRoomByID(ctx, req, senderID)
return req.RoomIDOrAlias, joinedVia, err
default:
@ -352,11 +367,13 @@ func (r *Joiner) performJoinRoomByID(
func (r *Joiner) performFederatedJoinRoomByID(
ctx context.Context,
req *rsAPI.PerformJoinRequest,
senderID spec.SenderID,
) (spec.ServerName, error) {
// Try joining by all of the supplied server names.
fedReq := fsAPI.PerformJoinRequest{
RoomID: req.RoomIDOrAlias, // the room ID to try and join
UserID: req.UserID, // the user ID joining the room
SenderID: spec.SenderID(senderID),
ServerNames: req.ServerNames, // the server to try joining with
Content: req.Content, // the membership event content
Unsigned: req.Unsigned, // the unsigned event content, if any

View file

@ -717,12 +717,6 @@ func (d *Database) GetOrCreateRoomInfoFromID(ctx context.Context, roomID string)
if err != nil {
return nil, err
}
if roomInfo == nil {
return nil, fmt.Errorf("Failed to find room info for %s", roomID)
}
d.Cache.StoreRoomServerRoomID(roomInfo.RoomNID, roomID)
d.Cache.StoreRoomVersion(roomID, roomInfo.RoomVersion)
return roomInfo, nil
}