diff --git a/.gitea/issue_template/bug.md b/.gitea/issue_template/bug.md deleted file mode 100644 index abf6a27..0000000 --- a/.gitea/issue_template/bug.md +++ /dev/null @@ -1,31 +0,0 @@ ---- - -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 deleted file mode 100644 index 551a59d..0000000 --- a/.gitea/issue_template/enhancement.md +++ /dev/null @@ -1,16 +0,0 @@ ---- - -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 diff --git a/.woodpecker.yml b/.woodpecker.yml deleted file mode 100644 index 19c16b4..0000000 --- a/.woodpecker.yml +++ /dev/null @@ -1,37 +0,0 @@ -pipeline: - fmt: - group: default - image: rust_full - commands: - - cargo fmt --all -- --check - - clippy: - group: default - image: rust_full - commands: - - cargo clippy --all-features - - test: - group: default - image: rust_full - commands: - - cargo test - - build: - group: default - image: rust_full - commands: - - cargo build - - cargo build --release - - build-deb: - group: default - image: rust_full - commands: - - cargo deb - - doc: - group: default - image: rust_full - commands: - - cargo doc diff --git a/Cargo.lock b/Cargo.lock index 3d535bc..5f8b51b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,107 +3,85 @@ version = 3 [[package]] -name = "aho-corasick" -version = "1.0.2" +name = "aead" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" +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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5" 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" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" +checksum = "28b2cd92db5cbd74e8e5028f7e27dd7aa3090e89e4f2a197cc7c8dfb69c7063b" [[package]] -name = "async-stream" -version = "0.3.5" +name = "arrayref" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" -dependencies = [ - "async-stream-impl", - "futures-core", - "pin-project-lite", -] +checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" [[package]] -name = "async-stream-impl" -version = "0.3.5" +name = "arrayvec" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "async-trait" -version = "0.1.68" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "atomic" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59bdb34bc650a32731b31bd8f0829cc15d24a708ee31559e0bb34f2bc320cba" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" [[package]] name = "atty" @@ -111,67 +89,88 @@ version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ - "hermit-abi 0.1.19", + "hermit-abi", "libc", "winapi", ] [[package]] name = "autocfg" -version = "1.1.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "base64" -version = "0.21.2" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" +checksum = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" +dependencies = [ + "byteorder", + "safemem", +] [[package]] -name = "binascii" -version = "0.1.4" +name = "base64" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "383d29d513d8764dcdc42ea295d979eb99c3c9f00607b3692cf68a431f7dca72" +checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" + +[[package]] +name = "base64" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" [[package]] name = "bitflags" -version = "1.3.2" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" [[package]] -name = "bitflags" -version = "2.3.1" +name = "bitvec" +version = "0.19.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6776fc96284a0bb647b615056fc496d1fe1644a7ab01829818a6d91cae888b84" +checksum = "8942c8d352ae1838c9dda0b0ca2ab657696ef2232a20147cf1b30ae1a9cb4321" +dependencies = [ + "funty", + "radium", + "tap", + "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.10.4" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" dependencies = [ "generic-array", ] [[package]] -name = "bumpalo" -version = "3.13.0" +name = "byteorder" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" - -[[package]] -name = "bytes" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "cc" -version = "1.0.79" +version = "1.0.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd" [[package]] name = "cfg-if" @@ -180,88 +179,83 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] -name = "clap" -version = "4.3.3" +name = "cipher" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca8f255e4b8027970e78db75e78831229c9815fdbfa67eb1a1b777a62e24b4a0" +checksum = "12f8e7987cbd042a63249497f41aed09f8e65add917ea6566effbc56578d6801" dependencies = [ - "clap_builder", - "clap_derive", - "once_cell", + "generic-array", ] [[package]] -name = "clap_builder" -version = "4.3.3" +name = "constant_time_eq" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acd4f3c17c83b0ba34ffbc4f8bbd74f079413f747f84a6f89292f138057e36ab" -dependencies = [ - "anstream", - "anstyle", - "bitflags 1.3.2", - "clap_lex", - "strsim", -] - -[[package]] -name = "clap_derive" -version = "4.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8cd2b2a819ad6eec39e8f1d6b53001af1e5469f8c177579cdaeb313115b825f" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "clap_lex" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" - -[[package]] -name = "colorchoice" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" [[package]] name = "cookie" -version = "0.17.0" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7efb37c3e1ccb1ff97164ad95ac1606e8ccd35b3fa0a7d99a304c7f4a428cc24" +checksum = "80f6044740a4a516b8aac14c140cdf35c1a640b1bd6b98b6224e49143b2f1566" dependencies = [ - "percent-encoding", + "aes-gcm", + "base64 0.13.0", + "hkdf", + "hmac", + "percent-encoding 2.1.0", + "rand", + "sha2", "time", - "version_check", ] [[package]] -name = "cpufeatures" -version = "0.2.7" +name = "cpuid-bool" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e4c1eaa2012c47becbbad2ab175484c2a84d1185b566fb2cc5b8707343dfe58" +checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634" + +[[package]] +name = "cpuid-bool" +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 = [ - "libc", + "autocfg", + "cfg-if", + "lazy_static", ] [[package]] -name = "crypto-common" -version = "0.1.6" +name = "crypto-mac" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +checksum = "4857fd85a0c34b3c3297875b747c1e02e06b6a0ea32dd892d8192b9ce0813ea6" dependencies = [ "generic-array", - "typenum", + "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.4.1" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6eacefd3f541c66fc61433d65e54e0e46e0a029a819a7dbbc7a7b489e8a85f8" +checksum = "74e04ba2d03c5fa0d954c061fc8c9c288badadffc272ebb87679a89846de3ed3" dependencies = [ "devise_codegen", "devise_core", @@ -269,52 +263,49 @@ dependencies = [ [[package]] name = "devise_codegen" -version = "0.4.1" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8cf4b8dd484ede80fd5c547592c46c3745a617c8af278e2b72bea86b2dfed6" +checksum = "066ceb7928ca93a9bedc6d0e612a8a0424048b0ab1f75971b203d01420c055d7" dependencies = [ "devise_core", - "quote", + "quote 0.6.13", ] [[package]] name = "devise_core" -version = "0.4.1" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35b50dba0afdca80b187392b24f2499a88c336d5a8493e4b4ccfb608708be56a" +checksum = "cf41c59b22b5e3ec0ea55c7847e5f358d340f3a8d6d53a5cf4f1564967f96487" dependencies = [ - "bitflags 2.3.1", - "proc-macro2", - "proc-macro2-diagnostics", - "quote", - "syn", + "bitflags", + "proc-macro2 0.4.30", + "quote 0.6.13", + "syn 0.15.44", ] [[package]] name = "digest" -version = "0.10.7" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" dependencies = [ - "block-buffer", - "crypto-common", - "subtle", + "generic-array", ] [[package]] name = "dirs" -version = "4.0.0" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" +checksum = "142995ed02755914747cc6ca76fc7e4583cd18578746716d0508ea6ed558b9ff" dependencies = [ "dirs-sys", ] [[package]] name = "dirs-sys" -version = "0.3.7" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" +checksum = "8e93d7f5705de3e49895a2b5e0b8855a1c27f080192ae9c32a6432d50741a57a" dependencies = [ "libc", "redox_users", @@ -322,259 +313,103 @@ dependencies = [ ] [[package]] -name = "dunce" -version = "1.0.4" +name = "dtoa" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" - -[[package]] -name = "either" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" - -[[package]] -name = "encoding_rs" -version = "0.8.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" -dependencies = [ - "cfg-if", -] +checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0" [[package]] name = "env_logger" -version = "0.9.3" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" +checksum = "17392a012ea30ef05a610aa97dfb49496e71c9f676b27879922ea5bdf60d9d3f" dependencies = [ "atty", "humantime", - "log", + "log 0.4.14", "regex", "termcolor", ] -[[package]] -name = "errno" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -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", - "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.3.1" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de6fce87c901c64837f745e7fffddeca1de8e054b544ba82c419905d40a0e1be" +checksum = "a50045aa8931ae01afbc5d72439e8f57f326becb8c70d07dfc816778eff3d167" dependencies = [ - "dunce", "rand", + "users", ] [[package]] -name = "futures" -version = "0.3.28" +name = "funty" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" - -[[package]] -name = "futures-io" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" - -[[package]] -name = "futures-sink" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" - -[[package]] -name = "futures-task" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" - -[[package]] -name = "futures-util" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] -name = "generator" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3e123d9ae7c02966b4d892e550bdc32164f05853cd40ab570650ad600596a8a" -dependencies = [ - "cc", - "libc", - "log", - "rustversion", - "windows", -] +checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" [[package]] name = "generic-array" -version = "0.14.7" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" dependencies = [ "typenum", - "version_check", + "version_check 0.9.3", ] [[package]] name = "getrandom" -version = "0.2.10" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" dependencies = [ "cfg-if", "libc", - "wasi", + "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", +] + +[[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.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" - -[[package]] -name = "h2" -version = "0.3.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d357c7ae988e7d2182f7d7871d0b963962420b0678b0997ce7de72001aeab782" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http", - "indexmap", - "slab", - "tokio", - "tokio-util", - "tracing", -] +checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" [[package]] name = "hashbrown" -version = "0.12.3" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" [[package]] name = "hermit-abi" -version = "0.1.19" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" 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" @@ -582,47 +417,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] -name = "hmac" -version = "0.12.1" +name = "hkdf" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +checksum = "51ab2f639c231793c5f6114bdb9bbe50a7dbbfcd7c7c6bd8475dec2d991e964f" dependencies = [ "digest", + "hmac", +] + +[[package]] +name = "hmac" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1441c6b1e930e2817404b5046f1f989899143a12bf92de603b69f4e0aee1e15" +dependencies = [ + "crypto-mac", + "digest", ] -[[package]] -name = "http" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "http-body" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" -dependencies = [ - "bytes", - "http", - "pin-project-lite", -] - [[package]] name = "httparse" -version = "1.8.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" - -[[package]] -name = "httpdate" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" +checksum = "4a1ce40d6fc9764887c2fdc7305c3dcc429ba11ff981c1509416afd5697e4437" [[package]] name = "humantime" @@ -632,100 +450,76 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.26" +version = "0.10.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab302d72a6f11a3b910431ff93aae7e773078c769f0a3ef15fb9ec692ed147d4" +checksum = "0a0652d9a2609a968c14be1a9ea00bf4b1d64e2e1f53a1b51b6fff3a6e829273" dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", + "base64 0.9.3", "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2", - "tokio", - "tower-service", - "tracing", - "want", + "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", ] [[package]] name = "indexmap" -version = "1.9.3" +version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +checksum = "824845a0bf897a9042383849b02c1bc219c2383772efcd5c6f9766fa4b81aef3" dependencies = [ "autocfg", "hashbrown", - "serde", -] - -[[package]] -name = "inlinable_string" -version = "0.1.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8fae54786f62fb2918dcfae3d568594e50eb9b5c25bf04371af6fe7516452fb" - -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "io-lifetimes" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" -dependencies = [ - "hermit-abi 0.3.1", - "libc", - "windows-sys", ] [[package]] name = "ipnet" -version = "2.7.2" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12b6ee2129af8d4fb011108c73d99a1b83a85977f23b82460c0ae2e25bb4b57f" +checksum = "47be2f14c678be2fdcab04ab1171db51b2762ce6f0a8ee87c8dd4a04ed216135" dependencies = [ "serde", ] [[package]] -name = "is-terminal" +name = "itoa" version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" -dependencies = [ - "hermit-abi 0.3.1", - "io-lifetimes", - "rustix", - "windows-sys", -] +checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" [[package]] -name = "itoa" -version = "1.0.6" +name = "language-tags" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" - -[[package]] -name = "js-sys" -version = "0.3.63" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f37a4a5928311ac501dee68b3c7613a1037d0edb30c8e5427bd832d55d1b790" -dependencies = [ - "wasm-bindgen", -] +checksum = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" [[package]] name = "lazy_static" @@ -734,255 +528,208 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] -name = "libc" -version = "0.2.146" +name = "lexical-core" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b" +checksum = "21f866863575d0e1d654fbeeabdc927292fdf862873dc3c96c6f753357e13374" +dependencies = [ + "arrayvec", + "bitflags", + "cfg-if", + "ryu", + "static_assertions", +] + +[[package]] +name = "libc" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9385f66bf6105b241aa65a61cb923ef20efc665cb9f9bb50ac2f0c4b7f378d41" [[package]] name = "linked-hash-map" -version = "0.5.6" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" +checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" [[package]] -name = "linux-raw-sys" -version = "0.3.8" +name = "log" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" - -[[package]] -name = "lock_api" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" +checksum = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" dependencies = [ - "autocfg", - "scopeguard", + "log 0.4.14", ] [[package]] name = "log" -version = "0.4.19" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" - -[[package]] -name = "loom" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff50ecb28bb86013e935fb6683ab1f6d3a20016f123c76fd4c27470076ac30f5" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" dependencies = [ "cfg-if", - "generator", - "scoped-tls", - "serde", - "serde_json", - "tracing", - "tracing-subscriber", ] [[package]] -name = "matchers" -version = "0.1.0" +name = "matches" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" -dependencies = [ - "regex-automata", -] +checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" [[package]] name = "memchr" -version = "2.5.0" +version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" [[package]] name = "mime" -version = "0.3.17" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - -[[package]] -name = "mio" -version = "0.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" +checksum = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0" dependencies = [ - "libc", - "wasi", - "windows-sys", + "log 0.3.9", ] [[package]] -name = "multer" -version = "2.1.0" +name = "nom" +version = "6.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01acbdc23469fd8fe07ab135923371d5f5a422fbf9c522158677c8eb15bc51c2" +checksum = "e7413f999671bd4745a7b624bd370a569fb6bc574b23c83a3c5ed2e453f3d5e2" dependencies = [ - "bytes", - "encoding_rs", - "futures-util", - "http", - "httparse", - "log", + "bitvec", + "funty", + "lexical-core", "memchr", - "mime", - "spin 0.9.8", - "tokio", - "tokio-util", - "version_check", -] - -[[package]] -name = "nu-ansi-term" -version = "0.46.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" -dependencies = [ - "overload", - "winapi", + "version_check 0.9.3", ] [[package]] name = "num_cpus" -version = "1.15.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" dependencies = [ - "hermit-abi 0.2.6", + "hermit-abi", "libc", ] [[package]] -name = "once_cell" -version = "1.18.0" +name = "opaque-debug" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" - -[[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.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall 0.3.5", - "smallvec", - "windows-targets", -] +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "pear" -version = "0.2.4" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ec95680a7087503575284e5063e14b694b7a9c0b065e5dceec661e0497127e8" +checksum = "5320f212db967792b67cfe12bd469d08afd6318a249bd917d5c19bc92200ab8a" dependencies = [ - "inlinable_string", "pear_codegen", - "yansi", ] [[package]] name = "pear_codegen" -version = "0.2.4" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9661a3a53f93f09f2ea882018e4d7c88f6ff2956d809a276060476fd8c879d3c" +checksum = "bfc1c836fdc3d1ef87c348b237b5b5c4dff922156fb2d968f57734f9669768ca" dependencies = [ - "proc-macro2", - "proc-macro2-diagnostics", - "quote", - "syn", -] - -[[package]] -name = "percent-encoding" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" - -[[package]] -name = "pin-project-lite" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" - -[[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.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" - -[[package]] -name = "proc-macro2" -version = "1.0.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "proc-macro2-diagnostics" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "606c4ba35817e2922a308af55ad51bab3645b59eae5c570d4a6cf07e36bd493b" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "version_check", + "proc-macro2 0.4.30", + "quote 0.6.13", + "syn 0.15.44", + "version_check 0.9.3", "yansi", ] [[package]] -name = "quote" -version = "1.0.28" +name = "percent-encoding" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" +checksum = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" + +[[package]] +name = "percent-encoding" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" + +[[package]] +name = "polyval" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eebcc4aa140b9abd2bc40d9c3f7ccec842679cd79045ac3a7ac698c1a064b7cd" dependencies = [ - "proc-macro2", + "cpuid-bool 0.2.0", + "opaque-debug", + "universal-hash", ] [[package]] -name = "rand" -version = "0.8.5" +name = "ppv-lite86" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" + +[[package]] +name = "proc-macro2" +version = "0.4.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" +dependencies = [ + "unicode-xid 0.1.0", +] + +[[package]] +name = "proc-macro2" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec" +dependencies = [ + "unicode-xid 0.2.1", +] + +[[package]] +name = "quote" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" +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.26", +] + +[[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.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" dependencies = [ "libc", "rand_chacha", "rand_core", + "rand_hc", ] [[package]] name = "rand_chacha" -version = "0.3.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" dependencies = [ "ppv-lite86", "rand_core", @@ -990,266 +737,175 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.6.4" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7" dependencies = [ - "getrandom", + "getrandom 0.2.2", +] + +[[package]] +name = "rand_hc" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" +dependencies = [ + "rand_core", ] [[package]] name = "redox_syscall" -version = "0.2.16" +version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "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", -] +checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" [[package]] name = "redox_users" -version = "0.4.3" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d" dependencies = [ - "getrandom", - "redox_syscall 0.2.16", - "thiserror", -] - -[[package]] -name = "ref-cast" -version = "1.0.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43faa91b1c8b36841ee70e97188a869d37ae21759da6846d4be66de5bf7b12c" -dependencies = [ - "ref-cast-impl", -] - -[[package]] -name = "ref-cast-impl" -version = "1.0.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d2275aab483050ab2a7364c1a46604865ee7d6906684e08db0f090acf74f9e7" -dependencies = [ - "proc-macro2", - "quote", - "syn", + "getrandom 0.1.16", + "redox_syscall", + "rust-argon2", ] [[package]] name = "regex" -version = "1.8.4" +version = "1.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f" +checksum = "957056ecddbeba1b26965114e191d2e8589ce74db242b6ea25fc4062427a5c19" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.7.2", -] - -[[package]] -name = "regex-automata" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" -dependencies = [ - "regex-syntax 0.6.29", + "regex-syntax", ] [[package]] name = "regex-syntax" -version = "0.6.29" +version = "0.6.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" - -[[package]] -name = "regex-syntax" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" +checksum = "24d5f089152e60f62d28b835fbff2cd2e8dc0baf1ac13343bef92ab7eed84548" [[package]] name = "ring" -version = "0.16.20" +version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +checksum = "2c4db68a2e35f3497146b7e4563df7d4773a2433230c5e4b448328e31740458a" dependencies = [ "cc", + "lazy_static", "libc", - "once_cell", - "spin 0.5.2", "untrusted", - "web-sys", - "winapi", ] [[package]] name = "rocket" -version = "0.5.0-rc.3" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58734f7401ae5cfd129685b48f61182331745b357b96f2367f01aebaf1cc9cc9" +checksum = "7febfdfd4d43facfc7daba20349ebe2c310c6735bd6a2a9255ea8bc425b4cb13" dependencies = [ - "async-stream", - "async-trait", - "atomic", - "binascii", - "bytes", - "either", - "figment", - "futures", - "indexmap", - "is-terminal", - "log", + "atty", + "base64 0.12.3", + "log 0.4.14", "memchr", - "multer", "num_cpus", - "parking_lot", - "pin-project-lite", - "rand", - "ref-cast", + "pear", "rocket_codegen", "rocket_http", - "serde", "state", - "tempfile", "time", - "tokio", - "tokio-stream", - "tokio-util", - "ubyte", - "version_check", + "toml", + "version_check 0.9.3", "yansi", ] [[package]] name = "rocket_codegen" -version = "0.5.0-rc.3" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7093353f14228c744982e409259fb54878ba9563d08214f2d880d59ff2fc508b" +checksum = "ceac2c55b2c8b1cdc53add64332defa5fc227f64263b86b4114d1386286d42a3" dependencies = [ "devise", "glob", "indexmap", - "proc-macro2", - "quote", + "quote 0.6.13", "rocket_http", - "syn", - "unicode-xid", + "version_check 0.9.3", + "yansi", ] [[package]] name = "rocket_http" -version = "0.5.0-rc.3" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "936012c99162a03a67f37f9836d5f938f662e26f2717809761a9ac46432090f4" +checksum = "ce364100ed7a1bf39257b69ebd014c1d5b4979b0d365d8c9ab0aa9c79645493d" dependencies = [ "cookie", - "either", - "futures", - "http", "hyper", + "hyper-sync-rustls", "indexmap", - "log", - "memchr", "pear", - "percent-encoding", - "pin-project-lite", - "ref-cast", + "percent-encoding 1.0.1", "rustls", - "rustls-pemfile", - "serde", "smallvec", - "stable-pattern", "state", "time", - "tokio", - "tokio-rustls", - "uncased", + "unicode-xid 0.1.0", ] [[package]] name = "run_script" -version = "0.9.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dd85213e37f76b40186ee781cf3a689b05c518c3102c987acf679c573d8e4ef" +checksum = "e1c022176d696304ff6655716c2c09e1b888c00ac66a7c53c037ae7c9511ce6c" dependencies = [ "fsio", ] [[package]] -name = "rustix" -version = "0.37.20" +name = "rust-argon2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b96e891d04aa506a6d1f318d2771bcb1c7dfda84e126660ace067c9b474bb2c0" +checksum = "4b18820d944b33caa75a71378964ac46f58517c92b6ae5f762636247c09e78fb" dependencies = [ - "bitflags 1.3.2", - "errno", - "io-lifetimes", - "libc", - "linux-raw-sys", - "windows-sys", + "base64 0.13.0", + "blake2b_simd", + "constant_time_eq", + "crossbeam-utils", ] [[package]] name = "rustls" -version = "0.20.8" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f" +checksum = "8b7891791343c75b73ed9a18cadcafd8c8563d11a88ebe2d87f5b8a3182654d9" dependencies = [ - "log", + "base64 0.9.3", + "log 0.4.14", "ring", "sct", + "untrusted", "webpki", ] -[[package]] -name = "rustls-pemfile" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -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.13" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" +checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" [[package]] -name = "scoped-tls" -version = "1.0.1" +name = "safemem" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" - -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" [[package]] name = "sct" -version = "0.7.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" +checksum = "cb8f61f9e6eadd062a71c380043d28036304a4706b3c4dd001ff3387ed00745a" dependencies = [ "ring", "untrusted", @@ -1257,585 +913,310 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.164" +version = "1.0.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d" +checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.164" +version = "1.0.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68" +checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.26", + "quote 1.0.9", + "syn 1.0.69", ] [[package]] name = "serde_json" -version = "1.0.96" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" +checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79" dependencies = [ "itoa", "ryu", "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_spanned" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93107647184f6027e3b7dcb2e11034cf95ffa1e3a682c67951963ac69c1c007d" -dependencies = [ - "serde", -] - [[package]] name = "serde_yaml" -version = "0.8.26" +version = "0.8.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578a7433b776b56a35785ed5ce9a7e777ac0598aac5a6dd1b4b18a307c7fc71b" +checksum = "15654ed4ab61726bf918a39cb8d98a2e2995b002387807fa6ba58fdf7f59bb23" dependencies = [ - "indexmap", - "ryu", + "dtoa", + "linked-hash-map", "serde", "yaml-rust", ] [[package]] name = "sha2" -version = "0.10.6" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +checksum = "fa827a14b29ab7f44778d14a88d3cb76e949c45083f7dbfa507d0cb699dc12de" dependencies = [ + "block-buffer", "cfg-if", - "cpufeatures", + "cpuid-bool 0.1.2", "digest", -] - -[[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.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" -dependencies = [ - "libc", -] - -[[package]] -name = "slab" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" -dependencies = [ - "autocfg", + "opaque-debug", ] [[package]] name = "smallvec" -version = "1.10.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" - -[[package]] -name = "socket2" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" -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.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" - -[[package]] -name = "stable-pattern" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4564168c00635f88eaed410d5efa8131afa8d8699a612c80c455a0ba05c21045" -dependencies = [ - "memchr", -] +checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" [[package]] name = "state" -version = "0.5.3" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbe866e1e51e8260c9eed836a042a5e7f6726bb2b411dffeaa712e19c388f23b" -dependencies = [ - "loom", -] +checksum = "3015a7d0a5fd5105c91c3710d42f9ccf0abfb287d62206484dcc67f9569a6483" [[package]] -name = "strsim" -version = "0.10.0" +name = "static_assertions" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "subtle" -version = "2.5.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" +checksum = "1e81da0851ada1f3e9d4312c704aa4f8806f0f9d69faaf8df2f3464b4a9437c2" [[package]] name = "syn" -version = "2.0.18" +version = "0.15.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" +checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", + "proc-macro2 0.4.30", + "quote 0.6.13", + "unicode-xid 0.1.0", ] [[package]] -name = "tempfile" -version = "3.6.0" +name = "syn" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31c0432476357e58790aaa47a8efb0c5138f137343f3b5f23bd36a27e3b0a6d6" +checksum = "48fe99c6bd8b1cc636890bcc071842de909d902c81ac7dab53ba33c421ab8ffb" dependencies = [ - "autocfg", - "cfg-if", - "fastrand", - "redox_syscall 0.3.5", - "rustix", - "windows-sys", + "proc-macro2 1.0.26", + "quote 1.0.9", + "unicode-xid 0.2.1", ] +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + [[package]] name = "termcolor" -version = "1.2.0" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" dependencies = [ "winapi-util", ] [[package]] name = "thiserror" -version = "1.0.40" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +checksum = "e0f4a65597094d4483ddaed134f409b2cb7c1beccf25201a9f73c719254fa98e" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.40" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" +checksum = "7765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0" dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "thread_local" -version = "1.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" -dependencies = [ - "cfg-if", - "once_cell", + "proc-macro2 1.0.26", + "quote 1.0.9", + "syn 1.0.69", ] [[package]] name = "time" -version = "0.3.22" +version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea9e1b3cf1243ae005d9e74085d4d542f3125458f3a81af210d901dcd7411efd" +checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" dependencies = [ - "itoa", - "serde", - "time-core", - "time-macros", -] - -[[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.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "372950940a5f07bf38dbe211d7283c9e6d7327df53794992d293e534c733d09b" -dependencies = [ - "time-core", -] - -[[package]] -name = "tokio" -version = "1.28.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94d7b1cfd2aa4011f2de74c2c4c63665e27a71006b0a192dcd2710272e73dfa2" -dependencies = [ - "autocfg", - "bytes", "libc", - "mio", - "num_cpus", - "pin-project-lite", - "signal-hook-registry", - "socket2", - "tokio-macros", - "windows-sys", + "winapi", ] [[package]] -name = "tokio-macros" -version = "2.1.0" +name = "tinyvec" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" +checksum = "5b5220f05bb7de7f3f53c7c065e1199b3172696fe2db9f9c4d8ad9b4ee74c342" dependencies = [ - "proc-macro2", - "quote", - "syn", + "tinyvec_macros", ] [[package]] -name = "tokio-rustls" -version = "0.23.4" +name = "tinyvec_macros" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" -dependencies = [ - "rustls", - "tokio", - "webpki", -] - -[[package]] -name = "tokio-stream" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" -dependencies = [ - "futures-core", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "tokio-util" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", - "tracing", -] +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "toml" -version = "0.7.4" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -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" +checksum = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f" dependencies = [ "serde", ] [[package]] -name = "toml_edit" -version = "0.19.10" +name = "traitobject" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2380d56e8670370eee6566b0bfd4265f65b3f432e8c6d85623f728d4fa31f739" -dependencies = [ - "indexmap", - "serde", - "serde_spanned", - "toml_datetime", - "winnow", -] +checksum = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" [[package]] -name = "tower-service" -version = "0.3.2" +name = "typeable" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" - -[[package]] -name = "tracing" -version = "0.1.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" -dependencies = [ - "cfg-if", - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f57e3ca2a01450b1a921183a9c9cbfda207fd822cef4ccb00a65402cbba7a74" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tracing-core" -version = "0.1.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" -dependencies = [ - "once_cell", - "valuable", -] - -[[package]] -name = "tracing-log" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" -dependencies = [ - "lazy_static", - "log", - "tracing-core", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77" -dependencies = [ - "matchers", - "nu-ansi-term", - "once_cell", - "regex", - "sharded-slab", - "smallvec", - "thread_local", - "tracing", - "tracing-core", - "tracing-log", -] - -[[package]] -name = "try-lock" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" +checksum = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887" [[package]] name = "typenum" -version = "1.16.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06" [[package]] -name = "ubyte" -version = "0.10.3" +name = "unicase" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c81f0dae7d286ad0d9366d7679a77934cfc3cf3a8d67e82669794412b2368fe6" +checksum = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33" dependencies = [ - "serde", + "version_check 0.1.5", ] [[package]] -name = "uncased" -version = "0.9.9" +name = "unicode-bidi" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b9bc53168a4be7402ab86c3aad243a84dd7381d09be0eddc81280c1da95ca68" +checksum = "eeb8be209bb1c96b7c177c7420d26e04eccacb0eeae6b980e35fcb74678107e0" dependencies = [ - "serde", - "version_check", + "matches", ] [[package]] -name = "unicode-ident" -version = "1.0.9" +name = "unicode-normalization" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" +checksum = "07fbfce1c8a97d547e8b5334978438d9d6ec8c20e38f56d4a4374d181493eaef" +dependencies = [ + "tinyvec", +] [[package]] name = "unicode-xid" -version = "0.2.4" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" + +[[package]] +name = "unicode-xid" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" + +[[package]] +name = "universal-hash" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8326b2c654932e3e4f9196e69d08fdf7cfd718e1dc6f66b347e6024a0c961402" +dependencies = [ + "generic-array", + "subtle", +] [[package]] name = "untrusted" -version = "0.7.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" +checksum = "55cd1f4b4e96b46aeb8d4855db4a7a9bd96eeeb5c6a1ab54593328761642ce2f" [[package]] -name = "utf8parse" -version = "0.2.1" +name = "url" +version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +checksum = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" +dependencies = [ + "idna", + "matches", + "percent-encoding 1.0.1", +] [[package]] -name = "valuable" -version = "0.1.0" +name = "users" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +checksum = "24cc0f6d6f267b73e5a2cadf007ba8f9bc39c6a6f9666f8cf25ea809a153b032" +dependencies = [ + "libc", + "log 0.4.14", +] [[package]] name = "version_check" -version = "0.9.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" [[package]] -name = "want" -version = "0.3.0" +name = "version_check" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" -dependencies = [ - "log", - "try-lock", -] +checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" [[package]] name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" [[package]] -name = "wasm-bindgen" -version = "0.2.86" +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bba0e8cb82ba49ff4e229459ff22a191bbe9a1cb3a341610c9c33efc27ddf73" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.86" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b04bc93f9d6bdee709f6bd2118f57dd6679cf1176a1af464fca3ab0d66d8fb" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.86" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14d6b024f1a526bb0234f52840389927257beb670610081360e5a03c5df9c258" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.86" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.86" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed9d5b4305409d1fc9482fee2d7f9bcbf24b3972bf59817ef757e23982242a93" - -[[package]] -name = "web-sys" -version = "0.3.63" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bdd9ef4e984da1187bf8110c5cf5b845fbc87a23602cdf912386a76fcd3a7c2" -dependencies = [ - "js-sys", - "wasm-bindgen", -] +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" [[package]] name = "webhookey" -version = "0.1.6" +version = "0.1.0-rc.0" dependencies = [ "anyhow", - "clap", "dirs", "env_logger", "hex", "hmac", "ipnet", - "log", + "log 0.4.14", + "nom", "regex", "rocket", "run_script", "serde", "serde_json", - "serde_regex", "serde_yaml", "sha2", "thiserror", @@ -1843,14 +1224,24 @@ dependencies = [ [[package]] name = "webpki" -version = "0.22.0" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" +checksum = "17d7967316d8411ca3b01821ee6c332bde138ba4363becdb492f12e514daa17f" 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" @@ -1883,88 +1274,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] -name = "windows" -version = "0.48.0" +name = "wyz" +version = "0.2.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", -] +checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" [[package]] name = "yaml-rust" @@ -1977,6 +1290,6 @@ dependencies = [ [[package]] name = "yansi" -version = "0.5.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" +checksum = "9fc79f4a1e39857fc00c3f662cbf2651c771f00e9c15fe2abc341806bd46bd71" diff --git a/Cargo.toml b/Cargo.toml index b7396f9..7c75771 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "webhookey" -version = "0.1.6" +version = "0.1.0-rc.0" authors = ["finga "] -edition = "2021" +edition = "2018" license = "GPL-3.0-or-later" readme = "README.md" description = "Trigger scripts via http(s) requests" @@ -11,33 +11,30 @@ description = "Trigger scripts via http(s) requests" tls = ["rocket/tls"] [dependencies] -anyhow = "1.0" -clap = { version = "4.3", features = ["derive"] } -dirs = "4.0" -env_logger = "0.9" -hex = "0.4" -hmac = "0.12" -ipnet = { version = "2.3", features = ["serde"] } -log = "0.4" -regex = "1.5" -rocket = "0.5.0-rc.1" -run_script = "0.9" +rocket = "0.4" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" -serde_regex = "1.1" serde_yaml = "0.8" -sha2 = "0.10" +regex = "1.4" +dirs = "3.0" +anyhow = "1.0" +log = "0.4" +env_logger = "0.8" +nom = "6" +hmac = "0.10" +sha2 = "0.9" +hex = "0.4" +ipnet = { version = "2.3", features = ["serde"] } thiserror = "1.0" +run_script = "0.7" [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." +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." maintainer-scripts = "debian/" systemd-units = { enable = false } 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"], + ["README.md", "usr/share/doc/cargo-deb/README", "644"], ["debian/service", "lib/systemd/system/webhookey.service", "644"], ] -conf-files = ["/etc/webhookey/config.yml"] diff --git a/README.md b/README.md index c48045a..25b32f2 100644 --- a/README.md +++ b/README.md @@ -1,9 +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 +Webhookey is a webserver listening for requests as for example sent by +gitea's webhooks. Further, Webhookey allows you to specifiy rules which are matched against the data received to trigger certain actions. @@ -12,8 +9,13 @@ 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: +The webhookey project can be built for development: ``` sh cargo b ``` @@ -25,7 +27,7 @@ or for releasing: ### Install Webhookey When a Rust toolchain installed you can also install Webhookey -directly without cloning it manually: +directly without cloning it manualy: ``` sh cargo install --git https://git.onders.org/finga/webhookey.git webhookey ``` @@ -42,14 +44,14 @@ 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 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` @@ -62,32 +64,15 @@ 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. 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 -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: -- `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. +- filters: List of filters. Example: ```yaml @@ -102,19 +87,10 @@ hooks: secrets: - secret_key_01 - secret_key_02 - filter: - or: - - not: - json: - pointer: /ref - regex: refs/heads/dev - - and: - - json: - pointer: /ref - regex: refs/heads/a_branch - - header: - field: X-Gitea-Event - regex: push + filters: + match_ref: + pointer: /ref + regex: refs/heads/master ``` ##### Command @@ -133,28 +109,25 @@ Use values from header fields sent with the HTTP request. Example: `{{ header X-Gitea-Event }}`. -##### 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. +##### 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. Example: ```yaml -ip_filter: - allow: - - 127.0.0.1 - - 127.0.0.1/31 - - "::1" +allow: + - 127.0.0.1 + - 127.0.0.1/31 + - "::1" ``` ```yaml -ip_filter: - deny: - - 127.0.0.1 - - 127.0.0.1/31 - - "::1" +deny: + - 127.0.0.1 + - 127.0.0.1/31 + - "::1" ``` ##### Signature @@ -164,35 +137,17 @@ Set the name of the HTTP header field containing the HMAC signature. Configure a list of secrets to validate the hook. ##### Filter -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. +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 -###### 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. - - `regex`: Regular expression which has to match the specified - header field. - -- `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. +# 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 diff --git a/Rocket.toml b/Rocket.toml deleted file mode 100644 index ebb03f7..0000000 --- a/Rocket.toml +++ /dev/null @@ -1,2 +0,0 @@ -[default] -ident = "Webhookey" diff --git a/config.yml b/config.yml index 2dcaa9e..0bb3a42 100644 --- a/config.yml +++ b/config.yml @@ -1,9 +1,4 @@ --- -metrics: - enabled: true - ip_filter: - allow: - - 127.0.0.1 hooks: hook1: command: /usr/bin/local/script_xy.sh {{ /field2/foo }} asdfasdf @@ -14,8 +9,8 @@ hooks: secrets: - secret_key_01 - secret_key_02 - filter: - json: + filters: + match_ref: pointer: /ref regex: refs/heads/master hook2: @@ -27,24 +22,19 @@ hooks: secrets: - secret_key_01 - secret_key_02 - filter: - and: - - json: - pointer: /ref - regex: refs/heads/master - - json: - pointer: /after - regex: f6e5fe4fe37df76629112d55cc210718b6a55e7e + filters: + match_ref: + pointer: /ref + regex: refs/heads/master hook3: command: /usr/bin/local/script_xyz.sh signature: X-Gitea-Signature secrets: - secret_key03 - filter: - or: - - json: - pointer: /ref - regex: refs/heads/master - - json: - pointer: /after - regex: f6e5fe4fe37df76629112d55cc210718b6a55e7e + filters: + match_ref: + pointer: /ref + regex: refs/heads/master + match_after: + pointer: /after + regex: f6e5fe4fe37df76629112d55cc210718b6a55e7e diff --git a/src/cli.rs b/src/cli.rs deleted file mode 100644 index 49a6d69..0000000 --- a/src/cli.rs +++ /dev/null @@ -1,16 +0,0 @@ -use clap::Parser; - -#[derive(Debug, Parser)] -pub enum Command { - /// Verifies if the configuration can be parsed without errors - Configtest, -} - -#[derive(Debug, Parser)] -pub struct Opts { - /// Provide a path to the configuration file - #[arg(short, long, value_name = "FILE")] - pub config: Option, - #[command(subcommand)] - pub command: Option, -} diff --git a/src/config.rs b/src/config.rs deleted file mode 100644 index 64b0eb4..0000000 --- a/src/config.rs +++ /dev/null @@ -1,52 +0,0 @@ -use crate::{filters::IpFilter, hooks::Hook}; -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/filters.rs b/src/filters.rs deleted file mode 100644 index dc74864..0000000 --- a/src/filters.rs +++ /dev/null @@ -1,157 +0,0 @@ -use crate::WebhookeyError; -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; - -#[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)] -pub struct HeaderFilter { - pub field: String, - #[serde(with = "serde_regex")] - pub regex: Regex, -} - -impl HeaderFilter { - pub fn evaluate(&self, headers: &HeaderMap) -> Result { - trace!( - "Matching `{}` on `{}` from received header", - &self.regex, - &self.field, - ); - - if let Some(value) = headers.get_one(&self.field) { - if self.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 { - pub pointer: String, - #[serde(with = "serde_regex")] - pub regex: Regex, -} - -impl JsonFilter { - pub fn evaluate(&self, data: &serde_json::Value) -> Result { - trace!( - "Matching `{}` on `{}` from received json", - &self.regex, - &self.pointer, - ); - - if let Some(value) = data.pointer(&self.pointer) { - if self.regex.is_match(&crate::get_string(value)?) { - debug!("Regex `{}` for `{}` matches", &self.regex, &self.pointer); - - return Ok(true); - } - } - - debug!( - "Regex `{}` for json field `{}` does not match", - &self.regex, &self.pointer - ); - - Ok(false) - } -} - -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 { - Not(Box), - And(Vec), - Or(Vec), - #[serde(rename = "header")] - HeaderFilter(HeaderFilter), - #[serde(rename = "json")] - JsonFilter(JsonFilter), -} - -impl FilterType { - pub fn evaluate( - &self, - request: &Request, - data: &serde_json::Value, - ) -> Result { - match self { - FilterType::Not(filter) => Ok(!filter.evaluate(request, data)?), - 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), - } - } -} diff --git a/src/hooks.rs b/src/hooks.rs deleted file mode 100644 index b653b00..0000000 --- a/src/hooks.rs +++ /dev/null @@ -1,804 +0,0 @@ -use crate::{ - filters::{FilterType, IpFilter}, - Config, Metrics, WebhookeyError, -}; -use anyhow::{anyhow, bail, Result}; -use hmac::{Hmac, Mac}; -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_slice(&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.first() { - 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!("Invalid expression `{}`", 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); - } - } - - metrics.hooks_successful.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 a18261b..79c126a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,70 +1,591 @@ -mod cli; -mod config; -mod filters; -mod hooks; -mod metrics; +#![feature(proc_macro_hygiene, decl_macro)] -use crate::{cli::Opts, config::Config, metrics::Metrics}; -use anyhow::Result; -use clap::Parser; -use log::{debug, error, trace}; -use rocket::routes; -use std::{fs::File, io::BufReader, net::IpAddr}; +use anyhow::{anyhow, bail, Result}; +use hmac::{Hmac, Mac, NewMac}; +use ipnet::IpNet; +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 regex::Regex; +use rocket::{ + data::{self, FromDataSimple}, + fairing::AdHoc, + get, + http::{HeaderMap, Status}, + post, routes, Data, + Outcome::{Failure, Success}, + Request, Response, State, +}; +use run_script::ScriptOptions; +use serde::{Deserialize, Serialize}; +use sha2::Sha256; use thiserror::Error; +use std::{ + collections::HashMap, + fs::File, + io::{BufReader, Read}, + net::{IpAddr, Ipv4Addr, SocketAddr}, +}; + +#[derive(Debug, Deserialize, Serialize)] +#[serde(deny_unknown_fields, untagged)] +enum AddrType { + IpAddr(IpAddr), + IpNet(IpNet), +} + +#[derive(Debug, Deserialize, Serialize)] +#[serde(deny_unknown_fields, rename_all = "lowercase")] +enum IpFilter { + Allow(Vec), + Deny(Vec), +} + +#[derive(Debug, Deserialize, Serialize)] +#[serde(deny_unknown_fields)] +struct Config { + hooks: HashMap, +} + +#[derive(Debug, Deserialize, Serialize)] +#[serde(deny_unknown_fields)] +struct Hook { + command: String, + signature: String, + ip_filter: Option, + secrets: Vec, + filters: HashMap, +} + +#[derive(Debug, Deserialize, Serialize)] +#[serde(deny_unknown_fields)] +struct Filter { + pointer: String, + regex: String, +} + #[derive(Debug, Error)] -pub enum WebhookeyError { +enum WebhookeyError { #[error("Could not extract signature from header")] - InvalidSignature, + InvalidHeader, #[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(#[from] std::io::Error), + Io(std::io::Error), #[error("Serde Error")] - Serde(#[from] serde_json::Error), + Serde(serde_json::Error), } -pub fn get_string(data: &serde_json::Value) -> Result { - match &data { - serde_json::Value::Bool(bool) => Ok(bool.to_string()), +#[derive(Debug)] +struct Hooks(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; + } + } + } + } + + 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 {} as no IP filter was configured", + &hook_name, &client_ip + ), + } + + true +} + +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))?; + mac.update(&data); + let raw_signature = hex::decode(signature.as_bytes())?; + 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 replace_parameter(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") => { + 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()), + }, + 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_string(value: &serde_json::Value) -> Result { + match &value { + serde_json::Value::Null => unimplemented!(), + serde_json::Value::Bool(_bool) => unimplemented!(), 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!() + serde_json::Value::Array(_array) => unimplemented!(), + serde_json::Value::Object(_object) => unimplemented!(), + } +} + +fn filter_match( + 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)?; + + for parameter in get_parameter(&hook.command)? { + let parameter = parameter.trim(); + + if let Some(json_value) = data.pointer(parameter) { + *data.pointer_mut(parameter).unwrap() = match json_value { + 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!() + } + } + } + } + + 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_parameter( + &hook.command, + &request.headers(), + data, + )?)); + } + } + + debug!( + "Filter `{}` of hook `{}` did not match", + filter_name, hook_name + ); + + Ok(None) +} + +fn execute_hooks(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 hooks = 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,); + + 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)) => { + hooks.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); + } + } + } + + if !valid { + return Err(WebhookeyError::Unauthorized(*client_ip)); + } + + Ok(Hooks(hooks)) +} + +impl FromDataSimple for Hooks { + type Error = WebhookeyError; + + fn from_data(request: &Request, data: Data) -> data::Outcome { + match execute_hooks(&request, data) { + Ok(hooks) => { + if hooks.0.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)) + } } } } -#[rocket::main] -async fn main() -> Result<()> { +#[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); + + match run_script::run(&hook.1, &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); + } + Err(e) => { + error!("Execution of `{}` failed: {}", &hook.1, e); + } + } + } + + Ok(Response::new()) +} + +fn get_config() -> Result { + if let Ok(config) = File::open("/etc/webhookey/config.yml") { + info!("Loading configuration from `/etc/webhookey/config.yml`"); + + return Ok(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); + } + } + + if let Ok(config) = File::open("config.yml") { + info!("Loading configuration from `./config.yml`"); + + return Ok(config); + } + + bail!("No configuration file found."); +} + +fn main() -> Result<()> { env_logger::init(); - let cli: Opts = Opts::parse(); - - let config: Config = match cli.config { - Some(config) => serde_yaml::from_reader(BufReader::new(File::open(config)?))?, - _ => serde_yaml::from_reader(BufReader::new(config::get_config()?))?, - }; + let config: Config = serde_yaml::from_reader(BufReader::new(get_config()?))?; trace!("Parsed configuration:\n{}", serde_yaml::to_string(&config)?); - if cli.command.is_some() { - debug!("Configtest succeded."); - println!("Config is OK"); - return Ok(()); - } - - rocket::build() - .mount("/", routes![hooks::receive_hook, metrics::metrics]) - .manage(config) - .manage(Metrics::default()) - .launch() - .await?; + rocket::ignite() + .mount("/", routes![index, receive_hook]) + .attach(AdHoc::on_attach("webhookey config", move |rocket| { + Ok(rocket.manage(config)) + })) + .launch(); Ok(()) } + +#[cfg(test)] +mod tests { + use super::*; + use rocket::{ + http::{ContentType, Header}, + local::Client, + }; + 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(); + hooks.insert( + "test_hook".to_string(), + Hook { + command: "".to_string(), + signature: "X-Gitea-Signature".to_string(), + ip_filter: None, + secrets: vec!["valid".to_string()], + filters: HashMap::new(), + }, + ); + let config = Config { hooks: hooks }; + + let rocket = rocket::ignite() + .mount("/", routes![receive_hook]) + .attach(AdHoc::on_attach("webhookey config", move |rocket| { + Ok(rocket.manage(config)) + })); + + let client = Client::new(rocket).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.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.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.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.status(), Status::Unauthorized); + } + + #[test] + fn parse_command() { + let mut map = HeaderMap::new(); + map.add_raw("X-Gitea-Event", "something"); + + assert_eq!( + replace_parameter("command", &map, &serde_json::Value::Null).unwrap(), + "command" + ); + + assert_eq!( + replace_parameter(" command", &map, &serde_json::Value::Null).unwrap(), + " command" + ); + + assert_eq!( + replace_parameter("command ", &map, &serde_json::Value::Null).unwrap(), + "command " + ); + + assert_eq!( + replace_parameter(" command ", &map, &serde_json::Value::Null).unwrap(), + " command " + ); + + assert_eq!( + replace_parameter("command command ", &map, &serde_json::Value::Null).unwrap(), + "command command " + ); + + assert_eq!( + replace_parameter("{{ /foo }} command", &map, &json!({ "foo": "bar" })).unwrap(), + "bar command" + ); + + assert_eq!( + replace_parameter(" command {{ /foo }} ", &map, &json!({ "foo": "bar" })).unwrap(), + " command bar " + ); + + assert_eq!( + replace_parameter( + "{{ /foo }} command{{/field1/foo}}", + &map, + &json!({ "foo": "bar", "field1": { "foo": "baz" } }) + ) + .unwrap(), + "bar commandbaz" + ); + + assert_eq!( + replace_parameter(" command {{ /foo }} ", &map, &json!({ "foo": "bar" })).unwrap(), + " command bar " + ); + + assert_eq!( + replace_parameter( + " {{ /field1/foo }} command", + &map, + &json!({ "field1": { "foo": "bar" } }) + ) + .unwrap(), + " bar command" + ); + + assert_eq!( + replace_parameter( + " {{ header X-Gitea-Event }} command", + &map, + &json!({ "field1": { "foo": "bar" } }) + ) + .unwrap(), + " something command" + ); + } +} diff --git a/src/metrics.rs b/src/metrics.rs deleted file mode 100644 index 71c4fae..0000000 --- a/src/metrics.rs +++ /dev/null @@ -1,91 +0,0 @@ -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), - ) - } -} diff --git a/webhookey.1 b/webhookey.1 deleted file mode 100644 index e0ca688..0000000 --- a/webhookey.1 +++ /dev/null @@ -1,57 +0,0 @@ -.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 .