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

@ -157,8 +157,9 @@ type PerformDirectoryLookupResponse struct {
} }
type PerformJoinRequest struct { type PerformJoinRequest struct {
RoomID string `json:"room_id"` RoomID string `json:"room_id"`
UserID string `json:"user_id"` UserID string `json:"user_id"`
SenderID spec.SenderID
// The sorted list of servers to try. Servers will be tried sequentially, after de-duplication. // The sorted list of servers to try. Servers will be tried sequentially, after de-duplication.
ServerNames types.ServerNames `json:"server_names"` ServerNames types.ServerNames `json:"server_names"`
Content map[string]interface{} `json:"content"` 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{ fsapi.PerformJoin(context.Background(), &api.PerformJoinRequest{
RoomID: room.ID, RoomID: room.ID,
UserID: joiningUser.ID, UserID: joiningUser.ID,
SenderID: spec.SenderID(joiningUser.ID),
ServerNames: []spec.ServerName{serverA}, ServerNames: []spec.ServerName{serverA},
}, &resp) }, &resp)
if resp.JoinedVia != serverA { if resp.JoinedVia != serverA {

View file

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

View file

@ -174,44 +174,6 @@ func (r *Joiner) performJoinRoomByID(
req.ServerNames = append(req.ServerNames, roomID.Domain()) 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 // Force a federated join if we aren't in the room and we've been
// given some server names to try joining by. // given some server names to try joining by.
inRoomReq := &rsAPI.QueryServerJoinedToRoomRequest{ inRoomReq := &rsAPI.QueryServerJoinedToRoomRequest{
@ -224,6 +186,31 @@ func (r *Joiner) performJoinRoomByID(
serverInRoom := inRoomRes.IsInRoom serverInRoom := inRoomRes.IsInRoom
forceFederatedJoin := len(req.ServerNames) > 0 && !serverInRoom 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 // Force a federated join if we're dealing with a pending invite
// and we aren't in the room. // and we aren't in the room.
isInvitePending, inviteSender, _, inviteEvent, err := helpers.IsInvitePending(ctx, r.DB, req.RoomIDOrAlias, senderID) 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. // If we should do a forced federated join then do that.
var joinedVia spec.ServerName var joinedVia spec.ServerName
if forceFederatedJoin { if forceFederatedJoin {
joinedVia, err = r.performFederatedJoinRoomByID(ctx, req) joinedVia, err = r.performFederatedJoinRoomByID(ctx, req, senderID)
return req.RoomIDOrAlias, joinedVia, err return req.RoomIDOrAlias, joinedVia, err
} }
@ -289,6 +276,34 @@ func (r *Joiner) performJoinRoomByID(
if err != nil { if err != nil {
return "", "", fmt.Errorf("error joining local room: %q", err) 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) event, err := eventutil.QueryAndBuildEvent(ctx, &proto, identity, time.Now(), r.RSAPI, &buildRes)
switch err.(type) { switch err.(type) {
@ -334,7 +349,7 @@ func (r *Joiner) performJoinRoomByID(
} }
// Perform a federated room join. // Perform a federated room join.
joinedVia, err = r.performFederatedJoinRoomByID(ctx, req) joinedVia, err = r.performFederatedJoinRoomByID(ctx, req, senderID)
return req.RoomIDOrAlias, joinedVia, err return req.RoomIDOrAlias, joinedVia, err
default: default:
@ -352,14 +367,16 @@ func (r *Joiner) performJoinRoomByID(
func (r *Joiner) performFederatedJoinRoomByID( func (r *Joiner) performFederatedJoinRoomByID(
ctx context.Context, ctx context.Context,
req *rsAPI.PerformJoinRequest, req *rsAPI.PerformJoinRequest,
senderID spec.SenderID,
) (spec.ServerName, error) { ) (spec.ServerName, error) {
// Try joining by all of the supplied server names. // Try joining by all of the supplied server names.
fedReq := fsAPI.PerformJoinRequest{ fedReq := fsAPI.PerformJoinRequest{
RoomID: req.RoomIDOrAlias, // the room ID to try and join RoomID: req.RoomIDOrAlias, // the room ID to try and join
UserID: req.UserID, // the user ID joining the room UserID: req.UserID, // the user ID joining the room
ServerNames: req.ServerNames, // the server to try joining with SenderID: spec.SenderID(senderID),
Content: req.Content, // the membership event content ServerNames: req.ServerNames, // the server to try joining with
Unsigned: req.Unsigned, // the unsigned event content, if any Content: req.Content, // the membership event content
Unsigned: req.Unsigned, // the unsigned event content, if any
} }
fedRes := fsAPI.PerformJoinResponse{} fedRes := fsAPI.PerformJoinResponse{}
r.FSAPI.PerformJoin(ctx, &fedReq, &fedRes) r.FSAPI.PerformJoin(ctx, &fedReq, &fedRes)

View file

@ -717,12 +717,6 @@ func (d *Database) GetOrCreateRoomInfoFromID(ctx context.Context, roomID string)
if err != nil { if err != nil {
return nil, err 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 return roomInfo, nil
} }