diff --git a/Cargo.lock b/Cargo.lock index cc8a103..f7064f5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -53,9 +53,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.75" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" +checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" [[package]] name = "arrayvec" @@ -171,7 +171,7 @@ dependencies = [ "proc-macro2", "quote", "strum", - "syn 2.0.40", + "syn 2.0.48", "thiserror", ] @@ -230,18 +230,18 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.40", + "syn 2.0.48", ] [[package]] name = "async-trait" -version = "0.1.74" +version = "0.1.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" +checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.40", + "syn 2.0.48", ] [[package]] @@ -304,7 +304,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.40", + "syn 2.0.48", ] [[package]] @@ -402,13 +402,13 @@ dependencies = [ [[package]] name = "clang-sys" -version = "1.6.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f" +checksum = "67523a3b4be3ce1989d607a828d036249522dd9c1c8de7f4dd2dae43a37369d1" dependencies = [ "glob", "libc", - "libloading 0.7.4", + "libloading 0.8.1", ] [[package]] @@ -466,18 +466,18 @@ checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" [[package]] name = "cpufeatures" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" dependencies = [ "libc", ] [[package]] name = "crossbeam-channel" -version = "0.5.8" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" +checksum = "82a9b73a36529d9c47029b9fb3a6f0ea3cc916a261195352ba19e770fc1748b2" dependencies = [ "cfg-if", "crossbeam-utils", @@ -485,9 +485,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +checksum = "fca89a0e215bab21874660c67903c5f143333cab1da83d041c7ded6053774751" dependencies = [ "cfg-if", "crossbeam-epoch", @@ -496,22 +496,20 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.15" +version = "0.9.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" +checksum = "0e3681d554572a651dda4186cd47240627c3d0114d45a95f6ad27f2f22e7548d" dependencies = [ "autocfg", "cfg-if", "crossbeam-utils", - "memoffset", - "scopeguard", ] [[package]] name = "crossbeam-utils" -version = "0.8.16" +version = "0.8.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" +checksum = "c3a430a770ebd84726f584a90ee7f020d28db52c6d02138900f22341f866d39c" dependencies = [ "cfg-if", ] @@ -528,12 +526,12 @@ dependencies = [ [[package]] name = "ctrlc" -version = "3.4.1" +version = "3.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e95fbd621905b854affdc67943b043a0fbb6ed7385fd5a25650d19a8a6cfdf" +checksum = "b467862cc8610ca6fc9a1532d7777cee0804e678ab45410897b9396495994a0b" dependencies = [ "nix", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -557,7 +555,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.40", + "syn 2.0.48", ] [[package]] @@ -568,7 +566,7 @@ checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ "darling_core", "quote", - "syn 2.0.40", + "syn 2.0.48", ] [[package]] @@ -587,7 +585,7 @@ dependencies = [ "deluxe-macros", "once_cell", "proc-macro2", - "syn 2.0.40", + "syn 2.0.48", ] [[package]] @@ -600,7 +598,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.40", + "syn 2.0.48", ] [[package]] @@ -615,7 +613,7 @@ dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", "quote", - "syn 2.0.40", + "syn 2.0.48", ] [[package]] @@ -634,9 +632,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.3.10" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eb30d70a07a3b04884d2677f06bec33509dc67ca60d92949e5535352d3191dc" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" dependencies = [ "powerfmt", "serde", @@ -681,7 +679,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.40", + "syn 2.0.48", ] [[package]] @@ -783,9 +781,9 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" dependencies = [ "futures-channel", "futures-core", @@ -798,9 +796,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" dependencies = [ "futures-core", "futures-sink", @@ -808,15 +806,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" [[package]] name = "futures-executor" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" dependencies = [ "futures-core", "futures-task", @@ -825,38 +823,38 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" [[package]] name = "futures-macro" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.40", + "syn 2.0.48", ] [[package]] name = "futures-sink" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" [[package]] name = "futures-task" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" [[package]] name = "futures-util" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ "futures-channel", "futures-core", @@ -938,7 +936,7 @@ dependencies = [ "semver", "serde", "serde_json", - "syn 2.0.40", + "syn 2.0.48", "tempfile", "tokio", "toml_edit 0.21.0", @@ -1189,9 +1187,9 @@ dependencies = [ [[package]] name = "hyper" -version = "0.14.27" +version = "0.14.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" +checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" dependencies = [ "bytes", "futures-channel", @@ -1204,7 +1202,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2 0.4.10", + "socket2", "tokio", "tower-service", "tracing", @@ -1240,9 +1238,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.58" +version = "0.1.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20" +checksum = "b6a67363e2aa4443928ce15e57ebae94fd8949958fd1223c4cfc0cd473ad7539" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -1383,12 +1381,12 @@ dependencies = [ [[package]] name = "libloading" -version = "0.7.4" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161" dependencies = [ "cfg-if", - "winapi", + "windows-sys 0.48.0", ] [[package]] @@ -1478,18 +1476,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.6.4" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" - -[[package]] -name = "memoffset" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" -dependencies = [ - "autocfg", -] +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" [[package]] name = "mime" @@ -1692,14 +1681,14 @@ dependencies = [ "proc-macro-crate 2.0.0", "proc-macro2", "quote", - "syn 2.0.40", + "syn 2.0.48", ] [[package]] name = "object" -version = "0.32.1" +version = "0.32.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" dependencies = [ "memchr", ] @@ -1721,9 +1710,9 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "openssl" -version = "0.10.61" +version = "0.10.62" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b8419dc8cc6d866deb801274bba2e6f8f6108c1bb7fcc10ee5ab864931dbb45" +checksum = "8cde4d2d9200ad5909f8dac647e29482e07c3a35de8a13fce7c9c7747ad9f671" dependencies = [ "bitflags 2.4.1", "cfg-if", @@ -1742,7 +1731,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.40", + "syn 2.0.48", ] [[package]] @@ -1753,9 +1742,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.97" +version = "0.9.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3eaad34cdd97d81de97964fc7f29e2d104f483840d906ef56daa1912338460b" +checksum = "c1665caf8ab2dc9aef43d1c0023bd904633a6a05cb30b0ad59bec2ae986e57a7" dependencies = [ "cc", "libc", @@ -1833,9 +1822,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.7.5" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae9cee2a55a544be8b89dc6848072af97a20f2422603c10865be2a42b580fff5" +checksum = "1f200d8d83c44a45b21764d1916299752ca035d15ecd46faca3e9a2a2bf6ad06" dependencies = [ "memchr", "thiserror", @@ -1844,9 +1833,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.7.5" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81d78524685f5ef2a3b3bd1cafbc9fcabb036253d9b1463e726a91cd16e2dfc2" +checksum = "bcd6ab1236bbdb3a49027e920e693192ebfe8913f6d60e294de57463a493cfde" dependencies = [ "pest", "pest_generator", @@ -1854,22 +1843,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.5" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68bd1206e71118b5356dae5ddc61c8b11e28b09ef6a31acbd15ea48a28e0c227" +checksum = "2a31940305ffc96863a735bef7c7994a00b325a7138fdbc5bda0f1a0476d3275" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.40", + "syn 2.0.48", ] [[package]] name = "pest_meta" -version = "2.7.5" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c747191d4ad9e4a4ab9c8798f1e82a39affe7ef9648390b7e5548d18e099de6" +checksum = "a7ff62f5259e53b78d1af898941cdcdccfae7385cf7d793a6e55de5d05bb4b7d" dependencies = [ "once_cell", "pest", @@ -1893,7 +1882,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.40", + "syn 2.0.48", ] [[package]] @@ -1910,9 +1899,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" +checksum = "69d3587f8a9e599cc7ec2c00e331f71c4e69a5f9a4b8a6efd5b07466b9736f9a" [[package]] name = "pnet" @@ -1959,7 +1948,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "syn 2.0.40", + "syn 2.0.48", ] [[package]] @@ -2019,12 +2008,12 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "prettyplease" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae005bd773ab59b4725093fd7df83fd7892f7d8eafb48dbd7de6e024e4215f9d" +checksum = "a41cf62165e97c7f814d2221421dbb9afcbcdb0a88068e5ea206e19951c2cbb5" dependencies = [ "proc-macro2", - "syn 2.0.40", + "syn 2.0.48", ] [[package]] @@ -2048,9 +2037,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.70" +version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" +checksum = "907a61bd0f64c2f29cd1cf1dc34d05176426a3f504a78010f08416ddb7b13708" dependencies = [ "unicode-ident", ] @@ -2098,16 +2087,16 @@ checksum = "055b4e778e8feb9f93c4e439f71dc2156ef13360b432b799e179a8c4cdf0b1d7" dependencies = [ "bytes", "libc", - "socket2 0.5.5", + "socket2", "tracing", "windows-sys 0.48.0", ] [[package]] name = "quote" -version = "1.0.33" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] @@ -2228,9 +2217,9 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "reqwest" -version = "0.11.22" +version = "0.11.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b" +checksum = "37b1ae8d9ac08420c66222fb9096fc5de435c3c48542bc5336c51892cffafb41" dependencies = [ "base64 0.21.5", "bytes", @@ -2427,11 +2416,11 @@ checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" [[package]] name = "schannel" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" +checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -2481,35 +2470,35 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.20" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" +checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" [[package]] name = "serde" -version = "1.0.193" +version = "1.0.194" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" +checksum = "0b114498256798c94a0689e1a15fec6005dee8ac1f41de56404b67afc2a4b773" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.193" +version = "1.0.194" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" +checksum = "a3385e45322e8f9931410f01b3031ec534c3947d0e94c18049af4d9f9907d4e0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.40", + "syn 2.0.48", ] [[package]] name = "serde_json" -version = "1.0.108" +version = "1.0.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" +checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4" dependencies = [ "itoa", "ryu", @@ -2554,14 +2543,14 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.40", + "syn 2.0.48", ] [[package]] name = "serde_yaml" -version = "0.9.27" +version = "0.9.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cc7a1570e38322cfe4154732e5110f887ea57e22b76f4bfd32b5bdd3368666c" +checksum = "b1bf28c79a99f70ee1f1d83d10c875d2e70618417fda01ad1785e027579d9d38" dependencies = [ "indexmap 2.1.0", "itoa", @@ -2618,9 +2607,9 @@ dependencies = [ [[package]] name = "similar" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2aeaf503862c419d66959f5d7ca015337d864e9c49485d771b732e2a20453597" +checksum = "32fea41aca09ee824cc9724996433064c89f7777e60762749a4170a14abbfa21" [[package]] name = "slab" @@ -2637,16 +2626,6 @@ version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" -[[package]] -name = "socket2" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" -dependencies = [ - "libc", - "winapi", -] - [[package]] name = "socket2" version = "0.5.5" @@ -2700,7 +2679,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.40", + "syn 2.0.48", ] [[package]] @@ -2716,9 +2695,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.40" +version = "2.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13fa70a4ee923979ffb522cacce59d34421ebdea5625e1073c4326ef9d2dd42e" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" dependencies = [ "proc-macro2", "quote", @@ -2786,35 +2765,35 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.8.1" +version = "3.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" +checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa" dependencies = [ "cfg-if", "fastrand", "redox_syscall", "rustix", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "thiserror" -version = "1.0.50" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" +checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.50" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" +checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" dependencies = [ "proc-macro2", "quote", - "syn 2.0.40", + "syn 2.0.48", ] [[package]] @@ -2829,9 +2808,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5" +checksum = "f657ba42c3f86e7680e53c8cd3af8abbe56b5491790b46e22e19c0d57463583e" dependencies = [ "deranged", "itoa", @@ -2849,9 +2828,9 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20" +checksum = "26197e33420244aeb70c3e8c78376ca46571bc4e701e4791c2cd9f57dcb3a43f" dependencies = [ "time-core", ] @@ -2873,9 +2852,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.35.0" +version = "1.35.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "841d45b238a16291a4e1584e61820b8ae57d696cc5015c459c229ccc6990cc1c" +checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104" dependencies = [ "backtrace", "bytes", @@ -2885,7 +2864,7 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.5.5", + "socket2", "tokio-macros", "windows-sys 0.48.0", ] @@ -2898,7 +2877,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.40", + "syn 2.0.48", ] [[package]] @@ -3044,7 +3023,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.40", + "syn 2.0.48", ] [[package]] @@ -3170,9 +3149,9 @@ dependencies = [ [[package]] name = "unsafe-libyaml" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f28467d3e1d3c6586d8f25fa243f544f5800fec42d97032474e17222c2b75cfa" +checksum = "ab4c90930b95a82d00dc9e9ac071b4991924390d46cbd0dfe566148667605e4b" [[package]] name = "untrusted" @@ -3305,7 +3284,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.40", + "syn 2.0.48", "wasm-bindgen-shared", ] @@ -3339,7 +3318,7 @@ checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" dependencies = [ "proc-macro2", "quote", - "syn 2.0.40", + "syn 2.0.48", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -3403,11 +3382,11 @@ dependencies = [ [[package]] name = "windows-core" -version = "0.51.1" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.48.5", + "windows-targets 0.52.0", ] [[package]] @@ -3617,9 +3596,9 @@ checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" [[package]] name = "winnow" -version = "0.5.28" +version = "0.5.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c830786f7720c2fd27a1a0e27a709dbd3c4d009b56d098fc742d4f4eab91fe2" +checksum = "8434aeec7b290e8da5c3f0d628cb0eac6cabcb31d14bb74f779a08109a5914d6" dependencies = [ "memchr", ] diff --git a/src/graphql.rs b/src/graphql.rs index 39fae9b..9c707e9 100644 --- a/src/graphql.rs +++ b/src/graphql.rs @@ -441,17 +441,17 @@ fn get_peekable_iter<'c, T>( where T: DeserializeOwned + EventFilter, { - let (filterd_iter, cursor, size) = + let (filtered_iter, cursor, size) = get_filtered_iter(store, filter, after, before, first, last)?; - let mut filterd_iter = filterd_iter.peekable(); + let mut filtered_iter = filtered_iter.peekable(); if let Some(cursor) = cursor { - if let Some((key, _)) = filterd_iter.peek() { + if let Some((key, _)) = filtered_iter.peek() { if key.as_ref() == cursor { - filterd_iter.next(); + filtered_iter.next(); } } } - Ok((filterd_iter, size)) + Ok((filtered_iter, size)) } fn get_filtered_iter<'c, T>( diff --git a/src/graphql/export.rs b/src/graphql/export.rs index 95d9bb3..eb6beb9 100644 --- a/src/graphql/export.rs +++ b/src/graphql/export.rs @@ -1,3 +1,6 @@ +#[cfg(test)] +mod tests; + use super::{ check_address, check_port, netflow::{millis_to_secs, tcp_flags}, @@ -2346,1420 +2349,3 @@ macro_rules! impl_from_giganto_export_filter_for_graphql_client { impl_from_giganto_range_structs_for_graphql_client!(exports); impl_from_giganto_export_filter_for_graphql_client!(exports); - -#[cfg(test)] -mod tests { - use crate::graphql::tests::TestSchema; - use crate::storage::RawEventStore; - use chrono::{Duration, Utc}; - use giganto_client::ingest::{ - log::{Log, OpLog, OpLogLevel}, - network::{ - Conn, DceRpc, Dns, Ftp, Http, Kerberos, Ldap, Mqtt, Nfs, Ntlm, Rdp, Smb, Smtp, Ssh, Tls, - }, - timeseries::PeriodicTimeSeries, - }; - use std::mem; - use std::net::IpAddr; - - #[tokio::test] - async fn invalid_query() { - let schema = TestSchema::new(); - - // invalid filter combine1 (log + addr) - let query = r#" - { - export( - filter:{ - protocol: "log", - sourceId: "src1", - time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } - origAddr: { start: "192.168.4.72", end: "192.168.4.79" } - } - ,exportType:"json") - }"#; - let res = schema.execute(query).await; - assert_eq!(res.data.to_string(), "null"); - - // invalid filter combine2 (network proto + kind) - let query = r#" - { - export( - filter:{ - protocol: "conn", - sourceId: "src1", - kind: "log1" - } - ,exportType:"json") - }"#; - let res = schema.execute(query).await; - assert_eq!(res.data.to_string(), "null"); - - // invalid export format - let query = r#" - { - export( - filter:{ - protocol: "conn", - sourceId: "src1", - } - ,exportType:"ppt") - }"#; - let res = schema.execute(query).await; - assert_eq!(res.data.to_string(), "null"); - - // invalid protocol format - let query = r#" - { - export( - filter:{ - protocol: "invalid_proto", - sourceId: "src1", - } - ,exportType:"json") - }"#; - let res = schema.execute(query).await; - assert_eq!(res.data.to_string(), "null"); - } - - #[tokio::test] - async fn export_conn() { - let schema = TestSchema::new(); - let store = schema.db.conn_store().unwrap(); - - insert_conn_raw_event(&store, "src1", Utc::now().timestamp_nanos_opt().unwrap()); - insert_conn_raw_event( - &store, - "ingest src 1", - Utc::now().timestamp_nanos_opt().unwrap(), - ); - - // export csv file - let query = r#" - { - export( - filter:{ - protocol: "conn", - sourceId: "src1", - time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } - origAddr: { start: "192.168.4.72", end: "192.168.4.79" } - respAddr: { start: "192.168.4.75", end: "192.168.4.79" } - origPort: { start: 46378, end: 46379 } - respPort: { start: 50, end: 200 } - } - ,exportType:"csv") - }"#; - let res = schema.execute(query).await; - assert!(res.data.to_string().contains("conn")); - - // export json file - let query = r#" - { - export( - filter:{ - protocol: "conn", - sourceId: "ingest src 1", - time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } - origAddr: { start: "192.168.4.72", end: "192.168.4.79" } - respAddr: { start: "192.168.4.75", end: "192.168.4.79" } - origPort: { start: 46378, end: 46379 } - respPort: { start: 50, end: 200 } - } - ,exportType:"json") - }"#; - let res = schema.execute(query).await; - assert!(res.data.to_string().contains("conn")); - } - - fn insert_conn_raw_event(store: &RawEventStore, source: &str, timestamp: i64) { - let mut key = Vec::with_capacity(source.len() + 1 + mem::size_of::()); - key.extend_from_slice(source.as_bytes()); - key.push(0); - key.extend(timestamp.to_be_bytes()); - - let tmp_dur = Duration::nanoseconds(12345); - let conn_body = Conn { - orig_addr: "192.168.4.76".parse::().unwrap(), - orig_port: 46378, - resp_addr: "192.168.4.76".parse::().unwrap(), - resp_port: 80, - proto: 6, - duration: tmp_dur.num_nanoseconds().unwrap(), - service: "-".to_string(), - orig_bytes: 77, - resp_bytes: 295, - orig_pkts: 397, - resp_pkts: 511, - }; - let ser_conn_body = bincode::serialize(&conn_body).unwrap(); - - store.append(&key, &ser_conn_body).unwrap(); - } - - #[tokio::test] - async fn export_dns() { - let schema = TestSchema::new(); - let store = schema.db.dns_store().unwrap(); - - insert_dns_raw_event(&store, "src1", Utc::now().timestamp_nanos_opt().unwrap()); - insert_dns_raw_event( - &store, - "ingest src 1", - Utc::now().timestamp_nanos_opt().unwrap(), - ); - - // export csv file - let query = r#" - { - export( - filter:{ - protocol: "dns", - sourceId: "src1", - time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } - origAddr: { start: "192.168.4.70", end: "192.168.4.78" } - respAddr: { start: "31.3.245.100", end: "31.3.245.245" } - origPort: { start: 46377, end: 46380 } - respPort: { start: 0, end: 200 } - } - ,exportType:"csv") - }"#; - let res = schema.execute(query).await; - assert!(res.data.to_string().contains("dns")); - - // export json file - let query = r#" - { - export( - filter:{ - protocol: "dns", - sourceId: "ingest src 1", - time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } - origAddr: { start: "192.168.4.70", end: "192.168.4.78" } - respAddr: { start: "31.3.245.100", end: "31.3.245.245" } - origPort: { start: 46377, end: 46380 } - respPort: { start: 0, end: 200 } - } - ,exportType:"json") - }"#; - let res = schema.execute(query).await; - assert!(res.data.to_string().contains("dns")); - } - - fn insert_dns_raw_event(store: &RawEventStore, source: &str, timestamp: i64) { - let mut key = Vec::with_capacity(source.len() + 1 + mem::size_of::()); - key.extend_from_slice(source.as_bytes()); - key.push(0); - key.extend(timestamp.to_be_bytes()); - - let dns_body = Dns { - orig_addr: "192.168.4.76".parse::().unwrap(), - orig_port: 46378, - resp_addr: "31.3.245.133".parse::().unwrap(), - resp_port: 80, - proto: 17, - last_time: 1, - query: "Hello Server Hello Server Hello Server".to_string(), - answer: vec!["1.1.1.1".to_string()], - trans_id: 1, - rtt: 1, - qclass: 0, - qtype: 0, - rcode: 0, - aa_flag: false, - tc_flag: false, - rd_flag: false, - ra_flag: false, - ttl: vec![1; 5], - }; - let ser_dns_body = bincode::serialize(&dns_body).unwrap(); - - store.append(&key, &ser_dns_body).unwrap(); - } - - #[tokio::test] - async fn export_http() { - let schema = TestSchema::new(); - let store = schema.db.http_store().unwrap(); - - insert_http_raw_event(&store, "src1", Utc::now().timestamp_nanos_opt().unwrap()); - insert_http_raw_event( - &store, - "ingest src 1", - Utc::now().timestamp_nanos_opt().unwrap(), - ); - - // export csv file - let query = r#" - { - export( - filter:{ - protocol: "http", - sourceId: "src1", - time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } - origAddr: { start: "192.168.4.75", end: "192.168.4.79" } - respAddr: { start: "192.168.4.75", end: "192.168.4.79" } - origPort: { start: 46377, end: 46380 } - respPort: { start: 0, end: 200 } - } - ,exportType:"csv") - }"#; - let res = schema.execute(query).await; - assert!(res.data.to_string().contains("http")); - - // export json file - let query = r#" - { - export( - filter:{ - protocol: "http", - sourceId: "ingest src 1", - time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } - origAddr: { start: "192.168.4.75", end: "192.168.4.79" } - respAddr: { start: "192.168.4.75", end: "192.168.4.79" } - origPort: { start: 46377, end: 46380 } - respPort: { start: 0, end: 200 } - } - ,exportType:"json") - }"#; - let res = schema.execute(query).await; - assert!(res.data.to_string().contains("http")); - } - - fn insert_http_raw_event(store: &RawEventStore, source: &str, timestamp: i64) { - let mut key = Vec::with_capacity(source.len() + 1 + mem::size_of::()); - key.extend_from_slice(source.as_bytes()); - key.push(0); - key.extend(timestamp.to_be_bytes()); - - let http_body = Http { - orig_addr: "192.168.4.76".parse::().unwrap(), - orig_port: 46378, - resp_addr: "192.168.4.76".parse::().unwrap(), - resp_port: 80, - proto: 6, - last_time: 1, - method: "POST".to_string(), - host: "einsis".to_string(), - uri: "/einsis.gif".to_string(), - referrer: "einsis.com".to_string(), - version: String::new(), - user_agent: "giganto".to_string(), - request_len: 0, - response_len: 0, - status_code: 200, - status_msg: String::new(), - username: String::new(), - password: String::new(), - cookie: String::new(), - content_encoding: String::new(), - content_type: String::new(), - cache_control: String::new(), - orig_filenames: Vec::new(), - orig_mime_types: Vec::new(), - resp_filenames: Vec::new(), - resp_mime_types: Vec::new(), - }; - let ser_http_body = bincode::serialize(&http_body).unwrap(); - - store.append(&key, &ser_http_body).unwrap(); - } - - #[tokio::test] - async fn export_rdp() { - let schema = TestSchema::new(); - let store = schema.db.rdp_store().unwrap(); - - insert_rdp_raw_event(&store, "src1", Utc::now().timestamp_nanos_opt().unwrap()); - insert_rdp_raw_event( - &store, - "ingest src 1", - Utc::now().timestamp_nanos_opt().unwrap(), - ); - - // export csv file - let query = r#" - { - export( - filter:{ - protocol: "rdp", - sourceId: "src1", - time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } - origAddr: { start: "192.168.4.75", end: "192.168.4.79" } - respAddr: { start: "192.168.4.75", end: "192.168.4.79" } - origPort: { start: 46377, end: 46380 } - respPort: { start: 0, end: 200 } - } - ,exportType:"csv") - }"#; - let res = schema.execute(query).await; - assert!(res.data.to_string().contains("rdp")); - - // export json file - let query = r#" - { - export( - filter:{ - protocol: "rdp", - sourceId: "ingest src 1", - time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } - origAddr: { start: "192.168.4.70", end: "192.168.4.78" } - respAddr: { start: "192.168.4.75", end: "192.168.4.79" } - origPort: { start: 46377, end: 46380 } - respPort: { start: 0, end: 200 } - } - ,exportType:"json") - }"#; - let res = schema.execute(query).await; - assert!(res.data.to_string().contains("rdp")); - } - - fn insert_rdp_raw_event(store: &RawEventStore, source: &str, timestamp: i64) { - let mut key = Vec::with_capacity(source.len() + 1 + mem::size_of::()); - key.extend_from_slice(source.as_bytes()); - key.push(0); - key.extend(timestamp.to_be_bytes()); - - let rdp_body = Rdp { - orig_addr: "192.168.4.76".parse::().unwrap(), - orig_port: 46378, - resp_addr: "192.168.4.76".parse::().unwrap(), - resp_port: 80, - proto: 6, - last_time: 1, - cookie: "rdp_test".to_string(), - }; - let ser_rdp_body = bincode::serialize(&rdp_body).unwrap(); - - store.append(&key, &ser_rdp_body).unwrap(); - } - - #[tokio::test] - async fn export_smtp() { - let schema = TestSchema::new(); - let store = schema.db.smtp_store().unwrap(); - - insert_smtp_raw_event(&store, "src1", Utc::now().timestamp_nanos_opt().unwrap()); - insert_smtp_raw_event( - &store, - "ingest src 1", - Utc::now().timestamp_nanos_opt().unwrap(), - ); - - // export csv file - let query = r#" - { - export( - filter:{ - protocol: "smtp", - sourceId: "src1", - time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } - origAddr: { start: "192.168.4.70", end: "192.168.4.78" } - respAddr: { start: "192.168.4.70", end: "192.168.4.78" } - origPort: { start: 46377, end: 46380 } - respPort: { start: 0, end: 200 } - } - ,exportType:"csv") - }"#; - let res = schema.execute(query).await; - assert!(res.data.to_string().contains("smtp")); - - // export json file - let query = r#" - { - export( - filter:{ - protocol: "smtp", - sourceId: "ingest src 1", - time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } - origAddr: { start: "192.168.4.70", end: "192.168.4.78" } - respAddr: { start: "192.168.4.70", end: "192.168.4.78" } - origPort: { start: 46377, end: 46380 } - respPort: { start: 0, end: 200 } - } - ,exportType:"json") - }"#; - let res = schema.execute(query).await; - assert!(res.data.to_string().contains("smtp")); - } - - fn insert_smtp_raw_event(store: &RawEventStore, source: &str, timestamp: i64) { - let mut key = Vec::with_capacity(source.len() + 1 + mem::size_of::()); - key.extend_from_slice(source.as_bytes()); - key.push(0); - key.extend(timestamp.to_be_bytes()); - - let smtp_body = Smtp { - orig_addr: "192.168.4.76".parse::().unwrap(), - orig_port: 46378, - resp_addr: "192.168.4.76".parse::().unwrap(), - resp_port: 80, - proto: 6, - last_time: 1, - mailfrom: "mailfrom".to_string(), - date: "date".to_string(), - from: "from".to_string(), - to: "to".to_string(), - subject: "subject".to_string(), - agent: "agent".to_string(), - }; - let ser_smtp_body = bincode::serialize(&smtp_body).unwrap(); - - store.append(&key, &ser_smtp_body).unwrap(); - } - - #[tokio::test] - async fn export_ntlm() { - let schema = TestSchema::new(); - let store = schema.db.ntlm_store().unwrap(); - - insert_ntlm_raw_event(&store, "src1", Utc::now().timestamp_nanos_opt().unwrap()); - insert_ntlm_raw_event( - &store, - "ingest src 1", - Utc::now().timestamp_nanos_opt().unwrap(), - ); - - // export csv file - let query = r#" - { - export( - filter:{ - protocol: "ntlm", - sourceId: "src1", - time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } - origAddr: { start: "192.168.4.72", end: "192.168.4.79" } - respAddr: { start: "192.168.4.75", end: "192.168.4.79" } - origPort: { start: 46378, end: 46379 } - respPort: { start: 50, end: 200 } - } - ,exportType:"csv") - }"#; - let res = schema.execute(query).await; - assert!(res.data.to_string().contains("ntlm")); - - // export json file - let query = r#" - { - export( - filter:{ - protocol: "ntlm", - sourceId: "ingest src 1", - time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } - origAddr: { start: "192.168.4.72", end: "192.168.4.79" } - respAddr: { start: "192.168.4.75", end: "192.168.4.79" } - origPort: { start: 46378, end: 46379 } - respPort: { start: 50, end: 200 } - } - ,exportType:"json") - }"#; - let res = schema.execute(query).await; - assert!(res.data.to_string().contains("ntlm")); - } - - fn insert_ntlm_raw_event(store: &RawEventStore, source: &str, timestamp: i64) { - let mut key = Vec::with_capacity(source.len() + 1 + mem::size_of::()); - key.extend_from_slice(source.as_bytes()); - key.push(0); - key.extend(timestamp.to_be_bytes()); - - let ntlm_body = Ntlm { - orig_addr: "192.168.4.76".parse::().unwrap(), - orig_port: 46378, - resp_addr: "192.168.4.76".parse::().unwrap(), - resp_port: 80, - proto: 6, - last_time: 1, - username: "bly".to_string(), - hostname: "host".to_string(), - domainname: "domain".to_string(), - server_nb_computer_name: "NB".to_string(), - server_dns_computer_name: "dns".to_string(), - server_tree_name: "tree".to_string(), - success: "tf".to_string(), - }; - let ser_ntlm_body = bincode::serialize(&ntlm_body).unwrap(); - - store.append(&key, &ser_ntlm_body).unwrap(); - } - - #[tokio::test] - async fn export_kerberos() { - let schema = TestSchema::new(); - let store = schema.db.kerberos_store().unwrap(); - - insert_kerberos_raw_event(&store, "src1", Utc::now().timestamp_nanos_opt().unwrap()); - insert_kerberos_raw_event( - &store, - "ingest src 1", - Utc::now().timestamp_nanos_opt().unwrap(), - ); - - // export csv file - let query = r#" - { - export( - filter:{ - protocol: "kerberos", - sourceId: "src1", - time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } - origAddr: { start: "192.168.4.72", end: "192.168.4.79" } - respAddr: { start: "192.168.4.75", end: "192.168.4.79" } - origPort: { start: 46378, end: 46379 } - respPort: { start: 50, end: 200 } - } - ,exportType:"csv") - }"#; - let res = schema.execute(query).await; - assert!(res.data.to_string().contains("kerberos")); - - // export json file - let query = r#" - { - export( - filter:{ - protocol: "kerberos", - sourceId: "ingest src 1", - time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } - origAddr: { start: "192.168.4.72", end: "192.168.4.79" } - respAddr: { start: "192.168.4.75", end: "192.168.4.79" } - origPort: { start: 46378, end: 46379 } - respPort: { start: 50, end: 200 } - } - ,exportType:"json") - }"#; - let res = schema.execute(query).await; - assert!(res.data.to_string().contains("kerberos")); - } - - fn insert_kerberos_raw_event(store: &RawEventStore, source: &str, timestamp: i64) { - let mut key = Vec::with_capacity(source.len() + 1 + mem::size_of::()); - key.extend_from_slice(source.as_bytes()); - key.push(0); - key.extend(timestamp.to_be_bytes()); - - let kerberos_body = Kerberos { - orig_addr: "192.168.4.76".parse::().unwrap(), - orig_port: 46378, - resp_addr: "192.168.4.76".parse::().unwrap(), - resp_port: 80, - proto: 6, - last_time: 1, - client_time: 1, - server_time: 1, - error_code: 1, - client_realm: "client_realm".to_string(), - cname_type: 1, - client_name: vec!["client_name".to_string()], - realm: "realm".to_string(), - sname_type: 1, - service_name: vec!["service_name".to_string()], - }; - let ser_kerberos_body = bincode::serialize(&kerberos_body).unwrap(); - - store.append(&key, &ser_kerberos_body).unwrap(); - } - - #[tokio::test] - async fn export_ssh() { - let schema = TestSchema::new(); - let store = schema.db.ssh_store().unwrap(); - - insert_ssh_raw_event(&store, "src1", Utc::now().timestamp_nanos_opt().unwrap()); - insert_ssh_raw_event( - &store, - "ingest src 1", - Utc::now().timestamp_nanos_opt().unwrap(), - ); - - // export csv file - let query = r#" - { - export( - filter:{ - protocol: "ssh", - sourceId: "src1", - time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } - origAddr: { start: "192.168.4.72", end: "192.168.4.79" } - respAddr: { start: "192.168.4.75", end: "192.168.4.79" } - origPort: { start: 46377, end: 46380 } - respPort: { start: 0, end: 200 } - } - ,exportType:"csv") - }"#; - let res = schema.execute(query).await; - assert!(res.data.to_string().contains("ssh")); - - // export json file - let query = r#" - { - export( - filter:{ - protocol: "ssh", - sourceId: "ingest src 1", - time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } - origAddr: { start: "192.168.4.72", end: "192.168.4.79" } - respAddr: { start: "192.168.4.75", end: "192.168.4.79" } - origPort: { start: 46377, end: 46380 } - respPort: { start: 0, end: 200 } - } - ,exportType:"json") - }"#; - let res = schema.execute(query).await; - assert!(res.data.to_string().contains("ssh")); - } - fn insert_ssh_raw_event(store: &RawEventStore, source: &str, timestamp: i64) { - let mut key = Vec::with_capacity(source.len() + 1 + mem::size_of::()); - key.extend_from_slice(source.as_bytes()); - key.push(0); - key.extend(timestamp.to_be_bytes()); - - let ssh_body = Ssh { - orig_addr: "192.168.4.76".parse::().unwrap(), - orig_port: 46378, - resp_addr: "192.168.4.76".parse::().unwrap(), - resp_port: 80, - proto: 6, - last_time: 1, - version: 01, - auth_success: "auth_success".to_string(), - auth_attempts: 3, - direction: "direction".to_string(), - client: "client".to_string(), - server: "server".to_string(), - cipher_alg: "cipher_alg".to_string(), - mac_alg: "mac_alg".to_string(), - compression_alg: "compression_alg".to_string(), - kex_alg: "kex_alg".to_string(), - host_key_alg: "host_key_alg".to_string(), - host_key: "host_key".to_string(), - }; - let ser_ssh_body = bincode::serialize(&ssh_body).unwrap(); - - store.append(&key, &ser_ssh_body).unwrap(); - } - - #[tokio::test] - async fn export_dce_rpc() { - let schema = TestSchema::new(); - let store = schema.db.dce_rpc_store().unwrap(); - - insert_dce_rpc_raw_event(&store, "src1", Utc::now().timestamp_nanos_opt().unwrap()); - insert_dce_rpc_raw_event( - &store, - "ingest src 1", - Utc::now().timestamp_nanos_opt().unwrap(), - ); - - // export csv file - let query = r#" - { - export( - filter:{ - protocol: "dce rpc", - sourceId: "src1", - time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } - origAddr: { start: "192.168.4.70", end: "192.168.4.78" } - respAddr: { start: "192.168.4.75", end: "192.168.4.79" } - origPort: { start: 46377, end: 46380 } - respPort: { start: 0, end: 200 } - } - ,exportType:"csv") - }"#; - let res = schema.execute(query).await; - assert!(res.data.to_string().contains("dcerpc")); - - // export json file - let query = r#" - { - export( - filter:{ - protocol: "dce rpc", - sourceId: "ingest src 1", - time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } - origAddr: { start: "192.168.4.70", end: "192.168.4.78" } - respAddr: { start: "192.168.4.75", end: "192.168.4.79" } - origPort: { start: 46377, end: 46380 } - respPort: { start: 0, end: 200 } - } - ,exportType:"json") - }"#; - let res = schema.execute(query).await; - assert!(res.data.to_string().contains("dcerpc")); - } - fn insert_dce_rpc_raw_event(store: &RawEventStore, source: &str, timestamp: i64) { - let mut key = Vec::with_capacity(source.len() + 1 + mem::size_of::()); - key.extend_from_slice(source.as_bytes()); - key.push(0); - key.extend(timestamp.to_be_bytes()); - - let dce_rpc_body = DceRpc { - orig_addr: "192.168.4.76".parse::().unwrap(), - orig_port: 46378, - resp_addr: "192.168.4.76".parse::().unwrap(), - resp_port: 80, - proto: 6, - last_time: 1, - rtt: 3, - named_pipe: "named_pipe".to_string(), - endpoint: "endpoint".to_string(), - operation: "operation".to_string(), - }; - let ser_dce_rpc_body = bincode::serialize(&dce_rpc_body).unwrap(); - - store.append(&key, &ser_dce_rpc_body).unwrap(); - } - - #[tokio::test] - async fn export_log() { - let schema = TestSchema::new(); - let store = schema.db.log_store().unwrap(); - - insert_log_raw_event( - &store, - "src1", - Utc::now().timestamp_nanos_opt().unwrap(), - "kind1", - b"log1", - ); - insert_log_raw_event( - &store, - "ingest src 1", - Utc::now().timestamp_nanos_opt().unwrap(), - "kind2", - b"log2", - ); - - // export csv file - let query = r#" - { - export( - filter:{ - protocol: "log", - sourceId: "src1", - kind: "kind1", - time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } - } - ,exportType:"csv") - }"#; - let res = schema.execute(query).await; - assert!(res.data.to_string().contains("log")); - - // export json file - let query = r#" - { - export( - filter:{ - protocol: "log", - sourceId: "ingest src 1", - kind: "kind2", - time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } - } - ,exportType:"json") - }"#; - let res = schema.execute(query).await; - assert!(res.data.to_string().contains("log")); - } - - fn insert_log_raw_event( - store: &RawEventStore, - source: &str, - timestamp: i64, - kind: &str, - body: &[u8], - ) { - let mut key: Vec = Vec::new(); - key.extend_from_slice(source.as_bytes()); - key.push(0); - key.extend_from_slice(kind.as_bytes()); - key.push(0); - key.extend_from_slice(×tamp.to_be_bytes()); - let log_body = Log { - kind: kind.to_string(), - log: body.to_vec(), - }; - let value = bincode::serialize(&log_body).unwrap(); - store.append(&key, &value).unwrap(); - } - - #[tokio::test] - async fn export_time_series() { - let schema = TestSchema::new(); - let store = schema.db.periodic_time_series_store().unwrap(); - - insert_time_series( - &store, - "src1", - Utc::now().timestamp_nanos_opt().unwrap(), - vec![0.0; 12], - ); - insert_time_series( - &store, - "ingest src 1", - Utc::now().timestamp_nanos_opt().unwrap(), - vec![0.0; 12], - ); - - // export csv file - let query = r#" - { - export( - filter:{ - protocol: "periodic time series", - sourceId: "src1", - time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } - } - ,exportType:"csv") - }"#; - let res = schema.execute(query).await; - assert!(res.data.to_string().contains("periodictimeseries")); - - // export json file - let query = r#" - { - export( - filter:{ - protocol: "periodic time series", - sourceId: "ingest src 1", - time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } - } - ,exportType:"json") - }"#; - let res = schema.execute(query).await; - assert!(res.data.to_string().contains("periodictimeseries")); - } - - fn insert_time_series( - store: &RawEventStore, - id: &str, - start: i64, - data: Vec, - ) { - let mut key: Vec = Vec::new(); - key.extend_from_slice(id.as_bytes()); - key.push(0); - key.extend_from_slice(&start.to_be_bytes()); - let time_series_data = PeriodicTimeSeries { - id: id.to_string(), - data, - }; - let value = bincode::serialize(&time_series_data).unwrap(); - store.append(&key, &value).unwrap(); - } - - #[tokio::test] - async fn export_op_log() { - let schema = TestSchema::new(); - let store = schema.db.op_log_store().unwrap(); - - insert_op_log_raw_event(&store, "agent1", 1); - insert_op_log_raw_event(&store, "agent2", 1); - - // export csv file - let query = r#" - { - export( - filter:{ - protocol: "op_log", - sourceId: "src1", - } - ,exportType:"csv") - }"#; - let res = schema.execute(query).await; - assert!(res.data.to_string().contains("op_log")); - - // export json file - let query = r#" - { - export( - filter:{ - protocol: "op_log", - sourceId: "src1", - } - ,exportType:"json") - }"#; - let res = schema.execute(query).await; - assert!(res.data.to_string().contains("op_log")); - } - - fn insert_op_log_raw_event(store: &RawEventStore, agent_name: &str, timestamp: i64) { - let mut key: Vec = Vec::new(); - let agent_id = format!("{agent_name}@src1"); - key.extend_from_slice(agent_id.as_bytes()); - key.push(0); - key.extend_from_slice(×tamp.to_be_bytes()); - - let op_log_body = OpLog { - agent_name: agent_id.to_string(), - log_level: OpLogLevel::Info, - contents: "op_log".to_string(), - }; - - let value = bincode::serialize(&op_log_body).unwrap(); - - store.append(&key, &value).unwrap(); - } - - #[tokio::test] - async fn export_ftp() { - let schema = TestSchema::new(); - let store = schema.db.ftp_store().unwrap(); - - insert_ftp_raw_event(&store, "src1", Utc::now().timestamp_nanos_opt().unwrap()); - insert_ftp_raw_event( - &store, - "ingest src 1", - Utc::now().timestamp_nanos_opt().unwrap(), - ); - - // export csv file - let query = r#" - { - export( - filter:{ - protocol: "ftp", - sourceId: "src1", - time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } - origAddr: { start: "192.168.4.70", end: "192.168.4.78" } - respAddr: { start: "192.168.4.75", end: "192.168.4.79" } - origPort: { start: 46377, end: 46380 } - respPort: { start: 0, end: 200 } - } - ,exportType:"csv") - }"#; - let res = schema.execute(query).await; - assert!(res.data.to_string().contains("ftp")); - - // export json file - let query = r#" - { - export( - filter:{ - protocol: "ftp", - sourceId: "ingest src 1", - time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } - origAddr: { start: "192.168.4.70", end: "192.168.4.78" } - respAddr: { start: "192.168.4.75", end: "192.168.4.79" } - origPort: { start: 46377, end: 46380 } - respPort: { start: 0, end: 200 } - } - ,exportType:"json") - }"#; - let res = schema.execute(query).await; - assert!(res.data.to_string().contains("ftp")); - } - - fn insert_ftp_raw_event(store: &RawEventStore, source: &str, timestamp: i64) { - let mut key = Vec::with_capacity(source.len() + 1 + mem::size_of::()); - key.extend_from_slice(source.as_bytes()); - key.push(0); - key.extend(timestamp.to_be_bytes()); - - let ftp_body = Ftp { - orig_addr: "192.168.4.76".parse::().unwrap(), - orig_port: 46378, - resp_addr: "31.3.245.133".parse::().unwrap(), - resp_port: 80, - proto: 17, - last_time: 1, - user: "einsis".to_string(), - password: "aice".to_string(), - command: "command".to_string(), - reply_code: "500".to_string(), - reply_msg: "reply_message".to_string(), - data_passive: false, - data_orig_addr: "192.168.4.76".parse::().unwrap(), - data_resp_addr: "31.3.245.133".parse::().unwrap(), - data_resp_port: 80, - file: "ftp_file".to_string(), - file_size: 100, - file_id: "1".to_string(), - }; - let ser_ftp_body = bincode::serialize(&ftp_body).unwrap(); - - store.append(&key, &ser_ftp_body).unwrap(); - } - - #[tokio::test] - async fn export_mqtt() { - let schema = TestSchema::new(); - let store = schema.db.mqtt_store().unwrap(); - - insert_mqtt_raw_event(&store, "src1", Utc::now().timestamp_nanos_opt().unwrap()); - insert_mqtt_raw_event( - &store, - "ingest src 1", - Utc::now().timestamp_nanos_opt().unwrap(), - ); - - // export csv file - let query = r#" - { - export( - filter:{ - protocol: "mqtt", - sourceId: "src1", - time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } - origAddr: { start: "192.168.4.70", end: "192.168.4.78" } - respAddr: { start: "192.168.4.75", end: "192.168.4.79" } - origPort: { start: 46377, end: 46380 } - respPort: { start: 0, end: 200 } - } - ,exportType:"csv") - }"#; - let res = schema.execute(query).await; - assert!(res.data.to_string().contains("mqtt")); - - // export json file - let query = r#" - { - export( - filter:{ - protocol: "mqtt", - sourceId: "ingest src 1", - time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } - origAddr: { start: "192.168.4.70", end: "192.168.4.78" } - respAddr: { start: "192.168.4.75", end: "192.168.4.79" } - origPort: { start: 46377, end: 46380 } - respPort: { start: 0, end: 200 } - } - ,exportType:"json") - }"#; - let res = schema.execute(query).await; - assert!(res.data.to_string().contains("mqtt")); - } - - fn insert_mqtt_raw_event(store: &RawEventStore, source: &str, timestamp: i64) { - let mut key = Vec::with_capacity(source.len() + 1 + mem::size_of::()); - key.extend_from_slice(source.as_bytes()); - key.push(0); - key.extend(timestamp.to_be_bytes()); - - let mqtt_body = Mqtt { - orig_addr: "192.168.4.76".parse::().unwrap(), - orig_port: 46378, - resp_addr: "31.3.245.133".parse::().unwrap(), - resp_port: 80, - proto: 17, - last_time: 1, - protocol: "protocol".to_string(), - version: 1, - client_id: "client".to_string(), - connack_reason: 1, - subscribe: vec!["subscribe".to_string()], - suback_reason: vec![1], - }; - let ser_mqtt_body = bincode::serialize(&mqtt_body).unwrap(); - - store.append(&key, &ser_mqtt_body).unwrap(); - } - - #[tokio::test] - async fn export_ldap() { - let schema = TestSchema::new(); - let store = schema.db.ldap_store().unwrap(); - - insert_ldap_raw_event(&store, "src1", Utc::now().timestamp_nanos_opt().unwrap()); - insert_ldap_raw_event( - &store, - "ingest src 1", - Utc::now().timestamp_nanos_opt().unwrap(), - ); - - // export csv file - let query = r#" - { - export( - filter:{ - protocol: "ldap", - sourceId: "src1", - time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } - origAddr: { start: "192.168.4.70", end: "192.168.4.78" } - respAddr: { start: "192.168.4.75", end: "192.168.4.79" } - origPort: { start: 46377, end: 46380 } - respPort: { start: 0, end: 200 } - } - ,exportType:"csv") - }"#; - let res = schema.execute(query).await; - assert!(res.data.to_string().contains("ldap")); - - // export json file - let query = r#" - { - export( - filter:{ - protocol: "ldap", - sourceId: "ingest src 1", - time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } - origAddr: { start: "192.168.4.70", end: "192.168.4.78" } - respAddr: { start: "192.168.4.75", end: "192.168.4.79" } - origPort: { start: 46377, end: 46380 } - respPort: { start: 0, end: 200 } - } - ,exportType:"json") - }"#; - let res = schema.execute(query).await; - assert!(res.data.to_string().contains("ldap")); - } - - fn insert_ldap_raw_event(store: &RawEventStore, source: &str, timestamp: i64) { - let mut key = Vec::with_capacity(source.len() + 1 + mem::size_of::()); - key.extend_from_slice(source.as_bytes()); - key.push(0); - key.extend(timestamp.to_be_bytes()); - - let ldap_body = Ldap { - orig_addr: "192.168.4.76".parse::().unwrap(), - orig_port: 46378, - resp_addr: "31.3.245.133".parse::().unwrap(), - resp_port: 80, - proto: 17, - last_time: 1, - message_id: 1, - version: 1, - opcode: vec!["opcode".to_string()], - result: vec!["result".to_string()], - diagnostic_message: Vec::new(), - object: Vec::new(), - argument: Vec::new(), - }; - let ser_ldap_body = bincode::serialize(&ldap_body).unwrap(); - - store.append(&key, &ser_ldap_body).unwrap(); - } - - #[tokio::test] - async fn export_tls() { - let schema = TestSchema::new(); - let store = schema.db.tls_store().unwrap(); - - insert_tls_raw_event(&store, "src1", Utc::now().timestamp_nanos_opt().unwrap()); - insert_tls_raw_event( - &store, - "ingest src 1", - Utc::now().timestamp_nanos_opt().unwrap(), - ); - - // export csv file - let query = r#" - { - export( - filter:{ - protocol: "tls", - sourceId: "src1", - time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } - origAddr: { start: "192.168.4.70", end: "192.168.4.78" } - respAddr: { start: "192.168.4.75", end: "192.168.4.79" } - origPort: { start: 46377, end: 46380 } - respPort: { start: 0, end: 200 } - } - ,exportType:"csv") - }"#; - let res = schema.execute(query).await; - assert!(res.data.to_string().contains("tls")); - - // export json file - let query = r#" - { - export( - filter:{ - protocol: "tls", - sourceId: "ingest src 1", - time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } - origAddr: { start: "192.168.4.70", end: "192.168.4.78" } - respAddr: { start: "192.168.4.75", end: "192.168.4.79" } - origPort: { start: 46377, end: 46380 } - respPort: { start: 0, end: 200 } - } - ,exportType:"json") - }"#; - let res = schema.execute(query).await; - assert!(res.data.to_string().contains("tls")); - } - - fn insert_tls_raw_event(store: &RawEventStore, source: &str, timestamp: i64) { - let mut key = Vec::with_capacity(source.len() + 1 + mem::size_of::()); - key.extend_from_slice(source.as_bytes()); - key.push(0); - key.extend(timestamp.to_be_bytes()); - - let tls_body = Tls { - orig_addr: "192.168.4.76".parse::().unwrap(), - orig_port: 46378, - resp_addr: "31.3.245.133".parse::().unwrap(), - resp_port: 80, - proto: 17, - last_time: 1, - server_name: "server_name".to_string(), - alpn_protocol: "alpn_protocol".to_string(), - ja3: "ja3".to_string(), - version: "version".to_string(), - cipher: 10, - ja3s: "ja3s".to_string(), - serial: "serial".to_string(), - subject_country: "sub_country".to_string(), - subject_org_name: "sub_org".to_string(), - subject_common_name: "sub_comm".to_string(), - validity_not_before: 11, - validity_not_after: 12, - subject_alt_name: "sub_alt".to_string(), - issuer_country: "issuer_country".to_string(), - issuer_org_name: "issuer_org".to_string(), - issuer_org_unit_name: "issuer_org_unit".to_string(), - issuer_common_name: "issuer_comm".to_string(), - last_alert: 13, - }; - let ser_tls_body = bincode::serialize(&tls_body).unwrap(); - - store.append(&key, &ser_tls_body).unwrap(); - } - - #[tokio::test] - async fn export_smb() { - let schema = TestSchema::new(); - let store = schema.db.smb_store().unwrap(); - - insert_smb_raw_event(&store, "src1", Utc::now().timestamp_nanos_opt().unwrap()); - insert_smb_raw_event( - &store, - "ingest src 1", - Utc::now().timestamp_nanos_opt().unwrap(), - ); - - // export csv file - let query = r#" - { - export( - filter:{ - protocol: "smb", - sourceId: "src1", - time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } - origAddr: { start: "192.168.4.70", end: "192.168.4.78" } - respAddr: { start: "192.168.4.75", end: "192.168.4.79" } - origPort: { start: 46377, end: 46380 } - respPort: { start: 0, end: 200 } - } - ,exportType:"csv") - }"#; - let res = schema.execute(query).await; - assert!(res.data.to_string().contains("smb")); - - // export json file - let query = r#" - { - export( - filter:{ - protocol: "smb", - sourceId: "ingest src 1", - time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } - origAddr: { start: "192.168.4.70", end: "192.168.4.78" } - respAddr: { start: "192.168.4.75", end: "192.168.4.79" } - origPort: { start: 46377, end: 46380 } - respPort: { start: 0, end: 200 } - } - ,exportType:"json") - }"#; - let res = schema.execute(query).await; - assert!(res.data.to_string().contains("smb")); - } - - fn insert_smb_raw_event(store: &RawEventStore, source: &str, timestamp: i64) { - let mut key = Vec::with_capacity(source.len() + 1 + mem::size_of::()); - key.extend_from_slice(source.as_bytes()); - key.push(0); - key.extend(timestamp.to_be_bytes()); - - let smb_body = Smb { - orig_addr: "192.168.4.76".parse::().unwrap(), - orig_port: 46378, - resp_addr: "31.3.245.133".parse::().unwrap(), - resp_port: 80, - proto: 17, - last_time: 1, - command: 0, - path: "something/path".to_string(), - service: "service".to_string(), - file_name: "fine_name".to_string(), - file_size: 10, - resource_type: 20, - fid: 30, - create_time: 10000000, - access_time: 20000000, - write_time: 10000000, - change_time: 20000000, - }; - let ser_smb_body = bincode::serialize(&smb_body).unwrap(); - - store.append(&key, &ser_smb_body).unwrap(); - } - - #[tokio::test] - async fn export_nfs() { - let schema = TestSchema::new(); - let store = schema.db.nfs_store().unwrap(); - - insert_nfs_raw_event(&store, "src1", Utc::now().timestamp_nanos_opt().unwrap()); - insert_nfs_raw_event( - &store, - "ingest src 1", - Utc::now().timestamp_nanos_opt().unwrap(), - ); - - // export csv file - let query = r#" - { - export( - filter:{ - protocol: "nfs", - sourceId: "src1", - time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } - origAddr: { start: "192.168.4.70", end: "192.168.4.78" } - respAddr: { start: "192.168.4.75", end: "192.168.4.79" } - origPort: { start: 46377, end: 46380 } - respPort: { start: 0, end: 200 } - } - ,exportType:"csv") - }"#; - let res = schema.execute(query).await; - assert!(res.data.to_string().contains("nfs")); - - // export json file - let query = r#" - { - export( - filter:{ - protocol: "nfs", - sourceId: "ingest src 1", - time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } - origAddr: { start: "192.168.4.70", end: "192.168.4.78" } - respAddr: { start: "192.168.4.75", end: "192.168.4.79" } - origPort: { start: 46377, end: 46380 } - respPort: { start: 0, end: 200 } - } - ,exportType:"json") - }"#; - let res = schema.execute(query).await; - assert!(res.data.to_string().contains("nfs")); - } - - fn insert_nfs_raw_event(store: &RawEventStore, source: &str, timestamp: i64) { - let mut key = Vec::with_capacity(source.len() + 1 + mem::size_of::()); - key.extend_from_slice(source.as_bytes()); - key.push(0); - key.extend(timestamp.to_be_bytes()); - - let nfs_body = Nfs { - orig_addr: "192.168.4.76".parse::().unwrap(), - orig_port: 46378, - resp_addr: "31.3.245.133".parse::().unwrap(), - resp_port: 80, - proto: 17, - last_time: 1, - read_files: vec![], - write_files: vec![], - }; - let ser_nfs_body = bincode::serialize(&nfs_body).unwrap(); - - store.append(&key, &ser_nfs_body).unwrap(); - } -} diff --git a/src/graphql/export/tests.rs b/src/graphql/export/tests.rs new file mode 100644 index 0000000..602d396 --- /dev/null +++ b/src/graphql/export/tests.rs @@ -0,0 +1,1413 @@ +use crate::graphql::tests::TestSchema; +use crate::storage::RawEventStore; +use chrono::{Duration, Utc}; +use giganto_client::ingest::{ + log::{Log, OpLog, OpLogLevel}, + network::{ + Conn, DceRpc, Dns, Ftp, Http, Kerberos, Ldap, Mqtt, Nfs, Ntlm, Rdp, Smb, Smtp, Ssh, Tls, + }, + timeseries::PeriodicTimeSeries, +}; +use std::mem; +use std::net::IpAddr; + +#[tokio::test] +async fn invalid_query() { + let schema = TestSchema::new(); + + // invalid filter combine1 (log + addr) + let query = r#" + { + export( + filter:{ + protocol: "log", + sourceId: "src1", + time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } + origAddr: { start: "192.168.4.72", end: "192.168.4.79" } + } + ,exportType:"json") + }"#; + let res = schema.execute(query).await; + assert_eq!(res.data.to_string(), "null"); + + // invalid filter combine2 (network proto + kind) + let query = r#" + { + export( + filter:{ + protocol: "conn", + sourceId: "src1", + kind: "log1" + } + ,exportType:"json") + }"#; + let res = schema.execute(query).await; + assert_eq!(res.data.to_string(), "null"); + + // invalid export format + let query = r#" + { + export( + filter:{ + protocol: "conn", + sourceId: "src1", + } + ,exportType:"ppt") + }"#; + let res = schema.execute(query).await; + assert_eq!(res.data.to_string(), "null"); + + // invalid protocol format + let query = r#" + { + export( + filter:{ + protocol: "invalid_proto", + sourceId: "src1", + } + ,exportType:"json") + }"#; + let res = schema.execute(query).await; + assert_eq!(res.data.to_string(), "null"); +} + +#[tokio::test] +async fn export_conn() { + let schema = TestSchema::new(); + let store = schema.db.conn_store().unwrap(); + + insert_conn_raw_event(&store, "src1", Utc::now().timestamp_nanos_opt().unwrap()); + insert_conn_raw_event( + &store, + "ingest src 1", + Utc::now().timestamp_nanos_opt().unwrap(), + ); + + // export csv file + let query = r#" + { + export( + filter:{ + protocol: "conn", + sourceId: "src1", + time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } + origAddr: { start: "192.168.4.72", end: "192.168.4.79" } + respAddr: { start: "192.168.4.75", end: "192.168.4.79" } + origPort: { start: 46378, end: 46379 } + respPort: { start: 50, end: 200 } + } + ,exportType:"csv") + }"#; + let res = schema.execute(query).await; + assert!(res.data.to_string().contains("conn")); + + // export json file + let query = r#" + { + export( + filter:{ + protocol: "conn", + sourceId: "ingest src 1", + time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } + origAddr: { start: "192.168.4.72", end: "192.168.4.79" } + respAddr: { start: "192.168.4.75", end: "192.168.4.79" } + origPort: { start: 46378, end: 46379 } + respPort: { start: 50, end: 200 } + } + ,exportType:"json") + }"#; + let res = schema.execute(query).await; + assert!(res.data.to_string().contains("conn")); +} + +fn insert_conn_raw_event(store: &RawEventStore, source: &str, timestamp: i64) { + let mut key = Vec::with_capacity(source.len() + 1 + mem::size_of::()); + key.extend_from_slice(source.as_bytes()); + key.push(0); + key.extend(timestamp.to_be_bytes()); + + let tmp_dur = Duration::nanoseconds(12345); + let conn_body = Conn { + orig_addr: "192.168.4.76".parse::().unwrap(), + orig_port: 46378, + resp_addr: "192.168.4.76".parse::().unwrap(), + resp_port: 80, + proto: 6, + duration: tmp_dur.num_nanoseconds().unwrap(), + service: "-".to_string(), + orig_bytes: 77, + resp_bytes: 295, + orig_pkts: 397, + resp_pkts: 511, + }; + let ser_conn_body = bincode::serialize(&conn_body).unwrap(); + + store.append(&key, &ser_conn_body).unwrap(); +} + +#[tokio::test] +async fn export_dns() { + let schema = TestSchema::new(); + let store = schema.db.dns_store().unwrap(); + + insert_dns_raw_event(&store, "src1", Utc::now().timestamp_nanos_opt().unwrap()); + insert_dns_raw_event( + &store, + "ingest src 1", + Utc::now().timestamp_nanos_opt().unwrap(), + ); + + // export csv file + let query = r#" + { + export( + filter:{ + protocol: "dns", + sourceId: "src1", + time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } + origAddr: { start: "192.168.4.70", end: "192.168.4.78" } + respAddr: { start: "31.3.245.100", end: "31.3.245.245" } + origPort: { start: 46377, end: 46380 } + respPort: { start: 0, end: 200 } + } + ,exportType:"csv") + }"#; + let res = schema.execute(query).await; + assert!(res.data.to_string().contains("dns")); + + // export json file + let query = r#" + { + export( + filter:{ + protocol: "dns", + sourceId: "ingest src 1", + time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } + origAddr: { start: "192.168.4.70", end: "192.168.4.78" } + respAddr: { start: "31.3.245.100", end: "31.3.245.245" } + origPort: { start: 46377, end: 46380 } + respPort: { start: 0, end: 200 } + } + ,exportType:"json") + }"#; + let res = schema.execute(query).await; + assert!(res.data.to_string().contains("dns")); +} + +fn insert_dns_raw_event(store: &RawEventStore, source: &str, timestamp: i64) { + let mut key = Vec::with_capacity(source.len() + 1 + mem::size_of::()); + key.extend_from_slice(source.as_bytes()); + key.push(0); + key.extend(timestamp.to_be_bytes()); + + let dns_body = Dns { + orig_addr: "192.168.4.76".parse::().unwrap(), + orig_port: 46378, + resp_addr: "31.3.245.133".parse::().unwrap(), + resp_port: 80, + proto: 17, + last_time: 1, + query: "Hello Server Hello Server Hello Server".to_string(), + answer: vec!["1.1.1.1".to_string()], + trans_id: 1, + rtt: 1, + qclass: 0, + qtype: 0, + rcode: 0, + aa_flag: false, + tc_flag: false, + rd_flag: false, + ra_flag: false, + ttl: vec![1; 5], + }; + let ser_dns_body = bincode::serialize(&dns_body).unwrap(); + + store.append(&key, &ser_dns_body).unwrap(); +} + +#[tokio::test] +async fn export_http() { + let schema = TestSchema::new(); + let store = schema.db.http_store().unwrap(); + + insert_http_raw_event(&store, "src1", Utc::now().timestamp_nanos_opt().unwrap()); + insert_http_raw_event( + &store, + "ingest src 1", + Utc::now().timestamp_nanos_opt().unwrap(), + ); + + // export csv file + let query = r#" + { + export( + filter:{ + protocol: "http", + sourceId: "src1", + time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } + origAddr: { start: "192.168.4.75", end: "192.168.4.79" } + respAddr: { start: "192.168.4.75", end: "192.168.4.79" } + origPort: { start: 46377, end: 46380 } + respPort: { start: 0, end: 200 } + } + ,exportType:"csv") + }"#; + let res = schema.execute(query).await; + assert!(res.data.to_string().contains("http")); + + // export json file + let query = r#" + { + export( + filter:{ + protocol: "http", + sourceId: "ingest src 1", + time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } + origAddr: { start: "192.168.4.75", end: "192.168.4.79" } + respAddr: { start: "192.168.4.75", end: "192.168.4.79" } + origPort: { start: 46377, end: 46380 } + respPort: { start: 0, end: 200 } + } + ,exportType:"json") + }"#; + let res = schema.execute(query).await; + assert!(res.data.to_string().contains("http")); +} + +fn insert_http_raw_event(store: &RawEventStore, source: &str, timestamp: i64) { + let mut key = Vec::with_capacity(source.len() + 1 + mem::size_of::()); + key.extend_from_slice(source.as_bytes()); + key.push(0); + key.extend(timestamp.to_be_bytes()); + + let http_body = Http { + orig_addr: "192.168.4.76".parse::().unwrap(), + orig_port: 46378, + resp_addr: "192.168.4.76".parse::().unwrap(), + resp_port: 80, + proto: 6, + last_time: 1, + method: "POST".to_string(), + host: "einsis".to_string(), + uri: "/einsis.gif".to_string(), + referrer: "einsis.com".to_string(), + version: String::new(), + user_agent: "giganto".to_string(), + request_len: 0, + response_len: 0, + status_code: 200, + status_msg: String::new(), + username: String::new(), + password: String::new(), + cookie: String::new(), + content_encoding: String::new(), + content_type: String::new(), + cache_control: String::new(), + orig_filenames: Vec::new(), + orig_mime_types: Vec::new(), + resp_filenames: Vec::new(), + resp_mime_types: Vec::new(), + }; + let ser_http_body = bincode::serialize(&http_body).unwrap(); + + store.append(&key, &ser_http_body).unwrap(); +} + +#[tokio::test] +async fn export_rdp() { + let schema = TestSchema::new(); + let store = schema.db.rdp_store().unwrap(); + + insert_rdp_raw_event(&store, "src1", Utc::now().timestamp_nanos_opt().unwrap()); + insert_rdp_raw_event( + &store, + "ingest src 1", + Utc::now().timestamp_nanos_opt().unwrap(), + ); + + // export csv file + let query = r#" + { + export( + filter:{ + protocol: "rdp", + sourceId: "src1", + time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } + origAddr: { start: "192.168.4.75", end: "192.168.4.79" } + respAddr: { start: "192.168.4.75", end: "192.168.4.79" } + origPort: { start: 46377, end: 46380 } + respPort: { start: 0, end: 200 } + } + ,exportType:"csv") + }"#; + let res = schema.execute(query).await; + assert!(res.data.to_string().contains("rdp")); + + // export json file + let query = r#" + { + export( + filter:{ + protocol: "rdp", + sourceId: "ingest src 1", + time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } + origAddr: { start: "192.168.4.70", end: "192.168.4.78" } + respAddr: { start: "192.168.4.75", end: "192.168.4.79" } + origPort: { start: 46377, end: 46380 } + respPort: { start: 0, end: 200 } + } + ,exportType:"json") + }"#; + let res = schema.execute(query).await; + assert!(res.data.to_string().contains("rdp")); +} + +fn insert_rdp_raw_event(store: &RawEventStore, source: &str, timestamp: i64) { + let mut key = Vec::with_capacity(source.len() + 1 + mem::size_of::()); + key.extend_from_slice(source.as_bytes()); + key.push(0); + key.extend(timestamp.to_be_bytes()); + + let rdp_body = Rdp { + orig_addr: "192.168.4.76".parse::().unwrap(), + orig_port: 46378, + resp_addr: "192.168.4.76".parse::().unwrap(), + resp_port: 80, + proto: 6, + last_time: 1, + cookie: "rdp_test".to_string(), + }; + let ser_rdp_body = bincode::serialize(&rdp_body).unwrap(); + + store.append(&key, &ser_rdp_body).unwrap(); +} + +#[tokio::test] +async fn export_smtp() { + let schema = TestSchema::new(); + let store = schema.db.smtp_store().unwrap(); + + insert_smtp_raw_event(&store, "src1", Utc::now().timestamp_nanos_opt().unwrap()); + insert_smtp_raw_event( + &store, + "ingest src 1", + Utc::now().timestamp_nanos_opt().unwrap(), + ); + + // export csv file + let query = r#" + { + export( + filter:{ + protocol: "smtp", + sourceId: "src1", + time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } + origAddr: { start: "192.168.4.70", end: "192.168.4.78" } + respAddr: { start: "192.168.4.70", end: "192.168.4.78" } + origPort: { start: 46377, end: 46380 } + respPort: { start: 0, end: 200 } + } + ,exportType:"csv") + }"#; + let res = schema.execute(query).await; + assert!(res.data.to_string().contains("smtp")); + + // export json file + let query = r#" + { + export( + filter:{ + protocol: "smtp", + sourceId: "ingest src 1", + time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } + origAddr: { start: "192.168.4.70", end: "192.168.4.78" } + respAddr: { start: "192.168.4.70", end: "192.168.4.78" } + origPort: { start: 46377, end: 46380 } + respPort: { start: 0, end: 200 } + } + ,exportType:"json") + }"#; + let res = schema.execute(query).await; + assert!(res.data.to_string().contains("smtp")); +} + +fn insert_smtp_raw_event(store: &RawEventStore, source: &str, timestamp: i64) { + let mut key = Vec::with_capacity(source.len() + 1 + mem::size_of::()); + key.extend_from_slice(source.as_bytes()); + key.push(0); + key.extend(timestamp.to_be_bytes()); + + let smtp_body = Smtp { + orig_addr: "192.168.4.76".parse::().unwrap(), + orig_port: 46378, + resp_addr: "192.168.4.76".parse::().unwrap(), + resp_port: 80, + proto: 6, + last_time: 1, + mailfrom: "mailfrom".to_string(), + date: "date".to_string(), + from: "from".to_string(), + to: "to".to_string(), + subject: "subject".to_string(), + agent: "agent".to_string(), + }; + let ser_smtp_body = bincode::serialize(&smtp_body).unwrap(); + + store.append(&key, &ser_smtp_body).unwrap(); +} + +#[tokio::test] +async fn export_ntlm() { + let schema = TestSchema::new(); + let store = schema.db.ntlm_store().unwrap(); + + insert_ntlm_raw_event(&store, "src1", Utc::now().timestamp_nanos_opt().unwrap()); + insert_ntlm_raw_event( + &store, + "ingest src 1", + Utc::now().timestamp_nanos_opt().unwrap(), + ); + + // export csv file + let query = r#" + { + export( + filter:{ + protocol: "ntlm", + sourceId: "src1", + time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } + origAddr: { start: "192.168.4.72", end: "192.168.4.79" } + respAddr: { start: "192.168.4.75", end: "192.168.4.79" } + origPort: { start: 46378, end: 46379 } + respPort: { start: 50, end: 200 } + } + ,exportType:"csv") + }"#; + let res = schema.execute(query).await; + assert!(res.data.to_string().contains("ntlm")); + + // export json file + let query = r#" + { + export( + filter:{ + protocol: "ntlm", + sourceId: "ingest src 1", + time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } + origAddr: { start: "192.168.4.72", end: "192.168.4.79" } + respAddr: { start: "192.168.4.75", end: "192.168.4.79" } + origPort: { start: 46378, end: 46379 } + respPort: { start: 50, end: 200 } + } + ,exportType:"json") + }"#; + let res = schema.execute(query).await; + assert!(res.data.to_string().contains("ntlm")); +} + +fn insert_ntlm_raw_event(store: &RawEventStore, source: &str, timestamp: i64) { + let mut key = Vec::with_capacity(source.len() + 1 + mem::size_of::()); + key.extend_from_slice(source.as_bytes()); + key.push(0); + key.extend(timestamp.to_be_bytes()); + + let ntlm_body = Ntlm { + orig_addr: "192.168.4.76".parse::().unwrap(), + orig_port: 46378, + resp_addr: "192.168.4.76".parse::().unwrap(), + resp_port: 80, + proto: 6, + last_time: 1, + username: "bly".to_string(), + hostname: "host".to_string(), + domainname: "domain".to_string(), + server_nb_computer_name: "NB".to_string(), + server_dns_computer_name: "dns".to_string(), + server_tree_name: "tree".to_string(), + success: "tf".to_string(), + }; + let ser_ntlm_body = bincode::serialize(&ntlm_body).unwrap(); + + store.append(&key, &ser_ntlm_body).unwrap(); +} + +#[tokio::test] +async fn export_kerberos() { + let schema = TestSchema::new(); + let store = schema.db.kerberos_store().unwrap(); + + insert_kerberos_raw_event(&store, "src1", Utc::now().timestamp_nanos_opt().unwrap()); + insert_kerberos_raw_event( + &store, + "ingest src 1", + Utc::now().timestamp_nanos_opt().unwrap(), + ); + + // export csv file + let query = r#" + { + export( + filter:{ + protocol: "kerberos", + sourceId: "src1", + time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } + origAddr: { start: "192.168.4.72", end: "192.168.4.79" } + respAddr: { start: "192.168.4.75", end: "192.168.4.79" } + origPort: { start: 46378, end: 46379 } + respPort: { start: 50, end: 200 } + } + ,exportType:"csv") + }"#; + let res = schema.execute(query).await; + assert!(res.data.to_string().contains("kerberos")); + + // export json file + let query = r#" + { + export( + filter:{ + protocol: "kerberos", + sourceId: "ingest src 1", + time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } + origAddr: { start: "192.168.4.72", end: "192.168.4.79" } + respAddr: { start: "192.168.4.75", end: "192.168.4.79" } + origPort: { start: 46378, end: 46379 } + respPort: { start: 50, end: 200 } + } + ,exportType:"json") + }"#; + let res = schema.execute(query).await; + assert!(res.data.to_string().contains("kerberos")); +} + +fn insert_kerberos_raw_event(store: &RawEventStore, source: &str, timestamp: i64) { + let mut key = Vec::with_capacity(source.len() + 1 + mem::size_of::()); + key.extend_from_slice(source.as_bytes()); + key.push(0); + key.extend(timestamp.to_be_bytes()); + + let kerberos_body = Kerberos { + orig_addr: "192.168.4.76".parse::().unwrap(), + orig_port: 46378, + resp_addr: "192.168.4.76".parse::().unwrap(), + resp_port: 80, + proto: 6, + last_time: 1, + client_time: 1, + server_time: 1, + error_code: 1, + client_realm: "client_realm".to_string(), + cname_type: 1, + client_name: vec!["client_name".to_string()], + realm: "realm".to_string(), + sname_type: 1, + service_name: vec!["service_name".to_string()], + }; + let ser_kerberos_body = bincode::serialize(&kerberos_body).unwrap(); + + store.append(&key, &ser_kerberos_body).unwrap(); +} + +#[tokio::test] +async fn export_ssh() { + let schema = TestSchema::new(); + let store = schema.db.ssh_store().unwrap(); + + insert_ssh_raw_event(&store, "src1", Utc::now().timestamp_nanos_opt().unwrap()); + insert_ssh_raw_event( + &store, + "ingest src 1", + Utc::now().timestamp_nanos_opt().unwrap(), + ); + + // export csv file + let query = r#" + { + export( + filter:{ + protocol: "ssh", + sourceId: "src1", + time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } + origAddr: { start: "192.168.4.72", end: "192.168.4.79" } + respAddr: { start: "192.168.4.75", end: "192.168.4.79" } + origPort: { start: 46377, end: 46380 } + respPort: { start: 0, end: 200 } + } + ,exportType:"csv") + }"#; + let res = schema.execute(query).await; + assert!(res.data.to_string().contains("ssh")); + + // export json file + let query = r#" + { + export( + filter:{ + protocol: "ssh", + sourceId: "ingest src 1", + time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } + origAddr: { start: "192.168.4.72", end: "192.168.4.79" } + respAddr: { start: "192.168.4.75", end: "192.168.4.79" } + origPort: { start: 46377, end: 46380 } + respPort: { start: 0, end: 200 } + } + ,exportType:"json") + }"#; + let res = schema.execute(query).await; + assert!(res.data.to_string().contains("ssh")); +} +fn insert_ssh_raw_event(store: &RawEventStore, source: &str, timestamp: i64) { + let mut key = Vec::with_capacity(source.len() + 1 + mem::size_of::()); + key.extend_from_slice(source.as_bytes()); + key.push(0); + key.extend(timestamp.to_be_bytes()); + + let ssh_body = Ssh { + orig_addr: "192.168.4.76".parse::().unwrap(), + orig_port: 46378, + resp_addr: "192.168.4.76".parse::().unwrap(), + resp_port: 80, + proto: 6, + last_time: 1, + version: 01, + auth_success: "auth_success".to_string(), + auth_attempts: 3, + direction: "direction".to_string(), + client: "client".to_string(), + server: "server".to_string(), + cipher_alg: "cipher_alg".to_string(), + mac_alg: "mac_alg".to_string(), + compression_alg: "compression_alg".to_string(), + kex_alg: "kex_alg".to_string(), + host_key_alg: "host_key_alg".to_string(), + host_key: "host_key".to_string(), + }; + let ser_ssh_body = bincode::serialize(&ssh_body).unwrap(); + + store.append(&key, &ser_ssh_body).unwrap(); +} + +#[tokio::test] +async fn export_dce_rpc() { + let schema = TestSchema::new(); + let store = schema.db.dce_rpc_store().unwrap(); + + insert_dce_rpc_raw_event(&store, "src1", Utc::now().timestamp_nanos_opt().unwrap()); + insert_dce_rpc_raw_event( + &store, + "ingest src 1", + Utc::now().timestamp_nanos_opt().unwrap(), + ); + + // export csv file + let query = r#" + { + export( + filter:{ + protocol: "dce rpc", + sourceId: "src1", + time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } + origAddr: { start: "192.168.4.70", end: "192.168.4.78" } + respAddr: { start: "192.168.4.75", end: "192.168.4.79" } + origPort: { start: 46377, end: 46380 } + respPort: { start: 0, end: 200 } + } + ,exportType:"csv") + }"#; + let res = schema.execute(query).await; + assert!(res.data.to_string().contains("dcerpc")); + + // export json file + let query = r#" + { + export( + filter:{ + protocol: "dce rpc", + sourceId: "ingest src 1", + time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } + origAddr: { start: "192.168.4.70", end: "192.168.4.78" } + respAddr: { start: "192.168.4.75", end: "192.168.4.79" } + origPort: { start: 46377, end: 46380 } + respPort: { start: 0, end: 200 } + } + ,exportType:"json") + }"#; + let res = schema.execute(query).await; + assert!(res.data.to_string().contains("dcerpc")); +} +fn insert_dce_rpc_raw_event(store: &RawEventStore, source: &str, timestamp: i64) { + let mut key = Vec::with_capacity(source.len() + 1 + mem::size_of::()); + key.extend_from_slice(source.as_bytes()); + key.push(0); + key.extend(timestamp.to_be_bytes()); + + let dce_rpc_body = DceRpc { + orig_addr: "192.168.4.76".parse::().unwrap(), + orig_port: 46378, + resp_addr: "192.168.4.76".parse::().unwrap(), + resp_port: 80, + proto: 6, + last_time: 1, + rtt: 3, + named_pipe: "named_pipe".to_string(), + endpoint: "endpoint".to_string(), + operation: "operation".to_string(), + }; + let ser_dce_rpc_body = bincode::serialize(&dce_rpc_body).unwrap(); + + store.append(&key, &ser_dce_rpc_body).unwrap(); +} + +#[tokio::test] +async fn export_log() { + let schema = TestSchema::new(); + let store = schema.db.log_store().unwrap(); + + insert_log_raw_event( + &store, + "src1", + Utc::now().timestamp_nanos_opt().unwrap(), + "kind1", + b"log1", + ); + insert_log_raw_event( + &store, + "ingest src 1", + Utc::now().timestamp_nanos_opt().unwrap(), + "kind2", + b"log2", + ); + + // export csv file + let query = r#" + { + export( + filter:{ + protocol: "log", + sourceId: "src1", + kind: "kind1", + time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } + } + ,exportType:"csv") + }"#; + let res = schema.execute(query).await; + assert!(res.data.to_string().contains("log")); + + // export json file + let query = r#" + { + export( + filter:{ + protocol: "log", + sourceId: "ingest src 1", + kind: "kind2", + time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } + } + ,exportType:"json") + }"#; + let res = schema.execute(query).await; + assert!(res.data.to_string().contains("log")); +} + +fn insert_log_raw_event( + store: &RawEventStore, + source: &str, + timestamp: i64, + kind: &str, + body: &[u8], +) { + let mut key: Vec = Vec::new(); + key.extend_from_slice(source.as_bytes()); + key.push(0); + key.extend_from_slice(kind.as_bytes()); + key.push(0); + key.extend_from_slice(×tamp.to_be_bytes()); + let log_body = Log { + kind: kind.to_string(), + log: body.to_vec(), + }; + let value = bincode::serialize(&log_body).unwrap(); + store.append(&key, &value).unwrap(); +} + +#[tokio::test] +async fn export_time_series() { + let schema = TestSchema::new(); + let store = schema.db.periodic_time_series_store().unwrap(); + + insert_time_series( + &store, + "src1", + Utc::now().timestamp_nanos_opt().unwrap(), + vec![0.0; 12], + ); + insert_time_series( + &store, + "ingest src 1", + Utc::now().timestamp_nanos_opt().unwrap(), + vec![0.0; 12], + ); + + // export csv file + let query = r#" + { + export( + filter:{ + protocol: "periodic time series", + sourceId: "src1", + time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } + } + ,exportType:"csv") + }"#; + let res = schema.execute(query).await; + assert!(res.data.to_string().contains("periodictimeseries")); + + // export json file + let query = r#" + { + export( + filter:{ + protocol: "periodic time series", + sourceId: "ingest src 1", + time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } + } + ,exportType:"json") + }"#; + let res = schema.execute(query).await; + assert!(res.data.to_string().contains("periodictimeseries")); +} + +fn insert_time_series( + store: &RawEventStore, + id: &str, + start: i64, + data: Vec, +) { + let mut key: Vec = Vec::new(); + key.extend_from_slice(id.as_bytes()); + key.push(0); + key.extend_from_slice(&start.to_be_bytes()); + let time_series_data = PeriodicTimeSeries { + id: id.to_string(), + data, + }; + let value = bincode::serialize(&time_series_data).unwrap(); + store.append(&key, &value).unwrap(); +} + +#[tokio::test] +async fn export_op_log() { + let schema = TestSchema::new(); + let store = schema.db.op_log_store().unwrap(); + + insert_op_log_raw_event(&store, "agent1", 1); + insert_op_log_raw_event(&store, "agent2", 1); + + // export csv file + let query = r#" + { + export( + filter:{ + protocol: "op_log", + sourceId: "src1", + } + ,exportType:"csv") + }"#; + let res = schema.execute(query).await; + assert!(res.data.to_string().contains("op_log")); + + // export json file + let query = r#" + { + export( + filter:{ + protocol: "op_log", + sourceId: "src1", + } + ,exportType:"json") + }"#; + let res = schema.execute(query).await; + assert!(res.data.to_string().contains("op_log")); +} + +fn insert_op_log_raw_event(store: &RawEventStore, agent_name: &str, timestamp: i64) { + let mut key: Vec = Vec::new(); + let agent_id = format!("{agent_name}@src1"); + key.extend_from_slice(agent_id.as_bytes()); + key.push(0); + key.extend_from_slice(×tamp.to_be_bytes()); + + let op_log_body = OpLog { + agent_name: agent_id.to_string(), + log_level: OpLogLevel::Info, + contents: "op_log".to_string(), + }; + + let value = bincode::serialize(&op_log_body).unwrap(); + + store.append(&key, &value).unwrap(); +} + +#[tokio::test] +async fn export_ftp() { + let schema = TestSchema::new(); + let store = schema.db.ftp_store().unwrap(); + + insert_ftp_raw_event(&store, "src1", Utc::now().timestamp_nanos_opt().unwrap()); + insert_ftp_raw_event( + &store, + "ingest src 1", + Utc::now().timestamp_nanos_opt().unwrap(), + ); + + // export csv file + let query = r#" + { + export( + filter:{ + protocol: "ftp", + sourceId: "src1", + time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } + origAddr: { start: "192.168.4.70", end: "192.168.4.78" } + respAddr: { start: "192.168.4.75", end: "192.168.4.79" } + origPort: { start: 46377, end: 46380 } + respPort: { start: 0, end: 200 } + } + ,exportType:"csv") + }"#; + let res = schema.execute(query).await; + assert!(res.data.to_string().contains("ftp")); + + // export json file + let query = r#" + { + export( + filter:{ + protocol: "ftp", + sourceId: "ingest src 1", + time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } + origAddr: { start: "192.168.4.70", end: "192.168.4.78" } + respAddr: { start: "192.168.4.75", end: "192.168.4.79" } + origPort: { start: 46377, end: 46380 } + respPort: { start: 0, end: 200 } + } + ,exportType:"json") + }"#; + let res = schema.execute(query).await; + assert!(res.data.to_string().contains("ftp")); +} + +fn insert_ftp_raw_event(store: &RawEventStore, source: &str, timestamp: i64) { + let mut key = Vec::with_capacity(source.len() + 1 + mem::size_of::()); + key.extend_from_slice(source.as_bytes()); + key.push(0); + key.extend(timestamp.to_be_bytes()); + + let ftp_body = Ftp { + orig_addr: "192.168.4.76".parse::().unwrap(), + orig_port: 46378, + resp_addr: "31.3.245.133".parse::().unwrap(), + resp_port: 80, + proto: 17, + last_time: 1, + user: "einsis".to_string(), + password: "aice".to_string(), + command: "command".to_string(), + reply_code: "500".to_string(), + reply_msg: "reply_message".to_string(), + data_passive: false, + data_orig_addr: "192.168.4.76".parse::().unwrap(), + data_resp_addr: "31.3.245.133".parse::().unwrap(), + data_resp_port: 80, + file: "ftp_file".to_string(), + file_size: 100, + file_id: "1".to_string(), + }; + let ser_ftp_body = bincode::serialize(&ftp_body).unwrap(); + + store.append(&key, &ser_ftp_body).unwrap(); +} + +#[tokio::test] +async fn export_mqtt() { + let schema = TestSchema::new(); + let store = schema.db.mqtt_store().unwrap(); + + insert_mqtt_raw_event(&store, "src1", Utc::now().timestamp_nanos_opt().unwrap()); + insert_mqtt_raw_event( + &store, + "ingest src 1", + Utc::now().timestamp_nanos_opt().unwrap(), + ); + + // export csv file + let query = r#" + { + export( + filter:{ + protocol: "mqtt", + sourceId: "src1", + time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } + origAddr: { start: "192.168.4.70", end: "192.168.4.78" } + respAddr: { start: "192.168.4.75", end: "192.168.4.79" } + origPort: { start: 46377, end: 46380 } + respPort: { start: 0, end: 200 } + } + ,exportType:"csv") + }"#; + let res = schema.execute(query).await; + assert!(res.data.to_string().contains("mqtt")); + + // export json file + let query = r#" + { + export( + filter:{ + protocol: "mqtt", + sourceId: "ingest src 1", + time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } + origAddr: { start: "192.168.4.70", end: "192.168.4.78" } + respAddr: { start: "192.168.4.75", end: "192.168.4.79" } + origPort: { start: 46377, end: 46380 } + respPort: { start: 0, end: 200 } + } + ,exportType:"json") + }"#; + let res = schema.execute(query).await; + assert!(res.data.to_string().contains("mqtt")); +} + +fn insert_mqtt_raw_event(store: &RawEventStore, source: &str, timestamp: i64) { + let mut key = Vec::with_capacity(source.len() + 1 + mem::size_of::()); + key.extend_from_slice(source.as_bytes()); + key.push(0); + key.extend(timestamp.to_be_bytes()); + + let mqtt_body = Mqtt { + orig_addr: "192.168.4.76".parse::().unwrap(), + orig_port: 46378, + resp_addr: "31.3.245.133".parse::().unwrap(), + resp_port: 80, + proto: 17, + last_time: 1, + protocol: "protocol".to_string(), + version: 1, + client_id: "client".to_string(), + connack_reason: 1, + subscribe: vec!["subscribe".to_string()], + suback_reason: vec![1], + }; + let ser_mqtt_body = bincode::serialize(&mqtt_body).unwrap(); + + store.append(&key, &ser_mqtt_body).unwrap(); +} + +#[tokio::test] +async fn export_ldap() { + let schema = TestSchema::new(); + let store = schema.db.ldap_store().unwrap(); + + insert_ldap_raw_event(&store, "src1", Utc::now().timestamp_nanos_opt().unwrap()); + insert_ldap_raw_event( + &store, + "ingest src 1", + Utc::now().timestamp_nanos_opt().unwrap(), + ); + + // export csv file + let query = r#" + { + export( + filter:{ + protocol: "ldap", + sourceId: "src1", + time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } + origAddr: { start: "192.168.4.70", end: "192.168.4.78" } + respAddr: { start: "192.168.4.75", end: "192.168.4.79" } + origPort: { start: 46377, end: 46380 } + respPort: { start: 0, end: 200 } + } + ,exportType:"csv") + }"#; + let res = schema.execute(query).await; + assert!(res.data.to_string().contains("ldap")); + + // export json file + let query = r#" + { + export( + filter:{ + protocol: "ldap", + sourceId: "ingest src 1", + time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } + origAddr: { start: "192.168.4.70", end: "192.168.4.78" } + respAddr: { start: "192.168.4.75", end: "192.168.4.79" } + origPort: { start: 46377, end: 46380 } + respPort: { start: 0, end: 200 } + } + ,exportType:"json") + }"#; + let res = schema.execute(query).await; + assert!(res.data.to_string().contains("ldap")); +} + +fn insert_ldap_raw_event(store: &RawEventStore, source: &str, timestamp: i64) { + let mut key = Vec::with_capacity(source.len() + 1 + mem::size_of::()); + key.extend_from_slice(source.as_bytes()); + key.push(0); + key.extend(timestamp.to_be_bytes()); + + let ldap_body = Ldap { + orig_addr: "192.168.4.76".parse::().unwrap(), + orig_port: 46378, + resp_addr: "31.3.245.133".parse::().unwrap(), + resp_port: 80, + proto: 17, + last_time: 1, + message_id: 1, + version: 1, + opcode: vec!["opcode".to_string()], + result: vec!["result".to_string()], + diagnostic_message: Vec::new(), + object: Vec::new(), + argument: Vec::new(), + }; + let ser_ldap_body = bincode::serialize(&ldap_body).unwrap(); + + store.append(&key, &ser_ldap_body).unwrap(); +} + +#[tokio::test] +async fn export_tls() { + let schema = TestSchema::new(); + let store = schema.db.tls_store().unwrap(); + + insert_tls_raw_event(&store, "src1", Utc::now().timestamp_nanos_opt().unwrap()); + insert_tls_raw_event( + &store, + "ingest src 1", + Utc::now().timestamp_nanos_opt().unwrap(), + ); + + // export csv file + let query = r#" + { + export( + filter:{ + protocol: "tls", + sourceId: "src1", + time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } + origAddr: { start: "192.168.4.70", end: "192.168.4.78" } + respAddr: { start: "192.168.4.75", end: "192.168.4.79" } + origPort: { start: 46377, end: 46380 } + respPort: { start: 0, end: 200 } + } + ,exportType:"csv") + }"#; + let res = schema.execute(query).await; + assert!(res.data.to_string().contains("tls")); + + // export json file + let query = r#" + { + export( + filter:{ + protocol: "tls", + sourceId: "ingest src 1", + time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } + origAddr: { start: "192.168.4.70", end: "192.168.4.78" } + respAddr: { start: "192.168.4.75", end: "192.168.4.79" } + origPort: { start: 46377, end: 46380 } + respPort: { start: 0, end: 200 } + } + ,exportType:"json") + }"#; + let res = schema.execute(query).await; + assert!(res.data.to_string().contains("tls")); +} + +fn insert_tls_raw_event(store: &RawEventStore, source: &str, timestamp: i64) { + let mut key = Vec::with_capacity(source.len() + 1 + mem::size_of::()); + key.extend_from_slice(source.as_bytes()); + key.push(0); + key.extend(timestamp.to_be_bytes()); + + let tls_body = Tls { + orig_addr: "192.168.4.76".parse::().unwrap(), + orig_port: 46378, + resp_addr: "31.3.245.133".parse::().unwrap(), + resp_port: 80, + proto: 17, + last_time: 1, + server_name: "server_name".to_string(), + alpn_protocol: "alpn_protocol".to_string(), + ja3: "ja3".to_string(), + version: "version".to_string(), + cipher: 10, + ja3s: "ja3s".to_string(), + serial: "serial".to_string(), + subject_country: "sub_country".to_string(), + subject_org_name: "sub_org".to_string(), + subject_common_name: "sub_comm".to_string(), + validity_not_before: 11, + validity_not_after: 12, + subject_alt_name: "sub_alt".to_string(), + issuer_country: "issuer_country".to_string(), + issuer_org_name: "issuer_org".to_string(), + issuer_org_unit_name: "issuer_org_unit".to_string(), + issuer_common_name: "issuer_comm".to_string(), + last_alert: 13, + }; + let ser_tls_body = bincode::serialize(&tls_body).unwrap(); + + store.append(&key, &ser_tls_body).unwrap(); +} + +#[tokio::test] +async fn export_smb() { + let schema = TestSchema::new(); + let store = schema.db.smb_store().unwrap(); + + insert_smb_raw_event(&store, "src1", Utc::now().timestamp_nanos_opt().unwrap()); + insert_smb_raw_event( + &store, + "ingest src 1", + Utc::now().timestamp_nanos_opt().unwrap(), + ); + + // export csv file + let query = r#" + { + export( + filter:{ + protocol: "smb", + sourceId: "src1", + time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } + origAddr: { start: "192.168.4.70", end: "192.168.4.78" } + respAddr: { start: "192.168.4.75", end: "192.168.4.79" } + origPort: { start: 46377, end: 46380 } + respPort: { start: 0, end: 200 } + } + ,exportType:"csv") + }"#; + let res = schema.execute(query).await; + assert!(res.data.to_string().contains("smb")); + + // export json file + let query = r#" + { + export( + filter:{ + protocol: "smb", + sourceId: "ingest src 1", + time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } + origAddr: { start: "192.168.4.70", end: "192.168.4.78" } + respAddr: { start: "192.168.4.75", end: "192.168.4.79" } + origPort: { start: 46377, end: 46380 } + respPort: { start: 0, end: 200 } + } + ,exportType:"json") + }"#; + let res = schema.execute(query).await; + assert!(res.data.to_string().contains("smb")); +} + +fn insert_smb_raw_event(store: &RawEventStore, source: &str, timestamp: i64) { + let mut key = Vec::with_capacity(source.len() + 1 + mem::size_of::()); + key.extend_from_slice(source.as_bytes()); + key.push(0); + key.extend(timestamp.to_be_bytes()); + + let smb_body = Smb { + orig_addr: "192.168.4.76".parse::().unwrap(), + orig_port: 46378, + resp_addr: "31.3.245.133".parse::().unwrap(), + resp_port: 80, + proto: 17, + last_time: 1, + command: 0, + path: "something/path".to_string(), + service: "service".to_string(), + file_name: "fine_name".to_string(), + file_size: 10, + resource_type: 20, + fid: 30, + create_time: 10000000, + access_time: 20000000, + write_time: 10000000, + change_time: 20000000, + }; + let ser_smb_body = bincode::serialize(&smb_body).unwrap(); + + store.append(&key, &ser_smb_body).unwrap(); +} + +#[tokio::test] +async fn export_nfs() { + let schema = TestSchema::new(); + let store = schema.db.nfs_store().unwrap(); + + insert_nfs_raw_event(&store, "src1", Utc::now().timestamp_nanos_opt().unwrap()); + insert_nfs_raw_event( + &store, + "ingest src 1", + Utc::now().timestamp_nanos_opt().unwrap(), + ); + + // export csv file + let query = r#" + { + export( + filter:{ + protocol: "nfs", + sourceId: "src1", + time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } + origAddr: { start: "192.168.4.70", end: "192.168.4.78" } + respAddr: { start: "192.168.4.75", end: "192.168.4.79" } + origPort: { start: 46377, end: 46380 } + respPort: { start: 0, end: 200 } + } + ,exportType:"csv") + }"#; + let res = schema.execute(query).await; + assert!(res.data.to_string().contains("nfs")); + + // export json file + let query = r#" + { + export( + filter:{ + protocol: "nfs", + sourceId: "ingest src 1", + time: { start: "1992-06-05T00:00:00Z", end: "2023-09-22T00:00:00Z" } + origAddr: { start: "192.168.4.70", end: "192.168.4.78" } + respAddr: { start: "192.168.4.75", end: "192.168.4.79" } + origPort: { start: 46377, end: 46380 } + respPort: { start: 0, end: 200 } + } + ,exportType:"json") + }"#; + let res = schema.execute(query).await; + assert!(res.data.to_string().contains("nfs")); +} + +fn insert_nfs_raw_event(store: &RawEventStore, source: &str, timestamp: i64) { + let mut key = Vec::with_capacity(source.len() + 1 + mem::size_of::()); + key.extend_from_slice(source.as_bytes()); + key.push(0); + key.extend(timestamp.to_be_bytes()); + + let nfs_body = Nfs { + orig_addr: "192.168.4.76".parse::().unwrap(), + orig_port: 46378, + resp_addr: "31.3.245.133".parse::().unwrap(), + resp_port: 80, + proto: 17, + last_time: 1, + read_files: vec![], + write_files: vec![], + }; + let ser_nfs_body = bincode::serialize(&nfs_body).unwrap(); + + store.append(&key, &ser_nfs_body).unwrap(); +} diff --git a/src/graphql/log.rs b/src/graphql/log.rs index f7b5546..2e60e9f 100644 --- a/src/graphql/log.rs +++ b/src/graphql/log.rs @@ -1,3 +1,6 @@ +#[cfg(test)] +mod tests; + use super::{ base64_engine, client::derives::{log_raw_events, LogRawEvents}, @@ -251,607 +254,3 @@ macro_rules! impl_from_giganto_log_filter_for_graphql_client { impl_from_giganto_time_range_struct_for_graphql_client!(log_raw_events); impl_from_giganto_log_filter_for_graphql_client!(log_raw_events); - -#[cfg(test)] -mod tests { - use super::{base64_engine, Engine, LogFilter, LogRawEvent, OpLogFilter, OpLogRawEvent}; - use crate::{ - graphql::{tests::TestSchema, TimeRange}, - storage::RawEventStore, - }; - use chrono::{DateTime, NaiveDateTime, Utc}; - use giganto_client::ingest::log::{Log, OpLog, OpLogLevel}; - - #[tokio::test] - async fn load_time_range() { - let schema = TestSchema::new(); - let store = schema.db.log_store().unwrap(); - - insert_log_raw_event(&store, "src1", 1, "kind1", b"log1"); - insert_log_raw_event(&store, "src1", 2, "kind1", b"log2"); - insert_log_raw_event(&store, "src1", 3, "kind1", b"log3"); - insert_log_raw_event(&store, "src1", 4, "kind1", b"log4"); - insert_log_raw_event(&store, "src1", 5, "kind1", b"log5"); - - // backward traversal in `start..end` - let connection = super::load_connection::( - &store, - &LogFilter { - time: Some(TimeRange { - start: Some(DateTime::::from_naive_utc_and_offset( - NaiveDateTime::from_timestamp_opt(0, 1).expect("valid value"), - Utc, - )), - end: Some(DateTime::::from_naive_utc_and_offset( - NaiveDateTime::from_timestamp_opt(0, 3).expect("valid value"), - Utc, - )), - }), - source: "src1".to_string(), - kind: Some("kind1".to_string()), - }, - None, - None, - None, - Some(3), - ) - .unwrap(); - assert_eq!(connection.edges.len(), 2); - assert_eq!( - base64_engine.decode(&connection.edges[0].node.log).unwrap(), - b"log1" - ); - assert_eq!( - base64_engine.decode(&connection.edges[1].node.log).unwrap(), - b"log2" - ); - - // backward traversal in `start..` - let connection = super::load_connection::( - &store, - &LogFilter { - time: Some(TimeRange { - start: Some(DateTime::::from_naive_utc_and_offset( - NaiveDateTime::from_timestamp_opt(0, 3).expect("valid value"), - Utc, - )), - end: None, - }), - source: "src1".to_string(), - kind: Some("kind1".to_string()), - }, - None, - None, - None, - Some(3), - ) - .unwrap(); - assert_eq!(connection.edges.len(), 3); - assert_eq!( - base64_engine.decode(&connection.edges[0].node.log).unwrap(), - b"log3" - ); - assert_eq!( - base64_engine.decode(&connection.edges[1].node.log).unwrap(), - b"log4" - ); - assert_eq!( - base64_engine.decode(&connection.edges[2].node.log).unwrap(), - b"log5" - ); - - // backward traversal in `..end` - let connection = super::load_connection::( - &store, - &LogFilter { - time: Some(TimeRange { - start: None, - end: Some(DateTime::::from_naive_utc_and_offset( - NaiveDateTime::from_timestamp_opt(0, 4).expect("valid value"), - Utc, - )), - }), - source: "src1".to_string(), - kind: Some("kind1".to_string()), - }, - None, - None, - None, - Some(3), - ) - .unwrap(); - assert_eq!(connection.edges.len(), 3); - assert_eq!( - base64_engine.decode(&connection.edges[0].node.log).unwrap(), - b"log1" - ); - assert_eq!( - base64_engine.decode(&connection.edges[1].node.log).unwrap(), - b"log2" - ); - assert_eq!( - base64_engine.decode(&connection.edges[2].node.log).unwrap(), - b"log3" - ); - - // forward traversal in `start..end` - let connection = super::load_connection::( - &store, - &LogFilter { - time: Some(TimeRange { - start: Some(DateTime::::from_naive_utc_and_offset( - NaiveDateTime::from_timestamp_opt(0, 1).expect("valid value"), - Utc, - )), - end: Some(DateTime::::from_naive_utc_and_offset( - NaiveDateTime::from_timestamp_opt(0, 3).expect("valid value"), - Utc, - )), - }), - source: "src1".to_string(), - kind: Some("kind1".to_string()), - }, - None, - None, - Some(3), - None, - ) - .unwrap(); - assert_eq!(connection.edges.len(), 2); - assert_eq!( - base64_engine.decode(&connection.edges[0].node.log).unwrap(), - b"log1" - ); - assert_eq!( - base64_engine.decode(&connection.edges[1].node.log).unwrap(), - b"log2" - ); - - // forward traversal `start..` - let connection = super::load_connection::( - &store, - &LogFilter { - time: Some(TimeRange { - start: Some(DateTime::::from_naive_utc_and_offset( - NaiveDateTime::from_timestamp_opt(0, 3).expect("valid value"), - Utc, - )), - end: None, - }), - source: "src1".to_string(), - kind: Some("kind1".to_string()), - }, - None, - None, - Some(3), - None, - ) - .unwrap(); - assert_eq!(connection.edges.len(), 3); - assert_eq!( - base64_engine.decode(&connection.edges[0].node.log).unwrap(), - b"log3" - ); - assert_eq!( - base64_engine.decode(&connection.edges[1].node.log).unwrap(), - b"log4" - ); - assert_eq!( - base64_engine.decode(&connection.edges[2].node.log).unwrap(), - b"log5" - ); - - // forward traversal `..end` - let connection = super::load_connection::( - &store, - &LogFilter { - time: Some(TimeRange { - start: None, - end: Some(DateTime::::from_naive_utc_and_offset( - NaiveDateTime::from_timestamp_opt(0, 3).expect("valid value"), - Utc, - )), - }), - source: "src1".to_string(), - kind: Some("kind1".to_string()), - }, - None, - None, - Some(3), - None, - ) - .unwrap(); - assert_eq!(connection.edges.len(), 2); - assert_eq!( - base64_engine.decode(&connection.edges[0].node.log).unwrap(), - b"log1" - ); - assert_eq!( - base64_engine.decode(&connection.edges[1].node.log).unwrap(), - b"log2" - ); - - // backward traversal in `start..end` and `before cursor` - let connection = super::load_connection::( - &store, - &LogFilter { - time: Some(TimeRange { - start: Some(DateTime::::from_naive_utc_and_offset( - NaiveDateTime::from_timestamp_opt(0, 1).expect("valid value"), - Utc, - )), - end: Some(DateTime::::from_naive_utc_and_offset( - NaiveDateTime::from_timestamp_opt(0, 3).expect("valid value"), - Utc, - )), - }), - source: "src1".to_string(), - kind: Some("kind1".to_string()), - }, - None, - Some(base64_engine.encode(b"src1\x00kind1\x00\x00\x00\x00\x00\x00\x00\x00\x03")), - None, - Some(3), - ) - .unwrap(); - assert_eq!(connection.edges.len(), 2); - assert_eq!( - base64_engine.decode(&connection.edges[0].node.log).unwrap(), - b"log1" - ); - assert_eq!( - base64_engine.decode(&connection.edges[1].node.log).unwrap(), - b"log2" - ); - - // backward traversal in `start..` and `before cursor` - let connection = super::load_connection::( - &store, - &LogFilter { - time: Some(TimeRange { - start: Some(DateTime::::from_naive_utc_and_offset( - NaiveDateTime::from_timestamp_opt(0, 2).expect("valid value"), - Utc, - )), - end: None, - }), - source: "src1".to_string(), - kind: Some("kind1".to_string()), - }, - None, - Some(base64_engine.encode(b"src1\x00kind1\x00\x00\x00\x00\x00\x00\x00\x00\x04")), - None, - Some(3), - ) - .unwrap(); - assert_eq!(connection.edges.len(), 2); - assert_eq!( - base64_engine.decode(&connection.edges[0].node.log).unwrap(), - b"log2" - ); - assert_eq!( - base64_engine.decode(&connection.edges[1].node.log).unwrap(), - b"log3" - ); - - // backward traversal in `..end` and `before cursor` - let connection = super::load_connection::( - &store, - &LogFilter { - time: Some(TimeRange { - start: None, - end: Some(DateTime::::from_naive_utc_and_offset( - NaiveDateTime::from_timestamp_opt(0, 5).expect("valid value"), - Utc, - )), - }), - source: "src1".to_string(), - kind: Some("kind1".to_string()), - }, - None, - Some(base64_engine.encode(b"src1\x00kind1\x00\x00\x00\x00\x00\x00\x00\x00\x04")), - None, - Some(3), - ) - .unwrap(); - assert_eq!(connection.edges.len(), 3); - assert_eq!( - base64_engine.decode(&connection.edges[0].node.log).unwrap(), - b"log1" - ); - assert_eq!( - base64_engine.decode(&connection.edges[1].node.log).unwrap(), - b"log2" - ); - assert_eq!( - base64_engine.decode(&connection.edges[2].node.log).unwrap(), - b"log3" - ); - - // forward traversal in `start..end` and `after cursor` - let connection = super::load_connection::( - &store, - &LogFilter { - time: Some(TimeRange { - start: Some(DateTime::::from_naive_utc_and_offset( - NaiveDateTime::from_timestamp_opt(0, 1).expect("valid value"), - Utc, - )), - end: Some(DateTime::::from_naive_utc_and_offset( - NaiveDateTime::from_timestamp_opt(0, 4).expect("valid value"), - Utc, - )), - }), - source: "src1".to_string(), - kind: Some("kind1".to_string()), - }, - Some(base64_engine.encode(b"src1\x00kind1\x00\x00\x00\x00\x00\x00\x00\x00\x01")), - None, - Some(3), - None, - ) - .unwrap(); - assert_eq!(connection.edges.len(), 2); - assert_eq!( - base64_engine.decode(&connection.edges[0].node.log).unwrap(), - b"log2" - ); - assert_eq!( - base64_engine.decode(&connection.edges[1].node.log).unwrap(), - b"log3" - ); - - // forward traversal `start..` and `after cursor` - let connection = super::load_connection::( - &store, - &LogFilter { - time: Some(TimeRange { - start: Some(DateTime::::from_naive_utc_and_offset( - NaiveDateTime::from_timestamp_opt(0, 2).expect("valid value"), - Utc, - )), - end: None, - }), - source: "src1".to_string(), - kind: Some("kind1".to_string()), - }, - Some(base64_engine.encode(b"src1\x00kind1\x00\x00\x00\x00\x00\x00\x00\x00\x03")), - None, - None, - None, - ) - .unwrap(); - assert_eq!(connection.edges.len(), 2); - assert_eq!( - base64_engine.decode(&connection.edges[0].node.log).unwrap(), - b"log4" - ); - assert_eq!( - base64_engine.decode(&connection.edges[1].node.log).unwrap(), - b"log5" - ); - - // forward traversal `..end` and `after cursor` - let connection = super::load_connection::( - &store, - &LogFilter { - time: Some(TimeRange { - start: None, - end: Some(DateTime::::from_naive_utc_and_offset( - NaiveDateTime::from_timestamp_opt(0, 4).expect("valid value"), - Utc, - )), - }), - source: "src1".to_string(), - kind: Some("kind1".to_string()), - }, - Some(base64_engine.encode(b"src1\x00kind1\x00\x00\x00\x00\x00\x00\x00\x00\x01")), - None, - None, - None, - ) - .unwrap(); - assert_eq!(connection.edges.len(), 2); - assert_eq!( - base64_engine.decode(&connection.edges[0].node.log).unwrap(), - b"log2" - ); - assert_eq!( - base64_engine.decode(&connection.edges[1].node.log).unwrap(), - b"log3" - ); - - // forward traversal `..` - let connection = super::load_connection::( - &store, - &LogFilter { - time: Some(TimeRange { - start: None, - end: None, - }), - source: "src1".to_string(), - kind: Some("kind1".to_string()), - }, - None, - None, - None, - None, - ) - .unwrap(); - assert_eq!(connection.edges.len(), 5); - assert_eq!( - base64_engine.decode(&connection.edges[0].node.log).unwrap(), - b"log1" - ); - assert_eq!( - base64_engine.decode(&connection.edges[4].node.log).unwrap(), - b"log5" - ); - } - - #[tokio::test] - async fn log_empty() { - let schema = TestSchema::new(); - let query = r#" - { - logRawEvents (filter: {source: "einsis", kind: "Hello"}, first: 1) { - edges { - node { - log - } - } - } - }"#; - let res = schema.execute(query).await; - assert_eq!(res.data.to_string(), "{logRawEvents: {edges: []}}"); - } - - #[tokio::test] - async fn log_with_data() { - let schema = TestSchema::new(); - let store = schema.db.log_store().unwrap(); - - insert_log_raw_event(&store, "src 1", 1, "kind 1", b"log 1"); - insert_log_raw_event(&store, "src 1", 2, "kind 2", b"log 2"); - - let query = r#" - { - logRawEvents (filter: {source: "src 1", kind: "kind 1"}, first: 1) { - edges { - node { - log - } - } - pageInfo { - hasPreviousPage - } - } - }"#; - let res = schema.execute(query).await; - assert_eq!( - res.data.to_string(), - format!("{{logRawEvents: {{edges: [{{node: {{log: \"{}\"}}}}],pageInfo: {{hasPreviousPage: false}}}}}}", base64_engine.encode("log 1")) - ); - } - - #[tokio::test] - async fn oplog_empty() { - let schema = TestSchema::new(); - let query = r#" - { - opLogRawEvents (filter: {agentId: "giganto@src 1", logLevel: "Info", contents: ""}, first: 1) { - edges { - node { - level, - contents - } - } - } - }"#; - let res = schema.execute(query).await; - assert_eq!(res.data.to_string(), "{opLogRawEvents: {edges: []}}"); - } - - #[tokio::test] - async fn oplog_with_data() { - let schema = TestSchema::new(); - let store = schema.db.op_log_store().unwrap(); - - insert_oplog_raw_event(&store, "giganto", 1); - - let query = r#" - { - opLogRawEvents (filter: {agentId: "giganto@src 1", logLevel: "Info"}, first: 1) { - edges { - node { - level, - contents - } - } - } - }"#; - let res = schema.execute(query).await; - assert_eq!( - res.data.to_string(), - "{opLogRawEvents: {edges: [{node: {level: \"Info\",contents: \"oplog\"}}]}}" - ); - } - - #[tokio::test] - async fn load_oplog() { - let schema = TestSchema::new(); - let store = schema.db.op_log_store().unwrap(); - - insert_oplog_raw_event(&store, "giganto", 1); - insert_oplog_raw_event(&store, "giganto", 2); - insert_oplog_raw_event(&store, "giganto", 3); - insert_oplog_raw_event(&store, "giganto", 4); - insert_oplog_raw_event(&store, "giganto", 5); - - let connection = super::load_connection::( - &store, - &OpLogFilter { - time: Some(TimeRange { - start: Some(DateTime::::from_naive_utc_and_offset( - NaiveDateTime::from_timestamp_opt(0, 1).expect("valid value"), - Utc, - )), - end: Some(DateTime::::from_naive_utc_and_offset( - NaiveDateTime::from_timestamp_opt(0, 3).expect("valid value"), - Utc, - )), - }), - agent_id: "giganto@src 1".to_string(), - log_level: Some("Info".to_string()), - contents: Some("oplog".to_string()), - }, - None, - None, - Some(3), - None, - ) - .unwrap(); - assert_eq!(connection.edges.len(), 2); - assert_eq!(connection.edges[0].node.level.as_str(), "Info"); - assert_eq!(connection.edges[1].node.contents.as_str(), "oplog"); - } - - fn insert_log_raw_event( - store: &RawEventStore, - source: &str, - timestamp: i64, - kind: &str, - body: &[u8], - ) { - let mut key: Vec = Vec::new(); - key.extend_from_slice(source.as_bytes()); - key.push(0); - key.extend_from_slice(kind.as_bytes()); - key.push(0); - key.extend_from_slice(×tamp.to_be_bytes()); - let log_body = Log { - kind: kind.to_string(), - log: body.to_vec(), - }; - let value = bincode::serialize(&log_body).unwrap(); - store.append(&key, &value).unwrap(); - } - - fn insert_oplog_raw_event(store: &RawEventStore, agent_name: &str, timestamp: i64) { - let mut key: Vec = Vec::new(); - let agent_id = format!("{agent_name}@src 1"); - key.extend_from_slice(agent_id.as_bytes()); - key.push(0); - key.extend_from_slice(×tamp.to_be_bytes()); - - let oplog_body = OpLog { - agent_name: agent_id.to_string(), - log_level: OpLogLevel::Info, - contents: "oplog".to_string(), - }; - - let value = bincode::serialize(&oplog_body).unwrap(); - - store.append(&key, &value).unwrap(); - } -} diff --git a/src/graphql/log/tests.rs b/src/graphql/log/tests.rs new file mode 100644 index 0000000..41d7e43 --- /dev/null +++ b/src/graphql/log/tests.rs @@ -0,0 +1,600 @@ +use super::{base64_engine, Engine, LogFilter, LogRawEvent, OpLogFilter, OpLogRawEvent}; +use crate::{ + graphql::{tests::TestSchema, TimeRange}, + storage::RawEventStore, +}; +use chrono::{DateTime, NaiveDateTime, Utc}; +use giganto_client::ingest::log::{Log, OpLog, OpLogLevel}; + +#[tokio::test] +async fn load_time_range() { + let schema = TestSchema::new(); + let store = schema.db.log_store().unwrap(); + + insert_log_raw_event(&store, "src1", 1, "kind1", b"log1"); + insert_log_raw_event(&store, "src1", 2, "kind1", b"log2"); + insert_log_raw_event(&store, "src1", 3, "kind1", b"log3"); + insert_log_raw_event(&store, "src1", 4, "kind1", b"log4"); + insert_log_raw_event(&store, "src1", 5, "kind1", b"log5"); + + // backward traversal in `start..end` + let connection = super::load_connection::( + &store, + &LogFilter { + time: Some(TimeRange { + start: Some(DateTime::::from_naive_utc_and_offset( + NaiveDateTime::from_timestamp_opt(0, 1).expect("valid value"), + Utc, + )), + end: Some(DateTime::::from_naive_utc_and_offset( + NaiveDateTime::from_timestamp_opt(0, 3).expect("valid value"), + Utc, + )), + }), + source: "src1".to_string(), + kind: Some("kind1".to_string()), + }, + None, + None, + None, + Some(3), + ) + .unwrap(); + assert_eq!(connection.edges.len(), 2); + assert_eq!( + base64_engine.decode(&connection.edges[0].node.log).unwrap(), + b"log1" + ); + assert_eq!( + base64_engine.decode(&connection.edges[1].node.log).unwrap(), + b"log2" + ); + + // backward traversal in `start..` + let connection = super::load_connection::( + &store, + &LogFilter { + time: Some(TimeRange { + start: Some(DateTime::::from_naive_utc_and_offset( + NaiveDateTime::from_timestamp_opt(0, 3).expect("valid value"), + Utc, + )), + end: None, + }), + source: "src1".to_string(), + kind: Some("kind1".to_string()), + }, + None, + None, + None, + Some(3), + ) + .unwrap(); + assert_eq!(connection.edges.len(), 3); + assert_eq!( + base64_engine.decode(&connection.edges[0].node.log).unwrap(), + b"log3" + ); + assert_eq!( + base64_engine.decode(&connection.edges[1].node.log).unwrap(), + b"log4" + ); + assert_eq!( + base64_engine.decode(&connection.edges[2].node.log).unwrap(), + b"log5" + ); + + // backward traversal in `..end` + let connection = super::load_connection::( + &store, + &LogFilter { + time: Some(TimeRange { + start: None, + end: Some(DateTime::::from_naive_utc_and_offset( + NaiveDateTime::from_timestamp_opt(0, 4).expect("valid value"), + Utc, + )), + }), + source: "src1".to_string(), + kind: Some("kind1".to_string()), + }, + None, + None, + None, + Some(3), + ) + .unwrap(); + assert_eq!(connection.edges.len(), 3); + assert_eq!( + base64_engine.decode(&connection.edges[0].node.log).unwrap(), + b"log1" + ); + assert_eq!( + base64_engine.decode(&connection.edges[1].node.log).unwrap(), + b"log2" + ); + assert_eq!( + base64_engine.decode(&connection.edges[2].node.log).unwrap(), + b"log3" + ); + + // forward traversal in `start..end` + let connection = super::load_connection::( + &store, + &LogFilter { + time: Some(TimeRange { + start: Some(DateTime::::from_naive_utc_and_offset( + NaiveDateTime::from_timestamp_opt(0, 1).expect("valid value"), + Utc, + )), + end: Some(DateTime::::from_naive_utc_and_offset( + NaiveDateTime::from_timestamp_opt(0, 3).expect("valid value"), + Utc, + )), + }), + source: "src1".to_string(), + kind: Some("kind1".to_string()), + }, + None, + None, + Some(3), + None, + ) + .unwrap(); + assert_eq!(connection.edges.len(), 2); + assert_eq!( + base64_engine.decode(&connection.edges[0].node.log).unwrap(), + b"log1" + ); + assert_eq!( + base64_engine.decode(&connection.edges[1].node.log).unwrap(), + b"log2" + ); + + // forward traversal `start..` + let connection = super::load_connection::( + &store, + &LogFilter { + time: Some(TimeRange { + start: Some(DateTime::::from_naive_utc_and_offset( + NaiveDateTime::from_timestamp_opt(0, 3).expect("valid value"), + Utc, + )), + end: None, + }), + source: "src1".to_string(), + kind: Some("kind1".to_string()), + }, + None, + None, + Some(3), + None, + ) + .unwrap(); + assert_eq!(connection.edges.len(), 3); + assert_eq!( + base64_engine.decode(&connection.edges[0].node.log).unwrap(), + b"log3" + ); + assert_eq!( + base64_engine.decode(&connection.edges[1].node.log).unwrap(), + b"log4" + ); + assert_eq!( + base64_engine.decode(&connection.edges[2].node.log).unwrap(), + b"log5" + ); + + // forward traversal `..end` + let connection = super::load_connection::( + &store, + &LogFilter { + time: Some(TimeRange { + start: None, + end: Some(DateTime::::from_naive_utc_and_offset( + NaiveDateTime::from_timestamp_opt(0, 3).expect("valid value"), + Utc, + )), + }), + source: "src1".to_string(), + kind: Some("kind1".to_string()), + }, + None, + None, + Some(3), + None, + ) + .unwrap(); + assert_eq!(connection.edges.len(), 2); + assert_eq!( + base64_engine.decode(&connection.edges[0].node.log).unwrap(), + b"log1" + ); + assert_eq!( + base64_engine.decode(&connection.edges[1].node.log).unwrap(), + b"log2" + ); + + // backward traversal in `start..end` and `before cursor` + let connection = super::load_connection::( + &store, + &LogFilter { + time: Some(TimeRange { + start: Some(DateTime::::from_naive_utc_and_offset( + NaiveDateTime::from_timestamp_opt(0, 1).expect("valid value"), + Utc, + )), + end: Some(DateTime::::from_naive_utc_and_offset( + NaiveDateTime::from_timestamp_opt(0, 3).expect("valid value"), + Utc, + )), + }), + source: "src1".to_string(), + kind: Some("kind1".to_string()), + }, + None, + Some(base64_engine.encode(b"src1\x00kind1\x00\x00\x00\x00\x00\x00\x00\x00\x03")), + None, + Some(3), + ) + .unwrap(); + assert_eq!(connection.edges.len(), 2); + assert_eq!( + base64_engine.decode(&connection.edges[0].node.log).unwrap(), + b"log1" + ); + assert_eq!( + base64_engine.decode(&connection.edges[1].node.log).unwrap(), + b"log2" + ); + + // backward traversal in `start..` and `before cursor` + let connection = super::load_connection::( + &store, + &LogFilter { + time: Some(TimeRange { + start: Some(DateTime::::from_naive_utc_and_offset( + NaiveDateTime::from_timestamp_opt(0, 2).expect("valid value"), + Utc, + )), + end: None, + }), + source: "src1".to_string(), + kind: Some("kind1".to_string()), + }, + None, + Some(base64_engine.encode(b"src1\x00kind1\x00\x00\x00\x00\x00\x00\x00\x00\x04")), + None, + Some(3), + ) + .unwrap(); + assert_eq!(connection.edges.len(), 2); + assert_eq!( + base64_engine.decode(&connection.edges[0].node.log).unwrap(), + b"log2" + ); + assert_eq!( + base64_engine.decode(&connection.edges[1].node.log).unwrap(), + b"log3" + ); + + // backward traversal in `..end` and `before cursor` + let connection = super::load_connection::( + &store, + &LogFilter { + time: Some(TimeRange { + start: None, + end: Some(DateTime::::from_naive_utc_and_offset( + NaiveDateTime::from_timestamp_opt(0, 5).expect("valid value"), + Utc, + )), + }), + source: "src1".to_string(), + kind: Some("kind1".to_string()), + }, + None, + Some(base64_engine.encode(b"src1\x00kind1\x00\x00\x00\x00\x00\x00\x00\x00\x04")), + None, + Some(3), + ) + .unwrap(); + assert_eq!(connection.edges.len(), 3); + assert_eq!( + base64_engine.decode(&connection.edges[0].node.log).unwrap(), + b"log1" + ); + assert_eq!( + base64_engine.decode(&connection.edges[1].node.log).unwrap(), + b"log2" + ); + assert_eq!( + base64_engine.decode(&connection.edges[2].node.log).unwrap(), + b"log3" + ); + + // forward traversal in `start..end` and `after cursor` + let connection = super::load_connection::( + &store, + &LogFilter { + time: Some(TimeRange { + start: Some(DateTime::::from_naive_utc_and_offset( + NaiveDateTime::from_timestamp_opt(0, 1).expect("valid value"), + Utc, + )), + end: Some(DateTime::::from_naive_utc_and_offset( + NaiveDateTime::from_timestamp_opt(0, 4).expect("valid value"), + Utc, + )), + }), + source: "src1".to_string(), + kind: Some("kind1".to_string()), + }, + Some(base64_engine.encode(b"src1\x00kind1\x00\x00\x00\x00\x00\x00\x00\x00\x01")), + None, + Some(3), + None, + ) + .unwrap(); + assert_eq!(connection.edges.len(), 2); + assert_eq!( + base64_engine.decode(&connection.edges[0].node.log).unwrap(), + b"log2" + ); + assert_eq!( + base64_engine.decode(&connection.edges[1].node.log).unwrap(), + b"log3" + ); + + // forward traversal `start..` and `after cursor` + let connection = super::load_connection::( + &store, + &LogFilter { + time: Some(TimeRange { + start: Some(DateTime::::from_naive_utc_and_offset( + NaiveDateTime::from_timestamp_opt(0, 2).expect("valid value"), + Utc, + )), + end: None, + }), + source: "src1".to_string(), + kind: Some("kind1".to_string()), + }, + Some(base64_engine.encode(b"src1\x00kind1\x00\x00\x00\x00\x00\x00\x00\x00\x03")), + None, + None, + None, + ) + .unwrap(); + assert_eq!(connection.edges.len(), 2); + assert_eq!( + base64_engine.decode(&connection.edges[0].node.log).unwrap(), + b"log4" + ); + assert_eq!( + base64_engine.decode(&connection.edges[1].node.log).unwrap(), + b"log5" + ); + + // forward traversal `..end` and `after cursor` + let connection = super::load_connection::( + &store, + &LogFilter { + time: Some(TimeRange { + start: None, + end: Some(DateTime::::from_naive_utc_and_offset( + NaiveDateTime::from_timestamp_opt(0, 4).expect("valid value"), + Utc, + )), + }), + source: "src1".to_string(), + kind: Some("kind1".to_string()), + }, + Some(base64_engine.encode(b"src1\x00kind1\x00\x00\x00\x00\x00\x00\x00\x00\x01")), + None, + None, + None, + ) + .unwrap(); + assert_eq!(connection.edges.len(), 2); + assert_eq!( + base64_engine.decode(&connection.edges[0].node.log).unwrap(), + b"log2" + ); + assert_eq!( + base64_engine.decode(&connection.edges[1].node.log).unwrap(), + b"log3" + ); + + // forward traversal `..` + let connection = super::load_connection::( + &store, + &LogFilter { + time: Some(TimeRange { + start: None, + end: None, + }), + source: "src1".to_string(), + kind: Some("kind1".to_string()), + }, + None, + None, + None, + None, + ) + .unwrap(); + assert_eq!(connection.edges.len(), 5); + assert_eq!( + base64_engine.decode(&connection.edges[0].node.log).unwrap(), + b"log1" + ); + assert_eq!( + base64_engine.decode(&connection.edges[4].node.log).unwrap(), + b"log5" + ); +} + +#[tokio::test] +async fn log_empty() { + let schema = TestSchema::new(); + let query = r#" + { + logRawEvents (filter: {source: "einsis", kind: "Hello"}, first: 1) { + edges { + node { + log + } + } + } + }"#; + let res = schema.execute(query).await; + assert_eq!(res.data.to_string(), "{logRawEvents: {edges: []}}"); +} + +#[tokio::test] +async fn log_with_data() { + let schema = TestSchema::new(); + let store = schema.db.log_store().unwrap(); + + insert_log_raw_event(&store, "src 1", 1, "kind 1", b"log 1"); + insert_log_raw_event(&store, "src 1", 2, "kind 2", b"log 2"); + + let query = r#" + { + logRawEvents (filter: {source: "src 1", kind: "kind 1"}, first: 1) { + edges { + node { + log + } + } + pageInfo { + hasPreviousPage + } + } + }"#; + let res = schema.execute(query).await; + assert_eq!( + res.data.to_string(), + format!("{{logRawEvents: {{edges: [{{node: {{log: \"{}\"}}}}],pageInfo: {{hasPreviousPage: false}}}}}}", base64_engine.encode("log 1")) + ); +} + +#[tokio::test] +async fn oplog_empty() { + let schema = TestSchema::new(); + let query = r#" + { + opLogRawEvents (filter: {agentId: "giganto@src 1", logLevel: "Info", contents: ""}, first: 1) { + edges { + node { + level, + contents + } + } + } + }"#; + let res = schema.execute(query).await; + assert_eq!(res.data.to_string(), "{opLogRawEvents: {edges: []}}"); +} + +#[tokio::test] +async fn oplog_with_data() { + let schema = TestSchema::new(); + let store = schema.db.op_log_store().unwrap(); + + insert_oplog_raw_event(&store, "giganto", 1); + + let query = r#" + { + opLogRawEvents (filter: {agentId: "giganto@src 1", logLevel: "Info"}, first: 1) { + edges { + node { + level, + contents + } + } + } + }"#; + let res = schema.execute(query).await; + assert_eq!( + res.data.to_string(), + "{opLogRawEvents: {edges: [{node: {level: \"Info\",contents: \"oplog\"}}]}}" + ); +} + +#[tokio::test] +async fn load_oplog() { + let schema = TestSchema::new(); + let store = schema.db.op_log_store().unwrap(); + + insert_oplog_raw_event(&store, "giganto", 1); + insert_oplog_raw_event(&store, "giganto", 2); + insert_oplog_raw_event(&store, "giganto", 3); + insert_oplog_raw_event(&store, "giganto", 4); + insert_oplog_raw_event(&store, "giganto", 5); + + let connection = super::load_connection::( + &store, + &OpLogFilter { + time: Some(TimeRange { + start: Some(DateTime::::from_naive_utc_and_offset( + NaiveDateTime::from_timestamp_opt(0, 1).expect("valid value"), + Utc, + )), + end: Some(DateTime::::from_naive_utc_and_offset( + NaiveDateTime::from_timestamp_opt(0, 3).expect("valid value"), + Utc, + )), + }), + agent_id: "giganto@src 1".to_string(), + log_level: Some("Info".to_string()), + contents: Some("oplog".to_string()), + }, + None, + None, + Some(3), + None, + ) + .unwrap(); + assert_eq!(connection.edges.len(), 2); + assert_eq!(connection.edges[0].node.level.as_str(), "Info"); + assert_eq!(connection.edges[1].node.contents.as_str(), "oplog"); +} + +fn insert_log_raw_event( + store: &RawEventStore, + source: &str, + timestamp: i64, + kind: &str, + body: &[u8], +) { + let mut key: Vec = Vec::new(); + key.extend_from_slice(source.as_bytes()); + key.push(0); + key.extend_from_slice(kind.as_bytes()); + key.push(0); + key.extend_from_slice(×tamp.to_be_bytes()); + let log_body = Log { + kind: kind.to_string(), + log: body.to_vec(), + }; + let value = bincode::serialize(&log_body).unwrap(); + store.append(&key, &value).unwrap(); +} + +fn insert_oplog_raw_event(store: &RawEventStore, agent_name: &str, timestamp: i64) { + let mut key: Vec = Vec::new(); + let agent_id = format!("{agent_name}@src 1"); + key.extend_from_slice(agent_id.as_bytes()); + key.push(0); + key.extend_from_slice(×tamp.to_be_bytes()); + + let oplog_body = OpLog { + agent_name: agent_id.to_string(), + log_level: OpLogLevel::Info, + contents: "oplog".to_string(), + }; + + let value = bincode::serialize(&oplog_body).unwrap(); + + store.append(&key, &value).unwrap(); +} diff --git a/src/graphql/network.rs b/src/graphql/network.rs index 5148767..103fe31 100644 --- a/src/graphql/network.rs +++ b/src/graphql/network.rs @@ -1,4 +1,8 @@ #![allow(clippy::unused_async)] + +#[cfg(test)] +mod tests; + use super::{ base64_engine, check_address, check_port, collect_exist_timestamp, events_vec_in_cluster, get_peekable_iter, get_timestamp_from_key, handle_paged_events, @@ -2247,3656 +2251,3 @@ impl_from_giganto_search_filter_for_graphql_client!( search_ssh_raw_events, search_tls_raw_events ); - -#[cfg(test)] -mod tests { - use crate::graphql::tests::TestSchema; - use crate::storage::RawEventStore; - use chrono::{Duration, TimeZone, Utc}; - use giganto_client::ingest::network::{ - Conn, DceRpc, Dns, Ftp, Http, Kerberos, Ldap, Mqtt, Nfs, Ntlm, Rdp, Smb, Smtp, Ssh, Tls, - }; - use mockito; - use std::mem; - use std::net::{IpAddr, SocketAddr}; - - #[tokio::test] - async fn conn_empty() { - let schema = TestSchema::new(); - let query = r#" - { - connRawEvents( - filter: { - time: { start: "1992-06-05T00:00:00Z", end: "2011-09-22T00:00:00Z" } - source: "ingest_source_1" - origAddr: { start: "192.168.4.75", end: "192.168.4.79" } - respAddr: { start: "192.168.4.75", end: "192.168.4.79" } - origPort: { start: 46377, end: 46380 } - respPort: { start: 50, end: 200 } - } - first: 1 - ) { - edges { - node { - origAddr, - respAddr, - origPort, - } - } - } - }"#; - let res = schema.execute(query).await; - assert_eq!(res.data.to_string(), "{connRawEvents: {edges: []}}"); - } - - #[tokio::test] - async fn conn_empty_giganto_cluster() { - // given - let query = r#" - { - connRawEvents( - filter: { - time: { start: "1992-06-05T00:00:00Z", end: "2011-09-22T00:00:00Z" } - source: "ingest src 2" - origAddr: { start: "192.168.4.75", end: "192.168.4.79" } - respAddr: { start: "192.168.4.75", end: "192.168.4.79" } - origPort: { start: 46377, end: 46380 } - respPort: { start: 50, end: 200 } - } - first: 1 - ) { - edges { - node { - origAddr, - respAddr, - origPort, - } - } - } - }"#; - - let mut peer_server = mockito::Server::new_async().await; - let peer_response_mock_data = r#" - { - "data": { - "connRawEvents": { - "pageInfo": { - "hasPreviousPage": false, - "hasNextPage": false - }, - "edges": [ - ] - } - } - } - "#; - let mock = peer_server - .mock("POST", "/graphql") - .with_status(200) - .with_body(peer_response_mock_data) - .create(); - - let peer_port = peer_server - .host_with_port() - .parse::() - .expect("Port must exist") - .port(); - let schema = TestSchema::new_with_graphql_peer(peer_port); - - // when - let res = schema.execute(query).await; - - // then - assert_eq!(res.data.to_string(), "{connRawEvents: {edges: []}}"); - - mock.assert_async().await; - } - - #[tokio::test] - async fn conn_with_data() { - let schema = TestSchema::new(); - let store = schema.db.conn_store().unwrap(); - - insert_conn_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); - insert_conn_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); - - let query = r#" - { - connRawEvents( - filter: { - time: { start: "1992-06-05T00:00:00Z", end: "2050-09-22T00:00:00Z" } - source: "src 1" - origAddr: { start: "192.168.4.72", end: "192.168.4.79" } - respAddr: { start: "192.168.4.75", end: "192.168.4.79" } - origPort: { start: 46378, end: 46379 } - respPort: { start: 50, end: 200 } - } - first: 1 - ) { - edges { - node { - origAddr, - respAddr, - origPort, - } - } - } - }"#; - let res = schema.execute(query).await; - assert_eq!( - res.data.to_string(), - "{connRawEvents: {edges: [{node: {origAddr: \"192.168.4.76\",respAddr: \"192.168.4.76\",origPort: 46378}}]}}" - ); - } - - fn insert_conn_raw_event(store: &RawEventStore, source: &str, timestamp: i64) { - let mut key = Vec::with_capacity(source.len() + 1 + mem::size_of::()); - key.extend_from_slice(source.as_bytes()); - key.push(0); - key.extend(timestamp.to_be_bytes()); - - let tmp_dur = Duration::nanoseconds(12345); - let conn_body = Conn { - orig_addr: "192.168.4.76".parse::().unwrap(), - orig_port: 46378, - resp_addr: "192.168.4.76".parse::().unwrap(), - resp_port: 80, - proto: 6, - duration: tmp_dur.num_nanoseconds().unwrap(), - service: "-".to_string(), - orig_bytes: 77, - resp_bytes: 295, - orig_pkts: 397, - resp_pkts: 511, - }; - let ser_conn_body = bincode::serialize(&conn_body).unwrap(); - - store.append(&key, &ser_conn_body).unwrap(); - } - - #[tokio::test] - async fn conn_with_data_giganto_cluster() { - // given - let query = r#" - { - connRawEvents( - filter: { - time: { start: "1992-06-05T00:00:00Z", end: "2050-09-22T00:00:00Z" } - source: "ingest src 2" - origAddr: { start: "192.168.4.72", end: "192.168.4.79" } - respAddr: { start: "192.168.4.75", end: "192.168.4.79" } - origPort: { start: 46378, end: 46379 } - respPort: { start: 50, end: 200 } - } - first: 1 - ) { - edges { - node { - origAddr, - respAddr, - origPort, - } - } - } - }"#; - - let mut peer_server = mockito::Server::new_async().await; - let peer_response_mock_data = r#" - { - "data": { - "connRawEvents": { - "pageInfo": { - "hasPreviousPage": true, - "hasNextPage": false - }, - "edges": [ - { - "cursor": "cGl0YTIwMjNNQlAAF5gitjR0HIM=", - "node": { - "timestamp": "2023-11-16T15:03:45.291779203+00:00", - "origAddr": "192.168.4.76", - "respAddr": "192.168.4.76", - "origPort": 46378, - "respPort": 443, - "proto": 6, - "service": "-", - "duration": 324234, - "origBytes": 0, - "respBytes": 0, - "origPkts": 6, - "respPkts": 0 - } - } - ] - } - } - } - "#; - - let mock = peer_server - .mock("POST", "/graphql") - .with_status(200) - .with_body(peer_response_mock_data) - .create(); - - let peer_port = peer_server - .host_with_port() - .parse::() - .expect("Port must exist") - .port(); - let schema = TestSchema::new_with_graphql_peer(peer_port); - - // when - let res = schema.execute(query).await; - - // then - assert_eq!( - res.data.to_string(), - "{connRawEvents: {edges: [{node: {origAddr: \"192.168.4.76\",respAddr: \"192.168.4.76\",origPort: 46378}}]}}" - ); - - mock.assert_async().await; - } - - #[tokio::test] - async fn dns_empty() { - let schema = TestSchema::new(); - let query = r#" - { - dnsRawEvents( - filter: { - time: { start: "1992-06-05T00:00:00Z", end: "2011-09-22T00:00:00Z" } - source: "einsis" - origAddr: { start: "192.168.4.75", end: "192.168.4.79" } - respAddr: { start: "31.3.245.123", end: "31.3.245.143" } - origPort: { start: 46377, end: 46380 } - respPort: { start: 100, end: 200 } - } - first: 1 - ) { - edges { - node { - origAddr, - respAddr, - origPort, - } - } - pageInfo { - hasPreviousPage - } - } - }"#; - let res = schema.execute(query).await; - assert_eq!( - res.data.to_string(), - "{dnsRawEvents: {edges: [],pageInfo: {hasPreviousPage: false}}}" - ); - } - - #[tokio::test] - async fn dns_empty_giganto_cluster() { - // given - let query = r#" - { - dnsRawEvents( - filter: { - time: { start: "1992-06-05T00:00:00Z", end: "2011-09-22T00:00:00Z" } - source: "src 2" - origAddr: { start: "192.168.4.75", end: "192.168.4.79" } - respAddr: { start: "31.3.245.123", end: "31.3.245.143" } - origPort: { start: 46377, end: 46380 } - respPort: { start: 100, end: 200 } - } - first: 1 - ) { - edges { - node { - origAddr, - respAddr, - origPort, - } - } - pageInfo { - hasPreviousPage - } - } - }"#; - - let mut peer_server = mockito::Server::new_async().await; - let peer_response_mock_data = r#" - { - "data": { - "dnsRawEvents": { - "pageInfo": { - "hasPreviousPage": false, - "hasNextPage": false - }, - "edges": [ - ] - } - } - } - "#; - let mock = peer_server - .mock("POST", "/graphql") - .with_status(200) - .with_body(peer_response_mock_data) - .create(); - - let peer_port = peer_server - .host_with_port() - .parse::() - .expect("Port must exist") - .port(); - let schema = TestSchema::new_with_graphql_peer(peer_port); - - // when - let res = schema.execute(query).await; - - // then - assert_eq!( - res.data.to_string(), - "{dnsRawEvents: {edges: [],pageInfo: {hasPreviousPage: false}}}" - ); - mock.assert_async().await; - } - - #[tokio::test] - async fn dns_with_data() { - let schema = TestSchema::new(); - let store = schema.db.dns_store().unwrap(); - - insert_dns_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); - insert_dns_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); - - let query = r#" - { - dnsRawEvents( - filter: { - source: "src 1" - origAddr: { start: "192.168.4.70", end: "192.168.4.78" } - respAddr: { start: "31.3.245.100", end: "31.3.245.245" } - origPort: { start: 46377, end: 46380 } - respPort: { start: 0, end: 200 } - } - last: 1 - ) { - edges { - node { - origAddr, - respAddr, - origPort, - } - } - } - }"#; - let res = schema.execute(query).await; - assert_eq!( - res.data.to_string(), - "{dnsRawEvents: {edges: [{node: {origAddr: \"192.168.4.76\",respAddr: \"31.3.245.133\",origPort: 46378}}]}}" - ); - } - - fn insert_dns_raw_event(store: &RawEventStore, source: &str, timestamp: i64) { - let mut key = Vec::with_capacity(source.len() + 1 + mem::size_of::()); - key.extend_from_slice(source.as_bytes()); - key.push(0); - key.extend(timestamp.to_be_bytes()); - - let dns_body = Dns { - orig_addr: "192.168.4.76".parse::().unwrap(), - orig_port: 46378, - resp_addr: "31.3.245.133".parse::().unwrap(), - resp_port: 80, - proto: 17, - last_time: 1, - query: "Hello Server Hello Server Hello Server".to_string(), - answer: vec!["1.1.1.1".to_string()], - trans_id: 1, - rtt: 1, - qclass: 0, - qtype: 0, - rcode: 0, - aa_flag: false, - tc_flag: false, - rd_flag: false, - ra_flag: false, - ttl: vec![1; 5], - }; - let ser_dns_body = bincode::serialize(&dns_body).unwrap(); - - store.append(&key, &ser_dns_body).unwrap(); - } - - #[tokio::test] - async fn dns_with_data_giganto_cluster() { - // given - let query = r#" - { - dnsRawEvents( - filter: { - source: "src 2" - origAddr: { start: "192.168.4.70", end: "192.168.4.78" } - respAddr: { start: "31.3.245.100", end: "31.3.245.245" } - origPort: { start: 46377, end: 46380 } - respPort: { start: 0, end: 200 } - } - last: 1 - ) { - edges { - node { - origAddr, - respAddr, - origPort, - } - } - } - }"#; - - let mut peer_server = mockito::Server::new_async().await; - let peer_response_mock_data = r#" - { - "data": { - "dnsRawEvents": { - "pageInfo": { - "hasPreviousPage": true, - "hasNextPage": false - }, - "edges": [ - { - "cursor": "cGl0YTIwMjNNQlAAF5gitjR0HIM=", - "node": { - "timestamp": "2023-11-16T15:03:45.291779203+00:00", - "origAddr": "192.168.4.76", - "respAddr": "31.3.245.133", - "origPort": 46378, - "respPort": 443, - "lastTime": 123456789, - "proto": 6, - "query": "example.com", - "answer": [ - "192.168.1.1" - ], - "transId": 12345, - "rtt": 567, - "qclass": 1, - "qtype": 1, - "rcode": 0, - "aaFlag": true, - "tcFlag": false, - "rdFlag": true, - "raFlag": false, - "ttl": [ - 3600, - 1800, - 900 - ] - } - } - ] - } - } - } - "#; - let mock = peer_server - .mock("POST", "/graphql") - .with_status(200) - .with_body(peer_response_mock_data) - .create(); - - let peer_port = peer_server - .host_with_port() - .parse::() - .expect("Port must exist") - .port(); - let schema = TestSchema::new_with_graphql_peer(peer_port); - - // when - let res = schema.execute(query).await; - - // then - assert_eq!( - res.data.to_string(), - "{dnsRawEvents: {edges: [{node: {origAddr: \"192.168.4.76\",respAddr: \"31.3.245.133\",origPort: 46378}}]}}" - ); - - mock.assert_async().await; - } - - #[tokio::test] - async fn http_empty() { - let schema = TestSchema::new(); - let query = r#" - { - httpRawEvents( - filter: { - time: { start: "1992-06-05T00:00:00Z", end: "2024-09-22T00:00:00Z" } - source: "einsis" - respAddr: { start: "192.168.4.75", end: "192.168.4.79" } - origPort: { start: 46377, end: 46380 } - respPort: { start: 0, end: 200 } - } - first: 1 - ) { - edges { - node { - origAddr, - respAddr, - origPort, - } - } - } - }"#; - let res = schema.execute(query).await; - assert_eq!(res.data.to_string(), "{httpRawEvents: {edges: []}}"); - } - - #[tokio::test] - async fn http_empty_giganto_cluster() { - // given - let query = r#" - { - httpRawEvents( - filter: { - time: { start: "1992-06-05T00:00:00Z", end: "2024-09-22T00:00:00Z" } - source: "src 2" - respAddr: { start: "192.168.4.75", end: "192.168.4.79" } - origPort: { start: 46377, end: 46380 } - respPort: { start: 0, end: 200 } - } - first: 1 - ) { - edges { - node { - origAddr, - respAddr, - origPort, - } - } - } - }"#; - - let mut peer_server = mockito::Server::new_async().await; - let peer_response_mock_data = r#" - { - "data": { - "httpRawEvents": { - "pageInfo": { - "hasPreviousPage": false, - "hasNextPage": false - }, - "edges": [ - ] - } - } - } - "#; - let mock = peer_server - .mock("POST", "/graphql") - .with_status(200) - .with_body(peer_response_mock_data) - .create(); - - let peer_port = peer_server - .host_with_port() - .parse::() - .expect("Port must exist") - .port(); - let schema = TestSchema::new_with_graphql_peer(peer_port); - - // when - let res = schema.execute(query).await; - - // then - assert_eq!(res.data.to_string(), "{httpRawEvents: {edges: []}}"); - - mock.assert_async().await; - } - - #[tokio::test] - async fn http_with_data() { - let schema = TestSchema::new(); - let store = schema.db.http_store().unwrap(); - - insert_http_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); - insert_http_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); - - let query = r#" - { - httpRawEvents( - filter: { - time: { start: "1992-06-05T00:00:00Z", end: "2025-09-22T00:00:00Z" } - source: "src 1" - origAddr: { start: "192.168.4.75", end: "192.168.4.79" } - respAddr: { start: "192.168.4.75", end: "192.168.4.79" } - origPort: { start: 46377, end: 46380 } - } - first: 1 - ) { - edges { - node { - origAddr, - respAddr, - origPort, - } - } - } - }"#; - let res = schema.execute(query).await; - assert_eq!( - res.data.to_string(), - "{httpRawEvents: {edges: [{node: {origAddr: \"192.168.4.76\",respAddr: \"192.168.4.76\",origPort: 46378}}]}}" - ); - } - - fn insert_http_raw_event(store: &RawEventStore, source: &str, timestamp: i64) { - let mut key = Vec::with_capacity(source.len() + 1 + mem::size_of::()); - key.extend_from_slice(source.as_bytes()); - key.push(0); - key.extend(timestamp.to_be_bytes()); - - let http_body = Http { - orig_addr: "192.168.4.76".parse::().unwrap(), - orig_port: 46378, - resp_addr: "192.168.4.76".parse::().unwrap(), - resp_port: 80, - proto: 17, - last_time: 1, - method: "POST".to_string(), - host: "einsis".to_string(), - uri: "/einsis.gif".to_string(), - referrer: "einsis.com".to_string(), - version: String::new(), - user_agent: "giganto".to_string(), - request_len: 0, - response_len: 0, - status_code: 200, - status_msg: String::new(), - username: String::new(), - password: String::new(), - cookie: String::new(), - content_encoding: String::new(), - content_type: String::new(), - cache_control: String::new(), - orig_filenames: Vec::new(), - orig_mime_types: Vec::new(), - resp_filenames: Vec::new(), - resp_mime_types: Vec::new(), - }; - let ser_http_body = bincode::serialize(&http_body).unwrap(); - - store.append(&key, &ser_http_body).unwrap(); - } - - #[tokio::test] - async fn http_with_data_giganto_cluster() { - // given - let query = r#" - { - httpRawEvents( - filter: { - time: { start: "1992-06-05T00:00:00Z", end: "2025-09-22T00:00:00Z" } - source: "src 2" - origAddr: { start: "192.168.4.75", end: "192.168.4.79" } - respAddr: { start: "192.168.4.75", end: "192.168.4.79" } - origPort: { start: 46377, end: 46380 } - } - first: 1 - ) { - edges { - node { - origAddr, - respAddr, - origPort, - } - } - } - }"#; - - let mut peer_server = mockito::Server::new_async().await; - let peer_response_mock_data = r#" - { - "data": { - "httpRawEvents": { - "pageInfo": { - "hasPreviousPage": true, - "hasNextPage": false - }, - "edges": [ - { - - "cursor": "cGl0YTIwMjNNQlAAF5gitjR0HIM=", - "node": { - "timestamp": "2023-11-16T15:03:45.291779203+00:00", - "origAddr": "192.168.4.76", - "respAddr": "192.168.4.76", - "origPort": 46378, - "respPort": 443, - "proto": 6, - "lastTime": 123456789, - "method": "GET", - "host": "example.com", - "uri": "/path/to/resource", - "referrer": "http://referrer.com", - "version": "HTTP/1.1", - "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36", - "requestLen": 1024, - "responseLen": 2048, - "statusCode": 200, - "statusMsg": "OK", - "username": "user123", - "password": "pass456", - "cookie": "session=abc123", - "contentEncoding": "gzip", - "contentType": "text/html", - "cacheControl": "no-cache", - "origFilenames": [ - "file1.txt", - "file2.txt" - ], - "origMimeTypes": [ - "text/plain", - "text/plain" - ], - "respFilenames": [ - "response1.txt", - "response2.txt" - ], - "respMimeTypes": [ - "text/plain", - "text/plain" - ] - } - } - ] - } - } - } - "#; - - let mock = peer_server - .mock("POST", "/graphql") - .with_status(200) - .with_body(peer_response_mock_data) - .create(); - - let peer_port = peer_server - .host_with_port() - .parse::() - .expect("Port must exist") - .port(); - let schema = TestSchema::new_with_graphql_peer(peer_port); - - // when - let res = schema.execute(query).await; - - // then - assert_eq!( - res.data.to_string(), - "{httpRawEvents: {edges: [{node: {origAddr: \"192.168.4.76\",respAddr: \"192.168.4.76\",origPort: 46378}}]}}" - ); - - mock.assert_async().await; - } - - #[tokio::test] - async fn rdp_empty() { - let schema = TestSchema::new(); - let query = r#" - { - rdpRawEvents( - filter: { - time: { start: "1992-06-05T00:00:00Z", end: "2025-09-22T00:00:00Z" } - source: "einsis" - origAddr: { start: "192.168.4.75", end: "192.168.4.79" } - respAddr: { start: "192.168.4.75", end: "192.168.4.79" } - respPort: { start: 0, end: 200 } - } - first: 1 - ) { - edges { - node { - origAddr, - respAddr, - origPort, - } - } - } - }"#; - let res = schema.execute(query).await; - assert_eq!(res.data.to_string(), "{rdpRawEvents: {edges: []}}"); - } - - #[tokio::test] - async fn rdp_empty_giganto_cluster() { - // given - let query = r#" - { - rdpRawEvents( - filter: { - time: { start: "1992-06-05T00:00:00Z", end: "2025-09-22T00:00:00Z" } - source: "ingest src 2" - origAddr: { start: "192.168.4.75", end: "192.168.4.79" } - respAddr: { start: "192.168.4.75", end: "192.168.4.79" } - respPort: { start: 0, end: 200 } - } - first: 1 - ) { - edges { - node { - origAddr, - respAddr, - origPort, - } - } - } - }"#; - - let mut peer_server = mockito::Server::new_async().await; - let peer_response_mock_data = r#" - { - "data": { - "rdpRawEvents": { - "pageInfo": { - "hasPreviousPage": false, - "hasNextPage": false - }, - "edges": [ - ] - } - } - } - "#; - let mock = peer_server - .mock("POST", "/graphql") - .with_status(200) - .with_body(peer_response_mock_data) - .create(); - - let peer_port = peer_server - .host_with_port() - .parse::() - .expect("Port must exist") - .port(); - let schema = TestSchema::new_with_graphql_peer(peer_port); - - // when - let res = schema.execute(query).await; - - // then - assert_eq!(res.data.to_string(), "{rdpRawEvents: {edges: []}}"); - - mock.assert_async().await; - } - - #[tokio::test] - async fn rdp_with_data() { - let schema = TestSchema::new(); - let store = schema.db.rdp_store().unwrap(); - - insert_rdp_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); - insert_rdp_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); - - let query = r#" - { - rdpRawEvents( - filter: { - time: { start: "1992-06-05T00:00:00Z", end: "2025-09-22T00:00:00Z" } - source: "src 1" - origAddr: { start: "192.168.4.75", end: "192.168.4.79" } - origPort: { start: 46377, end: 46380 } - respPort: { start: 0, end: 200 } - } - first: 1 - ) { - edges { - node { - origAddr, - respAddr, - origPort, - } - } - } - }"#; - let res = schema.execute(query).await; - assert_eq!( - res.data.to_string(), - "{rdpRawEvents: {edges: [{node: {origAddr: \"192.168.4.76\",respAddr: \"192.168.4.76\",origPort: 46378}}]}}" - ); - } - - fn insert_rdp_raw_event(store: &RawEventStore, source: &str, timestamp: i64) { - let mut key = Vec::with_capacity(source.len() + 1 + mem::size_of::()); - key.extend_from_slice(source.as_bytes()); - key.push(0); - key.extend(timestamp.to_be_bytes()); - - let rdp_body = Rdp { - orig_addr: "192.168.4.76".parse::().unwrap(), - orig_port: 46378, - resp_addr: "192.168.4.76".parse::().unwrap(), - resp_port: 80, - proto: 17, - last_time: 1, - cookie: "rdp_test".to_string(), - }; - let ser_rdp_body = bincode::serialize(&rdp_body).unwrap(); - - store.append(&key, &ser_rdp_body).unwrap(); - } - - #[tokio::test] - async fn rdp_with_data_giganto_cluster() { - // given - let query = r#" - { - rdpRawEvents( - filter: { - time: { start: "1992-06-05T00:00:00Z", end: "2025-09-22T00:00:00Z" } - source: "src 2" - origAddr: { start: "192.168.4.75", end: "192.168.4.79" } - origPort: { start: 46377, end: 46380 } - respPort: { start: 0, end: 200 } - } - first: 1 - ) { - edges { - node { - origAddr, - respAddr, - origPort, - } - } - } - }"#; - - let mut peer_server = mockito::Server::new_async().await; - let peer_response_mock_data = r#" - { - "data": { - "rdpRawEvents": { - "pageInfo": { - "hasPreviousPage": true, - "hasNextPage": false - }, - "edges": [ - { - "cursor": "cGl0YTIwMjNNQlAAF5gitjR0HIM=", - "node": { - "timestamp": "2023-11-16T15:03:45.291779203+00:00", - "origAddr": "192.168.4.76", - "respAddr": "192.168.4.76", - "origPort": 46378, - "respPort": 54321, - "proto": 6, - "lastTime": 987654321, - "cookie": "session=xyz789" - } - } - ] - } - } - } - "#; - - let mock = peer_server - .mock("POST", "/graphql") - .with_status(200) - .with_body(peer_response_mock_data) - .create(); - - let peer_port = peer_server - .host_with_port() - .parse::() - .expect("Port must exist") - .port(); - let schema = TestSchema::new_with_graphql_peer(peer_port); - - // when - let res = schema.execute(query).await; - - // then - assert_eq!( - res.data.to_string(), - "{rdpRawEvents: {edges: [{node: {origAddr: \"192.168.4.76\",respAddr: \"192.168.4.76\",origPort: 46378}}]}}" - ); - - mock.assert_async().await; - } - - #[tokio::test] - async fn smtp_with_data() { - let schema = TestSchema::new(); - let store = schema.db.smtp_store().unwrap(); - - insert_smtp_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); - insert_smtp_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); - - let query = r#" - { - smtpRawEvents( - filter: { - source: "src 1" - } - first: 1 - ) { - edges { - node { - origAddr, - } - } - } - }"#; - let res = schema.execute(query).await; - assert_eq!( - res.data.to_string(), - "{smtpRawEvents: {edges: [{node: {origAddr: \"192.168.4.76\"}}]}}" - ); - } - - fn insert_smtp_raw_event(store: &RawEventStore, source: &str, timestamp: i64) { - let mut key = Vec::with_capacity(source.len() + 1 + mem::size_of::()); - key.extend_from_slice(source.as_bytes()); - key.push(0); - key.extend(timestamp.to_be_bytes()); - - let smtp_body = Smtp { - orig_addr: "192.168.4.76".parse::().unwrap(), - orig_port: 46378, - resp_addr: "192.168.4.76".parse::().unwrap(), - resp_port: 80, - proto: 17, - last_time: 1, - mailfrom: "mailfrom".to_string(), - date: "date".to_string(), - from: "from".to_string(), - to: "to".to_string(), - subject: "subject".to_string(), - agent: "agent".to_string(), - }; - let ser_smtp_body = bincode::serialize(&smtp_body).unwrap(); - - store.append(&key, &ser_smtp_body).unwrap(); - } - - #[tokio::test] - async fn smtp_with_data_giganto_cluster() { - // given - let query = r#" - { - smtpRawEvents( - filter: { - source: "src 2" - } - first: 1 - ) { - edges { - node { - origAddr, - } - } - } - }"#; - - let mut peer_server = mockito::Server::new_async().await; - let peer_response_mock_data = r#" - { - "data": { - "smtpRawEvents": { - "pageInfo": { - "hasPreviousPage": true, - "hasNextPage": false - }, - "edges": [ - { - "cursor": "cGl0YTIwMjNNQlAAF5gitjR0HIM=", - "node": { - "timestamp": "2023-11-16T15:03:45.291779203+00:00", - "origAddr": "192.168.4.76", - "respAddr": "192.168.4.76", - "origPort": 25, - "respPort": 587, - "proto": 6, - "lastTime": 987654321, - "mailfrom": "sender@example.com", - "date": "2023-11-16T15:03:45+00:00", - "from": "sender@example.com", - "to": "recipient@example.com", - "subject": "Test Email", - "agent": "SMTP Client 1.0" - } - } - ] - } - } - } - "#; - - let mock = peer_server - .mock("POST", "/graphql") - .with_status(200) - .with_body(peer_response_mock_data) - .create(); - - let peer_port = peer_server - .host_with_port() - .parse::() - .expect("Port must exist") - .port(); - let schema = TestSchema::new_with_graphql_peer(peer_port); - - // when - let res = schema.execute(query).await; - - // then - assert_eq!( - res.data.to_string(), - "{smtpRawEvents: {edges: [{node: {origAddr: \"192.168.4.76\"}}]}}" - ); - - mock.assert_async().await; - } - - #[tokio::test] - async fn ntlm_with_data() { - let schema = TestSchema::new(); - let store = schema.db.ntlm_store().unwrap(); - - insert_ntlm_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); - insert_ntlm_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); - - let query = r#" - { - ntlmRawEvents( - filter: { - source: "src 1" - } - first: 1 - ) { - edges { - node { - origAddr, - } - } - } - }"#; - let res = schema.execute(query).await; - assert_eq!( - res.data.to_string(), - "{ntlmRawEvents: {edges: [{node: {origAddr: \"192.168.4.76\"}}]}}" - ); - } - - fn insert_ntlm_raw_event(store: &RawEventStore, source: &str, timestamp: i64) { - let mut key = Vec::with_capacity(source.len() + 1 + mem::size_of::()); - key.extend_from_slice(source.as_bytes()); - key.push(0); - key.extend(timestamp.to_be_bytes()); - - let ntlm_body = Ntlm { - orig_addr: "192.168.4.76".parse::().unwrap(), - orig_port: 46378, - resp_addr: "192.168.4.76".parse::().unwrap(), - resp_port: 80, - proto: 17, - last_time: 1, - username: "bly".to_string(), - hostname: "host".to_string(), - domainname: "domain".to_string(), - server_nb_computer_name: "NB".to_string(), - server_dns_computer_name: "dns".to_string(), - server_tree_name: "tree".to_string(), - success: "tf".to_string(), - }; - let ser_ntlm_body = bincode::serialize(&ntlm_body).unwrap(); - - store.append(&key, &ser_ntlm_body).unwrap(); - } - - #[tokio::test] - async fn ntlm_with_data_giganto_cluster() { - // given - let query = r#" - { - ntlmRawEvents( - filter: { - source: "src 2" - } - first: 1 - ) { - edges { - node { - origAddr, - } - } - } - }"#; - - let mut peer_server = mockito::Server::new_async().await; - let peer_response_mock_data = r#" - { - "data": { - "ntlmRawEvents": { - "pageInfo": { - "hasPreviousPage": true, - "hasNextPage": false - }, - "edges": [ - { - "cursor": "cGl0YTIwMjNNQlAAF5gitjR0HIM=", - "node": { - "timestamp": "2023-11-16T15:03:45.291779203+00:00", - "origAddr": "192.168.4.76", - "respAddr": "192.168.1.200", - "origPort": 12345, - "respPort": 6789, - "proto": 6, - "lastTime": 987654321, - "username": "john_doe", - "hostname": "client_machine", - "domainname": "example.com", - "serverNbComputerName": "server_nb_computer", - "serverDnsComputerName": "server_dns_computer", - "serverTreeName": "server_tree", - "success": "true" - } - } - ] - } - } - } - "#; - - let mock = peer_server - .mock("POST", "/graphql") - .with_status(200) - .with_body(peer_response_mock_data) - .create(); - - let peer_port = peer_server - .host_with_port() - .parse::() - .expect("Port must exist") - .port(); - let schema = TestSchema::new_with_graphql_peer(peer_port); - - // when - let res = schema.execute(query).await; - - // then - assert_eq!( - res.data.to_string(), - "{ntlmRawEvents: {edges: [{node: {origAddr: \"192.168.4.76\"}}]}}" - ); - - mock.assert_async().await; - } - - #[tokio::test] - async fn kerberos_with_data() { - let schema = TestSchema::new(); - let store = schema.db.kerberos_store().unwrap(); - - insert_kerberos_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); - insert_kerberos_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); - - let query = r#" - { - kerberosRawEvents( - filter: { - source: "src 1" - } - first: 1 - ) { - edges { - node { - origAddr, - } - } - } - }"#; - let res = schema.execute(query).await; - assert_eq!( - res.data.to_string(), - "{kerberosRawEvents: {edges: [{node: {origAddr: \"192.168.4.76\"}}]}}" - ); - } - - fn insert_kerberos_raw_event(store: &RawEventStore, source: &str, timestamp: i64) { - let mut key = Vec::with_capacity(source.len() + 1 + mem::size_of::()); - key.extend_from_slice(source.as_bytes()); - key.push(0); - key.extend(timestamp.to_be_bytes()); - - let kerberos_body = Kerberos { - orig_addr: "192.168.4.76".parse::().unwrap(), - orig_port: 46378, - resp_addr: "192.168.4.76".parse::().unwrap(), - resp_port: 80, - proto: 17, - last_time: 1, - client_time: 1, - server_time: 1, - error_code: 1, - client_realm: "client_realm".to_string(), - cname_type: 1, - client_name: vec!["client_name".to_string()], - realm: "realm".to_string(), - sname_type: 1, - service_name: vec!["service_name".to_string()], - }; - let ser_kerberos_body = bincode::serialize(&kerberos_body).unwrap(); - - store.append(&key, &ser_kerberos_body).unwrap(); - } - - #[tokio::test] - async fn kerberos_with_data_giganto_cluster() { - // given - let query = r#" - { - kerberosRawEvents( - filter: { - source: "src 2" - } - first: 1 - ) { - edges { - node { - origAddr, - } - } - } - }"#; - - let mut peer_server = mockito::Server::new_async().await; - let peer_response_mock_data = r#" - { - "data": { - "kerberosRawEvents": { - "pageInfo": { - "hasPreviousPage": true, - "hasNextPage": false - }, - "edges": [ - { - "cursor": "cGl0YTIwMjNNQlAAF5gitjR0HIM=", - "node": { - "timestamp": "2023-11-16T15:03:45.291779203+00:00", - "origAddr": "192.168.4.76", - "respAddr": "192.168.1.200", - "origPort": 12345, - "respPort": 6789, - "proto": 17, - "lastTime": 987654321, - "clientTime": 123456789, - "serverTime": 987654321, - "errorCode": 0, - "clientRealm": "client_realm", - "cnameType": 1, - "clientName": [ - "john_doe" - ], - "realm": "example.com", - "snameType": 2, - "serviceName": [ - "service_name_1", - "service_name_2" - ] - } - } - ] - } - } - } - "#; - - let mock = peer_server - .mock("POST", "/graphql") - .with_status(200) - .with_body(peer_response_mock_data) - .create(); - - let peer_port = peer_server - .host_with_port() - .parse::() - .expect("Port must exist") - .port(); - let schema = TestSchema::new_with_graphql_peer(peer_port); - - // when - let res = schema.execute(query).await; - - // then - assert_eq!( - res.data.to_string(), - "{kerberosRawEvents: {edges: [{node: {origAddr: \"192.168.4.76\"}}]}}" - ); - - mock.assert_async().await; - } - - #[tokio::test] - async fn ssh_with_data() { - let schema = TestSchema::new(); - let store = schema.db.ssh_store().unwrap(); - - insert_ssh_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); - insert_ssh_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); - - let query = r#" - { - sshRawEvents( - filter: { - source: "src 1" - } - first: 1 - ) { - edges { - node { - origAddr, - } - } - } - }"#; - let res = schema.execute(query).await; - assert_eq!( - res.data.to_string(), - "{sshRawEvents: {edges: [{node: {origAddr: \"192.168.4.76\"}}]}}" - ); - } - - fn insert_ssh_raw_event(store: &RawEventStore, source: &str, timestamp: i64) { - let mut key = Vec::with_capacity(source.len() + 1 + mem::size_of::()); - key.extend_from_slice(source.as_bytes()); - key.push(0); - key.extend(timestamp.to_be_bytes()); - - let ssh_body = Ssh { - orig_addr: "192.168.4.76".parse::().unwrap(), - orig_port: 46378, - resp_addr: "192.168.4.76".parse::().unwrap(), - resp_port: 80, - proto: 17, - last_time: 1, - version: 01, - auth_success: "auth_success".to_string(), - auth_attempts: 3, - direction: "direction".to_string(), - client: "client".to_string(), - server: "server".to_string(), - cipher_alg: "cipher_alg".to_string(), - mac_alg: "mac_alg".to_string(), - compression_alg: "compression_alg".to_string(), - kex_alg: "kex_alg".to_string(), - host_key_alg: "host_key_alg".to_string(), - host_key: "host_key".to_string(), - }; - let ser_ssh_body = bincode::serialize(&ssh_body).unwrap(); - - store.append(&key, &ser_ssh_body).unwrap(); - } - - #[tokio::test] - async fn ssh_with_data_giganto_cluster() { - // given - let query = r#" - { - sshRawEvents( - filter: { - source: "src 2" - } - first: 1 - ) { - edges { - node { - origAddr, - } - } - } - }"#; - - let mut peer_server = mockito::Server::new_async().await; - let peer_response_mock_data = r#" - { - "data": { - "sshRawEvents": { - "pageInfo": { - "hasPreviousPage": true, - "hasNextPage": false - }, - "edges": [ - { - "cursor": "cGl0YTIwMjNNQlAAF5gitjR0HIM=", - "node": { - "timestamp": "2023-11-16T15:03:45.291779203+00:00", - "origAddr": "192.168.4.76", - "respAddr": "192.168.4.76", - "origPort": 22, - "respPort": 54321, - "proto": 6, - "lastTime": 987654321, - "version": 2, - "authSuccess": "true", - "authAttempts": 3, - "direction": "inbound", - "client": "ssh_client", - "server": "ssh_server", - "cipherAlg": "aes256-ctr", - "macAlg": "hmac-sha2-256", - "compressionAlg": "none", - "kexAlg": "diffie-hellman-group14-sha1", - "hostKeyAlg": "ssh-rsa", - "hostKey": "ssh_host_key" - } - } - ] - } - } - } - "#; - - let mock = peer_server - .mock("POST", "/graphql") - .with_status(200) - .with_body(peer_response_mock_data) - .create(); - - let peer_port = peer_server - .host_with_port() - .parse::() - .expect("Port must exist") - .port(); - let schema = TestSchema::new_with_graphql_peer(peer_port); - - // when - let res = schema.execute(query).await; - - // then - assert_eq!( - res.data.to_string(), - "{sshRawEvents: {edges: [{node: {origAddr: \"192.168.4.76\"}}]}}" - ); - - mock.assert_async().await; - } - - #[tokio::test] - async fn dce_rpc_with_data() { - let schema = TestSchema::new(); - let store = schema.db.dce_rpc_store().unwrap(); - - insert_dce_rpc_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); - insert_dce_rpc_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); - - let query = r#" - { - dceRpcRawEvents( - filter: { - source: "src 1" - } - first: 1 - ) { - edges { - node { - origAddr, - } - } - } - }"#; - let res = schema.execute(query).await; - assert_eq!( - res.data.to_string(), - "{dceRpcRawEvents: {edges: [{node: {origAddr: \"192.168.4.76\"}}]}}" - ); - } - - fn insert_dce_rpc_raw_event(store: &RawEventStore, source: &str, timestamp: i64) { - let mut key = Vec::with_capacity(source.len() + 1 + mem::size_of::()); - key.extend_from_slice(source.as_bytes()); - key.push(0); - key.extend(timestamp.to_be_bytes()); - - let dce_rpc_body = DceRpc { - orig_addr: "192.168.4.76".parse::().unwrap(), - orig_port: 46378, - resp_addr: "192.168.4.76".parse::().unwrap(), - resp_port: 80, - proto: 17, - last_time: 1, - rtt: 3, - named_pipe: "named_pipe".to_string(), - endpoint: "endpoint".to_string(), - operation: "operation".to_string(), - }; - let ser_dce_rpc_body = bincode::serialize(&dce_rpc_body).unwrap(); - - store.append(&key, &ser_dce_rpc_body).unwrap(); - } - - #[tokio::test] - async fn dce_rpc_with_data_giganto_cluster() { - // given - let query = r#" - { - dceRpcRawEvents( - filter: { - source: "src 2" - } - first: 1 - ) { - edges { - node { - origAddr, - } - } - } - }"#; - - let mut peer_server = mockito::Server::new_async().await; - let peer_response_mock_data = r#" - { - "data": { - "dceRpcRawEvents": { - "pageInfo": { - "hasPreviousPage": true, - "hasNextPage": false - }, - "edges": [ - { - "cursor": "cGl0YTIwMjNNQlAAF5gitjR0HIM=", - "node": { - "timestamp": "2023-11-16T15:03:45.291779203+00:00", - "origAddr": "192.168.4.76", - "respAddr": "192.168.4.76", - "origPort": 135, - "respPort": 54321, - "proto": 6, - "lastTime": 987654321, - "rtt": 123456, - "namedPipe": "example_pipe", - "endpoint": "rpc_endpoint", - "operation": "rpc_operation" - } - } - ] - } - } - } - "#; - - let mock = peer_server - .mock("POST", "/graphql") - .with_status(200) - .with_body(peer_response_mock_data) - .create(); - - let peer_port = peer_server - .host_with_port() - .parse::() - .expect("Port must exist") - .port(); - let schema = TestSchema::new_with_graphql_peer(peer_port); - - // when - let res = schema.execute(query).await; - - // then - assert_eq!( - res.data.to_string(), - "{dceRpcRawEvents: {edges: [{node: {origAddr: \"192.168.4.76\"}}]}}" - ); - mock.assert_async().await; - } - - #[tokio::test] - async fn ftp_with_data() { - let schema = TestSchema::new(); - let store = schema.db.ftp_store().unwrap(); - - insert_ftp_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); - insert_ftp_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); - - let query = r#" - { - ftpRawEvents( - filter: { - source: "src 1" - } - first: 1 - ) { - edges { - node { - origAddr, - } - } - } - }"#; - let res = schema.execute(query).await; - assert_eq!( - res.data.to_string(), - "{ftpRawEvents: {edges: [{node: {origAddr: \"192.168.4.76\"}}]}}" - ); - } - - fn insert_ftp_raw_event(store: &RawEventStore, source: &str, timestamp: i64) { - let mut key = Vec::with_capacity(source.len() + 1 + mem::size_of::()); - key.extend_from_slice(source.as_bytes()); - key.push(0); - key.extend(timestamp.to_be_bytes()); - - let ftp_body = Ftp { - orig_addr: "192.168.4.76".parse::().unwrap(), - orig_port: 46378, - resp_addr: "31.3.245.133".parse::().unwrap(), - resp_port: 80, - proto: 17, - last_time: 1, - user: "einsis".to_string(), - password: "aice".to_string(), - command: "command".to_string(), - reply_code: "500".to_string(), - reply_msg: "reply_message".to_string(), - data_passive: false, - data_orig_addr: "192.168.4.76".parse::().unwrap(), - data_resp_addr: "31.3.245.133".parse::().unwrap(), - data_resp_port: 80, - file: "ftp_file".to_string(), - file_size: 100, - file_id: "1".to_string(), - }; - let ser_ftp_body = bincode::serialize(&ftp_body).unwrap(); - - store.append(&key, &ser_ftp_body).unwrap(); - } - - #[tokio::test] - async fn ftp_with_data_giganto_cluster() { - // given - let query = r#" - { - ftpRawEvents( - filter: { - source: "src 2" - } - first: 1 - ) { - edges { - node { - origAddr, - } - } - } - }"#; - - let mut peer_server = mockito::Server::new_async().await; - let peer_response_mock_data = r#" - { - "data": { - "ftpRawEvents": { - "pageInfo": { - "hasPreviousPage": true, - "hasNextPage": false - }, - "edges": [ - { - "cursor": "cGl0YTIwMjNNQlAAF5gitjR0HIM=", - "node": { - "timestamp": "2023-11-16T15:03:45.291779203+00:00", - "origAddr": "192.168.4.76", - "respAddr": "192.168.4.76", - "origPort": 21, - "respPort": 12345, - "proto": 6, - "lastTime": 987654321, - "user": "example_user", - "password": "example_password", - "command": "example_command", - "replyCode": "200", - "replyMsg": "Command OK", - "dataPassive": true, - "dataOrigAddr": "192.168.4.76", - "dataRespAddr": "192.168.4.76", - "dataRespPort": 54321, - "file": "example_file.txt", - "fileSize": 1024, - "fileId": "123456789" - } - } - ] - } - } - } - "#; - - let mock = peer_server - .mock("POST", "/graphql") - .with_status(200) - .with_body(peer_response_mock_data) - .create(); - - let peer_port = peer_server - .host_with_port() - .parse::() - .expect("Port must exist") - .port(); - let schema = TestSchema::new_with_graphql_peer(peer_port); - - // when - let res = schema.execute(query).await; - - // then - assert_eq!( - res.data.to_string(), - "{ftpRawEvents: {edges: [{node: {origAddr: \"192.168.4.76\"}}]}}" - ); - - mock.assert_async().await; - } - - #[tokio::test] - async fn mqtt_with_data() { - let schema = TestSchema::new(); - let store = schema.db.mqtt_store().unwrap(); - - insert_mqtt_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); - insert_mqtt_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); - - let query = r#" - { - mqttRawEvents( - filter: { - source: "src 1" - } - first: 1 - ) { - edges { - node { - origAddr, - } - } - } - }"#; - let res = schema.execute(query).await; - assert_eq!( - res.data.to_string(), - "{mqttRawEvents: {edges: [{node: {origAddr: \"192.168.4.76\"}}]}}" - ); - } - - fn insert_mqtt_raw_event(store: &RawEventStore, source: &str, timestamp: i64) { - let mut key = Vec::with_capacity(source.len() + 1 + mem::size_of::()); - key.extend_from_slice(source.as_bytes()); - key.push(0); - key.extend(timestamp.to_be_bytes()); - - let mqtt_body = Mqtt { - orig_addr: "192.168.4.76".parse::().unwrap(), - orig_port: 46378, - resp_addr: "31.3.245.133".parse::().unwrap(), - resp_port: 80, - proto: 17, - last_time: 1, - protocol: "protocol".to_string(), - version: 1, - client_id: "1".to_string(), - connack_reason: 1, - subscribe: vec!["subscribe".to_string()], - suback_reason: vec![1], - }; - let ser_mqtt_body = bincode::serialize(&mqtt_body).unwrap(); - - store.append(&key, &ser_mqtt_body).unwrap(); - } - - #[tokio::test] - async fn mqtt_with_data_giganto_cluster() { - // given - - let query = r#" - { - mqttRawEvents( - filter: { - source: "src 2" - } - first: 1 - ) { - edges { - node { - origAddr, - } - } - } - }"#; - - let mut peer_server = mockito::Server::new_async().await; - let peer_response_mock_data = r#" - { - "data": { - "mqttRawEvents": { - "pageInfo": { - "hasPreviousPage": true, - "hasNextPage": false - }, - "edges": [ - { - "cursor": "cGl0YTIwMjNNQlAAF5gitjR0HIM=", - "node": { - "timestamp": "2023-11-16T15:03:45.291779203+00:00", - "origAddr": "192.168.4.76", - "respAddr": "192.168.4.76", - "origPort": 1883, - "respPort": 5678, - "proto": 6, - "lastTime": 987654321, - "protocol": "MQTT", - "version": 4, - "clientId": "example_client_id", - "connackReason": 0, - "subscribe": [ - "topic/example" - ], - "subackReason": [ - 0 - ] - } - } - ] - } - } - } - "#; - - let mock = peer_server - .mock("POST", "/graphql") - .with_status(200) - .with_body(peer_response_mock_data) - .create(); - - let peer_port = peer_server - .host_with_port() - .parse::() - .expect("Port must exist") - .port(); - let schema = TestSchema::new_with_graphql_peer(peer_port); - - // when - let res = schema.execute(query).await; - - // then - assert_eq!( - res.data.to_string(), - "{mqttRawEvents: {edges: [{node: {origAddr: \"192.168.4.76\"}}]}}" - ); - - mock.assert_async().await; - } - - #[tokio::test] - async fn ldap_with_data() { - let schema = TestSchema::new(); - let store = schema.db.ldap_store().unwrap(); - - insert_ldap_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); - insert_ldap_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); - - let query = r#" - { - ldapRawEvents( - filter: { - source: "src 1" - } - first: 1 - ) { - edges { - node { - origAddr, - } - } - } - }"#; - let res = schema.execute(query).await; - assert_eq!( - res.data.to_string(), - "{ldapRawEvents: {edges: [{node: {origAddr: \"192.168.4.76\"}}]}}" - ); - } - - fn insert_ldap_raw_event(store: &RawEventStore, source: &str, timestamp: i64) { - let mut key = Vec::with_capacity(source.len() + 1 + mem::size_of::()); - key.extend_from_slice(source.as_bytes()); - key.push(0); - key.extend(timestamp.to_be_bytes()); - - let ldap_body = Ldap { - orig_addr: "192.168.4.76".parse::().unwrap(), - orig_port: 46378, - resp_addr: "31.3.245.133".parse::().unwrap(), - resp_port: 80, - proto: 17, - last_time: 1, - message_id: 1, - version: 1, - opcode: vec!["opcode".to_string()], - result: vec!["result".to_string()], - diagnostic_message: Vec::new(), - object: Vec::new(), - argument: Vec::new(), - }; - let ser_ldap_body = bincode::serialize(&ldap_body).unwrap(); - - store.append(&key, &ser_ldap_body).unwrap(); - } - - #[tokio::test] - async fn ldap_with_data_giganto_cluster() { - // given - let query = r#" - { - ldapRawEvents( - filter: { - source: "src 2" - } - first: 1 - ) { - edges { - node { - origAddr, - } - } - } - }"#; - - let mut peer_server = mockito::Server::new_async().await; - let peer_response_mock_data = r#" - { - "data": { - "ldapRawEvents": { - "pageInfo": { - "hasPreviousPage": true, - "hasNextPage": false - }, - "edges": [ - { - "cursor": "cGl0YTIwMjNNQlAAF5gitjR0HIM=", - "node": { - "timestamp": "2023-11-16T15:03:45.291779203+00:00", - "origAddr": "192.168.4.76", - "respAddr": "192.168.4.76", - "origPort": 389, - "respPort": 636, - "proto": 6, - "lastTime": 987654321, - "messageId": 123, - "version": 3, - "opcode": [ - "bind", - "search" - ], - "result": [ - "success", - "noSuchObject" - ], - "diagnosticMessage": [ - "", - "Object not found" - ], - "object": [ - "CN=John Doe", - "OU=Users" - ], - "argument": [ - "username", - "(&(objectClass=user)(sAMAccountName=jdoe))" - ] - } - } - ] - } - } - } - "#; - - let mock = peer_server - .mock("POST", "/graphql") - .with_status(200) - .with_body(peer_response_mock_data) - .create(); - - let peer_port = peer_server - .host_with_port() - .parse::() - .expect("Port must exist") - .port(); - let schema = TestSchema::new_with_graphql_peer(peer_port); - - // when - let res = schema.execute(query).await; - - // then - assert_eq!( - res.data.to_string(), - "{ldapRawEvents: {edges: [{node: {origAddr: \"192.168.4.76\"}}]}}" - ); - - mock.assert_async().await; - } - - #[tokio::test] - async fn tls_with_data() { - let schema = TestSchema::new(); - let store = schema.db.tls_store().unwrap(); - - insert_tls_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); - insert_tls_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); - - let query = r#" - { - tlsRawEvents( - filter: { - source: "src 1" - } - first: 1 - ) { - edges { - node { - origAddr, - } - } - } - }"#; - let res = schema.execute(query).await; - assert_eq!( - res.data.to_string(), - "{tlsRawEvents: {edges: [{node: {origAddr: \"192.168.4.76\"}}]}}" - ); - } - - fn insert_tls_raw_event(store: &RawEventStore, source: &str, timestamp: i64) { - let mut key = Vec::with_capacity(source.len() + 1 + mem::size_of::()); - key.extend_from_slice(source.as_bytes()); - key.push(0); - key.extend(timestamp.to_be_bytes()); - - let tls_body = Tls { - orig_addr: "192.168.4.76".parse::().unwrap(), - orig_port: 46378, - resp_addr: "31.3.245.133".parse::().unwrap(), - resp_port: 80, - proto: 17, - last_time: 1, - server_name: "server_name".to_string(), - alpn_protocol: "alpn_protocol".to_string(), - ja3: "ja3".to_string(), - version: "version".to_string(), - cipher: 10, - ja3s: "ja3s".to_string(), - serial: "serial".to_string(), - subject_country: "sub_country".to_string(), - subject_org_name: "sub_org".to_string(), - subject_common_name: "sub_comm".to_string(), - validity_not_before: 11, - validity_not_after: 12, - subject_alt_name: "sub_alt".to_string(), - issuer_country: "issuer_country".to_string(), - issuer_org_name: "issuer_org".to_string(), - issuer_org_unit_name: "issuer_org_unit".to_string(), - issuer_common_name: "issuer_comm".to_string(), - last_alert: 13, - }; - let ser_tls_body = bincode::serialize(&tls_body).unwrap(); - - store.append(&key, &ser_tls_body).unwrap(); - } - - #[tokio::test] - async fn tls_with_data_giganto_cluster() { - // given - let query = r#" - { - tlsRawEvents( - filter: { - source: "src 2" - } - first: 1 - ) { - edges { - node { - origAddr, - } - } - } - }"#; - - let mut peer_server = mockito::Server::new_async().await; - let peer_response_mock_data = r#" - { - "data": { - "tlsRawEvents": { - "pageInfo": { - "hasPreviousPage": true, - "hasNextPage": false - }, - "edges": [ - { - "cursor": "cGl0YTIwMjNNQlAAF5gitjR0HIM=", - "node": { - "timestamp": "2023-11-16T15:03:45.291779203+00:00", - "origAddr": "192.168.4.76", - "respAddr": "192.168.4.76", - "origPort": 443, - "respPort": 54321, - "proto": 6, - "lastTime": 987654321, - "serverName": "example.com", - "alpnProtocol": "h2", - "ja3": "aabbccddeeff", - "version": "TLSv1.2", - "cipher": 256, - "ja3S": "1122334455", - "serial": "1234567890", - "subjectCountry": "US", - "subjectOrgName": "Organization", - "subjectCommonName": "CommonName", - "validityNotBefore": 1637076000, - "validityNotAfter": 1668612000, - "subjectAltName": "www.example.com", - "issuerCountry": "CA", - "issuerOrgName": "IssuerOrg", - "issuerOrgUnitName": "IssuerUnit", - "issuerCommonName": "IssuerCommon", - "lastAlert": 789012345 - } - } - ] - } - } - } - "#; - - let mock = peer_server - .mock("POST", "/graphql") - .with_status(200) - .with_body(peer_response_mock_data) - .create(); - - let peer_port = peer_server - .host_with_port() - .parse::() - .expect("Port must exist") - .port(); - let schema = TestSchema::new_with_graphql_peer(peer_port); - - // when - let res = schema.execute(query).await; - - // then - assert_eq!( - res.data.to_string(), - "{tlsRawEvents: {edges: [{node: {origAddr: \"192.168.4.76\"}}]}}" - ); - - mock.assert_async().await; - } - - #[tokio::test] - async fn smb_with_data() { - let schema = TestSchema::new(); - let store = schema.db.smb_store().unwrap(); - - insert_smb_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); - insert_smb_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); - - let query = r#" - { - smbRawEvents( - filter: { - source: "src 1" - } - first: 1 - ) { - edges { - node { - origAddr, - } - } - } - }"#; - let res = schema.execute(query).await; - assert_eq!( - res.data.to_string(), - "{smbRawEvents: {edges: [{node: {origAddr: \"192.168.4.76\"}}]}}" - ); - } - - fn insert_smb_raw_event(store: &RawEventStore, source: &str, timestamp: i64) { - let mut key = Vec::with_capacity(source.len() + 1 + mem::size_of::()); - key.extend_from_slice(source.as_bytes()); - key.push(0); - key.extend(timestamp.to_be_bytes()); - - let smb_body = Smb { - orig_addr: "192.168.4.76".parse::().unwrap(), - orig_port: 46378, - resp_addr: "31.3.245.133".parse::().unwrap(), - resp_port: 80, - proto: 17, - last_time: 1, - command: 0, - path: "something/path".to_string(), - service: "service".to_string(), - file_name: "fine_name".to_string(), - file_size: 10, - resource_type: 20, - fid: 30, - create_time: 10000000, - access_time: 20000000, - write_time: 10000000, - change_time: 20000000, - }; - let ser_smb_body = bincode::serialize(&smb_body).unwrap(); - - store.append(&key, &ser_smb_body).unwrap(); - } - - #[tokio::test] - async fn smb_with_data_giganto_cluster() { - // given - let query = r#" - { - smbRawEvents( - filter: { - source: "src 2" - } - first: 1 - ) { - edges { - node { - origAddr, - } - } - } - }"#; - let mut peer_server = mockito::Server::new_async().await; - let peer_response_mock_data = r#" - { - "data": { - "smbRawEvents": { - "pageInfo": { - "hasPreviousPage": true, - "hasNextPage": false - }, - "edges": [ - { - "cursor": "cGl0YTIwMjNNQlAAF5gitjR0HIM=", - "node": { - "timestamp": "2023-11-16T15:03:45.291779203+00:00", - "origAddr": "192.168.4.76", - "respAddr": "192.168.4.77", - "origPort": 445, - "respPort": 12345, - "proto": 6, - "lastTime": 987654321, - "command": 1, - "path": "\\share\\folder\\file.txt", - "service": "IPC", - "fileName": "file.txt", - "fileSize": 1024, - "resourceType": 1, - "fid": 123, - "createTime": 1609459200, - "accessTime": 1637076000, - "writeTime": 1668612000, - "changeTime": 1700148000 - } - } - ] - } - } - } - "#; - - let mock = peer_server - .mock("POST", "/graphql") - .with_status(200) - .with_body(peer_response_mock_data) - .create(); - - let peer_port = peer_server - .host_with_port() - .parse::() - .expect("Port must exist") - .port(); - let schema = TestSchema::new_with_graphql_peer(peer_port); - - // when - let res = schema.execute(query).await; - - // then - assert_eq!( - res.data.to_string(), - "{smbRawEvents: {edges: [{node: {origAddr: \"192.168.4.76\"}}]}}" - ); - - mock.assert_async().await; - } - - #[tokio::test] - async fn nfs_with_data() { - let schema = TestSchema::new(); - let store = schema.db.nfs_store().unwrap(); - - insert_nfs_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); - insert_nfs_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); - - let query = r#" - { - nfsRawEvents( - filter: { - source: "src 1" - } - first: 1 - ) { - edges { - node { - origAddr, - } - } - } - }"#; - let res = schema.execute(query).await; - assert_eq!( - res.data.to_string(), - "{nfsRawEvents: {edges: [{node: {origAddr: \"192.168.4.76\"}}]}}" - ); - } - - fn insert_nfs_raw_event(store: &RawEventStore, source: &str, timestamp: i64) { - let mut key = Vec::with_capacity(source.len() + 1 + mem::size_of::()); - key.extend_from_slice(source.as_bytes()); - key.push(0); - key.extend(timestamp.to_be_bytes()); - - let nfs_body = Nfs { - orig_addr: "192.168.4.76".parse::().unwrap(), - orig_port: 46378, - resp_addr: "31.3.245.133".parse::().unwrap(), - resp_port: 80, - proto: 17, - last_time: 1, - read_files: vec![], - write_files: vec![], - }; - let ser_nfs_body = bincode::serialize(&nfs_body).unwrap(); - - store.append(&key, &ser_nfs_body).unwrap(); - } - - #[tokio::test] - async fn nfs_with_data_giganto_cluster() { - // given - let query = r#" - { - nfsRawEvents( - filter: { - source: "src 2" - } - first: 1 - ) { - edges { - node { - origAddr, - } - } - } - }"#; - let mut peer_server = mockito::Server::new_async().await; - let peer_response_mock_data = r#" - { - "data": { - "nfsRawEvents": { - "pageInfo": { - "hasPreviousPage": true, - "hasNextPage": false - }, - "edges": [ - { - "cursor": "cGl0YTIwMjNNQlAAF5gitjR0HIM=", - "node": { - "timestamp": "2023-11-16T15:03:45.291779203+00:00", - "origAddr": "192.168.4.76", - "respAddr": "192.168.4.76", - "origPort": 2049, - "respPort": 54321, - "proto": 6, - "lastTime": 987654321, - "readFiles": [ - "file1.txt", - "file2.txt" - ], - "writeFiles": [ - "file3.txt", - "file4.txt" - ] - } - } - ] - } - } - } - "#; - - let mock = peer_server - .mock("POST", "/graphql") - .with_status(200) - .with_body(peer_response_mock_data) - .create(); - - let peer_port = peer_server - .host_with_port() - .parse::() - .expect("Port must exist") - .port(); - let schema = TestSchema::new_with_graphql_peer(peer_port); - - // when - let res = schema.execute(query).await; - - // then - assert_eq!( - res.data.to_string(), - "{nfsRawEvents: {edges: [{node: {origAddr: \"192.168.4.76\"}}]}}" - ); - mock.assert_async().await; - } - - #[tokio::test] - async fn conn_with_start_or_end() { - let schema = TestSchema::new(); - let store = schema.db.conn_store().unwrap(); - - insert_conn_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); - insert_conn_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); - - let query = r#" - { - connRawEvents( - filter: { - time: { start: "1992-06-05T00:00:00Z", end: "2050-09-22T00:00:00Z" } - source: "src 1" - origAddr: { start: "192.168.4.76" } - origPort: { end: 46380 } - } - first: 1 - ) { - edges { - node { - origAddr, - respAddr, - origPort, - respPort, - } - } - } - }"#; - let res = schema.execute(query).await; - assert_eq!( - res.data.to_string(), - "{connRawEvents: {edges: [{node: {origAddr: \"192.168.4.76\",respAddr: \"192.168.4.76\",origPort: 46378,respPort: 80}}]}}" - ); - } - - #[tokio::test] - async fn union() { - let schema = TestSchema::new(); - let conn_store = schema.db.conn_store().unwrap(); - let dns_store = schema.db.dns_store().unwrap(); - let http_store = schema.db.http_store().unwrap(); - let rdp_store = schema.db.rdp_store().unwrap(); - let ntlm_store = schema.db.ntlm_store().unwrap(); - let kerberos_store = schema.db.kerberos_store().unwrap(); - let ssh_store = schema.db.ssh_store().unwrap(); - let dce_rpc_store = schema.db.dce_rpc_store().unwrap(); - let ftp_store = schema.db.ftp_store().unwrap(); - let mqtt_store = schema.db.mqtt_store().unwrap(); - let ldap_store = schema.db.ldap_store().unwrap(); - let tls_store = schema.db.tls_store().unwrap(); - let smb_store = schema.db.smb_store().unwrap(); - let nfs_store = schema.db.nfs_store().unwrap(); - - insert_conn_raw_event( - &conn_store, - "src 1", - Utc.with_ymd_and_hms(2020, 1, 1, 0, 1, 1) - .unwrap() - .timestamp_nanos_opt() - .unwrap(), - ); - insert_dns_raw_event( - &dns_store, - "src 1", - Utc.with_ymd_and_hms(2021, 1, 1, 0, 1, 1) - .unwrap() - .timestamp_nanos_opt() - .unwrap(), - ); - insert_http_raw_event( - &http_store, - "src 1", - Utc.with_ymd_and_hms(2020, 6, 1, 0, 1, 1) - .unwrap() - .timestamp_nanos_opt() - .unwrap(), - ); - insert_rdp_raw_event( - &rdp_store, - "src 1", - Utc.with_ymd_and_hms(2020, 1, 5, 0, 1, 1) - .unwrap() - .timestamp_nanos_opt() - .unwrap(), - ); - insert_ntlm_raw_event( - &ntlm_store, - "src 1", - Utc.with_ymd_and_hms(2022, 1, 5, 0, 1, 1) - .unwrap() - .timestamp_nanos_opt() - .unwrap(), - ); - insert_kerberos_raw_event( - &kerberos_store, - "src 1", - Utc.with_ymd_and_hms(2023, 1, 5, 0, 1, 1) - .unwrap() - .timestamp_nanos_opt() - .unwrap(), - ); - insert_ssh_raw_event( - &ssh_store, - "src 1", - Utc.with_ymd_and_hms(2020, 1, 1, 0, 0, 1) - .unwrap() - .timestamp_nanos_opt() - .unwrap(), - ); - insert_dce_rpc_raw_event( - &dce_rpc_store, - "src 1", - Utc.with_ymd_and_hms(2020, 1, 5, 6, 5, 0) - .unwrap() - .timestamp_nanos_opt() - .unwrap(), - ); - insert_ftp_raw_event( - &ftp_store, - "src 1", - Utc.with_ymd_and_hms(2023, 1, 5, 12, 12, 0) - .unwrap() - .timestamp_nanos_opt() - .unwrap(), - ); - insert_mqtt_raw_event( - &mqtt_store, - "src 1", - Utc.with_ymd_and_hms(2023, 1, 5, 12, 12, 0) - .unwrap() - .timestamp_nanos_opt() - .unwrap(), - ); - insert_ldap_raw_event( - &ldap_store, - "src 1", - Utc.with_ymd_and_hms(2023, 1, 6, 12, 12, 0) - .unwrap() - .timestamp_nanos_opt() - .unwrap(), - ); - insert_tls_raw_event( - &tls_store, - "src 1", - Utc.with_ymd_and_hms(2023, 1, 6, 11, 11, 0) - .unwrap() - .timestamp_nanos_opt() - .unwrap(), - ); - insert_smb_raw_event( - &smb_store, - "src 1", - Utc.with_ymd_and_hms(2023, 1, 6, 12, 12, 10) - .unwrap() - .timestamp_nanos_opt() - .unwrap(), - ); - insert_nfs_raw_event( - &nfs_store, - "src 1", - Utc.with_ymd_and_hms(2023, 1, 6, 12, 13, 0) - .unwrap() - .timestamp_nanos_opt() - .unwrap(), - ); - - // order: ssh, conn, rdp, dce_rpc, http, dns, ntlm, kerberos, ftp, mqtt, tls, ldap, smb, nfs - let query = r#" - { - networkRawEvents( - filter: { - time: { start: "1992-06-05T00:00:00Z", end: "2025-09-22T00:00:00Z" } - source: "src 1" - } - first: 20 - ) { - edges { - node { - ... on ConnRawEvent { - timestamp - } - ... on DnsRawEvent { - timestamp - } - ... on HttpRawEvent { - timestamp - } - ... on RdpRawEvent { - timestamp - } - ... on NtlmRawEvent { - timestamp - } - ... on KerberosRawEvent { - timestamp - } - ... on SshRawEvent { - timestamp - } - ... on DceRpcRawEvent { - timestamp - } - ... on FtpRawEvent { - timestamp - } - ... on MqttRawEvent { - timestamp - } - ... on LdapRawEvent { - timestamp - } - ... on TlsRawEvent { - timestamp - } - ... on SmbRawEvent { - timestamp - } - ... on NfsRawEvent { - timestamp - } - __typename - } - } - } - }"#; - let res = schema.execute(query).await; - assert_eq!(res.data.to_string(), "{networkRawEvents: {edges: [{node: {timestamp: \"2020-01-01T00:00:01+00:00\",__typename: \"SshRawEvent\"}},{node: {timestamp: \"2020-01-01T00:01:01+00:00\",__typename: \"ConnRawEvent\"}},{node: {timestamp: \"2020-01-05T00:01:01+00:00\",__typename: \"RdpRawEvent\"}},{node: {timestamp: \"2020-01-05T06:05:00+00:00\",__typename: \"DceRpcRawEvent\"}},{node: {timestamp: \"2020-06-01T00:01:01+00:00\",__typename: \"HttpRawEvent\"}},{node: {timestamp: \"2021-01-01T00:01:01+00:00\",__typename: \"DnsRawEvent\"}},{node: {timestamp: \"2022-01-05T00:01:01+00:00\",__typename: \"NtlmRawEvent\"}},{node: {timestamp: \"2023-01-05T00:01:01+00:00\",__typename: \"KerberosRawEvent\"}},{node: {timestamp: \"2023-01-05T12:12:00+00:00\",__typename: \"FtpRawEvent\"}},{node: {timestamp: \"2023-01-05T12:12:00+00:00\",__typename: \"MqttRawEvent\"}},{node: {timestamp: \"2023-01-06T11:11:00+00:00\",__typename: \"TlsRawEvent\"}},{node: {timestamp: \"2023-01-06T12:12:00+00:00\",__typename: \"LdapRawEvent\"}},{node: {timestamp: \"2023-01-06T12:12:10+00:00\",__typename: \"SmbRawEvent\"}},{node: {timestamp: \"2023-01-06T12:13:00+00:00\",__typename: \"NfsRawEvent\"}}]}}"); - } - - #[tokio::test] - async fn search_empty() { - let schema = TestSchema::new(); - let query = r#" - { - searchHttpRawEvents( - filter: { - time: { start: "2020-01-01T00:01:01Z", end: "2020-01-01T01:01:02Z" } - source: "src 1" - origAddr: { start: "192.168.4.75", end: "192.168.4.79" } - respAddr: { start: "192.168.4.75", end: "192.168.4.79" } - origPort: { start: 46377, end: 46380 } - respPort: { start: 46377, end: 46380 } - timestamps:["2020-01-01T00:00:01Z","2020-01-01T00:01:01Z","2020-01-01T01:01:01Z","2020-01-02T00:00:01Z"] - } - ) - }"#; - let res = schema.execute(query).await; - assert_eq!(res.data.to_string(), "{searchHttpRawEvents: []}"); - } - - #[tokio::test] - async fn search_http_with_data() { - let schema = TestSchema::new(); - let store = schema.db.http_store().unwrap(); - - let timestamp1 = Utc.with_ymd_and_hms(2020, 1, 1, 0, 0, 1).unwrap(); //2020-01-01T00:00:01Z - let timestamp2 = Utc.with_ymd_and_hms(2020, 1, 1, 0, 1, 1).unwrap(); //2020-01-01T00:01:01Z - let timestamp3 = Utc.with_ymd_and_hms(2020, 1, 1, 1, 1, 1).unwrap(); //2020-01-01T01:01:01Z - let timestamp4 = Utc.with_ymd_and_hms(2020, 1, 2, 0, 0, 1).unwrap(); //2020-01-02T00:00:01Z - - insert_http_raw_event(&store, "src 1", timestamp1.timestamp_nanos_opt().unwrap()); - insert_http_raw_event(&store, "src 1", timestamp2.timestamp_nanos_opt().unwrap()); - insert_http_raw_event(&store, "src 1", timestamp3.timestamp_nanos_opt().unwrap()); - insert_http_raw_event(&store, "src 1", timestamp4.timestamp_nanos_opt().unwrap()); - - let query = r#" - { - searchHttpRawEvents( - filter: { - time: { start: "2020-01-01T00:01:01Z", end: "2020-01-01T01:01:02Z" } - source: "src 1" - origAddr: { start: "192.168.4.75", end: "192.168.4.79" } - respAddr: { start: "192.168.4.75", end: "192.168.4.79" } - origPort: { start: 46377, end: 46380 } - respPort: { start: 75, end: 85 } - timestamps:["2020-01-01T00:00:01Z","2020-01-01T00:01:01Z","2020-01-01T01:01:01Z","2020-01-02T00:00:01Z"] - } - ) - }"#; - let res = schema.execute(query).await; - assert_eq!( - res.data.to_string(), - "{searchHttpRawEvents: [\"2020-01-01T00:01:01+00:00\",\"2020-01-01T01:01:01+00:00\"]}" - ); - } - - #[tokio::test] - async fn search_conn_with_data() { - let schema = TestSchema::new(); - let store = schema.db.conn_store().unwrap(); - - let timestamp1 = Utc.with_ymd_and_hms(2020, 1, 1, 0, 0, 1).unwrap(); //2020-01-01T00:00:01Z - let timestamp2 = Utc.with_ymd_and_hms(2020, 1, 1, 0, 1, 1).unwrap(); //2020-01-01T00:01:01Z - let timestamp3 = Utc.with_ymd_and_hms(2020, 1, 1, 1, 1, 1).unwrap(); //2020-01-01T01:01:01Z - let timestamp4 = Utc.with_ymd_and_hms(2020, 1, 2, 0, 0, 1).unwrap(); //2020-01-02T00:00:01Z - - insert_conn_raw_event(&store, "src 1", timestamp1.timestamp_nanos_opt().unwrap()); - insert_conn_raw_event(&store, "src 1", timestamp2.timestamp_nanos_opt().unwrap()); - insert_conn_raw_event(&store, "src 1", timestamp3.timestamp_nanos_opt().unwrap()); - insert_conn_raw_event(&store, "src 1", timestamp4.timestamp_nanos_opt().unwrap()); - - let query = r#" - { - searchConnRawEvents( - filter: { - time: { start: "2020-01-01T00:01:01Z", end: "2020-01-01T01:01:02Z" } - source: "src 1" - origAddr: { start: "192.168.4.75", end: "192.168.4.79" } - respAddr: { start: "192.168.4.75", end: "192.168.4.79" } - origPort: { start: 46377, end: 46380 } - respPort: { start: 75, end: 85 } - timestamps:["2020-01-01T00:00:01Z","2020-01-01T00:01:01Z","2020-01-01T01:01:01Z","2020-01-02T00:00:01Z"] - } - ) - }"#; - let res = schema.execute(query).await; - assert_eq!( - res.data.to_string(), - "{searchConnRawEvents: [\"2020-01-01T00:01:01+00:00\",\"2020-01-01T01:01:01+00:00\"]}" - ); - } - - #[tokio::test] - async fn search_conn_with_data_giganto_cluster() { - let query = r#" - { - searchConnRawEvents( - filter: { - time: { start: "2020-01-01T00:01:01Z", end: "2020-01-01T01:01:02Z" } - source: "src 2" - origAddr: { start: "192.168.4.75", end: "192.168.4.79" } - respAddr: { start: "192.168.4.75", end: "192.168.4.79" } - origPort: { start: 46377, end: 46380 } - respPort: { start: 75, end: 85 } - timestamps:["2020-01-01T00:00:01Z","2020-01-01T00:01:01Z","2020-01-01T01:01:01Z","2020-01-02T00:00:01Z"] - } - ) - }"#; - - let mut peer_server = mockito::Server::new_async().await; - let peer_response_mock_data = r#" - { - "data": { - "searchConnRawEvents": [ - "2020-01-01T00:01:01+00:00", - "2020-01-01T01:01:01+00:00" - ] - } - } - "#; - - let mock = peer_server - .mock("POST", "/graphql") - .with_status(200) - .with_body(peer_response_mock_data) - .create(); - - let peer_port = peer_server - .host_with_port() - .parse::() - .expect("Port must exist") - .port(); - let schema = TestSchema::new_with_graphql_peer(peer_port); - - let res = schema.execute(query).await; - assert_eq!( - res.data.to_string(), - "{searchConnRawEvents: [\"2020-01-01T00:01:01+00:00\",\"2020-01-01T01:01:01+00:00\"]}" - ); - mock.assert_async().await; - } - - #[tokio::test] - async fn search_dns_with_data() { - let schema = TestSchema::new(); - let store = schema.db.dns_store().unwrap(); - - let timestamp1 = Utc.with_ymd_and_hms(2020, 1, 1, 0, 0, 1).unwrap(); //2020-01-01T00:00:01Z - let timestamp2 = Utc.with_ymd_and_hms(2020, 1, 1, 0, 1, 1).unwrap(); //2020-01-01T00:01:01Z - let timestamp3 = Utc.with_ymd_and_hms(2020, 1, 1, 1, 1, 1).unwrap(); //2020-01-01T01:01:01Z - let timestamp4 = Utc.with_ymd_and_hms(2020, 1, 2, 0, 0, 1).unwrap(); //2020-01-02T00:00:01Z - - insert_dns_raw_event(&store, "src 1", timestamp1.timestamp_nanos_opt().unwrap()); - insert_dns_raw_event(&store, "src 1", timestamp2.timestamp_nanos_opt().unwrap()); - insert_dns_raw_event(&store, "src 1", timestamp3.timestamp_nanos_opt().unwrap()); - insert_dns_raw_event(&store, "src 1", timestamp4.timestamp_nanos_opt().unwrap()); - - let query = r#" - { - searchDnsRawEvents( - filter: { - time: { start: "2020-01-01T00:01:01Z", end: "2020-01-01T01:01:02Z" } - source: "src 1" - origAddr: { start: "192.168.4.75", end: "192.168.4.79" } - respAddr: { start: "31.3.245.130", end: "31.3.245.135" } - origPort: { start: 70, end: 46380 } - respPort: { start: 75, end: 85 } - timestamps:["2020-01-01T00:00:01Z","2020-01-01T00:01:01Z","2020-01-01T01:01:01Z","2020-01-02T00:00:01Z"] - } - ) - }"#; - let res = schema.execute(query).await; - assert_eq!( - res.data.to_string(), - "{searchDnsRawEvents: [\"2020-01-01T00:01:01+00:00\",\"2020-01-01T01:01:01+00:00\"]}" - ); - } - - #[tokio::test] - async fn search_dns_with_data_giganto_cluster() { - let query = r#" - { - searchDnsRawEvents( - filter: { - time: { start: "2020-01-01T00:01:01Z", end: "2020-01-01T01:01:02Z" } - source: "src 2" - origAddr: { start: "192.168.4.75", end: "192.168.4.79" } - respAddr: { start: "31.3.245.130", end: "31.3.245.135" } - origPort: { start: 70, end: 46380 } - respPort: { start: 75, end: 85 } - timestamps:["2020-01-01T00:00:01Z","2020-01-01T00:01:01Z","2020-01-01T01:01:01Z","2020-01-02T00:00:01Z"] - } - ) - }"#; - - let mut peer_server = mockito::Server::new_async().await; - let peer_response_mock_data = r#" - { - "data": { - "searchDnsRawEvents": [ - "2020-01-01T00:01:01+00:00", - "2020-01-01T01:01:01+00:00" - ] - } - } - "#; - - let mock = peer_server - .mock("POST", "/graphql") - .with_status(200) - .with_body(peer_response_mock_data) - .create(); - - let peer_port = peer_server - .host_with_port() - .parse::() - .expect("Port must exist") - .port(); - let schema = TestSchema::new_with_graphql_peer(peer_port); - - let res = schema.execute(query).await; - assert_eq!( - res.data.to_string(), - "{searchDnsRawEvents: [\"2020-01-01T00:01:01+00:00\",\"2020-01-01T01:01:01+00:00\"]}" - ); - mock.assert_async().await; - } - - #[tokio::test] - async fn search_rdp_with_data() { - let schema = TestSchema::new(); - let store = schema.db.rdp_store().unwrap(); - - let timestamp1 = Utc.with_ymd_and_hms(2020, 1, 1, 0, 0, 1).unwrap(); //2020-01-01T00:00:01Z - let timestamp2 = Utc.with_ymd_and_hms(2020, 1, 1, 0, 1, 1).unwrap(); //2020-01-01T00:01:01Z - let timestamp3 = Utc.with_ymd_and_hms(2020, 1, 1, 1, 1, 1).unwrap(); //2020-01-01T01:01:01Z - let timestamp4 = Utc.with_ymd_and_hms(2020, 1, 2, 0, 0, 1).unwrap(); //2020-01-02T00:00:01Z - - insert_rdp_raw_event(&store, "src 1", timestamp1.timestamp_nanos_opt().unwrap()); - insert_rdp_raw_event(&store, "src 1", timestamp2.timestamp_nanos_opt().unwrap()); - insert_rdp_raw_event(&store, "src 1", timestamp3.timestamp_nanos_opt().unwrap()); - insert_rdp_raw_event(&store, "src 1", timestamp4.timestamp_nanos_opt().unwrap()); - - let query = r#" - { - searchRdpRawEvents( - filter: { - time: { start: "2020-01-01T00:01:01Z", end: "2020-01-01T01:01:02Z" } - source: "src 1" - origAddr: { start: "192.168.4.75", end: "192.168.4.79" } - respAddr: { start: "192.168.4.75", end: "192.168.4.79" } - origPort: { start: 46377, end: 46380 } - respPort: { start: 75, end: 85 } - timestamps:["2020-01-01T00:00:01Z","2020-01-01T00:01:01Z","2020-01-01T01:01:01Z","2020-01-02T00:00:01Z"] - } - ) - }"#; - let res = schema.execute(query).await; - assert_eq!( - res.data.to_string(), - "{searchRdpRawEvents: [\"2020-01-01T00:01:01+00:00\",\"2020-01-01T01:01:01+00:00\"]}" - ); - } - - #[tokio::test] - async fn search_rdp_with_data_giganto_cluster() { - let query = r#" - { - searchRdpRawEvents( - filter: { - time: { start: "2020-01-01T00:01:01Z", end: "2020-01-01T01:01:02Z" } - source: "src 2" - origAddr: { start: "192.168.4.75", end: "192.168.4.79" } - respAddr: { start: "192.168.4.75", end: "192.168.4.79" } - origPort: { start: 46377, end: 46380 } - respPort: { start: 75, end: 85 } - timestamps:["2020-01-01T00:00:01Z","2020-01-01T00:01:01Z","2020-01-01T01:01:01Z","2020-01-02T00:00:01Z"] - } - ) - }"#; - - let mut peer_server = mockito::Server::new_async().await; - let peer_response_mock_data = r#" - { - "data": { - "searchRdpRawEvents": [ - "2020-01-01T00:01:01+00:00", - "2020-01-01T01:01:01+00:00" - ] - } - } - "#; - - let mock = peer_server - .mock("POST", "/graphql") - .with_status(200) - .with_body(peer_response_mock_data) - .create(); - - let peer_port = peer_server - .host_with_port() - .parse::() - .expect("Port must exist") - .port(); - let schema = TestSchema::new_with_graphql_peer(peer_port); - - let res = schema.execute(query).await; - assert_eq!( - res.data.to_string(), - "{searchRdpRawEvents: [\"2020-01-01T00:01:01+00:00\",\"2020-01-01T01:01:01+00:00\"]}" - ); - mock.assert_async().await; - } - - #[tokio::test] - async fn search_smtp_with_data() { - let schema = TestSchema::new(); - let store = schema.db.smtp_store().unwrap(); - - let timestamp1 = Utc.with_ymd_and_hms(2020, 1, 1, 0, 0, 1).unwrap(); //2020-01-01T00:00:01Z - let timestamp2 = Utc.with_ymd_and_hms(2020, 1, 1, 0, 1, 1).unwrap(); //2020-01-01T00:01:01Z - let timestamp3 = Utc.with_ymd_and_hms(2020, 1, 1, 1, 1, 1).unwrap(); //2020-01-01T01:01:01Z - let timestamp4 = Utc.with_ymd_and_hms(2020, 1, 2, 0, 0, 1).unwrap(); //2020-01-02T00:00:01Z - - insert_smtp_raw_event(&store, "src 1", timestamp1.timestamp_nanos_opt().unwrap()); - insert_smtp_raw_event(&store, "src 1", timestamp2.timestamp_nanos_opt().unwrap()); - insert_smtp_raw_event(&store, "src 1", timestamp3.timestamp_nanos_opt().unwrap()); - insert_smtp_raw_event(&store, "src 1", timestamp4.timestamp_nanos_opt().unwrap()); - - let query = r#" - { - searchSmtpRawEvents( - filter: { - time: { start: "2020-01-01T00:01:01Z", end: "2020-01-01T01:01:02Z" } - source: "src 1" - origAddr: { start: "192.168.4.75", end: "192.168.4.79" } - respAddr: { start: "192.168.4.75", end: "192.168.4.79" } - origPort: { start: 46377, end: 46380 } - respPort: { start: 75, end: 85 } - timestamps:["2020-01-01T00:00:01Z","2020-01-01T00:01:01Z","2020-01-01T01:01:01Z","2020-01-02T00:00:01Z"] - } - ) - }"#; - let res = schema.execute(query).await; - assert_eq!( - res.data.to_string(), - "{searchSmtpRawEvents: [\"2020-01-01T00:01:01+00:00\",\"2020-01-01T01:01:01+00:00\"]}" - ); - } - - #[tokio::test] - async fn search_smtp_with_data_giganto_cluster() { - let query = r#" - { - searchSmtpRawEvents( - filter: { - time: { start: "2020-01-01T00:01:01Z", end: "2020-01-01T01:01:02Z" } - source: "src 2" - origAddr: { start: "192.168.4.75", end: "192.168.4.79" } - respAddr: { start: "192.168.4.75", end: "192.168.4.79" } - origPort: { start: 46377, end: 46380 } - respPort: { start: 75, end: 85 } - timestamps:["2020-01-01T00:00:01Z","2020-01-01T00:01:01Z","2020-01-01T01:01:01Z","2020-01-02T00:00:01Z"] - } - ) - }"#; - - let mut peer_server = mockito::Server::new_async().await; - let peer_response_mock_data = r#" - { - "data": { - "searchSmtpRawEvents": [ - "2020-01-01T00:01:01+00:00", - "2020-01-01T01:01:01+00:00" - ] - } - } - "#; - - let mock = peer_server - .mock("POST", "/graphql") - .with_status(200) - .with_body(peer_response_mock_data) - .create(); - - let peer_port = peer_server - .host_with_port() - .parse::() - .expect("Port must exist") - .port(); - let schema = TestSchema::new_with_graphql_peer(peer_port); - - let res = schema.execute(query).await; - assert_eq!( - res.data.to_string(), - "{searchSmtpRawEvents: [\"2020-01-01T00:01:01+00:00\",\"2020-01-01T01:01:01+00:00\"]}" - ); - mock.assert_async().await; - } - - #[tokio::test] - async fn search_ntlm_with_data() { - let schema = TestSchema::new(); - let store = schema.db.ntlm_store().unwrap(); - - let timestamp1 = Utc.with_ymd_and_hms(2020, 1, 1, 0, 0, 1).unwrap(); //2020-01-01T00:00:01Z - let timestamp2 = Utc.with_ymd_and_hms(2020, 1, 1, 0, 1, 1).unwrap(); //2020-01-01T00:01:01Z - let timestamp3 = Utc.with_ymd_and_hms(2020, 1, 1, 1, 1, 1).unwrap(); //2020-01-01T01:01:01Z - let timestamp4 = Utc.with_ymd_and_hms(2020, 1, 2, 0, 0, 1).unwrap(); //2020-01-02T00:00:01Z - - insert_ntlm_raw_event(&store, "src 1", timestamp1.timestamp_nanos_opt().unwrap()); - insert_ntlm_raw_event(&store, "src 1", timestamp2.timestamp_nanos_opt().unwrap()); - insert_ntlm_raw_event(&store, "src 1", timestamp3.timestamp_nanos_opt().unwrap()); - insert_ntlm_raw_event(&store, "src 1", timestamp4.timestamp_nanos_opt().unwrap()); - - let query = r#" - { - searchNtlmRawEvents( - filter: { - time: { start: "2020-01-01T00:01:01Z", end: "2020-01-01T01:01:02Z" } - source: "src 1" - origAddr: { start: "192.168.4.75", end: "192.168.4.79" } - respAddr: { start: "192.168.4.75", end: "192.168.4.79" } - origPort: { start: 46377, end: 46380 } - respPort: { start: 75, end: 85 } - timestamps:["2020-01-01T00:00:01Z","2020-01-01T00:01:01Z","2020-01-01T01:01:01Z","2020-01-02T00:00:01Z"] - } - ) - }"#; - let res = schema.execute(query).await; - assert_eq!( - res.data.to_string(), - "{searchNtlmRawEvents: [\"2020-01-01T00:01:01+00:00\",\"2020-01-01T01:01:01+00:00\"]}" - ); - } - - #[tokio::test] - async fn search_ntlm_with_data_giganto_cluster() { - let query = r#" - { - searchNtlmRawEvents( - filter: { - time: { start: "2020-01-01T00:01:01Z", end: "2020-01-01T01:01:02Z" } - source: "src 2" - origAddr: { start: "192.168.4.75", end: "192.168.4.79" } - respAddr: { start: "192.168.4.75", end: "192.168.4.79" } - origPort: { start: 46377, end: 46380 } - respPort: { start: 75, end: 85 } - timestamps:["2020-01-01T00:00:01Z","2020-01-01T00:01:01Z","2020-01-01T01:01:01Z","2020-01-02T00:00:01Z"] - } - ) - }"#; - - let mut peer_server = mockito::Server::new_async().await; - let peer_response_mock_data = r#" - { - "data": { - "searchNtlmRawEvents": [ - "2020-01-01T00:01:01+00:00", - "2020-01-01T01:01:01+00:00" - ] - } - } - "#; - - let mock = peer_server - .mock("POST", "/graphql") - .with_status(200) - .with_body(peer_response_mock_data) - .create(); - - let peer_port = peer_server - .host_with_port() - .parse::() - .expect("Port must exist") - .port(); - let schema = TestSchema::new_with_graphql_peer(peer_port); - - let res = schema.execute(query).await; - assert_eq!( - res.data.to_string(), - "{searchNtlmRawEvents: [\"2020-01-01T00:01:01+00:00\",\"2020-01-01T01:01:01+00:00\"]}" - ); - mock.assert_async().await; - } - - #[tokio::test] - async fn search_kerberos_with_data() { - let schema = TestSchema::new(); - let store = schema.db.kerberos_store().unwrap(); - - let timestamp1 = Utc.with_ymd_and_hms(2020, 1, 1, 0, 0, 1).unwrap(); //2020-01-01T00:00:01Z - let timestamp2 = Utc.with_ymd_and_hms(2020, 1, 1, 0, 1, 1).unwrap(); //2020-01-01T00:01:01Z - let timestamp3 = Utc.with_ymd_and_hms(2020, 1, 1, 1, 1, 1).unwrap(); //2020-01-01T01:01:01Z - let timestamp4 = Utc.with_ymd_and_hms(2020, 1, 2, 0, 0, 1).unwrap(); //2020-01-02T00:00:01Z - - insert_kerberos_raw_event(&store, "src 1", timestamp1.timestamp_nanos_opt().unwrap()); - insert_kerberos_raw_event(&store, "src 1", timestamp2.timestamp_nanos_opt().unwrap()); - insert_kerberos_raw_event(&store, "src 1", timestamp3.timestamp_nanos_opt().unwrap()); - insert_kerberos_raw_event(&store, "src 1", timestamp4.timestamp_nanos_opt().unwrap()); - - let query = r#" - { - searchKerberosRawEvents( - filter: { - time: { start: "2020-01-01T00:01:01Z", end: "2020-01-01T01:01:02Z" } - source: "src 1" - origAddr: { start: "192.168.4.75", end: "192.168.4.79" } - respAddr: { start: "192.168.4.75", end: "192.168.4.79" } - origPort: { start: 46377, end: 46380 } - respPort: { start: 75, end: 85 } - timestamps:["2020-01-01T00:00:01Z","2020-01-01T00:01:01Z","2020-01-01T01:01:01Z","2020-01-02T00:00:01Z"] - } - ) - }"#; - let res = schema.execute(query).await; - assert_eq!( - res.data.to_string(), - "{searchKerberosRawEvents: [\"2020-01-01T00:01:01+00:00\",\"2020-01-01T01:01:01+00:00\"]}" - ); - } - - #[tokio::test] - async fn search_kerberos_with_data_giganto_cluster() { - let query = r#" - { - searchKerberosRawEvents( - filter: { - time: { start: "2020-01-01T00:01:01Z", end: "2020-01-01T01:01:02Z" } - source: "src 2" - origAddr: { start: "192.168.4.75", end: "192.168.4.79" } - respAddr: { start: "192.168.4.75", end: "192.168.4.79" } - origPort: { start: 46377, end: 46380 } - respPort: { start: 75, end: 85 } - timestamps:["2020-01-01T00:00:01Z","2020-01-01T00:01:01Z","2020-01-01T01:01:01Z","2020-01-02T00:00:01Z"] - } - ) - }"#; - let mut peer_server = mockito::Server::new_async().await; - let peer_response_mock_data = r#" - { - "data": { - "searchKerberosRawEvents": [ - "2020-01-01T00:01:01+00:00", - "2020-01-01T01:01:01+00:00" - ] - } - } - "#; - - let mock = peer_server - .mock("POST", "/graphql") - .with_status(200) - .with_body(peer_response_mock_data) - .create(); - - let peer_port = peer_server - .host_with_port() - .parse::() - .expect("Port must exist") - .port(); - let schema = TestSchema::new_with_graphql_peer(peer_port); - - let res = schema.execute(query).await; - assert_eq!( - res.data.to_string(), - "{searchKerberosRawEvents: [\"2020-01-01T00:01:01+00:00\",\"2020-01-01T01:01:01+00:00\"]}" - ); - mock.assert_async().await; - } - - #[tokio::test] - async fn search_ssh_with_data() { - let schema = TestSchema::new(); - let store = schema.db.ssh_store().unwrap(); - - let timestamp1 = Utc.with_ymd_and_hms(2020, 1, 1, 0, 0, 1).unwrap(); //2020-01-01T00:00:01Z - let timestamp2 = Utc.with_ymd_and_hms(2020, 1, 1, 0, 1, 1).unwrap(); //2020-01-01T00:01:01Z - let timestamp3 = Utc.with_ymd_and_hms(2020, 1, 1, 1, 1, 1).unwrap(); //2020-01-01T01:01:01Z - let timestamp4 = Utc.with_ymd_and_hms(2020, 1, 2, 0, 0, 1).unwrap(); //2020-01-02T00:00:01Z - - insert_ssh_raw_event(&store, "src 1", timestamp1.timestamp_nanos_opt().unwrap()); - insert_ssh_raw_event(&store, "src 1", timestamp2.timestamp_nanos_opt().unwrap()); - insert_ssh_raw_event(&store, "src 1", timestamp3.timestamp_nanos_opt().unwrap()); - insert_ssh_raw_event(&store, "src 1", timestamp4.timestamp_nanos_opt().unwrap()); - - let query = r#" - { - searchSshRawEvents( - filter: { - time: { start: "2020-01-01T00:01:01Z", end: "2020-01-01T01:01:02Z" } - source: "src 1" - origAddr: { start: "192.168.4.75", end: "192.168.4.79" } - respAddr: { start: "192.168.4.75", end: "192.168.4.79" } - origPort: { start: 46377, end: 46380 } - respPort: { start: 75, end: 85 } - timestamps:["2020-01-01T00:00:01Z","2020-01-01T00:01:01Z","2020-01-01T01:01:01Z","2020-01-02T00:00:01Z"] - } - ) - }"#; - let res = schema.execute(query).await; - assert_eq!( - res.data.to_string(), - "{searchSshRawEvents: [\"2020-01-01T00:01:01+00:00\",\"2020-01-01T01:01:01+00:00\"]}" - ); - } - - #[tokio::test] - async fn search_dce_rpc_with_data() { - let schema = TestSchema::new(); - let store = schema.db.dce_rpc_store().unwrap(); - - let timestamp1 = Utc.with_ymd_and_hms(2020, 1, 1, 0, 0, 1).unwrap(); //2020-01-01T00:00:01Z - let timestamp2 = Utc.with_ymd_and_hms(2020, 1, 1, 0, 1, 1).unwrap(); //2020-01-01T00:01:01Z - let timestamp3 = Utc.with_ymd_and_hms(2020, 1, 1, 1, 1, 1).unwrap(); //2020-01-01T01:01:01Z - let timestamp4 = Utc.with_ymd_and_hms(2020, 1, 2, 0, 0, 1).unwrap(); //2020-01-02T00:00:01Z - - insert_dce_rpc_raw_event(&store, "src 1", timestamp1.timestamp_nanos_opt().unwrap()); - insert_dce_rpc_raw_event(&store, "src 1", timestamp2.timestamp_nanos_opt().unwrap()); - insert_dce_rpc_raw_event(&store, "src 1", timestamp3.timestamp_nanos_opt().unwrap()); - insert_dce_rpc_raw_event(&store, "src 1", timestamp4.timestamp_nanos_opt().unwrap()); - - let query = r#" - { - searchDceRpcRawEvents( - filter: { - time: { start: "2020-01-01T00:01:01Z", end: "2020-01-01T01:01:02Z" } - source: "src 1" - origAddr: { start: "192.168.4.75", end: "192.168.4.79" } - respAddr: { start: "192.168.4.75", end: "192.168.4.79" } - origPort: { start: 46377, end: 46380 } - respPort: { start: 75, end: 85 } - timestamps:["2020-01-01T00:00:01Z","2020-01-01T00:01:01Z","2020-01-01T01:01:01Z","2020-01-02T00:00:01Z"] - } - ) - }"#; - let res = schema.execute(query).await; - assert_eq!( - res.data.to_string(), - "{searchDceRpcRawEvents: [\"2020-01-01T00:01:01+00:00\",\"2020-01-01T01:01:01+00:00\"]}" - ); - } - - #[tokio::test] - async fn search_ftp_with_data() { - let schema = TestSchema::new(); - let store = schema.db.ftp_store().unwrap(); - - let timestamp1 = Utc.with_ymd_and_hms(2020, 1, 1, 0, 0, 1).unwrap(); //2020-01-01T00:00:01Z - let timestamp2 = Utc.with_ymd_and_hms(2020, 1, 1, 0, 1, 1).unwrap(); //2020-01-01T00:01:01Z - let timestamp3 = Utc.with_ymd_and_hms(2020, 1, 1, 1, 1, 1).unwrap(); //2020-01-01T01:01:01Z - let timestamp4 = Utc.with_ymd_and_hms(2020, 1, 2, 0, 0, 1).unwrap(); //2020-01-02T00:00:01Z - - insert_ftp_raw_event(&store, "src 1", timestamp1.timestamp_nanos_opt().unwrap()); - insert_ftp_raw_event(&store, "src 1", timestamp2.timestamp_nanos_opt().unwrap()); - insert_ftp_raw_event(&store, "src 1", timestamp3.timestamp_nanos_opt().unwrap()); - insert_ftp_raw_event(&store, "src 1", timestamp4.timestamp_nanos_opt().unwrap()); - - let query = r#" - { - searchFtpRawEvents( - filter: { - time: { start: "2020-01-01T00:01:01Z", end: "2020-01-01T01:01:02Z" } - source: "src 1" - origAddr: { start: "192.168.4.75", end: "192.168.4.79" } - respAddr: { start: "31.3.245.130", end: "31.3.245.135" } - origPort: { start: 46377, end: 46380 } - respPort: { start: 75, end: 85 } - timestamps:["2020-01-01T00:00:01Z","2020-01-01T00:01:01Z","2020-01-01T01:01:01Z","2020-01-02T00:00:01Z"] - } - ) - }"#; - let res = schema.execute(query).await; - assert_eq!( - res.data.to_string(), - "{searchFtpRawEvents: [\"2020-01-01T00:01:01+00:00\",\"2020-01-01T01:01:01+00:00\"]}" - ); - } - - #[tokio::test] - async fn search_mqtt_with_data() { - let schema = TestSchema::new(); - let store = schema.db.mqtt_store().unwrap(); - - let timestamp1 = Utc.with_ymd_and_hms(2020, 1, 1, 0, 0, 1).unwrap(); //2020-01-01T00:00:01Z - let timestamp2 = Utc.with_ymd_and_hms(2020, 1, 1, 0, 1, 1).unwrap(); //2020-01-01T00:01:01Z - let timestamp3 = Utc.with_ymd_and_hms(2020, 1, 1, 1, 1, 1).unwrap(); //2020-01-01T01:01:01Z - let timestamp4 = Utc.with_ymd_and_hms(2020, 1, 2, 0, 0, 1).unwrap(); //2020-01-02T00:00:01Z - - insert_mqtt_raw_event(&store, "src 1", timestamp1.timestamp_nanos_opt().unwrap()); - insert_mqtt_raw_event(&store, "src 1", timestamp2.timestamp_nanos_opt().unwrap()); - insert_mqtt_raw_event(&store, "src 1", timestamp3.timestamp_nanos_opt().unwrap()); - insert_mqtt_raw_event(&store, "src 1", timestamp4.timestamp_nanos_opt().unwrap()); - - let query = r#" - { - searchMqttRawEvents( - filter: { - time: { start: "2020-01-01T00:01:01Z", end: "2020-01-01T01:01:02Z" } - source: "src 1" - origAddr: { start: "192.168.4.75", end: "192.168.4.79" } - respAddr: { start: "31.3.245.130", end: "31.3.245.135" } - origPort: { start: 46377, end: 46380 } - respPort: { start: 75, end: 85 } - timestamps:["2020-01-01T00:00:01Z","2020-01-01T00:01:01Z","2020-01-01T01:01:01Z","2020-01-02T00:00:01Z"] - } - ) - }"#; - let res = schema.execute(query).await; - assert_eq!( - res.data.to_string(), - "{searchMqttRawEvents: [\"2020-01-01T00:01:01+00:00\",\"2020-01-01T01:01:01+00:00\"]}" - ); - } - - #[tokio::test] - async fn search_ldap_with_data() { - let schema = TestSchema::new(); - let store = schema.db.ldap_store().unwrap(); - - let timestamp1 = Utc.with_ymd_and_hms(2020, 1, 1, 0, 0, 1).unwrap(); //2020-01-01T00:00:01Z - let timestamp2 = Utc.with_ymd_and_hms(2020, 1, 1, 0, 1, 1).unwrap(); //2020-01-01T00:01:01Z - let timestamp3 = Utc.with_ymd_and_hms(2020, 1, 1, 1, 1, 1).unwrap(); //2020-01-01T01:01:01Z - let timestamp4 = Utc.with_ymd_and_hms(2020, 1, 2, 0, 0, 1).unwrap(); //2020-01-02T00:00:01Z - - insert_ldap_raw_event(&store, "src 1", timestamp1.timestamp_nanos_opt().unwrap()); - insert_ldap_raw_event(&store, "src 1", timestamp2.timestamp_nanos_opt().unwrap()); - insert_ldap_raw_event(&store, "src 1", timestamp3.timestamp_nanos_opt().unwrap()); - insert_ldap_raw_event(&store, "src 1", timestamp4.timestamp_nanos_opt().unwrap()); - - let query = r#" - { - searchLdapRawEvents( - filter: { - time: { start: "2020-01-01T00:01:01Z", end: "2020-01-01T01:01:02Z" } - source: "src 1" - origAddr: { start: "192.168.4.75", end: "192.168.4.79" } - respAddr: { start: "31.3.245.130", end: "31.3.245.135" } - origPort: { start: 46377, end: 46380 } - respPort: { start: 75, end: 85 } - timestamps:["2020-01-01T00:00:01Z","2020-01-01T00:01:01Z","2020-01-01T01:01:01Z","2020-01-02T00:00:01Z"] - } - ) - }"#; - let res = schema.execute(query).await; - assert_eq!( - res.data.to_string(), - "{searchLdapRawEvents: [\"2020-01-01T00:01:01+00:00\",\"2020-01-01T01:01:01+00:00\"]}" - ); - } - - #[tokio::test] - async fn search_tls_with_data() { - let schema = TestSchema::new(); - let store = schema.db.tls_store().unwrap(); - - let timestamp1 = Utc.with_ymd_and_hms(2020, 1, 1, 0, 0, 1).unwrap(); //2020-01-01T00:00:01Z - let timestamp2 = Utc.with_ymd_and_hms(2020, 1, 1, 0, 1, 1).unwrap(); //2020-01-01T00:01:01Z - let timestamp3 = Utc.with_ymd_and_hms(2020, 1, 1, 1, 1, 1).unwrap(); //2020-01-01T01:01:01Z - let timestamp4 = Utc.with_ymd_and_hms(2020, 1, 2, 0, 0, 1).unwrap(); //2020-01-02T00:00:01Z - - insert_tls_raw_event(&store, "src 1", timestamp1.timestamp_nanos_opt().unwrap()); - insert_tls_raw_event(&store, "src 1", timestamp2.timestamp_nanos_opt().unwrap()); - insert_tls_raw_event(&store, "src 1", timestamp3.timestamp_nanos_opt().unwrap()); - insert_tls_raw_event(&store, "src 1", timestamp4.timestamp_nanos_opt().unwrap()); - - let query = r#" - { - searchTlsRawEvents( - filter: { - time: { start: "2020-01-01T00:01:01Z", end: "2020-01-01T01:01:02Z" } - source: "src 1" - origAddr: { start: "192.168.4.75", end: "192.168.4.79" } - respAddr: { start: "31.3.245.130", end: "31.3.245.135" } - origPort: { start: 46377, end: 46380 } - respPort: { start: 75, end: 85 } - timestamps:["2020-01-01T00:00:01Z","2020-01-01T00:01:01Z","2020-01-01T01:01:01Z","2020-01-02T00:00:01Z"] - } - ) - }"#; - let res = schema.execute(query).await; - assert_eq!( - res.data.to_string(), - "{searchTlsRawEvents: [\"2020-01-01T00:01:01+00:00\",\"2020-01-01T01:01:01+00:00\"]}" - ); - } - - #[tokio::test] - async fn search_smb_with_data() { - let schema = TestSchema::new(); - let store = schema.db.smb_store().unwrap(); - - let timestamp1 = Utc.with_ymd_and_hms(2020, 1, 1, 0, 0, 1).unwrap(); //2020-01-01T00:00:01Z - let timestamp2 = Utc.with_ymd_and_hms(2020, 1, 1, 0, 1, 1).unwrap(); //2020-01-01T00:01:01Z - let timestamp3 = Utc.with_ymd_and_hms(2020, 1, 1, 1, 1, 1).unwrap(); //2020-01-01T01:01:01Z - let timestamp4 = Utc.with_ymd_and_hms(2020, 1, 2, 0, 0, 1).unwrap(); //2020-01-02T00:00:01Z - - insert_smb_raw_event(&store, "src 1", timestamp1.timestamp_nanos_opt().unwrap()); - insert_smb_raw_event(&store, "src 1", timestamp2.timestamp_nanos_opt().unwrap()); - insert_smb_raw_event(&store, "src 1", timestamp3.timestamp_nanos_opt().unwrap()); - insert_smb_raw_event(&store, "src 1", timestamp4.timestamp_nanos_opt().unwrap()); - - let query = r#" - { - searchSmbRawEvents( - filter: { - time: { start: "2020-01-01T00:01:01Z", end: "2020-01-01T01:01:02Z" } - source: "src 1" - origAddr: { start: "192.168.4.75", end: "192.168.4.79" } - respAddr: { start: "31.3.245.130", end: "31.3.245.135" } - origPort: { start: 46377, end: 46380 } - respPort: { start: 75, end: 85 } - timestamps:["2020-01-01T00:00:01Z","2020-01-01T00:01:01Z","2020-01-01T01:01:01Z","2020-01-02T00:00:01Z"] - } - ) - }"#; - let res = schema.execute(query).await; - assert_eq!( - res.data.to_string(), - "{searchSmbRawEvents: [\"2020-01-01T00:01:01+00:00\",\"2020-01-01T01:01:01+00:00\"]}" - ); - } - - #[tokio::test] - async fn search_nfs_with_data() { - let schema = TestSchema::new(); - let store = schema.db.nfs_store().unwrap(); - - let timestamp1 = Utc.with_ymd_and_hms(2020, 1, 1, 0, 0, 1).unwrap(); //2020-01-01T00:00:01Z - let timestamp2 = Utc.with_ymd_and_hms(2020, 1, 1, 0, 1, 1).unwrap(); //2020-01-01T00:01:01Z - let timestamp3 = Utc.with_ymd_and_hms(2020, 1, 1, 1, 1, 1).unwrap(); //2020-01-01T01:01:01Z - let timestamp4 = Utc.with_ymd_and_hms(2020, 1, 2, 0, 0, 1).unwrap(); //2020-01-02T00:00:01Z - - insert_nfs_raw_event(&store, "src 1", timestamp1.timestamp_nanos_opt().unwrap()); - insert_nfs_raw_event(&store, "src 1", timestamp2.timestamp_nanos_opt().unwrap()); - insert_nfs_raw_event(&store, "src 1", timestamp3.timestamp_nanos_opt().unwrap()); - insert_nfs_raw_event(&store, "src 1", timestamp4.timestamp_nanos_opt().unwrap()); - - let query = r#" - { - searchNfsRawEvents( - filter: { - time: { start: "2020-01-01T00:01:01Z", end: "2020-01-01T01:01:02Z" } - source: "src 1" - origAddr: { start: "192.168.4.75", end: "192.168.4.79" } - respAddr: { start: "31.3.245.130", end: "31.3.245.135" } - origPort: { start: 46377, end: 46380 } - respPort: { start: 75, end: 85 } - timestamps:["2020-01-01T00:00:01Z","2020-01-01T00:01:01Z","2020-01-01T01:01:01Z","2020-01-02T00:00:01Z"] - } - ) - }"#; - let res = schema.execute(query).await; - assert_eq!( - res.data.to_string(), - "{searchNfsRawEvents: [\"2020-01-01T00:01:01+00:00\",\"2020-01-01T01:01:01+00:00\"]}" - ); - } -} diff --git a/src/graphql/network/tests.rs b/src/graphql/network/tests.rs new file mode 100644 index 0000000..7966204 --- /dev/null +++ b/src/graphql/network/tests.rs @@ -0,0 +1,3649 @@ +use crate::graphql::tests::TestSchema; +use crate::storage::RawEventStore; +use chrono::{Duration, TimeZone, Utc}; +use giganto_client::ingest::network::{ + Conn, DceRpc, Dns, Ftp, Http, Kerberos, Ldap, Mqtt, Nfs, Ntlm, Rdp, Smb, Smtp, Ssh, Tls, +}; +use mockito; +use std::mem; +use std::net::{IpAddr, SocketAddr}; + +#[tokio::test] +async fn conn_empty() { + let schema = TestSchema::new(); + let query = r#" + { + connRawEvents( + filter: { + time: { start: "1992-06-05T00:00:00Z", end: "2011-09-22T00:00:00Z" } + source: "ingest_source_1" + origAddr: { start: "192.168.4.75", end: "192.168.4.79" } + respAddr: { start: "192.168.4.75", end: "192.168.4.79" } + origPort: { start: 46377, end: 46380 } + respPort: { start: 50, end: 200 } + } + first: 1 + ) { + edges { + node { + origAddr, + respAddr, + origPort, + } + } + } + }"#; + let res = schema.execute(query).await; + assert_eq!(res.data.to_string(), "{connRawEvents: {edges: []}}"); +} + +#[tokio::test] +async fn conn_empty_giganto_cluster() { + // given + let query = r#" + { + connRawEvents( + filter: { + time: { start: "1992-06-05T00:00:00Z", end: "2011-09-22T00:00:00Z" } + source: "ingest src 2" + origAddr: { start: "192.168.4.75", end: "192.168.4.79" } + respAddr: { start: "192.168.4.75", end: "192.168.4.79" } + origPort: { start: 46377, end: 46380 } + respPort: { start: 50, end: 200 } + } + first: 1 + ) { + edges { + node { + origAddr, + respAddr, + origPort, + } + } + } + }"#; + + let mut peer_server = mockito::Server::new_async().await; + let peer_response_mock_data = r#" + { + "data": { + "connRawEvents": { + "pageInfo": { + "hasPreviousPage": false, + "hasNextPage": false + }, + "edges": [ + ] + } + } + } + "#; + let mock = peer_server + .mock("POST", "/graphql") + .with_status(200) + .with_body(peer_response_mock_data) + .create(); + + let peer_port = peer_server + .host_with_port() + .parse::() + .expect("Port must exist") + .port(); + let schema = TestSchema::new_with_graphql_peer(peer_port); + + // when + let res = schema.execute(query).await; + + // then + assert_eq!(res.data.to_string(), "{connRawEvents: {edges: []}}"); + + mock.assert_async().await; +} + +#[tokio::test] +async fn conn_with_data() { + let schema = TestSchema::new(); + let store = schema.db.conn_store().unwrap(); + + insert_conn_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); + insert_conn_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); + + let query = r#" + { + connRawEvents( + filter: { + time: { start: "1992-06-05T00:00:00Z", end: "2050-09-22T00:00:00Z" } + source: "src 1" + origAddr: { start: "192.168.4.72", end: "192.168.4.79" } + respAddr: { start: "192.168.4.75", end: "192.168.4.79" } + origPort: { start: 46378, end: 46379 } + respPort: { start: 50, end: 200 } + } + first: 1 + ) { + edges { + node { + origAddr, + respAddr, + origPort, + } + } + } + }"#; + let res = schema.execute(query).await; + assert_eq!( + res.data.to_string(), + "{connRawEvents: {edges: [{node: {origAddr: \"192.168.4.76\",respAddr: \"192.168.4.76\",origPort: 46378}}]}}" + ); +} + +fn insert_conn_raw_event(store: &RawEventStore, source: &str, timestamp: i64) { + let mut key = Vec::with_capacity(source.len() + 1 + mem::size_of::()); + key.extend_from_slice(source.as_bytes()); + key.push(0); + key.extend(timestamp.to_be_bytes()); + + let tmp_dur = Duration::nanoseconds(12345); + let conn_body = Conn { + orig_addr: "192.168.4.76".parse::().unwrap(), + orig_port: 46378, + resp_addr: "192.168.4.76".parse::().unwrap(), + resp_port: 80, + proto: 6, + duration: tmp_dur.num_nanoseconds().unwrap(), + service: "-".to_string(), + orig_bytes: 77, + resp_bytes: 295, + orig_pkts: 397, + resp_pkts: 511, + }; + let ser_conn_body = bincode::serialize(&conn_body).unwrap(); + + store.append(&key, &ser_conn_body).unwrap(); +} + +#[tokio::test] +async fn conn_with_data_giganto_cluster() { + // given + let query = r#" + { + connRawEvents( + filter: { + time: { start: "1992-06-05T00:00:00Z", end: "2050-09-22T00:00:00Z" } + source: "ingest src 2" + origAddr: { start: "192.168.4.72", end: "192.168.4.79" } + respAddr: { start: "192.168.4.75", end: "192.168.4.79" } + origPort: { start: 46378, end: 46379 } + respPort: { start: 50, end: 200 } + } + first: 1 + ) { + edges { + node { + origAddr, + respAddr, + origPort, + } + } + } + }"#; + + let mut peer_server = mockito::Server::new_async().await; + let peer_response_mock_data = r#" + { + "data": { + "connRawEvents": { + "pageInfo": { + "hasPreviousPage": true, + "hasNextPage": false + }, + "edges": [ + { + "cursor": "cGl0YTIwMjNNQlAAF5gitjR0HIM=", + "node": { + "timestamp": "2023-11-16T15:03:45.291779203+00:00", + "origAddr": "192.168.4.76", + "respAddr": "192.168.4.76", + "origPort": 46378, + "respPort": 443, + "proto": 6, + "service": "-", + "duration": 324234, + "origBytes": 0, + "respBytes": 0, + "origPkts": 6, + "respPkts": 0 + } + } + ] + } + } + } + "#; + + let mock = peer_server + .mock("POST", "/graphql") + .with_status(200) + .with_body(peer_response_mock_data) + .create(); + + let peer_port = peer_server + .host_with_port() + .parse::() + .expect("Port must exist") + .port(); + let schema = TestSchema::new_with_graphql_peer(peer_port); + + // when + let res = schema.execute(query).await; + + // then + assert_eq!( + res.data.to_string(), + "{connRawEvents: {edges: [{node: {origAddr: \"192.168.4.76\",respAddr: \"192.168.4.76\",origPort: 46378}}]}}" + ); + + mock.assert_async().await; +} + +#[tokio::test] +async fn dns_empty() { + let schema = TestSchema::new(); + let query = r#" + { + dnsRawEvents( + filter: { + time: { start: "1992-06-05T00:00:00Z", end: "2011-09-22T00:00:00Z" } + source: "einsis" + origAddr: { start: "192.168.4.75", end: "192.168.4.79" } + respAddr: { start: "31.3.245.123", end: "31.3.245.143" } + origPort: { start: 46377, end: 46380 } + respPort: { start: 100, end: 200 } + } + first: 1 + ) { + edges { + node { + origAddr, + respAddr, + origPort, + } + } + pageInfo { + hasPreviousPage + } + } + }"#; + let res = schema.execute(query).await; + assert_eq!( + res.data.to_string(), + "{dnsRawEvents: {edges: [],pageInfo: {hasPreviousPage: false}}}" + ); +} + +#[tokio::test] +async fn dns_empty_giganto_cluster() { + // given + let query = r#" + { + dnsRawEvents( + filter: { + time: { start: "1992-06-05T00:00:00Z", end: "2011-09-22T00:00:00Z" } + source: "src 2" + origAddr: { start: "192.168.4.75", end: "192.168.4.79" } + respAddr: { start: "31.3.245.123", end: "31.3.245.143" } + origPort: { start: 46377, end: 46380 } + respPort: { start: 100, end: 200 } + } + first: 1 + ) { + edges { + node { + origAddr, + respAddr, + origPort, + } + } + pageInfo { + hasPreviousPage + } + } + }"#; + + let mut peer_server = mockito::Server::new_async().await; + let peer_response_mock_data = r#" + { + "data": { + "dnsRawEvents": { + "pageInfo": { + "hasPreviousPage": false, + "hasNextPage": false + }, + "edges": [ + ] + } + } + } + "#; + let mock = peer_server + .mock("POST", "/graphql") + .with_status(200) + .with_body(peer_response_mock_data) + .create(); + + let peer_port = peer_server + .host_with_port() + .parse::() + .expect("Port must exist") + .port(); + let schema = TestSchema::new_with_graphql_peer(peer_port); + + // when + let res = schema.execute(query).await; + + // then + assert_eq!( + res.data.to_string(), + "{dnsRawEvents: {edges: [],pageInfo: {hasPreviousPage: false}}}" + ); + mock.assert_async().await; +} + +#[tokio::test] +async fn dns_with_data() { + let schema = TestSchema::new(); + let store = schema.db.dns_store().unwrap(); + + insert_dns_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); + insert_dns_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); + + let query = r#" + { + dnsRawEvents( + filter: { + source: "src 1" + origAddr: { start: "192.168.4.70", end: "192.168.4.78" } + respAddr: { start: "31.3.245.100", end: "31.3.245.245" } + origPort: { start: 46377, end: 46380 } + respPort: { start: 0, end: 200 } + } + last: 1 + ) { + edges { + node { + origAddr, + respAddr, + origPort, + } + } + } + }"#; + let res = schema.execute(query).await; + assert_eq!( + res.data.to_string(), + "{dnsRawEvents: {edges: [{node: {origAddr: \"192.168.4.76\",respAddr: \"31.3.245.133\",origPort: 46378}}]}}" + ); +} + +fn insert_dns_raw_event(store: &RawEventStore, source: &str, timestamp: i64) { + let mut key = Vec::with_capacity(source.len() + 1 + mem::size_of::()); + key.extend_from_slice(source.as_bytes()); + key.push(0); + key.extend(timestamp.to_be_bytes()); + + let dns_body = Dns { + orig_addr: "192.168.4.76".parse::().unwrap(), + orig_port: 46378, + resp_addr: "31.3.245.133".parse::().unwrap(), + resp_port: 80, + proto: 17, + last_time: 1, + query: "Hello Server Hello Server Hello Server".to_string(), + answer: vec!["1.1.1.1".to_string()], + trans_id: 1, + rtt: 1, + qclass: 0, + qtype: 0, + rcode: 0, + aa_flag: false, + tc_flag: false, + rd_flag: false, + ra_flag: false, + ttl: vec![1; 5], + }; + let ser_dns_body = bincode::serialize(&dns_body).unwrap(); + + store.append(&key, &ser_dns_body).unwrap(); +} + +#[tokio::test] +async fn dns_with_data_giganto_cluster() { + // given + let query = r#" + { + dnsRawEvents( + filter: { + source: "src 2" + origAddr: { start: "192.168.4.70", end: "192.168.4.78" } + respAddr: { start: "31.3.245.100", end: "31.3.245.245" } + origPort: { start: 46377, end: 46380 } + respPort: { start: 0, end: 200 } + } + last: 1 + ) { + edges { + node { + origAddr, + respAddr, + origPort, + } + } + } + }"#; + + let mut peer_server = mockito::Server::new_async().await; + let peer_response_mock_data = r#" + { + "data": { + "dnsRawEvents": { + "pageInfo": { + "hasPreviousPage": true, + "hasNextPage": false + }, + "edges": [ + { + "cursor": "cGl0YTIwMjNNQlAAF5gitjR0HIM=", + "node": { + "timestamp": "2023-11-16T15:03:45.291779203+00:00", + "origAddr": "192.168.4.76", + "respAddr": "31.3.245.133", + "origPort": 46378, + "respPort": 443, + "lastTime": 123456789, + "proto": 6, + "query": "example.com", + "answer": [ + "192.168.1.1" + ], + "transId": 12345, + "rtt": 567, + "qclass": 1, + "qtype": 1, + "rcode": 0, + "aaFlag": true, + "tcFlag": false, + "rdFlag": true, + "raFlag": false, + "ttl": [ + 3600, + 1800, + 900 + ] + } + } + ] + } + } + } + "#; + let mock = peer_server + .mock("POST", "/graphql") + .with_status(200) + .with_body(peer_response_mock_data) + .create(); + + let peer_port = peer_server + .host_with_port() + .parse::() + .expect("Port must exist") + .port(); + let schema = TestSchema::new_with_graphql_peer(peer_port); + + // when + let res = schema.execute(query).await; + + // then + assert_eq!( + res.data.to_string(), + "{dnsRawEvents: {edges: [{node: {origAddr: \"192.168.4.76\",respAddr: \"31.3.245.133\",origPort: 46378}}]}}" + ); + + mock.assert_async().await; +} + +#[tokio::test] +async fn http_empty() { + let schema = TestSchema::new(); + let query = r#" + { + httpRawEvents( + filter: { + time: { start: "1992-06-05T00:00:00Z", end: "2024-09-22T00:00:00Z" } + source: "einsis" + respAddr: { start: "192.168.4.75", end: "192.168.4.79" } + origPort: { start: 46377, end: 46380 } + respPort: { start: 0, end: 200 } + } + first: 1 + ) { + edges { + node { + origAddr, + respAddr, + origPort, + } + } + } + }"#; + let res = schema.execute(query).await; + assert_eq!(res.data.to_string(), "{httpRawEvents: {edges: []}}"); +} + +#[tokio::test] +async fn http_empty_giganto_cluster() { + // given + let query = r#" +{ + httpRawEvents( + filter: { + time: { start: "1992-06-05T00:00:00Z", end: "2024-09-22T00:00:00Z" } + source: "src 2" + respAddr: { start: "192.168.4.75", end: "192.168.4.79" } + origPort: { start: 46377, end: 46380 } + respPort: { start: 0, end: 200 } + } + first: 1 + ) { + edges { + node { + origAddr, + respAddr, + origPort, + } + } + } +}"#; + + let mut peer_server = mockito::Server::new_async().await; + let peer_response_mock_data = r#" +{ + "data": { + "httpRawEvents": { + "pageInfo": { + "hasPreviousPage": false, + "hasNextPage": false + }, + "edges": [ + ] + } + } +} +"#; + let mock = peer_server + .mock("POST", "/graphql") + .with_status(200) + .with_body(peer_response_mock_data) + .create(); + + let peer_port = peer_server + .host_with_port() + .parse::() + .expect("Port must exist") + .port(); + let schema = TestSchema::new_with_graphql_peer(peer_port); + + // when + let res = schema.execute(query).await; + + // then + assert_eq!(res.data.to_string(), "{httpRawEvents: {edges: []}}"); + + mock.assert_async().await; +} + +#[tokio::test] +async fn http_with_data() { + let schema = TestSchema::new(); + let store = schema.db.http_store().unwrap(); + + insert_http_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); + insert_http_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); + + let query = r#" + { + httpRawEvents( + filter: { + time: { start: "1992-06-05T00:00:00Z", end: "2025-09-22T00:00:00Z" } + source: "src 1" + origAddr: { start: "192.168.4.75", end: "192.168.4.79" } + respAddr: { start: "192.168.4.75", end: "192.168.4.79" } + origPort: { start: 46377, end: 46380 } + } + first: 1 + ) { + edges { + node { + origAddr, + respAddr, + origPort, + } + } + } + }"#; + let res = schema.execute(query).await; + assert_eq!( + res.data.to_string(), + "{httpRawEvents: {edges: [{node: {origAddr: \"192.168.4.76\",respAddr: \"192.168.4.76\",origPort: 46378}}]}}" + ); +} + +fn insert_http_raw_event(store: &RawEventStore, source: &str, timestamp: i64) { + let mut key = Vec::with_capacity(source.len() + 1 + mem::size_of::()); + key.extend_from_slice(source.as_bytes()); + key.push(0); + key.extend(timestamp.to_be_bytes()); + + let http_body = Http { + orig_addr: "192.168.4.76".parse::().unwrap(), + orig_port: 46378, + resp_addr: "192.168.4.76".parse::().unwrap(), + resp_port: 80, + proto: 17, + last_time: 1, + method: "POST".to_string(), + host: "einsis".to_string(), + uri: "/einsis.gif".to_string(), + referrer: "einsis.com".to_string(), + version: String::new(), + user_agent: "giganto".to_string(), + request_len: 0, + response_len: 0, + status_code: 200, + status_msg: String::new(), + username: String::new(), + password: String::new(), + cookie: String::new(), + content_encoding: String::new(), + content_type: String::new(), + cache_control: String::new(), + orig_filenames: Vec::new(), + orig_mime_types: Vec::new(), + resp_filenames: Vec::new(), + resp_mime_types: Vec::new(), + }; + let ser_http_body = bincode::serialize(&http_body).unwrap(); + + store.append(&key, &ser_http_body).unwrap(); +} + +#[tokio::test] +async fn http_with_data_giganto_cluster() { + // given + let query = r#" + { + httpRawEvents( + filter: { + time: { start: "1992-06-05T00:00:00Z", end: "2025-09-22T00:00:00Z" } + source: "src 2" + origAddr: { start: "192.168.4.75", end: "192.168.4.79" } + respAddr: { start: "192.168.4.75", end: "192.168.4.79" } + origPort: { start: 46377, end: 46380 } + } + first: 1 + ) { + edges { + node { + origAddr, + respAddr, + origPort, + } + } + } + }"#; + + let mut peer_server = mockito::Server::new_async().await; + let peer_response_mock_data = r#" + { + "data": { + "httpRawEvents": { + "pageInfo": { + "hasPreviousPage": true, + "hasNextPage": false + }, + "edges": [ + { + + "cursor": "cGl0YTIwMjNNQlAAF5gitjR0HIM=", + "node": { + "timestamp": "2023-11-16T15:03:45.291779203+00:00", + "origAddr": "192.168.4.76", + "respAddr": "192.168.4.76", + "origPort": 46378, + "respPort": 443, + "proto": 6, + "lastTime": 123456789, + "method": "GET", + "host": "example.com", + "uri": "/path/to/resource", + "referrer": "http://referrer.com", + "version": "HTTP/1.1", + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36", + "requestLen": 1024, + "responseLen": 2048, + "statusCode": 200, + "statusMsg": "OK", + "username": "user123", + "password": "pass456", + "cookie": "session=abc123", + "contentEncoding": "gzip", + "contentType": "text/html", + "cacheControl": "no-cache", + "origFilenames": [ + "file1.txt", + "file2.txt" + ], + "origMimeTypes": [ + "text/plain", + "text/plain" + ], + "respFilenames": [ + "response1.txt", + "response2.txt" + ], + "respMimeTypes": [ + "text/plain", + "text/plain" + ] + } + } + ] + } + } + } + "#; + + let mock = peer_server + .mock("POST", "/graphql") + .with_status(200) + .with_body(peer_response_mock_data) + .create(); + + let peer_port = peer_server + .host_with_port() + .parse::() + .expect("Port must exist") + .port(); + let schema = TestSchema::new_with_graphql_peer(peer_port); + + // when + let res = schema.execute(query).await; + + // then + assert_eq!( + res.data.to_string(), + "{httpRawEvents: {edges: [{node: {origAddr: \"192.168.4.76\",respAddr: \"192.168.4.76\",origPort: 46378}}]}}" + ); + + mock.assert_async().await; +} + +#[tokio::test] +async fn rdp_empty() { + let schema = TestSchema::new(); + let query = r#" + { + rdpRawEvents( + filter: { + time: { start: "1992-06-05T00:00:00Z", end: "2025-09-22T00:00:00Z" } + source: "einsis" + origAddr: { start: "192.168.4.75", end: "192.168.4.79" } + respAddr: { start: "192.168.4.75", end: "192.168.4.79" } + respPort: { start: 0, end: 200 } + } + first: 1 + ) { + edges { + node { + origAddr, + respAddr, + origPort, + } + } + } + }"#; + let res = schema.execute(query).await; + assert_eq!(res.data.to_string(), "{rdpRawEvents: {edges: []}}"); +} + +#[tokio::test] +async fn rdp_empty_giganto_cluster() { + // given + let query = r#" + { + rdpRawEvents( + filter: { + time: { start: "1992-06-05T00:00:00Z", end: "2025-09-22T00:00:00Z" } + source: "ingest src 2" + origAddr: { start: "192.168.4.75", end: "192.168.4.79" } + respAddr: { start: "192.168.4.75", end: "192.168.4.79" } + respPort: { start: 0, end: 200 } + } + first: 1 + ) { + edges { + node { + origAddr, + respAddr, + origPort, + } + } + } + }"#; + + let mut peer_server = mockito::Server::new_async().await; + let peer_response_mock_data = r#" + { + "data": { + "rdpRawEvents": { + "pageInfo": { + "hasPreviousPage": false, + "hasNextPage": false + }, + "edges": [ + ] + } + } + } + "#; + let mock = peer_server + .mock("POST", "/graphql") + .with_status(200) + .with_body(peer_response_mock_data) + .create(); + + let peer_port = peer_server + .host_with_port() + .parse::() + .expect("Port must exist") + .port(); + let schema = TestSchema::new_with_graphql_peer(peer_port); + + // when + let res = schema.execute(query).await; + + // then + assert_eq!(res.data.to_string(), "{rdpRawEvents: {edges: []}}"); + + mock.assert_async().await; +} + +#[tokio::test] +async fn rdp_with_data() { + let schema = TestSchema::new(); + let store = schema.db.rdp_store().unwrap(); + + insert_rdp_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); + insert_rdp_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); + + let query = r#" + { + rdpRawEvents( + filter: { + time: { start: "1992-06-05T00:00:00Z", end: "2025-09-22T00:00:00Z" } + source: "src 1" + origAddr: { start: "192.168.4.75", end: "192.168.4.79" } + origPort: { start: 46377, end: 46380 } + respPort: { start: 0, end: 200 } + } + first: 1 + ) { + edges { + node { + origAddr, + respAddr, + origPort, + } + } + } + }"#; + let res = schema.execute(query).await; + assert_eq!( + res.data.to_string(), + "{rdpRawEvents: {edges: [{node: {origAddr: \"192.168.4.76\",respAddr: \"192.168.4.76\",origPort: 46378}}]}}" + ); +} + +fn insert_rdp_raw_event(store: &RawEventStore, source: &str, timestamp: i64) { + let mut key = Vec::with_capacity(source.len() + 1 + mem::size_of::()); + key.extend_from_slice(source.as_bytes()); + key.push(0); + key.extend(timestamp.to_be_bytes()); + + let rdp_body = Rdp { + orig_addr: "192.168.4.76".parse::().unwrap(), + orig_port: 46378, + resp_addr: "192.168.4.76".parse::().unwrap(), + resp_port: 80, + proto: 17, + last_time: 1, + cookie: "rdp_test".to_string(), + }; + let ser_rdp_body = bincode::serialize(&rdp_body).unwrap(); + + store.append(&key, &ser_rdp_body).unwrap(); +} + +#[tokio::test] +async fn rdp_with_data_giganto_cluster() { + // given + let query = r#" + { + rdpRawEvents( + filter: { + time: { start: "1992-06-05T00:00:00Z", end: "2025-09-22T00:00:00Z" } + source: "src 2" + origAddr: { start: "192.168.4.75", end: "192.168.4.79" } + origPort: { start: 46377, end: 46380 } + respPort: { start: 0, end: 200 } + } + first: 1 + ) { + edges { + node { + origAddr, + respAddr, + origPort, + } + } + } + }"#; + + let mut peer_server = mockito::Server::new_async().await; + let peer_response_mock_data = r#" + { + "data": { + "rdpRawEvents": { + "pageInfo": { + "hasPreviousPage": true, + "hasNextPage": false + }, + "edges": [ + { + "cursor": "cGl0YTIwMjNNQlAAF5gitjR0HIM=", + "node": { + "timestamp": "2023-11-16T15:03:45.291779203+00:00", + "origAddr": "192.168.4.76", + "respAddr": "192.168.4.76", + "origPort": 46378, + "respPort": 54321, + "proto": 6, + "lastTime": 987654321, + "cookie": "session=xyz789" + } + } + ] + } + } + } + "#; + + let mock = peer_server + .mock("POST", "/graphql") + .with_status(200) + .with_body(peer_response_mock_data) + .create(); + + let peer_port = peer_server + .host_with_port() + .parse::() + .expect("Port must exist") + .port(); + let schema = TestSchema::new_with_graphql_peer(peer_port); + + // when + let res = schema.execute(query).await; + + // then + assert_eq!( + res.data.to_string(), + "{rdpRawEvents: {edges: [{node: {origAddr: \"192.168.4.76\",respAddr: \"192.168.4.76\",origPort: 46378}}]}}" + ); + + mock.assert_async().await; +} + +#[tokio::test] +async fn smtp_with_data() { + let schema = TestSchema::new(); + let store = schema.db.smtp_store().unwrap(); + + insert_smtp_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); + insert_smtp_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); + + let query = r#" + { + smtpRawEvents( + filter: { + source: "src 1" + } + first: 1 + ) { + edges { + node { + origAddr, + } + } + } + }"#; + let res = schema.execute(query).await; + assert_eq!( + res.data.to_string(), + "{smtpRawEvents: {edges: [{node: {origAddr: \"192.168.4.76\"}}]}}" + ); +} + +fn insert_smtp_raw_event(store: &RawEventStore, source: &str, timestamp: i64) { + let mut key = Vec::with_capacity(source.len() + 1 + mem::size_of::()); + key.extend_from_slice(source.as_bytes()); + key.push(0); + key.extend(timestamp.to_be_bytes()); + + let smtp_body = Smtp { + orig_addr: "192.168.4.76".parse::().unwrap(), + orig_port: 46378, + resp_addr: "192.168.4.76".parse::().unwrap(), + resp_port: 80, + proto: 17, + last_time: 1, + mailfrom: "mailfrom".to_string(), + date: "date".to_string(), + from: "from".to_string(), + to: "to".to_string(), + subject: "subject".to_string(), + agent: "agent".to_string(), + }; + let ser_smtp_body = bincode::serialize(&smtp_body).unwrap(); + + store.append(&key, &ser_smtp_body).unwrap(); +} + +#[tokio::test] +async fn smtp_with_data_giganto_cluster() { + // given + let query = r#" + { + smtpRawEvents( + filter: { + source: "src 2" + } + first: 1 + ) { + edges { + node { + origAddr, + } + } + } + }"#; + + let mut peer_server = mockito::Server::new_async().await; + let peer_response_mock_data = r#" + { + "data": { + "smtpRawEvents": { + "pageInfo": { + "hasPreviousPage": true, + "hasNextPage": false + }, + "edges": [ + { + "cursor": "cGl0YTIwMjNNQlAAF5gitjR0HIM=", + "node": { + "timestamp": "2023-11-16T15:03:45.291779203+00:00", + "origAddr": "192.168.4.76", + "respAddr": "192.168.4.76", + "origPort": 25, + "respPort": 587, + "proto": 6, + "lastTime": 987654321, + "mailfrom": "sender@example.com", + "date": "2023-11-16T15:03:45+00:00", + "from": "sender@example.com", + "to": "recipient@example.com", + "subject": "Test Email", + "agent": "SMTP Client 1.0" + } + } + ] + } + } + } + "#; + + let mock = peer_server + .mock("POST", "/graphql") + .with_status(200) + .with_body(peer_response_mock_data) + .create(); + + let peer_port = peer_server + .host_with_port() + .parse::() + .expect("Port must exist") + .port(); + let schema = TestSchema::new_with_graphql_peer(peer_port); + + // when + let res = schema.execute(query).await; + + // then + assert_eq!( + res.data.to_string(), + "{smtpRawEvents: {edges: [{node: {origAddr: \"192.168.4.76\"}}]}}" + ); + + mock.assert_async().await; +} + +#[tokio::test] +async fn ntlm_with_data() { + let schema = TestSchema::new(); + let store = schema.db.ntlm_store().unwrap(); + + insert_ntlm_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); + insert_ntlm_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); + + let query = r#" + { + ntlmRawEvents( + filter: { + source: "src 1" + } + first: 1 + ) { + edges { + node { + origAddr, + } + } + } + }"#; + let res = schema.execute(query).await; + assert_eq!( + res.data.to_string(), + "{ntlmRawEvents: {edges: [{node: {origAddr: \"192.168.4.76\"}}]}}" + ); +} + +fn insert_ntlm_raw_event(store: &RawEventStore, source: &str, timestamp: i64) { + let mut key = Vec::with_capacity(source.len() + 1 + mem::size_of::()); + key.extend_from_slice(source.as_bytes()); + key.push(0); + key.extend(timestamp.to_be_bytes()); + + let ntlm_body = Ntlm { + orig_addr: "192.168.4.76".parse::().unwrap(), + orig_port: 46378, + resp_addr: "192.168.4.76".parse::().unwrap(), + resp_port: 80, + proto: 17, + last_time: 1, + username: "bly".to_string(), + hostname: "host".to_string(), + domainname: "domain".to_string(), + server_nb_computer_name: "NB".to_string(), + server_dns_computer_name: "dns".to_string(), + server_tree_name: "tree".to_string(), + success: "tf".to_string(), + }; + let ser_ntlm_body = bincode::serialize(&ntlm_body).unwrap(); + + store.append(&key, &ser_ntlm_body).unwrap(); +} + +#[tokio::test] +async fn ntlm_with_data_giganto_cluster() { + // given + let query = r#" + { + ntlmRawEvents( + filter: { + source: "src 2" + } + first: 1 + ) { + edges { + node { + origAddr, + } + } + } + }"#; + + let mut peer_server = mockito::Server::new_async().await; + let peer_response_mock_data = r#" + { + "data": { + "ntlmRawEvents": { + "pageInfo": { + "hasPreviousPage": true, + "hasNextPage": false + }, + "edges": [ + { + "cursor": "cGl0YTIwMjNNQlAAF5gitjR0HIM=", + "node": { + "timestamp": "2023-11-16T15:03:45.291779203+00:00", + "origAddr": "192.168.4.76", + "respAddr": "192.168.1.200", + "origPort": 12345, + "respPort": 6789, + "proto": 6, + "lastTime": 987654321, + "username": "john_doe", + "hostname": "client_machine", + "domainname": "example.com", + "serverNbComputerName": "server_nb_computer", + "serverDnsComputerName": "server_dns_computer", + "serverTreeName": "server_tree", + "success": "true" + } + } + ] + } + } + } + "#; + + let mock = peer_server + .mock("POST", "/graphql") + .with_status(200) + .with_body(peer_response_mock_data) + .create(); + + let peer_port = peer_server + .host_with_port() + .parse::() + .expect("Port must exist") + .port(); + let schema = TestSchema::new_with_graphql_peer(peer_port); + + // when + let res = schema.execute(query).await; + + // then + assert_eq!( + res.data.to_string(), + "{ntlmRawEvents: {edges: [{node: {origAddr: \"192.168.4.76\"}}]}}" + ); + + mock.assert_async().await; +} + +#[tokio::test] +async fn kerberos_with_data() { + let schema = TestSchema::new(); + let store = schema.db.kerberos_store().unwrap(); + + insert_kerberos_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); + insert_kerberos_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); + + let query = r#" + { + kerberosRawEvents( + filter: { + source: "src 1" + } + first: 1 + ) { + edges { + node { + origAddr, + } + } + } + }"#; + let res = schema.execute(query).await; + assert_eq!( + res.data.to_string(), + "{kerberosRawEvents: {edges: [{node: {origAddr: \"192.168.4.76\"}}]}}" + ); +} + +fn insert_kerberos_raw_event(store: &RawEventStore, source: &str, timestamp: i64) { + let mut key = Vec::with_capacity(source.len() + 1 + mem::size_of::()); + key.extend_from_slice(source.as_bytes()); + key.push(0); + key.extend(timestamp.to_be_bytes()); + + let kerberos_body = Kerberos { + orig_addr: "192.168.4.76".parse::().unwrap(), + orig_port: 46378, + resp_addr: "192.168.4.76".parse::().unwrap(), + resp_port: 80, + proto: 17, + last_time: 1, + client_time: 1, + server_time: 1, + error_code: 1, + client_realm: "client_realm".to_string(), + cname_type: 1, + client_name: vec!["client_name".to_string()], + realm: "realm".to_string(), + sname_type: 1, + service_name: vec!["service_name".to_string()], + }; + let ser_kerberos_body = bincode::serialize(&kerberos_body).unwrap(); + + store.append(&key, &ser_kerberos_body).unwrap(); +} + +#[tokio::test] +async fn kerberos_with_data_giganto_cluster() { + // given + let query = r#" + { + kerberosRawEvents( + filter: { + source: "src 2" + } + first: 1 + ) { + edges { + node { + origAddr, + } + } + } + }"#; + + let mut peer_server = mockito::Server::new_async().await; + let peer_response_mock_data = r#" + { + "data": { + "kerberosRawEvents": { + "pageInfo": { + "hasPreviousPage": true, + "hasNextPage": false + }, + "edges": [ + { + "cursor": "cGl0YTIwMjNNQlAAF5gitjR0HIM=", + "node": { + "timestamp": "2023-11-16T15:03:45.291779203+00:00", + "origAddr": "192.168.4.76", + "respAddr": "192.168.1.200", + "origPort": 12345, + "respPort": 6789, + "proto": 17, + "lastTime": 987654321, + "clientTime": 123456789, + "serverTime": 987654321, + "errorCode": 0, + "clientRealm": "client_realm", + "cnameType": 1, + "clientName": [ + "john_doe" + ], + "realm": "example.com", + "snameType": 2, + "serviceName": [ + "service_name_1", + "service_name_2" + ] + } + } + ] + } + } + } + "#; + + let mock = peer_server + .mock("POST", "/graphql") + .with_status(200) + .with_body(peer_response_mock_data) + .create(); + + let peer_port = peer_server + .host_with_port() + .parse::() + .expect("Port must exist") + .port(); + let schema = TestSchema::new_with_graphql_peer(peer_port); + + // when + let res = schema.execute(query).await; + + // then + assert_eq!( + res.data.to_string(), + "{kerberosRawEvents: {edges: [{node: {origAddr: \"192.168.4.76\"}}]}}" + ); + + mock.assert_async().await; +} + +#[tokio::test] +async fn ssh_with_data() { + let schema = TestSchema::new(); + let store = schema.db.ssh_store().unwrap(); + + insert_ssh_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); + insert_ssh_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); + + let query = r#" + { + sshRawEvents( + filter: { + source: "src 1" + } + first: 1 + ) { + edges { + node { + origAddr, + } + } + } + }"#; + let res = schema.execute(query).await; + assert_eq!( + res.data.to_string(), + "{sshRawEvents: {edges: [{node: {origAddr: \"192.168.4.76\"}}]}}" + ); +} + +fn insert_ssh_raw_event(store: &RawEventStore, source: &str, timestamp: i64) { + let mut key = Vec::with_capacity(source.len() + 1 + mem::size_of::()); + key.extend_from_slice(source.as_bytes()); + key.push(0); + key.extend(timestamp.to_be_bytes()); + + let ssh_body = Ssh { + orig_addr: "192.168.4.76".parse::().unwrap(), + orig_port: 46378, + resp_addr: "192.168.4.76".parse::().unwrap(), + resp_port: 80, + proto: 17, + last_time: 1, + version: 01, + auth_success: "auth_success".to_string(), + auth_attempts: 3, + direction: "direction".to_string(), + client: "client".to_string(), + server: "server".to_string(), + cipher_alg: "cipher_alg".to_string(), + mac_alg: "mac_alg".to_string(), + compression_alg: "compression_alg".to_string(), + kex_alg: "kex_alg".to_string(), + host_key_alg: "host_key_alg".to_string(), + host_key: "host_key".to_string(), + }; + let ser_ssh_body = bincode::serialize(&ssh_body).unwrap(); + + store.append(&key, &ser_ssh_body).unwrap(); +} + +#[tokio::test] +async fn ssh_with_data_giganto_cluster() { + // given + let query = r#" + { + sshRawEvents( + filter: { + source: "src 2" + } + first: 1 + ) { + edges { + node { + origAddr, + } + } + } + }"#; + + let mut peer_server = mockito::Server::new_async().await; + let peer_response_mock_data = r#" + { + "data": { + "sshRawEvents": { + "pageInfo": { + "hasPreviousPage": true, + "hasNextPage": false + }, + "edges": [ + { + "cursor": "cGl0YTIwMjNNQlAAF5gitjR0HIM=", + "node": { + "timestamp": "2023-11-16T15:03:45.291779203+00:00", + "origAddr": "192.168.4.76", + "respAddr": "192.168.4.76", + "origPort": 22, + "respPort": 54321, + "proto": 6, + "lastTime": 987654321, + "version": 2, + "authSuccess": "true", + "authAttempts": 3, + "direction": "inbound", + "client": "ssh_client", + "server": "ssh_server", + "cipherAlg": "aes256-ctr", + "macAlg": "hmac-sha2-256", + "compressionAlg": "none", + "kexAlg": "diffie-hellman-group14-sha1", + "hostKeyAlg": "ssh-rsa", + "hostKey": "ssh_host_key" + } + } + ] + } + } + } + "#; + + let mock = peer_server + .mock("POST", "/graphql") + .with_status(200) + .with_body(peer_response_mock_data) + .create(); + + let peer_port = peer_server + .host_with_port() + .parse::() + .expect("Port must exist") + .port(); + let schema = TestSchema::new_with_graphql_peer(peer_port); + + // when + let res = schema.execute(query).await; + + // then + assert_eq!( + res.data.to_string(), + "{sshRawEvents: {edges: [{node: {origAddr: \"192.168.4.76\"}}]}}" + ); + + mock.assert_async().await; +} + +#[tokio::test] +async fn dce_rpc_with_data() { + let schema = TestSchema::new(); + let store = schema.db.dce_rpc_store().unwrap(); + + insert_dce_rpc_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); + insert_dce_rpc_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); + + let query = r#" + { + dceRpcRawEvents( + filter: { + source: "src 1" + } + first: 1 + ) { + edges { + node { + origAddr, + } + } + } + }"#; + let res = schema.execute(query).await; + assert_eq!( + res.data.to_string(), + "{dceRpcRawEvents: {edges: [{node: {origAddr: \"192.168.4.76\"}}]}}" + ); +} + +fn insert_dce_rpc_raw_event(store: &RawEventStore, source: &str, timestamp: i64) { + let mut key = Vec::with_capacity(source.len() + 1 + mem::size_of::()); + key.extend_from_slice(source.as_bytes()); + key.push(0); + key.extend(timestamp.to_be_bytes()); + + let dce_rpc_body = DceRpc { + orig_addr: "192.168.4.76".parse::().unwrap(), + orig_port: 46378, + resp_addr: "192.168.4.76".parse::().unwrap(), + resp_port: 80, + proto: 17, + last_time: 1, + rtt: 3, + named_pipe: "named_pipe".to_string(), + endpoint: "endpoint".to_string(), + operation: "operation".to_string(), + }; + let ser_dce_rpc_body = bincode::serialize(&dce_rpc_body).unwrap(); + + store.append(&key, &ser_dce_rpc_body).unwrap(); +} + +#[tokio::test] +async fn dce_rpc_with_data_giganto_cluster() { + // given + let query = r#" + { + dceRpcRawEvents( + filter: { + source: "src 2" + } + first: 1 + ) { + edges { + node { + origAddr, + } + } + } + }"#; + + let mut peer_server = mockito::Server::new_async().await; + let peer_response_mock_data = r#" + { + "data": { + "dceRpcRawEvents": { + "pageInfo": { + "hasPreviousPage": true, + "hasNextPage": false + }, + "edges": [ + { + "cursor": "cGl0YTIwMjNNQlAAF5gitjR0HIM=", + "node": { + "timestamp": "2023-11-16T15:03:45.291779203+00:00", + "origAddr": "192.168.4.76", + "respAddr": "192.168.4.76", + "origPort": 135, + "respPort": 54321, + "proto": 6, + "lastTime": 987654321, + "rtt": 123456, + "namedPipe": "example_pipe", + "endpoint": "rpc_endpoint", + "operation": "rpc_operation" + } + } + ] + } + } + } + "#; + + let mock = peer_server + .mock("POST", "/graphql") + .with_status(200) + .with_body(peer_response_mock_data) + .create(); + + let peer_port = peer_server + .host_with_port() + .parse::() + .expect("Port must exist") + .port(); + let schema = TestSchema::new_with_graphql_peer(peer_port); + + // when + let res = schema.execute(query).await; + + // then + assert_eq!( + res.data.to_string(), + "{dceRpcRawEvents: {edges: [{node: {origAddr: \"192.168.4.76\"}}]}}" + ); + mock.assert_async().await; +} + +#[tokio::test] +async fn ftp_with_data() { + let schema = TestSchema::new(); + let store = schema.db.ftp_store().unwrap(); + + insert_ftp_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); + insert_ftp_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); + + let query = r#" + { + ftpRawEvents( + filter: { + source: "src 1" + } + first: 1 + ) { + edges { + node { + origAddr, + } + } + } + }"#; + let res = schema.execute(query).await; + assert_eq!( + res.data.to_string(), + "{ftpRawEvents: {edges: [{node: {origAddr: \"192.168.4.76\"}}]}}" + ); +} + +fn insert_ftp_raw_event(store: &RawEventStore, source: &str, timestamp: i64) { + let mut key = Vec::with_capacity(source.len() + 1 + mem::size_of::()); + key.extend_from_slice(source.as_bytes()); + key.push(0); + key.extend(timestamp.to_be_bytes()); + + let ftp_body = Ftp { + orig_addr: "192.168.4.76".parse::().unwrap(), + orig_port: 46378, + resp_addr: "31.3.245.133".parse::().unwrap(), + resp_port: 80, + proto: 17, + last_time: 1, + user: "einsis".to_string(), + password: "aice".to_string(), + command: "command".to_string(), + reply_code: "500".to_string(), + reply_msg: "reply_message".to_string(), + data_passive: false, + data_orig_addr: "192.168.4.76".parse::().unwrap(), + data_resp_addr: "31.3.245.133".parse::().unwrap(), + data_resp_port: 80, + file: "ftp_file".to_string(), + file_size: 100, + file_id: "1".to_string(), + }; + let ser_ftp_body = bincode::serialize(&ftp_body).unwrap(); + + store.append(&key, &ser_ftp_body).unwrap(); +} + +#[tokio::test] +async fn ftp_with_data_giganto_cluster() { + // given + let query = r#" + { + ftpRawEvents( + filter: { + source: "src 2" + } + first: 1 + ) { + edges { + node { + origAddr, + } + } + } + }"#; + + let mut peer_server = mockito::Server::new_async().await; + let peer_response_mock_data = r#" + { + "data": { + "ftpRawEvents": { + "pageInfo": { + "hasPreviousPage": true, + "hasNextPage": false + }, + "edges": [ + { + "cursor": "cGl0YTIwMjNNQlAAF5gitjR0HIM=", + "node": { + "timestamp": "2023-11-16T15:03:45.291779203+00:00", + "origAddr": "192.168.4.76", + "respAddr": "192.168.4.76", + "origPort": 21, + "respPort": 12345, + "proto": 6, + "lastTime": 987654321, + "user": "example_user", + "password": "example_password", + "command": "example_command", + "replyCode": "200", + "replyMsg": "Command OK", + "dataPassive": true, + "dataOrigAddr": "192.168.4.76", + "dataRespAddr": "192.168.4.76", + "dataRespPort": 54321, + "file": "example_file.txt", + "fileSize": 1024, + "fileId": "123456789" + } + } + ] + } + } + } + "#; + + let mock = peer_server + .mock("POST", "/graphql") + .with_status(200) + .with_body(peer_response_mock_data) + .create(); + + let peer_port = peer_server + .host_with_port() + .parse::() + .expect("Port must exist") + .port(); + let schema = TestSchema::new_with_graphql_peer(peer_port); + + // when + let res = schema.execute(query).await; + + // then + assert_eq!( + res.data.to_string(), + "{ftpRawEvents: {edges: [{node: {origAddr: \"192.168.4.76\"}}]}}" + ); + + mock.assert_async().await; +} + +#[tokio::test] +async fn mqtt_with_data() { + let schema = TestSchema::new(); + let store = schema.db.mqtt_store().unwrap(); + + insert_mqtt_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); + insert_mqtt_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); + + let query = r#" + { + mqttRawEvents( + filter: { + source: "src 1" + } + first: 1 + ) { + edges { + node { + origAddr, + } + } + } + }"#; + let res = schema.execute(query).await; + assert_eq!( + res.data.to_string(), + "{mqttRawEvents: {edges: [{node: {origAddr: \"192.168.4.76\"}}]}}" + ); +} + +fn insert_mqtt_raw_event(store: &RawEventStore, source: &str, timestamp: i64) { + let mut key = Vec::with_capacity(source.len() + 1 + mem::size_of::()); + key.extend_from_slice(source.as_bytes()); + key.push(0); + key.extend(timestamp.to_be_bytes()); + + let mqtt_body = Mqtt { + orig_addr: "192.168.4.76".parse::().unwrap(), + orig_port: 46378, + resp_addr: "31.3.245.133".parse::().unwrap(), + resp_port: 80, + proto: 17, + last_time: 1, + protocol: "protocol".to_string(), + version: 1, + client_id: "1".to_string(), + connack_reason: 1, + subscribe: vec!["subscribe".to_string()], + suback_reason: vec![1], + }; + let ser_mqtt_body = bincode::serialize(&mqtt_body).unwrap(); + + store.append(&key, &ser_mqtt_body).unwrap(); +} + +#[tokio::test] +async fn mqtt_with_data_giganto_cluster() { + // given + + let query = r#" + { + mqttRawEvents( + filter: { + source: "src 2" + } + first: 1 + ) { + edges { + node { + origAddr, + } + } + } + }"#; + + let mut peer_server = mockito::Server::new_async().await; + let peer_response_mock_data = r#" + { + "data": { + "mqttRawEvents": { + "pageInfo": { + "hasPreviousPage": true, + "hasNextPage": false + }, + "edges": [ + { + "cursor": "cGl0YTIwMjNNQlAAF5gitjR0HIM=", + "node": { + "timestamp": "2023-11-16T15:03:45.291779203+00:00", + "origAddr": "192.168.4.76", + "respAddr": "192.168.4.76", + "origPort": 1883, + "respPort": 5678, + "proto": 6, + "lastTime": 987654321, + "protocol": "MQTT", + "version": 4, + "clientId": "example_client_id", + "connackReason": 0, + "subscribe": [ + "topic/example" + ], + "subackReason": [ + 0 + ] + } + } + ] + } + } + } + "#; + + let mock = peer_server + .mock("POST", "/graphql") + .with_status(200) + .with_body(peer_response_mock_data) + .create(); + + let peer_port = peer_server + .host_with_port() + .parse::() + .expect("Port must exist") + .port(); + let schema = TestSchema::new_with_graphql_peer(peer_port); + + // when + let res = schema.execute(query).await; + + // then + assert_eq!( + res.data.to_string(), + "{mqttRawEvents: {edges: [{node: {origAddr: \"192.168.4.76\"}}]}}" + ); + + mock.assert_async().await; +} + +#[tokio::test] +async fn ldap_with_data() { + let schema = TestSchema::new(); + let store = schema.db.ldap_store().unwrap(); + + insert_ldap_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); + insert_ldap_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); + + let query = r#" + { + ldapRawEvents( + filter: { + source: "src 1" + } + first: 1 + ) { + edges { + node { + origAddr, + } + } + } + }"#; + let res = schema.execute(query).await; + assert_eq!( + res.data.to_string(), + "{ldapRawEvents: {edges: [{node: {origAddr: \"192.168.4.76\"}}]}}" + ); +} + +fn insert_ldap_raw_event(store: &RawEventStore, source: &str, timestamp: i64) { + let mut key = Vec::with_capacity(source.len() + 1 + mem::size_of::()); + key.extend_from_slice(source.as_bytes()); + key.push(0); + key.extend(timestamp.to_be_bytes()); + + let ldap_body = Ldap { + orig_addr: "192.168.4.76".parse::().unwrap(), + orig_port: 46378, + resp_addr: "31.3.245.133".parse::().unwrap(), + resp_port: 80, + proto: 17, + last_time: 1, + message_id: 1, + version: 1, + opcode: vec!["opcode".to_string()], + result: vec!["result".to_string()], + diagnostic_message: Vec::new(), + object: Vec::new(), + argument: Vec::new(), + }; + let ser_ldap_body = bincode::serialize(&ldap_body).unwrap(); + + store.append(&key, &ser_ldap_body).unwrap(); +} + +#[tokio::test] +async fn ldap_with_data_giganto_cluster() { + // given + let query = r#" + { + ldapRawEvents( + filter: { + source: "src 2" + } + first: 1 + ) { + edges { + node { + origAddr, + } + } + } + }"#; + + let mut peer_server = mockito::Server::new_async().await; + let peer_response_mock_data = r#" + { + "data": { + "ldapRawEvents": { + "pageInfo": { + "hasPreviousPage": true, + "hasNextPage": false + }, + "edges": [ + { + "cursor": "cGl0YTIwMjNNQlAAF5gitjR0HIM=", + "node": { + "timestamp": "2023-11-16T15:03:45.291779203+00:00", + "origAddr": "192.168.4.76", + "respAddr": "192.168.4.76", + "origPort": 389, + "respPort": 636, + "proto": 6, + "lastTime": 987654321, + "messageId": 123, + "version": 3, + "opcode": [ + "bind", + "search" + ], + "result": [ + "success", + "noSuchObject" + ], + "diagnosticMessage": [ + "", + "Object not found" + ], + "object": [ + "CN=John Doe", + "OU=Users" + ], + "argument": [ + "username", + "(&(objectClass=user)(sAMAccountName=jdoe))" + ] + } + } + ] + } + } + } + "#; + + let mock = peer_server + .mock("POST", "/graphql") + .with_status(200) + .with_body(peer_response_mock_data) + .create(); + + let peer_port = peer_server + .host_with_port() + .parse::() + .expect("Port must exist") + .port(); + let schema = TestSchema::new_with_graphql_peer(peer_port); + + // when + let res = schema.execute(query).await; + + // then + assert_eq!( + res.data.to_string(), + "{ldapRawEvents: {edges: [{node: {origAddr: \"192.168.4.76\"}}]}}" + ); + + mock.assert_async().await; +} + +#[tokio::test] +async fn tls_with_data() { + let schema = TestSchema::new(); + let store = schema.db.tls_store().unwrap(); + + insert_tls_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); + insert_tls_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); + + let query = r#" + { + tlsRawEvents( + filter: { + source: "src 1" + } + first: 1 + ) { + edges { + node { + origAddr, + } + } + } + }"#; + let res = schema.execute(query).await; + assert_eq!( + res.data.to_string(), + "{tlsRawEvents: {edges: [{node: {origAddr: \"192.168.4.76\"}}]}}" + ); +} + +fn insert_tls_raw_event(store: &RawEventStore, source: &str, timestamp: i64) { + let mut key = Vec::with_capacity(source.len() + 1 + mem::size_of::()); + key.extend_from_slice(source.as_bytes()); + key.push(0); + key.extend(timestamp.to_be_bytes()); + + let tls_body = Tls { + orig_addr: "192.168.4.76".parse::().unwrap(), + orig_port: 46378, + resp_addr: "31.3.245.133".parse::().unwrap(), + resp_port: 80, + proto: 17, + last_time: 1, + server_name: "server_name".to_string(), + alpn_protocol: "alpn_protocol".to_string(), + ja3: "ja3".to_string(), + version: "version".to_string(), + cipher: 10, + ja3s: "ja3s".to_string(), + serial: "serial".to_string(), + subject_country: "sub_country".to_string(), + subject_org_name: "sub_org".to_string(), + subject_common_name: "sub_comm".to_string(), + validity_not_before: 11, + validity_not_after: 12, + subject_alt_name: "sub_alt".to_string(), + issuer_country: "issuer_country".to_string(), + issuer_org_name: "issuer_org".to_string(), + issuer_org_unit_name: "issuer_org_unit".to_string(), + issuer_common_name: "issuer_comm".to_string(), + last_alert: 13, + }; + let ser_tls_body = bincode::serialize(&tls_body).unwrap(); + + store.append(&key, &ser_tls_body).unwrap(); +} + +#[tokio::test] +async fn tls_with_data_giganto_cluster() { + // given + let query = r#" + { + tlsRawEvents( + filter: { + source: "src 2" + } + first: 1 + ) { + edges { + node { + origAddr, + } + } + } + }"#; + + let mut peer_server = mockito::Server::new_async().await; + let peer_response_mock_data = r#" + { + "data": { + "tlsRawEvents": { + "pageInfo": { + "hasPreviousPage": true, + "hasNextPage": false + }, + "edges": [ + { + "cursor": "cGl0YTIwMjNNQlAAF5gitjR0HIM=", + "node": { + "timestamp": "2023-11-16T15:03:45.291779203+00:00", + "origAddr": "192.168.4.76", + "respAddr": "192.168.4.76", + "origPort": 443, + "respPort": 54321, + "proto": 6, + "lastTime": 987654321, + "serverName": "example.com", + "alpnProtocol": "h2", + "ja3": "aabbccddeeff", + "version": "TLSv1.2", + "cipher": 256, + "ja3S": "1122334455", + "serial": "1234567890", + "subjectCountry": "US", + "subjectOrgName": "Organization", + "subjectCommonName": "CommonName", + "validityNotBefore": 1637076000, + "validityNotAfter": 1668612000, + "subjectAltName": "www.example.com", + "issuerCountry": "CA", + "issuerOrgName": "IssuerOrg", + "issuerOrgUnitName": "IssuerUnit", + "issuerCommonName": "IssuerCommon", + "lastAlert": 789012345 + } + } + ] + } + } + } + "#; + + let mock = peer_server + .mock("POST", "/graphql") + .with_status(200) + .with_body(peer_response_mock_data) + .create(); + + let peer_port = peer_server + .host_with_port() + .parse::() + .expect("Port must exist") + .port(); + let schema = TestSchema::new_with_graphql_peer(peer_port); + + // when + let res = schema.execute(query).await; + + // then + assert_eq!( + res.data.to_string(), + "{tlsRawEvents: {edges: [{node: {origAddr: \"192.168.4.76\"}}]}}" + ); + + mock.assert_async().await; +} + +#[tokio::test] +async fn smb_with_data() { + let schema = TestSchema::new(); + let store = schema.db.smb_store().unwrap(); + + insert_smb_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); + insert_smb_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); + + let query = r#" + { + smbRawEvents( + filter: { + source: "src 1" + } + first: 1 + ) { + edges { + node { + origAddr, + } + } + } + }"#; + let res = schema.execute(query).await; + assert_eq!( + res.data.to_string(), + "{smbRawEvents: {edges: [{node: {origAddr: \"192.168.4.76\"}}]}}" + ); +} + +fn insert_smb_raw_event(store: &RawEventStore, source: &str, timestamp: i64) { + let mut key = Vec::with_capacity(source.len() + 1 + mem::size_of::()); + key.extend_from_slice(source.as_bytes()); + key.push(0); + key.extend(timestamp.to_be_bytes()); + + let smb_body = Smb { + orig_addr: "192.168.4.76".parse::().unwrap(), + orig_port: 46378, + resp_addr: "31.3.245.133".parse::().unwrap(), + resp_port: 80, + proto: 17, + last_time: 1, + command: 0, + path: "something/path".to_string(), + service: "service".to_string(), + file_name: "fine_name".to_string(), + file_size: 10, + resource_type: 20, + fid: 30, + create_time: 10000000, + access_time: 20000000, + write_time: 10000000, + change_time: 20000000, + }; + let ser_smb_body = bincode::serialize(&smb_body).unwrap(); + + store.append(&key, &ser_smb_body).unwrap(); +} + +#[tokio::test] +async fn smb_with_data_giganto_cluster() { + // given + let query = r#" + { + smbRawEvents( + filter: { + source: "src 2" + } + first: 1 + ) { + edges { + node { + origAddr, + } + } + } + }"#; + let mut peer_server = mockito::Server::new_async().await; + let peer_response_mock_data = r#" + { + "data": { + "smbRawEvents": { + "pageInfo": { + "hasPreviousPage": true, + "hasNextPage": false + }, + "edges": [ + { + "cursor": "cGl0YTIwMjNNQlAAF5gitjR0HIM=", + "node": { + "timestamp": "2023-11-16T15:03:45.291779203+00:00", + "origAddr": "192.168.4.76", + "respAddr": "192.168.4.77", + "origPort": 445, + "respPort": 12345, + "proto": 6, + "lastTime": 987654321, + "command": 1, + "path": "\\share\\folder\\file.txt", + "service": "IPC", + "fileName": "file.txt", + "fileSize": 1024, + "resourceType": 1, + "fid": 123, + "createTime": 1609459200, + "accessTime": 1637076000, + "writeTime": 1668612000, + "changeTime": 1700148000 + } + } + ] + } + } + } + "#; + + let mock = peer_server + .mock("POST", "/graphql") + .with_status(200) + .with_body(peer_response_mock_data) + .create(); + + let peer_port = peer_server + .host_with_port() + .parse::() + .expect("Port must exist") + .port(); + let schema = TestSchema::new_with_graphql_peer(peer_port); + + // when + let res = schema.execute(query).await; + + // then + assert_eq!( + res.data.to_string(), + "{smbRawEvents: {edges: [{node: {origAddr: \"192.168.4.76\"}}]}}" + ); + + mock.assert_async().await; +} + +#[tokio::test] +async fn nfs_with_data() { + let schema = TestSchema::new(); + let store = schema.db.nfs_store().unwrap(); + + insert_nfs_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); + insert_nfs_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); + + let query = r#" + { + nfsRawEvents( + filter: { + source: "src 1" + } + first: 1 + ) { + edges { + node { + origAddr, + } + } + } + }"#; + let res = schema.execute(query).await; + assert_eq!( + res.data.to_string(), + "{nfsRawEvents: {edges: [{node: {origAddr: \"192.168.4.76\"}}]}}" + ); +} + +fn insert_nfs_raw_event(store: &RawEventStore, source: &str, timestamp: i64) { + let mut key = Vec::with_capacity(source.len() + 1 + mem::size_of::()); + key.extend_from_slice(source.as_bytes()); + key.push(0); + key.extend(timestamp.to_be_bytes()); + + let nfs_body = Nfs { + orig_addr: "192.168.4.76".parse::().unwrap(), + orig_port: 46378, + resp_addr: "31.3.245.133".parse::().unwrap(), + resp_port: 80, + proto: 17, + last_time: 1, + read_files: vec![], + write_files: vec![], + }; + let ser_nfs_body = bincode::serialize(&nfs_body).unwrap(); + + store.append(&key, &ser_nfs_body).unwrap(); +} + +#[tokio::test] +async fn nfs_with_data_giganto_cluster() { + // given + let query = r#" + { + nfsRawEvents( + filter: { + source: "src 2" + } + first: 1 + ) { + edges { + node { + origAddr, + } + } + } + }"#; + let mut peer_server = mockito::Server::new_async().await; + let peer_response_mock_data = r#" + { + "data": { + "nfsRawEvents": { + "pageInfo": { + "hasPreviousPage": true, + "hasNextPage": false + }, + "edges": [ + { + "cursor": "cGl0YTIwMjNNQlAAF5gitjR0HIM=", + "node": { + "timestamp": "2023-11-16T15:03:45.291779203+00:00", + "origAddr": "192.168.4.76", + "respAddr": "192.168.4.76", + "origPort": 2049, + "respPort": 54321, + "proto": 6, + "lastTime": 987654321, + "readFiles": [ + "file1.txt", + "file2.txt" + ], + "writeFiles": [ + "file3.txt", + "file4.txt" + ] + } + } + ] + } + } + } + "#; + + let mock = peer_server + .mock("POST", "/graphql") + .with_status(200) + .with_body(peer_response_mock_data) + .create(); + + let peer_port = peer_server + .host_with_port() + .parse::() + .expect("Port must exist") + .port(); + let schema = TestSchema::new_with_graphql_peer(peer_port); + + // when + let res = schema.execute(query).await; + + // then + assert_eq!( + res.data.to_string(), + "{nfsRawEvents: {edges: [{node: {origAddr: \"192.168.4.76\"}}]}}" + ); + mock.assert_async().await; +} + +#[tokio::test] +async fn conn_with_start_or_end() { + let schema = TestSchema::new(); + let store = schema.db.conn_store().unwrap(); + + insert_conn_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); + insert_conn_raw_event(&store, "src 1", Utc::now().timestamp_nanos_opt().unwrap()); + + let query = r#" + { + connRawEvents( + filter: { + time: { start: "1992-06-05T00:00:00Z", end: "2050-09-22T00:00:00Z" } + source: "src 1" + origAddr: { start: "192.168.4.76" } + origPort: { end: 46380 } + } + first: 1 + ) { + edges { + node { + origAddr, + respAddr, + origPort, + respPort, + } + } + } + }"#; + let res = schema.execute(query).await; + assert_eq!( + res.data.to_string(), + "{connRawEvents: {edges: [{node: {origAddr: \"192.168.4.76\",respAddr: \"192.168.4.76\",origPort: 46378,respPort: 80}}]}}" + ); +} + +#[tokio::test] +async fn union() { + let schema = TestSchema::new(); + let conn_store = schema.db.conn_store().unwrap(); + let dns_store = schema.db.dns_store().unwrap(); + let http_store = schema.db.http_store().unwrap(); + let rdp_store = schema.db.rdp_store().unwrap(); + let ntlm_store = schema.db.ntlm_store().unwrap(); + let kerberos_store = schema.db.kerberos_store().unwrap(); + let ssh_store = schema.db.ssh_store().unwrap(); + let dce_rpc_store = schema.db.dce_rpc_store().unwrap(); + let ftp_store = schema.db.ftp_store().unwrap(); + let mqtt_store = schema.db.mqtt_store().unwrap(); + let ldap_store = schema.db.ldap_store().unwrap(); + let tls_store = schema.db.tls_store().unwrap(); + let smb_store = schema.db.smb_store().unwrap(); + let nfs_store = schema.db.nfs_store().unwrap(); + + insert_conn_raw_event( + &conn_store, + "src 1", + Utc.with_ymd_and_hms(2020, 1, 1, 0, 1, 1) + .unwrap() + .timestamp_nanos_opt() + .unwrap(), + ); + insert_dns_raw_event( + &dns_store, + "src 1", + Utc.with_ymd_and_hms(2021, 1, 1, 0, 1, 1) + .unwrap() + .timestamp_nanos_opt() + .unwrap(), + ); + insert_http_raw_event( + &http_store, + "src 1", + Utc.with_ymd_and_hms(2020, 6, 1, 0, 1, 1) + .unwrap() + .timestamp_nanos_opt() + .unwrap(), + ); + insert_rdp_raw_event( + &rdp_store, + "src 1", + Utc.with_ymd_and_hms(2020, 1, 5, 0, 1, 1) + .unwrap() + .timestamp_nanos_opt() + .unwrap(), + ); + insert_ntlm_raw_event( + &ntlm_store, + "src 1", + Utc.with_ymd_and_hms(2022, 1, 5, 0, 1, 1) + .unwrap() + .timestamp_nanos_opt() + .unwrap(), + ); + insert_kerberos_raw_event( + &kerberos_store, + "src 1", + Utc.with_ymd_and_hms(2023, 1, 5, 0, 1, 1) + .unwrap() + .timestamp_nanos_opt() + .unwrap(), + ); + insert_ssh_raw_event( + &ssh_store, + "src 1", + Utc.with_ymd_and_hms(2020, 1, 1, 0, 0, 1) + .unwrap() + .timestamp_nanos_opt() + .unwrap(), + ); + insert_dce_rpc_raw_event( + &dce_rpc_store, + "src 1", + Utc.with_ymd_and_hms(2020, 1, 5, 6, 5, 0) + .unwrap() + .timestamp_nanos_opt() + .unwrap(), + ); + insert_ftp_raw_event( + &ftp_store, + "src 1", + Utc.with_ymd_and_hms(2023, 1, 5, 12, 12, 0) + .unwrap() + .timestamp_nanos_opt() + .unwrap(), + ); + insert_mqtt_raw_event( + &mqtt_store, + "src 1", + Utc.with_ymd_and_hms(2023, 1, 5, 12, 12, 0) + .unwrap() + .timestamp_nanos_opt() + .unwrap(), + ); + insert_ldap_raw_event( + &ldap_store, + "src 1", + Utc.with_ymd_and_hms(2023, 1, 6, 12, 12, 0) + .unwrap() + .timestamp_nanos_opt() + .unwrap(), + ); + insert_tls_raw_event( + &tls_store, + "src 1", + Utc.with_ymd_and_hms(2023, 1, 6, 11, 11, 0) + .unwrap() + .timestamp_nanos_opt() + .unwrap(), + ); + insert_smb_raw_event( + &smb_store, + "src 1", + Utc.with_ymd_and_hms(2023, 1, 6, 12, 12, 10) + .unwrap() + .timestamp_nanos_opt() + .unwrap(), + ); + insert_nfs_raw_event( + &nfs_store, + "src 1", + Utc.with_ymd_and_hms(2023, 1, 6, 12, 13, 0) + .unwrap() + .timestamp_nanos_opt() + .unwrap(), + ); + + // order: ssh, conn, rdp, dce_rpc, http, dns, ntlm, kerberos, ftp, mqtt, tls, ldap, smb, nfs + let query = r#" + { + networkRawEvents( + filter: { + time: { start: "1992-06-05T00:00:00Z", end: "2025-09-22T00:00:00Z" } + source: "src 1" + } + first: 20 + ) { + edges { + node { + ... on ConnRawEvent { + timestamp + } + ... on DnsRawEvent { + timestamp + } + ... on HttpRawEvent { + timestamp + } + ... on RdpRawEvent { + timestamp + } + ... on NtlmRawEvent { + timestamp + } + ... on KerberosRawEvent { + timestamp + } + ... on SshRawEvent { + timestamp + } + ... on DceRpcRawEvent { + timestamp + } + ... on FtpRawEvent { + timestamp + } + ... on MqttRawEvent { + timestamp + } + ... on LdapRawEvent { + timestamp + } + ... on TlsRawEvent { + timestamp + } + ... on SmbRawEvent { + timestamp + } + ... on NfsRawEvent { + timestamp + } + __typename + } + } + } + }"#; + let res = schema.execute(query).await; + assert_eq!(res.data.to_string(), "{networkRawEvents: {edges: [{node: {timestamp: \"2020-01-01T00:00:01+00:00\",__typename: \"SshRawEvent\"}},{node: {timestamp: \"2020-01-01T00:01:01+00:00\",__typename: \"ConnRawEvent\"}},{node: {timestamp: \"2020-01-05T00:01:01+00:00\",__typename: \"RdpRawEvent\"}},{node: {timestamp: \"2020-01-05T06:05:00+00:00\",__typename: \"DceRpcRawEvent\"}},{node: {timestamp: \"2020-06-01T00:01:01+00:00\",__typename: \"HttpRawEvent\"}},{node: {timestamp: \"2021-01-01T00:01:01+00:00\",__typename: \"DnsRawEvent\"}},{node: {timestamp: \"2022-01-05T00:01:01+00:00\",__typename: \"NtlmRawEvent\"}},{node: {timestamp: \"2023-01-05T00:01:01+00:00\",__typename: \"KerberosRawEvent\"}},{node: {timestamp: \"2023-01-05T12:12:00+00:00\",__typename: \"FtpRawEvent\"}},{node: {timestamp: \"2023-01-05T12:12:00+00:00\",__typename: \"MqttRawEvent\"}},{node: {timestamp: \"2023-01-06T11:11:00+00:00\",__typename: \"TlsRawEvent\"}},{node: {timestamp: \"2023-01-06T12:12:00+00:00\",__typename: \"LdapRawEvent\"}},{node: {timestamp: \"2023-01-06T12:12:10+00:00\",__typename: \"SmbRawEvent\"}},{node: {timestamp: \"2023-01-06T12:13:00+00:00\",__typename: \"NfsRawEvent\"}}]}}"); +} + +#[tokio::test] +async fn search_empty() { + let schema = TestSchema::new(); + let query = r#" + { + searchHttpRawEvents( + filter: { + time: { start: "2020-01-01T00:01:01Z", end: "2020-01-01T01:01:02Z" } + source: "src 1" + origAddr: { start: "192.168.4.75", end: "192.168.4.79" } + respAddr: { start: "192.168.4.75", end: "192.168.4.79" } + origPort: { start: 46377, end: 46380 } + respPort: { start: 46377, end: 46380 } + timestamps:["2020-01-01T00:00:01Z","2020-01-01T00:01:01Z","2020-01-01T01:01:01Z","2020-01-02T00:00:01Z"] + } + ) + }"#; + let res = schema.execute(query).await; + assert_eq!(res.data.to_string(), "{searchHttpRawEvents: []}"); +} + +#[tokio::test] +async fn search_http_with_data() { + let schema = TestSchema::new(); + let store = schema.db.http_store().unwrap(); + + let timestamp1 = Utc.with_ymd_and_hms(2020, 1, 1, 0, 0, 1).unwrap(); //2020-01-01T00:00:01Z + let timestamp2 = Utc.with_ymd_and_hms(2020, 1, 1, 0, 1, 1).unwrap(); //2020-01-01T00:01:01Z + let timestamp3 = Utc.with_ymd_and_hms(2020, 1, 1, 1, 1, 1).unwrap(); //2020-01-01T01:01:01Z + let timestamp4 = Utc.with_ymd_and_hms(2020, 1, 2, 0, 0, 1).unwrap(); //2020-01-02T00:00:01Z + + insert_http_raw_event(&store, "src 1", timestamp1.timestamp_nanos_opt().unwrap()); + insert_http_raw_event(&store, "src 1", timestamp2.timestamp_nanos_opt().unwrap()); + insert_http_raw_event(&store, "src 1", timestamp3.timestamp_nanos_opt().unwrap()); + insert_http_raw_event(&store, "src 1", timestamp4.timestamp_nanos_opt().unwrap()); + + let query = r#" + { + searchHttpRawEvents( + filter: { + time: { start: "2020-01-01T00:01:01Z", end: "2020-01-01T01:01:02Z" } + source: "src 1" + origAddr: { start: "192.168.4.75", end: "192.168.4.79" } + respAddr: { start: "192.168.4.75", end: "192.168.4.79" } + origPort: { start: 46377, end: 46380 } + respPort: { start: 75, end: 85 } + timestamps:["2020-01-01T00:00:01Z","2020-01-01T00:01:01Z","2020-01-01T01:01:01Z","2020-01-02T00:00:01Z"] + } + ) + }"#; + let res = schema.execute(query).await; + assert_eq!( + res.data.to_string(), + "{searchHttpRawEvents: [\"2020-01-01T00:01:01+00:00\",\"2020-01-01T01:01:01+00:00\"]}" + ); +} + +#[tokio::test] +async fn search_conn_with_data() { + let schema = TestSchema::new(); + let store = schema.db.conn_store().unwrap(); + + let timestamp1 = Utc.with_ymd_and_hms(2020, 1, 1, 0, 0, 1).unwrap(); //2020-01-01T00:00:01Z + let timestamp2 = Utc.with_ymd_and_hms(2020, 1, 1, 0, 1, 1).unwrap(); //2020-01-01T00:01:01Z + let timestamp3 = Utc.with_ymd_and_hms(2020, 1, 1, 1, 1, 1).unwrap(); //2020-01-01T01:01:01Z + let timestamp4 = Utc.with_ymd_and_hms(2020, 1, 2, 0, 0, 1).unwrap(); //2020-01-02T00:00:01Z + + insert_conn_raw_event(&store, "src 1", timestamp1.timestamp_nanos_opt().unwrap()); + insert_conn_raw_event(&store, "src 1", timestamp2.timestamp_nanos_opt().unwrap()); + insert_conn_raw_event(&store, "src 1", timestamp3.timestamp_nanos_opt().unwrap()); + insert_conn_raw_event(&store, "src 1", timestamp4.timestamp_nanos_opt().unwrap()); + + let query = r#" + { + searchConnRawEvents( + filter: { + time: { start: "2020-01-01T00:01:01Z", end: "2020-01-01T01:01:02Z" } + source: "src 1" + origAddr: { start: "192.168.4.75", end: "192.168.4.79" } + respAddr: { start: "192.168.4.75", end: "192.168.4.79" } + origPort: { start: 46377, end: 46380 } + respPort: { start: 75, end: 85 } + timestamps:["2020-01-01T00:00:01Z","2020-01-01T00:01:01Z","2020-01-01T01:01:01Z","2020-01-02T00:00:01Z"] + } + ) + }"#; + let res = schema.execute(query).await; + assert_eq!( + res.data.to_string(), + "{searchConnRawEvents: [\"2020-01-01T00:01:01+00:00\",\"2020-01-01T01:01:01+00:00\"]}" + ); +} + +#[tokio::test] +async fn search_conn_with_data_giganto_cluster() { + let query = r#" + { + searchConnRawEvents( + filter: { + time: { start: "2020-01-01T00:01:01Z", end: "2020-01-01T01:01:02Z" } + source: "src 2" + origAddr: { start: "192.168.4.75", end: "192.168.4.79" } + respAddr: { start: "192.168.4.75", end: "192.168.4.79" } + origPort: { start: 46377, end: 46380 } + respPort: { start: 75, end: 85 } + timestamps:["2020-01-01T00:00:01Z","2020-01-01T00:01:01Z","2020-01-01T01:01:01Z","2020-01-02T00:00:01Z"] + } + ) + }"#; + + let mut peer_server = mockito::Server::new_async().await; + let peer_response_mock_data = r#" + { + "data": { + "searchConnRawEvents": [ + "2020-01-01T00:01:01+00:00", + "2020-01-01T01:01:01+00:00" + ] + } + } + "#; + + let mock = peer_server + .mock("POST", "/graphql") + .with_status(200) + .with_body(peer_response_mock_data) + .create(); + + let peer_port = peer_server + .host_with_port() + .parse::() + .expect("Port must exist") + .port(); + let schema = TestSchema::new_with_graphql_peer(peer_port); + + let res = schema.execute(query).await; + assert_eq!( + res.data.to_string(), + "{searchConnRawEvents: [\"2020-01-01T00:01:01+00:00\",\"2020-01-01T01:01:01+00:00\"]}" + ); + mock.assert_async().await; +} + +#[tokio::test] +async fn search_dns_with_data() { + let schema = TestSchema::new(); + let store = schema.db.dns_store().unwrap(); + + let timestamp1 = Utc.with_ymd_and_hms(2020, 1, 1, 0, 0, 1).unwrap(); //2020-01-01T00:00:01Z + let timestamp2 = Utc.with_ymd_and_hms(2020, 1, 1, 0, 1, 1).unwrap(); //2020-01-01T00:01:01Z + let timestamp3 = Utc.with_ymd_and_hms(2020, 1, 1, 1, 1, 1).unwrap(); //2020-01-01T01:01:01Z + let timestamp4 = Utc.with_ymd_and_hms(2020, 1, 2, 0, 0, 1).unwrap(); //2020-01-02T00:00:01Z + + insert_dns_raw_event(&store, "src 1", timestamp1.timestamp_nanos_opt().unwrap()); + insert_dns_raw_event(&store, "src 1", timestamp2.timestamp_nanos_opt().unwrap()); + insert_dns_raw_event(&store, "src 1", timestamp3.timestamp_nanos_opt().unwrap()); + insert_dns_raw_event(&store, "src 1", timestamp4.timestamp_nanos_opt().unwrap()); + + let query = r#" + { + searchDnsRawEvents( + filter: { + time: { start: "2020-01-01T00:01:01Z", end: "2020-01-01T01:01:02Z" } + source: "src 1" + origAddr: { start: "192.168.4.75", end: "192.168.4.79" } + respAddr: { start: "31.3.245.130", end: "31.3.245.135" } + origPort: { start: 70, end: 46380 } + respPort: { start: 75, end: 85 } + timestamps:["2020-01-01T00:00:01Z","2020-01-01T00:01:01Z","2020-01-01T01:01:01Z","2020-01-02T00:00:01Z"] + } + ) + }"#; + let res = schema.execute(query).await; + assert_eq!( + res.data.to_string(), + "{searchDnsRawEvents: [\"2020-01-01T00:01:01+00:00\",\"2020-01-01T01:01:01+00:00\"]}" + ); +} + +#[tokio::test] +async fn search_dns_with_data_giganto_cluster() { + let query = r#" + { + searchDnsRawEvents( + filter: { + time: { start: "2020-01-01T00:01:01Z", end: "2020-01-01T01:01:02Z" } + source: "src 2" + origAddr: { start: "192.168.4.75", end: "192.168.4.79" } + respAddr: { start: "31.3.245.130", end: "31.3.245.135" } + origPort: { start: 70, end: 46380 } + respPort: { start: 75, end: 85 } + timestamps:["2020-01-01T00:00:01Z","2020-01-01T00:01:01Z","2020-01-01T01:01:01Z","2020-01-02T00:00:01Z"] + } + ) + }"#; + + let mut peer_server = mockito::Server::new_async().await; + let peer_response_mock_data = r#" + { + "data": { + "searchDnsRawEvents": [ + "2020-01-01T00:01:01+00:00", + "2020-01-01T01:01:01+00:00" + ] + } + } + "#; + + let mock = peer_server + .mock("POST", "/graphql") + .with_status(200) + .with_body(peer_response_mock_data) + .create(); + + let peer_port = peer_server + .host_with_port() + .parse::() + .expect("Port must exist") + .port(); + let schema = TestSchema::new_with_graphql_peer(peer_port); + + let res = schema.execute(query).await; + assert_eq!( + res.data.to_string(), + "{searchDnsRawEvents: [\"2020-01-01T00:01:01+00:00\",\"2020-01-01T01:01:01+00:00\"]}" + ); + mock.assert_async().await; +} + +#[tokio::test] +async fn search_rdp_with_data() { + let schema = TestSchema::new(); + let store = schema.db.rdp_store().unwrap(); + + let timestamp1 = Utc.with_ymd_and_hms(2020, 1, 1, 0, 0, 1).unwrap(); //2020-01-01T00:00:01Z + let timestamp2 = Utc.with_ymd_and_hms(2020, 1, 1, 0, 1, 1).unwrap(); //2020-01-01T00:01:01Z + let timestamp3 = Utc.with_ymd_and_hms(2020, 1, 1, 1, 1, 1).unwrap(); //2020-01-01T01:01:01Z + let timestamp4 = Utc.with_ymd_and_hms(2020, 1, 2, 0, 0, 1).unwrap(); //2020-01-02T00:00:01Z + + insert_rdp_raw_event(&store, "src 1", timestamp1.timestamp_nanos_opt().unwrap()); + insert_rdp_raw_event(&store, "src 1", timestamp2.timestamp_nanos_opt().unwrap()); + insert_rdp_raw_event(&store, "src 1", timestamp3.timestamp_nanos_opt().unwrap()); + insert_rdp_raw_event(&store, "src 1", timestamp4.timestamp_nanos_opt().unwrap()); + + let query = r#" + { + searchRdpRawEvents( + filter: { + time: { start: "2020-01-01T00:01:01Z", end: "2020-01-01T01:01:02Z" } + source: "src 1" + origAddr: { start: "192.168.4.75", end: "192.168.4.79" } + respAddr: { start: "192.168.4.75", end: "192.168.4.79" } + origPort: { start: 46377, end: 46380 } + respPort: { start: 75, end: 85 } + timestamps:["2020-01-01T00:00:01Z","2020-01-01T00:01:01Z","2020-01-01T01:01:01Z","2020-01-02T00:00:01Z"] + } + ) + }"#; + let res = schema.execute(query).await; + assert_eq!( + res.data.to_string(), + "{searchRdpRawEvents: [\"2020-01-01T00:01:01+00:00\",\"2020-01-01T01:01:01+00:00\"]}" + ); +} + +#[tokio::test] +async fn search_rdp_with_data_giganto_cluster() { + let query = r#" + { + searchRdpRawEvents( + filter: { + time: { start: "2020-01-01T00:01:01Z", end: "2020-01-01T01:01:02Z" } + source: "src 2" + origAddr: { start: "192.168.4.75", end: "192.168.4.79" } + respAddr: { start: "192.168.4.75", end: "192.168.4.79" } + origPort: { start: 46377, end: 46380 } + respPort: { start: 75, end: 85 } + timestamps:["2020-01-01T00:00:01Z","2020-01-01T00:01:01Z","2020-01-01T01:01:01Z","2020-01-02T00:00:01Z"] + } + ) + }"#; + + let mut peer_server = mockito::Server::new_async().await; + let peer_response_mock_data = r#" + { + "data": { + "searchRdpRawEvents": [ + "2020-01-01T00:01:01+00:00", + "2020-01-01T01:01:01+00:00" + ] + } + } + "#; + + let mock = peer_server + .mock("POST", "/graphql") + .with_status(200) + .with_body(peer_response_mock_data) + .create(); + + let peer_port = peer_server + .host_with_port() + .parse::() + .expect("Port must exist") + .port(); + let schema = TestSchema::new_with_graphql_peer(peer_port); + + let res = schema.execute(query).await; + assert_eq!( + res.data.to_string(), + "{searchRdpRawEvents: [\"2020-01-01T00:01:01+00:00\",\"2020-01-01T01:01:01+00:00\"]}" + ); + mock.assert_async().await; +} + +#[tokio::test] +async fn search_smtp_with_data() { + let schema = TestSchema::new(); + let store = schema.db.smtp_store().unwrap(); + + let timestamp1 = Utc.with_ymd_and_hms(2020, 1, 1, 0, 0, 1).unwrap(); //2020-01-01T00:00:01Z + let timestamp2 = Utc.with_ymd_and_hms(2020, 1, 1, 0, 1, 1).unwrap(); //2020-01-01T00:01:01Z + let timestamp3 = Utc.with_ymd_and_hms(2020, 1, 1, 1, 1, 1).unwrap(); //2020-01-01T01:01:01Z + let timestamp4 = Utc.with_ymd_and_hms(2020, 1, 2, 0, 0, 1).unwrap(); //2020-01-02T00:00:01Z + + insert_smtp_raw_event(&store, "src 1", timestamp1.timestamp_nanos_opt().unwrap()); + insert_smtp_raw_event(&store, "src 1", timestamp2.timestamp_nanos_opt().unwrap()); + insert_smtp_raw_event(&store, "src 1", timestamp3.timestamp_nanos_opt().unwrap()); + insert_smtp_raw_event(&store, "src 1", timestamp4.timestamp_nanos_opt().unwrap()); + + let query = r#" + { + searchSmtpRawEvents( + filter: { + time: { start: "2020-01-01T00:01:01Z", end: "2020-01-01T01:01:02Z" } + source: "src 1" + origAddr: { start: "192.168.4.75", end: "192.168.4.79" } + respAddr: { start: "192.168.4.75", end: "192.168.4.79" } + origPort: { start: 46377, end: 46380 } + respPort: { start: 75, end: 85 } + timestamps:["2020-01-01T00:00:01Z","2020-01-01T00:01:01Z","2020-01-01T01:01:01Z","2020-01-02T00:00:01Z"] + } + ) + }"#; + let res = schema.execute(query).await; + assert_eq!( + res.data.to_string(), + "{searchSmtpRawEvents: [\"2020-01-01T00:01:01+00:00\",\"2020-01-01T01:01:01+00:00\"]}" + ); +} + +#[tokio::test] +async fn search_smtp_with_data_giganto_cluster() { + let query = r#" + { + searchSmtpRawEvents( + filter: { + time: { start: "2020-01-01T00:01:01Z", end: "2020-01-01T01:01:02Z" } + source: "src 2" + origAddr: { start: "192.168.4.75", end: "192.168.4.79" } + respAddr: { start: "192.168.4.75", end: "192.168.4.79" } + origPort: { start: 46377, end: 46380 } + respPort: { start: 75, end: 85 } + timestamps:["2020-01-01T00:00:01Z","2020-01-01T00:01:01Z","2020-01-01T01:01:01Z","2020-01-02T00:00:01Z"] + } + ) + }"#; + + let mut peer_server = mockito::Server::new_async().await; + let peer_response_mock_data = r#" + { + "data": { + "searchSmtpRawEvents": [ + "2020-01-01T00:01:01+00:00", + "2020-01-01T01:01:01+00:00" + ] + } + } + "#; + + let mock = peer_server + .mock("POST", "/graphql") + .with_status(200) + .with_body(peer_response_mock_data) + .create(); + + let peer_port = peer_server + .host_with_port() + .parse::() + .expect("Port must exist") + .port(); + let schema = TestSchema::new_with_graphql_peer(peer_port); + + let res = schema.execute(query).await; + assert_eq!( + res.data.to_string(), + "{searchSmtpRawEvents: [\"2020-01-01T00:01:01+00:00\",\"2020-01-01T01:01:01+00:00\"]}" + ); + mock.assert_async().await; +} + +#[tokio::test] +async fn search_ntlm_with_data() { + let schema = TestSchema::new(); + let store = schema.db.ntlm_store().unwrap(); + + let timestamp1 = Utc.with_ymd_and_hms(2020, 1, 1, 0, 0, 1).unwrap(); //2020-01-01T00:00:01Z + let timestamp2 = Utc.with_ymd_and_hms(2020, 1, 1, 0, 1, 1).unwrap(); //2020-01-01T00:01:01Z + let timestamp3 = Utc.with_ymd_and_hms(2020, 1, 1, 1, 1, 1).unwrap(); //2020-01-01T01:01:01Z + let timestamp4 = Utc.with_ymd_and_hms(2020, 1, 2, 0, 0, 1).unwrap(); //2020-01-02T00:00:01Z + + insert_ntlm_raw_event(&store, "src 1", timestamp1.timestamp_nanos_opt().unwrap()); + insert_ntlm_raw_event(&store, "src 1", timestamp2.timestamp_nanos_opt().unwrap()); + insert_ntlm_raw_event(&store, "src 1", timestamp3.timestamp_nanos_opt().unwrap()); + insert_ntlm_raw_event(&store, "src 1", timestamp4.timestamp_nanos_opt().unwrap()); + + let query = r#" + { + searchNtlmRawEvents( + filter: { + time: { start: "2020-01-01T00:01:01Z", end: "2020-01-01T01:01:02Z" } + source: "src 1" + origAddr: { start: "192.168.4.75", end: "192.168.4.79" } + respAddr: { start: "192.168.4.75", end: "192.168.4.79" } + origPort: { start: 46377, end: 46380 } + respPort: { start: 75, end: 85 } + timestamps:["2020-01-01T00:00:01Z","2020-01-01T00:01:01Z","2020-01-01T01:01:01Z","2020-01-02T00:00:01Z"] + } + ) + }"#; + let res = schema.execute(query).await; + assert_eq!( + res.data.to_string(), + "{searchNtlmRawEvents: [\"2020-01-01T00:01:01+00:00\",\"2020-01-01T01:01:01+00:00\"]}" + ); +} + +#[tokio::test] +async fn search_ntlm_with_data_giganto_cluster() { + let query = r#" + { + searchNtlmRawEvents( + filter: { + time: { start: "2020-01-01T00:01:01Z", end: "2020-01-01T01:01:02Z" } + source: "src 2" + origAddr: { start: "192.168.4.75", end: "192.168.4.79" } + respAddr: { start: "192.168.4.75", end: "192.168.4.79" } + origPort: { start: 46377, end: 46380 } + respPort: { start: 75, end: 85 } + timestamps:["2020-01-01T00:00:01Z","2020-01-01T00:01:01Z","2020-01-01T01:01:01Z","2020-01-02T00:00:01Z"] + } + ) + }"#; + + let mut peer_server = mockito::Server::new_async().await; + let peer_response_mock_data = r#" + { + "data": { + "searchNtlmRawEvents": [ + "2020-01-01T00:01:01+00:00", + "2020-01-01T01:01:01+00:00" + ] + } + } + "#; + + let mock = peer_server + .mock("POST", "/graphql") + .with_status(200) + .with_body(peer_response_mock_data) + .create(); + + let peer_port = peer_server + .host_with_port() + .parse::() + .expect("Port must exist") + .port(); + let schema = TestSchema::new_with_graphql_peer(peer_port); + + let res = schema.execute(query).await; + assert_eq!( + res.data.to_string(), + "{searchNtlmRawEvents: [\"2020-01-01T00:01:01+00:00\",\"2020-01-01T01:01:01+00:00\"]}" + ); + mock.assert_async().await; +} + +#[tokio::test] +async fn search_kerberos_with_data() { + let schema = TestSchema::new(); + let store = schema.db.kerberos_store().unwrap(); + + let timestamp1 = Utc.with_ymd_and_hms(2020, 1, 1, 0, 0, 1).unwrap(); //2020-01-01T00:00:01Z + let timestamp2 = Utc.with_ymd_and_hms(2020, 1, 1, 0, 1, 1).unwrap(); //2020-01-01T00:01:01Z + let timestamp3 = Utc.with_ymd_and_hms(2020, 1, 1, 1, 1, 1).unwrap(); //2020-01-01T01:01:01Z + let timestamp4 = Utc.with_ymd_and_hms(2020, 1, 2, 0, 0, 1).unwrap(); //2020-01-02T00:00:01Z + + insert_kerberos_raw_event(&store, "src 1", timestamp1.timestamp_nanos_opt().unwrap()); + insert_kerberos_raw_event(&store, "src 1", timestamp2.timestamp_nanos_opt().unwrap()); + insert_kerberos_raw_event(&store, "src 1", timestamp3.timestamp_nanos_opt().unwrap()); + insert_kerberos_raw_event(&store, "src 1", timestamp4.timestamp_nanos_opt().unwrap()); + + let query = r#" + { + searchKerberosRawEvents( + filter: { + time: { start: "2020-01-01T00:01:01Z", end: "2020-01-01T01:01:02Z" } + source: "src 1" + origAddr: { start: "192.168.4.75", end: "192.168.4.79" } + respAddr: { start: "192.168.4.75", end: "192.168.4.79" } + origPort: { start: 46377, end: 46380 } + respPort: { start: 75, end: 85 } + timestamps:["2020-01-01T00:00:01Z","2020-01-01T00:01:01Z","2020-01-01T01:01:01Z","2020-01-02T00:00:01Z"] + } + ) + }"#; + let res = schema.execute(query).await; + assert_eq!( + res.data.to_string(), + "{searchKerberosRawEvents: [\"2020-01-01T00:01:01+00:00\",\"2020-01-01T01:01:01+00:00\"]}" + ); +} + +#[tokio::test] +async fn search_kerberos_with_data_giganto_cluster() { + let query = r#" + { + searchKerberosRawEvents( + filter: { + time: { start: "2020-01-01T00:01:01Z", end: "2020-01-01T01:01:02Z" } + source: "src 2" + origAddr: { start: "192.168.4.75", end: "192.168.4.79" } + respAddr: { start: "192.168.4.75", end: "192.168.4.79" } + origPort: { start: 46377, end: 46380 } + respPort: { start: 75, end: 85 } + timestamps:["2020-01-01T00:00:01Z","2020-01-01T00:01:01Z","2020-01-01T01:01:01Z","2020-01-02T00:00:01Z"] + } + ) + }"#; + let mut peer_server = mockito::Server::new_async().await; + let peer_response_mock_data = r#" + { + "data": { + "searchKerberosRawEvents": [ + "2020-01-01T00:01:01+00:00", + "2020-01-01T01:01:01+00:00" + ] + } + } + "#; + + let mock = peer_server + .mock("POST", "/graphql") + .with_status(200) + .with_body(peer_response_mock_data) + .create(); + + let peer_port = peer_server + .host_with_port() + .parse::() + .expect("Port must exist") + .port(); + let schema = TestSchema::new_with_graphql_peer(peer_port); + + let res = schema.execute(query).await; + assert_eq!( + res.data.to_string(), + "{searchKerberosRawEvents: [\"2020-01-01T00:01:01+00:00\",\"2020-01-01T01:01:01+00:00\"]}" + ); + mock.assert_async().await; +} + +#[tokio::test] +async fn search_ssh_with_data() { + let schema = TestSchema::new(); + let store = schema.db.ssh_store().unwrap(); + + let timestamp1 = Utc.with_ymd_and_hms(2020, 1, 1, 0, 0, 1).unwrap(); //2020-01-01T00:00:01Z + let timestamp2 = Utc.with_ymd_and_hms(2020, 1, 1, 0, 1, 1).unwrap(); //2020-01-01T00:01:01Z + let timestamp3 = Utc.with_ymd_and_hms(2020, 1, 1, 1, 1, 1).unwrap(); //2020-01-01T01:01:01Z + let timestamp4 = Utc.with_ymd_and_hms(2020, 1, 2, 0, 0, 1).unwrap(); //2020-01-02T00:00:01Z + + insert_ssh_raw_event(&store, "src 1", timestamp1.timestamp_nanos_opt().unwrap()); + insert_ssh_raw_event(&store, "src 1", timestamp2.timestamp_nanos_opt().unwrap()); + insert_ssh_raw_event(&store, "src 1", timestamp3.timestamp_nanos_opt().unwrap()); + insert_ssh_raw_event(&store, "src 1", timestamp4.timestamp_nanos_opt().unwrap()); + + let query = r#" + { + searchSshRawEvents( + filter: { + time: { start: "2020-01-01T00:01:01Z", end: "2020-01-01T01:01:02Z" } + source: "src 1" + origAddr: { start: "192.168.4.75", end: "192.168.4.79" } + respAddr: { start: "192.168.4.75", end: "192.168.4.79" } + origPort: { start: 46377, end: 46380 } + respPort: { start: 75, end: 85 } + timestamps:["2020-01-01T00:00:01Z","2020-01-01T00:01:01Z","2020-01-01T01:01:01Z","2020-01-02T00:00:01Z"] + } + ) + }"#; + let res = schema.execute(query).await; + assert_eq!( + res.data.to_string(), + "{searchSshRawEvents: [\"2020-01-01T00:01:01+00:00\",\"2020-01-01T01:01:01+00:00\"]}" + ); +} + +#[tokio::test] +async fn search_dce_rpc_with_data() { + let schema = TestSchema::new(); + let store = schema.db.dce_rpc_store().unwrap(); + + let timestamp1 = Utc.with_ymd_and_hms(2020, 1, 1, 0, 0, 1).unwrap(); //2020-01-01T00:00:01Z + let timestamp2 = Utc.with_ymd_and_hms(2020, 1, 1, 0, 1, 1).unwrap(); //2020-01-01T00:01:01Z + let timestamp3 = Utc.with_ymd_and_hms(2020, 1, 1, 1, 1, 1).unwrap(); //2020-01-01T01:01:01Z + let timestamp4 = Utc.with_ymd_and_hms(2020, 1, 2, 0, 0, 1).unwrap(); //2020-01-02T00:00:01Z + + insert_dce_rpc_raw_event(&store, "src 1", timestamp1.timestamp_nanos_opt().unwrap()); + insert_dce_rpc_raw_event(&store, "src 1", timestamp2.timestamp_nanos_opt().unwrap()); + insert_dce_rpc_raw_event(&store, "src 1", timestamp3.timestamp_nanos_opt().unwrap()); + insert_dce_rpc_raw_event(&store, "src 1", timestamp4.timestamp_nanos_opt().unwrap()); + + let query = r#" + { + searchDceRpcRawEvents( + filter: { + time: { start: "2020-01-01T00:01:01Z", end: "2020-01-01T01:01:02Z" } + source: "src 1" + origAddr: { start: "192.168.4.75", end: "192.168.4.79" } + respAddr: { start: "192.168.4.75", end: "192.168.4.79" } + origPort: { start: 46377, end: 46380 } + respPort: { start: 75, end: 85 } + timestamps:["2020-01-01T00:00:01Z","2020-01-01T00:01:01Z","2020-01-01T01:01:01Z","2020-01-02T00:00:01Z"] + } + ) + }"#; + let res = schema.execute(query).await; + assert_eq!( + res.data.to_string(), + "{searchDceRpcRawEvents: [\"2020-01-01T00:01:01+00:00\",\"2020-01-01T01:01:01+00:00\"]}" + ); +} + +#[tokio::test] +async fn search_ftp_with_data() { + let schema = TestSchema::new(); + let store = schema.db.ftp_store().unwrap(); + + let timestamp1 = Utc.with_ymd_and_hms(2020, 1, 1, 0, 0, 1).unwrap(); //2020-01-01T00:00:01Z + let timestamp2 = Utc.with_ymd_and_hms(2020, 1, 1, 0, 1, 1).unwrap(); //2020-01-01T00:01:01Z + let timestamp3 = Utc.with_ymd_and_hms(2020, 1, 1, 1, 1, 1).unwrap(); //2020-01-01T01:01:01Z + let timestamp4 = Utc.with_ymd_and_hms(2020, 1, 2, 0, 0, 1).unwrap(); //2020-01-02T00:00:01Z + + insert_ftp_raw_event(&store, "src 1", timestamp1.timestamp_nanos_opt().unwrap()); + insert_ftp_raw_event(&store, "src 1", timestamp2.timestamp_nanos_opt().unwrap()); + insert_ftp_raw_event(&store, "src 1", timestamp3.timestamp_nanos_opt().unwrap()); + insert_ftp_raw_event(&store, "src 1", timestamp4.timestamp_nanos_opt().unwrap()); + + let query = r#" + { + searchFtpRawEvents( + filter: { + time: { start: "2020-01-01T00:01:01Z", end: "2020-01-01T01:01:02Z" } + source: "src 1" + origAddr: { start: "192.168.4.75", end: "192.168.4.79" } + respAddr: { start: "31.3.245.130", end: "31.3.245.135" } + origPort: { start: 46377, end: 46380 } + respPort: { start: 75, end: 85 } + timestamps:["2020-01-01T00:00:01Z","2020-01-01T00:01:01Z","2020-01-01T01:01:01Z","2020-01-02T00:00:01Z"] + } + ) + }"#; + let res = schema.execute(query).await; + assert_eq!( + res.data.to_string(), + "{searchFtpRawEvents: [\"2020-01-01T00:01:01+00:00\",\"2020-01-01T01:01:01+00:00\"]}" + ); +} + +#[tokio::test] +async fn search_mqtt_with_data() { + let schema = TestSchema::new(); + let store = schema.db.mqtt_store().unwrap(); + + let timestamp1 = Utc.with_ymd_and_hms(2020, 1, 1, 0, 0, 1).unwrap(); //2020-01-01T00:00:01Z + let timestamp2 = Utc.with_ymd_and_hms(2020, 1, 1, 0, 1, 1).unwrap(); //2020-01-01T00:01:01Z + let timestamp3 = Utc.with_ymd_and_hms(2020, 1, 1, 1, 1, 1).unwrap(); //2020-01-01T01:01:01Z + let timestamp4 = Utc.with_ymd_and_hms(2020, 1, 2, 0, 0, 1).unwrap(); //2020-01-02T00:00:01Z + + insert_mqtt_raw_event(&store, "src 1", timestamp1.timestamp_nanos_opt().unwrap()); + insert_mqtt_raw_event(&store, "src 1", timestamp2.timestamp_nanos_opt().unwrap()); + insert_mqtt_raw_event(&store, "src 1", timestamp3.timestamp_nanos_opt().unwrap()); + insert_mqtt_raw_event(&store, "src 1", timestamp4.timestamp_nanos_opt().unwrap()); + + let query = r#" + { + searchMqttRawEvents( + filter: { + time: { start: "2020-01-01T00:01:01Z", end: "2020-01-01T01:01:02Z" } + source: "src 1" + origAddr: { start: "192.168.4.75", end: "192.168.4.79" } + respAddr: { start: "31.3.245.130", end: "31.3.245.135" } + origPort: { start: 46377, end: 46380 } + respPort: { start: 75, end: 85 } + timestamps:["2020-01-01T00:00:01Z","2020-01-01T00:01:01Z","2020-01-01T01:01:01Z","2020-01-02T00:00:01Z"] + } + ) + }"#; + let res = schema.execute(query).await; + assert_eq!( + res.data.to_string(), + "{searchMqttRawEvents: [\"2020-01-01T00:01:01+00:00\",\"2020-01-01T01:01:01+00:00\"]}" + ); +} + +#[tokio::test] +async fn search_ldap_with_data() { + let schema = TestSchema::new(); + let store = schema.db.ldap_store().unwrap(); + + let timestamp1 = Utc.with_ymd_and_hms(2020, 1, 1, 0, 0, 1).unwrap(); //2020-01-01T00:00:01Z + let timestamp2 = Utc.with_ymd_and_hms(2020, 1, 1, 0, 1, 1).unwrap(); //2020-01-01T00:01:01Z + let timestamp3 = Utc.with_ymd_and_hms(2020, 1, 1, 1, 1, 1).unwrap(); //2020-01-01T01:01:01Z + let timestamp4 = Utc.with_ymd_and_hms(2020, 1, 2, 0, 0, 1).unwrap(); //2020-01-02T00:00:01Z + + insert_ldap_raw_event(&store, "src 1", timestamp1.timestamp_nanos_opt().unwrap()); + insert_ldap_raw_event(&store, "src 1", timestamp2.timestamp_nanos_opt().unwrap()); + insert_ldap_raw_event(&store, "src 1", timestamp3.timestamp_nanos_opt().unwrap()); + insert_ldap_raw_event(&store, "src 1", timestamp4.timestamp_nanos_opt().unwrap()); + + let query = r#" + { + searchLdapRawEvents( + filter: { + time: { start: "2020-01-01T00:01:01Z", end: "2020-01-01T01:01:02Z" } + source: "src 1" + origAddr: { start: "192.168.4.75", end: "192.168.4.79" } + respAddr: { start: "31.3.245.130", end: "31.3.245.135" } + origPort: { start: 46377, end: 46380 } + respPort: { start: 75, end: 85 } + timestamps:["2020-01-01T00:00:01Z","2020-01-01T00:01:01Z","2020-01-01T01:01:01Z","2020-01-02T00:00:01Z"] + } + ) + }"#; + let res = schema.execute(query).await; + assert_eq!( + res.data.to_string(), + "{searchLdapRawEvents: [\"2020-01-01T00:01:01+00:00\",\"2020-01-01T01:01:01+00:00\"]}" + ); +} + +#[tokio::test] +async fn search_tls_with_data() { + let schema = TestSchema::new(); + let store = schema.db.tls_store().unwrap(); + + let timestamp1 = Utc.with_ymd_and_hms(2020, 1, 1, 0, 0, 1).unwrap(); //2020-01-01T00:00:01Z + let timestamp2 = Utc.with_ymd_and_hms(2020, 1, 1, 0, 1, 1).unwrap(); //2020-01-01T00:01:01Z + let timestamp3 = Utc.with_ymd_and_hms(2020, 1, 1, 1, 1, 1).unwrap(); //2020-01-01T01:01:01Z + let timestamp4 = Utc.with_ymd_and_hms(2020, 1, 2, 0, 0, 1).unwrap(); //2020-01-02T00:00:01Z + + insert_tls_raw_event(&store, "src 1", timestamp1.timestamp_nanos_opt().unwrap()); + insert_tls_raw_event(&store, "src 1", timestamp2.timestamp_nanos_opt().unwrap()); + insert_tls_raw_event(&store, "src 1", timestamp3.timestamp_nanos_opt().unwrap()); + insert_tls_raw_event(&store, "src 1", timestamp4.timestamp_nanos_opt().unwrap()); + + let query = r#" + { + searchTlsRawEvents( + filter: { + time: { start: "2020-01-01T00:01:01Z", end: "2020-01-01T01:01:02Z" } + source: "src 1" + origAddr: { start: "192.168.4.75", end: "192.168.4.79" } + respAddr: { start: "31.3.245.130", end: "31.3.245.135" } + origPort: { start: 46377, end: 46380 } + respPort: { start: 75, end: 85 } + timestamps:["2020-01-01T00:00:01Z","2020-01-01T00:01:01Z","2020-01-01T01:01:01Z","2020-01-02T00:00:01Z"] + } + ) + }"#; + let res = schema.execute(query).await; + assert_eq!( + res.data.to_string(), + "{searchTlsRawEvents: [\"2020-01-01T00:01:01+00:00\",\"2020-01-01T01:01:01+00:00\"]}" + ); +} + +#[tokio::test] +async fn search_smb_with_data() { + let schema = TestSchema::new(); + let store = schema.db.smb_store().unwrap(); + + let timestamp1 = Utc.with_ymd_and_hms(2020, 1, 1, 0, 0, 1).unwrap(); //2020-01-01T00:00:01Z + let timestamp2 = Utc.with_ymd_and_hms(2020, 1, 1, 0, 1, 1).unwrap(); //2020-01-01T00:01:01Z + let timestamp3 = Utc.with_ymd_and_hms(2020, 1, 1, 1, 1, 1).unwrap(); //2020-01-01T01:01:01Z + let timestamp4 = Utc.with_ymd_and_hms(2020, 1, 2, 0, 0, 1).unwrap(); //2020-01-02T00:00:01Z + + insert_smb_raw_event(&store, "src 1", timestamp1.timestamp_nanos_opt().unwrap()); + insert_smb_raw_event(&store, "src 1", timestamp2.timestamp_nanos_opt().unwrap()); + insert_smb_raw_event(&store, "src 1", timestamp3.timestamp_nanos_opt().unwrap()); + insert_smb_raw_event(&store, "src 1", timestamp4.timestamp_nanos_opt().unwrap()); + + let query = r#" + { + searchSmbRawEvents( + filter: { + time: { start: "2020-01-01T00:01:01Z", end: "2020-01-01T01:01:02Z" } + source: "src 1" + origAddr: { start: "192.168.4.75", end: "192.168.4.79" } + respAddr: { start: "31.3.245.130", end: "31.3.245.135" } + origPort: { start: 46377, end: 46380 } + respPort: { start: 75, end: 85 } + timestamps:["2020-01-01T00:00:01Z","2020-01-01T00:01:01Z","2020-01-01T01:01:01Z","2020-01-02T00:00:01Z"] + } + ) + }"#; + let res = schema.execute(query).await; + assert_eq!( + res.data.to_string(), + "{searchSmbRawEvents: [\"2020-01-01T00:01:01+00:00\",\"2020-01-01T01:01:01+00:00\"]}" + ); +} + +#[tokio::test] +async fn search_nfs_with_data() { + let schema = TestSchema::new(); + let store = schema.db.nfs_store().unwrap(); + + let timestamp1 = Utc.with_ymd_and_hms(2020, 1, 1, 0, 0, 1).unwrap(); //2020-01-01T00:00:01Z + let timestamp2 = Utc.with_ymd_and_hms(2020, 1, 1, 0, 1, 1).unwrap(); //2020-01-01T00:01:01Z + let timestamp3 = Utc.with_ymd_and_hms(2020, 1, 1, 1, 1, 1).unwrap(); //2020-01-01T01:01:01Z + let timestamp4 = Utc.with_ymd_and_hms(2020, 1, 2, 0, 0, 1).unwrap(); //2020-01-02T00:00:01Z + + insert_nfs_raw_event(&store, "src 1", timestamp1.timestamp_nanos_opt().unwrap()); + insert_nfs_raw_event(&store, "src 1", timestamp2.timestamp_nanos_opt().unwrap()); + insert_nfs_raw_event(&store, "src 1", timestamp3.timestamp_nanos_opt().unwrap()); + insert_nfs_raw_event(&store, "src 1", timestamp4.timestamp_nanos_opt().unwrap()); + + let query = r#" + { + searchNfsRawEvents( + filter: { + time: { start: "2020-01-01T00:01:01Z", end: "2020-01-01T01:01:02Z" } + source: "src 1" + origAddr: { start: "192.168.4.75", end: "192.168.4.79" } + respAddr: { start: "31.3.245.130", end: "31.3.245.135" } + origPort: { start: 46377, end: 46380 } + respPort: { start: 75, end: 85 } + timestamps:["2020-01-01T00:00:01Z","2020-01-01T00:01:01Z","2020-01-01T01:01:01Z","2020-01-02T00:00:01Z"] + } + ) + }"#; + let res = schema.execute(query).await; + assert_eq!( + res.data.to_string(), + "{searchNfsRawEvents: [\"2020-01-01T00:01:01+00:00\",\"2020-01-01T01:01:01+00:00\"]}" + ); +} diff --git a/src/graphql/packet.rs b/src/graphql/packet.rs index 1107073..f8c524f 100644 --- a/src/graphql/packet.rs +++ b/src/graphql/packet.rs @@ -68,6 +68,7 @@ impl RawEventFilter for PacketFilter { } } +#[allow(clippy::struct_field_names)] #[derive(SimpleObject, ConvertGraphQLEdgesNode)] #[graphql_client_type(names = [packets::PacketsPacketsEdgesNode, ])] struct Packet { diff --git a/src/peer.rs b/src/peer.rs index 0c01e08..a1a9274 100644 --- a/src/peer.rs +++ b/src/peer.rs @@ -1,5 +1,3 @@ -#![allow(clippy::module_name_repetitions)] - use crate::{ graphql::status::{ insert_toml_peers, parse_toml_element_to_string, read_toml_file, write_toml_file, @@ -45,6 +43,7 @@ const PEER_RETRY_INTERVAL: u64 = 5; pub type Peers = Arc>>; +#[allow(clippy::module_name_repetitions)] #[derive(Deserialize, Serialize, Debug, Default)] pub struct PeerInfo { pub ingest_sources: HashSet, @@ -52,6 +51,7 @@ pub struct PeerInfo { pub publish_port: Option, } +#[allow(clippy::module_name_repetitions)] #[derive( Clone, Copy, Debug, Deserialize, Eq, IntoPrimitive, PartialEq, Serialize, TryFromPrimitive, )] @@ -62,6 +62,7 @@ pub enum PeerCode { UpdateSourceList = 1, } +#[allow(clippy::module_name_repetitions)] #[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] pub struct PeerIdentity { pub address: SocketAddr, @@ -77,7 +78,7 @@ impl TomlPeers for PeerIdentity { } } -#[allow(clippy::module_name_repetitions)] +#[allow(clippy::module_name_repetitions, clippy::struct_field_names)] #[derive(Clone, Debug)] pub struct PeerConns { // Key string is cert's CN hostname; Value is Connection; e.g. ( ("node2", Connection { .. }), }