summaryrefslogtreecommitdiffstats
path: root/src/client
diff options
context:
space:
mode:
authorLibravatar cel 🌸 <cel@blos.sm>2023-10-21 01:28:54 +0100
committerLibravatar cel 🌸 <cel@blos.sm>2023-10-21 01:28:54 +0100
commite893869df974ebb7afcc318119840c53f8f377cb (patch)
tree3319dba477784c126011acc5422c9973782f7850 /src/client
parentba94ee66fafbabd63d6d1ed5edf435d4c46c6796 (diff)
downloadluz-e893869df974ebb7afcc318119840c53f8f377cb.tar.gz
luz-e893869df974ebb7afcc318119840c53f8f377cb.tar.bz2
luz-e893869df974ebb7afcc318119840c53f8f377cb.zip
implement connection
Diffstat (limited to '')
-rw-r--r--src/client/encrypted.rs205
-rw-r--r--src/client/mod.rs38
-rw-r--r--src/client/unencrypted.rs180
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)
- // }
-}