diff options
| -rw-r--r-- | xmpp/element_buffer_test.go | 4 | ||||
| -rw-r--r-- | xmpp/router.go | 10 | ||||
| -rw-r--r-- | xmpp/router_test.go | 13 | ||||
| -rw-r--r-- | xmpp/sasl.go | 40 | ||||
| -rw-r--r-- | xmpp/session.go | 1 | ||||
| -rw-r--r-- | xmpp/stream_pair.go | 26 | 
6 files changed, 72 insertions, 22 deletions
diff --git a/xmpp/element_buffer_test.go b/xmpp/element_buffer_test.go index 113a2c4..af3d5c2 100644 --- a/xmpp/element_buffer_test.go +++ b/xmpp/element_buffer_test.go @@ -11,8 +11,8 @@ import (  // which has to be exactly one XML element and an array of indentation levels  // which have to be checked after each token which is parsed.  type bufTest struct { -	xml     string -	levels  []int +	xml    string +	levels []int  }  func TestElementBuffer(t *testing.T) { diff --git a/xmpp/router.go b/xmpp/router.go index 839f870..9d69033 100644 --- a/xmpp/router.go +++ b/xmpp/router.go @@ -12,7 +12,7 @@ import (  // entry of the routingTable.  type routingTable []struct {  	name    xml.Name -	handler func([]xml.Token) +	handler func(*session, []xml.Token)  }  // getRoutingTable returns the routing table used in @@ -22,14 +22,16 @@ type routingTable []struct {  // variable would have the problem that it could be altered during execution.  func getRoutingTable() routingTable {  	return routingTable{ -		// TODO fill with entries +		{xml.Name{`http://etherx.jabber.org/streams`, `features`}, streamFeaturesHandler}, +		{xml.Name{`urn:ietf:params:xml:ns:xmpp-sasl`, `success`}, saslSuccessHandler}, +		{xml.Name{`urn:ietf:params:xml:ns:xmpp-sasl`, `failure`}, saslFailureHandler},  	}  }  // route determines the correct handler function for the given XML element by a  // given routingTable. In addition it executes the determined handler function.  // If no handler function is found an error message is send via the log module. -func route(e []xml.Token, t routingTable) { +func route(s *session, e []xml.Token, t routingTable) {  	var name xml.Name  	// TODO a stronger definition of an XML element (as here @@ -50,7 +52,7 @@ func route(e []xml.Token, t routingTable) {  	for _, r := range t {  		if name == r.name { -			r.handler(e) +			r.handler(s, e)  			return  		}  	} diff --git a/xmpp/router_test.go b/xmpp/router_test.go index ea13712..b490778 100644 --- a/xmpp/router_test.go +++ b/xmpp/router_test.go @@ -2,8 +2,8 @@ package xmpp  import (  	"encoding/xml" -	"testing"  	"strings" +	"testing"  )  // routerTest contains a single test case for the xmpp.router. The XML element @@ -11,8 +11,8 @@ import (  // test variable inside the corresponding unit test. See TestRouter for  // details.  type routerTest struct { -	xml     string -	value   int +	xml   string +	value int  }  // TestRouter tests the xmpp/router.go file. The central functionality is the @@ -23,9 +23,10 @@ type routerTest struct {  // validated.  func TestRouter(t *testing.T) {  	var testpoint int +	var s session -	factory := func(tp *int, i int) func([]xml.Token) { -		return func([]xml.Token) { +	factory := func(tp *int, i int) func(*session, []xml.Token) { +		return func(*session, []xml.Token) {  			*tp = i  		}  	} @@ -60,7 +61,7 @@ func TestRouter(t *testing.T) {  			tokens = append(tokens, xml.CopyToken(token))  		} -		route(tokens, testRouting) +		route(&s, tokens, testRouting)  		if testpoint != v.value {  			t.Fatalf("XML element was not routed correctly!\n") diff --git a/xmpp/sasl.go b/xmpp/sasl.go index 8687782..512fd58 100644 --- a/xmpp/sasl.go +++ b/xmpp/sasl.go @@ -29,8 +29,46 @@ func (s *session) sasl() {  	for _, t := range tokens {  		err := s.ed.encodeToken(t)  		if err != nil { -			log.Println("Could not encode stream end!") +			log.Println("Could not encode SASL PLAIN element!")  			return  		}  	}  } + +// hasSaslPlain scans the given stream features XML element for the SASL PLAIN +// mechanism which is supported by xengineering.eu/limox/xmpp. It returns true +// if the stream has support for this mechanism and false otherwise. +func hasSaslPlain(e []xml.Token) bool { +	mechanism := xml.Name{`urn:ietf:params:xml:ns:xmpp-sasl`, `mechanism`} + +	for i, t := range e { +		switch s := t.(type) { +		case xml.StartElement: +			if s.Name == mechanism { +				if i+1 < len(e) { +					subtype := func() string { +						switch c := e[i+1].(type) { +						case xml.CharData: +							return string(c) +						default: +							return "" +						} +					}() +					if subtype == `PLAIN` { +						return true +					} +				} +			} +		} +	} + +	return false +} + +func saslSuccessHandler(s *session, e []xml.Token) { +	runStreamPair(s) +} + +func saslFailureHandler(s *session, e []xml.Token) { +	log.Println("SASL autentication failed!") +} diff --git a/xmpp/session.go b/xmpp/session.go index f14cd34..bfa2582 100644 --- a/xmpp/session.go +++ b/xmpp/session.go @@ -19,7 +19,6 @@ type session struct {  	transport *tls.Conn  	ed        encoderDecoder  	rx        chan xml.Token -	streamEnd xml.EndElement  }  func StartSession(out chan<- any, jid string, pwd string) (in chan<- any) { diff --git a/xmpp/stream_pair.go b/xmpp/stream_pair.go index c9108d1..693972e 100644 --- a/xmpp/stream_pair.go +++ b/xmpp/stream_pair.go @@ -6,8 +6,8 @@ import (  )  func runStreamPair(s *session) { -	openStream(s) -	defer closeStream(s) +	end := openStream(s) +	defer closeStream(s, end)  	buf := newElementBuffer() @@ -28,13 +28,13 @@ func runStreamPair(s *session) {  			}  			if buf.isComplete() {  				element := buf.reset() -				route(element, getRoutingTable()) +				route(s, element, getRoutingTable())  			}  		}  	}  } -func openStream(s *session) { +func openStream(s *session) xml.EndElement {  	start := xml.StartElement{  		xml.Name{"jabber:client", "stream:stream"},  		[]xml.Attr{ @@ -45,8 +45,7 @@ func openStream(s *session) {  			xml.Attr{xml.Name{"", "xmlns:stream"}, "http://etherx.jabber.org/streams"},  		},  	} - -	s.streamEnd = start.End() +	end := start.End()  	err := s.ed.encodeToken(start)  	if err != nil { @@ -54,6 +53,8 @@ func openStream(s *session) {  	}  	syncStreams(s) + +	return end  }  // syncStreams drops XML tokens from the receiving stream until an @@ -84,9 +85,18 @@ func syncStreams(s *session) {  	}  } -func closeStream(s *session) { -	err := s.ed.encodeToken(s.streamEnd) +func closeStream(s *session, end xml.EndElement) { +	err := s.ed.encodeToken(end)  	if err != nil {  		log.Println("Could not encode stream end!")  	}  } + +func streamFeaturesHandler(s *session, e []xml.Token) { +	if hasSaslPlain(e) { +		s.sasl() +		return +	} + +	log.Println("Stream has no implemented features!") +}  | 
