diff --git a/Cargo.lock b/Cargo.lock index 2dfb8ce0..8c9f1122 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -54,9 +54,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "0.7.18" +version = "0.7.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +checksum = "b4f55bd91a0978cbfd91c457a164bab8b4001c833b7f323132c0a4e1922dd44e" dependencies = [ "memchr", ] @@ -76,6 +76,15 @@ dependencies = [ "alloc-no-stdlib", ] +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + [[package]] name = "ansi_term" version = "0.12.1" @@ -228,9 +237,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.10.0" +version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3" +checksum = "c1ad822118d20d2c234f427000d5acc36eabe1e29a348c89b63dd60b13f28e5d" [[package]] name = "byteorder" @@ -246,16 +255,16 @@ checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db" [[package]] name = "cached" -version = "0.38.0" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27e6092f8c7ba6e65a46f6f26d7d7997201d3a6f0e69ff5d2440b930d7c0513a" +checksum = "f3e27085975166ffaacbd04527132e1cf5906fa612991f9b4fea08e787da2961" dependencies = [ "async-trait", "async_once", "cached_proc_macro", "cached_proc_macro_types", "futures", - "hashbrown 0.12.3", + "hashbrown", "instant", "lazy_static", "once_cell", @@ -295,10 +304,11 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.20" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6127248204b9aba09a362f6c930ef6a78f2c1b2215f8a7b398c06e1083f17af0" +checksum = "bfd4d1b31faaa3a89d7934dbded3111da0d2ef28e3ebccdb4f0179f5929d1ef1" dependencies = [ + "iana-time-zone", "js-sys", "num-integer", "num-traits", @@ -353,7 +363,7 @@ dependencies = [ "rand", "sha2", "subtle", - "time 0.3.12", + "time 0.3.14", "version_check", ] @@ -369,7 +379,7 @@ dependencies = [ "publicsuffix", "serde", "serde_json", - "time 0.3.12", + "time 0.3.14", "url 2.2.2", ] @@ -391,9 +401,9 @@ checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" [[package]] name = "cpufeatures" -version = "0.2.2" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" +checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" dependencies = [ "libc", ] @@ -449,9 +459,9 @@ dependencies = [ [[package]] name = "ctrlc" -version = "3.2.2" +version = "3.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b37feaa84e6861e00a1f5e5aa8da3ee56d605c9992d33e082786754828e20865" +checksum = "1d91974fbbe88ec1df0c24a4f00f99583667a7e2e6272b2b92d294d81e462173" dependencies = [ "nix", "winapi", @@ -494,13 +504,14 @@ dependencies = [ [[package]] name = "dashmap" -version = "5.3.4" +version = "5.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3495912c9c1ccf2e18976439f4443f3fee0fd61f424ff99fde6a66b15ecb448f" +checksum = "907076dfda823b0b36d2a1bb5f90c96660a5bbcd7729e10727f07858f22c4edc" dependencies = [ "cfg-if", - "hashbrown 0.12.3", + "hashbrown", "lock_api", + "once_cell", "parking_lot_core", ] @@ -632,9 +643,9 @@ dependencies = [ [[package]] name = "either" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f107b87b6afc2a64fd13cac55fe06d6c8859f12d4b14cbcdd2c67d0976781be" +checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" [[package]] name = "email-encoding" @@ -648,9 +659,9 @@ dependencies = [ [[package]] name = "email_address" -version = "0.2.1" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8684b7c9cb4857dfa1e5b9629ef584ba618c9b93bae60f58cb23f4f271d0468e" +checksum = "b1b32a7a2580c4473f10f66b512c34bdd7d33c5e3473227ca833abdb5afe4809" [[package]] name = "encoding_rs" @@ -758,9 +769,9 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e" +checksum = "7f21eda599937fba36daeb58a22e8f5cee2d14c4a17b5b7739c7c8e5e3b8230c" dependencies = [ "futures-channel", "futures-core", @@ -773,9 +784,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" +checksum = "30bdd20c28fadd505d0fd6712cdfcb0d4b5648baf45faef7f852afb2399bb050" dependencies = [ "futures-core", "futures-sink", @@ -783,15 +794,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" +checksum = "4e5aa3de05362c3fb88de6531e6296e85cde7739cccad4b9dfeeb7f6ebce56bf" [[package]] name = "futures-executor" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6" +checksum = "9ff63c23854bee61b6e9cd331d523909f238fc7636290b96826e9cfa5faa00ab" dependencies = [ "futures-core", "futures-task", @@ -800,15 +811,15 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" +checksum = "bbf4d2a7a308fd4578637c0b17c7e1c7ba127b8f6ba00b29f717e9655d85eb68" [[package]] name = "futures-macro" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" +checksum = "42cd15d1c7456c04dbdf7e88bcd69760d74f3a798d6444e16974b505b0e62f17" dependencies = [ "proc-macro2", "quote", @@ -817,15 +828,15 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" +checksum = "21b20ba5a92e727ba30e72834706623d94ac93a725410b6a6b6fbc1b07f7ba56" [[package]] name = "futures-task" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" +checksum = "a6508c467c73851293f390476d4491cf4d227dbabcd4170f3bb6044959b294f1" [[package]] name = "futures-timer" @@ -835,9 +846,9 @@ checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" [[package]] name = "futures-util" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" +checksum = "44fb6cb1be61cc1d2e43b262516aafcf63b241cffdb1d3fa115f91d9c7b09c90" dependencies = [ "futures-channel", "futures-core", @@ -926,9 +937,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37a82c6d637fc9515a4694bbf1cb2457b79d81ce52b3108bdeea58b07dd34a57" +checksum = "5ca32592cf21ac7ccab1825cd87f6c9b3d9022c44d086172ed0966bec8af30be" dependencies = [ "bytes", "fnv", @@ -964,12 +975,6 @@ dependencies = [ "walkdir", ] -[[package]] -name = "hashbrown" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" - [[package]] name = "hashbrown" version = "0.12.3" @@ -1053,9 +1058,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.7.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "496ce29bb5a52785b44e0f7ca2847ae0bb839c9bd28f69acac9b99d461c0c04c" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" [[package]] name = "httpdate" @@ -1100,6 +1105,20 @@ dependencies = [ "tokio-native-tls", ] +[[package]] +name = "iana-time-zone" +version = "0.1.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c495f162af0bf17656d0014a0eded5f3cd2f365fdd204548c2869db89359dc7" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "js-sys", + "once_cell", + "wasm-bindgen", + "winapi", +] + [[package]] name = "ident_case" version = "1.0.1" @@ -1135,7 +1154,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" dependencies = [ "autocfg", - "hashbrown 0.12.3", + "hashbrown", "serde", ] @@ -1254,9 +1273,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.127" +version = "0.2.132" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "505e71a4706fa491e9b1b55f51b95d4037d0821ee40131190475f692b35b009b" +checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5" [[package]] name = "libmimalloc-sys" @@ -1286,9 +1305,9 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "lock_api" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" +checksum = "9f80bf5aacaf25cbfc8210d1cfb718f2bf3b11c4c54e5afe36c236853a8ec390" dependencies = [ "autocfg", "scopeguard", @@ -1407,9 +1426,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.5.3" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc" +checksum = "96590ba8f175222643a85693f33d26e9c8a015f599c216509b1a6894af675d34" dependencies = [ "adler", ] @@ -1475,10 +1494,11 @@ dependencies = [ [[package]] name = "nix" -version = "0.24.2" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "195cdbc1741b8134346d515b3a56a1c94b0912758009cfd53f99ea0f57b065fc" +checksum = "e322c04a9e3440c327fca7b6c8a63e6890a32fa2ad689db972425f07e0d22abb" dependencies = [ + "autocfg", "bitflags", "cfg-if", "libc", @@ -1577,9 +1597,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.13.0" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" +checksum = "2f7254b99e31cad77da24b08ebf628882739a608578bb1bcdfc1f9c21260d7c0" [[package]] name = "opaque-debug" @@ -1676,9 +1696,9 @@ dependencies = [ [[package]] name = "paste" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9423e2b32f7a043629287a536f21951e8c6a82482d0acb1eeebfc90bc2225b22" +checksum = "b1de2e551fb905ac83f73f7aedf2f0cb4a0da7e35efa24a202a936269f1f18e1" [[package]] name = "pear" @@ -1726,9 +1746,9 @@ checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" [[package]] name = "pest" -version = "2.2.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69486e2b8c2d2aeb9762db7b4e00b0331156393555cff467f4163ff06821eef8" +checksum = "4b0560d531d1febc25a3c9398a62a71256c0178f2e3443baedd9ad4bb8c9deb4" dependencies = [ "thiserror", "ucd-trie", @@ -1736,9 +1756,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.2.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b13570633aff33c6d22ce47dd566b10a3b9122c2fe9d8e7501895905be532b91" +checksum = "905708f7f674518498c1f8d644481440f476d39ca6ecae83319bba7c6c12da91" dependencies = [ "pest", "pest_generator", @@ -1746,9 +1766,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.2.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3c567e5702efdc79fb18859ea74c3eb36e14c43da7b8c1f098a4ed6514ec7a0" +checksum = "5803d8284a629cc999094ecd630f55e91b561a1d1ba75e233b00ae13b91a69ad" dependencies = [ "pest", "pest_meta", @@ -1759,9 +1779,9 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.2.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eb32be5ee3bbdafa8c7a18b0a8a8d962b66cfa2ceee4037f49267a50ee821fe" +checksum = "1538eb784f07615c6d9a8ab061089c6c54a344c5b4301db51990ca1c241e8c04" dependencies = [ "once_cell", "pest", @@ -1770,18 +1790,18 @@ dependencies = [ [[package]] name = "phf" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4724fa946c8d1e7cd881bd3dbee63ce32fc1e9e191e35786b3dc1320a3f68131" +checksum = "928c6535de93548188ef63bb7c4036bd415cd8f36ad25af44b9789b2ee72a48c" dependencies = [ "phf_shared", ] [[package]] name = "phf_codegen" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32ba0c43d7a1b6492b2924a62290cfd83987828af037b0743b38e6ab092aee58" +checksum = "a56ac890c5e3ca598bbdeaa99964edb5b0258a583a9eb6ef4e89fc85d9224770" dependencies = [ "phf_generator", "phf_shared", @@ -1789,9 +1809,9 @@ dependencies = [ [[package]] name = "phf_generator" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b450720b6f75cfbfabc195814bd3765f337a4f9a83186f8537297cac12f6705" +checksum = "b1181c94580fa345f50f19d738aaa39c0ed30a600d95cb2d3e23f94266f14fbf" dependencies = [ "phf_shared", "rand", @@ -1799,9 +1819,9 @@ dependencies = [ [[package]] name = "phf_shared" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd5609d4b2df87167f908a32e1b146ce309c16cf35df76bc11f440b756048e4" +checksum = "e1fb5f6f826b772a8d4c0394209441e7d37cbbb967ae9c7e0e8134365c9ee676" dependencies = [ "siphasher", "uncased", @@ -1888,18 +1908,16 @@ dependencies = [ [[package]] name = "psl-types" -version = "2.0.10" +version = "2.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8eda7c62d9ecaafdf8b62374c006de0adf61666ae96a96ba74a37134aa4e470" +checksum = "33cb294fe86a74cbcf50d4445b37da762029549ebeea341421c7c70370f86cac" [[package]] name = "publicsuffix" -version = "2.1.1" +version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "292972edad6bbecc137ab84c5e36421a4a6c979ea31d3cc73540dd04315b33e1" +checksum = "aeeedb0b429dc462f30ad27ef3de97058b060016f47790c066757be38ef792b4" dependencies = [ - "byteorder", - "hashbrown 0.11.2", "idna 0.2.3", "psl-types", ] @@ -1984,9 +2002,9 @@ dependencies = [ [[package]] name = "raw-cpuid" -version = "10.4.0" +version = "10.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c49596760fce12ca21550ac21dc5a9617b2ea4b6e0aa7d8dab8ff2824fc2bba" +checksum = "6aa2540135b6a94f74c7bc90ad4b794f822026a894f3d7bcd185c100d13d4ad6" dependencies = [ "bitflags", ] @@ -2186,7 +2204,7 @@ dependencies = [ "serde_json", "state", "tempfile", - "time 0.3.12", + "time 0.3.14", "tokio", "tokio-stream", "tokio-util", @@ -2235,7 +2253,7 @@ dependencies = [ "smallvec", "stable-pattern", "state", - "time 0.3.12", + "time 0.3.14", "tokio", "tokio-rustls", "uncased", @@ -2332,9 +2350,9 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.6.1" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dc14f172faf8a0194a3aded622712b0de276821addc574fa54fc0a1167e10dc" +checksum = "2bc1bb97804af6631813c55739f771071e0f2ed33ee20b68c86ec505d906356c" dependencies = [ "bitflags", "core-foundation", @@ -2355,9 +2373,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.142" +version = "1.0.144" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e590c437916fb6b221e1d00df6e3294f3fccd70ca7e92541c475d6ed6ef5fee2" +checksum = "0f747710de3dcd43b88c9168773254e809d8ddbdf9653b84e2554ab219f17860" dependencies = [ "serde_derive", ] @@ -2374,9 +2392,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.142" +version = "1.0.144" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34b5b8d809babe02f538c2cfec6f2c1ed10804c0e5a6a041a049a4f5588ccc2e" +checksum = "94ed3a816fb1d101812f83e789f888322c34e291f894f19590dc310963e87a00" dependencies = [ "proc-macro2", "quote", @@ -2385,9 +2403,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.83" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38dd04e3c8279e75b31ef29dbdceebfe5ad89f4d0937213c53f7d49d01b3d5a7" +checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44" dependencies = [ "itoa", "ryu", @@ -2419,9 +2437,9 @@ dependencies = [ [[package]] name = "sha1" -version = "0.10.1" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c77f4e7f65455545c2153c1253d25056825e77ee2533f0e41deb65a93a34852f" +checksum = "006769ba83e921b3085caa8334186b00cf92b4cb1a6cf4632fbccc8eff5c7549" dependencies = [ "cfg-if", "cpufeatures", @@ -2430,9 +2448,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.2" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676" +checksum = "cf9db03534dff993187064c4e0c05a5708d2a9728ace9a8959b77bedf415dac5" dependencies = [ "cfg-if", "cpufeatures", @@ -2466,7 +2484,7 @@ dependencies = [ "num-bigint", "num-traits", "thiserror", - "time 0.3.12", + "time 0.3.14", ] [[package]] @@ -2492,9 +2510,9 @@ checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1" [[package]] name = "socket2" -version = "0.4.4" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" +checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" dependencies = [ "libc", "winapi", @@ -2563,7 +2581,7 @@ dependencies = [ "hostname", "libc", "log", - "time 0.3.12", + "time 0.3.14", ] [[package]] @@ -2582,18 +2600,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.32" +version = "1.0.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5f6586b7f764adc0231f4c79be7b920e766bb2f3e51b3661cdb263828f19994" +checksum = "8c1b05ca9d106ba7d2e31a9dab4a64e7be2cce415321966ea3132c49a656e252" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.32" +version = "1.0.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12bafc5b54507e0149cdf1b145a5d80ab80a90bcd9275df43d4fff68460f6c21" +checksum = "e8f2591983642de85c921015f3f070c665a197ed69e417af436115e3a1407487" dependencies = [ "proc-macro2", "quote", @@ -2630,12 +2648,11 @@ dependencies = [ [[package]] name = "time" -version = "0.3.12" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74b7cc93fc23ba97fde84f7eea56c55d1ba183f495c6715defdfc7b9cb8c870f" +checksum = "3c3f9a28b618c3a6b9251b6908e9c99e04b9e5c02e6581ccbb67d59c34ef7f9b" dependencies = [ "itoa", - "js-sys", "libc", "num_threads", "time-macros", @@ -2664,9 +2681,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.20.1" +version = "1.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a8325f63a7d4774dd041e363b2409ed1c5cbbd0f867795e661df066b2b0a581" +checksum = "89797afd69d206ccd11fb0ea560a44bbb87731d020670e79416d442919257d42" dependencies = [ "autocfg", "bytes", @@ -2932,18 +2949,18 @@ checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" [[package]] name = "ubyte" -version = "0.10.2" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a58e29f263341a29bb79e14ad7fda5f63b1c7e48929bad4c685d7876b1d04e94" +checksum = "c81f0dae7d286ad0d9366d7679a77934cfc3cf3a8d67e82669794412b2368fe6" dependencies = [ "serde", ] [[package]] name = "ucd-trie" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89570599c4fe5585de2b388aab47e99f7fa4e9238a1399f707a02e356058141c" +checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81" [[package]] name = "uncased" @@ -3088,7 +3105,7 @@ dependencies = [ "serde", "serde_json", "syslog", - "time 0.3.12", + "time 0.3.14", "tokio", "tokio-tungstenite", "totp-lite", diff --git a/Cargo.toml b/Cargo.toml index 0ee42851..32838c72 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,10 +42,10 @@ tracing = { version = "0.1.36", features = ["log"] } # Needed to have lettre and backtrace = "0.3.66" # Logging panics to logfile instead stderr only # A `dotenv` implementation for Rust -dotenvy = { version = "0.15.1", default-features = false } +dotenvy = { version = "=0.15.1", default-features = false } # Lazy initialization -once_cell = "1.13.0" +once_cell = "1.14.0" # Numerical libraries num-traits = "0.2.15" @@ -57,15 +57,15 @@ rocket = { version = "0.5.0-rc.2", features = ["tls", "json"], default-features # WebSockets libraries tokio-tungstenite = "0.17.2" rmpv = "1.0.0" # MessagePack library -dashmap = "5.3.4" # Concurrent hashmap implementation +dashmap = "5.4.0" # Async futures -futures = "0.3.21" -tokio = { version = "1.20.1", features = ["rt-multi-thread", "fs", "io-util", "parking_lot", "time"] } +futures = "0.3.24" +tokio = { version = "1.21.0", features = ["rt-multi-thread", "fs", "io-util", "parking_lot", "time"] } # A generic serialization/deserialization framework -serde = { version = "1.0.142", features = ["derive"] } -serde_json = "1.0.83" +serde = { version = "1.0.144", features = ["derive"] } +serde_json = "1.0.85" # A safe, extensible ORM and Query builder diesel = { version = "1.4.8", features = ["chrono", "r2d2"] } @@ -82,9 +82,9 @@ ring = "0.16.20" uuid = { version = "1.1.2", features = ["v4"] } # Date and time libraries -chrono = { version = "0.4.20", features = ["clock", "serde"], default-features = false } +chrono = { version = "0.4.22", features = ["clock", "serde"], default-features = false } chrono-tz = "0.6.3" -time = "0.3.12" +time = "0.3.14" # Job scheduler job_scheduler_ng = "2.0.1" @@ -122,7 +122,7 @@ html5gum = "0.5.2" regex = { version = "1.6.0", features = ["std", "perf", "unicode-perl"], default-features = false } data-url = "0.1.1" bytes = "1.2.1" -cached = "0.38.0" +cached = "0.39.0" # Used for custom short lived cookie jar during favicon extraction cookie = "0.16.0" @@ -135,11 +135,11 @@ openssl = "0.10.41" pico-args = "0.5.0" # Macro ident concatenation -paste = "1.0.8" +paste = "1.0.9" governor = "0.4.2" # Capture CTRL+C -ctrlc = { version = "3.2.2", features = ["termination"] } +ctrlc = { version = "3.2.3", features = ["termination"] } # Allow overriding the default memory allocator # Mainly used for the musl builds, since the default musl malloc is very slow diff --git a/docker/Dockerfile.j2 b/docker/Dockerfile.j2 index ac42cee8..d9bc1338 100644 --- a/docker/Dockerfile.j2 +++ b/docker/Dockerfile.j2 @@ -59,8 +59,8 @@ # https://docs.docker.com/develop/develop-images/multistage-build/ # https://whitfin.io/speeding-up-rust-docker-builds/ ####################### VAULT BUILD IMAGE ####################### -{% set vault_version = "v2022.6.2" %} -{% set vault_image_digest = "sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70" %} +{% set vault_version = "v2022.9.0" %} +{% set vault_image_digest = "sha256:99d21235a64084c9115f4aa3da1298881b8bbf146c0d48d6530b4d685a6a6fbc" %} # The web-vault digest specifies a particular web-vault build on Docker Hub. # Using the digest instead of the tag name provides better security, # as the digest of an image is immutable, whereas a tag name can later diff --git a/docker/amd64/Dockerfile b/docker/amd64/Dockerfile index 5435cc8a..bc0f8248 100644 --- a/docker/amd64/Dockerfile +++ b/docker/amd64/Dockerfile @@ -16,15 +16,15 @@ # - From https://hub.docker.com/r/vaultwarden/web-vault/tags, # click the tag name to view the digest of the image it currently points to. # - From the command line: -# $ docker pull vaultwarden/web-vault:v2022.6.2 -# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.6.2 -# [vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70] +# $ docker pull vaultwarden/web-vault:v2022.9.0 +# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.9.0 +# [vaultwarden/web-vault@sha256:99d21235a64084c9115f4aa3da1298881b8bbf146c0d48d6530b4d685a6a6fbc] # # - Conversely, to get the tag name from the digest: -# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 -# [vaultwarden/web-vault:v2022.6.2] +# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:99d21235a64084c9115f4aa3da1298881b8bbf146c0d48d6530b4d685a6a6fbc +# [vaultwarden/web-vault:v2022.9.0] # -FROM vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 as vault +FROM vaultwarden/web-vault@sha256:99d21235a64084c9115f4aa3da1298881b8bbf146c0d48d6530b4d685a6a6fbc as vault ########################## BUILD IMAGE ########################## FROM rust:1.61-bullseye as build diff --git a/docker/amd64/Dockerfile.alpine b/docker/amd64/Dockerfile.alpine index 5e092305..0c488a02 100644 --- a/docker/amd64/Dockerfile.alpine +++ b/docker/amd64/Dockerfile.alpine @@ -16,15 +16,15 @@ # - From https://hub.docker.com/r/vaultwarden/web-vault/tags, # click the tag name to view the digest of the image it currently points to. # - From the command line: -# $ docker pull vaultwarden/web-vault:v2022.6.2 -# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.6.2 -# [vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70] +# $ docker pull vaultwarden/web-vault:v2022.9.0 +# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.9.0 +# [vaultwarden/web-vault@sha256:99d21235a64084c9115f4aa3da1298881b8bbf146c0d48d6530b4d685a6a6fbc] # # - Conversely, to get the tag name from the digest: -# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 -# [vaultwarden/web-vault:v2022.6.2] +# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:99d21235a64084c9115f4aa3da1298881b8bbf146c0d48d6530b4d685a6a6fbc +# [vaultwarden/web-vault:v2022.9.0] # -FROM vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 as vault +FROM vaultwarden/web-vault@sha256:99d21235a64084c9115f4aa3da1298881b8bbf146c0d48d6530b4d685a6a6fbc as vault ########################## BUILD IMAGE ########################## FROM blackdex/rust-musl:x86_64-musl-stable-1.61.0 as build diff --git a/docker/amd64/Dockerfile.buildx b/docker/amd64/Dockerfile.buildx index 1bae9391..872a90d9 100644 --- a/docker/amd64/Dockerfile.buildx +++ b/docker/amd64/Dockerfile.buildx @@ -16,15 +16,15 @@ # - From https://hub.docker.com/r/vaultwarden/web-vault/tags, # click the tag name to view the digest of the image it currently points to. # - From the command line: -# $ docker pull vaultwarden/web-vault:v2022.6.2 -# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.6.2 -# [vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70] +# $ docker pull vaultwarden/web-vault:v2022.9.0 +# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.9.0 +# [vaultwarden/web-vault@sha256:99d21235a64084c9115f4aa3da1298881b8bbf146c0d48d6530b4d685a6a6fbc] # # - Conversely, to get the tag name from the digest: -# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 -# [vaultwarden/web-vault:v2022.6.2] +# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:99d21235a64084c9115f4aa3da1298881b8bbf146c0d48d6530b4d685a6a6fbc +# [vaultwarden/web-vault:v2022.9.0] # -FROM vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 as vault +FROM vaultwarden/web-vault@sha256:99d21235a64084c9115f4aa3da1298881b8bbf146c0d48d6530b4d685a6a6fbc as vault ########################## BUILD IMAGE ########################## FROM rust:1.61-bullseye as build diff --git a/docker/amd64/Dockerfile.buildx.alpine b/docker/amd64/Dockerfile.buildx.alpine index 15f979b5..2892705a 100644 --- a/docker/amd64/Dockerfile.buildx.alpine +++ b/docker/amd64/Dockerfile.buildx.alpine @@ -16,15 +16,15 @@ # - From https://hub.docker.com/r/vaultwarden/web-vault/tags, # click the tag name to view the digest of the image it currently points to. # - From the command line: -# $ docker pull vaultwarden/web-vault:v2022.6.2 -# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.6.2 -# [vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70] +# $ docker pull vaultwarden/web-vault:v2022.9.0 +# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.9.0 +# [vaultwarden/web-vault@sha256:99d21235a64084c9115f4aa3da1298881b8bbf146c0d48d6530b4d685a6a6fbc] # # - Conversely, to get the tag name from the digest: -# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 -# [vaultwarden/web-vault:v2022.6.2] +# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:99d21235a64084c9115f4aa3da1298881b8bbf146c0d48d6530b4d685a6a6fbc +# [vaultwarden/web-vault:v2022.9.0] # -FROM vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 as vault +FROM vaultwarden/web-vault@sha256:99d21235a64084c9115f4aa3da1298881b8bbf146c0d48d6530b4d685a6a6fbc as vault ########################## BUILD IMAGE ########################## FROM blackdex/rust-musl:x86_64-musl-stable-1.61.0 as build diff --git a/docker/arm64/Dockerfile b/docker/arm64/Dockerfile index 0ab21c5b..e0d414a5 100644 --- a/docker/arm64/Dockerfile +++ b/docker/arm64/Dockerfile @@ -16,15 +16,15 @@ # - From https://hub.docker.com/r/vaultwarden/web-vault/tags, # click the tag name to view the digest of the image it currently points to. # - From the command line: -# $ docker pull vaultwarden/web-vault:v2022.6.2 -# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.6.2 -# [vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70] +# $ docker pull vaultwarden/web-vault:v2022.9.0 +# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.9.0 +# [vaultwarden/web-vault@sha256:99d21235a64084c9115f4aa3da1298881b8bbf146c0d48d6530b4d685a6a6fbc] # # - Conversely, to get the tag name from the digest: -# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 -# [vaultwarden/web-vault:v2022.6.2] +# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:99d21235a64084c9115f4aa3da1298881b8bbf146c0d48d6530b4d685a6a6fbc +# [vaultwarden/web-vault:v2022.9.0] # -FROM vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 as vault +FROM vaultwarden/web-vault@sha256:99d21235a64084c9115f4aa3da1298881b8bbf146c0d48d6530b4d685a6a6fbc as vault ########################## BUILD IMAGE ########################## FROM rust:1.61-bullseye as build diff --git a/docker/arm64/Dockerfile.alpine b/docker/arm64/Dockerfile.alpine index cfe8b3b3..11d5e80b 100644 --- a/docker/arm64/Dockerfile.alpine +++ b/docker/arm64/Dockerfile.alpine @@ -16,15 +16,15 @@ # - From https://hub.docker.com/r/vaultwarden/web-vault/tags, # click the tag name to view the digest of the image it currently points to. # - From the command line: -# $ docker pull vaultwarden/web-vault:v2022.6.2 -# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.6.2 -# [vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70] +# $ docker pull vaultwarden/web-vault:v2022.9.0 +# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.9.0 +# [vaultwarden/web-vault@sha256:99d21235a64084c9115f4aa3da1298881b8bbf146c0d48d6530b4d685a6a6fbc] # # - Conversely, to get the tag name from the digest: -# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 -# [vaultwarden/web-vault:v2022.6.2] +# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:99d21235a64084c9115f4aa3da1298881b8bbf146c0d48d6530b4d685a6a6fbc +# [vaultwarden/web-vault:v2022.9.0] # -FROM vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 as vault +FROM vaultwarden/web-vault@sha256:99d21235a64084c9115f4aa3da1298881b8bbf146c0d48d6530b4d685a6a6fbc as vault ########################## BUILD IMAGE ########################## FROM blackdex/rust-musl:aarch64-musl-stable-1.61.0 as build diff --git a/docker/arm64/Dockerfile.buildx b/docker/arm64/Dockerfile.buildx index 4c5d0474..e8c107c3 100644 --- a/docker/arm64/Dockerfile.buildx +++ b/docker/arm64/Dockerfile.buildx @@ -16,15 +16,15 @@ # - From https://hub.docker.com/r/vaultwarden/web-vault/tags, # click the tag name to view the digest of the image it currently points to. # - From the command line: -# $ docker pull vaultwarden/web-vault:v2022.6.2 -# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.6.2 -# [vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70] +# $ docker pull vaultwarden/web-vault:v2022.9.0 +# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.9.0 +# [vaultwarden/web-vault@sha256:99d21235a64084c9115f4aa3da1298881b8bbf146c0d48d6530b4d685a6a6fbc] # # - Conversely, to get the tag name from the digest: -# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 -# [vaultwarden/web-vault:v2022.6.2] +# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:99d21235a64084c9115f4aa3da1298881b8bbf146c0d48d6530b4d685a6a6fbc +# [vaultwarden/web-vault:v2022.9.0] # -FROM vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 as vault +FROM vaultwarden/web-vault@sha256:99d21235a64084c9115f4aa3da1298881b8bbf146c0d48d6530b4d685a6a6fbc as vault ########################## BUILD IMAGE ########################## FROM rust:1.61-bullseye as build diff --git a/docker/arm64/Dockerfile.buildx.alpine b/docker/arm64/Dockerfile.buildx.alpine index 787280d4..54bb60a5 100644 --- a/docker/arm64/Dockerfile.buildx.alpine +++ b/docker/arm64/Dockerfile.buildx.alpine @@ -16,15 +16,15 @@ # - From https://hub.docker.com/r/vaultwarden/web-vault/tags, # click the tag name to view the digest of the image it currently points to. # - From the command line: -# $ docker pull vaultwarden/web-vault:v2022.6.2 -# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.6.2 -# [vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70] +# $ docker pull vaultwarden/web-vault:v2022.9.0 +# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.9.0 +# [vaultwarden/web-vault@sha256:99d21235a64084c9115f4aa3da1298881b8bbf146c0d48d6530b4d685a6a6fbc] # # - Conversely, to get the tag name from the digest: -# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 -# [vaultwarden/web-vault:v2022.6.2] +# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:99d21235a64084c9115f4aa3da1298881b8bbf146c0d48d6530b4d685a6a6fbc +# [vaultwarden/web-vault:v2022.9.0] # -FROM vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 as vault +FROM vaultwarden/web-vault@sha256:99d21235a64084c9115f4aa3da1298881b8bbf146c0d48d6530b4d685a6a6fbc as vault ########################## BUILD IMAGE ########################## FROM blackdex/rust-musl:aarch64-musl-stable-1.61.0 as build diff --git a/docker/armv6/Dockerfile b/docker/armv6/Dockerfile index b3bbbf92..e04cb1f2 100644 --- a/docker/armv6/Dockerfile +++ b/docker/armv6/Dockerfile @@ -16,15 +16,15 @@ # - From https://hub.docker.com/r/vaultwarden/web-vault/tags, # click the tag name to view the digest of the image it currently points to. # - From the command line: -# $ docker pull vaultwarden/web-vault:v2022.6.2 -# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.6.2 -# [vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70] +# $ docker pull vaultwarden/web-vault:v2022.9.0 +# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.9.0 +# [vaultwarden/web-vault@sha256:99d21235a64084c9115f4aa3da1298881b8bbf146c0d48d6530b4d685a6a6fbc] # # - Conversely, to get the tag name from the digest: -# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 -# [vaultwarden/web-vault:v2022.6.2] +# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:99d21235a64084c9115f4aa3da1298881b8bbf146c0d48d6530b4d685a6a6fbc +# [vaultwarden/web-vault:v2022.9.0] # -FROM vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 as vault +FROM vaultwarden/web-vault@sha256:99d21235a64084c9115f4aa3da1298881b8bbf146c0d48d6530b4d685a6a6fbc as vault ########################## BUILD IMAGE ########################## FROM rust:1.61-bullseye as build diff --git a/docker/armv6/Dockerfile.alpine b/docker/armv6/Dockerfile.alpine index e544fea4..6b2fb48b 100644 --- a/docker/armv6/Dockerfile.alpine +++ b/docker/armv6/Dockerfile.alpine @@ -16,15 +16,15 @@ # - From https://hub.docker.com/r/vaultwarden/web-vault/tags, # click the tag name to view the digest of the image it currently points to. # - From the command line: -# $ docker pull vaultwarden/web-vault:v2022.6.2 -# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.6.2 -# [vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70] +# $ docker pull vaultwarden/web-vault:v2022.9.0 +# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.9.0 +# [vaultwarden/web-vault@sha256:99d21235a64084c9115f4aa3da1298881b8bbf146c0d48d6530b4d685a6a6fbc] # # - Conversely, to get the tag name from the digest: -# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 -# [vaultwarden/web-vault:v2022.6.2] +# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:99d21235a64084c9115f4aa3da1298881b8bbf146c0d48d6530b4d685a6a6fbc +# [vaultwarden/web-vault:v2022.9.0] # -FROM vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 as vault +FROM vaultwarden/web-vault@sha256:99d21235a64084c9115f4aa3da1298881b8bbf146c0d48d6530b4d685a6a6fbc as vault ########################## BUILD IMAGE ########################## FROM blackdex/rust-musl:arm-musleabi-stable-1.61.0 as build diff --git a/docker/armv6/Dockerfile.buildx b/docker/armv6/Dockerfile.buildx index 4fd3aef4..ae6a2471 100644 --- a/docker/armv6/Dockerfile.buildx +++ b/docker/armv6/Dockerfile.buildx @@ -16,15 +16,15 @@ # - From https://hub.docker.com/r/vaultwarden/web-vault/tags, # click the tag name to view the digest of the image it currently points to. # - From the command line: -# $ docker pull vaultwarden/web-vault:v2022.6.2 -# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.6.2 -# [vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70] +# $ docker pull vaultwarden/web-vault:v2022.9.0 +# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.9.0 +# [vaultwarden/web-vault@sha256:99d21235a64084c9115f4aa3da1298881b8bbf146c0d48d6530b4d685a6a6fbc] # # - Conversely, to get the tag name from the digest: -# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 -# [vaultwarden/web-vault:v2022.6.2] +# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:99d21235a64084c9115f4aa3da1298881b8bbf146c0d48d6530b4d685a6a6fbc +# [vaultwarden/web-vault:v2022.9.0] # -FROM vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 as vault +FROM vaultwarden/web-vault@sha256:99d21235a64084c9115f4aa3da1298881b8bbf146c0d48d6530b4d685a6a6fbc as vault ########################## BUILD IMAGE ########################## FROM rust:1.61-bullseye as build diff --git a/docker/armv6/Dockerfile.buildx.alpine b/docker/armv6/Dockerfile.buildx.alpine index af4547c1..826abd61 100644 --- a/docker/armv6/Dockerfile.buildx.alpine +++ b/docker/armv6/Dockerfile.buildx.alpine @@ -16,15 +16,15 @@ # - From https://hub.docker.com/r/vaultwarden/web-vault/tags, # click the tag name to view the digest of the image it currently points to. # - From the command line: -# $ docker pull vaultwarden/web-vault:v2022.6.2 -# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.6.2 -# [vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70] +# $ docker pull vaultwarden/web-vault:v2022.9.0 +# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.9.0 +# [vaultwarden/web-vault@sha256:99d21235a64084c9115f4aa3da1298881b8bbf146c0d48d6530b4d685a6a6fbc] # # - Conversely, to get the tag name from the digest: -# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 -# [vaultwarden/web-vault:v2022.6.2] +# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:99d21235a64084c9115f4aa3da1298881b8bbf146c0d48d6530b4d685a6a6fbc +# [vaultwarden/web-vault:v2022.9.0] # -FROM vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 as vault +FROM vaultwarden/web-vault@sha256:99d21235a64084c9115f4aa3da1298881b8bbf146c0d48d6530b4d685a6a6fbc as vault ########################## BUILD IMAGE ########################## FROM blackdex/rust-musl:arm-musleabi-stable-1.61.0 as build diff --git a/docker/armv7/Dockerfile b/docker/armv7/Dockerfile index 11a7a70e..26c2cd01 100644 --- a/docker/armv7/Dockerfile +++ b/docker/armv7/Dockerfile @@ -16,15 +16,15 @@ # - From https://hub.docker.com/r/vaultwarden/web-vault/tags, # click the tag name to view the digest of the image it currently points to. # - From the command line: -# $ docker pull vaultwarden/web-vault:v2022.6.2 -# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.6.2 -# [vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70] +# $ docker pull vaultwarden/web-vault:v2022.9.0 +# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.9.0 +# [vaultwarden/web-vault@sha256:99d21235a64084c9115f4aa3da1298881b8bbf146c0d48d6530b4d685a6a6fbc] # # - Conversely, to get the tag name from the digest: -# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 -# [vaultwarden/web-vault:v2022.6.2] +# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:99d21235a64084c9115f4aa3da1298881b8bbf146c0d48d6530b4d685a6a6fbc +# [vaultwarden/web-vault:v2022.9.0] # -FROM vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 as vault +FROM vaultwarden/web-vault@sha256:99d21235a64084c9115f4aa3da1298881b8bbf146c0d48d6530b4d685a6a6fbc as vault ########################## BUILD IMAGE ########################## FROM rust:1.61-bullseye as build diff --git a/docker/armv7/Dockerfile.alpine b/docker/armv7/Dockerfile.alpine index a64dd871..8e293970 100644 --- a/docker/armv7/Dockerfile.alpine +++ b/docker/armv7/Dockerfile.alpine @@ -16,15 +16,15 @@ # - From https://hub.docker.com/r/vaultwarden/web-vault/tags, # click the tag name to view the digest of the image it currently points to. # - From the command line: -# $ docker pull vaultwarden/web-vault:v2022.6.2 -# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.6.2 -# [vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70] +# $ docker pull vaultwarden/web-vault:v2022.9.0 +# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.9.0 +# [vaultwarden/web-vault@sha256:99d21235a64084c9115f4aa3da1298881b8bbf146c0d48d6530b4d685a6a6fbc] # # - Conversely, to get the tag name from the digest: -# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 -# [vaultwarden/web-vault:v2022.6.2] +# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:99d21235a64084c9115f4aa3da1298881b8bbf146c0d48d6530b4d685a6a6fbc +# [vaultwarden/web-vault:v2022.9.0] # -FROM vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 as vault +FROM vaultwarden/web-vault@sha256:99d21235a64084c9115f4aa3da1298881b8bbf146c0d48d6530b4d685a6a6fbc as vault ########################## BUILD IMAGE ########################## FROM blackdex/rust-musl:armv7-musleabihf-stable-1.61.0 as build diff --git a/docker/armv7/Dockerfile.buildx b/docker/armv7/Dockerfile.buildx index c3820a9d..711b8d2a 100644 --- a/docker/armv7/Dockerfile.buildx +++ b/docker/armv7/Dockerfile.buildx @@ -16,15 +16,15 @@ # - From https://hub.docker.com/r/vaultwarden/web-vault/tags, # click the tag name to view the digest of the image it currently points to. # - From the command line: -# $ docker pull vaultwarden/web-vault:v2022.6.2 -# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.6.2 -# [vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70] +# $ docker pull vaultwarden/web-vault:v2022.9.0 +# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.9.0 +# [vaultwarden/web-vault@sha256:99d21235a64084c9115f4aa3da1298881b8bbf146c0d48d6530b4d685a6a6fbc] # # - Conversely, to get the tag name from the digest: -# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 -# [vaultwarden/web-vault:v2022.6.2] +# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:99d21235a64084c9115f4aa3da1298881b8bbf146c0d48d6530b4d685a6a6fbc +# [vaultwarden/web-vault:v2022.9.0] # -FROM vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 as vault +FROM vaultwarden/web-vault@sha256:99d21235a64084c9115f4aa3da1298881b8bbf146c0d48d6530b4d685a6a6fbc as vault ########################## BUILD IMAGE ########################## FROM rust:1.61-bullseye as build diff --git a/docker/armv7/Dockerfile.buildx.alpine b/docker/armv7/Dockerfile.buildx.alpine index 3be205aa..c1eaad2a 100644 --- a/docker/armv7/Dockerfile.buildx.alpine +++ b/docker/armv7/Dockerfile.buildx.alpine @@ -16,15 +16,15 @@ # - From https://hub.docker.com/r/vaultwarden/web-vault/tags, # click the tag name to view the digest of the image it currently points to. # - From the command line: -# $ docker pull vaultwarden/web-vault:v2022.6.2 -# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.6.2 -# [vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70] +# $ docker pull vaultwarden/web-vault:v2022.9.0 +# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.9.0 +# [vaultwarden/web-vault@sha256:99d21235a64084c9115f4aa3da1298881b8bbf146c0d48d6530b4d685a6a6fbc] # # - Conversely, to get the tag name from the digest: -# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 -# [vaultwarden/web-vault:v2022.6.2] +# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:99d21235a64084c9115f4aa3da1298881b8bbf146c0d48d6530b4d685a6a6fbc +# [vaultwarden/web-vault:v2022.9.0] # -FROM vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 as vault +FROM vaultwarden/web-vault@sha256:99d21235a64084c9115f4aa3da1298881b8bbf146c0d48d6530b4d685a6a6fbc as vault ########################## BUILD IMAGE ########################## FROM blackdex/rust-musl:armv7-musleabihf-stable-1.61.0 as build diff --git a/src/api/admin.rs b/src/api/admin.rs index 2f946fc5..d77842e6 100644 --- a/src/api/admin.rs +++ b/src/api/admin.rs @@ -7,8 +7,8 @@ use rocket::serde::json::Json; use rocket::{ form::Form, http::{Cookie, CookieJar, SameSite, Status}, - request::{self, FlashMessage, FromRequest, Outcome, Request}, - response::{content::RawHtml as Html, Flash, Redirect}, + request::{self, FromRequest, Outcome, Request}, + response::{content::RawHtml as Html, Redirect}, Route, }; @@ -141,10 +141,24 @@ fn admin_url(referer: Referer) -> String { } } +#[derive(Responder)] +enum AdminResponse { + #[response(status = 200)] + Ok(ApiResult>), + #[response(status = 401)] + Unauthorized(ApiResult>), + #[response(status = 429)] + TooManyRequests(ApiResult>), +} + #[get("/", rank = 2)] -fn admin_login(flash: Option>) -> ApiResult> { +fn admin_login() -> ApiResult> { + render_admin_login(None) +} + +fn render_admin_login(msg: Option<&str>) -> ApiResult> { // If there is an error, show it - let msg = flash.map(|msg| format!("{}: {}", msg.kind(), msg.message())); + let msg = msg.map(|msg| format!("Error: {msg}")); let json = json!({ "page_content": "admin/login", "version": VERSION, @@ -163,22 +177,17 @@ struct LoginForm { } #[post("/", data = "")] -fn post_admin_login( - data: Form, - cookies: &CookieJar<'_>, - ip: ClientIp, - referer: Referer, -) -> Result> { +fn post_admin_login(data: Form, cookies: &CookieJar<'_>, ip: ClientIp) -> AdminResponse { let data = data.into_inner(); if crate::ratelimit::check_limit_admin(&ip.ip).is_err() { - return Err(Flash::error(Redirect::to(admin_url(referer)), "Too many requests, try again later.")); + return AdminResponse::TooManyRequests(render_admin_login(Some("Too many requests, try again later."))); } // If the token is invalid, redirect to login page if !_validate_token(&data.token) { error!("Invalid admin token. IP: {}", ip.ip); - Err(Flash::error(Redirect::to(admin_url(referer)), "Invalid admin token, please try again.")) + AdminResponse::Unauthorized(render_admin_login(Some("Invalid admin token, please try again."))) } else { // If the token received is valid, generate JWT and save it as a cookie let claims = generate_admin_claims(); @@ -192,7 +201,7 @@ fn post_admin_login( .finish(); cookies.add(cookie); - Ok(Redirect::to(admin_url(referer))) + AdminResponse::Ok(render_admin_page()) } } @@ -244,12 +253,16 @@ impl AdminTemplateData { } } -#[get("/", rank = 1)] -fn admin_page(_token: AdminToken) -> ApiResult> { +fn render_admin_page() -> ApiResult> { let text = AdminTemplateData::new().render()?; Ok(Html(text)) } +#[get("/", rank = 1)] +fn admin_page(_token: AdminToken) -> ApiResult> { + render_admin_page() +} + #[derive(Deserialize, Debug)] #[allow(non_snake_case)] struct InviteData { @@ -303,7 +316,7 @@ async fn test_smtp(data: Json, _token: AdminToken) -> EmptyResult { #[get("/logout")] fn logout(cookies: &CookieJar<'_>, referer: Referer) -> Redirect { cookies.remove(Cookie::build(COOKIE_NAME, "").path(admin_path()).finish()); - Redirect::to(admin_url(referer)) + Redirect::temporary(admin_url(referer)) } #[get("/users")] @@ -418,15 +431,26 @@ async fn update_user_org_type(data: Json, _token: AdminToken, c }; if user_to_edit.atype == UserOrgType::Owner && new_type != UserOrgType::Owner { - // Removing owner permmission, check that there are at least another owner - let num_owners = - UserOrganization::find_by_org_and_type(&data.org_uuid, UserOrgType::Owner as i32, &conn).await.len(); - - if num_owners <= 1 { + // Removing owner permmission, check that there is at least one other confirmed owner + if UserOrganization::count_confirmed_by_org_and_type(&data.org_uuid, UserOrgType::Owner, &conn).await <= 1 { err!("Can't change the type of the last owner") } } + // This check is also done at api::organizations::{accept_invite(), _confirm_invite, _activate_user(), edit_user()}, update_user_org_type + // It returns different error messages per function. + if new_type < UserOrgType::Admin { + match OrgPolicy::is_user_allowed(&user_to_edit.user_uuid, &user_to_edit.org_uuid, true, &conn).await { + Ok(_) => {} + Err(OrgPolicyErr::TwoFactorMissing) => { + err!("You cannot modify this user to this type because it has no two-step login method activated"); + } + Err(OrgPolicyErr::SingleOrgEnforced) => { + err!("You cannot modify this user to this type because it is a member of an organization which forbids it"); + } + } + } + user_to_edit.atype = new_type; user_to_edit.save(&conn).await } @@ -498,7 +522,6 @@ use cached::proc_macro::cached; async fn get_release_info(has_http_access: bool, running_within_docker: bool) -> (String, String, String) { // If the HTTP Check failed, do not even attempt to check for new versions since we were not able to connect with github.com anyway. if has_http_access { - info!("Running get_release_info!!"); ( match get_github_api::("https://api.github.com/repos/dani-garcia/vaultwarden/releases/latest") .await diff --git a/src/api/core/ciphers.rs b/src/api/core/ciphers.rs index fa80e31f..52283803 100644 --- a/src/api/core/ciphers.rs +++ b/src/api/core/ciphers.rs @@ -328,7 +328,7 @@ async fn enforce_personal_ownership_policy(data: Option<&CipherData>, headers: & if data.is_none() || data.unwrap().OrganizationId.is_none() { let user_uuid = &headers.user.uuid; let policy_type = OrgPolicyType::PersonalOwnership; - if OrgPolicy::is_applicable_to_user(user_uuid, policy_type, conn).await { + if OrgPolicy::is_applicable_to_user(user_uuid, policy_type, None, conn).await { err!("Due to an Enterprise Policy, you are restricted from saving items to your personal vault.") } } diff --git a/src/api/core/emergency_access.rs b/src/api/core/emergency_access.rs index d01b599b..5ca86910 100644 --- a/src/api/core/emergency_access.rs +++ b/src/api/core/emergency_access.rs @@ -258,7 +258,7 @@ async fn send_invite(data: JsonUpcase, headers: Heade match User::find_by_mail(&email, &conn).await { Some(user) => { match accept_invite_process(user.uuid, new_emergency_access.uuid, Some(email), conn.borrow()).await { - Ok(v) => (v), + Ok(v) => v, Err(e) => err!(e.to_string()), } } @@ -317,7 +317,7 @@ async fn resend_invite(emer_id: String, headers: Headers, conn: DbConn) -> Empty match accept_invite_process(grantee_user.uuid, emergency_access.uuid, emergency_access.email, conn.borrow()) .await { - Ok(v) => (v), + Ok(v) => v, Err(e) => err!(e.to_string()), } } @@ -363,7 +363,7 @@ async fn accept_invite(emer_id: String, data: JsonUpcase, conn: DbCo && (claims.grantor_email.is_some() && grantor_user.email == claims.grantor_email.unwrap()) { match accept_invite_process(grantee_user.uuid.clone(), emer_id, Some(grantee_user.email.clone()), &conn).await { - Ok(v) => (v), + Ok(v) => v, Err(e) => err!(e.to_string()), } diff --git a/src/api/core/mod.rs b/src/api/core/mod.rs index c54ebeb7..f296a3c9 100644 --- a/src/api/core/mod.rs +++ b/src/api/core/mod.rs @@ -16,7 +16,7 @@ pub fn routes() -> Vec { let mut device_token_routes = routes![clear_device_token, put_device_token]; let mut eq_domains_routes = routes![get_eq_domains, post_eq_domains, put_eq_domains]; let mut hibp_routes = routes![hibp_breach]; - let mut meta_routes = routes![alive, now, version]; + let mut meta_routes = routes![alive, now, version, config]; let mut routes = Vec::new(); routes.append(&mut accounts::routes()); @@ -200,3 +200,24 @@ pub fn now() -> Json { fn version() -> Json<&'static str> { Json(crate::VERSION.unwrap_or_default()) } + +#[get("/config")] +fn config() -> Json { + let domain = crate::CONFIG.domain(); + Json(json!({ + "version": crate::VERSION, + "gitHash": option_env!("GIT_REV"), + "server": { + "name": "Vaultwarden", + "url": "https://github.com/dani-garcia/vaultwarden" + }, + "environment": { + "vault": domain, + "api": format!("{domain}/api"), + "identity": format!("{domain}/identity"), + "admin": format!("{domain}/admin"), + "notifications": format!("{domain}/notifications"), + "sso": "", + }, + })) +} diff --git a/src/api/core/organizations.rs b/src/api/core/organizations.rs index 8784ba2a..98dfaa91 100644 --- a/src/api/core/organizations.rs +++ b/src/api/core/organizations.rs @@ -61,6 +61,14 @@ pub fn routes() -> Vec { import, post_org_keys, bulk_public_keys, + deactivate_organization_user, + bulk_deactivate_organization_user, + revoke_organization_user, + bulk_revoke_organization_user, + activate_organization_user, + bulk_activate_organization_user, + restore_organization_user, + bulk_restore_organization_user get_groups, post_groups, get_group, @@ -131,7 +139,7 @@ async fn create_organization(headers: Headers, data: JsonUpcase, conn: if !CONFIG.is_org_creation_allowed(&headers.user.email) { err!("User not allowed to create organizations") } - if OrgPolicy::is_applicable_to_user(&headers.user.uuid, OrgPolicyType::SingleOrg, &conn).await { + if OrgPolicy::is_applicable_to_user(&headers.user.uuid, OrgPolicyType::SingleOrg, None, &conn).await { err!( "You may not create an organization. You belong to an organization which has a policy that prohibits you from being a member of any other organization." ) @@ -196,13 +204,10 @@ async fn leave_organization(org_id: String, headers: Headers, conn: DbConn) -> E match UserOrganization::find_by_user_and_org(&headers.user.uuid, &org_id, &conn).await { None => err!("User not part of organization"), Some(user_org) => { - if user_org.atype == UserOrgType::Owner { - let num_owners = - UserOrganization::find_by_org_and_type(&org_id, UserOrgType::Owner as i32, &conn).await.len(); - - if num_owners <= 1 { - err!("The last owner can't leave") - } + if user_org.atype == UserOrgType::Owner + && UserOrganization::count_confirmed_by_org_and_type(&org_id, UserOrgType::Owner, &conn).await <= 1 + { + err!("The last owner can't leave") } user_org.delete(&conn).await @@ -797,17 +802,16 @@ struct AcceptData { Token: String, } -#[post("/organizations/<_org_id>/users/<_org_user_id>/accept", data = "")] +#[post("/organizations//users/<_org_user_id>/accept", data = "")] async fn accept_invite( - _org_id: String, + org_id: String, _org_user_id: String, data: JsonUpcase, conn: DbConn, ) -> EmptyResult { // The web-vault passes org_id and org_user_id in the URL, but we are just reading them from the JWT instead let data: AcceptData = data.into_inner().data; - let token = &data.Token; - let claims = decode_invite(token)?; + let claims = decode_invite(&data.Token)?; match User::find_by_mail(&claims.email, &conn).await { Some(_) => { @@ -823,46 +827,20 @@ async fn accept_invite( err!("User already accepted the invitation") } - let user_twofactor_disabled = TwoFactor::find_by_user(&user_org.user_uuid, &conn).await.is_empty(); - - let policy = OrgPolicyType::TwoFactorAuthentication as i32; - let org_twofactor_policy_enabled = - match OrgPolicy::find_by_org_and_type(&user_org.org_uuid, policy, &conn).await { - Some(p) => p.enabled, - None => false, - }; - - if org_twofactor_policy_enabled && user_twofactor_disabled { - err!("You cannot join this organization until you enable two-step login on your user account.") - } - - // Enforce Single Organization Policy of organization user is trying to join - let single_org_policy_enabled = - match OrgPolicy::find_by_org_and_type(&user_org.org_uuid, OrgPolicyType::SingleOrg as i32, &conn) - .await - { - Some(p) => p.enabled, - None => false, - }; - if single_org_policy_enabled && user_org.atype < UserOrgType::Admin { - let is_member_of_another_org = UserOrganization::find_any_state_by_user(&user_org.user_uuid, &conn) - .await - .into_iter() - .filter(|uo| uo.org_uuid != user_org.org_uuid) - .count() - > 1; - if is_member_of_another_org { - err!("You may not join this organization until you leave or remove all other organizations.") + // This check is also done at accept_invite(), _confirm_invite, _activate_user(), edit_user(), admin::update_user_org_type + // It returns different error messages per function. + if user_org.atype < UserOrgType::Admin { + match OrgPolicy::is_user_allowed(&user_org.user_uuid, &org_id, false, &conn).await { + Ok(_) => {} + Err(OrgPolicyErr::TwoFactorMissing) => { + err!("You cannot join this organization until you enable two-step login on your user account"); + } + Err(OrgPolicyErr::SingleOrgEnforced) => { + err!("You cannot join this organization because you are a member of an organization which forbids it"); + } } } - // Enforce Single Organization Policy of other organizations user is a member of - if OrgPolicy::is_applicable_to_user(&user_org.user_uuid, OrgPolicyType::SingleOrg, &conn).await { - err!( - "You cannot join this organization because you are a member of an organization which forbids it" - ) - } - user_org.status = UserOrgStatus::Accepted as i32; user_org.save(&conn).await?; } @@ -966,6 +944,20 @@ async fn _confirm_invite( err!("User in invalid state") } + // This check is also done at accept_invite(), _confirm_invite, _activate_user(), edit_user(), admin::update_user_org_type + // It returns different error messages per function. + if user_to_confirm.atype < UserOrgType::Admin { + match OrgPolicy::is_user_allowed(&user_to_confirm.user_uuid, org_id, true, conn).await { + Ok(_) => {} + Err(OrgPolicyErr::TwoFactorMissing) => { + err!("You cannot confirm this user because it has no two-step login method activated"); + } + Err(OrgPolicyErr::SingleOrgEnforced) => { + err!("You cannot confirm this user because it is a member of an organization which forbids it"); + } + } + } + user_to_confirm.status = UserOrgStatus::Confirmed as i32; user_to_confirm.akey = key.to_string(); @@ -1045,14 +1037,26 @@ async fn edit_user( } if user_to_edit.atype == UserOrgType::Owner && new_type != UserOrgType::Owner { - // Removing owner permmission, check that there are at least another owner - let num_owners = UserOrganization::find_by_org_and_type(&org_id, UserOrgType::Owner as i32, &conn).await.len(); - - if num_owners <= 1 { + // Removing owner permmission, check that there is at least one other confirmed owner + if UserOrganization::count_confirmed_by_org_and_type(&org_id, UserOrgType::Owner, &conn).await <= 1 { err!("Can't delete the last owner") } } + // This check is also done at accept_invite(), _confirm_invite, _activate_user(), edit_user(), admin::update_user_org_type + // It returns different error messages per function. + if new_type < UserOrgType::Admin { + match OrgPolicy::is_user_allowed(&user_to_edit.user_uuid, &org_id, true, &conn).await { + Ok(_) => {} + Err(OrgPolicyErr::TwoFactorMissing) => { + err!("You cannot modify this user to this type because it has no two-step login method activated"); + } + Err(OrgPolicyErr::SingleOrgEnforced) => { + err!("You cannot modify this user to this type because it is a member of an organization which forbids it"); + } + } + } + user_to_edit.access_all = data.AccessAll; user_to_edit.atype = new_type as i32; @@ -1131,10 +1135,8 @@ async fn _delete_user(org_id: &str, org_user_id: &str, headers: &AdminHeaders, c } if user_to_delete.atype == UserOrgType::Owner { - // Removing owner, check that there are at least another owner - let num_owners = UserOrganization::find_by_org_and_type(org_id, UserOrgType::Owner as i32, conn).await.len(); - - if num_owners <= 1 { + // Removing owner, check that there is at least one other confirmed owner + if UserOrganization::count_confirmed_by_org_and_type(org_id, UserOrgType::Owner, conn).await <= 1 { err!("Can't delete the last owner") } } @@ -1303,7 +1305,7 @@ async fn get_policy(org_id: String, pol_type: i32, _headers: AdminHeaders, conn: None => err!("Invalid or unsupported policy type"), }; - let policy = match OrgPolicy::find_by_org_and_type(&org_id, pol_type, &conn).await { + let policy = match OrgPolicy::find_by_org_and_type(&org_id, pol_type_enum, &conn).await { Some(p) => p, None => OrgPolicy::new(org_id, pol_type_enum, "{}".to_string()), }; @@ -1331,15 +1333,16 @@ async fn put_policy( let pol_type_enum = match OrgPolicyType::from_i32(pol_type) { Some(pt) => pt, - None => err!("Invalid policy type"), + None => err!("Invalid or unsupported policy type"), }; - // If enabling the TwoFactorAuthentication policy, remove this org's members that do have 2FA + // When enabling the TwoFactorAuthentication policy, remove this org's members that do have 2FA if pol_type_enum == OrgPolicyType::TwoFactorAuthentication && data.enabled { for member in UserOrganization::find_by_org(&org_id, &conn).await.into_iter() { let user_twofactor_disabled = TwoFactor::find_by_user(&member.user_uuid, &conn).await.is_empty(); // Policy only applies to non-Owner/non-Admin members who have accepted joining the org + // Invited users still need to accept the invite and will get an error when they try to accept the invite. if user_twofactor_disabled && member.atype < UserOrgType::Admin && member.status != UserOrgStatus::Invited as i32 @@ -1355,33 +1358,29 @@ async fn put_policy( } } - // If enabling the SingleOrg policy, remove this org's members that are members of other orgs + // When enabling the SingleOrg policy, remove this org's members that are members of other orgs if pol_type_enum == OrgPolicyType::SingleOrg && data.enabled { for member in UserOrganization::find_by_org(&org_id, &conn).await.into_iter() { // Policy only applies to non-Owner/non-Admin members who have accepted joining the org - if member.atype < UserOrgType::Admin && member.status != UserOrgStatus::Invited as i32 { - let is_member_of_another_org = UserOrganization::find_any_state_by_user(&member.user_uuid, &conn) - .await - .into_iter() - // Other UserOrganization's where they have accepted being a member of - .filter(|uo| uo.uuid != member.uuid && uo.status != UserOrgStatus::Invited as i32) - .count() - > 1; - - if is_member_of_another_org { - if CONFIG.mail_enabled() { - let org = Organization::find_by_uuid(&member.org_uuid, &conn).await.unwrap(); - let user = User::find_by_uuid(&member.user_uuid, &conn).await.unwrap(); - - mail::send_single_org_removed_from_org(&user.email, &org.name).await?; - } - member.delete(&conn).await?; + // Exclude invited and revoked users when checking for this policy. + // Those users will not be allowed to accept or be activated because of the policy checks done there. + // We check if the count is larger then 1, because it includes this organization also. + if member.atype < UserOrgType::Admin + && member.status != UserOrgStatus::Invited as i32 + && UserOrganization::count_accepted_and_confirmed_by_user(&member.user_uuid, &conn).await > 1 + { + if CONFIG.mail_enabled() { + let org = Organization::find_by_uuid(&member.org_uuid, &conn).await.unwrap(); + let user = User::find_by_uuid(&member.user_uuid, &conn).await.unwrap(); + + mail::send_single_org_removed_from_org(&user.email, &org.name).await?; } + member.delete(&conn).await?; } } } - let mut policy = match OrgPolicy::find_by_org_and_type(&org_id, pol_type, &conn).await { + let mut policy = match OrgPolicy::find_by_org_and_type(&org_id, pol_type_enum, &conn).await { Some(p) => p, None => OrgPolicy::new(org_id, pol_type_enum, "{}".to_string()), }; @@ -1404,7 +1403,7 @@ fn get_organization_tax(org_id: String, _headers: Headers) -> Json { } #[get("/plans")] -fn get_plans(_headers: Headers) -> Json { +fn get_plans() -> Json { // Respond with a minimal json just enough to allow the creation of an new organization. Json(json!({ "Object": "list", @@ -1521,7 +1520,7 @@ async fn import(org_id: String, data: JsonUpcase, headers: Header // If this flag is enabled, any user that isn't provided in the Users list will be removed (by default they will be kept unless they have Deleted == true) if data.OverwriteExisting { - for user_org in UserOrganization::find_by_org_and_type(&org_id, UserOrgType::User as i32, &conn).await { + for user_org in UserOrganization::find_by_org_and_type(&org_id, UserOrgType::User, &conn).await { if let Some(user_email) = User::find_by_uuid(&user_org.user_uuid, &conn).await.map(|u| u.email) { if !data.Users.iter().any(|u| u.Email == user_email) { user_org.delete(&conn).await?; @@ -1533,6 +1532,212 @@ async fn import(org_id: String, data: JsonUpcase, headers: Header Ok(()) } +// Pre web-vault v2022.9.x endpoint +#[put("/organizations//users//deactivate")] +async fn deactivate_organization_user( + org_id: String, + org_user_id: String, + headers: AdminHeaders, + conn: DbConn, +) -> EmptyResult { + _revoke_organization_user(&org_id, &org_user_id, &headers, &conn).await +} + +// Pre web-vault v2022.9.x endpoint +#[put("/organizations//users/deactivate", data = "")] +async fn bulk_deactivate_organization_user( + org_id: String, + data: JsonUpcase, + headers: AdminHeaders, + conn: DbConn, +) -> Json { + bulk_revoke_organization_user(org_id, data, headers, conn).await +} + +#[put("/organizations//users//revoke")] +async fn revoke_organization_user( + org_id: String, + org_user_id: String, + headers: AdminHeaders, + conn: DbConn, +) -> EmptyResult { + _revoke_organization_user(&org_id, &org_user_id, &headers, &conn).await +} + +#[put("/organizations//users/revoke", data = "")] +async fn bulk_revoke_organization_user( + org_id: String, + data: JsonUpcase, + headers: AdminHeaders, + conn: DbConn, +) -> Json { + let data = data.into_inner().data; + + let mut bulk_response = Vec::new(); + match data["Ids"].as_array() { + Some(org_users) => { + for org_user_id in org_users { + let org_user_id = org_user_id.as_str().unwrap_or_default(); + let err_msg = match _revoke_organization_user(&org_id, org_user_id, &headers, &conn).await { + Ok(_) => String::from(""), + Err(e) => format!("{:?}", e), + }; + + bulk_response.push(json!( + { + "Object": "OrganizationUserBulkResponseModel", + "Id": org_user_id, + "Error": err_msg + } + )); + } + } + None => error!("No users to revoke"), + } + + Json(json!({ + "Data": bulk_response, + "Object": "list", + "ContinuationToken": null + })) +} + +async fn _revoke_organization_user( + org_id: &str, + org_user_id: &str, + headers: &AdminHeaders, + conn: &DbConn, +) -> EmptyResult { + match UserOrganization::find_by_uuid_and_org(org_user_id, org_id, conn).await { + Some(mut user_org) if user_org.status > UserOrgStatus::Revoked as i32 => { + if user_org.user_uuid == headers.user.uuid { + err!("You cannot revoke yourself") + } + if user_org.atype == UserOrgType::Owner && headers.org_user_type != UserOrgType::Owner { + err!("Only owners can revoke other owners") + } + if user_org.atype == UserOrgType::Owner + && UserOrganization::count_confirmed_by_org_and_type(org_id, UserOrgType::Owner, conn).await <= 1 + { + err!("Organization must have at least one confirmed owner") + } + + user_org.revoke(); + user_org.save(conn).await?; + } + Some(_) => err!("User is already revoked"), + None => err!("User not found in organization"), + } + Ok(()) +} + +// Pre web-vault v2022.9.x endpoint +#[put("/organizations//users//activate")] +async fn activate_organization_user( + org_id: String, + org_user_id: String, + headers: AdminHeaders, + conn: DbConn, +) -> EmptyResult { + _restore_organization_user(&org_id, &org_user_id, &headers, &conn).await +} + +// Pre web-vault v2022.9.x endpoint +#[put("/organizations//users/activate", data = "")] +async fn bulk_activate_organization_user( + org_id: String, + data: JsonUpcase, + headers: AdminHeaders, + conn: DbConn, +) -> Json { + bulk_restore_organization_user(org_id, data, headers, conn).await +} + +#[put("/organizations//users//restore")] +async fn restore_organization_user( + org_id: String, + org_user_id: String, + headers: AdminHeaders, + conn: DbConn, +) -> EmptyResult { + _restore_organization_user(&org_id, &org_user_id, &headers, &conn).await +} + +#[put("/organizations//users/restore", data = "")] +async fn bulk_restore_organization_user( + org_id: String, + data: JsonUpcase, + headers: AdminHeaders, + conn: DbConn, +) -> Json { + let data = data.into_inner().data; + + let mut bulk_response = Vec::new(); + match data["Ids"].as_array() { + Some(org_users) => { + for org_user_id in org_users { + let org_user_id = org_user_id.as_str().unwrap_or_default(); + let err_msg = match _restore_organization_user(&org_id, org_user_id, &headers, &conn).await { + Ok(_) => String::from(""), + Err(e) => format!("{:?}", e), + }; + + bulk_response.push(json!( + { + "Object": "OrganizationUserBulkResponseModel", + "Id": org_user_id, + "Error": err_msg + } + )); + } + } + None => error!("No users to restore"), + } + + Json(json!({ + "Data": bulk_response, + "Object": "list", + "ContinuationToken": null + })) +} + +async fn _restore_organization_user( + org_id: &str, + org_user_id: &str, + headers: &AdminHeaders, + conn: &DbConn, +) -> EmptyResult { + match UserOrganization::find_by_uuid_and_org(org_user_id, org_id, conn).await { + Some(mut user_org) if user_org.status < UserOrgStatus::Accepted as i32 => { + if user_org.user_uuid == headers.user.uuid { + err!("You cannot restore yourself") + } + if user_org.atype == UserOrgType::Owner && headers.org_user_type != UserOrgType::Owner { + err!("Only owners can restore other owners") + } + + // This check is also done at accept_invite(), _confirm_invite, _activate_user(), edit_user(), admin::update_user_org_type + // It returns different error messages per function. + if user_org.atype < UserOrgType::Admin { + match OrgPolicy::is_user_allowed(&user_org.user_uuid, org_id, false, conn).await { + Ok(_) => {} + Err(OrgPolicyErr::TwoFactorMissing) => { + err!("You cannot restore this user because it has no two-step login method activated"); + } + Err(OrgPolicyErr::SingleOrgEnforced) => { + err!("You cannot restore this user because it is a member of an organization which forbids it"); + } + } + } + + user_org.restore(); + user_org.save(conn).await?; + } + Some(_) => err!("User is already active"), + None => err!("User not found in organization"), + } + Ok(()) + #[get("/organizations//groups")] async fn get_groups(org_id: String, _headers: AdminHeaders, conn: DbConn) -> JsonResult { let groups = Group::find_by_organization(&org_id, &conn).await.iter().map(Group::to_json).collect::(); diff --git a/src/api/core/sends.rs b/src/api/core/sends.rs index 4f3291dc..3d150b31 100644 --- a/src/api/core/sends.rs +++ b/src/api/core/sends.rs @@ -70,8 +70,9 @@ struct SendData { /// controls this policy globally. async fn enforce_disable_send_policy(headers: &Headers, conn: &DbConn) -> EmptyResult { let user_uuid = &headers.user.uuid; - let policy_type = OrgPolicyType::DisableSend; - if !CONFIG.sends_allowed() || OrgPolicy::is_applicable_to_user(user_uuid, policy_type, conn).await { + if !CONFIG.sends_allowed() + || OrgPolicy::is_applicable_to_user(user_uuid, OrgPolicyType::DisableSend, None, conn).await + { err!("Due to an Enterprise Policy, you are only able to delete an existing Send.") } Ok(()) diff --git a/src/api/core/two_factor/mod.rs b/src/api/core/two_factor/mod.rs index 3ecc5454..e690f19d 100644 --- a/src/api/core/two_factor/mod.rs +++ b/src/api/core/two_factor/mod.rs @@ -19,7 +19,14 @@ pub mod webauthn; pub mod yubikey; pub fn routes() -> Vec { - let mut routes = routes![get_twofactor, get_recover, recover, disable_twofactor, disable_twofactor_put,]; + let mut routes = routes![ + get_twofactor, + get_recover, + recover, + disable_twofactor, + disable_twofactor_put, + get_device_verification_settings, + ]; routes.append(&mut authenticator::routes()); routes.append(&mut duo::routes()); @@ -188,3 +195,21 @@ pub async fn send_incomplete_2fa_notifications(pool: DbPool) { login.delete(&conn).await.expect("Error deleting incomplete 2FA record"); } } + +// This function currently is just a dummy and the actual part is not implemented yet. +// This also prevents 404 errors. +// +// See the following Bitwarden PR's regarding this feature. +// https://github.com/bitwarden/clients/pull/2843 +// https://github.com/bitwarden/clients/pull/2839 +// https://github.com/bitwarden/server/pull/2016 +// +// The HTML part is hidden via the CSS patches done via the bw_web_build repo +#[get("/two-factor/get-device-verification-settings")] +fn get_device_verification_settings(_headers: Headers, _conn: DbConn) -> Json { + Json(json!({ + "isDeviceVerificationSectionEnabled":false, + "unknownDeviceVerificationEnabled":false, + "object":"deviceVerificationSettings" + })) +} diff --git a/src/api/web.rs b/src/api/web.rs index c8ecdb84..c01e782a 100644 --- a/src/api/web.rs +++ b/src/api/web.rs @@ -88,8 +88,8 @@ fn static_files(filename: String) -> Result<(ContentType, &'static [u8]), Error> "identicon.js" => Ok((ContentType::JavaScript, include_bytes!("../static/scripts/identicon.js"))), "datatables.js" => Ok((ContentType::JavaScript, include_bytes!("../static/scripts/datatables.js"))), "datatables.css" => Ok((ContentType::CSS, include_bytes!("../static/scripts/datatables.css"))), - "jquery-3.6.0.slim.js" => { - Ok((ContentType::JavaScript, include_bytes!("../static/scripts/jquery-3.6.0.slim.js"))) + "jquery-3.6.1.slim.js" => { + Ok((ContentType::JavaScript, include_bytes!("../static/scripts/jquery-3.6.1.slim.js"))) } _ => err!(format!("Static file not found: {}", filename)), } diff --git a/src/db/models/mod.rs b/src/db/models/mod.rs index 95f8b581..6c384e99 100644 --- a/src/db/models/mod.rs +++ b/src/db/models/mod.rs @@ -20,6 +20,7 @@ pub use self::device::Device; pub use self::emergency_access::{EmergencyAccess, EmergencyAccessStatus, EmergencyAccessType}; pub use self::favorite::Favorite; pub use self::folder::{Folder, FolderCipher}; +pub use self::org_policy::{OrgPolicy, OrgPolicyErr, OrgPolicyType}; pub use self::group::{CollectionGroup, Group, GroupUser}; pub use self::org_policy::{OrgPolicy, OrgPolicyType}; pub use self::organization::{Organization, UserOrgStatus, UserOrgType, UserOrganization}; diff --git a/src/db/models/org_policy.rs b/src/db/models/org_policy.rs index 65ec0fd8..02ca8408 100644 --- a/src/db/models/org_policy.rs +++ b/src/db/models/org_policy.rs @@ -6,7 +6,7 @@ use crate::db::DbConn; use crate::error::MapResult; use crate::util::UpCase; -use super::{UserOrgStatus, UserOrgType, UserOrganization}; +use super::{TwoFactor, UserOrgStatus, UserOrgType, UserOrganization}; db_object! { #[derive(Identifiable, Queryable, Insertable, AsChangeset)] @@ -21,25 +21,37 @@ db_object! { } } +// https://github.com/bitwarden/server/blob/b86a04cef9f1e1b82cf18e49fc94e017c641130c/src/Core/Enums/PolicyType.cs #[derive(Copy, Clone, Eq, PartialEq, num_derive::FromPrimitive)] pub enum OrgPolicyType { TwoFactorAuthentication = 0, MasterPassword = 1, PasswordGenerator = 2, SingleOrg = 3, - // RequireSso = 4, // Not currently supported. + // RequireSso = 4, // Not supported PersonalOwnership = 5, DisableSend = 6, SendOptions = 7, + // ResetPassword = 8, // Not supported + // MaximumVaultTimeout = 9, // Not supported (Not AGPLv3 Licensed) + // DisablePersonalVaultExport = 10, // Not supported (Not AGPLv3 Licensed) } -// https://github.com/bitwarden/server/blob/master/src/Core/Models/Data/SendOptionsPolicyData.cs +// https://github.com/bitwarden/server/blob/5cbdee137921a19b1f722920f0fa3cd45af2ef0f/src/Core/Models/Data/Organizations/Policies/SendOptionsPolicyData.cs #[derive(Deserialize)] #[allow(non_snake_case)] pub struct SendOptionsPolicyData { pub DisableHideEmail: bool, } +pub type OrgPolicyResult = Result<(), OrgPolicyErr>; + +#[derive(Debug)] +pub enum OrgPolicyErr { + TwoFactorMissing, + SingleOrgEnforced, +} + /// Local methods impl OrgPolicy { pub fn new(org_uuid: String, atype: OrgPolicyType, data: String) -> Self { @@ -160,11 +172,11 @@ impl OrgPolicy { }} } - pub async fn find_by_org_and_type(org_uuid: &str, atype: i32, conn: &DbConn) -> Option { + pub async fn find_by_org_and_type(org_uuid: &str, policy_type: OrgPolicyType, conn: &DbConn) -> Option { db_run! { conn: { org_policies::table .filter(org_policies::org_uuid.eq(org_uuid)) - .filter(org_policies::atype.eq(atype)) + .filter(org_policies::atype.eq(policy_type as i32)) .first::(conn) .ok() .from_db() @@ -179,40 +191,128 @@ impl OrgPolicy { }} } + pub async fn find_accepted_and_confirmed_by_user_and_active_policy( + user_uuid: &str, + policy_type: OrgPolicyType, + conn: &DbConn, + ) -> Vec { + db_run! { conn: { + org_policies::table + .inner_join( + users_organizations::table.on( + users_organizations::org_uuid.eq(org_policies::org_uuid) + .and(users_organizations::user_uuid.eq(user_uuid))) + ) + .filter( + users_organizations::status.eq(UserOrgStatus::Accepted as i32) + ) + .or_filter( + users_organizations::status.eq(UserOrgStatus::Confirmed as i32) + ) + .filter(org_policies::atype.eq(policy_type as i32)) + .filter(org_policies::enabled.eq(true)) + .select(org_policies::all_columns) + .load::(conn) + .expect("Error loading org_policy") + .from_db() + }} + } + + pub async fn find_confirmed_by_user_and_active_policy( + user_uuid: &str, + policy_type: OrgPolicyType, + conn: &DbConn, + ) -> Vec { + db_run! { conn: { + org_policies::table + .inner_join( + users_organizations::table.on( + users_organizations::org_uuid.eq(org_policies::org_uuid) + .and(users_organizations::user_uuid.eq(user_uuid))) + ) + .filter( + users_organizations::status.eq(UserOrgStatus::Confirmed as i32) + ) + .filter(org_policies::atype.eq(policy_type as i32)) + .filter(org_policies::enabled.eq(true)) + .select(org_policies::all_columns) + .load::(conn) + .expect("Error loading org_policy") + .from_db() + }} + } + /// Returns true if the user belongs to an org that has enabled the specified policy type, /// and the user is not an owner or admin of that org. This is only useful for checking /// applicability of policy types that have these particular semantics. - pub async fn is_applicable_to_user(user_uuid: &str, policy_type: OrgPolicyType, conn: &DbConn) -> bool { - // TODO: Should check confirmed and accepted users - for policy in OrgPolicy::find_confirmed_by_user(user_uuid, conn).await { - if policy.enabled && policy.has_type(policy_type) { - let org_uuid = &policy.org_uuid; - if let Some(user) = UserOrganization::find_by_user_and_org(user_uuid, org_uuid, conn).await { - if user.atype < UserOrgType::Admin { - return true; - } + pub async fn is_applicable_to_user( + user_uuid: &str, + policy_type: OrgPolicyType, + exclude_org_uuid: Option<&str>, + conn: &DbConn, + ) -> bool { + for policy in + OrgPolicy::find_accepted_and_confirmed_by_user_and_active_policy(user_uuid, policy_type, conn).await + { + // Check if we need to skip this organization. + if exclude_org_uuid.is_some() && exclude_org_uuid.unwrap() == policy.org_uuid { + continue; + } + + if let Some(user) = UserOrganization::find_by_user_and_org(user_uuid, &policy.org_uuid, conn).await { + if user.atype < UserOrgType::Admin { + return true; } } } false } + pub async fn is_user_allowed( + user_uuid: &str, + org_uuid: &str, + exclude_current_org: bool, + conn: &DbConn, + ) -> OrgPolicyResult { + // Enforce TwoFactor/TwoStep login + if TwoFactor::find_by_user(user_uuid, conn).await.is_empty() { + match Self::find_by_org_and_type(org_uuid, OrgPolicyType::TwoFactorAuthentication, conn).await { + Some(p) if p.enabled => { + return Err(OrgPolicyErr::TwoFactorMissing); + } + _ => {} + }; + } + + // Enforce Single Organization Policy of other organizations user is a member of + // This check here needs to exclude this current org-id, else an accepted user can not be confirmed. + let exclude_org = if exclude_current_org { + Some(org_uuid) + } else { + None + }; + if Self::is_applicable_to_user(user_uuid, OrgPolicyType::SingleOrg, exclude_org, conn).await { + return Err(OrgPolicyErr::SingleOrgEnforced); + } + + Ok(()) + } + /// Returns true if the user belongs to an org that has enabled the `DisableHideEmail` /// option of the `Send Options` policy, and the user is not an owner or admin of that org. pub async fn is_hide_email_disabled(user_uuid: &str, conn: &DbConn) -> bool { - for policy in OrgPolicy::find_confirmed_by_user(user_uuid, conn).await { - if policy.enabled && policy.has_type(OrgPolicyType::SendOptions) { - let org_uuid = &policy.org_uuid; - if let Some(user) = UserOrganization::find_by_user_and_org(user_uuid, org_uuid, conn).await { - if user.atype < UserOrgType::Admin { - match serde_json::from_str::>(&policy.data) { - Ok(opts) => { - if opts.data.DisableHideEmail { - return true; - } + for policy in + OrgPolicy::find_confirmed_by_user_and_active_policy(user_uuid, OrgPolicyType::SendOptions, conn).await + { + if let Some(user) = UserOrganization::find_by_user_and_org(user_uuid, &policy.org_uuid, conn).await { + if user.atype < UserOrgType::Admin { + match serde_json::from_str::>(&policy.data) { + Ok(opts) => { + if opts.data.DisableHideEmail { + return true; } - _ => error!("Failed to deserialize policy data: {}", policy.data), } + _ => error!("Failed to deserialize SendOptionsPolicyData: {}", policy.data), } } } diff --git a/src/db/models/organization.rs b/src/db/models/organization.rs index 112b966b..fa9be4ec 100644 --- a/src/db/models/organization.rs +++ b/src/db/models/organization.rs @@ -31,7 +31,9 @@ db_object! { } } +// https://github.com/bitwarden/server/blob/b86a04cef9f1e1b82cf18e49fc94e017c641130c/src/Core/Enums/OrganizationUserStatusType.cs pub enum UserOrgStatus { + Revoked = -1, Invited = 0, Accepted = 1, Confirmed = 2, @@ -133,26 +135,29 @@ impl Organization { public_key, } } - + // https://github.com/bitwarden/server/blob/13d1e74d6960cf0d042620b72d85bf583a4236f7/src/Api/Models/Response/Organizations/OrganizationResponseModel.cs pub fn to_json(&self) -> Value { json!({ "Id": self.uuid, "Identifier": null, // not supported by us "Name": self.name, "Seats": 10, // The value doesn't matter, we don't check server-side + // "MaxAutoscaleSeats": null, // The value doesn't matter, we don't check server-side "MaxCollections": 10, // The value doesn't matter, we don't check server-side "MaxStorageGb": 10, // The value doesn't matter, we don't check server-side "Use2fa": true, "UseDirectory": false, // Is supported, but this value isn't checked anywhere (yet) - "UseEvents": false, // not supported by us + "UseEvents": false, // Not supported "UseGroups": true, "UseTotp": true, "UsePolicies": true, - "UseSso": false, // We do not support SSO + // "UseScim": false, // Not supported (Not AGPLv3 Licensed) + "UseSso": false, // Not supported + // "UseKeyConnector": false, // Not supported "SelfHost": true, - "UseApi": false, // not supported by us + "UseApi": false, // Not supported "HasPublicAndPrivateKeys": self.private_key.is_some() && self.public_key.is_some(), - "ResetPasswordEnrolled": false, // not supported by us + "UseResetPassword": false, // Not supported "BusinessName": null, "BusinessAddress1": null, @@ -170,6 +175,12 @@ impl Organization { } } +// Used to either subtract or add to the current status +// The number 128 should be fine, it is well within the range of an i32 +// The same goes for the database where we only use INTEGER (the same as an i32) +// It should also provide enough room for 100+ types, which i doubt will ever happen. +static ACTIVATE_REVOKE_DIFF: i32 = 128; + impl UserOrganization { pub fn new(user_uuid: String, org_uuid: String) -> Self { Self { @@ -184,6 +195,18 @@ impl UserOrganization { atype: UserOrgType::User as i32, } } + + pub fn restore(&mut self) { + if self.status < UserOrgStatus::Accepted as i32 { + self.status += ACTIVATE_REVOKE_DIFF; + } + } + + pub fn revoke(&mut self) { + if self.status > UserOrgStatus::Revoked as i32 { + self.status -= ACTIVATE_REVOKE_DIFF; + } + } } use crate::db::DbConn; @@ -265,9 +288,10 @@ impl UserOrganization { pub async fn to_json(&self, conn: &DbConn) -> Value { let org = Organization::find_by_uuid(&self.org_uuid, conn).await.unwrap(); + // https://github.com/bitwarden/server/blob/13d1e74d6960cf0d042620b72d85bf583a4236f7/src/Api/Models/Response/ProfileOrganizationResponseModel.cs json!({ "Id": self.org_uuid, - "Identifier": null, // not supported by us + "Identifier": null, // Not supported "Name": org.name, "Seats": 10, // The value doesn't matter, we don't check server-side "MaxCollections": 10, // The value doesn't matter, we don't check server-side @@ -275,44 +299,48 @@ impl UserOrganization { "Use2fa": true, "UseDirectory": false, // Is supported, but this value isn't checked anywhere (yet) - "UseEvents": false, // not supported by us + "UseEvents": false, // Not supported "UseGroups": true, "UseTotp": true, + // "UseScim": false, // Not supported (Not AGPLv3 Licensed) "UsePolicies": true, - "UseApi": false, // not supported by us + "UseApi": false, // Not supported "SelfHost": true, "HasPublicAndPrivateKeys": org.private_key.is_some() && org.public_key.is_some(), - "ResetPasswordEnrolled": false, // not supported by us - "SsoBound": false, // We do not support SSO - "UseSso": false, // We do not support SSO - // TODO: Add support for Business Portal - // Upstream is moving Policies and SSO management outside of the web-vault to /portal - // For now they still have that code also in the web-vault, but they will remove it at some point. - // https://github.com/bitwarden/server/tree/master/bitwarden_license/src/ - "UseBusinessPortal": false, // Disable BusinessPortal Button + "ResetPasswordEnrolled": false, // Not supported + "SsoBound": false, // Not supported + "UseSso": false, // Not supported "ProviderId": null, "ProviderName": null, + // "KeyConnectorEnabled": false, + // "KeyConnectorUrl": null, // TODO: Add support for Custom User Roles // See: https://bitwarden.com/help/article/user-types-access-control/#custom-role // "Permissions": { - // "AccessBusinessPortal": false, - // "AccessEventLogs": false, + // "AccessEventLogs": false, // Not supported // "AccessImportExport": false, // "AccessReports": false, // "ManageAllCollections": false, + // "CreateNewCollections": false, + // "EditAnyCollection": false, + // "DeleteAnyCollection": false, // "ManageAssignedCollections": false, + // "editAssignedCollections": false, + // "deleteAssignedCollections": false, // "ManageCiphers": false, - // "ManageGroups": false, + // "ManageGroups": false, // Not supported // "ManagePolicies": false, - // "ManageResetPassword": false, - // "ManageSso": false, + // "ManageResetPassword": false, // Not supported + // "ManageSso": false, // Not supported // "ManageUsers": false, + // "ManageScim": false, // Not supported (Not AGPLv3 Licensed) // }, "MaxStorageGb": 10, // The value doesn't matter, we don't check server-side // These are per user + "UserId": self.user_uuid, "Key": self.akey, "Status": self.status, "Type": self.atype, @@ -325,13 +353,21 @@ impl UserOrganization { pub async fn to_json_user_details(&self, conn: &DbConn) -> Value { let user = User::find_by_uuid(&self.user_uuid, conn).await.unwrap(); + // Because BitWarden want the status to be -1 for revoked users we need to catch that here. + // We subtract/add a number so we can restore/activate the user to it's previouse state again. + let status = if self.status < UserOrgStatus::Revoked as i32 { + UserOrgStatus::Revoked as i32 + } else { + self.status + }; + json!({ "Id": self.uuid, "UserId": self.user_uuid, "Name": user.name, "Email": user.email, - "Status": self.status, + "Status": status, "Type": self.atype, "AccessAll": self.access_all, @@ -365,11 +401,19 @@ impl UserOrganization { .collect() }; + // Because BitWarden want the status to be -1 for revoked users we need to catch that here. + // We subtract/add a number so we can restore/activate the user to it's previouse state again. + let status = if self.status < UserOrgStatus::Revoked as i32 { + UserOrgStatus::Revoked as i32 + } else { + self.status + }; + json!({ "Id": self.uuid, "UserId": self.user_uuid, - "Status": self.status, + "Status": status, "Type": self.atype, "AccessAll": self.access_all, "Collections": coll_uuids, @@ -508,6 +552,18 @@ impl UserOrganization { }} } + pub async fn count_accepted_and_confirmed_by_user(user_uuid: &str, conn: &DbConn) -> i64 { + db_run! { conn: { + users_organizations::table + .filter(users_organizations::user_uuid.eq(user_uuid)) + .filter(users_organizations::status.eq(UserOrgStatus::Accepted as i32)) + .or_filter(users_organizations::status.eq(UserOrgStatus::Confirmed as i32)) + .count() + .first::(conn) + .unwrap_or(0) + }} + } + pub async fn find_by_org(org_uuid: &str, conn: &DbConn) -> Vec { db_run! { conn: { users_organizations::table @@ -528,16 +584,28 @@ impl UserOrganization { }} } - pub async fn find_by_org_and_type(org_uuid: &str, atype: i32, conn: &DbConn) -> Vec { + pub async fn find_by_org_and_type(org_uuid: &str, atype: UserOrgType, conn: &DbConn) -> Vec { db_run! { conn: { users_organizations::table .filter(users_organizations::org_uuid.eq(org_uuid)) - .filter(users_organizations::atype.eq(atype)) + .filter(users_organizations::atype.eq(atype as i32)) .load::(conn) .expect("Error loading user organizations").from_db() }} } + pub async fn count_confirmed_by_org_and_type(org_uuid: &str, atype: UserOrgType, conn: &DbConn) -> i64 { + db_run! { conn: { + users_organizations::table + .filter(users_organizations::org_uuid.eq(org_uuid)) + .filter(users_organizations::atype.eq(atype as i32)) + .filter(users_organizations::status.eq(UserOrgStatus::Confirmed as i32)) + .count() + .first::(conn) + .unwrap_or(0) + }} + } + pub async fn find_by_user_and_org(user_uuid: &str, org_uuid: &str, conn: &DbConn) -> Option { db_run! { conn: { users_organizations::table diff --git a/src/db/models/user.rs b/src/db/models/user.rs index a8d27060..9e692a3f 100644 --- a/src/db/models/user.rs +++ b/src/db/models/user.rs @@ -275,11 +275,11 @@ impl User { pub async fn delete(self, conn: &DbConn) -> EmptyResult { for user_org in UserOrganization::find_confirmed_by_user(&self.uuid, conn).await { - if user_org.atype == UserOrgType::Owner { - let owner_type = UserOrgType::Owner as i32; - if UserOrganization::find_by_org_and_type(&user_org.org_uuid, owner_type, conn).await.len() <= 1 { - err!("Can't delete last owner") - } + if user_org.atype == UserOrgType::Owner + && UserOrganization::count_confirmed_by_org_and_type(&user_org.org_uuid, UserOrgType::Owner, conn).await + <= 1 + { + err!("Can't delete last owner") } } diff --git a/src/static/scripts/bootstrap.css b/src/static/scripts/bootstrap.css index ddf519cc..3e4ae582 100644 --- a/src/static/scripts/bootstrap.css +++ b/src/static/scripts/bootstrap.css @@ -1,6 +1,6 @@ @charset "UTF-8"; /*! - * Bootstrap v5.2.0-beta1 (https://getbootstrap.com/) + * Bootstrap v5.2.0 (https://getbootstrap.com/) * Copyright 2011-2022 The Bootstrap Authors * Copyright 2011-2022 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) @@ -68,7 +68,6 @@ --bs-border-radius-xl: 1rem; --bs-border-radius-2xl: 2rem; --bs-border-radius-pill: 50rem; - --bs-heading-color: ; --bs-link-color: #0d6efd; --bs-link-hover-color: #0a58ca; --bs-code-color: #d63384; @@ -113,7 +112,6 @@ h6, .h6, h5, .h5, h4, .h4, h3, .h3, h2, .h2, h1, .h1 { margin-bottom: 0.5rem; font-weight: 500; line-height: 1.2; - color: var(--bs-heading-color); } h1, .h1 { @@ -313,7 +311,7 @@ table { caption { padding-top: 0.5rem; padding-bottom: 0.5rem; - color: rgba(var(--bs-body-color-rgb), 0.75); + color: #6c757d; text-align: left; } @@ -898,210 +896,166 @@ progress { .col-sm { flex: 1 0 0%; } - .row-cols-sm-auto > * { flex: 0 0 auto; width: auto; } - .row-cols-sm-1 > * { flex: 0 0 auto; width: 100%; } - .row-cols-sm-2 > * { flex: 0 0 auto; width: 50%; } - .row-cols-sm-3 > * { flex: 0 0 auto; width: 33.3333333333%; } - .row-cols-sm-4 > * { flex: 0 0 auto; width: 25%; } - .row-cols-sm-5 > * { flex: 0 0 auto; width: 20%; } - .row-cols-sm-6 > * { flex: 0 0 auto; width: 16.6666666667%; } - .col-sm-auto { flex: 0 0 auto; width: auto; } - .col-sm-1 { flex: 0 0 auto; width: 8.33333333%; } - .col-sm-2 { flex: 0 0 auto; width: 16.66666667%; } - .col-sm-3 { flex: 0 0 auto; width: 25%; } - .col-sm-4 { flex: 0 0 auto; width: 33.33333333%; } - .col-sm-5 { flex: 0 0 auto; width: 41.66666667%; } - .col-sm-6 { flex: 0 0 auto; width: 50%; } - .col-sm-7 { flex: 0 0 auto; width: 58.33333333%; } - .col-sm-8 { flex: 0 0 auto; width: 66.66666667%; } - .col-sm-9 { flex: 0 0 auto; width: 75%; } - .col-sm-10 { flex: 0 0 auto; width: 83.33333333%; } - .col-sm-11 { flex: 0 0 auto; width: 91.66666667%; } - .col-sm-12 { flex: 0 0 auto; width: 100%; } - .offset-sm-0 { margin-left: 0; } - .offset-sm-1 { margin-left: 8.33333333%; } - .offset-sm-2 { margin-left: 16.66666667%; } - .offset-sm-3 { margin-left: 25%; } - .offset-sm-4 { margin-left: 33.33333333%; } - .offset-sm-5 { margin-left: 41.66666667%; } - .offset-sm-6 { margin-left: 50%; } - .offset-sm-7 { margin-left: 58.33333333%; } - .offset-sm-8 { margin-left: 66.66666667%; } - .offset-sm-9 { margin-left: 75%; } - .offset-sm-10 { margin-left: 83.33333333%; } - .offset-sm-11 { margin-left: 91.66666667%; } - .g-sm-0, .gx-sm-0 { --bs-gutter-x: 0; } - .g-sm-0, .gy-sm-0 { --bs-gutter-y: 0; } - .g-sm-1, .gx-sm-1 { --bs-gutter-x: 0.25rem; } - .g-sm-1, .gy-sm-1 { --bs-gutter-y: 0.25rem; } - .g-sm-2, .gx-sm-2 { --bs-gutter-x: 0.5rem; } - .g-sm-2, .gy-sm-2 { --bs-gutter-y: 0.5rem; } - .g-sm-3, .gx-sm-3 { --bs-gutter-x: 1rem; } - .g-sm-3, .gy-sm-3 { --bs-gutter-y: 1rem; } - .g-sm-4, .gx-sm-4 { --bs-gutter-x: 1.5rem; } - .g-sm-4, .gy-sm-4 { --bs-gutter-y: 1.5rem; } - .g-sm-5, .gx-sm-5 { --bs-gutter-x: 3rem; } - .g-sm-5, .gy-sm-5 { --bs-gutter-y: 3rem; @@ -1111,210 +1065,166 @@ progress { .col-md { flex: 1 0 0%; } - .row-cols-md-auto > * { flex: 0 0 auto; width: auto; } - .row-cols-md-1 > * { flex: 0 0 auto; width: 100%; } - .row-cols-md-2 > * { flex: 0 0 auto; width: 50%; } - .row-cols-md-3 > * { flex: 0 0 auto; width: 33.3333333333%; } - .row-cols-md-4 > * { flex: 0 0 auto; width: 25%; } - .row-cols-md-5 > * { flex: 0 0 auto; width: 20%; } - .row-cols-md-6 > * { flex: 0 0 auto; width: 16.6666666667%; } - .col-md-auto { flex: 0 0 auto; width: auto; } - .col-md-1 { flex: 0 0 auto; width: 8.33333333%; } - .col-md-2 { flex: 0 0 auto; width: 16.66666667%; } - .col-md-3 { flex: 0 0 auto; width: 25%; } - .col-md-4 { flex: 0 0 auto; width: 33.33333333%; } - .col-md-5 { flex: 0 0 auto; width: 41.66666667%; } - .col-md-6 { flex: 0 0 auto; width: 50%; } - .col-md-7 { flex: 0 0 auto; width: 58.33333333%; } - .col-md-8 { flex: 0 0 auto; width: 66.66666667%; } - .col-md-9 { flex: 0 0 auto; width: 75%; } - .col-md-10 { flex: 0 0 auto; width: 83.33333333%; } - .col-md-11 { flex: 0 0 auto; width: 91.66666667%; } - .col-md-12 { flex: 0 0 auto; width: 100%; } - .offset-md-0 { margin-left: 0; } - .offset-md-1 { margin-left: 8.33333333%; } - .offset-md-2 { margin-left: 16.66666667%; } - .offset-md-3 { margin-left: 25%; } - .offset-md-4 { margin-left: 33.33333333%; } - .offset-md-5 { margin-left: 41.66666667%; } - .offset-md-6 { margin-left: 50%; } - .offset-md-7 { margin-left: 58.33333333%; } - .offset-md-8 { margin-left: 66.66666667%; } - .offset-md-9 { margin-left: 75%; } - .offset-md-10 { margin-left: 83.33333333%; } - .offset-md-11 { margin-left: 91.66666667%; } - .g-md-0, .gx-md-0 { --bs-gutter-x: 0; } - .g-md-0, .gy-md-0 { --bs-gutter-y: 0; } - .g-md-1, .gx-md-1 { --bs-gutter-x: 0.25rem; } - .g-md-1, .gy-md-1 { --bs-gutter-y: 0.25rem; } - .g-md-2, .gx-md-2 { --bs-gutter-x: 0.5rem; } - .g-md-2, .gy-md-2 { --bs-gutter-y: 0.5rem; } - .g-md-3, .gx-md-3 { --bs-gutter-x: 1rem; } - .g-md-3, .gy-md-3 { --bs-gutter-y: 1rem; } - .g-md-4, .gx-md-4 { --bs-gutter-x: 1.5rem; } - .g-md-4, .gy-md-4 { --bs-gutter-y: 1.5rem; } - .g-md-5, .gx-md-5 { --bs-gutter-x: 3rem; } - .g-md-5, .gy-md-5 { --bs-gutter-y: 3rem; @@ -1324,210 +1234,166 @@ progress { .col-lg { flex: 1 0 0%; } - .row-cols-lg-auto > * { flex: 0 0 auto; width: auto; } - .row-cols-lg-1 > * { flex: 0 0 auto; width: 100%; } - .row-cols-lg-2 > * { flex: 0 0 auto; width: 50%; } - .row-cols-lg-3 > * { flex: 0 0 auto; width: 33.3333333333%; } - .row-cols-lg-4 > * { flex: 0 0 auto; width: 25%; } - .row-cols-lg-5 > * { flex: 0 0 auto; width: 20%; } - .row-cols-lg-6 > * { flex: 0 0 auto; width: 16.6666666667%; } - .col-lg-auto { flex: 0 0 auto; width: auto; } - .col-lg-1 { flex: 0 0 auto; width: 8.33333333%; } - .col-lg-2 { flex: 0 0 auto; width: 16.66666667%; } - .col-lg-3 { flex: 0 0 auto; width: 25%; } - .col-lg-4 { flex: 0 0 auto; width: 33.33333333%; } - .col-lg-5 { flex: 0 0 auto; width: 41.66666667%; } - .col-lg-6 { flex: 0 0 auto; width: 50%; } - .col-lg-7 { flex: 0 0 auto; width: 58.33333333%; } - .col-lg-8 { flex: 0 0 auto; width: 66.66666667%; } - .col-lg-9 { flex: 0 0 auto; width: 75%; } - .col-lg-10 { flex: 0 0 auto; width: 83.33333333%; } - .col-lg-11 { flex: 0 0 auto; width: 91.66666667%; } - .col-lg-12 { flex: 0 0 auto; width: 100%; } - .offset-lg-0 { margin-left: 0; } - .offset-lg-1 { margin-left: 8.33333333%; } - .offset-lg-2 { margin-left: 16.66666667%; } - .offset-lg-3 { margin-left: 25%; } - .offset-lg-4 { margin-left: 33.33333333%; } - .offset-lg-5 { margin-left: 41.66666667%; } - .offset-lg-6 { margin-left: 50%; } - .offset-lg-7 { margin-left: 58.33333333%; } - .offset-lg-8 { margin-left: 66.66666667%; } - .offset-lg-9 { margin-left: 75%; } - .offset-lg-10 { margin-left: 83.33333333%; } - .offset-lg-11 { margin-left: 91.66666667%; } - .g-lg-0, .gx-lg-0 { --bs-gutter-x: 0; } - .g-lg-0, .gy-lg-0 { --bs-gutter-y: 0; } - .g-lg-1, .gx-lg-1 { --bs-gutter-x: 0.25rem; } - .g-lg-1, .gy-lg-1 { --bs-gutter-y: 0.25rem; } - .g-lg-2, .gx-lg-2 { --bs-gutter-x: 0.5rem; } - .g-lg-2, .gy-lg-2 { --bs-gutter-y: 0.5rem; } - .g-lg-3, .gx-lg-3 { --bs-gutter-x: 1rem; } - .g-lg-3, .gy-lg-3 { --bs-gutter-y: 1rem; } - .g-lg-4, .gx-lg-4 { --bs-gutter-x: 1.5rem; } - .g-lg-4, .gy-lg-4 { --bs-gutter-y: 1.5rem; } - .g-lg-5, .gx-lg-5 { --bs-gutter-x: 3rem; } - .g-lg-5, .gy-lg-5 { --bs-gutter-y: 3rem; @@ -1537,210 +1403,166 @@ progress { .col-xl { flex: 1 0 0%; } - .row-cols-xl-auto > * { flex: 0 0 auto; width: auto; } - .row-cols-xl-1 > * { flex: 0 0 auto; width: 100%; } - .row-cols-xl-2 > * { flex: 0 0 auto; width: 50%; } - .row-cols-xl-3 > * { flex: 0 0 auto; width: 33.3333333333%; } - .row-cols-xl-4 > * { flex: 0 0 auto; width: 25%; } - .row-cols-xl-5 > * { flex: 0 0 auto; width: 20%; } - .row-cols-xl-6 > * { flex: 0 0 auto; width: 16.6666666667%; } - .col-xl-auto { flex: 0 0 auto; width: auto; } - .col-xl-1 { flex: 0 0 auto; width: 8.33333333%; } - .col-xl-2 { flex: 0 0 auto; width: 16.66666667%; } - .col-xl-3 { flex: 0 0 auto; width: 25%; } - .col-xl-4 { flex: 0 0 auto; width: 33.33333333%; } - .col-xl-5 { flex: 0 0 auto; width: 41.66666667%; } - .col-xl-6 { flex: 0 0 auto; width: 50%; } - .col-xl-7 { flex: 0 0 auto; width: 58.33333333%; } - .col-xl-8 { flex: 0 0 auto; width: 66.66666667%; } - .col-xl-9 { flex: 0 0 auto; width: 75%; } - .col-xl-10 { flex: 0 0 auto; width: 83.33333333%; } - .col-xl-11 { flex: 0 0 auto; width: 91.66666667%; } - .col-xl-12 { flex: 0 0 auto; width: 100%; } - .offset-xl-0 { margin-left: 0; } - .offset-xl-1 { margin-left: 8.33333333%; } - .offset-xl-2 { margin-left: 16.66666667%; } - .offset-xl-3 { margin-left: 25%; } - .offset-xl-4 { margin-left: 33.33333333%; } - .offset-xl-5 { margin-left: 41.66666667%; } - .offset-xl-6 { margin-left: 50%; } - .offset-xl-7 { margin-left: 58.33333333%; } - .offset-xl-8 { margin-left: 66.66666667%; } - .offset-xl-9 { margin-left: 75%; } - .offset-xl-10 { margin-left: 83.33333333%; } - .offset-xl-11 { margin-left: 91.66666667%; } - .g-xl-0, .gx-xl-0 { --bs-gutter-x: 0; } - .g-xl-0, .gy-xl-0 { --bs-gutter-y: 0; } - .g-xl-1, .gx-xl-1 { --bs-gutter-x: 0.25rem; } - .g-xl-1, .gy-xl-1 { --bs-gutter-y: 0.25rem; } - .g-xl-2, .gx-xl-2 { --bs-gutter-x: 0.5rem; } - .g-xl-2, .gy-xl-2 { --bs-gutter-y: 0.5rem; } - .g-xl-3, .gx-xl-3 { --bs-gutter-x: 1rem; } - .g-xl-3, .gy-xl-3 { --bs-gutter-y: 1rem; } - .g-xl-4, .gx-xl-4 { --bs-gutter-x: 1.5rem; } - .g-xl-4, .gy-xl-4 { --bs-gutter-y: 1.5rem; } - .g-xl-5, .gx-xl-5 { --bs-gutter-x: 3rem; } - .g-xl-5, .gy-xl-5 { --bs-gutter-y: 3rem; @@ -1750,210 +1572,166 @@ progress { .col-xxl { flex: 1 0 0%; } - .row-cols-xxl-auto > * { flex: 0 0 auto; width: auto; } - .row-cols-xxl-1 > * { flex: 0 0 auto; width: 100%; } - .row-cols-xxl-2 > * { flex: 0 0 auto; width: 50%; } - .row-cols-xxl-3 > * { flex: 0 0 auto; width: 33.3333333333%; } - .row-cols-xxl-4 > * { flex: 0 0 auto; width: 25%; } - .row-cols-xxl-5 > * { flex: 0 0 auto; width: 20%; } - .row-cols-xxl-6 > * { flex: 0 0 auto; width: 16.6666666667%; } - .col-xxl-auto { flex: 0 0 auto; width: auto; } - .col-xxl-1 { flex: 0 0 auto; width: 8.33333333%; } - .col-xxl-2 { flex: 0 0 auto; width: 16.66666667%; } - .col-xxl-3 { flex: 0 0 auto; width: 25%; } - .col-xxl-4 { flex: 0 0 auto; width: 33.33333333%; } - .col-xxl-5 { flex: 0 0 auto; width: 41.66666667%; } - .col-xxl-6 { flex: 0 0 auto; width: 50%; } - .col-xxl-7 { flex: 0 0 auto; width: 58.33333333%; } - .col-xxl-8 { flex: 0 0 auto; width: 66.66666667%; } - .col-xxl-9 { flex: 0 0 auto; width: 75%; } - .col-xxl-10 { flex: 0 0 auto; width: 83.33333333%; } - .col-xxl-11 { flex: 0 0 auto; width: 91.66666667%; } - .col-xxl-12 { flex: 0 0 auto; width: 100%; } - .offset-xxl-0 { margin-left: 0; } - .offset-xxl-1 { margin-left: 8.33333333%; } - .offset-xxl-2 { margin-left: 16.66666667%; } - .offset-xxl-3 { margin-left: 25%; } - .offset-xxl-4 { margin-left: 33.33333333%; } - .offset-xxl-5 { margin-left: 41.66666667%; } - .offset-xxl-6 { margin-left: 50%; } - .offset-xxl-7 { margin-left: 58.33333333%; } - .offset-xxl-8 { margin-left: 66.66666667%; } - .offset-xxl-9 { margin-left: 75%; } - .offset-xxl-10 { margin-left: 83.33333333%; } - .offset-xxl-11 { margin-left: 91.66666667%; } - .g-xxl-0, .gx-xxl-0 { --bs-gutter-x: 0; } - .g-xxl-0, .gy-xxl-0 { --bs-gutter-y: 0; } - .g-xxl-1, .gx-xxl-1 { --bs-gutter-x: 0.25rem; } - .g-xxl-1, .gy-xxl-1 { --bs-gutter-y: 0.25rem; } - .g-xxl-2, .gx-xxl-2 { --bs-gutter-x: 0.5rem; } - .g-xxl-2, .gy-xxl-2 { --bs-gutter-y: 0.5rem; } - .g-xxl-3, .gx-xxl-3 { --bs-gutter-x: 1rem; } - .g-xxl-3, .gy-xxl-3 { --bs-gutter-y: 1rem; } - .g-xxl-4, .gx-xxl-4 { --bs-gutter-x: 1.5rem; } - .g-xxl-4, .gy-xxl-4 { --bs-gutter-y: 1.5rem; } - .g-xxl-5, .gx-xxl-5 { --bs-gutter-x: 3rem; } - .g-xxl-5, .gy-xxl-5 { --bs-gutter-y: 3rem; @@ -2209,7 +1987,7 @@ progress { .form-text { margin-top: 0.25rem; font-size: 0.875em; - color: rgba(var(--bs-body-color-rgb), 0.75); + color: #6c757d; } .form-control { @@ -2258,7 +2036,7 @@ progress { color: #6c757d; opacity: 1; } -.form-control:disabled, .form-control[readonly] { +.form-control:disabled { background-color: #e9ecef; opacity: 1; } @@ -2320,6 +2098,9 @@ progress { border: solid transparent; border-width: 1px 0; } +.form-control-plaintext:focus { + outline: 0; +} .form-control-plaintext.form-control-sm, .form-control-plaintext.form-control-lg { padding-right: 0; padding-left: 0; @@ -2375,20 +2156,25 @@ textarea.form-control-lg { .form-control-color { width: 3rem; - height: auto; + height: calc(1.5em + 0.75rem + 2px); padding: 0.375rem; } .form-control-color:not(:disabled):not([readonly]) { cursor: pointer; } .form-control-color::-moz-color-swatch { - height: 1.5em; + border: 0 !important; border-radius: 0.375rem; } .form-control-color::-webkit-color-swatch { - height: 1.5em; border-radius: 0.375rem; } +.form-control-color.form-control-sm { + height: calc(1.5em + 0.5rem + 2px); +} +.form-control-color.form-control-lg { + height: calc(1.5em + 1rem + 2px); +} .form-select { display: block; @@ -2678,8 +2464,12 @@ textarea.form-control-lg { position: absolute; top: 0; left: 0; + width: 100%; height: 100%; padding: 1rem 0.75rem; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; pointer-events: none; border: 1px solid transparent; transform-origin: 0 0; @@ -2747,14 +2537,16 @@ textarea.form-control-lg { width: 100%; } .input-group > .form-control, -.input-group > .form-select { +.input-group > .form-select, +.input-group > .form-floating { position: relative; flex: 1 1 auto; width: 1%; min-width: 0; } .input-group > .form-control:focus, -.input-group > .form-select:focus { +.input-group > .form-select:focus, +.input-group > .form-floating:focus-within { z-index: 3; } .input-group .btn { @@ -2803,17 +2595,23 @@ textarea.form-control-lg { padding-right: 3rem; } -.input-group:not(.has-validation) > :not(:last-child):not(.dropdown-toggle):not(.dropdown-menu), -.input-group:not(.has-validation) > .dropdown-toggle:nth-last-child(n+3) { +.input-group:not(.has-validation) > :not(:last-child):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating), +.input-group:not(.has-validation) > .dropdown-toggle:nth-last-child(n+3), +.input-group:not(.has-validation) > .form-floating:not(:last-child) > .form-control, +.input-group:not(.has-validation) > .form-floating:not(:last-child) > .form-select { border-top-right-radius: 0; border-bottom-right-radius: 0; } -.input-group.has-validation > :nth-last-child(n+3):not(.dropdown-toggle):not(.dropdown-menu), -.input-group.has-validation > .dropdown-toggle:nth-last-child(n+4) { +.input-group.has-validation > :nth-last-child(n+3):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating), +.input-group.has-validation > .dropdown-toggle:nth-last-child(n+4), +.input-group.has-validation > .form-floating:nth-last-child(n+3) > .form-control, +.input-group.has-validation > .form-floating:nth-last-child(n+3) > .form-select { border-top-right-radius: 0; border-bottom-right-radius: 0; } -.input-group > :not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback) { +.input-group > :not(:first-child):not(.dropdown-menu):not(.form-floating):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback), +.input-group > .form-floating:not(:first-child) > .form-control, +.input-group > .form-floating:not(:first-child) > .form-select { margin-left: -1px; border-top-left-radius: 0; border-bottom-left-radius: 0; @@ -3179,12 +2977,12 @@ textarea.form-control-lg { --bs-btn-bg: #f8f9fa; --bs-btn-border-color: #f8f9fa; --bs-btn-hover-color: #000; - --bs-btn-hover-bg: #f9fafb; - --bs-btn-hover-border-color: #f9fafb; + --bs-btn-hover-bg: #d3d4d5; + --bs-btn-hover-border-color: #c6c7c8; --bs-btn-focus-shadow-rgb: 211, 212, 213; --bs-btn-active-color: #000; - --bs-btn-active-bg: #f9fafb; - --bs-btn-active-border-color: #f9fafb; + --bs-btn-active-bg: #c6c7c8; + --bs-btn-active-border-color: #babbbc; --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); --bs-btn-disabled-color: #000; --bs-btn-disabled-bg: #f8f9fa; @@ -3196,12 +2994,12 @@ textarea.form-control-lg { --bs-btn-bg: #212529; --bs-btn-border-color: #212529; --bs-btn-hover-color: #fff; - --bs-btn-hover-bg: #1c1f23; - --bs-btn-hover-border-color: #1a1e21; + --bs-btn-hover-bg: #424649; + --bs-btn-hover-border-color: #373b3e; --bs-btn-focus-shadow-rgb: 66, 70, 73; --bs-btn-active-color: #fff; - --bs-btn-active-bg: #1a1e21; - --bs-btn-active-border-color: #191c1f; + --bs-btn-active-bg: #4d5154; + --bs-btn-active-border-color: #373b3e; --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); --bs-btn-disabled-color: #fff; --bs-btn-disabled-bg: #212529; @@ -3221,6 +3019,7 @@ textarea.form-control-lg { --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); --bs-btn-disabled-color: #0d6efd; --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #0d6efd; --bs-gradient: none; } @@ -3237,6 +3036,7 @@ textarea.form-control-lg { --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); --bs-btn-disabled-color: #6c757d; --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #6c757d; --bs-gradient: none; } @@ -3253,6 +3053,7 @@ textarea.form-control-lg { --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); --bs-btn-disabled-color: #198754; --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #198754; --bs-gradient: none; } @@ -3269,6 +3070,7 @@ textarea.form-control-lg { --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); --bs-btn-disabled-color: #0dcaf0; --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #0dcaf0; --bs-gradient: none; } @@ -3285,6 +3087,7 @@ textarea.form-control-lg { --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); --bs-btn-disabled-color: #ffc107; --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #ffc107; --bs-gradient: none; } @@ -3301,6 +3104,7 @@ textarea.form-control-lg { --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); --bs-btn-disabled-color: #dc3545; --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #dc3545; --bs-gradient: none; } @@ -3317,6 +3121,7 @@ textarea.form-control-lg { --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); --bs-btn-disabled-color: #f8f9fa; --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #f8f9fa; --bs-gradient: none; } @@ -3333,6 +3138,7 @@ textarea.form-control-lg { --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); --bs-btn-disabled-color: #212529; --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #212529; --bs-gradient: none; } @@ -3343,12 +3149,21 @@ textarea.form-control-lg { --bs-btn-border-color: transparent; --bs-btn-hover-color: var(--bs-link-hover-color); --bs-btn-hover-border-color: transparent; + --bs-btn-active-color: var(--bs-link-hover-color); --bs-btn-active-border-color: transparent; --bs-btn-disabled-color: #6c757d; --bs-btn-disabled-border-color: transparent; --bs-btn-box-shadow: none; + --bs-btn-focus-shadow-rgb: 49, 132, 253; text-decoration: underline; } +.btn-link:focus { + color: var(--bs-btn-color); +} +.btn-link:hover { + color: var(--bs-btn-hover-color); +} + .btn-lg, .btn-group-lg > .btn { --bs-btn-padding-y: 0.5rem; --bs-btn-padding-x: 1rem; @@ -3497,7 +3312,6 @@ textarea.form-control-lg { right: auto; left: 0; } - .dropdown-menu-sm-end { --bs-position: end; } @@ -3514,7 +3328,6 @@ textarea.form-control-lg { right: auto; left: 0; } - .dropdown-menu-md-end { --bs-position: end; } @@ -3531,7 +3344,6 @@ textarea.form-control-lg { right: auto; left: 0; } - .dropdown-menu-lg-end { --bs-position: end; } @@ -3548,7 +3360,6 @@ textarea.form-control-lg { right: auto; left: 0; } - .dropdown-menu-xl-end { --bs-position: end; } @@ -3565,7 +3376,6 @@ textarea.form-control-lg { right: auto; left: 0; } - .dropdown-menu-xxl-end { --bs-position: end; } @@ -3997,6 +3807,7 @@ textarea.form-control-lg { .navbar-nav { --bs-nav-link-padding-x: 0; --bs-nav-link-padding-y: 0.5rem; + --bs-nav-link-font-weight: ; --bs-nav-link-color: var(--bs-navbar-color); --bs-nav-link-hover-color: var(--bs-navbar-hover-color); --bs-nav-link-disabled-color: var(--bs-navbar-disabled-color); @@ -4822,7 +4633,7 @@ textarea.form-control-lg { text-align: center; white-space: nowrap; vertical-align: baseline; - border-radius: var(--bs-badge-border-radius, 0); + border-radius: var(--bs-badge-border-radius); } .badge:empty { display: none; @@ -4848,7 +4659,7 @@ textarea.form-control-lg { color: var(--bs-alert-color); background-color: var(--bs-alert-bg); border: var(--bs-alert-border); - border-radius: var(--bs-alert-border-radius, 0); + border-radius: var(--bs-alert-border-radius); } .alert-heading { @@ -5607,13 +5418,11 @@ textarea.form-control-lg { --bs-modal-margin: 1.75rem; --bs-modal-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15); } - .modal-dialog { max-width: var(--bs-modal-width); margin-right: auto; margin-left: auto; } - .modal-sm { --bs-modal-width: 300px; } @@ -5848,7 +5657,7 @@ textarea.form-control-lg { color: var(--bs-tooltip-color); text-align: center; background-color: var(--bs-tooltip-bg); - border-radius: var(--bs-tooltip-border-radius, 0); + border-radius: var(--bs-tooltip-border-radius); } .popover { @@ -6326,16 +6135,6 @@ textarea.form-control-lg { transition: none; } } -@media (max-width: 575.98px) { - .offcanvas-sm.showing, .offcanvas-sm.show:not(.hiding) { - transform: none; - } -} -@media (max-width: 575.98px) { - .offcanvas-sm.showing, .offcanvas-sm.hiding, .offcanvas-sm.show { - visibility: visible; - } -} @media (max-width: 575.98px) { .offcanvas-sm.offcanvas-start { top: 0; @@ -6375,6 +6174,16 @@ textarea.form-control-lg { transform: translateY(100%); } } +@media (max-width: 575.98px) { + .offcanvas-sm.showing, .offcanvas-sm.show:not(.hiding) { + transform: none; + } +} +@media (max-width: 575.98px) { + .offcanvas-sm.showing, .offcanvas-sm.hiding, .offcanvas-sm.show { + visibility: visible; + } +} @media (min-width: 576px) { .offcanvas-sm { --bs-offcanvas-height: auto; @@ -6414,16 +6223,6 @@ textarea.form-control-lg { transition: none; } } -@media (max-width: 767.98px) { - .offcanvas-md.showing, .offcanvas-md.show:not(.hiding) { - transform: none; - } -} -@media (max-width: 767.98px) { - .offcanvas-md.showing, .offcanvas-md.hiding, .offcanvas-md.show { - visibility: visible; - } -} @media (max-width: 767.98px) { .offcanvas-md.offcanvas-start { top: 0; @@ -6463,6 +6262,16 @@ textarea.form-control-lg { transform: translateY(100%); } } +@media (max-width: 767.98px) { + .offcanvas-md.showing, .offcanvas-md.show:not(.hiding) { + transform: none; + } +} +@media (max-width: 767.98px) { + .offcanvas-md.showing, .offcanvas-md.hiding, .offcanvas-md.show { + visibility: visible; + } +} @media (min-width: 768px) { .offcanvas-md { --bs-offcanvas-height: auto; @@ -6502,16 +6311,6 @@ textarea.form-control-lg { transition: none; } } -@media (max-width: 991.98px) { - .offcanvas-lg.showing, .offcanvas-lg.show:not(.hiding) { - transform: none; - } -} -@media (max-width: 991.98px) { - .offcanvas-lg.showing, .offcanvas-lg.hiding, .offcanvas-lg.show { - visibility: visible; - } -} @media (max-width: 991.98px) { .offcanvas-lg.offcanvas-start { top: 0; @@ -6551,6 +6350,16 @@ textarea.form-control-lg { transform: translateY(100%); } } +@media (max-width: 991.98px) { + .offcanvas-lg.showing, .offcanvas-lg.show:not(.hiding) { + transform: none; + } +} +@media (max-width: 991.98px) { + .offcanvas-lg.showing, .offcanvas-lg.hiding, .offcanvas-lg.show { + visibility: visible; + } +} @media (min-width: 992px) { .offcanvas-lg { --bs-offcanvas-height: auto; @@ -6590,16 +6399,6 @@ textarea.form-control-lg { transition: none; } } -@media (max-width: 1199.98px) { - .offcanvas-xl.showing, .offcanvas-xl.show:not(.hiding) { - transform: none; - } -} -@media (max-width: 1199.98px) { - .offcanvas-xl.showing, .offcanvas-xl.hiding, .offcanvas-xl.show { - visibility: visible; - } -} @media (max-width: 1199.98px) { .offcanvas-xl.offcanvas-start { top: 0; @@ -6639,6 +6438,16 @@ textarea.form-control-lg { transform: translateY(100%); } } +@media (max-width: 1199.98px) { + .offcanvas-xl.showing, .offcanvas-xl.show:not(.hiding) { + transform: none; + } +} +@media (max-width: 1199.98px) { + .offcanvas-xl.showing, .offcanvas-xl.hiding, .offcanvas-xl.show { + visibility: visible; + } +} @media (min-width: 1200px) { .offcanvas-xl { --bs-offcanvas-height: auto; @@ -6678,16 +6487,6 @@ textarea.form-control-lg { transition: none; } } -@media (max-width: 1399.98px) { - .offcanvas-xxl.showing, .offcanvas-xxl.show:not(.hiding) { - transform: none; - } -} -@media (max-width: 1399.98px) { - .offcanvas-xxl.showing, .offcanvas-xxl.hiding, .offcanvas-xxl.show { - visibility: visible; - } -} @media (max-width: 1399.98px) { .offcanvas-xxl.offcanvas-start { top: 0; @@ -6727,6 +6526,16 @@ textarea.form-control-lg { transform: translateY(100%); } } +@media (max-width: 1399.98px) { + .offcanvas-xxl.showing, .offcanvas-xxl.show:not(.hiding) { + transform: none; + } +} +@media (max-width: 1399.98px) { + .offcanvas-xxl.showing, .offcanvas-xxl.hiding, .offcanvas-xxl.show { + visibility: visible; + } +} @media (min-width: 1400px) { .offcanvas-xxl { --bs-offcanvas-height: auto; @@ -6764,12 +6573,6 @@ textarea.form-control-lg { transition: none; } } -.offcanvas.showing, .offcanvas.show:not(.hiding) { - transform: none; -} -.offcanvas.showing, .offcanvas.hiding, .offcanvas.show { - visibility: visible; -} .offcanvas.offcanvas-start { top: 0; left: 0; @@ -6801,6 +6604,12 @@ textarea.form-control-lg { border-top: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); transform: translateY(100%); } +.offcanvas.showing, .offcanvas.show:not(.hiding) { + transform: none; +} +.offcanvas.showing, .offcanvas.hiding, .offcanvas.show { + visibility: visible; +} .offcanvas-backdrop { position: fixed; @@ -7077,7 +6886,6 @@ textarea.form-control-lg { top: 0; z-index: 1020; } - .sticky-sm-bottom { position: -webkit-sticky; position: sticky; @@ -7092,7 +6900,6 @@ textarea.form-control-lg { top: 0; z-index: 1020; } - .sticky-md-bottom { position: -webkit-sticky; position: sticky; @@ -7107,7 +6914,6 @@ textarea.form-control-lg { top: 0; z-index: 1020; } - .sticky-lg-bottom { position: -webkit-sticky; position: sticky; @@ -7122,7 +6928,6 @@ textarea.form-control-lg { top: 0; z-index: 1020; } - .sticky-xl-bottom { position: -webkit-sticky; position: sticky; @@ -7137,7 +6942,6 @@ textarea.form-control-lg { top: 0; z-index: 1020; } - .sticky-xxl-bottom { position: -webkit-sticky; position: sticky; @@ -8365,7 +8169,7 @@ textarea.form-control-lg { .text-muted { --bs-text-opacity: 1; - color: rgba(var(--bs-body-color-rgb), 0.75) !important; + color: #6c757d !important; } .text-black-50 { @@ -8577,649 +8381,494 @@ textarea.form-control-lg { .float-sm-start { float: left !important; } - .float-sm-end { float: right !important; } - .float-sm-none { float: none !important; } - .d-sm-inline { display: inline !important; } - .d-sm-inline-block { display: inline-block !important; } - .d-sm-block { display: block !important; } - .d-sm-grid { display: grid !important; } - .d-sm-table { display: table !important; } - .d-sm-table-row { display: table-row !important; } - .d-sm-table-cell { display: table-cell !important; } - .d-sm-flex { display: flex !important; } - .d-sm-inline-flex { display: inline-flex !important; } - .d-sm-none { display: none !important; } - .flex-sm-fill { flex: 1 1 auto !important; } - .flex-sm-row { flex-direction: row !important; } - .flex-sm-column { flex-direction: column !important; } - .flex-sm-row-reverse { flex-direction: row-reverse !important; } - .flex-sm-column-reverse { flex-direction: column-reverse !important; } - .flex-sm-grow-0 { flex-grow: 0 !important; } - .flex-sm-grow-1 { flex-grow: 1 !important; } - .flex-sm-shrink-0 { flex-shrink: 0 !important; } - .flex-sm-shrink-1 { flex-shrink: 1 !important; } - .flex-sm-wrap { flex-wrap: wrap !important; } - .flex-sm-nowrap { flex-wrap: nowrap !important; } - .flex-sm-wrap-reverse { flex-wrap: wrap-reverse !important; } - .justify-content-sm-start { justify-content: flex-start !important; } - .justify-content-sm-end { justify-content: flex-end !important; } - .justify-content-sm-center { justify-content: center !important; } - .justify-content-sm-between { justify-content: space-between !important; } - .justify-content-sm-around { justify-content: space-around !important; } - .justify-content-sm-evenly { justify-content: space-evenly !important; } - .align-items-sm-start { align-items: flex-start !important; } - .align-items-sm-end { align-items: flex-end !important; } - .align-items-sm-center { align-items: center !important; } - .align-items-sm-baseline { align-items: baseline !important; } - .align-items-sm-stretch { align-items: stretch !important; } - .align-content-sm-start { align-content: flex-start !important; } - .align-content-sm-end { align-content: flex-end !important; } - .align-content-sm-center { align-content: center !important; } - .align-content-sm-between { align-content: space-between !important; } - .align-content-sm-around { align-content: space-around !important; } - .align-content-sm-stretch { align-content: stretch !important; } - .align-self-sm-auto { align-self: auto !important; } - .align-self-sm-start { align-self: flex-start !important; } - .align-self-sm-end { align-self: flex-end !important; } - .align-self-sm-center { align-self: center !important; } - .align-self-sm-baseline { align-self: baseline !important; } - .align-self-sm-stretch { align-self: stretch !important; } - .order-sm-first { order: -1 !important; } - .order-sm-0 { order: 0 !important; } - .order-sm-1 { order: 1 !important; } - .order-sm-2 { order: 2 !important; } - .order-sm-3 { order: 3 !important; } - .order-sm-4 { order: 4 !important; } - .order-sm-5 { order: 5 !important; } - .order-sm-last { order: 6 !important; } - .m-sm-0 { margin: 0 !important; } - .m-sm-1 { margin: 0.25rem !important; } - .m-sm-2 { margin: 0.5rem !important; } - .m-sm-3 { margin: 1rem !important; } - .m-sm-4 { margin: 1.5rem !important; } - .m-sm-5 { margin: 3rem !important; } - .m-sm-auto { margin: auto !important; } - .mx-sm-0 { margin-right: 0 !important; margin-left: 0 !important; } - .mx-sm-1 { margin-right: 0.25rem !important; margin-left: 0.25rem !important; } - .mx-sm-2 { margin-right: 0.5rem !important; margin-left: 0.5rem !important; } - .mx-sm-3 { margin-right: 1rem !important; margin-left: 1rem !important; } - .mx-sm-4 { margin-right: 1.5rem !important; margin-left: 1.5rem !important; } - .mx-sm-5 { margin-right: 3rem !important; margin-left: 3rem !important; } - .mx-sm-auto { margin-right: auto !important; margin-left: auto !important; } - .my-sm-0 { margin-top: 0 !important; margin-bottom: 0 !important; } - .my-sm-1 { margin-top: 0.25rem !important; margin-bottom: 0.25rem !important; } - .my-sm-2 { margin-top: 0.5rem !important; margin-bottom: 0.5rem !important; } - .my-sm-3 { margin-top: 1rem !important; margin-bottom: 1rem !important; } - .my-sm-4 { margin-top: 1.5rem !important; margin-bottom: 1.5rem !important; } - .my-sm-5 { margin-top: 3rem !important; margin-bottom: 3rem !important; } - .my-sm-auto { margin-top: auto !important; margin-bottom: auto !important; } - .mt-sm-0 { margin-top: 0 !important; } - .mt-sm-1 { margin-top: 0.25rem !important; } - .mt-sm-2 { margin-top: 0.5rem !important; } - .mt-sm-3 { margin-top: 1rem !important; } - .mt-sm-4 { margin-top: 1.5rem !important; } - .mt-sm-5 { margin-top: 3rem !important; } - .mt-sm-auto { margin-top: auto !important; } - .me-sm-0 { margin-right: 0 !important; } - .me-sm-1 { margin-right: 0.25rem !important; } - .me-sm-2 { margin-right: 0.5rem !important; } - .me-sm-3 { margin-right: 1rem !important; } - .me-sm-4 { margin-right: 1.5rem !important; } - .me-sm-5 { margin-right: 3rem !important; } - .me-sm-auto { margin-right: auto !important; } - .mb-sm-0 { margin-bottom: 0 !important; } - .mb-sm-1 { margin-bottom: 0.25rem !important; } - .mb-sm-2 { margin-bottom: 0.5rem !important; } - .mb-sm-3 { margin-bottom: 1rem !important; } - .mb-sm-4 { margin-bottom: 1.5rem !important; } - .mb-sm-5 { margin-bottom: 3rem !important; } - .mb-sm-auto { margin-bottom: auto !important; } - .ms-sm-0 { margin-left: 0 !important; } - .ms-sm-1 { margin-left: 0.25rem !important; } - .ms-sm-2 { margin-left: 0.5rem !important; } - .ms-sm-3 { margin-left: 1rem !important; } - .ms-sm-4 { margin-left: 1.5rem !important; } - .ms-sm-5 { margin-left: 3rem !important; } - .ms-sm-auto { margin-left: auto !important; } - .p-sm-0 { padding: 0 !important; } - .p-sm-1 { padding: 0.25rem !important; } - .p-sm-2 { padding: 0.5rem !important; } - .p-sm-3 { padding: 1rem !important; } - .p-sm-4 { padding: 1.5rem !important; } - .p-sm-5 { padding: 3rem !important; } - .px-sm-0 { padding-right: 0 !important; padding-left: 0 !important; } - .px-sm-1 { padding-right: 0.25rem !important; padding-left: 0.25rem !important; } - .px-sm-2 { padding-right: 0.5rem !important; padding-left: 0.5rem !important; } - .px-sm-3 { padding-right: 1rem !important; padding-left: 1rem !important; } - .px-sm-4 { padding-right: 1.5rem !important; padding-left: 1.5rem !important; } - .px-sm-5 { padding-right: 3rem !important; padding-left: 3rem !important; } - .py-sm-0 { padding-top: 0 !important; padding-bottom: 0 !important; } - .py-sm-1 { padding-top: 0.25rem !important; padding-bottom: 0.25rem !important; } - .py-sm-2 { padding-top: 0.5rem !important; padding-bottom: 0.5rem !important; } - .py-sm-3 { padding-top: 1rem !important; padding-bottom: 1rem !important; } - .py-sm-4 { padding-top: 1.5rem !important; padding-bottom: 1.5rem !important; } - .py-sm-5 { padding-top: 3rem !important; padding-bottom: 3rem !important; } - .pt-sm-0 { padding-top: 0 !important; } - .pt-sm-1 { padding-top: 0.25rem !important; } - .pt-sm-2 { padding-top: 0.5rem !important; } - .pt-sm-3 { padding-top: 1rem !important; } - .pt-sm-4 { padding-top: 1.5rem !important; } - .pt-sm-5 { padding-top: 3rem !important; } - .pe-sm-0 { padding-right: 0 !important; } - .pe-sm-1 { padding-right: 0.25rem !important; } - .pe-sm-2 { padding-right: 0.5rem !important; } - .pe-sm-3 { padding-right: 1rem !important; } - .pe-sm-4 { padding-right: 1.5rem !important; } - .pe-sm-5 { padding-right: 3rem !important; } - .pb-sm-0 { padding-bottom: 0 !important; } - .pb-sm-1 { padding-bottom: 0.25rem !important; } - .pb-sm-2 { padding-bottom: 0.5rem !important; } - .pb-sm-3 { padding-bottom: 1rem !important; } - .pb-sm-4 { padding-bottom: 1.5rem !important; } - .pb-sm-5 { padding-bottom: 3rem !important; } - .ps-sm-0 { padding-left: 0 !important; } - .ps-sm-1 { padding-left: 0.25rem !important; } - .ps-sm-2 { padding-left: 0.5rem !important; } - .ps-sm-3 { padding-left: 1rem !important; } - .ps-sm-4 { padding-left: 1.5rem !important; } - .ps-sm-5 { padding-left: 3rem !important; } - .gap-sm-0 { gap: 0 !important; } - .gap-sm-1 { gap: 0.25rem !important; } - .gap-sm-2 { gap: 0.5rem !important; } - .gap-sm-3 { gap: 1rem !important; } - .gap-sm-4 { gap: 1.5rem !important; } - .gap-sm-5 { gap: 3rem !important; } - .text-sm-start { text-align: left !important; } - .text-sm-end { text-align: right !important; } - .text-sm-center { text-align: center !important; } @@ -9228,649 +8877,494 @@ textarea.form-control-lg { .float-md-start { float: left !important; } - .float-md-end { float: right !important; } - .float-md-none { float: none !important; } - .d-md-inline { display: inline !important; } - .d-md-inline-block { display: inline-block !important; } - .d-md-block { display: block !important; } - .d-md-grid { display: grid !important; } - .d-md-table { display: table !important; } - .d-md-table-row { display: table-row !important; } - .d-md-table-cell { display: table-cell !important; } - .d-md-flex { display: flex !important; } - .d-md-inline-flex { display: inline-flex !important; } - .d-md-none { display: none !important; } - .flex-md-fill { flex: 1 1 auto !important; } - .flex-md-row { flex-direction: row !important; } - .flex-md-column { flex-direction: column !important; } - .flex-md-row-reverse { flex-direction: row-reverse !important; } - .flex-md-column-reverse { flex-direction: column-reverse !important; } - .flex-md-grow-0 { flex-grow: 0 !important; } - .flex-md-grow-1 { flex-grow: 1 !important; } - .flex-md-shrink-0 { flex-shrink: 0 !important; } - .flex-md-shrink-1 { flex-shrink: 1 !important; } - .flex-md-wrap { flex-wrap: wrap !important; } - .flex-md-nowrap { flex-wrap: nowrap !important; } - .flex-md-wrap-reverse { flex-wrap: wrap-reverse !important; } - .justify-content-md-start { justify-content: flex-start !important; } - .justify-content-md-end { justify-content: flex-end !important; } - .justify-content-md-center { justify-content: center !important; } - .justify-content-md-between { justify-content: space-between !important; } - .justify-content-md-around { justify-content: space-around !important; } - .justify-content-md-evenly { justify-content: space-evenly !important; } - .align-items-md-start { align-items: flex-start !important; } - .align-items-md-end { align-items: flex-end !important; } - .align-items-md-center { align-items: center !important; } - .align-items-md-baseline { align-items: baseline !important; } - .align-items-md-stretch { align-items: stretch !important; } - .align-content-md-start { align-content: flex-start !important; } - .align-content-md-end { align-content: flex-end !important; } - .align-content-md-center { align-content: center !important; } - .align-content-md-between { align-content: space-between !important; } - .align-content-md-around { align-content: space-around !important; } - .align-content-md-stretch { align-content: stretch !important; } - .align-self-md-auto { align-self: auto !important; } - .align-self-md-start { align-self: flex-start !important; } - .align-self-md-end { align-self: flex-end !important; } - .align-self-md-center { align-self: center !important; } - .align-self-md-baseline { align-self: baseline !important; } - .align-self-md-stretch { align-self: stretch !important; } - .order-md-first { order: -1 !important; } - .order-md-0 { order: 0 !important; } - .order-md-1 { order: 1 !important; } - .order-md-2 { order: 2 !important; } - .order-md-3 { order: 3 !important; } - .order-md-4 { order: 4 !important; } - .order-md-5 { order: 5 !important; } - .order-md-last { order: 6 !important; } - .m-md-0 { margin: 0 !important; } - .m-md-1 { margin: 0.25rem !important; } - .m-md-2 { margin: 0.5rem !important; } - .m-md-3 { margin: 1rem !important; } - .m-md-4 { margin: 1.5rem !important; } - .m-md-5 { margin: 3rem !important; } - .m-md-auto { margin: auto !important; } - .mx-md-0 { margin-right: 0 !important; margin-left: 0 !important; } - .mx-md-1 { margin-right: 0.25rem !important; margin-left: 0.25rem !important; } - .mx-md-2 { margin-right: 0.5rem !important; margin-left: 0.5rem !important; } - .mx-md-3 { margin-right: 1rem !important; margin-left: 1rem !important; } - .mx-md-4 { margin-right: 1.5rem !important; margin-left: 1.5rem !important; } - .mx-md-5 { margin-right: 3rem !important; margin-left: 3rem !important; } - .mx-md-auto { margin-right: auto !important; margin-left: auto !important; } - .my-md-0 { margin-top: 0 !important; margin-bottom: 0 !important; } - .my-md-1 { margin-top: 0.25rem !important; margin-bottom: 0.25rem !important; } - .my-md-2 { margin-top: 0.5rem !important; margin-bottom: 0.5rem !important; } - .my-md-3 { margin-top: 1rem !important; margin-bottom: 1rem !important; } - .my-md-4 { margin-top: 1.5rem !important; margin-bottom: 1.5rem !important; } - .my-md-5 { margin-top: 3rem !important; margin-bottom: 3rem !important; } - .my-md-auto { margin-top: auto !important; margin-bottom: auto !important; } - .mt-md-0 { margin-top: 0 !important; } - .mt-md-1 { margin-top: 0.25rem !important; } - .mt-md-2 { margin-top: 0.5rem !important; } - .mt-md-3 { margin-top: 1rem !important; } - .mt-md-4 { margin-top: 1.5rem !important; } - .mt-md-5 { margin-top: 3rem !important; } - .mt-md-auto { margin-top: auto !important; } - .me-md-0 { margin-right: 0 !important; } - .me-md-1 { margin-right: 0.25rem !important; } - .me-md-2 { margin-right: 0.5rem !important; } - .me-md-3 { margin-right: 1rem !important; } - .me-md-4 { margin-right: 1.5rem !important; } - .me-md-5 { margin-right: 3rem !important; } - .me-md-auto { margin-right: auto !important; } - .mb-md-0 { margin-bottom: 0 !important; } - .mb-md-1 { margin-bottom: 0.25rem !important; } - .mb-md-2 { margin-bottom: 0.5rem !important; } - .mb-md-3 { margin-bottom: 1rem !important; } - .mb-md-4 { margin-bottom: 1.5rem !important; } - .mb-md-5 { margin-bottom: 3rem !important; } - .mb-md-auto { margin-bottom: auto !important; } - .ms-md-0 { margin-left: 0 !important; } - .ms-md-1 { margin-left: 0.25rem !important; } - .ms-md-2 { margin-left: 0.5rem !important; } - .ms-md-3 { margin-left: 1rem !important; } - .ms-md-4 { margin-left: 1.5rem !important; } - .ms-md-5 { margin-left: 3rem !important; } - .ms-md-auto { margin-left: auto !important; } - .p-md-0 { padding: 0 !important; } - .p-md-1 { padding: 0.25rem !important; } - .p-md-2 { padding: 0.5rem !important; } - .p-md-3 { padding: 1rem !important; } - .p-md-4 { padding: 1.5rem !important; } - .p-md-5 { padding: 3rem !important; } - .px-md-0 { padding-right: 0 !important; padding-left: 0 !important; } - .px-md-1 { padding-right: 0.25rem !important; padding-left: 0.25rem !important; } - .px-md-2 { padding-right: 0.5rem !important; padding-left: 0.5rem !important; } - .px-md-3 { padding-right: 1rem !important; padding-left: 1rem !important; } - .px-md-4 { padding-right: 1.5rem !important; padding-left: 1.5rem !important; } - .px-md-5 { padding-right: 3rem !important; padding-left: 3rem !important; } - .py-md-0 { padding-top: 0 !important; padding-bottom: 0 !important; } - .py-md-1 { padding-top: 0.25rem !important; padding-bottom: 0.25rem !important; } - .py-md-2 { padding-top: 0.5rem !important; padding-bottom: 0.5rem !important; } - .py-md-3 { padding-top: 1rem !important; padding-bottom: 1rem !important; } - .py-md-4 { padding-top: 1.5rem !important; padding-bottom: 1.5rem !important; } - .py-md-5 { padding-top: 3rem !important; padding-bottom: 3rem !important; } - .pt-md-0 { padding-top: 0 !important; } - .pt-md-1 { padding-top: 0.25rem !important; } - .pt-md-2 { padding-top: 0.5rem !important; } - .pt-md-3 { padding-top: 1rem !important; } - .pt-md-4 { padding-top: 1.5rem !important; } - .pt-md-5 { padding-top: 3rem !important; } - .pe-md-0 { padding-right: 0 !important; } - .pe-md-1 { padding-right: 0.25rem !important; } - .pe-md-2 { padding-right: 0.5rem !important; } - .pe-md-3 { padding-right: 1rem !important; } - .pe-md-4 { padding-right: 1.5rem !important; } - .pe-md-5 { padding-right: 3rem !important; } - .pb-md-0 { padding-bottom: 0 !important; } - .pb-md-1 { padding-bottom: 0.25rem !important; } - .pb-md-2 { padding-bottom: 0.5rem !important; } - .pb-md-3 { padding-bottom: 1rem !important; } - .pb-md-4 { padding-bottom: 1.5rem !important; } - .pb-md-5 { padding-bottom: 3rem !important; } - .ps-md-0 { padding-left: 0 !important; } - .ps-md-1 { padding-left: 0.25rem !important; } - .ps-md-2 { padding-left: 0.5rem !important; } - .ps-md-3 { padding-left: 1rem !important; } - .ps-md-4 { padding-left: 1.5rem !important; } - .ps-md-5 { padding-left: 3rem !important; } - .gap-md-0 { gap: 0 !important; } - .gap-md-1 { gap: 0.25rem !important; } - .gap-md-2 { gap: 0.5rem !important; } - .gap-md-3 { gap: 1rem !important; } - .gap-md-4 { gap: 1.5rem !important; } - .gap-md-5 { gap: 3rem !important; } - .text-md-start { text-align: left !important; } - .text-md-end { text-align: right !important; } - .text-md-center { text-align: center !important; } @@ -9879,649 +9373,494 @@ textarea.form-control-lg { .float-lg-start { float: left !important; } - .float-lg-end { float: right !important; } - .float-lg-none { float: none !important; } - .d-lg-inline { display: inline !important; } - .d-lg-inline-block { display: inline-block !important; } - .d-lg-block { display: block !important; } - .d-lg-grid { display: grid !important; } - .d-lg-table { display: table !important; } - .d-lg-table-row { display: table-row !important; } - .d-lg-table-cell { display: table-cell !important; } - .d-lg-flex { display: flex !important; } - .d-lg-inline-flex { display: inline-flex !important; } - .d-lg-none { display: none !important; } - .flex-lg-fill { flex: 1 1 auto !important; } - .flex-lg-row { flex-direction: row !important; } - .flex-lg-column { flex-direction: column !important; } - .flex-lg-row-reverse { flex-direction: row-reverse !important; } - .flex-lg-column-reverse { flex-direction: column-reverse !important; } - .flex-lg-grow-0 { flex-grow: 0 !important; } - .flex-lg-grow-1 { flex-grow: 1 !important; } - .flex-lg-shrink-0 { flex-shrink: 0 !important; } - .flex-lg-shrink-1 { flex-shrink: 1 !important; } - .flex-lg-wrap { flex-wrap: wrap !important; } - .flex-lg-nowrap { flex-wrap: nowrap !important; } - .flex-lg-wrap-reverse { flex-wrap: wrap-reverse !important; } - .justify-content-lg-start { justify-content: flex-start !important; } - .justify-content-lg-end { justify-content: flex-end !important; } - .justify-content-lg-center { justify-content: center !important; } - .justify-content-lg-between { justify-content: space-between !important; } - .justify-content-lg-around { justify-content: space-around !important; } - .justify-content-lg-evenly { justify-content: space-evenly !important; } - .align-items-lg-start { align-items: flex-start !important; } - .align-items-lg-end { align-items: flex-end !important; } - .align-items-lg-center { align-items: center !important; } - .align-items-lg-baseline { align-items: baseline !important; } - .align-items-lg-stretch { align-items: stretch !important; } - .align-content-lg-start { align-content: flex-start !important; } - .align-content-lg-end { align-content: flex-end !important; } - .align-content-lg-center { align-content: center !important; } - .align-content-lg-between { align-content: space-between !important; } - .align-content-lg-around { align-content: space-around !important; } - .align-content-lg-stretch { align-content: stretch !important; } - .align-self-lg-auto { align-self: auto !important; } - .align-self-lg-start { align-self: flex-start !important; } - .align-self-lg-end { align-self: flex-end !important; } - .align-self-lg-center { align-self: center !important; } - .align-self-lg-baseline { align-self: baseline !important; } - .align-self-lg-stretch { align-self: stretch !important; } - .order-lg-first { order: -1 !important; } - .order-lg-0 { order: 0 !important; } - .order-lg-1 { order: 1 !important; } - .order-lg-2 { order: 2 !important; } - .order-lg-3 { order: 3 !important; } - .order-lg-4 { order: 4 !important; } - .order-lg-5 { order: 5 !important; } - .order-lg-last { order: 6 !important; } - .m-lg-0 { margin: 0 !important; } - .m-lg-1 { margin: 0.25rem !important; } - .m-lg-2 { margin: 0.5rem !important; } - .m-lg-3 { margin: 1rem !important; } - .m-lg-4 { margin: 1.5rem !important; } - .m-lg-5 { margin: 3rem !important; } - .m-lg-auto { margin: auto !important; } - .mx-lg-0 { margin-right: 0 !important; margin-left: 0 !important; } - .mx-lg-1 { margin-right: 0.25rem !important; margin-left: 0.25rem !important; } - .mx-lg-2 { margin-right: 0.5rem !important; margin-left: 0.5rem !important; } - .mx-lg-3 { margin-right: 1rem !important; margin-left: 1rem !important; } - .mx-lg-4 { margin-right: 1.5rem !important; margin-left: 1.5rem !important; } - .mx-lg-5 { margin-right: 3rem !important; margin-left: 3rem !important; } - .mx-lg-auto { margin-right: auto !important; margin-left: auto !important; } - .my-lg-0 { margin-top: 0 !important; margin-bottom: 0 !important; } - .my-lg-1 { margin-top: 0.25rem !important; margin-bottom: 0.25rem !important; } - .my-lg-2 { margin-top: 0.5rem !important; margin-bottom: 0.5rem !important; } - .my-lg-3 { margin-top: 1rem !important; margin-bottom: 1rem !important; } - .my-lg-4 { margin-top: 1.5rem !important; margin-bottom: 1.5rem !important; } - .my-lg-5 { margin-top: 3rem !important; margin-bottom: 3rem !important; } - .my-lg-auto { margin-top: auto !important; margin-bottom: auto !important; } - .mt-lg-0 { margin-top: 0 !important; } - .mt-lg-1 { margin-top: 0.25rem !important; } - .mt-lg-2 { margin-top: 0.5rem !important; } - .mt-lg-3 { margin-top: 1rem !important; } - .mt-lg-4 { margin-top: 1.5rem !important; } - .mt-lg-5 { margin-top: 3rem !important; } - .mt-lg-auto { margin-top: auto !important; } - .me-lg-0 { margin-right: 0 !important; } - .me-lg-1 { margin-right: 0.25rem !important; } - .me-lg-2 { margin-right: 0.5rem !important; } - .me-lg-3 { margin-right: 1rem !important; } - .me-lg-4 { margin-right: 1.5rem !important; } - .me-lg-5 { margin-right: 3rem !important; } - .me-lg-auto { margin-right: auto !important; } - .mb-lg-0 { margin-bottom: 0 !important; } - .mb-lg-1 { margin-bottom: 0.25rem !important; } - .mb-lg-2 { margin-bottom: 0.5rem !important; } - .mb-lg-3 { margin-bottom: 1rem !important; } - .mb-lg-4 { margin-bottom: 1.5rem !important; } - .mb-lg-5 { margin-bottom: 3rem !important; } - .mb-lg-auto { margin-bottom: auto !important; } - .ms-lg-0 { margin-left: 0 !important; } - .ms-lg-1 { margin-left: 0.25rem !important; } - .ms-lg-2 { margin-left: 0.5rem !important; } - .ms-lg-3 { margin-left: 1rem !important; } - .ms-lg-4 { margin-left: 1.5rem !important; } - .ms-lg-5 { margin-left: 3rem !important; } - .ms-lg-auto { margin-left: auto !important; } - .p-lg-0 { padding: 0 !important; } - .p-lg-1 { padding: 0.25rem !important; } - .p-lg-2 { padding: 0.5rem !important; } - .p-lg-3 { padding: 1rem !important; } - .p-lg-4 { padding: 1.5rem !important; } - .p-lg-5 { padding: 3rem !important; } - .px-lg-0 { padding-right: 0 !important; padding-left: 0 !important; } - .px-lg-1 { padding-right: 0.25rem !important; padding-left: 0.25rem !important; } - .px-lg-2 { padding-right: 0.5rem !important; padding-left: 0.5rem !important; } - .px-lg-3 { padding-right: 1rem !important; padding-left: 1rem !important; } - .px-lg-4 { padding-right: 1.5rem !important; padding-left: 1.5rem !important; } - .px-lg-5 { padding-right: 3rem !important; padding-left: 3rem !important; } - .py-lg-0 { padding-top: 0 !important; padding-bottom: 0 !important; } - .py-lg-1 { padding-top: 0.25rem !important; padding-bottom: 0.25rem !important; } - .py-lg-2 { padding-top: 0.5rem !important; padding-bottom: 0.5rem !important; } - .py-lg-3 { padding-top: 1rem !important; padding-bottom: 1rem !important; } - .py-lg-4 { padding-top: 1.5rem !important; padding-bottom: 1.5rem !important; } - .py-lg-5 { padding-top: 3rem !important; padding-bottom: 3rem !important; } - .pt-lg-0 { padding-top: 0 !important; } - .pt-lg-1 { padding-top: 0.25rem !important; } - .pt-lg-2 { padding-top: 0.5rem !important; } - .pt-lg-3 { padding-top: 1rem !important; } - .pt-lg-4 { padding-top: 1.5rem !important; } - .pt-lg-5 { padding-top: 3rem !important; } - .pe-lg-0 { padding-right: 0 !important; } - .pe-lg-1 { padding-right: 0.25rem !important; } - .pe-lg-2 { padding-right: 0.5rem !important; } - .pe-lg-3 { padding-right: 1rem !important; } - .pe-lg-4 { padding-right: 1.5rem !important; } - .pe-lg-5 { padding-right: 3rem !important; } - .pb-lg-0 { padding-bottom: 0 !important; } - .pb-lg-1 { padding-bottom: 0.25rem !important; } - .pb-lg-2 { padding-bottom: 0.5rem !important; } - .pb-lg-3 { padding-bottom: 1rem !important; } - .pb-lg-4 { padding-bottom: 1.5rem !important; } - .pb-lg-5 { padding-bottom: 3rem !important; } - .ps-lg-0 { padding-left: 0 !important; } - .ps-lg-1 { padding-left: 0.25rem !important; } - .ps-lg-2 { padding-left: 0.5rem !important; } - .ps-lg-3 { padding-left: 1rem !important; } - .ps-lg-4 { padding-left: 1.5rem !important; } - .ps-lg-5 { padding-left: 3rem !important; } - .gap-lg-0 { gap: 0 !important; } - .gap-lg-1 { gap: 0.25rem !important; } - .gap-lg-2 { gap: 0.5rem !important; } - .gap-lg-3 { gap: 1rem !important; } - .gap-lg-4 { gap: 1.5rem !important; } - .gap-lg-5 { gap: 3rem !important; } - .text-lg-start { text-align: left !important; } - .text-lg-end { text-align: right !important; } - .text-lg-center { text-align: center !important; } @@ -10530,649 +9869,494 @@ textarea.form-control-lg { .float-xl-start { float: left !important; } - .float-xl-end { float: right !important; } - .float-xl-none { float: none !important; } - .d-xl-inline { display: inline !important; } - .d-xl-inline-block { display: inline-block !important; } - .d-xl-block { display: block !important; } - .d-xl-grid { display: grid !important; } - .d-xl-table { display: table !important; } - .d-xl-table-row { display: table-row !important; } - .d-xl-table-cell { display: table-cell !important; } - .d-xl-flex { display: flex !important; } - .d-xl-inline-flex { display: inline-flex !important; } - .d-xl-none { display: none !important; } - .flex-xl-fill { flex: 1 1 auto !important; } - .flex-xl-row { flex-direction: row !important; } - .flex-xl-column { flex-direction: column !important; } - .flex-xl-row-reverse { flex-direction: row-reverse !important; } - .flex-xl-column-reverse { flex-direction: column-reverse !important; } - .flex-xl-grow-0 { flex-grow: 0 !important; } - .flex-xl-grow-1 { flex-grow: 1 !important; } - .flex-xl-shrink-0 { flex-shrink: 0 !important; } - .flex-xl-shrink-1 { flex-shrink: 1 !important; } - .flex-xl-wrap { flex-wrap: wrap !important; } - .flex-xl-nowrap { flex-wrap: nowrap !important; } - .flex-xl-wrap-reverse { flex-wrap: wrap-reverse !important; } - .justify-content-xl-start { justify-content: flex-start !important; } - .justify-content-xl-end { justify-content: flex-end !important; } - .justify-content-xl-center { justify-content: center !important; } - .justify-content-xl-between { justify-content: space-between !important; } - .justify-content-xl-around { justify-content: space-around !important; } - .justify-content-xl-evenly { justify-content: space-evenly !important; } - .align-items-xl-start { align-items: flex-start !important; } - .align-items-xl-end { align-items: flex-end !important; } - .align-items-xl-center { align-items: center !important; } - .align-items-xl-baseline { align-items: baseline !important; } - .align-items-xl-stretch { align-items: stretch !important; } - .align-content-xl-start { align-content: flex-start !important; } - .align-content-xl-end { align-content: flex-end !important; } - .align-content-xl-center { align-content: center !important; } - .align-content-xl-between { align-content: space-between !important; } - .align-content-xl-around { align-content: space-around !important; } - .align-content-xl-stretch { align-content: stretch !important; } - .align-self-xl-auto { align-self: auto !important; } - .align-self-xl-start { align-self: flex-start !important; } - .align-self-xl-end { align-self: flex-end !important; } - .align-self-xl-center { align-self: center !important; } - .align-self-xl-baseline { align-self: baseline !important; } - .align-self-xl-stretch { align-self: stretch !important; } - .order-xl-first { order: -1 !important; } - .order-xl-0 { order: 0 !important; } - .order-xl-1 { order: 1 !important; } - .order-xl-2 { order: 2 !important; } - .order-xl-3 { order: 3 !important; } - .order-xl-4 { order: 4 !important; } - .order-xl-5 { order: 5 !important; } - .order-xl-last { order: 6 !important; } - .m-xl-0 { margin: 0 !important; } - .m-xl-1 { margin: 0.25rem !important; } - .m-xl-2 { margin: 0.5rem !important; } - .m-xl-3 { margin: 1rem !important; } - .m-xl-4 { margin: 1.5rem !important; } - .m-xl-5 { margin: 3rem !important; } - .m-xl-auto { margin: auto !important; } - .mx-xl-0 { margin-right: 0 !important; margin-left: 0 !important; } - .mx-xl-1 { margin-right: 0.25rem !important; margin-left: 0.25rem !important; } - .mx-xl-2 { margin-right: 0.5rem !important; margin-left: 0.5rem !important; } - .mx-xl-3 { margin-right: 1rem !important; margin-left: 1rem !important; } - .mx-xl-4 { margin-right: 1.5rem !important; margin-left: 1.5rem !important; } - .mx-xl-5 { margin-right: 3rem !important; margin-left: 3rem !important; } - .mx-xl-auto { margin-right: auto !important; margin-left: auto !important; } - .my-xl-0 { margin-top: 0 !important; margin-bottom: 0 !important; } - .my-xl-1 { margin-top: 0.25rem !important; margin-bottom: 0.25rem !important; } - .my-xl-2 { margin-top: 0.5rem !important; margin-bottom: 0.5rem !important; } - .my-xl-3 { margin-top: 1rem !important; margin-bottom: 1rem !important; } - .my-xl-4 { margin-top: 1.5rem !important; margin-bottom: 1.5rem !important; } - .my-xl-5 { margin-top: 3rem !important; margin-bottom: 3rem !important; } - .my-xl-auto { margin-top: auto !important; margin-bottom: auto !important; } - .mt-xl-0 { margin-top: 0 !important; } - .mt-xl-1 { margin-top: 0.25rem !important; } - .mt-xl-2 { margin-top: 0.5rem !important; } - .mt-xl-3 { margin-top: 1rem !important; } - .mt-xl-4 { margin-top: 1.5rem !important; } - .mt-xl-5 { margin-top: 3rem !important; } - .mt-xl-auto { margin-top: auto !important; } - .me-xl-0 { margin-right: 0 !important; } - .me-xl-1 { margin-right: 0.25rem !important; } - .me-xl-2 { margin-right: 0.5rem !important; } - .me-xl-3 { margin-right: 1rem !important; } - .me-xl-4 { margin-right: 1.5rem !important; } - .me-xl-5 { margin-right: 3rem !important; } - .me-xl-auto { margin-right: auto !important; } - .mb-xl-0 { margin-bottom: 0 !important; } - .mb-xl-1 { margin-bottom: 0.25rem !important; } - .mb-xl-2 { margin-bottom: 0.5rem !important; } - .mb-xl-3 { margin-bottom: 1rem !important; } - .mb-xl-4 { margin-bottom: 1.5rem !important; } - .mb-xl-5 { margin-bottom: 3rem !important; } - .mb-xl-auto { margin-bottom: auto !important; } - .ms-xl-0 { margin-left: 0 !important; } - .ms-xl-1 { margin-left: 0.25rem !important; } - .ms-xl-2 { margin-left: 0.5rem !important; } - .ms-xl-3 { margin-left: 1rem !important; } - .ms-xl-4 { margin-left: 1.5rem !important; } - .ms-xl-5 { margin-left: 3rem !important; } - .ms-xl-auto { margin-left: auto !important; } - .p-xl-0 { padding: 0 !important; } - .p-xl-1 { padding: 0.25rem !important; } - .p-xl-2 { padding: 0.5rem !important; } - .p-xl-3 { padding: 1rem !important; } - .p-xl-4 { padding: 1.5rem !important; } - .p-xl-5 { padding: 3rem !important; } - .px-xl-0 { padding-right: 0 !important; padding-left: 0 !important; } - .px-xl-1 { padding-right: 0.25rem !important; padding-left: 0.25rem !important; } - .px-xl-2 { padding-right: 0.5rem !important; padding-left: 0.5rem !important; } - .px-xl-3 { padding-right: 1rem !important; padding-left: 1rem !important; } - .px-xl-4 { padding-right: 1.5rem !important; padding-left: 1.5rem !important; } - .px-xl-5 { padding-right: 3rem !important; padding-left: 3rem !important; } - .py-xl-0 { padding-top: 0 !important; padding-bottom: 0 !important; } - .py-xl-1 { padding-top: 0.25rem !important; padding-bottom: 0.25rem !important; } - .py-xl-2 { padding-top: 0.5rem !important; padding-bottom: 0.5rem !important; } - .py-xl-3 { padding-top: 1rem !important; padding-bottom: 1rem !important; } - .py-xl-4 { padding-top: 1.5rem !important; padding-bottom: 1.5rem !important; } - .py-xl-5 { padding-top: 3rem !important; padding-bottom: 3rem !important; } - .pt-xl-0 { padding-top: 0 !important; } - .pt-xl-1 { padding-top: 0.25rem !important; } - .pt-xl-2 { padding-top: 0.5rem !important; } - .pt-xl-3 { padding-top: 1rem !important; } - .pt-xl-4 { padding-top: 1.5rem !important; } - .pt-xl-5 { padding-top: 3rem !important; } - .pe-xl-0 { padding-right: 0 !important; } - .pe-xl-1 { padding-right: 0.25rem !important; } - .pe-xl-2 { padding-right: 0.5rem !important; } - .pe-xl-3 { padding-right: 1rem !important; } - .pe-xl-4 { padding-right: 1.5rem !important; } - .pe-xl-5 { padding-right: 3rem !important; } - .pb-xl-0 { padding-bottom: 0 !important; } - .pb-xl-1 { padding-bottom: 0.25rem !important; } - .pb-xl-2 { padding-bottom: 0.5rem !important; } - .pb-xl-3 { padding-bottom: 1rem !important; } - .pb-xl-4 { padding-bottom: 1.5rem !important; } - .pb-xl-5 { padding-bottom: 3rem !important; } - .ps-xl-0 { padding-left: 0 !important; } - .ps-xl-1 { padding-left: 0.25rem !important; } - .ps-xl-2 { padding-left: 0.5rem !important; } - .ps-xl-3 { padding-left: 1rem !important; } - .ps-xl-4 { padding-left: 1.5rem !important; } - .ps-xl-5 { padding-left: 3rem !important; } - .gap-xl-0 { gap: 0 !important; } - .gap-xl-1 { gap: 0.25rem !important; } - .gap-xl-2 { gap: 0.5rem !important; } - .gap-xl-3 { gap: 1rem !important; } - .gap-xl-4 { gap: 1.5rem !important; } - .gap-xl-5 { gap: 3rem !important; } - .text-xl-start { text-align: left !important; } - .text-xl-end { text-align: right !important; } - .text-xl-center { text-align: center !important; } @@ -11181,649 +10365,494 @@ textarea.form-control-lg { .float-xxl-start { float: left !important; } - .float-xxl-end { float: right !important; } - .float-xxl-none { float: none !important; } - .d-xxl-inline { display: inline !important; } - .d-xxl-inline-block { display: inline-block !important; } - .d-xxl-block { display: block !important; } - .d-xxl-grid { display: grid !important; } - .d-xxl-table { display: table !important; } - .d-xxl-table-row { display: table-row !important; } - .d-xxl-table-cell { display: table-cell !important; } - .d-xxl-flex { display: flex !important; } - .d-xxl-inline-flex { display: inline-flex !important; } - .d-xxl-none { display: none !important; } - .flex-xxl-fill { flex: 1 1 auto !important; } - .flex-xxl-row { flex-direction: row !important; } - .flex-xxl-column { flex-direction: column !important; } - .flex-xxl-row-reverse { flex-direction: row-reverse !important; } - .flex-xxl-column-reverse { flex-direction: column-reverse !important; } - .flex-xxl-grow-0 { flex-grow: 0 !important; } - .flex-xxl-grow-1 { flex-grow: 1 !important; } - .flex-xxl-shrink-0 { flex-shrink: 0 !important; } - .flex-xxl-shrink-1 { flex-shrink: 1 !important; } - .flex-xxl-wrap { flex-wrap: wrap !important; } - .flex-xxl-nowrap { flex-wrap: nowrap !important; } - .flex-xxl-wrap-reverse { flex-wrap: wrap-reverse !important; } - .justify-content-xxl-start { justify-content: flex-start !important; } - .justify-content-xxl-end { justify-content: flex-end !important; } - .justify-content-xxl-center { justify-content: center !important; } - .justify-content-xxl-between { justify-content: space-between !important; } - .justify-content-xxl-around { justify-content: space-around !important; } - .justify-content-xxl-evenly { justify-content: space-evenly !important; } - .align-items-xxl-start { align-items: flex-start !important; } - .align-items-xxl-end { align-items: flex-end !important; } - .align-items-xxl-center { align-items: center !important; } - .align-items-xxl-baseline { align-items: baseline !important; } - .align-items-xxl-stretch { align-items: stretch !important; } - .align-content-xxl-start { align-content: flex-start !important; } - .align-content-xxl-end { align-content: flex-end !important; } - .align-content-xxl-center { align-content: center !important; } - .align-content-xxl-between { align-content: space-between !important; } - .align-content-xxl-around { align-content: space-around !important; } - .align-content-xxl-stretch { align-content: stretch !important; } - .align-self-xxl-auto { align-self: auto !important; } - .align-self-xxl-start { align-self: flex-start !important; } - .align-self-xxl-end { align-self: flex-end !important; } - .align-self-xxl-center { align-self: center !important; } - .align-self-xxl-baseline { align-self: baseline !important; } - .align-self-xxl-stretch { align-self: stretch !important; } - .order-xxl-first { order: -1 !important; } - .order-xxl-0 { order: 0 !important; } - .order-xxl-1 { order: 1 !important; } - .order-xxl-2 { order: 2 !important; } - .order-xxl-3 { order: 3 !important; } - .order-xxl-4 { order: 4 !important; } - .order-xxl-5 { order: 5 !important; } - .order-xxl-last { order: 6 !important; } - .m-xxl-0 { margin: 0 !important; } - .m-xxl-1 { margin: 0.25rem !important; } - .m-xxl-2 { margin: 0.5rem !important; } - .m-xxl-3 { margin: 1rem !important; } - .m-xxl-4 { margin: 1.5rem !important; } - .m-xxl-5 { margin: 3rem !important; } - .m-xxl-auto { margin: auto !important; } - .mx-xxl-0 { margin-right: 0 !important; margin-left: 0 !important; } - .mx-xxl-1 { margin-right: 0.25rem !important; margin-left: 0.25rem !important; } - .mx-xxl-2 { margin-right: 0.5rem !important; margin-left: 0.5rem !important; } - .mx-xxl-3 { margin-right: 1rem !important; margin-left: 1rem !important; } - .mx-xxl-4 { margin-right: 1.5rem !important; margin-left: 1.5rem !important; } - .mx-xxl-5 { margin-right: 3rem !important; margin-left: 3rem !important; } - .mx-xxl-auto { margin-right: auto !important; margin-left: auto !important; } - .my-xxl-0 { margin-top: 0 !important; margin-bottom: 0 !important; } - .my-xxl-1 { margin-top: 0.25rem !important; margin-bottom: 0.25rem !important; } - .my-xxl-2 { margin-top: 0.5rem !important; margin-bottom: 0.5rem !important; } - .my-xxl-3 { margin-top: 1rem !important; margin-bottom: 1rem !important; } - .my-xxl-4 { margin-top: 1.5rem !important; margin-bottom: 1.5rem !important; } - .my-xxl-5 { margin-top: 3rem !important; margin-bottom: 3rem !important; } - .my-xxl-auto { margin-top: auto !important; margin-bottom: auto !important; } - .mt-xxl-0 { margin-top: 0 !important; } - .mt-xxl-1 { margin-top: 0.25rem !important; } - .mt-xxl-2 { margin-top: 0.5rem !important; } - .mt-xxl-3 { margin-top: 1rem !important; } - .mt-xxl-4 { margin-top: 1.5rem !important; } - .mt-xxl-5 { margin-top: 3rem !important; } - .mt-xxl-auto { margin-top: auto !important; } - .me-xxl-0 { margin-right: 0 !important; } - .me-xxl-1 { margin-right: 0.25rem !important; } - .me-xxl-2 { margin-right: 0.5rem !important; } - .me-xxl-3 { margin-right: 1rem !important; } - .me-xxl-4 { margin-right: 1.5rem !important; } - .me-xxl-5 { margin-right: 3rem !important; } - .me-xxl-auto { margin-right: auto !important; } - .mb-xxl-0 { margin-bottom: 0 !important; } - .mb-xxl-1 { margin-bottom: 0.25rem !important; } - .mb-xxl-2 { margin-bottom: 0.5rem !important; } - .mb-xxl-3 { margin-bottom: 1rem !important; } - .mb-xxl-4 { margin-bottom: 1.5rem !important; } - .mb-xxl-5 { margin-bottom: 3rem !important; } - .mb-xxl-auto { margin-bottom: auto !important; } - .ms-xxl-0 { margin-left: 0 !important; } - .ms-xxl-1 { margin-left: 0.25rem !important; } - .ms-xxl-2 { margin-left: 0.5rem !important; } - .ms-xxl-3 { margin-left: 1rem !important; } - .ms-xxl-4 { margin-left: 1.5rem !important; } - .ms-xxl-5 { margin-left: 3rem !important; } - .ms-xxl-auto { margin-left: auto !important; } - .p-xxl-0 { padding: 0 !important; } - .p-xxl-1 { padding: 0.25rem !important; } - .p-xxl-2 { padding: 0.5rem !important; } - .p-xxl-3 { padding: 1rem !important; } - .p-xxl-4 { padding: 1.5rem !important; } - .p-xxl-5 { padding: 3rem !important; } - .px-xxl-0 { padding-right: 0 !important; padding-left: 0 !important; } - .px-xxl-1 { padding-right: 0.25rem !important; padding-left: 0.25rem !important; } - .px-xxl-2 { padding-right: 0.5rem !important; padding-left: 0.5rem !important; } - .px-xxl-3 { padding-right: 1rem !important; padding-left: 1rem !important; } - .px-xxl-4 { padding-right: 1.5rem !important; padding-left: 1.5rem !important; } - .px-xxl-5 { padding-right: 3rem !important; padding-left: 3rem !important; } - .py-xxl-0 { padding-top: 0 !important; padding-bottom: 0 !important; } - .py-xxl-1 { padding-top: 0.25rem !important; padding-bottom: 0.25rem !important; } - .py-xxl-2 { padding-top: 0.5rem !important; padding-bottom: 0.5rem !important; } - .py-xxl-3 { padding-top: 1rem !important; padding-bottom: 1rem !important; } - .py-xxl-4 { padding-top: 1.5rem !important; padding-bottom: 1.5rem !important; } - .py-xxl-5 { padding-top: 3rem !important; padding-bottom: 3rem !important; } - .pt-xxl-0 { padding-top: 0 !important; } - .pt-xxl-1 { padding-top: 0.25rem !important; } - .pt-xxl-2 { padding-top: 0.5rem !important; } - .pt-xxl-3 { padding-top: 1rem !important; } - .pt-xxl-4 { padding-top: 1.5rem !important; } - .pt-xxl-5 { padding-top: 3rem !important; } - .pe-xxl-0 { padding-right: 0 !important; } - .pe-xxl-1 { padding-right: 0.25rem !important; } - .pe-xxl-2 { padding-right: 0.5rem !important; } - .pe-xxl-3 { padding-right: 1rem !important; } - .pe-xxl-4 { padding-right: 1.5rem !important; } - .pe-xxl-5 { padding-right: 3rem !important; } - .pb-xxl-0 { padding-bottom: 0 !important; } - .pb-xxl-1 { padding-bottom: 0.25rem !important; } - .pb-xxl-2 { padding-bottom: 0.5rem !important; } - .pb-xxl-3 { padding-bottom: 1rem !important; } - .pb-xxl-4 { padding-bottom: 1.5rem !important; } - .pb-xxl-5 { padding-bottom: 3rem !important; } - .ps-xxl-0 { padding-left: 0 !important; } - .ps-xxl-1 { padding-left: 0.25rem !important; } - .ps-xxl-2 { padding-left: 0.5rem !important; } - .ps-xxl-3 { padding-left: 1rem !important; } - .ps-xxl-4 { padding-left: 1.5rem !important; } - .ps-xxl-5 { padding-left: 3rem !important; } - .gap-xxl-0 { gap: 0 !important; } - .gap-xxl-1 { gap: 0.25rem !important; } - .gap-xxl-2 { gap: 0.5rem !important; } - .gap-xxl-3 { gap: 1rem !important; } - .gap-xxl-4 { gap: 1.5rem !important; } - .gap-xxl-5 { gap: 3rem !important; } - .text-xxl-start { text-align: left !important; } - .text-xxl-end { text-align: right !important; } - .text-xxl-center { text-align: center !important; } @@ -11832,15 +10861,12 @@ textarea.form-control-lg { .fs-1 { font-size: 2.5rem !important; } - .fs-2 { font-size: 2rem !important; } - .fs-3 { font-size: 1.75rem !important; } - .fs-4 { font-size: 1.5rem !important; } @@ -11849,39 +10875,30 @@ textarea.form-control-lg { .d-print-inline { display: inline !important; } - .d-print-inline-block { display: inline-block !important; } - .d-print-block { display: block !important; } - .d-print-grid { display: grid !important; } - .d-print-table { display: table !important; } - .d-print-table-row { display: table-row !important; } - .d-print-table-cell { display: table-cell !important; } - .d-print-flex { display: flex !important; } - .d-print-inline-flex { display: inline-flex !important; } - .d-print-none { display: none !important; } diff --git a/src/static/scripts/jquery-3.6.0.slim.js b/src/static/scripts/jquery-3.6.1.slim.js similarity index 98% rename from src/static/scripts/jquery-3.6.0.slim.js rename to src/static/scripts/jquery-3.6.1.slim.js index 665bf108..91512c95 100644 --- a/src/static/scripts/jquery-3.6.0.slim.js +++ b/src/static/scripts/jquery-3.6.1.slim.js @@ -1,5 +1,5 @@ /*! - * jQuery JavaScript Library v3.6.0 -ajax,-ajax/jsonp,-ajax/load,-ajax/script,-ajax/var/location,-ajax/var/nonce,-ajax/var/rquery,-ajax/xhr,-manipulation/_evalUrl,-deprecated/ajax-event-alias,-effects,-effects/Tween,-effects/animatedSelector + * jQuery JavaScript Library v3.6.1 -ajax,-ajax/jsonp,-ajax/load,-ajax/script,-ajax/var/location,-ajax/var/nonce,-ajax/var/rquery,-ajax/xhr,-manipulation/_evalUrl,-deprecated/ajax-event-alias,-effects,-effects/Tween,-effects/animatedSelector * https://jquery.com/ * * Includes Sizzle.js @@ -9,7 +9,7 @@ * Released under the MIT license * https://jquery.org/license * - * Date: 2021-03-02T17:08Z + * Date: 2022-08-26T17:52Z */ ( function( global, factory ) { @@ -23,7 +23,7 @@ // (such as Node.js), expose a factory as module.exports. // This accentuates the need for the creation of a real `window`. // e.g. var jQuery = require("jquery")(window); - // See ticket #14549 for more info. + // See ticket trac-14549 for more info. module.exports = global.document ? factory( global, true ) : function( w ) { @@ -151,7 +151,7 @@ function toType( obj ) { var - version = "3.6.0 -ajax,-ajax/jsonp,-ajax/load,-ajax/script,-ajax/var/location,-ajax/var/nonce,-ajax/var/rquery,-ajax/xhr,-manipulation/_evalUrl,-deprecated/ajax-event-alias,-effects,-effects/Tween,-effects/animatedSelector", + version = "3.6.1 -ajax,-ajax/jsonp,-ajax/load,-ajax/script,-ajax/var/location,-ajax/var/nonce,-ajax/var/rquery,-ajax/xhr,-manipulation/_evalUrl,-deprecated/ajax-event-alias,-effects,-effects/Tween,-effects/animatedSelector", // Define a local copy of jQuery jQuery = function( selector, context ) { @@ -3129,8 +3129,8 @@ jQuery.fn.extend( { var rootjQuery, // A simple way to check for HTML strings - // Prioritize #id over to avoid XSS via location.hash (#9521) - // Strict HTML recognition (#11290: must start with <) + // Prioritize #id over to avoid XSS via location.hash (trac-9521) + // Strict HTML recognition (trac-11290: must start with <) // Shortcut simple #id case for speed rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, @@ -4087,7 +4087,7 @@ jQuery.extend( { isReady: false, // A counter to track how many items to wait for before - // the ready event fires. See #6781 + // the ready event fires. See trac-6781 readyWait: 1, // Handle when the DOM is ready @@ -4215,7 +4215,7 @@ function fcamelCase( _all, letter ) { // Convert dashed to camelCase; used by the css and data modules // Support: IE <=9 - 11, Edge 12 - 15 -// Microsoft forgot to hump their vendor prefix (#9572) +// Microsoft forgot to hump their vendor prefix (trac-9572) function camelCase( string ) { return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); } @@ -4251,7 +4251,7 @@ Data.prototype = { value = {}; // We can accept data for non-element nodes in modern browsers, - // but we should not, see #8335. + // but we should not, see trac-8335. // Always return an empty object. if ( acceptData( owner ) ) { @@ -4490,7 +4490,7 @@ jQuery.fn.extend( { while ( i-- ) { // Support: IE 11 only - // The attrs elements can be null (#14894) + // The attrs elements can be null (trac-14894) if ( attrs[ i ] ) { name = attrs[ i ].name; if ( name.indexOf( "data-" ) === 0 ) { @@ -4913,9 +4913,9 @@ var rscriptType = ( /^$|^module$|\/(?:java|ecma)script/i ); input = document.createElement( "input" ); // Support: Android 4.0 - 4.3 only - // Check state lost if the name is set (#11217) + // Check state lost if the name is set (trac-11217) // Support: Windows Web Apps (WWA) - // `name` and `type` must use .setAttribute for WWA (#14901) + // `name` and `type` must use .setAttribute for WWA (trac-14901) input.setAttribute( "type", "radio" ); input.setAttribute( "checked", "checked" ); input.setAttribute( "name", "t" ); @@ -4939,7 +4939,7 @@ var rscriptType = ( /^$|^module$|\/(?:java|ecma)script/i ); } )(); -// We have to close these tags to support XHTML (#13200) +// We have to close these tags to support XHTML (trac-13200) var wrapMap = { // XHTML parsers do not magically insert elements in the @@ -4965,7 +4965,7 @@ if ( !support.option ) { function getAll( context, tag ) { // Support: IE <=9 - 11 only - // Use typeof to avoid zero-argument method invocation on host objects (#15151) + // Use typeof to avoid zero-argument method invocation on host objects (trac-15151) var ret; if ( typeof context.getElementsByTagName !== "undefined" ) { @@ -5048,7 +5048,7 @@ function buildFragment( elems, context, scripts, selection, ignored ) { // Remember the top-level container tmp = fragment.firstChild; - // Ensure the created nodes are orphaned (#12392) + // Ensure the created nodes are orphaned (trac-12392) tmp.textContent = ""; } } @@ -5469,15 +5469,15 @@ jQuery.event = { for ( ; cur !== this; cur = cur.parentNode || this ) { - // Don't check non-elements (#13208) - // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) + // Don't check non-elements (trac-13208) + // Don't process clicks on disabled elements (trac-6911, trac-8165, trac-11382, trac-11764) if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) { matchedHandlers = []; matchedSelectors = {}; for ( i = 0; i < delegateCount; i++ ) { handleObj = handlers[ i ]; - // Don't conflict with Object.prototype properties (#13203) + // Don't conflict with Object.prototype properties (trac-13203) sel = handleObj.selector + " "; if ( matchedSelectors[ sel ] === undefined ) { @@ -5731,7 +5731,7 @@ jQuery.Event = function( src, props ) { // Create target properties // Support: Safari <=6 - 7 only - // Target should not be a text node (#504, #13143) + // Target should not be a text node (trac-504, trac-13143) this.target = ( src.target && src.target.nodeType === 3 ) ? src.target.parentNode : src.target; @@ -5854,10 +5854,10 @@ jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateTyp return true; }, - // Suppress native focus or blur as it's already being fired - // in leverageNative. - _default: function() { - return true; + // Suppress native focus or blur if we're currently inside + // a leveraged native-event stack + _default: function( event ) { + return dataPriv.get( event.target, type ); }, delegateType: delegateType @@ -5956,7 +5956,8 @@ var // checked="checked" or checked rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i, - rcleanScript = /^\s*\s*$/g; + + rcleanScript = /^\s*\s*$/g; // Prefer a tbody over its parent table for containing new rows function manipulationTarget( elem, content ) { @@ -6070,7 +6071,7 @@ function domManip( collection, args, callback, ignored ) { // Use the original fragment for the last item // instead of the first because it can end up - // being emptied incorrectly in certain situations (#8070). + // being emptied incorrectly in certain situations (trac-8070). for ( ; i < l; i++ ) { node = fragment; @@ -6111,6 +6112,12 @@ function domManip( collection, args, callback, ignored ) { }, doc ); } } else { + + // Unwrap a CDATA section containing script contents. This shouldn't be + // needed as in XML documents they're already not visible when + // inspecting element contents and in HTML documents they have no + // meaning but we're preserving that logic for backwards compatibility. + // This will be removed completely in 4.0. See gh-4904. DOMEval( node.textContent.replace( rcleanScript, "" ), node, doc ); } } @@ -6393,9 +6400,12 @@ jQuery.each( { } ); var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); +var rcustomProp = /^--/; + + var getStyles = function( elem ) { - // Support: IE <=11 only, Firefox <=30 (#15098, #14150) + // Support: IE <=11 only, Firefox <=30 (trac-15098, trac-14150) // IE throws on elements created in popups // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" var view = elem.ownerDocument.defaultView; @@ -6430,6 +6440,15 @@ var swap = function( elem, options, callback ) { var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" ); +var whitespace = "[\\x20\\t\\r\\n\\f]"; + + +var rtrimCSS = new RegExp( + "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", + "g" +); + + ( function() { @@ -6495,7 +6514,7 @@ var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" ); } // Support: IE <=9 - 11 only - // Style of cloned element affects source element cloned (#8908) + // Style of cloned element affects source element cloned (trac-8908) div.style.backgroundClip = "content-box"; div.cloneNode( true ).style.backgroundClip = ""; support.clearCloneStyle = div.style.backgroundClip === "content-box"; @@ -6575,6 +6594,7 @@ var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" ); function curCSS( elem, name, computed ) { var width, minWidth, maxWidth, ret, + isCustomProp = rcustomProp.test( name ), // Support: Firefox 51+ // Retrieving style before computed somehow @@ -6585,11 +6605,22 @@ function curCSS( elem, name, computed ) { computed = computed || getStyles( elem ); // getPropertyValue is needed for: - // .css('filter') (IE 9 only, #12537) - // .css('--customProperty) (#3144) + // .css('filter') (IE 9 only, trac-12537) + // .css('--customProperty) (gh-3144) if ( computed ) { ret = computed.getPropertyValue( name ) || computed[ name ]; + // trim whitespace for custom property (issue gh-4926) + if ( isCustomProp ) { + + // rtrim treats U+000D CARRIAGE RETURN and U+000C FORM FEED + // as whitespace while CSS does not, but this is not a problem + // because CSS preprocessing replaces them with U+000A LINE FEED + // (which *is* CSS whitespace) + // https://www.w3.org/TR/css-syntax-3/#input-preprocessing + ret = ret.replace( rtrimCSS, "$1" ); + } + if ( ret === "" && !isAttached( elem ) ) { ret = jQuery.style( elem, name ); } @@ -6685,7 +6716,6 @@ var // except "table", "table-cell", or "table-caption" // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display rdisplayswap = /^(none|table(?!-c[ea]).+)/, - rcustomProp = /^--/, cssShow = { position: "absolute", visibility: "hidden", display: "block" }, cssNormalTransform = { letterSpacing: "0", @@ -6921,15 +6951,15 @@ jQuery.extend( { if ( value !== undefined ) { type = typeof value; - // Convert "+=" or "-=" to relative numbers (#7345) + // Convert "+=" or "-=" to relative numbers (trac-7345) if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) { value = adjustCSS( elem, name, ret ); - // Fixes bug #9237 + // Fixes bug trac-9237 type = "number"; } - // Make sure that null and NaN values aren't set (#7116) + // Make sure that null and NaN values aren't set (trac-7116) if ( value == null || value !== value ) { return; } @@ -7149,7 +7179,6 @@ jQuery.fn.extend( { // Based off of the plugin by Clint Helfers, with permission. -// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/ jQuery.fn.delay = function( time, type ) { time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; type = type || "fx"; @@ -7374,8 +7403,7 @@ jQuery.extend( { // Support: IE <=9 - 11 only // elem.tabIndex doesn't always return the // correct value when it hasn't been explicitly set - // https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ - // Use proper attribute retrieval(#12072) + // Use proper attribute retrieval (trac-12072) var tabindex = jQuery.find.attr( elem, "tabindex" ); if ( tabindex ) { @@ -7479,8 +7507,7 @@ function classesToArray( value ) { jQuery.fn.extend( { addClass: function( value ) { - var classes, elem, cur, curValue, clazz, j, finalValue, - i = 0; + var classNames, cur, curValue, className, i, finalValue; if ( isFunction( value ) ) { return this.each( function( j ) { @@ -7488,36 +7515,35 @@ jQuery.fn.extend( { } ); } - classes = classesToArray( value ); + classNames = classesToArray( value ); - if ( classes.length ) { - while ( ( elem = this[ i++ ] ) ) { - curValue = getClass( elem ); - cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + if ( classNames.length ) { + return this.each( function() { + curValue = getClass( this ); + cur = this.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); if ( cur ) { - j = 0; - while ( ( clazz = classes[ j++ ] ) ) { - if ( cur.indexOf( " " + clazz + " " ) < 0 ) { - cur += clazz + " "; + for ( i = 0; i < classNames.length; i++ ) { + className = classNames[ i ]; + if ( cur.indexOf( " " + className + " " ) < 0 ) { + cur += className + " "; } } // Only assign if different to avoid unneeded rendering. finalValue = stripAndCollapse( cur ); if ( curValue !== finalValue ) { - elem.setAttribute( "class", finalValue ); + this.setAttribute( "class", finalValue ); } } - } + } ); } return this; }, removeClass: function( value ) { - var classes, elem, cur, curValue, clazz, j, finalValue, - i = 0; + var classNames, cur, curValue, className, i, finalValue; if ( isFunction( value ) ) { return this.each( function( j ) { @@ -7529,45 +7555,42 @@ jQuery.fn.extend( { return this.attr( "class", "" ); } - classes = classesToArray( value ); + classNames = classesToArray( value ); - if ( classes.length ) { - while ( ( elem = this[ i++ ] ) ) { - curValue = getClass( elem ); + if ( classNames.length ) { + return this.each( function() { + curValue = getClass( this ); // This expression is here for better compressibility (see addClass) - cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + cur = this.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); if ( cur ) { - j = 0; - while ( ( clazz = classes[ j++ ] ) ) { + for ( i = 0; i < classNames.length; i++ ) { + className = classNames[ i ]; // Remove *all* instances - while ( cur.indexOf( " " + clazz + " " ) > -1 ) { - cur = cur.replace( " " + clazz + " ", " " ); + while ( cur.indexOf( " " + className + " " ) > -1 ) { + cur = cur.replace( " " + className + " ", " " ); } } // Only assign if different to avoid unneeded rendering. finalValue = stripAndCollapse( cur ); if ( curValue !== finalValue ) { - elem.setAttribute( "class", finalValue ); + this.setAttribute( "class", finalValue ); } } - } + } ); } return this; }, toggleClass: function( value, stateVal ) { - var type = typeof value, + var classNames, className, i, self, + type = typeof value, isValidValue = type === "string" || Array.isArray( value ); - if ( typeof stateVal === "boolean" && isValidValue ) { - return stateVal ? this.addClass( value ) : this.removeClass( value ); - } - if ( isFunction( value ) ) { return this.each( function( i ) { jQuery( this ).toggleClass( @@ -7577,17 +7600,20 @@ jQuery.fn.extend( { } ); } - return this.each( function() { - var className, i, self, classNames; + if ( typeof stateVal === "boolean" && isValidValue ) { + return stateVal ? this.addClass( value ) : this.removeClass( value ); + } + + classNames = classesToArray( value ); + return this.each( function() { if ( isValidValue ) { // Toggle individual class names - i = 0; self = jQuery( this ); - classNames = classesToArray( value ); - while ( ( className = classNames[ i++ ] ) ) { + for ( i = 0; i < classNames.length; i++ ) { + className = classNames[ i ]; // Check each className given, space separated list if ( self.hasClass( className ) ) { @@ -7721,7 +7747,7 @@ jQuery.extend( { val : // Support: IE <=10 - 11 only - // option.text throws exceptions (#14686, #14858) + // option.text throws exceptions (trac-14686, trac-14858) // Strip and collapse whitespace // https://html.spec.whatwg.org/#strip-and-collapse-whitespace stripAndCollapse( jQuery.text( elem ) ); @@ -7748,7 +7774,7 @@ jQuery.extend( { option = options[ i ]; // Support: IE <=9 only - // IE8-9 doesn't update selected after form reset (#2551) + // IE8-9 doesn't update selected after form reset (trac-2551) if ( ( option.selected || i === index ) && // Don't return options that are disabled or in a disabled optgroup @@ -7891,8 +7917,8 @@ jQuery.extend( jQuery.event, { return; } - // Determine event propagation path in advance, per W3C events spec (#9951) - // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + // Determine event propagation path in advance, per W3C events spec (trac-9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (trac-9724) if ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) { bubbleType = special.delegateType || type; @@ -7944,7 +7970,7 @@ jQuery.extend( jQuery.event, { acceptData( elem ) ) { // Call a native DOM method on the target with the same name as the event. - // Don't do default actions on window, that's where global variables be (#6170) + // Don't do default actions on window, that's where global variables be (trac-6170) if ( ontype && isFunction( elem[ type ] ) && !isWindow( elem ) ) { // Don't re-trigger an onFOO event when we call its FOO() method @@ -8654,7 +8680,9 @@ jQuery.each( // Support: Android <=4.0 only // Make sure we trim BOM and NBSP -var rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g; +// Require that the "whitespace run" starts from a non-whitespace +// to avoid O(N^2) behavior when the engine would try matching "\s+$" at each space position. +var rtrim = /^[\s\uFEFF\xA0]+|([^\s\uFEFF\xA0])[\s\uFEFF\xA0]+$/g; // Bind a function to a context, optionally partially applying any // arguments. @@ -8721,7 +8749,7 @@ jQuery.isNumeric = function( obj ) { jQuery.trim = function( text ) { return text == null ? "" : - ( text + "" ).replace( rtrim, "" ); + ( text + "" ).replace( rtrim, "$1" ); }; @@ -8769,8 +8797,8 @@ jQuery.noConflict = function( deep ) { }; // Expose jQuery and $ identifiers, even in AMD -// (#7102#comment:10, https://github.com/jquery/jquery/pull/557) -// and CommonJS for browser emulators (#13566) +// (trac-7102#comment:10, https://github.com/jquery/jquery/pull/557) +// and CommonJS for browser emulators (trac-13566) if ( typeof noGlobal === "undefined" ) { window.jQuery = window.$ = jQuery; } diff --git a/src/static/templates/admin/diagnostics.hbs b/src/static/templates/admin/diagnostics.hbs index 6fd08f4a..99f27193 100644 --- a/src/static/templates/admin/diagnostics.hbs +++ b/src/static/templates/admin/diagnostics.hbs @@ -168,8 +168,8 @@
If you need support please check the following links first before you create a new issue: - Vaultwarden Forum - | Github Discussions + Vaultwarden Forum + | Github Discussions
diff --git a/src/static/templates/admin/organizations.hbs b/src/static/templates/admin/organizations.hbs index ac3c0f30..71485901 100644 --- a/src/static/templates/admin/organizations.hbs +++ b/src/static/templates/admin/organizations.hbs @@ -49,7 +49,7 @@ - + +