// Copyright (c) 2019 Emmanuel Gil Peyrot // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. use xso::{FromXml, IntoXml}; use crate::iq::{IqGetPayload, IqResultPayload, IqSetPayload}; use crate::ns; use crate::util::text_node_codecs::{Base64, Codec}; generate_elem_id!( /// The name of a certificate. Name, "name", SASL_CERT ); generate_element!( /// An X.509 certificate. Cert, "x509cert", SASL_CERT, text: ( /// The BER X.509 data. data: Base64 ) ); generate_element!( /// For the client to upload an X.509 certificate. Append, "append", SASL_CERT, children: [ /// The name of this certificate. name: Required = ("name", SASL_CERT) => Name, /// The X.509 certificate to set. cert: Required = ("x509cert", SASL_CERT) => Cert, /// This client is forbidden from managing certificates. no_cert_management: Present<_> = ("no-cert-management", SASL_CERT) => bool ] ); impl IqSetPayload for Append {} /// Client requests the current list of X.509 certificates. #[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::SASL_CERT, name = "items")] pub struct ListCertsQuery; impl IqGetPayload for ListCertsQuery {} generate_elem_id!( /// One resource currently using a certificate. Resource, "resource", SASL_CERT ); generate_element!( /// A list of resources currently using this certificate. Users, "users", SASL_CERT, children: [ /// Resources currently using this certificate. resources: Vec = ("resource", SASL_CERT) => Resource ] ); generate_element!( /// An X.509 certificate being set for this user. Item, "item", SASL_CERT, children: [ /// The name of this certificate. name: Required = ("name", SASL_CERT) => Name, /// The X.509 certificate to set. cert: Required = ("x509cert", SASL_CERT) => Cert, /// This client is forbidden from managing certificates. no_cert_management: Present<_> = ("no-cert-management", SASL_CERT) => bool, /// List of resources currently using this certificate. users: Option = ("users", SASL_CERT) => Users ] ); generate_element!( /// Server answers with the current list of X.509 certificates. ListCertsResponse, "items", SASL_CERT, children: [ /// List of certificates. items: Vec = ("item", SASL_CERT) => Item ] ); impl IqResultPayload for ListCertsResponse {} generate_element!( /// Client disables an X.509 certificate. Disable, "disable", SASL_CERT, children: [ /// Name of the certificate to disable. name: Required = ("name", SASL_CERT) => Name ] ); impl IqSetPayload for Disable {} generate_element!( /// Client revokes an X.509 certificate. Revoke, "revoke", SASL_CERT, children: [ /// Name of the certificate to revoke. name: Required = ("name", SASL_CERT) => Name ] ); impl IqSetPayload for Revoke {} #[cfg(test)] mod tests { use super::*; use crate::ns; use crate::Element; use std::str::FromStr; #[cfg(target_pointer_width = "32")] #[test] fn test_size() { assert_size!(Append, 28); assert_size!(Disable, 12); assert_size!(Revoke, 12); assert_size!(ListCertsQuery, 0); assert_size!(ListCertsResponse, 12); assert_size!(Item, 40); assert_size!(Resource, 12); assert_size!(Users, 12); assert_size!(Cert, 12); } #[cfg(target_pointer_width = "64")] #[test] fn test_size() { assert_size!(Append, 56); assert_size!(Disable, 24); assert_size!(Revoke, 24); assert_size!(ListCertsQuery, 0); assert_size!(ListCertsResponse, 24); assert_size!(Item, 80); assert_size!(Resource, 24); assert_size!(Users, 24); assert_size!(Cert, 24); } #[test] fn simple() { let elem: Element = "Mobile ClientAAAA".parse().unwrap(); let append = Append::try_from(elem).unwrap(); assert_eq!(append.name.0, "Mobile Client"); assert_eq!(append.cert.data, b"\0\0\0"); let elem: Element = "Mobile Client" .parse() .unwrap(); let disable = Disable::try_from(elem).unwrap(); assert_eq!(disable.name.0, "Mobile Client"); let elem: Element = "Mobile Client" .parse() .unwrap(); let revoke = Revoke::try_from(elem).unwrap(); assert_eq!(revoke.name.0, "Mobile Client"); } #[test] fn list() { let elem: Element = r#" Mobile Client AAAA Phone Laptop BBBB "# .parse() .unwrap(); let mut list = ListCertsResponse::try_from(elem).unwrap(); assert_eq!(list.items.len(), 2); let item = list.items.pop().unwrap(); assert_eq!(item.name.0, "Laptop"); assert_eq!(item.cert.data, [4, 16, 65]); assert!(item.users.is_none()); let item = list.items.pop().unwrap(); assert_eq!(item.name.0, "Mobile Client"); assert_eq!(item.cert.data, b"\0\0\0"); assert_eq!(item.users.unwrap().resources.len(), 1); } #[test] fn test_serialise() { let append = Append { name: Name::from_str("Mobile Client").unwrap(), cert: Cert { data: b"\0\0\0".to_vec(), }, no_cert_management: false, }; let elem: Element = append.into(); assert!(elem.is("append", ns::SASL_CERT)); let disable = Disable { name: Name::from_str("Mobile Client").unwrap(), }; let elem: Element = disable.into(); assert!(elem.is("disable", ns::SASL_CERT)); let elem = elem.children().cloned().collect::>().pop().unwrap(); assert!(elem.is("name", ns::SASL_CERT)); assert_eq!(elem.text(), "Mobile Client"); } #[test] fn test_serialize_item() { let reference: Element = "Mobile ClientAAAA" .parse() .unwrap(); let item = Item { name: Name::from_str("Mobile Client").unwrap(), cert: Cert { data: b"\0\0\0".to_vec(), }, no_cert_management: false, users: None, }; let serialized: Element = item.into(); assert_eq!(serialized, reference); } #[test] fn test_serialize_append() { let reference: Element = "Mobile ClientAAAA" .parse() .unwrap(); let append = Append { name: Name::from_str("Mobile Client").unwrap(), cert: Cert { data: b"\0\0\0".to_vec(), }, no_cert_management: false, }; let serialized: Element = append.into(); assert_eq!(serialized, reference); } #[test] fn test_serialize_disable() { let reference: Element = "Mobile Client" .parse() .unwrap(); let disable = Disable { name: Name::from_str("Mobile Client").unwrap(), }; let serialized: Element = disable.into(); assert_eq!(serialized, reference); } #[test] fn test_serialize_revoke() { let reference: Element = "Mobile Client" .parse() .unwrap(); let revoke = Revoke { name: Name::from_str("Mobile Client").unwrap(), }; let serialized: Element = revoke.into(); assert_eq!(serialized, reference); } }