aboutsummaryrefslogtreecommitdiffstats
path: root/stanza/src/sasl.rs
diff options
context:
space:
mode:
Diffstat (limited to 'stanza/src/sasl.rs')
-rw-r--r--stanza/src/sasl.rs240
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 })
+ }
+}