diff --git a/Cargo.lock b/Cargo.lock index d9d9d23..ce808cd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,41 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +[[package]] +name = "aead" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +dependencies = [ + "crypto-common", + "generic-array", +] + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "aes-gcm" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "ghash", + "subtle", +] + [[package]] name = "aho-corasick" version = "1.1.3" @@ -116,12 +151,30 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + [[package]] name = "base64" version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "base64ct" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89e25b6adfb930f02d1981565a6e5d9c547ac15a96606256d3b59040e5cd4ca3" + [[package]] name = "binascii" version = "0.1.4" @@ -134,6 +187,15 @@ version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + [[package]] name = "bumpalo" version = "3.17.0" @@ -146,6 +208,12 @@ version = "1.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6b1fc10dbac614ebc03540c9dbd60e83887fda27794998c6528f1782047d540" +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "bytes" version = "1.10.1" @@ -181,11 +249,29 @@ checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c" dependencies = [ "android-tzdata", "iana-time-zone", + "js-sys", "num-traits", "serde", + "wasm-bindgen", "windows-link", ] +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + [[package]] name = "convert_case" version = "0.6.0" @@ -201,17 +287,188 @@ version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" dependencies = [ + "aes-gcm", + "base64 0.22.1", + "hkdf", "percent-encoding", + "rand 0.8.5", + "sha2", + "subtle", "time", "version_check", ] +[[package]] +name = "cookie_store" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2eac901828f88a5241ee0600950ab981148a18f2f756900ffba1b125ca6a3ef9" +dependencies = [ + "cookie", + "document-features", + "idna", + "log", + "publicsuffix", + "serde", + "serde_derive", + "serde_json", + "time", + "url", +] + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation-sys" version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "typenum", +] + +[[package]] +name = "cssparser" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c66d1cd8ed61bf80b38432613a7a2f09401ab8d0501110655f8b341484a3e3" +dependencies = [ + "cssparser-macros", + "dtoa-short", + "itoa", + "phf", + "smallvec", +] + +[[package]] +name = "cssparser-macros" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher", +] + +[[package]] +name = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest", + "fiat-crypto", + "rustc_version", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "darling" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" +dependencies = [ + "darling_core", + "quote", + "syn", +] + +[[package]] +name = "der" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" +dependencies = [ + "const-oid", + "pem-rfc7468", + "zeroize", +] + [[package]] name = "deranged" version = "0.4.1" @@ -222,6 +479,17 @@ dependencies = [ "serde", ] +[[package]] +name = "derive_more" +version = "0.99.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3da29a38df43d6f156149c9b43ded5e018ddff2a855cf2cfd62e8cd7d079c69f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "devise" version = "0.4.2" @@ -255,6 +523,18 @@ dependencies = [ "syn", ] +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "const-oid", + "crypto-common", + "subtle", +] + [[package]] name = "displaydoc" version = "0.2.5" @@ -266,6 +546,80 @@ dependencies = [ "syn", ] +[[package]] +name = "document-features" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95249b50c6c185bee49034bcb378a49dc2b5dff0be90ff6616d31d64febab05d" +dependencies = [ + "litrs", +] + +[[package]] +name = "dtoa" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6add3b8cff394282be81f3fc1a0605db594ed69890078ca6e2cab1c408bcf04" + +[[package]] +name = "dtoa-short" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87" +dependencies = [ + "dtoa", +] + +[[package]] +name = "dyn-clone" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c7a8fb8a9fbf66c1f703fe16184d10ca0ee9d23be5b4436400408ba54a95005" + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "pkcs8", + "signature", +] + +[[package]] +name = "ed25519-dalek" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" +dependencies = [ + "curve25519-dalek", + "ed25519", + "serde", + "sha2", + "subtle", + "zeroize", +] + +[[package]] +name = "ego-tree" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2972feb8dffe7bc8c5463b1dacda1b0dfbed3710e50f977d965429692d74cd8" + [[package]] name = "either" version = "1.15.0" @@ -275,6 +629,27 @@ dependencies = [ "serde", ] +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest", + "ff", + "generic-array", + "group", + "hkdf", + "pem-rfc7468", + "pkcs8", + "rand_core 0.6.4", + "sec1", + "subtle", + "zeroize", +] + [[package]] name = "encoding_rs" version = "0.8.35" @@ -306,6 +681,22 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +[[package]] +name = "ff" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + [[package]] name = "figment" version = "0.10.19" @@ -326,6 +717,21 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + [[package]] name = "form_urlencoded" version = "1.2.1" @@ -434,6 +840,15 @@ dependencies = [ "slab", ] +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + [[package]] name = "generator" version = "0.7.5" @@ -447,6 +862,17 @@ dependencies = [ "windows", ] +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + [[package]] name = "getrandom" version = "0.2.15" @@ -474,6 +900,16 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "ghash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" +dependencies = [ + "opaque-debug", + "polyval", +] + [[package]] name = "gimli" version = "0.31.1" @@ -486,6 +922,17 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "h2" version = "0.3.26" @@ -498,7 +945,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap", + "indexmap 2.8.0", "slab", "tokio", "tokio-util", @@ -517,13 +964,19 @@ dependencies = [ "futures-core", "futures-sink", "http 1.3.1", - "indexmap", + "indexmap 2.8.0", "slab", "tokio", "tokio-util", "tracing", ] +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + [[package]] name = "hashbrown" version = "0.15.2" @@ -542,6 +995,30 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbd780fe5cc30f81464441920d82ac8740e2e46b29a6fad543ddd075229ce37e" +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + [[package]] name = "html5ever" version = "0.27.0" @@ -550,12 +1027,24 @@ checksum = "c13771afe0e6e846f1e67d038d4cb29998a6779f93c809212e4e9c32efd244d4" dependencies = [ "log", "mac", - "markup5ever", + "markup5ever 0.12.1", "proc-macro2", "quote", "syn", ] +[[package]] +name = "html5ever" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b7410cae13cbc75623c98ac4cbfd1f0bedddf3227afc24f370cf0f50a44a11c" +dependencies = [ + "log", + "mac", + "markup5ever 0.14.1", + "match_token", +] + [[package]] name = "http" version = "0.2.12" @@ -686,6 +1175,22 @@ dependencies = [ "webpki-roots", ] +[[package]] +name = "hyper-tls" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" +dependencies = [ + "bytes", + "http-body-util", + "hyper 1.6.0", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", +] + [[package]] name = "hyper-util" version = "0.1.11" @@ -848,6 +1353,12 @@ dependencies = [ "syn", ] +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + [[package]] name = "idna" version = "1.0.3" @@ -869,6 +1380,17 @@ dependencies = [ "icu_properties", ] +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + [[package]] name = "indexmap" version = "2.8.0" @@ -876,7 +1398,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.15.2", "serde", ] @@ -886,6 +1408,15 @@ version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8fae54786f62fb2918dcfae3d568594e50eb9b5c25bf04371af6fe7516452fb" +[[package]] +name = "inout" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +dependencies = [ + "generic-array", +] + [[package]] name = "ipnet" version = "2.11.0" @@ -912,6 +1443,15 @@ dependencies = [ "nom", ] +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.15" @@ -934,7 +1474,7 @@ version = "9.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a87cc7a48537badeae96744432de36f4be2b4a34a05a5ef32e9dd8a1c169dde" dependencies = [ - "base64", + "base64 0.22.1", "js-sys", "ring", "serde", @@ -946,6 +1486,9 @@ name = "lazy_static" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin", +] [[package]] name = "libc" @@ -953,6 +1496,12 @@ version = "0.2.171" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" +[[package]] +name = "libm" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" + [[package]] name = "linux-raw-sys" version = "0.9.3" @@ -965,6 +1514,12 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" +[[package]] +name = "litrs" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" + [[package]] name = "lock_api" version = "0.4.12" @@ -1016,18 +1571,43 @@ dependencies = [ "tendril", ] +[[package]] +name = "markup5ever" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7a7213d12e1864c0f002f52c2923d4556935a43dec5e71355c2760e0f6e7a18" +dependencies = [ + "log", + "phf", + "phf_codegen", + "string_cache", + "string_cache_codegen", + "tendril", +] + [[package]] name = "markup5ever_rcdom" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edaa21ab3701bfee5099ade5f7e1f84553fd19228cf332f13cd6e964bf59be18" dependencies = [ - "html5ever", - "markup5ever", + "html5ever 0.27.0", + "markup5ever 0.12.1", "tendril", "xml5ever", ] +[[package]] +name = "match_token" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88a9689d8d44bf9964484516275f5cd4c9b59457a6940c1d5d0ecbb94510a36b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "matchers" version = "0.1.0" @@ -1128,6 +1708,23 @@ dependencies = [ "version_check", ] +[[package]] +name = "native-tls" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + [[package]] name = "new_debug_unreachable" version = "1.0.6" @@ -1153,12 +1750,49 @@ dependencies = [ "winapi", ] +[[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 0.8.5", + "smallvec", + "zeroize", +] + [[package]] name = "num-conv" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -1166,6 +1800,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", + "libm", ] [[package]] @@ -1178,6 +1813,26 @@ dependencies = [ "libc", ] +[[package]] +name = "oauth2" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51e219e79014df21a225b1860a479e2dcd7cbd9130f4defd4bd0e191ea31d67d" +dependencies = [ + "base64 0.22.1", + "chrono", + "getrandom 0.2.15", + "http 1.3.1", + "rand 0.8.5", + "reqwest", + "serde", + "serde_json", + "serde_path_to_error", + "sha2", + "thiserror 1.0.69", + "url", +] + [[package]] name = "object" version = "0.36.7" @@ -1193,12 +1848,126 @@ version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "openidconnect" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dd50d4a5e7730e754f94d977efe61f611aadd3131f6a2b464f6e3a4167e8ef7" +dependencies = [ + "base64 0.21.7", + "chrono", + "dyn-clone", + "ed25519-dalek", + "hmac", + "http 1.3.1", + "itertools", + "log", + "oauth2", + "p256", + "p384", + "rand 0.8.5", + "rsa", + "serde", + "serde-value", + "serde_json", + "serde_path_to_error", + "serde_plain", + "serde_with", + "sha2", + "subtle", + "thiserror 1.0.69", + "url", +] + +[[package]] +name = "openssl" +version = "0.10.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fedfea7d58a1f73118430a55da6a286e7b044961736ce96a16a17068ea25e5da" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "openssl-probe" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" + +[[package]] +name = "openssl-sys" +version = "0.9.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8288979acd84749c744a9014b4382d42b8f7b2592847b5afb2ed29e5d16ede07" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "ordered-float" +version = "2.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c" +dependencies = [ + "num-traits", +] + [[package]] name = "overload" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" +[[package]] +name = "p256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + +[[package]] +name = "p384" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe42f1670a52a47d448f14b6a5c61dd78fce51856e68edaa38f7ae3a46b8d6b6" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + [[package]] name = "parking_lot" version = "0.12.3" @@ -1245,6 +2014,15 @@ dependencies = [ "syn", ] +[[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.1" @@ -1257,6 +2035,7 @@ version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" dependencies = [ + "phf_macros", "phf_shared", ] @@ -1280,6 +2059,19 @@ dependencies = [ "rand 0.8.5", ] +[[package]] +name = "phf_macros" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "phf_shared" version = "0.11.3" @@ -1301,6 +2093,45 @@ 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.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "polyval" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" +dependencies = [ + "cfg-if", + "cpufeatures", + "opaque-debug", + "universal-hash", +] + [[package]] name = "powerfmt" version = "0.2.0" @@ -1322,6 +2153,15 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve", +] + [[package]] name = "proc-macro2" version = "1.0.94" @@ -1344,6 +2184,22 @@ dependencies = [ "yansi", ] +[[package]] +name = "psl-types" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33cb294fe86a74cbcf50d4445b37da762029549ebeea341421c7c70370f86cac" + +[[package]] +name = "publicsuffix" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42ea446cab60335f76979ec15e12619a2165b5ae2c12166bef27d283a9fadf" +dependencies = [ + "idna", + "psl-types", +] + [[package]] name = "quinn" version = "0.11.7" @@ -1552,8 +2408,11 @@ version = "0.12.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d19c46a6fdd48bc4dab94b6103fccc55d34c67cc0ad04653aad4ea2a07cd7bbb" dependencies = [ - "base64", + "base64 0.22.1", "bytes", + "cookie", + "cookie_store", + "encoding_rs", "futures-core", "futures-util", "h2 0.4.8", @@ -1562,11 +2421,13 @@ dependencies = [ "http-body-util", "hyper 1.6.0", "hyper-rustls", + "hyper-tls", "hyper-util", "ipnet", "js-sys", "log", "mime", + "native-tls", "once_cell", "percent-encoding", "pin-project-lite", @@ -1578,7 +2439,9 @@ dependencies = [ "serde_json", "serde_urlencoded", "sync_wrapper", + "system-configuration", "tokio", + "tokio-native-tls", "tokio-rustls", "tokio-util", "tower", @@ -1592,6 +2455,16 @@ dependencies = [ "windows-registry", ] +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + [[package]] name = "ring" version = "0.17.14" @@ -1620,7 +2493,7 @@ dependencies = [ "either", "figment", "futures", - "indexmap", + "indexmap 2.8.0", "log", "memchr", "multer", @@ -1652,7 +2525,7 @@ checksum = "575d32d7ec1a9770108c879fc7c47815a80073f96ca07ff9525a94fcede1dd46" dependencies = [ "devise", "glob", - "indexmap", + "indexmap 2.8.0", "proc-macro2", "quote", "rocket_http", @@ -1672,7 +2545,7 @@ dependencies = [ "futures", "http 0.2.12", "hyper 0.14.32", - "indexmap", + "indexmap 2.8.0", "log", "memchr", "pear", @@ -1688,6 +2561,26 @@ dependencies = [ "uncased", ] +[[package]] +name = "rsa" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78928ac1ed176a5ca1d17e578a1825f3d81ca54cf41053a592584b020cfd691b" +dependencies = [ + "const-oid", + "digest", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core 0.6.4", + "signature", + "spki", + "subtle", + "zeroize", +] + [[package]] name = "rustc-demangle" version = "0.1.24" @@ -1700,6 +2593,15 @@ version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + [[package]] name = "rustix" version = "1.0.5" @@ -1768,6 +2670,15 @@ version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" +[[package]] +name = "schannel" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" +dependencies = [ + "windows-sys 0.59.0", +] + [[package]] name = "scoped-tls" version = "1.0.1" @@ -1780,24 +2691,103 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "scraper" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "527e65d9d888567588db4c12da1087598d0f6f8b346cc2c5abc91f05fc2dffe2" +dependencies = [ + "cssparser", + "ego-tree", + "html5ever 0.29.1", + "precomputed-hash", + "selectors", + "tendril", +] + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "security-framework" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "seensite" version = "0.1.0" dependencies = [ "chrono", "form_urlencoded", - "html5ever", + "html5ever 0.27.0", "jsonwebtoken", "markup5ever_rcdom", "meilisearch-sdk", + "openidconnect", "rand 0.9.0", + "reqwest", "rocket", + "scraper", "serde", "thiserror 2.0.12", "tracing", "tracing-subscriber", ] +[[package]] +name = "selectors" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd568a4c9bb598e291a08244a5c1f5a8a6650bee243b5b0f8dbb3d9cc1d87fe8" +dependencies = [ + "bitflags", + "cssparser", + "derive_more", + "fxhash", + "log", + "new_debug_unreachable", + "phf", + "phf_codegen", + "precomputed-hash", + "servo_arc", + "smallvec", +] + +[[package]] +name = "semver" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" + [[package]] name = "serde" version = "1.0.219" @@ -1807,6 +2797,16 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde-value" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" +dependencies = [ + "ordered-float", + "serde", +] + [[package]] name = "serde_derive" version = "1.0.219" @@ -1830,6 +2830,25 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_path_to_error" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59fab13f937fa393d08645bf3a84bdfe86e296747b506ada67bb15f10f218b2a" +dependencies = [ + "itoa", + "serde", +] + +[[package]] +name = "serde_plain" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce1fc6db65a611022b23a0dec6975d63fb80a302cb3388835ff02c097258d50" +dependencies = [ + "serde", +] + [[package]] name = "serde_spanned" version = "0.6.8" @@ -1851,6 +2870,56 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_with" +version = "3.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6b6f7f2fcb69f747921f79f3926bd1e203fce4fef62c268dd3abfb6d86029aa" +dependencies = [ + "base64 0.22.1", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.8.0", + "serde", + "serde_derive", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d00caa5193a3c8362ac2b73be6b9e768aa5a4b2f721d8f4b339600c3cb51f8e" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "servo_arc" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae65c4249478a2647db249fb43e23cec56a2c8974a427e7bd8cb5a1d0964921a" +dependencies = [ + "stable_deref_trait", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "sharded-slab" version = "0.1.7" @@ -1875,6 +2944,16 @@ 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 0.6.4", +] + [[package]] name = "siphasher" version = "1.0.1" @@ -1912,6 +2991,16 @@ version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + [[package]] name = "stable-pattern" version = "0.1.0" @@ -1961,6 +3050,12 @@ dependencies = [ "quote", ] +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + [[package]] name = "structmeta" version = "0.3.0" @@ -2021,6 +3116,27 @@ dependencies = [ "syn", ] +[[package]] +name = "system-configuration" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" +dependencies = [ + "bitflags", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "tempfile" version = "3.19.1" @@ -2179,6 +3295,16 @@ dependencies = [ "syn", ] +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + [[package]] name = "tokio-rustls" version = "0.26.2" @@ -2240,7 +3366,7 @@ version = "0.22.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" dependencies = [ - "indexmap", + "indexmap 2.8.0", "serde", "serde_spanned", "toml_datetime", @@ -2341,6 +3467,12 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "typenum" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" + [[package]] name = "ubyte" version = "0.10.4" @@ -2378,6 +3510,16 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" +[[package]] +name = "universal-hash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +dependencies = [ + "crypto-common", + "subtle", +] + [[package]] name = "untrusted" version = "0.9.0" @@ -2393,6 +3535,7 @@ dependencies = [ "form_urlencoded", "idna", "percent-encoding", + "serde", ] [[package]] @@ -2430,6 +3573,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "version_check" version = "0.9.5" @@ -2924,7 +4073,7 @@ checksum = "9bbb26405d8e919bc1547a5aa9abc95cbfa438f04844f5fdd9dc7596b748bf69" dependencies = [ "log", "mac", - "markup5ever", + "markup5ever 0.12.1", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index a0e2030..296cbe1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,8 +9,10 @@ html5ever = "0.27.0" jsonwebtoken = { version = "9.3.1", default-features = false } markup5ever_rcdom = "0.3.0" meilisearch-sdk = "0.28.0" +openidconnect = { version = "4.0.0", default-features = false, features = ["reqwest", "native-tls"] } rand = "0.9.0" -rocket = { version = "0.5.1", features = ["json"] } +reqwest = { version = "0.12.15", features = ["json", "native-tls"] } +rocket = { version = "0.5.1", features = ["json", "secrets"] } serde = { version = "1.0.219", features = ["derive"] } thiserror = "2.0.12" tracing = "0.1.41" @@ -18,3 +20,5 @@ tracing-subscriber = { version = "0.3.19", features = ["env-filter"] } [dev-dependencies] form_urlencoded = "1.2.1" +reqwest = { version = "0.12.15", features = ["cookies"] } +scraper = { version = "0.23.1", default-features = false } diff --git a/dex.yaml b/dex.yaml new file mode 100644 index 0000000..52518bb --- /dev/null +++ b/dex.yaml @@ -0,0 +1,29 @@ +issuer: http://127.0.0.1:5556/dex + +storage: + type: memory + +web: + http: 0.0.0.0:5556 + +staticClients: +- id: example-app + redirectURIs: + - 'http://localhost:8000/oidc-callback' + name: 'Example App' + secret: example-app-secret + +enablePasswordDB: true + +staticPasswords: +- email: "user@example.com" + # bcrypt hash of "password" + hash: "$2y$10$BvrNnoSifaDAcS95zT5CyegMKE90S9gpiMHcJj82hVnyRYwn2LNwS" + username: "testuser" + userID: "1234" + +oauth2: + skipApprovalScreen: true + +logger: + level: debug diff --git a/run-tests.sh b/run-tests.sh index 314b1f7..75b090c 100755 --- a/run-tests.sh +++ b/run-tests.sh @@ -11,6 +11,11 @@ cleanup() { rm "${meilisearch_key}" fi unset meilisearch_key + if [ -n "${dex_cid}" ]; then + echo 'Stopping Dex ...' >&2 + podman stop "${dex_cid}" >/dev/null + fi + unset cid if [ -f "${jwt_key}" ]; then rm "${jwt_key}" fi @@ -48,6 +53,22 @@ curl -s 127.0.0.1:${port}/keys -H "Authorization: Bearer ${MEILI_MASTER_KEY}" \ | jq -r '.results[] | select(.name == "Default Admin API Key") | .key' \ > "${meilisearch_key}" +echo 'Starting Dex ...' +dex_cid=$( + podman run --rm -d \ + -p 5556:5556 \ + -v ./dex.yaml:/etc/dex/config.yaml:ro,z \ + ghcr.io/dexidp/dex \ + dex serve /etc/dex/config.yaml +) || exit +dex_port=5556 +printf 'Waiting for Dex on port %d ...' "${dex_port}" >&2 +until curl -fs -o /dev/null 127.0.0.1:${dex_port}/dex/healthz; do + printf '.' + sleep 0.25 +done +echo ' ready' >&2 + echo 'Generating JWT secret key ...' >&2 jwt_key=$(mktemp jwt.secret.XXXXXX) tr -cd 0-9A-Za-z_- < /dev/urandom | head -c 32 > "${jwt_key}" @@ -60,6 +81,12 @@ token = "${meilisearch_key}" [test.auth] jwt_secret = "${jwt_key}" + +[test.oidc] +discovery_url = "http://127.0.0.1:${dex_port}/dex" +client_id = "example-app" +client_secret = "example-app-secret" +callback_url = "http://localhost:8000/oidc-callback" EOF export ROCKET_PROFILE=test export ROCKET_CONFIG diff --git a/src/auth.rs b/src/auth.rs index b08db12..dd13f5f 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -1,16 +1,31 @@ +use std::collections::HashMap; use std::io::Read; use std::time::SystemTime; use jsonwebtoken::{ - decode, encode, Algorithm, DecodingKey, EncodingKey, Header, TokenData, - Validation, + decode, encode, Algorithm, DecodingKey, EncodingKey, Header, Validation, }; -use rocket::http::Status; +use openidconnect::core::{ + CoreAuthenticationFlow, CoreClient, CoreIdTokenClaims, + CoreProviderMetadata, +}; +use openidconnect::{ + AccessTokenHash, AuthorizationCode, ClientId, ClientSecret, CsrfToken, + EndpointMaybeSet, EndpointNotSet, EndpointSet, IssuerUrl, Nonce, + OAuth2TokenResponse, PkceCodeChallenge, PkceCodeVerifier, RedirectUrl, + Scope, TokenResponse, +}; +use rocket::config::Config as RocketConfig; +use rocket::http::{Cookie, CookieJar, SameSite, Status}; use rocket::request::{FromRequest, Outcome, Request}; +use rocket::response::Redirect; +use rocket::time::{Duration, OffsetDateTime}; +use rocket::State; use serde::{Deserialize, Serialize}; -use tracing::error; +use tracing::{debug, error, trace, warn}; use crate::config::Config; +use crate::error::{LoginError, OidcError}; use crate::Context; #[derive(Debug, PartialEq, Serialize, Deserialize)] @@ -31,7 +46,7 @@ impl<'r> FromRequest<'r> for UserClaims { let secret = &req.rocket().state::().unwrap().jwt_secret; match req.headers().get_one("Authorization") { Some(s) => match extract_token(secret, s) { - Ok(d) => Outcome::Success(d.claims), + Ok(d) => Outcome::Success(d), Err(e) => Outcome::Error((Status::Unauthorized, e)), }, None => Outcome::Error((Status::Unauthorized, "Unauthorized")), @@ -62,15 +77,89 @@ impl UserClaims { let k = EncodingKey::from_secret(secret); encode(&Header::default(), self, &k) } + + fn from_jwt( + token: &str, + secret: &[u8], + ) -> Result { + let mut v = Validation::new(Algorithm::HS256); + v.validate_nbf = true; + v.set_issuer(&[env!("CARGO_PKG_NAME")]); + v.set_audience(&[env!("CARGO_PKG_NAME")]); + let k = DecodingKey::from_secret(secret); + Ok(decode(token, &k, &v)?.claims) + } } impl Context { + /// Create a signed JWT for a [`UserClaims`] pub fn make_jwt( &self, claims: &UserClaims, ) -> Result { claims.to_jwt(&self.jwt_secret) } + + /// Decode a [`UserClaims`] from a JWT + pub fn decode_jwt( + &self, + token: &str, + ) -> Result { + UserClaims::from_jwt(token, &self.jwt_secret) + } +} + +pub type OidcClient = CoreClient< + EndpointSet, + EndpointNotSet, + EndpointNotSet, + EndpointNotSet, + EndpointMaybeSet, + EndpointMaybeSet, +>; + +/// Represents the OIDC login state, which is stored in a cookie +#[derive(Debug, Deserialize, Serialize)] +struct OidcClientState { + pkce: String, + csrf: String, + nonce: String, +} + +/// Error response returned to the client when OIDC login fails +#[derive(Debug, rocket::Responder)] +#[response(status = 401)] +pub struct LoginFailed(String); + +impl From for LoginFailed { + fn from(e: LoginError) -> Self { + error!("Login failed: {}", e); + Self(e.to_string()) + } +} + +/// Create an openidconnect Client instance from the given Config +pub async fn get_oidc_client( + config: &Config, +) -> Result { + let http_client = reqwest::ClientBuilder::new() + .redirect(reqwest::redirect::Policy::none()) + .build() + .unwrap(); + let oidc_url = config.oidc.discovery_url.clone(); + let client_id = config.oidc.client_id.clone(); + let client_secret = config.oidc.client_secret.clone(); + let provider_metadata = CoreProviderMetadata::discover_async( + IssuerUrl::new(oidc_url)?, + &http_client, + ) + .await?; + Ok(CoreClient::from_provider_metadata( + provider_metadata, + ClientId::new(client_id), + client_secret.map(ClientSecret::new), + ) + .set_redirect_uri(RedirectUrl::new(config.oidc.callback_url.clone())?)) } /// Load the JWT secret from the path specified in the configuration @@ -81,10 +170,11 @@ pub fn load_secret(config: &Config) -> Result, std::io::Error> { Ok(secret) } +/// Extract a JWT from the Authorization HTTP request header fn extract_token( secret: &[u8], header: &str, -) -> Result, &'static str> { +) -> Result { let mut iter = header.split_ascii_whitespace(); let scheme = iter.next(); let token = iter.next(); @@ -92,23 +182,188 @@ fn extract_token( return Err("Unsupported authorization scheme"); } if let Some(token) = token { - let mut v = Validation::new(Algorithm::HS256); - v.validate_nbf = true; - v.set_issuer(&[env!("CARGO_PKG_NAME")]); - v.set_audience(&[env!("CARGO_PKG_NAME")]); - let k = DecodingKey::from_secret(secret); - match decode(token, &k, &v) { - Ok(d) => Ok(d), - Err(e) => { - error!("Failed to decode auth token: {}", e); - Err("Invalid token") - }, - } + Ok(UserClaims::from_jwt(token, secret).map_err(|e| { + error!("Failed to decode auth token: {}", e); + "Invalid token" + })?) } else { Err("Invalid Authorization header") } } +/// Get the authorization code from OIDC callback parameters +/// +/// If the callback indicates an authorization failure, or the OAuth2 +/// state is invalid, a [`LoginError`] is returned. +fn get_auth_code( + csrf_token: &str, + params: &HashMap, +) -> Result { + let state = params.get("state").ok_or(LoginError::MissingStateParam)?; + if state != csrf_token { + return Err(LoginError::InvalidCsrfState); + } + if let Some(error) = params.get("error") { + let msg = if let Some(err_desc) = params.get("error_description") { + format!("Error handling OIDC callback ({}): {}", error, err_desc) + } else { + format!("Error handling OIDC callback: {}", error) + }; + error!("{}", msg); + return Err(LoginError::IdpError(msg)); + } + Ok(params + .get("code") + .ok_or(LoginError::MissingAuthCode)? + .to_string()) +} + +/// Exchange an OIDC Authorization code for an Identity Token +async fn exchange_code( + code: String, + state: OidcClientState, + ctx: &Context, +) -> Result { + let pkce_verifier = PkceCodeVerifier::new(state.pkce); + debug!("Exchanging authorization code for access token"); + let http_client = reqwest::ClientBuilder::new() + .redirect(reqwest::redirect::Policy::none()) + .build() + .unwrap(); + let token_response = ctx + .oidc + .exchange_code(AuthorizationCode::new(code))? + .set_pkce_verifier(pkce_verifier) + .request_async(&http_client) + .await + .map_err(LoginError::TokenRequestError)?; + debug!( + "Received response token type {:?}", + token_response.token_type() + ); + debug!("Access token: {}", token_response.access_token().secret()); + trace!("Token response: {:?}", token_response); + + let id_token = token_response + .id_token() + .ok_or(LoginError::MissingIdToken)?; + let id_token_verifier = ctx.oidc.id_token_verifier(); + let claims = id_token + .claims(&ctx.oidc.id_token_verifier(), &Nonce::new(state.nonce))?; + if let Some(expected_access_token_hash) = claims.access_token_hash() { + let actual_access_token_hash = AccessTokenHash::from_token( + token_response.access_token(), + id_token.signing_alg()?, + id_token.signing_key(&id_token_verifier)?, + )?; + if actual_access_token_hash != *expected_access_token_hash { + return Err(LoginError::InvalidAccessToken); + } + } + Ok(claims.clone()) +} + +/// Initiate OpenID Connect login flow +#[rocket::get("/login")] +pub async fn oidc_login( + ctx: &State, + cookies: &CookieJar<'_>, + config: &RocketConfig, +) -> Redirect { + let (pkce_challenge, pkce_verifier) = + PkceCodeChallenge::new_random_sha256(); + trace!("PKCE: {:?} {:?}", pkce_challenge, pkce_verifier); + + let (auth_url, csrf_token, nonce) = ctx + .oidc + .authorize_url( + CoreAuthenticationFlow::AuthorizationCode, + CsrfToken::new_random, + Nonce::new_random, + ) + .set_pkce_challenge(pkce_challenge) + .add_scope(Scope::new("openid".into())) + .add_scope(Scope::new("profile".into())) + .add_scope(Scope::new("email".into())) + .add_scope(Scope::new("groups".into())) + .url(); + trace!( + "CSRF token: {}, nonce: {}", + csrf_token.secret(), + nonce.secret() + ); + let state = OidcClientState { + pkce: pkce_verifier.into_secret(), + csrf: csrf_token.into_secret(), + nonce: nonce.secret().to_string(), + }; + match rocket::serde::json::to_string(&state) { + Ok(s) => { + cookies.add_private( + Cookie::build(("oidc.state", s)) + .secure(config.profile != RocketConfig::DEBUG_PROFILE) + .same_site( + if config.profile == RocketConfig::DEBUG_PROFILE { + SameSite::Lax + } else { + SameSite::Strict + }, + ) + .http_only(true) + .expires(None) + .build(), + ); + }, + Err(e) => { + error!("Failed to serialize OIDC client state: {}", e); + }, + }; + Redirect::to(auth_url.to_string()) +} + +/// Handle OpenID Connect authorization callback +#[rocket::get("/oidc-callback?")] +pub async fn oidc_callback( + params: HashMap, + cookies: &CookieJar<'_>, + ctx: &State, + config: &State, +) -> Result { + trace!("{:?}", params); + let state = cookies + .get_private("oidc.state") + .inspect(|c| cookies.remove(c.clone())) + .ok_or(LoginError::MissingClientState)?; + let state: OidcClientState = rocket::serde::json::from_str(state.value()) + .map_err(|e| { + error!("Failed to parse OIDC client state: {}", e); + LoginError::InvalidClientState + })?; + let code = get_auth_code(&state.csrf, ¶ms)?; + trace!("Got authorization code: {}", code); + let claims = exchange_code(code, state, ctx).await?; + let user = + UserClaims::new(claims.subject().as_str(), config.auth.login_ttl); + let expires = OffsetDateTime::now_utc() + + Duration::seconds(config.auth.login_ttl.try_into().unwrap_or_else( + |e| { + warn!("Invalid login TTL value: {}", e); + i64::MAX + }, + )); + cookies.add( + Cookie::build(( + "auth.token", + ctx.make_jwt(&user).map_err(LoginError::from)?, + )) + .secure(true) + .http_only(true) + .expires(expires) + .build(), + ); + Ok(Redirect::to("/")) +} + #[cfg(test)] mod test { use super::*; @@ -139,8 +394,8 @@ mod test { }; let jwt = make_token(&claims); let header = format!("Bearer {}", jwt); - let data = extract_token(SECRET, &header).unwrap(); - assert_eq!(claims, data.claims); + let claims = extract_token(SECRET, &header).unwrap(); + assert_eq!(claims, claims); } #[test] @@ -233,4 +488,12 @@ mod test { let err = extract_token(SECRET, header).unwrap_err(); assert_eq!(err, "Unsupported authorization scheme"); } + + #[test] + fn test_userclaims_jwt_round_trip() { + let claims = UserClaims::new("test1", 60); + let jwt = claims.to_jwt(SECRET).unwrap(); + let claims1 = UserClaims::from_jwt(&jwt, SECRET).unwrap(); + assert_eq!(claims, claims1); + } } diff --git a/src/config.rs b/src/config.rs index ff93815..8470bef 100644 --- a/src/config.rs +++ b/src/config.rs @@ -14,14 +14,29 @@ pub struct MeilisearchConfig { #[derive(Debug, Deserialize)] pub struct AuthConfig { pub jwt_secret: PathBuf, + #[serde(default = "default_login_ttl")] + pub login_ttl: u64, +} + +#[derive(Debug, Deserialize)] +pub struct OidcConfig { + pub discovery_url: String, + pub client_id: String, + pub client_secret: Option, + pub callback_url: String, } #[derive(Debug, Deserialize)] pub struct Config { pub auth: AuthConfig, + pub oidc: OidcConfig, pub meilisearch: MeilisearchConfig, } fn default_index() -> String { env!("CARGO_PKG_NAME").into() } + +fn default_login_ttl() -> u64 { + 604800 +} diff --git a/src/error.rs b/src/error.rs index a7214b3..ff56d03 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,7 +1,66 @@ +use openidconnect::core::CoreErrorResponseType; +use openidconnect::url::ParseError; +use openidconnect::{ + ClaimsVerificationError, ConfigurationError, DiscoveryError, + HttpClientError, RequestTokenError, SignatureVerificationError, + SigningError, StandardErrorResponse, +}; + +#[derive(Debug, thiserror::Error)] +pub enum OidcError { + #[error("Invalid URL {0}")] + Url(#[from] ParseError), + #[error("OIDC Discovery failed: {0}")] + Discovery(#[from] DiscoveryError>), +} + +#[derive(Debug, thiserror::Error)] +pub enum LoginError { + #[error("Missing state parameter")] + MissingStateParam, + #[error("Invalid state parameter")] + InvalidCsrfState, + #[error("Missing OIDC client state cookie")] + MissingClientState, + #[error("Invalid OIDC client state cookie")] + InvalidClientState, + #[error("{0}")] + IdpError(String), + #[error("Missing OAuth2 authorization code")] + MissingAuthCode, + #[error("OIDC configuration error: {0}")] + ConfigurationError(#[from] ConfigurationError), + #[error("Token request error: {0}")] + TokenRequestError( + RequestTokenError< + HttpClientError, + StandardErrorResponse, + >, + ), + #[error("Server did not return an ID token")] + MissingIdToken, + #[error("Server returned an invalid ID token")] + InvalidIdToken, + #[error("Invalid token claims: {0}")] + ClaimsVerificationError(#[from] ClaimsVerificationError), + #[error("Signature verification error: {0}")] + SignatureVerificationError(#[from] SignatureVerificationError), + #[error("Token signature error: {0}")] + SigningError(#[from] SigningError), + #[error("Invalid access token")] + InvalidAccessToken, + #[error("JWT serialization error: {0}")] + JwtError(#[from] jsonwebtoken::errors::Error), +} + #[derive(Debug, thiserror::Error)] pub enum InitError { #[error("Meilisearch error: {0}")] Meilisearch(#[from] crate::meilisearch::Error), + #[error("Failed to load JWT secret: {0}")] LoadSecret(std::io::Error), + + #[error("Invalid OIDC configuration: {0}")] + Oidc(#[from] OidcError), } diff --git a/src/lib.rs b/src/lib.rs index 0c09d2a..42dd76a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,28 +15,39 @@ pub use error::InitError; pub struct Context { client: MeilisearchClient, jwt_secret: Vec, + oidc: auth::OidcClient, } impl Context { - pub fn init(config: &Config) -> Result { + pub async fn init(config: &Config) -> Result { let client = MeilisearchClient::try_from(config)?; let jwt_secret = auth::load_secret(config).map_err(InitError::LoadSecret)?; - Ok(Self { client, jwt_secret }) + let oidc = auth::get_oidc_client(config).await?; + Ok(Self { + client, + jwt_secret, + oidc, + }) } } /// Initialize the application context async fn init_context(rocket: Rocket) -> fairing::Result { let config: &Config = rocket.state().unwrap(); - let ctx = match Context::init(config) { + let ctx = match Context::init(config).await { Ok(c) => c, Err(e) => { eprintln!("Could not initialize application context: {}", e); return Err(rocket); }, }; - Ok(rocket.manage(ctx)) + // Use the JWT secret as the Rocket secret key, for encrypted cookies + let figment = rocket + .figment() + .clone() + .join(("secret_key", &ctx.jwt_secret)); + Ok(rocket.configure(figment).manage(ctx)) } /// Set up Meilisearch @@ -59,7 +70,14 @@ async fn meilisearch_setup(rocket: Rocket) -> fairing::Result { pub fn rocket() -> Rocket { rocket::build() - .mount("/", rocket::routes![page::post_page]) + .mount( + "/", + rocket::routes![ + auth::oidc_callback, + auth::oidc_login, + page::post_page + ], + ) .attach(AdHoc::config::()) .attach(AdHoc::try_on_ignite("Initialize context", init_context)) .attach(AdHoc::try_on_ignite("Meilisearch Setup", meilisearch_setup)) diff --git a/tests/integration/auth.rs b/tests/integration/auth.rs new file mode 100644 index 0000000..e499d68 --- /dev/null +++ b/tests/integration/auth.rs @@ -0,0 +1,84 @@ +use rocket::http::Status; +use rocket::local::asynchronous::Client; +use rocket::uri; +use scraper::{Html, Selector}; +use tracing::debug; + +use seensite::auth::*; +use seensite::Context; + +#[rocket::async_test] +async fn test_login() { + super::setup(); + + let client = Client::tracked(seensite::rocket()).await.unwrap(); + let dex = reqwest::Client::builder() + .redirect(reqwest::redirect::Policy::none()) + .cookie_store(true) + .build() + .unwrap(); + + let ctx: &Context = client.rocket().state().unwrap(); + + // First, initiate the login process + let req = client.get(uri![oidc_login]); + let res = req.dispatch().await; + assert_eq!(res.status(), Status::SeeOther); + let mut location = res.headers().get_one("Location").unwrap().to_string(); + + // Next, follow the redirect URL provided by the login page. + // This will redirect again. + let res = loop { + debug!("Redirect: {}", location); + let res = dex.get(location).send().await.unwrap(); + if res.status() == reqwest::StatusCode::FOUND { + let base_url = res.url().clone(); + location = base_url + .join(res.headers().get("Location").unwrap().to_str().unwrap()) + .unwrap() + .to_string(); + continue; + } + break res; + }; + + // After all the redirects, we end up on the IdP login form. + assert_eq!(res.status(), reqwest::StatusCode::OK); + // Obtain the login form target + let base_url = res.url().clone(); + let body = res.text().await; + let doc = Html::parse_fragment(&body.unwrap()); + let sel = Selector::parse("form").unwrap(); + let form = doc.select(&sel).next().unwrap(); + let action = form.attr("action").unwrap(); + let url = base_url.join(action).unwrap(); + // Post the user credentials to the IdP login form + let res = dex + .post(url) + .form(&[("login", "user@example.com"), ("password", "password")]) + .send() + .await + .unwrap(); + assert_eq!(res.status(), reqwest::StatusCode::SEE_OTHER); + + // The result of the IdP login form submission is another redirect + // to the OIDC callback of our application. + let location = reqwest::Url::parse( + res.headers().get("Location").unwrap().to_str().unwrap(), + ) + .unwrap(); + let callback = + format!("{}?{}", location.path(), location.query().unwrap()); + debug!("Callback: {}", callback); + + // Finally, make the callback request to finish the login process. + let res = client.get(callback).dispatch().await; + assert_eq!(res.status(), Status::SeeOther); + let location = res.headers().get_one("Location").unwrap().to_string(); + assert_eq!(location, "/"); + let cookie = res.cookies().get("auth.token").unwrap(); + debug!("Cookie: {:?}", cookie); + let claims = ctx.decode_jwt(cookie.value()).unwrap(); + debug!("Claims: {:?}", claims); + assert!(!claims.sub.is_empty()); +} diff --git a/tests/integration/main.rs b/tests/integration/main.rs index c40e682..f77932e 100644 --- a/tests/integration/main.rs +++ b/tests/integration/main.rs @@ -1 +1,22 @@ +mod auth; mod page; + +use std::sync::LazyLock; + +static SETUP: LazyLock<()> = LazyLock::new(|| { + tracing_subscriber::fmt() + .with_env_filter(tracing_subscriber::EnvFilter::new( + concat!( + env!("CARGO_PKG_NAME"), + "=trace,", + "seensite=trace,", + "debug", + ) + )) + .with_test_writer() + .init(); +}); + +fn setup() { + LazyLock::force(&SETUP); +} diff --git a/tests/integration/page.rs b/tests/integration/page.rs index f746807..64ce70e 100644 --- a/tests/integration/page.rs +++ b/tests/integration/page.rs @@ -31,6 +31,7 @@ amet auctor risus lacinia. Duis feugiat lobortis orci quis sagittis.

#[test] fn test_post_page() { + super::setup(); let client = Client::tracked(seensite::rocket()).unwrap(); let ctx: &Context = client.rocket().state().unwrap(); let claims = UserClaims::new("test1", 60); @@ -52,6 +53,7 @@ fn test_post_page() { #[test] fn test_post_page_unauth() { + super::setup(); let client = Client::tracked(seensite::rocket()).unwrap(); let data = Serializer::new(String::new()) .append_pair("url", TEST_URL)