id: move room version from event package and add flags

This commit is contained in:
Tulir Asokan 2025-08-03 11:51:47 +03:00
commit e27e00b391
7 changed files with 298 additions and 34 deletions

View file

@ -4296,7 +4296,7 @@ func (portal *Portal) createMatrixRoomInLoop(ctx context.Context, source *UserLo
IsDirect: portal.RoomType == database.RoomTypeDM,
PowerLevelOverride: powerLevels,
BeeperLocalRoomID: portal.Bridge.Matrix.GenerateDeterministicRoomID(portal.PortalKey),
RoomVersion: event.RoomV11,
RoomVersion: id.RoomV11,
}
autoJoinInvites := portal.Bridge.Matrix.GetCapabilities().AutoJoinInvites
if autoJoinInvites {

View file

@ -164,7 +164,7 @@ func (ul *UserLogin) GetSpaceRoom(ctx context.Context) (id.RoomID, error) {
ul.UserMXID: 50,
},
},
RoomVersion: event.RoomV11,
RoomVersion: id.RoomV11,
Invite: []id.UserID{ul.UserMXID},
}
if autoJoin {

View file

@ -225,7 +225,7 @@ func (user *User) GetManagementRoom(ctx context.Context) (id.RoomID, error) {
user.MXID: 50,
},
},
RoomVersion: event.RoomV11,
RoomVersion: id.RoomV11,
Invite: []id.UserID{user.MXID},
IsDirect: true,
}

View file

