User in private room doesn't appear in user directory
This commit is contained in:
Joshua Hong 2021-06-02 22:18:24 -04:00
parent 3797d818c0
commit aa105dc1a2
14 changed files with 132 additions and 18 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,31 +49,25 @@ func SearchUserDirectory(
Limited: false, Limited: false,
} }
// First start searching local users. // First start searching users in public rooms
userReq := &rsapi.QueryPublicUsersRequest{
userReq := &userapi.QuerySearchProfilesRequest{
SearchString: searchString, SearchString: searchString,
Limit: limit, Limit: limit,
} }
userRes := &userapi.QuerySearchProfilesResponse{} userRes := &rsapi.QueryPublicUsersResponse{}
if err := userAPI.QuerySearchProfiles(ctx, userReq, userRes); err != nil { if err := rsAPI.QueryPublicUsers(ctx, userReq, userRes); err != nil {
errRes := util.ErrorResponse(fmt.Errorf("userAPI.QuerySearchProfiles: %w", err)) errRes := util.ErrorResponse(fmt.Errorf("rsAPI.QueryPublicUsers: %w", err))
return &errRes return &errRes
} }
for _, user := range userRes.Profiles { for _, user := range userRes.Users {
if len(results) == limit { if len(results) == limit {
response.Limited = true response.Limited = true
break break
} }
userID := fmt.Sprintf("@%s:%s", user.Localpart, serverName) if _, ok := results[user.UserID]; !ok {
if _, ok := results[userID]; !ok { results[user.UserID] = user
results[userID] = authtypes.FullyQualifiedProfile{
UserID: userID,
DisplayName: user.DisplayName,
AvatarURL: user.AvatarURL,
}
} }
} }
@ -81,12 +75,12 @@ func SearchUserDirectory(
// start searching for known users from joined rooms. // start searching for known users from joined rooms.
if len(results) <= limit { if len(results) <= limit {
stateReq := &api.QueryKnownUsersRequest{ stateReq := &rsapi.QueryKnownUsersRequest{
UserID: device.UserID, UserID: device.UserID,
SearchString: searchString, SearchString: searchString,
Limit: limit - len(results), Limit: limit - len(results),
} }
stateRes := &api.QueryKnownUsersResponse{} stateRes := &rsapi.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

View file

@ -315,6 +315,10 @@ func (t *testRoomserverAPI) QueryKnownUsers(ctx context.Context, req *api.QueryK
return fmt.Errorf("not implemented") return fmt.Errorf("not implemented")
} }
func (t *testRoomserverAPI) QueryPublicUsers(ctx context.Context, req *api.QueryPublicUsersRequest, res *api.QueryPublicUsersResponse) error {
return fmt.Errorf("not implemented")
}
func (t *testRoomserverAPI) QueryServerBannedFromRoom(ctx context.Context, req *api.QueryServerBannedFromRoomRequest, res *api.QueryServerBannedFromRoomResponse) error { func (t *testRoomserverAPI) QueryServerBannedFromRoom(ctx context.Context, req *api.QueryServerBannedFromRoomRequest, res *api.QueryServerBannedFromRoomResponse) error {
return nil return nil
} }

View file

@ -160,6 +160,8 @@ type RoomserverInternalAPI interface {
QuerySharedUsers(ctx context.Context, req *QuerySharedUsersRequest, res *QuerySharedUsersResponse) error QuerySharedUsers(ctx context.Context, req *QuerySharedUsersRequest, res *QuerySharedUsersResponse) error
// QueryKnownUsers returns a list of users that we know about from our joined rooms. // QueryKnownUsers returns a list of users that we know about from our joined rooms.
QueryKnownUsers(ctx context.Context, req *QueryKnownUsersRequest, res *QueryKnownUsersResponse) error QueryKnownUsers(ctx context.Context, req *QueryKnownUsersRequest, res *QueryKnownUsersResponse) error
// QueryPublicUsers returns a list of users in at least 1 public room.
QueryPublicUsers(ctx context.Context, req *QueryPublicUsersRequest, res *QueryPublicUsersResponse) error
// QueryServerBannedFromRoom returns whether a server is banned from a room by server ACLs. // QueryServerBannedFromRoom returns whether a server is banned from a room by server ACLs.
QueryServerBannedFromRoom(ctx context.Context, req *QueryServerBannedFromRoomRequest, res *QueryServerBannedFromRoomResponse) error QueryServerBannedFromRoom(ctx context.Context, req *QueryServerBannedFromRoomRequest, res *QueryServerBannedFromRoomResponse) error

View file

@ -332,6 +332,13 @@ func (t *RoomserverInternalAPITrace) QueryKnownUsers(ctx context.Context, req *Q
return err return err
} }
// QueryPublicUsers returns a list of users that are in at least one public room.
func (t *RoomserverInternalAPITrace) QueryPublicUsers(ctx context.Context, req *QueryPublicUsersRequest, res *QueryPublicUsersResponse) error {
err := t.Impl.QueryPublicUsers(ctx, req, res)
util.GetLogger(ctx).WithError(err).Infof("QueryPublicUsers req=%+v res=%+v", js(req), js(res))
return err
}
// QueryServerBannedFromRoom returns whether a server is banned from a room by server ACLs. // QueryServerBannedFromRoom returns whether a server is banned from a room by server ACLs.
func (t *RoomserverInternalAPITrace) QueryServerBannedFromRoom(ctx context.Context, req *QueryServerBannedFromRoomRequest, res *QueryServerBannedFromRoomResponse) error { func (t *RoomserverInternalAPITrace) QueryServerBannedFromRoom(ctx context.Context, req *QueryServerBannedFromRoomRequest, res *QueryServerBannedFromRoomResponse) error {
err := t.Impl.QueryServerBannedFromRoom(ctx, req, res) err := t.Impl.QueryServerBannedFromRoom(ctx, req, res)

View file

@ -348,6 +348,15 @@ type QueryKnownUsersResponse struct {
Users []authtypes.FullyQualifiedProfile `json:"profiles"` Users []authtypes.FullyQualifiedProfile `json:"profiles"`
} }
type QueryPublicUsersRequest struct {
SearchString string `json:"search_string"`
Limit int `json:"limit"`
}
type QueryPublicUsersResponse struct {
Users []authtypes.FullyQualifiedProfile `json:"profiles"`
}
type QueryServerBannedFromRoomRequest struct { type QueryServerBannedFromRoomRequest struct {
ServerName gomatrixserverlib.ServerName `json:"server_name"` ServerName gomatrixserverlib.ServerName `json:"server_name"`
RoomID string `json:"room_id"` RoomID string `json:"room_id"`

View file

@ -683,6 +683,19 @@ func (r *Queryer) QueryKnownUsers(ctx context.Context, req *api.QueryKnownUsersR
return nil return nil
} }
func (r *Queryer) QueryPublicUsers(ctx context.Context, req *api.QueryPublicUsersRequest, res *api.QueryPublicUsersResponse) error {
users, err := r.DB.GetPublicUsers(ctx, req.SearchString, req.Limit)
if err != nil {
return err
}
for _, user := range users {
res.Users = append(res.Users, authtypes.FullyQualifiedProfile{
UserID: user,
})
}
return nil
}
func (r *Queryer) QueryBulkStateContent(ctx context.Context, req *api.QueryBulkStateContentRequest, res *api.QueryBulkStateContentResponse) error { func (r *Queryer) QueryBulkStateContent(ctx context.Context, req *api.QueryBulkStateContentRequest, res *api.QueryBulkStateContentResponse) error {
events, err := r.DB.GetBulkStateContent(ctx, req.RoomIDs, req.StateTuples, req.AllowWildcards) events, err := r.DB.GetBulkStateContent(ctx, req.RoomIDs, req.StateTuples, req.AllowWildcards)
if err != nil { if err != nil {

View file

@ -55,6 +55,7 @@ const (
RoomserverQueryBulkStateContentPath = "/roomserver/queryBulkStateContent" RoomserverQueryBulkStateContentPath = "/roomserver/queryBulkStateContent"
RoomserverQuerySharedUsersPath = "/roomserver/querySharedUsers" RoomserverQuerySharedUsersPath = "/roomserver/querySharedUsers"
RoomserverQueryKnownUsersPath = "/roomserver/queryKnownUsers" RoomserverQueryKnownUsersPath = "/roomserver/queryKnownUsers"
RoomserverQueryPublicUsersPath = "/roomserver/queryPublicUsers"
RoomserverQueryServerBannedFromRoomPath = "/roomserver/queryServerBannedFromRoom" RoomserverQueryServerBannedFromRoomPath = "/roomserver/queryServerBannedFromRoom"
RoomserverQueryAuthChainPath = "/roomserver/queryAuthChain" RoomserverQueryAuthChainPath = "/roomserver/queryAuthChain"
) )
@ -521,6 +522,16 @@ func (h *httpRoomserverInternalAPI) QueryKnownUsers(
return httputil.PostJSON(ctx, span, h.httpClient, apiURL, req, res) return httputil.PostJSON(ctx, span, h.httpClient, apiURL, req, res)
} }
func (h *httpRoomserverInternalAPI) QueryPublicUsers(
ctx context.Context, req *api.QueryPublicUsersRequest, res *api.QueryPublicUsersResponse,
) error {
span, ctx := opentracing.StartSpanFromContext(ctx, "QueryPublicUsers")
defer span.Finish()
apiURL := h.roomserverURL + RoomserverQueryPublicUsersPath
return httputil.PostJSON(ctx, span, h.httpClient, apiURL, req, res)
}
func (h *httpRoomserverInternalAPI) QueryAuthChain( func (h *httpRoomserverInternalAPI) QueryAuthChain(
ctx context.Context, req *api.QueryAuthChainRequest, res *api.QueryAuthChainResponse, ctx context.Context, req *api.QueryAuthChainRequest, res *api.QueryAuthChainResponse,
) error { ) error {

View file

@ -452,6 +452,19 @@ func AddRoutes(r api.RoomserverInternalAPI, internalAPIMux *mux.Router) {
return util.JSONResponse{Code: http.StatusOK, JSON: &response} return util.JSONResponse{Code: http.StatusOK, JSON: &response}
}), }),
) )
internalAPIMux.Handle(RoomserverQueryPublicUsersPath,
httputil.MakeInternalAPI("queryPublicUsers", func(req *http.Request) util.JSONResponse {
request := api.QueryPublicUsersRequest{}
response := api.QueryPublicUsersResponse{}
if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
return util.MessageResponse(http.StatusBadRequest, err.Error())
}
if err := r.QueryPublicUsers(req.Context(), &request, &response); err != nil {
return util.ErrorResponse(err)
}
return util.JSONResponse{Code: http.StatusOK, JSON: &response}
}),
)
internalAPIMux.Handle(RoomserverQueryServerBannedFromRoomPath, internalAPIMux.Handle(RoomserverQueryServerBannedFromRoomPath,
httputil.MakeInternalAPI("queryServerBannedFromRoom", func(req *http.Request) util.JSONResponse { httputil.MakeInternalAPI("queryServerBannedFromRoom", func(req *http.Request) util.JSONResponse {
request := api.QueryServerBannedFromRoomRequest{} request := api.QueryServerBannedFromRoomRequest{}

View file

@ -156,6 +156,8 @@ type Database interface {
JoinedUsersSetInRooms(ctx context.Context, roomIDs []string) (map[string]int, error) JoinedUsersSetInRooms(ctx context.Context, roomIDs []string) (map[string]int, error)
// GetKnownUsers searches all users that userID knows about. // GetKnownUsers searches all users that userID knows about.
GetKnownUsers(ctx context.Context, userID, searchString string, limit int) ([]string, error) GetKnownUsers(ctx context.Context, userID, searchString string, limit int) ([]string, error)
// GetPublicUsers searches all users that are in a public room.
GetPublicUsers(ctx context.Context, searchString string, limit int) ([]string, error)
// GetKnownRooms returns a list of all rooms we know about. // GetKnownRooms returns a list of all rooms we know about.
GetKnownRooms(ctx context.Context) ([]string, error) GetKnownRooms(ctx context.Context) ([]string, error)
// ForgetRoom sets a flag in the membership table, that the user wishes to forget a specific room // ForgetRoom sets a flag in the membership table, that the user wishes to forget a specific room

View file

@ -124,6 +124,13 @@ var selectKnownUsersSQL = "" +
" 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" ") AND membership_nid = " + fmt.Sprintf("%d", tables.MembershipStateJoin) + " AND event_state_key LIKE $2 LIMIT $3"
// Select users in public rooms
const selectPublicUsersSQL = "" +
"SELECT DISTINCT event_state_key FROM roomserver_event_state_keys INNER JOIN roomserver_membership ON " +
"roomserver_membership.target_nid = roomserver_event_state_keys.event_state_key_nid INNER JOIN roomserver_rooms ON " +
"roomserver_rooms.room_nid = roomserver_membership.room_nid INNER JOIN roomserver_published ON roomserver_published.room_id = roomserver_rooms.room_id " +
"AND event_state_key LIKE $1 LIMIT $2"
type membershipStatements struct { type membershipStatements struct {
insertMembershipStmt *sql.Stmt insertMembershipStmt *sql.Stmt
selectMembershipForUpdateStmt *sql.Stmt selectMembershipForUpdateStmt *sql.Stmt
@ -136,6 +143,7 @@ type membershipStatements struct {
selectRoomsWithMembershipStmt *sql.Stmt selectRoomsWithMembershipStmt *sql.Stmt
selectJoinedUsersSetForRoomsStmt *sql.Stmt selectJoinedUsersSetForRoomsStmt *sql.Stmt
selectKnownUsersStmt *sql.Stmt selectKnownUsersStmt *sql.Stmt
selectPublicUsersStmt *sql.Stmt
updateMembershipForgetRoomStmt *sql.Stmt updateMembershipForgetRoomStmt *sql.Stmt
} }
@ -159,6 +167,7 @@ func prepareMembershipTable(db *sql.DB) (tables.Membership, error) {
{&s.selectRoomsWithMembershipStmt, selectRoomsWithMembershipSQL}, {&s.selectRoomsWithMembershipStmt, selectRoomsWithMembershipSQL},
{&s.selectJoinedUsersSetForRoomsStmt, selectJoinedUsersSetForRoomsSQL}, {&s.selectJoinedUsersSetForRoomsStmt, selectJoinedUsersSetForRoomsSQL},
{&s.selectKnownUsersStmt, selectKnownUsersSQL}, {&s.selectKnownUsersStmt, selectKnownUsersSQL},
{&s.selectPublicUsersStmt, selectPublicUsersSQL},
{&s.updateMembershipForgetRoomStmt, updateMembershipForgetRoom}, {&s.updateMembershipForgetRoomStmt, updateMembershipForgetRoom},
}.Prepare(db) }.Prepare(db)
} }
@ -314,6 +323,23 @@ func (s *membershipStatements) SelectKnownUsers(ctx context.Context, userID type
return result, rows.Err() return result, rows.Err()
} }
func (s *membershipStatements) SelectPublicUsers(ctx context.Context, searchString string, limit int) ([]string, error) {
rows, err := s.selectPublicUsersStmt.QueryContext(ctx, fmt.Sprintf("%%%s%%", searchString), limit)
if err != nil {
return nil, err
}
result := []string{}
defer internal.CloseAndLogIfError(ctx, rows, "SelectPublicUsers: rows.close() failed")
for rows.Next() {
var userID string
if err := rows.Scan(&userID); err != nil {
return nil, err
}
result = append(result, userID)
}
return result, rows.Err()
}
func (s *membershipStatements) UpdateForgetMembership( func (s *membershipStatements) UpdateForgetMembership(
ctx context.Context, ctx context.Context,
txn *sql.Tx, roomNID types.RoomNID, targetUserNID types.EventStateKeyNID, txn *sql.Tx, roomNID types.RoomNID, targetUserNID types.EventStateKeyNID,

View file

@ -1068,6 +1068,11 @@ func (d *Database) GetKnownUsers(ctx context.Context, userID, searchString strin
return d.MembershipTable.SelectKnownUsers(ctx, stateKeyNID, searchString, limit) return d.MembershipTable.SelectKnownUsers(ctx, stateKeyNID, searchString, limit)
} }
// Get users in public rooms
func (d *Database) GetPublicUsers(ctx context.Context, searchString string, limit int) ([]string, error) {
return d.MembershipTable.SelectPublicUsers(ctx, searchString, limit)
}
// GetKnownRooms returns a list of all rooms we know about. // GetKnownRooms returns a list of all rooms we know about.
func (d *Database) GetKnownRooms(ctx context.Context) ([]string, error) { func (d *Database) GetKnownRooms(ctx context.Context) ([]string, error) {
return d.RoomsTable.SelectRoomIDs(ctx) return d.RoomsTable.SelectRoomIDs(ctx)

View file

@ -100,6 +100,13 @@ var selectKnownUsersSQL = "" +
" 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" ") AND membership_nid = " + fmt.Sprintf("%d", tables.MembershipStateJoin) + " AND event_state_key LIKE $2 LIMIT $3"
// Select users in public rooms
const selectPublicUsersSQL = "" +
"SELECT DISTINCT event_state_key FROM roomserver_event_state_keys INNER JOIN roomserver_membership ON " +
"roomserver_membership.target_nid = roomserver_event_state_keys.event_state_key_nid INNER JOIN roomserver_rooms ON " +
"roomserver_rooms.room_nid = roomserver_membership.room_nid INNER JOIN roomserver_published ON roomserver_published.room_id = roomserver_rooms.room_id " +
"AND event_state_key LIKE $1 LIMIT $2"
type membershipStatements struct { type membershipStatements struct {
db *sql.DB db *sql.DB
insertMembershipStmt *sql.Stmt insertMembershipStmt *sql.Stmt
@ -112,6 +119,7 @@ type membershipStatements struct {
selectRoomsWithMembershipStmt *sql.Stmt selectRoomsWithMembershipStmt *sql.Stmt
updateMembershipStmt *sql.Stmt updateMembershipStmt *sql.Stmt
selectKnownUsersStmt *sql.Stmt selectKnownUsersStmt *sql.Stmt
selectPublicUsersStmt *sql.Stmt
updateMembershipForgetRoomStmt *sql.Stmt updateMembershipForgetRoomStmt *sql.Stmt
} }
@ -136,6 +144,7 @@ func prepareMembershipTable(db *sql.DB) (tables.Membership, error) {
{&s.updateMembershipStmt, updateMembershipSQL}, {&s.updateMembershipStmt, updateMembershipSQL},
{&s.selectRoomsWithMembershipStmt, selectRoomsWithMembershipSQL}, {&s.selectRoomsWithMembershipStmt, selectRoomsWithMembershipSQL},
{&s.selectKnownUsersStmt, selectKnownUsersSQL}, {&s.selectKnownUsersStmt, selectKnownUsersSQL},
{&s.selectPublicUsersStmt, selectPublicUsersSQL},
{&s.updateMembershipForgetRoomStmt, updateMembershipForgetRoom}, {&s.updateMembershipForgetRoomStmt, updateMembershipForgetRoom},
}.Prepare(db) }.Prepare(db)
} }
@ -294,6 +303,23 @@ func (s *membershipStatements) SelectKnownUsers(ctx context.Context, userID type
return result, rows.Err() return result, rows.Err()
} }
func (s *membershipStatements) SelectPublicUsers(ctx context.Context, searchString string, limit int) ([]string, error) {
rows, err := s.selectPublicUsersStmt.QueryContext(ctx, fmt.Sprintf("%%%s%%", searchString), limit)
if err != nil {
return nil, err
}
result := []string{}
defer internal.CloseAndLogIfError(ctx, rows, "SelectPublicUsers: rows.close() failed")
for rows.Next() {
var userID string
if err := rows.Scan(&userID); err != nil {
return nil, err
}
result = append(result, userID)
}
return result, rows.Err()
}
func (s *membershipStatements) UpdateForgetMembership( func (s *membershipStatements) UpdateForgetMembership(
ctx context.Context, ctx context.Context,
txn *sql.Tx, roomNID types.RoomNID, targetUserNID types.EventStateKeyNID, txn *sql.Tx, roomNID types.RoomNID, targetUserNID types.EventStateKeyNID,

View file

@ -134,6 +134,7 @@ type Membership interface {
// counts of how many rooms they are joined. // counts of how many rooms they are joined.
SelectJoinedUsersSetForRooms(ctx context.Context, roomNIDs []types.RoomNID) (map[types.EventStateKeyNID]int, error) SelectJoinedUsersSetForRooms(ctx context.Context, roomNIDs []types.RoomNID) (map[types.EventStateKeyNID]int, error)
SelectKnownUsers(ctx context.Context, userID types.EventStateKeyNID, searchString string, limit int) ([]string, error) SelectKnownUsers(ctx context.Context, userID types.EventStateKeyNID, searchString string, limit int) ([]string, error)
SelectPublicUsers(ctx context.Context, searchString string, limit int) ([]string, error)
UpdateForgetMembership(ctx context.Context, txn *sql.Tx, roomNID types.RoomNID, targetUserNID types.EventStateKeyNID, forget bool) error UpdateForgetMembership(ctx context.Context, txn *sql.Tx, roomNID types.RoomNID, targetUserNID types.EventStateKeyNID, forget bool) error
} }

View file

@ -520,3 +520,4 @@ Inviting an AS-hosted user asks the AS server
Can generate a openid access_token that can be exchanged for information about a user Can generate a openid access_token that can be exchanged for information about a user
Invalid openid access tokens are rejected Invalid openid access tokens are rejected
Requests to userinfo without access tokens are rejected Requests to userinfo without access tokens are rejected
User in private room doesn't appear in user directory