mirror of
https://github.com/hoernschen/dendrite.git
synced 2024-12-27 07:28:27 +00:00
Add MXIDMapping
for pseudoID rooms (#3112)
Add `MXIDMapping` on membership events when creating/joining rooms.
This commit is contained in:
parent
4722f12fab
commit
23cd7877a1
41 changed files with 593 additions and 177 deletions
|
@ -22,10 +22,6 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/getsentry/sentry-go"
|
"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"
|
appserviceAPI "github.com/matrix-org/dendrite/appservice/api"
|
||||||
"github.com/matrix-org/dendrite/clientapi/auth/authtypes"
|
"github.com/matrix-org/dendrite/clientapi/auth/authtypes"
|
||||||
"github.com/matrix-org/dendrite/clientapi/httputil"
|
"github.com/matrix-org/dendrite/clientapi/httputil"
|
||||||
|
@ -36,6 +32,9 @@ import (
|
||||||
"github.com/matrix-org/dendrite/roomserver/types"
|
"github.com/matrix-org/dendrite/roomserver/types"
|
||||||
"github.com/matrix-org/dendrite/setup/config"
|
"github.com/matrix-org/dendrite/setup/config"
|
||||||
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/fclient"
|
||||||
|
"github.com/matrix-org/gomatrixserverlib/spec"
|
||||||
|
|
||||||
"github.com/matrix-org/util"
|
"github.com/matrix-org/util"
|
||||||
)
|
)
|
||||||
|
@ -433,11 +432,6 @@ func buildMembershipEvent(
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
identity, err := cfg.Matrix.SigningIdentityFor(device.UserDomain())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
userID, err := spec.NewUserID(device.UserID, true)
|
userID, err := spec.NewUserID(device.UserID, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -459,6 +453,12 @@ func buildMembershipEvent(
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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,
|
return buildMembershipEventDirect(ctx, targetSenderID, reason, profile.DisplayName, profile.AvatarURL,
|
||||||
senderID, device.UserDomain(), membership, roomID, isDirect, identity.KeyID, identity.PrivateKey, evTime, rsAPI)
|
senderID, device.UserDomain(), membership, roomID, isDirect, identity.KeyID, identity.PrivateKey, evTime, rsAPI)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
if err != nil {
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
if err != nil {
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
@ -248,7 +248,7 @@ func SetDisplayName(
|
||||||
func updateProfile(
|
func updateProfile(
|
||||||
ctx context.Context, rsAPI api.ClientRoomserverAPI, device *userapi.Device,
|
ctx context.Context, rsAPI api.ClientRoomserverAPI, device *userapi.Device,
|
||||||
profile *authtypes.Profile,
|
profile *authtypes.Profile,
|
||||||
userID string, cfg *config.ClientAPI, evTime time.Time,
|
userID string, evTime time.Time,
|
||||||
) (util.JSONResponse, error) {
|
) (util.JSONResponse, error) {
|
||||||
var res api.QueryRoomsForUserResponse
|
var res api.QueryRoomsForUserResponse
|
||||||
err := rsAPI.QueryRoomsForUser(ctx, &api.QueryRoomsForUserRequest{
|
err := rsAPI.QueryRoomsForUser(ctx, &api.QueryRoomsForUserRequest{
|
||||||
|
@ -273,7 +273,7 @@ func updateProfile(
|
||||||
}
|
}
|
||||||
|
|
||||||
events, err := buildMembershipEvents(
|
events, err := buildMembershipEvents(
|
||||||
ctx, device, res.RoomIDs, *profile, userID, cfg, evTime, rsAPI,
|
ctx, res.RoomIDs, *profile, userID, evTime, rsAPI,
|
||||||
)
|
)
|
||||||
switch e := err.(type) {
|
switch e := err.(type) {
|
||||||
case nil:
|
case nil:
|
||||||
|
@ -344,9 +344,8 @@ func getProfile(
|
||||||
|
|
||||||
func buildMembershipEvents(
|
func buildMembershipEvents(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
device *userapi.Device,
|
|
||||||
roomIDs []string,
|
roomIDs []string,
|
||||||
newProfile authtypes.Profile, userID string, cfg *config.ClientAPI,
|
newProfile authtypes.Profile, userID string,
|
||||||
evTime time.Time, rsAPI api.ClientRoomserverAPI,
|
evTime time.Time, rsAPI api.ClientRoomserverAPI,
|
||||||
) ([]*types.HeaderedEvent, error) {
|
) ([]*types.HeaderedEvent, error) {
|
||||||
evs := []*types.HeaderedEvent{}
|
evs := []*types.HeaderedEvent{}
|
||||||
|
@ -383,12 +382,17 @@ func buildMembershipEvents(
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
identity, err := cfg.Matrix.SigningIdentityFor(device.UserDomain())
|
user, err := spec.NewUserID(userID, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -150,7 +150,7 @@ func SendRedaction(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
identity, err := cfg.Matrix.SigningIdentityFor(device.UserDomain())
|
identity, err := rsAPI.SigningIdentityFor(req.Context(), *validRoomID, *deviceUserID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusInternalServerError,
|
Code: http.StatusInternalServerError,
|
||||||
|
@ -159,7 +159,7 @@ func SendRedaction(
|
||||||
}
|
}
|
||||||
|
|
||||||
var queryRes roomserverAPI.QueryLatestEventsAndStateResponse
|
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{}) {
|
if errors.Is(err, eventutil.ErrRoomNoExists{}) {
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusNotFound,
|
Code: http.StatusNotFound,
|
||||||
|
|
|
@ -23,12 +23,6 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"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/clientapi/httputil"
|
||||||
"github.com/matrix-org/dendrite/internal/eventutil"
|
"github.com/matrix-org/dendrite/internal/eventutil"
|
||||||
"github.com/matrix-org/dendrite/internal/transactions"
|
"github.com/matrix-org/dendrite/internal/transactions"
|
||||||
|
@ -36,6 +30,11 @@ import (
|
||||||
"github.com/matrix-org/dendrite/roomserver/types"
|
"github.com/matrix-org/dendrite/roomserver/types"
|
||||||
"github.com/matrix-org/dendrite/setup/config"
|
"github.com/matrix-org/dendrite/setup/config"
|
||||||
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/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
|
// http://matrix.org/docs/spec/client_server/r0.2.0.html#put-matrix-client-r0-rooms-roomid-send-eventtype-txnid
|
||||||
|
@ -68,6 +67,8 @@ var sendEventDuration = prometheus.NewHistogramVec(
|
||||||
// /rooms/{roomID}/send/{eventType}
|
// /rooms/{roomID}/send/{eventType}
|
||||||
// /rooms/{roomID}/send/{eventType}/{txnID}
|
// /rooms/{roomID}/send/{eventType}/{txnID}
|
||||||
// /rooms/{roomID}/state/{eventType}/{stateKey}
|
// /rooms/{roomID}/state/{eventType}/{stateKey}
|
||||||
|
//
|
||||||
|
// nolint: gocyclo
|
||||||
func SendEvent(
|
func SendEvent(
|
||||||
req *http.Request,
|
req *http.Request,
|
||||||
device *userapi.Device,
|
device *userapi.Device,
|
||||||
|
@ -121,6 +122,17 @@ func SendEvent(
|
||||||
delete(r, "join_authorised_via_users_server")
|
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)
|
evTime, err := httputil.ParseTSParam(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
|
@ -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 {
|
if resErr != nil {
|
||||||
return *resErr
|
return *resErr
|
||||||
}
|
}
|
||||||
|
@ -225,6 +237,28 @@ func SendEvent(
|
||||||
return res
|
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
|
// 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.
|
// 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 {
|
func stateEqual(ctx context.Context, rsAPI api.ClientRoomserverAPI, eventType, stateKey, roomID string, newContent map[string]interface{}) *util.JSONResponse {
|
||||||
|
@ -261,7 +295,6 @@ func generateSendEvent(
|
||||||
r map[string]interface{},
|
r map[string]interface{},
|
||||||
device *userapi.Device,
|
device *userapi.Device,
|
||||||
roomID, eventType string, stateKey *string,
|
roomID, eventType string, stateKey *string,
|
||||||
cfg *config.ClientAPI,
|
|
||||||
rsAPI api.ClientRoomserverAPI,
|
rsAPI api.ClientRoomserverAPI,
|
||||||
evTime time.Time,
|
evTime time.Time,
|
||||||
) (gomatrixserverlib.PDU, *util.JSONResponse) {
|
) (gomatrixserverlib.PDU, *util.JSONResponse) {
|
||||||
|
@ -304,7 +337,7 @@ func generateSendEvent(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
identity, err := cfg.Matrix.SigningIdentityFor(device.UserDomain())
|
identity, err := rsAPI.SigningIdentityFor(ctx, *validRoomID, *fullUserID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, &util.JSONResponse{
|
return nil, &util.JSONResponse{
|
||||||
Code: http.StatusInternalServerError,
|
Code: http.StatusInternalServerError,
|
||||||
|
@ -313,7 +346,7 @@ func generateSendEvent(
|
||||||
}
|
}
|
||||||
|
|
||||||
var queryRes api.QueryLatestEventsAndStateResponse
|
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) {
|
switch specificErr := err.(type) {
|
||||||
case nil:
|
case nil:
|
||||||
case eventutil.ErrRoomNoExists:
|
case eventutil.ErrRoomNoExists:
|
||||||
|
|
|
@ -221,7 +221,7 @@ func SendServerNotice(
|
||||||
"body": r.Content.Body,
|
"body": r.Content.Body,
|
||||||
"msgtype": r.Content.MsgType,
|
"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 {
|
if resErr != nil {
|
||||||
logrus.Errorf("failed to send message: %+v", resErr)
|
logrus.Errorf("failed to send message: %+v", resErr)
|
||||||
return *resErr
|
return *resErr
|
||||||
|
@ -350,7 +350,7 @@ func getSenderDevice(
|
||||||
if len(deviceRes.Devices) > 0 {
|
if len(deviceRes.Devices) > 0 {
|
||||||
// If there were changes to the profile, create a new membership event
|
// If there were changes to the profile, create a new membership event
|
||||||
if displayNameChanged || avatarChanged {
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -192,7 +192,7 @@ func (s *OutputRoomEventConsumer) processMessage(ore api.OutputNewRoomEvent, rew
|
||||||
evs[i] = addsStateEvents[i].PDU
|
evs[i] = addsStateEvents[i].PDU
|
||||||
}
|
}
|
||||||
|
|
||||||
addsJoinedHosts, err := JoinedHostsFromEvents(evs)
|
addsJoinedHosts, err := JoinedHostsFromEvents(s.ctx, evs, s.rsAPI)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -345,7 +345,7 @@ func (s *OutputRoomEventConsumer) joinedHostsAtEvent(
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
combinedAddsJoinedHosts, err := JoinedHostsFromEvents(combinedAddsEvents)
|
combinedAddsJoinedHosts, err := JoinedHostsFromEvents(s.ctx, combinedAddsEvents, s.rsAPI)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -394,7 +394,7 @@ func (s *OutputRoomEventConsumer) joinedHostsAtEvent(
|
||||||
// JoinedHostsFromEvents turns a list of state events into a list of joined hosts.
|
// JoinedHostsFromEvents turns a list of state events into a list of joined hosts.
|
||||||
// This errors if one of the events was invalid.
|
// This errors if one of the events was invalid.
|
||||||
// It should be impossible for an invalid event to get this far in the pipeline.
|
// 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
|
var joinedHosts []types.JoinedHost
|
||||||
for _, ev := range evs {
|
for _, ev := range evs {
|
||||||
if ev.Type() != "m.room.member" || ev.StateKey() == nil {
|
if ev.Type() != "m.room.member" || ev.StateKey() == nil {
|
||||||
|
@ -407,12 +407,17 @@ func JoinedHostsFromEvents(evs []gomatrixserverlib.PDU) ([]types.JoinedHost, err
|
||||||
if membership != spec.Join {
|
if membership != spec.Join {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
_, serverName, err := gomatrixserverlib.SplitID('@', *ev.StateKey())
|
validRoomID, err := spec.NewRoomID(ev.RoomID())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
userID, err := rsAPI.QueryUserIDForSender(ctx, *validRoomID, spec.SenderID(*ev.StateKey()))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
joinedHosts = append(joinedHosts, types.JoinedHost{
|
joinedHosts = append(joinedHosts, types.JoinedHost{
|
||||||
MemberEventID: ev.EventID(), ServerName: serverName,
|
MemberEventID: ev.EventID(), ServerName: userID.Domain(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return joinedHosts, nil
|
return joinedHosts, nil
|
||||||
|
|
|
@ -2,6 +2,7 @@ package internal
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"crypto/ed25519"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
@ -170,13 +171,24 @@ func (r *FederationInternalAPI) performJoinUsingServer(
|
||||||
UserIDQuerier: func(roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) {
|
UserIDQuerier: func(roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) {
|
||||||
return r.rsAPI.QueryUserIDForSender(ctx, roomID, senderID)
|
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)
|
key, keyErr := r.rsAPI.GetOrCreateUserRoomPrivateKey(ctx, userID, roomID)
|
||||||
if keyErr != nil {
|
if keyErr != nil {
|
||||||
return "", keyErr
|
return "", nil, keyErr
|
||||||
}
|
}
|
||||||
|
return spec.SenderIDFromPseudoIDKey(key), key, nil
|
||||||
return spec.SenderID(spec.Base64Bytes(key).Encode()), 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)
|
response, joinErr := gomatrixserverlib.PerformJoin(ctx, r, joinInput)
|
||||||
|
@ -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
|
// 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")
|
// 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.
|
// 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 {
|
if err != nil {
|
||||||
return fmt.Errorf("JoinedHostsFromEvents: failed to get joined hosts: %s", err)
|
return fmt.Errorf("JoinedHostsFromEvents: failed to get joined hosts: %s", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
package routing
|
package routing
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"sort"
|
"sort"
|
||||||
|
@ -107,6 +108,10 @@ func MakeJoin(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if senderID == "" {
|
||||||
|
senderID = spec.SenderID(userID.String())
|
||||||
|
}
|
||||||
|
|
||||||
input := gomatrixserverlib.HandleMakeJoinInput{
|
input := gomatrixserverlib.HandleMakeJoinInput{
|
||||||
Context: httpReq.Context(),
|
Context: httpReq.Context(),
|
||||||
UserID: userID,
|
UserID: userID,
|
||||||
|
@ -218,6 +223,13 @@ func SendJoin(
|
||||||
UserIDQuerier: func(roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) {
|
UserIDQuerier: func(roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) {
|
||||||
return rsAPI.QueryUserIDForSender(httpReq.Context(), roomID, senderID)
|
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)
|
response, joinErr := gomatrixserverlib.HandleSendJoin(input)
|
||||||
switch e := joinErr.(type) {
|
switch e := joinErr.(type) {
|
||||||
|
|
4
go.mod
4
go.mod
|
@ -22,7 +22,7 @@ require (
|
||||||
github.com/matrix-org/dugong v0.0.0-20210921133753-66e6b1c67e2e
|
github.com/matrix-org/dugong v0.0.0-20210921133753-66e6b1c67e2e
|
||||||
github.com/matrix-org/go-sqlite3-js v0.0.0-20220419092513-28aa791a1c91
|
github.com/matrix-org/go-sqlite3-js v0.0.0-20220419092513-28aa791a1c91
|
||||||
github.com/matrix-org/gomatrix v0.0.0-20220926102614-ceba4d9f7530
|
github.com/matrix-org/gomatrix v0.0.0-20220926102614-ceba4d9f7530
|
||||||
github.com/matrix-org/gomatrixserverlib v0.0.0-20230614140620-4dea2171c8f1
|
github.com/matrix-org/gomatrixserverlib v0.0.0-20230628151943-f6e3c7f7b093
|
||||||
github.com/matrix-org/pinecone v0.11.1-0.20230210171230-8c3b24f2649a
|
github.com/matrix-org/pinecone v0.11.1-0.20230210171230-8c3b24f2649a
|
||||||
github.com/matrix-org/util v0.0.0-20221111132719-399730281e66
|
github.com/matrix-org/util v0.0.0-20221111132719-399730281e66
|
||||||
github.com/mattn/go-sqlite3 v1.14.16
|
github.com/mattn/go-sqlite3 v1.14.16
|
||||||
|
@ -43,6 +43,7 @@ require (
|
||||||
github.com/yggdrasil-network/yggdrasil-go v0.4.6
|
github.com/yggdrasil-network/yggdrasil-go v0.4.6
|
||||||
go.uber.org/atomic v1.10.0
|
go.uber.org/atomic v1.10.0
|
||||||
golang.org/x/crypto v0.10.0
|
golang.org/x/crypto v0.10.0
|
||||||
|
golang.org/x/exp v0.0.0-20221205204356-47842c84f3db
|
||||||
golang.org/x/image v0.5.0
|
golang.org/x/image v0.5.0
|
||||||
golang.org/x/mobile v0.0.0-20221020085226-b36e6246172e
|
golang.org/x/mobile v0.0.0-20221020085226-b36e6246172e
|
||||||
golang.org/x/sync v0.1.0
|
golang.org/x/sync v0.1.0
|
||||||
|
@ -124,7 +125,6 @@ require (
|
||||||
github.com/tidwall/match v1.1.1 // indirect
|
github.com/tidwall/match v1.1.1 // indirect
|
||||||
github.com/tidwall/pretty v1.2.1 // indirect
|
github.com/tidwall/pretty v1.2.1 // indirect
|
||||||
go.etcd.io/bbolt v1.3.6 // indirect
|
go.etcd.io/bbolt v1.3.6 // indirect
|
||||||
golang.org/x/exp v0.0.0-20221205204356-47842c84f3db // indirect
|
|
||||||
golang.org/x/mod v0.8.0 // indirect
|
golang.org/x/mod v0.8.0 // indirect
|
||||||
golang.org/x/net v0.10.0 // indirect
|
golang.org/x/net v0.10.0 // indirect
|
||||||
golang.org/x/sys v0.9.0 // indirect
|
golang.org/x/sys v0.9.0 // indirect
|
||||||
|
|
4
go.sum
4
go.sum
|
@ -323,8 +323,8 @@ github.com/matrix-org/go-sqlite3-js v0.0.0-20220419092513-28aa791a1c91 h1:s7fexw
|
||||||
github.com/matrix-org/go-sqlite3-js v0.0.0-20220419092513-28aa791a1c91/go.mod h1:e+cg2q7C7yE5QnAXgzo512tgFh1RbQLC0+jozuegKgo=
|
github.com/matrix-org/go-sqlite3-js v0.0.0-20220419092513-28aa791a1c91/go.mod h1:e+cg2q7C7yE5QnAXgzo512tgFh1RbQLC0+jozuegKgo=
|
||||||
github.com/matrix-org/gomatrix v0.0.0-20220926102614-ceba4d9f7530 h1:kHKxCOLcHH8r4Fzarl4+Y3K5hjothkVW5z7T1dUM11U=
|
github.com/matrix-org/gomatrix v0.0.0-20220926102614-ceba4d9f7530 h1:kHKxCOLcHH8r4Fzarl4+Y3K5hjothkVW5z7T1dUM11U=
|
||||||
github.com/matrix-org/gomatrix v0.0.0-20220926102614-ceba4d9f7530/go.mod h1:/gBX06Kw0exX1HrwmoBibFA98yBk/jxKpGVeyQbff+s=
|
github.com/matrix-org/gomatrix v0.0.0-20220926102614-ceba4d9f7530/go.mod h1:/gBX06Kw0exX1HrwmoBibFA98yBk/jxKpGVeyQbff+s=
|
||||||
github.com/matrix-org/gomatrixserverlib v0.0.0-20230614140620-4dea2171c8f1 h1:k75Fy0iQVbDjvddip/x898+BdyopBNAfL1BMNx0awA0=
|
github.com/matrix-org/gomatrixserverlib v0.0.0-20230628151943-f6e3c7f7b093 h1:FHd3SYhU2ZxZhkssZ/7ms5+M2j+g94lYp8ztvA1E6tA=
|
||||||
github.com/matrix-org/gomatrixserverlib v0.0.0-20230614140620-4dea2171c8f1/go.mod h1:H9V9N3Uqn1bBJqYJNGK1noqtgJTaCEhtTdcH/mp50uU=
|
github.com/matrix-org/gomatrixserverlib v0.0.0-20230628151943-f6e3c7f7b093/go.mod h1:H9V9N3Uqn1bBJqYJNGK1noqtgJTaCEhtTdcH/mp50uU=
|
||||||
github.com/matrix-org/pinecone v0.11.1-0.20230210171230-8c3b24f2649a h1:awrPDf9LEFySxTLKYBMCiObelNx/cBuv/wzllvCCH3A=
|
github.com/matrix-org/pinecone v0.11.1-0.20230210171230-8c3b24f2649a h1:awrPDf9LEFySxTLKYBMCiObelNx/cBuv/wzllvCCH3A=
|
||||||
github.com/matrix-org/pinecone v0.11.1-0.20230210171230-8c3b24f2649a/go.mod h1:HchJX9oKMXaT2xYFs0Ha/6Zs06mxLU8k6F1ODnrGkeQ=
|
github.com/matrix-org/pinecone v0.11.1-0.20230210171230-8c3b24f2649a/go.mod h1:HchJX9oKMXaT2xYFs0Ha/6Zs06mxLU8k6F1ODnrGkeQ=
|
||||||
github.com/matrix-org/util v0.0.0-20221111132719-399730281e66 h1:6z4KxomXSIGWqhHcfzExgkH3Z3UkIXry4ibJS4Aqz2Y=
|
github.com/matrix-org/util v0.0.0-20221111132719-399730281e66 h1:6z4KxomXSIGWqhHcfzExgkH3Z3UkIXry4ibJS4Aqz2Y=
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"crypto/ed25519"
|
"crypto/ed25519"
|
||||||
|
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
"github.com/matrix-org/gomatrixserverlib/fclient"
|
||||||
"github.com/matrix-org/gomatrixserverlib/spec"
|
"github.com/matrix-org/gomatrixserverlib/spec"
|
||||||
"github.com/matrix-org/util"
|
"github.com/matrix-org/util"
|
||||||
|
|
||||||
|
@ -73,6 +74,7 @@ type RoomserverInternalAPI interface {
|
||||||
type UserRoomPrivateKeyCreator interface {
|
type UserRoomPrivateKeyCreator interface {
|
||||||
// GetOrCreateUserRoomPrivateKey gets the user room key for the specified user. If no key exists yet, a new one is created.
|
// GetOrCreateUserRoomPrivateKey gets the user room key for the specified user. If no key exists yet, a new one is created.
|
||||||
GetOrCreateUserRoomPrivateKey(ctx context.Context, userID spec.UserID, roomID spec.RoomID) (ed25519.PrivateKey, error)
|
GetOrCreateUserRoomPrivateKey(ctx context.Context, userID spec.UserID, roomID spec.RoomID) (ed25519.PrivateKey, error)
|
||||||
|
StoreUserRoomPublicKey(ctx context.Context, senderID spec.SenderID, userID spec.UserID, roomID spec.RoomID) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type InputRoomEventsAPI interface {
|
type InputRoomEventsAPI interface {
|
||||||
|
@ -184,6 +186,7 @@ type ClientRoomserverAPI interface {
|
||||||
QueryBulkStateContentAPI
|
QueryBulkStateContentAPI
|
||||||
QueryEventsAPI
|
QueryEventsAPI
|
||||||
QuerySenderIDAPI
|
QuerySenderIDAPI
|
||||||
|
UserRoomPrivateKeyCreator
|
||||||
QueryMembershipForUser(ctx context.Context, req *QueryMembershipForUserRequest, res *QueryMembershipForUserResponse) error
|
QueryMembershipForUser(ctx context.Context, req *QueryMembershipForUserRequest, res *QueryMembershipForUserResponse) error
|
||||||
QueryMembershipsForRoom(ctx context.Context, req *QueryMembershipsForRoomRequest, res *QueryMembershipsForRoomResponse) error
|
QueryMembershipsForRoom(ctx context.Context, req *QueryMembershipsForRoomRequest, res *QueryMembershipsForRoomResponse) error
|
||||||
QueryRoomsForUser(ctx context.Context, req *QueryRoomsForUserRequest, res *QueryRoomsForUserResponse) error
|
QueryRoomsForUser(ctx context.Context, req *QueryRoomsForUserRequest, res *QueryRoomsForUserResponse) error
|
||||||
|
@ -213,6 +216,7 @@ type ClientRoomserverAPI interface {
|
||||||
PerformForget(ctx context.Context, req *PerformForgetRequest, resp *PerformForgetResponse) error
|
PerformForget(ctx context.Context, req *PerformForgetRequest, resp *PerformForgetResponse) error
|
||||||
SetRoomAlias(ctx context.Context, req *SetRoomAliasRequest, res *SetRoomAliasResponse) error
|
SetRoomAlias(ctx context.Context, req *SetRoomAliasRequest, res *SetRoomAliasResponse) error
|
||||||
RemoveRoomAlias(ctx context.Context, req *RemoveRoomAliasRequest, res *RemoveRoomAliasResponse) error
|
RemoveRoomAlias(ctx context.Context, req *RemoveRoomAliasRequest, res *RemoveRoomAliasResponse) error
|
||||||
|
SigningIdentityFor(ctx context.Context, roomID spec.RoomID, senderID spec.UserID) (fclient.SigningIdentity, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type UserRoomserverAPI interface {
|
type UserRoomserverAPI interface {
|
||||||
|
@ -232,7 +236,8 @@ type FederationRoomserverAPI interface {
|
||||||
QueryBulkStateContentAPI
|
QueryBulkStateContentAPI
|
||||||
QuerySenderIDAPI
|
QuerySenderIDAPI
|
||||||
UserRoomPrivateKeyCreator
|
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 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
|
||||||
QueryMembershipForUser(ctx context.Context, req *QueryMembershipForUserRequest, res *QueryMembershipForUserResponse) error
|
QueryMembershipForUser(ctx context.Context, req *QueryMembershipForUserRequest, res *QueryMembershipForUserResponse) error
|
||||||
|
|
|
@ -174,6 +174,8 @@ type QueryServerJoinedToRoomResponse struct {
|
||||||
RoomExists bool `json:"room_exists"`
|
RoomExists bool `json:"room_exists"`
|
||||||
// True if we still believe that the server is participating in the room
|
// True if we still believe that the server is participating in the room
|
||||||
IsInRoom bool `json:"is_in_room"`
|
IsInRoom bool `json:"is_in_room"`
|
||||||
|
// The roomversion if joined to room
|
||||||
|
RoomVersion gomatrixserverlib.RoomVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueryServerAllowedToSeeEventRequest is a request to QueryServerAllowedToSeeEvent
|
// QueryServerAllowedToSeeEventRequest is a request to QueryServerAllowedToSeeEvent
|
||||||
|
|
|
@ -115,6 +115,7 @@ func (r *RoomserverInternalAPI) GetAliasesForRoomID(
|
||||||
|
|
||||||
// nolint:gocyclo
|
// nolint:gocyclo
|
||||||
// RemoveRoomAlias implements alias.RoomserverInternalAPI
|
// RemoveRoomAlias implements alias.RoomserverInternalAPI
|
||||||
|
// nolint: gocyclo
|
||||||
func (r *RoomserverInternalAPI) RemoveRoomAlias(
|
func (r *RoomserverInternalAPI) RemoveRoomAlias(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
request *api.RemoveRoomAliasRequest,
|
request *api.RemoveRoomAliasRequest,
|
||||||
|
@ -188,9 +189,11 @@ func (r *RoomserverInternalAPI) RemoveRoomAlias(
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
senderDomain := sender.Domain()
|
validRoomID, err := spec.NewRoomID(roomID)
|
||||||
|
if err != nil {
|
||||||
identity, err := r.Cfg.Global.SigningIdentityFor(senderDomain)
|
return err
|
||||||
|
}
|
||||||
|
identity, err := r.SigningIdentityFor(ctx, *validRoomID, *sender)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -216,7 +219,7 @@ func (r *RoomserverInternalAPI) RemoveRoomAlias(
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
newEvent, err := eventutil.BuildEvent(ctx, proto, identity, time.Now(), &eventsNeeded, stateRes)
|
newEvent, err := eventutil.BuildEvent(ctx, proto, &identity, time.Now(), &eventsNeeded, stateRes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
|
|
||||||
"github.com/getsentry/sentry-go"
|
"github.com/getsentry/sentry-go"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
"github.com/matrix-org/gomatrixserverlib/fclient"
|
||||||
"github.com/matrix-org/gomatrixserverlib/spec"
|
"github.com/matrix-org/gomatrixserverlib/spec"
|
||||||
"github.com/matrix-org/util"
|
"github.com/matrix-org/util"
|
||||||
"github.com/nats-io/nats.go"
|
"github.com/nats-io/nats.go"
|
||||||
|
@ -110,11 +111,6 @@ func (r *RoomserverInternalAPI) SetFederationAPI(fsAPI fsAPI.RoomserverFederatio
|
||||||
r.fsAPI = fsAPI
|
r.fsAPI = fsAPI
|
||||||
r.KeyRing = keyRing
|
r.KeyRing = keyRing
|
||||||
|
|
||||||
identity, err := r.Cfg.Global.SigningIdentityFor(r.ServerName)
|
|
||||||
if err != nil {
|
|
||||||
logrus.Panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
r.Inputer = &input.Inputer{
|
r.Inputer = &input.Inputer{
|
||||||
Cfg: &r.Cfg.RoomServer,
|
Cfg: &r.Cfg.RoomServer,
|
||||||
ProcessContext: r.ProcessContext,
|
ProcessContext: r.ProcessContext,
|
||||||
|
@ -125,7 +121,7 @@ func (r *RoomserverInternalAPI) SetFederationAPI(fsAPI fsAPI.RoomserverFederatio
|
||||||
NATSClient: r.NATSClient,
|
NATSClient: r.NATSClient,
|
||||||
Durable: nats.Durable(r.Durable),
|
Durable: nats.Durable(r.Durable),
|
||||||
ServerName: r.ServerName,
|
ServerName: r.ServerName,
|
||||||
SigningIdentity: identity,
|
SigningIdentity: r.SigningIdentityFor,
|
||||||
FSAPI: fsAPI,
|
FSAPI: fsAPI,
|
||||||
KeyRing: keyRing,
|
KeyRing: keyRing,
|
||||||
ACLs: r.ServerACLs,
|
ACLs: r.ServerACLs,
|
||||||
|
@ -292,3 +288,45 @@ func (r *RoomserverInternalAPI) GetOrCreateUserRoomPrivateKey(ctx context.Contex
|
||||||
}
|
}
|
||||||
return key, nil
|
return key, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *RoomserverInternalAPI) StoreUserRoomPublicKey(ctx context.Context, senderID spec.SenderID, userID spec.UserID, roomID spec.RoomID) error {
|
||||||
|
pubKeyBytes, err := senderID.RawBytes()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = r.DB.InsertUserRoomPublicKey(ctx, userID, roomID, ed25519.PublicKey(pubKeyBytes))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RoomserverInternalAPI) SigningIdentityFor(ctx context.Context, roomID spec.RoomID, senderID spec.UserID) (fclient.SigningIdentity, error) {
|
||||||
|
roomVersion, ok := r.Cache.GetRoomVersion(roomID.String())
|
||||||
|
if !ok {
|
||||||
|
roomInfo, err := r.DB.RoomInfo(ctx, roomID.String())
|
||||||
|
if err != nil {
|
||||||
|
return fclient.SigningIdentity{}, err
|
||||||
|
}
|
||||||
|
if roomInfo != nil {
|
||||||
|
roomVersion = roomInfo.RoomVersion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if roomVersion == gomatrixserverlib.RoomVersionPseudoIDs {
|
||||||
|
privKey, err := r.GetOrCreateUserRoomPrivateKey(ctx, senderID, roomID)
|
||||||
|
if err != nil {
|
||||||
|
return fclient.SigningIdentity{}, err
|
||||||
|
}
|
||||||
|
return fclient.SigningIdentity{
|
||||||
|
PrivateKey: privKey,
|
||||||
|
KeyID: "ed25519:1",
|
||||||
|
ServerName: "self",
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
identity, err := r.Cfg.Global.SigningIdentityFor(senderID.Domain())
|
||||||
|
if err != nil {
|
||||||
|
return fclient.SigningIdentity{}, err
|
||||||
|
}
|
||||||
|
return *identity, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RoomserverInternalAPI) AssignRoomNID(ctx context.Context, roomID spec.RoomID, roomVersion gomatrixserverlib.RoomVersion) (roomNID types.RoomNID, err error) {
|
||||||
|
return r.DB.AssignRoomNID(ctx, roomID, roomVersion)
|
||||||
|
}
|
||||||
|
|
|
@ -81,7 +81,7 @@ type Inputer struct {
|
||||||
JetStream nats.JetStreamContext
|
JetStream nats.JetStreamContext
|
||||||
Durable nats.SubOpt
|
Durable nats.SubOpt
|
||||||
ServerName spec.ServerName
|
ServerName spec.ServerName
|
||||||
SigningIdentity *fclient.SigningIdentity
|
SigningIdentity func(ctx context.Context, roomID spec.RoomID, senderID spec.UserID) (fclient.SigningIdentity, error)
|
||||||
FSAPI fedapi.RoomserverFederationAPI
|
FSAPI fedapi.RoomserverFederationAPI
|
||||||
KeyRing gomatrixserverlib.JSONVerifier
|
KeyRing gomatrixserverlib.JSONVerifier
|
||||||
ACLs *acls.ServerACLs
|
ACLs *acls.ServerACLs
|
||||||
|
|
|
@ -406,7 +406,7 @@ func (r *Inputer) processRoomEvent(
|
||||||
)
|
)
|
||||||
if !isRejected && !isCreateEvent {
|
if !isRejected && !isCreateEvent {
|
||||||
resolver := state.NewStateResolution(r.DB, roomInfo, r.Queryer)
|
resolver := state.NewStateResolution(r.DB, roomInfo, r.Queryer)
|
||||||
redactionEvent, redactedEvent, err = r.DB.MaybeRedactEvent(ctx, roomInfo, eventNID, event, &resolver)
|
redactionEvent, redactedEvent, err = r.DB.MaybeRedactEvent(ctx, roomInfo, eventNID, event, &resolver, r.Queryer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -895,7 +895,22 @@ func (r *Inputer) kickGuests(ctx context.Context, event gomatrixserverlib.PDU, r
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
event, err := eventutil.BuildEvent(ctx, fledglingEvent, r.SigningIdentity, time.Now(), &eventsNeeded, latestRes)
|
validRoomID, err := spec.NewRoomID(event.RoomID())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
userID, err := spec.NewUserID(stateKey, true)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
signingIdentity, err := r.SigningIdentity(ctx, *validRoomID, *userID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
event, err := eventutil.BuildEvent(ctx, fledglingEvent, &signingIdentity, time.Now(), &eventsNeeded, latestRes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -647,7 +647,7 @@ func persistEvents(ctx context.Context, db storage.Database, querier api.QuerySe
|
||||||
|
|
||||||
resolver := state.NewStateResolution(db, roomInfo, querier)
|
resolver := state.NewStateResolution(db, roomInfo, querier)
|
||||||
|
|
||||||
_, redactedEvent, err := db.MaybeRedactEvent(ctx, roomInfo, eventNID, ev, &resolver)
|
_, redactedEvent, err := db.MaybeRedactEvent(ctx, roomInfo, eventNID, ev, &resolver, querier)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.WithError(err).WithField("event_id", ev.EventID()).Error("Failed to redact event")
|
logrus.WithError(err).WithField("event_id", ev.EventID()).Error("Failed to redact event")
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -31,6 +31,7 @@ import (
|
||||||
"github.com/matrix-org/gomatrixserverlib/fclient"
|
"github.com/matrix-org/gomatrixserverlib/fclient"
|
||||||
"github.com/matrix-org/gomatrixserverlib/spec"
|
"github.com/matrix-org/gomatrixserverlib/spec"
|
||||||
"github.com/matrix-org/util"
|
"github.com/matrix-org/util"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -64,6 +65,16 @@ func (c *Creator) PerformCreateRoom(ctx context.Context, userID spec.UserID, roo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_, err = c.DB.AssignRoomNID(ctx, roomID, createRequest.RoomVersion)
|
||||||
|
if err != nil {
|
||||||
|
util.GetLogger(ctx).WithError(err).Error("failed to assign roomNID")
|
||||||
|
return "", &util.JSONResponse{
|
||||||
|
Code: http.StatusInternalServerError,
|
||||||
|
JSON: spec.InternalServerError{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var senderID spec.SenderID
|
var senderID spec.SenderID
|
||||||
if createRequest.RoomVersion == gomatrixserverlib.RoomVersionPseudoIDs {
|
if createRequest.RoomVersion == gomatrixserverlib.RoomVersionPseudoIDs {
|
||||||
// create user room key if needed
|
// create user room key if needed
|
||||||
|
@ -75,7 +86,7 @@ func (c *Creator) PerformCreateRoom(ctx context.Context, userID spec.UserID, roo
|
||||||
JSON: spec.InternalServerError{},
|
JSON: spec.InternalServerError{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
senderID = spec.SenderID(spec.Base64Bytes(key.Public().(ed25519.PublicKey)).Encode())
|
senderID = spec.SenderIDFromPseudoIDKey(key)
|
||||||
} else {
|
} else {
|
||||||
senderID = spec.SenderID(userID.String())
|
senderID = spec.SenderID(userID.String())
|
||||||
}
|
}
|
||||||
|
@ -138,13 +149,59 @@ func (c *Creator) PerformCreateRoom(ctx context.Context, userID spec.UserID, roo
|
||||||
membershipEvent := gomatrixserverlib.FledglingEvent{
|
membershipEvent := gomatrixserverlib.FledglingEvent{
|
||||||
Type: spec.MRoomMember,
|
Type: spec.MRoomMember,
|
||||||
StateKey: string(senderID),
|
StateKey: string(senderID),
|
||||||
Content: gomatrixserverlib.MemberContent{
|
|
||||||
Membership: spec.Join,
|
|
||||||
DisplayName: createRequest.UserDisplayName,
|
|
||||||
AvatarURL: createRequest.UserAvatarURL,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
memberContent := gomatrixserverlib.MemberContent{
|
||||||
|
Membership: spec.Join,
|
||||||
|
DisplayName: createRequest.UserDisplayName,
|
||||||
|
AvatarURL: createRequest.UserAvatarURL,
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the signing identity
|
||||||
|
identity, err := c.Cfg.Matrix.SigningIdentityFor(userID.Domain()) // we MUST use the server signing mxid_mapping
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithError(err).WithField("domain", userID.Domain()).Error("unable to find signing identity for domain")
|
||||||
|
return "", &util.JSONResponse{
|
||||||
|
Code: http.StatusInternalServerError,
|
||||||
|
JSON: spec.InternalServerError{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we are creating a room with pseudo IDs, create and sign the MXIDMapping
|
||||||
|
if createRequest.RoomVersion == gomatrixserverlib.RoomVersionPseudoIDs {
|
||||||
|
var pseudoIDKey ed25519.PrivateKey
|
||||||
|
pseudoIDKey, err = c.RSAPI.GetOrCreateUserRoomPrivateKey(ctx, userID, roomID)
|
||||||
|
if err != nil {
|
||||||
|
util.GetLogger(ctx).WithError(err).Error("GetOrCreateUserRoomPrivateKey failed")
|
||||||
|
return "", &util.JSONResponse{
|
||||||
|
Code: http.StatusInternalServerError,
|
||||||
|
JSON: spec.InternalServerError{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mapping := &gomatrixserverlib.MXIDMapping{
|
||||||
|
UserRoomKey: spec.SenderIDFromPseudoIDKey(pseudoIDKey),
|
||||||
|
UserID: userID.String(),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sign the mapping with the server identity
|
||||||
|
if err = mapping.Sign(identity.ServerName, identity.KeyID, identity.PrivateKey); err != nil {
|
||||||
|
return "", &util.JSONResponse{
|
||||||
|
Code: http.StatusInternalServerError,
|
||||||
|
JSON: spec.InternalServerError{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
memberContent.MXIDMapping = mapping
|
||||||
|
|
||||||
|
// sign all events with the pseudo ID key
|
||||||
|
identity = &fclient.SigningIdentity{
|
||||||
|
ServerName: "self",
|
||||||
|
KeyID: "ed25519:1",
|
||||||
|
PrivateKey: pseudoIDKey,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
membershipEvent.Content = memberContent
|
||||||
|
|
||||||
var nameEvent *gomatrixserverlib.FledglingEvent
|
var nameEvent *gomatrixserverlib.FledglingEvent
|
||||||
var topicEvent *gomatrixserverlib.FledglingEvent
|
var topicEvent *gomatrixserverlib.FledglingEvent
|
||||||
var guestAccessEvent *gomatrixserverlib.FledglingEvent
|
var guestAccessEvent *gomatrixserverlib.FledglingEvent
|
||||||
|
@ -322,7 +379,7 @@ func (c *Creator) PerformCreateRoom(ctx context.Context, userID spec.UserID, roo
|
||||||
JSON: spec.InternalServerError{},
|
JSON: spec.InternalServerError{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ev, err = builder.Build(createRequest.EventTime, userID.Domain(), createRequest.KeyID, createRequest.PrivateKey)
|
ev, err = builder.Build(createRequest.EventTime, identity.ServerName, identity.KeyID, identity.PrivateKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
util.GetLogger(ctx).WithError(err).Error("buildEvent failed")
|
util.GetLogger(ctx).WithError(err).Error("buildEvent failed")
|
||||||
return "", &util.JSONResponse{
|
return "", &util.JSONResponse{
|
||||||
|
@ -363,17 +420,8 @@ func (c *Creator) PerformCreateRoom(ctx context.Context, userID spec.UserID, roo
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// first send the `m.room.create` event, so we have a roomNID
|
// send the events to the roomserver
|
||||||
if err = api.SendInputRoomEvents(ctx, c.RSAPI, userID.Domain(), inputs[:1], false); err != nil {
|
if err = api.SendInputRoomEvents(ctx, c.RSAPI, userID.Domain(), inputs, false); err != nil {
|
||||||
util.GetLogger(ctx).WithError(err).Error("roomserverAPI.SendInputRoomEvents failed")
|
|
||||||
return "", &util.JSONResponse{
|
|
||||||
Code: http.StatusInternalServerError,
|
|
||||||
JSON: spec.InternalServerError{},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// send the remaining events
|
|
||||||
if err = api.SendInputRoomEvents(ctx, c.RSAPI, userID.Domain(), inputs[1:], false); err != nil {
|
|
||||||
util.GetLogger(ctx).WithError(err).Error("roomserverAPI.SendInputRoomEvents failed")
|
util.GetLogger(ctx).WithError(err).Error("roomserverAPI.SendInputRoomEvents failed")
|
||||||
return "", &util.JSONResponse{
|
return "", &util.JSONResponse{
|
||||||
Code: http.StatusInternalServerError,
|
Code: http.StatusInternalServerError,
|
||||||
|
@ -483,11 +531,6 @@ func (c *Creator) PerformCreateRoom(ctx context.Context, userID spec.UserID, roo
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build the invite event.
|
// Build the invite event.
|
||||||
identity := &fclient.SigningIdentity{
|
|
||||||
ServerName: userID.Domain(),
|
|
||||||
KeyID: createRequest.KeyID,
|
|
||||||
PrivateKey: createRequest.PrivateKey,
|
|
||||||
}
|
|
||||||
inviteEvent, err = eventutil.QueryAndBuildEvent(ctx, &proto, identity, createRequest.EventTime, c.RSAPI, nil)
|
inviteEvent, err = eventutil.QueryAndBuildEvent(ctx, &proto, identity, createRequest.EventTime, c.RSAPI, nil)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -153,6 +153,23 @@ func (r *Inviter) PerformInvite(
|
||||||
}
|
}
|
||||||
isTargetLocal := r.Cfg.Matrix.IsLocalServerName(invitedUser.Domain())
|
isTargetLocal := r.Cfg.Matrix.IsLocalServerName(invitedUser.Domain())
|
||||||
|
|
||||||
|
// If we're inviting a local user, we can generate the needed pseudoID key here. (if needed)
|
||||||
|
if isTargetLocal {
|
||||||
|
var roomVersion gomatrixserverlib.RoomVersion
|
||||||
|
roomVersion, err = r.DB.GetRoomVersion(ctx, event.RoomID())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch roomVersion {
|
||||||
|
case gomatrixserverlib.RoomVersionPseudoIDs:
|
||||||
|
_, err = r.RSAPI.GetOrCreateUserRoomPrivateKey(ctx, *invitedUser, *validRoomID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
invitedSenderID, err := r.RSAPI.QuerySenderIDForUser(ctx, *validRoomID, *invitedUser)
|
invitedSenderID, err := r.RSAPI.QuerySenderIDForUser(ctx, *validRoomID, *invitedUser)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed looking up senderID for invited user")
|
return fmt.Errorf("failed looking up senderID for invited user")
|
||||||
|
|
|
@ -16,6 +16,7 @@ package perform
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"crypto/ed25519"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
@ -24,6 +25,7 @@ import (
|
||||||
|
|
||||||
"github.com/getsentry/sentry-go"
|
"github.com/getsentry/sentry-go"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
"github.com/matrix-org/gomatrixserverlib/fclient"
|
||||||
"github.com/matrix-org/gomatrixserverlib/spec"
|
"github.com/matrix-org/gomatrixserverlib/spec"
|
||||||
"github.com/matrix-org/util"
|
"github.com/matrix-org/util"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
@ -202,14 +204,15 @@ func (r *Joiner) performJoinRoomByID(
|
||||||
senderID, err = r.Queryer.QuerySenderIDForUser(ctx, *roomID, *userID)
|
senderID, err = r.Queryer.QuerySenderIDForUser(ctx, *roomID, *userID)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
checkInvitePending = true
|
checkInvitePending = true
|
||||||
} else {
|
}
|
||||||
|
if senderID == "" {
|
||||||
// create user room key if needed
|
// create user room key if needed
|
||||||
key, keyErr := r.RSAPI.GetOrCreateUserRoomPrivateKey(ctx, *userID, *roomID)
|
key, keyErr := r.RSAPI.GetOrCreateUserRoomPrivateKey(ctx, *userID, *roomID)
|
||||||
if keyErr != nil {
|
if keyErr != nil {
|
||||||
util.GetLogger(ctx).WithError(keyErr).Error("GetOrCreateUserRoomPrivateKey failed")
|
util.GetLogger(ctx).WithError(keyErr).Error("GetOrCreateUserRoomPrivateKey failed")
|
||||||
return "", "", fmt.Errorf("GetOrCreateUserRoomPrivateKey failed: %w", keyErr)
|
return "", "", fmt.Errorf("GetOrCreateUserRoomPrivateKey failed: %w", keyErr)
|
||||||
}
|
}
|
||||||
senderID = spec.SenderID(spec.Base64Bytes(key).Encode())
|
senderID = spec.SenderIDFromPseudoIDKey(key)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
checkInvitePending = true
|
checkInvitePending = true
|
||||||
|
@ -283,11 +286,39 @@ func (r *Joiner) performJoinRoomByID(
|
||||||
// but everyone has since left. I suspect it does the wrong thing.
|
// but everyone has since left. I suspect it does the wrong thing.
|
||||||
|
|
||||||
var buildRes rsAPI.QueryLatestEventsAndStateResponse
|
var buildRes rsAPI.QueryLatestEventsAndStateResponse
|
||||||
identity, err := r.Cfg.Matrix.SigningIdentityFor(userDomain)
|
identity, err := r.RSAPI.SigningIdentityFor(ctx, *roomID, *userID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", "", fmt.Errorf("error joining local room: %q", err)
|
return "", "", fmt.Errorf("error joining local room: %q", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// at this point we know we have an existing room
|
||||||
|
if inRoomRes.RoomVersion == gomatrixserverlib.RoomVersionPseudoIDs {
|
||||||
|
var pseudoIDKey ed25519.PrivateKey
|
||||||
|
pseudoIDKey, err = r.RSAPI.GetOrCreateUserRoomPrivateKey(ctx, *userID, *roomID)
|
||||||
|
if err != nil {
|
||||||
|
util.GetLogger(ctx).WithError(err).Error("GetOrCreateUserRoomPrivateKey failed")
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
mapping := &gomatrixserverlib.MXIDMapping{
|
||||||
|
UserRoomKey: spec.SenderIDFromPseudoIDKey(pseudoIDKey),
|
||||||
|
UserID: userID.String(),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sign the mapping with the server identity
|
||||||
|
if err = mapping.Sign(identity.ServerName, identity.KeyID, identity.PrivateKey); err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
req.Content["mxid_mapping"] = mapping
|
||||||
|
|
||||||
|
// sign the event with the pseudo ID key
|
||||||
|
identity = fclient.SigningIdentity{
|
||||||
|
ServerName: "self",
|
||||||
|
KeyID: "ed25519:1",
|
||||||
|
PrivateKey: pseudoIDKey,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
senderIDString := string(senderID)
|
senderIDString := string(senderID)
|
||||||
|
|
||||||
// Prepare the template for the join event.
|
// Prepare the template for the join event.
|
||||||
|
@ -317,7 +348,7 @@ func (r *Joiner) performJoinRoomByID(
|
||||||
if err = proto.SetContent(req.Content); err != nil {
|
if err = proto.SetContent(req.Content); err != nil {
|
||||||
return "", "", fmt.Errorf("eb.SetContent: %w", err)
|
return "", "", fmt.Errorf("eb.SetContent: %w", err)
|
||||||
}
|
}
|
||||||
event, err := eventutil.QueryAndBuildEvent(ctx, &proto, identity, time.Now(), r.RSAPI, &buildRes)
|
event, err := eventutil.QueryAndBuildEvent(ctx, &proto, &identity, time.Now(), r.RSAPI, &buildRes)
|
||||||
|
|
||||||
switch err.(type) {
|
switch err.(type) {
|
||||||
case nil:
|
case nil:
|
||||||
|
|
|
@ -177,12 +177,17 @@ func (r *Leaver) performLeaveRoomByID(
|
||||||
// TODO: Check what happens if the room exists on the server
|
// TODO: Check what happens if the room exists on the server
|
||||||
// but everyone has since left. I suspect it does the wrong thing.
|
// but everyone has since left. I suspect it does the wrong thing.
|
||||||
|
|
||||||
|
validRoomID, err := spec.NewRoomID(req.RoomID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
var buildRes rsAPI.QueryLatestEventsAndStateResponse
|
var buildRes rsAPI.QueryLatestEventsAndStateResponse
|
||||||
identity, err := r.Cfg.Matrix.SigningIdentityFor(req.Leaver.Domain())
|
identity, err := r.RSAPI.SigningIdentityFor(ctx, *validRoomID, req.Leaver)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("SigningIdentityFor: %w", err)
|
return nil, fmt.Errorf("SigningIdentityFor: %w", err)
|
||||||
}
|
}
|
||||||
event, err := eventutil.QueryAndBuildEvent(ctx, &proto, identity, time.Now(), r.RSAPI, &buildRes)
|
event, err := eventutil.QueryAndBuildEvent(ctx, &proto, &identity, time.Now(), r.RSAPI, &buildRes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("eventutil.QueryAndBuildEvent: %w", err)
|
return nil, fmt.Errorf("eventutil.QueryAndBuildEvent: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -478,6 +478,9 @@ func (r *Queryer) QueryServerJoinedToRoom(
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("r.DB.RoomInfo: %w", err)
|
return fmt.Errorf("r.DB.RoomInfo: %w", err)
|
||||||
}
|
}
|
||||||
|
if info != nil {
|
||||||
|
response.RoomVersion = info.RoomVersion
|
||||||
|
}
|
||||||
if info == nil || info.IsStub() {
|
if info == nil || info.IsStub() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,6 +35,14 @@ import (
|
||||||
"github.com/matrix-org/dendrite/test/testrig"
|
"github.com/matrix-org/dendrite/test/testrig"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type FakeQuerier struct {
|
||||||
|
api.QuerySenderIDAPI
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FakeQuerier) QueryUserIDForSender(ctx context.Context, roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) {
|
||||||
|
return spec.NewUserID(string(senderID), true)
|
||||||
|
}
|
||||||
|
|
||||||
func TestUsers(t *testing.T) {
|
func TestUsers(t *testing.T) {
|
||||||
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
|
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
|
||||||
cfg, processCtx, close := testrig.CreateConfig(t, dbType)
|
cfg, processCtx, close := testrig.CreateConfig(t, dbType)
|
||||||
|
@ -566,7 +574,7 @@ func TestRedaction(t *testing.T) {
|
||||||
err = updater.Commit()
|
err = updater.Commit()
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
_, redactedEvent, err := db.MaybeRedactEvent(ctx, roomInfo, eventNID, ev.PDU, &plResolver)
|
_, redactedEvent, err := db.MaybeRedactEvent(ctx, roomInfo, eventNID, ev.PDU, &plResolver, &FakeQuerier{})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
if redactedEvent != nil {
|
if redactedEvent != nil {
|
||||||
assert.Equal(t, ev.Redacts(), redactedEvent.EventID())
|
assert.Equal(t, ev.Redacts(), redactedEvent.EventID())
|
||||||
|
|
|
@ -18,6 +18,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/ed25519"
|
"crypto/ed25519"
|
||||||
|
|
||||||
|
"github.com/matrix-org/dendrite/roomserver/api"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
"github.com/matrix-org/gomatrixserverlib/spec"
|
"github.com/matrix-org/gomatrixserverlib/spec"
|
||||||
|
|
||||||
|
@ -190,7 +191,7 @@ type Database interface {
|
||||||
GetOrCreateEventTypeNID(ctx context.Context, eventType string) (eventTypeNID types.EventTypeNID, err error)
|
GetOrCreateEventTypeNID(ctx context.Context, eventType string) (eventTypeNID types.EventTypeNID, err error)
|
||||||
GetOrCreateEventStateKeyNID(ctx context.Context, eventStateKey *string) (types.EventStateKeyNID, error)
|
GetOrCreateEventStateKeyNID(ctx context.Context, eventStateKey *string) (types.EventStateKeyNID, error)
|
||||||
MaybeRedactEvent(
|
MaybeRedactEvent(
|
||||||
ctx context.Context, roomInfo *types.RoomInfo, eventNID types.EventNID, event gomatrixserverlib.PDU, plResolver state.PowerLevelResolver,
|
ctx context.Context, roomInfo *types.RoomInfo, eventNID types.EventNID, event gomatrixserverlib.PDU, plResolver state.PowerLevelResolver, querier api.QuerySenderIDAPI,
|
||||||
) (gomatrixserverlib.PDU, gomatrixserverlib.PDU, error)
|
) (gomatrixserverlib.PDU, gomatrixserverlib.PDU, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -251,7 +252,7 @@ type EventDatabase interface {
|
||||||
// MaybeRedactEvent returns the redaction event and the redacted event if this call resulted in a redaction, else an error
|
// MaybeRedactEvent returns the redaction event and the redacted event if this call resulted in a redaction, else an error
|
||||||
// (nil if there was nothing to do)
|
// (nil if there was nothing to do)
|
||||||
MaybeRedactEvent(
|
MaybeRedactEvent(
|
||||||
ctx context.Context, roomInfo *types.RoomInfo, eventNID types.EventNID, event gomatrixserverlib.PDU, plResolver state.PowerLevelResolver,
|
ctx context.Context, roomInfo *types.RoomInfo, eventNID types.EventNID, event gomatrixserverlib.PDU, plResolver state.PowerLevelResolver, querier api.QuerySenderIDAPI,
|
||||||
) (gomatrixserverlib.PDU, gomatrixserverlib.PDU, error)
|
) (gomatrixserverlib.PDU, gomatrixserverlib.PDU, error)
|
||||||
StoreEvent(ctx context.Context, event gomatrixserverlib.PDU, roomInfo *types.RoomInfo, eventTypeNID types.EventTypeNID, eventStateKeyNID types.EventStateKeyNID, authEventNIDs []types.EventNID, isRejected bool) (types.EventNID, types.StateAtEvent, error)
|
StoreEvent(ctx context.Context, event gomatrixserverlib.PDU, roomInfo *types.RoomInfo, eventTypeNID types.EventTypeNID, eventStateKeyNID types.EventStateKeyNID, authEventNIDs []types.EventNID, isRejected bool) (types.EventNID, types.StateAtEvent, error)
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
"github.com/matrix-org/dendrite/internal/eventutil"
|
"github.com/matrix-org/dendrite/internal/eventutil"
|
||||||
|
"github.com/matrix-org/dendrite/roomserver/api"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
"github.com/matrix-org/gomatrixserverlib/spec"
|
"github.com/matrix-org/gomatrixserverlib/spec"
|
||||||
"github.com/matrix-org/util"
|
"github.com/matrix-org/util"
|
||||||
|
@ -991,6 +992,7 @@ func extractRoomVersionFromCreateEvent(event gomatrixserverlib.PDU) (
|
||||||
// Returns the redaction event and the redacted event if this call resulted in a redaction.
|
// Returns the redaction event and the redacted event if this call resulted in a redaction.
|
||||||
func (d *EventDatabase) MaybeRedactEvent(
|
func (d *EventDatabase) MaybeRedactEvent(
|
||||||
ctx context.Context, roomInfo *types.RoomInfo, eventNID types.EventNID, event gomatrixserverlib.PDU, plResolver state.PowerLevelResolver,
|
ctx context.Context, roomInfo *types.RoomInfo, eventNID types.EventNID, event gomatrixserverlib.PDU, plResolver state.PowerLevelResolver,
|
||||||
|
querier api.QuerySenderIDAPI,
|
||||||
) (gomatrixserverlib.PDU, gomatrixserverlib.PDU, error) {
|
) (gomatrixserverlib.PDU, gomatrixserverlib.PDU, error) {
|
||||||
var (
|
var (
|
||||||
redactionEvent, redactedEvent *types.Event
|
redactionEvent, redactedEvent *types.Event
|
||||||
|
@ -1030,15 +1032,18 @@ func (d *EventDatabase) MaybeRedactEvent(
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Don't hack senderID into userID here (pseudoIDs)
|
var validRoomID *spec.RoomID
|
||||||
|
validRoomID, err = spec.NewRoomID(redactedEvent.RoomID())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
sender1Domain := ""
|
sender1Domain := ""
|
||||||
sender1, err1 := spec.NewUserID(string(redactedEvent.SenderID()), true)
|
sender1, err1 := querier.QueryUserIDForSender(ctx, *validRoomID, redactedEvent.SenderID())
|
||||||
if err1 == nil {
|
if err1 == nil {
|
||||||
sender1Domain = string(sender1.Domain())
|
sender1Domain = string(sender1.Domain())
|
||||||
}
|
}
|
||||||
// TODO: Don't hack senderID into userID here (pseudoIDs)
|
|
||||||
sender2Domain := ""
|
sender2Domain := ""
|
||||||
sender2, err2 := spec.NewUserID(string(redactionEvent.SenderID()), true)
|
sender2, err2 := querier.QueryUserIDForSender(ctx, *validRoomID, redactionEvent.SenderID())
|
||||||
if err2 == nil {
|
if err2 == nil {
|
||||||
sender2Domain = string(sender2.Domain())
|
sender2Domain = string(sender2.Domain())
|
||||||
}
|
}
|
||||||
|
@ -1698,6 +1703,7 @@ func (d *Database) InsertUserRoomPublicKey(ctx context.Context, userID spec.User
|
||||||
// SelectUserRoomPrivateKey queries the users room private key.
|
// SelectUserRoomPrivateKey queries the users room private key.
|
||||||
// If no key exists, returns no key and no error. Otherwise returns
|
// If no key exists, returns no key and no error. Otherwise returns
|
||||||
// the key and a database error, if any.
|
// the key and a database error, if any.
|
||||||
|
// TODO: Cache this?
|
||||||
func (d *Database) SelectUserRoomPrivateKey(ctx context.Context, userID spec.UserID, roomID spec.RoomID) (key ed25519.PrivateKey, err error) {
|
func (d *Database) SelectUserRoomPrivateKey(ctx context.Context, userID spec.UserID, roomID spec.RoomID) (key ed25519.PrivateKey, err error) {
|
||||||
uID := userID.String()
|
uID := userID.String()
|
||||||
stateKeyNIDMap, sErr := d.eventStateKeyNIDs(ctx, nil, []string{uID})
|
stateKeyNIDMap, sErr := d.eventStateKeyNIDs(ctx, nil, []string{uID})
|
||||||
|
@ -1756,58 +1762,54 @@ func (d *Database) SelectUserRoomPublicKey(ctx context.Context, userID spec.User
|
||||||
// SelectUserIDsForPublicKeys returns a map from roomID -> map from senderKey -> userID
|
// SelectUserIDsForPublicKeys returns a map from roomID -> map from senderKey -> userID
|
||||||
func (d *Database) SelectUserIDsForPublicKeys(ctx context.Context, publicKeys map[spec.RoomID][]ed25519.PublicKey) (result map[spec.RoomID]map[string]string, err error) {
|
func (d *Database) SelectUserIDsForPublicKeys(ctx context.Context, publicKeys map[spec.RoomID][]ed25519.PublicKey) (result map[spec.RoomID]map[string]string, err error) {
|
||||||
result = make(map[spec.RoomID]map[string]string, len(publicKeys))
|
result = make(map[spec.RoomID]map[string]string, len(publicKeys))
|
||||||
err = d.Writer.Do(d.DB, nil, func(txn *sql.Tx) error {
|
|
||||||
|
|
||||||
// map all roomIDs to roomNIDs
|
// map all roomIDs to roomNIDs
|
||||||
query := make(map[types.RoomNID][]ed25519.PublicKey)
|
query := make(map[types.RoomNID][]ed25519.PublicKey)
|
||||||
rooms := make(map[types.RoomNID]spec.RoomID)
|
rooms := make(map[types.RoomNID]spec.RoomID)
|
||||||
for roomID, keys := range publicKeys {
|
for roomID, keys := range publicKeys {
|
||||||
roomNID, ok := d.Cache.GetRoomServerRoomNID(roomID.String())
|
roomNID, ok := d.Cache.GetRoomServerRoomNID(roomID.String())
|
||||||
if !ok {
|
if !ok {
|
||||||
roomInfo, rErr := d.roomInfo(ctx, txn, roomID.String())
|
roomInfo, rErr := d.roomInfo(ctx, nil, roomID.String())
|
||||||
if rErr != nil {
|
if rErr != nil {
|
||||||
return rErr
|
return nil, rErr
|
||||||
}
|
|
||||||
if roomInfo == nil {
|
|
||||||
logrus.Warnf("missing room info for %s, there will be missing users in the response", roomID.String())
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
roomNID = roomInfo.RoomNID
|
|
||||||
}
|
}
|
||||||
|
if roomInfo == nil {
|
||||||
query[roomNID] = keys
|
logrus.Warnf("missing room info for %s, there will be missing users in the response", roomID.String())
|
||||||
rooms[roomNID] = roomID
|
continue
|
||||||
}
|
|
||||||
|
|
||||||
// get the user room key pars
|
|
||||||
userRoomKeyPairMap, sErr := d.UserRoomKeyTable.BulkSelectUserNIDs(ctx, txn, query)
|
|
||||||
if sErr != nil {
|
|
||||||
return sErr
|
|
||||||
}
|
|
||||||
nids := make([]types.EventStateKeyNID, 0, len(userRoomKeyPairMap))
|
|
||||||
for _, nid := range userRoomKeyPairMap {
|
|
||||||
nids = append(nids, nid.EventStateKeyNID)
|
|
||||||
}
|
|
||||||
// get the userIDs
|
|
||||||
nidMap, seErr := d.EventStateKeys(ctx, nids)
|
|
||||||
if seErr != nil {
|
|
||||||
return seErr
|
|
||||||
}
|
|
||||||
|
|
||||||
// build the result map (roomID -> map publicKey -> userID)
|
|
||||||
for publicKey, userRoomKeyPair := range userRoomKeyPairMap {
|
|
||||||
userID := nidMap[userRoomKeyPair.EventStateKeyNID]
|
|
||||||
roomID := rooms[userRoomKeyPair.RoomNID]
|
|
||||||
resMap, exists := result[roomID]
|
|
||||||
if !exists {
|
|
||||||
resMap = map[string]string{}
|
|
||||||
}
|
}
|
||||||
resMap[publicKey] = userID
|
roomNID = roomInfo.RoomNID
|
||||||
result[roomID] = resMap
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
query[roomNID] = keys
|
||||||
})
|
rooms[roomNID] = roomID
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the user room key pars
|
||||||
|
userRoomKeyPairMap, sErr := d.UserRoomKeyTable.BulkSelectUserNIDs(ctx, nil, query)
|
||||||
|
if sErr != nil {
|
||||||
|
return nil, sErr
|
||||||
|
}
|
||||||
|
nids := make([]types.EventStateKeyNID, 0, len(userRoomKeyPairMap))
|
||||||
|
for _, nid := range userRoomKeyPairMap {
|
||||||
|
nids = append(nids, nid.EventStateKeyNID)
|
||||||
|
}
|
||||||
|
// get the userIDs
|
||||||
|
nidMap, seErr := d.EventStateKeys(ctx, nids)
|
||||||
|
if seErr != nil {
|
||||||
|
return nil, seErr
|
||||||
|
}
|
||||||
|
|
||||||
|
// build the result map (roomID -> map publicKey -> userID)
|
||||||
|
for publicKey, userRoomKeyPair := range userRoomKeyPairMap {
|
||||||
|
userID := nidMap[userRoomKeyPair.EventStateKeyNID]
|
||||||
|
roomID := rooms[userRoomKeyPair.RoomNID]
|
||||||
|
resMap, exists := result[roomID]
|
||||||
|
if !exists {
|
||||||
|
resMap = map[string]string{}
|
||||||
|
}
|
||||||
|
resMap[publicKey] = userID
|
||||||
|
result[roomID] = resMap
|
||||||
|
}
|
||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -57,6 +57,7 @@ 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 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)`
|
||||||
|
|
||||||
type userRoomKeysStatements struct {
|
type userRoomKeysStatements struct {
|
||||||
|
db *sql.DB
|
||||||
insertUserRoomPrivateKeyStmt *sql.Stmt
|
insertUserRoomPrivateKeyStmt *sql.Stmt
|
||||||
insertUserRoomPublicKeyStmt *sql.Stmt
|
insertUserRoomPublicKeyStmt *sql.Stmt
|
||||||
selectUserRoomKeyStmt *sql.Stmt
|
selectUserRoomKeyStmt *sql.Stmt
|
||||||
|
@ -70,7 +71,7 @@ func CreateUserRoomKeysTable(db *sql.DB) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func PrepareUserRoomKeysTable(db *sql.DB) (tables.UserRoomKeys, error) {
|
func PrepareUserRoomKeysTable(db *sql.DB) (tables.UserRoomKeys, error) {
|
||||||
s := &userRoomKeysStatements{}
|
s := &userRoomKeysStatements{db: db}
|
||||||
return s, sqlutil.StatementList{
|
return s, sqlutil.StatementList{
|
||||||
{&s.insertUserRoomPrivateKeyStmt, insertUserRoomKeySQL},
|
{&s.insertUserRoomPrivateKeyStmt, insertUserRoomKeySQL},
|
||||||
{&s.insertUserRoomPublicKeyStmt, insertUserRoomPublicKeySQL},
|
{&s.insertUserRoomPublicKeyStmt, insertUserRoomPublicKeySQL},
|
||||||
|
@ -137,7 +138,7 @@ func (s *userRoomKeysStatements) BulkSelectUserNIDs(ctx context.Context, txn *sq
|
||||||
selectSQL := strings.Replace(selectUserNIDsSQL, "($2)", sqlutil.QueryVariadicOffset(len(senders), len(senderKeys)), 1)
|
selectSQL := strings.Replace(selectUserNIDsSQL, "($2)", sqlutil.QueryVariadicOffset(len(senders), len(senderKeys)), 1)
|
||||||
selectSQL = strings.Replace(selectSQL, "($1)", sqlutil.QueryVariadic(len(senderKeys)), 1) // replace $1 with the roomNIDs
|
selectSQL = strings.Replace(selectSQL, "($1)", sqlutil.QueryVariadic(len(senderKeys)), 1) // replace $1 with the roomNIDs
|
||||||
|
|
||||||
selectStmt, err := txn.Prepare(selectSQL)
|
selectStmt, err := s.db.Prepare(selectSQL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ import (
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
"github.com/matrix-org/gomatrixserverlib/spec"
|
||||||
)
|
)
|
||||||
|
|
||||||
// HeaderedEvent is an Event which serialises to the headered form, which includes
|
// HeaderedEvent is an Event which serialises to the headered form, which includes
|
||||||
|
@ -25,6 +26,10 @@ import (
|
||||||
type HeaderedEvent struct {
|
type HeaderedEvent struct {
|
||||||
gomatrixserverlib.PDU
|
gomatrixserverlib.PDU
|
||||||
Visibility gomatrixserverlib.HistoryVisibility
|
Visibility gomatrixserverlib.HistoryVisibility
|
||||||
|
// TODO: Remove this. This is a temporary workaround to store the userID in the syncAPI.
|
||||||
|
// It really should be the userKey instead.
|
||||||
|
UserID spec.UserID
|
||||||
|
StateKeyResolved *string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HeaderedEvent) CacheCost() int {
|
func (h *HeaderedEvent) CacheCost() int {
|
||||||
|
|
|
@ -256,16 +256,19 @@ func (s *OutputRoomEventConsumer) onNewRoomEvent(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pduPos, err := s.db.WriteEvent(
|
validRoomID, err := spec.NewRoomID(ev.RoomID())
|
||||||
ctx,
|
if err != nil {
|
||||||
ev,
|
return err
|
||||||
addsStateEvents,
|
}
|
||||||
msg.AddsStateEventIDs,
|
|
||||||
msg.RemovesStateEventIDs,
|
userID, err := s.rsAPI.QueryUserIDForSender(ctx, *validRoomID, ev.SenderID())
|
||||||
msg.TransactionID,
|
if err != nil {
|
||||||
false,
|
return err
|
||||||
msg.HistoryVisibility,
|
}
|
||||||
)
|
|
||||||
|
ev.UserID = *userID
|
||||||
|
|
||||||
|
pduPos, err := s.db.WriteEvent(ctx, ev, addsStateEvents, msg.AddsStateEventIDs, msg.RemovesStateEventIDs, msg.TransactionID, false, msg.HistoryVisibility)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// panic rather than continue with an inconsistent database
|
// panic rather than continue with an inconsistent database
|
||||||
log.WithFields(log.Fields{
|
log.WithFields(log.Fields{
|
||||||
|
@ -315,16 +318,19 @@ func (s *OutputRoomEventConsumer) onOldRoomEvent(
|
||||||
// hack but until we have some better strategy for dealing with
|
// hack but until we have some better strategy for dealing with
|
||||||
// old events in the sync API, this should at least prevent us
|
// old events in the sync API, this should at least prevent us
|
||||||
// from confusing clients into thinking they've joined/left rooms.
|
// from confusing clients into thinking they've joined/left rooms.
|
||||||
pduPos, err := s.db.WriteEvent(
|
|
||||||
ctx,
|
validRoomID, err := spec.NewRoomID(ev.RoomID())
|
||||||
ev,
|
if err != nil {
|
||||||
[]*rstypes.HeaderedEvent{},
|
return err
|
||||||
[]string{}, // adds no state
|
}
|
||||||
[]string{}, // removes no state
|
|
||||||
nil, // no transaction
|
userID, err := s.rsAPI.QueryUserIDForSender(ctx, *validRoomID, ev.SenderID())
|
||||||
ev.StateKey() != nil, // exclude from sync?,
|
if err != nil {
|
||||||
msg.HistoryVisibility,
|
return err
|
||||||
)
|
}
|
||||||
|
ev.UserID = *userID
|
||||||
|
|
||||||
|
pduPos, err := s.db.WriteEvent(ctx, ev, []*rstypes.HeaderedEvent{}, []string{}, []string{}, nil, ev.StateKey() != nil, msg.HistoryVisibility)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// panic rather than continue with an inconsistent database
|
// panic rather than continue with an inconsistent database
|
||||||
log.WithFields(log.Fields{
|
log.WithFields(log.Fields{
|
||||||
|
@ -420,6 +426,8 @@ func (s *OutputRoomEventConsumer) onNewInviteEvent(
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
msg.Event.UserID = *userID
|
||||||
|
|
||||||
pduPos, err := s.db.AddInviteEvent(ctx, msg.Event)
|
pduPos, err := s.db.AddInviteEvent(ctx, msg.Event)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
sentry.CaptureException(err)
|
sentry.CaptureException(err)
|
||||||
|
@ -537,6 +545,7 @@ func (s *OutputRoomEventConsumer) onPurgeRoom(
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *OutputRoomEventConsumer) updateStateEvent(event *rstypes.HeaderedEvent) (*rstypes.HeaderedEvent, error) {
|
func (s *OutputRoomEventConsumer) updateStateEvent(event *rstypes.HeaderedEvent) (*rstypes.HeaderedEvent, error) {
|
||||||
|
event.StateKeyResolved = event.StateKey()
|
||||||
if event.StateKey() == nil {
|
if event.StateKey() == nil {
|
||||||
return event, nil
|
return event, nil
|
||||||
}
|
}
|
||||||
|
@ -556,6 +565,29 @@ func (s *OutputRoomEventConsumer) updateStateEvent(event *rstypes.HeaderedEvent)
|
||||||
return event, err
|
return event, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
validRoomID, err := spec.NewRoomID(event.RoomID())
|
||||||
|
if err != nil {
|
||||||
|
return event, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if event.StateKey() != nil {
|
||||||
|
if *event.StateKey() != "" {
|
||||||
|
var sku *spec.UserID
|
||||||
|
sku, err = s.rsAPI.QueryUserIDForSender(s.ctx, *validRoomID, spec.SenderID(stateKey))
|
||||||
|
if err == nil && sku != nil {
|
||||||
|
sKey := sku.String()
|
||||||
|
event.StateKeyResolved = &sKey
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
userID, err := s.rsAPI.QueryUserIDForSender(s.ctx, *validRoomID, event.SenderID())
|
||||||
|
if err != nil {
|
||||||
|
return event, err
|
||||||
|
}
|
||||||
|
|
||||||
|
event.UserID = *userID
|
||||||
|
|
||||||
if prevEvent == nil || prevEvent.EventID() == event.EventID() {
|
if prevEvent == nil || prevEvent.EventID() == event.EventID() {
|
||||||
return event, nil
|
return event, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -230,6 +230,7 @@ func TestSearch(t *testing.T) {
|
||||||
stateEvents = append(stateEvents, x)
|
stateEvents = append(stateEvents, x)
|
||||||
stateEventIDs = append(stateEventIDs, x.EventID())
|
stateEventIDs = append(stateEventIDs, x.EventID())
|
||||||
}
|
}
|
||||||
|
x.StateKeyResolved = x.StateKey()
|
||||||
sp, err = db.WriteEvent(processCtx.Context(), x, stateEvents, stateEventIDs, nil, nil, false, gomatrixserverlib.HistoryVisibilityShared)
|
sp, err = db.WriteEvent(processCtx.Context(), x, stateEvents, stateEventIDs, nil, nil, false, gomatrixserverlib.HistoryVisibilityShared)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
if x.Type() != "m.room.message" {
|
if x.Type() != "m.room.message" {
|
||||||
|
|
|
@ -343,9 +343,9 @@ func (s *currentRoomStateStatements) UpsertRoomState(
|
||||||
event.RoomID(),
|
event.RoomID(),
|
||||||
event.EventID(),
|
event.EventID(),
|
||||||
event.Type(),
|
event.Type(),
|
||||||
event.SenderID(),
|
event.UserID.String(),
|
||||||
containsURL,
|
containsURL,
|
||||||
*event.StateKey(),
|
*event.StateKeyResolved,
|
||||||
headeredJSON,
|
headeredJSON,
|
||||||
membership,
|
membership,
|
||||||
addedAt,
|
addedAt,
|
||||||
|
|
|
@ -101,7 +101,7 @@ func (s *inviteEventsStatements) InsertInviteEvent(
|
||||||
ctx,
|
ctx,
|
||||||
inviteEvent.RoomID(),
|
inviteEvent.RoomID(),
|
||||||
inviteEvent.EventID(),
|
inviteEvent.EventID(),
|
||||||
*inviteEvent.StateKey(),
|
inviteEvent.UserID.String(),
|
||||||
headeredJSON,
|
headeredJSON,
|
||||||
).Scan(&streamPos)
|
).Scan(&streamPos)
|
||||||
return
|
return
|
||||||
|
|
|
@ -109,7 +109,7 @@ func (s *membershipsStatements) UpsertMembership(
|
||||||
_, err = sqlutil.TxStmt(txn, s.upsertMembershipStmt).ExecContext(
|
_, err = sqlutil.TxStmt(txn, s.upsertMembershipStmt).ExecContext(
|
||||||
ctx,
|
ctx,
|
||||||
event.RoomID(),
|
event.RoomID(),
|
||||||
*event.StateKey(),
|
event.StateKeyResolved,
|
||||||
membership,
|
membership,
|
||||||
event.EventID(),
|
event.EventID(),
|
||||||
streamPos,
|
streamPos,
|
||||||
|
|
|
@ -407,7 +407,7 @@ func (s *outputRoomEventsStatements) InsertEvent(
|
||||||
event.EventID(),
|
event.EventID(),
|
||||||
headeredJSON,
|
headeredJSON,
|
||||||
event.Type(),
|
event.Type(),
|
||||||
event.SenderID(),
|
event.UserID.String(),
|
||||||
containsURL,
|
containsURL,
|
||||||
pq.StringArray(addState),
|
pq.StringArray(addState),
|
||||||
pq.StringArray(removeState),
|
pq.StringArray(removeState),
|
||||||
|
|
|
@ -342,9 +342,9 @@ func (s *currentRoomStateStatements) UpsertRoomState(
|
||||||
event.RoomID(),
|
event.RoomID(),
|
||||||
event.EventID(),
|
event.EventID(),
|
||||||
event.Type(),
|
event.Type(),
|
||||||
event.SenderID(),
|
event.UserID.String(),
|
||||||
containsURL,
|
containsURL,
|
||||||
*event.StateKey(),
|
*event.StateKeyResolved,
|
||||||
headeredJSON,
|
headeredJSON,
|
||||||
membership,
|
membership,
|
||||||
addedAt,
|
addedAt,
|
||||||
|
|
|
@ -108,7 +108,7 @@ func (s *inviteEventsStatements) InsertInviteEvent(
|
||||||
streamPos,
|
streamPos,
|
||||||
inviteEvent.RoomID(),
|
inviteEvent.RoomID(),
|
||||||
inviteEvent.EventID(),
|
inviteEvent.EventID(),
|
||||||
*inviteEvent.StateKey(),
|
inviteEvent.UserID.String(),
|
||||||
headeredJSON,
|
headeredJSON,
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
|
@ -112,7 +112,7 @@ func (s *membershipsStatements) UpsertMembership(
|
||||||
_, err = sqlutil.TxStmt(txn, s.upsertMembershipStmt).ExecContext(
|
_, err = sqlutil.TxStmt(txn, s.upsertMembershipStmt).ExecContext(
|
||||||
ctx,
|
ctx,
|
||||||
event.RoomID(),
|
event.RoomID(),
|
||||||
*event.StateKey(),
|
event.StateKeyResolved,
|
||||||
membership,
|
membership,
|
||||||
event.EventID(),
|
event.EventID(),
|
||||||
streamPos,
|
streamPos,
|
||||||
|
|
|
@ -348,7 +348,7 @@ func (s *outputRoomEventsStatements) InsertEvent(
|
||||||
event.EventID(),
|
event.EventID(),
|
||||||
headeredJSON,
|
headeredJSON,
|
||||||
event.Type(),
|
event.Type(),
|
||||||
event.SenderID(),
|
event.UserID.String(),
|
||||||
containsURL,
|
containsURL,
|
||||||
string(addStateJSON),
|
string(addStateJSON),
|
||||||
string(removeStateJSON),
|
string(removeStateJSON),
|
||||||
|
|
|
@ -43,6 +43,7 @@ func MustWriteEvents(t *testing.T, db storage.Database, events []*rstypes.Header
|
||||||
var addStateEventIDs []string
|
var addStateEventIDs []string
|
||||||
var removeStateEventIDs []string
|
var removeStateEventIDs []string
|
||||||
if ev.StateKey() != nil {
|
if ev.StateKey() != nil {
|
||||||
|
ev.StateKeyResolved = ev.StateKey()
|
||||||
addStateEvents = append(addStateEvents, ev)
|
addStateEvents = append(addStateEvents, ev)
|
||||||
addStateEventIDs = append(addStateEventIDs, ev.EventID())
|
addStateEventIDs = append(addStateEventIDs, ev.EventID())
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,13 @@ func TestCurrentRoomStateTable(t *testing.T) {
|
||||||
events := room.CurrentState()
|
events := room.CurrentState()
|
||||||
err := sqlutil.WithTransaction(db, func(txn *sql.Tx) error {
|
err := sqlutil.WithTransaction(db, func(txn *sql.Tx) error {
|
||||||
for i, ev := range events {
|
for i, ev := range events {
|
||||||
err := tab.UpsertRoomState(ctx, txn, ev, nil, types.StreamPosition(i))
|
ev.StateKeyResolved = ev.StateKey()
|
||||||
|
userID, err := spec.NewUserID(string(ev.SenderID()), true)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ev.UserID = *userID
|
||||||
|
err = tab.UpsertRoomState(ctx, txn, ev, nil, types.StreamPosition(i))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to UpsertRoomState: %w", err)
|
return fmt.Errorf("failed to UpsertRoomState: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,6 +80,7 @@ func TestMembershipsTable(t *testing.T) {
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
for _, ev := range userEvents {
|
for _, ev := range userEvents {
|
||||||
|
ev.StateKeyResolved = ev.StateKey()
|
||||||
if err := table.UpsertMembership(ctx, nil, ev, types.StreamPosition(ev.Depth()), 1); err != nil {
|
if err := table.UpsertMembership(ctx, nil, ev, types.StreamPosition(ev.Depth()), 1); err != nil {
|
||||||
t.Fatalf("failed to upsert membership: %s", err)
|
t.Fatalf("failed to upsert membership: %s", err)
|
||||||
}
|
}
|
||||||
|
@ -134,6 +135,7 @@ func testUpsert(t *testing.T, ctx context.Context, table tables.Memberships, mem
|
||||||
ev := room.CreateAndInsert(t, user, spec.MRoomMember, map[string]interface{}{
|
ev := room.CreateAndInsert(t, user, spec.MRoomMember, map[string]interface{}{
|
||||||
"membership": spec.Join,
|
"membership": spec.Join,
|
||||||
}, test.WithStateKey(user.ID))
|
}, test.WithStateKey(user.ID))
|
||||||
|
ev.StateKeyResolved = ev.StateKey()
|
||||||
// Insert the same event again, but with different positions, which should get updated
|
// Insert the same event again, but with different positions, which should get updated
|
||||||
if err = table.UpsertMembership(ctx, nil, ev, 2, 2); err != nil {
|
if err = table.UpsertMembership(ctx, nil, ev, 2, 2); err != nil {
|
||||||
t.Fatalf("failed to upsert membership: %s", err)
|
t.Fatalf("failed to upsert membership: %s", err)
|
||||||
|
|
|
@ -3,6 +3,7 @@ package streams
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -15,6 +16,8 @@ import (
|
||||||
"github.com/matrix-org/dendrite/syncapi/types"
|
"github.com/matrix-org/dendrite/syncapi/types"
|
||||||
userapi "github.com/matrix-org/dendrite/userapi/api"
|
userapi "github.com/matrix-org/dendrite/userapi/api"
|
||||||
"github.com/matrix-org/gomatrixserverlib/spec"
|
"github.com/matrix-org/gomatrixserverlib/spec"
|
||||||
|
"github.com/tidwall/gjson"
|
||||||
|
"github.com/tidwall/sjson"
|
||||||
|
|
||||||
"github.com/matrix-org/dendrite/syncapi/notifier"
|
"github.com/matrix-org/dendrite/syncapi/notifier"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
@ -346,13 +349,40 @@ func (p *PDUStreamProvider) addRoomDeltaToResponse(
|
||||||
// Now that we've filtered the timeline, work out which state events are still
|
// Now that we've filtered the timeline, work out which state events are still
|
||||||
// left. Anything that appears in the filtered timeline will be removed from the
|
// left. Anything that appears in the filtered timeline will be removed from the
|
||||||
// "state" section and kept in "timeline".
|
// "state" section and kept in "timeline".
|
||||||
|
|
||||||
|
// update the powerlevel event for timeline events
|
||||||
|
for i, ev := range events {
|
||||||
|
if ev.Version() != gomatrixserverlib.RoomVersionPseudoIDs {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if ev.Type() != spec.MRoomPowerLevels || !ev.StateKeyEquals("") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
var newEvent gomatrixserverlib.PDU
|
||||||
|
newEvent, err = p.updatePowerLevelEvent(ctx, ev)
|
||||||
|
if err != nil {
|
||||||
|
return r.From, err
|
||||||
|
}
|
||||||
|
events[i] = &rstypes.HeaderedEvent{PDU: newEvent}
|
||||||
|
}
|
||||||
|
|
||||||
sEvents := gomatrixserverlib.HeaderedReverseTopologicalOrdering(
|
sEvents := gomatrixserverlib.HeaderedReverseTopologicalOrdering(
|
||||||
gomatrixserverlib.ToPDUs(removeDuplicates(delta.StateEvents, events)),
|
gomatrixserverlib.ToPDUs(removeDuplicates(delta.StateEvents, events)),
|
||||||
gomatrixserverlib.TopologicalOrderByAuthEvents,
|
gomatrixserverlib.TopologicalOrderByAuthEvents,
|
||||||
)
|
)
|
||||||
delta.StateEvents = make([]*rstypes.HeaderedEvent, len(sEvents))
|
delta.StateEvents = make([]*rstypes.HeaderedEvent, len(sEvents))
|
||||||
for i := range sEvents {
|
for i := range sEvents {
|
||||||
delta.StateEvents[i] = sEvents[i].(*rstypes.HeaderedEvent)
|
ev := sEvents[i]
|
||||||
|
delta.StateEvents[i] = ev.(*rstypes.HeaderedEvent)
|
||||||
|
// update the powerlevel event for state events
|
||||||
|
if ev.Version() == gomatrixserverlib.RoomVersionPseudoIDs && ev.Type() == spec.MRoomPowerLevels && ev.StateKeyEquals("") {
|
||||||
|
var newEvent gomatrixserverlib.PDU
|
||||||
|
newEvent, err = p.updatePowerLevelEvent(ctx, ev.(*rstypes.HeaderedEvent))
|
||||||
|
if err != nil {
|
||||||
|
return r.From, err
|
||||||
|
}
|
||||||
|
delta.StateEvents[i] = &rstypes.HeaderedEvent{PDU: newEvent}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(delta.StateEvents) > 0 {
|
if len(delta.StateEvents) > 0 {
|
||||||
|
@ -421,6 +451,75 @@ func (p *PDUStreamProvider) addRoomDeltaToResponse(
|
||||||
return latestPosition, nil
|
return latestPosition, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *PDUStreamProvider) updatePowerLevelEvent(ctx context.Context, ev *rstypes.HeaderedEvent) (gomatrixserverlib.PDU, error) {
|
||||||
|
pls, err := gomatrixserverlib.NewPowerLevelContentFromEvent(ev)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
newPls := make(map[string]int64)
|
||||||
|
var userID *spec.UserID
|
||||||
|
for user, level := range pls.Users {
|
||||||
|
validRoomID, _ := spec.NewRoomID(ev.RoomID())
|
||||||
|
userID, err = p.rsAPI.QueryUserIDForSender(ctx, *validRoomID, spec.SenderID(user))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
newPls[userID.String()] = level
|
||||||
|
}
|
||||||
|
var newPlBytes, newEv []byte
|
||||||
|
newPlBytes, err = json.Marshal(newPls)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
newEv, err = sjson.SetRawBytes(ev.JSON(), "content.users", newPlBytes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// do the same for prev content
|
||||||
|
prevContent := gjson.GetBytes(ev.JSON(), "unsigned.prev_content")
|
||||||
|
if !prevContent.Exists() {
|
||||||
|
var evNew gomatrixserverlib.PDU
|
||||||
|
evNew, err = gomatrixserverlib.MustGetRoomVersion(gomatrixserverlib.RoomVersionPseudoIDs).NewEventFromTrustedJSON(newEv, false)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return evNew, err
|
||||||
|
}
|
||||||
|
pls = gomatrixserverlib.PowerLevelContent{}
|
||||||
|
err = json.Unmarshal([]byte(prevContent.Raw), &pls)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
newPls = make(map[string]int64)
|
||||||
|
for user, level := range pls.Users {
|
||||||
|
validRoomID, _ := spec.NewRoomID(ev.RoomID())
|
||||||
|
userID, err = p.rsAPI.QueryUserIDForSender(ctx, *validRoomID, spec.SenderID(user))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
newPls[userID.String()] = level
|
||||||
|
}
|
||||||
|
newPlBytes, err = json.Marshal(newPls)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
newEv, err = sjson.SetRawBytes(newEv, "unsigned.prev_content.users", newPlBytes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var evNew gomatrixserverlib.PDU
|
||||||
|
evNew, err = gomatrixserverlib.MustGetRoomVersion(gomatrixserverlib.RoomVersionPseudoIDs).NewEventFromTrustedJSON(newEv, false)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return evNew, err
|
||||||
|
}
|
||||||
|
|
||||||
// applyHistoryVisibilityFilter gets the current room state and supplies it to ApplyHistoryVisibilityFilter, to make
|
// applyHistoryVisibilityFilter gets the current room state and supplies it to ApplyHistoryVisibilityFilter, to make
|
||||||
// sure we always return the required events in the timeline.
|
// sure we always return the required events in the timeline.
|
||||||
func applyHistoryVisibilityFilter(
|
func applyHistoryVisibilityFilter(
|
||||||
|
@ -470,6 +569,7 @@ func applyHistoryVisibilityFilter(
|
||||||
return events, nil
|
return events, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// nolint: gocyclo
|
||||||
func (p *PDUStreamProvider) getJoinResponseForCompleteSync(
|
func (p *PDUStreamProvider) getJoinResponseForCompleteSync(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
snapshot storage.DatabaseTransaction,
|
snapshot storage.DatabaseTransaction,
|
||||||
|
@ -563,6 +663,35 @@ func (p *PDUStreamProvider) getJoinResponseForCompleteSync(
|
||||||
prevBatch.Decrement()
|
prevBatch.Decrement()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update powerlevel events for timeline events
|
||||||
|
for i, ev := range events {
|
||||||
|
if ev.Version() != gomatrixserverlib.RoomVersionPseudoIDs {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if ev.Type() != spec.MRoomPowerLevels || !ev.StateKeyEquals("") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
newEvent, err := p.updatePowerLevelEvent(ctx, ev)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
events[i] = &rstypes.HeaderedEvent{PDU: newEvent}
|
||||||
|
}
|
||||||
|
// Update powerlevel events for state events
|
||||||
|
for i, ev := range stateEvents {
|
||||||
|
if ev.Version() != gomatrixserverlib.RoomVersionPseudoIDs {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if ev.Type() != spec.MRoomPowerLevels || !ev.StateKeyEquals("") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
newEvent, err := p.updatePowerLevelEvent(ctx, ev)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
stateEvents[i] = &rstypes.HeaderedEvent{PDU: newEvent}
|
||||||
|
}
|
||||||
|
|
||||||
jr.Timeline.PrevBatch = prevBatch
|
jr.Timeline.PrevBatch = prevBatch
|
||||||
jr.Timeline.Events = synctypes.ToClientEvents(gomatrixserverlib.ToPDUs(events), synctypes.FormatSync, func(roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) {
|
jr.Timeline.Events = synctypes.ToClientEvents(gomatrixserverlib.ToPDUs(events), synctypes.FormatSync, func(roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) {
|
||||||
return p.rsAPI.QueryUserIDForSender(ctx, roomID, senderID)
|
return p.rsAPI.QueryUserIDForSender(ctx, roomID, senderID)
|
||||||
|
|
Loading…
Reference in a new issue