From 3787c86fbf524edc8c15280138140104886ee28b Mon Sep 17 00:00:00 2001 From: Martin/Geno Date: Fri, 31 May 2019 13:53:44 +0200 Subject: [PATCH 1/4] handle xmpp component --- component/main.go | 4 ++ component/threema/main.go | 10 ++++- component/xmpp.go | 77 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 90 insertions(+), 1 deletion(-) diff --git a/component/main.go b/component/main.go index 0919671..9013bee 100644 --- a/component/main.go +++ b/component/main.go @@ -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) } } diff --git a/component/threema/main.go b/component/threema/main.go index 0616aac..349e215 100644 --- a/component/threema/main.go +++ b/component/threema/main.go @@ -1,6 +1,9 @@ package threema -import "dev.sum7.eu/genofire/thrempp/component" +import ( + "dev.sum7.eu/genofire/thrempp/component" + "gosrc.io/xmpp" +) type Threema struct { component.Component @@ -10,6 +13,11 @@ func NewThreema(config map[string]interface{}) (component.Component, error) { return &Threema{}, nil } +func (t *Threema) Connect() (chan xmpp.Packet, error) { + c := make(chan xmpp.Packet) + return c, nil +} + func init() { component.AddComponent("threema", NewThreema) } diff --git a/component/xmpp.go b/component/xmpp.go index 02a4ca6..1edf43c 100644 --- a/component/xmpp.go +++ b/component/xmpp.go @@ -1,6 +1,7 @@ package component import ( + "github.com/bdlm/log" "gosrc.io/xmpp" ) @@ -35,4 +36,80 @@ func (c *Config) Start() error { func (c *Config) recieve(chan xmpp.Packet) { } func (c *Config) sender() { + logger := log.WithField("type", c.Type) + for { + logger.Debug("wait fo recieve") + packet, err := c.xmpp.ReadPacket() + if err != nil { + logger.Panicf("connection closed%s", err) + return + } + logger.Debug("recieve") + + switch p := packet.(type) { + case xmpp.IQ: + attrs := p.PacketAttrs + + switch inner := p.Payload[0].(type) { + case *xmpp.DiscoInfo: + logger.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: + logger.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.Warn("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: + logger.Info("Received message:", p.Body) + + case xmpp.Presence: + logger.Info("Received presence:", p.Type) + + default: + logger.Warn("ignoring packet:", packet) + } + } } From 587e0b1e152937dab5aa2be6a190e0e7bb5377a2 Mon Sep 17 00:00:00 2001 From: Martin/Geno Date: Fri, 31 May 2019 14:36:18 +0200 Subject: [PATCH 2/4] handle xmpp message --- component/threema/account.go | 18 ++++++++++++++++++ component/threema/main.go | 31 ++++++++++++++++++++++++++++--- component/xmpp.go | 33 +++++++++++++++++++++++++++------ 3 files changed, 73 insertions(+), 9 deletions(-) create mode 100644 component/threema/account.go diff --git a/component/threema/account.go b/component/threema/account.go new file mode 100644 index 0000000..f5e4726 --- /dev/null +++ b/component/threema/account.go @@ -0,0 +1,18 @@ +package threema + +import "errors" + +type ThreemaAccount struct { + ID string +} + +func (t *Threema) getAccount(jid string) *ThreemaAccount { + return &ThreemaAccount{} +} + +func (a *ThreemaAccount) Send(to string, msg string) error { + if a.ID == "" { + return errors.New("It was not possible to send, becaouse we have no account for you.\nPlease generate one, by sending `generate` to gateway") + } + return nil +} diff --git a/component/threema/main.go b/component/threema/main.go index 349e215..545d3d4 100644 --- a/component/threema/main.go +++ b/component/threema/main.go @@ -1,12 +1,17 @@ package threema import ( - "dev.sum7.eu/genofire/thrempp/component" + "strings" + + "github.com/bdlm/log" "gosrc.io/xmpp" + + "dev.sum7.eu/genofire/thrempp/component" ) type Threema struct { component.Component + out chan xmpp.Packet } func NewThreema(config map[string]interface{}) (component.Component, error) { @@ -14,8 +19,28 @@ func NewThreema(config map[string]interface{}) (component.Component, error) { } func (t *Threema) Connect() (chan xmpp.Packet, error) { - c := make(chan xmpp.Packet) - return c, nil + t.out = make(chan xmpp.Packet) + return t.out, nil +} +func (t *Threema) Send(packet xmpp.Packet) { + switch p := packet.(type) { + case xmpp.Message: + attrs := p.PacketAttrs + account := t.getAccount(attrs.From) + log.WithFields(map[string]interface{}{ + "from": attrs.From, + "to": attrs.To, + }).Debug(p.Body) + threemaID := strings.ToUpper(strings.Split(attrs.To, "@")[0]) + err := account.Send(threemaID, p.Body) + if err != nil { + msg := xmpp.NewMessage("chat", "", attrs.From, "", "en") + msg.Body = err.Error() + t.out <- msg + } + default: + log.Warnf("unkown package%v", p) + } } func init() { diff --git a/component/xmpp.go b/component/xmpp.go index 1edf43c..77fd576 100644 --- a/component/xmpp.go +++ b/component/xmpp.go @@ -33,26 +33,47 @@ 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 { - logger.Debug("wait fo recieve") packet, err := c.xmpp.ReadPacket() if err != nil { logger.Panicf("connection closed%s", err) return } - logger.Debug("recieve") 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: - logger.Debug("Disco Info") + loggerIQ.Debug("Disco Info") if p.Type == "get" { iq := xmpp.NewIQ("result", attrs.To, attrs.From, attrs.Id, "en") var identity xmpp.Identity @@ -76,7 +97,7 @@ func (c *Config) sender() { _ = c.xmpp.Send(iq) } case *xmpp.DiscoItems: - logger.Debug("DiscoItems") + loggerIQ.Debug("DiscoItems") if p.Type == "get" { iq := xmpp.NewIQ("result", attrs.To, attrs.From, attrs.Id, "en") @@ -103,7 +124,7 @@ func (c *Config) sender() { } case xmpp.Message: - logger.Info("Received message:", p.Body) + c.comp.Send(packet) case xmpp.Presence: logger.Info("Received presence:", p.Type) From 90c5f4c5e111abd53de54dbd802d866994ed5399 Mon Sep 17 00:00:00 2001 From: Martin/Geno Date: Fri, 31 May 2019 18:26:15 +0200 Subject: [PATCH 3/4] send to threema --- component/threema/account.go | 59 +++++++++++++++++++++++++++------- component/threema/bot.go | 61 ++++++++++++++++++++++++++++++++++++ component/threema/main.go | 50 +++++++++++++++++++++-------- models/jid.go | 44 ++++++++++++++++++++++++++ 4 files changed, 190 insertions(+), 24 deletions(-) create mode 100644 component/threema/bot.go diff --git a/component/threema/account.go b/component/threema/account.go index f5e4726..c7ee62f 100644 --- a/component/threema/account.go +++ b/component/threema/account.go @@ -1,18 +1,55 @@ package threema -import "errors" +import ( + "github.com/o3ma/o3" -type ThreemaAccount struct { - ID string + "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 string) *ThreemaAccount { - return &ThreemaAccount{} -} - -func (a *ThreemaAccount) Send(to string, msg string) error { - if a.ID == "" { - return errors.New("It was not possible to send, becaouse we have no account for you.\nPlease generate one, by sending `generate` to gateway") +func (t *Threema) getAccount(jid *models.JID) *Account { + if a, ok := t.accountJID[jid.String()]; ok { + return a } - return nil + 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.Session = o3.NewSessionContext(tid) + a.send, a.recieve, err = a.Session.Run() + + // TODO error handling + if err != nil { + return nil + } + + t.accountJID[jid.String()] = a + t.accountTID[string(a.TID)] = a + return a +} + +func (a *Account) Send(to string, msg string) error { + return a.Session.SendTextMessage(to, msg, a.send) } diff --git a/component/threema/bot.go b/component/threema/bot.go new file mode 100644 index 0000000..7edcc61 --- /dev/null +++ b/component/threema/bot.go @@ -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" +} diff --git a/component/threema/main.go b/component/threema/main.go index 545d3d4..7715a20 100644 --- a/component/threema/main.go +++ b/component/threema/main.go @@ -7,34 +7,58 @@ import ( "gosrc.io/xmpp" "dev.sum7.eu/genofire/thrempp/component" + "dev.sum7.eu/genofire/thrempp/models" ) type Threema struct { component.Component - out chan xmpp.Packet + out chan xmpp.Packet + accountJID map[string]*Account + accountTID map[string]*Account } func NewThreema(config map[string]interface{}) (component.Component, error) { - return &Threema{}, nil + t := &Threema{ + out: make(chan xmpp.Packet), + accountJID: make(map[string]*Account), + accountTID: make(map[string]*Account), + } + // TODO load accounts on startup + return t, nil } func (t *Threema) Connect() (chan xmpp.Packet, error) { - t.out = make(chan xmpp.Packet) return t.out, nil } func (t *Threema) Send(packet xmpp.Packet) { switch p := packet.(type) { case xmpp.Message: - attrs := p.PacketAttrs - account := t.getAccount(attrs.From) - log.WithFields(map[string]interface{}{ - "from": attrs.From, - "to": attrs.To, - }).Debug(p.Body) - threemaID := strings.ToUpper(strings.Split(attrs.To, "@")[0]) - err := account.Send(threemaID, p.Body) - if err != nil { - msg := xmpp.NewMessage("chat", "", attrs.From, "", "en") + 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 } diff --git a/models/jid.go b/models/jid.go index b42a2aa..7ce2304 100644 --- a/models/jid.go +++ b/models/jid.go @@ -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{}) } From edb91f62542b4af2d047fdfbf9482a9886afda38 Mon Sep 17 00:00:00 2001 From: Martin/Geno Date: Fri, 31 May 2019 19:39:29 +0200 Subject: [PATCH 4/4] recieve + startup connect --- component/threema/account.go | 29 +++++++++++++++++++++++++++++ component/threema/main.go | 17 +++++++++++++---- component/xmpp.go | 6 +++--- 3 files changed, 45 insertions(+), 7 deletions(-) diff --git a/component/threema/account.go b/component/threema/account.go index c7ee62f..b3d2631 100644 --- a/component/threema/account.go +++ b/component/threema/account.go @@ -1,7 +1,11 @@ package threema import ( + "strconv" + + "github.com/bdlm/log" "github.com/o3ma/o3" + "gosrc.io/xmpp" "dev.sum7.eu/genofire/golang-lib/database" @@ -37,6 +41,7 @@ func (t *Threema) getAccount(jid *models.JID) *Account { 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() @@ -45,11 +50,35 @@ func (t *Threema) getAccount(jid *models.JID) *Account { 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) } diff --git a/component/threema/main.go b/component/threema/main.go index 7715a20..46015ba 100644 --- a/component/threema/main.go +++ b/component/threema/main.go @@ -6,6 +6,8 @@ import ( "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" ) @@ -18,16 +20,23 @@ type Threema struct { } func NewThreema(config map[string]interface{}) (component.Component, error) { - t := &Threema{ + return &Threema{ out: make(chan xmpp.Packet), accountJID: make(map[string]*Account), accountTID: make(map[string]*Account), - } - // TODO load accounts on startup - return t, nil + }, 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) { diff --git a/component/xmpp.go b/component/xmpp.go index 77fd576..0ae5ada 100644 --- a/component/xmpp.go +++ b/component/xmpp.go @@ -113,7 +113,7 @@ func (c *Config) sender() { _ = c.xmpp.Send(iq) } default: - logger.Warn("ignoring iq packet", inner) + logger.Debug("ignoring iq packet", inner) xError := xmpp.Err{ Code: 501, Reason: "feature-not-implemented", @@ -127,10 +127,10 @@ func (c *Config) sender() { c.comp.Send(packet) case xmpp.Presence: - logger.Info("Received presence:", p.Type) + logger.Debug("Received presence:", p.Type) default: - logger.Warn("ignoring packet:", packet) + logger.Debug("ignoring packet:", packet) } } }