diff options
author | cel 🌸 <cel@blos.sm> | 2023-07-04 21:27:15 +0100 |
---|---|---|
committer | cel 🌸 <cel@blos.sm> | 2023-07-04 21:27:15 +0100 |
commit | 143a0365d0822e6786cdac3530a725bbf450f38f (patch) | |
tree | 8b540aa73c1365ddc658e502ed93847dbb522064 /src/client | |
parent | c0a7116eef13ea75340fe7d75da97dfbd04fac20 (diff) | |
download | luz-143a0365d0822e6786cdac3530a725bbf450f38f.tar.gz luz-143a0365d0822e6786cdac3530a725bbf450f38f.tar.bz2 luz-143a0365d0822e6786cdac3530a725bbf450f38f.zip |
horrible
Diffstat (limited to 'src/client')
-rw-r--r-- | src/client/encrypted.rs | 189 | ||||
-rw-r--r-- | src/client/unencrypted.rs | 12 |
2 files changed, 184 insertions, 17 deletions
diff --git a/src/client/encrypted.rs b/src/client/encrypted.rs index 08439b2..a4bf0d1 100644 --- a/src/client/encrypted.rs +++ b/src/client/encrypted.rs @@ -1,24 +1,35 @@ +use std::str; + use quick_xml::{ + de::Deserializer, events::{BytesDecl, BytesStart, Event}, + name::QName, + se::Serializer, Reader, Writer, }; -use tokio::io::{BufReader, ReadHalf, WriteHalf}; +use rsasl::prelude::{Mechname, SASLClient}; +use serde::{Deserialize, Serialize}; +use tokio::io::{AsyncWriteExt, BufReader, ReadHalf, WriteHalf}; use tokio::net::TcpStream; use tokio_native_tls::TlsStream; +use crate::stanza::{ + sasl::{Auth, Challenge, Mechanisms}, + stream::{StreamFeature, StreamFeatures}, +}; use crate::Jabber; use crate::Result; pub struct JabberClient<'j> { reader: Reader<BufReader<ReadHalf<TlsStream<TcpStream>>>>, - writer: Writer<WriteHalf<TlsStream<TcpStream>>>, + writer: WriteHalf<TlsStream<TcpStream>>, jabber: &'j mut Jabber<'j>, } impl<'j> JabberClient<'j> { pub fn new( reader: Reader<BufReader<ReadHalf<TlsStream<TcpStream>>>>, - writer: Writer<WriteHalf<TlsStream<TcpStream>>>, + writer: WriteHalf<TlsStream<TcpStream>>, jabber: &'j mut Jabber<'j>, ) -> Self { Self { @@ -37,13 +48,9 @@ impl<'j> JabberClient<'j> { 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")); - self.writer - .write_event_async(Event::Decl(declaration)) - .await; - self.writer - .write_event_async(Event::Start(stream_element)) - .await - .unwrap(); + 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 mut buf = Vec::new(); loop { match self.reader.read_event_into_async(&mut buf).await.unwrap() { @@ -56,4 +63,166 @@ impl<'j> JabberClient<'j> { } 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(); + } + 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<()> { + loop { + 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), + } + } + } + + 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/unencrypted.rs b/src/client/unencrypted.rs index 74b800c..d4225d3 100644 --- a/src/client/unencrypted.rs +++ b/src/client/unencrypted.rs @@ -115,14 +115,12 @@ impl<'j> JabberClient<'j> { .connect(&self.jabber.server, stream) .await { - let (read, write) = tokio::io::split(tlsstream); + let (read, writer) = tokio::io::split(tlsstream); let reader = Reader::from_reader(BufReader::new(read)); - let writer = Writer::new(write); - return Ok(super::encrypted::JabberClient::new( - reader, - writer, - self.jabber, - )); + let mut client = + super::encrypted::JabberClient::new(reader, writer, self.jabber); + client.start_stream().await?; + return Ok(client); } } QName(_) => return Err(JabberError::TlsNegotiation), |