diff --git a/Cargo.lock b/Cargo.lock index 355c295..dfcbe31 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "addr2line" -version = "0.20.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" dependencies = [ "gimli", ] @@ -19,40 +19,31 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "ahash" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" -dependencies = [ - "getrandom", - "once_cell", - "version_check", -] - -[[package]] -name = "ahash" -version = "0.8.3" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a" dependencies = [ "cfg-if", + "getrandom", "once_cell", "version_check", + "zerocopy", ] [[package]] name = "aho-corasick" -version = "1.0.2" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" dependencies = [ "memchr", ] [[package]] name = "allocator-api2" -version = "0.2.14" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4f263788a35611fba42eb41ff811c5d0360c58b97402570312a350736e2542e" +checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" [[package]] name = "android-tzdata" @@ -71,64 +62,63 @@ dependencies = [ [[package]] name = "anstream" -version = "0.3.2" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163" +checksum = "d664a92ecae85fd0a7392615844904654d1d5f5514837f471ddef4a057aba1b6" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", - "is-terminal", "utf8parse", ] [[package]] name = "anstyle" -version = "1.0.0" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41ed9a86bf92ae6580e0a31281f65a1b1d867c0cc68d5346e2ae128dddfa6a7d" +checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" [[package]] name = "anstyle-parse" -version = "0.2.0" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e765fd216e48e067936442276d1d57399e37bce53c264d6fefbe298080cb57ee" +checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.0.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "anstyle-wincon" -version = "1.0.1" +version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188" +checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" dependencies = [ "anstyle", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "anyhow" -version = "1.0.71" +version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" [[package]] name = "assert_cmd" -version = "2.0.11" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86d6b683edf8d1119fe420a94f8a7e389239666aa72e65495d91c00462510151" +checksum = "88903cb14723e4d4003335bb7f8a14f27691649105346a0f0957466c096adfe6" dependencies = [ "anstyle", "bstr", @@ -141,24 +131,34 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.68" +version = "0.1.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" +checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.41", ] [[package]] name = "atoi" -version = "1.0.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7c57d12312ff59c811c0643f4d80830505833c9ffaebd193d819392b265be8e" +checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" dependencies = [ "num-traits", ] +[[package]] +name = "atomic-write-file" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edcdbedc2236483ab103a53415653d6b4442ea6141baf1ffa85df29635e88436" +dependencies = [ + "nix", + "rand", +] + [[package]] name = "autocfg" version = "1.1.0" @@ -167,19 +167,19 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "axum" -version = "0.6.18" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8175979259124331c1d7bf6586ee7e0da434155e4b2d48ec2c8386281d8df39" +checksum = "202651474fe73c62d9e0a56c6133f7a0ff1dc1c8cf7a5b03381af2a26553ac9d" dependencies = [ "async-trait", "axum-core", - "bitflags", "bytes", "futures-util", - "headers", - "http", - "http-body", - "hyper", + "http 1.0.0", + "http-body 1.0.0", + "http-body-util", + "hyper 1.0.1", + "hyper-util", "itoa", "matchit", "memchr", @@ -200,48 +200,74 @@ dependencies = [ [[package]] name = "axum-client-ip" -version = "0.3.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddfb5a3ddd6367075d50629546fb46710584016ae7704cd03b6d41cb5be82e5a" +checksum = "0f5ffe4637708b326c621d5494ab6c91dcf62ee440fa6ee967d289315a9c6f81" dependencies = [ "axum", "forwarded-header-value", + "serde", ] [[package]] name = "axum-core" -version = "0.3.4" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c" +checksum = "77cb22c689c44d4c07b0ab44ebc25d69d8ae601a2f28fb8d672d344178fa17aa" dependencies = [ "async-trait", "bytes", "futures-util", - "http", - "http-body", + "http 1.0.0", + "http-body 1.0.0", + "http-body-util", "mime", + "pin-project-lite", "rustversion", + "sync_wrapper", + "tower-layer", + "tower-service", +] + +[[package]] +name = "axum-extra" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "523ae92256049a3b02d3bb4df80152386cd97ddba0c8c5077619bdc8c4b1859b" +dependencies = [ + "axum", + "axum-core", + "bytes", + "futures-util", + "headers", + "http 1.0.0", + "http-body 1.0.0", + "http-body-util", + "mime", + "pin-project-lite", + "serde", + "tower", "tower-layer", "tower-service", ] [[package]] name = "axum-macros" -version = "0.3.7" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bb524613be645939e280b7279f7b017f98cf7f5ef084ec374df373530e73277" +checksum = "5a2edad600410b905404c594e2523549f1bcd4bded1e252c8f74524ccce0b867" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.41", ] [[package]] name = "backtrace" -version = "0.3.68" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" dependencies = [ "addr2line", "cc", @@ -254,15 +280,15 @@ dependencies = [ [[package]] name = "base64" -version = "0.13.1" +version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" +checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" [[package]] -name = "base64" -version = "0.21.2" +name = "base64ct" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" [[package]] name = "bitflags" @@ -270,6 +296,15 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" +dependencies = [ + "serde", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -281,21 +316,20 @@ dependencies = [ [[package]] name = "bstr" -version = "1.5.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a246e68bb43f6cd9db24bea052a53e40405417c5fb372e3d1a8a7f770a564ef5" +checksum = "542f33a8835a0884b006a0c3df3dadd99c0c3f296ed26c2fdc8028e01ad6230c" dependencies = [ "memchr", - "once_cell", - "regex-automata", + "regex-automata 0.4.3", "serde", ] [[package]] name = "btree-range-map" -version = "0.5.2" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3cdbe5a17ae759372f2106bf14d7fb8adc16f2dd5ad0cd6bb287ec554a3cc41" +checksum = "1be5c9672446d3800bcbcaabaeba121fe22f1fb25700c4562b22faf76d377c33" dependencies = [ "btree-slab", "cc-traits", @@ -305,9 +339,9 @@ dependencies = [ [[package]] name = "btree-slab" -version = "0.5.1" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbd15ebdf1711bae315f668ac8865d35754613955f6473515b6aa2762ea2ec86" +checksum = "7a2b56d3029f075c4fa892428a098425b86cef5c89ae54073137ece416aef13c" dependencies = [ "cc-traits", "slab", @@ -316,48 +350,51 @@ dependencies = [ [[package]] name = "buildstructor" -version = "0.5.2" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a94acaaeac95a57c88e5b97fd3b5dda18b4578cb33cbba6791cc4f62918c2922" +checksum = "c3907aac66c65520545ae3cb3c195306e20d5ed5c90bfbb992e061cf12a104d0" dependencies = [ "lazy_static", "proc-macro2", "quote", "str_inflector", - "syn 2.0.18", + "syn 2.0.41", "thiserror", "try_match", ] [[package]] name = "bumpalo" -version = "3.13.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" [[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.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" [[package]] name = "cc" -version = "1.0.79" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "libc", +] [[package]] name = "cc-traits" -version = "1.0.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "becb23f44ae9dd141d637d520b908c291bf4c5eed016ca368daa1430d54ebf4c" +checksum = "060303ef31ef4a522737e1b1ab68c67916f2a787bb2f4f54f383279adba962b5" dependencies = [ "slab", ] @@ -370,22 +407,28 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.26" +version = "0.4.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5" +checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" dependencies = [ "android-tzdata", "iana-time-zone", "num-traits", "serde", - "winapi", + "windows-targets 0.48.5", ] +[[package]] +name = "cidr" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d18b093eba54c9aaa1e3784d4361eb2ba944cf7d0a932a830132238f483e8d8" + [[package]] name = "cidr-utils" -version = "0.5.10" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdfa36f04861d39453affe1cf084ce2d6554021a84eb6f31ebdeafb6fb92a01c" +checksum = "2315f7119b7146d6a883de6acd63ddf96071b5f79d9d98d2adaa84d749f6abf1" dependencies = [ "debug-helper", "num-bigint", @@ -394,22 +437,32 @@ dependencies = [ "regex", ] +[[package]] +name = "cidr-utils" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25c0a9fb70c2c2cc2a520aa259b1d1345650046a07df1b6da1d3cefcd327f43e" +dependencies = [ + "cidr", + "num-bigint", + "num-traits", +] + [[package]] name = "clap" -version = "4.3.19" +version = "4.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fd304a20bff958a57f04c4e96a2e7594cc4490a0e809cbd48bb6437edaa452d" +checksum = "bfaff671f6b22ca62406885ece523383b9b64022e341e53e009a62ebc47a45f2" dependencies = [ "clap_builder", "clap_derive", - "once_cell", ] [[package]] name = "clap_builder" -version = "4.3.19" +version = "4.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01c6a3f08f1fe5662a35cfe393aec09c4df95f60ee93b7556505260f75eee9e1" +checksum = "a216b506622bb1d316cd51328dce24e07bdff4a6128a47c7e7fad11878d5adbb" dependencies = [ "anstream", "anstyle", @@ -419,21 +472,21 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.3.12" +version = "4.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54a9bb5758fc5dfe728d1019941681eccaf0cf8a4189b692a0ee2f2ecf90a050" +checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.41", ] [[package]] name = "clap_lex" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" +checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" [[package]] name = "colorchoice" @@ -441,20 +494,26 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + [[package]] name = "const_format" -version = "0.2.31" +version = "0.2.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c990efc7a285731f9a4378d81aff2f0e85a2c8781a05ef0f8baa8dac54d0ff48" +checksum = "e3a214c7af3d04997541b18d432afaff4c455e79e2029079647e72fc2bd27673" dependencies = [ "const_format_proc_macros", ] [[package]] name = "const_format_proc_macros" -version = "0.2.31" +version = "0.2.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e026b6ce194a874cb9cf32cd5772d1ef9767cc8fcb5765948d74f37a9d8b2bf6" +checksum = "c7f6ff08fd20f4f299298a28e2dfa8a8ba1036e6cd2460ac1de7b425d76f2500" dependencies = [ "proc-macro2", "quote", @@ -463,18 +522,18 @@ dependencies = [ [[package]] name = "coolor" -version = "0.5.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af4d7a805ca0d92f8c61a31c809d4323fdaa939b0b440e544d21db7797c5aaad" +checksum = "95ce3e41909f18d5860fe1e6699651fcca2cb2576ee68c6984c93c2b26d059ea" dependencies = [ "crossterm 0.23.2", ] [[package]] name = "core-foundation" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" dependencies = [ "core-foundation-sys", "libc", @@ -482,15 +541,15 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" [[package]] name = "cpufeatures" -version = "0.2.7" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e4c1eaa2012c47becbbad2ab175484c2a84d1185b566fb2cc5b8707343dfe58" +checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" dependencies = [ "libc", ] @@ -506,9 +565,9 @@ dependencies = [ [[package]] name = "crc-catalog" -version = "2.2.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cace84e55f07e7301bae1c519df89cdad8cc3cd868413d3fdbdeca9ff3db484" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" [[package]] name = "crossbeam" @@ -526,9 +585,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.8" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" +checksum = "14c3242926edf34aec4ac3a77108ad4854bffaa2e4ddc1824124ce59231302d5" dependencies = [ "cfg-if", "crossbeam-utils", @@ -536,9 +595,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +checksum = "fca89a0e215bab21874660c67903c5f143333cab1da83d041c7ded6053774751" dependencies = [ "cfg-if", "crossbeam-epoch", @@ -547,22 +606,21 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.15" +version = "0.9.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" +checksum = "2d2fe95351b870527a5d09bf563ed3c97c0cffb87cf1c78a591bf48bb218d9aa" dependencies = [ "autocfg", "cfg-if", "crossbeam-utils", "memoffset", - "scopeguard", ] [[package]] name = "crossbeam-queue" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add" +checksum = "b9bcf5bdbfdd6030fb4a1c497b5d5fc5921aa2f60d359a17e249c0e6df3de153" dependencies = [ "cfg-if", "crossbeam-utils", @@ -570,9 +628,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.16" +version = "0.8.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" +checksum = "c06d96137f14f244c37f989d9fff8f95e6c18b918e71f36638f8c49112e4c78f" dependencies = [ "cfg-if", ] @@ -583,11 +641,11 @@ version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2102ea4f781910f8a5b98dd061f4c2023f479ce7bb1236330099ceb5a93cf17" dependencies = [ - "bitflags", + "bitflags 1.3.2", "crossterm_winapi", "libc", "mio", - "parking_lot 0.12.1", + "parking_lot", "signal-hook", "signal-hook-mio", "winapi", @@ -595,15 +653,15 @@ dependencies = [ [[package]] name = "crossterm" -version = "0.26.1" +version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a84cda67535339806297f1b331d6dd6320470d2a0fe65381e79ee9e156dd3d13" +checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df" dependencies = [ - "bitflags", + "bitflags 2.4.1", "crossterm_winapi", "libc", "mio", - "parking_lot 0.12.1", + "parking_lot", "signal-hook", "signal-hook-mio", "winapi", @@ -628,12 +686,36 @@ dependencies = [ "typenum", ] +[[package]] +name = "dashmap" +version = "5.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" +dependencies = [ + "cfg-if", + "hashbrown 0.14.3", + "lock_api", + "once_cell", + "parking_lot_core", +] + [[package]] name = "debug-helper" version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f578e8e2c440e7297e008bb5486a3a8a194775224bbc23729b0dbdfaeebf162e" +[[package]] +name = "der" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" +dependencies = [ + "const-oid", + "pem-rfc7468", + "zeroize", +] + [[package]] name = "difflib" version = "0.4.0" @@ -647,6 +729,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", + "const-oid", "crypto-common", "subtle", ] @@ -657,27 +740,7 @@ version = "5.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a49173b84e034382284f27f1af4dcbbd231ffa358c0fe316541a7337f376a35" dependencies = [ - "dirs-sys 0.4.1", -] - -[[package]] -name = "dirs" -version = "4.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" -dependencies = [ - "dirs-sys 0.3.7", -] - -[[package]] -name = "dirs-sys" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" -dependencies = [ - "libc", - "redox_users", - "winapi", + "dirs-sys", ] [[package]] @@ -718,24 +781,24 @@ checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" [[package]] name = "dyn-clone" -version = "1.0.11" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68b0cf012f1230e43cd00ebb729c6bb58707ecfa8ad08b52ef3a4ccd2697fc30" +checksum = "545b22097d44f8a9581187cdf93de7a71e4722bf51200cfaba810865b49a495d" [[package]] name = "either" -version = "1.8.1" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" dependencies = [ "serde", ] [[package]] name = "encoding_rs" -version = "0.8.32" +version = "0.8.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" +checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" dependencies = [ "cfg-if", ] @@ -747,28 +810,34 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d73999a2b8871e74c8b8bc23759ee9f3d85011b24fafc91a4b3b5c8cc8185501" dependencies = [ "fsio", - "indexmap", + "indexmap 1.9.3", ] +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "errno" -version = "0.3.1" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" dependencies = [ - "errno-dragonfly", "libc", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] -name = "errno-dragonfly" -version = "0.1.2" +name = "etcetera" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" dependencies = [ - "cc", - "libc", + "cfg-if", + "home", + "windows-sys 0.48.0", ] [[package]] @@ -779,11 +848,25 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "fastrand" -version = "1.9.0" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" + +[[package]] +name = "finl_unicode" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fcfdc7a0362c9f4444381a9e697c79d435fe65b52a37466fc2c1184cee9edc6" + +[[package]] +name = "flume" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181" dependencies = [ - "instant", + "futures-core", + "futures-sink", + "spin 0.9.8", ] [[package]] @@ -809,9 +892,9 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "form_urlencoded" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] @@ -837,9 +920,9 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" +checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335" dependencies = [ "futures-channel", "futures-core", @@ -852,9 +935,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" dependencies = [ "futures-core", "futures-sink", @@ -862,15 +945,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" +checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" [[package]] name = "futures-executor" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" +checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc" dependencies = [ "futures-core", "futures-task", @@ -879,43 +962,43 @@ dependencies = [ [[package]] name = "futures-intrusive" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a604f7a68fbf8103337523b1fadc8ade7361ee3f112f7c680ad179651616aed5" +checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" dependencies = [ "futures-core", "lock_api", - "parking_lot 0.11.2", + "parking_lot", ] [[package]] name = "futures-io" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" +checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" [[package]] name = "futures-macro" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.41", ] [[package]] name = "futures-sink" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" +checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" [[package]] name = "futures-task" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" +checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" [[package]] name = "futures-timer" @@ -925,9 +1008,9 @@ checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" [[package]] name = "futures-util" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" dependencies = [ "futures-channel", "futures-core", @@ -953,9 +1036,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" dependencies = [ "cfg-if", "libc", @@ -964,23 +1047,42 @@ dependencies = [ [[package]] name = "gimli" -version = "0.27.3" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" + +[[package]] +name = "h2" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" +checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http 0.2.11", + "indexmap 2.1.0", + "slab", + "tokio", + "tokio-util", + "tracing", +] [[package]] name = "h2" -version = "0.3.19" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d357c7ae988e7d2182f7d7871d0b963962420b0678b0997ce7de72001aeab782" +checksum = "e1d308f63daf4181410c242d34c11f928dcb3aa105852019e043c9d1f4e4368a" dependencies = [ "bytes", "fnv", "futures-core", "futures-sink", "futures-util", - "http", - "indexmap", + "http 1.0.0", + "indexmap 2.1.0", "slab", "tokio", "tokio-util", @@ -995,34 +1097,33 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.14.0" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" dependencies = [ - "ahash 0.8.3", + "ahash", "allocator-api2", ] [[package]] name = "hashlink" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "312f66718a2d7789ffef4f4b7b213138ed9f1eb3aa1d0d82fc99f88fb3ffd26f" +checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" dependencies = [ - "hashbrown 0.14.0", + "hashbrown 0.14.3", ] [[package]] name = "headers" -version = "0.3.8" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3e372db8e5c0d213e0cd0b9be18be2aca3d44cf2fe30a9d46a65581cd454584" +checksum = "322106e6bd0cba2d5ead589ddb8150a13d7c4217cf80d7c4f682ca994ccc6aa9" dependencies = [ - "base64 0.13.1", - "bitflags", + "base64", "bytes", "headers-core", - "http", + "http 1.0.0", "httpdate", "mime", "sha1", @@ -1030,11 +1131,11 @@ dependencies = [ [[package]] name = "headers-core" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" +checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4" dependencies = [ - "http", + "http 1.0.0", ] [[package]] @@ -1048,18 +1149,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" -dependencies = [ - "libc", -] - -[[package]] -name = "hermit-abi" -version = "0.3.1" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" +checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" [[package]] name = "hex" @@ -1069,9 +1161,9 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "hkdf" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" dependencies = [ "hmac", ] @@ -1085,11 +1177,31 @@ dependencies = [ "digest", ] +[[package]] +name = "home" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "http" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + [[package]] name = "http" -version = "0.2.9" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +checksum = "b32afd38673a8016f7c9ae69e5af41a58f81b1d31689040f2f1959594ce194ea" dependencies = [ "bytes", "fnv", @@ -1098,20 +1210,37 @@ dependencies = [ [[package]] name = "http-body" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", - "http", + "http 0.2.11", "pin-project-lite", ] [[package]] -name = "http-range-header" -version = "0.3.0" +name = "http-body" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" +dependencies = [ + "bytes", + "http 1.0.0", +] + +[[package]] +name = "http-body-util" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bfe8eed0a9285ef776bb792479ea3834e8b94e13d615c2f66d03dd50a435a29" +checksum = "41cb79eb393015dadd30fc252023adb0b2400a0caee0fa2a077e6e21a551e840" +dependencies = [ + "bytes", + "futures-util", + "http 1.0.0", + "http-body 1.0.0", + "pin-project-lite", +] [[package]] name = "httparse" @@ -1121,34 +1250,54 @@ checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" [[package]] name = "httpdate" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" -version = "0.14.26" +version = "0.14.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab302d72a6f11a3b910431ff93aae7e773078c769f0a3ef15fb9ec692ed147d4" +checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" dependencies = [ "bytes", "futures-channel", "futures-core", "futures-util", - "h2", - "http", - "http-body", + "h2 0.3.22", + "http 0.2.11", + "http-body 0.4.6", "httparse", "httpdate", "itoa", "pin-project-lite", - "socket2", + "socket2 0.4.10", "tokio", "tower-service", "tracing", "want", ] +[[package]] +name = "hyper" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "403f9214f3e703236b221f1a9cd88ec8b4adfa5296de01ab96216361f4692f56" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "h2 0.4.0", + "http 1.0.0", + "http-body 1.0.0", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "tokio", + "want", +] + [[package]] name = "hyper-tls" version = "0.5.0" @@ -1156,29 +1305,49 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" dependencies = [ "bytes", - "hyper", + "hyper 0.14.27", "native-tls", "tokio", "tokio-native-tls", ] [[package]] -name = "iana-time-zone" -version = "0.1.57" +name = "hyper-util" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613" +checksum = "9ca339002caeb0d159cc6e023dff48e199f081e42fa039895c7c6f38b37f2e9d" dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "windows", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" + "bytes", + "futures-channel", + "futures-util", + "http 1.0.0", + "http-body 1.0.0", + "hyper 1.0.1", + "pin-project-lite", + "socket2 0.5.5", + "tokio", + "tower", + "tower-service", + "tracing", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" dependencies = [ @@ -1187,12 +1356,12 @@ dependencies = [ [[package]] name = "icann-rdap-cli" -version = "0.0.14" +version = "0.0.15" dependencies = [ "anyhow", "assert_cmd", "chrono", - "cidr-utils", + "cidr-utils 0.5.11", "clap", "const_format", "directories", @@ -1201,7 +1370,6 @@ dependencies = [ "icann-rdap-common", "icann-rdap-srv", "ipnet", - "is-terminal", "lazy_static", "minus", "pct-str", @@ -1210,6 +1378,7 @@ dependencies = [ "rstest", "serde", "serde_json", + "serial_test", "termimad", "test_dir", "thiserror", @@ -1220,11 +1389,11 @@ dependencies = [ [[package]] name = "icann-rdap-client" -version = "0.0.14" +version = "0.0.15" dependencies = [ "buildstructor", "chrono", - "cidr-utils", + "cidr-utils 0.6.1", "const_format", "icann-rdap-common", "lazy_static", @@ -1242,13 +1411,15 @@ dependencies = [ [[package]] name = "icann-rdap-common" -version = "0.0.14" +version = "0.0.15" dependencies = [ "buildstructor", "chrono", - "cidr-utils", + "cidr-utils 0.6.1", "const_format", + "ipnet", "lazy_static", + "prefix-trie", "reqwest", "rstest", "serde", @@ -1260,27 +1431,27 @@ dependencies = [ [[package]] name = "icann-rdap-srv" -version = "0.0.14" +version = "0.0.15" dependencies = [ "assert_cmd", "async-trait", "axum", "axum-client-ip", + "axum-extra", "axum-macros", "btree-range-map", "buildstructor", "chrono", - "cidr-utils", + "cidr-utils 0.6.1", "clap", "dotenv", "envmnt", "headers", - "http", - "hyper", + "http 1.0.0", + "hyper 1.0.1", "icann-rdap-client", "icann-rdap-common", "ipnet", - "is-terminal", "lazy_static", "pct-str", "prefix-trie", @@ -1303,9 +1474,9 @@ dependencies = [ [[package]] name = "idna" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -1322,94 +1493,135 @@ dependencies = [ ] [[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "io-lifetimes" -version = "1.0.11" +name = "indexmap" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" dependencies = [ - "hermit-abi 0.3.1", - "libc", - "windows-sys 0.48.0", + "equivalent", + "hashbrown 0.14.3", ] [[package]] name = "ipnet" -version = "2.7.2" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12b6ee2129af8d4fb011108c73d99a1b83a85977f23b82460c0ae2e25bb4b57f" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" dependencies = [ "schemars", "serde", ] [[package]] -name = "is-terminal" -version = "0.4.7" +name = "itertools" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" dependencies = [ - "hermit-abi 0.3.1", - "io-lifetimes", - "rustix", - "windows-sys 0.48.0", + "either", ] [[package]] name = "itertools" -version = "0.10.5" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0" dependencies = [ "either", ] [[package]] name = "itoa" -version = "1.0.6" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] name = "js-sys" -version = "0.3.64" +version = "0.3.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca" dependencies = [ "wasm-bindgen", ] +[[package]] +name = "lazy-regex" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d12be4595afdf58bd19e4a9f4e24187da2a66700786ff660a418e9059937a4c" +dependencies = [ + "lazy-regex-proc_macros", + "once_cell", + "regex", +] + +[[package]] +name = "lazy-regex-proc_macros" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44bcd58e6c97a7fcbaffcdc95728b393b8d98933bfadad49ed4097845b57ef0b" +dependencies = [ + "proc-macro2", + "quote", + "regex", + "syn 2.0.41", +] + [[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +dependencies = [ + "spin 0.5.2", +] [[package]] name = "libc" -version = "0.2.146" +version = "0.2.151" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" + +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[package]] +name = "libredox" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" +dependencies = [ + "bitflags 2.4.1", + "libc", + "redox_syscall", +] + +[[package]] +name = "libsqlite3-sys" +version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b" +checksum = "cf4e226dcd58b4be396f7bd3c20da8fdee2911400705297ba7d2d7cc2c30f716" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] [[package]] name = "linux-raw-sys" -version = "0.3.8" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" +checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" [[package]] name = "lock_api" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" dependencies = [ "autocfg", "scopeguard", @@ -1417,9 +1629,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.19" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "matchers" @@ -1427,29 +1639,30 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" dependencies = [ - "regex-automata", + "regex-automata 0.1.10", ] [[package]] name = "matchit" -version = "0.7.0" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b87248edafb776e59e6ee64a79086f65890d3510f2c656c000bf2a7e8a0aea40" +checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" [[package]] name = "md-5" -version = "0.10.5" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6365506850d44bff6e2fbcb5176cf63650e48bd45ef2fe2665ae1570e0f4b9ca" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" dependencies = [ + "cfg-if", "digest", ] [[package]] name = "memchr" -version = "2.5.0" +version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" [[package]] name = "memoffset" @@ -1468,9 +1681,9 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "minimad" -version = "0.12.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b136454924e4d020e55c4992e07c105b40d5c41b84662862f0e15bc0a2efef" +checksum = "f6c4610f430e49b882fcaad0186134150d4d74fc76080b0a61f7000460c2e268" dependencies = [ "once_cell", ] @@ -1492,14 +1705,14 @@ dependencies = [ [[package]] name = "minus" -version = "5.4.0" +version = "5.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c3b2098701d3565543b4deca8290a10337dbc585e0e356ca46ffd1b6f7e0d6a" +checksum = "1f9991684a4c6cad95f3cdc3c07b1fcf643654a2d3186b3b309fa77eb48cfb19" dependencies = [ "crossbeam-channel", - "crossterm 0.26.1", + "crossterm 0.27.0", "once_cell", - "parking_lot 0.12.1", + "parking_lot", "regex", "textwrap", "thiserror", @@ -1507,9 +1720,9 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.8" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" +checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" dependencies = [ "libc", "log", @@ -1535,6 +1748,17 @@ dependencies = [ "tempfile", ] +[[package]] +name = "nix" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" +dependencies = [ + "bitflags 2.4.1", + "cfg-if", + "libc", +] + [[package]] name = "nom" version = "7.1.3" @@ -1563,15 +1787,32 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" dependencies = [ "autocfg", "num-integer", "num-traits", ] +[[package]] +name = "num-bigint-dig" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" +dependencies = [ + "byteorder", + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand", + "smallvec", + "zeroize", +] + [[package]] name = "num-integer" version = "0.1.45" @@ -1582,50 +1823,62 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-iter" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" -version = "0.2.15" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" dependencies = [ "autocfg", + "libm", ] [[package]] name = "num_cpus" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.2.6", + "hermit-abi", "libc", ] [[package]] name = "object" -version = "0.31.1" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" +checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" dependencies = [ - "parking_lot_core 0.9.8", + "parking_lot_core", ] [[package]] name = "openssl" -version = "0.10.54" +version = "0.10.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69b3f656a17a6cbc115b5c7a40c616947d213ba182135b014d6051b73ab6f019" +checksum = "6b8419dc8cc6d866deb801274bba2e6f8f6108c1bb7fcc10ee5ab864931dbb45" dependencies = [ - "bitflags", + "bitflags 2.4.1", "cfg-if", "foreign-types", "libc", @@ -1642,7 +1895,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.41", ] [[package]] @@ -1653,18 +1906,18 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-src" -version = "111.26.0+1.1.1u" +version = "300.2.1+3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efc62c9f12b22b8f5208c23a7200a442b2e5999f8bdf80233852122b5a4f6f37" +checksum = "3fe476c29791a5ca0d1273c697e96085bbabbbea2ef7afd5617e78a4b40332d3" dependencies = [ "cc", ] [[package]] name = "openssl-sys" -version = "0.9.88" +version = "0.9.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2ce0f250f34a308dcfdbb351f511359857d4ed2134ba715a4eadd46e1ffd617" +checksum = "c3eaad34cdd97d81de97964fc7f29e2d104f483840d906ef56daa1912338460b" dependencies = [ "cc", "libc", @@ -1685,17 +1938,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" -[[package]] -name = "parking_lot" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" -dependencies = [ - "instant", - "lock_api", - "parking_lot_core 0.8.6", -] - [[package]] name = "parking_lot" version = "0.12.1" @@ -1703,41 +1945,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", - "parking_lot_core 0.9.8", + "parking_lot_core", ] [[package]] name = "parking_lot_core" -version = "0.8.6" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" dependencies = [ "cfg-if", - "instant", "libc", - "redox_syscall 0.2.16", + "redox_syscall", "smallvec", - "winapi", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall 0.3.5", - "smallvec", - "windows-targets", + "windows-targets 0.48.5", ] [[package]] name = "paste" -version = "1.0.12" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" [[package]] name = "pct-str" @@ -1748,37 +1976,46 @@ dependencies = [ "utf8-decode", ] +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + [[package]] name = "percent-encoding" -version = "2.3.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pin-project" -version = "1.1.0" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c95a7476719eab1e366eaf73d0260af3021184f18177925b07f54b30089ceead" +checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.0" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39407670928234ebc5e6e580247dd567ad73a3578460c5990f9503df207e8f07" +checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.41", ] [[package]] name = "pin-project-lite" -version = "0.2.9" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" [[package]] name = "pin-utils" @@ -1786,6 +2023,27 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkcs1" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" +dependencies = [ + "der", + "pkcs8", + "spki", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + [[package]] name = "pkg-config" version = "0.3.27" @@ -1800,13 +2058,13 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "predicates" -version = "3.0.3" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09963355b9f467184c04017ced4a2ba2d75cbcb4e7462690d388233253d4b1a9" +checksum = "6dfc28575c2e3f19cb3c73b93af36460ae898d426eba6fc15b9bd2a5220758a0" dependencies = [ "anstyle", "difflib", - "itertools", + "itertools 0.11.0", "predicates-core", ] @@ -1836,44 +2094,20 @@ dependencies = [ "num-traits", ] -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn 1.0.109", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - [[package]] name = "proc-macro2" -version = "1.0.60" +version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406" +checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.28" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] @@ -1910,48 +2144,40 @@ dependencies = [ [[package]] name = "range-traits" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ea26694da042b4016873b8c55515348f40d77281f239ade1f2ede3afb8da92c" - -[[package]] -name = "redox_syscall" -version = "0.2.16" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags", -] +checksum = "d20581732dd76fa913c7dff1a2412b714afe3573e94d41c34719de73337cc8ab" [[package]] name = "redox_syscall" -version = "0.3.5" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] name = "redox_users" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" dependencies = [ "getrandom", - "redox_syscall 0.2.16", + "libredox", "thiserror", ] [[package]] name = "regex" -version = "1.8.4" +version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.7.2", + "regex-automata 0.4.3", + "regex-syntax 0.8.2", ] [[package]] @@ -1963,6 +2189,17 @@ dependencies = [ "regex-syntax 0.6.29", ] +[[package]] +name = "regex-automata" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.8.2", +] + [[package]] name = "regex-syntax" version = "0.6.29" @@ -1971,25 +2208,25 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.7.2" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "reqwest" -version = "0.11.18" +version = "0.11.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cde824a14b7c14f85caff81225f411faacc04a2013f41670f41443742b1c1c55" +checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b" dependencies = [ - "base64 0.21.2", + "base64", "bytes", "encoding_rs", "futures-core", "futures-util", - "h2", - "http", - "http-body", - "hyper", + "h2 0.3.22", + "http 0.2.11", + "http-body 0.4.6", + "hyper 0.14.27", "hyper-tls", "ipnet", "js-sys", @@ -2002,6 +2239,7 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", + "system-configuration", "tokio", "tokio-native-tls", "tokio-util", @@ -2016,17 +2254,36 @@ dependencies = [ [[package]] name = "ring" -version = "0.16.20" +version = "0.17.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" dependencies = [ "cc", + "getrandom", "libc", - "once_cell", - "spin", + "spin 0.9.8", "untrusted", - "web-sys", - "winapi", + "windows-sys 0.48.0", +] + +[[package]] +name = "rsa" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0e5124fcb30e76a7e79bfee683a2746db83784b86289f6251b54b7950a0dfc" +dependencies = [ + "const-oid", + "digest", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core", + "signature", + "spki", + "subtle", + "zeroize", ] [[package]] @@ -2072,65 +2329,73 @@ dependencies = [ [[package]] name = "rustix" -version = "0.37.20" +version = "0.38.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b96e891d04aa506a6d1f318d2771bcb1c7dfda84e126660ace067c9b474bb2c0" +checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316" dependencies = [ - "bitflags", + "bitflags 2.4.1", "errno", - "io-lifetimes", "libc", "linux-raw-sys", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "rustls" -version = "0.20.8" +version = "0.21.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f" +checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" dependencies = [ - "log", "ring", + "rustls-webpki", "sct", - "webpki", ] [[package]] name = "rustls-pemfile" -version = "1.0.2" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64", +] + +[[package]] +name = "rustls-webpki" +version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ - "base64 0.21.2", + "ring", + "untrusted", ] [[package]] name = "rustversion" -version = "1.0.12" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" [[package]] name = "ryu" -version = "1.0.13" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" +checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" [[package]] name = "schannel" -version = "0.1.21" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" +checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" dependencies = [ - "windows-sys 0.42.0", + "windows-sys 0.48.0", ] [[package]] name = "schemars" -version = "0.8.12" +version = "0.8.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02c613288622e5f0c3fdc5dbd4db1c5fbe752746b1d1a56a0630b78fd00de44f" +checksum = "45a28f4c49489add4ce10783f7911893516f15afe45d015608d41faca6bc4d29" dependencies = [ "dyn-clone", "schemars_derive", @@ -2140,9 +2405,9 @@ dependencies = [ [[package]] name = "schemars_derive" -version = "0.8.12" +version = "0.8.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "109da1e6b197438deb6db99952990c7f959572794b80ff93707d55a232545e7c" +checksum = "c767fd6fa65d9ccf9cf026122c1b555f2ef9a4f0cea69da4d7dbc3e258d30967" dependencies = [ "proc-macro2", "quote", @@ -2152,15 +2417,15 @@ dependencies = [ [[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 = "sct" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ "ring", "untrusted", @@ -2168,11 +2433,11 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.9.1" +version = "2.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fc758eb7bffce5b308734e9b0c1468893cae9ff70ebf13e7090be8dcbcc83a8" +checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" dependencies = [ - "bitflags", + "bitflags 1.3.2", "core-foundation", "core-foundation-sys", "libc", @@ -2181,9 +2446,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.9.0" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f51d0c0d83bec45f16480d0ce0058397a69e48fcdc52d1dc8855fb68acbd31a7" +checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" dependencies = [ "core-foundation-sys", "libc", @@ -2191,28 +2456,28 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.17" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" +checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" [[package]] name = "serde" -version = "1.0.164" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d" +checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.164" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68" +checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.41", ] [[package]] @@ -2228,9 +2493,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.96" +version = "1.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" +checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" dependencies = [ "itoa", "ryu", @@ -2239,10 +2504,11 @@ dependencies = [ [[package]] name = "serde_path_to_error" -version = "0.1.11" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7f05c1d5476066defcdfacce1f52fc3cae3af1d3089727100c02ae92e5abbe0" +checksum = "4beec8bce849d58d06238cb50db2e1c417cfeafa4c63f692b15c82b7c80f8335" dependencies = [ + "itoa", "serde", ] @@ -2258,11 +2524,36 @@ dependencies = [ "serde", ] +[[package]] +name = "serial_test" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e56dd856803e253c8f298af3f4d7eb0ae5e23a737252cd90bb4f3b435033b2d" +dependencies = [ + "dashmap", + "futures", + "lazy_static", + "log", + "parking_lot", + "serial_test_derive", +] + +[[package]] +name = "serial_test_derive" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91d129178576168c589c9ec973feedf7d3126c01ac2bf08795109aa35b69fb8f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.41", +] + [[package]] name = "sha1" -version = "0.10.5" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", "cpufeatures", @@ -2271,9 +2562,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.6" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", "cpufeatures", @@ -2282,18 +2573,18 @@ dependencies = [ [[package]] name = "sharded-slab" -version = "0.1.4" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" dependencies = [ "lazy_static", ] [[package]] name = "signal-hook" -version = "0.3.15" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "732768f1176d21d09e076c23a93123d40bba92d50c4058da34d45c8de8e682b9" +checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" dependencies = [ "libc", "signal-hook-registry", @@ -2319,118 +2610,164 @@ dependencies = [ "libc", ] +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core", +] + [[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.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" +checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" [[package]] name = "socket2" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" +checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" dependencies = [ "libc", "winapi", ] +[[package]] +name = "socket2" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" +dependencies = [ + "libc", + "windows-sys 0.48.0", +] + [[package]] name = "spin" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + [[package]] name = "sqlformat" -version = "0.2.1" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c12bc9199d1db8234678b7051747c07f517cdcf019262d1847b94ec8b1aee3e" +checksum = "ce81b7bd7c4493975347ef60d8c7e8b742d4694f4c49f93e0a12ea263938176c" dependencies = [ - "itertools", + "itertools 0.12.0", "nom", "unicode_categories", ] [[package]] name = "sqlx" -version = "0.6.3" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8de3b03a925878ed54a954f621e64bf55a3c1bd29652d0d1a17830405350188" +checksum = "dba03c279da73694ef99763320dea58b51095dfe87d001b1d4b5fe78ba8763cf" dependencies = [ "sqlx-core", "sqlx-macros", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", ] [[package]] name = "sqlx-core" -version = "0.6.3" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa8241483a83a3f33aa5fff7e7d9def398ff9990b2752b6c6112b83c6d246029" +checksum = "d84b0a3c3739e220d94b3239fd69fb1f74bc36e16643423bd99de3b43c21bfbd" dependencies = [ - "ahash 0.7.6", + "ahash", "atoi", - "base64 0.13.1", - "bitflags", "byteorder", "bytes", "chrono", "crc", "crossbeam-queue", - "dirs", "dotenvy", "either", "event-listener", "futures-channel", "futures-core", "futures-intrusive", + "futures-io", "futures-util", "hashlink", "hex", - "hkdf", - "hmac", - "indexmap", - "itoa", - "libc", + "indexmap 2.1.0", "log", - "md-5", "memchr", "once_cell", "paste", "percent-encoding", - "rand", "rustls", "rustls-pemfile", "serde", "serde_json", - "sha1", "sha2", "smallvec", "sqlformat", - "sqlx-rt", - "stringprep", "thiserror", + "tokio", "tokio-stream", + "tracing", "url", "webpki-roots", - "whoami", ] [[package]] name = "sqlx-macros" -version = "0.6.3" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89961c00dc4d7dffb7aee214964b065072bff69e36ddb9e2c107541f75e4f2a5" +dependencies = [ + "proc-macro2", + "quote", + "sqlx-core", + "sqlx-macros-core", + "syn 1.0.109", +] + +[[package]] +name = "sqlx-macros-core" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9966e64ae989e7e575b19d7265cb79d7fc3cbbdf179835cb0d716f294c2049c9" +checksum = "d0bd4519486723648186a08785143599760f7cc81c52334a55d6a83ea1e20841" dependencies = [ + "atomic-write-file", "dotenvy", "either", "heck", @@ -2442,20 +2779,120 @@ dependencies = [ "serde_json", "sha2", "sqlx-core", - "sqlx-rt", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", "syn 1.0.109", + "tempfile", + "tokio", "url", ] [[package]] -name = "sqlx-rt" -version = "0.6.3" +name = "sqlx-mysql" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e37195395df71fd068f6e2082247891bc11e3289624bbc776a0cdfa1ca7f1ea4" +dependencies = [ + "atoi", + "base64", + "bitflags 2.4.1", + "byteorder", + "bytes", + "chrono", + "crc", + "digest", + "dotenvy", + "either", + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "generic-array", + "hex", + "hkdf", + "hmac", + "itoa", + "log", + "md-5", + "memchr", + "once_cell", + "percent-encoding", + "rand", + "rsa", + "serde", + "sha1", + "sha2", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror", + "tracing", + "whoami", +] + +[[package]] +name = "sqlx-postgres" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "804d3f245f894e61b1e6263c84b23ca675d96753b5abfd5cc8597d86806e8024" +checksum = "d6ac0ac3b7ccd10cc96c7ab29791a7dd236bd94021f31eec7ba3d46a74aa1c24" dependencies = [ + "atoi", + "base64", + "bitflags 2.4.1", + "byteorder", + "chrono", + "crc", + "dotenvy", + "etcetera", + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "hex", + "hkdf", + "hmac", + "home", + "itoa", + "log", + "md-5", + "memchr", "once_cell", - "tokio", - "tokio-rustls", + "rand", + "serde", + "serde_json", + "sha1", + "sha2", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror", + "tracing", + "whoami", +] + +[[package]] +name = "sqlx-sqlite" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "210976b7d948c7ba9fced8ca835b11cbb2d677c59c79de41ac0d397e14547490" +dependencies = [ + "atoi", + "chrono", + "flume", + "futures-channel", + "futures-core", + "futures-executor", + "futures-intrusive", + "futures-util", + "libsqlite3-sys", + "log", + "percent-encoding", + "serde", + "sqlx-core", + "tracing", + "url", + "urlencoding", ] [[package]] @@ -2470,10 +2907,11 @@ dependencies = [ [[package]] name = "stringprep" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ee348cb74b87454fff4b551cbf727025810a004f88aeacae7f85b87f4e9a1c1" +checksum = "bb41d74e231a107a1b4ee36bd1214b11285b77768d2e3824aedafa988fd36ee6" dependencies = [ + "finl_unicode", "unicode-bidi", "unicode-normalization", ] @@ -2522,9 +2960,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.18" +version = "2.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" +checksum = "44c8b28c477cc3bf0e7966561e3460130e1255f7a1cf71931075f1c5e7a7e269" dependencies = [ "proc-macro2", "quote", @@ -2537,30 +2975,52 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "tempfile" -version = "3.6.0" +version = "3.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31c0432476357e58790aaa47a8efb0c5138f137343f3b5f23bd36a27e3b0a6d6" +checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" dependencies = [ - "autocfg", "cfg-if", "fastrand", - "redox_syscall 0.3.5", + "redox_syscall", "rustix", "windows-sys 0.48.0", ] [[package]] name = "termimad" -version = "0.23.1" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7df2ed35b86d796df56633f1bb1f0c15816134e221822d65bbc64d5265ce8d4" +checksum = "7c3d19056c90eb12f23da61808c9f8c22b7d031bb5d50400b726ecf2d9718e73" dependencies = [ "coolor", "crossbeam", "crossterm 0.23.2", + "lazy-regex", "minimad", + "serde", "thiserror", "unicode-width", ] @@ -2591,22 +3051,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.40" +version = "1.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +checksum = "f11c217e1416d6f036b870f14e0413d480dbf28edbee1f877abaf0206af43bb7" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.40" +version = "1.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" +checksum = "01742297787513b79cf8e29d1056ede1313e2420b7b3b15d0a768b4921f549df" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.41", ] [[package]] @@ -2636,33 +3096,32 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.29.1" +version = "1.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da" +checksum = "841d45b238a16291a4e1584e61820b8ae57d696cc5015c459c229ccc6990cc1c" dependencies = [ - "autocfg", "backtrace", "bytes", "libc", "mio", "num_cpus", - "parking_lot 0.12.1", + "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2", + "socket2 0.5.5", "tokio-macros", "windows-sys 0.48.0", ] [[package]] name = "tokio-macros" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.41", ] [[package]] @@ -2675,17 +3134,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "tokio-rustls" -version = "0.23.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" -dependencies = [ - "rustls", - "tokio", - "webpki", -] - [[package]] name = "tokio-stream" version = "0.1.14" @@ -2699,9 +3147,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.8" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" +checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" dependencies = [ "bytes", "futures-core", @@ -2729,17 +3177,16 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.3.5" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f873044bf02dd1e8239e9c1293ea39dad76dc594ec16185d0a1bf31d8dc8d858" +checksum = "09e12e6351354851911bdf8c2b8f2ab15050c567d70a8b9a37ae7b8301a4080d" dependencies = [ - "bitflags", + "bitflags 2.4.1", "bytes", - "futures-core", "futures-util", - "http", - "http-body", - "http-range-header", + "http 1.0.0", + "http-body 1.0.0", + "http-body-util", "pin-project-lite", "tower-layer", "tower-service", @@ -2760,11 +3207,10 @@ checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.37" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "cfg-if", "log", "pin-project-lite", "tracing-attributes", @@ -2773,20 +3219,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.24" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f57e3ca2a01450b1a921183a9c9cbfda207fd822cef4ccb00a65402cbba7a74" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.41", ] [[package]] name = "tracing-core" -version = "0.1.31" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", "valuable", @@ -2794,20 +3240,20 @@ dependencies = [ [[package]] name = "tracing-log" -version = "0.1.3" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" dependencies = [ - "lazy_static", "log", + "once_cell", "tracing-core", ] [[package]] name = "tracing-subscriber" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" dependencies = [ "matchers", "nu-ansi-term", @@ -2823,48 +3269,47 @@ dependencies = [ [[package]] name = "try-lock" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "try_match" -version = "0.3.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "789f9cd474cc74c591dcc98669b846e158f2409ace4e6e342502ab44a41c584b" +checksum = "61ae3c1941e8859e30d28e572683fbfa89ae5330748b45139aedf488389e2be4" dependencies = [ "try_match_inner", ] [[package]] name = "try_match_inner" -version = "0.4.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "607e6b75bc1bdf1a60d4201c500ca965834c11f30e25921cfd28569315db49a9" +checksum = "b0a91713132798caecb23c977488945566875e7b61b902fb111979871cbff34e" dependencies = [ - "proc-macro-error", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.41", ] [[package]] name = "typenum" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "unicode-bidi" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" +checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416" [[package]] name = "unicode-ident" -version = "1.0.9" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-normalization" @@ -2883,9 +3328,9 @@ checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" [[package]] name = "unicode-width" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" +checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" [[package]] name = "unicode-xid" @@ -2901,21 +3346,27 @@ checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" [[package]] name = "untrusted" -version = "0.7.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" dependencies = [ "form_urlencoded", "idna", "percent-encoding", ] +[[package]] +name = "urlencoding" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" + [[package]] name = "utf8-decode" version = "1.0.1" @@ -2957,11 +3408,10 @@ dependencies = [ [[package]] name = "want" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" dependencies = [ - "log", "try-lock", ] @@ -2973,9 +3423,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -2983,24 +3433,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.41", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.37" +version = "0.4.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" +checksum = "ac36a15a220124ac510204aec1c3e5db8a22ab06fd6706d881dc6149f8ed9a12" dependencies = [ "cfg-if", "js-sys", @@ -3010,9 +3460,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3020,28 +3470,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.41", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" +checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" [[package]] name = "wasm-streams" -version = "0.2.3" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bbae3363c08332cadccd13b67db371814cd214c2524020932f0804b8cf7c078" +checksum = "b4609d447824375f43e1ffbc051b50ad8f4b3ae8219680c94452ea05eb240ac7" dependencies = [ "futures-util", "js-sys", @@ -3052,42 +3502,25 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.64" +version = "0.3.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +checksum = "50c24a44ec86bb68fbecd1b3efed7e85ea5621b39b35ef2766b66cd984f8010f" dependencies = [ "js-sys", "wasm-bindgen", ] -[[package]] -name = "webpki" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" -dependencies = [ - "ring", - "untrusted", -] - [[package]] name = "webpki-roots" -version = "0.22.6" +version = "0.25.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87" -dependencies = [ - "webpki", -] +checksum = "1778a42e8b3b90bff8d0f5032bf22250792889a5cdc752aa0020c84abe3aaf10" [[package]] name = "whoami" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c70234412ca409cc04e864e89523cb0fc37f5e1344ebed5a3ebf4192b6b9f68" -dependencies = [ - "wasm-bindgen", - "web-sys", -] +checksum = "22fc3756b8a9133049b26c7f61ab35416c130e8c09b660f5b3958b446f52cc50" [[package]] name = "winapi" @@ -3112,142 +3545,178 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] -name = "windows" -version = "0.48.0" +name = "windows-core" +version = "0.51.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" +checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", ] [[package]] name = "windows-sys" -version = "0.42.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", + "windows-targets 0.48.5", ] [[package]] name = "windows-sys" -version = "0.48.0" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets", + "windows-targets 0.52.0", ] [[package]] name = "windows-targets" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm 0.48.0", - "windows_aarch64_msvc 0.48.0", - "windows_i686_gnu 0.48.0", - "windows_i686_msvc 0.48.0", - "windows_x86_64_gnu 0.48.0", - "windows_x86_64_gnullvm 0.48.0", - "windows_x86_64_msvc 0.48.0", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", ] [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.0" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" [[package]] name = "windows_aarch64_msvc" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.48.0" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" [[package]] name = "windows_i686_gnu" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.48.0" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" [[package]] name = "windows_i686_msvc" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.48.0" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" [[package]] name = "windows_x86_64_gnu" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.48.0" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" [[package]] name = "windows_x86_64_gnullvm" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.0" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" [[package]] name = "windows_x86_64_msvc" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.48.0" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" [[package]] name = "winreg" -version = "0.10.1" +version = "0.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" dependencies = [ - "winapi", + "cfg-if", + "windows-sys 0.48.0", ] + +[[package]] +name = "zerocopy" +version = "0.7.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c4061bedbb353041c12f413700357bec76df2c7e2ca8e4df8bac24c6bf68e3d" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3c129550b3e6de3fd0ba67ba5c81818f9805e58b8d7fee80a3a59d2c9fc601a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.41", +] + +[[package]] +name = "zeroize" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" diff --git a/Cargo.toml b/Cargo.toml index 7c510d5..f86d13d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,9 +5,10 @@ members = [ "icann-rdap-common", "icann-rdap-srv" ] +resolver = "2" [workspace.package] -version = "0.0.14" +version = "0.0.15" edition = "2021" license = "MIT OR Apache-2.0" repository = "https://github.com/icann/icann-rdap" @@ -22,32 +23,33 @@ anyhow = "1.0" async-trait = "0.1" # axum (web server) -axum = { version = "0.6", features = ["headers"] } -axum-macros = "0.3" +axum = { version = "0.7" } +axum-extra = { version = "0.9", features = [ "typed-header" ] } +axum-macros = "0.4" # client IP address extractor -axum-client-ip = "0.3.0" +axum-client-ip = "0.5" # b-tree with ranges -btree-range-map = "0.5.1" +btree-range-map = "0.7.2" # macros for the builder pattern buildstructor = "0.5" # CIDR utilities -cidr-utils = "0.5" +cidr-utils = "0.6" # command line options parser -clap = { version = "4.3.19", features = [ "std", "derive", "env", "unstable-styles" ] } +clap = { version = "4.4", features = [ "std", "derive", "env", "unstable-styles" ] } # chrono (time and date library) chrono = { version = "0.4", features = ["alloc", "std", "clock", "serde"], default-features = false } # compile time constants formatting -const_format = "0.2.30" +const_format = "0.2" # cross-platform application directories -directories = "5.0.0" +directories = "5.0" # loads environment variables from the a file dotenv = "0.15.0" @@ -68,22 +70,19 @@ git-version = "0.3" lazy_static = "1.4" # headers (http headers) -headers = "0.3" +headers = "0.4" # http constructs -http = "0.2" +http = "1.0" # hyper (http implementation used by axum) -hyper = { version = "0.14", features = ["full"] } +hyper = { version = "1.0", features = ["full"] } # for use prefixmap -ipnet = { version = "2.7", features = ["json"] } - -# using terminal helper -is-terminal = "0.4" +ipnet = { version = "2.9", features = ["json"] } # embedded pager -minus = {version = "5.4", features = ["dynamic_output", "search"] } +minus = {version = "5.5", features = ["dynamic_output", "search"] } # percent encoding pct-str = "1.2" @@ -92,7 +91,7 @@ pct-str = "1.2" prefix-trie = "0.2.4" # regular expresions -regex = "1.7" +regex = "1.10" # http client library reqwest = {version = "0.11", features = ["json", "stream", "native-tls-vendored"]} @@ -104,13 +103,12 @@ serde = { version = "1.0", features = [ "derive" ] } serde_json = "1.0" # sqlx (async db) -sqlx = { version = "0.6", features = [ +sqlx = { version = "0.7", features = [ "runtime-tokio-rustls", "postgres", "chrono", "macros", "json", - "offline", ] } # enum utilities @@ -118,17 +116,17 @@ strum = "0.24" strum_macros = "0.24" # terminal markdown generator -termimad = "0.23" +termimad = "0.26" # error macros thiserror = "1.0" # tokio async runtime -tokio = { version = "1.29", features = [ "full" ] } +tokio = { version = "1.35", features = [ "full" ] } # tower (tokio/axum middleware) tower = { version = "0.4", features = ["timeout", "util"] } -tower-http = { version = "0.3.3", features = [ +tower-http = { version = "0.5", features = [ "add-extension", "trace", "cors", diff --git a/README.md b/README.md index b9a88a1..ba553e2 100644 --- a/README.md +++ b/README.md @@ -30,3 +30,13 @@ Unless you explicitly state otherwise, any contribution, as defined in the Apach intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed pursuant to the Apache License, Version 2.0 or the MIT License referenced as above, at ICANN’s option, without any additional terms or conditions. + +How To Contribute +----------------- + +Before working on a Pull Request (PR), seek advice from the maintainers regarding the acceptance +of the PR. To do this, submit an issue outlining the idea for the PR. If the maintainers agree +that the contribution would be welcome, they will assign the issue to you. + +When submitting the PR, submit it against the 'dev' branch (not the 'main' branch). + diff --git a/icann-rdap-cli/Cargo.toml b/icann-rdap-cli/Cargo.toml index bf741ae..a0fd921 100644 --- a/icann-rdap-cli/Cargo.toml +++ b/icann-rdap-cli/Cargo.toml @@ -14,8 +14,8 @@ path = "src/main.rs" [dependencies] -icann-rdap-client = { version = "0.0.14", path = "../icann-rdap-client" } -icann-rdap-common = { version = "0.0.14", path = "../icann-rdap-common" } +icann-rdap-client = { version = "0.0.15", path = "../icann-rdap-client" } +icann-rdap-common = { version = "0.0.15", path = "../icann-rdap-common" } anyhow.workspace = true clap.workspace = true @@ -24,7 +24,6 @@ const_format.workspace = true directories.workspace = true dotenv.workspace = true ipnet.workspace = true -is-terminal.workspace = true lazy_static.workspace = true minus.workspace = true pct-str.workspace = true @@ -51,6 +50,9 @@ cidr-utils = "0.5" # fixture testings rstest = "0.17.0" +# serial testings +serial_test = "2.0.0" + # test directories test_dir = "0.2.0" diff --git a/icann-rdap-cli/src/bootstrap.rs b/icann-rdap-cli/src/bootstrap.rs index c4bffc1..8b05716 100644 --- a/icann-rdap-cli/src/bootstrap.rs +++ b/icann-rdap-cli/src/bootstrap.rs @@ -1,16 +1,20 @@ -use core::panic; use std::{ fs::{self, File}, io::{BufRead, BufReader}, + path::PathBuf, }; -use icann_rdap_client::query::qtype::QueryType; +use icann_rdap_client::query::{ + bootstrap::{ + fetch_bootstrap, qtype_to_bootstrap_url, BootstrapStore, PreferredUrl, + RegistryHasNotExpired, + }, + qtype::QueryType, +}; use icann_rdap_common::{ cache::HttpData, - iana::{iana_request, IanaRegistry, IanaRegistryType}, + iana::{BootstrapRegistry, IanaRegistry, IanaRegistryType}, }; -use ipnet::{Ipv4Net, Ipv6Net}; -use prefix_trie::PrefixMap; use reqwest::Client; use tracing::debug; @@ -33,282 +37,133 @@ pub(crate) async fn get_base_url( return Ok(url.to_owned()); } + let store = FileCacheBootstrapStore; + match bootstrap_type { - BootstrapType::None => qtype_to_bootstrap_url(client, query_type).await, + BootstrapType::None => Ok(qtype_to_bootstrap_url(client, &store, query_type, |reg| { + debug!("Fetching IANA registry {}", reg.url()) + }) + .await?), BootstrapType::Url(url) => Ok(url.to_owned()), BootstrapType::Tag(tag) => { - let iana = get_iana_registry(IanaRegistryType::RdapObjectTags, client).await?; - let urls = get_tag_bootstrap_urls(iana, tag)?; - Ok(get_preferred_url(urls)?) + fetch_bootstrap(&IanaRegistryType::RdapObjectTags, client, &store, |_reg| { + debug!("Fetching IANA RDAP Object Tag Registry") + }) + .await?; + Ok(store.get_tag_urls(tag)?.preferred_url()?) } } } -pub(crate) async fn qtype_to_bootstrap_url( - client: &Client, - query_type: &QueryType, -) -> Result { - match query_type { - QueryType::IpV4Addr(_) | QueryType::IpV4Cidr(_) => { - let iana = get_iana_registry(IanaRegistryType::RdapBootstrapIpv4, client).await?; - let urls = get_ipv4_bootstrap_urls(iana, query_type)?; - Ok(get_preferred_url(urls)?) - } - QueryType::IpV6Addr(_) | QueryType::IpV6Cidr(_) => { - let iana = get_iana_registry(IanaRegistryType::RdapBootstrapIpv6, client).await?; - let urls = get_ipv6_bootstrap_urls(iana, query_type)?; - Ok(get_preferred_url(urls)?) +struct FileCacheBootstrapStore; + +impl BootstrapStore for FileCacheBootstrapStore { + fn has_bootstrap_registry( + &self, + reg_type: &IanaRegistryType, + ) -> Result { + let path = bootstrap_cache_path().join(reg_type.file_name()); + if path.exists() { + let fc_reg = fetch_file_cache_bootstrap(path, |s| debug!("Checking for {s}"))?; + return Ok(Some(fc_reg).registry_has_not_expired()); } - QueryType::AsNumber(_) => { - let iana = get_iana_registry(IanaRegistryType::RdapBootstrapAsn, client).await?; - let urls = get_asn_bootstrap_urls(iana, query_type)?; - Ok(get_preferred_url(urls)?) - } - QueryType::Domain(_) => { - let iana = get_iana_registry(IanaRegistryType::RdapBootstrapDns, client).await?; - let urls = get_domain_bootstrap_urls(iana, query_type)?; - Ok(get_preferred_url(urls)?) - } - QueryType::Entity(_) => { - let iana = get_iana_registry(IanaRegistryType::RdapObjectTags, client).await?; - let urls = get_entity_handle_bootstrap_urls(iana, query_type)?; - Ok(get_preferred_url(urls)?) - } - QueryType::Nameserver(_) => { - let iana = get_iana_registry(IanaRegistryType::RdapBootstrapDns, client).await?; - let urls = get_domain_bootstrap_urls(iana, query_type)?; - Ok(get_preferred_url(urls)?) - } - _ => Err(CliError::BootstrapNotFound), + Ok(false) } -} -/// Prefer HTTPS urls. -fn get_preferred_url(urls: Vec) -> Result { - if urls.is_empty() { - Err(CliError::InvalidBootstrap) - } else { - let url = urls - .iter() - .find(|s| s.starts_with("https://")) - .unwrap_or_else(|| urls.first().unwrap()); - Ok(url.to_owned()) + fn put_bootstrap_registry( + &self, + reg_type: &IanaRegistryType, + registry: IanaRegistry, + http_data: HttpData, + ) -> Result<(), icann_rdap_client::RdapClientError> { + let path = bootstrap_cache_path().join(reg_type.file_name()); + let data = serde_json::to_string_pretty(®istry)?; + let cache_contents = http_data.to_lines(&data)?; + fs::write(path, cache_contents)?; + Ok(()) } -} -/// Gets the bootstrap url from IANA. Requirements are that it must be the longest match. -fn get_domain_bootstrap_urls( - iana: IanaRegistry, - query_type: &QueryType, -) -> Result, CliError> { - let domain_name = match query_type { - QueryType::Domain(domain) => domain, - QueryType::Nameserver(ns) => ns, - _ => panic!("invalid domain query type"), - }; - let mut longest_match: Option<(usize, Vec)> = None; - let IanaRegistry::RdapBootstrapRegistry(bootstrap) = iana; - for service in bootstrap.services { - let tlds = service.first().ok_or(CliError::InvalidBootstrap)?; - for tld in tlds { - if domain_name.ends_with(tld) { - let urls = service.last().ok_or(CliError::InvalidBootstrap)?; - let longest = longest_match.get_or_insert_with(|| (tld.len(), urls.to_owned())); - if longest.0 < tld.len() { - *longest = (tld.len(), urls.to_owned()); - } - } - } + fn get_dns_urls(&self, ldh: &str) -> Result, icann_rdap_client::RdapClientError> { + let path = bootstrap_cache_path().join(IanaRegistryType::RdapBootstrapDns.file_name()); + let (iana, _http_data) = fetch_file_cache_bootstrap(path, |s| debug!("Reading {s}"))?; + Ok(iana.get_dns_bootstrap_urls(ldh)?) } - let longest = longest_match.ok_or(CliError::BootstrapNotFound)?; - Ok(longest.1) -} -fn get_asn_bootstrap_urls( - iana: IanaRegistry, - query_type: &QueryType, -) -> Result, CliError> { - let QueryType::AsNumber(asn) = query_type else { - panic!("invalid query type") - }; - let autnum = asn - .trim_start_matches(|c| -> bool { matches!(c, 'a' | 'A' | 's' | 'S') }) - .parse::() - .map_err(|_| CliError::InvalidBootstrap)?; - let IanaRegistry::RdapBootstrapRegistry(bootstrap) = iana; - for service in bootstrap.services { - let as_ranges = service.first().ok_or(CliError::InvalidBootstrap)?; - for range in as_ranges { - let as_split = range.split('-').collect::>(); - let start_as = as_split - .first() - .ok_or(CliError::InvalidBootstrap)? - .parse::() - .map_err(|_| CliError::InvalidBootstrap)?; - let end_as = as_split - .last() - .ok_or(CliError::InvalidBootstrap)? - .parse::() - .map_err(|_| CliError::InvalidBootstrap)?; - if start_as <= autnum && end_as >= autnum { - let urls = service.last().ok_or(CliError::InvalidBootstrap)?; - return Ok(urls.to_owned()); - } - } + fn get_asn_urls(&self, asn: &str) -> Result, icann_rdap_client::RdapClientError> { + let path = bootstrap_cache_path().join(IanaRegistryType::RdapBootstrapAsn.file_name()); + let (iana, _http_data) = fetch_file_cache_bootstrap(path, |s| debug!("Reading {s}"))?; + Ok(iana.get_asn_bootstrap_urls(asn)?) } - Err(CliError::BootstrapNotFound) -} -fn get_ipv4_bootstrap_urls( - iana: IanaRegistry, - query_type: &QueryType, -) -> Result, CliError> { - let ip = match query_type { - QueryType::IpV4Addr(addr) => format!("{addr}/32"), - QueryType::IpV4Cidr(cidr) => cidr.to_owned(), - _ => panic!("non ip query for ip bootstrap"), - }; - let mut pm: PrefixMap> = PrefixMap::new(); - let IanaRegistry::RdapBootstrapRegistry(bootstrap) = iana; - for service in bootstrap.services { - let urls = service.last().ok_or(CliError::InvalidBootstrap)?; - for cidr in service.first().ok_or(CliError::InvalidBootstrap)? { - pm.insert( - cidr.parse().map_err(|_| CliError::InvalidBootstrap)?, - urls.clone(), - ); - } + fn get_ipv4_urls(&self, ipv4: &str) -> Result, icann_rdap_client::RdapClientError> { + let path = bootstrap_cache_path().join(IanaRegistryType::RdapBootstrapIpv4.file_name()); + let (iana, _http_data) = fetch_file_cache_bootstrap(path, |s| debug!("Reading {s}"))?; + Ok(iana.get_ipv4_bootstrap_urls(ipv4)?) } - let net = pm - .get_lpm(&ip.parse().map_err(|_| CliError::InvalidBootstrap)?) - .ok_or(CliError::BootstrapNotFound)?; - Ok(net.1.to_owned()) -} -fn get_ipv6_bootstrap_urls( - iana: IanaRegistry, - query_type: &QueryType, -) -> Result, CliError> { - let ip = match query_type { - QueryType::IpV6Addr(addr) => format!("{addr}/128"), - QueryType::IpV6Cidr(cidr) => cidr.to_owned(), - _ => panic!("non ip query for ip bootstrap"), - }; - let mut pm: PrefixMap> = PrefixMap::new(); - let IanaRegistry::RdapBootstrapRegistry(bootstrap) = iana; - for service in bootstrap.services { - let urls = service.last().ok_or(CliError::InvalidBootstrap)?; - for cidr in service.first().ok_or(CliError::InvalidBootstrap)? { - pm.insert( - cidr.parse().map_err(|_| CliError::InvalidBootstrap)?, - urls.clone(), - ); - } + fn get_ipv6_urls(&self, ipv6: &str) -> Result, icann_rdap_client::RdapClientError> { + let path = bootstrap_cache_path().join(IanaRegistryType::RdapBootstrapIpv6.file_name()); + let (iana, _http_data) = fetch_file_cache_bootstrap(path, |s| debug!("Reading {s}"))?; + Ok(iana.get_ipv6_bootstrap_urls(ipv6)?) } - let net = pm - .get_lpm(&ip.parse().map_err(|_| CliError::InvalidBootstrap)?) - .ok_or(CliError::BootstrapNotFound)?; - Ok(net.1.to_owned()) -} -fn get_entity_handle_bootstrap_urls( - iana: IanaRegistry, - query_type: &QueryType, -) -> Result, CliError> { - let QueryType::Entity(handle) = query_type else { - panic!("non entity handle for bootstrap") - }; - let handle_split = handle.rsplit_once('-').ok_or(CliError::BootstrapNotFound)?; - get_tag_bootstrap_urls(iana, handle_split.1) -} - -fn get_tag_bootstrap_urls(iana: IanaRegistry, tag: &str) -> Result, CliError> { - let IanaRegistry::RdapBootstrapRegistry(bootstrap) = iana; - for service in bootstrap.services { - let object_tag = service - .get(1) - .ok_or(CliError::InvalidBootstrap)? - .first() - .ok_or(CliError::InvalidBootstrap)?; - if object_tag.to_ascii_uppercase() == tag.to_ascii_uppercase() { - let urls = service.last().ok_or(CliError::InvalidBootstrap)?; - return Ok(urls.to_owned()); - } + fn get_tag_urls(&self, tag: &str) -> Result, icann_rdap_client::RdapClientError> { + let path = bootstrap_cache_path().join(IanaRegistryType::RdapObjectTags.file_name()); + let (iana, _http_data) = fetch_file_cache_bootstrap(path, |s| debug!("Reading {s}"))?; + Ok(iana.get_tag_bootstrap_urls(tag)?) } - Err(CliError::BootstrapNotFound) } -async fn get_iana_registry( - reg_type: IanaRegistryType, - client: &Client, -) -> Result { - let path = bootstrap_cache_path().join(reg_type.file_name()); - if path.exists() { - let input = File::open(&path)?; - let buf = BufReader::new(input); - let mut lines = Vec::new(); - for line in buf.lines() { - lines.push(line?); - } - let cache_data = HttpData::from_lines(&lines)?; - if !cache_data.0.is_expired(604800i64) { - debug!("Getting bootstrap from {}", reg_type.file_name()); - let iana: IanaRegistry = serde_json::from_str(&cache_data.1.join(""))?; - return Ok(iana); - } +fn fetch_file_cache_bootstrap( + path: PathBuf, + callback: F, +) -> Result<(IanaRegistry, HttpData), std::io::Error> +where + F: FnOnce(String), +{ + let input = File::open(&path)?; + let buf = BufReader::new(input); + let mut lines = Vec::new(); + for line in buf.lines() { + lines.push(line?); } - debug!("Getting IANA bootstrap from {}", reg_type.url()); - let iana = iana_request(reg_type, client).await?; - let data = serde_json::to_string_pretty(&iana.registry)?; - let cache_contents = iana.http_data.to_lines(&data)?; - fs::write(path, cache_contents)?; - Ok(iana.registry) + let cache_data = HttpData::from_lines(&lines)?; + callback(path.display().to_string()); + let iana: IanaRegistry = serde_json::from_str(&cache_data.1.join(""))?; + Ok((iana, cache_data.0)) } #[cfg(test)] #[allow(non_snake_case)] -mod tests { - use icann_rdap_client::query::qtype::QueryType; - use icann_rdap_common::iana::IanaRegistry; - use rstest::rstest; - - use crate::bootstrap::{ - get_asn_bootstrap_urls, get_ipv4_bootstrap_urls, get_ipv6_bootstrap_urls, - get_tag_bootstrap_urls, +mod test { + use icann_rdap_client::query::{bootstrap::PreferredUrl, qtype::QueryType}; + use icann_rdap_common::{ + cache::HttpData, + iana::{IanaRegistry, IanaRegistryType}, }; + use serial_test::serial; + use test_dir::{DirBuilder, FileType, TestDir}; - use super::{get_domain_bootstrap_urls, get_preferred_url}; - - #[test] - fn GIVEN_one_url_WHEN_preferred_urls_THEN_that_is_the_one() { - // GIVEN - let urls = vec!["http://foo.example".to_string()]; - - // WHEN - let actual = get_preferred_url(urls).expect("cannot get preferred url"); - - // THEN - assert_eq!(actual, "http://foo.example"); - } - - #[test] - fn GIVEN_one_http_and_https_url_WHEN_preferred_urls_THEN_return_https() { - // GIVEN - let urls = vec![ - "http://foo.example".to_string(), - "https://foo.example".to_string(), - ]; + use crate::bootstrap::FileCacheBootstrapStore; - // WHEN - let actual = get_preferred_url(urls).expect("cannot get preferred url"); + use super::BootstrapStore; - // THEN - assert_eq!(actual, "https://foo.example"); + fn test_dir() -> TestDir { + let test_dir = TestDir::temp() + .create("cache", FileType::Dir) + .create("config", FileType::Dir); + std::env::set_var("XDG_CACHE_HOME", test_dir.path("cache")); + std::env::set_var("XDG_CONFIG_HOME", test_dir.path("config")); + crate::dirs::init().expect("unable to init directories"); + test_dir } #[test] - fn GIVEN_domain_bootstrap_with_matching_WHEN_find_THEN_url_matches() { + #[serial] + fn GIVEN_fcbootstrap_with_dns_WHEN_get_domain_query_url_THEN_correct_url() { // GIVEN + let _test_dir = test_dir(); + let bs = FileCacheBootstrapStore; let bootstrap = r#" { "version": "1.0", @@ -332,110 +187,30 @@ mod tests { "#; let iana = serde_json::from_str::(bootstrap).expect("cannot parse domain bootstrap"); + bs.put_bootstrap_registry( + &IanaRegistryType::RdapBootstrapDns, + iana, + HttpData::now().host("example.com").build(), + ) + .expect("put iana registry"); // WHEN - let actual = get_domain_bootstrap_urls(iana, &QueryType::Domain("foo.org".to_string())); - - // THEN - assert_eq!( - actual.expect("no vec").first().expect("vec is empty"), - "https://example.org/" - ); - } - - #[test] - fn GIVEN_domain_bootstrap_with_two_matching_WHEN_find_THEN_return_longest_match() { - // GIVEN - let bootstrap = r#" - { - "version": "1.0", - "publication": "2024-01-07T10:11:12Z", - "description": "Some text", - "services": [ - [ - ["co.uk"], - [ - "https://registry.co.uk/" - ] - ], - [ - ["uk"], - [ - "https://registry.uk/" - ] - ] - ] - } - "#; - let iana = - serde_json::from_str::(bootstrap).expect("cannot parse domain bootstrap"); - - // WHEN - let actual = get_domain_bootstrap_urls(iana, &QueryType::Domain("foo.co.uk".to_string())); + let actual = bs + .get_domain_query_urls(&QueryType::Domain("example.org".to_string())) + .expect("get bootstrap url") + .preferred_url() + .expect("preferred url"); // THEN - assert_eq!( - actual.expect("no vec").first().expect("vec is empty"), - "https://registry.co.uk/" - ); + assert_eq!(actual, "https://example.org/") } #[test] - fn GIVEN_autnum_bootstrap_with_match_WHEN_find_with_string_THEN_return_match() { - // GIVEN - let bootstrap = r#" - { - "version": "1.0", - "publication": "2024-01-07T10:11:12Z", - "description": "RDAP Bootstrap file for example registries.", - "services": [ - [ - ["64496-64496"], - [ - "https://rir3.example.com/myrdap/" - ] - ], - [ - ["64497-64510", "65536-65551"], - [ - "https://example.org/" - ] - ], - [ - ["64512-65534"], - [ - "http://example.net/rdaprir2/", - "https://example.net/rdaprir2/" - ] - ] - ] - } - "#; - let iana = - serde_json::from_str::(bootstrap).expect("cannot parse autnum bootstrap"); - - // WHEN - let actual = get_asn_bootstrap_urls(iana, &QueryType::AsNumber("as64498".to_string())); - - // THEN - assert_eq!( - actual.expect("no vec").first().expect("vec is empty"), - "https://example.org/" - ); - } - - #[rstest] - #[case(64497u32, "https://example.org/")] - #[case(64498u32, "https://example.org/")] - #[case(64510u32, "https://example.org/")] - #[case(65536u32, "https://example.org/")] - #[case(65537u32, "https://example.org/")] - #[case(64513u32, "http://example.net/rdaprir2/")] - fn GIVEN_autnum_bootstrap_with_match_WHEN_find_with_number_THEN_return_match( - #[case] asn: u32, - #[case] bootstrap_url: &str, - ) { + #[serial] + fn GIVEN_fcbootstrap_with_autnum_WHEN_get_autnum_query_url_THEN_correct_url() { // GIVEN + let _test_dir = test_dir(); + let bs = FileCacheBootstrapStore; let bootstrap = r#" { "version": "1.0", @@ -466,65 +241,30 @@ mod tests { "#; let iana = serde_json::from_str::(bootstrap).expect("cannot parse autnum bootstrap"); + bs.put_bootstrap_registry( + &IanaRegistryType::RdapBootstrapAsn, + iana, + HttpData::now().host("example.com").build(), + ) + .expect("put iana registry"); // WHEN - let actual = get_asn_bootstrap_urls(iana, &QueryType::AsNumber(asn.to_string())); - - // THEN - assert_eq!( - actual.expect("no vec").first().expect("vec is empty"), - bootstrap_url - ); - } - - #[test] - fn GIVEN_ipv4_bootstrap_with_match_WHEN_find_with_ip_address_THEN_return_match() { - // GIVEN - let bootstrap = r#" - { - "version": "1.0", - "publication": "2024-01-07T10:11:12Z", - "description": "RDAP Bootstrap file for example registries.", - "services": [ - [ - ["198.51.100.0/24", "192.0.0.0/8"], - [ - "https://rir1.example.com/myrdap/" - ] - ], - [ - ["203.0.113.0/24", "192.0.2.0/24"], - [ - "https://example.org/" - ] - ], - [ - ["203.0.113.0/28"], - [ - "https://example.net/rdaprir2/", - "http://example.net/rdaprir2/" - ] - ] - ] - } - "#; - let iana = - serde_json::from_str::(bootstrap).expect("cannot parse ipv4 bootstrap"); - - // WHEN - let actual = - get_ipv4_bootstrap_urls(iana, &QueryType::IpV4Addr("198.51.100.1".to_string())); + let actual = bs + .get_autnum_query_urls(&QueryType::AsNumber("as64512".to_string())) + .expect("get bootstrap url") + .preferred_url() + .expect("preferred url"); // THEN - assert_eq!( - actual.expect("no vec").first().expect("vec is empty"), - "https://rir1.example.com/myrdap/" - ); + assert_eq!(actual, "https://example.net/rdaprir2/"); } #[test] - fn GIVEN_ipv4_bootstrap_with_match_WHEN_find_with_cidr_THEN_return_match() { + #[serial] + fn GIVEN_fcbootstrap_with_ipv4_THEN_get_ipv4_query_urls_THEN_correct_url() { // GIVEN + let _test_dir = test_dir(); + let bs = FileCacheBootstrapStore; let bootstrap = r#" { "version": "1.0", @@ -554,66 +294,31 @@ mod tests { } "#; let iana = - serde_json::from_str::(bootstrap).expect("cannot parse ipv4 bootstrap"); - - // WHEN - let actual = - get_ipv4_bootstrap_urls(iana, &QueryType::IpV4Cidr("203.0.113.0/24".to_string())); - - // THEN - assert_eq!( - actual.expect("no vec").first().expect("vec is empty"), - "https://example.org/" - ); - } - - #[test] - fn GIVEN_ipv6_bootstrap_with_match_WHEN_find_with_ip_address_THEN_return_match() { - // GIVEN - let bootstrap = r#" - { - "version": "1.0", - "publication": "2024-01-07T10:11:12Z", - "description": "RDAP Bootstrap file for example registries.", - "services": [ - [ - ["2001:db8::/34"], - [ - "https://rir2.example.com/myrdap/" - ] - ], - [ - ["2001:db8:4000::/36", "2001:db8:ffff::/48"], - [ - "https://example.org/" - ] - ], - [ - ["2001:db8:1000::/36"], - [ - "https://example.net/rdaprir2/", - "http://example.net/rdaprir2/" - ] - ] - ] - } - "#; - let iana = - serde_json::from_str::(bootstrap).expect("cannot parse ipv6 bootstrap"); + serde_json::from_str::(bootstrap).expect("cannot parse autnum bootstrap"); + bs.put_bootstrap_registry( + &IanaRegistryType::RdapBootstrapIpv4, + iana, + HttpData::now().host("example.com").build(), + ) + .expect("put iana registry"); // WHEN - let actual = get_ipv6_bootstrap_urls(iana, &QueryType::IpV6Addr("2001:db8::1".to_string())); + let actual = bs + .get_ipv4_query_urls(&QueryType::IpV4Addr("198.51.100.1".to_string())) + .expect("get bootstrap url") + .preferred_url() + .expect("preferred url"); // THEN - assert_eq!( - actual.expect("no vec").first().expect("vec is empty"), - "https://rir2.example.com/myrdap/" - ); + assert_eq!(actual, "https://rir1.example.com/myrdap/"); } #[test] - fn GIVEN_ipv6_bootstrap_with_match_WHEN_find_with_ip_cidr_THEN_return_match() { + #[serial] + fn GIVEN_fcbootstrap_with_ipv6_THEN_get_ipv6_query_urls_THEN_correct_url() { // GIVEN + let _test_dir = test_dir(); + let bs = FileCacheBootstrapStore; let bootstrap = r#" { "version": "1.0", @@ -643,22 +348,31 @@ mod tests { } "#; let iana = - serde_json::from_str::(bootstrap).expect("cannot parse ipv6 bootstrap"); + serde_json::from_str::(bootstrap).expect("cannot parse autnum bootstrap"); + bs.put_bootstrap_registry( + &IanaRegistryType::RdapBootstrapIpv6, + iana, + HttpData::now().host("example.com").build(), + ) + .expect("put iana registry"); // WHEN - let actual = - get_ipv6_bootstrap_urls(iana, &QueryType::IpV6Cidr("2001:db8:4000::/36".to_string())); + let actual = bs + .get_ipv6_query_urls(&QueryType::IpV6Addr("2001:db8::1".to_string())) + .expect("get bootstrap url") + .preferred_url() + .expect("preferred url"); // THEN - assert_eq!( - actual.expect("no vec").first().expect("vec is empty"), - "https://example.org/" - ); + assert_eq!(actual, "https://rir2.example.com/myrdap/"); } #[test] - fn GIVEN_tag_bootstrap_with_match_WHEN_find_with_tag_THEN_return_match() { + #[serial] + fn GIVEN_fcbootstrap_with_tag_THEN_get_entity_handle_query_urls_THEN_correct_url() { // GIVEN + let _test_dir = test_dir(); + let bs = FileCacheBootstrapStore; let bootstrap = r#" { "version": "1.0", @@ -691,15 +405,22 @@ mod tests { } "#; let iana = - serde_json::from_str::(bootstrap).expect("cannot parse tag bootstrap"); + serde_json::from_str::(bootstrap).expect("cannot parse autnum bootstrap"); + bs.put_bootstrap_registry( + &IanaRegistryType::RdapObjectTags, + iana, + HttpData::now().host("example.com").build(), + ) + .expect("put iana registry"); // WHEN - let actual = get_tag_bootstrap_urls(iana, "YYYY"); + let actual = bs + .get_entity_handle_query_urls(&QueryType::Entity("foo-YYYY".to_string())) + .expect("get bootstrap url") + .preferred_url() + .expect("preferred url"); // THEN - assert_eq!( - actual.expect("no vec").first().expect("vec is empty"), - "https://example.com/rdap/" - ); + assert_eq!(actual, "https://example.com/rdap/"); } } diff --git a/icann-rdap-cli/src/main.rs b/icann-rdap-cli/src/main.rs index 01e5c7d..c28dcaf 100644 --- a/icann-rdap-cli/src/main.rs +++ b/icann-rdap-cli/src/main.rs @@ -5,6 +5,7 @@ use icann_rdap_common::check::CheckClass; use icann_rdap_common::client::create_client; use icann_rdap_common::client::ClientConfig; use query::ProcessingParams; +use std::io::IsTerminal; use std::str::FromStr; use tracing::error; use tracing::info; @@ -18,7 +19,6 @@ use clap::{ArgGroup, Parser, ValueEnum}; use error::CliError; use icann_rdap_client::query::qtype::QueryType; use icann_rdap_common::VERSION; -use is_terminal::IsTerminal; use query::OutputType; use reqwest::Client; use tokio::{join, task::spawn_blocking}; diff --git a/icann-rdap-cli/src/request.rs b/icann-rdap-cli/src/request.rs index 059eb4f..a2ffd0e 100644 --- a/icann-rdap-cli/src/request.rs +++ b/icann-rdap-cli/src/request.rs @@ -5,7 +5,7 @@ use std::{ use icann_rdap_client::query::{ qtype::QueryType, - request::{rdap_request, ResponseData}, + request::{rdap_url_request, ResponseData}, }; use icann_rdap_common::{cache::HttpData, response::GetSelfLink}; use pct_str::PctString; @@ -24,8 +24,9 @@ pub(crate) async fn do_request( if processing_params.no_cache { info!("Cache has been disabled.") } + let query_url = query_type.query_url(base_url)?; + debug!("Requestion RDAP URL {query_url}"); if !processing_params.no_cache { - let query_url = query_type.query_url(base_url)?; let file_name = format!( "{}.cache", PctString::encode(query_url.chars(), URIReserved) @@ -49,7 +50,7 @@ pub(crate) async fn do_request( } } } - let response = rdap_request(base_url, query_type, client).await?; + let response = rdap_url_request(&query_url, client).await?; if !processing_params.no_cache { if let Some(self_link) = response.rdap.get_self_link() { if response.http_data.should_cache() { diff --git a/icann-rdap-cli/tests/integration/cache.rs b/icann-rdap-cli/tests/integration/cache.rs index e58cdbf..90f45f9 100644 --- a/icann-rdap-cli/tests/integration/cache.rs +++ b/icann-rdap-cli/tests/integration/cache.rs @@ -9,7 +9,7 @@ use crate::test_jig::TestJig; #[tokio::test(flavor = "multi_thread")] async fn GIVEN_domain_with_entity_WHEN_retreived_from_cache_THEN_is_domain() { // GIVEN - let mut test_jig = TestJig::new(); + let mut test_jig = TestJig::new().await; let mut tx = test_jig.mem.new_tx().await.expect("new transaction"); tx.add_domain( &Domain::basic() diff --git a/icann-rdap-cli/tests/integration/check.rs b/icann-rdap-cli/tests/integration/check.rs index d9bb130..2b53e14 100644 --- a/icann-rdap-cli/tests/integration/check.rs +++ b/icann-rdap-cli/tests/integration/check.rs @@ -8,7 +8,7 @@ use crate::test_jig::TestJig; #[tokio::test(flavor = "multi_thread")] async fn GIVEN_domain_with_check_WHEN_query_THEN_failure() { // GIVEN - let mut test_jig = TestJig::new(); + let mut test_jig = TestJig::new().await; let mut tx = test_jig.mem.new_tx().await.expect("new transaction"); tx.add_domain(&Domain::basic().ldh_name("foo.example").build()) .await diff --git a/icann-rdap-cli/tests/integration/queries.rs b/icann-rdap-cli/tests/integration/queries.rs index 7fea313..5608855 100644 --- a/icann-rdap-cli/tests/integration/queries.rs +++ b/icann-rdap-cli/tests/integration/queries.rs @@ -15,7 +15,7 @@ use crate::test_jig::TestJig; #[tokio::test(flavor = "multi_thread")] async fn GIVEN_domain_WHEN_query_THEN_success(#[case] db_domain: &str, #[case] q_domain: &str) { // GIVEN - let mut test_jig = TestJig::new(); + let mut test_jig = TestJig::new().await; let mut tx = test_jig.mem.new_tx().await.expect("new transaction"); tx.add_domain(&Domain::basic().ldh_name(db_domain).build()) .await @@ -33,7 +33,7 @@ async fn GIVEN_domain_WHEN_query_THEN_success(#[case] db_domain: &str, #[case] q #[tokio::test(flavor = "multi_thread")] async fn GIVEN_entity_WHEN_query_THEN_success() { // GIVEN - let mut test_jig = TestJig::new(); + let mut test_jig = TestJig::new().await; let mut tx = test_jig.mem.new_tx().await.expect("new transaction"); tx.add_entity(&Entity::basic().handle("foo").build()) .await @@ -51,7 +51,7 @@ async fn GIVEN_entity_WHEN_query_THEN_success() { #[tokio::test(flavor = "multi_thread")] async fn GIVEN_nameserver_WHEN_query_THEN_success() { // GIVEN - let mut test_jig = TestJig::new(); + let mut test_jig = TestJig::new().await; let mut tx = test_jig.mem.new_tx().await.expect("new transaction"); tx.add_nameserver( &Nameserver::basic() @@ -74,7 +74,7 @@ async fn GIVEN_nameserver_WHEN_query_THEN_success() { #[tokio::test(flavor = "multi_thread")] async fn GIVEN_autnum_WHEN_query_THEN_success() { // GIVEN - let mut test_jig = TestJig::new(); + let mut test_jig = TestJig::new().await; let mut tx = test_jig.mem.new_tx().await.expect("new transaction"); tx.add_autnum(&Autnum::basic().autnum_range(700..710).build()) .await @@ -92,7 +92,7 @@ async fn GIVEN_autnum_WHEN_query_THEN_success() { #[tokio::test(flavor = "multi_thread")] async fn GIVEN_network_ip_WHEN_query_THEN_success() { // GIVEN - let mut test_jig = TestJig::new(); + let mut test_jig = TestJig::new().await; let mut tx = test_jig.mem.new_tx().await.expect("new transaction"); tx.add_network( &Network::basic() @@ -118,7 +118,7 @@ async fn GIVEN_network_ip_WHEN_query_THEN_success() { #[tokio::test(flavor = "multi_thread")] async fn GIVEN_network_cidr_WHEN_query_THEN_success(#[case] db_cidr: &str, #[case] q_cidr: &str) { // GIVEN - let mut test_jig = TestJig::new(); + let mut test_jig = TestJig::new().await; let mut tx = test_jig.mem.new_tx().await.expect("new transaction"); tx.add_network( &Network::basic() @@ -141,7 +141,7 @@ async fn GIVEN_network_cidr_WHEN_query_THEN_success(#[case] db_cidr: &str, #[cas #[tokio::test(flavor = "multi_thread")] async fn GIVEN_url_WHEN_query_THEN_success() { // GIVEN - let mut test_jig = TestJig::new(); + let mut test_jig = TestJig::new().await; let mut tx = test_jig.mem.new_tx().await.expect("new transaction"); tx.add_domain(&Domain::basic().ldh_name("foo.example").build()) .await diff --git a/icann-rdap-cli/tests/integration/source.rs b/icann-rdap-cli/tests/integration/source.rs index b44899e..7d425cc 100644 --- a/icann-rdap-cli/tests/integration/source.rs +++ b/icann-rdap-cli/tests/integration/source.rs @@ -16,7 +16,7 @@ async fn GIVEN_inr_query_WHEN_query_THEN_source_is_rir( #[case] q_cidr: &str, ) { // GIVEN - let mut test_jig = TestJig::new(); + let mut test_jig = TestJig::new().await; let mut tx = test_jig.mem.new_tx().await.expect("new transaction"); tx.add_network( &Network::basic() diff --git a/icann-rdap-cli/tests/integration/test_jig.rs b/icann-rdap-cli/tests/integration/test_jig.rs index d40bb8a..5e5db3e 100644 --- a/icann-rdap-cli/tests/integration/test_jig.rs +++ b/icann-rdap-cli/tests/integration/test_jig.rs @@ -17,14 +17,16 @@ pub struct TestJig { } impl TestJig { - pub fn new() -> TestJig { + pub async fn new() -> TestJig { let mem = Mem::default(); let app_state = AppState { storage: mem.clone(), bootstrap: false, }; let _ = tracing_subscriber::fmt().try_init(); - let listener = Listener::listen(&ListenConfig::default()).expect("listening on interface"); + let listener = Listener::listen(&ListenConfig::default()) + .await + .expect("listening on interface"); let rdap_base = listener.rdap_base(); tokio::spawn(async move { listener diff --git a/icann-rdap-cli/tests/integration/url.rs b/icann-rdap-cli/tests/integration/url.rs index 6289a41..98e0c34 100644 --- a/icann-rdap-cli/tests/integration/url.rs +++ b/icann-rdap-cli/tests/integration/url.rs @@ -8,7 +8,7 @@ use crate::test_jig::TestJig; #[tokio::test(flavor = "multi_thread")] async fn GIVEN_url_used_with_base_url_WHEN_query_THEN_success() { // GIVEN - let mut test_jig = TestJig::new(); + let mut test_jig = TestJig::new().await; let mut tx = test_jig.mem.new_tx().await.expect("new transaction"); tx.add_network( &Network::basic() @@ -32,7 +32,7 @@ async fn GIVEN_url_used_with_base_url_WHEN_query_THEN_success() { #[tokio::test(flavor = "multi_thread")] async fn GIVEN_url_used_with_no_base_url_WHEN_query_THEN_success() { // GIVEN - let mut test_jig = TestJig::new(); + let mut test_jig = TestJig::new().await; test_jig.cmd.env_remove("RDAP_BASE_URL"); let mut tx = test_jig.mem.new_tx().await.expect("new transaction"); tx.add_network( diff --git a/icann-rdap-client/Cargo.toml b/icann-rdap-client/Cargo.toml index 038b89a..66e7609 100644 --- a/icann-rdap-client/Cargo.toml +++ b/icann-rdap-client/Cargo.toml @@ -10,7 +10,7 @@ An RDAP client library. [dependencies] -icann-rdap-common = { version = "0.0.14", path = "../icann-rdap-common" } +icann-rdap-common = { version = "0.0.15", path = "../icann-rdap-common" } buildstructor.workspace = true cidr-utils.workspace = true diff --git a/icann-rdap-client/README.md b/icann-rdap-client/README.md index 9a75c7c..cfec3bd 100644 --- a/icann-rdap-client/README.md +++ b/icann-rdap-client/README.md @@ -19,12 +19,45 @@ Both icann-rdap-common and icann-rdap-client can be compiled for WASM targets. Usage ----- +In RDAP, bootstrapping is the process of finding the authoritative RDAP server to +query using the IANA RDAP bootstrap files. To make a query using bootstrapping: + +```no_run +use icann_rdap_client::*; +use std::str::FromStr; +use tokio::main; + +#[tokio::main] +async fn main() -> Result<(), RdapClientError> { + + // create a query + let query = QueryType::from_str("192.168.0.1")?; + // or + let query = QueryType::from_str("icann.org")?; + + // create a client (from icann-rdap-common) + let config = ClientConfig::default(); + let client = create_client(&config)?; + // ideally, keep store in same context as client + let store = MemoryBootstrapStore::new(); + + // issue the RDAP query + let response = + rdap_bootstrapped_request( + &query, + &client, + &store, + |reg| eprintln!("fetching {reg:?}") + ).await?; + + Ok(()) +} +``` + +To specify a base URL: + ```rust,no_run -use icann_rdap_common::client::ClientConfig; -use icann_rdap_common::client::create_client; -use icann_rdap_client::query::request::rdap_request; -use icann_rdap_client::query::qtype::QueryType; -use icann_rdap_client::RdapClientError; +use icann_rdap_client::*; use std::str::FromStr; use tokio::main; diff --git a/icann-rdap-client/src/lib.rs b/icann-rdap-client/src/lib.rs index 98b5a78..ad5effe 100644 --- a/icann-rdap-client/src/lib.rs +++ b/icann-rdap-client/src/lib.rs @@ -1,16 +1,35 @@ #![allow(dead_code)] // TODO remove this at some point #![allow(rustdoc::bare_urls)] #![doc = include_str!("../README.md")] -use std::fmt::Display; +use std::{fmt::Display, sync::PoisonError}; -use icann_rdap_common::response::RdapResponseError; -use reqwest::Url; +use icann_rdap_common::{ + cache::HttpData, + iana::{BootstrapRegistryError, IanaResponseError}, + response::RdapResponseError, +}; use thiserror::Error; pub mod md; pub mod query; pub mod request; +#[doc(inline)] +pub use crate::query::bootstrap::MemoryBootstrapStore; +#[doc(inline)] +pub use crate::query::qtype::QueryType; +#[doc(inline)] +pub use crate::query::request::rdap_bootstrapped_request; +#[doc(inline)] +pub use crate::query::request::rdap_request; +#[doc(inline)] +pub use crate::query::request::rdap_url_request; +#[doc(inline)] +pub use icann_rdap_common::client::create_client; +#[doc(inline)] +pub use icann_rdap_common::client::ClientConfig; + +/// Error returned by RDAP client functions and methods. #[derive(Error, Debug)] pub enum RdapClientError { #[error("Query value is not valid.")] @@ -25,14 +44,29 @@ pub enum RdapClientError { ParsingError(Box), #[error(transparent)] Json(#[from] serde_json::Error), + #[error("RwLock Poison Error")] + Poison, + #[error("Bootstrap unavailable")] + BootstrapUnavailable, + #[error(transparent)] + BootstrapError(#[from] BootstrapRegistryError), + #[error(transparent)] + IanaResponse(#[from] IanaResponseError), + #[error(transparent)] + IoError(#[from] std::io::Error), +} + +impl From> for RdapClientError { + fn from(_err: PoisonError) -> Self { + Self::Poison + } } +/// Describes the error that occurs when parsing RDAP responses. #[derive(Debug)] pub struct ParsingErrorInfo { pub text: String, - pub content_length: Option, - pub content_type: Option, - pub url: Url, + pub http_data: HttpData, pub error: serde_json::Error, } @@ -42,12 +76,14 @@ impl Display for ParsingErrorInfo { f, "Error: {}\n,Content Length: {}\nContent Type: {}\nUrl: {}\nText:\n{}\n", self.error, - self.content_length + self.http_data + .content_length .map_or("No content length given".to_string(), |n| n.to_string()), - self.content_type + self.http_data + .content_type .clone() .unwrap_or("No content type given".to_string()), - self.url, + self.http_data.host, self.text ) } diff --git a/icann-rdap-client/src/md/string.rs b/icann-rdap-client/src/md/string.rs index bd62461..4918a35 100644 --- a/icann-rdap-client/src/md/string.rs +++ b/icann-rdap-client/src/md/string.rs @@ -237,7 +237,7 @@ mod tests { #[test] fn GIVEN_list_of_sentences_WHEN_make_list_all_title_case_THEN_each_sentence_all_title_cased() { // GIVEN - let v = vec!["foo bar", "foO baR"]; + let v = ["foo bar", "foO baR"]; // WHEN let actual = v.make_list_all_title_case(); @@ -249,7 +249,7 @@ mod tests { #[test] fn GIVEN_list_WHEN_make_title_case_list_THEN_comma_separated_title_cased() { // GIVEN - let list = vec!["foo bar", "bizz buzz"]; + let list = ["foo bar", "bizz buzz"]; // WHEN let actual = list.make_title_case_list(); diff --git a/icann-rdap-client/src/md/types.rs b/icann-rdap-client/src/md/types.rs index 76e971c..6d67f43 100644 --- a/icann-rdap-client/src/md/types.rs +++ b/icann-rdap-client/src/md/types.rs @@ -232,6 +232,7 @@ pub(crate) fn events_to_table( let event_date = &event .event_date .to_owned() + .unwrap_or("????".to_string()) .format_date_time(params) .unwrap_or_default(); let mut ul: Vec<&String> = vec![event_date]; diff --git a/icann-rdap-client/src/query/bootstrap.rs b/icann-rdap-client/src/query/bootstrap.rs new file mode 100644 index 0000000..e8bc7cc --- /dev/null +++ b/icann-rdap-client/src/query/bootstrap.rs @@ -0,0 +1,617 @@ +use std::sync::{Arc, RwLock}; + +use icann_rdap_common::{ + cache::HttpData, + iana::{ + get_preferred_url, iana_request, BootstrapRegistry, BootstrapRegistryError, IanaRegistry, + IanaRegistryType, + }, +}; +use reqwest::Client; + +use crate::RdapClientError; + +use super::qtype::QueryType; + +const SECONDS_IN_WEEK: i64 = 604800; + +/// Defines a trait for things that store bootstrap registries. +pub trait BootstrapStore { + /// Called when store is checked to see if it has a valid bootstrap registry. + /// + /// This method should return false (i.e. `Ok(false)``) if the registry doesn't + /// exist in the store or if the registry in the store is out-of-date (such as + /// the cache control data indicates it is old). + fn has_bootstrap_registry(&self, reg_type: &IanaRegistryType) -> Result; + + /// Puts a registry into the bootstrap registry store. + fn put_bootstrap_registry( + &self, + reg_type: &IanaRegistryType, + registry: IanaRegistry, + http_data: HttpData, + ) -> Result<(), RdapClientError>; + + /// Get the urls for a domain or nameserver (which are domain names) query type. + /// + /// The default method should be good enough for most trait implementations. + fn get_domain_query_urls( + &self, + query_type: &QueryType, + ) -> Result, RdapClientError> { + let domain_name = match query_type { + QueryType::Domain(domain) => domain, + QueryType::Nameserver(ns) => ns, + _ => panic!("invalid domain query type"), + }; + self.get_dns_urls(domain_name) + } + + /// Get the urls for an autnum query type. + /// + /// The default method should be good enough for most trait implementations. + fn get_autnum_query_urls( + &self, + query_type: &QueryType, + ) -> Result, RdapClientError> { + let QueryType::AsNumber(asn) = query_type else { + panic!("invalid query type") + }; + self.get_asn_urls(asn) + } + + /// Get the urls for an IPv4 query type. + /// + /// The default method should be good enough for most trait implementations. + fn get_ipv4_query_urls(&self, query_type: &QueryType) -> Result, RdapClientError> { + let ip = match query_type { + QueryType::IpV4Addr(addr) => format!("{addr}/32"), + QueryType::IpV4Cidr(cidr) => cidr.to_owned(), + _ => panic!("non ip query for ip bootstrap"), + }; + self.get_ipv4_urls(&ip) + } + + /// Get the urls for an IPv6 query type. + /// + /// The default method should be good enough for most trait implementations. + fn get_ipv6_query_urls(&self, query_type: &QueryType) -> Result, RdapClientError> { + let ip = match query_type { + QueryType::IpV6Addr(addr) => format!("{addr}/128"), + QueryType::IpV6Cidr(cidr) => cidr.to_owned(), + _ => panic!("non ip query for ip bootstrap"), + }; + self.get_ipv6_urls(&ip) + } + + /// Get the urls for an entity handle query type. + /// + /// The default method should be good enough for most trait implementations. + fn get_entity_handle_query_urls( + &self, + query_type: &QueryType, + ) -> Result, RdapClientError> { + let QueryType::Entity(handle) = query_type else { + panic!("non entity handle for bootstrap") + }; + let handle_split = handle + .rsplit_once('-') + .ok_or(BootstrapRegistryError::InvalidBootstrapInput)?; + self.get_tag_query_urls(handle_split.1) + } + + /// Get the urls for an object tag query type. + /// + /// The default method should be good enough for most trait implementations. + fn get_tag_query_urls(&self, tag: &str) -> Result, RdapClientError> { + self.get_tag_urls(tag) + } + + /// Get the URLs associated with the IANA RDAP DNS bootstrap. + /// + /// Implementations should implement the logic to pull the [icann_rdap_common::iana::IanaRegistry] + /// and ultimately call its [icann_rdap_common::iana::IanaRegistry::get_dns_bootstrap_urls] method. + fn get_dns_urls(&self, ldh: &str) -> Result, RdapClientError>; + + /// Get the URLs associated with the IANA RDAP ASN bootstrap. + /// + /// Implementations should implement the logic to pull the [icann_rdap_common::iana::IanaRegistry] + /// and ultimately call its [icann_rdap_common::iana::IanaRegistry::get_asn_bootstrap_urls] method. + fn get_asn_urls(&self, asn: &str) -> Result, RdapClientError>; + + /// Get the URLs associated with the IANA RDAP IPv4 bootstrap. + /// + /// Implementations should implement the logic to pull the [icann_rdap_common::iana::IanaRegistry] + /// and ultimately call its [icann_rdap_common::iana::IanaRegistry::get_ipv4_bootstrap_urls] method. + fn get_ipv4_urls(&self, ipv4: &str) -> Result, RdapClientError>; + + /// Get the URLs associated with the IANA RDAP IPv6 bootstrap. + /// + /// Implementations should implement the logic to pull the [icann_rdap_common::iana::IanaRegistry] + /// and ultimately call its [icann_rdap_common::iana::IanaRegistry::get_ipv6_bootstrap_urls] method. + fn get_ipv6_urls(&self, ipv6: &str) -> Result, RdapClientError>; + + /// Get the URLs associated with the IANA RDAP Object Tags bootstrap. + /// + /// Implementations should implement the logic to pull the [icann_rdap_common::iana::IanaRegistry] + /// and ultimately call its [icann_rdap_common::iana::IanaRegistry::get_tag_bootstrap_urls] method. + fn get_tag_urls(&self, tag: &str) -> Result, RdapClientError>; +} + +pub trait PreferredUrl { + fn preferred_url(self) -> Result; +} + +impl PreferredUrl for Vec { + fn preferred_url(self) -> Result { + Ok(get_preferred_url(self)?) + } +} + +/// A bootstrap registry store backed by memory. +/// +/// This implementation of [BootstrapStore] keeps registries in memory. Every new instance starts with +/// no registries in memory. They are added and maintained over time by calls to [MemoryBootstrapStore::put_bootstrap_registry()] by the +/// machinery of [crate::query::request::rdap_bootstrapped_request()] and [crate::query::bootstrap::qtype_to_bootstrap_url()]. +/// +/// Ideally, this should be kept in the same scope as [reqwest::Client]. +pub struct MemoryBootstrapStore { + ipv4: Arc>>, + ipv6: Arc>>, + autnum: Arc>>, + dns: Arc>>, + tag: Arc>>, +} + +impl Default for MemoryBootstrapStore { + fn default() -> Self { + Self::new() + } +} + +impl MemoryBootstrapStore { + pub fn new() -> Self { + MemoryBootstrapStore { + ipv4: Arc::new(RwLock::new(None)), + ipv6: Arc::new(RwLock::new(None)), + autnum: Arc::new(RwLock::new(None)), + dns: Arc::new(RwLock::new(None)), + tag: Arc::new(RwLock::new(None)), + } + } +} + +impl BootstrapStore for MemoryBootstrapStore { + fn has_bootstrap_registry(&self, reg_type: &IanaRegistryType) -> Result { + Ok(match reg_type { + IanaRegistryType::RdapBootstrapDns => self.dns.read()?.registry_has_not_expired(), + IanaRegistryType::RdapBootstrapAsn => self.autnum.read()?.registry_has_not_expired(), + IanaRegistryType::RdapBootstrapIpv4 => self.ipv4.read()?.registry_has_not_expired(), + IanaRegistryType::RdapBootstrapIpv6 => self.ipv6.read()?.registry_has_not_expired(), + IanaRegistryType::RdapObjectTags => self.tag.read()?.registry_has_not_expired(), + }) + } + + fn put_bootstrap_registry( + &self, + reg_type: &IanaRegistryType, + registry: IanaRegistry, + http_data: HttpData, + ) -> Result<(), RdapClientError> { + match reg_type { + IanaRegistryType::RdapBootstrapDns => { + let mut g = self.dns.write()?; + *g = Some((registry, http_data)); + } + IanaRegistryType::RdapBootstrapAsn => { + let mut g = self.autnum.write()?; + *g = Some((registry, http_data)); + } + IanaRegistryType::RdapBootstrapIpv4 => { + let mut g = self.ipv4.write()?; + *g = Some((registry, http_data)); + } + IanaRegistryType::RdapBootstrapIpv6 => { + let mut g = self.ipv6.write()?; + *g = Some((registry, http_data)); + } + IanaRegistryType::RdapObjectTags => { + let mut g = self.tag.write()?; + *g = Some((registry, http_data)); + } + }; + Ok(()) + } + + fn get_dns_urls(&self, ldh: &str) -> Result, RdapClientError> { + if let Some((iana, _http_data)) = self.dns.read()?.as_ref() { + Ok(iana.get_dns_bootstrap_urls(ldh)?) + } else { + Err(RdapClientError::BootstrapUnavailable) + } + } + + fn get_asn_urls(&self, asn: &str) -> Result, RdapClientError> { + if let Some((iana, _http_data)) = self.autnum.read()?.as_ref() { + Ok(iana.get_asn_bootstrap_urls(asn)?) + } else { + Err(RdapClientError::BootstrapUnavailable) + } + } + + fn get_ipv4_urls(&self, ipv4: &str) -> Result, RdapClientError> { + if let Some((iana, _http_data)) = self.ipv4.read()?.as_ref() { + Ok(iana.get_ipv4_bootstrap_urls(ipv4)?) + } else { + Err(RdapClientError::BootstrapUnavailable) + } + } + + fn get_ipv6_urls(&self, ipv6: &str) -> Result, RdapClientError> { + if let Some((iana, _http_data)) = self.ipv6.read()?.as_ref() { + Ok(iana.get_ipv6_bootstrap_urls(ipv6)?) + } else { + Err(RdapClientError::BootstrapUnavailable) + } + } + + fn get_tag_urls(&self, tag: &str) -> Result, RdapClientError> { + if let Some((iana, _http_data)) = self.tag.read()?.as_ref() { + Ok(iana.get_tag_bootstrap_urls(tag)?) + } else { + Err(RdapClientError::BootstrapUnavailable) + } + } +} + +pub trait RegistryHasNotExpired { + fn registry_has_not_expired(&self) -> bool; +} + +impl RegistryHasNotExpired for Option<(IanaRegistry, HttpData)> { + fn registry_has_not_expired(&self) -> bool { + if let Some((_iana, http_data)) = self { + !http_data.is_expired(SECONDS_IN_WEEK) + } else { + false + } + } +} + +pub async fn qtype_to_bootstrap_url( + client: &Client, + store: &dyn BootstrapStore, + query_type: &QueryType, + callback: F, +) -> Result +where + F: FnOnce(&IanaRegistryType), +{ + match query_type { + QueryType::IpV4Addr(_) | QueryType::IpV4Cidr(_) => { + fetch_bootstrap( + &IanaRegistryType::RdapBootstrapIpv4, + client, + store, + callback, + ) + .await?; + Ok(store.get_ipv4_query_urls(query_type)?.preferred_url()?) + } + QueryType::IpV6Addr(_) | QueryType::IpV6Cidr(_) => { + fetch_bootstrap( + &IanaRegistryType::RdapBootstrapIpv6, + client, + store, + callback, + ) + .await?; + Ok(store.get_ipv6_query_urls(query_type)?.preferred_url()?) + } + QueryType::AsNumber(_) => { + fetch_bootstrap(&IanaRegistryType::RdapBootstrapAsn, client, store, callback).await?; + Ok(store.get_autnum_query_urls(query_type)?.preferred_url()?) + } + QueryType::Domain(_) => { + fetch_bootstrap(&IanaRegistryType::RdapBootstrapDns, client, store, callback).await?; + Ok(store.get_domain_query_urls(query_type)?.preferred_url()?) + } + QueryType::Entity(_) => { + fetch_bootstrap(&IanaRegistryType::RdapObjectTags, client, store, callback).await?; + Ok(store + .get_entity_handle_query_urls(query_type)? + .preferred_url()?) + } + QueryType::Nameserver(_) => { + fetch_bootstrap(&IanaRegistryType::RdapBootstrapDns, client, store, callback).await?; + Ok(store.get_domain_query_urls(query_type)?.preferred_url()?) + } + _ => Err(RdapClientError::BootstrapUnavailable), + } +} + +pub async fn fetch_bootstrap( + reg_type: &IanaRegistryType, + client: &Client, + store: &dyn BootstrapStore, + callback: F, +) -> Result<(), RdapClientError> +where + F: FnOnce(&IanaRegistryType), +{ + if !store.has_bootstrap_registry(reg_type)? { + callback(reg_type); + let iana_resp = iana_request(reg_type.clone(), client).await?; + store.put_bootstrap_registry(reg_type, iana_resp.registry, iana_resp.http_data)?; + } + Ok(()) +} + +#[cfg(test)] +#[allow(non_snake_case)] +mod test { + use icann_rdap_common::{ + cache::HttpData, + iana::{IanaRegistry, IanaRegistryType}, + }; + + use crate::query::{bootstrap::PreferredUrl, qtype::QueryType}; + + use super::{BootstrapStore, MemoryBootstrapStore}; + + #[test] + fn GIVEN_membootstrap_with_dns_WHEN_get_domain_query_url_THEN_correct_url() { + // GIVEN + let mem = MemoryBootstrapStore::new(); + let bootstrap = r#" + { + "version": "1.0", + "publication": "2024-01-07T10:11:12Z", + "description": "Some text", + "services": [ + [ + ["net", "com"], + [ + "https://registry.example.com/myrdap/" + ] + ], + [ + ["org", "mytld"], + [ + "https://example.org/" + ] + ] + ] + } + "#; + let iana = + serde_json::from_str::(bootstrap).expect("cannot parse domain bootstrap"); + mem.put_bootstrap_registry( + &IanaRegistryType::RdapBootstrapDns, + iana, + HttpData::now().host("example.com").build(), + ) + .expect("put iana registry"); + + // WHEN + let actual = mem + .get_domain_query_urls(&QueryType::Domain("example.org".to_string())) + .expect("get bootstrap url") + .preferred_url() + .expect("preferred url"); + + // THEN + assert_eq!(actual, "https://example.org/") + } + + #[test] + fn GIVEN_membootstrap_with_autnum_WHEN_get_autnum_query_url_THEN_correct_url() { + // GIVEN + let mem = MemoryBootstrapStore::new(); + let bootstrap = r#" + { + "version": "1.0", + "publication": "2024-01-07T10:11:12Z", + "description": "RDAP Bootstrap file for example registries.", + "services": [ + [ + ["64496-64496"], + [ + "https://rir3.example.com/myrdap/" + ] + ], + [ + ["64497-64510", "65536-65551"], + [ + "https://example.org/" + ] + ], + [ + ["64512-65534"], + [ + "http://example.net/rdaprir2/", + "https://example.net/rdaprir2/" + ] + ] + ] + } + "#; + let iana = + serde_json::from_str::(bootstrap).expect("cannot parse autnum bootstrap"); + mem.put_bootstrap_registry( + &IanaRegistryType::RdapBootstrapAsn, + iana, + HttpData::now().host("example.com").build(), + ) + .expect("put iana registry"); + + // WHEN + let actual = mem + .get_autnum_query_urls(&QueryType::AsNumber("as64512".to_string())) + .expect("get bootstrap url") + .preferred_url() + .expect("preferred url"); + + // THEN + assert_eq!(actual, "https://example.net/rdaprir2/"); + } + + #[test] + fn GIVEN_membootstrap_with_ipv4_THEN_get_ipv4_query_urls_THEN_correct_url() { + // GIVEN + let mem = MemoryBootstrapStore::new(); + let bootstrap = r#" + { + "version": "1.0", + "publication": "2024-01-07T10:11:12Z", + "description": "RDAP Bootstrap file for example registries.", + "services": [ + [ + ["198.51.100.0/24", "192.0.0.0/8"], + [ + "https://rir1.example.com/myrdap/" + ] + ], + [ + ["203.0.113.0/24", "192.0.2.0/24"], + [ + "https://example.org/" + ] + ], + [ + ["203.0.113.0/28"], + [ + "https://example.net/rdaprir2/", + "http://example.net/rdaprir2/" + ] + ] + ] + } + "#; + let iana = + serde_json::from_str::(bootstrap).expect("cannot parse autnum bootstrap"); + mem.put_bootstrap_registry( + &IanaRegistryType::RdapBootstrapIpv4, + iana, + HttpData::now().host("example.com").build(), + ) + .expect("put iana registry"); + + // WHEN + let actual = mem + .get_ipv4_query_urls(&QueryType::IpV4Addr("198.51.100.1".to_string())) + .expect("get bootstrap url") + .preferred_url() + .expect("preferred url"); + + // THEN + assert_eq!(actual, "https://rir1.example.com/myrdap/"); + } + + #[test] + fn GIVEN_membootstrap_with_ipv6_THEN_get_ipv6_query_urls_THEN_correct_url() { + // GIVEN + let mem = MemoryBootstrapStore::new(); + let bootstrap = r#" + { + "version": "1.0", + "publication": "2024-01-07T10:11:12Z", + "description": "RDAP Bootstrap file for example registries.", + "services": [ + [ + ["2001:db8::/34"], + [ + "https://rir2.example.com/myrdap/" + ] + ], + [ + ["2001:db8:4000::/36", "2001:db8:ffff::/48"], + [ + "https://example.org/" + ] + ], + [ + ["2001:db8:1000::/36"], + [ + "https://example.net/rdaprir2/", + "http://example.net/rdaprir2/" + ] + ] + ] + } + "#; + let iana = + serde_json::from_str::(bootstrap).expect("cannot parse autnum bootstrap"); + mem.put_bootstrap_registry( + &IanaRegistryType::RdapBootstrapIpv6, + iana, + HttpData::now().host("example.com").build(), + ) + .expect("put iana registry"); + + // WHEN + let actual = mem + .get_ipv6_query_urls(&QueryType::IpV6Addr("2001:db8::1".to_string())) + .expect("get bootstrap url") + .preferred_url() + .expect("preferred url"); + + // THEN + assert_eq!(actual, "https://rir2.example.com/myrdap/"); + } + + #[test] + fn GIVEN_membootstrap_with_tag_THEN_get_tag_query_urls_THEN_correct_url() { + // GIVEN + let mem = MemoryBootstrapStore::new(); + let bootstrap = r#" + { + "version": "1.0", + "publication": "YYYY-MM-DDTHH:MM:SSZ", + "description": "RDAP bootstrap file for service provider object tags", + "services": [ + [ + ["contact@example.com"], + ["YYYY"], + [ + "https://example.com/rdap/" + ] + ], + [ + ["contact@example.org"], + ["ZZ54"], + [ + "http://rdap.example.org/" + ] + ], + [ + ["contact@example.net"], + ["1754"], + [ + "https://example.net/rdap/", + "http://example.net/rdap/" + ] + ] + ] + } + "#; + let iana = + serde_json::from_str::(bootstrap).expect("cannot parse autnum bootstrap"); + mem.put_bootstrap_registry( + &IanaRegistryType::RdapObjectTags, + iana, + HttpData::now().host("example.com").build(), + ) + .expect("put iana registry"); + + // WHEN + let actual = mem + .get_entity_handle_query_urls(&QueryType::Entity("foo-YYYY".to_string())) + .expect("get bootstrap url") + .preferred_url() + .expect("preferred url"); + + // THEN + assert_eq!(actual, "https://example.com/rdap/"); + } +} diff --git a/icann-rdap-client/src/query/mod.rs b/icann-rdap-client/src/query/mod.rs index fe4ebc5..a722ea9 100644 --- a/icann-rdap-client/src/query/mod.rs +++ b/icann-rdap-client/src/query/mod.rs @@ -1,2 +1,3 @@ +pub mod bootstrap; pub mod qtype; pub mod request; diff --git a/icann-rdap-client/src/query/qtype.rs b/icann-rdap-client/src/query/qtype.rs index 25153c7..eca1701 100644 --- a/icann-rdap-client/src/query/qtype.rs +++ b/icann-rdap-client/src/query/qtype.rs @@ -1,6 +1,6 @@ use std::{net::IpAddr, str::FromStr}; -use cidr_utils::cidr::IpCidr; +use cidr_utils::cidr::IpInet; use lazy_static::lazy_static; use pct_str::{PctString, URIReserved}; use regex::Regex; @@ -8,6 +8,7 @@ use strum_macros::Display; use crate::RdapClientError; +/// Defines the various types of RDAP lookups and searches. #[derive(Display, Debug)] pub enum QueryType { #[strum(serialize = "IpV4 Address Lookup")] @@ -158,10 +159,10 @@ impl FromStr for QueryType { } // if it is a cidr - if let Ok(ip_cidr) = IpCidr::from_str(s) { + if let Ok(ip_cidr) = IpInet::from_str(s) { return match ip_cidr { - IpCidr::V4(_) => Ok(QueryType::IpV4Cidr(s.to_owned())), - IpCidr::V6(_) => Ok(QueryType::IpV6Cidr(s.to_owned())), + IpInet::V4(_) => Ok(QueryType::IpV4Cidr(s.to_owned())), + IpInet::V6(_) => Ok(QueryType::IpV6Cidr(s.to_owned())), }; } diff --git a/icann-rdap-client/src/query/request.rs b/icann-rdap-client/src/query/request.rs index 281e991..d1ffa25 100644 --- a/icann-rdap-client/src/query/request.rs +++ b/icann-rdap-client/src/query/request.rs @@ -1,4 +1,4 @@ -use icann_rdap_common::{cache::HttpData, response::RdapResponse}; +use icann_rdap_common::{cache::HttpData, iana::IanaRegistryType, response::RdapResponse}; use reqwest::{ header::{CACHE_CONTROL, CONTENT_TYPE, EXPIRES, LOCATION}, Client, @@ -8,14 +8,43 @@ use serde_json::Value; use crate::RdapClientError; -use super::qtype::QueryType; +use super::{ + bootstrap::{qtype_to_bootstrap_url, BootstrapStore}, + qtype::QueryType, +}; -pub async fn rdap_request( - base_url: &str, - query_type: &QueryType, - client: &Client, -) -> Result { - let url = query_type.query_url(base_url)?; +/// Makes an RDAP request with a full RDAP URL. +/// +/// This function takes the following parameters: +/// * url - a string reference of the URL +/// * client - a reference to a [reqwest::Client]. +/// +/// ```no_run +/// use icann_rdap_common::client::ClientConfig; +/// use icann_rdap_common::client::create_client; +/// use icann_rdap_client::query::request::rdap_url_request; +/// use icann_rdap_client::RdapClientError; +/// use std::str::FromStr; +/// use tokio::main; +/// +/// #[tokio::main] +/// async fn main() -> Result<(), RdapClientError> { +/// +/// // create a client (from icann-rdap-common) +/// let config = ClientConfig::default(); +/// let client = create_client(&config)?; +/// +/// // issue the RDAP query +/// let response = +/// rdap_url_request( +/// "https://rdap-bootstrap.arin.net/bootstrap/ip/192.168.0.1", +/// &client, +/// ).await?; +/// +/// Ok(()) +/// } +/// ``` +pub async fn rdap_url_request(url: &str, client: &Client) -> Result { let response = client.get(url).send().await?.error_for_status()?; let content_type = response .headers() @@ -37,22 +66,24 @@ pub async fn rdap_request( let status_code = response.status().as_u16(); let url = response.url().to_owned(); let text = response.text().await?; + + let http_data = HttpData::now() + .status_code(status_code) + .and_location(location) + .and_content_length(content_length) + .and_content_type(content_type) + .host( + url.host_str() + .expect("URL has no host. This shouldn't happen.") + .to_owned(), + ) + .and_expires(expires) + .and_cache_control(cache_control) + .build(); + let json: Result = serde_json::from_str(&text); if let Ok(rdap_json) = json { let rdap = RdapResponse::try_from(rdap_json)?; - let http_data = HttpData::now() - .status_code(status_code) - .and_location(location) - .and_content_length(content_length) - .and_content_type(content_type) - .host( - url.host_str() - .expect("URL has no host. This shouldn't happen.") - .to_owned(), - ) - .and_expires(expires) - .and_cache_control(cache_control) - .build(); Ok(ResponseData { http_data, rdap_type: rdap.to_string(), @@ -62,16 +93,124 @@ pub async fn rdap_request( Err(RdapClientError::ParsingError(Box::new( crate::ParsingErrorInfo { text, - content_length, - content_type, - url, + http_data, error: json.err().unwrap(), }, ))) } } -#[derive(Serialize, Deserialize, Clone)] +/// Makes an RDAP request with a base URL. +/// +/// This function takes the following parameters: +/// * base_url - a string reference of the base URL +/// * query_type - a reference to the RDAP query. +/// * client - a reference to a [reqwest::Client]. +/// +/// ```no_run +/// use icann_rdap_common::client::ClientConfig; +/// use icann_rdap_common::client::create_client; +/// use icann_rdap_client::query::request::rdap_request; +/// use icann_rdap_client::query::qtype::QueryType; +/// use icann_rdap_client::RdapClientError; +/// use std::str::FromStr; +/// use tokio::main; +/// +/// #[tokio::main] +/// async fn main() -> Result<(), RdapClientError> { +/// +/// // create a query +/// let query = QueryType::from_str("192.168.0.1")?; +/// // or +/// let query = QueryType::from_str("icann.org")?; +/// +/// // create a client (from icann-rdap-common) +/// let config = ClientConfig::default(); +/// let client = create_client(&config)?; +/// +/// // issue the RDAP query +/// let response = +/// rdap_request( +/// "https://rdap-bootstrap.arin.net/bootstrap", +/// &query, +/// &client, +/// ).await?; +/// +/// Ok(()) +/// } +/// ``` +pub async fn rdap_request( + base_url: &str, + query_type: &QueryType, + client: &Client, +) -> Result { + let url = query_type.query_url(base_url)?; + rdap_url_request(&url, client).await +} + +/// Makes an RDAP request using bootstrapping. +/// +/// This function takes the following parameters: +/// * query_type - a reference to the RDAP query. +/// * client - a reference to a [reqwest::Client]. +/// * store - a reference to a [BootstrapStore]. +/// * callback - a closure that is called when an IANA registry is fetched. +/// +/// The [BootstrapStore] is responsible for holding IANA RDAP bootstrap registries. +/// It will be populated with IANA registries as needed. Ideally, the calling code +/// would be kept it in the same scope as `client`. When using the [crate::query::bootstrap::MemoryBootstrapStore], +/// creating a new store for each request will result it fetching the appropriate IANA +/// registry with each request which is most likely not the desired behavior. +/// +/// ```no_run +/// use icann_rdap_common::client::ClientConfig; +/// use icann_rdap_common::client::create_client; +/// use icann_rdap_client::query::request::rdap_bootstrapped_request; +/// use icann_rdap_client::query::qtype::QueryType; +/// use icann_rdap_client::query::bootstrap::MemoryBootstrapStore; +/// use icann_rdap_client::RdapClientError; +/// use std::str::FromStr; +/// use tokio::main; +/// +/// #[tokio::main] +/// async fn main() -> Result<(), RdapClientError> { +/// +/// // create a query +/// let query = QueryType::from_str("192.168.0.1")?; +/// // or +/// let query = QueryType::from_str("icann.org")?; +/// +/// // create a client (from icann-rdap-common) +/// let config = ClientConfig::default(); +/// let client = create_client(&config)?; +/// let store = MemoryBootstrapStore::new(); +/// +/// // issue the RDAP query +/// let response = +/// rdap_bootstrapped_request( +/// &query, +/// &client, +/// &store, +/// |reg| eprintln!("fetching {reg:?}") +/// ).await?; +/// +/// Ok(()) +/// } +/// ``` +pub async fn rdap_bootstrapped_request( + query_type: &QueryType, + client: &Client, + store: &dyn BootstrapStore, + callback: F, +) -> Result +where + F: FnOnce(&IanaRegistryType), +{ + let base_url = qtype_to_bootstrap_url(client, store, query_type, callback).await?; + rdap_request(&base_url, query_type, client).await +} + +#[derive(Serialize, Deserialize, Clone, Debug)] pub struct ResponseData { pub rdap: RdapResponse, pub rdap_type: String, diff --git a/icann-rdap-common/Cargo.toml b/icann-rdap-common/Cargo.toml index a629479..4447f52 100644 --- a/icann-rdap-common/Cargo.toml +++ b/icann-rdap-common/Cargo.toml @@ -13,7 +13,9 @@ chrono.workspace = true cidr-utils.workspace = true const_format.workspace = true buildstructor.workspace = true +ipnet.workspace = true lazy_static.workspace = true +prefix-trie.workspace = true reqwest.workspace = true serde.workspace = true serde_json.workspace = true diff --git a/icann-rdap-common/src/check/items.rs b/icann-rdap-common/src/check/items.rs index df0a0d8..540578b 100644 --- a/icann-rdap-common/src/check/items.rs +++ b/icann-rdap-common/src/check/items.rs @@ -65,6 +65,12 @@ impl CheckItem { } // Events + pub fn event_date_is_absent() -> CheckItem { + CheckItem { + check_class: CheckClass::SpecificationError, + check: Check::EventDateIsAbsent, + } + } pub fn event_date_is_not_rfc3339() -> CheckItem { CheckItem { check_class: CheckClass::SpecificationError, diff --git a/icann-rdap-common/src/check/mod.rs b/icann-rdap-common/src/check/mod.rs index 4c7160c..38fb222 100644 --- a/icann-rdap-common/src/check/mod.rs +++ b/icann-rdap-common/src/check/mod.rs @@ -171,6 +171,8 @@ pub enum Check { EmptyDomainVariant, // Events + #[strum(message = "event date is absent")] + EventDateIsAbsent, #[strum(message = "event date is not RFC 3339 compliant")] EventDateIsNotRfc3339, diff --git a/icann-rdap-common/src/check/network.rs b/icann-rdap-common/src/check/network.rs index 5105195..e07aff2 100644 --- a/icann-rdap-common/src/check/network.rs +++ b/icann-rdap-common/src/check/network.rs @@ -66,7 +66,7 @@ impl GetChecks for Network { } let this_network = IpCidr::from_str("0.0.0.0/8").expect("incorrect this netowrk cidr"); - if this_network.contains(start_addr) && this_network.contains(end_addr) { + if this_network.contains(&start_addr) && this_network.contains(&end_addr) { items.push(CheckItem::this_network()) } let private_10 = IpCidr::from_str("10.0.0.0/8").expect("incorrect net 10 cidr"); @@ -74,50 +74,50 @@ impl GetChecks for Network { IpCidr::from_str("172.16.0.0/12").expect("incorrect net 172.16 cidr"); let private_192 = IpCidr::from_str("192.168.0.0/16").expect("incorrect net 192.168 cidr"); - if (private_10.contains(start_addr) && private_10.contains(end_addr)) - || (private_172.contains(start_addr) && private_172.contains(end_addr)) - || (private_192.contains(start_addr) && private_192.contains(end_addr)) + if (private_10.contains(&start_addr) && private_10.contains(&end_addr)) + || (private_172.contains(&start_addr) && private_172.contains(&end_addr)) + || (private_192.contains(&start_addr) && private_192.contains(&end_addr)) { items.push(CheckItem::private_use_ip()) } let shared_nat = IpCidr::from_str("100.64.0.0/10").expect("incorrect net 100 cidr"); - if shared_nat.contains(start_addr) && shared_nat.contains(end_addr) { + if shared_nat.contains(&start_addr) && shared_nat.contains(&end_addr) { items.push(CheckItem::shared_nat_ip()) } let loopback = IpCidr::from_str("127.0.0.0/8").expect("incorrect loopback cidr"); - if loopback.contains(start_addr) && loopback.contains(end_addr) { + if loopback.contains(&start_addr) && loopback.contains(&end_addr) { items.push(CheckItem::loopback()) } let linklocal1 = IpCidr::from_str("169.254.0.0/16").expect("incorrect linklocal1 cidr"); let linklocal2 = IpCidr::from_str("fe80::/10").expect("incorrect linklocal2 cidr"); - if (linklocal1.contains(start_addr) && linklocal1.contains(end_addr)) - || (linklocal2.contains(start_addr) && linklocal2.contains(end_addr)) + if (linklocal1.contains(&start_addr) && linklocal1.contains(&end_addr)) + || (linklocal2.contains(&start_addr) && linklocal2.contains(&end_addr)) { items.push(CheckItem::linklocal()) } let uniquelocal = IpCidr::from_str("fe80::/10").expect("incorrect unique local cidr"); - if uniquelocal.contains(start_addr) && uniquelocal.contains(end_addr) { + if uniquelocal.contains(&start_addr) && uniquelocal.contains(&end_addr) { items.push(CheckItem::unique_local()) } let doc1 = IpCidr::from_str("192.0.2.0/24").expect("incorrect doc1 cidr"); let doc2 = IpCidr::from_str("198.51.100.0/24").expect("incorrect doc2 cidr"); let doc3 = IpCidr::from_str("203.0.113.0/24").expect("incorrect doc3 cidr"); let doc4 = IpCidr::from_str("2001:db8::/32").expect("incorrect doc4 cidr"); - if (doc1.contains(start_addr) && doc1.contains(end_addr)) - || (doc2.contains(start_addr) && doc2.contains(end_addr)) - || (doc3.contains(start_addr) && doc3.contains(end_addr)) - || (doc4.contains(start_addr) && doc4.contains(end_addr)) + if (doc1.contains(&start_addr) && doc1.contains(&end_addr)) + || (doc2.contains(&start_addr) && doc2.contains(&end_addr)) + || (doc3.contains(&start_addr) && doc3.contains(&end_addr)) + || (doc4.contains(&start_addr) && doc4.contains(&end_addr)) { items.push(CheckItem::documentation_net()) } let reserved = IpCidr::from_str("240.0.0.0/4").expect("incorrect reserved cidr"); - if reserved.contains(start_addr) && reserved.contains(end_addr) { + if reserved.contains(&start_addr) && reserved.contains(&end_addr) { items.push(CheckItem::linklocal()) } } diff --git a/icann-rdap-common/src/check/types.rs b/icann-rdap-common/src/check/types.rs index 364670c..1d51e40 100644 --- a/icann-rdap-common/src/check/types.rs +++ b/icann-rdap-common/src/check/types.rs @@ -208,11 +208,19 @@ impl GetSubChecks for ObjectCommon { // events if let Some(events) = &self.events { events.iter().for_each(|e| { - let date = DateTime::parse_from_rfc3339(&e.event_date); - if date.is_err() { + if let Some(date) = &e.event_date { + let date = DateTime::parse_from_rfc3339(date); + if date.is_err() { + sub_checks.push(Checks { + struct_name: "Events", + items: vec![CheckItem::event_date_is_not_rfc3339()], + sub_checks: Vec::new(), + }) + } + } else { sub_checks.push(Checks { - struct_name: "Links", - items: vec![CheckItem::event_date_is_not_rfc3339()], + struct_name: "Events", + items: vec![CheckItem::event_date_is_absent()], sub_checks: Vec::new(), }) } @@ -265,7 +273,7 @@ mod tests { domain::Domain, entity::Entity, nameserver::Nameserver, - types::{Common, Extension, Link, ObjectCommon, StatusValue}, + types::{Common, Event, Extension, Link, ObjectCommon, StatusValue}, RdapResponse, }; @@ -547,6 +555,71 @@ mod tests { .expect("link missing check"); } + #[test] + fn GIVEN_event_with_no_date_WHEN_checked_THEN_event_date_absent() { + // GIVEN + let rdap = RdapResponse::Domain( + Domain::builder() + .common(Common::builder().build()) + .object_common( + ObjectCommon::domain() + .events(vec![Event::builder().event_action("foo").build()]) + .build(), + ) + .build(), + ); + + // WHEN + let checks = rdap.get_checks(CheckParams { + do_subchecks: true, + root: &rdap, + parent_type: rdap.get_type(), + }); + + // THEN + checks + .sub("Events") + .expect("Events not found") + .items + .iter() + .find(|c| c.check == Check::EventDateIsAbsent) + .expect("event missing check"); + } + + #[test] + fn GIVEN_event_with_bad_date_WHEN_checked_THEN_event_date_is_not_date() { + // GIVEN + let rdap = RdapResponse::Domain( + Domain::builder() + .common(Common::builder().build()) + .object_common( + ObjectCommon::domain() + .events(vec![Event::builder() + .event_action("foo") + .event_date("bar") + .build()]) + .build(), + ) + .build(), + ); + + // WHEN + let checks = rdap.get_checks(CheckParams { + do_subchecks: true, + root: &rdap, + parent_type: rdap.get_type(), + }); + + // THEN + checks + .sub("Events") + .expect("Events not found") + .items + .iter() + .find(|c| c.check == Check::EventDateIsNotRfc3339) + .expect("event missing check"); + } + #[test] fn GIVEN_nameserver_with_no_links_WHEN_checked_THEN_no_object_classes_should_have_self_link() { // GIVEN diff --git a/icann-rdap-common/src/contact/from_vcard.rs b/icann-rdap-common/src/contact/from_vcard.rs index c2bc23a..ebba8e2 100644 --- a/icann-rdap-common/src/contact/from_vcard.rs +++ b/icann-rdap-common/src/contact/from_vcard.rs @@ -89,7 +89,7 @@ trait GetText<'a> { impl<'a> GetText<'a> for Option<&'a Vec> { fn get_text(self) -> Option { - let Some(values) = self else { return None }; + let values = self?; let Some(fourth) = values.get(3) else { return None; }; @@ -377,7 +377,7 @@ trait GetNameParts<'a> { impl<'a> GetNameParts<'a> for Option<&'a Vec> { fn get_name_parts(self) -> Option { - let Some(values) = self else { return None }; + let values = self?; let Some(fourth) = values.get(3) else { return None; }; diff --git a/icann-rdap-common/src/iana.rs b/icann-rdap-common/src/iana.rs index 6079b28..5b96149 100644 --- a/icann-rdap-common/src/iana.rs +++ b/icann-rdap-common/src/iana.rs @@ -1,3 +1,6 @@ +use ipnet::Ipv4Net; +use ipnet::Ipv6Net; +use prefix_trie::PrefixMap; use reqwest::{ header::{CACHE_CONTROL, CONTENT_TYPE, EXPIRES, LOCATION}, Client, @@ -50,6 +53,163 @@ pub struct RdapBootstrapRegistry { pub services: Vec>>, } +pub trait BootstrapRegistry { + fn get_dns_bootstrap_urls(&self, ldh: &str) -> Result, BootstrapRegistryError>; + fn get_asn_bootstrap_urls(&self, asn: &str) -> Result, BootstrapRegistryError>; + fn get_ipv4_bootstrap_urls(&self, ipv4: &str) -> Result, BootstrapRegistryError>; + fn get_ipv6_bootstrap_urls(&self, ipv6: &str) -> Result, BootstrapRegistryError>; + fn get_tag_bootstrap_urls(&self, tag: &str) -> Result, BootstrapRegistryError>; +} + +#[derive(Debug, Error)] +pub enum BootstrapRegistryError { + #[error("Empty Service")] + EmptyService, + #[error("Empty URL Set")] + EmptyUrlSet, + #[error("Invalid Bootstrap Input")] + InvalidBootstrapInput, + #[error("No Bootstrap URLs Found")] + NoBootstrapUrls, + #[error("Invalid Bootstrap Service")] + InvalidBootstrapService, +} + +impl BootstrapRegistry for IanaRegistry { + fn get_dns_bootstrap_urls(&self, ldh: &str) -> Result, BootstrapRegistryError> { + let mut longest_match: Option<(usize, Vec)> = None; + let IanaRegistry::RdapBootstrapRegistry(bootstrap) = self; + for service in &bootstrap.services { + let tlds = service + .first() + .ok_or(BootstrapRegistryError::EmptyService)?; + for tld in tlds { + if ldh.ends_with(tld) { + let urls = service.last().ok_or(BootstrapRegistryError::EmptyUrlSet)?; + let longest = longest_match.get_or_insert_with(|| (tld.len(), urls.to_owned())); + if longest.0 < tld.len() { + *longest = (tld.len(), urls.to_owned()); + } + } + } + } + let longest = longest_match.ok_or(BootstrapRegistryError::NoBootstrapUrls)?; + Ok(longest.1) + } + + fn get_asn_bootstrap_urls(&self, asn: &str) -> Result, BootstrapRegistryError> { + let autnum = asn + .trim_start_matches(|c| -> bool { matches!(c, 'a' | 'A' | 's' | 'S') }) + .parse::() + .map_err(|_| BootstrapRegistryError::InvalidBootstrapInput)?; + let IanaRegistry::RdapBootstrapRegistry(bootstrap) = self; + for service in &bootstrap.services { + let as_ranges = service + .first() + .ok_or(BootstrapRegistryError::EmptyService)?; + for range in as_ranges { + let as_split = range.split('-').collect::>(); + let start_as = as_split + .first() + .ok_or(BootstrapRegistryError::InvalidBootstrapService)? + .parse::() + .map_err(|_| BootstrapRegistryError::InvalidBootstrapInput)?; + let end_as = as_split + .last() + .ok_or(BootstrapRegistryError::InvalidBootstrapService)? + .parse::() + .map_err(|_| BootstrapRegistryError::InvalidBootstrapService)?; + if start_as <= autnum && end_as >= autnum { + let urls = service.last().ok_or(BootstrapRegistryError::EmptyUrlSet)?; + return Ok(urls.to_owned()); + } + } + } + Err(BootstrapRegistryError::NoBootstrapUrls) + } + + fn get_ipv4_bootstrap_urls(&self, ipv4: &str) -> Result, BootstrapRegistryError> { + let mut pm: PrefixMap> = PrefixMap::new(); + let IanaRegistry::RdapBootstrapRegistry(bootstrap) = self; + for service in &bootstrap.services { + let urls = service.last().ok_or(BootstrapRegistryError::EmptyService)?; + for cidr in service + .first() + .ok_or(BootstrapRegistryError::InvalidBootstrapService)? + { + pm.insert( + cidr.parse() + .map_err(|_| BootstrapRegistryError::InvalidBootstrapService)?, + urls.clone(), + ); + } + } + let net = pm + .get_lpm( + &ipv4 + .parse::() + .map_err(|_| BootstrapRegistryError::InvalidBootstrapInput)?, + ) + .ok_or(BootstrapRegistryError::NoBootstrapUrls)?; + Ok(net.1.to_owned()) + } + + fn get_ipv6_bootstrap_urls(&self, ipv6: &str) -> Result, BootstrapRegistryError> { + let mut pm: PrefixMap> = PrefixMap::new(); + let IanaRegistry::RdapBootstrapRegistry(bootstrap) = self; + for service in &bootstrap.services { + let urls = service.last().ok_or(BootstrapRegistryError::EmptyService)?; + for cidr in service + .first() + .ok_or(BootstrapRegistryError::InvalidBootstrapService)? + { + pm.insert( + cidr.parse() + .map_err(|_| BootstrapRegistryError::InvalidBootstrapService)?, + urls.clone(), + ); + } + } + let net = pm + .get_lpm( + &ipv6 + .parse::() + .map_err(|_| BootstrapRegistryError::InvalidBootstrapInput)?, + ) + .ok_or(BootstrapRegistryError::NoBootstrapUrls)?; + Ok(net.1.to_owned()) + } + + fn get_tag_bootstrap_urls(&self, tag: &str) -> Result, BootstrapRegistryError> { + let IanaRegistry::RdapBootstrapRegistry(bootstrap) = self; + for service in &bootstrap.services { + let object_tag = service + .get(1) + .ok_or(BootstrapRegistryError::InvalidBootstrapService)? + .first() + .ok_or(BootstrapRegistryError::EmptyService)?; + if object_tag.to_ascii_uppercase() == tag.to_ascii_uppercase() { + let urls = service.last().ok_or(BootstrapRegistryError::EmptyUrlSet)?; + return Ok(urls.to_owned()); + } + } + Err(BootstrapRegistryError::NoBootstrapUrls) + } +} + +/// Prefer HTTPS urls. +pub fn get_preferred_url(urls: Vec) -> Result { + if urls.is_empty() { + Err(BootstrapRegistryError::EmptyUrlSet) + } else { + let url = urls + .iter() + .find(|s| s.starts_with("https://")) + .unwrap_or_else(|| urls.first().unwrap()); + Ok(url.to_owned()) + } +} + #[derive(Debug, Serialize, Deserialize, Clone)] pub struct IanaResponse { pub registry: IanaRegistry, @@ -117,6 +277,8 @@ pub async fn iana_request( mod tests { use rstest::rstest; + use crate::iana::{get_preferred_url, BootstrapRegistry}; + use super::{IanaRegistry, IanaRegistryType}; #[rstest] @@ -176,4 +338,425 @@ mod tests { // THEN actual.unwrap(); } + + #[test] + fn GIVEN_one_url_WHEN_preferred_urls_THEN_that_is_the_one() { + // GIVEN + let urls = vec!["http://foo.example".to_string()]; + + // WHEN + let actual = get_preferred_url(urls).expect("cannot get preferred url"); + + // THEN + assert_eq!(actual, "http://foo.example"); + } + + #[test] + fn GIVEN_one_http_and_https_url_WHEN_preferred_urls_THEN_return_https() { + // GIVEN + let urls = vec![ + "http://foo.example".to_string(), + "https://foo.example".to_string(), + ]; + + // WHEN + let actual = get_preferred_url(urls).expect("cannot get preferred url"); + + // THEN + assert_eq!(actual, "https://foo.example"); + } + + #[test] + fn GIVEN_domain_bootstrap_with_matching_WHEN_find_THEN_url_matches() { + // GIVEN + let bootstrap = r#" + { + "version": "1.0", + "publication": "2024-01-07T10:11:12Z", + "description": "Some text", + "services": [ + [ + ["net", "com"], + [ + "https://registry.example.com/myrdap/" + ] + ], + [ + ["org", "mytld"], + [ + "https://example.org/" + ] + ] + ] + } + "#; + let iana = + serde_json::from_str::(bootstrap).expect("cannot parse domain bootstrap"); + + // WHEN + let actual = iana.get_dns_bootstrap_urls("foo.org"); + + // THEN + assert_eq!( + actual.expect("no vec").first().expect("vec is empty"), + "https://example.org/" + ); + } + + #[test] + fn GIVEN_domain_bootstrap_with_two_matching_WHEN_find_THEN_return_longest_match() { + // GIVEN + let bootstrap = r#" + { + "version": "1.0", + "publication": "2024-01-07T10:11:12Z", + "description": "Some text", + "services": [ + [ + ["co.uk"], + [ + "https://registry.co.uk/" + ] + ], + [ + ["uk"], + [ + "https://registry.uk/" + ] + ] + ] + } + "#; + let iana = + serde_json::from_str::(bootstrap).expect("cannot parse domain bootstrap"); + + // WHEN + let actual = iana.get_dns_bootstrap_urls("foo.co.uk"); + + // THEN + assert_eq!( + actual.expect("no vec").first().expect("vec is empty"), + "https://registry.co.uk/" + ); + } + + #[test] + fn GIVEN_autnum_bootstrap_with_match_WHEN_find_with_string_THEN_return_match() { + // GIVEN + let bootstrap = r#" + { + "version": "1.0", + "publication": "2024-01-07T10:11:12Z", + "description": "RDAP Bootstrap file for example registries.", + "services": [ + [ + ["64496-64496"], + [ + "https://rir3.example.com/myrdap/" + ] + ], + [ + ["64497-64510", "65536-65551"], + [ + "https://example.org/" + ] + ], + [ + ["64512-65534"], + [ + "http://example.net/rdaprir2/", + "https://example.net/rdaprir2/" + ] + ] + ] + } + "#; + let iana = + serde_json::from_str::(bootstrap).expect("cannot parse autnum bootstrap"); + + // WHEN + let actual = iana.get_asn_bootstrap_urls("as64498"); + + // THEN + assert_eq!( + actual.expect("no vec").first().expect("vec is empty"), + "https://example.org/" + ); + } + + #[rstest] + #[case(64497u32, "https://example.org/")] + #[case(64498u32, "https://example.org/")] + #[case(64510u32, "https://example.org/")] + #[case(65536u32, "https://example.org/")] + #[case(65537u32, "https://example.org/")] + #[case(64513u32, "http://example.net/rdaprir2/")] + fn GIVEN_autnum_bootstrap_with_match_WHEN_find_with_number_THEN_return_match( + #[case] asn: u32, + #[case] bootstrap_url: &str, + ) { + // GIVEN + let bootstrap = r#" + { + "version": "1.0", + "publication": "2024-01-07T10:11:12Z", + "description": "RDAP Bootstrap file for example registries.", + "services": [ + [ + ["64496-64496"], + [ + "https://rir3.example.com/myrdap/" + ] + ], + [ + ["64497-64510", "65536-65551"], + [ + "https://example.org/" + ] + ], + [ + ["64512-65534"], + [ + "http://example.net/rdaprir2/", + "https://example.net/rdaprir2/" + ] + ] + ] + } + "#; + let iana = + serde_json::from_str::(bootstrap).expect("cannot parse autnum bootstrap"); + + // WHEN + let actual = iana.get_asn_bootstrap_urls(&asn.to_string()); + + // THEN + assert_eq!( + actual.expect("no vec").first().expect("vec is empty"), + bootstrap_url + ); + } + + #[test] + fn GIVEN_ipv4_bootstrap_with_match_WHEN_find_with_ip_address_THEN_return_match() { + // GIVEN + let bootstrap = r#" + { + "version": "1.0", + "publication": "2024-01-07T10:11:12Z", + "description": "RDAP Bootstrap file for example registries.", + "services": [ + [ + ["198.51.100.0/24", "192.0.0.0/8"], + [ + "https://rir1.example.com/myrdap/" + ] + ], + [ + ["203.0.113.0/24", "192.0.2.0/24"], + [ + "https://example.org/" + ] + ], + [ + ["203.0.113.0/28"], + [ + "https://example.net/rdaprir2/", + "http://example.net/rdaprir2/" + ] + ] + ] + } + "#; + let iana = + serde_json::from_str::(bootstrap).expect("cannot parse ipv4 bootstrap"); + + // WHEN + let actual = iana.get_ipv4_bootstrap_urls("198.51.100.1/32"); + + // THEN + assert_eq!( + actual.expect("no vec").first().expect("vec is empty"), + "https://rir1.example.com/myrdap/" + ); + } + + #[test] + fn GIVEN_ipv4_bootstrap_with_match_WHEN_find_with_cidr_THEN_return_match() { + // GIVEN + let bootstrap = r#" + { + "version": "1.0", + "publication": "2024-01-07T10:11:12Z", + "description": "RDAP Bootstrap file for example registries.", + "services": [ + [ + ["198.51.100.0/24", "192.0.0.0/8"], + [ + "https://rir1.example.com/myrdap/" + ] + ], + [ + ["203.0.113.0/24", "192.0.2.0/24"], + [ + "https://example.org/" + ] + ], + [ + ["203.0.113.0/28"], + [ + "https://example.net/rdaprir2/", + "http://example.net/rdaprir2/" + ] + ] + ] + } + "#; + let iana = + serde_json::from_str::(bootstrap).expect("cannot parse ipv4 bootstrap"); + + // WHEN + let actual = iana.get_ipv4_bootstrap_urls("203.0.113.0/24"); + + // THEN + assert_eq!( + actual.expect("no vec").first().expect("vec is empty"), + "https://example.org/" + ); + } + + #[test] + fn GIVEN_ipv6_bootstrap_with_match_WHEN_find_with_ip_address_THEN_return_match() { + // GIVEN + let bootstrap = r#" + { + "version": "1.0", + "publication": "2024-01-07T10:11:12Z", + "description": "RDAP Bootstrap file for example registries.", + "services": [ + [ + ["2001:db8::/34"], + [ + "https://rir2.example.com/myrdap/" + ] + ], + [ + ["2001:db8:4000::/36", "2001:db8:ffff::/48"], + [ + "https://example.org/" + ] + ], + [ + ["2001:db8:1000::/36"], + [ + "https://example.net/rdaprir2/", + "http://example.net/rdaprir2/" + ] + ] + ] + } + "#; + let iana = + serde_json::from_str::(bootstrap).expect("cannot parse ipv6 bootstrap"); + + // WHEN + let actual = iana.get_ipv6_bootstrap_urls("2001:db8::1/128"); + + // THEN + assert_eq!( + actual.expect("no vec").first().expect("vec is empty"), + "https://rir2.example.com/myrdap/" + ); + } + + #[test] + fn GIVEN_ipv6_bootstrap_with_match_WHEN_find_with_ip_cidr_THEN_return_match() { + // GIVEN + let bootstrap = r#" + { + "version": "1.0", + "publication": "2024-01-07T10:11:12Z", + "description": "RDAP Bootstrap file for example registries.", + "services": [ + [ + ["2001:db8::/34"], + [ + "https://rir2.example.com/myrdap/" + ] + ], + [ + ["2001:db8:4000::/36", "2001:db8:ffff::/48"], + [ + "https://example.org/" + ] + ], + [ + ["2001:db8:1000::/36"], + [ + "https://example.net/rdaprir2/", + "http://example.net/rdaprir2/" + ] + ] + ] + } + "#; + let iana = + serde_json::from_str::(bootstrap).expect("cannot parse ipv6 bootstrap"); + + // WHEN + let actual = iana.get_ipv6_bootstrap_urls("2001:db8:4000::/36"); + + // THEN + assert_eq!( + actual.expect("no vec").first().expect("vec is empty"), + "https://example.org/" + ); + } + + #[test] + fn GIVEN_tag_bootstrap_with_match_WHEN_find_with_tag_THEN_return_match() { + // GIVEN + let bootstrap = r#" + { + "version": "1.0", + "publication": "YYYY-MM-DDTHH:MM:SSZ", + "description": "RDAP bootstrap file for service provider object tags", + "services": [ + [ + ["contact@example.com"], + ["YYYY"], + [ + "https://example.com/rdap/" + ] + ], + [ + ["contact@example.org"], + ["ZZ54"], + [ + "http://rdap.example.org/" + ] + ], + [ + ["contact@example.net"], + ["1754"], + [ + "https://example.net/rdap/", + "http://example.net/rdap/" + ] + ] + ] + } + "#; + let iana = + serde_json::from_str::(bootstrap).expect("cannot parse tag bootstrap"); + + // WHEN + let actual = iana.get_tag_bootstrap_urls("YYYY"); + + // THEN + assert_eq!( + actual.expect("no vec").first().expect("vec is empty"), + "https://example.com/rdap/" + ); + } } diff --git a/icann-rdap-common/src/response/mod.rs b/icann-rdap-common/src/response/mod.rs index fbba93a..00b0bd5 100644 --- a/icann-rdap-common/src/response/mod.rs +++ b/icann-rdap-common/src/response/mod.rs @@ -1,5 +1,6 @@ use std::any::TypeId; +use cidr_utils::cidr; use serde::{Deserialize, Serialize}; use serde_json::Value; use strum_macros::Display; @@ -38,7 +39,7 @@ pub enum RdapResponseError { #[error(transparent)] AddrParse(#[from] std::net::AddrParseError), #[error(transparent)] - CidrParse(#[from] cidr_utils::cidr::IpCidrError), + CidrParse(#[from] cidr::errors::NetworkParseError), } /// The various types of RDAP response. @@ -258,12 +259,12 @@ impl GetSelfLink for RdapResponse { pub trait GetSelfLink { /// Get's the first self link. - /// See [ObjectCommon::get_self_link()]. + /// See [crate::response::types::ObjectCommon::get_self_link()]. fn get_self_link(&self) -> Option<&Link>; } pub trait SelfLink: GetSelfLink { - /// See [ObjectCommon::get_self_link()]. + /// See [crate::response::types::ObjectCommon::get_self_link()]. fn set_self_link(self, link: Link) -> Self; } diff --git a/icann-rdap-common/src/response/network.rs b/icann-rdap-common/src/response/network.rs index 16d6e83..4fe8a7c 100644 --- a/icann-rdap-common/src/response/network.rs +++ b/icann-rdap-common/src/response/network.rs @@ -1,5 +1,7 @@ +use std::str::FromStr; + use buildstructor::Builder; -use cidr_utils::cidr::IpCidr; +use cidr_utils::cidr::IpInet; use serde::{Deserialize, Serialize}; use super::{ @@ -155,7 +157,7 @@ impl Network { entities: Option>, notices: Option>, ) -> Result { - let cidr = IpCidr::from_str(cidr)?; + let cidr = IpInet::from_str(&cidr)?; Ok(Self { common: Common::level0_with_options() .extension("cidr0") @@ -170,24 +172,24 @@ impl Network { .and_port_43(port_43) .and_entities(entities) .build(), - start_address: Some(cidr.first_as_ip_addr().to_string()), - end_address: Some(cidr.last_as_ip_addr().to_string()), + start_address: Some(cidr.first_address().to_string()), + end_address: Some(cidr.last_address().to_string()), ip_version: match cidr { - IpCidr::V4(_) => Some("v4".to_string()), - IpCidr::V6(_) => Some("v6".to_string()), + IpInet::V4(_) => Some("v4".to_string()), + IpInet::V6(_) => Some("v6".to_string()), }, name, network_type, parent_handle, country, cidr0_cidrs: match cidr { - IpCidr::V4(cidr) => Some(vec![Cidr0Cidr::V4Cidr(V4Cidr { - v4prefix: cidr.get_prefix_as_ipv4_addr().to_string(), - length: cidr.get_bits(), + IpInet::V4(cidr) => Some(vec![Cidr0Cidr::V4Cidr(V4Cidr { + v4prefix: cidr.first_address().to_string(), + length: cidr.network_length(), })]), - IpCidr::V6(cidr) => Some(vec![Cidr0Cidr::V6Cidr(V6Cidr { - v6prefix: cidr.get_prefix_as_ipv6_addr().to_string(), - length: cidr.get_bits(), + IpInet::V6(cidr) => Some(vec![Cidr0Cidr::V6Cidr(V6Cidr { + v6prefix: cidr.first_address().to_string(), + length: cidr.network_length(), })]), }, }) diff --git a/icann-rdap-common/src/response/types.rs b/icann-rdap-common/src/response/types.rs index 39886af..2b208bd 100644 --- a/icann-rdap-common/src/response/types.rs +++ b/icann-rdap-common/src/response/types.rs @@ -124,8 +124,13 @@ pub struct Event { #[serde(skip_serializing_if = "Option::is_none")] pub event_actor: Option, + /// This value is required by RFC 9083 (and 7483), + /// however some servers don't include it. Therefore + /// it is optional here to be compatible with these + /// types of non-compliant servers. #[serde(rename = "eventDate")] - pub event_date: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub event_date: Option, #[serde(skip_serializing_if = "Option::is_none")] pub links: Option, diff --git a/icann-rdap-srv/Cargo.toml b/icann-rdap-srv/Cargo.toml index f39fc54..4bb88cf 100644 --- a/icann-rdap-srv/Cargo.toml +++ b/icann-rdap-srv/Cargo.toml @@ -10,11 +10,12 @@ An RDAP Server. [dependencies] -icann-rdap-client = { version = "0.0.14", path = "../icann-rdap-client" } -icann-rdap-common = { version = "0.0.14", path = "../icann-rdap-common" } +icann-rdap-client = { version = "0.0.15", path = "../icann-rdap-client" } +icann-rdap-common = { version = "0.0.15", path = "../icann-rdap-common" } async-trait.workspace = true axum.workspace = true +axum-extra.workspace = true axum-macros.workspace = true axum-client-ip.workspace = true btree-range-map.workspace = true @@ -25,7 +26,6 @@ clap.workspace = true dotenv.workspace = true envmnt.workspace = true ipnet.workspace = true -is-terminal.workspace = true headers.workspace = true http.workspace = true hyper.workspace = true diff --git a/icann-rdap-srv/src/bin/rdap-srv-data.rs b/icann-rdap-srv/src/bin/rdap-srv-data.rs index 33ec0e7..3514805 100644 --- a/icann-rdap-srv/src/bin/rdap-srv-data.rs +++ b/icann-rdap-srv/src/bin/rdap-srv-data.rs @@ -2,6 +2,7 @@ use chrono::DateTime; use chrono::FixedOffset; use chrono::Utc; use cidr_utils::cidr::IpCidr; +use cidr_utils::cidr::IpInet; use clap::{Args, Parser, Subcommand}; use icann_rdap_client::query::qtype::QueryType; use icann_rdap_common::contact::Contact; @@ -60,6 +61,7 @@ use pct_str::URIReserved; use regex::Regex; use std::fs; use std::path::PathBuf; +use std::str::FromStr; use tracing::error; use tracing::info; use tracing_subscriber::{ @@ -501,8 +503,8 @@ struct SrvHelpArgs { } fn parse_cidr(arg: &str) -> Result { - let ip_cidr = IpCidr::from_str(arg).map_err(|e| RdapServerError::InvalidArg(e.to_string()))?; - Ok(ip_cidr) + let ip_inet = IpInet::from_str(arg).map_err(|e| RdapServerError::InvalidArg(e.to_string()))?; + Ok(ip_inet.network()) } #[tokio::main(flavor = "multi_thread")] diff --git a/icann-rdap-srv/src/bin/rdap-srv-test-data.rs b/icann-rdap-srv/src/bin/rdap-srv-test-data.rs index c5bb44a..b7ae362 100644 --- a/icann-rdap-srv/src/bin/rdap-srv-test-data.rs +++ b/icann-rdap-srv/src/bin/rdap-srv-test-data.rs @@ -106,7 +106,6 @@ fn make_entity_template( ) -> Result<(), RdapServerError> { let entity = make_test_entity(base_url, None); let ids: Vec = (0..num_entities) - .into_iter() .map(|x| { EntityId::builder() .handle(format!("test-entity-{x}")) @@ -127,7 +126,6 @@ fn make_nameserver_template( ) -> Result<(), RdapServerError> { let nameserver = make_test_nameserver(base_url, None)?; let ids: Vec = (0..num_nameservers) - .into_iter() .map(|x| { NameserverId::builder() .ldh_name(format!("ns.test-nameserver-{x}.example")) @@ -177,7 +175,6 @@ fn make_domain_template( )) .build(); let ids: Vec = (0..num_domains) - .into_iter() .map(|x| { DomainId::builder() .ldh_name(format!("test-domain-{x}.example")) @@ -225,7 +222,6 @@ fn make_autnum_template( )) .build(); let ids: Vec = (0..num_autnums) - .into_iter() .map(|x| AutnumId::builder().start_autnum(x).end_autnum(x).build()) .collect(); let template = Template::Autnum { diff --git a/icann-rdap-srv/src/bin/rdap-srv.rs b/icann-rdap-srv/src/bin/rdap-srv.rs index e555624..df86263 100644 --- a/icann-rdap-srv/src/bin/rdap-srv.rs +++ b/icann-rdap-srv/src/bin/rdap-srv.rs @@ -33,7 +33,8 @@ async fn main() -> Result<(), RdapServerError> { .ip_addr(listen_addr) .port(listen_port) .build(), - )?; + ) + .await?; listener .start_server( &ServiceConfig::builder() diff --git a/icann-rdap-srv/src/rdap/ip.rs b/icann-rdap-srv/src/rdap/ip.rs index d9c7caf..fd4745b 100644 --- a/icann-rdap-srv/src/rdap/ip.rs +++ b/icann-rdap-srv/src/rdap/ip.rs @@ -1,10 +1,10 @@ -use std::net::IpAddr; +use std::{net::IpAddr, str::FromStr}; use axum::{ extract::{Path, State}, response::Response, }; -use cidr_utils::cidr::IpCidr; +use cidr_utils::cidr::IpInet; use tracing::debug; use crate::{ @@ -25,7 +25,7 @@ pub(crate) async fn network_by_netid( ) -> Result { if netid.contains('/') { debug!("getting network by cidr {netid}"); - if let Ok(cidr) = IpCidr::from_str(&netid) { + if let Ok(cidr) = IpInet::from_str(&netid) { let storage = state.get_storage().await?; let network = storage.get_network_by_cidr(&cidr.to_string()).await?; if state.get_bootstrap() { diff --git a/icann-rdap-srv/src/rdap/srvhelp.rs b/icann-rdap-srv/src/rdap/srvhelp.rs index 3a1e996..7e828ac 100644 --- a/icann-rdap-srv/src/rdap/srvhelp.rs +++ b/icann-rdap-srv/src/rdap/srvhelp.rs @@ -1,4 +1,6 @@ -use axum::{extract::State, headers::Host, response::Response, TypedHeader}; +use axum::{extract::State, response::Response}; +use axum_extra::typed_header::TypedHeader; +use headers::Host; use icann_rdap_common::response::RdapResponse; use crate::{error::RdapServerError, rdap::response::ResponseUtil, server::DynServiceState}; diff --git a/icann-rdap-srv/src/server.rs b/icann-rdap-srv/src/server.rs index 288db1f..4d08ca7 100644 --- a/icann-rdap-srv/src/server.rs +++ b/icann-rdap-srv/src/server.rs @@ -1,13 +1,10 @@ -use std::{ - net::{SocketAddr, TcpListener}, - sync::Arc, - time::Duration, -}; +use std::{net::SocketAddr, sync::Arc, time::Duration}; use async_trait::async_trait; use axum::{error_handling::HandleErrorLayer, Router}; use http::{Method, StatusCode}; use icann_rdap_common::VERSION; +use tokio::net::TcpListener; use tower::{BoxError, ServiceBuilder}; use tower_http::{ cors::{Any, CorsLayer}, @@ -35,7 +32,7 @@ pub struct Listener { /// Starts the RDAP service. impl Listener { - pub fn listen(config: &ListenConfig) -> Result { + pub async fn listen(config: &ListenConfig) -> Result { tracing::info!("rdap-srv version {}", VERSION); #[cfg(debug_assertions)] @@ -49,7 +46,7 @@ impl Listener { tracing::debug!("tcp binding to {}", binding); - let listener = TcpListener::bind(binding)?; + let listener = TcpListener::bind(binding).await?; let local_addr = listener.local_addr()?; Ok(Self { local_addr, @@ -75,7 +72,7 @@ impl Listener { /// Starts the server using a [ServiceConfig]. This is the entry point for a CLI. /// This function will initiate any needed non-HTTP services and then call - /// call [start_with_app_state()], which initiates the HTTP service. + /// call [Listener::start_with_state], which initiates the HTTP service. pub async fn start_server(self, service_config: &ServiceConfig) -> Result<(), RdapServerError> { init_bootstrap(service_config).await?; if let StorageType::Memory(config) = &service_config.storage_type { @@ -98,9 +95,14 @@ impl Listener { let app = app_router::(app_state); tracing::debug!("listening on {}", self.local_addr); - axum::Server::from_tcp(self.tcp_listener)? - .serve(app.into_make_service_with_connect_info::()) - .await?; + // axum::Server::from_tcp(self.tcp_listener)? + // .serve(app.into_make_service_with_connect_info::()) + // .await?; + axum::serve( + self.tcp_listener, + app.into_make_service_with_connect_info::(), + ) + .await?; Ok(()) } } diff --git a/icann-rdap-srv/src/storage/pg/ops.rs b/icann-rdap-srv/src/storage/pg/ops.rs index 6723b1c..81e674b 100644 --- a/icann-rdap-srv/src/storage/pg/ops.rs +++ b/icann-rdap-srv/src/storage/pg/ops.rs @@ -1,3 +1,4 @@ +#![allow(clippy::diverging_sub_expression)] use async_trait::async_trait; use icann_rdap_common::response::RdapResponse; use sqlx::{query, PgPool}; @@ -27,7 +28,7 @@ impl StoreOps for Pg { async fn init(&self) -> Result<(), RdapServerError> { debug!("Testing database connection."); let mut conn = self.pg_pool.acquire().await?; - query("select 1").fetch_one(&mut conn).await?; + query("select 1").fetch_one(&mut *conn).await?; info!("Database connection test is successful."); Ok(()) } diff --git a/icann-rdap-srv/src/storage/pg/tx.rs b/icann-rdap-srv/src/storage/pg/tx.rs index b97f364..8faddcf 100644 --- a/icann-rdap-srv/src/storage/pg/tx.rs +++ b/icann-rdap-srv/src/storage/pg/tx.rs @@ -1,3 +1,4 @@ +#![allow(clippy::diverging_sub_expression)] use async_trait::async_trait; use icann_rdap_common::response::{ autnum::Autnum, domain::Domain, entity::Entity, nameserver::Nameserver, network::Network, @@ -26,7 +27,7 @@ impl<'a> PgTx<'a> { let mut db_tx = pg_pool.begin().await?; // TODO actually complete this // this is just here to make sure something will compile - sqlx::query("truncate domain").execute(&mut db_tx).await?; + sqlx::query("truncate domain").execute(&mut *db_tx).await?; Ok(PgTx { db_tx }) } } @@ -49,7 +50,7 @@ impl<'a> TxHandle for PgTx<'a> { // TODO actually complete this // this is just here to make sure something will compile sqlx::query("insert domain") - .execute(&mut self.db_tx) + .execute(&mut *self.db_tx) .await?; Ok(()) } diff --git a/icann-rdap-srv/tests/integration/srv/bootstrap.rs b/icann-rdap-srv/tests/integration/srv/bootstrap.rs index 5ad0fee..961ce6f 100644 --- a/icann-rdap-srv/tests/integration/srv/bootstrap.rs +++ b/icann-rdap-srv/tests/integration/srv/bootstrap.rs @@ -13,7 +13,7 @@ use crate::test_jig::SrvTestJig; async fn GIVEN_bootstrap_with_less_specific_domain_WHEN_query_domain_THEN_status_code_is_redirect() { // GIVEN - let test_srv = SrvTestJig::new_bootstrap(); + let test_srv = SrvTestJig::new_bootstrap().await; let mut tx = test_srv.mem.new_tx().await.expect("new transaction"); tx.add_domain_err( &DomainId::builder().ldh_name("example").build(), @@ -52,7 +52,7 @@ async fn GIVEN_bootstrap_with_less_specific_domain_WHEN_query_domain_THEN_status #[should_panic] async fn GIVEN_bootstrap_with_no_less_specific_domain_WHEN_query_domain_THEN_should_panic() { // GIVEN - let test_srv = SrvTestJig::new_bootstrap(); + let test_srv = SrvTestJig::new_bootstrap().await; let mut tx = test_srv.mem.new_tx().await.expect("new transaction"); tx.add_domain_err( &DomainId::builder().ldh_name("no_example").build(), @@ -80,7 +80,7 @@ async fn GIVEN_bootstrap_with_no_less_specific_domain_WHEN_query_domain_THEN_sho #[tokio::test] async fn GIVEN_bootstrap_with_less_specific_ns_WHEN_query_ns_THEN_status_code_is_redirect() { // GIVEN - let test_srv = SrvTestJig::new_bootstrap(); + let test_srv = SrvTestJig::new_bootstrap().await; let mut tx = test_srv.mem.new_tx().await.expect("new transaction"); tx.add_domain_err( &DomainId::builder().ldh_name("example").build(), @@ -119,7 +119,7 @@ async fn GIVEN_bootstrap_with_less_specific_ns_WHEN_query_ns_THEN_status_code_is #[should_panic] async fn GIVEN_bootstrap_with_no_less_specific_ns_WHEN_query_ns_THEN_should_panic() { // GIVEN - let test_srv = SrvTestJig::new_bootstrap(); + let test_srv = SrvTestJig::new_bootstrap().await; let mut tx = test_srv.mem.new_tx().await.expect("new transaction"); tx.add_domain_err( &DomainId::builder().ldh_name("no_example").build(), @@ -147,7 +147,7 @@ async fn GIVEN_bootstrap_with_no_less_specific_ns_WHEN_query_ns_THEN_should_pani #[tokio::test] async fn GIVEN_bootstrap_with_less_specific_ip_WHEN_query_ip_THEN_status_code_is_redirect() { // GIVEN - let test_srv = SrvTestJig::new_bootstrap(); + let test_srv = SrvTestJig::new_bootstrap().await; let mut tx = test_srv.mem.new_tx().await.expect("new transaction"); tx.add_network_err( &NetworkId::builder() @@ -190,7 +190,7 @@ async fn GIVEN_bootstrap_with_less_specific_ip_WHEN_query_ip_THEN_status_code_is #[should_panic] async fn GIVEN_bootstrap_with_no_less_specific_ip_WHEN_query_ip_THEN_should_panic() { // GIVEN - let test_srv = SrvTestJig::new_bootstrap(); + let test_srv = SrvTestJig::new_bootstrap().await; let mut tx = test_srv.mem.new_tx().await.expect("new transaction"); tx.add_network_err( &NetworkId::builder() @@ -223,7 +223,7 @@ async fn GIVEN_bootstrap_with_no_less_specific_ip_WHEN_query_ip_THEN_should_pani async fn GIVEN_bootstrap_with_less_specific_autnum_WHEN_query_autnum_THEN_status_code_is_redirect() { // GIVEN - let test_srv = SrvTestJig::new_bootstrap(); + let test_srv = SrvTestJig::new_bootstrap().await; let mut tx = test_srv.mem.new_tx().await.expect("new transaction"); tx.add_autnum_err( &AutnumId::builder() @@ -265,7 +265,7 @@ async fn GIVEN_bootstrap_with_less_specific_autnum_WHEN_query_autnum_THEN_status #[should_panic] async fn GIVEN_bootstrap_with_no_less_specific_autnum_WHEN_query_autnum_THEN_should_panic() { // GIVEN - let test_srv = SrvTestJig::new_bootstrap(); + let test_srv = SrvTestJig::new_bootstrap().await; let mut tx = test_srv.mem.new_tx().await.expect("new transaction"); tx.add_autnum_err( &AutnumId::builder() @@ -296,7 +296,7 @@ async fn GIVEN_bootstrap_with_no_less_specific_autnum_WHEN_query_autnum_THEN_sho #[tokio::test] async fn GIVEN_bootstrap_with_specific_tag_WHEN_query_entity_THEN_status_code_is_redirect() { // GIVEN - let test_srv = SrvTestJig::new_bootstrap(); + let test_srv = SrvTestJig::new_bootstrap().await; let mut tx = test_srv.mem.new_tx().await.expect("new transaction"); tx.add_entity_err( &EntityId::builder().handle("-ARIN").build(), @@ -335,7 +335,7 @@ async fn GIVEN_bootstrap_with_specific_tag_WHEN_query_entity_THEN_status_code_is async fn GIVEN_bootstrap_with_specific_tag_lowercase_WHEN_query_entity_THEN_status_code_is_redirect( ) { // GIVEN - let test_srv = SrvTestJig::new_bootstrap(); + let test_srv = SrvTestJig::new_bootstrap().await; let mut tx = test_srv.mem.new_tx().await.expect("new transaction"); tx.add_entity_err( &EntityId::builder().handle("-ARIN").build(), @@ -374,7 +374,7 @@ async fn GIVEN_bootstrap_with_specific_tag_lowercase_WHEN_query_entity_THEN_stat #[should_panic] async fn GIVEN_bootstrap_with_no_specific_tag_WHEN_query_entity_THEN_should_panic() { // GIVEN - let test_srv = SrvTestJig::new_bootstrap(); + let test_srv = SrvTestJig::new_bootstrap().await; let mut tx = test_srv.mem.new_tx().await.expect("new transaction"); tx.add_entity_err( &EntityId::builder().handle("-CLAUCA").build(), diff --git a/icann-rdap-srv/tests/integration/srv/domain.rs b/icann-rdap-srv/tests/integration/srv/domain.rs index ca204fc..8b1c01e 100644 --- a/icann-rdap-srv/tests/integration/srv/domain.rs +++ b/icann-rdap-srv/tests/integration/srv/domain.rs @@ -12,7 +12,7 @@ use crate::test_jig::SrvTestJig; #[tokio::test] async fn GIVEN_server_with_domain_WHEN_query_domain_THEN_status_code_200() { // GIVEN - let test_srv = SrvTestJig::new(); + let test_srv = SrvTestJig::new().await; let mut tx = test_srv.mem.new_tx().await.expect("new transaction"); tx.add_domain(&Domain::basic().ldh_name("foo.example").build()) .await diff --git a/icann-rdap-srv/tests/integration/srv/redirect.rs b/icann-rdap-srv/tests/integration/srv/redirect.rs index c337daf..d885f16 100644 --- a/icann-rdap-srv/tests/integration/srv/redirect.rs +++ b/icann-rdap-srv/tests/integration/srv/redirect.rs @@ -18,7 +18,7 @@ use crate::test_jig::SrvTestJig; #[tokio::test] async fn GIVEN_domain_error_with_first_link_href_WHEN_query_THEN_status_code_is_redirect() { // GIVEN - let test_srv = SrvTestJig::new(); + let test_srv = SrvTestJig::new().await; let mut tx = test_srv.mem.new_tx().await.expect("new transaction"); tx.add_domain_err( &DomainId { @@ -66,7 +66,7 @@ async fn GIVEN_domain_error_with_first_link_href_WHEN_query_THEN_status_code_is_ #[tokio::test] async fn GIVEN_nameserver_error_with_first_link_href_WHEN_query_THEN_status_code_is_redirect() { // GIVEN - let test_srv = SrvTestJig::new(); + let test_srv = SrvTestJig::new().await; let mut tx = test_srv.mem.new_tx().await.expect("new transaction"); tx.add_nameserver_err( &NameserverId { @@ -114,7 +114,7 @@ async fn GIVEN_nameserver_error_with_first_link_href_WHEN_query_THEN_status_code #[tokio::test] async fn GIVEN_entity_error_with_first_link_href_WHEN_query_THEN_status_code_is_redirect() { // GIVEN - let test_srv = SrvTestJig::new(); + let test_srv = SrvTestJig::new().await; let mut tx = test_srv.mem.new_tx().await.expect("new transaction"); tx.add_entity_err( &EntityId { @@ -161,7 +161,7 @@ async fn GIVEN_entity_error_with_first_link_href_WHEN_query_THEN_status_code_is_ #[tokio::test] async fn GIVEN_autnum_error_with_first_link_href_WHEN_query_THEN_status_code_is_redirect() { // GIVEN - let test_srv = SrvTestJig::new(); + let test_srv = SrvTestJig::new().await; let mut tx = test_srv.mem.new_tx().await.expect("new transaction"); tx.add_autnum_err( &AutnumId { @@ -209,7 +209,7 @@ async fn GIVEN_autnum_error_with_first_link_href_WHEN_query_THEN_status_code_is_ #[tokio::test] async fn GIVEN_network_cidr_error_with_first_link_href_WHEN_query_THEN_status_code_is_redirect() { // GIVEN - let test_srv = SrvTestJig::new(); + let test_srv = SrvTestJig::new().await; let mut tx = test_srv.mem.new_tx().await.expect("new transaction"); tx.add_network_err( &NetworkId { @@ -256,7 +256,7 @@ async fn GIVEN_network_cidr_error_with_first_link_href_WHEN_query_THEN_status_co #[tokio::test] async fn GIVEN_network_addrs_error_with_first_link_href_WHEN_query_THEN_status_code_is_redirect() { // GIVEN - let test_srv = SrvTestJig::new(); + let test_srv = SrvTestJig::new().await; let mut tx = test_srv.mem.new_tx().await.expect("new transaction"); tx.add_network_err( &NetworkId { diff --git a/icann-rdap-srv/tests/integration/srv/srvhelp.rs b/icann-rdap-srv/tests/integration/srv/srvhelp.rs index 9824de5..154f358 100644 --- a/icann-rdap-srv/tests/integration/srv/srvhelp.rs +++ b/icann-rdap-srv/tests/integration/srv/srvhelp.rs @@ -1,6 +1,5 @@ #![allow(non_snake_case)] -use http::HeaderValue; use icann_rdap_client::query::{qtype::QueryType, request::rdap_request}; use icann_rdap_common::{ client::{create_client, ClientConfig}, @@ -16,7 +15,7 @@ use crate::test_jig::SrvTestJig; #[tokio::test] async fn GIVEN_server_with_default_help_WHEN_query_help_THEN_status_code_200() { // GIVEN - let test_srv = SrvTestJig::new(); + let test_srv = SrvTestJig::new().await; let mut tx = test_srv.mem.new_tx().await.expect("new transaction"); let srvhelp = Help::basic() .notice(Notice( @@ -49,7 +48,7 @@ async fn GIVEN_server_with_default_help_WHEN_query_help_THEN_status_code_200() { #[tokio::test] async fn GIVEN_server_with_host_help_WHEN_query_help_THEN_status_code_200() { // GIVEN - let test_srv = SrvTestJig::new(); + let test_srv = SrvTestJig::new().await; let mut tx = test_srv.mem.new_tx().await.expect("new transaction"); let srvhelp = Help::basic() .notice(Notice( @@ -68,7 +67,7 @@ async fn GIVEN_server_with_host_help_WHEN_query_help_THEN_status_code_200() { let client_config = ClientConfig::builder() .https_only(false) .follow_redirects(false) - .host(HeaderValue::from_str("foo.example.com").expect("host header value")) + .host(reqwest::header::HeaderValue::from_static("foo.example.com")) .build(); let client = create_client(&client_config).expect("creating client"); let query = QueryType::Help; diff --git a/icann-rdap-srv/tests/integration/test_jig.rs b/icann-rdap-srv/tests/integration/test_jig.rs index 61c9958..2584d4c 100644 --- a/icann-rdap-srv/tests/integration/test_jig.rs +++ b/icann-rdap-srv/tests/integration/test_jig.rs @@ -75,14 +75,16 @@ pub struct SrvTestJig { } impl SrvTestJig { - pub fn new() -> SrvTestJig { + pub async fn new() -> SrvTestJig { let mem = Mem::default(); let app_state = AppState { storage: mem.clone(), bootstrap: false, }; let _ = tracing_subscriber::fmt().with_test_writer().try_init(); - let listener = Listener::listen(&ListenConfig::default()).expect("listening on interface"); + let listener = Listener::listen(&ListenConfig::default()) + .await + .expect("listening on interface"); let rdap_base = listener.rdap_base(); tokio::spawn(async move { listener @@ -93,14 +95,16 @@ impl SrvTestJig { SrvTestJig { mem, rdap_base } } - pub fn new_bootstrap() -> SrvTestJig { + pub async fn new_bootstrap() -> SrvTestJig { let mem = Mem::default(); let app_state = AppState { storage: mem.clone(), bootstrap: true, }; let _ = tracing_subscriber::fmt().with_test_writer().try_init(); - let listener = Listener::listen(&ListenConfig::default()).expect("listening on interface"); + let listener = Listener::listen(&ListenConfig::default()) + .await + .expect("listening on interface"); let rdap_base = listener.rdap_base(); tokio::spawn(async move { listener diff --git a/release.md b/release.md new file mode 100644 index 0000000..fb7f0d7 --- /dev/null +++ b/release.md @@ -0,0 +1,23 @@ +Release Process +=============== + +This is the release process which must be carried out by a maintainer +with proper GitHub and crates.io credentials. Without both, this will +fail. + +1. Install the Cargo release plugin (if it is not already installed): `cargo install cargo-release` +1. On the 'dev' branch, use the cargo release plugin to bump either the patch, minor, or major version: `cargo release version patch -x`, `cargo release version minor -x` or `cargo release version major -x`. +1. Run the tests: `cargo test` +1. Commit these changes to git. +1. Push the changes to GitHub. +1. Do a PR from `dev` to `main`. +1. Wait for the test build. +1. Merge the PR. +1. Tag with version from step 2 as 'vVERSION' (lowercase 'v' followed by version number such as 'v0.0.5'). +1. Push the tag to GitHub. This triggers a release build in GitHub Actions. +1. Wait until the release works. It may need some babysitting because the GitHub macOS and Windows builds are sometimes flaky). +1. Switch to main branch: `git switch main` +1. Update local repo branch: `git pull`. +1. Create a build in preparation for of publication to crates.io: `cargo build --release`. +1. Publish to crates.io: `cargo release publish -x` (on occasion this needs babysitting too). +