diff --git a/.dockerignore b/.dockerignore index 37e0f2c42..b9969fcd2 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,3 +1,4 @@ target/ web/node_modules web/dist +.volumes/ diff --git a/Cargo.lock b/Cargo.lock index 0663a2ea0..d3ccfd49b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12,6 +12,15 @@ dependencies = [ "regex", ] +[[package]] +name = "addr2line" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" +dependencies = [ + "gimli", +] + [[package]] name = "adler" version = "1.0.2" @@ -122,15 +131,15 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41ed9a86bf92ae6580e0a31281f65a1b1d867c0cc68d5346e2ae128dddfa6a7d" +checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd" [[package]] name = "anstyle-parse" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e765fd216e48e067936442276d1d57399e37bce53c264d6fefbe298080cb57ee" +checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333" dependencies = [ "utf8parse", ] @@ -244,7 +253,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.22", ] [[package]] @@ -255,7 +264,7 @@ checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.22", ] [[package]] @@ -358,6 +367,21 @@ dependencies = [ "tower-service", ] +[[package]] +name = "backtrace" +version = "0.3.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide 0.6.2", + "object", + "rustc-demangle", +] + [[package]] name = "base16ct" version = "0.1.1" @@ -449,9 +473,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.3.2" +version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dbe3c979c178231552ecba20214a8272df4e09f232a87aef4320cf06539aded" +checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" [[package]] name = "bitvec" @@ -643,9 +667,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.3.4" +version = "4.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80672091db20273a15cf9fdd4e47ed43b5091ec9841bf4c6145c9dfbbcae09ed" +checksum = "d9394150f5b4273a1763355bd1c2ec54cc5a2593f790587bcd6b2c947cfa9211" dependencies = [ "clap_builder", "clap_derive", @@ -654,9 +678,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.3.4" +version = "4.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1458a1df40e1e2afebb7ab60ce55c1fa8f431146205aa5f4887e0b111c27636" +checksum = "9a78fbdd3cc2914ddf37ba444114bc7765bbdcb55ec9cbe6fa054f0137400717" dependencies = [ "anstream", "anstyle", @@ -674,7 +698,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.22", ] [[package]] @@ -770,7 +794,7 @@ dependencies = [ "serde_json", "tracing", "url", - "uuid 1.3.4", + "uuid 1.4.0", ] [[package]] @@ -978,18 +1002,31 @@ dependencies = [ [[package]] name = "curve25519-dalek" -version = "4.0.0-rc.2" +version = "4.0.0-rc.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03d928d978dbec61a1167414f5ec534f24bea0d7a0d24dd9b6233d3d8223e585" +checksum = "436ace70fc06e06f7f689d2624dc4e2f0ea666efb5aa704215f7249ae6e047a7" dependencies = [ "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", "fiat-crypto", - "packed_simd_2", "platforms", + "rustc_version", "subtle", "zeroize", ] +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.22", +] + [[package]] name = "darling" version = "0.13.4" @@ -1077,7 +1114,7 @@ dependencies = [ "tokio-stream", "tonic", "tonic-build", - "uuid 1.3.4", + "uuid 1.4.0", "webauthn-authenticator-rs", "webauthn-rs", "webauthn-rs-proto", @@ -1156,11 +1193,11 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35b50dba0afdca80b187392b24f2499a88c336d5a8493e4b4ccfb608708be56a" dependencies = [ - "bitflags 2.3.2", + "bitflags 2.3.3", "proc-macro2", "proc-macro2-diagnostics", "quote", - "syn 2.0.18", + "syn 2.0.22", ] [[package]] @@ -1239,7 +1276,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.22", ] [[package]] @@ -1381,6 +1418,12 @@ dependencies = [ "zeroize", ] +[[package]] +name = "equivalent" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88bffebc5d80432c9b140ee17875ff173a8ab62faad5b257da912bd2f6c1c0a1" + [[package]] name = "errno" version = "0.3.1" @@ -1531,14 +1574,14 @@ dependencies = [ "ethers-etherscan", "eyre", "hex", - "prettyplease 0.2.8", + "prettyplease 0.2.9", "proc-macro2", "quote", "regex", "reqwest", "serde", "serde_json", - "syn 2.0.18", + "syn 2.0.22", "toml", "walkdir", ] @@ -1556,7 +1599,7 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn 2.0.18", + "syn 2.0.22", ] [[package]] @@ -1582,7 +1625,7 @@ dependencies = [ "serde", "serde_json", "strum", - "syn 2.0.18", + "syn 2.0.22", "tempfile", "thiserror", "tiny-keccak", @@ -1817,7 +1860,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743" dependencies = [ "crc32fast", - "miniz_oxide", + "miniz_oxide 0.7.1", ] [[package]] @@ -1943,7 +1986,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.22", ] [[package]] @@ -1997,9 +2040,9 @@ dependencies = [ [[package]] name = "generator" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3e123d9ae7c02966b4d892e550bdc32164f05853cd40ab570650ad600596a8a" +checksum = "5cc16584ff22b460a382b7feec54b23d2908d858152e5739a120b949293bd74e" dependencies = [ "cc", "libc", @@ -2042,6 +2085,12 @@ dependencies = [ "polyval", ] +[[package]] +name = "gimli" +version = "0.27.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" + [[package]] name = "glob" version = "0.3.1" @@ -2084,9 +2133,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.19" +version = "0.3.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d357c7ae988e7d2182f7d7871d0b963962420b0678b0997ce7de72001aeab782" +checksum = "97ec8491ebaf99c8eaa73058b045fe58073cd6be7f596ac993ced0b0a0c01049" dependencies = [ "bytes", "fnv", @@ -2094,7 +2143,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap", + "indexmap 1.9.3", "slab", "tokio", "tokio-util", @@ -2249,9 +2298,9 @@ checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" [[package]] name = "hyper" -version = "0.14.26" +version = "0.14.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab302d72a6f11a3b910431ff93aae7e773078c769f0a3ef15fb9ec692ed147d4" +checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" dependencies = [ "bytes", "futures-channel", @@ -2403,6 +2452,16 @@ dependencies = [ "serde", ] +[[package]] +name = "indexmap" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +dependencies = [ + "equivalent", + "hashbrown 0.14.0", +] + [[package]] name = "inlinable_string" version = "0.1.15" @@ -2440,9 +2499,9 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.7.2" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12b6ee2129af8d4fb011108c73d99a1b83a85977f23b82460c0ae2e25bb4b57f" +checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" [[package]] name = "ipnetwork" @@ -2608,15 +2667,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.146" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b" - -[[package]] -name = "libm" -version = "0.1.4" +version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fc7aa29613bd6a620df431842069224d8bc9011086b1db4c0e0cd47fa03ec9a" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" [[package]] name = "libm" @@ -2727,6 +2780,15 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" +[[package]] +name = "miniz_oxide" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" +dependencies = [ + "adler", +] + [[package]] name = "miniz_oxide" version = "0.7.1" @@ -2838,13 +2900,13 @@ dependencies = [ [[package]] name = "num-bigint-dig" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2399c9463abc5f909349d8aa9ba080e0b88b3ce2885389b60b993f39b1a56905" +checksum = "53ba502077159ace3aa56c25449a007173a406607a94ef665247246191eb38b1" dependencies = [ "byteorder", "lazy_static", - "libm 0.2.7", + "libm", "num-integer", "num-iter", "num-traits", @@ -2881,7 +2943,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" dependencies = [ "autocfg", - "libm 0.2.7", + "libm", ] [[package]] @@ -2912,7 +2974,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.22", ] [[package]] @@ -2934,6 +2996,15 @@ dependencies = [ "url", ] +[[package]] +name = "object" +version = "0.30.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03b4680b86d9cfafba8fc491dc9b6df26b68cf40e9e6cd73909194759a63c385" +dependencies = [ + "memchr", +] + [[package]] name = "oid-registry" version = "0.4.0" @@ -3013,9 +3084,9 @@ dependencies = [ [[package]] name = "openssl" -version = "0.10.54" +version = "0.10.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69b3f656a17a6cbc115b5c7a40c616947d213ba182135b014d6051b73ab6f019" +checksum = "345df152bc43501c5eb9e4654ff05f794effb78d4efe3d53abc158baddc0703d" dependencies = [ "bitflags 1.3.2", "cfg-if", @@ -3034,7 +3105,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.22", ] [[package]] @@ -3045,9 +3116,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.88" +version = "0.9.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2ce0f250f34a308dcfdbb351f511359857d4ed2134ba715a4eadd46e1ffd617" +checksum = "374533b0e45f3a7ced10fcaeccca020e66656bc03dac384f852e4e5a7a8104a6" dependencies = [ "cc", "libc", @@ -3113,21 +3184,11 @@ dependencies = [ "sha2 0.10.7", ] -[[package]] -name = "packed_simd_2" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1914cd452d8fccd6f9db48147b29fd4ae05bea9dc5d9ad578509f72415de282" -dependencies = [ - "cfg-if", - "libm 0.1.4", -] - [[package]] name = "parity-scale-codec" -version = "3.6.0" +version = "3.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "430d26d62e66cbff6ae144e8eebd43c0235922dec7e3aa0d2016c32d4575bf45" +checksum = "2287753623c76f953acd29d15d8100bcab84d29db78fb6f352adb3c53e83b967" dependencies = [ "arrayvec", "bitvec 1.0.1", @@ -3139,9 +3200,9 @@ dependencies = [ [[package]] name = "parity-scale-codec-derive" -version = "3.6.0" +version = "3.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1620b1e3fc72ebaee01ff56fca838bab537c5d093a18b3549c3bbea374aa0b6" +checksum = "2b6937b5e67bfba3351b87b040d48352a2fcb6ad72f81855412ce97b45c8f110" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -3273,7 +3334,7 @@ dependencies = [ "proc-macro2", "proc-macro2-diagnostics", "quote", - "syn 2.0.18", + "syn 2.0.22", ] [[package]] @@ -3307,7 +3368,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4dd7d28ee937e54fe3080c91faa1c3a46c06de6252988a7f4592ba2310ef22a4" dependencies = [ "fixedbitset", - "indexmap", + "indexmap 1.9.3", ] [[package]] @@ -3322,35 +3383,35 @@ dependencies = [ [[package]] name = "phf" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "928c6535de93548188ef63bb7c4036bd415cd8f36ad25af44b9789b2ee72a48c" +checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" dependencies = [ "phf_macros", - "phf_shared 0.11.1", + "phf_shared 0.11.2", ] [[package]] name = "phf_generator" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1181c94580fa345f50f19d738aaa39c0ed30a600d95cb2d3e23f94266f14fbf" +checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" dependencies = [ - "phf_shared 0.11.1", + "phf_shared 0.11.2", "rand", ] [[package]] name = "phf_macros" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92aacdc5f16768709a569e913f7451034034178b05bdc8acda226659a3dccc66" +checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" dependencies = [ "phf_generator", - "phf_shared 0.11.1", + "phf_shared 0.11.2", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.22", ] [[package]] @@ -3364,9 +3425,9 @@ dependencies = [ [[package]] name = "phf_shared" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1fb5f6f826b772a8d4c0394209441e7d37cbbb967ae9c7e0e8134365c9ee676" +checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" dependencies = [ "siphasher", ] @@ -3388,7 +3449,7 @@ checksum = "39407670928234ebc5e6e580247dd567ad73a3578460c5990f9503df207e8f07" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.22", ] [[package]] @@ -3483,12 +3544,12 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2b0377b720bde721213a46cda1289b2f34abf0a436907cad91578c20de0454d" +checksum = "9825a04601d60621feed79c4e6b56d65db77cdca55cef43b46b0de1096d1c282" dependencies = [ "proc-macro2", - "syn 2.0.18", + "syn 2.0.22", ] [[package]] @@ -3547,9 +3608,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro2" -version = "1.0.60" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406" +checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb" dependencies = [ "unicode-ident", ] @@ -3562,7 +3623,7 @@ checksum = "606c4ba35817e2922a308af55ad51bab3645b59eae5c570d4a6cf07e36bd493b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.22", "version_check", "yansi", ] @@ -3740,7 +3801,7 @@ checksum = "8d2275aab483050ab2a7364c1a46604865ee7d6906684e08db0f090acf74f9e7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.22", ] [[package]] @@ -3898,7 +3959,7 @@ dependencies = [ "either", "figment", "futures", - "indexmap", + "indexmap 1.9.3", "is-terminal", "log", "memchr", @@ -3931,11 +3992,11 @@ checksum = "7093353f14228c744982e409259fb54878ba9563d08214f2d880d59ff2fc508b" dependencies = [ "devise", "glob", - "indexmap", + "indexmap 1.9.3", "proc-macro2", "quote", "rocket_http", - "syn 2.0.18", + "syn 2.0.22", "unicode-xid", ] @@ -3950,7 +4011,7 @@ dependencies = [ "futures", "http", "hyper", - "indexmap", + "indexmap 1.9.3", "log", "memchr", "pear", @@ -4027,6 +4088,12 @@ dependencies = [ "ordered-multimap", ] +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + [[package]] name = "rustc-hex" version = "2.1.0" @@ -4140,9 +4207,9 @@ dependencies = [ [[package]] name = "scale-info" -version = "2.7.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b569c32c806ec3abdf3b5869fb8bf1e0d275a7c1c9b0b05603d9464632649edf" +checksum = "ad560913365790f17cbf12479491169f01b9d46d29cfc7422bf8c64bdc61b731" dependencies = [ "cfg-if", "derive_more", @@ -4152,9 +4219,9 @@ dependencies = [ [[package]] name = "scale-info-derive" -version = "2.6.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53012eae69e5aa5c14671942a5dd47de59d4cdcff8532a6dd0e081faf1119482" +checksum = "19df9bd9ace6cc2fe19387c96ce677e823e07d017ceed253e7bb3d1d1bd9c73b" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -4333,14 +4400,14 @@ checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.22", ] [[package]] name = "serde_json" -version = "1.0.97" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdf3bf93142acad5821c99197022e170842cdbc1c30482b98750c688c640842a" +checksum = "46266871c240a00b8f503b877622fe33430b3c7d963bdc0f2adc511e54a1eae3" dependencies = [ "itoa", "ryu", @@ -4378,9 +4445,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93107647184f6027e3b7dcb2e11034cf95ffa1e3a682c67951963ac69c1c007d" +checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186" dependencies = [ "serde", ] @@ -4650,7 +4717,7 @@ dependencies = [ "hex", "hkdf", "hmac", - "indexmap", + "indexmap 1.9.3", "ipnetwork", "itoa", "libc", @@ -4672,7 +4739,7 @@ dependencies = [ "thiserror", "tokio-stream", "url", - "uuid 1.3.4", + "uuid 1.4.0", "whoami", ] @@ -4824,9 +4891,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.18" +version = "2.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" +checksum = "2efbeae7acf4eabd6bcdcbd11c92f45231ddda7539edc7806bd1a04a03b24616" dependencies = [ "proc-macro2", "quote", @@ -4899,7 +4966,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.22", ] [[package]] @@ -4976,11 +5043,12 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.28.2" +version = "1.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94d7b1cfd2aa4011f2de74c2c4c63665e27a71006b0a192dcd2710272e73dfa2" +checksum = "374442f06ee49c3a28a8fc9f01a2596fed7559c6b99b31279c3261778e77d84f" dependencies = [ "autocfg", + "backtrace", "bytes", "libc", "mio", @@ -5010,7 +5078,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.22", ] [[package]] @@ -5075,9 +5143,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6135d499e69981f9ff0ef2167955a5333c35e36f6937d382974566b3d5b94ec" +checksum = "1ebafdf5ad1220cb59e7d17cf4d2c72015297b75b19a10472f99b89225089240" dependencies = [ "serde", "serde_spanned", @@ -5087,20 +5155,20 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a76a9312f5ba4c2dec6b9161fdf25d87ad8a09256ccea5a556fef03c706a10f" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.19.10" +version = "0.19.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2380d56e8670370eee6566b0bfd4265f65b3f432e8c6d85623f728d4fa31f739" +checksum = "266f016b7f039eec8a1a80dfe6156b633d208b9fccca5e4db1d6775b0c4e34a7" dependencies = [ - "indexmap", + "indexmap 2.0.0", "serde", "serde_spanned", "toml_datetime", @@ -5161,7 +5229,7 @@ checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" dependencies = [ "futures-core", "futures-util", - "indexmap", + "indexmap 1.9.3", "pin-project", "pin-project-lite", "rand", @@ -5199,13 +5267,13 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.24" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f57e3ca2a01450b1a921183a9c9cbfda207fd822cef4ccb00a65402cbba7a74" +checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.22", ] [[package]] @@ -5412,9 +5480,9 @@ dependencies = [ [[package]] name = "uuid" -version = "1.3.4" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa2982af2eec27de306107c027578ff7f423d65f7250e40ce0fea8f45248b81" +checksum = "d023da39d1fde5a8a3fe1f3e01ca9632ada0a63e9797de55a879d6e2236277be" dependencies = [ "getrandom", "serde", @@ -5490,7 +5558,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.22", "wasm-bindgen-shared", ] @@ -5524,7 +5592,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.22", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -5560,7 +5628,7 @@ dependencies = [ "serde_json", "tracing", "url", - "uuid 1.3.4", + "uuid 1.4.0", "webauthn-rs-proto", ] @@ -5574,7 +5642,7 @@ dependencies = [ "serde", "tracing", "url", - "uuid 1.3.4", + "uuid 1.4.0", "webauthn-rs-core", ] @@ -5597,7 +5665,7 @@ dependencies = [ "thiserror", "tracing", "url", - "uuid 1.3.4", + "uuid 1.4.0", "webauthn-rs-proto", "x509-parser", ] @@ -5655,9 +5723,9 @@ dependencies = [ [[package]] name = "whoami" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c70234412ca409cc04e864e89523cb0fc37f5e1344ebed5a3ebf4192b6b9f68" +checksum = "22fc3756b8a9133049b26c7f61ab35416c130e8c09b660f5b3958b446f52cc50" dependencies = [ "wasm-bindgen", "web-sys", @@ -5874,9 +5942,9 @@ dependencies = [ [[package]] name = "x25519-dalek" -version = "2.0.0-rc.2" +version = "2.0.0-rc.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fabd6e16dd08033932fc3265ad4510cc2eab24656058a6dcb107ffe274abcc95" +checksum = "ec7fae07da688e17059d5886712c933bb0520f15eff2e09cfa18e30968f4e63a" dependencies = [ "curve25519-dalek", "rand_core", @@ -5925,7 +5993,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.22", ] [[package]] diff --git a/migrations/20230614093458_wireguard_network_device.down.sql b/migrations/20230614093458_wireguard_network_device.down.sql new file mode 100644 index 000000000..c29f36e7e --- /dev/null +++ b/migrations/20230614093458_wireguard_network_device.down.sql @@ -0,0 +1,4 @@ +-- Add down migration script here +ALTER TABLE device ADD COLUMN wireguard_ip text; +DELETE FROM device; +DROP TABLE wireguard_network_device; diff --git a/migrations/20230614093458_wireguard_network_device.up.sql b/migrations/20230614093458_wireguard_network_device.up.sql new file mode 100644 index 000000000..0250ebc29 --- /dev/null +++ b/migrations/20230614093458_wireguard_network_device.up.sql @@ -0,0 +1,12 @@ +-- Add up migration script here +CREATE TABLE wireguard_network_device ( + device_id bigint REFERENCES "device"(id) ON DELETE CASCADE, + wireguard_network_id bigint REFERENCES "wireguard_network"(id) ON DELETE CASCADE, + wireguard_ip text NOT NULL, + CONSTRAINT device_network UNIQUE (device_id, wireguard_network_id) +); +-- migrate data from device +INSERT INTO wireguard_network_device(device_id, wireguard_network_id, wireguard_ip) +SELECT d.id, (SELECT id from wireguard_network ORDER BY id ASC LIMIT 1), d.wireguard_ip FROM device d; + +ALTER TABLE device DROP COLUMN wireguard_ip; diff --git a/sqlx-data.json b/sqlx-data.json index bc61f484b..142b93364 100644 --- a/sqlx-data.json +++ b/sqlx-data.json @@ -83,29 +83,40 @@ }, "query": "SELECT id \"id?\", client_id, client_secret, redirect_uri, scope, name, enabled FROM oauth2client WHERE client_id = $1 AND enabled" }, - "048b548a3b07078af6e10bb9ce4f2795124f3b47f2ec1a77e94431ea86cc8c87": { + "05e3fce0c51856f6033195c7523a2b5fd1c2a7968a7abd27394422a7c93e8815": { "describe": { "columns": [ { - "name": "id", + "name": "collected_at: NaiveDateTime", "ordinal": 0, + "type_info": "Timestamp" + }, + { + "name": "upload", + "ordinal": 1, + "type_info": "Int8" + }, + { + "name": "download", + "ordinal": 2, "type_info": "Int8" } ], "nullable": [ - false + null, + null, + null ], "parameters": { "Left": [ "Text", - "Text", - "Text", + "Timestamp", "Int8", - "Timestamp" + "Int8" ] } }, - "query": "INSERT INTO \"device\" (\"name\", \"wireguard_ip\", \"wireguard_pubkey\", \"user_id\", \"created\") VALUES ($1, $2, $3, $4, $5) RETURNING id" + "query": "\n SELECT\n date_trunc($1, collected_at) \"collected_at: NaiveDateTime\",\n cast(sum(upload) AS bigint) upload, cast(sum(download) AS bigint) download\n FROM wireguard_peer_stats_view\n WHERE collected_at >= $2 AND network = $3\n GROUP BY 1\n ORDER BY 1\n LIMIT $4\n " }, "06be7b39c87c3a1d1465dfb007937b5b584f60e9094a18936b482c4dfb6b1aca": { "describe": { @@ -543,56 +554,6 @@ }, "query": "SELECT id \"id?\", user_id, name, passkey FROM webauthn WHERE user_id = $1" }, - "18ffb38cc65309feb0798f5d97368b9112ecfd7cf8a2714d3764e1f100c124f3": { - "describe": { - "columns": [ - { - "name": "id?", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "name", - "ordinal": 1, - "type_info": "Text" - }, - { - "name": "wireguard_ip", - "ordinal": 2, - "type_info": "Text" - }, - { - "name": "wireguard_pubkey", - "ordinal": 3, - "type_info": "Text" - }, - { - "name": "user_id", - "ordinal": 4, - "type_info": "Int8" - }, - { - "name": "created", - "ordinal": 5, - "type_info": "Timestamp" - } - ], - "nullable": [ - false, - false, - false, - false, - false, - false - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "SELECT device.id \"id?\", name, wireguard_ip, wireguard_pubkey, user_id, created FROM device WHERE user_id = $1" - }, "1996dee9b5e3b8f8a1f63f99e83230927c09d30ceabd07dc193502ce780a3aed": { "describe": { "columns": [], @@ -902,6 +863,38 @@ }, "query": "SELECT oauth2authorizedapp_id, access_token, refresh_token, redirect_uri, scope, expires_in FROM oauth2token WHERE oauth2authorizedapp_id = $1" }, + "30b56753b839207eae5dab9cba0c061203728b6e272b270ac1111048c80363d3": { + "describe": { + "columns": [ + { + "name": "device_id", + "ordinal": 0, + "type_info": "Int8" + }, + { + "name": "wireguard_network_id", + "ordinal": 1, + "type_info": "Int8" + }, + { + "name": "wireguard_ip", + "ordinal": 2, + "type_info": "Text" + } + ], + "nullable": [ + true, + true, + false + ], + "parameters": { + "Left": [ + "Int8" + ] + } + }, + "query": "SELECT *\n FROM wireguard_network_device WHERE device_id = $1" + }, "31b3fcaa8109121f985a2c740475f1d77fe8dcbcab76e64164be140ad361ab14": { "describe": { "columns": [], @@ -1010,6 +1003,50 @@ }, "query": "DELETE FROM group_user WHERE group_id = $1 AND user_id = $2" }, + "33a1e2f1904757c775d389fa99d67916b7b220d6aa1fe8bb6690f85ed1cd5666": { + "describe": { + "columns": [ + { + "name": "id?", + "ordinal": 0, + "type_info": "Int8" + }, + { + "name": "name", + "ordinal": 1, + "type_info": "Text" + }, + { + "name": "wireguard_pubkey", + "ordinal": 2, + "type_info": "Text" + }, + { + "name": "user_id", + "ordinal": 3, + "type_info": "Int8" + }, + { + "name": "created", + "ordinal": 4, + "type_info": "Timestamp" + } + ], + "nullable": [ + false, + false, + false, + false, + false + ], + "parameters": { + "Left": [ + "Text" + ] + } + }, + "query": "SELECT device.id \"id?\", name, wireguard_pubkey, user_id, created FROM device JOIN \"user\" ON device.user_id = \"user\".id WHERE \"user\".username = $1" + }, "33e91546890789d9341b06c541648149baf908b4f2ba35da8adc07feda6299e3": { "describe": { "columns": [ @@ -1113,6 +1150,26 @@ }, "query": "UPDATE \"user\" SET mfa_enabled = $2, totp_enabled = $3 AND totp_secret = $4 WHERE id = $1" }, + "3874e3ddc2d3b4b455fddca611702b86a1f2d02b1878f6f262211f97e0d661b2": { + "describe": { + "columns": [ + { + "name": "count!", + "ordinal": 0, + "type_info": "Int8" + } + ], + "nullable": [ + null + ], + "parameters": { + "Left": [ + "Int8" + ] + } + }, + "query": "SELECT count(*) \"count!\" FROM wireguard_network_device WHERE wireguard_network_id = $1" + }, "3a0fc5bc3005b4b6b5d6ccf2cf71b7915cda2c440eb8f3194480bbaf2969228e": { "describe": { "columns": [ @@ -1163,32 +1220,6 @@ }, "query": "SELECT mfa_method \"mfa_method: _\", totp_enabled totp_available, (SELECT count(*) > 0 FROM wallet WHERE user_id = $1 AND wallet.use_for_mfa) \"web3_available!\", (SELECT count(*) > 0 FROM webauthn WHERE user_id = $1) \"webauthn_available!\" FROM \"user\" WHERE \"user\".id = $1" }, - "3a73f9c03328d54bdaa61188dc3a53811defbe0814fabf6b69a81a78d0bdbd95": { - "describe": { - "columns": [ - { - "name": "active_users!", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "active_devices!", - "ordinal": 1, - "type_info": "Int8" - } - ], - "nullable": [ - null, - null - ], - "parameters": { - "Left": [ - "Timestamp" - ] - } - }, - "query": "\n SELECT\n COALESCE(COUNT(DISTINCT(u.id)), 0) as \"active_users!\",\n COALESCE(COUNT(DISTINCT(s.device_id)), 0) as \"active_devices!\"\n FROM \"user\" u\n JOIN device d ON d.user_id = u.id\n JOIN wireguard_peer_stats s ON s.device_id = d.id\n WHERE latest_handshake >= $1\n " - }, "3abcf090a9adea823eb2288d1379916fce5f172e9f92243c3706f3fac48464ab": { "describe": { "columns": [], @@ -1222,20 +1253,7 @@ }, "query": "DELETE FROM \"webhook\" WHERE id = $1" }, - "454f2edaee1d6c60e75f20ef4344e5ceba35c07316b4317b9b0a6e78b41de0bf": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Int8", - "Bool" - ] - } - }, - "query": "UPDATE \"user\" SET mfa_enabled = $2 WHERE id = $1" - }, - "4a50eccb1be2b1721d27b4aaf59108ab739b7cbc9dad8b602297c5cded6bd03e": { + "3fe95f7f36317af0d3b95e0b460536fd8e597e01cdc54936d3270b0a5937d708": { "describe": { "columns": [ { @@ -1248,24 +1266,19 @@ "ordinal": 1, "type_info": "Text" }, - { - "name": "wireguard_ip", - "ordinal": 2, - "type_info": "Text" - }, { "name": "wireguard_pubkey", - "ordinal": 3, + "ordinal": 2, "type_info": "Text" }, { "name": "user_id", - "ordinal": 4, + "ordinal": 3, "type_info": "Int8" }, { "name": "created", - "ordinal": 5, + "ordinal": 4, "type_info": "Timestamp" } ], @@ -1274,58 +1287,156 @@ false, false, false, - false, false ], "parameters": { "Left": [ - "Text" + "Int8" ] } }, - "query": "SELECT id \"id?\", name, wireguard_ip, wireguard_pubkey, user_id, created FROM device WHERE wireguard_pubkey = $1" + "query": "SELECT id \"id?\", \"name\", \"wireguard_pubkey\", \"user_id\", \"created\" FROM \"device\" WHERE id = $1" }, - "4ae5364b82667472eb900164f048c6678f521c051ea401338480f5e5f0bf21a2": { + "4183b4f169126bcc511ff76c7554622fc71857d0d459588b4f3934307611aee7": { "describe": { "columns": [ { - "name": "id?", + "name": "active_users!", "ordinal": 0, "type_info": "Int8" }, { - "name": "device_id!", + "name": "active_devices!", "ordinal": 1, "type_info": "Int8" - }, - { - "name": "collected_at!", - "ordinal": 2, - "type_info": "Timestamp" - }, + } + ], + "nullable": [ + null, + null + ], + "parameters": { + "Left": [ + "Timestamp", + "Int8" + ] + } + }, + "query": "\n SELECT\n COALESCE(COUNT(DISTINCT(u.id)), 0) as \"active_users!\",\n COALESCE(COUNT(DISTINCT(s.device_id)), 0) as \"active_devices!\"\n FROM \"user\" u\n JOIN device d ON d.user_id = u.id\n JOIN wireguard_peer_stats s ON s.device_id = d.id\n WHERE latest_handshake >= $1 AND s.network = $2\n " + }, + "439bef62ccc846cccca2c6979e5698a7aaba2beb19645b720eefa73e4dcac942": { + "describe": { + "columns": [ { - "name": "network!", - "ordinal": 3, + "name": "id?", + "ordinal": 0, "type_info": "Int8" }, { - "name": "endpoint", - "ordinal": 4, + "name": "name", + "ordinal": 1, "type_info": "Text" }, { - "name": "upload!", - "ordinal": 5, - "type_info": "Int8" + "name": "wireguard_pubkey", + "ordinal": 2, + "type_info": "Text" }, { - "name": "download!", - "ordinal": 6, + "name": "user_id", + "ordinal": 3, "type_info": "Int8" }, { - "name": "latest_handshake!", - "ordinal": 7, + "name": "created", + "ordinal": 4, + "type_info": "Timestamp" + } + ], + "nullable": [ + false, + false, + false, + false, + false + ], + "parameters": { + "Left": [ + "Int8", + "Text" + ] + } + }, + "query": "SELECT device.id \"id?\", name, wireguard_pubkey, user_id, created FROM device JOIN \"user\" ON device.user_id = \"user\".id WHERE device.id = $1 AND \"user\".username = $2" + }, + "454f2edaee1d6c60e75f20ef4344e5ceba35c07316b4317b9b0a6e78b41de0bf": { + "describe": { + "columns": [], + "nullable": [], + "parameters": { + "Left": [ + "Int8", + "Bool" + ] + } + }, + "query": "UPDATE \"user\" SET mfa_enabled = $2 WHERE id = $1" + }, + "45545d3190c14bb3e9528ab3d3a8522209f36956f65bf5a126682d5477db425e": { + "describe": { + "columns": [], + "nullable": [], + "parameters": { + "Left": [ + "Int8", + "Int8", + "Text" + ] + } + }, + "query": "\n UPDATE wireguard_network_device\n SET wireguard_ip = $3\n WHERE device_id = $1 AND wireguard_network_id = $2\n " + }, + "4ae5364b82667472eb900164f048c6678f521c051ea401338480f5e5f0bf21a2": { + "describe": { + "columns": [ + { + "name": "id?", + "ordinal": 0, + "type_info": "Int8" + }, + { + "name": "device_id!", + "ordinal": 1, + "type_info": "Int8" + }, + { + "name": "collected_at!", + "ordinal": 2, + "type_info": "Timestamp" + }, + { + "name": "network!", + "ordinal": 3, + "type_info": "Int8" + }, + { + "name": "endpoint", + "ordinal": 4, + "type_info": "Text" + }, + { + "name": "upload!", + "ordinal": 5, + "type_info": "Int8" + }, + { + "name": "download!", + "ordinal": 6, + "type_info": "Int8" + }, + { + "name": "latest_handshake!", + "ordinal": 7, "type_info": "Timestamp" }, { @@ -1353,6 +1464,63 @@ }, "query": "\n SELECT id \"id?\", device_id \"device_id!\", collected_at \"collected_at!\", network \"network!\",\n endpoint, upload \"upload!\", download \"download!\", latest_handshake \"latest_handshake!\", allowed_ips\n FROM wireguard_peer_stats\n WHERE device_id = $1\n ORDER BY collected_at DESC\n LIMIT 1\n " }, + "4b17182c8e0271894d0e91598672d9f3fd43328d37adcc82168e26c12c5f8c05": { + "describe": { + "columns": [ + { + "name": "network_id", + "ordinal": 0, + "type_info": "Int8" + }, + { + "name": "network_name", + "ordinal": 1, + "type_info": "Text" + }, + { + "name": "gateway_endpoint", + "ordinal": 2, + "type_info": "Text" + }, + { + "name": "device_wireguard_ip", + "ordinal": 3, + "type_info": "Text" + }, + { + "name": "device_endpoint", + "ordinal": 4, + "type_info": "Text" + }, + { + "name": "latest_handshake?", + "ordinal": 5, + "type_info": "Timestamp" + }, + { + "name": "is_active!", + "ordinal": 6, + "type_info": "Bool" + } + ], + "nullable": [ + false, + false, + false, + false, + true, + false, + null + ], + "parameters": { + "Left": [ + "Float8", + "Int8" + ] + } + }, + "query": "\n WITH stats AS (\n SELECT DISTINCT ON (network) network, endpoint, latest_handshake\n FROM wireguard_peer_stats\n ORDER BY network, collected_at DESC\n )\n SELECT\n n.id as network_id, n.name as network_name, n.endpoint as gateway_endpoint,\n wnd.wireguard_ip as device_wireguard_ip, stats.endpoint as device_endpoint,\n stats.latest_handshake as \"latest_handshake?\",\n COALESCE (((NOW() - stats.latest_handshake) < $1 * interval '1 minute'), false) as \"is_active!\"\n FROM wireguard_network_device wnd\n JOIN wireguard_network n ON n.id = wnd.wireguard_network_id\n LEFT JOIN stats on n.id = stats.network\n WHERE wnd.device_id = $2\n " + }, "4e1d29f6440594e4303d9ff7da541b4bca33b44e931126ba8c6b31304a9206b3": { "describe": { "columns": [], @@ -1493,7 +1661,7 @@ }, "query": "UPDATE \"webauthn\" SET \"user_id\" = $2, \"name\" = $3, \"passkey\" = $4 WHERE id = $1" }, - "5ecfb41255d2aa4cb98b509fc17122c4032c7b81db6645853c6dcdbcc596c0b6": { + "5a692c1c321149cbffd9e8726e74770d1299994ccd27ce3270d0fb7970a4da7c": { "describe": { "columns": [ { @@ -1502,44 +1670,89 @@ "type_info": "Int8" }, { - "name": "device_id", + "name": "name", "ordinal": 1, - "type_info": "Int8" + "type_info": "Text" }, { - "name": "collected_at", + "name": "wireguard_pubkey", "ordinal": 2, - "type_info": "Timestamp" + "type_info": "Text" }, { - "name": "network", + "name": "user_id", "ordinal": 3, "type_info": "Int8" }, { - "name": "endpoint", + "name": "created", "ordinal": 4, - "type_info": "Text" - }, + "type_info": "Timestamp" + } + ], + "nullable": [ + false, + false, + false, + false, + false + ], + "parameters": { + "Left": [] + } + }, + "query": "SELECT id \"id?\", \"name\", \"wireguard_pubkey\", \"user_id\", \"created\" FROM \"device\"" + }, + "5cc93c3d18adf2dc9cb02e79d38a41bd0b2d6a8e4d33efcd12a54a7760c75c71": { + "describe": { + "columns": [ { - "name": "upload", - "ordinal": 5, + "name": "id", + "ordinal": 0, "type_info": "Int8" - }, + } + ], + "nullable": [ + false + ], + "parameters": { + "Left": [ + "Text", + "Text", + "Int8", + "Timestamp" + ] + } + }, + "query": "INSERT INTO \"device\" (\"name\", \"wireguard_pubkey\", \"user_id\", \"created\") VALUES ($1, $2, $3, $4) RETURNING id" + }, + "5d98c0f4e3ee92bbaa13a8acf2b6008d327e3838eafbe175afd5a934f8218b12": { + "describe": { + "columns": [ { - "name": "download", - "ordinal": 6, + "name": "id?", + "ordinal": 0, "type_info": "Int8" }, { - "name": "latest_handshake", - "ordinal": 7, - "type_info": "Timestamp" + "name": "name", + "ordinal": 1, + "type_info": "Text" }, { - "name": "allowed_ips", - "ordinal": 8, + "name": "wireguard_pubkey", + "ordinal": 2, "type_info": "Text" + }, + { + "name": "user_id", + "ordinal": 3, + "type_info": "Int8" + }, + { + "name": "created", + "ordinal": 4, + "type_info": "Timestamp" } ], "nullable": [ @@ -1547,19 +1760,17 @@ false, false, false, - true, - false, - false, - false, - true + false ], "parameters": { - "Left": [] + "Left": [ + "Timestamp" + ] } }, - "query": "SELECT id \"id?\", \"device_id\", \"collected_at\", \"network\", \"endpoint\", \"upload\", \"download\", \"latest_handshake\", \"allowed_ips\" FROM \"wireguard_peer_stats\"" + "query": "\n WITH s AS (\n SELECT DISTINCT ON (device_id) *\n FROM wireguard_peer_stats\n ORDER BY device_id, latest_handshake DESC\n )\n SELECT\n d.id \"id?\", d.name, d.wireguard_pubkey, d.user_id, d.created\n FROM device d\n JOIN s ON d.id = s.device_id\n WHERE s.latest_handshake > $1\n " }, - "627ec688631de93ef949e41777f0ea076dcef5e9007466f0553dd1f1df45174a": { + "5ecfb41255d2aa4cb98b509fc17122c4032c7b81db6645853c6dcdbcc596c0b6": { "describe": { "columns": [ { @@ -1568,29 +1779,44 @@ "type_info": "Int8" }, { - "name": "name", + "name": "device_id", "ordinal": 1, - "type_info": "Text" + "type_info": "Int8" }, { - "name": "wireguard_ip", + "name": "collected_at", "ordinal": 2, - "type_info": "Text" + "type_info": "Timestamp" }, { - "name": "wireguard_pubkey", + "name": "network", "ordinal": 3, - "type_info": "Text" + "type_info": "Int8" }, { - "name": "user_id", + "name": "endpoint", "ordinal": 4, - "type_info": "Int8" + "type_info": "Text" }, { - "name": "created", + "name": "upload", "ordinal": 5, + "type_info": "Int8" + }, + { + "name": "download", + "ordinal": 6, + "type_info": "Int8" + }, + { + "name": "latest_handshake", + "ordinal": 7, "type_info": "Timestamp" + }, + { + "name": "allowed_ips", + "ordinal": 8, + "type_info": "Text" } ], "nullable": [ @@ -1598,17 +1824,17 @@ false, false, false, + true, false, - false + false, + false, + true ], "parameters": { - "Left": [ - "Int8", - "Int8" - ] + "Left": [] } }, - "query": "SELECT device.id \"id?\", name, wireguard_ip, wireguard_pubkey, user_id, created FROM device JOIN \"user\" ON device.user_id = \"user\".id WHERE device.id = $1 AND \"user\".id = $2" + "query": "SELECT id \"id?\", \"device_id\", \"collected_at\", \"network\", \"endpoint\", \"upload\", \"download\", \"latest_handshake\", \"allowed_ips\" FROM \"wireguard_peer_stats\"" }, "6700901a46e82d30d7586ad3039e9ad91d8ca682491977443d6e28e31513b86d": { "describe": { @@ -1933,24 +2159,6 @@ }, "query": "SELECT id \"id?\", \"user_id\", \"oauth2client_id\" FROM \"oauth2authorizedapp\"" }, - "7cf85946b3bb1f15d1158ccea7b361424056c3532cac1985e65fcdf3eca59242": { - "describe": { - "columns": [ - { - "name": "count!", - "ordinal": 0, - "type_info": "Int8" - } - ], - "nullable": [ - null - ], - "parameters": { - "Left": [] - } - }, - "query": "SELECT count(*) \"count!\" FROM device" - }, "7d502cb019e69adc755d828bc581fa56c24c48245689fd21799ec96b1dac10ad": { "describe": { "columns": [ @@ -2308,6 +2516,50 @@ }, "query": "INSERT INTO group_user (group_id, user_id) VALUES ($1, $2) ON CONFLICT DO NOTHING" }, + "929535564469ee1701f83a1489301d0d652d5452369a2dce933f032cdb7092e2": { + "describe": { + "columns": [ + { + "name": "id?", + "ordinal": 0, + "type_info": "Int8" + }, + { + "name": "name", + "ordinal": 1, + "type_info": "Text" + }, + { + "name": "wireguard_pubkey", + "ordinal": 2, + "type_info": "Text" + }, + { + "name": "user_id", + "ordinal": 3, + "type_info": "Int8" + }, + { + "name": "created", + "ordinal": 4, + "type_info": "Timestamp" + } + ], + "nullable": [ + false, + false, + false, + false, + false + ], + "parameters": { + "Left": [ + "Int8" + ] + } + }, + "query": "\n SELECT device.id \"id?\", name, wireguard_pubkey, user_id, created\n FROM device WHERE user_id = $1\n " + }, "92b38a3eec51c346623be6fc2ba18f8ca137d7c810a7cc6591b54bc686099254": { "describe": { "columns": [], @@ -2398,56 +2650,6 @@ }, "query": "SELECT id \"id?\", \"url\", \"description\", \"token\", \"enabled\", \"on_user_created\", \"on_user_deleted\", \"on_user_modified\", \"on_hwkey_provision\" FROM \"webhook\"" }, - "996fb6d746721e6ff78a3da44b2e5122ee4aaeeeb6c7548f340cff89111fffdb": { - "describe": { - "columns": [ - { - "name": "id?", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "name", - "ordinal": 1, - "type_info": "Text" - }, - { - "name": "wireguard_ip", - "ordinal": 2, - "type_info": "Text" - }, - { - "name": "wireguard_pubkey", - "ordinal": 3, - "type_info": "Text" - }, - { - "name": "user_id", - "ordinal": 4, - "type_info": "Int8" - }, - { - "name": "created", - "ordinal": 5, - "type_info": "Timestamp" - } - ], - "nullable": [ - false, - false, - false, - false, - false, - false - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "SELECT id \"id?\", \"name\", \"wireguard_ip\", \"wireguard_pubkey\", \"user_id\", \"created\" FROM \"device\" WHERE id = $1" - }, "9a1cfdf1f96c45d912bb7ad8874d690deb3daf05a93d8d83297872dad08fb8dc": { "describe": { "columns": [ @@ -2596,6 +2798,51 @@ }, "query": "SELECT id \"id?\", \"url\", \"description\", \"token\", \"enabled\", \"on_user_created\", \"on_user_deleted\", \"on_user_modified\", \"on_hwkey_provision\" FROM \"webhook\" WHERE id = $1" }, + "9e3c1c1f52bc1a576012c57c7472f9f7601e1128b15fc0ecc7676cd5aa01c88c": { + "describe": { + "columns": [ + { + "name": "id?", + "ordinal": 0, + "type_info": "Int8" + }, + { + "name": "name", + "ordinal": 1, + "type_info": "Text" + }, + { + "name": "wireguard_pubkey", + "ordinal": 2, + "type_info": "Text" + }, + { + "name": "user_id", + "ordinal": 3, + "type_info": "Int8" + }, + { + "name": "created", + "ordinal": 4, + "type_info": "Timestamp" + } + ], + "nullable": [ + false, + false, + false, + false, + false + ], + "parameters": { + "Left": [ + "Int8", + "Int8" + ] + } + }, + "query": "SELECT device.id \"id?\", name, wireguard_pubkey, user_id, created FROM device JOIN \"user\" ON device.user_id = \"user\".id WHERE device.id = $1 AND \"user\".id = $2" + }, "9ea6f3e288d0a23c2b020034c80e60c0c73bcc37705cf408ea14c65ec3d1dab8": { "describe": { "columns": [], @@ -2698,39 +2945,50 @@ }, "query": "UPDATE oauth2token SET access_token = $2, refresh_token = $3, expires_in = $4 WHERE access_token = $1" }, - "a85ff25c6803ab54c4a297fa946e2f469a9599d734163613c7ea7fa125c25148": { + "a38cb92e295e5cd6ee0237f95d6a838be2aff89d769f8c67c0fe3a9b53022697": { "describe": { "columns": [ { - "name": "collected_at: NaiveDateTime", + "name": "id?", "ordinal": 0, - "type_info": "Timestamp" + "type_info": "Int8" }, { - "name": "upload", + "name": "name", "ordinal": 1, - "type_info": "Int8" + "type_info": "Text" }, { - "name": "download", + "name": "wireguard_pubkey", "ordinal": 2, + "type_info": "Text" + }, + { + "name": "user_id", + "ordinal": 3, "type_info": "Int8" + }, + { + "name": "created", + "ordinal": 4, + "type_info": "Timestamp" } ], "nullable": [ - null, - null, - null + false, + false, + false, + false, + false ], "parameters": { "Left": [ "Text", - "Timestamp", "Int8" ] } }, - "query": "\n SELECT\n date_trunc($1, collected_at) \"collected_at: NaiveDateTime\",\n cast(sum(upload) AS bigint) upload, cast(sum(download) AS bigint) download\n FROM wireguard_peer_stats_view\n WHERE collected_at >= $2\n GROUP BY 1\n ORDER BY 1\n LIMIT $3\n " + "query": "SELECT d.id \"id?\", d.name, d.wireguard_pubkey, d.user_id, d.created FROM device d\n JOIN wireguard_network_device wnd\n ON d.id = wnd.device_id\n WHERE wnd.wireguard_ip = $1 AND wnd.wireguard_network_id = $2" }, "a8f720a41ab4509570490d444180ae58f20596491a3ac2be3ab00a8a19c78c58": { "describe": { @@ -3018,54 +3276,6 @@ }, "query": "SELECT id \"id?\", \"web3_enabled\", \"openid_enabled\", \"oauth_enabled\", \"ldap_enabled\", \"wireguard_enabled\", \"webhooks_enabled\", \"worker_enabled\", \"challenge_template\", \"instance_name\", \"main_logo_url\", \"nav_logo_url\" FROM \"settings\"" }, - "bb793a93f5810f6c1e6bfbada1b5d5d9ffab7c248d2b484ef471d67914a7fb72": { - "describe": { - "columns": [ - { - "name": "id?", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "name", - "ordinal": 1, - "type_info": "Text" - }, - { - "name": "wireguard_ip", - "ordinal": 2, - "type_info": "Text" - }, - { - "name": "wireguard_pubkey", - "ordinal": 3, - "type_info": "Text" - }, - { - "name": "user_id", - "ordinal": 4, - "type_info": "Int8" - }, - { - "name": "created", - "ordinal": 5, - "type_info": "Timestamp" - } - ], - "nullable": [ - false, - false, - false, - false, - false, - false - ], - "parameters": { - "Left": [] - } - }, - "query": "SELECT id \"id?\", \"name\", \"wireguard_ip\", \"wireguard_pubkey\", \"user_id\", \"created\" FROM \"device\"" - }, "bd814a4cae35fce9b8a8967e800c889cdfb836834beb17974e0ee115bb7654b7": { "describe": { "columns": [ @@ -3147,35 +3357,18 @@ false, false, false, - false, - false, - true, - true - ], - "parameters": { - "Left": [ - "Text" - ] - } - }, - "query": "SELECT id, user_id, state \"state: SessionState\", created, expires, webauthn_challenge, web3_challenge FROM session WHERE id = $1" - }, - "c6bce4888a517be6fa0d6c9dd21c681f60bc711dfb0c6f85529a4eef62e6c165": { - "describe": { - "columns": [], - "nullable": [], + false, + false, + true, + true + ], "parameters": { "Left": [ - "Int8", - "Text", - "Text", - "Text", - "Int8", - "Timestamp" + "Text" ] } }, - "query": "UPDATE \"device\" SET \"name\" = $2, \"wireguard_ip\" = $3, \"wireguard_pubkey\" = $4, \"user_id\" = $5, \"created\" = $6 WHERE id = $1" + "query": "SELECT id, user_id, state \"state: SessionState\", created, expires, webauthn_challenge, web3_challenge FROM session WHERE id = $1" }, "c851b4b167e29f757fbae6b1bc731aa733776496d05658cd8f1164554bd7539c": { "describe": { @@ -3349,55 +3542,21 @@ }, "query": "SELECT id \"id?\", username, password_hash, last_name, first_name, email, phone, ssh_key, pgp_key, pgp_cert_id, mfa_enabled, totp_enabled, totp_secret, mfa_method \"mfa_method: _\", recovery_codes FROM \"user\" WHERE username = $1" }, - "c8aa12003d91b6fc3fcd225bc260be4e51297101ebb0a02215245676cd708ab0": { + "cb43f45d5bf2d218fe219f44e3135d05f0a0113a1590fb501780593a26c840d9": { "describe": { - "columns": [ - { - "name": "id?", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "name", - "ordinal": 1, - "type_info": "Text" - }, - { - "name": "wireguard_ip", - "ordinal": 2, - "type_info": "Text" - }, - { - "name": "wireguard_pubkey", - "ordinal": 3, - "type_info": "Text" - }, - { - "name": "user_id", - "ordinal": 4, - "type_info": "Int8" - }, - { - "name": "created", - "ordinal": 5, - "type_info": "Timestamp" - } - ], - "nullable": [ - false, - false, - false, - false, - false, - false - ], + "columns": [], + "nullable": [], "parameters": { "Left": [ - "Text" + "Int8", + "Text", + "Text", + "Int8", + "Timestamp" ] } }, - "query": "SELECT device.id \"id?\", name, wireguard_ip, wireguard_pubkey, user_id, created FROM device JOIN \"user\" ON device.user_id = \"user\".id WHERE \"user\".username = $1" + "query": "UPDATE \"device\" SET \"name\" = $2, \"wireguard_pubkey\" = $3, \"user_id\" = $4, \"created\" = $5 WHERE id = $1" }, "cc4916bf8d6978021e9d9531c0f34fb71f41bb4a674d7080b983023316b5496f": { "describe": { @@ -3453,6 +3612,39 @@ }, "query": "SELECT id \"id?\", \"client_id\", \"client_secret\", \"redirect_uri\" \"redirect_uri: _\", \"scope\" \"scope: _\", \"name\", \"enabled\" FROM \"oauth2client\"" }, + "d4a4aa177810022c3b60c3d6c6cf83319aa258800d8d93c8804eaf2d0eb5d405": { + "describe": { + "columns": [ + { + "name": "device_id", + "ordinal": 0, + "type_info": "Int8" + }, + { + "name": "wireguard_network_id", + "ordinal": 1, + "type_info": "Int8" + }, + { + "name": "wireguard_ip", + "ordinal": 2, + "type_info": "Text" + } + ], + "nullable": [ + true, + true, + false + ], + "parameters": { + "Left": [ + "Int8", + "Int8" + ] + } + }, + "query": "SELECT * FROM\n wireguard_network_device\n WHERE device_id = $1 AND wireguard_network_id = $2" + }, "d98e365929bb0fbf3915b517db93168f76f9a0c4832cd2efd13d74268cc435b8": { "describe": { "columns": [], @@ -3729,56 +3921,26 @@ }, "query": "DELETE FROM \"user\" WHERE id = $1" }, - "e8bf23addc2761e39cd5215321d246e31199c48625e03762dda4a34c2930b6be": { + "e7e944f6bce4dce8cd58889dca8e38ceab97af014b51bfa24933e296e803effc": { "describe": { "columns": [ - { - "name": "id?", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "name", - "ordinal": 1, - "type_info": "Text" - }, { "name": "wireguard_ip", - "ordinal": 2, - "type_info": "Text" - }, - { - "name": "wireguard_pubkey", - "ordinal": 3, + "ordinal": 0, "type_info": "Text" - }, - { - "name": "user_id", - "ordinal": 4, - "type_info": "Int8" - }, - { - "name": "created", - "ordinal": 5, - "type_info": "Timestamp" } ], "nullable": [ - false, - false, - false, - false, - false, false ], "parameters": { "Left": [ "Int8", - "Text" + "Int8" ] } }, - "query": "SELECT device.id \"id?\", name, wireguard_ip, wireguard_pubkey, user_id, created FROM device JOIN \"user\" ON device.user_id = \"user\".id WHERE device.id = $1 AND \"user\".username = $2" + "query": "\n SELECT wireguard_ip\n FROM wireguard_network_device\n WHERE device_id = $1 AND wireguard_network_id = $2\n " }, "e99464b4da5a21bcffda16866783d11c819eb078e392f1492467ae420800242d": { "describe": { @@ -3800,6 +3962,20 @@ }, "query": "INSERT INTO \"group\" (\"name\") VALUES ($1) RETURNING id" }, + "ea89a1f46d3e94d611021a9eaccd2252a6bb7788ac44f2adb758c73f4476433d": { + "describe": { + "columns": [], + "nullable": [], + "parameters": { + "Left": [ + "Int8", + "Int8", + "Text" + ] + } + }, + "query": "INSERT INTO wireguard_network_device\n (device_id, wireguard_network_id, wireguard_ip)\n VALUES ($1, $2, $3)" + }, "eb00cea26638259fe12354abc085bbf893f10e62afb409fb0f198d33aadf1497": { "describe": { "columns": [ @@ -3845,48 +4021,33 @@ }, "query": "INSERT INTO \"user\" (\"username\", \"password_hash\", \"last_name\", \"first_name\", \"email\", \"phone\", \"ssh_key\", \"pgp_key\", \"pgp_cert_id\", \"mfa_enabled\", \"totp_enabled\", \"totp_secret\", \"mfa_method\", \"recovery_codes\") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14) RETURNING id" }, - "eee2734f98b411d6fc75bf92027d84b8ca5e41de023a473681c076d6cc072ab2": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [] - } - }, - "query": "DELETE FROM session WHERE expires < now()" - }, - "ef05db120b43f66cb1eebea856471ee8d81cdcf11af03472a10893ecedeeced3": { + "eb6dee5462657ac5ce0ecf31d1477ce7cc874d9ad8b3119977168f601b3e8072": { "describe": { "columns": [ { - "name": "oauth2authorizedapp_id", + "name": "id?", "ordinal": 0, "type_info": "Int8" }, { - "name": "access_token", + "name": "name", "ordinal": 1, "type_info": "Text" }, { - "name": "refresh_token", + "name": "wireguard_pubkey", "ordinal": 2, "type_info": "Text" }, { - "name": "redirect_uri", + "name": "user_id", "ordinal": 3, - "type_info": "Text" + "type_info": "Int8" }, { - "name": "scope", + "name": "created", "ordinal": 4, - "type_info": "Text" - }, - { - "name": "expires_in", - "ordinal": 5, - "type_info": "Int8" + "type_info": "Timestamp" } ], "nullable": [ @@ -3894,7 +4055,6 @@ false, false, false, - false, false ], "parameters": { @@ -3903,40 +4063,50 @@ ] } }, - "query": "SELECT oauth2authorizedapp_id, access_token, refresh_token, redirect_uri, scope, expires_in FROM oauth2token WHERE access_token = $1" + "query": "SELECT id \"id?\", name, wireguard_pubkey, user_id, created FROM device WHERE wireguard_pubkey = $1" + }, + "eee2734f98b411d6fc75bf92027d84b8ca5e41de023a473681c076d6cc072ab2": { + "describe": { + "columns": [], + "nullable": [], + "parameters": { + "Left": [] + } + }, + "query": "DELETE FROM session WHERE expires < now()" }, - "f444433840871aff81db51bbf1b615e64018be82154fd655509a365ca91d3e65": { + "ef05db120b43f66cb1eebea856471ee8d81cdcf11af03472a10893ecedeeced3": { "describe": { "columns": [ { - "name": "id?", + "name": "oauth2authorizedapp_id", "ordinal": 0, "type_info": "Int8" }, { - "name": "name", + "name": "access_token", "ordinal": 1, "type_info": "Text" }, { - "name": "wireguard_ip", + "name": "refresh_token", "ordinal": 2, "type_info": "Text" }, { - "name": "wireguard_pubkey", + "name": "redirect_uri", "ordinal": 3, "type_info": "Text" }, { - "name": "user_id", + "name": "scope", "ordinal": 4, - "type_info": "Int8" + "type_info": "Text" }, { - "name": "created", + "name": "expires_in", "ordinal": 5, - "type_info": "Timestamp" + "type_info": "Int8" } ], "nullable": [ @@ -3953,7 +4123,7 @@ ] } }, - "query": "SELECT id \"id?\", name, wireguard_ip, wireguard_pubkey, user_id, created FROM device WHERE wireguard_ip = $1" + "query": "SELECT oauth2authorizedapp_id, access_token, refresh_token, redirect_uri, scope, expires_in FROM oauth2token WHERE access_token = $1" }, "f5a52d311dd0ac4c76cf1638f30cffd8c97fe2b4987fcfb9f9ca523ab6e5bf5d": { "describe": { @@ -3986,67 +4156,43 @@ }, "query": "INSERT INTO oauth2token (oauth2authorizedapp_id, access_token, refresh_token, redirect_uri, scope, expires_in) VALUES ($1, $2, $3, $4, $5, $6)" }, - "fc3e288a55cef64d17ef2a373aa7fb46dd2548610a09ada4bf2daa8b98249901": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "DELETE FROM webauthn WHERE user_id = $1" - }, - "fd9c7f73acaec83bb9eb5aa48cf06760b775afd1253e6e5cef1b42d6ca04e04e": { + "f83b80fda6b7c7dd6c3493bbb80d8f6f5a8d5e86c5762b021196f32f4da9020c": { "describe": { "columns": [ { - "name": "id?", + "name": "pubkey", "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "name", - "ordinal": 1, - "type_info": "Text" - }, - { - "name": "wireguard_ip", - "ordinal": 2, - "type_info": "Text" - }, - { - "name": "wireguard_pubkey", - "ordinal": 3, "type_info": "Text" }, { - "name": "user_id", - "ordinal": 4, - "type_info": "Int8" - }, - { - "name": "created", - "ordinal": 5, - "type_info": "Timestamp" + "name": "allowed_ips!", + "ordinal": 1, + "type_info": "TextArray" } ], "nullable": [ false, - false, - false, - false, - false, - false + null ], "parameters": { "Left": [ - "Timestamp" + "Int8" + ] + } + }, + "query": "\n SELECT d.wireguard_pubkey as pubkey, array[wnd.wireguard_ip] as \"allowed_ips!\" FROM wireguard_network_device wnd\n JOIN device d\n ON wnd.device_id = d.id\n WHERE wireguard_network_id = $1\n " + }, + "fc3e288a55cef64d17ef2a373aa7fb46dd2548610a09ada4bf2daa8b98249901": { + "describe": { + "columns": [], + "nullable": [], + "parameters": { + "Left": [ + "Int8" ] } }, - "query": "\n WITH s AS (\n SELECT DISTINCT ON (device_id) *\n FROM wireguard_peer_stats\n ORDER BY device_id, latest_handshake DESC\n )\n SELECT\n d.id \"id?\", d.name, d.wireguard_ip, d.wireguard_pubkey, d.user_id, d.created\n FROM device d\n JOIN s ON d.id = s.device_id\n WHERE s.latest_handshake > $1\n " + "query": "DELETE FROM webauthn WHERE user_id = $1" }, "fdbd4d1e1b8634719de4ea543e51943e5d1d1c1ec63c62e22356d57ffa20ed02": { "describe": { @@ -4084,4 +4230,4 @@ }, "query": "SELECT id \"id?\", \"user_id\", \"name\", \"passkey\" FROM \"webauthn\"" } -} \ No newline at end of file +} diff --git a/src/db/mod.rs b/src/db/mod.rs index af0af2695..7559c1cb2 100644 --- a/src/db/mod.rs +++ b/src/db/mod.rs @@ -34,5 +34,5 @@ pub use models::{ webauthn::WebAuthn, webhook::{AppEvent, HWKeyUserData, WebHook}, wireguard::{GatewayEvent, WireguardNetwork, WireguardPeerStats}, - MFAInfo, UserInfo, + MFAInfo, UserDetails, UserInfo, }; diff --git a/src/db/models/device.rs b/src/db/models/device.rs index cfb004636..d6cc533c3 100644 --- a/src/db/models/device.rs +++ b/src/db/models/device.rs @@ -1,50 +1,263 @@ use super::{error::ModelError, wireguard::WireguardNetwork, DbPool}; +use crate::db::models::wireguard::WIREGUARD_MAX_HANDSHAKE_MINUTES; +use crate::handlers::wireguard::DeviceConfig; use chrono::{NaiveDateTime, Utc}; use ipnetwork::IpNetwork; use lazy_static::lazy_static; use model_derive::Model; use regex::Regex; -use sqlx::{query_as, Error as SqlxError}; +use sqlx::{query, query_as, Error as SqlxError, FromRow, Transaction}; +use std::fmt::{Display, Formatter}; +use thiserror::Error; #[derive(Clone, Deserialize, Model, Serialize, Debug)] pub struct Device { pub id: Option, pub name: String, - pub wireguard_ip: String, pub wireguard_pubkey: String, pub user_id: i64, pub created: NaiveDateTime, } -#[derive(Deserialize)] +impl Display for Device { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self.id { + Some(device_id) => write!(f, "[ID {}] {}", device_id, self.name), + None => write!(f, "{}", self.name), + } + } +} + +// helper struct which includes network configurations for a given device +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct DeviceInfo { + #[serde(flatten)] + pub device: Device, + pub network_info: Vec, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct DeviceNetworkInfo { + pub network_id: i64, + pub device_wireguard_ip: String, +} + +// helper struct which includes full device info +// including network activity metadata +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct UserDevice { + #[serde(flatten)] + pub device: Device, + pub networks: Vec, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct UserDeviceNetworkInfo { + pub network_id: i64, + pub network_name: String, + pub network_gateway_ip: String, + pub device_wireguard_ip: String, + pub last_connected_ip: Option, + pub last_connected_location: Option, + pub last_connected_at: Option, + pub is_active: bool, +} + +impl UserDevice { + pub async fn from_device(pool: &DbPool, device: Device) -> Result, SqlxError> { + if let Some(device_id) = device.id { + // fetch device config and connection info for all networks + let result = query!( + r#" + WITH stats AS ( + SELECT DISTINCT ON (network) network, endpoint, latest_handshake + FROM wireguard_peer_stats + ORDER BY network, collected_at DESC + ) + SELECT + n.id as network_id, n.name as network_name, n.endpoint as gateway_endpoint, + wnd.wireguard_ip as device_wireguard_ip, stats.endpoint as device_endpoint, + stats.latest_handshake as "latest_handshake?", + COALESCE (((NOW() - stats.latest_handshake) < $1 * interval '1 minute'), false) as "is_active!" + FROM wireguard_network_device wnd + JOIN wireguard_network n ON n.id = wnd.wireguard_network_id + LEFT JOIN stats on n.id = stats.network + WHERE wnd.device_id = $2 + "#, + WIREGUARD_MAX_HANDSHAKE_MINUTES as f64, + device_id, + ) + .fetch_all(pool) + .await?; + + let networks_info: Vec = result + .into_iter() + .map(|r| { + let device_ip = match r.device_endpoint { + Some(endpoint) => endpoint.split(':').next().map(|ip| ip.to_owned()), + None => None, + }; + UserDeviceNetworkInfo { + network_id: r.network_id, + network_name: r.network_name, + network_gateway_ip: r.gateway_endpoint, + device_wireguard_ip: r.device_wireguard_ip, + last_connected_ip: device_ip, + last_connected_location: None, + last_connected_at: r.latest_handshake, + is_active: r.is_active, + } + }) + .collect(); + return Ok(Some(Self { + device, + networks: networks_info, + })); + } + Ok(None) + } +} + +#[derive(Debug, Serialize, Deserialize, Clone, FromRow)] +pub struct WireguardNetworkDevice { + pub wireguard_network_id: Option, + pub wireguard_ip: String, + pub device_id: Option, +} + +#[derive(Deserialize, Debug)] pub struct AddDevice { pub name: String, pub wireguard_pubkey: String, } +#[derive(Deserialize, Debug)] +pub struct ModifyDevice { + pub name: String, + pub wireguard_pubkey: String, +} + +impl WireguardNetworkDevice { + pub fn new(network_id: i64, device_id: i64, wireguard_ip: String) -> Self { + Self { + wireguard_network_id: Some(network_id), + wireguard_ip, + device_id: Some(device_id), + } + } + + pub async fn insert<'e, E>(&self, executor: E) -> Result<(), SqlxError> + where + E: sqlx::Executor<'e, Database = sqlx::Postgres>, + { + query!( + "INSERT INTO wireguard_network_device + (device_id, wireguard_network_id, wireguard_ip) + VALUES ($1, $2, $3)", + self.device_id, + self.wireguard_network_id, + self.wireguard_ip + ) + .execute(executor) + .await?; + Ok(()) + } + + pub async fn update<'e, E>(&self, executor: E) -> Result<(), SqlxError> + where + E: sqlx::Executor<'e, Database = sqlx::Postgres>, + { + query!( + r#" + UPDATE wireguard_network_device + SET wireguard_ip = $3 + WHERE device_id = $1 AND wireguard_network_id = $2 + "#, + self.device_id, + self.wireguard_network_id, + self.wireguard_ip + ) + .execute(executor) + .await?; + Ok(()) + } + + pub async fn find<'e, E>( + executor: E, + device_id: i64, + network_id: i64, + ) -> Result, SqlxError> + where + E: sqlx::Executor<'e, Database = sqlx::Postgres>, + { + let res = query_as!( + Self, + "SELECT * FROM + wireguard_network_device + WHERE device_id = $1 AND wireguard_network_id = $2", + device_id, + network_id + ) + .fetch_optional(executor) + .await?; + Ok(res) + } + + pub async fn findy_by_device( + pool: &DbPool, + device_id: i64, + ) -> Result>, SqlxError> { + let result = query_as!( + Self, + "SELECT * + FROM wireguard_network_device WHERE device_id = $1", + device_id + ) + .fetch_all(pool) + .await?; + if !result.is_empty() { + return Ok(Some(result)); + } + Ok(None) + } +} + +#[derive(Error, Debug)] +pub enum DeviceError { + #[error("Device {0} pubkey is the same as gateway pubkey for network {1}")] + PubkeyConflict(Device, Box), + #[error("Database error")] + DatabaseError(#[from] sqlx::Error), + #[error("Model error")] + ModelError(#[from] ModelError), + #[error("Unexpected error: {0}")] + Unexpected(String), +} + impl Device { #[must_use] - pub fn new(name: String, wireguard_ip: String, wireguard_pubkey: String, user_id: i64) -> Self { + pub fn new(name: String, wireguard_pubkey: String, user_id: i64) -> Self { Self { id: None, name, - wireguard_ip, wireguard_pubkey, user_id, created: Utc::now().naive_utc(), } } - // FIXME: `other` should be a different struct - pub fn update_from(&mut self, other: Self) { + pub fn update_from(&mut self, other: ModifyDevice) { self.name = other.name; - self.wireguard_ip = other.wireguard_ip; self.wireguard_pubkey = other.wireguard_pubkey; } /// Create wireguard config for device #[must_use] - pub fn create_config(&self, network: WireguardNetwork) -> String { - let dns = match network.dns { + pub fn create_config( + &self, + network: &WireguardNetwork, + wireguard_network_device: &WireguardNetworkDevice, + ) -> String { + let dns = match &network.dns { Some(dns) => { if dns.is_empty() { String::new() @@ -52,7 +265,7 @@ impl Device { format!("DNS = {}", dns) } } - None => String::new(), + &None => String::new(), }; let allowed_ips = network .allowed_ips @@ -71,29 +284,48 @@ impl Device { AllowedIPs = {}\n\ Endpoint = {}:{}\n\ PersistentKeepalive = 300", - self.wireguard_ip, dns, network.pubkey, allowed_ips, network.endpoint, network.port, + wireguard_network_device.wireguard_ip, + dns, + network.pubkey, + allowed_ips, + network.endpoint, + network.port, ) } - pub async fn find_by_ip(pool: &DbPool, ip: &str) -> Result, SqlxError> { + pub async fn find_by_ip<'e, E>( + executor: E, + ip: &str, + network_id: i64, + ) -> Result, SqlxError> + where + E: sqlx::Executor<'e, Database = sqlx::Postgres>, + { query_as!( Self, - "SELECT id \"id?\", name, wireguard_ip, wireguard_pubkey, user_id, created \ - FROM device WHERE wireguard_ip = $1", - ip + "SELECT d.id \"id?\", d.name, d.wireguard_pubkey, d.user_id, d.created \ + FROM device d + JOIN wireguard_network_device wnd + ON d.id = wnd.device_id + WHERE wnd.wireguard_ip = $1 AND wnd.wireguard_network_id = $2", + ip, + network_id ) - .fetch_optional(pool) + .fetch_optional(executor) .await } - pub async fn find_by_pubkey(pool: &DbPool, pubkey: &str) -> Result, SqlxError> { + pub async fn find_by_pubkey<'e, E>(executor: E, pubkey: &str) -> Result, SqlxError> + where + E: sqlx::Executor<'e, Database = sqlx::Postgres>, + { query_as!( Self, - "SELECT id \"id?\", name, wireguard_ip, wireguard_pubkey, user_id, created \ + "SELECT id \"id?\", name, wireguard_pubkey, user_id, created \ FROM device WHERE wireguard_pubkey = $1", pubkey ) - .fetch_optional(pool) + .fetch_optional(executor) .await } @@ -104,7 +336,7 @@ impl Device { ) -> Result, SqlxError> { query_as!( Self, - "SELECT device.id \"id?\", name, wireguard_ip, wireguard_pubkey, user_id, created \ + "SELECT device.id \"id?\", name, wireguard_pubkey, user_id, created \ FROM device JOIN \"user\" ON device.user_id = \"user\".id \ WHERE device.id = $1 AND \"user\".username = $2", id, @@ -121,7 +353,7 @@ impl Device { ) -> Result, SqlxError> { query_as!( Self, - "SELECT device.id \"id?\", name, wireguard_ip, wireguard_pubkey, user_id, created \ + "SELECT device.id \"id?\", name, wireguard_pubkey, user_id, created \ FROM device JOIN \"user\" ON device.user_id = \"user\".id \ WHERE device.id = $1 AND \"user\".id = $2", id, @@ -131,10 +363,33 @@ impl Device { .await } + pub async fn get_ip( + &self, + pool: &DbPool, + network_id: i64, + ) -> Result, SqlxError> { + if let Some(device_id) = self.id { + let result = query!( + r#" + SELECT wireguard_ip + FROM wireguard_network_device + WHERE device_id = $1 AND wireguard_network_id = $2 + "#, + device_id, + network_id + ) + .fetch_one(pool) + .await?; + return Ok(Some(result.wireguard_ip)); + } + + Ok(None) + } + pub async fn all_for_username(pool: &DbPool, username: &str) -> Result, SqlxError> { query_as!( Self, - "SELECT device.id \"id?\", name, wireguard_ip, wireguard_pubkey, user_id, created \ + "SELECT device.id \"id?\", name, wireguard_pubkey, user_id, created \ FROM device JOIN \"user\" ON device.user_id = \"user\".id \ WHERE \"user\".username = $1", username @@ -142,14 +397,83 @@ impl Device { .fetch_all(pool) .await } - /// Assign available ip address to device - pub async fn assign_device_ip( - pool: &DbPool, - user_id: i64, - name: String, - pubkey: String, + + // Add device to all existing networks + pub async fn add_to_all_networks( + &self, + transaction: &mut Transaction<'_, sqlx::Postgres>, + ) -> Result<(Vec, Vec), DeviceError> { + info!("Adding device {} to all existing networks", self.name); + let networks = WireguardNetwork::all(&mut *transaction).await?; + + let mut configs = Vec::new(); + let mut network_info = Vec::new(); + for network in networks { + debug!( + "Assigning IP for device {} (user {}) in network {}", + self.name, self.user_id, network + ); + // check for pubkey conflicts with networks + if network.pubkey == self.wireguard_pubkey { + return Err(DeviceError::PubkeyConflict(self.clone(), Box::new(network))); + } + + let network_id = match network.id { + Some(id) => id, + None => return Err(DeviceError::Unexpected("Network has no ID".to_string())), + }; + + if WireguardNetworkDevice::find( + &mut *transaction, + self.id.expect("Device has no ID"), + network_id, + ) + .await? + .is_some() + { + debug!( + "Device {} already has an IP within network {}. Skipping...", + self, network + ); + continue; + } + + let wireguard_network_device = self + .assign_network_ip(&mut *transaction, &network, &Vec::new()) + .await?; + debug!( + "Assigned IP {} for device {} (user {}) in network {}", + wireguard_network_device.wireguard_ip, self.name, self.user_id, network + ); + let device_network_info = DeviceNetworkInfo { + network_id, + device_wireguard_ip: wireguard_network_device.wireguard_ip.clone(), + }; + network_info.push(device_network_info); + + let config = self.create_config(&network, &wireguard_network_device); + configs.push(DeviceConfig { + network_id, + network_name: network.name, + config, + }); + } + Ok((network_info, configs)) + } + + // Assign IP to the device in a given network + pub async fn assign_network_ip( + &self, + transaction: &mut Transaction<'_, sqlx::Postgres>, network: &WireguardNetwork, - ) -> Result { + reserved_ips: &[String], + ) -> Result { + let network_id = match network.id { + Some(id) => id, + None => { + return Err(ModelError::CannotCreate); + } + }; let net_ip = network.address.ip(); let net_network = network.address.network(); let net_broadcast = network.address.broadcast(); @@ -157,13 +481,19 @@ impl Device { if ip == net_ip || ip == net_network || ip == net_broadcast { continue; } - // Break loop if IP is unassigned and return device - match Self::find_by_ip(pool, &ip.to_string()).await? { + if reserved_ips.contains(&ip.to_string()) { + continue; + } + + // Break loop if IP is unassigned and return network device + match Self::find_by_ip(&mut *transaction, &ip.to_string(), network_id).await? { Some(_) => (), None => { - info!("Created IP: {} for device: {}", ip, name); - let device = Self::new(name, ip.to_string(), pubkey, user_id); - return Ok(device); + info!("Created IP: {} for device: {}", ip, self.name); + let wireguard_network_device = + WireguardNetworkDevice::new(network_id, self.id.unwrap(), ip.to_string()); + wireguard_network_device.insert(&mut *transaction).await?; + return Ok(wireguard_network_device); } } } @@ -188,10 +518,59 @@ mod test { use crate::db::User; use claims::{assert_err, assert_ok}; + impl Device { + /// Create new device and assign IP in a given network + pub async fn new_with_ip( + pool: &DbPool, + user_id: i64, + name: String, + pubkey: String, + network: &WireguardNetwork, + ) -> Result<(Self, WireguardNetworkDevice), ModelError> { + let network_id = match network.id { + Some(id) => id, + None => { + return Err(ModelError::CannotCreate); + } + }; + let net_ip = network.address.ip(); + let net_network = network.address.network(); + let net_broadcast = network.address.broadcast(); + for ip in network.address.iter() { + if ip == net_ip || ip == net_network || ip == net_broadcast { + continue; + } + // Break loop if IP is unassigned and return device + match Self::find_by_ip(pool, &ip.to_string(), network_id).await? { + Some(_) => (), + None => { + let mut device = Self::new(name.clone(), pubkey, user_id); + device.save(pool).await?; + info!("Created device: {}", device.name); + debug!("For user: {}", device.user_id); + let wireguard_network_device = WireguardNetworkDevice::new( + network_id, + device.id.unwrap(), + ip.to_string(), + ); + wireguard_network_device.insert(pool).await?; + info!( + "Assigned IP: {} for device: {} in network: {}", + ip, name, network_id + ); + return Ok((device, wireguard_network_device)); + } + } + } + Err(ModelError::CannotCreate) + } + } + #[sqlx::test] async fn test_assign_device_ip(pool: DbPool) { let mut network = WireguardNetwork::default(); network.try_set_address("10.1.1.1/30").unwrap(); + network.save(&pool).await.unwrap(); let mut user = User::new( "testuser".to_string(), @@ -202,7 +581,7 @@ mod test { None, ); user.save(&pool).await.unwrap(); - let mut device = Device::assign_device_ip( + let (_device, wireguard_network_device) = Device::new_with_ip( &pool, user.id.unwrap(), "dev1".into(), @@ -211,11 +590,9 @@ mod test { ) .await .unwrap(); - assert_eq!(device.wireguard_ip, "10.1.1.2"); - device.save(&pool).await.unwrap(); + assert_eq!(wireguard_network_device.wireguard_ip, "10.1.1.2"); - let device = - Device::assign_device_ip(&pool, 1, "dev4".into(), "key4".into(), &network).await; + let device = Device::new_with_ip(&pool, 1, "dev4".into(), "key4".into(), &network).await; assert!(device.is_err()); } diff --git a/src/db/models/error.rs b/src/db/models/error.rs index 654459a35..d4dd531b8 100644 --- a/src/db/models/error.rs +++ b/src/db/models/error.rs @@ -2,6 +2,7 @@ use std::{error, fmt}; #[derive(Debug)] pub enum ModelError { + CannotModify, CannotCreate, NetworkTooSmall, SqlxError(sqlx::Error), @@ -13,6 +14,7 @@ impl error::Error for ModelError {} impl fmt::Display for ModelError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { + Self::CannotModify => write!(f, "Cannot modify model"), Self::CannotCreate => write!(f, "Cannot create model"), Self::NetworkTooSmall => write!(f, "Network address will not fit existing devices"), Self::SqlxError(error) => { diff --git a/src/db/models/mod.rs b/src/db/models/mod.rs index 563ec3929..1ea84f7cb 100644 --- a/src/db/models/mod.rs +++ b/src/db/models/mod.rs @@ -18,7 +18,7 @@ pub mod webhook; pub mod wireguard; use super::{DbPool, Group}; -use device::Device; +use crate::db::models::device::UserDevice; use sqlx::{query_as, Error as SqlxError}; use user::{MFAMethod, User}; @@ -53,6 +53,7 @@ pub struct SecurityKey { pub name: String, } +// Basic user info used in user list, etc. #[derive(Deserialize, Serialize, Debug)] pub struct UserInfo { pub id: Option, @@ -67,41 +68,29 @@ pub struct UserInfo { pub mfa_enabled: bool, pub totp_enabled: bool, pub groups: Vec, - #[serde(default)] - pub devices: Vec, - #[serde(default)] - pub wallets: Vec, - #[serde(default)] - pub security_keys: Vec, pub mfa_method: MFAMethod, pub authorized_apps: Vec, } impl UserInfo { - pub async fn from_user(pool: &DbPool, user: User) -> Result { + pub async fn from_user(pool: &DbPool, user: &User) -> Result { let groups = user.member_of(pool).await?; - let devices = user.devices(pool).await?; - let wallets = user.wallets(pool).await?; let authorized_apps = user.oauth2authorizedapps(pool).await?; - let security_keys = user.security_keys(pool).await?; Ok(Self { id: user.id, - username: user.username, - last_name: user.last_name, - first_name: user.first_name, - email: user.email, - phone: user.phone, - ssh_key: user.ssh_key, - pgp_key: user.pgp_key, - pgp_cert_id: user.pgp_cert_id, + username: user.username.clone(), + last_name: user.last_name.clone(), + first_name: user.first_name.clone(), + email: user.email.clone(), + phone: user.phone.clone(), + ssh_key: user.ssh_key.clone(), + pgp_key: user.pgp_key.clone(), + pgp_cert_id: user.pgp_cert_id.clone(), mfa_enabled: user.mfa_enabled, totp_enabled: user.totp_enabled, groups, - devices, - wallets, - security_keys, - mfa_method: user.mfa_method, + mfa_method: user.mfa_method.clone(), authorized_apps, }) } @@ -173,6 +162,34 @@ impl UserInfo { } } +// Full user info with related objects +#[derive(Deserialize, Serialize, Debug)] +pub struct UserDetails { + #[serde(flatten)] + pub user: UserInfo, + #[serde(default)] + pub devices: Vec, + #[serde(default)] + pub wallets: Vec, + #[serde(default)] + pub security_keys: Vec, +} + +impl UserDetails { + pub async fn from_user(pool: &DbPool, user: &User) -> Result { + let devices = user.devices(pool).await?; + let wallets = user.wallets(pool).await?; + let security_keys = user.security_keys(pool).await?; + + Ok(Self { + user: UserInfo::from_user(pool, user).await?, + devices, + wallets, + security_keys, + }) + } +} + #[derive(Deserialize, Serialize)] pub struct MFAInfo { mfa_method: MFAMethod, @@ -252,7 +269,7 @@ mod test { user.add_to_group(&pool, &group1).await.unwrap(); user.add_to_group(&pool, &group2).await.unwrap(); - let mut user_info = UserInfo::from_user(&pool, user).await.unwrap(); + let mut user_info = UserInfo::from_user(&pool, &user).await.unwrap(); assert_eq!(user_info.groups, ["Gryffindor", "Hufflepuff"]); user_info.groups = vec!["Gryffindor".into(), "Ravenclaw".into()]; diff --git a/src/db/models/user.rs b/src/db/models/user.rs index fe2595919..b25879799 100644 --- a/src/db/models/user.rs +++ b/src/db/models/user.rs @@ -1,6 +1,7 @@ use super::{ device::Device, group::Group, MFAInfo, OAuth2AuthorizedAppInfo, SecurityKey, WalletInfo, }; +use crate::db::models::device::UserDevice; use crate::{ auth::TOTP_CODE_VALIDITY_PERIOD, db::{Wallet, WebAuthn}, @@ -25,7 +26,7 @@ use std::time::SystemTime; const RECOVERY_CODES_COUNT: usize = 8; -#[derive(Deserialize, Serialize, PartialEq, Type, Debug)] +#[derive(Clone, Deserialize, Serialize, PartialEq, Type, Debug)] #[sqlx(type_name = "mfa_method", rename_all = "snake_case")] pub enum MFAMethod { None, @@ -387,16 +388,26 @@ impl User { } } - pub async fn devices(&self, pool: &DbPool) -> Result, SqlxError> { + pub async fn devices(&self, pool: &DbPool) -> Result, SqlxError> { if let Some(id) = self.id { - query_as!( + let devices = query_as!( Device, - "SELECT device.id \"id?\", name, wireguard_ip, wireguard_pubkey, user_id, created \ - FROM device WHERE user_id = $1", + r#" + SELECT device.id "id?", name, wireguard_pubkey, user_id, created + FROM device WHERE user_id = $1 + "#, id ) .fetch_all(pool) - .await + .await?; + + let mut user_devices = Vec::new(); + for device in devices { + if let Some(user_device) = UserDevice::from_device(pool, device).await? { + user_devices.push(user_device); + } + } + Ok(user_devices) } else { Ok(Vec::new()) } diff --git a/src/db/models/wireguard.rs b/src/db/models/wireguard.rs index 7c95d6737..2765172eb 100644 --- a/src/db/models/wireguard.rs +++ b/src/db/models/wireguard.rs @@ -1,10 +1,17 @@ -use super::{device::Device, error::ModelError, DbPool, User, UserInfo}; +use super::{ + device::{Device, WireguardNetworkDevice}, + error::ModelError, + DbPool, User, UserInfo, +}; +use crate::db::models::device::DeviceInfo; +use crate::grpc::GatewayState; use base64::Engine; use chrono::{Duration, NaiveDateTime, Utc}; use ipnetwork::{IpNetwork, IpNetworkError, NetworkSize}; use model_derive::Model; use rand_core::OsRng; -use sqlx::{query_as, query_scalar, Error as SqlxError, FromRow}; +use sqlx::{query_as, query_scalar, Error as SqlxError, FromRow, Transaction}; +use std::fmt::{Display, Formatter}; use std::{ collections::HashMap, fmt::Debug, @@ -34,11 +41,11 @@ impl DateTimeAggregation { #[derive(Clone, Debug)] pub enum GatewayEvent { - NetworkCreated(WireguardNetwork), - NetworkModified(WireguardNetwork), - NetworkDeleted(String), - DeviceCreated(Device), - DeviceModified(Device), + NetworkCreated(i64, WireguardNetwork), + NetworkModified(i64, WireguardNetwork), + NetworkDeleted(i64, String), + DeviceCreated(DeviceInfo), + DeviceModified(DeviceInfo), DeviceDeleted(String), } @@ -66,6 +73,15 @@ pub struct WireguardKey { pub public: String, } +impl Display for WireguardNetwork { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self.id { + Some(network_id) => write!(f, "[ID {}] {}", network_id, self.name), + None => write!(f, "{}", self.name), + } + } +} + impl WireguardNetwork { pub fn new( name: String, @@ -92,10 +108,12 @@ impl WireguardNetwork { } /// Return number of devices that use this network. - async fn device_count(&self, pool: &DbPool) -> Result { - // FIXME: currently there is only one hard-coded network with id = 1. - query_scalar!("SELECT count(*) \"count!\" FROM device") - .fetch_one(pool) + async fn device_count( + &self, + transaction: &mut Transaction<'_, sqlx::Postgres>, + ) -> Result { + query_scalar!("SELECT count(*) \"count!\" FROM wireguard_network_device WHERE wireguard_network_id = $1", self.id) + .fetch_one(transaction) .await } @@ -121,16 +139,26 @@ impl WireguardNetwork { /// Try to change network address, changing device addresses if necessary. pub async fn change_address( &mut self, - pool: &DbPool, + transaction: &mut Transaction<'_, sqlx::Postgres>, new_address: IpNetwork, ) -> Result<(), ModelError> { + info!( + "Changing network address for {} from {} to {}", + self, self.address, new_address + ); + let network_id = match self.id { + Some(id) => id, + None => { + return Err(ModelError::CannotModify); + } + }; let old_address = self.address; // check if new network size will fit all existing devices let new_size = new_address.size(); if new_size < old_address.size() { // include address, network, and broadcast in the calculation - let count = self.device_count(pool).await? + 3; + let count = self.device_count(transaction).await? + 3; match new_size { NetworkSize::V4(size) => { if count as u32 > size { @@ -147,27 +175,32 @@ impl WireguardNetwork { // re-address all devices if new_address.network() != old_address.network() { - let transaction = pool.begin().await?; - - let mut devices = Device::all(pool).await?; + info!("Re-addressing devices in network {}", self); + let mut devices = Device::all(&mut *transaction).await?; let net_ip = new_address.ip(); let net_network = new_address.network(); let net_broadcast = new_address.broadcast(); let mut devices_iter = devices.iter_mut(); + for ip in new_address.iter() { if ip == net_ip || ip == net_network || ip == net_broadcast { continue; } match devices_iter.next() { Some(device) => { - device.wireguard_ip = ip.to_string(); - device.save(pool).await?; + let device_id = match device.id { + Some(id) => id, + None => { + return Err(ModelError::CannotModify); + } + }; + let wireguard_network_device = + WireguardNetworkDevice::new(network_id, device_id, ip.to_string()); + wireguard_network_device.update(&mut *transaction).await?; } None => break, } } - - transaction.commit().await?; } self.address = new_address; @@ -297,6 +330,7 @@ impl WireguardNetwork { /// Retrieves network stats grouped by currently active users since `from` timestamp pub async fn user_stats( + &self, conn: &DbPool, from: &NaiveDateTime, aggregation: &DateTimeAggregation, @@ -314,7 +348,7 @@ impl WireguardNetwork { ORDER BY device_id, latest_handshake DESC ) SELECT - d.id "id?", d.name, d.wireguard_ip, d.wireguard_pubkey, d.user_id, d.created + d.id "id?", d.name, d.wireguard_pubkey, d.user_id, d.created FROM device d JOIN s ON d.id = s.device_id WHERE s.latest_handshake > $1 @@ -335,7 +369,7 @@ impl WireguardNetwork { .await? .ok_or(SqlxError::RowNotFound)?; stats.push(WireguardUserStatsRow { - user: UserInfo::from_user(conn, user).await?, + user: UserInfo::from_user(conn, &user).await?, devices: u.1.clone(), }); } @@ -344,6 +378,7 @@ impl WireguardNetwork { /// Retrieves total active users/devices since `from` timestamp async fn total_activity( + &self, conn: &DbPool, from: &NaiveDateTime, ) -> Result { @@ -356,16 +391,21 @@ impl WireguardNetwork { FROM "user" u JOIN device d ON d.user_id = u.id JOIN wireguard_peer_stats s ON s.device_id = d.id - WHERE latest_handshake >= $1 + WHERE latest_handshake >= $1 AND s.network = $2 "#, from, + self.id, ) .fetch_one(conn) .await?; Ok(activity_stats) } - /// Retrievies currently connected users - async fn current_activity(conn: &DbPool) -> Result { + + /// Retrieves currently connected users + async fn current_activity( + &self, + conn: &DbPool, + ) -> Result { // Add 2 minutes margin because gateway sends stats in 1 minute period let from = Utc::now() .naive_utc() @@ -379,9 +419,10 @@ impl WireguardNetwork { FROM "user" u JOIN device d ON d.user_id = u.id JOIN wireguard_peer_stats s ON s.device_id = d.id - WHERE latest_handshake >= $1 + WHERE latest_handshake >= $1 AND s.network = $2 "#, from, + self.id ) .fetch_one(conn) .await?; @@ -391,6 +432,7 @@ impl WireguardNetwork { /// Retrieves network upload & download time series since `from` timestamp /// using `aggregation` (hour/minute) aggregation level async fn transfer_series( + &self, conn: &DbPool, from: &NaiveDateTime, aggregation: &DateTimeAggregation, @@ -402,13 +444,14 @@ impl WireguardNetwork { date_trunc($1, collected_at) "collected_at: NaiveDateTime", cast(sum(upload) AS bigint) upload, cast(sum(download) AS bigint) download FROM wireguard_peer_stats_view - WHERE collected_at >= $2 + WHERE collected_at >= $2 AND network = $3 GROUP BY 1 ORDER BY 1 - LIMIT $3 + LIMIT $4 "#, aggregation.fstring(), from, + self.id, PEER_STATS_LIMIT, ) .fetch_all(conn) @@ -418,13 +461,14 @@ impl WireguardNetwork { /// Retrieves network stats pub async fn network_stats( + &self, conn: &DbPool, from: &NaiveDateTime, aggregation: &DateTimeAggregation, ) -> Result { - let total_activity = Self::total_activity(conn, from).await?; - let current_activity = Self::current_activity(conn).await?; - let transfer_series = Self::transfer_series(conn, from, aggregation).await?; + let total_activity = self.total_activity(conn, from).await?; + let current_activity = self.current_activity(conn).await?; + let transfer_series = self.transfer_series(conn, from, aggregation).await?; Ok(WireguardNetworkStats { current_active_users: current_activity.active_users, current_active_devices: current_activity.active_devices, @@ -455,6 +499,14 @@ impl Default for WireguardNetwork { } } +#[derive(Serialize, Clone, Debug)] +pub struct WireguardNetworkInfo { + #[serde(flatten)] + pub network: WireguardNetwork, + pub connected: bool, + pub gateways: Vec, +} + #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] pub struct WireguardStatsRow { pub collected_at: Option, @@ -527,6 +579,8 @@ pub struct WireguardNetworkStats { mod test { use chrono::{Duration, SubsecRound}; + use crate::db::models::device::WireguardNetworkDevice; + use super::*; async fn add_devices(pool: &DbPool, network: &WireguardNetwork, count: usize) { @@ -540,7 +594,7 @@ mod test { ); user.save(pool).await.unwrap(); for i in 0..count { - let mut device = Device::assign_device_ip( + Device::new_with_ip( pool, user.id.unwrap(), format!("dev{i}"), @@ -549,7 +603,6 @@ mod test { ) .await .unwrap(); - device.save(pool).await.unwrap(); } } @@ -557,46 +610,48 @@ mod test { async fn test_change_address(pool: DbPool) { let mut network = WireguardNetwork::default(); network.try_set_address("10.1.1.1/29").unwrap(); + network.save(&pool).await.unwrap(); add_devices(&pool, &network, 3).await; + let mut transaction = pool.begin().await.unwrap(); network - .change_address(&pool, "10.2.2.2/28".parse().unwrap()) + .change_address(&mut transaction, "10.2.2.2/28".parse().unwrap()) .await .unwrap(); - - let dev0 = Device::find_by_pubkey(&pool, "key0") - .await - .unwrap() - .unwrap(); - assert_eq!(dev0.wireguard_ip, "10.2.2.1"); - - let dev1 = Device::find_by_pubkey(&pool, "key1") - .await - .unwrap() - .unwrap(); - assert_eq!(dev1.wireguard_ip, "10.2.2.3"); - - let dev2 = Device::find_by_pubkey(&pool, "key2") - .await - .unwrap() - .unwrap(); - assert_eq!(dev2.wireguard_ip, "10.2.2.4"); + let keys = vec!["key0", "key1", "key2"]; + let ips = vec!["10.2.2.1", "10.2.2.3", "10.2.2.4"]; + transaction.commit().await.unwrap(); + + for (index, pub_key) in keys.iter().enumerate() { + let device = Device::find_by_pubkey(&pool, pub_key) + .await + .unwrap() + .unwrap(); + let wireguard_network_device = + WireguardNetworkDevice::find(&pool, device.id.unwrap(), network.id.unwrap()) + .await + .unwrap() + .unwrap(); + assert_eq!(wireguard_network_device.wireguard_ip, ips[index]) + } } #[sqlx::test] async fn test_change_address_wont_fit(pool: DbPool) { let mut network = WireguardNetwork::default(); network.try_set_address("10.1.1.1/29").unwrap(); + network.save(&pool).await.unwrap(); add_devices(&pool, &network, 3).await; + let mut transaction = pool.begin().await.unwrap(); assert!(network - .change_address(&pool, "10.2.2.2/30".parse().unwrap()) + .change_address(&mut transaction, "10.2.2.2/30".parse().unwrap()) .await .is_err()); assert!(network - .change_address(&pool, "10.2.2.2/29".parse().unwrap()) + .change_address(&mut transaction, "10.2.2.2/29".parse().unwrap()) .await .is_ok()); } @@ -612,12 +667,7 @@ mod test { None, ); user.save(&pool).await.unwrap(); - let mut device = Device::new( - String::new(), - String::new(), - String::new(), - user.id.unwrap(), - ); + let mut device = Device::new(String::new(), String::new(), user.id.unwrap()); device.save(&pool).await.unwrap(); // insert stats @@ -662,12 +712,7 @@ mod test { None, ); user.save(&pool).await.unwrap(); - let mut device = Device::new( - String::new(), - String::new(), - String::new(), - user.id.unwrap(), - ); + let mut device = Device::new(String::new(), String::new(), user.id.unwrap()); device.save(&pool).await.unwrap(); // insert stats diff --git a/src/error.rs b/src/error.rs index 2203849df..f8b0a1a95 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,5 +1,7 @@ use crate::auth::failed_login::FailedLoginError; +use crate::db::models::device::DeviceError; use crate::{db::models::error::ModelError, ldap::error::OriLDAPError}; +use rocket::http::Status; use sqlx::error::Error as SqlxError; use thiserror::Error; @@ -26,7 +28,7 @@ pub enum OriWebError { DbError(String), #[error("Model error: {0}")] ModelError(String), - #[error("{0}")] + #[error("Public key invalid {0}")] PubkeyValidation(String), #[error("HTTP error: {0}")] Http(rocket::http::Status), @@ -66,3 +68,14 @@ impl From for OriWebError { Self::ModelError(error.to_string()) } } + +impl From for OriWebError { + fn from(error: DeviceError) -> Self { + match error { + DeviceError::PubkeyConflict(..) => Self::PubkeyValidation(format!("{}", error)), + DeviceError::DatabaseError(_) => Self::DbError(format!("{}", error)), + DeviceError::ModelError(_) => Self::ModelError(format!("{}", error)), + DeviceError::Unexpected(_) => Self::Http(Status::InternalServerError), + } + } +} diff --git a/src/grpc/gateway.rs b/src/grpc/gateway.rs index 17de7dbe4..d60a70c11 100644 --- a/src/grpc/gateway.rs +++ b/src/grpc/gateway.rs @@ -6,6 +6,7 @@ use crate::{ grpc::GatewayMap, }; use chrono::{NaiveDateTime, Utc}; +use sqlx::{query_as, Error as SqlxError}; use std::{ net::SocketAddr, pin::Pin, @@ -14,13 +15,13 @@ use std::{ }; use tokio::{ sync::{ - broadcast::Sender, + broadcast::{Receiver as BroadcastReceiver, Sender}, mpsc::{self, Receiver}, }, task::JoinHandle, }; use tokio_stream::Stream; -use tonic::{Request, Response, Status}; +use tonic::{metadata::MetadataMap, Code, Request, Response, Status}; tonic::include_proto!("gateway"); @@ -30,6 +31,27 @@ pub struct GatewayServer { wireguard_tx: Sender, } +impl WireguardNetwork { + /// Get a list of all peers + pub async fn get_peers(&self, pool: &DbPool) -> Result, SqlxError> { + debug!("Fetching all peers for network {}", self.id.unwrap()); + let result = query_as!( + Peer, + r#" + SELECT d.wireguard_pubkey as pubkey, array[wnd.wireguard_ip] as "allowed_ips!" FROM wireguard_network_device wnd + JOIN device d + ON wnd.device_id = d.id + WHERE wireguard_network_id = $1 + "#, + self.id + ) + .fetch_all(pool) + .await?; + + Ok(result) + } +} + impl GatewayServer { /// Create new gateway server instance #[must_use] @@ -44,13 +66,179 @@ impl GatewayServer { wireguard_tx, } } + + fn get_network_id(metadata: &MetadataMap) -> Result { + match Self::get_network_id_from_metadata(metadata) { + Some(m) => Ok(m), + None => Err(Status::new( + Code::Internal, + "Network ID was not found in metadata", + )), + } + } + + // parse network id from gateway request metadata from intercepted information from JWT token + fn get_network_id_from_metadata(metadata: &MetadataMap) -> Option { + if let Some(ascii_value) = metadata.get("gateway_network_id") { + if let Ok(slice) = ascii_value.clone().to_str() { + if let Ok(id) = slice.parse::() { + return Some(id); + } + } + } + None + } +} + +fn gen_config(network: &WireguardNetwork, peers: Vec) -> Configuration { + Configuration { + name: network.name.clone(), + port: network.port as u32, + prvkey: network.prvkey.clone(), + address: network.address.to_string(), + peers, + } +} + +impl WireguardPeerStats { + fn from_peer_stats(stats: PeerStats, network_id: i64) -> Self { + let endpoint = match stats.endpoint { + endpoint if endpoint.is_empty() => None, + _ => Some(stats.endpoint), + }; + Self { + id: None, + network: network_id, + endpoint, + device_id: -1, + collected_at: Utc::now().naive_utc(), + upload: stats.upload, + download: stats.download, + latest_handshake: NaiveDateTime::from_timestamp_opt(stats.latest_handshake, 0) + .unwrap_or_default(), + allowed_ips: Some(stats.allowed_ips), + } + } +} + +/// Helper struct for handling gateway events +struct GatewayUpdatesHandler { + network: WireguardNetwork, + gateway_address: SocketAddr, + events_rx: BroadcastReceiver, + tx: mpsc::Sender>, +} + +impl GatewayUpdatesHandler { + pub fn new( + network: WireguardNetwork, + gateway_address: SocketAddr, + events_rx: BroadcastReceiver, + tx: mpsc::Sender>, + ) -> Self { + Self { + network, + gateway_address, + events_rx, + tx, + } + } + + /// Process incoming gateway events + /// + /// Main gRPC server uses a shared channel for broadcasting all gateway events + /// so the handler must determine if an event is relevant for the network being services + pub async fn run(&mut self) { + info!( + "Starting update stream to gateway: {}, network {}", + self.gateway_address, self.network + ); + while let Ok(update) = self.events_rx.recv().await { + let result = match update { + GatewayEvent::NetworkCreated(network_id, network) => { + if Some(network_id) == self.network.id { + self.send_network_update(&network, 0).await + } else { + Ok(()) + } + } + GatewayEvent::NetworkModified(network_id, network) => { + if Some(network_id) == self.network.id { + self.send_network_update(&network, 1).await + } else { + Ok(()) + } + } + GatewayEvent::NetworkDeleted(network_id, network_name) => { + if Some(network_id) == self.network.id { + self.send_network_delete(&network_name).await + } else { + Ok(()) + } + } + GatewayEvent::DeviceCreated(device) => { + // check if a peer has to be added in the current network + match device + .network_info + .iter() + .find(|info| Some(info.network_id) == self.network.id) + { + Some(network_info) => { + self.send_peer_update( + Peer { + pubkey: device.device.wireguard_pubkey, + allowed_ips: vec![network_info.device_wireguard_ip.clone()], + }, + 0, + ) + .await + } + None => Ok(()), + } + } + GatewayEvent::DeviceModified(device) => { + // check if a peer has to be updated in the current network + match device + .network_info + .iter() + .find(|info| Some(info.network_id) == self.network.id) + { + Some(network_info) => { + self.send_peer_update( + Peer { + pubkey: device.device.wireguard_pubkey, + allowed_ips: vec![network_info.device_wireguard_ip.clone()], + }, + 1, + ) + .await + } + None => Ok(()), + } + } + GatewayEvent::DeviceDeleted(device_pub_key) => { + self.send_peer_delete(&device_pub_key).await + } + }; + if result.is_err() { + error!( + "Closing update steam to gateway: {}, network {}", + self.gateway_address, self.network + ); + break; + } + } + } + /// Sends updated network configuration async fn send_network_update( - tx: &mpsc::Sender>, + &self, network: &WireguardNetwork, update_type: i32, ) -> Result<(), Status> { - if let Err(err) = tx + debug!("Sending network update for network {}", network); + if let Err(err) = self + .tx .send(Ok(Update { update_type, update: Some(update::Update::Network(Configuration { @@ -65,19 +253,22 @@ impl GatewayServer { { let msg = format!( "Failed to send network update, network {}, update type: {}, error: {}", - network.name, update_type, err, + network, update_type, err, ); error!("{}", msg); return Err(Status::new(tonic::Code::Internal, msg)); } Ok(()) } + /// Sends delete network command to gateway - async fn send_network_delete( - tx: &mpsc::Sender>, - network_name: &str, - ) -> Result<(), Status> { - if let Err(err) = tx + async fn send_network_delete(&self, network_name: &str) -> Result<(), Status> { + debug!( + "Sending network delete command for network {}", + self.network + ); + if let Err(err) = self + .tx .send(Ok(Update { update_type: 2, update: Some(update::Update::Network(Configuration { @@ -92,44 +283,40 @@ impl GatewayServer { { let msg = format!( "Failed to send network update, network {}, update type: {}, error: {}", - network_name, 2, err, + self.network, 2, err, ); error!("{}", msg); return Err(Status::new(tonic::Code::Internal, msg)); } Ok(()) } + /// Send update peer command to gateway - async fn send_peer_update( - tx: &mpsc::Sender>, - device: &Device, - update_type: i32, - ) -> Result<(), Status> { - if let Err(err) = tx + async fn send_peer_update(&self, peer: Peer, update_type: i32) -> Result<(), Status> { + debug!("Sending peer update for network {}", self.network); + if let Err(err) = self + .tx .send(Ok(Update { update_type, - update: Some(update::Update::Peer(Peer { - pubkey: device.wireguard_pubkey.clone(), - allowed_ips: vec![device.wireguard_ip.clone()], - })), + update: Some(update::Update::Peer(peer)), })) .await { let msg = format!( - "Failed to send network update, device {}, update type: {}, error: {}", - device.name, update_type, err, + "Failed to send peer update for network {}, update type: {}, error: {}", + self.network, update_type, err, ); error!("{}", msg); return Err(Status::new(tonic::Code::Internal, msg)); } Ok(()) } + /// Send delete peer command to gateway - async fn send_peer_delete( - tx: &mpsc::Sender>, - peer_pubkey: &str, - ) -> Result<(), Status> { - if let Err(err) = tx + async fn send_peer_delete(&self, peer_pubkey: &str) -> Result<(), Status> { + debug!("Sending peer delete for network {}", self.network); + if let Err(err) = self + .tx .send(Ok(Update { update_type: 2, update: Some(update::Update::Peer(Peer { @@ -140,8 +327,8 @@ impl GatewayServer { .await { let msg = format!( - "Failed to send peer update, peer {}, update type: 2, error: {}", - peer_pubkey, err, + "Failed to send peer update for network {}, peer {}, update type: 2, error: {}", + self.network, peer_pubkey, err, ); error!("{}", msg); return Err(Status::new(tonic::Code::Internal, msg)); @@ -150,49 +337,10 @@ impl GatewayServer { } } -fn gen_config(network: &WireguardNetwork, devices: &[Device]) -> Configuration { - let peers = devices - .iter() - .map(|d| Peer { - pubkey: d.wireguard_pubkey.clone(), - allowed_ips: vec![d.wireguard_ip.clone()], - }) - .collect(); - - Configuration { - name: network.name.clone(), - port: network.port as u32, - prvkey: network.prvkey.clone(), - address: network.address.to_string(), - peers, - } -} - -impl From for WireguardPeerStats { - fn from(stats: PeerStats) -> Self { - let endpoint = match stats.endpoint { - endpoint if endpoint.is_empty() => None, - _ => Some(stats.endpoint), - }; - Self { - id: None, - // FIXME: hard-coded network id - network: 1, - endpoint, - device_id: -1, - collected_at: Utc::now().naive_utc(), - upload: stats.upload, - download: stats.download, - latest_handshake: NaiveDateTime::from_timestamp_opt(stats.latest_handshake, 0) - .unwrap_or_default(), - allowed_ips: Some(stats.allowed_ips), - } - } -} - pub struct GatewayUpdatesStream { task_handle: JoinHandle<()>, rx: Receiver>, + network_id: i64, gateway_addr: SocketAddr, gateway_state: Arc>, } @@ -202,12 +350,14 @@ impl GatewayUpdatesStream { pub fn new( task_handle: JoinHandle<()>, rx: Receiver>, + network_id: i64, gateway_addr: SocketAddr, gateway_state: Arc>, ) -> Self { Self { task_handle, rx, + network_id, gateway_addr, gateway_state, } @@ -225,28 +375,33 @@ impl Stream for GatewayUpdatesStream { impl Drop for GatewayUpdatesStream { fn drop(&mut self) { info!("Client disconnected"); + // terminate update task + self.task_handle.abort(); + // update gateway state self.gateway_state .lock() .unwrap() - .disconnect_gateway(self.gateway_addr); - // terminate update task - self.task_handle.abort(); + .disconnect_gateway(self.network_id, self.gateway_addr) + .expect("Unable to disconnect gateway."); } } #[tonic::async_trait] impl gateway_service_server::GatewayService for GatewayServer { type UpdatesStream = GatewayUpdatesStream; + /// Retrieve stats from gateway and save it to database async fn stats( &self, request: Request>, ) -> Result, Status> { + let network_id = Self::get_network_id(request.metadata())?; let mut stream = request.into_inner(); while let Some(peer_stats) = stream.message().await? { let public_key = peer_stats.public_key.clone(); - let mut stats = WireguardPeerStats::from(peer_stats); + let mut stats = WireguardPeerStats::from_peer_stats(peer_stats, network_id); // Get device by public key and fill in stats.device_id + // FIXME: keep an in-memory device map to avoid repeated DB requests stats.device_id = match Device::find_by_pubkey(&self.pool, &public_key).await { Ok(Some(device)) => device .id @@ -280,72 +435,84 @@ impl gateway_service_server::GatewayService for GatewayServer { format!("Saving WireGuard peer stats to db failed: {}", err), )); } - debug!("Saved WireGuard peer stats to db: {:?}", stats); + info!("Saved WireGuard peer stats to db: {:?}", stats); } Ok(Response::new(())) } - async fn config(&self, _request: Request<()>) -> Result, Status> { - info!("Sending configuration to gateway client."); + async fn config(&self, request: Request<()>) -> Result, Status> { + debug!("Sending configuration to gateway client."); + let network_id = Self::get_network_id(request.metadata())?; + let pool = self.pool.clone(); - let mut network = WireguardNetwork::find_by_id(&pool, 1) + let mut network = WireguardNetwork::find_by_id(&pool, network_id) .await .map_err(|e| { + error!("Network {} not found", network_id); Status::new( - tonic::Code::FailedPrecondition, + tonic::Code::Internal, format!("Failed to retrieve network: {}", e), ) })? - .ok_or_else(|| Status::new(tonic::Code::FailedPrecondition, "Network not found"))?; + .ok_or_else(|| Status::new(tonic::Code::Internal, "Network not found"))?; + + info!( + "Sending configuration to gateway client, network {}.", + network + ); + network.connected_at = Some(Utc::now().naive_utc()); if let Err(err) = network.save(&pool).await { - error!("Failed to save network: {}", err); + error!("Failed to update network {} status: {}", network_id, err); } - let devices = Device::all(&pool).await.unwrap_or_default(); - Ok(Response::new(gen_config(&network, &devices))) + + let peers = network.get_peers(&pool).await.map_err(|_| { + error!("Failed to fetch peers for network {}", network_id); + Status::new( + tonic::Code::Internal, + format!("Failed to retrieve peers for network: {}", network_id), + ) + })?; + + Ok(Response::new(gen_config(&network, peers))) } async fn updates(&self, request: Request<()>) -> Result, Status> { + let gateway_network_id = Self::get_network_id(request.metadata())?; let address = request.remote_addr().expect("Unable to get peer address."); - info!("New client connected to updates stream: {}", address); - let (tx, rx) = mpsc::channel(4); - let mut events_rx = self.wireguard_tx.subscribe(); + let network = match WireguardNetwork::find_by_id(&self.pool, gateway_network_id) + .await + .map_err(|_| { + error!("Failed to fetch network {}", gateway_network_id); + Status::new( + tonic::Code::Internal, + format!("Failed to retrieve network {}", gateway_network_id), + ) + })? { + Some(network) => network, + None => return Err(Status::new(Code::Internal, "Network not found")), + }; + + info!( + "New client connected to updates stream: {}, network {}", + address, network + ); + + let (tx, rx) = mpsc::channel(4); + let events_rx = self.wireguard_tx.subscribe(); let mut state = self.state.lock().unwrap(); - state.connect_gateway(address); + state.connect_gateway(gateway_network_id, address); let handle = tokio::spawn(async move { - info!("Starting update stream to gateway: {}", address); - while let Ok(update) = events_rx.recv().await { - let result = match update { - GatewayEvent::NetworkCreated(network) => { - Self::send_network_update(&tx, &network, 0).await - } - GatewayEvent::NetworkModified(network) => { - Self::send_network_update(&tx, &network, 1).await - } - GatewayEvent::NetworkDeleted(network_name) => { - Self::send_network_delete(&tx, &network_name).await - } - GatewayEvent::DeviceCreated(device) => { - Self::send_peer_update(&tx, &device, 0).await - } - GatewayEvent::DeviceModified(device) => { - Self::send_peer_update(&tx, &device, 1).await - } - GatewayEvent::DeviceDeleted(device_name) => { - Self::send_peer_delete(&tx, &device_name).await - } - }; - if result.is_err() { - error!("Closing update steam to gateway: {}", address); - break; - } - } + let mut update_handler = GatewayUpdatesHandler::new(network, address, events_rx, tx); + update_handler.run().await }); + Ok(Response::new(GatewayUpdatesStream::new( handle, rx, + gateway_network_id, address, Arc::clone(&self.state), ))) diff --git a/src/grpc/interceptor.rs b/src/grpc/interceptor.rs index a5a44663d..349b3085f 100644 --- a/src/grpc/interceptor.rs +++ b/src/grpc/interceptor.rs @@ -24,8 +24,20 @@ impl Interceptor for JwtInterceptor { None => return Err(Status::unauthenticated("Missing authorization header")), }; if let Ok(claims) = Claims::from_jwt(self.claims_type.clone(), token) { + let request_metadata = req.metadata_mut(); + + if let ClaimsType::Gateway = self.claims_type { + request_metadata.insert( + "gateway_network_id", + claims + .client_id + .parse() + .map_err(|_| Status::unknown("Network ID parsing error"))?, + ); + } + // FIXME: can we push whole Claims object into metadata? - req.metadata_mut().insert( + request_metadata.insert( "username", claims .sub diff --git a/src/grpc/mod.rs b/src/grpc/mod.rs index 15a028a07..283438e57 100644 --- a/src/grpc/mod.rs +++ b/src/grpc/mod.rs @@ -22,6 +22,7 @@ use crate::auth::failed_login::FailedLoginMap; use crate::db::AppEvent; use serde::Serialize; use std::{collections::hash_map::HashMap, time::Instant}; +use thiserror::Error; use tokio::sync::broadcast::Sender; mod auth; @@ -32,7 +33,16 @@ mod interceptor; #[cfg(feature = "worker")] pub mod worker; -pub struct GatewayMap(HashMap); +// Helper struct used to handle gateway state +// gateways are grouped by network +type NetworkId = i64; +pub struct GatewayMap(HashMap>); + +#[derive(Error, Debug)] +pub enum GatewayMapError { + #[error("Gateway {1} for network {0} not found")] + NotFound(i64, SocketAddr), +} impl GatewayMap { #[must_use] @@ -40,24 +50,73 @@ impl GatewayMap { Self(HashMap::new()) } - pub fn connect_gateway(&mut self, address: SocketAddr) { - match self.0.get_mut(&address) { + pub fn connect_gateway(&mut self, network_id: i64, address: SocketAddr) { + match self.0.get_mut(&network_id) { + Some(network_gateway_map) => match network_gateway_map.get_mut(&address) { + Some(state) => { + state.connected = true; + } + None => { + network_gateway_map.insert( + address, + GatewayState { + connected: true, + network_id, + name: None, + ip: address.ip(), + }, + ); + } + }, + // no map for a given network exists yet None => { - self.0.insert(address, GatewayState::new()); + let mut network_gateway_map = HashMap::new(); + network_gateway_map.insert( + address, + GatewayState { + connected: true, + network_id, + name: None, + ip: address.ip(), + }, + ); + self.0.insert(network_id, network_gateway_map); } - Some(state) => state.connected = true, - }; + } } - pub fn disconnect_gateway(&mut self, address: SocketAddr) { - if let Some(state) = self.0.get_mut(&address) { - state.connected = false + pub fn disconnect_gateway( + &mut self, + network_id: i64, + address: SocketAddr, + ) -> Result<(), GatewayMapError> { + if let Some(network_gateway_map) = self.0.get_mut(&network_id) { + if let Some(state) = network_gateway_map.get_mut(&address) { + state.connected = false; + return Ok(()); + }; }; + let err = GatewayMapError::NotFound(network_id, address); + error!("Gateway disconnect failed: {}", err); + Err(err) } - // return `true` if at least one gateway is connected - pub fn connected(&self) -> bool { - self.0.values().any(|gateway| gateway.connected) + // return `true` if at least one gateway in a given network is connected + pub fn connected(&self, network_id: i64) -> bool { + match self.0.get(&network_id) { + Some(network_gateway_map) => network_gateway_map + .values() + .any(|gateway| gateway.connected), + None => false, + } + } + + // return a list af aff statuses af all gateways in a given network + pub fn get_network_gateway_status(&self, network_id: i64) -> Vec { + match self.0.get(&network_id) { + Some(network_gateway_map) => network_gateway_map.clone().into_values().collect(), + None => Vec::new(), + } } } @@ -67,20 +126,23 @@ impl Default for GatewayMap { } } +#[derive(Serialize, Clone, Debug)] pub struct GatewayState { pub connected: bool, + pub network_id: i64, + pub name: Option, + pub ip: IpAddr, } impl GatewayState { #[must_use] - pub fn new() -> Self { - Self { connected: true } - } -} - -impl Default for GatewayState { - fn default() -> Self { - Self::new() + pub fn new(network_id: i64, address: SocketAddr) -> Self { + Self { + connected: true, + network_id, + name: None, + ip: address.ip(), + } } } diff --git a/src/handlers/auth.rs b/src/handlers/auth.rs index a0466e30f..b7d8a9979 100644 --- a/src/handlers/auth.rs +++ b/src/handlers/auth.rs @@ -106,7 +106,7 @@ pub async fn authenticate( Err(OriWebError::DbError("MFA info read error".into())) } } else { - let user_info = UserInfo::from_user(&appstate.pool, user).await?; + let user_info = UserInfo::from_user(&appstate.pool, &user).await?; if let Some(openid_cookie) = cookies.get_private("known_sign_in") { debug!("Found openid session cookie."); Ok(ApiResponse { @@ -322,7 +322,7 @@ pub async fn webauthn_end( .set_state(&appstate.pool, SessionState::MultiFactorVerified) .await?; return if let Some(user) = User::find_by_id(&appstate.pool, session.user_id).await? { - let user_info = UserInfo::from_user(&appstate.pool, user).await?; + let user_info = UserInfo::from_user(&appstate.pool, &user).await?; if let Some(openid_cookie) = cookies.get_private("known_sign_in") { debug!("Found openid session cookie."); Ok(ApiResponse { @@ -415,7 +415,7 @@ pub async fn totp_code( session .set_state(&appstate.pool, SessionState::MultiFactorVerified) .await?; - let user_info = UserInfo::from_user(&appstate.pool, user).await?; + let user_info = UserInfo::from_user(&appstate.pool, &user).await?; info!("Verified TOTP for user {}", username); if let Some(openid_cookie) = cookies.get_private("known_sign_in") { debug!("Found openid session cookie."); @@ -493,7 +493,7 @@ pub async fn web3auth_end( User::find_by_id(&appstate.pool, session.user_id).await? { let username = user.username.clone(); - let user_info = UserInfo::from_user(&appstate.pool, user).await?; + let user_info = UserInfo::from_user(&appstate.pool, &user).await?; info!( "User {} authenticated with wallet {}", username, signature.address @@ -546,7 +546,7 @@ pub async fn recovery_code( session .set_state(&appstate.pool, SessionState::MultiFactorVerified) .await?; - let user_info = UserInfo::from_user(&appstate.pool, user).await?; + let user_info = UserInfo::from_user(&appstate.pool, &user).await?; info!("Authenticated user {} with recovery code", username); if let Some(openid_cookie) = cookies.get_private("known_sign_in") { debug!("Found openid session cookie."); diff --git a/src/handlers/user.rs b/src/handlers/user.rs index 112f17320..8771c4fe5 100644 --- a/src/handlers/user.rs +++ b/src/handlers/user.rs @@ -5,7 +5,10 @@ use super::{ use crate::{ appstate::AppState, auth::{AdminRole, SessionInfo}, - db::{AppEvent, MFAMethod, OAuth2AuthorizedApp, Settings, User, UserInfo, Wallet, WebAuthn}, + db::{ + AppEvent, MFAMethod, OAuth2AuthorizedApp, Settings, User, UserDetails, UserInfo, Wallet, + WebAuthn, + }, error::OriWebError, ldap::utils::{ldap_add_user, ldap_change_password, ldap_delete_user, ldap_modify_user}, license::Features, @@ -76,7 +79,7 @@ pub async fn list_users(_admin: AdminRole, appstate: &State) -> ApiRes let all_users = User::all(&appstate.pool).await?; let mut users: Vec = Vec::with_capacity(all_users.len()); for user in all_users { - users.push(UserInfo::from_user(&appstate.pool, user).await?); + users.push(UserInfo::from_user(&appstate.pool, &user).await?); } Ok(ApiResponse { json: json!(users), @@ -91,7 +94,7 @@ pub async fn get_user( username: &str, ) -> ApiResult { let user = user_for_admin_or_self(&appstate.pool, &session, username).await?; - let user_info = UserInfo::from_user(&appstate.pool, user).await?; + let user_info = UserDetails::from_user(&appstate.pool, &user).await?; Ok(ApiResponse { json: json!(user_info), status: Status::Ok, @@ -134,7 +137,7 @@ pub async fn add_user( if appstate.license.validate(&Features::Ldap) { let _result = ldap_add_user(&appstate.config, &user, &user_data.password).await; }; - let user_info = UserInfo::from_user(&appstate.pool, user).await?; + let user_info = UserInfo::from_user(&appstate.pool, &user).await?; appstate.trigger_action(AppEvent::UserCreated(user_info)); info!("User {} added user {}", session.user.username, username); Ok(ApiResponse { @@ -211,7 +214,7 @@ pub async fn modify_user( if appstate.license.validate(&Features::Ldap) { let _result = ldap_modify_user(&appstate.config, username, &user).await; }; - let user_info = UserInfo::from_user(&appstate.pool, user).await?; + let user_info = UserInfo::from_user(&appstate.pool, &user).await?; appstate.trigger_action(AppEvent::UserModified(user_info)); info!("User {} updated user {}", session.user.username, username); Ok(ApiResponse::default()) @@ -498,7 +501,7 @@ pub async fn delete_security_key( #[get("/me", format = "json")] pub async fn me(session: SessionInfo, appstate: &State) -> ApiResult { - let user_info = UserInfo::from_user(&appstate.pool, session.user).await?; + let user_info = UserInfo::from_user(&appstate.pool, &session.user).await?; Ok(ApiResponse { json: json!(user_info), status: Status::Ok, diff --git a/src/handlers/wireguard.rs b/src/handlers/wireguard.rs index 0bff236dd..909af1276 100644 --- a/src/handlers/wireguard.rs +++ b/src/handlers/wireguard.rs @@ -1,17 +1,23 @@ use super::{ device_for_admin_or_self, user_for_admin_or_self, ApiResponse, ApiResult, OriWebError, }; +use crate::db::models::device::{DeviceInfo, DeviceNetworkInfo}; +use crate::db::models::wireguard::WireguardNetworkInfo; +use crate::grpc::GatewayMap; use crate::{ appstate::AppState, auth::{AdminRole, Claims, ClaimsType, SessionInfo}, db::{ - models::wireguard::DateTimeAggregation, AddDevice, DbPool, Device, GatewayEvent, - WireguardNetwork, + models::{ + device::{ModifyDevice, WireguardNetworkDevice}, + wireguard::DateTimeAggregation, + }, + AddDevice, DbPool, Device, GatewayEvent, WireguardNetwork, }, - grpc::GatewayMap, - wg_config::parse_wireguard_config, + wg_config::{parse_wireguard_config, ImportedDevice}, }; use chrono::{DateTime, Duration, NaiveDateTime, Utc}; +use ethers::utils::__serde_json::Value; use ipnetwork::IpNetwork; use rocket::{ http::Status, @@ -21,10 +27,8 @@ use rocket::{ }, State, }; -use std::{ - str::FromStr, - sync::{Arc, Mutex}, -}; +use std::str::FromStr; +use std::sync::{Arc, Mutex}; #[derive(Deserialize, Serialize)] pub struct WireguardNetworkData { @@ -46,9 +50,19 @@ impl WireguardNetworkData { } } -#[derive(Serialize, Deserialize)] -pub struct UserDevices { - pub devices: Vec, +// Used in process of importing network from wireguard config +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct MappedDevice { + pub user_id: i64, + pub name: String, + pub wireguard_pubkey: String, + pub wireguard_ip: String, +} + +// Used in process of importing network from wireguard config +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct MappedDevices { + pub devices: Vec, } #[derive(Serialize)] @@ -66,7 +80,7 @@ pub struct ImportNetworkData { #[derive(Serialize, Deserialize)] pub struct ImportedNetworkData { pub network: WireguardNetwork, - pub devices: Vec, + pub devices: Vec, } #[post("/", format = "json", data = "")] @@ -92,8 +106,35 @@ pub async fn create_network( allowed_ips, ) .map_err(|_| OriWebError::Serialization("Invalid network address".into()))?; - network.save(&appstate.pool).await?; - appstate.send_wireguard_event(GatewayEvent::NetworkCreated(network.clone())); + + let mut transaction = appstate.pool.begin().await?; + network.save(&mut transaction).await?; + + // generate IP addresses for existing devices + info!("Assigning IPs for existing devices in network {}", network); + let devices = Device::all(&mut transaction).await?; + for device in devices { + device + .assign_network_ip(&mut transaction, &network, &Vec::new()) + .await?; + } + + match &network.id { + Some(network_id) => { + appstate + .send_wireguard_event(GatewayEvent::NetworkCreated(*network_id, network.clone())); + } + None => { + error!("Network {} ID was not created during network creation, gateway event was not send!", &network.name); + return Ok(ApiResponse { + json: json!({}), + status: Status::InternalServerError, + }); + } + } + + transaction.commit().await?; + info!( "User {} created WireGuard network {}", session.user.username, network_name @@ -126,12 +167,28 @@ pub async fn modify_network( let data = data.into_inner(); network.allowed_ips = data.parse_allowed_ips(); network.name = data.name; - network.change_address(&appstate.pool, data.address).await?; + + let mut transaction = appstate.pool.begin().await?; + network + .change_address(&mut transaction, data.address) + .await?; network.endpoint = data.endpoint; network.port = data.port; network.dns = data.dns; - network.save(&appstate.pool).await?; - appstate.send_wireguard_event(GatewayEvent::NetworkModified(network.clone())); + network.save(&mut transaction).await?; + match &network.id { + Some(network_id) => { + appstate + .send_wireguard_event(GatewayEvent::NetworkModified(*network_id, network.clone())); + } + &None => { + error!( + "Network {} id not found, gateway update not send!", + network.name + ); + } + } + transaction.commit().await?; info!( "User {} updated WireGuard network {}", session.user.username, id @@ -156,7 +213,7 @@ pub async fn delete_network( let network = find_network(id, &appstate.pool).await?; let network_name = network.name.clone(); network.delete(&appstate.pool).await?; - appstate.send_wireguard_event(GatewayEvent::NetworkDeleted(network_name)); + appstate.send_wireguard_event(GatewayEvent::NetworkDeleted(id, network_name)); info!( "User {} deleted WireGuard network {}", session.user.username, id @@ -165,13 +222,30 @@ pub async fn delete_network( } #[get("/", format = "json")] -pub async fn list_networks(_admin: AdminRole, appstate: &State) -> ApiResult { +pub async fn list_networks( + _admin: AdminRole, + appstate: &State, + gateway_state: &State>>, +) -> ApiResult { debug!("Listing WireGuard networks"); + let mut network_info = Vec::new(); let networks = WireguardNetwork::all(&appstate.pool).await?; - info!("Listed WireGuard networks"); + // get gateway status for networks + let gateway_state = gateway_state + .lock() + .expect("Failed to acquire gateway state lock"); + for network in networks { + let network_id = network.id.expect("Network does not have an ID"); + network_info.push(WireguardNetworkInfo { + network, + connected: gateway_state.connected(network_id), + gateways: gateway_state.get_network_gateway_status(network_id), + }) + } + debug!("Listed WireGuard networks"); Ok(ApiResponse { - json: json!(networks), + json: json!(network_info), status: Status::Ok, }) } @@ -181,13 +255,48 @@ pub async fn network_details( network_id: i64, _admin: AdminRole, appstate: &State, + gateway_state: &State>>, ) -> ApiResult { debug!("Displaying network details for network {}", network_id); let network = WireguardNetwork::find_by_id(&appstate.pool, network_id).await?; - info!("Displayed network details for network {}", network_id); + let response = match network { + Some(network) => { + let gateway_state = gateway_state + .lock() + .expect("Failed to acquire gateway state lock"); + let network_info = WireguardNetworkInfo { + network, + connected: gateway_state.connected(network_id), + gateways: gateway_state.get_network_gateway_status(network_id), + }; + ApiResponse { + json: json!(network_info), + status: Status::Ok, + } + } + None => ApiResponse { + json: Value::Null, + status: Status::NotFound, + }, + }; + debug!("Displayed network details for network {}", network_id); + + Ok(response) +} + +#[get("//gateways", format = "json")] +pub async fn gateway_status( + network_id: i64, + _admin: AdminRole, + gateway_state: &State>>, +) -> ApiResult { + debug!("Displaying gateway status for network {}", network_id); + let gateway_state = gateway_state + .lock() + .expect("Failed to acquire gateway state lock"); Ok(ApiResponse { - json: json!(network), + json: json!(gateway_state.get_network_gateway_status(network_id)), status: Status::Ok, }) } @@ -198,52 +307,170 @@ pub async fn import_network( appstate: &State, data: Json, ) -> ApiResult { + info!("Importing network from config file"); let data = data.into_inner(); - let (mut network, devices) = parse_wireguard_config(&data.config) + let (mut network, imported_devices) = parse_wireguard_config(&data.config) .map_err(|_| OriWebError::Http(Status::UnprocessableEntity))?; network.name = data.name; network.endpoint = data.endpoint; - network.save(&appstate.pool).await?; - appstate.send_wireguard_event(GatewayEvent::NetworkCreated(network.clone())); + + let mut transaction = appstate.pool.begin().await?; + network.save(&mut transaction).await?; + info!("New network {} created", network); + match network.id { + Some(network_id) => { + appstate + .send_wireguard_event(GatewayEvent::NetworkCreated(network_id, network.clone())); + } + None => { + error!("Network {} id not found, gateway event not sent!", network); + } + } + + // check if any of the imported devices exist already + // if they do assign imported IP and remove from response + let network_id = network.id.expect("Network ID is missing"); + let mut devices = Vec::new(); + let mut assigned_device_ids = Vec::new(); + let reserved_ips: Vec = imported_devices + .iter() + .map(|dev| dev.wireguard_ip.clone()) + .collect(); + for imported_device in imported_devices { + match Device::find_by_pubkey(&mut transaction, &imported_device.wireguard_pubkey).await? { + Some(existing_device) => { + info!( + "Device with pubkey {} exists already, assigning IP for new network: {}", + existing_device.wireguard_pubkey, imported_device.wireguard_ip + ); + let wireguard_network_device = WireguardNetworkDevice::new( + network_id, + existing_device.id.expect("Device ID is missing"), + imported_device.wireguard_ip, + ); + wireguard_network_device.insert(&mut transaction).await?; + // store ID of device with already generated config + assigned_device_ids.push(existing_device.id); + // send device to connected gateways + appstate.send_wireguard_event(GatewayEvent::DeviceModified(DeviceInfo { + device: existing_device, + network_info: vec![DeviceNetworkInfo { + network_id, + device_wireguard_ip: wireguard_network_device.wireguard_ip, + }], + })); + } + None => devices.push(imported_device), + } + } + // assign IPs for other existing devices + info!("Assigning IPs in imported network for remaining existing devices"); + let existing_devices = Device::all(&mut transaction).await?; + for device in existing_devices { + // skip if IP was already assigned based on imported config + if assigned_device_ids.contains(&device.id) { + continue; + } + let wireguard_network_device = device + .assign_network_ip(&mut transaction, &network, &reserved_ips) + .await?; + appstate.send_wireguard_event(GatewayEvent::DeviceModified(DeviceInfo { + device, + network_info: vec![DeviceNetworkInfo { + network_id, + device_wireguard_ip: wireguard_network_device.wireguard_ip, + }], + })); + } + + transaction.commit().await?; + Ok(ApiResponse { json: json!(ImportedNetworkData { network, devices }), status: Status::Created, }) } -#[post("/devices", format = "json", data = "")] +// This is used exclusively during wizard for mapping imported devices to users +#[post("//devices", format = "json", data = "")] pub async fn add_user_devices( _admin: AdminRole, session: SessionInfo, appstate: &State, - data: Json, + data: Json, + network_id: i64, ) -> ApiResult { - let mut data = data.into_inner(); + let request_data = data.into_inner(); + let mapped_devices = request_data.devices.clone(); let user = session.user; - let device_count = data.devices.len(); - debug!("User {} adding {} devices", user.username, device_count); + let device_count = mapped_devices.len(); + if mapped_devices.is_empty() { + return Ok(ApiResponse { + json: json!({}), + status: Status::BadRequest, + }); + } + + info!( + "User {} mapping {} devices for network {}", + user.username, device_count, network_id + ); // wrap loop in transaction to abort if a device is invalid let mut transaction = appstate.pool.begin().await?; - for device in data.devices.as_mut_slice() { - Device::validate_pubkey(&device.wireguard_pubkey).map_err(OriWebError::PubkeyValidation)?; + for mapped_device in &mapped_devices { + debug!("Mapping device {}", mapped_device.name); + Device::validate_pubkey(&mapped_device.wireguard_pubkey) + .map_err(OriWebError::PubkeyValidation)?; + let mut device = Device::new( + mapped_device.name.clone(), + mapped_device.wireguard_pubkey.clone(), + mapped_device.user_id, + ); device.save(&mut transaction).await?; - } - transaction.commit().await?; + debug!("Saved new device {}", device); + + // assign IP in imported network + let wireguard_network_device = WireguardNetworkDevice::new( + network_id, + device.id.expect("Device ID is missing"), + mapped_device.wireguard_ip.clone(), + ); + wireguard_network_device.insert(&mut transaction).await?; + + let (mut network_info, _configs) = device.add_to_all_networks(&mut transaction).await?; + + network_info.push(DeviceNetworkInfo { + network_id, + device_wireguard_ip: wireguard_network_device.wireguard_ip.clone(), + }); - // send gRPC event after DB transaction succeeds - for device in data.devices.as_mut_slice() { - appstate.send_wireguard_event(GatewayEvent::DeviceCreated(device.clone())); + // send device to connected gateways + appstate.send_wireguard_event(GatewayEvent::DeviceCreated(DeviceInfo { + device, + network_info, + })); } + transaction.commit().await?; - info!("User {} added {} devices", user.username, device_count); + info!( + "User {} mapped {} devices for {} network", + user.username, device_count, network_id + ); Ok(ApiResponse { - json: json!(data), + json: json!({}), status: Status::Created, }) } +#[derive(Serialize)] +pub struct DeviceConfig { + pub(crate) network_id: i64, + pub(crate) network_name: String, + pub(crate) config: String, +} + #[post("/device/", format = "json", data = "")] pub async fn add_device( session: SessionInfo, @@ -257,99 +484,159 @@ pub async fn add_device( session.user.username, device_name, username ); let user = user_for_admin_or_self(&appstate.pool, &session, username).await?; - // FIXME: hard-coded network id - if let Ok(Some(network)) = WireguardNetwork::find_by_id(&appstate.pool, 1).await { - Device::validate_pubkey(&data.wireguard_pubkey).map_err(OriWebError::PubkeyValidation)?; - if network.pubkey == data.wireguard_pubkey { - return Ok(ApiResponse { - json: json!({"msg": "device's pubkey must be different from server's pubkey"}), - status: Status::BadRequest, - }); - } - - let add_device = data.into_inner(); - let mut device = Device::assign_device_ip( - &appstate.pool, - user.id.unwrap(), - add_device.name, - add_device.wireguard_pubkey, - &network, - ) - .await?; - device.save(&appstate.pool).await?; - appstate.send_wireguard_event(GatewayEvent::DeviceCreated(device.clone())); - info!( - "User {} added device {} for user {}", - session.user.username, device_name, username - ); - let config = device.create_config(network); - Ok(ApiResponse { - json: json!(config), - status: Status::Created, - }) - } else { + let networks = WireguardNetwork::all(&appstate.pool).await?; + if networks.is_empty() { error!("No network found, can't add device"); - Ok(ApiResponse { + return Ok(ApiResponse { json: json!({}), status: Status::BadRequest, - }) + }); + } + + Device::validate_pubkey(&data.wireguard_pubkey).map_err(OriWebError::PubkeyValidation)?; + + // save device + let add_device = data.into_inner(); + let user_id = match user.id { + Some(id) => id, + None => { + return Err(OriWebError::ModelError("User has no id".to_string())); + } + }; + let mut device = Device::new(add_device.name, add_device.wireguard_pubkey, user_id); + + let mut transaction = appstate.pool.begin().await?; + device.save(&mut transaction).await?; + + // assign IPs and generate configs for each network + #[derive(Serialize)] + struct AddDeviceResult { + configs: Vec, + device: Device, } + + let (network_info, configs) = device.add_to_all_networks(&mut transaction).await?; + + appstate.send_wireguard_event(GatewayEvent::DeviceCreated(DeviceInfo { + device: device.clone(), + network_info, + })); + + transaction.commit().await?; + + info!( + "User {} added device {} for user {}", + session.user.username, device_name, username + ); + + let result = AddDeviceResult { device, configs }; + + Ok(ApiResponse { + json: json!(result), + status: Status::Created, + }) } -#[put("/device/", format = "json", data = "")] +#[put("/device/", format = "json", data = "")] pub async fn modify_device( session: SessionInfo, - id: i64, - data: Json, + device_id: i64, + data: Json, appstate: &State, ) -> ApiResult { - debug!("User {} updating device {}", session.user.username, id); - let mut device = device_for_admin_or_self(&appstate.pool, &session, id).await?; + debug!( + "User {} updating device {}", + session.user.username, device_id + ); + let mut device = device_for_admin_or_self(&appstate.pool, &session, device_id).await?; + let networks = WireguardNetwork::all(&appstate.pool).await?; + + if networks.is_empty() { + error!("No network found can't modify device"); + return Ok(ApiResponse { + json: json!({}), + status: Status::BadRequest, + }); + } - // FIXME: hard-coded network id - if let Ok(Some(network)) = WireguardNetwork::find_by_id(&appstate.pool, 1).await { + // check pubkeys + for network in &networks { if network.pubkey == data.wireguard_pubkey { return Ok(ApiResponse { json: json!({"msg": "device's pubkey must be different from server's pubkey"}), status: Status::BadRequest, }); } + } - device.update_from(data.into_inner()); - device.save(&appstate.pool).await?; - appstate.send_wireguard_event(GatewayEvent::DeviceModified(device.clone())); - info!("User {} updated device {}", session.user.username, id); - Ok(ApiResponse { - json: json!(device), - status: Status::Ok, - }) - } else { - error!("No network found can't add device"); - Ok(ApiResponse { - json: json!({}), - status: Status::BadRequest, - }) + // update device info + device.update_from(data.into_inner()); + device.save(&appstate.pool).await?; + + // send update to gateway's + let mut network_info = Vec::new(); + for network in &networks { + if let Some(network_id) = network.id { + if let Some(device_id) = device.id { + let wireguard_network_device = + WireguardNetworkDevice::find(&appstate.pool, device_id, network_id).await?; + if let Some(wireguard_network_device) = wireguard_network_device { + let device_network_info = DeviceNetworkInfo { + network_id, + device_wireguard_ip: wireguard_network_device.wireguard_ip.clone(), + }; + network_info.push(device_network_info) + } + } + } } + appstate.send_wireguard_event(GatewayEvent::DeviceModified(DeviceInfo { + device: device.clone(), + network_info, + })); + + info!( + "User {} updated device {}", + session.user.username, device_id + ); + Ok(ApiResponse { + json: json!(device), + status: Status::Ok, + }) } -#[get("/device/", format = "json")] -pub async fn get_device(session: SessionInfo, id: i64, appstate: &State) -> ApiResult { - debug!("Retrieving device with id: {}", id); - let device = device_for_admin_or_self(&appstate.pool, &session, id).await?; +#[get("/device/", format = "json")] +pub async fn get_device( + session: SessionInfo, + device_id: i64, + appstate: &State, +) -> ApiResult { + debug!("Retrieving device with id: {}", device_id); + let device = device_for_admin_or_self(&appstate.pool, &session, device_id).await?; Ok(ApiResponse { json: json!(device), status: Status::Ok, }) } -#[delete("/device/")] -pub async fn delete_device(session: SessionInfo, id: i64, appstate: &State) -> ApiResult { - debug!("User {} deleting device {}", session.user.username, id); - let device = device_for_admin_or_self(&appstate.pool, &session, id).await?; +#[delete("/device/")] +pub async fn delete_device( + session: SessionInfo, + device_id: i64, + appstate: &State, +) -> ApiResult { + debug!( + "User {} deleting device {}", + session.user.username, device_id + ); + let device = device_for_admin_or_self(&appstate.pool, &session, device_id).await?; let device_pubkey = device.wireguard_pubkey.clone(); device.delete(&appstate.pool).await?; appstate.send_wireguard_event(GatewayEvent::DeviceDeleted(device_pubkey)); - info!("User {} deleted device {}", session.user.username, id); + info!( + "User {} deleted device {}", + session.user.username, device_id + ); Ok(ApiResponse::default()) } @@ -385,31 +672,46 @@ pub async fn list_user_devices( }) } -// FIXME: conflicts with /device/user/ -#[get("/device//config", rank = 2, format = "json")] +#[get("//device//config", rank = 2, format = "json")] pub async fn download_config( session: SessionInfo, appstate: &State, - id: i64, + network_id: i64, + device_id: i64, ) -> Result { - let network = find_network(1, &appstate.pool).await?; - let device = device_for_admin_or_self(&appstate.pool, &session, id).await?; - - Ok(device.create_config(network)) + let network = find_network(network_id, &appstate.pool).await?; + let device = device_for_admin_or_self(&appstate.pool, &session, device_id).await?; + let wireguard_network_device = + WireguardNetworkDevice::find(&appstate.pool, device_id, network_id).await?; + match wireguard_network_device { + Some(wireguard_network_device) => { + Ok(device.create_config(&network, &wireguard_network_device)) + } + None => { + let device_id = match device.id { + Some(id) => id.to_string(), + None => "".to_string(), + }; + Err(OriWebError::ObjectNotFound(format!( + "No ip found for device: {}({})", + device.name, device_id + ))) + } + } } -#[get("/token/", format = "json")] +#[get("//token", format = "json")] pub async fn create_network_token( _admin: AdminRole, appstate: &State, - id: i64, + network_id: i64, ) -> ApiResult { - info!("Generating a new token for network ID {}", id); - let network = find_network(id, &appstate.pool).await?; + info!("Generating a new token for network ID {}", network_id); + let network = find_network(network_id, &appstate.pool).await?; let token = Claims::new( ClaimsType::Gateway, - format!("DEFGUARD-NETWORK-{}", id), - String::new(), + format!("DEFGUARD-NETWORK-{}", network_id), + network_id.to_string(), u32::MAX.into(), ) .to_jwt() @@ -446,17 +748,29 @@ fn parse_timestamp(datetime: Option) -> Result, Status> { }) } -#[get("/stats/users?", format = "json")] +#[get("//stats/users?", format = "json")] pub async fn user_stats( _admin: AdminRole, appstate: &State, from: Option, + network_id: i64, ) -> ApiResult { debug!("Displaying wireguard user stats"); + let network = match WireguardNetwork::find_by_id(&appstate.pool, network_id).await? { + Some(n) => n, + None => { + return Err(OriWebError::ObjectNotFound(format!( + "Requested network ({}) not found", + network_id + ))); + } + }; let from = parse_timestamp(from)?.naive_utc(); let aggregation = get_aggregation(from)?; - let stats = WireguardNetwork::user_stats(&appstate.pool, &from, &aggregation).await?; - info!("Displayed wireguard user stats"); + let stats = network + .user_stats(&appstate.pool, &from, &aggregation) + .await?; + debug!("Displayed wireguard user stats"); Ok(ApiResponse { json: json!(stats), @@ -464,37 +778,32 @@ pub async fn user_stats( }) } -#[get("/stats?", format = "json")] +#[get("//stats?", format = "json")] pub async fn network_stats( _admin: AdminRole, appstate: &State, from: Option, + network_id: i64, ) -> ApiResult { debug!("Displaying wireguard network stats"); + let network = match WireguardNetwork::find_by_id(&appstate.pool, network_id).await? { + Some(n) => n, + None => { + return Err(OriWebError::ObjectNotFound(format!( + "Requested network ({}) not found", + network_id + ))); + } + }; let from = parse_timestamp(from)?.naive_utc(); let aggregation = get_aggregation(from)?; - let stats = WireguardNetwork::network_stats(&appstate.pool, &from, &aggregation).await?; - info!("Displayed wireguard network stats"); + let stats = network + .network_stats(&appstate.pool, &from, &aggregation) + .await?; + debug!("Displayed wireguard network stats"); Ok(ApiResponse { json: json!(stats), status: Status::Ok, }) } - -#[get("/connection", format = "json")] -pub async fn connection_info( - _admin: AdminRole, - gateway_state: &State>>, -) -> ApiResult { - debug!("Checking gateway connection info"); - let info = ConnectionInfo { - connected: gateway_state.lock().unwrap().connected(), - }; - info!("Checked gateway connection info"); - - Ok(ApiResponse { - json: json!(info), - status: Status::Ok, - }) -} diff --git a/src/lib.rs b/src/lib.rs index 6ec2acfa2..e5b857eb3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,24 +18,19 @@ use crate::handlers::{ }, }; #[cfg(any(feature = "oauth", feature = "openid", feature = "worker"))] -use crate::license::Features; use crate::{ - auth::failed_login::FailedLoginMap, grpc::GatewayMap, handlers::app_info::get_app_info, + auth::failed_login::FailedLoginMap, + db::models::oauth2client::OAuth2Client, + grpc::GatewayMap, + grpc::WorkerState, + handlers::app_info::get_app_info, + handlers::wireguard::{add_user_devices, import_network}, + license::{Features, License}, }; -use crate::{ - db::models::oauth2client::OAuth2Client, grpc::WorkerState, - handlers::wireguard::add_user_devices, -}; -use crate::{handlers::wireguard::import_network, license::License}; use appstate::AppState; use config::DefGuardConfig; use db::{init_db, AppEvent, DbPool, Device, GatewayEvent, WireguardNetwork}; #[cfg(feature = "wireguard")] -use handlers::wireguard::{ - add_device, create_network, create_network_token, delete_device, delete_network, - download_config, get_device, list_devices, list_networks, list_user_devices, modify_device, - modify_network, network_details, network_stats, user_stats, -}; use handlers::{ auth::{ authenticate, logout, mfa_disable, mfa_enable, recovery_code, totp_code, totp_disable, @@ -53,7 +48,12 @@ use handlers::{ webhooks::{ add_webhook, change_enabled, change_webhook, delete_webhook, get_webhook, list_webhooks, }, - wireguard::connection_info, + wireguard::{ + add_device, create_network, create_network_token, delete_device, delete_network, + download_config, gateway_status, get_device, list_devices, list_networks, + list_user_devices, modify_device, modify_network, network_details, network_stats, + user_stats, + }, }; use rocket::{ config::{Config, SecretKey}, @@ -198,8 +198,6 @@ pub async fn build_webapp( modify_device, delete_device, list_devices, - download_config, - connection_info, ], ); @@ -213,11 +211,13 @@ pub async fn build_webapp( modify_network, list_networks, network_details, + gateway_status, import_network, add_user_devices, create_network_token, user_stats, network_stats, + download_config, ], ); @@ -318,6 +318,11 @@ pub async fn init_dev_env(config: &DefGuardConfig) { &config.database_password, ) .await; + let mut transaction = pool + .begin() + .await + .expect("Failed to initialize transaction"); + let mut network = WireguardNetwork::new( "TestNet".to_string(), "10.1.1.1/24".parse().unwrap(), @@ -329,15 +334,24 @@ pub async fn init_dev_env(config: &DefGuardConfig) { .expect("Could not create network"); network.pubkey = "zGMeVGm9HV9I4wSKF9AXmYnnAIhDySyqLMuKpcfIaQo=".to_string(); network.prvkey = "MAk3d5KuB167G88HM7nGYR6ksnPMAOguAg2s5EcPp1M=".to_string(); - network.save(&pool).await.expect("Could not save network"); + network + .save(&mut transaction) + .await + .expect("Could not save network"); let mut device = Device::new( "TestDevice".to_string(), - "10.1.1.10".to_string(), "gQYL5eMeFDj0R+lpC7oZyIl0/sNVmQDC6ckP7husZjc=".to_string(), 1, ); - device.save(&pool).await.expect("Could not save device"); + device + .assign_network_ip(&mut transaction, &network, &Vec::new()) + .await + .expect("Could not assign IP to device"); + device + .save(&mut transaction) + .await + .expect("Could not save device"); for app_id in 1..=3 { let mut app = OAuth2Client::new( @@ -345,7 +359,14 @@ pub async fn init_dev_env(config: &DefGuardConfig) { vec!["openid".into(), "profile".into(), "email".into()], format!("app-{}", app_id), ); - app.save(&pool).await.expect("Could not save oauth2client"); + app.save(&mut transaction) + .await + .expect("Could not save oauth2client"); } + transaction + .commit() + .await + .expect("Failed to commit transaction"); + info!("Dev environment initialized - TestNet, TestDevice, AuthorizedApps added"); } diff --git a/src/wg_config.rs b/src/wg_config.rs index 975be53a3..1b2e79ea2 100644 --- a/src/wg_config.rs +++ b/src/wg_config.rs @@ -4,6 +4,14 @@ use ipnetwork::{IpNetwork, IpNetworkError}; use std::array::TryFromSliceError; use x25519_dalek::{PublicKey, StaticSecret}; +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ImportedDevice { + pub user_id: Option, + pub name: String, + pub wireguard_pubkey: String, + pub wireguard_ip: String, +} + #[derive(Debug)] pub enum WireguardConfigParseError { ParseError, @@ -40,7 +48,7 @@ impl From for WireguardConfigParseError { pub fn parse_wireguard_config( config: &str, -) -> Result<(WireguardNetwork, Vec), WireguardConfigParseError> { +) -> Result<(WireguardNetwork, Vec), WireguardConfigParseError> { let config = ini::Ini::load_from_str(config)?; // Parse WireguardNetwork let interface_section = config @@ -87,14 +95,38 @@ pub fn parse_wireguard_config( .get("AllowedIPs") .ok_or_else(|| WireguardConfigParseError::KeyNotFound("AllowedIPs".to_string()))?; let ip_network: IpNetwork = ip.parse()?; - let ip = ip_network.ip().to_string(); + let ip = ip_network.ip(); + + // check if assigned IP collides with gateway IP + let net_ip = network.address.ip(); + let net_network = network.address.network(); + let net_broadcast = network.address.broadcast(); + if ip == net_ip || ip == net_network || ip == net_broadcast { + return Err(WireguardConfigParseError::InvalidIp(format!( + "Invalid peer IP {}", + ip + ))); + } let pubkey = peer .get("PublicKey") .ok_or_else(|| WireguardConfigParseError::KeyNotFound("PublicKey".to_string()))?; Device::validate_pubkey(pubkey).map_err(WireguardConfigParseError::InvalidKey)?; - devices.push(Device::new(pubkey.to_string(), ip, pubkey.to_string(), -1)); + // check if device pubkey collides with network pubkey + if pubkey == network.pubkey { + return Err(WireguardConfigParseError::InvalidKey(format!( + "Device pubkey is the same as network pubkey {}", + pubkey + ))); + } + + devices.push(ImportedDevice { + user_id: None, + name: pubkey.to_string(), + wireguard_pubkey: pubkey.to_string(), + wireguard_ip: ip.to_string(), + }); } Ok((network, devices)) @@ -148,25 +180,17 @@ mod test { assert_eq!(devices.len(), 2); let device1 = &devices[0]; - assert_eq!(device1.id, None); - assert_eq!(device1.name, "2LYRr2HgSSpGCdXKDDAlcFe0Uuc6RR8TFgSquNc9VAE="); - assert_eq!(device1.wireguard_ip, "10.0.0.10"); assert_eq!( device1.wireguard_pubkey, "2LYRr2HgSSpGCdXKDDAlcFe0Uuc6RR8TFgSquNc9VAE=" ); - // TODO: do something about user_id - assert_eq!(device1.user_id, -1); + assert_eq!(device1.wireguard_ip, "10.0.0.10"); let device2 = &devices[1]; - assert_eq!(device2.id, None); - assert_eq!(device2.name, "OLQNaEH3FxW0hiodaChEHoETzd+7UzcqIbsLs+X8rD0="); - assert_eq!(device2.wireguard_ip, "10.0.0.11"); assert_eq!( device2.wireguard_pubkey, "OLQNaEH3FxW0hiodaChEHoETzd+7UzcqIbsLs+X8rD0=" ); - // TODO: do something about user_id - assert_eq!(device2.user_id, -1); + assert_eq!(device2.wireguard_ip, "10.0.0.11"); } } diff --git a/tests/auth.rs b/tests/auth.rs index 19fea54fd..206fdec8b 100644 --- a/tests/auth.rs +++ b/tests/auth.rs @@ -1,7 +1,8 @@ +use defguard::db::UserDetails; use defguard::handlers::WalletChallenge; use defguard::{ auth::TOTP_CODE_VALIDITY_PERIOD, - db::{models::wallet::keccak256, DbPool, MFAInfo, MFAMethod, UserInfo, Wallet}, + db::{models::wallet::keccak256, DbPool, MFAInfo, MFAMethod, Wallet}, handlers::AuthResponse, handlers::{Auth, AuthCode, AuthTotp}, }; @@ -316,9 +317,9 @@ async fn test_webauthn() { assert_eq!(response.status(), Status::Ok); // get security keys - let response = client.get("/api/v1/me").dispatch().await; + let response = client.get("/api/v1/user/hpotter").dispatch().await; assert_eq!(response.status(), Status::Ok); - let user_info: UserInfo = response.into_json().await.unwrap(); + let user_info: UserDetails = response.into_json().await.unwrap(); assert_eq!(user_info.security_keys.len(), 1); // delete security key @@ -339,7 +340,7 @@ async fn test_webauthn() { // check that recovery codes were cleared since last MFA method was removed let record = query!( "SELECT recovery_codes FROM \"user\" WHERE id = $1", - user_info.id, + user_info.user.id, ) .fetch_one(&pool) .await @@ -489,10 +490,10 @@ async fn test_mfa_method_is_updated_when_removing_last_webauthn_passkey() { // get user info let response = client.get("/api/v1/user/hpotter").dispatch().await; assert_eq!(response.status(), Status::Ok); - let mut user_info: UserInfo = response.into_json().await.unwrap(); + let mut user_info: UserDetails = response.into_json().await.unwrap(); // set default MFA method - user_info.mfa_method = MFAMethod::Webauthn; + user_info.user.mfa_method = MFAMethod::Webauthn; let response = client .put("/api/v1/user/hpotter") .json(&user_info) @@ -584,7 +585,7 @@ This request will not trigger a blockchain transaction or cost any gas fees."; assert_eq!(data.challenge, message); // Sign message - let signature = sign_message(data.challenge, &secp, secret_key); + let signature = sign_message(data.challenge, secp, secret_key); // Check if invalid signature results into 401 let invalid_request_response = client @@ -709,7 +710,7 @@ async fn test_re_adding_wallet() { let challenge: WalletChallenge = response.into_json().await.unwrap(); let signature = sign_message(challenge.message, &secp, secret_key); let response = client - .put(format!("/api/v1/user/hpotter/wallet")) + .put("/api/v1/user/hpotter/wallet") .json(&json!({ "address": wallet_address, "chain_id": 1, @@ -771,7 +772,7 @@ async fn test_re_adding_wallet() { let challenge: WalletChallenge = response.into_json().await.unwrap(); let signature = sign_message(challenge.message, &secp, secret_key); let response = client - .put(format!("/api/v1/user/hpotter/wallet")) + .put("/api/v1/user/hpotter/wallet") .json(&json!({ "address": wallet_address, "chain_id": 1, diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 6611171f8..b36ba4027 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -1,3 +1,4 @@ +use defguard::db::UserDetails; #[cfg(test)] use defguard::{ auth::failed_login::FailedLoginMap, @@ -6,6 +7,7 @@ use defguard::{ db::{init_db, AppEvent, DbPool, GatewayEvent, User}, grpc::{GatewayMap, WorkerState}, }; +use rocket::http::Status; use rocket::local::asynchronous::Client; use sqlx::{postgres::PgConnectOptions, query, types::Uuid}; use std::sync::{Arc, Mutex}; @@ -141,6 +143,16 @@ pub async fn make_enterprise_test_client() -> (Client, ClientState) { make_license_test_client(LICENSE_ENTERPRISE).await } +#[allow(dead_code)] +pub async fn fetch_user_details(client: &Client, username: &str) -> UserDetails { + let response = client + .get(format!("/api/v1/user/{}", username)) + .dispatch() + .await; + assert_eq!(response.status(), Status::Ok); + response.into_json().await.unwrap() +} + #[allow(dead_code)] #[cfg(feature = "openid")] pub(super) static LICENSE_ENTERPRISE: &str = "BwAAAAAAAAB0ZW9uaXRlCgAAAAAAAAAyMDUwLTEwLTEwAAAAAAFiayfBptq8pZXjPo4FV3VnmmwR/ipZHLriVPTW3AFyRq4c2wR+DzWC4BUACu3YMS27kX116JVKWB3/edYKNELFSiqYc6vsfoOrXnnQQJDI8RoyAQB6MpLv/EcgRZh47iI4L+tp44jKFQZ+EqqvMNt3G41u13P72HdkUv8yzQ7dmm3BrYQGJSCh/xiLna+mtQ9IQdqXOmYVInPXiWtIvi157Utfnow3gS0Ak45jci0DhtH+RWmFfiMOQCc4Qx0kEF9PsHl6Hn9Ay4oRTAnSYEPdWfQlVh5Rp276bLqnHDdyJ3/o2RSNK+QUXR7V2iuN1M3sWyW1rCGXtV5miHGI97CS"; diff --git a/tests/user.rs b/tests/user.rs index 4792191bc..f98f1e8dd 100644 --- a/tests/user.rs +++ b/tests/user.rs @@ -11,7 +11,7 @@ use rocket::{http::Status, local::asynchronous::Client, serde::json::serde_json: use secp256k1::{rand::rngs::OsRng, Message, Secp256k1}; mod common; -use crate::common::make_test_client; +use crate::common::{fetch_user_details, make_test_client}; use tokio_stream::{self as stream, StreamExt}; async fn make_client() -> Client { @@ -115,11 +115,9 @@ async fn test_get_user() { let response = client.post("/api/v1/auth").json(&auth).dispatch().await; assert_eq!(response.status(), Status::Ok); - let response = client.get("/api/v1/user/hpotter").dispatch().await; - assert_eq!(response.status(), Status::Ok); - let user_info: UserInfo = response.into_json().await.unwrap(); - assert_eq!(user_info.first_name, "Harry"); - assert_eq!(user_info.last_name, "Potter"); + let user_info = fetch_user_details(&client, "hpotter").await; + assert_eq!(user_info.user.first_name, "Harry"); + assert_eq!(user_info.user.last_name, "Potter"); } #[rocket::async_test] @@ -198,13 +196,11 @@ async fn test_crud_user() { assert_eq!(response.status(), Status::Created); // get user - let response = client.get("/api/v1/user/adumbledore").dispatch().await; - assert_eq!(response.status(), Status::Ok); - let mut user_info: UserInfo = response.into_json().await.unwrap(); - assert_eq!(user_info.first_name, "Albus"); + let mut user_info = fetch_user_details(&client, "adumbledore").await; + assert_eq!(user_info.user.first_name, "Albus"); // edit user - user_info.phone = Some("5678".into()); + user_info.user.phone = Some("5678".into()); let response = client .put("/api/v1/user/adumbledore") .json(&user_info) @@ -300,10 +296,9 @@ This request will not trigger a blockchain transaction or cost any gas fees."; assert_eq!(challenge.message, message); - let response = client.get("/api/v1/user/hpotter").dispatch().await; - assert_eq!(response.status(), Status::Ok); - let user_info: UserInfo = response.into_json().await.unwrap(); + let user_info = fetch_user_details(&client, "hpotter").await; assert!(user_info.wallets.is_empty()); + // Sign message let typed_data: TypedData = rocket::serde::json::serde_json::from_str(&message).unwrap(); let hash_msg = typed_data.encode_eip712().unwrap(); @@ -328,9 +323,7 @@ This request will not trigger a blockchain transaction or cost any gas fees."; assert_eq!(response.status(), Status::Ok); // get user info for wallets - let response = client.get("/api/v1/user/hpotter").dispatch().await; - assert_eq!(response.status(), Status::Ok); - let user_info: UserInfo = response.into_json().await.unwrap(); + let user_info = fetch_user_details(&client, "hpotter").await; assert_eq!(user_info.wallets.len(), 1); let wallet_info = &user_info.wallets[0]; assert_eq!(wallet_info.address, wallet_address); @@ -348,9 +341,7 @@ This request will not trigger a blockchain transaction or cost any gas fees."; .await; assert_eq!(response.status(), Status::Ok); - let response = client.get("/api/v1/user/hpotter").dispatch().await; - assert_eq!(response.status(), Status::Ok); - let user_info: UserInfo = response.into_json().await.unwrap(); + let user_info = fetch_user_details(&client, "hpotter").await; assert!(user_info.wallets.is_empty()); } diff --git a/tests/wireguard.rs b/tests/wireguard.rs index 3fe7a3623..fbb3e6794 100644 --- a/tests/wireguard.rs +++ b/tests/wireguard.rs @@ -1,4 +1,5 @@ use chrono::{Datelike, Duration, NaiveDate, SubsecRound, Timelike, Utc}; +use defguard::db::models::device::{UserDevice, WireguardNetworkDevice}; use defguard::{ db::{ models::wireguard::{ @@ -7,7 +8,7 @@ use defguard::{ Device, GatewayEvent, WireguardNetwork, WireguardPeerStats, }, handlers::{ - wireguard::{ImportedNetworkData, UserDevices, WireguardNetworkData}, + wireguard::{ImportedNetworkData, WireguardNetworkData}, Auth, }, }; @@ -19,7 +20,7 @@ use rocket::{ use tokio::sync::broadcast::error::TryRecvError; mod common; -use crate::common::make_test_client; +use crate::common::{fetch_user_details, make_test_client}; fn make_network() -> Value { json!({ @@ -52,7 +53,7 @@ async fn test_network() { let network: WireguardNetwork = response.into_json().await.unwrap(); assert_eq!(network.name, "network"); let event = wg_rx.try_recv().unwrap(); - assert_matches!(event, GatewayEvent::NetworkCreated(_)); + assert_matches!(event, GatewayEvent::NetworkCreated(..)); // modify network let network_data = WireguardNetworkData { @@ -70,7 +71,7 @@ async fn test_network() { .await; assert_eq!(response.status(), Status::Ok); let event = wg_rx.try_recv().unwrap(); - assert_matches!(event, GatewayEvent::NetworkModified(_)); + assert_matches!(event, GatewayEvent::NetworkModified(..)); // list networks let response = client.get("/api/v1/network").dispatch().await; @@ -96,7 +97,7 @@ async fn test_network() { .await; assert_eq!(response.status(), Status::Ok); let event = wg_rx.try_recv().unwrap(); - assert_matches!(event, GatewayEvent::NetworkDeleted(_)); + assert_matches!(event, GatewayEvent::NetworkDeleted(..)); } #[rocket::async_test] @@ -117,7 +118,7 @@ async fn test_device() { .await; assert_eq!(response.status(), Status::Created); let event = wg_rx.try_recv().unwrap(); - assert_matches!(event, GatewayEvent::NetworkCreated(_)); + assert_matches!(event, GatewayEvent::NetworkCreated(..)); // network details let response = client.get("/api/v1/network/1").dispatch().await; @@ -136,7 +137,33 @@ async fn test_device() { .await; assert_eq!(response.status(), Status::Created); let event = wg_rx.try_recv().unwrap(); - assert_matches!(event, GatewayEvent::DeviceCreated(_)); + assert_matches!(event, GatewayEvent::DeviceCreated(..)); + + // an IP was assigned for new device + let network_devices = WireguardNetworkDevice::findy_by_device(&client_state.pool, 1) + .await + .unwrap() + .unwrap(); + assert_eq!( + network_devices[0].wireguard_network_id, + network_from_details.id + ); + + // add another network + let response = client + .post("/api/v1/network") + .json(&make_network()) + .dispatch() + .await; + assert_eq!(response.status(), Status::Created); + assert_matches!(wg_rx.try_recv().unwrap(), GatewayEvent::NetworkCreated(..)); + + // an IP was assigned for an existing device + let network_devices = WireguardNetworkDevice::findy_by_device(&client_state.pool, 1) + .await + .unwrap() + .unwrap(); + assert_eq!(network_devices.len(), 2); // list devices let response = client.get("/api/v1/device").json(&device).dispatch().await; @@ -175,7 +202,7 @@ async fn test_device() { .await; assert_eq!(response.status(), Status::Ok); let event = wg_rx.try_recv().unwrap(); - assert_matches!(event, GatewayEvent::DeviceModified(_)); + assert_matches!(event, GatewayEvent::DeviceModified(..)); // device details let response = client @@ -189,7 +216,10 @@ async fn test_device() { // device config let response = client - .get(format!("/api/v1/device/{}/config", device.id.unwrap())) + .get(format!( + "/api/v1/network/1/device/{}/config", + device.id.unwrap() + )) .dispatch() .await; assert_eq!(response.status(), Status::Ok); @@ -211,7 +241,6 @@ async fn test_device() { ) ); - // FIXME: try to delete network, which should fail because there is a device let response = client .delete(format!( "/api/v1/network/{}", @@ -221,7 +250,7 @@ async fn test_device() { .await; assert_eq!(response.status(), Status::Ok); let event = wg_rx.try_recv().unwrap(); - assert_matches!(event, GatewayEvent::NetworkDeleted(_)); + assert_matches!(event, GatewayEvent::NetworkDeleted(..)); // delete device let response = client @@ -230,7 +259,7 @@ async fn test_device() { .await; assert_eq!(response.status(), Status::Ok); let event = wg_rx.try_recv().unwrap(); - assert_matches!(event, GatewayEvent::DeviceDeleted(_)); + assert_matches!(event, GatewayEvent::DeviceDeleted(..)); let response = client.get("/api/v1/device").json(&device).dispatch().await; assert_eq!(response.status(), Status::Ok); @@ -273,7 +302,7 @@ async fn test_device_permissions() { "created": "2023-05-05T23:56:04" }]}); let response = client - .post("/api/v1/network/devices") + .post("/api/v1/network/1/devices") .json(&device) .dispatch() .await; @@ -297,7 +326,7 @@ async fn test_device_permissions() { "created": "2023-05-05T23:56:04" }]}); let response = client - .post("/api/v1/network/devices") + .post("/api/v1/network/1/devices") .json(&device) .dispatch() .await; @@ -326,7 +355,7 @@ async fn test_device_permissions() { "created": "2023-05-05T23:56:04" }]}); let response = client - .post("/api/v1/network/devices") + .post("/api/v1/network/1/devices") .json(&device) .dispatch() .await; @@ -350,7 +379,7 @@ async fn test_device_permissions() { "created": "2023-05-05T23:56:04" }]}); let response = client - .post("/api/v1/network/devices") + .post("/api/v1/network/1/devices") .json(&device) .dispatch() .await; @@ -399,7 +428,7 @@ async fn test_device_pubkey() { .await; assert_eq!(response.status(), Status::Created); let event = wg_rx.try_recv().unwrap(); - assert_matches!(event, GatewayEvent::NetworkCreated(_)); + assert_matches!(event, GatewayEvent::NetworkCreated(..)); // network details let response = client.get("/api/v1/network/1").dispatch().await; @@ -474,7 +503,7 @@ async fn test_device_pubkey() { "created": "2023-05-05T23:56:04" }]}); let response = client - .post("/api/v1/network/devices") + .post("/api/v1/network/1/devices") .json(&devices) .dispatch() .await; @@ -542,7 +571,7 @@ async fn test_stats() { let hour_ago = now - Duration::hours(1); let response = client .get(format!( - "/api/v1/network/stats/users?from={}", + "/api/v1/network/1/stats/users?from={}", hour_ago.format("%Y-%m-%dT%H:%M:00Z"), )) .dispatch() @@ -573,7 +602,7 @@ async fn test_stats() { // minute aggregation let response = client .get(format!( - "/api/v1/network/stats/users?from={}", + "/api/v1/network/1/stats/users?from={}", hour_ago.format("%Y-%m-%dT%H:%M:00Z"), )) .dispatch() @@ -677,7 +706,7 @@ async fn test_stats() { let ten_hours_samples = 10 * 60 + 1; let response = client .get(format!( - "/api/v1/network/stats/users?from={}", + "/api/v1/network/1/stats/users?from={}", ten_hours_ago.format("%Y-%m-%dT%H:%M:00Z"), )) .dispatch() @@ -708,7 +737,7 @@ async fn test_stats() { // network stats let response = client .get(format!( - "/api/v1/network/stats?from={}", + "/api/v1/network/1/stats?from={}", ten_hours_ago.format("%Y-%m-%dT%H:%M:00Z"), )) .dispatch() @@ -761,8 +790,53 @@ async fn test_config_import() { PublicKey = OLQNaEH3FxW0hiodaChEHoETzd+7UzcqIbsLs+X8rD0= AllowedIPs = 10.0.0.11/24 PersistentKeepalive = 300 + + [Peer] + PublicKey = l07+qPWs4jzW3Gp1DKbHgBMRRm4Jg3q2BJxw0ZYl6c4= + AllowedIPs = 10.0.0.12/24 + PersistentKeepalive = 300 "; let (client, client_state) = make_test_client().await; + let pool = client_state.pool; + + // setup initial network + let mut initial_network = WireguardNetwork::new( + "initial".into(), + "10.1.9.0/24".parse().unwrap(), + 51515, + "".to_string(), + None, + vec![], + ) + .unwrap(); + initial_network.save(&pool).await.unwrap(); + + // add existing devices + let mut transaction = pool.begin().await.unwrap(); + + let mut device_1 = Device::new( + "test device".into(), + "l07+qPWs4jzW3Gp1DKbHgBMRRm4Jg3q2BJxw0ZYl6c4=".into(), + 1, + ); + device_1.save(&mut transaction).await.unwrap(); + device_1 + .add_to_all_networks(&mut transaction) + .await + .unwrap(); + + let mut device_2 = Device::new( + "another test device".into(), + "v2U14sjNN4tOYD3P15z0WkjriKY9Hl85I3vIEPomrYs=".into(), + 1, + ); + device_2.save(&mut transaction).await.unwrap(); + device_2 + .add_to_all_networks(&mut transaction) + .await + .unwrap(); + + transaction.commit().await.unwrap(); let mut wg_rx = client_state.wireguard_rx; @@ -781,7 +855,7 @@ async fn test_config_import() { // network assertions let network = response.network; - assert_eq!(network.id, Some(1)); + assert_eq!(network.id, Some(2)); assert_eq!(network.name, "network"); assert_eq!(network.address, "10.0.0.1/24".parse().unwrap()); assert_eq!(network.port, 55055); @@ -795,66 +869,104 @@ async fn test_config_import() { assert_eq!(network.allowed_ips, vec!["10.0.0.0/24".parse().unwrap()]); assert_eq!(network.connected_at, None); let event = wg_rx.try_recv().unwrap(); - assert_matches!(event, GatewayEvent::NetworkCreated(_)); + assert_matches!(event, GatewayEvent::NetworkCreated(..)); + + // existing devices assertion + // imported config for an existing device + assert_matches!(wg_rx.try_recv().unwrap(), GatewayEvent::DeviceModified(..)); + let user_device_1 = UserDevice::from_device(&pool, device_1) + .await + .unwrap() + .unwrap(); + assert_eq!(user_device_1.networks.len(), 2); + assert_eq!(user_device_1.networks[1].device_wireguard_ip, "10.0.0.12"); + // generated IP for other existing device + assert_matches!(wg_rx.try_recv().unwrap(), GatewayEvent::DeviceModified(..)); + let user_device_2 = UserDevice::from_device(&pool, device_2) + .await + .unwrap() + .unwrap(); + assert_eq!(user_device_2.networks.len(), 2); // device assertions let devices = response.devices; assert_eq!(devices.len(), 2); let mut device1 = devices[0].clone(); - assert_eq!(device1.id, None); - assert_eq!(device1.name, "2LYRr2HgSSpGCdXKDDAlcFe0Uuc6RR8TFgSquNc9VAE="); assert_eq!(device1.wireguard_ip, "10.0.0.10"); assert_eq!( device1.wireguard_pubkey, "2LYRr2HgSSpGCdXKDDAlcFe0Uuc6RR8TFgSquNc9VAE=" ); - // TODO: do something about user_id - assert_eq!(device1.user_id, -1); + assert_eq!(device1.name, "2LYRr2HgSSpGCdXKDDAlcFe0Uuc6RR8TFgSquNc9VAE="); + assert_eq!(device1.user_id, None); let mut device2 = devices[1].clone(); - assert_eq!(device2.id, None); - assert_eq!(device2.name, "OLQNaEH3FxW0hiodaChEHoETzd+7UzcqIbsLs+X8rD0="); assert_eq!(device2.wireguard_ip, "10.0.0.11"); assert_eq!( device2.wireguard_pubkey, "OLQNaEH3FxW0hiodaChEHoETzd+7UzcqIbsLs+X8rD0=" ); - // TODO: do something about user_id - assert_eq!(device2.user_id, -1); + assert_eq!(device2.name, "OLQNaEH3FxW0hiodaChEHoETzd+7UzcqIbsLs+X8rD0="); + assert_eq!(device2.user_id, None); // modify devices - device1.name = "device1".to_string(); - device1.user_id = 1; - device2.name = "device2".to_string(); - device2.user_id = 1; + device1.user_id = Some(1); + device1.name = "device_1".into(); + device2.user_id = Some(1); + device2.name = "device_2".into(); // post modified devices let response = client - .post("/api/v1/network/devices") + .post(format!("/api/v1/network/{}/devices", network.id.unwrap())) .json(&json!({"devices": [device1, device2]})) .dispatch() .await; assert_eq!(response.status(), Status::Created); - // assert modified devices - let response: UserDevices = response.into_json().await.unwrap(); - let device1 = response.devices[0].clone(); - assert_eq!(device1.name, "device1"); - assert_eq!(device1.user_id, 1); - let device2 = response.devices[1].clone(); - assert_eq!(device2.name, "device2"); - assert_eq!(device2.user_id, 1); - // assert events let event = wg_rx.try_recv().unwrap(); - assert_matches!(event, GatewayEvent::DeviceCreated(_)); + match event { + GatewayEvent::DeviceCreated(device_info) => { + assert_eq!(device_info.device.name, "device_1"); + } + _ => unreachable!("Invalid event type received"), + } let event = wg_rx.try_recv().unwrap(); - assert_matches!(event, GatewayEvent::DeviceCreated(_)); + match event { + GatewayEvent::DeviceCreated(device_info) => { + assert_eq!(device_info.device.name, "device_2"); + } + _ => unreachable!("Invalid event type received"), + } let event = wg_rx.try_recv(); assert_matches!(event, Err(TryRecvError::Empty)); + + // assert user devices + let user_info = fetch_user_details(&client, "admin").await; + assert_eq!(user_info.devices.len(), 4); + assert_eq!(user_info.devices[0].device.name, "test device"); + assert_eq!( + user_info.devices[0].networks[1].device_wireguard_ip, + "10.0.0.12" + ); + assert_eq!(user_info.devices[1].device.name, "another test device"); + assert_eq!( + user_info.devices[1].networks[1].device_wireguard_ip, + "10.0.0.2" + ); + assert_eq!(user_info.devices[2].device.name, "device_1"); + assert_eq!( + user_info.devices[2].networks[1].device_wireguard_ip, + "10.0.0.10" + ); + assert_eq!(user_info.devices[3].device.name, "device_2"); + assert_eq!( + user_info.devices[3].networks[1].device_wireguard_ip, + "10.0.0.11" + ); } #[rocket::async_test] diff --git a/web/index.html b/web/index.html index 38b23d464..249223cf0 100644 --- a/web/index.html +++ b/web/index.html @@ -29,61 +29,17 @@ /> - - - - - - - - - - - + + + + + + + + + + +
diff --git a/web/package.json b/web/package.json index ccd5b4d2d..2883bb203 100644 --- a/web/package.json +++ b/web/package.json @@ -36,19 +36,19 @@ "@floating-ui/react-dom-interactions": "^0.12.0", "@github/webauthn-json": "^2.1.1", "@hookform/resolvers": "^3.1.0", - "@ladle/react": "^2.14.0", - "@popperjs/core": "^2.11.7", + "@ladle/react": "^2.15.0", + "@popperjs/core": "^2.11.8", "@stablelib/base64": "^1.0.1", "@stablelib/x25519": "^1.0.3", - "@tanstack/query-core": "^4.29.11", - "@tanstack/react-query": "^4.29.12", + "@tanstack/query-core": "^4.29.19", + "@tanstack/react-query": "^4.29.19", "@tanstack/react-virtual": "3.0.0-beta.9", "@tanstack/virtual-core": "3.0.0-beta.9", - "@tauri-apps/api": "^1.3.0", + "@tauri-apps/api": "^1.4.0", "@types/react-virtualized-auto-sizer": "^1.0.1", "@types/react-window": "^1.8.5", - "@vitejs/plugin-legacy": "^4.0.4", - "@vitejs/plugin-react": "^4.0.0", + "@vitejs/plugin-legacy": "^4.0.5", + "@vitejs/plugin-react": "^4.0.1", "@walletconnect/encoding": "^1.0.2", "axios": "^1.4.0", "byte-size": "^8.1.1", @@ -60,14 +60,14 @@ "events": "^3.3.0", "fast-deep-equal": "^3.1.3", "file-saver": "^2.0.5", - "framer-motion": "^10.12.16", + "framer-motion": "^10.12.17", "hex-rgb": "^5.0.0", "html-react-parser": "^4.0.0", "itertools": "^2.1.1", "lodash-es": "^4.17.21", "numbro": "^2.3.6", "qrcode": "^1.5.3", - "radash": "^10.8.1", + "radash": "^11.0.0", "react": "^18.2.0", "react-click-away-listener": "^2.2.3", "react-dom": "^18.2.0", @@ -78,14 +78,14 @@ "react-markdown": "^8.0.7", "react-popper": "^2.3.0", "react-qr-code": "^2.0.11", - "react-router": "^6.12.1", - "react-router-dom": "^6.12.1", + "react-router": "^6.14.0", + "react-router-dom": "^6.14.0", "react-virtualized-auto-sizer": "^1.0.20", "react-window": "^1.8.9", - "recharts": "^2.6.2", - "rollup": "^3.25.1", + "recharts": "^2.7.2", + "rollup": "^3.26.0", "rxjs": "^7.8.1", - "terser": "^5.17.7", + "terser": "^5.18.2", "typesafe-i18n": "^5.24.3", "use-breakpoint": "^3.1.1", "vite-plugin-node-polyfills": "^0.9.0", @@ -97,18 +97,19 @@ "@babel/core": "^7.22.5", "@hookform/devtools": "^4.3.1", "@svgr/cli": "^8.0.1", - "@tauri-apps/cli": "^1.3.1", + "@tanstack/react-query-devtools": "^4.29.19", + "@tauri-apps/cli": "^1.4.0", "@types/byte-size": "^8.1.0", "@types/file-saver": "^2.0.5", "@types/lodash-es": "^4.17.7", - "@types/react": "^18.2.11", - "@types/react-dom": "^18.2.4", + "@types/react": "^18.2.14", + "@types/react-dom": "^18.2.6", "@types/react-router-dom": "^5.3.3", - "@typescript-eslint/eslint-plugin": "^5.59.2", - "@typescript-eslint/parser": "^5.59.9", + "@typescript-eslint/eslint-plugin": "^5.60.1", + "@typescript-eslint/parser": "^5.60.1", "autoprefixer": "^10.4.14", - "esbuild": "^0.18.1", - "eslint": "^8.42.0", + "esbuild": "^0.18.10", + "eslint": "^8.43.0", "eslint-config-prettier": "^8.8.0", "eslint-plugin-import": "^2.27.5", "eslint-plugin-jsx-a11y": "^6.7.1", @@ -120,14 +121,14 @@ "postcss": "^8.4.24", "prettier": "^2.8.8", "prop-types": "^15.8.1", - "sass": "^1.63.3", + "sass": "^1.63.6", "standard-version": "^9.5.0", - "stylelint": "^15.7.0", + "stylelint": "^15.9.0", "stylelint-config-prettier-scss": "^1.0.0", - "stylelint-config-standard-scss": "^9.0.0", + "stylelint-config-standard-scss": "^10.0.0", "stylelint-scss": "^5.0.1", "typedoc": "^0.24.8", - "typescript": "~5.1.3", + "typescript": "~5.1.6", "vite": "^4.3.9", "vite-plugin-eslint": "^1.8.1", "vite-plugin-package-version": "^1.0.2" diff --git a/web/pnpm-lock.yaml b/web/pnpm-lock.yaml index 79592254f..a422bf535 100644 --- a/web/pnpm-lock.yaml +++ b/web/pnpm-lock.yaml @@ -18,11 +18,11 @@ dependencies: specifier: ^3.1.0 version: 3.1.0(react-hook-form@7.44.3) '@ladle/react': - specifier: ^2.14.0 - version: 2.14.0(react-dom@18.2.0)(react@18.2.0)(sass@1.63.3)(terser@5.17.7) + specifier: ^2.15.0 + version: 2.15.0(react-dom@18.2.0)(react@18.2.0)(sass@1.63.6)(terser@5.18.2) '@popperjs/core': - specifier: ^2.11.7 - version: 2.11.7 + specifier: ^2.11.8 + version: 2.11.8 '@stablelib/base64': specifier: ^1.0.1 version: 1.0.1 @@ -30,11 +30,11 @@ dependencies: specifier: ^1.0.3 version: 1.0.3 '@tanstack/query-core': - specifier: ^4.29.11 - version: 4.29.11 + specifier: ^4.29.19 + version: 4.29.19 '@tanstack/react-query': - specifier: ^4.29.12 - version: 4.29.12(react-dom@18.2.0)(react@18.2.0) + specifier: ^4.29.19 + version: 4.29.19(react-dom@18.2.0)(react@18.2.0) '@tanstack/react-virtual': specifier: 3.0.0-beta.9 version: 3.0.0-beta.9(react@18.2.0) @@ -42,8 +42,8 @@ dependencies: specifier: 3.0.0-beta.9 version: 3.0.0-beta.9 '@tauri-apps/api': - specifier: ^1.3.0 - version: 1.3.0 + specifier: ^1.4.0 + version: 1.4.0 '@types/react-virtualized-auto-sizer': specifier: ^1.0.1 version: 1.0.1 @@ -51,11 +51,11 @@ dependencies: specifier: ^1.8.5 version: 1.8.5 '@vitejs/plugin-legacy': - specifier: ^4.0.4 - version: 4.0.4(terser@5.17.7)(vite@4.3.9) + specifier: ^4.0.5 + version: 4.0.5(terser@5.18.2)(vite@4.3.9) '@vitejs/plugin-react': - specifier: ^4.0.0 - version: 4.0.0(vite@4.3.9) + specifier: ^4.0.1 + version: 4.0.1(vite@4.3.9) '@walletconnect/encoding': specifier: ^1.0.2 version: 1.0.2 @@ -90,8 +90,8 @@ dependencies: specifier: ^2.0.5 version: 2.0.5 framer-motion: - specifier: ^10.12.16 - version: 10.12.16(react-dom@18.2.0)(react@18.2.0) + specifier: ^10.12.17 + version: 10.12.17(react-dom@18.2.0)(react@18.2.0) hex-rgb: specifier: ^5.0.0 version: 5.0.0 @@ -111,8 +111,8 @@ dependencies: specifier: ^1.5.3 version: 1.5.3 radash: - specifier: ^10.8.1 - version: 10.8.1 + specifier: ^11.0.0 + version: 11.0.0 react: specifier: ^18.2.0 version: 18.2.0 @@ -136,19 +136,19 @@ dependencies: version: 3.3.1(react@18.2.0) react-markdown: specifier: ^8.0.7 - version: 8.0.7(@types/react@18.2.11)(react@18.2.0) + version: 8.0.7(@types/react@18.2.14)(react@18.2.0) react-popper: specifier: ^2.3.0 - version: 2.3.0(@popperjs/core@2.11.7)(react-dom@18.2.0)(react@18.2.0) + version: 2.3.0(@popperjs/core@2.11.8)(react-dom@18.2.0)(react@18.2.0) react-qr-code: specifier: ^2.0.11 version: 2.0.11(react@18.2.0) react-router: - specifier: ^6.12.1 - version: 6.12.1(react@18.2.0) + specifier: ^6.14.0 + version: 6.14.0(react@18.2.0) react-router-dom: - specifier: ^6.12.1 - version: 6.12.1(react-dom@18.2.0)(react@18.2.0) + specifier: ^6.14.0 + version: 6.14.0(react-dom@18.2.0)(react@18.2.0) react-virtualized-auto-sizer: specifier: ^1.0.20 version: 1.0.20(react-dom@18.2.0)(react@18.2.0) @@ -156,29 +156,29 @@ dependencies: specifier: ^1.8.9 version: 1.8.9(react-dom@18.2.0)(react@18.2.0) recharts: - specifier: ^2.6.2 - version: 2.6.2(prop-types@15.8.1)(react-dom@18.2.0)(react@18.2.0) + specifier: ^2.7.2 + version: 2.7.2(prop-types@15.8.1)(react-dom@18.2.0)(react@18.2.0) rollup: - specifier: ^3.25.1 - version: 3.25.1 + specifier: ^3.26.0 + version: 3.26.0 rxjs: specifier: ^7.8.1 version: 7.8.1 terser: - specifier: ^5.17.7 - version: 5.17.7 + specifier: ^5.18.2 + version: 5.18.2 typesafe-i18n: specifier: ^5.24.3 - version: 5.24.3(typescript@5.1.3) + version: 5.24.3(typescript@5.1.6) use-breakpoint: specifier: ^3.1.1 version: 3.1.1(react-dom@18.2.0)(react@18.2.0) vite-plugin-node-polyfills: specifier: ^0.9.0 - version: 0.9.0(rollup@3.25.1)(vite@4.3.9) + version: 0.9.0(rollup@3.26.0)(vite@4.3.9) wagmi: specifier: ^0.10.15 - version: 0.10.15(ethers@5.7.2)(react-dom@18.2.0)(react@18.2.0)(typescript@5.1.3) + version: 0.10.15(ethers@5.7.2)(react-dom@18.2.0)(react@18.2.0)(typescript@5.1.6) yup: specifier: ^1.2.0 version: 1.2.0 @@ -192,13 +192,16 @@ devDependencies: version: 7.22.5 '@hookform/devtools': specifier: ^4.3.1 - version: 4.3.1(@types/react@18.2.11)(react-dom@18.2.0)(react@18.2.0) + version: 4.3.1(@types/react@18.2.14)(react-dom@18.2.0)(react@18.2.0) '@svgr/cli': specifier: ^8.0.1 version: 8.0.1 + '@tanstack/react-query-devtools': + specifier: ^4.29.19 + version: 4.29.19(@tanstack/react-query@4.29.19)(react-dom@18.2.0)(react@18.2.0) '@tauri-apps/cli': - specifier: ^1.3.1 - version: 1.3.1 + specifier: ^1.4.0 + version: 1.4.0 '@types/byte-size': specifier: ^8.1.0 version: 8.1.0 @@ -209,50 +212,50 @@ devDependencies: specifier: ^4.17.7 version: 4.17.7 '@types/react': - specifier: ^18.2.11 - version: 18.2.11 + specifier: ^18.2.14 + version: 18.2.14 '@types/react-dom': - specifier: ^18.2.4 - version: 18.2.4 + specifier: ^18.2.6 + version: 18.2.6 '@types/react-router-dom': specifier: ^5.3.3 version: 5.3.3 '@typescript-eslint/eslint-plugin': - specifier: ^5.59.2 - version: 5.59.2(@typescript-eslint/parser@5.59.9)(eslint@8.42.0)(typescript@5.1.3) + specifier: ^5.60.1 + version: 5.60.1(@typescript-eslint/parser@5.60.1)(eslint@8.43.0)(typescript@5.1.6) '@typescript-eslint/parser': - specifier: ^5.59.9 - version: 5.59.9(eslint@8.42.0)(typescript@5.1.3) + specifier: ^5.60.1 + version: 5.60.1(eslint@8.43.0)(typescript@5.1.6) autoprefixer: specifier: ^10.4.14 version: 10.4.14(postcss@8.4.24) esbuild: - specifier: ^0.18.1 - version: 0.18.1 + specifier: ^0.18.10 + version: 0.18.10 eslint: - specifier: ^8.42.0 - version: 8.42.0 + specifier: ^8.43.0 + version: 8.43.0 eslint-config-prettier: specifier: ^8.8.0 - version: 8.8.0(eslint@8.42.0) + version: 8.8.0(eslint@8.43.0) eslint-plugin-import: specifier: ^2.27.5 - version: 2.27.5(@typescript-eslint/parser@5.59.9)(eslint@8.42.0) + version: 2.27.5(@typescript-eslint/parser@5.60.1)(eslint@8.43.0) eslint-plugin-jsx-a11y: specifier: ^6.7.1 - version: 6.7.1(eslint@8.42.0) + version: 6.7.1(eslint@8.43.0) eslint-plugin-prettier: specifier: ^4.2.1 - version: 4.2.1(eslint-config-prettier@8.8.0)(eslint@8.42.0)(prettier@2.8.8) + version: 4.2.1(eslint-config-prettier@8.8.0)(eslint@8.43.0)(prettier@2.8.8) eslint-plugin-react: specifier: ^7.32.2 - version: 7.32.2(eslint@8.42.0) + version: 7.32.2(eslint@8.43.0) eslint-plugin-react-hooks: specifier: ^4.6.0 - version: 4.6.0(eslint@8.42.0) + version: 4.6.0(eslint@8.43.0) eslint-plugin-simple-import-sort: specifier: ^10.0.0 - version: 10.0.0(eslint@8.42.0) + version: 10.0.0(eslint@8.43.0) npm-run-all: specifier: ^4.1.5 version: 4.1.5 @@ -266,35 +269,35 @@ devDependencies: specifier: ^15.8.1 version: 15.8.1 sass: - specifier: ^1.63.3 - version: 1.63.3 + specifier: ^1.63.6 + version: 1.63.6 standard-version: specifier: ^9.5.0 version: 9.5.0 stylelint: - specifier: ^15.7.0 - version: 15.7.0 + specifier: ^15.9.0 + version: 15.9.0 stylelint-config-prettier-scss: specifier: ^1.0.0 - version: 1.0.0(stylelint@15.7.0) + version: 1.0.0(stylelint@15.9.0) stylelint-config-standard-scss: - specifier: ^9.0.0 - version: 9.0.0(postcss@8.4.24)(stylelint@15.7.0) + specifier: ^10.0.0 + version: 10.0.0(postcss@8.4.24)(stylelint@15.9.0) stylelint-scss: specifier: ^5.0.1 - version: 5.0.1(stylelint@15.7.0) + version: 5.0.1(stylelint@15.9.0) typedoc: specifier: ^0.24.8 - version: 0.24.8(typescript@5.1.3) + version: 0.24.8(typescript@5.1.6) typescript: - specifier: ~5.1.3 - version: 5.1.3 + specifier: ~5.1.6 + version: 5.1.6 vite: specifier: ^4.3.9 - version: 4.3.9(sass@1.63.3)(terser@5.17.7) + version: 4.3.9(sass@1.63.6)(terser@5.18.2) vite-plugin-eslint: specifier: ^1.8.1 - version: 1.8.1(eslint@8.42.0)(vite@4.3.9) + version: 1.8.1(eslint@8.43.0)(vite@4.3.9) vite-plugin-package-version: specifier: ^1.0.2 version: 1.0.2(vite@4.3.9) @@ -349,18 +352,17 @@ packages: '@jridgewell/trace-mapping': 0.3.18 jsesc: 2.5.2 - /@babel/helper-annotate-as-pure@7.18.6: - resolution: {integrity: sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==} + /@babel/helper-annotate-as-pure@7.22.5: + resolution: {integrity: sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==} engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.22.5 dev: false - /@babel/helper-builder-binary-assignment-operator-visitor@7.18.9: - resolution: {integrity: sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw==} + /@babel/helper-builder-binary-assignment-operator-visitor@7.22.5: + resolution: {integrity: sha512-m1EP3lVOPptR+2DwD125gziZNcmoNSHGmJROKoy87loWUQyJaVXDgpmruWqDARZSmtYQ+Dl25okU8+qhVzuykw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/helper-explode-assignable-expression': 7.18.6 '@babel/types': 7.22.5 dev: false @@ -377,21 +379,22 @@ packages: lru-cache: 5.1.1 semver: 6.3.0 - /@babel/helper-create-class-features-plugin@7.21.4(@babel/core@7.22.5): - resolution: {integrity: sha512-46QrX2CQlaFRF4TkwfTt6nJD7IHq8539cCL7SDpqWSDeJKY1xylKKY5F/33mJhLZ3mFvKv2gGrVS6NkyF6qs+Q==} + /@babel/helper-create-class-features-plugin@7.22.5(@babel/core@7.22.5): + resolution: {integrity: sha512-xkb58MyOYIslxu3gKmVXmjTtUPvBU4odYzbiIQbWwLKIHCsx6UGZGX6F1IznMFVnDdirseUZopzN+ZRt8Xb33Q==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-annotate-as-pure': 7.18.6 + '@babel/helper-annotate-as-pure': 7.22.5 '@babel/helper-environment-visitor': 7.22.5 '@babel/helper-function-name': 7.22.5 - '@babel/helper-member-expression-to-functions': 7.21.0 - '@babel/helper-optimise-call-expression': 7.18.6 - '@babel/helper-replace-supers': 7.20.7 - '@babel/helper-skip-transparent-expression-wrappers': 7.20.0 + '@babel/helper-member-expression-to-functions': 7.22.5 + '@babel/helper-optimise-call-expression': 7.22.5 + '@babel/helper-replace-supers': 7.22.5 + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 '@babel/helper-split-export-declaration': 7.22.5 + semver: 6.3.0 transitivePeerDependencies: - supports-color dev: false @@ -403,18 +406,30 @@ packages: '@babel/core': ^7.0.0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-annotate-as-pure': 7.18.6 + '@babel/helper-annotate-as-pure': 7.22.5 + regexpu-core: 5.3.2 + dev: false + + /@babel/helper-create-regexp-features-plugin@7.22.5(@babel/core@7.22.5): + resolution: {integrity: sha512-1VpEFOIbMRaXyDeUwUfmTIxExLwQ+zkW+Bh5zXpApA3oQedBx9v/updixWxnx/bZpKw7u8VxWjb/qWpIcmPq8A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.22.5 + '@babel/helper-annotate-as-pure': 7.22.5 regexpu-core: 5.3.2 + semver: 6.3.0 dev: false - /@babel/helper-define-polyfill-provider@0.3.3(@babel/core@7.22.5): - resolution: {integrity: sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==} + /@babel/helper-define-polyfill-provider@0.4.0(@babel/core@7.22.5): + resolution: {integrity: sha512-RnanLx5ETe6aybRi1cO/edaRH+bNYWaryCEmjDDYyNr4wnSzyOp8T0dWipmqVHKEY3AbVKUom50AKSlj1zmKbg==} peerDependencies: '@babel/core': ^7.4.0-0 dependencies: '@babel/core': 7.22.5 '@babel/helper-compilation-targets': 7.22.5(@babel/core@7.22.5) - '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-plugin-utils': 7.22.5 debug: 4.3.4 lodash.debounce: 4.0.8 resolve: 1.22.2 @@ -427,13 +442,6 @@ packages: resolution: {integrity: sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==} engines: {node: '>=6.9.0'} - /@babel/helper-explode-assignable-expression@7.18.6: - resolution: {integrity: sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.22.5 - dev: false - /@babel/helper-function-name@7.22.5: resolution: {integrity: sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==} engines: {node: '>=6.9.0'} @@ -447,8 +455,8 @@ packages: dependencies: '@babel/types': 7.22.5 - /@babel/helper-member-expression-to-functions@7.21.0: - resolution: {integrity: sha512-Muu8cdZwNN6mRRNG6lAYErJ5X3bRevgYR2O8wN0yn7jJSnGDu6eG59RfT29JHxGUovyfrh6Pj0XzmR7drNVL3Q==} + /@babel/helper-member-expression-to-functions@7.22.5: + resolution: {integrity: sha512-aBiH1NKMG0H2cGZqspNvsaBe6wNGjbJjuLy29aU+eDZjSbbN53BaxlpB02xm9v34pLTZ1nIQPFYn2qMZoa5BQQ==} engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.22.5 @@ -482,40 +490,40 @@ packages: transitivePeerDependencies: - supports-color - /@babel/helper-optimise-call-expression@7.18.6: - resolution: {integrity: sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==} + /@babel/helper-optimise-call-expression@7.22.5: + resolution: {integrity: sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==} engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.22.5 dev: false - /@babel/helper-plugin-utils@7.20.2: - resolution: {integrity: sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==} + /@babel/helper-plugin-utils@7.22.5: + resolution: {integrity: sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==} engines: {node: '>=6.9.0'} dev: false - /@babel/helper-remap-async-to-generator@7.18.9(@babel/core@7.22.5): - resolution: {integrity: sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==} + /@babel/helper-remap-async-to-generator@7.22.5(@babel/core@7.22.5): + resolution: {integrity: sha512-cU0Sq1Rf4Z55fgz7haOakIyM7+x/uCFwXpLPaeRzfoUtAEAuUZjZvFPjL/rk5rW693dIgn2hng1W7xbT7lWT4g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-annotate-as-pure': 7.18.6 + '@babel/helper-annotate-as-pure': 7.22.5 '@babel/helper-environment-visitor': 7.22.5 - '@babel/helper-wrap-function': 7.20.5 + '@babel/helper-wrap-function': 7.22.5 '@babel/types': 7.22.5 transitivePeerDependencies: - supports-color dev: false - /@babel/helper-replace-supers@7.20.7: - resolution: {integrity: sha512-vujDMtB6LVfNW13jhlCrp48QNslK6JXi7lQG736HVbHz/mbf4Dc7tIRh1Xf5C0rF7BP8iiSxGMCmY6Ci1ven3A==} + /@babel/helper-replace-supers@7.22.5: + resolution: {integrity: sha512-aLdNM5I3kdI/V9xGNyKSF3X/gTyMUBohTZ+/3QdQKAA9vxIiy12E+8E2HoOP1/DjeqU+g6as35QHJNMDDYpuCg==} engines: {node: '>=6.9.0'} dependencies: '@babel/helper-environment-visitor': 7.22.5 - '@babel/helper-member-expression-to-functions': 7.21.0 - '@babel/helper-optimise-call-expression': 7.18.6 + '@babel/helper-member-expression-to-functions': 7.22.5 + '@babel/helper-optimise-call-expression': 7.22.5 '@babel/template': 7.22.5 '@babel/traverse': 7.22.5 '@babel/types': 7.22.5 @@ -529,8 +537,8 @@ packages: dependencies: '@babel/types': 7.22.5 - /@babel/helper-skip-transparent-expression-wrappers@7.20.0: - resolution: {integrity: sha512-5y1JYeNKfvnT8sZcK9DVRtpTbGiomYIHviSP3OQWmDPU3DeH4a1ZlT/N2lyQ5P8egjcRaT/Y9aNqUxK0WsnIIg==} + /@babel/helper-skip-transparent-expression-wrappers@7.22.5: + resolution: {integrity: sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==} engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.22.5 @@ -554,8 +562,8 @@ packages: resolution: {integrity: sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw==} engines: {node: '>=6.9.0'} - /@babel/helper-wrap-function@7.20.5: - resolution: {integrity: sha512-bYMxIWK5mh+TgXGVqAtnu5Yn1un+v8DDZtqyzKRLUzrh70Eal2O3aZ7aPYiMADO4uKlkzOiRiZ6GX5q3qxvW9Q==} + /@babel/helper-wrap-function@7.22.5: + resolution: {integrity: sha512-bYqLIBSEshYcYQyfks8ewYA8S30yaGSeRslcvKMvoUk6HHPySbxHq9YRi6ghhzEU+yhQv9bP/jXnygkStOcqZw==} engines: {node: '>=6.9.0'} dependencies: '@babel/helper-function-name': 7.22.5 @@ -591,734 +599,795 @@ packages: dependencies: '@babel/types': 7.22.5 - /@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.18.6(@babel/core@7.22.5): - resolution: {integrity: sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==} + /@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.22.5(@babel/core@7.22.5): + resolution: {integrity: sha512-NP1M5Rf+u2Gw9qfSO4ihjcTGW5zXTi36ITLd4/EoAcEhIZ0yjMqmftDNl3QC19CX7olhrjpyU454g/2W7X0jvQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-plugin-utils': 7.22.5 dev: false - /@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.20.7(@babel/core@7.22.5): - resolution: {integrity: sha512-sbr9+wNE5aXMBBFBICk01tt7sBf2Oc9ikRFEcem/ZORup9IMUdNhW7/wVLEbbtlWOsEubJet46mHAL2C8+2jKQ==} + /@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.22.5(@babel/core@7.22.5): + resolution: {integrity: sha512-31Bb65aZaUwqCbWMnZPduIZxCBngHFlzyN6Dq6KAJjtx+lx6ohKHubc61OomYi7XwVD4Ol0XCVz4h+pYFR048g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.13.0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-plugin-utils': 7.20.2 - '@babel/helper-skip-transparent-expression-wrappers': 7.20.0 - '@babel/plugin-proposal-optional-chaining': 7.21.0(@babel/core@7.22.5) + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/plugin-transform-optional-chaining': 7.22.5(@babel/core@7.22.5) dev: false - /@babel/plugin-proposal-async-generator-functions@7.20.7(@babel/core@7.22.5): - resolution: {integrity: sha512-xMbiLsn/8RK7Wq7VeVytytS2L6qE69bXPB10YCmMdDZbKF4okCqY74pI/jJQ/8U0b/F6NrT2+14b8/P9/3AMGA==} + /@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.22.5): + resolution: {integrity: sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-environment-visitor': 7.22.5 - '@babel/helper-plugin-utils': 7.20.2 - '@babel/helper-remap-async-to-generator': 7.18.9(@babel/core@7.22.5) - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.22.5) - transitivePeerDependencies: - - supports-color dev: false - /@babel/plugin-proposal-class-properties@7.18.6(@babel/core@7.22.5): - resolution: {integrity: sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==} - engines: {node: '>=6.9.0'} + /@babel/plugin-proposal-unicode-property-regex@7.18.6(@babel/core@7.22.5): + resolution: {integrity: sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==} + engines: {node: '>=4'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-create-class-features-plugin': 7.21.4(@babel/core@7.22.5) - '@babel/helper-plugin-utils': 7.20.2 - transitivePeerDependencies: - - supports-color + '@babel/helper-create-regexp-features-plugin': 7.22.5(@babel/core@7.22.5) + '@babel/helper-plugin-utils': 7.22.5 dev: false - /@babel/plugin-proposal-class-static-block@7.21.0(@babel/core@7.22.5): - resolution: {integrity: sha512-XP5G9MWNUskFuP30IfFSEFB0Z6HzLIUcjYM4bYOPHXl7eiJ9HFv8tWj6TXTN5QODiEhDZAeI4hLok2iHFFV4hw==} - engines: {node: '>=6.9.0'} + /@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.22.5): + resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} peerDependencies: - '@babel/core': ^7.12.0 + '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-create-class-features-plugin': 7.21.4(@babel/core@7.22.5) - '@babel/helper-plugin-utils': 7.20.2 - '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.22.5) - transitivePeerDependencies: - - supports-color + '@babel/helper-plugin-utils': 7.22.5 dev: false - /@babel/plugin-proposal-dynamic-import@7.18.6(@babel/core@7.22.5): - resolution: {integrity: sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==} - engines: {node: '>=6.9.0'} + /@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.22.5): + resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-plugin-utils': 7.20.2 - '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.22.5) + '@babel/helper-plugin-utils': 7.22.5 dev: false - /@babel/plugin-proposal-export-namespace-from@7.18.9(@babel/core@7.22.5): - resolution: {integrity: sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==} + /@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.22.5): + resolution: {integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-plugin-utils': 7.20.2 - '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.22.5) + '@babel/helper-plugin-utils': 7.22.5 dev: false - /@babel/plugin-proposal-json-strings@7.18.6(@babel/core@7.22.5): - resolution: {integrity: sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==} - engines: {node: '>=6.9.0'} + /@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.22.5): + resolution: {integrity: sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-plugin-utils': 7.20.2 - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.22.5) + '@babel/helper-plugin-utils': 7.22.5 dev: false - /@babel/plugin-proposal-logical-assignment-operators@7.20.7(@babel/core@7.22.5): - resolution: {integrity: sha512-y7C7cZgpMIjWlKE5T7eJwp+tnRYM89HmRvWM5EQuB5BoHEONjmQ8lSNmBUwOyy/GFRsohJED51YBF79hE1djug==} - engines: {node: '>=6.9.0'} + /@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.22.5): + resolution: {integrity: sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-plugin-utils': 7.20.2 - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.22.5) + '@babel/helper-plugin-utils': 7.22.5 dev: false - /@babel/plugin-proposal-nullish-coalescing-operator@7.18.6(@babel/core@7.22.5): - resolution: {integrity: sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==} + /@babel/plugin-syntax-import-assertions@7.22.5(@babel/core@7.22.5): + resolution: {integrity: sha512-rdV97N7KqsRzeNGoWUOK6yUsWarLjE5Su/Snk9IYPU9CwkWHs4t+rTGOvffTR8XGkJMTAdLfO0xVnXm8wugIJg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-plugin-utils': 7.20.2 - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.22.5) + '@babel/helper-plugin-utils': 7.22.5 dev: false - /@babel/plugin-proposal-numeric-separator@7.18.6(@babel/core@7.22.5): - resolution: {integrity: sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==} + /@babel/plugin-syntax-import-attributes@7.22.5(@babel/core@7.22.5): + resolution: {integrity: sha512-KwvoWDeNKPETmozyFE0P2rOLqh39EoQHNjqizrI5B8Vt0ZNS7M56s7dAiAqbYfiAYOuIzIh96z3iR2ktgu3tEg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-plugin-utils': 7.20.2 - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.22.5) + '@babel/helper-plugin-utils': 7.22.5 dev: false - /@babel/plugin-proposal-object-rest-spread@7.20.7(@babel/core@7.22.5): - resolution: {integrity: sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg==} - engines: {node: '>=6.9.0'} + /@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.22.5): + resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/compat-data': 7.22.5 '@babel/core': 7.22.5 - '@babel/helper-compilation-targets': 7.22.5(@babel/core@7.22.5) - '@babel/helper-plugin-utils': 7.20.2 - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.22.5) - '@babel/plugin-transform-parameters': 7.21.3(@babel/core@7.22.5) + '@babel/helper-plugin-utils': 7.22.5 dev: false - /@babel/plugin-proposal-optional-catch-binding@7.18.6(@babel/core@7.22.5): - resolution: {integrity: sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==} - engines: {node: '>=6.9.0'} + /@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.22.5): + resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-plugin-utils': 7.20.2 - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.22.5) + '@babel/helper-plugin-utils': 7.22.5 dev: false - /@babel/plugin-proposal-optional-chaining@7.21.0(@babel/core@7.22.5): - resolution: {integrity: sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA==} - engines: {node: '>=6.9.0'} + /@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.22.5): + resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-plugin-utils': 7.20.2 - '@babel/helper-skip-transparent-expression-wrappers': 7.20.0 - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.22.5) + '@babel/helper-plugin-utils': 7.22.5 dev: false - /@babel/plugin-proposal-private-methods@7.18.6(@babel/core@7.22.5): - resolution: {integrity: sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==} - engines: {node: '>=6.9.0'} + /@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.22.5): + resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-create-class-features-plugin': 7.21.4(@babel/core@7.22.5) - '@babel/helper-plugin-utils': 7.20.2 - transitivePeerDependencies: - - supports-color + '@babel/helper-plugin-utils': 7.22.5 dev: false - /@babel/plugin-proposal-private-property-in-object@7.21.0(@babel/core@7.22.5): - resolution: {integrity: sha512-ha4zfehbJjc5MmXBlHec1igel5TJXXLDDRbuJ4+XT2TJcyD9/V1919BA8gMvsdHcNMBy4WBUBiRb3nw/EQUtBw==} - engines: {node: '>=6.9.0'} + /@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.22.5): + resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-annotate-as-pure': 7.18.6 - '@babel/helper-create-class-features-plugin': 7.21.4(@babel/core@7.22.5) - '@babel/helper-plugin-utils': 7.20.2 - '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.22.5) - transitivePeerDependencies: - - supports-color + '@babel/helper-plugin-utils': 7.22.5 dev: false - /@babel/plugin-proposal-unicode-property-regex@7.18.6(@babel/core@7.22.5): - resolution: {integrity: sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==} - engines: {node: '>=4'} + /@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.22.5): + resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-create-regexp-features-plugin': 7.21.4(@babel/core@7.22.5) - '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-plugin-utils': 7.22.5 dev: false - /@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.22.5): - resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} + /@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.22.5): + resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-plugin-utils': 7.22.5 dev: false - /@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.22.5): - resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} + /@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.22.5): + resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-plugin-utils': 7.22.5 dev: false - /@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.22.5): - resolution: {integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==} + /@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.22.5): + resolution: {integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-plugin-utils': 7.22.5 dev: false - /@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.22.5): - resolution: {integrity: sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==} + /@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.22.5): + resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} + engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-plugin-utils': 7.22.5 dev: false - /@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.22.5): - resolution: {integrity: sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==} + /@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.22.5): + resolution: {integrity: sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.22.5 + '@babel/helper-create-regexp-features-plugin': 7.21.4(@babel/core@7.22.5) + '@babel/helper-plugin-utils': 7.22.5 + dev: false + + /@babel/plugin-transform-arrow-functions@7.22.5(@babel/core@7.22.5): + resolution: {integrity: sha512-26lTNXoVRdAnsaDXPpvCNUq+OVWEVC6bx7Vvz9rC53F2bagUWW4u4ii2+h8Fejfh7RYqPxn+libeFBBck9muEw==} + engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-plugin-utils': 7.22.5 dev: false - /@babel/plugin-syntax-import-assertions@7.20.0(@babel/core@7.22.5): - resolution: {integrity: sha512-IUh1vakzNoWalR8ch/areW7qFopR2AEw03JlG7BbrDqmQ4X3q9uuipQwSGrUn7oGiemKjtSLDhNtQHzMHr1JdQ==} + /@babel/plugin-transform-async-generator-functions@7.22.5(@babel/core@7.22.5): + resolution: {integrity: sha512-gGOEvFzm3fWoyD5uZq7vVTD57pPJ3PczPUD/xCFGjzBpUosnklmXyKnGQbbbGs1NPNPskFex0j93yKbHt0cHyg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-environment-visitor': 7.22.5 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-remap-async-to-generator': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.22.5) + transitivePeerDependencies: + - supports-color dev: false - /@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.22.5): - resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} + /@babel/plugin-transform-async-to-generator@7.22.5(@babel/core@7.22.5): + resolution: {integrity: sha512-b1A8D8ZzE/VhNDoV1MSJTnpKkCG5bJo+19R4o4oy03zM7ws8yEMK755j61Dc3EyvdysbqH5BOOTquJ7ZX9C6vQ==} + engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-module-imports': 7.22.5 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-remap-async-to-generator': 7.22.5(@babel/core@7.22.5) + transitivePeerDependencies: + - supports-color dev: false - /@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.22.5): - resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} + /@babel/plugin-transform-block-scoped-functions@7.22.5(@babel/core@7.22.5): + resolution: {integrity: sha512-tdXZ2UdknEKQWKJP1KMNmuF5Lx3MymtMN/pvA+p/VEkhK8jVcQ1fzSy8KM9qRYhAf2/lV33hoMPKI/xaI9sADA==} + engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-plugin-utils': 7.22.5 dev: false - /@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.22.5): - resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} + /@babel/plugin-transform-block-scoping@7.22.5(@babel/core@7.22.5): + resolution: {integrity: sha512-EcACl1i5fSQ6bt+YGuU/XGCeZKStLmyVGytWkpyhCLeQVA0eu6Wtiw92V+I1T/hnezUv7j74dA/Ro69gWcU+hg==} + engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-plugin-utils': 7.22.5 dev: false - /@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.22.5): - resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} + /@babel/plugin-transform-class-properties@7.22.5(@babel/core@7.22.5): + resolution: {integrity: sha512-nDkQ0NfkOhPTq8YCLiWNxp1+f9fCobEjCb0n8WdbNUBc4IB5V7P1QnX9IjpSoquKrXF5SKojHleVNs2vGeHCHQ==} + engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-create-class-features-plugin': 7.22.5(@babel/core@7.22.5) + '@babel/helper-plugin-utils': 7.22.5 + transitivePeerDependencies: + - supports-color dev: false - /@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.22.5): - resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} + /@babel/plugin-transform-class-static-block@7.22.5(@babel/core@7.22.5): + resolution: {integrity: sha512-SPToJ5eYZLxlnp1UzdARpOGeC2GbHvr9d/UV0EukuVx8atktg194oe+C5BqQ8jRTkgLRVOPYeXRSBg1IlMoVRA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.12.0 + dependencies: + '@babel/core': 7.22.5 + '@babel/helper-create-class-features-plugin': 7.22.5(@babel/core@7.22.5) + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.22.5) + transitivePeerDependencies: + - supports-color + dev: false + + /@babel/plugin-transform-classes@7.22.5(@babel/core@7.22.5): + resolution: {integrity: sha512-2edQhLfibpWpsVBx2n/GKOz6JdGQvLruZQfGr9l1qes2KQaWswjBzhQF7UDUZMNaMMQeYnQzxwOMPsbYF7wqPQ==} + engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-compilation-targets': 7.22.5(@babel/core@7.22.5) + '@babel/helper-environment-visitor': 7.22.5 + '@babel/helper-function-name': 7.22.5 + '@babel/helper-optimise-call-expression': 7.22.5 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-replace-supers': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.5 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color dev: false - /@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.22.5): - resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} + /@babel/plugin-transform-computed-properties@7.22.5(@babel/core@7.22.5): + resolution: {integrity: sha512-4GHWBgRf0krxPX+AaPtgBAlTgTeZmqDynokHOX7aqqAB4tHs3U2Y02zH6ETFdLZGcg9UQSD1WCmkVrE9ErHeOg==} + engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/template': 7.22.5 dev: false - /@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.22.5): - resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} + /@babel/plugin-transform-destructuring@7.22.5(@babel/core@7.22.5): + resolution: {integrity: sha512-GfqcFuGW8vnEqTUBM7UtPd5A4q797LTvvwKxXTgRsFjoqaJiEg9deBG6kWeQYkVEL569NpnmpC0Pkr/8BLKGnQ==} + engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-plugin-utils': 7.22.5 dev: false - /@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.22.5): - resolution: {integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==} + /@babel/plugin-transform-dotall-regex@7.22.5(@babel/core@7.22.5): + resolution: {integrity: sha512-5/Yk9QxCQCl+sOIB1WelKnVRxTJDSAIxtJLL2/pqL14ZVlbH0fUQUZa/T5/UnQtBNgghR7mfB8ERBKyKPCi7Vw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-create-regexp-features-plugin': 7.22.5(@babel/core@7.22.5) + '@babel/helper-plugin-utils': 7.22.5 dev: false - /@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.22.5): - resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} + /@babel/plugin-transform-duplicate-keys@7.22.5(@babel/core@7.22.5): + resolution: {integrity: sha512-dEnYD+9BBgld5VBXHnF/DbYGp3fqGMsyxKbtD1mDyIA7AkTSpKXFhCVuj/oQVOoALfBs77DudA0BE4d5mcpmqw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-plugin-utils': 7.22.5 dev: false - /@babel/plugin-transform-arrow-functions@7.20.7(@babel/core@7.22.5): - resolution: {integrity: sha512-3poA5E7dzDomxj9WXWwuD6A5F3kc7VXwIJO+E+J8qtDtS+pXPAhrgEyh+9GBwBgPq1Z+bB+/JD60lp5jsN7JPQ==} + /@babel/plugin-transform-dynamic-import@7.22.5(@babel/core@7.22.5): + resolution: {integrity: sha512-0MC3ppTB1AMxd8fXjSrbPa7LT9hrImt+/fcj+Pg5YMD7UQyWp/02+JWpdnCymmsXwIx5Z+sYn1bwCn4ZJNvhqQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.22.5) dev: false - /@babel/plugin-transform-async-to-generator@7.20.7(@babel/core@7.22.5): - resolution: {integrity: sha512-Uo5gwHPT9vgnSXQxqGtpdufUiWp96gk7yiP4Mp5bm1QMkEmLXBO7PAGYbKoJ6DhAwiNkcHFBol/x5zZZkL/t0Q==} + /@babel/plugin-transform-exponentiation-operator@7.22.5(@babel/core@7.22.5): + resolution: {integrity: sha512-vIpJFNM/FjZ4rh1myqIya9jXwrwwgFRHPjT3DkUA9ZLHuzox8jiXkOLvwm1H+PQIP3CqfC++WPKeuDi0Sjdj1g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-module-imports': 7.22.5 - '@babel/helper-plugin-utils': 7.20.2 - '@babel/helper-remap-async-to-generator': 7.18.9(@babel/core@7.22.5) - transitivePeerDependencies: - - supports-color + '@babel/helper-builder-binary-assignment-operator-visitor': 7.22.5 + '@babel/helper-plugin-utils': 7.22.5 dev: false - /@babel/plugin-transform-block-scoped-functions@7.18.6(@babel/core@7.22.5): - resolution: {integrity: sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ==} + /@babel/plugin-transform-export-namespace-from@7.22.5(@babel/core@7.22.5): + resolution: {integrity: sha512-X4hhm7FRnPgd4nDA4b/5V280xCx6oL7Oob5+9qVS5C13Zq4bh1qq7LU0GgRU6b5dBWBvhGaXYVB4AcN6+ol6vg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.22.5) dev: false - /@babel/plugin-transform-block-scoping@7.21.0(@babel/core@7.22.5): - resolution: {integrity: sha512-Mdrbunoh9SxwFZapeHVrwFmri16+oYotcZysSzhNIVDwIAb1UV+kvnxULSYq9J3/q5MDG+4X6w8QVgD1zhBXNQ==} + /@babel/plugin-transform-for-of@7.22.5(@babel/core@7.22.5): + resolution: {integrity: sha512-3kxQjX1dU9uudwSshyLeEipvrLjBCVthCgeTp6CzE/9JYrlAIaeekVxRpCWsDDfYTfRZRoCeZatCQvwo+wvK8A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-plugin-utils': 7.22.5 dev: false - /@babel/plugin-transform-classes@7.21.0(@babel/core@7.22.5): - resolution: {integrity: sha512-RZhbYTCEUAe6ntPehC4hlslPWosNHDox+vAs4On/mCLRLfoDVHf6hVEd7kuxr1RnHwJmxFfUM3cZiZRmPxJPXQ==} + /@babel/plugin-transform-function-name@7.22.5(@babel/core@7.22.5): + resolution: {integrity: sha512-UIzQNMS0p0HHiQm3oelztj+ECwFnj+ZRV4KnguvlsD2of1whUeM6o7wGNj6oLwcDoAXQ8gEqfgC24D+VdIcevg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-annotate-as-pure': 7.18.6 '@babel/helper-compilation-targets': 7.22.5(@babel/core@7.22.5) - '@babel/helper-environment-visitor': 7.22.5 '@babel/helper-function-name': 7.22.5 - '@babel/helper-optimise-call-expression': 7.18.6 - '@babel/helper-plugin-utils': 7.20.2 - '@babel/helper-replace-supers': 7.20.7 - '@babel/helper-split-export-declaration': 7.22.5 - globals: 11.12.0 - transitivePeerDependencies: - - supports-color + '@babel/helper-plugin-utils': 7.22.5 dev: false - /@babel/plugin-transform-computed-properties@7.20.7(@babel/core@7.22.5): - resolution: {integrity: sha512-Lz7MvBK6DTjElHAmfu6bfANzKcxpyNPeYBGEafyA6E5HtRpjpZwU+u7Qrgz/2OR0z+5TvKYbPdphfSaAcZBrYQ==} + /@babel/plugin-transform-json-strings@7.22.5(@babel/core@7.22.5): + resolution: {integrity: sha512-DuCRB7fu8MyTLbEQd1ew3R85nx/88yMoqo2uPSjevMj3yoN7CDM8jkgrY0wmVxfJZyJ/B9fE1iq7EQppWQmR5A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-plugin-utils': 7.20.2 - '@babel/template': 7.22.5 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.22.5) dev: false - /@babel/plugin-transform-destructuring@7.21.3(@babel/core@7.22.5): - resolution: {integrity: sha512-bp6hwMFzuiE4HqYEyoGJ/V2LeIWn+hLVKc4pnj++E5XQptwhtcGmSayM029d/j2X1bPKGTlsyPwAubuU22KhMA==} + /@babel/plugin-transform-literals@7.22.5(@babel/core@7.22.5): + resolution: {integrity: sha512-fTLj4D79M+mepcw3dgFBTIDYpbcB9Sm0bpm4ppXPaO+U+PKFFyV9MGRvS0gvGw62sd10kT5lRMKXAADb9pWy8g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-plugin-utils': 7.22.5 dev: false - /@babel/plugin-transform-dotall-regex@7.18.6(@babel/core@7.22.5): - resolution: {integrity: sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg==} + /@babel/plugin-transform-logical-assignment-operators@7.22.5(@babel/core@7.22.5): + resolution: {integrity: sha512-MQQOUW1KL8X0cDWfbwYP+TbVbZm16QmQXJQ+vndPtH/BoO0lOKpVoEDMI7+PskYxH+IiE0tS8xZye0qr1lGzSA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-create-regexp-features-plugin': 7.21.4(@babel/core@7.22.5) - '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.22.5) dev: false - /@babel/plugin-transform-duplicate-keys@7.18.9(@babel/core@7.22.5): - resolution: {integrity: sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw==} + /@babel/plugin-transform-member-expression-literals@7.22.5(@babel/core@7.22.5): + resolution: {integrity: sha512-RZEdkNtzzYCFl9SE9ATaUMTj2hqMb4StarOJLrZRbqqU4HSBE7UlBw9WBWQiDzrJZJdUWiMTVDI6Gv/8DPvfew==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-plugin-utils': 7.22.5 dev: false - /@babel/plugin-transform-exponentiation-operator@7.18.6(@babel/core@7.22.5): - resolution: {integrity: sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw==} + /@babel/plugin-transform-modules-amd@7.22.5(@babel/core@7.22.5): + resolution: {integrity: sha512-R+PTfLTcYEmb1+kK7FNkhQ1gP4KgjpSO6HfH9+f8/yfp2Nt3ggBjiVpRwmwTlfqZLafYKJACy36yDXlEmI9HjQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-builder-binary-assignment-operator-visitor': 7.18.9 - '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-module-transforms': 7.22.5 + '@babel/helper-plugin-utils': 7.22.5 + transitivePeerDependencies: + - supports-color dev: false - /@babel/plugin-transform-for-of@7.21.0(@babel/core@7.22.5): - resolution: {integrity: sha512-LlUYlydgDkKpIY7mcBWvyPPmMcOphEyYA27Ef4xpbh1IiDNLr0kZsos2nf92vz3IccvJI25QUwp86Eo5s6HmBQ==} + /@babel/plugin-transform-modules-commonjs@7.22.5(@babel/core@7.22.5): + resolution: {integrity: sha512-B4pzOXj+ONRmuaQTg05b3y/4DuFz3WcCNAXPLb2Q0GT0TrGKGxNKV4jwsXts+StaM0LQczZbOpj8o1DLPDJIiA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-module-transforms': 7.22.5 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-simple-access': 7.22.5 + transitivePeerDependencies: + - supports-color dev: false - /@babel/plugin-transform-function-name@7.18.9(@babel/core@7.22.5): - resolution: {integrity: sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ==} + /@babel/plugin-transform-modules-systemjs@7.22.5(@babel/core@7.22.5): + resolution: {integrity: sha512-emtEpoaTMsOs6Tzz+nbmcePl6AKVtS1yC4YNAeMun9U8YCsgadPNxnOPQ8GhHFB2qdx+LZu9LgoC0Lthuu05DQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-compilation-targets': 7.22.5(@babel/core@7.22.5) - '@babel/helper-function-name': 7.22.5 - '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-hoist-variables': 7.22.5 + '@babel/helper-module-transforms': 7.22.5 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-validator-identifier': 7.22.5 + transitivePeerDependencies: + - supports-color dev: false - /@babel/plugin-transform-literals@7.18.9(@babel/core@7.22.5): - resolution: {integrity: sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg==} + /@babel/plugin-transform-modules-umd@7.22.5(@babel/core@7.22.5): + resolution: {integrity: sha512-+S6kzefN/E1vkSsKx8kmQuqeQsvCKCd1fraCM7zXm4SFoggI099Tr4G8U81+5gtMdUeMQ4ipdQffbKLX0/7dBQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-module-transforms': 7.22.5 + '@babel/helper-plugin-utils': 7.22.5 + transitivePeerDependencies: + - supports-color + dev: false + + /@babel/plugin-transform-named-capturing-groups-regex@7.22.5(@babel/core@7.22.5): + resolution: {integrity: sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.22.5 + '@babel/helper-create-regexp-features-plugin': 7.22.5(@babel/core@7.22.5) + '@babel/helper-plugin-utils': 7.22.5 dev: false - /@babel/plugin-transform-member-expression-literals@7.18.6(@babel/core@7.22.5): - resolution: {integrity: sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA==} + /@babel/plugin-transform-new-target@7.22.5(@babel/core@7.22.5): + resolution: {integrity: sha512-AsF7K0Fx/cNKVyk3a+DW0JLo+Ua598/NxMRvxDnkpCIGFh43+h/v2xyhRUYf6oD8gE4QtL83C7zZVghMjHd+iw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-plugin-utils': 7.22.5 dev: false - /@babel/plugin-transform-modules-amd@7.20.11(@babel/core@7.22.5): - resolution: {integrity: sha512-NuzCt5IIYOW0O30UvqktzHYR2ud5bOWbY0yaxWZ6G+aFzOMJvrs5YHNikrbdaT15+KNO31nPOy5Fim3ku6Zb5g==} + /@babel/plugin-transform-nullish-coalescing-operator@7.22.5(@babel/core@7.22.5): + resolution: {integrity: sha512-6CF8g6z1dNYZ/VXok5uYkkBBICHZPiGEl7oDnAx2Mt1hlHVHOSIKWJaXHjQJA5VB43KZnXZDIexMchY4y2PGdA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-module-transforms': 7.22.5 - '@babel/helper-plugin-utils': 7.20.2 - transitivePeerDependencies: - - supports-color + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.22.5) dev: false - /@babel/plugin-transform-modules-commonjs@7.21.2(@babel/core@7.22.5): - resolution: {integrity: sha512-Cln+Yy04Gxua7iPdj6nOV96smLGjpElir5YwzF0LBPKoPlLDNJePNlrGGaybAJkd0zKRnOVXOgizSqPYMNYkzA==} + /@babel/plugin-transform-numeric-separator@7.22.5(@babel/core@7.22.5): + resolution: {integrity: sha512-NbslED1/6M+sXiwwtcAB/nieypGw02Ejf4KtDeMkCEpP6gWFMX1wI9WKYua+4oBneCCEmulOkRpwywypVZzs/g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-module-transforms': 7.22.5 - '@babel/helper-plugin-utils': 7.20.2 - '@babel/helper-simple-access': 7.22.5 - transitivePeerDependencies: - - supports-color + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.22.5) dev: false - /@babel/plugin-transform-modules-systemjs@7.20.11(@babel/core@7.22.5): - resolution: {integrity: sha512-vVu5g9BPQKSFEmvt2TA4Da5N+QVS66EX21d8uoOihC+OCpUoGvzVsXeqFdtAEfVa5BILAeFt+U7yVmLbQnAJmw==} + /@babel/plugin-transform-object-rest-spread@7.22.5(@babel/core@7.22.5): + resolution: {integrity: sha512-Kk3lyDmEslH9DnvCDA1s1kkd3YWQITiBOHngOtDL9Pt6BZjzqb6hiOlb8VfjiiQJ2unmegBqZu0rx5RxJb5vmQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: + '@babel/compat-data': 7.22.5 '@babel/core': 7.22.5 - '@babel/helper-hoist-variables': 7.22.5 - '@babel/helper-module-transforms': 7.22.5 - '@babel/helper-plugin-utils': 7.20.2 - '@babel/helper-validator-identifier': 7.22.5 - transitivePeerDependencies: - - supports-color + '@babel/helper-compilation-targets': 7.22.5(@babel/core@7.22.5) + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.22.5) + '@babel/plugin-transform-parameters': 7.22.5(@babel/core@7.22.5) dev: false - /@babel/plugin-transform-modules-umd@7.18.6(@babel/core@7.22.5): - resolution: {integrity: sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ==} + /@babel/plugin-transform-object-super@7.22.5(@babel/core@7.22.5): + resolution: {integrity: sha512-klXqyaT9trSjIUrcsYIfETAzmOEZL3cBYqOYLJxBHfMFFggmXOv+NYSX/Jbs9mzMVESw/WycLFPRx8ba/b2Ipw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-module-transforms': 7.22.5 - '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-replace-supers': 7.22.5 transitivePeerDependencies: - supports-color dev: false - /@babel/plugin-transform-named-capturing-groups-regex@7.20.5(@babel/core@7.22.5): - resolution: {integrity: sha512-mOW4tTzi5iTLnw+78iEq3gr8Aoq4WNRGpmSlrogqaiCBoR1HFhpU4JkpQFOHfeYx3ReVIFWOQJS4aZBRvuZ6mA==} + /@babel/plugin-transform-optional-catch-binding@7.22.5(@babel/core@7.22.5): + resolution: {integrity: sha512-pH8orJahy+hzZje5b8e2QIlBWQvGpelS76C63Z+jhZKsmzfNaPQ+LaW6dcJ9bxTpo1mtXbgHwy765Ro3jftmUg==} engines: {node: '>=6.9.0'} peerDependencies: - '@babel/core': ^7.0.0 + '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-create-regexp-features-plugin': 7.21.4(@babel/core@7.22.5) - '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.22.5) + dev: false + + /@babel/plugin-transform-optional-chaining@7.22.5(@babel/core@7.22.5): + resolution: {integrity: sha512-AconbMKOMkyG+xCng2JogMCDcqW8wedQAqpVIL4cOSescZ7+iW8utC6YDZLMCSUIReEA733gzRSaOSXMAt/4WQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.5 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.22.5) dev: false - /@babel/plugin-transform-new-target@7.18.6(@babel/core@7.22.5): - resolution: {integrity: sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw==} + /@babel/plugin-transform-parameters@7.22.5(@babel/core@7.22.5): + resolution: {integrity: sha512-AVkFUBurORBREOmHRKo06FjHYgjrabpdqRSwq6+C7R5iTCZOsM4QbcB27St0a4U6fffyAOqh3s/qEfybAhfivg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-plugin-utils': 7.22.5 dev: false - /@babel/plugin-transform-object-super@7.18.6(@babel/core@7.22.5): - resolution: {integrity: sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA==} + /@babel/plugin-transform-private-methods@7.22.5(@babel/core@7.22.5): + resolution: {integrity: sha512-PPjh4gyrQnGe97JTalgRGMuU4icsZFnWkzicB/fUtzlKUqvsWBKEpPPfr5a2JiyirZkHxnAqkQMO5Z5B2kK3fA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-plugin-utils': 7.20.2 - '@babel/helper-replace-supers': 7.20.7 + '@babel/helper-create-class-features-plugin': 7.22.5(@babel/core@7.22.5) + '@babel/helper-plugin-utils': 7.22.5 transitivePeerDependencies: - supports-color dev: false - /@babel/plugin-transform-parameters@7.21.3(@babel/core@7.22.5): - resolution: {integrity: sha512-Wxc+TvppQG9xWFYatvCGPvZ6+SIUxQ2ZdiBP+PHYMIjnPXD+uThCshaz4NZOnODAtBjjcVQQ/3OKs9LW28purQ==} + /@babel/plugin-transform-private-property-in-object@7.22.5(@babel/core@7.22.5): + resolution: {integrity: sha512-/9xnaTTJcVoBtSSmrVyhtSvO3kbqS2ODoh2juEU72c3aYonNF0OMGiaz2gjukyKM2wBBYJP38S4JiE0Wfb5VMQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-create-class-features-plugin': 7.22.5(@babel/core@7.22.5) + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.22.5) + transitivePeerDependencies: + - supports-color dev: false - /@babel/plugin-transform-property-literals@7.18.6(@babel/core@7.22.5): - resolution: {integrity: sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg==} + /@babel/plugin-transform-property-literals@7.22.5(@babel/core@7.22.5): + resolution: {integrity: sha512-TiOArgddK3mK/x1Qwf5hay2pxI6wCZnvQqrFSqbtg1GLl2JcNMitVH/YnqjP+M31pLUeTfzY1HAXFDnUBV30rQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-plugin-utils': 7.22.5 dev: false - /@babel/plugin-transform-react-jsx-self@7.21.0(@babel/core@7.22.5): - resolution: {integrity: sha512-f/Eq+79JEu+KUANFks9UZCcvydOOGMgF7jBrcwjHa5jTZD8JivnhCJYvmlhR/WTXBWonDExPoW0eO/CR4QJirA==} + /@babel/plugin-transform-react-jsx-self@7.22.5(@babel/core@7.22.5): + resolution: {integrity: sha512-nTh2ogNUtxbiSbxaT4Ds6aXnXEipHweN9YRgOX/oNXdf0cCrGn/+2LozFa3lnPV5D90MkjhgckCPBrsoSc1a7g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-plugin-utils': 7.22.5 dev: false - /@babel/plugin-transform-react-jsx-source@7.19.6(@babel/core@7.22.5): - resolution: {integrity: sha512-RpAi004QyMNisst/pvSanoRdJ4q+jMCWyk9zdw/CyLB9j8RXEahodR6l2GyttDRyEVWZtbN+TpLiHJ3t34LbsQ==} + /@babel/plugin-transform-react-jsx-source@7.22.5(@babel/core@7.22.5): + resolution: {integrity: sha512-yIiRO6yobeEIaI0RTbIr8iAK9FcBHLtZq0S89ZPjDLQXBA4xvghaKqI0etp/tF3htTM0sazJKKLz9oEiGRtu7w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-plugin-utils': 7.22.5 dev: false - /@babel/plugin-transform-regenerator@7.20.5(@babel/core@7.22.5): - resolution: {integrity: sha512-kW/oO7HPBtntbsahzQ0qSE3tFvkFwnbozz3NWFhLGqH75vLEg+sCGngLlhVkePlCs3Jv0dBBHDzCHxNiFAQKCQ==} + /@babel/plugin-transform-regenerator@7.22.5(@babel/core@7.22.5): + resolution: {integrity: sha512-rR7KePOE7gfEtNTh9Qw+iO3Q/e4DEsoQ+hdvM6QUDH7JRJ5qxq5AA52ZzBWbI5i9lfNuvySgOGP8ZN7LAmaiPw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-plugin-utils': 7.22.5 regenerator-transform: 0.15.1 dev: false - /@babel/plugin-transform-reserved-words@7.18.6(@babel/core@7.22.5): - resolution: {integrity: sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA==} + /@babel/plugin-transform-reserved-words@7.22.5(@babel/core@7.22.5): + resolution: {integrity: sha512-DTtGKFRQUDm8svigJzZHzb/2xatPc6TzNvAIJ5GqOKDsGFYgAskjRulbR/vGsPKq3OPqtexnz327qYpP57RFyA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-plugin-utils': 7.22.5 dev: false - /@babel/plugin-transform-shorthand-properties@7.18.6(@babel/core@7.22.5): - resolution: {integrity: sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw==} + /@babel/plugin-transform-shorthand-properties@7.22.5(@babel/core@7.22.5): + resolution: {integrity: sha512-vM4fq9IXHscXVKzDv5itkO1X52SmdFBFcMIBZ2FRn2nqVYqw6dBexUgMvAjHW+KXpPPViD/Yo3GrDEBaRC0QYA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-plugin-utils': 7.22.5 dev: false - /@babel/plugin-transform-spread@7.20.7(@babel/core@7.22.5): - resolution: {integrity: sha512-ewBbHQ+1U/VnH1fxltbJqDeWBU1oNLG8Dj11uIv3xVf7nrQu0bPGe5Rf716r7K5Qz+SqtAOVswoVunoiBtGhxw==} + /@babel/plugin-transform-spread@7.22.5(@babel/core@7.22.5): + resolution: {integrity: sha512-5ZzDQIGyvN4w8+dMmpohL6MBo+l2G7tfC/O2Dg7/hjpgeWvUx8FzfeOKxGog9IimPa4YekaQ9PlDqTLOljkcxg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-plugin-utils': 7.20.2 - '@babel/helper-skip-transparent-expression-wrappers': 7.20.0 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 dev: false - /@babel/plugin-transform-sticky-regex@7.18.6(@babel/core@7.22.5): - resolution: {integrity: sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q==} + /@babel/plugin-transform-sticky-regex@7.22.5(@babel/core@7.22.5): + resolution: {integrity: sha512-zf7LuNpHG0iEeiyCNwX4j3gDg1jgt1k3ZdXBKbZSoA3BbGQGvMiSvfbZRR3Dr3aeJe3ooWFZxOOG3IRStYp2Bw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-plugin-utils': 7.22.5 dev: false - /@babel/plugin-transform-template-literals@7.18.9(@babel/core@7.22.5): - resolution: {integrity: sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==} + /@babel/plugin-transform-template-literals@7.22.5(@babel/core@7.22.5): + resolution: {integrity: sha512-5ciOehRNf+EyUeewo8NkbQiUs4d6ZxiHo6BcBcnFlgiJfu16q0bQUw9Jvo0b0gBKFG1SMhDSjeKXSYuJLeFSMA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-plugin-utils': 7.22.5 dev: false - /@babel/plugin-transform-typeof-symbol@7.18.9(@babel/core@7.22.5): - resolution: {integrity: sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw==} + /@babel/plugin-transform-typeof-symbol@7.22.5(@babel/core@7.22.5): + resolution: {integrity: sha512-bYkI5lMzL4kPii4HHEEChkD0rkc+nvnlR6+o/qdqR6zrm0Sv/nodmyLhlq2DO0YKLUNd2VePmPRjJXSBh9OIdA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-plugin-utils': 7.22.5 dev: false - /@babel/plugin-transform-unicode-escapes@7.18.10(@babel/core@7.22.5): - resolution: {integrity: sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ==} + /@babel/plugin-transform-unicode-escapes@7.22.5(@babel/core@7.22.5): + resolution: {integrity: sha512-biEmVg1IYB/raUO5wT1tgfacCef15Fbzhkx493D3urBI++6hpJ+RFG4SrWMn0NEZLfvilqKf3QDrRVZHo08FYg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-plugin-utils': 7.22.5 dev: false - /@babel/plugin-transform-unicode-regex@7.18.6(@babel/core@7.22.5): - resolution: {integrity: sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA==} + /@babel/plugin-transform-unicode-property-regex@7.22.5(@babel/core@7.22.5): + resolution: {integrity: sha512-HCCIb+CbJIAE6sXn5CjFQXMwkCClcOfPCzTlilJ8cUatfzwHlWQkbtV0zD338u9dZskwvuOYTuuaMaA8J5EI5A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-create-regexp-features-plugin': 7.21.4(@babel/core@7.22.5) - '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-create-regexp-features-plugin': 7.22.5(@babel/core@7.22.5) + '@babel/helper-plugin-utils': 7.22.5 dev: false - /@babel/preset-env@7.21.4(@babel/core@7.22.5): - resolution: {integrity: sha512-2W57zHs2yDLm6GD5ZpvNn71lZ0B/iypSdIeq25OurDKji6AdzV07qp4s3n1/x5BqtiGaTrPN3nerlSCaC5qNTw==} + /@babel/plugin-transform-unicode-regex@7.22.5(@babel/core@7.22.5): + resolution: {integrity: sha512-028laaOKptN5vHJf9/Arr/HiJekMd41hOEZYvNsrsXqJ7YPYuX2bQxh31fkZzGmq3YqHRJzYFFAVYvKfMPKqyg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.5 + '@babel/helper-create-regexp-features-plugin': 7.22.5(@babel/core@7.22.5) + '@babel/helper-plugin-utils': 7.22.5 + dev: false + + /@babel/plugin-transform-unicode-sets-regex@7.22.5(@babel/core@7.22.5): + resolution: {integrity: sha512-lhMfi4FC15j13eKrh3DnYHjpGj6UKQHtNKTbtc1igvAhRy4+kLhV07OpLcsN0VgDEw/MjAvJO4BdMJsHwMhzCg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.22.5 + '@babel/helper-create-regexp-features-plugin': 7.22.5(@babel/core@7.22.5) + '@babel/helper-plugin-utils': 7.22.5 + dev: false + + /@babel/preset-env@7.22.5(@babel/core@7.22.5): + resolution: {integrity: sha512-fj06hw89dpiZzGZtxn+QybifF07nNiZjZ7sazs2aVDcysAZVGjW7+7iFYxg6GLNM47R/thYfLdrXc+2f11Vi9A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1326,31 +1395,19 @@ packages: '@babel/compat-data': 7.22.5 '@babel/core': 7.22.5 '@babel/helper-compilation-targets': 7.22.5(@babel/core@7.22.5) - '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-plugin-utils': 7.22.5 '@babel/helper-validator-option': 7.22.5 - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.18.6(@babel/core@7.22.5) - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.20.7(@babel/core@7.22.5) - '@babel/plugin-proposal-async-generator-functions': 7.20.7(@babel/core@7.22.5) - '@babel/plugin-proposal-class-properties': 7.18.6(@babel/core@7.22.5) - '@babel/plugin-proposal-class-static-block': 7.21.0(@babel/core@7.22.5) - '@babel/plugin-proposal-dynamic-import': 7.18.6(@babel/core@7.22.5) - '@babel/plugin-proposal-export-namespace-from': 7.18.9(@babel/core@7.22.5) - '@babel/plugin-proposal-json-strings': 7.18.6(@babel/core@7.22.5) - '@babel/plugin-proposal-logical-assignment-operators': 7.20.7(@babel/core@7.22.5) - '@babel/plugin-proposal-nullish-coalescing-operator': 7.18.6(@babel/core@7.22.5) - '@babel/plugin-proposal-numeric-separator': 7.18.6(@babel/core@7.22.5) - '@babel/plugin-proposal-object-rest-spread': 7.20.7(@babel/core@7.22.5) - '@babel/plugin-proposal-optional-catch-binding': 7.18.6(@babel/core@7.22.5) - '@babel/plugin-proposal-optional-chaining': 7.21.0(@babel/core@7.22.5) - '@babel/plugin-proposal-private-methods': 7.18.6(@babel/core@7.22.5) - '@babel/plugin-proposal-private-property-in-object': 7.21.0(@babel/core@7.22.5) - '@babel/plugin-proposal-unicode-property-regex': 7.18.6(@babel/core@7.22.5) + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.22.5) '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.22.5) '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.22.5) '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.22.5) '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.22.5) '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.22.5) - '@babel/plugin-syntax-import-assertions': 7.20.0(@babel/core@7.22.5) + '@babel/plugin-syntax-import-assertions': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-syntax-import-attributes': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.22.5) '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.22.5) '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.22.5) '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.22.5) @@ -1360,44 +1417,61 @@ packages: '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.22.5) '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.22.5) '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.22.5) - '@babel/plugin-transform-arrow-functions': 7.20.7(@babel/core@7.22.5) - '@babel/plugin-transform-async-to-generator': 7.20.7(@babel/core@7.22.5) - '@babel/plugin-transform-block-scoped-functions': 7.18.6(@babel/core@7.22.5) - '@babel/plugin-transform-block-scoping': 7.21.0(@babel/core@7.22.5) - '@babel/plugin-transform-classes': 7.21.0(@babel/core@7.22.5) - '@babel/plugin-transform-computed-properties': 7.20.7(@babel/core@7.22.5) - '@babel/plugin-transform-destructuring': 7.21.3(@babel/core@7.22.5) - '@babel/plugin-transform-dotall-regex': 7.18.6(@babel/core@7.22.5) - '@babel/plugin-transform-duplicate-keys': 7.18.9(@babel/core@7.22.5) - '@babel/plugin-transform-exponentiation-operator': 7.18.6(@babel/core@7.22.5) - '@babel/plugin-transform-for-of': 7.21.0(@babel/core@7.22.5) - '@babel/plugin-transform-function-name': 7.18.9(@babel/core@7.22.5) - '@babel/plugin-transform-literals': 7.18.9(@babel/core@7.22.5) - '@babel/plugin-transform-member-expression-literals': 7.18.6(@babel/core@7.22.5) - '@babel/plugin-transform-modules-amd': 7.20.11(@babel/core@7.22.5) - '@babel/plugin-transform-modules-commonjs': 7.21.2(@babel/core@7.22.5) - '@babel/plugin-transform-modules-systemjs': 7.20.11(@babel/core@7.22.5) - '@babel/plugin-transform-modules-umd': 7.18.6(@babel/core@7.22.5) - '@babel/plugin-transform-named-capturing-groups-regex': 7.20.5(@babel/core@7.22.5) - '@babel/plugin-transform-new-target': 7.18.6(@babel/core@7.22.5) - '@babel/plugin-transform-object-super': 7.18.6(@babel/core@7.22.5) - '@babel/plugin-transform-parameters': 7.21.3(@babel/core@7.22.5) - '@babel/plugin-transform-property-literals': 7.18.6(@babel/core@7.22.5) - '@babel/plugin-transform-regenerator': 7.20.5(@babel/core@7.22.5) - '@babel/plugin-transform-reserved-words': 7.18.6(@babel/core@7.22.5) - '@babel/plugin-transform-shorthand-properties': 7.18.6(@babel/core@7.22.5) - '@babel/plugin-transform-spread': 7.20.7(@babel/core@7.22.5) - '@babel/plugin-transform-sticky-regex': 7.18.6(@babel/core@7.22.5) - '@babel/plugin-transform-template-literals': 7.18.9(@babel/core@7.22.5) - '@babel/plugin-transform-typeof-symbol': 7.18.9(@babel/core@7.22.5) - '@babel/plugin-transform-unicode-escapes': 7.18.10(@babel/core@7.22.5) - '@babel/plugin-transform-unicode-regex': 7.18.6(@babel/core@7.22.5) + '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.22.5) + '@babel/plugin-transform-arrow-functions': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-async-generator-functions': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-async-to-generator': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-block-scoped-functions': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-block-scoping': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-class-properties': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-class-static-block': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-classes': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-computed-properties': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-destructuring': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-dotall-regex': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-duplicate-keys': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-dynamic-import': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-exponentiation-operator': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-export-namespace-from': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-for-of': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-function-name': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-json-strings': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-literals': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-logical-assignment-operators': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-member-expression-literals': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-modules-amd': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-modules-commonjs': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-modules-systemjs': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-modules-umd': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-named-capturing-groups-regex': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-new-target': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-nullish-coalescing-operator': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-numeric-separator': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-object-rest-spread': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-object-super': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-optional-catch-binding': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-optional-chaining': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-parameters': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-private-methods': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-private-property-in-object': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-property-literals': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-regenerator': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-reserved-words': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-shorthand-properties': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-spread': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-sticky-regex': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-template-literals': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-typeof-symbol': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-unicode-escapes': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-unicode-property-regex': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-unicode-regex': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-unicode-sets-regex': 7.22.5(@babel/core@7.22.5) '@babel/preset-modules': 0.1.5(@babel/core@7.22.5) '@babel/types': 7.22.5 - babel-plugin-polyfill-corejs2: 0.3.3(@babel/core@7.22.5) - babel-plugin-polyfill-corejs3: 0.6.0(@babel/core@7.22.5) - babel-plugin-polyfill-regenerator: 0.4.1(@babel/core@7.22.5) - core-js-compat: 3.30.1 + babel-plugin-polyfill-corejs2: 0.4.3(@babel/core@7.22.5) + babel-plugin-polyfill-corejs3: 0.8.1(@babel/core@7.22.5) + babel-plugin-polyfill-regenerator: 0.5.0(@babel/core@7.22.5) + core-js-compat: 3.31.0 semver: 6.3.0 transitivePeerDependencies: - supports-color @@ -1409,9 +1483,9 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-proposal-unicode-property-regex': 7.18.6(@babel/core@7.22.5) - '@babel/plugin-transform-dotall-regex': 7.18.6(@babel/core@7.22.5) + '@babel/plugin-transform-dotall-regex': 7.22.5(@babel/core@7.22.5) '@babel/types': 7.22.5 esutils: 2.0.3 dev: false @@ -1578,7 +1652,7 @@ packages: resolution: {integrity: sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA==} dev: true - /@emotion/react@11.10.6(@types/react@18.2.11)(react@18.2.0): + /@emotion/react@11.10.6(@types/react@18.2.14)(react@18.2.0): resolution: {integrity: sha512-6HT8jBmcSkfzO7mc+N1L9uwvOnlcGoix8Zn7srt+9ga0MjREo6lRpuVX0kzo6Jp6oTqDhREOFsygN6Ew4fEQbw==} peerDependencies: '@types/react': '*' @@ -1594,7 +1668,7 @@ packages: '@emotion/use-insertion-effect-with-fallbacks': 1.0.0(react@18.2.0) '@emotion/utils': 1.2.0 '@emotion/weak-memoize': 0.3.0 - '@types/react': 18.2.11 + '@types/react': 18.2.14 hoist-non-react-statics: 3.3.2 react: 18.2.0 dev: true @@ -1613,7 +1687,7 @@ packages: resolution: {integrity: sha512-zxRBwl93sHMsOj4zs+OslQKg/uhF38MB+OMKoCrVuS0nyTkqnau+BM3WGEoOptg9Oz45T/aIGs1qbVAsEFo3nA==} dev: true - /@emotion/styled@11.10.6(@emotion/react@11.10.6)(@types/react@18.2.11)(react@18.2.0): + /@emotion/styled@11.10.6(@emotion/react@11.10.6)(@types/react@18.2.14)(react@18.2.0): resolution: {integrity: sha512-OXtBzOmDSJo5Q0AFemHCfl+bUueT8BIcPSxu0EGTpGk6DmI5dnhSzQANm1e1ze0YZL7TDyAyy6s/b/zmGOS3Og==} peerDependencies: '@emotion/react': ^11.0.0-rc.0 @@ -1626,11 +1700,11 @@ packages: '@babel/runtime': 7.21.0 '@emotion/babel-plugin': 11.10.6 '@emotion/is-prop-valid': 1.2.0 - '@emotion/react': 11.10.6(@types/react@18.2.11)(react@18.2.0) + '@emotion/react': 11.10.6(@types/react@18.2.14)(react@18.2.0) '@emotion/serialize': 1.1.1 '@emotion/use-insertion-effect-with-fallbacks': 1.0.0(react@18.2.0) '@emotion/utils': 1.2.0 - '@types/react': 18.2.11 + '@types/react': 18.2.14 react: 18.2.0 dev: true @@ -1662,8 +1736,8 @@ packages: requiresBuild: true optional: true - /@esbuild/android-arm64@0.18.1: - resolution: {integrity: sha512-l5V0IWGTYfQMzl4ulgIHKMZPwabIS4a39ZvtkPwL6LYiX3UtL76sylA6eFKufJCB43mwEYqbXoBSMn++NpxILw==} + /@esbuild/android-arm64@0.18.10: + resolution: {integrity: sha512-ynm4naLbNbK0ajf9LUWtQB+6Vfg1Z/AplArqr4tGebC00Z6m9Y91OVIcjDa461wGcZwcaHYaZAab4yJxfhisTQ==} engines: {node: '>=12'} cpu: [arm64] os: [android] @@ -1679,8 +1753,8 @@ packages: requiresBuild: true optional: true - /@esbuild/android-arm@0.18.1: - resolution: {integrity: sha512-8+QS98jqdreHLvCojIke8NjcuelB+Osysazr15EhkUIuG0Ov5WK26XgPYWViCTjHnKQxbpS86/JryBOkEpyrBA==} + /@esbuild/android-arm@0.18.10: + resolution: {integrity: sha512-3KClmVNd+Fku82uZJz5C4Rx8m1PPmWUFz5Zkw8jkpZPOmsq+EG1TTOtw1OXkHuX3WczOFQigrtf60B1ijKwNsg==} engines: {node: '>=12'} cpu: [arm] os: [android] @@ -1696,8 +1770,8 @@ packages: requiresBuild: true optional: true - /@esbuild/android-x64@0.18.1: - resolution: {integrity: sha512-1y8/bRek6EYxQeGTUfwL2mmj6NAeXZ3h5YSc4W2Y/kduI1B8VhT4x5X0VxrcGkIKef4N5qCdziRxvei/YUfESg==} + /@esbuild/android-x64@0.18.10: + resolution: {integrity: sha512-vFfXj8P9Yfjh54yqUDEHKzqzYuEfPyAOl3z7R9hjkwt+NCvbn9VMxX+IILnAfdImRBfYVItgSUsqGKhJFnBwZw==} engines: {node: '>=12'} cpu: [x64] os: [android] @@ -1713,8 +1787,8 @@ packages: requiresBuild: true optional: true - /@esbuild/darwin-arm64@0.18.1: - resolution: {integrity: sha512-FFT/on9qQTOntdloQvgfwFkRhNI5l/TCNXZS1CpH6JQd0boR637aThi9g9FYs4o31Ao72/jPZFDiRln5Cu6R2A==} + /@esbuild/darwin-arm64@0.18.10: + resolution: {integrity: sha512-k2OJQ7ZxE6sVc91+MQeZH9gFeDAH2uIYALPAwTjTCvcPy9Dzrf7V7gFUQPYkn09zloWhQ+nvxWHia2x2ZLR0sQ==} engines: {node: '>=12'} cpu: [arm64] os: [darwin] @@ -1730,8 +1804,8 @@ packages: requiresBuild: true optional: true - /@esbuild/darwin-x64@0.18.1: - resolution: {integrity: sha512-p/ZIUt+NlW8qRNVTXoKJgRuc49teazvmXBquoGOm5D6IAimTfWJVJrEivqpoMKyDS/0/PxDMRM2lrkxlSa7XeQ==} + /@esbuild/darwin-x64@0.18.10: + resolution: {integrity: sha512-tnz/mdZk1L1Z3WpGjin/L2bKTe8/AKZpI8fcCLtH+gq8WXWsCNJSxlesAObV4qbtTl6pG5vmqFXfWUQ5hV8PAQ==} engines: {node: '>=12'} cpu: [x64] os: [darwin] @@ -1747,8 +1821,8 @@ packages: requiresBuild: true optional: true - /@esbuild/freebsd-arm64@0.18.1: - resolution: {integrity: sha512-eYUDR3thO96ULRf4rJcG9TJ/sQc6Z/YNe16mC/KvVeAOtzmeTXiPMETEv/iMqTCxZhYkHyQG/mYbAxPBWC2mcg==} + /@esbuild/freebsd-arm64@0.18.10: + resolution: {integrity: sha512-QJluV0LwBrbHnYYwSKC+K8RGz0g/EyhpQH1IxdoFT0nM7PfgjE+aS8wxq/KFEsU0JkL7U/EEKd3O8xVBxXb2aA==} engines: {node: '>=12'} cpu: [arm64] os: [freebsd] @@ -1764,8 +1838,8 @@ packages: requiresBuild: true optional: true - /@esbuild/freebsd-x64@0.18.1: - resolution: {integrity: sha512-w03zjxyg51qktv0JKsV+AbY3uSb1Awifs8IkKQSUXdP3sdPxxmPzZLrlJ1+LjKZRiSa4yP/Haayi/hriNVoIdQ==} + /@esbuild/freebsd-x64@0.18.10: + resolution: {integrity: sha512-Hi/ycUkS6KTw+U9G5PK5NoK7CZboicaKUSVs0FSiPNtuCTzK6HNM4DIgniH7hFaeuszDS9T4dhAHWiLSt/Y5Ng==} engines: {node: '>=12'} cpu: [x64] os: [freebsd] @@ -1781,8 +1855,8 @@ packages: requiresBuild: true optional: true - /@esbuild/linux-arm64@0.18.1: - resolution: {integrity: sha512-dHlvkKAVlYNt5LPg1GUha99QiaEGKEC21zpHVAxs7hhW6EkR8nN3iWmyndGXxVJm4K7e4lKAzl8ekPqSr5gAXQ==} + /@esbuild/linux-arm64@0.18.10: + resolution: {integrity: sha512-Nz6XcfRBOO7jSrVpKAyEyFOPGhySPNlgumSDhWAspdQQ11ub/7/NZDMhWDFReE9QH/SsCOCLQbdj0atAk/HMOQ==} engines: {node: '>=12'} cpu: [arm64] os: [linux] @@ -1798,8 +1872,8 @@ packages: requiresBuild: true optional: true - /@esbuild/linux-arm@0.18.1: - resolution: {integrity: sha512-d6FXeb8F/cuXtSZuVHQN0Rz3gs3g2Xy/M4KJJRzbKsBx3pwCQuRdSrYxcr7g0PFN8geIOspiLQnUzwONyMA3Bw==} + /@esbuild/linux-arm@0.18.10: + resolution: {integrity: sha512-HfFoxY172tVHPIvJy+FHxzB4l8xU7e5cxmNS11cQ2jt4JWAukn/7LXaPdZid41UyTweqa4P/1zs201gRGCTwHw==} engines: {node: '>=12'} cpu: [arm] os: [linux] @@ -1815,8 +1889,8 @@ packages: requiresBuild: true optional: true - /@esbuild/linux-ia32@0.18.1: - resolution: {integrity: sha512-QHS4duBPuAsLZP82sNeoqTXAJ1mNU4QcfmYtBN/jNvQJXb6n0im8F4ljFSAQbivt1jl1OnKL8HhlLUeKY75nLg==} + /@esbuild/linux-ia32@0.18.10: + resolution: {integrity: sha512-otMdmSmkMe+pmiP/bZBjfphyAsTsngyT9RCYwoFzqrveAbux9nYitDTpdgToG0Z0U55+PnH654gCH2GQ1aB6Yw==} engines: {node: '>=12'} cpu: [ia32] os: [linux] @@ -1832,8 +1906,8 @@ packages: requiresBuild: true optional: true - /@esbuild/linux-loong64@0.18.1: - resolution: {integrity: sha512-g4YSiF/qBvXvJhSowxaR7Ei/79otL48Qfjviuo+FpXREykA9nSe407T5ZvezFXryFgdf44Fe8lWpjvtQ+n42cQ==} + /@esbuild/linux-loong64@0.18.10: + resolution: {integrity: sha512-t8tjFuON1koxskzQ4VFoh0T5UDUMiLYjwf9Wktd0tx8AoK6xgU+5ubKOpWpcnhEQ2tESS5u0v6QuN8PX/ftwcQ==} engines: {node: '>=12'} cpu: [loong64] os: [linux] @@ -1849,8 +1923,8 @@ packages: requiresBuild: true optional: true - /@esbuild/linux-mips64el@0.18.1: - resolution: {integrity: sha512-/G1fzmaR5u2S9wgQhiQEhWRct0+GMpuNjhll59uv5Tjojlma9MUPinVnvpw9Re+Idb6gxe6kmzUxFP2YkC/svg==} + /@esbuild/linux-mips64el@0.18.10: + resolution: {integrity: sha512-+dUkcVzcfEJHz3HEnVpIJu8z8Wdn2n/nWMWdl6FVPFGJAVySO4g3+XPzNKFytVFwf8hPVDwYXzVcu8GMFqsqZw==} engines: {node: '>=12'} cpu: [mips64el] os: [linux] @@ -1866,8 +1940,8 @@ packages: requiresBuild: true optional: true - /@esbuild/linux-ppc64@0.18.1: - resolution: {integrity: sha512-NkDjIvleUc3lSV1VI3QE9Oh5mz3nY11H5TCbi4DJ8X09FGwHN5pDVXdAsQYPGjlt/frXZzq6x7vMmTOb5VyBog==} + /@esbuild/linux-ppc64@0.18.10: + resolution: {integrity: sha512-sO3PjjxEGy+PY2qkGe2gwJbXdZN9wAYpVBZWFD0AwAoKuXRkWK0/zaMQ5ekUFJDRDCRm8x5U0Axaub7ynH/wVg==} engines: {node: '>=12'} cpu: [ppc64] os: [linux] @@ -1883,8 +1957,8 @@ packages: requiresBuild: true optional: true - /@esbuild/linux-riscv64@0.18.1: - resolution: {integrity: sha512-IhN7Nz+HyDRnMQOLcCl6m5BgQMITMhS9O1hOqgAUIy6FI0m/0zTSkZHtvMmSIpOy1uleaGqfNDA9SM3nBeTATQ==} + /@esbuild/linux-riscv64@0.18.10: + resolution: {integrity: sha512-JDtdbJg3yjDeXLv4lZYE1kiTnxv73/8cbPHY9T/dUKi8rYOM/k5b3W4UJLMUksuQ6nTm5c89W1nADsql6FW75A==} engines: {node: '>=12'} cpu: [riscv64] os: [linux] @@ -1900,8 +1974,8 @@ packages: requiresBuild: true optional: true - /@esbuild/linux-s390x@0.18.1: - resolution: {integrity: sha512-u9iRg0eUUIyBbg5hANvRBYRaAnhVemAA2+pi3IgrzQTMeR/uPHQtJI3XInNZkNR6ACA4Fdl8N941p81XygeqWQ==} + /@esbuild/linux-s390x@0.18.10: + resolution: {integrity: sha512-NLuSKcp8WckjD2a7z5kzLiCywFwBTMlIxDNuud1AUGVuwBBJSkuubp6cNjJ0p5c6CZaA3QqUGwjHJBiG1SoOFw==} engines: {node: '>=12'} cpu: [s390x] os: [linux] @@ -1917,8 +1991,8 @@ packages: requiresBuild: true optional: true - /@esbuild/linux-x64@0.18.1: - resolution: {integrity: sha512-0QeWU0a0+RmxPCDt+plXS7/hVMJtfde/LaSzs6X3UTr4FYA0hYpnwDzGXxumcPLzt5c8ctugPuKat0tmRb7noQ==} + /@esbuild/linux-x64@0.18.10: + resolution: {integrity: sha512-wj2KRsCsFusli+6yFgNO/zmmLslislAWryJnodteRmGej7ZzinIbMdsyp13rVGde88zxJd5vercNYK9kuvlZaQ==} engines: {node: '>=12'} cpu: [x64] os: [linux] @@ -1934,8 +2008,8 @@ packages: requiresBuild: true optional: true - /@esbuild/netbsd-x64@0.18.1: - resolution: {integrity: sha512-eFL7sxibN8wKuwrRf3HRkcjELALlfl/TavJ8P4J+BJfnkXOITF7zx4tTmGkzK8OwAR9snT2kEfp1Ictc80atGw==} + /@esbuild/netbsd-x64@0.18.10: + resolution: {integrity: sha512-pQ9QqxEPI3cVRZyUtCoZxhZK3If+7RzR8L2yz2+TDzdygofIPOJFaAPkEJ5rYIbUO101RaiYxfdOBahYexLk5A==} engines: {node: '>=12'} cpu: [x64] os: [netbsd] @@ -1951,8 +2025,8 @@ packages: requiresBuild: true optional: true - /@esbuild/openbsd-x64@0.18.1: - resolution: {integrity: sha512-riCQUnngF2xYUzr0XDdrGEEz0nqnocch0No7SBIQM22wTRi5gt5WqTQexGd/2u2Z19d0rVYQbKBelaJ1dwe9bg==} + /@esbuild/openbsd-x64@0.18.10: + resolution: {integrity: sha512-k8GTIIW9I8pEEfoOUm32TpPMgSg06JhL5DO+ql66aLTkOQUs0TxCA67Wi7pv6z8iF8STCGcNbm3UWFHLuci+ag==} engines: {node: '>=12'} cpu: [x64] os: [openbsd] @@ -1968,8 +2042,8 @@ packages: requiresBuild: true optional: true - /@esbuild/sunos-x64@0.18.1: - resolution: {integrity: sha512-6lTop2k+GMkWlrwMy2+55xIBXKfXOi6uzWYypXZZP8HxXG3Mb5N4O71z2KzisVNJtYK2VlQRNbmGtUzIQIhHAw==} + /@esbuild/sunos-x64@0.18.10: + resolution: {integrity: sha512-vIGYJIdEI6d4JBucAx8py792G8J0GP40qSH+EvSt80A4zvGd6jph+5t1g+eEXcS2aRpgZw6CrssNCFZxTdEsxw==} engines: {node: '>=12'} cpu: [x64] os: [sunos] @@ -1985,8 +2059,8 @@ packages: requiresBuild: true optional: true - /@esbuild/win32-arm64@0.18.1: - resolution: {integrity: sha512-d6wt4g9GluZp7xCmgpm7gY6wy0mjcBHbKeeK9MYrlWNFJd8KBcD2uCil8kFuaH3Dt6AUz62D0wIoDETFsZ01Tg==} + /@esbuild/win32-arm64@0.18.10: + resolution: {integrity: sha512-kRhNcMZFGMW+ZHCarAM1ypr8OZs0k688ViUCetVCef9p3enFxzWeBg9h/575Y0nsFu0ZItluCVF5gMR2pwOEpA==} engines: {node: '>=12'} cpu: [arm64] os: [win32] @@ -2002,8 +2076,8 @@ packages: requiresBuild: true optional: true - /@esbuild/win32-ia32@0.18.1: - resolution: {integrity: sha512-z51DOtcwECu4WlqJUhu39AVnnpaVmTvXei0EQxc99QK7ZJyn4tj0EelYkMBZckpqzqB/GyGSLwEclKtRJ0l2uw==} + /@esbuild/win32-ia32@0.18.10: + resolution: {integrity: sha512-AR9PX1whYaYh9p0EOaKna0h48F/A101Mt/ag72+kMkkBZXPQ7cjbz2syXI/HI3OlBdUytSdHneljfjvUoqwqiQ==} engines: {node: '>=12'} cpu: [ia32] os: [win32] @@ -2019,8 +2093,8 @@ packages: requiresBuild: true optional: true - /@esbuild/win32-x64@0.18.1: - resolution: {integrity: sha512-6tdeuCLT+l9QuCFaYsNtULO6xH2fgJObvICMCsOZvkqIey6FUXVVju5aO+OZjxswy7WgKadhI1k/nq2wQSmB+Q==} + /@esbuild/win32-x64@0.18.10: + resolution: {integrity: sha512-5sTkYhAGHNRr6bVf4RM0PsscqVr6/DBYdrlMh168oph3usid3lKHcHEEHmr34iZ9GHeeg2juFOxtpl6XyC3tpw==} engines: {node: '>=12'} cpu: [x64] os: [win32] @@ -2028,13 +2102,13 @@ packages: dev: true optional: true - /@eslint-community/eslint-utils@4.4.0(eslint@8.42.0): + /@eslint-community/eslint-utils@4.4.0(eslint@8.43.0): resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 dependencies: - eslint: 8.42.0 + eslint: 8.43.0 eslint-visitor-keys: 3.4.1 dev: true @@ -2060,8 +2134,8 @@ packages: - supports-color dev: true - /@eslint/js@8.42.0: - resolution: {integrity: sha512-6SWlXpWU5AvId8Ac7zjzmIOqMOba/JWY8XZ4A7q7Gn1Vlfg/SFFIlrtHXt9nPn4op9ZPAkl91Jao+QQv3r/ukw==} + /@eslint/js@8.43.0: + resolution: {integrity: sha512-s2UHCoiXfxMvmfzqoN+vrQ84ahUSYde9qNO1MdxmoEhyHWsfmwOpFlwYV+ePJEVc7gFnATGUi376WowX1N7tFg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true @@ -2420,14 +2494,14 @@ packages: hasBin: true dev: false - /@hookform/devtools@4.3.1(@types/react@18.2.11)(react-dom@18.2.0)(react@18.2.0): + /@hookform/devtools@4.3.1(@types/react@18.2.14)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-CrWxEoHQZaOXJZVQ8KBgOuAa8p2LI8M0DAN5GTRTmdCieRwFVjVDEmuTAVazWVRRkpEQSgSt3KYp7VmmqXdEnw==} peerDependencies: react: ^16.8.0 || ^17 || ^18 react-dom: ^16.8.0 || ^17 || ^18 dependencies: - '@emotion/react': 11.10.6(@types/react@18.2.11)(react@18.2.0) - '@emotion/styled': 11.10.6(@emotion/react@11.10.6)(@types/react@18.2.11)(react@18.2.0) + '@emotion/react': 11.10.6(@types/react@18.2.14)(react@18.2.0) + '@emotion/styled': 11.10.6(@emotion/react@11.10.6)(@types/react@18.2.14)(react@18.2.0) '@types/lodash': 4.14.194 little-state-machine: 4.8.0(react@18.2.0) lodash: 4.17.21 @@ -2546,8 +2620,8 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: false - /@ladle/react@2.14.0(react-dom@18.2.0)(react@18.2.0)(sass@1.63.3)(terser@5.17.7): - resolution: {integrity: sha512-QV+eNlAL382xddeSis26RWVtwxlXTi5ky+QT1Ro9/SUKTfVfCeGeeCYH0GDlUmZ+snD+28pck0QfqoJqxHOk9A==} + /@ladle/react@2.15.0(react-dom@18.2.0)(react@18.2.0)(sass@1.63.6)(terser@5.18.2): + resolution: {integrity: sha512-rEl5WU1f0YQO+oXFV9fh2FQUHdXR/k4waLxHBnVyJoQvNvZKZJiKSXkzi7kNIxQazK5iVla12pbhlvDe2jR/Yw==} engines: {node: '>=16.0.0'} hasBin: true peerDependencies: @@ -2591,7 +2665,7 @@ packages: remark-gfm: 3.0.1 source-map: 0.7.4 vfile: 5.3.7 - vite: 4.3.9(sass@1.63.3)(terser@5.17.7) + vite: 4.3.9(sass@1.63.6)(terser@5.18.2) vite-tsconfig-paths: 3.6.0(vite@4.3.9) transitivePeerDependencies: - '@swc/helpers' @@ -2648,7 +2722,7 @@ packages: react: '>=16' dependencies: '@types/mdx': 2.0.4 - '@types/react': 18.2.11 + '@types/react': 18.2.14 react: 18.2.0 dev: false @@ -2763,20 +2837,20 @@ packages: resolution: {integrity: sha512-HaW78NszGzRZd9SeoI3JD11JqY+lubnaOx7Pewj5pfjqWXOEATpeKIFb9Z4t2WBUK2iryiXX3lzWwmYWgUL0Ug==} dev: false - /@popperjs/core@2.11.7: - resolution: {integrity: sha512-Cr4OjIkipTtcXKjAsm8agyleBuDHvxzeBoa1v543lbv1YaIwQjESsVcmjiWiPEbC1FIeHOG/Op9kdCmAmiS3Kw==} + /@popperjs/core@2.11.8: + resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==} dev: false /@reach/observe-rect@1.2.0: resolution: {integrity: sha512-Ba7HmkFgfQxZqqaeIWWkNK0rEhpxVQHIoVyW1YDSkGsGIXzcaW4deC8B0pZrNSSyLTdIk7y+5olKt5+g0GmFIQ==} dev: false - /@remix-run/router@1.6.3: - resolution: {integrity: sha512-EXJysQ7J3veRECd0kZFQwYYd5sJMcq2O/m60zu1W2l3oVQ9xtub8jTOtYRE0+M2iomyG/W3Ps7+vp2kna0C27Q==} + /@remix-run/router@1.7.0: + resolution: {integrity: sha512-Eu1V3kz3mV0wUpVTiFHuaT8UD1gj/0VnoFHQYX35xlslQUpe8CuYoKFn9d4WZFHm3yDywz6ALZuGdnUPKrNeAw==} engines: {node: '>=14'} dev: false - /@rollup/plugin-inject@5.0.3(rollup@3.25.1): + /@rollup/plugin-inject@5.0.3(rollup@3.26.0): resolution: {integrity: sha512-411QlbL+z2yXpRWFXSmw/teQRMkXcAAC8aYTemc15gwJRpvEVDQwoe+N/HTFD8RFG8+88Bme9DK2V9CVm7hJdA==} engines: {node: '>=14.0.0'} peerDependencies: @@ -2785,10 +2859,10 @@ packages: rollup: optional: true dependencies: - '@rollup/pluginutils': 5.0.2(rollup@3.25.1) + '@rollup/pluginutils': 5.0.2(rollup@3.26.0) estree-walker: 2.0.2 magic-string: 0.27.0 - rollup: 3.25.1 + rollup: 3.26.0 dev: false /@rollup/pluginutils@4.2.1: @@ -2799,7 +2873,7 @@ packages: picomatch: 2.3.1 dev: true - /@rollup/pluginutils@5.0.2(rollup@3.25.1): + /@rollup/pluginutils@5.0.2(rollup@3.26.0): resolution: {integrity: sha512-pTd9rIsP92h+B6wWwFbW8RkZv4hiR/xKsqre4SIuAOaOEQRxi0lqLke9k2/7WegC85GgUs9pjmOjCUi3In4vwA==} engines: {node: '>=14.0.0'} peerDependencies: @@ -2811,7 +2885,7 @@ packages: '@types/estree': 1.0.1 estree-walker: 2.0.2 picomatch: 2.3.1 - rollup: 3.25.1 + rollup: 3.26.0 dev: false /@solana/buffer-layout@4.0.1: @@ -3246,9 +3320,15 @@ packages: '@swc/core-win32-x64-msvc': 1.3.55 dev: false - /@tanstack/query-core@4.29.11: - resolution: {integrity: sha512-8C+hF6SFAb/TlFZyS9FItgNwrw4PMa7YeX+KQYe2ZAiEz6uzg6yIr+QBzPkUwZ/L0bXvGd1sufTm3wotoz+GwQ==} - dev: false + /@tanstack/match-sorter-utils@8.8.4: + resolution: {integrity: sha512-rKH8LjZiszWEvmi01NR72QWZ8m4xmXre0OOwlRGnjU01Eqz/QnN+cqpty2PJ0efHblq09+KilvyR7lsbzmXVEw==} + engines: {node: '>=12'} + dependencies: + remove-accents: 0.4.2 + dev: true + + /@tanstack/query-core@4.29.19: + resolution: {integrity: sha512-uPe1DukeIpIHpQi6UzIgBcXsjjsDaLnc7hF+zLBKnaUlh7jFE/A+P8t4cU4VzKPMFB/C970n/9SxtpO5hmIRgw==} /@tanstack/query-core@4.29.5: resolution: {integrity: sha512-xXIiyQ/4r9KfaJ3k6kejqcaqFXXBTzN2aOJ5H1J6aTJE9hl/nbgAdfF6oiIu0CD5xowejJEJ6bBg8TO7BN4NuQ==} @@ -3266,17 +3346,32 @@ packages: '@tanstack/query-persist-client-core': 4.29.5 dev: false - /@tanstack/react-query-persist-client@4.29.5(@tanstack/react-query@4.29.12): + /@tanstack/react-query-devtools@4.29.19(@tanstack/react-query@4.29.19)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-rL2xqTPr+7gJvVGwyq8E8CWqqw950N4lZ6ffJeNX0qqymKHxHW1FM6nZaYt7Aufs/bXH0m1L9Sj3kDGQbp0rwg==} + peerDependencies: + '@tanstack/react-query': 4.29.19 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + dependencies: + '@tanstack/match-sorter-utils': 8.8.4 + '@tanstack/react-query': 4.29.19(react-dom@18.2.0)(react@18.2.0) + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + superjson: 1.12.4 + use-sync-external-store: 1.2.0(react@18.2.0) + dev: true + + /@tanstack/react-query-persist-client@4.29.5(@tanstack/react-query@4.29.19): resolution: {integrity: sha512-zvQChSqO/HpRHWjCn+4L4M45Yr2eslogJcQr2HFxRw27Wj/5WlFYhnQFo5SCCR+gZh09tMnkzD+zFhN76wMEGw==} peerDependencies: '@tanstack/react-query': 4.29.5 dependencies: '@tanstack/query-persist-client-core': 4.29.5 - '@tanstack/react-query': 4.29.12(react-dom@18.2.0)(react@18.2.0) + '@tanstack/react-query': 4.29.19(react-dom@18.2.0)(react@18.2.0) dev: false - /@tanstack/react-query@4.29.12(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-zhcN6+zF6cxprxhTHQajHGlvxgK8npnp9uLe9yaWhGc6sYcPWXzyO4raL4HomUzQOPzu3jLvkriJQ7BOrDM8vA==} + /@tanstack/react-query@4.29.19(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-XiTIOHHQ5Cw1WUlHaD4fmVUMhoWjuNJlAeJGq7eM4BraI5z7y8WkZO+NR8PSuRnQGblpuVdjClQbDFtwxTtTUw==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -3287,11 +3382,10 @@ packages: react-native: optional: true dependencies: - '@tanstack/query-core': 4.29.11 + '@tanstack/query-core': 4.29.19 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) use-sync-external-store: 1.2.0(react@18.2.0) - dev: false /@tanstack/react-virtual@3.0.0-beta.9(react@18.2.0): resolution: {integrity: sha512-zW914lzyPWunqKaHYwiOu/R7k/LJ43W6lutpCAeDbYqaOOme5tp/G+/PCpnK2vKseUnCpKM7x/WicrQoDX8H0A==} @@ -3310,13 +3404,13 @@ packages: '@reach/observe-rect': 1.2.0 dev: false - /@tauri-apps/api@1.3.0: - resolution: {integrity: sha512-AH+3FonkKZNtfRtGrObY38PrzEj4d+1emCbwNGu0V2ENbXjlLHMZQlUh+Bhu/CRmjaIwZMGJ3yFvWaZZgTHoog==} + /@tauri-apps/api@1.4.0: + resolution: {integrity: sha512-Jd6HPoTM1PZSFIzq7FB8VmMu3qSSyo/3lSwLpoapW+lQ41CL5Dow2KryLg+gyazA/58DRWI9vu/XpEeHK4uMdw==} engines: {node: '>= 14.6.0', npm: '>= 6.6.0', yarn: '>= 1.19.1'} dev: false - /@tauri-apps/cli-darwin-arm64@1.3.1: - resolution: {integrity: sha512-QlepYVPgOgspcwA/u4kGG4ZUijlXfdRtno00zEy+LxinN/IRXtk+6ErVtsmoLi1ZC9WbuMwzAcsRvqsD+RtNAg==} + /@tauri-apps/cli-darwin-arm64@1.4.0: + resolution: {integrity: sha512-nA/ml0SfUt6/CYLVbHmT500Y+ijqsuv5+s9EBnVXYSLVg9kbPUZJJHluEYK+xKuOj6xzyuT/+rZFMRapmJD3jQ==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] @@ -3324,8 +3418,8 @@ packages: dev: true optional: true - /@tauri-apps/cli-darwin-x64@1.3.1: - resolution: {integrity: sha512-fKcAUPVFO3jfDKXCSDGY0MhZFF/wDtx3rgFnogWYu4knk38o9RaqRkvMvqJhLYPuWaEM5h6/z1dRrr9KKCbrVg==} + /@tauri-apps/cli-darwin-x64@1.4.0: + resolution: {integrity: sha512-ov/F6Zr+dg9B0PtRu65stFo2G0ow2TUlneqYYrkj+vA3n+moWDHfVty0raDjMLQbQt3rv3uayFMXGPMgble9OA==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] @@ -3333,8 +3427,8 @@ packages: dev: true optional: true - /@tauri-apps/cli-linux-arm-gnueabihf@1.3.1: - resolution: {integrity: sha512-+4H0dv8ltJHYu/Ma1h9ixUPUWka9EjaYa8nJfiMsdCI4LJLNE6cPveE7RmhZ59v9GW1XB108/k083JUC/OtGvA==} + /@tauri-apps/cli-linux-arm-gnueabihf@1.4.0: + resolution: {integrity: sha512-zwjbiMncycXDV7doovymyKD7sCg53ouAmfgpUqEBOTY3vgBi9TwijyPhJOqoG5vUVWhouNBC08akGmE4dja15g==} engines: {node: '>= 10'} cpu: [arm] os: [linux] @@ -3342,8 +3436,8 @@ packages: dev: true optional: true - /@tauri-apps/cli-linux-arm64-gnu@1.3.1: - resolution: {integrity: sha512-Pj3odVO1JAxLjYmoXKxcrpj/tPxcA8UP8N06finhNtBtBaxAjrjjxKjO4968KB0BUH7AASIss9EL4Tr0FGnDuw==} + /@tauri-apps/cli-linux-arm64-gnu@1.4.0: + resolution: {integrity: sha512-5MCBcziqXC72mMXnkZU68mutXIR6zavDxopArE2gQtK841IlE06bIgtLi0kUUhlFJk2nhPRgiDgdLbrPlyt7fw==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] @@ -3351,8 +3445,8 @@ packages: dev: true optional: true - /@tauri-apps/cli-linux-arm64-musl@1.3.1: - resolution: {integrity: sha512-tA0JdDLPFaj42UDIVcF2t8V0tSha40rppcmAR/MfQpTCxih6399iMjwihz9kZE1n4b5O4KTq9GliYo50a8zYlQ==} + /@tauri-apps/cli-linux-arm64-musl@1.4.0: + resolution: {integrity: sha512-7J3pRB6n6uNYgIfCeKt2Oz8J7oSaz2s8GGFRRH2HPxuTHrBNCinzVYm68UhVpJrL3bnGkU0ziVZLsW/iaOGfUg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] @@ -3360,8 +3454,8 @@ packages: dev: true optional: true - /@tauri-apps/cli-linux-x64-gnu@1.3.1: - resolution: {integrity: sha512-FDU+Mnvk6NLkqQimcNojdKpMN4Y3W51+SQl+NqG9AFCWprCcSg62yRb84751ujZuf2MGT8HQOfmd0i77F4Q3tQ==} + /@tauri-apps/cli-linux-x64-gnu@1.4.0: + resolution: {integrity: sha512-Zh5gfAJxOv5AVWxcwuueaQ2vIAhlg0d6nZui6nMyfIJ8dbf3aZQ5ZzP38sYow5h/fbvgL+3GSQxZRBIa3c2E1w==} engines: {node: '>= 10'} cpu: [x64] os: [linux] @@ -3369,8 +3463,8 @@ packages: dev: true optional: true - /@tauri-apps/cli-linux-x64-musl@1.3.1: - resolution: {integrity: sha512-MpO3akXFmK8lZYEbyQRDfhdxz1JkTBhonVuz5rRqxwA7gnGWHa1aF1+/2zsy7ahjB2tQ9x8DDFDMdVE20o9HrA==} + /@tauri-apps/cli-linux-x64-musl@1.4.0: + resolution: {integrity: sha512-OLAYoICU3FaYiTdBsI+lQTKnDHeMmFMXIApN0M+xGiOkoIOQcV9CConMPjgmJQ867+NHRNgUGlvBEAh9CiJodQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] @@ -3378,8 +3472,17 @@ packages: dev: true optional: true - /@tauri-apps/cli-win32-ia32-msvc@1.3.1: - resolution: {integrity: sha512-9Boeo3K5sOrSBAZBuYyGkpV2RfnGQz3ZhGJt4hE6P+HxRd62lS6+qDKAiw1GmkZ0l1drc2INWrNeT50gwOKwIQ==} + /@tauri-apps/cli-win32-arm64-msvc@1.4.0: + resolution: {integrity: sha512-gZ05GENFbI6CB5MlOUsLlU0kZ9UtHn9riYtSXKT6MYs8HSPRffPHaHSL0WxsJweWh9nR5Hgh/TUU8uW3sYCzCg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@tauri-apps/cli-win32-ia32-msvc@1.4.0: + resolution: {integrity: sha512-JsetT/lTx/Zq98eo8T5CiRyF1nKeX04RO8JlJrI3ZOYsZpp/A5RJvMd/szQ17iOzwiHdge+tx7k2jHysR6oBlQ==} engines: {node: '>= 10'} cpu: [ia32] os: [win32] @@ -3387,8 +3490,8 @@ packages: dev: true optional: true - /@tauri-apps/cli-win32-x64-msvc@1.3.1: - resolution: {integrity: sha512-wMrTo91hUu5CdpbElrOmcZEoJR4aooTG+fbtcc87SMyPGQy1Ux62b+ZdwLvL1sVTxnIm//7v6QLRIWGiUjCPwA==} + /@tauri-apps/cli-win32-x64-msvc@1.4.0: + resolution: {integrity: sha512-z8Olcnwp5aYhzqUAarFjqF+oELCjuYWnB2HAJHlfsYNfDCAORY5kct3Fklz8PSsubC3U2EugWn8n42DwnThurg==} engines: {node: '>= 10'} cpu: [x64] os: [win32] @@ -3396,20 +3499,21 @@ packages: dev: true optional: true - /@tauri-apps/cli@1.3.1: - resolution: {integrity: sha512-o4I0JujdITsVRm3/0spfJX7FcKYrYV1DXJqzlWIn6IY25/RltjU6qbC1TPgVww3RsRX63jyVUTcWpj5wwFl+EQ==} + /@tauri-apps/cli@1.4.0: + resolution: {integrity: sha512-VXYr2i2iVFl98etQSQsqLzXgX96bnWiNZd1YADgatqwy/qecbd6Kl5ZAPB5R4ynsgE8A1gU7Fbzh7dCEQYFfmA==} engines: {node: '>= 10'} hasBin: true optionalDependencies: - '@tauri-apps/cli-darwin-arm64': 1.3.1 - '@tauri-apps/cli-darwin-x64': 1.3.1 - '@tauri-apps/cli-linux-arm-gnueabihf': 1.3.1 - '@tauri-apps/cli-linux-arm64-gnu': 1.3.1 - '@tauri-apps/cli-linux-arm64-musl': 1.3.1 - '@tauri-apps/cli-linux-x64-gnu': 1.3.1 - '@tauri-apps/cli-linux-x64-musl': 1.3.1 - '@tauri-apps/cli-win32-ia32-msvc': 1.3.1 - '@tauri-apps/cli-win32-x64-msvc': 1.3.1 + '@tauri-apps/cli-darwin-arm64': 1.4.0 + '@tauri-apps/cli-darwin-x64': 1.4.0 + '@tauri-apps/cli-linux-arm-gnueabihf': 1.4.0 + '@tauri-apps/cli-linux-arm64-gnu': 1.4.0 + '@tauri-apps/cli-linux-arm64-musl': 1.4.0 + '@tauri-apps/cli-linux-x64-gnu': 1.4.0 + '@tauri-apps/cli-linux-x64-musl': 1.4.0 + '@tauri-apps/cli-win32-arm64-msvc': 1.4.0 + '@tauri-apps/cli-win32-ia32-msvc': 1.4.0 + '@tauri-apps/cli-win32-x64-msvc': 1.4.0 dev: true /@trysound/sax@0.2.0: @@ -3566,17 +3670,17 @@ packages: /@types/prop-types@15.7.5: resolution: {integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==} - /@types/react-dom@18.2.4: - resolution: {integrity: sha512-G2mHoTMTL4yoydITgOGwWdWMVd8sNgyEP85xVmMKAPUBwQWm9wBPQUmvbeF4V3WBY1P7mmL4BkjQ0SqUpf1snw==} + /@types/react-dom@18.2.6: + resolution: {integrity: sha512-2et4PDvg6PVCyS7fuTc4gPoksV58bW0RwSxWKcPRcHZf0PRUGq03TKcD/rUHe3azfV6/5/biUBJw+HhCQjaP0A==} dependencies: - '@types/react': 18.2.11 + '@types/react': 18.2.14 dev: true /@types/react-router-dom@5.3.3: resolution: {integrity: sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==} dependencies: '@types/history': 4.7.11 - '@types/react': 18.2.11 + '@types/react': 18.2.14 '@types/react-router': 5.1.20 dev: true @@ -3584,23 +3688,23 @@ packages: resolution: {integrity: sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q==} dependencies: '@types/history': 4.7.11 - '@types/react': 18.2.11 + '@types/react': 18.2.14 dev: true /@types/react-virtualized-auto-sizer@1.0.1: resolution: {integrity: sha512-GH8sAnBEM5GV9LTeiz56r4ZhMOUSrP43tAQNSRVxNexDjcNKLCEtnxusAItg1owFUFE6k0NslV26gqVClVvong==} dependencies: - '@types/react': 18.2.11 + '@types/react': 18.2.14 dev: false /@types/react-window@1.8.5: resolution: {integrity: sha512-V9q3CvhC9Jk9bWBOysPGaWy/Z0lxYcTXLtLipkt2cnRj1JOSFNF7wqGpkScSXMgBwC+fnVRg/7shwgddBG5ICw==} dependencies: - '@types/react': 18.2.11 + '@types/react': 18.2.14 dev: false - /@types/react@18.2.11: - resolution: {integrity: sha512-+hsJr9hmwyDecSMQAmX7drgbDpyE+EgSF6t7+5QEBAn1tQK7kl1vWZ4iRf6SjQ8lk7dyEULxUmZOIpN0W5baZA==} + /@types/react@18.2.14: + resolution: {integrity: sha512-A0zjq+QN/O0Kpe30hA1GidzyFjatVvrpIvWLxD+xv67Vt91TWWgco9IvrJBkeyHm1trGaFS/FSGqPlhyeZRm0g==} dependencies: '@types/prop-types': 15.7.5 '@types/scheduler': 0.16.3 @@ -3627,8 +3731,8 @@ packages: '@types/node': 12.20.55 dev: false - /@typescript-eslint/eslint-plugin@5.59.2(@typescript-eslint/parser@5.59.9)(eslint@8.42.0)(typescript@5.1.3): - resolution: {integrity: sha512-yVrXupeHjRxLDcPKL10sGQ/QlVrA8J5IYOEWVqk0lJaSZP7X5DfnP7Ns3cc74/blmbipQ1htFNVGsHX6wsYm0A==} + /@typescript-eslint/eslint-plugin@5.60.1(@typescript-eslint/parser@5.60.1)(eslint@8.43.0)(typescript@5.1.6): + resolution: {integrity: sha512-KSWsVvsJsLJv3c4e73y/Bzt7OpqMCADUO846bHcuWYSYM19bldbAeDv7dYyV0jwkbMfJ2XdlzwjhXtuD7OY6bw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: '@typescript-eslint/parser': ^5.0.0 @@ -3639,24 +3743,24 @@ packages: optional: true dependencies: '@eslint-community/regexpp': 4.5.0 - '@typescript-eslint/parser': 5.59.9(eslint@8.42.0)(typescript@5.1.3) - '@typescript-eslint/scope-manager': 5.59.2 - '@typescript-eslint/type-utils': 5.59.2(eslint@8.42.0)(typescript@5.1.3) - '@typescript-eslint/utils': 5.59.2(eslint@8.42.0)(typescript@5.1.3) + '@typescript-eslint/parser': 5.60.1(eslint@8.43.0)(typescript@5.1.6) + '@typescript-eslint/scope-manager': 5.60.1 + '@typescript-eslint/type-utils': 5.60.1(eslint@8.43.0)(typescript@5.1.6) + '@typescript-eslint/utils': 5.60.1(eslint@8.43.0)(typescript@5.1.6) debug: 4.3.4 - eslint: 8.42.0 + eslint: 8.43.0 grapheme-splitter: 1.0.4 ignore: 5.2.4 natural-compare-lite: 1.4.0 semver: 7.5.0 - tsutils: 3.21.0(typescript@5.1.3) - typescript: 5.1.3 + tsutils: 3.21.0(typescript@5.1.6) + typescript: 5.1.6 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/parser@5.59.9(eslint@8.42.0)(typescript@5.1.3): - resolution: {integrity: sha512-FsPkRvBtcLQ/eVK1ivDiNYBjn3TGJdXy2fhXX+rc7czWl4ARwnpArwbihSOHI2Peg9WbtGHrbThfBUkZZGTtvQ==} + /@typescript-eslint/parser@5.60.1(eslint@8.43.0)(typescript@5.1.6): + resolution: {integrity: sha512-pHWlc3alg2oSMGwsU/Is8hbm3XFbcrb6P5wIxcQW9NsYBfnrubl/GhVVD/Jm/t8HXhA2WncoIRfBtnCgRGV96Q==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -3665,34 +3769,26 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/scope-manager': 5.59.9 - '@typescript-eslint/types': 5.59.9 - '@typescript-eslint/typescript-estree': 5.59.9(typescript@5.1.3) + '@typescript-eslint/scope-manager': 5.60.1 + '@typescript-eslint/types': 5.60.1 + '@typescript-eslint/typescript-estree': 5.60.1(typescript@5.1.6) debug: 4.3.4 - eslint: 8.42.0 - typescript: 5.1.3 + eslint: 8.43.0 + typescript: 5.1.6 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/scope-manager@5.59.2: - resolution: {integrity: sha512-dB1v7ROySwQWKqQ8rEWcdbTsFjh2G0vn8KUyvTXdPoyzSL6lLGkiXEV5CvpJsEe9xIdKV+8Zqb7wif2issoOFA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dependencies: - '@typescript-eslint/types': 5.59.2 - '@typescript-eslint/visitor-keys': 5.59.2 - dev: true - - /@typescript-eslint/scope-manager@5.59.9: - resolution: {integrity: sha512-8RA+E+w78z1+2dzvK/tGZ2cpGigBZ58VMEHDZtpE1v+LLjzrYGc8mMaTONSxKyEkz3IuXFM0IqYiGHlCsmlZxQ==} + /@typescript-eslint/scope-manager@5.60.1: + resolution: {integrity: sha512-Dn/LnN7fEoRD+KspEOV0xDMynEmR3iSHdgNsarlXNLGGtcUok8L4N71dxUgt3YvlO8si7E+BJ5Fe3wb5yUw7DQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: - '@typescript-eslint/types': 5.59.9 - '@typescript-eslint/visitor-keys': 5.59.9 + '@typescript-eslint/types': 5.60.1 + '@typescript-eslint/visitor-keys': 5.60.1 dev: true - /@typescript-eslint/type-utils@5.59.2(eslint@8.42.0)(typescript@5.1.3): - resolution: {integrity: sha512-b1LS2phBOsEy/T381bxkkywfQXkV1dWda/z0PhnIy3bC5+rQWQDS7fk9CSpcXBccPY27Z6vBEuaPBCKCgYezyQ==} + /@typescript-eslint/type-utils@5.60.1(eslint@8.43.0)(typescript@5.1.6): + resolution: {integrity: sha512-vN6UztYqIu05nu7JqwQGzQKUJctzs3/Hg7E2Yx8rz9J+4LgtIDFWjjl1gm3pycH0P3mHAcEUBd23LVgfrsTR8A==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: '*' @@ -3701,49 +3797,23 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/typescript-estree': 5.59.2(typescript@5.1.3) - '@typescript-eslint/utils': 5.59.2(eslint@8.42.0)(typescript@5.1.3) + '@typescript-eslint/typescript-estree': 5.60.1(typescript@5.1.6) + '@typescript-eslint/utils': 5.60.1(eslint@8.43.0)(typescript@5.1.6) debug: 4.3.4 - eslint: 8.42.0 - tsutils: 3.21.0(typescript@5.1.3) - typescript: 5.1.3 + eslint: 8.43.0 + tsutils: 3.21.0(typescript@5.1.6) + typescript: 5.1.6 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/types@5.59.2: - resolution: {integrity: sha512-LbJ/HqoVs2XTGq5shkiKaNTuVv5tTejdHgfdjqRUGdYhjW1crm/M7og2jhVskMt8/4wS3T1+PfFvL1K3wqYj4w==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dev: true - - /@typescript-eslint/types@5.59.9: - resolution: {integrity: sha512-uW8H5NRgTVneSVTfiCVffBb8AbwWSKg7qcA4Ot3JI3MPCJGsB4Db4BhvAODIIYE5mNj7Q+VJkK7JxmRhk2Lyjw==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dev: true - - /@typescript-eslint/typescript-estree@5.59.2(typescript@5.1.3): - resolution: {integrity: sha512-+j4SmbwVmZsQ9jEyBMgpuBD0rKwi9RxRpjX71Brr73RsYnEr3Lt5QZ624Bxphp8HUkSKfqGnPJp1kA5nl0Sh7Q==} + /@typescript-eslint/types@5.60.1: + resolution: {integrity: sha512-zDcDx5fccU8BA0IDZc71bAtYIcG9PowaOwaD8rjYbqwK7dpe/UMQl3inJ4UtUK42nOCT41jTSCwg76E62JpMcg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@typescript-eslint/types': 5.59.2 - '@typescript-eslint/visitor-keys': 5.59.2 - debug: 4.3.4 - globby: 11.1.0 - is-glob: 4.0.3 - semver: 7.5.0 - tsutils: 3.21.0(typescript@5.1.3) - typescript: 5.1.3 - transitivePeerDependencies: - - supports-color dev: true - /@typescript-eslint/typescript-estree@5.59.9(typescript@5.1.3): - resolution: {integrity: sha512-pmM0/VQ7kUhd1QyIxgS+aRvMgw+ZljB3eDb+jYyp6d2bC0mQWLzUDF+DLwCTkQ3tlNyVsvZRXjFyV0LkU/aXjA==} + /@typescript-eslint/typescript-estree@5.60.1(typescript@5.1.6): + resolution: {integrity: sha512-hkX70J9+2M2ZT6fhti5Q2FoU9zb+GeZK2SLP1WZlvUDqdMbEKhexZODD1WodNRyO8eS+4nScvT0dts8IdaBzfw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: typescript: '*' @@ -3751,31 +3821,31 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/types': 5.59.9 - '@typescript-eslint/visitor-keys': 5.59.9 + '@typescript-eslint/types': 5.60.1 + '@typescript-eslint/visitor-keys': 5.60.1 debug: 4.3.4 globby: 11.1.0 is-glob: 4.0.3 semver: 7.5.0 - tsutils: 3.21.0(typescript@5.1.3) - typescript: 5.1.3 + tsutils: 3.21.0(typescript@5.1.6) + typescript: 5.1.6 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/utils@5.59.2(eslint@8.42.0)(typescript@5.1.3): - resolution: {integrity: sha512-kSuF6/77TZzyGPhGO4uVp+f0SBoYxCDf+lW3GKhtKru/L8k/Hd7NFQxyWUeY7Z/KGB2C6Fe3yf2vVi4V9TsCSQ==} + /@typescript-eslint/utils@5.60.1(eslint@8.43.0)(typescript@5.1.6): + resolution: {integrity: sha512-tiJ7FFdFQOWssFa3gqb94Ilexyw0JVxj6vBzaSpfN/8IhoKkDuSAenUKvsSHw2A/TMpJb26izIszTXaqygkvpQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.42.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@8.43.0) '@types/json-schema': 7.0.11 '@types/semver': 7.3.13 - '@typescript-eslint/scope-manager': 5.59.2 - '@typescript-eslint/types': 5.59.2 - '@typescript-eslint/typescript-estree': 5.59.2(typescript@5.1.3) - eslint: 8.42.0 + '@typescript-eslint/scope-manager': 5.60.1 + '@typescript-eslint/types': 5.60.1 + '@typescript-eslint/typescript-estree': 5.60.1(typescript@5.1.6) + eslint: 8.43.0 eslint-scope: 5.1.1 semver: 7.5.0 transitivePeerDependencies: @@ -3783,38 +3853,30 @@ packages: - typescript dev: true - /@typescript-eslint/visitor-keys@5.59.2: - resolution: {integrity: sha512-EEpsO8m3RASrKAHI9jpavNv9NlEUebV4qmF1OWxSTtKSFBpC1NCmWazDQHFivRf0O1DV11BA645yrLEVQ0/Lig==} + /@typescript-eslint/visitor-keys@5.60.1: + resolution: {integrity: sha512-xEYIxKcultP6E/RMKqube11pGjXH1DCo60mQoWhVYyKfLkwbIVVjYxmOenNMxILx0TjCujPTjjnTIVzm09TXIw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: - '@typescript-eslint/types': 5.59.2 + '@typescript-eslint/types': 5.60.1 eslint-visitor-keys: 3.4.1 dev: true - /@typescript-eslint/visitor-keys@5.59.9: - resolution: {integrity: sha512-bT7s0td97KMaLwpEBckbzj/YohnvXtqbe2XgqNvTl6RJVakY5mvENOTPvw5u66nljfZxthESpDozs86U+oLY8Q==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dependencies: - '@typescript-eslint/types': 5.59.9 - eslint-visitor-keys: 3.4.1 - dev: true - - /@vitejs/plugin-legacy@4.0.4(terser@5.17.7)(vite@4.3.9): - resolution: {integrity: sha512-UwVfkMfUEszbQ2vs3RDfiDxxvYnIjmtIrGxTnxRev5Sh8ZoDpieV2dwvTUB7zXKJpfRsOgimM6MxQ65VDHJeQw==} + /@vitejs/plugin-legacy@4.0.5(terser@5.18.2)(vite@4.3.9): + resolution: {integrity: sha512-0N1CSAHjFTaxcKC9IcKDWMapmAfGn2mNdbROMf6UW0kypYLzDK8vAAbJIFW0jWvkv2aZfTgNs4KmQxoQDupUuQ==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: terser: ^5.4.0 vite: ^4.0.0 dependencies: '@babel/core': 7.22.5 - '@babel/preset-env': 7.21.4(@babel/core@7.22.5) - browserslist: 4.21.5 - core-js: 3.30.1 + '@babel/preset-env': 7.22.5(@babel/core@7.22.5) + browserslist: 4.21.9 + core-js: 3.31.0 magic-string: 0.30.0 regenerator-runtime: 0.13.11 systemjs: 6.14.1 - terser: 5.17.7 - vite: 4.3.9(sass@1.63.3)(terser@5.17.7) + terser: 5.18.2 + vite: 4.3.9(sass@1.63.6)(terser@5.18.2) transitivePeerDependencies: - supports-color dev: false @@ -3825,7 +3887,7 @@ packages: vite: ^4 dependencies: '@swc/core': 1.3.55 - vite: 4.3.9(sass@1.63.3)(terser@5.17.7) + vite: 4.3.9(sass@1.63.6)(terser@5.18.2) transitivePeerDependencies: - '@swc/helpers' dev: false @@ -3837,26 +3899,26 @@ packages: vite: ^4.1.0-beta.0 dependencies: '@babel/core': 7.22.5 - '@babel/plugin-transform-react-jsx-self': 7.21.0(@babel/core@7.22.5) - '@babel/plugin-transform-react-jsx-source': 7.19.6(@babel/core@7.22.5) + '@babel/plugin-transform-react-jsx-self': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-react-jsx-source': 7.22.5(@babel/core@7.22.5) magic-string: 0.27.0 react-refresh: 0.14.0 - vite: 4.3.9(sass@1.63.3)(terser@5.17.7) + vite: 4.3.9(sass@1.63.6)(terser@5.18.2) transitivePeerDependencies: - supports-color dev: false - /@vitejs/plugin-react@4.0.0(vite@4.3.9): - resolution: {integrity: sha512-HX0XzMjL3hhOYm+0s95pb0Z7F8O81G7joUHgfDd/9J/ZZf5k4xX6QAMFkKsHFxaHlf6X7GD7+XuaZ66ULiJuhQ==} + /@vitejs/plugin-react@4.0.1(vite@4.3.9): + resolution: {integrity: sha512-g25lL98essfeSj43HJ0o4DMp0325XK0ITkxpgChzJU/CyemgyChtlxfnRbjfwxDGCTRxTiXtQAsdebQXKMRSOA==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: vite: ^4.2.0 dependencies: '@babel/core': 7.22.5 - '@babel/plugin-transform-react-jsx-self': 7.21.0(@babel/core@7.22.5) - '@babel/plugin-transform-react-jsx-source': 7.19.6(@babel/core@7.22.5) + '@babel/plugin-transform-react-jsx-self': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-react-jsx-source': 7.22.5(@babel/core@7.22.5) react-refresh: 0.14.0 - vite: 4.3.9(sass@1.63.3)(terser@5.17.7) + vite: 4.3.9(sass@1.63.6)(terser@5.18.2) transitivePeerDependencies: - supports-color dev: false @@ -3876,7 +3938,7 @@ packages: dependencies: '@coinbase/wallet-sdk': 3.6.6 '@ledgerhq/connect-kit-loader': 1.0.2 - '@wagmi/core': 0.8.19(@coinbase/wallet-sdk@3.6.6)(@walletconnect/ethereum-provider@1.8.0)(ethers@5.7.2)(react@18.2.0)(typescript@5.1.3) + '@wagmi/core': 0.8.19(@coinbase/wallet-sdk@3.6.6)(@walletconnect/ethereum-provider@1.8.0)(ethers@5.7.2)(react@18.2.0)(typescript@5.1.6) '@walletconnect/ethereum-provider': 1.8.0 '@walletconnect/universal-provider': 2.7.1 '@web3modal/standalone': 2.3.7(react@18.2.0) @@ -3893,7 +3955,7 @@ packages: - utf-8-validate dev: false - /@wagmi/core@0.8.19(@coinbase/wallet-sdk@3.6.6)(@walletconnect/ethereum-provider@1.8.0)(ethers@5.7.2)(react@18.2.0)(typescript@5.1.3): + /@wagmi/core@0.8.19(@coinbase/wallet-sdk@3.6.6)(@walletconnect/ethereum-provider@1.8.0)(ethers@5.7.2)(react@18.2.0)(typescript@5.1.6): resolution: {integrity: sha512-B1iXB4MRjxgoybZATRmBI7YEfUhpIl3aZGUjo5GXPU1SNtlXIA4/3wePlmLD64XzICXVBp99kynrrdlvJxc4gw==} peerDependencies: '@coinbase/wallet-sdk': '>=3.6.0' @@ -3909,7 +3971,7 @@ packages: '@wagmi/chains': 0.1.14 '@wagmi/connectors': 0.1.10(@wagmi/core@0.8.19)(ethers@5.7.2)(react@18.2.0) '@walletconnect/ethereum-provider': 1.8.0 - abitype: 0.2.5(typescript@5.1.3) + abitype: 0.2.5(typescript@5.1.6) ethers: 5.7.2 eventemitter3: 4.0.7 zustand: 4.3.8(react@18.2.0) @@ -4361,7 +4423,7 @@ packages: jsonparse: 1.3.1 through: 2.3.8 - /abitype@0.2.5(typescript@5.1.3): + /abitype@0.2.5(typescript@5.1.6): resolution: {integrity: sha512-t1iiokWYpkrziu4WL2Gb6YdGvaP9ZKs7WnA39TI8TsW2E99GVRgDPW/xOKhzoCdyxOYt550CNYEFluCwGaFHaA==} engines: {pnpm: '>=7'} peerDependencies: @@ -4371,7 +4433,7 @@ packages: zod: optional: true dependencies: - typescript: 5.1.3 + typescript: 5.1.6 dev: false /accepts@1.3.8: @@ -4674,38 +4736,38 @@ packages: resolve: 1.22.2 dev: true - /babel-plugin-polyfill-corejs2@0.3.3(@babel/core@7.22.5): - resolution: {integrity: sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==} + /babel-plugin-polyfill-corejs2@0.4.3(@babel/core@7.22.5): + resolution: {integrity: sha512-bM3gHc337Dta490gg+/AseNB9L4YLHxq1nGKZZSHbhXv4aTYU2MD2cjza1Ru4S6975YLTaL1K8uJf6ukJhhmtw==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/compat-data': 7.22.5 '@babel/core': 7.22.5 - '@babel/helper-define-polyfill-provider': 0.3.3(@babel/core@7.22.5) + '@babel/helper-define-polyfill-provider': 0.4.0(@babel/core@7.22.5) semver: 6.3.0 transitivePeerDependencies: - supports-color dev: false - /babel-plugin-polyfill-corejs3@0.6.0(@babel/core@7.22.5): - resolution: {integrity: sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA==} + /babel-plugin-polyfill-corejs3@0.8.1(@babel/core@7.22.5): + resolution: {integrity: sha512-ikFrZITKg1xH6pLND8zT14UPgjKHiGLqex7rGEZCH2EvhsneJaJPemmpQaIZV5AL03II+lXylw3UmddDK8RU5Q==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-define-polyfill-provider': 0.3.3(@babel/core@7.22.5) - core-js-compat: 3.30.1 + '@babel/helper-define-polyfill-provider': 0.4.0(@babel/core@7.22.5) + core-js-compat: 3.31.0 transitivePeerDependencies: - supports-color dev: false - /babel-plugin-polyfill-regenerator@0.4.1(@babel/core@7.22.5): - resolution: {integrity: sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==} + /babel-plugin-polyfill-regenerator@0.5.0(@babel/core@7.22.5): + resolution: {integrity: sha512-hDJtKjMLVa7Z+LwnTCxoDLQj6wdc+B8dun7ayF2fYieI6OzfuvcLMB32ihJZ4UhCBwNYGl5bg/x/P9cMdnkc2g==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.5 - '@babel/helper-define-polyfill-provider': 0.3.3(@babel/core@7.22.5) + '@babel/helper-define-polyfill-provider': 0.4.0(@babel/core@7.22.5) transitivePeerDependencies: - supports-color dev: false @@ -4904,6 +4966,17 @@ packages: node-releases: 2.0.10 update-browserslist-db: 1.0.11(browserslist@4.21.5) + /browserslist@4.21.9: + resolution: {integrity: sha512-M0MFoZzbUrRU4KNfCrDLnvyE7gub+peetoTid3TBIqtunaDJyXlwhakT+/VkvSXcfIzFfK/nkCs4nmyTmxdNSg==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + dependencies: + caniuse-lite: 1.0.30001509 + electron-to-chromium: 1.4.446 + node-releases: 2.0.12 + update-browserslist-db: 1.0.11(browserslist@4.21.9) + dev: false + /bs58@4.0.1: resolution: {integrity: sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==} dependencies: @@ -5015,6 +5088,10 @@ packages: /caniuse-lite@1.0.30001481: resolution: {integrity: sha512-KCqHwRnaa1InZBtqXzP98LPg0ajCVujMKjqKDhZEthIpAsJl/YEIa3YvXjGXPVqzZVguccuu7ga9KOE1J9rKPQ==} + /caniuse-lite@1.0.30001509: + resolution: {integrity: sha512-2uDDk+TRiTX5hMcUYT/7CSyzMZxjfGu0vAUjS2g0LSD8UoXOv0LtpH4LxGMemsiPq6LCVIUjNwVM0erkOkGCDA==} + dev: false + /ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} dev: false @@ -5400,20 +5477,27 @@ packages: keygrip: 1.1.0 dev: false + /copy-anything@3.0.5: + resolution: {integrity: sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==} + engines: {node: '>=12.13'} + dependencies: + is-what: 4.1.15 + dev: true + /copy-to-clipboard@3.3.3: resolution: {integrity: sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==} dependencies: toggle-selection: 1.0.6 dev: false - /core-js-compat@3.30.1: - resolution: {integrity: sha512-d690npR7MC6P0gq4npTl5n2VQeNAmUrJ90n+MHiKS7W2+xno4o3F5GDEuylSdi6EJ3VssibSGXOa1r3YXD3Mhw==} + /core-js-compat@3.31.0: + resolution: {integrity: sha512-hM7YCu1cU6Opx7MXNu0NuumM0ezNeAeRKadixyiQELWY3vT3De9S4J5ZBMraWV2vZnrE1Cirl0GtFtDtMUXzPw==} dependencies: - browserslist: 4.21.5 + browserslist: 4.21.9 dev: false - /core-js@3.30.1: - resolution: {integrity: sha512-ZNS5nbiSwDTq4hFosEDqm65izl2CWmLz0hARJMyNQBgkUZMIF51cQiMvIQKA6hvuaeWxQDP3hEedM1JZIgTldQ==} + /core-js@3.31.0: + resolution: {integrity: sha512-NIp2TQSGfR6ba5aalZD+ZQ1fSxGhDo/s1w0nx3RYzf2pnJxt7YynxFlFScP6eV7+GZsKO95NSjGxyJsU3DZgeQ==} requiresBuild: true dev: false @@ -5866,10 +5950,6 @@ packages: dependencies: path-type: 4.0.0 - /dlv@1.1.3: - resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} - dev: true - /doctrine@2.1.0: resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} engines: {node: '>=0.10.0'} @@ -5970,6 +6050,10 @@ packages: /electron-to-chromium@1.4.372: resolution: {integrity: sha512-MrlFq/j+TYHOjeWsWGYfzevc25HNeJdsF6qaLFrqBTRWZQtWkb1myq/Q2veLWezVaa5OcSZ99CFwTT4aF4Mung==} + /electron-to-chromium@1.4.446: + resolution: {integrity: sha512-4Gnw7ztEQ/E0eOt5JWfPn9jjeupfUlKoeW5ETKP9nLdWj+4spFoS3Stj19fqlKIaX28UQs0fNX+uKEyoLCBnkw==} + dev: false + /elliptic@6.5.4: resolution: {integrity: sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==} dependencies: @@ -6138,34 +6222,34 @@ packages: '@esbuild/win32-ia32': 0.17.18 '@esbuild/win32-x64': 0.17.18 - /esbuild@0.18.1: - resolution: {integrity: sha512-ZUvsIx2wPjpj86b805UwbGJu47Kxgr2UTio9rGhWpBr1oOVk88exzoieOgTweX0UcVCwSAk3z2WvNALpTcpQZw==} + /esbuild@0.18.10: + resolution: {integrity: sha512-33WKo67auOXzZHBY/9DTJRo7kIvfU12S+D4sp2wIz39N88MDIaCGyCwbW01RR70pK6Iya0I74lHEpyLfFqOHPA==} engines: {node: '>=12'} hasBin: true requiresBuild: true optionalDependencies: - '@esbuild/android-arm': 0.18.1 - '@esbuild/android-arm64': 0.18.1 - '@esbuild/android-x64': 0.18.1 - '@esbuild/darwin-arm64': 0.18.1 - '@esbuild/darwin-x64': 0.18.1 - '@esbuild/freebsd-arm64': 0.18.1 - '@esbuild/freebsd-x64': 0.18.1 - '@esbuild/linux-arm': 0.18.1 - '@esbuild/linux-arm64': 0.18.1 - '@esbuild/linux-ia32': 0.18.1 - '@esbuild/linux-loong64': 0.18.1 - '@esbuild/linux-mips64el': 0.18.1 - '@esbuild/linux-ppc64': 0.18.1 - '@esbuild/linux-riscv64': 0.18.1 - '@esbuild/linux-s390x': 0.18.1 - '@esbuild/linux-x64': 0.18.1 - '@esbuild/netbsd-x64': 0.18.1 - '@esbuild/openbsd-x64': 0.18.1 - '@esbuild/sunos-x64': 0.18.1 - '@esbuild/win32-arm64': 0.18.1 - '@esbuild/win32-ia32': 0.18.1 - '@esbuild/win32-x64': 0.18.1 + '@esbuild/android-arm': 0.18.10 + '@esbuild/android-arm64': 0.18.10 + '@esbuild/android-x64': 0.18.10 + '@esbuild/darwin-arm64': 0.18.10 + '@esbuild/darwin-x64': 0.18.10 + '@esbuild/freebsd-arm64': 0.18.10 + '@esbuild/freebsd-x64': 0.18.10 + '@esbuild/linux-arm': 0.18.10 + '@esbuild/linux-arm64': 0.18.10 + '@esbuild/linux-ia32': 0.18.10 + '@esbuild/linux-loong64': 0.18.10 + '@esbuild/linux-mips64el': 0.18.10 + '@esbuild/linux-ppc64': 0.18.10 + '@esbuild/linux-riscv64': 0.18.10 + '@esbuild/linux-s390x': 0.18.10 + '@esbuild/linux-x64': 0.18.10 + '@esbuild/netbsd-x64': 0.18.10 + '@esbuild/openbsd-x64': 0.18.10 + '@esbuild/sunos-x64': 0.18.10 + '@esbuild/win32-arm64': 0.18.10 + '@esbuild/win32-ia32': 0.18.10 + '@esbuild/win32-x64': 0.18.10 dev: true /escalade@3.1.1: @@ -6190,13 +6274,13 @@ packages: engines: {node: '>=12'} dev: false - /eslint-config-prettier@8.8.0(eslint@8.42.0): + /eslint-config-prettier@8.8.0(eslint@8.43.0): resolution: {integrity: sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA==} hasBin: true peerDependencies: eslint: '>=7.0.0' dependencies: - eslint: 8.42.0 + eslint: 8.43.0 dev: true /eslint-import-resolver-node@0.3.7: @@ -6209,7 +6293,7 @@ packages: - supports-color dev: true - /eslint-module-utils@2.8.0(@typescript-eslint/parser@5.59.9)(eslint-import-resolver-node@0.3.7)(eslint@8.42.0): + /eslint-module-utils@2.8.0(@typescript-eslint/parser@5.60.1)(eslint-import-resolver-node@0.3.7)(eslint@8.43.0): resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==} engines: {node: '>=4'} peerDependencies: @@ -6230,15 +6314,15 @@ packages: eslint-import-resolver-webpack: optional: true dependencies: - '@typescript-eslint/parser': 5.59.9(eslint@8.42.0)(typescript@5.1.3) + '@typescript-eslint/parser': 5.60.1(eslint@8.43.0)(typescript@5.1.6) debug: 3.2.7 - eslint: 8.42.0 + eslint: 8.43.0 eslint-import-resolver-node: 0.3.7 transitivePeerDependencies: - supports-color dev: true - /eslint-plugin-import@2.27.5(@typescript-eslint/parser@5.59.9)(eslint@8.42.0): + /eslint-plugin-import@2.27.5(@typescript-eslint/parser@5.60.1)(eslint@8.43.0): resolution: {integrity: sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==} engines: {node: '>=4'} peerDependencies: @@ -6248,15 +6332,15 @@ packages: '@typescript-eslint/parser': optional: true dependencies: - '@typescript-eslint/parser': 5.59.9(eslint@8.42.0)(typescript@5.1.3) + '@typescript-eslint/parser': 5.60.1(eslint@8.43.0)(typescript@5.1.6) array-includes: 3.1.6 array.prototype.flat: 1.3.1 array.prototype.flatmap: 1.3.1 debug: 3.2.7 doctrine: 2.1.0 - eslint: 8.42.0 + eslint: 8.43.0 eslint-import-resolver-node: 0.3.7 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@5.59.9)(eslint-import-resolver-node@0.3.7)(eslint@8.42.0) + eslint-module-utils: 2.8.0(@typescript-eslint/parser@5.60.1)(eslint-import-resolver-node@0.3.7)(eslint@8.43.0) has: 1.0.3 is-core-module: 2.12.0 is-glob: 4.0.3 @@ -6271,7 +6355,7 @@ packages: - supports-color dev: true - /eslint-plugin-jsx-a11y@6.7.1(eslint@8.42.0): + /eslint-plugin-jsx-a11y@6.7.1(eslint@8.43.0): resolution: {integrity: sha512-63Bog4iIethyo8smBklORknVjB0T2dwB8Mr/hIC+fBS0uyHdYYpzM/Ed+YC8VxTjlXHEWFOdmgwcDn1U2L9VCA==} engines: {node: '>=4.0'} peerDependencies: @@ -6286,7 +6370,7 @@ packages: axobject-query: 3.1.1 damerau-levenshtein: 1.0.8 emoji-regex: 9.2.2 - eslint: 8.42.0 + eslint: 8.43.0 has: 1.0.3 jsx-ast-utils: 3.3.3 language-tags: 1.0.5 @@ -6296,7 +6380,7 @@ packages: semver: 6.3.0 dev: true - /eslint-plugin-prettier@4.2.1(eslint-config-prettier@8.8.0)(eslint@8.42.0)(prettier@2.8.8): + /eslint-plugin-prettier@4.2.1(eslint-config-prettier@8.8.0)(eslint@8.43.0)(prettier@2.8.8): resolution: {integrity: sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==} engines: {node: '>=12.0.0'} peerDependencies: @@ -6307,22 +6391,22 @@ packages: eslint-config-prettier: optional: true dependencies: - eslint: 8.42.0 - eslint-config-prettier: 8.8.0(eslint@8.42.0) + eslint: 8.43.0 + eslint-config-prettier: 8.8.0(eslint@8.43.0) prettier: 2.8.8 prettier-linter-helpers: 1.0.0 dev: true - /eslint-plugin-react-hooks@4.6.0(eslint@8.42.0): + /eslint-plugin-react-hooks@4.6.0(eslint@8.43.0): resolution: {integrity: sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==} engines: {node: '>=10'} peerDependencies: eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 dependencies: - eslint: 8.42.0 + eslint: 8.43.0 dev: true - /eslint-plugin-react@7.32.2(eslint@8.42.0): + /eslint-plugin-react@7.32.2(eslint@8.43.0): resolution: {integrity: sha512-t2fBMa+XzonrrNkyVirzKlvn5RXzzPwRHtMvLAtVZrt8oxgnTQaYbU6SXTOO1mwQgp1y5+toMSKInnzGr0Knqg==} engines: {node: '>=4'} peerDependencies: @@ -6332,7 +6416,7 @@ packages: array.prototype.flatmap: 1.3.1 array.prototype.tosorted: 1.1.1 doctrine: 2.1.0 - eslint: 8.42.0 + eslint: 8.43.0 estraverse: 5.3.0 jsx-ast-utils: 3.3.3 minimatch: 3.1.2 @@ -6346,12 +6430,12 @@ packages: string.prototype.matchall: 4.0.8 dev: true - /eslint-plugin-simple-import-sort@10.0.0(eslint@8.42.0): + /eslint-plugin-simple-import-sort@10.0.0(eslint@8.43.0): resolution: {integrity: sha512-AeTvO9UCMSNzIHRkg8S6c3RPy5YEwKWSQPx3DYghLedo2ZQxowPFLGDN1AZ2evfg6r6mjBSZSLxLFsWSu3acsw==} peerDependencies: eslint: '>=5.0.0' dependencies: - eslint: 8.42.0 + eslint: 8.43.0 dev: true /eslint-scope@5.1.1: @@ -6375,15 +6459,15 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /eslint@8.42.0: - resolution: {integrity: sha512-ulg9Ms6E1WPf67PHaEY4/6E2tEn5/f7FXGzr3t9cBMugOmf1INYvuUwwh1aXQN4MfJ6a5K2iNwP3w4AColvI9A==} + /eslint@8.43.0: + resolution: {integrity: sha512-aaCpf2JqqKesMFGgmRPessmVKjcGXqdlAYLLC3THM8t5nBRZRQ+st5WM/hoJXkdioEXLLbXgclUpM0TXo5HX5Q==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} hasBin: true dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.42.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@8.43.0) '@eslint-community/regexpp': 4.5.0 '@eslint/eslintrc': 2.0.3 - '@eslint/js': 8.42.0 + '@eslint/js': 8.43.0 '@humanwhocodes/config-array': 0.11.10 '@humanwhocodes/module-importer': 1.0.1 '@nodelib/fs.walk': 1.2.8 @@ -6792,8 +6876,8 @@ packages: resolution: {integrity: sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==} dev: true - /framer-motion@10.12.16(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-w/SfWEIWJkYSgRHYBmln7EhcNo31ao8Xexol8lGXf1pR/tlnBtf1HcxoUmEiEh6pacB4/geku5ami53AAQWHMQ==} + /framer-motion@10.12.17(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-IR+aAYntsyu6ofyxqQV4QYotmOqzcuKxhqNpfc3DXJjNWOPpOeSyH0A+In3IEBu49Yx/+PNht+YMeZSdCNaYbw==} peerDependencies: react: ^18.0.0 react-dom: ^18.0.0 @@ -7652,6 +7736,11 @@ packages: get-intrinsic: 1.2.0 dev: true + /is-what@4.1.15: + resolution: {integrity: sha512-uKua1wfy3Yt+YqsD6mTUEa2zSi3G1oPlqTflgaPJ7z63vUGN5pxFpnQfeSLMFnJDEsdvOtkp1rUWkYjB4YfhgA==} + engines: {node: '>=12.13'} + dev: true + /is-wsl@2.2.0: resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} engines: {node: '>=8'} @@ -8846,6 +8935,10 @@ packages: /node-releases@2.0.10: resolution: {integrity: sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==} + /node-releases@2.0.12: + resolution: {integrity: sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ==} + dev: false + /node-stdlib-browser@1.2.0: resolution: {integrity: sha512-VSjFxUhRhkyed8AtLwSCkMrJRfQ3e2lGtG3sP6FEgaLKBBbxM/dLfjRe1+iLhjvyLFW3tBQ8+c0pcOtXGbAZJg==} engines: {node: '>=10'} @@ -9561,8 +9654,8 @@ packages: engines: {node: '>=8'} dev: true - /radash@10.8.1: - resolution: {integrity: sha512-NzYo3XgM9Tzjf5iFPIMG2l5+LSOCi2H7Axe3Ry/1PrhlvuqxUoiLsmcTBtw4CfKtzy5Fzo79STiEj9JZWMfDQg==} + /radash@11.0.0: + resolution: {integrity: sha512-CRWxTFTDff0IELGJ/zz58yY4BDgyI14qSM5OLNKbCItJrff7m7dXbVF0kWYVCXQtPb3SXIVhXvAImH6eT7VLSg==} engines: {node: '>=14.18.0'} dev: false @@ -9660,7 +9753,7 @@ packages: react: 18.2.0 dev: false - /react-markdown@8.0.7(@types/react@18.2.11)(react@18.2.0): + /react-markdown@8.0.7(@types/react@18.2.14)(react@18.2.0): resolution: {integrity: sha512-bvWbzG4MtOU62XqBx3Xx+zB2raaFFsq4mYiAzfjXJMEz2sixgeAfraA3tvzULF02ZdOMUOKTBFFaZJDDrq+BJQ==} peerDependencies: '@types/react': '>=16' @@ -9668,7 +9761,7 @@ packages: dependencies: '@types/hast': 2.3.4 '@types/prop-types': 15.7.5 - '@types/react': 18.2.11 + '@types/react': 18.2.14 '@types/unist': 2.0.6 comma-separated-tokens: 2.0.3 hast-util-whitespace: 2.0.1 @@ -9687,14 +9780,14 @@ packages: - supports-color dev: false - /react-popper@2.3.0(@popperjs/core@2.11.7)(react-dom@18.2.0)(react@18.2.0): + /react-popper@2.3.0(@popperjs/core@2.11.8)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-e1hj8lL3uM+sgSR4Lxzn5h1GxBlpa4CQz0XLF8kx4MDrDRWY0Ena4c97PUeSX9i5W3UAfDP0z0FXCTQkoXUl3Q==} peerDependencies: '@popperjs/core': ^2.0.0 react: ^16.8.0 || ^17 || ^18 react-dom: ^16.8.0 || ^17 || ^18 dependencies: - '@popperjs/core': 2.11.7 + '@popperjs/core': 2.11.8 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) react-fast-compare: 3.2.1 @@ -9735,26 +9828,26 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: false - /react-router-dom@6.12.1(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-POIZN9UDKWwEDga054LvYr2KnK8V+0HR4Ny4Bwv8V7/FZCPxJgsCjYxXGxqxzHs7VBxMKZfgvtKhafuJkJSPGA==} + /react-router-dom@6.14.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-YEwlApKwzMMMbGbhh+Q7MsloTldcwMgHxUY/1g0uA62+B1hZo2jsybCWIDCL8zvIDB1FA0pBKY9chHbZHt+2dQ==} engines: {node: '>=14'} peerDependencies: react: '>=16.8' react-dom: '>=16.8' dependencies: - '@remix-run/router': 1.6.3 + '@remix-run/router': 1.7.0 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - react-router: 6.12.1(react@18.2.0) + react-router: 6.14.0(react@18.2.0) dev: false - /react-router@6.12.1(react@18.2.0): - resolution: {integrity: sha512-evd/GrKJOeOypD0JB9e1r7pQh2gWCsTbUfq059Wm1AFT/K2MNZuDo19lFtAgIhlBrp0MmpgpqtvZC7LPAs7vSw==} + /react-router@6.14.0(react@18.2.0): + resolution: {integrity: sha512-OD+vkrcGbvlwkspUFDgMzsu1RXwdjNh83YgG/28lBnDzgslhCgxIqoExLlxsfTpIygp7fc+Hd3esloNwzkm2xA==} engines: {node: '>=14'} peerDependencies: react: '>=16.8' dependencies: - '@remix-run/router': 1.6.3 + '@remix-run/router': 1.7.0 react: 18.2.0 dev: false @@ -9896,8 +9989,8 @@ packages: decimal.js-light: 2.5.1 dev: false - /recharts@2.6.2(prop-types@15.8.1)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-dVhNfgI21LlF+4AesO3mj+i+9YdAAjoGaDWIctUgH/G2iy14YVtb/DSUeic77xr19rbKCiq+pQGfeg2kJQDHig==} + /recharts@2.7.2(prop-types@15.8.1)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-HMKRBkGoOXHW+7JcRa6+MukPSifNtJlqbc+JreGVNA407VLE/vOP+8n3YYjprDVVIF9E2ZgwWnL3D7K/LUFzBg==} engines: {node: '>=12'} peerDependencies: prop-types: ^15.6.0 @@ -10038,6 +10131,10 @@ packages: unified: 10.1.2 dev: false + /remove-accents@0.4.2: + resolution: {integrity: sha512-7pXIJqJOq5tFgG1A2Zxti3Ht8jJF337m4sowbuHsW30ZnkQFnDzy9qBNhgzX8ZLW4+UBcXiiR7SwR6pokHsxiA==} + dev: true + /require-directory@2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} @@ -10104,8 +10201,8 @@ packages: fsevents: 2.3.2 dev: true - /rollup@3.25.1: - resolution: {integrity: sha512-tywOR+rwIt5m2ZAWSe5AIJcTat8vGlnPFAv15ycCrw33t6iFsXZ6mzHVFh2psSjxQPmI+xgzMZZizUAukBI4aQ==} + /rollup@3.26.0: + resolution: {integrity: sha512-YzJH0eunH2hr3knvF3i6IkLO/jTjAEwU4HoMUbQl4//Tnl3ou0e7P5SjxdDr8HQJdeUJShlbEHXrrnEHy1l7Yg==} engines: {node: '>=14.18.0', npm: '>=8.0.0'} hasBin: true optionalDependencies: @@ -10183,8 +10280,8 @@ packages: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} dev: false - /sass@1.63.3: - resolution: {integrity: sha512-ySdXN+DVpfwq49jG1+hmtDslYqpS7SkOR5GpF6o2bmb1RL/xS+wvPmegMvMywyfsmAV6p7TgwXYGrCZIFFbAHg==} + /sass@1.63.6: + resolution: {integrity: sha512-MJuxGMHzaOW7ipp+1KdELtqKbfAWbH7OLIdoSMnVe3EXPMTmxTmlaZDCTsgIpPCs3w99lLo9/zDKkOrJuT5byw==} engines: {node: '>=14.0.0'} hasBin: true dependencies: @@ -10612,18 +10709,18 @@ packages: inline-style-parser: 0.1.1 dev: false - /stylelint-config-prettier-scss@1.0.0(stylelint@15.7.0): + /stylelint-config-prettier-scss@1.0.0(stylelint@15.9.0): resolution: {integrity: sha512-Gr2qLiyvJGKeDk0E/+awNTrZB/UtNVPLqCDOr07na/sLekZwm26Br6yYIeBYz3ulsEcQgs5j+2IIMXCC+wsaQA==} engines: {node: 14.* || 16.* || >= 18} hasBin: true peerDependencies: stylelint: '>=15.0.0' dependencies: - stylelint: 15.7.0 + stylelint: 15.9.0 dev: true - /stylelint-config-recommended-scss@11.0.0(postcss@8.4.24)(stylelint@15.7.0): - resolution: {integrity: sha512-EDghTDU7aOv2LTsRZvcT1w8mcjUaMhuy+t38iV5I/0Qiu6ixdkRwhLEMul3K/fnB2v9Nwqvb3xpvJfPH+HduDw==} + /stylelint-config-recommended-scss@12.0.0(postcss@8.4.24)(stylelint@15.9.0): + resolution: {integrity: sha512-5Bb2mlGy6WLa30oNeKpZvavv2lowJUsUJO25+OA68GFTemlwd1zbFsL7q0bReKipOSU3sG47hKneZ6Nd+ctrFA==} peerDependencies: postcss: ^8.3.3 stylelint: ^15.5.0 @@ -10633,21 +10730,21 @@ packages: dependencies: postcss: 8.4.24 postcss-scss: 4.0.6(postcss@8.4.24) - stylelint: 15.7.0 - stylelint-config-recommended: 12.0.0(stylelint@15.7.0) - stylelint-scss: 4.6.0(stylelint@15.7.0) + stylelint: 15.9.0 + stylelint-config-recommended: 12.0.0(stylelint@15.9.0) + stylelint-scss: 5.0.1(stylelint@15.9.0) dev: true - /stylelint-config-recommended@12.0.0(stylelint@15.7.0): + /stylelint-config-recommended@12.0.0(stylelint@15.9.0): resolution: {integrity: sha512-x6x8QNARrGO2sG6iURkzqL+Dp+4bJorPMMRNPScdvaUK8PsynriOcMW7AFDKqkWAS5wbue/u8fUT/4ynzcmqdQ==} peerDependencies: stylelint: ^15.5.0 dependencies: - stylelint: 15.7.0 + stylelint: 15.9.0 dev: true - /stylelint-config-standard-scss@9.0.0(postcss@8.4.24)(stylelint@15.7.0): - resolution: {integrity: sha512-yPKpJsrZn4ybuQZx/DkEHuCjw7pJginErE/47dFhCnrvD48IJ4UYec8tSiCuJWMA3HRjbIa3nh5ZeSauDGuVAg==} + /stylelint-config-standard-scss@10.0.0(postcss@8.4.24)(stylelint@15.9.0): + resolution: {integrity: sha512-bChBEo1p3xUVWh/wenJI+josoMk21f2yuLDGzGjmKYcALfl2u3DFltY+n4UHswYiXghqXaA8mRh+bFy/q1hQlg==} peerDependencies: postcss: ^8.3.3 stylelint: ^15.5.0 @@ -10656,34 +10753,21 @@ packages: optional: true dependencies: postcss: 8.4.24 - stylelint: 15.7.0 - stylelint-config-recommended-scss: 11.0.0(postcss@8.4.24)(stylelint@15.7.0) - stylelint-config-standard: 33.0.0(stylelint@15.7.0) + stylelint: 15.9.0 + stylelint-config-recommended-scss: 12.0.0(postcss@8.4.24)(stylelint@15.9.0) + stylelint-config-standard: 33.0.0(stylelint@15.9.0) dev: true - /stylelint-config-standard@33.0.0(stylelint@15.7.0): + /stylelint-config-standard@33.0.0(stylelint@15.9.0): resolution: {integrity: sha512-eyxnLWoXImUn77+ODIuW9qXBDNM+ALN68L3wT1lN2oNspZ7D9NVGlNHb2QCUn4xDug6VZLsh0tF8NyoYzkgTzg==} peerDependencies: stylelint: ^15.5.0 dependencies: - stylelint: 15.7.0 - stylelint-config-recommended: 12.0.0(stylelint@15.7.0) + stylelint: 15.9.0 + stylelint-config-recommended: 12.0.0(stylelint@15.9.0) dev: true - /stylelint-scss@4.6.0(stylelint@15.7.0): - resolution: {integrity: sha512-M+E0BQim6G4XEkaceEhfVjP/41C9Klg5/tTPTCQVlgw/jm2tvB+OXJGaU0TDP5rnTCB62aX6w+rT+gqJW/uwjA==} - peerDependencies: - stylelint: ^14.5.1 || ^15.0.0 - dependencies: - dlv: 1.1.3 - postcss-media-query-parser: 0.2.3 - postcss-resolve-nested-selector: 0.1.1 - postcss-selector-parser: 6.0.13 - postcss-value-parser: 4.2.0 - stylelint: 15.7.0 - dev: true - - /stylelint-scss@5.0.1(stylelint@15.7.0): + /stylelint-scss@5.0.1(stylelint@15.9.0): resolution: {integrity: sha512-n87iCRZrr2J7//I/QFsDXxFLnHKw633U4qvWZ+mOW6KDAp/HLj06H+6+f9zOuTYy+MdGdTuCSDROCpQIhw5fvQ==} peerDependencies: stylelint: ^14.5.1 || ^15.0.0 @@ -10692,11 +10776,11 @@ packages: postcss-resolve-nested-selector: 0.1.1 postcss-selector-parser: 6.0.13 postcss-value-parser: 4.2.0 - stylelint: 15.7.0 + stylelint: 15.9.0 dev: true - /stylelint@15.7.0: - resolution: {integrity: sha512-fQRwHwWuZsDn4ENyE9AsKkOkV9WlD2CmYiVDbdZPdS3iZh0ceypOn1EuwTNuZ8xTrHF+jVeIEzLtFFSlD/nJHg==} + /stylelint@15.9.0: + resolution: {integrity: sha512-sXtAZi64CllWr6A+8ymDWnlIaYwuAa7XRmGnJxLQXFNnLjd3Izm4HAD+loKVaZ7cpK6SLxhAUX1lwPJKGCn0mg==} engines: {node: ^14.13.1 || >=16.0.0} hasBin: true dependencies: @@ -10740,7 +10824,6 @@ packages: supports-hyperlinks: 3.0.0 svg-tags: 1.0.0 table: 6.8.1 - v8-compile-cache: 2.3.0 write-file-atomic: 5.0.1 transitivePeerDependencies: - supports-color @@ -10764,6 +10847,13 @@ packages: ts-interface-checker: 0.1.13 dev: false + /superjson@1.12.4: + resolution: {integrity: sha512-vkpPQAxdCg9SLfPv5GPC5fnGrui/WryktoN9O5+Zif/14QIMjw+RITf/5LbBh+9QpBFb3KNvJth+puz2H8o6GQ==} + engines: {node: '>=10'} + dependencies: + copy-anything: 3.0.5 + dev: true + /superstruct@0.14.2: resolution: {integrity: sha512-nPewA6m9mR3d6k7WkZ8N8zpTWfenFH3q9pA2PkuiZxINr9DKB2+40wEQf0ixn8VaGuJ78AB6iWOtStI+/4FKZQ==} dev: false @@ -10838,8 +10928,8 @@ packages: strip-ansi: 6.0.1 dev: true - /terser@5.17.7: - resolution: {integrity: sha512-/bi0Zm2C6VAexlGgLlVxA0P2lru/sdLyfCVaRMfKVo9nWxbmz7f/sD8VPybPeSUJaJcwmCJis9pBIhcVcG1QcQ==} + /terser@5.18.2: + resolution: {integrity: sha512-Ah19JS86ypbJzTzvUCX7KOsEIhDaRONungA4aYBjEP3JZRf4ocuDzTg4QWZnPn9DEMiMYGJPiSOy7aykoCc70w==} engines: {node: '>=10'} hasBin: true dependencies: @@ -10985,14 +11075,14 @@ packages: engines: {node: '>=0.6.x'} dev: false - /tsutils@3.21.0(typescript@5.1.3): + /tsutils@3.21.0(typescript@5.1.6): resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} engines: {node: '>= 6'} peerDependencies: typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' dependencies: tslib: 1.14.1 - typescript: 5.1.3 + typescript: 5.1.6 dev: true /tty-browserify@0.0.1: @@ -11057,7 +11147,7 @@ packages: resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} dev: true - /typedoc@0.24.8(typescript@5.1.3): + /typedoc@0.24.8(typescript@5.1.6): resolution: {integrity: sha512-ahJ6Cpcvxwaxfu4KtjA8qZNqS43wYt6JL27wYiIgl1vd38WW/KWX11YuAeZhuz9v+ttrutSsgK+XO1CjL1kA3w==} engines: {node: '>= 14.14'} hasBin: true @@ -11068,20 +11158,20 @@ packages: marked: 4.3.0 minimatch: 9.0.0 shiki: 0.14.1 - typescript: 5.1.3 + typescript: 5.1.6 dev: true - /typesafe-i18n@5.24.3(typescript@5.1.3): + /typesafe-i18n@5.24.3(typescript@5.1.6): resolution: {integrity: sha512-VqjGbIydOqtQjO81mGo++TjuqeC8YoxxgYrO1/ikXIS/l/Q6mAcz4yrt5AvqjdFHMt3gRm7oGbVI/yLyV+VTOg==} hasBin: true peerDependencies: typescript: '>=3.5.1' dependencies: - typescript: 5.1.3 + typescript: 5.1.6 dev: false - /typescript@5.1.3: - resolution: {integrity: sha512-XH627E9vkeqhlZFQuL+UsyAXEnibT0kWR2FWONlr4sTjvxyJYnyefgrkyECLzM5NenmKzRAy2rR/OlYLA1HkZw==} + /typescript@5.1.6: + resolution: {integrity: sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==} engines: {node: '>=14.17'} hasBin: true @@ -11208,6 +11298,17 @@ packages: escalade: 3.1.1 picocolors: 1.0.0 + /update-browserslist-db@1.0.11(browserslist@4.21.9): + resolution: {integrity: sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + dependencies: + browserslist: 4.21.9 + escalade: 3.1.1 + picocolors: 1.0.0 + dev: false + /uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} dependencies: @@ -11249,7 +11350,6 @@ packages: react: ^16.8.0 || ^17.0.0 || ^18.0.0 dependencies: react: 18.2.0 - dev: false /utf-8-validate@5.0.10: resolution: {integrity: sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==} @@ -11287,10 +11387,6 @@ packages: sade: 1.8.1 dev: false - /v8-compile-cache@2.3.0: - resolution: {integrity: sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==} - dev: true - /validate-npm-package-license@3.0.4: resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} dependencies: @@ -11359,7 +11455,7 @@ packages: d3-timer: 3.0.1 dev: false - /vite-plugin-eslint@1.8.1(eslint@8.42.0)(vite@4.3.9): + /vite-plugin-eslint@1.8.1(eslint@8.43.0)(vite@4.3.9): resolution: {integrity: sha512-PqdMf3Y2fLO9FsNPmMX+//2BF5SF8nEWspZdgl4kSt7UvHDRHVVfHvxsD7ULYzZrJDGRxR81Nq7TOFgwMnUang==} peerDependencies: eslint: '>=7' @@ -11367,19 +11463,19 @@ packages: dependencies: '@rollup/pluginutils': 4.2.1 '@types/eslint': 8.37.0 - eslint: 8.42.0 + eslint: 8.43.0 rollup: 2.79.1 - vite: 4.3.9(sass@1.63.3)(terser@5.17.7) + vite: 4.3.9(sass@1.63.6)(terser@5.18.2) dev: true - /vite-plugin-node-polyfills@0.9.0(rollup@3.25.1)(vite@4.3.9): + /vite-plugin-node-polyfills@0.9.0(rollup@3.26.0)(vite@4.3.9): resolution: {integrity: sha512-+i+WPUuIBhJy+ODfxx6S6FTl28URCxUszbl/IL4GwrZvbqqY/8VDIp+zpjMS8Us/a7GwN4Iaqr/fVIBtkNQojQ==} peerDependencies: vite: ^2.0.0 || ^3.0.0 || ^4.0.0 dependencies: - '@rollup/plugin-inject': 5.0.3(rollup@3.25.1) + '@rollup/plugin-inject': 5.0.3(rollup@3.26.0) node-stdlib-browser: 1.2.0 - vite: 4.3.9(sass@1.63.3)(terser@5.17.7) + vite: 4.3.9(sass@1.63.6)(terser@5.18.2) transitivePeerDependencies: - rollup dev: false @@ -11389,7 +11485,7 @@ packages: peerDependencies: vite: '>=2.0.0-beta.69' dependencies: - vite: 4.3.9(sass@1.63.3)(terser@5.17.7) + vite: 4.3.9(sass@1.63.6)(terser@5.18.2) dev: true /vite-tsconfig-paths@3.6.0(vite@4.3.9): @@ -11401,12 +11497,12 @@ packages: globrex: 0.1.2 recrawl-sync: 2.2.3 tsconfig-paths: 4.2.0 - vite: 4.3.9(sass@1.63.3)(terser@5.17.7) + vite: 4.3.9(sass@1.63.6)(terser@5.18.2) transitivePeerDependencies: - supports-color dev: false - /vite@4.3.9(sass@1.63.3)(terser@5.17.7): + /vite@4.3.9(sass@1.63.6)(terser@5.18.2): resolution: {integrity: sha512-qsTNZjO9NoJNW7KnOrgYwczm0WctJ8m/yqYAMAK9Lxt4SoySUfS5S8ia9K7JHpa3KEeMfyF8LoJ3c5NeBJy6pg==} engines: {node: ^14.18.0 || >=16.0.0} hasBin: true @@ -11433,9 +11529,9 @@ packages: dependencies: esbuild: 0.17.18 postcss: 8.4.24 - rollup: 3.25.1 - sass: 1.63.3 - terser: 5.17.7 + rollup: 3.26.0 + sass: 1.63.6 + terser: 5.18.2 optionalDependencies: fsevents: 2.3.2 @@ -11451,7 +11547,7 @@ packages: resolution: {integrity: sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==} dev: true - /wagmi@0.10.15(ethers@5.7.2)(react-dom@18.2.0)(react@18.2.0)(typescript@5.1.3): + /wagmi@0.10.15(ethers@5.7.2)(react-dom@18.2.0)(react@18.2.0)(typescript@5.1.6): resolution: {integrity: sha512-hyVhPJ9KrgQULCvdbxggbq+1O61O4Cqo2NQ+f6xT7EUwOXYS+SDvasy5EpyKToxkTSlR4+LhbQR+0+u70e2OkA==} peerDependencies: ethers: '>=5.5.1' @@ -11459,11 +11555,11 @@ packages: dependencies: '@coinbase/wallet-sdk': 3.6.6 '@tanstack/query-sync-storage-persister': 4.29.5 - '@tanstack/react-query': 4.29.12(react-dom@18.2.0)(react@18.2.0) - '@tanstack/react-query-persist-client': 4.29.5(@tanstack/react-query@4.29.12) - '@wagmi/core': 0.8.19(@coinbase/wallet-sdk@3.6.6)(@walletconnect/ethereum-provider@1.8.0)(ethers@5.7.2)(react@18.2.0)(typescript@5.1.3) + '@tanstack/react-query': 4.29.19(react-dom@18.2.0)(react@18.2.0) + '@tanstack/react-query-persist-client': 4.29.5(@tanstack/react-query@4.29.19) + '@wagmi/core': 0.8.19(@coinbase/wallet-sdk@3.6.6)(@walletconnect/ethereum-provider@1.8.0)(ethers@5.7.2)(react@18.2.0)(typescript@5.1.6) '@walletconnect/ethereum-provider': 1.8.0 - abitype: 0.2.5(typescript@5.1.3) + abitype: 0.2.5(typescript@5.1.6) ethers: 5.7.2 react: 18.2.0 use-sync-external-store: 1.2.0(react@18.2.0) diff --git a/web/src-tauri/Cargo.lock b/web/src-tauri/Cargo.lock index f2245cbb9..3f88df8d9 100644 --- a/web/src-tauri/Cargo.lock +++ b/web/src-tauri/Cargo.lock @@ -2,6 +2,15 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "addr2line" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" +dependencies = [ + "gimli", +] + [[package]] name = "adler" version = "1.0.2" @@ -93,7 +102,7 @@ dependencies = [ "glib-sys", "gobject-sys", "libc", - "system-deps 6.1.0", + "system-deps 6.1.1", ] [[package]] @@ -102,6 +111,21 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "backtrace" +version = "0.3.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + [[package]] name = "base64" version = "0.13.1" @@ -211,7 +235,7 @@ checksum = "3c55d429bef56ac9172d25fecb85dc8068307d17acd74b377866b7a1ef25d3c8" dependencies = [ "glib-sys", "libc", - "system-deps 6.1.0", + "system-deps 6.1.1", ] [[package]] @@ -221,7 +245,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "599aa35200ffff8f04c1925aa1acc92fa2e08874379ef42e210a80e527e60838" dependencies = [ "serde", - "toml 0.7.3", + "toml 0.7.5", ] [[package]] @@ -258,9 +282,9 @@ dependencies = [ [[package]] name = "cfg-expr" -version = "0.15.2" +version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e70d3ad08698a0568b0562f22710fe6bfc1f4a61a367c77d0398c562eadd453a" +checksum = "215c0072ecc28f92eeb0eea38ba63ddfcb65c2828c46311d646f1a3ff5f9841c" dependencies = [ "smallvec", "target-lexicon", @@ -369,21 +393,20 @@ dependencies = [ [[package]] name = "core-graphics-types" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a68b68b3446082644c91ac778bf50cd4104bfb002b5a6a7c44cca5a2c70788b" +checksum = "2bb142d41022986c1d8ff29103a1411c8a3dfad3552f87a4f8dc50d61d4f4e33" dependencies = [ "bitflags", "core-foundation", - "foreign-types", "libc", ] [[package]] name = "cpufeatures" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e4c1eaa2012c47becbbad2ab175484c2a84d1185b566fb2cc5b8707343dfe58" +checksum = "03e69e28e9f7f77debdedbaafa2866e1de9ba56df55a8bd7cfc724c25a09987c" dependencies = [ "libc", ] @@ -409,9 +432,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.15" +version = "0.8.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" dependencies = [ "cfg-if", ] @@ -450,7 +473,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" dependencies = [ "quote", - "syn 2.0.18", + "syn 2.0.22", ] [[package]] @@ -463,12 +486,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "cty" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" - [[package]] name = "darling" version = "0.20.1" @@ -490,7 +507,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.18", + "syn 2.0.22", ] [[package]] @@ -501,7 +518,7 @@ checksum = "29a358ff9f12ec09c3e61fef9b5a9902623a695a46a917b07f269bff1445611a" dependencies = [ "darling_core", "quote", - "syn 2.0.18", + "syn 2.0.22", ] [[package]] @@ -583,7 +600,7 @@ checksum = "80663502655af01a2902dff3f06869330782267924bf1788410b74edcd93770a" dependencies = [ "cc", "rustc_version", - "toml 0.7.3", + "toml 0.7.5", "vswhom", "winreg", ] @@ -603,6 +620,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "equivalent" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88bffebc5d80432c9b140ee17875ff173a8ab62faad5b257da912bd2f6c1c0a1" + [[package]] name = "errno" version = "0.3.1" @@ -754,7 +777,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.22", ] [[package]] @@ -825,7 +848,7 @@ dependencies = [ "glib-sys", "gobject-sys", "libc", - "system-deps 6.1.0", + "system-deps 6.1.1", ] [[package]] @@ -842,7 +865,7 @@ dependencies = [ "libc", "pango-sys", "pkg-config", - "system-deps 6.1.0", + "system-deps 6.1.1", ] [[package]] @@ -856,7 +879,7 @@ dependencies = [ "gobject-sys", "libc", "pkg-config", - "system-deps 6.1.0", + "system-deps 6.1.1", ] [[package]] @@ -868,15 +891,15 @@ dependencies = [ "gdk-sys", "glib-sys", "libc", - "system-deps 6.1.0", + "system-deps 6.1.1", "x11", ] [[package]] name = "generator" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3e123d9ae7c02966b4d892e550bdc32164f05853cd40ab570650ad600596a8a" +checksum = "5cc16584ff22b460a382b7feec54b23d2908d858152e5739a120b949293bd74e" dependencies = [ "cc", "libc", @@ -917,6 +940,12 @@ dependencies = [ "wasi 0.11.0+wasi-snapshot-preview1", ] +[[package]] +name = "gimli" +version = "0.27.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" + [[package]] name = "gio" version = "0.15.12" @@ -943,7 +972,7 @@ dependencies = [ "glib-sys", "gobject-sys", "libc", - "system-deps 6.1.0", + "system-deps 6.1.1", "winapi", ] @@ -989,7 +1018,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef4b192f8e65e9cf76cbf4ea71fa8e3be4a0e18ffe3d68b8da6836974cc5bad4" dependencies = [ "libc", - "system-deps 6.1.0", + "system-deps 6.1.1", ] [[package]] @@ -1019,7 +1048,7 @@ checksum = "0d57ce44246becd17153bd035ab4d32cfee096a657fc01f2231c9278378d1e0a" dependencies = [ "glib-sys", "libc", - "system-deps 6.1.0", + "system-deps 6.1.1", ] [[package]] @@ -1060,7 +1089,7 @@ dependencies = [ "gobject-sys", "libc", "pango-sys", - "system-deps 6.1.0", + "system-deps 6.1.1", ] [[package]] @@ -1083,6 +1112,12 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +[[package]] +name = "hashbrown" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" + [[package]] name = "heck" version = "0.3.3" @@ -1098,15 +1133,6 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" -[[package]] -name = "hermit-abi" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" -dependencies = [ - "libc", -] - [[package]] name = "hermit-abi" version = "0.3.1" @@ -1201,11 +1227,10 @@ dependencies = [ [[package]] name = "ignore" -version = "0.4.18" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "713f1b139373f96a2e0ce3ac931cd01ee973c3c5dd7c40c0c2efe96ad2b6751d" +checksum = "dbe7873dab538a9a44ad79ede1faf5f30d49f9a5c883ddbab48bce81b64b7492" dependencies = [ - "crossbeam-utils", "globset", "lazy_static", "log", @@ -1237,10 +1262,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", - "hashbrown", + "hashbrown 0.12.3", "serde", ] +[[package]] +name = "indexmap" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +dependencies = [ + "equivalent", + "hashbrown 0.14.0", +] + [[package]] name = "infer" version = "0.12.0" @@ -1265,7 +1300,7 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ - "hermit-abi 0.3.1", + "hermit-abi", "libc", "windows-sys", ] @@ -1327,9 +1362,9 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "js-sys" -version = "0.3.63" +version = "0.3.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f37a4a5928311ac501dee68b3c7613a1037d0edb30c8e5427bd832d55d1b790" +checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" dependencies = [ "wasm-bindgen", ] @@ -1366,9 +1401,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.146" +version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" [[package]] name = "line-wrap" @@ -1567,11 +1602,11 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.2.6", + "hermit-abi", "libc", ] @@ -1596,15 +1631,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "num_threads" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" -dependencies = [ - "libc", -] - [[package]] name = "objc" version = "0.2.7" @@ -1633,6 +1659,15 @@ dependencies = [ "objc", ] +[[package]] +name = "object" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" +dependencies = [ + "memchr", +] + [[package]] name = "once_cell" version = "1.18.0" @@ -1667,7 +1702,7 @@ dependencies = [ "glib-sys", "gobject-sys", "libc", - "system-deps 6.1.0", + "system-deps 6.1.1", ] [[package]] @@ -1822,7 +1857,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9bd9647b268a3d3e14ff09c23201133a62589c658db02bb7388c7246aafe0590" dependencies = [ "base64 0.21.2", - "indexmap", + "indexmap 1.9.3", "line-wrap", "quick-xml", "serde", @@ -1896,9 +1931,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro2" -version = "1.0.60" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406" +checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb" dependencies = [ "unicode-ident", ] @@ -1914,9 +1949,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.28" +version = "1.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" +checksum = "573015e8ab27661678357f27dc26460738fd2b6c86e46f386fde94cb5d913105" dependencies = [ "proc-macro2", ] @@ -2004,12 +2039,9 @@ dependencies = [ [[package]] name = "raw-window-handle" -version = "0.5.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed7e3d950b66e19e0c372f3fa3fbbcf85b1746b571f74e0c2af6042a5c93420a" -dependencies = [ - "cty", -] +checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9" [[package]] name = "redox_syscall" @@ -2072,6 +2104,12 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + [[package]] name = "rustc_version" version = "0.4.0" @@ -2083,9 +2121,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.37.20" +version = "0.37.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b96e891d04aa506a6d1f318d2771bcb1c7dfda84e126660ace067c9b474bb2c0" +checksum = "62f25693a73057a1b4cb56179dd3c7ea21a7c6c5ee7d85781f5749b46f34b79c" dependencies = [ "bitflags", "errno", @@ -2180,14 +2218,14 @@ checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.22", ] [[package]] name = "serde_json" -version = "1.0.96" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" +checksum = "46266871c240a00b8f503b877622fe33430b3c7d963bdc0f2adc511e54a1eae3" dependencies = [ "itoa 1.0.6", "ryu", @@ -2202,28 +2240,28 @@ checksum = "bcec881020c684085e55a25f7fd888954d56609ef363479dc5a1305eb0d40cab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.22", ] [[package]] name = "serde_spanned" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93107647184f6027e3b7dcb2e11034cf95ffa1e3a682c67951963ac69c1c007d" +checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186" dependencies = [ "serde", ] [[package]] name = "serde_with" -version = "2.3.3" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07ff71d2c147a7b57362cead5e22f772cd52f6ab31cfcd9edcd7f6aeb2a0afbe" +checksum = "9f02d8aa6e3c385bf084924f660ce2a3a6bd333ba55b35e8590b321f35d88513" dependencies = [ - "base64 0.13.1", + "base64 0.21.2", "chrono", "hex", - "indexmap", + "indexmap 1.9.3", "serde", "serde_json", "serde_with_macros", @@ -2232,14 +2270,14 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "2.3.3" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "881b6f881b17d13214e5d494c939ebab463d01264ce1811e9d4ac3a882e7695f" +checksum = "edc7d5d3932fb12ce722ee5e64dd38c504efba37567f0c402f6ca728c3b8b070" dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.22", ] [[package]] @@ -2276,9 +2314,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" dependencies = [ "cfg-if", "cpufeatures", @@ -2409,9 +2447,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.18" +version = "2.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" +checksum = "2efbeae7acf4eabd6bcdcbd11c92f45231ddda7539edc7806bd1a04a03b24616" dependencies = [ "proc-macro2", "quote", @@ -2433,14 +2471,14 @@ dependencies = [ [[package]] name = "system-deps" -version = "6.1.0" +version = "6.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5fa6fb9ee296c0dc2df41a656ca7948546d061958115ddb0bcaae43ad0d17d2" +checksum = "30c2de8a4d8f4b823d634affc9cd2a74ec98c53a756f317e529a48046cbf71f3" dependencies = [ - "cfg-expr 0.15.2", + "cfg-expr 0.15.3", "heck 0.4.1", "pkg-config", - "toml 0.7.3", + "toml 0.7.5", "version-compare 0.1.1", ] @@ -2515,15 +2553,15 @@ dependencies = [ [[package]] name = "target-lexicon" -version = "0.12.7" +version = "0.12.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd1ba337640d60c3e96bc6f0638a939b9c9a7f2c316a1598c279828b3d1dc8c5" +checksum = "1b1c7f239eb94671427157bd93b3694320f3668d4e1eff08c7285366fd777fac" [[package]] name = "tauri" -version = "1.3.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d42ba3a2e8556722f31336a0750c10dbb6a81396a1c452977f515da83f69f842" +checksum = "7fbe522898e35407a8e60dc3870f7579fea2fc262a6a6072eccdd37ae1e1d91e" dependencies = [ "anyhow", "cocoa", @@ -2566,9 +2604,9 @@ dependencies = [ [[package]] name = "tauri-build" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "929b3bd1248afc07b63e33a6a53c3f82c32d0b0a5e216e4530e94c467e019389" +checksum = "7d2edd6a259b5591c8efdeb9d5702cb53515b82a6affebd55c7fd6d3a27b7d1b" dependencies = [ "anyhow", "cargo_toml", @@ -2579,14 +2617,13 @@ dependencies = [ "serde_json", "tauri-utils", "tauri-winres", - "winnow", ] [[package]] name = "tauri-codegen" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5a2105f807c6f50b2fa2ce5abd62ef207bc6f14c9fcc6b8caec437f6fb13bde" +checksum = "54ad2d49fdeab4a08717f5b49a163bdc72efc3b1950b6758245fcde79b645e1a" dependencies = [ "base64 0.21.2", "brotli", @@ -2609,9 +2646,9 @@ dependencies = [ [[package]] name = "tauri-macros" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8784cfe6f5444097e93c69107d1ac5e8f13d02850efa8d8f2a40fe79674cef46" +checksum = "8eb12a2454e747896929338d93b0642144bb51e0dddbb36e579035731f0d76b7" dependencies = [ "heck 0.4.1", "proc-macro2", @@ -2623,9 +2660,9 @@ dependencies = [ [[package]] name = "tauri-runtime" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3b80ea3fcd5fefb60739a3b577b277e8fc30434538a2f5bba82ad7d4368c422" +checksum = "108683199cb18f96d2d4134187bb789964143c845d2d154848dda209191fd769" dependencies = [ "gtk", "http", @@ -2644,9 +2681,9 @@ dependencies = [ [[package]] name = "tauri-runtime-wry" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1c396950b1ba06aee1b4ffe6c7cd305ff433ca0e30acbc5fa1a2f92a4ce70f1" +checksum = "0b7aa256a1407a3a091b5d843eccc1a5042289baf0a43d1179d9f0fcfea37c1b" dependencies = [ "cocoa", "gtk", @@ -2664,12 +2701,13 @@ dependencies = [ [[package]] name = "tauri-utils" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a6f9c2dafef5cbcf52926af57ce9561bd33bb41d7394f8bb849c0330260d864" +checksum = "03fc02bb6072bb397e1d473c6f76c953cda48b4a2d0cce605df284aa74a12e84" dependencies = [ "brotli", "ctor", + "dunce", "glob", "heck 0.4.1", "html5ever", @@ -2697,7 +2735,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5993dc129e544393574288923d1ec447c857f3f644187f4fbf7d9a875fbfc4fb" dependencies = [ "embed-resource", - "toml 0.7.3", + "toml 0.7.5", ] [[package]] @@ -2748,7 +2786,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.22", ] [[package]] @@ -2763,14 +2801,29 @@ dependencies = [ [[package]] name = "time" -version = "0.3.15" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d634a985c4d4238ec39cacaed2e7ae552fbd3c476b552c1deac3021b7d7eaf0c" +checksum = "ea9e1b3cf1243ae005d9e74085d4d542f3125458f3a81af210d901dcd7411efd" dependencies = [ "itoa 1.0.6", - "libc", - "num_threads", "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" + +[[package]] +name = "time-macros" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "372950940a5f07bf38dbe211d7283c9e6d7327df53794992d293e534c733d09b" +dependencies = [ + "time-core", ] [[package]] @@ -2790,15 +2843,15 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.28.2" +version = "1.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94d7b1cfd2aa4011f2de74c2c4c63665e27a71006b0a192dcd2710272e73dfa2" +checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da" dependencies = [ "autocfg", + "backtrace", "bytes", "num_cpus", "pin-project-lite", - "windows-sys", ] [[package]] @@ -2812,9 +2865,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.7.3" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b403acf6f2bb0859c93c7f0d967cb4a75a7ac552100f9322faf64dc047669b21" +checksum = "1ebafdf5ad1220cb59e7d17cf4d2c72015297b75b19a10472f99b89225089240" dependencies = [ "serde", "serde_spanned", @@ -2824,20 +2877,20 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a76a9312f5ba4c2dec6b9161fdf25d87ad8a09256ccea5a556fef03c706a10f" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.19.8" +version = "0.19.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "239410c8609e8125456927e6707163a3b1fdb40561e4b803bc041f466ccfdc13" +checksum = "266f016b7f039eec8a1a80dfe6156b633d208b9fccca5e4db1d6775b0c4e34a7" dependencies = [ - "indexmap", + "indexmap 2.0.0", "serde", "serde_spanned", "toml_datetime", @@ -2858,13 +2911,13 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.24" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f57e3ca2a01450b1a921183a9c9cbfda207fd822cef4ccb00a65402cbba7a74" +checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.22", ] [[package]] @@ -2968,9 +3021,9 @@ checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" [[package]] name = "uuid" -version = "1.3.3" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "345444e32442451b267fc254ae85a209c64be56d2890e601a0c37ff0c3c5ecd2" +checksum = "d023da39d1fde5a8a3fe1f3e01ca9632ada0a63e9797de55a879d6e2236277be" dependencies = [ "getrandom 0.2.10", ] @@ -3043,9 +3096,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bba0e8cb82ba49ff4e229459ff22a191bbe9a1cb3a341610c9c33efc27ddf73" +checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -3053,24 +3106,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b04bc93f9d6bdee709f6bd2118f57dd6679cf1176a1af464fca3ab0d66d8fb" +checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.22", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14d6b024f1a526bb0234f52840389927257beb670610081360e5a03c5df9c258" +checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3078,22 +3131,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8" +checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.22", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed9d5b4305409d1fc9482fee2d7f9bcbf24b3972bf59817ef757e23982242a93" +checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" [[package]] name = "webkit2gtk" @@ -3139,7 +3192,7 @@ dependencies = [ "pango-sys", "pkg-config", "soup2-sys", - "system-deps 6.1.0", + "system-deps 6.1.1", ] [[package]] @@ -3271,9 +3324,9 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.48.0" +version = "0.48.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc 0.48.0", @@ -3364,9 +3417,9 @@ checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" [[package]] name = "winnow" -version = "0.4.1" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae8970b36c66498d8ff1d66685dc86b91b29db0c7739899012f63a63814b4b28" +checksum = "ca0ace3845f0d96209f0375e6d367e3eb87eb65d27d445bdc9f1843a26f39448" dependencies = [ "memchr", ] diff --git a/web/src/components/AppLoader.tsx b/web/src/components/AppLoader.tsx index 567a2dcc3..fa30ad737 100644 --- a/web/src/components/AppLoader.tsx +++ b/web/src/components/AppLoader.tsx @@ -12,7 +12,6 @@ import LoaderPage from '../pages/loader/LoaderPage'; import { isUserAdmin } from '../shared/helpers/isUserAdmin'; import { useAppStore } from '../shared/hooks/store/useAppStore'; import { useAuthStore } from '../shared/hooks/store/useAuthStore'; -import { useNavigationStore } from '../shared/hooks/store/useNavigationStore'; import useApi from '../shared/hooks/useApi'; import { useToaster } from '../shared/hooks/useToaster'; import { QueryKeys } from '../shared/queries'; @@ -32,27 +31,17 @@ export const AppLoader = () => { user: { getMe }, settings: { getSettings }, license: { getLicense }, - network: { getNetworks }, } = useApi(); const [userLoading, setUserLoading] = useState(true); const { setLocale } = useI18nContext(); const activeLanguage = useAppStore((state) => state.language); const setAppStore = useAppStore((state) => state.setAppStore); - const setNavigation = useNavigationStore((state) => state.setState); const license = useAppStore((state) => state.license); const { LL } = useI18nContext(); useQuery([QueryKeys.FETCH_ME], getMe, { onSuccess: async (user) => { const isAdmin = isUserAdmin(user); - if (isAdmin) { - const networks = await getNetworks(); - if (networks.length === 0) { - setNavigation({ enableWizard: true }); - } else { - setNavigation({ enableWizard: false }); - } - } setAuthState({ isAdmin, user }); setUserLoading(false); }, @@ -75,7 +64,7 @@ export const AppLoader = () => { toaster.error(LL.messages.errorVersion()); console.error(err); }, - refetchOnWindowFocus: true, + refetchOnWindowFocus: false, retry: false, enabled: !isUndefined(currentUser), }); diff --git a/web/src/components/Navigation/Navigation.tsx b/web/src/components/Navigation/Navigation.tsx index 651aa98d2..6b8dc093b 100644 --- a/web/src/components/Navigation/Navigation.tsx +++ b/web/src/components/Navigation/Navigation.tsx @@ -50,7 +50,6 @@ export const Navigation = () => { (state) => [state.isNavigationOpen, state.setNavigationOpen, state.user], shallow ); - const [enableWizard] = useNavigationStore((state) => [state.enableWizard], shallow); const { auth: { logout }, } = useApi(); @@ -101,14 +100,7 @@ export const Navigation = () => { linkPath: '/admin/overview', icon: , allowedToView: ['admin'], - enabled: settings?.wireguard_enabled && !enableWizard, - }, - { - title: LL.navigation.bar.wizard(), - linkPath: '/admin/wizard', - icon: , - allowedToView: ['admin'], - enabled: settings?.wireguard_enabled && enableWizard, + enabled: settings?.wireguard_enabled, }, { title: LL.navigation.bar.users(), diff --git a/web/src/i18n/en/index.ts b/web/src/i18n/en/index.ts index a94e87d6a..4d61104c1 100644 --- a/web/src/i18n/en/index.ts +++ b/web/src/i18n/en/index.ts @@ -119,8 +119,8 @@ const en: BaseTranslation = { messages: { copyConfig: 'Config copied to clipboard', }, - inputNameLabel: 'Device Name', - warningMessage: ` + helpers: { + warningAutoMode: `

Please be advised that you have to download the configuration now, since we do not store your private key. After this @@ -128,23 +128,27 @@ const en: BaseTranslation = { full configuration file (with private keys, only blank template).

`, + warningManualMode: ` +

+ Please be advised that configuration provided here does not include private key and uses public key to fill it's place you will need to repalce it on your own for configuration to work properly. +

+`, + qrHelper: ` +

+ You can setup your device faster with wireguard application by scanning this QR code. +

`, + }, qrInfo: 'Use provided configuration file below by scanning QR Code or importing it as file on your devices WireGuard instance.', + inputNameLabel: 'Device Name', qrLabel: 'WireGuard Config File', - qrHelper: ` -

- This configuration file can be scanned, copied or downloaded, but - needs to be used - on your device that you are adding now. - Read more in documentation. -

`, - qrCardTitle: 'WireGuard Config', + qrCardTitle: 'WireGuard Config for location:', }, setup: { infoMessage: `

You need to configure WireguardVPN on your device, please visit  - documentation if you don't know how to do it. + documentation if you don't know how to do it.

`, options: { @@ -152,7 +156,7 @@ const en: BaseTranslation = { manual: 'Use my own public key', }, form: { - submit: 'Generate Config', + submit: 'Generate configuration', fields: { name: { label: 'Device Name', @@ -358,6 +362,7 @@ const en: BaseTranslation = { }, messages: { editSuccess: 'User updated.', + failedToFetchUserData: 'Could not get user information.', }, userDetails: { header: 'Profile Details', @@ -451,14 +456,15 @@ const en: BaseTranslation = { }, card: { labels: { - location: 'Last location', - lastIpAddress: 'Last IP address', - date: 'Date added', + lastLocation: 'Last connected from', + lastConnected: 'Last connected', + assignedIp: 'Assigned IP', + active: 'active', }, edit: { edit: 'Edit device', - download: 'Download config', delete: 'Delete device', + showConfigurations: 'Show configuration', }, }, }, @@ -591,6 +597,20 @@ const en: BaseTranslation = { }, }, components: { + gatewaysStatus: { + label: 'Gateways', + states: { + connected: 'All connected', + partial: 'One or more are not working', + disconnected: 'Disconnected', + error: 'Retrieving connections failed', + loading: 'Retrieving connections', + }, + messages: { + error: 'Failed to get gateways status', + deleteError: 'Failed to delete gateway', + }, + }, noLicenseBox: { footer: { get: 'Get an enterprise license', @@ -934,10 +954,12 @@ Any other requests you can reach us at: support@defguard.net }, }, networkOverview: { - pageTitle: 'Network overview', + pageTitle: 'Location overview', controls: { - editNetwork: 'Edit network settings', - configureNetwork: 'Configure network settings', + editNetworks: 'Edit Locations settings', + selectNetwork: { + placeholder: 'Loading locations', + }, }, filterLabels: { grid: 'Grid view', @@ -967,29 +989,32 @@ Any other requests you can reach us at: support@defguard.net }, }, networkPage: { - pageTitle: 'Edit network', + pageTitle: 'Edit Location', + addNetwork: '+ Add new location', }, activityOverview: { header: 'Activity stream', noData: 'Currently there is no activity detected', }, networkConfiguration: { - header: 'Network configuration', - importHeader: 'Network import', + header: 'Location configuration', + importHeader: 'Location import', form: { - messages: { + helpers: { address: 'Based on this address VPN network address will be defined, eg. 10.10.10.1/24 (and VPN network will be: 10.10.10.0/24)', gateway: 'Gateway public address, used by VPN users to connect', dns: 'Specify the DNS resolvers to query when the wireguard interface is up.', allowedIps: 'List of addresses/masks that should be routed through the VPN network.', - networkModified: 'Network modified.', - networkCreated: 'Network created.', + }, + messages: { + networkModified: 'Location modified.', + networkCreated: 'Location created', }, fields: { name: { - label: 'Network name', + label: 'Location name', }, address: { label: 'Gateway VPN IP address and netmask', @@ -1009,7 +1034,7 @@ Any other requests you can reach us at: support@defguard.net }, controls: { submit: 'Save changes', - cancel: 'Back', + cancel: 'Back to Overview', }, }, }, @@ -1121,7 +1146,10 @@ Any other requests you can reach us at: support@defguard.net }, }, deviceMap: { - crateSuccess: 'Devices added', + messages: { + crateSuccess: 'Devices added', + errorsInForm: 'Please fill marked fields.', + }, list: { headers: { deviceName: 'Device Name', @@ -1156,6 +1184,11 @@ Any other requests you can reach us at: support@defguard.net }, }, }, + layout: { + select: { + addNewOption: 'Add new', + }, + }, }; export default en; diff --git a/web/src/i18n/i18n-types.ts b/web/src/i18n/i18n-types.ts index 30e06d831..6cc87b6b5 100644 --- a/web/src/i18n/i18n-types.ts +++ b/web/src/i18n/i18n-types.ts @@ -247,41 +247,48 @@ type RootTranslation = { */ copyConfig: string } - /** - * D​e​v​i​c​e​ ​N​a​m​e - */ - inputNameLabel: string - /** - * - ​ ​ ​ ​ ​ ​ ​ ​ ​<​p​>​ - ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​P​l​e​a​s​e​ ​b​e​ ​a​d​v​i​s​e​d​ ​t​h​a​t​ ​y​o​u​ ​h​a​v​e​ ​t​o​ ​d​o​w​n​l​o​a​d​ ​t​h​e​ ​c​o​n​f​i​g​u​r​a​t​i​o​n​ ​n​o​w​,​ - ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​s​i​n​c​e​ ​<​s​t​r​o​n​g​>​w​e​ ​d​o​ ​n​o​t​<​/​s​t​r​o​n​g​>​ ​s​t​o​r​e​ ​y​o​u​r​ ​p​r​i​v​a​t​e​ ​k​e​y​.​ ​A​f​t​e​r​ ​t​h​i​s​ - ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​d​i​a​l​o​g​ ​i​s​ ​c​l​o​s​e​d​,​ ​y​o​u​ ​<​s​t​r​o​n​g​>​w​i​l​l​ ​n​o​t​ ​b​e​ ​a​b​l​e​<​/​s​t​r​o​n​g​>​ ​t​o​ ​g​e​t​ ​y​o​u​r​ - ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​f​u​l​l​ ​c​o​n​f​i​g​u​r​a​t​i​o​n​ ​f​i​l​e​ ​(​w​i​t​h​ ​p​r​i​v​a​t​e​ ​k​e​y​s​,​ ​o​n​l​y​ ​b​l​a​n​k​ ​t​e​m​p​l​a​t​e​)​.​ - ​ ​ ​ ​ ​ ​ ​ ​ ​<​/​p​>​ - - */ - warningMessage: string + helpers: { + /** + * + ​ ​ ​ ​ ​ ​ ​ ​ ​<​p​>​ + ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​P​l​e​a​s​e​ ​b​e​ ​a​d​v​i​s​e​d​ ​t​h​a​t​ ​y​o​u​ ​h​a​v​e​ ​t​o​ ​d​o​w​n​l​o​a​d​ ​t​h​e​ ​c​o​n​f​i​g​u​r​a​t​i​o​n​ ​n​o​w​,​ + ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​s​i​n​c​e​ ​<​s​t​r​o​n​g​>​w​e​ ​d​o​ ​n​o​t​<​/​s​t​r​o​n​g​>​ ​s​t​o​r​e​ ​y​o​u​r​ ​p​r​i​v​a​t​e​ ​k​e​y​.​ ​A​f​t​e​r​ ​t​h​i​s​ + ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​d​i​a​l​o​g​ ​i​s​ ​c​l​o​s​e​d​,​ ​y​o​u​ ​<​s​t​r​o​n​g​>​w​i​l​l​ ​n​o​t​ ​b​e​ ​a​b​l​e​<​/​s​t​r​o​n​g​>​ ​t​o​ ​g​e​t​ ​y​o​u​r​ + ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​f​u​l​l​ ​c​o​n​f​i​g​u​r​a​t​i​o​n​ ​f​i​l​e​ ​(​w​i​t​h​ ​p​r​i​v​a​t​e​ ​k​e​y​s​,​ ​o​n​l​y​ ​b​l​a​n​k​ ​t​e​m​p​l​a​t​e​)​.​ + ​ ​ ​ ​ ​ ​ ​ ​ ​<​/​p​>​ + + */ + warningAutoMode: string + /** + * + ​ ​ ​ ​ ​ ​ ​ ​ ​<​p​>​ + ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​P​l​e​a​s​e​ ​b​e​ ​a​d​v​i​s​e​d​ ​t​h​a​t​ ​c​o​n​f​i​g​u​r​a​t​i​o​n​ ​p​r​o​v​i​d​e​d​ ​h​e​r​e​ ​<​s​t​r​o​n​g​>​ ​d​o​e​s​ ​n​o​t​ ​i​n​c​l​u​d​e​ ​p​r​i​v​a​t​e​ ​k​e​y​ ​a​n​d​ ​u​s​e​s​ ​p​u​b​l​i​c​ ​k​e​y​ ​t​o​ ​f​i​l​l​ ​i​t​'​s​ ​p​l​a​c​e​ ​<​/​s​t​r​o​n​g​>​ ​y​o​u​ ​w​i​l​l​ ​n​e​e​d​ ​t​o​ ​r​e​p​a​l​c​e​ ​i​t​ ​o​n​ ​y​o​u​r​ ​o​w​n​ ​f​o​r​ ​c​o​n​f​i​g​u​r​a​t​i​o​n​ ​t​o​ ​w​o​r​k​ ​p​r​o​p​e​r​l​y​.​ + ​ ​ ​ ​ ​ ​ ​ ​ ​<​/​p​>​ + + */ + warningManualMode: string + /** + * + ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​<​p​>​ + ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​Y​o​u​ ​c​a​n​ ​s​e​t​u​p​ ​y​o​u​r​ ​d​e​v​i​c​e​ ​f​a​s​t​e​r​ ​w​i​t​h​ ​w​i​r​e​g​u​a​r​d​ ​a​p​p​l​i​c​a​t​i​o​n​ ​b​y​ ​s​c​a​n​n​i​n​g​ ​t​h​i​s​ ​Q​R​ ​c​o​d​e​.​ + ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​<​/​p​> + */ + qrHelper: string + } /** * U​s​e​ ​p​r​o​v​i​d​e​d​ ​c​o​n​f​i​g​u​r​a​t​i​o​n​ ​f​i​l​e​ ​b​e​l​o​w​ ​b​y​ ​s​c​a​n​n​i​n​g​ ​Q​R​ ​C​o​d​e​ ​o​r​ ​i​m​p​o​r​t​i​n​g​ ​i​t​ ​a​s​ ​f​i​l​e​ ​o​n​ ​y​o​u​r​ ​d​e​v​i​c​e​s​ ​W​i​r​e​G​u​a​r​d​ ​i​n​s​t​a​n​c​e​. */ qrInfo: string /** - * W​i​r​e​G​u​a​r​d​ ​C​o​n​f​i​g​ ​F​i​l​e + * D​e​v​i​c​e​ ​N​a​m​e */ - qrLabel: string + inputNameLabel: string /** - * - ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​<​p​>​ - ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​T​h​i​s​ ​c​o​n​f​i​g​u​r​a​t​i​o​n​ ​f​i​l​e​ ​c​a​n​ ​b​e​ ​s​c​a​n​n​e​d​,​ ​c​o​p​i​e​d​ ​o​r​ ​d​o​w​n​l​o​a​d​e​d​,​ ​b​u​t​ - ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​n​e​e​d​s​ ​t​o​ ​b​e​ ​u​s​e​d​ - ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​<​s​t​r​o​n​g​>​o​n​ ​y​o​u​r​ ​d​e​v​i​c​e​ ​t​h​a​t​ ​y​o​u​ ​a​r​e​ ​a​d​d​i​n​g​ ​n​o​w​.​<​/​s​t​r​o​n​g​>​ - ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​<​a​>​R​e​a​d​ ​m​o​r​e​ ​i​n​ ​d​o​c​u​m​e​n​t​a​t​i​o​n​.​<​/​a​>​ - ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​<​/​p​> + * W​i​r​e​G​u​a​r​d​ ​C​o​n​f​i​g​ ​F​i​l​e */ - qrHelper: string + qrLabel: string /** - * W​i​r​e​G​u​a​r​d​ ​C​o​n​f​i​g + * W​i​r​e​G​u​a​r​d​ ​C​o​n​f​i​g​ ​f​o​r​ ​l​o​c​a​t​i​o​n​: */ qrCardTitle: string } @@ -290,7 +297,7 @@ type RootTranslation = { * ​ ​ ​ ​ ​ ​ ​ ​ ​<​p​>​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​Y​o​u​ ​n​e​e​d​ ​t​o​ ​c​o​n​f​i​g​u​r​e​ ​W​i​r​e​g​u​a​r​d​V​P​N​ ​o​n​ ​y​o​u​r​ ​d​e​v​i​c​e​,​ ​p​l​e​a​s​e​ ​v​i​s​i​t​&​n​b​s​p​;​ - ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​<​a​ ​h​r​e​f​=​"​"​>​d​o​c​u​m​e​n​t​a​t​i​o​n​<​/​a​>​ ​i​f​ ​y​o​u​ ​d​o​n​&​a​p​o​s​;​t​ ​k​n​o​w​ ​h​o​w​ ​t​o​ ​d​o​ ​i​t​.​ + ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​<​a​ ​h​r​e​f​=​"​h​t​t​p​s​:​/​/​d​e​f​g​u​a​r​d​.​g​i​t​b​o​o​k​.​i​o​/​d​e​f​g​u​a​r​d​/​f​e​a​t​u​r​e​s​/​w​i​r​e​g​u​a​r​d​/​a​d​d​i​n​g​-​w​i​r​e​g​u​a​r​d​-​d​e​v​i​c​e​s​"​>​d​o​c​u​m​e​n​t​a​t​i​o​n​<​/​a​>​ ​i​f​ ​y​o​u​ ​d​o​n​&​a​p​o​s​;​t​ ​k​n​o​w​ ​h​o​w​ ​t​o​ ​d​o​ ​i​t​.​ ​ ​ ​ ​ ​ ​ ​ ​ ​<​/​p​>​ */ @@ -307,7 +314,7 @@ type RootTranslation = { } form: { /** - * G​e​n​e​r​a​t​e​ ​C​o​n​f​i​g + * G​e​n​e​r​a​t​e​ ​c​o​n​f​i​g​u​r​a​t​i​o​n */ submit: string fields: { @@ -751,6 +758,10 @@ type RootTranslation = { * U​s​e​r​ ​u​p​d​a​t​e​d​. */ editSuccess: string + /** + * C​o​u​l​d​ ​n​o​t​ ​g​e​t​ ​u​s​e​r​ ​i​n​f​o​r​m​a​t​i​o​n​. + */ + failedToFetchUserData: string } userDetails: { /** @@ -968,31 +979,35 @@ type RootTranslation = { card: { labels: { /** - * L​a​s​t​ ​l​o​c​a​t​i​o​n + * L​a​s​t​ ​c​o​n​n​e​c​t​e​d​ ​f​r​o​m */ - location: string + lastLocation: string /** - * L​a​s​t​ ​I​P​ ​a​d​d​r​e​s​s + * L​a​s​t​ ​c​o​n​n​e​c​t​e​d */ - lastIpAddress: string + lastConnected: string /** - * D​a​t​e​ ​a​d​d​e​d + * A​s​s​i​g​n​e​d​ ​I​P */ - date: string + assignedIp: string + /** + * a​c​t​i​v​e + */ + active: string } edit: { /** * E​d​i​t​ ​d​e​v​i​c​e */ edit: string - /** - * D​o​w​n​l​o​a​d​ ​c​o​n​f​i​g - */ - download: string /** * D​e​l​e​t​e​ ​d​e​v​i​c​e */ 'delete': string + /** + * S​h​o​w​ ​c​o​n​f​i​g​u​r​a​t​i​o​n + */ + showConfigurations: string } } } @@ -1375,6 +1390,44 @@ type RootTranslation = { } } components: { + gatewaysStatus: { + /** + * G​a​t​e​w​a​y​s + */ + label: string + states: { + /** + * A​l​l​ ​c​o​n​n​e​c​t​e​d + */ + connected: string + /** + * O​n​e​ ​o​r​ ​m​o​r​e​ ​a​r​e​ ​n​o​t​ ​w​o​r​k​i​n​g + */ + partial: string + /** + * D​i​s​c​o​n​n​e​c​t​e​d + */ + disconnected: string + /** + * R​e​t​r​i​e​v​i​n​g​ ​c​o​n​n​e​c​t​i​o​n​s​ ​f​a​i​l​e​d + */ + error: string + /** + * R​e​t​r​i​e​v​i​n​g​ ​c​o​n​n​e​c​t​i​o​n​s + */ + loading: string + } + messages: { + /** + * F​a​i​l​e​d​ ​t​o​ ​g​e​t​ ​g​a​t​e​w​a​y​s​ ​s​t​a​t​u​s + */ + error: string + /** + * F​a​i​l​e​d​ ​t​o​ ​d​e​l​e​t​e​ ​g​a​t​e​w​a​y + */ + deleteError: string + } + } noLicenseBox: { footer: { /** @@ -2132,18 +2185,20 @@ type RootTranslation = { } networkOverview: { /** - * N​e​t​w​o​r​k​ ​o​v​e​r​v​i​e​w + * L​o​c​a​t​i​o​n​ ​o​v​e​r​v​i​e​w */ pageTitle: string controls: { /** - * E​d​i​t​ ​n​e​t​w​o​r​k​ ​s​e​t​t​i​n​g​s + * E​d​i​t​ ​L​o​c​a​t​i​o​n​s​ ​s​e​t​t​i​n​g​s */ - editNetwork: string - /** - * C​o​n​f​i​g​u​r​e​ ​n​e​t​w​o​r​k​ ​s​e​t​t​i​n​g​s - */ - configureNetwork: string + editNetworks: string + selectNetwork: { + /** + * L​o​a​d​i​n​g​ ​l​o​c​a​t​i​o​n​s + */ + placeholder: string + } } filterLabels: { /** @@ -2231,9 +2286,13 @@ type RootTranslation = { } networkPage: { /** - * E​d​i​t​ ​n​e​t​w​o​r​k + * E​d​i​t​ ​L​o​c​a​t​i​o​n */ pageTitle: string + /** + * +​ ​A​d​d​ ​n​e​w​ ​l​o​c​a​t​i​o​n + */ + addNetwork: string } activityOverview: { /** @@ -2247,15 +2306,15 @@ type RootTranslation = { } networkConfiguration: { /** - * N​e​t​w​o​r​k​ ​c​o​n​f​i​g​u​r​a​t​i​o​n + * L​o​c​a​t​i​o​n​ ​c​o​n​f​i​g​u​r​a​t​i​o​n */ header: string /** - * N​e​t​w​o​r​k​ ​i​m​p​o​r​t + * L​o​c​a​t​i​o​n​ ​i​m​p​o​r​t */ importHeader: string form: { - messages: { + helpers: { /** * B​a​s​e​d​ ​o​n​ ​t​h​i​s​ ​a​d​d​r​e​s​s​ ​V​P​N​ ​n​e​t​w​o​r​k​ ​a​d​d​r​e​s​s​ ​w​i​l​l​ ​b​e​ ​d​e​f​i​n​e​d​,​ ​e​g​.​ ​1​0​.​1​0​.​1​0​.​1​/​2​4​ ​(​a​n​d​ ​V​P​N​ ​n​e​t​w​o​r​k​ ​w​i​l​l​ ​b​e​:​ ​1​0​.​1​0​.​1​0​.​0​/​2​4​) */ @@ -2272,19 +2331,21 @@ type RootTranslation = { * L​i​s​t​ ​o​f​ ​a​d​d​r​e​s​s​e​s​/​m​a​s​k​s​ ​t​h​a​t​ ​s​h​o​u​l​d​ ​b​e​ ​r​o​u​t​e​d​ ​t​h​r​o​u​g​h​ ​t​h​e​ ​V​P​N​ ​n​e​t​w​o​r​k​. */ allowedIps: string + } + messages: { /** - * N​e​t​w​o​r​k​ ​m​o​d​i​f​i​e​d​. + * L​o​c​a​t​i​o​n​ ​m​o​d​i​f​i​e​d​. */ networkModified: string /** - * N​e​t​w​o​r​k​ ​c​r​e​a​t​e​d​. + * L​o​c​a​t​i​o​n​ ​c​r​e​a​t​e​d */ networkCreated: string } fields: { name: { /** - * N​e​t​w​o​r​k​ ​n​a​m​e + * L​o​c​a​t​i​o​n​ ​n​a​m​e */ label: string } @@ -2325,7 +2386,7 @@ type RootTranslation = { */ submit: string /** - * B​a​c​k + * B​a​c​k​ ​t​o​ ​O​v​e​r​v​i​e​w */ cancel: string } @@ -2554,10 +2615,16 @@ type RootTranslation = { } } deviceMap: { - /** - * D​e​v​i​c​e​s​ ​a​d​d​e​d - */ - crateSuccess: string + messages: { + /** + * D​e​v​i​c​e​s​ ​a​d​d​e​d + */ + crateSuccess: string + /** + * P​l​e​a​s​e​ ​f​i​l​l​ ​m​a​r​k​e​d​ ​f​i​e​l​d​s​. + */ + errorsInForm: string + } list: { headers: { /** @@ -2644,6 +2711,14 @@ type RootTranslation = { } } } + layout: { + select: { + /** + * A​d​d​ ​n​e​w + */ + addNewOption: string + } + } } export type TranslationFunctions = { @@ -2879,41 +2954,48 @@ export type TranslationFunctions = { */ copyConfig: () => LocalizedString } - /** - * Device Name - */ - inputNameLabel: () => LocalizedString - /** - * -

- Please be advised that you have to download the configuration now, - since we do not store your private key. After this - dialog is closed, you will not be able to get your - full configuration file (with private keys, only blank template). -

- - */ - warningMessage: () => LocalizedString + helpers: { + /** + * +

+ Please be advised that you have to download the configuration now, + since we do not store your private key. After this + dialog is closed, you will not be able to get your + full configuration file (with private keys, only blank template). +

+ + */ + warningAutoMode: () => LocalizedString + /** + * +

+ Please be advised that configuration provided here does not include private key and uses public key to fill it's place you will need to repalce it on your own for configuration to work properly. +

+ + */ + warningManualMode: () => LocalizedString + /** + * +

+ You can setup your device faster with wireguard application by scanning this QR code. +

+ */ + qrHelper: () => LocalizedString + } /** * Use provided configuration file below by scanning QR Code or importing it as file on your devices WireGuard instance. */ qrInfo: () => LocalizedString /** - * WireGuard Config File + * Device Name */ - qrLabel: () => LocalizedString + inputNameLabel: () => LocalizedString /** - * -

- This configuration file can be scanned, copied or downloaded, but - needs to be used - on your device that you are adding now. - Read more in documentation. -

+ * WireGuard Config File */ - qrHelper: () => LocalizedString + qrLabel: () => LocalizedString /** - * WireGuard Config + * WireGuard Config for location: */ qrCardTitle: () => LocalizedString } @@ -2922,7 +3004,7 @@ export type TranslationFunctions = { *

You need to configure WireguardVPN on your device, please visit  - documentation if you don't know how to do it. + documentation if you don't know how to do it.

*/ @@ -2939,7 +3021,7 @@ export type TranslationFunctions = { } form: { /** - * Generate Config + * Generate configuration */ submit: () => LocalizedString fields: { @@ -3378,6 +3460,10 @@ export type TranslationFunctions = { * User updated. */ editSuccess: () => LocalizedString + /** + * Could not get user information. + */ + failedToFetchUserData: () => LocalizedString } userDetails: { /** @@ -3595,31 +3681,35 @@ export type TranslationFunctions = { card: { labels: { /** - * Last location + * Last connected from */ - location: () => LocalizedString + lastLocation: () => LocalizedString /** - * Last IP address + * Last connected */ - lastIpAddress: () => LocalizedString + lastConnected: () => LocalizedString /** - * Date added + * Assigned IP */ - date: () => LocalizedString + assignedIp: () => LocalizedString + /** + * active + */ + active: () => LocalizedString } edit: { /** * Edit device */ edit: () => LocalizedString - /** - * Download config - */ - download: () => LocalizedString /** * Delete device */ 'delete': () => LocalizedString + /** + * Show configuration + */ + showConfigurations: () => LocalizedString } } } @@ -4001,6 +4091,44 @@ export type TranslationFunctions = { } } components: { + gatewaysStatus: { + /** + * Gateways + */ + label: () => LocalizedString + states: { + /** + * All connected + */ + connected: () => LocalizedString + /** + * One or more are not working + */ + partial: () => LocalizedString + /** + * Disconnected + */ + disconnected: () => LocalizedString + /** + * Retrieving connections failed + */ + error: () => LocalizedString + /** + * Retrieving connections + */ + loading: () => LocalizedString + } + messages: { + /** + * Failed to get gateways status + */ + error: () => LocalizedString + /** + * Failed to delete gateway + */ + deleteError: () => LocalizedString + } + } noLicenseBox: { footer: { /** @@ -4752,18 +4880,20 @@ export type TranslationFunctions = { } networkOverview: { /** - * Network overview + * Location overview */ pageTitle: () => LocalizedString controls: { /** - * Edit network settings + * Edit Locations settings */ - editNetwork: () => LocalizedString - /** - * Configure network settings - */ - configureNetwork: () => LocalizedString + editNetworks: () => LocalizedString + selectNetwork: { + /** + * Loading locations + */ + placeholder: () => LocalizedString + } } filterLabels: { /** @@ -4848,9 +4978,13 @@ export type TranslationFunctions = { } networkPage: { /** - * Edit network + * Edit Location */ pageTitle: () => LocalizedString + /** + * + Add new location + */ + addNetwork: () => LocalizedString } activityOverview: { /** @@ -4864,15 +4998,15 @@ export type TranslationFunctions = { } networkConfiguration: { /** - * Network configuration + * Location configuration */ header: () => LocalizedString /** - * Network import + * Location import */ importHeader: () => LocalizedString form: { - messages: { + helpers: { /** * Based on this address VPN network address will be defined, eg. 10.10.10.1/24 (and VPN network will be: 10.10.10.0/24) */ @@ -4889,19 +5023,21 @@ export type TranslationFunctions = { * List of addresses/masks that should be routed through the VPN network. */ allowedIps: () => LocalizedString + } + messages: { /** - * Network modified. + * Location modified. */ networkModified: () => LocalizedString /** - * Network created. + * Location created */ networkCreated: () => LocalizedString } fields: { name: { /** - * Network name + * Location name */ label: () => LocalizedString } @@ -4942,7 +5078,7 @@ export type TranslationFunctions = { */ submit: () => LocalizedString /** - * Back + * Back to Overview */ cancel: () => LocalizedString } @@ -5171,10 +5307,16 @@ export type TranslationFunctions = { } } deviceMap: { - /** - * Devices added - */ - crateSuccess: () => LocalizedString + messages: { + /** + * Devices added + */ + crateSuccess: () => LocalizedString + /** + * Please fill marked fields. + */ + errorsInForm: () => LocalizedString + } list: { headers: { /** @@ -5261,6 +5403,14 @@ export type TranslationFunctions = { } } } + layout: { + select: { + /** + * Add new + */ + addNewOption: () => LocalizedString + } + } } export type Formatters = {} diff --git a/web/src/i18n/pl/index.ts b/web/src/i18n/pl/index.ts index 30857a752..0c98004a2 100644 --- a/web/src/i18n/pl/index.ts +++ b/web/src/i18n/pl/index.ts @@ -120,24 +120,29 @@ const pl: Translation = { messages: { copyConfig: 'Konfiguracja skopiowana do schowka.', }, - inputNameLabel: 'Nazwa urzÄ…dzenia', - warningMessage: ` -

- Informujemy, że musisz teraz pobrać konfigurację, ponieważ nie przechowujemy Twojego klucza prywatnego. - Po zamknięciu tego okna dialogowego nie będzie można uzyskać pełnego pliku konfiguracyjnego - (z kluczami prywatnymi, tylko z pustym szablonem). -

-`, - qrInfo: `Użyj dostarczonego pliku konfiguracyjnego poniżej skanując QR Code lub importując go jako plik na - instancję WireGuard w Twoich urządzeniach.`, - qrLabel: 'Plik konfiguracyjny Wireguard', - qrHelper: ` + helpers: { + qrHelper: `

Ten plik konfiguracyjny można zeskanować, skopiować lub pobrać, ale musi być użyty na urządzeniu, które teraz dodajesz. Przeczytaj więcej w dokumentacji.

`, - qrCardTitle: 'Konfiguracja Wireguard', + warningAutoMode: ` +

+ Informujemy, że musisz pobrać teraz plik konifguracjny. Ponieważ nie przechowujemy twojego klucza prywatnego, nie będzie możliwe ponowne pobranie klucza prywatnego dla tego urządzenia co uniemożliwi połączenie się tego użądzenia z VPN. +

+`, + warningManualMode: ` +

+ Informujemy, że podany plik konfiguracyjny nie posiada klucza prywatnego. Musisz uzupełnić konfigurację o swój klucz prywatny aby urządzenie mogło nawiązać połączenie z VPN. +

+`, + }, + inputNameLabel: 'Nazwa urządzenia', + qrInfo: `Użyj dostarczonego pliku konfiguracyjnego poniżej skanując QR Code lub importując go jako plik na + instancję WireGuard w Twoich urządzeniach.`, + qrLabel: 'Plik konfiguracyjny Wireguard', + qrCardTitle: 'Konfiguracja dla lokalizacji:', }, setup: { infoMessage: ` @@ -358,6 +363,7 @@ const pl: Translation = { }, messages: { editSuccess: 'Użytkownik zaktualizowany.', + failedToFetchUserData: 'Błąd pobierania informacji o użtkowniku.', }, userDetails: { header: 'Szczegóły profilu', @@ -451,14 +457,15 @@ const pl: Translation = { }, card: { labels: { - location: 'Ostatnia lokalizacja', - lastIpAddress: 'Ostatni adres IP', - date: 'Data dodania', + lastLocation: 'Ostatnie połączenie z', + active: 'aktywne', + assignedIp: 'Przydzielone IP', + lastConnected: 'Ostatnio połączone', }, edit: { edit: 'Edycja urządzenia', - download: 'Pobierz konfigurację', delete: 'Usuń urządzenie', + showConfigurations: 'Pokaż konfiguracje', }, }, }, @@ -591,6 +598,20 @@ const pl: Translation = { }, }, components: { + gatewaysStatus: { + label: 'Gateways', + states: { + error: 'Błąd pobierania statusu', + loading: 'Pobieranie informacji', + partial: 'Jeden lub więcej odłączonych', + connected: 'Połączone', + disconnected: 'Brak połączenia', + }, + messages: { + error: 'Błąd pobierania statusu połączeń gatway', + deleteError: 'Błąd usuwania gateway', + }, + }, noLicenseBox: { footer: { get: 'Uzyskaj licencję enterprise', @@ -934,10 +955,12 @@ W przypadku innych zgłoszeń skontaktuj się z nami: support@defguard.net }, }, networkOverview: { - pageTitle: 'Przegląd sieci', + pageTitle: 'Przegląd lokalizacji', controls: { - editNetwork: 'Edycja ustawień sieci', - configureNetwork: 'Konfiguracja ustawień sieci', + editNetworks: 'Edycja lokalizacji', + selectNetwork: { + placeholder: 'Oczekiwanie na lokalizacje', + }, }, filterLabels: { grid: 'Widok siatki', @@ -967,29 +990,32 @@ W przypadku innych zgłoszeń skontaktuj się z nami: support@defguard.net }, }, networkPage: { - pageTitle: 'Edycja sieci', + pageTitle: 'Edycja lokalizacji', + addNetwork: '+ Dodaj lokalizacje', }, activityOverview: { header: 'Strumien aktywności', noData: 'Obecnie nie wykryto żadnej aktywności', }, networkConfiguration: { - header: 'Konfiguracja sieci', - importHeader: 'Import sieci', + header: 'Konfiguracja lokalizacji', + importHeader: 'Import lokalizacji', form: { - messages: { + helpers: { address: 'Od tego adresu będzie stworzona sieć VPN, np. 10.10.10.1/24 (sieć VPN będzie: 10.10.10.0/24)', gateway: 'Adres publiczny Gatewaya, używany przez użytkowników VPN do łączenia się.', dns: 'Określ resolwery DNS, które mają odpytywać, gdy interfejs wireguard jest aktywny.', allowedIps: 'Lista adresów/masek, które powinny być routowane przez sieć VPN.', - networkModified: 'Sieć zmodyfikowana.', - networkCreated: 'Sieć utworzona.', + }, + messages: { + networkModified: 'Lokalizacja zmodyfikowana', + networkCreated: 'Lokalizacja utworzona', }, fields: { name: { - label: 'Nazwa sieci', + label: 'Nazwa lokalizacji', }, address: { label: 'Adres i maska sieci VPN', @@ -1009,7 +1035,7 @@ W przypadku innych zgłoszeń skontaktuj się z nami: support@defguard.net }, controls: { submit: 'Zapisz zmiany', - cancel: 'Cofnij', + cancel: 'Wróć', }, }, }, @@ -1123,7 +1149,10 @@ W przypadku innych zgłoszeń skontaktuj się z nami: support@defguard.net sub: 'Zanim zaczniesz, musisz wybrać tryb konfiguracji. Ikony zawierają przydane informacje.', }, deviceMap: { - crateSuccess: 'Urządzenia dodane', + messages: { + crateSuccess: 'Urządzenie dodane', + errorsInForm: 'Uzupełnij oznaczone pola', + }, list: { headers: { deviceName: 'Nazwa', @@ -1158,6 +1187,11 @@ W przypadku innych zgłoszeń skontaktuj się z nami: support@defguard.net }, }, }, + layout: { + select: { + addNewOption: 'Dodaj', + }, + }, }; export default pl; diff --git a/web/src/pages/auth/AuthPage.tsx b/web/src/pages/auth/AuthPage.tsx index 903bd91bc..a0941127b 100644 --- a/web/src/pages/auth/AuthPage.tsx +++ b/web/src/pages/auth/AuthPage.tsx @@ -9,7 +9,6 @@ import SvgDefguardLogoLogin from '../../shared/components/svg/DefguardLogoLogin' import { isUserAdmin } from '../../shared/helpers/isUserAdmin'; import { useAppStore } from '../../shared/hooks/store/useAppStore'; import { useAuthStore } from '../../shared/hooks/store/useAuthStore'; -import { useNavigationStore } from '../../shared/hooks/store/useNavigationStore'; import useApi from '../../shared/hooks/useApi'; import { useToaster } from '../../shared/hooks/useToaster'; import { UserMFAMethod } from '../../shared/types'; @@ -24,10 +23,6 @@ export const AuthPage = () => { const loginSubject = useAuthStore((state) => state.loginSubject); - const setNavigation = useNavigationStore((state) => state.setState); - - const wizardEnabled = useNavigationStore((state) => state.enableWizard); - const setAuthStore = useAuthStore((state) => state.setState); const [openIdParams, user] = useAuthStore( @@ -102,10 +97,8 @@ export const AuthPage = () => { const appInfo = await getAppInfo(); setAppStore({ appInfo }); if (!appInfo?.network_present) { - setNavigation({ enableWizard: true }); navigateURL = '/admin/wizard'; } else { - setNavigation({ enableWizard: false }); navigateURL = '/admin/overview'; } } @@ -116,7 +109,7 @@ export const AuthPage = () => { }); return () => sub?.unsubscribe(); // eslint-disable-next-line react-hooks/exhaustive-deps - }, [loginSubject, openIdParams, wizardEnabled]); + }, [loginSubject, openIdParams]); return (
diff --git a/web/src/pages/network/NetworkControls/NetworkControls.tsx b/web/src/pages/network/NetworkControls/NetworkControls.tsx new file mode 100644 index 000000000..94fcebe7d --- /dev/null +++ b/web/src/pages/network/NetworkControls/NetworkControls.tsx @@ -0,0 +1,39 @@ +import './style.scss'; + +import { useNavigate } from 'react-router'; +import { shallow } from 'zustand/shallow'; + +import { useI18nContext } from '../../../i18n/i18n-react'; +import Button, { + ButtonSize, + ButtonStyleVariant, +} from '../../../shared/components/layout/Button/Button'; +import { IconCheckmarkWhite } from '../../../shared/components/svg'; +import { useNetworkPageStore } from '../hooks/useNetworkPageStore'; + +export const NetworkControls = () => { + const navigate = useNavigate(); + const { LL } = useI18nContext(); + const [save, loading] = useNetworkPageStore( + (state) => [state.saveSubject, state.loading], + shallow + ); + return ( +
+
+ ); +}; diff --git a/web/src/pages/network/NetworkControls/style.scss b/web/src/pages/network/NetworkControls/style.scss new file mode 100644 index 000000000..f2f3c36e4 --- /dev/null +++ b/web/src/pages/network/NetworkControls/style.scss @@ -0,0 +1,13 @@ +@use '@scssutils' as *; + +#network-page { + .network-controls { + column-gap: 20px; + display: flex; + flex-flow: row nowrap; + height: 100%; + width: 100%; + align-items: center; + justify-content: flex-end; + } +} diff --git a/web/src/pages/network/NetworkConfiguration/NetworkConfiguration.tsx b/web/src/pages/network/NetworkEditForm/NetworkEditForm.tsx similarity index 57% rename from web/src/pages/network/NetworkConfiguration/NetworkConfiguration.tsx rename to web/src/pages/network/NetworkEditForm/NetworkEditForm.tsx index afd8e3e4e..36e800fc9 100644 --- a/web/src/pages/network/NetworkConfiguration/NetworkConfiguration.tsx +++ b/web/src/pages/network/NetworkEditForm/NetworkEditForm.tsx @@ -5,12 +5,11 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; import { isNull, omit, omitBy } from 'lodash-es'; import { useEffect, useMemo, useRef } from 'react'; import { SubmitHandler, useForm } from 'react-hook-form'; -import { useNavigate } from 'react-router'; import * as yup from 'yup'; +import { shallow } from 'zustand/shallow'; import { useI18nContext } from '../../../i18n/i18n-react'; import { FormInput } from '../../../shared/components/Form/FormInput/FormInput'; -import { Card } from '../../../shared/components/layout/Card/Card'; import { Helper } from '../../../shared/components/layout/Helper/Helper'; import MessageBox from '../../../shared/components/layout/MessageBox/MessageBox'; import useApi from '../../../shared/hooks/useApi'; @@ -26,7 +25,7 @@ import { } from '../../../shared/validators'; import { useNetworkPageStore } from '../hooks/useNetworkPageStore'; -type FormInputs = ModifyNetworkRequest; +type FormInputs = ModifyNetworkRequest['network']; const defaultValues: FormInputs = { address: '', @@ -46,59 +45,35 @@ const networkToForm = (data?: Network): FormInputs | undefined => { return { ...defaultValues, ...omited } as FormInputs; }; -export const NetworkConfiguration: React.FC = () => { +export const NetworkEditForm = () => { const toaster = useToaster(); const { - network: { addNetwork, editNetwork }, + network: { editNetwork }, } = useApi(); const submitRef = useRef(null); - const network = useNetworkPageStore((state) => state.network); const setStoreState = useNetworkPageStore((state) => state.setState); const submitSubject = useNetworkPageStore((state) => state.saveSubject); + const [selectedNetworkId, networks] = useNetworkPageStore( + (state) => [state.selectedNetworkId, state.networks], + shallow + ); const queryClient = useQueryClient(); const { LL } = useI18nContext(); - const { mutateAsync: editNetworkMutation, isLoading: editLoading } = useMutation( - [MutationKeys.CHANGE_NETWORK], - editNetwork, - { - onSuccess: async (response) => { - setStoreState({ network: response }); - toaster.success(LL.networkConfiguration.form.messages.networkModified()); - await queryClient.refetchQueries([QueryKeys.FETCH_NETWORK_TOKEN]); - }, - onError: (err) => { - console.error(err); - toaster.error(LL.messages.error()); - }, - } - ); - const { mutateAsync: addNetworkMutation, isLoading: addLoading } = useMutation( - [MutationKeys.ADD_NETWORK], - addNetwork, - { - onSuccess: async (network) => { - setStoreState({ network, loading: false }); - toaster.success(LL.networkConfiguration.form.messages.networkCreated()); - await queryClient.refetchQueries([QueryKeys.FETCH_NETWORK_TOKEN]); - }, - onError: (err) => { - setStoreState({ loading: false }); - toaster.error(LL.messages.error()); - console.error(err); - }, - } - ); + const { mutateAsync } = useMutation([MutationKeys.CHANGE_NETWORK], editNetwork); const defaultFormValues = useMemo(() => { - if (network) { - const res = networkToForm(network); - if (res) { - return res; + if (selectedNetworkId && networks) { + const network = networks.find((n) => n.id === selectedNetworkId); + if (network) { + const res = networkToForm(network); + if (res) { + return res; + } } } return defaultValues; - }, [network]); + }, [networks, selectedNetworkId]); const schema = yup .object({ @@ -148,26 +123,44 @@ export const NetworkConfiguration: React.FC = () => { }) .required(); - const { control, handleSubmit } = useForm({ + const { control, handleSubmit, reset } = useForm({ defaultValues: defaultFormValues, resolver: yupResolver(schema), mode: 'all', }); - const navigate = useNavigate(); const onValidSubmit: SubmitHandler = async (values) => { setStoreState({ loading: true }); - if (network) { - await editNetworkMutation({ ...network, ...values }); - } else { - await addNetworkMutation(values); - } - navigate('/admin/network'); + mutateAsync({ + id: selectedNetworkId, + network: values, + }) + .then(() => { + setStoreState({ loading: false }); + toaster.success(LL.networkConfiguration.form.messages.networkModified()); + const keys = [ + QueryKeys.FETCH_NETWORK, + QueryKeys.FETCH_NETWORKS, + QueryKeys.FETCH_NETWORK_TOKEN, + ]; + for (const key of keys) { + queryClient.refetchQueries({ + queryKey: [key], + }); + } + }) + .catch((err) => { + setStoreState({ loading: false }); + console.error(err); + toaster.error(LL.messages.error()); + }); }; + // reset form when network is selected useEffect(() => { - setStoreState({ loading: addLoading || editLoading }); - }, [addLoading, editLoading, setStoreState]); + reset(defaultFormValues); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [defaultFormValues, reset]); useEffect(() => { const sub = submitSubject.subscribe(() => submitRef.current?.click()); @@ -183,47 +176,45 @@ export const NetworkConfiguration: React.FC = () => {

PLACEHOLDER

- -
- - -

{LL.networkConfiguration.form.messages.address()}

-
- - -

{LL.networkConfiguration.form.messages.gateway()}

-
- - - -

{LL.networkConfiguration.form.messages.allowedIps()}

-
- - -

{LL.networkConfiguration.form.messages.dns()}

-
- - - -
+
+ + +

{LL.networkConfiguration.form.helpers.address()}

+
+ + +

{LL.networkConfiguration.form.helpers.gateway()}

+
+ + + +

{LL.networkConfiguration.form.helpers.allowedIps()}

+
+ + +

{LL.networkConfiguration.form.helpers.dns()}

+
+ + + ); }; diff --git a/web/src/pages/network/NetworkConfiguration/style.scss b/web/src/pages/network/NetworkEditForm/style.scss similarity index 100% rename from web/src/pages/network/NetworkConfiguration/style.scss rename to web/src/pages/network/NetworkEditForm/style.scss diff --git a/web/src/pages/network/NetworkGateway/NetworkGateway.tsx b/web/src/pages/network/NetworkGateway/NetworkGateway.tsx index 41850a98e..690f2b626 100644 --- a/web/src/pages/network/NetworkGateway/NetworkGateway.tsx +++ b/web/src/pages/network/NetworkGateway/NetworkGateway.tsx @@ -1,6 +1,6 @@ import './style.scss'; -import { useQuery, useQueryClient } from '@tanstack/react-query'; +import { useQuery } from '@tanstack/react-query'; import clipboard from 'clipboardy'; import parse from 'html-react-parser'; import { useCallback, useMemo } from 'react'; @@ -10,40 +10,25 @@ import { ActionButton, ActionButtonVariant, } from '../../../shared/components/layout/ActionButton/ActionButton'; -import Button, { - ButtonSize, - ButtonStyleVariant, -} from '../../../shared/components/layout/Button/Button'; -import { Card } from '../../../shared/components/layout/Card/Card'; import { ExpandableCard } from '../../../shared/components/layout/ExpandableCard/ExpandableCard'; -import MessageBox, { - MessageBoxType, -} from '../../../shared/components/layout/MessageBox/MessageBox'; +import MessageBox from '../../../shared/components/layout/MessageBox/MessageBox'; +import { GatewaysStatus } from '../../../shared/components/network/GatewaysStatus/GatewaysStatus'; import useApi from '../../../shared/hooks/useApi'; import { useToaster } from '../../../shared/hooks/useToaster'; import { QueryKeys } from '../../../shared/queries'; +import { useNetworkPageStore } from '../hooks/useNetworkPageStore'; export const NetworkGatewaySetup = () => { + const selectedNetworkId = useNetworkPageStore((state) => state.selectedNetworkId); const toaster = useToaster(); const { LL } = useI18nContext(); const { - network: { getGatewayStatus, getNetworkToken }, + network: { getNetworkToken }, } = useApi(); - const queryClient = useQueryClient(); - const { data: gatewayStatus, isLoading: statusLoading } = useQuery( - [QueryKeys.FETCH_GATEWAY_STATUS], - getGatewayStatus, - { - onError: (err) => { - toaster.error(LL.gatewaySetup.messages.statusError()); - console.error(err); - }, - refetchOnWindowFocus: false, - } - ); - const { data: networkToken } = useQuery([QueryKeys.FETCH_NETWORK_TOKEN], () => - getNetworkToken('1') + const { data: networkToken } = useQuery( + [QueryKeys.FETCH_NETWORK_TOKEN, selectedNetworkId], + () => getNetworkToken(selectedNetworkId) ); const command = useCallback(() => { @@ -76,50 +61,26 @@ export const NetworkGatewaySetup = () => {

{LL.gatewaySetup.header()}

- - - {parse( - networkToken - ? LL.gatewaySetup.messages.runCommand() - : LL.gatewaySetup.messages.createNetwork() - )} - - {networkToken && ( - <> - -

{command()}

-
-
-
- + + {parse( + networkToken + ? LL.gatewaySetup.messages.runCommand() + : LL.gatewaySetup.messages.createNetwork() )} -
+ + {networkToken && ( + <> + +

{command()}

+
+ + )} + ); }; diff --git a/web/src/pages/network/NetworkGateway/style.scss b/web/src/pages/network/NetworkGateway/style.scss index 2b014bea7..16760263f 100644 --- a/web/src/pages/network/NetworkGateway/style.scss +++ b/web/src/pages/network/NetworkGateway/style.scss @@ -2,70 +2,34 @@ #network-page { .gateway { - & > .card { - padding: 1.5rem 1.5rem 3rem; - @include media-breakpoint-up(lg) { - padding: 3rem 4rem 5rem; - } - - & > .message-box-container { - min-height: 80px; - margin-bottom: 2rem; - - @include media-breakpoint-up(lg) { - margin-bottom: 4rem; - } - } - - & > .expandable-card { - & > .expanded-content { - overflow: hidden; - - & > p { - max-width: 100%; - text-overflow: ellipsis; - text-align: left; - word-break: break-all; - white-space: normal; - @include small-text; - - line-height: 22px; - } - } + & > .message-box-container { + min-height: 80px; + margin-bottom: 2rem; - margin-bottom: 3rem; + @include media-breakpoint-up(lg) { + margin-bottom: 4rem; } + } - & > .status { - width: 100%; - display: flex; - flex-flow: column-reverse; - row-gap: 1.5rem; - - @include media-breakpoint-up(lg) { - display: inline-grid; - grid-template-columns: 280px 1fr; - column-gap: 3rem; - grid-template-rows: 50px; - align-items: center; - justify-content: center; - align-content: center; - } - - & > .message-box-container { - height: 50px; - min-height: 50px; - - & > .message-box { - padding: 1rem 2rem; - } - } + & > .expandable-card { + & > .expanded-content { + overflow: hidden; + box-sizing: border-box; - & > .btn { - height: 100%; + & > p { width: 100%; + max-width: 100%; + text-overflow: ellipsis; + text-align: left; + word-break: break-all; + white-space: normal; + @include small-text; + + line-height: 22px; } } + + margin-bottom: 3rem; } } } diff --git a/web/src/pages/network/NetworkPage.tsx b/web/src/pages/network/NetworkPage.tsx index aeab5e5de..9c4413017 100644 --- a/web/src/pages/network/NetworkPage.tsx +++ b/web/src/pages/network/NetworkPage.tsx @@ -1,57 +1,45 @@ import './style.scss'; -import { useNavigate } from 'react-router'; -import { shallow } from 'zustand/shallow'; +import { useQuery } from '@tanstack/react-query'; import { useI18nContext } from '../../i18n/i18n-react'; -import Button, { - ButtonSize, - ButtonStyleVariant, -} from '../../shared/components/layout/Button/Button'; +import { Card } from '../../shared/components/layout/Card/Card'; import { PageContainer } from '../../shared/components/layout/PageContainer/PageContainer'; -import { IconCheckmarkWhite } from '../../shared/components/svg'; +import useApi from '../../shared/hooks/useApi'; +import { QueryKeys } from '../../shared/queries'; import { useNetworkPageStore } from './hooks/useNetworkPageStore'; -import { NetworkConfiguration } from './NetworkConfiguration/NetworkConfiguration'; +import { NetworkControls } from './NetworkControls/NetworkControls'; +import { NetworkEditForm } from './NetworkEditForm/NetworkEditForm'; import { NetworkGatewaySetup } from './NetworkGateway/NetworkGateway'; +import { NetworkTabs } from './NetworkTabs/NetworkTabs'; export const NetworkPage = () => { - const navigate = useNavigate(); + const { + network: { getNetworks }, + } = useApi(); const { LL } = useI18nContext(); + const setPageStore = useNetworkPageStore((state) => state.setState); + + useQuery({ + queryKey: [QueryKeys.FETCH_NETWORKS], + queryFn: getNetworks, + onSuccess: (res) => { + setPageStore({ networks: res }); + }, + refetchOnWindowFocus: false, + }); return (

{LL.networkPage.pageTitle()}

-
-
- - + + + + + +
); }; - -const SaveFormButton = () => { - const { LL } = useI18nContext(); - const [save, loading] = useNetworkPageStore( - (state) => [state.saveSubject, state.loading], - shallow - ); - return ( -
- - ); -}; diff --git a/web/src/pages/users/UserProfile/UserDevices/modals/DeleteUserDeviceModal/DeleteUserDeviceModal.tsx b/web/src/pages/users/UserProfile/UserDevices/modals/DeleteUserDeviceModal/DeleteUserDeviceModal.tsx index 099f478ea..a46dc0043 100644 --- a/web/src/pages/users/UserProfile/UserDevices/modals/DeleteUserDeviceModal/DeleteUserDeviceModal.tsx +++ b/web/src/pages/users/UserProfile/UserDevices/modals/DeleteUserDeviceModal/DeleteUserDeviceModal.tsx @@ -1,21 +1,29 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; import { AxiosError } from 'axios'; +import { isUndefined } from 'lodash-es'; +import { shallow } from 'zustand/shallow'; import { useI18nContext } from '../../../../../../i18n/i18n-react'; import ConfirmModal, { ConfirmModalType, } from '../../../../../../shared/components/layout/ConfirmModal/ConfirmModal'; -import { useModalStore } from '../../../../../../shared/hooks/store/useModalStore'; import useApi from '../../../../../../shared/hooks/useApi'; import { useToaster } from '../../../../../../shared/hooks/useToaster'; import { MutationKeys } from '../../../../../../shared/mutations'; import { QueryKeys } from '../../../../../../shared/queries'; +import { useDeleteDeviceModal } from '../../hooks/useDeleteDeviceModal'; export const DeleteUserDeviceModal = () => { const { LL } = useI18nContext(); const toaster = useToaster(); - const modalState = useModalStore((state) => state.deleteUserDeviceModal); - const setModalState = useModalStore((state) => state.setDeleteUserDeviceModal); + const [device, visible] = useDeleteDeviceModal( + (state) => [state.device, state.visible], + shallow + ); + const [setModalState, closeModal] = useDeleteDeviceModal( + (state) => [state.setState, state.close], + shallow + ); const { device: { deleteDevice }, } = useApi(); @@ -27,8 +35,8 @@ export const DeleteUserDeviceModal = () => { { onSuccess: () => { queryClient.invalidateQueries([QueryKeys.FETCH_USER]); - setModalState({ visible: false, device: undefined }); toaster.success(LL.modals.deleteDevice.messages.success()); + closeModal(); }, onError: (err: AxiosError) => { toaster.error(LL.messages.error()); @@ -42,16 +50,16 @@ export const DeleteUserDeviceModal = () => { title={LL.modals.deleteDevice.title()} type={ConfirmModalType.WARNING} subTitle={LL.modals.deleteDevice.message({ - deviceName: modalState.device?.name || '', + deviceName: device?.name || '', })} cancelText={LL.form.cancel()} submitText={LL.modals.deleteDevice.submit()} - loading={isLoading || !modalState.device} - isOpen={modalState.visible} + loading={isLoading || isUndefined(device)} + isOpen={visible} setIsOpen={(visibility) => setModalState({ visible: visibility })} onSubmit={() => { - if (modalState.device) { - mutate(modalState.device); + if (device) { + mutate(device); } }} /> diff --git a/web/src/pages/users/UserProfile/UserDevices/modals/EditUserDeviceModal/EditUserDeviceModal.tsx b/web/src/pages/users/UserProfile/UserDevices/modals/EditUserDeviceModal/EditUserDeviceModal.tsx index 4d8e118a4..00eb1e822 100644 --- a/web/src/pages/users/UserProfile/UserDevices/modals/EditUserDeviceModal/EditUserDeviceModal.tsx +++ b/web/src/pages/users/UserProfile/UserDevices/modals/EditUserDeviceModal/EditUserDeviceModal.tsx @@ -1,17 +1,19 @@ import { useI18nContext } from '../../../../../../i18n/i18n-react'; import { ModalWithTitle } from '../../../../../../shared/components/layout/ModalWithTitle/ModalWithTitle'; -import { useModalStore } from '../../../../../../shared/hooks/store/useModalStore'; +import { useEditDeviceModal } from '../../hooks/useEditDeviceModal'; import { EditUserDeviceForm } from './UserDeviceEditForm'; + export const EditUserDeviceModal = () => { const { LL } = useI18nContext(); - const modalState = useModalStore((state) => state.editUserDeviceModal); - const setModalsState = useModalStore((state) => state.setState); + const visible = useEditDeviceModal((state) => state.visible); + const closeModal = useEditDeviceModal((state) => state.close); + return ( setModalsState({ editUserDeviceModal: { visible: v } })} + isOpen={visible} + setIsOpen={() => closeModal()} backdrop > diff --git a/web/src/pages/users/UserProfile/UserDevices/modals/EditUserDeviceModal/UserDeviceEditForm.tsx b/web/src/pages/users/UserProfile/UserDevices/modals/EditUserDeviceModal/UserDeviceEditForm.tsx index 527b14280..c818e63b1 100644 --- a/web/src/pages/users/UserProfile/UserDevices/modals/EditUserDeviceModal/UserDeviceEditForm.tsx +++ b/web/src/pages/users/UserProfile/UserDevices/modals/EditUserDeviceModal/UserDeviceEditForm.tsx @@ -10,7 +10,6 @@ import Button, { ButtonSize, ButtonStyleVariant, } from '../../../../../../shared/components/layout/Button/Button'; -import { useModalStore } from '../../../../../../shared/hooks/store/useModalStore'; import useApi from '../../../../../../shared/hooks/useApi'; import { useToaster } from '../../../../../../shared/hooks/useToaster'; import { MutationKeys } from '../../../../../../shared/mutations'; @@ -19,6 +18,7 @@ import { patternValidWireguardKey, } from '../../../../../../shared/patterns'; import { QueryKeys } from '../../../../../../shared/queries'; +import { useEditDeviceModal } from '../../hooks/useEditDeviceModal'; interface Inputs { name: string; @@ -31,8 +31,8 @@ const defaultFormValues: Inputs = { }; export const EditUserDeviceForm = () => { - const device = useModalStore((state) => state.editUserDeviceModal.device); - const setModalsState = useModalStore((state) => state.setState); + const device = useEditDeviceModal((state) => state.device); + const closeModal = useEditDeviceModal((state) => state.close); const { LL, locale } = useI18nContext(); const schema = useMemo(() => { @@ -77,7 +77,7 @@ export const EditUserDeviceForm = () => { onSuccess: () => { toaster.success(LL.modals.editDevice.messages.success()); queryClient.invalidateQueries([QueryKeys.FETCH_USER]); - setModalsState({ editUserDeviceModal: { visible: false } }); + closeModal(); }, onError: (err) => { toaster.error(LL.messages.error()); @@ -109,11 +109,7 @@ export const EditUserDeviceForm = () => { styleVariant={ButtonStyleVariant.STANDARD} text={LL.form.cancel()} className="cancel" - onClick={() => - setModalsState({ - editUserDeviceModal: { visible: false, device: undefined }, - }) - } + onClick={() => closeModal()} /> + {!isUndefined(topExtras) &&
{topExtras}
} {actions &&
{actions}
} {children && (controlledOutside ? expanded : localExpanded) ? ( diff --git a/web/src/shared/components/layout/ExpandableCard/style.scss b/web/src/shared/components/layout/ExpandableCard/style.scss index 768065132..273737d83 100644 --- a/web/src/shared/components/layout/ExpandableCard/style.scss +++ b/web/src/shared/components/layout/ExpandableCard/style.scss @@ -23,6 +23,12 @@ box-sizing: border-box; padding: 0 1.5rem 0 2rem; + & > .extras { + display: flex; + flex-flow: row nowrap; + margin-left: 20px; + } + & > .expand-button { display: flex; flex-flow: row; diff --git a/web/src/shared/components/layout/MessageBox/MessageBox.tsx b/web/src/shared/components/layout/MessageBox/MessageBox.tsx index b5bae4680..51a0cb72a 100644 --- a/web/src/shared/components/layout/MessageBox/MessageBox.tsx +++ b/web/src/shared/components/layout/MessageBox/MessageBox.tsx @@ -1,7 +1,7 @@ import './style.scss'; import classNames from 'classnames'; -import React, { ComponentPropsWithoutRef, useMemo } from 'react'; +import { ComponentPropsWithoutRef, useMemo } from 'react'; import SvgIconDeactivated from '../../svg/IconDeactivated'; import SvgIconInfo from '../../svg/IconInfo'; diff --git a/web/src/shared/components/layout/NoData/style.scss b/web/src/shared/components/layout/NoData/style.scss index 516cb5544..a82b21c60 100644 --- a/web/src/shared/components/layout/NoData/style.scss +++ b/web/src/shared/components/layout/NoData/style.scss @@ -8,4 +8,8 @@ width: 100%; text-align: center; + user-select: none; + & > * { + user-select: none; + } } diff --git a/web/src/shared/components/layout/RowBox/RowBox.tsx b/web/src/shared/components/layout/RowBox/RowBox.tsx index 8a4fe3bdd..a06ea5727 100644 --- a/web/src/shared/components/layout/RowBox/RowBox.tsx +++ b/web/src/shared/components/layout/RowBox/RowBox.tsx @@ -1,8 +1,8 @@ import './style.scss'; import classNames from 'classnames'; -import { HTMLMotionProps, motion, Variants } from 'framer-motion'; -import { ReactNode, useMemo } from 'react'; +import { HTMLMotionProps, motion, TargetAndTransition } from 'framer-motion'; +import { ReactNode, useMemo, useState } from 'react'; import { buttonsBoxShadow, ColorsRGB, inactiveBoxShadow } from '../../../constants'; @@ -10,9 +10,17 @@ interface Props extends HTMLMotionProps<'div'> { children: ReactNode; className?: string; disabled?: boolean; + customAnimate?: TargetAndTransition; } -export const RowBox = ({ children, className, disabled = false, ...rest }: Props) => { +export const RowBox = ({ + children, + className, + customAnimate, + disabled = false, + ...rest +}: Props) => { + const [hovered, setHovered] = useState(false); const cn = useMemo( () => classNames('row-box', className, { @@ -20,29 +28,35 @@ export const RowBox = ({ children, className, disabled = false, ...rest }: Props }), [className, disabled] ); + + const getAnimate = useMemo((): TargetAndTransition => { + let res: TargetAndTransition = { + borderColor: ColorsRGB.GrayBorder, + boxShadow: inactiveBoxShadow, + opacity: 1, + }; + if (disabled) { + res.opacity = 0.8; + } + if (hovered) { + res.boxShadow = buttonsBoxShadow; + } + if (customAnimate) { + res = { ...res, ...customAnimate }; + } + return res; + }, [disabled, hovered, customAnimate]); + return ( setHovered(true)} + onHoverEnd={() => setHovered(false)} {...rest} > {children} ); }; - -const defaultVariants: Variants = { - rowBoxIdle: ({ disabled }) => ({ - borderColor: ColorsRGB.GrayBorder, - boxShadow: inactiveBoxShadow, - opacity: disabled ? 0.8 : 1, - }), - rowBoxActive: ({ disabled }) => ({ - borderColor: ColorsRGB.GrayLighter, - boxShadow: disabled ? inactiveBoxShadow : buttonsBoxShadow, - opacity: disabled ? 0.8 : 1, - }), -}; diff --git a/web/src/shared/components/layout/Select/Select.stories.tsx b/web/src/shared/components/layout/Select/Select.stories.tsx index 2747c520c..2381fd819 100644 --- a/web/src/shared/components/layout/Select/Select.stories.tsx +++ b/web/src/shared/components/layout/Select/Select.stories.tsx @@ -1,4 +1,5 @@ import { Story } from '@ladle/react'; +import { cloneDeep } from 'lodash-es'; import { useMemo, useState } from 'react'; import { Select, SelectOption } from './Select'; @@ -103,3 +104,40 @@ export const SingleOptionSelectStory: Story = () => { }; SingleOptionSelectStory.storyName = 'Single option select'; + +export const SingleOptionWithCreate: Story = () => { + const [selected, setSelected] = useState | undefined>(); + const [options, setOptions] = useState[]>([]); + return ( +