xmpp-parsers: Migrate Caps to xso
The hash member has been split into a hash and a ver members, to reflect the attributes.
This commit is contained in:
parent
01a0c51a2f
commit
c0e45b6a0f
2 changed files with 27 additions and 45 deletions
|
|
@ -39,6 +39,8 @@ XXXX-YY-ZZ RELEASER <admin@example.com>
|
||||||
- message::Message id field is now Option<message::Id> instead of
|
- message::Message id field is now Option<message::Id> instead of
|
||||||
Option<String> (!504)
|
Option<String> (!504)
|
||||||
- message_correction::Replace id field is now Id instead of String (!504)
|
- message_correction::Replace id field is now Id instead of String (!504)
|
||||||
|
- `Caps::hash` has been split into `Caps::hash` (the algo) and
|
||||||
|
`Caps::ver` (the actual hash), to reflect the attributes (!517)
|
||||||
* New parsers/serialisers:
|
* New parsers/serialisers:
|
||||||
- Stream Features (RFC 6120) (!400)
|
- Stream Features (RFC 6120) (!400)
|
||||||
- Spam Reporting (XEP-0377) (!506)
|
- Spam Reporting (XEP-0377) (!506)
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@
|
||||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
// 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/.
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
use xso::{AsXml, FromXml};
|
||||||
|
|
||||||
use crate::data_forms::DataForm;
|
use crate::data_forms::DataForm;
|
||||||
use crate::disco::{DiscoInfoQuery, DiscoInfoResult, Feature, Identity};
|
use crate::disco::{DiscoInfoQuery, DiscoInfoResult, Feature, Identity};
|
||||||
use crate::hashes::{Algo, Hash};
|
use crate::hashes::{Algo, Hash};
|
||||||
|
|
@ -12,70 +14,46 @@ use crate::presence::PresencePayload;
|
||||||
use base64::{engine::general_purpose::STANDARD as Base64, Engine};
|
use base64::{engine::general_purpose::STANDARD as Base64, Engine};
|
||||||
use blake2::Blake2bVar;
|
use blake2::Blake2bVar;
|
||||||
use digest::{Digest, Update, VariableOutput};
|
use digest::{Digest, Update, VariableOutput};
|
||||||
use minidom::Element;
|
|
||||||
use sha1::Sha1;
|
use sha1::Sha1;
|
||||||
use sha2::{Sha256, Sha512};
|
use sha2::{Sha256, Sha512};
|
||||||
use sha3::{Sha3_256, Sha3_512};
|
use sha3::{Sha3_256, Sha3_512};
|
||||||
use xso::error::{Error, FromElementError};
|
|
||||||
|
|
||||||
/// Represents a capability hash for a given client.
|
/// Represents a capability hash for a given client.
|
||||||
#[derive(Debug, Clone)]
|
///
|
||||||
|
/// Warning: This protocol is insecure, you may want to switch to
|
||||||
|
/// [ecaps2](../ecaps2/index.html) instead, see [this
|
||||||
|
/// email](https://mail.jabber.org/pipermail/security/2009-July/000812.html).
|
||||||
|
#[derive(FromXml, AsXml, Debug, Clone)]
|
||||||
|
#[xml(namespace = ns::CAPS, name = "c")]
|
||||||
pub struct Caps {
|
pub struct Caps {
|
||||||
/// Deprecated list of additional feature bundles.
|
/// Deprecated list of additional feature bundles.
|
||||||
|
#[xml(attribute(default))]
|
||||||
pub ext: Option<String>,
|
pub ext: Option<String>,
|
||||||
|
|
||||||
/// A URI identifying an XMPP application.
|
/// A URI identifying an XMPP application.
|
||||||
|
#[xml(attribute)]
|
||||||
pub node: String,
|
pub node: String,
|
||||||
|
|
||||||
|
/// The algorithm of the hash of these caps.
|
||||||
|
#[xml(attribute)]
|
||||||
|
pub hash: Algo,
|
||||||
|
|
||||||
/// The hash of that application’s
|
/// The hash of that application’s
|
||||||
/// [disco#info](../disco/struct.DiscoInfoResult.html).
|
/// [disco#info](../disco/struct.DiscoInfoResult.html).
|
||||||
///
|
#[xml(attribute(codec = Base64))]
|
||||||
/// Warning: This protocol is insecure, you may want to switch to
|
pub ver: Vec<u8>,
|
||||||
/// [ecaps2](../ecaps2/index.html) instead, see [this
|
|
||||||
/// email](https://mail.jabber.org/pipermail/security/2009-July/000812.html).
|
|
||||||
pub hash: Hash,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PresencePayload for Caps {}
|
impl PresencePayload for Caps {}
|
||||||
|
|
||||||
impl TryFrom<Element> for Caps {
|
|
||||||
type Error = FromElementError;
|
|
||||||
|
|
||||||
fn try_from(elem: Element) -> Result<Caps, FromElementError> {
|
|
||||||
check_self!(elem, "c", CAPS, "caps");
|
|
||||||
check_no_children!(elem, "caps");
|
|
||||||
check_no_unknown_attributes!(elem, "caps", ["hash", "ver", "ext", "node"]);
|
|
||||||
let ver: String = get_attr!(elem, "ver", Required);
|
|
||||||
let hash = Hash {
|
|
||||||
algo: get_attr!(elem, "hash", Required),
|
|
||||||
hash: Base64.decode(ver).map_err(Error::text_parse_error)?,
|
|
||||||
};
|
|
||||||
Ok(Caps {
|
|
||||||
ext: get_attr!(elem, "ext", Option),
|
|
||||||
node: get_attr!(elem, "node", Required),
|
|
||||||
hash,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Caps> for Element {
|
|
||||||
fn from(caps: Caps) -> Element {
|
|
||||||
Element::builder("c", ns::CAPS)
|
|
||||||
.attr("ext", caps.ext)
|
|
||||||
.attr("hash", caps.hash.algo)
|
|
||||||
.attr("node", caps.node)
|
|
||||||
.attr("ver", Base64.encode(&caps.hash.hash))
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Caps {
|
impl Caps {
|
||||||
/// Create a Caps element from its node and hash.
|
/// Create a Caps element from its node and hash.
|
||||||
pub fn new<N: Into<String>>(node: N, hash: Hash) -> Caps {
|
pub fn new<N: Into<String>>(node: N, hash: Hash) -> Caps {
|
||||||
Caps {
|
Caps {
|
||||||
ext: None,
|
ext: None,
|
||||||
node: node.into(),
|
node: node.into(),
|
||||||
hash,
|
hash: hash.algo,
|
||||||
|
ver: hash.hash,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -207,7 +185,7 @@ pub fn hash_caps(data: &[u8], algo: Algo) -> Result<Hash, String> {
|
||||||
/// caps hash.
|
/// caps hash.
|
||||||
pub fn query_caps(caps: Caps) -> DiscoInfoQuery {
|
pub fn query_caps(caps: Caps) -> DiscoInfoQuery {
|
||||||
DiscoInfoQuery {
|
DiscoInfoQuery {
|
||||||
node: Some(format!("{}#{}", caps.node, Base64.encode(&caps.hash.hash))),
|
node: Some(format!("{}#{}", caps.node, Base64.encode(&caps.ver))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -215,6 +193,8 @@ pub fn query_caps(caps: Caps) -> DiscoInfoQuery {
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::caps;
|
use crate::caps;
|
||||||
|
use minidom::Element;
|
||||||
|
use xso::error::{Error, FromElementError};
|
||||||
|
|
||||||
#[cfg(target_pointer_width = "32")]
|
#[cfg(target_pointer_width = "32")]
|
||||||
#[test]
|
#[test]
|
||||||
|
|
@ -233,9 +213,9 @@ mod tests {
|
||||||
let elem: Element = "<c xmlns='http://jabber.org/protocol/caps' hash='sha-256' node='coucou' ver='K1Njy3HZBThlo4moOD5gBGhn0U0oK7/CbfLlIUDi6o4='/>".parse().unwrap();
|
let elem: Element = "<c xmlns='http://jabber.org/protocol/caps' hash='sha-256' node='coucou' ver='K1Njy3HZBThlo4moOD5gBGhn0U0oK7/CbfLlIUDi6o4='/>".parse().unwrap();
|
||||||
let caps = Caps::try_from(elem).unwrap();
|
let caps = Caps::try_from(elem).unwrap();
|
||||||
assert_eq!(caps.node, String::from("coucou"));
|
assert_eq!(caps.node, String::from("coucou"));
|
||||||
assert_eq!(caps.hash.algo, Algo::Sha_256);
|
assert_eq!(caps.hash, Algo::Sha_256);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
caps.hash.hash,
|
caps.ver,
|
||||||
Base64
|
Base64
|
||||||
.decode("K1Njy3HZBThlo4moOD5gBGhn0U0oK7/CbfLlIUDi6o4=")
|
.decode("K1Njy3HZBThlo4moOD5gBGhn0U0oK7/CbfLlIUDi6o4=")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
|
@ -245,13 +225,13 @@ mod tests {
|
||||||
#[cfg(not(feature = "disable-validation"))]
|
#[cfg(not(feature = "disable-validation"))]
|
||||||
#[test]
|
#[test]
|
||||||
fn test_invalid_child() {
|
fn test_invalid_child() {
|
||||||
let elem: Element = "<c xmlns='http://jabber.org/protocol/caps'><hash xmlns='urn:xmpp:hashes:2' algo='sha-256'>K1Njy3HZBThlo4moOD5gBGhn0U0oK7/CbfLlIUDi6o4=</hash></c>".parse().unwrap();
|
let elem: Element = "<c xmlns='http://jabber.org/protocol/caps' node='coucou' hash='sha-256' ver='K1Njy3HZBThlo4moOD5gBGhn0U0oK7/CbfLlIUDi6o4='><hash xmlns='urn:xmpp:hashes:2' algo='sha-256'>K1Njy3HZBThlo4moOD5gBGhn0U0oK7/CbfLlIUDi6o4=</hash></c>".parse().unwrap();
|
||||||
let error = Caps::try_from(elem).unwrap_err();
|
let error = Caps::try_from(elem).unwrap_err();
|
||||||
let message = match error {
|
let message = match error {
|
||||||
FromElementError::Invalid(Error::Other(string)) => string,
|
FromElementError::Invalid(Error::Other(string)) => string,
|
||||||
_ => panic!(),
|
_ => panic!(),
|
||||||
};
|
};
|
||||||
assert_eq!(message, "Unknown child in caps element.");
|
assert_eq!(message, "Unknown child in Caps element.");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue