diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a4a32ef..4a72acfb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Optionally wrap TCP stream in a TLS session in TCP driver (#203) - Support for SPNEGO authentication (#307) +## Changed + +- Rework subscription filters (#186) (**Warning: this require a databatase migration**) +- In formats `Json`, `Nxlog` and `RawJson`, `OpenWEC.Principal` is replaced by `OpenWEC.Client` (#186) +- In `Files` driver, `{principal}` is replaced by `{client}` in `path` config (#186) +- In access log pattern, `{X(principal)}` is replaced by `{X(client)}` (#186) + +## Removed + +- Subscription filters can no longer be created nor edited using the cli (#186) + ## [v0.3.0] ### Added diff --git a/Cargo.lock b/Cargo.lock index a34f2e43..4670e321 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 4 [[package]] name = "addr2line" -version = "0.24.2" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" dependencies = [ "gimli", ] @@ -44,12 +44,6 @@ version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - [[package]] name = "android_system_properties" version = "0.1.5" @@ -61,9 +55,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.19" +version = "0.6.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933" +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" dependencies = [ "anstyle", "anstyle-parse", @@ -76,9 +70,9 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.11" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" [[package]] name = "anstyle-parse" @@ -91,29 +85,29 @@ dependencies = [ [[package]] name = "anstyle-query" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9" +checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] name = "anstyle-wincon" -version = "3.0.9" +version = "3.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882" +checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] name = "anyhow" -version = "1.0.98" +version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" [[package]] name = "arc-swap" @@ -133,7 +127,7 @@ dependencies = [ "nom", "num-traits", "rusticata-macros", - "thiserror 2.0.12", + "thiserror 2.0.17", "time", ] @@ -145,7 +139,7 @@ checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", "synstructure", ] @@ -157,18 +151,18 @@ checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", ] [[package]] name = "async-trait" -version = "0.1.88" +version = "0.1.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", ] [[package]] @@ -185,9 +179,9 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "aws-lc-rs" -version = "1.13.1" +version = "1.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fcc8f365936c834db5514fc45aee5b1202d677e6b40e48468aaaa8183ca8c7" +checksum = "879b6c89592deb404ba4dc0ae6b58ffd1795c78991cbb5b8bc441c48a070440d" dependencies = [ "aws-lc-sys", "zeroize", @@ -195,22 +189,23 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.29.0" +version = "0.32.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61b1d86e7705efe1be1b569bab41d4fa1e14e220b60a160f78de2db687add079" +checksum = "a2b715a6010afb9e457ca2b7c9d2b9c344baa8baed7b38dc476034c171b32575" dependencies = [ - "bindgen 0.69.5", + "bindgen 0.72.1", "cc", "cmake", "dunce", "fs_extra", + "libloading", ] [[package]] name = "backtrace" -version = "0.3.75" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" +checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" dependencies = [ "addr2line", "cfg-if", @@ -218,7 +213,7 @@ dependencies = [ "miniz_oxide", "object", "rustc-demangle", - "windows-targets 0.52.6", + "windows-link 0.2.1", ] [[package]] @@ -229,34 +224,31 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "bindgen" -version = "0.69.5" +version = "0.71.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" +checksum = "5f58bf3d7db68cfbac37cfc485a8d711e87e064c3d0fe0435b92f7a407f9d6b3" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.4", "cexpr", "clang-sys", - "itertools 0.12.1", - "lazy_static", - "lazycell", + "itertools 0.13.0", "log", "prettyplease", "proc-macro2", "quote", "regex", - "rustc-hash 1.1.0", + "rustc-hash", "shlex", - "syn 2.0.104", - "which", + "syn", ] [[package]] name = "bindgen" -version = "0.71.1" +version = "0.72.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f58bf3d7db68cfbac37cfc485a8d711e87e064c3d0fe0435b92f7a407f9d6b3" +checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.4", "cexpr", "clang-sys", "itertools 0.13.0", @@ -265,9 +257,9 @@ dependencies = [ "proc-macro2", "quote", "regex", - "rustc-hash 2.1.1", + "rustc-hash", "shlex", - "syn 2.0.104", + "syn", ] [[package]] @@ -278,9 +270,12 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.9.1" +version = "2.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" +checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" +dependencies = [ + "serde", +] [[package]] name = "bitreader" @@ -326,10 +321,11 @@ checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" [[package]] name = "cc" -version = "1.2.27" +version = "1.2.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc" +checksum = "ac9fe6cdbb24b6ade63616c0a0688e45bb56732262c158df3c0c4bea4ca47cb7" dependencies = [ + "find-msvc-tools", "jobserver", "libc", "shlex", @@ -346,20 +342,19 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.1" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" +checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" [[package]] name = "chrono" -version = "0.4.41" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" +checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" dependencies = [ - "android-tzdata", "iana-time-zone", "num-traits", - "windows-link", + "windows-link 0.2.1", ] [[package]] @@ -375,18 +370,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.40" +version = "4.5.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f" +checksum = "e2134bb3ea021b78629caa971416385309e0131b351b25e01dc16fb54e1b5fae" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.5.40" +version = "4.5.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e" +checksum = "c2ba64afa3c0a6df7fa517765e31314e983f51dda798ffba27b988194fb65dc9" dependencies = [ "anstream", "anstyle", @@ -453,10 +448,12 @@ version = "0.3.0" dependencies = [ "anyhow", "async-trait", + "bitflags 2.9.4", "chrono", "deadpool-postgres", "deadpool-sqlite", "encoding_rs", + "glob", "log", "openssl", "postgres-openssl", @@ -472,6 +469,16 @@ dependencies = [ "uuid", ] +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation" version = "0.10.1" @@ -543,11 +550,12 @@ dependencies = [ [[package]] name = "deadpool" -version = "0.12.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ed5957ff93768adf7a65ab167a17835c3d2c3c50d084fe305174c112f468e2f" +checksum = "0be2b1d1d6ec8d846f05e137292d0b89133caf95ef33695424c09568bdd39b1b" dependencies = [ "deadpool-runtime", + "lazy_static", "num_cpus", "tokio", ] @@ -559,7 +567,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d697d376cbfa018c23eb4caab1fd1883dd9c906a8c034e8d9a3cb06a7e0bef9" dependencies = [ "async-trait", - "deadpool 0.12.2", + "deadpool 0.12.3", "getrandom 0.2.16", "tokio", "tokio-postgres", @@ -611,22 +619,32 @@ dependencies = [ [[package]] name = "deranged" -version = "0.4.0" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" +checksum = "a41953f86f8a05768a6cda24def994fd2f424b04ec5c719cf89989779f199071" dependencies = [ "powerfmt", ] [[package]] -name = "derivative" -version = "2.2.0" +name = "derive_more" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn", + "unicode-xid", ] [[package]] @@ -654,7 +672,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", ] [[package]] @@ -721,12 +739,12 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -747,6 +765,12 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +[[package]] +name = "find-msvc-tools" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127" + [[package]] name = "fnv" version = "1.0.7" @@ -776,9 +800,9 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "form_urlencoded" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" dependencies = [ "percent-encoding", ] @@ -845,7 +869,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", ] [[package]] @@ -910,26 +934,26 @@ dependencies = [ "cfg-if", "libc", "r-efi", - "wasi 0.14.2+wasi-0.2.4", + "wasi 0.14.7+wasi-0.2.4", ] [[package]] name = "gimli" -version = "0.31.1" +version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" [[package]] name = "glob" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" [[package]] name = "h2" -version = "0.4.10" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9421a676d1b147b16b82c9225157dc629087ef8ec4d5e2960f9437a90dac0a5" +checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386" dependencies = [ "atomic-waker", "bytes", @@ -956,13 +980,19 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.4" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ "foldhash", ] +[[package]] +name = "hashbrown" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" + [[package]] name = "hashlink" version = "0.8.4" @@ -999,15 +1029,6 @@ dependencies = [ "digest", ] -[[package]] -name = "home" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" -dependencies = [ - "windows-sys 0.59.0", -] - [[package]] name = "http" version = "1.3.1" @@ -1056,19 +1077,20 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "humantime" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b112acc8b3adf4b107a8ec20977da0273a8c386765a3ec0229bd500a1443f9f" +checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424" [[package]] name = "hyper" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" +checksum = "eb3aa54a13a0dfe7fbe3a59e0c76093041720fdc77b110cc0fc260fafb4dc51e" dependencies = [ + "atomic-waker", "bytes", "futures-channel", - "futures-util", + "futures-core", "h2", "http", "http-body", @@ -1076,6 +1098,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", + "pin-utils", "smallvec", "tokio", "want", @@ -1100,10 +1123,11 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.14" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc2fdfdbff08affe55bb779f33b053aa1fe5dd5b54c257343c17edfa55711bdb" +checksum = "3c6995591a8f1380fcb4ba966a252a4b29188d51d2b89e3a252f5305be65aea8" dependencies = [ + "base64", "bytes", "futures-channel", "futures-core", @@ -1111,19 +1135,23 @@ dependencies = [ "http", "http-body", "hyper", + "ipnet", "libc", + "percent-encoding", "pin-project-lite", - "socket2", + "socket2 0.6.0", + "system-configuration", "tokio", "tower-service", "tracing", + "windows-registry", ] [[package]] name = "iana-time-zone" -version = "0.1.63" +version = "0.1.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" +checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -1231,9 +1259,9 @@ dependencies = [ [[package]] name = "idna" -version = "1.0.3" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" dependencies = [ "idna_adapter", "smallvec", @@ -1252,12 +1280,23 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.9.0" +version = "2.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" +checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" dependencies = [ "equivalent", - "hashbrown 0.15.4", + "hashbrown 0.16.0", +] + +[[package]] +name = "io-uring" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" +dependencies = [ + "bitflags 2.9.4", + "cfg-if", + "libc", ] [[package]] @@ -1272,15 +1311,6 @@ version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" -[[package]] -name = "itertools" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" -dependencies = [ - "either", -] - [[package]] name = "itertools" version = "0.13.0" @@ -1326,14 +1356,14 @@ checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", ] [[package]] name = "jobserver" -version = "0.1.33" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" dependencies = [ "getrandom 0.3.3", "libc", @@ -1341,9 +1371,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.77" +version = "0.3.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +checksum = "ec48937a97411dcb524a265206ccd4c90bb711fca92b2792c407f268825b9305" dependencies = [ "once_cell", "wasm-bindgen", @@ -1355,12 +1385,6 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" -[[package]] -name = "lazycell" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" - [[package]] name = "leon" version = "3.0.2" @@ -1368,14 +1392,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42a865ffec5587961f5afc6d365bccb304f4feaa1928f4fe94c91c9d210d7310" dependencies = [ "miette", - "thiserror 2.0.12", + "thiserror 2.0.17", ] [[package]] name = "libc" -version = "0.2.174" +version = "0.2.177" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" +checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" [[package]] name = "libgssapi" @@ -1383,7 +1407,7 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8663f3a3a93dd394b669dd9b213b457c5e0d2bc5a1b13a0950bd733c6fb6e37" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.4", "bytes", "lazy_static", "libgssapi-sys", @@ -1406,7 +1430,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" dependencies = [ "cfg-if", - "windows-targets 0.53.2", + "windows-targets 0.53.5", +] + +[[package]] +name = "libredox" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" +dependencies = [ + "bitflags 2.9.4", + "libc", + "redox_syscall", ] [[package]] @@ -1434,15 +1469,9 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.4.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" - -[[package]] -name = "linux-raw-sys" -version = "0.9.4" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" [[package]] name = "litemap" @@ -1452,19 +1481,18 @@ checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" [[package]] name = "lock_api" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" dependencies = [ - "autocfg", "scopeguard", ] [[package]] name = "log" -version = "0.4.27" +version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" dependencies = [ "serde", ] @@ -1477,29 +1505,30 @@ checksum = "a94d21414c1f4a51209ad204c1776a3d0765002c76c6abcb602a6f09f1e881c7" [[package]] name = "log4rs" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0816135ae15bd0391cf284eab37e6e3ee0a6ee63d2ceeb659862bd8d0a984ca6" +checksum = "3e947bb896e702c711fccc2bf02ab2abb6072910693818d1d6b07ee2b9dfd86c" dependencies = [ "anyhow", "arc-swap", "chrono", - "derivative", + "derive_more", "fnv", "humantime", "libc", "log", "log-mdc", - "once_cell", + "mock_instant", "parking_lot", - "rand 0.8.5", + "rand", "serde", "serde-value", "serde_json", "serde_yaml", - "thiserror 1.0.69", + "thiserror 2.0.17", "thread-id", "typemap-ors", + "unicode-segmentation", "winapi", ] @@ -1525,9 +1554,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.5" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "metrics" @@ -1568,10 +1597,10 @@ checksum = "b8496cc523d1f94c1385dd8f0f0c2c480b2b8aeccb5b7e4485ad6365523ae376" dependencies = [ "crossbeam-epoch", "crossbeam-utils", - "hashbrown 0.15.4", + "hashbrown 0.15.5", "metrics", "quanta", - "rand 0.9.1", + "rand", "rand_xoshiro", "sketches-ddsketch", ] @@ -1595,7 +1624,7 @@ checksum = "db5b29714e950dbb20d5e6f74f9dcec4edbcc1067bb7f8ed198c097b8c1a818b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", ] [[package]] @@ -1630,6 +1659,12 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "mock_instant" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce6dd36094cac388f119d2e9dc82dc730ef91c32a6222170d630e5414b956e6" + [[package]] name = "nom" version = "7.1.3" @@ -1703,14 +1738,14 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.104", + "syn", ] [[package]] name = "object" -version = "0.36.7" +version = "0.37.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" dependencies = [ "memchr", ] @@ -1742,7 +1777,7 @@ version = "0.10.73" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.4", "cfg-if", "foreign-types", "libc", @@ -1759,7 +1794,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", ] [[package]] @@ -1801,9 +1836,9 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.4" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" dependencies = [ "lock_api", "parking_lot_core", @@ -1811,37 +1846,38 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.11" +version = "0.9.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-targets 0.52.6", + "windows-link 0.2.1", ] [[package]] name = "percent-encoding" -version = "2.3.1" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "phf" -version = "0.11.3" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" +checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" dependencies = [ "phf_shared", + "serde", ] [[package]] name = "phf_shared" -version = "0.11.3" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" +checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266" dependencies = [ "siphasher", ] @@ -1881,9 +1917,9 @@ dependencies = [ [[package]] name = "postgres-openssl" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb14e4bbc2c0b3d165bf30b79c7a9c10412dff9d98491ffdd64ed810ab891d21" +checksum = "8f86f073ad570f76e9e278ce6f05775fc723eed7daa6b4f9c2aa078080a564a0" dependencies = [ "openssl", "tokio", @@ -1893,9 +1929,9 @@ dependencies = [ [[package]] name = "postgres-protocol" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76ff0abab4a9b844b93ef7b81f1efc0a366062aaef2cd702c76256b5dc075c54" +checksum = "fbef655056b916eb868048276cfd5d6a7dea4f81560dfd047f97c8c6fe3fcfd4" dependencies = [ "base64", "byteorder", @@ -1904,16 +1940,16 @@ dependencies = [ "hmac", "md-5", "memchr", - "rand 0.9.1", + "rand", "sha2", "stringprep", ] [[package]] name = "postgres-types" -version = "0.2.9" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613283563cd90e1dfc3518d548caee47e0e725455ed619881f5cf21f36de4b48" +checksum = "ef4605b7c057056dd35baeb6ac0c0338e4975b1f2bef0f65da953285eb007095" dependencies = [ "bytes", "fallible-iterator", @@ -1922,9 +1958,9 @@ dependencies = [ [[package]] name = "potential_utf" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +checksum = "84df19adbe5b5a0782edcab45899906947ab039ccf4573713735ee7de1e6b08a" dependencies = [ "zerovec", ] @@ -1955,28 +1991,28 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.2.35" +version = "0.2.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "061c1221631e079b26479d25bbf2275bfe5917ae8419cd7e34f13bfc2aa7539a" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", - "syn 2.0.104", + "syn", ] [[package]] name = "proc-macro-crate" -version = "3.3.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35" +checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" dependencies = [ - "toml_edit", + "toml_edit 0.23.7", ] [[package]] name = "proc-macro2" -version = "1.0.95" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" dependencies = [ "unicode-ident", ] @@ -2007,9 +2043,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.40" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" dependencies = [ "proc-macro2", ] @@ -2022,33 +2058,12 @@ checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" [[package]] name = "rand" -version = "0.8.5" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ - "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.4", -] - -[[package]] -name = "rand" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" -dependencies = [ - "rand_chacha 0.9.0", - "rand_core 0.9.3", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core 0.6.4", + "rand_chacha", + "rand_core", ] [[package]] @@ -2058,16 +2073,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core 0.9.3", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom 0.2.16", + "rand_core", ] [[package]] @@ -2085,16 +2091,16 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f703f4665700daf5512dcca5f43afa6af89f09db47fb56be587f80636bda2d41" dependencies = [ - "rand_core 0.9.3", + "rand_core", ] [[package]] name = "raw-cpuid" -version = "11.5.0" +version = "11.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6df7ab838ed27997ba19a4664507e6f82b41fe6e20be42929332156e5e85146" +checksum = "498cd0dc59d73224351ee52a95fee0f1a617a2eae0e7d9d720cc622c73a54186" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.4", ] [[package]] @@ -2117,9 +2123,9 @@ dependencies = [ [[package]] name = "rdkafka-sys" -version = "4.8.0+2.3.0" +version = "4.9.0+2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced38182dc436b3d9df0c77976f37a67134df26b050df1f0006688e46fc4c8be" +checksum = "5230dca48bc354d718269f3e4353280e188b610f7af7e2fcf54b7a79d5802872" dependencies = [ "libc", "libz-sys", @@ -2146,7 +2152,7 @@ dependencies = [ "pin-project-lite", "ryu", "sha1_smol", - "socket2", + "socket2 0.5.10", "tokio", "tokio-util", "url", @@ -2154,18 +2160,18 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.13" +version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.4", ] [[package]] name = "regex" -version = "1.11.1" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +checksum = "4a52d8d02cacdb176ef4678de6c052efb4b3da14b78e4db683a4252762be5433" dependencies = [ "aho-corasick", "memchr", @@ -2175,9 +2181,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.9" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +checksum = "722166aa0d7438abbaa4d5cc2c649dac844e8c56d82fb3d33e9c34b5cd268fc6" dependencies = [ "aho-corasick", "memchr", @@ -2186,9 +2192,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.5" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +checksum = "c3160422bbd54dd5ecfdca71e5fd59b7b8fe2b1697ab2baf64f6d05dcc66d298" [[package]] name = "retain_mut" @@ -2232,15 +2238,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.25" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f" - -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" [[package]] name = "rustc-hash" @@ -2259,35 +2259,22 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" -dependencies = [ - "bitflags 2.9.1", - "errno", - "libc", - "linux-raw-sys 0.4.15", - "windows-sys 0.59.0", -] - -[[package]] -name = "rustix" -version = "1.0.7" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" +checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.4", "errno", "libc", - "linux-raw-sys 0.9.4", - "windows-sys 0.59.0", + "linux-raw-sys", + "windows-sys 0.61.2", ] [[package]] name = "rustls" -version = "0.23.28" +version = "0.23.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7160e3e10bf4535308537f3c4e1641468cd0e485175d6163087c0393c7d46643" +checksum = "cd3c25631629d034ce7cd9940adc9d45762d46de2b0f57193c4443b92c6d4d40" dependencies = [ "aws-lc-rs", "log", @@ -2330,9 +2317,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.103.3" +version = "0.103.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4a72fe2bcf7a6ac6fd7d0b9e5cb68aeb7d4c0a0271730218b3e92d43b4eb435" +checksum = "e10b3f4191e8a80e6b43eebabfac91e5dcecebb27a71f04e820c47ec41d314bf" dependencies = [ "aws-lc-rs", "ring", @@ -2342,9 +2329,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.21" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "ryu" @@ -2366,20 +2353,20 @@ dependencies = [ [[package]] name = "scc" -version = "2.3.4" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22b2d775fb28f245817589471dd49c5edf64237f4a19d10ce9a92ff4651a27f4" +checksum = "46e6f046b7fef48e2660c57ed794263155d713de679057f2d0c169bfc6e756cc" dependencies = [ "sdd", ] [[package]] name = "schannel" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" +checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -2390,18 +2377,18 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "sdd" -version = "3.0.8" +version = "3.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "584e070911c7017da6cb2eb0788d09f43d789029b5877d3e5ecc8acf86ceee21" +checksum = "490dcfcbfef26be6800d11870ff2df8774fa6e86d047e3e8c8a76b25655e41ca" [[package]] name = "security-framework" -version = "3.2.0" +version = "3.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271720403f46ca04f7ba6f55d438f8bd878d6b8ca0a1046e8228c4145bcbb316" +checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef" dependencies = [ - "bitflags 2.9.1", - "core-foundation", + "bitflags 2.9.4", + "core-foundation 0.10.1", "core-foundation-sys", "libc", "security-framework-sys", @@ -2409,9 +2396,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.14.0" +version = "2.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" +checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" dependencies = [ "core-foundation-sys", "libc", @@ -2419,10 +2406,11 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ + "serde_core", "serde_derive", ] @@ -2436,27 +2424,37 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + [[package]] name = "serde_derive" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", ] [[package]] name = "serde_json" -version = "1.0.140" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" dependencies = [ "itoa", "memchr", "ryu", "serde", + "serde_core", ] [[package]] @@ -2503,7 +2501,7 @@ checksum = "5d69265a08751de7844521fd15003ae0a888e035773ba05695c5c759a6f89eef" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", ] [[package]] @@ -2545,9 +2543,9 @@ dependencies = [ "serde", "serde_json", "sha1", - "socket2", + "socket2 0.6.0", "strum", - "thiserror 2.0.12", + "thiserror 2.0.17", "tokio", "tokio-rustls", "tokio-util", @@ -2587,9 +2585,9 @@ dependencies = [ [[package]] name = "shared_child" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2778001df1384cf20b6dc5a5a90f48da35539885edaaefd887f8d744e939c0b" +checksum = "1e362d9935bc50f019969e2f9ecd66786612daae13e8f277be7bfb66e8bed3f7" dependencies = [ "libc", "sigchld", @@ -2604,9 +2602,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "sigchld" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1219ef50fc0fdb04fcc243e6aa27f855553434ffafe4fa26554efb78b5b4bf89" +checksum = "47106eded3c154e70176fc83df9737335c94ce22f821c32d17ed1db1f83badb1" dependencies = [ "libc", "os_pipe", @@ -2625,9 +2623,9 @@ dependencies = [ [[package]] name = "signal-hook-registry" -version = "1.4.5" +version = "1.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" +checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b" dependencies = [ "libc", ] @@ -2666,11 +2664,21 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "socket2" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + [[package]] name = "stable_deref_trait" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "stringprep" @@ -2691,24 +2699,23 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "strum" -version = "0.27.1" +version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f64def088c51c9510a8579e3c5d67c65349dcf755e5479ad3d010aa6454e2c32" +checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf" dependencies = [ "strum_macros", ] [[package]] name = "strum_macros" -version = "0.27.1" +version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c77a8c5abcaf0f9ce05d62342b7d298c346515365c36b673df4ebe3ced01fde8" +checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7" dependencies = [ "heck", "proc-macro2", "quote", - "rustversion", - "syn 2.0.104", + "syn", ] [[package]] @@ -2719,9 +2726,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "1.0.109" +version = "2.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" dependencies = [ "proc-macro2", "quote", @@ -2729,38 +2736,48 @@ dependencies = [ ] [[package]] -name = "syn" -version = "2.0.104" +name = "synstructure" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "unicode-ident", + "syn", ] [[package]] -name = "synstructure" -version = "0.13.2" +name = "system-configuration" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.104", + "bitflags 2.9.4", + "core-foundation 0.9.4", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" +dependencies = [ + "core-foundation-sys", + "libc", ] [[package]] name = "tempfile" -version = "3.20.0" +version = "3.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" +checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" dependencies = [ "fastrand", "getrandom 0.3.3", "once_cell", - "rustix 1.0.7", - "windows-sys 0.59.0", + "rustix", + "windows-sys 0.61.2", ] [[package]] @@ -2774,11 +2791,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.12" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" dependencies = [ - "thiserror-impl 2.0.12", + "thiserror-impl 2.0.17", ] [[package]] @@ -2789,35 +2806,35 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", ] [[package]] name = "thiserror-impl" -version = "2.0.12" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", ] [[package]] name = "thread-id" -version = "4.2.2" +version = "5.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfe8f25bbdd100db7e1d34acf7fd2dc59c4bf8f7483f505eaa7d4f12f76cc0ea" +checksum = "99043e46c5a15af379c06add30d9c93a6c0e8849de00d244c4a2c417da128d80" dependencies = [ "libc", - "winapi", + "windows-sys 0.59.0", ] [[package]] name = "time" -version = "0.3.41" +version = "0.3.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" +checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" dependencies = [ "deranged", "itoa", @@ -2830,15 +2847,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.4" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" +checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" [[package]] name = "time-macros" -version = "0.2.22" +version = "0.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" +checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" dependencies = [ "num-conv", "time-core", @@ -2856,9 +2873,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71" +checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" dependencies = [ "tinyvec_macros", ] @@ -2871,20 +2888,22 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.45.1" +version = "1.47.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779" +checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" dependencies = [ "backtrace", "bytes", + "io-uring", "libc", "mio", "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2", + "slab", + "socket2 0.6.0", "tokio-macros", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -2895,7 +2914,7 @@ checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", ] [[package]] @@ -2911,9 +2930,9 @@ dependencies = [ [[package]] name = "tokio-postgres" -version = "0.7.13" +version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c95d533c83082bb6490e0189acaa0bbeef9084e60471b696ca6988cd0541fb0" +checksum = "2b40d66d9b2cfe04b628173409368e58247e8eddbbd3b0e6c6ba1d09f20f6c9e" dependencies = [ "async-trait", "byteorder", @@ -2928,8 +2947,8 @@ dependencies = [ "pin-project-lite", "postgres-protocol", "postgres-types", - "rand 0.9.1", - "socket2", + "rand", + "socket2 0.6.0", "tokio", "tokio-util", "whoami", @@ -2937,9 +2956,9 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.26.2" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" dependencies = [ "rustls", "tokio", @@ -2947,9 +2966,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.15" +version = "0.7.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df" +checksum = "14307c986784f72ef81c89db7d9e28d6ac26d16213b109ea501696195e6e3ce5" dependencies = [ "bytes", "futures-core", @@ -2966,8 +2985,8 @@ checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" dependencies = [ "serde", "serde_spanned", - "toml_datetime", - "toml_edit", + "toml_datetime 0.6.11", + "toml_edit 0.22.27", ] [[package]] @@ -2979,6 +2998,15 @@ dependencies = [ "serde", ] +[[package]] +name = "toml_datetime" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2cdb639ebbc97961c51720f858597f7f24c4fc295327923af55b74c3c724533" +dependencies = [ + "serde_core", +] + [[package]] name = "toml_edit" version = "0.22.27" @@ -2988,11 +3016,32 @@ dependencies = [ "indexmap", "serde", "serde_spanned", - "toml_datetime", + "toml_datetime 0.6.11", "toml_write", "winnow", ] +[[package]] +name = "toml_edit" +version = "0.23.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6485ef6d0d9b5d0ec17244ff7eb05310113c3f316f2d14200d4de56b3cb98f8d" +dependencies = [ + "indexmap", + "toml_datetime 0.7.3", + "toml_parser", + "winnow", +] + +[[package]] +name = "toml_parser" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e" +dependencies = [ + "winnow", +] + [[package]] name = "toml_write" version = "0.1.2" @@ -3024,7 +3073,7 @@ checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", ] [[package]] @@ -3053,9 +3102,9 @@ dependencies = [ [[package]] name = "typenum" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] name = "unicode-bidi" @@ -3065,9 +3114,9 @@ checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" [[package]] name = "unicode-ident" -version = "1.0.18" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" [[package]] name = "unicode-normalization" @@ -3084,12 +3133,24 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + [[package]] name = "unicode-width" version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + [[package]] name = "unsafe-any-ors" version = "1.0.0" @@ -3113,13 +3174,14 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.4" +version = "2.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" dependencies = [ "form_urlencoded", "idna", "percent-encoding", + "serde", ] [[package]] @@ -3136,13 +3198,13 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.17.0" +version = "1.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d" +checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2" dependencies = [ "getrandom 0.3.3", "js-sys", - "rand 0.9.1", + "rand", "serde", "wasm-bindgen", ] @@ -3176,11 +3238,20 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasi" -version = "0.14.2+wasi-0.2.4" +version = "0.14.7+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" +dependencies = [ + "wasip2", +] + +[[package]] +name = "wasip2" +version = "1.0.1+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" dependencies = [ - "wit-bindgen-rt", + "wit-bindgen", ] [[package]] @@ -3191,35 +3262,36 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasm-bindgen" -version = "0.2.100" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +checksum = "c1da10c01ae9f1ae40cbfac0bac3b1e724b320abfcf52229f80b547c0d250e2d" dependencies = [ "cfg-if", "once_cell", "rustversion", "wasm-bindgen-macro", + "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.100" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +checksum = "671c9a5a66f49d8a47345ab942e2cb93c7d1d0339065d4f8139c486121b43b19" dependencies = [ "bumpalo", "log", "proc-macro2", "quote", - "syn 2.0.104", + "syn", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.100" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +checksum = "7ca60477e4c59f5f2986c50191cd972e3a50d8a95603bc9434501cf156a9a119" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3227,55 +3299,43 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.100" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.100" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +checksum = "bad67dc8b2a1a6e5448428adec4c3e84c43e561d8c9ee8a9e5aabeb193ec41d1" dependencies = [ "unicode-ident", ] [[package]] name = "web-sys" -version = "0.3.77" +version = "0.3.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +checksum = "9367c417a924a74cae129e6a2ae3b47fabb1f8995595ab474029da749a8be120" dependencies = [ "js-sys", "wasm-bindgen", ] -[[package]] -name = "which" -version = "4.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" -dependencies = [ - "either", - "home", - "once_cell", - "rustix 0.38.44", -] - [[package]] name = "whoami" -version = "1.6.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6994d13118ab492c3c80c1f81928718159254c53c472bf9ce36f8dae4add02a7" +checksum = "5d4a4db5077702ca3015d3d02d74974948aba2ad9e12ab7df718ee64ccd7e97d" dependencies = [ - "redox_syscall", + "libredox", "wasite", "web-sys", ] @@ -3304,37 +3364,37 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-core" -version = "0.61.2" +version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ "windows-implement", "windows-interface", - "windows-link", - "windows-result", - "windows-strings", + "windows-link 0.2.1", + "windows-result 0.4.1", + "windows-strings 0.5.1", ] [[package]] name = "windows-implement" -version = "0.60.0" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", ] [[package]] name = "windows-interface" -version = "0.59.1" +version = "0.59.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", ] [[package]] @@ -3343,13 +3403,39 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-registry" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b8a9ed28765efc97bbc954883f4e6796c33a06546ebafacbabee9696967499e" +dependencies = [ + "windows-link 0.1.3", + "windows-result 0.3.4", + "windows-strings 0.4.2", +] + [[package]] name = "windows-result" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" dependencies = [ - "windows-link", + "windows-link 0.1.3", +] + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link 0.2.1", ] [[package]] @@ -3358,7 +3444,16 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" dependencies = [ - "windows-link", + "windows-link 0.1.3", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link 0.2.1", ] [[package]] @@ -3385,7 +3480,16 @@ version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ - "windows-targets 0.53.2", + "windows-targets 0.53.5", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link 0.2.1", ] [[package]] @@ -3406,18 +3510,19 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.53.2" +version = "0.53.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" dependencies = [ - "windows_aarch64_gnullvm 0.53.0", - "windows_aarch64_msvc 0.53.0", - "windows_i686_gnu 0.53.0", - "windows_i686_gnullvm 0.53.0", - "windows_i686_msvc 0.53.0", - "windows_x86_64_gnu 0.53.0", - "windows_x86_64_gnullvm 0.53.0", - "windows_x86_64_msvc 0.53.0", + "windows-link 0.2.1", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", ] [[package]] @@ -3428,9 +3533,9 @@ checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" [[package]] name = "windows_aarch64_msvc" @@ -3440,9 +3545,9 @@ checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_aarch64_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" [[package]] name = "windows_i686_gnu" @@ -3452,9 +3557,9 @@ checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnu" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" [[package]] name = "windows_i686_gnullvm" @@ -3464,9 +3569,9 @@ checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" [[package]] name = "windows_i686_msvc" @@ -3476,9 +3581,9 @@ checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_i686_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" [[package]] name = "windows_x86_64_gnu" @@ -3488,9 +3593,9 @@ checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnu" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" [[package]] name = "windows_x86_64_gnullvm" @@ -3500,9 +3605,9 @@ checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" [[package]] name = "windows_x86_64_msvc" @@ -3512,27 +3617,24 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "windows_x86_64_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] name = "winnow" -version = "0.7.11" +version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74c7b26e3480b707944fc872477815d29a8e429d2f93a1ce000f5fa84a15cbcd" +checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" dependencies = [ "memchr", ] [[package]] -name = "wit-bindgen-rt" -version = "0.39.0" +name = "wit-bindgen" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" -dependencies = [ - "bitflags 2.9.1", -] +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" [[package]] name = "writeable" @@ -3553,7 +3655,7 @@ dependencies = [ "nom", "oid-registry", "rusticata-macros", - "thiserror 2.0.12", + "thiserror 2.0.17", "time", ] @@ -3583,28 +3685,28 @@ checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", "synstructure", ] [[package]] name = "zerocopy" -version = "0.8.26" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" +checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.26" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" +checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", ] [[package]] @@ -3624,15 +3726,15 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", "synstructure", ] [[package]] name = "zeroize" -version = "1.8.1" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" [[package]] name = "zerotrie" @@ -3647,9 +3749,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.2" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" +checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b" dependencies = [ "yoke", "zerofrom", @@ -3664,16 +3766,16 @@ checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", ] [[package]] name = "zstd-sys" -version = "2.0.15+zstd.1.5.7" +version = "2.0.16+zstd.1.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb81183ddd97d0c74cedf1d50d85c8d08c1b8b68ee863bdee9e706eedba1a237" +checksum = "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748" dependencies = [ - "bindgen 0.71.1", + "bindgen 0.72.1", "cc", "pkg-config", ] diff --git a/cli/src/main.rs b/cli/src/main.rs index f36195c4..e72f3874 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -113,7 +113,7 @@ async fn main() { .subcommand( Command::new("files") .about("Configures a Files output which will store events on disk at configured path") - .arg(arg!( "Destination path that can use variables. Example: \"/archive/{ip}/{principal}/{node}/messages\", where {ip} is the string representation of the IP addr of the machine and {principal} its Kerberos principal. See documentation for other variables.")) + .arg(arg!( "Destination path that can use variables. Example: \"/archive/{ip}/{client}/{node}/messages\", where {ip} is the string representation of the IP addr of the machine and {client} its identifier (Kerberos Principal or TLS subject). See documentation for other variables.")) ) .subcommand( Command::new("unixdatagram") @@ -139,35 +139,6 @@ async fn main() { .arg(arg!( "Index of the output to disable").value_parser(value_parser!(usize))) ) ) - .subcommand( - Command::new("filter") - .about("Manage the principals filter of a subscription.") - .subcommand( - Command::new("set") - .about("Set the principals filter.") - .arg(arg!( "Possible operations are: 'none' (don't filter), 'only' (only apply this subscription to the given principals), 'except' (apply this subcription to everyone except the given principals).").value_parser(["none", "only", "except"]).required(true)) - .arg(arg!( ... "Principals to filter. The comparison of principal names is case-sensitive.").action(ArgAction::Append).required(false)) - ) - .subcommand( - Command::new("princs") - .about("Manage the principals of the filter.") - .subcommand( - Command::new("add") - .about("Add a principal (case-sensitive)") - .arg(arg!( "Principal to add. The comparison of principal names is case-sensitive.")) - ) - .subcommand( - Command::new("delete") - .about("Delete a principal (case-sensitive)") - .arg(arg!( "Principal to delete. The comparison of principal names is case-sensitive.")) - ) - .subcommand( - Command::new("set") - .about("Set the principals (case-sensitive)") - .arg(arg!( ... "Principals to filter. The comparison of principal names is case-sensitive.").action(ArgAction::Append).required(true)) - ) - ) - ) .arg(arg!(-q --query "File containing the query (XML format)")) .arg(arg!(-r --rename "Rename the subscription")) .arg( @@ -263,12 +234,13 @@ async fn main() { .arg(arg!( "Name or UUID of the subscription")) ) .subcommand( - Command::new("machines") - .about("Show subscribing machines. Defaults to all machines ever seen.") + Command::new("clients") + .alias("machines") + .about("Show subscribing clients. Defaults to all clients ever seen.") .arg(arg!( "Name or UUID of the subscription")) - .arg(arg!(-a --active "Only show active machines")) - .arg(arg!(-l --alive "Only show machines that are alive but not active")) - .arg(arg!(-d --dead "Only show dead machines principal")) + .arg(arg!(-a --active "Only show active clients")) + .arg(arg!(-l --alive "Only show clients that are alive but not active")) + .arg(arg!(-d --dead "Only show dead clients")) .arg( arg!(-i --interval "Duration after which a machine is considered alive if no events are received or dead if no heartbeats are received. \ Defaults to heartbeat-interval") diff --git a/cli/src/skell.rs b/cli/src/skell.rs index 3e7ef5e7..417bea5a 100644 --- a/cli/src/skell.rs +++ b/cli/src/skell.rs @@ -121,17 +121,28 @@ fn get_filter() -> String { r#" # Subscription filter (optional) # +# By default, everyone can read the subscription. +# # Filters enables you to choose which clients can read the subscription -# There are two operations available : -# - "Only": only the listed principals will be able to read the subscription -# - "Except": everyone but the listed principals will be able to read the subscription +# There are two operations available: +# - "Only": only the listed clients will be able to read the subscription +# - "Except": everyone but the listed clients will be able to read the subscription # -# By default, everyone can read the subscription. +# You can filter based on the following types: +# - Client: defines clients based on their identifier (from authentication) +# - MachineID: defines clients based on their System.Computer +# The default value is "Client" +# +# Multiple flags can be combined using the bitwise OR operator "|": +# - GlobPattern: targets are interpreted as glob patterns (e.g. "radis*@REALM") +# - CaseInsensitive: targets are compared in a case-insensitive way (off by default) # -# Example to only authorize "courgette@REALM" and "radis@REALM" to read the subscription. +# Example to only authorize clients matching the "courgette@REALM" and "radis*@REALM" patterns to read the subscription. # [filter] # operation = "Only" -# princs = ["courgette@REALM", "radis@REALM"] +# type = "Client" +# flags = "GlobPattern | CaseInsensitive" +# targets = ["courgette@REALM", "radis*@REALM"] "# .to_string() @@ -155,7 +166,7 @@ fn get_outputs() -> String { # Files driver has the following parameters: # - path (required): the path in which files will be written. It can be parameterized # with variables using the syntax {variable} (see available variables in documentation) -# config = { path = "/var/log/openwec/{ip:2}/{ip:3}/{ip}/{principal}/messages" } +# config = { path = "/var/log/openwec/{ip:2}/{ip:3}/{ip}/{client}/messages" } # Configure a Kafka output @@ -224,7 +235,7 @@ pub fn get_minimal_skell_content(uuid: Uuid, name: &str, now: DateTime) - [[outputs]] driver = "Files" format = "Raw" -config = { path = "/var/log/openwec/{ip:2}/{ip:3}/{ip}/{principal}/messages" } +config = { path = "/var/log/openwec/{ip:2}/{ip:3}/{ip}/{client}/messages" } "#, ); content diff --git a/cli/src/subscriptions.rs b/cli/src/subscriptions.rs index 0d191cfb..bcca4de4 100644 --- a/cli/src/subscriptions.rs +++ b/cli/src/subscriptions.rs @@ -3,10 +3,9 @@ use common::{ encoding::decode_utf16le, settings::Settings, subscription::{ - ContentFormat, FilesConfiguration, KafkaConfiguration, PrincsFilterOperation, - RedisConfiguration, SubscriptionData, SubscriptionMachineState, SubscriptionOutput, - SubscriptionOutputDriver, SubscriptionOutputFormat, TcpConfiguration, - UnixDatagramConfiguration, + ContentFormat, FilesConfiguration, KafkaConfiguration, RedisConfiguration, + SubscriptionData, SubscriptionMachineState, SubscriptionOutput, SubscriptionOutputDriver, + SubscriptionOutputFormat, TcpConfiguration, UnixDatagramConfiguration, }, }; use roxmltree::{Document, Node}; @@ -20,7 +19,7 @@ use std::{ }; use uuid::Uuid; -use anyhow::{anyhow, bail, ensure, Context, Result}; +use anyhow::{anyhow, bail, ensure, Context, Ok, Result}; use clap::ArgMatches; use log::{debug, info, warn}; use std::io::Write; @@ -234,9 +233,6 @@ async fn edit(db: &Db, matches: &ArgMatches) -> Result<()> { if let Some(("outputs", matches)) = matches.subcommand() { outputs(&mut subscription, matches).await?; } - if let Some(("filter", matches)) = matches.subcommand() { - edit_filter(&mut subscription, matches).await?; - } if let Some(query) = matches.get_one::("query") { let mut file = File::open(query)?; let mut new_query = String::new(); @@ -594,69 +590,6 @@ async fn delete(db: &Db, matches: &ArgMatches) -> Result<()> { db.delete_subscription(&subscription.uuid_string()).await } -async fn edit_filter(subscription: &mut SubscriptionData, matches: &ArgMatches) -> Result<()> { - let mut filter = subscription.princs_filter().clone(); - match matches.subcommand() { - Some(("set", matches)) => { - let op_str = matches - .get_one::("operation") - .ok_or_else(|| anyhow!("Missing operation argument"))?; - - let op_opt = PrincsFilterOperation::opt_from_str(op_str)?; - filter.set_operation(op_opt.clone()); - - if let Some(op) = op_opt { - let mut princs = HashSet::new(); - if let Some(identifiers) = matches.get_many::("principals") { - for identifier in identifiers { - princs.insert(identifier.clone()); - } - } - if op == PrincsFilterOperation::Only && princs.is_empty() { - warn!("'{}' filter has been set without principals making this subscription apply to nothing.", op) - } - filter.set_princs(princs)?; - } - } - Some(("princs", matches)) => match matches.subcommand() { - Some(("add", matches)) => { - filter.add_princ( - matches - .get_one::("principal") - .ok_or_else(|| anyhow!("Missing principal"))?, - )?; - } - Some(("delete", matches)) => { - filter.delete_princ( - matches - .get_one::("principal") - .ok_or_else(|| anyhow!("Missing principal"))?, - )?; - } - Some(("set", matches)) => match matches.get_many::("principals") { - Some(identifiers) => { - let mut princs = HashSet::new(); - for identifier in identifiers { - princs.insert(identifier.clone()); - } - filter.set_princs(princs)?; - } - None => { - bail!("No principals to set") - } - }, - _ => { - bail!("Nothing to do"); - } - }, - _ => { - bail!("Nothing to do"); - } - } - subscription.set_princs_filter(filter); - - Ok(()) -} async fn outputs(subscription: &mut SubscriptionData, matches: &ArgMatches) -> Result<()> { info!( "Loading subscription {} ({})", diff --git a/common/Cargo.toml b/common/Cargo.toml index 4bf8e3ca..bc9346e2 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -26,6 +26,8 @@ deadpool-sqlite = "0.5.0" openssl = "0.10.70" postgres-openssl = "0.5.0" strum = { version = "0.27.1", features = ["derive"] } +bitflags = { version = "2.6.0", features = ["serde"] } +glob = "0.3.1" [dev-dependencies] tempfile = "3.16.0" @@ -68,4 +70,4 @@ assets = [ { source = "../openwec.conf.sample.toml", dest = "/usr/share/doc/openwec/", mode = "0644", doc = true }, { source = "../README.md", dest = "/usr/share/doc/openwec/", mode = "0644", doc = true }, { source = "../doc/*", dest = "/usr/share/doc/openwec/doc/", mode = "0644", doc = true }, -] \ No newline at end of file +] diff --git a/common/src/database/mod.rs b/common/src/database/mod.rs index 1d23b17d..3a813ecf 100644 --- a/common/src/database/mod.rs +++ b/common/src/database/mod.rs @@ -124,14 +124,19 @@ pub mod tests { use crate::{ heartbeat::{HeartbeatKey, HeartbeatValue}, subscription::{ - ContentFormat, FilesConfiguration, PrincsFilter, PrincsFilterOperation, - SubscriptionOutput, SubscriptionOutputDriver, SubscriptionOutputFormat, - DEFAULT_CONTENT_FORMAT, DEFAULT_IGNORE_CHANNEL_ERROR, DEFAULT_READ_EXISTING_EVENTS, + ClientFilter, ClientFilterFlags, ClientFilterKind, ClientFilterOperation, + ContentFormat, FilesConfiguration, SubscriptionOutput, SubscriptionOutputDriver, + SubscriptionOutputFormat, DEFAULT_CONTENT_FORMAT, DEFAULT_IGNORE_CHANNEL_ERROR, + DEFAULT_READ_EXISTING_EVENTS, }, }; use super::{schema::Migrator, *}; - use std::{collections::HashSet, thread::sleep, time::Duration, time::SystemTime}; + use std::{ + collections::HashSet, + thread::sleep, + time::{Duration, SystemTime}, + }; async fn setup_db(db: Arc) -> Result<()> { db.setup_schema().await?; @@ -168,9 +173,9 @@ pub mod tests { assert_eq!(toto.read_existing_events(), DEFAULT_READ_EXISTING_EVENTS); assert_eq!(toto.content_format(), &DEFAULT_CONTENT_FORMAT); assert_eq!(toto.ignore_channel_error(), DEFAULT_IGNORE_CHANNEL_ERROR); - assert_eq!(toto.princs_filter().operation(), None); + assert_eq!(toto.client_filter(), None); assert_eq!(toto.is_active(), false); - assert_eq!(toto.is_active_for("couscous"), false); + assert_eq!(toto.is_active_for("couscous", None), false); assert_eq!(toto.revision(), None); assert_eq!(toto.data_locale(), None); assert_eq!(toto.locale(), None); @@ -185,17 +190,19 @@ pub mod tests { .unwrap(); assert_eq!(toto, &toto3); - let file_config_1 = FilesConfiguration::new("/path1/{ip}/{principal}/messages".to_string()); - let file_config_2 = FilesConfiguration::new("/path2/{ip}/{principal}/messages".to_string()); + let file_config_1 = FilesConfiguration::new("/path1/{ip}/{client}/messages".to_string()); + let file_config_2 = FilesConfiguration::new("/path2/{ip}/{client}/messages".to_string()); let mut subscription2 = SubscriptionData::new("tata", "query2"); subscription2 .set_read_existing_events(true) .set_content_format(ContentFormat::RenderedText) .set_ignore_channel_error(false) - .set_princs_filter(PrincsFilter::from( - Some("Only".to_string()), + .set_client_filter(Some(ClientFilter::from( + "Only".to_string(), + "Client".to_string(), + None, Some("couscous,boulette".to_string()), - )?) + )?)) .set_outputs(vec![ SubscriptionOutput::new( SubscriptionOutputFormat::Json, @@ -225,12 +232,20 @@ pub mod tests { assert_eq!(tata.content_format(), &ContentFormat::RenderedText); assert_eq!(tata.ignore_channel_error(), false); assert_eq!( - *tata.princs_filter().operation().unwrap(), - PrincsFilterOperation::Only + *tata.client_filter().unwrap().operation(), + ClientFilterOperation::Only + ); + assert_eq!( + tata.client_filter().unwrap().targets(), + HashSet::from(["couscous", "boulette"]) ); assert_eq!( - tata.princs_filter().princs(), - &HashSet::from(["couscous".to_string(), "boulette".to_string()]) + tata.client_filter().unwrap().kind(), + &ClientFilterKind::Client + ); + assert_eq!( + tata.client_filter().unwrap().flags(), + &ClientFilterFlags::empty() ); assert_eq!( @@ -249,10 +264,10 @@ pub mod tests { ], ); assert_eq!(tata.is_active(), true); - assert_eq!(tata.is_active_for("couscous"), true); + assert_eq!(tata.is_active_for("couscous", None), true); // Filter is case-sensitive - assert_eq!(tata.is_active_for("Couscous"), false); - assert_eq!(tata.is_active_for("semoule"), false); + assert_eq!(tata.is_active_for("Couscous", None), false); + assert_eq!(tata.is_active_for("semoule", None), false); assert_eq!(tata.revision(), Some("1472".to_string()).as_ref()); assert_eq!(tata.locale(), Some("fr-FR".to_string()).as_ref()); assert_eq!(tata.data_locale(), Some("en-US".to_string()).as_ref()); @@ -270,9 +285,23 @@ pub mod tests { .set_ignore_channel_error(true) .set_revision(Some("1890".to_string())) .set_data_locale(Some("fr-FR".to_string())); - let mut new_princs_filter = tata.princs_filter().clone(); - new_princs_filter.add_princ("semoule")?; - tata.set_princs_filter(new_princs_filter); + + let orig_filter = &tata.client_filter().unwrap(); + let mut new_targets: HashSet = orig_filter + .targets() + .iter() + .map(|&f| f.to_owned()) + .collect(); + new_targets.insert("semoule".to_owned()); + + let new_client_filter = ClientFilter::try_new( + orig_filter.operation().clone(), + orig_filter.kind().clone(), + orig_filter.flags().clone(), + new_targets, + )?; + + tata.set_client_filter(Some(new_client_filter)); db.store_subscription(&tata).await?; @@ -291,29 +320,36 @@ pub mod tests { assert_eq!(tata2.content_format(), &ContentFormat::Raw); assert_eq!(tata2.ignore_channel_error(), true); assert_eq!( - *tata2.princs_filter().operation().unwrap(), - PrincsFilterOperation::Only + *tata2.client_filter().unwrap().operation(), + ClientFilterOperation::Only ); assert_eq!( - tata2.princs_filter().princs(), - &HashSet::from([ - "couscous".to_string(), - "boulette".to_string(), - "semoule".to_string() - ]) + tata2.client_filter().unwrap().targets(), + HashSet::from(["couscous", "boulette", "semoule"]) + ); + assert_eq!( + tata.client_filter().unwrap().kind(), + &ClientFilterKind::Client ); - assert_eq!(tata2.is_active_for("couscous"), true); - assert_eq!(tata2.is_active_for("semoule"), true); + assert_eq!( + tata.client_filter().unwrap().flags(), + &ClientFilterFlags::empty() + ); + assert_eq!(tata2.is_active_for("couscous", None), true); + assert_eq!(tata2.is_active_for("semoule", None), true); assert_eq!(tata2.revision(), Some("1890".to_string()).as_ref()); assert_eq!(tata2.locale(), Some("fr-FR".to_string()).as_ref()); // Unchanged assert_eq!(tata2.data_locale(), Some("fr-FR".to_string()).as_ref()); assert!(tata2.public_version()? != tata_save.public_version()?); - let mut new_princs_filter = tata2.princs_filter().clone(); - new_princs_filter.delete_princ("couscous")?; - new_princs_filter.set_operation(Some(PrincsFilterOperation::Except)); - tata2.set_princs_filter(new_princs_filter); + let new_client_filter = ClientFilter::try_new( + ClientFilterOperation::Except, + ClientFilterKind::MachineID, + ClientFilterFlags::CaseInsensitive, + HashSet::from(["boulette".to_owned(), "semoule".to_owned()]), + )?; + tata2.set_client_filter(Some(new_client_filter)); db.store_subscription(&tata2).await?; @@ -322,21 +358,39 @@ pub mod tests { .await? .unwrap(); assert_eq!( - *tata2_clone.princs_filter().operation().unwrap(), - PrincsFilterOperation::Except + *tata2_clone.client_filter().unwrap().operation(), + ClientFilterOperation::Except + ); + assert_eq!( + *tata2_clone.client_filter().unwrap().kind(), + ClientFilterKind::MachineID + ); + assert_eq!( + *tata2_clone.client_filter().unwrap().flags(), + ClientFilterFlags::CaseInsensitive ); assert_eq!( - tata2_clone.princs_filter().princs(), - &HashSet::from(["boulette".to_string(), "semoule".to_string()]) + tata2_clone.client_filter().unwrap().targets(), + HashSet::from(["boulette", "semoule"]) ); - assert_eq!(tata2_clone.is_active_for("couscous"), true); - assert_eq!(tata2_clone.is_active_for("semoule"), false); - assert_eq!(tata2_clone.is_active_for("boulette"), false); + assert_eq!(tata2_clone.is_active_for("couscous", None), true); + assert_eq!(tata2_clone.is_active_for("semoule", None), true); + assert_eq!(tata2_clone.is_active_for("boulette", None), true); + + assert_eq!( + tata2_clone.is_active_for("couscous", Some("couscous")), + true + ); + assert_eq!(tata2_clone.is_active_for("semoule", Some("semoule")), false); + assert_eq!(tata2_clone.is_active_for("babar", Some("SEmOuLe")), false); + assert_eq!(tata2_clone.is_active_for("boul", Some("BOUlette")), false); + assert_eq!( + tata2_clone.is_active_for("boulette", Some("notboulette")), + true + ); - let mut new_princs_filter = tata2_clone.princs_filter().clone(); - new_princs_filter.set_operation(None); - tata2_clone.set_princs_filter(new_princs_filter); + tata2_clone.set_client_filter(None); db.store_subscription(&tata2_clone).await?; @@ -344,11 +398,10 @@ pub mod tests { .get_subscription_by_identifier(&tata.uuid_string()) .await? .unwrap(); - assert_eq!(tata2_clone_clone.princs_filter().operation(), None); - assert_eq!(tata2_clone_clone.princs_filter().princs(), &HashSet::new()); - assert_eq!(tata2_clone_clone.is_active_for("couscous"), true); - assert_eq!(tata2_clone_clone.is_active_for("semoule"), true); - assert_eq!(tata2_clone_clone.is_active_for("boulette"), true); + assert_eq!(tata2_clone_clone.client_filter(), None); + assert_eq!(tata2_clone_clone.is_active_for("couscous", None), true); + assert_eq!(tata2_clone_clone.is_active_for("semoule", None), true); + assert_eq!(tata2_clone_clone.is_active_for("boulette", None), true); db.delete_subscription(&toto3.uuid_string()).await?; ensure!( diff --git a/common/src/database/postgres.rs b/common/src/database/postgres.rs index 921bbf21..9743f68e 100644 --- a/common/src/database/postgres.rs +++ b/common/src/database/postgres.rs @@ -31,7 +31,7 @@ use crate::bookmark::BookmarkData; use crate::heartbeat::{HeartbeatKey, HeartbeatsCache}; use crate::settings::PostgresSslMode; use crate::subscription::{ - ContentFormat, InternalVersion, PrincsFilter, SubscriptionMachine, SubscriptionMachineState, + ClientFilter, ContentFormat, InternalVersion, SubscriptionMachine, SubscriptionMachineState, SubscriptionStatsCounters, SubscriptionUuid, }; use crate::{ @@ -213,10 +213,21 @@ fn row_to_subscription(row: &Row) -> Result { let max_time: i32 = row.try_get("max_time")?; let max_elements: Option = row.try_get("max_elements")?; - let princs_filter = PrincsFilter::from( - row.try_get("princs_filter_op")?, - row.try_get("princs_filter_value")?, - )?; + let client_filter_op: Option = row.try_get("client_filter_op")?; + + let client_filter = match client_filter_op { + Some(op) => { + let client_filter_kind: Option = row.try_get("client_filter_kind")?; + let client_filter_flags: Option = row.try_get("client_filter_flags")?; + Some(ClientFilter::from( + op, + client_filter_kind.unwrap(), + client_filter_flags.map(|c| c.try_into()).transpose()?, + row.try_get("client_filter_targets")?, + )?) + } + None => None, + }; let mut subscription = SubscriptionData::new(row.try_get("name")?, row.try_get("query")?); subscription @@ -238,7 +249,7 @@ fn row_to_subscription(row: &Row) -> Result { .set_ignore_channel_error(row.try_get("ignore_channel_error")?) .set_locale(row.try_get("locale")?) .set_data_locale(row.try_get("data_locale")?) - .set_princs_filter(princs_filter) + .set_client_filter(client_filter) .set_outputs(outputs); // This needs to be done at the end because version is updated each time @@ -625,6 +636,18 @@ impl Database for PostgresDatabase { }; let max_envelope_size: i32 = subscription.max_envelope_size().try_into()?; + let client_filter_op: Option = subscription + .client_filter() + .map(|f| f.operation().to_string()); + let client_filter_kind = subscription.client_filter().map(|f| f.kind().to_string()); + let client_filter_flags: Option = subscription + .client_filter() + .map(|f| f.flags().bits().try_into()) + .transpose()?; + let client_filter_targets = subscription + .client_filter() + .and_then(|f| f.targets_to_opt_string()); + let count = self .pool .get() @@ -633,9 +656,9 @@ impl Database for PostgresDatabase { r#"INSERT INTO subscriptions (uuid, version, revision, name, uri, query, heartbeat_interval, connection_retry_count, connection_retry_interval, max_time, max_elements, max_envelope_size, enabled, read_existing_events, content_format, - ignore_channel_error, princs_filter_op, princs_filter_value, outputs, locale, + ignore_channel_error, client_filter_op, client_filter_kind, client_filter_flags, client_filter_targets, outputs, locale, data_locale) - VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21) + VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23) ON CONFLICT (uuid) DO UPDATE SET version = excluded.version, revision = excluded.revision, @@ -652,8 +675,10 @@ impl Database for PostgresDatabase { read_existing_events = excluded.read_existing_events, content_format = excluded.content_format, ignore_channel_error = excluded.ignore_channel_error, - princs_filter_op = excluded.princs_filter_op, - princs_filter_value = excluded.princs_filter_value, + client_filter_op = excluded.client_filter_op, + client_filter_kind = excluded.client_filter_kind, + client_filter_flags = excluded.client_filter_flags, + client_filter_targets = excluded.client_filter_targets, outputs = excluded.outputs, locale = excluded.locale, data_locale = excluded.data_locale"#, @@ -674,11 +699,10 @@ impl Database for PostgresDatabase { &subscription.read_existing_events(), &subscription.content_format().to_string(), &subscription.ignore_channel_error(), - &subscription - .princs_filter() - .operation() - .map(|x| x.to_string()), - &subscription.princs_filter().princs_to_opt_string(), + &client_filter_op, + &client_filter_kind, + &client_filter_flags, + &client_filter_targets, &serde_json::to_string(subscription.outputs())?.as_str(), &subscription.locale(), &subscription.data_locale() diff --git a/common/src/database/schema/postgres/_014_alter_client_filter_in_subscriptions.rs b/common/src/database/schema/postgres/_014_alter_client_filter_in_subscriptions.rs new file mode 100644 index 00000000..753cda7f --- /dev/null +++ b/common/src/database/schema/postgres/_014_alter_client_filter_in_subscriptions.rs @@ -0,0 +1,63 @@ +use anyhow::Result; +use async_trait::async_trait; +use deadpool_postgres::Transaction; + +use crate::{database::postgres::PostgresMigration, migration}; + +pub(super) struct AlterClientFilterInSubscriptionsTable; +migration!( + AlterClientFilterInSubscriptionsTable, + 14, + "renames fields and adds filter type and flags to subscriptions table" +); + +#[async_trait] +impl PostgresMigration for AlterClientFilterInSubscriptionsTable { + async fn up(&self, tx: &mut Transaction) -> Result<()> { + tx.execute( + "ALTER TABLE subscriptions RENAME COLUMN princs_filter_op TO client_filter_op", + &[], + ) + .await?; + tx.execute( + "ALTER TABLE subscriptions RENAME COLUMN princs_filter_value TO client_filter_targets", + &[], + ) + .await?; + tx.execute( + "ALTER TABLE subscriptions ADD COLUMN client_filter_kind TEXT", + &[], + ) + .await?; + tx.execute( + "ALTER TABLE subscriptions ADD COLUMN client_filter_flags INT4", + &[], + ) + .await?; + Ok(()) + } + + async fn down(&self, tx: &mut Transaction) -> Result<()> { + tx.execute( + "ALTER TABLE subscriptions RENAME COLUMN client_filter_op TO princs_filter_op", + &[], + ) + .await?; + tx.execute( + "ALTER TABLE subscriptions RENAME COLUMN client_filter_targets TO princs_filter_value", + &[], + ) + .await?; + tx.execute( + "ALTER TABLE subscriptions DROP COLUMN client_filter_kind", + &[], + ) + .await?; + tx.execute( + "ALTER TABLE subscriptions DROP COLUMN client_filter_flags", + &[], + ) + .await?; + Ok(()) + } +} diff --git a/common/src/database/schema/postgres/_015_add_default_client_filter_kind_in_subscriptions.rs b/common/src/database/schema/postgres/_015_add_default_client_filter_kind_in_subscriptions.rs new file mode 100644 index 00000000..71a00850 --- /dev/null +++ b/common/src/database/schema/postgres/_015_add_default_client_filter_kind_in_subscriptions.rs @@ -0,0 +1,24 @@ +use anyhow::Result; +use async_trait::async_trait; +use deadpool_postgres::Transaction; + +use crate::{database::postgres::PostgresMigration, migration}; + +pub(super) struct AddDefaultClientFilterKindInSubscriptionsTable; +migration!( + AddDefaultClientFilterKindInSubscriptionsTable, + 15, + "add default value of client_filter_kind for previously configured filters" +); + +#[async_trait] +impl PostgresMigration for AddDefaultClientFilterKindInSubscriptionsTable { + async fn up(&self, tx: &mut Transaction) -> Result<()> { + tx.execute("UPDATE subscriptions SET client_filter_kind = 'Client' WHERE client_filter_op IS NOT NULL", &[]).await?; + Ok(()) + } + + async fn down(&self, _tx: &mut Transaction) -> Result<()> { + Ok(()) + } +} diff --git a/common/src/database/schema/postgres/mod.rs b/common/src/database/schema/postgres/mod.rs index 5b12f958..cfe1f85c 100644 --- a/common/src/database/schema/postgres/mod.rs +++ b/common/src/database/schema/postgres/mod.rs @@ -1,6 +1,9 @@ use std::sync::Arc; -use crate::database::postgres::PostgresDatabase; +use crate::database::{ + postgres::PostgresDatabase, + schema::postgres::_015_add_default_client_filter_kind_in_subscriptions::AddDefaultClientFilterKindInSubscriptionsTable, +}; use self::{ _001_create_subscriptions_table::CreateSubscriptionsTable, @@ -16,6 +19,7 @@ use self::{ _011_add_locale_fields_in_subscriptions_table::AddLocaleFieldsInSubscriptionsTable, _012_alter_outputs_files_config::AlterOutputsFilesConfig, _013_add_max_elements_field_in_subscriptions_table::AddMaxElementsFieldInSubscriptionsTable, + _014_alter_client_filter_in_subscriptions::AlterClientFilterInSubscriptionsTable, }; mod _001_create_subscriptions_table; @@ -31,6 +35,8 @@ mod _010_add_revision_field_in_subscriptions_table; mod _011_add_locale_fields_in_subscriptions_table; mod _012_alter_outputs_files_config; mod _013_add_max_elements_field_in_subscriptions_table; +mod _014_alter_client_filter_in_subscriptions; +mod _015_add_default_client_filter_kind_in_subscriptions; pub fn register_migrations(postgres_db: &mut PostgresDatabase) { postgres_db.register_migration(Arc::new(CreateSubscriptionsTable)); @@ -46,4 +52,6 @@ pub fn register_migrations(postgres_db: &mut PostgresDatabase) { postgres_db.register_migration(Arc::new(AddLocaleFieldsInSubscriptionsTable)); postgres_db.register_migration(Arc::new(AlterOutputsFilesConfig)); postgres_db.register_migration(Arc::new(AddMaxElementsFieldInSubscriptionsTable)); + postgres_db.register_migration(Arc::new(AlterClientFilterInSubscriptionsTable)); + postgres_db.register_migration(Arc::new(AddDefaultClientFilterKindInSubscriptionsTable)); } diff --git a/common/src/database/schema/sqlite/_014_alter_client_filter_in_subscriptions.rs b/common/src/database/schema/sqlite/_014_alter_client_filter_in_subscriptions.rs new file mode 100644 index 00000000..b943946e --- /dev/null +++ b/common/src/database/schema/sqlite/_014_alter_client_filter_in_subscriptions.rs @@ -0,0 +1,66 @@ +use anyhow::{anyhow, Result}; +use rusqlite::Connection; + +use crate::database::sqlite::SQLiteMigration; +use crate::migration; + +pub(super) struct AlterClientFilterInSubscriptionsTable; +migration!( + AlterClientFilterInSubscriptionsTable, + 14, + "renames fields and adds filter type and flags to subscriptions table" +); + +impl SQLiteMigration for AlterClientFilterInSubscriptionsTable { + fn up(&self, conn: &Connection) -> Result<()> { + conn.execute( + "ALTER TABLE subscriptions RENAME COLUMN princs_filter_op TO client_filter_op", + [], + ) + .map_err(|err| anyhow!("SQLiteError: {}", err))?; + conn.execute( + "ALTER TABLE subscriptions RENAME COLUMN princs_filter_value TO client_filter_targets", + [], + ) + .map_err(|err| anyhow!("SQLiteError: {}", err))?; + + conn.execute( + "ALTER TABLE subscriptions ADD COLUMN client_filter_kind TEXT", + [], + ) + .map_err(|err| anyhow!("SQLiteError: {}", err))?; + conn.execute("UPDATE subscriptions SET client_filter_kind = 'Client' WHERE client_filter_op IS NOT NULL", []) + .map_err(|err| anyhow!("SQLiteError: {}", err))?; + + conn.execute( + "ALTER TABLE subscriptions ADD COLUMN client_filter_flags INTEGER", + [], + ) + .map_err(|err| anyhow!("SQLiteError: {}", err))?; + Ok(()) + } + + fn down(&self, conn: &Connection) -> Result<()> { + conn.execute( + "ALTER TABLE subscriptions RENAME COLUMN client_filter_op TO princs_filter_op", + [], + ) + .map_err(|err| anyhow!("SQLiteError: {}", err))?; + conn.execute( + "ALTER TABLE subscriptions RENAME COLUMN client_filter_targets TO princs_filter_value", + [], + ) + .map_err(|err| anyhow!("SQLiteError: {}", err))?; + conn.execute( + "ALTER TABLE subscriptions DROP COLUMN client_filter_kind", + [], + ) + .map_err(|err| anyhow!("SQLiteError: {}", err))?; + conn.execute( + "ALTER TABLE subscriptions DROP COLUMN client_filter_flags", + [], + ) + .map_err(|err| anyhow!("SQLiteError: {}", err))?; + Ok(()) + } +} diff --git a/common/src/database/schema/sqlite/mod.rs b/common/src/database/schema/sqlite/mod.rs index c49935c5..5bad7be6 100644 --- a/common/src/database/schema/sqlite/mod.rs +++ b/common/src/database/schema/sqlite/mod.rs @@ -16,6 +16,7 @@ use self::{ _011_add_locale_fields_in_subscriptions_table::AddLocaleFieldsInSubscriptionsTable, _012_alter_outputs_files_config::AlterOutputsFilesConfig, _013_add_max_elements_field_in_subscriptions_table::AddMaxElementsFieldInSubscriptionsTable, + _014_alter_client_filter_in_subscriptions::AlterClientFilterInSubscriptionsTable, }; mod _001_create_subscriptions_table; @@ -31,6 +32,7 @@ mod _010_add_revision_field_in_subscriptions_table; mod _011_add_locale_fields_in_subscriptions_table; mod _012_alter_outputs_files_config; mod _013_add_max_elements_field_in_subscriptions_table; +mod _014_alter_client_filter_in_subscriptions; pub fn register_migrations(sqlite_db: &mut SQLiteDatabase) { sqlite_db.register_migration(Arc::new(CreateSubscriptionsTable)); @@ -46,4 +48,5 @@ pub fn register_migrations(sqlite_db: &mut SQLiteDatabase) { sqlite_db.register_migration(Arc::new(AddLocaleFieldsInSubscriptionsTable)); sqlite_db.register_migration(Arc::new(AlterOutputsFilesConfig)); sqlite_db.register_migration(Arc::new(AddMaxElementsFieldInSubscriptionsTable)); + sqlite_db.register_migration(Arc::new(AlterClientFilterInSubscriptionsTable)); } diff --git a/common/src/database/sqlite.rs b/common/src/database/sqlite.rs index a3d2082f..b253484a 100644 --- a/common/src/database/sqlite.rs +++ b/common/src/database/sqlite.rs @@ -41,7 +41,7 @@ use crate::bookmark::BookmarkData; use crate::database::Database; use crate::heartbeat::{HeartbeatData, HeartbeatsCache}; use crate::subscription::{ - ContentFormat, InternalVersion, PrincsFilter, SubscriptionData, SubscriptionMachine, + ClientFilter, ContentFormat, InternalVersion, SubscriptionData, SubscriptionMachine, SubscriptionMachineState, SubscriptionStatsCounters, SubscriptionUuid, }; @@ -170,10 +170,21 @@ fn row_to_subscription(row: &Row) -> Result { let content_format = ContentFormat::from_str(row.get::<&str, String>("content_format")?.as_ref())?; - let princs_filter = PrincsFilter::from( - row.get("princs_filter_op")?, - row.get("princs_filter_value")?, - )?; + + let client_filter_op: Option = row.get("client_filter_op")?; + + let client_filter = match client_filter_op { + Some(op) => { + let client_filter_kind: Option = row.get("client_filter_kind")?; + Some(ClientFilter::from( + op, + client_filter_kind.unwrap(), + row.get("client_filter_flags")?, + row.get("client_filter_targets")?, + )?) + } + None => None, + }; let mut subscription = SubscriptionData::new(&name, &query); subscription @@ -192,7 +203,7 @@ fn row_to_subscription(row: &Row) -> Result { .set_ignore_channel_error(row.get("ignore_channel_error")?) .set_locale(row.get("locale")?) .set_data_locale(row.get("data_locale")?) - .set_princs_filter(princs_filter) + .set_client_filter(client_filter) .set_outputs(outputs); // This needs to be done at the end because version is updated each time @@ -565,6 +576,15 @@ impl Database for SQLiteDatabase { async fn store_subscription(&self, subscription: &SubscriptionData) -> Result<()> { let subscription = subscription.clone(); + let client_filter_op: Option = subscription + .client_filter() + .map(|f| f.operation().to_string()); + let client_filter_kind = subscription.client_filter().map(|f| f.kind().to_string()); + let client_filter_flags = subscription.client_filter().map(|f| f.flags().bits()); + let client_filter_targets = subscription + .client_filter() + .and_then(|f| f.targets_to_opt_string()); + let count = self .pool .get() @@ -574,12 +594,12 @@ impl Database for SQLiteDatabase { r#"INSERT INTO subscriptions (uuid, version, revision, name, uri, query, heartbeat_interval, connection_retry_count, connection_retry_interval, max_time, max_elements, max_envelope_size, enabled, read_existing_events, content_format, - ignore_channel_error, princs_filter_op, princs_filter_value, outputs, locale, + ignore_channel_error, client_filter_op, client_filter_kind, client_filter_flags, client_filter_targets, outputs, locale, data_locale) VALUES (:uuid, :version, :revision, :name, :uri, :query, :heartbeat_interval, :connection_retry_count, :connection_retry_interval, :max_time, :max_elements, :max_envelope_size, :enabled, :read_existing_events, :content_format, - :ignore_channel_error, :princs_filter_op, :princs_filter_value, :outputs, + :ignore_channel_error, :client_filter_op, :client_filter_kind, :client_filter_flags, :client_filter_targets, :outputs, :locale, :data_locale) ON CONFLICT (uuid) DO UPDATE SET version = excluded.version, @@ -597,8 +617,10 @@ impl Database for SQLiteDatabase { read_existing_events = excluded.read_existing_events, content_format = excluded.content_format, ignore_channel_error = excluded.ignore_channel_error, - princs_filter_op = excluded.princs_filter_op, - princs_filter_value = excluded.princs_filter_value, + client_filter_op = excluded.client_filter_op, + client_filter_kind = excluded.client_filter_kind, + client_filter_flags = excluded.client_filter_flags, + client_filter_targets = excluded.client_filter_targets, outputs = excluded.outputs, locale = excluded.locale, data_locale = excluded.data_locale"#, @@ -619,8 +641,10 @@ impl Database for SQLiteDatabase { ":read_existing_events": subscription.read_existing_events(), ":content_format": subscription.content_format().to_string(), ":ignore_channel_error": subscription.ignore_channel_error(), - ":princs_filter_op": subscription.princs_filter().operation().map(|x| x.to_string()), - ":princs_filter_value": subscription.princs_filter().princs_to_opt_string(), + ":client_filter_op": client_filter_op, + ":client_filter_kind": client_filter_kind, + ":client_filter_flags": client_filter_flags, + ":client_filter_targets": client_filter_targets, ":outputs": serde_json::to_string(subscription.outputs())?, ":locale": subscription.locale(), ":data_locale": subscription.data_locale(), diff --git a/common/src/models/config.rs b/common/src/models/config.rs index 3c6376a7..04d9301b 100644 --- a/common/src/models/config.rs +++ b/common/src/models/config.rs @@ -1,7 +1,10 @@ use std::collections::{HashMap, HashSet}; use anyhow::{bail, Context, Result}; -use serde::Deserialize; +use bitflags::bitflags; +use serde::{Deserialize, Serialize}; +use std::fmt::{Display, Formatter}; +use strum::{AsRefStr, Display, EnumString}; use uuid::Uuid; use crate::{ @@ -200,36 +203,87 @@ impl From for crate::subscription::SubscriptionOutputF } #[derive(Debug, Clone, Eq, PartialEq, Deserialize)] -enum PrincsFilterOperation { +enum ClientFilterOperation { Only, Except, } -impl From for crate::subscription::PrincsFilterOperation { - fn from(value: PrincsFilterOperation) -> Self { +impl From for crate::subscription::ClientFilterOperation { + fn from(value: ClientFilterOperation) -> Self { match value { - PrincsFilterOperation::Except => crate::subscription::PrincsFilterOperation::Except, - PrincsFilterOperation::Only => crate::subscription::PrincsFilterOperation::Only, + ClientFilterOperation::Except => crate::subscription::ClientFilterOperation::Except, + ClientFilterOperation::Only => crate::subscription::ClientFilterOperation::Only, } } } +#[derive( + Default, Debug, Clone, Eq, PartialEq, Serialize, Deserialize, Display, AsRefStr, EnumString, +)] +#[strum(ascii_case_insensitive)] +pub enum ClientFilterKind { + #[default] + Client, + MachineID, +} + +impl From for crate::subscription::ClientFilterKind { + fn from(value: ClientFilterKind) -> Self { + match value { + ClientFilterKind::Client => crate::subscription::ClientFilterKind::Client, + ClientFilterKind::MachineID => crate::subscription::ClientFilterKind::MachineID, + } + } +} + +bitflags! { + #[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] + pub struct ClientFilterFlags: u32 { + const CaseInsensitive = 1 << 0; + const GlobPattern = 1 << 1; + } +} + +impl From for crate::subscription::ClientFilterFlags { + fn from(value: ClientFilterFlags) -> Self { + crate::subscription::ClientFilterFlags::from_bits(value.bits()).unwrap() + } +} + +impl Display for ClientFilterFlags { + fn fmt(&self, f: &mut Formatter) -> std::fmt::Result { + bitflags::parser::to_writer_strict(self, f) + } +} + +impl Default for ClientFilterFlags { + fn default() -> Self { + Self::empty() + } +} + #[derive(Debug, Clone, Eq, PartialEq, Deserialize)] #[serde(deny_unknown_fields)] -struct PrincsFilter { - pub operation: Option, - pub princs: HashSet, +struct ClientFilter { + pub operation: ClientFilterOperation, + #[serde(rename = "type", default)] + pub kind: ClientFilterKind, + #[serde(default)] + pub flags: ClientFilterFlags, + #[serde(alias = "cert_subjects", alias = "princs")] + pub targets: HashSet, } -impl TryFrom for crate::subscription::PrincsFilter { +impl TryFrom for crate::subscription::ClientFilter { type Error = anyhow::Error; - fn try_from(value: PrincsFilter) -> std::prelude::v1::Result { - let mut filter = crate::subscription::PrincsFilter::empty(); - let operation = value.operation.map(|op| op.into()); - filter.set_operation(operation); - filter.set_princs(value.princs)?; - Ok(filter) + fn try_from(value: ClientFilter) -> std::prelude::v1::Result { + crate::subscription::ClientFilter::try_new( + value.operation.into(), + value.kind.into(), + value.flags.into(), + value.targets, + ) } } @@ -320,7 +374,7 @@ struct Subscription { pub version: Uuid, pub name: String, pub query: String, - pub filter: Option, + pub filter: Option, pub outputs: Vec, pub options: Option, } @@ -335,7 +389,7 @@ impl TryFrom for crate::subscription::SubscriptionData { data.set_name(subscription.name.clone()); data.set_query(subscription.query.clone()); if let Some(filter) = subscription.filter { - data.set_princs_filter(filter.try_into()?); + data.set_client_filter(Some(filter.try_into()?)); } if subscription.outputs.is_empty() { @@ -497,7 +551,7 @@ format = "Json" # or "Raw" enabled = true [outputs.config] -path = "/whatever/you/{ip}/want/{principal}/{ip:2}/{node}/end" +path = "/whatever/you/{ip}/want/{client}/{ip:2}/{node}/end" "#; #[test] @@ -532,7 +586,7 @@ path = "/whatever/you/{ip}/want/{principal}/{ip:2}/{node}/end" crate::subscription::SubscriptionOutputFormat::Json, crate::subscription::SubscriptionOutputDriver::Files( crate::subscription::FilesConfiguration::new( - "/tmp/{ip:2}/{ip:3}/{ip}/{principal}/{node}/courgette".to_string(), + "/tmp/{ip:2}/{ip:3}/{ip}/{client}/{node}/courgette".to_string(), ), ), true, @@ -626,7 +680,7 @@ path = "/whatever/you/{ip}/want/{principal}/{ip:2}/{node}/end" crate::subscription::SubscriptionOutputFormat::Json, crate::subscription::SubscriptionOutputDriver::Files( crate::subscription::FilesConfiguration::new( - "/whatever/you/{ip}/want/{principal}/{ip:2}/{node}/end".to_string(), + "/whatever/you/{ip}/want/{client}/{ip:2}/{node}/end".to_string(), ), ), true, @@ -635,14 +689,19 @@ path = "/whatever/you/{ip}/want/{principal}/{ip:2}/{node}/end" expected.set_outputs(outputs); - let mut filter = crate::subscription::PrincsFilter::empty(); - filter.set_operation(Some(crate::subscription::PrincsFilterOperation::Only)); - let mut princs = HashSet::new(); - princs.insert("toto@windomain.local".to_string()); - princs.insert("tutu@windomain.local".to_string()); - filter.set_princs(princs)?; + let mut targets = HashSet::new(); + targets.insert("toto@windomain.local".to_string()); + targets.insert("tutu@windomain.local".to_string()); + let kind = crate::subscription::ClientFilterKind::Client; + let flags = crate::subscription::ClientFilterFlags::empty(); + let filter = crate::subscription::ClientFilter::try_new( + crate::subscription::ClientFilterOperation::Only, + kind, + flags, + targets, + )?; - expected.set_princs_filter(filter); + expected.set_client_filter(Some(filter)); // The only difference between both subscriptions should be the // internal version, so we set both the same value @@ -824,7 +883,7 @@ query = """ [[outputs]] driver = "Files" format = "Raw" -config = { path = "/data/logs/{ip}/{principal}/messages" } +config = { path = "/data/logs/{ip}/{client}/messages" } # Subscription outputs [[outputs]] @@ -867,7 +926,7 @@ config = { topic = "my-kafka-topic", options = { "bootstrap.servers" = "localhos crate::subscription::SubscriptionOutputFormat::Raw, crate::subscription::SubscriptionOutputDriver::Files( crate::subscription::FilesConfiguration::new( - "/data/logs/{ip}/{principal}/messages".to_string(), + "/data/logs/{ip}/{client}/messages".to_string(), ), ), true, @@ -896,4 +955,66 @@ config = { topic = "my-kafka-topic", options = { "bootstrap.servers" = "localhos assert_eq!(data, expected); Ok(()) } + + const CLIENT_FILTER_CONF: &str = r#" +uuid = "28fcc206-1336-4e4a-b76b-18b0ab46e585" +name = "my-test-subscription" +query = "" + +[[outputs]] +driver = "Files" +format = "Raw" +config = { path = "/data/logs/{ip}/{client}/messages" } + +[filter] +operation = "Only" +type = "Client" +flags = "GlobPattern | CaseInsensitive" +targets = ["radis*@REALM"] + + "#; + + #[test] + fn test_client_filter() -> Result<()> { + let mut data = parse(CLIENT_FILTER_CONF, None)?; + + let mut expected = crate::subscription::SubscriptionData::new( + "my-test-subscription", + "", + ); + expected.set_uuid(crate::subscription::SubscriptionUuid(Uuid::from_str( + "28fcc206-1336-4e4a-b76b-18b0ab46e585", + )?)); + + let outputs = vec![crate::subscription::SubscriptionOutput::new( + crate::subscription::SubscriptionOutputFormat::Raw, + crate::subscription::SubscriptionOutputDriver::Files( + crate::subscription::FilesConfiguration::new( + "/data/logs/{ip}/{client}/messages".to_string(), + ), + ), + true, + )]; + + expected.set_outputs(outputs); + + let operation = crate::subscription::ClientFilterOperation::Only; + let kind = crate::subscription::ClientFilterKind::Client; + let flags = crate::subscription::ClientFilterFlags::GlobPattern + | crate::subscription::ClientFilterFlags::CaseInsensitive; + + let mut targets = HashSet::new(); + targets.insert("radis*@REALM".to_string()); + + let filter = crate::subscription::ClientFilter::try_new(operation, kind, flags, targets)?; + expected.set_client_filter(Some(filter)); + + let version = Uuid::new_v4(); + // Must be done last + expected.set_internal_version(crate::subscription::InternalVersion(version.clone())); + data.set_internal_version(crate::subscription::InternalVersion(version.clone())); + + assert_eq!(data, expected); + Ok(()) + } } diff --git a/common/src/models/export.rs b/common/src/models/export.rs index f420d7cc..a9e96a9b 100644 --- a/common/src/models/export.rs +++ b/common/src/models/export.rs @@ -16,10 +16,11 @@ use anyhow::{Context, Result}; enum ImportExport { V1(v1::Subscriptions), V2(v2::Subscriptions), + V3(v3::Subscriptions), } pub fn serialize(subscriptions: &[crate::subscription::SubscriptionData]) -> Result { - let export = ImportExport::V2(subscriptions.into()); + let export = ImportExport::V3(subscriptions.into()); Ok(serde_json::to_string(&export)?) } @@ -32,6 +33,9 @@ pub fn parse(content: &str) -> Result ImportExport::V2(subscriptions) => subscriptions .try_into() .context("Invalid subscription data")?, + ImportExport::V3(subscriptions) => subscriptions + .try_into() + .context("Invalid subscription data")?, }; Ok(subscriptions) } @@ -204,11 +208,11 @@ mod v1 { Except, } - impl From for crate::subscription::PrincsFilterOperation { + impl From for crate::subscription::ClientFilterOperation { fn from(value: PrincsFilterOperation) -> Self { match value { - PrincsFilterOperation::Except => crate::subscription::PrincsFilterOperation::Except, - PrincsFilterOperation::Only => crate::subscription::PrincsFilterOperation::Only, + PrincsFilterOperation::Except => crate::subscription::ClientFilterOperation::Except, + PrincsFilterOperation::Only => crate::subscription::ClientFilterOperation::Only, } } } @@ -219,9 +223,13 @@ mod v1 { pub princs: HashSet, } - impl From for crate::subscription::PrincsFilter { - fn from(value: PrincsFilter) -> Self { - crate::subscription::PrincsFilter::new(value.operation.map(|x| x.into()), value.princs) + impl PrincsFilter { + fn into_client_filter(self) -> Option { + let op = self.operation?; + Some(crate::subscription::ClientFilter::new_legacy( + op.into(), + self.princs, + )) } } @@ -280,7 +288,7 @@ mod v1 { .set_read_existing_events(value.read_existing_events) .set_content_format(value.content_format.into()) .set_ignore_channel_error(value.ignore_channel_error) - .set_princs_filter(value.filter.into()) + .set_client_filter(value.filter.into_client_filter()) .set_locale(value.locale) .set_data_locale(value.data_locale) .set_outputs(outputs?) @@ -567,20 +575,20 @@ pub mod v2 { Except, } - impl From for crate::subscription::PrincsFilterOperation { + impl From for crate::subscription::ClientFilterOperation { fn from(value: PrincsFilterOperation) -> Self { match value { - PrincsFilterOperation::Except => crate::subscription::PrincsFilterOperation::Except, - PrincsFilterOperation::Only => crate::subscription::PrincsFilterOperation::Only, + PrincsFilterOperation::Except => crate::subscription::ClientFilterOperation::Except, + PrincsFilterOperation::Only => crate::subscription::ClientFilterOperation::Only, } } } - impl From for PrincsFilterOperation { - fn from(value: crate::subscription::PrincsFilterOperation) -> Self { + impl From for PrincsFilterOperation { + fn from(value: crate::subscription::ClientFilterOperation) -> Self { match value { - crate::subscription::PrincsFilterOperation::Except => PrincsFilterOperation::Except, - crate::subscription::PrincsFilterOperation::Only => PrincsFilterOperation::Only, + crate::subscription::ClientFilterOperation::Except => PrincsFilterOperation::Except, + crate::subscription::ClientFilterOperation::Only => PrincsFilterOperation::Only, } } } @@ -591,17 +599,23 @@ pub mod v2 { pub princs: HashSet, } - impl From for crate::subscription::PrincsFilter { - fn from(value: PrincsFilter) -> Self { - crate::subscription::PrincsFilter::new(value.operation.map(|x| x.into()), value.princs) + impl PrincsFilter { + fn into_client_filter(self) -> Option { + let op = self.operation?; + Some(crate::subscription::ClientFilter::new_legacy( + op.into(), + self.princs, + )) } } - impl From for PrincsFilter { - fn from(value: crate::subscription::PrincsFilter) -> Self { + impl From> for PrincsFilter { + fn from(value: Option) -> Self { Self { - operation: value.operation().map(|x| x.clone().into()), - princs: value.princs().clone(), + operation: value.as_ref().map(|f| f.operation().clone().into()), + princs: value.map_or(HashSet::new(), |f| { + f.targets().iter().cloned().map(String::from).collect() + }), } } } @@ -672,11 +686,522 @@ pub mod v2 { .set_read_existing_events(value.read_existing_events) .set_content_format(value.content_format.into()) .set_ignore_channel_error(value.ignore_channel_error) - .set_princs_filter(value.filter.into()) + .set_client_filter(value.filter.into_client_filter()) + .set_locale(value.locale) + .set_data_locale(value.data_locale) + .set_outputs(outputs?) + .set_revision(value.revision); + // Note: internal version is not exported nor set + Ok(data) + } + } + + impl From for SubscriptionData { + fn from(value: crate::subscription::SubscriptionData) -> Self { + // Note: internal version is not exported nor set + Self { + uuid: value.uuid().0, + name: value.name().to_string(), + uri: value.uri().cloned(), + revision: value.revision().cloned(), + query: value.query().to_string(), + heartbeat_interval: value.heartbeat_interval(), + connection_retry_count: value.connection_retry_count(), + connection_retry_interval: value.connection_retry_interval(), + max_time: value.max_time(), + max_elements: value.max_elements(), + max_envelope_size: value.max_envelope_size(), + enabled: value.enabled(), + read_existing_events: value.read_existing_events(), + content_format: value.content_format().to_owned().into(), + ignore_channel_error: value.ignore_channel_error(), + locale: value.locale().cloned(), + data_locale: value.data_locale().cloned(), + filter: value.client_filter().cloned().into(), + outputs: value.outputs().iter().map(|o| o.clone().into()).collect(), + } + } + } + + #[derive(Debug, PartialEq, Clone, Eq, Deserialize, Serialize)] + pub(super) struct Subscriptions { + pub subscriptions: Vec, + } + + impl TryFrom for Vec { + type Error = anyhow::Error; + + fn try_from(value: Subscriptions) -> Result { + let subscriptions: Result, _> = value + .subscriptions + .iter() + .map(|s| s.clone().try_into()) + .collect(); + subscriptions + } + } + + impl From<&[crate::subscription::SubscriptionData]> for Subscriptions { + fn from(value: &[crate::subscription::SubscriptionData]) -> Self { + Self { + subscriptions: value.iter().map(|s| s.clone().into()).collect(), + } + } + } +} + +pub mod v3 { + use bitflags::bitflags; + use serde::{Deserialize, Serialize}; + use std::collections::{HashMap, HashSet}; + use std::fmt::{Display, Formatter}; + use strum::{AsRefStr, Display, EnumString}; + use uuid::Uuid; + + #[derive(Debug, Clone, Deserialize, Eq, PartialEq, Serialize)] + pub(super) struct KafkaConfiguration { + pub topic: String, + pub options: HashMap, + } + + // Used for import + impl From for crate::subscription::KafkaConfiguration { + fn from(value: KafkaConfiguration) -> Self { + crate::subscription::KafkaConfiguration::new(value.topic, value.options) + } + } + + // Used for export + impl From for KafkaConfiguration { + fn from(value: crate::subscription::KafkaConfiguration) -> Self { + Self { + topic: value.topic().to_string(), + options: value.options().clone(), + } + } + } + + #[derive(Debug, Clone, Deserialize, Eq, PartialEq, Serialize)] + pub(super) struct RedisConfiguration { + pub addr: String, + pub list: String, + } + + impl From for crate::subscription::RedisConfiguration { + fn from(value: RedisConfiguration) -> Self { + crate::subscription::RedisConfiguration::new(value.addr, value.list) + } + } + + impl From for RedisConfiguration { + fn from(value: crate::subscription::RedisConfiguration) -> Self { + Self { + addr: value.addr().to_string(), + list: value.list().to_string(), + } + } + } + + #[derive(Debug, Clone, Deserialize, Eq, PartialEq, Serialize)] + pub(super) struct TcpConfiguration { + pub addr: String, + pub port: u16, + pub tls_enabled: Option, + #[serde(default)] + pub tls_certificate_authorities: Vec, + pub tls_certificate: Option, + pub tls_key: Option, + } + + impl TryFrom for crate::subscription::TcpConfiguration { + type Error = anyhow::Error; + + fn try_from(value: TcpConfiguration) -> Result { + crate::subscription::TcpConfiguration::new( + value.addr, + value.port, + value.tls_enabled.unwrap_or(false), + value.tls_certificate_authorities, + value.tls_certificate, + value.tls_key, + ) + } + } + + impl From for TcpConfiguration { + fn from(value: crate::subscription::TcpConfiguration) -> Self { + Self { + addr: value.host().to_string(), + port: value.port(), + tls_enabled: Some(value.tls_enabled()), + tls_certificate_authorities: value.tls_certificate_authorities().to_owned(), + tls_certificate: value.tls_certificate().cloned(), + tls_key: value.tls_key().cloned(), + } + } + } + + #[derive(Debug, Clone, Deserialize, Eq, PartialEq, Serialize)] + pub(super) struct FilesConfiguration { + pub path: String, + } + + impl From for crate::subscription::FilesConfiguration { + fn from(value: FilesConfiguration) -> Self { + crate::subscription::FilesConfiguration::new(value.path) + } + } + + impl From for FilesConfiguration { + fn from(value: crate::subscription::FilesConfiguration) -> Self { + Self { + path: value.path().to_owned(), + } + } + } + + #[derive(Debug, Clone, Deserialize, Eq, PartialEq, Serialize)] + pub(super) struct UnixDatagramConfiguration { + pub path: String, + } + + impl From for crate::subscription::UnixDatagramConfiguration { + fn from(value: UnixDatagramConfiguration) -> Self { + crate::subscription::UnixDatagramConfiguration::new(value.path) + } + } + + impl From for UnixDatagramConfiguration { + fn from(value: crate::subscription::UnixDatagramConfiguration) -> Self { + Self { + path: value.path().to_string(), + } + } + } + + #[derive(Debug, Clone, Deserialize, Eq, PartialEq, Serialize)] + pub(super) enum SubscriptionOutputDriver { + Files(FilesConfiguration), + Kafka(KafkaConfiguration), + Tcp(TcpConfiguration), + Redis(RedisConfiguration), + UnixDatagram(UnixDatagramConfiguration), + } + + impl TryFrom for crate::subscription::SubscriptionOutputDriver { + type Error = anyhow::Error; + + fn try_from(value: SubscriptionOutputDriver) -> Result { + Ok(match value { + SubscriptionOutputDriver::Files(config) => { + crate::subscription::SubscriptionOutputDriver::Files(config.into()) + } + SubscriptionOutputDriver::Kafka(config) => { + crate::subscription::SubscriptionOutputDriver::Kafka(config.into()) + } + SubscriptionOutputDriver::Tcp(config) => { + crate::subscription::SubscriptionOutputDriver::Tcp(config.try_into()?) + } + SubscriptionOutputDriver::Redis(config) => { + crate::subscription::SubscriptionOutputDriver::Redis(config.into()) + } + SubscriptionOutputDriver::UnixDatagram(config) => { + crate::subscription::SubscriptionOutputDriver::UnixDatagram(config.into()) + } + }) + } + } + + impl From for SubscriptionOutputDriver { + fn from(value: crate::subscription::SubscriptionOutputDriver) -> Self { + match value { + crate::subscription::SubscriptionOutputDriver::Files(config) => { + SubscriptionOutputDriver::Files(config.into()) + } + crate::subscription::SubscriptionOutputDriver::Kafka(config) => { + SubscriptionOutputDriver::Kafka(config.into()) + } + crate::subscription::SubscriptionOutputDriver::Tcp(config) => { + SubscriptionOutputDriver::Tcp(config.into()) + } + crate::subscription::SubscriptionOutputDriver::Redis(config) => { + SubscriptionOutputDriver::Redis(config.into()) + } + crate::subscription::SubscriptionOutputDriver::UnixDatagram(config) => { + SubscriptionOutputDriver::UnixDatagram(config.into()) + } + } + } + } + + #[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize)] + pub(super) enum SubscriptionOutputFormat { + Json, + Raw, + RawJson, + Nxlog, + } + + impl From for crate::subscription::SubscriptionOutputFormat { + fn from(value: SubscriptionOutputFormat) -> Self { + match value { + SubscriptionOutputFormat::Json => { + crate::subscription::SubscriptionOutputFormat::Json + } + SubscriptionOutputFormat::Raw => crate::subscription::SubscriptionOutputFormat::Raw, + SubscriptionOutputFormat::RawJson => { + crate::subscription::SubscriptionOutputFormat::RawJson + } + SubscriptionOutputFormat::Nxlog => { + crate::subscription::SubscriptionOutputFormat::Nxlog + } + } + } + } + + impl From for SubscriptionOutputFormat { + fn from(value: crate::subscription::SubscriptionOutputFormat) -> Self { + match value { + crate::subscription::SubscriptionOutputFormat::Json => { + SubscriptionOutputFormat::Json + } + crate::subscription::SubscriptionOutputFormat::Raw => SubscriptionOutputFormat::Raw, + crate::subscription::SubscriptionOutputFormat::RawJson => { + SubscriptionOutputFormat::RawJson + } + crate::subscription::SubscriptionOutputFormat::Nxlog => { + SubscriptionOutputFormat::Nxlog + } + } + } + } + + #[derive(Deserialize, Debug, Clone, Eq, PartialEq, Serialize)] + pub(super) struct SubscriptionOutput { + pub format: SubscriptionOutputFormat, + pub driver: SubscriptionOutputDriver, + pub enabled: bool, + } + + impl TryFrom for crate::subscription::SubscriptionOutput { + type Error = anyhow::Error; + + fn try_from(value: SubscriptionOutput) -> Result { + Ok(crate::subscription::SubscriptionOutput::new( + value.format.into(), + value.driver.try_into()?, + value.enabled, + )) + } + } + + impl From for SubscriptionOutput { + fn from(value: crate::subscription::SubscriptionOutput) -> Self { + Self { + format: value.format().clone().into(), + driver: value.driver().clone().into(), + enabled: value.enabled(), + } + } + } + + #[derive(Debug, Clone, Eq, PartialEq, Display, Serialize, Deserialize, EnumString)] + #[strum(serialize_all = "PascalCase", ascii_case_insensitive)] + pub(super) enum ClientFilterOperation { + Only, + Except, + } + + impl From for crate::subscription::ClientFilterOperation { + fn from(value: ClientFilterOperation) -> Self { + match value { + ClientFilterOperation::Except => crate::subscription::ClientFilterOperation::Except, + ClientFilterOperation::Only => crate::subscription::ClientFilterOperation::Only, + } + } + } + + impl From for ClientFilterOperation { + fn from(value: crate::subscription::ClientFilterOperation) -> Self { + match value { + crate::subscription::ClientFilterOperation::Except => ClientFilterOperation::Except, + crate::subscription::ClientFilterOperation::Only => ClientFilterOperation::Only, + } + } + } + + #[derive( + Default, Debug, Clone, Eq, PartialEq, Serialize, Deserialize, Display, AsRefStr, EnumString, + )] + #[strum(ascii_case_insensitive)] + pub(super) enum ClientFilterKind { + #[default] + Client, + MachineID, + } + + impl From for crate::subscription::ClientFilterKind { + fn from(value: ClientFilterKind) -> Self { + match value { + ClientFilterKind::Client => crate::subscription::ClientFilterKind::Client, + ClientFilterKind::MachineID => crate::subscription::ClientFilterKind::MachineID, + } + } + } + + impl From for ClientFilterKind { + fn from(value: crate::subscription::ClientFilterKind) -> Self { + match value { + crate::subscription::ClientFilterKind::Client => ClientFilterKind::Client, + crate::subscription::ClientFilterKind::MachineID => ClientFilterKind::MachineID, + } + } + } + + bitflags! { + #[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] + pub(super) struct ClientFilterFlags: u32 { + const CaseInsensitive = 1 << 0; + const GlobPattern = 1 << 1; + } + } + + impl From for crate::subscription::ClientFilterFlags { + fn from(value: ClientFilterFlags) -> Self { + crate::subscription::ClientFilterFlags::from_bits(value.bits()).unwrap() + } + } + + impl From for ClientFilterFlags { + fn from(value: crate::subscription::ClientFilterFlags) -> Self { + ClientFilterFlags::from_bits(value.bits()).unwrap() + } + } + + impl Display for ClientFilterFlags { + fn fmt(&self, f: &mut Formatter) -> std::fmt::Result { + bitflags::parser::to_writer_strict(self, f) + } + } + + impl Default for ClientFilterFlags { + fn default() -> Self { + Self::empty() + } + } + + #[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] + #[serde(deny_unknown_fields)] + pub(super) struct ClientFilter { + pub operation: ClientFilterOperation, + #[serde(rename = "type", default)] + pub kind: ClientFilterKind, + #[serde(default)] + pub flags: ClientFilterFlags, + #[serde(alias = "cert_subjects", alias = "princs")] + pub targets: HashSet, + } + + impl TryFrom for crate::subscription::ClientFilter { + type Error = anyhow::Error; + + fn try_from(value: ClientFilter) -> std::prelude::v1::Result { + crate::subscription::ClientFilter::try_new( + value.operation.into(), + value.kind.into(), + value.flags.into(), + value.targets, + ) + } + } + + impl From for ClientFilter { + fn from(value: crate::subscription::ClientFilter) -> Self { + Self { + operation: value.operation().clone().into(), + kind: value.kind().clone().into(), + flags: value.flags().clone().into(), + targets: value.targets().iter().cloned().map(String::from).collect(), + } + } + } + + #[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize)] + pub(super) enum ContentFormat { + Raw, + RenderedText, + } + + impl From for crate::subscription::ContentFormat { + fn from(value: ContentFormat) -> Self { + match value { + ContentFormat::Raw => crate::subscription::ContentFormat::Raw, + ContentFormat::RenderedText => crate::subscription::ContentFormat::RenderedText, + } + } + } + + impl From for ContentFormat { + fn from(value: crate::subscription::ContentFormat) -> Self { + match value { + crate::subscription::ContentFormat::Raw => ContentFormat::Raw, + crate::subscription::ContentFormat::RenderedText => ContentFormat::RenderedText, + } + } + } + + #[derive(Debug, PartialEq, Clone, Eq, Deserialize, Serialize)] + pub(super) struct SubscriptionData { + pub uuid: Uuid, + pub revision: Option, + pub name: String, + pub uri: Option, + pub query: String, + pub heartbeat_interval: u32, + pub connection_retry_count: u16, + pub connection_retry_interval: u32, + pub max_time: u32, + pub max_elements: Option, + pub max_envelope_size: u32, + pub enabled: bool, + pub read_existing_events: bool, + pub content_format: ContentFormat, + pub ignore_channel_error: bool, + pub locale: Option, + pub data_locale: Option, + pub filter: Option, + pub outputs: Vec, + } + + impl TryFrom for crate::subscription::SubscriptionData { + type Error = anyhow::Error; + + fn try_from(value: SubscriptionData) -> Result { + let mut data = crate::subscription::SubscriptionData::new(&value.name, &value.query); + let outputs: Result, _> = + value.outputs.iter().map(|s| s.clone().try_into()).collect(); + + data.set_uuid(crate::subscription::SubscriptionUuid(value.uuid)) + .set_uri(value.uri) + .set_heartbeat_interval(value.heartbeat_interval) + .set_connection_retry_count(value.connection_retry_count) + .set_connection_retry_interval(value.connection_retry_interval) + .set_max_time(value.max_time) + .set_max_elements(value.max_elements) + .set_max_envelope_size(value.max_envelope_size) + .set_enabled(value.enabled) + .set_read_existing_events(value.read_existing_events) + .set_content_format(value.content_format.into()) + .set_ignore_channel_error(value.ignore_channel_error) .set_locale(value.locale) .set_data_locale(value.data_locale) .set_outputs(outputs?) .set_revision(value.revision); + + if let Some(filter) = value.filter { + data.set_client_filter(Some(filter.try_into()?)); + } + // Note: internal version is not exported nor set Ok(data) } @@ -703,7 +1228,7 @@ pub mod v2 { ignore_channel_error: value.ignore_channel_error(), locale: value.locale().cloned(), data_locale: value.data_locale().cloned(), - filter: value.princs_filter().clone().into(), + filter: value.client_filter().cloned().map(Into::into), outputs: value.outputs().iter().map(|o| o.clone().into()).collect(), } } @@ -747,9 +1272,9 @@ mod tests { fn test_export_import() -> Result<()> { let mut subscription = crate::subscription::SubscriptionData::new("my-subscription", "my-query"); - let mut princs = HashSet::new(); - princs.insert("courgette@WINDOMAIN.LOCAL".to_string()); - princs.insert("boulette@WINDOMAIN.LOCAL".to_string()); + let mut targets = HashSet::new(); + targets.insert("courgette@WINDOMAIN.LOCAL".to_string()); + targets.insert("boulette@WINDOMAIN.LOCAL".to_string()); subscription .set_content_format(crate::subscription::ContentFormat::RenderedText) @@ -763,10 +1288,12 @@ mod tests { .set_max_elements(Some(100)) .set_read_existing_events(false) .set_uri(Some("toto".to_string())) - .set_princs_filter(crate::subscription::PrincsFilter::new( - Some(crate::subscription::PrincsFilterOperation::Except), - princs, - )) + .set_client_filter(Some(crate::subscription::ClientFilter::try_new( + crate::subscription::ClientFilterOperation::Except, + crate::subscription::ClientFilterKind::Client, + crate::subscription::ClientFilterFlags::empty(), + targets, + )?)) .set_outputs(vec![crate::subscription::SubscriptionOutput::new( crate::subscription::SubscriptionOutputFormat::Json, crate::subscription::SubscriptionOutputDriver::Tcp( diff --git a/common/src/settings.rs b/common/src/settings.rs index 990d80d9..056c42c4 100644 --- a/common/src/settings.rs +++ b/common/src/settings.rs @@ -247,7 +247,7 @@ impl Logging { pub fn access_logs_pattern(&self) -> String { match &self.access_logs_pattern { Some(s) => s.to_owned(), - None => "{X(ip)}:{X(port)} - {X(principal)} [{d}] \"{X(http_uri)}\" {X(http_status)} {X(response_time)}{n}".to_owned() + None => "{X(ip)}:{X(port)} - {X(client)} [{d}] \"{X(http_uri)}\" {X(http_status)} {X(response_time)}{n}".to_owned() } } diff --git a/common/src/subscription.rs b/common/src/subscription.rs index bfcdfb3b..39a43b0f 100644 --- a/common/src/subscription.rs +++ b/common/src/subscription.rs @@ -6,10 +6,12 @@ use std::{ str::FromStr, }; -use anyhow::{anyhow, bail, Result}; -use log::{info, warn}; +use anyhow::{anyhow, bail, Context, Result}; +use bitflags::bitflags; +use glob::Pattern; +use log::info; use serde::{Deserialize, Serialize}; -use strum::{AsRefStr, EnumString, IntoStaticStr, VariantNames}; +use strum::{AsRefStr, Display, EnumString, IntoStaticStr, VariantNames}; use uuid::Uuid; use crate::utils::VersionHasher; @@ -265,121 +267,236 @@ impl SubscriptionOutputFormat { } } -#[derive(Debug, Clone, Eq, PartialEq)] -pub enum PrincsFilterOperation { +#[derive(Debug, Clone, Eq, PartialEq, Display, EnumString)] +#[strum(serialize_all = "PascalCase", ascii_case_insensitive)] +pub enum ClientFilterOperation { Only, Except, } -impl Display for PrincsFilterOperation { +#[derive( + Default, Debug, Clone, Eq, PartialEq, Serialize, Deserialize, Display, AsRefStr, EnumString, +)] +#[strum(ascii_case_insensitive)] +pub enum ClientFilterKind { + #[default] + Client, + MachineID, +} + +bitflags! { + #[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] + pub struct ClientFilterFlags: u32 { + const CaseInsensitive = 1 << 0; + const GlobPattern = 1 << 1; + } +} + +impl Display for ClientFilterFlags { fn fmt(&self, f: &mut Formatter) -> std::fmt::Result { - match self { - PrincsFilterOperation::Only => write!(f, "Only"), - PrincsFilterOperation::Except => write!(f, "Except"), - } + bitflags::parser::to_writer_strict(self, f) } } -impl PrincsFilterOperation { - pub fn opt_from_str(op: &str) -> Result> { - if op.eq_ignore_ascii_case("only") { - Ok(Some(PrincsFilterOperation::Only)) - } else if op.eq_ignore_ascii_case("except") { - Ok(Some(PrincsFilterOperation::Except)) - } else if op.eq_ignore_ascii_case("none") { - Ok(None) - } else { - bail!("Could not parse principal filter operation") - } +impl Default for ClientFilterFlags { + fn default() -> Self { + Self::empty() } } #[derive(Debug, Clone, Eq, PartialEq)] -pub struct PrincsFilter { - operation: Option, - princs: HashSet, +enum ClientFilterTargets { + Exact(HashSet), + Glob(Vec), } -impl PrincsFilter { - pub fn empty() -> Self { - PrincsFilter { - operation: None, - princs: HashSet::new(), +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct ClientFilter { + operation: ClientFilterOperation, + kind: ClientFilterKind, + flags: ClientFilterFlags, + targets: ClientFilterTargets, +} + +impl ClientFilter { + pub fn new_legacy(operation: ClientFilterOperation, targets: HashSet) -> Self { + Self { + operation, + kind: ClientFilterKind::Client, + flags: ClientFilterFlags::empty(), + targets: ClientFilterTargets::Exact(targets), } } - pub fn new(operation: Option, princs: HashSet) -> Self { - Self { operation, princs } + pub fn try_new( + operation: ClientFilterOperation, + kind: ClientFilterKind, + flags: ClientFilterFlags, + mut targets: HashSet, + ) -> Result { + let targets = if flags.contains(ClientFilterFlags::GlobPattern) { + ClientFilterTargets::Glob( + targets + .iter() + .map(|t| Pattern::new(t.as_str())) + .collect::, _>>()?, + ) + } else { + if flags.contains(ClientFilterFlags::CaseInsensitive) { + targets = targets.iter().map(|t| t.to_lowercase()).collect(); + } + ClientFilterTargets::Exact(targets) + }; + + Ok(Self { + operation, + kind, + flags, + targets, + }) } - pub fn from(operation: Option, princs: Option) -> Result { - Ok(PrincsFilter { - operation: match operation { - Some(op) => PrincsFilterOperation::opt_from_str(&op)?, - None => None, - }, - princs: match princs { - Some(p) => HashSet::from_iter(p.split(',').map(|s| s.to_string())), - None => HashSet::new(), - }, + pub fn from( + operation: String, + kind: String, + flags: Option, + targets: Option, + ) -> Result { + let flags = flags.unwrap_or_default(); + let flags = ClientFilterFlags::from_bits(flags) + .context("unknown bits are set in client filter flags")?; + + let mut clients = if flags.contains(ClientFilterFlags::GlobPattern) { + ClientFilterTargets::Glob(Vec::new()) + } else { + ClientFilterTargets::Exact(HashSet::new()) + }; + + if let Some(targets) = targets { + let targets = targets.split(','); + + clients = if flags.contains(ClientFilterFlags::GlobPattern) { + ClientFilterTargets::Glob( + targets + .map(Pattern::new) + .collect::, _>>()?, + ) + } else { + let targets = if flags.contains(ClientFilterFlags::CaseInsensitive) { + HashSet::from_iter(targets.map(|t| t.to_lowercase())) + } else { + HashSet::from_iter(targets.map(|s| s.to_string())) + }; + + ClientFilterTargets::Exact(targets) + }; + } + + Ok(ClientFilter { + operation: operation.parse()?, + kind: kind.parse()?, + flags, + targets: clients, }) } - pub fn princs(&self) -> &HashSet { - &self.princs - } + fn matches(&self, target: &str) -> bool { + match &self.targets { + ClientFilterTargets::Exact(targets) => { + if self.flags.contains(ClientFilterFlags::CaseInsensitive) { + return targets.contains(&target.to_lowercase()); + } - pub fn princs_to_string(&self) -> String { - self.princs() - .iter() - .cloned() - .collect::>() - .join(",") + targets.contains(target) + } + ClientFilterTargets::Glob(targets) => { + let mut match_opts = glob::MatchOptions::new(); + match_opts.case_sensitive = + !self.flags.contains(ClientFilterFlags::CaseInsensitive); + + for p in targets { + if p.matches_with(target, match_opts) { + return true; + } + } + + false + } + } } - pub fn princs_to_opt_string(&self) -> Option { - if self.princs().is_empty() { - None - } else { - Some(self.princs_to_string()) + pub fn eval(&self, client: &str, machine_id: Option<&str>) -> bool { + match self.operation { + ClientFilterOperation::Only => { + let target = match self.kind { + ClientFilterKind::MachineID => { + let Some(machine_id) = machine_id else { + return false; + }; + machine_id + } + _ => client, + }; + self.matches(target) + } + ClientFilterOperation::Except => { + let target = match self.kind { + ClientFilterKind::MachineID => { + let Some(machine_id) = machine_id else { + return true; + }; + machine_id + } + _ => client, + }; + !self.matches(target) + } } } - pub fn add_princ(&mut self, princ: &str) -> Result<()> { - if self.operation.is_none() { - bail!("Could not add a principal to an unset filter") + pub fn targets(&self) -> HashSet<&str> { + match &self.targets { + ClientFilterTargets::Exact(targets) => targets.iter().map(|t| t.as_str()).collect(), + ClientFilterTargets::Glob(targets) => targets.iter().map(|t| t.as_str()).collect(), } - self.princs.insert(princ.to_owned()); - Ok(()) } - pub fn delete_princ(&mut self, princ: &str) -> Result<()> { - if self.operation.is_none() { - bail!("Could not delete a principal of an unset filter") - } - if !self.princs.remove(princ) { - warn!("{} was not present in the principals set", princ) - } - Ok(()) + pub fn targets_to_string(&self) -> String { + self.targets() + .iter() + .cloned() + .map(String::from) + .collect::>() + .join(",") } - pub fn set_princs(&mut self, princs: HashSet) -> Result<()> { - if self.operation.is_none() { - bail!("Could not set principals of an unset filter") + pub fn targets_to_opt_string(&self) -> Option { + match &self.targets { + ClientFilterTargets::Exact(targets) => { + if targets.is_empty() { + return None; + } + } + ClientFilterTargets::Glob(targets) => { + if targets.is_empty() { + return None; + } + } } - self.princs = princs; - Ok(()) + + Some(self.targets_to_string()) } - pub fn operation(&self) -> Option<&PrincsFilterOperation> { - self.operation.as_ref() + pub fn operation(&self) -> &ClientFilterOperation { + &self.operation } - pub fn set_operation(&mut self, operation: Option) { - if operation.is_none() { - self.princs.clear(); - } - self.operation = operation; + pub fn kind(&self) -> &ClientFilterKind { + &self.kind + } + + pub fn flags(&self) -> &ClientFilterFlags { + &self.flags } } @@ -481,8 +598,8 @@ pub struct SubscriptionData { uri: Option, // Enable or disable the subscription enabled: bool, - // Configure which principal can see the subscription - princs_filter: PrincsFilter, + // Configure which client can see the subscription + client_filter: Option, // Public parameters of the subscriptions. This structure is used // to compute the public subscription version sent to clients. parameters: SubscriptionParameters, @@ -560,16 +677,16 @@ impl Display for SubscriptionData { None => "Not configured", } )?; - match self.princs_filter().operation() { + match self.client_filter() { None => { - writeln!(f, "\tPrincipal filter: Not configured")?; + writeln!(f, "\tClient filter: Not configured")?; } - Some(operation) => { + Some(filter) => { writeln!( f, - "\tPrincipal filter: {} the following principals: {}", - operation, - self.princs_filter().princs_to_string(), + "\tClient filter: {} the following targets: {}", + filter.operation(), + filter.targets_to_string(), )?; } } @@ -594,7 +711,7 @@ impl SubscriptionData { revision: None, uri: None, enabled: DEFAULT_ENABLED, - princs_filter: PrincsFilter::empty(), + client_filter: None, outputs: Vec::new(), parameters: SubscriptionParameters { name: name.to_string(), @@ -856,27 +973,25 @@ impl SubscriptionData { self.enabled() && self.outputs().iter().any(|output| output.enabled()) } - pub fn princs_filter(&self) -> &PrincsFilter { - &self.princs_filter + pub fn client_filter(&self) -> Option<&ClientFilter> { + self.client_filter.as_ref() } - pub fn set_princs_filter(&mut self, princs_filter: PrincsFilter) -> &mut Self { - self.princs_filter = princs_filter; + pub fn set_client_filter(&mut self, client_filter: Option) -> &mut Self { + self.client_filter = client_filter; self.update_internal_version(); self } - pub fn is_active_for(&self, principal: &str) -> bool { + pub fn is_active_for(&self, client: &str, machine_id: Option<&str>) -> bool { if !self.is_active() { return false; } - match self.princs_filter().operation { - None => true, - Some(PrincsFilterOperation::Only) => self.princs_filter().princs().contains(principal), - Some(PrincsFilterOperation::Except) => { - !self.princs_filter().princs().contains(principal) - } + if let Some(client_filter) = self.client_filter() { + client_filter.eval(client, machine_id) + } else { + true } } @@ -994,3 +1109,125 @@ impl SubscriptionMachine { self.ip.as_ref() } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_client_filter_operation() { + let mut targets = HashSet::new(); + targets.insert("expected_target".to_string()); + targets.insert("another".to_string()); + + let filter = ClientFilter::try_new( + ClientFilterOperation::Only, + ClientFilterKind::default(), + ClientFilterFlags::default(), + targets.clone(), + ) + .expect("couldn't construct client filter"); + + assert_eq!(*filter.operation(), ClientFilterOperation::Only); + assert!(!filter.eval("expected_target_similar", None)); + assert!(filter.eval("expected_target", None)); + assert!(filter.eval("another", None)); + + let filter = ClientFilter::try_new( + ClientFilterOperation::Except, + ClientFilterKind::default(), + ClientFilterFlags::default(), + targets.clone(), + ) + .expect("couldn't construct client filter"); + + assert_eq!(*filter.operation(), ClientFilterOperation::Except); + assert!(filter.eval("different_target", None)); + assert!(!filter.eval("expected_target", None)); + assert!(!filter.eval("another", None)); + } + + #[test] + fn test_client_filter_types() { + let mut targets = HashSet::new(); + targets.insert("expected_machine".to_string()); + + let filter = ClientFilter::try_new( + ClientFilterOperation::Only, + ClientFilterKind::MachineID, + ClientFilterFlags::default(), + targets.clone(), + ) + .expect("couldn't construct client filter"); + + assert!(!filter.eval("expected_machine", None)); + assert!(!filter.eval("client", Some("unexpected_machine"))); + assert!(filter.eval("client", Some("expected_machine"))); + } + + #[test] + fn test_client_filter_flags() { + let mut targets = HashSet::new(); + targets.insert("eXPected_*".to_string()); + targets.insert("aNother?_target".to_string()); + + let filter = ClientFilter::try_new( + ClientFilterOperation::Only, + ClientFilterKind::default(), + ClientFilterFlags::GlobPattern, + targets, + ) + .expect("couldn't construct client filter"); + + assert!(!filter.eval("expected_target", None)); + assert!(filter.eval("eXPected_", None)); + assert!(filter.eval("eXPected_target", None)); + assert!(!filter.eval("aNother_target", None)); + assert!(!filter.eval("aNother11_target", None)); + assert!(filter.eval("aNother1_target", None)); + assert!(filter.eval("aNother2_target", None)); + + let mut targets = HashSet::new(); + targets.insert("eXPected_*".to_string()); + targets.insert("aNother?_target".to_string()); + + let filter = ClientFilter::try_new( + ClientFilterOperation::Only, + ClientFilterKind::default(), + ClientFilterFlags::GlobPattern | ClientFilterFlags::CaseInsensitive, + targets, + ) + .expect("couldn't construct client filter"); + + assert!(filter.eval("expected_target", None)); + assert!(filter.eval("expected_", None)); + assert!(filter.eval("ExpecteD_target", None)); + assert!(!filter.eval("aNother_target", None)); + assert!(!filter.eval("aNother11_target", None)); + assert!(filter.eval("Another1_target", None)); + assert!(filter.eval("another2_target", None)); + } + + #[test] + fn test_client_filter_from() { + let mut expected_targets = HashSet::new(); + expected_targets.insert("target1"); + expected_targets.insert("target2"); + + let filter = ClientFilter::from( + "only".to_string(), + "Client".to_string(), + Some(0b11), + Some("target1,target2".to_string()), + ) + .expect("couldn't construct client filter"); + + assert_eq!(*filter.operation(), ClientFilterOperation::Only); + assert_eq!(*filter.kind(), ClientFilterKind::Client); + assert_eq!( + *filter.flags(), + ClientFilterFlags::GlobPattern | ClientFilterFlags::CaseInsensitive + ); + assert_eq!(filter.targets(), expected_targets); + } +} diff --git a/common/src/transformers/output_files_use_path.rs b/common/src/transformers/output_files_use_path.rs index fa1edfbe..9a529dd3 100644 --- a/common/src/transformers/output_files_use_path.rs +++ b/common/src/transformers/output_files_use_path.rs @@ -22,7 +22,7 @@ pub fn transform_files_config_to_path( path.push("{ip}") } - path.push("{principal}"); + path.push("{client}"); let append_node_name = append_node_name.unwrap_or(false); if append_node_name { @@ -249,7 +249,7 @@ mod tests { &None, &None )?, - "/base/openwec/{ip}/{principal}/messages".to_string() + "/base/openwec/{ip}/{client}/messages".to_string() ); assert_eq!( @@ -259,7 +259,7 @@ mod tests { &None, &None )?, - "/base/openwec/{ip:1}/{ip:2}/{ip:3}/{ip}/{principal}/messages".to_string() + "/base/openwec/{ip:1}/{ip:2}/{ip:3}/{ip}/{client}/messages".to_string() ); assert_eq!( @@ -269,7 +269,7 @@ mod tests { &None, &None )?, - "/base/openwec/{ip:2}/{ip:3}/{ip}/{principal}/messages".to_string() + "/base/openwec/{ip:2}/{ip:3}/{ip}/{client}/messages".to_string() ); assert_eq!( @@ -279,7 +279,7 @@ mod tests { &None, &None )?, - "/base/openwec/{ip:3}/{ip}/{principal}/messages".to_string() + "/base/openwec/{ip:3}/{ip}/{client}/messages".to_string() ); assert_eq!( @@ -289,7 +289,7 @@ mod tests { &None, &None )?, - "/base/openwec/{ip}/{principal}/messages".to_string() + "/base/openwec/{ip}/{client}/messages".to_string() ); assert_eq!( @@ -299,7 +299,7 @@ mod tests { &Some(false), &None )?, - "/base/openwec/{ip}/{principal}/messages".to_string() + "/base/openwec/{ip}/{client}/messages".to_string() ); assert_eq!( @@ -309,7 +309,7 @@ mod tests { &Some(true), &None )?, - "/base/openwec/{ip}/{principal}/{node}/messages".to_string() + "/base/openwec/{ip}/{client}/{node}/messages".to_string() ); assert_eq!( @@ -319,7 +319,7 @@ mod tests { &Some(true), &Some("test".to_string()) )?, - "/base/openwec/{ip}/{principal}/{node}/test".to_string() + "/base/openwec/{ip}/{client}/{node}/test".to_string() ); Ok(()) diff --git a/doc/docker.md b/doc/docker.md index 8fdfaeb7..4edbcb76 100644 --- a/doc/docker.md +++ b/doc/docker.md @@ -104,7 +104,7 @@ query = """ [[outputs]] driver = "Files" format = "Raw" -config = { path = "/var/lib/openwec/data/simple/{ip}/{principal}/messages" } +config = { path = "/var/lib/openwec/data/simple/{ip}/{client}/messages" } ``` - `test`: ```toml @@ -130,7 +130,7 @@ content_format = "RenderedText" [[outputs]] driver = "Files" format = "RawJson" -config = { path = "/var/lib/openwec/data/test/{ip}/{principal}/messages" } +config = { path = "/var/lib/openwec/data/test/{ip}/{client}/messages" } ``` You should end up with the following tree structure: diff --git a/doc/formats.md b/doc/formats.md index 9d877d0b..6042ae8f 100644 --- a/doc/formats.md +++ b/doc/formats.md @@ -13,7 +13,7 @@ The XML schema is defined in the Windows SDK (see [event.xsd](event.xsd)). ## Json Raw format OpenWEC can add useful metadata to events, such as: -- The Windows client principal that sent an event +- The Windows client identifier that sent an event - The Windows client IP address that sent an event - The time when the event was received - the OpenWEC subscription that received the event @@ -61,7 +61,7 @@ openwec_data := { Using this format, raw XML events are parsed and then serialized using Json. -In addition, OpenWEC adds some data that may be useful: the Windows client IP address, its principal, the time when the event was received and the OpenWEC subscription. +In addition, OpenWEC adds some data that may be useful: the Windows client IP address, its identifier (Kerberos Principal or TLS subject), the time when the event was received and the OpenWEC subscription. The JSON document generated uses the following structure: ```json diff --git a/doc/getting_started.md b/doc/getting_started.md index cb94974f..eba50455 100644 --- a/doc/getting_started.md +++ b/doc/getting_started.md @@ -106,11 +106,11 @@ In this example, let's say we want to retrieve every events in *Security*, *Syst ### Outputs In this example, we want to: -- store events in `Raw` format in files in the path `/data/logs///messages`, where `` is the IP address of the machine who sent the log messages and `` its Kerberos principal +- store events in `Raw` format in files in the path `/data/logs///messages`, where `` is the IP address of the machine who sent the log messages and `` its identifier (Kerberos Principal) - send events in `RawJson` format in a Kafka topic (`my-kafka-topic`) on `localhost:9092` for further processing We need to configure two outputs: -- one using the `Files` driver and the `Raw` format with path `/data/logs/{ip}/{principal}/messages` +- one using the `Files` driver and the `Raw` format with path `/data/logs/{ip}/{client}/messages` - one using the `Kafka` driver and the `RawJson` format with topic `my-kafka-topic` and option `bootstrap-servers=localhost:9092` ### Configuration file @@ -153,7 +153,7 @@ query = """ [[outputs]] driver = "Files" format = "Raw" -config = { path = "/data/logs/{ip}/{principal}/messages" } +config = { path = "/data/logs/{ip}/{client}/messages" } # Subscription outputs [[outputs]] diff --git a/doc/how_it_works.md b/doc/how_it_works.md index c2c38d57..78aab164 100644 --- a/doc/how_it_works.md +++ b/doc/how_it_works.md @@ -34,7 +34,7 @@ Each output is composed of two elements: a **driver** and a **format**. Drivers answer the question "*what should openwec do with collected events*". Currently there are several supported drivers: -* `Files`: Events are stored in files. You must specify a path that can contain variables such as the IP of the client or its Kerberos principal. +* `Files`: Events are stored in files. You must specify a path that can contain variables such as the IP of the client or its identifier. * `TCP`: Events are sent to a TCP server. You must specify a host and port. * `Kafka`: Events are sent in a Kafka topic. You need to specify the name of the Kafka topic and the usual Kafka settings such as *bootstrap servers*. * `UnixDatagram`: Events are sent in a Unix domain socket. @@ -44,8 +44,8 @@ Currently there are several supported drivers: The OpenWEC server can parse each event and format it. There are several formatters available: * `Raw`: as its name suggests, it does nothing to the events. It just writes raw XML data. *Warning: each event may contain EOL characters which are neither filtered nor transformed*. -* `Json`: format events in Json. Json schema is documented [there](formats.md). When using the `Json` formatter, OpenWEC parses XML events and is able to add useful data such as the Kerberos principal or the IP address that sent the event. -* `RawJson`: encapsulates the raw XML data in a json document. OpenWEC does not parse the XML event, but can still add useful metadata such as the Kerberos principal or the IP address that sent the event. +* `Json`: format events in Json. Json schema is documented [there](formats.md). When using the `Json` formatter, OpenWEC parses XML events and is able to add useful data such as the identifier or the IP address of the client that sent the event. +* `RawJson`: encapsulates the raw XML data in a json document. OpenWEC does not parse the XML event, but can still add useful metadata such as the identifier or the IP address of the client that sent the event. * `Nxlog`: format events in Json which mimics the output of the `im_msvistalog` module of Nxlog. ## Bookmarks diff --git a/doc/outputs.md b/doc/outputs.md index 04d862b0..b54621df 100644 --- a/doc/outputs.md +++ b/doc/outputs.md @@ -32,7 +32,7 @@ Available variables are: |:----:|-----------------| | `ip` | The Windows client IP address | | `ip:` | The Windows client IP address until the ``-th separator where `` is an integer between 1 and 4.
- `ip:2` would transform `127.0.0.1` into `127.0`
- `ip:3` would transform `192.168.2.1` into `192.168.2`
- `ip:4` would transform `2001:0:130F:0:0:9C0:876A:130B` into `2001:0:130F:0`. -| `principal` | The Kerberos principal of the Windows client. Because this principal is used to build a path, all the characters that do not match `[a-zA-Z0-9.\-_@]` are deleted. | +| `client` | The identifier of the Windows client. Depending on authentication method used, it can be either its Kerberos Principal or its TLS subject name. Because this identifier is used to build a path, all the characters that do not match `[a-zA-Z0-9.\-_@]` are deleted. | | `node` | The OpenWEC node's name which is configured in OpenWEC setting `server.node_name`. If the node does not have a name, the string `{node}` is left unchanged and a warning is generated. | The `Files` driver uses a unique thread (even if there are multiple instances of the driver) to write files. This thread maintains a hash table which contains every opened file descriptors. A garbage collector is run regularly (see `outputs.garbage_collect_interval` setting) to close the file descriptors that have not been used in a while (see `outputs.files.file_descriptors_close_timeout`). @@ -46,10 +46,10 @@ You may want to tell OpenWEC to close all its file descriptors and to open them | **Path** | **Description** | |----------|-----------------| | `/var/events/forwarded.log` | Store events in `/var/events/forwarded.log` -| `/var/events/{ip}/{principal}/messages` | Store events in `/var/events///messages` -| `/var/events/{ip:3}/{ip}/{principal}/messages` | With ` = A.B.C.D`, store events in `/var/events/A.B.C/A.B.C.D//messages` -| `/var/events/{ip:2}/{ip:3}/{ip}/{principal}/my-events` | With ` = A.B.C.D`, store events in `/var/events/A.B/A.B.C/A.B.C.D//my-events` -| `/var/events/{ip:1}/{ip:2}/{ip:3}/{ip}/{principal}/{node}/my-events` | With ` = A.B.C.D`, store events in `/var/events/A/A.B/A.B.C/A.B.C.D///my-events` +| `/var/events/{ip}/{client}/messages` | Store events in `/var/events///messages` +| `/var/events/{ip:3}/{ip}/{client}/messages` | With ` = A.B.C.D`, store events in `/var/events/A.B.C/A.B.C.D//messages` +| `/var/events/{ip:2}/{ip:3}/{ip}/{client}/my-events` | With ` = A.B.C.D`, store events in `/var/events/A.B/A.B.C/A.B.C.D//my-events` +| `/var/events/{ip:1}/{ip:2}/{ip:3}/{ip}/{client}/{node}/my-events` | With ` = A.B.C.D`, store events in `/var/events/A/A.B/A.B.C/A.B.C.D///my-events` #### Configuration @@ -211,7 +211,7 @@ This command prints the current outputs of the subscription. ``` $ openwec subscriptions edit my-subscription outputs -0: Enabled: true, Format: Json, Driver: Files(FilesConfiguration { path: "/var/events/{ip}/{principal}/messages" }) +0: Enabled: true, Format: Json, Driver: Files(FilesConfiguration { path: "/var/events/{ip}/{client}/messages" }) 1: Enabled: true, Format: Json, Driver: Tcp(dc.windomain.local:12000) ``` diff --git a/doc/subscription.md b/doc/subscription.md index dec00776..16e5c0b7 100644 --- a/doc/subscription.md +++ b/doc/subscription.md @@ -69,25 +69,36 @@ In its configuration UI, Microsoft WEC enables users to choose between three eve In its documentation, Microsoft states that Normal mode uses a Pull delivery mode (meaning that its the collector who connects to Windows machines and retrieve their event logs). It seems to be a mistake, as the exported configuration of a subscription configured in Normal mode clearly specifies that it is SourceInitiated in Push mode. -## Principals filter +## Client filter -It is possible to filter the client Kerberos principals that can see a subscription. The comparison is **case-sensitive**. +It is possible to filter the clients that can see a subscription. -There are three filtering modes: -* `None` (default): no filtering based on Kerberos principal -* `Only [princ, ...]`: the subscription will only be shown to the listed principals -* `Except [princ, ...]`: the subscription will be shown to everyone except the listed principals +### Filtering modes: +* `Only`: the subscription will only be shown to the listed clients +* `Except`: the subscription will be shown to everyone except the listed clients -The principals filter can be configured using openwec cli: -* `openwec subscriptions edit filter set [princ, ...]` configures the principals filter. -* `openwec subscriptions edit filter princs {add,delete,set} [princ, ...]` manages the principals in the filter. +### Filtering types: +* `Client`: the filter will be evaluated on client identifier, either Kerberos principal if Kerberos authentication is used or TLS certificate's subject field if TLS authentication is used. +* `MachineID`: the filtering is done based on the name of the computer (`System.Computer`) +The default is `Client`. + +> [!warning] +> `MachineID` is not cryptographically authenticated information, it can be spoofed. +> For more info, see [Hunting rogue Windows Event Forwarder](issues.md#hunting-rogue-windows-event-forwarder). + +### Filtering flags: +* `GlobPattern`: Glob patterns like `*` and `?` can be used in `targets` +* `CaseInsensitive`: Filter matching will be case-insensitive + +Flags are composable using the `|` operator. +The comparison is **case-sensitive** by default. ## Configuration There are two methods available to configure subscriptions: - using configuration files (recommended) -- using the `openwec` command line interface (`openwec subscriptions`) +- using the `openwec` command line interface (`openwec subscriptions`) (deprecated) ## Configuration Files @@ -111,7 +122,7 @@ query = """ [[outputs]] driver = "Files" format = "Raw" -config = { path = "/var/log/openwec/{ip}/{principal}/messages" } +config = { path = "/var/log/openwec/{ip}/{client}/messages" } ``` Note: `uuid` and `name` must be unique for each subscription. @@ -238,7 +249,7 @@ Subscription my-super-subscription ReadExistingEvents: false ContentFormat: Raw IgnoreChannelError: true - Principal filter: Not configured + Client filter: Not configured Outputs: Not configured Enabled: false @@ -285,7 +296,7 @@ Subscription this-is-a-clone ReadExistingEvents: false ContentFormat: Raw IgnoreChannelError: true - Principal filter: Not configured + Client filter: Not configured Outputs: None Enabled: false @@ -352,7 +363,7 @@ $ openwec subscriptions delete windows-subscription Are you sure that you want to delete "windows-subscription" (92A7836D-96FC-4EE5-9E45-03D0618607DE) ? [y/n] y ``` -### `openwec subscriptions machines` +### `openwec subscriptions clients` This command enables you to retrieve the list of clients attached to a subscription. @@ -363,7 +374,7 @@ You may filter on status: If you only want numbers, check `openwec stats` command. -The output format is `:`. +The output format is `:`. #### Usage diff --git a/openwec.conf.sample.toml b/openwec.conf.sample.toml index 167a60af..16f7d9ae 100644 --- a/openwec.conf.sample.toml +++ b/openwec.conf.sample.toml @@ -109,10 +109,10 @@ # - response_time (in ms) # - ip # - port -# - principal +# - client # - conn_status: 'X' (connection aborted before the response completed) # '+' (connection may be kept alive after the response is sent) -# Default value is None, meaning "{X(ip)}:{X(port)} - {X(principal)} [{d}] \"{X(http_uri)}\" {X(http_status)} {X(response_time)}{n}" +# Default value is None, meaning "{X(ip)}:{X(port)} - {X(client)} [{d}] \"{X(http_uri)}\" {X(http_status)} {X(response_time)}{n}" # access_logs_pattern = None ########################## diff --git a/server/Cargo.toml b/server/Cargo.toml index 86676b2f..2e1e1e3b 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -46,7 +46,7 @@ log-mdc = "0.1.0" tokio-util = "0.7.10" thiserror = "2.0.11" hyper-util = { version = "0.1", features = ["full"] } -socket2 = "0.5.6" +socket2 = "0.6.0" http-body-util = "0.1" ppp = "2.2.0" tokio-rustls = "0.26.0" diff --git a/server/src/drivers/files.rs b/server/src/drivers/files.rs index ff2849ec..fce5bd1e 100644 --- a/server/src/drivers/files.rs +++ b/server/src/drivers/files.rs @@ -254,8 +254,8 @@ impl leon::Values for PathValues { fn get_value(&self, key: &str) -> Option> { if key == "ip" { Some(Cow::from(self.metadata.addr().ip().to_string())) - } else if key == "principal" { - Some(sanitize_name(self.metadata.principal()).into()) + } else if key == "principal" || key == "client" { + Some(sanitize_name(self.metadata.client()).into()) } else if key == "node" { if let Some(node_name) = self.metadata.node_name() { Some(node_name.as_str().into()) @@ -437,6 +437,7 @@ mod tests { #[tokio::test] async fn test_build_path() -> Result<()> { + // {principal} is kept for compatibility let config = FilesConfiguration::new("/base/{ip}/{principal}/messages".to_string()); let ip: IpAddr = "127.0.0.1".parse()?; @@ -471,8 +472,7 @@ mod tests { PathBuf::from_str("/base/127/127.0/127.0.0/127.0.0.1/node/messages")? ); - let config = - FilesConfiguration::new("/base/{ip:2}/{ip:3}/{ip}/{principal}/other".to_string()); + let config = FilesConfiguration::new("/base/{ip:2}/{ip:3}/{ip}/{client}/other".to_string()); let output_file = OutputFiles::new(&config, &context)?; assert_eq!( @@ -488,7 +488,7 @@ mod tests { PathBuf::from_str("/base/127.0.0/127.0.0.1/messages")? ); - let config = FilesConfiguration::new("/base/{ip:4}/{principal}/messages".to_string()); + let config = FilesConfiguration::new("/base/{ip:4}/{client}/messages".to_string()); let output_file = OutputFiles::new(&config, &context)?; assert_eq!( @@ -529,7 +529,7 @@ mod tests { ); let event_metadata_without_node = create_event_metadata(ip, "COMPUTER$@REALM", None); - let config = FilesConfiguration::new("/base/{principal}/messages".to_string()); + let config = FilesConfiguration::new("/base/{client}/messages".to_string()); let output_file = OutputFiles::new(&config, &context)?; assert_eq!( output_file.build_path(&event_metadata_without_node)?, diff --git a/server/src/event.rs b/server/src/event.rs index d1bf4ff1..16ced3ba 100644 --- a/server/src/event.rs +++ b/server/src/event.rs @@ -499,7 +499,7 @@ impl RenderingInfo { pub struct EventMetadata { // TODO : add authentication method (TLS or Kerberos) addr: SocketAddr, - principal: String, + client: String, node_name: Option, time_received: DateTime, subscription_uuid: String, @@ -513,7 +513,7 @@ pub struct EventMetadata { impl EventMetadata { pub fn new( addr: &SocketAddr, - principal: &str, + client: &str, node_name: Option, subscription: &Subscription, public_version: String, @@ -521,7 +521,7 @@ impl EventMetadata { ) -> Self { EventMetadata { addr: *addr, - principal: principal.to_owned(), + client: client.to_owned(), node_name, time_received: Utc::now(), subscription_uuid: subscription.data().uuid_string(), @@ -543,8 +543,8 @@ impl EventMetadata { self.addr } - pub fn principal(&self) -> &str { - self.principal.as_ref() + pub fn client(&self) -> &str { + self.client.as_ref() } pub fn node_name(&self) -> Option<&String> { diff --git a/server/src/formats/json.rs b/server/src/formats/json.rs index 814adc3c..6e62babc 100644 --- a/server/src/formats/json.rs +++ b/server/src/formats/json.rs @@ -227,8 +227,11 @@ struct Additional { addr: String, #[serde(rename = "TimeReceived")] time_received: String, + // deprecated, will disappear at some point #[serde(rename = "Principal")] principal: String, + #[serde(rename = "Client")] + client: String, #[serde(rename = "Subscription")] subscription: SubscriptionType, #[serde(rename = "Node", skip_serializing_if = "Option::is_none")] @@ -241,7 +244,8 @@ impl Additional { pub fn new(additional: crate::event::Additional, metadata: &EventMetadata) -> Self { Self { addr: metadata.addr().ip().to_string(), - principal: metadata.principal().to_owned(), // TODO : change to something that works for TLS as well (modify db and output) + principal: metadata.client().to_owned(), + client: metadata.client().to_owned(), node: metadata.node_name().cloned(), time_received: metadata.time_received().to_rfc3339(), subscription: SubscriptionType { @@ -495,7 +499,7 @@ Type 1 is a full token with no privileges removed or groups disabled. A full to Type 2 is an elevated token with no privileges removed or groups disabled. An elevated token is used when User Account Control is enabled and the user chooses to start the program using Run as administrator. An elevated token is also used when an application is configured to always require administrative privilege or to always require maximum privilege, and the user is a member of the Administrators group. Type 3 is a limited token with administrative privileges removed and administrative groups disabled. The limited token is used when User Account Control is enabled, the application does not require administrative privilege, and the user does not choose to start the program using Run as administrator.InformationProcess CreationInfoSecurityMicrosoft Windows security auditing.Audit Success"#; - const EVENT_4688_JSON: &str = r#"{"System":{"Provider":{"Name":"Microsoft-Windows-Security-Auditing","Guid":"{54849625-5478-4994-a5ba-3e3b0328c30d}"},"EventID":4688,"Version":2,"Level":0,"Task":13312,"Opcode":0,"Keywords":"0x8020000000000000","TimeCreated":"2022-12-14T16:06:51.0643605Z","EventRecordID":114689,"Correlation":{},"Execution":{"ProcessID":4,"ThreadID":196},"Channel":"Security","Computer":"win10.windomain.local"},"EventData":{"SubjectLogonId":"0x3e7","SubjectUserName":"WIN10$","SubjectDomainName":"WINDOMAIN","ParentProcessName":"C:\\Windows\\System32\\services.exe","MandatoryLabel":"S-1-16-16384","SubjectUserSid":"S-1-5-18","NewProcessName":"C:\\Program Files (x86)\\Microsoft\\EdgeUpdate\\MicrosoftEdgeUpdate.exe","TokenElevationType":"%%1936","TargetUserSid":"S-1-0-0","TargetDomainName":"-","CommandLine":"","TargetUserName":"-","NewProcessId":"0x3a8","TargetLogonId":"0x0","ProcessId":"0x240"},"RenderingInfo":{"Message":"A new process has been created.\n\nCreator Subject:\n\tSecurity ID:\t\tS-1-5-18\n\tAccount Name:\t\tWIN10$\n\tAccount Domain:\t\tWINDOMAIN\n\tLogon ID:\t\t0x3E7\n\nTarget Subject:\n\tSecurity ID:\t\tS-1-0-0\n\tAccount Name:\t\t-\n\tAccount Domain:\t\t-\n\tLogon ID:\t\t0x0\n\nProcess Information:\n\tNew Process ID:\t\t0x3a8\n\tNew Process Name:\tC:\\Program Files (x86)\\Microsoft\\EdgeUpdate\\MicrosoftEdgeUpdate.exe\n\tToken Elevation Type:\t%%1936\n\tMandatory Label:\t\tS-1-16-16384\n\tCreator Process ID:\t0x240\n\tCreator Process Name:\tC:\\Windows\\System32\\services.exe\n\tProcess Command Line:\t\n\nToken Elevation Type indicates the type of token that was assigned to the new process in accordance with User Account Control policy.\n\nType 1 is a full token with no privileges removed or groups disabled. A full token is only used if User Account Control is disabled or if the user is the built-in Administrator account or a service account.\n\nType 2 is an elevated token with no privileges removed or groups disabled. An elevated token is used when User Account Control is enabled and the user chooses to start the program using Run as administrator. An elevated token is also used when an application is configured to always require administrative privilege or to always require maximum privilege, and the user is a member of the Administrators group.\n\nType 3 is a limited token with administrative privileges removed and administrative groups disabled. The limited token is used when User Account Control is enabled, the application does not require administrative privilege, and the user does not choose to start the program using Run as administrator.","Level":"Information","Task":"Process Creation","Opcode":"Info","Channel":"Security","Provider":"Microsoft Windows security auditing.","Keywords":["Audit Success"],"Culture":"en-US"},"OpenWEC":{"IpAddress":"192.168.58.100","TimeReceived":"2022-12-14T16:07:03.331+00:00","Principal":"WIN10$@WINDOMAIN.LOCAL","Node":"openwec","Subscription":{"Uuid":"8B18D83D-2964-4F35-AC3B-6F4E6FFA727B","Version":"188BB736-9441-5C66-188B-B73694415C66","Name":"Test","Uri":"/this/is/a/test","ClientRevision":"1234","ServerRevision":"babar"}}}"#; + const EVENT_4688_JSON: &str = r#"{"System":{"Provider":{"Name":"Microsoft-Windows-Security-Auditing","Guid":"{54849625-5478-4994-a5ba-3e3b0328c30d}"},"EventID":4688,"Version":2,"Level":0,"Task":13312,"Opcode":0,"Keywords":"0x8020000000000000","TimeCreated":"2022-12-14T16:06:51.0643605Z","EventRecordID":114689,"Correlation":{},"Execution":{"ProcessID":4,"ThreadID":196},"Channel":"Security","Computer":"win10.windomain.local"},"EventData":{"SubjectLogonId":"0x3e7","SubjectUserName":"WIN10$","SubjectDomainName":"WINDOMAIN","ParentProcessName":"C:\\Windows\\System32\\services.exe","MandatoryLabel":"S-1-16-16384","SubjectUserSid":"S-1-5-18","NewProcessName":"C:\\Program Files (x86)\\Microsoft\\EdgeUpdate\\MicrosoftEdgeUpdate.exe","TokenElevationType":"%%1936","TargetUserSid":"S-1-0-0","TargetDomainName":"-","CommandLine":"","TargetUserName":"-","NewProcessId":"0x3a8","TargetLogonId":"0x0","ProcessId":"0x240"},"RenderingInfo":{"Message":"A new process has been created.\n\nCreator Subject:\n\tSecurity ID:\t\tS-1-5-18\n\tAccount Name:\t\tWIN10$\n\tAccount Domain:\t\tWINDOMAIN\n\tLogon ID:\t\t0x3E7\n\nTarget Subject:\n\tSecurity ID:\t\tS-1-0-0\n\tAccount Name:\t\t-\n\tAccount Domain:\t\t-\n\tLogon ID:\t\t0x0\n\nProcess Information:\n\tNew Process ID:\t\t0x3a8\n\tNew Process Name:\tC:\\Program Files (x86)\\Microsoft\\EdgeUpdate\\MicrosoftEdgeUpdate.exe\n\tToken Elevation Type:\t%%1936\n\tMandatory Label:\t\tS-1-16-16384\n\tCreator Process ID:\t0x240\n\tCreator Process Name:\tC:\\Windows\\System32\\services.exe\n\tProcess Command Line:\t\n\nToken Elevation Type indicates the type of token that was assigned to the new process in accordance with User Account Control policy.\n\nType 1 is a full token with no privileges removed or groups disabled. A full token is only used if User Account Control is disabled or if the user is the built-in Administrator account or a service account.\n\nType 2 is an elevated token with no privileges removed or groups disabled. An elevated token is used when User Account Control is enabled and the user chooses to start the program using Run as administrator. An elevated token is also used when an application is configured to always require administrative privilege or to always require maximum privilege, and the user is a member of the Administrators group.\n\nType 3 is a limited token with administrative privileges removed and administrative groups disabled. The limited token is used when User Account Control is enabled, the application does not require administrative privilege, and the user does not choose to start the program using Run as administrator.","Level":"Information","Task":"Process Creation","Opcode":"Info","Channel":"Security","Provider":"Microsoft Windows security auditing.","Keywords":["Audit Success"],"Culture":"en-US"},"OpenWEC":{"IpAddress":"192.168.58.100","TimeReceived":"2022-12-14T16:07:03.331+00:00","Principal":"WIN10$@WINDOMAIN.LOCAL","Client":"WIN10$@WINDOMAIN.LOCAL","Node":"openwec","Subscription":{"Uuid":"8B18D83D-2964-4F35-AC3B-6F4E6FFA727B","Version":"188BB736-9441-5C66-188B-B73694415C66","Name":"Test","Uri":"/this/is/a/test","ClientRevision":"1234","ServerRevision":"babar"}}}"#; #[test] fn test_serialize_4688_event_data() { @@ -549,7 +553,7 @@ Licensing Status= InformationMicrosoft-Windows-Security-SPPClassic "#; - const EVENT_1003_JSON: &str = r#"{"System":{"Provider":{"Name":"Microsoft-Windows-Security-SPP","Guid":"{E23B33B0-C8C9-472C-A5F9-F2BDFEA0F156}","EventSourceName":"Software Protection Platform Service"},"EventID":1003,"EventIDQualifiers":16384,"Version":0,"Level":4,"Task":0,"Opcode":0,"Keywords":"0x80000000000000","TimeCreated":"2022-12-14T16:05:59.7074374Z","EventRecordID":7603,"Correlation":{},"Execution":{"ProcessID":0,"ThreadID":0},"Channel":"Application","Computer":"win10.windomain.local"},"EventData":{"Data":["55c92734-d682-4d71-983e-d6ec3f16059f","\n1: 3f4c0546-36c6-46a8-a37f-be13cdd0cf25, 1, 1 [(0 [0xC004E003, 0, 0], [( 9 0xC004FC07 90 0)( 1 0x00000000)(?)( 2 0x00000000 0 0 msft:rm/algorithm/hwid/4.0 0x00000000 0)(?)( 9 0xC004FC07 90 0)( 10 0x00000000 msft:rm/algorithm/flags/1.0)(?)])(1 )(2 )(3 [0x00000000, 0, 0], [( 6 0xC004F009 0 0)( 1 0x00000000)( 6 0xC004F009 0 0)(?)(?)(?)( 10 0x00000000 msft:rm/algorithm/flags/1.0)( 11 0x00000000 0xC004FC07)])]\n\n"]},"RenderingInfo":{"Message":"The Software Protection service has completed licensing status check.\nApplication Id=55c92734-d682-4d71-983e-d6ec3f16059f\nLicensing Status=\n1: 3f4c0546-36c6-46a8-a37f-be13cdd0cf25, 1, 1 [(0 [0xC004E003, 0, 0], [( 9 0xC004FC07 90 0)( 1 0x00000000)(?)( 2 0x00000000 0 0 msft:rm/algorithm/hwid/4.0 0x00000000 0)(?)( 9 0xC004FC07 90 0)( 10 0x00000000 msft:rm/algorithm/flags/1.0)(?)])(1 )(2 )(3 [0x00000000, 0, 0], [( 6 0xC004F009 0 0)( 1 0x00000000)( 6 0xC004F009 0 0)(?)(?)(?)( 10 0x00000000 msft:rm/algorithm/flags/1.0)( 11 0x00000000 0xC004FC07)])]\n\n","Level":"Information","Provider":"Microsoft-Windows-Security-SPP","Keywords":["Classic"],"Culture":"en-US"},"OpenWEC":{"IpAddress":"192.168.58.100","TimeReceived":"2022-12-14T16:07:03.324+00:00","Principal":"WIN10$@WINDOMAIN.LOCAL","Node":"openwec","Subscription":{"Uuid":"8B18D83D-2964-4F35-AC3B-6F4E6FFA727B","Version":"188BB736-9441-5C66-188B-B73694415C66","Name":"Test"}}}"#; + const EVENT_1003_JSON: &str = r#"{"System":{"Provider":{"Name":"Microsoft-Windows-Security-SPP","Guid":"{E23B33B0-C8C9-472C-A5F9-F2BDFEA0F156}","EventSourceName":"Software Protection Platform Service"},"EventID":1003,"EventIDQualifiers":16384,"Version":0,"Level":4,"Task":0,"Opcode":0,"Keywords":"0x80000000000000","TimeCreated":"2022-12-14T16:05:59.7074374Z","EventRecordID":7603,"Correlation":{},"Execution":{"ProcessID":0,"ThreadID":0},"Channel":"Application","Computer":"win10.windomain.local"},"EventData":{"Data":["55c92734-d682-4d71-983e-d6ec3f16059f","\n1: 3f4c0546-36c6-46a8-a37f-be13cdd0cf25, 1, 1 [(0 [0xC004E003, 0, 0], [( 9 0xC004FC07 90 0)( 1 0x00000000)(?)( 2 0x00000000 0 0 msft:rm/algorithm/hwid/4.0 0x00000000 0)(?)( 9 0xC004FC07 90 0)( 10 0x00000000 msft:rm/algorithm/flags/1.0)(?)])(1 )(2 )(3 [0x00000000, 0, 0], [( 6 0xC004F009 0 0)( 1 0x00000000)( 6 0xC004F009 0 0)(?)(?)(?)( 10 0x00000000 msft:rm/algorithm/flags/1.0)( 11 0x00000000 0xC004FC07)])]\n\n"]},"RenderingInfo":{"Message":"The Software Protection service has completed licensing status check.\nApplication Id=55c92734-d682-4d71-983e-d6ec3f16059f\nLicensing Status=\n1: 3f4c0546-36c6-46a8-a37f-be13cdd0cf25, 1, 1 [(0 [0xC004E003, 0, 0], [( 9 0xC004FC07 90 0)( 1 0x00000000)(?)( 2 0x00000000 0 0 msft:rm/algorithm/hwid/4.0 0x00000000 0)(?)( 9 0xC004FC07 90 0)( 10 0x00000000 msft:rm/algorithm/flags/1.0)(?)])(1 )(2 )(3 [0x00000000, 0, 0], [( 6 0xC004F009 0 0)( 1 0x00000000)( 6 0xC004F009 0 0)(?)(?)(?)( 10 0x00000000 msft:rm/algorithm/flags/1.0)( 11 0x00000000 0xC004FC07)])]\n\n","Level":"Information","Provider":"Microsoft-Windows-Security-SPP","Keywords":["Classic"],"Culture":"en-US"},"OpenWEC":{"IpAddress":"192.168.58.100","TimeReceived":"2022-12-14T16:07:03.324+00:00","Principal":"WIN10$@WINDOMAIN.LOCAL","Client":"WIN10$@WINDOMAIN.LOCAL","Node":"openwec","Subscription":{"Uuid":"8B18D83D-2964-4F35-AC3B-6F4E6FFA727B","Version":"188BB736-9441-5C66-188B-B73694415C66","Name":"Test"}}}"#; #[test] fn test_serialize_1003_event_data_unamed() { @@ -592,7 +596,7 @@ This may lead to authentication problems. Make sure that this computer is connec ADDITIONAL INFO If this computer is a domain controller for the specified domain, it sets up the secure session to the primary domain controller emulator in the specified domain. Otherwise, this computer sets up the secure session to any domain controller in the specified domain.ErrorInfoClassic"#; - const EVENT_5719_JSON: &str = r#"{"System":{"Provider":{"Name":"NETLOGON"},"EventID":5719,"EventIDQualifiers":0,"Version":0,"Level":2,"Task":0,"Opcode":0,"Keywords":"0x80000000000000","TimeCreated":"2022-12-14T16:04:59.0817047Z","EventRecordID":9466,"Correlation":{},"Execution":{"ProcessID":0,"ThreadID":0},"Channel":"System","Computer":"win10.windomain.local"},"EventData":{"Data":["WINDOMAIN","%%1311"],"Binary":"5E0000C0"},"RenderingInfo":{"Message":"This computer was not able to set up a secure session with a domain controller in domain WINDOMAIN due to the following:\nWe can't sign you in with this credential because your domain isn't available. Make sure your device is connected to your organization's network and try again. If you previously signed in on this device with another credential, you can sign in with that credential.\nThis may lead to authentication problems. Make sure that this computer is connected to the network. If the problem persists, please contact your domain administrator.\n\nADDITIONAL INFO\nIf this computer is a domain controller for the specified domain, it sets up the secure session to the primary domain controller emulator in the specified domain. Otherwise, this computer sets up the secure session to any domain controller in the specified domain.","Level":"Error","Opcode":"Info","Keywords":["Classic"],"Culture":"en-US"},"OpenWEC":{"IpAddress":"192.168.58.100","TimeReceived":"2022-12-14T16:07:02.919+00:00","Principal":"WIN10$@WINDOMAIN.LOCAL","Node":"openwec","Subscription":{"Uuid":"8B18D83D-2964-4F35-AC3B-6F4E6FFA727B","Version":"188BB736-9441-5C66-188B-B73694415C66","Name":"Test","Uri":"/this/is/a/test","ServerRevision":"babar","ClientRevision": "babar"}}}"#; + const EVENT_5719_JSON: &str = r#"{"System":{"Provider":{"Name":"NETLOGON"},"EventID":5719,"EventIDQualifiers":0,"Version":0,"Level":2,"Task":0,"Opcode":0,"Keywords":"0x80000000000000","TimeCreated":"2022-12-14T16:04:59.0817047Z","EventRecordID":9466,"Correlation":{},"Execution":{"ProcessID":0,"ThreadID":0},"Channel":"System","Computer":"win10.windomain.local"},"EventData":{"Data":["WINDOMAIN","%%1311"],"Binary":"5E0000C0"},"RenderingInfo":{"Message":"This computer was not able to set up a secure session with a domain controller in domain WINDOMAIN due to the following:\nWe can't sign you in with this credential because your domain isn't available. Make sure your device is connected to your organization's network and try again. If you previously signed in on this device with another credential, you can sign in with that credential.\nThis may lead to authentication problems. Make sure that this computer is connected to the network. If the problem persists, please contact your domain administrator.\n\nADDITIONAL INFO\nIf this computer is a domain controller for the specified domain, it sets up the secure session to the primary domain controller emulator in the specified domain. Otherwise, this computer sets up the secure session to any domain controller in the specified domain.","Level":"Error","Opcode":"Info","Keywords":["Classic"],"Culture":"en-US"},"OpenWEC":{"IpAddress":"192.168.58.100","TimeReceived":"2022-12-14T16:07:02.919+00:00","Principal":"WIN10$@WINDOMAIN.LOCAL","Client":"WIN10$@WINDOMAIN.LOCAL","Node":"openwec","Subscription":{"Uuid":"8B18D83D-2964-4F35-AC3B-6F4E6FFA727B","Version":"188BB736-9441-5C66-188B-B73694415C66","Name":"Test","Uri":"/this/is/a/test","ServerRevision":"babar","ClientRevision": "babar"}}}"#; #[test] fn test_serialize_5719_event_data_binary() { @@ -633,7 +637,7 @@ If this computer is a domain controller for the specified domain, it sets up the } const EVENT_6013: &str = r#"601304000x800000000000009427Systemwin10.windomain.local6600 Coordinated Universal Time31002E003100000030000000570069006E0064006F0077007300200031003000200045006E007400650072007000720069007300650020004500760061006C0075006100740069006F006E000000310030002E0030002E003100390030003400330020004200750069006C0064002000310039003000340033002000200000004D0075006C0074006900700072006F0063006500730073006F007200200046007200650065000000310039003000340031002E00760062005F00720065006C0065006100730065002E003100390031003200300036002D00310034003000360000003600320031003400640066003100630000004E006F007400200041007600610069006C00610062006C00650000004E006F007400200041007600610069006C00610062006C00650000003900000031000000320030003400380000003400300039000000770069006E00310030002E00770069006E0064006F006D00610069006E002E006C006F00630061006C0000000000The system uptime is 6 seconds.InformationClassic"#; - const EVENT_6013_JSON: &str = r#"{"System":{"Provider":{"Name":"EventLog"},"EventID":6013,"EventIDQualifiers":32768,"Version":0,"Level":4,"Task":0,"Opcode":0,"Keywords":"0x80000000000000","TimeCreated":"2022-12-14T16:04:43.7965565Z","EventRecordID":9427,"Correlation":{},"Execution":{"ProcessID":0,"ThreadID":0},"Channel":"System","Computer":"win10.windomain.local"},"EventData":{"Data":["6","60","0 Coordinated Universal Time"],"Binary":"31002E003100000030000000570069006E0064006F0077007300200031003000200045006E007400650072007000720069007300650020004500760061006C0075006100740069006F006E000000310030002E0030002E003100390030003400330020004200750069006C0064002000310039003000340033002000200000004D0075006C0074006900700072006F0063006500730073006F007200200046007200650065000000310039003000340031002E00760062005F00720065006C0065006100730065002E003100390031003200300036002D00310034003000360000003600320031003400640066003100630000004E006F007400200041007600610069006C00610062006C00650000004E006F007400200041007600610069006C00610062006C00650000003900000031000000320030003400380000003400300039000000770069006E00310030002E00770069006E0064006F006D00610069006E002E006C006F00630061006C0000000000"},"RenderingInfo":{"Message":"The system uptime is 6 seconds.","Level":"Information","Keywords":["Classic"],"Culture":"en-US"},"OpenWEC":{"IpAddress":"192.168.58.100","TimeReceived":"2022-12-14T16:07:02.524+00:00","Principal":"WIN10$@WINDOMAIN.LOCAL","Subscription":{"Uuid":"8B18D83D-2964-4F35-AC3B-6F4E6FFA727B","Version":"188BB736-9441-5C66-188B-B73694415C66","Name":"Test","Uri":"/this/is/a/test"}}}"#; + const EVENT_6013_JSON: &str = r#"{"System":{"Provider":{"Name":"EventLog"},"EventID":6013,"EventIDQualifiers":32768,"Version":0,"Level":4,"Task":0,"Opcode":0,"Keywords":"0x80000000000000","TimeCreated":"2022-12-14T16:04:43.7965565Z","EventRecordID":9427,"Correlation":{},"Execution":{"ProcessID":0,"ThreadID":0},"Channel":"System","Computer":"win10.windomain.local"},"EventData":{"Data":["6","60","0 Coordinated Universal Time"],"Binary":"31002E003100000030000000570069006E0064006F0077007300200031003000200045006E007400650072007000720069007300650020004500760061006C0075006100740069006F006E000000310030002E0030002E003100390030003400330020004200750069006C0064002000310039003000340033002000200000004D0075006C0074006900700072006F0063006500730073006F007200200046007200650065000000310039003000340031002E00760062005F00720065006C0065006100730065002E003100390031003200300036002D00310034003000360000003600320031003400640066003100630000004E006F007400200041007600610069006C00610062006C00650000004E006F007400200041007600610069006C00610062006C00650000003900000031000000320030003400380000003400300039000000770069006E00310030002E00770069006E0064006F006D00610069006E002E006C006F00630061006C0000000000"},"RenderingInfo":{"Message":"The system uptime is 6 seconds.","Level":"Information","Keywords":["Classic"],"Culture":"en-US"},"OpenWEC":{"IpAddress":"192.168.58.100","TimeReceived":"2022-12-14T16:07:02.524+00:00","Principal":"WIN10$@WINDOMAIN.LOCAL","Client":"WIN10$@WINDOMAIN.LOCAL","Subscription":{"Uuid":"8B18D83D-2964-4F35-AC3B-6F4E6FFA727B","Version":"188BB736-9441-5C66-188B-B73694415C66","Name":"Test","Uri":"/this/is/a/test"}}}"#; #[test] fn test_serialize_6013_event_data_unamed_empty() { @@ -673,7 +677,7 @@ If this computer is a domain controller for the specified domain, it sets up the } const EVENT_1100: &str = r#"11000410300x4020000000000000114371Securitywin10.windomain.localThe event logging service has shut down.InformationService shutdownInfoSecurityMicrosoft-Windows-EventlogAudit Success"#; - const EVENT_1100_JSON: &str = r#"{"System":{"Provider":{"Name":"Microsoft-Windows-Eventlog","Guid":"{fc65ddd8-d6ef-4962-83d5-6e5cfe9ce148}"},"EventID":1100,"Version":0,"Level":4,"Task":103,"Opcode":0,"Keywords":"0x4020000000000000","TimeCreated":"2022-12-14T14:39:07.1686183Z","EventRecordID":114371,"Correlation":{},"Execution":{"ProcessID":496,"ThreadID":204},"Channel":"Security","Computer":"win10.windomain.local"},"UserData":"","RenderingInfo":{"Message":"The event logging service has shut down.","Level":"Information","Task":"Service shutdown","Opcode":"Info","Channel":"Security","Provider":"Microsoft-Windows-Eventlog","Keywords":["Audit Success"],"Culture":"en-US"},"OpenWEC":{"IpAddress":"192.168.58.100","TimeReceived":"2022-12-14T16:07:02.156+00:00","Principal":"WIN10$@WINDOMAIN.LOCAL","Node":"openwec","Subscription":{"Uuid":"8B18D83D-2964-4F35-AC3B-6F4E6FFA727B","Version":"188BB736-9441-5C66-188B-B73694415C66","Name":"Test","Uri":"/this/is/a/test"}}}"#; + const EVENT_1100_JSON: &str = r#"{"System":{"Provider":{"Name":"Microsoft-Windows-Eventlog","Guid":"{fc65ddd8-d6ef-4962-83d5-6e5cfe9ce148}"},"EventID":1100,"Version":0,"Level":4,"Task":103,"Opcode":0,"Keywords":"0x4020000000000000","TimeCreated":"2022-12-14T14:39:07.1686183Z","EventRecordID":114371,"Correlation":{},"Execution":{"ProcessID":496,"ThreadID":204},"Channel":"Security","Computer":"win10.windomain.local"},"UserData":"","RenderingInfo":{"Message":"The event logging service has shut down.","Level":"Information","Task":"Service shutdown","Opcode":"Info","Channel":"Security","Provider":"Microsoft-Windows-Eventlog","Keywords":["Audit Success"],"Culture":"en-US"},"OpenWEC":{"IpAddress":"192.168.58.100","TimeReceived":"2022-12-14T16:07:02.156+00:00","Principal":"WIN10$@WINDOMAIN.LOCAL","Client":"WIN10$@WINDOMAIN.LOCAL","Node":"openwec","Subscription":{"Uuid":"8B18D83D-2964-4F35-AC3B-6F4E6FFA727B","Version":"188BB736-9441-5C66-188B-B73694415C66","Name":"Test","Uri":"/this/is/a/test"}}}"#; #[test] fn test_serialize_1100_user_data() { @@ -713,7 +717,7 @@ If this computer is a domain controller for the specified domain, it sets up the } const EVENT_111: &str = r#"111win10.windomain.local"#; - const EVENT_111_JSON: &str = r#"{"System":{"Provider":{"Name":"Microsoft-Windows-EventForwarder"},"EventID":111,"TimeCreated":"2023-02-14T09:14:23.175Z","Computer":"win10.windomain.local"},"OpenWEC":{"IpAddress":"192.168.58.100","TimeReceived":"2022-12-14T16:07:02.156+00:00","Principal":"WIN10$@WINDOMAIN.LOCAL","Node":"other_node","Subscription":{"Uuid":"8B18D83D-2964-4F35-AC3B-6F4E6FFA727B","Version":"188BB736-9441-5C66-188B-B73694415C66","Name":"Test","Uri":"/this/is/a/test"}}}"#; + const EVENT_111_JSON: &str = r#"{"System":{"Provider":{"Name":"Microsoft-Windows-EventForwarder"},"EventID":111,"TimeCreated":"2023-02-14T09:14:23.175Z","Computer":"win10.windomain.local"},"OpenWEC":{"IpAddress":"192.168.58.100","TimeReceived":"2022-12-14T16:07:02.156+00:00","Principal":"WIN10$@WINDOMAIN.LOCAL","Client":"WIN10$@WINDOMAIN.LOCAL","Node":"other_node","Subscription":{"Uuid":"8B18D83D-2964-4F35-AC3B-6F4E6FFA727B","Version":"188BB736-9441-5C66-188B-B73694415C66","Name":"Test","Uri":"/this/is/a/test"}}}"#; #[test] fn test_serialize_111() { diff --git a/server/src/formats/nxlog.rs b/server/src/formats/nxlog.rs index 09a5e8b8..df982a05 100644 --- a/server/src/formats/nxlog.rs +++ b/server/src/formats/nxlog.rs @@ -260,8 +260,11 @@ struct Additional { addr: String, #[serde(rename = "TimeReceived")] time_received: String, + // deprecated, will disappear at some point #[serde(rename = "Principal")] principal: String, + #[serde(rename = "Client")] + client: String, #[serde(rename = "Subscription")] subscription: SubscriptionType, #[serde(rename = "Node", skip_serializing_if = "Option::is_none")] @@ -274,7 +277,8 @@ impl Additional { pub fn new(additional: crate::event::Additional, metadata: &EventMetadata) -> Self { Self { addr: metadata.addr().ip().to_string(), - principal: metadata.principal().to_owned(), // TODO : change to something that works for TLS as well (modify db and output) + principal: metadata.client().to_owned(), + client: metadata.client().to_owned(), node: metadata.node_name().cloned(), time_received: metadata.time_received().to_rfc3339(), subscription: SubscriptionType { @@ -597,7 +601,7 @@ mod tests { } const EVENT_4624: &str = r#"4624301254400x80200000000000001446SecurityWKS10001S-1-5-18WKS10001$WORKGROUP0x3e7S-1-5-21-1430380458-3079459327-630937868-1001userWKS100010x615a442User32 NegotiateWKS10001{00000000-0000-0000-0000-000000000000}--00x5c8C:\Windows\System32\svchost.exe127.0.0.10%%1833----%%18430x615a61%%1842An account was successfully logged on. Subject: Security ID: S-1-5-18 Account Name: WKS10001$ Account Domain: WORKGROUP Logon ID: 0x3E7 Logon Information: Logon Type: 2 Restricted Admin Mode: - Remote Credential Guard: - Virtual Account: No Elevated Token: Yes Impersonation Level: Impersonation New Logon: Security ID: S-1-5-21-1430380458-3079459327-630937868-1001 Account Name: user Account Domain: WKS10001 Logon ID: 0x615A44 Linked Logon ID: 0x615A61 Network Account Name: - Network Account Domain: - Logon GUID: {00000000-0000-0000-0000-000000000000} Process Information: Process ID: 0x5c8 Process Name: C:\Windows\System32\svchost.exe Network Information: Workstation Name: WKS10001 Source Network Address: 127.0.0.1 Source Port: 0 Detailed Authentication Information: Logon Process: User32 Authentication Package: Negotiate Transited Services: - Package Name (NTLM only): - Key Length: 0 This event is generated when a logon session is created. It is generated on the computer that was accessed. The subject fields indicate the account on the local system which requested the logon. This is most commonly a service such as the Server service, or a local process such as Winlogon.exe or Services.exe. The logon type field indicates the kind of logon that occurred. The most common types are 2 (interactive) and 3 (network). The New Logon fields indicate the account for whom the new logon was created, i.e. the account that was logged on. The network fields indicate where a remote logon request originated. Workstation name is not always available and may be left blank in some cases. The impersonation level field indicates the extent to which a process in the logon session can impersonate. The authentication information fields provide detailed information about this specific logon request. - Logon GUID is a unique identifier that can be used to correlate this event with a KDC event. - Transited services indicate which intermediate services have participated in this logon request. - Package name indicates which sub-protocol was used among the NTLM protocols. - Key length indicates the length of the generated session key. This will be 0 if no session key was requested.InformationLogonInfoSecurityMicrosoft Windows security auditing.Audit Success "#; - const EVENT_4624_JSON: &str = r#"{"EventTime":"2024-03-14T13:54:19.3628662Z","Hostname":"WKS10001","Keywords":-9214364837600034816,"EventType":"AUDIT_SUCCESS","SeverityValue":2,"Severity":"INFO","EventID":4624,"SourceName":"Microsoft-Windows-Security-Auditing","ProviderGuid":"{54849625-5478-4994-A5BA-3E3B0328C30D}","Version":3,"Task":12544,"OpcodeValue":0,"RecordNumber":1446,"ActivityID":"{B073A4BF-7611-0000-BCA5-73B01176DA01}","ProcessID":780,"ThreadID":2832,"Channel":"Security","Message":"An account was successfully logged on.\r\n\r\nSubject:\r\n\tSecurity ID:\t\tS-1-5-18\r\n\tAccount Name:\t\tWKS10001$\r\n\tAccount Domain:\t\tWORKGROUP\r\n\tLogon ID:\t\t0x3E7\r\n\r\nLogon Information:\r\n\tLogon Type:\t\t2\r\n\tRestricted Admin Mode:\t-\r\n\tRemote Credential Guard:\t-\r\n\tVirtual Account:\t\tNo\r\n\tElevated Token:\t\tYes\r\n\r\nImpersonation Level:\t\tImpersonation\r\n\r\nNew Logon:\r\n\tSecurity ID:\t\tS-1-5-21-1430380458-3079459327-630937868-1001\r\n\tAccount Name:\t\tuser\r\n\tAccount Domain:\t\tWKS10001\r\n\tLogon ID:\t\t0x615A44\r\n\tLinked Logon ID:\t\t0x615A61\r\n\tNetwork Account Name:\t-\r\n\tNetwork Account Domain:\t-\r\n\tLogon GUID:\t\t{00000000-0000-0000-0000-000000000000}\r\n\r\nProcess Information:\r\n\tProcess ID:\t\t0x5c8\r\n\tProcess Name:\t\tC:\\Windows\\System32\\svchost.exe\r\n\r\nNetwork Information:\r\n\tWorkstation Name:\tWKS10001\r\n\tSource Network Address:\t127.0.0.1\r\n\tSource Port:\t\t0\r\n\r\nDetailed Authentication Information:\r\n\tLogon Process:\t\tUser32 \r\n\tAuthentication Package:\tNegotiate\r\n\tTransited Services:\t-\r\n\tPackage Name (NTLM only):\t-\r\n\tKey Length:\t\t0\r\n\r\nThis event is generated when a logon session is created. It is generated on the computer that was accessed.\r\n\r\nThe subject fields indicate the account on the local system which requested the logon. This is most commonly a service such as the Server service, or a local process such as Winlogon.exe or Services.exe.\r\n\r\nThe logon type field indicates the kind of logon that occurred. The most common types are 2 (interactive) and 3 (network).\r\n\r\nThe New Logon fields indicate the account for whom the new logon was created, i.e. the account that was logged on.\r\n\r\nThe network fields indicate where a remote logon request originated. Workstation name is not always available and may be left blank in some cases.\r\n\r\nThe impersonation level field indicates the extent to which a process in the logon session can impersonate.\r\n\r\nThe authentication information fields provide detailed information about this specific logon request.\r\n\t- Logon GUID is a unique identifier that can be used to correlate this event with a KDC event.\r\n\t- Transited services indicate which intermediate services have participated in this logon request.\r\n\t- Package name indicates which sub-protocol was used among the NTLM protocols.\r\n\t- Key length indicates the length of the generated session key. This will be 0 if no session key was requested.","Category":"Logon","Opcode":"Info","SubjectUserSid":"S-1-5-18","SubjectUserName":"WKS10001$","SubjectDomainName":"WORKGROUP","SubjectLogonId":"0x3e7","TargetUserSid":"S-1-5-21-1430380458-3079459327-630937868-1001","TargetUserName":"user","TargetDomainName":"WKS10001","TargetLogonId":"0x615a44","LogonType":"2","LogonProcessName":"User32 ","AuthenticationPackageName":"Negotiate","WorkstationName":"WKS10001","LogonGuid":"{00000000-0000-0000-0000-000000000000}","TransmittedServices":"-","LmPackageName":"-","KeyLength":"0","ProcessName":"C:\\Windows\\System32\\svchost.exe","IpAddress":"127.0.0.1","IpPort":"0","ImpersonationLevel":"%%1833","RestrictedAdminMode":"-","RemoteCredentialGuard":"-","TargetOutboundUserName":"-","TargetOutboundDomainName":"-","VirtualAccount":"%%1843","TargetLinkedLogonId":"0x615a61","ElevatedToken":"%%1842","EventReceivedTime":"2024-03-14T13:54:20.331+00:00","OpenWEC":{"IpAddress":"192.168.58.100","TimeReceived":"2024-03-14T13:54:20.331+00:00","Principal":"WIN10$@WINDOMAIN.LOCAL","Subscription":{"Uuid":"8B18D83D-2964-4F35-AC3B-6F4E6FFA727B","Version":"188BB736-9441-5C66-188B-B73694415C66","Name":"Test","Uri":"/this/is/a/test","ServerRevision":"BABAR","ClientRevision":"TOTO"},"Node":"openwec"}, "ProcessId": "0x5c8"}"#; + const EVENT_4624_JSON: &str = r#"{"EventTime":"2024-03-14T13:54:19.3628662Z","Hostname":"WKS10001","Keywords":-9214364837600034816,"EventType":"AUDIT_SUCCESS","SeverityValue":2,"Severity":"INFO","EventID":4624,"SourceName":"Microsoft-Windows-Security-Auditing","ProviderGuid":"{54849625-5478-4994-A5BA-3E3B0328C30D}","Version":3,"Task":12544,"OpcodeValue":0,"RecordNumber":1446,"ActivityID":"{B073A4BF-7611-0000-BCA5-73B01176DA01}","ProcessID":780,"ThreadID":2832,"Channel":"Security","Message":"An account was successfully logged on.\r\n\r\nSubject:\r\n\tSecurity ID:\t\tS-1-5-18\r\n\tAccount Name:\t\tWKS10001$\r\n\tAccount Domain:\t\tWORKGROUP\r\n\tLogon ID:\t\t0x3E7\r\n\r\nLogon Information:\r\n\tLogon Type:\t\t2\r\n\tRestricted Admin Mode:\t-\r\n\tRemote Credential Guard:\t-\r\n\tVirtual Account:\t\tNo\r\n\tElevated Token:\t\tYes\r\n\r\nImpersonation Level:\t\tImpersonation\r\n\r\nNew Logon:\r\n\tSecurity ID:\t\tS-1-5-21-1430380458-3079459327-630937868-1001\r\n\tAccount Name:\t\tuser\r\n\tAccount Domain:\t\tWKS10001\r\n\tLogon ID:\t\t0x615A44\r\n\tLinked Logon ID:\t\t0x615A61\r\n\tNetwork Account Name:\t-\r\n\tNetwork Account Domain:\t-\r\n\tLogon GUID:\t\t{00000000-0000-0000-0000-000000000000}\r\n\r\nProcess Information:\r\n\tProcess ID:\t\t0x5c8\r\n\tProcess Name:\t\tC:\\Windows\\System32\\svchost.exe\r\n\r\nNetwork Information:\r\n\tWorkstation Name:\tWKS10001\r\n\tSource Network Address:\t127.0.0.1\r\n\tSource Port:\t\t0\r\n\r\nDetailed Authentication Information:\r\n\tLogon Process:\t\tUser32 \r\n\tAuthentication Package:\tNegotiate\r\n\tTransited Services:\t-\r\n\tPackage Name (NTLM only):\t-\r\n\tKey Length:\t\t0\r\n\r\nThis event is generated when a logon session is created. It is generated on the computer that was accessed.\r\n\r\nThe subject fields indicate the account on the local system which requested the logon. This is most commonly a service such as the Server service, or a local process such as Winlogon.exe or Services.exe.\r\n\r\nThe logon type field indicates the kind of logon that occurred. The most common types are 2 (interactive) and 3 (network).\r\n\r\nThe New Logon fields indicate the account for whom the new logon was created, i.e. the account that was logged on.\r\n\r\nThe network fields indicate where a remote logon request originated. Workstation name is not always available and may be left blank in some cases.\r\n\r\nThe impersonation level field indicates the extent to which a process in the logon session can impersonate.\r\n\r\nThe authentication information fields provide detailed information about this specific logon request.\r\n\t- Logon GUID is a unique identifier that can be used to correlate this event with a KDC event.\r\n\t- Transited services indicate which intermediate services have participated in this logon request.\r\n\t- Package name indicates which sub-protocol was used among the NTLM protocols.\r\n\t- Key length indicates the length of the generated session key. This will be 0 if no session key was requested.","Category":"Logon","Opcode":"Info","SubjectUserSid":"S-1-5-18","SubjectUserName":"WKS10001$","SubjectDomainName":"WORKGROUP","SubjectLogonId":"0x3e7","TargetUserSid":"S-1-5-21-1430380458-3079459327-630937868-1001","TargetUserName":"user","TargetDomainName":"WKS10001","TargetLogonId":"0x615a44","LogonType":"2","LogonProcessName":"User32 ","AuthenticationPackageName":"Negotiate","WorkstationName":"WKS10001","LogonGuid":"{00000000-0000-0000-0000-000000000000}","TransmittedServices":"-","LmPackageName":"-","KeyLength":"0","ProcessName":"C:\\Windows\\System32\\svchost.exe","IpAddress":"127.0.0.1","IpPort":"0","ImpersonationLevel":"%%1833","RestrictedAdminMode":"-","RemoteCredentialGuard":"-","TargetOutboundUserName":"-","TargetOutboundDomainName":"-","VirtualAccount":"%%1843","TargetLinkedLogonId":"0x615a61","ElevatedToken":"%%1842","EventReceivedTime":"2024-03-14T13:54:20.331+00:00","OpenWEC":{"IpAddress":"192.168.58.100","TimeReceived":"2024-03-14T13:54:20.331+00:00","Principal":"WIN10$@WINDOMAIN.LOCAL","Client":"WIN10$@WINDOMAIN.LOCAL","Subscription":{"Uuid":"8B18D83D-2964-4F35-AC3B-6F4E6FFA727B","Version":"188BB736-9441-5C66-188B-B73694415C66","Name":"Test","Uri":"/this/is/a/test","ServerRevision":"BABAR","ClientRevision":"TOTO"},"Node":"openwec"}, "ProcessId": "0x5c8"}"#; #[test] fn test_serialize_4624_event_data() { @@ -661,7 +665,7 @@ mod tests { 54: fe74f55b-0338-41d6-b267-4a201abe7285, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )] The Software Protection service has completed licensing status check. Application Id=55c92734-d682-4d71-983e-d6ec3f16059f Licensing Status= 1: 040fa323-92b1-4baf-97a2-5b67feaefddb, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )] 2: 0724cb7d-3437-4cb7-93cb-830375d0079d, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )] 3: 0ad2ac98-7bb9-4201-8d92-312299201369, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )] 4: 1a9a717a-cf13-4ba5-83c3-0fe25fa868d5, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )] 5: 221a02da-e2a1-4b75-864c-0a4410a33fdf, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )] 6: 291ece0e-9c38-40ca-a9e1-32cc7ec19507, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )] 7: 2936d1d2-913a-4542-b54e-ce5a602a2a38, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )] 8: 2c293c26-a45a-4a2a-a350-c69a67097529, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )] 9: 2de67392-b7a7-462a-b1ca-108dd189f588, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )] 10: 2ffd8952-423e-4903-b993-72a1aa44cf82, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )] 11: 30a42c86-b7a0-4a34-8c90-ff177cb2acb7, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )] 12: 345a5db0-d94f-4e3b-a0c0-7c42f7bc3ebf, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )] 13: 3502365a-f88a-4ba4-822a-5769d3073b65, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )] 14: 377333b1-8b5d-48d6-9679-1225c872d37c, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )] 15: 3df374ef-d444-4494-a5a1-4b0d9fd0e203, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )] 16: 3f1afc82-f8ac-4f6c-8005-1d233e606eee, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )] 17: 49cd895b-53b2-4dc4-a5f7-b18aa019ad37, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )] 18: 4de7cb65-cdf1-4de9-8ae8-e3cce27b9f2c, 1, 1 [(0 )(1 )(2 [0xC004E003, 0, 0], [( 1 0xC004F034)( 1 0xC004F034)(?)(?)(?)(?)(?)(?)])(3 [0x00000000, 0, 0], [( 6 0xC004F009 0 0)( 1 0x00000000)( 6 0xC004F009 0 0)(?)(?)(?)( 10 0x00000000 msft:rm/algorithm/flags/1.0)( 11 0x00000000 0xC004F034)])] 19: 4f3da0d2-271d-4508-ae81-626b60809a38, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )] 20: 5d78c4e9-aeb3-4b40-8ac2-6a6005e0ad6d, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )] 21: 60b3ec1b-9545-4921-821f-311b129dd6f6, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )] 22: 613d217f-7f13-4268-9907-1662339531cd, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )] 23: 62f0c100-9c53-4e02-b886-a3528ddfe7f6, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )] 24: 6365275e-368d-46ca-a0ef-fc0404119333, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )] 25: 721f9237-9341-4453-a661-09e8baa6cca5, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )] 26: 73111121-5638-40f6-bc11-f1d7b0d64300, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )] 27: 7a802526-4c94-4bd1-ba14-835a1aca2120, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )] 28: 7cb546c0-c7d5-44d8-9a5c-69ecdd782b69, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )] 29: 82bbc092-bc50-4e16-8e18-b74fc486aec3, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )] 30: 8ab9bdd1-1f67-4997-82d9-8878520837d9, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )] 31: 8b351c9c-f398-4515-9900-09df49427262, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )] 32: 90da7373-1c51-430b-bf26-c97e9c5cdc31, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )] 33: 92fb8726-92a8-4ffc-94ce-f82e07444653, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )] 34: 95dca82f-385d-4d39-b85b-5c73fa285d6f, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )] 35: a48938aa-62fa-4966-9d44-9f04da3f72f2, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )] 36: b0773a15-df3a-4312-9ad2-83d69648e356, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )] 37: b4bfe195-541e-4e64-ad23-6177f19e395e, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )] 38: b68e61d2-68ca-4757-be45-0cc2f3e68eee, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )] 39: bd3762d7-270d-4760-8fb3-d829ca45278a, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )] 40: c86d5194-4840-4dae-9c1c-0301003a5ab0, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )] 41: ca7df2e3-5ea0-47b8-9ac1-b1be4d8edd69, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )] 42: d552befb-48cc-4327-8f39-47d2d94f987c, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )] 43: d6eadb3b-5ca8-4a6b-986e-35b550756111, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )] 44: df96023b-dcd9-4be2-afa0-c6c871159ebe, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )] 45: e0c42288-980c-4788-a014-c080d2e1926e, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )] 46: e4db50ea-bda1-4566-b047-0ca50abc6f07, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )] 47: e558417a-5123-4f6f-91e7-385c1c7ca9d4, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )] 48: e7a950a2-e548-4f10-bf16-02ec848e0643, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )] 49: eb6d346f-1c60-4643-b960-40ec31596c45, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )] 50: ec868e65-fadf-4759-b23e-93fe37f2cc29, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )] 51: ef51e000-2659-4f25-8345-3de70a9cf4c4, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )] 52: f7af7d09-40e4-419c-a49b-eae366689ebd, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )] 53: fa755fe6-6739-40b9-8d84-6d0ea3b6d1ab, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )] 54: fe74f55b-0338-41d6-b267-4a201abe7285, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )] InformationMicrosoft-Windows-Security-SPPClassic"#; - const EVENT_1003_JSON: &str = r#"{"EventTime":"2024-03-14T13:54:25.0379869Z","Hostname":"WKS10001","Keywords":36028797018963968,"EventType":"INFO","SeverityValue":2,"Severity":"INFO","EventID":1003,"SourceName":"Microsoft-Windows-Security-SPP","ProviderGuid":"{E23B33B0-C8C9-472C-A5F9-F2BDFEA0F156}","Version":0,"Task":0,"OpcodeValue":0,"RecordNumber":403,"ProcessID":6628,"ThreadID":0,"Channel":"Application","Message":"The Software Protection service has completed licensing status check.\r\nApplication Id=55c92734-d682-4d71-983e-d6ec3f16059f\r\nLicensing Status=\n1: 040fa323-92b1-4baf-97a2-5b67feaefddb, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n2: 0724cb7d-3437-4cb7-93cb-830375d0079d, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n3: 0ad2ac98-7bb9-4201-8d92-312299201369, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n4: 1a9a717a-cf13-4ba5-83c3-0fe25fa868d5, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n5: 221a02da-e2a1-4b75-864c-0a4410a33fdf, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n6: 291ece0e-9c38-40ca-a9e1-32cc7ec19507, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n7: 2936d1d2-913a-4542-b54e-ce5a602a2a38, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n8: 2c293c26-a45a-4a2a-a350-c69a67097529, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n9: 2de67392-b7a7-462a-b1ca-108dd189f588, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n10: 2ffd8952-423e-4903-b993-72a1aa44cf82, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n11: 30a42c86-b7a0-4a34-8c90-ff177cb2acb7, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n12: 345a5db0-d94f-4e3b-a0c0-7c42f7bc3ebf, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n13: 3502365a-f88a-4ba4-822a-5769d3073b65, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n14: 377333b1-8b5d-48d6-9679-1225c872d37c, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n15: 3df374ef-d444-4494-a5a1-4b0d9fd0e203, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n16: 3f1afc82-f8ac-4f6c-8005-1d233e606eee, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n17: 49cd895b-53b2-4dc4-a5f7-b18aa019ad37, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n18: 4de7cb65-cdf1-4de9-8ae8-e3cce27b9f2c, 1, 1 [(0 )(1 )(2 [0xC004E003, 0, 0], [( 1 0xC004F034)( 1 0xC004F034)(?)(?)(?)(?)(?)(?)])(3 [0x00000000, 0, 0], [( 6 0xC004F009 0 0)( 1 0x00000000)( 6 0xC004F009 0 0)(?)(?)(?)( 10 0x00000000 msft:rm/algorithm/flags/1.0)( 11 0x00000000 0xC004F034)])]\n19: 4f3da0d2-271d-4508-ae81-626b60809a38, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n20: 5d78c4e9-aeb3-4b40-8ac2-6a6005e0ad6d, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n21: 60b3ec1b-9545-4921-821f-311b129dd6f6, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n22: 613d217f-7f13-4268-9907-1662339531cd, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n23: 62f0c100-9c53-4e02-b886-a3528ddfe7f6, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n24: 6365275e-368d-46ca-a0ef-fc0404119333, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n25: 721f9237-9341-4453-a661-09e8baa6cca5, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n26: 73111121-5638-40f6-bc11-f1d7b0d64300, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n27: 7a802526-4c94-4bd1-ba14-835a1aca2120, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n28: 7cb546c0-c7d5-44d8-9a5c-69ecdd782b69, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n29: 82bbc092-bc50-4e16-8e18-b74fc486aec3, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n30: 8ab9bdd1-1f67-4997-82d9-8878520837d9, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n31: 8b351c9c-f398-4515-9900-09df49427262, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n32: 90da7373-1c51-430b-bf26-c97e9c5cdc31, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n33: 92fb8726-92a8-4ffc-94ce-f82e07444653, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n34: 95dca82f-385d-4d39-b85b-5c73fa285d6f, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n35: a48938aa-62fa-4966-9d44-9f04da3f72f2, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n36: b0773a15-df3a-4312-9ad2-83d69648e356, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n37: b4bfe195-541e-4e64-ad23-6177f19e395e, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n38: b68e61d2-68ca-4757-be45-0cc2f3e68eee, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n39: bd3762d7-270d-4760-8fb3-d829ca45278a, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n40: c86d5194-4840-4dae-9c1c-0301003a5ab0, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n41: ca7df2e3-5ea0-47b8-9ac1-b1be4d8edd69, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n42: d552befb-48cc-4327-8f39-47d2d94f987c, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n43: d6eadb3b-5ca8-4a6b-986e-35b550756111, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n44: df96023b-dcd9-4be2-afa0-c6c871159ebe, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n45: e0c42288-980c-4788-a014-c080d2e1926e, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n46: e4db50ea-bda1-4566-b047-0ca50abc6f07, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n47: e558417a-5123-4f6f-91e7-385c1c7ca9d4, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n48: e7a950a2-e548-4f10-bf16-02ec848e0643, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n49: eb6d346f-1c60-4643-b960-40ec31596c45, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n50: ec868e65-fadf-4759-b23e-93fe37f2cc29, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n51: ef51e000-2659-4f25-8345-3de70a9cf4c4, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n52: f7af7d09-40e4-419c-a49b-eae366689ebd, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n53: fa755fe6-6739-40b9-8d84-6d0ea3b6d1ab, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n54: fe74f55b-0338-41d6-b267-4a201abe7285, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n\n","EventReceivedTime":"2024-03-14T13:54:20.331+00:00","Data":["55c92734-d682-4d71-983e-d6ec3f16059f","\n1: 040fa323-92b1-4baf-97a2-5b67feaefddb, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n2: 0724cb7d-3437-4cb7-93cb-830375d0079d, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n3: 0ad2ac98-7bb9-4201-8d92-312299201369, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n4: 1a9a717a-cf13-4ba5-83c3-0fe25fa868d5, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n5: 221a02da-e2a1-4b75-864c-0a4410a33fdf, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n6: 291ece0e-9c38-40ca-a9e1-32cc7ec19507, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n7: 2936d1d2-913a-4542-b54e-ce5a602a2a38, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n8: 2c293c26-a45a-4a2a-a350-c69a67097529, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n9: 2de67392-b7a7-462a-b1ca-108dd189f588, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n10: 2ffd8952-423e-4903-b993-72a1aa44cf82, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n11: 30a42c86-b7a0-4a34-8c90-ff177cb2acb7, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n12: 345a5db0-d94f-4e3b-a0c0-7c42f7bc3ebf, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n13: 3502365a-f88a-4ba4-822a-5769d3073b65, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n14: 377333b1-8b5d-48d6-9679-1225c872d37c, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n15: 3df374ef-d444-4494-a5a1-4b0d9fd0e203, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n16: 3f1afc82-f8ac-4f6c-8005-1d233e606eee, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n17: 49cd895b-53b2-4dc4-a5f7-b18aa019ad37, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n18: 4de7cb65-cdf1-4de9-8ae8-e3cce27b9f2c, 1, 1 [(0 )(1 )(2 [0xC004E003, 0, 0], [( 1 0xC004F034)( 1 0xC004F034)(?)(?)(?)(?)(?)(?)])(3 [0x00000000, 0, 0], [( 6 0xC004F009 0 0)( 1 0x00000000)( 6 0xC004F009 0 0)(?)(?)(?)( 10 0x00000000 msft:rm/algorithm/flags/1.0)( 11 0x00000000 0xC004F034)])]\n19: 4f3da0d2-271d-4508-ae81-626b60809a38, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n20: 5d78c4e9-aeb3-4b40-8ac2-6a6005e0ad6d, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n21: 60b3ec1b-9545-4921-821f-311b129dd6f6, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n22: 613d217f-7f13-4268-9907-1662339531cd, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n23: 62f0c100-9c53-4e02-b886-a3528ddfe7f6, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n24: 6365275e-368d-46ca-a0ef-fc0404119333, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n25: 721f9237-9341-4453-a661-09e8baa6cca5, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n26: 73111121-5638-40f6-bc11-f1d7b0d64300, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n27: 7a802526-4c94-4bd1-ba14-835a1aca2120, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n28: 7cb546c0-c7d5-44d8-9a5c-69ecdd782b69, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n29: 82bbc092-bc50-4e16-8e18-b74fc486aec3, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n30: 8ab9bdd1-1f67-4997-82d9-8878520837d9, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n31: 8b351c9c-f398-4515-9900-09df49427262, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n32: 90da7373-1c51-430b-bf26-c97e9c5cdc31, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n33: 92fb8726-92a8-4ffc-94ce-f82e07444653, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n34: 95dca82f-385d-4d39-b85b-5c73fa285d6f, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n35: a48938aa-62fa-4966-9d44-9f04da3f72f2, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n36: b0773a15-df3a-4312-9ad2-83d69648e356, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n37: b4bfe195-541e-4e64-ad23-6177f19e395e, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n38: b68e61d2-68ca-4757-be45-0cc2f3e68eee, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n39: bd3762d7-270d-4760-8fb3-d829ca45278a, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n40: c86d5194-4840-4dae-9c1c-0301003a5ab0, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n41: ca7df2e3-5ea0-47b8-9ac1-b1be4d8edd69, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n42: d552befb-48cc-4327-8f39-47d2d94f987c, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n43: d6eadb3b-5ca8-4a6b-986e-35b550756111, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n44: df96023b-dcd9-4be2-afa0-c6c871159ebe, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n45: e0c42288-980c-4788-a014-c080d2e1926e, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n46: e4db50ea-bda1-4566-b047-0ca50abc6f07, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n47: e558417a-5123-4f6f-91e7-385c1c7ca9d4, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n48: e7a950a2-e548-4f10-bf16-02ec848e0643, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n49: eb6d346f-1c60-4643-b960-40ec31596c45, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n50: ec868e65-fadf-4759-b23e-93fe37f2cc29, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n51: ef51e000-2659-4f25-8345-3de70a9cf4c4, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n52: f7af7d09-40e4-419c-a49b-eae366689ebd, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n53: fa755fe6-6739-40b9-8d84-6d0ea3b6d1ab, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n54: fe74f55b-0338-41d6-b267-4a201abe7285, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n\n"],"OpenWEC":{"IpAddress":"192.168.58.100","TimeReceived":"2024-03-14T13:54:20.331+00:00","Principal":"WIN10$@WINDOMAIN.LOCAL","Subscription":{"Uuid":"8B18D83D-2964-4F35-AC3B-6F4E6FFA727B","Version":"188BB736-9441-5C66-188B-B73694415C66","Name":"Test","Uri":"/this/is/a/test","ServerRevision":"BABAR","ClientRevision":"TOTO"},"Node":"openwec"}}"#; + const EVENT_1003_JSON: &str = r#"{"EventTime":"2024-03-14T13:54:25.0379869Z","Hostname":"WKS10001","Keywords":36028797018963968,"EventType":"INFO","SeverityValue":2,"Severity":"INFO","EventID":1003,"SourceName":"Microsoft-Windows-Security-SPP","ProviderGuid":"{E23B33B0-C8C9-472C-A5F9-F2BDFEA0F156}","Version":0,"Task":0,"OpcodeValue":0,"RecordNumber":403,"ProcessID":6628,"ThreadID":0,"Channel":"Application","Message":"The Software Protection service has completed licensing status check.\r\nApplication Id=55c92734-d682-4d71-983e-d6ec3f16059f\r\nLicensing Status=\n1: 040fa323-92b1-4baf-97a2-5b67feaefddb, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n2: 0724cb7d-3437-4cb7-93cb-830375d0079d, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n3: 0ad2ac98-7bb9-4201-8d92-312299201369, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n4: 1a9a717a-cf13-4ba5-83c3-0fe25fa868d5, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n5: 221a02da-e2a1-4b75-864c-0a4410a33fdf, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n6: 291ece0e-9c38-40ca-a9e1-32cc7ec19507, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n7: 2936d1d2-913a-4542-b54e-ce5a602a2a38, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n8: 2c293c26-a45a-4a2a-a350-c69a67097529, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n9: 2de67392-b7a7-462a-b1ca-108dd189f588, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n10: 2ffd8952-423e-4903-b993-72a1aa44cf82, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n11: 30a42c86-b7a0-4a34-8c90-ff177cb2acb7, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n12: 345a5db0-d94f-4e3b-a0c0-7c42f7bc3ebf, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n13: 3502365a-f88a-4ba4-822a-5769d3073b65, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n14: 377333b1-8b5d-48d6-9679-1225c872d37c, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n15: 3df374ef-d444-4494-a5a1-4b0d9fd0e203, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n16: 3f1afc82-f8ac-4f6c-8005-1d233e606eee, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n17: 49cd895b-53b2-4dc4-a5f7-b18aa019ad37, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n18: 4de7cb65-cdf1-4de9-8ae8-e3cce27b9f2c, 1, 1 [(0 )(1 )(2 [0xC004E003, 0, 0], [( 1 0xC004F034)( 1 0xC004F034)(?)(?)(?)(?)(?)(?)])(3 [0x00000000, 0, 0], [( 6 0xC004F009 0 0)( 1 0x00000000)( 6 0xC004F009 0 0)(?)(?)(?)( 10 0x00000000 msft:rm/algorithm/flags/1.0)( 11 0x00000000 0xC004F034)])]\n19: 4f3da0d2-271d-4508-ae81-626b60809a38, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n20: 5d78c4e9-aeb3-4b40-8ac2-6a6005e0ad6d, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n21: 60b3ec1b-9545-4921-821f-311b129dd6f6, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n22: 613d217f-7f13-4268-9907-1662339531cd, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n23: 62f0c100-9c53-4e02-b886-a3528ddfe7f6, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n24: 6365275e-368d-46ca-a0ef-fc0404119333, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n25: 721f9237-9341-4453-a661-09e8baa6cca5, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n26: 73111121-5638-40f6-bc11-f1d7b0d64300, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n27: 7a802526-4c94-4bd1-ba14-835a1aca2120, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n28: 7cb546c0-c7d5-44d8-9a5c-69ecdd782b69, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n29: 82bbc092-bc50-4e16-8e18-b74fc486aec3, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n30: 8ab9bdd1-1f67-4997-82d9-8878520837d9, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n31: 8b351c9c-f398-4515-9900-09df49427262, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n32: 90da7373-1c51-430b-bf26-c97e9c5cdc31, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n33: 92fb8726-92a8-4ffc-94ce-f82e07444653, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n34: 95dca82f-385d-4d39-b85b-5c73fa285d6f, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n35: a48938aa-62fa-4966-9d44-9f04da3f72f2, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n36: b0773a15-df3a-4312-9ad2-83d69648e356, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n37: b4bfe195-541e-4e64-ad23-6177f19e395e, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n38: b68e61d2-68ca-4757-be45-0cc2f3e68eee, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n39: bd3762d7-270d-4760-8fb3-d829ca45278a, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n40: c86d5194-4840-4dae-9c1c-0301003a5ab0, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n41: ca7df2e3-5ea0-47b8-9ac1-b1be4d8edd69, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n42: d552befb-48cc-4327-8f39-47d2d94f987c, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n43: d6eadb3b-5ca8-4a6b-986e-35b550756111, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n44: df96023b-dcd9-4be2-afa0-c6c871159ebe, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n45: e0c42288-980c-4788-a014-c080d2e1926e, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n46: e4db50ea-bda1-4566-b047-0ca50abc6f07, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n47: e558417a-5123-4f6f-91e7-385c1c7ca9d4, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n48: e7a950a2-e548-4f10-bf16-02ec848e0643, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n49: eb6d346f-1c60-4643-b960-40ec31596c45, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n50: ec868e65-fadf-4759-b23e-93fe37f2cc29, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n51: ef51e000-2659-4f25-8345-3de70a9cf4c4, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n52: f7af7d09-40e4-419c-a49b-eae366689ebd, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n53: fa755fe6-6739-40b9-8d84-6d0ea3b6d1ab, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n54: fe74f55b-0338-41d6-b267-4a201abe7285, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n\n","EventReceivedTime":"2024-03-14T13:54:20.331+00:00","Data":["55c92734-d682-4d71-983e-d6ec3f16059f","\n1: 040fa323-92b1-4baf-97a2-5b67feaefddb, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n2: 0724cb7d-3437-4cb7-93cb-830375d0079d, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n3: 0ad2ac98-7bb9-4201-8d92-312299201369, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n4: 1a9a717a-cf13-4ba5-83c3-0fe25fa868d5, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n5: 221a02da-e2a1-4b75-864c-0a4410a33fdf, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n6: 291ece0e-9c38-40ca-a9e1-32cc7ec19507, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n7: 2936d1d2-913a-4542-b54e-ce5a602a2a38, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n8: 2c293c26-a45a-4a2a-a350-c69a67097529, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n9: 2de67392-b7a7-462a-b1ca-108dd189f588, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n10: 2ffd8952-423e-4903-b993-72a1aa44cf82, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n11: 30a42c86-b7a0-4a34-8c90-ff177cb2acb7, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n12: 345a5db0-d94f-4e3b-a0c0-7c42f7bc3ebf, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n13: 3502365a-f88a-4ba4-822a-5769d3073b65, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n14: 377333b1-8b5d-48d6-9679-1225c872d37c, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n15: 3df374ef-d444-4494-a5a1-4b0d9fd0e203, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n16: 3f1afc82-f8ac-4f6c-8005-1d233e606eee, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n17: 49cd895b-53b2-4dc4-a5f7-b18aa019ad37, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n18: 4de7cb65-cdf1-4de9-8ae8-e3cce27b9f2c, 1, 1 [(0 )(1 )(2 [0xC004E003, 0, 0], [( 1 0xC004F034)( 1 0xC004F034)(?)(?)(?)(?)(?)(?)])(3 [0x00000000, 0, 0], [( 6 0xC004F009 0 0)( 1 0x00000000)( 6 0xC004F009 0 0)(?)(?)(?)( 10 0x00000000 msft:rm/algorithm/flags/1.0)( 11 0x00000000 0xC004F034)])]\n19: 4f3da0d2-271d-4508-ae81-626b60809a38, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n20: 5d78c4e9-aeb3-4b40-8ac2-6a6005e0ad6d, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n21: 60b3ec1b-9545-4921-821f-311b129dd6f6, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n22: 613d217f-7f13-4268-9907-1662339531cd, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n23: 62f0c100-9c53-4e02-b886-a3528ddfe7f6, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n24: 6365275e-368d-46ca-a0ef-fc0404119333, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n25: 721f9237-9341-4453-a661-09e8baa6cca5, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n26: 73111121-5638-40f6-bc11-f1d7b0d64300, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n27: 7a802526-4c94-4bd1-ba14-835a1aca2120, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n28: 7cb546c0-c7d5-44d8-9a5c-69ecdd782b69, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n29: 82bbc092-bc50-4e16-8e18-b74fc486aec3, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n30: 8ab9bdd1-1f67-4997-82d9-8878520837d9, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n31: 8b351c9c-f398-4515-9900-09df49427262, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n32: 90da7373-1c51-430b-bf26-c97e9c5cdc31, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n33: 92fb8726-92a8-4ffc-94ce-f82e07444653, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n34: 95dca82f-385d-4d39-b85b-5c73fa285d6f, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n35: a48938aa-62fa-4966-9d44-9f04da3f72f2, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n36: b0773a15-df3a-4312-9ad2-83d69648e356, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n37: b4bfe195-541e-4e64-ad23-6177f19e395e, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n38: b68e61d2-68ca-4757-be45-0cc2f3e68eee, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n39: bd3762d7-270d-4760-8fb3-d829ca45278a, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n40: c86d5194-4840-4dae-9c1c-0301003a5ab0, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n41: ca7df2e3-5ea0-47b8-9ac1-b1be4d8edd69, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n42: d552befb-48cc-4327-8f39-47d2d94f987c, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n43: d6eadb3b-5ca8-4a6b-986e-35b550756111, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n44: df96023b-dcd9-4be2-afa0-c6c871159ebe, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n45: e0c42288-980c-4788-a014-c080d2e1926e, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n46: e4db50ea-bda1-4566-b047-0ca50abc6f07, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n47: e558417a-5123-4f6f-91e7-385c1c7ca9d4, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n48: e7a950a2-e548-4f10-bf16-02ec848e0643, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n49: eb6d346f-1c60-4643-b960-40ec31596c45, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n50: ec868e65-fadf-4759-b23e-93fe37f2cc29, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n51: ef51e000-2659-4f25-8345-3de70a9cf4c4, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n52: f7af7d09-40e4-419c-a49b-eae366689ebd, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n53: fa755fe6-6739-40b9-8d84-6d0ea3b6d1ab, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n54: fe74f55b-0338-41d6-b267-4a201abe7285, 1, 0 [(0 [0xC004F014, 0, 0], [(?)(?)(?)(?)(?)(?)(?)(?)])(1 )(2 )(3 )]\n\n"],"OpenWEC":{"IpAddress":"192.168.58.100","TimeReceived":"2024-03-14T13:54:20.331+00:00","Principal":"WIN10$@WINDOMAIN.LOCAL","Client":"WIN10$@WINDOMAIN.LOCAL","Subscription":{"Uuid":"8B18D83D-2964-4F35-AC3B-6F4E6FFA727B","Version":"188BB736-9441-5C66-188B-B73694415C66","Name":"Test","Uri":"/this/is/a/test","ServerRevision":"BABAR","ClientRevision":"TOTO"},"Node":"openwec"}}"#; #[test] fn test_serialize_1003_event_data_unamed() { @@ -669,7 +673,7 @@ mod tests { } const EVENT_8198: &str = r#"819802000x80000000000000405ApplicationWKS10001hr=0x800704CFRuleId=31e71c49-8da7-4a2f-ad92-45d98a1c79ba;Action=AutoActivate;AppId=55c92734-d682-4d71-983e-d6ec3f16059f;SkuId=4de7cb65-cdf1-4de9-8ae8-e3cce27b9f2c;NotificationInterval=1440;Trigger=UserLogon;SessionId=2License Activation (slui.exe) failed with the following error code: hr=0x800704CF Command-line arguments: RuleId=31e71c49-8da7-4a2f-ad92-45d98a1c79ba;Action=AutoActivate;AppId=55c92734-d682-4d71-983e-d6ec3f16059f;SkuId=4de7cb65-cdf1-4de9-8ae8-e3cce27b9f2c;NotificationInterval=1440;Trigger=UserLogon;SessionId=2ErrorMicrosoft-Windows-Security-SPPClassic"#; - const EVENT_8198_JSON: &str = r#"{"Data":["hr=0x800704CF","RuleId=31e71c49-8da7-4a2f-ad92-45d98a1c79ba;Action=AutoActivate;AppId=55c92734-d682-4d71-983e-d6ec3f16059f;SkuId=4de7cb65-cdf1-4de9-8ae8-e3cce27b9f2c;NotificationInterval=1440;Trigger=UserLogon;SessionId=2"],"EventTime":"2024-03-14T13:54:25.1166916Z","Hostname":"WKS10001","Keywords":36028797018963968,"EventType":"ERROR","SeverityValue":4,"Severity":"ERROR","EventID":8198,"SourceName":"Microsoft-Windows-Security-SPP","ProviderGuid":"{E23B33B0-C8C9-472C-A5F9-F2BDFEA0F156}","Version":0,"Task":0,"OpcodeValue":0,"RecordNumber":405,"ProcessID":7240,"ThreadID":0,"Channel":"Application","Message":"License Activation (slui.exe) failed with the following error code:\r\nhr=0x800704CF\r\nCommand-line arguments:\r\nRuleId=31e71c49-8da7-4a2f-ad92-45d98a1c79ba;Action=AutoActivate;AppId=55c92734-d682-4d71-983e-d6ec3f16059f;SkuId=4de7cb65-cdf1-4de9-8ae8-e3cce27b9f2c;NotificationInterval=1440;Trigger=UserLogon;SessionId=2","EventReceivedTime":"2024-03-14T13:54:20.331+00:00","OpenWEC":{"IpAddress":"192.168.58.100","Node":"openwec","Principal":"WIN10$@WINDOMAIN.LOCAL","Subscription":{"Name": "Test","Uri":"/this/is/a/test","Uuid":"8B18D83D-2964-4F35-AC3B-6F4E6FFA727B","Version":"188BB736-9441-5C66-188B-B73694415C66","ServerRevision":"BABAR","ClientRevision":"TOTO"},"TimeReceived":"2024-03-14T13:54:20.331+00:00"}}"#; + const EVENT_8198_JSON: &str = r#"{"Data":["hr=0x800704CF","RuleId=31e71c49-8da7-4a2f-ad92-45d98a1c79ba;Action=AutoActivate;AppId=55c92734-d682-4d71-983e-d6ec3f16059f;SkuId=4de7cb65-cdf1-4de9-8ae8-e3cce27b9f2c;NotificationInterval=1440;Trigger=UserLogon;SessionId=2"],"EventTime":"2024-03-14T13:54:25.1166916Z","Hostname":"WKS10001","Keywords":36028797018963968,"EventType":"ERROR","SeverityValue":4,"Severity":"ERROR","EventID":8198,"SourceName":"Microsoft-Windows-Security-SPP","ProviderGuid":"{E23B33B0-C8C9-472C-A5F9-F2BDFEA0F156}","Version":0,"Task":0,"OpcodeValue":0,"RecordNumber":405,"ProcessID":7240,"ThreadID":0,"Channel":"Application","Message":"License Activation (slui.exe) failed with the following error code:\r\nhr=0x800704CF\r\nCommand-line arguments:\r\nRuleId=31e71c49-8da7-4a2f-ad92-45d98a1c79ba;Action=AutoActivate;AppId=55c92734-d682-4d71-983e-d6ec3f16059f;SkuId=4de7cb65-cdf1-4de9-8ae8-e3cce27b9f2c;NotificationInterval=1440;Trigger=UserLogon;SessionId=2","EventReceivedTime":"2024-03-14T13:54:20.331+00:00","OpenWEC":{"IpAddress":"192.168.58.100","Node":"openwec","Principal":"WIN10$@WINDOMAIN.LOCAL","Client":"WIN10$@WINDOMAIN.LOCAL","Subscription":{"Name": "Test","Uri":"/this/is/a/test","Uuid":"8B18D83D-2964-4F35-AC3B-6F4E6FFA727B","Version":"188BB736-9441-5C66-188B-B73694415C66","ServerRevision":"BABAR","ClientRevision":"TOTO"},"TimeReceived":"2024-03-14T13:54:20.331+00:00"}}"#; #[test] fn test_serialize_8198() { @@ -677,7 +681,7 @@ mod tests { } const EVENT_8002: &str = r#"8002038001130x80001000000000004974Microsoft-Windows-Store/OperationalWKS10001Trying to remove timer {5691E7B0-78A4-A20B-3094-CD9BCC47193D} not in tableMemoryTimerService::CancelTimerWithIdonecoreuap\enduser\winstore\licensemanager\lib\memorytimer.cpp80Trying to remove timer {5691E7B0-78A4-A20B-3094-CD9BCC47193D} not in table Function: MemoryTimerService::CancelTimerWithId Source: onecoreuap\enduser\winstore\licensemanager\lib\memorytimer.cpp (80)WarningLMWarningMicrosoft-Windows-Store"#; - const EVENT_8002_JSON: &str = r#"{"EventTime":"2024-03-14T13:54:11.8558403Z","Hostname":"WKS10001","Keywords":-9223354444668731392,"EventType":"WARNING","SeverityValue":3,"Severity":"WARNING","EventID":8002,"SourceName":"Microsoft-Windows-Store","ProviderGuid":"{9C2A37F3-E5FD-5CAE-BCD1-43DAFEEE1FF0}","Version":0,"Task":8001,"OpcodeValue":13,"RecordNumber":4974,"ProcessID":5496,"ThreadID":3248,"Channel":"Microsoft-Windows-Store/Operational","UserID":"S-1-5-19","Message":"Trying to remove timer {5691E7B0-78A4-A20B-3094-CD9BCC47193D} not in table\r\nFunction: MemoryTimerService::CancelTimerWithId\r\nSource: onecoreuap\\enduser\\winstore\\licensemanager\\lib\\memorytimer.cpp (80)","Category":"LM","Opcode":"Warning","Function":"MemoryTimerService::CancelTimerWithId","Source":"onecoreuap\\enduser\\winstore\\licensemanager\\lib\\memorytimer.cpp","Line Number":"80","EventReceivedTime":"2024-03-14T13:54:20.331+00:00","OpenWEC":{"IpAddress":"192.168.58.100","Node":"openwec","Principal":"WIN10$@WINDOMAIN.LOCAL","Subscription":{"Name":"Test","Uri":"/this/is/a/test","Uuid":"8B18D83D-2964-4F35-AC3B-6F4E6FFA727B","Version":"188BB736-9441-5C66-188B-B73694415C66","ServerRevision":"BABAR","ClientRevision":"TOTO"},"TimeReceived":"2024-03-14T13:54:20.331+00:00"}}"#; + const EVENT_8002_JSON: &str = r#"{"EventTime":"2024-03-14T13:54:11.8558403Z","Hostname":"WKS10001","Keywords":-9223354444668731392,"EventType":"WARNING","SeverityValue":3,"Severity":"WARNING","EventID":8002,"SourceName":"Microsoft-Windows-Store","ProviderGuid":"{9C2A37F3-E5FD-5CAE-BCD1-43DAFEEE1FF0}","Version":0,"Task":8001,"OpcodeValue":13,"RecordNumber":4974,"ProcessID":5496,"ThreadID":3248,"Channel":"Microsoft-Windows-Store/Operational","UserID":"S-1-5-19","Message":"Trying to remove timer {5691E7B0-78A4-A20B-3094-CD9BCC47193D} not in table\r\nFunction: MemoryTimerService::CancelTimerWithId\r\nSource: onecoreuap\\enduser\\winstore\\licensemanager\\lib\\memorytimer.cpp (80)","Category":"LM","Opcode":"Warning","Function":"MemoryTimerService::CancelTimerWithId","Source":"onecoreuap\\enduser\\winstore\\licensemanager\\lib\\memorytimer.cpp","Line Number":"80","EventReceivedTime":"2024-03-14T13:54:20.331+00:00","OpenWEC":{"IpAddress":"192.168.58.100","Node":"openwec","Principal":"WIN10$@WINDOMAIN.LOCAL","Client":"WIN10$@WINDOMAIN.LOCAL","Subscription":{"Name":"Test","Uri":"/this/is/a/test","Uuid":"8B18D83D-2964-4F35-AC3B-6F4E6FFA727B","Version":"188BB736-9441-5C66-188B-B73694415C66","ServerRevision":"BABAR","ClientRevision":"TOTO"},"TimeReceived":"2024-03-14T13:54:20.331+00:00"}}"#; #[test] fn test_serialize_8002() { @@ -685,7 +689,7 @@ mod tests { } const EVENT_4625: &str = r#"4625001254400x80100000000000001444SecurityWKS10001S-1-5-18WKS10001$WORKGROUP0x3e7S-1-0-0userWKS100010xc000006d%%23130xc000006a2User32 NegotiateWKS10001--00x5c8C:\Windows\System32\svchost.exe127.0.0.10An account failed to log on. Subject: Security ID: S-1-5-18 Account Name: WKS10001$ Account Domain: WORKGROUP Logon ID: 0x3E7 Logon Type: 2 Account For Which Logon Failed: Security ID: S-1-0-0 Account Name: user Account Domain: WKS10001 Failure Information: Failure Reason: Unknown user name or bad password. Status: 0xC000006D Sub Status: 0xC000006A Process Information: Caller Process ID: 0x5c8 Caller Process Name: C:\Windows\System32\svchost.exe Network Information: Workstation Name: WKS10001 Source Network Address: 127.0.0.1 Source Port: 0 Detailed Authentication Information: Logon Process: User32 Authentication Package: Negotiate Transited Services: - Package Name (NTLM only): - Key Length: 0 This event is generated when a logon request fails. It is generated on the computer where access was attempted. The Subject fields indicate the account on the local system which requested the logon. This is most commonly a service such as the Server service, or a local process such as Winlogon.exe or Services.exe. The Logon Type field indicates the kind of logon that was requested. The most common types are 2 (interactive) and 3 (network). The Process Information fields indicate which account and process on the system requested the logon. The Network Information fields indicate where a remote logon request originated. Workstation name is not always available and may be left blank in some cases. The authentication information fields provide detailed information about this specific logon request. - Transited services indicate which intermediate services have participated in this logon request. - Package name indicates which sub-protocol was used among the NTLM protocols. - Key length indicates the length of the generated session key. This will be 0 if no session key was requested.InformationLogonInfoSecurityMicrosoft Windows security auditing.Audit Failure"#; - const EVENT_4625_JSON: &str = r#"{"EventTime":"2024-03-14T13:54:16.6138329Z","Hostname":"WKS10001","Keywords":-9218868437227405312,"EventType":"AUDIT_FAILURE","SeverityValue":4,"Severity":"ERROR","EventID":4625,"SourceName":"Microsoft-Windows-Security-Auditing","ProviderGuid":"{54849625-5478-4994-A5BA-3E3B0328C30D}","Version":0,"Task":12544,"OpcodeValue":0,"RecordNumber":1444,"ActivityID":"{B073A4BF-7611-0000-BCA5-73B01176DA01}","ProcessID":780,"ThreadID":8372,"Channel":"Security","Message":"An account failed to log on.\r\n\r\nSubject:\r\n\tSecurity ID:\t\tS-1-5-18\r\n\tAccount Name:\t\tWKS10001$\r\n\tAccount Domain:\t\tWORKGROUP\r\n\tLogon ID:\t\t0x3E7\r\n\r\nLogon Type:\t\t\t2\r\n\r\nAccount For Which Logon Failed:\r\n\tSecurity ID:\t\tS-1-0-0\r\n\tAccount Name:\t\tuser\r\n\tAccount Domain:\t\tWKS10001\r\n\r\nFailure Information:\r\n\tFailure Reason:\t\tUnknown user name or bad password.\r\n\tStatus:\t\t\t0xC000006D\r\n\tSub Status:\t\t0xC000006A\r\n\r\nProcess Information:\r\n\tCaller Process ID:\t0x5c8\r\n\tCaller Process Name:\tC:\\Windows\\System32\\svchost.exe\r\n\r\nNetwork Information:\r\n\tWorkstation Name:\tWKS10001\r\n\tSource Network Address:\t127.0.0.1\r\n\tSource Port:\t\t0\r\n\r\nDetailed Authentication Information:\r\n\tLogon Process:\t\tUser32 \r\n\tAuthentication Package:\tNegotiate\r\n\tTransited Services:\t-\r\n\tPackage Name (NTLM only):\t-\r\n\tKey Length:\t\t0\r\n\r\nThis event is generated when a logon request fails. It is generated on the computer where access was attempted.\r\n\r\nThe Subject fields indicate the account on the local system which requested the logon. This is most commonly a service such as the Server service, or a local process such as Winlogon.exe or Services.exe.\r\n\r\nThe Logon Type field indicates the kind of logon that was requested. The most common types are 2 (interactive) and 3 (network).\r\n\r\nThe Process Information fields indicate which account and process on the system requested the logon.\r\n\r\nThe Network Information fields indicate where a remote logon request originated. Workstation name is not always available and may be left blank in some cases.\r\n\r\nThe authentication information fields provide detailed information about this specific logon request.\r\n\t- Transited services indicate which intermediate services have participated in this logon request.\r\n\t- Package name indicates which sub-protocol was used among the NTLM protocols.\r\n\t- Key length indicates the length of the generated session key. This will be 0 if no session key was requested.","Category":"Logon","Opcode":"Info","SubjectUserSid":"S-1-5-18","SubjectUserName":"WKS10001$","SubjectDomainName":"WORKGROUP","SubjectLogonId":"0x3e7","TargetUserSid":"S-1-0-0","TargetUserName":"user","TargetDomainName":"WKS10001","Status":"0xc000006d","FailureReason":"%%2313","SubStatus":"0xc000006a","LogonType":"2","LogonProcessName":"User32 ","AuthenticationPackageName":"Negotiate","WorkstationName":"WKS10001","TransmittedServices":"-","LmPackageName":"-","KeyLength":"0","ProcessName":"C:\\Windows\\System32\\svchost.exe","IpAddress":"127.0.0.1","IpPort":"0","EventReceivedTime":"2024-03-14T13:54:20.331+00:00","OpenWEC":{"IpAddress":"192.168.58.100","TimeReceived":"2024-03-14T13:54:20.331+00:00","Principal":"WIN10$@WINDOMAIN.LOCAL","Subscription":{"Uuid":"8B18D83D-2964-4F35-AC3B-6F4E6FFA727B","Version":"188BB736-9441-5C66-188B-B73694415C66","Name":"Test","Uri":"/this/is/a/test","ServerRevision":"BABAR","ClientRevision":"TOTO"},"Node":"openwec"},"ProcessId":"0x5c8"}"#; + const EVENT_4625_JSON: &str = r#"{"EventTime":"2024-03-14T13:54:16.6138329Z","Hostname":"WKS10001","Keywords":-9218868437227405312,"EventType":"AUDIT_FAILURE","SeverityValue":4,"Severity":"ERROR","EventID":4625,"SourceName":"Microsoft-Windows-Security-Auditing","ProviderGuid":"{54849625-5478-4994-A5BA-3E3B0328C30D}","Version":0,"Task":12544,"OpcodeValue":0,"RecordNumber":1444,"ActivityID":"{B073A4BF-7611-0000-BCA5-73B01176DA01}","ProcessID":780,"ThreadID":8372,"Channel":"Security","Message":"An account failed to log on.\r\n\r\nSubject:\r\n\tSecurity ID:\t\tS-1-5-18\r\n\tAccount Name:\t\tWKS10001$\r\n\tAccount Domain:\t\tWORKGROUP\r\n\tLogon ID:\t\t0x3E7\r\n\r\nLogon Type:\t\t\t2\r\n\r\nAccount For Which Logon Failed:\r\n\tSecurity ID:\t\tS-1-0-0\r\n\tAccount Name:\t\tuser\r\n\tAccount Domain:\t\tWKS10001\r\n\r\nFailure Information:\r\n\tFailure Reason:\t\tUnknown user name or bad password.\r\n\tStatus:\t\t\t0xC000006D\r\n\tSub Status:\t\t0xC000006A\r\n\r\nProcess Information:\r\n\tCaller Process ID:\t0x5c8\r\n\tCaller Process Name:\tC:\\Windows\\System32\\svchost.exe\r\n\r\nNetwork Information:\r\n\tWorkstation Name:\tWKS10001\r\n\tSource Network Address:\t127.0.0.1\r\n\tSource Port:\t\t0\r\n\r\nDetailed Authentication Information:\r\n\tLogon Process:\t\tUser32 \r\n\tAuthentication Package:\tNegotiate\r\n\tTransited Services:\t-\r\n\tPackage Name (NTLM only):\t-\r\n\tKey Length:\t\t0\r\n\r\nThis event is generated when a logon request fails. It is generated on the computer where access was attempted.\r\n\r\nThe Subject fields indicate the account on the local system which requested the logon. This is most commonly a service such as the Server service, or a local process such as Winlogon.exe or Services.exe.\r\n\r\nThe Logon Type field indicates the kind of logon that was requested. The most common types are 2 (interactive) and 3 (network).\r\n\r\nThe Process Information fields indicate which account and process on the system requested the logon.\r\n\r\nThe Network Information fields indicate where a remote logon request originated. Workstation name is not always available and may be left blank in some cases.\r\n\r\nThe authentication information fields provide detailed information about this specific logon request.\r\n\t- Transited services indicate which intermediate services have participated in this logon request.\r\n\t- Package name indicates which sub-protocol was used among the NTLM protocols.\r\n\t- Key length indicates the length of the generated session key. This will be 0 if no session key was requested.","Category":"Logon","Opcode":"Info","SubjectUserSid":"S-1-5-18","SubjectUserName":"WKS10001$","SubjectDomainName":"WORKGROUP","SubjectLogonId":"0x3e7","TargetUserSid":"S-1-0-0","TargetUserName":"user","TargetDomainName":"WKS10001","Status":"0xc000006d","FailureReason":"%%2313","SubStatus":"0xc000006a","LogonType":"2","LogonProcessName":"User32 ","AuthenticationPackageName":"Negotiate","WorkstationName":"WKS10001","TransmittedServices":"-","LmPackageName":"-","KeyLength":"0","ProcessName":"C:\\Windows\\System32\\svchost.exe","IpAddress":"127.0.0.1","IpPort":"0","EventReceivedTime":"2024-03-14T13:54:20.331+00:00","OpenWEC":{"IpAddress":"192.168.58.100","TimeReceived":"2024-03-14T13:54:20.331+00:00","Principal":"WIN10$@WINDOMAIN.LOCAL","Client":"WIN10$@WINDOMAIN.LOCAL","Subscription":{"Uuid":"8B18D83D-2964-4F35-AC3B-6F4E6FFA727B","Version":"188BB736-9441-5C66-188B-B73694415C66","Name":"Test","Uri":"/this/is/a/test","ServerRevision":"BABAR","ClientRevision":"TOTO"},"Node":"openwec"},"ProcessId":"0x5c8"}"#; #[test] fn test_serialize_4625() { @@ -693,7 +697,7 @@ mod tests { } const EVENT_328: &str = r#"32802000x400000000001000020Microsoft-Windows-AppXDeployment/OperationalWKS100010x800401f0Unable to determine packages to be installed during logon with error: 0x800401F0.ErrorInfoMicrosoft-Windows-AppXDeployment"#; - const EVENT_328_JSON: &str = r#"{"EventTime":"2024-03-14T13:54:19.4093952Z","Hostname":"WKS10001","Keywords":4611686018427453440,"EventType":"ERROR","SeverityValue":4,"Severity":"ERROR","EventID":328,"SourceName":"Microsoft-Windows-AppXDeployment","ProviderGuid":"{8127F6D4-59F9-4ABF-8952-3E3A02073D5F}","Version":0,"Task":0,"OpcodeValue":0,"RecordNumber":20,"ActivityID":"{61A55000-55E5-1017-0000-000000000000}","ProcessID":468,"ThreadID":4744,"Channel":"Microsoft-Windows-AppXDeployment/Operational","UserID":"S-1-5-18","Message":"Unable to determine packages to be installed during logon with error: 0x800401F0.","Opcode":"Info","ErrorCode":"0x800401f0","EventReceivedTime":"2024-03-14T13:54:20.331+00:00","OpenWEC":{"IpAddress":"192.168.58.100","TimeReceived":"2024-03-14T13:54:20.331+00:00","Principal":"WIN10$@WINDOMAIN.LOCAL","Subscription":{"Uuid":"8B18D83D-2964-4F35-AC3B-6F4E6FFA727B","Version":"188BB736-9441-5C66-188B-B73694415C66","Name":"Test","Uri":"/this/is/a/test","ServerRevision":"BABAR","ClientRevision":"TOTO"},"Node":"openwec"}}"#; + const EVENT_328_JSON: &str = r#"{"EventTime":"2024-03-14T13:54:19.4093952Z","Hostname":"WKS10001","Keywords":4611686018427453440,"EventType":"ERROR","SeverityValue":4,"Severity":"ERROR","EventID":328,"SourceName":"Microsoft-Windows-AppXDeployment","ProviderGuid":"{8127F6D4-59F9-4ABF-8952-3E3A02073D5F}","Version":0,"Task":0,"OpcodeValue":0,"RecordNumber":20,"ActivityID":"{61A55000-55E5-1017-0000-000000000000}","ProcessID":468,"ThreadID":4744,"Channel":"Microsoft-Windows-AppXDeployment/Operational","UserID":"S-1-5-18","Message":"Unable to determine packages to be installed during logon with error: 0x800401F0.","Opcode":"Info","ErrorCode":"0x800401f0","EventReceivedTime":"2024-03-14T13:54:20.331+00:00","OpenWEC":{"IpAddress":"192.168.58.100","TimeReceived":"2024-03-14T13:54:20.331+00:00","Principal":"WIN10$@WINDOMAIN.LOCAL","Client":"WIN10$@WINDOMAIN.LOCAL","Subscription":{"Uuid":"8B18D83D-2964-4F35-AC3B-6F4E6FFA727B","Version":"188BB736-9441-5C66-188B-B73694415C66","Name":"Test","Uri":"/this/is/a/test","ServerRevision":"BABAR","ClientRevision":"TOTO"},"Node":"openwec"}}"#; #[test] fn test_serialize_328() { @@ -701,7 +705,7 @@ mod tests { } const EVENT_1100: &str = r#"11000410300x4020000000000000114371Securitywin10.windomain.localThe event logging service has shut down.InformationService shutdownInfoSecurityMicrosoft-Windows-EventlogAudit Success"#; - const EVENT_1100_JSON: &str = r#"{"SourceName":"Microsoft-Windows-Eventlog","ProviderGuid":"{FC65DDD8-D6EF-4962-83D5-6E5CFE9CE148}","EventID":1100,"Version":0,"Task":103,"OpcodeValue":0,"Keywords":4620693217682128896,"EventTime":"2022-12-14T14:39:07.1686183Z","RecordNumber":114371,"ProcessID":496,"ThreadID":204,"Channel":"Security","Hostname":"win10.windomain.local","EventType":"AUDIT_SUCCESS","Severity":"INFO","SeverityValue":2,"UserData":"","Message":"The event logging service has shut down.","Category":"Service shutdown","Opcode":"Info","OpenWEC":{"IpAddress":"192.168.58.100","TimeReceived":"2024-03-14T13:54:20.331+00:00","Principal":"WIN10$@WINDOMAIN.LOCAL","Subscription":{"Uuid":"8B18D83D-2964-4F35-AC3B-6F4E6FFA727B","Version":"188BB736-9441-5C66-188B-B73694415C66","Name":"Test","Uri":"/this/is/a/test","ClientRevision":"TOTO","ServerRevision":"BABAR"},"Node":"openwec"},"EventReceivedTime":"2024-03-14T13:54:20.331+00:00"}"#; + const EVENT_1100_JSON: &str = r#"{"SourceName":"Microsoft-Windows-Eventlog","ProviderGuid":"{FC65DDD8-D6EF-4962-83D5-6E5CFE9CE148}","EventID":1100,"Version":0,"Task":103,"OpcodeValue":0,"Keywords":4620693217682128896,"EventTime":"2022-12-14T14:39:07.1686183Z","RecordNumber":114371,"ProcessID":496,"ThreadID":204,"Channel":"Security","Hostname":"win10.windomain.local","EventType":"AUDIT_SUCCESS","Severity":"INFO","SeverityValue":2,"UserData":"","Message":"The event logging service has shut down.","Category":"Service shutdown","Opcode":"Info","OpenWEC":{"IpAddress":"192.168.58.100","TimeReceived":"2024-03-14T13:54:20.331+00:00","Principal":"WIN10$@WINDOMAIN.LOCAL","Client":"WIN10$@WINDOMAIN.LOCAL","Subscription":{"Uuid":"8B18D83D-2964-4F35-AC3B-6F4E6FFA727B","Version":"188BB736-9441-5C66-188B-B73694415C66","Name":"Test","Uri":"/this/is/a/test","ClientRevision":"TOTO","ServerRevision":"BABAR"},"Node":"openwec"},"EventReceivedTime":"2024-03-14T13:54:20.331+00:00"}"#; #[test] fn test_serialize_1100() { diff --git a/server/src/formats/raw_json.rs b/server/src/formats/raw_json.rs index 69f474a7..833a49dc 100644 --- a/server/src/formats/raw_json.rs +++ b/server/src/formats/raw_json.rs @@ -22,8 +22,11 @@ struct Metadata { addr: String, #[serde(rename = "TimeReceived")] time_received: String, + // deprecated, will disappear at some point #[serde(rename = "Principal")] principal: String, + #[serde(rename = "Client")] + client: String, #[serde(rename = "Subscription")] subscription: SubscriptionType, #[serde(rename = "Node", skip_serializing_if = "Option::is_none")] @@ -50,7 +53,8 @@ impl Metadata { pub fn new(metadata: &EventMetadata) -> Self { Self { addr: metadata.addr().ip().to_string(), - principal: metadata.principal().to_owned(), // TODO : change to something that works for TLS as well (modify db and output) + principal: metadata.client().to_owned(), + client: metadata.client().to_owned(), node: metadata.node_name().cloned(), time_received: metadata.time_received().to_rfc3339(), subscription: SubscriptionType { @@ -130,7 +134,7 @@ Type 1 is a full token with no privileges removed or groups disabled. A full to Type 2 is an elevated token with no privileges removed or groups disabled. An elevated token is used when User Account Control is enabled and the user chooses to start the program using Run as administrator. An elevated token is also used when an application is configured to always require administrative privilege or to always require maximum privilege, and the user is a member of the Administrators group. Type 3 is a limited token with administrative privileges removed and administrative groups disabled. The limited token is used when User Account Control is enabled, the application does not require administrative privilege, and the user does not choose to start the program using Run as administrator.InformationProcess CreationInfoSecurityMicrosoft Windows security auditing.Audit Success"#; - const EVENT_4688_JSON: &str = r#"{"meta":{"IpAddress":"192.168.58.100","TimeReceived":"2022-12-14T16:07:03.331+00:00","Principal":"WIN10$@WINDOMAIN.LOCAL","Subscription":{"Uuid":"8B18D83D-2964-4F35-AC3B-6F4E6FFA727B","Version":"188BB736-9441-5C66-188B-B73694415C66","Name":"Test","Uri":"/this/is/a/test","ClientRevision":"1234","ServerRevision":"tutu"},"Node":"openwec"},"data":"4688201331200x8020000000000000114689Securitywin10.windomain.localS-1-5-18WIN10$WINDOMAIN0x3e70x3a8C:\\Program Files (x86)\\Microsoft\\EdgeUpdate\\MicrosoftEdgeUpdate.exe%%19360x240S-1-0-0--0x0C:\\Windows\\System32\\services.exeS-1-16-16384A new process has been created.\n\nCreator Subject:\n\tSecurity ID:\t\tS-1-5-18\n\tAccount Name:\t\tWIN10$\n\tAccount Domain:\t\tWINDOMAIN\n\tLogon ID:\t\t0x3E7\n\nTarget Subject:\n\tSecurity ID:\t\tS-1-0-0\n\tAccount Name:\t\t-\n\tAccount Domain:\t\t-\n\tLogon ID:\t\t0x0\n\nProcess Information:\n\tNew Process ID:\t\t0x3a8\n\tNew Process Name:\tC:\\Program Files (x86)\\Microsoft\\EdgeUpdate\\MicrosoftEdgeUpdate.exe\n\tToken Elevation Type:\t%%1936\n\tMandatory Label:\t\tS-1-16-16384\n\tCreator Process ID:\t0x240\n\tCreator Process Name:\tC:\\Windows\\System32\\services.exe\n\tProcess Command Line:\t\n\nToken Elevation Type indicates the type of token that was assigned to the new process in accordance with User Account Control policy.\n\nType 1 is a full token with no privileges removed or groups disabled. A full token is only used if User Account Control is disabled or if the user is the built-in Administrator account or a service account.\n\nType 2 is an elevated token with no privileges removed or groups disabled. An elevated token is used when User Account Control is enabled and the user chooses to start the program using Run as administrator. An elevated token is also used when an application is configured to always require administrative privilege or to always require maximum privilege, and the user is a member of the Administrators group.\n\nType 3 is a limited token with administrative privileges removed and administrative groups disabled. The limited token is used when User Account Control is enabled, the application does not require administrative privilege, and the user does not choose to start the program using Run as administrator.InformationProcess CreationInfoSecurityMicrosoft Windows security auditing.Audit Success"}"#; + const EVENT_4688_JSON: &str = r#"{"meta":{"IpAddress":"192.168.58.100","TimeReceived":"2022-12-14T16:07:03.331+00:00","Principal":"WIN10$@WINDOMAIN.LOCAL","Client":"WIN10$@WINDOMAIN.LOCAL","Subscription":{"Uuid":"8B18D83D-2964-4F35-AC3B-6F4E6FFA727B","Version":"188BB736-9441-5C66-188B-B73694415C66","Name":"Test","Uri":"/this/is/a/test","ClientRevision":"1234","ServerRevision":"tutu"},"Node":"openwec"},"data":"4688201331200x8020000000000000114689Securitywin10.windomain.localS-1-5-18WIN10$WINDOMAIN0x3e70x3a8C:\\Program Files (x86)\\Microsoft\\EdgeUpdate\\MicrosoftEdgeUpdate.exe%%19360x240S-1-0-0--0x0C:\\Windows\\System32\\services.exeS-1-16-16384A new process has been created.\n\nCreator Subject:\n\tSecurity ID:\t\tS-1-5-18\n\tAccount Name:\t\tWIN10$\n\tAccount Domain:\t\tWINDOMAIN\n\tLogon ID:\t\t0x3E7\n\nTarget Subject:\n\tSecurity ID:\t\tS-1-0-0\n\tAccount Name:\t\t-\n\tAccount Domain:\t\t-\n\tLogon ID:\t\t0x0\n\nProcess Information:\n\tNew Process ID:\t\t0x3a8\n\tNew Process Name:\tC:\\Program Files (x86)\\Microsoft\\EdgeUpdate\\MicrosoftEdgeUpdate.exe\n\tToken Elevation Type:\t%%1936\n\tMandatory Label:\t\tS-1-16-16384\n\tCreator Process ID:\t0x240\n\tCreator Process Name:\tC:\\Windows\\System32\\services.exe\n\tProcess Command Line:\t\n\nToken Elevation Type indicates the type of token that was assigned to the new process in accordance with User Account Control policy.\n\nType 1 is a full token with no privileges removed or groups disabled. A full token is only used if User Account Control is disabled or if the user is the built-in Administrator account or a service account.\n\nType 2 is an elevated token with no privileges removed or groups disabled. An elevated token is used when User Account Control is enabled and the user chooses to start the program using Run as administrator. An elevated token is also used when an application is configured to always require administrative privilege or to always require maximum privilege, and the user is a member of the Administrators group.\n\nType 3 is a limited token with administrative privileges removed and administrative groups disabled. The limited token is used when User Account Control is enabled, the application does not require administrative privilege, and the user does not choose to start the program using Run as administrator.InformationProcess CreationInfoSecurityMicrosoft Windows security auditing.Audit Success"}"#; #[test] fn test_json_format_4688() { diff --git a/server/src/lib.rs b/server/src/lib.rs index 7b932113..9118de30 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -93,7 +93,7 @@ impl TryFrom<&Request> for RequestCategory { } pub struct RequestData { - principal: String, + client: String, remote_addr: SocketAddr, category: RequestCategory, uri: String, @@ -101,9 +101,9 @@ pub struct RequestData { } impl RequestData { - fn new(principal: &str, remote_addr: &SocketAddr, req: &Request) -> Result { + fn new(client: &str, remote_addr: &SocketAddr, req: &Request) -> Result { Ok(RequestData { - principal: principal.to_owned(), + client: client.to_owned(), remote_addr: remote_addr.to_owned(), category: RequestCategory::try_from(req)?, method: req.method().to_string(), @@ -111,9 +111,9 @@ impl RequestData { }) } - /// Get a reference to the request data's principal. - pub fn principal(&self) -> &str { - self.principal.as_ref() + /// Get a reference to the request data's client. + pub fn client(&self) -> &str { + self.client.as_ref() } /// Get a reference to the request data's remote addr. @@ -195,7 +195,7 @@ async fn get_request_payload( { counter!(HTTP_REQUEST_BODY_NETWORK_SIZE_BYTES_COUNTER, HTTP_REQUEST_URI => request_data.uri().to_string(), - MACHINE => request_data.principal().to_string()) + MACHINE => request_data.client().to_string()) } _ => { counter!(HTTP_REQUEST_BODY_NETWORK_SIZE_BYTES_COUNTER, @@ -219,7 +219,7 @@ async fn get_request_payload( { counter!(HTTP_REQUEST_BODY_REAL_SIZE_BYTES_COUNTER, HTTP_REQUEST_URI => request_data.uri().to_string(), - MACHINE => request_data.principal().to_string()) + MACHINE => request_data.client().to_string()) } _ => { counter!(HTTP_REQUEST_BODY_REAL_SIZE_BYTES_COUNTER, @@ -436,7 +436,7 @@ fn log_response( uri: &str, start: &Instant, status: StatusCode, - principal: &str, + client: &str, conn_status: ConnectionStatus, ) { let duration = start.elapsed().as_secs_f64(); @@ -458,7 +458,9 @@ fn log_response( log_mdc::insert("response_time", format!("{:.3}", duration * 1000.0)); log_mdc::insert("ip", addr.ip().to_string()); log_mdc::insert("port", addr.port().to_string()); - log_mdc::insert("principal", principal); + log_mdc::insert("client", client); + // "principal" is kept for compatibility + log_mdc::insert("principal", client); log_mdc::insert("conn_status", conn_status.as_str()); // Empty message, logging pattern should use MDC @@ -498,8 +500,8 @@ async fn handle( let uri = req.uri().to_string(); // Check authentication - let (principal, mut response_builder) = match authenticate(&auth_ctx, &req, &addr).await { - Ok((principal, builder)) => (principal, builder), + let (client, mut response_builder) = match authenticate(&auth_ctx, &req, &addr).await { + Ok((client, builder)) => (client, builder), Err(_) => { let status = StatusCode::UNAUTHORIZED; log_response( @@ -524,9 +526,9 @@ async fn handle( } }; - debug!("Successfully authenticated {}", principal); + debug!("Successfully authenticated {}", client); - let request_data = match RequestData::new(&principal, &addr, &req) { + let request_data = match RequestData::new(&client, &addr, &req) { Ok(request_data) => request_data, Err(e) => { error!("Failed to compute request data: {:?}", e); @@ -537,7 +539,7 @@ async fn handle( &uri, &start, status, - &principal, + &client, ConnectionStatus::Alive, ); return Ok(build_error_response(status)); @@ -557,7 +559,7 @@ async fn handle( &uri, &start, status, - &principal, + &client, ConnectionStatus::Alive, ); return Ok(build_error_response(status)); @@ -587,7 +589,7 @@ async fn handle( let auth_ctx_cloned = auth_ctx.clone(); let method_cloned = method.clone(); let uri_cloned = uri.clone(); - let principal_cloned = principal.clone(); + let client_cloned = client.clone(); tokio::spawn(async move { let res = handle_payload( @@ -628,7 +630,7 @@ async fn handle( &uri_cloned, &start, status, - &principal_cloned, + &client_cloned, ConnectionStatus::Aborted, ); } @@ -646,7 +648,7 @@ async fn handle( &uri, &start, status, - &principal, + &client, ConnectionStatus::Alive, ); return Ok(build_error_response(status)); @@ -661,7 +663,7 @@ async fn handle( &uri, &start, status, - &principal, + &client, ConnectionStatus::Alive, ); return Ok(build_error_response(status)); @@ -687,7 +689,7 @@ async fn handle( &uri, &start, status, - &principal, + &client, ConnectionStatus::Alive, ); return Ok(build_error_response(status)); @@ -700,7 +702,7 @@ async fn handle( &uri, &start, response.status(), - &principal, + &client, ConnectionStatus::Alive, ); Ok(response) diff --git a/server/src/logic.rs b/server/src/logic.rs index 42f33169..37914b14 100644 --- a/server/src/logic.rs +++ b/server/src/logic.rs @@ -122,7 +122,7 @@ async fn handle_enumerate( "Received Enumerate request from {}:{} ({}) with URI {}", request_data.remote_addr.ip(), request_data.remote_addr.port(), - request_data.principal(), + request_data.client(), uri ); @@ -179,14 +179,16 @@ async fn handle_enumerate( _ => (), } - // Skip subscriptions that filter out this principal - if !subscription_data.is_active_for(request_data.principal()) { + // Skip subscriptions that filter out this client + let machine_id = message.header().machine_id().map(|m| m.as_str()); + if !subscription_data.is_active_for(request_data.client(), machine_id) { debug!( - "Skip subscription \"{}\" ({}) which principals filter {:?} rejects {}", + "Skip subscription \"{}\" ({}) which client filter {:?} rejects {} ({})", subscription_data.name(), subscription_data.uuid(), - subscription_data.princs_filter(), - request_data.principal() + subscription_data.client_filter(), + request_data.client(), + machine_id.unwrap_or("unknown MachineID"), ); continue; } @@ -237,7 +239,7 @@ async fn handle_enumerate( ); let mut bookmark: Option = db - .get_bookmark(request_data.principal(), &subscription_data.uuid_string()) + .get_bookmark(request_data.client(), &subscription_data.uuid_string()) .await .context("Failed to retrieve current bookmark from database")?; @@ -248,7 +250,7 @@ async fn handle_enumerate( debug!( "Load bookmark of {} for subscription {}: {:?}", - request_data.principal(), + request_data.client(), subscription_data.uuid(), bookmark ); @@ -298,7 +300,7 @@ async fn handle_heartbeat( "Received Heartbeat from {}:{} ({}) for unknown subscription {}", request_data.remote_addr().ip(), request_data.remote_addr().port(), - request_data.principal(), + request_data.client(), subscription_uuid ); return Ok(Response::err(StatusCode::NOT_FOUND)); @@ -306,12 +308,17 @@ async fn handle_heartbeat( } }; - if !subscription.data().is_active_for(request_data.principal()) { + let machine_id = message.header().machine_id().map(|m| m.as_str()); + if !subscription + .data() + .is_active_for(request_data.client(), machine_id) + { debug!( - "Received Heartbeat from {}:{} ({}) for subscription {} ({}) but the principal is not allowed to use the subscription.", + "Received Heartbeat from {}:{} ({}, {}) for subscription {} ({}) but the client is not allowed to use the subscription.", request_data.remote_addr().ip(), request_data.remote_addr().port(), - request_data.principal(), + request_data.client(), + machine_id.unwrap_or("unknown MachineID"), subscription.data().name(), subscription.uuid_string() ); @@ -322,14 +329,14 @@ async fn handle_heartbeat( "Received Heartbeat from {}:{} ({:?}) for subscription {} ({})", request_data.remote_addr().ip(), request_data.remote_addr().port(), - request_data.principal(), + request_data.client(), subscription.data().name(), subscription.uuid_string(), ); store_heartbeat( heartbeat_tx, - request_data.principal(), + request_data.client(), request_data.remote_addr().ip().to_string(), &subscription.uuid_string(), false, @@ -436,12 +443,17 @@ async fn handle_events( } }; - if !subscription.data().is_active_for(request_data.principal()) { + let machine_id = message.header().machine_id().map(|m| m.as_str()); + if !subscription + .data() + .is_active_for(request_data.client(), machine_id) + { debug!( - "Received Events from {}:{} ({}) for subscription {} ({}) but the principal is not allowed to use this subscription.", + "Received Events from {}:{} ({}, {}) for subscription {} ({}) but the client is not allowed to use this subscription.", request_data.remote_addr().ip(), request_data.remote_addr().port(), - request_data.principal(), + request_data.client(), + machine_id.unwrap_or("unknown MachineID"), subscription.data().name(), subscription.uuid_string(), ); @@ -461,7 +473,7 @@ async fn handle_events( events.len(), request_data.remote_addr().ip(), request_data.remote_addr().port(), - request_data.principal(), + request_data.client(), subscription.data().name(), subscription.uuid_string() ); @@ -473,7 +485,7 @@ async fn handle_events( counter!(INPUT_EVENTS_COUNTER, SUBSCRIPTION_NAME => subscription.data().name().to_owned(), SUBSCRIPTION_UUID => subscription.uuid_string(), - MACHINE => request_data.principal().to_string()) + MACHINE => request_data.client().to_string()) } _ => { counter!(INPUT_EVENTS_COUNTER, @@ -488,7 +500,7 @@ async fn handle_events( counter!(INPUT_EVENT_BYTES_COUNTER, SUBSCRIPTION_NAME => subscription.data().name().to_owned(), SUBSCRIPTION_UUID => subscription.uuid_string(), - MACHINE => request_data.principal().to_string()) + MACHINE => request_data.client().to_string()) } _ => { counter!(INPUT_EVENT_BYTES_COUNTER, @@ -505,7 +517,7 @@ async fn handle_events( let metadata = Arc::new(EventMetadata::new( request_data.remote_addr(), - request_data.principal(), + request_data.client(), server.node_name().cloned(), &subscription, public_version.clone(), @@ -610,26 +622,22 @@ async fn handle_events( .bookmarks() .ok_or_else(|| anyhow!("Missing bookmarks in request payload"))?; // Store bookmarks and heartbeats - db.store_bookmark( - request_data.principal(), - &subscription.uuid_string(), - bookmark, - ) - .await - .context("Failed to store bookmarks")?; + db.store_bookmark(request_data.client(), &subscription.uuid_string(), bookmark) + .await + .context("Failed to store bookmarks")?; debug!( "Store bookmark from {}:{} ({}) for subscription {} ({}): {}", request_data.remote_addr().ip(), request_data.remote_addr().port(), - request_data.principal(), + request_data.client(), subscription.data().name(), subscription.uuid_string(), bookmark ); store_heartbeat( heartbeat_tx, - request_data.principal(), + request_data.client(), request_data.remote_addr().ip().to_string(), &subscription.uuid_string(), true, diff --git a/server/src/soap.rs b/server/src/soap.rs index ebf4a1d3..0cb7c715 100644 --- a/server/src/soap.rs +++ b/server/src/soap.rs @@ -428,6 +428,10 @@ impl Header { pub fn revision(&self) -> Option<&String> { self.revision.as_ref() } + + pub fn machine_id(&self) -> Option<&String> { + self.machine_id.as_ref() + } } impl Serializable for Header { diff --git a/subscription.sample.toml b/subscription.sample.toml index cfa42c24..7be1e620 100644 --- a/subscription.sample.toml +++ b/subscription.sample.toml @@ -1,10 +1,10 @@ # autogenerated by openwec 0.3.0 -# Mon, 2 Dec 2024 19:26:21 +0100 +# Mon, 22 Dec 2025 20:42:27 +0100 # Unique identifier of the subscription -uuid = "d9e046ec-92ad-4a18-899f-f5da94108fc8" +uuid = "7a1d16ab-6575-427b-a937-09d2f685cce1" # Unique name of the subscription -name = "subscription-d9e046ec-92ad-4a18-899f-f5da94108fc8" +name = "subscription-7a1d16ab-6575-427b-a937-09d2f685cce1" # Subscription query query = """ @@ -79,17 +79,28 @@ query = """ # Subscription filter (optional) # +# By default, everyone can read the subscription. +# # Filters enables you to choose which clients can read the subscription -# There are two operations available : -# - "Only": only the listed principals will be able to read the subscription -# - "Except": everyone but the listed principals will be able to read the subscription +# There are two operations available: +# - "Only": only the listed clients will be able to read the subscription +# - "Except": everyone but the listed clients will be able to read the subscription # -# By default, everyone can read the subscription. +# You can filter based on the following types: +# - Client: defines clients based on their identifier (from authentication) +# - MachineID: defines clients based on their System.Computer +# The default value is "Client" +# +# Multiple flags can be combined using the bitwise OR operator "|": +# - GlobPattern: targets are interpreted as glob patterns (e.g. "radis*@REALM") +# - CaseInsensitive: targets are compared in a case-insensitive way (off by default) # -# Example to only authorize "courgette@REALM" and "radis@REALM" to read the subscription. +# Example to only authorize clients matching the "courgette@REALM" and "radis*@REALM" patterns to read the subscription. # [filter] # operation = "Only" -# princs = ["courgette@REALM", "radis@REALM"] +# type = "Client" +# flags = "GlobPattern | CaseInsensitive" +# targets = ["courgette@REALM", "radis*@REALM"] # @@ -108,7 +119,7 @@ query = """ # Files driver has the following parameters: # - path (required): the path in which files will be written. It can be parameterized # with variables using the syntax {variable} (see available variables in documentation) -# config = { path = "/var/log/openwec/{ip:2}/{ip:3}/{ip}/{principal}/messages" } +# config = { path = "/var/log/openwec/{ip:2}/{ip:3}/{ip}/{client}/messages" } # Configure a Kafka output