[WIP] User directory respects room privacy

This commit is contained in:
Joshua Hong 2021-06-02 22:18:24 -04:00
parent 125ea75b24
commit 66cb93c010
12 changed files with 252 additions and 70 deletions

View file

@ -19,7 +19,7 @@ import (
"fmt" "fmt"
"github.com/matrix-org/dendrite/clientapi/auth/authtypes" "github.com/matrix-org/dendrite/clientapi/auth/authtypes"
"github.com/matrix-org/dendrite/roomserver/api" rsapi "github.com/matrix-org/dendrite/roomserver/api"
userapi "github.com/matrix-org/dendrite/userapi/api" userapi "github.com/matrix-org/dendrite/userapi/api"
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
"github.com/matrix-org/util" "github.com/matrix-org/util"
@ -34,7 +34,7 @@ func SearchUserDirectory(
ctx context.Context, ctx context.Context,
device *userapi.Device, device *userapi.Device,
userAPI userapi.UserInternalAPI, userAPI userapi.UserInternalAPI,
rsAPI api.RoomserverInternalAPI, rsAPI rsapi.RoomserverInternalAPI,
serverName gomatrixserverlib.ServerName, serverName gomatrixserverlib.ServerName,
searchString string, searchString string,
limit int, limit int,
@ -49,44 +49,12 @@ func SearchUserDirectory(
Limited: false, Limited: false,
} }
// First start searching local users. stateReq := &rsapi.QueryKnownUsersRequest{
UserID: device.UserID,
userReq := &userapi.QuerySearchProfilesRequest{
SearchString: searchString, SearchString: searchString,
Limit: limit, Limit: limit,
} }
userRes := &userapi.QuerySearchProfilesResponse{} stateRes := &rsapi.QueryKnownUsersResponse{}
if err := userAPI.QuerySearchProfiles(ctx, userReq, userRes); err != nil {
errRes := util.ErrorResponse(fmt.Errorf("userAPI.QuerySearchProfiles: %w", err))
return &errRes
}
for _, user := range userRes.Profiles {
if len(results) == limit {
response.Limited = true
break
}
userID := fmt.Sprintf("@%s:%s", user.Localpart, serverName)
if _, ok := results[userID]; !ok {
results[userID] = authtypes.FullyQualifiedProfile{
UserID: userID,
DisplayName: user.DisplayName,
AvatarURL: user.AvatarURL,
}
}
}
// Then, if we have enough room left in the response,
// start searching for known users from joined rooms.
if len(results) <= limit {
stateReq := &api.QueryKnownUsersRequest{
UserID: device.UserID,
SearchString: searchString,
Limit: limit - len(results),
}
stateRes := &api.QueryKnownUsersResponse{}
if err := rsAPI.QueryKnownUsers(ctx, stateReq, stateRes); err != nil { if err := rsAPI.QueryKnownUsers(ctx, stateReq, stateRes); err != nil {
errRes := util.ErrorResponse(fmt.Errorf("rsAPI.QueryKnownUsers: %w", err)) errRes := util.ErrorResponse(fmt.Errorf("rsAPI.QueryKnownUsers: %w", err))
return &errRes return &errRes
@ -102,7 +70,6 @@ func SearchUserDirectory(
results[user.UserID] = user results[user.UserID] = user
} }
} }
}
for _, result := range results { for _, result := range results {
response.Results = append(response.Results, result) response.Results = append(response.Results, result)

View file

@ -157,11 +157,22 @@ func (r *Inputer) isLocalTarget(event *gomatrixserverlib.Event) bool {
func updateToJoinMembership( func updateToJoinMembership(
mu *shared.MembershipUpdater, add *gomatrixserverlib.Event, updates []api.OutputEvent, mu *shared.MembershipUpdater, add *gomatrixserverlib.Event, updates []api.OutputEvent,
) ([]api.OutputEvent, error) { ) ([]api.OutputEvent, error) {
// Extract the displayname, if there is one, from the membership event
// so that we can add it as a queryable field to the membership table
memberEvent, err := gomatrixserverlib.NewMemberContentFromEvent(add)
if err != nil {
return nil, err
}
var displayname string
if memberEvent.DisplayName != "" {
displayname = memberEvent.DisplayName
}
// If the user is already marked as being joined, we call SetToJoin to update // If the user is already marked as being joined, we call SetToJoin to update
// the event ID then we can return immediately. Retired is ignored as there // the event ID then we can return immediately. Retired is ignored as there
// is no invite event to retire. // is no invite event to retire.
if mu.IsJoin() { if mu.IsJoin() {
_, err := mu.SetToJoin(add.Sender(), add.EventID(), true) _, err := mu.SetToJoin(add.Sender(), add.EventID(), displayname, true)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -171,7 +182,7 @@ func updateToJoinMembership(
// are active for that user. We notify the consumers that the invites have // are active for that user. We notify the consumers that the invites have
// been retired using a special event, even though they could infer this // been retired using a special event, even though they could infer this
// by studying the state changes in the room event stream. // by studying the state changes in the room event stream.
retired, err := mu.SetToJoin(add.Sender(), add.EventID(), false) retired, err := mu.SetToJoin(add.Sender(), add.EventID(), displayname, false)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -0,0 +1,52 @@
// Copyright 2020 The Matrix.org Foundation C.I.C.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package deltas
import (
"database/sql"
"fmt"
"github.com/matrix-org/dendrite/internal/sqlutil"
)
func LoadAddDisplaynameColumn(m *sqlutil.Migrations) {
m.AddMigration(UpAddDisplaynameColumn, DownAddDisplaynameColumn)
}
func UpAddDisplaynameColumn(tx *sql.Tx) error {
_, err := tx.Exec(`ALTER TABLE roomserver_membership ADD COLUMN IF NOT EXISTS displayname TEXT NOT NULL DEFAULT '';`)
if err != nil {
return fmt.Errorf("failed to execute upgrade: %w", err)
}
_, err = tx.Exec(`UPDATE roomserver_membership SET displayname = event_json::json->'content'->'displayname'
FROM roomserver_event_json WHERE
roomserver_membership.event_nid = roomserver_event_json.event_nid
AND event_json::json->'content'->'displayname' IS NOT NULL;
`)
if err != nil {
return fmt.Errorf("failed to move displayname from JSON to column: %w", err)
}
return nil
}
func DownAddDisplaynameColumn(tx *sql.Tx) error {
_, err := tx.Exec(`ALTER TABLE roomserver_membership DROP COLUMN IF EXISTS displayname;`)
if err != nil {
return fmt.Errorf("failed to execute downgrade: %w", err)
}
return nil
}

View file

@ -61,6 +61,7 @@ CREATE TABLE IF NOT EXISTS roomserver_membership (
-- room joins. -- room joins.
target_local BOOLEAN NOT NULL DEFAULT false, target_local BOOLEAN NOT NULL DEFAULT false,
forgotten BOOLEAN NOT NULL DEFAULT FALSE, forgotten BOOLEAN NOT NULL DEFAULT FALSE,
displayname TEXT NOT NULL DEFAULT '',
UNIQUE (room_nid, target_nid) UNIQUE (room_nid, target_nid)
); );
` `
@ -104,7 +105,7 @@ const selectMembershipForUpdateSQL = "" +
" WHERE room_nid = $1 AND target_nid = $2 FOR UPDATE" " WHERE room_nid = $1 AND target_nid = $2 FOR UPDATE"
const updateMembershipSQL = "" + const updateMembershipSQL = "" +
"UPDATE roomserver_membership SET sender_nid = $3, membership_nid = $4, event_nid = $5, forgotten = $6" + "UPDATE roomserver_membership SET sender_nid = $3, membership_nid = $4, event_nid = $5, forgotten = $6, displayname = $7" +
" WHERE room_nid = $1 AND target_nid = $2" " WHERE room_nid = $1 AND target_nid = $2"
const updateMembershipForgetRoom = "" + const updateMembershipForgetRoom = "" +
@ -118,11 +119,16 @@ const selectRoomsWithMembershipSQL = "" +
// joined to. Since this information is used to populate the user directory, we will // joined to. Since this information is used to populate the user directory, we will
// only return users that the user would ordinarily be able to see anyway. // only return users that the user would ordinarily be able to see anyway.
var selectKnownUsersSQL = "" + var selectKnownUsersSQL = "" +
"SELECT DISTINCT event_state_key FROM roomserver_membership INNER JOIN roomserver_event_state_keys ON " + "SELECT DISTINCT event_state_key, displayname FROM roomserver_membership INNER JOIN roomserver_event_state_keys ON " +
"roomserver_membership.target_nid = roomserver_event_state_keys.event_state_key_nid " + "roomserver_membership.target_nid = roomserver_event_state_keys.event_state_key_nid " +
" WHERE room_nid = ANY(" + "WHERE room_nid IN (" +
" SELECT DISTINCT room_nid FROM roomserver_membership WHERE target_nid = $1 AND membership_nid = " + fmt.Sprintf("%d", tables.MembershipStateJoin) + " SELECT DISTINCT room_nid FROM roomserver_membership WHERE target_nid = $1 AND membership_nid = " + fmt.Sprintf("%d", tables.MembershipStateJoin) +
") AND membership_nid = " + fmt.Sprintf("%d", tables.MembershipStateJoin) + " AND event_state_key LIKE $2 LIMIT $3" " UNION " +
" SELECT DISTINCT room_nid from roomserver_rooms INNER JOIN roomserver_published ON " +
" roomserver_rooms.room_id = roomserver_published.room_id WHERE published = true " +
") AND membership_nid = " + fmt.Sprintf("%d", tables.MembershipStateJoin) + " AND ( " +
" event_state_key LIKE $2 OR displayname LIKE $2" +
") LIMIT $3"
// selectLocalServerInRoomSQL is an optimised case for checking if we, the local server, // selectLocalServerInRoomSQL is an optimised case for checking if we, the local server,
// are in the room by using the target_local column of the membership table. Normally when // are in the room by using the target_local column of the membership table. Normally when
@ -270,10 +276,10 @@ func (s *membershipStatements) SelectMembershipsFromRoomAndMembership(
func (s *membershipStatements) UpdateMembership( func (s *membershipStatements) UpdateMembership(
ctx context.Context, ctx context.Context,
txn *sql.Tx, roomNID types.RoomNID, targetUserNID types.EventStateKeyNID, senderUserNID types.EventStateKeyNID, membership tables.MembershipState, txn *sql.Tx, roomNID types.RoomNID, targetUserNID types.EventStateKeyNID, senderUserNID types.EventStateKeyNID, membership tables.MembershipState,
eventNID types.EventNID, forgotten bool, eventNID types.EventNID, forgotten bool, displayname string,
) error { ) error {
_, err := sqlutil.TxStmt(txn, s.updateMembershipStmt).ExecContext( _, err := sqlutil.TxStmt(txn, s.updateMembershipStmt).ExecContext(
ctx, roomNID, targetUserNID, senderUserNID, membership, eventNID, forgotten, ctx, roomNID, targetUserNID, senderUserNID, membership, eventNID, forgotten, displayname,
) )
return err return err
} }
@ -328,7 +334,8 @@ func (s *membershipStatements) SelectKnownUsers(ctx context.Context, userID type
defer internal.CloseAndLogIfError(ctx, rows, "SelectKnownUsers: rows.close() failed") defer internal.CloseAndLogIfError(ctx, rows, "SelectKnownUsers: rows.close() failed")
for rows.Next() { for rows.Next() {
var userID string var userID string
if err := rows.Scan(&userID); err != nil { var displayname string
if err := rows.Scan(&userID, &displayname); err != nil {
return nil, err return nil, err
} }
result = append(result, userID) result = append(result, userID)

View file

@ -53,6 +53,7 @@ func Open(dbProperties *config.DatabaseOptions, cache caching.RoomServerCaches)
m := sqlutil.NewMigrations() m := sqlutil.NewMigrations()
deltas.LoadAddForgottenColumn(m) deltas.LoadAddForgottenColumn(m)
deltas.LoadStateBlocksRefactor(m) deltas.LoadStateBlocksRefactor(m)
deltas.LoadAddDisplaynameColumn(m)
if err := m.RunDeltas(db, dbProperties); err != nil { if err := m.RunDeltas(db, dbProperties); err != nil {
return nil, err return nil, err
} }

View file

@ -106,7 +106,7 @@ func (u *MembershipUpdater) SetToInvite(event gomatrixserverlib.Event) (bool, er
return fmt.Errorf("u.d.InvitesTable.InsertInviteEvent: %w", err) return fmt.Errorf("u.d.InvitesTable.InsertInviteEvent: %w", err)
} }
if u.membership != tables.MembershipStateInvite { if u.membership != tables.MembershipStateInvite {
if err = u.d.MembershipTable.UpdateMembership(u.ctx, u.txn, u.roomNID, u.targetUserNID, senderUserNID, tables.MembershipStateInvite, 0, false); err != nil { if err = u.d.MembershipTable.UpdateMembership(u.ctx, u.txn, u.roomNID, u.targetUserNID, senderUserNID, tables.MembershipStateInvite, 0, false, ""); err != nil {
return fmt.Errorf("u.d.MembershipTable.UpdateMembership: %w", err) return fmt.Errorf("u.d.MembershipTable.UpdateMembership: %w", err)
} }
} }
@ -116,7 +116,7 @@ func (u *MembershipUpdater) SetToInvite(event gomatrixserverlib.Event) (bool, er
} }
// SetToJoin implements types.MembershipUpdater // SetToJoin implements types.MembershipUpdater
func (u *MembershipUpdater) SetToJoin(senderUserID string, eventID string, isUpdate bool) ([]string, error) { func (u *MembershipUpdater) SetToJoin(senderUserID string, eventID string, displayname string, isUpdate bool) ([]string, error) {
var inviteEventIDs []string var inviteEventIDs []string
err := u.d.Writer.Do(u.d.DB, u.txn, func(txn *sql.Tx) error { err := u.d.Writer.Do(u.d.DB, u.txn, func(txn *sql.Tx) error {
@ -142,7 +142,7 @@ func (u *MembershipUpdater) SetToJoin(senderUserID string, eventID string, isUpd
} }
if u.membership != tables.MembershipStateJoin || isUpdate { if u.membership != tables.MembershipStateJoin || isUpdate {
if err = u.d.MembershipTable.UpdateMembership(u.ctx, u.txn, u.roomNID, u.targetUserNID, senderUserNID, tables.MembershipStateJoin, nIDs[eventID], false); err != nil { if err = u.d.MembershipTable.UpdateMembership(u.ctx, u.txn, u.roomNID, u.targetUserNID, senderUserNID, tables.MembershipStateJoin, nIDs[eventID], false, displayname); err != nil {
return fmt.Errorf("u.d.MembershipTable.UpdateMembership: %w", err) return fmt.Errorf("u.d.MembershipTable.UpdateMembership: %w", err)
} }
} }
@ -176,7 +176,7 @@ func (u *MembershipUpdater) SetToLeave(senderUserID string, eventID string) ([]s
} }
if u.membership != tables.MembershipStateLeaveOrBan { if u.membership != tables.MembershipStateLeaveOrBan {
if err = u.d.MembershipTable.UpdateMembership(u.ctx, u.txn, u.roomNID, u.targetUserNID, senderUserNID, tables.MembershipStateLeaveOrBan, nIDs[eventID], false); err != nil { if err = u.d.MembershipTable.UpdateMembership(u.ctx, u.txn, u.roomNID, u.targetUserNID, senderUserNID, tables.MembershipStateLeaveOrBan, nIDs[eventID], false, ""); err != nil {
return fmt.Errorf("u.d.MembershipTable.UpdateMembership: %w", err) return fmt.Errorf("u.d.MembershipTable.UpdateMembership: %w", err)
} }
} }

View file

@ -1080,8 +1080,14 @@ func (d *Database) GetServerInRoom(ctx context.Context, roomNID types.RoomNID, s
func (d *Database) GetKnownUsers(ctx context.Context, userID, searchString string, limit int) ([]string, error) { func (d *Database) GetKnownUsers(ctx context.Context, userID, searchString string, limit int) ([]string, error) {
stateKeyNID, err := d.EventStateKeysTable.SelectEventStateKeyNID(ctx, nil, userID) stateKeyNID, err := d.EventStateKeysTable.SelectEventStateKeyNID(ctx, nil, userID)
if err != nil { if err != nil {
if err == sql.ErrNoRows {
// Happens if a search is performed before user joins any rooms
// NID is never -1, so SelectKnownUsers will only pull users in public rooms
stateKeyNID = -1
} else {
return nil, err return nil, err
} }
}
return d.MembershipTable.SelectKnownUsers(ctx, stateKeyNID, searchString, limit) return d.MembershipTable.SelectKnownUsers(ctx, stateKeyNID, searchString, limit)
} }

View file

@ -0,0 +1,126 @@
// Copyright 2020 The Matrix.org Foundation C.I.C.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package deltas
import (
"database/sql"
"encoding/json"
"fmt"
"github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/dendrite/roomserver/types"
)
func LoadAddDisplaynameColumn(m *sqlutil.Migrations) {
m.AddMigration(UpAddDisplaynameColumn, DownAddDisplaynameColumn)
}
func UpAddDisplaynameColumn(tx *sql.Tx) error {
_, err := tx.Exec(` ALTER TABLE roomserver_membership RENAME TO roomserver_membership_tmp;
CREATE TABLE IF NOT EXISTS roomserver_membership (
room_nid INTEGER NOT NULL,
target_nid INTEGER NOT NULL,
sender_nid INTEGER NOT NULL DEFAULT 0,
membership_nid INTEGER NOT NULL DEFAULT 1,
event_nid INTEGER NOT NULL DEFAULT 0,
target_local BOOLEAN NOT NULL DEFAULT false,
forgotten BOOLEAN NOT NULL DEFAULT false,
displayname TEXT NOT NULL DEFAULT '',
UNIQUE (room_nid, target_nid)
);
INSERT
INTO roomserver_membership (
room_nid, target_nid, sender_nid, membership_nid, event_nid, target_local, forgotten
) SELECT
room_nid, target_nid, sender_nid, membership_nid, event_nid, target_local, forgotten
FROM roomserver_membership_tmp
;
DROP TABLE roomserver_membership_tmp;`)
if err != nil {
return fmt.Errorf("failed to execute upgrade: %w", err)
}
rows, err := tx.Query(`SELECT room_nid, target_nid, event_json FROM roomserver_membership
INNER JOIN roomserver_event_json ON
roomserver_membership.event_nid = roomserver_event_json.event_nid
WHERE displayname = '';
`)
if err != nil {
return fmt.Errorf("failed to execute upgrade: %w", err)
}
for rows.Next() {
var roomNID types.RoomNID
var targetUserNID types.EventStateKeyNID
var eventJSONRaw []byte
if err = rows.Scan(&roomNID, &targetUserNID, &eventJSONRaw); err != nil {
return fmt.Errorf("error scanning row: %v", err)
}
eventJSON := make(map[string]interface{})
err = json.Unmarshal(eventJSONRaw, &eventJSON)
if err != nil {
return fmt.Errorf("could not unmarshal event JSON: %v", err)
}
eventDisplayname := ""
if content, ok := eventJSON["content"]; ok {
if displayname, ok := content.(map[string]interface{})["displayname"]; ok {
if displaynameString, ok := displayname.(string); ok {
eventDisplayname = displaynameString
}
}
}
if eventDisplayname != "" {
_, err = tx.Exec(`UPDATE roomserver_membership
SET displayname = $1
WHERE room_nid = $2 AND target_nid = $3;`,
eventDisplayname, roomNID, targetUserNID)
if err != nil {
return fmt.Errorf("could not update displayname field: %v", err)
}
}
}
return nil
}
func DownAddDisplaynameColumn(tx *sql.Tx) error {
_, err := tx.Exec(` ALTER TABLE roomserver_membership RENAME TO roomserver_membership_tmp;
CREATE TABLE IF NOT EXISTS roomserver_membership (
room_nid INTEGER NOT NULL,
target_nid INTEGER NOT NULL,
sender_nid INTEGER NOT NULL DEFAULT 0,
membership_nid INTEGER NOT NULL DEFAULT 1,
event_nid INTEGER NOT NULL DEFAULT 0,
target_local BOOLEAN NOT NULL DEFAULT false,
forgotten BOOLEAN NOT NULL DEFAULT false,
UNIQUE (room_nid, target_nid)
);
INSERT
INTO roomserver_membership (
room_nid, target_nid, sender_nid, membership_nid, event_nid, target_local, forgotten
) SELECT
room_nid, target_nid, sender_nid, membership_nid, event_nid, target_local, forgotten
FROM roomserver_membership_tmp
;
DROP TABLE roomserver_membership_tmp;`)
if err != nil {
return fmt.Errorf("failed to execute downgrade: %w", err)
}
return nil
}

View file

@ -37,6 +37,7 @@ const membershipSchema = `
event_nid INTEGER NOT NULL DEFAULT 0, event_nid INTEGER NOT NULL DEFAULT 0,
target_local BOOLEAN NOT NULL DEFAULT false, target_local BOOLEAN NOT NULL DEFAULT false,
forgotten BOOLEAN NOT NULL DEFAULT false, forgotten BOOLEAN NOT NULL DEFAULT false,
displayname TEXT NOT NULL DEFAULT '',
UNIQUE (room_nid, target_nid) UNIQUE (room_nid, target_nid)
); );
` `
@ -80,8 +81,8 @@ const selectMembershipForUpdateSQL = "" +
" WHERE room_nid = $1 AND target_nid = $2" " WHERE room_nid = $1 AND target_nid = $2"
const updateMembershipSQL = "" + const updateMembershipSQL = "" +
"UPDATE roomserver_membership SET sender_nid = $1, membership_nid = $2, event_nid = $3, forgotten = $4" + "UPDATE roomserver_membership SET sender_nid = $1, membership_nid = $2, event_nid = $3, forgotten = $4, displayname = $5" +
" WHERE room_nid = $5 AND target_nid = $6" " WHERE room_nid = $6 AND target_nid = $7"
const updateMembershipForgetRoom = "" + const updateMembershipForgetRoom = "" +
"UPDATE roomserver_membership SET forgotten = $1" + "UPDATE roomserver_membership SET forgotten = $1" +
@ -94,11 +95,16 @@ const selectRoomsWithMembershipSQL = "" +
// joined to. Since this information is used to populate the user directory, we will // joined to. Since this information is used to populate the user directory, we will
// only return users that the user would ordinarily be able to see anyway. // only return users that the user would ordinarily be able to see anyway.
var selectKnownUsersSQL = "" + var selectKnownUsersSQL = "" +
"SELECT DISTINCT event_state_key FROM roomserver_membership INNER JOIN roomserver_event_state_keys ON " + "SELECT DISTINCT event_state_key, displayname FROM roomserver_membership INNER JOIN roomserver_event_state_keys ON " +
"roomserver_membership.target_nid = roomserver_event_state_keys.event_state_key_nid " + "roomserver_membership.target_nid = roomserver_event_state_keys.event_state_key_nid " +
"WHERE room_nid IN (" + "WHERE room_nid IN (" +
" SELECT DISTINCT room_nid FROM roomserver_membership WHERE target_nid = $1 AND membership_nid = " + fmt.Sprintf("%d", tables.MembershipStateJoin) + " SELECT DISTINCT room_nid FROM roomserver_membership WHERE target_nid = $1 AND membership_nid = " + fmt.Sprintf("%d", tables.MembershipStateJoin) +
") AND membership_nid = " + fmt.Sprintf("%d", tables.MembershipStateJoin) + " AND event_state_key LIKE $2 LIMIT $3" " UNION " +
" SELECT DISTINCT room_nid from roomserver_rooms INNER JOIN roomserver_published ON " +
" roomserver_rooms.room_id = roomserver_published.room_id WHERE published = true " +
") AND membership_nid = " + fmt.Sprintf("%d", tables.MembershipStateJoin) + " AND ( " +
" event_state_key LIKE $2 OR displayname LIKE $2" +
") LIMIT $3"
// selectLocalServerInRoomSQL is an optimised case for checking if we, the local server, // selectLocalServerInRoomSQL is an optimised case for checking if we, the local server,
// are in the room by using the target_local column of the membership table. Normally when // are in the room by using the target_local column of the membership table. Normally when
@ -248,11 +254,11 @@ func (s *membershipStatements) SelectMembershipsFromRoomAndMembership(
func (s *membershipStatements) UpdateMembership( func (s *membershipStatements) UpdateMembership(
ctx context.Context, txn *sql.Tx, ctx context.Context, txn *sql.Tx,
roomNID types.RoomNID, targetUserNID types.EventStateKeyNID, senderUserNID types.EventStateKeyNID, membership tables.MembershipState, roomNID types.RoomNID, targetUserNID types.EventStateKeyNID, senderUserNID types.EventStateKeyNID, membership tables.MembershipState,
eventNID types.EventNID, forgotten bool, eventNID types.EventNID, forgotten bool, displayname string,
) error { ) error {
stmt := sqlutil.TxStmt(txn, s.updateMembershipStmt) stmt := sqlutil.TxStmt(txn, s.updateMembershipStmt)
_, err := stmt.ExecContext( _, err := stmt.ExecContext(
ctx, senderUserNID, membership, eventNID, forgotten, roomNID, targetUserNID, ctx, senderUserNID, membership, eventNID, forgotten, displayname, roomNID, targetUserNID,
) )
return err return err
} }
@ -308,7 +314,8 @@ func (s *membershipStatements) SelectKnownUsers(ctx context.Context, userID type
defer internal.CloseAndLogIfError(ctx, rows, "SelectKnownUsers: rows.close() failed") defer internal.CloseAndLogIfError(ctx, rows, "SelectKnownUsers: rows.close() failed")
for rows.Next() { for rows.Next() {
var userID string var userID string
if err := rows.Scan(&userID); err != nil { var displayname string
if err := rows.Scan(&userID, &displayname); err != nil {
return nil, err return nil, err
} }
result = append(result, userID) result = append(result, userID)

View file

@ -61,6 +61,7 @@ func Open(dbProperties *config.DatabaseOptions, cache caching.RoomServerCaches)
m := sqlutil.NewMigrations() m := sqlutil.NewMigrations()
deltas.LoadAddForgottenColumn(m) deltas.LoadAddForgottenColumn(m)
deltas.LoadStateBlocksRefactor(m) deltas.LoadStateBlocksRefactor(m)
deltas.LoadAddDisplaynameColumn(m)
if err := m.RunDeltas(db, dbProperties); err != nil { if err := m.RunDeltas(db, dbProperties); err != nil {
return nil, err return nil, err
} }

View file

@ -129,7 +129,7 @@ type Membership interface {
SelectMembershipFromRoomAndTarget(ctx context.Context, roomNID types.RoomNID, targetUserNID types.EventStateKeyNID) (types.EventNID, MembershipState, bool, error) SelectMembershipFromRoomAndTarget(ctx context.Context, roomNID types.RoomNID, targetUserNID types.EventStateKeyNID) (types.EventNID, MembershipState, bool, error)
SelectMembershipsFromRoom(ctx context.Context, roomNID types.RoomNID, localOnly bool) (eventNIDs []types.EventNID, err error) SelectMembershipsFromRoom(ctx context.Context, roomNID types.RoomNID, localOnly bool) (eventNIDs []types.EventNID, err error)
SelectMembershipsFromRoomAndMembership(ctx context.Context, roomNID types.RoomNID, membership MembershipState, localOnly bool) (eventNIDs []types.EventNID, err error) SelectMembershipsFromRoomAndMembership(ctx context.Context, roomNID types.RoomNID, membership MembershipState, localOnly bool) (eventNIDs []types.EventNID, err error)
UpdateMembership(ctx context.Context, txn *sql.Tx, roomNID types.RoomNID, targetUserNID types.EventStateKeyNID, senderUserNID types.EventStateKeyNID, membership MembershipState, eventNID types.EventNID, forgotten bool) error UpdateMembership(ctx context.Context, txn *sql.Tx, roomNID types.RoomNID, targetUserNID types.EventStateKeyNID, senderUserNID types.EventStateKeyNID, membership MembershipState, eventNID types.EventNID, forgotten bool, displayname string) error
SelectRoomsWithMembership(ctx context.Context, userID types.EventStateKeyNID, membershipState MembershipState) ([]types.RoomNID, error) SelectRoomsWithMembership(ctx context.Context, userID types.EventStateKeyNID, membershipState MembershipState) ([]types.RoomNID, error)
// SelectJoinedUsersSetForRooms returns the set of all users in the rooms who are joined to any of these rooms, along with the // SelectJoinedUsersSetForRooms returns the set of all users in the rooms who are joined to any of these rooms, along with the
// counts of how many rooms they are joined. // counts of how many rooms they are joined.

View file

@ -554,3 +554,7 @@ Can upload self-signing keys
Fails to upload self-signing keys with no auth Fails to upload self-signing keys with no auth
Fails to upload self-signing key without master key Fails to upload self-signing key without master key
can fetch self-signing keys over federation can fetch self-signing keys over federation
User in private room doesn't appear in user directory
User joining then leaving public room appears and dissappears from directory
User in remote room doesn't appear in user directory after server left room
User in shared private room does appear in user directory until leave