From e9deb5244edd4827234622ea0d3b11678a33b0ac Mon Sep 17 00:00:00 2001 From: Till <2353100+S7evinK@users.noreply.github.com> Date: Tue, 13 Feb 2024 19:28:52 +0100 Subject: [PATCH] Fix `/createRoom` and `/invite` containing displayname/avatarURL of inviter (#3326) Fixes #3324 --- .github/workflows/schedules.yaml | 8 +-- clientapi/clientapi_test.go | 65 +++++++++++++++++++ clientapi/routing/membership.go | 31 ++++----- clientapi/routing/server_notices.go | 2 +- roomserver/api/perform.go | 18 +++-- .../internal/perform/perform_create_room.go | 18 +++-- roomserver/internal/perform/perform_invite.go | 8 +-- 7 files changed, 100 insertions(+), 50 deletions(-) diff --git a/.github/workflows/schedules.yaml b/.github/workflows/schedules.yaml index 4ba7c2e8..e339c14d 100644 --- a/.github/workflows/schedules.yaml +++ b/.github/workflows/schedules.yaml @@ -93,8 +93,8 @@ jobs: timeout-minutes: 5 name: "Sytest Coverage" runs-on: ubuntu-latest - needs: sytest # only run once Sytest is done - if: ${{ always() }} + needs: [ sytest, check_date ] # only run once Sytest is done and there was a commit + if: ${{ always() && needs.check_date.outputs.should_run != 'false' }} steps: - uses: actions/checkout@v4 - name: Install Go @@ -217,8 +217,8 @@ jobs: timeout-minutes: 5 name: "Complement Coverage" runs-on: ubuntu-latest - needs: complement # only run once Complement is done - if: ${{ always() }} + needs: [ complement, check_date ] # only run once Complements is done and there was a commit + if: ${{ always() && needs.check_date.outputs.should_run != 'false' }} steps: - uses: actions/checkout@v4 - name: Install Go diff --git a/clientapi/clientapi_test.go b/clientapi/clientapi_test.go index 1b2f1358..29ff5866 100644 --- a/clientapi/clientapi_test.go +++ b/clientapi/clientapi_test.go @@ -2278,3 +2278,68 @@ func TestGetMembership(t *testing.T) { } }) } + +func TestCreateRoomInvite(t *testing.T) { + alice := test.NewUser(t) + bob := test.NewUser(t) + + test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) { + + cfg, processCtx, close := testrig.CreateConfig(t, dbType) + routers := httputil.NewRouters() + cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions) + caches := caching.NewRistrettoCache(128*1024*1024, time.Hour, caching.DisableMetrics) + defer close() + natsInstance := jetstream.NATSInstance{} + jsctx, _ := natsInstance.Prepare(processCtx, &cfg.Global.JetStream) + defer jetstream.DeleteAllStreams(jsctx, &cfg.Global.JetStream) + + // Use an actual roomserver for this + rsAPI := roomserver.NewInternalAPI(processCtx, cfg, cm, &natsInstance, caches, caching.DisableMetrics) + rsAPI.SetFederationAPI(nil, nil) + userAPI := userapi.NewInternalAPI(processCtx, cfg, cm, &natsInstance, rsAPI, nil, caching.DisableMetrics, testIsBlacklistedOrBackingOff) + + // We mostly need the rsAPI for this test, so nil for other APIs/caches etc. + AddPublicRoutes(processCtx, routers, cfg, &natsInstance, nil, rsAPI, nil, nil, nil, userAPI, nil, nil, caching.DisableMetrics) + + accessTokens := map[*test.User]userDevice{ + alice: {}, + } + createAccessTokens(t, accessTokens, userAPI, processCtx.Context(), routers) + + reqBody := map[string]any{ + "invite": []string{bob.ID}, + } + body, err := json.Marshal(reqBody) + if err != nil { + t.Fatal(err) + } + + w := httptest.NewRecorder() + req := httptest.NewRequest(http.MethodPost, "/_matrix/client/v3/createRoom", strings.NewReader(string(body))) + req.Header.Set("Authorization", "Bearer "+accessTokens[alice].accessToken) + + routers.Client.ServeHTTP(w, req) + + if w.Code != http.StatusOK { + t.Fatalf("expected room creation to be successful, got HTTP %d instead: %s", w.Code, w.Body.String()) + } + + roomID := gjson.GetBytes(w.Body.Bytes(), "room_id").Str + validRoomID, _ := spec.NewRoomID(roomID) + // Now ask the roomserver about the membership event of Bob + ev, err := rsAPI.CurrentStateEvent(context.Background(), *validRoomID, spec.MRoomMember, bob.ID) + if err != nil { + t.Fatal(err) + } + + if ev == nil { + t.Fatal("Membership event for Bob does not exist") + } + + // Validate that there is NO displayname in content + if gjson.GetBytes(ev.Content(), "displayname").Exists() { + t.Fatal("Found displayname in invite") + } + }) +} diff --git a/clientapi/routing/membership.go b/clientapi/routing/membership.go index 06683c47..9e41a379 100644 --- a/clientapi/routing/membership.go +++ b/clientapi/routing/membership.go @@ -324,19 +324,18 @@ func SendInvite( } // We already received the return value, so no need to check for an error here. - response, _ := sendInvite(req.Context(), profileAPI, device, roomID, body.UserID, body.Reason, cfg, rsAPI, asAPI, evTime) + response, _ := sendInvite(req.Context(), device, roomID, body.UserID, body.Reason, cfg, rsAPI, evTime) return response } // sendInvite sends an invitation to a user. Returns a JSONResponse and an error func sendInvite( ctx context.Context, - profileAPI userapi.ClientUserAPI, device *userapi.Device, roomID, userID, reason string, cfg *config.ClientAPI, rsAPI roomserverAPI.ClientRoomserverAPI, - asAPI appserviceAPI.AppServiceInternalAPI, evTime time.Time, + evTime time.Time, ) (util.JSONResponse, error) { validRoomID, err := spec.NewRoomID(roomID) if err != nil { @@ -359,13 +358,7 @@ func sendInvite( JSON: spec.InvalidParam("UserID is invalid"), }, err } - profile, err := loadProfile(ctx, userID, cfg, profileAPI, asAPI) - if err != nil { - return util.JSONResponse{ - Code: http.StatusInternalServerError, - JSON: spec.InternalServerError{}, - }, err - } + identity, err := cfg.Matrix.SigningIdentityFor(device.UserDomain()) if err != nil { return util.JSONResponse{ @@ -375,16 +368,14 @@ func sendInvite( } err = rsAPI.PerformInvite(ctx, &api.PerformInviteRequest{ InviteInput: roomserverAPI.InviteInput{ - RoomID: *validRoomID, - Inviter: *inviter, - Invitee: *invitee, - DisplayName: profile.DisplayName, - AvatarURL: profile.AvatarURL, - Reason: reason, - IsDirect: false, - KeyID: identity.KeyID, - PrivateKey: identity.PrivateKey, - EventTime: evTime, + RoomID: *validRoomID, + Inviter: *inviter, + Invitee: *invitee, + Reason: reason, + IsDirect: false, + KeyID: identity.KeyID, + PrivateKey: identity.PrivateKey, + EventTime: evTime, }, InviteRoomState: nil, // ask the roomserver to draw up invite room state for us SendAsServer: string(device.UserDomain()), diff --git a/clientapi/routing/server_notices.go b/clientapi/routing/server_notices.go index 5deb559d..d4644b3e 100644 --- a/clientapi/routing/server_notices.go +++ b/clientapi/routing/server_notices.go @@ -215,7 +215,7 @@ func SendServerNotice( } if !membershipRes.IsInRoom { // re-invite the user - res, err := sendInvite(ctx, userAPI, senderDevice, roomID, r.UserID, "Server notice room", cfgClient, rsAPI, asAPI, time.Now()) + res, err := sendInvite(ctx, senderDevice, roomID, r.UserID, "Server notice room", cfgClient, rsAPI, time.Now()) if err != nil { return res } diff --git a/roomserver/api/perform.go b/roomserver/api/perform.go index 9e00da2c..d6caec08 100644 --- a/roomserver/api/perform.go +++ b/roomserver/api/perform.go @@ -50,16 +50,14 @@ type PerformLeaveResponse struct { } type InviteInput struct { - RoomID spec.RoomID - Inviter spec.UserID - Invitee spec.UserID - DisplayName string - AvatarURL string - Reason string - IsDirect bool - KeyID gomatrixserverlib.KeyID - PrivateKey ed25519.PrivateKey - EventTime time.Time + RoomID spec.RoomID + Inviter spec.UserID + Invitee spec.UserID + Reason string + IsDirect bool + KeyID gomatrixserverlib.KeyID + PrivateKey ed25519.PrivateKey + EventTime time.Time } type PerformInviteRequest struct { diff --git a/roomserver/internal/perform/perform_create_room.go b/roomserver/internal/perform/perform_create_room.go index eb8de781..093082f9 100644 --- a/roomserver/internal/perform/perform_create_room.go +++ b/roomserver/internal/perform/perform_create_room.go @@ -503,16 +503,14 @@ func (c *Creator) PerformCreateRoom(ctx context.Context, userID spec.UserID, roo err = c.RSAPI.PerformInvite(ctx, &api.PerformInviteRequest{ InviteInput: api.InviteInput{ - RoomID: roomID, - Inviter: userID, - Invitee: *inviteeUserID, - DisplayName: createRequest.UserDisplayName, - AvatarURL: createRequest.UserAvatarURL, - Reason: "", - IsDirect: createRequest.IsDirect, - KeyID: createRequest.KeyID, - PrivateKey: createRequest.PrivateKey, - EventTime: createRequest.EventTime, + RoomID: roomID, + Inviter: userID, + Invitee: *inviteeUserID, + Reason: "", + IsDirect: createRequest.IsDirect, + KeyID: createRequest.KeyID, + PrivateKey: createRequest.PrivateKey, + EventTime: createRequest.EventTime, }, InviteRoomState: globalStrippedState, SendAsServer: string(userID.Domain()), diff --git a/roomserver/internal/perform/perform_invite.go b/roomserver/internal/perform/perform_invite.go index 3abb69cb..86563e8c 100644 --- a/roomserver/internal/perform/perform_invite.go +++ b/roomserver/internal/perform/perform_invite.go @@ -144,11 +144,9 @@ func (r *Inviter) PerformInvite( } content := gomatrixserverlib.MemberContent{ - Membership: spec.Invite, - DisplayName: req.InviteInput.DisplayName, - AvatarURL: req.InviteInput.AvatarURL, - Reason: req.InviteInput.Reason, - IsDirect: req.InviteInput.IsDirect, + Membership: spec.Invite, + Reason: req.InviteInput.Reason, + IsDirect: req.InviteInput.IsDirect, } if err = proto.SetContent(content); err != nil {