diff options
| author | 2024-11-24 02:04:45 +0000 | |
|---|---|---|
| committer | 2024-11-24 02:04:45 +0000 | |
| commit | 35f164cdb6324c6dfb635f8de93a8221861a5991 (patch) | |
| tree | f858e55999007046e511acce17b9e35bc1585ba4 /src/stanza | |
| parent | 40024d2dadba9e70edb2f3448204565ce3f68ab7 (diff) | |
| download | luz-35f164cdb6324c6dfb635f8de93a8221861a5991.tar.gz luz-35f164cdb6324c6dfb635f8de93a8221861a5991.tar.bz2 luz-35f164cdb6324c6dfb635f8de93a8221861a5991.zip | |
implement starttls
Diffstat (limited to '')
| -rw-r--r-- | src/stanza/starttls.rs | 162 | ||||
| -rw-r--r-- | src/stanza/stream.rs | 73 | 
2 files changed, 234 insertions, 1 deletions
| diff --git a/src/stanza/starttls.rs b/src/stanza/starttls.rs index 8b13789..874ae66 100644 --- a/src/stanza/starttls.rs +++ b/src/stanza/starttls.rs @@ -1 +1,163 @@ +use std::collections::{HashMap, HashSet}; +use peanuts::{ +    element::{Content, FromElement, IntoElement, Name, NamespaceDeclaration}, +    Element, +}; + +pub const XMLNS: &str = "urn:ietf:params:xml:ns:xmpp-tls"; + +#[derive(Debug)] +pub struct StartTls { +    pub required: bool, +} + +impl IntoElement for StartTls { +    fn into_element(&self) -> peanuts::Element { +        let content; +        if self.required == true { +            let element = Content::Element(Element { +                name: Name { +                    namespace: Some(XMLNS.to_string()), +                    local_name: "required".to_string(), +                }, +                namespace_declarations: HashSet::new(), +                attributes: HashMap::new(), +                content: Vec::new(), +            }); +            content = vec![element]; +        } else { +            content = Vec::new(); +        } +        let mut namespace_declarations = HashSet::new(); +        namespace_declarations.insert(NamespaceDeclaration { +            prefix: None, +            namespace: XMLNS.to_string(), +        }); +        Element { +            name: Name { +                namespace: Some(XMLNS.to_string()), +                local_name: "starttls".to_string(), +            }, +            namespace_declarations, +            attributes: HashMap::new(), +            content, +        } +    } +} + +impl FromElement for StartTls { +    fn from_element(element: peanuts::Element) -> peanuts::Result<Self> { +        let Name { +            namespace, +            local_name, +        } = element.name; +        if namespace.as_deref() == Some(XMLNS) && &local_name == "starttls" { +            let mut required = false; +            if element.content.len() == 1 { +                match element.content.first().unwrap() { +                    Content::Element(element) => { +                        let Name { +                            namespace, +                            local_name, +                        } = &element.name; + +                        if namespace.as_deref() == Some(XMLNS) && local_name == "required" { +                            required = true +                        } else { +                            return Err(peanuts::Error::UnexpectedElement(element.name.clone())); +                        } +                    } +                    c => return Err(peanuts::Error::UnexpectedContent((*c).clone())), +                } +            } else { +                return Err(peanuts::Error::UnexpectedNumberOfContents( +                    element.content.len(), +                )); +            } +            return Ok(StartTls { required }); +        } else { +            return Err(peanuts::Error::IncorrectName(Name { +                namespace, +                local_name, +            })); +        } +    } +} + +#[derive(Debug)] +pub struct Proceed; + +impl IntoElement for Proceed { +    fn into_element(&self) -> Element { +        let mut namespace_declarations = HashSet::new(); +        namespace_declarations.insert(NamespaceDeclaration { +            prefix: None, +            namespace: XMLNS.to_string(), +        }); +        Element { +            name: Name { +                namespace: Some(XMLNS.to_string()), +                local_name: "proceed".to_string(), +            }, +            namespace_declarations, +            attributes: HashMap::new(), +            content: Vec::new(), +        } +    } +} + +impl FromElement for Proceed { +    fn from_element(element: Element) -> peanuts::Result<Self> { +        let Name { +            namespace, +            local_name, +        } = element.name; +        if namespace.as_deref() == Some(XMLNS) && &local_name == "proceed" { +            return Ok(Proceed); +        } else { +            return Err(peanuts::Error::IncorrectName(Name { +                namespace, +                local_name, +            })); +        } +    } +} + +pub struct Failure; + +impl IntoElement for Failure { +    fn into_element(&self) -> Element { +        let mut namespace_declarations = HashSet::new(); +        namespace_declarations.insert(NamespaceDeclaration { +            prefix: None, +            namespace: XMLNS.to_string(), +        }); +        Element { +            name: Name { +                namespace: Some(XMLNS.to_string()), +                local_name: "failure".to_string(), +            }, +            namespace_declarations, +            attributes: HashMap::new(), +            content: Vec::new(), +        } +    } +} + +impl FromElement for Failure { +    fn from_element(element: Element) -> peanuts::Result<Self> { +        let Name { +            namespace, +            local_name, +        } = element.name; +        if namespace.as_deref() == Some(XMLNS) && &local_name == "failure" { +            return Ok(Failure); +        } else { +            return Err(peanuts::Error::IncorrectName(Name { +                namespace, +                local_name, +            })); +        } +    } +} diff --git a/src/stanza/stream.rs b/src/stanza/stream.rs index ac4badc..4516682 100644 --- a/src/stanza/stream.rs +++ b/src/stanza/stream.rs @@ -6,12 +6,15 @@ use peanuts::{element::Name, Element};  use crate::{Error, JID}; +use super::starttls::StartTls; +  pub const XMLNS: &str = "http://etherx.jabber.org/streams";  pub const XMLNS_CLIENT: &str = "jabber:client";  // MUST be qualified by stream namespace  // #[derive(XmlSerialize, XmlDeserialize)]  // #[peanuts(xmlns = XMLNS)] +#[derive(Debug)]  pub struct Stream {      pub from: Option<JID>,      to: Option<JID>, @@ -93,7 +96,7 @@ impl IntoElement for Stream {              attributes.insert(                  Name {                      namespace: None, -                    local_name: "version".to_string(), +                    local_name: "id".to_string(),                  },                  id.clone(),              ); @@ -158,3 +161,71 @@ impl<'s> Stream {          }      }  } + +#[derive(Debug)] +pub struct Features { +    features: Vec<Feature>, +} + +impl IntoElement for Features { +    fn into_element(&self) -> Element { +        let mut content = Vec::new(); +        for feature in &self.features { +            match feature { +                Feature::StartTls(start_tls) => { +                    content.push(Content::Element(start_tls.into_element())) +                } +                Feature::Sasl => {} +                Feature::Bind => {} +                Feature::Unknown => {} +            } +        } +        Element { +            name: Name { +                namespace: Some(XMLNS.to_string()), +                local_name: "features".to_string(), +            }, +            namespace_declarations: HashSet::new(), +            attributes: HashMap::new(), +            content, +        } +    } +} + +impl FromElement for Features { +    fn from_element(element: Element) -> peanuts::Result<Self> { +        let Name { +            namespace, +            local_name, +        } = element.name; +        if namespace.as_deref() == Some(XMLNS) && &local_name == "features" { +            let mut features = Vec::new(); +            for feature in element.content { +                match feature { +                    Content::Element(element) => { +                        if let Ok(start_tls) = FromElement::from_element(element) { +                            features.push(Feature::StartTls(start_tls)) +                        } else { +                            features.push(Feature::Unknown) +                        } +                    } +                    c => return Err(peanuts::Error::UnexpectedContent(c.clone())), +                } +            } +            return Ok(Self { features }); +        } else { +            return Err(peanuts::Error::IncorrectName(Name { +                namespace, +                local_name, +            })); +        } +    } +} + +#[derive(Debug)] +pub enum Feature { +    StartTls(StartTls), +    Sasl, +    Bind, +    Unknown, +} | 
