2018-08-13 22:24:44 +02:00
// mautrix-whatsapp - A Matrix-WhatsApp puppeting bridge.
2024-03-11 21:27:10 +01:00
// Copyright (C) 2024 Tulir Asokan
2018-08-13 00:00:23 +02:00
//
// 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
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
package main
2018-08-13 22:24:44 +02:00
import (
2024-03-11 21:27:10 +01:00
"context"
2019-05-15 22:04:09 +02:00
"fmt"
2020-05-09 13:31:06 +02:00
2024-03-11 21:27:10 +01:00
"github.com/rs/zerolog"
2021-12-09 13:17:13 +01:00
"go.mau.fi/whatsmeow/types"
2020-09-24 14:25:36 +02:00
"maunium.net/go/mautrix"
2022-05-22 00:06:30 +02:00
"maunium.net/go/mautrix/bridge"
2020-05-08 21:32:22 +02:00
"maunium.net/go/mautrix/event"
2019-05-15 22:04:09 +02:00
"maunium.net/go/mautrix/format"
2020-05-08 21:32:22 +02:00
"maunium.net/go/mautrix/id"
2020-07-05 17:57:03 +02:00
"maunium.net/go/mautrix-whatsapp/database"
2018-08-13 22:24:44 +02:00
)
2018-08-13 00:00:23 +02:00
2022-05-22 15:15:54 +02:00
func ( br * WABridge ) CreatePrivatePortal ( roomID id . RoomID , brInviter bridge . User , brGhost bridge . Ghost ) {
inviter := brInviter . ( * User )
puppet := brGhost . ( * Puppet )
key := database . NewPortalKey ( puppet . JID , inviter . JID )
portal := br . GetPortalByJID ( key )
2024-03-11 21:27:10 +01:00
log := br . ZLog . With ( ) .
Str ( "action" , "create private portal" ) .
Stringer ( "target_room_id" , roomID ) .
Stringer ( "inviter_mxid" , inviter . MXID ) .
Stringer ( "invitee_jid" , puppet . JID ) .
Logger ( )
ctx := log . WithContext ( context . TODO ( ) )
2020-07-10 14:23:32 +02:00
if len ( portal . MXID ) == 0 {
2024-03-11 21:27:10 +01:00
br . createPrivatePortalFromInvite ( ctx , roomID , inviter , puppet , portal )
2020-07-10 14:23:32 +02:00
return
}
2024-03-11 21:27:10 +01:00
ok := portal . ensureUserInvited ( ctx , inviter )
2022-07-12 11:24:31 +02:00
if ! ok {
2024-03-11 21:27:10 +01:00
log . Warn ( ) . Msg ( "Failed to invite user to existing private chat portal. Redirecting portal to new room..." )
br . createPrivatePortalFromInvite ( ctx , roomID , inviter , puppet , portal )
2020-07-05 17:57:03 +02:00
return
}
intent := puppet . DefaultIntent ( )
2024-03-11 21:27:10 +01:00
errorMessage := fmt . Sprintf ( "You already have a private chat portal with me at [%s](%s)" , portal . MXID , portal . MXID . URI ( br . Config . Homeserver . Domain ) . MatrixToURL ( ) )
2021-02-11 12:19:54 +01:00
errorContent := format . RenderMarkdown ( errorMessage , true , false )
2024-03-11 21:27:10 +01:00
_ , _ = intent . SendMessageEvent ( ctx , roomID , event . EventMessage , errorContent )
log . Debug ( ) . Msg ( "Leaving private chat room from invite as we already have chat with the user" )
_ , _ = intent . LeaveRoom ( ctx , roomID )
2020-07-05 17:57:03 +02:00
}
2024-03-11 21:27:10 +01:00
func ( br * WABridge ) createPrivatePortalFromInvite ( ctx context . Context , roomID id . RoomID , inviter * User , puppet * Puppet , portal * Portal ) {
log := zerolog . Ctx ( ctx )
2022-10-07 20:01:04 +02:00
// TODO check if room is already encrypted
var existingEncryption event . EncryptionEventContent
var encryptionEnabled bool
2024-03-11 21:27:10 +01:00
err := portal . MainIntent ( ) . StateEvent ( ctx , roomID , event . StateEncryption , "" , & existingEncryption )
2022-10-07 20:01:04 +02:00
if err != nil {
2024-03-11 21:27:10 +01:00
log . Err ( err ) . Msg ( "Failed to check if encryption is enabled" )
2022-10-07 20:01:04 +02:00
} else {
encryptionEnabled = existingEncryption . Algorithm == id . AlgorithmMegolmV1
}
2020-07-05 17:57:03 +02:00
portal . MXID = roomID
2024-03-11 21:27:10 +01:00
portal . updateLogger ( )
2021-06-01 14:28:15 +02:00
portal . Topic = PrivateChatTopic
2023-04-14 12:40:34 +02:00
portal . Name = puppet . Displayname
portal . AvatarURL = puppet . AvatarURL
portal . Avatar = puppet . Avatar
2024-03-11 21:27:10 +01:00
log . Info ( ) . Msg ( "Created private chat portal from invite" )
2020-07-05 17:57:03 +02:00
intent := puppet . DefaultIntent ( )
2022-10-07 20:01:04 +02:00
if br . Config . Bridge . Encryption . Default || encryptionEnabled {
2024-03-11 21:27:10 +01:00
_ , err = intent . InviteUser ( ctx , roomID , & mautrix . ReqInviteUser { UserID : br . Bot . UserID } )
2020-07-05 17:57:03 +02:00
if err != nil {
2024-03-11 21:27:10 +01:00
log . Err ( err ) . Msg ( "Failed to invite bridge bot to enable e2be" )
2020-07-05 17:57:03 +02:00
}
2024-03-11 21:27:10 +01:00
err = br . Bot . EnsureJoined ( ctx , roomID )
2020-07-05 17:57:03 +02:00
if err != nil {
2024-03-11 21:27:10 +01:00
log . Err ( err ) . Msg ( "Failed to join as bridge bot to enable e2be" )
2020-07-05 17:57:03 +02:00
}
2022-10-07 20:01:04 +02:00
if ! encryptionEnabled {
2024-03-11 21:27:10 +01:00
_ , err = intent . SendStateEvent ( ctx , roomID , event . StateEncryption , "" , portal . GetEncryptionEventContent ( ) )
2022-10-07 20:01:04 +02:00
if err != nil {
2024-03-11 21:27:10 +01:00
log . Err ( err ) . Msg ( "Failed to enable e2be" )
2022-10-07 20:01:04 +02:00
}
2020-07-05 17:57:03 +02:00
}
2024-03-11 21:27:10 +01:00
br . AS . StateStore . SetMembership ( ctx , roomID , inviter . MXID , event . MembershipJoin )
br . AS . StateStore . SetMembership ( ctx , roomID , puppet . MXID , event . MembershipJoin )
br . AS . StateStore . SetMembership ( ctx , roomID , br . Bot . UserID , event . MembershipJoin )
2020-07-05 17:57:03 +02:00
portal . Encrypted = true
}
2024-03-11 21:27:10 +01:00
_ , _ = portal . MainIntent ( ) . SetRoomTopic ( ctx , portal . MXID , portal . Topic )
2023-04-14 12:40:34 +02:00
if portal . shouldSetDMRoomMetadata ( ) {
2024-03-11 21:27:10 +01:00
_ , err = portal . MainIntent ( ) . SetRoomName ( ctx , portal . MXID , portal . Name )
2023-04-14 12:40:34 +02:00
portal . NameSet = err == nil
2024-03-11 21:27:10 +01:00
_ , err = portal . MainIntent ( ) . SetRoomAvatar ( ctx , portal . MXID , portal . AvatarURL )
2023-04-14 12:40:34 +02:00
portal . AvatarSet = err == nil
}
2024-03-11 21:27:10 +01:00
err = portal . Update ( ctx )
if err != nil {
log . Err ( err ) . Msg ( "Failed to save portal to database after creating from invite" )
}
portal . UpdateBridgeInfo ( ctx )
_ , _ = intent . SendNotice ( ctx , roomID , "Private chat portal created" )
2020-07-05 17:57:03 +02:00
}
2024-03-11 21:27:10 +01:00
func ( br * WABridge ) HandlePresence ( ctx context . Context , evt * event . Event ) {
2022-05-22 15:15:54 +02:00
user := br . GetUserByMXIDIfExists ( evt . Sender )
2021-12-07 15:02:51 +01:00
if user == nil || ! user . IsLoggedIn ( ) {
return
}
2022-05-22 15:15:54 +02:00
customPuppet := br . GetPuppetByCustomMXID ( user . MXID )
2021-12-07 15:02:51 +01:00
// TODO move this flag to the user and/or portal data
if customPuppet != nil && ! customPuppet . EnablePresence {
return
}
presence := types . PresenceAvailable
if evt . Content . AsPresence ( ) . Presence != event . PresenceOnline {
presence = types . PresenceUnavailable
2024-03-11 21:27:10 +01:00
user . zlog . Debug ( ) . Msg ( "Marking offline" )
2021-12-07 15:02:51 +01:00
} else {
2024-03-11 21:27:10 +01:00
user . zlog . Debug ( ) . Msg ( "Marking online" )
2021-12-07 15:02:51 +01:00
}
user . lastPresence = presence
if user . Client . Store . PushName != "" {
err := user . Client . SendPresence ( presence )
if err != nil {
2024-03-11 21:27:10 +01:00
user . zlog . Err ( err ) . Msg ( "Failed to set presence" )
2021-12-07 15:02:51 +01:00
}
}
}