Add support for delegation namespace packet parsing

Refactor and clean up pubsub & pep files
This commit is contained in:
Mickael Remond 2019-06-17 11:59:39 +02:00 committed by Mickaël Rémond
parent cc2fa7307f
commit c6f0d03f60
5 changed files with 158 additions and 66 deletions

View File

@ -216,6 +216,40 @@ func (handshakeDecoder) decode(p *xml.Decoder, se xml.StartElement) (Handshake,
return packet, err return packet, err
} }
// ============================================================================
// Component delegation
// XEP-0355
// Delegation can be used both on message (for delegated) and IQ (for Forwarded),
// depending on the context.
type Delegation struct {
MsgExtension
XMLName xml.Name `xml:"urn:xmpp:delegation:1 delegation"`
Forwarded Forwarded // This is used in iq to wrap delegated iqs
Delegated Delegated // This is used in a message to confirm delegated namespace
}
func (d *Delegation) Namespace() string {
return d.XMLName.Space
}
type Forwarded struct {
XMLName xml.Name `xml:"urn:xmpp:forward:0 forwarded"`
IQ IQ
Message Message
Presence Presence
}
type Delegated struct {
XMLName xml.Name `xml:"delegated"`
Namespace string `xml:"namespace,attr,omitempty"`
}
func init() {
TypeRegistry.MapExtension(PKTMessage, xml.Name{"urn:xmpp:delegation:1", "delegation"}, Delegation{})
TypeRegistry.MapExtension(PKTIQ, xml.Name{"urn:xmpp:delegation:1", "delegation"}, Delegation{})
}
/* /*
TODO: Add support for discovery management directly in component TODO: Add support for discovery management directly in component
TODO: Support multiple identities on disco info TODO: Support multiple identities on disco info

View File

@ -1,6 +1,9 @@
package xmpp // import "gosrc.io/xmpp" package xmpp // import "gosrc.io/xmpp"
import "testing" import (
"encoding/xml"
"testing"
)
func TestHandshake(t *testing.T) { func TestHandshake(t *testing.T) {
opts := ComponentOptions{ opts := ComponentOptions{
@ -21,3 +24,72 @@ func TestHandshake(t *testing.T) {
func TestGenerateHandshake(t *testing.T) { func TestGenerateHandshake(t *testing.T) {
// TODO // TODO
} }
// We should be able to properly parse delegation confirmation messages
func TestParsingDelegationMessage(t *testing.T) {
packetStr := `<message to='service.localhost' from='localhost'>
<delegation xmlns='urn:xmpp:delegation:1'>
<delegated namespace='http://jabber.org/protocol/pubsub'/>
</delegation>
</message>`
var msg Message
data := []byte(packetStr)
if err := xml.Unmarshal(data, &msg); err != nil {
t.Errorf("Unmarshal(%s) returned error", data)
}
// Check that we have extracted the delegation info as MsgExtension
var nsDelegated string
for _, ext := range msg.Extensions {
if delegation, ok := ext.(*Delegation); ok {
nsDelegated = delegation.Delegated.Namespace
}
}
if nsDelegated != "http://jabber.org/protocol/pubsub" {
t.Errorf("Could not find delegated namespace in delegation: %#v\n", msg)
}
}
// Check that we can parse a delegation IQ.
// The most important thing is to be able to
func TestParsingDelegationIQ(t *testing.T) {
packetStr := `<iq to='service.localhost' from='localhost' type='set' id='1'>
<delegation xmlns='urn:xmpp:delegation:1'>
<forwarded xmlns='urn:xmpp:forward:0'>
<iq xml:lang='en' to='test1@localhost' from='test1@localhost/mremond-mbp' type='set' id='aaf3a' xmlns='jabber:client'>
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
<publish node='http://jabber.org/protocol/mood'>
<item id='current'>
<mood xmlns='http://jabber.org/protocol/mood'>
<excited/>
</mood>
</item>
</publish>
</pubsub>
</iq>
</forwarded>
</delegation>
</iq>`
var iq IQ
data := []byte(packetStr)
if err := xml.Unmarshal(data, &iq); err != nil {
t.Errorf("Unmarshal(%s) returned error", data)
}
// Check that we have extracted the delegation info as IQPayload
var node string
for _, ext := range iq.Payload {
if delegation, ok := ext.(*Delegation); ok {
payload := delegation.Forwarded.IQ.Payload
if len(payload) > 0 {
payload := delegation.Forwarded.IQ.Payload[0]
if pubsub, ok := payload.(*PubSub); ok {
node = pubsub.Publish.Node
}
}
}
}
if node != "http://jabber.org/protocol/mood" {
t.Errorf("Could not find mood node name on delegated publish: %#v\n", iq)
}
}

72
pep.go
View File

@ -1,25 +1,11 @@
package xmpp // import "gosrc.io/xmpp" package xmpp // import "gosrc.io/xmpp"
// TODO: Move to a pubsub file
import ( import (
"encoding/xml" "encoding/xml"
) )
type PubSub struct {
XMLName xml.Name `xml:"http://jabber.org/protocol/pubsub pubsub"`
Publish Publish
}
type Publish struct {
XMLName xml.Name `xml:"publish"`
Node string `xml:"node,attr"`
Item Item
}
type Item struct {
XMLName xml.Name `xml:"item"`
Tune Tune
}
type Tune struct { type Tune struct {
XMLName xml.Name `xml:"http://jabber.org/protocol/tune tune"` XMLName xml.Name `xml:"http://jabber.org/protocol/tune tune"`
Artist string `xml:"artist,omitempty"` Artist string `xml:"artist,omitempty"`
@ -31,53 +17,9 @@ type Tune struct {
Uri string `xml:"uri,omitempty"` Uri string `xml:"uri,omitempty"`
} }
/* type Mood struct {
type PubsubPublish struct { XMLName xml.Name `xml:"http://jabber.org/protocol/mood mood"`
XMLName xml.Name `xml:"publish"` // TODO: Custom parsing to extract mood type from tag name
node string `xml:"node,attr"` // Mood type
item PubSubItem Text string `xml:"text,omitempty"`
} }
type PubSubItem struct {
xmlName xml.Name `xml:"item"`
}
type Thing2 struct {
XMLName xml.Name `xml:"publish"`
node string `xml:"node,attr"`
tune string `xml:"http://jabber.org/protocol/tune item>tune"`
}
type Tune struct {
artist string
length int
rating int
source string
title string
track string
uri string
}
*/
/*
func (*Tune) XMPPFormat() string {
return fmt.Sprintf(
`<iq type='set' id='%s'>
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
<publish node='http://jabber.org/protocol/tune'>
<item>
<tune xmlns='http://jabber.org/protocol/tune'>
<artist>%s</artist>
<length>%i</length>
<rating>%i</rating>
<source>%s</source>
<title>%s</title>
<track>%s</track>
<uri>%s</uri>
</tune>
</item>
</publish>
</pubsub>
</iq>`)
}
*/

