some work towards proper SASL support

lumi created

Change summary

src/client.rs | 10 ++++----
src/lib.rs    |  1 
src/sasl.rs   | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 66 insertions(+), 5 deletions(-)

Detailed changes

src/client.rs 🔗

@@ -5,6 +5,8 @@ use ns;
 use plugin::{Plugin, PluginProxyBinding};
 use event::AbstractEvent;
 use connection::{Connection, C2S};
+use sasl::SaslMechanism;
+use sasl::mechanisms::Plain as SaslPlain;
 
 use base64;
 
@@ -148,11 +150,9 @@ impl Client {
                     self.transport.write_element(&elem)?;
                 }
                 else {
-                    let mut auth = Vec::new();
-                    auth.push(0);
-                    auth.extend(self.jid.node.as_ref().expect("JID has no node").bytes());
-                    auth.push(0);
-                    auth.extend(password.bytes());
+                    let name = self.jid.node.clone().expect("JID has no node");
+                    let mut plain = SaslPlain::new(name, password.to_owned());
+                    let auth = plain.initial();
                     let elem = Element::builder("auth")
                                        .text(base64::encode(&auth))
                                        .ns(ns::SASL)

src/lib.rs 🔗

@@ -12,5 +12,6 @@ pub mod plugin;
 pub mod event;
 pub mod plugins;
 pub mod connection;
+pub mod sasl;
 
 mod locked_io;

src/sasl.rs 🔗

@@ -0,0 +1,60 @@
+//! Provides the `SaslMechanism` trait and some implementations.
+
+pub trait SaslMechanism {
+    /// The name of the mechanism.
+    fn name() -> &'static str;
+
+    /// Provides initial payload of the SASL mechanism.
+    fn initial(&mut self) -> Vec<u8> {
+        Vec::new()
+    }
+
+    /// Creates a response to the SASL challenge.
+    fn respond(&mut self, _challenge: &[u8]) -> Vec<u8> {
+        Vec::new()
+    }
+}
+
+/// A few SASL mechanisms.
+pub mod mechanisms {
+    use super::SaslMechanism;
+
+    pub struct Anonymous;
+
+    impl Anonymous {
+        pub fn new() -> Anonymous {
+            Anonymous
+        }
+    }
+
+    impl SaslMechanism for Anonymous {
+        fn name() -> &'static str { "ANONYMOUS" }
+    }
+
+    pub struct Plain {
+        name: String,
+        password: String,
+    }
+
+    impl Plain {
+        pub fn new<N: Into<String>, P: Into<String>>(name: N, password: P) -> Plain {
+            Plain {
+                name: name.into(),
+                password: password.into(),
+            }
+        }
+    }
+
+    impl SaslMechanism for Plain {
+        fn name() -> &'static str { "PLAIN" }
+
+        fn initial(&mut self) -> Vec<u8> {
+            let mut auth = Vec::new();
+            auth.push(0);
+            auth.extend(self.name.bytes());
+            auth.push(0);
+            auth.extend(self.password.bytes());
+            auth
+        }
+    }
+}