proxy state requests to user IDs to sender IDs

- so state events that use user IDs translate to pseudo IDs in pseudo ID rooms
- e.g. allowing to query m.room.member by user ID in a pseudo ID room
This commit is contained in:
Sam Wedgwood 2023-08-16 11:52:29 +01:00
parent 9a12420428
commit efa50d9a0a

View file

@ -217,6 +217,21 @@ func OnIncomingStateTypeRequest(
var worldReadable bool var worldReadable bool
var wantLatestState bool var wantLatestState bool
parsedRoomID, err := spec.NewRoomID(roomID)
if err != nil {
return util.JSONResponse{
Code: http.StatusNotFound,
JSON: spec.InvalidParam("invalid room ID"),
}
}
// Handle user ID state keys appropriately
newStateKey, errorResp := translateUserStateKey(ctx, rsAPI, stateKey, evType, *parsedRoomID)
if errorResp != nil {
return *errorResp
}
stateKey = *newStateKey
// Always fetch visibility so that we can work out whether to show // Always fetch visibility so that we can work out whether to show
// the latest events or the last event from when the user was joined. // the latest events or the last event from when the user was joined.
// Then include the requested event type and state key, assuming it // Then include the requested event type and state key, assuming it
@ -389,3 +404,41 @@ func OnIncomingStateTypeRequest(
JSON: res, JSON: res,
} }
} }
// If provided state key is a user ID (state keys beginning with @ are reserved for this purpose)
// fetch it's associated sender ID and use that instead. Otherwise returns the same state key back.
//
// This function either returns the state key that should be used, or a JSON error response that should be returned to the user.
//
// TODO: if any step of this process fails, should we fail with 404, or silently continue without using sender ID?
func translateUserStateKey(ctx context.Context, rsAPI api.ClientRoomserverAPI, stateKey string, evType string, roomID spec.RoomID) (*string, *util.JSONResponse) {
if len(stateKey) >= 1 && stateKey[0] == '@' {
parsedStateKey, err := spec.NewUserID(stateKey, true)
if err != nil {
// If invalid user ID, then there is no associated state event.
return nil, &util.JSONResponse{
Code: http.StatusNotFound,
JSON: spec.NotFound(fmt.Sprintf("Cannot find state event for %q", evType)),
}
}
senderID, err := rsAPI.QuerySenderIDForUser(ctx, roomID, *parsedStateKey)
if err != nil {
util.GetLogger(ctx).WithError(err).Error("QuerySenderIDForUser failed")
return nil, &util.JSONResponse{
Code: http.StatusInternalServerError,
JSON: spec.Unknown("internal server error"),
}
}
if senderID == nil {
// If no sender ID, then there is no associated state event.
return nil, &util.JSONResponse{
Code: http.StatusNotFound,
JSON: spec.NotFound(fmt.Sprintf("Cannot find state event for %q", evType)),
}
}
newStateKey := string(*senderID)
return &newStateKey, nil
} else {
return &stateKey, nil
}
}