39
pubsub.go Normal file
View File

@ -0,0 +1,39 @@
package xmpp // import "gosrc.io/xmpp"
import (
"encoding/xml"
)
type PubSub struct {
XMLName xml.Name `xml:"http://jabber.org/protocol/pubsub pubsub"`
Publish Publish
Retract Retract
// TODO <configure/>
}
func (p *PubSub) Namespace() string {
return p.XMLName.Space
}
type Publish struct {
XMLName xml.Name `xml:"publish"`
Node string `xml:"node,attr"`
Item Item
}
type Item struct {
XMLName xml.Name `xml:"item"`
Id string `xml:"id,attr,omitempty"`
Tune Tune
}
type Retract struct {
XMLName xml.Name `xml:"retract"`
Node string `xml:"node,attr"`
Notify string `xml:"notify,attr"`
Item Item
}
func init() {
TypeRegistry.MapExtension(PKTIQ, xml.Name{"http://jabber.org/protocol/pubsub", "pubsub"}, PubSub{})
}

View File

@ -8,6 +8,11 @@ import (
The XMPP router helps client and component developers select which XMPP they would like to process, The XMPP router helps client and component developers select which XMPP they would like to process,
and associate processing code depending on the router configuration. and associate processing code depending on the router configuration.
Here are important rules to keep in mind while setting your routes and matchers:
- Routes are evaluated in the order they are set.
- When a route matches, it is executed and all others routes are ignored. For each packet, only a single
route is executed.
TODO: Automatically reply to IQ that do not match any route, to comply to XMPP standard. TODO: Automatically reply to IQ that do not match any route, to comply to XMPP standard.
*/ */