mirror of
https://github.com/element-hq/dendrite.git
synced 2025-09-13 12:52:24 +03:00
Room version 12 (#3623)
Some checks are pending
Dendrite / Sytest (SQLite Cgo) (push) Blocked by required conditions
Dendrite / WASM build test (push) Waiting to run
Dendrite / Linting (push) Waiting to run
Dendrite / Unit tests (push) Waiting to run
Dendrite / Build for Linux (push) Waiting to run
Dendrite / Build for Windows (push) Waiting to run
Dendrite / Initial tests passed (push) Blocked by required conditions
Dendrite / Integration tests (push) Blocked by required conditions
Dendrite / Upgrade tests (push) Blocked by required conditions
Dendrite / Upgrade tests from HEAD-2 (push) Blocked by required conditions
Dendrite / Sytest (PostgreSQL) (push) Blocked by required conditions
Dendrite / Sytest (SQLite native) (push) Blocked by required conditions
Dendrite / Complement (PostgreSQL) (push) Blocked by required conditions
Dendrite / Complement (SQLite native) (push) Blocked by required conditions
Dendrite / Complement (SQLite Cgo) (push) Blocked by required conditions
Dendrite / Integration tests passed (push) Blocked by required conditions
Dendrite / Update Docker images (push) Blocked by required conditions
Some checks are pending
Dendrite / Sytest (SQLite Cgo) (push) Blocked by required conditions
Dendrite / WASM build test (push) Waiting to run
Dendrite / Linting (push) Waiting to run
Dendrite / Unit tests (push) Waiting to run
Dendrite / Build for Linux (push) Waiting to run
Dendrite / Build for Windows (push) Waiting to run
Dendrite / Initial tests passed (push) Blocked by required conditions
Dendrite / Integration tests (push) Blocked by required conditions
Dendrite / Upgrade tests (push) Blocked by required conditions
Dendrite / Upgrade tests from HEAD-2 (push) Blocked by required conditions
Dendrite / Sytest (PostgreSQL) (push) Blocked by required conditions
Dendrite / Sytest (SQLite native) (push) Blocked by required conditions
Dendrite / Complement (PostgreSQL) (push) Blocked by required conditions
Dendrite / Complement (SQLite native) (push) Blocked by required conditions
Dendrite / Complement (SQLite Cgo) (push) Blocked by required conditions
Dendrite / Integration tests passed (push) Blocked by required conditions
Dendrite / Update Docker images (push) Blocked by required conditions
This commit is contained in:
parent
a408b24d28
commit
4d93d921be
26 changed files with 530 additions and 208 deletions
|
@ -176,12 +176,6 @@ func createRoom(
|
||||||
roomVersion = candidateVersion
|
roomVersion = candidateVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.WithFields(log.Fields{
|
|
||||||
"userID": userID.String(),
|
|
||||||
"roomID": roomID.String(),
|
|
||||||
"roomVersion": roomVersion,
|
|
||||||
}).Info("Creating new room")
|
|
||||||
|
|
||||||
profile, err := appserviceAPI.RetrieveUserProfile(ctx, userID.String(), asAPI, profileAPI)
|
profile, err := appserviceAPI.RetrieveUserProfile(ctx, userID.String(), asAPI, profileAPI)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
util.GetLogger(ctx).WithError(err).Error("appserviceAPI.RetrieveUserProfile failed")
|
util.GetLogger(ctx).WithError(err).Error("appserviceAPI.RetrieveUserProfile failed")
|
||||||
|
@ -197,6 +191,49 @@ func createRoom(
|
||||||
keyID := cfg.Matrix.KeyID
|
keyID := cfg.Matrix.KeyID
|
||||||
privateKey := cfg.Matrix.PrivateKey
|
privateKey := cfg.Matrix.PrivateKey
|
||||||
|
|
||||||
|
verImpl := gomatrixserverlib.MustGetRoomVersion(roomVersion)
|
||||||
|
|
||||||
|
var createEventJSON json.RawMessage
|
||||||
|
if verImpl.DomainlessRoomIDs() {
|
||||||
|
// make the create event up-front so the roomserver can calculate the room NID to store.
|
||||||
|
var additionalCreators []string
|
||||||
|
if createRequest.Preset == spec.PresetTrustedPrivateChat {
|
||||||
|
additionalCreators = createRequest.Invite
|
||||||
|
}
|
||||||
|
createContent, err := roomserverAPI.GenerateCreateContent(ctx, createRequest.RoomVersion, userID.String(), createRequest.CreationContent, additionalCreators)
|
||||||
|
if err != nil {
|
||||||
|
util.GetLogger(ctx).WithError(err).Error("GenerateCreateContent failed")
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: http.StatusBadRequest,
|
||||||
|
JSON: spec.BadJSON("invalid create content"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
authEvents, _ := gomatrixserverlib.NewAuthEvents(nil)
|
||||||
|
identity, err := cfg.Matrix.SigningIdentityFor(userID.Domain())
|
||||||
|
if err != nil {
|
||||||
|
util.GetLogger(ctx).WithError(err).Error("Failed to get signing identity")
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: http.StatusInternalServerError,
|
||||||
|
JSON: spec.InternalServerError{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
createEvent, jsonErr := roomserverAPI.GeneratePDU(
|
||||||
|
ctx, gomatrixserverlib.MustGetRoomVersion(roomVersion),
|
||||||
|
gomatrixserverlib.FledglingEvent{
|
||||||
|
Type: spec.MRoomCreate,
|
||||||
|
Content: createContent,
|
||||||
|
},
|
||||||
|
authEvents, 1, "", identity, evTime, userID.String(), "", rsAPI,
|
||||||
|
)
|
||||||
|
if jsonErr != nil {
|
||||||
|
util.GetLogger(ctx).WithError(err).Error("Failed to make the create event")
|
||||||
|
return *jsonErr
|
||||||
|
}
|
||||||
|
createEventJSON = createEvent.JSON()
|
||||||
|
r := createEvent.RoomID()
|
||||||
|
roomID = &r
|
||||||
|
}
|
||||||
|
|
||||||
req := roomserverAPI.PerformCreateRoomRequest{
|
req := roomserverAPI.PerformCreateRoomRequest{
|
||||||
InvitedUsers: createRequest.Invite,
|
InvitedUsers: createRequest.Invite,
|
||||||
RoomName: createRequest.Name,
|
RoomName: createRequest.Name,
|
||||||
|
@ -204,6 +241,7 @@ func createRoom(
|
||||||
Topic: createRequest.Topic,
|
Topic: createRequest.Topic,
|
||||||
StatePreset: createRequest.Preset,
|
StatePreset: createRequest.Preset,
|
||||||
CreationContent: createRequest.CreationContent,
|
CreationContent: createRequest.CreationContent,
|
||||||
|
CreateEvent: createEventJSON,
|
||||||
InitialState: createRequest.InitialState,
|
InitialState: createRequest.InitialState,
|
||||||
RoomAliasName: createRequest.RoomAliasName,
|
RoomAliasName: createRequest.RoomAliasName,
|
||||||
RoomVersion: roomVersion,
|
RoomVersion: roomVersion,
|
||||||
|
@ -217,6 +255,12 @@ func createRoom(
|
||||||
EventTime: evTime,
|
EventTime: evTime,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger.WithFields(log.Fields{
|
||||||
|
"userID": userID.String(),
|
||||||
|
"roomID": roomID.String(),
|
||||||
|
"roomVersion": roomVersion,
|
||||||
|
}).Info("Creating new room")
|
||||||
|
|
||||||
roomAlias, createRes := rsAPI.PerformCreateRoom(ctx, *userID, *roomID, &req)
|
roomAlias, createRes := rsAPI.PerformCreateRoom(ctx, *userID, *roomID, &req)
|
||||||
if createRes != nil {
|
if createRes != nil {
|
||||||
return *createRes
|
return *createRes
|
||||||
|
|
|
@ -411,10 +411,11 @@ func SetVisibility(
|
||||||
JSON: spec.InternalServerError{},
|
JSON: spec.InternalServerError{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
privileged := isPrivilegedCreator(req.Context(), rsAPI, roomID, *senderID)
|
||||||
|
|
||||||
// NOTSPEC: Check if the user's power is greater than power required to change m.room.canonical_alias event
|
// NOTSPEC: Check if the user's power is greater than power required to change m.room.canonical_alias event
|
||||||
power, _ := gomatrixserverlib.NewPowerLevelContentFromEvent(queryEventsRes.StateEvents[0].PDU)
|
power, _ := gomatrixserverlib.NewPowerLevelContentFromEvent(queryEventsRes.StateEvents[0].PDU)
|
||||||
if power.UserLevel(*senderID) < power.EventLevel(spec.MRoomCanonicalAlias, true) {
|
if !privileged && power.UserLevel(*senderID) < power.EventLevel(spec.MRoomCanonicalAlias, true) {
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusForbidden,
|
Code: http.StatusForbidden,
|
||||||
JSON: spec.Forbidden("userID doesn't have power level to change visibility"),
|
JSON: spec.Forbidden("userID doesn't have power level to change visibility"),
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"crypto/ed25519"
|
"crypto/ed25519"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"slices"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
appserviceAPI "github.com/element-hq/dendrite/appservice/api"
|
appserviceAPI "github.com/element-hq/dendrite/appservice/api"
|
||||||
|
@ -79,7 +80,8 @@ func SendBan(
|
||||||
if errRes != nil {
|
if errRes != nil {
|
||||||
return *errRes
|
return *errRes
|
||||||
}
|
}
|
||||||
allowedToBan := pl.UserLevel(*senderID) >= pl.Ban
|
privileged := isPrivilegedCreator(req.Context(), rsAPI, roomID, *senderID)
|
||||||
|
allowedToBan := privileged || pl.UserLevel(*senderID) >= pl.Ban
|
||||||
if !allowedToBan {
|
if !allowedToBan {
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusForbidden,
|
Code: http.StatusForbidden,
|
||||||
|
@ -118,6 +120,12 @@ func sendMembership(ctx context.Context, profileAPI userapi.ClientUserAPI, devic
|
||||||
false,
|
false,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
util.GetLogger(ctx).WithError(err).Error("SendEvents failed")
|
util.GetLogger(ctx).WithError(err).Error("SendEvents failed")
|
||||||
|
if err.Error() == api.InputWasRejected {
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: http.StatusForbidden,
|
||||||
|
JSON: spec.Forbidden("the event was rejected"),
|
||||||
|
}
|
||||||
|
}
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusInternalServerError,
|
Code: http.StatusInternalServerError,
|
||||||
JSON: spec.InternalServerError{},
|
JSON: spec.InternalServerError{},
|
||||||
|
@ -185,7 +193,8 @@ func SendKick(
|
||||||
if errRes != nil {
|
if errRes != nil {
|
||||||
return *errRes
|
return *errRes
|
||||||
}
|
}
|
||||||
allowedToKick := pl.UserLevel(*senderID) >= pl.Kick || bodyUserID.String() == deviceUserID.String()
|
privileged := isPrivilegedCreator(req.Context(), rsAPI, roomID, *senderID)
|
||||||
|
allowedToKick := privileged || pl.UserLevel(*senderID) >= pl.Kick || bodyUserID.String() == deviceUserID.String()
|
||||||
if !allowedToKick {
|
if !allowedToKick {
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusForbidden,
|
Code: http.StatusForbidden,
|
||||||
|
@ -680,3 +689,12 @@ func getPowerlevels(req *http.Request, rsAPI roomserverAPI.ClientRoomserverAPI,
|
||||||
}
|
}
|
||||||
return pl, nil
|
return pl, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns true if the room is a room which supports privileged creators and the sender is a creator, else false.
|
||||||
|
func isPrivilegedCreator(ctx context.Context, rsAPI roomserverAPI.ClientRoomserverAPI, roomID string, senderID spec.SenderID) bool {
|
||||||
|
createEvent := roomserverAPI.GetStateEvent(ctx, rsAPI, roomID, gomatrixserverlib.StateKeyTuple{
|
||||||
|
EventType: spec.MRoomCreate,
|
||||||
|
StateKey: "",
|
||||||
|
})
|
||||||
|
return gomatrixserverlib.MustGetRoomVersion(createEvent.Version()).PrivilegedCreators() && slices.Contains(gomatrixserverlib.CreatorsFromCreateEvent(createEvent), string(senderID))
|
||||||
|
}
|
||||||
|
|
|
@ -98,10 +98,12 @@ func SendRedaction(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
privileged := isPrivilegedCreator(req.Context(), rsAPI, roomID, *senderID)
|
||||||
|
|
||||||
// "Users may redact their own events, and any user with a power level greater than or equal
|
// "Users may redact their own events, and any user with a power level greater than or equal
|
||||||
// to the redact power level of the room may redact events there"
|
// to the redact power level of the room may redact events there"
|
||||||
// https://matrix.org/docs/spec/client_server/r0.6.1#put-matrix-client-r0-rooms-roomid-redact-eventid-txnid
|
// https://matrix.org/docs/spec/client_server/r0.6.1#put-matrix-client-r0-rooms-roomid-redact-eventid-txnid
|
||||||
allowedToRedact := ev.SenderID() == *senderID
|
allowedToRedact := ev.SenderID() == *senderID || privileged
|
||||||
if !allowedToRedact {
|
if !allowedToRedact {
|
||||||
plEvent := roomserverAPI.GetStateEvent(req.Context(), rsAPI, roomID, gomatrixserverlib.StateKeyTuple{
|
plEvent := roomserverAPI.GetStateEvent(req.Context(), rsAPI, roomID, gomatrixserverlib.StateKeyTuple{
|
||||||
EventType: spec.MRoomPowerLevels,
|
EventType: spec.MRoomPowerLevels,
|
||||||
|
|
|
@ -77,7 +77,6 @@ func SendEvent(
|
||||||
JSON: spec.UnsupportedRoomVersion(err.Error()),
|
JSON: spec.UnsupportedRoomVersion(err.Error()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if txnID != nil {
|
if txnID != nil {
|
||||||
// Try to fetch response from transactionsCache
|
// Try to fetch response from transactionsCache
|
||||||
if res, ok := txnCache.FetchTransaction(device.AccessToken, *txnID, req.URL); ok {
|
if res, ok := txnCache.FetchTransaction(device.AccessToken, *txnID, req.URL); ok {
|
||||||
|
@ -367,6 +366,12 @@ func generateSendEvent(
|
||||||
JSON: spec.InternalServerError{},
|
JSON: spec.InternalServerError{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if proto.Type == spec.MRoomCreate && proto.StateKey != nil && *proto.StateKey == "" {
|
||||||
|
return nil, &util.JSONResponse{
|
||||||
|
Code: http.StatusBadRequest,
|
||||||
|
JSON: spec.InvalidParam("cannot resend m.room.create event"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
identity, err := rsAPI.SigningIdentityFor(ctx, *validRoomID, *fullUserID)
|
identity, err := rsAPI.SigningIdentityFor(ctx, *validRoomID, *fullUserID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -424,8 +429,13 @@ func generateSendEvent(
|
||||||
if err = gomatrixserverlib.Allowed(e.PDU, provider, func(roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) {
|
if err = gomatrixserverlib.Allowed(e.PDU, provider, func(roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) {
|
||||||
return rsAPI.QueryUserIDForSender(ctx, *validRoomID, senderID)
|
return rsAPI.QueryUserIDForSender(ctx, *validRoomID, senderID)
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
|
code := 403
|
||||||
|
validationErr, ok := err.(*gomatrixserverlib.EventValidationError)
|
||||||
|
if ok {
|
||||||
|
code = validationErr.Code
|
||||||
|
}
|
||||||
return nil, &util.JSONResponse{
|
return nil, &util.JSONResponse{
|
||||||
Code: http.StatusForbidden,
|
Code: code,
|
||||||
JSON: spec.Forbidden(err.Error()), // TODO: Is this error string comprehensible to the client?
|
JSON: spec.Forbidden(err.Error()), // TODO: Is this error string comprehensible to the client?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/matrix-org/gomatrix"
|
"github.com/matrix-org/gomatrix"
|
||||||
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
"github.com/matrix-org/gomatrixserverlib/tokens"
|
"github.com/matrix-org/gomatrixserverlib/tokens"
|
||||||
"github.com/matrix-org/util"
|
"github.com/matrix-org/util"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
@ -139,7 +140,7 @@ func SendServerNotice(
|
||||||
|
|
||||||
// create a new room for the user
|
// create a new room for the user
|
||||||
if len(commonRooms) == 0 {
|
if len(commonRooms) == 0 {
|
||||||
powerLevelContent := eventutil.InitialPowerLevelsContent(senderUserID.String())
|
powerLevelContent := eventutil.InitialPowerLevelsContent(gomatrixserverlib.MustGetRoomVersion(roomVersion), senderUserID.String())
|
||||||
powerLevelContent.Users[r.UserID] = -10 // taken from Synapse
|
powerLevelContent.Users[r.UserID] = -10 // taken from Synapse
|
||||||
pl, err := json.Marshal(powerLevelContent)
|
pl, err := json.Marshal(powerLevelContent)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -24,6 +24,7 @@ import (
|
||||||
|
|
||||||
type upgradeRoomRequest struct {
|
type upgradeRoomRequest struct {
|
||||||
NewVersion string `json:"new_version"`
|
NewVersion string `json:"new_version"`
|
||||||
|
AdditionalCreators []string `json:"additional_creators"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type upgradeRoomResponse struct {
|
type upgradeRoomResponse struct {
|
||||||
|
@ -43,6 +44,13 @@ func UpgradeRoom(
|
||||||
return *rErr
|
return *rErr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if r.NewVersion == "" {
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: http.StatusBadRequest,
|
||||||
|
JSON: spec.InvalidParam("missing version to upgrade to"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Validate that the room version is supported
|
// Validate that the room version is supported
|
||||||
if _, err := version.SupportedRoomVersion(gomatrixserverlib.RoomVersion(r.NewVersion)); err != nil {
|
if _, err := version.SupportedRoomVersion(gomatrixserverlib.RoomVersion(r.NewVersion)); err != nil {
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
|
@ -59,7 +67,10 @@ func UpgradeRoom(
|
||||||
JSON: spec.InternalServerError{},
|
JSON: spec.InternalServerError{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
newRoomID, err := rsAPI.PerformRoomUpgrade(req.Context(), roomID, *userID, gomatrixserverlib.RoomVersion(r.NewVersion))
|
newRoomID, err := rsAPI.PerformRoomUpgrade(req.Context(), roomID, *userID, gomatrixserverlib.RoomVersion(r.NewVersion), r.AdditionalCreators)
|
||||||
|
if err != nil {
|
||||||
|
util.GetLogger(req.Context()).WithError(err).Error("PerformRoomUpgrade failed")
|
||||||
|
}
|
||||||
switch e := err.(type) {
|
switch e := err.(type) {
|
||||||
case nil:
|
case nil:
|
||||||
case roomserverAPI.ErrNotAllowed:
|
case roomserverAPI.ErrNotAllowed:
|
||||||
|
|
4
go.mod
4
go.mod
|
@ -25,7 +25,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-20250619052822-904c8f04597e
|
github.com/matrix-org/gomatrixserverlib v0.0.0-20250811193806-b7e0e0824751
|
||||||
github.com/matrix-org/pinecone v0.11.1-0.20230810010612-ea4c33717fd7
|
github.com/matrix-org/pinecone v0.11.1-0.20230810010612-ea4c33717fd7
|
||||||
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.28
|
github.com/mattn/go-sqlite3 v1.14.28
|
||||||
|
@ -100,6 +100,7 @@ require (
|
||||||
github.com/google/go-tpm v0.9.3 // indirect
|
github.com/google/go-tpm v0.9.3 // indirect
|
||||||
github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd // indirect
|
github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd // indirect
|
||||||
github.com/h2non/filetype v1.1.3 // indirect
|
github.com/h2non/filetype v1.1.3 // indirect
|
||||||
|
github.com/hashicorp/go-set/v3 v3.0.0 // indirect
|
||||||
github.com/hjson/hjson-go/v4 v4.4.0 // indirect
|
github.com/hjson/hjson-go/v4 v4.4.0 // indirect
|
||||||
github.com/json-iterator/go v1.1.12 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
github.com/juju/errors v1.0.0 // indirect
|
github.com/juju/errors v1.0.0 // indirect
|
||||||
|
@ -118,6 +119,7 @@ require (
|
||||||
github.com/nats-io/nkeys v0.4.11 // indirect
|
github.com/nats-io/nkeys v0.4.11 // indirect
|
||||||
github.com/nats-io/nuid v1.0.1 // indirect
|
github.com/nats-io/nuid v1.0.1 // indirect
|
||||||
github.com/ncruces/go-strftime v0.1.9 // indirect
|
github.com/ncruces/go-strftime v0.1.9 // indirect
|
||||||
|
github.com/oleiade/lane/v2 v2.0.0 // indirect
|
||||||
github.com/onsi/ginkgo/v2 v2.11.0 // indirect
|
github.com/onsi/ginkgo/v2 v2.11.0 // indirect
|
||||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||||
github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 // indirect
|
github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 // indirect
|
||||||
|
|
12
go.sum
12
go.sum
|
@ -199,6 +199,8 @@ github.com/h2non/filetype v1.1.3 h1:FKkx9QbD7HR/zjK1Ia5XiBsq9zdLi5Kf3zGyFTAFkGg=
|
||||||
github.com/h2non/filetype v1.1.3/go.mod h1:319b3zT68BvV+WRj7cwy856M2ehB3HqNOt6sy1HndBY=
|
github.com/h2non/filetype v1.1.3/go.mod h1:319b3zT68BvV+WRj7cwy856M2ehB3HqNOt6sy1HndBY=
|
||||||
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw=
|
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw=
|
||||||
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
|
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
|
||||||
|
github.com/hashicorp/go-set/v3 v3.0.0 h1:CaJBQvQCOWoftrBcDt7Nwgo0kdpmrKxar/x2o6pV9JA=
|
||||||
|
github.com/hashicorp/go-set/v3 v3.0.0/go.mod h1:IEghM2MpE5IaNvL+D7X480dfNtxjRXZ6VMpK3C8s2ok=
|
||||||
github.com/hjson/hjson-go/v4 v4.4.0 h1:D/NPvqOCH6/eisTb5/ztuIS8GUvmpHaLOcNk1Bjr298=
|
github.com/hjson/hjson-go/v4 v4.4.0 h1:D/NPvqOCH6/eisTb5/ztuIS8GUvmpHaLOcNk1Bjr298=
|
||||||
github.com/hjson/hjson-go/v4 v4.4.0/go.mod h1:KaYt3bTw3zhBjYqnXkYywcYctk0A2nxeEFTse3rH13E=
|
github.com/hjson/hjson-go/v4 v4.4.0/go.mod h1:KaYt3bTw3zhBjYqnXkYywcYctk0A2nxeEFTse3rH13E=
|
||||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
|
@ -235,8 +237,10 @@ 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-20250619052822-904c8f04597e h1:SWediqisy1Eoumr06sjGaA6gt6gS4FtXe00VB6fSNZw=
|
github.com/matrix-org/gomatrixserverlib v0.0.0-20250811171307-390dbaa8de98 h1:AH19nhwaPYCRddS/s7LgKS+fhntFXg2qG47uFAjwFJ4=
|
||||||
github.com/matrix-org/gomatrixserverlib v0.0.0-20250619052822-904c8f04597e/go.mod h1:61LpEsWAroRfdVh2dnr6fQ+K3MmRgD5I35GVvF4FpXQ=
|
github.com/matrix-org/gomatrixserverlib v0.0.0-20250811171307-390dbaa8de98/go.mod h1:b6KVfDjXjA5Q7vhpOaMqIhFYvu5BuFVZixlNeTV/CLc=
|
||||||
|
github.com/matrix-org/gomatrixserverlib v0.0.0-20250811193806-b7e0e0824751 h1:x1pC7Nt1Qb24q9WtPybMHWo2uVFTzCKtlUAzarju8bk=
|
||||||
|
github.com/matrix-org/gomatrixserverlib v0.0.0-20250811193806-b7e0e0824751/go.mod h1:b6KVfDjXjA5Q7vhpOaMqIhFYvu5BuFVZixlNeTV/CLc=
|
||||||
github.com/matrix-org/pinecone v0.11.1-0.20230810010612-ea4c33717fd7 h1:6t8kJr8i1/1I5nNttw6nn1ryQJgzVlBmSGgPiiaTdw4=
|
github.com/matrix-org/pinecone v0.11.1-0.20230810010612-ea4c33717fd7 h1:6t8kJr8i1/1I5nNttw6nn1ryQJgzVlBmSGgPiiaTdw4=
|
||||||
github.com/matrix-org/pinecone v0.11.1-0.20230810010612-ea4c33717fd7/go.mod h1:ReWMS/LoVnOiRAdq9sNUC2NZnd1mZkMNB52QhpTRWjg=
|
github.com/matrix-org/pinecone v0.11.1-0.20230810010612-ea4c33717fd7/go.mod h1:ReWMS/LoVnOiRAdq9sNUC2NZnd1mZkMNB52QhpTRWjg=
|
||||||
github.com/matrix-org/util v0.0.0-20221111132719-399730281e66 h1:6z4KxomXSIGWqhHcfzExgkH3Z3UkIXry4ibJS4Aqz2Y=
|
github.com/matrix-org/util v0.0.0-20221111132719-399730281e66 h1:6z4KxomXSIGWqhHcfzExgkH3Z3UkIXry4ibJS4Aqz2Y=
|
||||||
|
@ -286,6 +290,8 @@ github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJm
|
||||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
|
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
|
||||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
|
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
|
||||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||||
|
github.com/oleiade/lane/v2 v2.0.0 h1:XW/ex/Inr+bPkLd3O240xrFOhUkTd4Wy176+Gv0E3Qw=
|
||||||
|
github.com/oleiade/lane/v2 v2.0.0/go.mod h1:i5FBPFAYSWCgLh58UkUGCChjcCzef/MI7PlQm2TKCeg=
|
||||||
github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU=
|
github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU=
|
||||||
github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM=
|
github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM=
|
||||||
github.com/onsi/gomega v1.27.8 h1:gegWiwZjBsf2DgiSbf5hpokZ98JVDMcWkUiigk6/KXc=
|
github.com/onsi/gomega v1.27.8 h1:gegWiwZjBsf2DgiSbf5hpokZ98JVDMcWkUiigk6/KXc=
|
||||||
|
@ -324,6 +330,8 @@ github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWN
|
||||||
github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||||
github.com/rs/zerolog v1.29.1 h1:cO+d60CHkknCbvzEWxP0S9K6KqyTjrCNUy1LdQLCGPc=
|
github.com/rs/zerolog v1.29.1 h1:cO+d60CHkknCbvzEWxP0S9K6KqyTjrCNUy1LdQLCGPc=
|
||||||
github.com/rs/zerolog v1.29.1/go.mod h1:Le6ESbR7hc+DP6Lt1THiV8CQSdkkNrd3R0XbEgp3ZBU=
|
github.com/rs/zerolog v1.29.1/go.mod h1:Le6ESbR7hc+DP6Lt1THiV8CQSdkkNrd3R0XbEgp3ZBU=
|
||||||
|
github.com/shoenig/test v1.11.0 h1:NoPa5GIoBwuqzIviCrnUJa+t5Xb4xi5Z+zODJnIDsEQ=
|
||||||
|
github.com/shoenig/test v1.11.0/go.mod h1:UxJ6u/x2v/TNs/LoLxBNJRV9DiwBBKYxXSyczsBHFoI=
|
||||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||||
|
|
|
@ -37,7 +37,7 @@ type CanonicalAlias struct {
|
||||||
// if they have not been specified.
|
// if they have not been specified.
|
||||||
// http://matrix.org/docs/spec/client_server/r0.2.0.html#m-room-power-levels
|
// http://matrix.org/docs/spec/client_server/r0.2.0.html#m-room-power-levels
|
||||||
// https://github.com/matrix-org/synapse/blob/v0.19.2/synapse/handlers/room.py#L294
|
// https://github.com/matrix-org/synapse/blob/v0.19.2/synapse/handlers/room.py#L294
|
||||||
func InitialPowerLevelsContent(roomCreator string) (c gomatrixserverlib.PowerLevelContent) {
|
func InitialPowerLevelsContent(roomVersion gomatrixserverlib.IRoomVersion, roomCreator string) (c gomatrixserverlib.PowerLevelContent) {
|
||||||
c.Defaults()
|
c.Defaults()
|
||||||
c.Events = map[string]int64{
|
c.Events = map[string]int64{
|
||||||
"m.room.name": 50,
|
"m.room.name": 50,
|
||||||
|
@ -49,7 +49,12 @@ func InitialPowerLevelsContent(roomCreator string) (c gomatrixserverlib.PowerLev
|
||||||
"m.room.encryption": 100,
|
"m.room.encryption": 100,
|
||||||
"m.room.server_acl": 100,
|
"m.room.server_acl": 100,
|
||||||
}
|
}
|
||||||
c.Users = map[string]int64{roomCreator: 100}
|
c.Users = map[string]int64{}
|
||||||
|
if roomVersion.PrivilegedCreators() {
|
||||||
|
c.Events["m.room.tombstone"] = 150
|
||||||
|
} else {
|
||||||
|
c.Users[roomCreator] = 100
|
||||||
|
}
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -67,16 +67,24 @@ func BuildEvent(
|
||||||
identity *fclient.SigningIdentity, evTime time.Time,
|
identity *fclient.SigningIdentity, evTime time.Time,
|
||||||
eventsNeeded *gomatrixserverlib.StateNeeded, queryRes *api.QueryLatestEventsAndStateResponse,
|
eventsNeeded *gomatrixserverlib.StateNeeded, queryRes *api.QueryLatestEventsAndStateResponse,
|
||||||
) (*types.HeaderedEvent, error) {
|
) (*types.HeaderedEvent, error) {
|
||||||
if err := addPrevEventsToEvent(proto, eventsNeeded, queryRes); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
verImpl, err := gomatrixserverlib.GetRoomVersion(queryRes.RoomVersion)
|
verImpl, err := gomatrixserverlib.GetRoomVersion(queryRes.RoomVersion)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
proto.Version = verImpl
|
||||||
|
if err = addPrevEventsToEvent(proto, eventsNeeded, queryRes); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
builder := verImpl.NewEventBuilderFromProtoEvent(proto)
|
builder := verImpl.NewEventBuilderFromProtoEvent(proto)
|
||||||
|
|
||||||
|
if verImpl.DomainlessRoomIDs() && builder.RoomID != "" && proto.Type == spec.MRoomCreate && proto.StateKey != nil && *proto.StateKey == "" {
|
||||||
|
return nil, gomatrixserverlib.EventValidationError{
|
||||||
|
Message: "cannot resend m.room.create event",
|
||||||
|
Code: 400,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
event, err := builder.Build(
|
event, err := builder.Build(
|
||||||
evTime, identity.ServerName, identity.KeyID,
|
evTime, identity.ServerName, identity.KeyID,
|
||||||
identity.PrivateKey,
|
identity.PrivateKey,
|
||||||
|
@ -136,8 +144,22 @@ func addPrevEventsToEvent(
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("eventsNeeded.AuthEventReferences: %w", err)
|
return fmt.Errorf("eventsNeeded.AuthEventReferences: %w", err)
|
||||||
}
|
}
|
||||||
|
var authEventIDs []string
|
||||||
|
if builder.Version.DomainlessRoomIDs() && len(builder.RoomID) > 0 {
|
||||||
|
// the room ID is the create event so we shouldn't set it in auth_events
|
||||||
|
authEventIDs = make([]string, 0, len(refs))
|
||||||
|
createEventID := fmt.Sprintf("$%s", builder.RoomID[1:])
|
||||||
|
for _, id := range refs {
|
||||||
|
if id == createEventID {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
authEventIDs = append(authEventIDs, id)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
authEventIDs = refs
|
||||||
|
}
|
||||||
|
|
||||||
builder.AuthEvents, builder.PrevEvents = truncateAuthAndPrevEvents(refs, queryRes.LatestEvents)
|
builder.AuthEvents, builder.PrevEvents = truncateAuthAndPrevEvents(authEventIDs, queryRes.LatestEvents)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -243,7 +243,7 @@ type ClientRoomserverAPI interface {
|
||||||
|
|
||||||
PerformCreateRoom(ctx context.Context, userID spec.UserID, roomID spec.RoomID, createRequest *PerformCreateRoomRequest) (string, *util.JSONResponse)
|
PerformCreateRoom(ctx context.Context, userID spec.UserID, roomID spec.RoomID, createRequest *PerformCreateRoomRequest) (string, *util.JSONResponse)
|
||||||
// PerformRoomUpgrade upgrades a room to a newer version
|
// PerformRoomUpgrade upgrades a room to a newer version
|
||||||
PerformRoomUpgrade(ctx context.Context, roomID string, userID spec.UserID, roomVersion gomatrixserverlib.RoomVersion) (newRoomID string, err error)
|
PerformRoomUpgrade(ctx context.Context, roomID string, userID spec.UserID, roomVersion gomatrixserverlib.RoomVersion, additionalCreators []string) (newRoomID string, err error)
|
||||||
PerformAdminEvacuateRoom(ctx context.Context, roomID string) (affected []string, err error)
|
PerformAdminEvacuateRoom(ctx context.Context, roomID string) (affected []string, err error)
|
||||||
PerformAdminEvacuateUser(ctx context.Context, userID string) (affected []string, err error)
|
PerformAdminEvacuateUser(ctx context.Context, userID string) (affected []string, err error)
|
||||||
PerformAdminPurgeRoom(ctx context.Context, roomID string) error
|
PerformAdminPurgeRoom(ctx context.Context, roomID string) error
|
||||||
|
|
|
@ -15,6 +15,9 @@ import (
|
||||||
"github.com/matrix-org/gomatrixserverlib/spec"
|
"github.com/matrix-org/gomatrixserverlib/spec"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// for detecting rejected events and returning 403 instead of 500ing
|
||||||
|
const InputWasRejected = "InputWasRejected"
|
||||||
|
|
||||||
type Kind int
|
type Kind int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -108,5 +111,5 @@ func (r *InputRoomEventsResponse) Err() error {
|
||||||
Message: r.ErrMsg,
|
Message: r.ErrMsg,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return fmt.Errorf("InputRoomEventsResponse: %s", r.ErrMsg)
|
return fmt.Errorf(r.ErrMsg)
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ type PerformCreateRoomRequest struct {
|
||||||
Topic string
|
Topic string
|
||||||
StatePreset string
|
StatePreset string
|
||||||
CreationContent json.RawMessage
|
CreationContent json.RawMessage
|
||||||
|
CreateEvent json.RawMessage
|
||||||
InitialState []gomatrixserverlib.FledglingEvent
|
InitialState []gomatrixserverlib.FledglingEvent
|
||||||
RoomAliasName string
|
RoomAliasName string
|
||||||
RoomVersion gomatrixserverlib.RoomVersion
|
RoomVersion gomatrixserverlib.RoomVersion
|
||||||
|
|
|
@ -8,6 +8,10 @@ package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/element-hq/dendrite/roomserver/types"
|
"github.com/element-hq/dendrite/roomserver/types"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
@ -216,3 +220,117 @@ func PopulatePublicRooms(ctx context.Context, roomIDs []string, rsAPI QueryBulkS
|
||||||
}
|
}
|
||||||
return chunk, nil
|
return chunk, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GenerateCreateContent(ctx context.Context, roomVer gomatrixserverlib.RoomVersion, senderID string, createContentJSON json.RawMessage, additionalCreators []string) (map[string]any, error) {
|
||||||
|
createContent := map[string]any{}
|
||||||
|
if len(createContentJSON) > 0 {
|
||||||
|
if err := json.Unmarshal(createContentJSON, &createContent); err != nil {
|
||||||
|
return nil, fmt.Errorf("invalid create content: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: Maybe, at some point, GMSL should return the events to create, so we can define the version
|
||||||
|
// entirely there.
|
||||||
|
switch roomVer {
|
||||||
|
case gomatrixserverlib.RoomVersionV11:
|
||||||
|
fallthrough
|
||||||
|
case gomatrixserverlib.RoomVersionV12:
|
||||||
|
// RoomVersionV11 removed the creator field from the create content: https://github.com/matrix-org/matrix-spec-proposals/pull/2175
|
||||||
|
default:
|
||||||
|
createContent["creator"] = senderID
|
||||||
|
}
|
||||||
|
createContent["room_version"] = string(roomVer)
|
||||||
|
|
||||||
|
verImpl := gomatrixserverlib.MustGetRoomVersion(roomVer)
|
||||||
|
|
||||||
|
if verImpl.PrivilegedCreators() {
|
||||||
|
var finalAdditionalCreators []string
|
||||||
|
creatorsSet := make(map[string]struct{})
|
||||||
|
var unverifiedCreators []string
|
||||||
|
unverifiedCreators = append(unverifiedCreators, additionalCreators...)
|
||||||
|
// they get added to any additional creators specified already
|
||||||
|
existingAdditionalCreators, ok := createContent["additional_creators"].([]any)
|
||||||
|
if ok {
|
||||||
|
for _, add := range existingAdditionalCreators {
|
||||||
|
addStr, ok := add.(string)
|
||||||
|
if ok {
|
||||||
|
unverifiedCreators = append(unverifiedCreators, addStr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, add := range unverifiedCreators {
|
||||||
|
if _, exists := creatorsSet[add]; exists {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
_, err := spec.NewUserID(add, true)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("invalid additional creator: '%s': %s", add, err)
|
||||||
|
}
|
||||||
|
finalAdditionalCreators = append(finalAdditionalCreators, add)
|
||||||
|
creatorsSet[add] = struct{}{}
|
||||||
|
}
|
||||||
|
if len(finalAdditionalCreators) > 0 {
|
||||||
|
createContent["additional_creators"] = finalAdditionalCreators
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return createContent, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GeneratePDU(
|
||||||
|
ctx context.Context, verImpl gomatrixserverlib.IRoomVersion, e gomatrixserverlib.FledglingEvent, authEvents *gomatrixserverlib.AuthEvents, depth int, prevEventID string,
|
||||||
|
identity *fclient.SigningIdentity, timestamp time.Time, senderID, roomID string, queryer QuerySenderIDAPI,
|
||||||
|
) (gomatrixserverlib.PDU, *util.JSONResponse) {
|
||||||
|
builder := verImpl.NewEventBuilderFromProtoEvent(&gomatrixserverlib.ProtoEvent{
|
||||||
|
SenderID: senderID,
|
||||||
|
RoomID: roomID,
|
||||||
|
Type: e.Type,
|
||||||
|
StateKey: &e.StateKey,
|
||||||
|
Depth: int64(depth),
|
||||||
|
})
|
||||||
|
err := builder.SetContent(e.Content)
|
||||||
|
if err != nil {
|
||||||
|
util.GetLogger(ctx).WithError(err).Error("builder.SetContent failed")
|
||||||
|
return nil, &util.JSONResponse{
|
||||||
|
Code: http.StatusInternalServerError,
|
||||||
|
JSON: spec.InternalServerError{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if prevEventID != "" {
|
||||||
|
builder.PrevEvents = []string{prevEventID}
|
||||||
|
}
|
||||||
|
var ev gomatrixserverlib.PDU
|
||||||
|
if err = builder.AddAuthEvents(authEvents); err != nil {
|
||||||
|
util.GetLogger(ctx).WithError(err).Error("AddAuthEvents failed")
|
||||||
|
return nil, &util.JSONResponse{
|
||||||
|
Code: http.StatusInternalServerError,
|
||||||
|
JSON: spec.InternalServerError{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ev, err = builder.Build(timestamp, identity.ServerName, identity.KeyID, identity.PrivateKey)
|
||||||
|
if err != nil {
|
||||||
|
util.GetLogger(ctx).WithError(err).Error("buildEvent failed")
|
||||||
|
return nil, &util.JSONResponse{
|
||||||
|
Code: http.StatusInternalServerError,
|
||||||
|
JSON: spec.InternalServerError{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = gomatrixserverlib.Allowed(ev, authEvents, func(roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) {
|
||||||
|
return queryer.QueryUserIDForSender(ctx, roomID, senderID)
|
||||||
|
}); err != nil {
|
||||||
|
util.GetLogger(ctx).WithError(err).Error("gomatrixserverlib.Allowed failed")
|
||||||
|
validationErr, ok := err.(*gomatrixserverlib.EventValidationError)
|
||||||
|
if ok {
|
||||||
|
return nil, &util.JSONResponse{
|
||||||
|
Code: validationErr.Code,
|
||||||
|
JSON: spec.Forbidden(err.Error()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, &util.JSONResponse{
|
||||||
|
Code: http.StatusForbidden,
|
||||||
|
JSON: spec.Forbidden(err.Error()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ev, nil
|
||||||
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"slices"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
asAPI "github.com/element-hq/dendrite/appservice/api"
|
asAPI "github.com/element-hq/dendrite/appservice/api"
|
||||||
|
@ -134,7 +135,7 @@ func (r *RoomserverInternalAPI) RemoveRoomAlias(ctx context.Context, senderID sp
|
||||||
}
|
}
|
||||||
|
|
||||||
if spec.SenderID(creatorID) != senderID {
|
if spec.SenderID(creatorID) != senderID {
|
||||||
var plEvent *types.HeaderedEvent
|
var createEvent, plEvent *types.HeaderedEvent
|
||||||
var pls *gomatrixserverlib.PowerLevelContent
|
var pls *gomatrixserverlib.PowerLevelContent
|
||||||
|
|
||||||
plEvent, err = r.DB.GetStateEvent(ctx, roomID, spec.MRoomPowerLevels, "")
|
plEvent, err = r.DB.GetStateEvent(ctx, roomID, spec.MRoomPowerLevels, "")
|
||||||
|
@ -147,7 +148,14 @@ func (r *RoomserverInternalAPI) RemoveRoomAlias(ctx context.Context, senderID sp
|
||||||
return true, false, fmt.Errorf("plEvent.PowerLevels: %w", err)
|
return true, false, fmt.Errorf("plEvent.PowerLevels: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if pls.UserLevel(senderID) < pls.EventLevel(spec.MRoomCanonicalAlias, true) {
|
createEvent, err = r.DB.GetStateEvent(ctx, roomID, spec.MRoomCreate, "")
|
||||||
|
if err != nil {
|
||||||
|
return true, false, fmt.Errorf("r.DB.GetStateEvent: %w", err)
|
||||||
|
}
|
||||||
|
isPrivilegedCreator := gomatrixserverlib.MustGetRoomVersion(createEvent.Version()).PrivilegedCreators() &&
|
||||||
|
slices.Contains(gomatrixserverlib.CreatorsFromCreateEvent(createEvent), string(senderID))
|
||||||
|
|
||||||
|
if !isPrivilegedCreator && pls.UserLevel(senderID) < pls.EventLevel(spec.MRoomCanonicalAlias, true) {
|
||||||
return true, false, nil
|
return true, false, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -330,6 +330,7 @@ func (w *worker) _next() {
|
||||||
// a string, because we might want to return that to the caller if
|
// a string, because we might want to return that to the caller if
|
||||||
// it was a synchronous request.
|
// it was a synchronous request.
|
||||||
var errString string
|
var errString string
|
||||||
|
wasRejected := false
|
||||||
if err = w.r.processRoomEvent(
|
if err = w.r.processRoomEvent(
|
||||||
w.r.ProcessContext.Context(),
|
w.r.ProcessContext.Context(),
|
||||||
spec.ServerName(msg.Header.Get("virtual_host")),
|
spec.ServerName(msg.Header.Get("virtual_host")),
|
||||||
|
@ -343,6 +344,7 @@ func (w *worker) _next() {
|
||||||
"event_id": inputRoomEvent.Event.EventID(),
|
"event_id": inputRoomEvent.Event.EventID(),
|
||||||
"type": inputRoomEvent.Event.Type(),
|
"type": inputRoomEvent.Event.Type(),
|
||||||
}).Warn("Roomserver rejected event")
|
}).Warn("Roomserver rejected event")
|
||||||
|
wasRejected = true
|
||||||
default:
|
default:
|
||||||
if !errors.Is(err, context.DeadlineExceeded) && !errors.Is(err, context.Canceled) {
|
if !errors.Is(err, context.DeadlineExceeded) && !errors.Is(err, context.Canceled) {
|
||||||
w.sentryHub.CaptureException(err)
|
w.sentryHub.CaptureException(err)
|
||||||
|
@ -364,6 +366,10 @@ func (w *worker) _next() {
|
||||||
_ = msg.AckSync()
|
_ = msg.AckSync()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if wasRejected {
|
||||||
|
errString = api.InputWasRejected
|
||||||
|
}
|
||||||
|
|
||||||
// If it was a synchronous input request then the "sync" field
|
// If it was a synchronous input request then the "sync" field
|
||||||
// will be present in the message. That means that someone is
|
// will be present in the message. That means that someone is
|
||||||
// waiting for a response. The temporary inbox name is present in
|
// waiting for a response. The temporary inbox name is present in
|
||||||
|
|
|
@ -39,6 +39,7 @@ type Creator struct {
|
||||||
// PerformCreateRoom handles all the steps necessary to create a new room.
|
// PerformCreateRoom handles all the steps necessary to create a new room.
|
||||||
// nolint: gocyclo
|
// nolint: gocyclo
|
||||||
func (c *Creator) PerformCreateRoom(ctx context.Context, userID spec.UserID, roomID spec.RoomID, createRequest *api.PerformCreateRoomRequest) (string, *util.JSONResponse) {
|
func (c *Creator) PerformCreateRoom(ctx context.Context, userID spec.UserID, roomID spec.RoomID, createRequest *api.PerformCreateRoomRequest) (string, *util.JSONResponse) {
|
||||||
|
// Make sure we know the room version
|
||||||
verImpl, err := gomatrixserverlib.GetRoomVersion(createRequest.RoomVersion)
|
verImpl, err := gomatrixserverlib.GetRoomVersion(createRequest.RoomVersion)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", &util.JSONResponse{
|
return "", &util.JSONResponse{
|
||||||
|
@ -47,17 +48,7 @@ func (c *Creator) PerformCreateRoom(ctx context.Context, userID spec.UserID, roo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
createContent := map[string]interface{}{}
|
// Allocate the room
|
||||||
if len(createRequest.CreationContent) > 0 {
|
|
||||||
if err = json.Unmarshal(createRequest.CreationContent, &createContent); err != nil {
|
|
||||||
util.GetLogger(ctx).WithError(err).Error("json.Unmarshal for creation_content failed")
|
|
||||||
return "", &util.JSONResponse{
|
|
||||||
Code: http.StatusBadRequest,
|
|
||||||
JSON: spec.BadJSON("invalid create content"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = c.DB.AssignRoomNID(ctx, roomID, createRequest.RoomVersion)
|
_, err = c.DB.AssignRoomNID(ctx, roomID, createRequest.RoomVersion)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
util.GetLogger(ctx).WithError(err).Error("failed to assign roomNID")
|
util.GetLogger(ctx).WithError(err).Error("failed to assign roomNID")
|
||||||
|
@ -67,6 +58,7 @@ func (c *Creator) PerformCreateRoom(ctx context.Context, userID spec.UserID, roo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Allocate the user
|
||||||
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
|
||||||
|
@ -83,17 +75,73 @@ func (c *Creator) PerformCreateRoom(ctx context.Context, userID spec.UserID, roo
|
||||||
senderID = spec.SenderID(userID.String())
|
senderID = spec.SenderID(userID.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Maybe, at some point, GMSL should return the events to create, so we can define the version
|
// get the signing identity
|
||||||
// entirely there.
|
identity, err := c.Cfg.Matrix.SigningIdentityFor(userID.Domain()) // we MUST use the server signing mxid_mapping
|
||||||
switch createRequest.RoomVersion {
|
if err != nil {
|
||||||
case gomatrixserverlib.RoomVersionV11:
|
logrus.WithError(err).WithField("domain", userID.Domain()).Error("unable to find signing identity for domain")
|
||||||
// RoomVersionV11 removed the creator field from the create content: https://github.com/matrix-org/matrix-spec-proposals/pull/2175
|
return "", &util.JSONResponse{
|
||||||
default:
|
Code: http.StatusInternalServerError,
|
||||||
createContent["creator"] = senderID
|
JSON: spec.InternalServerError{},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
createContent["room_version"] = createRequest.RoomVersion
|
// Make the create event if we need to
|
||||||
powerLevelContent := eventutil.InitialPowerLevelsContent(string(senderID))
|
var (
|
||||||
|
createEvent gomatrixserverlib.PDU
|
||||||
|
jsonErr *util.JSONResponse
|
||||||
|
)
|
||||||
|
authEvents, _ := gomatrixserverlib.NewAuthEvents(nil)
|
||||||
|
if createRequest.CreateEvent != nil {
|
||||||
|
createEvent, err = verImpl.NewEventFromTrustedJSON(createRequest.CreateEvent, false)
|
||||||
|
if err != nil {
|
||||||
|
util.GetLogger(ctx).WithError(err).Error("gomatrixserverlib.NewEventFromTrustedJSON failed to verify create event")
|
||||||
|
return "", &util.JSONResponse{
|
||||||
|
Code: http.StatusInternalServerError,
|
||||||
|
JSON: spec.InternalServerError{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err = authEvents.AddEvent(createEvent); err != nil {
|
||||||
|
util.GetLogger(ctx).WithError(err).Error("gomatrixserverlib.AuthEvents.AddEvent failed")
|
||||||
|
return "", &util.JSONResponse{
|
||||||
|
Code: http.StatusInternalServerError,
|
||||||
|
JSON: spec.InternalServerError{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var additionalCreators []string
|
||||||
|
if createRequest.StatePreset == spec.PresetTrustedPrivateChat {
|
||||||
|
additionalCreators = createRequest.InvitedUsers
|
||||||
|
}
|
||||||
|
createContent, contentErr := api.GenerateCreateContent(ctx, createRequest.RoomVersion, string(senderID), createRequest.CreationContent, additionalCreators)
|
||||||
|
if contentErr != nil {
|
||||||
|
util.GetLogger(ctx).WithError(contentErr).Error("GenerateCreateContent failed")
|
||||||
|
return "", &util.JSONResponse{
|
||||||
|
Code: http.StatusBadRequest,
|
||||||
|
JSON: spec.BadJSON("invalid create content"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
createEvent, jsonErr = api.GeneratePDU(
|
||||||
|
ctx, verImpl,
|
||||||
|
gomatrixserverlib.FledglingEvent{
|
||||||
|
Type: spec.MRoomCreate,
|
||||||
|
Content: createContent,
|
||||||
|
},
|
||||||
|
authEvents, 1, "", identity, createRequest.EventTime, string(senderID), roomID.String(), c.RSAPI,
|
||||||
|
)
|
||||||
|
if jsonErr != nil {
|
||||||
|
util.GetLogger(ctx).WithError(err).Error("Failed to make the create event")
|
||||||
|
return "", jsonErr
|
||||||
|
}
|
||||||
|
if err = authEvents.AddEvent(createEvent); err != nil {
|
||||||
|
util.GetLogger(ctx).WithError(err).Error("authEvents.AddEvent failed")
|
||||||
|
return "", &util.JSONResponse{
|
||||||
|
Code: http.StatusInternalServerError,
|
||||||
|
JSON: spec.InternalServerError{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
powerLevelContent := eventutil.InitialPowerLevelsContent(verImpl, string(senderID))
|
||||||
joinRuleContent := gomatrixserverlib.JoinRuleContent{
|
joinRuleContent := gomatrixserverlib.JoinRuleContent{
|
||||||
JoinRule: spec.Invite,
|
JoinRule: spec.Invite,
|
||||||
}
|
}
|
||||||
|
@ -122,19 +170,17 @@ func (c *Creator) PerformCreateRoom(ctx context.Context, userID spec.UserID, roo
|
||||||
case spec.PresetTrustedPrivateChat:
|
case spec.PresetTrustedPrivateChat:
|
||||||
joinRuleContent.JoinRule = spec.Invite
|
joinRuleContent.JoinRule = spec.Invite
|
||||||
historyVisibilityContent.HistoryVisibility = historyVisibilityShared
|
historyVisibilityContent.HistoryVisibility = historyVisibilityShared
|
||||||
|
if !verImpl.PrivilegedCreators() {
|
||||||
for _, invitee := range createRequest.InvitedUsers {
|
for _, invitee := range createRequest.InvitedUsers {
|
||||||
powerLevelContent.Users[invitee] = 100
|
powerLevelContent.Users[invitee] = 100
|
||||||
}
|
}
|
||||||
|
}
|
||||||
guestsCanJoin = true
|
guestsCanJoin = true
|
||||||
case spec.PresetPublicChat:
|
case spec.PresetPublicChat:
|
||||||
joinRuleContent.JoinRule = spec.Public
|
joinRuleContent.JoinRule = spec.Public
|
||||||
historyVisibilityContent.HistoryVisibility = historyVisibilityShared
|
historyVisibilityContent.HistoryVisibility = historyVisibilityShared
|
||||||
}
|
}
|
||||||
|
|
||||||
createEvent := gomatrixserverlib.FledglingEvent{
|
|
||||||
Type: spec.MRoomCreate,
|
|
||||||
Content: createContent,
|
|
||||||
}
|
|
||||||
powerLevelEvent := gomatrixserverlib.FledglingEvent{
|
powerLevelEvent := gomatrixserverlib.FledglingEvent{
|
||||||
Type: spec.MRoomPowerLevels,
|
Type: spec.MRoomPowerLevels,
|
||||||
Content: powerLevelContent,
|
Content: powerLevelContent,
|
||||||
|
@ -158,16 +204,6 @@ func (c *Creator) PerformCreateRoom(ctx context.Context, userID spec.UserID, roo
|
||||||
AvatarURL: createRequest.UserAvatarURL,
|
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 we are creating a room with pseudo IDs, create and sign the MXIDMapping
|
||||||
if createRequest.RoomVersion == gomatrixserverlib.RoomVersionPseudoIDs {
|
if createRequest.RoomVersion == gomatrixserverlib.RoomVersionPseudoIDs {
|
||||||
var pseudoIDKey ed25519.PrivateKey
|
var pseudoIDKey ed25519.PrivateKey
|
||||||
|
@ -279,7 +315,6 @@ func (c *Creator) PerformCreateRoom(ctx context.Context, userID spec.UserID, roo
|
||||||
switch createRequest.InitialState[i].Type {
|
switch createRequest.InitialState[i].Type {
|
||||||
case spec.MRoomCreate:
|
case spec.MRoomCreate:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
case spec.MRoomPowerLevels:
|
case spec.MRoomPowerLevels:
|
||||||
powerLevelEvent = createRequest.InitialState[i]
|
powerLevelEvent = createRequest.InitialState[i]
|
||||||
|
|
||||||
|
@ -321,7 +356,8 @@ func (c *Creator) PerformCreateRoom(ctx context.Context, userID spec.UserID, roo
|
||||||
// harder to reason about, hence sticking to a strict static ordering.
|
// harder to reason about, hence sticking to a strict static ordering.
|
||||||
// TODO: Synapse has txn/token ID on each event. Do we need to do this here?
|
// TODO: Synapse has txn/token ID on each event. Do we need to do this here?
|
||||||
eventsToMake := []gomatrixserverlib.FledglingEvent{
|
eventsToMake := []gomatrixserverlib.FledglingEvent{
|
||||||
createEvent, membershipEvent, powerLevelEvent, joinRuleEvent, historyVisibilityEvent,
|
// we made the create event already hence it isn't here.
|
||||||
|
membershipEvent, powerLevelEvent, joinRuleEvent, historyVisibilityEvent,
|
||||||
}
|
}
|
||||||
if guestAccessEvent != nil {
|
if guestAccessEvent != nil {
|
||||||
eventsToMake = append(eventsToMake, *guestAccessEvent)
|
eventsToMake = append(eventsToMake, *guestAccessEvent)
|
||||||
|
@ -342,61 +378,19 @@ func (c *Creator) PerformCreateRoom(ctx context.Context, userID spec.UserID, roo
|
||||||
// TODO: invite events
|
// TODO: invite events
|
||||||
// TODO: 3pid invite events
|
// TODO: 3pid invite events
|
||||||
|
|
||||||
var builtEvents []*types.HeaderedEvent
|
builtEvents := []*types.HeaderedEvent{
|
||||||
authEvents, _ := gomatrixserverlib.NewAuthEvents(nil)
|
{PDU: createEvent},
|
||||||
if err != nil {
|
|
||||||
util.GetLogger(ctx).WithError(err).Error("rsapi.QuerySenderIDForUser failed")
|
|
||||||
return "", &util.JSONResponse{
|
|
||||||
Code: http.StatusInternalServerError,
|
|
||||||
JSON: spec.InternalServerError{},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
for i, e := range eventsToMake {
|
for i, e := range eventsToMake {
|
||||||
depth := i + 1 // depth starts at 1
|
depth := i + 2 // depth starts at 2 since we made the create event already
|
||||||
|
|
||||||
builder := verImpl.NewEventBuilderFromProtoEvent(&gomatrixserverlib.ProtoEvent{
|
ev, jsonErr := api.GeneratePDU(
|
||||||
SenderID: string(senderID),
|
ctx, verImpl, e,
|
||||||
RoomID: roomID.String(),
|
authEvents, depth, builtEvents[len(builtEvents)-1].EventID(),
|
||||||
Type: e.Type,
|
identity, createRequest.EventTime, string(senderID), roomID.String(), c.RSAPI,
|
||||||
StateKey: &e.StateKey,
|
)
|
||||||
Depth: int64(depth),
|
if jsonErr != nil {
|
||||||
})
|
return "", jsonErr
|
||||||
err = builder.SetContent(e.Content)
|
|
||||||
if err != nil {
|
|
||||||
util.GetLogger(ctx).WithError(err).Error("builder.SetContent failed")
|
|
||||||
return "", &util.JSONResponse{
|
|
||||||
Code: http.StatusInternalServerError,
|
|
||||||
JSON: spec.InternalServerError{},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if i > 0 {
|
|
||||||
builder.PrevEvents = []string{builtEvents[i-1].EventID()}
|
|
||||||
}
|
|
||||||
var ev gomatrixserverlib.PDU
|
|
||||||
if err = builder.AddAuthEvents(authEvents); err != nil {
|
|
||||||
util.GetLogger(ctx).WithError(err).Error("AddAuthEvents failed")
|
|
||||||
return "", &util.JSONResponse{
|
|
||||||
Code: http.StatusInternalServerError,
|
|
||||||
JSON: spec.InternalServerError{},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ev, err = builder.Build(createRequest.EventTime, identity.ServerName, identity.KeyID, identity.PrivateKey)
|
|
||||||
if err != nil {
|
|
||||||
util.GetLogger(ctx).WithError(err).Error("buildEvent failed")
|
|
||||||
return "", &util.JSONResponse{
|
|
||||||
Code: http.StatusInternalServerError,
|
|
||||||
JSON: spec.InternalServerError{},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = gomatrixserverlib.Allowed(ev, authEvents, func(roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) {
|
|
||||||
return c.RSAPI.QueryUserIDForSender(ctx, roomID, senderID)
|
|
||||||
}); err != nil {
|
|
||||||
util.GetLogger(ctx).WithError(err).Error("gomatrixserverlib.Allowed failed")
|
|
||||||
return "", &util.JSONResponse{
|
|
||||||
Code: http.StatusInternalServerError,
|
|
||||||
JSON: spec.InternalServerError{},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the event to the list of auth events
|
// Add the event to the list of auth events
|
||||||
|
|
|
@ -156,19 +156,11 @@ func (r *Joiner) performJoinRoomByID(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the domain part of the room ID.
|
|
||||||
roomID, err := spec.NewRoomID(req.RoomIDOrAlias)
|
roomID, err := spec.NewRoomID(req.RoomIDOrAlias)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", "", rsAPI.ErrInvalidID{Err: fmt.Errorf("room ID %q is invalid: %w", req.RoomIDOrAlias, err)}
|
return "", "", rsAPI.ErrInvalidID{Err: fmt.Errorf("room ID %q is invalid: %w", req.RoomIDOrAlias, err)}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the server name in the room ID isn't ours then it's a
|
|
||||||
// possible candidate for finding the room via federation. Add
|
|
||||||
// it to the list of servers to try.
|
|
||||||
if !r.Cfg.Matrix.IsLocalServerName(roomID.Domain()) {
|
|
||||||
req.ServerNames = append(req.ServerNames, roomID.Domain())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Force a federated join if we aren't in the room and we've been
|
// Force a federated join if we aren't in the room and we've been
|
||||||
// given some server names to try joining by.
|
// given some server names to try joining by.
|
||||||
inRoomReq := &rsAPI.QueryServerJoinedToRoomRequest{
|
inRoomReq := &rsAPI.QueryServerJoinedToRoomRequest{
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"slices"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/element-hq/dendrite/internal/eventutil"
|
"github.com/element-hq/dendrite/internal/eventutil"
|
||||||
|
@ -30,14 +31,15 @@ type Upgrader struct {
|
||||||
// PerformRoomUpgrade upgrades a room from one version to another
|
// PerformRoomUpgrade upgrades a room from one version to another
|
||||||
func (r *Upgrader) PerformRoomUpgrade(
|
func (r *Upgrader) PerformRoomUpgrade(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
roomID string, userID spec.UserID, roomVersion gomatrixserverlib.RoomVersion,
|
roomID string, userID spec.UserID, roomVersion gomatrixserverlib.RoomVersion, additionalCreators []string,
|
||||||
) (newRoomID string, err error) {
|
) (newRoomID string, err error) {
|
||||||
return r.performRoomUpgrade(ctx, roomID, userID, roomVersion)
|
return r.performRoomUpgrade(ctx, roomID, userID, roomVersion, additionalCreators)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// nolint:gocyclo
|
||||||
func (r *Upgrader) performRoomUpgrade(
|
func (r *Upgrader) performRoomUpgrade(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
roomID string, userID spec.UserID, roomVersion gomatrixserverlib.RoomVersion,
|
roomID string, userID spec.UserID, roomVersion gomatrixserverlib.RoomVersion, additionalCreators []string,
|
||||||
) (string, error) {
|
) (string, error) {
|
||||||
evTime := time.Now()
|
evTime := time.Now()
|
||||||
|
|
||||||
|
@ -64,35 +66,110 @@ func (r *Upgrader) performRoomUpgrade(
|
||||||
return "", api.ErrNotAllowed{Err: fmt.Errorf("You don't have permission to upgrade the room, power level too low.")}
|
return "", api.ErrNotAllowed{Err: fmt.Errorf("You don't have permission to upgrade the room, power level too low.")}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO (#267): Check room ID doesn't clash with an existing one, and we
|
|
||||||
// probably shouldn't be using pseudo-random strings, maybe GUIDs?
|
|
||||||
newRoomID := fmt.Sprintf("!%s:%s", util.RandomString(16), userID.Domain())
|
|
||||||
|
|
||||||
// Get the existing room state for the old room.
|
// Get the existing room state for the old room.
|
||||||
oldRoomReq := &api.QueryLatestEventsAndStateRequest{
|
oldRoomReq := &api.QueryLatestEventsAndStateRequest{
|
||||||
RoomID: roomID,
|
RoomID: roomID,
|
||||||
}
|
}
|
||||||
oldRoomRes := &api.QueryLatestEventsAndStateResponse{}
|
oldRoomRes := &api.QueryLatestEventsAndStateResponse{}
|
||||||
if err := r.URSAPI.QueryLatestEventsAndState(ctx, oldRoomReq, oldRoomRes); err != nil {
|
if err = r.URSAPI.QueryLatestEventsAndState(ctx, oldRoomReq, oldRoomRes); err != nil {
|
||||||
return "", fmt.Errorf("Failed to get latest state: %s", err)
|
return "", fmt.Errorf("Failed to get latest state: %s", err)
|
||||||
}
|
}
|
||||||
|
var oldCreateEvent *types.HeaderedEvent
|
||||||
|
for _, ev := range oldRoomRes.StateEvents {
|
||||||
|
if ev.Type() == spec.MRoomCreate && ev.StateKeyEquals("") {
|
||||||
|
oldCreateEvent = ev
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make the create event and calculate the new room ID.
|
||||||
|
var newRoomID string
|
||||||
|
newRoomVerImpl := gomatrixserverlib.MustGetRoomVersion(roomVersion)
|
||||||
|
var tombstoneEvent *types.HeaderedEvent
|
||||||
|
var newCreateEvent gomatrixserverlib.PDU
|
||||||
|
var pErr error
|
||||||
|
if !newRoomVerImpl.DomainlessRoomIDs() {
|
||||||
|
// TODO (#267): Check room ID doesn't clash with an existing one, and we
|
||||||
|
// probably shouldn't be using pseudo-random strings, maybe GUIDs?
|
||||||
|
newRoomID = fmt.Sprintf("!%s:%s", util.RandomString(16), userID.Domain())
|
||||||
|
|
||||||
// Make the tombstone event
|
// Make the tombstone event
|
||||||
tombstoneEvent, pErr := r.makeTombstoneEvent(ctx, evTime, *senderID, userID.Domain(), roomID, newRoomID)
|
tombstoneEvent, pErr = r.makeTombstoneEvent(ctx, evTime, *senderID, userID.Domain(), roomID, newRoomID)
|
||||||
if pErr != nil {
|
if pErr != nil {
|
||||||
return "", pErr
|
return "", pErr
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
content := struct {
|
||||||
|
Federate *bool `json:"m.federate,omitempty"`
|
||||||
|
Type string `json:"type,omitempty"`
|
||||||
|
Predecessor struct {
|
||||||
|
RoomID string `json:"room_id"`
|
||||||
|
EventID string `json:"event_id,omitempty"`
|
||||||
|
} `json:"predecessor"`
|
||||||
|
}{}
|
||||||
|
// keep existing values in old room e.g type/m.federate
|
||||||
|
if err = json.Unmarshal(oldCreateEvent.Content(), &content); err != nil {
|
||||||
|
return "", fmt.Errorf("failed to copy old create event content to new create event: %s", err)
|
||||||
|
}
|
||||||
|
content.Predecessor.RoomID = roomID
|
||||||
|
content.Predecessor.EventID = ""
|
||||||
|
if tombstoneEvent != nil {
|
||||||
|
content.Predecessor.EventID = tombstoneEvent.EventID()
|
||||||
|
}
|
||||||
|
contentJSON, err := json.Marshal(content)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("Failed to make content for new create event: %s", err)
|
||||||
|
}
|
||||||
|
// make the create event up-front so the roomserver can calculate the room NID to store.
|
||||||
|
createContent, err := api.GenerateCreateContent(ctx, roomVersion, userID.String(), contentJSON, additionalCreators)
|
||||||
|
if err != nil {
|
||||||
|
util.GetLogger(ctx).WithError(err).Error("GenerateCreateContent failed")
|
||||||
|
return "", fmt.Errorf("failed to GenerateCreateContent")
|
||||||
|
}
|
||||||
|
authEvents, _ := gomatrixserverlib.NewAuthEvents(nil)
|
||||||
|
identity, err := r.Cfg.Matrix.SigningIdentityFor(userID.Domain())
|
||||||
|
if err != nil {
|
||||||
|
util.GetLogger(ctx).WithError(err).Error("Failed to get signing identity")
|
||||||
|
return "", fmt.Errorf("No SigningIdentityFor domain %s", userID.Domain())
|
||||||
|
}
|
||||||
|
createEvent, jsonErr := api.GeneratePDU(
|
||||||
|
ctx, gomatrixserverlib.MustGetRoomVersion(roomVersion),
|
||||||
|
gomatrixserverlib.FledglingEvent{
|
||||||
|
Type: spec.MRoomCreate,
|
||||||
|
Content: createContent,
|
||||||
|
},
|
||||||
|
// newRoomID will be empty for domainless rooms
|
||||||
|
authEvents, 1, "", identity, evTime, userID.String(), newRoomID, r.URSAPI,
|
||||||
|
)
|
||||||
|
if jsonErr != nil {
|
||||||
|
util.GetLogger(ctx).Error("Failed to make the create event")
|
||||||
|
return "", fmt.Errorf("failed to create new create event PDU")
|
||||||
|
}
|
||||||
|
newCreateEvent = createEvent
|
||||||
|
if newRoomVerImpl.DomainlessRoomIDs() {
|
||||||
|
newRoomID = newCreateEvent.RoomID().String()
|
||||||
|
}
|
||||||
|
|
||||||
|
if tombstoneEvent == nil {
|
||||||
|
// Make the tombstone event
|
||||||
|
tombstoneEvent, pErr = r.makeTombstoneEvent(ctx, evTime, *senderID, userID.Domain(), roomID, newRoomID)
|
||||||
|
if pErr != nil {
|
||||||
|
return "", pErr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
creators := gomatrixserverlib.CreatorsFromCreateEvent(newCreateEvent)
|
||||||
|
|
||||||
// Generate the initial events we need to send into the new room. This includes copied state events and bans
|
// Generate the initial events we need to send into the new room. This includes copied state events and bans
|
||||||
// as well as the power level events needed to set up the room
|
// as well as the power level events needed to set up the room
|
||||||
eventsToMake, pErr := r.generateInitialEvents(ctx, oldRoomRes, *senderID, roomID, roomVersion, tombstoneEvent)
|
eventsToMake, pErr := r.generateInitialEvents(ctx, oldRoomRes, *senderID, roomID, roomVersion, creators)
|
||||||
if pErr != nil {
|
if pErr != nil {
|
||||||
return "", pErr
|
return "", pErr
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send the setup events to the new room
|
// Send the setup events to the new room
|
||||||
if pErr = r.sendInitialEvents(ctx, evTime, *senderID, userID.Domain(), newRoomID, roomVersion, eventsToMake); pErr != nil {
|
if pErr = r.sendInitialEvents(ctx, evTime, *senderID, userID.Domain(), newRoomID, roomVersion, newCreateEvent, eventsToMake); pErr != nil {
|
||||||
return "", pErr
|
return "", fmt.Errorf("sendInitialEvents: %s", pErr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5. Send the tombstone event to the old room
|
// 5. Send the tombstone event to the old room
|
||||||
|
@ -296,13 +373,25 @@ func (r *Upgrader) userIsAuthorized(ctx context.Context, senderID spec.SenderID,
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
createEvent := api.GetStateEvent(ctx, r.URSAPI, roomID, gomatrixserverlib.StateKeyTuple{
|
||||||
|
EventType: spec.MRoomCreate,
|
||||||
|
StateKey: "",
|
||||||
|
})
|
||||||
|
if gomatrixserverlib.MustGetRoomVersion(createEvent.Version()).PrivilegedCreators() &&
|
||||||
|
slices.Contains(gomatrixserverlib.CreatorsFromCreateEvent(createEvent), string(senderID)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
// Check for power level required to send tombstone event (marks the current room as obsolete),
|
// Check for power level required to send tombstone event (marks the current room as obsolete),
|
||||||
// if not found, use the StateDefault power level
|
// if not found, use the StateDefault power level
|
||||||
return pl.UserLevel(senderID) >= pl.EventLevel("m.room.tombstone", true)
|
return pl.UserLevel(senderID) >= pl.EventLevel("m.room.tombstone", true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return the events to create AFTER the new create event
|
||||||
// nolint:gocyclo
|
// nolint:gocyclo
|
||||||
func (r *Upgrader) generateInitialEvents(ctx context.Context, oldRoom *api.QueryLatestEventsAndStateResponse, senderID spec.SenderID, roomID string, newVersion gomatrixserverlib.RoomVersion, tombstoneEvent *types.HeaderedEvent) ([]gomatrixserverlib.FledglingEvent, error) {
|
func (r *Upgrader) generateInitialEvents(
|
||||||
|
ctx context.Context, oldRoom *api.QueryLatestEventsAndStateResponse, senderID spec.SenderID, _ string, newVersion gomatrixserverlib.RoomVersion,
|
||||||
|
creators []string) ([]gomatrixserverlib.FledglingEvent, error) {
|
||||||
|
|
||||||
state := make(map[gomatrixserverlib.StateKeyTuple]*types.HeaderedEvent, len(oldRoom.StateEvents))
|
state := make(map[gomatrixserverlib.StateKeyTuple]*types.HeaderedEvent, len(oldRoom.StateEvents))
|
||||||
for _, event := range oldRoom.StateEvents {
|
for _, event := range oldRoom.StateEvents {
|
||||||
if event.StateKey() == nil {
|
if event.StateKey() == nil {
|
||||||
|
@ -350,37 +439,10 @@ func (r *Upgrader) generateInitialEvents(ctx context.Context, oldRoom *api.Query
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
oldCreateEvent := state[gomatrixserverlib.StateKeyTuple{EventType: spec.MRoomCreate, StateKey: ""}]
|
|
||||||
oldMembershipEvent := state[gomatrixserverlib.StateKeyTuple{EventType: spec.MRoomMember, StateKey: string(senderID)}]
|
oldMembershipEvent := state[gomatrixserverlib.StateKeyTuple{EventType: spec.MRoomMember, StateKey: string(senderID)}]
|
||||||
oldPowerLevelsEvent := state[gomatrixserverlib.StateKeyTuple{EventType: spec.MRoomPowerLevels, StateKey: ""}]
|
oldPowerLevelsEvent := state[gomatrixserverlib.StateKeyTuple{EventType: spec.MRoomPowerLevels, StateKey: ""}]
|
||||||
oldJoinRulesEvent := state[gomatrixserverlib.StateKeyTuple{EventType: spec.MRoomJoinRules, StateKey: ""}]
|
oldJoinRulesEvent := state[gomatrixserverlib.StateKeyTuple{EventType: spec.MRoomJoinRules, StateKey: ""}]
|
||||||
|
|
||||||
// Create the new room create event. Using a map here instead of CreateContent
|
|
||||||
// means that we preserve any other interesting fields that might be present
|
|
||||||
// in the create event (such as for the room types MSC).
|
|
||||||
newCreateContent := map[string]interface{}{}
|
|
||||||
_ = json.Unmarshal(oldCreateEvent.Content(), &newCreateContent)
|
|
||||||
|
|
||||||
switch newVersion {
|
|
||||||
case gomatrixserverlib.RoomVersionV11:
|
|
||||||
// RoomVersionV11 removed the creator field from the create content: https://github.com/matrix-org/matrix-spec-proposals/pull/2175
|
|
||||||
// So if we are upgrading from pre v11, we need to remove the field.
|
|
||||||
delete(newCreateContent, "creator")
|
|
||||||
default:
|
|
||||||
newCreateContent["creator"] = senderID
|
|
||||||
}
|
|
||||||
|
|
||||||
newCreateContent["room_version"] = newVersion
|
|
||||||
newCreateContent["predecessor"] = gomatrixserverlib.PreviousRoom{
|
|
||||||
EventID: tombstoneEvent.EventID(),
|
|
||||||
RoomID: roomID,
|
|
||||||
}
|
|
||||||
newCreateEvent := gomatrixserverlib.FledglingEvent{
|
|
||||||
Type: spec.MRoomCreate,
|
|
||||||
StateKey: "",
|
|
||||||
Content: newCreateContent,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now create the new membership event. Same rules apply as above, so
|
// Now create the new membership event. Same rules apply as above, so
|
||||||
// that we preserve fields we don't otherwise know about. We'll always
|
// that we preserve fields we don't otherwise know about. We'll always
|
||||||
// set the membership to join though, because that is necessary to auth
|
// set the membership to join though, because that is necessary to auth
|
||||||
|
@ -405,7 +467,9 @@ func (r *Upgrader) generateInitialEvents(ctx context.Context, oldRoom *api.Query
|
||||||
return nil, fmt.Errorf("Power level event content was invalid")
|
return nil, fmt.Errorf("Power level event content was invalid")
|
||||||
}
|
}
|
||||||
|
|
||||||
tempPowerLevelsEvent, powerLevelsOverridden := createTemporaryPowerLevels(powerLevelContent, senderID)
|
verImpl := gomatrixserverlib.MustGetRoomVersion(newVersion)
|
||||||
|
|
||||||
|
tempPowerLevelsEvent, powerLevelsOverridden := createTemporaryPowerLevels(verImpl, powerLevelContent, senderID, creators)
|
||||||
|
|
||||||
// Now do the join rules event, same as the create and membership
|
// Now do the join rules event, same as the create and membership
|
||||||
// events. We'll set a sane default of "invite" so that if the
|
// events. We'll set a sane default of "invite" so that if the
|
||||||
|
@ -423,7 +487,7 @@ func (r *Upgrader) generateInitialEvents(ctx context.Context, oldRoom *api.Query
|
||||||
|
|
||||||
eventsToMake := make([]gomatrixserverlib.FledglingEvent, 0, len(state))
|
eventsToMake := make([]gomatrixserverlib.FledglingEvent, 0, len(state))
|
||||||
eventsToMake = append(
|
eventsToMake = append(
|
||||||
eventsToMake, newCreateEvent, newMembershipEvent,
|
eventsToMake, newMembershipEvent,
|
||||||
tempPowerLevelsEvent, newJoinRulesEvent,
|
tempPowerLevelsEvent, newJoinRulesEvent,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -467,12 +531,16 @@ func (r *Upgrader) generateInitialEvents(ctx context.Context, oldRoom *api.Query
|
||||||
return eventsToMake, nil
|
return eventsToMake, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Upgrader) sendInitialEvents(ctx context.Context, evTime time.Time, senderID spec.SenderID, userDomain spec.ServerName, newRoomID string, newVersion gomatrixserverlib.RoomVersion, eventsToMake []gomatrixserverlib.FledglingEvent) error {
|
func (r *Upgrader) sendInitialEvents(
|
||||||
|
ctx context.Context, evTime time.Time, senderID spec.SenderID, userDomain spec.ServerName, newRoomID string,
|
||||||
|
newVersion gomatrixserverlib.RoomVersion, newCreateEvent gomatrixserverlib.PDU, eventsToMake []gomatrixserverlib.FledglingEvent) error {
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
var builtEvents []*types.HeaderedEvent
|
var builtEvents []*types.HeaderedEvent
|
||||||
authEvents, _ := gomatrixserverlib.NewAuthEvents(nil)
|
builtEvents = append(builtEvents, &types.HeaderedEvent{PDU: newCreateEvent})
|
||||||
|
authEvents, _ := gomatrixserverlib.NewAuthEvents([]gomatrixserverlib.PDU{newCreateEvent})
|
||||||
for i, e := range eventsToMake {
|
for i, e := range eventsToMake {
|
||||||
depth := i + 1 // depth starts at 1
|
depth := i + 2 // depth starts at 2 since we made the create event already.
|
||||||
|
|
||||||
proto := gomatrixserverlib.ProtoEvent{
|
proto := gomatrixserverlib.ProtoEvent{
|
||||||
SenderID: string(senderID),
|
SenderID: string(senderID),
|
||||||
|
@ -485,9 +553,7 @@ func (r *Upgrader) sendInitialEvents(ctx context.Context, evTime time.Time, send
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to set content of new %q event: %w", proto.Type, err)
|
return fmt.Errorf("failed to set content of new %q event: %w", proto.Type, err)
|
||||||
}
|
}
|
||||||
if i > 0 {
|
proto.PrevEvents = []string{builtEvents[i].EventID()}
|
||||||
proto.PrevEvents = []string{builtEvents[i-1].EventID()}
|
|
||||||
}
|
|
||||||
|
|
||||||
var verImpl gomatrixserverlib.IRoomVersion
|
var verImpl gomatrixserverlib.IRoomVersion
|
||||||
verImpl, err = gomatrixserverlib.GetRoomVersion(newVersion)
|
verImpl, err = gomatrixserverlib.GetRoomVersion(newVersion)
|
||||||
|
@ -503,13 +569,12 @@ func (r *Upgrader) sendInitialEvents(ctx context.Context, evTime time.Time, send
|
||||||
event, err = builder.Build(evTime, userDomain, r.Cfg.Matrix.KeyID, r.Cfg.Matrix.PrivateKey)
|
event, err = builder.Build(evTime, userDomain, r.Cfg.Matrix.KeyID, r.Cfg.Matrix.PrivateKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to build new %q event: %w", builder.Type, err)
|
return fmt.Errorf("failed to build new %q event: %w", builder.Type, err)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = gomatrixserverlib.Allowed(event, authEvents, func(roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) {
|
if err = gomatrixserverlib.Allowed(event, authEvents, func(roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) {
|
||||||
return r.URSAPI.QueryUserIDForSender(ctx, roomID, senderID)
|
return r.URSAPI.QueryUserIDForSender(ctx, roomID, senderID)
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return fmt.Errorf("Failed to auth new %q event: %w", builder.Type, err)
|
return fmt.Errorf("Failed to auth new initial %q event: %w", builder.Type, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the event to the list of auth events
|
// Add the event to the list of auth events
|
||||||
|
@ -599,7 +664,7 @@ func (r *Upgrader) makeHeaderedEvent(ctx context.Context, evTime time.Time, send
|
||||||
return headeredEvent, nil
|
return headeredEvent, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func createTemporaryPowerLevels(powerLevelContent *gomatrixserverlib.PowerLevelContent, senderID spec.SenderID) (gomatrixserverlib.FledglingEvent, bool) {
|
func createTemporaryPowerLevels(roomVersion gomatrixserverlib.IRoomVersion, powerLevelContent *gomatrixserverlib.PowerLevelContent, senderID spec.SenderID, creators []string) (gomatrixserverlib.FledglingEvent, bool) {
|
||||||
// Work out what power level we need in order to be able to send events
|
// Work out what power level we need in order to be able to send events
|
||||||
// of all types into the room.
|
// of all types into the room.
|
||||||
neededPowerLevel := powerLevelContent.StateDefault
|
neededPowerLevel := powerLevelContent.StateDefault
|
||||||
|
@ -619,15 +684,21 @@ func createTemporaryPowerLevels(powerLevelContent *gomatrixserverlib.PowerLevelC
|
||||||
// so that we can modify them without modifying the original.
|
// so that we can modify them without modifying the original.
|
||||||
tempPowerLevelContent.Users = make(map[string]int64, len(powerLevelContent.Users))
|
tempPowerLevelContent.Users = make(map[string]int64, len(powerLevelContent.Users))
|
||||||
for key, value := range powerLevelContent.Users {
|
for key, value := range powerLevelContent.Users {
|
||||||
|
if roomVersion.PrivilegedCreators() && slices.Contains(creators, key) {
|
||||||
|
continue // don't set the creator in the users map!
|
||||||
|
}
|
||||||
tempPowerLevelContent.Users[key] = value
|
tempPowerLevelContent.Users[key] = value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// the upgrader will be the creator so is guaranteed to have enough perms to do this.
|
||||||
|
if !roomVersion.PrivilegedCreators() {
|
||||||
// If the user who is upgrading the room doesn't already have sufficient
|
// If the user who is upgrading the room doesn't already have sufficient
|
||||||
// power, then elevate their power levels.
|
// power, then elevate their power levels.
|
||||||
if tempPowerLevelContent.UserLevel(senderID) < neededPowerLevel {
|
if tempPowerLevelContent.UserLevel(senderID) < neededPowerLevel {
|
||||||
tempPowerLevelContent.Users[string(senderID)] = neededPowerLevel
|
tempPowerLevelContent.Users[string(senderID)] = neededPowerLevel
|
||||||
powerLevelsOverridden = true
|
powerLevelsOverridden = true
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Then return the temporary power levels event.
|
// Then return the temporary power levels event.
|
||||||
return gomatrixserverlib.FledglingEvent{
|
return gomatrixserverlib.FledglingEvent{
|
||||||
|
|
|
@ -1075,7 +1075,7 @@ func TestUpgrade(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("upgrade userID is invalid")
|
t.Fatalf("upgrade userID is invalid")
|
||||||
}
|
}
|
||||||
newRoomID, err := rsAPI.PerformRoomUpgrade(processCtx.Context(), roomID, *userID, rsAPI.DefaultRoomVersion())
|
newRoomID, err := rsAPI.PerformRoomUpgrade(processCtx.Context(), roomID, *userID, rsAPI.DefaultRoomVersion(), nil)
|
||||||
if err != nil && tc.wantNewRoom {
|
if err != nil && tc.wantNewRoom {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -888,6 +888,8 @@ func (v *StateResolution) resolveConflicts(
|
||||||
case gomatrixserverlib.StateResV1:
|
case gomatrixserverlib.StateResV1:
|
||||||
return v.resolveConflictsV1(ctx, notConflicted, conflicted)
|
return v.resolveConflictsV1(ctx, notConflicted, conflicted)
|
||||||
case gomatrixserverlib.StateResV2:
|
case gomatrixserverlib.StateResV2:
|
||||||
|
fallthrough
|
||||||
|
case gomatrixserverlib.StateResV2_1:
|
||||||
return v.resolveConflictsV2(ctx, notConflicted, conflicted)
|
return v.resolveConflictsV2(ctx, notConflicted, conflicted)
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("unsupported state resolution algorithm %v", stateResAlgo)
|
return nil, fmt.Errorf("unsupported state resolution algorithm %v", stateResAlgo)
|
||||||
|
|
|
@ -1052,6 +1052,7 @@ func (d *EventDatabase) MaybeRedactEvent(
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO HYDRA: we need to load the create event here
|
||||||
switch {
|
switch {
|
||||||
case powerlevels.UserLevel(redactionEvent.SenderID()) >= powerlevels.Redact:
|
case powerlevels.UserLevel(redactionEvent.SenderID()) >= powerlevels.Redact:
|
||||||
// 1. The power level of the redaction event’s sender is greater than or equal to the redact level.
|
// 1. The power level of the redaction event’s sender is greater than or equal to the redact level.
|
||||||
|
|
|
@ -216,14 +216,6 @@ func OnIncomingMessagesRequest(
|
||||||
|
|
||||||
// TODO: Implement filtering (#587)
|
// TODO: Implement filtering (#587)
|
||||||
|
|
||||||
// Check the room ID's format.
|
|
||||||
if _, _, err = gomatrixserverlib.SplitID('!', roomID); err != nil {
|
|
||||||
return util.JSONResponse{
|
|
||||||
Code: http.StatusBadRequest,
|
|
||||||
JSON: spec.MissingParam("Bad room ID: " + err.Error()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the user already left the room, grep events from before that
|
// If the user already left the room, grep events from before that
|
||||||
if membershipResp.Membership == spec.Leave {
|
if membershipResp.Membership == spec.Leave {
|
||||||
var token types.TopologyToken
|
var token types.TopologyToken
|
||||||
|
|
|
@ -94,7 +94,7 @@ func (r *Room) insertCreateEvents(t *testing.T) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
var joinRule gomatrixserverlib.JoinRuleContent
|
var joinRule gomatrixserverlib.JoinRuleContent
|
||||||
var hisVis gomatrixserverlib.HistoryVisibilityContent
|
var hisVis gomatrixserverlib.HistoryVisibilityContent
|
||||||
plContent := eventutil.InitialPowerLevelsContent(r.creator.ID)
|
plContent := eventutil.InitialPowerLevelsContent(gomatrixserverlib.MustGetRoomVersion(r.Version), r.creator.ID)
|
||||||
switch r.preset {
|
switch r.preset {
|
||||||
case PresetTrustedPrivateChat:
|
case PresetTrustedPrivateChat:
|
||||||
fallthrough
|
fallthrough
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
@ -727,26 +728,35 @@ func (rse *ruleSetEvalContext) HasPowerLevel(senderID spec.SenderID, levelKey st
|
||||||
req := &rsapi.QueryLatestEventsAndStateRequest{
|
req := &rsapi.QueryLatestEventsAndStateRequest{
|
||||||
RoomID: rse.roomID,
|
RoomID: rse.roomID,
|
||||||
StateToFetch: []gomatrixserverlib.StateKeyTuple{
|
StateToFetch: []gomatrixserverlib.StateKeyTuple{
|
||||||
{EventType: spec.MRoomPowerLevels},
|
{EventType: spec.MRoomPowerLevels, StateKey: ""},
|
||||||
|
{EventType: spec.MRoomCreate, StateKey: ""},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
var res rsapi.QueryLatestEventsAndStateResponse
|
var res rsapi.QueryLatestEventsAndStateResponse
|
||||||
if err := rse.rsAPI.QueryLatestEventsAndState(rse.ctx, req, &res); err != nil {
|
if err := rse.rsAPI.QueryLatestEventsAndState(rse.ctx, req, &res); err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
for _, ev := range res.StateEvents {
|
var createEvent, plEvent *rstypes.HeaderedEvent
|
||||||
if ev.Type() != spec.MRoomPowerLevels {
|
for i, ev := range res.StateEvents {
|
||||||
continue
|
if ev.Type() == spec.MRoomCreate {
|
||||||
|
createEvent = res.StateEvents[i]
|
||||||
|
} else if ev.Type() == spec.MRoomPowerLevels {
|
||||||
|
plEvent = res.StateEvents[i]
|
||||||
}
|
}
|
||||||
|
}
|
||||||
plc, err := gomatrixserverlib.NewPowerLevelContentFromEvent(ev.PDU)
|
verImpl := gomatrixserverlib.MustGetRoomVersion(createEvent.Version())
|
||||||
|
if verImpl.PrivilegedCreators() && slices.Contains(gomatrixserverlib.CreatorsFromCreateEvent(createEvent), string(senderID)) {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
if plEvent == nil {
|
||||||
|
return true, nil // unsure, but this is what we did before
|
||||||
|
}
|
||||||
|
plc, err := gomatrixserverlib.NewPowerLevelContentFromEvent(plEvent.PDU)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
return plc.UserLevel(senderID) >= plc.NotificationLevel(levelKey), nil
|
return plc.UserLevel(senderID) >= plc.NotificationLevel(levelKey), nil
|
||||||
}
|
}
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// localPushDevices pushes to the configured devices of a local
|
// localPushDevices pushes to the configured devices of a local
|
||||||
// user. The map keys are [url][format].
|
// user. The map keys are [url][format].
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue