mirror of
https://github.com/hoernschen/dendrite.git
synced 2025-07-30 21:12:45 +00:00
[pseudoID] More pseudo ID fixes (#3167)
Signed-off-by: `Sam Wedgwood <sam@wedgwood.dev>`
This commit is contained in:
parent
fa6c7ba456
commit
9a12420428
24 changed files with 472 additions and 237 deletions
|
@ -141,11 +141,28 @@ type QueryRoomHierarchyAPI interface {
|
|||
QueryNextRoomHierarchyPage(ctx context.Context, walker RoomHierarchyWalker, limit int) ([]fclient.RoomHierarchyRoom, *RoomHierarchyWalker, error)
|
||||
}
|
||||
|
||||
type QueryMembershipAPI interface {
|
||||
QueryMembershipForSenderID(ctx context.Context, roomID spec.RoomID, senderID spec.SenderID, res *QueryMembershipForUserResponse) error
|
||||
QueryMembershipForUser(ctx context.Context, req *QueryMembershipForUserRequest, res *QueryMembershipForUserResponse) error
|
||||
QueryMembershipsForRoom(ctx context.Context, req *QueryMembershipsForRoomRequest, res *QueryMembershipsForRoomResponse) error
|
||||
QueryRoomVersionForRoom(ctx context.Context, roomID string) (gomatrixserverlib.RoomVersion, error)
|
||||
|
||||
// QueryMembershipAtEvent queries the memberships at the given events.
|
||||
// Returns a map from eventID to *types.HeaderedEvent of membership events.
|
||||
QueryMembershipAtEvent(
|
||||
ctx context.Context,
|
||||
roomID spec.RoomID,
|
||||
eventIDs []string,
|
||||
senderID spec.SenderID,
|
||||
) (map[string]*types.HeaderedEvent, error)
|
||||
}
|
||||
|
||||
// API functions required by the syncapi
|
||||
type SyncRoomserverAPI interface {
|
||||
QueryLatestEventsAndStateAPI
|
||||
QueryBulkStateContentAPI
|
||||
QuerySenderIDAPI
|
||||
QueryMembershipAPI
|
||||
// QuerySharedUsers returns a list of users who share at least 1 room in common with the given user.
|
||||
QuerySharedUsers(ctx context.Context, req *QuerySharedUsersRequest, res *QuerySharedUsersResponse) error
|
||||
// QueryEventsByID queries a list of events by event ID for one room. If no room is specified, it will try to determine
|
||||
|
@ -155,12 +172,6 @@ type SyncRoomserverAPI interface {
|
|||
req *QueryEventsByIDRequest,
|
||||
res *QueryEventsByIDResponse,
|
||||
) error
|
||||
// Query the membership event for an user for a room.
|
||||
QueryMembershipForUser(
|
||||
ctx context.Context,
|
||||
req *QueryMembershipForUserRequest,
|
||||
res *QueryMembershipForUserResponse,
|
||||
) error
|
||||
|
||||
// Query the state after a list of events in a room from the room server.
|
||||
QueryStateAfterEvents(
|
||||
|
@ -175,14 +186,6 @@ type SyncRoomserverAPI interface {
|
|||
req *PerformBackfillRequest,
|
||||
res *PerformBackfillResponse,
|
||||
) error
|
||||
|
||||
// QueryMembershipAtEvent queries the memberships at the given events.
|
||||
// Returns a map from eventID to a slice of types.HeaderedEvent.
|
||||
QueryMembershipAtEvent(
|
||||
ctx context.Context,
|
||||
request *QueryMembershipAtEventRequest,
|
||||
response *QueryMembershipAtEventResponse,
|
||||
) error
|
||||
}
|
||||
|
||||
type AppserviceRoomserverAPI interface {
|
||||
|
@ -219,7 +222,7 @@ type ClientRoomserverAPI interface {
|
|||
DefaultRoomVersionAPI
|
||||
QueryMembershipForUser(ctx context.Context, req *QueryMembershipForUserRequest, res *QueryMembershipForUserResponse) error
|
||||
QueryMembershipsForRoom(ctx context.Context, req *QueryMembershipsForRoomRequest, res *QueryMembershipsForRoomResponse) error
|
||||
QueryRoomsForUser(ctx context.Context, req *QueryRoomsForUserRequest, res *QueryRoomsForUserResponse) error
|
||||
QueryRoomsForUser(ctx context.Context, userID spec.UserID, desiredMembership string) ([]spec.RoomID, error)
|
||||
QueryStateAfterEvents(ctx context.Context, req *QueryStateAfterEventsRequest, res *QueryStateAfterEventsResponse) error
|
||||
// QueryKnownUsers returns a list of users that we know about from our joined rooms.
|
||||
QueryKnownUsers(ctx context.Context, req *QueryKnownUsersRequest, res *QueryKnownUsersResponse) error
|
||||
|
@ -278,15 +281,12 @@ type FederationRoomserverAPI interface {
|
|||
QueryBulkStateContentAPI
|
||||
QuerySenderIDAPI
|
||||
QueryRoomHierarchyAPI
|
||||
QueryMembershipAPI
|
||||
UserRoomPrivateKeyCreator
|
||||
AssignRoomNID(ctx context.Context, roomID spec.RoomID, roomVersion gomatrixserverlib.RoomVersion) (roomNID types.RoomNID, err error)
|
||||
SigningIdentityFor(ctx context.Context, roomID spec.RoomID, senderID spec.UserID) (fclient.SigningIdentity, error)
|
||||
// QueryServerBannedFromRoom returns whether a server is banned from a room by server ACLs.
|
||||
QueryServerBannedFromRoom(ctx context.Context, req *QueryServerBannedFromRoomRequest, res *QueryServerBannedFromRoomResponse) error
|
||||
QueryMembershipForUser(ctx context.Context, req *QueryMembershipForUserRequest, res *QueryMembershipForUserResponse) error
|
||||
QueryMembershipForSenderID(ctx context.Context, roomID spec.RoomID, senderID spec.SenderID, res *QueryMembershipForUserResponse) error
|
||||
QueryMembershipsForRoom(ctx context.Context, req *QueryMembershipsForRoomRequest, res *QueryMembershipsForRoomResponse) error
|
||||
QueryRoomVersionForRoom(ctx context.Context, roomID string) (gomatrixserverlib.RoomVersion, error)
|
||||
GetRoomIDForAlias(ctx context.Context, req *GetRoomIDForAliasRequest, res *GetRoomIDForAliasResponse) error
|
||||
// QueryEventsByID queries a list of events by event ID for one room. If no room is specified, it will try to determine
|
||||
// which room to use by querying the first events roomID.
|
||||
|
@ -300,7 +300,7 @@ type FederationRoomserverAPI interface {
|
|||
QueryMissingEvents(ctx context.Context, req *QueryMissingEventsRequest, res *QueryMissingEventsResponse) error
|
||||
// Query whether a server is allowed to see an event
|
||||
QueryServerAllowedToSeeEvent(ctx context.Context, serverName spec.ServerName, eventID string, roomID string) (allowed bool, err error)
|
||||
QueryRoomsForUser(ctx context.Context, req *QueryRoomsForUserRequest, res *QueryRoomsForUserResponse) error
|
||||
QueryRoomsForUser(ctx context.Context, userID spec.UserID, desiredMembership string) ([]spec.RoomID, error)
|
||||
QueryRestrictedJoinAllowed(ctx context.Context, roomID spec.RoomID, senderID spec.SenderID) (string, error)
|
||||
PerformInboundPeek(ctx context.Context, req *PerformInboundPeekRequest, res *PerformInboundPeekResponse) error
|
||||
HandleInvite(ctx context.Context, event *types.HeaderedEvent) error
|
||||
|
|
|
@ -132,6 +132,8 @@ type QueryMembershipForUserResponse struct {
|
|||
// True if the user asked to forget this room.
|
||||
IsRoomForgotten bool `json:"is_room_forgotten"`
|
||||
RoomExists bool `json:"room_exists"`
|
||||
// The sender ID of the user in the room, if it exists
|
||||
SenderID *spec.SenderID
|
||||
}
|
||||
|
||||
// QueryMembershipsForRoomRequest is a request to QueryMembershipsForRoom
|
||||
|
@ -289,16 +291,6 @@ type QuerySharedUsersResponse struct {
|
|||
UserIDsToCount map[string]int
|
||||
}
|
||||
|
||||
type QueryRoomsForUserRequest struct {
|
||||
UserID string
|
||||
// The desired membership of the user. If this is the empty string then no rooms are returned.
|
||||
WantMembership string
|
||||
}
|
||||
|
||||
type QueryRoomsForUserResponse struct {
|
||||
RoomIDs []string
|
||||
}
|
||||
|
||||
type QueryBulkStateContentRequest struct {
|
||||
// Returns state events in these rooms
|
||||
RoomIDs []string
|
||||
|
@ -414,22 +406,6 @@ func (r *QueryCurrentStateResponse) UnmarshalJSON(data []byte) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// QueryMembershipAtEventRequest requests the membership event for a user
|
||||
// for a list of eventIDs.
|
||||
type QueryMembershipAtEventRequest struct {
|
||||
RoomID string
|
||||
EventIDs []string
|
||||
UserID string
|
||||
}
|
||||
|
||||
// QueryMembershipAtEventResponse is the response to QueryMembershipAtEventRequest.
|
||||
type QueryMembershipAtEventResponse struct {
|
||||
// Membership is a map from eventID to membership event. Events that
|
||||
// do not have known state will return a nil event, resulting in a "leave" membership
|
||||
// when calculating history visibility.
|
||||
Membership map[string]*types.HeaderedEvent `json:"membership"`
|
||||
}
|
||||
|
||||
// QueryLeftUsersRequest is a request to calculate users that we (the server) don't share a
|
||||
// a room with anymore. This is used to cleanup stale device list entries, where we would
|
||||
// otherwise keep on trying to get device lists.
|
||||
|
|
|
@ -161,12 +161,12 @@ func (r *Admin) PerformAdminEvacuateUser(
|
|||
return nil, fmt.Errorf("can only evacuate local users using this endpoint")
|
||||
}
|
||||
|
||||
roomIDs, err := r.DB.GetRoomsByMembership(ctx, userID, spec.Join)
|
||||
roomIDs, err := r.DB.GetRoomsByMembership(ctx, *fullUserID, spec.Join)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
inviteRoomIDs, err := r.DB.GetRoomsByMembership(ctx, userID, spec.Invite)
|
||||
inviteRoomIDs, err := r.DB.GetRoomsByMembership(ctx, *fullUserID, spec.Invite)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -230,6 +230,33 @@ func (r *Queryer) QueryMembershipForSenderID(
|
|||
senderID spec.SenderID,
|
||||
response *api.QueryMembershipForUserResponse,
|
||||
) error {
|
||||
return r.queryMembershipForOptionalSenderID(ctx, roomID, &senderID, response)
|
||||
}
|
||||
|
||||
// QueryMembershipForUser implements api.RoomserverInternalAPI
|
||||
func (r *Queryer) QueryMembershipForUser(
|
||||
ctx context.Context,
|
||||
request *api.QueryMembershipForUserRequest,
|
||||
response *api.QueryMembershipForUserResponse,
|
||||
) error {
|
||||
roomID, err := spec.NewRoomID(request.RoomID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
senderID, err := r.QuerySenderIDForUser(ctx, *roomID, request.UserID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return r.queryMembershipForOptionalSenderID(ctx, *roomID, senderID, response)
|
||||
}
|
||||
|
||||
// Query membership information for provided sender ID and room ID
|
||||
//
|
||||
// If sender ID is nil, then act as if the provided sender is not a member of the room.
|
||||
func (r *Queryer) queryMembershipForOptionalSenderID(ctx context.Context, roomID spec.RoomID, senderID *spec.SenderID, response *api.QueryMembershipForUserResponse) error {
|
||||
response.SenderID = senderID
|
||||
|
||||
info, err := r.DB.RoomInfo(ctx, roomID.String())
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -240,7 +267,11 @@ func (r *Queryer) QueryMembershipForSenderID(
|
|||
}
|
||||
response.RoomExists = true
|
||||
|
||||
membershipEventNID, stillInRoom, isRoomforgotten, err := r.DB.GetMembership(ctx, info.RoomNID, senderID)
|
||||
if senderID == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
membershipEventNID, stillInRoom, isRoomforgotten, err := r.DB.GetMembership(ctx, info.RoomNID, *senderID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -268,70 +299,55 @@ func (r *Queryer) QueryMembershipForSenderID(
|
|||
return err
|
||||
}
|
||||
|
||||
// QueryMembershipForUser implements api.RoomserverInternalAPI
|
||||
func (r *Queryer) QueryMembershipForUser(
|
||||
ctx context.Context,
|
||||
request *api.QueryMembershipForUserRequest,
|
||||
response *api.QueryMembershipForUserResponse,
|
||||
) error {
|
||||
roomID, err := spec.NewRoomID(request.RoomID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
senderID, err := r.QuerySenderIDForUser(ctx, *roomID, request.UserID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return r.QueryMembershipForSenderID(ctx, *roomID, *senderID, response)
|
||||
}
|
||||
|
||||
// QueryMembershipAtEvent returns the known memberships at a given event.
|
||||
// If the state before an event is not known, an empty list will be returned
|
||||
// for that event instead.
|
||||
//
|
||||
// Returned map from eventID to membership event. Events that
|
||||
// do not have known state will return a nil event, resulting in a "leave" membership
|
||||
// when calculating history visibility.
|
||||
func (r *Queryer) QueryMembershipAtEvent(
|
||||
ctx context.Context,
|
||||
request *api.QueryMembershipAtEventRequest,
|
||||
response *api.QueryMembershipAtEventResponse,
|
||||
) error {
|
||||
response.Membership = make(map[string]*types.HeaderedEvent)
|
||||
|
||||
info, err := r.DB.RoomInfo(ctx, request.RoomID)
|
||||
roomID spec.RoomID,
|
||||
eventIDs []string,
|
||||
senderID spec.SenderID,
|
||||
) (map[string]*types.HeaderedEvent, error) {
|
||||
info, err := r.DB.RoomInfo(ctx, roomID.String())
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to get roomInfo: %w", err)
|
||||
return nil, fmt.Errorf("unable to get roomInfo: %w", err)
|
||||
}
|
||||
if info == nil {
|
||||
return fmt.Errorf("no roomInfo found")
|
||||
return nil, fmt.Errorf("no roomInfo found")
|
||||
}
|
||||
|
||||
// get the users stateKeyNID
|
||||
stateKeyNIDs, err := r.DB.EventStateKeyNIDs(ctx, []string{request.UserID})
|
||||
stateKeyNIDs, err := r.DB.EventStateKeyNIDs(ctx, []string{string(senderID)})
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to get stateKeyNIDs for %s: %w", request.UserID, err)
|
||||
return nil, fmt.Errorf("unable to get stateKeyNIDs for %s: %w", senderID, err)
|
||||
}
|
||||
if _, ok := stateKeyNIDs[request.UserID]; !ok {
|
||||
return fmt.Errorf("requested stateKeyNID for %s was not found", request.UserID)
|
||||
if _, ok := stateKeyNIDs[string(senderID)]; !ok {
|
||||
return nil, fmt.Errorf("requested stateKeyNID for %s was not found", senderID)
|
||||
}
|
||||
|
||||
response.Membership, err = r.DB.GetMembershipForHistoryVisibility(ctx, stateKeyNIDs[request.UserID], info, request.EventIDs...)
|
||||
eventIDMembershipMap, err := r.DB.GetMembershipForHistoryVisibility(ctx, stateKeyNIDs[string(senderID)], info, eventIDs...)
|
||||
switch err {
|
||||
case nil:
|
||||
return nil
|
||||
return eventIDMembershipMap, nil
|
||||
case tables.OptimisationNotSupportedError: // fallthrough, slow way of getting the membership events for each event
|
||||
default:
|
||||
return err
|
||||
return eventIDMembershipMap, err
|
||||
}
|
||||
|
||||
response.Membership = make(map[string]*types.HeaderedEvent)
|
||||
stateEntries, err := helpers.MembershipAtEvent(ctx, r.DB, nil, request.EventIDs, stateKeyNIDs[request.UserID], r)
|
||||
eventIDMembershipMap = make(map[string]*types.HeaderedEvent)
|
||||
stateEntries, err := helpers.MembershipAtEvent(ctx, r.DB, nil, eventIDs, stateKeyNIDs[string(senderID)], r)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to get state before event: %w", err)
|
||||
return eventIDMembershipMap, fmt.Errorf("unable to get state before event: %w", err)
|
||||
}
|
||||
|
||||
// If we only have one or less state entries, we can short circuit the below
|
||||
// loop and avoid hitting the database
|
||||
allStateEventNIDs := make(map[types.EventNID]types.StateEntry)
|
||||
for _, eventID := range request.EventIDs {
|
||||
for _, eventID := range eventIDs {
|
||||
stateEntry := stateEntries[eventID]
|
||||
for _, s := range stateEntry {
|
||||
allStateEventNIDs[s.EventNID] = s
|
||||
|
@ -344,10 +360,10 @@ func (r *Queryer) QueryMembershipAtEvent(
|
|||
}
|
||||
|
||||
var memberships []types.Event
|
||||
for _, eventID := range request.EventIDs {
|
||||
for _, eventID := range eventIDs {
|
||||
stateEntry, ok := stateEntries[eventID]
|
||||
if !ok || len(stateEntry) == 0 {
|
||||
response.Membership[eventID] = nil
|
||||
eventIDMembershipMap[eventID] = nil
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -361,7 +377,7 @@ func (r *Queryer) QueryMembershipAtEvent(
|
|||
memberships, err = helpers.GetMembershipsAtState(ctx, r.DB, info, stateEntry, false)
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to get memberships at state: %w", err)
|
||||
return eventIDMembershipMap, fmt.Errorf("unable to get memberships at state: %w", err)
|
||||
}
|
||||
|
||||
// Iterate over all membership events we got. Given we only query the membership for
|
||||
|
@ -369,13 +385,13 @@ func (r *Queryer) QueryMembershipAtEvent(
|
|||
// a given event, overwrite any other existing membership events.
|
||||
for i := range memberships {
|
||||
ev := memberships[i]
|
||||
if ev.Type() == spec.MRoomMember && ev.StateKeyEquals(request.UserID) {
|
||||
response.Membership[eventID] = &types.HeaderedEvent{PDU: ev.PDU}
|
||||
if ev.Type() == spec.MRoomMember && ev.StateKeyEquals(string(senderID)) {
|
||||
eventIDMembershipMap[eventID] = &types.HeaderedEvent{PDU: ev.PDU}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
return eventIDMembershipMap, nil
|
||||
}
|
||||
|
||||
// QueryMembershipsForRoom implements api.RoomserverInternalAPI
|
||||
|
@ -830,13 +846,20 @@ func (r *Queryer) QueryCurrentState(ctx context.Context, req *api.QueryCurrentSt
|
|||
return nil
|
||||
}
|
||||
|
||||
func (r *Queryer) QueryRoomsForUser(ctx context.Context, req *api.QueryRoomsForUserRequest, res *api.QueryRoomsForUserResponse) error {
|
||||
roomIDs, err := r.DB.GetRoomsByMembership(ctx, req.UserID, req.WantMembership)
|
||||
func (r *Queryer) QueryRoomsForUser(ctx context.Context, userID spec.UserID, desiredMembership string) ([]spec.RoomID, error) {
|
||||
roomIDStrs, err := r.DB.GetRoomsByMembership(ctx, userID, desiredMembership)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
res.RoomIDs = roomIDs
|
||||
return nil
|
||||
roomIDs := make([]spec.RoomID, len(roomIDStrs))
|
||||
for i, roomIDStr := range roomIDStrs {
|
||||
roomID, err := spec.NewRoomID(roomIDStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
roomIDs[i] = *roomID
|
||||
}
|
||||
return roomIDs, nil
|
||||
}
|
||||
|
||||
func (r *Queryer) QueryKnownUsers(ctx context.Context, req *api.QueryKnownUsersRequest, res *api.QueryKnownUsersResponse) error {
|
||||
|
@ -879,7 +902,12 @@ func (r *Queryer) QueryLeftUsers(ctx context.Context, req *api.QueryLeftUsersReq
|
|||
}
|
||||
|
||||
func (r *Queryer) QuerySharedUsers(ctx context.Context, req *api.QuerySharedUsersRequest, res *api.QuerySharedUsersResponse) error {
|
||||
roomIDs, err := r.DB.GetRoomsByMembership(ctx, req.UserID, "join")
|
||||
parsedUserID, err := spec.NewUserID(req.UserID, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
roomIDs, err := r.DB.GetRoomsByMembership(ctx, *parsedUserID, "join")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -158,7 +158,7 @@ type Database interface {
|
|||
GetStateEvent(ctx context.Context, roomID, evType, stateKey string) (*types.HeaderedEvent, error)
|
||||
GetStateEventsWithEventType(ctx context.Context, roomID, evType string) ([]*types.HeaderedEvent, error)
|
||||
// GetRoomsByMembership returns a list of room IDs matching the provided membership and user ID (as state_key).
|
||||
GetRoomsByMembership(ctx context.Context, userID, membership string) ([]string, error)
|
||||
GetRoomsByMembership(ctx context.Context, userID spec.UserID, membership string) ([]string, error)
|
||||
// GetBulkStateContent returns all state events which match a given room ID and a given state key tuple. Both must be satisfied for a match.
|
||||
// If a tuple has the StateKey of '*' and allowWildcards=true then all state events with the EventType should be returned.
|
||||
GetBulkStateContent(ctx context.Context, roomIDs []string, tuples []gomatrixserverlib.StateKeyTuple, allowWildcards bool) ([]tables.StrippedEvent, error)
|
||||
|
|
|
@ -56,12 +56,15 @@ const selectUserRoomPublicKeySQL = `SELECT pseudo_id_pub_key FROM roomserver_use
|
|||
|
||||
const selectUserNIDsSQL = `SELECT user_nid, room_nid, pseudo_id_pub_key FROM roomserver_user_room_keys WHERE room_nid = ANY($1) AND pseudo_id_pub_key = ANY($2)`
|
||||
|
||||
const selectAllUserRoomPublicKeyForUserSQL = `SELECT room_nid, pseudo_id_pub_key FROM roomserver_user_room_keys WHERE user_nid = $1`
|
||||
|
||||
type userRoomKeysStatements struct {
|
||||
insertUserRoomPrivateKeyStmt *sql.Stmt
|
||||
insertUserRoomPublicKeyStmt *sql.Stmt
|
||||
selectUserRoomKeyStmt *sql.Stmt
|
||||
selectUserRoomPublicKeyStmt *sql.Stmt
|
||||
selectUserNIDsStmt *sql.Stmt
|
||||
insertUserRoomPrivateKeyStmt *sql.Stmt
|
||||
insertUserRoomPublicKeyStmt *sql.Stmt
|
||||
selectUserRoomKeyStmt *sql.Stmt
|
||||
selectUserRoomPublicKeyStmt *sql.Stmt
|
||||
selectUserNIDsStmt *sql.Stmt
|
||||
selectAllUserRoomPublicKeysForUser *sql.Stmt
|
||||
}
|
||||
|
||||
func CreateUserRoomKeysTable(db *sql.DB) error {
|
||||
|
@ -77,6 +80,7 @@ func PrepareUserRoomKeysTable(db *sql.DB) (tables.UserRoomKeys, error) {
|
|||
{&s.selectUserRoomKeyStmt, selectUserRoomKeySQL},
|
||||
{&s.selectUserRoomPublicKeyStmt, selectUserRoomPublicKeySQL},
|
||||
{&s.selectUserNIDsStmt, selectUserNIDsSQL},
|
||||
{&s.selectAllUserRoomPublicKeysForUser, selectAllUserRoomPublicKeyForUserSQL},
|
||||
}.Prepare(db)
|
||||
}
|
||||
|
||||
|
@ -150,3 +154,24 @@ func (s *userRoomKeysStatements) BulkSelectUserNIDs(ctx context.Context, txn *sq
|
|||
}
|
||||
return result, rows.Err()
|
||||
}
|
||||
|
||||
func (s *userRoomKeysStatements) SelectAllPublicKeysForUser(ctx context.Context, txn *sql.Tx, userNID types.EventStateKeyNID) (map[types.RoomNID]ed25519.PublicKey, error) {
|
||||
stmt := sqlutil.TxStmtContext(ctx, txn, s.selectAllUserRoomPublicKeysForUser)
|
||||
|
||||
rows, err := stmt.QueryContext(ctx, userNID)
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
resultMap := make(map[types.RoomNID]ed25519.PublicKey)
|
||||
|
||||
var roomNID types.RoomNID
|
||||
var pubkey ed25519.PublicKey
|
||||
for rows.Next() {
|
||||
if err = rows.Scan(&roomNID, &pubkey); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resultMap[roomNID] = pubkey
|
||||
}
|
||||
return resultMap, err
|
||||
}
|
||||
|
|
|
@ -1347,7 +1347,7 @@ func (d *Database) GetStateEventsWithEventType(ctx context.Context, roomID, evTy
|
|||
}
|
||||
|
||||
// GetRoomsByMembership returns a list of room IDs matching the provided membership and user ID (as state_key).
|
||||
func (d *Database) GetRoomsByMembership(ctx context.Context, userID, membership string) ([]string, error) {
|
||||
func (d *Database) GetRoomsByMembership(ctx context.Context, userID spec.UserID, membership string) ([]string, error) {
|
||||
var membershipState tables.MembershipState
|
||||
switch membership {
|
||||
case "join":
|
||||
|
@ -1361,17 +1361,73 @@ func (d *Database) GetRoomsByMembership(ctx context.Context, userID, membership
|
|||
default:
|
||||
return nil, fmt.Errorf("GetRoomsByMembership: invalid membership %s", membership)
|
||||
}
|
||||
stateKeyNID, err := d.EventStateKeysTable.SelectEventStateKeyNID(ctx, nil, userID)
|
||||
|
||||
// Convert provided user ID to NID
|
||||
userNID, err := d.EventStateKeysTable.SelectEventStateKeyNID(ctx, nil, userID.String())
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, nil
|
||||
} else {
|
||||
return nil, fmt.Errorf("SelectEventStateKeyNID: cannot map user ID to state key NIDs: %w", err)
|
||||
}
|
||||
return nil, fmt.Errorf("GetRoomsByMembership: cannot map user ID to state key NID: %w", err)
|
||||
}
|
||||
roomNIDs, err := d.MembershipTable.SelectRoomsWithMembership(ctx, nil, stateKeyNID, membershipState)
|
||||
|
||||
// Use this NID to fetch all associated room keys (for pseudo ID rooms)
|
||||
roomKeyMap, err := d.UserRoomKeyTable.SelectAllPublicKeysForUser(ctx, nil, userNID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("GetRoomsByMembership: failed to SelectRoomsWithMembership: %w", err)
|
||||
if err == sql.ErrNoRows {
|
||||
roomKeyMap = map[types.RoomNID]ed25519.PublicKey{}
|
||||
} else {
|
||||
return nil, fmt.Errorf("SelectAllPublicKeysForUser: could not select user room public keys for user: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
var eventStateKeyNIDs []types.EventStateKeyNID
|
||||
|
||||
// If there are room keys (i.e. this user is in pseudo ID rooms), then gather the appropriate NIDs
|
||||
if len(roomKeyMap) != 0 {
|
||||
// Convert keys to string representation
|
||||
userRoomKeys := make([]string, len(roomKeyMap))
|
||||
i := 0
|
||||
for _, key := range roomKeyMap {
|
||||
userRoomKeys[i] = spec.Base64Bytes(key).Encode()
|
||||
i += 1
|
||||
}
|
||||
|
||||
// Convert the string representation to its NID
|
||||
pseudoIDStateKeys, sqlErr := d.EventStateKeysTable.BulkSelectEventStateKeyNID(ctx, nil, userRoomKeys)
|
||||
if sqlErr != nil {
|
||||
if sqlErr == sql.ErrNoRows {
|
||||
pseudoIDStateKeys = map[string]types.EventStateKeyNID{}
|
||||
} else {
|
||||
return nil, fmt.Errorf("BulkSelectEventStateKeyNID: could not select state keys for public room keys: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Collect all NIDs together
|
||||
eventStateKeyNIDs = make([]types.EventStateKeyNID, len(pseudoIDStateKeys)+1)
|
||||
eventStateKeyNIDs[0] = userNID
|
||||
i = 1
|
||||
for _, nid := range pseudoIDStateKeys {
|
||||
eventStateKeyNIDs[i] = nid
|
||||
i += 1
|
||||
}
|
||||
} else {
|
||||
// If there are no room keys (so no pseudo ID rooms), we only need to care about the user ID NID.
|
||||
eventStateKeyNIDs = []types.EventStateKeyNID{userNID}
|
||||
}
|
||||
|
||||
// Fetch rooms that match membership for each NID
|
||||
roomNIDs := []types.RoomNID{}
|
||||
for _, nid := range eventStateKeyNIDs {
|
||||
var roomNIDsChunk []types.RoomNID
|
||||
roomNIDsChunk, err = d.MembershipTable.SelectRoomsWithMembership(ctx, nil, nid, membershipState)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("GetRoomsByMembership: failed to SelectRoomsWithMembership: %w", err)
|
||||
}
|
||||
roomNIDs = append(roomNIDs, roomNIDsChunk...)
|
||||
}
|
||||
|
||||
roomIDs, err := d.RoomsTable.BulkSelectRoomIDs(ctx, nil, roomNIDs)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("GetRoomsByMembership: failed to lookup room nids: %w", err)
|
||||
|
|
|
@ -56,12 +56,15 @@ const selectUserRoomPublicKeySQL = `SELECT pseudo_id_pub_key FROM roomserver_use
|
|||
|
||||
const selectUserNIDsSQL = `SELECT user_nid, room_nid, pseudo_id_pub_key FROM roomserver_user_room_keys WHERE room_nid IN ($1) AND pseudo_id_pub_key IN ($2)`
|
||||
|
||||
const selectAllUserRoomPublicKeyForUserSQL = `SELECT room_nid, pseudo_id_pub_key FROM roomserver_user_room_keys WHERE user_nid = $1`
|
||||
|
||||
type userRoomKeysStatements struct {
|
||||
db *sql.DB
|
||||
insertUserRoomPrivateKeyStmt *sql.Stmt
|
||||
insertUserRoomPublicKeyStmt *sql.Stmt
|
||||
selectUserRoomKeyStmt *sql.Stmt
|
||||
selectUserRoomPublicKeyStmt *sql.Stmt
|
||||
db *sql.DB
|
||||
insertUserRoomPrivateKeyStmt *sql.Stmt
|
||||
insertUserRoomPublicKeyStmt *sql.Stmt
|
||||
selectUserRoomKeyStmt *sql.Stmt
|
||||
selectUserRoomPublicKeyStmt *sql.Stmt
|
||||
selectAllUserRoomPublicKeysForUser *sql.Stmt
|
||||
//selectUserNIDsStmt *sql.Stmt //prepared at runtime
|
||||
}
|
||||
|
||||
|
@ -77,6 +80,7 @@ func PrepareUserRoomKeysTable(db *sql.DB) (tables.UserRoomKeys, error) {
|
|||
{&s.insertUserRoomPublicKeyStmt, insertUserRoomPublicKeySQL},
|
||||
{&s.selectUserRoomKeyStmt, selectUserRoomKeySQL},
|
||||
{&s.selectUserRoomPublicKeyStmt, selectUserRoomPublicKeySQL},
|
||||
{&s.selectAllUserRoomPublicKeysForUser, selectAllUserRoomPublicKeyForUserSQL},
|
||||
//{&s.selectUserNIDsStmt, selectUserNIDsSQL}, //prepared at runtime
|
||||
}.Prepare(db)
|
||||
}
|
||||
|
@ -165,3 +169,24 @@ func (s *userRoomKeysStatements) BulkSelectUserNIDs(ctx context.Context, txn *sq
|
|||
}
|
||||
return result, rows.Err()
|
||||
}
|
||||
|
||||
func (s *userRoomKeysStatements) SelectAllPublicKeysForUser(ctx context.Context, txn *sql.Tx, userNID types.EventStateKeyNID) (map[types.RoomNID]ed25519.PublicKey, error) {
|
||||
stmt := sqlutil.TxStmtContext(ctx, txn, s.selectAllUserRoomPublicKeysForUser)
|
||||
|
||||
rows, err := stmt.QueryContext(ctx, userNID)
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
resultMap := make(map[types.RoomNID]ed25519.PublicKey)
|
||||
|
||||
var roomNID types.RoomNID
|
||||
var pubkey ed25519.PublicKey
|
||||
for rows.Next() {
|
||||
if err = rows.Scan(&roomNID, &pubkey); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resultMap[roomNID] = pubkey
|
||||
}
|
||||
return resultMap, err
|
||||
}
|
||||
|
|
|
@ -198,6 +198,8 @@ type UserRoomKeys interface {
|
|||
// BulkSelectUserNIDs selects all userIDs for the requested senderKeys. Returns a map from publicKey -> types.UserRoomKeyPair.
|
||||
// If a senderKey can't be found, it is omitted in the result.
|
||||
BulkSelectUserNIDs(ctx context.Context, txn *sql.Tx, senderKeys map[types.RoomNID][]ed25519.PublicKey) (map[string]types.UserRoomKeyPair, error)
|
||||
// SelectAllPublicKeysForUser returns all known public keys for a user. Returns a map from room NID -> public key
|
||||
SelectAllPublicKeysForUser(ctx context.Context, txn *sql.Tx, userNID types.EventStateKeyNID) (map[types.RoomNID]ed25519.PublicKey, error)
|
||||
}
|
||||
|
||||
// StrippedEvent represents a stripped event for returning extracted content values.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue