Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
6 changes: 3 additions & 3 deletions Dockerfile_whatsappmulti
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
FROM alpine AS builder
FROM golang:1.25-alpine AS builder

COPY . /go/src/matterbridge
RUN apk --no-cache add go git \
RUN apk --no-cache add git \
&& cd /go/src/matterbridge \
&& CGO_ENABLED=0 go build -tags whatsappmulti -mod vendor -ldflags "-X github.com/42wim/matterbridge/version.GitHash=$(git log --pretty=format:'%h' -n 1)" -o /bin/matterbridge
&& CGO_ENABLED=0 go build -mod=mod -tags whatsappmulti -ldflags "-X github.com/42wim/matterbridge/version.GitHash=$(git log --pretty=format:'%h' -n 1)" -o /bin/matterbridge

FROM alpine
RUN apk --no-cache add ca-certificates mailcap
Expand Down
43 changes: 32 additions & 11 deletions bridge/whatsappmulti/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package bwhatsapp

import (
"context"
"fmt"
"mime"
"strings"
Expand Down Expand Up @@ -149,7 +150,9 @@ func (b *Bwhatsapp) handleTextMessage(messageInfo types.MessageInfo, msg *proto.
ci := msg.GetExtendedTextMessage().GetContextInfo()

if senderJID == (types.JID{}) && ci.Participant != nil {
senderJID = types.NewJID(ci.GetParticipant(), types.DefaultUserServer)
if parsed, err := types.ParseJID(ci.GetParticipant()); err == nil {
senderJID = parsed
}
}

if ci.MentionedJID != nil {
Expand All @@ -159,7 +162,13 @@ func (b *Bwhatsapp) handleTextMessage(messageInfo types.MessageInfo, msg *proto.

// mentions comes as telephone numbers and we don't want to expose it to other bridges
// replace it with something more meaninful to others
mention := b.getSenderNotify(types.NewJID(numberAndSuffix[0], types.DefaultUserServer))
var mentionJID types.JID
if parsed, err := types.ParseJID(mentionedJID); err == nil {
mentionJID = parsed
} else {
mentionJID = types.NewJID(numberAndSuffix[0], types.DefaultUserServer)
}
mention := b.getSenderNotify(mentionJID)

text = strings.Replace(text, "@"+numberAndSuffix[0], "@"+mention, 1)
}
Expand Down Expand Up @@ -203,7 +212,9 @@ func (b *Bwhatsapp) handleImageMessage(msg *events.Message) {
ci := imsg.GetContextInfo()

if senderJID == (types.JID{}) && ci.Participant != nil {
senderJID = types.NewJID(ci.GetParticipant(), types.DefaultUserServer)
if parsed, err := types.ParseJID(ci.GetParticipant()); err == nil {
senderJID = parsed
}
}

rmsg := config.Message{
Expand Down Expand Up @@ -242,7 +253,8 @@ func (b *Bwhatsapp) handleImageMessage(msg *events.Message) {

b.Log.Debugf("Trying to download %s with type %s", filename, imsg.GetMimetype())

data, err := b.wc.Download(imsg)
// Fix: Add context.Background() as first parameter
data, err := b.wc.Download(context.Background(), imsg)
if err != nil {
b.Log.Errorf("Download image failed: %s", err)

Expand All @@ -267,7 +279,9 @@ func (b *Bwhatsapp) handleVideoMessage(msg *events.Message) {
ci := imsg.GetContextInfo()

if senderJID == (types.JID{}) && ci.Participant != nil {
senderJID = types.NewJID(ci.GetParticipant(), types.DefaultUserServer)
if parsed, err := types.ParseJID(ci.GetParticipant()); err == nil {
senderJID = parsed
}
}

rmsg := config.Message{
Expand Down Expand Up @@ -309,7 +323,8 @@ func (b *Bwhatsapp) handleVideoMessage(msg *events.Message) {

b.Log.Debugf("Trying to download %s with size %#v and type %s", filename, imsg.GetFileLength(), imsg.GetMimetype())

data, err := b.wc.Download(imsg)
// Fix: Add context.Background() as first parameter
data, err := b.wc.Download(context.Background(), imsg)
if err != nil {
b.Log.Errorf("Download video failed: %s", err)

Expand All @@ -334,7 +349,9 @@ func (b *Bwhatsapp) handleAudioMessage(msg *events.Message) {
ci := imsg.GetContextInfo()

if senderJID == (types.JID{}) && ci.Participant != nil {
senderJID = types.NewJID(ci.GetParticipant(), types.DefaultUserServer)
if parsed, err := types.ParseJID(ci.GetParticipant()); err == nil {
senderJID = parsed
}
}
rmsg := config.Message{
UserID: senderJID.String(),
Expand Down Expand Up @@ -366,7 +383,8 @@ func (b *Bwhatsapp) handleAudioMessage(msg *events.Message) {

b.Log.Debugf("Trying to download %s with size %#v and type %s", filename, imsg.GetFileLength(), imsg.GetMimetype())

data, err := b.wc.Download(imsg)
// Fix: Add context.Background() as first parameter
data, err := b.wc.Download(context.Background(), imsg)
if err != nil {
b.Log.Errorf("Download video failed: %s", err)

Expand All @@ -391,7 +409,9 @@ func (b *Bwhatsapp) handleDocumentMessage(msg *events.Message) {
ci := imsg.GetContextInfo()

if senderJID == (types.JID{}) && ci.Participant != nil {
senderJID = types.NewJID(ci.GetParticipant(), types.DefaultUserServer)
if parsed, err := types.ParseJID(ci.GetParticipant()); err == nil {
senderJID = parsed
}
}

rmsg := config.Message{
Expand Down Expand Up @@ -420,7 +440,8 @@ func (b *Bwhatsapp) handleDocumentMessage(msg *events.Message) {

b.Log.Debugf("Trying to download %s with extension %s and type %s", filename, fileExt, imsg.GetMimetype())

data, err := b.wc.Download(imsg)
// Fix: Add context.Background() as first parameter
data, err := b.wc.Download(context.Background(), imsg)
if err != nil {
b.Log.Errorf("Download document message failed: %s", err)

Expand Down Expand Up @@ -451,4 +472,4 @@ func (b *Bwhatsapp) handleDelete(messageInfo *proto.ProtocolMessage) {
b.Log.Debugf("<= Sending message from %s to gateway", b.Account)
b.Log.Debugf("<= Message is %#v", rmsg)
b.Remote <- rmsg
}
}
23 changes: 17 additions & 6 deletions bridge/whatsappmulti/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package bwhatsapp

import (
"context"
"fmt"
"strings"

Expand All @@ -14,6 +15,7 @@ import (
"go.mau.fi/whatsmeow/store"
"go.mau.fi/whatsmeow/store/sqlstore"
"go.mau.fi/whatsmeow/types"
waLog "go.mau.fi/whatsmeow/util/log"
)

type ProfilePicInfo struct {
Expand All @@ -23,11 +25,13 @@ type ProfilePicInfo struct {
}

func (b *Bwhatsapp) reloadContacts() {
if _, err := b.wc.Store.Contacts.GetAllContacts(); err != nil {
// Fix: Add context.Background() as first parameter
if _, err := b.wc.Store.Contacts.GetAllContacts(context.Background()); err != nil {
b.Log.Errorf("error on update of contacts: %v", err)
}

allcontacts, err := b.wc.Store.Contacts.GetAllContacts()
// Fix: Add context.Background() as first parameter
allcontacts, err := b.wc.Store.Contacts.GetAllContacts(context.Background())
if err != nil {
b.Log.Errorf("error on update of contacts: %v", err)
}
Expand Down Expand Up @@ -117,7 +121,7 @@ func (b *Bwhatsapp) getSenderNotify(senderJid types.JID) string {
func (b *Bwhatsapp) GetProfilePicThumb(jid string) (*types.ProfilePictureInfo, error) {
pjid, _ := types.ParseJID(jid)

info, err := b.wc.GetProfilePictureInfo(pjid, &whatsmeow.GetProfilePictureParams{
info, err := b.wc.GetProfilePictureInfo(context.Background(), pjid, &whatsmeow.GetProfilePictureParams{
Preview: true,
})
if err != nil {
Expand All @@ -133,15 +137,22 @@ func isGroupJid(identifier string) bool {
strings.HasSuffix(identifier, "@broadcast")
}

func isPrivateJid(identifier string) bool {
return strings.HasSuffix(identifier, "@"+types.DefaultUserServer) ||
strings.HasSuffix(identifier, "@"+types.HiddenUserServer)
}

func (b *Bwhatsapp) getDevice() (*store.Device, error) {
device := &store.Device{}

storeContainer, err := sqlstore.New("sqlite", "file:"+b.Config.GetString("sessionfile")+".db?_pragma=foreign_keys(1)&_pragma=busy_timeout=10000", nil)
// Fix: Add context.Background() as first parameter and waLog.Noop logger
storeContainer, err := sqlstore.New(context.Background(), "sqlite", "file:"+b.Config.GetString("sessionfile")+".db?_pragma=foreign_keys(1)&_pragma=busy_timeout=10000", waLog.Noop)
if err != nil {
return device, fmt.Errorf("failed to connect to database: %v", err)
}

device, err = storeContainer.GetFirstDevice()
// Fix: Add context.Background() as first parameter
device, err = storeContainer.GetFirstDevice(context.Background())
if err != nil {
return device, fmt.Errorf("failed to get device: %v", err)
}
Expand Down Expand Up @@ -206,4 +217,4 @@ func getMessageIdFormat(jid types.JID, messageID string) string {
// we're crafting our own JID str as AD JID format messes with how stuff looks on a webclient
jidStr := fmt.Sprintf("%s@%s", jid.User, jid.Server)
return fmt.Sprintf("%s/%s", jidStr, messageID)
}
}
35 changes: 30 additions & 5 deletions bridge/whatsappmulti/whatsapp.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,12 +122,13 @@ func (b *Bwhatsapp) Connect() error {

b.Log.Infoln("WhatsApp connection successful")

b.contacts, err = b.wc.Store.Contacts.GetAllContacts()
// Fix: Add context.Background() as first parameter
b.contacts, err = b.wc.Store.Contacts.GetAllContacts(context.Background())
if err != nil {
return errors.New("failed to get contacts: " + err.Error())
}

b.joinedGroups, err = b.wc.GetJoinedGroups()
b.joinedGroups, err = b.wc.GetJoinedGroups(context.Background())
if err != nil {
return errors.New("failed to get list of joined groups: " + err.Error())
}
Expand Down Expand Up @@ -171,10 +172,34 @@ func (b *Bwhatsapp) Disconnect() error {
return nil
}

// JoinChannel Join a WhatsApp group specified in gateway config as channel='number-id@g.us' or channel='Channel name'
// JoinChannel Join a WhatsApp group specified in gateway config as
// channel='number-id@g.us' or channel='Channel name' or channel='number@s.whatsapp.net' or channel='number@lid'
// Required implementation of the Bridger interface
// https://github.com/42wim/matterbridge/blob/2cfd880cdb0df29771bf8f31df8d990ab897889d/bridge/bridge.go#L11-L16
func (b *Bwhatsapp) JoinChannel(channel config.ChannelInfo) error {
// Skip status@broadcast - it's a special WhatsApp broadcast list, not a joinable group
if channel.Name == "status@broadcast" {
b.Log.Debugf("Skipping status@broadcast channel - not a joinable group")
return nil
}

// Check if this is a private chat JID
if isPrivateJid(channel.Name) {
// For private chats, validate the JID format but don't require group membership
jid, err := types.ParseJID(channel.Name)
if err != nil {
return fmt.Errorf("invalid WhatsApp private chat JID format: %s", err)
}

// Optionally verify that the contact exists in the contacts list
if _, exists := b.contacts[jid]; !exists {
b.Log.Warnf("Private chat contact %s not found in contacts list, but will attempt to bridge anyway", channel.Name)
}

b.Log.Infof("Configured private chat channel: %s", channel.Name)
return nil
}

byJid := isGroupJid(channel.Name)

// verify if we are member of the given group
Expand Down Expand Up @@ -383,7 +408,7 @@ func (b *Bwhatsapp) Send(msg config.Message) (string, error) {
return "", nil
}

_, err := b.wc.RevokeMessage(groupJID, msg.ID)
_, err := b.wc.RevokeMessage(context.Background(), groupJID, msg.ID)

return "", err
}
Expand Down Expand Up @@ -453,4 +478,4 @@ func (b *Bwhatsapp) sendMessage(rmsg config.Message, message *proto.Message) (st
_, err := b.wc.SendMessage(context.Background(), groupJID, message, whatsmeow.SendRequestExtra{ID: ID})

return getMessageIdFormat(*b.wc.Store.ID, ID), err
}
}
35 changes: 20 additions & 15 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -34,24 +34,24 @@ require (
github.com/nelsonken/gomf v0.0.0-20190423072027-c65cc0469e94
github.com/olahol/melody v1.2.1
github.com/paulrosania/go-charset v0.0.0-20190326053356-55c9d7a5834c
github.com/rs/xid v1.5.0
github.com/rs/xid v1.6.0
github.com/russross/blackfriday v1.6.0
github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d
github.com/shazow/ssh-chat v1.10.1
github.com/sirupsen/logrus v1.9.3
github.com/slack-go/slack v0.14.0
github.com/spf13/viper v1.19.0
github.com/stretchr/testify v1.9.0
github.com/stretchr/testify v1.11.1
github.com/vincent-petithory/dataurl v1.0.0
github.com/writeas/go-strip-markdown v2.0.1+incompatible
github.com/yaegashi/msgraph.go v0.1.4
github.com/zfjagann/golang-ring v0.0.0-20220330170733-19bcea1b6289
go.mau.fi/whatsmeow v0.0.0-20240821142752-3d63c6fcc1a7
go.mau.fi/whatsmeow v0.0.0-20260218135554-9cbe80fb25a4
golang.org/x/image v0.19.0
golang.org/x/oauth2 v0.22.0
golang.org/x/text v0.17.0
golang.org/x/text v0.34.0
gomod.garykim.dev/nc-talk v0.3.0
google.golang.org/protobuf v1.34.2
google.golang.org/protobuf v1.36.11
layeh.com/gumble v0.0.0-20221205141517-d1df60a3cc14
modernc.org/sqlite v1.32.0
)
Expand All @@ -62,9 +62,12 @@ require (
github.com/Jeffail/gabs v1.4.0 // indirect
github.com/apex/log v1.9.0 // indirect
github.com/av-elier/go-decimal-to-rational v0.0.0-20191127152832-89e6aad02ecf // indirect
github.com/beeper/argo-go v1.1.2 // indirect
github.com/blang/semver/v4 v4.0.0 // indirect
github.com/coder/websocket v1.8.14 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/dyatlov/go-opengraph/opengraph v0.0.0-20220524092352-606d7b1e5f8a // indirect
github.com/elliotchance/orderedmap/v3 v3.1.0 // indirect
github.com/fatih/color v1.17.0 // indirect
github.com/francoispqt/gojay v1.2.13 // indirect
github.com/go-asn1-ber/asn1-ber v1.5.7 // indirect
Expand All @@ -87,7 +90,7 @@ require (
github.com/mattermost/go-i18n v1.11.1-0.20211013152124-5c415071e404 // indirect
github.com/mattermost/ldap v0.0.0-20231116144001-0f480c025956 // indirect
github.com/mattermost/logr/v2 v2.0.21 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
Expand All @@ -99,14 +102,15 @@ require (
github.com/pborman/uuid v1.2.1 // indirect
github.com/pelletier/go-toml v1.9.5 // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/petermattis/goid v0.0.0-20260113132338-7c7de50cc741 // indirect
github.com/philhofer/fwd v1.1.3-0.20240612014219-fbbf4953d986 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/rickb777/date v1.12.4 // indirect
github.com/rickb777/plural v1.2.0 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/rs/zerolog v1.33.0 // indirect
github.com/rs/zerolog v1.34.0 // indirect
github.com/sagikazarmark/locafero v0.4.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/shazow/rateio v0.0.0-20200113175441-4461efc8bdc4 // indirect
Expand All @@ -120,18 +124,19 @@ require (
github.com/tinylib/msgp v1.2.0 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.2 // indirect
github.com/vektah/gqlparser/v2 v2.5.27 // indirect
github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
github.com/wiggin77/merror v1.0.5 // indirect
github.com/wiggin77/srslog v1.0.1 // indirect
go.mau.fi/libsignal v0.1.1 // indirect
go.mau.fi/util v0.6.0 // indirect
go.mau.fi/libsignal v0.2.1 // indirect
go.mau.fi/util v0.9.6 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/crypto v0.25.0 // indirect
golang.org/x/exp v0.0.0-20240707233637-46b078467d37 // indirect
golang.org/x/net v0.27.0 // indirect
golang.org/x/sys v0.22.0 // indirect
golang.org/x/term v0.22.0 // indirect
golang.org/x/crypto v0.48.0 // indirect
golang.org/x/exp v0.0.0-20260212183809-81e46e3db34a // indirect
golang.org/x/net v0.50.0 // indirect
golang.org/x/sys v0.41.0 // indirect
golang.org/x/term v0.40.0 // indirect
golang.org/x/time v0.5.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240722135656-d784300faade // indirect
google.golang.org/grpc v1.65.0 // indirect
Expand All @@ -150,4 +155,4 @@ require (

//replace github.com/matrix-org/gomatrix => github.com/matterbridge/gomatrix v0.0.0-20220205235239-607eb9ee6419

go 1.22.0
go 1.25.0
Loading