Skip to content

Commit dcfbb70

Browse files
Try to support MSC3787 (#310)
* `knock_restricted` join rules permit knocking * `knock_restricted` join rules permit restricted joins Co-authored-by: Neil Alexander <[email protected]>
1 parent b1c5619 commit dcfbb70

File tree

3 files changed

+114
-38
lines changed

3 files changed

+114
-38
lines changed

eventauth.go

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ const (
3838
Knock = "knock"
3939
// Restricted is the string constant "restricted"
4040
Restricted = "restricted"
41+
// NOTSPEC: Restricted is the string constant "knock_restricted" (MSC3787)
42+
// REVIEW: the MSC is merged though... so is this specced? Idk.
43+
KnockRestricted = "knock_restricted"
4144
// NOTSPEC: Peek is the string constant "peek" (MSC2753, used as the label in the sync block)
4245
Peek = "peek"
4346
// Public is the string constant "public"
@@ -983,7 +986,7 @@ func (m *membershipAllower) membershipAllowed(event *Event) error { // nolint: g
983986
func (m *membershipAllower) membershipAllowedSelfForRestrictedJoin() error {
984987
// Special case for restricted room joins, where we will check if the membership
985988
// event is signed by one of the allowed servers in the join rule content.
986-
allowsRestricted, err := m.roomVersion.AllowRestrictedJoinsInEventAuth()
989+
allowsRestricted, err := m.roomVersion.AllowRestrictedJoinsInEventAuth(m.joinRule.JoinRule)
987990
if err != nil {
988991
return err
989992
}
@@ -1081,7 +1084,7 @@ func (m *membershipAllower) membershipAllowedSelf() error { // nolint: gocyclo
10811084

10821085
switch m.newMember.Membership {
10831086
case Knock:
1084-
if m.joinRule.JoinRule != Knock {
1087+
if m.joinRule.JoinRule != Knock && m.joinRule.JoinRule != KnockRestricted {
10851088
return m.membershipFailed(
10861089
"join rule %q does not allow knocking", m.joinRule.JoinRule,
10871090
)
@@ -1090,11 +1093,16 @@ func (m *membershipAllower) membershipAllowedSelf() error { // nolint: gocyclo
10901093
// rules are "knock" and they are not already joined to, invited to
10911094
// or banned from the room.
10921095
// Spec: https://spec.matrix.org/unstable/rooms/v7/
1093-
if supported, err := m.roomVersion.AllowKnockingInEventAuth(); err != nil {
1096+
// MSC3787 extends this: the behaviour above is also permitted if the
1097+
// join rules are "knock_restricted"
1098+
// Spec: https://github.com/matrix-org/matrix-spec-proposals/pull/3787
1099+
if supported, err := m.roomVersion.AllowKnockingInEventAuth(m.joinRule.JoinRule); err != nil {
10941100
return fmt.Errorf("m.roomVersion.AllowKnockingInEventAuth: %w", err)
10951101
} else if !supported {
10961102
return m.membershipFailed(
1097-
"room version %q does not support knocking", m.roomVersion,
1103+
"room version %q does not support knocking on rooms with join rule %q",
1104+
m.roomVersion,
1105+
m.joinRule.JoinRule,
10981106
)
10991107
}
11001108
switch m.oldMember.Membership {
@@ -1216,16 +1224,18 @@ func (m *membershipAllower) membershipAllowedOther() error { // nolint: gocyclo
12161224
}
12171225
// A user can invite in response to a knock.
12181226
if m.oldMember.Membership == Knock && senderLevel >= m.powerLevels.Invite {
1219-
if m.joinRule.JoinRule != Knock {
1227+
if m.joinRule.JoinRule != Knock && m.joinRule.JoinRule != KnockRestricted {
12201228
return m.membershipFailed(
12211229
"join rule %q does not allow knocking", m.joinRule.JoinRule,
12221230
)
12231231
}
1224-
if supported, err := m.roomVersion.AllowKnockingInEventAuth(); err != nil {
1232+
if supported, err := m.roomVersion.AllowKnockingInEventAuth(m.joinRule.JoinRule); err != nil {
12251233
return fmt.Errorf("m.roomVersion.AllowKnockingInEventAuth: %w", err)
12261234
} else if !supported {
12271235
return m.membershipFailed(
1228-
"room version %q does not allow knocking", m.roomVersion,
1236+
"room version %q does not support knocking on rooms with join rule %q",
1237+
m.roomVersion,
1238+
m.joinRule.JoinRule,
12291239
)
12301240
}
12311241
return nil

eventcrypto.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ func (e *Event) VerifyEventSignatures(ctx context.Context, verifier JSONVerifier
8383
}
8484

8585
// For restricted join rules, the authorising server should have signed.
86-
if restricted, err := e.roomVersion.AllowRestrictedJoinsInEventAuth(); err != nil {
86+
if restricted, err := e.roomVersion.MayAllowRestrictedJoinsInEventAuth(); err != nil {
8787
return fmt.Errorf("failed to check if restricted joins allowed: %w", err)
8888
} else if restricted && membership == Join {
8989
if v := gjson.GetBytes(e.Content(), "join_authorised_via_users_server"); v.Exists() {

eventversion.go

Lines changed: 96 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,14 @@ type EventIDFormat int
1717
// RedactionAlgorithm refers to the redaction algorithm used in a room version.
1818
type RedactionAlgorithm int
1919

20+
// JoinRulesPermittingKnockInEventAuth specifies which kinds of join_rule allow
21+
// a room to be knocked upon.
22+
type JoinRulesPermittingKnockInEventAuth int
23+
24+
// JoinRulesPermittingRestrictedJoinInEventAuth specifies which kinds of join_rule allow
25+
// a room to be joined via a space.
26+
type JoinRulesPermittingRestrictedJoinInEventAuth int
27+
2028
// Room version constants. These are strings because the version grammar
2129
// allows for future expansion.
2230
// https://matrix.org/docs/spec/#room-version-grammar
@@ -59,6 +67,20 @@ const (
5967
RedactionAlgorithmV4 // protects membership 'join_authorised_via_users_server' key
6068
)
6169

70+
// Which join_rules permit knocking?
71+
const (
72+
KnocksForbidden JoinRulesPermittingKnockInEventAuth = iota + 1 // no rooms can be knocked upon
73+
KnockOnly // rooms with join_rule "knock" can be knocked upon
74+
KnockOrKnockRestricted // rooms with join_rule "knock" or "knock_restricted" can be knocked upon
75+
)
76+
77+
// Which join_rules permit restricted joins?
78+
const (
79+
NoRestrictedJoins JoinRulesPermittingRestrictedJoinInEventAuth = iota + 1 // no rooms can be joined via a space
80+
RestrictedOnly // rooms with join_rule "restricted" can be joined via a space
81+
RestrictedOrKnockRestricted // rooms with join_rule "restricted" or "knock_restricted" can be joined via a space
82+
)
83+
6284
var roomVersionMeta = map[RoomVersion]RoomVersionDescription{
6385
RoomVersionV1: {
6486
Supported: true,
@@ -70,8 +92,8 @@ var roomVersionMeta = map[RoomVersion]RoomVersionDescription{
7092
enforceSignatureChecks: false,
7193
enforceCanonicalJSON: false,
7294
powerLevelsIncludeNotifications: false,
73-
allowKnockingInEventAuth: false,
74-
allowRestrictedJoinsInEventAuth: false,
95+
allowKnockingInEventAuth: KnocksForbidden,
96+
allowRestrictedJoinsInEventAuth: NoRestrictedJoins,
7597
requireIntegerPowerLevels: false,
7698
},
7799
RoomVersionV2: {
@@ -84,8 +106,8 @@ var roomVersionMeta = map[RoomVersion]RoomVersionDescription{
84106
enforceSignatureChecks: false,
85107
enforceCanonicalJSON: false,
86108
powerLevelsIncludeNotifications: false,
87-
allowKnockingInEventAuth: false,
88-
allowRestrictedJoinsInEventAuth: false,
109+
allowKnockingInEventAuth: KnocksForbidden,
110+
allowRestrictedJoinsInEventAuth: NoRestrictedJoins,
89111
requireIntegerPowerLevels: false,
90112
},
91113
RoomVersionV3: {
@@ -98,8 +120,8 @@ var roomVersionMeta = map[RoomVersion]RoomVersionDescription{
98120
enforceSignatureChecks: false,
99121
enforceCanonicalJSON: false,
100122
powerLevelsIncludeNotifications: false,
101-
allowKnockingInEventAuth: false,
102-
allowRestrictedJoinsInEventAuth: false,
123+
allowKnockingInEventAuth: KnocksForbidden,
124+
allowRestrictedJoinsInEventAuth: NoRestrictedJoins,
103125
requireIntegerPowerLevels: false,
104126
},
105127
RoomVersionV4: {
@@ -112,8 +134,8 @@ var roomVersionMeta = map[RoomVersion]RoomVersionDescription{
112134
enforceSignatureChecks: false,
113135
enforceCanonicalJSON: false,
114136
powerLevelsIncludeNotifications: false,
115-
allowKnockingInEventAuth: false,
116-
allowRestrictedJoinsInEventAuth: false,
137+
allowKnockingInEventAuth: KnocksForbidden,
138+
allowRestrictedJoinsInEventAuth: NoRestrictedJoins,
117139
requireIntegerPowerLevels: false,
118140
},
119141
RoomVersionV5: {
@@ -126,8 +148,8 @@ var roomVersionMeta = map[RoomVersion]RoomVersionDescription{
126148
enforceSignatureChecks: true,
127149
enforceCanonicalJSON: false,
128150
powerLevelsIncludeNotifications: false,
129-
allowKnockingInEventAuth: false,
130-
allowRestrictedJoinsInEventAuth: false,
151+
allowKnockingInEventAuth: KnocksForbidden,
152+
allowRestrictedJoinsInEventAuth: NoRestrictedJoins,
131153
requireIntegerPowerLevels: false,
132154
},
133155
RoomVersionV6: {
@@ -140,8 +162,8 @@ var roomVersionMeta = map[RoomVersion]RoomVersionDescription{
140162
enforceSignatureChecks: true,
141163
enforceCanonicalJSON: true,
142164
powerLevelsIncludeNotifications: true,
143-
allowKnockingInEventAuth: false,
144-
allowRestrictedJoinsInEventAuth: false,
165+
allowKnockingInEventAuth: KnocksForbidden,
166+
allowRestrictedJoinsInEventAuth: NoRestrictedJoins,
145167
requireIntegerPowerLevels: false,
146168
},
147169
RoomVersionV7: {
@@ -154,8 +176,8 @@ var roomVersionMeta = map[RoomVersion]RoomVersionDescription{
154176
enforceSignatureChecks: true,
155177
enforceCanonicalJSON: true,
156178
powerLevelsIncludeNotifications: true,
157-
allowKnockingInEventAuth: true,
158-
allowRestrictedJoinsInEventAuth: false,
179+
allowKnockingInEventAuth: KnockOnly,
180+
allowRestrictedJoinsInEventAuth: NoRestrictedJoins,
159181
requireIntegerPowerLevels: false,
160182
},
161183
RoomVersionV8: {
@@ -168,8 +190,8 @@ var roomVersionMeta = map[RoomVersion]RoomVersionDescription{
168190
enforceSignatureChecks: true,
169191
enforceCanonicalJSON: true,
170192
powerLevelsIncludeNotifications: true,
171-
allowKnockingInEventAuth: true,
172-
allowRestrictedJoinsInEventAuth: true,
193+
allowKnockingInEventAuth: KnocksForbidden,
194+
allowRestrictedJoinsInEventAuth: RestrictedOnly,
173195
requireIntegerPowerLevels: false,
174196
},
175197
RoomVersionV9: {
@@ -182,8 +204,8 @@ var roomVersionMeta = map[RoomVersion]RoomVersionDescription{
182204
enforceSignatureChecks: true,
183205
enforceCanonicalJSON: true,
184206
powerLevelsIncludeNotifications: true,
185-
allowKnockingInEventAuth: true,
186-
allowRestrictedJoinsInEventAuth: true,
207+
allowKnockingInEventAuth: KnocksForbidden,
208+
allowRestrictedJoinsInEventAuth: RestrictedOnly,
187209
requireIntegerPowerLevels: false,
188210
},
189211
"org.matrix.msc3667": { // based on room version 7
@@ -196,10 +218,24 @@ var roomVersionMeta = map[RoomVersion]RoomVersionDescription{
196218
enforceSignatureChecks: true,
197219
enforceCanonicalJSON: true,
198220
powerLevelsIncludeNotifications: true,
199-
allowKnockingInEventAuth: true,
200-
allowRestrictedJoinsInEventAuth: false,
221+
allowKnockingInEventAuth: KnockOnly,
222+
allowRestrictedJoinsInEventAuth: NoRestrictedJoins,
201223
requireIntegerPowerLevels: true,
202224
},
225+
"org.matrix.msc3787": { // roughly, the union of v7 and v9
226+
Supported: true,
227+
Stable: false,
228+
stateResAlgorithm: StateResV2,
229+
eventFormat: EventFormatV2,
230+
eventIDFormat: EventIDFormatV3,
231+
redactionAlgorithm: RedactionAlgorithmV4,
232+
enforceSignatureChecks: true,
233+
enforceCanonicalJSON: true,
234+
powerLevelsIncludeNotifications: true,
235+
allowKnockingInEventAuth: KnockOrKnockRestricted,
236+
allowRestrictedJoinsInEventAuth: RestrictedOrKnockRestricted,
237+
requireIntegerPowerLevels: false,
238+
},
203239
}
204240

205241
// RoomVersions returns information about room versions currently
@@ -249,11 +285,11 @@ type RoomVersionDescription struct {
249285
eventFormat EventFormat
250286
eventIDFormat EventIDFormat
251287
redactionAlgorithm RedactionAlgorithm
288+
allowKnockingInEventAuth JoinRulesPermittingKnockInEventAuth
289+
allowRestrictedJoinsInEventAuth JoinRulesPermittingRestrictedJoinInEventAuth
252290
enforceSignatureChecks bool
253291
enforceCanonicalJSON bool
254292
powerLevelsIncludeNotifications bool
255-
allowKnockingInEventAuth bool
256-
allowRestrictedJoinsInEventAuth bool
257293
requireIntegerPowerLevels bool
258294
Supported bool
259295
Stable bool
@@ -309,20 +345,50 @@ func (v RoomVersion) PowerLevelsIncludeNotifications() (bool, error) {
309345
return false, UnsupportedRoomVersionError{v}
310346
}
311347

312-
// AllowKnockingInEventAuth returns true if the given room version allows for
313-
// the `knock` membership state or false otherwise.
314-
func (v RoomVersion) AllowKnockingInEventAuth() (bool, error) {
348+
// AllowKnockingInEventAuth returns true if the given room version and given
349+
// join rule allows for the `knock` membership state or false otherwise.
350+
func (v RoomVersion) AllowKnockingInEventAuth(joinRule string) (bool, error) {
315351
if r, ok := roomVersionMeta[v]; ok {
316-
return r.allowKnockingInEventAuth, nil
352+
switch r.allowKnockingInEventAuth {
353+
case KnockOnly:
354+
return joinRule == Knock, nil
355+
case KnockOrKnockRestricted:
356+
return (joinRule == Knock || joinRule == KnockRestricted), nil
357+
case KnocksForbidden:
358+
return false, nil
359+
}
317360
}
318361
return false, UnsupportedRoomVersionError{v}
319362
}
320363

321-
// AllowRestrictedJoinsInEventAuth returns true if the given room version allows
322-
// for memberships signed by servers in the restricted join rules.
323-
func (v RoomVersion) AllowRestrictedJoinsInEventAuth() (bool, error) {
364+
// AllowRestrictedJoinsInEventAuth returns true if the given room version and
365+
// join rule allows for memberships signed by servers in the restricted join rules.
366+
func (v RoomVersion) AllowRestrictedJoinsInEventAuth(joinRule string) (bool, error) {
324367
if r, ok := roomVersionMeta[v]; ok {
325-
return r.allowRestrictedJoinsInEventAuth, nil
368+
switch r.allowRestrictedJoinsInEventAuth {
369+
case NoRestrictedJoins:
370+
return false, nil
371+
case RestrictedOnly:
372+
return joinRule == Restricted, nil
373+
case RestrictedOrKnockRestricted:
374+
return (joinRule == Restricted || joinRule == KnockRestricted), nil
375+
}
376+
}
377+
return false, UnsupportedRoomVersionError{v}
378+
}
379+
380+
// MayAllowRestrictedJoinsInEventAuth returns true if the given room version
381+
// might allow for memberships signed by servers in the restricted join rules.
382+
// (For an authoritative answer, the room's join rules must be known. If they
383+
// are, use AllowRestrictedJoinsInEventAuth.)
384+
func (v RoomVersion) MayAllowRestrictedJoinsInEventAuth() (bool, error) {
385+
if r, ok := roomVersionMeta[v]; ok {
386+
switch r.allowRestrictedJoinsInEventAuth {
387+
case NoRestrictedJoins:
388+
return false, nil
389+
case RestrictedOnly, RestrictedOrKnockRestricted:
390+
return true, nil
391+
}
326392
}
327393
return false, UnsupportedRoomVersionError{v}
328394
}

0 commit comments

Comments
 (0)