go-xmpp/src/xmpp/component.go

88 lines
1.7 KiB
Go

package xmpp
import (
"crypto/sha1"
"encoding/xml"
"errors"
"fmt"
)
// Create a component XMPP connection.
func NewComponentXMPP(addr string, jid JID, secret string) (*XMPP, error) {
stream, err := NewStream(addr)
if err != nil {
return nil, err
}
streamId, err := startComponent(stream, jid)
if err != nil {
return nil, err
}
if err := handshake(stream, streamId, secret); err != nil {
return nil, err
}
return newXMPP(jid, stream), nil
}
func startComponent(stream *Stream, jid JID) (string, error) {
start := xml.StartElement{
xml.Name{"stream", "stream"},
[]xml.Attr{
xml.Attr{xml.Name{"", "xmlns"}, "jabber:component:accept"},
xml.Attr{xml.Name{"xmlns", "stream"}, "http://etherx.jabber.org/streams"},
xml.Attr{xml.Name{"", "to"}, jid.Full()},
},
}
if err := stream.SendStart(&start); err != nil {
return "", err
}
streamId := ""
if e, err := stream.Next(&xml.Name{nsStream, "stream"}); err != nil {
return "", err
} else {
// Find the stream id.
for _, attr := range e.Attr {
if attr.Name.Local == "id" {
streamId = attr.Value
break
}
}
if streamId == "" {
return "", errors.New("Missing stream id")
}
}
return streamId, nil
}
func handshake(stream *Stream, streamId, secret string) error {
hash := sha1.New()
hash.Write([]byte(streamId))
hash.Write([]byte(secret))
// Send handshake.
handshake := saslHandshake{Value: fmt.Sprintf("%x", hash.Sum(nil))}
if err := stream.Send(&handshake); err != nil {
return err
}
// Get handshake response.
if _, err := stream.Next(&xml.Name{"jabber:component:accept", "handshake"}); err != nil {
return err
}
return nil
}
type saslHandshake struct {
XMLName xml.Name `xml:"handshake"`
Value string `xml:",innerxml"`
}