@ -75,30 +75,32 @@ type Predecessor struct {
EventID id.EventID `json:"event_id"`
}
type RoomVersion string
// Deprecated: use id.RoomVersion instead
type RoomVersion = id.RoomVersion
// Deprecated: use id.RoomVX constants instead
const (
RoomV1 RoomVersion = "1"
RoomV2 RoomVersion = "2"
RoomV3 RoomVersion = "3"
RoomV4 RoomVersion = "4"
RoomV5 RoomVersion = "5"
RoomV6 RoomVersion = "6"
RoomV7 RoomVersion = "7"
RoomV8 RoomVersion = "8"
RoomV9 RoomVersion = "9"
RoomV10 RoomVersion = "10"
RoomV11 RoomVersion = "11"
RoomV12 RoomVersion = "12"
RoomV1 = id.RoomV1
RoomV2 = id.RoomV2
RoomV3 = id.RoomV3
RoomV4 = id.RoomV4
RoomV5 = id.RoomV5
RoomV6 = id.RoomV6
RoomV7 = id.RoomV7
RoomV8 = id.RoomV8
RoomV9 = id.RoomV9
RoomV10 = id.RoomV10
RoomV11 = id.RoomV11
RoomV12 = id.RoomV12
)
// CreateEventContent represents the content of a m.room.create state event.
// https://spec.matrix.org/v1.2/client-server-api/#mroomcreate
type CreateEventContent struct {
Type RoomType `json:"type,omitempty"`
Federate *bool `json:"m.federate,omitempty"`
RoomVersion RoomVersion `json:"room_version,omitempty"`
Predecessor *Predecessor `json:"predecessor,omitempty"`
Type RoomType `json:"type,omitempty"`
Federate *bool `json:"m.federate,omitempty"`
RoomVersion id.RoomVersion `json:"room_version,omitempty"`
Predecessor *Predecessor `json:"predecessor,omitempty"`
// Room v12+ only
AdditionalCreators []id.UserID `json:"additional_creators,omitempty"`
@ -108,13 +110,10 @@ type CreateEventContent struct {
}
func (cec *CreateEventContent) SupportsCreatorPower() bool {
switch cec.RoomVersion {
case "", RoomV1, RoomV2, RoomV3, RoomV4, RoomV5, RoomV6, RoomV7, RoomV8, RoomV9, RoomV10, RoomV11:
if cec == nil {
return false
default:
// Assume anything except known old versions supports creator power.
return true
}
return cec.RoomVersion.PrivilegedRoomCreators()
}
// JoinRule specifies how open a room is to new members.

265
id/roomversion.go Normal file
View file

@ -0,0 +1,265 @@
// Copyright (c) 2025 Tulir Asokan
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package id
import (
"errors"
"fmt"
"slices"
)
type RoomVersion string
const (
RoomV0 RoomVersion = "" // No room version, used for rooms created before room versions were introduced, equivalent to v1
RoomV1 RoomVersion = "1"
RoomV2 RoomVersion = "2"
RoomV3 RoomVersion = "3"
RoomV4 RoomVersion = "4"
RoomV5 RoomVersion = "5"
RoomV6 RoomVersion = "6"
RoomV7 RoomVersion = "7"
RoomV8 RoomVersion = "8"
RoomV9 RoomVersion = "9"
RoomV10 RoomVersion = "10"
RoomV11 RoomVersion = "11"
RoomV12 RoomVersion = "12"
)
func (rv RoomVersion) Equals(versions ...RoomVersion) bool {
return slices.Contains(versions, rv)
}
func (rv RoomVersion) NotEquals(versions ...RoomVersion) bool {
return !rv.Equals(versions...)
}
var ErrUnknownRoomVersion = errors.New("unknown room version")
func (rv RoomVersion) unknownVersionError() error {
return fmt.Errorf("%w %s", ErrUnknownRoomVersion, rv)
}
func (rv RoomVersion) IsKnown() bool {
switch rv {
case RoomV0, RoomV1, RoomV2, RoomV3, RoomV4, RoomV5, RoomV6, RoomV7, RoomV8, RoomV9, RoomV10, RoomV11, RoomV12:
return true
default:
return false
}
}
type StateResVersion int
const (
// StateResV1 is the original state resolution algorithm.
StateResV1 StateResVersion = 0
// StateResV2 is state resolution v2 introduced by https://github.com/matrix-org/matrix-spec-proposals/pull/1759
StateResV2 StateResVersion = 1
// StateResV2_1 is state resolution v2.1 introduced by https://github.com/matrix-org/matrix-spec-proposals/pull/4297
StateResV2_1 StateResVersion = 2
)
// StateResVersion returns the version of the state resolution algorithm used by this room version.
func (rv RoomVersion) StateResVersion() StateResVersion {
switch rv {
case RoomV0, RoomV1:
return StateResV1
case RoomV2, RoomV3, RoomV4, RoomV5, RoomV6, RoomV7, RoomV8, RoomV9, RoomV10, RoomV11:
return StateResV2
case RoomV12:
return StateResV2_1
default:
panic(rv.unknownVersionError())
}
}
type EventIDFormat int
const (
// EventIDFormatCustom is the original format used by room v1 and v2.
// Event IDs in this format are an arbitrary string followed by a colon and the server name.
EventIDFormatCustom EventIDFormat = 0
// EventIDFormatBase64 is the format used by room v3 introduced by https://github.com/matrix-org/matrix-spec-proposals/pull/1659.
// Event IDs in this format are the standard unpadded base64-encoded SHA256 reference hash of the event.
EventIDFormatBase64 EventIDFormat = 1
// EventIDFormatURLSafeBase64 is the format used by room v4 and later introduced by https://github.com/matrix-org/matrix-spec-proposals/pull/2002.
// Event IDs in this format are the url-safe unpadded base64-encoded SHA256 reference hash of the event.
EventIDFormatURLSafeBase64 EventIDFormat = 2
)
// EventIDFormat returns the format of event IDs used by this room version.
func (rv RoomVersion) EventIDFormat() EventIDFormat {
switch rv {
case RoomV0, RoomV1, RoomV2:
return EventIDFormatCustom
case RoomV3:
return EventIDFormatBase64
default:
return EventIDFormatURLSafeBase64
}
}
/////////////////////
// Room v5 changes //
/////////////////////
// https://github.com/matrix-org/matrix-spec-proposals/pull/2077
// EnforceSigningKeyValidity returns true if the `valid_until_ts` field of federation signing keys
// must be enforced on received events.
//
// See https://github.com/matrix-org/matrix-spec-proposals/pull/2076
func (rv RoomVersion) EnforceSigningKeyValidity() bool {
return rv.NotEquals(RoomV0, RoomV1, RoomV2, RoomV3, RoomV4)
}
/////////////////////
// Room v6 changes //
/////////////////////
// https://github.com/matrix-org/matrix-spec-proposals/pull/2240
// SpecialCasedAliasesAuth returns true if the `m.room.aliases` event authorization is special cased
// to only always allow servers to modify the state event with their own server name as state key.
// This also implies that the `aliases` field is protected from redactions.
//
// See https://github.com/matrix-org/matrix-spec-proposals/pull/2432
func (rv RoomVersion) SpecialCasedAliasesAuth() bool {
return rv.Equals(RoomV0, RoomV1, RoomV2, RoomV3, RoomV4, RoomV5)
}
// ForbidFloatsAndBigInts returns true if floats and integers greater than 2^53-1 or lower than -2^53+1 are forbidden everywhere.
//
// See https://github.com/matrix-org/matrix-spec-proposals/pull/2540
func (rv RoomVersion) ForbidFloatsAndBigInts() bool {
return rv.NotEquals(RoomV0, RoomV1, RoomV2, RoomV3, RoomV4, RoomV5)
}
// NotificationsPowerLevels returns true if the `notifications` field in `m.room.power_levels` is validated in event auth.
// However, the field is not protected from redactions.
//
// See https://github.com/matrix-org/matrix-spec-proposals/pull/2209
func (rv RoomVersion) NotificationsPowerLevels() bool {
return rv.NotEquals(RoomV0, RoomV1, RoomV2, RoomV3, RoomV4, RoomV5)
}
/////////////////////
// Room v7 changes //
/////////////////////
// https://github.com/matrix-org/matrix-spec-proposals/pull/2998
// Knocks returns true if the `knock` join rule is supported.
//
// See https://github.com/matrix-org/matrix-spec-proposals/pull/2403
func (rv RoomVersion) Knocks() bool {
return rv.NotEquals(RoomV0, RoomV1, RoomV2, RoomV3, RoomV4, RoomV5, RoomV6)
}
/////////////////////
// Room v8 changes //
/////////////////////
// https://github.com/matrix-org/matrix-spec-proposals/pull/3289
// RestrictedJoins returns true if the `restricted` join rule is supported.
// This also implies that the `allow` field in the `m.room.join_rules` event is supported and protected from redactions.
//
// See https://github.com/matrix-org/matrix-spec-proposals/pull/3083
func (rv RoomVersion) RestrictedJoins() bool {
return rv.NotEquals(RoomV0, RoomV1, RoomV2, RoomV3, RoomV4, RoomV5, RoomV6, RoomV7)
}
/////////////////////
// Room v9 changes //
/////////////////////
// https://github.com/matrix-org/matrix-spec-proposals/pull/3375
// RestrictedJoinsFix returns true if the `join_authorised_via_users_server` field in `m.room.member` events is protected from redactions.
//
// See https://github.com/matrix-org/matrix-spec-proposals/pull/3375
func (rv RoomVersion) RestrictedJoinsFix() bool {
return rv.RestrictedJoins() && rv != RoomV8
}
//////////////////////
// Room v10 changes //
//////////////////////
// https://github.com/matrix-org/matrix-spec-proposals/pull/3604
// ValidatePowerLevelInts returns true if the known values in `m.room.power_levels` must be integers (and not strings).
//
// See https://github.com/matrix-org/matrix-spec-proposals/pull/3667
func (rv RoomVersion) ValidatePowerLevelInts() bool {
return rv.NotEquals(RoomV0, RoomV1, RoomV2, RoomV3, RoomV4, RoomV5, RoomV6, RoomV7, RoomV8, RoomV9)
}
// KnockRestricted returns true if the `knock_restricted` join rule is supported.
//
// See https://github.com/matrix-org/matrix-spec-proposals/pull/3787
func (rv RoomVersion) KnockRestricted() bool {
return rv.NotEquals(RoomV0, RoomV1, RoomV2, RoomV3, RoomV4, RoomV5, RoomV6, RoomV7, RoomV8, RoomV9)
}
//////////////////////
// Room v11 changes //
//////////////////////
// https://github.com/matrix-org/matrix-spec-proposals/pull/3820
// CreatorInContent returns true if the `m.room.create` event has a `creator` field in content.
//
// See https://github.com/matrix-org/matrix-spec-proposals/pull/2175
func (rv RoomVersion) CreatorInContent() bool {
return rv.Equals(RoomV0, RoomV1, RoomV2, RoomV3, RoomV4, RoomV5, RoomV6, RoomV7, RoomV8, RoomV9, RoomV10)
}
// RedactsInContent returns true if the `m.room.redaction` event has the `redacts` field in content instead of at the top level.
// The redaction protection is also moved from the top level to the content field.
//
// See https://github.com/matrix-org/matrix-spec-proposals/pull/2174
// (and https://github.com/matrix-org/matrix-spec-proposals/pull/2176 for the redaction protection).
func (rv RoomVersion) RedactsInContent() bool {
return rv.NotEquals(RoomV0, RoomV1, RoomV2, RoomV3, RoomV4, RoomV5, RoomV6, RoomV7, RoomV8, RoomV9, RoomV10)
}
// UpdatedRedactionRules returns true if various updates to the redaction algorithm are applied.
//
// Specifically:
//
// * the `membership`, `origin`, and `prev_state` fields at the top level of all events are no longer protected.
// * the entire content of `m.room.create` is protected.
// * the `redacts` field in `m.room.redaction` content is protected instead of the top-level field.
// * the `m.room.power_levels` event protects the `invite` field in content.
// * the `signed` field inside the `third_party_invite` field in content of `m.room.member` events is protected.
//
// See https://github.com/matrix-org/matrix-spec-proposals/pull/2176,
// https://github.com/matrix-org/matrix-spec-proposals/pull/3821, and
// https://github.com/matrix-org/matrix-spec-proposals/pull/3989
func (rv RoomVersion) UpdatedRedactionRules() bool {
return rv.NotEquals(RoomV0, RoomV1, RoomV2, RoomV3, RoomV4, RoomV5, RoomV6, RoomV7, RoomV8, RoomV9, RoomV10)
}
//////////////////////
// Room v12 changes //
//////////////////////
// https://github.com/matrix-org/matrix-spec-proposals/pull/4304
// Return value of StateResVersion was changed to StateResV2_1
// PrivilegedRoomCreators returns true if the creator(s) of a room always have infinite power level.
// This also implies that the `m.room.create` event has an `additional_creators` field,
// and that the creators can't be present in the `m.room.power_levels` event.
//
// See https://github.com/matrix-org/matrix-spec-proposals/pull/4289
func (rv RoomVersion) PrivilegedRoomCreators() bool {
return rv.NotEquals(RoomV0, RoomV1, RoomV2, RoomV3, RoomV4, RoomV5, RoomV6, RoomV7, RoomV8, RoomV9, RoomV10, RoomV11)
}
// RoomIDIsCreateEventID returns true if the ID of rooms is the same as the ID of the `m.room.create` event.
// This also implies that `m.room.create` events do not have a `room_id` field.
//
// See https://github.com/matrix-org/matrix-spec-proposals/pull/4291
func (rv RoomVersion) RoomIDIsCreateEventID() bool {
return rv.NotEquals(RoomV0, RoomV1, RoomV2, RoomV3, RoomV4, RoomV5, RoomV6, RoomV7, RoomV8, RoomV9, RoomV10, RoomV11)
}

View file

@ -120,7 +120,7 @@ type ReqCreateRoom struct {
InitialState []*event.Event `json:"initial_state,omitempty"`
Preset string `json:"preset,omitempty"`
IsDirect bool `json:"is_direct,omitempty"`
RoomVersion event.RoomVersion `json:"room_version,omitempty"`
RoomVersion id.RoomVersion `json:"room_version,omitempty"`
PowerLevelOverride *event.PowerLevelsEventContent `json:"power_level_content_override,omitempty"`

View file

@ -221,14 +221,14 @@ type RespMutualRooms struct {
type RespRoomSummary struct {
PublicRoomInfo
Membership event.Membership `json:"membership,omitempty"`
RoomVersion event.RoomVersion `json:"room_version,omitempty"`
Encryption id.Algorithm `json:"encryption,omitempty"`
AllowedRoomIDs []id.RoomID `json:"allowed_room_ids,omitempty"`
Membership event.Membership `json:"membership,omitempty"`
RoomVersion id.RoomVersion `json:"room_version,omitempty"`
Encryption id.Algorithm `json:"encryption,omitempty"`
AllowedRoomIDs []id.RoomID `json:"allowed_room_ids,omitempty"`
UnstableRoomVersion event.RoomVersion `json:"im.nheko.summary.room_version,omitempty"`
UnstableRoomVersionOld event.RoomVersion `json:"im.nheko.summary.version,omitempty"`
UnstableEncryption id.Algorithm `json:"im.nheko.summary.encryption,omitempty"`
UnstableRoomVersion id.RoomVersion `json:"im.nheko.summary.room_version,omitempty"`
UnstableRoomVersionOld id.RoomVersion `json:"im.nheko.summary.version,omitempty"`
UnstableEncryption id.Algorithm `json:"im.nheko.summary.encryption,omitempty"`
}
// RespRegisterAvailable is the JSON response for https://spec.matrix.org/v1.4/client-server-api/#get_matrixclientv3registeravailable