diff options
Diffstat (limited to 'stanza/src/sasl.rs')
| -rw-r--r-- | stanza/src/sasl.rs | 240 | 
1 files changed, 240 insertions, 0 deletions
| diff --git a/stanza/src/sasl.rs b/stanza/src/sasl.rs new file mode 100644 index 0000000..0a3f06f --- /dev/null +++ b/stanza/src/sasl.rs @@ -0,0 +1,240 @@ +use std::ops::Deref; + +use peanuts::{ +    element::{FromElement, IntoElement}, +    DeserializeError, Element, +}; + +pub const XMLNS: &str = "urn:ietf:params:xml:ns:xmpp-sasl"; + +#[derive(Debug, Clone)] +pub struct Mechanisms { +    pub mechanisms: Vec<String>, +} + +impl FromElement for Mechanisms { +    fn from_element(mut element: Element) -> peanuts::element::DeserializeResult<Self> { +        element.check_name("mechanisms")?; +        element.check_namespace(XMLNS)?; +        let mechanisms: Vec<Mechanism> = element.pop_children()?; +        let mechanisms = mechanisms +            .into_iter() +            .map(|Mechanism(mechanism)| mechanism) +            .collect(); +        Ok(Mechanisms { mechanisms }) +    } +} + +impl IntoElement for Mechanisms { +    fn builder(&self) -> peanuts::element::ElementBuilder { +        Element::builder("mechanisms", Some(XMLNS)).push_children( +            self.mechanisms +                .iter() +                .map(|mechanism| Mechanism(mechanism.to_string())) +                .collect(), +        ) +    } +} + +pub struct Mechanism(String); + +impl FromElement for Mechanism { +    fn from_element(mut element: peanuts::Element) -> peanuts::element::DeserializeResult<Self> { +        element.check_name("mechanism")?; +        element.check_namespace(XMLNS)?; + +        let mechanism = element.pop_value()?; + +        Ok(Mechanism(mechanism)) +    } +} + +impl IntoElement for Mechanism { +    fn builder(&self) -> peanuts::element::ElementBuilder { +        Element::builder("mechanism", Some(XMLNS)).push_text(self.0.clone()) +    } +} + +impl Deref for Mechanism { +    type Target = str; + +    fn deref(&self) -> &Self::Target { +        &self.0 +    } +} + +#[derive(Debug)] +pub struct Auth { +    pub mechanism: String, +    pub sasl_data: String, +} + +impl IntoElement for Auth { +    fn builder(&self) -> peanuts::element::ElementBuilder { +        Element::builder("auth", Some(XMLNS)) +            .push_attribute("mechanism", self.mechanism.clone()) +            .push_text(self.sasl_data.clone()) +    } +} + +#[derive(Debug)] +pub struct Challenge(String); + +impl Deref for Challenge { +    type Target = str; + +    fn deref(&self) -> &Self::Target { +        &self.0 +    } +} + +impl FromElement for Challenge { +    fn from_element(mut element: Element) -> peanuts::element::DeserializeResult<Self> { +        element.check_name("challenge")?; +        element.check_namespace(XMLNS)?; + +        let sasl_data = element.value()?; + +        Ok(Challenge(sasl_data)) +    } +} + +#[derive(Debug)] +pub struct Success(Option<String>); + +impl Deref for Success { +    type Target = Option<String>; + +    fn deref(&self) -> &Self::Target { +        &self.0 +    } +} + +impl FromElement for Success { +    fn from_element(mut element: Element) -> peanuts::element::DeserializeResult<Self> { +        element.check_name("success")?; +        element.check_namespace(XMLNS)?; + +        let sasl_data = element.value_opt()?; + +        Ok(Success(sasl_data)) +    } +} + +#[derive(Debug)] +pub enum ServerResponse { +    Challenge(Challenge), +    Success(Success), +    Failure(Failure), +} + +impl FromElement for ServerResponse { +    fn from_element(element: Element) -> peanuts::element::DeserializeResult<Self> { +        match element.identify() { +            (Some(XMLNS), "challenge") => { +                Ok(ServerResponse::Challenge(Challenge::from_element(element)?)) +            } +            (Some(XMLNS), "success") => { +                Ok(ServerResponse::Success(Success::from_element(element)?)) +            } +            (Some(XMLNS), "failure") => { +                Ok(ServerResponse::Failure(Failure::from_element(element)?)) +            } +            _ => Err(DeserializeError::UnexpectedElement(element)), +        } +    } +} + +#[derive(Debug)] +pub struct Response(String); + +impl Response { +    pub fn new(response: String) -> Self { +        Self(response) +    } +} + +impl Deref for Response { +    type Target = str; + +    fn deref(&self) -> &Self::Target { +        &self.0 +    } +} + +impl IntoElement for Response { +    fn builder(&self) -> peanuts::element::ElementBuilder { +        Element::builder("response", Some(XMLNS)).push_text(self.0.clone()) +    } +} + +#[derive(Debug)] +pub struct Failure { +    r#type: Option<FailureType>, +    text: Option<Text>, +} + +impl FromElement for Failure { +    fn from_element(mut element: Element) -> peanuts::element::DeserializeResult<Self> { +        element.check_name("failure")?; +        element.check_namespace(XMLNS)?; + +        let r#type = element.pop_child_opt()?; +        let text = element.pop_child_opt()?; + +        Ok(Failure { r#type, text }) +    } +} + +#[derive(Debug)] +pub enum FailureType { +    Aborted, +    AccountDisabled, +    CredentialsExpired, +    EncryptionRequired, +    IncorrectEncoding, +    InvalidAuthzid, +    InvalidMechanism, +    MalformedRequest, +    MechanismTooWeak, +    NotAuthorized, +    TemporaryAuthFailure, +} + +impl FromElement for FailureType { +    fn from_element(element: Element) -> peanuts::element::DeserializeResult<Self> { +        match element.identify() { +            (Some(XMLNS), "aborted") => Ok(FailureType::Aborted), +            (Some(XMLNS), "account-disabled") => Ok(FailureType::AccountDisabled), +            (Some(XMLNS), "credentials-expired") => Ok(FailureType::CredentialsExpired), +            (Some(XMLNS), "encryption-required") => Ok(FailureType::EncryptionRequired), +            (Some(XMLNS), "incorrect-encoding") => Ok(FailureType::IncorrectEncoding), +            (Some(XMLNS), "invalid-authzid") => Ok(FailureType::InvalidAuthzid), +            (Some(XMLNS), "invalid-mechanism") => Ok(FailureType::InvalidMechanism), +            (Some(XMLNS), "malformed-request") => Ok(FailureType::MalformedRequest), +            (Some(XMLNS), "mechanism-too-weak") => Ok(FailureType::MechanismTooWeak), +            (Some(XMLNS), "not-authorized") => Ok(FailureType::NotAuthorized), +            (Some(XMLNS), "temporary-auth-failure") => Ok(FailureType::TemporaryAuthFailure), +            _ => Err(DeserializeError::UnexpectedElement(element)), +        } +    } +} + +#[derive(Debug)] +pub struct Text { +    lang: Option<String>, +    text: Option<String>, +} + +impl FromElement for Text { +    fn from_element(mut element: Element) -> peanuts::element::DeserializeResult<Self> { +        element.check_name("text")?; +        element.check_namespace(XMLNS)?; + +        let lang = element.attribute_opt_namespaced("lang", peanuts::XML_NS)?; + +        let text = element.pop_value_opt()?; + +        Ok(Text { lang, text }) +    } +} | 
