Merge branch 'wait-for-comp-fix' into 'master'
handle xmpp component See merge request genofire/thrempp!1
This commit is contained in:
commit
20efd72da8
|
@ -31,6 +31,10 @@ func Load(configs []Config) {
|
|||
log.WithField("type", config.Type).Panic(err)
|
||||
}
|
||||
config.comp = comp
|
||||
err = config.Start()
|
||||
if err != nil {
|
||||
log.WithField("type", config.Type).Panic(err)
|
||||
}
|
||||
log.WithField("type", config.Type).Infof("component for %s started", config.Host)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
package threema
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/bdlm/log"
|
||||
"github.com/o3ma/o3"
|
||||
"gosrc.io/xmpp"
|
||||
|
||||
"dev.sum7.eu/genofire/golang-lib/database"
|
||||
|
||||
"dev.sum7.eu/genofire/thrempp/models"
|
||||
)
|
||||
|
||||
type Account struct {
|
||||
models.AccountThreema
|
||||
Session o3.SessionContext
|
||||
send chan<- o3.Message
|
||||
recieve <-chan o3.ReceivedMsg
|
||||
}
|
||||
|
||||
func (t *Threema) getAccount(jid *models.JID) *Account {
|
||||
if a, ok := t.accountJID[jid.String()]; ok {
|
||||
return a
|
||||
}
|
||||
account := models.AccountThreema{}
|
||||
|
||||
database.Read.Where("xmpp_id = (?)",
|
||||
database.Read.Table(jid.TableName()).Select("id").Where(map[string]interface{}{
|
||||
"local": jid.Local,
|
||||
"domain": jid.Domain,
|
||||
}).QueryExpr()).First(&account)
|
||||
|
||||
var lsk [32]byte
|
||||
copy(lsk[:], account.LSK[:])
|
||||
tid, err := o3.NewThreemaID(string(account.TID), lsk, o3.AddressBook{})
|
||||
// TODO error handling
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
tid.Nick = o3.NewPubNick("xmpp:" + jid.String())
|
||||
|
||||
a := &Account{AccountThreema: account}
|
||||
a.XMPP = *jid
|
||||
a.Session = o3.NewSessionContext(tid)
|
||||
a.send, a.recieve, err = a.Session.Run()
|
||||
|
||||
// TODO error handling
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
go a.reciever(t.out)
|
||||
|
||||
t.accountJID[jid.String()] = a
|
||||
t.accountTID[string(a.TID)] = a
|
||||
return a
|
||||
}
|
||||
|
||||
func (a *Account) reciever(out chan<- xmpp.Packet) {
|
||||
for receivedMessage := range a.recieve {
|
||||
if receivedMessage.Err != nil {
|
||||
log.Warnf("Error Receiving Message: %s\n", receivedMessage.Err)
|
||||
continue
|
||||
}
|
||||
switch msg := receivedMessage.Msg.(type) {
|
||||
case o3.TextMessage:
|
||||
sender := msg.Sender().String()
|
||||
if string(a.TID) == sender {
|
||||
continue
|
||||
}
|
||||
xMSG := xmpp.NewMessage("chat", sender, a.XMPP.String(), strconv.FormatUint(msg.ID(), 10), "en")
|
||||
xMSG.Body = msg.Text()
|
||||
out <- xMSG
|
||||
case o3.DeliveryReceiptMessage:
|
||||
// msg.MsgID()
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (a *Account) Send(to string, msg string) error {
|
||||
return a.Session.SendTextMessage(to, msg, a.send)
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
package threema
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/bdlm/log"
|
||||
"github.com/o3ma/o3"
|
||||
|
||||
"dev.sum7.eu/genofire/golang-lib/database"
|
||||
|
||||
"dev.sum7.eu/genofire/thrempp/models"
|
||||
)
|
||||
|
||||
func (t *Threema) Bot(from *models.JID, request string) string {
|
||||
server := o3.ThreemaRest{}
|
||||
logger := log.WithFields(map[string]interface{}{
|
||||
"type": "threema",
|
||||
"jid": from.String(),
|
||||
})
|
||||
|
||||
switch request {
|
||||
case "generate":
|
||||
|
||||
// test if account already exists
|
||||
account := t.getAccount(from)
|
||||
if account != nil {
|
||||
return fmt.Sprintf("you already has the threema account with id: %s", string(account.TID))
|
||||
}
|
||||
|
||||
// create account
|
||||
id, err := server.CreateIdentity()
|
||||
if err != nil {
|
||||
logger.Warnf("failed to generate: %s", err)
|
||||
return fmt.Sprintf("failed to create a threema account: %s", err)
|
||||
}
|
||||
//TODO works it
|
||||
if err := database.Read.Where(from).First(from); err != nil {
|
||||
database.Write.Create(from)
|
||||
}
|
||||
|
||||
// store account
|
||||
a := models.AccountThreema{}
|
||||
a.XMPPID = from.ID
|
||||
a.TID = make([]byte, len(id.ID))
|
||||
a.LSK = make([]byte, len(id.LSK))
|
||||
copy(a.TID, id.ID[:])
|
||||
copy(a.LSK, id.LSK[:])
|
||||
database.Write.Create(&a)
|
||||
|
||||
// fetch account and connect
|
||||
account = t.getAccount(from)
|
||||
tid := string(account.TID)
|
||||
if tid != "" {
|
||||
logger.WithField("threema", tid).Info("generate")
|
||||
return fmt.Sprintf("threema account with id: %s", tid)
|
||||
}
|
||||
logger.Warn("failed to generate")
|
||||
return "failed to create a threema account"
|
||||
}
|
||||
return "command not supported"
|
||||
}
|
|
@ -1,13 +1,79 @@
|
|||
package threema
|
||||
|
||||
import "dev.sum7.eu/genofire/thrempp/component"
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/bdlm/log"
|
||||
"gosrc.io/xmpp"
|
||||
|
||||
"dev.sum7.eu/genofire/golang-lib/database"
|
||||
|
||||
"dev.sum7.eu/genofire/thrempp/component"
|
||||
"dev.sum7.eu/genofire/thrempp/models"
|
||||
)
|
||||
|
||||
type Threema struct {
|
||||
component.Component
|
||||
out chan xmpp.Packet
|
||||
accountJID map[string]*Account
|
||||
accountTID map[string]*Account
|
||||
}
|
||||
|
||||
func NewThreema(config map[string]interface{}) (component.Component, error) {
|
||||
return &Threema{}, nil
|
||||
return &Threema{
|
||||
out: make(chan xmpp.Packet),
|
||||
accountJID: make(map[string]*Account),
|
||||
accountTID: make(map[string]*Account),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (t *Threema) Connect() (chan xmpp.Packet, error) {
|
||||
var jids []*models.JID
|
||||
database.Read.Find(&jids)
|
||||
for _, jid := range jids {
|
||||
a := t.getAccount(jid)
|
||||
log.WithFields(map[string]interface{}{
|
||||
"jid": jid.String(),
|
||||
"threema": string(a.TID),
|
||||
}).Debug("connected")
|
||||
}
|
||||
return t.out, nil
|
||||
}
|
||||
func (t *Threema) Send(packet xmpp.Packet) {
|
||||
switch p := packet.(type) {
|
||||
case xmpp.Message:
|
||||
from := models.ParseJID(p.PacketAttrs.From)
|
||||
to := models.ParseJID(p.PacketAttrs.To)
|
||||
|
||||
logger := log.WithFields(map[string]interface{}{
|
||||
"from": from,
|
||||
"to": to,
|
||||
})
|
||||
logger.Debug(p.Body)
|
||||
if to.IsDomain() {
|
||||
msg := xmpp.NewMessage("chat", "", from.String(), "", "en")
|
||||
msg.Body = t.Bot(from, p.Body)
|
||||
t.out <- msg
|
||||
return
|
||||
}
|
||||
|
||||
account := t.getAccount(from)
|
||||
if account == nil {
|
||||
msg := xmpp.NewMessage("chat", "", from.String(), "", "en")
|
||||
msg.Body = "It was not possible to send, becouse we have no account for you.\nPlease generate one, by sending `generate` to this gateway"
|
||||
t.out <- msg
|
||||
return
|
||||
}
|
||||
|
||||
threemaID := strings.ToUpper(to.Local)
|
||||
if err := account.Send(threemaID, p.Body); err != nil {
|
||||
msg := xmpp.NewMessage("chat", "", from.String(), "", "en")
|
||||
msg.Body = err.Error()
|
||||
t.out <- msg
|
||||
}
|
||||
default:
|
||||
log.Warnf("unkown package%v", p)
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package component
|
||||
|
||||
import (
|
||||
"github.com/bdlm/log"
|
||||
"gosrc.io/xmpp"
|
||||
)
|
||||
|
||||
|
@ -32,7 +33,104 @@ func (c *Config) Start() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (c *Config) recieve(chan xmpp.Packet) {
|
||||
func (c *Config) recieve(packets chan xmpp.Packet) {
|
||||
logger := log.WithField("type", c.Type)
|
||||
for packet := range packets {
|
||||
switch p := packet.(type) {
|
||||
case xmpp.Message:
|
||||
if p.PacketAttrs.From == "" {
|
||||
p.PacketAttrs.From = c.Host
|
||||
} else {
|
||||
p.PacketAttrs.From += "@" + c.Host
|
||||
}
|
||||
loggerMSG := logger.WithFields(map[string]interface{}{
|
||||
"from": p.PacketAttrs.From,
|
||||
"to": p.PacketAttrs.To,
|
||||
})
|
||||
loggerMSG.Debug(p.Body)
|
||||
c.xmpp.Send(p)
|
||||
default:
|
||||
log.Warn("ignoring packet:", packet)
|
||||
}
|
||||
}
|
||||
}
|
||||
func (c *Config) sender() {
|
||||
logger := log.WithField("type", c.Type)
|
||||
for {
|
||||
packet, err := c.xmpp.ReadPacket()
|
||||
if err != nil {
|
||||
logger.Panicf("connection closed%s", err)
|
||||
return
|
||||
}
|
||||
|
||||
switch p := packet.(type) {
|
||||
case xmpp.IQ:
|
||||
attrs := p.PacketAttrs
|
||||
loggerIQ := logger.WithFields(map[string]interface{}{
|
||||
"from": attrs.From,
|
||||
"to": attrs.To,
|
||||
})
|
||||
|
||||
switch inner := p.Payload[0].(type) {
|
||||
case *xmpp.DiscoInfo:
|
||||
loggerIQ.Debug("Disco Info")
|
||||
if p.Type == "get" {
|
||||
iq := xmpp.NewIQ("result", attrs.To, attrs.From, attrs.Id, "en")
|
||||
var identity xmpp.Identity
|
||||
if inner.Node == "" {
|
||||
identity = xmpp.Identity{
|
||||
Name: c.Type,
|
||||
Category: "gateway",
|
||||
Type: "service",
|
||||
}
|
||||
}
|
||||
|
||||
payload := xmpp.DiscoInfo{
|
||||
Identity: identity,
|
||||
Features: []xmpp.Feature{
|
||||
{Var: "http://jabber.org/protocol/disco#info"},
|
||||
{Var: "http://jabber.org/protocol/disco#item"},
|
||||
},
|
||||
}
|
||||
iq.AddPayload(&payload)
|
||||
|
||||
_ = c.xmpp.Send(iq)
|
||||
}
|
||||
case *xmpp.DiscoItems:
|
||||
loggerIQ.Debug("DiscoItems")
|
||||
if p.Type == "get" {
|
||||
iq := xmpp.NewIQ("result", attrs.To, attrs.From, attrs.Id, "en")
|
||||
|
||||
var payload xmpp.DiscoItems
|
||||
if inner.Node == "" {
|
||||
payload = xmpp.DiscoItems{
|
||||
Items: []xmpp.DiscoItem{
|
||||
{Name: c.Type, JID: c.Host, Node: "node1"},
|
||||
},
|
||||
}
|
||||
}
|
||||
iq.AddPayload(&payload)
|
||||
_ = c.xmpp.Send(iq)
|
||||
}
|
||||
default:
|
||||
logger.Debug("ignoring iq packet", inner)
|
||||
xError := xmpp.Err{
|
||||
Code: 501,
|
||||
Reason: "feature-not-implemented",
|
||||
Type: "cancel",
|
||||
}
|
||||
reply := p.MakeError(xError)
|
||||
_ = c.xmpp.Send(&reply)
|
||||
}
|
||||
|
||||
case xmpp.Message:
|
||||
c.comp.Send(packet)
|
||||
|
||||
case xmpp.Presence:
|
||||
logger.Debug("Received presence:", p.Type)
|
||||
|
||||
default:
|
||||
logger.Debug("ignoring packet:", packet)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
|
||||
"github.com/jinzhu/gorm"
|
||||
|
||||
"dev.sum7.eu/genofire/golang-lib/database"
|
||||
|
@ -16,6 +18,48 @@ func (j *JID) TableName() string {
|
|||
return "jid"
|
||||
}
|
||||
|
||||
func ParseJID(jidString string) (jid *JID) {
|
||||
jidSplitTmp := jidRegex.FindAllStringSubmatch(jidString, -1)
|
||||
|
||||
if len(jidSplitTmp) != 1 {
|
||||
return nil
|
||||
}
|
||||
jidSplit := jidSplitTmp[0]
|
||||
|
||||
return &JID{
|
||||
Local: jidSplit[1],
|
||||
Domain: jidSplit[2],
|
||||
}
|
||||
}
|
||||
|
||||
func (jid *JID) String() string {
|
||||
if jid == nil {
|
||||
return ""
|
||||
}
|
||||
str := jid.Domain
|
||||
if jid.Local != "" {
|
||||
str = jid.Local + "@" + str
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
func (jid *JID) IsDomain() bool {
|
||||
return jid != nil && jid.Local == "" && jid.Domain != ""
|
||||
}
|
||||
|
||||
func GetJID(jidStr string) (jid *JID) {
|
||||
jidS := ParseJID(jidStr)
|
||||
err := database.Read.Where(jidS).First(jid).Error
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
var jidRegex *regexp.Regexp
|
||||
|
||||
func init() {
|
||||
jidRegex = regexp.MustCompile(`^(?:([^@/<>'\" ]+)@)?([^@/<>'\"]+)(?:/([^<>'\" ][^<>'\"]*))?$`)
|
||||
|
||||
database.AddModel(&JID{})
|
||||
}
|
||||
|
|
Reference in New Issue