From a18807f19e98c1f2cafddc28ab3f838b44b68fa1 Mon Sep 17 00:00:00 2001 From: Wim Date: Sun, 29 Mar 2020 17:35:40 +0200 Subject: [PATCH] Update matterbridge/go-xmpp to add xmpp avatar support (#1070) --- go.mod | 2 +- go.sum | 4 +- .../github.com/matterbridge/go-xmpp/xmpp.go | 54 +++++++- .../matterbridge/go-xmpp/xmpp_avatar.go | 125 ++++++++++++++++++ vendor/modules.txt | 2 +- 5 files changed, 178 insertions(+), 9 deletions(-) create mode 100644 vendor/github.com/matterbridge/go-xmpp/xmpp_avatar.go diff --git a/go.mod b/go.mod index 3da58716..184514b3 100644 --- a/go.mod +++ b/go.mod @@ -24,7 +24,7 @@ require ( github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20190210153444-cc9d05784d5d github.com/matterbridge/discordgo v0.18.1-0.20200308151012-aa40f01cbcc3 github.com/matterbridge/emoji v2.1.1-0.20191117213217-af507f6b02db+incompatible - github.com/matterbridge/go-xmpp v0.0.0-20200328215643-8d36ff2c85d1 + github.com/matterbridge/go-xmpp v0.0.0-20200329150250-5812999b292b github.com/matterbridge/gomatrix v0.0.0-20200209224845-c2104d7936a6 github.com/matterbridge/gozulipbot v0.0.0-20190212232658-7aa251978a18 github.com/matterbridge/logrus-prefixed-formatter v0.0.0-20180806162718-01618749af61 diff --git a/go.sum b/go.sum index e3e07622..3d16f1fc 100644 --- a/go.sum +++ b/go.sum @@ -130,8 +130,8 @@ github.com/matterbridge/discordgo v0.18.1-0.20200308151012-aa40f01cbcc3 h1:VP/DN github.com/matterbridge/discordgo v0.18.1-0.20200308151012-aa40f01cbcc3/go.mod h1:5a1bHtG/38ofcx9cgwM5eTW/Pl4SpbQksNDnTRcGA2Y= github.com/matterbridge/emoji v2.1.1-0.20191117213217-af507f6b02db+incompatible h1:oaOqwbg5HxHRxvAbd84ks0Okwoc1ISyUZ87EiVJFhGI= github.com/matterbridge/emoji v2.1.1-0.20191117213217-af507f6b02db+incompatible/go.mod h1:igE6rUAn3jai2wCdsjFHfhUoekjrFthoEjFObKKwSb4= -github.com/matterbridge/go-xmpp v0.0.0-20200328215643-8d36ff2c85d1 h1:1GBtdv3HbYTPbGP3y/QpJ7S4ogB5gs/+gGKhj4ri2CM= -github.com/matterbridge/go-xmpp v0.0.0-20200328215643-8d36ff2c85d1/go.mod h1:ECDRehsR9TYTKCAsRS8/wLeOk6UUqDydw47ln7wG41Q= +github.com/matterbridge/go-xmpp v0.0.0-20200329150250-5812999b292b h1:ZYI2HCj9zPzI4Si1ouSOi/ImA2xSQLUCJPQsLWr8FE0= +github.com/matterbridge/go-xmpp v0.0.0-20200329150250-5812999b292b/go.mod h1:ECDRehsR9TYTKCAsRS8/wLeOk6UUqDydw47ln7wG41Q= github.com/matterbridge/gomatrix v0.0.0-20200209224845-c2104d7936a6 h1:Kl65VJv38HjYFnnwH+MP6Z8hcJT5UHuSpHVU5vW1HH0= github.com/matterbridge/gomatrix v0.0.0-20200209224845-c2104d7936a6/go.mod h1:+jWeaaUtXQbBRdKYWfjW6JDDYiI2XXE+3NnTjW5kg8g= github.com/matterbridge/gozulipbot v0.0.0-20190212232658-7aa251978a18 h1:fLhwXtWGtfTgZVxHG1lcKjv+re7dRwyyuYFNu69xdho= diff --git a/vendor/github.com/matterbridge/go-xmpp/xmpp.go b/vendor/github.com/matterbridge/go-xmpp/xmpp.go index cc13218e..bb1438e9 100644 --- a/vendor/github.com/matterbridge/go-xmpp/xmpp.go +++ b/vendor/github.com/matterbridge/go-xmpp/xmpp.go @@ -644,7 +644,20 @@ func (c *Client) Recv() (stanza interface{}, err error) { case *clientMessage: if v.Event.XMLNS == XMPPNS_PUBSUB_EVENT { // Handle Pubsub notifications - return pubsubClientToReturn(v.Event), nil + switch v.Event.Items.Node { + case XMPPNS_AVATAR_PEP_METADATA: + return handleAvatarMetadata(v.Event.Items.Items[0].Body, + v.From) + // I am not sure whether this can even happen. + // XEP-0084 only specifies a subscription to + // the metadata node. + /*case XMPPNS_AVATAR_PEP_DATA: + return handleAvatarData(v.Event.Items.Items[0].Body, + v.From, + v.Event.Items.Items[0].ID)*/ + default: + return pubsubClientToReturn(v.Event), nil + } } stamp, _ := time.Parse( @@ -745,10 +758,41 @@ func (c *Client) Recv() (stanza interface{}, err error) { return PubsubItems{}, err } - return PubsubItems{ - p.Node, - pubsubItemsToReturn(p.Items), - }, nil + switch p.Node { + case XMPPNS_AVATAR_PEP_DATA: + return handleAvatarData(p.Items[0].Body, + v.From, + p.Items[0].ID) + case XMPPNS_AVATAR_PEP_METADATA: + return handleAvatarMetadata(p.Items[0].Body, + v.From) + default: + return PubsubItems{ + p.Node, + pubsubItemsToReturn(p.Items), + }, nil + } + // Note: XEP-0084 states that metadata and data + // should be fetched with an id of retrieve1. + // Since we already have PubSub implemented, we + // can just use items1 and items3 to do the same + // as an Avatar node is just a PEP (PubSub) node. + /*case "retrieve1": + var p clientPubsubItems + err := xml.Unmarshal([]byte(v.Query.InnerXML), &p) + if err != nil { + return PubsubItems{}, err + } + + switch p.Node { + case XMPPNS_AVATAR_PEP_DATA: + return handleAvatarData(p.Items[0].Body, + v.From, + p.Items[0].ID) + case XMPPNS_AVATAR_PEP_METADATA: + return handleAvatarMetadata(p.Items[0].Body, + v + }*/ } case v.Query.XMLName.Local == "": return IQ{ID: v.ID, From: v.From, To: v.To, Type: v.Type}, nil diff --git a/vendor/github.com/matterbridge/go-xmpp/xmpp_avatar.go b/vendor/github.com/matterbridge/go-xmpp/xmpp_avatar.go new file mode 100644 index 00000000..7303dba5 --- /dev/null +++ b/vendor/github.com/matterbridge/go-xmpp/xmpp_avatar.go @@ -0,0 +1,125 @@ +package xmpp + +import ( + "crypto/sha1" + "encoding/base64" + "encoding/hex" + "encoding/xml" + "errors" + "strconv" +) + +const ( + XMPPNS_AVATAR_PEP_DATA = "urn:xmpp:avatar:data" + XMPPNS_AVATAR_PEP_METADATA = "urn:xmpp:avatar:metadata" +) + +type clientAvatarData struct { + XMLName xml.Name `xml:"data"` + Data []byte `xml:",innerxml"` +} + +type clientAvatarInfo struct { + XMLName xml.Name `xml:"info"` + Bytes string `xml:"bytes,attr"` + Width string `xml:"width,attr"` + Height string `xml:"height,attr"` + ID string `xml:"id,attr"` + Type string `xml:"type,attr"` + URL string `xml:"url,attr"` +} + +type clientAvatarMetadata struct { + XMLName xml.Name `xml:"metadata"` + XMLNS string `xml:"xmlns,attr"` + Info clientAvatarInfo `xml:"info"` +} + +type AvatarData struct { + Data []byte + From string +} + +type AvatarMetadata struct { + From string + Bytes int + Width int + Height int + ID string + Type string + URL string +} + +func handleAvatarData(itemsBody []byte, from, id string) (AvatarData, error) { + var data clientAvatarData + err := xml.Unmarshal(itemsBody, &data) + if err != nil { + return AvatarData{}, err + } + + // Base64-decode the avatar data to check its SHA1 hash + dataRaw, err := base64.StdEncoding.DecodeString( + string(data.Data)) + if err != nil { + return AvatarData{}, err + } + + hash := sha1.Sum(dataRaw) + hashStr := hex.EncodeToString(hash[:]) + if hashStr != id { + return AvatarData{}, errors.New("SHA1 hashes do not match") + } + + return AvatarData{ + Data: dataRaw, + From: from, + }, nil +} + +func handleAvatarMetadata(body []byte, from string) (AvatarMetadata, error) { + var meta clientAvatarMetadata + err := xml.Unmarshal(body, &meta) + if err != nil { + return AvatarMetadata{}, err + } + + return AvatarMetadata{ + From: from, + Bytes: atoiw(meta.Info.Bytes), + Width: atoiw(meta.Info.Width), + Height: atoiw(meta.Info.Height), + ID: meta.Info.ID, + Type: meta.Info.Type, + URL: meta.Info.URL, + }, nil +} + +// A wrapper for atoi which just returns -1 if an error occurs +func atoiw(str string) int { + i, err := strconv.Atoi(str) + if err != nil { + return -1 + } + + return i +} + +func (c *Client) AvatarSubscribeMetadata(jid string) { + c.PubsubSubscribeNode(XMPPNS_AVATAR_PEP_METADATA, jid) +} + +func (c *Client) AvatarUnsubscribeMetadata(jid string) { + c.PubsubUnsubscribeNode(XMPPNS_AVATAR_PEP_METADATA, jid) +} + +func (c *Client) AvatarRequestData(jid string) { + c.PubsubRequestLastItems(XMPPNS_AVATAR_PEP_DATA, jid) +} + +func (c *Client) AvatarRequestDataByID(jid, id string) { + c.PubsubRequestItem(XMPPNS_AVATAR_PEP_DATA, jid, id) +} + +func (c *Client) AvatarRequestMetadata(jid string) { + c.PubsubRequestLastItems(XMPPNS_AVATAR_PEP_METADATA, jid) +} diff --git a/vendor/modules.txt b/vendor/modules.txt index b63c1861..54b6eab9 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -103,7 +103,7 @@ github.com/matterbridge/Rocket.Chat.Go.SDK/rest github.com/matterbridge/discordgo # github.com/matterbridge/emoji v2.1.1-0.20191117213217-af507f6b02db+incompatible github.com/matterbridge/emoji -# github.com/matterbridge/go-xmpp v0.0.0-20200328215643-8d36ff2c85d1 +# github.com/matterbridge/go-xmpp v0.0.0-20200329150250-5812999b292b github.com/matterbridge/go-xmpp # github.com/matterbridge/gomatrix v0.0.0-20200209224845-c2104d7936a6 github.com/matterbridge/gomatrix