diff --git a/Cargo.lock b/Cargo.lock index 540d77e..03dfff4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -112,7 +112,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" dependencies = [ - "crypto-common", + "crypto-common 0.1.7", "generic-array", ] @@ -123,8 +123,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" dependencies = [ "cfg-if", - "cipher", - "cpufeatures", + "cipher 0.4.4", + "cpufeatures 0.2.17", "zeroize", ] @@ -581,13 +581,14 @@ dependencies = [ [[package]] name = "async-wsocket" -version = "0.13.1" -source = "git+https://github.com/shadowylab/async-wsocket?rev=0fed6c9c6aec7393ee0e9cf3933d76914ab427d3#0fed6c9c6aec7393ee0e9cf3933d76914ab427d3" +version = "0.14.0" +source = "git+https://github.com/shadowylab/async-wsocket?rev=07c0fda670d05d695929cab55f41761b90aef9a0#07c0fda670d05d695929cab55f41761b90aef9a0" dependencies = [ "futures", "futures-util", "js-sys", "tokio", + "tokio-happy-eyeballs", "tokio-rustls", "tokio-socks", "tokio-tungstenite", @@ -769,12 +770,6 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" -[[package]] -name = "base64ct" -version = "1.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" - [[package]] name = "bech32" version = "0.11.1" @@ -787,7 +782,7 @@ version = "0.71.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f58bf3d7db68cfbac37cfc485a8d711e87e064c3d0fe0435b92f7a407f9d6b3" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "cexpr", "clang-sys", "itertools 0.13.0", @@ -858,9 +853,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.11.1" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" +checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8" dependencies = [ "serde_core", ] @@ -889,6 +884,15 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block-buffer" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdd35008169921d80bc60d3d0ab416eecb028c4cd653352907921d95084790be" +dependencies = [ + "hybrid-array", +] + [[package]] name = "block-padding" version = "0.3.3" @@ -1020,7 +1024,7 @@ version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4dbf9978365bac10f54d1d4b04f7ce4427e51f71d61f2fe15e3fed5166474df7" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "polling", "rustix 1.1.4", "slab", @@ -1045,7 +1049,7 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6" dependencies = [ - "cipher", + "cipher 0.4.4", ] [[package]] @@ -1121,8 +1125,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" dependencies = [ "cfg-if", - "cipher", - "cpufeatures", + "cipher 0.4.4", + "cpufeatures 0.2.17", ] [[package]] @@ -1133,7 +1137,7 @@ checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35" dependencies = [ "aead", "chacha20", - "cipher", + "cipher 0.4.4", "poly1305", "zeroize", ] @@ -1191,9 +1195,9 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.44" +version = "0.4.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" +checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327" dependencies = [ "iana-time-zone", "js-sys", @@ -1209,11 +1213,22 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" dependencies = [ - "crypto-common", - "inout", + "crypto-common 0.1.7", + "inout 0.1.4", "zeroize", ] +[[package]] +name = "cipher" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8cf2a2c93cd704877c0858356ed03480ff301ee950b43f1cbe4573b088bfa6c" +dependencies = [ + "block-buffer 0.12.0", + "crypto-common 0.2.2", + "inout 0.2.2", +] + [[package]] name = "clang-sys" version = "1.8.1" @@ -1274,6 +1289,12 @@ dependencies = [ "cc", ] +[[package]] +name = "cmov" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c9ea0ac24bc397ab3c98583a3c9ba74fa56b09a4449bbe172b9b1ddb016027a" + [[package]] name = "cocoa" version = "0.25.0" @@ -1296,7 +1317,7 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f79398230a6e2c08f5c9760610eb6924b52aa9e7950a619602baba59dcbbdbb2" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "block", "cocoa-foundation 0.2.0", "core-foundation 0.10.0", @@ -1326,7 +1347,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e14045fb83be07b5acf1c0884b2180461635b433455fa35d1cd6f17f1450679d" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "block", "core-foundation 0.10.0", "core-graphics-types 0.2.0", @@ -1348,8 +1369,9 @@ dependencies = [ [[package]] name = "collections" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#46ac5758a5562f05b786b88cf3600b9334abeb7d" +source = "git+https://github.com/zed-industries/zed#e5052961af01e6810f961d6b217376edbe02b106" dependencies = [ + "gpui_util", "indexmap", "rustc-hash 2.1.2", ] @@ -1606,7 +1628,7 @@ version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "core-foundation 0.10.0", "core-graphics-types 0.2.0", "foreign-types", @@ -1619,7 +1641,7 @@ version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32eb7c354ae9f6d437a6039099ce7ecd049337a8109b23d73e48e8ffba8e9cd5" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "core-foundation 0.9.4", "core-graphics-types 0.1.3", "foreign-types", @@ -1643,7 +1665,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "core-foundation 0.10.0", "libc", ] @@ -1654,7 +1676,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4416167a69126e617f8d0a214af0e3c1dbdeffcb100ddf72dcd1a1ac9893c146" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "block", "cfg-if", "core-foundation 0.10.0", @@ -1702,7 +1724,7 @@ version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be17b688510d934ce13f48a2beba700e11583e281e0fda99c22bb256a14eda73" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "fontdb", "harfrust", "linebender_resource_handle", @@ -1710,7 +1732,7 @@ dependencies = [ "rangemap", "rustc-hash 2.1.2", "self_cell", - "skrifa", + "skrifa 0.40.0", "smol_str", "swash", "sys-locale", @@ -1729,6 +1751,15 @@ dependencies = [ "libc", ] +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + [[package]] name = "crc32fast" version = "1.5.0" @@ -1788,6 +1819,15 @@ dependencies = [ "typenum", ] +[[package]] +name = "crypto-common" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" +dependencies = [ + "hybrid-array", +] + [[package]] name = "ctor" version = "1.0.7" @@ -1798,6 +1838,15 @@ dependencies = [ "linktime-proc-macro", ] +[[package]] +name = "ctutils" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5515a3834141de9eafb9717ad39eea8247b5674e6066c404e8c4b365d2a29e" +dependencies = [ + "cmov", +] + [[package]] name = "data-encoding" version = "2.11.0" @@ -1842,7 +1891,7 @@ dependencies = [ [[package]] name = "derive_refineable" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#46ac5758a5562f05b786b88cf3600b9334abeb7d" +source = "git+https://github.com/zed-industries/zed#e5052961af01e6810f961d6b217376edbe02b106" dependencies = [ "proc-macro2", "quote", @@ -1877,11 +1926,22 @@ version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer", - "crypto-common", + "block-buffer 0.10.4", + "crypto-common 0.1.7", "subtle", ] +[[package]] +name = "digest" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" +dependencies = [ + "block-buffer 0.12.0", + "crypto-common 0.2.2", + "ctutils", +] + [[package]] name = "dirs" version = "5.0.1" @@ -1936,7 +1996,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "block2 0.6.2", "libc", "objc2 0.6.4", @@ -2274,7 +2334,7 @@ version = "25.12.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35f6839d7b3b98adde531effaf34f0c2badc6f4735d26fe74709d8e513a96ef3" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "rustc_version", ] @@ -2674,6 +2734,7 @@ dependencies = [ "cfg-if", "libc", "r-efi 6.0.0", + "rand_core 0.10.1", "wasip2", "wasip3", ] @@ -2787,7 +2848,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b89c83349105e3732062a895becfc71a8f921bb71ecbbdd8ff99263e3b53a0ca" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "gpu-descriptor-types", "hashbrown 0.15.5", ] @@ -2798,20 +2859,20 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdf242682df893b86f33a73828fb09ca4b2d3bb6cc95249707fc684d27484b91" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", ] [[package]] name = "gpui" version = "0.2.2" -source = "git+https://github.com/zed-industries/zed#46ac5758a5562f05b786b88cf3600b9334abeb7d" +source = "git+https://github.com/zed-industries/zed#e5052961af01e6810f961d6b217376edbe02b106" dependencies = [ "accesskit", "anyhow", "async-channel 2.5.0", "async-task", "bindgen", - "bitflags 2.11.1", + "bitflags 2.13.0", "block", "cbindgen", "chrono", @@ -2834,6 +2895,7 @@ dependencies = [ "gpui_macros", "gpui_shared_string", "gpui_util", + "heapless 0.9.3", "http_client", "image", "inventory", @@ -2885,14 +2947,14 @@ dependencies = [ [[package]] name = "gpui_linux" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#46ac5758a5562f05b786b88cf3600b9334abeb7d" +source = "git+https://github.com/zed-industries/zed#e5052961af01e6810f961d6b217376edbe02b106" dependencies = [ "accesskit", "accesskit_unix", "anyhow", "as-raw-xcb-connection", "ashpd", - "bitflags 2.11.1", + "bitflags 2.13.0", "bytemuck", "calloop", "calloop-wayland-source", @@ -2936,7 +2998,7 @@ dependencies = [ [[package]] name = "gpui_macos" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#46ac5758a5562f05b786b88cf3600b9334abeb7d" +source = "git+https://github.com/zed-industries/zed#e5052961af01e6810f961d6b217376edbe02b106" dependencies = [ "accesskit", "accesskit_macos", @@ -2981,7 +3043,7 @@ dependencies = [ [[package]] name = "gpui_macros" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#46ac5758a5562f05b786b88cf3600b9334abeb7d" +source = "git+https://github.com/zed-industries/zed#e5052961af01e6810f961d6b217376edbe02b106" dependencies = [ "heck 0.5.0", "proc-macro2", @@ -2992,7 +3054,7 @@ dependencies = [ [[package]] name = "gpui_platform" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#46ac5758a5562f05b786b88cf3600b9334abeb7d" +source = "git+https://github.com/zed-industries/zed#e5052961af01e6810f961d6b217376edbe02b106" dependencies = [ "console_error_panic_hook", "gpui", @@ -3005,7 +3067,7 @@ dependencies = [ [[package]] name = "gpui_shared_string" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#46ac5758a5562f05b786b88cf3600b9334abeb7d" +source = "git+https://github.com/zed-industries/zed#e5052961af01e6810f961d6b217376edbe02b106" dependencies = [ "schemars", "serde", @@ -3015,7 +3077,7 @@ dependencies = [ [[package]] name = "gpui_tokio" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#46ac5758a5562f05b786b88cf3600b9334abeb7d" +source = "git+https://github.com/zed-industries/zed#e5052961af01e6810f961d6b217376edbe02b106" dependencies = [ "anyhow", "gpui", @@ -3026,7 +3088,7 @@ dependencies = [ [[package]] name = "gpui_util" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#46ac5758a5562f05b786b88cf3600b9334abeb7d" +source = "git+https://github.com/zed-industries/zed#e5052961af01e6810f961d6b217376edbe02b106" dependencies = [ "anyhow", "log", @@ -3035,7 +3097,7 @@ dependencies = [ [[package]] name = "gpui_web" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#46ac5758a5562f05b786b88cf3600b9334abeb7d" +source = "git+https://github.com/zed-industries/zed#e5052961af01e6810f961d6b217376edbe02b106" dependencies = [ "anyhow", "console_error_panic_hook", @@ -3059,7 +3121,7 @@ dependencies = [ [[package]] name = "gpui_wgpu" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#46ac5758a5562f05b786b88cf3600b9334abeb7d" +source = "git+https://github.com/zed-industries/zed#e5052961af01e6810f961d6b217376edbe02b106" dependencies = [ "anyhow", "bytemuck", @@ -3088,7 +3150,7 @@ dependencies = [ [[package]] name = "gpui_windows" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#46ac5758a5562f05b786b88cf3600b9334abeb7d" +source = "git+https://github.com/zed-industries/zed#e5052961af01e6810f961d6b217376edbe02b106" dependencies = [ "accesskit", "accesskit_windows", @@ -3155,10 +3217,10 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9da2e5ae821f6e96664977bf974d6d6a2d6682f9ccee23e62ec1d134246845f9" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "bytemuck", "core_maths", - "read-fonts", + "read-fonts 0.37.0", "smallvec", ] @@ -3250,7 +3312,7 @@ version = "0.20.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d4f449bab7320c56003d37732a917e18798e2f1709d80263face2b4f9436ddb" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "byteorder", "heed-traits", "heed-types", @@ -3311,7 +3373,7 @@ version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" dependencies = [ - "hmac", + "hmac 0.12.1", ] [[package]] @@ -3320,7 +3382,16 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest", + "digest 0.10.7", +] + +[[package]] +name = "hmac" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6303bc9732ae41b04cb554b844a762b4115a61bfaa81e3e83050991eeb56863f" +dependencies = [ + "digest 0.11.3", ] [[package]] @@ -3334,9 +3405,9 @@ dependencies = [ [[package]] name = "http" -version = "1.4.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8be7462df143984c4598a256ef469b251d7d7f9e271135073e78fc535414f3d0" +checksum = "6970f50e31d6fc17d3fa27329444bfa74e196cf62e95052a3f6fee181dba6425" dependencies = [ "bytes", "itoa", @@ -3368,7 +3439,7 @@ dependencies = [ [[package]] name = "http_client" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#46ac5758a5562f05b786b88cf3600b9334abeb7d" +source = "git+https://github.com/zed-industries/zed#e5052961af01e6810f961d6b217376edbe02b106" dependencies = [ "anyhow", "async-compression", @@ -3384,7 +3455,7 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", - "sha2", + "sha2 0.10.9", "tempfile", "url", "util", @@ -3393,7 +3464,7 @@ dependencies = [ [[package]] name = "http_client_tls" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#46ac5758a5562f05b786b88cf3600b9334abeb7d" +source = "git+https://github.com/zed-industries/zed#e5052961af01e6810f961d6b217376edbe02b106" dependencies = [ "rustls", "rustls-platform-verifier", @@ -3405,6 +3476,15 @@ version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" +[[package]] +name = "hybrid-array" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9155a582abd142abc056962c29e3ce5ff2ad5469f4246b537ed42c5deba857da" +dependencies = [ + "typenum", +] + [[package]] name = "hyper" version = "1.10.1" @@ -3641,9 +3721,9 @@ checksum = "edcd27d72f2f071c64249075f42e205ff93c9a4c5f6c6da53e79ed9f9832c285" [[package]] name = "imgref" -version = "1.12.1" +version = "1.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40fac9d56ed6437b198fddba683305e8e2d651aa42647f00f5ae542e7f5c94a2" +checksum = "89194689a993ab15268672e99e7b0e19da2da3268ac682e8f02d29d4d1434cd7" [[package]] name = "indexmap" @@ -3676,6 +3756,15 @@ dependencies = [ "generic-array", ] +[[package]] +name = "inout" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4250ce6452e92010fdf7268ccc5d14faa80bb12fc741938534c58f16804e03c7" +dependencies = [ + "hybrid-array", +] + [[package]] name = "instant" version = "0.1.13" @@ -3858,13 +3947,12 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.99" +version = "0.3.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "142bc4740e452c1e57ade0cbc129f139c9093e354346f0872ef985f4f5cf5f11" +checksum = "f2025f20d7a4fa7785846e7b63d10a76d3f1cee98ee5cb79ea59703f95e42162" dependencies = [ "cfg-if", "futures-util", - "once_cell", "wasm-bindgen", ] @@ -3952,9 +4040,9 @@ checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" [[package]] name = "libfuzzer-sys" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f12a681b7dd8ce12bff52488013ba614b869148d54dd79836ab85aafdd53f08d" +checksum = "a9fd2f41a1cba099f79a0b6b6c35656cf7c03351a7bae8ff0f28f25270f929d2" dependencies = [ "arbitrary", "cc", @@ -3982,10 +4070,10 @@ version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f02ab6bace2054fb888a3c16f990117b579d14a3088e472d63c6011fa185c9d3" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "libc", "plain", - "redox_syscall 0.8.0", + "redox_syscall 0.8.1", ] [[package]] @@ -4019,9 +4107,9 @@ dependencies = [ [[package]] name = "link-section" -version = "0.18.1" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "014e440054ce8170890229eeef5bcda955305e056ec713de40ed366944483f09" +checksum = "c2b1dd6fe32e55c0fc0ea9493aa57459ca3cf4ff3c857c7d0302290150da6e4f" [[package]] name = "linkify" @@ -4084,9 +4172,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.30" +version = "0.4.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "616ec5685824bcc94416c6d4a7a446eea774a31efd7062c8480ba6fd06d7a6e5" +checksum = "953f07c43838f8e6f9758cab68bf5bed85465e7587ebe0b823f1bcd81978ad3a" dependencies = [ "serde_core", "value-bag", @@ -4228,13 +4316,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" dependencies = [ "cfg-if", - "digest", + "digest 0.10.7", ] [[package]] name = "media" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#46ac5758a5562f05b786b88cf3600b9334abeb7d" +source = "git+https://github.com/zed-industries/zed#e5052961af01e6810f961d6b217376edbe02b106" dependencies = [ "anyhow", "bindgen", @@ -4285,7 +4373,7 @@ version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7047791b5bc903b8cd963014b355f71dc9864a9a0b727057676c1dcae5cbc15" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "block", "core-graphics-types 0.2.0", "foreign-types", @@ -4354,7 +4442,7 @@ source = "git+https://github.com/zed-industries/wgpu.git?rev=357a0c56e0070480ad9 dependencies = [ "arrayvec", "bit-set", - "bitflags 2.11.1", + "bitflags 2.13.0", "cfg-if", "cfg_aliases", "codespan-reporting", @@ -4414,7 +4502,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "cfg-if", "cfg_aliases", "libc", @@ -4426,7 +4514,7 @@ version = "0.31.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf20d2fde8ff38632c426f1165ed7436270b44f199fc55284c38276f9db47c3d" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "cfg-if", "cfg_aliases", "libc", @@ -4468,8 +4556,8 @@ checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8" [[package]] name = "nostr" -version = "0.44.1" -source = "git+https://github.com/rust-nostr/nostr?rev=46d66396467e07c3dfb71e5102104ecb7e9c6b64#46d66396467e07c3dfb71e5102104ecb7e9c6b64" +version = "0.45.0-alpha.1" +source = "git+https://github.com/rust-nostr/nostr#02a59264ed8c6075753e398cf4eb81f489d9a5af" dependencies = [ "aes", "base64", @@ -4480,7 +4568,7 @@ dependencies = [ "chacha20", "chacha20poly1305", "faster-hex", - "rand 0.9.4", + "rand 0.10.1", "scrypt", "secp256k1", "serde", @@ -4492,8 +4580,8 @@ dependencies = [ [[package]] name = "nostr-blossom" -version = "0.44.0" -source = "git+https://github.com/rust-nostr/nostr?rev=46d66396467e07c3dfb71e5102104ecb7e9c6b64#46d66396467e07c3dfb71e5102104ecb7e9c6b64" +version = "0.45.0-alpha.1" +source = "git+https://github.com/rust-nostr/nostr#02a59264ed8c6075753e398cf4eb81f489d9a5af" dependencies = [ "base64", "nostr", @@ -4503,8 +4591,8 @@ dependencies = [ [[package]] name = "nostr-connect" -version = "0.44.0" -source = "git+https://github.com/rust-nostr/nostr?rev=46d66396467e07c3dfb71e5102104ecb7e9c6b64#46d66396467e07c3dfb71e5102104ecb7e9c6b64" +version = "0.45.0-alpha.1" +source = "git+https://github.com/rust-nostr/nostr#02a59264ed8c6075753e398cf4eb81f489d9a5af" dependencies = [ "async-utility", "futures-core", @@ -4516,8 +4604,8 @@ dependencies = [ [[package]] name = "nostr-database" -version = "0.44.0" -source = "git+https://github.com/rust-nostr/nostr?rev=46d66396467e07c3dfb71e5102104ecb7e9c6b64#46d66396467e07c3dfb71e5102104ecb7e9c6b64" +version = "0.45.0-alpha.1" +source = "git+https://github.com/rust-nostr/nostr#02a59264ed8c6075753e398cf4eb81f489d9a5af" dependencies = [ "btreecap", "flatbuffers", @@ -4526,16 +4614,16 @@ dependencies = [ [[package]] name = "nostr-gossip" -version = "0.44.0" -source = "git+https://github.com/rust-nostr/nostr?rev=46d66396467e07c3dfb71e5102104ecb7e9c6b64#46d66396467e07c3dfb71e5102104ecb7e9c6b64" +version = "0.45.0-alpha.1" +source = "git+https://github.com/rust-nostr/nostr#02a59264ed8c6075753e398cf4eb81f489d9a5af" dependencies = [ "nostr", ] [[package]] name = "nostr-gossip-memory" -version = "0.44.0" -source = "git+https://github.com/rust-nostr/nostr?rev=46d66396467e07c3dfb71e5102104ecb7e9c6b64#46d66396467e07c3dfb71e5102104ecb7e9c6b64" +version = "0.45.0-alpha.1" +source = "git+https://github.com/rust-nostr/nostr#02a59264ed8c6075753e398cf4eb81f489d9a5af" dependencies = [ "indexmap", "lru", @@ -4546,8 +4634,8 @@ dependencies = [ [[package]] name = "nostr-lmdb" -version = "0.44.0" -source = "git+https://github.com/rust-nostr/nostr?rev=46d66396467e07c3dfb71e5102104ecb7e9c6b64#46d66396467e07c3dfb71e5102104ecb7e9c6b64" +version = "0.45.0-alpha.1" +source = "git+https://github.com/rust-nostr/nostr#02a59264ed8c6075753e398cf4eb81f489d9a5af" dependencies = [ "async-utility", "flume 0.12.0", @@ -4560,8 +4648,8 @@ dependencies = [ [[package]] name = "nostr-sdk" -version = "0.44.1" -source = "git+https://github.com/rust-nostr/nostr?rev=46d66396467e07c3dfb71e5102104ecb7e9c6b64#46d66396467e07c3dfb71e5102104ecb7e9c6b64" +version = "0.45.0-alpha.1" +source = "git+https://github.com/rust-nostr/nostr#02a59264ed8c6075753e398cf4eb81f489d9a5af" dependencies = [ "async-utility", "async-wsocket", @@ -4760,7 +4848,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "block2 0.5.1", "libc", "objc2 0.5.2", @@ -4786,7 +4874,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "block2 0.5.1", "objc2 0.5.2", "objc2-foundation 0.2.2", @@ -4798,7 +4886,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "dispatch2", "objc2 0.6.4", ] @@ -4827,7 +4915,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "block2 0.5.1", "libc", "objc2 0.5.2", @@ -4839,7 +4927,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "objc2 0.6.4", "objc2-core-foundation", ] @@ -4850,7 +4938,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "block2 0.5.1", "objc2 0.5.2", "objc2-foundation 0.2.2", @@ -4862,7 +4950,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0125f776a10d00af4152d74616409f0d4a2053a6f57fa5b7d6aa2854ac04794" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "block2 0.6.2", "objc2 0.6.4", "objc2-foundation 0.3.2", @@ -4874,7 +4962,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "block2 0.5.1", "objc2 0.5.2", "objc2-foundation 0.2.2", @@ -4887,7 +4975,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96c1358452b371bf9f104e21ec536d37a650eb10f7ee379fff67d2e08d537f1f" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "objc2 0.6.4", "objc2-core-foundation", "objc2-foundation 0.3.2", @@ -4952,21 +5040,21 @@ dependencies = [ "async-lock", "blocking", "cbc", - "cipher", - "digest", + "cipher 0.4.4", + "digest 0.10.7", "endi", "futures-lite 2.6.1", "futures-util", "getrandom 0.4.2", "hkdf", - "hmac", + "hmac 0.12.1", "md-5", "num", "num-bigint-dig", - "pbkdf2", + "pbkdf2 0.12.2", "serde", "serde_bytes", - "sha2", + "sha2 0.10.9", "subtle", "zbus", "zbus_macros", @@ -5071,17 +5159,6 @@ dependencies = [ "windows-link 0.2.1", ] -[[package]] -name = "password-hash" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" -dependencies = [ - "base64ct", - "rand_core 0.6.4", - "subtle", -] - [[package]] name = "paste" version = "1.0.15" @@ -5125,8 +5202,18 @@ version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" dependencies = [ - "digest", - "hmac", + "digest 0.10.7", + "hmac 0.12.1", +] + +[[package]] +name = "pbkdf2" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112d82ceb8c5bf524d9af484d4e4970c9fd5a0cc15ba14ad93dccd28873b0629" +dependencies = [ + "digest 0.11.3", + "hmac 0.13.0", ] [[package]] @@ -5138,7 +5225,7 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "perf" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#46ac5758a5562f05b786b88cf3600b9334abeb7d" +source = "git+https://github.com/zed-industries/zed#e5052961af01e6810f961d6b217376edbe02b106" dependencies = [ "collections", "serde", @@ -5340,7 +5427,7 @@ version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "crc32fast", "fdeflate", "flate2", @@ -5379,7 +5466,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" dependencies = [ - "cpufeatures", + "cpufeatures 0.2.17", "opaque-debug", "universal-hash", ] @@ -5525,7 +5612,7 @@ version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e9f068eba8e7071c5f9511831b44f32c740d5adf574e990f946ddb53db2f314e" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "getopts", "memchr", "pulldown-cmark-escape", @@ -5684,6 +5771,16 @@ dependencies = [ "rand_core 0.9.5", ] +[[package]] +name = "rand" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207" +dependencies = [ + "getrandom 0.4.2", + "rand_core 0.10.1", +] + [[package]] name = "rand_chacha" version = "0.3.1" @@ -5722,6 +5819,12 @@ dependencies = [ "getrandom 0.3.4", ] +[[package]] +name = "rand_core" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" + [[package]] name = "range-alloc" version = "0.1.5" @@ -5833,6 +5936,16 @@ dependencies = [ "font-types", ] +[[package]] +name = "read-fonts" +version = "0.39.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4ed38b89c2c77ff968c524145ad65fb010f38af5c7a224b53b81d47ac2daa81" +dependencies = [ + "bytemuck", + "font-types", +] + [[package]] name = "redox_syscall" version = "0.2.16" @@ -5848,16 +5961,16 @@ version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", ] [[package]] name = "redox_syscall" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c7591fa2c6b601dfcfe5f043f65a1c39fcdf50efefcd7f1572e538c1f4b398d" +checksum = "5b44b894f2a6e36457d665d1e08c3866add6ed5e70050c1b4ba8a8ddedb02ce7" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", ] [[package]] @@ -5905,7 +6018,7 @@ dependencies = [ [[package]] name = "refineable" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#46ac5758a5562f05b786b88cf3600b9334abeb7d" +source = "git+https://github.com/zed-industries/zed#e5052961af01e6810f961d6b217376edbe02b106" dependencies = [ "derive_refineable", ] @@ -5972,6 +6085,7 @@ dependencies = [ "base64", "bytes", "futures-core", + "h2", "http", "http-body", "http-body-util", @@ -6004,7 +6118,7 @@ dependencies = [ [[package]] name = "reqwest_client" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#46ac5758a5562f05b786b88cf3600b9334abeb7d" +source = "git+https://github.com/zed-industries/zed#e5052961af01e6810f961d6b217376edbe02b106" dependencies = [ "anyhow", "bytes", @@ -6105,7 +6219,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5bcdef0be6fe7f6fa333b1073c949729274b05f123a0ad7efcb8efd878e5c3b1" dependencies = [ "globset", - "sha2", + "sha2 0.10.9", "walkdir", ] @@ -6152,7 +6266,7 @@ version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "errno", "libc", "linux-raw-sys 0.4.15", @@ -6165,7 +6279,7 @@ version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "errno", "libc", "linux-raw-sys 0.12.1", @@ -6190,9 +6304,9 @@ dependencies = [ [[package]] name = "rustls-native-certs" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" +checksum = "dab5152771c58876a2146916e53e35057e1a4dfa2b9df0f0305b07f611fdea4d" dependencies = [ "openssl-probe", "rustls-pki-types", @@ -6270,7 +6384,7 @@ version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd3c7c96f8a08ee34eff8857b11b49b07d71d1c3f4e88f8a88d4c9e9f90b1702" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "bytemuck", "core_maths", "log", @@ -6290,11 +6404,12 @@ checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" [[package]] name = "salsa20" -version = "0.10.2" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" +checksum = "2f874456e72520ff1375a06c588eaf074b0f01f9e9e1aada45bd9b7954a6e42c" dependencies = [ - "cipher", + "cfg-if", + "cipher 0.5.2", ] [[package]] @@ -6318,7 +6433,7 @@ dependencies = [ [[package]] name = "scheduler" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#46ac5758a5562f05b786b88cf3600b9334abeb7d" +source = "git+https://github.com/zed-industries/zed#e5052961af01e6810f961d6b217376edbe02b106" dependencies = [ "async-task", "backtrace", @@ -6393,14 +6508,14 @@ dependencies = [ [[package]] name = "scrypt" -version = "0.11.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0516a385866c09368f0b5bcd1caff3366aace790fcd46e2bb032697bb172fd1f" +checksum = "d87af57419b594aa23fa95f09f0e06d80d84ba01c26148c43844cad6ff4485f0" dependencies = [ - "password-hash", - "pbkdf2", + "cfg-if", + "pbkdf2 0.13.0", "salsa20", - "sha2", + "sha2 0.11.0", ] [[package]] @@ -6434,7 +6549,7 @@ version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "core-foundation 0.10.0", "core-foundation-sys", "libc", @@ -6619,8 +6734,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", - "cpufeatures", - "digest", + "cpufeatures 0.2.17", + "digest 0.10.7", ] [[package]] @@ -6636,8 +6751,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", - "cpufeatures", - "digest", + "cpufeatures 0.2.17", + "digest 0.10.7", +] + +[[package]] +name = "sha2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "digest 0.11.3", ] [[package]] @@ -6724,7 +6850,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fbdfe3d2475fbd7ddd1f3e5cf8288a30eb3e5f95832829570cd88115a7434ac" dependencies = [ "bytemuck", - "read-fonts", + "read-fonts 0.37.0", +] + +[[package]] +name = "skrifa" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c34617370ae968efb7161bb2beb517d9084659aae19e24b89e3db25b46e4564" +dependencies = [ + "bytemuck", + "read-fonts 0.39.2", ] [[package]] @@ -6809,7 +6945,7 @@ version = "0.4.0+sdk-1.4.341.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9571ea910ebd84c86af4b3ed27f9dbdc6ad06f17c5f96146b2b671e2976744f" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", ] [[package]] @@ -6941,7 +7077,7 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "sum_tree" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#46ac5758a5562f05b786b88cf3600b9334abeb7d" +source = "git+https://github.com/zed-industries/zed#e5052961af01e6810f961d6b217376edbe02b106" dependencies = [ "heapless 0.9.3", "log", @@ -7046,11 +7182,11 @@ dependencies = [ [[package]] name = "swash" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "842f3cd369c2ba38966204f983eaa5e54a8e84a7d7159ed36ade2b6c335aae64" +checksum = "d1804632b66a35ca2b1d277eb0a138e10f46cb365b9a6d297e876b69ef79de43" dependencies = [ - "skrifa", + "skrifa 0.42.1", "yazi", "zeno", ] @@ -7124,7 +7260,7 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "core-foundation 0.9.4", "system-configuration-sys", ] @@ -7371,6 +7507,15 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "tokio-happy-eyeballs" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8564c32dfb6f4257f8bc6edfc178a34af97520e0b7b9815500c55eb3d092f29f" +dependencies = [ + "tokio", +] + [[package]] name = "tokio-macros" version = "2.7.0" @@ -7558,7 +7703,7 @@ version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "bytes", "futures-util", "http", @@ -7815,9 +7960,9 @@ checksum = "383ad40bb927465ec0ce7720e033cb4ca06912855fc35db31b5755d0de75b1ee" [[package]] name = "unicode-segmentation" -version = "1.13.2" +version = "1.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c" +checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" [[package]] name = "unicode-vo" @@ -7843,7 +7988,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" dependencies = [ - "crypto-common", + "crypto-common 0.1.7", "subtle", ] @@ -7926,7 +8071,7 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "util" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#46ac5758a5562f05b786b88cf3600b9334abeb7d" +source = "git+https://github.com/zed-industries/zed#e5052961af01e6810f961d6b217376edbe02b106" dependencies = [ "anyhow", "async-fs", @@ -7965,7 +8110,7 @@ dependencies = [ [[package]] name = "util_macros" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#46ac5758a5562f05b786b88cf3600b9334abeb7d" +source = "git+https://github.com/zed-industries/zed#e5052961af01e6810f961d6b217376edbe02b106" dependencies = [ "perf", "quote", @@ -7974,9 +8119,9 @@ dependencies = [ [[package]] name = "uuid" -version = "1.23.2" +version = "1.23.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d258b83ceec21034727ecee8c382cfa6c3e133699b0742c64571814fb420c9f7" +checksum = "144d6b123cef80b301b8f72a9e2ca4370ddec21950d0a103dd22c437006d2db7" dependencies = [ "getrandom 0.4.2", "js-sys", @@ -8121,9 +8266,9 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasm-bindgen" -version = "0.2.122" +version = "0.2.123" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed04576f974d2b2fba0f38c51dbc5518011e38c36bf1143164be765528fd409" +checksum = "a254a4b10c19a76f09a27640e7ffbf9bc30bf67e16a3bf28aaefa4920fe81563" dependencies = [ "cfg-if", "once_cell", @@ -8134,9 +8279,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.72" +version = "0.4.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9473dbd2991ae90b6291c3c32c30c6187ac49aa32f9905d1cce280ec1e110b0f" +checksum = "54568702fabf5d4849ce2b90fadfa64168a097eaf4b351ce9df8b687a0086aaf" dependencies = [ "js-sys", "wasm-bindgen", @@ -8144,9 +8289,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.122" +version = "0.2.123" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "916151b09da36bd82f6615cbf3a419e2f0ba23a03c6160e8e92eb6bd4aa1dec6" +checksum = "24a40fc75b0ec6f3746ceb10d36f53a93dcd68a93b11b6445983945d79eba0dc" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -8154,9 +8299,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.122" +version = "0.2.123" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "299047362ccbfce148b67ab7e73349f77748e00c8296f9542adfad2ad82c5c5e" +checksum = "908f34bd9b9ce3d4caf07b72dfab63d61504d156856c6bd3cd87fa350cf3985b" dependencies = [ "bumpalo", "proc-macro2", @@ -8167,9 +8312,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.122" +version = "0.2.123" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a929b2c61f11ba3e9bc35b50c1f25cb38e0e892c0c231ae2b8cf78d5dad4437" +checksum = "7acbf7616c27b194bbb550bf77ed0c2c3e5b7fd1260a93082b95fb7f47959b92" dependencies = [ "unicode-ident", ] @@ -8227,7 +8372,7 @@ version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "hashbrown 0.15.5", "indexmap", "semver", @@ -8253,7 +8398,7 @@ version = "0.31.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "645c7c96bb74690c3189b5c9cb4ca1627062bb23693a4fad9d8c3de958260144" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "rustix 1.1.4", "wayland-backend", "wayland-scanner", @@ -8276,7 +8421,7 @@ version = "0.32.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "563a85523cade2429938e790815fd7319062103b9f4a2dc806e9b53b95982d8f" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "wayland-backend", "wayland-client", "wayland-scanner", @@ -8288,7 +8433,7 @@ version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b6d8cf1eb2c1c31ed1f5643c88a6e53538129d4af80030c8cabd1f9fa884d91" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "wayland-backend", "wayland-client", "wayland-protocols", @@ -8301,7 +8446,7 @@ version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb04e52f7836d7c7976c78ca0250d61e33873c34156a2a1fc9474828ec268234" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "wayland-backend", "wayland-client", "wayland-protocols", @@ -8333,9 +8478,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.99" +version = "0.3.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d621441cfc37b84979402712047321980c178f299193a3589d05b99e8763436" +checksum = "6e0871acf327f283dc6da28a1696cdc64fb355ba9f935d052021fa77f35cce69" dependencies = [ "js-sys", "wasm-bindgen", @@ -8415,7 +8560,7 @@ version = "29.0.3" source = "git+https://github.com/zed-industries/wgpu.git?rev=357a0c56e0070480ad9daea5d2eaa83150b79e88#357a0c56e0070480ad9daea5d2eaa83150b79e88" dependencies = [ "arrayvec", - "bitflags 2.11.1", + "bitflags 2.13.0", "bytemuck", "cfg-if", "cfg_aliases", @@ -8446,7 +8591,7 @@ dependencies = [ "arrayvec", "bit-set", "bit-vec", - "bitflags 2.11.1", + "bitflags 2.13.0", "bytemuck", "cfg_aliases", "document-features", @@ -8503,7 +8648,7 @@ dependencies = [ "arrayvec", "ash", "bit-set", - "bitflags 2.11.1", + "bitflags 2.13.0", "block2 0.6.2", "bytemuck", "cfg-if", @@ -8561,7 +8706,7 @@ name = "wgpu-types" version = "29.0.3" source = "git+https://github.com/zed-industries/wgpu.git?rev=357a0c56e0070480ad9daea5d2eaa83150b79e88#357a0c56e0070480ad9daea5d2eaa83150b79e88" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "bytemuck", "js-sys", "log", @@ -9323,7 +9468,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" dependencies = [ "anyhow", - "bitflags 2.11.1", + "bitflags 2.13.0", "indexmap", "log", "serde", @@ -9439,7 +9584,7 @@ name = "xim-parser" version = "0.2.1" source = "git+https://github.com/zed-industries/xim-rs.git?rev=16f35a2c881b815a2b6cdfd6687988e84f8447d8#16f35a2c881b815a2b6cdfd6687988e84f8447d8" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", ] [[package]] @@ -9497,9 +9642,9 @@ dependencies = [ [[package]] name = "yoke" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca" +checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" dependencies = [ "stable_deref_trait", "yoke-derive", @@ -9620,7 +9765,7 @@ name = "zed-font-kit" version = "0.14.1-zed" source = "git+https://github.com/zed-industries/font-kit?rev=94b0f28166665e8fd2f53ff6d268a14955c82269#94b0f28166665e8fd2f53ff6d268a14955c82269" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "byteorder", "core-foundation 0.10.0", "core-graphics 0.24.0", @@ -9825,7 +9970,7 @@ dependencies = [ [[package]] name = "zlog" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#46ac5758a5562f05b786b88cf3600b9334abeb7d" +source = "git+https://github.com/zed-industries/zed#e5052961af01e6810f961d6b217376edbe02b106" dependencies = [ "anyhow", "chrono", @@ -9842,7 +9987,7 @@ checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" [[package]] name = "ztracing" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#46ac5758a5562f05b786b88cf3600b9334abeb7d" +source = "git+https://github.com/zed-industries/zed#e5052961af01e6810f961d6b217376edbe02b106" dependencies = [ "tracing", "tracing-subscriber", @@ -9853,7 +9998,7 @@ dependencies = [ [[package]] name = "ztracing_macro" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#46ac5758a5562f05b786b88cf3600b9334abeb7d" +source = "git+https://github.com/zed-industries/zed#e5052961af01e6810f961d6b217376edbe02b106" [[package]] name = "zune-core" diff --git a/Cargo.toml b/Cargo.toml index b53f547..3865dce 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,12 +19,12 @@ gpui_tokio = { git = "https://github.com/zed-industries/zed" } reqwest_client = { git = "https://github.com/zed-industries/zed" } # Nostr -nostr-lmdb = { git = "https://github.com/rust-nostr/nostr", rev = "46d66396467e07c3dfb71e5102104ecb7e9c6b64" } -nostr-connect = { git = "https://github.com/rust-nostr/nostr", rev = "46d66396467e07c3dfb71e5102104ecb7e9c6b64" } -nostr-blossom = { git = "https://github.com/rust-nostr/nostr", rev = "46d66396467e07c3dfb71e5102104ecb7e9c6b64" } -nostr-gossip-memory = { git = "https://github.com/rust-nostr/nostr", rev = "46d66396467e07c3dfb71e5102104ecb7e9c6b64" } -nostr-sdk = { git = "https://github.com/rust-nostr/nostr", rev = "46d66396467e07c3dfb71e5102104ecb7e9c6b64" } -nostr = { git = "https://github.com/rust-nostr/nostr", features = [ "nip96", "nip59", "nip49", "nip44" ], rev = "46d66396467e07c3dfb71e5102104ecb7e9c6b64" } +nostr-lmdb = { git = "https://github.com/rust-nostr/nostr", } +nostr-connect = { git = "https://github.com/rust-nostr/nostr" } +nostr-blossom = { git = "https://github.com/rust-nostr/nostr" } +nostr-gossip-memory = { git = "https://github.com/rust-nostr/nostr" } +nostr-sdk = { git = "https://github.com/rust-nostr/nostr" } +nostr = { git = "https://github.com/rust-nostr/nostr", features = [ "nip59", "nip49", "nip44" ] } # Others anyhow = "1.0.44" diff --git a/crates/chat/src/lib.rs b/crates/chat/src/lib.rs index f5346e7..fb38881 100644 --- a/crates/chat/src/lib.rs +++ b/crates/chat/src/lib.rs @@ -16,7 +16,7 @@ use gpui::{ use nostr_sdk::prelude::*; use smallvec::{SmallVec, smallvec}; use smol::lock::RwLock; -use state::{CoopSigner, DEVICE_GIFTWRAP, NostrRegistry, StateEvent, USER_GIFTWRAP}; +use state::{DEVICE_GIFTWRAP, NostrRegistry, USER_GIFTWRAP}; mod message; mod room; @@ -137,15 +137,17 @@ impl ChatRegistry { /// Create a new chat registry instance fn new(window: &mut Window, cx: &mut Context) -> Self { let nostr = NostrRegistry::global(cx); + let user_signer = nostr.read(cx).signer.clone(); let (tx, rx) = flume::unbounded::(); let mut subscriptions = smallvec![]; subscriptions.push( // Subscribe to the signer event - cx.subscribe(&nostr, |this, _state, event, cx| { - if event == &StateEvent::SignerSet { + cx.observe(&user_signer, |this, signer, cx| { + if let Some(keys) = signer.read(cx).clone() { this.reset(cx); + this.handle_notifications(keys, cx); this.get_metadata(cx); this.get_rooms(cx); }; @@ -154,7 +156,6 @@ impl ChatRegistry { // Run at the end of the current cycle cx.defer_in(window, |this, _window, cx| { - this.handle_notifications(cx); this.tracking(cx); this.get_rooms(cx); }); @@ -174,10 +175,9 @@ impl ChatRegistry { } /// Handle nostr notifications - fn handle_notifications(&mut self, cx: &mut Context) { + fn handle_notifications(&mut self, signer: Keys, cx: &mut Context) { let nostr = NostrRegistry::global(cx); let client = nostr.read(cx).client(); - let signer = nostr.read(cx).signer(); let tracking = self.tracking.clone(); let msg_relays_existed = self.msg_relays_existed.clone(); @@ -219,7 +219,7 @@ impl ChatRegistry { // Handle msg relays event to determine when the app is ready to subscribe if event.kind == Kind::InboxRelays { - let current_user = signer.get_public_key().await?; + let current_user = signer.get_public_key_async().await?; if event.pubkey == current_user { // Mark that the msg relays have been found @@ -265,10 +265,10 @@ impl ChatRegistry { } } } - RelayMessage::EndOfStoredEvents(id) => { - if id.as_ref() == &sub_id1 || id.as_ref() == &sub_id2 { - tx.send_async(Signal::eose()).await?; - } + RelayMessage::EndOfStoredEvents(id) + if (id.as_ref() == &sub_id1 || id.as_ref() == &sub_id2) => + { + tx.send_async(Signal::eose()).await?; } _ => {} } @@ -337,9 +337,8 @@ impl ChatRegistry { pub fn get_metadata(&mut self, cx: &mut Context) { let nostr = NostrRegistry::global(cx); let client = nostr.read(cx).client(); - let signer = nostr.read(cx).signer(); - let Some(public_key) = signer.public_key() else { + let Some(public_key) = nostr.read(cx).signer_pubkey(cx) else { return; }; @@ -392,11 +391,14 @@ impl ChatRegistry { fn get_messages(&mut self, msg_relays: &Event, cx: &mut Context) { let nostr = NostrRegistry::global(cx); let client = nostr.read(cx).client(); - let signer = nostr.read(cx).signer(); - let urls: Vec = nip17::extract_relay_list(msg_relays).cloned().collect(); + let urls: Vec = nip17::extract_relay_list(msg_relays).collect(); + + let Some(signer) = nostr.read(cx).signer(cx) else { + return; + }; let task: Task> = cx.background_spawn(async move { - let public_key = signer.get_public_key().await?; + let public_key = signer.get_public_key_async().await?; let filter = Filter::new().kind(Kind::GiftWrap).pubkey(public_key); let id = SubscriptionId::new(format!("{}-msg", public_key.to_hex())); @@ -510,11 +512,12 @@ impl ChatRegistry { I: Into + 'static, { let nostr = NostrRegistry::global(cx); - let client = nostr.read(cx).client(); + + let Some(public_key) = nostr.read(cx).signer_pubkey(cx) else { + return; + }; cx.spawn(async move |this, cx| { - let signer = client.signer()?; - let public_key = signer.get_public_key().await.ok()?; let room: Room = room.into().organize(&public_key); this.update(cx, |this, cx| { @@ -643,10 +646,11 @@ impl ChatRegistry { let nostr = NostrRegistry::global(cx); let client = nostr.read(cx).client(); - cx.background_spawn(async move { - let signer = client.signer().context("Signer not found")?; - let public_key = signer.get_public_key().await?; + let Some(public_key) = nostr.read(cx).signer_pubkey(cx) else { + return Task::ready(Err(anyhow!("Signer is required"))); + }; + cx.background_spawn(async move { // Get contacts let contacts = client .database() @@ -723,15 +727,15 @@ impl ChatRegistry { /// Updates room ordering based on the most recent messages. pub fn new_message(&mut self, message: NewMessage, cx: &mut Context) { let nostr = NostrRegistry::global(cx); - let signer = nostr.read(cx).signer(); + + let Some(public_key) = nostr.read(cx).signer_pubkey(cx) else { + return; + }; match self.rooms.iter().find(|e| e.read(cx).id == message.room) { Some(room) => { room.update(cx, |this, cx| { - if this.kind == RoomKind::Request - && let Some(public_key) = signer.public_key() - && message.rumor.pubkey == public_key - { + if this.kind == RoomKind::Request && message.rumor.pubkey == public_key { this.set_ongoing(cx); } this.push_message(message, cx); @@ -760,7 +764,7 @@ impl ChatRegistry { /// Unwraps a gift-wrapped event and processes its contents. async fn extract_rumor( client: &Client, - signer: &Arc, + signer: &Keys, gift_wrap: &Event, ) -> Result { // Try to get cached rumor first @@ -784,8 +788,9 @@ async fn extract_rumor( } /// Helper method to try unwrapping with different signers -async fn try_unwrap(signer: &Arc, gift_wrap: &Event) -> Result { - // Try with the device signer first +async fn try_unwrap(signer: &Keys, gift_wrap: &Event) -> Result { + /* + * // Try with the device signer first if let Some(signer) = signer.get_encryption_signer().await { log::info!("trying with encryption key"); if let Ok(unwrapped) = try_unwrap_with(gift_wrap, &signer).await { @@ -795,19 +800,17 @@ async fn try_unwrap(signer: &Arc, gift_wrap: &Event) -> Result(gift_wrap: &Event, signer: &T) -> Result -where - T: NostrSigner + 'static, -{ +async fn try_unwrap_with(gift_wrap: &Event, signer: &Keys) -> Result { // Get the sealed event let seal = signer - .nip44_decrypt(&gift_wrap.pubkey, &gift_wrap.content) + .nip44_decrypt_async(&gift_wrap.pubkey, &gift_wrap.content) .await?; // Verify the sealed event @@ -815,7 +818,10 @@ where seal.verify_with_ctx(&SECP256K1)?; // Get the rumor event - let rumor = signer.nip44_decrypt(&seal.pubkey, &seal.content).await?; + let rumor = signer + .nip44_decrypt_async(&seal.pubkey, &seal.content) + .await?; + let rumor = UnsignedEvent::from_json(rumor)?; Ok(UnwrappedGift { @@ -836,26 +842,17 @@ async fn set_rumor(client: &Client, id: EventId, rumor: &UnsignedEvent) -> Resul tags.push(Tag::identifier(id)); // Add a reference to the rumor's author - tags.push(Tag::custom( - TagKind::SingleLetter(SingleLetterTag::lowercase(Alphabet::A)), - [author], - )); + tags.push(Tag::custom("a", [author])); // Add a conversation id - tags.push(Tag::custom( - TagKind::SingleLetter(SingleLetterTag::lowercase(Alphabet::C)), - [conversation.to_string()], - )); + tags.push(Tag::custom("c", [conversation.to_string()])); // Add a reference to the rumor's id tags.push(Tag::event(rumor_id)); // Add references to the rumor's participants - for receiver in rumor.tags.public_keys().copied() { - tags.push(Tag::custom( - TagKind::SingleLetter(SingleLetterTag::lowercase(Alphabet::P)), - [receiver], - )); + for receiver in rumor.tags.public_keys() { + tags.push(Tag::custom("P", [receiver])); } // Convert rumor to json @@ -864,7 +861,7 @@ async fn set_rumor(client: &Client, id: EventId, rumor: &UnsignedEvent) -> Resul // Construct the event let event = EventBuilder::new(Kind::ApplicationSpecificData, content) .tags(tags) - .sign(&Keys::generate()) + .finalize_async(&Keys::generate()) .await?; // Save the event to the database @@ -890,7 +887,7 @@ async fn get_rumor(client: &Client, gift_wrap: EventId) -> Result u64 { let mut hasher = DefaultHasher::new(); - let mut pubkeys: Vec = rumor.tags.public_keys().copied().collect(); + let mut pubkeys: Vec = rumor.tags.public_keys().collect(); pubkeys.push(rumor.pubkey); pubkeys.sort(); pubkeys.dedup(); diff --git a/crates/chat/src/message.rs b/crates/chat/src/message.rs index 3234226..10a8ba6 100644 --- a/crates/chat/src/message.rs +++ b/crates/chat/src/message.rs @@ -242,13 +242,13 @@ fn extract_mentions(content: &str) -> Vec { fn extract_reply_ids(inner: &Tags) -> Vec { let mut replies_to = vec![]; - for tag in inner.filter(TagKind::e()) { + for tag in inner.iter().filter(|tag| tag.kind() == "e") { if let Some(id) = tag.content().and_then(|id| EventId::parse(id).ok()) { replies_to.push(id); } } - for tag in inner.filter(TagKind::q()) { + for tag in inner.iter().filter(|tag| tag.kind() == "q") { if let Some(id) = tag.content().and_then(|id| EventId::parse(id).ok()) { replies_to.push(id); } diff --git a/crates/chat/src/room.rs b/crates/chat/src/room.rs index c77a1fb..50c5827 100644 --- a/crates/chat/src/room.rs +++ b/crates/chat/src/room.rs @@ -4,6 +4,7 @@ use std::time::Duration; use anyhow::{Error, anyhow}; use common::EventExt; +use device::DeviceRegistry; use gpui::{App, AppContext, Context, EventEmitter, SharedString, Task}; use itertools::Itertools; use nostr_sdk::prelude::*; @@ -21,7 +22,7 @@ pub struct SendReport { pub receiver: PublicKey, pub gift_wrap_id: Option, pub error: Option, - pub output: Option>, + pub output: Option>, } impl SendReport { @@ -41,7 +42,7 @@ impl SendReport { } /// Set the output. - pub fn output(mut self, output: Output) -> Self { + pub fn output(mut self, output: Output) -> Self { self.output = Some(output); self } @@ -171,7 +172,8 @@ impl From<&UnsignedEvent> for Room { let members = val.extract_public_keys(); let subject = val .tags - .find(TagKind::Subject) + .iter() + .find(|tag| tag.kind() == "subject") .and_then(|tag| tag.content().map(|s| s.to_owned().into())); Room { @@ -205,7 +207,7 @@ impl Room { // WARNING: never sign this event let mut event = EventBuilder::new(Kind::PrivateDirectMessage, "") .tags(tags) - .build(author); + .finalize_unsigned(author); // Ensure that the ID is set event.ensure_id(); @@ -425,7 +427,7 @@ impl Room { let nostr = NostrRegistry::global(cx); // Get current user's public key - let sender = nostr.read(cx).signer().public_key()?; + let sender = nostr.read(cx).signer_pubkey(cx)?; // Get all members, excluding the sender let members: Vec = self @@ -440,9 +442,7 @@ impl Room { // Add subject tag if present if let Some(value) = self.subject.as_ref() { - tags.push(Tag::from_standardized_without_cell(TagStandard::Subject( - value.to_string(), - ))); + tags.push(Tag::custom("subject", vec![value.to_string()])); } // Add all reply tags @@ -452,19 +452,20 @@ impl Room { // Add all receiver tags for member in members.into_iter() { - tags.push(Tag::from_standardized_without_cell( - TagStandard::PublicKey { + tags.push( + Nip01Tag::PublicKey { public_key: member.public_key(), - relay_url: member.messaging_relay_hint(), - alias: None, - uppercase: false, - }, - )); + relay_hint: member.messaging_relay_hint(), + } + .to_tag(), + ); } // Construct a direct message rumor event // WARNING: never sign and send this event to relays - let mut event = EventBuilder::new(kind, content).tags(tags).build(sender); + let mut event = EventBuilder::new(kind, content) + .tags(tags) + .finalize_unsigned(sender); // Ensure that the ID is set event.ensure_id(); @@ -475,13 +476,18 @@ impl Room { /// Send rumor event to all members's messaging relays pub fn send(&self, rumor: UnsignedEvent, cx: &App) -> Option>> { let config = self.config.clone(); - let persons = PersonRegistry::global(cx); + + let device = DeviceRegistry::global(cx); + let encryption_signer = device.read(cx).signer(cx); + let nostr = NostrRegistry::global(cx); let client = nostr.read(cx).client(); - let signer = nostr.read(cx).signer(); // Get current user's public key - let public_key = nostr.read(cx).signer().public_key()?; + let user_signer = nostr.read(cx).signer(cx)?; + let public_key = nostr.read(cx).signer_pubkey(cx)?; + + let persons = PersonRegistry::global(cx); let sender = persons.read(cx).get(&public_key, cx); // Get all members (excluding sender) @@ -496,9 +502,6 @@ impl Room { let signer_kind = config.signer_kind(); let backup = config.backup(); - let user_signer = signer.get().await; - let encryption_signer = signer.get_encryption_signer().await; - let mut sents = 0; let mut reports = Vec::new(); @@ -592,17 +595,14 @@ impl Room { } // Helper function to send a gift-wrapped event -async fn send_gift_wrap( +async fn send_gift_wrap( client: &Client, - signer: &T, + signer: &Keys, receiver: &Person, rumor: &UnsignedEvent, config: &SignerKind, -) -> Result -where - T: NostrSigner + 'static, -{ - let k_tag = Tag::custom(TagKind::k(), vec!["14"]); +) -> Result { + let k_tag = Tag::custom("k", vec!["14"]); let mut extra_tags = vec![k_tag]; // Determine the receiver public key based on the config @@ -627,7 +627,10 @@ where }; // Construct the gift wrap event - let event = EventBuilder::gift_wrap(signer, &receiver, rumor.clone(), extra_tags).await?; + let event = nip59::GiftWrapBuilder::new(receiver, rumor.clone()) + .extra_tags(extra_tags) + .finalize_async(signer) + .await?; // Send the gift wrap event and collect the report let report = client diff --git a/crates/chat_ui/src/lib.rs b/crates/chat_ui/src/lib.rs index 9fc609d..6b87781 100644 --- a/crates/chat_ui/src/lib.rs +++ b/crates/chat_ui/src/lib.rs @@ -234,7 +234,7 @@ impl ChatPanel { match &*status { SendStatus::Ok { id, relay } => { if output.id() == id { - output.success.insert(relay.clone()); + output.success.insert(relay.clone(), EventSendStatus::Sent); } } SendStatus::Failed { id, relay, message } => { @@ -1158,7 +1158,7 @@ impl ChatPanel { .text_xs() .font_semibold() .line_height(relative(1.25)) - .child(SharedString::from(url.to_string())), + .child(SharedString::from(url.0.to_string())), ) .child( div() diff --git a/crates/common/src/event.rs b/crates/common/src/event.rs index 194cddf..e115775 100644 --- a/crates/common/src/event.rs +++ b/crates/common/src/event.rs @@ -18,7 +18,7 @@ impl EventExt for Event { } fn extract_public_keys(&self) -> Vec { - let mut public_keys: Vec = self.tags.public_keys().copied().collect(); + let mut public_keys: Vec = self.tags.public_keys().collect(); public_keys.push(self.pubkey); public_keys.into_iter().unique().collect() @@ -46,7 +46,7 @@ impl EventExt for UnsignedEvent { } fn extract_public_keys(&self) -> Vec { - let mut public_keys: Vec = self.tags.public_keys().copied().collect(); + let mut public_keys: Vec = self.tags.public_keys().collect(); public_keys.push(self.pubkey); public_keys.into_iter().unique().sorted().collect() } diff --git a/crates/device/src/lib.rs b/crates/device/src/lib.rs index dd69da1..1b1a462 100644 --- a/crates/device/src/lib.rs +++ b/crates/device/src/lib.rs @@ -65,6 +65,9 @@ pub struct DeviceRegistry { /// Whether an announcement has been made for this device pub announcement_existed: Arc, + /// Signer + signer: Entity>, + /// Async tasks tasks: Vec>>, @@ -87,7 +90,10 @@ impl DeviceRegistry { /// Create a new device registry instance fn new(window: &mut Window, cx: &mut Context) -> Self { + let signer = cx.new(|_| None); let nostr = NostrRegistry::global(cx); + let user_signer = nostr.read(cx).signer.clone(); + let settings = AppSettings::global(cx); let is_nip4e_enabled = settings.read(cx).is_nip4e_enabled(cx); @@ -104,8 +110,8 @@ impl DeviceRegistry { subscriptions.push( // Subscribe to nostr state events - cx.subscribe(&nostr, move |this, _e, event, cx| { - if event == &StateEvent::SignerSet && is_nip4e_enabled { + cx.observe(&user_signer, move |this, signer, cx| { + if signer.read(cx).is_some() && is_nip4e_enabled { this.get_announcement(cx); }; }), @@ -116,6 +122,7 @@ impl DeviceRegistry { }); Self { + signer, pending_request: false, announcement_existed: Arc::new(AtomicBool::new(false)), tasks: vec![], @@ -126,13 +133,15 @@ impl DeviceRegistry { fn handle_notifications(&mut self, window: &mut Window, cx: &mut Context) { let nostr = NostrRegistry::global(cx); let client = nostr.read(cx).client(); - let signer = nostr.read(cx).signer(); let announcement_existed = self.announcement_existed.clone(); let (tx, rx) = flume::bounded::(100); + let Some(current_user) = nostr.read(cx).signer_pubkey(cx) else { + return; + }; + self.tasks.push(cx.background_spawn(async move { - let current_user = signer.get_public_key().await?; let mut notifications = client.notifications(); let mut processed_events = HashSet::new(); @@ -203,24 +212,18 @@ impl DeviceRegistry { cx.notify(); } + /// Get the signer + pub fn signer(&self, cx: &App) -> Option { + self.signer.read(cx).clone() + } + /// Set the decoupled encryption key for the current user - fn set_signer(&mut self, new: S, cx: &mut Context) - where - S: NostrSigner + 'static, - { - let nostr = NostrRegistry::global(cx); - let signer = nostr.read(cx).signer(); - - self.tasks.push(cx.spawn(async move |this, cx| { - signer.set_encryption_signer(new).await; - - // Notify the UI via event - this.update(cx, |_this, cx| { - cx.emit(DeviceEvent::Set); - })?; - - Ok(()) - })); + fn set_signer(&mut self, new: Keys, cx: &mut Context) { + self.signer.update(cx, |this, cx| { + *this = Some(new); + cx.notify(); + }); + cx.emit(DeviceEvent::Set); } /// Backup the encryption's secret key to a file @@ -228,8 +231,12 @@ impl DeviceRegistry { let nostr = NostrRegistry::global(cx); let client = nostr.read(cx).client(); + let Some(signer) = nostr.read(cx).signer(cx) else { + return Task::ready(Err(anyhow!("Signer is required"))); + }; + cx.background_spawn(async move { - let keys = get_keys(&client).await?; + let keys = get_keys(&client, &signer).await?; let content = keys.secret_key().to_bech32()?; smol::fs::write(path, &content).await?; @@ -242,16 +249,18 @@ impl DeviceRegistry { pub fn get_announcement(&mut self, cx: &mut Context) { let nostr = NostrRegistry::global(cx); let client = nostr.read(cx).client(); - let signer = nostr.read(cx).signer(); + + let Some(current_user) = nostr.read(cx).signer_pubkey(cx) else { + return; + }; self.tasks.push(cx.background_spawn(async move { - let public_key = signer.get_public_key().await?; let opts = SubscribeAutoCloseOptions::default().exit_policy(ReqExitPolicy::ExitOnEOSE); // Construct the filter for the device announcement event let filter = Filter::new() .kind(Kind::Custom(10044)) - .author(public_key) + .author(current_user) .limit(1); client @@ -319,15 +328,19 @@ impl DeviceRegistry { let secret = keys.secret_key().to_secret_hex(); let n = keys.public_key(); + let Some(signer) = nostr.read(cx).signer(cx) else { + return Task::ready(Err(anyhow!("Signer is required"))); + }; + cx.background_spawn(async move { // Construct an announcement event - let builder = EventBuilder::new(Kind::Custom(10044), "").tags(vec![ - Tag::custom(TagKind::custom("n"), vec![n]), - Tag::client(CLIENT_NAME), - ]); - - // Sign the event with user's signer - let event = client.sign_event_builder(builder).await?; + let event = EventBuilder::new(Kind::Custom(10044), "") + .tags(vec![ + Tag::custom("n", vec![n]), + Tag::custom("client", vec![CLIENT_NAME]), + ]) + .finalize_async(&signer) + .await?; // Publish announcement client @@ -337,7 +350,7 @@ impl DeviceRegistry { .await?; // Save device keys to the database - set_keys(&client, &secret).await?; + set_keys(&client, &signer, &secret).await?; Ok(keys) }) @@ -348,12 +361,16 @@ impl DeviceRegistry { let nostr = NostrRegistry::global(cx); let client = nostr.read(cx).client(); + let Some(signer) = nostr.read(cx).signer(cx) else { + return; + }; + let announcement = Announcement::from(event); let device_pubkey = announcement.public_key(); // Get encryption key from the database and compare with the announcement let task: Task> = cx.background_spawn(async move { - let keys = get_keys(&client).await?; + let keys = get_keys(&client, &signer).await?; // Compare the public key from the announcement with the one from the database if keys.public_key() != device_pubkey { @@ -382,10 +399,13 @@ impl DeviceRegistry { fn wait_for_request(&mut self, cx: &mut Context) { let nostr = NostrRegistry::global(cx); let client = nostr.read(cx).client(); - let signer = nostr.read(cx).signer(); + + let Some(signer) = nostr.read(cx).signer(cx) else { + return; + }; self.tasks.push(cx.background_spawn(async move { - let public_key = signer.get_public_key().await?; + let public_key = signer.get_public_key_async().await?; let id = SubscriptionId::new("dekey-requests"); // Construct a filter for encryption key requests @@ -405,13 +425,16 @@ impl DeviceRegistry { pub fn request(&mut self, cx: &mut Context) { let nostr = NostrRegistry::global(cx); let client = nostr.read(cx).client(); - let signer = nostr.read(cx).signer(); - let app_keys = nostr.read(cx).keys(); + let app_keys = Keys::generate(); let app_pubkey = app_keys.public_key(); + let Some(signer) = nostr.read(cx).signer(cx) else { + return; + }; + let task: Task, Error>> = cx.background_spawn(async move { - let public_key = signer.get_public_key().await?; + let public_key = signer.get_public_key_async().await?; // Construct a filter to get the latest approval event let filter = Filter::new() @@ -426,13 +449,13 @@ impl DeviceRegistry { // No approval event found, construct a request event None => { // Construct an event for device key request - let builder = EventBuilder::new(Kind::Custom(4454), "").tags(vec![ - Tag::custom(TagKind::custom("P"), vec![app_pubkey]), - Tag::client(CLIENT_NAME), - ]); - - // Sign the event with user's signer - let event = client.sign_event_builder(builder).await?; + let event = EventBuilder::new(Kind::Custom(4454), "") + .tags(vec![ + Tag::custom("P", vec![app_pubkey]), + Tag::custom("client", vec![CLIENT_NAME]), + ]) + .finalize_async(&signer) + .await?; // Send the event to write relays client.send_event(&event).to_nip65().await?; @@ -468,12 +491,15 @@ impl DeviceRegistry { fn wait_for_approval(&mut self, cx: &mut Context) { let nostr = NostrRegistry::global(cx); let client = nostr.read(cx).client(); - let signer = nostr.read(cx).signer(); + + let Some(signer) = nostr.read(cx).signer(cx) else { + return; + }; cx.emit(DeviceEvent::Requesting); self.tasks.push(cx.background_spawn(async move { - let public_key = signer.get_public_key().await?; + let public_key = signer.get_public_key_async().await?; // Construct a filter for device key requests let filter = Filter::new() @@ -491,18 +517,19 @@ impl DeviceRegistry { /// Parse the approval event to get encryption key then set it fn extract_encryption(&mut self, event: Event, cx: &mut Context) { let nostr = NostrRegistry::global(cx); - let app_keys = nostr.read(cx).keys(); + let app_keys = Keys::generate(); let task: Task> = cx.background_spawn(async move { let master = event .tags - .find(TagKind::custom("P")) + .iter() + .find(|tag| tag.kind() == "P") .and_then(|tag| tag.content()) .and_then(|content| PublicKey::parse(content).ok()) .context("Invalid event's tags")?; let payload = event.content.as_str(); - let decrypted = app_keys.nip44_decrypt(&master, payload).await?; + let decrypted = app_keys.nip44_decrypt_async(&master, payload).await?; let secret = SecretKey::from_hex(&decrypted)?; let keys = Keys::new(secret); @@ -532,37 +559,42 @@ impl DeviceRegistry { let nostr = NostrRegistry::global(cx); let client = nostr.read(cx).client(); + let Some(signer) = nostr.read(cx).signer(cx) else { + return; + }; + // Get user's write relays let event = event.clone(); let id: SharedString = event.id.to_hex().into(); let task: Task> = cx.background_spawn(async move { // Get device keys - let keys = get_keys(&client).await?; + let keys = get_keys(&client, &signer).await?; let secret = keys.secret_key().to_secret_hex(); // Extract the target public key from the event tags let target = event .tags - .find(TagKind::custom("P")) + .iter() + .find(|tag| tag.kind() == "P") .and_then(|tag| tag.content()) .and_then(|content| PublicKey::parse(content).ok()) .context("Target is not a valid public key")?; // Encrypt the device keys with the user's signer - let payload = keys.nip44_encrypt(&target, &secret).await?; + let payload = keys.nip44_encrypt_async(&target, &secret).await?; // Construct the response event // // P tag: the current device's public key // p tag: the requester's public key - let builder = EventBuilder::new(Kind::Custom(4455), payload).tags(vec![ - Tag::custom(TagKind::custom("P"), vec![keys.public_key().to_hex()]), - Tag::public_key(target), - ]); - - // Sign the builder - let event = client.sign_event_builder(builder).await?; + let event = EventBuilder::new(Kind::Custom(4455), payload) + .tags(vec![ + Tag::custom("P", vec![keys.public_key().to_hex()]), + Tag::public_key(target), + ]) + .finalize_async(&signer) + .await?; // Send the response event to the user's relay list client.send_event(&event).to_nip65().await?; @@ -713,18 +745,14 @@ impl DeviceRegistry { struct DeviceNotification; /// Encrypt and store device keys in the local database. -async fn set_keys(client: &Client, secret: &str) -> Result<(), Error> { - let signer = client.signer().context("Signer not found")?; - let public_key = signer.get_public_key().await?; - - // Encrypt the value - let content = signer.nip44_encrypt(&public_key, secret).await?; +async fn set_keys(client: &Client, signer: &Keys, secret: &str) -> Result<(), Error> { + let public_key = signer.get_public_key_async().await?; + let content = signer.nip44_encrypt_async(&public_key, secret).await?; // Construct the application data event let event = EventBuilder::new(Kind::ApplicationSpecificData, content) .tag(Tag::identifier(IDENTIFIER)) - .build(public_key) - .sign(&Keys::generate()) + .finalize_async(signer) .await?; // Save the event to the database @@ -734,9 +762,8 @@ async fn set_keys(client: &Client, secret: &str) -> Result<(), Error> { } /// Get device keys from the local database. -async fn get_keys(client: &Client) -> Result { - let signer = client.signer().context("Signer not found")?; - let public_key = signer.get_public_key().await?; +async fn get_keys(client: &Client, signer: &Keys) -> Result { + let public_key = signer.get_public_key_async().await?; let filter = Filter::new() .kind(Kind::ApplicationSpecificData) @@ -744,7 +771,10 @@ async fn get_keys(client: &Client) -> Result { .author(public_key); if let Some(event) = client.database().query(filter).await?.first() { - let content = signer.nip44_decrypt(&public_key, &event.content).await?; + let content = signer + .nip44_decrypt_async(&public_key, &event.content) + .await?; + let secret = SecretKey::parse(&content)?; let keys = Keys::new(secret); diff --git a/crates/person/src/lib.rs b/crates/person/src/lib.rs index 3f72f99..b8423f1 100644 --- a/crates/person/src/lib.rs +++ b/crates/person/src/lib.rs @@ -242,7 +242,7 @@ impl PersonRegistry { /// Set messaging relays for a person fn set_messaging_relays(&mut self, event: &Event, cx: &mut App) { - let urls: Vec = nip17::extract_relay_list(event).cloned().collect(); + let urls: Vec = nip17::extract_relay_list(event).collect(); if let Some(person) = self.persons.get(&event.pubkey) { person.update(cx, |person, cx| { diff --git a/crates/relay_auth/src/lib.rs b/crates/relay_auth/src/lib.rs index dc63cc7..13ed5ca 100644 --- a/crates/relay_auth/src/lib.rs +++ b/crates/relay_auth/src/lib.rs @@ -193,15 +193,20 @@ impl RelayAuth { fn auth(&self, req: &Arc, cx: &App) -> Task> { let nostr = NostrRegistry::global(cx); let client = nostr.read(cx).client(); - let req = req.clone(); + + let Some(signer) = nostr.read(cx).signer(cx) else { + return Task::ready(Err(anyhow!("Signer is required"))); + }; // Get all pending events for the relay + let req = req.clone(); let pending_events = self.get_pending_events(req.url(), cx); cx.background_spawn(async move { // Construct event - let builder = EventBuilder::auth(req.challenge(), req.url().clone()); - let event = client.sign_event_builder(builder).await?; + let event = EventBuilder::auth(req.challenge(), req.url().clone()) + .finalize_async(&signer) + .await?; // Get the event ID let id = event.id; diff --git a/crates/state/src/lib.rs b/crates/state/src/lib.rs index 2fc4c51..0546279 100644 --- a/crates/state/src/lib.rs +++ b/crates/state/src/lib.rs @@ -1,9 +1,7 @@ use std::collections::HashMap; -use std::path::PathBuf; -use std::sync::Arc; use std::time::Duration; -use anyhow::{Context as AnyhowContext, Error, anyhow}; +use anyhow::{Error, anyhow}; use common::config_dir; use gpui::{App, AppContext, Context, Entity, EventEmitter, Global, SharedString, Task, Window}; use nostr_connect::prelude::*; @@ -15,13 +13,11 @@ mod blossom; mod constants; mod nip05; mod nip4e; -mod signer; pub use blossom::*; pub use constants::*; pub use nip4e::*; pub use nip05::*; -pub use signer::*; pub fn init(window: &mut Window, cx: &mut App) { // rustls uses the `aws_lc_rs` provider by default @@ -48,12 +44,6 @@ pub enum StateEvent { Connecting, /// Connected to the bootstrapping relay Connected, - /// Creating the signer - Creating, - /// Show the identity dialog - Show, - /// A new signer has been set - SignerSet, /// An error occurred Error(SharedString), } @@ -73,19 +63,8 @@ pub struct NostrRegistry { /// Nostr client client: Client, - /// Nostr signer - signer: Arc, - - /// All local stored identities - npubs: Entity>, - - /// Keys directory - key_dir: PathBuf, - - /// Master app keys used for various operations. - /// - /// Example: Nostr Connect and NIP-4e operations - app_keys: Keys, + /// Currently active signer + pub signer: Entity>, /// Tasks for asynchronous operations tasks: Vec>>, @@ -106,20 +85,7 @@ impl NostrRegistry { /// Create a new nostr instance fn new(window: &mut Window, cx: &mut Context) -> Self { - let key_dir = config_dir().join("keys"); - let app_keys = get_or_init_app_keys(cx).unwrap_or(Keys::generate()); - - // Construct the nostr signer - let signer = Arc::new(CoopSigner::new(app_keys.clone())); - - // Get all local stored npubs - let npubs = cx.new(|_| match Self::discover(&key_dir) { - Ok(npubs) => npubs, - Err(e) => { - log::error!("Failed to discover npubs: {e}"); - vec![] - } - }); + let signer = cx.new(|_| None); // Construct the nostr lmdb instance let lmdb = cx.foreground_executor().block_on(async move { @@ -130,7 +96,6 @@ impl NostrRegistry { // Construct the nostr client let client = ClientBuilder::default() - .signer(signer.clone()) .database(lmdb) .gossip(NostrGossipMemory::unbounded()) .gossip_config( @@ -139,7 +104,6 @@ impl NostrRegistry { .sync_idle_timeout(Duration::from_millis(100)) .no_background_refresh(), ) - .automatic_authentication(false) .connect_timeout(Duration::from_secs(10)) .sleep_when_idle(SleepWhenIdle::Enabled { timeout: Duration::from_secs(600), @@ -149,22 +113,11 @@ impl NostrRegistry { // Run at the end of current cycle cx.defer_in(window, |this, _window, cx| { this.connect(cx); - - if this.npubs.read(cx).is_empty() { - // Create an identity if none exists - this.create_identity(cx); - } else { - // Show the account selector dialog - cx.emit(StateEvent::Show); - } }); Self { client, signer, - npubs, - key_dir, - app_keys, tasks: vec![], } } @@ -174,46 +127,22 @@ impl NostrRegistry { self.client.clone() } - /// Get the nostr signer - pub fn signer(&self) -> Arc { - self.signer.clone() + /// Get the signer + pub fn signer(&self, cx: &App) -> Option { + self.signer.read(cx).clone() } - /// Get the npubs entity - pub fn npubs(&self) -> Entity> { - self.npubs.clone() + /// Get the public key of the signer + pub fn signer_pubkey(&self, cx: &App) -> Option { + self.signer.read(cx).as_ref().map(|s| s.public_key()) } - /// Get the app keys - pub fn keys(&self) -> Keys { - self.app_keys.clone() - } - - /// Discover all npubs in the keys directory - fn discover(dir: &PathBuf) -> Result, Error> { - // Ensure keys directory exists - std::fs::create_dir_all(dir)?; - - let files = std::fs::read_dir(dir)?; - let mut entries = Vec::new(); - let mut npubs: Vec = Vec::new(); - - for file in files.flatten() { - let metadata = file.metadata()?; - let modified_time = metadata.modified()?; - let name = file.file_name().into_string().unwrap().replace(".npub", ""); - entries.push((modified_time, name)); - } - - // Sort by modification time (most recent first) - entries.sort_by(|a, b| b.0.cmp(&a.0)); - - for (_, name) in entries { - let public_key = PublicKey::parse(&name)?; - npubs.push(public_key); - } - - Ok(npubs) + /// Set the signer to the given keys + pub fn set_signer(&mut self, new_keys: Keys, cx: &mut Context) { + self.signer.update(cx, |this, cx| { + *this = Some(new_keys); + cx.notify(); + }); } /// Connect to the bootstrapping relays @@ -258,278 +187,8 @@ impl NostrRegistry { })); } - /// Get the secret for a given npub. - pub fn get_secret( - &self, - public_key: PublicKey, - cx: &App, - ) -> Task, Error>> { - let npub = public_key.to_bech32().unwrap(); - let key_path = self.key_dir.join(format!("{}.npub", npub)); - let app_keys = self.app_keys.clone(); - - if let Ok(payload) = std::fs::read_to_string(key_path) - && !payload.is_empty() - { - return cx.background_spawn(async move { - let decrypted = app_keys.nip44_decrypt(&public_key, &payload).await?; - let secret = SecretKey::parse(&decrypted)?; - let keys = Keys::new(secret); - - Ok(keys.into_nostr_signer()) - }); - } - - Task::ready(Err(anyhow::anyhow!("No secret found"))) - } - - /// Add a new npub to the keys directory - fn write_secret( - &self, - public_key: PublicKey, - secret: String, - cx: &App, - ) -> Task> { - let npub = public_key.to_bech32().unwrap(); - let key_path = self.key_dir.join(format!("{}.npub", npub)); - let app_keys = self.app_keys.clone(); - - cx.background_spawn(async move { - // If the secret starts with "bunker://" (nostr connect), use it directly; otherwise, encrypt it - let content = if secret.starts_with("bunker://") { - secret - } else { - app_keys.nip44_encrypt(&public_key, &secret).await? - }; - - // Write the encrypted secret to the keys directory - smol::fs::write(key_path, &content).await?; - - Ok(()) - }) - } - - /// Remove a secret - pub fn remove_secret(&mut self, public_key: &PublicKey, cx: &mut Context) { - let public_key = public_key.to_owned(); - let npub = public_key.to_bech32().unwrap(); - - let keys_dir = config_dir().join("keys"); - let key_path = keys_dir.join(format!("{}.npub", npub)); - - // Remove the secret file from the keys directory - std::fs::remove_file(key_path).ok(); - - self.npubs.update(cx, |this, cx| { - this.retain(|k| k != &public_key); - cx.notify(); - }); - } - - /// Create a new identity - pub fn create_identity(&mut self, cx: &mut Context) { - let client = self.client(); - let keys = Keys::generate(); - let async_keys = keys.clone(); - - // Emit creating event - cx.emit(StateEvent::Creating); - - // Create the write secret task - let write_secret = - self.write_secret(keys.public_key(), keys.secret_key().to_secret_hex(), cx); - - // Run async tasks in background - let task: Task> = cx.background_spawn(async move { - let signer = async_keys.into_nostr_signer(); - - // Construct relay list event - let relay_list = default_relay_list(); - let event = EventBuilder::relay_list(relay_list).sign(&signer).await?; - - // Publish relay list - client - .send_event(&event) - .to(BOOTSTRAP_RELAYS) - .ack_policy(AckPolicy::none()) - .await?; - - // Construct the default metadata - let name = petname::petname(2, "-").unwrap_or("Cooper".to_string()); - let avatar = Url::parse(&format!("https://avatar.vercel.sh/{name}")).unwrap(); - let metadata = Metadata::new().display_name(&name).picture(avatar); - let event = EventBuilder::metadata(&metadata).sign(&signer).await?; - - // Publish metadata event - client - .send_event(&event) - .to_nip65() - .ack_policy(AckPolicy::none()) - .await?; - - // Construct the default contact list - let contacts = vec![Contact::new(PublicKey::parse(COOP_PUBKEY).unwrap())]; - let event = EventBuilder::contact_list(contacts).sign(&signer).await?; - - // Publish contact list event - client - .send_event(&event) - .to_nip65() - .ack_policy(AckPolicy::none()) - .await?; - - // Construct the default messaging relay list - let relays = default_messaging_relays(); - let event = EventBuilder::nip17_relay_list(relays).sign(&signer).await?; - - // Publish messaging relay list event - client.send_event(&event).to_nip65().await?; - - // Write user's credentials to the system keyring - write_secret.await?; - - Ok(()) - }); - - self.tasks.push(cx.spawn(async move |this, cx| { - match task.await { - Ok(_) => { - this.update(cx, |this, cx| { - this.set_signer(keys, cx); - })?; - } - Err(e) => { - this.update(cx, |_this, cx| { - cx.emit(StateEvent::error(e.to_string())); - })?; - } - }; - - Ok(()) - })); - } - - /// Set the signer for the nostr client and verify the public key - pub fn set_signer(&mut self, new: T, cx: &mut Context) - where - T: NostrSigner + 'static, - { - let client = self.client(); - let signer = self.signer(); - - // Create a task to update the signer and verify the public key - let task: Task> = cx.background_spawn(async move { - // Update signer and unsubscribe - signer.switch(new).await; - client.unsubscribe_all().await?; - - // Verify and get public key - let signer = client.signer().context("Signer not found")?; - let public_key = signer.get_public_key().await?; - - log::info!("Signer's public key: {}", public_key); - Ok(public_key) - }); - - self.tasks.push(cx.spawn(async move |this, cx| { - match task.await { - Ok(public_key) => { - this.update(cx, |this, cx| { - // Add public key to npubs if not already present - this.npubs.update(cx, |this, cx| { - if !this.contains(&public_key) { - this.push(public_key); - cx.notify(); - } - }); - - // Emit signer changed event - cx.emit(StateEvent::SignerSet); - })?; - } - Err(e) => { - this.update(cx, |_this, cx| { - cx.emit(StateEvent::error(e.to_string())); - })?; - } - }; - - Ok(()) - })); - } - - /// Add a key signer to keyring - pub fn add_key_signer(&mut self, keys: &Keys, cx: &mut Context) { - let keys = keys.clone(); - let write_secret = - self.write_secret(keys.public_key(), keys.secret_key().to_secret_hex(), cx); - - self.tasks.push(cx.spawn(async move |this, cx| { - match write_secret.await { - Ok(_) => { - this.update(cx, |this, cx| { - this.set_signer(keys, cx); - })?; - } - Err(e) => { - this.update(cx, |_this, cx| { - cx.emit(StateEvent::error(e.to_string())); - })?; - } - }; - - Ok(()) - })); - } - - /// Add a nostr connect signer to keyring - pub fn add_nip46_signer(&mut self, nip46: &NostrConnect, cx: &mut Context) { - let nip46 = nip46.clone(); - let async_nip46 = nip46.clone(); - - // Connect and verify the remote signer - let task: Task> = - cx.background_spawn(async move { - let uri = async_nip46.bunker_uri().await?; - let public_key = async_nip46.get_public_key().await?; - - Ok((public_key, uri)) - }); - - self.tasks.push(cx.spawn(async move |this, cx| { - match task.await { - Ok((public_key, uri)) => { - // Create the write secret task - let write_secret = this.read_with(cx, |this, cx| { - this.write_secret(public_key, uri.to_string(), cx) - })?; - - match write_secret.await { - Ok(_) => { - this.update(cx, |this, cx| { - this.set_signer(nip46, cx); - })?; - } - Err(e) => { - this.update(cx, |_this, cx| { - cx.emit(StateEvent::error(e.to_string())); - })?; - } - } - } - Err(e) => { - this.update(cx, |_this, cx| { - cx.emit(StateEvent::error(e.to_string())); - })?; - } - }; - - Ok(()) - })); - } - /// Get the public key of a NIP-05 address - pub fn get_address(&self, addr: Nip05Address, cx: &App) -> Task> { + pub fn query_address(&self, addr: Nip05Address, cx: &App) -> Task> { let client = self.client(); let http_client = cx.http_client(); @@ -566,7 +225,7 @@ impl NostrRegistry { // Get the address task if the query is a valid NIP-05 address let address_task = if let Ok(addr) = Nip05Address::parse(&query) { - Some(self.get_address(addr, cx)) + Some(self.query_address(addr, cx)) } else { None }; @@ -638,13 +297,19 @@ impl NostrRegistry { let client = self.client(); let query = query.to_string(); + let Some(signer) = self.signer.read(cx).clone() else { + return Task::ready(Err(anyhow!("Signer is required"))); + }; + cx.background_spawn(async move { // Construct a vertex request event - let builder = EventBuilder::new(Kind::Custom(5315), "").tags(vec![ - Tag::custom(TagKind::custom("param"), vec!["search", &query]), - Tag::custom(TagKind::custom("param"), vec!["limit", "10"]), - ]); - let event = client.sign_event_builder(builder).await?; + let event = EventBuilder::new(Kind::Custom(5315), "") + .tags(vec![ + Tag::custom("param", vec!["search", &query]), + Tag::custom("param", vec!["limit", "10"]), + ]) + .finalize_async(&signer) + .await?; // Send the event to vertex relays let output = client.send_event(&event).to(WOT_RELAYS).await?; @@ -694,78 +359,3 @@ impl NostrRegistry { }) } } - -/// Get or create new app keys -fn get_or_init_app_keys(cx: &App) -> Result { - let read = cx.read_credentials(CLIENT_NAME); - let stored_keys: Option = cx.foreground_executor().block_on(async move { - if let Ok(Some((_, secret))) = read.await { - SecretKey::from_slice(&secret).map(Keys::new).ok() - } else { - None - } - }); - - if let Some(keys) = stored_keys { - Ok(keys) - } else { - let keys = Keys::generate(); - let user = keys.public_key().to_hex(); - let secret = keys.secret_key().to_secret_bytes(); - let write = cx.write_credentials(CLIENT_NAME, &user, &secret); - - cx.foreground_executor().block_on(async move { - if let Err(e) = write.await { - log::error!("Keyring not available or panic: {e}") - } - }); - - Ok(keys) - } -} - -fn default_relay_list() -> Vec<(RelayUrl, Option)> { - vec![ - ( - RelayUrl::parse("wss://relay.nostr.net").unwrap(), - Some(RelayMetadata::Write), - ), - ( - RelayUrl::parse("wss://relay.primal.net").unwrap(), - Some(RelayMetadata::Write), - ), - ( - RelayUrl::parse("wss://relay.damus.io").unwrap(), - Some(RelayMetadata::Read), - ), - ( - RelayUrl::parse("wss://nos.lol").unwrap(), - Some(RelayMetadata::Read), - ), - ( - RelayUrl::parse("wss://nostr.superfriends.online").unwrap(), - None, - ), - ] -} - -fn default_messaging_relays() -> Vec { - vec![ - RelayUrl::parse("wss://nos.lol").unwrap(), - RelayUrl::parse("wss://nip17.com").unwrap(), - RelayUrl::parse("wss://auth.nostr1.com").unwrap(), - ] -} - -#[derive(Debug, Clone)] -pub struct CoopAuthUrlHandler; - -impl AuthUrlHandler for CoopAuthUrlHandler { - #[allow(mismatched_lifetime_syntaxes)] - fn on_auth_url(&self, auth_url: Url) -> BoxedFuture> { - Box::pin(async move { - webbrowser::open(auth_url.as_str())?; - Ok(()) - }) - } -} diff --git a/crates/state/src/nip4e.rs b/crates/state/src/nip4e.rs index 4aae264..475795c 100644 --- a/crates/state/src/nip4e.rs +++ b/crates/state/src/nip4e.rs @@ -16,14 +16,15 @@ impl From<&Event> for Announcement { let public_key = val .tags .iter() - .find(|tag| tag.kind().as_str() == "n") + .find(|tag| tag.kind() == "n") .and_then(|tag| tag.content()) .and_then(|c| PublicKey::parse(c).ok()) .unwrap_or(val.pubkey); let client_name = val .tags - .find(TagKind::Client) + .iter() + .find(|tag| tag.kind() == "client") .and_then(|tag| tag.content()) .map(|c| c.to_string()); diff --git a/crates/state/src/signer.rs b/crates/state/src/signer.rs deleted file mode 100644 index c6e9b20..0000000 --- a/crates/state/src/signer.rs +++ /dev/null @@ -1,134 +0,0 @@ -use std::borrow::Cow; -use std::result::Result; -use std::sync::Arc; - -use nostr_sdk::prelude::*; -use smol::lock::RwLock; - -#[derive(Debug)] -pub struct CoopSigner { - /// User's signer - signer: RwLock>, - - /// User's signer public key - signer_pkey: RwLock>, - - /// Specific signer for encryption purposes - encryption_signer: RwLock>>, -} - -impl CoopSigner { - pub fn new(signer: T) -> Self - where - T: IntoNostrSigner, - { - Self { - signer: RwLock::new(signer.into_nostr_signer()), - signer_pkey: RwLock::new(None), - encryption_signer: RwLock::new(None), - } - } - - /// Get the current signer. - pub async fn get(&self) -> Arc { - self.signer.read().await.clone() - } - - /// Get the encryption signer. - pub async fn get_encryption_signer(&self) -> Option> { - self.encryption_signer.read().await.clone() - } - - /// Get public key - /// - /// Ensure to call this method after the signer has been initialized. - /// Otherwise, it will panic. - pub fn public_key(&self) -> Option { - *self.signer_pkey.read_blocking() - } - - /// Switch the current signer to a new signer. - pub async fn switch(&self, new: T) - where - T: IntoNostrSigner, - { - let new_signer = new.into_nostr_signer(); - let public_key = new_signer.get_public_key().await.ok(); - let mut signer = self.signer.write().await; - let mut signer_pkey = self.signer_pkey.write().await; - let mut encryption_signer = self.encryption_signer.write().await; - - // Switch to the new signer - *signer = new_signer; - - // Update the public key - *signer_pkey = public_key; - - // Reset the encryption signer - *encryption_signer = None; - } - - /// Set the encryption signer. - pub async fn set_encryption_signer(&self, new: T) - where - T: IntoNostrSigner, - { - let mut encryption_signer = self.encryption_signer.write().await; - *encryption_signer = Some(new.into_nostr_signer()); - } -} - -impl NostrSigner for CoopSigner { - #[allow(mismatched_lifetime_syntaxes)] - fn backend(&self) -> SignerBackend { - SignerBackend::Custom(Cow::Borrowed("custom")) - } - - fn get_public_key<'a>(&'a self) -> BoxedFuture<'a, Result> { - Box::pin(async move { self.get().await.get_public_key().await }) - } - - fn sign_event<'a>( - &'a self, - unsigned: UnsignedEvent, - ) -> BoxedFuture<'a, Result> { - Box::pin(async move { self.get().await.sign_event(unsigned).await }) - } - - fn nip04_encrypt<'a>( - &'a self, - public_key: &'a PublicKey, - content: &'a str, - ) -> BoxedFuture<'a, Result> { - Box::pin(async move { self.get().await.nip04_encrypt(public_key, content).await }) - } - - fn nip04_decrypt<'a>( - &'a self, - public_key: &'a PublicKey, - encrypted_content: &'a str, - ) -> BoxedFuture<'a, Result> { - Box::pin(async move { - self.get() - .await - .nip04_decrypt(public_key, encrypted_content) - .await - }) - } - - fn nip44_encrypt<'a>( - &'a self, - public_key: &'a PublicKey, - content: &'a str, - ) -> BoxedFuture<'a, Result> { - Box::pin(async move { self.get().await.nip44_encrypt(public_key, content).await }) - } - - fn nip44_decrypt<'a>( - &'a self, - public_key: &'a PublicKey, - payload: &'a str, - ) -> BoxedFuture<'a, Result> { - Box::pin(async move { self.get().await.nip44_decrypt(public_key, payload).await }) - } -} diff --git a/desktop/src/dialogs/accounts.rs b/desktop/src/dialogs/accounts.rs deleted file mode 100644 index c780046..0000000 --- a/desktop/src/dialogs/accounts.rs +++ /dev/null @@ -1,257 +0,0 @@ -use anyhow::Error; -use gpui::prelude::FluentBuilder; -use gpui::{ - App, AppContext, Context, Entity, InteractiveElement, IntoElement, ParentElement, Render, - SharedString, StatefulInteractiveElement, Styled, Subscription, Task, Window, div, px, -}; -use nostr_sdk::prelude::*; -use person::PersonRegistry; -use state::{NostrRegistry, StateEvent}; -use theme::ActiveTheme; -use ui::avatar::Avatar; -use ui::button::{Button, ButtonVariants}; -use ui::indicator::Indicator; -use ui::{Disableable, Icon, IconName, Sizable, WindowExtension, h_flex, v_flex}; - -use crate::dialogs::connect::ConnectSigner; -use crate::dialogs::import::ImportKey; - -pub fn init(window: &mut Window, cx: &mut App) -> Entity { - cx.new(|cx| AccountSelector::new(window, cx)) -} - -/// Account selector -pub struct AccountSelector { - /// Public key currently being chosen for login - logging_in: Entity>, - - /// The error message displayed when an error occurs. - error: Entity>, - - /// Async tasks - tasks: Vec>>, - - /// Subscription to the signer events - _subscription: Option, -} - -impl AccountSelector { - pub fn new(window: &mut Window, cx: &mut Context) -> Self { - let logging_in = cx.new(|_| None); - let error = cx.new(|_| None); - - // Subscribe to the signer events - let nostr = NostrRegistry::global(cx); - let subscription = cx.subscribe_in(&nostr, window, |this, _state, event, window, cx| { - match event { - StateEvent::SignerSet => { - window.close_all_modals(cx); - window.refresh(); - } - StateEvent::Error(e) => { - this.set_error(e.to_string(), cx); - } - _ => {} - }; - }); - - Self { - logging_in, - error, - tasks: vec![], - _subscription: Some(subscription), - } - } - - fn logging_in(&self, public_key: &PublicKey, cx: &App) -> bool { - self.logging_in.read(cx) == &Some(*public_key) - } - - fn set_logging_in(&mut self, public_key: PublicKey, cx: &mut Context) { - self.logging_in.update(cx, |this, cx| { - *this = Some(public_key); - cx.notify(); - }); - } - - fn set_error(&mut self, error: T, cx: &mut Context) - where - T: Into, - { - self.error.update(cx, |this, cx| { - *this = Some(error.into()); - cx.notify(); - }); - - self.logging_in.update(cx, |this, cx| { - *this = None; - cx.notify(); - }) - } - - fn login(&mut self, public_key: PublicKey, window: &mut Window, cx: &mut Context) { - let nostr = NostrRegistry::global(cx); - let task = nostr.read(cx).get_secret(public_key, cx); - - // Mark the public key as being logged in - self.set_logging_in(public_key, cx); - - self.tasks.push(cx.spawn_in(window, async move |this, cx| { - match task.await { - Ok(signer) => { - nostr.update(cx, |this, cx| { - this.set_signer(signer, cx); - }); - } - Err(e) => { - this.update(cx, |this, cx| { - this.set_error(e.to_string(), cx); - })?; - } - }; - Ok(()) - })); - } - - fn remove(&mut self, public_key: PublicKey, cx: &mut Context) { - let nostr = NostrRegistry::global(cx); - - nostr.update(cx, |this, cx| { - this.remove_secret(&public_key, cx); - }); - } - - fn open_import(&mut self, window: &mut Window, cx: &mut Context) { - let import = cx.new(|cx| ImportKey::new(window, cx)); - - window.open_modal(cx, move |this, _window, _cx| { - this.width(px(460.)) - .title("Import a Secret Key or Bunker Connection") - .show_close(true) - .pb_2() - .child(import.clone()) - }); - } - - fn open_connect(&mut self, window: &mut Window, cx: &mut Context) { - let connect = cx.new(|cx| ConnectSigner::new(window, cx)); - - window.open_modal(cx, move |this, _window, _cx| { - this.width(px(460.)) - .title("Scan QR Code to Connect") - .show_close(true) - .pb_2() - .child(connect.clone()) - }); - } -} - -impl Render for AccountSelector { - fn render(&mut self, _window: &mut Window, cx: &mut Context) -> impl IntoElement { - let persons = PersonRegistry::global(cx); - let nostr = NostrRegistry::global(cx); - let npubs = nostr.read(cx).npubs(); - let loading = self.logging_in.read(cx).is_some(); - - v_flex() - .size_full() - .gap_2() - .when_some(self.error.read(cx).as_ref(), |this, error| { - this.child( - div() - .italic() - .text_xs() - .text_center() - .text_color(cx.theme().text_danger) - .child(error.clone()), - ) - }) - .children({ - let mut items = vec![]; - - for (ix, public_key) in npubs.read(cx).iter().enumerate() { - let profile = persons.read(cx).get(public_key, cx); - let logging_in = self.logging_in(public_key, cx); - - items.push( - h_flex() - .id(ix) - .group("") - .px_2() - .h_10() - .justify_between() - .w_full() - .rounded(cx.theme().radius) - .bg(cx.theme().ghost_element_background) - .hover(|this| this.bg(cx.theme().ghost_element_hover)) - .child( - h_flex() - .gap_2() - .child(Avatar::new(profile.avatar()).small()) - .child(div().text_sm().child(profile.name())), - ) - .when(logging_in, |this| this.child(Indicator::new().small())) - .when(!logging_in, |this| { - this.child( - h_flex() - .gap_1() - .invisible() - .group_hover("", |this| this.visible()) - .child( - Button::new(format!("del-{ix}")) - .icon(IconName::Close) - .ghost() - .small() - .disabled(logging_in) - .on_click(cx.listener({ - let public_key = *public_key; - move |this, _ev, _window, cx| { - cx.stop_propagation(); - this.remove(public_key, cx); - } - })), - ), - ) - }) - .when(!logging_in, |this| { - let public_key = *public_key; - this.on_click(cx.listener(move |this, _ev, window, cx| { - this.login(public_key, window, cx); - })) - }), - ); - } - - items - }) - .child(div().w_full().h_px().bg(cx.theme().border_variant)) - .child( - h_flex() - .gap_1() - .justify_end() - .w_full() - .child( - Button::new("input") - .icon(Icon::new(IconName::Usb)) - .label("Import") - .ghost() - .small() - .disabled(loading) - .on_click(cx.listener(move |this, _ev, window, cx| { - this.open_import(window, cx); - })), - ) - .child( - Button::new("qr") - .icon(Icon::new(IconName::Scan)) - .label("Scan QR to connect") - .ghost() - .small() - .disabled(loading) - .on_click(cx.listener(move |this, _ev, window, cx| { - this.open_connect(window, cx); - })), - ), - ) - } -} diff --git a/desktop/src/dialogs/connect.rs b/desktop/src/dialogs/connect.rs deleted file mode 100644 index 537cdc1..0000000 --- a/desktop/src/dialogs/connect.rs +++ /dev/null @@ -1,115 +0,0 @@ -use std::sync::Arc; -use std::time::Duration; - -use common::StringExt; -use gpui::prelude::FluentBuilder; -use gpui::{ - AppContext, Context, Entity, Image, IntoElement, ParentElement, Render, SharedString, Styled, - Subscription, Window, div, img, px, -}; -use nostr_connect::prelude::*; -use state::{ - CLIENT_NAME, CoopAuthUrlHandler, NOSTR_CONNECT_RELAY, NOSTR_CONNECT_TIMEOUT, NostrRegistry, - StateEvent, -}; -use theme::ActiveTheme; -use ui::v_flex; - -pub struct ConnectSigner { - /// QR Code - qr_code: Option>, - - /// Error message - error: Entity>, - - /// Subscription to the signer event - _subscription: Option, -} - -impl ConnectSigner { - pub fn new(window: &mut Window, cx: &mut Context) -> Self { - let error = cx.new(|_| None); - - let nostr = NostrRegistry::global(cx); - let app_keys = nostr.read(cx).keys(); - - let timeout = Duration::from_secs(NOSTR_CONNECT_TIMEOUT); - let relay = RelayUrl::parse(NOSTR_CONNECT_RELAY).unwrap(); - - // Generate the nostr connect uri - let uri = NostrConnectUri::client(app_keys.public_key(), vec![relay], CLIENT_NAME); - - // Generate the nostr connect - let mut signer = NostrConnect::new(uri.clone(), app_keys.clone(), timeout, None).unwrap(); - - // Handle the auth request - signer.auth_url_handler(CoopAuthUrlHandler); - - // Generate a QR code for quick connection - let qr_code = uri.to_string().to_qr(); - - // Set signer in the background - nostr.update(cx, |this, cx| { - this.add_nip46_signer(&signer, cx); - }); - - // Subscribe to the signer event - let subscription = cx.subscribe_in(&nostr, window, |this, _state, event, _window, cx| { - if let StateEvent::Error(e) = event { - this.set_error(e, cx); - } - }); - - Self { - qr_code, - error, - _subscription: Some(subscription), - } - } - - fn set_error(&mut self, message: S, cx: &mut Context) - where - S: Into, - { - self.error.update(cx, |this, cx| { - *this = Some(message.into()); - cx.notify(); - }); - } -} - -impl Render for ConnectSigner { - fn render(&mut self, _window: &mut Window, cx: &mut Context) -> impl IntoElement { - const MSG: &str = "Scan with any Nostr Connect-compatible app to connect"; - - v_flex() - .size_full() - .items_center() - .justify_center() - .p_4() - .when_some(self.qr_code.as_ref(), |this, qr| { - this.child( - img(qr.clone()) - .size(px(256.)) - .rounded(cx.theme().radius_lg) - .border_1() - .border_color(cx.theme().border), - ) - }) - .when_some(self.error.read(cx).as_ref(), |this, error| { - this.child( - div() - .text_xs() - .text_center() - .text_color(cx.theme().text_danger) - .child(error.clone()), - ) - }) - .child( - div() - .text_xs() - .text_color(cx.theme().text_muted) - .child(SharedString::from(MSG)), - ) - } -} diff --git a/desktop/src/dialogs/import.rs b/desktop/src/dialogs/import.rs index 7810a53..ad2347b 100644 --- a/desktop/src/dialogs/import.rs +++ b/desktop/src/dialogs/import.rs @@ -7,15 +7,14 @@ use gpui::{ Subscription, Task, Window, div, }; use nostr_connect::prelude::*; -use smallvec::{SmallVec, smallvec}; -use state::{CoopAuthUrlHandler, NostrRegistry, StateEvent}; +use state::NostrRegistry; use theme::ActiveTheme; use ui::button::{Button, ButtonVariants}; use ui::input::{Input, InputEvent, InputState}; use ui::{Disableable, v_flex}; #[derive(Debug)] -pub struct ImportKey { +pub struct ImportIdentity { /// Secret key input key_input: Entity, @@ -25,73 +24,43 @@ pub struct ImportKey { /// Error message error: Entity>, - /// Countdown timer for nostr connect - countdown: Entity>, - /// Whether the user is currently loading loading: bool, /// Async tasks tasks: Vec>>, - /// Event subscriptions - _subscriptions: SmallVec<[Subscription; 2]>, + /// Input subscription + _subscription: Option, } -impl ImportKey { +impl ImportIdentity { pub fn new(window: &mut Window, cx: &mut Context) -> Self { - let nostr = NostrRegistry::global(cx); let key_input = cx.new(|cx| InputState::new(window, cx).masked(true)); let pass_input = cx.new(|cx| InputState::new(window, cx).masked(true)); let error = cx.new(|_| None); - let countdown = cx.new(|_| None); - let mut subscriptions = smallvec![]; - - subscriptions.push( - // Subscribe to key input events and process login when the user presses enter + let input_subscription = cx.subscribe_in(&key_input, window, |this, _input, event, window, cx| { if let InputEvent::PressEnter { .. } = event { this.login(window, cx); }; - }), - ); - - subscriptions.push( - // Subscribe to the nostr signer event - cx.subscribe_in(&nostr, window, |this, _state, event, _window, cx| { - if let StateEvent::Error(e) = event { - this.set_error(e, cx); - } - }), - ); + }); Self { key_input, pass_input, error, - countdown, loading: false, tasks: vec![], - _subscriptions: subscriptions, + _subscription: Some(input_subscription), } } fn login(&mut self, window: &mut Window, cx: &mut Context) { - if self.loading { - return; - }; - // Prevent duplicate login requests - self.set_loading(true, cx); - let value = self.key_input.read(cx).value(); let password = self.pass_input.read(cx).value(); - if value.starts_with("bunker://") { - self.bunker(&value, window, cx); - return; - } - if value.starts_with("ncryptsec1") { self.ncryptsec(value, password, window, cx); return; @@ -103,52 +72,13 @@ impl ImportKey { // Update the signer nostr.update(cx, |this, cx| { - this.add_key_signer(&keys, cx); + this.set_signer(keys, cx); }); } else { self.set_error("Invalid key", cx); } } - fn bunker(&mut self, content: &str, window: &mut Window, cx: &mut Context) { - let Ok(uri) = NostrConnectUri::parse(content) else { - self.set_error("Bunker is not valid", cx); - return; - }; - - let nostr = NostrRegistry::global(cx); - let app_keys = nostr.read(cx).keys(); - let timeout = Duration::from_secs(30); - - // Construct the nostr connect signer - let mut signer = NostrConnect::new(uri, app_keys.clone(), timeout, None).unwrap(); - - // Handle auth url with the default browser - signer.auth_url_handler(CoopAuthUrlHandler); - - // Set signer in the background - nostr.update(cx, |this, cx| { - this.add_nip46_signer(&signer, cx); - }); - - // Start countdown - self.tasks.push(cx.spawn_in(window, async move |this, cx| { - for i in (0..=30).rev() { - if i == 0 { - this.update(cx, |this, cx| { - this.set_countdown(None, cx); - })?; - } else { - this.update(cx, |this, cx| { - this.set_countdown(Some(i), cx); - })?; - } - cx.background_executor().timer(Duration::from_secs(1)).await; - } - Ok(()) - })); - } - fn ncryptsec(&mut self, content: S, pwd: S, window: &mut Window, cx: &mut Context) where S: Into, @@ -180,7 +110,7 @@ impl ImportKey { match task.await { Ok(keys) => { nostr.update(cx, |this, cx| { - this.add_key_signer(&keys, cx); + this.set_signer(keys, cx); }); } Err(e) => { @@ -198,12 +128,6 @@ impl ImportKey { where S: Into, { - // Reset the log in state - self.set_loading(false, cx); - - // Reset the countdown - self.set_countdown(None, cx); - // Update error message self.error.update(cx, |this, cx| { *this = Some(message.into()); @@ -224,22 +148,12 @@ impl ImportKey { Ok(()) })); } - - fn set_loading(&mut self, status: bool, cx: &mut Context) { - self.loading = status; - cx.notify(); - } - - fn set_countdown(&mut self, i: Option, cx: &mut Context) { - self.countdown.update(cx, |this, cx| { - *this = i; - cx.notify(); - }); - } } -impl Render for ImportKey { +impl Render for ImportIdentity { fn render(&mut self, _window: &mut gpui::Window, cx: &mut Context) -> impl IntoElement { + const MSG: &str = "Coop isn't stored your identity secret in local device. Everything will be reset on the next login."; + v_flex() .size_full() .gap_2() @@ -249,7 +163,7 @@ impl Render for ImportKey { .gap_1() .text_sm() .text_color(cx.theme().text_muted) - .child("nsec or bunker://") + .child("nsec or ncryptsec://") .child(Input::new(&self.key_input)), ) .when( @@ -265,6 +179,7 @@ impl Render for ImportKey { ) }, ) + .child(div().text_xs().text_color(cx.theme().text_muted).child(MSG)) .child( Button::new("login") .label("Continue") @@ -275,18 +190,6 @@ impl Render for ImportKey { this.login(window, cx); })), ) - .when_some(self.countdown.read(cx).as_ref(), |this, i| { - this.child( - div() - .text_xs() - .text_center() - .text_color(cx.theme().text_muted) - .child(SharedString::from(format!( - "Approve connection request from your signer in {} seconds", - i - ))), - ) - }) .when_some(self.error.read(cx).as_ref(), |this, error| { this.child( div() diff --git a/desktop/src/dialogs/mod.rs b/desktop/src/dialogs/mod.rs index 831a2de..ffdf97b 100644 --- a/desktop/src/dialogs/mod.rs +++ b/desktop/src/dialogs/mod.rs @@ -1,5 +1,3 @@ -pub mod accounts; -pub mod connect; pub mod import; pub mod restore; pub mod screening; diff --git a/desktop/src/dialogs/screening.rs b/desktop/src/dialogs/screening.rs index 3a13e7a..3f5b375 100644 --- a/desktop/src/dialogs/screening.rs +++ b/desktop/src/dialogs/screening.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use std::time::Duration; -use anyhow::{Context as AnyhowContext, Error}; +use anyhow::Error; use common::TimestampExt; use gpui::prelude::FluentBuilder; use gpui::{ @@ -78,12 +78,13 @@ impl Screening { let client = nostr.read(cx).client(); let public_key = self.public_key; - let task: Task> = cx.background_spawn(async move { - let signer = client.signer().context("Signer not found")?; - let signer_pubkey = signer.get_public_key().await?; + let Some(current_user) = nostr.read(cx).signer_pubkey(cx) else { + return; + }; + let task: Task> = cx.background_spawn(async move { // Check if user is in contact list - let contacts = client.database().contacts_public_keys(signer_pubkey).await; + let contacts = client.database().contacts_public_keys(current_user).await; let followed = contacts.unwrap_or_default().contains(&public_key); Ok(followed) @@ -105,16 +106,17 @@ impl Screening { let client = nostr.read(cx).client(); let public_key = self.public_key; - let task: Task, Error>> = cx.background_spawn(async move { - let signer = client.signer().context("Signer not found")?; - let signer_pubkey = signer.get_public_key().await?; + let Some(current_user) = nostr.read(cx).signer_pubkey(cx) else { + return; + }; + let task: Task, Error>> = cx.background_spawn(async move { // Check mutual contacts let filter = Filter::new().kind(Kind::ContactList).pubkey(public_key); let mut mutual_contacts = vec![]; if let Ok(events) = client.database().query(filter).await { - for event in events.into_iter().filter(|ev| ev.pubkey != signer_pubkey) { + for event in events.into_iter().filter(|ev| ev.pubkey != current_user) { mutual_contacts.push(event.pubkey); } } @@ -224,10 +226,20 @@ impl Screening { let client = nostr.read(cx).client(); let public_key = self.public_key; + let Some(signer) = nostr.read(cx).signer(cx) else { + return; + }; + let task: Task> = cx.background_spawn(async move { - let tag = Tag::public_key_report(public_key, Report::Impersonation); - let builder = EventBuilder::report(vec![tag], ""); - let event = client.sign_event_builder(builder).await?; + let tag = Nip56Tag::PublicKey { + public_key, + report: Report::Impersonation, + } + .to_tag(); + + let event = EventBuilder::report(vec![tag], "") + .finalize_async(&signer) + .await?; // Send the report to the public relays client.send_event(&event).to(BOOTSTRAP_RELAYS).await?; diff --git a/desktop/src/panels/contact_list.rs b/desktop/src/panels/contact_list.rs index a9f86f2..7db2a29 100644 --- a/desktop/src/panels/contact_list.rs +++ b/desktop/src/panels/contact_list.rs @@ -1,7 +1,7 @@ use std::collections::HashSet; use std::time::Duration; -use anyhow::{Context as AnyhowContext, Error}; +use anyhow::Error; use gpui::prelude::FluentBuilder; use gpui::{ AnyElement, App, AppContext, Context, Entity, EventEmitter, FocusHandle, Focusable, @@ -82,11 +82,12 @@ impl ContactListPanel { let nostr = NostrRegistry::global(cx); let client = nostr.read(cx).client(); - let task: Task, Error>> = cx.background_spawn(async move { - let signer = client.signer().context("Signer not found")?; - let public_key = signer.get_public_key().await?; - let contact_list = client.database().contacts_public_keys(public_key).await?; + let Some(public_key) = nostr.read(cx).signer_pubkey(cx) else { + return; + }; + let task: Task, Error>> = cx.background_spawn(async move { + let contact_list = client.database().contacts_public_keys(public_key).await?; Ok(contact_list) }); @@ -157,6 +158,10 @@ impl ContactListPanel { let nostr = NostrRegistry::global(cx); let client = nostr.read(cx).client(); + let Some(signer) = nostr.read(cx).signer(cx) else { + return; + }; + // Get contacts let contacts: Vec = self .contacts @@ -169,8 +174,9 @@ impl ContactListPanel { let task: Task> = cx.background_spawn(async move { // Construct contact list event builder - let builder = EventBuilder::contact_list(contacts); - let event = client.sign_event_builder(builder).await?; + let event = ContactListBuilder::new(contacts) + .finalize_async(&signer) + .await?; // Set contact list client.send_event(&event).to_nip65().await?; diff --git a/desktop/src/panels/greeter.rs b/desktop/src/panels/greeter.rs index 97e1c37..07e973c 100644 --- a/desktop/src/panels/greeter.rs +++ b/desktop/src/panels/greeter.rs @@ -30,9 +30,8 @@ impl GreeterPanel { fn add_profile_panel(&mut self, window: &mut Window, cx: &mut Context) { let nostr = NostrRegistry::global(cx); - let signer = nostr.read(cx).signer(); - if let Some(public_key) = signer.public_key() { + if let Some(public_key) = nostr.read(cx).signer_pubkey(cx) { cx.spawn_in(window, async move |_this, cx| { cx.update(|window, cx| { Workspace::add_panel( diff --git a/desktop/src/panels/messaging_relays.rs b/desktop/src/panels/messaging_relays.rs index 1125c13..284c92c 100644 --- a/desktop/src/panels/messaging_relays.rs +++ b/desktop/src/panels/messaging_relays.rs @@ -1,7 +1,7 @@ use std::collections::HashSet; use std::time::Duration; -use anyhow::{Context as AnyhowContext, Error, anyhow}; +use anyhow::{Error, anyhow}; use gpui::prelude::FluentBuilder; use gpui::{ AnyElement, App, AppContext, Context, Entity, EventEmitter, FocusHandle, Focusable, @@ -83,17 +83,18 @@ impl MessagingRelayPanel { let nostr = NostrRegistry::global(cx); let client = nostr.read(cx).client(); - let task: Task, Error>> = cx.background_spawn(async move { - let signer = client.signer().context("Signer not found")?; - let public_key = signer.get_public_key().await?; + let Some(public_key) = nostr.read(cx).signer_pubkey(cx) else { + return; + }; + let task: Task, Error>> = cx.background_spawn(async move { let filter = Filter::new() .kind(Kind::InboxRelays) .author(public_key) .limit(1); if let Some(event) = client.database().query(filter).await?.first_owned() { - Ok(nip17::extract_owned_relay_list(event).collect()) + Ok(nip17::extract_relay_list(&event).collect()) } else { Err(anyhow!("Not found.")) } @@ -171,11 +172,15 @@ impl MessagingRelayPanel { let nostr = NostrRegistry::global(cx); let client = nostr.read(cx).client(); + let Some(signer) = nostr.read(cx).signer(cx) else { + return; + }; + // Construct event tags let tags: Vec = self .relays .iter() - .map(|relay| Tag::relay(relay.clone())) + .map(|relay| Nip17Tag::Relay(relay.to_owned()).to_tag()) .collect(); // Set updating state @@ -183,8 +188,10 @@ impl MessagingRelayPanel { let task: Task> = cx.background_spawn(async move { // Construct nip17 event builder - let builder = EventBuilder::new(Kind::InboxRelays, "").tags(tags); - let event = client.sign_event_builder(builder).await?; + let event = EventBuilder::new(Kind::InboxRelays, "") + .tags(tags) + .finalize_async(&signer) + .await?; // Set messaging relays client.send_event(&event).to_nip65().await?; diff --git a/desktop/src/panels/profile.rs b/desktop/src/panels/profile.rs index 606b6ae..6b70ace 100644 --- a/desktop/src/panels/profile.rs +++ b/desktop/src/panels/profile.rs @@ -1,7 +1,7 @@ use std::str::FromStr; use std::time::Duration; -use anyhow::{Context as AnyhowContext, Error}; +use anyhow::{Context as AnyhowContext, Error, anyhow}; use gpui::{ AnyElement, App, AppContext, ClipboardItem, Context, Entity, EventEmitter, FocusHandle, Focusable, IntoElement, ParentElement, PathPromptOptions, Render, SharedString, Styled, Task, @@ -209,10 +209,15 @@ impl ProfilePanel { let client = nostr.read(cx).client(); let metadata = metadata.clone(); + let Some(signer) = nostr.read(cx).signer(cx) else { + return Task::ready(Err(anyhow!("Signer is required"))); + }; + cx.background_spawn(async move { // Build and sign the metadata event - let builder = EventBuilder::metadata(&metadata); - let event = client.sign_event_builder(builder).await?; + let event = EventBuilder::metadata(&metadata) + .finalize_async(&signer) + .await?; // Send event to user's relays client.send_event(&event).await?; diff --git a/desktop/src/panels/relay_list.rs b/desktop/src/panels/relay_list.rs index 8e8dfb8..26d4237 100644 --- a/desktop/src/panels/relay_list.rs +++ b/desktop/src/panels/relay_list.rs @@ -1,7 +1,7 @@ use std::collections::HashSet; use std::time::Duration; -use anyhow::{Context as AnyhowContext, Error, anyhow}; +use anyhow::{Error, anyhow}; use gpui::prelude::FluentBuilder; use gpui::{ Action, AnyElement, App, AppContext, Context, Entity, EventEmitter, FocusHandle, Focusable, @@ -100,18 +100,19 @@ impl RelayListPanel { let nostr = NostrRegistry::global(cx); let client = nostr.read(cx).client(); + let Some(public_key) = nostr.read(cx).signer_pubkey(cx) else { + return; + }; + let task: Task)>, Error>> = cx .background_spawn(async move { - let signer = client.signer().context("Signer not found")?; - let public_key = signer.get_public_key().await?; - let filter = Filter::new() .kind(Kind::RelayList) .author(public_key) .limit(1); if let Some(event) = client.database().query(filter).await?.first_owned() { - Ok(nip65::extract_owned_relay_list(event).collect()) + Ok(nip65::extract_relay_list(&event).collect()) } else { Err(anyhow!("Not found.")) } @@ -207,6 +208,10 @@ impl RelayListPanel { let nostr = NostrRegistry::global(cx); let client = nostr.read(cx).client(); + let Some(signer) = nostr.read(cx).signer(cx) else { + return; + }; + // Get all relays let relays = self.relays.clone(); @@ -214,8 +219,9 @@ impl RelayListPanel { self.set_updating(true, cx); let task: Task> = cx.background_spawn(async move { - let builder = EventBuilder::relay_list(relays); - let event = client.sign_event_builder(builder).await?; + let event = EventBuilder::relay_list(relays) + .finalize_async(&signer) + .await?; // Set relay list for current user client.send_event(&event).await?; diff --git a/desktop/src/sidebar/mod.rs b/desktop/src/sidebar/mod.rs index fb74388..fa5598f 100644 --- a/desktop/src/sidebar/mod.rs +++ b/desktop/src/sidebar/mod.rs @@ -2,7 +2,7 @@ use std::collections::HashSet; use std::ops::Range; use std::time::Duration; -use anyhow::{Context as AnyhowContext, Error}; +use anyhow::Error; use chat::{ChatEvent, ChatRegistry, Room, RoomKind}; use common::{DebouncedDelay, TimestampExt, coop_cache}; use entry::RoomEntry; @@ -159,11 +159,12 @@ impl Sidebar { let nostr = NostrRegistry::global(cx); let client = nostr.read(cx).client(); - let task: Task, Error>> = cx.background_spawn(async move { - let signer = client.signer().context("Signer not found")?; - let public_key = signer.get_public_key().await?; - let contacts = client.database().contacts_public_keys(public_key).await?; + let Some(public_key) = nostr.read(cx).signer_pubkey(cx) else { + return; + }; + let task: Task, Error>> = cx.background_spawn(async move { + let contacts = client.database().contacts_public_keys(public_key).await?; Ok(contacts) }); @@ -319,14 +320,14 @@ impl Sidebar { let async_chat = chat.downgrade(); let nostr = NostrRegistry::global(cx); - let signer = nostr.read(cx).signer(); + let Some(public_key) = nostr.read(cx).signer_pubkey(cx) else { + return; + }; // Get all selected public keys let receivers = self.get_selected(cx); self.tasks.push(cx.spawn_in(window, async move |this, cx| { - let public_key = signer.get_public_key().await?; - // Create a new room and emit it async_chat.update_in(cx, |this, _window, cx| { let room = cx.new(|_| { diff --git a/desktop/src/workspace.rs b/desktop/src/workspace.rs index 0ef6318..985ae5d 100644 --- a/desktop/src/workspace.rs +++ b/desktop/src/workspace.rs @@ -24,23 +24,17 @@ use ui::menu::{DropdownMenu, PopupMenuItem}; use ui::notification::{Notification, NotificationKind}; use ui::{Icon, IconName, Root, Sizable, WindowExtension, h_flex, v_flex}; +use crate::dialogs::import::ImportIdentity; use crate::dialogs::restore::RestoreEncryption; -use crate::dialogs::{accounts, settings}; +use crate::dialogs::settings; use crate::panels::{backup, contact_list, greeter, messaging_relays, profile, relay_list, trash}; use crate::sidebar; -const PREPARE_MSG: &str = "Coop is preparing a new identity for you. This may take a moment..."; -const ENC_MSG: &str = "Encryption Key is a special key that used to encrypt and decrypt your messages. \ - Your identity is completely decoupled from all encryption processes to protect your privacy."; -const ENC_WARN: &str = "By resetting your encryption key, you will lose access to \ - all your encrypted messages before. This action cannot be undone."; - pub fn init(window: &mut Window, cx: &mut App) -> Entity { cx.new(|cx| Workspace::new(window, cx)) } struct DeviceNotifcation; -struct SignerNotifcation; struct RelayNotifcation; struct MsgRelayNotification; @@ -48,7 +42,6 @@ struct MsgRelayNotification; #[action(namespace = workspace, no_json)] enum Command { ToggleTheme, - ToggleAccount, RefreshMessagingRelays, BackupEncryption, @@ -75,7 +68,7 @@ pub struct Workspace { image_cache: Entity, /// Event subscriptions - _subscriptions: SmallVec<[Subscription; 5]>, + _subscriptions: SmallVec<[Subscription; 6]>, } impl Workspace { @@ -83,6 +76,7 @@ impl Workspace { let chat = ChatRegistry::global(cx); let device = DeviceRegistry::global(cx); let nostr = NostrRegistry::global(cx); + let signer = nostr.read(cx).signer.clone(); let titlebar = cx.new(|_| TitleBar::new()); let dock = cx.new(|cx| DockArea::new(window, cx)); @@ -98,19 +92,20 @@ impl Workspace { ); subscriptions.push( - // Subscribe to the signer events - cx.subscribe_in(&nostr, window, move |this, _state, event, window, cx| { - match event { - StateEvent::Creating => { - let note = Notification::new() - .id::() - .title("Preparing a new identity") - .message(PREPARE_MSG) - .autohide(false) - .with_kind(NotificationKind::Info); + // Observe the signer + cx.observe_in(&signer, window, |this, signer, window, cx| { + if signer.read(cx).is_some() { + this.set_center_layout(window, cx); + } else { + this.import_identity(window, cx); + } + }), + ); - window.push_notification(note, cx); - } + subscriptions.push( + // Subscribe to the nostr events + cx.subscribe_in(&nostr, window, move |this, state, event, window, cx| { + match event { StateEvent::Connecting => { let note = Notification::new() .id::() @@ -126,14 +121,10 @@ impl Workspace { .with_kind(NotificationKind::Success); window.push_notification(note, cx); - } - StateEvent::SignerSet => { - this.set_center_layout(window, cx); - // Clear the signer notification - window.clear_notification::(cx); - } - StateEvent::Show => { - this.account_selector(window, cx); + + if state.read(cx).signer.read(cx).is_none() { + this.import_identity(window, cx); + } } _ => {} }; @@ -341,9 +332,8 @@ impl Workspace { } Command::ShowProfile => { let nostr = NostrRegistry::global(cx); - let signer = nostr.read(cx).signer(); - if let Some(public_key) = signer.public_key() { + if let Some(public_key) = nostr.read(cx).signer_pubkey(cx) { self.dock.update(cx, |this, cx| { this.add_panel( Arc::new(profile::init(public_key, window, cx)), @@ -413,9 +403,6 @@ impl Workspace { Command::ToggleTheme => { self.theme_selector(window, cx); } - Command::ToggleAccount => { - self.account_selector(window, cx); - } Command::BackupEncryption => { let device = DeviceRegistry::global(cx).downgrade(); let save_dialog = cx.prompt_for_new_path(download_dir(), Some("encryption.txt")); @@ -458,6 +445,12 @@ impl Workspace { } fn confirm_reset_encryption(&mut self, window: &mut Window, cx: &mut Context) { + const ENC_MSG: &str = "Encryption Key is a special key that used to encrypt and decrypt your messages. \ + Your identity is completely decoupled from all encryption processes to protect your privacy."; + + const ENC_WARN: &str = "By resetting your encryption key, you will lose access to \ + all your encrypted messages before. This action cannot be undone."; + let device = DeviceRegistry::global(cx); let ent = device.downgrade(); @@ -492,24 +485,21 @@ impl Workspace { fn import_encryption(&mut self, window: &mut Window, cx: &mut Context) { let restore = cx.new(|cx| RestoreEncryption::new(window, cx)); - window.open_modal(cx, move |this, _window, _cx| { - this.width(px(520.)) + this.width(px(420.)) .title("Restore Encryption") .child(restore.clone()) }); } - fn account_selector(&mut self, window: &mut Window, cx: &mut Context) { - let accounts = accounts::init(window, cx); + fn import_identity(&mut self, window: &mut Window, cx: &mut Context) { + let import = cx.new(|cx| ImportIdentity::new(window, cx)); window.open_modal(cx, move |this, _window, _cx| { - this.width(px(520.)) - .title("Continue with") + this.width(px(420.)) .show_close(false) - .keyboard(false) - .overlay_closable(false) - .child(accounts.clone()) + .title("Import Identity") + .child(import.clone()) }); } @@ -595,8 +585,7 @@ impl Workspace { fn titlebar_left(&mut self, cx: &mut Context) -> impl IntoElement { let nostr = NostrRegistry::global(cx); - let signer = nostr.read(cx).signer(); - let current_user = signer.public_key(); + let current_user = nostr.read(cx).signer_pubkey(cx); h_flex() .flex_shrink_0() @@ -606,7 +595,7 @@ impl Workspace { div() .text_xs() .text_color(cx.theme().text_muted) - .child(SharedString::from("Choose an account to continue...")), + .child(SharedString::from("Import your identity to continue")), ) }) .when_some(current_user.as_ref(), |this, public_key| { @@ -657,11 +646,6 @@ impl Workspace { Box::new(Command::ToggleTheme), ) .separator() - .menu_with_icon( - "Accounts", - IconName::Group, - Box::new(Command::ToggleAccount), - ) .menu_with_icon( "Settings", IconName::Settings, @@ -676,11 +660,9 @@ impl Workspace { let chat = ChatRegistry::global(cx); let trash_messages = chat.read(cx).count_trash_messages(cx); let is_nip4e_enabled = AppSettings::get_encryption_key(cx); - let nostr = NostrRegistry::global(cx); - let signer = nostr.read(cx).signer(); - let Some(public_key) = signer.public_key() else { + let Some(public_key) = nostr.read(cx).signer_pubkey(cx) else { return div(); }; diff --git a/rust-toolchain.toml b/rust-toolchain.toml index a3f50e4..65beb3c 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,5 +1,5 @@ [toolchain] -channel = "1.92" +channel = "1.96" profile = "minimal" components = ["rustfmt", "clippy"] targets = [