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 }) + } +} |