diff --git a/Cargo.lock b/Cargo.lock index 5b9a28c..c2138e4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,211 +1,171 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] -name = "aead" -version = "0.5.1" +name = "addr2line" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c192eb8f11fc081b0fe4259ba5af04217d4e0faddd02417310a927911abd7c8" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" dependencies = [ - "crypto-common", - "generic-array", + "gimli", ] [[package]] -name = "aes" -version = "0.8.2" +name = "adler2" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "433cfd6710c9986c576a25ca913c39d66a6474107b406f34f91d4a8923395241" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", - "cipher", - "cpufeatures", + "once_cell", + "version_check", + "zerocopy", ] [[package]] -name = "aes-gcm" -version = "0.10.1" +name = "async-lock" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e1366e0c69c9f927b1fa5ce2c7bf9eafc8f9268c0b9800729e8b267612447c" +checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" dependencies = [ - "aead", - "aes", - "cipher", - "ctr", - "ghash", - "subtle", -] - -[[package]] -name = "aho-corasick" -version = "0.7.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" -dependencies = [ - "memchr", -] - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - -[[package]] -name = "argon2" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db4ce4441f99dbd377ca8a8f57b698c44d0d6e712d8329b5040da5a64aa1ce73" -dependencies = [ - "base64ct", - "blake2", - "password-hash", -] - -[[package]] -name = "async-stream" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad445822218ce64be7a341abfb0b1ea43b5c23aa83902542a4542e78309d8e5e" -dependencies = [ - "async-stream-impl", - "futures-core", + "event-listener", + "event-listener-strategy", "pin-project-lite", ] -[[package]] -name = "async-stream-impl" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4655ae1a7b0cdf149156f780c5bf3f1352bc53cbd9e0a361a7ef7b22947e965" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "async-trait" -version = "0.1.64" +version = "0.1.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd7fce9ba8c3c042128ce72d8b2ddbf3a05747efb67ea0313c635e10bda47a2" +checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", "syn", ] -[[package]] -name = "atomic" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b88d82667eca772c4aa12f0f1348b3ae643424c8876448f3f7bd5787032e234c" -dependencies = [ - "autocfg", -] - -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi 0.1.19", - "libc", - "winapi", -] - [[package]] name = "autocfg" -version = "1.1.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] -name = "base64" -version = "0.20.0" +name = "axum" +version = "0.8.0-alpha.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ea22880d78093b0cbe17c89f64a7d457941e65759157ec6cb31a31d652b05e5" +checksum = "4132c8995c63b222c56f38b80748c23323d7012d1f783b0f42e92782c2676690" +dependencies = [ + "axum-core", + "bytes", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-util", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tower", + "tower-layer", + "tower-service", +] [[package]] -name = "base64" -version = "0.21.0" +name = "axum-core" +version = "0.5.0-alpha.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" +checksum = "f3405ae79f3aab93ae35fe2944aff9bf0f5aac918c0229f3528043c5a454d17d" +dependencies = [ + "bytes", + "futures-util", + "http", + "http-body", + "http-body-util", + "mime", + "pin-project-lite", + "rustversion", + "sync_wrapper", + "tower-layer", + "tower-service", +] [[package]] -name = "base64ct" -version = "1.5.3" +name = "backtrace" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b645a089122eccb6111b4f81cbc1a49f5900ac4666bb93ac027feaecf15607bf" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-targets", +] [[package]] -name = "binascii" -version = "0.1.4" +name = "bb8" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "383d29d513d8764dcdc42ea295d979eb99c3c9f00607b3692cf68a431f7dca72" +checksum = "212d8b8e1a22743d9241575c6ba822cf9c8fef34771c86ab7e477a4fbfd254e5" +dependencies = [ + "futures-util", + "parking_lot", + "tokio", +] [[package]] name = "bitflags" -version = "1.3.2" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "blake2" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" -dependencies = [ - "digest", -] - -[[package]] -name = "block-buffer" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" -dependencies = [ - "generic-array", -] - -[[package]] -name = "bstr" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ffdb39cb703212f3c11973452c2861b972f757b021158f3516ba10f2fa8b2c1" -dependencies = [ - "memchr", - "serde", -] +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "bumpalo" -version = "3.12.0" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "byteorder" -version = "1.4.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.4.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" [[package]] name = "cc" -version = "1.0.79" +version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +checksum = "27f657647bcff5394bf56c7317665bbf790a137a50eaaa5c6bfbb9e27a518f2d" +dependencies = [ + "shlex", +] [[package]] name = "cfg-if" @@ -214,328 +174,97 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] -name = "chrono" -version = "0.4.23" +name = "concurrent-queue" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" dependencies = [ - "iana-time-zone", - "js-sys", - "num-integer", - "num-traits", - "serde", - "time 0.1.45", - "wasm-bindgen", - "winapi", + "crossbeam-utils", ] [[package]] -name = "cipher" -version = "0.4.3" +name = "crossbeam-channel" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1873270f8f7942c191139cb8a40fd228da6c3fd2fc376d7e92d47aa14aeb59e" +checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" dependencies = [ - "crypto-common", - "inout", + "crossbeam-utils", ] [[package]] -name = "clap" -version = "3.2.23" +name = "crossbeam-epoch" +version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71655c45cb9845d3270c9d6df84ebe72b4dad3c2ba3f7023ad47c144e4e473a5" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" dependencies = [ - "atty", - "bitflags", - "clap_derive", - "clap_lex", - "indexmap", - "once_cell", - "strsim", - "termcolor", - "textwrap", + "crossbeam-utils", ] [[package]] -name = "clap_derive" -version = "3.2.18" +name = "crossbeam-utils" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea0c8bce528c4be4da13ea6fead8965e95b6073585a2f05204bd8f4119f82a65" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" dependencies = [ - "heck", - "proc-macro-error", - "proc-macro2", - "quote", - "syn", + "powerfmt", ] [[package]] -name = "clap_lex" -version = "0.2.4" +name = "domain" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +checksum = "64008666d9f3b6a88a63cd28ad8f3a5a859b8037e11bfb680c1b24945ea1c28d" dependencies = [ - "os_str_bytes", -] - -[[package]] -name = "codespan-reporting" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" -dependencies = [ - "termcolor", - "unicode-width", -] - -[[package]] -name = "cookie" -version = "0.16.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb" -dependencies = [ - "aes-gcm", - "base64 0.20.0", - "hkdf", - "hmac", - "percent-encoding", + "bytes", + "futures-util", + "moka", + "octseq", "rand", - "sha2", - "subtle", - "time 0.3.19", - "version_check", + "ring", + "smallvec", + "time", + "tokio", + "tracing", ] [[package]] -name = "core-foundation-sys" -version = "0.8.3" +name = "event-listener" +version = "5.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" - -[[package]] -name = "cpufeatures" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" +checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" dependencies = [ - "libc", + "concurrent-queue", + "parking", + "pin-project-lite", ] [[package]] -name = "crypto-common" -version = "0.1.6" +name = "event-listener-strategy" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +checksum = "3c3e4e0dd3673c1139bf041f3008816d9cf2946bbfac2945c09e523b8d7b05b2" dependencies = [ - "generic-array", - "rand_core", - "typenum", + "event-listener", + "pin-project-lite", ] [[package]] -name = "ctr" -version = "0.9.2" +name = "fallible-iterator" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" -dependencies = [ - "cipher", -] +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" [[package]] -name = "cxx" -version = "1.0.91" +name = "fallible-streaming-iterator" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86d3488e7665a7a483b57e25bdd90d0aeb2bc7608c8d0346acf2ad3f1caf1d62" -dependencies = [ - "cc", - "cxxbridge-flags", - "cxxbridge-macro", - "link-cplusplus", -] - -[[package]] -name = "cxx-build" -version = "1.0.91" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48fcaf066a053a41a81dfb14d57d99738b767febb8b735c3016e469fac5da690" -dependencies = [ - "cc", - "codespan-reporting", - "once_cell", - "proc-macro2", - "quote", - "scratch", - "syn", -] - -[[package]] -name = "cxxbridge-flags" -version = "1.0.91" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2ef98b8b717a829ca5603af80e1f9e2e48013ab227b68ef37872ef84ee479bf" - -[[package]] -name = "cxxbridge-macro" -version = "1.0.91" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "086c685979a698443656e5cf7856c95c642295a38599f12fb1ff76fb28d19892" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "data-encoding" -version = "2.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d8666cb01533c39dde32bcbab8e227b4ed6679b2c925eba05feabea39508fb" - -[[package]] -name = "devise" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50c7580b072f1c8476148f16e0a0d5dedddab787da98d86c5082c5e9ed8ab595" -dependencies = [ - "devise_codegen", - "devise_core", -] - -[[package]] -name = "devise_codegen" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "123c73e7a6e51b05c75fe1a1b2f4e241399ea5740ed810b0e3e6cacd9db5e7b2" -dependencies = [ - "devise_core", - "quote", -] - -[[package]] -name = "devise_core" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "841ef46f4787d9097405cac4e70fb8644fc037b526e8c14054247c0263c400d0" -dependencies = [ - "bitflags", - "proc-macro2", - "proc-macro2-diagnostics", - "quote", - "syn", -] - -[[package]] -name = "diesel" -version = "1.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b28135ecf6b7d446b43e27e225622a038cc4e2930a1022f51cdb97ada19b8e4d" -dependencies = [ - "byteorder", - "chrono", - "diesel_derives", - "libsqlite3-sys", - "r2d2", -] - -[[package]] -name = "diesel-derive-enum" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8910921b014e2af16298f006de12aa08af894b71f0f49a486ab6d74b17bbed" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "diesel_derives" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45f5098f628d02a7a0f68ddba586fb61e80edec3bdc1be3b921f4ceec60858d3" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "diesel_migrations" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf3cde8413353dc7f5d72fa8ce0b99a560a359d2c5ef1e5817ca731cd9008f4c" -dependencies = [ - "migrations_internals", - "migrations_macros", -] - -[[package]] -name = "digest" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" -dependencies = [ - "block-buffer", - "crypto-common", - "subtle", -] - -[[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", -] - -[[package]] -name = "endian-type" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" - -[[package]] -name = "enum-as-inner" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9720bba047d567ffc8a3cba48bf19126600e249ab7f128e9233e6376976a116" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn", -] - -[[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.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e56602b469b2201400dec66a66aec5a9b8761ee97cd1b8c96ab2483fcc16cc9" -dependencies = [ - "atomic", - "pear", - "serde", - "toml", - "uncased", - "version_check", -] +checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" [[package]] name = "fnv" @@ -543,222 +272,101 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - [[package]] name = "form_urlencoded" -version = "1.1.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] -[[package]] -name = "futures" -version = "0.3.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13e2792b0ff0340399d58445b88fd9770e3489eff258a4cbc1523418f12abf84" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - [[package]] name = "futures-channel" -version = "0.3.26" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e5317663a9089767a1ec00a487df42e0ca174b61b4483213ac24448e4664df5" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", - "futures-sink", ] [[package]] name = "futures-core" -version = "0.3.26" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec90ff4d0fe1f57d600049061dc6bb68ed03c7d2fbd697274c41805dcb3f8608" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] -name = "futures-io" -version = "0.3.26" +name = "futures-macro" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfb8371b6fb2aeb2d280374607aeabfc99d95c72edfe51692e42d3d7f0d08531" - -[[package]] -name = "futures-sink" -version = "0.3.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f310820bb3e8cfd46c80db4d7fb8353e15dfff853a127158425f31e0be6c8364" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] name = "futures-task" -version = "0.3.26" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf79a1bf610b10f42aea489289c5a2c478a786509693b80cd39c44ccd936366" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-util" -version = "0.3.26" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c1d6de3acfef38d2be4b1f543f553131788603495be83da675e180c8d6b7bd1" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ - "futures-channel", "futures-core", - "futures-io", - "futures-sink", + "futures-macro", "futures-task", - "memchr", "pin-project-lite", "pin-utils", "slab", ] -[[package]] -name = "generator" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d266041a359dfa931b370ef684cceb84b166beb14f7f0421f4a6a3d0c446d12e" -dependencies = [ - "cc", - "libc", - "log", - "rustversion", - "windows", -] - -[[package]] -name = "generic-array" -version = "0.14.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" -dependencies = [ - "typenum", - "version_check", -] - [[package]] name = "getrandom" -version = "0.2.8" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", ] [[package]] -name = "ghash" -version = "0.5.0" +name = "gimli" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d930750de5717d2dd0b8c0d42c076c0e884c81a73e6cab859bbd2339c71e3e40" -dependencies = [ - "opaque-debug", - "polyval", -] - -[[package]] -name = "glob" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" - -[[package]] -name = "globset" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "029d74589adefde59de1a0c4f4732695c32805624aec7b68d91503d4dba79afc" -dependencies = [ - "aho-corasick", - "bstr", - "fnv", - "log", - "regex", -] - -[[package]] -name = "globwalk" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93e3af942408868f6934a7b85134a3230832b9977cf66125df2f9edcfce4ddcc" -dependencies = [ - "bitflags", - "ignore", - "walkdir", -] +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "hashbrown" -version = "0.12.3" +version = "0.14.5" 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" - -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ - "libc", + "ahash", ] [[package]] -name = "hermit-abi" -version = "0.2.6" +name = "hashlink" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" +checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" dependencies = [ - "libc", -] - -[[package]] -name = "hkdf" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437" -dependencies = [ - "hmac", -] - -[[package]] -name = "hmac" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" -dependencies = [ - "digest", + "hashbrown", ] [[package]] name = "http" -version = "0.2.9" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" dependencies = [ "bytes", "fnv", @@ -767,42 +375,47 @@ dependencies = [ [[package]] name = "http-body" -version = "0.4.5" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" +dependencies = [ + "bytes", + "futures-util", + "http", + "http-body", "pin-project-lite", ] [[package]] name = "httparse" -version = "1.8.0" +version = "1.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" +checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" [[package]] name = "httpdate" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" - -[[package]] -name = "humantime" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" -version = "0.14.24" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e011372fa0b68db8350aa7a248930ecc7839bf46d8485577d69f117a75f164c" +checksum = "97818827ef4f364230e16705d4706e2897df2bb60617d6ca15d598025a3c481f" dependencies = [ "bytes", "futures-channel", - "futures-core", "futures-util", "http", "http-body", @@ -810,167 +423,63 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2", + "smallvec", + "tokio", +] + +[[package]] +name = "hyper-util" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" +dependencies = [ + "bytes", + "futures-util", + "http", + "http-body", + "hyper", + "pin-project-lite", "tokio", "tower-service", - "tracing", - "want", ] -[[package]] -name = "iana-time-zone" -version = "0.1.53" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "winapi", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" -dependencies = [ - "cxx", - "cxx-build", -] - -[[package]] -name = "idna" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" -dependencies = [ - "matches", - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "idna" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "ignore" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbe7873dab538a9a44ad79ede1faf5f30d49f9a5c883ddbab48bce81b64b7492" -dependencies = [ - "globset", - "lazy_static", - "log", - "memchr", - "regex", - "same-file", - "thread_local", - "walkdir", - "winapi-util", -] - -[[package]] -name = "indexmap" -version = "1.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" -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 = "inout" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" -dependencies = [ - "generic-array", -] - -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "ipnet" -version = "2.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30e22bd8629359895450b59ea7a776c850561b96a3b1d31321c1949d9e6c9146" - [[package]] name = "itoa" -version = "1.0.5" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "js-sys" -version = "0.3.61" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" +checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7" dependencies = [ + "once_cell", "wasm-bindgen", ] -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - [[package]] name = "libc" -version = "0.2.139" +version = "0.2.168" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" +checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d" [[package]] name = "libsqlite3-sys" -version = "0.22.2" +version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290b64917f8b0cb885d9de0f9959fe1f775d7fa12f1da2db9001c1c8ab60f89d" +checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" dependencies = [ "pkg-config", "vcpkg", ] -[[package]] -name = "link-cplusplus" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" -dependencies = [ - "cc", -] - [[package]] name = "lock_api" -version = "0.4.9" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", @@ -978,251 +487,128 @@ dependencies = [ [[package]] name = "log" -version = "0.4.17" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] -name = "loom" -version = "0.5.6" +name = "matchit" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff50ecb28bb86013e935fb6683ab1f6d3a20016f123c76fd4c27470076ac30f5" -dependencies = [ - "cfg-if", - "generator", - "scoped-tls", - "serde", - "serde_json", - "tracing", - "tracing-subscriber", -] - -[[package]] -name = "matchers" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" -dependencies = [ - "regex-automata", -] - -[[package]] -name = "matches" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" +checksum = "56e8fcd7bd6025a951597d6ba2f8e48a121af7e262f2b52a006a09c8d61f9304" [[package]] name = "memchr" -version = "2.5.0" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" - -[[package]] -name = "migrations_internals" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b4fc84e4af020b837029e017966f86a1c2d5e83e64b589963d5047525995860" -dependencies = [ - "diesel", -] - -[[package]] -name = "migrations_macros" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9753f12909fd8d923f75ae5c3258cae1ed3c8ec052e1b38c93c21a6d157f789c" -dependencies = [ - "migrations_internals", - "proc-macro2", - "quote", - "syn", -] +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "mime" -version = "0.3.16" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "miniz_oxide" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +dependencies = [ + "adler2", +] [[package]] name = "mio" -version = "0.8.6" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" +checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ "libc", - "log", - "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.45.0", + "wasi", + "windows-sys", ] [[package]] -name = "multer" -version = "2.0.4" +name = "moka" +version = "0.12.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ed4198ce7a4cbd2a57af78d28c6fbb57d81ac5f1d6ad79ac6c5587419cbdf22" +checksum = "32cf62eb4dd975d2dde76432fb1075c49e3ee2331cf36f1f8fd4b66550d32b6f" dependencies = [ - "bytes", - "encoding_rs", + "async-lock", + "async-trait", + "crossbeam-channel", + "crossbeam-epoch", + "crossbeam-utils", + "event-listener", "futures-util", - "http", - "httparse", - "log", - "memchr", - "mime", - "spin", - "tokio", - "tokio-util", - "version_check", -] - -[[package]] -name = "nibble_vec" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43" -dependencies = [ + "once_cell", + "parking_lot", + "quanta", + "rustc_version", "smallvec", -] - -[[package]] -name = "nomilo" -version = "0.1.0-dev" -dependencies = [ - "argon2", - "base64 0.21.0", - "chrono", - "clap", - "diesel", - "diesel-derive-enum", - "diesel_migrations", - "figment", - "futures-util", - "humantime", - "rand", - "rocket", - "rocket_sync_db_pools", - "serde", - "serde_json", - "tera", - "time 0.3.19", - "tokio", - "trust-dns-client", - "trust-dns-proto", + "tagptr", + "thiserror", + "triomphe", "uuid", ] [[package]] -name = "nu-ansi-term" -version = "0.46.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +name = "nomilo" +version = "0.2.0-dev" dependencies = [ - "overload", - "winapi", + "async-trait", + "axum", + "bb8", + "domain", + "rusqlite", + "serde", + "serde_json", + "tokio", ] [[package]] -name = "num-integer" -version = "0.1.45" +name = "num-conv" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "object" +version = "0.36.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" dependencies = [ - "autocfg", - "num-traits", + "memchr", ] [[package]] -name = "num-traits" -version = "0.2.15" +name = "octseq" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "126c3ca37c9c44cec575247f43a3e4374d8927684f129d2beeb0d2cef262fe12" dependencies = [ - "autocfg", -] - -[[package]] -name = "num_cpus" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" -dependencies = [ - "hermit-abi 0.2.6", - "libc", + "bytes", + "smallvec", ] [[package]] name = "once_cell" -version = "1.17.1" +version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] -name = "opaque-debug" -version = "0.3.0" +name = "parking" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" - -[[package]] -name = "openssl" -version = "0.10.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b102428fd03bc5edf97f62620f7298614c45cedf287c271e7ed450bbaf83f2e1" -dependencies = [ - "bitflags", - "cfg-if", - "foreign-types", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "openssl-sys" -version = "0.9.80" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23bbbf7854cd45b83958ebe919f0e8e516793727652e27fda10a8384cfc790b7" -dependencies = [ - "autocfg", - "cc", - "libc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "os_str_bytes" -version = "6.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee" - -[[package]] -name = "overload" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "parking_lot" -version = "0.12.1" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", "parking_lot_core", @@ -1230,106 +616,28 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.7" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-sys 0.45.0", -] - -[[package]] -name = "password-hash" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" -dependencies = [ - "base64ct", - "rand_core", - "subtle", -] - -[[package]] -name = "pear" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15e44241c5e4c868e3eaa78b7c1848cadd6344ed4f54d029832d32b415a58702" -dependencies = [ - "inlinable_string", - "pear_codegen", - "yansi", -] - -[[package]] -name = "pear_codegen" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82a5ca643c2303ecb740d506539deba189e16f2754040a42901cd8105d0282d0" -dependencies = [ - "proc-macro2", - "proc-macro2-diagnostics", - "quote", - "syn", + "windows-targets", ] [[package]] name = "percent-encoding" -version = "2.2.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" - -[[package]] -name = "pest" -version = "2.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "028accff104c4e513bad663bbcd2ad7cfd5304144404c31ed0a77ac103d00660" -dependencies = [ - "thiserror", - "ucd-trie", -] - -[[package]] -name = "pest_derive" -version = "2.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ac3922aac69a40733080f53c1ce7f91dcf57e1a5f6c52f421fadec7fbdc4b69" -dependencies = [ - "pest", - "pest_generator", -] - -[[package]] -name = "pest_generator" -version = "2.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d06646e185566b5961b4058dd107e0a7f56e77c3f484549fb119867773c0f202" -dependencies = [ - "pest", - "pest_meta", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "pest_meta" -version = "2.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6f60b2ba541577e2a0c307c8f39d1439108120eb7903adeb6497fa880c59616" -dependencies = [ - "once_cell", - "pest", - "sha2", -] +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pin-project-lite" -version = "0.2.9" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" [[package]] name = "pin-utils" @@ -1339,104 +647,58 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.26" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] -name = "polyval" -version = "0.6.0" +name = "powerfmt" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef234e08c11dfcb2e56f79fd70f6f2eb7f025c0ce2333e82f4f0518ecad30c6" -dependencies = [ - "cfg-if", - "cpufeatures", - "opaque-debug", - "universal-hash", -] +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" - -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", + "zerocopy", ] [[package]] name = "proc-macro2" -version = "1.0.51" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] [[package]] -name = "proc-macro2-diagnostics" -version = "0.9.1" +name = "quanta" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bf29726d67464d49fa6224a1d07936a8c08bb3fba727c7493f6cf1616fdaada" +checksum = "8e5167a477619228a0b284fac2674e3c388cba90631d7b7de620e6f1fcd08da5" dependencies = [ - "proc-macro2", - "quote", - "syn", - "version_check", - "yansi", + "crossbeam-utils", + "libc", + "once_cell", + "raw-cpuid", + "wasi", + "web-sys", + "winapi", ] [[package]] name = "quote" -version = "1.0.23" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] -[[package]] -name = "r2d2" -version = "0.8.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51de85fb3fb6524929c8a2eb85e6b6d363de4e8c48f9e2c2eac4944abc181c93" -dependencies = [ - "log", - "parking_lot", - "scheduled-thread-pool", -] - -[[package]] -name = "radix_trie" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd" -dependencies = [ - "endian-type", - "nibble_vec", -] - [[package]] name = "rand" version = "0.8.5" @@ -1468,237 +730,105 @@ dependencies = [ ] [[package]] -name = "redox_syscall" -version = "0.2.16" +name = "raw-cpuid" +version = "11.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +checksum = "1ab240315c661615f2ee9f0f2cd32d5a7343a84d5ebcccb99d46e6637565e7b0" dependencies = [ "bitflags", ] [[package]] -name = "ref-cast" -version = "1.0.14" +name = "redox_syscall" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c78fb8c9293bcd48ef6fce7b4ca950ceaf21210de6e105a883ee280c0f7b9ed" +checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" dependencies = [ - "ref-cast-impl", + "bitflags", ] [[package]] -name = "ref-cast-impl" -version = "1.0.14" +name = "ring" +version = "0.17.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f9c0c92af03644e4806106281fe2e068ac5bc0ae74a707266d06ea27bccee5f" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ - "proc-macro2", - "quote", - "syn", + "cc", + "cfg-if", + "getrandom", + "libc", + "spin", + "untrusted", + "windows-sys", ] [[package]] -name = "regex" -version = "1.7.1" +name = "rusqlite" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" +checksum = "7753b721174eb8ff87a9a0e799e2d7bc3749323e773db92e0984debb00019d6e" dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" -dependencies = [ - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.6.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" - -[[package]] -name = "remove_dir_all" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" -dependencies = [ - "winapi", -] - -[[package]] -name = "rocket" -version = "0.5.0-rc.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98ead083fce4a405feb349cf09abdf64471c6077f14e0ce59364aa90d4b99317" -dependencies = [ - "async-stream", - "async-trait", - "atomic", - "atty", - "binascii", - "bytes", - "either", - "figment", - "futures", - "indexmap", - "log", - "memchr", - "multer", - "num_cpus", - "parking_lot", - "pin-project-lite", - "rand", - "ref-cast", - "rocket_codegen", - "rocket_http", - "serde", - "serde_json", - "state", - "tempfile", - "time 0.3.19", - "tokio", - "tokio-stream", - "tokio-util", - "ubyte", - "version_check", - "yansi", -] - -[[package]] -name = "rocket_codegen" -version = "0.5.0-rc.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6aeb6bb9c61e9cd2c00d70ea267bf36f76a4cc615e5908b349c2f9d93999b47" -dependencies = [ - "devise", - "glob", - "indexmap", - "proc-macro2", - "quote", - "rocket_http", - "syn", - "unicode-xid", -] - -[[package]] -name = "rocket_http" -version = "0.5.0-rc.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ded65d127954de3c12471630bf4b81a2792f065984461e65b91d0fdaafc17a2" -dependencies = [ - "cookie", - "either", - "futures", - "http", - "hyper", - "indexmap", - "log", - "memchr", - "pear", - "percent-encoding", - "pin-project-lite", - "ref-cast", - "serde", + "bitflags", + "fallible-iterator", + "fallible-streaming-iterator", + "hashlink", + "libsqlite3-sys", "smallvec", - "stable-pattern", - "state", - "time 0.3.19", - "tokio", - "uncased", ] [[package]] -name = "rocket_sync_db_pools" -version = "0.1.0-rc.2" +name = "rustc-demangle" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fa48b6ab25013e9812f1b0c592741900b3a2a83c0936292e0565c0ac842f558" -dependencies = [ - "diesel", - "r2d2", - "rocket", - "rocket_sync_db_pools_codegen", - "serde", - "tokio", -] +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] -name = "rocket_sync_db_pools_codegen" -version = "0.1.0-rc.2" +name = "rustc_version" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "280ef2d232923e69cb93da156972eb5476a7cce5ba44843f6608f46a4abf7aab" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ - "devise", - "quote", + "semver", ] [[package]] name = "rustversion" -version = "1.0.11" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5583e89e108996506031660fe09baa5011b9dd0341b89029313006d1fb508d70" +checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" [[package]] name = "ryu" -version = "1.0.12" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "scheduled-thread-pool" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "977a7519bff143a44f842fd07e80ad1329295bd71686457f18e496736f4bf9bf" -dependencies = [ - "parking_lot", -] - -[[package]] -name = "scoped-tls" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "scopeguard" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] -name = "scratch" -version = "1.0.3" +name = "semver" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddccb15bcce173023b3fedd9436f882a0739b8dfb45e4f6b6002bee5929f61b2" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "serde" -version = "1.0.152" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.152" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" dependencies = [ "proc-macro2", "quote", @@ -1707,110 +837,80 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.93" +version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cad406b69c91885b5107daf2c29572f6c8cdb3c66826821e286c533490c0bc76" +checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_path_to_error" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af99884400da37c88f5e9146b7f1fd0fbcae8f6eec4e9da38b67d05486f814a6" +dependencies = [ + "itoa", + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", "itoa", "ryu", "serde", ] [[package]] -name = "sha2" -version = "0.10.6" +name = "shlex" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" -dependencies = [ - "cfg-if", - "cpufeatures", - "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", -] +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "slab" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ "autocfg", ] [[package]] name = "smallvec" -version = "1.10.0" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "socket2" -version = "0.4.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" +checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" dependencies = [ "libc", - "winapi", + "windows-sys", ] [[package]] name = "spin" -version = "0.9.5" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dccf47db1b41fa1573ed27ccf5e08e3ca771cb994f776668c5ebda893b248fc" - -[[package]] -name = "stable-pattern" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4564168c00635f88eaed410d5efa8131afa8d8699a612c80c455a0ba05c21045" -dependencies = [ - "memchr", -] - -[[package]] -name = "state" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbe866e1e51e8260c9eed836a042a5e7f6726bb2b411dffeaa712e19c388f23b" -dependencies = [ - "loom", -] - -[[package]] -name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - -[[package]] -name = "subtle" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" [[package]] name = "syn" -version = "1.0.107" +version = "2.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" +checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" dependencies = [ "proc-macro2", "quote", @@ -1818,157 +918,78 @@ dependencies = [ ] [[package]] -name = "tempfile" -version = "3.3.0" +name = "sync_wrapper" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" -dependencies = [ - "cfg-if", - "fastrand", - "libc", - "redox_syscall", - "remove_dir_all", - "winapi", -] +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" [[package]] -name = "tera" -version = "1.17.1" +name = "tagptr" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3df578c295f9ec044ff1c829daf31bb7581d5b3c2a7a3d87419afe1f2531438c" -dependencies = [ - "globwalk", - "lazy_static", - "pest", - "pest_derive", - "regex", - "serde", - "serde_json", - "unic-segment", -] - -[[package]] -name = "termcolor" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "textwrap" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" +checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" [[package]] name = "thiserror" -version = "1.0.38" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.38" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" 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", -] - [[package]] name = "time" -version = "0.1.45" +version = "0.3.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" +checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" dependencies = [ - "libc", - "wasi 0.10.0+wasi-snapshot-preview1", - "winapi", -] - -[[package]] -name = "time" -version = "0.3.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53250a3b3fed8ff8fd988587d8925d26a83ac3845d9e03b220b37f34c2b8d6c2" -dependencies = [ - "itoa", + "deranged", + "num-conv", + "powerfmt", "serde", "time-core", - "time-macros", ] [[package]] name = "time-core" -version = "0.1.0" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" - -[[package]] -name = "time-macros" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a460aeb8de6dcb0f381e1ee05f1cd56fcf5a5f6eb8187ff3d8f0b11078d38b7c" -dependencies = [ - "time-core", -] - -[[package]] -name = "tinyvec" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "tokio" -version = "1.25.0" +version = "1.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8e00990ebabbe4c14c08aca901caed183ecd5c09562a12c824bb53d3c3fd3af" +checksum = "5cec9b21b0450273377fc97bd4c33a8acffc8c996c987a7c5b319a0083707551" dependencies = [ - "autocfg", + "backtrace", "bytes", "libc", - "memchr", "mio", - "num_cpus", + "parking_lot", "pin-project-lite", - "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys 0.42.0", + "windows-sys", ] [[package]] name = "tokio-macros" -version = "1.8.2" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", @@ -1976,51 +997,38 @@ dependencies = [ ] [[package]] -name = "tokio-stream" -version = "0.1.12" +name = "tower" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fb52b74f05dbf495a8fba459fdc331812b96aa086d9eb78101fa0d4569c3313" +checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" dependencies = [ "futures-core", + "futures-util", "pin-project-lite", + "sync_wrapper", "tokio", + "tower-layer", + "tower-service", ] [[package]] -name = "tokio-util" -version = "0.7.7" +name = "tower-layer" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5427d89453009325de0d8f342c9490009f76e999cb7672d77e46267448f7e6b2" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "toml" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" -dependencies = [ - "serde", -] +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" [[package]] name = "tower-service" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.37" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ - "cfg-if", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -2028,9 +1036,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.23" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", @@ -2039,247 +1047,40 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.30" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" dependencies = [ "once_cell", - "valuable", ] [[package]] -name = "tracing-log" -version = "0.1.3" +name = "triomphe" +version = "0.1.11" 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.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70" -dependencies = [ - "matchers", - "nu-ansi-term", - "once_cell", - "regex", - "sharded-slab", - "smallvec", - "thread_local", - "tracing", - "tracing-core", - "tracing-log", -] - -[[package]] -name = "trust-dns-client" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c408c32e6a9dbb38037cece35740f2cf23c875d8ca134d33631cec83f74d3fe" -dependencies = [ - "cfg-if", - "data-encoding", - "futures-channel", - "futures-util", - "lazy_static", - "openssl", - "radix_trie", - "rand", - "thiserror", - "time 0.3.19", - "tokio", - "tracing", - "trust-dns-proto", -] - -[[package]] -name = "trust-dns-proto" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f7f83d1e4a0e4358ac54c5c3681e5d7da5efc5a7a632c90bb6d6669ddd9bc26" -dependencies = [ - "async-trait", - "cfg-if", - "data-encoding", - "enum-as-inner", - "futures-channel", - "futures-io", - "futures-util", - "idna 0.2.3", - "ipnet", - "lazy_static", - "openssl", - "rand", - "smallvec", - "thiserror", - "tinyvec", - "tokio", - "tracing", - "url", -] - -[[package]] -name = "try-lock" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" - -[[package]] -name = "typenum" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" - -[[package]] -name = "ubyte" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c81f0dae7d286ad0d9366d7679a77934cfc3cf3a8d67e82669794412b2368fe6" -dependencies = [ - "serde", -] - -[[package]] -name = "ucd-trie" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81" - -[[package]] -name = "uncased" -version = "0.9.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09b01702b0fd0b3fadcf98e098780badda8742d4f4a7676615cad90e8ac73622" -dependencies = [ - "serde", - "version_check", -] - -[[package]] -name = "unic-char-property" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221" -dependencies = [ - "unic-char-range", -] - -[[package]] -name = "unic-char-range" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc" - -[[package]] -name = "unic-common" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" - -[[package]] -name = "unic-segment" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4ed5d26be57f84f176157270c112ef57b86debac9cd21daaabbe56db0f88f23" -dependencies = [ - "unic-ucd-segment", -] - -[[package]] -name = "unic-ucd-segment" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2079c122a62205b421f499da10f3ee0f7697f012f55b675e002483c73ea34700" -dependencies = [ - "unic-char-property", - "unic-char-range", - "unic-ucd-version", -] - -[[package]] -name = "unic-ucd-version" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4" -dependencies = [ - "unic-common", -] - -[[package]] -name = "unicode-bidi" -version = "0.3.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54675592c1dbefd78cbd98db9bacd89886e1ca50692a0692baefffdeb92dd58" +checksum = "859eb650cfee7434994602c3a68b25d77ad9e68c8a6cd491616ef86661382eb3" [[package]] name = "unicode-ident" -version = "1.0.6" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] -name = "unicode-normalization" -version = "0.1.22" +name = "untrusted" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "unicode-width" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" - -[[package]] -name = "unicode-xid" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" - -[[package]] -name = "universal-hash" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d3160b73c9a19f7e2939a2fdad446c57c1bbbbf4d919d3213ff1267a580d8b5" -dependencies = [ - "crypto-common", - "subtle", -] - -[[package]] -name = "url" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" -dependencies = [ - "form_urlencoded", - "idna 0.3.0", - "percent-encoding", -] +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "uuid" -version = "0.8.2" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" +checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" dependencies = [ "getrandom", - "serde", ] -[[package]] -name = "valuable" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" - [[package]] name = "vcpkg" version = "0.2.15" @@ -2288,36 +1089,9 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "walkdir" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" -dependencies = [ - "same-file", - "winapi", - "winapi-util", -] - -[[package]] -name = "want" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" -dependencies = [ - "log", - "try-lock", -] - -[[package]] -name = "wasi" -version = "0.10.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "wasi" @@ -2327,23 +1101,23 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.84" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" +checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396" dependencies = [ "cfg-if", + "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.84" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" +checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79" dependencies = [ "bumpalo", "log", - "once_cell", "proc-macro2", "quote", "syn", @@ -2352,9 +1126,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.84" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" +checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2362,9 +1136,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.84" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" +checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" dependencies = [ "proc-macro2", "quote", @@ -2375,9 +1149,19 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.84" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" +checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6" + +[[package]] +name = "web-sys" +version = "0.3.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04dd7223427d52553d3702c004d3b2fe07c148165faa56313cb00211e31c12bc" +dependencies = [ + "js-sys", + "wasm-bindgen", +] [[package]] name = "winapi" @@ -2395,147 +1179,102 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -[[package]] -name = "winapi-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] - [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows" -version = "0.39.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1c4bd0a50ac6020f65184721f758dba47bb9fbc2133df715ec74a237b26794a" -dependencies = [ - "windows_aarch64_msvc 0.39.0", - "windows_i686_gnu 0.39.0", - "windows_i686_msvc 0.39.0", - "windows_x86_64_gnu 0.39.0", - "windows_x86_64_msvc 0.39.0", -] - [[package]] name = "windows-sys" -version = "0.42.0" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc 0.42.1", - "windows_i686_gnu 0.42.1", - "windows_i686_msvc 0.42.1", - "windows_x86_64_gnu 0.42.1", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc 0.42.1", -] - -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ "windows-targets", ] [[package]] name = "windows-targets" -version = "0.42.1" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ "windows_aarch64_gnullvm", - "windows_aarch64_msvc 0.42.1", - "windows_i686_gnu 0.42.1", - "windows_i686_msvc 0.42.1", - "windows_x86_64_gnu 0.42.1", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", "windows_x86_64_gnullvm", - "windows_x86_64_msvc 0.42.1", + "windows_x86_64_msvc", ] [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.1" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" -version = "0.39.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec7711666096bd4096ffa835238905bb33fb87267910e154b18b44eaabb340f2" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" -version = "0.39.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "763fc57100a5f7042e3057e7e8d9bdd7860d330070251a73d003563a3bb49e1b" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] -name = "windows_i686_gnu" -version = "0.42.1" +name = "windows_i686_gnullvm" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" -version = "0.39.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bc7cbfe58828921e10a9f446fcaaf649204dcfe6c1ddd712c5eebae6bda1106" - -[[package]] -name = "windows_i686_msvc" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" -version = "0.39.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6868c165637d653ae1e8dc4d82c25d4f97dd6605eaa8d784b5c6e0ab2a252b65" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" -version = "0.42.1" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" -version = "0.39.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e4d40883ae9cae962787ca76ba76390ffa29214667a111db9e0a1ad8377e809" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] -name = "windows_x86_64_msvc" -version = "0.42.1" +name = "zerocopy" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] [[package]] -name = "yansi" -version = "0.5.1" +name = "zerocopy-derive" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/Cargo.toml b/Cargo.toml index 8b52435..478fedb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,35 +1,26 @@ [package] name = "nomilo" -version = "0.1.0-dev" -authors = ["DNS Witch Collective "] +version = "0.2.0-dev" +authors = ["DNS Witch Collective "] edition = "2021" license = "AGPL-3.0-or-later" readme = "README.md" repository = "https://git.familier.net.eu.org/dns-witch/nomilo" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [dependencies] -trust-dns-client = { version = "0.22", features = ["dnssec-openssl"] } -trust-dns-proto = "0.22" + serde = { version = "1", features = ["derive"] } serde_json = "1" -rocket = { version = "0.5.0-rc.2", features = ["json"], default-features = false } -rocket_sync_db_pools = { default-features = false, features = ["diesel_sqlite_pool"], version = "0.1.0-rc.2"} -base64 = "0.21" -uuid = { version = "0.8", features = ["v4", "serde"] } -diesel = { version = "1.4", features = ["sqlite", "chrono"] } -diesel_migrations = "1.4" -diesel-derive-enum = { version = "1", features = ["sqlite"] } -chrono = { version = "0.4", features = ["serde"] } -humantime = "2.1" -tokio = "1" -figment = { version = "0.10", features = ["toml", "env"] } -clap = {version = "3", features = ["derive", "cargo"]} -argon2 = {version = "0.4", default-features = false, features = ["alloc", "password-hash"] } -rand = "0.8" -tera = {version = "1", default-features = false} -# From trust-dns-client -futures-util = { version = "0.3", default-features = false, features = ["std"] } -# From rocket / cookie-rs -time = "0.3" +#uuid = { version = "1.11", features = ["v4", "serde"] } +#chrono = { version = "0.4", features = ["serde"] } +#humantime = "2.1" +tokio = {version = "1", default-features = false, features = [ "macros", "rt-multi-thread" ] } +#clap = { version = "4", features = [ "derive", "cargo" ] } +#argon2 = { version = "0.5", default-features = false, features = ["alloc", "password-hash"] } +#rand = "0.8" +#tera = { version = "1", default-features = false } +domain = { version = "0.10.3", features = [ "tsig", "unstable-client-transport" ]} +axum = { version = "0.8.0-alpha.1", default-features = false, features = [ "http1", "json", "form", "query", "tokio" ]} +bb8 = { version = "0.9" } +rusqlite = { version = "0.32"} +async-trait = { version = "0.1" } diff --git a/dev-scripts/docker-compose.yml b/dev-scripts/docker-compose.yml index 5738e1c..c7cb154 100644 --- a/dev-scripts/docker-compose.yml +++ b/dev-scripts/docker-compose.yml @@ -1,8 +1,16 @@ services: + knot: - image: cznic/knot + image: cznic/knot:3.4 volumes: - ./zones:/storage/zones:ro - ./config:/config:ro - command: knotd + command: knotd --verbose + network_mode: host + named: + image: internetsystemsconsortium/bind9:9.20 + volumes: + - ./zones:/var/lib/bind:ro + - ./config:/etc/bind:ro + #command: named -g network_mode: host diff --git a/dev-scripts/zones/example.com.zone b/dev-scripts/zones/example.com.zone index aea8c99..5de5bb0 100644 --- a/dev-scripts/zones/example.com.zone +++ b/dev-scripts/zones/example.com.zone @@ -7,6 +7,7 @@ example.com. IN SOA ns.example.com. admin.example.com. ( ) example.com. 84600 IN NS ns.example.com. +ns.example.com. 84600 IN A 198.51.100.3 srv1.example.com. 600 IN A 198.51.100.3 srv1.example.com. 600 IN AAAA 2001:db8:cafe:bc68::2 diff --git a/src/database.rs b/src/database.rs new file mode 100644 index 0000000..ef3ba34 --- /dev/null +++ b/src/database.rs @@ -0,0 +1,65 @@ +use std::sync::Arc; + +use crate::ressouces::zone::ZoneModel; + +pub trait Db: ZoneModel + Send + Sync {} +pub type BoxedDb = Arc; + +impl Db for sqlite::SqliteDB {} + +pub mod sqlite { + use std::path::PathBuf; + use std::sync::Arc; + + #[derive(Clone)] + pub struct SqliteDB { + pub pool: bb8::Pool + } + + impl SqliteDB { + pub async fn new(path: PathBuf) -> Self { + let pool = bb8::Pool::builder() + .build(SqliteConnManager::new(path)) + .await + .expect("Unable to connect to database"); + + SqliteDB { + pool, + } + } + } + + #[derive(Clone)] + pub struct SqliteConnManager { + path: Arc + } + + impl SqliteConnManager { + pub fn new(path: PathBuf) -> Self { + SqliteConnManager { + path: Arc::new(path) + } + } + } + + impl bb8::ManageConnection for SqliteConnManager { + type Connection = rusqlite::Connection; + type Error = rusqlite::Error; + + async fn connect(&self) -> Result { + let opt = self.clone(); + + tokio::task::spawn_blocking(move || { + rusqlite::Connection::open(opt.path.as_ref()) + }).await.unwrap() + } + + async fn is_valid(&self, conn: &mut Self::Connection) -> Result<(), Self::Error> { + tokio::task::block_in_place(|| conn.execute_batch("")) + } + + fn has_broken(&self, _conn: &mut Self::Connection) -> bool { + false + } + } +} diff --git a/src/dns/dns_connector.rs b/src/dns/dns_connector.rs deleted file mode 100644 index 025eff6..0000000 --- a/src/dns/dns_connector.rs +++ /dev/null @@ -1,271 +0,0 @@ -use trust_dns_proto::DnsHandle; -use trust_dns_client::client::ClientHandle; -use trust_dns_client::rr::{DNSClass, RecordType}; -use trust_dns_client::op::{UpdateMessage, OpCode, MessageType, Message, Query, ResponseCode, Edns}; -use trust_dns_client::error::ClientError; - -use super::{Name, Record, RData}; -use super::client::{ClientResponse, DnsClient}; -use super::connector::{RecordConnector, ZoneConnector, ConnectorError, ConnectorResult}; - - -const MAX_PAYLOAD_LEN: u16 = 1232; - - -#[derive(Debug)] -pub enum DnsConnectorError { - ClientError(ClientError), - ResponceNotOk { - code: ResponseCode, - zone: Name, - }, -} - -pub struct DnsConnectorClient { - client: DnsClient -} - -impl DnsConnectorClient { - pub fn new(client: DnsClient) -> Self { - DnsConnectorClient { - client - } - } -} - -impl ConnectorError for DnsConnectorError { - fn zone_name(&self) -> Option { - if let DnsConnectorError::ResponceNotOk { code: _code, zone } = self { - Some(zone.clone()) - } else { - None - } - } - - fn is_proto_error(&self) -> bool { - return matches!(self, DnsConnectorError::ClientError(_)); - } -} - -impl std::fmt::Display for DnsConnectorError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - DnsConnectorError::ClientError(e) => { - write!(f, "DNS client error: {}", e) - }, - DnsConnectorError::ResponceNotOk { code, zone } => { - write!(f, "Query for zone \"{}\" failed with code \"{}\"", zone, code) - } - } - - } -} - -fn set_edns(message: &mut Message) { - let edns = message.extensions_mut().get_or_insert_with(Edns::new); - edns.set_max_payload(MAX_PAYLOAD_LEN); - edns.set_version(0); -} - -#[async_trait] -impl RecordConnector for DnsConnectorClient { - //type Error = DnsConnectorError; - - async fn get_records(&mut self, zone: Name, class: DNSClass) -> ConnectorResult> - { - let response = { - let query = self.client.query(zone.clone(), class, RecordType::AXFR); - match query.await.map_err(|e| Box::new(DnsConnectorError::ClientError(e))) { - Err(e) => return Err(e), - Ok(v) => v, - } - }; - - if response.response_code() != ResponseCode::NoError { - return Err(Box::new(DnsConnectorError::ResponceNotOk { - code: response.response_code(), - zone: zone, - })); - } - - let answers = response.answers(); - let mut records: Vec<_> = answers.to_vec().into_iter() - .filter(|record| record.data().is_some() && !matches!(record.data().unwrap(), RData::NULL { .. } | RData::DNSSEC(_))) - .collect(); - - // AXFR response ends with SOA, we remove it so it is not doubled in the response. - records.pop(); - Ok(records) - } - - async fn add_records(&mut self, zone: Name, class: DNSClass, new_records: Vec) -> ConnectorResult<()> - { - // Taken from trust_dns_client::op::update_message::append - // The original function can not be used as is because it takes a RecordSet and not a Record list - - let mut zone_query = Query::new(); - zone_query.set_name(zone.clone()) - .set_query_class(class) - .set_query_type(RecordType::SOA); - - let mut message = Message::new(); - - // TODO: set random / time based id - message - .set_id(0) - .set_message_type(MessageType::Query) - .set_op_code(OpCode::Update) - .set_recursion_desired(false); - message.add_zone(zone_query); - message.add_updates(new_records); - - set_edns(&mut message); - - let response = match ClientResponse(self.client.send(message)).await.map_err(|e| Box::new(DnsConnectorError::ClientError(e))) { - Err(e) => return Err(e), - Ok(v) => v, - }; - - if response.response_code() != ResponseCode::NoError { - return Err(Box::new(DnsConnectorError::ResponceNotOk { - code: response.response_code(), - zone: zone, - })); - } - - Ok(()) - } - - async fn update_records(&mut self, zone: Name, class: DNSClass, old_records: Vec, new_records: Vec) -> ConnectorResult<()> - { - // Taken from trust_dns_client::op::update_message::compare_and_swap - // The original function can not be used as is because it takes a RecordSet and not a Record list - - // for updates, the query section is used for the zone - let mut zone_query = Query::new(); - zone_query.set_name(zone.clone()) - .set_query_class(class) - .set_query_type(RecordType::SOA); - - let mut message: Message = Message::new(); - - // build the message - // TODO: set random / time based id - message - .set_id(0) - .set_message_type(MessageType::Query) - .set_op_code(OpCode::Update) - .set_recursion_desired(false); - message.add_zone(zone_query); - - // make sure the record is what is expected - let mut prerequisite = old_records.clone(); - for record in prerequisite.iter_mut() { - record.set_ttl(0); - } - message.add_pre_requisites(prerequisite); - - // add the delete for the old record - let mut delete = old_records; - for record in delete.iter_mut() { - // the class must be none for delete - record.set_dns_class(DNSClass::NONE); - // the TTL should be 0 - record.set_ttl(0); - } - message.add_updates(delete); - - // insert the new record... - message.add_updates(new_records); - - // Extended dns - set_edns(&mut message); - - let response = match ClientResponse(self.client.send(message)).await.map_err(|e| Box::new(DnsConnectorError::ClientError(e))) { - Err(e) => return Err(e), - Ok(v) => v, - }; - - if response.response_code() != ResponseCode::NoError { - return Err(Box::new(DnsConnectorError::ResponceNotOk { - code: response.response_code(), - zone: zone, - })); - } - - Ok(()) - } - - async fn delete_records(&mut self, zone: Name, class: DNSClass, records: Vec) -> ConnectorResult<()> - { - // for updates, the query section is used for the zone - let mut zone_query = Query::new(); - zone_query.set_name(zone.clone()) - .set_query_class(class) - .set_query_type(RecordType::SOA); - - let mut message: Message = Message::new(); - - // build the message - // TODO: set random / time based id - message - .set_id(0) - .set_message_type(MessageType::Query) - .set_op_code(OpCode::Update) - .set_recursion_desired(false); - message.add_zone(zone_query); - - let mut delete = records; - for record in delete.iter_mut() { - // the class must be none for delete - record.set_dns_class(DNSClass::NONE); - // the TTL should be 0 - record.set_ttl(0); - } - message.add_updates(delete); - - // Extended dns - set_edns(&mut message); - - let response = match ClientResponse(self.client.send(message)).await.map_err(|e| Box::new(DnsConnectorError::ClientError(e))) { - Err(e) => return Err(e), - Ok(v) => v, - }; - - if response.response_code() != ResponseCode::NoError { - return Err(Box::new(DnsConnectorError::ResponceNotOk { - code: response.response_code(), - zone: zone, - })); - } - - Ok(()) - - } -} - - -#[async_trait] -impl ZoneConnector for DnsConnectorClient { - async fn zone_exists(&mut self, zone: Name, class: DNSClass) -> ConnectorResult<()> - { - let response = { - info!("Querying SOA for name {}", zone); - let query = self.client.query(zone.clone(), class, RecordType::SOA); - match query.await.map_err(|e| Box::new(DnsConnectorError::ClientError(e))) { - Err(e) => return Err(e), - Ok(v) => v, - } - }; - - if response.response_code() != ResponseCode::NoError { - return Err(Box::new(DnsConnectorError::ResponceNotOk { - code: response.response_code(), - zone: zone, - })); - } - - Ok(()) - } - -} diff --git a/src/dns/dns_driver.rs b/src/dns/dns_driver.rs new file mode 100644 index 0000000..5f1181b --- /dev/null +++ b/src/dns/dns_driver.rs @@ -0,0 +1,569 @@ +use std::io; +use std::net::SocketAddr; +use std::time::Duration; +use std::sync::Arc; + +use domain::base::iana::{Opcode, Rcode}; +use domain::base::{message_builder, name, wire}; +use domain::base::{MessageBuilder, Name, Rtype}; +use domain::net::client::{tsig, stream}; +use domain::tsig::{Algorithm, Key, KeyName}; +use domain::net::client::request::{self, RequestMessage, RequestMessageMulti, SendRequest, SendRequestMulti}; +use tokio::net::TcpStream; + +use super::{rdata, record}; +use super::{RecordDriver, ZoneDriver, DnsDriverError}; +use crate::errors::Error; + +use async_trait::async_trait; + +pub struct DnsDriverConfig { + pub address: SocketAddr, + pub tsig: Option +} + +pub struct TsigConfig { + pub key_name: KeyName, + pub secret: Vec, + pub algorithm: Algorithm +} + +#[derive(Clone)] +pub struct DnsDriver { + pub addr: SocketAddr, + pub tsig_key: Option>, +} + +type TsigDnsClient = tsig::Connection>, Arc>, + tsig::RequestMessage>, Arc> +>, Arc>; + +impl DnsDriver { + pub fn from_config(config: DnsDriverConfig) -> Self { + let key = config.tsig.map(|tsig_config| { + Arc::new( + Key::new( + tsig_config.algorithm, + &tsig_config.secret, + tsig_config.key_name, + None, + None + ).expect("Failed to build key"), + ) + }); + + Self { + addr: config.address, + tsig_key: key, + } + } + + async fn client(&self) -> Result, DnsDriverError> + where + Req: request::ComposeRequest + Send + Sync + 'static, + ReqMulti: request::ComposeRequestMulti + Send + Sync + 'static, + { + let mut stream_config = stream::Config::default(); + stream_config.set_response_timeout( + Duration::from_millis(100), + ); + let tcp_connect = TcpStream::connect(self.addr).await?; + + let (tcp_conn, transport) = stream::Connection::with_config( + tcp_connect, stream_config + ); + + tokio::spawn(transport.run()); + + Ok(tcp_conn) + } + + async fn tsig_client(&self) -> Result, DnsDriverError> + { + if let Some(ref key) = self.tsig_key { + let conn = self.client().await?; + Ok(Some(tsig::Connection::new(key.clone(), conn))) + } else { + Ok(None) + } + } +} + +#[async_trait] +impl ZoneDriver for DnsDriver { + async fn zone_exists(&self, zone: &str) -> Result<(), DnsDriverError> { + let client = self.client::<_, RequestMessageMulti>>().await?; + + let mut msg = MessageBuilder::new_vec().question(); + msg.push(( + Name::vec_from_str(zone)?, + Rtype::SOA, + ))?; + + let req = RequestMessage::new(msg)?; + + let res = SendRequest::send_request(&client, req) + .get_response() + .await?; + + let rcode = res.header().rcode(); + + match rcode { + Rcode::NOERROR => Ok(()), + Rcode::NXDOMAIN | Rcode::REFUSED => Err(DnsDriverError::ZoneNotFound { + name: zone.to_string(), + }), + rcode => Err(DnsDriverError::ServerError { + rcode: rcode.to_string(), + name: zone.to_string(), + qtype: Rtype::SOA.to_string() + }) + } + } +} + +#[async_trait] +impl RecordDriver for DnsDriver { + /// ------------- AXFR ------------- + + async fn get_records(&self, zone: &str) -> Result, DnsDriverError> { + let mut msg = MessageBuilder::new_vec(); + msg.header_mut().set_ad(true); + + let mut msg = msg.question(); + msg.push(( + Name::vec_from_str(zone)?, + Rtype::AXFR, + ))?; + + let req = RequestMessageMulti::new(msg)?; + + let tsig_client = self.tsig_client().await?; + + let mut request = if let Some(client) = tsig_client { + SendRequestMulti::send_request(&client, req) + } else { + let client = self.client::>,_>().await?; + SendRequestMulti::send_request(&client, req) + }; + + let mut records = Vec::new(); + + while let Some(reply) = request.get_response().await? { + let rcode = reply.header().rcode(); + + if rcode != Rcode::NOERROR { + return Err(DnsDriverError::ServerError { + rcode: rcode.to_string(), + name: zone.to_string(), + qtype: Rtype::AXFR.to_string() + }); + } + + let answer = reply.answer()?; + + for record in answer.limit_to::>() { + let record = record?; + records.push(record.into()) + } + } + + // AXFR response ends with SOA, we remove it so it is not doubled in the response. + records.pop(); + + Ok(records) + } + + /// ------------- Dynamic Update - RFC 2136 ------------- + /// + /// 2 - Update Message Format + /// +---------------------+ + /// | Header | + /// +---------------------+ + /// | Zone | specifies the zone to be updated (RFC1035 Question) + /// +---------------------+ + /// | Prerequisite | RRs or RRsets which must (not) preexist (RFC1035 Answer) + /// +---------------------+ + /// | Update | RRs or RRsets to be added or deleted (RFC1035 Authority) + /// +---------------------+ + /// | Additional Data | additional data + /// +---------------------+ + /// 2.2 - Message Header + /// + /// OPCODE is set to UPDATE. + /// UPDATE uses only one flag bit (QR). + /// + /// 2.3 - Zone Section + /// + /// The ZNAME is the zone name, the ZTYPE must be SOA, and the ZCLASS is + /// the zone's class. + /// + /// 3.2.4 - Table Of Metavalues Used In Prerequisite Section + /// + /// TTL must be specified as zero (0) for all prerequisite + /// + /// CLASS TYPE RDATA Meaning + /// ------------------------------------------------------------ + /// ANY ANY empty Name is in use + /// ANY rrset empty RRset exists (value independent) + /// NONE ANY empty Name is not in use + /// NONE rrset empty RRset does not exist + /// zone rrset rr RRset exists (value dependent) - Match against ALL RR in a RRset!! + /// + /// 3.4.2.6 - Table Of Metavalues Used In Update Section + /// + /// CLASS TYPE RDATA Meaning + /// --------------------------------------------------------- + /// ANY ANY empty Delete all RRsets from a name - TTL must be specified as zero (0) + /// ANY rrset empty Delete an RRset - TTL must be specified as zero (0) + /// NONE rrset rr Delete an RR from an RRset - TTL must be specified as zero (0) + /// zone rrset rr Add to an RRset + + + async fn add_records(&self, zone: &str, new_records: &[record::DnsRecordImpl]) -> Result<(), DnsDriverError> { + let mut msg = MessageBuilder::new_vec(); + msg.header_mut().set_opcode(Opcode::UPDATE); + + let mut msg = msg.question(); + msg.push(( + Name::vec_from_str(zone)?, + Rtype::SOA, + ))?; + + let mut msg = msg.authority(); + + for record in new_records { + msg.push(record)?; + } + + let req = RequestMessage::new(msg)?; + + let tsig_client = self.tsig_client().await?; + + let mut request = if let Some(client) = tsig_client { + SendRequest::send_request(&client, req) + } else { + let client = self.client::<_, RequestMessageMulti>>().await?; + SendRequest::send_request(&client, req) + }; + + let reply = request.get_response().await?; + let rcode = reply.header().rcode(); + + if rcode != Rcode::NOERROR { + Err(DnsDriverError::ServerError { + rcode: rcode.to_string(), + name: zone.to_string(), + qtype: "UPDATE".to_string(), + }) + } else { + Ok(()) + } + + } +} + +impl From for DnsDriverError { + fn from(value: io::Error) -> Self { + DnsDriverError::ConnectionError { reason: Box::new(value) } + } +} + +impl From for DnsDriverError { + fn from(value: request::Error) -> Self { + DnsDriverError::ConnectionError { reason: Box::new(value) } + } +} + +impl From for DnsDriverError { + fn from(value: message_builder::PushError) -> Self { + DnsDriverError::OperationError { reason: Box::new(value) } + } +} + +impl From for DnsDriverError { + fn from(value: name::FromStrError) -> Self { + DnsDriverError::OperationError { reason: Box::new(value) } + } +} + +impl From for DnsDriverError { + fn from(value: wire::ParseError) -> Self { + DnsDriverError::OperationError { reason: Box::new(value) } + } +} + +/* +use trust_dns_proto::DnsHandle; +use trust_dns_client::client::ClientHandle; +use trust_dns_client::rr::{DNSClass, RecordType}; +use trust_dns_client::op::{UpdateMessage, OpCode, MessageType, Message, Query, ResponseCode, Edns}; +use trust_dns_client::error::ClientError; + +use super::{Name, Record, RData}; +use super::client::{ClientResponse, DnsClient}; +use super::connector::{RecordConnector, ZoneConnector, ConnectorError, ConnectorResult}; + + +const MAX_PAYLOAD_LEN: u16 = 1232; + + +#[derive(Debug)] +pub enum DnsConnectorError { + ClientError(ClientError), + ResponceNotOk { + code: ResponseCode, + zone: Name, + }, +} + +pub struct DnsConnectorClient { + client: DnsClient +} + +impl DnsConnectorClient { + pub fn new(client: DnsClient) -> Self { + DnsConnectorClient { + client + } + } +} + +impl ConnectorError for DnsConnectorError { + fn zone_name(&self) -> Option { + if let DnsConnectorError::ResponceNotOk { code: _code, zone } = self { + Some(zone.clone()) + } else { + None + } + } + + fn is_proto_error(&self) -> bool { + return matches!(self, DnsConnectorError::ClientError(_)); + } +} + +impl std::fmt::Display for DnsConnectorError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + DnsConnectorError::ClientError(e) => { + write!(f, "DNS client error: {}", e) + }, + DnsConnectorError::ResponceNotOk { code, zone } => { + write!(f, "Query for zone \"{}\" failed with code \"{}\"", zone, code) + } + } + + } +} + +fn set_edns(message: &mut Message) { + let edns = message.extensions_mut().get_or_insert_with(Edns::new); + edns.set_max_payload(MAX_PAYLOAD_LEN); + edns.set_version(0); +} + +#[async_trait] +impl RecordConnector for DnsConnectorClient { + //type Error = DnsConnectorError; + + async fn get_records(&mut self, zone: Name, class: DNSClass) -> ConnectorResult> + { + let response = { + let query = self.client.query(zone.clone(), class, RecordType::AXFR); + match query.await.map_err(|e| Box::new(DnsConnectorError::ClientError(e))) { + Err(e) => return Err(e), + Ok(v) => v, + } + }; + + if response.response_code() != ResponseCode::NoError { + return Err(Box::new(DnsConnectorError::ResponceNotOk { + code: response.response_code(), + zone: zone, + })); + } + + let answers = response.answers(); + let mut records: Vec<_> = answers.to_vec().into_iter() + .filter(|record| record.data().is_some() && !matches!(record.data().unwrap(), RData::NULL { .. } | RData::DNSSEC(_))) + .collect(); + + // AXFR response ends with SOA, we remove it so it is not doubled in the response. + records.pop(); + Ok(records) + } + + async fn add_records(&mut self, zone: Name, class: DNSClass, new_records: Vec) -> ConnectorResult<()> + { + // Taken from trust_dns_client::op::update_message::append + // The original function can not be used as is because it takes a RecordSet and not a Record list + + let mut zone_query = Query::new(); + zone_query.set_name(zone.clone()) + .set_query_class(class) + .set_query_type(RecordType::SOA); + + let mut message = Message::new(); + + // TODO: set random / time based id + message + .set_id(0) + .set_message_type(MessageType::Query) + .set_op_code(OpCode::Update) + .set_recursion_desired(false); + message.add_zone(zone_query); + message.add_updates(new_records); + + set_edns(&mut message); + + let response = match ClientResponse(self.client.send(message)).await.map_err(|e| Box::new(DnsConnectorError::ClientError(e))) { + Err(e) => return Err(e), + Ok(v) => v, + }; + + if response.response_code() != ResponseCode::NoError { + return Err(Box::new(DnsConnectorError::ResponceNotOk { + code: response.response_code(), + zone: zone, + })); + } + + Ok(()) + } + + async fn update_records(&mut self, zone: Name, class: DNSClass, old_records: Vec, new_records: Vec) -> ConnectorResult<()> + { + // Taken from trust_dns_client::op::update_message::compare_and_swap + // The original function can not be used as is because it takes a RecordSet and not a Record list + + // for updates, the query section is used for the zone + let mut zone_query = Query::new(); + zone_query.set_name(zone.clone()) + .set_query_class(class) + .set_query_type(RecordType::SOA); + + let mut message: Message = Message::new(); + + // build the message + // TODO: set random / time based id + message + .set_id(0) + .set_message_type(MessageType::Query) + .set_op_code(OpCode::Update) + .set_recursion_desired(false); + message.add_zone(zone_query); + + // make sure the record is what is expected + let mut prerequisite = old_records.clone(); + for record in prerequisite.iter_mut() { + record.set_ttl(0); + } + message.add_pre_requisites(prerequisite); + + // add the delete for the old record + let mut delete = old_records; + for record in delete.iter_mut() { + // the class must be none for delete + record.set_dns_class(DNSClass::NONE); + // the TTL should be 0 + record.set_ttl(0); + } + message.add_updates(delete); + + // insert the new record... + message.add_updates(new_records); + + // Extended dns + set_edns(&mut message); + + let response = match ClientResponse(self.client.send(message)).await.map_err(|e| Box::new(DnsConnectorError::ClientError(e))) { + Err(e) => return Err(e), + Ok(v) => v, + }; + + if response.response_code() != ResponseCode::NoError { + return Err(Box::new(DnsConnectorError::ResponceNotOk { + code: response.response_code(), + zone: zone, + })); + } + + Ok(()) + } + + async fn delete_records(&mut self, zone: Name, class: DNSClass, records: Vec) -> ConnectorResult<()> + { + // for updates, the query section is used for the zone + let mut zone_query = Query::new(); + zone_query.set_name(zone.clone()) + .set_query_class(class) + .set_query_type(RecordType::SOA); + + let mut message: Message = Message::new(); + + // build the message + // TODO: set random / time based id + message + .set_id(0) + .set_message_type(MessageType::Query) + .set_op_code(OpCode::Update) + .set_recursion_desired(false); + message.add_zone(zone_query); + + let mut delete = records; + for record in delete.iter_mut() { + // the class must be none for delete + record.set_dns_class(DNSClass::NONE); + // the TTL should be 0 + record.set_ttl(0); + } + message.add_updates(delete); + + // Extended dns + set_edns(&mut message); + + let response = match ClientResponse(self.client.send(message)).await.map_err(|e| Box::new(DnsConnectorError::ClientError(e))) { + Err(e) => return Err(e), + Ok(v) => v, + }; + + if response.response_code() != ResponseCode::NoError { + return Err(Box::new(DnsConnectorError::ResponceNotOk { + code: response.response_code(), + zone: zone, + })); + } + + Ok(()) + + } +} + + +#[async_trait] +impl ZoneConnector for DnsConnectorClient { + async fn zone_exists(&mut self, zone: Name, class: DNSClass) -> ConnectorResult<()> + { + let response = { + info!("Querying SOA for name {}", zone); + let query = self.client.query(zone.clone(), class, RecordType::SOA); + match query.await.map_err(|e| Box::new(DnsConnectorError::ClientError(e))) { + Err(e) => return Err(e), + Ok(v) => v, + } + }; + + if response.response_code() != ResponseCode::NoError { + return Err(Box::new(DnsConnectorError::ResponceNotOk { + code: response.response_code(), + zone: zone, + })); + } + + Ok(()) + } + +} +*/ diff --git a/src/dns/mod.rs b/src/dns/mod.rs index 48c6e8b..f00c618 100644 --- a/src/dns/mod.rs +++ b/src/dns/mod.rs @@ -1,3 +1,37 @@ +pub mod rdata; +pub mod record; +pub mod dns_driver; + +use std::sync::Arc; + +use async_trait::async_trait; + +pub type BoxedZoneDriver = Arc; +pub enum DnsDriverError { + ConnectionError { reason: Box }, + OperationError { reason: Box }, + ServerError { rcode: String, name: String, qtype: String }, + ZoneNotFound { name: String }, +} + +#[async_trait] +pub trait ZoneDriver: Send + Sync { + // get_zones + // add_zone + // delete_zone + async fn zone_exists(&self, zone: &str) -> Result<(), DnsDriverError>; +} + +#[async_trait] +pub trait RecordDriver: Send + Sync { + async fn get_records(&self, zone: &str) -> Result, DnsDriverError>; + async fn add_records(&self, zone: &str, new_records: &[record::DnsRecordImpl]) -> Result<(), DnsDriverError>; + //async fn update_records(&mut self, zone: dns::Name, class: dns::DNSClass, old_records: Vec, new_records: Vec) -> ConnectorResult<()>; + //async fn delete_records(&mut self, zone: dns::Name, class: dns::DNSClass, records: Vec) -> ConnectorResult<()>; + +} + +/* pub mod client; pub mod dns_connector; pub mod connector; @@ -53,3 +87,4 @@ impl<'r> FromRequest<'r> for Box { } } } +*/ diff --git a/src/dns/rdata.rs b/src/dns/rdata.rs new file mode 100644 index 0000000..0ad5f67 --- /dev/null +++ b/src/dns/rdata.rs @@ -0,0 +1,528 @@ +use std::fmt::Write; +use std::net::{Ipv4Addr, Ipv6Addr}; + +use domain::base::rdata::ComposeRecordData; +use domain::base::scan::Symbol; +use domain::base::wire::{Composer, ParseError}; +use domain::base::{Name, ParseRecordData, ParsedName, RecordData, Rtype, ToName, Ttl}; +use domain::rdata; +use domain::dep::octseq::{Parser, Octets}; +use serde::{Deserialize, Serialize}; + +use crate::errors::Error; +use crate::validation; + +use crate::macros::{append_errors, push_error}; +use super::record::RecordParseError; + +/// Type used to serialize / deserialize resource records data to response / request +/// +#[derive(Debug, Deserialize, Serialize)] +#[serde(tag = "type", content = "rdata")] +#[serde(rename_all = "UPPERCASE")] +pub enum RData { + A(A), + Aaaa(Aaaa), + // TODO: CAA + Cname(Cname), + // TODO: DS + Mx(Mx), + Ns(Ns), + Ptr(Ptr), + Soa(Soa), + Srv(Srv), + // TODO: SSHFP + // TODO: SVCB / HTTPS + // TODO: TLSA + Txt(Txt), +} + +pub enum ParsedRData { + A(rdata::A), + Aaaa(rdata::Aaaa), + Cname(rdata::Cname), + Mx(rdata::Mx), + Ns(rdata::Ns), + Ptr(rdata::Ptr), + Soa(rdata::Soa), + Srv(rdata::Srv), + Txt(rdata::Txt), +} + +impl> From> for RData { + fn from(value: ParsedRData) -> Self { + match value { + ParsedRData::A(record_rdata) => RData::A(record_rdata.into()), + ParsedRData::Aaaa(record_rdata) => RData::Aaaa(record_rdata.into()), + ParsedRData::Cname(record_rdata) => RData::Cname(record_rdata.into()), + ParsedRData::Mx(record_rdata) => RData::Mx(record_rdata.into()), + ParsedRData::Ns(record_rdata) => RData::Ns(record_rdata.into()), + ParsedRData::Ptr(record_rdata) => RData::Ptr(record_rdata.into()), + ParsedRData::Soa(record_rdata) => RData::Soa(record_rdata.into()), + ParsedRData::Srv(record_rdata) => RData::Srv(record_rdata.into()), + ParsedRData::Txt(record_rdata) => RData::Txt(record_rdata.into()), + } + } +} + +impl TryFrom for ParsedRData>, Vec> { + type Error = Vec; + + fn try_from(value: RData) -> Result { + let rdata = match value { + RData::A(record_rdata) => ParsedRData::A(record_rdata.parse_record()?), + RData::Aaaa(record_rdata) => ParsedRData::Aaaa(record_rdata.parse_record()?), + RData::Cname(record_rdata) => ParsedRData::Cname(record_rdata.parse_record()?), + RData::Mx(record_rdata) => ParsedRData::Mx(record_rdata.parse_record()?), + RData::Ns(record_rdata) => ParsedRData::Ns(record_rdata.parse_record()?), + RData::Ptr(record_rdata) => ParsedRData::Ptr(record_rdata.parse_record()?), + RData::Soa(record_rdata) => ParsedRData::Soa(record_rdata.parse_record()?), + RData::Srv(record_rdata) => ParsedRData::Srv(record_rdata.parse_record()?), + RData::Txt(record_rdata) => ParsedRData::Txt(record_rdata.parse_record()?), + }; + Ok(rdata) + } +} + + + +macro_rules! parse_name { + ($value:expr, $field:ident, $rtype:literal, $errors:expr) => { + { + let name = push_error!( + validation::normalize_domain(&$value.$field), + $errors, concat!("/", stringify!($field)) + ); + + let name = name.and_then(|name| { + push_error!( + name.parse::>().map_err(|e| { + Error::from(RecordParseError::RDataUnknown { + input: $value.$field, + field: stringify!(field).to_string(), + rtype: $rtype.to_string(), + }).with_cause(&e.to_string()) + }), + $errors, concat!("/", stringify!($field)) + ) + }); + + name + } + }; +} + +/* --------- A --------- */ + +#[derive(Debug, Deserialize, Serialize)] +pub struct A { + pub address: String, +} + +impl From for A { + fn from(record_data: rdata::A) -> Self { + A { address: record_data.addr().to_string() } + } +} + +impl A { + pub fn parse_record(self) -> Result> { + let mut errors = Vec::new(); + + let address = push_error!(self.address.parse::().map_err(|e| { + Error::from(RecordParseError::Ip4Address { input: self.address }) + .with_cause(&e.to_string()) + .with_path("/address") + }), errors); + + if errors.is_empty() { + Ok(rdata::A::new(address.unwrap())) + } else { + Err(errors) + } + } +} + +/* --------- AAAA --------- */ + +#[derive(Debug, Deserialize, Serialize)] +pub struct Aaaa { + pub address: String, +} + +impl From for Aaaa { + fn from(record_data: rdata::Aaaa) -> Self { + Aaaa { address: record_data.addr().to_string() } + } +} + +impl Aaaa { + pub fn parse_record(self) -> Result> { + let mut errors = Vec::new(); + + let address = push_error!(self.address.parse::().map_err(|e| { + Error::from(RecordParseError::Ip6Address { input: self.address }) + .with_cause(&e.to_string()) + .with_path("/address") + }), errors); + + if errors.is_empty() { + Ok(rdata::Aaaa::new(address.unwrap())) + } else { + Err(errors) + } + } +} + +/* --------- CNAME --------- */ + +#[derive(Debug, Deserialize, Serialize)] +pub struct Cname { + pub target: String, +} + +impl From> for Cname { + fn from(record_data: rdata::Cname) -> Self { + Cname { target: record_data.cname().to_string() } + } +} + +impl Cname { + pub fn parse_record(self) -> Result>>, Vec> { + let mut errors = Vec::new(); + + let cname = parse_name!(self, target, "CNAME", errors); + + if errors.is_empty() { + Ok(rdata::Cname::new(cname.unwrap())) + } else { + Err(errors) + } + + } +} + +/* --------- MX --------- */ + +#[derive(Debug, Deserialize, Serialize)] +pub struct Mx { + pub preference: u16, + pub mail_exchanger: String, +} + +impl From> for Mx { + fn from(record_data: rdata::Mx) -> Self { + Mx { + preference: record_data.preference(), + mail_exchanger: record_data.exchange().to_string() + } + } +} + +impl Mx { + fn parse_record(self) -> Result>>, Vec> { + let mut errors = Vec::new(); + + let mail_exchanger = parse_name!(self, mail_exchanger, "MX", errors); + + if errors.is_empty() { + Ok(rdata::Mx::new(self.preference, mail_exchanger.unwrap())) + } else { + Err(errors) + } + } +} + +/* --------- NS --------- */ + +#[derive(Debug, Deserialize, Serialize)] +pub struct Ns { + pub target: String, +} + +impl From> for Ns { + fn from(record_rdata: rdata::Ns) -> Self { + Ns { + target: record_rdata.nsdname().to_string(), + } + } +} + +impl Ns { + fn parse_record(self) -> Result>>, Vec> { + let mut errors = Vec::new(); + + let ns_name = parse_name!(self, target, "NS", errors); + + if errors.is_empty() { + Ok(rdata::Ns::new(ns_name.unwrap())) + } else { + Err(errors) + } + } +} + +/* --------- PTR --------- */ + +#[derive(Debug, Deserialize, Serialize)] +pub struct Ptr { + pub target: String, +} + +impl From> for Ptr { + fn from(record_rdata: rdata::Ptr) -> Self { + Ptr { + target: record_rdata.ptrdname().to_string(), + } + } +} + +impl Ptr { + fn parse_record(self) -> Result>>, Vec> { + let mut errors = Vec::new(); + + let ptr_name = parse_name!(self, target, "PTR", errors); + + if errors.is_empty() { + Ok(rdata::Ptr::new(ptr_name.unwrap())) + } else { + Err(errors) + } + } +} + +/* --------- SOA --------- */ + +#[derive(Debug, Deserialize, Serialize)] +pub struct Soa { + pub primary_server: String, + pub maintainer: String, + pub refresh: u32, + pub retry: u32, + pub expire: u32, + pub minimum: u32, + pub serial: u32, +} + +impl From> for Soa { + fn from(record_rdata: rdata::Soa) -> Self { + Soa { + primary_server: record_rdata.mname().to_string(), + maintainer: record_rdata.rname().to_string(), + refresh: record_rdata.refresh().as_secs(), + retry: record_rdata.retry().as_secs(), + expire: record_rdata.expire().as_secs(), + minimum: record_rdata.minimum().as_secs(), + serial: record_rdata.serial().into(), + } + } +} + +impl Soa { + fn parse_record(self) -> Result>>, Vec> { + let mut errors = Vec::new(); + + let primary_ns = parse_name!(self, primary_server, "SOA", errors); + let maintainer = parse_name!(self, maintainer, "SOA", errors); + + if errors.is_empty() { + Ok(rdata::Soa::new( + primary_ns.unwrap(), + maintainer.unwrap(), + self.refresh.into(), + Ttl::from_secs(self.retry), + Ttl::from_secs(self.expire), + Ttl::from_secs(self.minimum), + Ttl::from_secs(self.serial), + )) + } else { + Err(errors) + } + } +} + +/* --------- SRV --------- */ + +#[derive(Debug, Deserialize, Serialize)] +pub struct Srv { + pub server: String, + pub port: u16, + pub priority: u16, + pub weight: u16, +} + +impl From> for Srv { + fn from(record_data: rdata::Srv) -> Self { + Srv { + server: record_data.target().to_string(), + priority: record_data.priority(), + weight: record_data.weight(), + port: record_data.port(), + } + } +} + +impl Srv { + fn parse_record(self) -> Result>>, Vec> { + let mut errors = Vec::new(); + + let server = parse_name!(self, server, "SRV", errors); + + if errors.is_empty() { + Ok(rdata::Srv::new( + self.priority, + self.weight, + self.port, + server.unwrap(), + )) + } else { + Err(errors) + } + } +} + + +/* --------- TXT --------- */ + +#[derive(Debug, Deserialize, Serialize)] +pub struct Txt { + pub text: String, +} + +impl> From> for Txt { + fn from(record_data: rdata::Txt) -> Self { + let mut concatenated_text = String::new(); + for text in record_data.iter() { + for c in text { + // Escapes '\' and non printable chars + let c = Symbol::display_from_octet(*c); + write!(concatenated_text, "{}", c).unwrap(); + } + } + + Txt { + text: concatenated_text + } + } +} + +impl Txt { + fn parse_record(self) -> Result>, Vec> { + let mut errors = Vec::new(); + let data = append_errors!(validation::parse_txt_data(&self.text), errors, "/text"); + let data = data.and_then(|data| { + push_error!(rdata::Txt::build_from_slice(&data).map_err(|e| { + Error::from(RecordParseError::RDataUnknown { + input: self.text, + field: "text".into(), + rtype: "TXT".into(), + }).with_cause(&e.to_string()) + .with_path("/text") + }), errors) + }); + + + + if errors.is_empty() { + Ok(data.unwrap()) + } else { + Err(errors) + } + } +} + +/* --------- ParsedRData: domain traits impl --------- */ + +impl ParsedRData { + pub fn rtype(&self) -> Rtype { + match self { + ParsedRData::A(_) => Rtype::A, + ParsedRData::Aaaa(_) => Rtype::AAAA, + ParsedRData::Cname(_) => Rtype::CNAME, + ParsedRData::Mx(_) => Rtype::MX, + ParsedRData::Ns(_) => Rtype::NS, + ParsedRData::Ptr(_) => Rtype::PTR, + ParsedRData::Soa(_) => Rtype::SOA, + ParsedRData::Srv(_) => Rtype::SRV, + ParsedRData::Txt(_) => Rtype::TXT, + } + } +} + +impl RecordData for ParsedRData { + fn rtype(&self) -> Rtype { + ParsedRData::rtype(self) + } +} + +impl<'a, Octs: Octets + ?Sized> ParseRecordData<'a, Octs> for ParsedRData>, Octs::Range<'a>> { + fn parse_rdata( + rtype: Rtype, + parser: &mut Parser<'a, Octs>, + ) -> Result, ParseError> { + let record = match rtype { + Rtype::A => ParsedRData::A(rdata::A::parse(parser)?), + Rtype::AAAA => ParsedRData::Aaaa(rdata::Aaaa::parse(parser)?), + Rtype::CNAME => ParsedRData::Cname(rdata::Cname::parse(parser)?), + Rtype::MX => ParsedRData::Mx(rdata::Mx::parse(parser)?), + Rtype::NS => ParsedRData::Ns(rdata::Ns::parse(parser)?), + Rtype::PTR => ParsedRData::Ptr(rdata::Ptr::parse(parser)?), + Rtype::SOA => ParsedRData::Soa(rdata::Soa::parse(parser)?), + Rtype::SRV => ParsedRData::Srv(rdata::Srv::parse(parser)?), + Rtype::TXT => ParsedRData::Txt(rdata::Txt::parse(parser)?), + _ => return Ok(None) + }; + + Ok(Some(record)) + } +} + +impl> ComposeRecordData for ParsedRData { + fn rdlen(&self, compress: bool) -> Option { + match self { + ParsedRData::A(record_rdata) => record_rdata.rdlen(compress), + ParsedRData::Aaaa(record_rdata) => record_rdata.rdlen(compress), + ParsedRData::Cname(record_rdata) => record_rdata.rdlen(compress), + ParsedRData::Mx(record_rdata) => record_rdata.rdlen(compress), + ParsedRData::Ns(record_rdata) => record_rdata.rdlen(compress), + ParsedRData::Ptr(record_rdata) => record_rdata.rdlen(compress), + ParsedRData::Soa(record_rdata) => record_rdata.rdlen(compress), + ParsedRData::Srv(record_rdata) => record_rdata.rdlen(compress), + ParsedRData::Txt(record_rdata) => record_rdata.rdlen(compress), + } + } + + fn compose_rdata( + &self, + target: &mut Target, + ) -> Result<(), Target::AppendError> { + match self { + ParsedRData::A(record_rdata) => record_rdata.compose_rdata(target), + ParsedRData::Aaaa(record_rdata) => record_rdata.compose_rdata(target), + ParsedRData::Cname(record_rdata) => record_rdata.compose_rdata(target), + ParsedRData::Mx(record_rdata) => record_rdata.compose_rdata(target), + ParsedRData::Ns(record_rdata) => record_rdata.compose_rdata(target), + ParsedRData::Ptr(record_rdata) => record_rdata.compose_rdata(target), + ParsedRData::Soa(record_rdata) => record_rdata.compose_rdata(target), + ParsedRData::Srv(record_rdata) => record_rdata.compose_rdata(target), + ParsedRData::Txt(record_rdata) => record_rdata.compose_rdata(target), + } + } + + fn compose_canonical_rdata( + &self, + target: &mut Target, + ) -> Result<(), Target::AppendError> { + match self { + ParsedRData::A(record_rdata) => record_rdata.compose_canonical_rdata(target), + ParsedRData::Aaaa(record_rdata) => record_rdata.compose_canonical_rdata(target), + ParsedRData::Cname(record_rdata) => record_rdata.compose_canonical_rdata(target), + ParsedRData::Mx(record_rdata) => record_rdata.compose_canonical_rdata(target), + ParsedRData::Ns(record_rdata) => record_rdata.compose_canonical_rdata(target), + ParsedRData::Ptr(record_rdata) => record_rdata.compose_canonical_rdata(target), + ParsedRData::Soa(record_rdata) => record_rdata.compose_canonical_rdata(target), + ParsedRData::Srv(record_rdata) => record_rdata.compose_canonical_rdata(target), + ParsedRData::Txt(record_rdata) => record_rdata.compose_canonical_rdata(target), + } + } +} diff --git a/src/dns/record.rs b/src/dns/record.rs new file mode 100644 index 0000000..4de8cbc --- /dev/null +++ b/src/dns/record.rs @@ -0,0 +1,128 @@ +use serde::{Deserialize, Serialize}; + +use domain::base::{iana::Class, Name, Record as DnsRecord, Ttl}; + +use crate::{errors::Error, validation}; +use crate::macros::{append_errors, push_error}; +use super::rdata::{ParsedRData, RData}; + +pub enum RecordParseError { + Ip4Address { input: String }, + Ip6Address { input: String }, + RDataUnknown { input: String, field: String, rtype: String }, + NameUnknown { input: String }, + NotInZone { name: String, zone: String }, +} + +pub enum RecordError { + Validation { suberrors: Vec }, +} + +pub(crate) type DnsRecordImpl = DnsRecord< + Name>, + ParsedRData>,Vec> +>; + +#[derive(Debug, Deserialize, Serialize)] +pub struct Record { + pub name: String, + pub ttl: u32, + #[serde(flatten)] + pub rdata: RData +} + +impl> From>> for Record { + fn from(value: DnsRecord>) -> Self { + Record { + name: value.owner().to_string(), + ttl: value.ttl().as_secs(), + rdata: value.into_data().into(), + } + } +} + +impl Record { + fn convert(self, zone_name: &Name>) -> Result> { + let mut errors = Vec::new(); + + let name = push_error!(validation::normalize_domain(&self.name), errors, "/name"); + + let name = name.and_then(|name| push_error!(name.parse::>().map_err(|e| { + Error::from(RecordParseError::NameUnknown { + input: self.name.clone() + }).with_cause(&e.to_string()) + }), errors, "/name")); + + let name = name.and_then(|name| { + if !name.ends_with(zone_name) { + errors.push( + Error::from(RecordParseError::NotInZone { name: self.name, zone: zone_name.to_string() }) + .with_path("/name") + ); + None + } else { + Some(name) + } + }); + + let ttl = Ttl::from_secs(self.ttl); + let rdata = append_errors!(ParsedRData::try_from(self.rdata), errors, "/rdata"); + + if errors.is_empty() { + Ok(DnsRecord::new(name.unwrap(), Class::IN, ttl, rdata.unwrap())) + } else { + Err(errors) + } + } +} + + +#[derive(Debug, Deserialize)] +pub struct RecordList(Vec); + +impl RecordList { + fn convert(self, zone_name: &Name>) -> Result, Vec> { + let mut errors = Vec::new(); + let mut records = Vec::new(); + + for (index, record) in self.0.into_iter().enumerate() { + let record = append_errors!(record.convert(zone_name), errors, &format!("/{index}")); + + if let Some(record) = record { + records.push(record) + } + } + + if errors.is_empty() { + Ok(records) + } else { + Err(errors) + } + } +} + +#[derive(Debug,Deserialize)] +pub struct AddRecordsRequest { + pub new_records: RecordList +} + +pub struct AddRecords { + pub new_records: Vec +} + +impl AddRecordsRequest { + pub fn validate(self, zone_name: &str) -> Result { + let zone_name: Name> = zone_name.parse().expect("zone name is assumed to be valid"); + + let mut errors = Vec::new(); + let records = append_errors!(self.new_records.convert(&zone_name), errors, "/new_records"); + + if errors.is_empty() { + Ok(AddRecords { + new_records: records.unwrap(), + }) + } else { + Err(Error::from(RecordError::Validation { suberrors: errors })) + } + } +} diff --git a/src/errors.rs b/src/errors.rs new file mode 100644 index 0000000..9d456e4 --- /dev/null +++ b/src/errors.rs @@ -0,0 +1,370 @@ +use std::fmt; + +use axum::http::{self, StatusCode}; +use axum::response::{AppendHeaders, IntoResponse, Response}; + +use axum::Json; +use serde::{Serialize, Serializer}; +use serde_json::{Value, json}; + +use crate::dns::{DnsDriverError, ZoneDriver}; +use crate::dns::record::{RecordError, RecordParseError}; +use crate::ressouces::zone::ZoneError; +use crate::validation::{DomainValidationError, TxtParseError}; + +#[derive(Debug, Serialize)] +pub struct Error { + #[serde(skip)] + cause: Option, + #[serde(skip_serializing_if = "Option::is_none", serialize_with = "serialize_status")] + status: Option, + code: String, + description: String, + #[serde(skip_serializing_if = "Option::is_none")] + details: Option, + #[serde(skip_serializing_if = "Option::is_none")] + path: Option, + #[serde(skip_serializing_if = "Option::is_none")] + errors: Option>, +} + +pub fn serialize_status(status: &Option, serializer: S) -> Result + where S: Serializer +{ + if let Some(status) = status { + serializer.serialize_u16(status.as_u16()) + } else { + serializer.serialize_unit() + } +} + +impl Error { + pub fn new(code: &str, description: &str) -> Self { + Error { + cause: None, + status: None, + code: code.into(), + description: description.into(), + details: None, + path: None, + errors: None + } + } + + pub fn with_cause(self, cause: &str) -> Self { + Self { + cause: Some(cause.into()), + ..self + } + } + + pub fn with_status(self, status: StatusCode) -> Self { + Self { + status: Some(status), + ..self + } + } + + pub fn with_path(self, path: &str) -> Self { + if let Some(current_path) = self.path { + Self { + path: Some(format!("{path}{current_path}")), + ..self + } + } else { + Self { + path: Some(path.into()), + ..self + } + } + } + + pub fn with_details (self, details: T) -> Self { + let mut new_details = serde_json::to_value(details).expect("failed to convert details to serde_json::Value"); + let details = self.details; + + // append new details to existing details + if let Some(mut details) = details { + if let Some(object) = details.as_object_mut() { + if let Some(new_object) = new_details.as_object_mut() { + object.append(new_object); + + return Self { + details: Some(details), + ..self + } + } + } + } + + Self { + details: Some(new_details), + ..self + } + + } + + pub fn with_suberrors(self, mut errors: Vec) -> Self { + for error in &mut errors { + error.status = None; + } + + Self { + errors: Some(errors), + ..self + } + } + + pub fn override_status(self, status: StatusCode) -> Self { + if self.status.is_some() { + self.with_status(status) + } else { + self + } + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.description)?; + + if let Some(cause) = &self.cause { + write!(f, ": {}", cause)?; + } + + if self.status.is_some() || self.details.is_some() { + write!(f, " (")?; + } + + if let Some(status) = &self.status { + write!(f, "status = {}", status)?; + } + + if let Some(details) = &self.details { + if self.status.is_some() { + write!(f, ", ")?; + } + write!(f, "details = {}", serde_json::to_string(details).expect("Failed to serialize error details"))?; + } + + if self.status.is_some() || self.details.is_some() { + write!(f, ")")?; + } + + Ok(()) + } +} + +impl IntoResponse for Error { + fn into_response(self) -> Response { + if let Some(status) = self.status { + (status, Json(self)).into_response() + } else { + eprintln!("{}", self); + ( + StatusCode::INTERNAL_SERVER_ERROR, + AppendHeaders([ + (http::header::CONTENT_TYPE, "application/json") + ]), + r#"{"status": 500,"description":"Internal server error","code":"internal"}"# + ).into_response() + } + } +} + +impl From> for Error { + fn from(value: bb8::RunError) -> Self { + Error::new("db:pool", "Failed to get database connection from pool") + .with_cause(&value.to_string()) + } +} + +impl From for Error { + fn from(value: rusqlite::Error) -> Self { + Error::new("db:sqlite", "Sqlite failure") + .with_cause(&format!("{:?}", value)) + } +} + +impl From for Error { + fn from(value: ZoneError) -> Self { + match value { + ZoneError::ZoneConflict { name } => { + Error::new("zone:conflict", "Zone {zone_name} already exists") + .with_details(json!({ + "zone_name": name + })) + .with_status(StatusCode::CONFLICT) + }, + ZoneError::NotFound { name } => { + Error::new("zone:not_found", "The zone {zone_name} could not be found") + .with_details(json!({ + "zone_name": name + })) + .with_status(StatusCode::NOT_FOUND) + }, + ZoneError::Validation { suberrors } => { + Error::new("zone:validation", "Error while validating zone input data") + .with_suberrors(suberrors) + .with_status(StatusCode::BAD_REQUEST) + }, + ZoneError::NotExistsNs { name } => { + Error::new("zone:not_exists_ns", "The zone {zone_name} does not exist on the name server") + .with_details(json!({ + "zone_name": name + })) + .with_status(StatusCode::BAD_REQUEST) + } + } + } +} + +impl From for Error { + fn from(value: DomainValidationError) -> Self { + match value { + DomainValidationError::CharactersNotPermitted { label } => { + Error::new("domain:characters_not_permitted", "Domain name label {label} contains characters not permitted. The allowed characters are lowercase alphanumeric characters (a-z and 0-9), the dash ('-'), the underscore ('_') and the forward slash ('/').") + .with_details(json!({ + "label": label + })) + }, + DomainValidationError::EmptyDomain => { + Error::new("domain:empty_domain", "Domain name can not be empty or the root domain ('.')") + }, + DomainValidationError::EmptyLabel => { + Error::new("domain:empty_label", "Domain name contains empty labels (repeated dots)") + }, + DomainValidationError::DomainTooLong { length } => { + Error::new("domain:domain_too_long", "Domain name too long ({length} characters), the maximum length is 255 characters") + .with_details(json!({ + "length": length + })) + }, + DomainValidationError::LabelToolLong { length, label } => { + Error::new("domain:label_too_long", "Domain name label {label} is too long ({label_length} characters), the maximum length is 63 characters") + .with_details(json!({ + "label": label, + "length": length, + })) + }, + } + } +} + +impl From for Error { + fn from(value: TxtParseError) -> Self { + match value { + TxtParseError::BadEscapeDigitIndexTooHigh { sequence } => { + Error::new("record:txt:parse:escape_decimal_index_too_high", "Octect escape sequence should be between 000 and 255. Offending escape sequence: \\{sequence}") + .with_details(json!({ + "sequence": sequence + })) + }, + TxtParseError::BadEscapeDigitsNotDigits { sequence } => { + Error::new("record:txt:parse:escape_decimal_not_digits", "Expected an octect escape sequence due to the presence of a back slash (\\) followed by a digit but found non digit characters. Offending escape sequence: \\{sequence}") + .with_details(json!({ + "sequence": sequence + })) + }, + TxtParseError::BadEscapeDigitsTooShort { sequence } => { + Error::new("record:txt:parse:escape_decimal_too_short", "Expected an octect escape sequence due to the presence of a back slash (\\) followed by a digit but found found {sequence_lenght} characters instead of three. Offending escape sequence: \\{sequence}") + .with_details(json!({ + "sequence": sequence, + "sequence_lenght": sequence.len() + })) + }, + TxtParseError::MissingEscape => { + Error::new("record:txt:parse:escape_missing", "Expected an escape sequence due to the presence of a back slash (\\) at the end of the input but found nothing") + }, + TxtParseError::NonAscii { character } => { + Error::new("record:txt:parse:non_ascii", "Found a non ASCII character ({character}). Only printable ASCII characters are allowed.") + .with_details(json!({ + "character": character + })) + } + } + } +} + + +impl From for Error { + fn from(value: DnsDriverError) -> Self { + + match value { + DnsDriverError::ConnectionError { reason } => { + Error::new("dns:connection", "Error while connecting to the name server") + .with_cause(&reason.to_string()) + }, + DnsDriverError::OperationError { reason } => { + Error::new("dns:operation", "DNS operation error") + .with_cause(&reason.to_string()) + }, + DnsDriverError::ServerError { rcode, name, qtype } => { + Error::new("dns:server", "Unexpected response to query") + .with_details(json!({ + "rcode": rcode, + "name": name, + "qtype": qtype, + })) + }, + DnsDriverError::ZoneNotFound { name } => { + Error::new("dns:zone_not_found", "The zone {zone_name} does not exist on the name server") + .with_details(json!({ + "zone_name": name + })) + } + } + } +} + +impl From for Error { + fn from(value: RecordParseError) -> Self { + match value { + RecordParseError::Ip4Address { input } => { + Error::new("record:parse:ip4", "The following IPv4 address {input} is invalid. IPv4 addresses should have four numbers, each between 0 and 255, separated by dots.") + .with_details(json!({ + "input": input + })) + }, + RecordParseError::Ip6Address { input } => { + Error::new("record:parse:ip6", "The following IPv4 address {input} is invalid. IPv6 addresses should have eight groups of four hexadecimal digit separated by colons. Leftmost zeros in a group can be omitted, sequence of zeros can be shorted by a double colons.") + .with_details(json!({ + "input": input + })) + }, + RecordParseError::RDataUnknown { input, field, rtype } => { + Error::new("record:parse:rdata_unknown", "Unknown error while parsing record rdata field") + .with_details(json!({ + "input": input, + "field": field, + "rtype": rtype, + })) + }, + RecordParseError::NameUnknown { input } => { + Error::new("record:parse:name_unknown", "Unknown error while parsing record name") + .with_details(json!({ + "input": input + })) + }, + RecordParseError::NotInZone { name, zone } => { + Error::new("record:parse:not_in_zone", "The domain name {name} is not in the current zone ({zone})") + .with_details(json!({ + "name": name, + "zone": zone + })) + } + } + } +} + +impl From for Error { + fn from(value: RecordError) -> Self { + match value { + RecordError::Validation { suberrors } => { + Error::new("record:validation", "Error while validating input records") + .with_suberrors(suberrors) + .with_status(StatusCode::BAD_REQUEST) + } + } + } +} diff --git a/src/macros.rs b/src/macros.rs new file mode 100644 index 0000000..5009b76 --- /dev/null +++ b/src/macros.rs @@ -0,0 +1,35 @@ +macro_rules! push_error { + ($value:expr, $errors:expr) => { + match $value { + Err(error) => { $errors.push(error); None }, + Ok(value) => Some(value) + } + }; + ($value:expr, $errors:expr, $path:expr) => { + match $value { + Err(error) => { $errors.push(error.with_path($path)); None }, + Ok(value) => Some(value) + } + }; +} + +macro_rules! append_errors { + ($value:expr, $errors:expr) => { + match $value { + Err(mut err) => { $errors.append(&mut err); None }, + Ok(value) => Some(value) + } + }; + ($value:expr, $errors:expr, $path:expr) => { + match $value { + Err(err) => { $errors.extend(err.into_iter().map(|e| { + e.with_path($path) + })); None }, + Ok(value) => Some(value) + } + }; +} + + +pub(crate) use append_errors; +pub(crate) use push_error; diff --git a/src/main.rs b/src/main.rs index a1c8ffd..c07dbca 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,26 +1,86 @@ -#![feature(proc_macro_hygiene, decl_macro)] - +//#![feature(proc_macro_hygiene, decl_macro)] +/* #[macro_use] extern crate rocket; #[macro_use] extern crate diesel; #[macro_use] extern crate diesel_migrations; +*/ -mod routes; -mod cli; -mod config; +//mod routes; +//mod cli; +//mod config; +//mod models; +//mod schema; +//mod template; +//mod controllers; + +//use std::process::exit; + +//use clap::Parser; +//use figment::{Figment, Profile, providers::{Format, Toml, Env}}; +//use rocket_sync_db_pools::database; +//use diesel::prelude::*; + +mod errors; mod dns; -mod models; -mod schema; -mod template; -mod controllers; +mod routes; +mod ressouces; +mod database; +mod validation; +mod macros; -use std::process::exit; +use std::sync::Arc; -use clap::Parser; -use figment::{Figment, Profile, providers::{Format, Toml, Env}}; -use rocket_sync_db_pools::database; -use diesel::prelude::*; +use axum::Router; +use axum::routing; +use database::sqlite::SqliteDB; +use database::Db; +use dns::dns_driver::DnsDriverConfig; +use dns::dns_driver::TsigConfig; +use dns::{ZoneDriver, RecordDriver}; + +#[derive(Clone)] +pub struct AppState { + zone: Arc, + records: Arc, + db: Arc, +} + + + +#[tokio::main] +async fn main() { + let dns_driver = dns::dns_driver::DnsDriver::from_config(DnsDriverConfig { + address: "127.0.0.1:5353".parse().unwrap(), + tsig: Some(TsigConfig { + key_name: "dev".parse().unwrap(), + secret: domain::utils::base64::decode::>("mbmz4J3Efm1BUjqe12M1RHsOnPjYhKQe+2iKO4tL+a4=").unwrap(), + algorithm: domain::tsig::Algorithm::Sha256, + }) + }); + + let dns_driver = Arc::new(dns_driver); + + let app_state = AppState { + zone: dns_driver.clone(), + records: dns_driver.clone(), + db: Arc::new(SqliteDB::new("db.sqlite".into()).await), + }; + + let app = Router::new() + .route("/admin/zones", routing::post(routes::api::zones::create_zone)) + .route("/zones/{zone_name}/records", routing::get(routes::api::zones::get_zone_records)) + .route("/zones/{zone_name}/records", routing::post(routes::api::zones::create_zone_records)) + .with_state(app_state); + + let listener = tokio::net::TcpListener::bind("127.0.0.1:8000").await.unwrap(); + axum::serve(listener, app).await.unwrap(); +} + + + +/* use crate::cli::{NomiloCli, NomiloCommand}; #[database("sqlite")] @@ -63,3 +123,4 @@ fn main() { let nomilo = NomiloCli::parse(); nomilo.run(figment, app_config); } +*/ diff --git a/src/models/zone.rs b/src/models/zone.rs deleted file mode 100644 index cdad91b..0000000 --- a/src/models/zone.rs +++ /dev/null @@ -1,93 +0,0 @@ -use crate::models::user::UserInfo; - -use uuid::Uuid; -use diesel::prelude::*; -use diesel::result::Error as DieselError; -use serde::{Serialize, Deserialize}; - -use crate::schema::*; -use super::name::AbsoluteName; -use super::user::UserZone; -use super::errors::UserError; - - -#[derive(Debug, Serialize, Queryable, Identifiable, Insertable)] -#[table_name = "zone"] -pub struct Zone { - #[serde(skip)] - pub id: String, - pub name: String, -} - -#[derive(Debug, Deserialize)] -pub struct AddZoneMemberRequest { - pub id: String, -} - -#[derive(Debug, Deserialize, FromForm)] -pub struct CreateZoneRequest { - pub name: AbsoluteName, -} - -// NOTE: Should probably not be implemented here -// also, "UserError" seems like a misleading name -impl Zone { - pub fn get_all(conn: &diesel::SqliteConnection) -> Result, UserError> { - use crate::schema::zone::dsl::*; - - zone.get_results(conn) - .map_err(UserError::DbError) - } - - pub fn get_by_name(conn: &diesel::SqliteConnection, zone_name: &str) -> Result { - use crate::schema::zone::dsl::*; - - zone.filter(name.eq(zone_name)) - .get_result(conn) - .map_err(|e| match e { - DieselError::NotFound => UserError::ZoneNotFound, - other => UserError::DbError(other) - }) - } - - pub fn create_zone(conn: &diesel::SqliteConnection, zone_request: CreateZoneRequest) -> Result { - use crate::schema::zone::dsl::*; - - let new_zone = Zone { - id: Uuid::new_v4().to_simple().to_string(), - name: zone_request.name.to_utf8(), - }; - - diesel::insert_into(zone) - .values(&new_zone) - .execute(conn) - .map_err(|e| match e { - DieselError::DatabaseError(diesel::result::DatabaseErrorKind::UniqueViolation, _) => UserError::UserConflict, - other => UserError::DbError(other) - })?; - Ok(new_zone) - } - - - pub fn add_member(&self, conn: &diesel::SqliteConnection, new_member: &UserInfo) -> Result<(), UserError> { - use crate::schema::user_zone::dsl::*; - - let new_user_zone = UserZone { - zone_id: self.id.clone(), - user_id: new_member.id.clone() - }; - - let res = diesel::insert_into(user_zone) - .values(new_user_zone) - .execute(conn); - - match res { - // If user has already access to the zone, safely ignore the conflit - // TODO: use 'on conflict do nothing' in postgres when we get there - Err(DieselError::DatabaseError(diesel::result::DatabaseErrorKind::UniqueViolation, _)) => (), - Err(e) => return Err(e.into()), - Ok(_) => () - }; - Ok(()) - } -} diff --git a/src/models/class.rs b/src/ressouces/class.rs similarity index 100% rename from src/models/class.rs rename to src/ressouces/class.rs diff --git a/src/models/errors.rs b/src/ressouces/errors.rs similarity index 100% rename from src/models/errors.rs rename to src/ressouces/errors.rs diff --git a/src/models/mod.rs b/src/ressouces/mod.rs similarity index 96% rename from src/models/mod.rs rename to src/ressouces/mod.rs index f200898..a4c95c3 100644 --- a/src/models/mod.rs +++ b/src/ressouces/mod.rs @@ -1,3 +1,4 @@ +/* pub mod class; pub mod errors; pub mod name; @@ -16,3 +17,6 @@ pub use user::{LocalUser, UserInfo, Role, UserZone, User, CreateUserRequest}; pub use rdata::RData; pub use record::{Record, RecordList, ParseRecordList, RecordListParseError, UpdateRecordsRequest}; pub use zone::{Zone, AddZoneMemberRequest, CreateZoneRequest}; +*/ + +pub mod zone; diff --git a/src/models/name.rs b/src/ressouces/name.rs similarity index 100% rename from src/models/name.rs rename to src/ressouces/name.rs diff --git a/src/models/rdata.rs b/src/ressouces/rdata.rs similarity index 100% rename from src/models/rdata.rs rename to src/ressouces/rdata.rs diff --git a/src/models/record.rs b/src/ressouces/record.rs similarity index 100% rename from src/models/record.rs rename to src/ressouces/record.rs diff --git a/src/models/session.rs b/src/ressouces/session.rs similarity index 100% rename from src/models/session.rs rename to src/ressouces/session.rs diff --git a/src/models/user.rs b/src/ressouces/user.rs similarity index 99% rename from src/models/user.rs rename to src/ressouces/user.rs index a7b9219..6c494d0 100644 --- a/src/models/user.rs +++ b/src/ressouces/user.rs @@ -1,3 +1,4 @@ +/* use uuid::Uuid; use diesel::prelude::*; use diesel::result::Error as DieselError; @@ -234,3 +235,4 @@ impl LocalUser { }) } } +*/ diff --git a/src/ressouces/zone.rs b/src/ressouces/zone.rs new file mode 100644 index 0000000..f653635 --- /dev/null +++ b/src/ressouces/zone.rs @@ -0,0 +1,222 @@ +use async_trait::async_trait; +use serde::{Deserialize, Serialize}; +use rusqlite::Error as RusqliteError; + + +use crate::database::{BoxedDb, sqlite::SqliteDB}; +use crate::dns::{BoxedZoneDriver, DnsDriverError}; +use crate::errors::Error; +use crate::macros::push_error; +use crate::validation; + +pub enum ZoneError { + ZoneConflict { name: String }, + NotFound { name: String }, + NotExistsNs { name: String }, + Validation { suberrors: Vec }, +} + +#[derive(Debug, Serialize)] +pub struct Zone { + pub name: String, +} + +impl Zone { + pub async fn create(create_zone: CreateZoneRequest, zone_driver: BoxedZoneDriver, db: BoxedDb) -> Result { + let create_zone = create_zone.validate()?; + + zone_driver.zone_exists(&create_zone.name) + .await + .map_err(|e| { + match e { + DnsDriverError::ZoneNotFound { name } => { + Error::from(ZoneError::NotExistsNs { name }) + .with_path("/name") + }, + e => Error::from(e) + } + })?; + + db.create_zone(create_zone).await + } +} + +#[derive(Deserialize)] +pub struct CreateZoneRequest { + pub name: String +} + +pub struct CreateZone { + pub name: String +} + +impl CreateZoneRequest { + pub fn validate(self) -> Result { + + let mut errors = Vec::new(); + + let name = push_error!(validation::normalize_domain(&self.name), errors, "/name"); + name.ok_or(Error::from(ZoneError::Validation { suberrors: errors })) + .map(|name| { + CreateZone { name } + }) + } +} + +#[async_trait] +pub trait ZoneModel: Send + Sync { + async fn create_zone(&self, create_zone: CreateZone) -> Result; + async fn get_zone_by_name(&self, zone_name: &str) -> Result; +} + +#[async_trait] +impl ZoneModel for SqliteDB { + async fn create_zone(&self, create_zone: CreateZone) -> Result { + let pool = self.pool.clone(); + + let conn = pool.get().await?; + + tokio::task::block_in_place(move || { + let mut stmt = conn.prepare("insert into zones (name) values (?1) returning *")?; + let zone = stmt.query_row((&create_zone.name,), |row| { + Ok(Zone { + name: row.get(0)? + }) + }).map_err(|e| { + match e { + /* SQLITE_CONSTRAINT_PRIMARYKEY */ + RusqliteError::SqliteFailure(e, _) if e.extended_code == 1555 => { + Error::from(ZoneError::ZoneConflict { name: create_zone.name }) + .with_path("/name") + }, + e => Error::new("internal:zone:create", "Failed to create zone") + .with_cause(&e.to_string()) + } + })?; + + Ok(zone) + }) + } + + async fn get_zone_by_name(&self, zone_name: &str) -> Result { + let pool = self.pool.clone(); + + let conn = pool.get().await?; + + tokio::task::block_in_place(move || { + let mut stmt = conn.prepare("select * from zones where name = ?1")?; + let zone = stmt.query_row((zone_name,), |row| { + Ok(Zone { + name: row.get(0)? + }) + }).map_err(|e| { + match e { + RusqliteError::QueryReturnedNoRows => { + Error::from(ZoneError::NotFound { name: zone_name.to_string() }) + }, + e => Error::new("internal:zone:get_by_name", "Failed to fetch zone by name") + .with_cause(&e.to_string()) + } + })?; + + Ok(zone) + }) + } +} + + +/* +use crate::models::user::UserInfo; + +use uuid::Uuid; +use diesel::prelude::*; +use diesel::result::Error as DieselError; +use serde::{Serialize, Deserialize}; + +use crate::schema::*; +use super::name::AbsoluteName; +use super::user::UserZone; +use super::errors::UserError; + + +#[derive(Debug, Serialize, Queryable, Identifiable, Insertable)] +#[table_name = "zone"] +pub struct Zone { + #[serde(skip)] + pub id: String, + pub name: String, +} + +#[derive(Debug, Deserialize)] +pub struct AddZoneMemberRequest { + pub id: String, +} + +#[derive(Debug, Deserialize, FromForm)] +pub struct CreateZoneRequest { + pub name: AbsoluteName, +} + +// NOTE: Should probably not be implemented here +// also, "UserError" seems like a misleading name +impl Zone { + pub fn get_all(conn: &diesel::SqliteConnection) -> Result, UserError> { + use crate::schema::zone::dsl::*; + + zone.get_results(conn) + .map_err(UserError::DbError) + } + + pub fn get_by_name(conn: &diesel::SqliteConnection, zone_name: &str) -> Result { + use crate::schema::zone::dsl::*; + + zone.filter(name.eq(zone_name)) + .get_result(conn) + .map_err(|e| match e { + DieselError::NotFound => UserError::ZoneNotFound, + other => UserError::DbError(other) + }) + } + + pub fn create_zone(conn: &diesel::SqliteConnection, zone_request: CreateZoneRequest) -> Result { + use crate::schema::zone::dsl::*; + + let new_zone = Zone { + id: Uuid::new_v4().to_simple().to_string(), + name: zone_request.name.to_utf8(), + }; + + diesel::insert_into(zone) + .values(&new_zone) + .execute(conn) + .map_err(|e| match e { + DieselError::DatabaseError(diesel::result::DatabaseErrorKind::UniqueViolation, _) => UserError::UserConflict, + other => UserError::DbError(other) + })?; + Ok(new_zone) + } + + + pub fn add_member(&self, conn: &diesel::SqliteConnection, new_member: &UserInfo) -> Result<(), UserError> { + use crate::schema::user_zone::dsl::*; + + let new_user_zone = UserZone { + zone_id: self.id.clone(), + user_id: new_member.id.clone() + }; + + let res = diesel::insert_into(user_zone) + .values(new_user_zone) + .execute(conn); + + match res { + // If user has already access to the zone, safely ignore the conflit + // TODO: use 'on conflict do nothing' in postgres when we get there + Err(DieselError::DatabaseError(diesel::result::DatabaseErrorKind::UniqueViolation, _)) => (), + Err(e) => return Err(e.into()), + Ok(_) => () + }; + Ok(()) + } +} +*/ diff --git a/src/routes/api/mod.rs b/src/routes/api/mod.rs index ab7455e..34fbc16 100644 --- a/src/routes/api/mod.rs +++ b/src/routes/api/mod.rs @@ -1,5 +1,5 @@ -pub mod users; +//pub mod users; pub mod zones; -pub use users::*; -pub use zones::*; +//pub use users::*; +//pub use zones::*; diff --git a/src/routes/api/zones.rs b/src/routes/api/zones.rs index f2cdd73..0741ad7 100644 --- a/src/routes/api/zones.rs +++ b/src/routes/api/zones.rs @@ -1,3 +1,50 @@ +use axum::extract::{Path, State}; +use axum::Json; + +use crate::dns::record::{AddRecordsRequest, Record}; +use crate::AppState; +use crate::errors::Error; +use crate::ressouces::zone::{CreateZoneRequest, Zone}; + + +pub async fn create_zone( + State(app): State, + Json(create_zone): Json, +) -> Result, Error> +{ + Zone::create(create_zone, app.zone, app.db).await.map(Json) +} + +pub async fn get_zone_records( + Path(zone_name): Path, + State(app): State, +) -> Result>, Error> +{ + + let zone = app.db.get_zone_by_name(&zone_name).await?; + let records = app.records.get_records(&zone.name).await?; + + Ok(Json(records)) +} + +pub async fn create_zone_records( + Path(zone_name): Path, + State(app): State, + Json(add_records): Json, +) -> Result>, Error> +{ + + let zone = app.db.get_zone_by_name(&zone_name).await?; + let add_records = add_records.validate(&zone.name)?; + app.records.add_records(&zone.name, &add_records.new_records).await?; + let records = add_records.new_records.into_iter() + .map(|r| r.into()) + .collect(); + + Ok(Json(records)) +} + +/* use rocket::http::Status; use rocket::serde::json::Json; @@ -178,3 +225,4 @@ pub async fn add_member_to_zone<'r>( Ok(Status::Created) // TODO: change this? } +*/ diff --git a/src/routes/mod.rs b/src/routes/mod.rs index 9f43e82..b697dec 100644 --- a/src/routes/mod.rs +++ b/src/routes/mod.rs @@ -1,2 +1,2 @@ -pub mod ui; +//pub mod ui; pub mod api; diff --git a/src/validation.rs b/src/validation.rs new file mode 100644 index 0000000..1f4ac14 --- /dev/null +++ b/src/validation.rs @@ -0,0 +1,116 @@ +use crate::errors::Error; + +pub enum DomainValidationError { + EmptyDomain, + DomainTooLong { length: usize }, + CharactersNotPermitted { label: String }, + LabelToolLong { length: usize, label: String }, + EmptyLabel +} + + +/// Not complete but probably good enough +/// https://doc.zonemaster.fr/v2024.1/specifications/tests/RequirementsAndNormalizationOfDomainNames.html +/// TODO: No support of dots in labels, how to handle RNAME in SOA? +pub fn normalize_domain(domain_name: &str) -> Result { + let domain = domain_name.strip_prefix('.').unwrap_or(domain_name).to_lowercase(); + + if domain.is_empty() { + Err(Error::from(DomainValidationError::EmptyDomain)) + } else if domain.as_bytes().len() > 255 { + Err(Error::from(DomainValidationError::DomainTooLong { length: domain.as_bytes().len() })) + } else { + let labels = domain.split('.').collect::>(); + + if labels.iter().any(|l| l.is_empty()) { + return Err( + Error::from(DomainValidationError::EmptyLabel) + ); + } + + for label in labels { + if !label.chars().all(|c| { + // allow for '/' for reverse zone + c.is_ascii_alphanumeric() || c == '-' || c == '/' || c == '_' + }) { + return Err( + Error::from(DomainValidationError::CharactersNotPermitted { label: label.into() }) + ); + } + + if label.as_bytes().len() > 63 { + return Err(Error::from(DomainValidationError::LabelToolLong { + label: label.into(), + length: label.as_bytes().len() + })); + } + } + + Ok(domain) + } +} +pub enum TxtParseError { + MissingEscape, + NonAscii { character: String }, + BadEscapeDigitsTooShort { sequence: String }, + BadEscapeDigitsNotDigits { sequence: String }, + BadEscapeDigitIndexTooHigh { sequence: String }, +} + +pub fn parse_txt_data(text: &str) -> Result, Vec> { + let mut chars = text.chars(); + let mut errors = Vec::new(); + let mut data = Vec::new(); + + #[inline] + fn printable(ch: char) -> bool { + ch.is_ascii() && ('\u{20}'..='\u{7E}').contains(&ch) + } + + while let Some(ch) = chars.next() { + if ch == '\\' { + match chars.next() { + Some(ch) => { + if ch.is_ascii_digit() { + let mut digits: Vec<_> = chars.by_ref().take(2).collect(); + digits.insert(0, ch); + if digits.len() < 3 { + errors.push(Error::from(TxtParseError::BadEscapeDigitsTooShort { sequence: String::from_iter(digits) })) + } else if digits.iter().all(|c| c.is_ascii_digit()) { + errors.push(Error::from(TxtParseError::BadEscapeDigitsNotDigits { sequence: String::from_iter(digits) })) + } else { + let index = { + digits[0].to_digit(10).unwrap() * 100 + + digits[1].to_digit(10).unwrap() * 10 + + digits[2].to_digit(10).unwrap() + }; + + if index > 255 { + errors.push(Error::from(TxtParseError::BadEscapeDigitIndexTooHigh { sequence: String::from_iter(digits) })) + } + } + } else if printable(ch) { + data.push(ch as u8) + } else { + errors.push(Error::from(TxtParseError::NonAscii { character: ch.into() })) + } + }, + None => { + errors.push(Error::from(TxtParseError::MissingEscape)) + } + } + } else if printable(ch) { + data.push(ch as u8); + } else { + errors.push(Error::from(TxtParseError::NonAscii { character: ch.into() })) + } + } + + //TODO: check txt data max length? + + if errors.is_empty() { + Ok(data) + } else { + Err(errors) + } +}