tokio_xmpp/component/
login.rs

1use std::io;
2
3use futures::{SinkExt, StreamExt};
4use tokio::io::{AsyncBufRead, AsyncWrite};
5use xmpp_parsers::{component::Handshake, jid::Jid, ns};
6
7use crate::component::ServerConnector;
8use crate::error::{AuthError, Error};
9use crate::xmlstream::{ReadError, Timeouts, XmppStream, XmppStreamElement};
10
11/// Log into an XMPP server as a client with a jid+pass
12pub async fn component_login<C: ServerConnector>(
13    connector: C,
14    jid: Jid,
15    password: &str,
16    timeouts: Timeouts,
17) -> Result<XmppStream<C::Stream>, Error> {
18    let (mut stream, _) = connector.connect(&jid, ns::COMPONENT, timeouts).await?;
19    let header = stream.take_header();
20    let mut stream = stream.skip_features();
21    let stream_id = match header.id {
22        Some(id) => id.into_owned(),
23        None => {
24            return Err(io::Error::new(
25                io::ErrorKind::InvalidData,
26                "stream id missing on component stream",
27            )
28            .into())
29        }
30    };
31    auth(&mut stream, stream_id, password).await?;
32    Ok(stream)
33}
34
35pub async fn auth<S: AsyncBufRead + AsyncWrite + Unpin>(
36    stream: &mut XmppStream<S>,
37    stream_id: String,
38    password: &str,
39) -> Result<(), Error> {
40    let nonza = Handshake::from_stream_id_and_password(stream_id, password);
41    stream
42        .send(&XmppStreamElement::ComponentHandshake(nonza))
43        .await?;
44
45    loop {
46        match stream.next().await {
47            Some(Ok(XmppStreamElement::ComponentHandshake(_))) => {
48                return Ok(());
49            }
50            Some(Ok(_)) => {
51                return Err(AuthError::ComponentFail.into());
52            }
53            Some(Err(ReadError::SoftTimeout)) => (),
54            Some(Err(ReadError::HardError(e))) => return Err(e.into()),
55            Some(Err(ReadError::ParseError(e))) => {
56                return Err(io::Error::new(io::ErrorKind::InvalidData, e).into())
57            }
58            Some(Err(ReadError::StreamFooterReceived)) | None => return Err(Error::Disconnected),
59        }
60    }
61}