diff options
| author | 2023-07-11 21:28:42 +0100 | |
|---|---|---|
| committer | 2023-07-11 21:28:42 +0100 | |
| commit | f43911ccbae3856b35b0d3e8ec6ac6450e295da6 (patch) | |
| tree | 492b195cc06b08e546c059c16a748f369995eab1 | |
| parent | 143a0365d0822e6786cdac3530a725bbf450f38f (diff) | |
| download | luz-f43911ccbae3856b35b0d3e8ec6ac6450e295da6.tar.gz luz-f43911ccbae3856b35b0d3e8ec6ac6450e295da6.tar.bz2 luz-f43911ccbae3856b35b0d3e8ec6ac6450e295da6.zip | |
remove serde functions
Diffstat (limited to '')
| -rw-r--r-- | Cargo.toml | 1 | ||||
| -rw-r--r-- | notes.md | 5 | ||||
| -rw-r--r-- | src/client/encrypted.rs | 216 | ||||
| -rw-r--r-- | src/client/mod.rs | 17 | ||||
| -rw-r--r-- | src/client/unencrypted.rs | 76 | ||||
| -rw-r--r-- | src/element.rs | 108 | ||||
| -rw-r--r-- | src/error.rs | 31 | ||||
| -rw-r--r-- | src/jabber.rs | 16 | ||||
| -rw-r--r-- | src/jid/mod.rs | 2 | ||||
| -rw-r--r-- | src/lib.rs | 1 | ||||
| -rw-r--r-- | src/stanza/mod.rs | 4 | ||||
| -rw-r--r-- | src/stanza/sasl.rs | 24 | ||||
| -rw-r--r-- | src/stanza/stream.rs | 197 | 
13 files changed, 389 insertions, 309 deletions
| @@ -7,6 +7,7 @@ edition = "2021"  # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html  [dependencies] +async-recursion = "1.0.4"  async-trait = "0.1.68"  quick-xml = { git = "https://github.com/tafia/quick-xml.git", features = ["async-tokio", "serialize"] }  # TODO: remove unneeded features diff --git a/notes.md b/notes.md new file mode 100644 index 0000000..7d76da1 --- /dev/null +++ b/notes.md @@ -0,0 +1,5 @@ +tag = <tag> or </tag> +element = <sajdlfkajsdf/> or <slakdfj></slakdfj> +stanza = specific element <message/> <presence/> <iq/> + + diff --git a/src/client/encrypted.rs b/src/client/encrypted.rs index a4bf0d1..76f600c 100644 --- a/src/client/encrypted.rs +++ b/src/client/encrypted.rs @@ -1,35 +1,26 @@ -use std::str; -  use quick_xml::{ -    de::Deserializer, -    events::{BytesDecl, BytesStart, Event}, -    name::QName, -    se::Serializer, +    events::{BytesDecl, Event},      Reader, Writer,  }; -use rsasl::prelude::{Mechname, SASLClient}; -use serde::{Deserialize, Serialize}; -use tokio::io::{AsyncWriteExt, BufReader, ReadHalf, WriteHalf}; +use tokio::io::{BufReader, ReadHalf, WriteHalf};  use tokio::net::TcpStream;  use tokio_native_tls::TlsStream; -use crate::stanza::{ -    sasl::{Auth, Challenge, Mechanisms}, -    stream::{StreamFeature, StreamFeatures}, -}; +use crate::element::Element; +use crate::stanza::stream::{Stream, StreamFeature};  use crate::Jabber;  use crate::Result;  pub struct JabberClient<'j> {      reader: Reader<BufReader<ReadHalf<TlsStream<TcpStream>>>>, -    writer: WriteHalf<TlsStream<TcpStream>>, +    writer: Writer<WriteHalf<TlsStream<TcpStream>>>,      jabber: &'j mut Jabber<'j>,  }  impl<'j> JabberClient<'j> {      pub fn new(          reader: Reader<BufReader<ReadHalf<TlsStream<TcpStream>>>>, -        writer: WriteHalf<TlsStream<TcpStream>>, +        writer: Writer<WriteHalf<TlsStream<TcpStream>>>,          jabber: &'j mut Jabber<'j>,      ) -> Self {          Self { @@ -40,90 +31,29 @@ impl<'j> JabberClient<'j> {      }      pub async fn start_stream(&mut self) -> Result<()> { +        // client to server          let declaration = BytesDecl::new("1.0", None, None); -        let mut stream_element = BytesStart::new("stream:stream"); -        stream_element.push_attribute(("from".as_bytes(), self.jabber.jid.to_string().as_bytes())); -        stream_element.push_attribute(("to".as_bytes(), self.jabber.server.as_bytes())); -        stream_element.push_attribute(("version", "1.0")); -        stream_element.push_attribute(("xml:lang", "en")); -        stream_element.push_attribute(("xmlns", "jabber:client")); -        stream_element.push_attribute(("xmlns:stream", "http://etherx.jabber.org/streams")); -        let mut writer = Writer::new(&mut self.writer); -        writer.write_event_async(Event::Decl(declaration)).await; -        writer.write_event_async(Event::Start(stream_element)).await; +        let server = &self.jabber.server.to_owned().try_into()?; +        let stream_element = +            Stream::new_client(&self.jabber.jid, server, None, Some("en".to_string())); +        self.writer +            .write_event_async(Event::Decl(declaration)) +            .await; +        let stream_element: Element<'_> = stream_element.into(); +        stream_element.write_start(&mut self.writer).await?; +        // server to client          let mut buf = Vec::new(); -        loop { -            match self.reader.read_event_into_async(&mut buf).await.unwrap() { -                Event::Start(e) => { -                    println!("{:?}", e); -                    break; -                } -                e => println!("decl: {:?}", e), -            }; -        } +        self.reader.read_event_into_async(&mut buf).await?; +        let _stream_response = Element::read_start(&mut self.reader).await?;          Ok(())      } -    pub async fn get_node<'a>(&mut self) -> Result<String> { -        let mut buf = Vec::new(); -        let mut txt = Vec::new(); -        let mut qname_set = false; -        let mut qname: Option<Vec<u8>> = None; -        loop { -            match self.reader.read_event_into_async(&mut buf).await? { -                Event::Start(e) => { -                    if !qname_set { -                        qname = Some(e.name().into_inner().to_owned()); -                        qname_set = true; -                    } -                    txt.push(b'<'); -                    txt = txt -                        .into_iter() -                        .chain(buf.to_owned()) -                        .chain(vec![b'>']) -                        .collect(); -                } -                Event::End(e) => { -                    let mut end = false; -                    if e.name() == QName(qname.as_deref().unwrap()) { -                        end = true; -                    } -                    txt.push(b'<'); -                    txt = txt -                        .into_iter() -                        .chain(buf.to_owned()) -                        .chain(vec![b'>']) -                        .collect(); -                    if end { -                        break; -                    } -                } -                Event::Text(_e) => { -                    txt = txt.into_iter().chain(buf.to_owned()).collect(); -                } -                _ => { -                    txt.push(b'<'); -                    txt = txt -                        .into_iter() -                        .chain(buf.to_owned()) -                        .chain(vec![b'>']) -                        .collect(); -                } -            } -            buf.clear(); +    pub async fn get_features(&mut self) -> Result<Option<Vec<StreamFeature>>> { +        if let Some(features) = Element::read(&mut self.reader).await? { +            Ok(Some(features.try_into()?)) +        } else { +            Ok(None)          } -        println!("{:?}", txt); -        let decoded = str::from_utf8(&txt)?.to_owned(); -        println!("{:?}", decoded); -        Ok(decoded) -    } - -    pub async fn get_features(&mut self) -> Result<Vec<StreamFeature>> { -        let node = self.get_node().await?; -        let mut deserializer = Deserializer::from_str(&node); -        let features = StreamFeatures::deserialize(&mut deserializer).unwrap(); -        println!("{:?}", features); -        Ok(features.features)      }      pub async fn negotiate(&mut self) -> Result<()> { @@ -131,98 +61,14 @@ impl<'j> JabberClient<'j> {              println!("loop");              let features = &self.get_features().await?;              println!("{:?}", features); -            match &features[0] { -                StreamFeature::Sasl(sasl) => { -                    println!("{:?}", sasl); -                    self.sasl(&sasl).await?; -                } -                StreamFeature::Bind => todo!(), -                x => println!("{:?}", x), -            } +            // match &features[0] { +            //     StreamFeature::Sasl(sasl) => { +            //         println!("{:?}", sasl); +            //         todo!() +            //     } +            //     StreamFeature::Bind => todo!(), +            //     x => println!("{:?}", x), +            // }          }      } - -    pub async fn sasl(&mut self, mechanisms: &Mechanisms) -> Result<()> { -        println!("{:?}", mechanisms); -        let sasl = SASLClient::new(self.jabber.auth.clone()); -        let mut offered_mechs: Vec<&Mechname> = Vec::new(); -        for mechanism in &mechanisms.mechanisms { -            offered_mechs.push(Mechname::parse(&mechanism.mechanism.as_bytes())?) -        } -        println!("{:?}", offered_mechs); -        let mut session = sasl.start_suggested(&offered_mechs)?; -        let selected_mechanism = session.get_mechname().as_str().to_owned(); -        println!("selected mech: {:?}", selected_mechanism); -        let mut data: Option<Vec<u8>> = None; -        if !session.are_we_first() { -            // if not first mention the mechanism then get challenge data -            // mention mechanism -            let auth = Auth { -                ns: "urn:ietf:params:xml:ns:xmpp-sasl".to_owned(), -                mechanism: selected_mechanism.clone(), -                sasl_data: Some("=".to_owned()), -            }; -            let mut buffer = String::new(); -            let ser = Serializer::new(&mut buffer); -            auth.serialize(ser).unwrap(); -            self.writer.write_all(buffer.as_bytes()); -            // get challenge data -            let node = self.get_node().await?; -            let mut deserializer = Deserializer::from_str(&node); -            let challenge = Challenge::deserialize(&mut deserializer).unwrap(); -            println!("challenge: {:?}", challenge); -            data = Some(challenge.sasl_data.as_bytes().to_owned()); -            println!("we didn't go first"); -        } else { -            // if first, mention mechanism and send data -            let mut sasl_data = Vec::new(); -            session.step64(None, &mut sasl_data).unwrap(); -            let auth = Auth { -                ns: "urn:ietf:params:xml:ns:xmpp-sasl".to_owned(), -                mechanism: selected_mechanism.clone(), -                sasl_data: Some(str::from_utf8(&sasl_data).unwrap().to_owned()), -            }; -            let mut buffer = String::new(); -            let ser = Serializer::new(&mut buffer); -            auth.serialize(ser).unwrap(); -            println!("node: {:?}", buffer); -            self.writer.write_all(buffer.as_bytes()).await; -            println!("we went first"); -            // get challenge data -            // TODO: check if needed -            // let node = self.get_node().await?; -            // println!("node: {:?}", node); -            // let mut deserializer = Deserializer::from_str(&node); -            // let challenge = Challenge::deserialize(&mut deserializer).unwrap(); -            // println!("challenge: {:?}", challenge); -            // data = Some(challenge.sasl_data.as_bytes().to_owned()); -        } - -        // stepping the authentication exchange to completion -        let mut sasl_data = Vec::new(); -        while { -            // decide if need to send more data over -            let state = session -                .step64(data.as_deref(), &mut sasl_data) -                .expect("step errored!"); -            state.is_running() -        } { -            // While we aren't finished, receive more data from the other party -            let auth = Auth { -                ns: "urn:ietf:params:xml:ns:xmpp-sasl".to_owned(), -                mechanism: selected_mechanism.clone(), -                sasl_data: Some(str::from_utf8(&sasl_data).unwrap().to_owned()), -            }; -            let mut buffer = String::new(); -            let ser = Serializer::new(&mut buffer); -            auth.serialize(ser).unwrap(); -            self.writer.write_all(buffer.as_bytes()); -            let node = self.get_node().await?; -            let mut deserializer = Deserializer::from_str(&node); -            let challenge = Challenge::deserialize(&mut deserializer).unwrap(); -            data = Some(challenge.sasl_data.as_bytes().to_owned()); -        } -        self.start_stream().await?; -        Ok(()) -    }  } diff --git a/src/client/mod.rs b/src/client/mod.rs index fe3dd34..d545923 100644 --- a/src/client/mod.rs +++ b/src/client/mod.rs @@ -15,17 +15,16 @@ pub enum JabberClientType<'j> {  impl<'j> JabberClientType<'j> {      pub async fn ensure_tls(self) -> Result<encrypted::JabberClient<'j>> {          match self { -            Self::Encrypted(mut c) => { -                c.start_stream(); -                Ok(c) -            } +            Self::Encrypted(c) => Ok(c),              Self::Unencrypted(mut c) => { -                c.start_stream().await?; -                let features = c.get_features().await?; -                if features.contains(&StreamFeature::StartTls) { -                    Ok(c.starttls().await?) +                if let Some(features) = c.get_features().await? { +                    if features.contains(&StreamFeature::StartTls) { +                        Ok(c.starttls().await?) +                    } else { +                        Err(JabberError::StartTlsUnavailable) +                    }                  } else { -                    Err(JabberError::StartTlsUnavailable) +                    Err(JabberError::NoFeatures)                  }              }          } diff --git a/src/client/unencrypted.rs b/src/client/unencrypted.rs index d4225d3..ce534c7 100644 --- a/src/client/unencrypted.rs +++ b/src/client/unencrypted.rs @@ -1,19 +1,19 @@  use std::str;  use quick_xml::{ -    de::Deserializer,      events::{BytesDecl, BytesStart, Event},      name::QName,      Reader, Writer,  }; -use serde::Deserialize;  use tokio::io::{BufReader, ReadHalf, WriteHalf};  use tokio::net::TcpStream;  use tokio_native_tls::native_tls::TlsConnector; +use crate::element::Element; +use crate::stanza::stream::StreamFeature; +use crate::Jabber;  use crate::Result; -use crate::{error::JabberError, stanza::stream::StreamFeature}; -use crate::{stanza::stream::StreamFeatures, Jabber}; +use crate::{error::JabberError, stanza::stream::Stream};  pub struct JabberClient<'j> {      reader: Reader<BufReader<ReadHalf<TcpStream>>>, @@ -35,63 +35,30 @@ impl<'j> JabberClient<'j> {      }      pub async fn start_stream(&mut self) -> Result<()> { +        // client to server          let declaration = BytesDecl::new("1.0", None, None); -        let mut stream_element = BytesStart::new("stream:stream"); -        stream_element.push_attribute(("from".as_bytes(), self.jabber.jid.to_string().as_bytes())); -        stream_element.push_attribute(("to".as_bytes(), self.jabber.server.as_bytes())); -        stream_element.push_attribute(("version", "1.0")); -        stream_element.push_attribute(("xml:lang", "en")); -        stream_element.push_attribute(("xmlns", "jabber:client")); -        stream_element.push_attribute(("xmlns:stream", "http://etherx.jabber.org/streams")); +        let server = &self.jabber.server.to_owned().try_into()?; +        let stream_element = +            Stream::new_client(&self.jabber.jid, server, None, Some("en".to_string()));          self.writer              .write_event_async(Event::Decl(declaration)) -            .await; -        self.writer -            .write_event_async(Event::Start(stream_element)) -            .await -            .unwrap(); +            .await?; +        let stream_element: Element<'_> = stream_element.into(); +        stream_element.write_start(&mut self.writer).await?; +        // server to client          let mut buf = Vec::new(); -        loop { -            match self.reader.read_event_into_async(&mut buf).await.unwrap() { -                Event::Start(e) => { -                    println!("{:?}", e); -                    break; -                } -                Event::Decl(e) => println!("decl: {:?}", e), -                _ => return Err(JabberError::BadStream), -            } -        } +        self.reader.read_event_into_async(&mut buf).await?; +        let _stream_response = Element::read_start(&mut self.reader).await?;          Ok(())      } -    pub async fn get_features(&mut self) -> Result<Vec<StreamFeature>> { -        let mut buf = Vec::new(); -        let mut txt = Vec::new(); -        let mut loop_end = false; -        while !loop_end { -            match self.reader.read_event_into_async(&mut buf).await.unwrap() { -                Event::End(e) => { -                    if e.name() == QName(b"stream:features") { -                        loop_end = true; -                    } -                } -                _ => (), -            } -            txt.push(b'<'); -            txt = txt -                .into_iter() -                .chain(buf.to_owned()) -                .chain(vec![b'>']) -                .collect(); -            buf.clear(); +    pub async fn get_features(&mut self) -> Result<Option<Vec<StreamFeature>>> { +        if let Some(features) = Element::read(&mut self.reader).await? { +            println!("{:?}", features); +            Ok(Some(features.try_into()?)) +        } else { +            Ok(None)          } -        println!("{:?}", txt); -        let decoded = str::from_utf8(&txt).unwrap(); -        println!("decoded: {:?}", decoded); -        let mut deserializer = Deserializer::from_str(decoded); -        let features = StreamFeatures::deserialize(&mut deserializer).unwrap(); -        println!("{:?}", features); -        Ok(features.features)      }      pub async fn starttls(mut self) -> Result<super::encrypted::JabberClient<'j>> { @@ -115,8 +82,9 @@ impl<'j> JabberClient<'j> {                          .connect(&self.jabber.server, stream)                          .await                      { -                        let (read, writer) = tokio::io::split(tlsstream); +                        let (read, write) = tokio::io::split(tlsstream);                          let reader = Reader::from_reader(BufReader::new(read)); +                        let writer = Writer::new(write);                          let mut client =                              super::encrypted::JabberClient::new(reader, writer, self.jabber);                          client.start_stream().await?; diff --git a/src/element.rs b/src/element.rs new file mode 100644 index 0000000..21b1a3e --- /dev/null +++ b/src/element.rs @@ -0,0 +1,108 @@ +use async_recursion::async_recursion; +use quick_xml::events::Event; +use quick_xml::{Reader, Writer}; +use tokio::io::{AsyncBufRead, AsyncWrite}; + +use crate::Result; + +#[derive(Debug)] +pub struct Element<'e> { +    pub event: Event<'e>, +    pub content: Option<Vec<Element<'e>>>, +} + +// TODO: make method +#[async_recursion] +pub async fn write<'e: 'async_recursion, W: AsyncWrite + Unpin + Send>( +    element: Element<'e>, +    writer: &mut Writer<W>, +) -> Result<()> { +    match element.event { +        Event::Start(e) => { +            writer.write_event_async(Event::Start(e.clone())).await?; +            if let Some(content) = element.content { +                for e in content { +                    write(e, writer).await?; +                } +            } +            writer.write_event_async(Event::End(e.to_end())).await?; +            return Ok(()); +        } +        e => Ok(writer.write_event_async(e).await?), +    } +} + +impl<'e> Element<'e> { +    pub async fn write_start<W: AsyncWrite + Unpin + Send>( +        &self, +        writer: &mut Writer<W>, +    ) -> Result<()> { +        match self.event.as_ref() { +            Event::Start(e) => Ok(writer.write_event_async(Event::Start(e.clone())).await?), +            e => Err(ElementError::NotAStart(e.clone().into_owned()).into()), +        } +    } + +    pub async fn write_end<W: AsyncWrite + Unpin + Send>( +        &self, +        writer: &mut Writer<W>, +    ) -> Result<()> { +        match self.event.as_ref() { +            Event::Start(e) => Ok(writer +                .write_event_async(Event::End(e.clone().to_end())) +                .await?), +            e => Err(ElementError::NotAStart(e.clone().into_owned()).into()), +        } +    } + +    #[async_recursion] +    pub async fn read<R: AsyncBufRead + Unpin + Send>( +        reader: &mut Reader<R>, +    ) -> Result<Option<Self>> { +        let mut buf = Vec::new(); +        let event = reader.read_event_into_async(&mut buf).await?; +        match event { +            Event::Start(e) => { +                let mut content_vec = Vec::new(); +                while let Some(sub_element) = Element::read(reader).await? { +                    content_vec.push(sub_element) +                } +                let mut content = None; +                if !content_vec.is_empty() { +                    content = Some(content_vec) +                } +                Ok(Some(Self { +                    event: Event::Start(e.into_owned()), +                    content, +                })) +            } +            Event::End(_) => Ok(None), +            e => Ok(Some(Self { +                event: e.into_owned(), +                content: None, +            })), +        } +    } + +    #[async_recursion] +    pub async fn read_start<R: AsyncBufRead + Unpin + Send>( +        reader: &mut Reader<R>, +    ) -> Result<Self> { +        let mut buf = Vec::new(); +        let event = reader.read_event_into_async(&mut buf).await?; +        match event { +            Event::Start(e) => { +                return Ok(Self { +                    event: Event::Start(e.into_owned()), +                    content: None, +                }) +            } +            e => Err(ElementError::NotAStart(e.into_owned()).into()), +        } +    } +} + +#[derive(Debug)] +pub enum ElementError<'e> { +    NotAStart(Event<'e>), +} diff --git a/src/error.rs b/src/error.rs index 20ebc3e..37be7fa 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,7 +1,13 @@  use std::str::Utf8Error; +use quick_xml::events::attributes::AttrError;  use rsasl::mechname::MechanismNameError; +use crate::{ +    element::{self, ElementError}, +    jid::ParseError, +}; +  #[derive(Debug)]  pub enum JabberError {      Connection, @@ -9,8 +15,13 @@ pub enum JabberError {      StartTlsUnavailable,      TlsNegotiation,      Utf8Decode, +    NoFeatures, +    UnknownNamespace, +    ParseError,      XML(quick_xml::Error),      SASL(SASLError), +    Element(ElementError<'static>), +    JID(ParseError),  }  #[derive(Debug)] @@ -32,7 +43,7 @@ impl From<MechanismNameError> for JabberError {  }  impl From<Utf8Error> for JabberError { -    fn from(e: Utf8Error) -> Self { +    fn from(_e: Utf8Error) -> Self {          Self::Utf8Decode      }  } @@ -42,3 +53,21 @@ impl From<quick_xml::Error> for JabberError {          Self::XML(e)      }  } + +impl From<element::ElementError<'static>> for JabberError { +    fn from(e: element::ElementError<'static>) -> Self { +        Self::Element(e) +    } +} + +impl From<AttrError> for JabberError { +    fn from(e: AttrError) -> Self { +        Self::XML(e.into()) +    } +} + +impl From<ParseError> for JabberError { +    fn from(e: ParseError) -> Self { +        Self::JID(e) +    } +} diff --git a/src/jabber.rs b/src/jabber.rs index a1b2a2f..a48751c 100644 --- a/src/jabber.rs +++ b/src/jabber.rs @@ -117,11 +117,12 @@ impl<'j> Jabber<'j> {                          .connect(&self.server, socket)                          .await                      { -                        let (read, writer) = tokio::io::split(stream); +                        let (read, write) = tokio::io::split(stream);                          let reader = Reader::from_reader(BufReader::new(read)); -                        return Ok(JabberClientType::Encrypted( -                            client::encrypted::JabberClient::new(reader, writer, self), -                        )); +                        let writer = Writer::new(write); +                        let mut client = client::encrypted::JabberClient::new(reader, writer, self); +                        client.start_stream().await?; +                        return Ok(JabberClientType::Encrypted(client));                      }                  }                  false => { @@ -129,9 +130,10 @@ impl<'j> Jabber<'j> {                          let (read, write) = tokio::io::split(stream);                          let reader = Reader::from_reader(BufReader::new(read));                          let writer = Writer::new(write); -                        return Ok(JabberClientType::Unencrypted( -                            client::unencrypted::JabberClient::new(reader, writer, self), -                        )); +                        let mut client = +                            client::unencrypted::JabberClient::new(reader, writer, self); +                        client.start_stream().await?; +                        return Ok(JabberClientType::Unencrypted(client));                      }                  }              } diff --git a/src/jid/mod.rs b/src/jid/mod.rs index b2a03ea..e13fed7 100644 --- a/src/jid/mod.rs +++ b/src/jid/mod.rs @@ -1,6 +1,6 @@  use std::str::FromStr; -#[derive(PartialEq, Debug)] +#[derive(PartialEq, Debug, Clone)]  pub struct JID {      // TODO: validate localpart (length, char]      pub localpart: Option<String>, @@ -2,6 +2,7 @@  // TODO: logging (dropped errors)  pub mod client; +pub mod element;  pub mod error;  pub mod jabber;  pub mod jid; diff --git a/src/stanza/mod.rs b/src/stanza/mod.rs index 4eaa4c2..02ea277 100644 --- a/src/stanza/mod.rs +++ b/src/stanza/mod.rs @@ -1,2 +1,6 @@ +// use quick_xml::events::BytesDecl; +  pub mod sasl;  pub mod stream; + +// const DECLARATION: BytesDecl<'_> = BytesDecl::new("1.0", None, None); diff --git a/src/stanza/sasl.rs b/src/stanza/sasl.rs index c0e41ab..1f77ffa 100644 --- a/src/stanza/sasl.rs +++ b/src/stanza/sasl.rs @@ -1,32 +1,8 @@ -use serde::{Deserialize, Serialize}; - -#[derive(Deserialize, PartialEq, Debug)] -pub struct Mechanisms { -    #[serde(rename = "$value")] -    pub mechanisms: Vec<Mechanism>, -} - -#[derive(Deserialize, PartialEq, Debug)] -pub struct Mechanism { -    #[serde(rename = "$text")] -    pub mechanism: String, -} - -#[derive(Serialize, Debug)] -#[serde(rename = "auth")]  pub struct Auth { -    #[serde(rename = "@xmlns")] -    pub ns: String, -    #[serde(rename = "@mechanism")]      pub mechanism: String, -    #[serde(rename = "$text")]      pub sasl_data: Option<String>,  } -#[derive(Deserialize, Debug)]  pub struct Challenge { -    #[serde(rename = "@xmlns")] -    pub ns: String, -    #[serde(rename = "$text")]      pub sasl_data: String,  } diff --git a/src/stanza/stream.rs b/src/stanza/stream.rs index 4c0addd..f0fb6a1 100644 --- a/src/stanza/stream.rs +++ b/src/stanza/stream.rs @@ -1,41 +1,182 @@ -use serde::{Deserialize, Serialize}; +use std::str; -use super::sasl::Mechanisms; +use quick_xml::{ +    events::{BytesStart, Event}, +    name::QName, +}; -#[derive(Serialize, Deserialize)] -#[serde(rename = "stream:stream")] -struct Stream { -    #[serde(rename = "@from")] -    from: Option<String>, -    #[serde(rename = "@id")] +use crate::{element::Element, JabberError, Result, JID}; + +const XMLNS_STREAM: &str = "http://etherx.jabber.org/streams"; +const VERSION: &str = "1.0"; + +enum XMLNS { +    Client, +    Server, +} + +impl From<XMLNS> for &str { +    fn from(xmlns: XMLNS) -> Self { +        match xmlns { +            XMLNS::Client => return "jabber:client", +            XMLNS::Server => return "jabber:server", +        } +    } +} + +impl TryInto<XMLNS> for &str { +    type Error = JabberError; + +    fn try_into(self) -> Result<XMLNS> { +        match self { +            "jabber:client" => Ok(XMLNS::Client), +            "jabber:server" => Ok(XMLNS::Server), +            _ => Err(JabberError::UnknownNamespace), +        } +    } +} + +pub struct Stream { +    from: Option<JID>,      id: Option<String>, -    #[serde(rename = "@to")] -    to: Option<String>, -    #[serde(rename = "@version")] -    version: Option<f32>, -    #[serde(rename = "@xml:lang")] +    to: Option<JID>, +    version: Option<String>,      lang: Option<String>, -    #[serde(rename = "@xmlns")] -    namespace: Option<String>, -    #[serde(rename = "@xmlns:stream")] -    stream_namespace: Option<String>, +    _ns: XMLNS,  } -#[derive(Deserialize, Debug)] -#[serde(rename = "stream:features")] -pub struct StreamFeatures { -    #[serde(rename = "$value")] -    pub features: Vec<StreamFeature>, +impl Stream { +    pub fn new_client(from: &JID, to: &JID, id: Option<String>, lang: Option<String>) -> Self { +        Self { +            from: Some(from.clone()), +            id, +            to: Some(to.clone()), +            version: Some(VERSION.to_owned()), +            lang, +            _ns: XMLNS::Client, +        } +    } + +    fn build(&self) -> BytesStart { +        let mut start = BytesStart::new("stream:stream"); +        if let Some(from) = &self.from { +            start.push_attribute(("from", from.to_string().as_str())); +        } +        if let Some(id) = &self.id { +            start.push_attribute(("id", id.as_str())); +        } +        if let Some(to) = &self.to { +            start.push_attribute(("to", to.to_string().as_str())); +        } +        if let Some(version) = &self.version { +            start.push_attribute(("version", version.to_string().as_str())); +        } +        if let Some(lang) = &self.lang { +            start.push_attribute(("xml:lang", lang.as_str())); +        } +        start.push_attribute(("xmlns", XMLNS::Client.into())); +        start.push_attribute(("xmlns:stream", XMLNS_STREAM)); +        start +    } +} + +impl<'e> Into<Element<'e>> for Stream { +    fn into(self) -> Element<'e> { +        Element { +            event: Event::Start(self.build().to_owned()), +            content: None, +        } +    }  } -#[derive(Deserialize, PartialEq, Debug)] +impl<'e> TryFrom<Element<'e>> for Stream { +    type Error = JabberError; + +    fn try_from(value: Element<'e>) -> Result<Stream> { +        let (mut from, mut id, mut to, mut version, mut lang, mut ns) = +            (None, None, None, None, None, XMLNS::Client); +        if let Event::Start(e) = value.event.as_ref() { +            for attribute in e.attributes() { +                let attribute = attribute?; +                match attribute.key { +                    QName(b"from") => { +                        from = Some(str::from_utf8(&attribute.value)?.to_string().try_into()?); +                    } +                    QName(b"id") => { +                        id = Some(str::from_utf8(&attribute.value)?.to_owned()); +                    } +                    QName(b"to") => { +                        to = Some(str::from_utf8(&attribute.value)?.to_string().try_into()?); +                    } +                    QName(b"version") => { +                        version = Some(str::from_utf8(&attribute.value)?.to_owned()); +                    } +                    QName(b"lang") => { +                        lang = Some(str::from_utf8(&attribute.value)?.to_owned()); +                    } +                    QName(b"xmlns") => { +                        ns = str::from_utf8(&attribute.value)?.try_into()?; +                    } +                    _ => { +                        println!("unknown attribute: {:?}", attribute) +                    } +                } +            } +            Ok(Stream { +                from, +                id, +                to, +                version, +                lang, +                _ns: ns, +            }) +        } else { +            Err(JabberError::ParseError) +        } +    } +} + +#[derive(PartialEq, Debug)]  pub enum StreamFeature { -    #[serde(rename = "starttls")]      StartTls, -    // TODO: other stream features -    #[serde(rename = "mechanisms")] -    Sasl(Mechanisms), +    Sasl(Vec<String>),      Bind, -    #[serde(other)]      Unknown,  } + +impl<'e> TryFrom<Element<'e>> for Vec<StreamFeature> { +    type Error = JabberError; + +    fn try_from(features_element: Element) -> Result<Self> { +        let mut features = Vec::new(); +        if let Some(content) = features_element.content { +            for feature_element in content { +                match feature_element.event { +                    Event::Start(e) => match e.name() { +                        QName(b"starttls") => features.push(StreamFeature::StartTls), +                        QName(b"mechanisms") => { +                            let mut mechanisms = Vec::new(); +                            if let Some(content) = feature_element.content { +                                for mechanism_element in content { +                                    if let Some(content) = mechanism_element.content { +                                        for mechanism_text in content { +                                            match mechanism_text.event { +                                                Event::Text(e) => mechanisms +                                                    .push(str::from_utf8(e.as_ref())?.to_owned()), +                                                _ => {} +                                            } +                                        } +                                    } +                                } +                            } +                            features.push(StreamFeature::Sasl(mechanisms)) +                        } +                        _ => {} +                    }, +                    _ => features.push(StreamFeature::Unknown), +                } +            } +        } +        Ok(features) +    } +} | 
