summaryrefslogtreecommitdiffstats
path: root/src/client
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/client/encrypted.rs16
-rw-r--r--src/client/mod.rs10
-rw-r--r--src/client/unencrypted.rs199
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)
+ // }
}