mirror of
https://github.com/FluuxIO/go-xmpp.git
synced 2026-05-24 04:43:47 -07:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b04299b40c |
@@ -13,6 +13,32 @@ The goal is to make simple to write simple XMPP clients and components:
|
|||||||
|
|
||||||
The library is designed to have minimal dependencies. For now, the library does not depend on any other library.
|
The library is designed to have minimal dependencies. For now, the library does not depend on any other library.
|
||||||
|
|
||||||
|
## Configuration and connection
|
||||||
|
|
||||||
|
### Allowing Insecure TLS connection during development
|
||||||
|
|
||||||
|
It is not recommended to disable the check for domain name and certificate chain. Doing so would open your client
|
||||||
|
to man-in-the-middle attacks.
|
||||||
|
|
||||||
|
However, in development, XMPP servers often use self-signed certificates. In that situation, it is better to add the
|
||||||
|
root CA that signed the certificate to your trusted list of root CA. It avoids changing the code and limit the risk
|
||||||
|
of shipping an insecure client to production.
|
||||||
|
|
||||||
|
That said, if you really want to allow your client to trust any TLS certificate, you can customize Go standard
|
||||||
|
`tls.Config` and set it in Config struct.
|
||||||
|
|
||||||
|
Here is an example code to configure a client to allow connecting to a server with self-signed certificate. Note the
|
||||||
|
`InsecureSkipVerify` option. When using this `tls.Config` option, all the checks on the certificate are skipped.
|
||||||
|
|
||||||
|
```go
|
||||||
|
config := xmpp.Config{
|
||||||
|
Address: "localhost:5222",
|
||||||
|
Jid: "test@localhost",
|
||||||
|
Password: "test",
|
||||||
|
TLSConfig: tls.Config{InsecureSkipVerify: true},
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Supported specifications
|
## Supported specifications
|
||||||
|
|
||||||
### Clients
|
### Clients
|
||||||
|
|||||||
@@ -99,9 +99,26 @@ func discoInfo(c xmpp.Sender, p stanza.Packet, opts xmpp.ComponentOptions) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func discoInfoRoot(iqResp *stanza.IQ, opts xmpp.ComponentOptions) {
|
func discoInfoRoot(iqResp *stanza.IQ, opts xmpp.ComponentOptions) {
|
||||||
disco := iqResp.DiscoInfo()
|
// Higher level discovery
|
||||||
disco.AddIdentity(opts.Name, opts.Category, opts.Type)
|
identity := stanza.Identity{
|
||||||
disco.AddFeatures(stanza.NSDiscoInfo, stanza.NSDiscoItems, "jabber:iq:version", "urn:xmpp:delegation:1")
|
Name: opts.Name,
|
||||||
|
Category: opts.Category,
|
||||||
|
Type: opts.Type,
|
||||||
|
}
|
||||||
|
payload := stanza.DiscoInfo{
|
||||||
|
XMLName: xml.Name{
|
||||||
|
Space: stanza.NSDiscoInfo,
|
||||||
|
Local: "query",
|
||||||
|
},
|
||||||
|
Identity: []stanza.Identity{identity},
|
||||||
|
Features: []stanza.Feature{
|
||||||
|
{Var: stanza.NSDiscoInfo},
|
||||||
|
{Var: stanza.NSDiscoItems},
|
||||||
|
{Var: "jabber:iq:version"},
|
||||||
|
{Var: "urn:xmpp:delegation:1"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
iqResp.Payload = &payload
|
||||||
}
|
}
|
||||||
|
|
||||||
func discoInfoPubSub(iqResp *stanza.IQ) {
|
func discoInfoPubSub(iqResp *stanza.IQ) {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/xml"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
@@ -60,9 +61,25 @@ func discoInfo(c xmpp.Sender, p stanza.Packet, opts xmpp.ComponentOptions) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
iqResp := stanza.NewIQ(stanza.Attrs{Type: "result", From: iq.To, To: iq.From, Id: iq.Id, Lang: "en"})
|
iqResp := stanza.NewIQ(stanza.Attrs{Type: "result", From: iq.To, To: iq.From, Id: iq.Id, Lang: "en"})
|
||||||
disco := iqResp.DiscoInfo()
|
identity := stanza.Identity{
|
||||||
disco.AddIdentity(opts.Name, opts.Category, opts.Type)
|
Name: opts.Name,
|
||||||
disco.AddFeatures(stanza.NSDiscoInfo, stanza.NSDiscoItems, "jabber:iq:version", "urn:xmpp:delegation:1")
|
Category: opts.Category,
|
||||||
|
Type: opts.Type,
|
||||||
|
}
|
||||||
|
payload := stanza.DiscoInfo{
|
||||||
|
XMLName: xml.Name{
|
||||||
|
Space: stanza.NSDiscoInfo,
|
||||||
|
Local: "query",
|
||||||
|
},
|
||||||
|
Identity: []stanza.Identity{identity},
|
||||||
|
Features: []stanza.Feature{
|
||||||
|
{Var: stanza.NSDiscoInfo},
|
||||||
|
{Var: stanza.NSDiscoItems},
|
||||||
|
{Var: "jabber:iq:version"},
|
||||||
|
{Var: "urn:xmpp:delegation:1"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
iqResp.Payload = &payload
|
||||||
_ = c.Send(iqResp)
|
_ = c.Send(iqResp)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,11 +97,16 @@ func discoItems(c xmpp.Sender, p stanza.Packet) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
iqResp := stanza.NewIQ(stanza.Attrs{Type: "result", From: iq.To, To: iq.From, Id: iq.Id, Lang: "en"})
|
iqResp := stanza.NewIQ(stanza.Attrs{Type: "result", From: iq.To, To: iq.From, Id: iq.Id, Lang: "en"})
|
||||||
items := iqResp.DiscoItems()
|
|
||||||
|
|
||||||
|
var payload stanza.DiscoItems
|
||||||
if discoItems.Node == "" {
|
if discoItems.Node == "" {
|
||||||
items.AddItem("service.localhost", "node1", "test node")
|
payload = stanza.DiscoItems{
|
||||||
|
Items: []stanza.DiscoItem{
|
||||||
|
{Name: "test node", JID: "service.localhost", Node: "node1"},
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
iqResp.Payload = &payload
|
||||||
_ = c.Send(iqResp)
|
_ = c.Send(iqResp)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,6 +118,9 @@ func handleVersion(c xmpp.Sender, p stanza.Packet) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
iqResp := stanza.NewIQ(stanza.Attrs{Type: "result", From: iq.To, To: iq.From, Id: iq.Id, Lang: "en"})
|
iqResp := stanza.NewIQ(stanza.Attrs{Type: "result", From: iq.To, To: iq.From, Id: iq.Id, Lang: "en"})
|
||||||
iqResp.Version().SetInfo("Fluux XMPP Component", "0.0.1", "")
|
var payload stanza.Version
|
||||||
|
payload.Name = "Fluux XMPP Component"
|
||||||
|
payload.Version = "0.0.1"
|
||||||
|
iq.Payload = &payload
|
||||||
_ = c.Send(iqResp)
|
_ = c.Send(iqResp)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ func main() {
|
|||||||
Password: "test",
|
Password: "test",
|
||||||
StreamLogger: os.Stdout,
|
StreamLogger: os.Stdout,
|
||||||
Insecure: true,
|
Insecure: true,
|
||||||
|
// TLSConfig: tls.Config{InsecureSkipVerify: true},
|
||||||
}
|
}
|
||||||
|
|
||||||
router := xmpp.NewRouter()
|
router := xmpp.NewRouter()
|
||||||
|
|||||||
+3
-2
@@ -86,8 +86,9 @@ func (c *ServerCheck) Check() error {
|
|||||||
return fmt.Errorf("expecting starttls proceed: %s", err)
|
return fmt.Errorf("expecting starttls proceed: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
stanza.DefaultTlsConfig.ServerName = c.domain
|
var tlsConfig tls.Config
|
||||||
tlsConn := tls.Client(tcpconn, &stanza.DefaultTlsConfig)
|
tlsConfig.ServerName = c.domain
|
||||||
|
tlsConn := tls.Client(tcpconn, &tlsConfig)
|
||||||
// We convert existing connection to TLS
|
// We convert existing connection to TLS
|
||||||
if err = tlsConn.Handshake(); err != nil {
|
if err = tlsConn.Handshake(); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package xmpp
|
package xmpp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/tls"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
@@ -13,6 +14,7 @@ type Config struct {
|
|||||||
StreamLogger *os.File // Used for debugging
|
StreamLogger *os.File // Used for debugging
|
||||||
Lang string // TODO: should default to 'en'
|
Lang string // TODO: should default to 'en'
|
||||||
ConnectTimeout int // Client timeout in seconds. Default to 15
|
ConnectTimeout int // Client timeout in seconds. Default to 15
|
||||||
|
TLSConfig tls.Config
|
||||||
// Insecure can be set to true to allow to open a session without TLS. If TLS
|
// Insecure can be set to true to allow to open a session without TLS. If TLS
|
||||||
// is supported on the server, we will still try to use it.
|
// is supported on the server, we will still try to use it.
|
||||||
Insecure bool
|
Insecure bool
|
||||||
|
|||||||
+23
-12
@@ -35,13 +35,15 @@ func NewSession(conn net.Conn, o Config) (net.Conn, *Session, error) {
|
|||||||
|
|
||||||
// starttls
|
// starttls
|
||||||
var tlsConn net.Conn
|
var tlsConn net.Conn
|
||||||
tlsConn = s.startTlsIfSupported(conn, o.parsedJid.Domain)
|
tlsConn = s.startTlsIfSupported(conn, o.parsedJid.Domain, o)
|
||||||
if s.TlsEnabled {
|
|
||||||
s.reset(conn, tlsConn, o)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !s.TlsEnabled && !o.Insecure {
|
if !s.TlsEnabled && !o.Insecure {
|
||||||
return nil, nil, NewConnError(errors.New("failed to negotiate TLS session"), true)
|
err := fmt.Errorf("failed to negotiate TLS session : %s", s.err)
|
||||||
|
return nil, nil, NewConnError(err, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.TlsEnabled {
|
||||||
|
s.reset(conn, tlsConn, o)
|
||||||
}
|
}
|
||||||
|
|
||||||
// auth
|
// auth
|
||||||
@@ -101,7 +103,7 @@ func (s *Session) open(domain string) (f stanza.StreamFeatures) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Session) startTlsIfSupported(conn net.Conn, domain string) net.Conn {
|
func (s *Session) startTlsIfSupported(conn net.Conn, domain string, o Config) net.Conn {
|
||||||
if s.err != nil {
|
if s.err != nil {
|
||||||
return conn
|
return conn
|
||||||
}
|
}
|
||||||
@@ -114,21 +116,30 @@ func (s *Session) startTlsIfSupported(conn net.Conn, domain string) net.Conn {
|
|||||||
s.err = errors.New("expecting starttls proceed: " + s.err.Error())
|
s.err = errors.New("expecting starttls proceed: " + s.err.Error())
|
||||||
return conn
|
return conn
|
||||||
}
|
}
|
||||||
s.TlsEnabled = true
|
|
||||||
|
|
||||||
// TODO: add option to accept all TLS certificates: insecureSkipTlsVerify (DefaultTlsConfig.InsecureSkipVerify)
|
o.TLSConfig.ServerName = domain
|
||||||
stanza.DefaultTlsConfig.ServerName = domain
|
tlsConn := tls.Client(conn, &o.TLSConfig)
|
||||||
tlsConn := tls.Client(conn, &stanza.DefaultTlsConfig)
|
|
||||||
// We convert existing connection to TLS
|
// We convert existing connection to TLS
|
||||||
if s.err = tlsConn.Handshake(); s.err != nil {
|
if s.err = tlsConn.Handshake(); s.err != nil {
|
||||||
return tlsConn
|
return tlsConn
|
||||||
}
|
}
|
||||||
|
|
||||||
// We check that cert matches hostname
|
if !o.TLSConfig.InsecureSkipVerify {
|
||||||
s.err = tlsConn.VerifyHostname(domain)
|
// We check that cert matches hostname
|
||||||
|
s.err = tlsConn.VerifyHostname(domain)
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.err == nil {
|
||||||
|
s.TlsEnabled = true
|
||||||
|
}
|
||||||
return tlsConn
|
return tlsConn
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we do not allow cleartext connections, make it explicit that server do not support starttls
|
||||||
|
if !o.Insecure {
|
||||||
|
s.err = errors.New("XMPP server does not advertise support for starttls")
|
||||||
|
}
|
||||||
|
|
||||||
// starttls is not supported => we do not upgrade the connection:
|
// starttls is not supported => we do not upgrade the connection:
|
||||||
return conn
|
return conn
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-31
@@ -56,9 +56,8 @@ func (d *DiscoInfo) AddFeatures(namespace ...string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DiscoInfo) SetNode(node string) *DiscoInfo {
|
func (d *DiscoInfo) SetNode(node string) {
|
||||||
d.Node = node
|
d.Node = node
|
||||||
return d
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DiscoInfo) SetIdentities(ident ...Identity) *DiscoInfo {
|
func (d *DiscoInfo) SetIdentities(ident ...Identity) *DiscoInfo {
|
||||||
@@ -67,7 +66,6 @@ func (d *DiscoInfo) SetIdentities(ident ...Identity) *DiscoInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *DiscoInfo) SetFeatures(namespace ...string) *DiscoInfo {
|
func (d *DiscoInfo) SetFeatures(namespace ...string) *DiscoInfo {
|
||||||
d.Features = []Feature{}
|
|
||||||
for _, ns := range namespace {
|
for _, ns := range namespace {
|
||||||
d.Features = append(d.Features, Feature{Var: ns})
|
d.Features = append(d.Features, Feature{Var: ns})
|
||||||
}
|
}
|
||||||
@@ -106,38 +104,11 @@ func (d *DiscoItems) Namespace() string {
|
|||||||
return d.XMLName.Space
|
return d.XMLName.Space
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------
|
|
||||||
// Builder helpers
|
|
||||||
|
|
||||||
// DiscoItems builds a default DiscoItems payload
|
|
||||||
func (iq *IQ) DiscoItems() *DiscoItems {
|
|
||||||
d := DiscoItems{
|
|
||||||
XMLName: xml.Name{Space: "http://jabber.org/protocol/disco#items", Local: "query"},
|
|
||||||
}
|
|
||||||
iq.Payload = &d
|
|
||||||
return &d
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DiscoItems) SetNode(node string) *DiscoItems {
|
|
||||||
d.Node = node
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DiscoItems) AddItem(jid, node, name string) *DiscoItems {
|
|
||||||
item := DiscoItem{
|
|
||||||
JID: jid,
|
|
||||||
Node: node,
|
|
||||||
Name: name,
|
|
||||||
}
|
|
||||||
d.Items = append(d.Items, item)
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
type DiscoItem struct {
|
type DiscoItem struct {
|
||||||
XMLName xml.Name `xml:"item"`
|
XMLName xml.Name `xml:"item"`
|
||||||
|
Name string `xml:"name,attr,omitempty"`
|
||||||
JID string `xml:"jid,attr,omitempty"`
|
JID string `xml:"jid,attr,omitempty"`
|
||||||
Node string `xml:"node,attr,omitempty"`
|
Node string `xml:"node,attr,omitempty"`
|
||||||
Name string `xml:"name,attr,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|||||||
+11
-46
@@ -7,22 +7,29 @@ import (
|
|||||||
"gosrc.io/xmpp/stanza"
|
"gosrc.io/xmpp/stanza"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Test DiscoInfo Builder with several features
|
func TestDiscoInfoBuilder(t *testing.T) {
|
||||||
func TestDiscoInfo_Builder(t *testing.T) {
|
|
||||||
iq := stanza.NewIQ(stanza.Attrs{Type: "get", To: "service.localhost", Id: "disco-get-1"})
|
iq := stanza.NewIQ(stanza.Attrs{Type: "get", To: "service.localhost", Id: "disco-get-1"})
|
||||||
disco := iq.DiscoInfo()
|
disco := iq.DiscoInfo()
|
||||||
disco.AddIdentity("Test Component", "gateway", "service")
|
disco.AddIdentity("Test Component", "gateway", "service")
|
||||||
disco.AddFeatures(stanza.NSDiscoInfo, stanza.NSDiscoItems, "jabber:iq:version", "urn:xmpp:delegation:1")
|
disco.AddFeatures(stanza.NSDiscoInfo, stanza.NSDiscoItems, "jabber:iq:version", "urn:xmpp:delegation:1")
|
||||||
|
|
||||||
parsedIQ, err := checkMarshalling(t, iq)
|
// Marshall
|
||||||
|
data, err := xml.Marshal(iq)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
t.Errorf("cannot marshal xml structure: %s", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unmarshall
|
||||||
|
var parsedIQ stanza.IQ
|
||||||
|
if err = xml.Unmarshal(data, &parsedIQ); err != nil {
|
||||||
|
t.Errorf("Unmarshal(%s) returned error: %s", data, err)
|
||||||
|
}
|
||||||
|
|
||||||
// Check result
|
// Check result
|
||||||
pp, ok := parsedIQ.Payload.(*stanza.DiscoInfo)
|
pp, ok := parsedIQ.Payload.(*stanza.DiscoInfo)
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Errorf("Parsed stanza does not contain correct IQ payload")
|
t.Errorf("Parsed stanza does not contain an IQ payload")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check features
|
// Check features
|
||||||
@@ -46,45 +53,3 @@ func TestDiscoInfo_Builder(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implements XEP-0030 example 17
|
|
||||||
// https://xmpp.org/extensions/xep-0030.html#example-17
|
|
||||||
func TestDiscoItems_Builder(t *testing.T) {
|
|
||||||
iq := stanza.NewIQ(stanza.Attrs{Type: "result", From: "catalog.shakespeare.lit",
|
|
||||||
To: "romeo@montague.net/orchard", Id: "items-2"})
|
|
||||||
iq.DiscoItems().
|
|
||||||
AddItem("catalog.shakespeare.lit", "books", "Books by and about Shakespeare").
|
|
||||||
AddItem("catalog.shakespeare.lit", "clothing", "Wear your literary taste with pride").
|
|
||||||
AddItem("catalog.shakespeare.lit", "music", "Music from the time of Shakespeare")
|
|
||||||
|
|
||||||
parsedIQ, err := checkMarshalling(t, iq)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check result
|
|
||||||
pp, ok := parsedIQ.Payload.(*stanza.DiscoItems)
|
|
||||||
if !ok {
|
|
||||||
t.Errorf("Parsed stanza does not contain correct IQ payload")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check items
|
|
||||||
items := []stanza.DiscoItem{{xml.Name{}, "catalog.shakespeare.lit", "books", "Books by and about Shakespeare"},
|
|
||||||
{xml.Name{}, "catalog.shakespeare.lit", "clothing", "Wear your literary taste with pride"},
|
|
||||||
{xml.Name{}, "catalog.shakespeare.lit", "music", "Music from the time of Shakespeare"}}
|
|
||||||
if len(pp.Items) != len(items) {
|
|
||||||
t.Errorf("Items length mismatch: %#v", pp.Items)
|
|
||||||
} else {
|
|
||||||
for i, item := range pp.Items {
|
|
||||||
if item.JID != items[i].JID {
|
|
||||||
t.Errorf("JID Mismatch (expected: %s): %s", items[i].JID, item.JID)
|
|
||||||
}
|
|
||||||
if item.Node != items[i].Node {
|
|
||||||
t.Errorf("Node Mismatch (expected: %s): %s", items[i].JID, item.JID)
|
|
||||||
}
|
|
||||||
if item.Name != items[i].Name {
|
|
||||||
t.Errorf("Name Mismatch (expected: %s): %s", items[i].JID, item.JID)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -17,26 +17,6 @@ func (v *Version) Namespace() string {
|
|||||||
return v.XMLName.Space
|
return v.XMLName.Space
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------
|
|
||||||
// Builder helpers
|
|
||||||
|
|
||||||
// Version builds a default software version payload
|
|
||||||
func (iq *IQ) Version() *Version {
|
|
||||||
d := Version{
|
|
||||||
XMLName: xml.Name{Space: "jabber:iq:version", Local: "query"},
|
|
||||||
}
|
|
||||||
iq.Payload = &d
|
|
||||||
return &d
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set all software version info
|
|
||||||
func (v *Version) SetInfo(name, version, os string) *Version {
|
|
||||||
v.Name = name
|
|
||||||
v.Version = version
|
|
||||||
v.OS = os
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Registry init
|
// Registry init
|
||||||
|
|
||||||
|
|||||||
@@ -1,40 +0,0 @@
|
|||||||
package stanza_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"gosrc.io/xmpp/stanza"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Build a Software Version reply
|
|
||||||
// https://xmpp.org/extensions/xep-0092.html#example-2
|
|
||||||
func TestVersion_Builder(t *testing.T) {
|
|
||||||
name := "Exodus"
|
|
||||||
version := "0.7.0.4"
|
|
||||||
os := "Windows-XP 5.01.2600"
|
|
||||||
iq := stanza.NewIQ(stanza.Attrs{Type: "result", From: "romeo@montague.net/orchard",
|
|
||||||
To: "juliet@capulet.com/balcony", Id: "version_1"})
|
|
||||||
iq.Version().SetInfo(name, version, os)
|
|
||||||
|
|
||||||
parsedIQ, err := checkMarshalling(t, iq)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check result
|
|
||||||
pp, ok := parsedIQ.Payload.(*stanza.Version)
|
|
||||||
if !ok {
|
|
||||||
t.Errorf("Parsed stanza does not contain correct IQ payload")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check version info
|
|
||||||
if pp.Name != name {
|
|
||||||
t.Errorf("Name Mismatch (expected: %s): %s", name, pp.Name)
|
|
||||||
}
|
|
||||||
if pp.Version != version {
|
|
||||||
t.Errorf("Version Mismatch (expected: %s): %s", version, pp.Version)
|
|
||||||
}
|
|
||||||
if pp.OS != os {
|
|
||||||
t.Errorf("OS Mismatch (expected: %s): %s", os, pp.OS)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +1,9 @@
|
|||||||
package stanza
|
package stanza
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/tls"
|
|
||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
)
|
)
|
||||||
|
|
||||||
var DefaultTlsConfig tls.Config
|
|
||||||
|
|
||||||
// Used during stream initiation / session establishment
|
// Used during stream initiation / session establishment
|
||||||
type TLSProceed struct {
|
type TLSProceed struct {
|
||||||
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-tls proceed"`
|
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-tls proceed"`
|
||||||
|
|||||||
@@ -2,35 +2,10 @@ package stanza_test
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/google/go-cmp/cmp"
|
"github.com/google/go-cmp/cmp"
|
||||||
"gosrc.io/xmpp/stanza"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// Marshaller / unmarshaller test
|
|
||||||
|
|
||||||
func checkMarshalling(t *testing.T, iq stanza.IQ) (*stanza.IQ, error) {
|
|
||||||
// Marshall
|
|
||||||
data, err := xml.Marshal(iq)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("cannot marshal iq: %s\n%#v", err, iq)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unmarshall
|
|
||||||
var parsedIQ stanza.IQ
|
|
||||||
err = xml.Unmarshal(data, &parsedIQ)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Unmarshal returned error: %s\n%s", err, data)
|
|
||||||
}
|
|
||||||
return &parsedIQ, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// XML structs comparison
|
|
||||||
|
|
||||||
// Compare iq structure but ignore empty namespace as they are set properly on
|
// Compare iq structure but ignore empty namespace as they are set properly on
|
||||||
// marshal / unmarshal. There is no need to manage them on the manually
|
// marshal / unmarshal. There is no need to manage them on the manually
|
||||||
// crafted structure.
|
// crafted structure.
|
||||||
|
|||||||
+1
-1
@@ -119,7 +119,7 @@ func (sm *StreamManager) connect() error {
|
|||||||
var actualErr ConnError
|
var actualErr ConnError
|
||||||
if xerrors.As(err, &actualErr) {
|
if xerrors.As(err, &actualErr) {
|
||||||
if actualErr.Permanent {
|
if actualErr.Permanent {
|
||||||
return xerrors.Errorf("unrecoverable connect error %w", actualErr)
|
return xerrors.Errorf("unrecoverable connect error %#v", actualErr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
backoff.wait()
|
backoff.wait()
|
||||||
|
|||||||
Reference in New Issue
Block a user