Skip to content
This repository has been archived by the owner on Nov 25, 2024. It is now read-only.

Fix /createRoom and /invite containing displayname/avatarURL of inviter #3326

Merged
merged 5 commits into from
Feb 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/schedules.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
65 changes: 65 additions & 0 deletions clientapi/clientapi_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
}
})
}
31 changes: 11 additions & 20 deletions clientapi/routing/membership.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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{
Expand All @@ -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()),
Expand Down
2 changes: 1 addition & 1 deletion clientapi/routing/server_notices.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
18 changes: 8 additions & 10 deletions roomserver/api/perform.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
18 changes: 8 additions & 10 deletions roomserver/internal/perform/perform_create_room.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()),
Expand Down
8 changes: 3 additions & 5 deletions roomserver/internal/perform/perform_invite.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down