2018-02-11 22:03:58 +01:00
|
|
|
package client
|
|
|
|
|
|
|
|
import (
|
|
|
|
"crypto/tls"
|
|
|
|
"encoding/xml"
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"net"
|
|
|
|
|
|
|
|
"dev.sum7.eu/genofire/yaja/model"
|
2018-02-14 18:49:26 +01:00
|
|
|
"dev.sum7.eu/genofire/yaja/xmpp"
|
|
|
|
"dev.sum7.eu/genofire/yaja/xmpp/base"
|
2018-02-11 22:03:58 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
func (client *Client) setConnection(conn net.Conn) {
|
|
|
|
client.conn = conn
|
|
|
|
client.in = xml.NewDecoder(client.conn)
|
|
|
|
client.out = xml.NewEncoder(client.conn)
|
|
|
|
}
|
|
|
|
|
2018-02-14 18:49:26 +01:00
|
|
|
func (client *Client) startStream() (*xmpp.StreamFeatures, error) {
|
2018-02-22 18:13:17 +01:00
|
|
|
logCTX := client.Logging.WithField("type", "stream")
|
2018-02-11 22:03:58 +01:00
|
|
|
// XMPP-Connection
|
|
|
|
_, err := fmt.Fprintf(client.conn, "<?xml version='1.0'?>\n"+
|
|
|
|
"<stream:stream to='%s' xmlns='%s'\n"+
|
|
|
|
" xmlns:stream='%s' version='1.0'>\n",
|
2018-02-14 18:49:26 +01:00
|
|
|
model.XMLEscape(client.JID.Domain), xmpp.NSClient, xmpp.NSStream)
|
2018-02-11 22:03:58 +01:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
element, err := client.Read()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2018-02-14 18:49:26 +01:00
|
|
|
if element.Name.Space != xmpp.NSStream || element.Name.Local != "stream" {
|
2018-02-11 22:03:58 +01:00
|
|
|
return nil, errors.New("is not stream")
|
|
|
|
}
|
2018-02-14 18:49:26 +01:00
|
|
|
f := &xmpp.StreamFeatures{}
|
2018-02-11 22:03:58 +01:00
|
|
|
if err := client.ReadDecode(f); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2018-02-22 18:13:17 +01:00
|
|
|
debug := "start >"
|
2018-02-11 22:03:58 +01:00
|
|
|
if f.StartTLS != nil {
|
|
|
|
debug += " tls"
|
|
|
|
}
|
|
|
|
debug += " mechanism("
|
2018-02-11 22:43:42 +01:00
|
|
|
mFirst := true
|
2018-02-11 22:03:58 +01:00
|
|
|
for _, m := range f.Mechanisms.Mechanism {
|
2018-02-11 22:43:42 +01:00
|
|
|
if mFirst {
|
|
|
|
mFirst = false
|
|
|
|
debug += m
|
|
|
|
} else {
|
|
|
|
debug += ", " + m
|
|
|
|
}
|
2018-02-11 22:03:58 +01:00
|
|
|
}
|
|
|
|
debug += ")"
|
|
|
|
if f.Bind != nil {
|
|
|
|
debug += " bind"
|
|
|
|
}
|
2018-02-22 18:13:17 +01:00
|
|
|
logCTX.Info(debug)
|
2018-02-11 22:03:58 +01:00
|
|
|
return f, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (client *Client) connect(password string) error {
|
|
|
|
if _, err := client.startStream(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2018-02-14 18:49:26 +01:00
|
|
|
if err := client.Send(&xmpp.TLSStartTLS{}); err != nil {
|
2018-02-11 22:03:58 +01:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2018-02-14 18:49:26 +01:00
|
|
|
var p xmpp.TLSProceed
|
2018-02-11 22:03:58 +01:00
|
|
|
if err := client.ReadDecode(&p); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
// Change tcp to tls
|
|
|
|
tlsconn := tls.Client(client.conn, &tls.Config{
|
|
|
|
ServerName: client.JID.Domain,
|
|
|
|
})
|
|
|
|
client.setConnection(tlsconn)
|
|
|
|
|
|
|
|
if err := tlsconn.Handshake(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err := tlsconn.VerifyHostname(client.JID.Domain); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err := client.auth(password); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2018-02-11 22:43:42 +01:00
|
|
|
f, err := client.startStream()
|
|
|
|
if err != nil {
|
2018-02-11 22:03:58 +01:00
|
|
|
return err
|
|
|
|
}
|
2018-02-11 22:43:42 +01:00
|
|
|
bind := f.Bind
|
|
|
|
if f.Bind == nil || (f.Bind.JID == nil && f.Bind.Resource == "") {
|
|
|
|
// bind to resource
|
|
|
|
if client.JID.Resource != "" {
|
|
|
|
bind.Resource = client.JID.Resource
|
|
|
|
}
|
2018-02-14 18:49:26 +01:00
|
|
|
if err := client.Send(&xmpp.IQClient{
|
|
|
|
Type: xmpp.IQTypeSet,
|
|
|
|
To: xmppbase.NewJID(client.JID.Domain),
|
2018-02-11 22:43:42 +01:00
|
|
|
Bind: bind,
|
|
|
|
}); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2018-02-11 22:03:58 +01:00
|
|
|
|
2018-02-14 18:49:26 +01:00
|
|
|
var iq xmpp.IQClient
|
2018-02-11 22:43:42 +01:00
|
|
|
if err := client.ReadDecode(&iq); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if iq.Error != nil {
|
2018-02-14 18:49:26 +01:00
|
|
|
return errors.New(fmt.Sprintf("recv error on iq>bind: %s[%s]: %s -> %s -> %s", iq.Error.Code, iq.Error.Type, iq.Error.Text, xmpp.XMLChildrenString(iq.Error.StanzaErrorGroup), xmpp.XMLChildrenString(iq.Error.Other)))
|
2018-02-11 22:43:42 +01:00
|
|
|
} else if iq.Bind == nil {
|
2018-02-14 18:49:26 +01:00
|
|
|
return errors.New("iq>bind is nil :" + xmpp.XMLChildrenString(iq.Other))
|
2018-02-11 22:03:58 +01:00
|
|
|
}
|
2018-02-11 22:43:42 +01:00
|
|
|
bind = iq.Bind
|
|
|
|
}
|
|
|
|
if bind == nil {
|
|
|
|
return errors.New("bind is nil")
|
|
|
|
} else if bind.JID != nil {
|
2018-02-15 22:03:49 +01:00
|
|
|
client.JID.Local = bind.JID.Local
|
2018-02-11 22:43:42 +01:00
|
|
|
client.JID.Domain = bind.JID.Domain
|
|
|
|
client.JID.Resource = bind.JID.Resource
|
2018-02-22 18:13:17 +01:00
|
|
|
client.Logging.WithField("type", "bind").Infof("set jid by server bind '%s'", bind.JID.Full())
|
2018-02-11 22:43:42 +01:00
|
|
|
} else if bind.Resource != "" {
|
|
|
|
client.JID.Resource = bind.Resource
|
2018-02-22 18:13:17 +01:00
|
|
|
client.Logging.WithField("type", "bind").Infof("set resource by server bind '%s'", bind.Resource)
|
2018-02-11 22:03:58 +01:00
|
|
|
} else {
|
2018-02-14 18:49:26 +01:00
|
|
|
return errors.New("bind>jid is nil" + xmpp.XMLChildrenString(bind))
|
2018-02-11 22:03:58 +01:00
|
|
|
}
|
|
|
|
// set status
|
2018-02-14 18:49:26 +01:00
|
|
|
return client.Send(&xmpp.PresenceClient{Show: xmpp.PresenceShowXA, Status: "online"})
|
2018-02-11 22:03:58 +01:00
|
|
|
}
|