remove serde functions
This commit is contained in:
parent
143a0365d0
commit
f43911ccba
|
@ -7,6 +7,7 @@ edition = "2021"
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
async-recursion = "1.0.4"
|
||||||
async-trait = "0.1.68"
|
async-trait = "0.1.68"
|
||||||
quick-xml = { git = "https://github.com/tafia/quick-xml.git", features = ["async-tokio", "serialize"] }
|
quick-xml = { git = "https://github.com/tafia/quick-xml.git", features = ["async-tokio", "serialize"] }
|
||||||
# TODO: remove unneeded features
|
# TODO: remove unneeded features
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
tag = <tag> or </tag>
|
||||||
|
element = <sajdlfkajsdf/> or <slakdfj></slakdfj>
|
||||||
|
stanza = specific element <message/> <presence/> <iq/>
|
||||||
|
|
||||||
|
|
|
@ -1,35 +1,26 @@
|
||||||
use std::str;
|
|
||||||
|
|
||||||
use quick_xml::{
|
use quick_xml::{
|
||||||
de::Deserializer,
|
events::{BytesDecl, Event},
|
||||||
events::{BytesDecl, BytesStart, Event},
|
|
||||||
name::QName,
|
|
||||||
se::Serializer,
|
|
||||||
Reader, Writer,
|
Reader, Writer,
|
||||||
};
|
};
|
||||||
use rsasl::prelude::{Mechname, SASLClient};
|
use tokio::io::{BufReader, ReadHalf, WriteHalf};
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use tokio::io::{AsyncWriteExt, BufReader, ReadHalf, WriteHalf};
|
|
||||||
use tokio::net::TcpStream;
|
use tokio::net::TcpStream;
|
||||||
use tokio_native_tls::TlsStream;
|
use tokio_native_tls::TlsStream;
|
||||||
|
|
||||||
use crate::stanza::{
|
use crate::element::Element;
|
||||||
sasl::{Auth, Challenge, Mechanisms},
|
use crate::stanza::stream::{Stream, StreamFeature};
|
||||||
stream::{StreamFeature, StreamFeatures},
|
|
||||||
};
|
|
||||||
use crate::Jabber;
|
use crate::Jabber;
|
||||||
use crate::Result;
|
use crate::Result;
|
||||||
|
|
||||||
pub struct JabberClient<'j> {
|
pub struct JabberClient<'j> {
|
||||||
reader: Reader<BufReader<ReadHalf<TlsStream<TcpStream>>>>,
|
reader: Reader<BufReader<ReadHalf<TlsStream<TcpStream>>>>,
|
||||||
writer: WriteHalf<TlsStream<TcpStream>>,
|
writer: Writer<WriteHalf<TlsStream<TcpStream>>>,
|
||||||
jabber: &'j mut Jabber<'j>,
|
jabber: &'j mut Jabber<'j>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'j> JabberClient<'j> {
|
impl<'j> JabberClient<'j> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
reader: Reader<BufReader<ReadHalf<TlsStream<TcpStream>>>>,
|
reader: Reader<BufReader<ReadHalf<TlsStream<TcpStream>>>>,
|
||||||
writer: WriteHalf<TlsStream<TcpStream>>,
|
writer: Writer<WriteHalf<TlsStream<TcpStream>>>,
|
||||||
jabber: &'j mut Jabber<'j>,
|
jabber: &'j mut Jabber<'j>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
@ -40,90 +31,29 @@ impl<'j> JabberClient<'j> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn start_stream(&mut self) -> Result<()> {
|
pub async fn start_stream(&mut self) -> Result<()> {
|
||||||
|
// client to server
|
||||||
let declaration = BytesDecl::new("1.0", None, None);
|
let declaration = BytesDecl::new("1.0", None, None);
|
||||||
let mut stream_element = BytesStart::new("stream:stream");
|
let server = &self.jabber.server.to_owned().try_into()?;
|
||||||
stream_element.push_attribute(("from".as_bytes(), self.jabber.jid.to_string().as_bytes()));
|
let stream_element =
|
||||||
stream_element.push_attribute(("to".as_bytes(), self.jabber.server.as_bytes()));
|
Stream::new_client(&self.jabber.jid, server, None, Some("en".to_string()));
|
||||||
stream_element.push_attribute(("version", "1.0"));
|
self.writer
|
||||||
stream_element.push_attribute(("xml:lang", "en"));
|
.write_event_async(Event::Decl(declaration))
|
||||||
stream_element.push_attribute(("xmlns", "jabber:client"));
|
.await;
|
||||||
stream_element.push_attribute(("xmlns:stream", "http://etherx.jabber.org/streams"));
|
let stream_element: Element<'_> = stream_element.into();
|
||||||
let mut writer = Writer::new(&mut self.writer);
|
stream_element.write_start(&mut self.writer).await?;
|
||||||
writer.write_event_async(Event::Decl(declaration)).await;
|
// server to client
|
||||||
writer.write_event_async(Event::Start(stream_element)).await;
|
|
||||||
let mut buf = Vec::new();
|
let mut buf = Vec::new();
|
||||||
loop {
|
self.reader.read_event_into_async(&mut buf).await?;
|
||||||
match self.reader.read_event_into_async(&mut buf).await.unwrap() {
|
let _stream_response = Element::read_start(&mut self.reader).await?;
|
||||||
Event::Start(e) => {
|
|
||||||
println!("{:?}", e);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
e => println!("decl: {:?}", e),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_node<'a>(&mut self) -> Result<String> {
|
pub async fn get_features(&mut self) -> Result<Option<Vec<StreamFeature>>> {
|
||||||
let mut buf = Vec::new();
|
if let Some(features) = Element::read(&mut self.reader).await? {
|
||||||
let mut txt = Vec::new();
|
Ok(Some(features.try_into()?))
|
||||||
let mut qname_set = false;
|
} else {
|
||||||
let mut qname: Option<Vec<u8>> = None;
|
Ok(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<()> {
|
pub async fn negotiate(&mut self) -> Result<()> {
|
||||||
|
@ -131,98 +61,14 @@ impl<'j> JabberClient<'j> {
|
||||||
println!("loop");
|
println!("loop");
|
||||||
let features = &self.get_features().await?;
|
let features = &self.get_features().await?;
|
||||||
println!("{:?}", features);
|
println!("{:?}", features);
|
||||||
match &features[0] {
|
// match &features[0] {
|
||||||
StreamFeature::Sasl(sasl) => {
|
// StreamFeature::Sasl(sasl) => {
|
||||||
println!("{:?}", sasl);
|
// println!("{:?}", sasl);
|
||||||
self.sasl(&sasl).await?;
|
// todo!()
|
||||||
|
// }
|
||||||
|
// StreamFeature::Bind => todo!(),
|
||||||
|
// x => println!("{:?}", x),
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
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(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,18 +15,17 @@ pub enum JabberClientType<'j> {
|
||||||
impl<'j> JabberClientType<'j> {
|
impl<'j> JabberClientType<'j> {
|
||||||
pub async fn ensure_tls(self) -> Result<encrypted::JabberClient<'j>> {
|
pub async fn ensure_tls(self) -> Result<encrypted::JabberClient<'j>> {
|
||||||
match self {
|
match self {
|
||||||
Self::Encrypted(mut c) => {
|
Self::Encrypted(c) => Ok(c),
|
||||||
c.start_stream();
|
|
||||||
Ok(c)
|
|
||||||
}
|
|
||||||
Self::Unencrypted(mut c) => {
|
Self::Unencrypted(mut c) => {
|
||||||
c.start_stream().await?;
|
if let Some(features) = c.get_features().await? {
|
||||||
let features = c.get_features().await?;
|
|
||||||
if features.contains(&StreamFeature::StartTls) {
|
if features.contains(&StreamFeature::StartTls) {
|
||||||
Ok(c.starttls().await?)
|
Ok(c.starttls().await?)
|
||||||
} else {
|
} else {
|
||||||
Err(JabberError::StartTlsUnavailable)
|
Err(JabberError::StartTlsUnavailable)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
Err(JabberError::NoFeatures)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
use std::str;
|
use std::str;
|
||||||
|
|
||||||
use quick_xml::{
|
use quick_xml::{
|
||||||
de::Deserializer,
|
|
||||||
events::{BytesDecl, BytesStart, Event},
|
events::{BytesDecl, BytesStart, Event},
|
||||||
name::QName,
|
name::QName,
|
||||||
Reader, Writer,
|
Reader, Writer,
|
||||||
};
|
};
|
||||||
use serde::Deserialize;
|
|
||||||
use tokio::io::{BufReader, ReadHalf, WriteHalf};
|
use tokio::io::{BufReader, ReadHalf, WriteHalf};
|
||||||
use tokio::net::TcpStream;
|
use tokio::net::TcpStream;
|
||||||
use tokio_native_tls::native_tls::TlsConnector;
|
use tokio_native_tls::native_tls::TlsConnector;
|
||||||
|
|
||||||
|
use crate::element::Element;
|
||||||
|
use crate::stanza::stream::StreamFeature;
|
||||||
|
use crate::Jabber;
|
||||||
use crate::Result;
|
use crate::Result;
|
||||||
use crate::{error::JabberError, stanza::stream::StreamFeature};
|
use crate::{error::JabberError, stanza::stream::Stream};
|
||||||
use crate::{stanza::stream::StreamFeatures, Jabber};
|
|
||||||
|
|
||||||
pub struct JabberClient<'j> {
|
pub struct JabberClient<'j> {
|
||||||
reader: Reader<BufReader<ReadHalf<TcpStream>>>,
|
reader: Reader<BufReader<ReadHalf<TcpStream>>>,
|
||||||
|
@ -35,63 +35,30 @@ impl<'j> JabberClient<'j> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn start_stream(&mut self) -> Result<()> {
|
pub async fn start_stream(&mut self) -> Result<()> {
|
||||||
|
// client to server
|
||||||
let declaration = BytesDecl::new("1.0", None, None);
|
let declaration = BytesDecl::new("1.0", None, None);
|
||||||
let mut stream_element = BytesStart::new("stream:stream");
|
let server = &self.jabber.server.to_owned().try_into()?;
|
||||||
stream_element.push_attribute(("from".as_bytes(), self.jabber.jid.to_string().as_bytes()));
|
let stream_element =
|
||||||
stream_element.push_attribute(("to".as_bytes(), self.jabber.server.as_bytes()));
|
Stream::new_client(&self.jabber.jid, server, None, Some("en".to_string()));
|
||||||
stream_element.push_attribute(("version", "1.0"));
|
|
||||||
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
|
self.writer
|
||||||
.write_event_async(Event::Decl(declaration))
|
.write_event_async(Event::Decl(declaration))
|
||||||
.await;
|
.await?;
|
||||||
self.writer
|
let stream_element: Element<'_> = stream_element.into();
|
||||||
.write_event_async(Event::Start(stream_element))
|
stream_element.write_start(&mut self.writer).await?;
|
||||||
.await
|
// server to client
|
||||||
.unwrap();
|
|
||||||
let mut buf = Vec::new();
|
let mut buf = Vec::new();
|
||||||
loop {
|
self.reader.read_event_into_async(&mut buf).await?;
|
||||||
match self.reader.read_event_into_async(&mut buf).await.unwrap() {
|
let _stream_response = Element::read_start(&mut self.reader).await?;
|
||||||
Event::Start(e) => {
|
|
||||||
println!("{:?}", e);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
Event::Decl(e) => println!("decl: {:?}", e),
|
|
||||||
_ => return Err(JabberError::BadStream),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_features(&mut self) -> Result<Vec<StreamFeature>> {
|
pub async fn get_features(&mut self) -> Result<Option<Vec<StreamFeature>>> {
|
||||||
let mut buf = Vec::new();
|
if let Some(features) = Element::read(&mut self.reader).await? {
|
||||||
let mut txt = Vec::new();
|
|
||||||
let mut loop_end = false;
|
|
||||||
while !loop_end {
|
|
||||||
match self.reader.read_event_into_async(&mut buf).await.unwrap() {
|
|
||||||
Event::End(e) => {
|
|
||||||
if e.name() == QName(b"stream:features") {
|
|
||||||
loop_end = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
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).unwrap();
|
|
||||||
println!("decoded: {:?}", decoded);
|
|
||||||
let mut deserializer = Deserializer::from_str(decoded);
|
|
||||||
let features = StreamFeatures::deserialize(&mut deserializer).unwrap();
|
|
||||||
println!("{:?}", features);
|
println!("{:?}", features);
|
||||||
Ok(features.features)
|
Ok(Some(features.try_into()?))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn starttls(mut self) -> Result<super::encrypted::JabberClient<'j>> {
|
pub async fn starttls(mut self) -> Result<super::encrypted::JabberClient<'j>> {
|
||||||
|
@ -115,8 +82,9 @@ impl<'j> JabberClient<'j> {
|
||||||
.connect(&self.jabber.server, stream)
|
.connect(&self.jabber.server, stream)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
let (read, writer) = tokio::io::split(tlsstream);
|
let (read, write) = tokio::io::split(tlsstream);
|
||||||
let reader = Reader::from_reader(BufReader::new(read));
|
let reader = Reader::from_reader(BufReader::new(read));
|
||||||
|
let writer = Writer::new(write);
|
||||||
let mut client =
|
let mut client =
|
||||||
super::encrypted::JabberClient::new(reader, writer, self.jabber);
|
super::encrypted::JabberClient::new(reader, writer, self.jabber);
|
||||||
client.start_stream().await?;
|
client.start_stream().await?;
|
||||||
|
|
|
@ -0,0 +1,108 @@
|
||||||
|
use async_recursion::async_recursion;
|
||||||
|
use quick_xml::events::Event;
|
||||||
|
use quick_xml::{Reader, Writer};
|
||||||
|
use tokio::io::{AsyncBufRead, AsyncWrite};
|
||||||
|
|
||||||
|
use crate::Result;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Element<'e> {
|
||||||
|
pub event: Event<'e>,
|
||||||
|
pub content: Option<Vec<Element<'e>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: make method
|
||||||
|
#[async_recursion]
|
||||||
|
pub async fn write<'e: 'async_recursion, W: AsyncWrite + Unpin + Send>(
|
||||||
|
element: Element<'e>,
|
||||||
|
writer: &mut Writer<W>,
|
||||||
|
) -> Result<()> {
|
||||||
|
match element.event {
|
||||||
|
Event::Start(e) => {
|
||||||
|
writer.write_event_async(Event::Start(e.clone())).await?;
|
||||||
|
if let Some(content) = element.content {
|
||||||
|
for e in content {
|
||||||
|
write(e, writer).await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writer.write_event_async(Event::End(e.to_end())).await?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
e => Ok(writer.write_event_async(e).await?),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'e> Element<'e> {
|
||||||
|
pub async fn write_start<W: AsyncWrite + Unpin + Send>(
|
||||||
|
&self,
|
||||||
|
writer: &mut Writer<W>,
|
||||||
|
) -> Result<()> {
|
||||||
|
match self.event.as_ref() {
|
||||||
|
Event::Start(e) => Ok(writer.write_event_async(Event::Start(e.clone())).await?),
|
||||||
|
e => Err(ElementError::NotAStart(e.clone().into_owned()).into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn write_end<W: AsyncWrite + Unpin + Send>(
|
||||||
|
&self,
|
||||||
|
writer: &mut Writer<W>,
|
||||||
|
) -> Result<()> {
|
||||||
|
match self.event.as_ref() {
|
||||||
|
Event::Start(e) => Ok(writer
|
||||||
|
.write_event_async(Event::End(e.clone().to_end()))
|
||||||
|
.await?),
|
||||||
|
e => Err(ElementError::NotAStart(e.clone().into_owned()).into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_recursion]
|
||||||
|
pub async fn read<R: AsyncBufRead + Unpin + Send>(
|
||||||
|
reader: &mut Reader<R>,
|
||||||
|
) -> Result<Option<Self>> {
|
||||||
|
let mut buf = Vec::new();
|
||||||
|
let event = reader.read_event_into_async(&mut buf).await?;
|
||||||
|
match event {
|
||||||
|
Event::Start(e) => {
|
||||||
|
let mut content_vec = Vec::new();
|
||||||
|
while let Some(sub_element) = Element::read(reader).await? {
|
||||||
|
content_vec.push(sub_element)
|
||||||
|
}
|
||||||
|
let mut content = None;
|
||||||
|
if !content_vec.is_empty() {
|
||||||
|
content = Some(content_vec)
|
||||||
|
}
|
||||||
|
Ok(Some(Self {
|
||||||
|
event: Event::Start(e.into_owned()),
|
||||||
|
content,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
Event::End(_) => Ok(None),
|
||||||
|
e => Ok(Some(Self {
|
||||||
|
event: e.into_owned(),
|
||||||
|
content: None,
|
||||||
|
})),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_recursion]
|
||||||
|
pub async fn read_start<R: AsyncBufRead + Unpin + Send>(
|
||||||
|
reader: &mut Reader<R>,
|
||||||
|
) -> Result<Self> {
|
||||||
|
let mut buf = Vec::new();
|
||||||
|
let event = reader.read_event_into_async(&mut buf).await?;
|
||||||
|
match event {
|
||||||
|
Event::Start(e) => {
|
||||||
|
return Ok(Self {
|
||||||
|
event: Event::Start(e.into_owned()),
|
||||||
|
content: None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
e => Err(ElementError::NotAStart(e.into_owned()).into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum ElementError<'e> {
|
||||||
|
NotAStart(Event<'e>),
|
||||||
|
}
|
31
src/error.rs
31
src/error.rs
|
@ -1,7 +1,13 @@
|
||||||
use std::str::Utf8Error;
|
use std::str::Utf8Error;
|
||||||
|
|
||||||
|
use quick_xml::events::attributes::AttrError;
|
||||||
use rsasl::mechname::MechanismNameError;
|
use rsasl::mechname::MechanismNameError;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
element::{self, ElementError},
|
||||||
|
jid::ParseError,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum JabberError {
|
pub enum JabberError {
|
||||||
Connection,
|
Connection,
|
||||||
|
@ -9,8 +15,13 @@ pub enum JabberError {
|
||||||
StartTlsUnavailable,
|
StartTlsUnavailable,
|
||||||
TlsNegotiation,
|
TlsNegotiation,
|
||||||
Utf8Decode,
|
Utf8Decode,
|
||||||
|
NoFeatures,
|
||||||
|
UnknownNamespace,
|
||||||
|
ParseError,
|
||||||
XML(quick_xml::Error),
|
XML(quick_xml::Error),
|
||||||
SASL(SASLError),
|
SASL(SASLError),
|
||||||
|
Element(ElementError<'static>),
|
||||||
|
JID(ParseError),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -32,7 +43,7 @@ impl From<MechanismNameError> for JabberError {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Utf8Error> for JabberError {
|
impl From<Utf8Error> for JabberError {
|
||||||
fn from(e: Utf8Error) -> Self {
|
fn from(_e: Utf8Error) -> Self {
|
||||||
Self::Utf8Decode
|
Self::Utf8Decode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,3 +53,21 @@ impl From<quick_xml::Error> for JabberError {
|
||||||
Self::XML(e)
|
Self::XML(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<element::ElementError<'static>> for JabberError {
|
||||||
|
fn from(e: element::ElementError<'static>) -> Self {
|
||||||
|
Self::Element(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<AttrError> for JabberError {
|
||||||
|
fn from(e: AttrError) -> Self {
|
||||||
|
Self::XML(e.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ParseError> for JabberError {
|
||||||
|
fn from(e: ParseError) -> Self {
|
||||||
|
Self::JID(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -117,11 +117,12 @@ impl<'j> Jabber<'j> {
|
||||||
.connect(&self.server, socket)
|
.connect(&self.server, socket)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
let (read, writer) = tokio::io::split(stream);
|
let (read, write) = tokio::io::split(stream);
|
||||||
let reader = Reader::from_reader(BufReader::new(read));
|
let reader = Reader::from_reader(BufReader::new(read));
|
||||||
return Ok(JabberClientType::Encrypted(
|
let writer = Writer::new(write);
|
||||||
client::encrypted::JabberClient::new(reader, writer, self),
|
let mut client = client::encrypted::JabberClient::new(reader, writer, self);
|
||||||
));
|
client.start_stream().await?;
|
||||||
|
return Ok(JabberClientType::Encrypted(client));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
false => {
|
false => {
|
||||||
|
@ -129,9 +130,10 @@ impl<'j> Jabber<'j> {
|
||||||
let (read, write) = tokio::io::split(stream);
|
let (read, write) = tokio::io::split(stream);
|
||||||
let reader = Reader::from_reader(BufReader::new(read));
|
let reader = Reader::from_reader(BufReader::new(read));
|
||||||
let writer = Writer::new(write);
|
let writer = Writer::new(write);
|
||||||
return Ok(JabberClientType::Unencrypted(
|
let mut client =
|
||||||
client::unencrypted::JabberClient::new(reader, writer, self),
|
client::unencrypted::JabberClient::new(reader, writer, self);
|
||||||
));
|
client.start_stream().await?;
|
||||||
|
return Ok(JabberClientType::Unencrypted(client));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
#[derive(PartialEq, Debug)]
|
#[derive(PartialEq, Debug, Clone)]
|
||||||
pub struct JID {
|
pub struct JID {
|
||||||
// TODO: validate localpart (length, char]
|
// TODO: validate localpart (length, char]
|
||||||
pub localpart: Option<String>,
|
pub localpart: Option<String>,
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
// TODO: logging (dropped errors)
|
// TODO: logging (dropped errors)
|
||||||
pub mod client;
|
pub mod client;
|
||||||
|
pub mod element;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod jabber;
|
pub mod jabber;
|
||||||
pub mod jid;
|
pub mod jid;
|
||||||
|
|
|
@ -1,2 +1,6 @@
|
||||||
|
// use quick_xml::events::BytesDecl;
|
||||||
|
|
||||||
pub mod sasl;
|
pub mod sasl;
|
||||||
pub mod stream;
|
pub mod stream;
|
||||||
|
|
||||||
|
// const DECLARATION: BytesDecl<'_> = BytesDecl::new("1.0", None, None);
|
||||||
|
|
|
@ -1,32 +1,8 @@
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
#[derive(Deserialize, PartialEq, Debug)]
|
|
||||||
pub struct Mechanisms {
|
|
||||||
#[serde(rename = "$value")]
|
|
||||||
pub mechanisms: Vec<Mechanism>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize, PartialEq, Debug)]
|
|
||||||
pub struct Mechanism {
|
|
||||||
#[serde(rename = "$text")]
|
|
||||||
pub mechanism: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Debug)]
|
|
||||||
#[serde(rename = "auth")]
|
|
||||||
pub struct Auth {
|
pub struct Auth {
|
||||||
#[serde(rename = "@xmlns")]
|
|
||||||
pub ns: String,
|
|
||||||
#[serde(rename = "@mechanism")]
|
|
||||||
pub mechanism: String,
|
pub mechanism: String,
|
||||||
#[serde(rename = "$text")]
|
|
||||||
pub sasl_data: Option<String>,
|
pub sasl_data: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
|
||||||
pub struct Challenge {
|
pub struct Challenge {
|
||||||
#[serde(rename = "@xmlns")]
|
|
||||||
pub ns: String,
|
|
||||||
#[serde(rename = "$text")]
|
|
||||||
pub sasl_data: String,
|
pub sasl_data: String,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,41 +1,182 @@
|
||||||
use serde::{Deserialize, Serialize};
|
use std::str;
|
||||||
|
|
||||||
use super::sasl::Mechanisms;
|
use quick_xml::{
|
||||||
|
events::{BytesStart, Event},
|
||||||
|
name::QName,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
use crate::{element::Element, JabberError, Result, JID};
|
||||||
#[serde(rename = "stream:stream")]
|
|
||||||
struct Stream {
|
const XMLNS_STREAM: &str = "http://etherx.jabber.org/streams";
|
||||||
#[serde(rename = "@from")]
|
const VERSION: &str = "1.0";
|
||||||
from: Option<String>,
|
|
||||||
#[serde(rename = "@id")]
|
enum XMLNS {
|
||||||
|
Client,
|
||||||
|
Server,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<XMLNS> for &str {
|
||||||
|
fn from(xmlns: XMLNS) -> Self {
|
||||||
|
match xmlns {
|
||||||
|
XMLNS::Client => return "jabber:client",
|
||||||
|
XMLNS::Server => return "jabber:server",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryInto<XMLNS> for &str {
|
||||||
|
type Error = JabberError;
|
||||||
|
|
||||||
|
fn try_into(self) -> Result<XMLNS> {
|
||||||
|
match self {
|
||||||
|
"jabber:client" => Ok(XMLNS::Client),
|
||||||
|
"jabber:server" => Ok(XMLNS::Server),
|
||||||
|
_ => Err(JabberError::UnknownNamespace),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Stream {
|
||||||
|
from: Option<JID>,
|
||||||
id: Option<String>,
|
id: Option<String>,
|
||||||
#[serde(rename = "@to")]
|
to: Option<JID>,
|
||||||
to: Option<String>,
|
version: Option<String>,
|
||||||
#[serde(rename = "@version")]
|
|
||||||
version: Option<f32>,
|
|
||||||
#[serde(rename = "@xml:lang")]
|
|
||||||
lang: Option<String>,
|
lang: Option<String>,
|
||||||
#[serde(rename = "@xmlns")]
|
_ns: XMLNS,
|
||||||
namespace: Option<String>,
|
|
||||||
#[serde(rename = "@xmlns:stream")]
|
|
||||||
stream_namespace: Option<String>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
impl Stream {
|
||||||
#[serde(rename = "stream:features")]
|
pub fn new_client(from: &JID, to: &JID, id: Option<String>, lang: Option<String>) -> Self {
|
||||||
pub struct StreamFeatures {
|
Self {
|
||||||
#[serde(rename = "$value")]
|
from: Some(from.clone()),
|
||||||
pub features: Vec<StreamFeature>,
|
id,
|
||||||
|
to: Some(to.clone()),
|
||||||
|
version: Some(VERSION.to_owned()),
|
||||||
|
lang,
|
||||||
|
_ns: XMLNS::Client,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build(&self) -> BytesStart {
|
||||||
|
let mut start = BytesStart::new("stream:stream");
|
||||||
|
if let Some(from) = &self.from {
|
||||||
|
start.push_attribute(("from", from.to_string().as_str()));
|
||||||
|
}
|
||||||
|
if let Some(id) = &self.id {
|
||||||
|
start.push_attribute(("id", id.as_str()));
|
||||||
|
}
|
||||||
|
if let Some(to) = &self.to {
|
||||||
|
start.push_attribute(("to", to.to_string().as_str()));
|
||||||
|
}
|
||||||
|
if let Some(version) = &self.version {
|
||||||
|
start.push_attribute(("version", version.to_string().as_str()));
|
||||||
|
}
|
||||||
|
if let Some(lang) = &self.lang {
|
||||||
|
start.push_attribute(("xml:lang", lang.as_str()));
|
||||||
|
}
|
||||||
|
start.push_attribute(("xmlns", XMLNS::Client.into()));
|
||||||
|
start.push_attribute(("xmlns:stream", XMLNS_STREAM));
|
||||||
|
start
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, PartialEq, Debug)]
|
impl<'e> Into<Element<'e>> for Stream {
|
||||||
|
fn into(self) -> Element<'e> {
|
||||||
|
Element {
|
||||||
|
event: Event::Start(self.build().to_owned()),
|
||||||
|
content: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'e> TryFrom<Element<'e>> for Stream {
|
||||||
|
type Error = JabberError;
|
||||||
|
|
||||||
|
fn try_from(value: Element<'e>) -> Result<Stream> {
|
||||||
|
let (mut from, mut id, mut to, mut version, mut lang, mut ns) =
|
||||||
|
(None, None, None, None, None, XMLNS::Client);
|
||||||
|
if let Event::Start(e) = value.event.as_ref() {
|
||||||
|
for attribute in e.attributes() {
|
||||||
|
let attribute = attribute?;
|
||||||
|
match attribute.key {
|
||||||
|
QName(b"from") => {
|
||||||
|
from = Some(str::from_utf8(&attribute.value)?.to_string().try_into()?);
|
||||||
|
}
|
||||||
|
QName(b"id") => {
|
||||||
|
id = Some(str::from_utf8(&attribute.value)?.to_owned());
|
||||||
|
}
|
||||||
|
QName(b"to") => {
|
||||||
|
to = Some(str::from_utf8(&attribute.value)?.to_string().try_into()?);
|
||||||
|
}
|
||||||
|
QName(b"version") => {
|
||||||
|
version = Some(str::from_utf8(&attribute.value)?.to_owned());
|
||||||
|
}
|
||||||
|
QName(b"lang") => {
|
||||||
|
lang = Some(str::from_utf8(&attribute.value)?.to_owned());
|
||||||
|
}
|
||||||
|
QName(b"xmlns") => {
|
||||||
|
ns = str::from_utf8(&attribute.value)?.try_into()?;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
println!("unknown attribute: {:?}", attribute)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(Stream {
|
||||||
|
from,
|
||||||
|
id,
|
||||||
|
to,
|
||||||
|
version,
|
||||||
|
lang,
|
||||||
|
_ns: ns,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Err(JabberError::ParseError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Debug)]
|
||||||
pub enum StreamFeature {
|
pub enum StreamFeature {
|
||||||
#[serde(rename = "starttls")]
|
|
||||||
StartTls,
|
StartTls,
|
||||||
// TODO: other stream features
|
Sasl(Vec<String>),
|
||||||
#[serde(rename = "mechanisms")]
|
|
||||||
Sasl(Mechanisms),
|
|
||||||
Bind,
|
Bind,
|
||||||
#[serde(other)]
|
|
||||||
Unknown,
|
Unknown,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'e> TryFrom<Element<'e>> for Vec<StreamFeature> {
|
||||||
|
type Error = JabberError;
|
||||||
|
|
||||||
|
fn try_from(features_element: Element) -> Result<Self> {
|
||||||
|
let mut features = Vec::new();
|
||||||
|
if let Some(content) = features_element.content {
|
||||||
|
for feature_element in content {
|
||||||
|
match feature_element.event {
|
||||||
|
Event::Start(e) => match e.name() {
|
||||||
|
QName(b"starttls") => features.push(StreamFeature::StartTls),
|
||||||
|
QName(b"mechanisms") => {
|
||||||
|
let mut mechanisms = Vec::new();
|
||||||
|
if let Some(content) = feature_element.content {
|
||||||
|
for mechanism_element in content {
|
||||||
|
if let Some(content) = mechanism_element.content {
|
||||||
|
for mechanism_text in content {
|
||||||
|
match mechanism_text.event {
|
||||||
|
Event::Text(e) => mechanisms
|
||||||
|
.push(str::from_utf8(e.as_ref())?.to_owned()),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
features.push(StreamFeature::Sasl(mechanisms))
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
},
|
||||||
|
_ => features.push(StreamFeature::Unknown),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(features)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue