diff --git a/config/bridge.go b/config/bridge.go index 02c3eeb..3046d92 100644 --- a/config/bridge.go +++ b/config/bridge.go @@ -1,5 +1,5 @@ // mautrix-whatsapp - A Matrix-WhatsApp puppeting bridge. -// Copyright (C) 2021 Tulir Asokan +// Copyright (C) 2023 Tulir Asokan // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -99,7 +99,7 @@ type BridgeConfig struct { DoublePuppetAllowDiscovery bool `yaml:"double_puppet_allow_discovery"` LoginSharedSecretMap map[string]string `yaml:"login_shared_secret_map"` - PrivateChatPortalMeta bool `yaml:"private_chat_portal_meta"` + PrivateChatPortalMeta string `yaml:"private_chat_portal_meta"` ParallelMemberSync bool `yaml:"parallel_member_sync"` BridgeNotices bool `yaml:"bridge_notices"` ResendBridgeInfo bool `yaml:"resend_bridge_info"` diff --git a/config/upgrade.go b/config/upgrade.go index 86cf6a0..4a137e6 100644 --- a/config/upgrade.go +++ b/config/upgrade.go @@ -77,7 +77,15 @@ func DoUpgrade(helper *up.Helper) { } else { helper.Copy(up.Map, "bridge", "login_shared_secret_map") } - helper.Copy(up.Bool, "bridge", "private_chat_portal_meta") + if legacyPrivateChatPortalMeta, ok := helper.Get(up.Bool, "bridge", "private_chat_portal_meta"); ok { + updatedPrivateChatPortalMeta := "default" + if legacyPrivateChatPortalMeta == "true" { + updatedPrivateChatPortalMeta = "always" + } + helper.Set(up.Str, updatedPrivateChatPortalMeta, "bridge", "private_chat_portal_meta") + } else { + helper.Copy(up.Str, "bridge", "private_chat_portal_meta") + } helper.Copy(up.Bool, "bridge", "parallel_member_sync") helper.Copy(up.Bool, "bridge", "bridge_notices") helper.Copy(up.Bool, "bridge", "resend_bridge_info") diff --git a/example-config.yaml b/example-config.yaml index dd96b9c..93f1eb8 100644 --- a/example-config.yaml +++ b/example-config.yaml @@ -254,9 +254,11 @@ bridge: # manually. login_shared_secret_map: example.com: foobar - # Should the bridge explicitly set the avatar and room name for private chat portal rooms? - # This is implicitly enabled in encrypted rooms. - private_chat_portal_meta: false + # Whether to explicitly set the avatar and room name for private chat portal rooms. + # If set to `default`, this will be enabled in encrypted rooms and disabled in unencrypted rooms. + # If set to `always`, all DM rooms will have explicit names and avatars set. + # If set to `never`, DM rooms will never have names and avatars set. + private_chat_portal_meta: default # Should group members be synced in parallel? This makes member sync faster parallel_member_sync: false # Should Matrix m.notice-type messages be bridged? diff --git a/matrix.go b/matrix.go index e249170..57552ad 100644 --- a/matrix.go +++ b/matrix.go @@ -67,16 +67,9 @@ func (br *WABridge) createPrivatePortalFromInvite(roomID id.RoomID, inviter *Use } portal.MXID = roomID portal.Topic = PrivateChatTopic - _, _ = portal.MainIntent().SetRoomTopic(portal.MXID, portal.Topic) - if portal.bridge.Config.Bridge.PrivateChatPortalMeta || br.Config.Bridge.Encryption.Default || encryptionEnabled { - portal.Name = puppet.Displayname - portal.AvatarURL = puppet.AvatarURL - portal.Avatar = puppet.Avatar - _, _ = portal.MainIntent().SetRoomName(portal.MXID, portal.Name) - _, _ = portal.MainIntent().SetRoomAvatar(portal.MXID, portal.AvatarURL) - } else { - portal.Name = "" - } + portal.Name = puppet.Displayname + portal.AvatarURL = puppet.AvatarURL + portal.Avatar = puppet.Avatar portal.log.Infofln("Created private chat portal in %s after invite from %s", roomID, inviter.MXID) intent := puppet.DefaultIntent() @@ -100,6 +93,13 @@ func (br *WABridge) createPrivatePortalFromInvite(roomID id.RoomID, inviter *Use br.AS.StateStore.SetMembership(roomID, br.Bot.UserID, event.MembershipJoin) portal.Encrypted = true } + _, _ = portal.MainIntent().SetRoomTopic(portal.MXID, portal.Topic) + if portal.shouldSetDMRoomMetadata() { + _, err = portal.MainIntent().SetRoomName(portal.MXID, portal.Name) + portal.NameSet = err == nil + _, err = portal.MainIntent().SetRoomAvatar(portal.MXID, portal.AvatarURL) + portal.AvatarSet = err == nil + } portal.Update(nil) portal.UpdateBridgeInfo() _, _ = intent.SendNotice(roomID, "Private chat portal created") diff --git a/portal.go b/portal.go index 3ae5e1b..4d3acf1 100644 --- a/portal.go +++ b/portal.go @@ -1156,7 +1156,7 @@ func (portal *Portal) UpdateName(name string, setBy types.JID, updateInfo bool) if name == "" && portal.IsBroadcastList() { name = UnnamedBroadcastName } - if portal.Name != name || (!portal.NameSet && len(portal.MXID) > 0) { + if portal.Name != name || (!portal.NameSet && len(portal.MXID) > 0 && portal.shouldSetDMRoomMetadata()) { portal.log.Debugfln("Updating name %q -> %q", portal.Name, name) portal.Name = name portal.NameSet = false @@ -1164,7 +1164,9 @@ func (portal *Portal) UpdateName(name string, setBy types.JID, updateInfo bool) defer portal.Update(nil) } - if len(portal.MXID) > 0 { + if len(portal.MXID) > 0 && !portal.shouldSetDMRoomMetadata() { + portal.UpdateBridgeInfo() + } else if len(portal.MXID) > 0 { intent := portal.MainIntent() if !setBy.IsEmpty() { intent = portal.bridge.GetPuppetByJID(setBy).IntentFor(portal) @@ -1497,6 +1499,12 @@ func (portal *Portal) updateChildRooms() { } } +func (portal *Portal) shouldSetDMRoomMetadata() bool { + return !portal.IsPrivateChat() || + portal.bridge.Config.Bridge.PrivateChatPortalMeta == "always" || + (portal.IsEncrypted() && portal.bridge.Config.Bridge.PrivateChatPortalMeta != "never") +} + func (portal *Portal) GetEncryptionEventContent() (evt *event.EncryptionEventContent) { evt = &event.EncryptionEventContent{Algorithm: id.AlgorithmMegolmV1} if rot := portal.bridge.Config.Bridge.Encryption.Rotation; rot.EnableCustom { @@ -1524,13 +1532,9 @@ func (portal *Portal) CreateMatrixRoom(user *User, groupInfo *types.GroupInfo, i if portal.IsPrivateChat() { puppet := portal.bridge.GetPuppetByJID(portal.Key.JID) puppet.SyncContact(user, true, false, "creating private chat portal") - if portal.bridge.Config.Bridge.PrivateChatPortalMeta || portal.bridge.Config.Bridge.Encryption.Default { - portal.Name = puppet.Displayname - portal.AvatarURL = puppet.AvatarURL - portal.Avatar = puppet.Avatar - } else { - portal.Name = "" - } + portal.Name = puppet.Displayname + portal.AvatarURL = puppet.AvatarURL + portal.Avatar = puppet.Avatar portal.Topic = PrivateChatTopic } else if portal.IsStatusBroadcastList() { if !portal.bridge.Config.Bridge.EnableStatusBroadcast { @@ -1616,18 +1620,7 @@ func (portal *Portal) CreateMatrixRoom(user *User, groupInfo *types.GroupInfo, i Content: event.Content{Parsed: bridgeInfo}, StateKey: &bridgeInfoStateKey, }} - if !portal.AvatarURL.IsEmpty() { - initialState = append(initialState, &event.Event{ - Type: event.StateRoomAvatar, - Content: event.Content{ - Parsed: event.RoomAvatarEventContent{URL: portal.AvatarURL}, - }, - }) - portal.AvatarSet = true - } - var invite []id.UserID - if portal.bridge.Config.Bridge.Encryption.Default { initialState = append(initialState, &event.Event{ Type: event.StateEncryption, @@ -1640,6 +1633,17 @@ func (portal *Portal) CreateMatrixRoom(user *User, groupInfo *types.GroupInfo, i invite = append(invite, portal.bridge.Bot.UserID) } } + if !portal.AvatarURL.IsEmpty() && portal.shouldSetDMRoomMetadata() { + initialState = append(initialState, &event.Event{ + Type: event.StateRoomAvatar, + Content: event.Content{ + Parsed: event.RoomAvatarEventContent{URL: portal.AvatarURL}, + }, + }) + portal.AvatarSet = true + } else { + portal.AvatarSet = false + } creationContent := make(map[string]interface{}) if !portal.bridge.Config.Bridge.FederateRooms { @@ -1674,7 +1678,7 @@ func (portal *Portal) CreateMatrixRoom(user *User, groupInfo *types.GroupInfo, i invite = append(invite, user.MXID) } } - resp, err := intent.CreateRoom(&mautrix.ReqCreateRoom{ + req := &mautrix.ReqCreateRoom{ Visibility: "private", Name: portal.Name, Topic: portal.Topic, @@ -1685,14 +1689,18 @@ func (portal *Portal) CreateMatrixRoom(user *User, groupInfo *types.GroupInfo, i CreationContent: creationContent, BeeperAutoJoinInvites: autoJoinInvites, - }) + } + if !portal.shouldSetDMRoomMetadata() { + req.Name = "" + } + resp, err := intent.CreateRoom(req) if err != nil { return err } portal.log.Infoln("Matrix room created:", resp.RoomID) portal.InSpace = false - portal.NameSet = len(portal.Name) > 0 - portal.TopicSet = len(portal.Topic) > 0 + portal.NameSet = len(req.Name) > 0 + portal.TopicSet = len(req.Topic) > 0 portal.MXID = resp.RoomID portal.bridge.portalsLock.Lock() portal.bridge.portalsByMXID[portal.MXID] = portal diff --git a/puppet.go b/puppet.go index 137aebf..562ddd2 100644 --- a/puppet.go +++ b/puppet.go @@ -294,29 +294,26 @@ func (puppet *Puppet) UpdateContactInfo() bool { } func (puppet *Puppet) updatePortalMeta(meta func(portal *Portal)) { - if puppet.bridge.Config.Bridge.PrivateChatPortalMeta || puppet.bridge.Config.Bridge.Encryption.Allow { - for _, portal := range puppet.bridge.GetAllPortalsByJID(puppet.JID) { - if !puppet.bridge.Config.Bridge.PrivateChatPortalMeta && !portal.Encrypted { - continue - } - // Get room create lock to prevent races between receiving contact info and room creation. - portal.roomCreateLock.Lock() - meta(portal) - portal.roomCreateLock.Unlock() - } + for _, portal := range puppet.bridge.GetAllPortalsByJID(puppet.JID) { + // Get room create lock to prevent races between receiving contact info and room creation. + portal.roomCreateLock.Lock() + meta(portal) + portal.roomCreateLock.Unlock() } } func (puppet *Puppet) updatePortalAvatar() { puppet.updatePortalMeta(func(portal *Portal) { - if portal.Avatar == puppet.Avatar && portal.AvatarURL == puppet.AvatarURL && portal.AvatarSet { + if portal.Avatar == puppet.Avatar && portal.AvatarURL == puppet.AvatarURL && (portal.AvatarSet || !portal.shouldSetDMRoomMetadata()) { return } portal.AvatarURL = puppet.AvatarURL portal.Avatar = puppet.Avatar portal.AvatarSet = false defer portal.Update(nil) - if len(portal.MXID) > 0 { + if len(portal.MXID) > 0 && !portal.shouldSetDMRoomMetadata() { + portal.UpdateBridgeInfo() + } else if len(portal.MXID) > 0 { _, err := portal.MainIntent().SetRoomAvatar(portal.MXID, puppet.AvatarURL) if err != nil { portal.log.Warnln("Failed to set avatar:", err)