diff options
author | xengineering <me@xengineering.eu> | 2023-06-30 13:58:53 +0200 |
---|---|---|
committer | xengineering <me@xengineering.eu> | 2023-06-30 13:58:53 +0200 |
commit | 2f1fd4d1ce2c0c2e46fcfa1ffedfd84f0d36484e (patch) | |
tree | 8f6177e668c2737705949bc2fed200eb5e19a974 | |
parent | 04746f75ea935266ded4e28edb6ab25c537d50e1 (diff) | |
parent | 3dc04660a87e1b9fabeea0e55a8511d80d34a694 (diff) | |
download | limox-2f1fd4d1ce2c0c2e46fcfa1ffedfd84f0d36484e.tar limox-2f1fd4d1ce2c0c2e46fcfa1ffedfd84f0d36484e.tar.zst limox-2f1fd4d1ce2c0c2e46fcfa1ffedfd84f0d36484e.zip |
Merge branch 'stream-features'
The added code provides a structured way to handle features offered by
the server.
-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!") +} |