Hopefully make a functional keybase bridge

This commit is contained in:
Cori Hudson
2019-08-23 22:16:12 -04:00
parent b9e3576427
commit 1afa05584b
2 changed files with 59 additions and 124 deletions

View File

@@ -87,7 +87,7 @@ type Protocol struct {
IgnoreMessages string // all protocols IgnoreMessages string // all protocols
Jid string // xmpp Jid string // xmpp
Label string // all protocols Label string // all protocols
Login string // mattermost, matrix Login string // mattermost, matrix, keybase
MediaDownloadBlackList []string MediaDownloadBlackList []string
MediaDownloadPath string // Basically MediaServerUpload, but instead of uploading it, just write it to a file on the same server. MediaDownloadPath string // Basically MediaServerUpload, but instead of uploading it, just write it to a file on the same server.
MediaDownloadSize int // all protocols MediaDownloadSize int // all protocols
@@ -131,7 +131,7 @@ type Protocol struct {
StripNick bool // all protocols StripNick bool // all protocols
SyncTopic bool // slack SyncTopic bool // slack
TengoModifyMessage string // general TengoModifyMessage string // general
Team string // mattermost Team string // mattermost, keybase
Token string // gitter, slack, discord, api Token string // gitter, slack, discord, api
Topic string // zulip Topic string // zulip
URL string // mattermost, slack // DEPRECATED URL string // mattermost, slack // DEPRECATED
@@ -145,6 +145,7 @@ type Protocol struct {
VerboseJoinPart bool // IRC VerboseJoinPart bool // IRC
WebhookBindAddress string // mattermost, slack WebhookBindAddress string // mattermost, slack
WebhookURL string // mattermost, slack WebhookURL string // mattermost, slack
PaperKey string // keybase
} }
type ChannelOptions struct { type ChannelOptions struct {

View File

@@ -1,145 +1,91 @@
package bmatrix package bmatrix
import ( import (
"html" "strconv"
"regexp"
"sync"
"github.com/42wim/matterbridge/bridge" "github.com/42wim/matterbridge/bridge"
"github.com/42wim/matterbridge/bridge/config" "github.com/42wim/matterbridge/bridge/config"
"github.com/42wim/matterbridge/bridge/helper"
"github.com/keybase/go-keybase-chat-bot/kbchat" "github.com/keybase/go-keybase-chat-bot/kbchat"
) )
type Bkeybase struct { type Bkeybase struct {
kbc *kbchat.API kbc *kbchat.API
UserID string user string
sync.RWMutex channel string
htmlTag *regexp.Regexp team string
*bridge.Config *bridge.Config
} }
func New(cfg *bridge.Config) bridge.Bridger { // idk what this does func New(cfg *bridge.Config) bridge.Bridger { // idk what this does
b := &Bkeybase{Config: cfg} b := &Bkeybase{Config: cfg}
b.htmlTag = regexp.MustCompile("</.*?>") b.team = b.Config.GetString("Team")
return b return b
} }
func (b *Bkeybase) Connect() error { func (b *Bkeybase) Connect() error {
var err error var err error
b.Log.Infof("Connecting %s", b.GetString("Server")) b.Log.Infof("Connecting %s", b.GetString("Team"))
b.mc, err = matrix.NewClient(b.GetString("Server"), "", "") b.kbc, err = kbchat.Start(kbchat.RunOptions{})
if err != nil { if err != nil {
return err return err
} }
resp, err := b.mc.Login(&matrix.ReqLogin{ b.user = b.kbc.GetUsername()
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") b.Log.Info("Connection succeeded")
go b.handlematrix() go b.handleKeybase()
return nil return nil
} }
func (b *Bmatrix) Disconnect() error { func (b *Bkeybase) Disconnect() error {
return nil return nil
} }
func (b *Bmatrix) JoinChannel(channel config.ChannelInfo) error { func (b *Bkeybase) JoinChannel(channel config.ChannelInfo) error {
resp, err := b.mc.JoinRoom(channel.Name, "", nil)
if err != nil {
return err
}
b.Lock() b.Lock()
b.RoomMap[resp.RoomID] = channel.Name b.channel = channel.Name
b.Unlock() b.Unlock()
return err return nil
} }
func (b *Bmatrix) Send(msg config.Message) (string, error) { func (b *Bkeybase) Send(msg config.Message) (string, error) {
b.Log.Debugf("=> Receiving %#v", msg) b.Log.Debugf("=> Receiving %#v", msg)
channel := b.getRoomID(msg.Channel) // TODO: /me handling
b.Log.Debugf("Channel %s maps to channel id %s", msg.Channel, channel) // 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
// }
// Make a action /me of the message // Delete message not supported by keybase go library yet
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 // Upload a file if it exists
if msg.Extra != nil { // kbchat does not support attachments yet
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 // Edit message if we have an ID
// matrix has no editing support // matrix has no editing support
// Use notices to send join/leave events // Use notices to send join/leave events
if msg.Event == config.EventJoinLeave { // if msg.Event == config.EventJoinLeave {
resp, err := b.mc.SendNotice(channel, msg.Username+msg.Text) // resp, err := b.mc.SendNotice(channel, msg.Username+msg.Text)
if err != nil { // if err != nil {
return "", err // return "", err
} // }
return resp.EventID, err // return resp.EventID, err
} // }
username := html.EscapeString(msg.Username) // resp, err := b.mc.SendHTML(channel, msg.Username+msg.Text, username+helper.ParseMarkdown(msg.Text))
// check if we have a </tag>. if we have, we don't escape HTML. #696 resp, err := b.kbc.SendMessageByTeamName(b.team, msg.Username+msg.Text, &b.channel)
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 { if err != nil {
return "", err return "", err
} }
return resp.EventID, err
}
func (b *Bmatrix) getRoomID(channel string) string { return strconv.Itoa(resp.Result.MsgID), err
b.RLock()
defer b.RUnlock()
for ID, name := range b.RoomMap {
if name == channel {
return ID
}
}
return ""
} }
func (b *Bkeybase) handleKeybase() { func (b *Bkeybase) handleKeybase() {
@@ -172,49 +118,37 @@ func (b *Bkeybase) handleKeybase() {
func (b *Bkeybase) handleEvent(msg kbchat.Message) { func (b *Bkeybase) handleEvent(msg kbchat.Message) {
b.Log.Debugf("== Receiving event: %#v", msg) b.Log.Debugf("== Receiving event: %#v", msg)
if ev.Sender != b.UserID { if msg.Sender.Username != b.kbc.GetUsername() {
// TODO download avatar // TODO download avatar
// Create our message // Create our message
rmsg := config.Message{Username: msg.Sender.Username, Channel: channel, Account: b.Account, UserID: ev.Sender, ID: ev.ID} rmsg := config.Message{Username: msg.Sender.Username, Channel: msg.Channel.Name, ID: strconv.Itoa(msg.MsgID)}
// Text must be a string // Text must be a string
if rmsg.Text, ok = ev.Content["body"].(string); !ok { if msg.Content.Type != "text" {
b.Log.Errorf("Content[body] is not a string: %T\n%#v", b.Log.Errorf("message is not text")
ev.Content["body"], ev.Content)
return return
} }
// Remove homeserver suffix if configured // Delete event TODO
if b.GetBool("NoHomeServerSuffix") { // if ev.Type == "m.room.redaction" {
re := regexp.MustCompile("(.*?):.*") // rmsg.Event = config.EventMsgDelete
rmsg.Username = re.ReplaceAllString(rmsg.Username, `$1`) // rmsg.ID = ev.Redacts
} // rmsg.Text = config.EventMsgDelete
// b.Remote <- rmsg
// Delete event // return
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 // Do we have a /me action
if ev.Content["msgtype"].(string) == "m.emote" { // if ev.Content["msgtype"].(string) == "m.emote" {
rmsg.Event = config.EventUserAction // rmsg.Event = config.EventUserAction
} // }
// Do we have attachments // Do we have attachments
if b.containsAttachment(ev.Content) { // doesn't matter because we can't handle it yet
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.Log.Debugf("<= Sending message from %s on %s to gateway", msg.Sender.Username, msg.Channel.Name)
b.Remote <- rmsg b.Remote <- rmsg
} }
} }