vw_small

Hardened fork of Vaultwarden (https://github.com/dani-garcia/vaultwarden) with fewer features.
git clone https://git.philomathiclife.com/repos/vw_small
Log | Files | Refs | README

commit d0bf0ab2370daff3353baaf22291f2dff34c1a5b
parent ead2f02cbd8a6fe29da0d0b09e68569920d3a4d2
Author: Daniel García <dani-garcia@users.noreply.github.com>
Date:   Wed,  8 Dec 2021 00:26:31 +0100

Merge pull request #2125 from BlackDex/trust-dns

Enabled trust-dns and some updates.
Diffstat:
MCargo.lock | 307+++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------
MCargo.toml | 15++++++---------
Msrc/api/admin.rs | 6+++---
Msrc/main.rs | 10++++++++++
Msrc/static/scripts/bootstrap-native.js | 398++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
Msrc/static/scripts/bootstrap.css | 947+++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------
Msrc/static/scripts/datatables.css | 4++--
Msrc/static/scripts/datatables.js | 227++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------------
Msrc/static/templates/admin/diagnostics.hbs | 2+-
9 files changed, 1295 insertions(+), 621 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock @@ -56,6 +56,17 @@ dependencies = [ ] [[package]] +name = "async-trait" +version = "0.1.51" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44318e776df68115a881de9a8fd1b9e53368d7a4a5ce4cc48517da3393233a5e" +dependencies = [ + "proc-macro2 1.0.32", + "quote 1.0.10", + "syn 1.0.82", +] + +[[package]] name = "atty" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -230,9 +241,9 @@ checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" [[package]] name = "cc" -version = "1.0.71" +version = "1.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79c2681d6594606957bbb8631c4b90a7fcaaa72cdb714743a437b156d6a7eedd" +checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee" [[package]] name = "cfg-if" @@ -322,9 +333,9 @@ dependencies = [ [[package]] name = "cookie_store" -version = "0.15.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55b4ac5559dd39f7bdc516f769cb412b151585d8886d216871a8435ed7f862cd" +checksum = "b3f7034c0932dc36f5bd8ec37368d971346809435824f277cb3b8299fc56167c" dependencies = [ "cookie 0.15.1", "idna 0.2.3", @@ -363,9 +374,9 @@ dependencies = [ [[package]] name = "crc32fast" -version = "1.2.1" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a" +checksum = "738c290dfaea84fc1ca15ad9c168d083b05a714e1efddd8edaab678dc28d2836" dependencies = [ "cfg-if 1.0.0", ] @@ -409,8 +420,9 @@ checksum = "3ee2393c4a91429dffb4bedf19f4d6abf27d8a732c8ce4980305d782e5426d57" [[package]] name = "data-url" -version = "0.1.0" -source = "git+https://github.com/servo/rust-url?rev=eb7330b5296c0d43816d1346211b74182bb4ae37#eb7330b5296c0d43816d1346211b74182bb4ae37" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a30bfce702bcfa94e906ef82421f2c0e61c076ad76030c16ee5d2e9a32fe193" dependencies = [ "matches", ] @@ -441,7 +453,7 @@ dependencies = [ "bitflags", "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.81", + "syn 1.0.82", ] [[package]] @@ -469,7 +481,7 @@ checksum = "45f5098f628d02a7a0f68ddba586fb61e80edec3bdc1be3b921f4ceec60858d3" dependencies = [ "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.81", + "syn 1.0.82", ] [[package]] @@ -528,6 +540,18 @@ dependencies = [ ] [[package]] +name = "enum-as-inner" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c5f0096a91d210159eceb2ff5e1c4da18388a170e1e3ce948aac9c8fdbbf595" +dependencies = [ + "heck", + "proc-macro2 1.0.32", + "quote 1.0.10", + "syn 1.0.82", +] + +[[package]] name = "error-chain" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -638,9 +662,9 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a12aa0eb539080d55c3f2d45a67c3b58b6b0773c1a3ca2dfec66d58c97fd66ca" +checksum = "8cd0210d8c325c245ff06fd95a3b13689a1a276ac8cfa8e8720cb840bfb84b9e" dependencies = [ "futures-channel", "futures-core", @@ -653,9 +677,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5da6ba8c3bb3c165d3c7319fc1cc8304facf1fb8db99c5de877183c08a273888" +checksum = "7fc8cd39e3dbf865f7340dce6a2d401d24fd37c6fe6c4f0ee0de8bfca2252d27" dependencies = [ "futures-core", "futures-sink", @@ -663,15 +687,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d1c26957f23603395cd326b0ffe64124b818f4449552f960d815cfba83a53d" +checksum = "629316e42fe7c2a0b9a65b47d159ceaa5453ab14e8f0a3c5eedbb8cd55b4a445" [[package]] name = "futures-executor" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45025be030969d763025784f7f355043dc6bc74093e4ecc5000ca4dc50d8745c" +checksum = "7b808bf53348a36cab739d7e04755909b9fcaaa69b7d7e588b37b6ec62704c97" dependencies = [ "futures-core", "futures-task", @@ -680,42 +704,39 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "522de2a0fe3e380f1bc577ba0474108faf3f6b18321dbf60b3b9c39a75073377" +checksum = "e481354db6b5c353246ccf6a728b0c5511d752c08da7260546fc0933869daa11" [[package]] name = "futures-macro" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18e4a4b95cea4b4ccbcf1c5675ca7c4ee4e9e75eb79944d07defde18068f79bb" +checksum = "a89f17b21645bc4ed773c69af9c9a0effd4a3f1a3876eadd453469f8854e7fdd" dependencies = [ - "autocfg", - "proc-macro-hack", "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.81", + "syn 1.0.82", ] [[package]] name = "futures-sink" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36ea153c13024fe480590b3e3d4cad89a0cfacecc24577b68f86c6ced9c2bc11" +checksum = "996c6442437b62d21a32cd9906f9c41e7dc1e19a9579843fad948696769305af" [[package]] name = "futures-task" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d3d00f4eddb73e498a54394f228cd55853bdf059259e8e7bc6e69d408892e99" +checksum = "dabf1872aaab32c886832f2276d2f5399887e2bd613698a02359e4ea83f8de12" [[package]] name = "futures-util" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36568465210a3a6ee45e1f165136d68671471a501e632e9a98d96872222b5481" +checksum = "41d22213122356472061ac0f1ab2cee28d2bac8491410fd68c2af53d1cedb83e" dependencies = [ - "autocfg", "futures-channel", "futures-core", "futures-io", @@ -725,8 +746,6 @@ dependencies = [ "memchr", "pin-project-lite", "pin-utils", - "proc-macro-hack", - "proc-macro-nested", "slab", ] @@ -810,9 +829,9 @@ checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" [[package]] name = "handlebars" -version = "4.1.3" +version = "4.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66b09e2322d20d14bc2572401ce7c1d60b4748580a76c230ed9c1f8938f0c833" +checksum = "8ad84da8f63da982543fc85fcabaee2ad1fdd809d99d64a48887e2e942ddfe46" dependencies = [ "log 0.4.14", "pest", @@ -830,6 +849,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" [[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + +[[package]] name = "hermit-abi" version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -880,7 +908,7 @@ dependencies = [ "markup5ever", "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.81", + "syn 1.0.82", ] [[package]] @@ -913,9 +941,9 @@ checksum = "acd94fdbe1d4ff688b67b04eee2e17bd50995534a61539e45adfefb45e5e5503" [[package]] name = "httpdate" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6456b8a6c8f33fee7d958fcd1b60d55b11940a79e63ae87013e6d22e26034440" +checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" [[package]] name = "hyper" @@ -938,9 +966,9 @@ dependencies = [ [[package]] name = "hyper" -version = "0.14.14" +version = "0.14.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b91bb1f221b6ea1f1e4371216b70f40748774c2fb5971b450c07773fb92d26b" +checksum = "436ec0091e4f20e655156a30a0df3770fe2900aa301e548e08446ec794b6953c" dependencies = [ "bytes 1.1.0", "futures-channel", @@ -953,7 +981,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2", + "socket2 0.4.2", "tokio", "tower-service", "tracing", @@ -979,7 +1007,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" dependencies = [ "bytes 1.1.0", - "hyper 0.14.14", + "hyper 0.14.15", "native-tls", "tokio", "tokio-native-tls", @@ -1036,6 +1064,18 @@ dependencies = [ ] [[package]] +name = "ipconfig" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7e2f18aece9709094573a9f24f483c4f65caa4298e2f7ae1b71cc65d853fad7" +dependencies = [ + "socket2 0.3.19", + "widestring", + "winapi 0.3.9", + "winreg 0.6.2", +] + +[[package]] name = "ipnet" version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1131,9 +1171,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.106" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a60553f9a9e039a333b4e9b20573b9e9b9c0bb3a11e201ccc48ef4283456d673" +checksum = "8521a1b57e76b1ec69af7599e75e38e7b7fad6610f037db8c79b127201b5d119" [[package]] name = "libsqlite3-sys" @@ -1147,6 +1187,12 @@ dependencies = [ ] [[package]] +name = "linked-hash-map" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" + +[[package]] name = "lock_api" version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1174,6 +1220,15 @@ dependencies = [ ] [[package]] +name = "lru-cache" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" +dependencies = [ + "linked-hash-map", +] + +[[package]] name = "mac" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1253,7 +1308,7 @@ dependencies = [ "migrations_internals", "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.81", + "syn 1.0.82", ] [[package]] @@ -1473,7 +1528,7 @@ checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" dependencies = [ "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.81", + "syn 1.0.82", ] [[package]] @@ -1563,9 +1618,9 @@ dependencies = [ [[package]] name = "openssl-sys" -version = "0.9.70" +version = "0.9.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6517987b3f8226b5da3661dad65ff7f300cc59fb5ea8333ca191fc65fde3edf" +checksum = "7df13d165e607909b363a4757a6f133f8a818a74e9d3a98d09c6128e15fa4c73" dependencies = [ "autocfg", "cc", @@ -1660,9 +1715,9 @@ dependencies = [ [[package]] name = "paste" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf547ad0c65e31259204bd90935776d1c693cec2f4ff7abb7a1bbbd40dfe58" +checksum = "0744126afe1a6dd7f394cb50a716dbe086cb06e255e53d8d0185d82828358fb5" [[package]] name = "pear" @@ -1738,7 +1793,7 @@ dependencies = [ "pest_meta", "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.81", + "syn 1.0.82", ] [[package]] @@ -1881,12 +1936,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" [[package]] -name = "proc-macro-nested" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" - -[[package]] name = "proc-macro2" version = "0.4.30" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1906,9 +1955,9 @@ dependencies = [ [[package]] name = "psl-types" -version = "2.0.7" +version = "2.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66b398073e7cdd6f05934389a8f5961e3aabfa66675b6f440df4e2c793d51a4f" +checksum = "4af8f675df9e68626b5059f8909ae261b8f5c3e8ab14813ad7f6cc7a134dcafb" [[package]] name = "publicsuffix" @@ -1954,9 +2003,9 @@ dependencies = [ [[package]] name = "quoted_printable" -version = "0.4.3" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1238256b09923649ec89b08104c4dfe9f6cb2fea734a5db5384e44916d59e9c5" +checksum = "3fee2dce59f7a43418e3382c766554c614e06a552d53a8f07ef499ea4b332c0f" [[package]] name = "r2d2" @@ -2134,9 +2183,9 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.11.6" +version = "0.11.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66d2927ca2f685faf0fc620ac4834690d29e7abb153add10f5812eef20b5e280" +checksum = "07bea77bc708afa10e59905c3d4af7c8fd43c9214251673095ff8b14345fcbc5" dependencies = [ "async-compression", "base64 0.13.0", @@ -2148,7 +2197,7 @@ dependencies = [ "futures-util", "http", "http-body", - "hyper 0.14.14", + "hyper 0.14.15", "hyper-tls", "ipnet", "js-sys", @@ -2158,19 +2207,30 @@ dependencies = [ "native-tls", "percent-encoding 2.1.0", "pin-project-lite", + "proc-macro-hack", "serde", "serde_json", "serde_urlencoded", - "time 0.2.27", "tokio", "tokio-native-tls", "tokio-socks", "tokio-util", + "trust-dns-resolver", "url 2.2.2", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "winreg", + "winreg 0.7.0", +] + +[[package]] +name = "resolv-conf" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52e44394d2086d010551b14b53b1f24e31647570cd1deb0379e2c21b329aba00" +dependencies = [ + "hostname", + "quick-error 1.2.3", ] [[package]] @@ -2301,9 +2361,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" +checksum = "3c9613b5a66ab9ba26415184cfc41156594925a9cf3a2057e57f31ff145f6568" [[package]] name = "safemem" @@ -2429,14 +2489,14 @@ checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b" dependencies = [ "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.81", + "syn 1.0.82", ] [[package]] name = "serde_json" -version = "1.0.68" +version = "1.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f690853975602e1bfe1ccbf50504d67174e3bcf340f23b5ea9992e0587a52d8" +checksum = "d0ffa0837f2dfa6fb90868c2b5468cad482e175f7dad97e7421951e663f2b527" dependencies = [ "itoa", "ryu", @@ -2539,6 +2599,17 @@ checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" [[package]] name = "socket2" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "winapi 0.3.9", +] + +[[package]] +name = "socket2" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5dc90fe6c7be1a323296982db1836d1ea9e47b6839496dde9a541bc496df3516" @@ -2598,7 +2669,7 @@ dependencies = [ "quote 1.0.10", "serde", "serde_derive", - "syn 1.0.81", + "syn 1.0.82", ] [[package]] @@ -2614,7 +2685,7 @@ dependencies = [ "serde_derive", "serde_json", "sha1", - "syn 1.0.81", + "syn 1.0.82", ] [[package]] @@ -2668,9 +2739,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.81" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2afee18b8beb5a596ecb4a2dce128c719b4ba399d34126b9e4396e3f9860966" +checksum = "8daf5dd0bb60cbd4137b1b587d2fc0ae729bc07cf01cd70b36a1ed5ade3b9d59" dependencies = [ "proc-macro2 1.0.32", "quote 1.0.10", @@ -2731,7 +2802,7 @@ checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" dependencies = [ "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.81", + "syn 1.0.82", ] [[package]] @@ -2789,14 +2860,14 @@ dependencies = [ "proc-macro2 1.0.32", "quote 1.0.10", "standback", - "syn 1.0.81", + "syn 1.0.82", ] [[package]] name = "tinyvec" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f83b2a3d4d9091d0abd7eba4dc2710b1718583bd4d8992e2190720ea38f391f7" +checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2" dependencies = [ "tinyvec_macros", ] @@ -2809,9 +2880,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.13.0" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "588b2d10a336da58d877567cd8fb8a14b463e2104910f8132cd054b4b96e29ee" +checksum = "70e992e41e0d2fb9f755b37446f20900f64446ef54874f40a60c78f021ac6144" dependencies = [ "autocfg", "bytes 1.1.0", @@ -2907,7 +2978,7 @@ checksum = "f4f480b8f81512e825f337ad51e94c1eb5d3bbdf2b363dcd01e2b19a9ffe3f8e" dependencies = [ "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.81", + "syn 1.0.82", ] [[package]] @@ -2926,6 +2997,51 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" [[package]] +name = "trust-dns-proto" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0d7f5db438199a6e2609debe3f69f808d074e0a2888ee0bccb45fe234d03f4" +dependencies = [ + "async-trait", + "cfg-if 1.0.0", + "data-encoding", + "enum-as-inner", + "futures-channel", + "futures-io", + "futures-util", + "idna 0.2.3", + "ipnet", + "lazy_static", + "log 0.4.14", + "rand 0.8.4", + "smallvec 1.7.0", + "thiserror", + "tinyvec", + "tokio", + "url 2.2.2", +] + +[[package]] +name = "trust-dns-resolver" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ad17b608a64bd0735e67bde16b0636f8aa8591f831a25d18443ed00a699770" +dependencies = [ + "cfg-if 1.0.0", + "futures-util", + "ipconfig", + "lazy_static", + "log 0.4.14", + "lru-cache", + "parking_lot 0.11.2", + "resolv-conf", + "smallvec 1.7.0", + "thiserror", + "tokio", + "trust-dns-proto", +] + +[[package]] name = "try-lock" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3018,6 +3134,12 @@ dependencies = [ ] [[package]] +name = "unicode-segmentation" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" + +[[package]] name = "unicode-xid" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3201,7 +3323,7 @@ dependencies = [ "log 0.4.14", "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.81", + "syn 1.0.82", "wasm-bindgen-shared", ] @@ -3235,7 +3357,7 @@ checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab" dependencies = [ "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.81", + "syn 1.0.82", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -3296,6 +3418,12 @@ dependencies = [ ] [[package]] +name = "widestring" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c168940144dd21fd8046987c16a46a33d5fc84eec29ef9dcddc2ac9e31526b7c" + +[[package]] name = "winapi" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3340,6 +3468,15 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "winreg" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2986deb581c4fe11b621998a5e53361efe6b48a151178d0cd9eeffa4dc6acc9" +dependencies = [ + "winapi 0.3.9", +] + +[[package]] +name = "winreg" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0120db82e8a1e0b9fb3345a539c478767c0048d842860994d96113d5b667bd69" diff --git a/Cargo.toml b/Cargo.toml @@ -34,11 +34,11 @@ rocket = { version = "=0.5.0-dev", features = ["tls"], default-features = false rocket_contrib = "=0.5.0-dev" # HTTP client -reqwest = { version = "0.11.6", features = ["blocking", "json", "gzip", "brotli", "socks", "cookies"] } +reqwest = { version = "0.11.7", features = ["blocking", "json", "gzip", "brotli", "socks", "cookies", "trust-dns"] } # Used for custom short lived cookie jar cookie = "0.15.1" -cookie_store = "0.15.0" +cookie_store = "0.15.1" bytes = "1.1.0" url = "2.2.2" @@ -56,7 +56,7 @@ chashmap = "2.2.2" # A generic serialization/deserialization framework serde = { version = "1.0.130", features = ["derive"] } -serde_json = "1.0.68" +serde_json = "1.0.72" # Logging log = "0.4.14" @@ -115,13 +115,13 @@ tracing = { version = "0.1.29", features = ["log"] } # Needed to have lettre tra lettre = { version = "0.10.0-rc.4", features = ["smtp-transport", "builder", "serde", "native-tls", "hostname", "tracing"], default-features = false } # Template library -handlebars = { version = "4.1.3", features = ["dir_source"] } +handlebars = { version = "4.1.5", features = ["dir_source"] } # For favicon extraction from main website html5ever = "0.25.1" markup5ever_rcdom = "0.1.0" regex = { version = "1.5.4", features = ["std", "perf", "unicode-perl"], default-features = false } -data-url = "0.1.0" +data-url = "0.1.1" # Used by U2F, JWT and Postgres openssl = "0.10.38" @@ -138,16 +138,13 @@ pico-args = "0.4.2" backtrace = "0.3.63" # Macro ident concatenation -paste = "1.0.5" +paste = "1.0.6" [patch.crates-io] # Use newest ring rocket = { git = 'https://github.com/SergioBenitez/Rocket', rev = '263e39b5b429de1913ce7e3036575a7b4d88b6d7' } rocket_contrib = { git = 'https://github.com/SergioBenitez/Rocket', rev = '263e39b5b429de1913ce7e3036575a7b4d88b6d7' } -# For favicon extraction from main website -data-url = { git = 'https://github.com/servo/rust-url', package="data-url", rev = 'eb7330b5296c0d43816d1346211b74182bb4ae37' } - # The maintainer of the `job_scheduler` crate doesn't seem to have responded # to any issues or PRs for almost a year (as of April 2021). This hopefully # temporary fork updates Cargo.toml to use more up-to-date dependencies. diff --git a/src/api/admin.rs b/src/api/admin.rs @@ -1,7 +1,7 @@ use once_cell::sync::Lazy; use serde::de::DeserializeOwned; use serde_json::Value; -use std::{env, time::Duration}; +use std::env; use rocket::{ http::{Cookie, Cookies, SameSite, Status}, @@ -462,13 +462,13 @@ struct GitCommit { fn get_github_api<T: DeserializeOwned>(url: &str) -> Result<T, Error> { let github_api = get_reqwest_client(); - Ok(github_api.get(url).timeout(Duration::from_secs(10)).send()?.error_for_status()?.json::<T>()?) + Ok(github_api.get(url).send()?.error_for_status()?.json::<T>()?) } fn has_http_access() -> bool { let http_access = get_reqwest_client(); - match http_access.head("https://github.com/dani-garcia/vaultwarden").timeout(Duration::from_secs(10)).send() { + match http_access.head("https://github.com/dani-garcia/vaultwarden").send() { Ok(r) => r.status().is_success(), _ => false, } diff --git a/src/main.rs b/src/main.rs @@ -108,6 +108,14 @@ fn launch_info() { } fn init_logging(level: log::LevelFilter) -> Result<(), fern::InitError> { + // Depending on the main log level we either want to disable or enable logging for trust-dns. + // Else if there are timeouts it will clutter the logs since trust-dns uses warn for this. + let trust_dns_level = if level >= log::LevelFilter::Debug { + level + } else { + log::LevelFilter::Off + }; + let mut logger = fern::Dispatch::new() .level(level) // Hide unknown certificate errors if using self-signed @@ -126,6 +134,8 @@ fn init_logging(level: log::LevelFilter) -> Result<(), fern::InitError> { .level_for("hyper::client", log::LevelFilter::Off) // Prevent cookie_store logs .level_for("cookie_store", log::LevelFilter::Off) + // Variable level for trust-dns used by reqwest + .level_for("trust_dns_proto", trust_dns_level) .chain(std::io::stdout()); // Enable smtp debug logging only specifically for smtp when need. diff --git a/src/static/scripts/bootstrap-native.js b/src/static/scripts/bootstrap-native.js @@ -1,5 +1,5 @@ /*! - * Native JavaScript for Bootstrap v4.0.6 (https://thednp.github.io/bootstrap.native/) + * Native JavaScript for Bootstrap v4.0.8 (https://thednp.github.io/bootstrap.native/) * Copyright 2015-2021 © dnp_theme * Licensed under MIT (https://github.com/thednp/bootstrap.native/blob/master/LICENSE) */ @@ -7,7 +7,7 @@ typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.BSN = factory()); -}(this, (function () { 'use strict'; +})(this, (function () { 'use strict'; const transitionEndEvent = 'webkitTransition' in document.head.style ? 'webkitTransitionEnd' : 'transitionend'; @@ -188,7 +188,7 @@ element.dispatchEvent(closedAlertEvent); self.dispose(); - element.parentNode.removeChild(element); + element.remove(); } // ALERT PRIVATE METHOD @@ -1022,9 +1022,9 @@ function isEmptyAnchor(elem) { const parentAnchor = elem.closest('A'); // anchor href starts with # - return elem && ((elem.href && elem.href.slice(-1) === '#') + return elem && ((elem.hasAttribute('href') && elem.href.slice(-1) === '#') // OR a child of an anchor with href starts with # - || (parentAnchor && parentAnchor.href && parentAnchor.href.slice(-1) === '#')); + || (parentAnchor && parentAnchor.hasAttribute('href') && parentAnchor.href.slice(-1) === '#')); } function setFocus(element) { @@ -1487,7 +1487,7 @@ function appendOverlay(hasFade, isModal) { toggleOverlayType(isModal); - document.body.appendChild(overlay); + document.body.append(overlay); if (hasFade) addClass(overlay, fadeClass); } @@ -1501,12 +1501,11 @@ } function removeOverlay() { - const bd = document.body; const currentOpen = getCurrentOpen(); if (!currentOpen) { removeClass(overlay, fadeClass); - bd.removeChild(overlay); + overlay.remove(); resetScrollbar(); } } @@ -1928,7 +1927,7 @@ if ((!element.contains(target) && options.backdrop && (!trigger || (trigger && !triggers.includes(trigger)))) - || offCanvasDismiss.contains(target)) { + || (offCanvasDismiss && offCanvasDismiss.contains(target))) { self.relatedTarget = target === offCanvasDismiss ? offCanvasDismiss : null; self.hide(); } @@ -2122,19 +2121,6 @@ .some((mediaType) => element instanceof mediaType); } - function closestRelative(element) { - let retval = null; - let el = element; - while (el !== document.body) { - el = el.parentElement; - if (getComputedStyle(el).position === 'relative') { - retval = el; - break; - } - } - return retval; - } - // both popovers and tooltips (this, event) function styleTip(self, e) { const tipClasses = /\b(top|bottom|start|end)+/; @@ -2148,32 +2134,32 @@ let tipDimensions = { w: tip.offsetWidth, h: tip.offsetHeight }; const windowWidth = (document.documentElement.clientWidth || document.body.clientWidth); const windowHeight = (document.documentElement.clientHeight || document.body.clientHeight); - const { element, options, arrow } = self; + const { + element, options, arrow, positions, + } = self; let { container, placement } = options; let parentIsBody = container === document.body; - const targetPosition = getComputedStyle(element).position; - const parentPosition = getComputedStyle(container).position; - const staticParent = !parentIsBody && parentPosition === 'static'; - let relativeParent = !parentIsBody && parentPosition === 'relative'; - const relContainer = staticParent && closestRelative(container); + + const { elementPosition, containerIsStatic, relContainer } = positions; + let { containerIsRelative } = positions; // static containers should refer to another relative container or the body container = relContainer || container; - relativeParent = staticParent && relContainer ? 1 : relativeParent; + containerIsRelative = containerIsStatic && relContainer ? 1 : containerIsRelative; parentIsBody = container === document.body; const parentRect = container.getBoundingClientRect(); - const leftBoundry = relativeParent ? parentRect.left : 0; - const rightBoundry = relativeParent ? parentRect.right : windowWidth; + const leftBoundry = containerIsRelative ? parentRect.left : 0; + const rightBoundry = containerIsRelative ? parentRect.right : windowWidth; // this case should not be possible - // absoluteParent = !parentIsBody && parentPosition === 'absolute', - // this case requires a container with placement: relative - const absoluteTarget = targetPosition === 'absolute'; + // containerIsAbsolute = !parentIsBody && containerPosition === 'absolute', + // this case requires a container with position: relative + const absoluteTarget = elementPosition === 'absolute'; const targetRect = element.getBoundingClientRect(); const scroll = parentIsBody ? { x: window.pageXOffset, y: window.pageYOffset } : { x: container.scrollLeft, y: container.scrollTop }; const elemDimensions = { w: element.offsetWidth, h: element.offsetHeight }; - const top = relativeParent ? element.offsetTop : targetRect.top; - const left = relativeParent ? element.offsetLeft : targetRect.left; + const top = containerIsRelative ? element.offsetTop : targetRect.top; + const left = containerIsRelative ? element.offsetLeft : targetRect.left; // reset arrow style arrow.style.top = ''; arrow.style.left = ''; @@ -2245,8 +2231,12 @@ } } else if (['top', 'bottom'].includes(placement)) { if (e && isMedia(element)) { - const eX = !relativeParent ? e.pageX : e.layerX + (absoluteTarget ? element.offsetLeft : 0); - const eY = !relativeParent ? e.pageY : e.layerY + (absoluteTarget ? element.offsetTop : 0); + const eX = !containerIsRelative + ? e.pageX + : e.layerX + (absoluteTarget ? element.offsetLeft : 0); + const eY = !containerIsRelative + ? e.pageY + : e.layerY + (absoluteTarget ? element.offsetTop : 0); if (placement === 'top') { topPosition = eY - tipDimensions.h - (isPopover ? arrowWidth : arrowHeight); @@ -2323,6 +2313,36 @@ return modal || navbarFixed || document.body; } + function closestRelative(element) { + let retval = null; + let el = element; + while (el !== document.body) { + el = el.parentElement; + if (getComputedStyle(el).position === 'relative') { + retval = el; + break; + } + } + return retval; + } + + function setHtml(element, content, sanitizeFn) { + if (typeof content === 'string' && !content.length) return; + + if (typeof content === 'object') { + element.append(content); + } else { + let dirty = content.trim(); // fixing #233 + + if (typeof sanitizeFn === 'function') dirty = sanitizeFn(dirty); + + const domParser = new DOMParser(); + const tempDocument = domParser.parseFromString(dirty, 'text/html'); + const method = tempDocument.children.length ? 'innerHTML' : 'innerText'; + element[method] = tempDocument.body[method]; + } + } + /* Native JavaScript for Bootstrap 5 | Popover ---------------------------------------------- */ @@ -2335,12 +2355,13 @@ template: '<div class="popover" role="tooltip"><div class="popover-arrow"></div><h3 class="popover-header"></h3><div class="popover-body"></div></div>', // string title: null, // string content: null, // string - sanitizeFn: null, // function customClass: null, // string - dismissible: false, // boolean - animation: true, // boolean trigger: 'hover', // string placement: 'top', // string + btnClose: '<button class="btn-close" aria-label="Close"></button>', // string + sanitizeFn: null, // function + dismissible: false, // boolean + animation: true, // boolean delay: 200, // number }; @@ -2350,11 +2371,8 @@ const isIphone = navigator.userAgentData ? navigator.userAgentData.brands.some((x) => appleBrands.test(x.brand)) : appleBrands.test(navigator.userAgent); - // popoverArrowClass = `${popoverString}-arrow`, const popoverHeaderClass = `${popoverString}-header`; const popoverBodyClass = `${popoverString}-body`; - // close btn for dissmissible popover - let popoverCloseButton = '<button type="button" class="btn-close"></button>'; // POPOVER CUSTOM EVENTS // ===================== @@ -2387,51 +2405,59 @@ const { animation, customClass, sanitizeFn, placement, dismissible, } = options; - let { title, content, template } = options; + let { + title, content, + } = options; + const { + template, btnClose, + } = options; // set initial popover class const placementClass = `bs-${popoverString}-${tipClassPositions[placement]}`; - // fixing #233 - title = title ? title.trim() : null; - content = content ? content.trim() : null; - - // sanitize title && content - if (sanitizeFn) { - title = title ? sanitizeFn(title) : null; - content = content ? sanitizeFn(content) : null; - template = template ? sanitizeFn(template) : null; - popoverCloseButton = sanitizeFn(popoverCloseButton); + // load template + let popoverTemplate; + if (typeof template === 'object') { + popoverTemplate = template; + } else { + const htmlMarkup = document.createElement('div'); + setHtml(htmlMarkup, template, sanitizeFn); + popoverTemplate = htmlMarkup.firstChild; } + // set popover markup + self.popover = popoverTemplate.cloneNode(true); - self.popover = document.createElement('div'); const { popover } = self; - // set id and aria-describedby + // set id and role attributes popover.setAttribute('id', id); popover.setAttribute('role', 'tooltip'); - // load template - const popoverTemplate = document.createElement('div'); - popoverTemplate.innerHTML = template.trim(); - popover.className = popoverTemplate.firstChild.className; - popover.innerHTML = popoverTemplate.firstChild.innerHTML; - const popoverHeader = queryElement(`.${popoverHeaderClass}`, popover); const popoverBody = queryElement(`.${popoverBodyClass}`, popover); - // set arrow + // set arrow and enable access for styleTip self.arrow = queryElement(`.${popoverString}-arrow`, popover); // set dismissible button if (dismissible) { - title = title ? title + popoverCloseButton : title; - content = title === null ? +popoverCloseButton : content; + if (title) { + if (title instanceof Element) setHtml(title, btnClose, sanitizeFn); + else title += btnClose; + } else { + if (popoverHeader) popoverHeader.remove(); + if (content instanceof Element) setHtml(content, btnClose, sanitizeFn); + else content += btnClose; + } } - // fill the template with content from data attributes - if (title && popoverHeader) popoverHeader.innerHTML = title.trim(); - if (content && popoverBody) popoverBody.innerHTML = content.trim(); + // fill the template with content from options / data attributes + // also sanitize title && content + if (title && popoverHeader) setHtml(popoverHeader, title, sanitizeFn); + if (content && popoverBody) setHtml(popoverBody, content, sanitizeFn); + + // set btn and enable access for styleTip + [self.btn] = popover.getElementsByClassName('btn-close'); // set popover animation and placement if (!hasClass(popover, popoverString)) addClass(popover, popoverString); @@ -2443,9 +2469,9 @@ } function removePopover(self) { - const { element, popover, options } = self; + const { element, popover } = self; element.removeAttribute(ariaDescribedBy); - options.container.removeChild(popover); + popover.remove(); self.timer = null; } @@ -2470,12 +2496,11 @@ function dismissHandlerToggle(self, add) { const action = add ? addEventListener : removeEventListener; - const { options, element, popover } = self; + const { options, element, btn } = self; const { trigger, dismissible } = options; if (dismissible) { - const [btnClose] = popover.getElementsByClassName('btn-close'); - if (btnClose) btnClose[action]('click', self.hide); + if (btn) btn[action]('click', self.hide); } else { if (trigger === 'focus') element[action]('focusout', self.hide); if (trigger === 'hover') document[action]('touchstart', popoverTouchHandler, passiveHandler); @@ -2488,12 +2513,10 @@ } function popoverShowTrigger(self) { - dismissHandlerToggle(self, 1); self.element.dispatchEvent(shownPopoverEvent); } function popoverHideTrigger(self) { - dismissHandlerToggle(self); removePopover(self); self.element.dispatchEvent(hiddenPopoverEvent); } @@ -2514,6 +2537,7 @@ self.timer = null; self.popover = null; self.arrow = null; + self.btn = null; self.enabled = false; // set unique ID for aria-describedby self.id = `${popoverString}-${getUID(element)}`; @@ -2535,6 +2559,21 @@ // crate popover createPopover(self); + // set positions + const { container } = self.options; + const elementPosition = getComputedStyle(element).position; + const containerPosition = getComputedStyle(container).position; + const parentIsBody = container === document.body; + const containerIsStatic = !parentIsBody && containerPosition === 'static'; + const containerIsRelative = !parentIsBody && containerPosition === 'relative'; + const relContainer = containerIsStatic && closestRelative(container); + self.positions = { + elementPosition, + containerIsRelative, + containerIsStatic, + relContainer, + }; + // bind self.update = self.update.bind(self); @@ -2563,23 +2602,21 @@ const { container } = options; clearTimeout(self.timer); + if (!isVisibleTip(popover, container)) { + element.dispatchEvent(showPopoverEvent); + if (showPopoverEvent.defaultPrevented) return; - self.timer = setTimeout(() => { - if (!isVisibleTip(popover, container)) { - element.dispatchEvent(showPopoverEvent); - if (showPopoverEvent.defaultPrevented) return; - - // append to the container - container.appendChild(popover); - element.setAttribute(ariaDescribedBy, id); + // append to the container + container.append(popover); + element.setAttribute(ariaDescribedBy, id); - self.update(e); - if (!hasClass(popover, showClass)) addClass(popover, showClass); + self.update(e); + if (!hasClass(popover, showClass)) addClass(popover, showClass); + dismissHandlerToggle(self, 1); - if (options.animation) emulateTransitionEnd(popover, () => popoverShowTrigger(self)); - else popoverShowTrigger(self); - } - }, 17); + if (options.animation) emulateTransitionEnd(popover, () => popoverShowTrigger(self)); + else popoverShowTrigger(self); + } } hide(e) { @@ -2596,13 +2633,13 @@ const { element, popover, options } = self; clearTimeout(self.timer); - self.timer = setTimeout(() => { if (isVisibleTip(popover, options.container)) { element.dispatchEvent(hidePopoverEvent); if (hidePopoverEvent.defaultPrevented) return; removeClass(popover, showClass); + dismissHandlerToggle(self); if (options.animation) emulateTransitionEnd(popover, () => popoverHideTrigger(self)); else popoverHideTrigger(self); @@ -2648,7 +2685,7 @@ const { popover, options } = self; const { container, animation } = options; if (animation && isVisibleTip(popover, container)) { - options.delay = 0; // reset delay + self.options.delay = 0; // reset delay self.hide(); emulateTransitionEnd(popover, () => togglePopoverHandlers(self)); } else { @@ -3067,7 +3104,7 @@ const toastSelector = `.${toastString}`; const toastDismissSelector = `[${dataBsDismiss}="${toastString}"]`; const showingClass = 'showing'; - const hideClass = 'hide'; + const hideClass = 'hide'; // marked as deprecated const toastDefaultOptions = { animation: true, autohide: true, @@ -3085,10 +3122,7 @@ // ===================== function showToastComplete(self) { const { element, options } = self; - if (!options.animation) { - removeClass(element, showingClass); - addClass(element, showClass); - } + removeClass(element, showingClass); element.dispatchEvent(shownToastEvent); if (options.autohide) self.hide(); @@ -3096,13 +3130,15 @@ function hideToastComplete(self) { const { element } = self; - addClass(element, hideClass); + removeClass(element, showingClass); + removeClass(element, showClass); + addClass(element, hideClass); // B/C element.dispatchEvent(hiddenToastEvent); } - function closeToast(self) { + function hideToast(self) { const { element, options } = self; - removeClass(element, showClass); + addClass(element, showingClass); if (options.animation) { reflow(element); @@ -3112,15 +3148,14 @@ } } - function openToast(self) { + function showToast(self) { const { element, options } = self; - removeClass(element, hideClass); + removeClass(element, hideClass); // B/C + reflow(element); + addClass(element, showClass); + addClass(element, showingClass); if (options.animation) { - reflow(element); - addClass(element, showingClass); - addClass(element, showClass); - emulateTransitionEnd(element, () => showToastComplete(self)); } else { showToastComplete(self); @@ -3148,9 +3183,13 @@ super(toastComponent, target, toastDefaultOptions, config); // bind const self = this; + const { element, options } = self; + // set fadeClass, the options.animation will override the markup + if (options.animation && !hasClass(element, fadeClass)) addClass(element, fadeClass); + else if (!options.animation && hasClass(element, fadeClass)) removeClass(element, fadeClass); // dismiss button - self.dismiss = queryElement(toastDismissSelector, self.element); + self.dismiss = queryElement(toastDismissSelector, element); // bind self.show = self.show.bind(self); @@ -3165,13 +3204,12 @@ show() { const self = this; const { element } = self; - if (element && hasClass(element, hideClass)) { + if (element && !hasClass(element, showClass)) { element.dispatchEvent(showToastEvent); if (showToastEvent.defaultPrevented) return; - addClass(element, fadeClass); clearTimeout(self.timer); - self.timer = setTimeout(() => openToast(self), 10); + self.timer = setTimeout(() => showToast(self), 10); } } @@ -3184,7 +3222,7 @@ if (hideToastEvent.defaultPrevented) return; clearTimeout(self.timer); - self.timer = setTimeout(() => closeToast(self), + self.timer = setTimeout(() => hideToast(self), noTimer ? 10 : options.delay); } } @@ -3192,7 +3230,7 @@ dispose() { const self = this; const { element, options } = self; - self.hide(); + self.hide(1); if (options.animation) emulateTransitionEnd(element, () => completeDisposeToast(self)); else completeDisposeToast(self); @@ -3221,13 +3259,14 @@ const titleAttr = 'title'; const tooltipInnerClass = `${tooltipString}-inner`; const tooltipDefaultOptions = { - title: null, template: '<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>', - placement: 'top', - animation: true, - customClass: null, - delay: 200, - sanitizeFn: null, + title: null, // string + customClass: null, // string | null + placement: 'top', // string + sanitizeFn: null, // function + animation: true, // bool + html: false, // bool + delay: 200, // number }; // TOOLTIP CUSTOM EVENTS @@ -3241,51 +3280,48 @@ // ======================= function createTooltip(self) { const { options, id } = self; - const placementClass = `bs-${tooltipString}-${tipClassPositions[options.placement]}`; - let titleString = options.title.trim(); + const { + title, template, customClass, animation, placement, sanitizeFn, + } = options; + const placementClass = `bs-${tooltipString}-${tipClassPositions[placement]}`; - // sanitize stuff - if (options.sanitizeFn) { - titleString = options.sanitizeFn(titleString); - options.template = options.sanitizeFn(options.template); - } + if (!title) return; - if (!titleString) return; + // load template + let tooltipTemplate; + if (typeof template === 'object') { + tooltipTemplate = template; + } else { + const htmlMarkup = document.createElement('div'); + setHtml(htmlMarkup, template, sanitizeFn); + tooltipTemplate = htmlMarkup.firstChild; + } // create tooltip - self.tooltip = document.createElement('div'); + self.tooltip = tooltipTemplate.cloneNode(true); const { tooltip } = self; - - // set aria + // set title + setHtml(queryElement(`.${tooltipInnerClass}`, tooltip), title, sanitizeFn); + // set id & role attribute tooltip.setAttribute('id', id); - - // set markup - const tooltipMarkup = document.createElement('div'); - tooltipMarkup.innerHTML = options.template.trim(); - - tooltip.className = tooltipMarkup.firstChild.className; - tooltip.innerHTML = tooltipMarkup.firstChild.innerHTML; - - queryElement(`.${tooltipInnerClass}`, tooltip).innerHTML = titleString; + tooltip.setAttribute('role', tooltipString); // set arrow self.arrow = queryElement(`.${tooltipString}-arrow`, tooltip); - // set class and role attribute - tooltip.setAttribute('role', tooltipString); // set classes if (!hasClass(tooltip, tooltipString)) addClass(tooltip, tooltipString); - if (options.animation && !hasClass(tooltip, fadeClass)) addClass(tooltip, fadeClass); - if (options.customClass && !hasClass(tooltip, options.customClass)) { - addClass(tooltip, options.customClass); + if (animation && !hasClass(tooltip, fadeClass)) addClass(tooltip, fadeClass); + if (customClass && !hasClass(tooltip, customClass)) { + addClass(tooltip, customClass); } if (!hasClass(tooltip, placementClass)) addClass(tooltip, placementClass); } function removeTooltip(self) { - const { element, options, tooltip } = self; + const { element, tooltip } = self; element.removeAttribute(ariaDescribedBy); - options.container.removeChild(tooltip); + tooltip.remove(); self.timer = null; } @@ -3387,6 +3423,21 @@ self.id = `${tooltipString}-${getUID(element)}`; createTooltip(self); + // set positions + const { container } = self.options; + const elementPosition = getComputedStyle(element).position; + const containerPosition = getComputedStyle(container).position; + const parentIsBody = container === document.body; + const containerIsStatic = !parentIsBody && containerPosition === 'static'; + const containerIsRelative = !parentIsBody && containerPosition === 'relative'; + const relContainer = containerIsStatic && closestRelative(container); + self.positions = { + elementPosition, + containerIsRelative, + containerIsStatic, + relContainer, + }; + // attach events toggleTooltipHandlers(self, 1); } @@ -3398,22 +3449,23 @@ const { options, tooltip, element, id, } = self; + const { + container, animation, + } = options; clearTimeout(self.timer); - self.timer = setTimeout(() => { - if (!isVisibleTip(tooltip, options.container)) { - element.dispatchEvent(showTooltipEvent); - if (showTooltipEvent.defaultPrevented) return; - - // append to container - options.container.appendChild(tooltip); - element.setAttribute(ariaDescribedBy, id); - - self.update(e); - if (!hasClass(tooltip, showClass)) addClass(tooltip, showClass); - if (options.animation) emulateTransitionEnd(tooltip, () => tooltipShownAction(self)); - else tooltipShownAction(self); - } - }, 20); + if (!isVisibleTip(tooltip, container)) { + element.dispatchEvent(showTooltipEvent); + if (showTooltipEvent.defaultPrevented) return; + + // append to container + container.append(tooltip); + element.setAttribute(ariaDescribedBy, id); + + self.update(e); + if (!hasClass(tooltip, showClass)) addClass(tooltip, showClass); + if (animation) emulateTransitionEnd(tooltip, () => tooltipShownAction(self)); + else tooltipShownAction(self); + } } hide(e) { @@ -3498,20 +3550,9 @@ constructor: Tooltip, }; - var version = "4.0.6"; - - // import { alertInit } from '../components/alert-native.js'; - // import { buttonInit } from '../components/button-native.js'; - // import { carouselInit } from '../components/carousel-native.js'; - // import { collapseInit } from '../components/collapse-native.js'; - // import { dropdownInit } from '../components/dropdown-native.js'; - // import { modalInit } from '../components/modal-native.js'; - // import { offcanvasInit } from '../components/offcanvas-native.js'; - // import { popoverInit } from '../components/popover-native.js'; - // import { scrollSpyInit } from '../components/scrollspy-native.js'; - // import { tabInit } from '../components/tab-native.js'; - // import { toastInit } from '../components/toast-native.js'; - // import { tooltipInit } from '../components/tooltip-native.js'; + var version = "4.0.8"; + + const Version = version; const componentsInit = { Alert: Alert.init, @@ -3547,7 +3588,7 @@ document.addEventListener('DOMContentLoaded', () => initCallback(), { once: true }); } - var index = { + const BSN = { Alert, Button, Carousel, @@ -3562,9 +3603,9 @@ Tooltip, initCallback, - Version: version, + Version, }; - return index; + return BSN; -}))); +})); +\ No newline at end of file diff --git a/src/static/scripts/bootstrap.css b/src/static/scripts/bootstrap.css @@ -1,6 +1,6 @@ @charset "UTF-8"; /*! - * Bootstrap v5.0.2 (https://getbootstrap.com/) + * Bootstrap v5.1.3 (https://getbootstrap.com/) * Copyright 2011-2021 The Bootstrap Authors * Copyright 2011-2021 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) @@ -19,6 +19,15 @@ --bs-white: #fff; --bs-gray: #6c757d; --bs-gray-dark: #343a40; + --bs-gray-100: #f8f9fa; + --bs-gray-200: #e9ecef; + --bs-gray-300: #dee2e6; + --bs-gray-400: #ced4da; + --bs-gray-500: #adb5bd; + --bs-gray-600: #6c757d; + --bs-gray-700: #495057; + --bs-gray-800: #343a40; + --bs-gray-900: #212529; --bs-primary: #0d6efd; --bs-secondary: #6c757d; --bs-success: #198754; @@ -27,9 +36,27 @@ --bs-danger: #dc3545; --bs-light: #f8f9fa; --bs-dark: #212529; + --bs-primary-rgb: 13, 110, 253; + --bs-secondary-rgb: 108, 117, 125; + --bs-success-rgb: 25, 135, 84; + --bs-info-rgb: 13, 202, 240; + --bs-warning-rgb: 255, 193, 7; + --bs-danger-rgb: 220, 53, 69; + --bs-light-rgb: 248, 249, 250; + --bs-dark-rgb: 33, 37, 41; + --bs-white-rgb: 255, 255, 255; + --bs-black-rgb: 0, 0, 0; + --bs-body-color-rgb: 33, 37, 41; + --bs-body-bg-rgb: 255, 255, 255; --bs-font-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; --bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; --bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0)); + --bs-body-font-family: var(--bs-font-sans-serif); + --bs-body-font-size: 1rem; + --bs-body-font-weight: 400; + --bs-body-line-height: 1.5; + --bs-body-color: #212529; + --bs-body-bg: #fff; } *, @@ -46,12 +73,13 @@ body { margin: 0; - font-family: var(--bs-font-sans-serif); - font-size: 1rem; - font-weight: 400; - line-height: 1.5; - color: #212529; - background-color: #fff; + font-family: var(--bs-body-font-family); + font-size: var(--bs-body-font-size); + font-weight: var(--bs-body-font-weight); + line-height: var(--bs-body-line-height); + color: var(--bs-body-color); + text-align: var(--bs-body-text-align); + background-color: var(--bs-body-bg); -webkit-text-size-adjust: 100%; -webkit-tap-highlight-color: rgba(0, 0, 0, 0); } @@ -420,6 +448,10 @@ legend + * { padding: 0; } +::-webkit-file-upload-button { + font: inherit; +} + ::file-selector-button { font: inherit; } @@ -633,16 +665,16 @@ progress { --bs-gutter-y: 0; display: flex; flex-wrap: wrap; - margin-top: calc(var(--bs-gutter-y) * -1); - margin-right: calc(var(--bs-gutter-x) * -.5); - margin-left: calc(var(--bs-gutter-x) * -.5); + margin-top: calc(-1 * var(--bs-gutter-y)); + margin-right: calc(-0.5 * var(--bs-gutter-x)); + margin-left: calc(-0.5 * var(--bs-gutter-x)); } .row > * { flex-shrink: 0; width: 100%; max-width: 100%; - padding-right: calc(var(--bs-gutter-x) * .5); - padding-left: calc(var(--bs-gutter-x) * .5); + padding-right: calc(var(--bs-gutter-x) * 0.5); + padding-left: calc(var(--bs-gutter-x) * 0.5); margin-top: var(--bs-gutter-y); } @@ -685,206 +717,6 @@ progress { width: 16.6666666667%; } -@media (min-width: 576px) { - .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%; - } -} -@media (min-width: 768px) { - .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%; - } -} -@media (min-width: 992px) { - .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%; - } -} -@media (min-width: 1200px) { - .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%; - } -} -@media (min-width: 1400px) { - .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-auto { flex: 0 0 auto; width: auto; @@ -1055,6 +887,45 @@ progress { } @media (min-width: 576px) { + .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; @@ -1229,6 +1100,45 @@ progress { } } @media (min-width: 768px) { + .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; @@ -1403,6 +1313,45 @@ progress { } } @media (min-width: 992px) { + .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; @@ -1571,12 +1520,51 @@ progress { --bs-gutter-x: 3rem; } - .g-lg-5, -.gy-lg-5 { - --bs-gutter-y: 3rem; + .g-lg-5, +.gy-lg-5 { + --bs-gutter-y: 3rem; + } +} +@media (min-width: 1200px) { + .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%; } -} -@media (min-width: 1200px) { + .col-xl-auto { flex: 0 0 auto; width: auto; @@ -1751,6 +1739,45 @@ progress { } } @media (min-width: 1400px) { + .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; @@ -1951,8 +1978,8 @@ progress { .table > thead { vertical-align: bottom; } -.table > :not(:last-child) > :last-child > * { - border-bottom-color: currentColor; +.table > :not(:first-child) { + border-top: 2px solid currentColor; } .caption-top { @@ -1973,8 +2000,11 @@ progress { .table-borderless > :not(caption) > * > * { border-bottom-width: 0; } +.table-borderless > :not(:first-child) { + border-top-width: 0; +} -.table-striped > tbody > tr:nth-of-type(odd) { +.table-striped > tbody > tr:nth-of-type(odd) > * { --bs-table-accent-bg: var(--bs-table-striped-bg); color: var(--bs-table-striped-color); } @@ -1984,7 +2014,7 @@ progress { color: var(--bs-table-active-color); } -.table-hover > tbody > tr:hover { +.table-hover > tbody > tr:hover > * { --bs-table-accent-bg: var(--bs-table-hover-bg); color: var(--bs-table-hover-color); } @@ -2200,6 +2230,22 @@ progress { background-color: #e9ecef; opacity: 1; } +.form-control::-webkit-file-upload-button { + padding: 0.375rem 0.75rem; + margin: -0.375rem -0.75rem; + -webkit-margin-end: 0.75rem; + margin-inline-end: 0.75rem; + color: #212529; + background-color: #e9ecef; + pointer-events: none; + border-color: inherit; + border-style: solid; + border-width: 0; + border-inline-end-width: 1px; + border-radius: 0; + -webkit-transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; + transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} .form-control::file-selector-button { padding: 0.375rem 0.75rem; margin: -0.375rem -0.75rem; @@ -2216,10 +2262,17 @@ progress { transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; } @media (prefers-reduced-motion: reduce) { + .form-control::-webkit-file-upload-button { + -webkit-transition: none; + transition: none; + } .form-control::file-selector-button { transition: none; } } +.form-control:hover:not(:disabled):not([readonly])::-webkit-file-upload-button { + background-color: #dde0e3; +} .form-control:hover:not(:disabled):not([readonly])::file-selector-button { background-color: #dde0e3; } @@ -2266,11 +2319,17 @@ progress { } .form-control-sm { - min-height: calc(1.5em + (0.5rem + 2px)); + min-height: calc(1.5em + 0.5rem + 2px); padding: 0.25rem 0.5rem; font-size: 0.875rem; border-radius: 0.2rem; } +.form-control-sm::-webkit-file-upload-button { + padding: 0.25rem 0.5rem; + margin: -0.25rem -0.5rem; + -webkit-margin-end: 0.5rem; + margin-inline-end: 0.5rem; +} .form-control-sm::file-selector-button { padding: 0.25rem 0.5rem; margin: -0.25rem -0.5rem; @@ -2285,11 +2344,17 @@ progress { } .form-control-lg { - min-height: calc(1.5em + (1rem + 2px)); + min-height: calc(1.5em + 1rem + 2px); padding: 0.5rem 1rem; font-size: 1.25rem; border-radius: 0.3rem; } +.form-control-lg::-webkit-file-upload-button { + padding: 0.5rem 1rem; + margin: -0.5rem -1rem; + -webkit-margin-end: 1rem; + margin-inline-end: 1rem; +} .form-control-lg::file-selector-button { padding: 0.5rem 1rem; margin: -0.5rem -1rem; @@ -2304,17 +2369,17 @@ progress { } textarea.form-control { - min-height: calc(1.5em + (0.75rem + 2px)); + min-height: calc(1.5em + 0.75rem + 2px); } textarea.form-control-sm { - min-height: calc(1.5em + (0.5rem + 2px)); + min-height: calc(1.5em + 0.5rem + 2px); } textarea.form-control-lg { - min-height: calc(1.5em + (1rem + 2px)); + min-height: calc(1.5em + 1rem + 2px); } .form-control-color { - max-width: 3rem; + width: 3rem; height: auto; padding: 0.375rem; } @@ -2378,6 +2443,7 @@ textarea.form-control-lg { padding-bottom: 0.25rem; padding-left: 0.5rem; font-size: 0.875rem; + border-radius: 0.2rem; } .form-select-lg { @@ -2385,6 +2451,7 @@ textarea.form-control-lg { padding-bottom: 0.5rem; padding-left: 1rem; font-size: 1.25rem; + border-radius: 0.3rem; } .form-check { @@ -3430,6 +3497,16 @@ textarea.form-control-lg { transition: none; } } +.collapsing.collapse-horizontal { + width: 0; + height: auto; + transition: width 0.35s ease; +} +@media (prefers-reduced-motion: reduce) { + .collapsing.collapse-horizontal { + transition: none; + } +} .dropup, .dropend, @@ -4047,6 +4124,33 @@ textarea.form-control-lg { .navbar-expand-sm .navbar-toggler { display: none; } + .navbar-expand-sm .offcanvas-header { + display: none; + } + .navbar-expand-sm .offcanvas { + position: inherit; + bottom: 0; + z-index: 1000; + flex-grow: 1; + visibility: visible !important; + background-color: transparent; + border-right: 0; + border-left: 0; + transition: none; + transform: none; + } + .navbar-expand-sm .offcanvas-top, +.navbar-expand-sm .offcanvas-bottom { + height: auto; + border-top: 0; + border-bottom: 0; + } + .navbar-expand-sm .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + overflow-y: visible; + } } @media (min-width: 768px) { .navbar-expand-md { @@ -4073,6 +4177,33 @@ textarea.form-control-lg { .navbar-expand-md .navbar-toggler { display: none; } + .navbar-expand-md .offcanvas-header { + display: none; + } + .navbar-expand-md .offcanvas { + position: inherit; + bottom: 0; + z-index: 1000; + flex-grow: 1; + visibility: visible !important; + background-color: transparent; + border-right: 0; + border-left: 0; + transition: none; + transform: none; + } + .navbar-expand-md .offcanvas-top, +.navbar-expand-md .offcanvas-bottom { + height: auto; + border-top: 0; + border-bottom: 0; + } + .navbar-expand-md .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + overflow-y: visible; + } } @media (min-width: 992px) { .navbar-expand-lg { @@ -4099,6 +4230,33 @@ textarea.form-control-lg { .navbar-expand-lg .navbar-toggler { display: none; } + .navbar-expand-lg .offcanvas-header { + display: none; + } + .navbar-expand-lg .offcanvas { + position: inherit; + bottom: 0; + z-index: 1000; + flex-grow: 1; + visibility: visible !important; + background-color: transparent; + border-right: 0; + border-left: 0; + transition: none; + transform: none; + } + .navbar-expand-lg .offcanvas-top, +.navbar-expand-lg .offcanvas-bottom { + height: auto; + border-top: 0; + border-bottom: 0; + } + .navbar-expand-lg .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + overflow-y: visible; + } } @media (min-width: 1200px) { .navbar-expand-xl { @@ -4125,6 +4283,33 @@ textarea.form-control-lg { .navbar-expand-xl .navbar-toggler { display: none; } + .navbar-expand-xl .offcanvas-header { + display: none; + } + .navbar-expand-xl .offcanvas { + position: inherit; + bottom: 0; + z-index: 1000; + flex-grow: 1; + visibility: visible !important; + background-color: transparent; + border-right: 0; + border-left: 0; + transition: none; + transform: none; + } + .navbar-expand-xl .offcanvas-top, +.navbar-expand-xl .offcanvas-bottom { + height: auto; + border-top: 0; + border-bottom: 0; + } + .navbar-expand-xl .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + overflow-y: visible; + } } @media (min-width: 1400px) { .navbar-expand-xxl { @@ -4151,6 +4336,33 @@ textarea.form-control-lg { .navbar-expand-xxl .navbar-toggler { display: none; } + .navbar-expand-xxl .offcanvas-header { + display: none; + } + .navbar-expand-xxl .offcanvas { + position: inherit; + bottom: 0; + z-index: 1000; + flex-grow: 1; + visibility: visible !important; + background-color: transparent; + border-right: 0; + border-left: 0; + transition: none; + transform: none; + } + .navbar-expand-xxl .offcanvas-top, +.navbar-expand-xxl .offcanvas-bottom { + height: auto; + border-top: 0; + border-bottom: 0; + } + .navbar-expand-xxl .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + overflow-y: visible; + } } .navbar-expand { flex-wrap: nowrap; @@ -4176,6 +4388,33 @@ textarea.form-control-lg { .navbar-expand .navbar-toggler { display: none; } +.navbar-expand .offcanvas-header { + display: none; +} +.navbar-expand .offcanvas { + position: inherit; + bottom: 0; + z-index: 1000; + flex-grow: 1; + visibility: visible !important; + background-color: transparent; + border-right: 0; + border-left: 0; + transition: none; + transform: none; +} +.navbar-expand .offcanvas-top, +.navbar-expand .offcanvas-bottom { + height: auto; + border-top: 0; + border-bottom: 0; +} +.navbar-expand .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + overflow-y: visible; +} .navbar-light .navbar-brand { color: rgba(0, 0, 0, 0.9); @@ -4299,9 +4538,6 @@ textarea.form-control-lg { margin-bottom: 0; } -.card-link:hover { - text-decoration: none; -} .card-link + .card-link { margin-left: 1rem; } @@ -5177,10 +5413,10 @@ textarea.form-control-lg { box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15); border-radius: 0.25rem; } -.toast:not(.showing):not(.show) { +.toast.showing { opacity: 0; } -.toast.hide { +.toast:not(.show) { display: none; } @@ -5220,7 +5456,7 @@ textarea.form-control-lg { position: fixed; top: 0; left: 0; - z-index: 1060; + z-index: 1055; display: none; width: 100%; height: 100%; @@ -5285,7 +5521,7 @@ textarea.form-control-lg { position: fixed; top: 0; left: 0; - z-index: 1040; + z-index: 1050; width: 100vw; height: 100vh; background-color: #000; @@ -6010,7 +6246,7 @@ textarea.form-control-lg { .offcanvas { position: fixed; bottom: 0; - z-index: 1050; + z-index: 1045; display: flex; flex-direction: column; max-width: 100%; @@ -6026,6 +6262,22 @@ textarea.form-control-lg { } } +.offcanvas-backdrop { + position: fixed; + top: 0; + left: 0; + z-index: 1040; + width: 100vw; + height: 100vh; + background-color: #000; +} +.offcanvas-backdrop.fade { + opacity: 0; +} +.offcanvas-backdrop.show { + opacity: 0.5; +} + .offcanvas-header { display: flex; align-items: center; @@ -6089,6 +6341,69 @@ textarea.form-control-lg { transform: none; } +.placeholder { + display: inline-block; + min-height: 1em; + vertical-align: middle; + cursor: wait; + background-color: currentColor; + opacity: 0.5; +} +.placeholder.btn::before { + display: inline-block; + content: ""; +} + +.placeholder-xs { + min-height: 0.6em; +} + +.placeholder-sm { + min-height: 0.8em; +} + +.placeholder-lg { + min-height: 1.2em; +} + +.placeholder-glow .placeholder { + -webkit-animation: placeholder-glow 2s ease-in-out infinite; + animation: placeholder-glow 2s ease-in-out infinite; +} + +@-webkit-keyframes placeholder-glow { + 50% { + opacity: 0.2; + } +} + +@keyframes placeholder-glow { + 50% { + opacity: 0.2; + } +} +.placeholder-wave { + -webkit-mask-image: linear-gradient(130deg, #000 55%, rgba(0, 0, 0, 0.8) 75%, #000 95%); + mask-image: linear-gradient(130deg, #000 55%, rgba(0, 0, 0, 0.8) 75%, #000 95%); + -webkit-mask-size: 200% 100%; + mask-size: 200% 100%; + -webkit-animation: placeholder-wave 2s linear infinite; + animation: placeholder-wave 2s linear infinite; +} + +@-webkit-keyframes placeholder-wave { + 100% { + -webkit-mask-position: -200% 0%; + mask-position: -200% 0%; + } +} + +@keyframes placeholder-wave { + 100% { + -webkit-mask-position: -200% 0%; + mask-position: -200% 0%; + } +} .clearfix::after { display: block; clear: both; @@ -6173,15 +6488,15 @@ textarea.form-control-lg { } .ratio-4x3 { - --bs-aspect-ratio: calc(3 / 4 * 100%); + --bs-aspect-ratio: 75%; } .ratio-16x9 { - --bs-aspect-ratio: calc(9 / 16 * 100%); + --bs-aspect-ratio: 56.25%; } .ratio-21x9 { - --bs-aspect-ratio: calc(9 / 21 * 100%); + --bs-aspect-ratio: 42.8571428571%; } .fixed-top { @@ -6247,6 +6562,20 @@ textarea.form-control-lg { z-index: 1020; } } +.hstack { + display: flex; + flex-direction: row; + align-items: center; + align-self: stretch; +} + +.vstack { + display: flex; + flex: 1 1 auto; + flex-direction: column; + align-self: stretch; +} + .visually-hidden, .visually-hidden-focusable:not(:focus):not(:focus-within) { position: absolute !important; @@ -6276,6 +6605,15 @@ textarea.form-control-lg { white-space: nowrap; } +.vr { + display: inline-block; + align-self: stretch; + width: 1px; + min-height: 1em; + background-color: currentColor; + opacity: 0.25; +} + .align-baseline { vertical-align: baseline !important; } @@ -6312,6 +6650,26 @@ textarea.form-control-lg { float: none !important; } +.opacity-0 { + opacity: 0 !important; +} + +.opacity-25 { + opacity: 0.25 !important; +} + +.opacity-50 { + opacity: 0.5 !important; +} + +.opacity-75 { + opacity: 0.75 !important; +} + +.opacity-100 { + opacity: 1 !important; +} + .overflow-auto { overflow: auto !important; } @@ -7335,105 +7693,176 @@ textarea.form-control-lg { /* rtl:end:remove */ .text-primary { - color: #0d6efd !important; + --bs-text-opacity: 1; + color: rgba(var(--bs-primary-rgb), var(--bs-text-opacity)) !important; } .text-secondary { - color: #6c757d !important; + --bs-text-opacity: 1; + color: rgba(var(--bs-secondary-rgb), var(--bs-text-opacity)) !important; } .text-success { - color: #198754 !important; + --bs-text-opacity: 1; + color: rgba(var(--bs-success-rgb), var(--bs-text-opacity)) !important; } .text-info { - color: #0dcaf0 !important; + --bs-text-opacity: 1; + color: rgba(var(--bs-info-rgb), var(--bs-text-opacity)) !important; } .text-warning { - color: #ffc107 !important; + --bs-text-opacity: 1; + color: rgba(var(--bs-warning-rgb), var(--bs-text-opacity)) !important; } .text-danger { - color: #dc3545 !important; + --bs-text-opacity: 1; + color: rgba(var(--bs-danger-rgb), var(--bs-text-opacity)) !important; } .text-light { - color: #f8f9fa !important; + --bs-text-opacity: 1; + color: rgba(var(--bs-light-rgb), var(--bs-text-opacity)) !important; } .text-dark { - color: #212529 !important; + --bs-text-opacity: 1; + color: rgba(var(--bs-dark-rgb), var(--bs-text-opacity)) !important; +} + +.text-black { + --bs-text-opacity: 1; + color: rgba(var(--bs-black-rgb), var(--bs-text-opacity)) !important; } .text-white { - color: #fff !important; + --bs-text-opacity: 1; + color: rgba(var(--bs-white-rgb), var(--bs-text-opacity)) !important; } .text-body { - color: #212529 !important; + --bs-text-opacity: 1; + color: rgba(var(--bs-body-color-rgb), var(--bs-text-opacity)) !important; } .text-muted { + --bs-text-opacity: 1; color: #6c757d !important; } .text-black-50 { + --bs-text-opacity: 1; color: rgba(0, 0, 0, 0.5) !important; } .text-white-50 { + --bs-text-opacity: 1; color: rgba(255, 255, 255, 0.5) !important; } .text-reset { + --bs-text-opacity: 1; color: inherit !important; } +.text-opacity-25 { + --bs-text-opacity: 0.25; +} + +.text-opacity-50 { + --bs-text-opacity: 0.5; +} + +.text-opacity-75 { + --bs-text-opacity: 0.75; +} + +.text-opacity-100 { + --bs-text-opacity: 1; +} + .bg-primary { - background-color: #0d6efd !important; + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-primary-rgb), var(--bs-bg-opacity)) !important; } .bg-secondary { - background-color: #6c757d !important; + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-secondary-rgb), var(--bs-bg-opacity)) !important; } .bg-success { - background-color: #198754 !important; + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-success-rgb), var(--bs-bg-opacity)) !important; } .bg-info { - background-color: #0dcaf0 !important; + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-info-rgb), var(--bs-bg-opacity)) !important; } .bg-warning { - background-color: #ffc107 !important; + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-warning-rgb), var(--bs-bg-opacity)) !important; } .bg-danger { - background-color: #dc3545 !important; + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-danger-rgb), var(--bs-bg-opacity)) !important; } .bg-light { - background-color: #f8f9fa !important; + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-light-rgb), var(--bs-bg-opacity)) !important; } .bg-dark { - background-color: #212529 !important; + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-dark-rgb), var(--bs-bg-opacity)) !important; } -.bg-body { - background-color: #fff !important; +.bg-black { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-black-rgb), var(--bs-bg-opacity)) !important; } .bg-white { - background-color: #fff !important; + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-white-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-body { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-body-bg-rgb), var(--bs-bg-opacity)) !important; } .bg-transparent { + --bs-bg-opacity: 1; background-color: transparent !important; } +.bg-opacity-10 { + --bs-bg-opacity: 0.1; +} + +.bg-opacity-25 { + --bs-bg-opacity: 0.25; +} + +.bg-opacity-50 { + --bs-bg-opacity: 0.5; +} + +.bg-opacity-75 { + --bs-bg-opacity: 0.75; +} + +.bg-opacity-100 { + --bs-bg-opacity: 1; +} + .bg-gradient { background-image: var(--bs-gradient) !important; } diff --git a/src/static/scripts/datatables.css b/src/static/scripts/datatables.css @@ -4,10 +4,10 @@ * * To rebuild or modify this file with the latest versions of the included * software please visit: - * https://datatables.net/download/#bs5/dt-1.11.2 + * https://datatables.net/download/#bs5/dt-1.11.3 * * Included libraries: - * DataTables 1.11.2 + * DataTables 1.11.3 */ @charset "UTF-8"; diff --git a/src/static/scripts/datatables.js b/src/static/scripts/datatables.js @@ -4,20 +4,20 @@ * * To rebuild or modify this file with the latest versions of the included * software please visit: - * https://datatables.net/download/#bs5/dt-1.11.2 + * https://datatables.net/download/#bs5/dt-1.11.3 * * Included libraries: - * DataTables 1.11.2 + * DataTables 1.11.3 */ -/*! DataTables 1.11.2 +/*! DataTables 1.11.3 * ©2008-2021 SpryMedia Ltd - datatables.net/license */ /** * @summary DataTables * @description Paginate, search and order HTML tables - * @version 1.11.2 + * @version 1.11.3 * @file jquery.dataTables.js * @author SpryMedia Ltd * @contact www.datatables.net @@ -1626,6 +1626,14 @@ return out; } + var _includes = function (search, start) { + if (start === undefined) { + start = 0; + } + + return this.indexOf(search, start) !== -1; + }; + // Array.isArray polyfill. // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray if (! Array.isArray) { @@ -1634,6 +1642,10 @@ }; } + if (! Array.prototype.includes) { + Array.prototype.includes = _includes; + } + // .trim() polyfill // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/trim if (!String.prototype.trim) { @@ -1642,6 +1654,10 @@ }; } + if (! String.prototype.includes) { + String.prototype.includes = _includes; + } + /** * DataTables utility methods * @@ -2808,9 +2824,18 @@ return cellData.call( rowData ); } - if ( cellData === null && type == 'display' ) { + if ( cellData === null && type === 'display' ) { return ''; } + + if ( type === 'filter' ) { + var fomatters = DataTable.ext.type.search; + + if ( fomatters[ col.sType ] ) { + cellData = fomatters[ col.sType ]( cellData ); + } + } + return cellData; } @@ -4565,7 +4590,6 @@ var columns = settings.aoColumns; var column; var i, j, ien, jen, filterData, cellData, row; - var fomatters = DataTable.ext.type.search; var wasInvalidated = false; for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) { @@ -4580,10 +4604,6 @@ if ( column.bSearchable ) { cellData = _fnGetCellData( settings, i, j, 'filter' ); - if ( fomatters[ column.sType ] ) { - cellData = fomatters[ column.sType ]( cellData ); - } - // Search in DataTables 1.10 is string based. In 1.11 this // should be altered to also allow strict type checking. if ( cellData === null ) { @@ -6374,6 +6394,10 @@ */ function _fnSaveState ( settings ) { + if (settings._bLoadingState) { + return; + } + /* Store the interesting variables */ var state = { time: +new Date(), @@ -6408,98 +6432,128 @@ */ function _fnLoadState ( settings, oInit, callback ) { + if ( ! settings.oFeatures.bStateSave ) { + callback(); + return; + } + + var loaded = function(state) { + _fnImplementState(settings, state, callback); + } + + var state = settings.fnStateLoadCallback.call( settings.oInstance, settings, loaded ); + + if ( state !== undefined ) { + _fnImplementState( settings, state, callback ); + } + // otherwise, wait for the loaded callback to be executed + + return true; + } + + function _fnImplementState ( settings, s, callback) { var i, ien; var columns = settings.aoColumns; - var loaded = function ( s ) { - if ( ! s || ! s.time ) { - callback(); - return; - } + settings._bLoadingState = true; - // Allow custom and plug-in manipulation functions to alter the saved data set and - // cancelling of loading by returning false - var abStateLoad = _fnCallbackFire( settings, 'aoStateLoadParams', 'stateLoadParams', [settings, s] ); - if ( $.inArray( false, abStateLoad ) !== -1 ) { - callback(); - return; - } + // When StateRestore was introduced the state could now be implemented at any time + // Not just initialisation. To do this an api instance is required in some places + var api = settings._bInitComplete ? new DataTable.Api(settings) : null; - // Reject old data - var duration = settings.iStateDuration; - if ( duration > 0 && s.time < +new Date() - (duration*1000) ) { - callback(); - return; - } + if ( ! s || ! s.time ) { + settings._bLoadingState = false; + callback(); + return; + } - // Number of columns have changed - all bets are off, no restore of settings - if ( s.columns && columns.length !== s.columns.length ) { - callback(); - return; - } + // Allow custom and plug-in manipulation functions to alter the saved data set and + // cancelling of loading by returning false + var abStateLoad = _fnCallbackFire( settings, 'aoStateLoadParams', 'stateLoadParams', [settings, s] ); + if ( $.inArray( false, abStateLoad ) !== -1 ) { + settings._bLoadingState = false; + callback(); + return; + } + + // Reject old data + var duration = settings.iStateDuration; + if ( duration > 0 && s.time < +new Date() - (duration*1000) ) { + settings._bLoadingState = false; + callback(); + return; + } - // Store the saved state so it might be accessed at any time - settings.oLoadedState = $.extend( true, {}, s ); + // Number of columns have changed - all bets are off, no restore of settings + if ( s.columns && columns.length !== s.columns.length ) { + settings._bLoadingState = false; + callback(); + return; + } - // Restore key features - todo - for 1.11 this needs to be done by - // subscribed events - if ( s.start !== undefined ) { - settings._iDisplayStart = s.start; + // Store the saved state so it might be accessed at any time + settings.oLoadedState = $.extend( true, {}, s ); + + // Restore key features - todo - for 1.11 this needs to be done by + // subscribed events + if ( s.start !== undefined ) { + settings._iDisplayStart = s.start; + if(api === null) { settings.iInitDisplayStart = s.start; } - if ( s.length !== undefined ) { - settings._iDisplayLength = s.length; - } + } + if ( s.length !== undefined ) { + settings._iDisplayLength = s.length; + } - // Order - if ( s.order !== undefined ) { - settings.aaSorting = []; - $.each( s.order, function ( i, col ) { - settings.aaSorting.push( col[0] >= columns.length ? - [ 0, col[1] ] : - col - ); - } ); - } + // Order + if ( s.order !== undefined ) { + settings.aaSorting = []; + $.each( s.order, function ( i, col ) { + settings.aaSorting.push( col[0] >= columns.length ? + [ 0, col[1] ] : + col + ); + } ); + } - // Search - if ( s.search !== undefined ) { - $.extend( settings.oPreviousSearch, _fnSearchToHung( s.search ) ); - } + // Search + if ( s.search !== undefined ) { + $.extend( settings.oPreviousSearch, _fnSearchToHung( s.search ) ); + } - // Columns - // - if ( s.columns ) { - for ( i=0, ien=s.columns.length ; i<ien ; i++ ) { - var col = s.columns[i]; + // Columns + if ( s.columns ) { + for ( i=0, ien=s.columns.length ; i<ien ; i++ ) { + var col = s.columns[i]; - // Visibility - if ( col.visible !== undefined ) { + // Visibility + if ( col.visible !== undefined ) { + // If the api is defined, the table has been initialised so we need to use it rather than internal settings + if (api) { + // Don't redraw the columns on every iteration of this loop, we will do this at the end instead + api.column(i).visible(col.visible, false); + } + else { columns[i].bVisible = col.visible; } + } - // Search - if ( col.search !== undefined ) { - $.extend( settings.aoPreSearchCols[i], _fnSearchToHung( col.search ) ); - } + // Search + if ( col.search !== undefined ) { + $.extend( settings.aoPreSearchCols[i], _fnSearchToHung( col.search ) ); } } - - _fnCallbackFire( settings, 'aoStateLoaded', 'stateLoaded', [settings, s] ); - callback(); - }; - - if ( ! settings.oFeatures.bStateSave ) { - callback(); - return; + + // If the api is defined then we need to adjust the columns once the visibility has been changed + if (api) { + api.columns.adjust(); + } } - var state = settings.fnStateLoadCallback.call( settings.oInstance, settings, loaded ); - - if ( state !== undefined ) { - loaded( state ); - } - // otherwise, wait for the loaded callback to be executed - } + settings._bLoadingState = false; + _fnCallbackFire( settings, 'aoStateLoaded', 'stateLoaded', [settings, s] ); + callback(); + }; /** @@ -9590,7 +9644,7 @@ * @type string * @default Version number */ - DataTable.version = "1.11.2"; + DataTable.version = "1.11.3"; /** * Private data store, containing all of the settings objects that are @@ -14015,7 +14069,7 @@ * * @type string */ - build:"bs5/dt-1.11.2", + build:"bs5/dt-1.11.3", /** @@ -15048,6 +15102,10 @@ */ var __htmlEscapeEntities = function ( d ) { + if (Array.isArray(d)) { + d = d.join(','); + } + return typeof d === 'string' ? d .replace(/&/g, '&amp;') @@ -15242,6 +15300,7 @@ _fnSortData: _fnSortData, _fnSaveState: _fnSaveState, _fnLoadState: _fnLoadState, + _fnImplementState: _fnImplementState, _fnSettingsFromNode: _fnSettingsFromNode, _fnLog: _fnLog, _fnMap: _fnMap, diff --git a/src/static/templates/admin/diagnostics.hbs b/src/static/templates/admin/diagnostics.hbs @@ -150,7 +150,7 @@ <dt class="col-sm-5">Domain configuration <span class="badge bg-success d-none" id="domain-success" title="The domain variable matches the browser location and seems to be configured correctly.">Match</span> - <span class="badge bg-danger d-none" id="domain-warning" title="The domain variable does not matches the browsers location.&#013;&#010;The domain variable does not seem to be configured correctly.&#013;&#010;Some features may not work as expected!">No Match</span> + <span class="badge bg-danger d-none" id="domain-warning" title="The domain variable does not match the browser location.&#013;&#010;The domain variable does not seem to be configured correctly.&#013;&#010;Some features may not work as expected!">No Match</span> <span class="badge bg-success d-none" id="https-success" title="Configurued to use HTTPS">HTTPS</span> <span class="badge bg-danger d-none" id="https-warning" title="Not configured to use HTTPS.&#013;&#010;Some features may not work as expected!">No HTTPS</span> </dt>