auth.rs

  1use std::mem::replace;
  2use futures::{Future, Poll, Async, sink, Sink, Stream};
  3use tokio_io::{AsyncRead, AsyncWrite};
  4use minidom::Element;
  5use sha1::{Sha1, Digest};
  6
  7use xmpp_codec::Packet;
  8use xmpp_stream::XMPPStream;
  9
 10const NS_JABBER_COMPONENT_ACCEPT: &str = "jabber:component:accept";
 11
 12pub struct ComponentAuth<S: AsyncWrite> {
 13    state: ComponentAuthState<S>,
 14}
 15
 16enum ComponentAuthState<S: AsyncWrite> {
 17    WaitSend(sink::Send<XMPPStream<S>>),
 18    WaitRecv(XMPPStream<S>),
 19    Invalid,
 20}
 21
 22impl<S: AsyncWrite> ComponentAuth<S> {
 23    pub fn new(stream: XMPPStream<S>, password: String) -> Result<Self, String> {
 24        // FIXME: huge hack, shouldn’t be an element!
 25        let sid = stream.stream_features.name().to_owned();
 26        let mut this = ComponentAuth {
 27            state: ComponentAuthState::Invalid,
 28        };
 29        this.send(
 30            stream,
 31            "handshake",
 32            // TODO: sha1(sid + password)
 33            &format!("{:x}", Sha1::digest((sid + &password).as_bytes()))
 34        );
 35        return Ok(this);
 36    }
 37
 38    fn send(&mut self, stream: XMPPStream<S>, nonza_name: &str, handshake: &str) {
 39        let nonza = Element::builder(nonza_name)
 40            .ns(NS_JABBER_COMPONENT_ACCEPT)
 41            .append(handshake)
 42            .build();
 43
 44        let send = stream.send(Packet::Stanza(nonza));
 45
 46        self.state = ComponentAuthState::WaitSend(send);
 47    }
 48}
 49
 50impl<S: AsyncRead + AsyncWrite> Future for ComponentAuth<S> {
 51    type Item = XMPPStream<S>;
 52    type Error = String;
 53
 54    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
 55        let state = replace(&mut self.state, ComponentAuthState::Invalid);
 56
 57        match state {
 58            ComponentAuthState::WaitSend(mut send) =>
 59                match send.poll() {
 60                    Ok(Async::Ready(stream)) => {
 61                        self.state = ComponentAuthState::WaitRecv(stream);
 62                        self.poll()
 63                    },
 64                    Ok(Async::NotReady) => {
 65                        self.state = ComponentAuthState::WaitSend(send);
 66                        Ok(Async::NotReady)
 67                    },
 68                    Err(e) =>
 69                        Err(format!("{}", e)),
 70                },
 71            ComponentAuthState::WaitRecv(mut stream) =>
 72                match stream.poll() {
 73                    Ok(Async::Ready(Some(Packet::Stanza(ref stanza))))
 74                        if stanza.is("handshake", NS_JABBER_COMPONENT_ACCEPT) =>
 75                    {
 76                        self.state = ComponentAuthState::Invalid;
 77                        Ok(Async::Ready(stream))
 78                    },
 79                    Ok(Async::Ready(Some(Packet::Stanza(ref stanza))))
 80                        if stanza.is("error", "http://etherx.jabber.org/streams") =>
 81                    {
 82                        let e = "Authentication failure";
 83                        Err(e.to_owned())
 84                    },
 85                    Ok(Async::Ready(event)) => {
 86                        println!("ComponentAuth ignore {:?}", event);
 87                        Ok(Async::NotReady)
 88                    },
 89                    Ok(_) => {
 90                        self.state = ComponentAuthState::WaitRecv(stream);
 91                        Ok(Async::NotReady)
 92                    },
 93                    Err(e) =>
 94                        Err(format!("{}", e)),
 95                },
 96            ComponentAuthState::Invalid =>
 97                unreachable!(),
 98        }
 99    }
100}