diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index cf5215c014f3dea2a872e706ee033404b8f4a39c..9f74e6dca4c9dc3dca4175f28c3d106d2e7cfc1a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -2,26 +2,39 @@ stages: - build - test +variables: + FEATURES: "" + rust-latest-build: stage: build image: rust:latest script: - - cargo build --verbose + - cargo build --verbose --no-default-features --features=$FEATURES rust-nightly-build: stage: build image: rustlang/rust:nightly script: - - cargo build --verbose + - cargo build --verbose --no-default-features --features=$FEATURES rust-latest-test: stage: test image: rust:latest script: - - cargo test --verbose + - cargo test --verbose --no-default-features --features=$FEATURES rust-nightly-test: stage: test image: rustlang/rust:nightly script: - - cargo test --verbose + - cargo test --verbose --no-default-features --features=$FEATURES + +"rust-latest-test with features=disable-validation": + extends: rust-latest-test + variables: + FEATURES: "disable-validation" + +"rust-nightly-test with features=disable-validation": + extends: rust-nightly-test + variables: + FEATURES: "disable-validation" diff --git a/Cargo.toml b/Cargo.toml index 2d3122cb9084fd17e1434003c591f8e2036d1454..0e3b9a36dbde483ea64a3f00074fcfd2d1a29199 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,3 +28,5 @@ try_from = "0.3.2" [features] # Build xmpp-parsers to make components instead of clients. component = [] +# Disable validation of unknown attributes. +disable-validation = [] diff --git a/src/attention.rs b/src/attention.rs index be33bb3b6f07d002163bfa2ee46d4f3a7bc6b6c3..bd4c7a15e431cc8f5548cd837b96f97abbc59968 100644 --- a/src/attention.rs +++ b/src/attention.rs @@ -18,6 +18,7 @@ impl MessagePayload for Attention {} #[cfg(test)] mod tests { use super::*; + #[cfg(not(feature = "disable-validation"))] use crate::error::Error; use minidom::Element; use try_from::TryFrom; @@ -33,6 +34,7 @@ mod tests { Attention::try_from(elem).unwrap(); } + #[cfg(not(feature = "disable-validation"))] #[test] fn test_invalid_child() { let elem: Element = "" @@ -46,6 +48,7 @@ mod tests { assert_eq!(message, "Unknown child in attention element."); } + #[cfg(not(feature = "disable-validation"))] #[test] fn test_invalid_attribute() { let elem: Element = "" diff --git a/src/bind.rs b/src/bind.rs index fe9472b2cc3c2192c959cd7c076dc87d9adc2786..9d3a894f8950c2aee20cda960de6b17acc6a4bac 100644 --- a/src/bind.rs +++ b/src/bind.rs @@ -112,6 +112,7 @@ mod tests { assert_eq!(bind, Bind::None); } + #[cfg(not(feature = "disable-validation"))] #[test] fn test_invalid_resource() { let elem: Element = "resource" diff --git a/src/blocking.rs b/src/blocking.rs index d34fee3d97a1935c5d825e7bfc836408e74885a2..53417f7f749ccebc425fceeee2da39d63b03f337 100644 --- a/src/blocking.rs +++ b/src/blocking.rs @@ -155,14 +155,6 @@ mod tests { }, ]; - let request_elem = elem.clone(); - let error = BlocklistRequest::try_from(request_elem).unwrap_err(); - let message = match error { - Error::ParseError(string) => string, - _ => panic!(), - }; - assert_eq!(message, "Unknown child in blocklist element."); - let result_elem = elem.clone(); let result = BlocklistResult::try_from(result_elem).unwrap(); assert_eq!(result.items, two_items); @@ -176,6 +168,7 @@ mod tests { assert_eq!(unblock.items, two_items); } + #[cfg(not(feature = "disable-validation"))] #[test] fn test_invalid() { let elem: Element = "" @@ -217,4 +210,16 @@ mod tests { }; assert_eq!(message, "Unknown attribute in unblock element."); } + + #[cfg(not(feature = "disable-validation"))] + #[test] + fn test_non_empty_blocklist_request() { + let elem: Element = "".parse().unwrap(); + let error = BlocklistRequest::try_from(elem).unwrap_err(); + let message = match error { + Error::ParseError(string) => string, + _ => panic!(), + }; + assert_eq!(message, "Unknown child in blocklist element."); + } } diff --git a/src/caps.rs b/src/caps.rs index 72b04263f14bfd58a51276de57be39026c63d21e..74042be31a368be7a0d5b756a7393ec0ad77a09c 100644 --- a/src/caps.rs +++ b/src/caps.rs @@ -233,6 +233,7 @@ mod tests { ); } + #[cfg(not(feature = "disable-validation"))] #[test] fn test_invalid_child() { let elem: Element = "K1Njy3HZBThlo4moOD5gBGhn0U0oK7/CbfLlIUDi6o4=".parse().unwrap(); diff --git a/src/chatstates.rs b/src/chatstates.rs index 75d64d91b1549651793e2fd2c2775f811743f64a..4eb173f11b796d1ef554f7f766638de486efef6f 100644 --- a/src/chatstates.rs +++ b/src/chatstates.rs @@ -63,6 +63,7 @@ mod tests { assert_eq!(message, "This is not a chatstate element."); } + #[cfg(not(feature = "disable-validation"))] #[test] fn test_invalid_child() { let elem: Element = "" @@ -76,6 +77,7 @@ mod tests { assert_eq!(message, "Unknown child in chatstate element."); } + #[cfg(not(feature = "disable-validation"))] #[test] fn test_invalid_attribute() { let elem: Element = "" diff --git a/src/jingle_ft.rs b/src/jingle_ft.rs index 381eb21fa288b1c37ac00ef139d4f033750b454c..32dd41f6aeb7233bc5a236796ea7bfa6fa80418f 100644 --- a/src/jingle_ft.rs +++ b/src/jingle_ft.rs @@ -510,14 +510,6 @@ mod tests { }; assert_eq!(message, "Unknown child in received element."); - let elem: Element = "".parse().unwrap(); - let error = Received::try_from(elem).unwrap_err(); - let message = match error { - Error::ParseError(string) => string, - _ => panic!(), - }; - assert_eq!(message, "Unknown attribute in received element."); - let elem: Element = "" .parse() @@ -538,6 +530,18 @@ mod tests { assert_eq!(message, "Unknown value for 'creator' attribute."); } + #[cfg(not(feature = "disable-validation"))] + #[test] + fn test_invalid_received() { + let elem: Element = "".parse().unwrap(); + let error = Received::try_from(elem).unwrap_err(); + let message = match error { + Error::ParseError(string) => string, + _ => panic!(), + }; + assert_eq!(message, "Unknown attribute in received element."); + } + #[test] fn test_checksum() { let elem: Element = "w0mcJylzCn+AfvuGdqkty2+KP48=".parse().unwrap(); @@ -575,29 +579,33 @@ mod tests { }; assert_eq!(message, "This is not a file element."); - let elem: Element = "w0mcJylzCn+AfvuGdqkty2+KP48=".parse().unwrap(); + let elem: Element = "w0mcJylzCn+AfvuGdqkty2+KP48=".parse().unwrap(); let error = Checksum::try_from(elem).unwrap_err(); let message = match error { Error::ParseError(string) => string, _ => panic!(), }; - assert_eq!(message, "Unknown attribute in checksum element."); + assert_eq!(message, "Required attribute 'name' missing."); - let elem: Element = "w0mcJylzCn+AfvuGdqkty2+KP48=".parse().unwrap(); + let elem: Element = "w0mcJylzCn+AfvuGdqkty2+KP48=".parse().unwrap(); let error = Checksum::try_from(elem).unwrap_err(); let message = match error { Error::ParseError(string) => string, _ => panic!(), }; - assert_eq!(message, "Required attribute 'name' missing."); + assert_eq!(message, "Unknown value for 'creator' attribute."); + } - let elem: Element = "w0mcJylzCn+AfvuGdqkty2+KP48=".parse().unwrap(); + #[cfg(not(feature = "disable-validation"))] + #[test] + fn test_invalid_checksum() { + let elem: Element = "w0mcJylzCn+AfvuGdqkty2+KP48=".parse().unwrap(); let error = Checksum::try_from(elem).unwrap_err(); let message = match error { Error::ParseError(string) => string, _ => panic!(), }; - assert_eq!(message, "Unknown value for 'creator' attribute."); + assert_eq!(message, "Unknown attribute in checksum element."); } #[test] @@ -627,7 +635,11 @@ mod tests { assert_eq!(range2.offset, 2048); assert_eq!(range2.length, Some(1024)); assert_eq!(range2.hashes, hashes); + } + #[cfg(not(feature = "disable-validation"))] + #[test] + fn test_invalid_range() { let elem: Element = "" .parse() .unwrap(); diff --git a/src/macros.rs b/src/macros.rs index 62c59736dc5a52435d988e88b30597f22a3f5097..aa89a45cbe2b6c429ef7c6300c75cc8fcc49621c 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -248,6 +248,7 @@ macro_rules! check_ns_only { macro_rules! check_no_children { ($elem:ident, $name:tt) => { + #[cfg(not(feature = "disable-validation"))] for _ in $elem.children() { return Err(crate::error::Error::ParseError(concat!( "Unknown child in ", @@ -260,6 +261,7 @@ macro_rules! check_no_children { macro_rules! check_no_attributes { ($elem:ident, $name:tt) => { + #[cfg(not(feature = "disable-validation"))] for _ in $elem.attrs() { return Err(crate::error::Error::ParseError(concat!( "Unknown attribute in ", @@ -272,6 +274,7 @@ macro_rules! check_no_attributes { macro_rules! check_no_unknown_attributes { ($elem:ident, $name:tt, [$($attr:tt),*]) => ( + #[cfg(not(feature = "disable-validation"))] for (_attr, _) in $elem.attrs() { $( if _attr == $attr { diff --git a/src/message_correct.rs b/src/message_correct.rs index 9e7a08f726c1e789b2794949a3888ec4d8524eb8..3bba10e7a187abf3cb1fcdb2e116a9b014fda2f8 100644 --- a/src/message_correct.rs +++ b/src/message_correct.rs @@ -45,6 +45,7 @@ mod tests { Replace::try_from(elem).unwrap(); } + #[cfg(not(feature = "disable-validation"))] #[test] fn test_invalid_attribute() { let elem: Element = "" diff --git a/src/muc/muc.rs b/src/muc/muc.rs index 32df468d7e46f8548656f6a9503daef514dc610f..fc596fa9c95adfe4f759cefead11bbabca89974e 100644 --- a/src/muc/muc.rs +++ b/src/muc/muc.rs @@ -142,6 +142,7 @@ mod tests { assert_eq!(elem, elem2); } + #[cfg(not(feature = "disable-validation"))] #[test] fn test_muc_invalid_attribute() { let elem: Element = "" diff --git a/src/muc/user.rs b/src/muc/user.rs index 2c1a6926a98b9099f207268bcb683ec9127070a1..56c111e8ef18b7cd8a6be65a3544bdff4bb17efb 100644 --- a/src/muc/user.rs +++ b/src/muc/user.rs @@ -303,6 +303,7 @@ mod tests { assert!(elem.compare_to(&elem2)); } + #[cfg(not(feature = "disable-validation"))] #[test] fn test_invalid_attribute() { let elem: Element = " @@ -343,6 +344,7 @@ mod tests { assert_eq!(message, "Required attribute 'code' missing."); } + #[cfg(not(feature = "disable-validation"))] #[test] fn test_status_invalid_child() { let elem: Element = " @@ -513,6 +515,7 @@ mod tests { assert_eq!(reason.0, "Reason".to_owned()); } + #[cfg(not(feature = "disable-validation"))] #[test] fn test_reason_invalid_attribute() { let elem: Element = " @@ -528,6 +531,7 @@ mod tests { assert_eq!(message, "Unknown attribute in reason element.".to_owned()); } + #[cfg(not(feature = "disable-validation"))] #[test] fn test_reason_invalid() { let elem: Element = " @@ -545,6 +549,7 @@ mod tests { assert_eq!(message, "Unknown child in reason element.".to_owned()); } + #[cfg(not(feature = "disable-validation"))] #[test] fn test_item_invalid_attr() { let elem: Element = " diff --git a/src/nick.rs b/src/nick.rs index edf8dcacce17b23e54ac39fcbea32b87aad8d5a2..03f544aaa9455e9d9b8894972098676b9f898df2 100644 --- a/src/nick.rs +++ b/src/nick.rs @@ -14,6 +14,7 @@ generate_elem_id!( #[cfg(test)] mod tests { use super::*; + #[cfg(not(feature = "disable-validation"))] use crate::error::Error; use minidom::Element; use try_from::TryFrom; @@ -48,6 +49,7 @@ mod tests { assert_eq!(elem1, elem2); } + #[cfg(not(feature = "disable-validation"))] #[test] fn test_invalid() { let elem: Element = "" @@ -61,6 +63,7 @@ mod tests { assert_eq!(message, "Unknown child in nick element."); } + #[cfg(not(feature = "disable-validation"))] #[test] fn test_invalid_attribute() { let elem: Element = "" diff --git a/src/ping.rs b/src/ping.rs index 4cb25f649c453db84f9879f5871c743df187898f..018531205c3d16f9b6b681251fe12091b1e091ab 100644 --- a/src/ping.rs +++ b/src/ping.rs @@ -20,6 +20,7 @@ impl IqGetPayload for Ping {} #[cfg(test)] mod tests { use super::*; + #[cfg(not(feature = "disable-validation"))] use crate::error::Error; use minidom::Element; use try_from::TryFrom; @@ -42,6 +43,7 @@ mod tests { assert_eq!(elem1, elem2); } + #[cfg(not(feature = "disable-validation"))] #[test] fn test_invalid() { let elem: Element = "" @@ -55,6 +57,7 @@ mod tests { assert_eq!(message, "Unknown child in ping element."); } + #[cfg(not(feature = "disable-validation"))] #[test] fn test_invalid_attribute() { let elem: Element = "".parse().unwrap(); diff --git a/src/presence.rs b/src/presence.rs index 1f9846c2b7dc493b5f37d6c135327ebfcd125a68..7e3e8aa8f78a6afb68bfd7430467580f96a7e527 100644 --- a/src/presence.rs +++ b/src/presence.rs @@ -570,6 +570,7 @@ mod tests { assert!(payload.is("test", "invalid")); } + #[cfg(not(feature = "disable-validation"))] #[test] fn test_invalid_status_child() { #[cfg(not(feature = "component"))] @@ -589,6 +590,7 @@ mod tests { assert_eq!(message, "Unknown child in status element."); } + #[cfg(not(feature = "disable-validation"))] #[test] fn test_invalid_attribute() { #[cfg(not(feature = "component"))] diff --git a/src/pubsub/event.rs b/src/pubsub/event.rs index fac8e2fe26b822297abf1438cfe6ae4332bd065d..0cef2c397c453bf00b9bddb5e08d43158a2a9e60 100644 --- a/src/pubsub/event.rs +++ b/src/pubsub/event.rs @@ -420,6 +420,7 @@ mod tests { assert_eq!(message, "Unknown child in event element."); } + #[cfg(not(feature = "disable-validation"))] #[test] fn test_invalid_attribute() { let elem: Element = "" diff --git a/src/roster.rs b/src/roster.rs index 40cc7a25dc7f8a7f935306df4507e3cff8d4862e..c13b0f59ad1eed7cc791c8ac512a56b721056ebd 100644 --- a/src/roster.rs +++ b/src/roster.rs @@ -245,6 +245,7 @@ mod tests { assert_eq!(roster.items[0].subscription, Subscription::Remove); } + #[cfg(not(feature = "disable-validation"))] #[test] fn test_invalid() { let elem: Element = "" diff --git a/src/sasl.rs b/src/sasl.rs index 05dd250aba849569c445349720e024dee0e0179a..db9b17e6fd3a90f071898c15cad65054fdd0dde3 100644 --- a/src/sasl.rs +++ b/src/sasl.rs @@ -288,4 +288,23 @@ mod tests { String::from("Call 212-555-1212 for assistance.") ); } + + /// Some servers apparently use a non-namespaced 'lang' attribute, which is invalid as not part + /// of the schema. This tests whether we can parse it when disabling validation. + #[cfg(feature = "disable-validation")] + #[test] + fn invalid_failure_with_non_prefixed_text_lang() { + let elem: Element = " + + Invalid username or password + " + .parse() + .unwrap(); + let failure = Failure::try_from(elem).unwrap(); + assert_eq!(failure.defined_condition, DefinedCondition::NotAuthorized); + assert_eq!( + failure.texts[""], + String::from("Invalid username or password") + ); + } }