[TASK] add support to receive image from threema

This commit is contained in:
Martin/Geno 2019-06-02 21:39:21 +02:00
parent 211e0abed0
commit b9bf07389c
No known key found for this signature in database
GPG Key ID: 9D7D3C6BFF600C6A
9 changed files with 194 additions and 36 deletions

View File

@ -12,6 +12,7 @@ import (
type Account struct { type Account struct {
models.AccountThreema models.AccountThreema
threema *Threema
Session o3.SessionContext Session o3.SessionContext
send chan<- o3.Message send chan<- o3.Message
receive <-chan o3.ReceivedMsg receive <-chan o3.ReceivedMsg
@ -43,8 +44,11 @@ func (t *Threema) getAccount(jid *models.JID) (*Account, error) {
} }
tid.Nick = o3.NewPubNick("xmpp:" + jid.String()) tid.Nick = o3.NewPubNick("xmpp:" + jid.String())
a := &Account{AccountThreema: account} a := &Account{
a.Session = o3.NewSessionContext(tid) AccountThreema: account,
Session: o3.NewSessionContext(tid),
threema: t,
}
a.send, a.receive, err = a.Session.Run() a.send, a.receive, err = a.Session.Run()
if err != nil { if err != nil {

29
component/threema/file.go Normal file
View File

@ -0,0 +1,29 @@
package threema
import (
"fmt"
"io/ioutil"
"strconv"
"gosrc.io/xmpp"
)
func (a *Account) FileToXMPP(from string, msgID uint64, ext string, data []byte) (xmpp.Message, error) {
msgIDStr := strconv.FormatUint(msgID, 10)
msg := xmpp.Message{
PacketAttrs: xmpp.PacketAttrs{
Id: msgIDStr,
From: from,
To: a.XMPP.String(),
},
}
url := fmt.Sprintf("%s/%d.%s", a.threema.httpUploadURL, msgID, ext)
path := fmt.Sprintf("%s/%d.%s", a.threema.httpUploadPath, msgID, ext)
if err := ioutil.WriteFile(path, data, 0644); err != nil {
msg.Body = "unable to save file on transport to forward"
return msg, err
}
msg.Body = url
msg.X = &xmpp.MsgXOOB{URL: url}
return msg, nil
}

View File

@ -0,0 +1,26 @@
package threema
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestFileToXMPP(t *testing.T) {
assert := assert.New(t)
a := createDummyAccount()
a.threema = &Threema{
httpUploadURL: "a",
httpUploadPath: "/tmp",
}
msg, err := a.FileToXMPP("", 1, "jpg", []byte("hallo"))
assert.NoError(err)
assert.Equal("a/1.jpg", msg.X.URL)
a.threema.httpUploadPath = "/gibt/es/nicht"
msg, err = a.FileToXMPP("", 1, "jpg", []byte("hallo"))
assert.Error(err)
assert.Equal("unable to save file on transport to forward", msg.Body)
}

View File

@ -1,6 +1,7 @@
package threema package threema
import ( import (
"errors"
"strings" "strings"
"github.com/bdlm/log" "github.com/bdlm/log"
@ -14,17 +15,34 @@ import (
type Threema struct { type Threema struct {
component.Component component.Component
out chan xmpp.Packet out chan xmpp.Packet
accountJID map[string]*Account accountJID map[string]*Account
bot map[string]*Bot bot map[string]*Bot
httpUploadPath string
httpUploadURL string
} }
func NewThreema(config map[string]interface{}) (component.Component, error) { func NewThreema(config map[string]interface{}) (component.Component, error) {
return &Threema{ t := &Threema{
out: make(chan xmpp.Packet), out: make(chan xmpp.Packet),
accountJID: make(map[string]*Account), accountJID: make(map[string]*Account),
bot: make(map[string]*Bot), bot: make(map[string]*Bot),
}, nil }
if pathI, ok := config["http_upload_path"]; ok {
if path, ok := pathI.(string); ok {
t.httpUploadPath = path
} else {
return nil, errors.New("wrong format of http_upload_path")
}
}
if urlI, ok := config["http_upload_url"]; ok {
if url, ok := urlI.(string); ok {
t.httpUploadURL = url
} else {
return nil, errors.New("wrong format of http_upload_url")
}
}
return t, nil
} }
func (t *Threema) Connect() (chan xmpp.Packet, error) { func (t *Threema) Connect() (chan xmpp.Packet, error) {

View File

@ -13,7 +13,25 @@ import (
func TestThreema(t *testing.T) { func TestThreema(t *testing.T) {
assert := assert.New(t) assert := assert.New(t)
c, err := NewThreema(map[string]interface{}{}) // failed
c, err := NewThreema(map[string]interface{}{
"http_upload_path": 3,
})
assert.Error(err)
assert.Nil(c)
// failed
c, err = NewThreema(map[string]interface{}{
"http_upload_url": 3,
})
assert.Error(err)
assert.Nil(c)
// ---
c, err = NewThreema(map[string]interface{}{
"http_upload_url": "",
"http_upload_path": "",
})
assert.NoError(err) assert.NoError(err)
assert.NotNil(c) assert.NotNil(c)
@ -75,6 +93,14 @@ func TestSend(t *testing.T) {
p = tr.send(xmpp.IQ{}) p = tr.send(xmpp.IQ{})
assert.Nil(p) assert.Nil(p)
// chat with bot without sender
p = tr.send(xmpp.Message{
PacketAttrs: xmpp.PacketAttrs{
To: "example.org",
},
})
assert.Nil(p)
// chat with bot // chat with bot
p = tr.send(xmpp.Message{ p = tr.send(xmpp.Message{
PacketAttrs: xmpp.PacketAttrs{ PacketAttrs: xmpp.PacketAttrs{

View File

@ -1,6 +1,8 @@
package threema package threema
import ( import (
"errors"
"fmt"
"strconv" "strconv"
"github.com/bdlm/log" "github.com/bdlm/log"
@ -10,27 +12,55 @@ import (
func (a *Account) receiver(out chan<- xmpp.Packet) { func (a *Account) receiver(out chan<- xmpp.Packet) {
for receivedMessage := range a.receive { for receivedMessage := range a.receive {
if p := a.receiving(receivedMessage); p != nil { sender := receivedMessage.Msg.Sender().String()
if string(a.TID) == sender {
continue
}
if p, err := a.receiving(receivedMessage); err != nil {
xMSG := xmpp.NewMessage("chat", sender, a.XMPP.String(), "", "en")
xMSG.Body = fmt.Sprintf("error on decoding message: %s\n%v", err, receivedMessage.Msg.Serialize())
out <- xMSG
} else if p != nil {
out <- p out <- p
} }
} }
} }
func (a *Account) receiving(receivedMessage o3.ReceivedMsg) xmpp.Packet {
func requestExtensions(xMSG *xmpp.Message) {
xMSG.Extensions = append(xMSG.Extensions, xmpp.ReceiptRequest{})
xMSG.Extensions = append(xMSG.Extensions, xmpp.ChatMarkerMarkable{})
}
func (a *Account) receiving(receivedMessage o3.ReceivedMsg) (xmpp.Packet, error) {
if receivedMessage.Err != nil { if receivedMessage.Err != nil {
log.Warnf("Error Receiving Message: %s\n", receivedMessage.Err) log.Warnf("Error Receiving Message: %s\n", receivedMessage.Err)
return nil return nil, receivedMessage.Err
} }
switch msg := receivedMessage.Msg.(type) { switch msg := receivedMessage.Msg.(type) {
case o3.TextMessage: case o3.TextMessage:
sender := msg.Sender().String() sender := msg.Sender().String()
if string(a.TID) == sender {
return nil
}
xMSG := xmpp.NewMessage("chat", sender, a.XMPP.String(), strconv.FormatUint(msg.ID(), 10), "en") xMSG := xmpp.NewMessage("chat", sender, a.XMPP.String(), strconv.FormatUint(msg.ID(), 10), "en")
xMSG.Body = msg.Text() xMSG.Body = msg.Text()
xMSG.Extensions = append(xMSG.Extensions, xmpp.ReceiptRequest{}) requestExtensions(&xMSG)
xMSG.Extensions = append(xMSG.Extensions, xmpp.ChatMarkerMarkable{}) return xMSG, nil
return xMSG
case o3.ImageMessage:
if a.threema.httpUploadPath == "" {
return nil, errors.New("no place to store files at transport configurated")
}
data, err := msg.GetImageData(a.Session)
if err != nil {
log.Warnf("unable to read data from message: %s", err)
return nil, err
}
xMSG, err := a.FileToXMPP(msg.Sender().String(), msg.ID(), "jpg", data)
if err != nil {
log.Warnf("unable to create data from message: %s", err)
return nil, err
}
xMSG.Type = "chat"
requestExtensions(&xMSG)
return xMSG, nil
case o3.DeliveryReceiptMessage: case o3.DeliveryReceiptMessage:
msgID := msg.MsgID() msgID := msg.MsgID()
@ -55,8 +85,9 @@ func (a *Account) receiving(receivedMessage o3.ReceivedMsg) xmpp.Packet {
} }
if len(xMSG.Extensions) > 0 { if len(xMSG.Extensions) > 0 {
return xMSG return xMSG, nil
} }
return nil, nil
} }
return nil return nil, errors.New("not known data format")
} }

View File

@ -34,14 +34,16 @@ func TestReceive(t *testing.T) {
a := createDummyAccount() a := createDummyAccount()
// receiving/skip error // receiving/skip error
p := a.receiving(o3.ReceivedMsg{ p, err := a.receiving(o3.ReceivedMsg{
Err: errors.New("dummy"), Err: errors.New("dummy"),
}) })
assert.Nil(p) assert.Nil(p)
assert.Error(err)
// nothing to receiving // nothing to receiving
p = a.receiving(o3.ReceivedMsg{}) p, err = a.receiving(o3.ReceivedMsg{})
assert.Nil(p) assert.Nil(p)
assert.Error(err)
} }
func TestReceiveText(t *testing.T) { func TestReceiveText(t *testing.T) {
@ -58,26 +60,40 @@ func TestReceiveText(t *testing.T) {
} }
txtMsg, err := o3.NewTextMessage(&session, threemaID, "Oojoh0Ah") txtMsg, err := o3.NewTextMessage(&session, threemaID, "Oojoh0Ah")
assert.NoError(err) assert.NoError(err)
p := a.receiving(o3.ReceivedMsg{ p, err := a.receiving(o3.ReceivedMsg{
Msg: txtMsg, Msg: txtMsg,
}) })
assert.NoError(err)
xMSG, ok := p.(xmpp.Message) xMSG, ok := p.(xmpp.Message)
assert.True(ok) assert.True(ok)
assert.Equal("Oojoh0Ah", xMSG.Body) assert.Equal("Oojoh0Ah", xMSG.Body)
}
// receiving/skip text to own id func TestReceiveImage(t *testing.T) {
session = o3.SessionContext{ assert := assert.New(t)
a := createDummyAccount()
a.threema = &Threema{}
/* receiving image
session := o3.SessionContext{
ID: o3.ThreemaID{ ID: o3.ThreemaID{
ID: threemaIDByte, ID: o3.NewIDString("12345678"),
Nick: o3.NewPubNick("user"), Nick: o3.NewPubNick("user"),
}, },
} }*/
txtMsg, err = o3.NewTextMessage(&session, threemaID, "Aesh8shu") imgMsg := o3.ImageMessage{}
assert.NoError(err) _, err := a.receiving(o3.ReceivedMsg{
p = a.receiving(o3.ReceivedMsg{ Msg: imgMsg,
Msg: txtMsg,
}) })
assert.Nil(p) assert.Error(err)
a.threema.httpUploadPath = "/tmp"
imgMsg = o3.ImageMessage{}
_, err = a.receiving(o3.ReceivedMsg{
Msg: imgMsg,
})
assert.Error(err)
} }
func TestReceiveDeliveryReceipt(t *testing.T) { func TestReceiveDeliveryReceipt(t *testing.T) {
@ -98,34 +114,38 @@ func TestReceiveDeliveryReceipt(t *testing.T) {
drm, err := o3.NewDeliveryReceiptMessage(&session, threemaID, msgID, o3.MSGDELIVERED) drm, err := o3.NewDeliveryReceiptMessage(&session, threemaID, msgID, o3.MSGDELIVERED)
assert.NoError(err) assert.NoError(err)
p := a.receiving(o3.ReceivedMsg{ p, err := a.receiving(o3.ReceivedMsg{
Msg: drm, Msg: drm,
}) })
assert.NoError(err)
xMSG, ok := p.(xmpp.Message) xMSG, ok := p.(xmpp.Message)
assert.True(ok) assert.True(ok)
rr := xMSG.Extensions[0].(xmpp.ReceiptReceived) rr := xMSG.Extensions[0].(xmpp.ReceiptReceived)
assert.Equal("im4aeseeh1IbaQui", rr.Id) assert.Equal("im4aeseeh1IbaQui", rr.Id)
// receiving delivered -> not in cache // receiving delivered -> not in cache
p = a.receiving(o3.ReceivedMsg{ p, err = a.receiving(o3.ReceivedMsg{
Msg: drm, Msg: drm,
}) })
assert.NoError(err)
assert.Nil(p) assert.Nil(p)
// receiving readed // receiving readed
drm, err = o3.NewDeliveryReceiptMessage(&session, threemaID, msgID, o3.MSGREAD) drm, err = o3.NewDeliveryReceiptMessage(&session, threemaID, msgID, o3.MSGREAD)
assert.NoError(err) assert.NoError(err)
p = a.receiving(o3.ReceivedMsg{ p, err = a.receiving(o3.ReceivedMsg{
Msg: drm, Msg: drm,
}) })
assert.NoError(err)
xMSG, ok = p.(xmpp.Message) xMSG, ok = p.(xmpp.Message)
assert.True(ok) assert.True(ok)
cmdd := xMSG.Extensions[0].(xmpp.ChatMarkerDisplayed) cmdd := xMSG.Extensions[0].(xmpp.ChatMarkerDisplayed)
assert.Equal("im4aeseeh1IbaQui", cmdd.Id) assert.Equal("im4aeseeh1IbaQui", cmdd.Id)
// receiving delivered -> not in cache // receiving delivered -> not in cache
p = a.receiving(o3.ReceivedMsg{ p, err = a.receiving(o3.ReceivedMsg{
Msg: drm, Msg: drm,
}) })
assert.NoError(err)
assert.Nil(p) assert.Nil(p)
} }

View File

@ -6,6 +6,10 @@ host = "threema.chat.sum7.eu"
connection = "localhost:5347" connection = "localhost:5347"
secret = "change_me" secret = "change_me"
[component.special]
http_upload_url = "https://example.org/upload/threema"
http_upload_path = "/var/www/http/upload/threema"
[database] [database]
type = "sqlite3" type = "sqlite3"
logging = false logging = false

2
vendor/gosrc.io/xmpp generated vendored

@ -1 +1 @@
Subproject commit 3ddad3f7a28604fa8c4fd5035d5a37aa1d676c95 Subproject commit d0b7b1f864f0fd4651f8a92b92a341314ef7aa5b