From 280dab6e8c915c4a1a20c4650b2c534a9ca629a2 Mon Sep 17 00:00:00 2001 From: finga Date: Thu, 22 Apr 2021 11:52:02 +0200 Subject: [PATCH 01/65] Support matching boolean values with regex --- Cargo.lock | 2 +- Cargo.toml | 2 +- src/main.rs | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5f8b51b..37dc95e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1202,7 +1202,7 @@ checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" [[package]] name = "webhookey" -version = "0.1.0-rc.0" +version = "0.1.0-rc.1" dependencies = [ "anyhow", "dirs", diff --git a/Cargo.toml b/Cargo.toml index 7c75771..f27176a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "webhookey" -version = "0.1.0-rc.0" +version = "0.1.0-rc.1" authors = ["finga "] edition = "2018" license = "GPL-3.0-or-later" diff --git a/src/main.rs b/src/main.rs index 79c126a..d773821 100644 --- a/src/main.rs +++ b/src/main.rs @@ -204,7 +204,7 @@ fn replace_parameter(input: &str, headers: &HeaderMap, data: &serde_json::Value) fn get_string(value: &serde_json::Value) -> Result { match &value { serde_json::Value::Null => unimplemented!(), - serde_json::Value::Bool(_bool) => unimplemented!(), + serde_json::Value::Bool(bool) => Ok(bool.to_string()), serde_json::Value::Number(number) => Ok(number.to_string()), serde_json::Value::String(string) => Ok(string.as_str().to_string()), serde_json::Value::Array(_array) => unimplemented!(), @@ -229,6 +229,7 @@ fn filter_match( if let Some(json_value) = data.pointer(parameter) { *data.pointer_mut(parameter).unwrap() = match json_value { + serde_json::Value::Bool(bool) => serde_json::Value::String(bool.to_string()), serde_json::Value::String(string) => serde_json::Value::String(string.to_string()), serde_json::Value::Number(number) => serde_json::Value::String(number.to_string()), x => { From 2ddb2d376f07a96995e3cdfb2e91b7621d179593 Mon Sep 17 00:00:00 2001 From: finga Date: Thu, 22 Apr 2021 13:19:03 +0200 Subject: [PATCH 02/65] Cargo update --- Cargo.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 37dc95e..224c50f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -529,9 +529,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "lexical-core" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21f866863575d0e1d654fbeeabdc927292fdf862873dc3c96c6f753357e13374" +checksum = "6607c62aa161d23d17a9072cc5da0be67cdfc89d3afb1e8d9c842bebc2525ffe" dependencies = [ "arrayvec", "bitflags", @@ -928,7 +928,7 @@ checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d" dependencies = [ "proc-macro2 1.0.26", "quote 1.0.9", - "syn 1.0.69", + "syn 1.0.70", ] [[package]] @@ -1004,9 +1004,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.69" +version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48fe99c6bd8b1cc636890bcc071842de909d902c81ac7dab53ba33c421ab8ffb" +checksum = "b9505f307c872bab8eb46f77ae357c8eba1fdacead58ee5a850116b1d7f82883" dependencies = [ "proc-macro2 1.0.26", "quote 1.0.9", @@ -1045,7 +1045,7 @@ checksum = "7765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0" dependencies = [ "proc-macro2 1.0.26", "quote 1.0.9", - "syn 1.0.69", + "syn 1.0.70", ] [[package]] From 29caaff596d025ac3a8f83b389a853916e94f5e0 Mon Sep 17 00:00:00 2001 From: finga Date: Thu, 22 Apr 2021 13:19:28 +0200 Subject: [PATCH 03/65] Fix debian build overwriting config file Add missing `confi-files` parameter to `Cargo.toml`. --- Cargo.lock | 2 +- Cargo.toml | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 224c50f..ec9bfe0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1202,7 +1202,7 @@ checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" [[package]] name = "webhookey" -version = "0.1.0-rc.1" +version = "0.1.0-rc.2" dependencies = [ "anyhow", "dirs", diff --git a/Cargo.toml b/Cargo.toml index f27176a..37ae86b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "webhookey" -version = "0.1.0-rc.1" +version = "0.1.0-rc.2" authors = ["finga "] edition = "2018" license = "GPL-3.0-or-later" @@ -38,3 +38,4 @@ assets = [ ["README.md", "usr/share/doc/cargo-deb/README", "644"], ["debian/service", "lib/systemd/system/webhookey.service", "644"], ] +conf-files = ["/etc/webhookey/config.yml"] From 891a8a70ae7da2d9634fdf8830c93e64a4d0c07d Mon Sep 17 00:00:00 2001 From: finga Date: Sat, 29 May 2021 00:50:48 +0200 Subject: [PATCH 04/65] Update build deps and improve readability The ip filtering is improved as well as the replacing of parameters. The index page is removed. --- Cargo.lock | 202 +++++++++++++------------------------- Cargo.toml | 2 +- README.md | 2 +- src/main.rs | 278 +++++++++++++++++++++++++--------------------------- 4 files changed, 204 insertions(+), 280 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ec9bfe0..b21d842 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -58,9 +58,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "0.7.15" +version = "0.7.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" dependencies = [ "memchr", ] @@ -71,12 +71,6 @@ version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28b2cd92db5cbd74e8e5028f7e27dd7aa3090e89e4f2a197cc7c8dfb69c7063b" -[[package]] -name = "arrayref" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" - [[package]] name = "arrayvec" version = "0.5.2" @@ -110,12 +104,6 @@ dependencies = [ "safemem", ] -[[package]] -name = "base64" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" - [[package]] name = "base64" version = "0.13.0" @@ -140,17 +128,6 @@ dependencies = [ "wyz", ] -[[package]] -name = "blake2b_simd" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587" -dependencies = [ - "arrayref", - "arrayvec", - "constant_time_eq", -] - [[package]] name = "block-buffer" version = "0.9.0" @@ -168,9 +145,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "cc" -version = "1.0.67" +version = "1.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd" +checksum = "4a72c244c1ff497a746a7e1fb3d14bd08420ecda70c8f25c7112f2781652d787" [[package]] name = "cfg-if" @@ -187,12 +164,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "constant_time_eq" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" - [[package]] name = "cookie" version = "0.11.4" @@ -210,10 +181,13 @@ dependencies = [ ] [[package]] -name = "cpuid-bool" -version = "0.1.2" +name = "cpufeatures" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634" +checksum = "ed00c67cb5d0a7d64a44f6ad2668db7e7530311dd53ea79bcd4fb022c64911c8" +dependencies = [ + "libc", +] [[package]] name = "cpuid-bool" @@ -221,17 +195,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcb25d077389e53838a8158c8e99174c5a9d902dee4904320db714f3c653ffba" -[[package]] -name = "crossbeam-utils" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7e9d99fa91428effe99c5c6d4634cdeba32b8cf784fc428a2a687f61a952c49" -dependencies = [ - "autocfg", - "cfg-if", - "lazy_static", -] - [[package]] name = "crypto-mac" version = "0.10.0" @@ -294,18 +257,18 @@ dependencies = [ [[package]] name = "dirs" -version = "3.0.1" +version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "142995ed02755914747cc6ca76fc7e4583cd18578746716d0508ea6ed558b9ff" +checksum = "30baa043103c9d0c2a57cf537cc2f35623889dc0d405e6c3cccfadbc81c71309" dependencies = [ "dirs-sys", ] [[package]] name = "dirs-sys" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e93d7f5705de3e49895a2b5e0b8855a1c27f080192ae9c32a6432d50741a57a" +checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780" dependencies = [ "libc", "redox_users", @@ -359,24 +322,13 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.1.16" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" dependencies = [ "cfg-if", "libc", - "wasi 0.9.0+wasi-snapshot-preview1", -] - -[[package]] -name = "getrandom" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.10.2+wasi-snapshot-preview1", + "wasi", ] [[package]] @@ -438,9 +390,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a1ce40d6fc9764887c2fdc7305c3dcc429ba11ff981c1509416afd5697e4437" +checksum = "f3a87b616e37e93c22fb19bcd386f02f3af5ea98a25670ad0fce773de23c5e68" [[package]] name = "humantime" @@ -542,9 +494,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9385f66bf6105b241aa65a61cb923ef20efc665cb9f9bb50ac2f0c4b7f378d41" +checksum = "789da6d93f1b866ffe175afc5322a4d76c038605a1c3319bb57b06967ca98a36" [[package]] name = "linked-hash-map" @@ -578,9 +530,9 @@ checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" [[package]] name = "memchr" -version = "2.3.4" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" +checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc" [[package]] name = "mime" @@ -660,7 +612,7 @@ version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eebcc4aa140b9abd2bc40d9c3f7ccec842679cd79045ac3a7ac698c1a064b7cd" dependencies = [ - "cpuid-bool 0.2.0", + "cpuid-bool", "opaque-debug", "universal-hash", ] @@ -682,11 +634,11 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.26" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec" +checksum = "f0d8caf72986c1a598726adc988bb5984792ef84f5ee5aa50209145ee8077038" dependencies = [ - "unicode-xid 0.2.1", + "unicode-xid 0.2.2", ] [[package]] @@ -704,7 +656,7 @@ version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" dependencies = [ - "proc-macro2 1.0.26", + "proc-macro2 1.0.27", ] [[package]] @@ -741,7 +693,7 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7" dependencies = [ - "getrandom 0.2.2", + "getrandom", ] [[package]] @@ -755,26 +707,28 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.1.57" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" +checksum = "742739e41cd49414de871ea5e549afb7e2a3ac77b589bcbebe8c82fab37147fc" +dependencies = [ + "bitflags", +] [[package]] name = "redox_users" -version = "0.3.5" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d" +checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" dependencies = [ - "getrandom 0.1.16", + "getrandom", "redox_syscall", - "rust-argon2", ] [[package]] name = "regex" -version = "1.4.5" +version = "1.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "957056ecddbeba1b26965114e191d2e8589ce74db242b6ea25fc4062427a5c19" +checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" dependencies = [ "aho-corasick", "memchr", @@ -783,9 +737,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.23" +version = "0.6.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5f089152e60f62d28b835fbff2cd2e8dc0baf1ac13343bef92ab7eed84548" +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" [[package]] name = "ring" @@ -801,12 +755,12 @@ dependencies = [ [[package]] name = "rocket" -version = "0.4.7" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7febfdfd4d43facfc7daba20349ebe2c310c6735bd6a2a9255ea8bc425b4cb13" +checksum = "4a7ab1dfdc75bb8bd2be381f37796b1b300c45a3c9145b34d86715e8dd90bf28" dependencies = [ "atty", - "base64 0.12.3", + "base64 0.13.0", "log 0.4.14", "memchr", "num_cpus", @@ -822,9 +776,9 @@ dependencies = [ [[package]] name = "rocket_codegen" -version = "0.4.7" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ceac2c55b2c8b1cdc53add64332defa5fc227f64263b86b4114d1386286d42a3" +checksum = "1729e687d6d2cf434d174da84fb948f7fef4fac22d20ce94ca61c28b72dbcf9f" dependencies = [ "devise", "glob", @@ -837,9 +791,9 @@ dependencies = [ [[package]] name = "rocket_http" -version = "0.4.7" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce364100ed7a1bf39257b69ebd014c1d5b4979b0d365d8c9ab0aa9c79645493d" +checksum = "6131e6e6d38a9817f4a494ff5da95971451c2eb56a53915579fc9c80f6ef0117" dependencies = [ "cookie", "hyper", @@ -863,18 +817,6 @@ dependencies = [ "fsio", ] -[[package]] -name = "rust-argon2" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b18820d944b33caa75a71378964ac46f58517c92b6ae5f762636247c09e78fb" -dependencies = [ - "base64 0.13.0", - "blake2b_simd", - "constant_time_eq", - "crossbeam-utils", -] - [[package]] name = "rustls" version = "0.14.0" @@ -913,22 +855,22 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.125" +version = "1.0.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171" +checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.125" +version = "1.0.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d" +checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43" dependencies = [ - "proc-macro2 1.0.26", + "proc-macro2 1.0.27", "quote 1.0.9", - "syn 1.0.70", + "syn 1.0.72", ] [[package]] @@ -956,13 +898,13 @@ dependencies = [ [[package]] name = "sha2" -version = "0.9.3" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa827a14b29ab7f44778d14a88d3cb76e949c45083f7dbfa507d0cb699dc12de" +checksum = "b362ae5752fd2137731f9fa25fd4d9058af34666ca1966fb969119cc35719f12" dependencies = [ "block-buffer", "cfg-if", - "cpuid-bool 0.1.2", + "cpufeatures", "digest", "opaque-debug", ] @@ -1004,13 +946,13 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.70" +version = "1.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9505f307c872bab8eb46f77ae357c8eba1fdacead58ee5a850116b1d7f82883" +checksum = "a1e8cdbefb79a9a5a65e0db8b47b723ee907b7c7f8496c76a1770b5c310bab82" dependencies = [ - "proc-macro2 1.0.26", + "proc-macro2 1.0.27", "quote 1.0.9", - "unicode-xid 0.2.1", + "unicode-xid 0.2.2", ] [[package]] @@ -1030,22 +972,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.24" +version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0f4a65597094d4483ddaed134f409b2cb7c1beccf25201a9f73c719254fa98e" +checksum = "fa6f76457f59514c7eeb4e59d891395fab0b2fd1d40723ae737d64153392e9c6" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.24" +version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0" +checksum = "8a36768c0fbf1bb15eca10defa29526bda730a2376c2ab4393ccfa16fb1a318d" dependencies = [ - "proc-macro2 1.0.26", + "proc-macro2 1.0.27", "quote 1.0.9", - "syn 1.0.70", + "syn 1.0.72", ] [[package]] @@ -1135,9 +1077,9 @@ checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" [[package]] name = "unicode-xid" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" [[package]] name = "universal-hash" @@ -1188,12 +1130,6 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - [[package]] name = "wasi" version = "0.10.2+wasi-snapshot-preview1" diff --git a/Cargo.toml b/Cargo.toml index 37ae86b..0a021c0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,7 +29,7 @@ thiserror = "1.0" run_script = "0.7" [package.metadata.deb] -extended-description = "Webhookey receives requests as for example sent by Gitea's webhooks. Those requests are filtered against configurable filters. When a filter matches values from the header and the body can be passed to scripts which are then executed." +extended-description = "Webhookey receives requests in form of a so called Webhook as for example sent by Gitea. Those requests are matched against configured filters, if a filter matches, values from the header and the body can be passed to scripts as parameters which are then executed subsequently." maintainer-scripts = "debian/" systemd-units = { enable = false } assets = [ diff --git a/README.md b/README.md index 25b32f2..50943c7 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ Webhookey can either be run from the project directory with: ``` or you can copy the produced binary somewhere else from -`webhookey/target/{debug, release}/webhookey` depending on which one +`webhookey/target/{debug,release}/webhookey` depending on which one you built. ## Configuration diff --git a/src/main.rs b/src/main.rs index d773821..7e372f2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,7 +16,6 @@ use regex::Regex; use rocket::{ data::{self, FromDataSimple}, fairing::AdHoc, - get, http::{HeaderMap, Status}, post, routes, Data, Outcome::{Failure, Success}, @@ -41,6 +40,15 @@ enum AddrType { IpNet(IpNet), } +impl AddrType { + fn matches(&self, client_ip: &IpAddr) -> bool { + match self { + AddrType::IpAddr(addr) => addr == client_ip, + AddrType::IpNet(net) => net.contains(client_ip), + } + } +} + #[derive(Debug, Deserialize, Serialize)] #[serde(deny_unknown_fields, rename_all = "lowercase")] enum IpFilter { @@ -48,6 +56,15 @@ enum IpFilter { Deny(Vec), } +impl IpFilter { + fn validate(&self, client_ip: &IpAddr) -> bool { + match self { + IpFilter::Allow(list) => list.iter().any(|i| i.matches(client_ip)), + IpFilter::Deny(list) => !list.iter().any(|i| i.matches(client_ip)), + } + } +} + #[derive(Debug, Deserialize, Serialize)] #[serde(deny_unknown_fields)] struct Config { @@ -74,7 +91,7 @@ struct Filter { #[derive(Debug, Error)] enum WebhookeyError { #[error("Could not extract signature from header")] - InvalidHeader, + InvalidSignature, #[error("Unauthorized request from `{0}`")] Unauthorized(IpAddr), #[error("Unmatched hook from `{0}`")] @@ -86,58 +103,29 @@ enum WebhookeyError { } #[derive(Debug)] -struct Hooks(HashMap); +struct Hooks { + inner: HashMap, +} fn accept_ip(hook_name: &str, client_ip: &IpAddr, ip_filter: &Option) -> bool { match ip_filter { - Some(IpFilter::Allow(list)) => { - for i in list { - match i { - AddrType::IpAddr(addr) => { - if addr == client_ip { - info!("Allow hook `{}` from {}", &hook_name, &addr); - return true; - } - } - AddrType::IpNet(net) => { - if net.contains(client_ip) { - info!("Allow hook `{}` from {}", &hook_name, &net); - return true; - } - } - } + Some(filter) => { + if filter.validate(client_ip) { + info!("Allow hook `{}` from {}", &hook_name, &client_ip); + true + } else { + warn!("Deny hook `{}` from {}", &hook_name, &client_ip); + false } - - warn!("Deny hook `{}` from {}", &hook_name, &client_ip); - return false; } - Some(IpFilter::Deny(list)) => { - for i in list { - match i { - AddrType::IpAddr(addr) => { - if addr == client_ip { - warn!("Deny hook `{}` from {}", &hook_name, &addr); - return false; - } - } - AddrType::IpNet(net) => { - if net.contains(client_ip) { - warn!("Deny hook `{}` from {}", &hook_name, &net); - return false; - } - } - } - } - - info!("Allow hook `{}` from {}", &hook_name, &client_ip) + None => { + info!( + "Allow hook `{}` from {}, no IP filter was configured", + &hook_name, &client_ip + ); + true } - None => info!( - "Allow hook `{}` from {} as no IP filter was configured", - &hook_name, &client_ip - ), } - - true } fn validate_request(secret: &str, signature: &str, data: &[u8]) -> Result<()> { @@ -161,7 +149,31 @@ fn get_parameter(input: &str) -> Result> { Ok(result) } -fn replace_parameter(input: &str, headers: &HeaderMap, data: &serde_json::Value) -> Result { +fn get_header_field<'a>(headers: &'a HeaderMap, param: &[&str]) -> Result<&'a str> { + headers + .get_one( + param + .get(1) + .ok_or_else(|| anyhow!("Missing parameter for `header` expression"))?, + ) + .ok_or_else(|| anyhow!("Could not extract event parameter from header")) +} + +fn get_value_from_pointer<'a>(data: &'a serde_json::Value, pointer: &'a str) -> Result<&'a str> { + let value = data + .pointer(pointer) + .ok_or_else(|| anyhow!("Could not get field from pointer {}", pointer))?; + + value + .as_str() + .ok_or_else(|| anyhow!("Could not convert value `{}` to string", value)) +} + +fn replace_parameters( + input: &str, + headers: &HeaderMap, + data: &serde_json::Value, +) -> Result { let parse: IResult<&str, Vec<&str>> = many0(alt(( map_res( delimited(tag("{{"), take_until("}}"), tag("}}")), @@ -169,23 +181,8 @@ fn replace_parameter(input: &str, headers: &HeaderMap, data: &serde_json::Value) let expr = param.trim().split(' ').collect::>(); match expr.get(0) { - Some(&"header") => { - if let Some(field) = expr.get(1) { - match headers.get_one(field) { - Some(value) => Ok(value), - _ => bail!("Could not extract event parameter from header"), - } - } else { - bail!("Missing parameter for `header` expression"); - } - } - Some(pointer) => match data.pointer(pointer) { - Some(value) => match value.as_str() { - Some(value) => Ok(value), - _ => bail!("Could not convert value `{}` to string", value), - }, - _ => bail!("Could not convert field `{}` to string", param.trim()), - }, + Some(&"header") => get_header_field(headers, &expr), + Some(pointer) => get_value_from_pointer(data, &pointer), None => bail!("Missing expression in `{}`", input), } }, @@ -203,12 +200,13 @@ fn replace_parameter(input: &str, headers: &HeaderMap, data: &serde_json::Value) fn get_string(value: &serde_json::Value) -> Result { match &value { - serde_json::Value::Null => unimplemented!(), serde_json::Value::Bool(bool) => Ok(bool.to_string()), serde_json::Value::Number(number) => Ok(number.to_string()), serde_json::Value::String(string) => Ok(string.as_str().to_string()), - serde_json::Value::Array(_array) => unimplemented!(), - serde_json::Value::Object(_object) => unimplemented!(), + x => { + error!("Could not get string from: {:?}", x); + unimplemented!() + } } } @@ -228,15 +226,8 @@ fn filter_match( let parameter = parameter.trim(); if let Some(json_value) = data.pointer(parameter) { - *data.pointer_mut(parameter).unwrap() = match json_value { - serde_json::Value::Bool(bool) => serde_json::Value::String(bool.to_string()), - serde_json::Value::String(string) => serde_json::Value::String(string.to_string()), - serde_json::Value::Number(number) => serde_json::Value::String(number.to_string()), - x => { - error!("Could not get string from: {:?}", x); - unimplemented!() - } - } + *data.pointer_mut(parameter).unwrap() = + serde_json::Value::String(get_string(json_value)?); } } @@ -246,7 +237,7 @@ fn filter_match( if regex.is_match(&value) { debug!("Filter `{}` of hook `{}` matched", filter_name, hook_name); - return Ok(Some(replace_parameter( + return Ok(Some(replace_parameters( &hook.command, &request.headers(), data, @@ -272,47 +263,56 @@ fn execute_hooks(request: &Request, data: Data) -> Result let config = request.guard::>().unwrap(); // should never fail let mut valid = false; - let mut hooks = HashMap::new(); + let mut result = HashMap::new(); let client_ip = &request .client_ip() .unwrap_or(IpAddr::V4(Ipv4Addr::UNSPECIFIED)); - for (hook_name, hook) in &config.hooks { - if accept_ip(&hook_name, &client_ip, &hook.ip_filter) { - if let Some(signature) = request.headers().get_one(&hook.signature) { - for secret in &hook.secrets { - match validate_request(&secret, &signature, &buffer) { - Ok(()) => { - trace!("Valid signature found for hook `{}`", hook_name,); + let hooks = config + .hooks + .iter() + .filter(|(name, hook)| accept_ip(&name, &client_ip, &hook.ip_filter)); - valid = true; + for (hook_name, hook) in hooks { + let signature = request + .headers() + .get_one(&hook.signature) + .ok_or_else(|| WebhookeyError::InvalidSignature)?; - let mut data: serde_json::Value = - serde_json::from_slice(&buffer).map_err(WebhookeyError::Serde)?; + let secrets = hook + .secrets + .iter() + .map(|secret| validate_request(&secret, &signature, &buffer)); - for (filter_name, filter) in &hook.filters { - match filter_match( - &hook_name, - &hook, - &filter_name, - &filter, - &request, - &mut data, - ) { - Ok(Some(command)) => { - hooks.insert(hook_name.to_string(), command); - break; - } - Ok(None) => {} - Err(e) => error!("{}", e), - } + for secret in secrets { + match secret { + Ok(()) => { + trace!("Valid signature found for hook `{}`", hook_name); + + valid = true; + + let mut data: serde_json::Value = + serde_json::from_slice(&buffer).map_err(WebhookeyError::Serde)?; + + for (filter_name, filter) in &hook.filters { + match filter_match( + &hook_name, + &hook, + &filter_name, + &filter, + &request, + &mut data, + ) { + Ok(Some(command)) => { + result.insert(hook_name.to_string(), command); + break; } + Ok(None) => {} + Err(e) => error!("{}", e), } - Err(e) => trace!("Hook `{}` could not validate request: {}", &hook_name, e), } } - } else { - return Err(WebhookeyError::InvalidHeader); + Err(e) => trace!("Hook `{}` could not validate request: {}", &hook_name, e), } } } @@ -321,7 +321,7 @@ fn execute_hooks(request: &Request, data: Data) -> Result return Err(WebhookeyError::Unauthorized(*client_ip)); } - Ok(Hooks(hooks)) + Ok(Hooks { inner: result }) } impl FromDataSimple for Hooks { @@ -330,7 +330,7 @@ impl FromDataSimple for Hooks { fn from_data(request: &Request, data: Data) -> data::Outcome { match execute_hooks(&request, data) { Ok(hooks) => { - if hooks.0.is_empty() { + if hooks.inner.is_empty() { let client_ip = &request .client_ip() .unwrap_or(IpAddr::V4(Ipv4Addr::UNSPECIFIED)); @@ -353,26 +353,21 @@ impl FromDataSimple for Hooks { } } -#[get("/")] -fn index() -> &'static str { - "Hello, webhookey!" -} - #[post("/", format = "json", data = "")] fn receive_hook<'a>(address: SocketAddr, hooks: Hooks) -> Result> { info!("Post request received from: {}", address); - for hook in hooks.0 { - info!("Execute `{}` from hook `{}`", &hook.1, &hook.0); + for (name, command) in hooks.inner { + info!("Execute `{}` from hook `{}`", &command, &name); - match run_script::run(&hook.1, &vec![], &ScriptOptions::new()) { + match run_script::run(&command, &vec![], &ScriptOptions::new()) { Ok((status, stdout, stderr)) => { - info!("Command `{}` exited with return code: {}", &hook.1, status); - trace!("Output of command `{}` on stdout: {:?}", &hook.1, &stdout); - debug!("Output of command `{}` on stderr: {:?}", &hook.1, &stderr); + info!("Command `{}` exited with return code: {}", &command, status); + trace!("Output of command `{}` on stdout: {:?}", &command, &stdout); + debug!("Output of command `{}` on stderr: {:?}", &command, &stderr); } Err(e) => { - error!("Execution of `{}` failed: {}", &hook.1, e); + error!("Execution of `{}` failed: {}", &command, e); } } } @@ -381,12 +376,14 @@ fn receive_hook<'a>(address: SocketAddr, hooks: Hooks) -> Result> { } fn get_config() -> Result { + // Look for systemwide config.. if let Ok(config) = File::open("/etc/webhookey/config.yml") { info!("Loading configuration from `/etc/webhookey/config.yml`"); return Ok(config); } + // ..look for user path config.. if let Some(mut path) = dirs::config_dir() { path.push("webhookey/config.yml"); @@ -400,12 +397,14 @@ fn get_config() -> Result { } } + // ..look for config in CWD.. if let Ok(config) = File::open("config.yml") { info!("Loading configuration from `./config.yml`"); return Ok(config); } + // ..you had your chance. bail!("No configuration file found."); } @@ -417,7 +416,7 @@ fn main() -> Result<()> { trace!("Parsed configuration:\n{}", serde_yaml::to_string(&config)?); rocket::ignite() - .mount("/", routes![index, receive_hook]) + .mount("/", routes![receive_hook]) .attach(AdHoc::on_attach("webhookey config", move |rocket| { Ok(rocket.manage(config)) })) @@ -435,17 +434,6 @@ mod tests { }; use serde_json::json; - #[test] - fn index() { - let rocket = rocket::ignite().mount("/", routes![index]); - - let client = Client::new(rocket).unwrap(); - let mut response = client.get("/").dispatch(); - - assert_eq!(response.status(), Status::Ok); - assert_eq!(response.body_string(), Some("Hello, webhookey!".into())); - } - #[test] fn secret() { let mut hooks = HashMap::new(); @@ -520,42 +508,42 @@ mod tests { map.add_raw("X-Gitea-Event", "something"); assert_eq!( - replace_parameter("command", &map, &serde_json::Value::Null).unwrap(), + replace_parameters("command", &map, &serde_json::Value::Null).unwrap(), "command" ); assert_eq!( - replace_parameter(" command", &map, &serde_json::Value::Null).unwrap(), + replace_parameters(" command", &map, &serde_json::Value::Null).unwrap(), " command" ); assert_eq!( - replace_parameter("command ", &map, &serde_json::Value::Null).unwrap(), + replace_parameters("command ", &map, &serde_json::Value::Null).unwrap(), "command " ); assert_eq!( - replace_parameter(" command ", &map, &serde_json::Value::Null).unwrap(), + replace_parameters(" command ", &map, &serde_json::Value::Null).unwrap(), " command " ); assert_eq!( - replace_parameter("command command ", &map, &serde_json::Value::Null).unwrap(), + replace_parameters("command command ", &map, &serde_json::Value::Null).unwrap(), "command command " ); assert_eq!( - replace_parameter("{{ /foo }} command", &map, &json!({ "foo": "bar" })).unwrap(), + replace_parameters("{{ /foo }} command", &map, &json!({ "foo": "bar" })).unwrap(), "bar command" ); assert_eq!( - replace_parameter(" command {{ /foo }} ", &map, &json!({ "foo": "bar" })).unwrap(), + replace_parameters(" command {{ /foo }} ", &map, &json!({ "foo": "bar" })).unwrap(), " command bar " ); assert_eq!( - replace_parameter( + replace_parameters( "{{ /foo }} command{{/field1/foo}}", &map, &json!({ "foo": "bar", "field1": { "foo": "baz" } }) @@ -565,12 +553,12 @@ mod tests { ); assert_eq!( - replace_parameter(" command {{ /foo }} ", &map, &json!({ "foo": "bar" })).unwrap(), + replace_parameters(" command {{ /foo }} ", &map, &json!({ "foo": "bar" })).unwrap(), " command bar " ); assert_eq!( - replace_parameter( + replace_parameters( " {{ /field1/foo }} command", &map, &json!({ "field1": { "foo": "bar" } }) @@ -580,7 +568,7 @@ mod tests { ); assert_eq!( - replace_parameter( + replace_parameters( " {{ header X-Gitea-Event }} command", &map, &json!({ "field1": { "foo": "bar" } }) From 43b7fd562584649467188c7af34a22fe5428f471 Mon Sep 17 00:00:00 2001 From: finga Date: Mon, 31 May 2021 02:16:22 +0200 Subject: [PATCH 05/65] Support so called conjunction filters This introduces thee so called conjunction filters and therefore restructures the configuration file. The most obvious changes from an users perspective are that the `filters` field was renamed to `filter` and can, from now on, only support a single filter at first level. Thats why now different filter types are implemented, please consult the readme for further information on their usage. To reflect the changes the readme file is updated as well as the example config file contained in this repository. This is related to #8 --- README.md | 62 ++++++++++------- config.yml | 31 +++++---- src/main.rs | 188 +++++++++++++++++++++++++++++++++++----------------- 3 files changed, 185 insertions(+), 96 deletions(-) diff --git a/README.md b/README.md index 50943c7..ccd79b8 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Webhookey -Webhookey is a webserver listening for requests as for example sent by -gitea's webhooks. Further, Webhookey allows you to specifiy rules +Webhookey is a web server listening for requests as for example sent by +gitea's webhooks. Further, Webhookey allows you to specify rules which are matched against the data received to trigger certain actions. @@ -15,7 +15,7 @@ Further, for Rocket we need to have the nightly toolchain installed: ``` ### Build Webhookey -The webhookey project can be built for development: +The Webhookey project can be built for development: ``` sh cargo b ``` @@ -27,7 +27,7 @@ or for releasing: ### Install Webhookey When a Rust toolchain installed you can also install Webhookey -directly without cloning it manualy: +directly without cloning it manually: ``` sh cargo install --git https://git.onders.org/finga/webhookey.git webhookey ``` @@ -51,7 +51,7 @@ you built. Configuration syntax is YAML and it's paths as well as it's configuration format is described in the following sections. -### Configuration paths +### Configuration Paths Following locations are checked for a configuration file: - `/etc/webhookey/config.yml` - `/webhookey/config.yml` @@ -72,7 +72,7 @@ consists of the following fields: source addresses or ranges. - signature: Name of the HTTP header field containing the signature. - secrets: List of secrets. -- filters: List of filters. +- filter: Tree of filters. Example: ```yaml @@ -87,10 +87,18 @@ hooks: secrets: - secret_key_01 - secret_key_02 - filters: - match_ref: - pointer: /ref - regex: refs/heads/master + filter: + or: + - json: + pointer: /ref + regex: refs/heads/master + - and: + - json: + pointer: /ref + regex: refs/heads/a_branch + - json: + pointer: /after + regex: f6e5fe4fe37df76629112d55cc210718b6a55e7e ``` ##### Command @@ -137,17 +145,25 @@ Set the name of the HTTP header field containing the HMAC signature. Configure a list of secrets to validate the hook. ##### Filter -Each filter must have following fields: -- pointer: pointer to the JSON field according to [RFC - 6901](https://tools.ietf.org/html/rfc6901) -- regex: regular expression which has to match the field pointed to by - the pointer +Filter can be either a concrete filter or a conjunction +filter. Concrete filters return either true or false on specific +constraints. Conjunction filters contain lists of filters which are +evaluated and combined based on the type. The result is either used +for parent conjunction filters or, if at the root, used to decide if a +hook should be executed. -# TODOs -## Use `clap` to parse command line arguments -## Configure rocket via config.yml -## Security -### https support -basically supported, but related to "Configure rocket via config.yml". -### Authentication features -## Use proptest or quickcheck for tests of parsers +###### Conjunction Filters +Conjunction filters contain lists of other filters. +- `and`: Logical conjunction. +- `or`: Logical disjunction. + +###### Concrete Filters +- `json`: + + The `json` filter matches a regular expression on a field from the + received JSON data. + + - pointer: Pointer to the JSON field according to [RFC + 6901](https://tools.ietf.org/html/rfc6901). + - regex: Regular expression which has to match the field pointed to + by the pointer. diff --git a/config.yml b/config.yml index 0bb3a42..4d57324 100644 --- a/config.yml +++ b/config.yml @@ -9,8 +9,8 @@ hooks: secrets: - secret_key_01 - secret_key_02 - filters: - match_ref: + filter: + json: pointer: /ref regex: refs/heads/master hook2: @@ -22,19 +22,24 @@ hooks: secrets: - secret_key_01 - secret_key_02 - filters: - match_ref: - pointer: /ref - regex: refs/heads/master + filter: + and: + - json: + pointer: /ref + regex: refs/heads/master + - json: + pointer: /after + regex: f6e5fe4fe37df76629112d55cc210718b6a55e7e hook3: command: /usr/bin/local/script_xyz.sh signature: X-Gitea-Signature secrets: - secret_key03 - filters: - match_ref: - pointer: /ref - regex: refs/heads/master - match_after: - pointer: /after - regex: f6e5fe4fe37df76629112d55cc210718b6a55e7e + filter: + or: + - json: + pointer: /ref + regex: refs/heads/master + - json: + pointer: /after + regex: f6e5fe4fe37df76629112d55cc210718b6a55e7e diff --git a/src/main.rs b/src/main.rs index 7e372f2..78704b9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -71,6 +71,95 @@ struct Config { hooks: HashMap, } +#[derive(Debug, Deserialize, Serialize)] +#[serde(deny_unknown_fields)] +struct JsonFilter { + pointer: String, + regex: String, +} + +impl JsonFilter { + fn evaluate(&self, data: &serde_json::Value) -> Result { + trace!( + "Matching `{}` on `{}` from received json", + &self.regex, + &self.pointer, + ); + + let regex = Regex::new(&self.regex).map_err(WebhookeyError::Regex)?; + + if let Some(value) = data.pointer(&self.pointer) { + let value = get_string(value)?; + + if regex.is_match(&value) { + debug!("Regex `{}` for `{}` matches", &self.regex, &self.pointer); + + return Ok(true); + } + } + + debug!( + "Regex `{}` for `{}` does not match", + &self.regex, &self.pointer + ); + + Ok(false) + } +} + +#[derive(Debug, Deserialize, Serialize)] +#[serde(deny_unknown_fields, rename_all = "lowercase")] +enum FilterType { + And(Vec), + Or(Vec), + #[serde(rename = "json")] + JsonFilter(JsonFilter), +} + +impl FilterType { + fn evaluate( + &self, + request: &Request, + data: &serde_json::Value, + ) -> Result { + match self { + FilterType::And(filters) => { + let (results, errors): (Vec<_>, Vec<_>) = filters + .iter() + .map(|filter| filter.evaluate(request, data)) + .partition(Result::is_ok); + + if errors.is_empty() { + Ok(results.iter().all(|r| *r.as_ref().unwrap())) // should never fail + } else { + errors.iter().for_each(|e| { + error!("Could not evaluate Filter: {}", e.as_ref().unwrap_err()) + }); + + Err(WebhookeyError::InvalidFilter) + } + } + FilterType::Or(filters) => { + let (results, errors): (Vec<_>, Vec<_>) = filters + .iter() + .map(|filter| filter.evaluate(request, data)) + .partition(Result::is_ok); + + if errors.is_empty() { + Ok(results.iter().any(|r| *r.as_ref().unwrap())) // should never fail + } else { + errors.iter().for_each(|e| { + error!("Could not evaluate Filter: {}", e.as_ref().unwrap_err()) + }); + + Err(WebhookeyError::InvalidFilter) + } + } + FilterType::JsonFilter(filter) => filter.evaluate(data), + } + } +} + #[derive(Debug, Deserialize, Serialize)] #[serde(deny_unknown_fields)] struct Hook { @@ -78,14 +167,7 @@ struct Hook { signature: String, ip_filter: Option, secrets: Vec, - filters: HashMap, -} - -#[derive(Debug, Deserialize, Serialize)] -#[serde(deny_unknown_fields)] -struct Filter { - pointer: String, - regex: String, + filter: FilterType, } #[derive(Debug, Error)] @@ -96,10 +178,16 @@ enum WebhookeyError { Unauthorized(IpAddr), #[error("Unmatched hook from `{0}`")] UnmatchedHook(IpAddr), + #[error("Could not find field refered to in parameter `{0}`")] + InvalidParameterPointer(String), + #[error("Could not evaluate filter request")] + InvalidFilter, #[error("IO Error")] Io(std::io::Error), #[error("Serde Error")] Serde(serde_json::Error), + #[error("Regex Error")] + Regex(regex::Error), } #[derive(Debug)] @@ -198,7 +286,7 @@ fn replace_parameters( Ok(result.join("")) } -fn get_string(value: &serde_json::Value) -> Result { +fn get_string(value: &serde_json::Value) -> Result { match &value { serde_json::Value::Bool(bool) => Ok(bool.to_string()), serde_json::Value::Number(number) => Ok(number.to_string()), @@ -210,50 +298,29 @@ fn get_string(value: &serde_json::Value) -> Result { } } -fn filter_match( +fn get_command( hook_name: &str, hook: &Hook, - filter_name: &str, - filter: &Filter, request: &Request, data: &mut serde_json::Value, -) -> Result> { - trace!("Matching filter `{}` of hook `{}`", filter_name, hook_name); - - let regex = Regex::new(&filter.regex)?; +) -> Result { + trace!("Replacing parameters for command of hook `{}`", hook_name); for parameter in get_parameter(&hook.command)? { let parameter = parameter.trim(); if let Some(json_value) = data.pointer(parameter) { - *data.pointer_mut(parameter).unwrap() = + *data + .pointer_mut(parameter) + .ok_or_else(|| WebhookeyError::InvalidParameterPointer(parameter.to_string()))? = serde_json::Value::String(get_string(json_value)?); } } - if let Some(value) = data.pointer(&filter.pointer) { - let value = get_string(value)?; - - if regex.is_match(&value) { - debug!("Filter `{}` of hook `{}` matched", filter_name, hook_name); - - return Ok(Some(replace_parameters( - &hook.command, - &request.headers(), - data, - )?)); - } - } - - debug!( - "Filter `{}` of hook `{}` did not match", - filter_name, hook_name - ); - - Ok(None) + replace_parameters(&hook.command, &request.headers(), data) } -fn execute_hooks(request: &Request, data: Data) -> Result { +fn get_commands(request: &Request, data: Data) -> Result { let mut buffer = Vec::new(); let size = data .open() @@ -277,7 +344,7 @@ fn execute_hooks(request: &Request, data: Data) -> Result let signature = request .headers() .get_one(&hook.signature) - .ok_or_else(|| WebhookeyError::InvalidSignature)?; + .ok_or(WebhookeyError::InvalidSignature)?; let secrets = hook .secrets @@ -294,21 +361,17 @@ fn execute_hooks(request: &Request, data: Data) -> Result let mut data: serde_json::Value = serde_json::from_slice(&buffer).map_err(WebhookeyError::Serde)?; - for (filter_name, filter) in &hook.filters { - match filter_match( - &hook_name, - &hook, - &filter_name, - &filter, - &request, - &mut data, - ) { - Ok(Some(command)) => { + match hook.filter.evaluate(request, &data) { + Ok(true) => match get_command(&hook_name, &hook, &request, &mut data) { + Ok(command) => { result.insert(hook_name.to_string(), command); break; } - Ok(None) => {} Err(e) => error!("{}", e), + }, + Ok(false) => info!("Filter for `{}` did not match", &hook_name), + Err(error) => { + error!("Could not match filter for `{}`: {}", &hook_name, error) } } } @@ -328,7 +391,7 @@ impl FromDataSimple for Hooks { type Error = WebhookeyError; fn from_data(request: &Request, data: Data) -> data::Outcome { - match execute_hooks(&request, data) { + match get_commands(&request, data) { Ok(hooks) => { if hooks.inner.is_empty() { let client_ip = &request @@ -357,7 +420,7 @@ impl FromDataSimple for Hooks { fn receive_hook<'a>(address: SocketAddr, hooks: Hooks) -> Result> { info!("Post request received from: {}", address); - for (name, command) in hooks.inner { + hooks.inner.iter().for_each(|(name, command)| { info!("Execute `{}` from hook `{}`", &command, &name); match run_script::run(&command, &vec![], &ScriptOptions::new()) { @@ -370,15 +433,15 @@ fn receive_hook<'a>(address: SocketAddr, hooks: Hooks) -> Result> { error!("Execution of `{}` failed: {}", &command, e); } } - } + }); Ok(Response::new()) } fn get_config() -> Result { - // Look for systemwide config.. - if let Ok(config) = File::open("/etc/webhookey/config.yml") { - info!("Loading configuration from `/etc/webhookey/config.yml`"); + // Look for config in CWD.. + if let Ok(config) = File::open("config.yml") { + info!("Loading configuration from `./config.yml`"); return Ok(config); } @@ -397,9 +460,9 @@ fn get_config() -> Result { } } - // ..look for config in CWD.. - if let Ok(config) = File::open("config.yml") { - info!("Loading configuration from `./config.yml`"); + // ..look for systemwide config.. + if let Ok(config) = File::open("/etc/webhookey/config.yml") { + info!("Loading configuration from `/etc/webhookey/config.yml`"); return Ok(config); } @@ -437,6 +500,7 @@ mod tests { #[test] fn secret() { let mut hooks = HashMap::new(); + hooks.insert( "test_hook".to_string(), Hook { @@ -444,9 +508,13 @@ mod tests { signature: "X-Gitea-Signature".to_string(), ip_filter: None, secrets: vec!["valid".to_string()], - filters: HashMap::new(), + filter: FilterType::JsonFilter(JsonFilter { + pointer: "*".to_string(), + regex: "*".to_string(), + }), }, ); + let config = Config { hooks: hooks }; let rocket = rocket::ignite() From d29bfdf88d6b5d02b41fbee5e120db7f20d34eee Mon Sep 17 00:00:00 2001 From: finga Date: Mon, 31 May 2021 16:14:19 +0200 Subject: [PATCH 06/65] Use clap for command line arguments To support command line arguments `clap` is used. This adds following argument `--config`/`-c` to provide a different path for the configurationf file and the subcommand `configtest` which parses and loads the configuration and exits. --- Cargo.lock | 105 ++++++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 1 + src/main.rs | 27 +++++++++++++- 3 files changed, 132 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index b21d842..1f0f72c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -164,6 +164,38 @@ dependencies = [ "generic-array", ] +[[package]] +name = "clap" +version = "3.0.0-beta.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bd1061998a501ee7d4b6d449020df3266ca3124b941ec56cf2005c3779ca142" +dependencies = [ + "atty", + "bitflags", + "clap_derive", + "indexmap", + "lazy_static", + "os_str_bytes", + "strsim", + "termcolor", + "textwrap", + "unicode-width", + "vec_map", +] + +[[package]] +name = "clap_derive" +version = "3.0.0-beta.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "370f715b81112975b1b69db93e0b56ea4cd4e5002ac43b2da8474106a54096a1" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2 1.0.27", + "quote 1.0.9", + "syn 1.0.72", +] + [[package]] name = "cookie" version = "0.11.4" @@ -353,6 +385,15 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" +[[package]] +name = "heck" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cbf45460356b7deeb5e3415b5563308c0a9b057c85e12b06ad551f98d0a6ac" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "hermit-abi" version = "0.1.18" @@ -572,6 +613,12 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +[[package]] +name = "os_str_bytes" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afb2e1c3ee07430c2cf76151675e583e0f19985fa6efae47d6848a3e2c824f85" + [[package]] name = "pear" version = "0.1.4" @@ -623,6 +670,30 @@ version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2 1.0.27", + "quote 1.0.9", + "syn 1.0.72", + "version_check 0.9.3", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2 1.0.27", + "quote 1.0.9", + "version_check 0.9.3", +] + [[package]] name = "proc-macro2" version = "0.4.30" @@ -927,6 +998,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + [[package]] name = "subtle" version = "2.4.0" @@ -970,6 +1047,15 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "textwrap" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "203008d98caf094106cfaba70acfed15e18ed3ddb7d94e49baec153a2b462789" +dependencies = [ + "unicode-width", +] + [[package]] name = "thiserror" version = "1.0.25" @@ -1069,6 +1155,18 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-segmentation" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796" + +[[package]] +name = "unicode-width" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" + [[package]] name = "unicode-xid" version = "0.1.0" @@ -1118,6 +1216,12 @@ dependencies = [ "log 0.4.14", ] +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" + [[package]] name = "version_check" version = "0.1.5" @@ -1141,6 +1245,7 @@ name = "webhookey" version = "0.1.0-rc.2" dependencies = [ "anyhow", + "clap", "dirs", "env_logger", "hex", diff --git a/Cargo.toml b/Cargo.toml index 0a021c0..6506c0e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,6 +27,7 @@ hex = "0.4" ipnet = { version = "2.3", features = ["serde"] } thiserror = "1.0" run_script = "0.7" +clap = "3.0.0-beta.2" [package.metadata.deb] extended-description = "Webhookey receives requests in form of a so called Webhook as for example sent by Gitea. Those requests are matched against configured filters, if a filter matches, values from the header and the body can be passed to scripts as parameters which are then executed subsequently." diff --git a/src/main.rs b/src/main.rs index 78704b9..3494d91 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,7 @@ #![feature(proc_macro_hygiene, decl_macro)] use anyhow::{anyhow, bail, Result}; +use clap::{app_from_crate, App, Arg}; use hmac::{Hmac, Mac, NewMac}; use ipnet::IpNet; use log::{debug, error, info, trace, warn}; @@ -474,10 +475,34 @@ fn get_config() -> Result { fn main() -> Result<()> { env_logger::init(); - let config: Config = serde_yaml::from_reader(BufReader::new(get_config()?))?; + let cli = app_from_crate!() + .arg( + Arg::new("config") + .short('c') + .long("config") + .takes_value(true) + .value_name("FILE") + .about("Provide a path to the configuration file"), + ) + .subcommand( + App::new("configtest") + .about("Verifies if the configuration can be parsed without errors."), + ) + .get_matches(); + + let config: Config = match cli.value_of("config") { + Some(config) => serde_yaml::from_reader(BufReader::new(File::open(config)?))?, + _ => serde_yaml::from_reader(BufReader::new(get_config()?))?, + }; trace!("Parsed configuration:\n{}", serde_yaml::to_string(&config)?); + if let Some(_) = cli.subcommand_matches("configtest") { + debug!("Configtest succeded."); + println!("Config is OK"); + return Ok(()) + } + rocket::ignite() .mount("/", routes![receive_hook]) .attach(AdHoc::on_attach("webhookey config", move |rocket| { From 65430e65b76d6a6c7a813d31472a4a7649ade3dd Mon Sep 17 00:00:00 2001 From: finga Date: Wed, 2 Jun 2021 03:35:43 +0200 Subject: [PATCH 07/65] Restructure and minor improvements In order to keep things together the code was restructured. Some small improvements such as clippy warnings and the validation of a hook in regards of the ip filter. --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 18 +-- src/main.rs | 316 ++++++++++++++++++++++++++-------------------------- 4 files changed, 169 insertions(+), 169 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1f0f72c..114168f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1242,7 +1242,7 @@ checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" [[package]] name = "webhookey" -version = "0.1.0-rc.2" +version = "0.1.0" dependencies = [ "anyhow", "clap", diff --git a/Cargo.toml b/Cargo.toml index 6506c0e..f123f85 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "webhookey" -version = "0.1.0-rc.2" +version = "0.1.0" authors = ["finga "] edition = "2018" license = "GPL-3.0-or-later" diff --git a/README.md b/README.md index ccd79b8..4bad877 100644 --- a/README.md +++ b/README.md @@ -67,12 +67,12 @@ Whereas `` depends on the platform: #### Hooks With `hooks` you can configure a sequence of hooks. A single hook consists of the following fields: -- command: A command to be executed if a filter matches -- allow/deny: An optional parameter to either allow or deny specific - source addresses or ranges. -- signature: Name of the HTTP header field containing the signature. -- secrets: List of secrets. -- filter: Tree of filters. +- `command`: A command to be executed if a filter matches +- `allow`/`deny`: An optional parameter to either allow or deny + specific source addresses or ranges. +- `signature`: Name of the HTTP header field containing the signature. +- `secrets`: List of secrets. +- `filter`: Tree of filters. Example: ```yaml @@ -163,7 +163,7 @@ Conjunction filters contain lists of other filters. The `json` filter matches a regular expression on a field from the received JSON data. - - pointer: Pointer to the JSON field according to [RFC + - `pointer`: Pointer to the JSON field according to [RFC 6901](https://tools.ietf.org/html/rfc6901). - - regex: Regular expression which has to match the field pointed to - by the pointer. + - `regex`: Regular expression which has to match the field pointed + to by the pointer. diff --git a/src/main.rs b/src/main.rs index 3494d91..c352620 100644 --- a/src/main.rs +++ b/src/main.rs @@ -34,6 +34,26 @@ use std::{ net::{IpAddr, Ipv4Addr, SocketAddr}, }; +#[derive(Debug, Error)] +enum WebhookeyError { + #[error("Could not extract signature from header")] + InvalidSignature, + #[error("Unauthorized request from `{0}`")] + Unauthorized(IpAddr), + #[error("Unmatched hook from `{0}`")] + UnmatchedHook(IpAddr), + #[error("Could not find field refered to in parameter `{0}`")] + InvalidParameterPointer(String), + #[error("Could not evaluate filter request")] + InvalidFilter, + #[error("IO Error")] + Io(std::io::Error), + #[error("Serde Error")] + Serde(serde_json::Error), + #[error("Regex Error")] + Regex(regex::Error), +} + #[derive(Debug, Deserialize, Serialize)] #[serde(deny_unknown_fields, untagged)] enum AddrType { @@ -66,12 +86,6 @@ impl IpFilter { } } -#[derive(Debug, Deserialize, Serialize)] -#[serde(deny_unknown_fields)] -struct Config { - hooks: HashMap, -} - #[derive(Debug, Deserialize, Serialize)] #[serde(deny_unknown_fields)] struct JsonFilter { @@ -171,24 +185,27 @@ struct Hook { filter: FilterType, } -#[derive(Debug, Error)] -enum WebhookeyError { - #[error("Could not extract signature from header")] - InvalidSignature, - #[error("Unauthorized request from `{0}`")] - Unauthorized(IpAddr), - #[error("Unmatched hook from `{0}`")] - UnmatchedHook(IpAddr), - #[error("Could not find field refered to in parameter `{0}`")] - InvalidParameterPointer(String), - #[error("Could not evaluate filter request")] - InvalidFilter, - #[error("IO Error")] - Io(std::io::Error), - #[error("Serde Error")] - Serde(serde_json::Error), - #[error("Regex Error")] - Regex(regex::Error), +impl Hook { + fn get_command( + &self, + hook_name: &str, + request: &Request, + data: &mut serde_json::Value, + ) -> Result { + trace!("Replacing parameters for command of hook `{}`", hook_name); + + for parameter in get_parameter(&self.command)? { + let parameter = parameter.trim(); + + if let Some(json_value) = data.pointer(parameter) { + *data.pointer_mut(parameter).ok_or_else(|| { + WebhookeyError::InvalidParameterPointer(parameter.to_string()) + })? = serde_json::Value::String(get_string(json_value)?); + } + } + + replace_parameters(&self.command, &request.headers(), data) + } } #[derive(Debug)] @@ -196,27 +213,128 @@ struct Hooks { inner: HashMap, } -fn accept_ip(hook_name: &str, client_ip: &IpAddr, ip_filter: &Option) -> bool { - match ip_filter { - Some(filter) => { - if filter.validate(client_ip) { - info!("Allow hook `{}` from {}", &hook_name, &client_ip); - true +impl Hooks { + fn get_commands(request: &Request, data: Data) -> Result { + let mut buffer = Vec::new(); + let size = data + .open() + .read_to_end(&mut buffer) + .map_err(WebhookeyError::Io)?; + info!("Data of size {} received", size); + + let config = request.guard::>().unwrap(); // should never fail + let mut valid = false; + let mut result = HashMap::new(); + let client_ip = &request + .client_ip() + .unwrap_or(IpAddr::V4(Ipv4Addr::UNSPECIFIED)); + + let hooks = config.hooks.iter().filter(|(name, hook)| { + if let Some(ip) = &hook.ip_filter { + return accept_ip(&name, &client_ip, &ip); } else { - warn!("Deny hook `{}` from {}", &hook_name, &client_ip); - false + info!( + "Allow hook `{}` from {}, no IP filter was configured", + &name, &client_ip + ); + true + } + }); + + for (hook_name, hook) in hooks { + let signature = request + .headers() + .get_one(&hook.signature) + .ok_or(WebhookeyError::InvalidSignature)?; + + let secrets = hook + .secrets + .iter() + .map(|secret| validate_request(&secret, &signature, &buffer)); + + for secret in secrets { + match secret { + Ok(()) => { + trace!("Valid signature found for hook `{}`", hook_name); + + valid = true; + + let mut data: serde_json::Value = + serde_json::from_slice(&buffer).map_err(WebhookeyError::Serde)?; + + match hook.filter.evaluate(request, &data) { + Ok(true) => match hook.get_command(&hook_name, &request, &mut data) { + Ok(command) => { + info!("Filter for `{}` matched", &hook_name); + result.insert(hook_name.to_string(), command); + break; + } + Err(e) => error!("{}", e), + }, + Ok(false) => info!("Filter for `{}` did not match", &hook_name), + Err(error) => { + error!("Could not match filter for `{}`: {}", &hook_name, error) + } + } + } + Err(e) => trace!("Hook `{}` could not validate request: {}", &hook_name, e), + } } } - None => { - info!( - "Allow hook `{}` from {}, no IP filter was configured", - &hook_name, &client_ip - ); - true + + if !valid { + return Err(WebhookeyError::Unauthorized(*client_ip)); + } + + Ok(Hooks { inner: result }) + } +} + +impl FromDataSimple for Hooks { + type Error = WebhookeyError; + + fn from_data(request: &Request, data: Data) -> data::Outcome { + match Hooks::get_commands(&request, data) { + Ok(hooks) => { + if hooks.inner.is_empty() { + let client_ip = &request + .client_ip() + .unwrap_or(IpAddr::V4(Ipv4Addr::UNSPECIFIED)); + + warn!("Unmatched hook from {}", &client_ip); + return Failure((Status::NotFound, WebhookeyError::UnmatchedHook(*client_ip))); + } + + Success(hooks) + } + Err(WebhookeyError::Unauthorized(e)) => { + error!("{}", WebhookeyError::Unauthorized(e)); + Failure((Status::Unauthorized, WebhookeyError::Unauthorized(e))) + } + Err(e) => { + error!("{}", e); + Failure((Status::BadRequest, e)) + } } } } +#[derive(Debug, Deserialize, Serialize)] +#[serde(deny_unknown_fields)] +struct Config { + hooks: HashMap, +} + +fn accept_ip(hook_name: &str, client_ip: &IpAddr, ip: &IpFilter) -> bool { + if ip.validate(client_ip) { + info!("Allow hook `{}` from {}", &hook_name, &client_ip); + return true; + } + + warn!("Deny hook `{}` from {}", &hook_name, &client_ip); + false +} + fn validate_request(secret: &str, signature: &str, data: &[u8]) -> Result<()> { let mut mac = Hmac::::new_varkey(&secret.as_bytes()) .map_err(|e| anyhow!("Could not create hasher with secret: {}", e))?; @@ -299,124 +417,6 @@ fn get_string(value: &serde_json::Value) -> Result { } } -fn get_command( - hook_name: &str, - hook: &Hook, - request: &Request, - data: &mut serde_json::Value, -) -> Result { - trace!("Replacing parameters for command of hook `{}`", hook_name); - - for parameter in get_parameter(&hook.command)? { - let parameter = parameter.trim(); - - if let Some(json_value) = data.pointer(parameter) { - *data - .pointer_mut(parameter) - .ok_or_else(|| WebhookeyError::InvalidParameterPointer(parameter.to_string()))? = - serde_json::Value::String(get_string(json_value)?); - } - } - - replace_parameters(&hook.command, &request.headers(), data) -} - -fn get_commands(request: &Request, data: Data) -> Result { - let mut buffer = Vec::new(); - let size = data - .open() - .read_to_end(&mut buffer) - .map_err(WebhookeyError::Io)?; - info!("Data of size {} received", size); - - let config = request.guard::>().unwrap(); // should never fail - let mut valid = false; - let mut result = HashMap::new(); - let client_ip = &request - .client_ip() - .unwrap_or(IpAddr::V4(Ipv4Addr::UNSPECIFIED)); - - let hooks = config - .hooks - .iter() - .filter(|(name, hook)| accept_ip(&name, &client_ip, &hook.ip_filter)); - - for (hook_name, hook) in hooks { - let signature = request - .headers() - .get_one(&hook.signature) - .ok_or(WebhookeyError::InvalidSignature)?; - - let secrets = hook - .secrets - .iter() - .map(|secret| validate_request(&secret, &signature, &buffer)); - - for secret in secrets { - match secret { - Ok(()) => { - trace!("Valid signature found for hook `{}`", hook_name); - - valid = true; - - let mut data: serde_json::Value = - serde_json::from_slice(&buffer).map_err(WebhookeyError::Serde)?; - - match hook.filter.evaluate(request, &data) { - Ok(true) => match get_command(&hook_name, &hook, &request, &mut data) { - Ok(command) => { - result.insert(hook_name.to_string(), command); - break; - } - Err(e) => error!("{}", e), - }, - Ok(false) => info!("Filter for `{}` did not match", &hook_name), - Err(error) => { - error!("Could not match filter for `{}`: {}", &hook_name, error) - } - } - } - Err(e) => trace!("Hook `{}` could not validate request: {}", &hook_name, e), - } - } - } - - if !valid { - return Err(WebhookeyError::Unauthorized(*client_ip)); - } - - Ok(Hooks { inner: result }) -} - -impl FromDataSimple for Hooks { - type Error = WebhookeyError; - - fn from_data(request: &Request, data: Data) -> data::Outcome { - match get_commands(&request, data) { - Ok(hooks) => { - if hooks.inner.is_empty() { - let client_ip = &request - .client_ip() - .unwrap_or(IpAddr::V4(Ipv4Addr::UNSPECIFIED)); - - warn!("Unmatched hook from {}", &client_ip); - return Failure((Status::NotFound, WebhookeyError::UnmatchedHook(*client_ip))); - } - - Success(hooks) - } - Err(WebhookeyError::Unauthorized(e)) => { - error!("{}", WebhookeyError::Unauthorized(e)); - Failure((Status::Unauthorized, WebhookeyError::Unauthorized(e))) - } - Err(e) => { - error!("{}", e); - Failure((Status::BadRequest, e)) - } - } - } -} - #[post("/", format = "json", data = "")] fn receive_hook<'a>(address: SocketAddr, hooks: Hooks) -> Result> { info!("Post request received from: {}", address); @@ -486,7 +486,7 @@ fn main() -> Result<()> { ) .subcommand( App::new("configtest") - .about("Verifies if the configuration can be parsed without errors."), + .about("Verifies if the configuration can be parsed without errors"), ) .get_matches(); @@ -500,7 +500,7 @@ fn main() -> Result<()> { if let Some(_) = cli.subcommand_matches("configtest") { debug!("Configtest succeded."); println!("Config is OK"); - return Ok(()) + return Ok(()); } rocket::ignite() From 33edc4a8b86e9753b327a2f90fc3fdf3c00a2894 Mon Sep 17 00:00:00 2001 From: finga Date: Wed, 30 Jun 2021 23:27:29 +0200 Subject: [PATCH 08/65] Add gitea issue templates --- .gitea/issue_template/bug.md | 31 ++++++++++++++++++++++++++++ .gitea/issue_template/enhancement.md | 16 ++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 .gitea/issue_template/bug.md create mode 100644 .gitea/issue_template/enhancement.md diff --git a/.gitea/issue_template/bug.md b/.gitea/issue_template/bug.md new file mode 100644 index 0000000..abf6a27 --- /dev/null +++ b/.gitea/issue_template/bug.md @@ -0,0 +1,31 @@ +--- + +name: "Bug Report" +about: "Something is not working as expected, file a bug report." +title: "" +labels: +- bug +- "help needed" + +--- + +# What do you want to achieve (expected behaviour)? + +# What is the result? + +# Steps to reproduce the problem + + 1. + 1. + 1. + +# Further information +- Version and commit id: +- Package or build command: +- Run command: + +# Configuration file: + +# System information +- Rust version: +- Operating system: diff --git a/.gitea/issue_template/enhancement.md b/.gitea/issue_template/enhancement.md new file mode 100644 index 0000000..551a59d --- /dev/null +++ b/.gitea/issue_template/enhancement.md @@ -0,0 +1,16 @@ +--- + +name: "Enhancement" +about: "Something could be improved or missing a feature?" +title: "" +labels: +- enhancement +- "help needed" + +--- + +# What do you want to achieve? + +# Example of the enhancement + +# Further information From dd78835f17ed8193e8823e6d27200747a4554fa5 Mon Sep 17 00:00:00 2001 From: finga Date: Wed, 30 Jun 2021 23:45:46 +0200 Subject: [PATCH 09/65] Cargo update --- Cargo.lock | 88 +++++++++++++++++++++++++++--------------------------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 114168f..7df069f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -58,18 +58,18 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "0.7.18" +version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5" dependencies = [ "memchr", ] [[package]] name = "anyhow" -version = "1.0.40" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b2cd92db5cbd74e8e5028f7e27dd7aa3090e89e4f2a197cc7c8dfb69c7063b" +checksum = "15af2628f6890fe2609a3b91bef4c83450512802e59489f9c1cb1fa5df064a61" [[package]] name = "arrayvec" @@ -193,7 +193,7 @@ dependencies = [ "proc-macro-error", "proc-macro2 1.0.27", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.73", ] [[package]] @@ -214,9 +214,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed00c67cb5d0a7d64a44f6ad2668db7e7530311dd53ea79bcd4fb022c64911c8" +checksum = "66c99696f6c9dd7f35d486b9d04d7e6e202aa3e8c40d553f2fdf5e7e0c6a71ef" dependencies = [ "libc", ] @@ -315,9 +315,9 @@ checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0" [[package]] name = "env_logger" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17392a012ea30ef05a610aa97dfb49496e71c9f676b27879922ea5bdf60d9d3f" +checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3" dependencies = [ "atty", "humantime", @@ -381,24 +381,24 @@ checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" [[package]] name = "hashbrown" -version = "0.9.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" [[package]] name = "heck" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cbf45460356b7deeb5e3415b5563308c0a9b057c85e12b06ad551f98d0a6ac" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" dependencies = [ "unicode-segmentation", ] [[package]] name = "hermit-abi" -version = "0.1.18" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" dependencies = [ "libc", ] @@ -485,9 +485,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.6.2" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "824845a0bf897a9042383849b02c1bc219c2383772efcd5c6f9766fa4b81aef3" +checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" dependencies = [ "autocfg", "hashbrown", @@ -495,9 +495,9 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.3.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47be2f14c678be2fdcab04ab1171db51b2762ce6f0a8ee87c8dd4a04ed216135" +checksum = "68f2d64f2edebec4ce84ad108148e67e1064789bee435edc5b60ad398714a3a9" dependencies = [ "serde", ] @@ -535,9 +535,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.95" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "789da6d93f1b866ffe175afc5322a4d76c038605a1c3319bb57b06967ca98a36" +checksum = "12b8adadd720df158f4d70dfe7ccc6adb0472d7c55ca83445f6a5ab3e36f8fb6" [[package]] name = "linked-hash-map" @@ -571,9 +571,9 @@ checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" [[package]] name = "memchr" -version = "2.4.0" +version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc" +checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" [[package]] name = "mime" @@ -586,9 +586,9 @@ dependencies = [ [[package]] name = "nom" -version = "6.1.2" +version = "6.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7413f999671bd4745a7b624bd370a569fb6bc574b23c83a3c5ed2e453f3d5e2" +checksum = "9c5c51b9083a3c620fa67a2a635d1ce7d95b897e957d6b28ff9a5da960a103a6" dependencies = [ "bitvec", "funty", @@ -679,7 +679,7 @@ dependencies = [ "proc-macro-error-attr", "proc-macro2 1.0.27", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.73", "version_check 0.9.3", ] @@ -738,9 +738,9 @@ checksum = "941ba9d78d8e2f7ce474c015eea4d9c6d25b6a3327f9832ee29a4de27f91bbb8" [[package]] name = "rand" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" +checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" dependencies = [ "libc", "rand_chacha", @@ -750,9 +750,9 @@ dependencies = [ [[package]] name = "rand_chacha" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", "rand_core", @@ -760,27 +760,27 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" dependencies = [ "getrandom", ] [[package]] name = "rand_hc" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" +checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" dependencies = [ "rand_core", ] [[package]] name = "redox_syscall" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "742739e41cd49414de871ea5e549afb7e2a3ac77b589bcbebe8c82fab37147fc" +checksum = "5ab49abadf3f9e1c4bc499e8845e152ad87d2ad2d30371841171169e9d75feee" dependencies = [ "bitflags", ] @@ -797,9 +797,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.5.4" +version = "1.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +checksum = "2a26af418b574bd56588335b3a3659a65725d4e636eb1016c2f9e3b38c7cc759" dependencies = [ "aho-corasick", "memchr", @@ -941,7 +941,7 @@ checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43" dependencies = [ "proc-macro2 1.0.27", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.73", ] [[package]] @@ -1023,9 +1023,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.72" +version = "1.0.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1e8cdbefb79a9a5a65e0db8b47b723ee907b7c7f8496c76a1770b5c310bab82" +checksum = "f71489ff30030d2ae598524f61326b902466f72a0fb1a8564c001cc63425bcc7" dependencies = [ "proc-macro2 1.0.27", "quote 1.0.9", @@ -1073,7 +1073,7 @@ checksum = "8a36768c0fbf1bb15eca10defa29526bda730a2376c2ab4393ccfa16fb1a318d" dependencies = [ "proc-macro2 1.0.27", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.73", ] [[package]] @@ -1148,9 +1148,9 @@ dependencies = [ [[package]] name = "unicode-normalization" -version = "0.1.17" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07fbfce1c8a97d547e8b5334978438d9d6ec8c20e38f56d4a4374d181493eaef" +checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" dependencies = [ "tinyvec", ] From 5d20366e5d99fac0154c6bf8e4757f94db9a0246 Mon Sep 17 00:00:00 2001 From: finga Date: Wed, 30 Jun 2021 23:52:19 +0200 Subject: [PATCH 10/65] Fix clippy warnings --- src/main.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/main.rs b/src/main.rs index c352620..12742b8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -204,7 +204,7 @@ impl Hook { } } - replace_parameters(&self.command, &request.headers(), data) + replace_parameters(&self.command, request.headers(), data) } } @@ -231,7 +231,7 @@ impl Hooks { let hooks = config.hooks.iter().filter(|(name, hook)| { if let Some(ip) = &hook.ip_filter { - return accept_ip(&name, &client_ip, &ip); + accept_ip(name, client_ip, ip) } else { info!( "Allow hook `{}` from {}, no IP filter was configured", @@ -250,7 +250,7 @@ impl Hooks { let secrets = hook .secrets .iter() - .map(|secret| validate_request(&secret, &signature, &buffer)); + .map(|secret| validate_request(secret, signature, &buffer)); for secret in secrets { match secret { @@ -263,7 +263,7 @@ impl Hooks { serde_json::from_slice(&buffer).map_err(WebhookeyError::Serde)?; match hook.filter.evaluate(request, &data) { - Ok(true) => match hook.get_command(&hook_name, &request, &mut data) { + Ok(true) => match hook.get_command(hook_name, request, &mut data) { Ok(command) => { info!("Filter for `{}` matched", &hook_name); result.insert(hook_name.to_string(), command); @@ -294,7 +294,7 @@ impl FromDataSimple for Hooks { type Error = WebhookeyError; fn from_data(request: &Request, data: Data) -> data::Outcome { - match Hooks::get_commands(&request, data) { + match Hooks::get_commands(request, data) { Ok(hooks) => { if hooks.inner.is_empty() { let client_ip = &request @@ -336,9 +336,9 @@ fn accept_ip(hook_name: &str, client_ip: &IpAddr, ip: &IpFilter) -> bool { } fn validate_request(secret: &str, signature: &str, data: &[u8]) -> Result<()> { - let mut mac = Hmac::::new_varkey(&secret.as_bytes()) + let mut mac = Hmac::::new_varkey(secret.as_bytes()) .map_err(|e| anyhow!("Could not create hasher with secret: {}", e))?; - mac.update(&data); + mac.update(data); let raw_signature = hex::decode(signature.as_bytes())?; mac.verify(&raw_signature).map_err(|e| anyhow!("{}", e)) } @@ -347,7 +347,7 @@ fn get_parameter(input: &str) -> Result> { let parse: IResult<&str, Vec<&str>> = many0(alt(( delimited(tag("{{"), take_until("}}"), tag("}}")), take_until("{{"), - )))(&input); + )))(input); let (_last, result) = parse .finish() @@ -389,7 +389,7 @@ fn replace_parameters( match expr.get(0) { Some(&"header") => get_header_field(headers, &expr), - Some(pointer) => get_value_from_pointer(data, &pointer), + Some(pointer) => get_value_from_pointer(data, pointer), None => bail!("Missing expression in `{}`", input), } }, @@ -424,7 +424,7 @@ fn receive_hook<'a>(address: SocketAddr, hooks: Hooks) -> Result> { hooks.inner.iter().for_each(|(name, command)| { info!("Execute `{}` from hook `{}`", &command, &name); - match run_script::run(&command, &vec![], &ScriptOptions::new()) { + match run_script::run(command, &vec![], &ScriptOptions::new()) { Ok((status, stdout, stderr)) => { info!("Command `{}` exited with return code: {}", &command, status); trace!("Output of command `{}` on stdout: {:?}", &command, &stdout); @@ -497,7 +497,7 @@ fn main() -> Result<()> { trace!("Parsed configuration:\n{}", serde_yaml::to_string(&config)?); - if let Some(_) = cli.subcommand_matches("configtest") { + if cli.subcommand_matches("configtest").is_some() { debug!("Configtest succeded."); println!("Config is OK"); return Ok(()); From 34e3e3f32a09dc830fffe545620007a36cf2f8a0 Mon Sep 17 00:00:00 2001 From: finga Date: Wed, 30 Jun 2021 23:55:21 +0200 Subject: [PATCH 11/65] Better command line argument parsing Use structs and enums instead of builder style options. --- src/main.rs | 54 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/src/main.rs b/src/main.rs index 12742b8..d41f50c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,7 @@ #![feature(proc_macro_hygiene, decl_macro)] use anyhow::{anyhow, bail, Result}; -use clap::{app_from_crate, App, Arg}; +use clap::{crate_authors, crate_version, AppSettings, Clap}; use hmac::{Hmac, Mac, NewMac}; use ipnet::IpNet; use log::{debug, error, info, trace, warn}; @@ -54,6 +54,27 @@ enum WebhookeyError { Regex(regex::Error), } +#[derive(Clap, Debug)] +enum Command { + /// Verifies if the configuration can be parsed without errors + Configtest, +} + +#[derive(Clap, Debug)] +#[clap( + version = crate_version!(), + author = crate_authors!(", "), + global_setting = AppSettings::VersionlessSubcommands, + global_setting = AppSettings::InferSubcommands, +)] +struct Opts { + /// Provide a path to the configuration file + #[clap(short, long, value_name = "FILE")] + config: Option, + #[clap(subcommand)] + command: Option, +} + #[derive(Debug, Deserialize, Serialize)] #[serde(deny_unknown_fields, untagged)] enum AddrType { @@ -86,6 +107,12 @@ impl IpFilter { } } +#[derive(Debug, Deserialize, Serialize)] +#[serde(deny_unknown_fields)] +struct Config { + hooks: HashMap, +} + #[derive(Debug, Deserialize, Serialize)] #[serde(deny_unknown_fields)] struct JsonFilter { @@ -319,12 +346,6 @@ impl FromDataSimple for Hooks { } } -#[derive(Debug, Deserialize, Serialize)] -#[serde(deny_unknown_fields)] -struct Config { - hooks: HashMap, -} - fn accept_ip(hook_name: &str, client_ip: &IpAddr, ip: &IpFilter) -> bool { if ip.validate(client_ip) { info!("Allow hook `{}` from {}", &hook_name, &client_ip); @@ -475,29 +496,16 @@ fn get_config() -> Result { fn main() -> Result<()> { env_logger::init(); - let cli = app_from_crate!() - .arg( - Arg::new("config") - .short('c') - .long("config") - .takes_value(true) - .value_name("FILE") - .about("Provide a path to the configuration file"), - ) - .subcommand( - App::new("configtest") - .about("Verifies if the configuration can be parsed without errors"), - ) - .get_matches(); + let cli: Opts = Opts::parse(); - let config: Config = match cli.value_of("config") { + let config: Config = match cli.config { Some(config) => serde_yaml::from_reader(BufReader::new(File::open(config)?))?, _ => serde_yaml::from_reader(BufReader::new(get_config()?))?, }; trace!("Parsed configuration:\n{}", serde_yaml::to_string(&config)?); - if cli.subcommand_matches("configtest").is_some() { + if cli.command.is_some() { debug!("Configtest succeded."); println!("Config is OK"); return Ok(()); From ed6646195cead7eff87a50f29153be1ce9ff3926 Mon Sep 17 00:00:00 2001 From: finga Date: Thu, 30 Sep 2021 00:20:54 +0200 Subject: [PATCH 12/65] Cargo update Update dependencies. --- Cargo.lock | 152 +++++++++++++++++++++++++--------------------------- Cargo.toml | 2 +- src/main.rs | 2 +- 3 files changed, 76 insertions(+), 80 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7df069f..a46732e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -67,9 +67,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.41" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15af2628f6890fe2609a3b91bef4c83450512802e59489f9c1cb1fa5df064a61" +checksum = "61604a8f862e1d5c3229fdd78f8b02c68dcf73a4c4b05fd636d12240aaa242c1" [[package]] name = "arrayvec" @@ -112,9 +112,9 @@ checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" [[package]] name = "bitflags" -version = "1.2.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitvec" @@ -145,9 +145,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "cc" -version = "1.0.68" +version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a72c244c1ff497a746a7e1fb3d14bd08420ecda70c8f25c7112f2781652d787" +checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0" [[package]] name = "cfg-if" @@ -166,9 +166,9 @@ dependencies = [ [[package]] name = "clap" -version = "3.0.0-beta.2" +version = "3.0.0-beta.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bd1061998a501ee7d4b6d449020df3266ca3124b941ec56cf2005c3779ca142" +checksum = "fcd70aa5597dbc42f7217a543f9ef2768b2ef823ba29036072d30e1d88e98406" dependencies = [ "atty", "bitflags", @@ -179,21 +179,20 @@ dependencies = [ "strsim", "termcolor", "textwrap", - "unicode-width", "vec_map", ] [[package]] name = "clap_derive" -version = "3.0.0-beta.2" +version = "3.0.0-beta.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "370f715b81112975b1b69db93e0b56ea4cd4e5002ac43b2da8474106a54096a1" +checksum = "0b5bb0d655624a0b8770d1c178fb8ffcb1f91cc722cb08f451e3dc72465421ac" dependencies = [ "heck", "proc-macro-error", - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.73", + "syn 1.0.77", ] [[package]] @@ -214,9 +213,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.1.5" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66c99696f6c9dd7f35d486b9d04d7e6e202aa3e8c40d553f2fdf5e7e0c6a71ef" +checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469" dependencies = [ "libc", ] @@ -229,9 +228,9 @@ checksum = "dcb25d077389e53838a8158c8e99174c5a9d902dee4904320db714f3c653ffba" [[package]] name = "crypto-mac" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4857fd85a0c34b3c3297875b747c1e02e06b6a0ea32dd892d8192b9ce0813ea6" +checksum = "bff07008ec701e8028e2ceb8f83f0e4274ee62bd2dbdc4fefff2e9a91824081a" dependencies = [ "generic-array", "subtle", @@ -431,9 +430,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.4.1" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3a87b616e37e93c22fb19bcd386f02f3af5ea98a25670ad0fce773de23c5e68" +checksum = "acd94fdbe1d4ff688b67b04eee2e17bd50995534a61539e45adfefb45e5e5503" [[package]] name = "humantime" @@ -504,9 +503,9 @@ dependencies = [ [[package]] name = "itoa" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" +checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" [[package]] name = "language-tags" @@ -535,9 +534,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.97" +version = "0.2.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12b8adadd720df158f4d70dfe7ccc6adb0472d7c55ca83445f6a5ab3e36f8fb6" +checksum = "dd8f7255a17a627354f321ef0055d63b898c6fb27eff628af4d1b66b7331edf6" [[package]] name = "linked-hash-map" @@ -565,9 +564,9 @@ dependencies = [ [[package]] name = "matches" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" +checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" [[package]] name = "memchr" @@ -615,9 +614,9 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "os_str_bytes" -version = "2.4.0" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afb2e1c3ee07430c2cf76151675e583e0f19985fa6efae47d6848a3e2c824f85" +checksum = "6acbef58a60fe69ab50510a55bc8cdd4d6cf2283d27ad338f54cb52747a9cf2d" [[package]] name = "pear" @@ -677,9 +676,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ "proc-macro-error-attr", - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.73", + "syn 1.0.77", "version_check 0.9.3", ] @@ -689,7 +688,7 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", "version_check 0.9.3", ] @@ -705,9 +704,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.27" +version = "1.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0d8caf72986c1a598726adc988bb5984792ef84f5ee5aa50209145ee8077038" +checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d" dependencies = [ "unicode-xid 0.2.2", ] @@ -727,7 +726,7 @@ version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" dependencies = [ - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", ] [[package]] @@ -778,9 +777,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ab49abadf3f9e1c4bc499e8845e152ad87d2ad2d30371841171169e9d75feee" +checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" dependencies = [ "bitflags", ] @@ -926,29 +925,29 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.126" +version = "1.0.130" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03" +checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.126" +version = "1.0.130" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43" +checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b" dependencies = [ - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.73", + "syn 1.0.77", ] [[package]] name = "serde_json" -version = "1.0.64" +version = "1.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79" +checksum = "0f690853975602e1bfe1ccbf50504d67174e3bcf340f23b5ea9992e0587a52d8" dependencies = [ "itoa", "ryu", @@ -957,21 +956,21 @@ dependencies = [ [[package]] name = "serde_yaml" -version = "0.8.17" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15654ed4ab61726bf918a39cb8d98a2e2995b002387807fa6ba58fdf7f59bb23" +checksum = "d8c608a35705a5d3cdc9fbe403147647ff34b921f8e833e49306df898f9b20af" dependencies = [ "dtoa", - "linked-hash-map", + "indexmap", "serde", "yaml-rust", ] [[package]] name = "sha2" -version = "0.9.5" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b362ae5752fd2137731f9fa25fd4d9058af34666ca1966fb969119cc35719f12" +checksum = "b69f9a4c9740d74c5baa3fd2e547f9525fa8088a8a958e0ca2409a514e33f5fa" dependencies = [ "block-buffer", "cfg-if", @@ -982,9 +981,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.6.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" +checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" [[package]] name = "state" @@ -1006,9 +1005,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "subtle" -version = "2.4.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e81da0851ada1f3e9d4312c704aa4f8806f0f9d69faaf8df2f3464b4a9437c2" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "syn" @@ -1023,11 +1022,11 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.73" +version = "1.0.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f71489ff30030d2ae598524f61326b902466f72a0fb1a8564c001cc63425bcc7" +checksum = "5239bc68e0fef57495900cfea4e8dc75596d9a319d7e16b1e0a440d24e6fe0a0" dependencies = [ - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", "unicode-xid 0.2.2", ] @@ -1049,31 +1048,31 @@ dependencies = [ [[package]] name = "textwrap" -version = "0.12.1" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "203008d98caf094106cfaba70acfed15e18ed3ddb7d94e49baec153a2b462789" +checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80" dependencies = [ "unicode-width", ] [[package]] name = "thiserror" -version = "1.0.25" +version = "1.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa6f76457f59514c7eeb4e59d891395fab0b2fd1d40723ae737d64153392e9c6" +checksum = "602eca064b2d83369e2b2f34b09c70b605402801927c65c11071ac911d299b88" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.25" +version = "1.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a36768c0fbf1bb15eca10defa29526bda730a2376c2ab4393ccfa16fb1a318d" +checksum = "bad553cc2c78e8de258400763a647e80e6d1b31ee237275d756f6836d204494c" dependencies = [ - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.73", + "syn 1.0.77", ] [[package]] @@ -1088,9 +1087,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.2.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b5220f05bb7de7f3f53c7c065e1199b3172696fe2db9f9c4d8ad9b4ee74c342" +checksum = "f83b2a3d4d9091d0abd7eba4dc2710b1718583bd4d8992e2190720ea38f391f7" dependencies = [ "tinyvec_macros", ] @@ -1124,9 +1123,9 @@ checksum = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887" [[package]] name = "typenum" -version = "1.13.0" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06" +checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec" [[package]] name = "unicase" @@ -1139,12 +1138,9 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eeb8be209bb1c96b7c177c7420d26e04eccacb0eeae6b980e35fcb74678107e0" -dependencies = [ - "matches", -] +checksum = "246f4c42e67e7a4e3c6106ff716a5d067d4132a642840b242e357e468a2a0085" [[package]] name = "unicode-normalization" @@ -1157,15 +1153,15 @@ dependencies = [ [[package]] name = "unicode-segmentation" -version = "1.7.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796" +checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" [[package]] name = "unicode-width" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" +checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" [[package]] name = "unicode-xid" @@ -1181,9 +1177,9 @@ checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" [[package]] name = "universal-hash" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8326b2c654932e3e4f9196e69d08fdf7cfd718e1dc6f66b347e6024a0c961402" +checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05" dependencies = [ "generic-array", "subtle", diff --git a/Cargo.toml b/Cargo.toml index f123f85..c9ae492 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,7 @@ hex = "0.4" ipnet = { version = "2.3", features = ["serde"] } thiserror = "1.0" run_script = "0.7" -clap = "3.0.0-beta.2" +clap = "3.0.0-beta.4" [package.metadata.deb] extended-description = "Webhookey receives requests in form of a so called Webhook as for example sent by Gitea. Those requests are matched against configured filters, if a filter matches, values from the header and the body can be passed to scripts as parameters which are then executed subsequently." diff --git a/src/main.rs b/src/main.rs index d41f50c..73c0a39 100644 --- a/src/main.rs +++ b/src/main.rs @@ -64,8 +64,8 @@ enum Command { #[clap( version = crate_version!(), author = crate_authors!(", "), - global_setting = AppSettings::VersionlessSubcommands, global_setting = AppSettings::InferSubcommands, + global_setting = AppSettings::PropagateVersion, )] struct Opts { /// Provide a path to the configuration file From 39096ef9cc0b77cc32bfe9f899f3259b8976b9f9 Mon Sep 17 00:00:00 2001 From: finga Date: Thu, 30 Sep 2021 00:21:28 +0200 Subject: [PATCH 13/65] Colored help Print colored help message. --- src/main.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main.rs b/src/main.rs index 73c0a39..ba2ed19 100644 --- a/src/main.rs +++ b/src/main.rs @@ -64,6 +64,7 @@ enum Command { #[clap( version = crate_version!(), author = crate_authors!(", "), + global_setting = AppSettings::ColoredHelp, global_setting = AppSettings::InferSubcommands, global_setting = AppSettings::PropagateVersion, )] From 41d8efe8a8994c574ec84b902e62f425d0cb992b Mon Sep 17 00:00:00 2001 From: finga Date: Sun, 17 Oct 2021 08:53:31 +0200 Subject: [PATCH 14/65] Fix readme path in Debian package Move the readme into to right directory when installing the debian package. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index c9ae492..8abe721 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,7 +36,7 @@ systemd-units = { enable = false } assets = [ ["config.yml", "etc/webhookey/", "644"], ["target/release/webhookey", "usr/bin/", "755"], - ["README.md", "usr/share/doc/cargo-deb/README", "644"], + ["README.md", "usr/share/doc/webhookey/README", "644"], ["debian/service", "lib/systemd/system/webhookey.service", "644"], ] conf-files = ["/etc/webhookey/config.yml"] From 5a88fb892bec084a4a5393f3cc579f727b067050 Mon Sep 17 00:00:00 2001 From: finga Date: Wed, 3 Nov 2021 13:09:44 +0100 Subject: [PATCH 15/65] Adapt to new versions of rocket and clap Use clap `3.0.0-beta.5` and rocket `0.5.0-rc.1`. --- Cargo.lock | 1525 +++++++++++++++++++++++++++++++++++++-------------- Cargo.toml | 4 +- src/main.rs | 77 +-- 3 files changed, 1169 insertions(+), 437 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a46732e..4690d59 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,74 +2,29 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "aead" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fc95d1bdb8e6666b2b217308eeeb09f2d6728d104be3e31916cc74d15420331" -dependencies = [ - "generic-array", -] - -[[package]] -name = "aes" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "884391ef1066acaa41e766ba8f596341b96e93ce34f9a43e7d24bf0a0eaf0561" -dependencies = [ - "aes-soft", - "aesni", - "cipher", -] - -[[package]] -name = "aes-gcm" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5278b5fabbb9bd46e24aa69b2fdea62c99088e0a950a9be40e3e0101298f88da" -dependencies = [ - "aead", - "aes", - "cipher", - "ctr", - "ghash", - "subtle", -] - -[[package]] -name = "aes-soft" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be14c7498ea50828a38d0e24a765ed2effe92a705885b57d029cd67d45744072" -dependencies = [ - "cipher", - "opaque-debug", -] - -[[package]] -name = "aesni" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea2e11f5e94c2f7d386164cc2aa1f97823fed6f259e486940a71c174dd01b0ce" -dependencies = [ - "cipher", - "opaque-debug", -] - [[package]] name = "aho-corasick" -version = "0.7.15" +version = "0.7.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" dependencies = [ "memchr", ] [[package]] -name = "anyhow" -version = "1.0.44" +name = "ansi_term" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61604a8f862e1d5c3229fdd78f8b02c68dcf73a4c4b05fd636d12240aaa242c1" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +dependencies = [ + "winapi", +] + +[[package]] +name = "anyhow" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee10e43ae4a853c0a3591d4e2ada1719e553be18199d9da9d4a83f5927c2f5c7" [[package]] name = "arrayvec" @@ -77,6 +32,47 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" +[[package]] +name = "async-stream" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "171374e7e3b2504e0e5236e3b59260560f9fe94bfe9ac39ba5e4e929c5590625" +dependencies = [ + "async-stream-impl", + "futures-core", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "648ed8c8d2ce5409ccd57453d9d1b214b342a0d69376a6feda1fd6cae3299308" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "async-trait" +version = "0.1.51" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44318e776df68115a881de9a8fd1b9e53368d7a4a5ce4cc48517da3393233a5e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "atomic" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3410529e8288c463bedb5930f82833bc0c90e5d2fe639a56582a4d09220b281" +dependencies = [ + "autocfg", +] + [[package]] name = "atty" version = "0.2.14" @@ -95,14 +91,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] -name = "base64" -version = "0.9.3" +name = "base-x" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" -dependencies = [ - "byteorder", - "safemem", -] +checksum = "a4521f3e3d031370679b3b140beb36dfe4801b09ac77e30c61941f97df3ef28b" [[package]] name = "base64" @@ -110,6 +102,12 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" +[[package]] +name = "binascii" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "383d29d513d8764dcdc42ea295d979eb99c3c9f00607b3692cf68a431f7dca72" + [[package]] name = "bitflags" version = "1.3.2" @@ -138,16 +136,22 @@ dependencies = [ ] [[package]] -name = "byteorder" -version = "1.4.3" +name = "bumpalo" +version = "3.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c" + +[[package]] +name = "bytes" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" [[package]] name = "cc" -version = "1.0.70" +version = "1.0.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0" +checksum = "79c2681d6594606957bbb8631c4b90a7fcaaa72cdb714743a437b156d6a7eedd" [[package]] name = "cfg-if" @@ -156,19 +160,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] -name = "cipher" -version = "0.2.5" +name = "chrono" +version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12f8e7987cbd042a63249497f41aed09f8e65add917ea6566effbc56578d6801" +checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" dependencies = [ - "generic-array", + "libc", + "num-integer", + "num-traits", + "winapi", ] [[package]] name = "clap" -version = "3.0.0-beta.4" +version = "3.0.0-beta.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcd70aa5597dbc42f7217a543f9ef2768b2ef823ba29036072d30e1d88e98406" +checksum = "feff3878564edb93745d58cf63e17b63f24142506e7a20c87a5521ed7bfb1d63" dependencies = [ "atty", "bitflags", @@ -179,36 +186,37 @@ dependencies = [ "strsim", "termcolor", "textwrap", - "vec_map", + "unicase", ] [[package]] name = "clap_derive" -version = "3.0.0-beta.4" +version = "3.0.0-beta.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b5bb0d655624a0b8770d1c178fb8ffcb1f91cc722cb08f451e3dc72465421ac" +checksum = "8b15c6b4f786ffb6192ffe65a36855bc1fc2444bcd0945ae16748dcd6ed7d0d3" dependencies = [ "heck", "proc-macro-error", - "proc-macro2 1.0.29", - "quote 1.0.9", - "syn 1.0.77", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "cookie" -version = "0.11.4" +name = "const_fn" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80f6044740a4a516b8aac14c140cdf35c1a640b1bd6b98b6224e49143b2f1566" +checksum = "f92cfa0fd5690b3cf8c1ef2cabbd9b7ef22fa53cf5e1f92b05103f6d5d1cf6e7" + +[[package]] +name = "cookie" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5f1c7727e460397e56abc4bddc1d49e07a1ad78fc98eb2e1c8f032a58a2f80d" dependencies = [ - "aes-gcm", - "base64 0.13.0", - "hkdf", - "hmac", - "percent-encoding 2.1.0", - "rand", - "sha2", + "percent-encoding", "time", + "version_check", ] [[package]] @@ -220,12 +228,6 @@ dependencies = [ "libc", ] -[[package]] -name = "cpuid-bool" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcb25d077389e53838a8158c8e99174c5a9d902dee4904320db714f3c653ffba" - [[package]] name = "crypto-mac" version = "0.10.1" @@ -236,20 +238,11 @@ dependencies = [ "subtle", ] -[[package]] -name = "ctr" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb4a30d54f7443bf3d6191dcd486aca19e67cb3c49fa7a06a319966346707e7f" -dependencies = [ - "cipher", -] - [[package]] name = "devise" -version = "0.2.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74e04ba2d03c5fa0d954c061fc8c9c288badadffc272ebb87679a89846de3ed3" +checksum = "50c7580b072f1c8476148f16e0a0d5dedddab787da98d86c5082c5e9ed8ab595" dependencies = [ "devise_codegen", "devise_core", @@ -257,24 +250,25 @@ dependencies = [ [[package]] name = "devise_codegen" -version = "0.2.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "066ceb7928ca93a9bedc6d0e612a8a0424048b0ab1f75971b203d01420c055d7" +checksum = "123c73e7a6e51b05c75fe1a1b2f4e241399ea5740ed810b0e3e6cacd9db5e7b2" dependencies = [ "devise_core", - "quote 0.6.13", + "quote", ] [[package]] name = "devise_core" -version = "0.2.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf41c59b22b5e3ec0ea55c7847e5f358d340f3a8d6d53a5cf4f1564967f96487" +checksum = "841ef46f4787d9097405cac4e70fb8644fc037b526e8c14054247c0263c400d0" dependencies = [ "bitflags", - "proc-macro2 0.4.30", - "quote 0.6.13", - "syn 0.15.44", + "proc-macro2", + "proc-macro2-diagnostics", + "quote", + "syn", ] [[package]] @@ -306,12 +300,33 @@ dependencies = [ "winapi", ] +[[package]] +name = "discard" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" + [[package]] name = "dtoa" version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0" +[[package]] +name = "either" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" + +[[package]] +name = "encoding_rs" +version = "0.8.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a74ea89a0a1b98f6332de42c95baff457ada66d1cb4030f9ff151b2041a1c746" +dependencies = [ + "cfg-if", +] + [[package]] name = "env_logger" version = "0.8.4" @@ -320,11 +335,31 @@ checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3" dependencies = [ "atty", "humantime", - "log 0.4.14", + "log", "regex", "termcolor", ] +[[package]] +name = "figment" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790b4292c72618abbab50f787a477014fe15634f96291de45672ce46afe122df" +dependencies = [ + "atomic", + "pear", + "serde", + "toml", + "uncased", + "version_check", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + [[package]] name = "fsio" version = "0.2.0" @@ -341,6 +376,113 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" +[[package]] +name = "futures" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a12aa0eb539080d55c3f2d45a67c3b58b6b0773c1a3ca2dfec66d58c97fd66ca" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5da6ba8c3bb3c165d3c7319fc1cc8304facf1fb8db99c5de877183c08a273888" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88d1c26957f23603395cd326b0ffe64124b818f4449552f960d815cfba83a53d" + +[[package]] +name = "futures-executor" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45025be030969d763025784f7f355043dc6bc74093e4ecc5000ca4dc50d8745c" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "522de2a0fe3e380f1bc577ba0474108faf3f6b18321dbf60b3b9c39a75073377" + +[[package]] +name = "futures-macro" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18e4a4b95cea4b4ccbcf1c5675ca7c4ee4e9e75eb79944d07defde18068f79bb" +dependencies = [ + "autocfg", + "proc-macro-hack", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36ea153c13024fe480590b3e3d4cad89a0cfacecc24577b68f86c6ced9c2bc11" + +[[package]] +name = "futures-task" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d3d00f4eddb73e498a54394f228cd55853bdf059259e8e7bc6e69d408892e99" + +[[package]] +name = "futures-util" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36568465210a3a6ee45e1f165136d68671471a501e632e9a98d96872222b5481" +dependencies = [ + "autocfg", + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "proc-macro-hack", + "proc-macro-nested", + "slab", +] + +[[package]] +name = "generator" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1d9279ca822891c1a4dae06d185612cf8fc6acfe5dff37781b41297811b12ee" +dependencies = [ + "cc", + "libc", + "log", + "rustversion", + "winapi", +] + [[package]] name = "generic-array" version = "0.14.4" @@ -348,7 +490,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" dependencies = [ "typenum", - "version_check 0.9.3", + "version_check", ] [[package]] @@ -362,22 +504,31 @@ dependencies = [ "wasi", ] -[[package]] -name = "ghash" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97304e4cd182c3846f7575ced3890c53012ce534ad9114046b0a9e00bb30a375" -dependencies = [ - "opaque-debug", - "polyval", -] - [[package]] name = "glob" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" +[[package]] +name = "h2" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fd819562fcebdac5afc5c113c3ec36f902840b70fd4fc458799c8ce4607ae55" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "hashbrown" version = "0.11.2" @@ -408,16 +559,6 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" -[[package]] -name = "hkdf" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51ab2f639c231793c5f6114bdb9bbe50a7dbbfcd7c7c6bd8475dec2d991e964f" -dependencies = [ - "digest", - "hmac", -] - [[package]] name = "hmac" version = "0.10.1" @@ -428,12 +569,40 @@ dependencies = [ "digest", ] +[[package]] +name = "http" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1323096b05d41827dadeaee54c9981958c0f94e670bc94ed80037d1a7b8b186b" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ff4f84919677303da5f147645dbea6b1881f368d03ac84e1dc09031ebd7b2c6" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + [[package]] name = "httparse" version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acd94fdbe1d4ff688b67b04eee2e17bd50995534a61539e45adfefb45e5e5503" +[[package]] +name = "httpdate" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6456b8a6c8f33fee7d958fcd1b60d55b11940a79e63ae87013e6d22e26034440" + [[package]] name = "humantime" version = "2.1.0" @@ -442,44 +611,26 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.10.16" +version = "0.14.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a0652d9a2609a968c14be1a9ea00bf4b1d64e2e1f53a1b51b6fff3a6e829273" +checksum = "2b91bb1f221b6ea1f1e4371216b70f40748774c2fb5971b450c07773fb92d26b" dependencies = [ - "base64 0.9.3", + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", "httparse", - "language-tags", - "log 0.3.9", - "mime", - "num_cpus", - "time", - "traitobject", - "typeable", - "unicase", - "url", -] - -[[package]] -name = "hyper-sync-rustls" -version = "0.3.0-rc.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d1a443a90413a118ac6739e024f6a5180aa3b3f43f7de65f9d388a961cff19b" -dependencies = [ - "hyper", - "rustls", - "webpki", - "webpki-roots", -] - -[[package]] -name = "idna" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" -dependencies = [ - "matches", - "unicode-bidi", - "unicode-normalization", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", ] [[package]] @@ -490,6 +641,22 @@ checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" dependencies = [ "autocfg", "hashbrown", + "serde", +] + +[[package]] +name = "inlinable_string" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3094308123a0e9fd59659ce45e22de9f53fc1d2ac6e1feb9fef988e4f76cad77" + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", ] [[package]] @@ -508,10 +675,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" [[package]] -name = "language-tags" -version = "0.2.2" +name = "js-sys" +version = "0.3.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" +checksum = "7cc9ffccd38c451a86bf13657df244e9c3f37493cce8e5e21e940963777acc84" +dependencies = [ + "wasm-bindgen", +] [[package]] name = "lazy_static" @@ -534,9 +704,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.103" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8f7255a17a627354f321ef0055d63b898c6fb27eff628af4d1b66b7331edf6" +checksum = "a60553f9a9e039a333b4e9b20573b9e9b9c0bb3a11e201ccc48ef4283456d673" [[package]] name = "linked-hash-map" @@ -545,12 +715,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" [[package]] -name = "log" -version = "0.3.9" +name = "lock_api" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" +checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" dependencies = [ - "log 0.4.14", + "scopeguard", ] [[package]] @@ -563,37 +733,122 @@ dependencies = [ ] [[package]] -name = "matches" -version = "0.1.9" +name = "loom" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" +checksum = "b2b9df80a3804094bf49bb29881d18f6f05048db72127e84e09c26fc7c2324f5" +dependencies = [ + "cfg-if", + "generator", + "scoped-tls", + "serde", + "serde_json", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "matchers" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f099785f7595cc4b4553a174ce30dd7589ef93391ff414dbb67f62392b9e0ce1" +dependencies = [ + "regex-automata", +] [[package]] name = "memchr" -version = "2.3.4" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" [[package]] name = "mime" -version = "0.2.6" +version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0" +checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" + +[[package]] +name = "mio" +version = "0.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8067b404fe97c70829f082dec8bcf4f71225d7eaea1d8645349cb76fa06205cc" dependencies = [ - "log 0.3.9", + "libc", + "log", + "miow", + "ntapi", + "winapi", +] + +[[package]] +name = "miow" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" +dependencies = [ + "winapi", +] + +[[package]] +name = "multer" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "408327e2999b839cd1af003fc01b2019a6c10a1361769542203f6fedc5179680" +dependencies = [ + "bytes", + "encoding_rs", + "futures-util", + "http", + "httparse", + "log", + "mime", + "spin 0.9.2", + "tokio", + "tokio-util", + "twoway", + "version_check", ] [[package]] name = "nom" -version = "6.2.1" +version = "6.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c5c51b9083a3c620fa67a2a635d1ce7d95b897e957d6b28ff9a5da960a103a6" +checksum = "e7413f999671bd4745a7b624bd370a569fb6bc574b23c83a3c5ed2e453f3d5e2" dependencies = [ "bitvec", "funty", "lexical-core", "memchr", - "version_check 0.9.3", + "version_check", +] + +[[package]] +name = "ntapi" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" +dependencies = [ + "winapi", +] + +[[package]] +name = "num-integer" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +dependencies = [ + "autocfg", ] [[package]] @@ -606,6 +861,12 @@ dependencies = [ "libc", ] +[[package]] +name = "once_cell" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" + [[package]] name = "opaque-debug" version = "0.3.0" @@ -614,37 +875,60 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "os_str_bytes" -version = "3.1.0" +version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6acbef58a60fe69ab50510a55bc8cdd4d6cf2283d27ad338f54cb52747a9cf2d" - -[[package]] -name = "pear" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5320f212db967792b67cfe12bd469d08afd6318a249bd917d5c19bc92200ab8a" +checksum = "addaa943333a514159c80c97ff4a93306530d965d27e139188283cd13e06a799" dependencies = [ - "pear_codegen", + "memchr", ] [[package]] -name = "pear_codegen" -version = "0.1.4" +name = "parking_lot" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfc1c836fdc3d1ef87c348b237b5b5c4dff922156fb2d968f57734f9669768ca" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" dependencies = [ - "proc-macro2 0.4.30", - "quote 0.6.13", - "syn 0.15.44", - "version_check 0.9.3", + "instant", + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" +dependencies = [ + "cfg-if", + "instant", + "libc", + "redox_syscall", + "smallvec", + "winapi", +] + +[[package]] +name = "pear" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15e44241c5e4c868e3eaa78b7c1848cadd6344ed4f54d029832d32b415a58702" +dependencies = [ + "inlinable_string", + "pear_codegen", "yansi", ] [[package]] -name = "percent-encoding" -version = "1.0.1" +name = "pear_codegen" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" +checksum = "82a5ca643c2303ecb740d506539deba189e16f2754040a42901cd8105d0282d0" +dependencies = [ + "proc-macro2", + "proc-macro2-diagnostics", + "quote", + "syn", +] [[package]] name = "percent-encoding" @@ -653,21 +937,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" [[package]] -name = "polyval" -version = "0.4.5" +name = "pin-project-lite" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eebcc4aa140b9abd2bc40d9c3f7ccec842679cd79045ac3a7ac698c1a064b7cd" -dependencies = [ - "cpuid-bool", - "opaque-debug", - "universal-hash", -] +checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "ppv-lite86" -version = "0.2.10" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" +checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba" [[package]] name = "proc-macro-error" @@ -676,10 +961,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ "proc-macro-error-attr", - "proc-macro2 1.0.29", - "quote 1.0.9", - "syn 1.0.77", - "version_check 0.9.3", + "proc-macro2", + "quote", + "syn", + "version_check", ] [[package]] @@ -688,45 +973,52 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ - "proc-macro2 1.0.29", - "quote 1.0.9", - "version_check 0.9.3", + "proc-macro2", + "quote", + "version_check", ] [[package]] -name = "proc-macro2" -version = "0.4.30" +name = "proc-macro-hack" +version = "0.5.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" -dependencies = [ - "unicode-xid 0.1.0", -] +checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" + +[[package]] +name = "proc-macro-nested" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" [[package]] name = "proc-macro2" -version = "1.0.29" +version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d" +checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43" dependencies = [ - "unicode-xid 0.2.2", + "unicode-xid", +] + +[[package]] +name = "proc-macro2-diagnostics" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bf29726d67464d49fa6224a1d07936a8c08bb3fba727c7493f6cf1616fdaada" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "version_check", + "yansi", ] [[package]] name = "quote" -version = "0.6.13" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" +checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" dependencies = [ - "proc-macro2 0.4.30", -] - -[[package]] -name = "quote" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" -dependencies = [ - "proc-macro2 1.0.29", + "proc-macro2", ] [[package]] @@ -795,16 +1087,45 @@ dependencies = [ ] [[package]] -name = "regex" -version = "1.4.6" +name = "ref-cast" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a26af418b574bd56588335b3a3659a65725d4e636eb1016c2f9e3b38c7cc759" +checksum = "300f2a835d808734ee295d45007adacb9ebb29dd3ae2424acfa17930cae541da" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c38e3aecd2b21cb3959637b883bb3714bc7e43f0268b9a29d3743ee3e55cdd2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "regex" +version = "1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" dependencies = [ "aho-corasick", "memchr", "regex-syntax", ] +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax", +] + [[package]] name = "regex-syntax" version = "0.6.25" @@ -812,70 +1133,110 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" [[package]] -name = "ring" -version = "0.13.5" +name = "remove_dir_all" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c4db68a2e35f3497146b7e4563df7d4773a2433230c5e4b448328e31740458a" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" dependencies = [ "cc", - "lazy_static", "libc", + "once_cell", + "spin 0.5.2", "untrusted", + "web-sys", + "winapi", ] [[package]] name = "rocket" -version = "0.4.10" +version = "0.5.0-rc.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a7ab1dfdc75bb8bd2be381f37796b1b300c45a3c9145b34d86715e8dd90bf28" +checksum = "0a71c18c42a0eb15bf3816831caf0dad11e7966f2a41aaf486a701979c4dd1f2" dependencies = [ + "async-stream", + "async-trait", + "atomic", "atty", - "base64 0.13.0", - "log 0.4.14", + "binascii", + "bytes", + "either", + "figment", + "futures", + "indexmap", + "log", "memchr", + "multer", "num_cpus", - "pear", + "parking_lot", + "pin-project-lite", + "rand", + "ref-cast", "rocket_codegen", "rocket_http", + "serde", "state", + "tempfile", "time", - "toml", - "version_check 0.9.3", + "tokio", + "tokio-stream", + "tokio-util", + "ubyte", + "version_check", "yansi", ] [[package]] name = "rocket_codegen" -version = "0.4.10" +version = "0.5.0-rc.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1729e687d6d2cf434d174da84fb948f7fef4fac22d20ce94ca61c28b72dbcf9f" +checksum = "66f5fa462f7eb958bba8710c17c5d774bbbd59809fa76fb1957af7e545aea8bb" dependencies = [ "devise", "glob", "indexmap", - "quote 0.6.13", + "proc-macro2", + "quote", "rocket_http", - "version_check 0.9.3", - "yansi", + "syn", + "unicode-xid", ] [[package]] name = "rocket_http" -version = "0.4.10" +version = "0.5.0-rc.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6131e6e6d38a9817f4a494ff5da95971451c2eb56a53915579fc9c80f6ef0117" +checksum = "23c8b7d512d2fcac2316ebe590cde67573844b99e6cc9ee0f53375fa16e25ebd" dependencies = [ "cookie", + "either", + "http", "hyper", - "hyper-sync-rustls", "indexmap", + "log", + "memchr", + "mime", + "parking_lot", "pear", - "percent-encoding 1.0.1", - "rustls", + "percent-encoding", + "pin-project-lite", + "ref-cast", + "serde", "smallvec", + "stable-pattern", "state", "time", - "unicode-xid 0.1.0", + "tokio", + "tokio-rustls", + "uncased", ] [[package]] @@ -888,19 +1249,33 @@ dependencies = [ ] [[package]] -name = "rustls" -version = "0.14.0" +name = "rustc_version" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b7891791343c75b73ed9a18cadcafd8c8563d11a88ebe2d87f5b8a3182654d9" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" dependencies = [ - "base64 0.9.3", - "log 0.4.14", + "semver", +] + +[[package]] +name = "rustls" +version = "0.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35edb675feee39aec9c99fa5ff985081995a06d594114ae14cbe797ad7b7a6d7" +dependencies = [ + "base64", + "log", "ring", "sct", - "untrusted", "webpki", ] +[[package]] +name = "rustversion" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61b3909d758bb75c79f23d4736fac9433868679d3ad2ea7a61e3c25cfda9a088" + [[package]] name = "ryu" version = "1.0.5" @@ -908,21 +1283,42 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" [[package]] -name = "safemem" -version = "0.3.3" +name = "scoped-tls" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" +checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "sct" -version = "0.4.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb8f61f9e6eadd062a71c380043d28036304a4706b3c4dd001ff3387ed00745a" +checksum = "b362b83898e0e69f38515b82ee15aa80636befe47c3b6d3d89a911e78fc228ce" dependencies = [ "ring", "untrusted", ] +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + [[package]] name = "serde" version = "1.0.130" @@ -938,9 +1334,9 @@ version = "1.0.130" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b" dependencies = [ - "proc-macro2 1.0.29", - "quote 1.0.9", - "syn 1.0.77", + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -966,6 +1362,12 @@ dependencies = [ "yaml-rust", ] +[[package]] +name = "sha1" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" + [[package]] name = "sha2" version = "0.9.8" @@ -979,6 +1381,30 @@ dependencies = [ "opaque-debug", ] +[[package]] +name = "sharded-slab" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" +dependencies = [ + "libc", +] + +[[package]] +name = "slab" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5" + [[package]] name = "smallvec" version = "1.7.0" @@ -986,10 +1412,53 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" [[package]] -name = "state" +name = "socket2" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3015a7d0a5fd5105c91c3710d42f9ccf0abfb287d62206484dcc67f9569a6483" +checksum = "5dc90fe6c7be1a323296982db1836d1ea9e47b6839496dde9a541bc496df3516" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "spin" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "511254be0c5bcf062b019a6c89c01a664aa359ded62f78aa72c6fc137c0590e5" + +[[package]] +name = "stable-pattern" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4564168c00635f88eaed410d5efa8131afa8d8699a612c80c455a0ba05c21045" +dependencies = [ + "memchr", +] + +[[package]] +name = "standback" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e113fb6f3de07a243d434a56ec6f186dfd51cb08448239fe7bcae73f87ff28ff" +dependencies = [ + "version_check", +] + +[[package]] +name = "state" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cf4f5369e6d3044b5e365c9690f451516ac8f0954084622b49ea3fde2f6de5" +dependencies = [ + "loom", +] [[package]] name = "static_assertions" @@ -997,6 +1466,55 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "stdweb" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5" +dependencies = [ + "discard", + "rustc_version", + "stdweb-derive", + "stdweb-internal-macros", + "stdweb-internal-runtime", + "wasm-bindgen", +] + +[[package]] +name = "stdweb-derive" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" +dependencies = [ + "proc-macro2", + "quote", + "serde", + "serde_derive", + "syn", +] + +[[package]] +name = "stdweb-internal-macros" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11" +dependencies = [ + "base-x", + "proc-macro2", + "quote", + "serde", + "serde_derive", + "serde_json", + "sha1", + "syn", +] + +[[package]] +name = "stdweb-internal-runtime" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" + [[package]] name = "strsim" version = "0.10.0" @@ -1011,24 +1529,13 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "syn" -version = "0.15.44" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" +checksum = "f2afee18b8beb5a596ecb4a2dce128c719b4ba399d34126b9e4396e3f9860966" dependencies = [ - "proc-macro2 0.4.30", - "quote 0.6.13", - "unicode-xid 0.1.0", -] - -[[package]] -name = "syn" -version = "1.0.77" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5239bc68e0fef57495900cfea4e8dc75596d9a319d7e16b1e0a440d24e6fe0a0" -dependencies = [ - "proc-macro2 1.0.29", - "quote 1.0.9", - "unicode-xid 0.2.2", + "proc-macro2", + "quote", + "unicode-xid", ] [[package]] @@ -1037,6 +1544,20 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" +[[package]] +name = "tempfile" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" +dependencies = [ + "cfg-if", + "libc", + "rand", + "redox_syscall", + "remove_dir_all", + "winapi", +] + [[package]] name = "termcolor" version = "1.1.2" @@ -1057,69 +1578,242 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.29" +version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "602eca064b2d83369e2b2f34b09c70b605402801927c65c11071ac911d299b88" +checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.29" +version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bad553cc2c78e8de258400763a647e80e6d1b31ee237275d756f6836d204494c" +checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" dependencies = [ - "proc-macro2 1.0.29", - "quote 1.0.9", - "syn 1.0.77", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thread_local" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8018d24e04c95ac8790716a5987d0fec4f8b27249ffa0f7d33f1369bdfb88cbd" +dependencies = [ + "once_cell", ] [[package]] name = "time" -version = "0.1.43" +version = "0.2.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" +checksum = "4752a97f8eebd6854ff91f1c1824cd6160626ac4bd44287f7f4ea2035a02a242" dependencies = [ + "const_fn", "libc", + "standback", + "stdweb", + "time-macros", + "version_check", "winapi", ] [[package]] -name = "tinyvec" -version = "1.5.0" +name = "time-macros" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f83b2a3d4d9091d0abd7eba4dc2710b1718583bd4d8992e2190720ea38f391f7" +checksum = "957e9c6e26f12cb6d0dd7fc776bb67a706312e7299aed74c8dd5b17ebb27e2f1" dependencies = [ - "tinyvec_macros", + "proc-macro-hack", + "time-macros-impl", ] [[package]] -name = "tinyvec_macros" -version = "0.1.0" +name = "time-macros-impl" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" +checksum = "fd3c141a1b43194f3f56a1411225df8646c55781d5f26db825b3d98507eb482f" +dependencies = [ + "proc-macro-hack", + "proc-macro2", + "quote", + "standback", + "syn", +] + +[[package]] +name = "tokio" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "588b2d10a336da58d877567cd8fb8a14b463e2104910f8132cd054b4b96e29ee" +dependencies = [ + "autocfg", + "bytes", + "libc", + "memchr", + "mio", + "num_cpus", + "once_cell", + "pin-project-lite", + "signal-hook-registry", + "tokio-macros", + "winapi", +] + +[[package]] +name = "tokio-macros" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "114383b041aa6212c579467afa0075fbbdd0718de036100bc0ba7961d8cb9095" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio-rustls" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc6844de72e57df1980054b38be3a9f4702aba4858be64dd700181a8a6d0e1b6" +dependencies = [ + "rustls", + "tokio", + "webpki", +] + +[[package]] +name = "tokio-stream" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50145484efff8818b5ccd256697f36863f587da82cf8b409c53adf1e840798e3" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e99e1983e5d376cd8eb4b66604d2e99e79f5bd988c3055891dcd8c9e2604cc0" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "log", + "pin-project-lite", + "tokio", +] [[package]] name = "toml" -version = "0.4.10" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f" +checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" dependencies = [ "serde", ] [[package]] -name = "traitobject" -version = "0.1.0" +name = "tower-service" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" +checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" [[package]] -name = "typeable" +name = "tracing" +version = "0.1.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "375a639232caf30edfc78e8d89b2d4c375515393e7af7e16f01cd96917fb2105" +dependencies = [ + "cfg-if", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f480b8f81512e825f337ad51e94c1eb5d3bbdf2b363dcd01e2b19a9ffe3f8e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f4ed65637b8390770814083d20756f87bfa2c21bf2f110babdc5438351746e4" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "tracing-log" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887" +checksum = "a6923477a48e41c1951f1999ef8bb5a3023eb723ceadafe78ffb65dc366761e3" +dependencies = [ + "lazy_static", + "log", + "tracing-core", +] + +[[package]] +name = "tracing-serde" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb65ea441fbb84f9f6748fd496cf7f63ec9af5bca94dd86456978d055e8eb28b" +dependencies = [ + "serde", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71" +dependencies = [ + "ansi_term", + "chrono", + "lazy_static", + "matchers", + "regex", + "serde", + "serde_json", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", + "tracing-serde", +] + +[[package]] +name = "try-lock" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" + +[[package]] +name = "twoway" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c57ffb460d7c24cd6eda43694110189030a3d1dfe418416d9468fd1c1d290b47" +dependencies = [ + "memchr", + "unchecked-index", +] [[package]] name = "typenum" @@ -1128,27 +1822,37 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec" [[package]] -name = "unicase" -version = "1.4.2" +name = "ubyte" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33" +checksum = "42756bb9e708855de2f8a98195643dff31a97f0485d90d8467b39dc24be9e8fe" dependencies = [ - "version_check 0.1.5", + "serde", ] [[package]] -name = "unicode-bidi" -version = "0.3.6" +name = "uncased" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "246f4c42e67e7a4e3c6106ff716a5d067d4132a642840b242e357e468a2a0085" +checksum = "5baeed7327e25054889b9bd4f975f32e5f4c5d434042d59ab6cd4142c0a76ed0" +dependencies = [ + "serde", + "version_check", +] [[package]] -name = "unicode-normalization" -version = "0.1.19" +name = "unchecked-index" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" +checksum = "eeba86d422ce181a719445e51872fa30f1f7413b62becb52e95ec91aa262d85c" + +[[package]] +name = "unicase" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" dependencies = [ - "tinyvec", + "version_check", ] [[package]] @@ -1163,44 +1867,17 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" -[[package]] -name = "unicode-xid" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" - [[package]] name = "unicode-xid" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" -[[package]] -name = "universal-hash" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05" -dependencies = [ - "generic-array", - "subtle", -] - [[package]] name = "untrusted" -version = "0.6.2" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cd1f4b4e96b46aeb8d4855db4a7a9bd96eeeb5c6a1ab54593328761642ce2f" - -[[package]] -name = "url" -version = "1.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" -dependencies = [ - "idna", - "matches", - "percent-encoding 1.0.1", -] +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" [[package]] name = "users" @@ -1209,33 +1886,95 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24cc0f6d6f267b73e5a2cadf007ba8f9bc39c6a6f9666f8cf25ea809a153b032" dependencies = [ "libc", - "log 0.4.14", + "log", ] -[[package]] -name = "vec_map" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" - -[[package]] -name = "version_check" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" - [[package]] name = "version_check" version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" +[[package]] +name = "want" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +dependencies = [ + "log", + "try-lock", +] + [[package]] name = "wasi" version = "0.10.2+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" +[[package]] +name = "wasm-bindgen" +version = "0.2.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a317bf8f9fba2476b4b2c85ef4c4af8ff39c3c7f0cdfeed4f82c34a880aa837b" +dependencies = [ + "bumpalo", + "lazy_static", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d56146e7c495528bf6587663bea13a8eb588d39b36b679d83972e1a2dbbdacf9" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0237232789cf037d5480773fe568aac745bfe2afbc11a863e97901780a6b47cc" + +[[package]] +name = "web-sys" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38eb105f1c59d9eaa6b5cdc92b859d85b926e82cb2e0945cd0c9259faa6fe9fb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "webhookey" version = "0.1.0" @@ -1247,7 +1986,7 @@ dependencies = [ "hex", "hmac", "ipnet", - "log 0.4.14", + "log", "nom", "regex", "rocket", @@ -1261,24 +2000,14 @@ dependencies = [ [[package]] name = "webpki" -version = "0.18.1" +version = "0.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17d7967316d8411ca3b01821ee6c332bde138ba4363becdb492f12e514daa17f" +checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea" dependencies = [ "ring", "untrusted", ] -[[package]] -name = "webpki-roots" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85d1f408918fd590908a70d36b7ac388db2edc221470333e4d6e5b598e44cabf" -dependencies = [ - "untrusted", - "webpki", -] - [[package]] name = "winapi" version = "0.3.9" diff --git a/Cargo.toml b/Cargo.toml index 8abe721..eb47b30 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,7 @@ description = "Trigger scripts via http(s) requests" tls = ["rocket/tls"] [dependencies] -rocket = "0.4" +rocket = "0.5.0-rc.1" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" serde_yaml = "0.8" @@ -27,7 +27,7 @@ hex = "0.4" ipnet = { version = "2.3", features = ["serde"] } thiserror = "1.0" run_script = "0.7" -clap = "3.0.0-beta.4" +clap = "3.0.0-beta.5" [package.metadata.deb] extended-description = "Webhookey receives requests in form of a so called Webhook as for example sent by Gitea. Those requests are matched against configured filters, if a filter matches, values from the header and the body can be passed to scripts as parameters which are then executed subsequently." diff --git a/src/main.rs b/src/main.rs index ba2ed19..44f7559 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,7 @@ #![feature(proc_macro_hygiene, decl_macro)] use anyhow::{anyhow, bail, Result}; -use clap::{crate_authors, crate_version, AppSettings, Clap}; +use clap::{crate_authors, crate_version, AppSettings, Parser}; use hmac::{Hmac, Mac, NewMac}; use ipnet::IpNet; use log::{debug, error, info, trace, warn}; @@ -15,12 +15,13 @@ use nom::{ }; use regex::Regex; use rocket::{ - data::{self, FromDataSimple}, - fairing::AdHoc, + data::{FromData, ToByteUnit}, + futures::TryFutureExt, http::{HeaderMap, Status}, - post, routes, Data, - Outcome::{Failure, Success}, - Request, Response, State, + outcome::Outcome::{self, Failure, Success}, + post, routes, + tokio::io::AsyncReadExt, + Data, Request, State, }; use run_script::ScriptOptions; use serde::{Deserialize, Serialize}; @@ -30,7 +31,7 @@ use thiserror::Error; use std::{ collections::HashMap, fs::File, - io::{BufReader, Read}, + io::BufReader, net::{IpAddr, Ipv4Addr, SocketAddr}, }; @@ -54,17 +55,16 @@ enum WebhookeyError { Regex(regex::Error), } -#[derive(Clap, Debug)] +#[derive(Debug, Parser)] enum Command { /// Verifies if the configuration can be parsed without errors Configtest, } -#[derive(Clap, Debug)] +#[derive(Debug, Parser)] #[clap( version = crate_version!(), author = crate_authors!(", "), - global_setting = AppSettings::ColoredHelp, global_setting = AppSettings::InferSubcommands, global_setting = AppSettings::PropagateVersion, )] @@ -242,15 +242,16 @@ struct Hooks { } impl Hooks { - fn get_commands(request: &Request, data: Data) -> Result { + async fn get_commands(request: &Request<'_>, data: Data<'_>) -> Result { let mut buffer = Vec::new(); let size = data - .open() + .open(256_i32.kilobytes()) .read_to_end(&mut buffer) - .map_err(WebhookeyError::Io)?; + .map_err(WebhookeyError::Io) + .await?; info!("Data of size {} received", size); - let config = request.guard::>().unwrap(); // should never fail + let config = request.guard::<&State>().await.unwrap(); // should never fail let mut valid = false; let mut result = HashMap::new(); let client_ip = &request @@ -318,11 +319,15 @@ impl Hooks { } } -impl FromDataSimple for Hooks { +#[rocket::async_trait] +impl<'r> FromData<'r> for Hooks { type Error = WebhookeyError; - fn from_data(request: &Request, data: Data) -> data::Outcome { - match Hooks::get_commands(request, data) { + async fn from_data( + request: &'r Request<'_>, + data: Data<'r>, + ) -> Outcome> { + match Hooks::get_commands(request, data).await { Ok(hooks) => { if hooks.inner.is_empty() { let client_ip = &request @@ -440,7 +445,7 @@ fn get_string(value: &serde_json::Value) -> Result { } #[post("/", format = "json", data = "")] -fn receive_hook<'a>(address: SocketAddr, hooks: Hooks) -> Result> { +async fn receive_hook<'a>(address: SocketAddr, hooks: Hooks) -> Status { info!("Post request received from: {}", address); hooks.inner.iter().for_each(|(name, command)| { @@ -458,7 +463,7 @@ fn receive_hook<'a>(address: SocketAddr, hooks: Hooks) -> Result> { } }); - Ok(Response::new()) + Status::Ok } fn get_config() -> Result { @@ -494,7 +499,8 @@ fn get_config() -> Result { bail!("No configuration file found."); } -fn main() -> Result<()> { +#[rocket::main] +async fn main() -> Result<()> { env_logger::init(); let cli: Opts = Opts::parse(); @@ -512,12 +518,11 @@ fn main() -> Result<()> { return Ok(()); } - rocket::ignite() + rocket::build() .mount("/", routes![receive_hook]) - .attach(AdHoc::on_attach("webhookey config", move |rocket| { - Ok(rocket.manage(config)) - })) - .launch(); + .manage(config) + .launch() + .await?; Ok(()) } @@ -527,12 +532,12 @@ mod tests { use super::*; use rocket::{ http::{ContentType, Header}, - local::Client, + local::asynchronous::Client, }; use serde_json::json; - #[test] - fn secret() { + #[rocket::async_test] + async fn secret() { let mut hooks = HashMap::new(); hooks.insert( @@ -551,13 +556,11 @@ mod tests { let config = Config { hooks: hooks }; - let rocket = rocket::ignite() + let rocket = rocket::build() .mount("/", routes![receive_hook]) - .attach(AdHoc::on_attach("webhookey config", move |rocket| { - Ok(rocket.manage(config)) - })); + .manage(config); - let client = Client::new(rocket).unwrap(); + let client = Client::tracked(rocket).await.unwrap(); let response = client .post("/") .header(Header::new( @@ -569,7 +572,7 @@ mod tests { .body(&serde_json::to_string(&json!({ "foo": "bar" })).unwrap()) .dispatch(); - assert_eq!(response.status(), Status::NotFound); + assert_eq!(response.await.status(), Status::NotFound); let response = client .post("/") @@ -579,7 +582,7 @@ mod tests { .body(&serde_json::to_string(&json!({ "foo": "bar" })).unwrap()) .dispatch(); - assert_eq!(response.status(), Status::Unauthorized); + assert_eq!(response.await.status(), Status::Unauthorized); let response = client .post("/") @@ -592,7 +595,7 @@ mod tests { .body(r#"{ "not_secret": "invalid" "#) .dispatch(); - assert_eq!(response.status(), Status::BadRequest); + assert_eq!(response.await.status(), Status::BadRequest); let response = client .post("/") @@ -601,7 +604,7 @@ mod tests { .remote("127.0.0.1:8000".parse().unwrap()) .dispatch(); - assert_eq!(response.status(), Status::Unauthorized); + assert_eq!(response.await.status(), Status::Unauthorized); } #[test] From 87d6f58f729e86546b2bd7f0be2214a0f741e28e Mon Sep 17 00:00:00 2001 From: finga Date: Fri, 5 Nov 2021 13:51:31 +0100 Subject: [PATCH 16/65] Rename variable in `parse_command` test Rename `map` to `headers` inside the `parse_command` test to improve readability. --- src/main.rs | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/src/main.rs b/src/main.rs index 44f7559..9751538 100644 --- a/src/main.rs +++ b/src/main.rs @@ -609,48 +609,53 @@ mod tests { #[test] fn parse_command() { - let mut map = HeaderMap::new(); - map.add_raw("X-Gitea-Event", "something"); + let mut headers = HeaderMap::new(); + headers.add_raw("X-Gitea-Event", "something"); assert_eq!( - replace_parameters("command", &map, &serde_json::Value::Null).unwrap(), + replace_parameters("command", &headers, &serde_json::Value::Null).unwrap(), "command" ); assert_eq!( - replace_parameters(" command", &map, &serde_json::Value::Null).unwrap(), + replace_parameters(" command", &headers, &serde_json::Value::Null).unwrap(), " command" ); assert_eq!( - replace_parameters("command ", &map, &serde_json::Value::Null).unwrap(), + replace_parameters("command ", &headers, &serde_json::Value::Null).unwrap(), "command " ); assert_eq!( - replace_parameters(" command ", &map, &serde_json::Value::Null).unwrap(), + replace_parameters(" command ", &headers, &serde_json::Value::Null).unwrap(), " command " ); assert_eq!( - replace_parameters("command command ", &map, &serde_json::Value::Null).unwrap(), + replace_parameters("command command ", &headers, &serde_json::Value::Null).unwrap(), "command command " ); assert_eq!( - replace_parameters("{{ /foo }} command", &map, &json!({ "foo": "bar" })).unwrap(), + replace_parameters("{{ /foo }} command", &headers, &json!({ "foo": "bar" })).unwrap(), "bar command" ); assert_eq!( - replace_parameters(" command {{ /foo }} ", &map, &json!({ "foo": "bar" })).unwrap(), + replace_parameters( + " command {{ /foo }} ", + &headers, + &json!({ "foo": "bar" }) + ) + .unwrap(), " command bar " ); assert_eq!( replace_parameters( "{{ /foo }} command{{/field1/foo}}", - &map, + &headers, &json!({ "foo": "bar", "field1": { "foo": "baz" } }) ) .unwrap(), @@ -658,14 +663,19 @@ mod tests { ); assert_eq!( - replace_parameters(" command {{ /foo }} ", &map, &json!({ "foo": "bar" })).unwrap(), + replace_parameters( + " command {{ /foo }} ", + &headers, + &json!({ "foo": "bar" }) + ) + .unwrap(), " command bar " ); assert_eq!( replace_parameters( " {{ /field1/foo }} command", - &map, + &headers, &json!({ "field1": { "foo": "bar" } }) ) .unwrap(), @@ -675,7 +685,7 @@ mod tests { assert_eq!( replace_parameters( " {{ header X-Gitea-Event }} command", - &map, + &headers, &json!({ "field1": { "foo": "bar" } }) ) .unwrap(), From c82c0fcbd5d9415906748ff81c2e511ff4f524c9 Mon Sep 17 00:00:00 2001 From: finga Date: Sat, 6 Nov 2021 11:03:27 +0100 Subject: [PATCH 17/65] Remove double parsing of data pointed to As there was an issues with the parser which checked the validity of the JSON pointer pointing to the received JSON data this part is removed. Further some checks were added to double check that case which lead to an invalid behaviour. This fixes #9. --- src/main.rs | 171 +++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 143 insertions(+), 28 deletions(-) diff --git a/src/main.rs b/src/main.rs index 9751538..25fa945 100644 --- a/src/main.rs +++ b/src/main.rs @@ -43,8 +43,6 @@ enum WebhookeyError { Unauthorized(IpAddr), #[error("Unmatched hook from `{0}`")] UnmatchedHook(IpAddr), - #[error("Could not find field refered to in parameter `{0}`")] - InvalidParameterPointer(String), #[error("Could not evaluate filter request")] InvalidFilter, #[error("IO Error")] @@ -218,20 +216,10 @@ impl Hook { &self, hook_name: &str, request: &Request, - data: &mut serde_json::Value, + data: &serde_json::Value, ) -> Result { trace!("Replacing parameters for command of hook `{}`", hook_name); - for parameter in get_parameter(&self.command)? { - let parameter = parameter.trim(); - - if let Some(json_value) = data.pointer(parameter) { - *data.pointer_mut(parameter).ok_or_else(|| { - WebhookeyError::InvalidParameterPointer(parameter.to_string()) - })? = serde_json::Value::String(get_string(json_value)?); - } - } - replace_parameters(&self.command, request.headers(), data) } } @@ -288,11 +276,11 @@ impl Hooks { valid = true; - let mut data: serde_json::Value = + let data: serde_json::Value = serde_json::from_slice(&buffer).map_err(WebhookeyError::Serde)?; match hook.filter.evaluate(request, &data) { - Ok(true) => match hook.get_command(hook_name, request, &mut data) { + Ok(true) => match hook.get_command(hook_name, request, &data) { Ok(command) => { info!("Filter for `{}` matched", &hook_name); result.insert(hook_name.to_string(), command); @@ -370,19 +358,6 @@ fn validate_request(secret: &str, signature: &str, data: &[u8]) -> Result<()> { mac.verify(&raw_signature).map_err(|e| anyhow!("{}", e)) } -fn get_parameter(input: &str) -> Result> { - let parse: IResult<&str, Vec<&str>> = many0(alt(( - delimited(tag("{{"), take_until("}}"), tag("}}")), - take_until("{{"), - )))(input); - - let (_last, result) = parse - .finish() - .map_err(|e| anyhow!("Could not get parameters from command: {}", e))?; - - Ok(result) -} - fn get_header_field<'a>(headers: &'a HeaderMap, param: &[&str]) -> Result<&'a str> { headers .get_one( @@ -691,5 +666,145 @@ mod tests { .unwrap(), " something command" ); + + assert_eq!( + replace_parameters( + " {{ header X-Gitea-Event }} {{ /field1/foo }} command", + &headers, + &json!({ "field1": { "foo": "bar" } }) + ) + .unwrap(), + " something bar command" + ); + } + + #[rocket::async_test] + async fn parse_command_request() { + let mut hooks = HashMap::new(); + + hooks.insert( + "test_hook".to_string(), + Hook { + command: + "/usr/bin/echo {{ /repository/full_name }} --foo {{ /pull_request/base/ref }}" + .to_string(), + signature: "X-Gitea-Signature".to_string(), + ip_filter: None, + secrets: vec!["valid".to_string()], + filter: FilterType::JsonFilter(JsonFilter { + pointer: "/foo".to_string(), + regex: "bar".to_string(), + }), + }, + ); + + hooks.insert( + "test_hook".to_string(), + Hook { + command: "/usr/bin/echo {{ /repository/full_name }} {{ /pull_request/base/ref }}" + .to_string(), + signature: "X-Gitea-Signature".to_string(), + ip_filter: None, + secrets: vec!["valid".to_string()], + filter: FilterType::JsonFilter(JsonFilter { + pointer: "/foo".to_string(), + regex: "bar".to_string(), + }), + }, + ); + + let config = Config { + // default: None, + hooks: hooks, + }; + + let rocket = rocket::build() + .mount("/", routes![receive_hook]) + .manage(config); + + let client = Client::tracked(rocket).await.unwrap(); + + let response = client + .post("/") + .header(Header::new( + "X-Gitea-Signature", + "693b733871ecb684651a813c82936df683c9e4a816581f385353e06170545400", + )) + .header(ContentType::JSON) + .remote("127.0.0.1:8000".parse().unwrap()) + .body( + &serde_json::to_string(&json!({ + "foo": "bar", + "repository": { + "full_name": "keith" + }, + "pull_request": { + "base": { + "ref": "main" + } + } + })) + .unwrap(), + ) + .dispatch(); + + assert_eq!(response.await.status(), Status::Ok); + } + + #[rocket::async_test] + async fn parse_invalid_command_request() { + let mut hooks = HashMap::new(); + + hooks.insert( + "test_hook".to_string(), + Hook { + command: "/usr/bin/echo {{ /repository/full }} {{ /pull_request/base/ref }}" + .to_string(), + signature: "X-Gitea-Signature".to_string(), + ip_filter: None, + secrets: vec!["valid".to_string()], + filter: FilterType::JsonFilter(JsonFilter { + pointer: "/foo".to_string(), + regex: "bar".to_string(), + }), + }, + ); + + let config = Config { + // default: None, + hooks: hooks, + }; + + let rocket = rocket::build() + .mount("/", routes![receive_hook]) + .manage(config); + + let client = Client::tracked(rocket).await.unwrap(); + + let response = client + .post("/") + .header(Header::new( + "X-Gitea-Signature", + "693b733871ecb684651a813c82936df683c9e4a816581f385353e06170545400", + )) + .header(ContentType::JSON) + .remote("127.0.0.1:8000".parse().unwrap()) + .body( + &serde_json::to_string(&json!({ + "foo": "bar", + "repository": { + "full_name": "keith" + }, + "pull_request": { + "base": { + "ref": "main" + } + } + })) + .unwrap(), + ) + .dispatch(); + + assert_eq!(response.await.status(), Status::NotFound); } } From 02dc225fa84f26c62721350083086f31f389ca44 Mon Sep 17 00:00:00 2001 From: finga Date: Sat, 6 Nov 2021 12:06:10 +0100 Subject: [PATCH 18/65] Update build dependencies to latest versions Update build dependencies to latest version, also use the 2021 Rust edition. This is also the next version of `webhookey` with version number 0.1.1. --- Cargo.lock | 112 +++++++++++++++------------------------------------- Cargo.toml | 16 ++++---- src/main.rs | 2 +- 3 files changed, 40 insertions(+), 90 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4690d59..33cf72f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -26,12 +26,6 @@ version = "1.0.45" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee10e43ae4a853c0a3591d4e2ada1719e553be18199d9da9d4a83f5927c2f5c7" -[[package]] -name = "arrayvec" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" - [[package]] name = "async-stream" version = "0.3.2" @@ -114,18 +108,6 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" -[[package]] -name = "bitvec" -version = "0.19.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8942c8d352ae1838c9dda0b0ca2ab657696ef2232a20147cf1b30ae1a9cb4321" -dependencies = [ - "funty", - "radium", - "tap", - "wyz", -] - [[package]] name = "block-buffer" version = "0.9.0" @@ -230,9 +212,9 @@ dependencies = [ [[package]] name = "crypto-mac" -version = "0.10.1" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bff07008ec701e8028e2ceb8f83f0e4274ee62bd2dbdc4fefff2e9a91824081a" +checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" dependencies = [ "generic-array", "subtle", @@ -282,9 +264,9 @@ dependencies = [ [[package]] name = "dirs" -version = "3.0.2" +version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30baa043103c9d0c2a57cf537cc2f35623889dc0d405e6c3cccfadbc81c71309" +checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" dependencies = [ "dirs-sys", ] @@ -312,6 +294,12 @@ version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0" +[[package]] +name = "dunce" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "453440c271cf5577fd2a40e4942540cb7d0d2f85e27c8d07dd0023c925a67541" + [[package]] name = "either" version = "1.6.1" @@ -329,9 +317,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.8.4" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3" +checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3" dependencies = [ "atty", "humantime", @@ -362,20 +350,15 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "fsio" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a50045aa8931ae01afbc5d72439e8f57f326becb8c70d07dfc816778eff3d167" +checksum = "09e87827efaf94c7a44b562ff57de06930712fe21b530c3797cdede26e6377eb" dependencies = [ + "dunce", "rand", "users", ] -[[package]] -name = "funty" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" - [[package]] name = "futures" version = "0.3.17" @@ -561,9 +544,9 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "hmac" -version = "0.10.1" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1441c6b1e930e2817404b5046f1f989899143a12bf92de603b69f4e0aee1e15" +checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" dependencies = [ "crypto-mac", "digest", @@ -689,19 +672,6 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -[[package]] -name = "lexical-core" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6607c62aa161d23d17a9072cc5da0be67cdfc89d3afb1e8d9c842bebc2525ffe" -dependencies = [ - "arrayvec", - "bitflags", - "cfg-if", - "ryu", - "static_assertions", -] - [[package]] name = "libc" version = "0.2.106" @@ -768,6 +738,12 @@ version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "mio" version = "0.7.14" @@ -812,14 +788,12 @@ dependencies = [ [[package]] name = "nom" -version = "6.1.2" +version = "7.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7413f999671bd4745a7b624bd370a569fb6bc574b23c83a3c5ed2e453f3d5e2" +checksum = "1b1d11e1ef389c76fe5b81bcaf2ea32cf88b62bc494e19f493d0b30e7a930109" dependencies = [ - "bitvec", - "funty", - "lexical-core", "memchr", + "minimal-lexical", "version_check", ] @@ -1021,12 +995,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "radium" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "941ba9d78d8e2f7ce474c015eea4d9c6d25b6a3327f9832ee29a4de27f91bbb8" - [[package]] name = "rand" version = "0.8.4" @@ -1241,9 +1209,9 @@ dependencies = [ [[package]] name = "run_script" -version = "0.7.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1c022176d696304ff6655716c2c09e1b888c00ac66a7c53c037ae7c9511ce6c" +checksum = "5dd85213e37f76b40186ee781cf3a689b05c518c3102c987acf679c573d8e4ef" dependencies = [ "fsio", ] @@ -1341,9 +1309,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.68" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f690853975602e1bfe1ccbf50504d67174e3bcf340f23b5ea9992e0587a52d8" +checksum = "e466864e431129c7e0d3476b92f20458e5879919a0596c6472738d9fa2d342f8" dependencies = [ "itoa", "ryu", @@ -1460,12 +1428,6 @@ dependencies = [ "loom", ] -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - [[package]] name = "stdweb" version = "0.4.20" @@ -1538,12 +1500,6 @@ dependencies = [ "unicode-xid", ] -[[package]] -name = "tap" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" - [[package]] name = "tempfile" version = "3.2.0" @@ -1977,7 +1933,7 @@ dependencies = [ [[package]] name = "webhookey" -version = "0.1.0" +version = "0.1.1" dependencies = [ "anyhow", "clap", @@ -2039,12 +1995,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "wyz" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" - [[package]] name = "yaml-rust" version = "0.4.5" diff --git a/Cargo.toml b/Cargo.toml index eb47b30..1c69f4d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "webhookey" -version = "0.1.0" +version = "0.1.1" authors = ["finga "] -edition = "2018" +edition = "2021" license = "GPL-3.0-or-later" readme = "README.md" description = "Trigger scripts via http(s) requests" @@ -15,18 +15,18 @@ rocket = "0.5.0-rc.1" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" serde_yaml = "0.8" -regex = "1.4" -dirs = "3.0" +regex = "1.5" +dirs = "4.0" anyhow = "1.0" log = "0.4" -env_logger = "0.8" -nom = "6" -hmac = "0.10" +env_logger = "0.9" +nom = "7" +hmac = "0.11" sha2 = "0.9" hex = "0.4" ipnet = { version = "2.3", features = ["serde"] } thiserror = "1.0" -run_script = "0.7" +run_script = "0.9" clap = "3.0.0-beta.5" [package.metadata.deb] diff --git a/src/main.rs b/src/main.rs index 25fa945..5cc0d0a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -351,7 +351,7 @@ fn accept_ip(hook_name: &str, client_ip: &IpAddr, ip: &IpFilter) -> bool { } fn validate_request(secret: &str, signature: &str, data: &[u8]) -> Result<()> { - let mut mac = Hmac::::new_varkey(secret.as_bytes()) + let mut mac = Hmac::::new_from_slice(secret.as_bytes()) .map_err(|e| anyhow!("Could not create hasher with secret: {}", e))?; mac.update(data); let raw_signature = hex::decode(signature.as_bytes())?; From b7cb27ed220c877dccf929a72de8cb2f90138e70 Mon Sep 17 00:00:00 2001 From: finga Date: Sat, 6 Nov 2021 12:21:12 +0100 Subject: [PATCH 19/65] Update readme as nightly is not needed anymore Due to the update to `rocket v0.5` nightly is not needed anymore. --- README.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/README.md b/README.md index 4bad877..37dcf4f 100644 --- a/README.md +++ b/README.md @@ -9,11 +9,6 @@ actions. ### Install Rust Install the Rust toolchain from [rustup.rs](https://rustup.rs). -Further, for Rocket we need to have the nightly toolchain installed: -``` sh - rustup toolchain install nightly -``` - ### Build Webhookey The Webhookey project can be built for development: ``` sh From 4594db6c44867fdb2b21a63b232f089d439b8044 Mon Sep 17 00:00:00 2001 From: finga Date: Sun, 7 Nov 2021 16:41:58 +0100 Subject: [PATCH 20/65] Remove feature annotation This is not needed anymore. --- src/main.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main.rs b/src/main.rs index 5cc0d0a..eb00efa 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,3 @@ -#![feature(proc_macro_hygiene, decl_macro)] - use anyhow::{anyhow, bail, Result}; use clap::{crate_authors, crate_version, AppSettings, Parser}; use hmac::{Hmac, Mac, NewMac}; From beb039aa3cf634b0d55007491a739f8a45f291f7 Mon Sep 17 00:00:00 2001 From: finga Date: Sun, 7 Nov 2021 16:43:10 +0100 Subject: [PATCH 21/65] Reorder code To improve readibility and to prepeare split of `webhookey` code from `Rocket` some functions are reordered. --- src/main.rs | 134 ++++++++++++++++++++++++++-------------------------- 1 file changed, 67 insertions(+), 67 deletions(-) diff --git a/src/main.rs b/src/main.rs index eb00efa..8fba053 100644 --- a/src/main.rs +++ b/src/main.rs @@ -305,39 +305,6 @@ impl Hooks { } } -#[rocket::async_trait] -impl<'r> FromData<'r> for Hooks { - type Error = WebhookeyError; - - async fn from_data( - request: &'r Request<'_>, - data: Data<'r>, - ) -> Outcome> { - match Hooks::get_commands(request, data).await { - Ok(hooks) => { - if hooks.inner.is_empty() { - let client_ip = &request - .client_ip() - .unwrap_or(IpAddr::V4(Ipv4Addr::UNSPECIFIED)); - - warn!("Unmatched hook from {}", &client_ip); - return Failure((Status::NotFound, WebhookeyError::UnmatchedHook(*client_ip))); - } - - Success(hooks) - } - Err(WebhookeyError::Unauthorized(e)) => { - error!("{}", WebhookeyError::Unauthorized(e)); - Failure((Status::Unauthorized, WebhookeyError::Unauthorized(e))) - } - Err(e) => { - error!("{}", e); - Failure((Status::BadRequest, e)) - } - } - } -} - fn accept_ip(hook_name: &str, client_ip: &IpAddr, ip: &IpFilter) -> bool { if ip.validate(client_ip) { info!("Allow hook `{}` from {}", &hook_name, &client_ip); @@ -376,6 +343,18 @@ fn get_value_from_pointer<'a>(data: &'a serde_json::Value, pointer: &'a str) -> .ok_or_else(|| anyhow!("Could not convert value `{}` to string", value)) } +fn get_string(value: &serde_json::Value) -> Result { + match &value { + serde_json::Value::Bool(bool) => Ok(bool.to_string()), + serde_json::Value::Number(number) => Ok(number.to_string()), + serde_json::Value::String(string) => Ok(string.as_str().to_string()), + x => { + error!("Could not get string from: {:?}", x); + unimplemented!() + } + } +} + fn replace_parameters( input: &str, headers: &HeaderMap, @@ -405,40 +384,6 @@ fn replace_parameters( Ok(result.join("")) } -fn get_string(value: &serde_json::Value) -> Result { - match &value { - serde_json::Value::Bool(bool) => Ok(bool.to_string()), - serde_json::Value::Number(number) => Ok(number.to_string()), - serde_json::Value::String(string) => Ok(string.as_str().to_string()), - x => { - error!("Could not get string from: {:?}", x); - unimplemented!() - } - } -} - -#[post("/", format = "json", data = "")] -async fn receive_hook<'a>(address: SocketAddr, hooks: Hooks) -> Status { - info!("Post request received from: {}", address); - - hooks.inner.iter().for_each(|(name, command)| { - info!("Execute `{}` from hook `{}`", &command, &name); - - match run_script::run(command, &vec![], &ScriptOptions::new()) { - Ok((status, stdout, stderr)) => { - info!("Command `{}` exited with return code: {}", &command, status); - trace!("Output of command `{}` on stdout: {:?}", &command, &stdout); - debug!("Output of command `{}` on stderr: {:?}", &command, &stderr); - } - Err(e) => { - error!("Execution of `{}` failed: {}", &command, e); - } - } - }); - - Status::Ok -} - fn get_config() -> Result { // Look for config in CWD.. if let Ok(config) = File::open("config.yml") { @@ -472,6 +417,61 @@ fn get_config() -> Result { bail!("No configuration file found."); } +#[rocket::async_trait] +impl<'r> FromData<'r> for Hooks { + type Error = WebhookeyError; + + async fn from_data( + request: &'r Request<'_>, + data: Data<'r>, + ) -> Outcome> { + match Hooks::get_commands(request, data).await { + Ok(hooks) => { + if hooks.inner.is_empty() { + let client_ip = &request + .client_ip() + .unwrap_or(IpAddr::V4(Ipv4Addr::UNSPECIFIED)); + + warn!("Unmatched hook from {}", &client_ip); + return Failure((Status::NotFound, WebhookeyError::UnmatchedHook(*client_ip))); + } + + Success(hooks) + } + Err(WebhookeyError::Unauthorized(e)) => { + error!("{}", WebhookeyError::Unauthorized(e)); + Failure((Status::Unauthorized, WebhookeyError::Unauthorized(e))) + } + Err(e) => { + error!("{}", e); + Failure((Status::BadRequest, e)) + } + } + } +} + +#[post("/", format = "json", data = "")] +async fn receive_hook<'a>(address: SocketAddr, hooks: Hooks) -> Status { + info!("Post request received from: {}", address); + + hooks.inner.iter().for_each(|(name, command)| { + info!("Execute `{}` from hook `{}`", &command, &name); + + match run_script::run(command, &vec![], &ScriptOptions::new()) { + Ok((status, stdout, stderr)) => { + info!("Command `{}` exited with return code: {}", &command, status); + trace!("Output of command `{}` on stdout: {:?}", &command, &stdout); + debug!("Output of command `{}` on stderr: {:?}", &command, &stderr); + } + Err(e) => { + error!("Execution of `{}` failed: {}", &command, e); + } + } + }); + + Status::Ok +} + #[rocket::main] async fn main() -> Result<()> { env_logger::init(); From a12ad80cbabc9635a3307980e976fa12a545ee38 Mon Sep 17 00:00:00 2001 From: finga Date: Sun, 7 Nov 2021 16:55:11 +0100 Subject: [PATCH 22/65] Add metrics page Add a page to print metrics. --- src/main.rs | 138 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 133 insertions(+), 5 deletions(-) diff --git a/src/main.rs b/src/main.rs index 8fba053..a681d5d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -15,6 +15,7 @@ use regex::Regex; use rocket::{ data::{FromData, ToByteUnit}, futures::TryFutureExt, + get, http::{HeaderMap, Status}, outcome::Outcome::{self, Failure, Success}, post, routes, @@ -31,6 +32,7 @@ use std::{ fs::File, io::BufReader, net::{IpAddr, Ipv4Addr, SocketAddr}, + sync::Mutex, }; #[derive(Debug, Error)] @@ -72,6 +74,19 @@ struct Opts { command: Option, } +#[derive(Debug, Default)] +struct WebhookeyMetrics { + requests_received: Mutex, + requests_invalid: Mutex, + hooks_successful: Mutex, + hooks_forbidden: Mutex, + hooks_unmatched: Mutex, + commands_executed: Mutex, + commands_execution_failed: Mutex, + commands_successful: Mutex, + commands_failed: Mutex, +} + #[derive(Debug, Deserialize, Serialize)] #[serde(deny_unknown_fields, untagged)] enum AddrType { @@ -425,6 +440,18 @@ impl<'r> FromData<'r> for Hooks { request: &'r Request<'_>, data: Data<'r>, ) -> Outcome> { + { + let requests_received = &mut request + .guard::<&State>() + .await + .unwrap() // TODO: Check if unwrap need to be fixed + .requests_received + .lock() + .unwrap(); // TODO: Check if unwrap need to be fixed + + **requests_received += 1; + } + match Hooks::get_commands(request, data).await { Ok(hooks) => { if hooks.inner.is_empty() { @@ -432,6 +459,16 @@ impl<'r> FromData<'r> for Hooks { .client_ip() .unwrap_or(IpAddr::V4(Ipv4Addr::UNSPECIFIED)); + let hooks_unmatched = &mut request + .guard::<&State>() + .await + .unwrap() // TODO: Check if unwrap need to be fixed + .hooks_unmatched + .lock() + .unwrap(); // TODO: Check if unwrap need to be fixed + + **hooks_unmatched += 1; + warn!("Unmatched hook from {}", &client_ip); return Failure((Status::NotFound, WebhookeyError::UnmatchedHook(*client_ip))); } @@ -440,10 +477,32 @@ impl<'r> FromData<'r> for Hooks { } Err(WebhookeyError::Unauthorized(e)) => { error!("{}", WebhookeyError::Unauthorized(e)); + + let hooks_forbidden = &mut request + .guard::<&State>() + .await + .unwrap() // TODO: Check if unwrap need to be fixed + .hooks_forbidden + .lock() + .unwrap(); // TODO: Check if unwrap need to be fixed + + **hooks_forbidden += 1; + Failure((Status::Unauthorized, WebhookeyError::Unauthorized(e))) } Err(e) => { error!("{}", e); + + let requests_invalid = &mut request + .guard::<&State>() + .await + .unwrap() // TODO: Check if unwrap need to be fixed + .requests_invalid + .lock() + .unwrap(); // TODO: Check if unwrap need to be fixed + + **requests_invalid += 1; + Failure((Status::BadRequest, e)) } } @@ -451,7 +510,11 @@ impl<'r> FromData<'r> for Hooks { } #[post("/", format = "json", data = "")] -async fn receive_hook<'a>(address: SocketAddr, hooks: Hooks) -> Status { +async fn receive_hook<'a>( + address: SocketAddr, + hooks: Hooks, + metrics: &State, +) -> Status { info!("Post request received from: {}", address); hooks.inner.iter().for_each(|(name, command)| { @@ -462,9 +525,27 @@ async fn receive_hook<'a>(address: SocketAddr, hooks: Hooks) -> Status { info!("Command `{}` exited with return code: {}", &command, status); trace!("Output of command `{}` on stdout: {:?}", &command, &stdout); debug!("Output of command `{}` on stderr: {:?}", &command, &stderr); + + let commands_executed = &mut metrics.commands_executed.lock().unwrap(); // TODO: Check if unwrap need to be fixed + **commands_executed += 1; + + match status { + 0 => { + let commands_successful = &mut metrics.commands_successful.lock().unwrap(); // TODO: Check if unwrap need to be fixed + **commands_successful += 1; + } + _ => { + let commands_failed = &mut metrics.commands_failed.lock().unwrap(); // TODO: Check if unwrap need to be fixed + **commands_failed += 1; + } + } } Err(e) => { error!("Execution of `{}` failed: {}", &command, e); + + let command_execution_failed = + &mut metrics.commands_execution_failed.lock().unwrap(); // TODO: Check if unwrap need to be fixed + **command_execution_failed += 1; } } }); @@ -472,6 +553,49 @@ async fn receive_hook<'a>(address: SocketAddr, hooks: Hooks) -> Status { Status::Ok } +#[get("/metrics")] +async fn metrics(metrics: &State) -> String { + format!( + r"# HELP webhookey_requests_received Number of requests received +# TYPE webhookey_requests_received gauge +webhookey_requests_received {:?} +# HELP webhookey_requests_invalid Number of invalid requests received +# TYPE webhookey_requests_invalid gauge +webhookey_requests_invalid {:?} +# HELP webhookey_hooks_successful Number of successfully executed hooks +# TYPE webhookey_hooks_successful gauge +webhookey_hooks_sucessful {:?} +# HELP webhookey_hooks_forbidden Number of forbidden requests +# TYPE webhookey_hooks_forbidden gauge +webhookey_hooks_forbidden {:?} +# HELP webhookey_hooks_unmatched Number of unmatched requests +# TYPE webhookey_hooks_unmatched gauge +webhookey_hooks_unmatched {:?} +# HELP webhookey_commands_executed Number of commands executed +# TYPE webhookey_commands_executed gauge +webhookey_commands_executed {:?} +# HELP webhookey_commands_execution_failed Number of commands failed to execute +# TYPE webhookey_commands_execution_failed gauge +webhookey_commands_execution_failed {:?} +# HELP webhookey_commands_successful Number of executed commands returning return code 0 +# TYPE webhookey_commands_successful gauge +webhookey_commands_successful {:?} +# HELP webhookey_commands_failed Number of executed commands returning different return code than 0 +# TYPE webhookey_commands_failed gauge +webhookey_commands_failed {:?} +", + metrics.requests_received.lock().unwrap(), // TODO: Check if unwrap need to be fixed + metrics.requests_invalid.lock().unwrap(), // TODO: Check if unwrap need to be fixed + metrics.hooks_successful.lock().unwrap(), // TODO: Check if unwrap need to be fixed + metrics.hooks_forbidden.lock().unwrap(), // TODO: Check if unwrap need to be fixed + metrics.hooks_unmatched.lock().unwrap(), // TODO: Check if unwrap need to be fixed + metrics.commands_executed.lock().unwrap(), // TODO: Check if unwrap need to be fixed + metrics.commands_execution_failed.lock().unwrap(), // TODO: Check if unwrap need to be fixed + metrics.commands_successful.lock().unwrap(), // TODO: Check if unwrap need to be fixed + metrics.commands_failed.lock().unwrap() // TODO: Check if unwrap need to be fixed + ) +} + #[rocket::main] async fn main() -> Result<()> { env_logger::init(); @@ -492,8 +616,9 @@ async fn main() -> Result<()> { } rocket::build() - .mount("/", routes![receive_hook]) + .mount("/", routes![receive_hook, metrics]) .manage(config) + .manage(WebhookeyMetrics::default()) .launch() .await?; @@ -531,7 +656,8 @@ mod tests { let rocket = rocket::build() .mount("/", routes![receive_hook]) - .manage(config); + .manage(config) + .manage(WebhookeyMetrics::default()); let client = Client::tracked(rocket).await.unwrap(); let response = client @@ -718,7 +844,8 @@ mod tests { let rocket = rocket::build() .mount("/", routes![receive_hook]) - .manage(config); + .manage(config) + .manage(WebhookeyMetrics::default()); let client = Client::tracked(rocket).await.unwrap(); @@ -775,7 +902,8 @@ mod tests { let rocket = rocket::build() .mount("/", routes![receive_hook]) - .manage(config); + .manage(config) + .manage(WebhookeyMetrics::default()); let client = Client::tracked(rocket).await.unwrap(); From f0f1d3239dfb18994e414352f8293026428e93b5 Mon Sep 17 00:00:00 2001 From: finga Date: Tue, 9 Nov 2021 13:58:57 +0100 Subject: [PATCH 23/65] Use `BTreeMap` instead of `HashMap` As ordering of `BTreeMap` is easier for testing and the difference does not really matter. --- src/main.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main.rs b/src/main.rs index a681d5d..2bfbf6f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -28,7 +28,7 @@ use sha2::Sha256; use thiserror::Error; use std::{ - collections::HashMap, + collections::BTreeMap, fs::File, io::BufReader, net::{IpAddr, Ipv4Addr, SocketAddr}, @@ -122,7 +122,7 @@ impl IpFilter { #[derive(Debug, Deserialize, Serialize)] #[serde(deny_unknown_fields)] struct Config { - hooks: HashMap, + hooks: BTreeMap, } #[derive(Debug, Deserialize, Serialize)] @@ -239,7 +239,7 @@ impl Hook { #[derive(Debug)] struct Hooks { - inner: HashMap, + inner: BTreeMap, } impl Hooks { @@ -254,7 +254,7 @@ impl Hooks { let config = request.guard::<&State>().await.unwrap(); // should never fail let mut valid = false; - let mut result = HashMap::new(); + let mut result = BTreeMap::new(); let client_ip = &request .client_ip() .unwrap_or(IpAddr::V4(Ipv4Addr::UNSPECIFIED)); @@ -636,7 +636,7 @@ mod tests { #[rocket::async_test] async fn secret() { - let mut hooks = HashMap::new(); + let mut hooks = BTreeMap::new(); hooks.insert( "test_hook".to_string(), @@ -804,7 +804,7 @@ mod tests { #[rocket::async_test] async fn parse_command_request() { - let mut hooks = HashMap::new(); + let mut hooks = BTreeMap::new(); hooks.insert( "test_hook".to_string(), @@ -878,7 +878,7 @@ mod tests { #[rocket::async_test] async fn parse_invalid_command_request() { - let mut hooks = HashMap::new(); + let mut hooks = BTreeMap::new(); hooks.insert( "test_hook".to_string(), From f24a786ec67a02bb21be559e32a5d8526c0ddd4a Mon Sep 17 00:00:00 2001 From: finga Date: Tue, 9 Nov 2021 14:50:02 +0100 Subject: [PATCH 24/65] Make the metrics page configurable Make the metrics page configurable with an `ip_filter`. This closes #10. --- README.md | 14 +++ config.yml | 5 ++ src/main.rs | 246 +++++++++++++++++++++++++++++++++++++++++++--------- 3 files changed, 222 insertions(+), 43 deletions(-) diff --git a/README.md b/README.md index 37dcf4f..9990ed7 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,20 @@ Whereas `` depends on the platform: ### Configuration parameters +#### Metrics +A metrics page can optionally enabled to query stats of the currently +running webhookey instance. Note that stats are lost between restarts +of webhookey as those are not stored persistently. + +Example: +```yaml +metrics: + enabled: true + ip_filter: + allow: + - 127.0.0.1/31 +``` + #### Hooks With `hooks` you can configure a sequence of hooks. A single hook consists of the following fields: diff --git a/config.yml b/config.yml index 4d57324..ae94496 100644 --- a/config.yml +++ b/config.yml @@ -1,4 +1,9 @@ --- +metrics: + enabled: true + ip_filter: + deny: + - 127.0.0.1 hooks: hook1: command: /usr/bin/local/script_xy.sh {{ /field2/foo }} asdfasdf diff --git a/src/main.rs b/src/main.rs index 2bfbf6f..8a870b1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -119,9 +119,17 @@ impl IpFilter { } } +#[derive(Debug, Deserialize, Serialize)] +#[serde(deny_unknown_fields)] +struct MetricsConfig { + enabled: bool, + ip_filter: Option, +} + #[derive(Debug, Deserialize, Serialize)] #[serde(deny_unknown_fields)] struct Config { + metrics: Option, hooks: BTreeMap, } @@ -432,6 +440,48 @@ fn get_config() -> Result { bail!("No configuration file found."); } +fn get_metrics(metrics: &WebhookeyMetrics) -> String { + format!( + r"# HELP webhookey_requests_received Number of requests received +# TYPE webhookey_requests_received gauge +webhookey_requests_received {} +# HELP webhookey_requests_invalid Number of invalid requests received +# TYPE webhookey_requests_invalid gauge +webhookey_requests_invalid {} +# HELP webhookey_hooks_successful Number of successfully executed hooks +# TYPE webhookey_hooks_successful gauge +webhookey_hooks_sucessful {} +# HELP webhookey_hooks_forbidden Number of forbidden requests +# TYPE webhookey_hooks_forbidden gauge +webhookey_hooks_forbidden {} +# HELP webhookey_hooks_unmatched Number of unmatched requests +# TYPE webhookey_hooks_unmatched gauge +webhookey_hooks_unmatched {} +# HELP webhookey_commands_executed Number of commands executed +# TYPE webhookey_commands_executed gauge +webhookey_commands_executed {} +# HELP webhookey_commands_execution_failed Number of commands failed to execute +# TYPE webhookey_commands_execution_failed gauge +webhookey_commands_execution_failed {} +# HELP webhookey_commands_successful Number of executed commands returning return code 0 +# TYPE webhookey_commands_successful gauge +webhookey_commands_successful {} +# HELP webhookey_commands_failed Number of executed commands returning different return code than 0 +# TYPE webhookey_commands_failed gauge +webhookey_commands_failed {} +", + metrics.requests_received.lock().unwrap(), // TODO: Check if unwrap need to be fixed + metrics.requests_invalid.lock().unwrap(), // TODO: Check if unwrap need to be fixed + metrics.hooks_successful.lock().unwrap(), // TODO: Check if unwrap need to be fixed + metrics.hooks_forbidden.lock().unwrap(), // TODO: Check if unwrap need to be fixed + metrics.hooks_unmatched.lock().unwrap(), // TODO: Check if unwrap need to be fixed + metrics.commands_executed.lock().unwrap(), // TODO: Check if unwrap need to be fixed + metrics.commands_execution_failed.lock().unwrap(), // TODO: Check if unwrap need to be fixed + metrics.commands_successful.lock().unwrap(), // TODO: Check if unwrap need to be fixed + metrics.commands_failed.lock().unwrap() // TODO: Check if unwrap need to be fixed + ) +} + #[rocket::async_trait] impl<'r> FromData<'r> for Hooks { type Error = WebhookeyError; @@ -554,46 +604,24 @@ async fn receive_hook<'a>( } #[get("/metrics")] -async fn metrics(metrics: &State) -> String { - format!( - r"# HELP webhookey_requests_received Number of requests received -# TYPE webhookey_requests_received gauge -webhookey_requests_received {:?} -# HELP webhookey_requests_invalid Number of invalid requests received -# TYPE webhookey_requests_invalid gauge -webhookey_requests_invalid {:?} -# HELP webhookey_hooks_successful Number of successfully executed hooks -# TYPE webhookey_hooks_successful gauge -webhookey_hooks_sucessful {:?} -# HELP webhookey_hooks_forbidden Number of forbidden requests -# TYPE webhookey_hooks_forbidden gauge -webhookey_hooks_forbidden {:?} -# HELP webhookey_hooks_unmatched Number of unmatched requests -# TYPE webhookey_hooks_unmatched gauge -webhookey_hooks_unmatched {:?} -# HELP webhookey_commands_executed Number of commands executed -# TYPE webhookey_commands_executed gauge -webhookey_commands_executed {:?} -# HELP webhookey_commands_execution_failed Number of commands failed to execute -# TYPE webhookey_commands_execution_failed gauge -webhookey_commands_execution_failed {:?} -# HELP webhookey_commands_successful Number of executed commands returning return code 0 -# TYPE webhookey_commands_successful gauge -webhookey_commands_successful {:?} -# HELP webhookey_commands_failed Number of executed commands returning different return code than 0 -# TYPE webhookey_commands_failed gauge -webhookey_commands_failed {:?} -", - metrics.requests_received.lock().unwrap(), // TODO: Check if unwrap need to be fixed - metrics.requests_invalid.lock().unwrap(), // TODO: Check if unwrap need to be fixed - metrics.hooks_successful.lock().unwrap(), // TODO: Check if unwrap need to be fixed - metrics.hooks_forbidden.lock().unwrap(), // TODO: Check if unwrap need to be fixed - metrics.hooks_unmatched.lock().unwrap(), // TODO: Check if unwrap need to be fixed - metrics.commands_executed.lock().unwrap(), // TODO: Check if unwrap need to be fixed - metrics.commands_execution_failed.lock().unwrap(), // TODO: Check if unwrap need to be fixed - metrics.commands_successful.lock().unwrap(), // TODO: Check if unwrap need to be fixed - metrics.commands_failed.lock().unwrap() // TODO: Check if unwrap need to be fixed - ) +async fn metrics( + address: SocketAddr, + metrics: &State, + config: &State, +) -> Option { + if let Some(metrics_config) = &config.metrics { + if let Some(filter) = &metrics_config.ip_filter { + if filter.validate(&address.ip()) { + return Some(get_metrics(&metrics)); + } + } else { + return Some(get_metrics(&metrics)); + } + } + + warn!("Forbidden request for metrics: {:?}", address); + + None } #[rocket::main] @@ -652,7 +680,10 @@ mod tests { }, ); - let config = Config { hooks: hooks }; + let config = Config { + metrics: None, + hooks: hooks, + }; let rocket = rocket::build() .mount("/", routes![receive_hook]) @@ -838,7 +869,7 @@ mod tests { ); let config = Config { - // default: None, + metrics: None, hooks: hooks, }; @@ -896,7 +927,7 @@ mod tests { ); let config = Config { - // default: None, + metrics: None, hooks: hooks, }; @@ -933,4 +964,133 @@ mod tests { assert_eq!(response.await.status(), Status::NotFound); } + + #[test] + fn parse_config() { + let config: Config = serde_yaml::from_str( + r#"--- +hooks: + hook1: + command: /usr/bin/local/script_xy.sh {{ /field2/foo }} asdfasdf + signature: X-Gitea-Signature + ip_filter: + allow: + - 127.0.0.1/31 + secrets: + - secret_key_01 + - secret_key_02 + filter: + json: + pointer: /ref + regex: refs/heads/master + hook2: + command: /usr/bin/local/script_xy.sh asdfasdf + signature: X-Gitea-Signature + secrets: + - secret_key_01 + - secret_key_02 + filter: + and: + - json: + pointer: /ref + regex: refs/heads/master + - json: + pointer: /after + regex: f6e5fe4fe37df76629112d55cc210718b6a55e7e"#, + ) + .unwrap(); + + assert_eq!( + serde_yaml::to_string(&config).unwrap(), + serde_yaml::to_string(&Config { + metrics: None, + hooks: BTreeMap::from([ + ( + "hook1".to_string(), + Hook { + command: "/usr/bin/local/script_xy.sh {{ /field2/foo }} asdfasdf" + .to_string(), + signature: "X-Gitea-Signature".to_string(), + ip_filter: Some(IpFilter::Allow(vec![AddrType::IpNet( + "127.0.0.1/31".parse().unwrap() + )])), + secrets: vec!["secret_key_01".to_string(), "secret_key_02".to_string()], + filter: FilterType::JsonFilter(JsonFilter { + pointer: "/ref".to_string(), + regex: "refs/heads/master".to_string(), + }), + } + ), + ( + "hook2".to_string(), + Hook { + command: "/usr/bin/local/script_xy.sh asdfasdf".to_string(), + signature: "X-Gitea-Signature".to_string(), + ip_filter: None, + secrets: vec!["secret_key_01".to_string(), "secret_key_02".to_string()], + filter: FilterType::And(vec![ + FilterType::JsonFilter(JsonFilter { + pointer: "/ref".to_string(), + regex: "refs/heads/master".to_string(), + }), + FilterType::JsonFilter(JsonFilter { + pointer: "/after".to_string(), + regex: "f6e5fe4fe37df76629112d55cc210718b6a55e7e".to_string(), + }), + ]), + } + ) + ]) + }) + .unwrap() + ); + + let config: Config = serde_yaml::from_str( + r#"--- +metrics: + enabled: true +hooks: + hook1: + command: /usr/bin/local/script_xy.sh {{ /field2/foo }} asdfasdf + signature: X-Gitea-Signature + ip_filter: + allow: + - 127.0.0.1/31 + secrets: + - secret_key_01 + - secret_key_02 + filter: + json: + pointer: /ref + regex: refs/heads/master"#, + ) + .unwrap(); + + assert_eq!( + serde_yaml::to_string(&config).unwrap(), + serde_yaml::to_string(&Config { + metrics: Some(MetricsConfig { + enabled: true, + ip_filter: None + }), + hooks: BTreeMap::from([( + "hook1".to_string(), + Hook { + command: "/usr/bin/local/script_xy.sh {{ /field2/foo }} asdfasdf" + .to_string(), + signature: "X-Gitea-Signature".to_string(), + ip_filter: Some(IpFilter::Allow(vec![AddrType::IpNet( + "127.0.0.1/31".parse().unwrap() + )])), + secrets: vec!["secret_key_01".to_string(), "secret_key_02".to_string()], + filter: FilterType::JsonFilter(JsonFilter { + pointer: "/ref".to_string(), + regex: "refs/heads/master".to_string(), + }), + } + ),]) + }) + .unwrap() + ); + } } From b2205ea5f4f2ee08babaf2240a272ef0adfdb82d Mon Sep 17 00:00:00 2001 From: finga Date: Wed, 10 Nov 2021 10:35:47 +0100 Subject: [PATCH 25/65] Increase version to `0.1.2` Also update build dependencies and fix readme. --- Cargo.lock | 6 +++--- Cargo.toml | 2 +- config.yml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 33cf72f..f1f33a2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -674,9 +674,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.106" +version = "0.2.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a60553f9a9e039a333b4e9b20573b9e9b9c0bb3a11e201ccc48ef4283456d673" +checksum = "fbe5e23404da5b4f555ef85ebed98fb4083e55a00c317800bc2a50ede9f3d219" [[package]] name = "linked-hash-map" @@ -1933,7 +1933,7 @@ dependencies = [ [[package]] name = "webhookey" -version = "0.1.1" +version = "0.1.2" dependencies = [ "anyhow", "clap", diff --git a/Cargo.toml b/Cargo.toml index 1c69f4d..aa7b18d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "webhookey" -version = "0.1.1" +version = "0.1.2" authors = ["finga "] edition = "2021" license = "GPL-3.0-or-later" diff --git a/config.yml b/config.yml index ae94496..2dcaa9e 100644 --- a/config.yml +++ b/config.yml @@ -2,7 +2,7 @@ metrics: enabled: true ip_filter: - deny: + allow: - 127.0.0.1 hooks: hook1: From d92e8029f2f1cc91dd987ee63594752f1bd0c0f6 Mon Sep 17 00:00:00 2001 From: finga Date: Thu, 11 Nov 2021 21:09:47 +0100 Subject: [PATCH 26/65] Break up code into multiple files In order to increase readability, maintainability and maybe a future independence regarding web frameworks move code to new files. --- src/cli.rs | 22 ++++++ src/main.rs | 185 +++--------------------------------------------- src/webhooks.rs | 159 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 191 insertions(+), 175 deletions(-) create mode 100644 src/cli.rs create mode 100644 src/webhooks.rs diff --git a/src/cli.rs b/src/cli.rs new file mode 100644 index 0000000..63c024d --- /dev/null +++ b/src/cli.rs @@ -0,0 +1,22 @@ +use clap::{crate_authors, crate_version, AppSettings, Parser}; + +#[derive(Debug, Parser)] +pub enum Command { + /// Verifies if the configuration can be parsed without errors + Configtest, +} + +#[derive(Debug, Parser)] +#[clap( + version = crate_version!(), + author = crate_authors!(", "), + global_setting = AppSettings::InferSubcommands, + global_setting = AppSettings::PropagateVersion, +)] +pub struct Opts { + /// Provide a path to the configuration file + #[clap(short, long, value_name = "FILE")] + pub config: Option, + #[clap(subcommand)] + pub command: Option, +} diff --git a/src/main.rs b/src/main.rs index 8a870b1..ca3daec 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,6 @@ use anyhow::{anyhow, bail, Result}; -use clap::{crate_authors, crate_version, AppSettings, Parser}; +use clap::Parser; use hmac::{Hmac, Mac, NewMac}; -use ipnet::IpNet; use log::{debug, error, info, trace, warn}; use nom::{ branch::alt, @@ -11,7 +10,6 @@ use nom::{ sequence::delimited, Finish, IResult, }; -use regex::Regex; use rocket::{ data::{FromData, ToByteUnit}, futures::TryFutureExt, @@ -25,7 +23,6 @@ use rocket::{ use run_script::ScriptOptions; use serde::{Deserialize, Serialize}; use sha2::Sha256; -use thiserror::Error; use std::{ collections::BTreeMap, @@ -35,44 +32,13 @@ use std::{ sync::Mutex, }; -#[derive(Debug, Error)] -enum WebhookeyError { - #[error("Could not extract signature from header")] - InvalidSignature, - #[error("Unauthorized request from `{0}`")] - Unauthorized(IpAddr), - #[error("Unmatched hook from `{0}`")] - UnmatchedHook(IpAddr), - #[error("Could not evaluate filter request")] - InvalidFilter, - #[error("IO Error")] - Io(std::io::Error), - #[error("Serde Error")] - Serde(serde_json::Error), - #[error("Regex Error")] - Regex(regex::Error), -} +mod cli; +mod webhooks; -#[derive(Debug, Parser)] -enum Command { - /// Verifies if the configuration can be parsed without errors - Configtest, -} - -#[derive(Debug, Parser)] -#[clap( - version = crate_version!(), - author = crate_authors!(", "), - global_setting = AppSettings::InferSubcommands, - global_setting = AppSettings::PropagateVersion, -)] -struct Opts { - /// Provide a path to the configuration file - #[clap(short, long, value_name = "FILE")] - config: Option, - #[clap(subcommand)] - command: Option, -} +use crate::{ + cli::Opts, + webhooks::{FilterType, IpFilter, WebhookeyError}, +}; #[derive(Debug, Default)] struct WebhookeyMetrics { @@ -87,38 +53,6 @@ struct WebhookeyMetrics { commands_failed: Mutex, } -#[derive(Debug, Deserialize, Serialize)] -#[serde(deny_unknown_fields, untagged)] -enum AddrType { - IpAddr(IpAddr), - IpNet(IpNet), -} - -impl AddrType { - fn matches(&self, client_ip: &IpAddr) -> bool { - match self { - AddrType::IpAddr(addr) => addr == client_ip, - AddrType::IpNet(net) => net.contains(client_ip), - } - } -} - -#[derive(Debug, Deserialize, Serialize)] -#[serde(deny_unknown_fields, rename_all = "lowercase")] -enum IpFilter { - Allow(Vec), - Deny(Vec), -} - -impl IpFilter { - fn validate(&self, client_ip: &IpAddr) -> bool { - match self { - IpFilter::Allow(list) => list.iter().any(|i| i.matches(client_ip)), - IpFilter::Deny(list) => !list.iter().any(|i| i.matches(client_ip)), - } - } -} - #[derive(Debug, Deserialize, Serialize)] #[serde(deny_unknown_fields)] struct MetricsConfig { @@ -129,99 +63,11 @@ struct MetricsConfig { #[derive(Debug, Deserialize, Serialize)] #[serde(deny_unknown_fields)] struct Config { + // default: Option, metrics: Option, hooks: BTreeMap, } -#[derive(Debug, Deserialize, Serialize)] -#[serde(deny_unknown_fields)] -struct JsonFilter { - pointer: String, - regex: String, -} - -impl JsonFilter { - fn evaluate(&self, data: &serde_json::Value) -> Result { - trace!( - "Matching `{}` on `{}` from received json", - &self.regex, - &self.pointer, - ); - - let regex = Regex::new(&self.regex).map_err(WebhookeyError::Regex)?; - - if let Some(value) = data.pointer(&self.pointer) { - let value = get_string(value)?; - - if regex.is_match(&value) { - debug!("Regex `{}` for `{}` matches", &self.regex, &self.pointer); - - return Ok(true); - } - } - - debug!( - "Regex `{}` for `{}` does not match", - &self.regex, &self.pointer - ); - - Ok(false) - } -} - -#[derive(Debug, Deserialize, Serialize)] -#[serde(deny_unknown_fields, rename_all = "lowercase")] -enum FilterType { - And(Vec), - Or(Vec), - #[serde(rename = "json")] - JsonFilter(JsonFilter), -} - -impl FilterType { - fn evaluate( - &self, - request: &Request, - data: &serde_json::Value, - ) -> Result { - match self { - FilterType::And(filters) => { - let (results, errors): (Vec<_>, Vec<_>) = filters - .iter() - .map(|filter| filter.evaluate(request, data)) - .partition(Result::is_ok); - - if errors.is_empty() { - Ok(results.iter().all(|r| *r.as_ref().unwrap())) // should never fail - } else { - errors.iter().for_each(|e| { - error!("Could not evaluate Filter: {}", e.as_ref().unwrap_err()) - }); - - Err(WebhookeyError::InvalidFilter) - } - } - FilterType::Or(filters) => { - let (results, errors): (Vec<_>, Vec<_>) = filters - .iter() - .map(|filter| filter.evaluate(request, data)) - .partition(Result::is_ok); - - if errors.is_empty() { - Ok(results.iter().any(|r| *r.as_ref().unwrap())) // should never fail - } else { - errors.iter().for_each(|e| { - error!("Could not evaluate Filter: {}", e.as_ref().unwrap_err()) - }); - - Err(WebhookeyError::InvalidFilter) - } - } - FilterType::JsonFilter(filter) => filter.evaluate(data), - } - } -} - #[derive(Debug, Deserialize, Serialize)] #[serde(deny_unknown_fields)] struct Hook { @@ -300,7 +146,7 @@ impl Hooks { let data: serde_json::Value = serde_json::from_slice(&buffer).map_err(WebhookeyError::Serde)?; - match hook.filter.evaluate(request, &data) { + match hook.filter.evaluate(&data) { Ok(true) => match hook.get_command(hook_name, request, &data) { Ok(command) => { info!("Filter for `{}` matched", &hook_name); @@ -366,18 +212,6 @@ fn get_value_from_pointer<'a>(data: &'a serde_json::Value, pointer: &'a str) -> .ok_or_else(|| anyhow!("Could not convert value `{}` to string", value)) } -fn get_string(value: &serde_json::Value) -> Result { - match &value { - serde_json::Value::Bool(bool) => Ok(bool.to_string()), - serde_json::Value::Number(number) => Ok(number.to_string()), - serde_json::Value::String(string) => Ok(string.as_str().to_string()), - x => { - error!("Could not get string from: {:?}", x); - unimplemented!() - } - } -} - fn replace_parameters( input: &str, headers: &HeaderMap, @@ -656,6 +490,7 @@ async fn main() -> Result<()> { #[cfg(test)] mod tests { use super::*; + use crate::webhooks::{AddrType, JsonFilter}; use rocket::{ http::{ContentType, Header}, local::asynchronous::Client, diff --git a/src/webhooks.rs b/src/webhooks.rs new file mode 100644 index 0000000..fee01c7 --- /dev/null +++ b/src/webhooks.rs @@ -0,0 +1,159 @@ +use anyhow::Result; +use ipnet::IpNet; +use log::{debug, error, trace}; +use regex::Regex; +use serde::{Deserialize, Serialize}; +use std::net::IpAddr; +use thiserror::Error; + +#[derive(Debug, Error)] +pub enum WebhookeyError { + #[error("Could not extract signature from header")] + InvalidSignature, + #[error("Unauthorized request from `{0}`")] + Unauthorized(IpAddr), + #[error("Unmatched hook from `{0}`")] + UnmatchedHook(IpAddr), + #[error("Could not evaluate filter request")] + InvalidFilter, + #[error("IO Error")] + Io(std::io::Error), + #[error("Serde Error")] + Serde(serde_json::Error), + #[error("Regex Error")] + Regex(regex::Error), +} + +#[derive(Debug, Deserialize, Serialize)] +#[serde(deny_unknown_fields, untagged)] +pub enum AddrType { + IpAddr(IpAddr), + IpNet(IpNet), +} + +impl AddrType { + pub fn matches(&self, client_ip: &IpAddr) -> bool { + match self { + AddrType::IpAddr(addr) => addr == client_ip, + AddrType::IpNet(net) => net.contains(client_ip), + } + } +} + +#[derive(Debug, Deserialize, Serialize)] +#[serde(deny_unknown_fields, rename_all = "lowercase")] +pub enum IpFilter { + Allow(Vec), + Deny(Vec), +} + +impl IpFilter { + pub fn validate(&self, client_ip: &IpAddr) -> bool { + match self { + IpFilter::Allow(list) => list.iter().any(|i| i.matches(client_ip)), + IpFilter::Deny(list) => !list.iter().any(|i| i.matches(client_ip)), + } + } +} + +#[derive(Debug, Deserialize, Serialize)] +#[serde(deny_unknown_fields)] +pub struct JsonFilter { + pub pointer: String, + pub regex: String, +} + +impl JsonFilter { + pub fn evaluate(&self, data: &serde_json::Value) -> Result { + trace!( + "Matching `{}` on `{}` from received json", + &self.regex, + &self.pointer, + ); + + let regex = Regex::new(&self.regex).map_err(WebhookeyError::Regex)?; + // let value = self.get_string(data)?; + + // if let Some(value) = self.get_string() {data.pointer(&self.pointer) { + // let value = get_string(); + + if let Some(value) = data.pointer(&self.pointer) { + if regex.is_match(&self.get_string(&value)?) { + debug!("Regex `{}` for `{}` matches", &self.regex, &self.pointer); + + return Ok(true); + } + } + + debug!( + "Regex `{}` for `{}` does not match", + &self.regex, &self.pointer + ); + + Ok(false) + } + + fn get_string(&self, data: &serde_json::Value) -> Result { + match &data { + serde_json::Value::Bool(bool) => Ok(bool.to_string()), + serde_json::Value::Number(number) => Ok(number.to_string()), + serde_json::Value::String(string) => Ok(string.as_str().to_string()), + x => { + error!("Could not get string from: {:?}", x); + unimplemented!() + } + } + } +} + +#[derive(Debug, Deserialize, Serialize)] +#[serde(deny_unknown_fields, rename_all = "lowercase")] +pub enum FilterType { + And(Vec), + Or(Vec), + // #[serde(rename = "header")] + // HeaderFilter(HeaderFilter), + #[serde(rename = "json")] + JsonFilter(JsonFilter), +} + +impl FilterType { + pub fn evaluate(&self, data: &serde_json::Value) -> Result { + match self { + FilterType::And(filters) => { + let (results, errors): (Vec<_>, Vec<_>) = filters + .iter() + .map(|filter| filter.evaluate(data)) + .partition(Result::is_ok); + + if errors.is_empty() { + Ok(results.iter().all(|r| *r.as_ref().unwrap())) // should never fail + } else { + errors.iter().for_each(|e| { + error!("Could not evaluate Filter: {}", e.as_ref().unwrap_err()) + }); + + Err(WebhookeyError::InvalidFilter) + } + } + FilterType::Or(filters) => { + let (results, errors): (Vec<_>, Vec<_>) = filters + .iter() + .map(|filter| filter.evaluate(data)) + .partition(Result::is_ok); + + if errors.is_empty() { + Ok(results.iter().any(|r| *r.as_ref().unwrap())) // should never fail + } else { + errors.iter().for_each(|e| { + error!("Could not evaluate Filter: {}", e.as_ref().unwrap_err()) + }); + + Err(WebhookeyError::InvalidFilter) + } + } + // FilterType::HeaderFilter(filter) => todo!(), + FilterType::JsonFilter(filter) => filter.evaluate(data), + } + } +} From b4b46ebd587fb9be59360a81623d7080366431f0 Mon Sep 17 00:00:00 2001 From: finga Date: Sat, 13 Nov 2021 14:16:21 +0100 Subject: [PATCH 27/65] Refactor filters Clean up some comments and refactor the code to improve readability and to get rid of "ugly" unwraps. --- src/webhooks.rs | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/src/webhooks.rs b/src/webhooks.rs index fee01c7..701c3d4 100644 --- a/src/webhooks.rs +++ b/src/webhooks.rs @@ -72,10 +72,6 @@ impl JsonFilter { ); let regex = Regex::new(&self.regex).map_err(WebhookeyError::Regex)?; - // let value = self.get_string(data)?; - - // if let Some(value) = self.get_string() {data.pointer(&self.pointer) { - // let value = get_string(); if let Some(value) = data.pointer(&self.pointer) { if regex.is_match(&self.get_string(&value)?) { @@ -121,33 +117,43 @@ impl FilterType { pub fn evaluate(&self, data: &serde_json::Value) -> Result { match self { FilterType::And(filters) => { - let (results, errors): (Vec<_>, Vec<_>) = filters + let (mut results, mut errors) = (Vec::new(), Vec::new()); + + filters .iter() .map(|filter| filter.evaluate(data)) - .partition(Result::is_ok); + .for_each(|item| match item { + Ok(o) => results.push(o), + Err(e) => errors.push(e), + }); if errors.is_empty() { - Ok(results.iter().all(|r| *r.as_ref().unwrap())) // should never fail + Ok(results.iter().all(|r| *r)) } else { - errors.iter().for_each(|e| { - error!("Could not evaluate Filter: {}", e.as_ref().unwrap_err()) - }); + errors + .iter() + .for_each(|e| error!("Could not evaluate Filter: {}", e)); Err(WebhookeyError::InvalidFilter) } } FilterType::Or(filters) => { - let (results, errors): (Vec<_>, Vec<_>) = filters + let (mut results, mut errors) = (Vec::new(), Vec::new()); + + filters .iter() .map(|filter| filter.evaluate(data)) - .partition(Result::is_ok); + .for_each(|item| match item { + Ok(o) => results.push(o), + Err(e) => errors.push(e), + }); if errors.is_empty() { - Ok(results.iter().any(|r| *r.as_ref().unwrap())) // should never fail + Ok(results.iter().any(|r| *r)) } else { - errors.iter().for_each(|e| { - error!("Could not evaluate Filter: {}", e.as_ref().unwrap_err()) - }); + errors + .iter() + .for_each(|e| error!("Could not evaluate Filter: {}", e)); Err(WebhookeyError::InvalidFilter) } From a122bf28d2741e3ac3ca75008671b7ed34bb0059 Mon Sep 17 00:00:00 2001 From: finga Date: Sat, 13 Nov 2021 14:35:40 +0100 Subject: [PATCH 28/65] Use atomics instead of mutexes Use atomics instead of mutexes to improve access on metrics. Therefor also remove unneeded borrows. --- src/main.rs | 93 ++++++++++++++++++++----------------------------- src/webhooks.rs | 2 +- 2 files changed, 38 insertions(+), 57 deletions(-) diff --git a/src/main.rs b/src/main.rs index ca3daec..815ec9e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -29,7 +29,7 @@ use std::{ fs::File, io::BufReader, net::{IpAddr, Ipv4Addr, SocketAddr}, - sync::Mutex, + sync::atomic::{AtomicUsize, Ordering}, }; mod cli; @@ -42,15 +42,15 @@ use crate::{ #[derive(Debug, Default)] struct WebhookeyMetrics { - requests_received: Mutex, - requests_invalid: Mutex, - hooks_successful: Mutex, - hooks_forbidden: Mutex, - hooks_unmatched: Mutex, - commands_executed: Mutex, - commands_execution_failed: Mutex, - commands_successful: Mutex, - commands_failed: Mutex, + requests_received: AtomicUsize, + requests_invalid: AtomicUsize, + hooks_successful: AtomicUsize, + hooks_forbidden: AtomicUsize, + hooks_unmatched: AtomicUsize, + commands_executed: AtomicUsize, + commands_execution_failed: AtomicUsize, + commands_successful: AtomicUsize, + commands_failed: AtomicUsize, } #[derive(Debug, Deserialize, Serialize)] @@ -304,15 +304,15 @@ webhookey_commands_successful {} # TYPE webhookey_commands_failed gauge webhookey_commands_failed {} ", - metrics.requests_received.lock().unwrap(), // TODO: Check if unwrap need to be fixed - metrics.requests_invalid.lock().unwrap(), // TODO: Check if unwrap need to be fixed - metrics.hooks_successful.lock().unwrap(), // TODO: Check if unwrap need to be fixed - metrics.hooks_forbidden.lock().unwrap(), // TODO: Check if unwrap need to be fixed - metrics.hooks_unmatched.lock().unwrap(), // TODO: Check if unwrap need to be fixed - metrics.commands_executed.lock().unwrap(), // TODO: Check if unwrap need to be fixed - metrics.commands_execution_failed.lock().unwrap(), // TODO: Check if unwrap need to be fixed - metrics.commands_successful.lock().unwrap(), // TODO: Check if unwrap need to be fixed - metrics.commands_failed.lock().unwrap() // TODO: Check if unwrap need to be fixed + metrics.requests_received.load(Ordering::Relaxed), + metrics.requests_invalid.load(Ordering::Relaxed), + metrics.hooks_successful.load(Ordering::Relaxed), + metrics.hooks_forbidden.load(Ordering::Relaxed), + metrics.hooks_unmatched.load(Ordering::Relaxed), + metrics.commands_executed.load(Ordering::Relaxed), + metrics.commands_execution_failed.load(Ordering::Relaxed), + metrics.commands_successful.load(Ordering::Relaxed), + metrics.commands_failed.load(Ordering::Relaxed), ) } @@ -325,15 +325,12 @@ impl<'r> FromData<'r> for Hooks { data: Data<'r>, ) -> Outcome> { { - let requests_received = &mut request + request .guard::<&State>() .await .unwrap() // TODO: Check if unwrap need to be fixed .requests_received - .lock() - .unwrap(); // TODO: Check if unwrap need to be fixed - - **requests_received += 1; + .fetch_add(1, Ordering::Relaxed); } match Hooks::get_commands(request, data).await { @@ -343,15 +340,12 @@ impl<'r> FromData<'r> for Hooks { .client_ip() .unwrap_or(IpAddr::V4(Ipv4Addr::UNSPECIFIED)); - let hooks_unmatched = &mut request + request .guard::<&State>() .await .unwrap() // TODO: Check if unwrap need to be fixed .hooks_unmatched - .lock() - .unwrap(); // TODO: Check if unwrap need to be fixed - - **hooks_unmatched += 1; + .fetch_add(1, Ordering::Relaxed); warn!("Unmatched hook from {}", &client_ip); return Failure((Status::NotFound, WebhookeyError::UnmatchedHook(*client_ip))); @@ -362,30 +356,24 @@ impl<'r> FromData<'r> for Hooks { Err(WebhookeyError::Unauthorized(e)) => { error!("{}", WebhookeyError::Unauthorized(e)); - let hooks_forbidden = &mut request + request .guard::<&State>() .await .unwrap() // TODO: Check if unwrap need to be fixed .hooks_forbidden - .lock() - .unwrap(); // TODO: Check if unwrap need to be fixed - - **hooks_forbidden += 1; + .fetch_add(1, Ordering::Relaxed); Failure((Status::Unauthorized, WebhookeyError::Unauthorized(e))) } Err(e) => { error!("{}", e); - let requests_invalid = &mut request + request .guard::<&State>() .await .unwrap() // TODO: Check if unwrap need to be fixed .requests_invalid - .lock() - .unwrap(); // TODO: Check if unwrap need to be fixed - - **requests_invalid += 1; + .fetch_add(1, Ordering::Relaxed); Failure((Status::BadRequest, e)) } @@ -410,26 +398,19 @@ async fn receive_hook<'a>( trace!("Output of command `{}` on stdout: {:?}", &command, &stdout); debug!("Output of command `{}` on stderr: {:?}", &command, &stderr); - let commands_executed = &mut metrics.commands_executed.lock().unwrap(); // TODO: Check if unwrap need to be fixed - **commands_executed += 1; + metrics.commands_executed.fetch_add(1, Ordering::Relaxed); - match status { - 0 => { - let commands_successful = &mut metrics.commands_successful.lock().unwrap(); // TODO: Check if unwrap need to be fixed - **commands_successful += 1; - } - _ => { - let commands_failed = &mut metrics.commands_failed.lock().unwrap(); // TODO: Check if unwrap need to be fixed - **commands_failed += 1; - } - } + let _ = match status { + 0 => metrics.commands_successful.fetch_add(1, Ordering::Relaxed), + _ => metrics.commands_failed.fetch_add(1, Ordering::Relaxed), + }; } Err(e) => { error!("Execution of `{}` failed: {}", &command, e); - let command_execution_failed = - &mut metrics.commands_execution_failed.lock().unwrap(); // TODO: Check if unwrap need to be fixed - **command_execution_failed += 1; + metrics + .commands_execution_failed + .fetch_add(1, Ordering::Relaxed); } } }); @@ -446,10 +427,10 @@ async fn metrics( if let Some(metrics_config) = &config.metrics { if let Some(filter) = &metrics_config.ip_filter { if filter.validate(&address.ip()) { - return Some(get_metrics(&metrics)); + return Some(get_metrics(metrics)); } } else { - return Some(get_metrics(&metrics)); + return Some(get_metrics(metrics)); } } diff --git a/src/webhooks.rs b/src/webhooks.rs index 701c3d4..caf8c06 100644 --- a/src/webhooks.rs +++ b/src/webhooks.rs @@ -74,7 +74,7 @@ impl JsonFilter { let regex = Regex::new(&self.regex).map_err(WebhookeyError::Regex)?; if let Some(value) = data.pointer(&self.pointer) { - if regex.is_match(&self.get_string(&value)?) { + if regex.is_match(&self.get_string(value)?) { debug!("Regex `{}` for `{}` matches", &self.regex, &self.pointer); return Ok(true); From e7e136195b07b29f6bcaf879ab0f3edaddebfcc0 Mon Sep 17 00:00:00 2001 From: finga Date: Sat, 13 Nov 2021 19:43:39 +0100 Subject: [PATCH 29/65] Fix metrics check when disabled Previously, disabled metrics had no effect and a request to the `/metrics` route was answered nonetheless. Remove needles borrow --- src/main.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main.rs b/src/main.rs index 815ec9e..e638791 100644 --- a/src/main.rs +++ b/src/main.rs @@ -425,12 +425,14 @@ async fn metrics( config: &State, ) -> Option { if let Some(metrics_config) = &config.metrics { - if let Some(filter) = &metrics_config.ip_filter { - if filter.validate(&address.ip()) { + if metrics_config.enabled { + if let Some(filter) = &metrics_config.ip_filter { + if filter.validate(&address.ip()) { + return Some(get_metrics(metrics)); + } + } else { return Some(get_metrics(metrics)); } - } else { - return Some(get_metrics(metrics)); } } From 4a54aabf2676b61a52d8a3ac74c08177168c2ba8 Mon Sep 17 00:00:00 2001 From: finga Date: Sat, 13 Nov 2021 19:56:38 +0100 Subject: [PATCH 30/65] Increase version to `v0.1.3` Increase version to `v0.1.3` and update build deps. --- Cargo.lock | 14 +++++++------- Cargo.toml | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f1f33a2..96529cd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -60,9 +60,9 @@ dependencies = [ [[package]] name = "atomic" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3410529e8288c463bedb5930f82833bc0c90e5d2fe639a56582a4d09220b281" +checksum = "b88d82667eca772c4aa12f0f1348b3ae643424c8876448f3f7bd5787032e234c" dependencies = [ "autocfg", ] @@ -131,9 +131,9 @@ checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" [[package]] name = "cc" -version = "1.0.71" +version = "1.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79c2681d6594606957bbb8631c4b90a7fcaaa72cdb714743a437b156d6a7eedd" +checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee" [[package]] name = "cfg-if" @@ -1309,9 +1309,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.69" +version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e466864e431129c7e0d3476b92f20458e5879919a0596c6472738d9fa2d342f8" +checksum = "e277c495ac6cd1a01a58d0a0c574568b4d1ddf14f59965c6a58b8d96400b54f3" dependencies = [ "itoa", "ryu", @@ -1933,7 +1933,7 @@ dependencies = [ [[package]] name = "webhookey" -version = "0.1.2" +version = "0.1.3" dependencies = [ "anyhow", "clap", diff --git a/Cargo.toml b/Cargo.toml index aa7b18d..28246a8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "webhookey" -version = "0.1.2" +version = "0.1.3" authors = ["finga "] edition = "2021" license = "GPL-3.0-or-later" From 3a482a3eb9820d626b2339a8384ef20eb96b1db5 Mon Sep 17 00:00:00 2001 From: finga Date: Sun, 14 Nov 2021 11:58:34 +0100 Subject: [PATCH 31/65] Remove prototyping code which is commented out This comments are ment for future development and not for the main branch yet. --- src/main.rs | 1 - src/webhooks.rs | 2 -- 2 files changed, 3 deletions(-) diff --git a/src/main.rs b/src/main.rs index e638791..03c6a78 100644 --- a/src/main.rs +++ b/src/main.rs @@ -63,7 +63,6 @@ struct MetricsConfig { #[derive(Debug, Deserialize, Serialize)] #[serde(deny_unknown_fields)] struct Config { - // default: Option, metrics: Option, hooks: BTreeMap, } diff --git a/src/webhooks.rs b/src/webhooks.rs index caf8c06..f9f8b24 100644 --- a/src/webhooks.rs +++ b/src/webhooks.rs @@ -107,8 +107,6 @@ impl JsonFilter { pub enum FilterType { And(Vec), Or(Vec), - // #[serde(rename = "header")] - // HeaderFilter(HeaderFilter), #[serde(rename = "json")] JsonFilter(JsonFilter), } From 4b9186b10d108c6df14f8de92b487fc931d9a845 Mon Sep 17 00:00:00 2001 From: finga Date: Tue, 16 Nov 2021 14:39:22 +0100 Subject: [PATCH 32/65] Fix json parsing bug Increase version for building a new Debian package. --- Cargo.toml | 2 +- src/main.rs | 29 ++++++++++++++++++++++++++--- src/webhooks.rs | 28 +++++++++++++++------------- 3 files changed, 42 insertions(+), 17 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 28246a8..0b63cad 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "webhookey" -version = "0.1.3" +version = "0.1.4" authors = ["finga "] edition = "2021" license = "GPL-3.0-or-later" diff --git a/src/main.rs b/src/main.rs index 03c6a78..d0e7eb8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -82,12 +82,35 @@ impl Hook { &self, hook_name: &str, request: &Request, - data: &serde_json::Value, + data: &mut serde_json::Value, ) -> Result { trace!("Replacing parameters for command of hook `{}`", hook_name); + for parameter in self.get_parameter()? { + let parameter = parameter.trim(); + + if let Some(json_value) = data.pointer(parameter) { + *data.pointer_mut(parameter).ok_or_else(|| { + WebhookeyError::InvalidParameterPointer(parameter.to_string()) + })? = serde_json::Value::String(webhooks::get_string(json_value)?); + } + } + replace_parameters(&self.command, request.headers(), data) } + + fn get_parameter(&self) -> Result> { + let parse: IResult<&str, Vec<&str>> = many0(alt(( + delimited(tag("{{"), take_until("}}"), tag("}}")), + take_until("{{"), + )))(&self.command); + + let (_last, result) = parse + .finish() + .map_err(|e| anyhow!("Could not get parameters from command: {}", e))?; + + Ok(result) + } } #[derive(Debug)] @@ -142,11 +165,11 @@ impl Hooks { valid = true; - let data: serde_json::Value = + let mut data: serde_json::Value = serde_json::from_slice(&buffer).map_err(WebhookeyError::Serde)?; match hook.filter.evaluate(&data) { - Ok(true) => match hook.get_command(hook_name, request, &data) { + Ok(true) => match hook.get_command(hook_name, request, &mut data) { Ok(command) => { info!("Filter for `{}` matched", &hook_name); result.insert(hook_name.to_string(), command); diff --git a/src/webhooks.rs b/src/webhooks.rs index f9f8b24..85a52d1 100644 --- a/src/webhooks.rs +++ b/src/webhooks.rs @@ -14,6 +14,8 @@ pub enum WebhookeyError { Unauthorized(IpAddr), #[error("Unmatched hook from `{0}`")] UnmatchedHook(IpAddr), + #[error("Could not find field refered to in parameter `{0}`")] + InvalidParameterPointer(String), #[error("Could not evaluate filter request")] InvalidFilter, #[error("IO Error")] @@ -74,7 +76,7 @@ impl JsonFilter { let regex = Regex::new(&self.regex).map_err(WebhookeyError::Regex)?; if let Some(value) = data.pointer(&self.pointer) { - if regex.is_match(&self.get_string(value)?) { + if regex.is_match(&get_string(value)?) { debug!("Regex `{}` for `{}` matches", &self.regex, &self.pointer); return Ok(true); @@ -88,18 +90,6 @@ impl JsonFilter { Ok(false) } - - fn get_string(&self, data: &serde_json::Value) -> Result { - match &data { - serde_json::Value::Bool(bool) => Ok(bool.to_string()), - serde_json::Value::Number(number) => Ok(number.to_string()), - serde_json::Value::String(string) => Ok(string.as_str().to_string()), - x => { - error!("Could not get string from: {:?}", x); - unimplemented!() - } - } - } } #[derive(Debug, Deserialize, Serialize)] @@ -161,3 +151,15 @@ impl FilterType { } } } + +pub fn get_string(data: &serde_json::Value) -> Result { + match &data { + serde_json::Value::Bool(bool) => Ok(bool.to_string()), + serde_json::Value::Number(number) => Ok(number.to_string()), + serde_json::Value::String(string) => Ok(string.as_str().to_string()), + x => { + error!("Could not get string from: {:?}", x); + unimplemented!() + } + } +} From 4d39488c320f9f5a6d0585a917d24751d293cb79 Mon Sep 17 00:00:00 2001 From: finga Date: Wed, 17 Nov 2021 13:17:15 +0100 Subject: [PATCH 33/65] Use a custom parser for commands The removes the dependency for `nom` as commands are now parsed with its own tiny parser. --- Cargo.lock | 20 +----- Cargo.toml | 3 +- src/main.rs | 173 ++++++++++++++++++++++++------------------------ src/webhooks.rs | 2 - 4 files changed, 89 insertions(+), 109 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 96529cd..e7c10da 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -738,12 +738,6 @@ version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - [[package]] name = "mio" version = "0.7.14" @@ -786,17 +780,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "nom" -version = "7.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1d11e1ef389c76fe5b81bcaf2ea32cf88b62bc494e19f493d0b30e7a930109" -dependencies = [ - "memchr", - "minimal-lexical", - "version_check", -] - [[package]] name = "ntapi" version = "0.3.6" @@ -1933,7 +1916,7 @@ dependencies = [ [[package]] name = "webhookey" -version = "0.1.3" +version = "0.1.5" dependencies = [ "anyhow", "clap", @@ -1943,7 +1926,6 @@ dependencies = [ "hmac", "ipnet", "log", - "nom", "regex", "rocket", "run_script", diff --git a/Cargo.toml b/Cargo.toml index 0b63cad..d49ab4e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "webhookey" -version = "0.1.4" +version = "0.1.5" authors = ["finga "] edition = "2021" license = "GPL-3.0-or-later" @@ -20,7 +20,6 @@ dirs = "4.0" anyhow = "1.0" log = "0.4" env_logger = "0.9" -nom = "7" hmac = "0.11" sha2 = "0.9" hex = "0.4" diff --git a/src/main.rs b/src/main.rs index d0e7eb8..7b161c4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,14 +2,6 @@ use anyhow::{anyhow, bail, Result}; use clap::Parser; use hmac::{Hmac, Mac, NewMac}; use log::{debug, error, info, trace, warn}; -use nom::{ - branch::alt, - bytes::complete::{tag, take_until}, - combinator::map_res, - multi::many0, - sequence::delimited, - Finish, IResult, -}; use rocket::{ data::{FromData, ToByteUnit}, futures::TryFutureExt, @@ -84,32 +76,71 @@ impl Hook { request: &Request, data: &mut serde_json::Value, ) -> Result { - trace!("Replacing parameters for command of hook `{}`", hook_name); + debug!("Replacing parameters for command of hook `{}`", hook_name); - for parameter in self.get_parameter()? { - let parameter = parameter.trim(); + Hook::replace_parameters(&self.command, request.headers(), data) + } - if let Some(json_value) = data.pointer(parameter) { - *data.pointer_mut(parameter).ok_or_else(|| { - WebhookeyError::InvalidParameterPointer(parameter.to_string()) - })? = serde_json::Value::String(webhooks::get_string(json_value)?); + fn replace_parameters( + input: &str, + headers: &HeaderMap, + data: &serde_json::Value, + ) -> Result { + let mut command = String::new(); + let command_template = &mut input.chars(); + + while let Some(i) = command_template.next() { + if i == '{' { + if let Some('{') = command_template.next() { + let mut token = String::new(); + + while let Some(i) = command_template.next() { + if i == '}' { + if let Some('}') = command_template.next() { + let expr = token.trim().split(' ').collect::>(); + + let replaced = match expr.get(0) { + Some(&"header") => get_header_field( + headers, + expr.get(1).ok_or_else(|| { + anyhow!("Missing parameter for `header` expression") + })?, + )? + .to_string(), + Some(pointer) => webhooks::get_string( + data.pointer(pointer).ok_or_else(|| { + anyhow!( + "Could not find field refered to in parameter `{}`", + pointer + ) + })?, + )?, + None => bail!("Missing expression in variable `{}`", token), + }; + + command.push_str(&replaced); + + trace!("Replace `{}` with: {}", token, replaced); + + break; + } else { + command.push('}'); + command.push(i); + } + } else { + token.push(i); + } + } + } else { + command.push('{'); + command.push(i); + } + } else { + command.push(i); } } - replace_parameters(&self.command, request.headers(), data) - } - - fn get_parameter(&self) -> Result> { - let parse: IResult<&str, Vec<&str>> = many0(alt(( - delimited(tag("{{"), take_until("}}"), tag("}}")), - take_until("{{"), - )))(&self.command); - - let (_last, result) = parse - .finish() - .map_err(|e| anyhow!("Could not get parameters from command: {}", e))?; - - Ok(result) + Ok(command) } } @@ -214,55 +245,12 @@ fn validate_request(secret: &str, signature: &str, data: &[u8]) -> Result<()> { mac.verify(&raw_signature).map_err(|e| anyhow!("{}", e)) } -fn get_header_field<'a>(headers: &'a HeaderMap, param: &[&str]) -> Result<&'a str> { +fn get_header_field<'a>(headers: &'a HeaderMap, param: &str) -> Result<&'a str> { headers - .get_one( - param - .get(1) - .ok_or_else(|| anyhow!("Missing parameter for `header` expression"))?, - ) + .get_one(param) .ok_or_else(|| anyhow!("Could not extract event parameter from header")) } -fn get_value_from_pointer<'a>(data: &'a serde_json::Value, pointer: &'a str) -> Result<&'a str> { - let value = data - .pointer(pointer) - .ok_or_else(|| anyhow!("Could not get field from pointer {}", pointer))?; - - value - .as_str() - .ok_or_else(|| anyhow!("Could not convert value `{}` to string", value)) -} - -fn replace_parameters( - input: &str, - headers: &HeaderMap, - data: &serde_json::Value, -) -> Result { - let parse: IResult<&str, Vec<&str>> = many0(alt(( - map_res( - delimited(tag("{{"), take_until("}}"), tag("}}")), - |param: &str| { - let expr = param.trim().split(' ').collect::>(); - - match expr.get(0) { - Some(&"header") => get_header_field(headers, &expr), - Some(pointer) => get_value_from_pointer(data, pointer), - None => bail!("Missing expression in `{}`", input), - } - }, - ), - take_until("{{"), - )))(input); - - let (last, mut result) = parse - .finish() - .map_err(|e| anyhow!("Could not parse command: {}", e))?; - result.push(last); - - Ok(result.join("")) -} - fn get_config() -> Result { // Look for config in CWD.. if let Ok(config) = File::open("config.yml") { @@ -583,37 +571,40 @@ mod tests { headers.add_raw("X-Gitea-Event", "something"); assert_eq!( - replace_parameters("command", &headers, &serde_json::Value::Null).unwrap(), + Hook::replace_parameters("command", &headers, &serde_json::Value::Null).unwrap(), "command" ); assert_eq!( - replace_parameters(" command", &headers, &serde_json::Value::Null).unwrap(), + Hook::replace_parameters(" command", &headers, &serde_json::Value::Null).unwrap(), " command" ); assert_eq!( - replace_parameters("command ", &headers, &serde_json::Value::Null).unwrap(), + Hook::replace_parameters("command ", &headers, &serde_json::Value::Null).unwrap(), "command " ); assert_eq!( - replace_parameters(" command ", &headers, &serde_json::Value::Null).unwrap(), + Hook::replace_parameters(" command ", &headers, &serde_json::Value::Null) + .unwrap(), " command " ); assert_eq!( - replace_parameters("command command ", &headers, &serde_json::Value::Null).unwrap(), + Hook::replace_parameters("command command ", &headers, &serde_json::Value::Null) + .unwrap(), "command command " ); assert_eq!( - replace_parameters("{{ /foo }} command", &headers, &json!({ "foo": "bar" })).unwrap(), + Hook::replace_parameters("{{ /foo }} command", &headers, &json!({ "foo": "bar" })) + .unwrap(), "bar command" ); assert_eq!( - replace_parameters( + Hook::replace_parameters( " command {{ /foo }} ", &headers, &json!({ "foo": "bar" }) @@ -623,7 +614,7 @@ mod tests { ); assert_eq!( - replace_parameters( + Hook::replace_parameters( "{{ /foo }} command{{/field1/foo}}", &headers, &json!({ "foo": "bar", "field1": { "foo": "baz" } }) @@ -633,7 +624,7 @@ mod tests { ); assert_eq!( - replace_parameters( + Hook::replace_parameters( " command {{ /foo }} ", &headers, &json!({ "foo": "bar" }) @@ -643,7 +634,7 @@ mod tests { ); assert_eq!( - replace_parameters( + Hook::replace_parameters( " {{ /field1/foo }} command", &headers, &json!({ "field1": { "foo": "bar" } }) @@ -653,7 +644,7 @@ mod tests { ); assert_eq!( - replace_parameters( + Hook::replace_parameters( " {{ header X-Gitea-Event }} command", &headers, &json!({ "field1": { "foo": "bar" } }) @@ -663,7 +654,7 @@ mod tests { ); assert_eq!( - replace_parameters( + Hook::replace_parameters( " {{ header X-Gitea-Event }} {{ /field1/foo }} command", &headers, &json!({ "field1": { "foo": "bar" } }) @@ -671,6 +662,16 @@ mod tests { .unwrap(), " something bar command" ); + + assert_eq!( + Hook::replace_parameters( + " {{ header X-Gitea-Event }} {{ /field1/foo }} {{ /field1/bar }} {{ /field2/foo }} --command{{ /cmd }}", + &headers, + &json!({ "field1": { "foo": "bar", "bar": "baz" }, "field2": { "foo": "qux" }, "cmd": " else"}) + ) + .unwrap(), + " something bar baz qux --command else" + ); } #[rocket::async_test] diff --git a/src/webhooks.rs b/src/webhooks.rs index 85a52d1..efd9fb6 100644 --- a/src/webhooks.rs +++ b/src/webhooks.rs @@ -14,8 +14,6 @@ pub enum WebhookeyError { Unauthorized(IpAddr), #[error("Unmatched hook from `{0}`")] UnmatchedHook(IpAddr), - #[error("Could not find field refered to in parameter `{0}`")] - InvalidParameterPointer(String), #[error("Could not evaluate filter request")] InvalidFilter, #[error("IO Error")] From 9c423b8dc830de8014cb36caec1908c5951f9a80 Mon Sep 17 00:00:00 2001 From: finga Date: Wed, 17 Nov 2021 14:06:07 +0100 Subject: [PATCH 34/65] Add `Not` filter to `FilterType` To invert the result of filters. --- src/main.rs | 19 +++++++++++++++++-- src/webhooks.rs | 2 ++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/main.rs b/src/main.rs index 7b161c4..fbb8d9a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -679,7 +679,7 @@ mod tests { let mut hooks = BTreeMap::new(); hooks.insert( - "test_hook".to_string(), + "test_hook0".to_string(), Hook { command: "/usr/bin/echo {{ /repository/full_name }} --foo {{ /pull_request/base/ref }}" @@ -695,7 +695,7 @@ mod tests { ); hooks.insert( - "test_hook".to_string(), + "test_hook2".to_string(), Hook { command: "/usr/bin/echo {{ /repository/full_name }} {{ /pull_request/base/ref }}" .to_string(), @@ -709,6 +709,21 @@ mod tests { }, ); + hooks.insert( + "test_hook3".to_string(), + Hook { + command: "/usr/bin/echo {{ /repository/full_name }} {{ /pull_request/base/ref }}" + .to_string(), + signature: "X-Gitea-Signature".to_string(), + ip_filter: None, + secrets: vec!["valid".to_string()], + filter: FilterType::Not(Box::new(FilterType::JsonFilter(JsonFilter { + pointer: "/foobar".to_string(), + regex: "bar".to_string(), + }))), + }, + ); + let config = Config { metrics: None, hooks: hooks, diff --git a/src/webhooks.rs b/src/webhooks.rs index efd9fb6..0c4ee15 100644 --- a/src/webhooks.rs +++ b/src/webhooks.rs @@ -93,6 +93,7 @@ impl JsonFilter { #[derive(Debug, Deserialize, Serialize)] #[serde(deny_unknown_fields, rename_all = "lowercase")] pub enum FilterType { + Not(Box), And(Vec), Or(Vec), #[serde(rename = "json")] @@ -102,6 +103,7 @@ pub enum FilterType { impl FilterType { pub fn evaluate(&self, data: &serde_json::Value) -> Result { match self { + FilterType::Not(filter) => Ok(!filter.evaluate(data)?), FilterType::And(filters) => { let (mut results, mut errors) = (Vec::new(), Vec::new()); From 0d9c5f650f54388e4a6657a8391ed85999e5cb78 Mon Sep 17 00:00:00 2001 From: finga Date: Wed, 17 Nov 2021 14:07:39 +0100 Subject: [PATCH 35/65] Update build dependencies --- Cargo.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e7c10da..9e118a9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -582,9 +582,9 @@ checksum = "acd94fdbe1d4ff688b67b04eee2e17bd50995534a61539e45adfefb45e5e5503" [[package]] name = "httpdate" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6456b8a6c8f33fee7d958fcd1b60d55b11940a79e63ae87013e6d22e26034440" +checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" [[package]] name = "humantime" @@ -594,9 +594,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.14" +version = "0.14.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b91bb1f221b6ea1f1e4371216b70f40748774c2fb5971b450c07773fb92d26b" +checksum = "436ec0091e4f20e655156a30a0df3770fe2900aa301e548e08446ec794b6953c" dependencies = [ "bytes", "futures-channel", @@ -1584,9 +1584,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.13.0" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "588b2d10a336da58d877567cd8fb8a14b463e2104910f8132cd054b4b96e29ee" +checksum = "70e992e41e0d2fb9f755b37446f20900f64446ef54874f40a60c78f021ac6144" dependencies = [ "autocfg", "bytes", @@ -1603,9 +1603,9 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "1.5.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "114383b041aa6212c579467afa0075fbbdd0718de036100bc0ba7961d8cb9095" +checksum = "c9efc1aba077437943f7515666aa2b882dfabfbfdf89c819ea75a8d6e9eaba5e" dependencies = [ "proc-macro2", "quote", From 8c9d9e63f20edd543c1db5ee75ae59e05e49afff Mon Sep 17 00:00:00 2001 From: finga Date: Wed, 17 Nov 2021 15:13:12 +0100 Subject: [PATCH 36/65] Add `HeaderFilter` for filter based on the header This extends filtering to filter also on the received http header. --- src/main.rs | 12 ++++++------ src/webhooks.rs | 52 +++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 52 insertions(+), 12 deletions(-) diff --git a/src/main.rs b/src/main.rs index fbb8d9a..4cd5658 100644 --- a/src/main.rs +++ b/src/main.rs @@ -199,7 +199,7 @@ impl Hooks { let mut data: serde_json::Value = serde_json::from_slice(&buffer).map_err(WebhookeyError::Serde)?; - match hook.filter.evaluate(&data) { + match hook.filter.evaluate(request, &data) { Ok(true) => match hook.get_command(hook_name, request, &mut data) { Ok(command) => { info!("Filter for `{}` matched", &hook_name); @@ -483,7 +483,7 @@ async fn main() -> Result<()> { #[cfg(test)] mod tests { use super::*; - use crate::webhooks::{AddrType, JsonFilter}; + use crate::webhooks::{AddrType, HeaderFilter, JsonFilter}; use rocket::{ http::{ContentType, Header}, local::asynchronous::Client, @@ -850,8 +850,8 @@ hooks: - json: pointer: /ref regex: refs/heads/master - - json: - pointer: /after + - header: + field: X-Gitea-Signature regex: f6e5fe4fe37df76629112d55cc210718b6a55e7e"#, ) .unwrap(); @@ -889,8 +889,8 @@ hooks: pointer: "/ref".to_string(), regex: "refs/heads/master".to_string(), }), - FilterType::JsonFilter(JsonFilter { - pointer: "/after".to_string(), + FilterType::HeaderFilter(HeaderFilter { + field: "X-Gitea-Signature".to_string(), regex: "f6e5fe4fe37df76629112d55cc210718b6a55e7e".to_string(), }), ]), diff --git a/src/webhooks.rs b/src/webhooks.rs index 0c4ee15..9bef844 100644 --- a/src/webhooks.rs +++ b/src/webhooks.rs @@ -2,6 +2,7 @@ use anyhow::Result; use ipnet::IpNet; use log::{debug, error, trace}; use regex::Regex; +use rocket::{http::HeaderMap, Request}; use serde::{Deserialize, Serialize}; use std::net::IpAddr; use thiserror::Error; @@ -56,6 +57,39 @@ impl IpFilter { } } +#[derive(Debug, Deserialize, Serialize)] +pub struct HeaderFilter { + pub field: String, + pub regex: String, +} + +impl HeaderFilter { + pub fn evaluate(&self, headers: &HeaderMap) -> Result { + trace!( + "Matching `{}` on `{}` from received header", + &self.regex, + &self.field, + ); + + let regex = Regex::new(&self.regex).map_err(WebhookeyError::Regex)?; + + if let Some(value) = headers.get_one(&self.field) { + if regex.is_match(value) { + debug!("Regex `{}` for `{}` matches", &self.regex, &self.field); + + return Ok(true); + } + } + + debug!( + "Regex `{}` for header field `{}` does not match", + &self.regex, &self.field + ); + + Ok(false) + } +} + #[derive(Debug, Deserialize, Serialize)] #[serde(deny_unknown_fields)] pub struct JsonFilter { @@ -82,7 +116,7 @@ impl JsonFilter { } debug!( - "Regex `{}` for `{}` does not match", + "Regex `{}` for json field `{}` does not match", &self.regex, &self.pointer ); @@ -96,20 +130,26 @@ pub enum FilterType { Not(Box), And(Vec), Or(Vec), + #[serde(rename = "header")] + HeaderFilter(HeaderFilter), #[serde(rename = "json")] JsonFilter(JsonFilter), } impl FilterType { - pub fn evaluate(&self, data: &serde_json::Value) -> Result { + pub fn evaluate( + &self, + request: &Request, + data: &serde_json::Value, + ) -> Result { match self { - FilterType::Not(filter) => Ok(!filter.evaluate(data)?), + FilterType::Not(filter) => Ok(!filter.evaluate(request, data)?), FilterType::And(filters) => { let (mut results, mut errors) = (Vec::new(), Vec::new()); filters .iter() - .map(|filter| filter.evaluate(data)) + .map(|filter| filter.evaluate(request, data)) .for_each(|item| match item { Ok(o) => results.push(o), Err(e) => errors.push(e), @@ -130,7 +170,7 @@ impl FilterType { filters .iter() - .map(|filter| filter.evaluate(data)) + .map(|filter| filter.evaluate(request, data)) .for_each(|item| match item { Ok(o) => results.push(o), Err(e) => errors.push(e), @@ -146,7 +186,7 @@ impl FilterType { Err(WebhookeyError::InvalidFilter) } } - // FilterType::HeaderFilter(filter) => todo!(), + FilterType::HeaderFilter(filter) => filter.evaluate(request.headers()), FilterType::JsonFilter(filter) => filter.evaluate(data), } } From 181edf589cd8d09bac776f3751d2d640295955b5 Mon Sep 17 00:00:00 2001 From: finga Date: Wed, 17 Nov 2021 15:19:38 +0100 Subject: [PATCH 37/65] Update readme with filters `not` and `header` --- README.md | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 9990ed7..5689753 100644 --- a/README.md +++ b/README.md @@ -98,16 +98,17 @@ hooks: - secret_key_02 filter: or: - - json: - pointer: /ref - regex: refs/heads/master + - not: + json: + pointer: /ref + regex: refs/heads/dev - and: - json: pointer: /ref regex: refs/heads/a_branch - - json: - pointer: /after - regex: f6e5fe4fe37df76629112d55cc210718b6a55e7e + - header: + field: X-Gitea-Event + regex: push ``` ##### Command @@ -163,10 +164,20 @@ hook should be executed. ###### Conjunction Filters Conjunction filters contain lists of other filters. +- `not`: Logical negation. - `and`: Logical conjunction. - `or`: Logical disjunction. ###### Concrete Filters +- `header`: + + The `header` filter matches a regular expression on a field from the + received http(s) request header. + + - `field`: The header field which should be matched. + - `regeq`: Regular expression which has to match the specified + header field. + - `json`: The `json` filter matches a regular expression on a field from the From 83785cc77d9d2052d9641eaac1d4e85b7fd70f39 Mon Sep 17 00:00:00 2001 From: finga Date: Thu, 18 Nov 2021 00:16:09 +0100 Subject: [PATCH 38/65] Add comments to metrics To improve readability. --- src/main.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main.rs b/src/main.rs index 4cd5658..21f912e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -434,9 +434,13 @@ async fn metrics( metrics: &State, config: &State, ) -> Option { + // Are metrics configured? if let Some(metrics_config) = &config.metrics { + // Are metrics enabled? if metrics_config.enabled { + // Is a filter configured? if let Some(filter) = &metrics_config.ip_filter { + // Does the request match the filter? if filter.validate(&address.ip()) { return Some(get_metrics(metrics)); } From b8f114900bb92f13d20d08a4b4297d275130627d Mon Sep 17 00:00:00 2001 From: finga Date: Thu, 18 Nov 2021 17:47:13 +0100 Subject: [PATCH 39/65] Compile regex when parsing config The regexes are now compiled when the config is parsed and not each time a new webhook is received. Adapt tests to using parsed regex. --- Cargo.lock | 11 +++++++++++ Cargo.toml | 1 + src/main.rs | 20 +++++++++++--------- src/webhooks.rs | 16 ++++++---------- 4 files changed, 29 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9e118a9..9c1a7a8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1301,6 +1301,16 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_regex" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8136f1a4ea815d7eac4101cfd0b16dc0cb5e1fe1b8609dfd728058656b7badf" +dependencies = [ + "regex", + "serde", +] + [[package]] name = "serde_yaml" version = "0.8.21" @@ -1931,6 +1941,7 @@ dependencies = [ "run_script", "serde", "serde_json", + "serde_regex", "serde_yaml", "sha2", "thiserror", diff --git a/Cargo.toml b/Cargo.toml index d49ab4e..db4a136 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ rocket = "0.5.0-rc.1" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" serde_yaml = "0.8" +serde_regex = "1.1" regex = "1.5" dirs = "4.0" anyhow = "1.0" diff --git a/src/main.rs b/src/main.rs index 21f912e..2b7147b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -488,6 +488,7 @@ async fn main() -> Result<()> { mod tests { use super::*; use crate::webhooks::{AddrType, HeaderFilter, JsonFilter}; + use regex::Regex; use rocket::{ http::{ContentType, Header}, local::asynchronous::Client, @@ -507,7 +508,7 @@ mod tests { secrets: vec!["valid".to_string()], filter: FilterType::JsonFilter(JsonFilter { pointer: "*".to_string(), - regex: "*".to_string(), + regex: Regex::new(".*").unwrap(), }), }, ); @@ -693,7 +694,7 @@ mod tests { secrets: vec!["valid".to_string()], filter: FilterType::JsonFilter(JsonFilter { pointer: "/foo".to_string(), - regex: "bar".to_string(), + regex: Regex::new("bar").unwrap(), }), }, ); @@ -708,7 +709,7 @@ mod tests { secrets: vec!["valid".to_string()], filter: FilterType::JsonFilter(JsonFilter { pointer: "/foo".to_string(), - regex: "bar".to_string(), + regex: Regex::new("bar").unwrap(), }), }, ); @@ -723,7 +724,7 @@ mod tests { secrets: vec!["valid".to_string()], filter: FilterType::Not(Box::new(FilterType::JsonFilter(JsonFilter { pointer: "/foobar".to_string(), - regex: "bar".to_string(), + regex: Regex::new("bar").unwrap(), }))), }, ); @@ -781,7 +782,7 @@ mod tests { secrets: vec!["valid".to_string()], filter: FilterType::JsonFilter(JsonFilter { pointer: "/foo".to_string(), - regex: "bar".to_string(), + regex: Regex::new("bar").unwrap(), }), }, ); @@ -877,7 +878,7 @@ hooks: secrets: vec!["secret_key_01".to_string(), "secret_key_02".to_string()], filter: FilterType::JsonFilter(JsonFilter { pointer: "/ref".to_string(), - regex: "refs/heads/master".to_string(), + regex: Regex::new("refs/heads/master").unwrap(), }), } ), @@ -891,11 +892,12 @@ hooks: filter: FilterType::And(vec![ FilterType::JsonFilter(JsonFilter { pointer: "/ref".to_string(), - regex: "refs/heads/master".to_string(), + regex: Regex::new("refs/heads/master").unwrap(), }), FilterType::HeaderFilter(HeaderFilter { field: "X-Gitea-Signature".to_string(), - regex: "f6e5fe4fe37df76629112d55cc210718b6a55e7e".to_string(), + regex: Regex::new("f6e5fe4fe37df76629112d55cc210718b6a55e7e") + .unwrap(), }), ]), } @@ -945,7 +947,7 @@ hooks: secrets: vec!["secret_key_01".to_string(), "secret_key_02".to_string()], filter: FilterType::JsonFilter(JsonFilter { pointer: "/ref".to_string(), - regex: "refs/heads/master".to_string(), + regex: Regex::new("refs/heads/master").unwrap(), }), } ),]) diff --git a/src/webhooks.rs b/src/webhooks.rs index 9bef844..625af56 100644 --- a/src/webhooks.rs +++ b/src/webhooks.rs @@ -21,8 +21,6 @@ pub enum WebhookeyError { Io(std::io::Error), #[error("Serde Error")] Serde(serde_json::Error), - #[error("Regex Error")] - Regex(regex::Error), } #[derive(Debug, Deserialize, Serialize)] @@ -60,7 +58,8 @@ impl IpFilter { #[derive(Debug, Deserialize, Serialize)] pub struct HeaderFilter { pub field: String, - pub regex: String, + #[serde(with = "serde_regex")] + pub regex: Regex, } impl HeaderFilter { @@ -71,10 +70,8 @@ impl HeaderFilter { &self.field, ); - let regex = Regex::new(&self.regex).map_err(WebhookeyError::Regex)?; - if let Some(value) = headers.get_one(&self.field) { - if regex.is_match(value) { + if self.regex.is_match(value) { debug!("Regex `{}` for `{}` matches", &self.regex, &self.field); return Ok(true); @@ -94,7 +91,8 @@ impl HeaderFilter { #[serde(deny_unknown_fields)] pub struct JsonFilter { pub pointer: String, - pub regex: String, + #[serde(with = "serde_regex")] + pub regex: Regex, } impl JsonFilter { @@ -105,10 +103,8 @@ impl JsonFilter { &self.pointer, ); - let regex = Regex::new(&self.regex).map_err(WebhookeyError::Regex)?; - if let Some(value) = data.pointer(&self.pointer) { - if regex.is_match(&get_string(value)?) { + if self.regex.is_match(&get_string(value)?) { debug!("Regex `{}` for `{}` matches", &self.regex, &self.pointer); return Ok(true); From b7ad590d39403e767872ffd1b2c8c05cd5cc1b27 Mon Sep 17 00:00:00 2001 From: finga Date: Fri, 19 Nov 2021 11:04:11 +0100 Subject: [PATCH 40/65] Create interrelate macro to evaluate filters This reduces code duplication. --- src/webhooks.rs | 68 +++++++++++++++++++------------------------------ 1 file changed, 26 insertions(+), 42 deletions(-) diff --git a/src/webhooks.rs b/src/webhooks.rs index 625af56..4029d38 100644 --- a/src/webhooks.rs +++ b/src/webhooks.rs @@ -120,6 +120,30 @@ impl JsonFilter { } } +macro_rules! interrelate { + ($request:expr, $data:expr, $filters:expr, $relation:ident) => {{ + let (mut results, mut errors) = (Vec::new(), Vec::new()); + + $filters + .iter() + .map(|filter| filter.evaluate($request, $data)) + .for_each(|item| match item { + Ok(o) => results.push(o), + Err(e) => errors.push(e), + }); + + if errors.is_empty() { + Ok(results.iter().$relation(|r| *r)) + } else { + errors + .iter() + .for_each(|e| error!("Could not evaluate Filter: {}", e)); + + Err(WebhookeyError::InvalidFilter) + } + }}; +} + #[derive(Debug, Deserialize, Serialize)] #[serde(deny_unknown_fields, rename_all = "lowercase")] pub enum FilterType { @@ -140,48 +164,8 @@ impl FilterType { ) -> Result { match self { FilterType::Not(filter) => Ok(!filter.evaluate(request, data)?), - FilterType::And(filters) => { - let (mut results, mut errors) = (Vec::new(), Vec::new()); - - filters - .iter() - .map(|filter| filter.evaluate(request, data)) - .for_each(|item| match item { - Ok(o) => results.push(o), - Err(e) => errors.push(e), - }); - - if errors.is_empty() { - Ok(results.iter().all(|r| *r)) - } else { - errors - .iter() - .for_each(|e| error!("Could not evaluate Filter: {}", e)); - - Err(WebhookeyError::InvalidFilter) - } - } - FilterType::Or(filters) => { - let (mut results, mut errors) = (Vec::new(), Vec::new()); - - filters - .iter() - .map(|filter| filter.evaluate(request, data)) - .for_each(|item| match item { - Ok(o) => results.push(o), - Err(e) => errors.push(e), - }); - - if errors.is_empty() { - Ok(results.iter().any(|r| *r)) - } else { - errors - .iter() - .for_each(|e| error!("Could not evaluate Filter: {}", e)); - - Err(WebhookeyError::InvalidFilter) - } - } + FilterType::And(filters) => interrelate!(request, data, filters, all), + FilterType::Or(filters) => interrelate!(request, data, filters, any), FilterType::HeaderFilter(filter) => filter.evaluate(request.headers()), FilterType::JsonFilter(filter) => filter.evaluate(data), } From 3a95ecfd11880c6d58ab1876003dfd6b0d9e0dea Mon Sep 17 00:00:00 2001 From: finga Date: Fri, 19 Nov 2021 11:28:37 +0100 Subject: [PATCH 41/65] Rename `webook.rs` to `filter.rs` Also improve code separation, still more to come. --- src/{webhooks.rs => filters.rs} | 32 ++------------------ src/main.rs | 53 +++++++++++++++++++++++++-------- 2 files changed, 42 insertions(+), 43 deletions(-) rename src/{webhooks.rs => filters.rs} (81%) diff --git a/src/webhooks.rs b/src/filters.rs similarity index 81% rename from src/webhooks.rs rename to src/filters.rs index 4029d38..dc74864 100644 --- a/src/webhooks.rs +++ b/src/filters.rs @@ -1,3 +1,4 @@ +use crate::WebhookeyError; use anyhow::Result; use ipnet::IpNet; use log::{debug, error, trace}; @@ -5,23 +6,6 @@ use regex::Regex; use rocket::{http::HeaderMap, Request}; use serde::{Deserialize, Serialize}; use std::net::IpAddr; -use thiserror::Error; - -#[derive(Debug, Error)] -pub enum WebhookeyError { - #[error("Could not extract signature from header")] - InvalidSignature, - #[error("Unauthorized request from `{0}`")] - Unauthorized(IpAddr), - #[error("Unmatched hook from `{0}`")] - UnmatchedHook(IpAddr), - #[error("Could not evaluate filter request")] - InvalidFilter, - #[error("IO Error")] - Io(std::io::Error), - #[error("Serde Error")] - Serde(serde_json::Error), -} #[derive(Debug, Deserialize, Serialize)] #[serde(deny_unknown_fields, untagged)] @@ -104,7 +88,7 @@ impl JsonFilter { ); if let Some(value) = data.pointer(&self.pointer) { - if self.regex.is_match(&get_string(value)?) { + if self.regex.is_match(&crate::get_string(value)?) { debug!("Regex `{}` for `{}` matches", &self.regex, &self.pointer); return Ok(true); @@ -171,15 +155,3 @@ impl FilterType { } } } - -pub fn get_string(data: &serde_json::Value) -> Result { - match &data { - serde_json::Value::Bool(bool) => Ok(bool.to_string()), - serde_json::Value::Number(number) => Ok(number.to_string()), - serde_json::Value::String(string) => Ok(string.as_str().to_string()), - x => { - error!("Could not get string from: {:?}", x); - unimplemented!() - } - } -} diff --git a/src/main.rs b/src/main.rs index 2b7147b..a187849 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,10 @@ +mod cli; +mod filters; + +use crate::{ + cli::Opts, + filters::{FilterType, IpFilter}, +}; use anyhow::{anyhow, bail, Result}; use clap::Parser; use hmac::{Hmac, Mac, NewMac}; @@ -15,7 +22,6 @@ use rocket::{ use run_script::ScriptOptions; use serde::{Deserialize, Serialize}; use sha2::Sha256; - use std::{ collections::BTreeMap, fs::File, @@ -23,14 +29,23 @@ use std::{ net::{IpAddr, Ipv4Addr, SocketAddr}, sync::atomic::{AtomicUsize, Ordering}, }; +use thiserror::Error; -mod cli; -mod webhooks; - -use crate::{ - cli::Opts, - webhooks::{FilterType, IpFilter, WebhookeyError}, -}; +#[derive(Debug, Error)] +pub enum WebhookeyError { + #[error("Could not extract signature from header")] + InvalidSignature, + #[error("Unauthorized request from `{0}`")] + Unauthorized(IpAddr), + #[error("Unmatched hook from `{0}`")] + UnmatchedHook(IpAddr), + #[error("Could not evaluate filter request")] + InvalidFilter, + #[error("IO Error")] + Io(std::io::Error), + #[error("Serde Error")] + Serde(serde_json::Error), +} #[derive(Debug, Default)] struct WebhookeyMetrics { @@ -107,14 +122,14 @@ impl Hook { })?, )? .to_string(), - Some(pointer) => webhooks::get_string( - data.pointer(pointer).ok_or_else(|| { + Some(pointer) => { + get_string(data.pointer(pointer).ok_or_else(|| { anyhow!( "Could not find field refered to in parameter `{}`", pointer ) - })?, - )?, + })?)? + } None => bail!("Missing expression in variable `{}`", token), }; @@ -251,6 +266,18 @@ fn get_header_field<'a>(headers: &'a HeaderMap, param: &str) -> Result<&'a str> .ok_or_else(|| anyhow!("Could not extract event parameter from header")) } +pub fn get_string(data: &serde_json::Value) -> Result { + match &data { + serde_json::Value::Bool(bool) => Ok(bool.to_string()), + serde_json::Value::Number(number) => Ok(number.to_string()), + serde_json::Value::String(string) => Ok(string.as_str().to_string()), + x => { + error!("Could not get string from: {:?}", x); + unimplemented!() + } + } +} + fn get_config() -> Result { // Look for config in CWD.. if let Ok(config) = File::open("config.yml") { @@ -487,7 +514,7 @@ async fn main() -> Result<()> { #[cfg(test)] mod tests { use super::*; - use crate::webhooks::{AddrType, HeaderFilter, JsonFilter}; + use filters::{AddrType, HeaderFilter, JsonFilter}; use regex::Regex; use rocket::{ http::{ContentType, Header}, From 5e1d433c38b7dad36116586f0affe17b5fbefdfd Mon Sep 17 00:00:00 2001 From: finga Date: Fri, 19 Nov 2021 11:40:21 +0100 Subject: [PATCH 42/65] Move metrics related code into `metrics.rs` To improve readability metrics related code moves to `metrics.rs`. --- src/main.rs | 113 ++++++------------------------------------------- src/metrics.rs | 91 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 105 insertions(+), 99 deletions(-) create mode 100644 src/metrics.rs diff --git a/src/main.rs b/src/main.rs index a187849..a7850e3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,9 +1,11 @@ mod cli; mod filters; +mod metrics; use crate::{ cli::Opts, filters::{FilterType, IpFilter}, + metrics::Metrics, }; use anyhow::{anyhow, bail, Result}; use clap::Parser; @@ -12,7 +14,6 @@ use log::{debug, error, info, trace, warn}; use rocket::{ data::{FromData, ToByteUnit}, futures::TryFutureExt, - get, http::{HeaderMap, Status}, outcome::Outcome::{self, Failure, Success}, post, routes, @@ -27,7 +28,7 @@ use std::{ fs::File, io::BufReader, net::{IpAddr, Ipv4Addr, SocketAddr}, - sync::atomic::{AtomicUsize, Ordering}, + sync::atomic::Ordering, }; use thiserror::Error; @@ -47,19 +48,6 @@ pub enum WebhookeyError { Serde(serde_json::Error), } -#[derive(Debug, Default)] -struct WebhookeyMetrics { - requests_received: AtomicUsize, - requests_invalid: AtomicUsize, - hooks_successful: AtomicUsize, - hooks_forbidden: AtomicUsize, - hooks_unmatched: AtomicUsize, - commands_executed: AtomicUsize, - commands_execution_failed: AtomicUsize, - commands_successful: AtomicUsize, - commands_failed: AtomicUsize, -} - #[derive(Debug, Deserialize, Serialize)] #[serde(deny_unknown_fields)] struct MetricsConfig { @@ -69,7 +57,7 @@ struct MetricsConfig { #[derive(Debug, Deserialize, Serialize)] #[serde(deny_unknown_fields)] -struct Config { +pub struct Config { metrics: Option, hooks: BTreeMap, } @@ -311,48 +299,6 @@ fn get_config() -> Result { bail!("No configuration file found."); } -fn get_metrics(metrics: &WebhookeyMetrics) -> String { - format!( - r"# HELP webhookey_requests_received Number of requests received -# TYPE webhookey_requests_received gauge -webhookey_requests_received {} -# HELP webhookey_requests_invalid Number of invalid requests received -# TYPE webhookey_requests_invalid gauge -webhookey_requests_invalid {} -# HELP webhookey_hooks_successful Number of successfully executed hooks -# TYPE webhookey_hooks_successful gauge -webhookey_hooks_sucessful {} -# HELP webhookey_hooks_forbidden Number of forbidden requests -# TYPE webhookey_hooks_forbidden gauge -webhookey_hooks_forbidden {} -# HELP webhookey_hooks_unmatched Number of unmatched requests -# TYPE webhookey_hooks_unmatched gauge -webhookey_hooks_unmatched {} -# HELP webhookey_commands_executed Number of commands executed -# TYPE webhookey_commands_executed gauge -webhookey_commands_executed {} -# HELP webhookey_commands_execution_failed Number of commands failed to execute -# TYPE webhookey_commands_execution_failed gauge -webhookey_commands_execution_failed {} -# HELP webhookey_commands_successful Number of executed commands returning return code 0 -# TYPE webhookey_commands_successful gauge -webhookey_commands_successful {} -# HELP webhookey_commands_failed Number of executed commands returning different return code than 0 -# TYPE webhookey_commands_failed gauge -webhookey_commands_failed {} -", - metrics.requests_received.load(Ordering::Relaxed), - metrics.requests_invalid.load(Ordering::Relaxed), - metrics.hooks_successful.load(Ordering::Relaxed), - metrics.hooks_forbidden.load(Ordering::Relaxed), - metrics.hooks_unmatched.load(Ordering::Relaxed), - metrics.commands_executed.load(Ordering::Relaxed), - metrics.commands_execution_failed.load(Ordering::Relaxed), - metrics.commands_successful.load(Ordering::Relaxed), - metrics.commands_failed.load(Ordering::Relaxed), - ) -} - #[rocket::async_trait] impl<'r> FromData<'r> for Hooks { type Error = WebhookeyError; @@ -363,7 +309,7 @@ impl<'r> FromData<'r> for Hooks { ) -> Outcome> { { request - .guard::<&State>() + .guard::<&State>() .await .unwrap() // TODO: Check if unwrap need to be fixed .requests_received @@ -378,7 +324,7 @@ impl<'r> FromData<'r> for Hooks { .unwrap_or(IpAddr::V4(Ipv4Addr::UNSPECIFIED)); request - .guard::<&State>() + .guard::<&State>() .await .unwrap() // TODO: Check if unwrap need to be fixed .hooks_unmatched @@ -394,7 +340,7 @@ impl<'r> FromData<'r> for Hooks { error!("{}", WebhookeyError::Unauthorized(e)); request - .guard::<&State>() + .guard::<&State>() .await .unwrap() // TODO: Check if unwrap need to be fixed .hooks_forbidden @@ -406,7 +352,7 @@ impl<'r> FromData<'r> for Hooks { error!("{}", e); request - .guard::<&State>() + .guard::<&State>() .await .unwrap() // TODO: Check if unwrap need to be fixed .requests_invalid @@ -419,11 +365,7 @@ impl<'r> FromData<'r> for Hooks { } #[post("/", format = "json", data = "")] -async fn receive_hook<'a>( - address: SocketAddr, - hooks: Hooks, - metrics: &State, -) -> Status { +async fn receive_hook<'a>(address: SocketAddr, hooks: Hooks, metrics: &State) -> Status { info!("Post request received from: {}", address); hooks.inner.iter().for_each(|(name, command)| { @@ -455,33 +397,6 @@ async fn receive_hook<'a>( Status::Ok } -#[get("/metrics")] -async fn metrics( - address: SocketAddr, - metrics: &State, - config: &State, -) -> Option { - // Are metrics configured? - if let Some(metrics_config) = &config.metrics { - // Are metrics enabled? - if metrics_config.enabled { - // Is a filter configured? - if let Some(filter) = &metrics_config.ip_filter { - // Does the request match the filter? - if filter.validate(&address.ip()) { - return Some(get_metrics(metrics)); - } - } else { - return Some(get_metrics(metrics)); - } - } - } - - warn!("Forbidden request for metrics: {:?}", address); - - None -} - #[rocket::main] async fn main() -> Result<()> { env_logger::init(); @@ -502,9 +417,9 @@ async fn main() -> Result<()> { } rocket::build() - .mount("/", routes![receive_hook, metrics]) + .mount("/", routes![receive_hook, metrics::metrics]) .manage(config) - .manage(WebhookeyMetrics::default()) + .manage(Metrics::default()) .launch() .await?; @@ -548,7 +463,7 @@ mod tests { let rocket = rocket::build() .mount("/", routes![receive_hook]) .manage(config) - .manage(WebhookeyMetrics::default()); + .manage(Metrics::default()); let client = Client::tracked(rocket).await.unwrap(); let response = client @@ -764,7 +679,7 @@ mod tests { let rocket = rocket::build() .mount("/", routes![receive_hook]) .manage(config) - .manage(WebhookeyMetrics::default()); + .manage(Metrics::default()); let client = Client::tracked(rocket).await.unwrap(); @@ -822,7 +737,7 @@ mod tests { let rocket = rocket::build() .mount("/", routes![receive_hook]) .manage(config) - .manage(WebhookeyMetrics::default()); + .manage(Metrics::default()); let client = Client::tracked(rocket).await.unwrap(); diff --git a/src/metrics.rs b/src/metrics.rs new file mode 100644 index 0000000..71c4fae --- /dev/null +++ b/src/metrics.rs @@ -0,0 +1,91 @@ +use crate::Config; +use log::warn; +use rocket::{get, State}; +use std::{ + net::SocketAddr, + sync::atomic::{AtomicUsize, Ordering}, +}; + +#[derive(Debug, Default)] +pub struct Metrics { + pub requests_received: AtomicUsize, + pub requests_invalid: AtomicUsize, + pub hooks_successful: AtomicUsize, + pub hooks_forbidden: AtomicUsize, + pub hooks_unmatched: AtomicUsize, + pub commands_executed: AtomicUsize, + pub commands_execution_failed: AtomicUsize, + pub commands_successful: AtomicUsize, + pub commands_failed: AtomicUsize, +} + +#[get("/metrics")] +pub async fn metrics( + address: SocketAddr, + metrics: &State, + config: &State, +) -> Option { + // Are metrics configured? + if let Some(metrics_config) = &config.metrics { + // Are metrics enabled? + if metrics_config.enabled { + // Is a filter configured? + if let Some(filter) = &metrics_config.ip_filter { + // Does the request match the filter? + if filter.validate(&address.ip()) { + return Some(metrics.get_metrics()); + } + } else { + return Some(metrics.get_metrics()); + } + } + } + + warn!("Forbidden request for metrics: {:?}", address); + + None +} + +impl Metrics { + fn get_metrics(&self) -> String { + format!( + r"# HELP webhookey_requests_received Number of requests received +# TYPE webhookey_requests_received gauge +webhookey_requests_received {} +# HELP webhookey_requests_invalid Number of invalid requests received +# TYPE webhookey_requests_invalid gauge +webhookey_requests_invalid {} +# HELP webhookey_hooks_successful Number of successfully executed hooks +# TYPE webhookey_hooks_successful gauge +webhookey_hooks_sucessful {} +# HELP webhookey_hooks_forbidden Number of forbidden requests +# TYPE webhookey_hooks_forbidden gauge +webhookey_hooks_forbidden {} +# HELP webhookey_hooks_unmatched Number of unmatched requests +# TYPE webhookey_hooks_unmatched gauge +webhookey_hooks_unmatched {} +# HELP webhookey_commands_executed Number of commands executed +# TYPE webhookey_commands_executed gauge +webhookey_commands_executed {} +# HELP webhookey_commands_execution_failed Number of commands failed to execute +# TYPE webhookey_commands_execution_failed gauge +webhookey_commands_execution_failed {} +# HELP webhookey_commands_successful Number of executed commands returning return code 0 +# TYPE webhookey_commands_successful gauge +webhookey_commands_successful {} +# HELP webhookey_commands_failed Number of executed commands returning different return code than 0 +# TYPE webhookey_commands_failed gauge +webhookey_commands_failed {} +", + self.requests_received.load(Ordering::Relaxed), + self.requests_invalid.load(Ordering::Relaxed), + self.hooks_successful.load(Ordering::Relaxed), + self.hooks_forbidden.load(Ordering::Relaxed), + self.hooks_unmatched.load(Ordering::Relaxed), + self.commands_executed.load(Ordering::Relaxed), + self.commands_execution_failed.load(Ordering::Relaxed), + self.commands_successful.load(Ordering::Relaxed), + self.commands_failed.load(Ordering::Relaxed), + ) + } +} From 1280352f2552380228efc11665cdfb61159e98d5 Mon Sep 17 00:00:00 2001 From: finga Date: Fri, 19 Nov 2021 13:41:48 +0100 Subject: [PATCH 43/65] Move config related code into `config.rs` To continue with code separation to improve readability. --- src/config.rs | 52 +++++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 54 +++++---------------------------------------------- 2 files changed, 57 insertions(+), 49 deletions(-) create mode 100644 src/config.rs diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..ee45a4f --- /dev/null +++ b/src/config.rs @@ -0,0 +1,52 @@ +use crate::{Hook, IpFilter}; +use anyhow::{bail, Result}; +use log::info; +use serde::{Deserialize, Serialize}; +use std::{collections::BTreeMap, fs::File}; + +#[derive(Debug, Deserialize, Serialize)] +#[serde(deny_unknown_fields)] +pub struct MetricsConfig { + pub enabled: bool, + pub ip_filter: Option, +} + +#[derive(Debug, Deserialize, Serialize)] +#[serde(deny_unknown_fields)] +pub struct Config { + pub metrics: Option, + pub hooks: BTreeMap, +} + +pub fn get_config() -> Result { + // Look for config in CWD.. + if let Ok(config) = File::open("config.yml") { + info!("Loading configuration from `./config.yml`"); + + return Ok(config); + } + + // ..look for user path config.. + if let Some(mut path) = dirs::config_dir() { + path.push("webhookey/config.yml"); + + if let Ok(config) = File::open(&path) { + info!( + "Loading configuration from `{}`", + path.to_str().unwrap_or(""), + ); + + return Ok(config); + } + } + + // ..look for systemwide config.. + if let Ok(config) = File::open("/etc/webhookey/config.yml") { + info!("Loading configuration from `/etc/webhookey/config.yml`"); + + return Ok(config); + } + + // ..you had your chance. + bail!("No configuration file found."); +} diff --git a/src/main.rs b/src/main.rs index a7850e3..d97f601 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,9 +1,11 @@ mod cli; +mod config; mod filters; mod metrics; use crate::{ cli::Opts, + config::Config, filters::{FilterType, IpFilter}, metrics::Metrics, }; @@ -50,21 +52,7 @@ pub enum WebhookeyError { #[derive(Debug, Deserialize, Serialize)] #[serde(deny_unknown_fields)] -struct MetricsConfig { - enabled: bool, - ip_filter: Option, -} - -#[derive(Debug, Deserialize, Serialize)] -#[serde(deny_unknown_fields)] -pub struct Config { - metrics: Option, - hooks: BTreeMap, -} - -#[derive(Debug, Deserialize, Serialize)] -#[serde(deny_unknown_fields)] -struct Hook { +pub struct Hook { command: String, signature: String, ip_filter: Option, @@ -266,39 +254,6 @@ pub fn get_string(data: &serde_json::Value) -> Result { } } -fn get_config() -> Result { - // Look for config in CWD.. - if let Ok(config) = File::open("config.yml") { - info!("Loading configuration from `./config.yml`"); - - return Ok(config); - } - - // ..look for user path config.. - if let Some(mut path) = dirs::config_dir() { - path.push("webhookey/config.yml"); - - if let Ok(config) = File::open(&path) { - info!( - "Loading configuration from `{}`", - path.to_str().unwrap_or(""), - ); - - return Ok(config); - } - } - - // ..look for systemwide config.. - if let Ok(config) = File::open("/etc/webhookey/config.yml") { - info!("Loading configuration from `/etc/webhookey/config.yml`"); - - return Ok(config); - } - - // ..you had your chance. - bail!("No configuration file found."); -} - #[rocket::async_trait] impl<'r> FromData<'r> for Hooks { type Error = WebhookeyError; @@ -405,7 +360,7 @@ async fn main() -> Result<()> { let config: Config = match cli.config { Some(config) => serde_yaml::from_reader(BufReader::new(File::open(config)?))?, - _ => serde_yaml::from_reader(BufReader::new(get_config()?))?, + _ => serde_yaml::from_reader(BufReader::new(config::get_config()?))?, }; trace!("Parsed configuration:\n{}", serde_yaml::to_string(&config)?); @@ -429,6 +384,7 @@ async fn main() -> Result<()> { #[cfg(test)] mod tests { use super::*; + use crate::config::MetricsConfig; use filters::{AddrType, HeaderFilter, JsonFilter}; use regex::Regex; use rocket::{ From 5775870a8e5cfa5ef968ce06814bfdce9376c2de Mon Sep 17 00:00:00 2001 From: finga Date: Fri, 19 Nov 2021 14:18:33 +0100 Subject: [PATCH 44/65] Move hook related code into `hooks.rs` This concludes the code separation into several files. --- src/config.rs | 2 +- src/hooks.rs | 801 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 800 +------------------------------------------------ 3 files changed, 809 insertions(+), 794 deletions(-) create mode 100644 src/hooks.rs diff --git a/src/config.rs b/src/config.rs index ee45a4f..64b0eb4 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,4 +1,4 @@ -use crate::{Hook, IpFilter}; +use crate::{filters::IpFilter, hooks::Hook}; use anyhow::{bail, Result}; use log::info; use serde::{Deserialize, Serialize}; diff --git a/src/hooks.rs b/src/hooks.rs new file mode 100644 index 0000000..5840524 --- /dev/null +++ b/src/hooks.rs @@ -0,0 +1,801 @@ +use crate::{ + filters::{FilterType, IpFilter}, + Config, Metrics, WebhookeyError, +}; +use anyhow::{anyhow, bail, Result}; +use hmac::{Hmac, Mac, NewMac}; +use log::{debug, error, info, trace, warn}; +use rocket::{ + data::{FromData, ToByteUnit}, + futures::TryFutureExt, + http::{HeaderMap, Status}, + outcome::Outcome::{self, Failure, Success}, + post, + tokio::io::AsyncReadExt, + Data, Request, State, +}; +use run_script::ScriptOptions; +use serde::{Deserialize, Serialize}; +use sha2::Sha256; +use std::{ + collections::BTreeMap, + net::{IpAddr, Ipv4Addr, SocketAddr}, + sync::atomic::Ordering, +}; + +fn accept_ip(hook_name: &str, client_ip: &IpAddr, ip: &IpFilter) -> bool { + if ip.validate(client_ip) { + info!("Allow hook `{}` from {}", &hook_name, &client_ip); + return true; + } + + warn!("Deny hook `{}` from {}", &hook_name, &client_ip); + false +} + +fn get_header_field<'a>(headers: &'a HeaderMap, param: &str) -> Result<&'a str> { + headers + .get_one(param) + .ok_or_else(|| anyhow!("Could not extract event parameter from header")) +} + +fn validate_request(secret: &str, signature: &str, data: &[u8]) -> Result<()> { + let mut mac = Hmac::::new_from_slice(secret.as_bytes()) + .map_err(|e| anyhow!("Could not create hasher with secret: {}", e))?; + mac.update(data); + let raw_signature = hex::decode(signature.as_bytes())?; + mac.verify(&raw_signature).map_err(|e| anyhow!("{}", e)) +} + +#[derive(Debug, Deserialize, Serialize)] +#[serde(deny_unknown_fields)] +pub struct Hook { + command: String, + signature: String, + ip_filter: Option, + secrets: Vec, + filter: FilterType, +} + +impl Hook { + fn get_command( + &self, + hook_name: &str, + request: &Request, + data: &mut serde_json::Value, + ) -> Result { + debug!("Replacing parameters for command of hook `{}`", hook_name); + + Hook::replace_parameters(&self.command, request.headers(), data) + } + + fn replace_parameters( + input: &str, + headers: &HeaderMap, + data: &serde_json::Value, + ) -> Result { + let mut command = String::new(); + let command_template = &mut input.chars(); + + while let Some(i) = command_template.next() { + if i == '{' { + if let Some('{') = command_template.next() { + let mut token = String::new(); + + while let Some(i) = command_template.next() { + if i == '}' { + if let Some('}') = command_template.next() { + let expr = token.trim().split(' ').collect::>(); + + let replaced = match expr.get(0) { + Some(&"header") => get_header_field( + headers, + expr.get(1).ok_or_else(|| { + anyhow!("Missing parameter for `header` expression") + })?, + )? + .to_string(), + Some(pointer) => crate::get_string( + data.pointer(pointer).ok_or_else(|| { + anyhow!( + "Could not find field refered to in parameter `{}`", + pointer + ) + })?, + )?, + None => bail!("Missing expression in variable `{}`", token), + }; + + command.push_str(&replaced); + + trace!("Replace `{}` with: {}", token, replaced); + + break; + } else { + command.push('}'); + command.push(i); + } + } else { + token.push(i); + } + } + } else { + command.push('{'); + command.push(i); + } + } else { + command.push(i); + } + } + + Ok(command) + } +} + +#[derive(Debug)] +pub struct Hooks { + pub inner: BTreeMap, +} + +impl Hooks { + pub async fn get_commands( + request: &Request<'_>, + data: Data<'_>, + ) -> Result { + let mut buffer = Vec::new(); + let size = data + .open(1_i32.megabytes()) + .read_to_end(&mut buffer) + .map_err(WebhookeyError::Io) + .await?; + info!("Data of size {} received", size); + + let config = request.guard::<&State>().await.unwrap(); // should never fail + let mut valid = false; + let mut result = BTreeMap::new(); + let client_ip = &request + .client_ip() + .unwrap_or(IpAddr::V4(Ipv4Addr::UNSPECIFIED)); + + let hooks = config.hooks.iter().filter(|(name, hook)| { + if let Some(ip) = &hook.ip_filter { + accept_ip(name, client_ip, ip) + } else { + info!( + "Allow hook `{}` from {}, no IP filter was configured", + &name, &client_ip + ); + true + } + }); + + for (hook_name, hook) in hooks { + let signature = request + .headers() + .get_one(&hook.signature) + .ok_or(WebhookeyError::InvalidSignature)?; + + let secrets = hook + .secrets + .iter() + .map(|secret| validate_request(secret, signature, &buffer)); + + for secret in secrets { + match secret { + Ok(()) => { + trace!("Valid signature found for hook `{}`", hook_name); + + valid = true; + + let mut data: serde_json::Value = + serde_json::from_slice(&buffer).map_err(WebhookeyError::Serde)?; + + match hook.filter.evaluate(request, &data) { + Ok(true) => match hook.get_command(hook_name, request, &mut data) { + Ok(command) => { + info!("Filter for `{}` matched", &hook_name); + result.insert(hook_name.to_string(), command); + break; + } + Err(e) => error!("{}", e), + }, + Ok(false) => info!("Filter for `{}` did not match", &hook_name), + Err(error) => { + error!("Could not match filter for `{}`: {}", &hook_name, error) + } + } + } + Err(e) => trace!("Hook `{}` could not validate request: {}", &hook_name, e), + } + } + } + + if !valid { + return Err(WebhookeyError::Unauthorized(*client_ip)); + } + + Ok(Hooks { inner: result }) + } +} + +#[rocket::async_trait] +impl<'r> FromData<'r> for Hooks { + type Error = WebhookeyError; + + async fn from_data( + request: &'r Request<'_>, + data: Data<'r>, + ) -> Outcome> { + { + request + .guard::<&State>() + .await + .unwrap() // TODO: Check if unwrap need to be fixed + .requests_received + .fetch_add(1, Ordering::Relaxed); + } + + match Hooks::get_commands(request, data).await { + Ok(hooks) => { + if hooks.inner.is_empty() { + let client_ip = &request + .client_ip() + .unwrap_or(IpAddr::V4(Ipv4Addr::UNSPECIFIED)); + + request + .guard::<&State>() + .await + .unwrap() // TODO: Check if unwrap need to be fixed + .hooks_unmatched + .fetch_add(1, Ordering::Relaxed); + + warn!("Unmatched hook from {}", &client_ip); + return Failure((Status::NotFound, WebhookeyError::UnmatchedHook(*client_ip))); + } + + Success(hooks) + } + Err(WebhookeyError::Unauthorized(e)) => { + error!("{}", WebhookeyError::Unauthorized(e)); + + request + .guard::<&State>() + .await + .unwrap() // TODO: Check if unwrap need to be fixed + .hooks_forbidden + .fetch_add(1, Ordering::Relaxed); + + Failure((Status::Unauthorized, WebhookeyError::Unauthorized(e))) + } + Err(e) => { + error!("{}", e); + + request + .guard::<&State>() + .await + .unwrap() // TODO: Check if unwrap need to be fixed + .requests_invalid + .fetch_add(1, Ordering::Relaxed); + + Failure((Status::BadRequest, e)) + } + } + } +} + +#[post("/", format = "json", data = "")] +pub async fn receive_hook<'a>( + address: SocketAddr, + hooks: Hooks, + metrics: &State, +) -> Status { + info!("Post request received from: {}", address); + + hooks.inner.iter().for_each(|(name, command)| { + info!("Execute `{}` from hook `{}`", &command, &name); + + match run_script::run(command, &vec![], &ScriptOptions::new()) { + Ok((status, stdout, stderr)) => { + info!("Command `{}` exited with return code: {}", &command, status); + trace!("Output of command `{}` on stdout: {:?}", &command, &stdout); + debug!("Output of command `{}` on stderr: {:?}", &command, &stderr); + + metrics.commands_executed.fetch_add(1, Ordering::Relaxed); + + let _ = match status { + 0 => metrics.commands_successful.fetch_add(1, Ordering::Relaxed), + _ => metrics.commands_failed.fetch_add(1, Ordering::Relaxed), + }; + } + Err(e) => { + error!("Execution of `{}` failed: {}", &command, e); + + metrics + .commands_execution_failed + .fetch_add(1, Ordering::Relaxed); + } + } + }); + + Status::Ok +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{ + config::MetricsConfig, + filters::{AddrType, FilterType, HeaderFilter, JsonFilter}, + hooks::Hook, + Metrics, + }; + use regex::Regex; + use rocket::{ + http::{ContentType, Header, Status}, + local::asynchronous::Client, + routes, + }; + use serde_json::json; + use std::collections::BTreeMap; + + #[rocket::async_test] + async fn secret() { + let mut hooks = BTreeMap::new(); + + hooks.insert( + "test_hook".to_string(), + Hook { + command: "".to_string(), + signature: "X-Gitea-Signature".to_string(), + ip_filter: None, + secrets: vec!["valid".to_string()], + filter: FilterType::JsonFilter(JsonFilter { + pointer: "*".to_string(), + regex: Regex::new(".*").unwrap(), + }), + }, + ); + + let config = Config { + metrics: None, + hooks: hooks, + }; + + let rocket = rocket::build() + .mount("/", routes![receive_hook]) + .manage(config) + .manage(Metrics::default()); + + let client = Client::tracked(rocket).await.unwrap(); + let response = client + .post("/") + .header(Header::new( + "X-Gitea-Signature", + "28175a0035f637f3cbb85afee9f9d319631580e7621cf790cd16ca063a2f820e", + )) + .header(ContentType::JSON) + .remote("127.0.0.1:8000".parse().unwrap()) + .body(&serde_json::to_string(&json!({ "foo": "bar" })).unwrap()) + .dispatch(); + + assert_eq!(response.await.status(), Status::NotFound); + + let response = client + .post("/") + .header(Header::new("X-Gitea-Signature", "beef")) + .header(ContentType::JSON) + .remote("127.0.0.1:8000".parse().unwrap()) + .body(&serde_json::to_string(&json!({ "foo": "bar" })).unwrap()) + .dispatch(); + + assert_eq!(response.await.status(), Status::Unauthorized); + + let response = client + .post("/") + .header(Header::new( + "X-Gitea-Signature", + "c5c315d76318362ec129ca629b50b626bba09ad3d7ba4cc0f4c0afe4a90537a0", + )) + .header(ContentType::JSON) + .remote("127.0.0.1:8000".parse().unwrap()) + .body(r#"{ "not_secret": "invalid" "#) + .dispatch(); + + assert_eq!(response.await.status(), Status::BadRequest); + + let response = client + .post("/") + .header(Header::new("X-Gitea-Signature", "foobar")) + .header(ContentType::JSON) + .remote("127.0.0.1:8000".parse().unwrap()) + .dispatch(); + + assert_eq!(response.await.status(), Status::Unauthorized); + } + + #[rocket::async_test] + async fn parse_command_request() { + let mut hooks = BTreeMap::new(); + + hooks.insert( + "test_hook0".to_string(), + Hook { + command: + "/usr/bin/echo {{ /repository/full_name }} --foo {{ /pull_request/base/ref }}" + .to_string(), + signature: "X-Gitea-Signature".to_string(), + ip_filter: None, + secrets: vec!["valid".to_string()], + filter: FilterType::JsonFilter(JsonFilter { + pointer: "/foo".to_string(), + regex: Regex::new("bar").unwrap(), + }), + }, + ); + + hooks.insert( + "test_hook2".to_string(), + Hook { + command: "/usr/bin/echo {{ /repository/full_name }} {{ /pull_request/base/ref }}" + .to_string(), + signature: "X-Gitea-Signature".to_string(), + ip_filter: None, + secrets: vec!["valid".to_string()], + filter: FilterType::JsonFilter(JsonFilter { + pointer: "/foo".to_string(), + regex: Regex::new("bar").unwrap(), + }), + }, + ); + + hooks.insert( + "test_hook3".to_string(), + Hook { + command: "/usr/bin/echo {{ /repository/full_name }} {{ /pull_request/base/ref }}" + .to_string(), + signature: "X-Gitea-Signature".to_string(), + ip_filter: None, + secrets: vec!["valid".to_string()], + filter: FilterType::Not(Box::new(FilterType::JsonFilter(JsonFilter { + pointer: "/foobar".to_string(), + regex: Regex::new("bar").unwrap(), + }))), + }, + ); + + let config = Config { + metrics: None, + hooks: hooks, + }; + + let rocket = rocket::build() + .mount("/", routes![receive_hook]) + .manage(config) + .manage(Metrics::default()); + + let client = Client::tracked(rocket).await.unwrap(); + + let response = client + .post("/") + .header(Header::new( + "X-Gitea-Signature", + "693b733871ecb684651a813c82936df683c9e4a816581f385353e06170545400", + )) + .header(ContentType::JSON) + .remote("127.0.0.1:8000".parse().unwrap()) + .body( + &serde_json::to_string(&json!({ + "foo": "bar", + "repository": { + "full_name": "keith" + }, + "pull_request": { + "base": { + "ref": "main" + } + } + })) + .unwrap(), + ) + .dispatch(); + + assert_eq!(response.await.status(), Status::Ok); + } + + #[rocket::async_test] + async fn parse_invalid_command_request() { + let mut hooks = BTreeMap::new(); + + hooks.insert( + "test_hook".to_string(), + Hook { + command: "/usr/bin/echo {{ /repository/full }} {{ /pull_request/base/ref }}" + .to_string(), + signature: "X-Gitea-Signature".to_string(), + ip_filter: None, + secrets: vec!["valid".to_string()], + filter: FilterType::JsonFilter(JsonFilter { + pointer: "/foo".to_string(), + regex: Regex::new("bar").unwrap(), + }), + }, + ); + + let config = Config { + metrics: None, + hooks: hooks, + }; + + let rocket = rocket::build() + .mount("/", routes![receive_hook]) + .manage(config) + .manage(Metrics::default()); + + let client = Client::tracked(rocket).await.unwrap(); + + let response = client + .post("/") + .header(Header::new( + "X-Gitea-Signature", + "693b733871ecb684651a813c82936df683c9e4a816581f385353e06170545400", + )) + .header(ContentType::JSON) + .remote("127.0.0.1:8000".parse().unwrap()) + .body( + &serde_json::to_string(&json!({ + "foo": "bar", + "repository": { + "full_name": "keith" + }, + "pull_request": { + "base": { + "ref": "main" + } + } + })) + .unwrap(), + ) + .dispatch(); + + assert_eq!(response.await.status(), Status::NotFound); + } + + #[test] + fn parse_command() { + let mut headers = HeaderMap::new(); + headers.add_raw("X-Gitea-Event", "something"); + + assert_eq!( + Hook::replace_parameters("command", &headers, &serde_json::Value::Null).unwrap(), + "command" + ); + + assert_eq!( + Hook::replace_parameters(" command", &headers, &serde_json::Value::Null).unwrap(), + " command" + ); + + assert_eq!( + Hook::replace_parameters("command ", &headers, &serde_json::Value::Null).unwrap(), + "command " + ); + + assert_eq!( + Hook::replace_parameters(" command ", &headers, &serde_json::Value::Null) + .unwrap(), + " command " + ); + + assert_eq!( + Hook::replace_parameters("command command ", &headers, &serde_json::Value::Null) + .unwrap(), + "command command " + ); + + assert_eq!( + Hook::replace_parameters("{{ /foo }} command", &headers, &json!({ "foo": "bar" })) + .unwrap(), + "bar command" + ); + + assert_eq!( + Hook::replace_parameters( + " command {{ /foo }} ", + &headers, + &json!({ "foo": "bar" }) + ) + .unwrap(), + " command bar " + ); + + assert_eq!( + Hook::replace_parameters( + "{{ /foo }} command{{/field1/foo}}", + &headers, + &json!({ "foo": "bar", "field1": { "foo": "baz" } }) + ) + .unwrap(), + "bar commandbaz" + ); + + assert_eq!( + Hook::replace_parameters( + " command {{ /foo }} ", + &headers, + &json!({ "foo": "bar" }) + ) + .unwrap(), + " command bar " + ); + + assert_eq!( + Hook::replace_parameters( + " {{ /field1/foo }} command", + &headers, + &json!({ "field1": { "foo": "bar" } }) + ) + .unwrap(), + " bar command" + ); + + assert_eq!( + Hook::replace_parameters( + " {{ header X-Gitea-Event }} command", + &headers, + &json!({ "field1": { "foo": "bar" } }) + ) + .unwrap(), + " something command" + ); + + assert_eq!( + Hook::replace_parameters( + " {{ header X-Gitea-Event }} {{ /field1/foo }} command", + &headers, + &json!({ "field1": { "foo": "bar" } }) + ) + .unwrap(), + " something bar command" + ); + + assert_eq!( + Hook::replace_parameters( + " {{ header X-Gitea-Event }} {{ /field1/foo }} {{ /field1/bar }} {{ /field2/foo }} --command{{ /cmd }}", + &headers, + &json!({ "field1": { "foo": "bar", "bar": "baz" }, "field2": { "foo": "qux" }, "cmd": " else"}) + ) + .unwrap(), + " something bar baz qux --command else" + ); + } + + #[test] + fn parse_config() { + let config: Config = serde_yaml::from_str( + r#"--- +hooks: + hook1: + command: /usr/bin/local/script_xy.sh {{ /field2/foo }} asdfasdf + signature: X-Gitea-Signature + ip_filter: + allow: + - 127.0.0.1/31 + secrets: + - secret_key_01 + - secret_key_02 + filter: + json: + pointer: /ref + regex: refs/heads/master + hook2: + command: /usr/bin/local/script_xy.sh asdfasdf + signature: X-Gitea-Signature + secrets: + - secret_key_01 + - secret_key_02 + filter: + and: + - json: + pointer: /ref + regex: refs/heads/master + - header: + field: X-Gitea-Signature + regex: f6e5fe4fe37df76629112d55cc210718b6a55e7e"#, + ) + .unwrap(); + + assert_eq!( + serde_yaml::to_string(&config).unwrap(), + serde_yaml::to_string(&Config { + metrics: None, + hooks: BTreeMap::from([ + ( + "hook1".to_string(), + Hook { + command: "/usr/bin/local/script_xy.sh {{ /field2/foo }} asdfasdf" + .to_string(), + signature: "X-Gitea-Signature".to_string(), + ip_filter: Some(IpFilter::Allow(vec![AddrType::IpNet( + "127.0.0.1/31".parse().unwrap() + )])), + secrets: vec!["secret_key_01".to_string(), "secret_key_02".to_string()], + filter: FilterType::JsonFilter(JsonFilter { + pointer: "/ref".to_string(), + regex: Regex::new("refs/heads/master").unwrap(), + }), + } + ), + ( + "hook2".to_string(), + Hook { + command: "/usr/bin/local/script_xy.sh asdfasdf".to_string(), + signature: "X-Gitea-Signature".to_string(), + ip_filter: None, + secrets: vec!["secret_key_01".to_string(), "secret_key_02".to_string()], + filter: FilterType::And(vec![ + FilterType::JsonFilter(JsonFilter { + pointer: "/ref".to_string(), + regex: Regex::new("refs/heads/master").unwrap(), + }), + FilterType::HeaderFilter(HeaderFilter { + field: "X-Gitea-Signature".to_string(), + regex: Regex::new("f6e5fe4fe37df76629112d55cc210718b6a55e7e") + .unwrap(), + }), + ]), + } + ) + ]) + }) + .unwrap() + ); + + let config: Config = serde_yaml::from_str( + r#"--- +metrics: + enabled: true +hooks: + hook1: + command: /usr/bin/local/script_xy.sh {{ /field2/foo }} asdfasdf + signature: X-Gitea-Signature + ip_filter: + allow: + - 127.0.0.1/31 + secrets: + - secret_key_01 + - secret_key_02 + filter: + json: + pointer: /ref + regex: refs/heads/master"#, + ) + .unwrap(); + + assert_eq!( + serde_yaml::to_string(&config).unwrap(), + serde_yaml::to_string(&Config { + metrics: Some(MetricsConfig { + enabled: true, + ip_filter: None + }), + hooks: BTreeMap::from([( + "hook1".to_string(), + Hook { + command: "/usr/bin/local/script_xy.sh {{ /field2/foo }} asdfasdf" + .to_string(), + signature: "X-Gitea-Signature".to_string(), + ip_filter: Some(IpFilter::Allow(vec![AddrType::IpNet( + "127.0.0.1/31".parse().unwrap() + )])), + secrets: vec!["secret_key_01".to_string(), "secret_key_02".to_string()], + filter: FilterType::JsonFilter(JsonFilter { + pointer: "/ref".to_string(), + regex: Regex::new("refs/heads/master").unwrap(), + }), + } + ),]) + }) + .unwrap() + ); + } +} diff --git a/src/main.rs b/src/main.rs index d97f601..65c64c4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,37 +1,15 @@ mod cli; mod config; mod filters; +mod hooks; mod metrics; -use crate::{ - cli::Opts, - config::Config, - filters::{FilterType, IpFilter}, - metrics::Metrics, -}; -use anyhow::{anyhow, bail, Result}; +use crate::{cli::Opts, config::Config, metrics::Metrics}; +use anyhow::Result; use clap::Parser; -use hmac::{Hmac, Mac, NewMac}; -use log::{debug, error, info, trace, warn}; -use rocket::{ - data::{FromData, ToByteUnit}, - futures::TryFutureExt, - http::{HeaderMap, Status}, - outcome::Outcome::{self, Failure, Success}, - post, routes, - tokio::io::AsyncReadExt, - Data, Request, State, -}; -use run_script::ScriptOptions; -use serde::{Deserialize, Serialize}; -use sha2::Sha256; -use std::{ - collections::BTreeMap, - fs::File, - io::BufReader, - net::{IpAddr, Ipv4Addr, SocketAddr}, - sync::atomic::Ordering, -}; +use log::{debug, error, trace}; +use rocket::routes; +use std::{fs::File, io::BufReader, net::IpAddr}; use thiserror::Error; #[derive(Debug, Error)] @@ -50,198 +28,6 @@ pub enum WebhookeyError { Serde(serde_json::Error), } -#[derive(Debug, Deserialize, Serialize)] -#[serde(deny_unknown_fields)] -pub struct Hook { - command: String, - signature: String, - ip_filter: Option, - secrets: Vec, - filter: FilterType, -} - -impl Hook { - fn get_command( - &self, - hook_name: &str, - request: &Request, - data: &mut serde_json::Value, - ) -> Result { - debug!("Replacing parameters for command of hook `{}`", hook_name); - - Hook::replace_parameters(&self.command, request.headers(), data) - } - - fn replace_parameters( - input: &str, - headers: &HeaderMap, - data: &serde_json::Value, - ) -> Result { - let mut command = String::new(); - let command_template = &mut input.chars(); - - while let Some(i) = command_template.next() { - if i == '{' { - if let Some('{') = command_template.next() { - let mut token = String::new(); - - while let Some(i) = command_template.next() { - if i == '}' { - if let Some('}') = command_template.next() { - let expr = token.trim().split(' ').collect::>(); - - let replaced = match expr.get(0) { - Some(&"header") => get_header_field( - headers, - expr.get(1).ok_or_else(|| { - anyhow!("Missing parameter for `header` expression") - })?, - )? - .to_string(), - Some(pointer) => { - get_string(data.pointer(pointer).ok_or_else(|| { - anyhow!( - "Could not find field refered to in parameter `{}`", - pointer - ) - })?)? - } - None => bail!("Missing expression in variable `{}`", token), - }; - - command.push_str(&replaced); - - trace!("Replace `{}` with: {}", token, replaced); - - break; - } else { - command.push('}'); - command.push(i); - } - } else { - token.push(i); - } - } - } else { - command.push('{'); - command.push(i); - } - } else { - command.push(i); - } - } - - Ok(command) - } -} - -#[derive(Debug)] -struct Hooks { - inner: BTreeMap, -} - -impl Hooks { - async fn get_commands(request: &Request<'_>, data: Data<'_>) -> Result { - let mut buffer = Vec::new(); - let size = data - .open(256_i32.kilobytes()) - .read_to_end(&mut buffer) - .map_err(WebhookeyError::Io) - .await?; - info!("Data of size {} received", size); - - let config = request.guard::<&State>().await.unwrap(); // should never fail - let mut valid = false; - let mut result = BTreeMap::new(); - let client_ip = &request - .client_ip() - .unwrap_or(IpAddr::V4(Ipv4Addr::UNSPECIFIED)); - - let hooks = config.hooks.iter().filter(|(name, hook)| { - if let Some(ip) = &hook.ip_filter { - accept_ip(name, client_ip, ip) - } else { - info!( - "Allow hook `{}` from {}, no IP filter was configured", - &name, &client_ip - ); - true - } - }); - - for (hook_name, hook) in hooks { - let signature = request - .headers() - .get_one(&hook.signature) - .ok_or(WebhookeyError::InvalidSignature)?; - - let secrets = hook - .secrets - .iter() - .map(|secret| validate_request(secret, signature, &buffer)); - - for secret in secrets { - match secret { - Ok(()) => { - trace!("Valid signature found for hook `{}`", hook_name); - - valid = true; - - let mut data: serde_json::Value = - serde_json::from_slice(&buffer).map_err(WebhookeyError::Serde)?; - - match hook.filter.evaluate(request, &data) { - Ok(true) => match hook.get_command(hook_name, request, &mut data) { - Ok(command) => { - info!("Filter for `{}` matched", &hook_name); - result.insert(hook_name.to_string(), command); - break; - } - Err(e) => error!("{}", e), - }, - Ok(false) => info!("Filter for `{}` did not match", &hook_name), - Err(error) => { - error!("Could not match filter for `{}`: {}", &hook_name, error) - } - } - } - Err(e) => trace!("Hook `{}` could not validate request: {}", &hook_name, e), - } - } - } - - if !valid { - return Err(WebhookeyError::Unauthorized(*client_ip)); - } - - Ok(Hooks { inner: result }) - } -} - -fn accept_ip(hook_name: &str, client_ip: &IpAddr, ip: &IpFilter) -> bool { - if ip.validate(client_ip) { - info!("Allow hook `{}` from {}", &hook_name, &client_ip); - return true; - } - - warn!("Deny hook `{}` from {}", &hook_name, &client_ip); - false -} - -fn validate_request(secret: &str, signature: &str, data: &[u8]) -> Result<()> { - let mut mac = Hmac::::new_from_slice(secret.as_bytes()) - .map_err(|e| anyhow!("Could not create hasher with secret: {}", e))?; - mac.update(data); - let raw_signature = hex::decode(signature.as_bytes())?; - mac.verify(&raw_signature).map_err(|e| anyhow!("{}", e)) -} - -fn get_header_field<'a>(headers: &'a HeaderMap, param: &str) -> Result<&'a str> { - headers - .get_one(param) - .ok_or_else(|| anyhow!("Could not extract event parameter from header")) -} - pub fn get_string(data: &serde_json::Value) -> Result { match &data { serde_json::Value::Bool(bool) => Ok(bool.to_string()), @@ -254,104 +40,6 @@ pub fn get_string(data: &serde_json::Value) -> Result { } } -#[rocket::async_trait] -impl<'r> FromData<'r> for Hooks { - type Error = WebhookeyError; - - async fn from_data( - request: &'r Request<'_>, - data: Data<'r>, - ) -> Outcome> { - { - request - .guard::<&State>() - .await - .unwrap() // TODO: Check if unwrap need to be fixed - .requests_received - .fetch_add(1, Ordering::Relaxed); - } - - match Hooks::get_commands(request, data).await { - Ok(hooks) => { - if hooks.inner.is_empty() { - let client_ip = &request - .client_ip() - .unwrap_or(IpAddr::V4(Ipv4Addr::UNSPECIFIED)); - - request - .guard::<&State>() - .await - .unwrap() // TODO: Check if unwrap need to be fixed - .hooks_unmatched - .fetch_add(1, Ordering::Relaxed); - - warn!("Unmatched hook from {}", &client_ip); - return Failure((Status::NotFound, WebhookeyError::UnmatchedHook(*client_ip))); - } - - Success(hooks) - } - Err(WebhookeyError::Unauthorized(e)) => { - error!("{}", WebhookeyError::Unauthorized(e)); - - request - .guard::<&State>() - .await - .unwrap() // TODO: Check if unwrap need to be fixed - .hooks_forbidden - .fetch_add(1, Ordering::Relaxed); - - Failure((Status::Unauthorized, WebhookeyError::Unauthorized(e))) - } - Err(e) => { - error!("{}", e); - - request - .guard::<&State>() - .await - .unwrap() // TODO: Check if unwrap need to be fixed - .requests_invalid - .fetch_add(1, Ordering::Relaxed); - - Failure((Status::BadRequest, e)) - } - } - } -} - -#[post("/", format = "json", data = "")] -async fn receive_hook<'a>(address: SocketAddr, hooks: Hooks, metrics: &State) -> Status { - info!("Post request received from: {}", address); - - hooks.inner.iter().for_each(|(name, command)| { - info!("Execute `{}` from hook `{}`", &command, &name); - - match run_script::run(command, &vec![], &ScriptOptions::new()) { - Ok((status, stdout, stderr)) => { - info!("Command `{}` exited with return code: {}", &command, status); - trace!("Output of command `{}` on stdout: {:?}", &command, &stdout); - debug!("Output of command `{}` on stderr: {:?}", &command, &stderr); - - metrics.commands_executed.fetch_add(1, Ordering::Relaxed); - - let _ = match status { - 0 => metrics.commands_successful.fetch_add(1, Ordering::Relaxed), - _ => metrics.commands_failed.fetch_add(1, Ordering::Relaxed), - }; - } - Err(e) => { - error!("Execution of `{}` failed: {}", &command, e); - - metrics - .commands_execution_failed - .fetch_add(1, Ordering::Relaxed); - } - } - }); - - Status::Ok -} - #[rocket::main] async fn main() -> Result<()> { env_logger::init(); @@ -372,7 +60,7 @@ async fn main() -> Result<()> { } rocket::build() - .mount("/", routes![receive_hook, metrics::metrics]) + .mount("/", routes![hooks::receive_hook, metrics::metrics]) .manage(config) .manage(Metrics::default()) .launch() @@ -380,477 +68,3 @@ async fn main() -> Result<()> { Ok(()) } - -#[cfg(test)] -mod tests { - use super::*; - use crate::config::MetricsConfig; - use filters::{AddrType, HeaderFilter, JsonFilter}; - use regex::Regex; - use rocket::{ - http::{ContentType, Header}, - local::asynchronous::Client, - }; - use serde_json::json; - - #[rocket::async_test] - async fn secret() { - let mut hooks = BTreeMap::new(); - - hooks.insert( - "test_hook".to_string(), - Hook { - command: "".to_string(), - signature: "X-Gitea-Signature".to_string(), - ip_filter: None, - secrets: vec!["valid".to_string()], - filter: FilterType::JsonFilter(JsonFilter { - pointer: "*".to_string(), - regex: Regex::new(".*").unwrap(), - }), - }, - ); - - let config = Config { - metrics: None, - hooks: hooks, - }; - - let rocket = rocket::build() - .mount("/", routes![receive_hook]) - .manage(config) - .manage(Metrics::default()); - - let client = Client::tracked(rocket).await.unwrap(); - let response = client - .post("/") - .header(Header::new( - "X-Gitea-Signature", - "28175a0035f637f3cbb85afee9f9d319631580e7621cf790cd16ca063a2f820e", - )) - .header(ContentType::JSON) - .remote("127.0.0.1:8000".parse().unwrap()) - .body(&serde_json::to_string(&json!({ "foo": "bar" })).unwrap()) - .dispatch(); - - assert_eq!(response.await.status(), Status::NotFound); - - let response = client - .post("/") - .header(Header::new("X-Gitea-Signature", "beef")) - .header(ContentType::JSON) - .remote("127.0.0.1:8000".parse().unwrap()) - .body(&serde_json::to_string(&json!({ "foo": "bar" })).unwrap()) - .dispatch(); - - assert_eq!(response.await.status(), Status::Unauthorized); - - let response = client - .post("/") - .header(Header::new( - "X-Gitea-Signature", - "c5c315d76318362ec129ca629b50b626bba09ad3d7ba4cc0f4c0afe4a90537a0", - )) - .header(ContentType::JSON) - .remote("127.0.0.1:8000".parse().unwrap()) - .body(r#"{ "not_secret": "invalid" "#) - .dispatch(); - - assert_eq!(response.await.status(), Status::BadRequest); - - let response = client - .post("/") - .header(Header::new("X-Gitea-Signature", "foobar")) - .header(ContentType::JSON) - .remote("127.0.0.1:8000".parse().unwrap()) - .dispatch(); - - assert_eq!(response.await.status(), Status::Unauthorized); - } - - #[test] - fn parse_command() { - let mut headers = HeaderMap::new(); - headers.add_raw("X-Gitea-Event", "something"); - - assert_eq!( - Hook::replace_parameters("command", &headers, &serde_json::Value::Null).unwrap(), - "command" - ); - - assert_eq!( - Hook::replace_parameters(" command", &headers, &serde_json::Value::Null).unwrap(), - " command" - ); - - assert_eq!( - Hook::replace_parameters("command ", &headers, &serde_json::Value::Null).unwrap(), - "command " - ); - - assert_eq!( - Hook::replace_parameters(" command ", &headers, &serde_json::Value::Null) - .unwrap(), - " command " - ); - - assert_eq!( - Hook::replace_parameters("command command ", &headers, &serde_json::Value::Null) - .unwrap(), - "command command " - ); - - assert_eq!( - Hook::replace_parameters("{{ /foo }} command", &headers, &json!({ "foo": "bar" })) - .unwrap(), - "bar command" - ); - - assert_eq!( - Hook::replace_parameters( - " command {{ /foo }} ", - &headers, - &json!({ "foo": "bar" }) - ) - .unwrap(), - " command bar " - ); - - assert_eq!( - Hook::replace_parameters( - "{{ /foo }} command{{/field1/foo}}", - &headers, - &json!({ "foo": "bar", "field1": { "foo": "baz" } }) - ) - .unwrap(), - "bar commandbaz" - ); - - assert_eq!( - Hook::replace_parameters( - " command {{ /foo }} ", - &headers, - &json!({ "foo": "bar" }) - ) - .unwrap(), - " command bar " - ); - - assert_eq!( - Hook::replace_parameters( - " {{ /field1/foo }} command", - &headers, - &json!({ "field1": { "foo": "bar" } }) - ) - .unwrap(), - " bar command" - ); - - assert_eq!( - Hook::replace_parameters( - " {{ header X-Gitea-Event }} command", - &headers, - &json!({ "field1": { "foo": "bar" } }) - ) - .unwrap(), - " something command" - ); - - assert_eq!( - Hook::replace_parameters( - " {{ header X-Gitea-Event }} {{ /field1/foo }} command", - &headers, - &json!({ "field1": { "foo": "bar" } }) - ) - .unwrap(), - " something bar command" - ); - - assert_eq!( - Hook::replace_parameters( - " {{ header X-Gitea-Event }} {{ /field1/foo }} {{ /field1/bar }} {{ /field2/foo }} --command{{ /cmd }}", - &headers, - &json!({ "field1": { "foo": "bar", "bar": "baz" }, "field2": { "foo": "qux" }, "cmd": " else"}) - ) - .unwrap(), - " something bar baz qux --command else" - ); - } - - #[rocket::async_test] - async fn parse_command_request() { - let mut hooks = BTreeMap::new(); - - hooks.insert( - "test_hook0".to_string(), - Hook { - command: - "/usr/bin/echo {{ /repository/full_name }} --foo {{ /pull_request/base/ref }}" - .to_string(), - signature: "X-Gitea-Signature".to_string(), - ip_filter: None, - secrets: vec!["valid".to_string()], - filter: FilterType::JsonFilter(JsonFilter { - pointer: "/foo".to_string(), - regex: Regex::new("bar").unwrap(), - }), - }, - ); - - hooks.insert( - "test_hook2".to_string(), - Hook { - command: "/usr/bin/echo {{ /repository/full_name }} {{ /pull_request/base/ref }}" - .to_string(), - signature: "X-Gitea-Signature".to_string(), - ip_filter: None, - secrets: vec!["valid".to_string()], - filter: FilterType::JsonFilter(JsonFilter { - pointer: "/foo".to_string(), - regex: Regex::new("bar").unwrap(), - }), - }, - ); - - hooks.insert( - "test_hook3".to_string(), - Hook { - command: "/usr/bin/echo {{ /repository/full_name }} {{ /pull_request/base/ref }}" - .to_string(), - signature: "X-Gitea-Signature".to_string(), - ip_filter: None, - secrets: vec!["valid".to_string()], - filter: FilterType::Not(Box::new(FilterType::JsonFilter(JsonFilter { - pointer: "/foobar".to_string(), - regex: Regex::new("bar").unwrap(), - }))), - }, - ); - - let config = Config { - metrics: None, - hooks: hooks, - }; - - let rocket = rocket::build() - .mount("/", routes![receive_hook]) - .manage(config) - .manage(Metrics::default()); - - let client = Client::tracked(rocket).await.unwrap(); - - let response = client - .post("/") - .header(Header::new( - "X-Gitea-Signature", - "693b733871ecb684651a813c82936df683c9e4a816581f385353e06170545400", - )) - .header(ContentType::JSON) - .remote("127.0.0.1:8000".parse().unwrap()) - .body( - &serde_json::to_string(&json!({ - "foo": "bar", - "repository": { - "full_name": "keith" - }, - "pull_request": { - "base": { - "ref": "main" - } - } - })) - .unwrap(), - ) - .dispatch(); - - assert_eq!(response.await.status(), Status::Ok); - } - - #[rocket::async_test] - async fn parse_invalid_command_request() { - let mut hooks = BTreeMap::new(); - - hooks.insert( - "test_hook".to_string(), - Hook { - command: "/usr/bin/echo {{ /repository/full }} {{ /pull_request/base/ref }}" - .to_string(), - signature: "X-Gitea-Signature".to_string(), - ip_filter: None, - secrets: vec!["valid".to_string()], - filter: FilterType::JsonFilter(JsonFilter { - pointer: "/foo".to_string(), - regex: Regex::new("bar").unwrap(), - }), - }, - ); - - let config = Config { - metrics: None, - hooks: hooks, - }; - - let rocket = rocket::build() - .mount("/", routes![receive_hook]) - .manage(config) - .manage(Metrics::default()); - - let client = Client::tracked(rocket).await.unwrap(); - - let response = client - .post("/") - .header(Header::new( - "X-Gitea-Signature", - "693b733871ecb684651a813c82936df683c9e4a816581f385353e06170545400", - )) - .header(ContentType::JSON) - .remote("127.0.0.1:8000".parse().unwrap()) - .body( - &serde_json::to_string(&json!({ - "foo": "bar", - "repository": { - "full_name": "keith" - }, - "pull_request": { - "base": { - "ref": "main" - } - } - })) - .unwrap(), - ) - .dispatch(); - - assert_eq!(response.await.status(), Status::NotFound); - } - - #[test] - fn parse_config() { - let config: Config = serde_yaml::from_str( - r#"--- -hooks: - hook1: - command: /usr/bin/local/script_xy.sh {{ /field2/foo }} asdfasdf - signature: X-Gitea-Signature - ip_filter: - allow: - - 127.0.0.1/31 - secrets: - - secret_key_01 - - secret_key_02 - filter: - json: - pointer: /ref - regex: refs/heads/master - hook2: - command: /usr/bin/local/script_xy.sh asdfasdf - signature: X-Gitea-Signature - secrets: - - secret_key_01 - - secret_key_02 - filter: - and: - - json: - pointer: /ref - regex: refs/heads/master - - header: - field: X-Gitea-Signature - regex: f6e5fe4fe37df76629112d55cc210718b6a55e7e"#, - ) - .unwrap(); - - assert_eq!( - serde_yaml::to_string(&config).unwrap(), - serde_yaml::to_string(&Config { - metrics: None, - hooks: BTreeMap::from([ - ( - "hook1".to_string(), - Hook { - command: "/usr/bin/local/script_xy.sh {{ /field2/foo }} asdfasdf" - .to_string(), - signature: "X-Gitea-Signature".to_string(), - ip_filter: Some(IpFilter::Allow(vec![AddrType::IpNet( - "127.0.0.1/31".parse().unwrap() - )])), - secrets: vec!["secret_key_01".to_string(), "secret_key_02".to_string()], - filter: FilterType::JsonFilter(JsonFilter { - pointer: "/ref".to_string(), - regex: Regex::new("refs/heads/master").unwrap(), - }), - } - ), - ( - "hook2".to_string(), - Hook { - command: "/usr/bin/local/script_xy.sh asdfasdf".to_string(), - signature: "X-Gitea-Signature".to_string(), - ip_filter: None, - secrets: vec!["secret_key_01".to_string(), "secret_key_02".to_string()], - filter: FilterType::And(vec![ - FilterType::JsonFilter(JsonFilter { - pointer: "/ref".to_string(), - regex: Regex::new("refs/heads/master").unwrap(), - }), - FilterType::HeaderFilter(HeaderFilter { - field: "X-Gitea-Signature".to_string(), - regex: Regex::new("f6e5fe4fe37df76629112d55cc210718b6a55e7e") - .unwrap(), - }), - ]), - } - ) - ]) - }) - .unwrap() - ); - - let config: Config = serde_yaml::from_str( - r#"--- -metrics: - enabled: true -hooks: - hook1: - command: /usr/bin/local/script_xy.sh {{ /field2/foo }} asdfasdf - signature: X-Gitea-Signature - ip_filter: - allow: - - 127.0.0.1/31 - secrets: - - secret_key_01 - - secret_key_02 - filter: - json: - pointer: /ref - regex: refs/heads/master"#, - ) - .unwrap(); - - assert_eq!( - serde_yaml::to_string(&config).unwrap(), - serde_yaml::to_string(&Config { - metrics: Some(MetricsConfig { - enabled: true, - ip_filter: None - }), - hooks: BTreeMap::from([( - "hook1".to_string(), - Hook { - command: "/usr/bin/local/script_xy.sh {{ /field2/foo }} asdfasdf" - .to_string(), - signature: "X-Gitea-Signature".to_string(), - ip_filter: Some(IpFilter::Allow(vec![AddrType::IpNet( - "127.0.0.1/31".parse().unwrap() - )])), - secrets: vec!["secret_key_01".to_string(), "secret_key_02".to_string()], - filter: FilterType::JsonFilter(JsonFilter { - pointer: "/ref".to_string(), - regex: Regex::new("refs/heads/master").unwrap(), - }), - } - ),]) - }) - .unwrap() - ); - } -} From 33e39f0b4092c8750e5360e595875162e2b3d81e Mon Sep 17 00:00:00 2001 From: finga Date: Fri, 19 Nov 2021 14:32:18 +0100 Subject: [PATCH 45/65] Improve readme and fix typos Improve wording and fix typos in readme. --- README.md | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 5689753..2464c09 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Webhookey Webhookey is a web server listening for requests as for example sent by -gitea's webhooks. Further, Webhookey allows you to specify rules +Gitea's webhooks. Further, Webhookey allows you to specify rules which are matched against the data received to trigger certain actions. @@ -62,7 +62,10 @@ Whereas `` depends on the platform: #### Metrics A metrics page can optionally enabled to query stats of the currently running webhookey instance. Note that stats are lost between restarts -of webhookey as those are not stored persistently. +of webhookey as those are not stored persistently. The `metrics` +structure is optional as well as the `ip_filter`. The `ip_filter` +supports either `allow` or `deny` containing a list of IPv4 and IPv6 +addresses and networks. Example: ```yaml @@ -127,25 +130,28 @@ Use values from header fields sent with the HTTP request. Example: `{{ header X-Gitea-Event }}`. -##### Allow and Deny -To allow or deny specific network ranges source is an optional -configuration parameter which either contains an allow or a deny field -with sequences containing networks. Note that IPv6 addresses have to -be put in single quotes due to the colons. +##### IP Filter +Specific IPv4 and IPv6 addresses and/or ranges ranges can be allowed +or denied. The `ip_filter` is optional and has to contain either an +`allow` or a `deny` field which contains a sequence of IPv4 or IPv6 +addresses or CIDR network ranges. Note that IPv6 addresses have to be +quoted due to the colons. Example: ```yaml -allow: - - 127.0.0.1 - - 127.0.0.1/31 - - "::1" +ip_filter: + allow: + - 127.0.0.1 + - 127.0.0.1/31 + - "::1" ``` ```yaml -deny: - - 127.0.0.1 - - 127.0.0.1/31 - - "::1" +ip_filter: + deny: + - 127.0.0.1 + - 127.0.0.1/31 + - "::1" ``` ##### Signature @@ -175,7 +181,7 @@ Conjunction filters contain lists of other filters. received http(s) request header. - `field`: The header field which should be matched. - - `regeq`: Regular expression which has to match the specified + - `regex`: Regular expression which has to match the specified header field. - `json`: From 506001a3661925ffa91c7fb21abc6dedb0657e28 Mon Sep 17 00:00:00 2001 From: finga Date: Mon, 22 Nov 2021 14:40:39 +0100 Subject: [PATCH 46/65] Improve error message Write a more correct error message. --- src/hooks.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hooks.rs b/src/hooks.rs index 5840524..1184555 100644 --- a/src/hooks.rs +++ b/src/hooks.rs @@ -103,7 +103,7 @@ impl Hook { ) })?, )?, - None => bail!("Missing expression in variable `{}`", token), + None => bail!("Invalid expression `{}`", token), }; command.push_str(&replaced); From c1b322bc5282990e2a1a5c32ff7f86fa42de8951 Mon Sep 17 00:00:00 2001 From: finga Date: Mon, 22 Nov 2021 14:42:38 +0100 Subject: [PATCH 47/65] Add link to webhooks wiki page to readme So that we have one thing which points to an explaination about what webhooks are. --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2464c09..b586e67 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # Webhookey -Webhookey is a web server listening for requests as for example sent by -Gitea's webhooks. Further, Webhookey allows you to specify rules +Webhookey is a web server listening for +[webhooks](https://en.wikipedia.org/wiki/Webhook) as for example sent +by Gitea's webhooks. Further, Webhookey allows you to specify rules which are matched against the data received to trigger certain actions. From 5f5d014bc00c8dc8731aa863f414e05ff5f68054 Mon Sep 17 00:00:00 2001 From: finga Date: Fri, 26 Nov 2021 10:58:37 +0100 Subject: [PATCH 48/65] Update build dependencies --- Cargo.lock | 120 ++++++++++++++--------------------------------------- 1 file changed, 32 insertions(+), 88 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9c1a7a8..0df1cf6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -22,9 +22,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.45" +version = "1.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee10e43ae4a853c0a3591d4e2ada1719e553be18199d9da9d4a83f5927c2f5c7" +checksum = "62e1f47f7dc0422027a4e370dd4548d4d66b26782e513e98dca1e689e058a80e" [[package]] name = "async-stream" @@ -141,18 +141,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -[[package]] -name = "chrono" -version = "0.4.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" -dependencies = [ - "libc", - "num-integer", - "num-traits", - "winapi", -] - [[package]] name = "clap" version = "3.0.0-beta.5" @@ -361,9 +349,9 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a12aa0eb539080d55c3f2d45a67c3b58b6b0773c1a3ca2dfec66d58c97fd66ca" +checksum = "8cd0210d8c325c245ff06fd95a3b13689a1a276ac8cfa8e8720cb840bfb84b9e" dependencies = [ "futures-channel", "futures-core", @@ -376,9 +364,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5da6ba8c3bb3c165d3c7319fc1cc8304facf1fb8db99c5de877183c08a273888" +checksum = "7fc8cd39e3dbf865f7340dce6a2d401d24fd37c6fe6c4f0ee0de8bfca2252d27" dependencies = [ "futures-core", "futures-sink", @@ -386,15 +374,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d1c26957f23603395cd326b0ffe64124b818f4449552f960d815cfba83a53d" +checksum = "629316e42fe7c2a0b9a65b47d159ceaa5453ab14e8f0a3c5eedbb8cd55b4a445" [[package]] name = "futures-executor" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45025be030969d763025784f7f355043dc6bc74093e4ecc5000ca4dc50d8745c" +checksum = "7b808bf53348a36cab739d7e04755909b9fcaaa69b7d7e588b37b6ec62704c97" dependencies = [ "futures-core", "futures-task", @@ -403,18 +391,16 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "522de2a0fe3e380f1bc577ba0474108faf3f6b18321dbf60b3b9c39a75073377" +checksum = "e481354db6b5c353246ccf6a728b0c5511d752c08da7260546fc0933869daa11" [[package]] name = "futures-macro" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18e4a4b95cea4b4ccbcf1c5675ca7c4ee4e9e75eb79944d07defde18068f79bb" +checksum = "a89f17b21645bc4ed773c69af9c9a0effd4a3f1a3876eadd453469f8854e7fdd" dependencies = [ - "autocfg", - "proc-macro-hack", "proc-macro2", "quote", "syn", @@ -422,23 +408,22 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36ea153c13024fe480590b3e3d4cad89a0cfacecc24577b68f86c6ced9c2bc11" +checksum = "996c6442437b62d21a32cd9906f9c41e7dc1e19a9579843fad948696769305af" [[package]] name = "futures-task" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d3d00f4eddb73e498a54394f228cd55853bdf059259e8e7bc6e69d408892e99" +checksum = "dabf1872aaab32c886832f2276d2f5399887e2bd613698a02359e4ea83f8de12" [[package]] name = "futures-util" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36568465210a3a6ee45e1f165136d68671471a501e632e9a98d96872222b5481" +checksum = "41d22213122356472061ac0f1ab2cee28d2bac8491410fd68c2af53d1cedb83e" dependencies = [ - "autocfg", "futures-channel", "futures-core", "futures-io", @@ -448,8 +433,6 @@ dependencies = [ "memchr", "pin-project-lite", "pin-utils", - "proc-macro-hack", - "proc-macro-nested", "slab", ] @@ -674,9 +657,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.107" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbe5e23404da5b4f555ef85ebed98fb4083e55a00c317800bc2a50ede9f3d219" +checksum = "8521a1b57e76b1ec69af7599e75e38e7b7fad6610f037db8c79b127201b5d119" [[package]] name = "linked-hash-map" @@ -704,9 +687,9 @@ dependencies = [ [[package]] name = "loom" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2b9df80a3804094bf49bb29881d18f6f05048db72127e84e09c26fc7c2324f5" +checksum = "5df2c4aeb432e60c9e5ae517ca8ed8b63556ce23093b2758fc8837d75439c5ec" dependencies = [ "cfg-if", "generator", @@ -719,9 +702,9 @@ dependencies = [ [[package]] name = "matchers" -version = "0.0.1" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f099785f7595cc4b4553a174ce30dd7589ef93391ff414dbb67f62392b9e0ce1" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" dependencies = [ "regex-automata", ] @@ -789,25 +772,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "num-integer" -version = "0.1.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" -dependencies = [ - "autocfg", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" -dependencies = [ - "autocfg", -] - [[package]] name = "num_cpus" version = "1.13.0" @@ -941,12 +905,6 @@ version = "0.5.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" -[[package]] -name = "proc-macro-nested" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" - [[package]] name = "proc-macro2" version = "1.0.32" @@ -1292,9 +1250,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.70" +version = "1.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e277c495ac6cd1a01a58d0a0c574568b4d1ddf14f59965c6a58b8d96400b54f3" +checksum = "d0ffa0837f2dfa6fb90868c2b5468cad482e175f7dad97e7421951e663f2b527" dependencies = [ "itoa", "ryu", @@ -1484,9 +1442,9 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "syn" -version = "1.0.81" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2afee18b8beb5a596ecb4a2dce128c719b4ba399d34126b9e4396e3f9860966" +checksum = "8daf5dd0bb60cbd4137b1b587d2fc0ae729bc07cf01cd70b36a1ed5ade3b9d59" dependencies = [ "proc-macro2", "quote", @@ -1716,36 +1674,22 @@ dependencies = [ "tracing-core", ] -[[package]] -name = "tracing-serde" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb65ea441fbb84f9f6748fd496cf7f63ec9af5bca94dd86456978d055e8eb28b" -dependencies = [ - "serde", - "tracing-core", -] - [[package]] name = "tracing-subscriber" -version = "0.2.25" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71" +checksum = "7507ec620f809cdf07cccb5bc57b13069a88031b795efd4079b1c71b66c1613d" dependencies = [ "ansi_term", - "chrono", "lazy_static", "matchers", "regex", - "serde", - "serde_json", "sharded-slab", "smallvec", "thread_local", "tracing", "tracing-core", "tracing-log", - "tracing-serde", ] [[package]] From 0f62ce701edcda39639453bf50128df919144b8f Mon Sep 17 00:00:00 2001 From: finga Date: Fri, 26 Nov 2021 11:44:59 +0100 Subject: [PATCH 49/65] Set server ident in headers Set server ident in headers to Webhookey. --- Rocket.toml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Rocket.toml diff --git a/Rocket.toml b/Rocket.toml new file mode 100644 index 0000000..ebb03f7 --- /dev/null +++ b/Rocket.toml @@ -0,0 +1,2 @@ +[default] +ident = "Webhookey" From 2c3319ad84f621f7b7bb3d360bf9c4e7092d04bf Mon Sep 17 00:00:00 2001 From: finga Date: Fri, 26 Nov 2021 11:59:47 +0100 Subject: [PATCH 50/65] Create the webhookey manpage Also add the manpage to the build recipe of the debian package. This closes #13. --- Cargo.toml | 1 + webhookey.1 | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 webhookey.1 diff --git a/Cargo.toml b/Cargo.toml index db4a136..c01a14d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,6 +37,7 @@ assets = [ ["config.yml", "etc/webhookey/", "644"], ["target/release/webhookey", "usr/bin/", "755"], ["README.md", "usr/share/doc/webhookey/README", "644"], + ["webhookey.1", "usr/share/man/man1/", "644"], ["debian/service", "lib/systemd/system/webhookey.service", "644"], ] conf-files = ["/etc/webhookey/config.yml"] diff --git a/webhookey.1 b/webhookey.1 new file mode 100644 index 0000000..e0ca688 --- /dev/null +++ b/webhookey.1 @@ -0,0 +1,57 @@ +.TH WEBHOOKEY 1 "26 Nov 2021" "webhookey" "Linux" +.SH NAME +webhookey \- Receive webhooks and act upon them +.SH SYNOPSIS +.B webhookey [OPTIONS] [SUBCOMMAND] +.SH DESCRIPTION +\fBwebhookey\fR receives http(s) requests in form of webhooks. Those +webhooks are matched against configured filters. If a filter matches, +a command (which can also incorporate data contained in the received +header or body) is executed. +.SH OPTIONS +.TP +.BR "-c", " --config " +Provide a path to the configuration file. +.TP +.BR "-h", " --help" +Print help information. +.TP +.BR "-V", " --version" +Print version information. +.SH SUBCOMMAND +.TP +.B configtest +- Verifies if the configuration can be parsed without errors. +.TP +.B help +- Print the general help message or the help of the given subcommand(s). +.SH ENVIRONMENT +.TP +.B ROCKET_ADDRESS +The IP address webhookey listens on (default: 127.0.0.1). +.TP +.B ROCKET_PORT +The port webhookey listens on (default: 8000). +.TP +.B ROCKET_WORKERS +The numbers of threads to use (default: CPU core count). +.TP +.B RUST_LOG +Set the Log level, which can be one one of "error", "warn", "info", +"debug", "trace" (default: "error"). +.SH EXAMPLES +.PP +webhookey configtest +.RS 4 +Return either "Config is OK" and return code 0 or an error description +and return code 1. +.RE +.PP +webhookey +.RS 4 +Start webhookey. +.RE +.SH REPORTING BUGS +To report any bugs file an issue at +https://git.onders.org/finga/webhookey/issues/new?template=bug.md or +send an email to . From 856cdc94571b70b60e0ae0a3953e450c09056da2 Mon Sep 17 00:00:00 2001 From: finga Date: Thu, 9 Dec 2021 13:40:17 +0100 Subject: [PATCH 51/65] Update build dependencies This needed also some adaption in order to use `clap 3.0.0-rc.0`. --- Cargo.lock | 79 +++++++++++++++++++++--------------------------------- Cargo.toml | 2 +- src/cli.rs | 7 ++--- 3 files changed, 35 insertions(+), 53 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0df1cf6..9108c94 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -22,9 +22,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.48" +version = "1.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62e1f47f7dc0422027a4e370dd4548d4d66b26782e513e98dca1e689e058a80e" +checksum = "8b26702f315f53b6071259e15dd9d64528213b44d61de1ec926eca7715d62203" [[package]] name = "async-stream" @@ -49,9 +49,9 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.51" +version = "0.1.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44318e776df68115a881de9a8fd1b9e53368d7a4a5ce4cc48517da3393233a5e" +checksum = "061a7acccaa286c011ddc30970520b98fa40e00c9d644633fb26b5fc63a265e3" dependencies = [ "proc-macro2", "quote", @@ -143,9 +143,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" -version = "3.0.0-beta.5" +version = "3.0.0-rc.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "feff3878564edb93745d58cf63e17b63f24142506e7a20c87a5521ed7bfb1d63" +checksum = "79b70f999da60e6619a29b131739d2211ed4d4301f40372e94a8081422e9d6c7" dependencies = [ "atty", "bitflags", @@ -156,14 +156,13 @@ dependencies = [ "strsim", "termcolor", "textwrap", - "unicase", ] [[package]] name = "clap_derive" -version = "3.0.0-beta.5" +version = "3.0.0-rc.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b15c6b4f786ffb6192ffe65a36855bc1fc2444bcd0945ae16748dcd6ed7d0d3" +checksum = "fe8c0f28022faaef0387fa54f8e33fee22b804a88bbd91303197da2ff8ca6a5d" dependencies = [ "heck", "proc-macro-error", @@ -296,9 +295,9 @@ checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" [[package]] name = "encoding_rs" -version = "0.8.29" +version = "0.8.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a74ea89a0a1b98f6332de42c95baff457ada66d1cb4030f9ff151b2041a1c746" +checksum = "7896dc8abb250ffdda33912550faa54c88ec8b998dec0b2c55ab224921ce11df" dependencies = [ "cfg-if", ] @@ -478,9 +477,9 @@ checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" [[package]] name = "h2" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fd819562fcebdac5afc5c113c3ec36f902840b70fd4fc458799c8ce4607ae55" +checksum = "8d09bbc040ce3758a0d32a8a910562104a853aea429dbe1a998beb065c2eacb2" dependencies = [ "bytes", "fnv", @@ -657,9 +656,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.108" +version = "0.2.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8521a1b57e76b1ec69af7599e75e38e7b7fad6610f037db8c79b127201b5d119" +checksum = "f98a04dce437184842841303488f70d0188c5f51437d2a834dc097eafa909a01" [[package]] name = "linked-hash-map" @@ -687,9 +686,9 @@ dependencies = [ [[package]] name = "loom" -version = "0.5.3" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5df2c4aeb432e60c9e5ae517ca8ed8b63556ce23093b2758fc8837d75439c5ec" +checksum = "edc5c7d328e32cc4954e8e01193d7f0ef5ab257b5090b70a964e099a36034309" dependencies = [ "cfg-if", "generator", @@ -796,9 +795,9 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "os_str_bytes" -version = "4.2.0" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "addaa943333a514159c80c97ff4a93306530d965d27e139188283cd13e06a799" +checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64" dependencies = [ "memchr", ] @@ -907,9 +906,9 @@ checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" [[package]] name = "proc-macro2" -version = "1.0.32" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43" +checksum = "fb37d2df5df740e582f28f8560cf425f52bb267d872fe58358eadb554909f07a" dependencies = [ "unicode-xid", ] @@ -1181,15 +1180,15 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61b3909d758bb75c79f23d4736fac9433868679d3ad2ea7a61e3c25cfda9a088" +checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f" [[package]] name = "ryu" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" +checksum = "3c9613b5a66ab9ba26415184cfc41156594925a9cf3a2057e57f31ff145f6568" [[package]] name = "scoped-tls" @@ -1230,18 +1229,18 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.130" +version = "1.0.131" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" +checksum = "b4ad69dfbd3e45369132cc64e6748c2d65cdfb001a2b1c232d128b4ad60561c1" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.130" +version = "1.0.131" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b" +checksum = "b710a83c4e0dff6a3d511946b95274ad9ca9e5d3ae497b63fda866ac955358d2" dependencies = [ "proc-macro2", "quote", @@ -1479,9 +1478,6 @@ name = "textwrap" version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80" -dependencies = [ - "unicode-width", -] [[package]] name = "thiserror" @@ -1676,9 +1672,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7507ec620f809cdf07cccb5bc57b13069a88031b795efd4079b1c71b66c1613d" +checksum = "245da694cc7fc4729f3f418b304cb57789f1bed2a78c575407ab8a23f53cb4d3" dependencies = [ "ansi_term", "lazy_static", @@ -1739,27 +1735,12 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eeba86d422ce181a719445e51872fa30f1f7413b62becb52e95ec91aa262d85c" -[[package]] -name = "unicase" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" -dependencies = [ - "version_check", -] - [[package]] name = "unicode-segmentation" version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" -[[package]] -name = "unicode-width" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" - [[package]] name = "unicode-xid" version = "0.2.2" diff --git a/Cargo.toml b/Cargo.toml index c01a14d..2eb75ad 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,7 @@ hex = "0.4" ipnet = { version = "2.3", features = ["serde"] } thiserror = "1.0" run_script = "0.9" -clap = "3.0.0-beta.5" +clap = { version = "3.0.0-rc.0", features = ["derive"] } [package.metadata.deb] extended-description = "Webhookey receives requests in form of a so called Webhook as for example sent by Gitea. Those requests are matched against configured filters, if a filter matches, values from the header and the body can be passed to scripts as parameters which are then executed subsequently." diff --git a/src/cli.rs b/src/cli.rs index 63c024d..f34a8b3 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -1,4 +1,4 @@ -use clap::{crate_authors, crate_version, AppSettings, Parser}; +use clap::{AppSettings, Parser}; #[derive(Debug, Parser)] pub enum Command { @@ -8,8 +8,9 @@ pub enum Command { #[derive(Debug, Parser)] #[clap( - version = crate_version!(), - author = crate_authors!(", "), + about, + version, + author, global_setting = AppSettings::InferSubcommands, global_setting = AppSettings::PropagateVersion, )] From 620fa520cea38235a55f74c05bcb24b5b684e03f Mon Sep 17 00:00:00 2001 From: finga Date: Thu, 9 Dec 2021 13:43:46 +0100 Subject: [PATCH 52/65] Raise version to 0.1.6 --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9108c94..34d0c75 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1851,7 +1851,7 @@ dependencies = [ [[package]] name = "webhookey" -version = "0.1.5" +version = "0.1.6" dependencies = [ "anyhow", "clap", diff --git a/Cargo.toml b/Cargo.toml index 2eb75ad..a1a890c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "webhookey" -version = "0.1.5" +version = "0.1.6" authors = ["finga "] edition = "2021" license = "GPL-3.0-or-later" From f7aea10c6bbf3e9ad8b4854b35c49058cd5121a2 Mon Sep 17 00:00:00 2001 From: finga Date: Tue, 14 Dec 2021 17:00:55 +0100 Subject: [PATCH 53/65] Update build dependencies --- Cargo.lock | 56 +++++++++++++++++++++++++++--------------------------- Cargo.toml | 2 +- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 34d0c75..0e43a3a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -143,9 +143,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" -version = "3.0.0-rc.0" +version = "3.0.0-rc.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79b70f999da60e6619a29b131739d2211ed4d4301f40372e94a8081422e9d6c7" +checksum = "967965e82fc46fee1a88147a7a977a66d615ed5f83eb95b18577b342c08f90ff" dependencies = [ "atty", "bitflags", @@ -160,9 +160,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "3.0.0-rc.0" +version = "3.0.0-rc.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe8c0f28022faaef0387fa54f8e33fee22b804a88bbd91303197da2ff8ca6a5d" +checksum = "85946d4034625800196413478a1c6d3a57c12785e1f3970e590e0137dfa07342" dependencies = [ "heck", "proc-macro-error", @@ -275,12 +275,6 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" -[[package]] -name = "dtoa" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0" - [[package]] name = "dunce" version = "1.0.2" @@ -477,9 +471,9 @@ checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" [[package]] name = "h2" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d09bbc040ce3758a0d32a8a910562104a853aea429dbe1a998beb065c2eacb2" +checksum = "8f072413d126e57991455e0a922b31e4c8ba7c2ffbebf6b78b4f8521397d65cd" dependencies = [ "bytes", "fnv", @@ -542,7 +536,7 @@ checksum = "1323096b05d41827dadeaee54c9981958c0f94e670bc94ed80037d1a7b8b186b" dependencies = [ "bytes", "fnv", - "itoa", + "itoa 0.4.8", ] [[package]] @@ -576,9 +570,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.15" +version = "0.14.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436ec0091e4f20e655156a30a0df3770fe2900aa301e548e08446ec794b6953c" +checksum = "b7ec3e62bdc98a2f0393a5048e4c30ef659440ea6e0e572965103e72bd836f55" dependencies = [ "bytes", "futures-channel", @@ -589,7 +583,7 @@ dependencies = [ "http-body", "httparse", "httpdate", - "itoa", + "itoa 0.4.8", "pin-project-lite", "socket2", "tokio", @@ -639,6 +633,12 @@ version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" +[[package]] +name = "itoa" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" + [[package]] name = "js-sys" version = "0.3.55" @@ -656,9 +656,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.109" +version = "0.2.112" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f98a04dce437184842841303488f70d0188c5f51437d2a834dc097eafa909a01" +checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125" [[package]] name = "linked-hash-map" @@ -783,9 +783,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" +checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5" [[package]] name = "opaque-debug" @@ -1186,9 +1186,9 @@ checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f" [[package]] name = "ryu" -version = "1.0.6" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c9613b5a66ab9ba26415184cfc41156594925a9cf3a2057e57f31ff145f6568" +checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" [[package]] name = "scoped-tls" @@ -1249,11 +1249,11 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.72" +version = "1.0.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0ffa0837f2dfa6fb90868c2b5468cad482e175f7dad97e7421951e663f2b527" +checksum = "bcbd0344bc6533bc7ec56df11d42fb70f1b912351c0825ccb7211b59d8af7cf5" dependencies = [ - "itoa", + "itoa 1.0.1", "ryu", "serde", ] @@ -1270,12 +1270,12 @@ dependencies = [ [[package]] name = "serde_yaml" -version = "0.8.21" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8c608a35705a5d3cdc9fbe403147647ff34b921f8e833e49306df898f9b20af" +checksum = "a4a521f2940385c165a24ee286aa8599633d162077a54bdcae2a6fd5a7bfa7a0" dependencies = [ - "dtoa", "indexmap", + "ryu", "serde", "yaml-rust", ] diff --git a/Cargo.toml b/Cargo.toml index a1a890c..d626c73 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,7 @@ hex = "0.4" ipnet = { version = "2.3", features = ["serde"] } thiserror = "1.0" run_script = "0.9" -clap = { version = "3.0.0-rc.0", features = ["derive"] } +clap = { version = "3.0.0-rc.4", features = ["derive"] } [package.metadata.deb] extended-description = "Webhookey receives requests in form of a so called Webhook as for example sent by Gitea. Those requests are matched against configured filters, if a filter matches, values from the header and the body can be passed to scripts as parameters which are then executed subsequently." From 0312a600edd5a0cc93bdc6c8526b46898a4963bf Mon Sep 17 00:00:00 2001 From: finga Date: Fri, 7 Jan 2022 11:49:16 +0100 Subject: [PATCH 54/65] Add `from` annotation to inherited errors --- src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main.rs b/src/main.rs index 65c64c4..a18261b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -23,9 +23,9 @@ pub enum WebhookeyError { #[error("Could not evaluate filter request")] InvalidFilter, #[error("IO Error")] - Io(std::io::Error), + Io(#[from] std::io::Error), #[error("Serde Error")] - Serde(serde_json::Error), + Serde(#[from] serde_json::Error), } pub fn get_string(data: &serde_json::Value) -> Result { From f195162ce5728f0ef76ba38cc3d4498530a90bc1 Mon Sep 17 00:00:00 2001 From: finga Date: Fri, 7 Jan 2022 11:50:52 +0100 Subject: [PATCH 55/65] Update build dependencies Use clap `v3.0`. --- Cargo.lock | 170 +++++++++++++++++++++++------------------------------ Cargo.toml | 2 +- 2 files changed, 73 insertions(+), 99 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0e43a3a..056b72b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -22,9 +22,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.51" +version = "1.0.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b26702f315f53b6071259e15dd9d64528213b44d61de1ec926eca7715d62203" +checksum = "84450d0b4a8bd1ba4144ce8ce718fbc5d071358b1e5384bace6536b3d1f2d5b3" [[package]] name = "async-stream" @@ -119,9 +119,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.8.0" +version = "3.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c" +checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" [[package]] name = "bytes" @@ -143,9 +143,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" -version = "3.0.0-rc.4" +version = "3.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "967965e82fc46fee1a88147a7a977a66d615ed5f83eb95b18577b342c08f90ff" +checksum = "f6f34b09b9ee8c7c7b400fe2f8df39cafc9538b03d6ba7f4ae13e4cb90bfbb7d" dependencies = [ "atty", "bitflags", @@ -160,9 +160,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "3.0.0-rc.4" +version = "3.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85946d4034625800196413478a1c6d3a57c12785e1f3970e590e0137dfa07342" +checksum = "41a0645a430ec9136d2d701e54a95d557de12649a9dd7109ced3187e648ac824" dependencies = [ "heck", "proc-macro-error", @@ -173,9 +173,9 @@ dependencies = [ [[package]] name = "const_fn" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f92cfa0fd5690b3cf8c1ef2cabbd9b7ef22fa53cf5e1f92b05103f6d5d1cf6e7" +checksum = "fbdcdcb6d86f71c5e97409ad45898af11cbc995b4ee8112d59095a28d376c935" [[package]] name = "cookie" @@ -342,9 +342,9 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.18" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cd0210d8c325c245ff06fd95a3b13689a1a276ac8cfa8e8720cb840bfb84b9e" +checksum = "28560757fe2bb34e79f907794bb6b22ae8b0e5c669b638a1132f2592b19035b4" dependencies = [ "futures-channel", "futures-core", @@ -357,9 +357,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.18" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fc8cd39e3dbf865f7340dce6a2d401d24fd37c6fe6c4f0ee0de8bfca2252d27" +checksum = "ba3dda0b6588335f360afc675d0564c17a77a2bda81ca178a4b6081bd86c7f0b" dependencies = [ "futures-core", "futures-sink", @@ -367,15 +367,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.18" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "629316e42fe7c2a0b9a65b47d159ceaa5453ab14e8f0a3c5eedbb8cd55b4a445" +checksum = "d0c8ff0461b82559810cdccfde3215c3f373807f5e5232b71479bff7bb2583d7" [[package]] name = "futures-executor" -version = "0.3.18" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b808bf53348a36cab739d7e04755909b9fcaaa69b7d7e588b37b6ec62704c97" +checksum = "29d6d2ff5bb10fb95c85b8ce46538a2e5f5e7fdc755623a7d4529ab8a4ed9d2a" dependencies = [ "futures-core", "futures-task", @@ -384,15 +384,15 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.18" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e481354db6b5c353246ccf6a728b0c5511d752c08da7260546fc0933869daa11" +checksum = "b1f9d34af5a1aac6fb380f735fe510746c38067c5bf16c7fd250280503c971b2" [[package]] name = "futures-macro" -version = "0.3.18" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a89f17b21645bc4ed773c69af9c9a0effd4a3f1a3876eadd453469f8854e7fdd" +checksum = "6dbd947adfffb0efc70599b3ddcf7b5597bb5fa9e245eb99f62b3a5f7bb8bd3c" dependencies = [ "proc-macro2", "quote", @@ -401,21 +401,21 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.18" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "996c6442437b62d21a32cd9906f9c41e7dc1e19a9579843fad948696769305af" +checksum = "e3055baccb68d74ff6480350f8d6eb8fcfa3aa11bdc1a1ae3afdd0514617d508" [[package]] name = "futures-task" -version = "0.3.18" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dabf1872aaab32c886832f2276d2f5399887e2bd613698a02359e4ea83f8de12" +checksum = "6ee7c6485c30167ce4dfb83ac568a849fe53274c831081476ee13e0dce1aad72" [[package]] name = "futures-util" -version = "0.3.18" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d22213122356472061ac0f1ab2cee28d2bac8491410fd68c2af53d1cedb83e" +checksum = "d9b5cf40b47a271f77a8b1bec03ca09044d99d2372c0de244e66430761127164" dependencies = [ "futures-channel", "futures-core", @@ -444,9 +444,9 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.14.4" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" +checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" dependencies = [ "typenum", "version_check", @@ -471,9 +471,9 @@ checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" [[package]] name = "h2" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f072413d126e57991455e0a922b31e4c8ba7c2ffbebf6b78b4f8521397d65cd" +checksum = "0c9de88456263e249e241fcd211d3954e2c9b0ef7ccfc235a444eb367cae3689" dependencies = [ "bytes", "fnv", @@ -496,12 +496,9 @@ checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" [[package]] name = "heck" -version = "0.3.3" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" -dependencies = [ - "unicode-segmentation", -] +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" [[package]] name = "hermit-abi" @@ -530,13 +527,13 @@ dependencies = [ [[package]] name = "http" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1323096b05d41827dadeaee54c9981958c0f94e670bc94ed80037d1a7b8b186b" +checksum = "31f4c6746584866f0feabcc69893c5b51beef3831656a968ed7ae254cdc4fd03" dependencies = [ "bytes", "fnv", - "itoa 0.4.8", + "itoa 1.0.1", ] [[package]] @@ -605,9 +602,9 @@ dependencies = [ [[package]] name = "inlinable_string" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3094308123a0e9fd59659ce45e22de9f53fc1d2ac6e1feb9fef988e4f76cad77" +checksum = "c8fae54786f62fb2918dcfae3d568594e50eb9b5c25bf04371af6fe7516452fb" [[package]] name = "instant" @@ -744,9 +741,9 @@ dependencies = [ [[package]] name = "multer" -version = "2.0.1" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "408327e2999b839cd1af003fc01b2019a6c10a1361769542203f6fedc5179680" +checksum = "5f8f35e687561d5c1667590911e6698a8cb714a134a7505718a182e7bc9d3836" dependencies = [ "bytes", "encoding_rs", @@ -754,11 +751,11 @@ dependencies = [ "http", "httparse", "log", + "memchr", "mime", "spin 0.9.2", "tokio", "tokio-util", - "twoway", "version_check", ] @@ -773,9 +770,9 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.13.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" dependencies = [ "hermit-abi", "libc", @@ -858,9 +855,9 @@ checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" [[package]] name = "pin-project-lite" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443" +checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c" [[package]] name = "pin-utils" @@ -870,9 +867,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "ppv-lite86" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba" +checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" [[package]] name = "proc-macro-error" @@ -906,9 +903,9 @@ checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" [[package]] name = "proc-macro2" -version = "1.0.33" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb37d2df5df740e582f28f8560cf425f52bb267d872fe58358eadb554909f07a" +checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" dependencies = [ "unicode-xid", ] @@ -928,9 +925,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.10" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" +checksum = "47aa80447ce4daf1717500037052af176af5d38cc3e571d9ec1c7353fc10c87d" dependencies = [ "proc-macro2", ] @@ -1229,18 +1226,18 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.131" +version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4ad69dfbd3e45369132cc64e6748c2d65cdfb001a2b1c232d128b4ad60561c1" +checksum = "97565067517b60e2d1ea8b268e59ce036de907ac523ad83a0475da04e818989a" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.131" +version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b710a83c4e0dff6a3d511946b95274ad9ca9e5d3ae497b63fda866ac955358d2" +checksum = "ed201699328568d8d08208fdd080e3ff594e6c422e438b6705905da01005d537" dependencies = [ "proc-macro2", "quote", @@ -1249,9 +1246,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.73" +version = "1.0.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcbd0344bc6533bc7ec56df11d42fb70f1b912351c0825ccb7211b59d8af7cf5" +checksum = "ee2bb9cd061c5865d345bb02ca49fcef1391741b672b54a0bf7b679badec3142" dependencies = [ "itoa 1.0.1", "ryu", @@ -1288,9 +1285,9 @@ checksum = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" [[package]] name = "sha2" -version = "0.9.8" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b69f9a4c9740d74c5baa3fd2e547f9525fa8088a8a958e0ca2409a514e33f5fa" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" dependencies = [ "block-buffer", "cfg-if", @@ -1441,9 +1438,9 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "syn" -version = "1.0.82" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8daf5dd0bb60cbd4137b1b587d2fc0ae729bc07cf01cd70b36a1ed5ade3b9d59" +checksum = "a684ac3dcd8913827e18cd09a68384ee66c1de24157e3c556c9ab16d85695fb7" dependencies = [ "proc-macro2", "quote", @@ -1548,11 +1545,10 @@ dependencies = [ [[package]] name = "tokio" -version = "1.14.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70e992e41e0d2fb9f755b37446f20900f64446ef54874f40a60c78f021ac6144" +checksum = "fbbf1c778ec206785635ce8ad57fe52b3009ae9e0c9f574a728f3049d3e55838" dependencies = [ - "autocfg", "bytes", "libc", "memchr", @@ -1567,9 +1563,9 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9efc1aba077437943f7515666aa2b882dfabfbfdf89c819ea75a8d6e9eaba5e" +checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7" dependencies = [ "proc-macro2", "quote", @@ -1672,9 +1668,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.3" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245da694cc7fc4729f3f418b304cb57789f1bed2a78c575407ab8a23f53cb4d3" +checksum = "5d81bfa81424cc98cb034b837c985b7a290f592e5b4322f353f94a0ab0f9f594" dependencies = [ "ansi_term", "lazy_static", @@ -1694,21 +1690,11 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" -[[package]] -name = "twoway" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c57ffb460d7c24cd6eda43694110189030a3d1dfe418416d9468fd1c1d290b47" -dependencies = [ - "memchr", - "unchecked-index", -] - [[package]] name = "typenum" -version = "1.14.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" [[package]] name = "ubyte" @@ -1729,18 +1715,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "unchecked-index" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eeba86d422ce181a719445e51872fa30f1f7413b62becb52e95ec91aa262d85c" - -[[package]] -name = "unicode-segmentation" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" - [[package]] name = "unicode-xid" version = "0.2.2" @@ -1765,9 +1739,9 @@ dependencies = [ [[package]] name = "version_check" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "want" diff --git a/Cargo.toml b/Cargo.toml index d626c73..86f09ec 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,7 @@ hex = "0.4" ipnet = { version = "2.3", features = ["serde"] } thiserror = "1.0" run_script = "0.9" -clap = { version = "3.0.0-rc.4", features = ["derive"] } +clap = { version = "3.0", features = ["derive"] } [package.metadata.deb] extended-description = "Webhookey receives requests in form of a so called Webhook as for example sent by Gitea. Those requests are matched against configured filters, if a filter matches, values from the header and the body can be passed to scripts as parameters which are then executed subsequently." From 81be79d46d891dea906b3ef1b3e797b64a96c8ce Mon Sep 17 00:00:00 2001 From: finga Date: Thu, 10 Feb 2022 00:28:47 +0100 Subject: [PATCH 56/65] ci: Add a basic ci config Do things like build docs, check fmt, clippy and build in non-release and release mode as well as the debian package. Include a badge which reflects the status of the ci for the main branch to the readme. --- .woodpecker.yml | 29 +++++++++++++++++++++++++++++ README.md | 2 ++ 2 files changed, 31 insertions(+) create mode 100644 .woodpecker.yml diff --git a/.woodpecker.yml b/.woodpecker.yml new file mode 100644 index 0000000..1fe79b8 --- /dev/null +++ b/.woodpecker.yml @@ -0,0 +1,29 @@ +pipeline: + doc: + image: rust + commands: + - cargo doc + + fmt: + image: rust + commands: + - rustup component add rustfmt + - cargo fmt --all -- --check + + clippy: + image: rust + commands: + - rustup component add clippy + - cargo clippy --all-features + + build: + image: rust + commands: + - cargo build + - cargo build --release + + build-deb: + image: rust + commands: + - cargo install cargo-deb + - cargo deb diff --git a/README.md b/README.md index b586e67..c48045a 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,6 @@ # Webhookey +![status-badge](https://ci.onders.org/api/badges/finga/webhookey/status.svg?branch=main) + Webhookey is a web server listening for [webhooks](https://en.wikipedia.org/wiki/Webhook) as for example sent by Gitea's webhooks. Further, Webhookey allows you to specify rules From 976c25ba1a58da60706897d0923dafaa931f5030 Mon Sep 17 00:00:00 2001 From: finga Date: Thu, 10 Feb 2022 01:38:37 +0100 Subject: [PATCH 57/65] ci: Also execute the tests during ci --- .woodpecker.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.woodpecker.yml b/.woodpecker.yml index 1fe79b8..327b799 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -16,6 +16,11 @@ pipeline: - rustup component add clippy - cargo clippy --all-features + test: + image: rust + commands: + - cargo test + build: image: rust commands: From f25ee6b943eb988e1f8a312f6f40c4afca1d6855 Mon Sep 17 00:00:00 2001 From: finga Date: Fri, 11 Feb 2022 19:52:09 +0100 Subject: [PATCH 58/65] ci: run everything in pipeline in parallel --- .woodpecker.yml | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/.woodpecker.yml b/.woodpecker.yml index 327b799..32d2fe4 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -1,34 +1,40 @@ pipeline: - doc: - image: rust - commands: - - cargo doc - fmt: + group: default image: rust commands: - rustup component add rustfmt - cargo fmt --all -- --check clippy: + group: default image: rust commands: - rustup component add clippy - cargo clippy --all-features test: + group: default image: rust commands: - cargo test build: + group: default image: rust commands: - cargo build - cargo build --release build-deb: + group: default image: rust commands: - cargo install cargo-deb - cargo deb + + doc: + group: default + image: rust + commands: + - cargo doc From f38c70373c6aa14b07f1f0862a0795dfacfb1bc8 Mon Sep 17 00:00:00 2001 From: finga Date: Wed, 23 Mar 2022 14:46:00 +0100 Subject: [PATCH 59/65] metrics: Increase `hooks_successful` when done --- src/hooks.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/hooks.rs b/src/hooks.rs index 1184555..2429dca 100644 --- a/src/hooks.rs +++ b/src/hooks.rs @@ -315,6 +315,8 @@ pub async fn receive_hook<'a>( .fetch_add(1, Ordering::Relaxed); } } + + metrics.hooks_successful.fetch_add(1, Ordering::Relaxed); }); Status::Ok From 55c5134840b160b5e558e2f774cb1f5fe0e15391 Mon Sep 17 00:00:00 2001 From: finga Date: Sat, 15 Oct 2022 01:56:07 +0200 Subject: [PATCH 60/65] ci: Update CI config --- .woodpecker.yml | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/.woodpecker.yml b/.woodpecker.yml index 32d2fe4..19c16b4 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -1,40 +1,37 @@ pipeline: fmt: group: default - image: rust + image: rust_full commands: - - rustup component add rustfmt - cargo fmt --all -- --check clippy: group: default - image: rust + image: rust_full commands: - - rustup component add clippy - cargo clippy --all-features test: group: default - image: rust + image: rust_full commands: - cargo test build: group: default - image: rust + image: rust_full commands: - cargo build - cargo build --release build-deb: group: default - image: rust + image: rust_full commands: - - cargo install cargo-deb - cargo deb doc: group: default - image: rust + image: rust_full commands: - cargo doc From f6ec8af9444fc268fe7d786bdbc40a65460af128 Mon Sep 17 00:00:00 2001 From: finga Date: Sun, 11 Jun 2023 15:08:42 +0200 Subject: [PATCH 61/65] clippy: Fix `clippy::get_first` Fix the `clippy::get_first` lint. Note clippy fails due to a false positive. --- src/hooks.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hooks.rs b/src/hooks.rs index 2429dca..b51a47f 100644 --- a/src/hooks.rs +++ b/src/hooks.rs @@ -87,7 +87,7 @@ impl Hook { if let Some('}') = command_template.next() { let expr = token.trim().split(' ').collect::>(); - let replaced = match expr.get(0) { + let replaced = match expr.first() { Some(&"header") => get_header_field( headers, expr.get(1).ok_or_else(|| { From 71153b28ec03a42762ffaf8cd766ce4d79729bc7 Mon Sep 17 00:00:00 2001 From: finga Date: Sat, 10 Jun 2023 22:19:13 +0200 Subject: [PATCH 62/65] cargo: Order dependencies alphabetically To improve readability of dependencies order them alphabetically. --- Cargo.toml | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 86f09ec..159acbd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,23 +11,23 @@ description = "Trigger scripts via http(s) requests" tls = ["rocket/tls"] [dependencies] +anyhow = "1.0" +clap = { version = "3.0", features = ["derive"] } +dirs = "4.0" +env_logger = "0.9" +hex = "0.4" +hmac = "0.11" +ipnet = { version = "2.3", features = ["serde"] } +log = "0.4" +regex = "1.5" rocket = "0.5.0-rc.1" +run_script = "0.9" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" -serde_yaml = "0.8" serde_regex = "1.1" -regex = "1.5" -dirs = "4.0" -anyhow = "1.0" -log = "0.4" -env_logger = "0.9" -hmac = "0.11" +serde_yaml = "0.8" sha2 = "0.9" -hex = "0.4" -ipnet = { version = "2.3", features = ["serde"] } thiserror = "1.0" -run_script = "0.9" -clap = { version = "3.0", features = ["derive"] } [package.metadata.deb] extended-description = "Webhookey receives requests in form of a so called Webhook as for example sent by Gitea. Those requests are matched against configured filters, if a filter matches, values from the header and the body can be passed to scripts as parameters which are then executed subsequently." From 35b31b2a152f13575d3592debc455cedaf9be723 Mon Sep 17 00:00:00 2001 From: finga Date: Sun, 11 Jun 2023 14:30:15 +0200 Subject: [PATCH 63/65] cargo: Cargo update Update the build dependencies by `cargo update`. --- Cargo.lock | 1127 ++++++++++++++++++++++++++++------------------------ 1 file changed, 598 insertions(+), 529 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 056b72b..36e409c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,68 +4,57 @@ version = 3 [[package]] name = "aho-corasick" -version = "0.7.18" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" dependencies = [ "memchr", ] -[[package]] -name = "ansi_term" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" -dependencies = [ - "winapi", -] - [[package]] name = "anyhow" -version = "1.0.52" +version = "1.0.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84450d0b4a8bd1ba4144ce8ce718fbc5d071358b1e5384bace6536b3d1f2d5b3" +checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" [[package]] name = "async-stream" -version = "0.3.2" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "171374e7e3b2504e0e5236e3b59260560f9fe94bfe9ac39ba5e4e929c5590625" +checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" dependencies = [ "async-stream-impl", "futures-core", + "pin-project-lite", ] [[package]] name = "async-stream-impl" -version = "0.3.2" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "648ed8c8d2ce5409ccd57453d9d1b214b342a0d69376a6feda1fd6cae3299308" +checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.18", ] [[package]] name = "async-trait" -version = "0.1.52" +version = "0.1.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "061a7acccaa286c011ddc30970520b98fa40e00c9d644633fb26b5fc63a265e3" +checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.18", ] [[package]] name = "atomic" -version = "0.5.1" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b88d82667eca772c4aa12f0f1348b3ae643424c8876448f3f7bd5787032e234c" -dependencies = [ - "autocfg", -] +checksum = "c59bdb34bc650a32731b31bd8f0829cc15d24a708ee31559e0bb34f2bc320cba" [[package]] name = "atty" @@ -73,28 +62,22 @@ version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ - "hermit-abi", + "hermit-abi 0.1.19", "libc", "winapi", ] [[package]] name = "autocfg" -version = "1.0.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" - -[[package]] -name = "base-x" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4521f3e3d031370679b3b140beb36dfe4801b09ac77e30c61941f97df3ef28b" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "base64" -version = "0.13.0" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" +checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" [[package]] name = "binascii" @@ -108,6 +91,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6776fc96284a0bb647b615056fc496d1fe1644a7ab01829818a6d91cae888b84" + [[package]] name = "block-buffer" version = "0.9.0" @@ -119,21 +108,21 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.9.1" +version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" +checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" [[package]] name = "bytes" -version = "1.1.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" +checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" [[package]] name = "cc" -version = "1.0.72" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" [[package]] name = "cfg-if" @@ -143,16 +132,16 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" -version = "3.0.5" +version = "3.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f34b09b9ee8c7c7b400fe2f8df39cafc9538b03d6ba7f4ae13e4cb90bfbb7d" +checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" dependencies = [ "atty", - "bitflags", + "bitflags 1.3.2", "clap_derive", + "clap_lex", "indexmap", - "lazy_static", - "os_str_bytes", + "once_cell", "strsim", "termcolor", "textwrap", @@ -160,28 +149,31 @@ dependencies = [ [[package]] name = "clap_derive" -version = "3.0.5" +version = "3.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41a0645a430ec9136d2d701e54a95d557de12649a9dd7109ced3187e648ac824" +checksum = "ae6371b8bdc8b7d3959e9cf7b22d4435ef3e79e138688421ec654acf8c81b008" dependencies = [ "heck", "proc-macro-error", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] -name = "const_fn" -version = "0.4.9" +name = "clap_lex" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbdcdcb6d86f71c5e97409ad45898af11cbc995b4ee8112d59095a28d376c935" +checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +dependencies = [ + "os_str_bytes", +] [[package]] name = "cookie" -version = "0.15.1" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f1c7727e460397e56abc4bddc1d49e07a1ad78fc98eb2e1c8f032a58a2f80d" +checksum = "7efb37c3e1ccb1ff97164ad95ac1606e8ccd35b3fa0a7d99a304c7f4a428cc24" dependencies = [ "percent-encoding", "time", @@ -190,9 +182,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.1" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469" +checksum = "3e4c1eaa2012c47becbbad2ab175484c2a84d1185b566fb2cc5b8707343dfe58" dependencies = [ "libc", ] @@ -209,9 +201,9 @@ dependencies = [ [[package]] name = "devise" -version = "0.3.1" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50c7580b072f1c8476148f16e0a0d5dedddab787da98d86c5082c5e9ed8ab595" +checksum = "d6eacefd3f541c66fc61433d65e54e0e46e0a029a819a7dbbc7a7b489e8a85f8" dependencies = [ "devise_codegen", "devise_core", @@ -219,9 +211,9 @@ dependencies = [ [[package]] name = "devise_codegen" -version = "0.3.1" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "123c73e7a6e51b05c75fe1a1b2f4e241399ea5740ed810b0e3e6cacd9db5e7b2" +checksum = "9c8cf4b8dd484ede80fd5c547592c46c3745a617c8af278e2b72bea86b2dfed6" dependencies = [ "devise_core", "quote", @@ -229,15 +221,15 @@ dependencies = [ [[package]] name = "devise_core" -version = "0.3.1" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "841ef46f4787d9097405cac4e70fb8644fc037b526e8c14054247c0263c400d0" +checksum = "35b50dba0afdca80b187392b24f2499a88c336d5a8493e4b4ccfb608708be56a" dependencies = [ - "bitflags", + "bitflags 2.3.1", "proc-macro2", "proc-macro2-diagnostics", "quote", - "syn", + "syn 2.0.18", ] [[package]] @@ -260,9 +252,9 @@ dependencies = [ [[package]] name = "dirs-sys" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780" +checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" dependencies = [ "libc", "redox_users", @@ -270,37 +262,31 @@ dependencies = [ ] [[package]] -name = "discard" +name = "dunce" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" - -[[package]] -name = "dunce" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453440c271cf5577fd2a40e4942540cb7d0d2f85e27c8d07dd0023c925a67541" +checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" [[package]] name = "either" -version = "1.6.1" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" [[package]] name = "encoding_rs" -version = "0.8.30" +version = "0.8.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dc8abb250ffdda33912550faa54c88ec8b998dec0b2c55ab224921ce11df" +checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" dependencies = [ "cfg-if", ] [[package]] name = "env_logger" -version = "0.9.0" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3" +checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" dependencies = [ "atty", "humantime", @@ -310,10 +296,40 @@ dependencies = [ ] [[package]] -name = "figment" -version = "0.10.6" +name = "errno" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "790b4292c72618abbab50f787a477014fe15634f96291de45672ce46afe122df" +checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +dependencies = [ + "errno-dragonfly", + "libc", + "windows-sys", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "fastrand" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +dependencies = [ + "instant", +] + +[[package]] +name = "figment" +version = "0.10.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4547e226f4c9ab860571e070a9034192b3175580ecea38da34fcdb53a018c9a5" dependencies = [ "atomic", "pear", @@ -331,24 +347,22 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "fsio" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09e87827efaf94c7a44b562ff57de06930712fe21b530c3797cdede26e6377eb" +checksum = "de6fce87c901c64837f745e7fffddeca1de8e054b544ba82c419905d40a0e1be" dependencies = [ "dunce", "rand", - "users", ] [[package]] name = "futures" -version = "0.3.19" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28560757fe2bb34e79f907794bb6b22ae8b0e5c669b638a1132f2592b19035b4" +checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" dependencies = [ "futures-channel", "futures-core", - "futures-executor", "futures-io", "futures-sink", "futures-task", @@ -357,9 +371,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.19" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3dda0b6588335f360afc675d0564c17a77a2bda81ca178a4b6081bd86c7f0b" +checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" dependencies = [ "futures-core", "futures-sink", @@ -367,60 +381,37 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.19" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0c8ff0461b82559810cdccfde3215c3f373807f5e5232b71479bff7bb2583d7" - -[[package]] -name = "futures-executor" -version = "0.3.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29d6d2ff5bb10fb95c85b8ce46538a2e5f5e7fdc755623a7d4529ab8a4ed9d2a" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] +checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" [[package]] name = "futures-io" -version = "0.3.19" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f9d34af5a1aac6fb380f735fe510746c38067c5bf16c7fd250280503c971b2" - -[[package]] -name = "futures-macro" -version = "0.3.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dbd947adfffb0efc70599b3ddcf7b5597bb5fa9e245eb99f62b3a5f7bb8bd3c" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] +checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" [[package]] name = "futures-sink" -version = "0.3.19" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3055baccb68d74ff6480350f8d6eb8fcfa3aa11bdc1a1ae3afdd0514617d508" +checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" [[package]] name = "futures-task" -version = "0.3.19" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ee7c6485c30167ce4dfb83ac568a849fe53274c831081476ee13e0dce1aad72" +checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" [[package]] name = "futures-util" -version = "0.3.19" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b5cf40b47a271f77a8b1bec03ca09044d99d2372c0de244e66430761127164" +checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" dependencies = [ "futures-channel", "futures-core", "futures-io", - "futures-macro", "futures-sink", "futures-task", "memchr", @@ -431,22 +422,22 @@ dependencies = [ [[package]] name = "generator" -version = "0.7.0" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1d9279ca822891c1a4dae06d185612cf8fc6acfe5dff37781b41297811b12ee" +checksum = "f3e123d9ae7c02966b4d892e550bdc32164f05853cd40ab570650ad600596a8a" dependencies = [ "cc", "libc", "log", "rustversion", - "winapi", + "windows", ] [[package]] name = "generic-array" -version = "0.14.5" +version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", @@ -454,9 +445,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.3" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ "cfg-if", "libc", @@ -465,15 +456,15 @@ dependencies = [ [[package]] name = "glob" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "h2" -version = "0.3.10" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c9de88456263e249e241fcd211d3954e2c9b0ef7ccfc235a444eb367cae3689" +checksum = "d357c7ae988e7d2182f7d7871d0b963962420b0678b0997ce7de72001aeab782" dependencies = [ "bytes", "fnv", @@ -490,15 +481,15 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.11.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "heck" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" @@ -509,6 +500,21 @@ dependencies = [ "libc", ] +[[package]] +name = "hermit-abi" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" + [[package]] name = "hex" version = "0.4.3" @@ -527,20 +533,20 @@ dependencies = [ [[package]] name = "http" -version = "0.2.6" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f4c6746584866f0feabcc69893c5b51beef3831656a968ed7ae254cdc4fd03" +checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" dependencies = [ "bytes", "fnv", - "itoa 1.0.1", + "itoa", ] [[package]] name = "http-body" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ff4f84919677303da5f147645dbea6b1881f368d03ac84e1dc09031ebd7b2c6" +checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" dependencies = [ "bytes", "http", @@ -549,9 +555,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.5.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acd94fdbe1d4ff688b67b04eee2e17bd50995534a61539e45adfefb45e5e5503" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" [[package]] name = "httpdate" @@ -567,9 +573,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.16" +version = "0.14.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7ec3e62bdc98a2f0393a5048e4c30ef659440ea6e0e572965103e72bd836f55" +checksum = "ab302d72a6f11a3b910431ff93aae7e773078c769f0a3ef15fb9ec692ed147d4" dependencies = [ "bytes", "futures-channel", @@ -580,7 +586,7 @@ dependencies = [ "http-body", "httparse", "httpdate", - "itoa 0.4.8", + "itoa", "pin-project-lite", "socket2", "tokio", @@ -591,9 +597,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.7.0" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", "hashbrown", @@ -616,31 +622,48 @@ dependencies = [ ] [[package]] -name = "ipnet" -version = "2.3.1" +name = "io-lifetimes" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68f2d64f2edebec4ce84ad108148e67e1064789bee435edc5b60ad398714a3a9" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +dependencies = [ + "hermit-abi 0.3.1", + "libc", + "windows-sys", +] + +[[package]] +name = "ipnet" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12b6ee2129af8d4fb011108c73d99a1b83a85977f23b82460c0ae2e25bb4b57f" dependencies = [ "serde", ] [[package]] -name = "itoa" -version = "0.4.8" +name = "is-terminal" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" +checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" +dependencies = [ + "hermit-abi 0.3.1", + "io-lifetimes", + "rustix", + "windows-sys", +] [[package]] name = "itoa" -version = "1.0.1" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" +checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" [[package]] name = "js-sys" -version = "0.3.55" +version = "0.3.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cc9ffccd38c451a86bf13657df244e9c3f37493cce8e5e21e940963777acc84" +checksum = "2f37a4a5928311ac501dee68b3c7613a1037d0edb30c8e5427bd832d55d1b790" dependencies = [ "wasm-bindgen", ] @@ -653,39 +676,43 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.112" +version = "0.2.146" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125" +checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b" [[package]] name = "linked-hash-map" -version = "0.5.4" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + +[[package]] +name = "linux-raw-sys" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] name = "lock_api" -version = "0.4.5" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" +checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" dependencies = [ + "autocfg", "scopeguard", ] [[package]] name = "log" -version = "0.4.14" +version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" -dependencies = [ - "cfg-if", -] +checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" [[package]] name = "loom" -version = "0.5.4" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edc5c7d328e32cc4954e8e01193d7f0ef5ab257b5090b70a964e099a36034309" +checksum = "ff50ecb28bb86013e935fb6683ab1f6d3a20016f123c76fd4c27470076ac30f5" dependencies = [ "cfg-if", "generator", @@ -707,43 +734,32 @@ dependencies = [ [[package]] name = "memchr" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "mime" -version = "0.3.16" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "mio" -version = "0.7.14" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8067b404fe97c70829f082dec8bcf4f71225d7eaea1d8645349cb76fa06205cc" +checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" dependencies = [ "libc", - "log", - "miow", - "ntapi", - "winapi", -] - -[[package]] -name = "miow" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" -dependencies = [ - "winapi", + "wasi", + "windows-sys", ] [[package]] name = "multer" -version = "2.0.2" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f8f35e687561d5c1667590911e6698a8cb714a134a7505718a182e7bc9d3836" +checksum = "01acbdc23469fd8fe07ab135923371d5f5a422fbf9c522158677c8eb15bc51c2" dependencies = [ "bytes", "encoding_rs", @@ -753,36 +769,37 @@ dependencies = [ "log", "memchr", "mime", - "spin 0.9.2", + "spin 0.9.8", "tokio", "tokio-util", "version_check", ] [[package]] -name = "ntapi" -version = "0.3.6" +name = "nu-ansi-term" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" dependencies = [ + "overload", "winapi", ] [[package]] name = "num_cpus" -version = "1.13.1" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" dependencies = [ - "hermit-abi", + "hermit-abi 0.2.6", "libc", ] [[package]] name = "once_cell" -version = "1.9.0" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "opaque-debug" @@ -792,43 +809,44 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "os_str_bytes" -version = "6.0.0" +version = "6.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64" -dependencies = [ - "memchr", -] +checksum = "4d5d9eb14b174ee9aa2ef96dc2b94637a2d4b6e7cb873c7e171f0c20c6cf3eac" + +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] name = "parking_lot" -version = "0.11.2" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ - "instant", "lock_api", "parking_lot_core", ] [[package]] name = "parking_lot_core" -version = "0.8.5" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" +checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" dependencies = [ "cfg-if", - "instant", "libc", - "redox_syscall", + "redox_syscall 0.3.5", "smallvec", - "winapi", + "windows-targets", ] [[package]] name = "pear" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15e44241c5e4c868e3eaa78b7c1848cadd6344ed4f54d029832d32b415a58702" +checksum = "0ec95680a7087503575284e5063e14b694b7a9c0b065e5dceec661e0497127e8" dependencies = [ "inlinable_string", "pear_codegen", @@ -837,27 +855,27 @@ dependencies = [ [[package]] name = "pear_codegen" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82a5ca643c2303ecb740d506539deba189e16f2754040a42901cd8105d0282d0" +checksum = "9661a3a53f93f09f2ea882018e4d7c88f6ff2956d809a276060476fd8c879d3c" dependencies = [ "proc-macro2", "proc-macro2-diagnostics", "quote", - "syn", + "syn 2.0.18", ] [[package]] name = "percent-encoding" -version = "2.1.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" +checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" [[package]] name = "pin-project-lite" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" [[package]] name = "pin-utils" @@ -867,9 +885,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "ppv-lite86" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro-error" @@ -880,7 +898,7 @@ dependencies = [ "proc-macro-error-attr", "proc-macro2", "quote", - "syn", + "syn 1.0.109", "version_check", ] @@ -895,53 +913,46 @@ dependencies = [ "version_check", ] -[[package]] -name = "proc-macro-hack" -version = "0.5.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" - [[package]] name = "proc-macro2" -version = "1.0.36" +version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" +checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406" dependencies = [ - "unicode-xid", + "unicode-ident", ] [[package]] name = "proc-macro2-diagnostics" -version = "0.9.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bf29726d67464d49fa6224a1d07936a8c08bb3fba727c7493f6cf1616fdaada" +checksum = "606c4ba35817e2922a308af55ad51bab3645b59eae5c570d4a6cf07e36bd493b" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.18", "version_check", "yansi", ] [[package]] name = "quote" -version = "1.0.14" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47aa80447ce4daf1717500037052af176af5d38cc3e571d9ec1c7353fc10c87d" +checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" dependencies = [ "proc-macro2", ] [[package]] name = "rand" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha", "rand_core", - "rand_hc", ] [[package]] @@ -956,70 +967,71 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ "getrandom", ] -[[package]] -name = "rand_hc" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" -dependencies = [ - "rand_core", -] - [[package]] name = "redox_syscall" -version = "0.2.10" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ - "bitflags", + "bitflags 1.3.2", +] + +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags 1.3.2", ] [[package]] name = "redox_users" -version = "0.4.0" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" +checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" dependencies = [ "getrandom", - "redox_syscall", + "redox_syscall 0.2.16", + "thiserror", ] [[package]] name = "ref-cast" -version = "1.0.6" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "300f2a835d808734ee295d45007adacb9ebb29dd3ae2424acfa17930cae541da" +checksum = "f43faa91b1c8b36841ee70e97188a869d37ae21759da6846d4be66de5bf7b12c" dependencies = [ "ref-cast-impl", ] [[package]] name = "ref-cast-impl" -version = "1.0.6" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c38e3aecd2b21cb3959637b883bb3714bc7e43f0268b9a29d3743ee3e55cdd2" +checksum = "8d2275aab483050ab2a7364c1a46604865ee7d6906684e08db0f090acf74f9e7" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.18", ] [[package]] name = "regex" -version = "1.5.4" +version = "1.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f" dependencies = [ "aho-corasick", "memchr", - "regex-syntax", + "regex-syntax 0.7.2", ] [[package]] @@ -1028,23 +1040,20 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" dependencies = [ - "regex-syntax", + "regex-syntax 0.6.29", ] [[package]] name = "regex-syntax" -version = "0.6.25" +version = "0.6.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] -name = "remove_dir_all" -version = "0.5.3" +name = "regex-syntax" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" -dependencies = [ - "winapi", -] +checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" [[package]] name = "ring" @@ -1063,20 +1072,20 @@ dependencies = [ [[package]] name = "rocket" -version = "0.5.0-rc.1" +version = "0.5.0-rc.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a71c18c42a0eb15bf3816831caf0dad11e7966f2a41aaf486a701979c4dd1f2" +checksum = "58734f7401ae5cfd129685b48f61182331745b357b96f2367f01aebaf1cc9cc9" dependencies = [ "async-stream", "async-trait", "atomic", - "atty", "binascii", "bytes", "either", "figment", "futures", "indexmap", + "is-terminal", "log", "memchr", "multer", @@ -1101,9 +1110,9 @@ dependencies = [ [[package]] name = "rocket_codegen" -version = "0.5.0-rc.1" +version = "0.5.0-rc.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66f5fa462f7eb958bba8710c17c5d774bbbd59809fa76fb1957af7e545aea8bb" +checksum = "7093353f14228c744982e409259fb54878ba9563d08214f2d880d59ff2fc508b" dependencies = [ "devise", "glob", @@ -1111,29 +1120,30 @@ dependencies = [ "proc-macro2", "quote", "rocket_http", - "syn", + "syn 2.0.18", "unicode-xid", ] [[package]] name = "rocket_http" -version = "0.5.0-rc.1" +version = "0.5.0-rc.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23c8b7d512d2fcac2316ebe590cde67573844b99e6cc9ee0f53375fa16e25ebd" +checksum = "936012c99162a03a67f37f9836d5f938f662e26f2717809761a9ac46432090f4" dependencies = [ "cookie", "either", + "futures", "http", "hyper", "indexmap", "log", "memchr", - "mime", - "parking_lot", "pear", "percent-encoding", "pin-project-lite", "ref-cast", + "rustls", + "rustls-pemfile", "serde", "smallvec", "stable-pattern", @@ -1154,21 +1164,25 @@ dependencies = [ ] [[package]] -name = "rustc_version" -version = "0.2.3" +name = "rustix" +version = "0.37.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d" dependencies = [ - "semver", + "bitflags 1.3.2", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys", + "windows-sys", ] [[package]] name = "rustls" -version = "0.19.1" +version = "0.20.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35edb675feee39aec9c99fa5ff985081995a06d594114ae14cbe797ad7b7a6d7" +checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f" dependencies = [ - "base64", "log", "ring", "sct", @@ -1176,22 +1190,31 @@ dependencies = [ ] [[package]] -name = "rustversion" -version = "1.0.6" +name = "rustls-pemfile" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f" +checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" +dependencies = [ + "base64", +] + +[[package]] +name = "rustversion" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06" [[package]] name = "ryu" -version = "1.0.9" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" +checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" [[package]] name = "scoped-tls" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" [[package]] name = "scopeguard" @@ -1201,56 +1224,41 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "sct" -version = "0.6.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b362b83898e0e69f38515b82ee15aa80636befe47c3b6d3d89a911e78fc228ce" +checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" dependencies = [ "ring", "untrusted", ] -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -dependencies = [ - "semver-parser", -] - -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" - [[package]] name = "serde" -version = "1.0.133" +version = "1.0.164" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97565067517b60e2d1ea8b268e59ce036de907ac523ad83a0475da04e818989a" +checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.133" +version = "1.0.164" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed201699328568d8d08208fdd080e3ff594e6c422e438b6705905da01005d537" +checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.18", ] [[package]] name = "serde_json" -version = "1.0.74" +version = "1.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee2bb9cd061c5865d345bb02ca49fcef1391741b672b54a0bf7b679badec3142" +checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" dependencies = [ - "itoa 1.0.1", + "itoa", "ryu", "serde", ] @@ -1266,10 +1274,19 @@ dependencies = [ ] [[package]] -name = "serde_yaml" -version = "0.8.23" +name = "serde_spanned" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a521f2940385c165a24ee286aa8599633d162077a54bdcae2a6fd5a7bfa7a0" +checksum = "93107647184f6027e3b7dcb2e11034cf95ffa1e3a682c67951963ac69c1c007d" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_yaml" +version = "0.8.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578a7433b776b56a35785ed5ce9a7e777ac0598aac5a6dd1b4b18a307c7fc71b" dependencies = [ "indexmap", "ryu", @@ -1277,12 +1294,6 @@ dependencies = [ "yaml-rust", ] -[[package]] -name = "sha1" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" - [[package]] name = "sha2" version = "0.9.9" @@ -1307,30 +1318,33 @@ dependencies = [ [[package]] name = "signal-hook-registry" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" dependencies = [ "libc", ] [[package]] name = "slab" -version = "0.4.5" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5" +checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +dependencies = [ + "autocfg", +] [[package]] name = "smallvec" -version = "1.7.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" [[package]] name = "socket2" -version = "0.4.2" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dc90fe6c7be1a323296982db1836d1ea9e47b6839496dde9a541bc496df3516" +checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" dependencies = [ "libc", "winapi", @@ -1344,9 +1358,9 @@ checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" [[package]] name = "spin" -version = "0.9.2" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "511254be0c5bcf062b019a6c89c01a664aa359ded62f78aa72c6fc137c0590e5" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" [[package]] name = "stable-pattern" @@ -1357,73 +1371,15 @@ dependencies = [ "memchr", ] -[[package]] -name = "standback" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e113fb6f3de07a243d434a56ec6f186dfd51cb08448239fe7bcae73f87ff28ff" -dependencies = [ - "version_check", -] - [[package]] name = "state" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cf4f5369e6d3044b5e365c9690f451516ac8f0954084622b49ea3fde2f6de5" +checksum = "dbe866e1e51e8260c9eed836a042a5e7f6726bb2b411dffeaa712e19c388f23b" dependencies = [ "loom", ] -[[package]] -name = "stdweb" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5" -dependencies = [ - "discard", - "rustc_version", - "stdweb-derive", - "stdweb-internal-macros", - "stdweb-internal-runtime", - "wasm-bindgen", -] - -[[package]] -name = "stdweb-derive" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" -dependencies = [ - "proc-macro2", - "quote", - "serde", - "serde_derive", - "syn", -] - -[[package]] -name = "stdweb-internal-macros" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11" -dependencies = [ - "base-x", - "proc-macro2", - "quote", - "serde", - "serde_derive", - "serde_json", - "sha1", - "syn", -] - -[[package]] -name = "stdweb-internal-runtime" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" - [[package]] name = "strsim" version = "0.10.0" @@ -1438,145 +1394,146 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "syn" -version = "1.0.85" +version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a684ac3dcd8913827e18cd09a68384ee66c1de24157e3c556c9ab16d85695fb7" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2", "quote", - "unicode-xid", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", ] [[package]] name = "tempfile" -version = "3.2.0" +version = "3.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" +checksum = "31c0432476357e58790aaa47a8efb0c5138f137343f3b5f23bd36a27e3b0a6d6" dependencies = [ + "autocfg", "cfg-if", - "libc", - "rand", - "redox_syscall", - "remove_dir_all", - "winapi", + "fastrand", + "redox_syscall 0.3.5", + "rustix", + "windows-sys", ] [[package]] name = "termcolor" -version = "1.1.2" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" dependencies = [ "winapi-util", ] [[package]] name = "textwrap" -version = "0.14.2" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80" +checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" [[package]] name = "thiserror" -version = "1.0.30" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" +checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.30" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" +checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.18", ] [[package]] name = "thread_local" -version = "1.1.3" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8018d24e04c95ac8790716a5987d0fec4f8b27249ffa0f7d33f1369bdfb88cbd" +checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" dependencies = [ + "cfg-if", "once_cell", ] [[package]] name = "time" -version = "0.2.27" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4752a97f8eebd6854ff91f1c1824cd6160626ac4bd44287f7f4ea2035a02a242" +checksum = "ea9e1b3cf1243ae005d9e74085d4d542f3125458f3a81af210d901dcd7411efd" dependencies = [ - "const_fn", - "libc", - "standback", - "stdweb", + "itoa", + "serde", + "time-core", "time-macros", - "version_check", - "winapi", ] +[[package]] +name = "time-core" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" + [[package]] name = "time-macros" -version = "0.1.1" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "957e9c6e26f12cb6d0dd7fc776bb67a706312e7299aed74c8dd5b17ebb27e2f1" +checksum = "372950940a5f07bf38dbe211d7283c9e6d7327df53794992d293e534c733d09b" dependencies = [ - "proc-macro-hack", - "time-macros-impl", -] - -[[package]] -name = "time-macros-impl" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd3c141a1b43194f3f56a1411225df8646c55781d5f26db825b3d98507eb482f" -dependencies = [ - "proc-macro-hack", - "proc-macro2", - "quote", - "standback", - "syn", + "time-core", ] [[package]] name = "tokio" -version = "1.15.0" +version = "1.28.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbbf1c778ec206785635ce8ad57fe52b3009ae9e0c9f574a728f3049d3e55838" +checksum = "94d7b1cfd2aa4011f2de74c2c4c63665e27a71006b0a192dcd2710272e73dfa2" dependencies = [ + "autocfg", "bytes", "libc", - "memchr", "mio", "num_cpus", - "once_cell", "pin-project-lite", "signal-hook-registry", + "socket2", "tokio-macros", - "winapi", + "windows-sys", ] [[package]] name = "tokio-macros" -version = "1.7.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7" +checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.18", ] [[package]] name = "tokio-rustls" -version = "0.22.0" +version = "0.23.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc6844de72e57df1980054b38be3a9f4702aba4858be64dd700181a8a6d0e1b6" +checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" dependencies = [ "rustls", "tokio", @@ -1585,9 +1542,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.8" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50145484efff8818b5ccd256697f36863f587da82cf8b409c53adf1e840798e3" +checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" dependencies = [ "futures-core", "pin-project-lite", @@ -1596,38 +1553,63 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.6.9" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e99e1983e5d376cd8eb4b66604d2e99e79f5bd988c3055891dcd8c9e2604cc0" +checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" dependencies = [ "bytes", "futures-core", "futures-sink", - "log", "pin-project-lite", "tokio", + "tracing", ] [[package]] name = "toml" -version = "0.5.8" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" +checksum = "d6135d499e69981f9ff0ef2167955a5333c35e36f6937d382974566b3d5b94ec" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a76a9312f5ba4c2dec6b9161fdf25d87ad8a09256ccea5a556fef03c706a10f" dependencies = [ "serde", ] [[package]] -name = "tower-service" -version = "0.3.1" +name = "toml_edit" +version = "0.19.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" +checksum = "2380d56e8670370eee6566b0bfd4265f65b3f432e8c6d85623f728d4fa31f739" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.29" +version = "0.1.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "375a639232caf30edfc78e8d89b2d4c375515393e7af7e16f01cd96917fb2105" +checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" dependencies = [ "cfg-if", "pin-project-lite", @@ -1637,29 +1619,30 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.18" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f480b8f81512e825f337ad51e94c1eb5d3bbdf2b363dcd01e2b19a9ffe3f8e" +checksum = "0f57e3ca2a01450b1a921183a9c9cbfda207fd822cef4ccb00a65402cbba7a74" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.18", ] [[package]] name = "tracing-core" -version = "0.1.21" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4ed65637b8390770814083d20756f87bfa2c21bf2f110babdc5438351746e4" +checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" dependencies = [ - "lazy_static", + "once_cell", + "valuable", ] [[package]] name = "tracing-log" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6923477a48e41c1951f1999ef8bb5a3023eb723ceadafe78ffb65dc366761e3" +checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" dependencies = [ "lazy_static", "log", @@ -1668,13 +1651,13 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.5" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d81bfa81424cc98cb034b837c985b7a290f592e5b4322f353f94a0ab0f9f594" +checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77" dependencies = [ - "ansi_term", - "lazy_static", "matchers", + "nu-ansi-term", + "once_cell", "regex", "sharded-slab", "smallvec", @@ -1686,40 +1669,46 @@ dependencies = [ [[package]] name = "try-lock" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" +checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" [[package]] name = "typenum" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" [[package]] name = "ubyte" -version = "0.10.1" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42756bb9e708855de2f8a98195643dff31a97f0485d90d8467b39dc24be9e8fe" +checksum = "c81f0dae7d286ad0d9366d7679a77934cfc3cf3a8d67e82669794412b2368fe6" dependencies = [ "serde", ] [[package]] name = "uncased" -version = "0.9.6" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5baeed7327e25054889b9bd4f975f32e5f4c5d434042d59ab6cd4142c0a76ed0" +checksum = "9b9bc53168a4be7402ab86c3aad243a84dd7381d09be0eddc81280c1da95ca68" dependencies = [ "serde", "version_check", ] [[package]] -name = "unicode-xid" -version = "0.2.2" +name = "unicode-ident" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" +checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" + +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" [[package]] name = "untrusted" @@ -1728,14 +1717,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" [[package]] -name = "users" -version = "0.11.0" +name = "valuable" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24cc0f6d6f267b73e5a2cadf007ba8f9bc39c6a6f9666f8cf25ea809a153b032" -dependencies = [ - "libc", - "log", -] +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" [[package]] name = "version_check" @@ -1755,15 +1740,15 @@ dependencies = [ [[package]] name = "wasi" -version = "0.10.2+wasi-snapshot-preview1" +version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.78" +version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce" +checksum = "5bba0e8cb82ba49ff4e229459ff22a191bbe9a1cb3a341610c9c33efc27ddf73" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -1771,24 +1756,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.78" +version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a317bf8f9fba2476b4b2c85ef4c4af8ff39c3c7f0cdfeed4f82c34a880aa837b" +checksum = "19b04bc93f9d6bdee709f6bd2118f57dd6679cf1176a1af464fca3ab0d66d8fb" dependencies = [ "bumpalo", - "lazy_static", "log", + "once_cell", "proc-macro2", "quote", - "syn", + "syn 2.0.18", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.78" +version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d56146e7c495528bf6587663bea13a8eb588d39b36b679d83972e1a2dbbdacf9" +checksum = "14d6b024f1a526bb0234f52840389927257beb670610081360e5a03c5df9c258" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1796,28 +1781,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.78" +version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab" +checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.18", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.78" +version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0237232789cf037d5480773fe568aac745bfe2afbc11a863e97901780a6b47cc" +checksum = "ed9d5b4305409d1fc9482fee2d7f9bcbf24b3972bf59817ef757e23982242a93" [[package]] name = "web-sys" -version = "0.3.55" +version = "0.3.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38eb105f1c59d9eaa6b5cdc92b859d85b926e82cb2e0945cd0c9259faa6fe9fb" +checksum = "3bdd9ef4e984da1187bf8110c5cf5b845fbc87a23602cdf912386a76fcd3a7c2" dependencies = [ "js-sys", "wasm-bindgen", @@ -1848,9 +1833,9 @@ dependencies = [ [[package]] name = "webpki" -version = "0.21.4" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea" +checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" dependencies = [ "ring", "untrusted", @@ -1887,6 +1872,90 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" + +[[package]] +name = "winnow" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61de7bac303dc551fe038e2b3cef0f571087a47571ea6e79a87692ac99b99699" +dependencies = [ + "memchr", +] + [[package]] name = "yaml-rust" version = "0.4.5" @@ -1898,6 +1967,6 @@ dependencies = [ [[package]] name = "yansi" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc79f4a1e39857fc00c3f662cbf2651c771f00e9c15fe2abc341806bd46bd71" +checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" From 57d4f10b417749f4a4faab6d63584652a62c319c Mon Sep 17 00:00:00 2001 From: finga Date: Sun, 11 Jun 2023 14:41:09 +0200 Subject: [PATCH 64/65] cargo: Bump `clap` to `4.3` Bump `clap` to latest version. --- Cargo.lock | 171 +++++++++++++++++++++++++++++------------------------ Cargo.toml | 2 +- src/cli.rs | 13 +--- 3 files changed, 98 insertions(+), 88 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 36e409c..ecb122e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,6 +11,55 @@ dependencies = [ "memchr", ] +[[package]] +name = "anstream" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is-terminal", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41ed9a86bf92ae6580e0a31281f65a1b1d867c0cc68d5346e2ae128dddfa6a7d" + +[[package]] +name = "anstyle-parse" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e765fd216e48e067936442276d1d57399e37bce53c264d6fefbe298080cb57ee" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188" +dependencies = [ + "anstyle", + "windows-sys", +] + [[package]] name = "anyhow" version = "1.0.71" @@ -36,7 +85,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn", ] [[package]] @@ -47,7 +96,7 @@ checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn", ] [[package]] @@ -132,42 +181,51 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" -version = "3.2.25" +version = "4.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" +checksum = "ca8f255e4b8027970e78db75e78831229c9815fdbfa67eb1a1b777a62e24b4a0" dependencies = [ - "atty", - "bitflags 1.3.2", + "clap_builder", "clap_derive", - "clap_lex", - "indexmap", "once_cell", +] + +[[package]] +name = "clap_builder" +version = "4.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acd4f3c17c83b0ba34ffbc4f8bbd74f079413f747f84a6f89292f138057e36ab" +dependencies = [ + "anstream", + "anstyle", + "bitflags 1.3.2", + "clap_lex", "strsim", - "termcolor", - "textwrap", ] [[package]] name = "clap_derive" -version = "3.2.25" +version = "4.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae6371b8bdc8b7d3959e9cf7b22d4435ef3e79e138688421ec654acf8c81b008" +checksum = "b8cd2b2a819ad6eec39e8f1d6b53001af1e5469f8c177579cdaeb313115b825f" dependencies = [ "heck", - "proc-macro-error", "proc-macro2", "quote", - "syn 1.0.109", + "syn", ] [[package]] name = "clap_lex" -version = "0.2.4" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" -dependencies = [ - "os_str_bytes", -] +checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" + +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" [[package]] name = "cookie" @@ -229,7 +287,7 @@ dependencies = [ "proc-macro2", "proc-macro2-diagnostics", "quote", - "syn 2.0.18", + "syn", ] [[package]] @@ -807,12 +865,6 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" -[[package]] -name = "os_str_bytes" -version = "6.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d5d9eb14b174ee9aa2ef96dc2b94637a2d4b6e7cb873c7e171f0c20c6cf3eac" - [[package]] name = "overload" version = "0.1.1" @@ -862,7 +914,7 @@ dependencies = [ "proc-macro2", "proc-macro2-diagnostics", "quote", - "syn 2.0.18", + "syn", ] [[package]] @@ -889,30 +941,6 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn 1.0.109", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - [[package]] name = "proc-macro2" version = "1.0.60" @@ -930,7 +958,7 @@ checksum = "606c4ba35817e2922a308af55ad51bab3645b59eae5c570d4a6cf07e36bd493b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn", "version_check", "yansi", ] @@ -1020,7 +1048,7 @@ checksum = "8d2275aab483050ab2a7364c1a46604865ee7d6906684e08db0f090acf74f9e7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn", ] [[package]] @@ -1120,7 +1148,7 @@ dependencies = [ "proc-macro2", "quote", "rocket_http", - "syn 2.0.18", + "syn", "unicode-xid", ] @@ -1249,7 +1277,7 @@ checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn", ] [[package]] @@ -1392,17 +1420,6 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - [[package]] name = "syn" version = "2.0.18" @@ -1437,12 +1454,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "textwrap" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" - [[package]] name = "thiserror" version = "1.0.40" @@ -1460,7 +1471,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn", ] [[package]] @@ -1526,7 +1537,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn", ] [[package]] @@ -1625,7 +1636,7 @@ checksum = "0f57e3ca2a01450b1a921183a9c9cbfda207fd822cef4ccb00a65402cbba7a74" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn", ] [[package]] @@ -1716,6 +1727,12 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + [[package]] name = "valuable" version = "0.1.0" @@ -1765,7 +1782,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.18", + "syn", "wasm-bindgen-shared", ] @@ -1787,7 +1804,7 @@ checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn", "wasm-bindgen-backend", "wasm-bindgen-shared", ] diff --git a/Cargo.toml b/Cargo.toml index 159acbd..494260b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ tls = ["rocket/tls"] [dependencies] anyhow = "1.0" -clap = { version = "3.0", features = ["derive"] } +clap = { version = "4.3", features = ["derive"] } dirs = "4.0" env_logger = "0.9" hex = "0.4" diff --git a/src/cli.rs b/src/cli.rs index f34a8b3..49a6d69 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -1,4 +1,4 @@ -use clap::{AppSettings, Parser}; +use clap::Parser; #[derive(Debug, Parser)] pub enum Command { @@ -7,17 +7,10 @@ pub enum Command { } #[derive(Debug, Parser)] -#[clap( - about, - version, - author, - global_setting = AppSettings::InferSubcommands, - global_setting = AppSettings::PropagateVersion, -)] pub struct Opts { /// Provide a path to the configuration file - #[clap(short, long, value_name = "FILE")] + #[arg(short, long, value_name = "FILE")] pub config: Option, - #[clap(subcommand)] + #[command(subcommand)] pub command: Option, } From faba2949d2ef7fbf4486734407d5e41d44b4935d Mon Sep 17 00:00:00 2001 From: finga Date: Sun, 11 Jun 2023 15:03:00 +0200 Subject: [PATCH 65/65] cargo: Bump `hmac` and `sha2` dependencies. Bump the `hmac` dependency to `0.12`, therefor remove deprecated `NewMac`. Further, bump the `sha2` dependency to `0.10`. --- Cargo.lock | 45 +++++++++++++++++++-------------------------- Cargo.toml | 4 ++-- src/hooks.rs | 5 +++-- 3 files changed, 24 insertions(+), 30 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ecb122e..3d535bc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -148,9 +148,9 @@ checksum = "6776fc96284a0bb647b615056fc496d1fe1644a7ab01829818a6d91cae888b84" [[package]] name = "block-buffer" -version = "0.9.0" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ "generic-array", ] @@ -248,13 +248,13 @@ dependencies = [ ] [[package]] -name = "crypto-mac" -version = "0.11.1" +name = "crypto-common" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", - "subtle", + "typenum", ] [[package]] @@ -292,11 +292,13 @@ dependencies = [ [[package]] name = "digest" -version = "0.9.0" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "generic-array", + "block-buffer", + "crypto-common", + "subtle", ] [[package]] @@ -581,11 +583,10 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "hmac" -version = "0.11.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "crypto-mac", "digest", ] @@ -859,12 +860,6 @@ version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" -[[package]] -name = "opaque-debug" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" - [[package]] name = "overload" version = "0.1.1" @@ -1193,9 +1188,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.37.19" +version = "0.37.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d" +checksum = "b96e891d04aa506a6d1f318d2771bcb1c7dfda84e126660ace067c9b474bb2c0" dependencies = [ "bitflags 1.3.2", "errno", @@ -1324,15 +1319,13 @@ dependencies = [ [[package]] name = "sha2" -version = "0.9.9" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" dependencies = [ - "block-buffer", "cfg-if", "cpufeatures", "digest", - "opaque-debug", ] [[package]] @@ -1416,9 +1409,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "subtle" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" [[package]] name = "syn" diff --git a/Cargo.toml b/Cargo.toml index 494260b..b7396f9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ clap = { version = "4.3", features = ["derive"] } dirs = "4.0" env_logger = "0.9" hex = "0.4" -hmac = "0.11" +hmac = "0.12" ipnet = { version = "2.3", features = ["serde"] } log = "0.4" regex = "1.5" @@ -26,7 +26,7 @@ serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" serde_regex = "1.1" serde_yaml = "0.8" -sha2 = "0.9" +sha2 = "0.10" thiserror = "1.0" [package.metadata.deb] diff --git a/src/hooks.rs b/src/hooks.rs index b51a47f..b653b00 100644 --- a/src/hooks.rs +++ b/src/hooks.rs @@ -3,7 +3,7 @@ use crate::{ Config, Metrics, WebhookeyError, }; use anyhow::{anyhow, bail, Result}; -use hmac::{Hmac, Mac, NewMac}; +use hmac::{Hmac, Mac}; use log::{debug, error, info, trace, warn}; use rocket::{ data::{FromData, ToByteUnit}, @@ -44,7 +44,8 @@ fn validate_request(secret: &str, signature: &str, data: &[u8]) -> Result<()> { .map_err(|e| anyhow!("Could not create hasher with secret: {}", e))?; mac.update(data); let raw_signature = hex::decode(signature.as_bytes())?; - mac.verify(&raw_signature).map_err(|e| anyhow!("{}", e)) + mac.verify_slice(&raw_signature) + .map_err(|e| anyhow!("{}", e)) } #[derive(Debug, Deserialize, Serialize)]