Skip to content

Commit f3e2ef8

Browse files
MSC3667 implementation (#284)
* Add `org.matrix.msc3667` room version * Add test * Comment
1 parent f282e8f commit f3e2ef8

File tree

4 files changed

+109
-43
lines changed

4 files changed

+109
-43
lines changed

event.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -978,11 +978,11 @@ func (e *Event) PowerLevels() (*PowerLevelContent, error) {
978978
if !e.StateKeyEquals("") {
979979
return nil, fmt.Errorf("gomatrixserverlib: PowerLevels() event is not a m.room.power_levels event, bad state key")
980980
}
981-
var content PowerLevelContent
982-
if err := e.extractContent(MRoomPowerLevels, &content); err != nil {
981+
c, err := NewPowerLevelContentFromEvent(e)
982+
if err != nil {
983983
return nil, err
984984
}
985-
return &content, nil
985+
return &c, nil
986986
}
987987

988988
// AuthEvents returns references to the events needed to auth the event.

eventcontent.go

+52-40
Original file line numberDiff line numberDiff line change
@@ -348,53 +348,65 @@ func NewPowerLevelContentFromEvent(event *Event) (c PowerLevelContent, err error
348348
// Set the levels to their default values.
349349
c.Defaults()
350350

351-
// We can't extract the JSON directly to the powerLevelContent because we
352-
// need to convert string values to int values.
353-
var content struct {
354-
InviteLevel levelJSONValue `json:"invite"`
355-
BanLevel levelJSONValue `json:"ban"`
356-
KickLevel levelJSONValue `json:"kick"`
357-
RedactLevel levelJSONValue `json:"redact"`
358-
UserLevels map[string]levelJSONValue `json:"users"`
359-
UsersDefaultLevel levelJSONValue `json:"users_default"`
360-
EventLevels map[string]levelJSONValue `json:"events"`
361-
StateDefaultLevel levelJSONValue `json:"state_default"`
362-
EventDefaultLevel levelJSONValue `json:"event_default"`
363-
NotificationLevels map[string]levelJSONValue `json:"notifications"`
364-
}
365-
if err = json.Unmarshal(event.Content(), &content); err != nil {
366-
err = errorf("unparsable power_levels event content: %s", err.Error())
351+
var strict bool
352+
if strict, err = event.roomVersion.RequireIntegerPowerLevels(); err != nil {
367353
return
368-
}
354+
} else if strict {
355+
// Unmarshal directly to PowerLevelContent, since that will kick up an
356+
// error if one of the power levels isn't an int64.
357+
if err = json.Unmarshal(event.Content(), &c); err != nil {
358+
err = errorf("unparsable power_levels event content: %s", err.Error())
359+
return
360+
}
361+
} else {
362+
// We can't extract the JSON directly to the powerLevelContent because we
363+
// need to convert string values to int values.
364+
var content struct {
365+
InviteLevel levelJSONValue `json:"invite"`
366+
BanLevel levelJSONValue `json:"ban"`
367+
KickLevel levelJSONValue `json:"kick"`
368+
RedactLevel levelJSONValue `json:"redact"`
369+
UserLevels map[string]levelJSONValue `json:"users"`
370+
UsersDefaultLevel levelJSONValue `json:"users_default"`
371+
EventLevels map[string]levelJSONValue `json:"events"`
372+
StateDefaultLevel levelJSONValue `json:"state_default"`
373+
EventDefaultLevel levelJSONValue `json:"event_default"`
374+
NotificationLevels map[string]levelJSONValue `json:"notifications"`
375+
}
376+
if err = json.Unmarshal(event.Content(), &content); err != nil {
377+
err = errorf("unparsable power_levels event content: %s", err.Error())
378+
return
379+
}
369380

370-
// Update the levels with the values that are present in the event content.
371-
content.InviteLevel.assignIfExists(&c.Invite)
372-
content.BanLevel.assignIfExists(&c.Ban)
373-
content.KickLevel.assignIfExists(&c.Kick)
374-
content.RedactLevel.assignIfExists(&c.Redact)
375-
content.UsersDefaultLevel.assignIfExists(&c.UsersDefault)
376-
content.StateDefaultLevel.assignIfExists(&c.StateDefault)
377-
content.EventDefaultLevel.assignIfExists(&c.EventsDefault)
378-
379-
for k, v := range content.UserLevels {
380-
if c.Users == nil {
381-
c.Users = make(map[string]int64)
381+
// Update the levels with the values that are present in the event content.
382+
content.InviteLevel.assignIfExists(&c.Invite)
383+
content.BanLevel.assignIfExists(&c.Ban)
384+
content.KickLevel.assignIfExists(&c.Kick)
385+
content.RedactLevel.assignIfExists(&c.Redact)
386+
content.UsersDefaultLevel.assignIfExists(&c.UsersDefault)
387+
content.StateDefaultLevel.assignIfExists(&c.StateDefault)
388+
content.EventDefaultLevel.assignIfExists(&c.EventsDefault)
389+
390+
for k, v := range content.UserLevels {
391+
if c.Users == nil {
392+
c.Users = make(map[string]int64)
393+
}
394+
c.Users[k] = v.value
382395
}
383-
c.Users[k] = v.value
384-
}
385396

386-
for k, v := range content.EventLevels {
387-
if c.Events == nil {
388-
c.Events = make(map[string]int64)
397+
for k, v := range content.EventLevels {
398+
if c.Events == nil {
399+
c.Events = make(map[string]int64)
400+
}
401+
c.Events[k] = v.value
389402
}
390-
c.Events[k] = v.value
391-
}
392403

393-
for k, v := range content.NotificationLevels {
394-
if c.Notifications == nil {
395-
c.Notifications = make(map[string]int64)
404+
for k, v := range content.NotificationLevels {
405+
if c.Notifications == nil {
406+
c.Notifications = make(map[string]int64)
407+
}
408+
c.Notifications[k] = v.value
396409
}
397-
c.Notifications[k] = v.value
398410
}
399411

400412
return

eventcontent_test.go

+21
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,24 @@ func TestLevelJSONValueInvalid(t *testing.T) {
7070
}
7171
}
7272
}
73+
74+
func TestStrictPowerLevelContent(t *testing.T) {
75+
// The event JSON has a "100" instead of a 100 in the power level. In
76+
// room version 7, this is permissible, but it isn't in our new experimental
77+
// room version.
78+
eventJSON := `{"content":{"ban":50,"events":{"m.room.avatar":50,"m.room.canonical_alias":50,"m.room.encryption":100,"m.room.history_visibility":100,"m.room.name":50,"m.room.power_levels":100,"m.room.server_acl":100,"m.room.tombstone":100},"events_default":0,"historical":100,"invite":0,"kick":50,"redact":50,"state_default":50,"users":{"@neilalexander:matrix.org":"100"},"users_default":0},"origin_server_ts":1643017369993,"sender":"@neilalexander:matrix.org","state_key":"","type":"m.room.power_levels","unsigned":{"age":592},"event_id":"$2CT2RSF8B4XJyysh7i6Zdw0oYSs53JkIhTMrapIVYnw","room_id":"!CeUyQRqMxuBnjcxiIr:matrix.org"}`
79+
goodEvent, err := NewEventFromTrustedJSON([]byte(eventJSON), false, RoomVersionV7)
80+
if err != nil {
81+
t.Fatal(err)
82+
}
83+
badEvent, err := NewEventFromTrustedJSON([]byte(eventJSON), false, "org.matrix.msc3667")
84+
if err != nil {
85+
t.Fatal(err)
86+
}
87+
if _, err := goodEvent.PowerLevels(); err != nil {
88+
t.Fatalf("good content should not have errored but did: %s", err)
89+
}
90+
if _, err := badEvent.PowerLevels(); err == nil {
91+
t.Fatal("bad content should have errored but didn't")
92+
}
93+
}

eventversion.go

+33
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ var roomVersionMeta = map[RoomVersion]RoomVersionDescription{
7272
powerLevelsIncludeNotifications: false,
7373
allowKnockingInEventAuth: false,
7474
allowRestrictedJoinsInEventAuth: false,
75+
requireIntegerPowerLevels: false,
7576
},
7677
RoomVersionV2: {
7778
Supported: true,
@@ -85,6 +86,7 @@ var roomVersionMeta = map[RoomVersion]RoomVersionDescription{
8586
powerLevelsIncludeNotifications: false,
8687
allowKnockingInEventAuth: false,
8788
allowRestrictedJoinsInEventAuth: false,
89+
requireIntegerPowerLevels: false,
8890
},
8991
RoomVersionV3: {
9092
Supported: true,
@@ -98,6 +100,7 @@ var roomVersionMeta = map[RoomVersion]RoomVersionDescription{
98100
powerLevelsIncludeNotifications: false,
99101
allowKnockingInEventAuth: false,
100102
allowRestrictedJoinsInEventAuth: false,
103+
requireIntegerPowerLevels: false,
101104
},
102105
RoomVersionV4: {
103106
Supported: true,
@@ -111,6 +114,7 @@ var roomVersionMeta = map[RoomVersion]RoomVersionDescription{
111114
powerLevelsIncludeNotifications: false,
112115
allowKnockingInEventAuth: false,
113116
allowRestrictedJoinsInEventAuth: false,
117+
requireIntegerPowerLevels: false,
114118
},
115119
RoomVersionV5: {
116120
Supported: true,
@@ -124,6 +128,7 @@ var roomVersionMeta = map[RoomVersion]RoomVersionDescription{
124128
powerLevelsIncludeNotifications: false,
125129
allowKnockingInEventAuth: false,
126130
allowRestrictedJoinsInEventAuth: false,
131+
requireIntegerPowerLevels: false,
127132
},
128133
RoomVersionV6: {
129134
Supported: true,
@@ -137,6 +142,7 @@ var roomVersionMeta = map[RoomVersion]RoomVersionDescription{
137142
powerLevelsIncludeNotifications: true,
138143
allowKnockingInEventAuth: false,
139144
allowRestrictedJoinsInEventAuth: false,
145+
requireIntegerPowerLevels: false,
140146
},
141147
RoomVersionV7: {
142148
Supported: true,
@@ -150,6 +156,7 @@ var roomVersionMeta = map[RoomVersion]RoomVersionDescription{
150156
powerLevelsIncludeNotifications: true,
151157
allowKnockingInEventAuth: true,
152158
allowRestrictedJoinsInEventAuth: false,
159+
requireIntegerPowerLevels: false,
153160
},
154161
RoomVersionV8: {
155162
Supported: true,
@@ -163,6 +170,7 @@ var roomVersionMeta = map[RoomVersion]RoomVersionDescription{
163170
powerLevelsIncludeNotifications: true,
164171
allowKnockingInEventAuth: true,
165172
allowRestrictedJoinsInEventAuth: true,
173+
requireIntegerPowerLevels: false,
166174
},
167175
RoomVersionV9: {
168176
Supported: true,
@@ -176,6 +184,21 @@ var roomVersionMeta = map[RoomVersion]RoomVersionDescription{
176184
powerLevelsIncludeNotifications: true,
177185
allowKnockingInEventAuth: true,
178186
allowRestrictedJoinsInEventAuth: true,
187+
requireIntegerPowerLevels: false,
188+
},
189+
"org.matrix.msc3667": { // based on room version 7
190+
Supported: true,
191+
Stable: false,
192+
stateResAlgorithm: StateResV2,
193+
eventFormat: EventFormatV2,
194+
eventIDFormat: EventIDFormatV3,
195+
redactionAlgorithm: RedactionAlgorithmV2,
196+
enforceSignatureChecks: true,
197+
enforceCanonicalJSON: true,
198+
powerLevelsIncludeNotifications: true,
199+
allowKnockingInEventAuth: true,
200+
allowRestrictedJoinsInEventAuth: false,
201+
requireIntegerPowerLevels: true,
179202
},
180203
}
181204

@@ -231,6 +254,7 @@ type RoomVersionDescription struct {
231254
powerLevelsIncludeNotifications bool
232255
allowKnockingInEventAuth bool
233256
allowRestrictedJoinsInEventAuth bool
257+
requireIntegerPowerLevels bool
234258
Supported bool
235259
Stable bool
236260
}
@@ -312,6 +336,15 @@ func (v RoomVersion) EnforceCanonicalJSON() (bool, error) {
312336
return false, UnsupportedRoomVersionError{v}
313337
}
314338

339+
// RequireIntegerPowerLevels returns true if the given room version calls for
340+
// power levels as integers only, false otherwise.
341+
func (v RoomVersion) RequireIntegerPowerLevels() (bool, error) {
342+
if r, ok := roomVersionMeta[v]; ok {
343+
return r.requireIntegerPowerLevels, nil
344+
}
345+
return false, UnsupportedRoomVersionError{v}
346+
}
347+
315348
// UnsupportedRoomVersionError occurs when a call has been made with a room
316349
// version that is not supported by this version of gomatrixserverlib.
317350
type UnsupportedRoomVersionError struct {

0 commit comments

Comments
 (0)