forked from MirrorHub/mautrix-whatsapp
Make relay mode more like the Signal bridge
This commit is contained in:
parent
d5bf8dd417
commit
bb9a0f6528
72
commands.go
72
commands.go
|
@ -93,17 +93,11 @@ func (handler *CommandHandler) Handle(roomID id.RoomID, user *User, message stri
|
||||||
Args: args[1:],
|
Args: args[1:],
|
||||||
}
|
}
|
||||||
handler.log.Debugfln("%s sent '%s' in %s", user.MXID, message, roomID)
|
handler.log.Debugfln("%s sent '%s' in %s", user.MXID, message, roomID)
|
||||||
if roomID == handler.bridge.Config.Bridge.Relaybot.ManagementRoom {
|
handler.CommandMux(ce)
|
||||||
handler.CommandRelaybot(ce)
|
|
||||||
} else {
|
|
||||||
handler.CommandMux(ce)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (handler *CommandHandler) CommandMux(ce *CommandEvent) {
|
func (handler *CommandHandler) CommandMux(ce *CommandEvent) {
|
||||||
switch ce.Command {
|
switch ce.Command {
|
||||||
case "relaybot":
|
|
||||||
handler.CommandRelaybot(ce)
|
|
||||||
case "login":
|
case "login":
|
||||||
handler.CommandLogin(ce)
|
handler.CommandLogin(ce)
|
||||||
case "logout-matrix":
|
case "logout-matrix":
|
||||||
|
@ -134,7 +128,7 @@ func (handler *CommandHandler) CommandMux(ce *CommandEvent) {
|
||||||
handler.CommandLogout(ce)
|
handler.CommandLogout(ce)
|
||||||
case "toggle":
|
case "toggle":
|
||||||
handler.CommandToggle(ce)
|
handler.CommandToggle(ce)
|
||||||
case "login-matrix", "sync", "list", "open", "pm", "invite-link", "join", "create":
|
case "set-relay", "unset-relay", "login-matrix", "sync", "list", "open", "pm", "invite-link", "join", "create":
|
||||||
if !ce.User.HasSession() {
|
if !ce.User.HasSession() {
|
||||||
ce.Reply("You are not logged in. Use the `login` command to log into WhatsApp.")
|
ce.Reply("You are not logged in. Use the `login` command to log into WhatsApp.")
|
||||||
return
|
return
|
||||||
|
@ -144,6 +138,10 @@ func (handler *CommandHandler) CommandMux(ce *CommandEvent) {
|
||||||
}
|
}
|
||||||
|
|
||||||
switch ce.Command {
|
switch ce.Command {
|
||||||
|
case "set-relay":
|
||||||
|
handler.CommandSetRelay(ce)
|
||||||
|
case "unset-relay":
|
||||||
|
handler.CommandUnsetRelay(ce)
|
||||||
case "login-matrix":
|
case "login-matrix":
|
||||||
handler.CommandLoginMatrix(ce)
|
handler.CommandLoginMatrix(ce)
|
||||||
case "list":
|
case "list":
|
||||||
|
@ -175,22 +173,35 @@ func (handler *CommandHandler) CommandDiscardMegolmSession(ce *CommandEvent) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (handler *CommandHandler) CommandRelaybot(ce *CommandEvent) {
|
const cmdSetRelayHelp = `set-relay - Relay messages in this room through your WhatsApp account.`
|
||||||
if handler.bridge.Relaybot == nil {
|
|
||||||
ce.Reply("The relaybot is disabled")
|
func (handler *CommandHandler) CommandSetRelay(ce *CommandEvent) {
|
||||||
} else if !ce.User.Admin {
|
if !handler.bridge.Config.Bridge.Relay.Enabled {
|
||||||
ce.Reply("Only admins can manage the relaybot")
|
ce.Reply("Relay mode is not enabled on this instance of the bridge")
|
||||||
|
} else if ce.Portal == nil {
|
||||||
|
ce.Reply("This is not a portal room")
|
||||||
|
} else if handler.bridge.Config.Bridge.Relay.AdminOnly && !ce.User.Admin {
|
||||||
|
ce.Reply("Only admins are allowed to enable relay mode on this instance of the bridge")
|
||||||
} else {
|
} else {
|
||||||
if ce.Command == "relaybot" {
|
ce.Portal.RelayUserID = ce.User.MXID
|
||||||
if len(ce.Args) == 0 {
|
ce.Portal.Update()
|
||||||
ce.Reply("**Usage:** `relaybot <command>`")
|
ce.Reply("Messages from non-logged-in users in this room will now be bridged through your WhatsApp account")
|
||||||
return
|
}
|
||||||
}
|
}
|
||||||
ce.Command = strings.ToLower(ce.Args[0])
|
|
||||||
ce.Args = ce.Args[1:]
|
const cmdUnsetRelayHelp = `set-relay - Stop relaying messages in this room.`
|
||||||
}
|
|
||||||
ce.User = handler.bridge.Relaybot
|
func (handler *CommandHandler) CommandUnsetRelay(ce *CommandEvent) {
|
||||||
handler.CommandMux(ce)
|
if !handler.bridge.Config.Bridge.Relay.Enabled {
|
||||||
|
ce.Reply("Relay mode is not enabled on this instance of the bridge")
|
||||||
|
} else if ce.Portal == nil {
|
||||||
|
ce.Reply("This is not a portal room")
|
||||||
|
} else if handler.bridge.Config.Bridge.Relay.AdminOnly && !ce.User.Admin {
|
||||||
|
ce.Reply("Only admins are allowed to enable relay mode on this instance of the bridge")
|
||||||
|
} else {
|
||||||
|
ce.Portal.RelayUserID = ""
|
||||||
|
ce.Portal.Update()
|
||||||
|
ce.Reply("Messages from non-logged-in users will no longer be bridged in this room")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -627,7 +638,7 @@ const cmdHelpHelp = `help - Prints this help`
|
||||||
// CommandHelp handles help command
|
// CommandHelp handles help command
|
||||||
func (handler *CommandHandler) CommandHelp(ce *CommandEvent) {
|
func (handler *CommandHandler) CommandHelp(ce *CommandEvent) {
|
||||||
cmdPrefix := ""
|
cmdPrefix := ""
|
||||||
if ce.User.ManagementRoom != ce.RoomID || ce.User.IsRelaybot {
|
if ce.User.ManagementRoom != ce.RoomID {
|
||||||
cmdPrefix = handler.bridge.Config.Bridge.CommandPrefix + " "
|
cmdPrefix = handler.bridge.Config.Bridge.CommandPrefix + " "
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -640,6 +651,8 @@ func (handler *CommandHandler) CommandHelp(ce *CommandEvent) {
|
||||||
cmdPrefix + cmdReconnectHelp,
|
cmdPrefix + cmdReconnectHelp,
|
||||||
cmdPrefix + cmdDisconnectHelp,
|
cmdPrefix + cmdDisconnectHelp,
|
||||||
cmdPrefix + cmdPingHelp,
|
cmdPrefix + cmdPingHelp,
|
||||||
|
cmdPrefix + cmdSetRelayHelp,
|
||||||
|
cmdPrefix + cmdUnsetRelayHelp,
|
||||||
cmdPrefix + cmdLoginMatrixHelp,
|
cmdPrefix + cmdLoginMatrixHelp,
|
||||||
cmdPrefix + cmdLogoutMatrixHelp,
|
cmdPrefix + cmdLogoutMatrixHelp,
|
||||||
cmdPrefix + cmdToggleHelp,
|
cmdPrefix + cmdToggleHelp,
|
||||||
|
@ -871,14 +884,9 @@ func (handler *CommandHandler) CommandPM(ce *CommandEvent) {
|
||||||
puppet.SyncContact(user, true)
|
puppet.SyncContact(user, true)
|
||||||
portal := user.GetPortalByJID(puppet.JID)
|
portal := user.GetPortalByJID(puppet.JID)
|
||||||
if len(portal.MXID) > 0 {
|
if len(portal.MXID) > 0 {
|
||||||
if !user.IsRelaybot {
|
ok := portal.ensureUserInvited(user)
|
||||||
_, err = portal.MainIntent().Client.InviteUser(portal.MXID, &mautrix.ReqInviteUser{UserID: user.MXID})
|
if !ok {
|
||||||
if httpErr, ok := err.(mautrix.HTTPError); ok && httpErr.RespError != nil && strings.Contains(httpErr.RespError.Err, "is already in the room") {
|
portal.log.Warnfln("ensureUserInvited(%s) returned false, creating new portal", user.MXID)
|
||||||
err = nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
portal.log.Warnfln("Failed to invite %s to portal: %v. Creating new portal", user.MXID, err)
|
|
||||||
portal.MXID = ""
|
portal.MXID = ""
|
||||||
} else {
|
} else {
|
||||||
ce.Reply("You already have a private chat portal with that user at [%s](https://matrix.to/#/%s)", puppet.Displayname, portal.MXID)
|
ce.Reply("You already have a private chat portal with that user at [%s](https://matrix.to/#/%s)", puppet.Displayname, portal.MXID)
|
||||||
|
|
|
@ -85,7 +85,7 @@ type BridgeConfig struct {
|
||||||
|
|
||||||
Permissions PermissionConfig `yaml:"permissions"`
|
Permissions PermissionConfig `yaml:"permissions"`
|
||||||
|
|
||||||
Relaybot RelaybotConfig `yaml:"relaybot"`
|
Relay RelaybotConfig `yaml:"relay"`
|
||||||
|
|
||||||
usernameTemplate *template.Template `yaml:"-"`
|
usernameTemplate *template.Template `yaml:"-"`
|
||||||
displaynameTemplate *template.Template `yaml:"-"`
|
displaynameTemplate *template.Template `yaml:"-"`
|
||||||
|
@ -110,6 +110,8 @@ func (bc *BridgeConfig) setDefaults() {
|
||||||
|
|
||||||
bc.BridgeNotices = true
|
bc.BridgeNotices = true
|
||||||
bc.EnableStatusBroadcast = true
|
bc.EnableStatusBroadcast = true
|
||||||
|
|
||||||
|
bc.Relay.AdminOnly = true
|
||||||
}
|
}
|
||||||
|
|
||||||
type umBridgeConfig BridgeConfig
|
type umBridgeConfig BridgeConfig
|
||||||
|
@ -271,10 +273,8 @@ func (pc PermissionConfig) GetPermissionLevel(userID id.UserID) PermissionLevel
|
||||||
}
|
}
|
||||||
|
|
||||||
type RelaybotConfig struct {
|
type RelaybotConfig struct {
|
||||||
Enabled bool `yaml:"enabled"`
|
Enabled bool `yaml:"enabled"`
|
||||||
ManagementRoom id.RoomID `yaml:"management"`
|
AdminOnly bool `yaml:"admin_only"`
|
||||||
InviteUsers []id.UserID `yaml:"invites"`
|
|
||||||
|
|
||||||
MessageFormats map[event.MessageType]string `yaml:"message_formats"`
|
MessageFormats map[event.MessageType]string `yaml:"message_formats"`
|
||||||
messageTemplates *template.Template `yaml:"-"`
|
messageTemplates *template.Template `yaml:"-"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -121,11 +121,13 @@ type Portal struct {
|
||||||
|
|
||||||
FirstEventID id.EventID
|
FirstEventID id.EventID
|
||||||
NextBatchID id.BatchID
|
NextBatchID id.BatchID
|
||||||
|
|
||||||
|
RelayUserID id.UserID
|
||||||
}
|
}
|
||||||
|
|
||||||
func (portal *Portal) Scan(row Scannable) *Portal {
|
func (portal *Portal) Scan(row Scannable) *Portal {
|
||||||
var mxid, avatarURL, firstEventID, nextBatchID sql.NullString
|
var mxid, avatarURL, firstEventID, nextBatchID, relayUserID sql.NullString
|
||||||
err := row.Scan(&portal.Key.JID, &portal.Key.Receiver, &mxid, &portal.Name, &portal.Topic, &portal.Avatar, &avatarURL, &portal.Encrypted, &firstEventID, &nextBatchID)
|
err := row.Scan(&portal.Key.JID, &portal.Key.Receiver, &mxid, &portal.Name, &portal.Topic, &portal.Avatar, &avatarURL, &portal.Encrypted, &firstEventID, &nextBatchID, &relayUserID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err != sql.ErrNoRows {
|
if err != sql.ErrNoRows {
|
||||||
portal.log.Errorln("Database scan failed:", err)
|
portal.log.Errorln("Database scan failed:", err)
|
||||||
|
@ -136,6 +138,7 @@ func (portal *Portal) Scan(row Scannable) *Portal {
|
||||||
portal.AvatarURL, _ = id.ParseContentURI(avatarURL.String)
|
portal.AvatarURL, _ = id.ParseContentURI(avatarURL.String)
|
||||||
portal.FirstEventID = id.EventID(firstEventID.String)
|
portal.FirstEventID = id.EventID(firstEventID.String)
|
||||||
portal.NextBatchID = id.BatchID(nextBatchID.String)
|
portal.NextBatchID = id.BatchID(nextBatchID.String)
|
||||||
|
portal.RelayUserID = id.UserID(relayUserID.String)
|
||||||
return portal
|
return portal
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,17 +149,24 @@ func (portal *Portal) mxidPtr() *id.RoomID {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (portal *Portal) relayUserPtr() *id.UserID {
|
||||||
|
if len(portal.RelayUserID) > 0 {
|
||||||
|
return &portal.RelayUserID
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (portal *Portal) Insert() {
|
func (portal *Portal) Insert() {
|
||||||
_, err := portal.db.Exec("INSERT INTO portal (jid, receiver, mxid, name, topic, avatar, avatar_url, encrypted, first_event_id, next_batch_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)",
|
_, err := portal.db.Exec("INSERT INTO portal (jid, receiver, mxid, name, topic, avatar, avatar_url, encrypted, first_event_id, next_batch_id, relay_user_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)",
|
||||||
portal.Key.JID, portal.Key.Receiver, portal.mxidPtr(), portal.Name, portal.Topic, portal.Avatar, portal.AvatarURL.String(), portal.Encrypted, portal.FirstEventID.String(), portal.NextBatchID.String())
|
portal.Key.JID, portal.Key.Receiver, portal.mxidPtr(), portal.Name, portal.Topic, portal.Avatar, portal.AvatarURL.String(), portal.Encrypted, portal.FirstEventID.String(), portal.NextBatchID.String(), portal.relayUserPtr())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
portal.log.Warnfln("Failed to insert %s: %v", portal.Key, err)
|
portal.log.Warnfln("Failed to insert %s: %v", portal.Key, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (portal *Portal) Update() {
|
func (portal *Portal) Update() {
|
||||||
_, err := portal.db.Exec("UPDATE portal SET mxid=$1, name=$2, topic=$3, avatar=$4, avatar_url=$5, encrypted=$6, first_event_id=$7, next_batch_id=$8 WHERE jid=$9 AND receiver=$10",
|
_, err := portal.db.Exec("UPDATE portal SET mxid=$3, name=$4, topic=$5, avatar=$6, avatar_url=$7, encrypted=$8, first_event_id=$9, next_batch_id=$10, relay_user_id=$11 WHERE jid=$1 AND receiver=$2",
|
||||||
portal.mxidPtr(), portal.Name, portal.Topic, portal.Avatar, portal.AvatarURL.String(), portal.Encrypted, portal.FirstEventID.String(), portal.NextBatchID.String(), portal.Key.JID, portal.Key.Receiver)
|
portal.Key.JID, portal.Key.Receiver, portal.mxidPtr(), portal.Name, portal.Topic, portal.Avatar, portal.AvatarURL.String(), portal.Encrypted, portal.FirstEventID.String(), portal.NextBatchID.String(), portal.relayUserPtr())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
portal.log.Warnfln("Failed to update %s: %v", portal.Key, err)
|
portal.log.Warnfln("Failed to update %s: %v", portal.Key, err)
|
||||||
}
|
}
|
||||||
|
|
12
database/upgrades/2021-10-28-portal-relay-user.go
Normal file
12
database/upgrades/2021-10-28-portal-relay-user.go
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
package upgrades
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
upgrades[28] = upgrade{"Add relay user field to portal table", func(tx *sql.Tx, ctx context) error {
|
||||||
|
_, err := tx.Exec(`ALTER TABLE portal ADD COLUMN relay_user_id TEXT`)
|
||||||
|
return err
|
||||||
|
}}
|
||||||
|
}
|
|
@ -39,7 +39,7 @@ type upgrade struct {
|
||||||
fn upgradeFunc
|
fn upgradeFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
const NumberOfUpgrades = 28
|
const NumberOfUpgrades = 29
|
||||||
|
|
||||||
var upgrades [NumberOfUpgrades]upgrade
|
var upgrades [NumberOfUpgrades]upgrade
|
||||||
|
|
||||||
|
|
|
@ -204,15 +204,12 @@ bridge:
|
||||||
"example.com": user
|
"example.com": user
|
||||||
"@admin:example.com": admin
|
"@admin:example.com": admin
|
||||||
|
|
||||||
relaybot:
|
relay:
|
||||||
# Whether or not relaybot support is enabled.
|
# Whether relay mode should be allowed. If allowed, `!signal set-relay` can be used to turn any
|
||||||
|
# authenticated user into a relaybot for that chat.
|
||||||
enabled: false
|
enabled: false
|
||||||
# The management room for the bot. This is where all status notifications are posted and
|
# Should only admins be allowed to set themselves as relay users?
|
||||||
# in this room, you can use `!wa <command>` instead of `!wa relaybot <command>`. Omitting
|
admin_only: true
|
||||||
# the command prefix completely like in user management rooms is not possible.
|
|
||||||
management: "!foo:example.com"
|
|
||||||
# List of users to invite to all created rooms that include the relaybot.
|
|
||||||
invites: []
|
|
||||||
# The formats to use when sending messages to WhatsApp via the relaybot.
|
# The formats to use when sending messages to WhatsApp via the relaybot.
|
||||||
message_formats:
|
message_formats:
|
||||||
m.text: "<b>{{ .Sender.Displayname }}</b>: {{ .Message }}"
|
m.text: "<b>{{ .Sender.Displayname }}</b>: {{ .Message }}"
|
||||||
|
|
39
main.go
39
main.go
|
@ -47,21 +47,29 @@ import (
|
||||||
"maunium.net/go/mautrix-whatsapp/database/upgrades"
|
"maunium.net/go/mautrix-whatsapp/database/upgrades"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// The name and repo URL of the bridge.
|
||||||
var (
|
var (
|
||||||
// These are static
|
|
||||||
Name = "mautrix-whatsapp"
|
Name = "mautrix-whatsapp"
|
||||||
URL = "https://github.com/mautrix/whatsapp"
|
URL = "https://github.com/mautrix/whatsapp"
|
||||||
// This is changed when making a release
|
)
|
||||||
Version = "0.1.8"
|
|
||||||
// This is filled by init()
|
// Information to find out exactly which commit the bridge was built from.
|
||||||
WAVersion = ""
|
// These are filled at build time with the -X linker flag.
|
||||||
VersionString = ""
|
var (
|
||||||
// These are filled at build time with the -X linker flag
|
|
||||||
Tag = "unknown"
|
Tag = "unknown"
|
||||||
Commit = "unknown"
|
Commit = "unknown"
|
||||||
BuildTime = "unknown"
|
BuildTime = "unknown"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// Version is the version number of the bridge. Changed manually when making a release.
|
||||||
|
Version = "0.1.8"
|
||||||
|
// WAVersion is the version number exposed to WhatsApp. Filled in init()
|
||||||
|
WAVersion = ""
|
||||||
|
// VersionString is the bridge version, plus commit information. Filled in init() using the build-time values.
|
||||||
|
VersionString = ""
|
||||||
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
if len(Tag) > 0 && Tag[0] == 'v' {
|
if len(Tag) > 0 && Tag[0] == 'v' {
|
||||||
Tag = Tag[1:]
|
Tag = Tag[1:]
|
||||||
|
@ -151,7 +159,6 @@ type Bridge struct {
|
||||||
Provisioning *ProvisioningAPI
|
Provisioning *ProvisioningAPI
|
||||||
Bot *appservice.IntentAPI
|
Bot *appservice.IntentAPI
|
||||||
Formatter *Formatter
|
Formatter *Formatter
|
||||||
Relaybot *User
|
|
||||||
Crypto Crypto
|
Crypto Crypto
|
||||||
Metrics *MetricsHandler
|
Metrics *MetricsHandler
|
||||||
WAContainer *sqlstore.Container
|
WAContainer *sqlstore.Container
|
||||||
|
@ -320,7 +327,6 @@ func (bridge *Bridge) Start() {
|
||||||
bridge.Log.Debugln("Initializing provisioning API")
|
bridge.Log.Debugln("Initializing provisioning API")
|
||||||
bridge.Provisioning.Init()
|
bridge.Provisioning.Init()
|
||||||
}
|
}
|
||||||
bridge.LoadRelaybot()
|
|
||||||
bridge.Log.Debugln("Starting application service HTTP server")
|
bridge.Log.Debugln("Starting application service HTTP server")
|
||||||
go bridge.AS.Start()
|
go bridge.AS.Start()
|
||||||
bridge.Log.Debugln("Starting event processor")
|
bridge.Log.Debugln("Starting event processor")
|
||||||
|
@ -353,21 +359,6 @@ func (bridge *Bridge) ResendBridgeInfo() {
|
||||||
bridge.Log.Infoln("Finished re-sending bridge info state events")
|
bridge.Log.Infoln("Finished re-sending bridge info state events")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bridge *Bridge) LoadRelaybot() {
|
|
||||||
if !bridge.Config.Bridge.Relaybot.Enabled {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
bridge.Relaybot = bridge.GetUserByMXID("relaybot")
|
|
||||||
if bridge.Relaybot.HasSession() {
|
|
||||||
bridge.Log.Debugln("Relaybot is enabled")
|
|
||||||
} else {
|
|
||||||
bridge.Log.Debugln("Relaybot is enabled, but not logged in")
|
|
||||||
}
|
|
||||||
bridge.Relaybot.ManagementRoom = bridge.Config.Bridge.Relaybot.ManagementRoom
|
|
||||||
bridge.Relaybot.IsRelaybot = true
|
|
||||||
bridge.Relaybot.Connect()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bridge *Bridge) UpdateBotProfile() {
|
func (bridge *Bridge) UpdateBotProfile() {
|
||||||
bridge.Log.Debugln("Updating bot profile")
|
bridge.Log.Debugln("Updating bot profile")
|
||||||
botConfig := bridge.Config.AppService.Bot
|
botConfig := bridge.Config.AppService.Bot
|
||||||
|
|
|
@ -114,12 +114,6 @@ func (mx *MatrixHandler) HandleBotInvite(evt *event.Event) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if evt.RoomID == mx.bridge.Config.Bridge.Relaybot.ManagementRoom {
|
|
||||||
_, _ = intent.SendNotice(evt.RoomID, "This is the relaybot management room. Send `!wa help` to get a list of commands.")
|
|
||||||
mx.log.Debugln("Joined relaybot management room", evt.RoomID, "after invite from", evt.Sender)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
hasPuppets := false
|
hasPuppets := false
|
||||||
for mxid, _ := range members.Joined {
|
for mxid, _ := range members.Joined {
|
||||||
if mxid == intent.UserID || mxid == evt.Sender {
|
if mxid == intent.UserID || mxid == evt.Sender {
|
||||||
|
|
92
portal.go
92
portal.go
|
@ -190,7 +190,7 @@ type Portal struct {
|
||||||
|
|
||||||
messages chan PortalMessage
|
messages chan PortalMessage
|
||||||
|
|
||||||
hasRelaybot *bool
|
relayUser *User
|
||||||
}
|
}
|
||||||
|
|
||||||
func (portal *Portal) handleMessageLoop() {
|
func (portal *Portal) handleMessageLoop() {
|
||||||
|
@ -519,14 +519,17 @@ func (portal *Portal) SyncParticipants(source *User, metadata *types.GroupInfo)
|
||||||
participantMap := make(map[types.JID]bool)
|
participantMap := make(map[types.JID]bool)
|
||||||
for _, participant := range metadata.Participants {
|
for _, participant := range metadata.Participants {
|
||||||
participantMap[participant.JID] = true
|
participantMap[participant.JID] = true
|
||||||
user := portal.bridge.GetUserByJID(participant.JID)
|
|
||||||
portal.userMXIDAction(user, portal.ensureMXIDInvited)
|
|
||||||
|
|
||||||
puppet := portal.bridge.GetPuppetByJID(participant.JID)
|
puppet := portal.bridge.GetPuppetByJID(participant.JID)
|
||||||
puppet.SyncContact(source, true)
|
puppet.SyncContact(source, true)
|
||||||
err = puppet.IntentFor(portal).EnsureJoined(portal.MXID)
|
user := portal.bridge.GetUserByJID(participant.JID)
|
||||||
if err != nil {
|
if user != nil {
|
||||||
portal.log.Warnfln("Failed to make puppet of %s join %s: %v", participant.JID, portal.MXID, err)
|
portal.ensureUserInvited(user)
|
||||||
|
}
|
||||||
|
if user == nil || !puppet.IntentFor(portal).IsCustomPuppet {
|
||||||
|
err = puppet.IntentFor(portal).EnsureJoined(portal.MXID)
|
||||||
|
if err != nil {
|
||||||
|
portal.log.Warnfln("Failed to make puppet of %s join %s: %v", participant.JID, portal.MXID, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
expectedLevel := 0
|
expectedLevel := 0
|
||||||
|
@ -692,20 +695,6 @@ func (portal *Portal) UpdateMetadata(user *User) bool {
|
||||||
return update
|
return update
|
||||||
}
|
}
|
||||||
|
|
||||||
func (portal *Portal) userMXIDAction(user *User, fn func(mxid id.UserID)) {
|
|
||||||
if user == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if user == portal.bridge.Relaybot {
|
|
||||||
for _, mxid := range portal.bridge.Config.Bridge.Relaybot.InviteUsers {
|
|
||||||
fn(mxid)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fn(user.MXID)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (portal *Portal) ensureMXIDInvited(mxid id.UserID) {
|
func (portal *Portal) ensureMXIDInvited(mxid id.UserID) {
|
||||||
err := portal.MainIntent().EnsureInvited(portal.MXID, mxid)
|
err := portal.MainIntent().EnsureInvited(portal.MXID, mxid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -713,12 +702,7 @@ func (portal *Portal) ensureMXIDInvited(mxid id.UserID) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (portal *Portal) ensureUserInvited(user *User) {
|
func (portal *Portal) ensureUserInvited(user *User) (ok bool) {
|
||||||
if user.IsRelaybot {
|
|
||||||
portal.userMXIDAction(user, portal.ensureMXIDInvited)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
inviteContent := event.Content{
|
inviteContent := event.Content{
|
||||||
Parsed: &event.MemberEventContent{
|
Parsed: &event.MemberEventContent{
|
||||||
Membership: event.MembershipInvite,
|
Membership: event.MembershipInvite,
|
||||||
|
@ -734,26 +718,28 @@ func (portal *Portal) ensureUserInvited(user *User) {
|
||||||
var httpErr mautrix.HTTPError
|
var httpErr mautrix.HTTPError
|
||||||
if err != nil && errors.As(err, &httpErr) && httpErr.RespError != nil && strings.Contains(httpErr.RespError.Err, "is already in the room") {
|
if err != nil && errors.As(err, &httpErr) && httpErr.RespError != nil && strings.Contains(httpErr.RespError.Err, "is already in the room") {
|
||||||
portal.bridge.StateStore.SetMembership(portal.MXID, user.MXID, event.MembershipJoin)
|
portal.bridge.StateStore.SetMembership(portal.MXID, user.MXID, event.MembershipJoin)
|
||||||
|
ok = true
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
portal.log.Warnfln("Failed to invite %s: %v", user.MXID, err)
|
portal.log.Warnfln("Failed to invite %s: %v", user.MXID, err)
|
||||||
|
} else {
|
||||||
|
ok = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if customPuppet != nil && customPuppet.CustomIntent() != nil {
|
if customPuppet != nil && customPuppet.CustomIntent() != nil {
|
||||||
err = customPuppet.CustomIntent().EnsureJoined(portal.MXID)
|
err = customPuppet.CustomIntent().EnsureJoined(portal.MXID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
portal.log.Warnfln("Failed to auto-join portal as %s: %v", user.MXID, err)
|
portal.log.Warnfln("Failed to auto-join portal as %s: %v", user.MXID, err)
|
||||||
|
ok = false
|
||||||
|
} else {
|
||||||
|
ok = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (portal *Portal) Sync(user *User) bool {
|
func (portal *Portal) Sync(user *User) bool {
|
||||||
portal.log.Infoln("Syncing portal for", user.MXID)
|
portal.log.Infoln("Syncing portal for", user.MXID)
|
||||||
|
|
||||||
if user.IsRelaybot {
|
|
||||||
yes := true
|
|
||||||
portal.hasRelaybot = &yes
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(portal.MXID) == 0 {
|
if len(portal.MXID) == 0 {
|
||||||
err := portal.CreateMatrixRoom(user)
|
err := portal.CreateMatrixRoom(user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1299,9 +1285,6 @@ func (portal *Portal) CreateMatrixRoom(user *User) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
var invite []id.UserID
|
var invite []id.UserID
|
||||||
if user.IsRelaybot {
|
|
||||||
invite = portal.bridge.Config.Bridge.Relaybot.InviteUsers
|
|
||||||
}
|
|
||||||
|
|
||||||
if portal.bridge.Config.Bridge.Encryption.Default {
|
if portal.bridge.Config.Bridge.Encryption.Default {
|
||||||
initialState = append(initialState, &event.Event{
|
initialState = append(initialState, &event.Event{
|
||||||
|
@ -1354,7 +1337,7 @@ func (portal *Portal) CreateMatrixRoom(user *User) error {
|
||||||
//if broadcastMetadata != nil {
|
//if broadcastMetadata != nil {
|
||||||
// portal.SyncBroadcastRecipients(user, broadcastMetadata)
|
// portal.SyncBroadcastRecipients(user, broadcastMetadata)
|
||||||
//}
|
//}
|
||||||
if portal.IsPrivateChat() && !user.IsRelaybot {
|
if portal.IsPrivateChat() {
|
||||||
puppet := user.bridge.GetPuppetByJID(portal.Key.JID)
|
puppet := user.bridge.GetPuppetByJID(portal.Key.JID)
|
||||||
|
|
||||||
if portal.bridge.Config.Bridge.Encryption.Default {
|
if portal.bridge.Config.Bridge.Encryption.Default {
|
||||||
|
@ -1397,15 +1380,16 @@ func (portal *Portal) IsStatusBroadcastList() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (portal *Portal) HasRelaybot() bool {
|
func (portal *Portal) HasRelaybot() bool {
|
||||||
if portal.bridge.Relaybot == nil {
|
return portal.bridge.Config.Bridge.Relay.Enabled && len(portal.RelayUserID) > 0
|
||||||
return false
|
}
|
||||||
} else if portal.hasRelaybot == nil {
|
|
||||||
// FIXME
|
func (portal *Portal) GetRelayUser() *User {
|
||||||
//val := portal.bridge.Relaybot.IsInPortal(portal.Key)
|
if !portal.HasRelaybot() {
|
||||||
val := true
|
return nil
|
||||||
portal.hasRelaybot = &val
|
} else if portal.relayUser == nil {
|
||||||
|
portal.relayUser = portal.bridge.GetUserByMXID(portal.RelayUserID)
|
||||||
}
|
}
|
||||||
return *portal.hasRelaybot
|
return portal.relayUser
|
||||||
}
|
}
|
||||||
|
|
||||||
func (portal *Portal) MainIntent() *appservice.IntentAPI {
|
func (portal *Portal) MainIntent() *appservice.IntentAPI {
|
||||||
|
@ -1426,8 +1410,8 @@ func (portal *Portal) SetReply(content *event.MessageEventContent, replyToID typ
|
||||||
portal.log.Warnln("Failed to get reply target:", err)
|
portal.log.Warnln("Failed to get reply target:", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
_ = evt.Content.ParseRaw(evt.Type)
|
||||||
if evt.Type == event.EventEncrypted {
|
if evt.Type == event.EventEncrypted {
|
||||||
_ = evt.Content.ParseRaw(evt.Type)
|
|
||||||
decryptedEvt, err := portal.bridge.Crypto.Decrypt(evt)
|
decryptedEvt, err := portal.bridge.Crypto.Decrypt(evt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
portal.log.Warnln("Failed to decrypt reply target:", err)
|
portal.log.Warnln("Failed to decrypt reply target:", err)
|
||||||
|
@ -1435,7 +1419,6 @@ func (portal *Portal) SetReply(content *event.MessageEventContent, replyToID typ
|
||||||
evt = decryptedEvt
|
evt = decryptedEvt
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ = evt.Content.ParseRaw(evt.Type)
|
|
||||||
content.SetReply(evt)
|
content.SetReply(evt)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
@ -2176,7 +2159,7 @@ func (portal *Portal) addRelaybotFormat(sender *User, content *event.MessageEven
|
||||||
content.FormattedBody = strings.Replace(html.EscapeString(content.Body), "\n", "<br/>", -1)
|
content.FormattedBody = strings.Replace(html.EscapeString(content.Body), "\n", "<br/>", -1)
|
||||||
content.Format = event.FormatHTML
|
content.Format = event.FormatHTML
|
||||||
}
|
}
|
||||||
data, err := portal.bridge.Config.Bridge.Relaybot.FormatMessage(content, sender.MXID, member)
|
data, err := portal.bridge.Config.Bridge.Relay.FormatMessage(content, sender.MXID, member)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
portal.log.Errorln("Failed to apply relaybot format:", err)
|
portal.log.Errorln("Failed to apply relaybot format:", err)
|
||||||
}
|
}
|
||||||
|
@ -2243,18 +2226,13 @@ func (portal *Portal) convertMatrixMessage(sender *User, evt *event.Event) (*waP
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
relaybotFormatted := false
|
relaybotFormatted := false
|
||||||
if sender.NeedsRelaybot(portal) {
|
if !sender.HasSession() {
|
||||||
if !portal.HasRelaybot() {
|
if !portal.HasRelaybot() {
|
||||||
if sender.HasSession() {
|
portal.log.Debugln("Ignoring message from", sender.MXID, "in chat with no relaybot")
|
||||||
portal.log.Debugln("Database says", sender.MXID, "not in chat and no relaybot, but trying to send anyway")
|
return nil, sender
|
||||||
} else {
|
|
||||||
portal.log.Debugln("Ignoring message from", sender.MXID, "in chat with no relaybot")
|
|
||||||
return nil, sender
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
relaybotFormatted = portal.addRelaybotFormat(sender, content)
|
|
||||||
sender = portal.bridge.Relaybot
|
|
||||||
}
|
}
|
||||||
|
relaybotFormatted = portal.addRelaybotFormat(sender, content)
|
||||||
|
sender = portal.GetRelayUser()
|
||||||
}
|
}
|
||||||
if evt.Type == event.EventSticker {
|
if evt.Type == event.EventSticker {
|
||||||
content.MsgType = event.MsgImage
|
content.MsgType = event.MsgImage
|
||||||
|
|
4
user.go
4
user.go
|
@ -58,8 +58,6 @@ type User struct {
|
||||||
Whitelisted bool
|
Whitelisted bool
|
||||||
RelaybotWhitelisted bool
|
RelaybotWhitelisted bool
|
||||||
|
|
||||||
IsRelaybot bool
|
|
||||||
|
|
||||||
mgmtCreateLock sync.Mutex
|
mgmtCreateLock sync.Mutex
|
||||||
connLock sync.Mutex
|
connLock sync.Mutex
|
||||||
|
|
||||||
|
@ -179,8 +177,6 @@ func (bridge *Bridge) NewUser(dbUser *database.User) *User {
|
||||||
log: bridge.Log.Sub("User").Sub(string(dbUser.MXID)),
|
log: bridge.Log.Sub("User").Sub(string(dbUser.MXID)),
|
||||||
|
|
||||||
historySyncs: make(chan *events.HistorySync, 32),
|
historySyncs: make(chan *events.HistorySync, 32),
|
||||||
|
|
||||||
IsRelaybot: false,
|
|
||||||
}
|
}
|
||||||
user.RelaybotWhitelisted = user.bridge.Config.Bridge.Permissions.IsRelaybotWhitelisted(user.MXID)
|
user.RelaybotWhitelisted = user.bridge.Config.Bridge.Permissions.IsRelaybotWhitelisted(user.MXID)
|
||||||
user.Whitelisted = user.bridge.Config.Bridge.Permissions.IsWhitelisted(user.MXID)
|
user.Whitelisted = user.bridge.Config.Bridge.Permissions.IsWhitelisted(user.MXID)
|
||||||
|
|
Loading…
Reference in a new issue