Thumbnail

rani/matterbridge.git

Clone URL: https://git.buni.party/rani/matterbridge.git

commit 2f812744e07413743b8d33c0ea79ada031b092d4 Author: Krzysiek Madejski <krzysztof.madejski@epf.org.pl> Date: Thu Feb 21 20:28:13 2019 +0000 Add initial WhatsApp support (#711) diff --git a/README.md b/README.md index 6694c62..82332ba 100644 --- a/README.md +++ b/README.md @@ -186 +187 @@ [Rocket.Chat][mb-rocketchat] | [XMPP][mb-xmpp] | [Twitch][mb-twitch] | + [WhatsApp][mb-whatsapp] | [Zulip][mb-zulip] | And more... </sup> @@ -796 +807 @@  * [Steam](https://store.steampowered.com/)  * [Twitch](https://twitch.tv)  * [Ssh-chat](https://github.com/shazow/ssh-chat) +* [WhatsApp](https://www.whatsapp.com/)  * [Zulip](https://zulipchat.com)    ### 3rd party via matterbridge api @@ -2766 +2787 @@ Matterbridge wouldn't exist without these libraries:  * steam - https://github.com/Philipp15b/go-steam  * telegram - https://github.com/go-telegram-bot-api/telegram-bot-api  * xmpp - https://github.com/mattn/go-xmpp +* whatsapp - https://github.com/Rhymen/go-whatsapp/  * zulip - https://github.com/ifo/gozulipbot    <!-- Links --> @@ -2894 +2925 @@ Matterbridge wouldn't exist without these libraries: [mb-rocketchat]: https://open.rocket.chat/channel/matterbridge [mb-xmpp]: https://inverse.chat/ [mb-twitch]: https://www.twitch.tv/matterbridge + [mb-whatsapp]: https://www.whatsapp.com/ [mb-zulip]: https://matterbridge.zulipchat.com/register/ diff --git a/bridge/config/config.go b/bridge/config/config.go index 98f3f2a..f473ab0 100644 --- a/bridge/config/config.go +++ b/bridge/config/config.go @@ -1856 +1857 @@ type BridgeValues struct {   Telegram map[string]Protocol   Rocketchat map[string]Protocol   SSHChat map[string]Protocol + WhatsApp map[string]Protocol // TODO is this struct used? Search for "SlackLegacy" for example didn't return any results   Zulip map[string]Protocol   General Protocol   Gateway []Gateway diff --git a/bridge/whatsapp/handlers.go b/bridge/whatsapp/handlers.go new file mode 100644 index 0000000..456f200 --- /dev/null +++ b/bridge/whatsapp/handlers.go @@ -00 +1104 @@ +package bwhatsapp + +import ( + "strings" + "time" + + "github.com/42wim/matterbridge/bridge/config" + + "github.com/Rhymen/go-whatsapp" + + whatsappExt "maunium.net/go/mautrix-whatsapp/whatsapp-ext" +) + +/* +Implement handling messages coming from WhatsApp +Check: +- https://github.com/Rhymen/go-whatsapp#add-message-handlers +- https://github.com/Rhymen/go-whatsapp/blob/master/handler.go +- https://github.com/tulir/mautrix-whatsapp/tree/master/whatsapp-ext for more advanced command handling +*/ + +// HandleError received from WhatsApp +func (b *Bwhatsapp) HandleError(err error) { + b.Log.Errorf("%v", err) // TODO implement proper handling? at least respond to different error types +} + +// HandleTextMessage sent from WhatsApp, relay it to the brige +func (b *Bwhatsapp) HandleTextMessage(message whatsapp.TextMessage) { + if message.Info.FromMe { // || !strings.Contains(strings.ToLower(message.Text), "@echo") { + return + } + // whatsapp sends last messages to show context , cut them + if message.Info.Timestamp < b.startedAt { + return + } + + messageTime := time.Unix(int64(message.Info.Timestamp), 0) // TODO check how behaves between timezones + groupJid := message.Info.RemoteJid + + senderJid := message.Info.SenderJid + if len(senderJid) == 0 { + // TODO workaround till https://github.com/Rhymen/go-whatsapp/issues/86 resolved + senderJid = *message.Info.Source.Participant + } + + // translate sender's Jid to the nicest username we can get + senderName := b.getSenderName(senderJid) + if senderName == "" { + senderName = "Someone" // don't expose telephone number + } + + extText := message.Info.Source.Message.ExtendedTextMessage + if extText != nil && extText.ContextInfo != nil && extText.ContextInfo.MentionedJid != nil { + // handle user mentions + for _, mentionedJid := range extText.ContextInfo.MentionedJid { + numberAndSuffix := strings.SplitN(mentionedJid, "@", 2) + + // 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(numberAndSuffix[0] + whatsappExt.NewUserSuffix) + if mention == "" { + mention = "someone" + } + message.Text = strings.Replace(message.Text, "@"+numberAndSuffix[0], "@"+mention, 1) + } + } + + b.Log.Debugf("<= Sending message from %s on %s to gateway", senderJid, b.Account) + rmsg := config.Message{ + UserID: senderJid, + Username: senderName, + Text: message.Text, + Timestamp: messageTime, + Channel: groupJid, + Account: b.Account, + Protocol: b.Protocol, + Extra: make(map[string][]interface{}), + // ParentID: TODO, // TODO handle thread replies // map from Info.QuotedMessageID string + // Event string `json:"event"` + // Gateway string // will be added during message processing + ID: message.Info.Id} + + if avatarURL, exists := b.userAvatars[senderJid]; exists { + rmsg.Avatar = avatarURL + } + + b.Log.Debugf("<= Message is %#v", rmsg) + b.Remote <- rmsg +} + +// +//func (b *Bwhatsapp) HandleImageMessage(message whatsapp.ImageMessage) { +// fmt.Println(message) // TODO implement +//} +// +//func (b *Bwhatsapp) HandleVideoMessage(message whatsapp.VideoMessage) { +// fmt.Println(message) // TODO implement +//} +// +//func (b *Bwhatsapp) HandleJsonMessage(message string) { +// fmt.Println(message) // TODO implement +//} +// TODO HandleRawMessage +// TODO HandleAudioMessage diff --git a/bridge/whatsapp/helpers.go b/bridge/whatsapp/helpers.go new file mode 100644 index 0000000..5268ba3 --- /dev/null +++ b/bridge/whatsapp/helpers.go @@ -00 +184 @@ +package bwhatsapp + +import ( + "encoding/gob" + "errors" + "os" + + qrcodeTerminal "github.com/Baozisoftware/qrcode-terminal-go" + "github.com/Rhymen/go-whatsapp" +) + +func qrFromTerminal(invert bool) chan string { + qr := make(chan string) + go func() { + terminal := qrcodeTerminal.New() + if invert { + terminal = qrcodeTerminal.New2(qrcodeTerminal.ConsoleColors.BrightWhite, qrcodeTerminal.ConsoleColors.BrightBlack, qrcodeTerminal.QRCodeRecoveryLevels.Medium) + } + + terminal.Get(<-qr).Print() + }() + + return qr +} + +func (b *Bwhatsapp) readSession() (whatsapp.Session, error) { + session := whatsapp.Session{} + sessionFile := b.Config.GetString(sessionFile) + + if sessionFile == "" { + return session, errors.New("if you won't set SessionFile then you will need to scan QR code on every restart") + } + + file, err := os.Open(sessionFile) + if err != nil { + return session, err + } + defer file.Close() + decoder := gob.NewDecoder(file) + err = decoder.Decode(&session) + if err != nil { + return session, err + } + return session, nil +} + +func (b *Bwhatsapp) writeSession(session whatsapp.Session) error { + sessionFile := b.Config.GetString(sessionFile) + + if sessionFile == "" { + // we already sent a warning while starting the bridge, so let's be quiet here + return nil + } + + file, err := os.Create(sessionFile) + if err != nil { + return err + } + defer file.Close() + encoder := gob.NewEncoder(file) + err = encoder.Encode(session) + + return err +} + +func (b *Bwhatsapp) getSenderName(senderJid string) string { + if sender, exists := b.users[senderJid]; exists { + if sender.Name != "" { + return sender.Name + } + // if user is not in phone contacts + // it is the most obvious scenario unless you sync your phone contacts with some remote updated source + // users can change it in their WhatsApp settings -> profile -> click on Avatar + return sender.Notify + } + return "" +} + +func (b *Bwhatsapp) getSenderNotify(senderJid string) string { + if sender, exists := b.users[senderJid]; exists { + return sender.Notify + } + return "" +} diff --git a/bridge/whatsapp/whatsapp.go b/bridge/whatsapp/whatsapp.go new file mode 100644 index 0000000..e17339d --- /dev/null +++ b/bridge/whatsapp/whatsapp.go @@ -00 +1305 @@ +package bwhatsapp + +import ( + "crypto/rand" + "encoding/hex" + "errors" + "fmt" + "os" + "strings" + "time" + + "github.com/42wim/matterbridge/bridge" + "github.com/42wim/matterbridge/bridge/config" + + "github.com/Rhymen/go-whatsapp" + + whatsappExt "maunium.net/go/mautrix-whatsapp/whatsapp-ext" +) + +const ( + // Account config parameters + cfgNumber = "Number" + qrOnWhiteTerminal = "QrOnWhiteTerminal" + sessionFile = "SessionFile" +) + +// Bwhatsapp Bridge structure keeping all the information needed for relying +type Bwhatsapp struct { + *bridge.Config + + // https://github.com/Rhymen/go-whatsapp/blob/c31092027237441cffba1b9cb148eadf7c83c3d2/session.go#L18-L21 + session *whatsapp.Session + conn *whatsapp.Conn + // https://github.com/tulir/mautrix-whatsapp/blob/master/whatsapp-ext/whatsapp.go + connExt *whatsappExt.ExtendedConn + startedAt uint64 + + users map[string]whatsapp.Contact + userAvatars map[string]string +} + +// New Create a new WhatsApp bridge. This will be called for each [whatsapp.<server>] entry you have in the config file +func New(cfg *bridge.Config) bridge.Bridger { + number := cfg.GetString(cfgNumber) + if number == "" { + cfg.Log.Fatalf("Missing configuration for WhatsApp bridge: Number") + } + + b := &Bwhatsapp{ + Config: cfg, + + users: make(map[string]whatsapp.Contact), + userAvatars: make(map[string]string), + } + return b +} + +// Connect to WhatsApp. Required implementation of the Bridger interface +// https://github.com/42wim/matterbridge/blob/2cfd880cdb0df29771bf8f31df8d990ab897889d/bridge/bridge.go#L11-L16 +func (b *Bwhatsapp) Connect() error { + b.RLock() // TODO do we need locking for Whatsapp? + defer b.RUnlock() + + number := b.GetString(cfgNumber) + if number == "" { + return errors.New("WhatsApp's telephone Number need to be configured") + } + + // https://github.com/Rhymen/go-whatsapp#creating-a-connection + b.Log.Debugln("Connecting to WhatsApp..") + conn, err := whatsapp.NewConn(20 * time.Second) + if err != nil { + return errors.New("failed to connect to WhatsApp: " + err.Error()) + } + + b.conn = conn + b.connExt = whatsappExt.ExtendConn(b.conn) + // TODO do we want to use it? b.connExt.SetClientName("Matterbridge WhatsApp bridge", "mb-wa") + + b.conn.AddHandler(b) + b.Log.Debugln("WhatsApp connection successful") + + // load existing session in order to keep it between restarts + if b.session == nil { + var session whatsapp.Session + session, err = b.readSession() + + if err == nil { + b.Log.Debugln("Restoring WhatsApp session..") + + // https://github.com/Rhymen/go-whatsapp#restore + session, err = b.conn.RestoreSession(session) + if err != nil { + // TODO return or continue to normal login? + // restore session connection timed out (I couldn't get over it without logging in again) + return errors.New("failed to restore session: " + err.Error()) + } + + b.session = &session + b.Log.Debugln("Session restored successfully!") + } else { + b.Log.Warn(err.Error()) + } + } + + // login to a new session + if b.session == nil { + err = b.Login() + if err != nil { + return err + } + } + b.startedAt = uint64(time.Now().Unix()) + + _, err = b.conn.Contacts() + if err != nil { + return fmt.Errorf("error on update of contacts: %v", err) + } + + // map all the users + for id, contact := range b.conn.Store.Contacts { + if !isGroupJid(id) && id != "status@broadcast" { + // it is user + b.users[id] = contact + } + } + + // get user avatar asynchronously + go func() { + b.Log.Debug("Getting user avatars..") + + for jid := range b.users { + info, err := b.connExt.GetProfilePicThumb(jid) + if err != nil { + b.Log.Warnf("Could not get profile photo of %s: %v", jid, err) + + } else { + // TODO any race conditions here? + b.userAvatars[jid] = info.URL + } + } + b.Log.Debug("Finished getting avatars..") + }() + + return nil +} + +// Login to WhatsApp creating a new session. This will require to scan a QR code on your mobile device +func (b *Bwhatsapp) Login() error { + b.Log.Debugln("Logging in..") + + invert := b.GetBool(qrOnWhiteTerminal) // false is the default + qrChan := qrFromTerminal(invert) + + session, err := b.conn.Login(qrChan) + if err != nil { + b.Log.Warnln("Failed to log in:", err) + return err + } + b.session = &session + + b.Log.Infof("Logged into session: %#v", session) + b.Log.Infof("Connection: %#v", b.conn) + + err = b.writeSession(session) + if err != nil { + fmt.Fprintf(os.Stderr, "error saving session: %v\n", err) + } + + // TODO change connection strings to configured ones longClientName:"github.com/rhymen/go-whatsapp", shortClientName:"go-whatsapp"}" prefix=whatsapp + // TODO get also a nice logo + + // TODO notification about unplugged and dead battery + // conn.Info: Wid, Pushname, Connected, Battery, Plugged + + return nil +} + +// Disconnect is called while reconnecting to the bridge +// TODO 42wim Documentation would be helpful on when reconnects happen and what should be done in this function +// Required implementation of the Bridger interface +// https://github.com/42wim/matterbridge/blob/2cfd880cdb0df29771bf8f31df8d990ab897889d/bridge/bridge.go#L11-L16 +func (b *Bwhatsapp) Disconnect() error { + // We could Logout, but that would close the session completely and would require a new QR code scan + // https://github.com/Rhymen/go-whatsapp/blob/c31092027237441cffba1b9cb148eadf7c83c3d2/session.go#L377-L381 + return nil +} + +func isGroupJid(identifier string) bool { + return strings.HasSuffix(identifier, "@g.us") || strings.HasSuffix(identifier, "@temp") +} + +// JoinChannel Join a WhatsApp group specified in gateway config as channel='number-id@g.us' or channel='Channel name' +// 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 { + byJid := isGroupJid(channel.Name) + + // verify if we are member of the given group + if byJid { + // channel.Name specifies static group jID, not the name + if _, exists := b.conn.Store.Contacts[channel.Name]; !exists { + return fmt.Errorf("account doesn't belong to group with jid %s", channel.Name) + } + } else { + // channel.Name specifies group name that might change, warn about it + var jids []string + for id, contact := range b.conn.Store.Contacts { + if isGroupJid(id) && contact.Name == channel.Name { + jids = append(jids, id) + } + } + + switch len(jids) { + case 0: + // didn't match any group - print out possibilites + // TODO sort + // copy b; + //sort.Slice(people, func(i, j int) bool { + // return people[i].Age > people[j].Age + //}) + for id, contact := range b.conn.Store.Contacts { + if isGroupJid(id) { + b.Log.Infof("%s %s", contact.Jid, contact.Name) + } + } + return fmt.Errorf("please specify group's JID from the list above instead of the name '%s'", channel.Name) + + case 1: + return fmt.Errorf("group name might change. Please configure gateway with channel=\"%v\" instead of channel=\"%v\"", jids[0], channel.Name) + + default: + return fmt.Errorf("there is more than one group with name '%s'. Please specify one of JIDs as channel name: %v", channel.Name, jids) + } + } + + return nil +} + +// Send a message from the bridge to WhatsApp +// Required implementation of the Bridger interface +// https://github.com/42wim/matterbridge/blob/2cfd880cdb0df29771bf8f31df8d990ab897889d/bridge/bridge.go#L11-L16 +func (b *Bwhatsapp) Send(msg config.Message) (string, error) { + b.Log.Debugf("=> Receiving %#v", msg) + + // Delete message + if msg.Event == config.EventMsgDelete { + if msg.ID == "" { + // No message ID in case action is executed on a message sent before the bridge was started + // and then the bridge cache doesn't have this message ID mapped + + // TODO 42wim Doesn't the app get clogged with a ton of IDs after some time of running? + // WhatsApp allows to set any ID so in that case we could use external IDs and don't do mapping + // but external IDs are not set + return "", nil + } + // TODO delete message on WhatsApp https://github.com/Rhymen/go-whatsapp/issues/100 + return "", nil + } + + // Edit message + if msg.ID != "" { + b.Log.Debugf("updating message with id %s", msg.ID) + + msg.Text += " (edited)" + // TODO handle edit as a message reply with updated text + } + + //// TODO Handle Upload a file + //if msg.Extra != nil { + // for _, rmsg := range helper.HandleExtra(&msg, b.General) { + // b.c.SendMessage(roomID, rmsg.Username+rmsg.Text) + // } + // if len(msg.Extra["file"]) > 0 { + // return b.handleUploadFile(&msg, roomID) + // } + //} + + // Post text message + text := whatsapp.TextMessage{ + Info: whatsapp.MessageInfo{ + RemoteJid: msg.Channel, // which equals to group id + }, + Text: msg.Username + msg.Text, + } + + b.Log.Debugf("=> Sending %#v", msg) + + // create message ID + // TODO follow and act if https://github.com/Rhymen/go-whatsapp/issues/101 implemented + bytes := make([]byte, 10) + if _, err := rand.Read(bytes); err != nil { + b.Log.Warn(err.Error()) + } + text.Info.Id = strings.ToUpper(hex.EncodeToString(bytes)) + + err := b.conn.Send(text) + + return text.Info.Id, err +} + +// TODO do we want that? to allow login with QR code from a bridged channel? https://github.com/tulir/mautrix-whatsapp/blob/513eb18e2d59bada0dd515ee1abaaf38a3bfe3d5/commands.go#L76 +//func (b *Bwhatsapp) Command(cmd string) string { +// return "" +//} diff --git a/gateway/bridgemap/bridgemap.go b/gateway/bridgemap/bridgemap.go index 20577dc..1ad013e 100644 --- a/gateway/bridgemap/bridgemap.go +++ b/gateway/bridgemap/bridgemap.go @@ -136 +137 @@ import (   "github.com/42wim/matterbridge/bridge/sshchat"   "github.com/42wim/matterbridge/bridge/steam"   "github.com/42wim/matterbridge/bridge/telegram" + "github.com/42wim/matterbridge/bridge/whatsapp"   "github.com/42wim/matterbridge/bridge/xmpp"   "github.com/42wim/matterbridge/bridge/zulip"  ) @@ -306 +317 @@ var FullMap = map[string]bridge.Factory{   "sshchat": bsshchat.New,   "steam": bsteam.New,   "telegram": btelegram.New, + "whatsapp": bwhatsapp.New,   "xmpp": bxmpp.New,   "zulip": bzulip.New,  } diff --git a/go.mod b/go.mod index 15fbb83..0d79c67 100644 --- a/go.mod +++ b/go.mod @@ -214 +215 @@ module github.com/42wim/matterbridge    require (   github.com/42wim/go-gitter v0.0.0-20170828205020-017310c2d557 + github.com/Baozisoftware/qrcode-terminal-go v0.0.0-20170407111555-c0650d8dff0f   github.com/BurntSushi/toml v0.0.0-20170318202913-d94612f9fc14 // indirect   github.com/Jeffail/gabs v1.1.1 // indirect   github.com/Philipp15b/go-steam v1.0.1-0.20180818081528-681bd9573329 + github.com/Rhymen/go-whatsapp v0.0.0-20190208184307-c9a81e957884   github.com/bwmarrin/discordgo v0.19.0   github.com/dfordsoft/golib v0.0.0-20180902042739-76ee6ab99bec   github.com/fsnotify/fsnotify v1.4.7   github.com/go-telegram-bot-api/telegram-bot-api v4.6.5-0.20181225215658-ec221ba9ea45+incompatible - github.com/golang/protobuf v0.0.0-20170613224224-e325f446bebc // indirect   github.com/google/gops v0.3.5   github.com/gopackage/ddp v0.0.0-20170117053602-652027933df4 // indirect   github.com/gopherjs/gopherjs v0.0.0-20180628210949-0892b62f0d9f // indirect @@ -477 +486 @@ require (   github.com/russross/blackfriday v2.0.0+incompatible   github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca   github.com/shazow/ssh-chat v0.0.0-20190125184227-81d7e1686296 - github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95 // indirect   github.com/sirupsen/logrus v1.3.0   github.com/smartystreets/assertions v0.0.0-20180803164922-886ec427f6b9 // indirect   github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a // indirect @@ -6510 +658 @@ require (   go.uber.org/atomic v1.3.2 // indirect   go.uber.org/multierr v1.1.0 // indirect   go.uber.org/zap v1.9.1 // indirect - golang.org/x/net v0.0.0-20180108090419-434ec0c7fe37 // indirect - golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f // indirect - gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect   gopkg.in/fsnotify.v1 v1.4.7 // indirect   gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect   gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect + maunium.net/go/mautrix-whatsapp v0.0.0-20190127121751-281b3e8f77f3  ) diff --git a/go.sum b/go.sum index 4df46c7..f0fabad 100644 --- a/go.sum +++ b/go.sum @@ -111 +117 @@  github.com/42wim/go-gitter v0.0.0-20170828205020-017310c2d557 h1:IZtuWGfzQnKnCSu+vl8WGLhpVQ5Uvy3rlSwqXSg+sQg=  github.com/42wim/go-gitter v0.0.0-20170828205020-017310c2d557/go.mod h1:jL0YSXMs/txjtGJ4PWrmETOk6KUHMDPMshgQZlTeB3Y= +github.com/Baozisoftware/qrcode-terminal-go v0.0.0-20170407111555-c0650d8dff0f h1:2dk3eOnYllh+wUOuDhOoC2vUVoJF/5z478ryJ+wzEII= +github.com/Baozisoftware/qrcode-terminal-go v0.0.0-20170407111555-c0650d8dff0f/go.mod h1:4a58ifQTEe2uwwsaqbh3i2un5/CBPg+At/qHpt18Tmk=  github.com/BurntSushi/toml v0.0.0-20170318202913-d94612f9fc14 h1:v/zr4ns/4sSahF9KBm4Uc933bLsEEv7LuT63CJ019yo=  github.com/BurntSushi/toml v0.0.0-20170318202913-d94612f9fc14/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=  github.com/Jeffail/gabs v1.1.1 h1:V0uzR08Hj22EX8+8QMhyI9sX2hwRu+/RJhJUmnwda/E=  github.com/Jeffail/gabs v1.1.1/go.mod h1:6xMvQMK4k33lb7GUUpaAPh6nKMmemQeg5d4gn7/bOXc=  github.com/Philipp15b/go-steam v1.0.1-0.20180818081528-681bd9573329 h1:xZBoq249G9MSt+XuY7sVQzcfONJ6IQuwpCK+KAaOpnY=  github.com/Philipp15b/go-steam v1.0.1-0.20180818081528-681bd9573329/go.mod h1:HuVM+sZFzumUdKPWiz+IlCMb4RdsKdT3T+nQBKL+sYg= +github.com/Rhymen/go-whatsapp v0.0.0-20181218094654-2ca6af00572c h1:ldRXgMEfKmzBomrZusl3edG9AGEeztA7jovLEQy62us= +github.com/Rhymen/go-whatsapp v0.0.0-20181218094654-2ca6af00572c/go.mod h1:MSDmePOOkbFFbVW2WRRppBcbA+aabwpXRgyIIG7jDFQ= +github.com/Rhymen/go-whatsapp v0.0.0-20190208184307-c9a81e957884 h1:2AxfzkQi2L4QGBvUCZoWD6hQuUJa5MG54wiYyNqJlf4= +github.com/Rhymen/go-whatsapp v0.0.0-20190208184307-c9a81e957884/go.mod h1:rdQr95g2C1xcOfM7QGOhza58HeI3I+tZ/bbluv7VazA=  github.com/alexcesaro/log v0.0.0-20150915221235-61e686294e58 h1:MkpmYfld/S8kXqTYI68DfL8/hHXjHogL120Dy00TIxc=  github.com/alexcesaro/log v0.0.0-20150915221235-61e686294e58/go.mod h1:YNfsMyWSs+h+PaYkxGeMVmVCX75Zj/pqdjbu12ciCYE=  github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= @@ -2118 +2722 @@ github.com/dfordsoft/golib v0.0.0-20180902042739-76ee6ab99bec h1:JEUiu7P9smN7zgX  github.com/dfordsoft/golib v0.0.0-20180902042739-76ee6ab99bec/go.mod h1:UGa5M2Sz/Uh13AMse4+RELKCDw7kqgqlTjeGae+7vUY=  github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=  github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=  github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=  github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=  github.com/go-telegram-bot-api/telegram-bot-api v4.6.5-0.20181225215658-ec221ba9ea45+incompatible h1:i64CCJcSqkRIkm5OSdZQjZq84/gJsk2zNwHWIRYWlKE=  github.com/go-telegram-bot-api/telegram-bot-api v4.6.5-0.20181225215658-ec221ba9ea45+incompatible/go.mod h1:qf9acutJ8cwBUhm1bqgz6Bei9/C/c93FPDljKWwsOgM=  github.com/golang/protobuf v0.0.0-20170613224224-e325f446bebc h1:wdhDSKrkYy24mcfzuA3oYm58h0QkyXjwERCkzJDP5kA=  github.com/golang/protobuf v0.0.0-20170613224224-e325f446bebc/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=  github.com/google/gops v0.3.5 h1:SIWvPLiYvy5vMwjxB3rVFTE4QBhUFj2KKWr3Xm7CKhw=  github.com/google/gops v0.3.5/go.mod h1:pMQgrscwEK/aUSW1IFSaBPbJX82FPHWaSoJw1axQfD0=  github.com/gopackage/ddp v0.0.0-20170117053602-652027933df4 h1:4EZlYQIiyecYJlUbVkFXCXHz1QPhVXcHnQKAzBTPfQo=  github.com/gopackage/ddp v0.0.0-20170117053602-652027933df4/go.mod h1:lEO7XoHJ/xNRBCxrn4h/CEB67h0kW1B0t4ooP2yrjUA=  github.com/gopherjs/gopherjs v0.0.0-20180628210949-0892b62f0d9f h1:FDM3EtwZLyhW48YRiyqjivNlNZjAObv4xt4NnJaU+NQ=  github.com/gopherjs/gopherjs v0.0.0-20180628210949-0892b62f0d9f/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=  github.com/gorilla/schema v1.0.2 h1:sAgNfOcNYvdDSrzGHVy9nzCQahG+qmsg+nE8dK85QRA=  github.com/gorilla/schema v1.0.2/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU=  github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= @@ -866 +967 @@ github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRU  github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=  github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs=  github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=  github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4=  github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=  github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= @@ -1206 +1317 @@ github.com/rs/xid v1.2.1 h1:mhH9Nq+C1fY2l1XIpgxIiUOfNpRBYH1kKcr+qfKgjRc=  github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=  github.com/russross/blackfriday v2.0.0+incompatible h1:cBXrhZNUf9C+La9/YpS+UHpUT8YD6Td9ZMSU9APFcsk=  github.com/russross/blackfriday v2.0.0+incompatible/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=  github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca h1:NugYot0LIVPxTvN8n+Kvkn6TrbMyxQiuvKdEwFdR9vI=  github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca/go.mod h1:uugorj2VCxiV1x+LzaIdVa9b4S4qGAcH6cbhh4qVxOU=  github.com/shazow/rateio v0.0.0-20150116013248-e8e00881e5c1 h1:Lx3BlDGFElJt4u/zKc9A3BuGYbQAGlEFyPuUA3jeMD0= @@ -1288 +14013 @@ github.com/shazow/ssh-chat v0.0.0-20190125184227-81d7e1686296 h1:8RLq547MSVc6vhO  github.com/shazow/ssh-chat v0.0.0-20190125184227-81d7e1686296/go.mod h1:1GLXsL4esywkpNId3v4QWuMf3THtWGitWvtQ/L3aSA4=  github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95 h1:/vdW8Cb7EXrkqWGufVMES1OH2sU9gKVb2n9/1y5NMBY=  github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=  github.com/sirupsen/logrus v1.3.0 h1:hI/7Q+DtNZ2kINb6qt/lS+IyXnHQe9e90POfeewL/ME=  github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/skip2/go-qrcode v0.0.0-20171229120447-cf5f9fa2f0d8/go.mod h1:PLPIyL7ikehBD1OAjmKKiOEhbvWyHGaNDjquXMcYABo= +github.com/skip2/go-qrcode v0.0.0-20190110000554-dc11ecdae0a9 h1:lpEzuenPuO1XNTeikEmvqYFcU37GVLl8SRNblzyvGBE= +github.com/skip2/go-qrcode v0.0.0-20190110000554-dc11ecdae0a9/go.mod h1:PLPIyL7ikehBD1OAjmKKiOEhbvWyHGaNDjquXMcYABo=  github.com/smartystreets/assertions v0.0.0-20180803164922-886ec427f6b9 h1:lXQ+j+KwZcbwrbgU0Rp4Eglg3EJLHbuZU3BbOqAGBmg=  github.com/smartystreets/assertions v0.0.0-20180803164922-886ec427f6b9/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=  github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a h1:JSvGDIbmil4Ui/dDdFBExb7/cmkNjyX5F97oglmvCDo= @@ -18514 +20223 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf  golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16 h1:y6ce7gCWtnH+m3dCjzQ1PCuwl28DDIc3VNnvY29DlIA=  golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=  golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190103213133-ff983b9c42bc/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=  golang.org/x/crypto v0.0.0-20190130090550-b01c7a725664 h1:YbZJ76lQ1BqNhVe7dKTSB67wDrc2VPRR75IyGyyPDX8=  golang.org/x/crypto v0.0.0-20190130090550-b01c7a725664/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190131182504-b8fe1690c613 h1:MQ/ZZiDsUapFFiMS+vzwXkCTeEKaum+Do5rINYJDmxc= +golang.org/x/crypto v0.0.0-20190131182504-b8fe1690c613/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=  golang.org/x/net v0.0.0-20180108090419-434ec0c7fe37 h1:BkNcmLtAVeWe9h5k0jt24CQgaG5vb4x/doFbAiEC/Ho=  golang.org/x/net v0.0.0-20180108090419-434ec0c7fe37/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190110200230-915654e7eabc h1:Yx9JGxI1SBhVLFjpAkWMaO1TF+xyqtHLjZpvQboJGiM= +golang.org/x/net v0.0.0-20190110200230-915654e7eabc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=  golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA=  golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=  golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=  golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181212120007-b05ddf57801d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190109145017-48ac38b7c8cb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=  golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc h1:WiYx1rIFmx8c0mXAFtv5D/mHyKe1+jmuP7PViuwqwuQ=  golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=  golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= @@ -2083 +2349 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkep  gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=  gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=  gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +maunium.net/go/mauflag v1.0.0/go.mod h1:nLivPOpTpHnpzEh8jEdSL9UqO9+/KBJFmNRlwKfkPeA= +maunium.net/go/maulogger/v2 v2.0.0/go.mod h1:Hbbkq3NV6jvJodByZu1mgEF3fpT7Kz9z0MjEZ3/BusI= +maunium.net/go/mautrix v0.1.0-alpha.3/go.mod h1:GTVu6WDHR+98DKOrYetWsXorvUeKQV3jsSWO6ScbuFI= +maunium.net/go/mautrix-appservice v0.1.0-alpha.3/go.mod h1:wOnWOIuprYad7ly12rHIo3JLCPh4jwvx1prVrAB9RhM= +maunium.net/go/mautrix-whatsapp v0.0.0-20190127121751-281b3e8f77f3 h1:A18t5Lp7I3aK0V7B7zdpb0hb/PBlu0X/Ai2AyU/XEk4= +maunium.net/go/mautrix-whatsapp v0.0.0-20190127121751-281b3e8f77f3/go.mod h1:r5E3J4urDEsjfui9OYZYMLBfCliaAqcCwM2xeczta6k= diff --git a/matterbridge.toml.sample b/matterbridge.toml.sample index 33bf99c..55f3ab7 100644 --- a/matterbridge.toml.sample +++ b/matterbridge.toml.sample @@ -117210 +117245 @@ StripNick=false  #OPTIONAL (default false)  ShowTopicChange=false   + + +################################################################### +# +# WhatsApp +# +################################################################### + +[whatsapp.bridge] + +# Number you will use as a relay bot. Tip: Get some disposable sim card, don't rely on your own number. +Number="+48111222333" + +# First time that you login you will need to scan QR code, then credentials willl be saved in a session file +# If you won't set SessionFile then you will need to scan QR code on every restart +# optional (by default the session is stored only in memory, till restarting matterbridge) +SessionFile="session-48111222333.gob" + +# If your terminal is white we need to invert QR code in order for it to be scanned properly +# optional (default false) +QrOnWhiteTerminal=true + +# Messages will be seen by other WhatsApp contacts as coming from the bridge. Original nick will be part of the message. +RemoteNickFormat="@{NICK}: " + +# extra label that can be used in the RemoteNickFormat +# optional (default empty) +Label="Organization" + + +  ################################################################### -#zulip section +# +# zulip +#  ################################################################### +  [zulip] +  #You can configure multiple servers "[zulip.name]" or "[zulip.name2]"  #In this example we use [zulip.streamchat]  #REQUIRED @@ -137336 +140841 @@ name="gateway1"  ##OPTIONAL (default false)  enable=true   - #[[gateway.in]] specifies the account and channels we will receive messages from. - #The following example bridges between mattermost and irc + # [[gateway.in]] specifies the account and channels we will receive messages from. + # The following example bridges between mattermost and irc [[gateway.in]]   - #account specified above - #REQUIRED + # account specified above + # REQUIRED account="irc.freenode" - #channel to connect on that account - #How to specify them for the different bridges: + + # channel to connect on that account + # How to specify them for the different bridges: # - #irc - #channel (# is required) (this needs to be lowercase!) - #mattermost - channel (the channel name as seen in the URL, not the displayname) - #gitter - username/room - #xmpp - channel - #slack - channel (without the #) - # - ID:C123456 (where C123456 is the channel ID) does not work with webhook - #discord - channel (without the #) - # - ID:123456789 (where 123456789 is the channel ID) + # irc - #channel (# is required) (this needs to be lowercase!) + # mattermost - channel (the channel name as seen in the URL, not the displayname) + # gitter - username/room + # xmpp - channel + # slack - channel (without the #) + # - ID:C123456 (where C123456 is the channel ID) does not work with webhook + # discord - channel (without the #) + # - ID:123456789 (where 123456789 is the channel ID) # (https://github.com/42wim/matterbridge/issues/57) - #telegram - chatid (a large negative number, eg -123456789) + # telegram - chatid (a large negative number, eg -123456789) # see (https://www.linkedin.com/pulse/telegram-bots-beginners-marco-frau) - #hipchat - id_channel (see https://www.hipchat.com/account/xmpp for the correct channel) - #rocketchat - #channel (# is required (also needed for private channels!) - #matrix - #channel:server (eg #yourchannel:matrix.org) - # - encrypted rooms are not supported in matrix - #steam - chatid (a large number). + # hipchat - id_channel (see https://www.hipchat.com/account/xmpp for the correct channel) + # rocketchat - #channel (# is required (also needed for private channels!) + # matrix - #channel:server (eg #yourchannel:matrix.org) + # - encrypted rooms are not supported in matrix + # steam - chatid (a large number). # The number in the URL when you click "enter chat room" in the browser - #zulip - stream (without the #) + # whatsapp - 48111222333-123455678999@g.us A unique group JID; + # if you specify an empty string bridge will list all the possibilities + # - "Group Name" if you specify a group name the bridge will hint its JID to specify + # as group names might change in time and contain weird emoticons + # zulip - stream (without the #) # - #REQUIRED + # REQUIRED channel="#testing"   #OPTIONAL - only used for IRC and XMPP protocols at the moment