diff options
author | cel 🌸 <cel@blos.sm> | 2023-10-20 04:51:56 +0100 |
---|---|---|
committer | cel 🌸 <cel@blos.sm> | 2023-10-20 04:51:56 +0100 |
commit | ba94ee66fafbabd63d6d1ed5edf435d4c46c6796 (patch) | |
tree | fe1bebc35914941b5c4fbd6f0286f4c9f8916154 /src/client | |
parent | 2536fa4937f0283b4187142cc6cede8e1dbfafa8 (diff) | |
download | luz-ba94ee66fafbabd63d6d1ed5edf435d4c46c6796.tar.gz luz-ba94ee66fafbabd63d6d1ed5edf435d4c46c6796.tar.bz2 luz-ba94ee66fafbabd63d6d1ed5edf435d4c46c6796.zip |
WIP: refactor to parse incoming stream as state machine
Diffstat (limited to 'src/client')
-rw-r--r-- | src/client/encrypted.rs | 16 | ||||
-rw-r--r-- | src/client/mod.rs | 10 | ||||
-rw-r--r-- | src/client/unencrypted.rs | 199 |
3 files changed, 152 insertions, 73 deletions
diff --git a/src/client/encrypted.rs b/src/client/encrypted.rs index 47b2b2c..263d5ff 100644 --- a/src/client/encrypted.rs +++ b/src/client/encrypted.rs @@ -2,36 +2,26 @@ use std::{collections::BTreeMap, str}; use quick_xml::{ events::{BytesDecl, Event}, - Reader, Writer, + NsReader, Writer, }; use rsasl::prelude::{Mechname, SASLClient}; use tokio::io::{BufReader, ReadHalf, WriteHalf}; use tokio::net::TcpStream; use tokio_native_tls::TlsStream; -use crate::stanza::{ - bind::Bind, - iq::IQ, - sasl::{Challenge, Success}, - Element, -}; -use crate::stanza::{ - sasl::{Auth, Response}, - stream::{Stream, StreamFeature}, -}; use crate::Jabber; use crate::JabberError; use crate::Result; pub struct JabberClient<'j> { - pub reader: Reader<BufReader<ReadHalf<TlsStream<TcpStream>>>>, + pub reader: NsReader<BufReader<ReadHalf<TlsStream<TcpStream>>>>, pub writer: Writer<WriteHalf<TlsStream<TcpStream>>>, jabber: &'j mut Jabber<'j>, } impl<'j> JabberClient<'j> { pub fn new( - reader: Reader<BufReader<ReadHalf<TlsStream<TcpStream>>>>, + reader: NsReader<BufReader<ReadHalf<TlsStream<TcpStream>>>>, writer: Writer<WriteHalf<TlsStream<TcpStream>>>, jabber: &'j mut Jabber<'j>, ) -> Self { diff --git a/src/client/mod.rs b/src/client/mod.rs index 280e0a1..01df4a4 100644 --- a/src/client/mod.rs +++ b/src/client/mod.rs @@ -1,22 +1,24 @@ -pub mod encrypted; +// pub mod encrypted; pub mod unencrypted; // use async_trait::async_trait; -use crate::stanza::stream::StreamFeature; +// use crate::stanza::stream::StreamFeature; use crate::JabberError; use crate::Result; pub enum JabberClientType<'j> { - Encrypted(encrypted::JabberClient<'j>), + // Encrypted(encrypted::JabberClient<'j>), Unencrypted(unencrypted::JabberClient<'j>), } impl<'j> JabberClientType<'j> { + /// ensures an encrypted jabber client pub async fn ensure_tls(self) -> Result<encrypted::JabberClient<'j>> { match self { 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?) @@ -28,7 +30,7 @@ impl<'j> JabberClientType<'j> { } } -// TODO: jabber client trait over both client types +// TODO: jabber client trait over both client types using macro // #[async_trait] // pub trait JabberTrait { // async fn start_stream(&mut self) -> Result<()>; diff --git a/src/client/unencrypted.rs b/src/client/unencrypted.rs index 27b0a5f..4aa9c63 100644 --- a/src/client/unencrypted.rs +++ b/src/client/unencrypted.rs @@ -1,27 +1,30 @@ +use std::str; + use quick_xml::{ - events::{BytesDecl, BytesStart, Event}, + events::{BytesStart, Event}, name::QName, - Reader, Writer, + se, NsReader, Writer, }; use tokio::io::{BufReader, ReadHalf, WriteHalf}; use tokio::net::TcpStream; use tokio_native_tls::native_tls::TlsConnector; +use try_map::FallibleMapExt; -use crate::stanza::stream::StreamFeature; -use crate::stanza::Element; +use crate::error::JabberError; +use crate::stanza::stream::Stream; +use crate::stanza::DECLARATION; use crate::Jabber; use crate::Result; -use crate::{error::JabberError, stanza::stream::Stream}; pub struct JabberClient<'j> { - reader: Reader<BufReader<ReadHalf<TcpStream>>>, + reader: NsReader<BufReader<ReadHalf<TcpStream>>>, writer: Writer<WriteHalf<TcpStream>>, jabber: &'j mut Jabber<'j>, } impl<'j> JabberClient<'j> { pub fn new( - reader: Reader<BufReader<ReadHalf<TcpStream>>>, + reader: NsReader<BufReader<ReadHalf<TcpStream>>>, writer: Writer<WriteHalf<TcpStream>>, jabber: &'j mut Jabber<'j>, ) -> Self { @@ -34,60 +37,144 @@ impl<'j> JabberClient<'j> { pub async fn start_stream(&mut self) -> Result<()> { // client to server - let declaration = BytesDecl::new("1.0", None, None); + + // declaration + self.writer.write_event_async(DECLARATION).await?; + + // opening stream element 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(); - self.reader.read_event_into_async(&mut buf).await?; - let _stream_response = Element::read_start(&mut self.reader).await?; - Ok(()) - } + let stream_element = Stream::new_client(None, server, None, "en"); + se::to_writer_with_root(&mut self.writer, "stream:stream", &stream_element); - pub async fn get_features(&mut self) -> Result<Vec<StreamFeature>> { - Element::read(&mut self.reader).await?.try_into() - } + // server to client - pub async fn starttls(mut self) -> Result<super::encrypted::JabberClient<'j>> { - let mut starttls_element = BytesStart::new("starttls"); - starttls_element.push_attribute(("xmlns", "urn:ietf:params:xml:ns:xmpp-tls")); - self.writer - .write_event_async(Event::Empty(starttls_element)) - .await - .unwrap(); - let mut buf = Vec::new(); - match self.reader.read_event_into_async(&mut buf).await.unwrap() { - Event::Empty(e) => match e.name() { - QName(b"proceed") => { - let connector = TlsConnector::new().unwrap(); - let stream = self - .reader - .into_inner() - .into_inner() - .unsplit(self.writer.into_inner()); - if let Ok(tlsstream) = tokio_native_tls::TlsConnector::from(connector) - .connect(&self.jabber.server, stream) - .await - { - 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?; - return Ok(client); + // may or may not send a declaration + let buf = Vec::new(); + let mut first_event = self.reader.read_resolved_event_into_async(&mut buf).await?; + match first_event { + (quick_xml::name::ResolveResult::Unbound, Event::Decl(e)) => { + if let Ok(version) = e.version() { + if version.as_ref() == b"1.0" { + first_event = self.reader.read_resolved_event_into_async(&mut buf).await? + } else { + // todo: error + todo!() } + } else { + first_event = self.reader.read_resolved_event_into_async(&mut buf).await? + } + } + _ => (), + } + + // receive stream element and validate + let stream_response: Stream; + match first_event { + (quick_xml::name::ResolveResult::Bound(ns), Event::Start(e)) => { + if ns.0 == crate::stanza::stream::XMLNS.as_bytes() { + // stream_response = Stream::new( + // e.try_get_attribute("from")?.try_map(|attribute| { + // str::from_utf8(attribute.value.as_ref())? + // .try_into()? + // .as_ref() + // })?, + // e.try_get_attribute("to")?.try_map(|attribute| { + // str::from_utf8(attribute.value.as_ref())? + // .try_into()? + // .as_ref() + // })?, + // e.try_get_attribute("id")?.try_map(|attribute| { + // str::from_utf8(attribute.value.as_ref())? + // .try_into()? + // .as_ref() + // })?, + // e.try_get_attribute("version")?.try_map(|attribute| { + // str::from_utf8(attribute.value.as_ref())? + // .try_into()? + // .as_ref() + // })?, + // e.try_get_attribute("lang")?.try_map(|attribute| { + // str::from_utf8(attribute.value.as_ref())? + // .try_into()? + // .as_ref() + // })?, + // ); + return Ok(()); + } else { + return Err(JabberError::BadStream); } - QName(_) => return Err(JabberError::TlsNegotiation), - }, - _ => return Err(JabberError::TlsNegotiation), + } + // TODO: errors for incorrect namespace + (quick_xml::name::ResolveResult::Unbound, Event::Decl(_)) => todo!(), + (quick_xml::name::ResolveResult::Unknown(_), Event::Start(_)) => todo!(), + (quick_xml::name::ResolveResult::Unknown(_), Event::End(_)) => todo!(), + (quick_xml::name::ResolveResult::Unknown(_), Event::Empty(_)) => todo!(), + (quick_xml::name::ResolveResult::Unknown(_), Event::Text(_)) => todo!(), + (quick_xml::name::ResolveResult::Unknown(_), Event::CData(_)) => todo!(), + (quick_xml::name::ResolveResult::Unknown(_), Event::Comment(_)) => todo!(), + (quick_xml::name::ResolveResult::Unknown(_), Event::Decl(_)) => todo!(), + (quick_xml::name::ResolveResult::Unknown(_), Event::PI(_)) => todo!(), + (quick_xml::name::ResolveResult::Unknown(_), Event::DocType(_)) => todo!(), + (quick_xml::name::ResolveResult::Unknown(_), Event::Eof) => todo!(), + (quick_xml::name::ResolveResult::Unbound, Event::Start(_)) => todo!(), + (quick_xml::name::ResolveResult::Unbound, Event::End(_)) => todo!(), + (quick_xml::name::ResolveResult::Unbound, Event::Empty(_)) => todo!(), + (quick_xml::name::ResolveResult::Unbound, Event::Text(_)) => todo!(), + (quick_xml::name::ResolveResult::Unbound, Event::CData(_)) => todo!(), + (quick_xml::name::ResolveResult::Unbound, Event::Comment(_)) => todo!(), + (quick_xml::name::ResolveResult::Unbound, Event::PI(_)) => todo!(), + (quick_xml::name::ResolveResult::Unbound, Event::DocType(_)) => todo!(), + (quick_xml::name::ResolveResult::Unbound, Event::Eof) => todo!(), + (quick_xml::name::ResolveResult::Bound(_), Event::End(_)) => todo!(), + (quick_xml::name::ResolveResult::Bound(_), Event::Empty(_)) => todo!(), + (quick_xml::name::ResolveResult::Bound(_), Event::Text(_)) => todo!(), + (quick_xml::name::ResolveResult::Bound(_), Event::CData(_)) => todo!(), + (quick_xml::name::ResolveResult::Bound(_), Event::Comment(_)) => todo!(), + (quick_xml::name::ResolveResult::Bound(_), Event::Decl(_)) => todo!(), + (quick_xml::name::ResolveResult::Bound(_), Event::PI(_)) => todo!(), + (quick_xml::name::ResolveResult::Bound(_), Event::DocType(_)) => todo!(), + (quick_xml::name::ResolveResult::Bound(_), Event::Eof) => todo!(), } - Err(JabberError::TlsNegotiation) } + + // pub async fn get_features(&mut self) -> Result<Vec<StreamFeature>> { + // Element::read(&mut self.reader).await?.try_into() + // } + + // pub async fn starttls(mut self) -> Result<super::encrypted::JabberClient<'j>> { + // let mut starttls_element = BytesStart::new("starttls"); + // starttls_element.push_attribute(("xmlns", "urn:ietf:params:xml:ns:xmpp-tls")); + // self.writer + // .write_event_async(Event::Empty(starttls_element)) + // .await + // .unwrap(); + // let mut buf = Vec::new(); + // match self.reader.read_event_into_async(&mut buf).await.unwrap() { + // Event::Empty(e) => match e.name() { + // QName(b"proceed") => { + // let connector = TlsConnector::new().unwrap(); + // let stream = self + // .reader + // .into_inner() + // .into_inner() + // .unsplit(self.writer.into_inner()); + // if let Ok(tlsstream) = tokio_native_tls::TlsConnector::from(connector) + // .connect(&self.jabber.server, stream) + // .await + // { + // 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?; + // return Ok(client); + // } + // } + // QName(_) => return Err(JabberError::TlsNegotiation), + // }, + // _ => return Err(JabberError::TlsNegotiation), + // } + // Err(JabberError::TlsNegotiation) + // } } |