Skip to content

Commit 4d93d92

Browse files
authored
Room version 12 (#3623)
1 parent a408b24 commit 4d93d92

File tree

26 files changed

+530
-208
lines changed

26 files changed

+530
-208
lines changed

clientapi/routing/createroom.go

Lines changed: 50 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -176,12 +176,6 @@ func createRoom(
176176
roomVersion = candidateVersion
177177
}
178178

179-
logger.WithFields(log.Fields{
180-
"userID": userID.String(),
181-
"roomID": roomID.String(),
182-
"roomVersion": roomVersion,
183-
}).Info("Creating new room")
184-
185179
profile, err := appserviceAPI.RetrieveUserProfile(ctx, userID.String(), asAPI, profileAPI)
186180
if err != nil {
187181
util.GetLogger(ctx).WithError(err).Error("appserviceAPI.RetrieveUserProfile failed")
@@ -197,13 +191,57 @@ func createRoom(
197191
keyID := cfg.Matrix.KeyID
198192
privateKey := cfg.Matrix.PrivateKey
199193

194+
verImpl := gomatrixserverlib.MustGetRoomVersion(roomVersion)
195+
196+
var createEventJSON json.RawMessage
197+
if verImpl.DomainlessRoomIDs() {
198+
// make the create event up-front so the roomserver can calculate the room NID to store.
199+
var additionalCreators []string
200+
if createRequest.Preset == spec.PresetTrustedPrivateChat {
201+
additionalCreators = createRequest.Invite
202+
}
203+
createContent, err := roomserverAPI.GenerateCreateContent(ctx, createRequest.RoomVersion, userID.String(), createRequest.CreationContent, additionalCreators)
204+
if err != nil {
205+
util.GetLogger(ctx).WithError(err).Error("GenerateCreateContent failed")
206+
return util.JSONResponse{
207+
Code: http.StatusBadRequest,
208+
JSON: spec.BadJSON("invalid create content"),
209+
}
210+
}
211+
authEvents, _ := gomatrixserverlib.NewAuthEvents(nil)
212+
identity, err := cfg.Matrix.SigningIdentityFor(userID.Domain())
213+
if err != nil {
214+
util.GetLogger(ctx).WithError(err).Error("Failed to get signing identity")
215+
return util.JSONResponse{
216+
Code: http.StatusInternalServerError,
217+
JSON: spec.InternalServerError{},
218+
}
219+
}
220+
createEvent, jsonErr := roomserverAPI.GeneratePDU(
221+
ctx, gomatrixserverlib.MustGetRoomVersion(roomVersion),
222+
gomatrixserverlib.FledglingEvent{
223+
Type: spec.MRoomCreate,
224+
Content: createContent,
225+
},
226+
authEvents, 1, "", identity, evTime, userID.String(), "", rsAPI,
227+
)
228+
if jsonErr != nil {
229+
util.GetLogger(ctx).WithError(err).Error("Failed to make the create event")
230+
return *jsonErr
231+
}
232+
createEventJSON = createEvent.JSON()
233+
r := createEvent.RoomID()
234+
roomID = &r
235+
}
236+
200237
req := roomserverAPI.PerformCreateRoomRequest{
201238
InvitedUsers: createRequest.Invite,
202239
RoomName: createRequest.Name,
203240
Visibility: createRequest.Visibility,
204241
Topic: createRequest.Topic,
205242
StatePreset: createRequest.Preset,
206243
CreationContent: createRequest.CreationContent,
244+
CreateEvent: createEventJSON,
207245
InitialState: createRequest.InitialState,
208246
RoomAliasName: createRequest.RoomAliasName,
209247
RoomVersion: roomVersion,
@@ -217,6 +255,12 @@ func createRoom(
217255
EventTime: evTime,
218256
}
219257

258+
logger.WithFields(log.Fields{
259+
"userID": userID.String(),
260+
"roomID": roomID.String(),
261+
"roomVersion": roomVersion,
262+
}).Info("Creating new room")
263+
220264
roomAlias, createRes := rsAPI.PerformCreateRoom(ctx, *userID, *roomID, &req)
221265
if createRes != nil {
222266
return *createRes

clientapi/routing/directory.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -411,10 +411,11 @@ func SetVisibility(
411411
JSON: spec.InternalServerError{},
412412
}
413413
}
414+
privileged := isPrivilegedCreator(req.Context(), rsAPI, roomID, *senderID)
414415

415416
// NOTSPEC: Check if the user's power is greater than power required to change m.room.canonical_alias event
416417
power, _ := gomatrixserverlib.NewPowerLevelContentFromEvent(queryEventsRes.StateEvents[0].PDU)
417-
if power.UserLevel(*senderID) < power.EventLevel(spec.MRoomCanonicalAlias, true) {
418+
if !privileged && power.UserLevel(*senderID) < power.EventLevel(spec.MRoomCanonicalAlias, true) {
418419
return util.JSONResponse{
419420
Code: http.StatusForbidden,
420421
JSON: spec.Forbidden("userID doesn't have power level to change visibility"),

clientapi/routing/membership.go

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"crypto/ed25519"
1212
"fmt"
1313
"net/http"
14+
"slices"
1415
"time"
1516

1617
appserviceAPI "github.com/element-hq/dendrite/appservice/api"
@@ -79,7 +80,8 @@ func SendBan(
7980
if errRes != nil {
8081
return *errRes
8182
}
82-
allowedToBan := pl.UserLevel(*senderID) >= pl.Ban
83+
privileged := isPrivilegedCreator(req.Context(), rsAPI, roomID, *senderID)
84+
allowedToBan := privileged || pl.UserLevel(*senderID) >= pl.Ban
8385
if !allowedToBan {
8486
return util.JSONResponse{
8587
Code: http.StatusForbidden,
@@ -118,6 +120,12 @@ func sendMembership(ctx context.Context, profileAPI userapi.ClientUserAPI, devic
118120
false,
119121
); err != nil {
120122
util.GetLogger(ctx).WithError(err).Error("SendEvents failed")
123+
if err.Error() == api.InputWasRejected {
124+
return util.JSONResponse{
125+
Code: http.StatusForbidden,
126+
JSON: spec.Forbidden("the event was rejected"),
127+
}
128+
}
121129
return util.JSONResponse{
122130
Code: http.StatusInternalServerError,
123131
JSON: spec.InternalServerError{},
@@ -185,7 +193,8 @@ func SendKick(
185193
if errRes != nil {
186194
return *errRes
187195
}
188-
allowedToKick := pl.UserLevel(*senderID) >= pl.Kick || bodyUserID.String() == deviceUserID.String()
196+
privileged := isPrivilegedCreator(req.Context(), rsAPI, roomID, *senderID)
197+
allowedToKick := privileged || pl.UserLevel(*senderID) >= pl.Kick || bodyUserID.String() == deviceUserID.String()
189198
if !allowedToKick {
190199
return util.JSONResponse{
191200
Code: http.StatusForbidden,
@@ -680,3 +689,12 @@ func getPowerlevels(req *http.Request, rsAPI roomserverAPI.ClientRoomserverAPI,
680689
}
681690
return pl, nil
682691
}
692+
693+
// Returns true if the room is a room which supports privileged creators and the sender is a creator, else false.
694+
func isPrivilegedCreator(ctx context.Context, rsAPI roomserverAPI.ClientRoomserverAPI, roomID string, senderID spec.SenderID) bool {
695+
createEvent := roomserverAPI.GetStateEvent(ctx, rsAPI, roomID, gomatrixserverlib.StateKeyTuple{
696+
EventType: spec.MRoomCreate,
697+
StateKey: "",
698+
})
699+
return gomatrixserverlib.MustGetRoomVersion(createEvent.Version()).PrivilegedCreators() && slices.Contains(gomatrixserverlib.CreatorsFromCreateEvent(createEvent), string(senderID))
700+
}

clientapi/routing/redaction.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,10 +98,12 @@ func SendRedaction(
9898
}
9999
}
100100

101+
privileged := isPrivilegedCreator(req.Context(), rsAPI, roomID, *senderID)
102+
101103
// "Users may redact their own events, and any user with a power level greater than or equal
102104
// to the redact power level of the room may redact events there"
103105
// https://matrix.org/docs/spec/client_server/r0.6.1#put-matrix-client-r0-rooms-roomid-redact-eventid-txnid
104-
allowedToRedact := ev.SenderID() == *senderID
106+
allowedToRedact := ev.SenderID() == *senderID || privileged
105107
if !allowedToRedact {
106108
plEvent := roomserverAPI.GetStateEvent(req.Context(), rsAPI, roomID, gomatrixserverlib.StateKeyTuple{
107109
EventType: spec.MRoomPowerLevels,

clientapi/routing/sendevent.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,6 @@ func SendEvent(
7777
JSON: spec.UnsupportedRoomVersion(err.Error()),
7878
}
7979
}
80-
8180
if txnID != nil {
8281
// Try to fetch response from transactionsCache
8382
if res, ok := txnCache.FetchTransaction(device.AccessToken, *txnID, req.URL); ok {
@@ -367,6 +366,12 @@ func generateSendEvent(
367366
JSON: spec.InternalServerError{},
368367
}
369368
}
369+
if proto.Type == spec.MRoomCreate && proto.StateKey != nil && *proto.StateKey == "" {
370+
return nil, &util.JSONResponse{
371+
Code: http.StatusBadRequest,
372+
JSON: spec.InvalidParam("cannot resend m.room.create event"),
373+
}
374+
}
370375

371376
identity, err := rsAPI.SigningIdentityFor(ctx, *validRoomID, *fullUserID)
372377
if err != nil {
@@ -424,8 +429,13 @@ func generateSendEvent(
424429
if err = gomatrixserverlib.Allowed(e.PDU, provider, func(roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) {
425430
return rsAPI.QueryUserIDForSender(ctx, *validRoomID, senderID)
426431
}); err != nil {
432+
code := 403
433+
validationErr, ok := err.(*gomatrixserverlib.EventValidationError)
434+
if ok {
435+
code = validationErr.Code
436+
}
427437
return nil, &util.JSONResponse{
428-
Code: http.StatusForbidden,
438+
Code: code,
429439
JSON: spec.Forbidden(err.Error()), // TODO: Is this error string comprehensible to the client?
430440
}
431441
}

clientapi/routing/server_notices.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"time"
1515

1616
"github.com/matrix-org/gomatrix"
17+
"github.com/matrix-org/gomatrixserverlib"
1718
"github.com/matrix-org/gomatrixserverlib/tokens"
1819
"github.com/matrix-org/util"
1920
"github.com/prometheus/client_golang/prometheus"
@@ -139,7 +140,7 @@ func SendServerNotice(
139140

140141
// create a new room for the user
141142
if len(commonRooms) == 0 {
142-
powerLevelContent := eventutil.InitialPowerLevelsContent(senderUserID.String())
143+
powerLevelContent := eventutil.InitialPowerLevelsContent(gomatrixserverlib.MustGetRoomVersion(roomVersion), senderUserID.String())
143144
powerLevelContent.Users[r.UserID] = -10 // taken from Synapse
144145
pl, err := json.Marshal(powerLevelContent)
145146
if err != nil {

clientapi/routing/upgrade_room.go

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ import (
2323
)
2424

2525
type upgradeRoomRequest struct {
26-
NewVersion string `json:"new_version"`
26+
NewVersion string `json:"new_version"`
27+
AdditionalCreators []string `json:"additional_creators"`
2728
}
2829

2930
type upgradeRoomResponse struct {
@@ -43,6 +44,13 @@ func UpgradeRoom(
4344
return *rErr
4445
}
4546

47+
if r.NewVersion == "" {
48+
return util.JSONResponse{
49+
Code: http.StatusBadRequest,
50+
JSON: spec.InvalidParam("missing version to upgrade to"),
51+
}
52+
}
53+
4654
// Validate that the room version is supported
4755
if _, err := version.SupportedRoomVersion(gomatrixserverlib.RoomVersion(r.NewVersion)); err != nil {
4856
return util.JSONResponse{
@@ -59,7 +67,10 @@ func UpgradeRoom(
5967
JSON: spec.InternalServerError{},
6068
}
6169
}
62-
newRoomID, err := rsAPI.PerformRoomUpgrade(req.Context(), roomID, *userID, gomatrixserverlib.RoomVersion(r.NewVersion))
70+
newRoomID, err := rsAPI.PerformRoomUpgrade(req.Context(), roomID, *userID, gomatrixserverlib.RoomVersion(r.NewVersion), r.AdditionalCreators)
71+
if err != nil {
72+
util.GetLogger(req.Context()).WithError(err).Error("PerformRoomUpgrade failed")
73+
}
6374
switch e := err.(type) {
6475
case nil:
6576
case roomserverAPI.ErrNotAllowed:

go.mod

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ require (
2525
github.com/matrix-org/dugong v0.0.0-20210921133753-66e6b1c67e2e
2626
github.com/matrix-org/go-sqlite3-js v0.0.0-20220419092513-28aa791a1c91
2727
github.com/matrix-org/gomatrix v0.0.0-20220926102614-ceba4d9f7530
28-
github.com/matrix-org/gomatrixserverlib v0.0.0-20250619052822-904c8f04597e
28+
github.com/matrix-org/gomatrixserverlib v0.0.0-20250811193806-b7e0e0824751
2929
github.com/matrix-org/pinecone v0.11.1-0.20230810010612-ea4c33717fd7
3030
github.com/matrix-org/util v0.0.0-20221111132719-399730281e66
3131
github.com/mattn/go-sqlite3 v1.14.28
@@ -100,6 +100,7 @@ require (
100100
github.com/google/go-tpm v0.9.3 // indirect
101101
github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd // indirect
102102
github.com/h2non/filetype v1.1.3 // indirect
103+
github.com/hashicorp/go-set/v3 v3.0.0 // indirect
103104
github.com/hjson/hjson-go/v4 v4.4.0 // indirect
104105
github.com/json-iterator/go v1.1.12 // indirect
105106
github.com/juju/errors v1.0.0 // indirect
@@ -118,6 +119,7 @@ require (
118119
github.com/nats-io/nkeys v0.4.11 // indirect
119120
github.com/nats-io/nuid v1.0.1 // indirect
120121
github.com/ncruces/go-strftime v0.1.9 // indirect
122+
github.com/oleiade/lane/v2 v2.0.0 // indirect
121123
github.com/onsi/ginkgo/v2 v2.11.0 // indirect
122124
github.com/opencontainers/go-digest v1.0.0 // indirect
123125
github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 // indirect

go.sum

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,8 @@ github.com/h2non/filetype v1.1.3 h1:FKkx9QbD7HR/zjK1Ia5XiBsq9zdLi5Kf3zGyFTAFkGg=
199199
github.com/h2non/filetype v1.1.3/go.mod h1:319b3zT68BvV+WRj7cwy856M2ehB3HqNOt6sy1HndBY=
200200
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw=
201201
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
202+
github.com/hashicorp/go-set/v3 v3.0.0 h1:CaJBQvQCOWoftrBcDt7Nwgo0kdpmrKxar/x2o6pV9JA=
203+
github.com/hashicorp/go-set/v3 v3.0.0/go.mod h1:IEghM2MpE5IaNvL+D7X480dfNtxjRXZ6VMpK3C8s2ok=
202204
github.com/hjson/hjson-go/v4 v4.4.0 h1:D/NPvqOCH6/eisTb5/ztuIS8GUvmpHaLOcNk1Bjr298=
203205
github.com/hjson/hjson-go/v4 v4.4.0/go.mod h1:KaYt3bTw3zhBjYqnXkYywcYctk0A2nxeEFTse3rH13E=
204206
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
235237
github.com/matrix-org/go-sqlite3-js v0.0.0-20220419092513-28aa791a1c91/go.mod h1:e+cg2q7C7yE5QnAXgzo512tgFh1RbQLC0+jozuegKgo=
236238
github.com/matrix-org/gomatrix v0.0.0-20220926102614-ceba4d9f7530 h1:kHKxCOLcHH8r4Fzarl4+Y3K5hjothkVW5z7T1dUM11U=
237239
github.com/matrix-org/gomatrix v0.0.0-20220926102614-ceba4d9f7530/go.mod h1:/gBX06Kw0exX1HrwmoBibFA98yBk/jxKpGVeyQbff+s=
238-
github.com/matrix-org/gomatrixserverlib v0.0.0-20250619052822-904c8f04597e h1:SWediqisy1Eoumr06sjGaA6gt6gS4FtXe00VB6fSNZw=
239-
github.com/matrix-org/gomatrixserverlib v0.0.0-20250619052822-904c8f04597e/go.mod h1:61LpEsWAroRfdVh2dnr6fQ+K3MmRgD5I35GVvF4FpXQ=
240+
github.com/matrix-org/gomatrixserverlib v0.0.0-20250811171307-390dbaa8de98 h1:AH19nhwaPYCRddS/s7LgKS+fhntFXg2qG47uFAjwFJ4=
241+
github.com/matrix-org/gomatrixserverlib v0.0.0-20250811171307-390dbaa8de98/go.mod h1:b6KVfDjXjA5Q7vhpOaMqIhFYvu5BuFVZixlNeTV/CLc=
242+
github.com/matrix-org/gomatrixserverlib v0.0.0-20250811193806-b7e0e0824751 h1:x1pC7Nt1Qb24q9WtPybMHWo2uVFTzCKtlUAzarju8bk=
243+
github.com/matrix-org/gomatrixserverlib v0.0.0-20250811193806-b7e0e0824751/go.mod h1:b6KVfDjXjA5Q7vhpOaMqIhFYvu5BuFVZixlNeTV/CLc=
240244
github.com/matrix-org/pinecone v0.11.1-0.20230810010612-ea4c33717fd7 h1:6t8kJr8i1/1I5nNttw6nn1ryQJgzVlBmSGgPiiaTdw4=
241245
github.com/matrix-org/pinecone v0.11.1-0.20230810010612-ea4c33717fd7/go.mod h1:ReWMS/LoVnOiRAdq9sNUC2NZnd1mZkMNB52QhpTRWjg=
242246
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
286290
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
287291
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
288292
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
293+
github.com/oleiade/lane/v2 v2.0.0 h1:XW/ex/Inr+bPkLd3O240xrFOhUkTd4Wy176+Gv0E3Qw=
294+
github.com/oleiade/lane/v2 v2.0.0/go.mod h1:i5FBPFAYSWCgLh58UkUGCChjcCzef/MI7PlQm2TKCeg=
289295
github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU=
290296
github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM=
291297
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
324330
github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
325331
github.com/rs/zerolog v1.29.1 h1:cO+d60CHkknCbvzEWxP0S9K6KqyTjrCNUy1LdQLCGPc=
326332
github.com/rs/zerolog v1.29.1/go.mod h1:Le6ESbR7hc+DP6Lt1THiV8CQSdkkNrd3R0XbEgp3ZBU=
333+
github.com/shoenig/test v1.11.0 h1:NoPa5GIoBwuqzIviCrnUJa+t5Xb4xi5Z+zODJnIDsEQ=
334+
github.com/shoenig/test v1.11.0/go.mod h1:UxJ6u/x2v/TNs/LoLxBNJRV9DiwBBKYxXSyczsBHFoI=
327335
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
328336
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
329337
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=

internal/eventutil/eventcontent.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ type CanonicalAlias struct {
3737
// if they have not been specified.
3838
// http://matrix.org/docs/spec/client_server/r0.2.0.html#m-room-power-levels
3939
// https://github.com/matrix-org/synapse/blob/v0.19.2/synapse/handlers/room.py#L294
40-
func InitialPowerLevelsContent(roomCreator string) (c gomatrixserverlib.PowerLevelContent) {
40+
func InitialPowerLevelsContent(roomVersion gomatrixserverlib.IRoomVersion, roomCreator string) (c gomatrixserverlib.PowerLevelContent) {
4141
c.Defaults()
4242
c.Events = map[string]int64{
4343
"m.room.name": 50,
@@ -49,7 +49,12 @@ func InitialPowerLevelsContent(roomCreator string) (c gomatrixserverlib.PowerLev
4949
"m.room.encryption": 100,
5050
"m.room.server_acl": 100,
5151
}
52-
c.Users = map[string]int64{roomCreator: 100}
52+
c.Users = map[string]int64{}
53+
if roomVersion.PrivilegedCreators() {
54+
c.Events["m.room.tombstone"] = 150
55+
} else {
56+
c.Users[roomCreator] = 100
57+
}
5358
return c
5459
}
5560

0 commit comments

Comments
 (0)