From ba94ee66fafbabd63d6d1ed5edf435d4c46c6796 Mon Sep 17 00:00:00 2001 From: cel 🌸 Date: Fri, 20 Oct 2023 04:51:56 +0100 Subject: WIP: refactor to parse incoming stream as state machine --- src/client/unencrypted.rs | 199 +++++++++++++++++++++++++++++++++------------- 1 file changed, 143 insertions(+), 56 deletions(-) (limited to 'src/client/unencrypted.rs') 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>>, + reader: NsReader>>, writer: Writer>, jabber: &'j mut Jabber<'j>, } impl<'j> JabberClient<'j> { pub fn new( - reader: Reader>>, + reader: NsReader>>, writer: Writer>, 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> { - Element::read(&mut self.reader).await?.try_into() - } + // server to client - pub async fn starttls(mut self) -> Result> { - 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> { + // Element::read(&mut self.reader).await?.try_into() + // } + + // pub async fn starttls(mut self) -> Result> { + // 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) + // } } -- cgit