2018-08-13 22:24:44 +02:00
// mautrix-whatsapp - A Matrix-WhatsApp puppeting bridge.
2018-08-13 00:00:23 +02:00
// Copyright (C) 2018 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
// 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 (
2018-08-26 16:02:32 +02:00
"strings"
2018-08-16 14:59:18 +02:00
"maunium.net/go/gomatrix"
2018-08-18 21:57:08 +02:00
"maunium.net/go/maulogger"
2018-08-26 16:02:32 +02:00
"maunium.net/go/mautrix-appservice"
"maunium.net/go/mautrix-whatsapp/types"
2018-08-13 22:24:44 +02:00
)
2018-08-13 00:00:23 +02:00
2018-08-18 21:57:08 +02:00
type MatrixHandler struct {
bridge * Bridge
as * appservice . AppService
log maulogger . Logger
cmd * CommandHandler
}
func NewMatrixHandler ( bridge * Bridge ) * MatrixHandler {
handler := & MatrixHandler {
bridge : bridge ,
2018-08-28 23:40:54 +02:00
as : bridge . AS ,
2018-08-18 21:57:08 +02:00
log : bridge . Log . Sub ( "Matrix" ) ,
cmd : NewCommandHandler ( bridge ) ,
}
bridge . EventProcessor . On ( gomatrix . EventMessage , handler . HandleMessage )
bridge . EventProcessor . On ( gomatrix . StateMember , handler . HandleMembership )
2018-08-26 16:02:32 +02:00
bridge . EventProcessor . On ( gomatrix . StateRoomName , handler . HandleRoomMetadata )
bridge . EventProcessor . On ( gomatrix . StateRoomAvatar , handler . HandleRoomMetadata )
bridge . EventProcessor . On ( gomatrix . StateTopic , handler . HandleRoomMetadata )
2018-08-18 21:57:08 +02:00
return handler
}
func ( mx * MatrixHandler ) HandleBotInvite ( evt * gomatrix . Event ) {
intent := mx . as . BotIntent ( )
2018-08-16 14:59:18 +02:00
2018-08-28 23:40:54 +02:00
user := mx . bridge . GetUserByMXID ( evt . Sender )
2018-08-26 16:08:37 +02:00
if user == nil {
return
}
2018-08-16 18:20:07 +02:00
resp , err := intent . JoinRoom ( evt . RoomID , "" , nil )
2018-08-16 14:59:18 +02:00
if err != nil {
2018-08-18 21:57:08 +02:00
mx . log . Debugln ( "Failed to join room" , evt . RoomID , "with invite from" , evt . Sender )
2018-08-16 14:59:18 +02:00
return
}
2018-08-16 18:20:07 +02:00
members , err := intent . JoinedMembers ( resp . RoomID )
2018-08-16 14:59:18 +02:00
if err != nil {
2018-08-18 21:57:08 +02:00
mx . log . Debugln ( "Failed to get members in room" , resp . RoomID , "after accepting invite from" , evt . Sender )
2018-08-16 18:20:07 +02:00
intent . LeaveRoom ( resp . RoomID )
2018-08-16 14:59:18 +02:00
return
}
if len ( members . Joined ) < 2 {
2018-08-18 21:57:08 +02:00
mx . log . Debugln ( "Leaving empty room" , resp . RoomID , "after accepting invite from" , evt . Sender )
2018-08-16 18:20:07 +02:00
intent . LeaveRoom ( resp . RoomID )
2018-08-16 14:59:18 +02:00
return
}
2018-08-16 23:11:28 +02:00
2018-08-26 16:08:37 +02:00
if ! user . Whitelisted {
intent . SendNotice ( resp . RoomID , "You are not whitelisted to use this bridge.\n" +
"If you're the owner of this bridge, see the bridge.permissions section in your config file." )
intent . LeaveRoom ( resp . RoomID )
return
}
2018-08-16 23:11:28 +02:00
hasPuppets := false
2018-08-16 14:59:18 +02:00
for mxid , _ := range members . Joined {
2018-08-16 18:20:07 +02:00
if mxid == intent . UserID || mxid == evt . Sender {
2018-08-16 14:59:18 +02:00
continue
2018-08-28 23:40:54 +02:00
} else if _ , ok := mx . bridge . ParsePuppetMXID ( types . MatrixUserID ( mxid ) ) ; ok {
2018-08-16 23:11:28 +02:00
hasPuppets = true
2018-08-16 14:59:18 +02:00
continue
}
2018-08-18 21:57:08 +02:00
mx . log . Debugln ( "Leaving multi-user room" , resp . RoomID , "after accepting invite from" , evt . Sender )
2018-08-16 18:20:07 +02:00
intent . SendNotice ( resp . RoomID , "This bridge is user-specific, please don't invite me into rooms with other users." )
intent . LeaveRoom ( resp . RoomID )
2018-08-16 14:59:18 +02:00
return
}
2018-08-16 23:11:28 +02:00
if ! hasPuppets {
2018-08-28 23:40:54 +02:00
user := mx . bridge . GetUserByMXID ( types . MatrixUserID ( evt . Sender ) )
2018-08-18 21:57:08 +02:00
user . SetManagementRoom ( types . MatrixRoomID ( resp . RoomID ) )
2018-12-07 14:31:55 +01:00
intent . SendNotice ( string ( user . ManagementRoom ) , "This room has been registered as your bridge management/status room. Send `help` to get a list of commands." )
2018-08-18 21:57:08 +02:00
mx . log . Debugln ( resp . RoomID , "registered as a management room with" , evt . Sender )
2018-08-16 14:59:18 +02:00
}
}
2018-08-18 21:57:08 +02:00
func ( mx * MatrixHandler ) HandleMembership ( evt * gomatrix . Event ) {
if evt . Content . Membership == "invite" && evt . GetStateKey ( ) == mx . as . BotMXID ( ) {
mx . HandleBotInvite ( evt )
2018-08-16 23:11:28 +02:00
}
2018-08-16 14:59:18 +02:00
}
2018-08-26 16:02:32 +02:00
func ( mx * MatrixHandler ) HandleRoomMetadata ( evt * gomatrix . Event ) {
2018-08-28 23:40:54 +02:00
user := mx . bridge . GetUserByMXID ( types . MatrixUserID ( evt . Sender ) )
if user == nil || ! user . Whitelisted || ! user . IsLoggedIn ( ) {
2018-08-26 16:02:32 +02:00
return
}
2018-08-28 23:40:54 +02:00
portal := mx . bridge . GetPortalByMXID ( evt . RoomID )
2018-08-26 16:02:32 +02:00
if portal == nil || portal . IsPrivateChat ( ) {
return
}
var resp <- chan string
var err error
switch evt . Type {
case gomatrix . StateRoomName :
2018-08-28 23:40:54 +02:00
resp , err = user . Conn . UpdateGroupSubject ( evt . Content . Name , portal . Key . JID )
2018-08-26 16:02:32 +02:00
case gomatrix . StateRoomAvatar :
return
case gomatrix . StateTopic :
return
}
if err != nil {
mx . log . Errorln ( err )
} else {
out := <- resp
mx . log . Infoln ( out )
}
}
2018-08-18 21:57:08 +02:00
func ( mx * MatrixHandler ) HandleMessage ( evt * gomatrix . Event ) {
2018-09-01 22:38:03 +02:00
if _ , isPuppet := mx . bridge . ParsePuppetMXID ( evt . Sender ) ; evt . Sender == mx . bridge . Bot . UserID || isPuppet {
return
}
2018-08-18 21:57:08 +02:00
roomID := types . MatrixRoomID ( evt . RoomID )
2018-08-28 23:40:54 +02:00
user := mx . bridge . GetUserByMXID ( types . MatrixUserID ( evt . Sender ) )
2018-08-18 21:57:08 +02:00
2018-08-26 16:08:37 +02:00
if ! user . Whitelisted {
return
}
2018-08-18 21:57:08 +02:00
if evt . Content . MsgType == gomatrix . MsgText {
commandPrefix := mx . bridge . Config . Bridge . CommandPrefix
hasCommandPrefix := strings . HasPrefix ( evt . Content . Body , commandPrefix )
if hasCommandPrefix {
evt . Content . Body = strings . TrimLeft ( evt . Content . Body [ len ( commandPrefix ) : ] , " " )
}
if hasCommandPrefix || roomID == user . ManagementRoom {
mx . cmd . Handle ( roomID , user , evt . Content . Body )
return
}
}
2018-08-28 23:40:54 +02:00
if ! user . IsLoggedIn ( ) {
return
}
portal := mx . bridge . GetPortalByMXID ( roomID )
2018-08-18 21:57:08 +02:00
if portal != nil {
2018-08-28 23:40:54 +02:00
portal . HandleMatrixMessage ( user , evt )
2018-08-18 21:57:08 +02:00
}
2018-08-13 00:00:23 +02:00
}