diff --git a/Cargo.lock b/Cargo.lock index fd05bbe..2113113 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -108,9 +108,9 @@ checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" [[package]] name = "anyhow" -version = "1.0.100" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" +checksum = "5f0e0fee31ef5ed1ba1316088939cea399010ed7731dba877ed44aeb407a75ea" [[package]] name = "arrayref" @@ -147,7 +147,7 @@ dependencies = [ "rand 0.9.2", "safelog", "serde", - "thiserror 2.0.17", + "thiserror 2.0.18", "time", "tor-async-utils", "tor-basic-utils", @@ -191,7 +191,8 @@ dependencies = [ "nom", "num-traits", "rusticata-macros", - "thiserror 2.0.17", + "thiserror 2.0.18", + "time", ] [[package]] @@ -202,7 +203,7 @@ checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.116", "synstructure", ] @@ -214,7 +215,7 @@ checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.116", ] [[package]] @@ -225,9 +226,9 @@ checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" [[package]] name = "async-compression" -version = "0.4.37" +version = "0.4.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d10e4f991a553474232bc0a31799f6d24b034a84c0971d80d2e2f78b2e576e40" +checksum = "68650b7df54f0293fd061972a0fb05aaf4fc0879d3b3d21a638a182c5c543b9f" dependencies = [ "compression-codecs", "compression-core", @@ -243,7 +244,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.116", ] [[package]] @@ -303,9 +304,9 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "aws-lc-rs" -version = "1.15.3" +version = "1.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e84ce723ab67259cfeb9877c6a639ee9eb7a27b28123abd71db7f0d5d0cc9d86" +checksum = "7b7b6141e96a8c160799cc2d5adecd5cbbe5054cb8c7c4af53da0f83bb7ad256" dependencies = [ "aws-lc-sys", "zeroize", @@ -313,9 +314,9 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.36.0" +version = "0.37.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a442ece363113bd4bd4c8b18977a7798dd4d3c3383f34fb61936960e8f4ad8" +checksum = "b092fe214090261288111db7a2b2c2118e5a7f30dc2569f1732c4069a6840549" dependencies = [ "cc", "cmake", @@ -440,9 +441,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.10.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" [[package]] name = "bitvec" @@ -486,7 +487,7 @@ checksum = "e0b121a9fe0df916e362fb3271088d071159cdf11db0e4182d02152850756eff" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.116", ] [[package]] @@ -526,7 +527,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09dc0086e469182132244e9b8d313a0742e1132da43a08c24b9dd3c18e0faf3a" dependencies = [ - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -564,9 +565,9 @@ checksum = "64fa3c856b712db6612c019f14756e64e4bcea13337a6b33b696333a9eaa2d06" [[package]] name = "bytemuck" -version = "1.24.0" +version = "1.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4" +checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" [[package]] name = "byteorder" @@ -576,9 +577,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" [[package]] name = "caret" @@ -603,9 +604,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.53" +version = "1.2.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "755d2fce177175ffca841e9a06afdb2c4ab0f593d53b4dee48147dfaade85932" +checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" dependencies = [ "find-msvc-tools", "jobserver", @@ -695,18 +696,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.54" +version = "4.5.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6e6ff9dcd79cff5cd969a17a545d79e84ab086e444102a591e288a8aa3ce394" +checksum = "63be97961acde393029492ce0be7a1af7e323e6bae9511ebfac33751be5e6806" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.5.54" +version = "4.5.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa42cf4d2b7a41bc8f663a7cab4031ebafa1bf3875705bfaf8466dc60ab52c00" +checksum = "7f13174bda5dfd69d7e947827e5af4b0f2f94a4a3ee92912fba07a66150f21e2" dependencies = [ "anstyle", "clap_lex", @@ -714,9 +715,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3e64b0cc0439b12df2fa678eae89a1c56a529fd067a9115f7827f1fffd22b32" +checksum = "3a822ea5bc7590f9d40f1ba12c0dc3c2760f3482c6984db1573ad11031420831" [[package]] name = "cmake" @@ -995,7 +996,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.116", ] [[package]] @@ -1043,7 +1044,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.114", + "syn 2.0.116", ] [[package]] @@ -1065,7 +1066,7 @@ checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" dependencies = [ "darling_core 0.21.3", "quote", - "syn 2.0.114", + "syn 2.0.116", ] [[package]] @@ -1095,6 +1096,7 @@ dependencies = [ "cookie-factory", "displaydoc", "nom", + "num-bigint", "num-traits", "rusticata-macros", ] @@ -1133,7 +1135,7 @@ dependencies = [ "quote", "sha3", "strum", - "syn 2.0.114", + "syn 2.0.116", "void", ] @@ -1187,7 +1189,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.114", + "syn 2.0.116", "unicode-xid", ] @@ -1252,7 +1254,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.116", ] [[package]] @@ -1299,7 +1301,7 @@ checksum = "0b0713d5c1d52e774c5cd7bb8b043d7c0fc4f921abfb678556140bfbe6ab2364" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.116", ] [[package]] @@ -1389,7 +1391,7 @@ dependencies = [ "num-traits", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.116", ] [[package]] @@ -1401,7 +1403,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.116", ] [[package]] @@ -1506,21 +1508,20 @@ dependencies = [ [[package]] name = "filetime" -version = "0.2.26" +version = "0.2.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc0505cd1b6fa6580283f6bdf70a73fcf4aba1184038c90902b92b3dd0df63ed" +checksum = "f98844151eee8917efc50bd9e8318cb963ae8b297431495d3f758616ea5c57db" dependencies = [ "cfg-if", "libc", "libredox", - "windows-sys 0.60.2", ] [[package]] name = "find-msvc-tools" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8591b0bcc8a98a64310a2fae1bb3e9b8564dd10e381e6e28010fde8e8e8568db" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" [[package]] name = "fixedbitset" @@ -1530,9 +1531,9 @@ checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" [[package]] name = "flate2" -version = "1.1.8" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b375d6465b98090a5f25b1c7703f3859783755aa9a80433b36e0379a3ec2f369" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" dependencies = [ "crc32fast", "miniz_oxide", @@ -1581,7 +1582,7 @@ dependencies = [ "libc", "pwd-grp", "serde", - "thiserror 2.0.17", + "thiserror 2.0.18", "walkdir", ] @@ -1609,9 +1610,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" dependencies = [ "futures-channel", "futures-core", @@ -1624,9 +1625,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" dependencies = [ "futures-core", "futures-sink", @@ -1634,15 +1635,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" [[package]] name = "futures-executor" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" dependencies = [ "futures-core", "futures-task", @@ -1651,19 +1652,19 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" [[package]] name = "futures-macro" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.116", ] [[package]] @@ -1679,21 +1680,21 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" [[package]] name = "futures-task" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" [[package]] name = "futures-util" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" dependencies = [ "futures-channel", "futures-core", @@ -1703,7 +1704,6 @@ dependencies = [ "futures-task", "memchr", "pin-project-lite", - "pin-utils", "slab", ] @@ -1745,6 +1745,19 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "getrandom" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139ef39800118c7683f2fd3c98c1b23c09ae076556b435f8e9064ae108aaeeec" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", + "wasip3", +] + [[package]] name = "getset" version = "0.1.6" @@ -1754,7 +1767,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.116", ] [[package]] @@ -2061,13 +2074,12 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.19" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "727805d60e7938b76b826a6ef209eb70eaa1812794f9424d4a4e2d740662df5f" +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" dependencies = [ "bytes", "futures-channel", - "futures-core", "futures-util", "http", "http-body", @@ -2082,9 +2094,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.64" +version = "0.1.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -2104,6 +2116,12 @@ dependencies = [ "cc", ] +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + [[package]] name = "ident_case" version = "1.0.1" @@ -2148,7 +2166,7 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f37dccff2791ab604f9babef0ba14fbe0be30bd368dc541e2b08d07c8aa908f3" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "inotify-sys", "libc", ] @@ -2240,9 +2258,9 @@ dependencies = [ [[package]] name = "keccak" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +checksum = "cb26cec98cce3a3d96cbb7bced3c4b16e3d13f27ec56dbd62cbc8f39cfb9d653" dependencies = [ "cpufeatures", ] @@ -2276,11 +2294,17 @@ dependencies = [ "spin", ] +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + [[package]] name = "libc" -version = "0.2.180" +version = "0.2.182" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" +checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" [[package]] name = "liblzma" @@ -2293,9 +2317,9 @@ dependencies = [ [[package]] name = "liblzma-sys" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01b9596486f6d60c3bbe644c0e1be1aa6ccc472ad630fe8927b456973d7cb736" +checksum = "9f2db66f3268487b5033077f266da6777d057949b8f93c8ad82e441df25e6186" dependencies = [ "cc", "libc", @@ -2304,9 +2328,9 @@ dependencies = [ [[package]] name = "libm" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" [[package]] name = "libredox" @@ -2314,9 +2338,9 @@ version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "libc", - "redox_syscall 0.7.0", + "redox_syscall 0.7.1", ] [[package]] @@ -2382,15 +2406,15 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.6" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" [[package]] name = "memmap2" -version = "0.9.9" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "744133e4a0e0a658e1374cf3bf8e415c4052a15a111acd372764c55b4177d490" +checksum = "714098028fe011992e1c3962653c96b2d578c4b4bce9036e15ff220319b1e0e3" dependencies = [ "libc", ] @@ -2481,7 +2505,7 @@ version = "8.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d3d07927151ff8575b7087f245456e549fea62edf0ec4e565a5ee50c8402bc3" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "inotify", "kqueue", "libc", @@ -2494,15 +2518,18 @@ dependencies = [ [[package]] name = "notify-types" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e0826a989adedc2a244799e823aece04662b66609d96af8dff7ac6df9a8925d" +checksum = "42b8cfee0e339a0337359f3c88165702ac6e600dc01c0cc9579a92d62b08477a" +dependencies = [ + "bitflags 2.11.0", +] [[package]] name = "ntapi" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c70f219e21142367c70c0b30c6a9e3a14d55b4d12a204d897fbec83a0363f081" +checksum = "c3b335231dfd352ffb0f8017f3b6027a4917f7df785ea2143d8af2adc66980ae" dependencies = [ "winapi", ] @@ -2597,7 +2624,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.116", ] [[package]] @@ -2606,7 +2633,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", ] [[package]] @@ -2619,6 +2646,15 @@ dependencies = [ "objc2-core-foundation", ] +[[package]] +name = "oid-registry" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f40cff3dde1b6087cc5d5f5d4d65712f34016a03ed60e9c08dcc392736b5b7" +dependencies = [ + "asn1-rs", +] + [[package]] name = "once_cell" version = "1.21.3" @@ -2648,9 +2684,9 @@ checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "openssl-probe" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f50d9b3dabb09ecd771ad0aa242ca6894994c130308ca3d7684634df8037391" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" [[package]] name = "option-ext" @@ -2865,7 +2901,7 @@ dependencies = [ "phf_shared", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.116", ] [[package]] @@ -2894,7 +2930,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.116", ] [[package]] @@ -3012,7 +3048,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", - "syn 2.0.114", + "syn 2.0.116", ] [[package]] @@ -3063,14 +3099,14 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.116", ] [[package]] name = "proc-macro2" -version = "1.0.105" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "535d180e0ecab6268a3e718bb9fd44db66bbbc256257165fc699dadf70d16fe7" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] @@ -3100,7 +3136,7 @@ dependencies = [ "prost", "prost-types", "regex", - "syn 2.0.114", + "syn 2.0.116", "tempfile", ] @@ -3114,7 +3150,7 @@ dependencies = [ "itertools 0.14.0", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.116", ] [[package]] @@ -3135,14 +3171,14 @@ dependencies = [ "derive-deftly", "libc", "paste", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] name = "quote" -version = "1.0.43" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" dependencies = [ "proc-macro2", ] @@ -3294,16 +3330,16 @@ version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", ] [[package]] name = "redox_syscall" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f3fe0889e69e2ae9e41f4d6c4c0181701d00e4697b356fb1f74173a5e0ee27" +checksum = "35985aa610addc02e24fc232012c86fd11f14111180f902b67e2d5331f8ebf2b" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", ] [[package]] @@ -3314,7 +3350,7 @@ checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" dependencies = [ "getrandom 0.2.17", "libredox", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -3334,14 +3370,14 @@ checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.116", ] [[package]] name = "regex" -version = "1.12.2" +version = "1.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" dependencies = [ "aho-corasick", "memchr", @@ -3351,9 +3387,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" dependencies = [ "aho-corasick", "memchr", @@ -3362,9 +3398,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" +checksum = "a96887878f22d7bad8a3b6dc5b7440e0ada9a245242924394987b21cf2210a4c" [[package]] name = "retry-error" @@ -3441,7 +3477,7 @@ version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "165ca6e57b20e1351573e3729b958bc62f0e48025386970b6e4d29e7a7e71f3f" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "fallible-iterator", "fallible-streaming-iterator", "hashlink", @@ -3485,7 +3521,7 @@ version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "errno", "libc", "linux-raw-sys", @@ -3566,7 +3602,7 @@ dependencies = [ "educe", "either", "fluid-let", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -3643,9 +3679,9 @@ dependencies = [ [[package]] name = "schemars" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54e910108742c57a770f492731f99be216a52fadd361b06c8fb59d74ccc267d2" +checksum = "a2b42f36aa1cd011945615b92222f6bf73c599a102a300334cd7f8dbeec726cc" dependencies = [ "dyn-clone", "ref-cast", @@ -3702,11 +3738,11 @@ dependencies = [ [[package]] name = "security-framework" -version = "3.5.1" +version = "3.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef" +checksum = "d17b898a6d6948c3a8ee4372c17cb384f90d2e6e912ef00895b14fd7ab54ec38" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "core-foundation", "core-foundation-sys", "libc", @@ -3715,9 +3751,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.15.0" +version = "2.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" +checksum = "321c8673b092a9a42605034a9879d73cb79101ed5fd117bc9a597b89b4e9e61a" dependencies = [ "core-foundation-sys", "libc", @@ -3766,7 +3802,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.116", ] [[package]] @@ -3822,7 +3858,7 @@ dependencies = [ "indexmap 1.9.3", "indexmap 2.13.0", "schemars 0.9.0", - "schemars 1.2.0", + "schemars 1.2.1", "serde_core", "serde_json", "serde_with_macros", @@ -3838,7 +3874,7 @@ dependencies = [ "darling 0.21.3", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.116", ] [[package]] @@ -3899,7 +3935,7 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "637e95dcd06bc1bb3f86ed9db1e1832a70125f32daae071ef37dcb7701b7d4fe" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "either", "incrementalmerkletree", "tracing", @@ -3961,15 +3997,15 @@ dependencies = [ [[package]] name = "siphasher" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" +checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e" [[package]] name = "slab" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "slotmap" @@ -3990,7 +4026,7 @@ dependencies = [ "paste", "serde", "slotmap", - "thiserror 2.0.17", + "thiserror 2.0.18", "void", ] @@ -4002,9 +4038,9 @@ checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "socket2" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" +checksum = "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0" dependencies = [ "libc", "windows-sys 0.60.2", @@ -4104,7 +4140,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.116", ] [[package]] @@ -4126,9 +4162,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.114" +version = "2.0.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" +checksum = "3df424c70518695237746f84cede799c9c58fcb37450d7b23716568cc8bc69cb" dependencies = [ "proc-macro2", "quote", @@ -4149,7 +4185,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.116", ] [[package]] @@ -4174,12 +4210,12 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" -version = "3.24.0" +version = "3.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "655da9c7eb6305c55742045d5a8d2037996d61d8de95806335c7c86ce0f82e9c" +checksum = "0136791f7c95b1f6dd99f9cc786b91bb81c3800b639b3478e561ddb7be95e5f1" dependencies = [ "fastrand", - "getrandom 0.3.4", + "getrandom 0.4.1", "once_cell", "rustix", "windows-sys 0.61.2", @@ -4196,11 +4232,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.17" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" dependencies = [ - "thiserror-impl 2.0.17", + "thiserror-impl 2.0.18", ] [[package]] @@ -4211,18 +4247,18 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.116", ] [[package]] name = "thiserror-impl" -version = "2.0.17" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.116", ] [[package]] @@ -4325,7 +4361,7 @@ checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.116", ] [[package]] @@ -4377,9 +4413,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.9.11+spec-1.1.0" +version = "0.9.12+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3afc9a848309fe1aaffaed6e1546a7a14de1f935dc9d89d32afd9a44bab7c46" +checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863" dependencies = [ "indexmap 2.13.0", "serde_core", @@ -4436,9 +4472,9 @@ dependencies = [ [[package]] name = "toml_parser" -version = "1.0.6+spec-1.1.0" +version = "1.0.8+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3198b4b0a8e11f09dd03e133c0280504d0801269e9afa46362ffde1cbeebf44" +checksum = "0742ff5ff03ea7e67c8ae6c93cac239e0d9784833362da3f9a9c1da8dfefcbdc" dependencies = [ "winnow", ] @@ -4457,9 +4493,9 @@ checksum = "ab16f14aed21ee8bfd8ec22513f7287cd4a91aa92e44edfe2c17ddd004e92607" [[package]] name = "tonic" -version = "0.14.2" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb7613188ce9f7df5bfe185db26c5814347d110db17920415cf2fbcad85e7203" +checksum = "7f32a6f80051a4111560201420c7885d0082ba9efe2ab61875c587bb6b18b9a0" dependencies = [ "async-trait", "axum", @@ -4483,26 +4519,26 @@ dependencies = [ "tower-layer", "tower-service", "tracing", - "webpki-roots 1.0.5", + "webpki-roots 1.0.6", ] [[package]] name = "tonic-build" -version = "0.14.2" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c40aaccc9f9eccf2cd82ebc111adc13030d23e887244bc9cfa5d1d636049de3" +checksum = "ce6d8958ed3be404120ca43ffa0fb1e1fc7be214e96c8d33bd43a131b6eebc9e" dependencies = [ "prettyplease", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.116", ] [[package]] name = "tonic-prost" -version = "0.14.2" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66bd50ad6ce1252d87ef024b3d64fe4c3cf54a86fb9ef4c631fdd0ded7aeaa67" +checksum = "9f86539c0089bfd09b1f8c0ab0239d80392af74c21bc9e0f15e1b4aca4c1647f" dependencies = [ "bytes", "prost", @@ -4511,16 +4547,16 @@ dependencies = [ [[package]] name = "tonic-prost-build" -version = "0.14.2" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4a16cba4043dc3ff43fcb3f96b4c5c154c64cbd18ca8dce2ab2c6a451d058a2" +checksum = "65873ace111e90344b8973e94a1fc817c924473affff24629281f90daed1cd2e" dependencies = [ "prettyplease", "proc-macro2", "prost-build", "prost-types", "quote", - "syn 2.0.114", + "syn 2.0.116", "tempfile", "tonic-build", ] @@ -4537,7 +4573,7 @@ dependencies = [ "oneshot-fused-workaround", "pin-project", "postage", - "thiserror 2.0.17", + "thiserror 2.0.18", "void", ] @@ -4557,7 +4593,7 @@ dependencies = [ "serde", "slab", "smallvec", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -4572,7 +4608,7 @@ dependencies = [ "educe", "getrandom 0.3.4", "safelog", - "thiserror 2.0.17", + "thiserror 2.0.18", "tor-error", "tor-llcrypto", "zeroize", @@ -4585,7 +4621,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79ba1b43f22fab2daee3e0c902f1455b3aed8e086b2d83d8c60b36523b173d25" dependencies = [ "amplify", - "bitflags 2.10.0", + "bitflags 2.11.0", "bytes", "caret", "derive-deftly", @@ -4595,7 +4631,7 @@ dependencies = [ "paste", "rand 0.9.2", "smallvec", - "thiserror 2.0.17", + "thiserror 2.0.18", "tor-basic-utils", "tor-bytes", "tor-cert", @@ -4618,7 +4654,7 @@ dependencies = [ "derive_builder_fork_arti", "derive_more", "digest 0.10.7", - "thiserror 2.0.17", + "thiserror 2.0.18", "tor-bytes", "tor-checkable", "tor-llcrypto", @@ -4641,7 +4677,7 @@ dependencies = [ "rand 0.9.2", "safelog", "serde", - "thiserror 2.0.17", + "thiserror 2.0.18", "tor-async-utils", "tor-basic-utils", "tor-cell", @@ -4668,7 +4704,7 @@ checksum = "7c9839e9bb302f17447c350e290bb107084aca86c640882a91522f2059f6a686" dependencies = [ "humantime", "signature", - "thiserror 2.0.17", + "thiserror 2.0.18", "tor-llcrypto", ] @@ -4697,7 +4733,7 @@ dependencies = [ "retry-error", "safelog", "serde", - "thiserror 2.0.17", + "thiserror 2.0.18", "tor-async-utils", "tor-basic-utils", "tor-cell", @@ -4745,8 +4781,8 @@ dependencies = [ "serde-value", "serde_ignored", "strum", - "thiserror 2.0.17", - "toml 0.9.11+spec-1.1.0", + "thiserror 2.0.18", + "toml 0.9.12+spec-1.1.0", "tor-basic-utils", "tor-error", "tor-rtcompat", @@ -4763,7 +4799,7 @@ dependencies = [ "directories", "serde", "shellexpand", - "thiserror 2.0.17", + "thiserror 2.0.18", "tor-error", "tor-general-addr", ] @@ -4776,7 +4812,7 @@ checksum = "c1690438c1fc778fc7c89c132e529365b1430d6afe03aeecbc2508324807bf0b" dependencies = [ "digest 0.10.7", "hex", - "thiserror 2.0.17", + "thiserror 2.0.18", "tor-llcrypto", ] @@ -4796,7 +4832,7 @@ dependencies = [ "httpdate", "itertools 0.14.0", "memchr", - "thiserror 2.0.17", + "thiserror 2.0.18", "tor-circmgr", "tor-error", "tor-linkspec", @@ -4861,7 +4897,7 @@ dependencies = [ "signature", "static_assertions", "strum", - "thiserror 2.0.17", + "thiserror 2.0.18", "time", "tor-async-utils", "tor-basic-utils", @@ -4895,7 +4931,7 @@ dependencies = [ "retry-error", "static_assertions", "strum", - "thiserror 2.0.17", + "thiserror 2.0.18", "tracing", "void", ] @@ -4907,7 +4943,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c42cb5b5aec0584db2fba4a88c4e08fb09535ef61e4ef5674315a89e69ec31a2" dependencies = [ "derive_more", - "thiserror 2.0.17", + "thiserror 2.0.18", "void", ] @@ -4936,7 +4972,7 @@ dependencies = [ "safelog", "serde", "strum", - "thiserror 2.0.17", + "thiserror 2.0.18", "tor-async-utils", "tor-basic-utils", "tor-config", @@ -4973,7 +5009,7 @@ dependencies = [ "serde", "signature", "subtle", - "thiserror 2.0.17", + "thiserror 2.0.18", "tor-basic-utils", "tor-bytes", "tor-error", @@ -4997,7 +5033,7 @@ dependencies = [ "rsa", "signature", "ssh-key", - "thiserror 2.0.17", + "thiserror 2.0.18", "tor-bytes", "tor-cert", "tor-checkable", @@ -5029,7 +5065,7 @@ dependencies = [ "serde", "signature", "ssh-key", - "thiserror 2.0.17", + "thiserror 2.0.18", "tor-basic-utils", "tor-bytes", "tor-config", @@ -5063,7 +5099,7 @@ dependencies = [ "serde", "serde_with", "strum", - "thiserror 2.0.17", + "thiserror 2.0.18", "tor-basic-utils", "tor-bytes", "tor-config", @@ -5104,7 +5140,7 @@ dependencies = [ "sha3", "signature", "subtle", - "thiserror 2.0.17", + "thiserror 2.0.18", "tor-error", "tor-memquota", "visibility", @@ -5120,7 +5156,7 @@ checksum = "845d65304be6a614198027c4b2d1b35aaf073335c26df619d17e5f4027f2657f" dependencies = [ "futures", "humantime", - "thiserror 2.0.17", + "thiserror 2.0.18", "tor-error", "tor-rtcompat", "tracing", @@ -5146,7 +5182,7 @@ dependencies = [ "slotmap-careful", "static_assertions", "sysinfo", - "thiserror 2.0.17", + "thiserror 2.0.18", "tor-async-utils", "tor-basic-utils", "tor-config", @@ -5164,7 +5200,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "638b4e6507e3786488859d3c463fa73addbad4f788806c6972603727e527672e" dependencies = [ "async-trait", - "bitflags 2.10.0", + "bitflags 2.11.0", "derive_more", "futures", "humantime", @@ -5173,7 +5209,7 @@ dependencies = [ "rand 0.9.2", "serde", "strum", - "thiserror 2.0.17", + "thiserror 2.0.18", "tor-basic-utils", "tor-error", "tor-linkspec", @@ -5193,7 +5229,7 @@ checksum = "1dbc32d89e7ea2e2799168d0c453061647a727e39fc66f52e1bcb4c38c8dc433" dependencies = [ "amplify", "base64ct", - "bitflags 2.10.0", + "bitflags 2.11.0", "cipher", "derive-deftly", "derive_builder_fork_arti", @@ -5212,7 +5248,7 @@ dependencies = [ "smallvec", "strum", "subtle", - "thiserror 2.0.17", + "thiserror 2.0.18", "time", "tinystr", "tor-basic-utils", @@ -5246,7 +5282,7 @@ dependencies = [ "sanitize-filename", "serde", "serde_json", - "thiserror 2.0.17", + "thiserror 2.0.18", "time", "tor-async-utils", "tor-basic-utils", @@ -5293,7 +5329,7 @@ dependencies = [ "static_assertions", "subtle", "sync_wrapper", - "thiserror 2.0.17", + "thiserror 2.0.18", "tokio", "tokio-util", "tor-async-utils", @@ -5328,7 +5364,7 @@ dependencies = [ "caret", "paste", "serde_with", - "thiserror 2.0.17", + "thiserror 2.0.18", "tor-bytes", ] @@ -5367,7 +5403,7 @@ dependencies = [ "pin-project", "rustls-pki-types", "rustls-webpki", - "thiserror 2.0.17", + "thiserror 2.0.18", "tokio", "tokio-util", "tor-error", @@ -5396,7 +5432,7 @@ dependencies = [ "priority-queue", "slotmap-careful", "strum", - "thiserror 2.0.17", + "thiserror 2.0.18", "tor-error", "tor-general-addr", "tor-rtcompat", @@ -5417,7 +5453,7 @@ dependencies = [ "educe", "safelog", "subtle", - "thiserror 2.0.17", + "thiserror 2.0.18", "tor-bytes", "tor-error", ] @@ -5431,7 +5467,7 @@ dependencies = [ "derive-deftly", "derive_more", "serde", - "thiserror 2.0.17", + "thiserror 2.0.18", "tor-memquota", ] @@ -5485,7 +5521,7 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.116", ] [[package]] @@ -5529,9 +5565,9 @@ dependencies = [ [[package]] name = "tracing-test" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "557b891436fe0d5e0e363427fc7f217abf9ccd510d5136549847bdcbcd011d68" +checksum = "19a4c448db514d4f24c5ddb9f73f2ee71bfb24c526cf0c570ba142d1119e0051" dependencies = [ "tracing-core", "tracing-subscriber", @@ -5540,12 +5576,12 @@ dependencies = [ [[package]] name = "tracing-test-macro" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04659ddb06c87d233c566112c1c9c5b9e98256d9af50ec3bc9c8327f873a7568" +checksum = "ad06847b7afb65c7866a36664b75c40b895e318cea4f71299f013fb22965329d" dependencies = [ "quote", - "syn 2.0.114", + "syn 2.0.116", ] [[package]] @@ -5556,7 +5592,7 @@ checksum = "70977707304198400eb4835a78f6a9f928bf41bba420deb8fdb175cd965d77a7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.116", ] [[package]] @@ -5567,9 +5603,9 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "typed-index-collections" -version = "3.4.0" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5318ee4ce62a4e948a33915574021a7a953d83e84fba6e25c72ffcfd7dad35ff" +checksum = "898160f1dfd383b4e92e17f0512a7d62f3c51c44937b23b6ffc3a1614a8eaccd" dependencies = [ "bincode", "serde", @@ -5604,9 +5640,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" +checksum = "537dd038a89878be9b64dd4bd1b260315c1bb94f4d784956b81e27a088d9a09e" [[package]] name = "unicode-segmentation" @@ -5668,7 +5704,7 @@ checksum = "d674d135b4a8c1d7e813e2f8d1c9a58308aee4a680323066025e53132218bd91" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.116", ] [[package]] @@ -5711,6 +5747,15 @@ dependencies = [ "wit-bindgen", ] +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen", +] + [[package]] name = "wasix" version = "0.13.1" @@ -5752,7 +5797,7 @@ dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.116", "wasm-bindgen-shared", ] @@ -5765,6 +5810,40 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap 2.13.0", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags 2.11.0", + "hashbrown 0.15.5", + "indexmap 2.13.0", + "semver", +] + [[package]] name = "weak-table" version = "0.3.2" @@ -5789,9 +5868,9 @@ checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" [[package]] name = "webpki-roots" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12bed680863276c63889429bfd6cab3b99943659923822de1c8a39c49e4d722c" +checksum = "22cfaf3c063993ff62e73cb4311efde4db1efb31ab78a3e5c457939ad5cc0bed" dependencies = [ "rustls-pki-types", ] @@ -5905,7 +5984,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.116", ] [[package]] @@ -5916,7 +5995,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.116", ] [[package]] @@ -6162,6 +6241,88 @@ name = "wit-bindgen" version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck", + "indexmap 2.13.0", + "prettyplease", + "syn 2.0.116", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn 2.0.116", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags 2.11.0", + "indexmap 2.13.0", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap 2.13.0", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] [[package]] name = "wyz" @@ -6184,6 +6345,23 @@ dependencies = [ "zeroize", ] +[[package]] +name = "x509-parser" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d43b0f71ce057da06bc0851b23ee24f3f86190b07203dd8f567d0b706a185202" +dependencies = [ + "asn1-rs", + "data-encoding", + "der-parser", + "lazy_static", + "nom", + "oid-registry", + "rusticata-macros", + "thiserror 2.0.18", + "time", +] + [[package]] name = "zcash_address" version = "0.10.1" @@ -6250,7 +6428,7 @@ dependencies = [ "tower", "tracing", "trait-variant", - "webpki-roots 1.0.5", + "webpki-roots 1.0.6", "which", "zcash_address", "zcash_encoding", @@ -6378,14 +6556,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9bed6cf5b2b4361105d4ea06b2752f0c8af4641756c7fbc9858a80af186c234f" dependencies = [ "bip32", - "bitflags 2.10.0", + "bitflags 2.11.0", "bounded-vec", "hex", "ripemd 0.1.3", "secp256k1", "sha1", "sha2 0.10.9", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -6425,22 +6603,22 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.33" +version = "0.8.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "668f5168d10b9ee831de31933dc111a459c97ec93225beb307aed970d1372dfd" +checksum = "db6d35d663eadb6c932438e763b262fe1a70987f9ae936e60158176d710cae4a" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.33" +version = "0.8.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c7962b26b0a8685668b671ee4b54d007a67d4eaf05fda79ac0ecf41e32270f1" +checksum = "4122cd3169e94605190e77839c9a40d40ed048d305bfdc146e7df40ab0f3e517" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.116", ] [[package]] @@ -6466,7 +6644,7 @@ checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.116", ] [[package]] @@ -6485,15 +6663,18 @@ version = "1.1.0" dependencies = [ "http", "http-body", + "http-body-util", "hyper", "hyper-rustls", "hyper-util", "rustls-pemfile", "thiserror 1.0.69", + "tokio", "tokio-rustls", "tonic", "tower", "webpki-roots 0.25.4", + "x509-parser", "zcash_client_backend", ] @@ -6529,9 +6710,9 @@ dependencies = [ [[package]] name = "zmij" -version = "1.0.14" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd8f3f50b848df28f887acb68e41201b5aea6bc8a8dacc00fb40635ff9a72fea" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" [[package]] name = "zstd" diff --git a/Cargo.toml b/Cargo.toml index 17d1e2b..a5ad5b1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,16 +7,18 @@ resolver = "2" # network http = "1.1.0" http-body = "1" -hyper-util = "0.1" +hyper-util = "0.1.20" hyper = { version = "1", features = ["full"] } hyper-rustls = { version = "0.27", features = ["http2"] } +http-body-util = "0.1.3" rustls-pemfile = "2" tokio-rustls = "0.26" -tonic = { version = "0.14", features = [ - "tls-webpki-roots", -] } +tokio = { version = "1" } +tonic = { version = "0.14.4", features = ["tls-webpki-roots"] } tower = { version = "0.5" } webpki-roots = "0.25" # error thiserror = "1.0.64" +x509-parser = "0.18" +zcash_client_backend = "0.21" diff --git a/zingo-netutils/Cargo.toml b/zingo-netutils/Cargo.toml index 47c11d0..beb89ce 100644 --- a/zingo-netutils/Cargo.toml +++ b/zingo-netutils/Cargo.toml @@ -23,7 +23,7 @@ tonic.workspace = true tower.workspace = true webpki-roots.workspace = true -zcash_client_backend = { version = "0.21", features = [ +zcash_client_backend = { workspace = true, features = [ "lightwalletd-tonic", "orchard", "transparent-inputs", @@ -32,3 +32,6 @@ zcash_client_backend = { version = "0.21", features = [ [dev-dependencies] rustls-pemfile.workspace = true +tokio.workspace = true +http-body-util.workspace = true +x509-parser = { workspace = true } diff --git a/zingo-netutils/src/lib.rs b/zingo-netutils/src/lib.rs index 88e6df2..f5f2cb0 100644 --- a/zingo-netutils/src/lib.rs +++ b/zingo-netutils/src/lib.rs @@ -1,10 +1,7 @@ -//! Zingo-Netutils +//! `zingo-netutils` //! //! This crate provides the `GrpcConnector` struct, -//! used to communicate with a lightwalletd - -#![warn(missing_docs)] -use std::sync::Arc; +//! used to communicate with an indexer. use client::client_from_connector; use http::{Uri, uri::PathAndQuery}; @@ -15,14 +12,12 @@ use tower::ServiceExt; use tower::util::BoxCloneService; use zcash_client_backend::proto::service::compact_tx_streamer_client::CompactTxStreamerClient; -/// ? pub type UnderlyingService = BoxCloneService< http::Request, http::Response, hyper_util::client::legacy::Error, >; -#[allow(missing_docs)] // error types document themselves #[derive(Debug, thiserror::Error)] pub enum GetClientError { #[error("bad uri: invalid scheme")] @@ -33,11 +28,11 @@ pub enum GetClientError { InvalidPathAndQuery, } -/// ? pub mod client { use http_body::Body; use hyper_util::client::legacy::{Client, connect::Connect}; - /// a utility used in multiple places + + /// A utility used in multiple places pub fn client_from_connector(connector: C, http2_only: bool) -> Box> where C: Connect + Clone, @@ -53,9 +48,9 @@ pub mod client { } /// The connector, containing the URI to connect to. -/// This type is mostly an interface to the `get_client` method, -/// the proto-generated `CompactTxStreamerClient` type is the main -/// interface to actually communicating with a lightwalletd. +/// This type is mostly an interface to the `get_client` method. +/// The proto-generated `CompactTxStreamerClient` type is the main +/// interface to actually communicating with a Zcash indexer. #[derive(Clone)] pub struct GrpcConnector { uri: http::Uri, @@ -67,31 +62,58 @@ impl GrpcConnector { Self { uri } } - /// The URI to connect to + /// The URI to connect to. pub fn uri(&self) -> &Uri { &self.uri } /// Connect to the URI, and return a Client. For the full list of methods /// the client supports, see the service.proto file (some of the types - /// are defined in the `compact_formats.proto` file) + /// are defined in the `compact_formats.proto` file). pub fn get_client( &self, ) -> impl std::future::Future< Output = Result, GetClientError>, > { - let uri = Arc::new(self.uri.clone()); + let uri = self.uri.clone(); + async move { let mut http_connector = HttpConnector::new(); http_connector.enforce_http(false); + let scheme = uri.scheme().ok_or(GetClientError::InvalidScheme)?.clone(); let authority = uri .authority() .ok_or(GetClientError::InvalidAuthority)? .clone(); + + match uri.scheme_str() { + Some("https") | Some("http") => {} + _ => return Err(GetClientError::InvalidScheme), + } + + // Infallible request rewrite: scheme/authority came from a validated `Uri`, + // `path_and_query` is a valid `PathAndQuery` from the request. + let rewrite = move |mut request: http::Request<_>| { + let path_and_query = request + .uri() + .path_and_query() + .cloned() + .unwrap_or(PathAndQuery::from_static("/")); + + let new_uri = Uri::builder() + .scheme(scheme.clone()) + .authority(authority.clone()) + .path_and_query(path_and_query) + .build() + .expect("scheme/authority/path_and_query are known-valid"); + + *request.uri_mut() = new_uri; + request + }; + if uri.scheme_str() == Some("https") { let mut root_store = RootCertStore::empty(); - //webpki uses a different struct for TrustAnchor root_store.extend(webpki_roots::TLS_SERVER_ROOTS.iter().map(|anchor_ref| { TrustAnchor { subject: Der::from_slice(anchor_ref.subject), @@ -100,9 +122,6 @@ impl GrpcConnector { } })); - #[cfg(test)] - add_test_cert_to_roots(&mut root_store); - let config = ClientConfig::builder() .with_root_certificates(root_store) .with_no_client_auth(); @@ -110,7 +129,6 @@ impl GrpcConnector { let connector = tower::ServiceBuilder::new() .layer_fn(move |s| { let tls = config.clone(); - hyper_rustls::HttpsConnectorBuilder::new() .with_tls_config(tls) .https_or_http() @@ -118,72 +136,522 @@ impl GrpcConnector { .wrap_connector(s) }) .service(http_connector); - let client = client_from_connector(connector, false); + + // Enforce HTTP/2 for gRPC, otherwise it will seem "connected", but won't work + let client = client_from_connector(connector, true); + let svc = tower::ServiceBuilder::new() - //Here, we take all the pieces of our uri, and add in the path from the Requests's uri - .map_request(move |mut request: http::Request<_>| { - let path_and_query = request - .uri() - .path_and_query() - .cloned() - .unwrap_or(PathAndQuery::from_static("/")); - let uri = Uri::builder() - .scheme(scheme.clone()) - .authority(authority.clone()) - //here. The Request's uri contains the path to the GRPC server and - //the method being called - .path_and_query(path_and_query) - .build() - .unwrap(); - - *request.uri_mut() = uri; - request - }) + .map_request(rewrite) .service(client); Ok(CompactTxStreamerClient::new(svc.boxed_clone())) } else { let connector = tower::ServiceBuilder::new().service(http_connector); + let client = client_from_connector(connector, true); + let svc = tower::ServiceBuilder::new() - //Here, we take all the pieces of our uri, and add in the path from the Requests's uri - .map_request(move |mut request: http::Request<_>| { - let path_and_query = request - .uri() - .path_and_query() - .cloned() - .unwrap_or(PathAndQuery::from_static("/")); - let uri = Uri::builder() - .scheme(scheme.clone()) - .authority(authority.clone()) - //here. The Request's uri contains the path to the GRPC server and - //the method being called - .path_and_query(path_and_query) - .build() - .unwrap(); - - *request.uri_mut() = uri; - request - }) + .map_request(rewrite) .service(client); Ok(CompactTxStreamerClient::new(svc.boxed_clone())) } } } + + #[cfg(test)] + async fn get_service_for_tests(&self) -> Result { + let uri = self.uri.clone(); + + let mut http_connector = HttpConnector::new(); + http_connector.enforce_http(false); + + let scheme = uri.scheme().ok_or(GetClientError::InvalidScheme)?.clone(); + let authority = uri + .authority() + .ok_or(GetClientError::InvalidAuthority)? + .clone(); + + if uri.scheme_str() == Some("https") { + let mut root_store = RootCertStore::empty(); + root_store.extend(webpki_roots::TLS_SERVER_ROOTS.iter().map(|anchor_ref| { + TrustAnchor { + subject: Der::from_slice(anchor_ref.subject), + subject_public_key_info: Der::from_slice(anchor_ref.spki), + name_constraints: anchor_ref.name_constraints.map(Der::from_slice), + } + })); + + add_test_cert_to_roots(&mut root_store); + + let config = ClientConfig::builder() + .with_root_certificates(root_store) + .with_no_client_auth(); + + let connector = tower::ServiceBuilder::new() + .layer_fn(move |s| { + let tls = config.clone(); + hyper_rustls::HttpsConnectorBuilder::new() + .with_tls_config(tls) + .https_or_http() + .enable_http2() + .wrap_connector(s) + }) + .service(http_connector); + + let client = client_from_connector(connector, true); + + let svc = tower::ServiceBuilder::new() + .map_request(move |mut request: http::Request<_>| { + let path_and_query = request + .uri() + .path_and_query() + .cloned() + .unwrap_or(PathAndQuery::from_static("/")); + let uri = Uri::builder() + .scheme(scheme.clone()) + .authority(authority.clone()) + .path_and_query(path_and_query) + .build() + .unwrap(); + + *request.uri_mut() = uri; + request + }) + .service(client); + + Ok(svc.boxed_clone()) + } else { + let connector = tower::ServiceBuilder::new().service(http_connector); + + let client = client_from_connector(connector, true); + + let svc = tower::ServiceBuilder::new() + .map_request(move |mut request: http::Request<_>| { + let path_and_query = request + .uri() + .path_and_query() + .cloned() + .unwrap_or(PathAndQuery::from_static("/")); + let uri = Uri::builder() + .scheme(scheme.clone()) + .authority(authority.clone()) + .path_and_query(path_and_query) + .build() + .unwrap(); + + *request.uri_mut() = uri; + request + }) + .service(client); + + Ok(svc.boxed_clone()) + } + } } #[cfg(test)] fn add_test_cert_to_roots(roots: &mut RootCertStore) { use tonic::transport::CertificateDer; + eprintln!("Adding test cert to roots"); const TEST_PEMFILE_PATH: &str = "test-data/localhost.pem"; - let fd = std::fs::File::open(TEST_PEMFILE_PATH).unwrap(); - let mut buf = std::io::BufReader::new(&fd); + + let Ok(fd) = std::fs::File::open(TEST_PEMFILE_PATH) else { + eprintln!("Test TLS cert not found at {TEST_PEMFILE_PATH}, skipping"); + return; + }; + + let mut buf = std::io::BufReader::new(fd); let certs_bytes: Vec = rustls_pemfile::certs(&mut buf) .filter_map(Result::ok) .collect(); - let certs: Vec> = certs_bytes.into_iter().collect(); + let certs: Vec> = certs_bytes.into_iter().collect(); roots.add_parsable_certificates(certs); } + +#[cfg(test)] +mod tests { + //! Unit and integration-style tests for `zingo-netutils`. + //! + //! These tests focus on: + //! - TLS test asset sanity (`test-data/localhost.pem` + `.key`) + //! - Rustls plumbing (adding a local cert to a root store) + //! - Connector correctness (scheme validation, HTTP/2 expectations) + //! - URI rewrite behavior (no panics; returns structured errors) + //! + //! Notes: + //! - Some tests spin up an in-process TLS server and use aggressive timeouts to + //! avoid hangs under nextest. + //! - We explicitly install a rustls crypto provider to avoid + //! provider-selection panics in test binaries. + + use std::time::Duration; + + use http::{Request, Response}; + use hyper::{ + body::{Bytes, Incoming}, + service::service_fn, + }; + use hyper_util::rt::TokioIo; + use tokio::{net::TcpListener, sync::oneshot, time::timeout}; + use tokio_rustls::{TlsAcceptor, rustls}; + + use crate::tests::utils::{load_test_server_config, rewrite_request_uri}; + + use super::*; + + mod utils { + //! Test helpers shared across multiple test cases. + + use std::sync::Arc; + + use http::Uri; + use tokio_rustls::rustls; + + use crate::GetClientError; + + /// Loads a rustls `ServerConfig` for a local TLS server using the committed + /// test certificate and private key. + /// + /// The cert/key pair is *test-only* and is stored under `test-data/`. + /// This is used to verify that the client-side root-store injection + /// (`add_test_cert_to_roots`) actually enables successful TLS handshakes. + pub fn load_test_server_config() -> Arc { + let cert_pem = + std::fs::read("test-data/localhost.pem").expect("missing test-data/localhost.pem"); + let key_pem = + std::fs::read("test-data/localhost.key").expect("missing test-data/localhost.key"); + + let mut cert_cursor = std::io::BufReader::new(cert_pem.as_slice()); + let mut key_cursor = std::io::BufReader::new(key_pem.as_slice()); + + let certs = rustls_pemfile::certs(&mut cert_cursor) + .filter_map(Result::ok) + .map(rustls::pki_types::CertificateDer::from) + .collect::>(); + + let key = rustls_pemfile::private_key(&mut key_cursor) + .expect("failed to read private key") + .expect("no private key found"); + + let config = rustls::ServerConfig::builder() + .with_no_client_auth() + .with_single_cert(certs, key) + .expect("bad cert or key"); + + Arc::new(config) + } + + /// Rewrites a request URI by injecting a base `scheme://authority` and a + /// request-provided path. + /// + /// This is a test helper to validate the intended error behavior for + /// malformed inputs. The production code currently uses `unwrap()` when + /// rebuilding the URI. Tests use this helper to lock in a “no panics, + /// return `InvalidPathAndQuery`” contract for the eventual refactor. + pub fn rewrite_request_uri( + scheme: &str, + authority: &str, + path_and_query: &str, + ) -> Result { + Uri::builder() + .scheme(scheme) + .authority(authority) + .path_and_query(path_and_query) + .build() + .map_err(|_| GetClientError::InvalidPathAndQuery) + } + } + + /// Ensures the committed localhost test certificate exists and is parseable as X.509. + /// + /// This catches: + /// - missing file / wrong working directory assumptions + /// - invalid PEM encoding + /// - accidentally committing the wrong artifact (e.g., key instead of cert) + #[test] + fn localhost_cert_file_exists_and_is_parseable() { + const CERT_PATH: &str = "test-data/localhost.pem"; + + let pem = std::fs::read(CERT_PATH).expect("missing test-data/localhost.pem"); + + let mut cursor = std::io::BufReader::new(pem.as_slice()); + let certs = rustls_pemfile::certs(&mut cursor) + .filter_map(Result::ok) + .collect::>(); + + assert!(!certs.is_empty(), "no certs found in {CERT_PATH}"); + + for cert in certs { + let der = cert.as_ref(); + let parsed = x509_parser::parse_x509_certificate(der); + assert!( + parsed.is_ok(), + "failed to parse a cert from {CERT_PATH} as X.509" + ); + } + } + + /// Guards against committing a CA certificate as the TLS server certificate. + /// + /// Rustls rejects certificates with CA constraints when used as an end-entity + /// server certificate (e.g. `CaUsedAsEndEntity`), even if the cert is in the + /// root store. This test ensures the committed localhost cert has `CA:FALSE`. + #[test] + fn localhost_cert_is_end_entity_not_ca() { + let pem = + std::fs::read("test-data/localhost.pem").expect("missing test-data/localhost.pem"); + let mut cursor = std::io::BufReader::new(pem.as_slice()); + + let certs = rustls_pemfile::certs(&mut cursor) + .filter_map(Result::ok) + .collect::>(); + + assert!(!certs.is_empty(), "no certs found in localhost.pem"); + + let der = certs[0].as_ref(); + let parsed = x509_parser::parse_x509_certificate(der).expect("failed to parse X.509"); + let x509 = parsed.1; + + let bc = x509 + .basic_constraints() + .expect("missing basic constraints extension"); + + assert!(!bc.unwrap().value.ca, "localhost.pem must be CA:FALSE"); + } + + /// Smoke test: adding the committed localhost cert to a rustls root store enables + /// a client to complete a TLS handshake and perform an HTTP request. + /// + /// Implementation notes: + /// - Uses a local TLS server with the committed cert/key. + /// - Uses strict timeouts to prevent hangs under nextest. + /// - Explicitly drains the request body and disables keep-alive so that + /// `serve_connection` terminates deterministically. + /// - Installs the rustls crypto provider to avoid provider + /// selection panics in test binaries. + #[tokio::test] + async fn add_test_cert_to_roots_enables_tls_handshake() { + use http_body_util::Full; + use hyper::service::service_fn; + use hyper_util::rt::TokioIo; + use tokio::net::TcpListener; + use tokio_rustls::TlsAcceptor; + use tokio_rustls::rustls; + + let _ = rustls::crypto::ring::default_provider().install_default(); + + let listener = TcpListener::bind("127.0.0.1:0").await.expect("bind failed"); + let addr = listener.local_addr().expect("local_addr failed"); + + let tls_config = load_test_server_config(); + let acceptor = TlsAcceptor::from(tls_config); + + let ready = oneshot::channel::<()>(); + let ready_tx = ready.0; + let ready_rx = ready.1; + + let server_task = tokio::spawn(async move { + let _ = ready_tx.send(()); + + let accept_res = timeout(Duration::from_secs(3), listener.accept()).await; + let (socket, _) = accept_res + .expect("server accept timed out") + .expect("accept failed"); + + let tls_stream = timeout(Duration::from_secs(3), acceptor.accept(socket)) + .await + .expect("tls accept timed out") + .expect("tls accept failed"); + + let io = TokioIo::new(tls_stream); + + let svc = service_fn(|mut req: http::Request| async move { + use http_body_util::BodyExt; + + while let Some(frame) = req.body_mut().frame().await { + if frame.is_err() { + break; + } + } + + let mut resp = http::Response::new(Full::new(Bytes::from_static(b"ok"))); + resp.headers_mut().insert( + http::header::CONNECTION, + http::HeaderValue::from_static("close"), + ); + Ok::<_, hyper::Error>(resp) + }); + + timeout( + Duration::from_secs(3), + hyper::server::conn::http1::Builder::new() + .keep_alive(false) + .serve_connection(io, svc), + ) + .await + .expect("serve_connection timed out") + .expect("serve_connection failed"); + }); + + let _ = timeout(Duration::from_secs(1), ready_rx) + .await + .expect("server ready signal timed out") + .expect("server dropped before ready"); + + // Build client root store and add the test cert. + let mut roots = rustls::RootCertStore::empty(); + add_test_cert_to_roots(&mut roots); + + let client_config = rustls::ClientConfig::builder() + .with_root_certificates(roots) + .with_no_client_auth(); + + // This MUST allow http1 since the server uses hyper http1 builder. + let https = hyper_rustls::HttpsConnectorBuilder::new() + .with_tls_config(client_config) + .https_only() + .enable_http1() + .build(); + + let client = + hyper_util::client::legacy::Client::builder(hyper_util::rt::TokioExecutor::new()) + .build(https); + + let uri: http::Uri = format!("https://127.0.0.1:{}/", addr.port()) + .parse() + .expect("bad uri"); + + let req = http::Request::builder() + .method("GET") + .uri(uri) + .body(Full::::new(Bytes::new())) + .expect("request build failed"); + + let res = timeout(Duration::from_secs(3), client.request(req)) + .await + .expect("client request timed out") + .expect("TLS handshake or request failed"); + + assert!(res.status().is_success()); + + timeout(Duration::from_secs(3), server_task) + .await + .expect("server task timed out") + .expect("server task failed"); + } + + /// Validates that the connector rejects non-HTTP(S) URIs. + /// + /// This test is intended to fail until production code checks for: + /// - `http` and `https` schemes only + /// and rejects everything else (e.g. `ftp`). + #[tokio::test] + async fn rejects_non_http_schemes() { + let uri: http::Uri = "ftp://example.com:1234".parse().unwrap(); + let connector = GrpcConnector::new(uri); + let res = connector.get_client().await; + + assert!( + res.is_err(), + "expected get_client() to reject non-http(s) schemes, but got Ok" + ); + } + + /// Demonstrates the HTTPS downgrade hazard: the underlying client can successfully + /// talk to an HTTP/1.1-only TLS server if the HTTPS branch does not enforce HTTP/2. + /// + /// This is intentionally written as a “should be HTTP/2” test so it fails until + /// the HTTPS client is constructed with `http2_only(true)`. + #[tokio::test] + async fn https_connector_must_not_downgrade_to_http1() { + use http_body_util::Full; + + let _ = rustls::crypto::ring::default_provider().install_default(); + + let listener = TcpListener::bind("127.0.0.1:0").await.expect("bind failed"); + let addr = listener.local_addr().expect("local_addr failed"); + + let tls_config = load_test_server_config(); + let acceptor = TlsAcceptor::from(tls_config); + + // Server: HTTP/1.1-only over TLS. + // If the client is truly HTTP/2-only, Hyper's http1 parser will error with VersionH2. + let server_task = tokio::spawn(async move { + let (socket, _) = listener.accept().await.expect("accept failed"); + + let tls_stream = acceptor.accept(socket).await.expect("tls accept failed"); + let io = TokioIo::new(tls_stream); + + let svc = service_fn(|_req: Request| async move { + Ok::<_, hyper::Error>(Response::new(Full::new(Bytes::from_static(b"ok")))) + }); + + let res = hyper::server::conn::http1::Builder::new() + .serve_connection(io, svc) + .await; + + // The client sent an h2 preface to an h1 server, which is expected. + if let Err(err) = res { + let msg = err.to_string(); + assert!( + msg.contains("VersionH2") || msg.contains("version") || msg.contains("HTTP/2"), + "unexpected server error (expected VersionH2-ish parse error), got: {msg}" + ); + } + }); + + let base = format!("https://127.0.0.1:{}", addr.port()); + let uri = base.parse::().expect("bad base uri"); + let connector = GrpcConnector::new(uri); + + // Must match production: HTTP/2-only in HTTPS branch + let mut svc = connector + .get_service_for_tests() + .await + .expect("get_service_for_tests failed"); + + let req = Request::builder() + .method("POST") + .uri("/") + .header("content-type", "application/grpc") + .body(tonic::body::Body::empty()) + .expect("request build failed"); + + // The request MUST fail, meaning, not downgrade to HTTP/1.1 + let res = tower::ServiceExt::oneshot(&mut svc, req).await; + assert!( + res.is_err(), + "expected HTTP/2-only client to fail against HTTP/1.1-only TLS server" + ); + + let join = timeout(Duration::from_secs(3), server_task).await; + match join { + Ok(Ok(())) => {} + Ok(Err(join_err)) => panic!("server task join failed: {join_err}"), + Err(_) => { + // In rare cases the client might fail before server finishes parsing, abort to be safe. + // This is still success for the test. + } + } + } + + /// Ensures URI rewriting returns a structured error for invalid inputs instead + /// of panicking. + /// + /// This is a forward-looking regression test for refactoring production code to + /// replace `unwrap()` with `map_err(|_| InvalidPathAndQuery)`. + #[test] + fn rewrite_returns_error_instead_of_panicking() { + // Intentionally invalid path and query string. + let bad = "not-a path"; + + let result = rewrite_request_uri("https", "example.com:443", bad); + + assert!(matches!(result, Err(GetClientError::InvalidPathAndQuery))); + + let _ = PathAndQuery::from_static("/"); + } +} diff --git a/zingo-netutils/test-data/localhost.csr b/zingo-netutils/test-data/localhost.csr new file mode 100644 index 0000000..1fffccf --- /dev/null +++ b/zingo-netutils/test-data/localhost.csr @@ -0,0 +1,15 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIICWTCCAUECAQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEAnyEBTq2ooaN91tHj5PtvUU/cvGu+OAz9A7WWuVS0 +Y0TjrkkvGboCZM64mGjE6VHWX2EkTx9d7m7GpkYADR3770QuHVjOTHJWleXXbkci +EwtgAThGXul2mYwoFUySjGYt3pDLIXTHnTwU3NXvi562GfkG0lR5X3h7YRII833k +mMMWOdM3T6MSLO2+vu8tqQ5aAepJ/MyrnRjqSo2mMqXmmMqOWTpef1L++czmtJdK +H8NE6ELo6T/YPC2WT4vWUlanzmsCkeDI5h+v9KmMe3xISc/QwLgabBoZU1YBa+J7 +Y1zgR2YM9cmkJ3dRQrw3FzXoc++R4vYnFIte+LkGG3aoKQIDAQABoAAwDQYJKoZI +hvcNAQELBQADggEBAAp70LfmgLUvFdf3Z410m6AqkN50WStSp8gDgf1QcOXvXtm6 +BfzDZWmN45KcgX0/E56ROCJ4AWb5V6iXbfqjWkS/fLciOswH2g0pxDWegvuXA9XL +i0r/Zz08jsf6XlwqPQDw7OVH4K/voO5pDjLw7/biftCYo8jEYODM35eoavf+B2yZ +D4bCwuTCsjW9qTRTh2L9KhLHZQV4+uG4lBNsZ3QFYr5ZNFRHzAPNNIr8uTGrZ7DO +FsDBIwG5giycMCxonvlQ36coKhW7mO5xzsHDuP14iagSIX5+gKf0CZDYUuwOfifA +6XZZXdTVZYrRR8kh18vVLEiMYMa6Y1XgjreKiu4= +-----END CERTIFICATE REQUEST----- diff --git a/zingo-netutils/test-data/localhost.key b/zingo-netutils/test-data/localhost.key new file mode 100644 index 0000000..9647294 --- /dev/null +++ b/zingo-netutils/test-data/localhost.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCfIQFOraiho33W +0ePk+29RT9y8a744DP0DtZa5VLRjROOuSS8ZugJkzriYaMTpUdZfYSRPH13ubsam +RgANHfvvRC4dWM5MclaV5dduRyITC2ABOEZe6XaZjCgVTJKMZi3ekMshdMedPBTc +1e+LnrYZ+QbSVHlfeHthEgjzfeSYwxY50zdPoxIs7b6+7y2pDloB6kn8zKudGOpK +jaYypeaYyo5ZOl5/Uv75zOa0l0ofw0ToQujpP9g8LZZPi9ZSVqfOawKR4MjmH6/0 +qYx7fEhJz9DAuBpsGhlTVgFr4ntjXOBHZgz1yaQnd1FCvDcXNehz75Hi9icUi174 +uQYbdqgpAgMBAAECggEAAY75/rOKlBEYyZ5coytat8Ba4vYSpg/A5212iPqtREZL +6vczdhf54tNmryqmdCF67RTAWTgrBs/cRODkxAjsNfNu3P1ieO7NNo9spx+US3SF +mUG5+WFUx8Q1PznBkFmoYEiYFtjcntRHi8M4XrkqJUiTXZhCeR/VOcgGXvOZw/U8 +9g7/t5KSi/77GaNJ2lbueORGMgRxqg18tJ0MRi/UZ/jMC95iWsvjWgZlOO6lYGOt +zy5A+Wr5w85Hfi93VjLtMiOQk3rUzSRlcdmH9xON9uLDxhzobMu4R2TRZb4nl5eU +UCf4WcBODALmEcp8bFC559hIVFcF6U8IzafyvHQhkQKBgQDL1s7bift+rSBT7jMx +TPb/YfLKR+AwgGzINexpwM6HMGSztn8f2wzZLJj/GsQ1ym2BMIyomT1db/A2+Z7s +YGlaWw3sgZq64gx1A0PQhxtqvTdwMkogDMaB+i1wXTQgK5EsD3ub+T3ef0yLrPjF +okqiXyAyrdpyBlisS5hqbTv4MwKBgQDH2U0kgTSBCEldKu3bfAEe7EyFz/L9QPWW +xET9d8F+HhtKeEhzPiDPhylbRAwfdcc4hsNFcTZ+r+5qowYLhxffsPWwPG9r8HQL +43KfvZVqdJZAuY0V4JklJ+dEaqU1glzrGPWekKbd/ibAT6pqzxOMQvJmZ3XZuPLJ +RH3wZIzyMwKBgQCQpBSU5Ax5jw/pfpUE3sBF55MIxofm4rpONzVStWXXuBc9DrqW +ODGdyW+nVa71HHcnvPOSj2pj6xJhcC+9O4yGeSYgNLc+9Tgxr+dnCPgDfdDg5E6E +/4u8n3Gu0fQy/7c7tKDZxLqKL3p5gnvkgYzEOwv16jefwbEaUWoN2wU60QKBgEj3 +VesWIY1a8S5LFj0ksWQQ8n+IxTciGIjLcET7DHJ3m489C3bIIEKlHrxrw+FYpzxE +N9eK1lK6+VmF3BcpY9YQTiPibOwEBtqwWJFqLruHhbRsCs8KCeA/CXk5VsiKqFJN +8p/KQKKcwJlGfPoyUPjNGKO68pRjqoFBuJmknLFxAoGARu1lx4gy55g0/oxZxqw7 +yaCcpVUWbm44UjPYVo2zPmCXgw5c5LzS3qcKyJZMor7TCXdA407XzH5avdKwkDGz +8FDrequmTJinZ/x0tZHT4Pa+VPthFAHgHCFKSmqL7x3fg9CP6Wv24Lvc/uly6RA7 +5Nqkpf+sxNiyuKU1lcizcUA= +-----END PRIVATE KEY----- diff --git a/zingo-netutils/test-data/localhost.pem b/zingo-netutils/test-data/localhost.pem new file mode 100644 index 0000000..dba53bd --- /dev/null +++ b/zingo-netutils/test-data/localhost.pem @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDPDCCAiSgAwIBAgIUGCznatKhidESk1bKCKtOMfdaMacwDQYJKoZIhvcNAQEL +BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MCAXDTI2MDIxNTE4NDk0NVoYDzIxMjYw +MTIyMTg0OTQ1WjAUMRIwEAYDVQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQCfIQFOraiho33W0ePk+29RT9y8a744DP0DtZa5VLRj +ROOuSS8ZugJkzriYaMTpUdZfYSRPH13ubsamRgANHfvvRC4dWM5MclaV5dduRyIT +C2ABOEZe6XaZjCgVTJKMZi3ekMshdMedPBTc1e+LnrYZ+QbSVHlfeHthEgjzfeSY +wxY50zdPoxIs7b6+7y2pDloB6kn8zKudGOpKjaYypeaYyo5ZOl5/Uv75zOa0l0of +w0ToQujpP9g8LZZPi9ZSVqfOawKR4MjmH6/0qYx7fEhJz9DAuBpsGhlTVgFr4ntj +XOBHZgz1yaQnd1FCvDcXNehz75Hi9icUi174uQYbdqgpAgMBAAGjgYMwgYAwDAYD +VR0TAQH/BAIwADAOBgNVHQ8BAf8EBAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUHAwEw +LAYDVR0RBCUwI4IJbG9jYWxob3N0hwR/AAABhxAAAAAAAAAAAAAAAAAAAAABMB0G +A1UdDgQWBBQvBAfrJIywR4VbIAzBq+FUm55ncTANBgkqhkiG9w0BAQsFAAOCAQEA +JsvgC1x2/kHWBjoJmgvlZh0ZE7jS9a9JgXZju8PpCAADBbyhKhFLLjel6s5b9qTt +ZHyFDCBiZnSkDCVNKHqZSejDwLDN15zdwv06A9WUTnTgMp43s+h1+dUpU7QKscFa +4SWnDLSfV7gGVAFTDKwVmsNcVsGKpVP8rkLWzquPu9z3/W1wucDa8p++OVMQROLC +OkM3azphnJJdXqcVpefJXVb/11G1UFJmHXyj3PnshQp7hpB3ug5Br1+/lQOz9p1j +nEBcIlj+VatqmTABQg1IIlJDMzvFWIw31bgXja9dkAy8pxA5YnNiq38C6T6XKqBH +TNtJO8OPwYlPH6ckht/YjA== +-----END CERTIFICATE-----