diff --git a/Cargo.lock b/Cargo.lock index 0ce6491..498787a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,19 +4,13 @@ version = 3 [[package]] name = "addr2line" -version = "0.22.0" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" dependencies = [ "gimli", ] -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - [[package]] name = "adler2" version = "2.0.0" @@ -69,9 +63,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.15" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" dependencies = [ "anstyle", "anstyle-parse", @@ -84,49 +78,49 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.8" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "anstyle-parse" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.4" +version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" dependencies = [ "anstyle", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "anyhow" -version = "1.0.86" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" [[package]] name = "async-stream" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" dependencies = [ "async-stream-impl", "futures-core", @@ -135,24 +129,24 @@ dependencies = [ [[package]] name = "async-stream-impl" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn", ] [[package]] name = "async-trait" -version = "0.1.81" +version = "0.1.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" +checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn", ] [[package]] @@ -163,15 +157,15 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "autocfg" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "axum" -version = "0.7.5" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf" +checksum = "504e3947307ac8326a5437504c517c4b56716c9d98fac0028c2acc7ca47d70ae" dependencies = [ "async-trait", "axum-core", @@ -196,7 +190,7 @@ dependencies = [ "serde_urlencoded", "sync_wrapper 1.0.1", "tokio", - "tower", + "tower 0.5.1", "tower-layer", "tower-service", "tracing", @@ -204,9 +198,9 @@ dependencies = [ [[package]] name = "axum-client-ip" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72188bed20deb981f3a4a9fe674e5980fd9e9c2bd880baa94715ad5d60d64c67" +checksum = "9eefda7e2b27e1bda4d6fa8a06b50803b8793769045918bc37ad062d48a6efac" dependencies = [ "axum", "forwarded-header-value", @@ -215,9 +209,9 @@ dependencies = [ [[package]] name = "axum-core" -version = "0.4.3" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3" +checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" dependencies = [ "async-trait", "bytes", @@ -228,7 +222,7 @@ dependencies = [ "mime", "pin-project-lite", "rustversion", - "sync_wrapper 0.1.2", + "sync_wrapper 1.0.1", "tower-layer", "tower-service", "tracing", @@ -236,9 +230,9 @@ dependencies = [ [[package]] name = "axum-extra" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0be6ea09c9b96cb5076af0de2e383bd2bc0c18f827cf1967bdd353e0b910d733" +checksum = "73c3220b188aea709cf1b6c5f9b01c3bd936bb08bd2b5184a12b35ac8131b1f9" dependencies = [ "axum", "axum-core", @@ -252,7 +246,7 @@ dependencies = [ "mime", "pin-project-lite", "serde", - "tower", + "tower 0.5.1", "tower-layer", "tower-service", "tracing", @@ -260,29 +254,28 @@ dependencies = [ [[package]] name = "axum-macros" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00c055ee2d014ae5981ce1016374e8213682aa14d9bf40e48ab48b5f3ef20eaa" +checksum = "57d123550fa8d071b7255cb0cc04dc302baa6c8c4a79f55701552684d8399bce" dependencies = [ - "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.76", + "syn", ] [[package]] name = "backtrace" -version = "0.3.73" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ "addr2line", - "cc", "cfg-if", "libc", - "miniz_oxide 0.7.4", + "miniz_oxide", "object", "rustc-demangle", + "windows-targets", ] [[package]] @@ -336,15 +329,15 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.7.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" +checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" [[package]] name = "cc" -version = "1.1.14" +version = "1.1.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d2eb3cd3d1bf4529e31c215ee6f93ec5a3d536d9f578f93d9d33ee19562932" +checksum = "40545c26d092346d8a8dab71ee48e7685a7a9cba76e634790c215b41a4a7b4cf" dependencies = [ "jobserver", "libc", @@ -369,9 +362,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.16" +version = "4.5.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed6719fffa43d0d87e5fd8caeab59be1554fb028cd30edc88fc4369b17971019" +checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" dependencies = [ "clap_builder", "clap_derive", @@ -379,9 +372,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.15" +version = "4.5.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "216aec2b177652e3846684cbfe25c9964d18ec45234f0f5da5157b207ed1aab6" +checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" dependencies = [ "anstream", "anstyle", @@ -391,14 +384,14 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.13" +version = "4.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" dependencies = [ - "heck 0.5.0", + "heck", "proc-macro2", "quote", - "syn 2.0.76", + "syn", ] [[package]] @@ -409,9 +402,9 @@ checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" [[package]] name = "colorchoice" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "cookie" @@ -446,9 +439,9 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.13" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad" +checksum = "0ca741a962e1b0bff6d724a1a0958b686406e853bb14061f218562e1896f95e6" dependencies = [ "libc", ] @@ -509,7 +502,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.76", + "syn", ] [[package]] @@ -520,7 +513,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.76", + "syn", ] [[package]] @@ -579,33 +572,33 @@ dependencies = [ [[package]] name = "derive_builder" -version = "0.20.1" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd33f37ee6a119146a1781d3356a7c26028f83d779b2e04ecd45fdc75c76877b" +checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947" dependencies = [ "derive_builder_macro", ] [[package]] name = "derive_builder_core" -version = "0.20.1" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7431fa049613920234f22c47fdc33e6cf3ee83067091ea4277a3f8c4587aae38" +checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8" dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.76", + "syn", ] [[package]] name = "derive_builder_macro" -version = "0.20.1" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4abae7035bf79b9877b779505d8cf3749285b80c43941eda66604841889451dc" +checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" dependencies = [ "derive_builder_core", - "syn 2.0.76", + "syn", ] [[package]] @@ -618,6 +611,17 @@ dependencies = [ "crypto-common", ] +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "dotenvy" version = "0.15.7" @@ -648,9 +652,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" +checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" [[package]] name = "fixedbitset" @@ -660,12 +664,12 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "flate2" -version = "1.0.33" +version = "1.0.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "324a1be68054ef05ad64b861cc9eaf1d623d2d8cb25b4bf2cb9cdd902b4bf253" +checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" dependencies = [ "crc32fast", - "miniz_oxide 0.8.0", + "miniz_oxide", ] [[package]] @@ -695,9 +699,9 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", @@ -710,9 +714,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", "futures-sink", @@ -720,15 +724,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", @@ -737,32 +741,32 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-macro" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn", ] [[package]] name = "futures-sink" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-timer" @@ -772,9 +776,9 @@ checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-channel", "futures-core", @@ -809,18 +813,6 @@ dependencies = [ "wasi", ] -[[package]] -name = "getset" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e45727250e75cc04ff2846a66397da8ef2b3db8e40e0cef4df67950a07621eb9" -dependencies = [ - "proc-macro-error", - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "ghash" version = "0.5.1" @@ -833,9 +825,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.29.0" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "git2" @@ -852,15 +844,15 @@ dependencies = [ [[package]] name = "globset" -version = "0.4.14" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1" +checksum = "15f1ce686646e7f1e19bf7d5533fe443a45dbfb990e00629110797578b42fb19" dependencies = [ "aho-corasick", "bstr", "log", - "regex-automata 0.4.7", - "regex-syntax 0.8.4", + "regex-automata 0.4.9", + "regex-syntax 0.8.5", ] [[package]] @@ -895,7 +887,7 @@ dependencies = [ "futures-core", "futures-sink", "http", - "indexmap 2.4.0", + "indexmap 2.6.0", "slab", "tokio", "tokio-util", @@ -914,6 +906,12 @@ version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +[[package]] +name = "hashbrown" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" + [[package]] name = "headers" version = "0.4.0" @@ -938,12 +936,6 @@ dependencies = [ "http", ] -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - [[package]] name = "heck" version = "0.5.0" @@ -998,9 +990,9 @@ checksum = "08a397c49fec283e3d6211adbe480be95aae5f304cfb923e9970e08956d5168a" [[package]] name = "httparse" -version = "1.9.4" +version = "1.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" +checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" [[package]] name = "httpdate" @@ -1010,9 +1002,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" -version = "1.4.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" +checksum = "bbbff0a806a4728c99295b254c8838933b5b082d75e3cb70c8dab21fdfbcfa9a" dependencies = [ "bytes", "futures-channel", @@ -1031,9 +1023,9 @@ dependencies = [ [[package]] name = "hyper-timeout" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3203a961e5c83b6f5498933e78b6b263e208c197b63e9c6c53cc82ffd3f63793" +checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0" dependencies = [ "hyper", "hyper-util", @@ -1044,9 +1036,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.7" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cde7055719c54e36e95e8719f95883f22072a48ede39db7fc17a4e1d5281e9b9" +checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" dependencies = [ "bytes", "futures-channel", @@ -1057,11 +1049,128 @@ dependencies = [ "pin-project-lite", "socket2", "tokio", - "tower", "tower-service", "tracing", ] +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "ident_case" version = "1.0.1" @@ -1070,12 +1179,23 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "0.5.0" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "icu_normalizer", + "icu_properties", ] [[package]] @@ -1090,12 +1210,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.4.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ "equivalent", - "hashbrown 0.14.5", + "hashbrown 0.15.1", ] [[package]] @@ -1139,9 +1259,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.70" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" +checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" dependencies = [ "wasm-bindgen", ] @@ -1154,9 +1274,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.158" +version = "0.2.162" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" +checksum = "18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398" [[package]] name = "libgit2-sys" @@ -1188,6 +1308,12 @@ version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +[[package]] +name = "litemap" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704" + [[package]] name = "lock_api" version = "0.4.12" @@ -1244,15 +1370,6 @@ dependencies = [ "unicase", ] -[[package]] -name = "miniz_oxide" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" -dependencies = [ - "adler", -] - [[package]] name = "miniz_oxide" version = "0.8.0" @@ -1325,18 +1442,18 @@ dependencies = [ [[package]] name = "object" -version = "0.36.3" +version = "0.36.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27b64972346851a39438c60b341ebc01bba47464ae329e55cf343eb93964efd9" +checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.19.0" +version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "opaque-debug" @@ -1392,34 +1509,34 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset", - "indexmap 2.4.0", + "indexmap 2.6.0", ] [[package]] name = "pin-project" -version = "1.1.5" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +checksum = "be57f64e946e500c8ee36ef6331845d40a93055567ec57e8fae13efd33759b95" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.5" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn", ] [[package]] name = "pin-project-lite" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" [[package]] name = "pin-utils" @@ -1429,9 +1546,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "polyval" @@ -1447,9 +1564,9 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.7.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da544ee218f0d287a911e9c99a39a8c9bc8fcad3cb8db5959940044ecfc67265" +checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2" [[package]] name = "powerfmt" @@ -1468,52 +1585,28 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.2.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479cf940fbbb3426c32c5d5176f62ad57549a0bb84773423ba8be9d089f5faba" -dependencies = [ - "proc-macro2", - "syn 2.0.76", -] - -[[package]] -name = "proc-macro-error" -version = "1.0.4" +version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033" dependencies = [ - "proc-macro-error-attr", "proc-macro2", - "quote", - "syn 1.0.109", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", + "syn", ] [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" dependencies = [ "unicode-ident", ] [[package]] name = "prost" -version = "0.13.1" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13db3d3fde688c61e2446b4d843bc27a7e8af269a69440c0308021dc92333cc" +checksum = "7b0487d90e047de87f984913713b85c601c05609aad5b0df4b4573fbf69aa13f" dependencies = [ "bytes", "prost-derive", @@ -1521,12 +1614,12 @@ dependencies = [ [[package]] name = "prost-build" -version = "0.13.1" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bb182580f71dd070f88d01ce3de9f4da5021db7115d2e1c3605a754153b77c1" +checksum = "0c1318b19085f08681016926435853bbf7858f9c082d0999b80550ff5d9abe15" dependencies = [ "bytes", - "heck 0.5.0", + "heck", "itertools", "log", "multimap", @@ -1536,28 +1629,28 @@ dependencies = [ "prost", "prost-types", "regex", - "syn 2.0.76", + "syn", "tempfile", ] [[package]] name = "prost-derive" -version = "0.13.1" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18bec9b0adc4eba778b33684b7ba3e7137789434769ee3ce3930463ef904cfca" +checksum = "e9552f850d5f0964a4e4d0bf306459ac29323ddfbae05e35a7c0d35cb0803cc5" dependencies = [ "anyhow", "itertools", "proc-macro2", "quote", - "syn 2.0.76", + "syn", ] [[package]] name = "prost-types" -version = "0.13.1" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cee5168b05f49d4b0ca581206eb14a7b22fafd963efe729ac48eb03266e25cc2" +checksum = "4759aa0d3a6232fb8dbdb97b61de2c20047c68aca932c7ed76da9d788508d670" dependencies = [ "prost", ] @@ -1618,32 +1711,32 @@ dependencies = [ [[package]] name = "raw-cpuid" -version = "11.1.0" +version = "11.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb9ee317cfe3fbd54b36a511efc1edd42e216903c9cd575e686dd68a2ba90d8d" +checksum = "1ab240315c661615f2ee9f0f2cd32d5a7343a84d5ebcccb99d46e6637565e7b0" dependencies = [ "bitflags", ] [[package]] name = "redox_syscall" -version = "0.5.3" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" +checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" dependencies = [ "bitflags", ] [[package]] name = "regex" -version = "1.10.6" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.7", - "regex-syntax 0.8.4", + "regex-automata 0.4.9", + "regex-syntax 0.8.5", ] [[package]] @@ -1657,13 +1750,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.4", + "regex-syntax 0.8.5", ] [[package]] @@ -1674,9 +1767,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "ring" @@ -1713,7 +1806,7 @@ dependencies = [ "proc-macro2", "quote", "rust-embed-utils", - "syn 2.0.76", + "syn", "walkdir", ] @@ -1736,9 +1829,9 @@ checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustix" -version = "0.38.34" +version = "0.38.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +checksum = "99e4ea3e1cdc4b559b8e5650f9c8e5998e3e5c1343b4eaf034565f32318d63c0" dependencies = [ "bitflags", "errno", @@ -1749,9 +1842,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.12" +version = "0.23.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c58f8c84392efc0a126acce10fa59ff7b3d2ac06ab451a33f2741989b806b044" +checksum = "eee87ff5d9b36712a58574e12e9f0ea80f915a5b0ac518d322b24a465617925e" dependencies = [ "log", "once_cell", @@ -1764,9 +1857,9 @@ dependencies = [ [[package]] name = "rustls-native-certs" -version = "0.7.2" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04182dffc9091a404e0fc069ea5cd60e5b866c3adf881eff99a32d048242dffa" +checksum = "fcaf18a4f2be7326cd874a5fa579fae794320a0f388d365dca7e480e55f83f8a" dependencies = [ "openssl-probe", "rustls-pemfile", @@ -1777,25 +1870,24 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "2.1.3" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "196fe16b00e106300d3e45ecfcb764fa292a535d7326a29a5875c579c7417425" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" dependencies = [ - "base64 0.22.1", "rustls-pki-types", ] [[package]] name = "rustls-pki-types" -version = "1.8.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0" +checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" [[package]] name = "rustls-webpki" -version = "0.102.6" +version = "0.102.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e6b52d4fda176fd835fdc55a835d4a89b8499cad995885a21149d5ad62f852e" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" dependencies = [ "ring", "rustls-pki-types", @@ -1804,9 +1896,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" +checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" [[package]] name = "ryu" @@ -1825,11 +1917,11 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.23" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +checksum = "01227be5826fa0690321a2ba6c5cd57a19cf3f6a09e76973b58e61de6ab9d1c1" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -1853,9 +1945,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.11.1" +version = "2.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75da29fe9b9b08fe9d6b22b5b4bcbc75d8db3aa31e639aa56bb62e9d46bfceaf" +checksum = "fa39c7303dc58b5543c94d22c1766b0d31f2ee58306363ea622b10bbc075eaa2" dependencies = [ "core-foundation-sys", "libc", @@ -1863,29 +1955,29 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.209" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99fce0ffe7310761ca6bf9faf5115afbc19688edd00171d81b1bb1b116c63e09" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.209" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn", ] [[package]] name = "serde_json" -version = "1.0.127" +version = "1.0.132" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8043c06d9f82bd7271361ed64f415fe5e12a77fdb52e573e7f06a516dea329ad" +checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" dependencies = [ "itoa", "memchr", @@ -1905,9 +1997,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.7" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" dependencies = [ "serde", ] @@ -2001,6 +2093,12 @@ dependencies = [ "lock_api", ] +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "strsim" version = "0.11.1" @@ -2015,20 +2113,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.76" +version = "2.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578e081a14e0cefc3279b0472138c513f37b41a08d5a3cca9b6e4e8ceb6cd525" +checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" dependencies = [ "proc-macro2", "quote", @@ -2047,11 +2134,22 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "tempfile" -version = "3.12.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" +checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" dependencies = [ "cfg-if", "fastrand", @@ -2062,22 +2160,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.63" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.63" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn", ] [[package]] @@ -2124,25 +2222,20 @@ dependencies = [ ] [[package]] -name = "tinyvec" -version = "1.8.0" +name = "tinystr" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" dependencies = [ - "tinyvec_macros", + "displaydoc", + "zerovec", ] -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - [[package]] name = "tokio" -version = "1.39.3" +version = "1.41.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9babc99b9923bfa4804bd74722ff02c0381021eafa4db9949217e3be8e84fff5" +checksum = "22cfb5bee7a6a52939ca9224d6ac897bb669134078daa8735560897f69de4d33" dependencies = [ "backtrace", "bytes", @@ -2162,7 +2255,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn", ] [[package]] @@ -2178,9 +2271,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.15" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" +checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1" dependencies = [ "futures-core", "pin-project-lite", @@ -2189,9 +2282,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.11" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" dependencies = [ "bytes", "futures-core", @@ -2223,11 +2316,11 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.20" +version = "0.22.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ - "indexmap 2.4.0", + "indexmap 2.6.0", "serde", "serde_spanned", "toml_datetime", @@ -2236,9 +2329,9 @@ dependencies = [ [[package]] name = "tonic" -version = "0.12.1" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38659f4a91aba8598d27821589f5db7dddd94601e7a01b1e485a50e5484c7401" +checksum = "877c5b330756d856ffcc4553ab34a5684481ade925ecc54bcd1bf02b1d0d4d52" dependencies = [ "async-stream", "async-trait", @@ -2262,7 +2355,7 @@ dependencies = [ "tokio", "tokio-rustls", "tokio-stream", - "tower", + "tower 0.4.13", "tower-layer", "tower-service", "tracing", @@ -2270,15 +2363,16 @@ dependencies = [ [[package]] name = "tonic-build" -version = "0.12.1" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "568392c5a2bd0020723e3f387891176aabafe36fd9fcd074ad309dfa0c8eb964" +checksum = "9557ce109ea773b399c9b9e5dca39294110b74f1f342cb347a80d1fce8c26a11" dependencies = [ "prettyplease", "proc-macro2", "prost-build", + "prost-types", "quote", - "syn 2.0.76", + "syn", ] [[package]] @@ -2301,6 +2395,22 @@ dependencies = [ "tracing", ] +[[package]] +name = "tower" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2873938d487c3cfb9aed7546dc9f2711d867c9f90c46b889989a2cb84eba6b4f" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper 0.1.2", + "tokio", + "tower-layer", + "tower-service", + "tracing", +] + [[package]] name = "tower-http" version = "0.5.2" @@ -2340,9 +2450,9 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tower_governor" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "313fa625fea5790ed56360a30ea980e41229cf482b4835801a67ef1922bf63b9" +checksum = "aea939ea6cfa7c4880f3e7422616624f97a567c16df67b53b11f0d03917a8e46" dependencies = [ "axum", "forwarded-header-value", @@ -2350,7 +2460,7 @@ dependencies = [ "http", "pin-project", "thiserror", - "tower", + "tower 0.5.1", "tracing", ] @@ -2374,7 +2484,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn", ] [[package]] @@ -2430,33 +2540,15 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "unicase" -version = "2.7.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" -dependencies = [ - "version_check", -] - -[[package]] -name = "unicode-bidi" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" +checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" [[package]] name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "unicode-normalization" -version = "0.1.23" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" -dependencies = [ - "tinyvec", -] +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "universal-hash" @@ -2476,15 +2568,28 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.2" +version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" +checksum = "8d157f1b96d14500ffdc1f10ba712e780825526c03d9a49b4d0324b0d9113ada" dependencies = [ "form_urlencoded", "idna", "percent-encoding", + "serde", ] +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + [[package]] name = "utf8parse" version = "0.2.2" @@ -2505,9 +2610,9 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "vergen" -version = "9.0.0" +version = "9.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c32e7318e93a9ac53693b6caccfb05ff22e04a44c7cf8a279051f24c09da286f" +checksum = "349ed9e45296a581f455bc18039878f409992999bc1d5da12a6800eb18c8752f" dependencies = [ "anyhow", "derive_builder", @@ -2518,9 +2623,9 @@ dependencies = [ [[package]] name = "vergen-git2" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62c52cd2b2b8b7ec75fc20111b3022ac3ff83e4fc14b9497cfcfd39c54f9c67" +checksum = "e771aff771c0d7c2f42e434e2766d304d917e29b40f0424e8faaaa936bbc3f29" dependencies = [ "anyhow", "derive_builder", @@ -2533,13 +2638,12 @@ dependencies = [ [[package]] name = "vergen-lib" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e06bee42361e43b60f363bad49d63798d0f42fb1768091812270eca00c784720" +checksum = "229eaddb0050920816cf051e619affaf18caa3dd512de8de5839ccbc8e53abb0" dependencies = [ "anyhow", "derive_builder", - "getset", "rustversion", ] @@ -2576,9 +2680,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" +checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" dependencies = [ "cfg-if", "once_cell", @@ -2587,24 +2691,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" +checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.76", + "syn", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" +checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2612,28 +2716,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" +checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" +checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" [[package]] name = "web-sys" -version = "0.3.70" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" +checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112" dependencies = [ "js-sys", "wasm-bindgen", @@ -2754,13 +2858,49 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.6.18" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" dependencies = [ "memchr", ] +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + +[[package]] +name = "yoke" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c5b1314b079b0930c31e3af543d8ee1757b1951ae1e1565ec704403a7240ca5" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + [[package]] name = "zerocopy" version = "0.7.35" @@ -2779,7 +2919,28 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn", +] + +[[package]] +name = "zerofrom" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ec111ce797d0e0784a1116d0ddcdbea84322cd79e5d5ad173daeba4f93ab55" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", ] [[package]] @@ -2787,3 +2948,25 @@ name = "zeroize" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" + +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/Cargo.toml b/Cargo.toml index b0ca2ad..8edcfde 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,7 +38,7 @@ anyhow = "1.0" clap = { version = "4.5", features = ["derive", "env", "cargo"] } # other utils dotenvy = "0.15" -url = "2.5" +url = { version = "2.5", features = ["serde"] } tower_governor = "0.4" # UI embedding rust-embed = { version = "8.5", features = ["include-exclude"] } diff --git a/build.rs b/build.rs index 8eb4a15..ea2f9ad 100644 --- a/build.rs +++ b/build.rs @@ -11,7 +11,7 @@ fn main() -> Result<(), Box> { config.protoc_arg("--experimental_allow_proto3_optional"); // Make all messages serde-serializable config.type_attribute(".", "#[derive(serde::Serialize,serde::Deserialize)]"); - tonic_build::configure().compile_with_config( + tonic_build::configure().compile_protos_with_config( config, &["proto/core/proxy.proto"], &["proto/core"], diff --git a/proto b/proto index 8309982..b9adb0b 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit 8309982b94e82a7cbe39dd529967f43e49b3ef1d +Subproject commit b9adb0bc87228c88c42f144caa47c8b69a3fb98c diff --git a/src/config.rs b/src/config.rs index 994cdf7..b1dcd5e 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,8 +1,9 @@ -use std::{fs, io::Error as IoError}; +use std::{fs::read_to_string, path::PathBuf}; use clap::Parser; use log::LevelFilter; use serde::Deserialize; +use url::Url; #[derive(Parser, Debug, Deserialize)] #[command(version)] @@ -35,16 +36,24 @@ pub struct Config { #[arg(long, env = "DEFGUARD_PROXY_RATELIMIT_BURST", default_value_t = 0)] pub rate_limit_burst: u32, + #[arg( + long, + env = "DEFGUARD_PROXY_URL", + value_parser = Url::parse, + default_value = "http://localhost:8080" + )] + pub url: Url, + /// Configuration file path #[arg(long = "config", short)] #[serde(skip)] - config_path: Option, + config_path: Option, } #[derive(thiserror::Error, Debug)] pub enum ConfigError { #[error("Failed to read config file")] - IoError(#[from] IoError), + IoError(#[from] std::io::Error), #[error("Failed to parse config file")] ParseError(#[from] toml::de::Error), } @@ -55,11 +64,11 @@ pub fn get_config() -> Result { // load config from file if one was specified if let Some(config_path) = cli_config.config_path { - info!("Reading configuration from config file: {config_path:?}"); - let config_toml = fs::read_to_string(config_path)?; + info!("Reading configuration from file: {config_path:?}"); + let config_toml = read_to_string(config_path)?; let file_config: Config = toml::from_str(&config_toml)?; - return Ok(file_config); + Ok(file_config) + } else { + Ok(cli_config) } - - Ok(cli_config) } diff --git a/src/enterprise/handlers/mod.rs b/src/enterprise/handlers/mod.rs new file mode 100644 index 0000000..3e4fa9f --- /dev/null +++ b/src/enterprise/handlers/mod.rs @@ -0,0 +1 @@ +pub mod openid_login; diff --git a/src/enterprise/handlers/openid_login.rs b/src/enterprise/handlers/openid_login.rs new file mode 100644 index 0000000..cdf07d8 --- /dev/null +++ b/src/enterprise/handlers/openid_login.rs @@ -0,0 +1,147 @@ +use axum::{ + extract::State, + routing::{get, post}, + Json, Router, +}; +use axum_extra::extract::{ + cookie::{Cookie, SameSite}, + PrivateCookieJar, +}; +use serde::{Deserialize, Serialize}; +use time::Duration; + +use crate::{ + error::ApiError, + handlers::get_core_response, + http::AppState, + proto::{ + core_request, core_response, AuthCallbackRequest, AuthCallbackResponse, AuthInfoRequest, + }, +}; + +const COOKIE_MAX_AGE: Duration = Duration::days(1); +static CSRF_COOKIE_NAME: &str = "csrf"; +static NONCE_COOKIE_NAME: &str = "nonce"; + +pub(crate) fn router() -> Router { + Router::new() + .route("/auth_info", get(auth_info)) + .route("/callback", post(auth_callback)) +} + +#[derive(Serialize)] +struct AuthInfo { + url: String, + button_display_name: Option, +} + +impl AuthInfo { + #[must_use] + fn new(url: String, button_display_name: Option) -> Self { + Self { + url, + button_display_name, + } + } +} + +/// Request external OAuth2/OpenID provider details from Defguard Core. +#[instrument(level = "debug", skip(state))] +async fn auth_info( + State(state): State, + private_cookies: PrivateCookieJar, +) -> Result<(PrivateCookieJar, Json), ApiError> { + debug!("Getting auth info for OAuth2/OpenID login"); + + let request = AuthInfoRequest { + redirect_url: state.callback_url().to_string(), + }; + + let rx = state + .grpc_server + .send(Some(core_request::Payload::AuthInfo(request)), None)?; + let payload = get_core_response(rx).await?; + if let core_response::Payload::AuthInfo(response) = payload { + debug!("Received auth info {response:?}"); + + let nonce_cookie = Cookie::build((NONCE_COOKIE_NAME, response.nonce)) + // .domain(cookie_domain) + .path("/api/v1/openid/callback") + .http_only(true) + .same_site(SameSite::Strict) + .secure(true) + .max_age(COOKIE_MAX_AGE) + .build(); + let csrf_cookie = Cookie::build((CSRF_COOKIE_NAME, response.csrf_token)) + // .domain(cookie_domain) + .path("/api/v1/openid/callback") + .http_only(true) + .same_site(SameSite::Strict) + .secure(true) + .max_age(COOKIE_MAX_AGE) + .build(); + let private_cookies = private_cookies.add(nonce_cookie).add(csrf_cookie); + + let auth_info = AuthInfo::new(response.url, response.button_display_name); + Ok((private_cookies, Json(auth_info))) + } else { + error!("Received invalid gRPC response type: {payload:#?}"); + Err(ApiError::InvalidResponseType) + } +} + +#[derive(Debug, Deserialize)] +pub struct AuthenticationResponse { + code: String, + state: String, +} + +#[derive(Serialize)] +struct CallbackResponseData { + url: String, + token: String, +} + +#[instrument(level = "debug", skip(state))] +async fn auth_callback( + State(state): State, + mut private_cookies: PrivateCookieJar, + Json(payload): Json, +) -> Result<(PrivateCookieJar, Json), ApiError> { + let nonce = private_cookies + .get(NONCE_COOKIE_NAME) + .ok_or(ApiError::Unauthorized("Nonce cookie not found".into()))? + .value_trimmed() + .to_string(); + let csrf = private_cookies + .get(CSRF_COOKIE_NAME) + .ok_or(ApiError::Unauthorized("CSRF cookie not found".into()))? + .value_trimmed() + .to_string(); + + if payload.state != csrf { + return Err(ApiError::Unauthorized("CSRF token mismatch".into())); + } + + private_cookies = private_cookies + .remove(Cookie::from(NONCE_COOKIE_NAME)) + .remove(Cookie::from(CSRF_COOKIE_NAME)); + + let request = AuthCallbackRequest { + code: payload.code, + nonce, + callback_url: state.callback_url().to_string(), + }; + + let rx = state + .grpc_server + .send(Some(core_request::Payload::AuthCallback(request)), None)?; + let payload = get_core_response(rx).await?; + if let core_response::Payload::AuthCallback(AuthCallbackResponse { url, token }) = payload { + debug!("Received auth callback response {url:?} {token:?}"); + Ok((private_cookies, Json(CallbackResponseData { url, token }))) + } else { + error!("Received invalid gRPC response type during handling the OpenID authentication callback: {payload:#?}"); + Err(ApiError::InvalidResponseType) + } +} diff --git a/src/enterprise/mod.rs b/src/enterprise/mod.rs new file mode 100644 index 0000000..c3d4495 --- /dev/null +++ b/src/enterprise/mod.rs @@ -0,0 +1 @@ +pub mod handlers; diff --git a/src/grpc.rs b/src/grpc.rs index 3f31eca..ef98dab 100644 --- a/src/grpc.rs +++ b/src/grpc.rs @@ -30,7 +30,7 @@ pub(crate) struct ProxyServer { impl ProxyServer { #[must_use] /// Create new `ProxyServer`. - pub fn new() -> Self { + pub(crate) fn new() -> Self { Self { current_id: Arc::new(AtomicU64::new(1)), clients: Arc::new(Mutex::new(HashMap::new())), @@ -42,7 +42,7 @@ impl ProxyServer { /// Sends message to the other side of RPC, with given `payload` and optional `device_info`. /// Returns `tokio::sync::oneshot::Reveicer` to let the caller await reply. #[instrument(name = "send_grpc_message", level = "debug", skip(self))] - pub fn send( + pub(crate) fn send( &self, payload: Option, device_info: Option, @@ -64,9 +64,11 @@ impl ProxyServer { self.connected.store(true, Ordering::Relaxed); Ok(rx) } else { - error!("Defguard core is disconnected"); + error!("Defguard Core is not connected"); self.connected.store(false, Ordering::Relaxed); - Err(ApiError::Unexpected("Defguard core is disconnected".into())) + Err(ApiError::Unexpected( + "Defguard Core is not connected".into(), + )) } } } @@ -96,7 +98,7 @@ impl proxy_server::Proxy for ProxyServer { error!("Failed to determine client address for request: {request:?}"); return Err(Status::internal("Failed to determine client address")); }; - info!("Defguard core RPC client connected from: {address}"); + info!("Defguard Core gRPC client connected from: {address}"); let (tx, rx) = mpsc::unbounded_channel(); self.clients.lock().unwrap().insert(address, tx); diff --git a/src/handlers/enrollment.rs b/src/handlers/enrollment.rs index bb8d5da..fc30752 100644 --- a/src/handlers/enrollment.rs +++ b/src/handlers/enrollment.rs @@ -12,7 +12,7 @@ use crate::{ }, }; -pub fn router() -> Router { +pub(crate) fn router() -> Router { Router::new() .route("/start", post(start_enrollment_process)) .route("/activate_user", post(activate_user)) @@ -21,7 +21,7 @@ pub fn router() -> Router { } #[instrument(level = "debug", skip(state))] -pub async fn start_enrollment_process( +async fn start_enrollment_process( State(state): State, mut private_cookies: PrivateCookieJar, Json(req): Json, @@ -60,7 +60,7 @@ pub async fn start_enrollment_process( } #[instrument(level = "debug", skip(state))] -pub async fn activate_user( +async fn activate_user( State(state): State, device_info: Option, mut private_cookies: PrivateCookieJar, @@ -95,7 +95,7 @@ pub async fn activate_user( } #[instrument(level = "debug", skip(state))] -pub async fn create_device( +async fn create_device( State(state): State, device_info: Option, private_cookies: PrivateCookieJar, @@ -123,7 +123,7 @@ pub async fn create_device( } #[instrument(level = "debug", skip(state))] -pub async fn get_network_info( +async fn get_network_info( State(state): State, private_cookies: PrivateCookieJar, Json(mut req): Json, diff --git a/src/handlers/mod.rs b/src/handlers/mod.rs index 4d77261..e73a208 100644 --- a/src/handlers/mod.rs +++ b/src/handlers/mod.rs @@ -4,6 +4,7 @@ use axum::{extract::FromRequestParts, http::request::Parts}; use axum_client_ip::{InsecureClientIp, LeftmostXForwardedFor}; use axum_extra::{headers::UserAgent, TypedHeader}; use tokio::{sync::oneshot::Receiver, time::timeout}; +use tonic::Code; use super::proto::DeviceInfo; use crate::{error::ApiError, proto::core_response::Payload}; @@ -13,8 +14,8 @@ pub(crate) mod enrollment; pub(crate) mod password_reset; pub(crate) mod polling; -// timeout in seconds for awaiting core response -const CORE_RESPONSE_TIMEOUT: u64 = 5; +// Timeout for awaiting response from Defguard Core. +const CORE_RESPONSE_TIMEOUT: Duration = Duration::from_secs(5); #[tonic::async_trait] impl FromRequestParts for DeviceInfo @@ -47,11 +48,17 @@ where /// Helper which awaits core response /// /// Waits for core response with a given timeout and returns the response payload. -async fn get_core_response(rx: Receiver) -> Result { +pub(crate) async fn get_core_response(rx: Receiver) -> Result { debug!("Fetching core response..."); - if let Ok(core_response) = timeout(Duration::from_secs(CORE_RESPONSE_TIMEOUT), rx).await { + if let Ok(core_response) = timeout(CORE_RESPONSE_TIMEOUT, rx).await { debug!("Got gRPC response from Defguard core: {core_response:?}"); if let Ok(Payload::CoreError(core_error)) = core_response { + if core_error.status_code == Code::FailedPrecondition as i32 + && core_error.message == "no valid license" + { + debug!("Tried to get core response related to an enterprise feature but the enterprise is not enabled, ignoring it..."); + return Err(ApiError::EnterpriseNotEnabled); + } error!( "Received an error response from the core service. | status code: {} message: {}", core_error.status_code, core_error.message @@ -61,7 +68,7 @@ async fn get_core_response(rx: Receiver) -> Result { core_response .map_err(|err| ApiError::Unexpected(format!("Failed to receive core response: {err}"))) } else { - error!("Did not receive core response within {CORE_RESPONSE_TIMEOUT} seconds"); + error!("Did not receive core response within {CORE_RESPONSE_TIMEOUT:?}"); Err(ApiError::CoreTimeout) } } diff --git a/src/handlers/password_reset.rs b/src/handlers/password_reset.rs index dea6d61..9062405 100644 --- a/src/handlers/password_reset.rs +++ b/src/handlers/password_reset.rs @@ -12,7 +12,7 @@ use crate::{ }, }; -pub fn router() -> Router { +pub(crate) fn router() -> Router { Router::new() .route("/request", post(request_password_reset)) .route("/start", post(start_password_reset)) @@ -20,7 +20,7 @@ pub fn router() -> Router { } #[instrument(level = "debug", skip(state))] -pub async fn request_password_reset( +async fn request_password_reset( State(state): State, device_info: Option, Json(req): Json, @@ -42,7 +42,7 @@ pub async fn request_password_reset( } #[instrument(level = "debug", skip(state))] -pub async fn start_password_reset( +async fn start_password_reset( State(state): State, device_info: Option, mut private_cookies: PrivateCookieJar, @@ -77,7 +77,7 @@ pub async fn start_password_reset( } #[instrument(level = "debug", skip(state))] -pub async fn reset_password( +async fn reset_password( State(state): State, device_info: Option, mut private_cookies: PrivateCookieJar, diff --git a/src/handlers/polling.rs b/src/handlers/polling.rs index 3820196..d4abfa0 100644 --- a/src/handlers/polling.rs +++ b/src/handlers/polling.rs @@ -8,7 +8,7 @@ use crate::{ }; #[instrument(level = "debug", skip(state))] -pub async fn info( +pub(crate) async fn info( State(state): State, Json(req): Json, ) -> Result, ApiError> { diff --git a/src/http.rs b/src/http.rs index a6be8d3..e2a0e86 100644 --- a/src/http.rs +++ b/src/http.rs @@ -23,10 +23,12 @@ use tower_governor::{ }; use tower_http::trace::{self, TraceLayer}; use tracing::{info_span, Level}; +use url::Url; use crate::{ assets::{index, svg, web_asset}, config::Config, + enterprise::handlers::openid_login, error::ApiError, grpc::ProxyServer, handlers::{desktop_client_mfa, enrollment, password_reset, polling}, @@ -41,6 +43,20 @@ const RATE_LIMITER_CLEANUP_PERIOD: Duration = Duration::from_secs(60); pub(crate) struct AppState { pub(crate) grpc_server: ProxyServer, key: Key, + url: Url, +} + +impl AppState { + /// Returns configured URL with "auth/callback" appended to the path. + #[must_use] + pub(crate) fn callback_url(&self) -> Url { + let mut url = self.url.clone(); + // Append "/openid/callback" to the URL. + if let Ok(mut path_segments) = url.path_segments_mut() { + path_segments.extend(&["openid", "callback"]); + } + url + } } impl FromRef for Key { @@ -71,7 +87,10 @@ async fn healthcheckgrpc(State(state): State) -> (StatusCode, &'static if state.grpc_server.connected.load(Ordering::Relaxed) { (StatusCode::OK, "Alive") } else { - (StatusCode::SERVICE_UNAVAILABLE, "Not connected to core") + ( + StatusCode::SERVICE_UNAVAILABLE, + "Not connected to Defguard Core", + ) } } @@ -95,7 +114,7 @@ fn get_client_addr(request: &Request) -> String { } pub async fn run_server(config: Config) -> anyhow::Result<()> { - info!("Starting Defguard proxy server"); + info!("Starting Defguard Proxy server"); debug!("Using config: {config:?}"); let mut tasks = JoinSet::new(); @@ -109,9 +128,10 @@ pub async fn run_server(config: Config) -> anyhow::Result<()> { grpc_server: grpc_server.clone(), // Generate secret key for encrypting cookies. key: Key::generate(), + url: config.url.clone(), }; - // read gRPC TLS cert and key + // Read gRPC TLS certificate and key. debug!("Configuring certificates for gRPC"); let grpc_cert = config .grpc_cert @@ -121,7 +141,7 @@ pub async fn run_server(config: Config) -> anyhow::Result<()> { .grpc_key .as_ref() .and_then(|path| read_to_string(path).ok()); - debug!("Configured certificates for gRPC, cert: {grpc_cert:?}"); + debug!("Configured gRPC certificate: {grpc_cert:?}"); // Start gRPC server. debug!("Spawning gRPC server"); @@ -159,7 +179,7 @@ pub async fn run_server(config: Config) -> anyhow::Result<()> { tokio::spawn(async move { loop { tokio::time::sleep(RATE_LIMITER_CLEANUP_PERIOD).await; - tracing::debug!( + debug!( "Cleaning-up rate limiter storage, current size: {}", governor_limiter.len() ); @@ -188,6 +208,7 @@ pub async fn run_server(config: Config) -> anyhow::Result<()> { .nest("/enrollment", enrollment::router()) .nest("/password-reset", password_reset::router()) .nest("/client-mfa", desktop_client_mfa::router()) + .nest("/openid", openid_login::router()) .route("/poll", post(polling::info)) .route("/health", get(healthcheck)) .route("/health-grpc", get(healthcheckgrpc)) @@ -231,7 +252,7 @@ pub async fn run_server(config: Config) -> anyhow::Result<()> { .context("Error running HTTP server") }); - info!("Defguard proxy server initialization complete"); + info!("Defguard Proxy server initialization complete"); while let Some(Ok(result)) = tasks.join_next().await { result?; } diff --git a/src/lib.rs b/src/lib.rs index d098454..7384779 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,6 @@ pub mod assets; pub mod config; +mod enterprise; mod error; mod grpc; mod handlers; @@ -13,4 +14,4 @@ pub(crate) mod proto { #[macro_use] extern crate tracing; -pub const VERSION: &str = concat!(env!("CARGO_PKG_VERSION"), "-", env!("VERGEN_GIT_SHA")); +pub static VERSION: &str = concat!(env!("CARGO_PKG_VERSION"), "-", env!("VERGEN_GIT_SHA")); diff --git a/web/src/components/App/App.tsx b/web/src/components/App/App.tsx index e7d0289..e3a7166 100644 --- a/web/src/components/App/App.tsx +++ b/web/src/components/App/App.tsx @@ -18,6 +18,7 @@ import { detectLocale } from '../../i18n/i18n-util'; import { loadLocaleAsync } from '../../i18n/i18n-util.async'; import { EnrollmentPage } from '../../pages/enrollment/EnrollmentPage'; import { MainPage } from '../../pages/main/MainPage'; +import { OpenIDCallbackPage } from '../../pages/openidCallback/OpenIDCallback'; import { PasswordResetPage } from '../../pages/passwordReset/PasswordResetPage'; import { SessionTimeoutPage } from '../../pages/sessionTimeout/SessionTimeoutPage'; import { TokenPage } from '../../pages/token/TokenPage'; @@ -52,6 +53,10 @@ const router = createBrowserRouter([ path: routes.passwordReset, element: , }, + { + path: routes.openidCallback, + element: , + }, { path: '/*', element: , diff --git a/web/src/i18n/en/index.ts b/web/src/i18n/en/index.ts index e156319..bee21c2 100644 --- a/web/src/i18n/en/index.ts +++ b/web/src/i18n/en/index.ts @@ -290,6 +290,35 @@ If you want to disengage your VPN connection, simply press "deactivate". submit: 'Next', }, }, + oidc: { + oidcButton: 'Sign in with', + title: 'Or Sign In with External SSO', + infoBox: + 'If you would like to initiate the enrollment process using External SSO, please click the link below to sign in and start the process.', + }, + }, + }, + oidcLogin: { + card: { + title: 'Start your enrollment process', + infoBox: + 'Thank you for validating your account, please follow instruction below for configuring your VPN connection.', + steps: { + first: 'Please download and install defguard VPN Desktop Client.', + second: `2. Open the client and Add Instance. Copy the data provided below into the corresponding fields. + You can also learn more about the process in our + documentation + .`, + tokenInput: { + instanceUrl: 'Instance URL', + token: 'Token', + title: 'Please provide instance URL and token', + addInstance: 'Add Instance', + }, + }, }, }, }, diff --git a/web/src/i18n/i18n-types.ts b/web/src/i18n/i18n-types.ts index fc6be39..f5b155a 100644 --- a/web/src/i18n/i18n-types.ts +++ b/web/src/i18n/i18n-types.ts @@ -573,6 +573,66 @@ type RootTranslation = { submit: string } } + oidc: { + /** + * S​i​g​n​ ​i​n​ ​w​i​t​h + */ + oidcButton: string + /** + * O​r​ ​S​i​g​n​ ​I​n​ ​w​i​t​h​ ​E​x​t​e​r​n​a​l​ ​S​S​O + */ + title: string + /** + * I​f​ ​y​o​u​ ​w​o​u​l​d​ ​l​i​k​e​ ​t​o​ ​i​n​i​t​i​a​t​e​ ​t​h​e​ ​e​n​r​o​l​l​m​e​n​t​ ​p​r​o​c​e​s​s​ ​u​s​i​n​g​ ​E​x​t​e​r​n​a​l​ ​S​S​O​,​ ​p​l​e​a​s​e​ ​c​l​i​c​k​ ​t​h​e​ ​l​i​n​k​ ​b​e​l​o​w​ ​t​o​ ​s​i​g​n​ ​i​n​ ​a​n​d​ ​s​t​a​r​t​ ​t​h​e​ ​p​r​o​c​e​s​s​. + */ + infoBox: string + } + } + } + oidcLogin: { + card: { + /** + * S​t​a​r​t​ ​y​o​u​r​ ​e​n​r​o​l​l​m​e​n​t​ ​p​r​o​c​e​s​s + */ + title: string + /** + * T​h​a​n​k​ ​y​o​u​ ​f​o​r​ ​v​a​l​i​d​a​t​i​n​g​ ​y​o​u​r​ ​a​c​c​o​u​n​t​,​ ​p​l​e​a​s​e​ ​f​o​l​l​o​w​ ​i​n​s​t​r​u​c​t​i​o​n​ ​b​e​l​o​w​ ​f​o​r​ ​c​o​n​f​i​g​u​r​i​n​g​ ​y​o​u​r​ ​V​P​N​ ​c​o​n​n​e​c​t​i​o​n​. + */ + infoBox: string + steps: { + /** + * P​l​e​a​s​e​ ​d​o​w​n​l​o​a​d​ ​a​n​d​ ​i​n​s​t​a​l​l​ ​d​e​f​g​u​a​r​d​ ​V​P​N​ ​D​e​s​k​t​o​p​ ​C​l​i​e​n​t​. + */ + first: string + /** + * 2​.​ ​O​p​e​n​ ​t​h​e​ ​c​l​i​e​n​t​ ​a​n​d​ ​<​i​>​A​d​d​ ​I​n​s​t​a​n​c​e​<​/​i​>​.​ ​C​o​p​y​ ​t​h​e​ ​d​a​t​a​ ​p​r​o​v​i​d​e​d​ ​b​e​l​o​w​ ​i​n​t​o​ ​t​h​e​ ​c​o​r​r​e​s​p​o​n​d​i​n​g​ ​f​i​e​l​d​s​.​ ​ + ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​Y​o​u​ ​c​a​n​ ​a​l​s​o​ ​l​e​a​r​n​ ​m​o​r​e​ ​a​b​o​u​t​ ​t​h​e​ ​p​r​o​c​e​s​s​ ​i​n​ ​o​u​r​ ​<​a​ + ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​h​r​e​f​=​"​h​t​t​p​s​:​/​/​d​o​c​s​.​d​e​f​g​u​a​r​d​.​n​e​t​/​h​e​l​p​/​c​o​n​f​i​g​u​r​i​n​g​-​v​p​n​/​a​d​d​-​n​e​w​-​i​n​s​t​a​n​c​e​"​ + ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​t​a​r​g​e​t​=​"​_​b​l​a​n​k​"​ + ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​>​ + ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​d​o​c​u​m​e​n​t​a​t​i​o​n​ + ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​<​/​a​>​. + */ + second: string + tokenInput: { + /** + * I​n​s​t​a​n​c​e​ ​U​R​L + */ + instanceUrl: string + /** + * T​o​k​e​n + */ + token: string + /** + * P​l​e​a​s​e​ ​p​r​o​v​i​d​e​ ​i​n​s​t​a​n​c​e​ ​U​R​L​ ​a​n​d​ ​t​o​k​e​n + */ + title: string + /** + * A​d​d​ ​I​n​s​t​a​n​c​e + */ + addInstance: string + } + } } } } @@ -1134,6 +1194,66 @@ export type TranslationFunctions = { submit: () => LocalizedString } } + oidc: { + /** + * Sign in with + */ + oidcButton: () => LocalizedString + /** + * Or Sign In with External SSO + */ + title: () => LocalizedString + /** + * If you would like to initiate the enrollment process using External SSO, please click the link below to sign in and start the process. + */ + infoBox: () => LocalizedString + } + } + } + oidcLogin: { + card: { + /** + * Start your enrollment process + */ + title: () => LocalizedString + /** + * Thank you for validating your account, please follow instruction below for configuring your VPN connection. + */ + infoBox: () => LocalizedString + steps: { + /** + * Please download and install defguard VPN Desktop Client. + */ + first: () => LocalizedString + /** + * 2. Open the client and Add Instance. Copy the data provided below into the corresponding fields. + You can also learn more about the process in our + documentation + . + */ + second: () => LocalizedString + tokenInput: { + /** + * Instance URL + */ + instanceUrl: () => LocalizedString + /** + * Token + */ + token: () => LocalizedString + /** + * Please provide instance URL and token + */ + title: () => LocalizedString + /** + * Add Instance + */ + addInstance: () => LocalizedString + } + } } } } diff --git a/web/src/pages/openidCallback/OpenIDCallback.tsx b/web/src/pages/openidCallback/OpenIDCallback.tsx new file mode 100644 index 0000000..b5c73d0 --- /dev/null +++ b/web/src/pages/openidCallback/OpenIDCallback.tsx @@ -0,0 +1,14 @@ +import './style.scss'; + +import { LogoContainer } from '../../components/LogoContainer/LogoContainer'; +import { PageContainer } from '../../shared/components/layout/PageContainer/PageContainer'; +import { OpenIDCallbackCard } from './components/OpenIDCallbackCard'; + +export const OpenIDCallbackPage = () => { + return ( + + + + + ); +}; diff --git a/web/src/pages/openidCallback/components/OpenIDCallbackCard.tsx b/web/src/pages/openidCallback/components/OpenIDCallbackCard.tsx new file mode 100644 index 0000000..6f894b7 --- /dev/null +++ b/web/src/pages/openidCallback/components/OpenIDCallbackCard.tsx @@ -0,0 +1,164 @@ +import './style.scss'; + +import { useQuery } from '@tanstack/react-query'; +import { AxiosError } from 'axios'; +import parse from 'html-react-parser'; +import { useState } from 'react'; +import { useBreakpoint } from 'use-breakpoint'; + +import { useI18nContext } from '../../../i18n/i18n-react'; +import { ActionButton } from '../../../shared/components/layout/ActionButton/ActionButton'; +import { ActionButtonVariant } from '../../../shared/components/layout/ActionButton/types'; +import { BigInfoBox } from '../../../shared/components/layout/BigInfoBox/BigInfoBox'; +import { Button } from '../../../shared/components/layout/Button/Button'; +import { ButtonStyleVariant } from '../../../shared/components/layout/Button/types'; +import { Card } from '../../../shared/components/layout/Card/Card'; +import { Input } from '../../../shared/components/layout/Input/Input'; +import { LoaderSpinner } from '../../../shared/components/layout/LoaderSpinner/LoaderSpinner'; +import { MessageBox } from '../../../shared/components/layout/MessageBox/MessageBox'; +import { MessageBoxType } from '../../../shared/components/layout/MessageBox/types'; +import SvgIconDownload from '../../../shared/components/svg/IconDownload'; +import { deviceBreakpoints } from '../../../shared/constants'; +import { useApi } from '../../../shared/hooks/api/useApi'; + +type ErrorResponse = { + error: string; +}; + +export const OpenIDCallbackCard = () => { + const { openIDCallback } = useApi(); + const { breakpoint } = useBreakpoint(deviceBreakpoints); + const { LL } = useI18nContext(); + const [error, setError] = useState(null); + + const { isLoading, data } = useQuery( + [], + () => { + const params = new URLSearchParams(window.location.search); + const error = params.get('error'); + if (error) { + setError(error); + return; + } + const code = params.get('code'); + const state = params.get('state'); + if (!code || !state) { + setError( + "Missing code or state in the callback's URL. \ + The provider might not be configured correctly.", + ); + return; + } + if (code && state) { + return openIDCallback({ + code, + state, + }); + } + }, + { + retry: false, + refetchOnWindowFocus: false, + refetchOnMount: false, + onError: (error: AxiosError) => { + console.error(error); + const errorResponse = error.response?.data as ErrorResponse; + if (errorResponse.error) { + setError(errorResponse.error); + } else { + setError(String(error)); + } + }, + onSuccess(data) { + if (!data?.token || !data?.url) { + setError("The server's response is missing the token or url."); + } + }, + }, + ); + + if (isLoading) { + return ( +
+ +
+ ); + } + + if (error) { + return ( + + + + ); +}; + +const CustomButton = ({ url, display_name }: { url: string; display_name?: string }) => { + const { LL } = useI18nContext(); + return ( + + ); +}; diff --git a/web/src/pages/token/components/TokenCard.tsx b/web/src/pages/token/components/TokenCard.tsx index b6d38d4..f49825c 100644 --- a/web/src/pages/token/components/TokenCard.tsx +++ b/web/src/pages/token/components/TokenCard.tsx @@ -1,7 +1,7 @@ import './style.scss'; import { zodResolver } from '@hookform/resolvers/zod'; -import { useMutation } from '@tanstack/react-query'; +import { useMutation, useQuery } from '@tanstack/react-query'; import dayjs from 'dayjs'; import { useMemo } from 'react'; import { SubmitHandler, useForm } from 'react-hook-form'; @@ -16,18 +16,19 @@ import { ArrowSingleDirection, ArrowSingleSize, } from '../../../shared/components/icons/ArrowSingle/types'; +import { BigInfoBox } from '../../../shared/components/layout/BigInfoBox/BigInfoBox'; import { Button } from '../../../shared/components/layout/Button/Button'; import { ButtonSize, ButtonStyleVariant, } from '../../../shared/components/layout/Button/types'; import { Card } from '../../../shared/components/layout/Card/Card'; -import { MessageBox } from '../../../shared/components/layout/MessageBox/MessageBox'; -import { MessageBoxType } from '../../../shared/components/layout/MessageBox/types'; +import { LoaderSpinner } from '../../../shared/components/layout/LoaderSpinner/LoaderSpinner'; import { deviceBreakpoints } from '../../../shared/constants'; import { useApi } from '../../../shared/hooks/api/useApi'; import { routes } from '../../../shared/routes'; import { useEnrollmentStore } from '../../enrollment/hooks/store/useEnrollmentStore'; +import { OpenIdLoginButton } from './OIDCButtons'; type FormFields = { token: string; @@ -37,6 +38,7 @@ export const TokenCard = () => { const navigate = useNavigate(); const { enrollment: { start: startEnrollment }, + getOpenIDAuthInfo, } = useApi(); const { breakpoint } = useBreakpoint(deviceBreakpoints); const { LL } = useI18nContext(); @@ -62,6 +64,15 @@ export const TokenCard = () => { resolver: zodResolver(schema), }); + const { isLoading: openidLoading, data: openidData } = useQuery( + [], + () => getOpenIDAuthInfo(), + { + refetchOnMount: true, + refetchOnWindowFocus: false, + }, + ); + const { isLoading, mutate } = useMutation({ mutationFn: startEnrollment, onSuccess: (res) => { @@ -100,42 +111,19 @@ export const TokenCard = () => { } }; + if (openidLoading) { + return ( +
+ +
+ ); + } + return ( <> -
-

{LL.pages.token.card.title()}

- +
{ required />
+ {openidData?.url && ( + <> +

{LL.pages.token.card.oidc.title()}

+ +
+ +
+ + )} +
+
); diff --git a/web/src/pages/token/components/style.scss b/web/src/pages/token/components/style.scss index 94ba251..442abf9 100644 --- a/web/src/pages/token/components/style.scss +++ b/web/src/pages/token/components/style.scss @@ -16,22 +16,143 @@ & > form { margin-top: 40px; - .controls { - width: 100%; - margin-top: 15px; - .btn { - width: 100%; - svg { - g { - fill: var(--surface-icon-secondary); - } - } - .arrow-single { - width: 100%; - height: 100%; - } - } - } } } + + .loader-container { + min-height: 300px; + display: flex; + justify-content: center; + align-items: center; + } + + .openid-button { + display: flex; + justify-content: center; + padding: 50px 0; + } + + .openid-heading { + margin-top: 20px; + } +} + +.gsi-material-button { + -moz-user-select: none; + -webkit-user-select: none; + -ms-user-select: none; + -webkit-appearance: none; + background-color: WHITE; + background-image: none; + border: 1px solid #747775; + -webkit-border-radius: 4px; + border-radius: 4px; + -webkit-box-sizing: border-box; + box-sizing: border-box; + color: #1f1f1f; + cursor: pointer; + font-family: 'Roboto', arial, sans-serif; + font-size: 14px; + letter-spacing: 0.25px; + outline: none; + overflow: hidden; + padding: 10px 30px; + position: relative; + text-align: center; + -webkit-transition: + background-color 0.218s, + border-color 0.218s, + box-shadow 0.218s; + transition: + background-color 0.218s, + border-color 0.218s, + box-shadow 0.218s; + vertical-align: middle; + white-space: nowrap; + width: auto; + max-width: 400px; + min-width: min-content; +} + +.gsi-material-button .gsi-material-button-icon { + height: 20px; + margin-right: 12px; + min-width: 20px; + width: 20px; +} + +.gsi-material-button .gsi-material-button-content-wrapper { + -webkit-align-items: center; + align-items: center; + display: flex; + -webkit-flex-direction: row; + flex-direction: row; + -webkit-flex-wrap: nowrap; + flex-wrap: nowrap; + height: 100%; + justify-content: space-between; + position: relative; + width: 100%; +} + +.gsi-material-button .gsi-material-button-contents { + -webkit-flex-grow: 1; + flex-grow: 1; + font-family: 'Roboto', arial, sans-serif; + font-weight: 500; + overflow: hidden; + text-overflow: ellipsis; + vertical-align: top; +} + +.gsi-material-button .gsi-material-button-state { + -webkit-transition: opacity 0.218s; + transition: opacity 0.218s; + bottom: 0; + left: 0; + opacity: 0; + position: absolute; + right: 0; + top: 0; +} + +.gsi-material-button:disabled { + cursor: default; + background-color: #ffffff61; + border-color: #1f1f1f1f; +} + +.gsi-material-button:disabled .gsi-material-button-contents { + opacity: 38%; +} + +.gsi-material-button:disabled .gsi-material-button-icon { + opacity: 38%; +} + +.gsi-material-button:not(:disabled):active .gsi-material-button-state, +.gsi-material-button:not(:disabled):focus .gsi-material-button-state { + background-color: #303030; + opacity: 12%; +} + +.gsi-material-button:not(:disabled):hover { + -webkit-box-shadow: + 0 1px 2px 0 rgba(60, 64, 67, 0.3), + 0 1px 3px 1px rgba(60, 64, 67, 0.15); + box-shadow: + 0 1px 2px 0 rgba(60, 64, 67, 0.3), + 0 1px 3px 1px rgba(60, 64, 67, 0.15); +} + +.gsi-material-button:not(:disabled):hover .gsi-material-button-state { + background-color: #303030; + opacity: 8%; +} + +.ms-button { + background-color: transparent; + border: none; + cursor: pointer; + padding: 0; } diff --git a/web/src/pages/token/style.scss b/web/src/pages/token/style.scss index 96b809d..03ad499 100644 --- a/web/src/pages/token/style.scss +++ b/web/src/pages/token/style.scss @@ -27,12 +27,6 @@ column-gap: 32px; width: 100%; box-sizing: border-box; - padding: 0 20px; - margin-bottom: 50px; - - @include media-breakpoint-up(md) { - padding: 0 135px; - } &.single { grid-template-columns: 1fr; diff --git a/web/src/shared/components/layout/BigInfoBox/BigInfoBox.tsx b/web/src/shared/components/layout/BigInfoBox/BigInfoBox.tsx new file mode 100644 index 0000000..d3ec3cf --- /dev/null +++ b/web/src/shared/components/layout/BigInfoBox/BigInfoBox.tsx @@ -0,0 +1,35 @@ +import './style.scss'; + +import { isUndefined } from 'lodash-es'; +import { HTMLProps, ReactNode, useMemo } from 'react'; + +import SvgIconInfo from '../../svg/IconInfo'; + +interface Props extends HTMLProps { + message?: string | ReactNode; + children?: ReactNode; +} + +/** + * Big infobox with a message. + */ +export const BigInfoBox = ({ message, children, ...props }: Props) => { + const renderMessage = useMemo(() => { + if (!isUndefined(children)) { + return children; + } + if (typeof message === 'string') { + return

{message}

; + } + return message; + }, [message, children]); + + return ( +
+
+ +
+
{renderMessage}
+
+ ); +}; diff --git a/web/src/shared/components/layout/BigInfoBox/style.scss b/web/src/shared/components/layout/BigInfoBox/style.scss new file mode 100644 index 0000000..7f39d7e --- /dev/null +++ b/web/src/shared/components/layout/BigInfoBox/style.scss @@ -0,0 +1,46 @@ +@use '../../../scss/helpers' as *; + +.big-info-box { + height: auto; + width: 100%; + display: flex; + align-items: center; + justify-items: center; + gap: 20px; + border-radius: 10px; + border: 1px solid var(--surface-tag-modal); + box-sizing: border-box; + padding: 20px; + + & > .icon-container { + display: flex; + align-items: center; + + & > svg { + width: 42px; + height: 42px; + } + } + + .message { + box-sizing: border-box; + p, + span, + b, + strong { + @include typography(infobox-message); + } + + b, + strong { + font-weight: 700; + } + + p, + span { + color: inherit; + max-width: 100%; + white-space: normal; + } + } +} diff --git a/web/src/shared/hooks/api/types.ts b/web/src/shared/hooks/api/types.ts index 170e086..f0ee0b0 100644 --- a/web/src/shared/hooks/api/types.ts +++ b/web/src/shared/hooks/api/types.ts @@ -93,4 +93,9 @@ export type UseApi = { reset: (data: PasswordResetRequest) => Promise; }; getAppInfo: () => Promise; + getOpenIDAuthInfo: () => Promise<{ url: string; button_display_name: string }>; + openIDCallback: (data: { code: string; state: string }) => Promise<{ + token: string; + url: string; + }>; }; diff --git a/web/src/shared/hooks/api/useApi.tsx b/web/src/shared/hooks/api/useApi.tsx index 2c2c89f..e16dfb6 100644 --- a/web/src/shared/hooks/api/useApi.tsx +++ b/web/src/shared/hooks/api/useApi.tsx @@ -33,6 +33,19 @@ export const useApi = (): UseApi => { const resetPassword: UseApi['passwordReset']['reset'] = (data) => client.post('/password-reset/reset', data).then(unpackRequest); + const getOpenIDAuthInfo: UseApi['getOpenIDAuthInfo'] = () => + client + .get('/openid/auth_info') + .then((res) => res.data) + .catch(() => { + return { + url: null, + }; + }); + + const openIDCallback: UseApi['openIDCallback'] = (data) => + client.post('/openid/callback', data).then(unpackRequest); + return { enrollment: { start: startEnrollment, @@ -45,5 +58,7 @@ export const useApi = (): UseApi => { reset: resetPassword, }, getAppInfo, + getOpenIDAuthInfo, + openIDCallback, }; }; diff --git a/web/src/shared/routes.ts b/web/src/shared/routes.ts index 26fcd98..97c5e53 100644 --- a/web/src/shared/routes.ts +++ b/web/src/shared/routes.ts @@ -4,4 +4,5 @@ export const routes = { token: '/token', timeout: '/timeout', passwordReset: '/password-reset', + openidCallback: '/openid/callback', }; diff --git a/web/src/shared/scss/helpers/_typography.scss b/web/src/shared/scss/helpers/_typography.scss index aac40a5..9daa510 100644 --- a/web/src/shared/scss/helpers/_typography.scss +++ b/web/src/shared/scss/helpers/_typography.scss @@ -219,4 +219,25 @@ text-decoration: underline; font-weight: 500; } + + @if $value ==infobox-message { + font-family: 'Poppins'; + font-size: 15px; + line-height: 23px; + font-weight: 400; + } + + @if $value ==openidcallback-steps { + font-family: 'Poppins'; + font-size: 15px; + line-height: 23px; + font-weight: 400; + } + + @if $value ==client-download-button { + font-family: 'Poppins'; + font-size: 15px; + line-height: normal; + font-weight: 600; + } }