summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxengineering <me@xengineering.eu>2023-06-30 13:58:53 +0200
committerxengineering <me@xengineering.eu>2023-06-30 13:58:53 +0200
commit2f1fd4d1ce2c0c2e46fcfa1ffedfd84f0d36484e (patch)
tree8f6177e668c2737705949bc2fed200eb5e19a974
parent04746f75ea935266ded4e28edb6ab25c537d50e1 (diff)
parent3dc04660a87e1b9fabeea0e55a8511d80d34a694 (diff)
downloadlimox-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.go4
-rw-r--r--xmpp/router.go10
-rw-r--r--xmpp/router_test.go13
-rw-r--r--xmpp/sasl.go40
-rw-r--r--xmpp/session.go1
-rw-r--r--xmpp/stream_pair.go26
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!")
+}