initial work on native keybase bridging
This commit is contained in:
@@ -198,6 +198,7 @@ type BridgeValues struct {
|
|||||||
SSHChat 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
|
WhatsApp map[string]Protocol // TODO is this struct used? Search for "SlackLegacy" for example didn't return any results
|
||||||
Zulip map[string]Protocol
|
Zulip map[string]Protocol
|
||||||
|
Keybase map[string]Protocol
|
||||||
General Protocol
|
General Protocol
|
||||||
Tengo Tengo
|
Tengo Tengo
|
||||||
Gateway []Gateway
|
Gateway []Gateway
|
||||||
|
|||||||
220
bridge/keybase/keybase.go
Normal file
220
bridge/keybase/keybase.go
Normal file
@@ -0,0 +1,220 @@
|
|||||||
|
package bmatrix
|
||||||
|
|
||||||
|
import (
|
||||||
|
"html"
|
||||||
|
"regexp"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/42wim/matterbridge/bridge"
|
||||||
|
"github.com/42wim/matterbridge/bridge/config"
|
||||||
|
"github.com/42wim/matterbridge/bridge/helper"
|
||||||
|
"github.com/keybase/go-keybase-chat-bot/kbchat"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Bkeybase struct {
|
||||||
|
kbc *kbchat.API
|
||||||
|
UserID string
|
||||||
|
sync.RWMutex
|
||||||
|
htmlTag *regexp.Regexp
|
||||||
|
*bridge.Config
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(cfg *bridge.Config) bridge.Bridger { // idk what this does
|
||||||
|
b := &Bkeybase{Config: cfg}
|
||||||
|
b.htmlTag = regexp.MustCompile("</.*?>")
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Bkeybase) Connect() error {
|
||||||
|
var err error
|
||||||
|
b.Log.Infof("Connecting %s", b.GetString("Server"))
|
||||||
|
b.mc, err = matrix.NewClient(b.GetString("Server"), "", "")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
resp, err := b.mc.Login(&matrix.ReqLogin{
|
||||||
|
Type: "m.login.password",
|
||||||
|
User: b.GetString("Login"),
|
||||||
|
Password: b.GetString("Password"),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
b.mc.SetCredentials(resp.UserID, resp.AccessToken)
|
||||||
|
b.UserID = resp.UserID
|
||||||
|
b.Log.Info("Connection succeeded")
|
||||||
|
go b.handlematrix()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Bmatrix) Disconnect() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Bmatrix) JoinChannel(channel config.ChannelInfo) error {
|
||||||
|
resp, err := b.mc.JoinRoom(channel.Name, "", nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
b.Lock()
|
||||||
|
b.RoomMap[resp.RoomID] = channel.Name
|
||||||
|
b.Unlock()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Bmatrix) Send(msg config.Message) (string, error) {
|
||||||
|
b.Log.Debugf("=> Receiving %#v", msg)
|
||||||
|
|
||||||
|
channel := b.getRoomID(msg.Channel)
|
||||||
|
b.Log.Debugf("Channel %s maps to channel id %s", msg.Channel, channel)
|
||||||
|
|
||||||
|
// Make a action /me of the message
|
||||||
|
if msg.Event == config.EventUserAction {
|
||||||
|
m := matrix.TextMessage{
|
||||||
|
MsgType: "m.emote",
|
||||||
|
Body: msg.Username + msg.Text,
|
||||||
|
}
|
||||||
|
resp, err := b.mc.SendMessageEvent(channel, "m.room.message", m)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return resp.EventID, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete message
|
||||||
|
if msg.Event == config.EventMsgDelete {
|
||||||
|
if msg.ID == "" {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
resp, err := b.mc.RedactEvent(channel, msg.ID, &matrix.ReqRedact{})
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return resp.EventID, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Upload a file if it exists
|
||||||
|
if msg.Extra != nil {
|
||||||
|
for _, rmsg := range helper.HandleExtra(&msg, b.General) {
|
||||||
|
if _, err := b.mc.SendText(channel, rmsg.Username+rmsg.Text); err != nil {
|
||||||
|
b.Log.Errorf("sendText failed: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// check if we have files to upload (from slack, telegram or mattermost)
|
||||||
|
if len(msg.Extra["file"]) > 0 {
|
||||||
|
return b.handleUploadFiles(&msg, channel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Edit message if we have an ID
|
||||||
|
// matrix has no editing support
|
||||||
|
|
||||||
|
// Use notices to send join/leave events
|
||||||
|
if msg.Event == config.EventJoinLeave {
|
||||||
|
resp, err := b.mc.SendNotice(channel, msg.Username+msg.Text)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return resp.EventID, err
|
||||||
|
}
|
||||||
|
|
||||||
|
username := html.EscapeString(msg.Username)
|
||||||
|
// check if we have a </tag>. if we have, we don't escape HTML. #696
|
||||||
|
if b.htmlTag.MatchString(msg.Username) {
|
||||||
|
username = msg.Username
|
||||||
|
}
|
||||||
|
// Post normal message with HTML support (eg riot.im)
|
||||||
|
resp, err := b.mc.SendHTML(channel, msg.Username+msg.Text, username+helper.ParseMarkdown(msg.Text))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return resp.EventID, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Bmatrix) getRoomID(channel string) string {
|
||||||
|
b.RLock()
|
||||||
|
defer b.RUnlock()
|
||||||
|
for ID, name := range b.RoomMap {
|
||||||
|
if name == channel {
|
||||||
|
return ID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Bkeybase) handleKeybase() {
|
||||||
|
sub, err := b.kbc.ListenForNewTextMessages()
|
||||||
|
if err != nil {
|
||||||
|
b.Log.Error("Error listening: %s", err.Error())
|
||||||
|
}
|
||||||
|
// syncer.OnEventType("m.room.redaction", b.handleEvent)
|
||||||
|
// syncer.OnEventType("m.room.message", b.handleEvent)
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
msg, err := sub.Read()
|
||||||
|
if err != nil {
|
||||||
|
b.Log.Error("failed to read message: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
if msg.Message.Content.Type != "text" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if msg.Message.Sender.Username == b.kbc.GetUsername() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
b.handleEvent(msg.Message)
|
||||||
|
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Bkeybase) handleEvent(msg kbchat.Message) {
|
||||||
|
b.Log.Debugf("== Receiving event: %#v", msg)
|
||||||
|
if ev.Sender != b.UserID {
|
||||||
|
|
||||||
|
// TODO download avatar
|
||||||
|
|
||||||
|
// Create our message
|
||||||
|
rmsg := config.Message{Username: msg.Sender.Username, Channel: channel, Account: b.Account, UserID: ev.Sender, ID: ev.ID}
|
||||||
|
|
||||||
|
// Text must be a string
|
||||||
|
if rmsg.Text, ok = ev.Content["body"].(string); !ok {
|
||||||
|
b.Log.Errorf("Content[body] is not a string: %T\n%#v",
|
||||||
|
ev.Content["body"], ev.Content)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove homeserver suffix if configured
|
||||||
|
if b.GetBool("NoHomeServerSuffix") {
|
||||||
|
re := regexp.MustCompile("(.*?):.*")
|
||||||
|
rmsg.Username = re.ReplaceAllString(rmsg.Username, `$1`)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete event
|
||||||
|
if ev.Type == "m.room.redaction" {
|
||||||
|
rmsg.Event = config.EventMsgDelete
|
||||||
|
rmsg.ID = ev.Redacts
|
||||||
|
rmsg.Text = config.EventMsgDelete
|
||||||
|
b.Remote <- rmsg
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do we have a /me action
|
||||||
|
if ev.Content["msgtype"].(string) == "m.emote" {
|
||||||
|
rmsg.Event = config.EventUserAction
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do we have attachments
|
||||||
|
if b.containsAttachment(ev.Content) {
|
||||||
|
err := b.handleDownloadFile(&rmsg, ev.Content)
|
||||||
|
if err != nil {
|
||||||
|
b.Log.Errorf("download failed: %#v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
b.Log.Debugf("<= Sending message from %s on %s to gateway", ev.Sender, b.Account)
|
||||||
|
b.Remote <- rmsg
|
||||||
|
}
|
||||||
|
}
|
||||||
1
go.mod
1
go.mod
@@ -20,6 +20,7 @@ require (
|
|||||||
github.com/hpcloud/tail v1.0.0 // indirect
|
github.com/hpcloud/tail v1.0.0 // indirect
|
||||||
github.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7
|
github.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7
|
||||||
github.com/jtolds/gls v4.2.1+incompatible // indirect
|
github.com/jtolds/gls v4.2.1+incompatible // indirect
|
||||||
|
github.com/keybase/go-keybase-chat-bot v0.0.0-20190816161829-561f10822eb2
|
||||||
github.com/labstack/echo/v4 v4.1.6
|
github.com/labstack/echo/v4 v4.1.6
|
||||||
github.com/lrstanley/girc v0.0.0-20190210212025-51b8e096d398
|
github.com/lrstanley/girc v0.0.0-20190210212025-51b8e096d398
|
||||||
github.com/lusis/go-slackbot v0.0.0-20180109053408-401027ccfef5 // indirect
|
github.com/lusis/go-slackbot v0.0.0-20180109053408-401027ccfef5 // indirect
|
||||||
|
|||||||
2
go.sum
2
go.sum
@@ -94,6 +94,8 @@ github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVY
|
|||||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||||
github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1 h1:PJPDf8OUfOK1bb/NeTKd4f1QXZItOX389VN3B6qC8ro=
|
github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1 h1:PJPDf8OUfOK1bb/NeTKd4f1QXZItOX389VN3B6qC8ro=
|
||||||
github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
|
github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
|
||||||
|
github.com/keybase/go-keybase-chat-bot v0.0.0-20190816161829-561f10822eb2 h1:zacJswvfPqUSGdcBXJzKvLN/dB1UjDGDvDesMBBzoA4=
|
||||||
|
github.com/keybase/go-keybase-chat-bot v0.0.0-20190816161829-561f10822eb2/go.mod h1:vNc28YFzigVJod0j5EbuTtRIe7swx8vodh2yA4jZ2s8=
|
||||||
github.com/keybase/go-ps v0.0.0-20161005175911-668c8856d999 h1:2d+FLQbz4xRTi36DO1qYNUwfORax9XcQ0jhbO81Vago=
|
github.com/keybase/go-ps v0.0.0-20161005175911-668c8856d999 h1:2d+FLQbz4xRTi36DO1qYNUwfORax9XcQ0jhbO81Vago=
|
||||||
github.com/keybase/go-ps v0.0.0-20161005175911-668c8856d999/go.mod h1:hY+WOq6m2FpbvyrI93sMaypsttvaIL5nhVR92dTMUcQ=
|
github.com/keybase/go-ps v0.0.0-20161005175911-668c8856d999/go.mod h1:hY+WOq6m2FpbvyrI93sMaypsttvaIL5nhVR92dTMUcQ=
|
||||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||||
|
|||||||
Reference in New Issue
Block a user