Skip to content

Add a way to set custom room version impls #455

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 28 additions & 15 deletions eventauth.go
Original file line number Diff line number Diff line change
Expand Up @@ -1158,7 +1158,12 @@
switch m.newMember.Membership {
case spec.Knock:
// Check if the given roomVersionImpl allows knocking.
return m.roomVersionImpl.CheckKnockingAllowed(m)
return m.roomVersionImpl.CheckKnockingAllowed(
string(m.roomVersionImpl.Version()),
m.senderID, m.targetID,
m.joinRule.JoinRule,
m.oldMember.Membership,
)
case spec.Join:
if m.joinRule.JoinRule == spec.Restricted || m.joinRule.JoinRule == spec.KnockRestricted {
if err := m.membershipAllowedSelfForRestrictedJoin(); err != nil {
Expand Down Expand Up @@ -1227,11 +1232,17 @@
return errorf("restricted joins are not supported in this room version")
}

func disallowKnocking(m *membershipAllower) error {
return m.membershipFailed(
"room version %q does not support knocking on rooms with join rule %q",
m.roomVersionImpl.Version(),
m.joinRule.JoinRule,
func disallowKnocking(roomVer, sender, target, joinRule, prevMembership string) error {
if sender == target {
return errorf(
"%q is not allowed to change their membership from %q as room version %q does not support knocking on rooms with join rule %q",
sender, prevMembership, roomVer, joinRule,
)
}

Check warning on line 1241 in eventauth.go

View check run for this annotation

Codecov / codecov/patch

eventauth.go#L1235-L1241

Added lines #L1235 - L1241 were not covered by tests

return errorf(
"%q is not allowed to change the membership of %q from %q as room version %q does not support knocking on rooms with join rule %q",
sender, target, prevMembership, roomVer, joinRule,

Check warning on line 1245 in eventauth.go

View check run for this annotation

Codecov / codecov/patch

eventauth.go#L1243-L1245

Added lines #L1243 - L1245 were not covered by tests
)
}

Expand All @@ -1242,23 +1253,25 @@
// MSC3787 extends this: the behaviour above is also permitted if the
// join rules are "knock_restricted"
// Spec: https://github.com/matrix-org/matrix-spec-proposals/pull/3787
func checkKnocking(m *membershipAllower) error {
func checkKnocking(roomVer, sender, target, joinRule, prevMembership string) error {
// If the join_rule is anything other than knock or knock_restricted, reject.
supported := m.joinRule.JoinRule == spec.Knock || m.joinRule.JoinRule == spec.KnockRestricted
supported := joinRule == spec.Knock || joinRule == spec.KnockRestricted
if !supported {
return m.membershipFailed(
"room version %q does not support knocking on rooms with join rule %q",
m.roomVersionImpl.Version(),
m.joinRule.JoinRule,
return errorf(
"%q is not allowed to change the membership of %q from %q as room version %q does not support knocking on rooms with join rule %q",
sender, target, prevMembership,
roomVer,
joinRule,

Check warning on line 1264 in eventauth.go

View check run for this annotation

Codecov / codecov/patch

eventauth.go#L1260-L1264

Added lines #L1260 - L1264 were not covered by tests
)
}
switch m.oldMember.Membership {
switch prevMembership {

case spec.Join, spec.Invite, spec.Ban:
// The user is already joined, invited or banned, therefore they
// can't knock.
return m.membershipFailed(
"sender is already joined/invited/banned",
return errorf(
"%q is not allowed to change the membership of %q from %q as sender is already joined/invited/banned",
sender, target, prevMembership,
)
}
// A non-joined, non-invited, non-banned user is allowed to knock.
Expand Down
18 changes: 18 additions & 0 deletions eventauth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1999,3 +1999,21 @@ func TestJoinRuleKnockRestricted(t *testing.T) {
}]
}`, RoomVersionV10)
}

type CustomVer struct {
IRoomVersion
}

func (v CustomVer) Version() RoomVersion {
return "hello"
}

func TestSetRoomVersion(t *testing.T) {
// ensure we can set and get custom room versions.
// GMSL doesn't use this but users of GMSL do.
v := CustomVer{
IRoomVersion: MustGetRoomVersion("10"),
}
SetRoomVersion(v)
MustGetRoomVersion("hello")
}
4 changes: 2 additions & 2 deletions eventcontent.go
Original file line number Diff line number Diff line change
Expand Up @@ -581,11 +581,11 @@
RelationType string `json:"rel_type"`
}

func noCheckCreateEvent(event PDU, knownRoomVersion knownRoomVersionFunc) error {
func noCheckCreateEvent(event PDU, knownRoomVersion KnownRoomVersionFunc) error {

Check warning on line 584 in eventcontent.go

View check run for this annotation

Codecov / codecov/patch

eventcontent.go#L584

Added line #L584 was not covered by tests
return nil
}

func checkCreateEvent(event PDU, knownRoomVersion knownRoomVersionFunc) error {
func checkCreateEvent(event PDU, knownRoomVersion KnownRoomVersionFunc) error {
c := struct {
Creator *string `json:"creator"`
RoomVersion *RoomVersion `json:"room_version"`
Expand Down
26 changes: 18 additions & 8 deletions eventversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import (
// RoomVersion refers to the room version for a specific room.
type RoomVersion string

// The interface which needs to be implemented to register a room version with gomatrixserverlib.
// All types should be public to allow for extensibility.
type IRoomVersion interface {
Version() RoomVersion
Stable() bool
Expand All @@ -29,14 +31,14 @@ type IRoomVersion interface {

RestrictedJoinServername(content []byte) (spec.ServerName, error)
CheckRestrictedJoinsAllowed() error
CheckKnockingAllowed(m *membershipAllower) error
CheckKnockingAllowed(roomVer, sender, target, joinRule, prevMembership string) error
CheckNotificationLevels(senderLevel int64, oldPowerLevels, newPowerLevels PowerLevelContent) error
CheckCanonicalJSON(input []byte) error
ParsePowerLevels(contentBytes []byte, c *PowerLevelContent) error
CheckCreateEvent(event PDU, knownRoomVersion knownRoomVersionFunc) error
CheckCreateEvent(event PDU, knownRoomVersion KnownRoomVersionFunc) error
}

type knownRoomVersionFunc func(RoomVersion) bool
type KnownRoomVersionFunc func(RoomVersion) bool

// StateResAlgorithm refers to a version of the state resolution algorithm.
type StateResAlgorithm int
Expand Down Expand Up @@ -416,6 +418,14 @@ func StableRoomVersions() map[RoomVersion]IRoomVersion {
return versions
}

// SetRoomVersion sets a room version implementation so it is recognised by gomatrixserverlib.
// This is useful when you are testing custom room versions which gomatrixserverlib may be unaware of,
// e.g for Complement usage. Full room version impls should be defined in gomatrixserverlib, but
// partial impls for testing can be set here.
func SetRoomVersion(ver IRoomVersion) {
roomVersionMeta[ver.Version()] = ver
}

// RoomVersionDescription contains information about a room version,
// namely whether it is marked as supported or stable in this server
// version, along with the state resolution algorithm, event ID etc
Expand All @@ -440,8 +450,8 @@ type RoomVersionImpl struct {
checkRestrictedJoin restrictedJoinCheckFunc
restrictedJoinServernameFunc func(content []byte) (spec.ServerName, error)
checkRestrictedJoinAllowedFunc func() error
checkKnockingAllowedFunc func(m *membershipAllower) error
checkCreateEvent func(e PDU, knownRoomVersion knownRoomVersionFunc) error
checkKnockingAllowedFunc func(roomVer, sender, target, joinRule, prevMembership string) error
checkCreateEvent func(e PDU, knownRoomVersion KnownRoomVersionFunc) error
newEventFromUntrustedJSONFunc func(eventJSON []byte, roomVersion IRoomVersion) (result PDU, err error)
newEventFromTrustedJSONFunc func(eventJSON []byte, redacted bool, roomVersion IRoomVersion) (result PDU, err error)
newEventFromTrustedJSONWithEventIDFunc func(eventID string, eventJSON []byte, redacted bool, roomVersion IRoomVersion) (result PDU, err error)
Expand Down Expand Up @@ -483,8 +493,8 @@ func (v RoomVersionImpl) CheckNotificationLevels(senderLevel int64, oldPowerLeve
}

// CheckKnockingAllowed checks if this room version supports knocking on rooms.
func (v RoomVersionImpl) CheckKnockingAllowed(m *membershipAllower) error {
return v.checkKnockingAllowedFunc(m)
func (v RoomVersionImpl) CheckKnockingAllowed(roomVer, sender, target, joinRule, prevMembership string) error {
return v.checkKnockingAllowedFunc(roomVer, sender, target, joinRule, prevMembership)
}

// CheckRestrictedJoinsAllowed checks if this room version allows restricted joins.
Expand All @@ -508,7 +518,7 @@ func (v RoomVersionImpl) ParsePowerLevels(contentBytes []byte, c *PowerLevelCont
return v.parsePowerLevelsFunc(contentBytes, c)
}

func (v RoomVersionImpl) CheckCreateEvent(event PDU, knownRoomVersion knownRoomVersionFunc) error {
func (v RoomVersionImpl) CheckCreateEvent(event PDU, knownRoomVersion KnownRoomVersionFunc) error {
return v.checkCreateEvent(event, knownRoomVersion)
}

Expand Down
Loading