Skip to content
This repository has been archived by the owner on Nov 25, 2024. It is now read-only.

Support initial_state properly in /createRoom #1932

Merged
merged 8 commits into from
Jul 21, 2021
Merged
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
215 changes: 156 additions & 59 deletions clientapi/routing/createroom.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ type createRoomRequest struct {
Visibility string `json:"visibility"`
Topic string `json:"topic"`
Preset string `json:"preset"`
CreationContent map[string]interface{} `json:"creation_content"`
CreationContent json.RawMessage `json:"creation_content"`
InitialState []fledglingEvent `json:"initial_state"`
RoomAliasName string `json:"room_alias_name"`
GuestCanJoin bool `json:"guest_can_join"`
Expand Down Expand Up @@ -177,11 +177,6 @@ func createRoom(

// Clobber keys: creator, room_version

if r.CreationContent == nil {
r.CreationContent = make(map[string]interface{}, 2)
}

r.CreationContent["creator"] = userID
roomVersion := roomserverVersion.DefaultRoomVersion()
if r.RoomVersion != "" {
candidateVersion := gomatrixserverlib.RoomVersion(r.RoomVersion)
Expand All @@ -194,7 +189,6 @@ func createRoom(
}
roomVersion = candidateVersion
}
r.CreationContent["room_version"] = roomVersion

// TODO: visibility/presets/raw initial state
// TODO: Create room alias association
Expand All @@ -203,7 +197,7 @@ func createRoom(
logger.WithFields(log.Fields{
"userID": userID,
"roomID": roomID,
"roomVersion": r.CreationContent["room_version"],
"roomVersion": roomVersion,
}).Info("Creating new room")

profile, err := appserviceAPI.RetrieveUserProfile(req.Context(), userID, asAPI, accountDB)
Expand All @@ -212,6 +206,109 @@ func createRoom(
return jsonerror.InternalServerError()
}

createContent := map[string]interface{}{}
if len(r.CreationContent) > 0 {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just have this inlined in the struct as it was before?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There seems to be sytests for being able to put arbitrary fields into the create event. If we use the struct then they get stripped marshalling in/out of the struct.

if err = json.Unmarshal(r.CreationContent, &createContent); err != nil {
util.GetLogger(req.Context()).WithError(err).Error("json.Unmarshal for creation_content failed")
return util.JSONResponse{
Code: http.StatusBadRequest,
JSON: jsonerror.BadJSON("invalid create content"),
}
}
}
createContent["creator"] = userID
createContent["room_version"] = roomVersion
powerLevelContent := eventutil.InitialPowerLevelsContent(userID)
joinRuleContent := gomatrixserverlib.JoinRuleContent{
JoinRule: gomatrixserverlib.Invite,
}
historyVisibilityContent := gomatrixserverlib.HistoryVisibilityContent{
HistoryVisibility: historyVisibilityShared,
}

if r.PowerLevelContentOverride != nil {
// Merge powerLevelContentOverride fields by unmarshalling it atop the defaults
err = json.Unmarshal(r.PowerLevelContentOverride, &powerLevelContent)
if err != nil {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we log these somewhere as it's annoying to not see what the err is.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, done!

util.GetLogger(req.Context()).WithError(err).Error("json.Unmarshal for power_level_content_override failed")
return util.JSONResponse{
Code: http.StatusBadRequest,
JSON: jsonerror.BadJSON("malformed power_level_content_override"),
}
}
}

switch r.Preset {
case presetPrivateChat:
joinRuleContent.JoinRule = gomatrixserverlib.Invite
historyVisibilityContent.HistoryVisibility = historyVisibilityShared
case presetTrustedPrivateChat:
joinRuleContent.JoinRule = gomatrixserverlib.Invite
historyVisibilityContent.HistoryVisibility = historyVisibilityShared
// TODO If trusted_private_chat, all invitees are given the same power level as the room creator.
case presetPublicChat:
joinRuleContent.JoinRule = gomatrixserverlib.Public
historyVisibilityContent.HistoryVisibility = historyVisibilityShared
}

createEvent := fledglingEvent{
Type: gomatrixserverlib.MRoomCreate,
Content: createContent,
}
powerLevelEvent := fledglingEvent{
Type: gomatrixserverlib.MRoomPowerLevels,
Content: powerLevelContent,
}
joinRuleEvent := fledglingEvent{
Type: gomatrixserverlib.MRoomJoinRules,
Content: joinRuleContent,
}
historyVisibilityEvent := fledglingEvent{
Type: gomatrixserverlib.MRoomHistoryVisibility,
Content: historyVisibilityContent,
}
membershipEvent := fledglingEvent{
Type: gomatrixserverlib.MRoomMember,
StateKey: userID,
Content: gomatrixserverlib.MemberContent{
Membership: gomatrixserverlib.Join,
DisplayName: profile.DisplayName,
AvatarURL: profile.AvatarURL,
},
}

var nameEvent *fledglingEvent
var topicEvent *fledglingEvent
var guestAccessEvent *fledglingEvent
var aliasEvent *fledglingEvent

if r.Name != "" {
nameEvent = &fledglingEvent{
Type: gomatrixserverlib.MRoomName,
Content: eventutil.NameContent{
Name: r.Name,
},
}
}

if r.Topic != "" {
topicEvent = &fledglingEvent{
Type: gomatrixserverlib.MRoomTopic,
Content: eventutil.TopicContent{
Topic: r.Topic,
},
}
}

if r.GuestCanJoin {
guestAccessEvent = &fledglingEvent{
Type: gomatrixserverlib.MRoomGuestAccess,
Content: eventutil.GuestAccessContent{
GuestAccess: "can_join",
},
}
}

var roomAlias string
if r.RoomAliasName != "" {
roomAlias = fmt.Sprintf("#%s:%s", r.RoomAliasName, cfg.Matrix.ServerName)
Expand All @@ -230,44 +327,46 @@ func createRoom(
if aliasResp.RoomID != "" {
return util.MessageResponse(400, "Alias already exists")
}
}

membershipContent := gomatrixserverlib.MemberContent{
Membership: gomatrixserverlib.Join,
DisplayName: profile.DisplayName,
AvatarURL: profile.AvatarURL,
aliasEvent = &fledglingEvent{
Type: gomatrixserverlib.MRoomCanonicalAlias,
Content: eventutil.CanonicalAlias{
Alias: roomAlias,
},
}
}

var joinRules, historyVisibility string
switch r.Preset {
case presetPrivateChat:
joinRules = gomatrixserverlib.Invite
historyVisibility = historyVisibilityShared
case presetTrustedPrivateChat:
joinRules = gomatrixserverlib.Invite
historyVisibility = historyVisibilityShared
// TODO If trusted_private_chat, all invitees are given the same power level as the room creator.
case presetPublicChat:
joinRules = gomatrixserverlib.Public
historyVisibility = historyVisibilityShared
default:
// Default room rules, r.Preset was previously checked for valid values so
// only a request with no preset should end up here.
joinRules = gomatrixserverlib.Invite
historyVisibility = historyVisibilityShared
}
var initialStateEvents []fledglingEvent
for i := range r.InitialState {
if r.InitialState[i].StateKey != "" {
initialStateEvents = append(initialStateEvents, r.InitialState[i])
continue
}

var builtEvents []*gomatrixserverlib.HeaderedEvent
switch r.InitialState[i].Type {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not enough to do this, we need to check that r.InitialState.StateKey == "" as well, else append them to the list.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, added.

case gomatrixserverlib.MRoomCreate:
continue

powerLevelContent := eventutil.InitialPowerLevelsContent(userID)
if r.PowerLevelContentOverride != nil {
// Merge powerLevelContentOverride fields by unmarshalling it atop the defaults
err = json.Unmarshal(r.PowerLevelContentOverride, &powerLevelContent)
if err != nil {
return util.JSONResponse{
Code: http.StatusBadRequest,
JSON: jsonerror.BadJSON("malformed power_level_content_override"),
}
case gomatrixserverlib.MRoomPowerLevels:
powerLevelEvent = r.InitialState[i]

case gomatrixserverlib.MRoomJoinRules:
joinRuleEvent = r.InitialState[i]

case gomatrixserverlib.MRoomHistoryVisibility:
historyVisibilityEvent = r.InitialState[i]

case gomatrixserverlib.MRoomGuestAccess:
guestAccessEvent = &r.InitialState[i]

case gomatrixserverlib.MRoomName:
nameEvent = &r.InitialState[i]

case gomatrixserverlib.MRoomTopic:
topicEvent = &r.InitialState[i]

default:
initialStateEvents = append(initialStateEvents, r.InitialState[i])
}
}

Expand All @@ -290,31 +389,29 @@ func createRoom(
// harder to reason about, hence sticking to a strict static ordering.
// TODO: Synapse has txn/token ID on each event. Do we need to do this here?
eventsToMake := []fledglingEvent{
{"m.room.create", "", r.CreationContent},
{"m.room.member", userID, membershipContent},
{"m.room.power_levels", "", powerLevelContent},
{"m.room.join_rules", "", gomatrixserverlib.JoinRuleContent{JoinRule: joinRules}},
{"m.room.history_visibility", "", eventutil.HistoryVisibilityContent{HistoryVisibility: historyVisibility}},
createEvent, membershipEvent, powerLevelEvent, joinRuleEvent, historyVisibilityEvent,
}
if roomAlias != "" {
// TODO: bit of a chicken and egg problem here as the alias doesn't exist and cannot until we have made the room.
// This means we might fail creating the alias but say the canonical alias is something that doesn't exist.
// m.room.aliases is handled when we call roomserver.SetRoomAlias
eventsToMake = append(eventsToMake, fledglingEvent{"m.room.canonical_alias", "", eventutil.CanonicalAlias{Alias: roomAlias}})
if guestAccessEvent != nil {
eventsToMake = append(eventsToMake, *guestAccessEvent)
}
if r.GuestCanJoin {
eventsToMake = append(eventsToMake, fledglingEvent{"m.room.guest_access", "", eventutil.GuestAccessContent{GuestAccess: "can_join"}})
eventsToMake = append(eventsToMake, initialStateEvents...)
if nameEvent != nil {
eventsToMake = append(eventsToMake, *nameEvent)
}
eventsToMake = append(eventsToMake, r.InitialState...)
if r.Name != "" {
eventsToMake = append(eventsToMake, fledglingEvent{"m.room.name", "", eventutil.NameContent{Name: r.Name}})
if topicEvent != nil {
eventsToMake = append(eventsToMake, *topicEvent)
}
if r.Topic != "" {
eventsToMake = append(eventsToMake, fledglingEvent{"m.room.topic", "", eventutil.TopicContent{Topic: r.Topic}})
if aliasEvent != nil {
// TODO: bit of a chicken and egg problem here as the alias doesn't exist and cannot until we have made the room.
// This means we might fail creating the alias but say the canonical alias is something that doesn't exist.
// m.room.aliases is handled when we call roomserver.SetRoomAlias
eventsToMake = append(eventsToMake, *aliasEvent)
}

// TODO: invite events
// TODO: 3pid invite events

var builtEvents []*gomatrixserverlib.HeaderedEvent
authEvents := gomatrixserverlib.NewAuthEvents(nil)
for i, e := range eventsToMake {
depth := i + 1 // depth starts at 1
Expand Down Expand Up @@ -403,7 +500,7 @@ func createRoom(
fallthrough
case gomatrixserverlib.MRoomCanonicalAlias:
fallthrough
case "m.room.encryption": // TODO: move this to gmsl
case gomatrixserverlib.MRoomEncryption:
fallthrough
case gomatrixserverlib.MRoomMember:
fallthrough
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ require (
github.com/matrix-org/go-http-js-libp2p v0.0.0-20200518170932-783164aeeda4
github.com/matrix-org/go-sqlite3-js v0.0.0-20210709140738-b0d1ba599a6d
github.com/matrix-org/gomatrix v0.0.0-20210324163249-be2af5ef2e16
github.com/matrix-org/gomatrixserverlib v0.0.0-20210720141356-d52ec9c4dd2f
github.com/matrix-org/gomatrixserverlib v0.0.0-20210721094149-75792185bf42
github.com/matrix-org/naffka v0.0.0-20210623111924-14ff508b58e0
github.com/matrix-org/pinecone v0.0.0-20210623102758-74f885644c1b
github.com/matrix-org/util v0.0.0-20200807132607-55161520e1d4
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1027,8 +1027,8 @@ github.com/matrix-org/go-sqlite3-js v0.0.0-20210709140738-b0d1ba599a6d/go.mod h1
github.com/matrix-org/gomatrix v0.0.0-20190528120928-7df988a63f26/go.mod h1:3fxX6gUjWyI/2Bt7J1OLhpCzOfO/bB3AiX0cJtEKud0=
github.com/matrix-org/gomatrix v0.0.0-20210324163249-be2af5ef2e16 h1:ZtO5uywdd5dLDCud4r0r55eP4j9FuUNpl60Gmntcop4=
github.com/matrix-org/gomatrix v0.0.0-20210324163249-be2af5ef2e16/go.mod h1:/gBX06Kw0exX1HrwmoBibFA98yBk/jxKpGVeyQbff+s=
github.com/matrix-org/gomatrixserverlib v0.0.0-20210720141356-d52ec9c4dd2f h1:FP+tOVTX4mw4GPjHJE28UsPkw59ieISgjDtkCwb1vls=
github.com/matrix-org/gomatrixserverlib v0.0.0-20210720141356-d52ec9c4dd2f/go.mod h1:JsAzE1Ll3+gDWS9JSUHPJiiyAksvOOnGWF2nXdg4ZzU=
github.com/matrix-org/gomatrixserverlib v0.0.0-20210721094149-75792185bf42 h1:UsCdEX9G3svG07bBV8RKAWIyGzCgJpbX4BCP1n4ezH8=
github.com/matrix-org/gomatrixserverlib v0.0.0-20210721094149-75792185bf42/go.mod h1:JsAzE1Ll3+gDWS9JSUHPJiiyAksvOOnGWF2nXdg4ZzU=
github.com/matrix-org/naffka v0.0.0-20210623111924-14ff508b58e0 h1:HZCzy4oVzz55e+cOMiX/JtSF2UOY1evBl2raaE7ACcU=
github.com/matrix-org/naffka v0.0.0-20210623111924-14ff508b58e0/go.mod h1:sjyPyRxKM5uw1nD2cJ6O2OxI6GOqyVBfNXqKjBZTBZE=
github.com/matrix-org/pinecone v0.0.0-20210623102758-74f885644c1b h1:5X5vdWQ13xrNkJVqaJHPsrt7rKkMJH5iac0EtfOuxSg=
Expand Down