forked from jshiffer/go-xmpp
golint/gofmt the code
This commit is contained in:
parent
0a3375a6ad
commit
0655f5913b
69
xmpp.go
69
xmpp.go
@ -38,11 +38,13 @@ const (
|
|||||||
nsSASL = "urn:ietf:params:xml:ns:xmpp-sasl"
|
nsSASL = "urn:ietf:params:xml:ns:xmpp-sasl"
|
||||||
nsBind = "urn:ietf:params:xml:ns:xmpp-bind"
|
nsBind = "urn:ietf:params:xml:ns:xmpp-bind"
|
||||||
nsClient = "jabber:client"
|
nsClient = "jabber:client"
|
||||||
NsSession = "urn:ietf:params:xml:ns:xmpp-session"
|
nsSession = "urn:ietf:params:xml:ns:xmpp-session"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Default TLS configuration options
|
||||||
var DefaultConfig tls.Config
|
var DefaultConfig tls.Config
|
||||||
|
|
||||||
|
// Cookie is a unique XMPP session identifier
|
||||||
type Cookie uint64
|
type Cookie uint64
|
||||||
|
|
||||||
func getCookie() Cookie {
|
func getCookie() Cookie {
|
||||||
@ -53,6 +55,7 @@ func getCookie() Cookie {
|
|||||||
return Cookie(binary.LittleEndian.Uint64(buf[:]))
|
return Cookie(binary.LittleEndian.Uint64(buf[:]))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Client holds XMPP connection opitons
|
||||||
type Client struct {
|
type Client struct {
|
||||||
conn net.Conn // connection to server
|
conn net.Conn // connection to server
|
||||||
jid string // Jabber ID for our connection
|
jid string // Jabber ID for our connection
|
||||||
@ -211,6 +214,7 @@ func NewClient(host, user, passwd string, debug bool) (*Client, error) {
|
|||||||
return opts.NewClient()
|
return opts.NewClient()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewClientNoTLS creates a new client without TLS
|
||||||
func NewClientNoTLS(host, user, passwd string, debug bool) (*Client, error) {
|
func NewClientNoTLS(host, user, passwd string, debug bool) (*Client, error) {
|
||||||
opts := Options{
|
opts := Options{
|
||||||
Host: host,
|
Host: host,
|
||||||
@ -223,16 +227,15 @@ func NewClientNoTLS(host, user, passwd string, debug bool) (*Client, error) {
|
|||||||
return opts.NewClient()
|
return opts.NewClient()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Close closes the XMPP connection
|
||||||
func (c *Client) Close() error {
|
func (c *Client) Close() error {
|
||||||
if c.conn != (*tls.Conn)(nil) {
|
if c.conn != (*tls.Conn)(nil) {
|
||||||
return c.conn.Close()
|
return c.conn.Close()
|
||||||
} else {
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func saslDigestResponse(username, realm, passwd, nonce, cnonceStr,
|
func saslDigestResponse(username, realm, passwd, nonce, cnonceStr, authenticate, digestURI, nonceCountStr string) string {
|
||||||
authenticate, digestUri, nonceCountStr string) string {
|
|
||||||
h := func(text string) []byte {
|
h := func(text string) []byte {
|
||||||
h := md5.New()
|
h := md5.New()
|
||||||
h.Write([]byte(text))
|
h.Write([]byte(text))
|
||||||
@ -245,12 +248,9 @@ func saslDigestResponse(username, realm, passwd, nonce, cnonceStr,
|
|||||||
return h(secret + ":" + data)
|
return h(secret + ":" + data)
|
||||||
}
|
}
|
||||||
|
|
||||||
a1 := string(h(username+":"+realm+":"+passwd)) + ":" +
|
a1 := string(h(username+":"+realm+":"+passwd)) + ":" + nonce + ":" + cnonceStr
|
||||||
nonce + ":" + cnonceStr
|
a2 := authenticate + ":" + digestURI
|
||||||
a2 := authenticate + ":" + digestUri
|
response := hex(kd(hex(h(a1)), nonce+":"+nonceCountStr+":"+cnonceStr+":auth:"+hex(h(a2))))
|
||||||
response := hex(kd(hex(h(a1)), nonce+":"+
|
|
||||||
nonceCountStr+":"+cnonceStr+":auth:"+
|
|
||||||
hex(h(a2))))
|
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -265,10 +265,11 @@ func cnonce() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) init(o *Options) error {
|
func (c *Client) init(o *Options) error {
|
||||||
c.p = xml.NewDecoder(c.conn)
|
|
||||||
// For debugging: the following causes the plaintext of the connection to be duplicated to stdout.
|
|
||||||
if o.Debug {
|
if o.Debug {
|
||||||
c.p = xml.NewDecoder(tee{c.conn, os.Stdout})
|
// For debugging: the following causes the plaintext of the connection to be duplicated to stderr.
|
||||||
|
c.p = xml.NewDecoder(tee{c.conn, os.Stderr})
|
||||||
|
} else {
|
||||||
|
c.p = xml.NewDecoder(c.conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
a := strings.SplitN(o.User, "@", 2)
|
a := strings.SplitN(o.User, "@", 2)
|
||||||
@ -284,7 +285,7 @@ func (c *Client) init(o *Options) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If the server requires we STARTTLS, attempt to do so.
|
// If the server requires we STARTTLS, attempt to do so.
|
||||||
if f, err = c.startTlsIfRequired(f, o, domain); err != nil {
|
if f, err = c.startTLSIfRequired(f, o, domain); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -316,15 +317,13 @@ func (c *Client) init(o *Options) error {
|
|||||||
raw := "\x00" + user + "\x00" + o.Password
|
raw := "\x00" + user + "\x00" + o.Password
|
||||||
enc := make([]byte, base64.StdEncoding.EncodedLen(len(raw)))
|
enc := make([]byte, base64.StdEncoding.EncodedLen(len(raw)))
|
||||||
base64.StdEncoding.Encode(enc, []byte(raw))
|
base64.StdEncoding.Encode(enc, []byte(raw))
|
||||||
fmt.Fprintf(c.conn, "<auth xmlns='%s' mechanism='PLAIN'>%s</auth>\n",
|
fmt.Fprintf(c.conn, "<auth xmlns='%s' mechanism='PLAIN'>%s</auth>\n", nsSASL, enc)
|
||||||
nsSASL, enc)
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if m == "DIGEST-MD5" {
|
if m == "DIGEST-MD5" {
|
||||||
mechanism = m
|
mechanism = m
|
||||||
// Digest-MD5 authentication
|
// Digest-MD5 authentication
|
||||||
fmt.Fprintf(c.conn, "<auth xmlns='%s' mechanism='DIGEST-MD5'/>\n",
|
fmt.Fprintf(c.conn, "<auth xmlns='%s' mechanism='DIGEST-MD5'/>\n", nsSASL)
|
||||||
nsSASL)
|
|
||||||
var ch saslChallenge
|
var ch saslChallenge
|
||||||
if err = c.p.DecodeElement(&ch, nil); err != nil {
|
if err = c.p.DecodeElement(&ch, nil); err != nil {
|
||||||
return errors.New("unmarshal <challenge>: " + err.Error())
|
return errors.New("unmarshal <challenge>: " + err.Error())
|
||||||
@ -348,10 +347,11 @@ func (c *Client) init(o *Options) error {
|
|||||||
qop, _ := tokens["qop"]
|
qop, _ := tokens["qop"]
|
||||||
charset, _ := tokens["charset"]
|
charset, _ := tokens["charset"]
|
||||||
cnonceStr := cnonce()
|
cnonceStr := cnonce()
|
||||||
digestUri := "xmpp/" + domain
|
digestURI := "xmpp/" + domain
|
||||||
nonceCount := fmt.Sprintf("%08x", 1)
|
nonceCount := fmt.Sprintf("%08x", 1)
|
||||||
digest := saslDigestResponse(user, realm, o.Password, nonce, cnonceStr, "AUTHENTICATE", digestUri, nonceCount)
|
digest := saslDigestResponse(user, realm, o.Password, nonce, cnonceStr, "AUTHENTICATE", digestURI, nonceCount)
|
||||||
message := "username=\"" + user + "\", realm=\"" + realm + "\", nonce=\"" + nonce + "\", cnonce=\"" + cnonceStr + "\", nc=" + nonceCount + ", qop=" + qop + ", digest-uri=\"" + digestUri + "\", response=" + digest + ", charset=" + charset
|
message := "username=\"" + user + "\", realm=\"" + realm + "\", nonce=\"" + nonce + "\", cnonce=\"" + cnonceStr +
|
||||||
|
"\", nc=" + nonceCount + ", qop=" + qop + ", digest-uri=\"" + digestURI + "\", response=" + digest + ", charset=" + charset
|
||||||
|
|
||||||
fmt.Fprintf(c.conn, "<response xmlns='%s'>%s</response>\n", nsSASL, base64.StdEncoding.EncodeToString([]byte(message)))
|
fmt.Fprintf(c.conn, "<response xmlns='%s'>%s</response>\n", nsSASL, base64.StdEncoding.EncodeToString([]byte(message)))
|
||||||
|
|
||||||
@ -368,7 +368,7 @@ func (c *Client) init(o *Options) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if mechanism == "" {
|
if mechanism == "" {
|
||||||
return errors.New(fmt.Sprintf("PLAIN authentication is not an option: %v", f.Mechanisms.Mechanism))
|
return fmt.Errorf("PLAIN authentication is not an option: %v", f.Mechanisms.Mechanism)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Next message should be either success or failure.
|
// Next message should be either success or failure.
|
||||||
@ -392,7 +392,7 @@ func (c *Client) init(o *Options) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
//Generate uniq cookie
|
// Generate a uniqe cookie
|
||||||
cookie := getCookie()
|
cookie := getCookie()
|
||||||
|
|
||||||
// Send IQ message asking to bind to the local user name.
|
// Send IQ message asking to bind to the local user name.
|
||||||
@ -412,7 +412,7 @@ func (c *Client) init(o *Options) error {
|
|||||||
|
|
||||||
if o.Session {
|
if o.Session {
|
||||||
//if server support session, open it
|
//if server support session, open it
|
||||||
fmt.Fprintf(c.conn, "<iq to='%s' type='set' id='%x'><session xmlns='%s'/></iq>", xmlEscape(domain), cookie, NsSession)
|
fmt.Fprintf(c.conn, "<iq to='%s' type='set' id='%x'><session xmlns='%s'/></iq>", xmlEscape(domain), cookie, nsSession)
|
||||||
}
|
}
|
||||||
|
|
||||||
// We're connected and can now receive and send messages.
|
// We're connected and can now receive and send messages.
|
||||||
@ -423,7 +423,7 @@ func (c *Client) init(o *Options) error {
|
|||||||
|
|
||||||
// startTlsIfRequired examines the server's stream features and, if STARTTLS is required or supported, performs the TLS handshake.
|
// startTlsIfRequired examines the server's stream features and, if STARTTLS is required or supported, performs the TLS handshake.
|
||||||
// f will be updated if the handshake completes, as the new stream's features are typically different from the original.
|
// f will be updated if the handshake completes, as the new stream's features are typically different from the original.
|
||||||
func (c *Client) startTlsIfRequired(f *streamFeatures, o *Options, domain string) (*streamFeatures, error) {
|
func (c *Client) startTLSIfRequired(f *streamFeatures, o *Options, domain string) (*streamFeatures, error) {
|
||||||
// whether we start tls is a matter of opinion: the server's and the user's.
|
// whether we start tls is a matter of opinion: the server's and the user's.
|
||||||
switch {
|
switch {
|
||||||
case f.StartTLS == nil:
|
case f.StartTLS == nil:
|
||||||
@ -465,12 +465,13 @@ func (c *Client) startTlsIfRequired(f *streamFeatures, o *Options, domain string
|
|||||||
}
|
}
|
||||||
|
|
||||||
// startStream will start a new XML decoder for the connection, signal the start of a stream to the server and verify that the server has
|
// startStream will start a new XML decoder for the connection, signal the start of a stream to the server and verify that the server has
|
||||||
// also started the stream; if o.Debug is true, startStream will tee decoded XML data to stdout. The features advertised by the server
|
// also started the stream; if o.Debug is true, startStream will tee decoded XML data to stderr. The features advertised by the server
|
||||||
// will be returned.
|
// will be returned.
|
||||||
func (c *Client) startStream(o *Options, domain string) (*streamFeatures, error) {
|
func (c *Client) startStream(o *Options, domain string) (*streamFeatures, error) {
|
||||||
c.p = xml.NewDecoder(c.conn)
|
|
||||||
if o.Debug {
|
if o.Debug {
|
||||||
c.p = xml.NewDecoder(tee{c.conn, os.Stdout})
|
c.p = xml.NewDecoder(tee{c.conn, os.Stderr})
|
||||||
|
} else {
|
||||||
|
c.p = xml.NewDecoder(c.conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := fmt.Fprintf(c.conn, "<?xml version='1.0'?>\n"+
|
_, err := fmt.Fprintf(c.conn, "<?xml version='1.0'?>\n"+
|
||||||
@ -508,6 +509,7 @@ func (c *Client) IsEncrypted() bool {
|
|||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Chat is an incoming or outgoing XMPP chat message
|
||||||
type Chat struct {
|
type Chat struct {
|
||||||
Remote string
|
Remote string
|
||||||
Type string
|
Type string
|
||||||
@ -515,6 +517,7 @@ type Chat struct {
|
|||||||
Other []string
|
Other []string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Presence is an XMPP presence message
|
||||||
type Presence struct {
|
type Presence struct {
|
||||||
From string
|
From string
|
||||||
To string
|
To string
|
||||||
@ -546,7 +549,7 @@ func (c *Client) Send(chat Chat) (n int, err error) {
|
|||||||
xmlEscape(chat.Remote), xmlEscape(chat.Type), xmlEscape(chat.Text))
|
xmlEscape(chat.Remote), xmlEscape(chat.Type), xmlEscape(chat.Text))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send origin
|
// SendOrg sends the original text without being wrapped in an XMPP message stanza.
|
||||||
func (c *Client) SendOrg(org string) (n int, err error) {
|
func (c *Client) SendOrg(org string) (n int, err error) {
|
||||||
return fmt.Fprint(c.conn, org)
|
return fmt.Fprint(c.conn, org)
|
||||||
}
|
}
|
||||||
@ -625,7 +628,7 @@ type bindBind struct {
|
|||||||
type clientMessage struct {
|
type clientMessage struct {
|
||||||
XMLName xml.Name `xml:"jabber:client message"`
|
XMLName xml.Name `xml:"jabber:client message"`
|
||||||
From string `xml:"from,attr"`
|
From string `xml:"from,attr"`
|
||||||
Id string `xml:"id,attr"`
|
ID string `xml:"id,attr"`
|
||||||
To string `xml:"to,attr"`
|
To string `xml:"to,attr"`
|
||||||
Type string `xml:"type,attr"` // chat, error, groupchat, headline, or normal
|
Type string `xml:"type,attr"` // chat, error, groupchat, headline, or normal
|
||||||
|
|
||||||
@ -647,7 +650,7 @@ type clientText struct {
|
|||||||
type clientPresence struct {
|
type clientPresence struct {
|
||||||
XMLName xml.Name `xml:"jabber:client presence"`
|
XMLName xml.Name `xml:"jabber:client presence"`
|
||||||
From string `xml:"from,attr"`
|
From string `xml:"from,attr"`
|
||||||
Id string `xml:"id,attr"`
|
ID string `xml:"id,attr"`
|
||||||
To string `xml:"to,attr"`
|
To string `xml:"to,attr"`
|
||||||
Type string `xml:"type,attr"` // error, probe, subscribe, subscribed, unavailable, unsubscribe, unsubscribed
|
Type string `xml:"type,attr"` // error, probe, subscribe, subscribed, unavailable, unsubscribe, unsubscribed
|
||||||
Lang string `xml:"lang,attr"`
|
Lang string `xml:"lang,attr"`
|
||||||
@ -661,7 +664,7 @@ type clientPresence struct {
|
|||||||
type clientIQ struct { // info/query
|
type clientIQ struct { // info/query
|
||||||
XMLName xml.Name `xml:"jabber:client iq"`
|
XMLName xml.Name `xml:"jabber:client iq"`
|
||||||
From string `xml:",attr"`
|
From string `xml:",attr"`
|
||||||
Id string `xml:",attr"`
|
ID string `xml:",attr"`
|
||||||
To string `xml:",attr"`
|
To string `xml:",attr"`
|
||||||
Type string `xml:",attr"` // error, get, result, set
|
Type string `xml:",attr"` // error, get, result, set
|
||||||
Error clientError
|
Error clientError
|
||||||
|
Loading…
Reference in New Issue
Block a user