diff options
author | cel 🌸 <cel@blos.sm> | 2023-10-21 01:28:54 +0100 |
---|---|---|
committer | cel 🌸 <cel@blos.sm> | 2023-10-21 01:28:54 +0100 |
commit | e893869df974ebb7afcc318119840c53f8f377cb (patch) | |
tree | 3319dba477784c126011acc5422c9973782f7850 /src/client | |
parent | ba94ee66fafbabd63d6d1ed5edf435d4c46c6796 (diff) | |
download | luz-e893869df974ebb7afcc318119840c53f8f377cb.tar.gz luz-e893869df974ebb7afcc318119840c53f8f377cb.tar.bz2 luz-e893869df974ebb7afcc318119840c53f8f377cb.zip |
implement connection
Diffstat (limited to 'src/client')
-rw-r--r-- | src/client/encrypted.rs | 205 | ||||
-rw-r--r-- | src/client/mod.rs | 38 | ||||
-rw-r--r-- | src/client/unencrypted.rs | 180 |
3 files changed, 0 insertions, 423 deletions
diff --git a/src/client/encrypted.rs b/src/client/encrypted.rs deleted file mode 100644 index 263d5ff..0000000 --- a/src/client/encrypted.rs +++ /dev/null @@ -1,205 +0,0 @@ -use std::{collections::BTreeMap, str}; - -use quick_xml::{ - events::{BytesDecl, Event}, - NsReader, Writer, -}; -use rsasl::prelude::{Mechname, SASLClient}; -use tokio::io::{BufReader, ReadHalf, WriteHalf}; -use tokio::net::TcpStream; -use tokio_native_tls::TlsStream; - -use crate::Jabber; -use crate::JabberError; -use crate::Result; - -pub struct JabberClient<'j> { - 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: NsReader<BufReader<ReadHalf<TlsStream<TcpStream>>>>, - writer: Writer<WriteHalf<TlsStream<TcpStream>>>, - jabber: &'j mut Jabber<'j>, - ) -> Self { - Self { - reader, - writer, - jabber, - } - } - - pub async fn start_stream(&mut self) -> Result<()> { - // client to server - let declaration = BytesDecl::new("1.0", None, None); - 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, &BTreeMap::new()) - .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(()) - } - - pub async fn get_features(&mut self) -> Result<Vec<StreamFeature>> { - Element::read(&mut self.reader).await?.try_into() - } - - pub async fn negotiate(&mut self) -> Result<()> { - loop { - println!("negotiate loop"); - let features = self.get_features().await?; - println!("features: {:?}", features); - - match &features[0] { - StreamFeature::Sasl(sasl) => { - println!("sasl?"); - self.sasl(&sasl).await?; - } - StreamFeature::Bind => { - self.bind().await?; - return Ok(()); - } - x => println!("{:?}", x), - } - } - } - - pub async fn watch(&mut self) -> Result<()> { - loop { - let element = Element::read(&mut self.reader).await?; - println!("{:#?}", element); - } - } - - pub async fn sasl(&mut self, mechanisms: &Vec<String>) -> Result<()> { - println!("{:?}", mechanisms); - let sasl = SASLClient::new(self.jabber.auth.clone()); - let mut offered_mechs: Vec<&Mechname> = Vec::new(); - for mechanism in mechanisms { - offered_mechs.push(Mechname::parse(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 { - mechanism: selected_mechanism.as_str(), - sasl_data: "=", - }; - Into::<Element>::into(auth).write(&mut self.writer).await?; - // get challenge data - let challenge = &Element::read(&mut self.reader).await?; - let challenge: Challenge = challenge.try_into()?; - println!("challenge: {:?}", challenge); - data = Some(challenge.sasl_data.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 { - mechanism: selected_mechanism.as_str(), - sasl_data: str::from_utf8(&sasl_data)?, - }; - println!("{:?}", auth); - Into::<Element>::into(auth).write(&mut self.writer).await?; - - let server_response = Element::read(&mut self.reader).await?; - println!("server_response: {:#?}", server_response); - match TryInto::<Challenge>::try_into(&server_response) { - Ok(challenge) => data = Some(challenge.sasl_data.to_owned()), - Err(_) => { - let success = TryInto::<Success>::try_into(&server_response)?; - if let Some(sasl_data) = success.sasl_data { - data = Some(sasl_data.to_owned()) - } - } - } - println!("we went first"); - } - - // stepping the authentication exchange to completion - if data != None { - println!("data: {:?}", data); - 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 response = Response { - sasl_data: str::from_utf8(&sasl_data)?, - }; - println!("response: {:?}", response); - Into::<Element>::into(response) - .write(&mut self.writer) - .await?; - - let server_response = Element::read(&mut self.reader).await?; - println!("server_response: {:?}", server_response); - match TryInto::<Challenge>::try_into(&server_response) { - Ok(challenge) => data = Some(challenge.sasl_data.to_owned()), - Err(_) => { - let success = TryInto::<Success>::try_into(&server_response)?; - if let Some(sasl_data) = success.sasl_data { - data = Some(sasl_data.to_owned()) - } - } - } - } - } - self.start_stream().await?; - Ok(()) - } - - pub async fn bind(&mut self) -> Result<()> { - match &self.jabber.jid.resourcepart { - Some(resource) => { - println!("setting resource"); - let bind = Bind { - resource: Some(resource.clone()), - jid: None, - }; - let result: Bind = IQ::set(self, None, None, bind).await?.try_into()?; - if let Some(jid) = result.jid { - println!("{}", jid); - self.jabber.jid = jid; - return Ok(()); - } - } - None => { - println!("not setting resource"); - let bind = Bind { - resource: None, - jid: None, - }; - let result: Bind = IQ::set(self, None, None, bind).await?.try_into()?; - if let Some(jid) = result.jid { - println!("{}", jid); - self.jabber.jid = jid; - return Ok(()); - } - } - } - Err(JabberError::BindError) - } -} diff --git a/src/client/mod.rs b/src/client/mod.rs deleted file mode 100644 index 01df4a4..0000000 --- a/src/client/mod.rs +++ /dev/null @@ -1,38 +0,0 @@ -// pub mod encrypted; -pub mod unencrypted; - -// use async_trait::async_trait; - -// use crate::stanza::stream::StreamFeature; -use crate::JabberError; -use crate::Result; - -pub enum JabberClientType<'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?) - } else { - Err(JabberError::StartTlsUnavailable) - } - } - } - } -} - -// TODO: jabber client trait over both client types using macro -// #[async_trait] -// pub trait JabberTrait { -// async fn start_stream(&mut self) -> Result<()>; -// async fn get_features(&self) -> Result<Vec<StreamFeatures>>; -// } diff --git a/src/client/unencrypted.rs b/src/client/unencrypted.rs deleted file mode 100644 index 4aa9c63..0000000 --- a/src/client/unencrypted.rs +++ /dev/null @@ -1,180 +0,0 @@ -use std::str; - -use quick_xml::{ - events::{BytesStart, Event}, - name::QName, - 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::error::JabberError; -use crate::stanza::stream::Stream; -use crate::stanza::DECLARATION; -use crate::Jabber; -use crate::Result; - -pub struct JabberClient<'j> { - reader: NsReader<BufReader<ReadHalf<TcpStream>>>, - writer: Writer<WriteHalf<TcpStream>>, - jabber: &'j mut Jabber<'j>, -} - -impl<'j> JabberClient<'j> { - pub fn new( - reader: NsReader<BufReader<ReadHalf<TcpStream>>>, - writer: Writer<WriteHalf<TcpStream>>, - jabber: &'j mut Jabber<'j>, - ) -> Self { - Self { - reader, - writer, - jabber, - } - } - - pub async fn start_stream(&mut self) -> Result<()> { - // client to server - - // 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(None, server, None, "en"); - se::to_writer_with_root(&mut self.writer, "stream:stream", &stream_element); - - // server to 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); - } - } - // 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!(), - } - } - - // 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) - // } -} |