Skip to content

Commit

Permalink
Add MXIDMapping for pseudoID rooms (#3112)
Browse files Browse the repository at this point in the history
Add `MXIDMapping` on membership events when
creating/joining rooms.
  • Loading branch information
S7evinK authored Jun 28, 2023
1 parent 4722f12 commit 23cd787
Show file tree
Hide file tree
Showing 41 changed files with 592 additions and 176 deletions.
18 changes: 9 additions & 9 deletions clientapi/routing/membership.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,6 @@ import (
"time"

"github.com/getsentry/sentry-go"
"github.com/matrix-org/gomatrixserverlib"
"github.com/matrix-org/gomatrixserverlib/fclient"
"github.com/matrix-org/gomatrixserverlib/spec"

appserviceAPI "github.com/matrix-org/dendrite/appservice/api"
"github.com/matrix-org/dendrite/clientapi/auth/authtypes"
"github.com/matrix-org/dendrite/clientapi/httputil"
Expand All @@ -36,6 +32,9 @@ import (
"github.com/matrix-org/dendrite/roomserver/types"
"github.com/matrix-org/dendrite/setup/config"
userapi "github.com/matrix-org/dendrite/userapi/api"
"github.com/matrix-org/gomatrixserverlib"
"github.com/matrix-org/gomatrixserverlib/fclient"
"github.com/matrix-org/gomatrixserverlib/spec"

"github.com/matrix-org/util"
)
Expand Down Expand Up @@ -433,11 +432,6 @@ func buildMembershipEvent(
return nil, err
}

identity, err := cfg.Matrix.SigningIdentityFor(device.UserDomain())
if err != nil {
return nil, err
}

userID, err := spec.NewUserID(device.UserID, true)
if err != nil {
return nil, err
Expand All @@ -459,6 +453,12 @@ func buildMembershipEvent(
if err != nil {
return nil, err
}

identity, err := rsAPI.SigningIdentityFor(ctx, *validRoomID, *userID)
if err != nil {
return nil, err
}

return buildMembershipEventDirect(ctx, targetSenderID, reason, profile.DisplayName, profile.AvatarURL,
senderID, device.UserDomain(), membership, roomID, isDirect, identity.KeyID, identity.PrivateKey, evTime, rsAPI)
}
Expand Down
20 changes: 12 additions & 8 deletions clientapi/routing/profile.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ func SetAvatarURL(
}
}

response, err := updateProfile(req.Context(), rsAPI, device, profile, userID, cfg, evTime)
response, err := updateProfile(req.Context(), rsAPI, device, profile, userID, evTime)
if err != nil {
return response
}
Expand Down Expand Up @@ -234,7 +234,7 @@ func SetDisplayName(
}
}

response, err := updateProfile(req.Context(), rsAPI, device, profile, userID, cfg, evTime)
response, err := updateProfile(req.Context(), rsAPI, device, profile, userID, evTime)
if err != nil {
return response
}
Expand All @@ -248,7 +248,7 @@ func SetDisplayName(
func updateProfile(
ctx context.Context, rsAPI api.ClientRoomserverAPI, device *userapi.Device,
profile *authtypes.Profile,
userID string, cfg *config.ClientAPI, evTime time.Time,
userID string, evTime time.Time,
) (util.JSONResponse, error) {
var res api.QueryRoomsForUserResponse
err := rsAPI.QueryRoomsForUser(ctx, &api.QueryRoomsForUserRequest{
Expand All @@ -273,7 +273,7 @@ func updateProfile(
}

events, err := buildMembershipEvents(
ctx, device, res.RoomIDs, *profile, userID, cfg, evTime, rsAPI,
ctx, res.RoomIDs, *profile, userID, evTime, rsAPI,
)
switch e := err.(type) {
case nil:
Expand Down Expand Up @@ -344,9 +344,8 @@ func getProfile(

func buildMembershipEvents(
ctx context.Context,
device *userapi.Device,
roomIDs []string,
newProfile authtypes.Profile, userID string, cfg *config.ClientAPI,
newProfile authtypes.Profile, userID string,
evTime time.Time, rsAPI api.ClientRoomserverAPI,
) ([]*types.HeaderedEvent, error) {
evs := []*types.HeaderedEvent{}
Expand Down Expand Up @@ -383,12 +382,17 @@ func buildMembershipEvents(
return nil, err
}

identity, err := cfg.Matrix.SigningIdentityFor(device.UserDomain())
user, err := spec.NewUserID(userID, true)
if err != nil {
return nil, err
}

event, err := eventutil.QueryAndBuildEvent(ctx, &proto, identity, evTime, rsAPI, nil)
identity, err := rsAPI.SigningIdentityFor(ctx, *validRoomID, *user)
if err != nil {
return nil, err
}

event, err := eventutil.QueryAndBuildEvent(ctx, &proto, &identity, evTime, rsAPI, nil)
if err != nil {
return nil, err
}
Expand Down
4 changes: 2 additions & 2 deletions clientapi/routing/redaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ func SendRedaction(
}
}

identity, err := cfg.Matrix.SigningIdentityFor(device.UserDomain())
identity, err := rsAPI.SigningIdentityFor(req.Context(), *validRoomID, *deviceUserID)
if err != nil {
return util.JSONResponse{
Code: http.StatusInternalServerError,
Expand All @@ -159,7 +159,7 @@ func SendRedaction(
}

var queryRes roomserverAPI.QueryLatestEventsAndStateResponse
e, err := eventutil.QueryAndBuildEvent(req.Context(), &proto, identity, time.Now(), rsAPI, &queryRes)
e, err := eventutil.QueryAndBuildEvent(req.Context(), &proto, &identity, time.Now(), rsAPI, &queryRes)
if errors.Is(err, eventutil.ErrRoomNoExists{}) {
return util.JSONResponse{
Code: http.StatusNotFound,
Expand Down
53 changes: 43 additions & 10 deletions clientapi/routing/sendevent.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,18 @@ import (
"sync"
"time"

"github.com/matrix-org/gomatrixserverlib"
"github.com/matrix-org/gomatrixserverlib/spec"
"github.com/matrix-org/util"
"github.com/prometheus/client_golang/prometheus"
"github.com/sirupsen/logrus"

"github.com/matrix-org/dendrite/clientapi/httputil"
"github.com/matrix-org/dendrite/internal/eventutil"
"github.com/matrix-org/dendrite/internal/transactions"
"github.com/matrix-org/dendrite/roomserver/api"
"github.com/matrix-org/dendrite/roomserver/types"
"github.com/matrix-org/dendrite/setup/config"
userapi "github.com/matrix-org/dendrite/userapi/api"
"github.com/matrix-org/gomatrixserverlib"
"github.com/matrix-org/gomatrixserverlib/spec"
"github.com/matrix-org/util"
"github.com/prometheus/client_golang/prometheus"
"github.com/sirupsen/logrus"
)

// http://matrix.org/docs/spec/client_server/r0.2.0.html#put-matrix-client-r0-rooms-roomid-send-eventtype-txnid
Expand Down Expand Up @@ -68,6 +67,8 @@ var sendEventDuration = prometheus.NewHistogramVec(
// /rooms/{roomID}/send/{eventType}
// /rooms/{roomID}/send/{eventType}/{txnID}
// /rooms/{roomID}/state/{eventType}/{stateKey}
//
// nolint: gocyclo
func SendEvent(
req *http.Request,
device *userapi.Device,
Expand Down Expand Up @@ -121,6 +122,17 @@ func SendEvent(
delete(r, "join_authorised_via_users_server")
}

// for power level events we need to replace the userID with the pseudoID
if roomVersion == gomatrixserverlib.RoomVersionPseudoIDs && eventType == spec.MRoomPowerLevels {
err = updatePowerLevels(req, r, roomID, rsAPI)
if err != nil {
return util.JSONResponse{
Code: http.StatusInternalServerError,
JSON: spec.InternalServerError{Err: err.Error()},
}
}
}

evTime, err := httputil.ParseTSParam(req)
if err != nil {
return util.JSONResponse{
Expand All @@ -129,7 +141,7 @@ func SendEvent(
}
}

e, resErr := generateSendEvent(req.Context(), r, device, roomID, eventType, stateKey, cfg, rsAPI, evTime)
e, resErr := generateSendEvent(req.Context(), r, device, roomID, eventType, stateKey, rsAPI, evTime)
if resErr != nil {
return *resErr
}
Expand Down Expand Up @@ -225,6 +237,28 @@ func SendEvent(
return res
}

func updatePowerLevels(req *http.Request, r map[string]interface{}, roomID string, rsAPI api.ClientRoomserverAPI) error {
userMap := r["users"].(map[string]interface{})
validRoomID, err := spec.NewRoomID(roomID)
if err != nil {
return err
}
for user, level := range userMap {
uID, err := spec.NewUserID(user, true)
if err != nil {
continue // we're modifying the map in place, so we're going to have invalid userIDs after the first iteration
}
senderID, err := rsAPI.QuerySenderIDForUser(req.Context(), *validRoomID, *uID)
if err != nil {
return err
}
userMap[string(senderID)] = level
delete(userMap, user)
}
r["users"] = userMap
return nil
}

// stateEqual compares the new and the existing state event content. If they are equal, returns a *util.JSONResponse
// with the existing event_id, making this an idempotent request.
func stateEqual(ctx context.Context, rsAPI api.ClientRoomserverAPI, eventType, stateKey, roomID string, newContent map[string]interface{}) *util.JSONResponse {
Expand Down Expand Up @@ -261,7 +295,6 @@ func generateSendEvent(
r map[string]interface{},
device *userapi.Device,
roomID, eventType string, stateKey *string,
cfg *config.ClientAPI,
rsAPI api.ClientRoomserverAPI,
evTime time.Time,
) (gomatrixserverlib.PDU, *util.JSONResponse) {
Expand Down Expand Up @@ -304,7 +337,7 @@ func generateSendEvent(
}
}

identity, err := cfg.Matrix.SigningIdentityFor(device.UserDomain())
identity, err := rsAPI.SigningIdentityFor(ctx, *validRoomID, *fullUserID)
if err != nil {
return nil, &util.JSONResponse{
Code: http.StatusInternalServerError,
Expand All @@ -313,7 +346,7 @@ func generateSendEvent(
}

var queryRes api.QueryLatestEventsAndStateResponse
e, err := eventutil.QueryAndBuildEvent(ctx, &proto, identity, evTime, rsAPI, &queryRes)
e, err := eventutil.QueryAndBuildEvent(ctx, &proto, &identity, evTime, rsAPI, &queryRes)
switch specificErr := err.(type) {
case nil:
case eventutil.ErrRoomNoExists:
Expand Down
4 changes: 2 additions & 2 deletions clientapi/routing/server_notices.go
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ func SendServerNotice(
"body": r.Content.Body,
"msgtype": r.Content.MsgType,
}
e, resErr := generateSendEvent(ctx, request, senderDevice, roomID, "m.room.message", nil, cfgClient, rsAPI, time.Now())
e, resErr := generateSendEvent(ctx, request, senderDevice, roomID, "m.room.message", nil, rsAPI, time.Now())
if resErr != nil {
logrus.Errorf("failed to send message: %+v", resErr)
return *resErr
Expand Down Expand Up @@ -350,7 +350,7 @@ func getSenderDevice(
if len(deviceRes.Devices) > 0 {
// If there were changes to the profile, create a new membership event
if displayNameChanged || avatarChanged {
_, err = updateProfile(ctx, rsAPI, &deviceRes.Devices[0], profile, accRes.Account.UserID, cfg, time.Now())
_, err = updateProfile(ctx, rsAPI, &deviceRes.Devices[0], profile, accRes.Account.UserID, time.Now())
if err != nil {
return nil, err
}
Expand Down
15 changes: 10 additions & 5 deletions federationapi/consumers/roomserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ func (s *OutputRoomEventConsumer) processMessage(ore api.OutputNewRoomEvent, rew
evs[i] = addsStateEvents[i].PDU
}

addsJoinedHosts, err := JoinedHostsFromEvents(evs)
addsJoinedHosts, err := JoinedHostsFromEvents(s.ctx, evs, s.rsAPI)
if err != nil {
return err
}
Expand Down Expand Up @@ -345,7 +345,7 @@ func (s *OutputRoomEventConsumer) joinedHostsAtEvent(
return nil, err
}

combinedAddsJoinedHosts, err := JoinedHostsFromEvents(combinedAddsEvents)
combinedAddsJoinedHosts, err := JoinedHostsFromEvents(s.ctx, combinedAddsEvents, s.rsAPI)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -394,7 +394,7 @@ func (s *OutputRoomEventConsumer) joinedHostsAtEvent(
// JoinedHostsFromEvents turns a list of state events into a list of joined hosts.
// This errors if one of the events was invalid.
// It should be impossible for an invalid event to get this far in the pipeline.
func JoinedHostsFromEvents(evs []gomatrixserverlib.PDU) ([]types.JoinedHost, error) {
func JoinedHostsFromEvents(ctx context.Context, evs []gomatrixserverlib.PDU, rsAPI api.FederationRoomserverAPI) ([]types.JoinedHost, error) {
var joinedHosts []types.JoinedHost
for _, ev := range evs {
if ev.Type() != "m.room.member" || ev.StateKey() == nil {
Expand All @@ -407,12 +407,17 @@ func JoinedHostsFromEvents(evs []gomatrixserverlib.PDU) ([]types.JoinedHost, err
if membership != spec.Join {
continue
}
_, serverName, err := gomatrixserverlib.SplitID('@', *ev.StateKey())
validRoomID, err := spec.NewRoomID(ev.RoomID())
if err != nil {
return nil, err
}
userID, err := rsAPI.QueryUserIDForSender(ctx, *validRoomID, spec.SenderID(*ev.StateKey()))
if err != nil {
return nil, err
}

joinedHosts = append(joinedHosts, types.JoinedHost{
MemberEventID: ev.EventID(), ServerName: serverName,
MemberEventID: ev.EventID(), ServerName: userID.Domain(),
})
}
return joinedHosts, nil
Expand Down
22 changes: 17 additions & 5 deletions federationapi/internal/perform.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package internal

import (
"context"
"crypto/ed25519"
"encoding/json"
"errors"
"fmt"
Expand Down Expand Up @@ -170,13 +171,24 @@ func (r *FederationInternalAPI) performJoinUsingServer(
UserIDQuerier: func(roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) {
return r.rsAPI.QueryUserIDForSender(ctx, roomID, senderID)
},
SenderIDCreator: func(ctx context.Context, userID spec.UserID, roomID spec.RoomID) (spec.SenderID, error) {
GetOrCreateSenderID: func(ctx context.Context, userID spec.UserID, roomID spec.RoomID, roomVersion string) (spec.SenderID, ed25519.PrivateKey, error) {
// assign a roomNID, otherwise we can't create a private key for the user
_, nidErr := r.rsAPI.AssignRoomNID(ctx, roomID, gomatrixserverlib.RoomVersion(roomVersion))
if nidErr != nil {
return "", nil, nidErr
}
key, keyErr := r.rsAPI.GetOrCreateUserRoomPrivateKey(ctx, userID, roomID)
if keyErr != nil {
return "", keyErr
return "", nil, keyErr
}

return spec.SenderID(spec.Base64Bytes(key).Encode()), nil
return spec.SenderIDFromPseudoIDKey(key), key, nil
},
StoreSenderIDFromPublicID: func(ctx context.Context, senderID spec.SenderID, userIDRaw string, roomID spec.RoomID) error {
storeUserID, userErr := spec.NewUserID(userIDRaw, true)
if userErr != nil {
return userErr
}
return r.rsAPI.StoreUserRoomPublicKey(ctx, senderID, *storeUserID, roomID)
},
}
response, joinErr := gomatrixserverlib.PerformJoin(ctx, r, joinInput)
Expand All @@ -200,7 +212,7 @@ func (r *FederationInternalAPI) performJoinUsingServer(
// joining a room, waiting for 200 OK then changing device keys and have those keys not be sent
// to other servers (this was a cause of a flakey sytest "Local device key changes get to remote servers")
// The events are trusted now as we performed auth checks above.
joinedHosts, err := consumers.JoinedHostsFromEvents(response.StateSnapshot.GetStateEvents().TrustedEvents(response.JoinEvent.Version(), false))
joinedHosts, err := consumers.JoinedHostsFromEvents(ctx, response.StateSnapshot.GetStateEvents().TrustedEvents(response.JoinEvent.Version(), false), r.rsAPI)
if err != nil {
return fmt.Errorf("JoinedHostsFromEvents: failed to get joined hosts: %s", err)
}
Expand Down
12 changes: 12 additions & 0 deletions federationapi/routing/join.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package routing

import (
"context"
"fmt"
"net/http"
"sort"
Expand Down Expand Up @@ -107,6 +108,10 @@ func MakeJoin(
}
}

if senderID == "" {
senderID = spec.SenderID(userID.String())
}

input := gomatrixserverlib.HandleMakeJoinInput{
Context: httpReq.Context(),
UserID: userID,
Expand Down Expand Up @@ -218,6 +223,13 @@ func SendJoin(
UserIDQuerier: func(roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) {
return rsAPI.QueryUserIDForSender(httpReq.Context(), roomID, senderID)
},
StoreSenderIDFromPublicID: func(ctx context.Context, senderID spec.SenderID, userIDRaw string, roomID spec.RoomID) error {
userID, userErr := spec.NewUserID(userIDRaw, true)
if userErr != nil {
return userErr
}
return rsAPI.StoreUserRoomPublicKey(ctx, senderID, *userID, roomID)
},
}
response, joinErr := gomatrixserverlib.HandleSendJoin(input)
switch e := joinErr.(type) {
Expand Down
Loading

0 comments on commit 23cd787

Please sign in to comment.