matrix-fuzz

git clone git://archive.git.mtrnord.blog/MTRNord/matrix-fuzz.git
Log | Files | Refs | README | LICENSE

commit 443ceeae2bef950794feda3cc090108e20dcca2d
parent e45d65bc757970a561efb2a7102ac63abe4d8dee
Author: MTRNord <mtrnord1@gmail.com>
Date:   Fri, 12 Aug 2022 18:28:39 +0200

Add initial_state fuzzing

Diffstat:
MCargo.toml | 11+++++------
Msrc/lib.rs | 42+++++++++++++++++++++++++++++++++++++-----
Msrc/types.rs | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 99 insertions(+), 11 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml @@ -1,13 +1,13 @@ [package] +edition = "2021" name = "matrix-fuzz" version = "0.1.0" -edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -serde = { version = "1.0", features = ["derive"] } -reqwest = { version = "0.11.11", features = ["blocking","json","gzip"] } -serde_json = "1.0.83" +fuzzcheck = {git = "https://github.com/MTRNord/fuzzcheck-rs.git", branch = "patch-1"} once_cell = "1.13.0" -fuzzcheck = "0.12" -\ No newline at end of file +reqwest = {version = "0.11.11", features = ["blocking", "json", "gzip"]} +serde = {version = "1.0", features = ["derive"]} +serde_json = "1.0.83" diff --git a/src/lib.rs b/src/lib.rs @@ -12,10 +12,13 @@ use crate::types::{Flow, LoginGet, LoginPost}; mod secrets; mod types; +#[no_coverage] fn access_token() -> &'static String { static INSTANCE: OnceCell<String> = OnceCell::new(); INSTANCE.get_or_init(login) } + +#[no_coverage] fn client() -> &'static reqwest::blocking::Client { static INSTANCE: OnceCell<reqwest::blocking::Client> = OnceCell::new(); INSTANCE.get_or_init(|| { @@ -28,6 +31,7 @@ fn client() -> &'static reqwest::blocking::Client { }) } +#[no_coverage] fn login() -> String { let client = crate::client(); let res: LoginGet = client @@ -59,9 +63,10 @@ fn login() -> String { mod tests { use reqwest::header::{HeaderValue, CONTENT_TYPE}; - use crate::types::CreateRoomMagic; + use crate::types::{CreateRoomMagic, CreateRoomMagicJSON}; #[test] + #[no_coverage] fn connection_test() { let client = crate::client(); let resp = client @@ -72,6 +77,7 @@ mod tests { } #[test] + #[no_coverage] fn null_in_room() { let content = CreateRoomMagic { name: Some("a".to_string()), @@ -81,7 +87,6 @@ mod tests { topic: Some("c".to_string()), ..Default::default() }; - println!("{}", serde_json::to_string(&content).unwrap()); let access_token = crate::access_token(); let client = crate::client(); let resp = client @@ -96,6 +101,7 @@ mod tests { } #[test] + #[no_coverage] fn weird_req() { let content = std::fs::read_to_string("./weird_ones/af84a60a1b7997b4.json").unwrap(); let access_token = crate::access_token(); @@ -108,6 +114,18 @@ mod tests { .send(); assert!(resp.is_err()) } + + #[test] + #[no_coverage] + fn converter() { + let content = std::fs::read_to_string( + "./fuzz/tests::fuzz_create_room/artifacts/36d21e863bdd02f6.json", + ) + .unwrap(); + let typed = serde_json::from_str::<CreateRoomMagic>(&content).unwrap(); + let typed_json: CreateRoomMagicJSON = (&typed).into(); + println!("{}", serde_json::to_string(&typed_json).unwrap()); + } } #[cfg(all(fuzzing, test))] @@ -122,6 +140,17 @@ mod tests { return true; } } + // HACK due to NUL in type or state_key + if let Some(initial_state) = &data.initial_state { + for state in initial_state { + if state._type.contains("\0") { + return true; + } + if state.state_key.contains("\0") { + return true; + } + } + } /*// HACK due to https://github.com/matrix-org/synapse/issues/13511 if let Some(pids) = &data.invite_3pid { for pid in pids { @@ -147,9 +176,12 @@ mod tests { let content = resp.text(); if let Ok(ref content) = content { if content.contains("M_ROOM_IN_USE") - || content.contains("Invalid characters in room alias") - || content.contains("':' is not permitted in the room alias name. Please note this expects a local part — 'wombat', not '#wombat:example.com'.") - || content.contains("M_UNSUPPORTED_ROOM_VERSION") || content.contains("Invalid user_id") || content.contains("is not a valid preset") + || content.contains("Invalid characters in room alias") + || content.contains("':' is not permitted in the room alias name. Please note this expects a local part — 'wombat', not '#wombat:example.com'.") + || content.contains("M_UNSUPPORTED_ROOM_VERSION") + || content.contains("Invalid user_id") + || content.contains("is not a valid preset") + || content.contains("You are not allowed to set others state") { return true; } diff --git a/src/types.rs b/src/types.rs @@ -25,6 +25,8 @@ pub struct CreateRoomMagicJSON { #[serde(skip_serializing_if = "Option::is_none")] pub creation_content: Option<HashMap<String, String>>, #[serde(skip_serializing_if = "Option::is_none")] + pub initial_state: Option<Vec<StateEventJSON>>, + #[serde(skip_serializing_if = "Option::is_none")] pub invite: Option<Vec<String>>, // Due to https://github.com/matrix-org/synapse/issues/13512 //#[serde(skip_serializing_if = "Option::is_none")] @@ -47,6 +49,7 @@ pub struct CreateRoomMagicJSON { // FIXME: This is stupid hacky. impl From<&CreateRoomMagic> for CreateRoomMagicJSON { + #[no_coverage] fn from(item: &CreateRoomMagic) -> Self { let mut creation_content = HashMap::new(); if let Some(mut creation_content_keys) = item.creation_content_keys.clone() { @@ -67,6 +70,10 @@ impl From<&CreateRoomMagic> for CreateRoomMagicJSON { CreateRoomMagicJSON { invite: item.invite.clone(), + initial_state: item + .initial_state + .clone() + .map(|initial_state| initial_state.into_iter().map(Into::into).collect()), is_direct: item.is_direct, name: item.name.clone(), preset: item.preset.clone(), @@ -92,6 +99,8 @@ pub struct CreateRoomMagic { #[serde(skip_serializing_if = "Option::is_none")] pub creation_content_values: Option<Vec<String>>, #[serde(skip_serializing_if = "Option::is_none")] + pub initial_state: Option<Vec<StateEvent>>, + #[serde(skip_serializing_if = "Option::is_none")] pub invite: Option<Vec<String>>, // Due to https://github.com/matrix-org/synapse/issues/13512 //#[serde(skip_serializing_if = "Option::is_none")] @@ -119,3 +128,51 @@ pub struct Invite3pid { pub id_server: String, pub medium: String, } + +#[derive(Clone, Serialize, Deserialize, Debug, Default)] +pub struct StateEventJSON { + pub content: HashMap<String, String>, + #[serde(rename = "type")] + pub _type: String, + pub state_key: String, +} + +// FIXME: This is stupid hacky. +impl From<StateEvent> for StateEventJSON { + #[no_coverage] + fn from(item: StateEvent) -> Self { + let mut content = HashMap::new(); + let mut item_clone = item.clone(); + if item_clone.content_keys.len() > item_clone.content_values.len() { + item_clone + .content_keys + .truncate(item_clone.content_values.len()); + } else { + item_clone + .content_values + .truncate(item_clone.content_keys.len()); + } + for (key, value) in item_clone + .content_keys + .iter() + .zip(item_clone.content_values.iter()) + { + content.insert(key.to_string(), value.to_string()); + } + + StateEventJSON { + content, + _type: item._type.clone(), + state_key: item.state_key, + } + } +} + +#[derive(Clone, Serialize, Deserialize, Debug, DefaultMutator, Default)] +pub struct StateEvent { + pub content_keys: Vec<String>, + pub content_values: Vec<String>, + #[serde(rename = "type")] + pub _type: String, + pub state_key: String, +}