Implement User Avatar spoofing of XMPP users (#1090)
* Implement User Avatar spoofing of XMPP users
This commit is contained in:
parent
13c90893c7
commit
7183095a28
|
@ -0,0 +1,34 @@
|
||||||
|
package bxmpp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/42wim/matterbridge/bridge/config"
|
||||||
|
"github.com/42wim/matterbridge/bridge/helper"
|
||||||
|
"github.com/matterbridge/go-xmpp"
|
||||||
|
)
|
||||||
|
|
||||||
|
// handleDownloadAvatar downloads the avatar of userid from channel
|
||||||
|
// sends a EVENT_AVATAR_DOWNLOAD message to the gateway if successful.
|
||||||
|
// logs an error message if it fails
|
||||||
|
func (b *Bxmpp) handleDownloadAvatar(avatar xmpp.AvatarData) {
|
||||||
|
rmsg := config.Message{
|
||||||
|
Username: "system",
|
||||||
|
Text: "avatar",
|
||||||
|
Channel: b.parseChannel(avatar.From),
|
||||||
|
Account: b.Account,
|
||||||
|
UserID: avatar.From,
|
||||||
|
Event: config.EventAvatarDownload,
|
||||||
|
Extra: make(map[string][]interface{}),
|
||||||
|
}
|
||||||
|
if _, ok := b.avatarMap[avatar.From]; !ok {
|
||||||
|
b.Log.Debugf("Avatar.From: %s", avatar.From)
|
||||||
|
|
||||||
|
err := helper.HandleDownloadSize(b.Log, &rmsg, avatar.From+".png", int64(len(avatar.Data)), b.General)
|
||||||
|
if err != nil {
|
||||||
|
b.Log.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.HandleDownloadData(b.Log, &rmsg, avatar.From+".png", rmsg.Text, "", &avatar.Data, b.General)
|
||||||
|
b.Log.Debugf("Avatar download complete")
|
||||||
|
b.Remote <- rmsg
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
package bxmpp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"regexp"
|
||||||
|
|
||||||
|
"github.com/42wim/matterbridge/bridge/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
var pathRegex = regexp.MustCompile("[^a-zA-Z0-9]+")
|
||||||
|
|
||||||
|
// GetAvatar constructs a URL for a given user-avatar if it is available in the cache.
|
||||||
|
func getAvatar(av map[string]string, userid string, general *config.Protocol) string {
|
||||||
|
if hash, ok := av[userid]; ok {
|
||||||
|
// NOTE: This does not happen in bridge/helper/helper.go but messes up XMPP
|
||||||
|
id := pathRegex.ReplaceAllString(userid, "_")
|
||||||
|
return general.MediaServerDownload + "/" + hash + "/" + id + ".png"
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Bxmpp) cacheAvatar(msg *config.Message) string {
|
||||||
|
fi := msg.Extra["file"][0].(config.FileInfo)
|
||||||
|
/* if we have a sha we have successfully uploaded the file to the media server,
|
||||||
|
so we can now cache the sha */
|
||||||
|
if fi.SHA != "" {
|
||||||
|
b.Log.Debugf("Added %s to %s in avatarMap", fi.SHA, msg.UserID)
|
||||||
|
b.avatarMap[msg.UserID] = fi.SHA
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
|
@ -23,12 +23,15 @@ type Bxmpp struct {
|
||||||
xmppMap map[string]string
|
xmppMap map[string]string
|
||||||
connected bool
|
connected bool
|
||||||
sync.RWMutex
|
sync.RWMutex
|
||||||
|
|
||||||
|
avatarMap map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(cfg *bridge.Config) bridge.Bridger {
|
func New(cfg *bridge.Config) bridge.Bridger {
|
||||||
return &Bxmpp{
|
return &Bxmpp{
|
||||||
Config: cfg,
|
Config: cfg,
|
||||||
xmppMap: make(map[string]string),
|
xmppMap: make(map[string]string),
|
||||||
|
avatarMap: make(map[string]string),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,6 +72,10 @@ func (b *Bxmpp) Send(msg config.Message) (string, error) {
|
||||||
}
|
}
|
||||||
b.Log.Debugf("=> Receiving %#v", msg)
|
b.Log.Debugf("=> Receiving %#v", msg)
|
||||||
|
|
||||||
|
if msg.Event == config.EventAvatarDownload {
|
||||||
|
return b.cacheAvatar(&msg), nil
|
||||||
|
}
|
||||||
|
|
||||||
// Upload a file (in XMPP case send the upload URL because XMPP has no native upload support).
|
// Upload a file (in XMPP case send the upload URL because XMPP has no native upload support).
|
||||||
if msg.Extra != nil {
|
if msg.Extra != nil {
|
||||||
for _, rmsg := range helper.HandleExtra(&msg, b.General) {
|
for _, rmsg := range helper.HandleExtra(&msg, b.General) {
|
||||||
|
@ -230,6 +237,12 @@ func (b *Bxmpp) handleXMPP() error {
|
||||||
event = config.EventTopicChange
|
event = config.EventTopicChange
|
||||||
}
|
}
|
||||||
|
|
||||||
|
avatar := getAvatar(b.avatarMap, v.Remote, b.General)
|
||||||
|
if avatar == "" {
|
||||||
|
b.Log.Debugf("Requesting avatar data")
|
||||||
|
b.xc.AvatarRequestData(v.Remote)
|
||||||
|
}
|
||||||
|
|
||||||
msgID := v.ID
|
msgID := v.ID
|
||||||
if v.ReplaceID != "" {
|
if v.ReplaceID != "" {
|
||||||
msgID = v.ReplaceID
|
msgID = v.ReplaceID
|
||||||
|
@ -239,6 +252,7 @@ func (b *Bxmpp) handleXMPP() error {
|
||||||
Text: v.Text,
|
Text: v.Text,
|
||||||
Channel: b.parseChannel(v.Remote),
|
Channel: b.parseChannel(v.Remote),
|
||||||
Account: b.Account,
|
Account: b.Account,
|
||||||
|
Avatar: avatar,
|
||||||
UserID: v.Remote,
|
UserID: v.Remote,
|
||||||
ID: msgID,
|
ID: msgID,
|
||||||
Event: event,
|
Event: event,
|
||||||
|
@ -255,6 +269,8 @@ func (b *Bxmpp) handleXMPP() error {
|
||||||
b.Log.Debugf("<= Message is %#v", rmsg)
|
b.Log.Debugf("<= Message is %#v", rmsg)
|
||||||
b.Remote <- rmsg
|
b.Remote <- rmsg
|
||||||
}
|
}
|
||||||
|
case xmpp.AvatarData:
|
||||||
|
b.handleDownloadAvatar(v)
|
||||||
case xmpp.Presence:
|
case xmpp.Presence:
|
||||||
// Do nothing.
|
// Do nothing.
|
||||||
}
|
}
|
||||||
|
|
|
@ -169,7 +169,7 @@ func (gw *Gateway) ignoreEvent(event string, dest *bridge.Bridge) bool {
|
||||||
switch event {
|
switch event {
|
||||||
case config.EventAvatarDownload:
|
case config.EventAvatarDownload:
|
||||||
// Avatar downloads are only relevant for telegram and mattermost for now
|
// Avatar downloads are only relevant for telegram and mattermost for now
|
||||||
if dest.Protocol != "mattermost" && dest.Protocol != "telegram" {
|
if dest.Protocol != "mattermost" && dest.Protocol != "telegram" && dest.Protocol != "xmpp" {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
case config.EventJoinLeave:
|
case config.EventJoinLeave:
|
||||||
|
|
Loading…
Reference in New Issue