diff --git a/Cargo.lock b/Cargo.lock index 182111c..0e7ad2c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -493,6 +493,12 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c59bdb34bc650a32731b31bd8f0829cc15d24a708ee31559e0bb34f2bc320cba" +[[package]] +name = "atomic-destructor" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef49f5882e4b6afaac09ad239a4f8c70a24b8f2b0897edb1f706008efd109cf4" + [[package]] name = "atomic-waker" version = "1.1.2" @@ -1806,7 +1812,7 @@ dependencies = [ "libc", "option-ext", "redox_users 0.5.2", - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -2006,7 +2012,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -3226,6 +3232,12 @@ version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + [[package]] name = "hybrid-array" version = "0.4.14" @@ -3249,6 +3261,7 @@ dependencies = [ "http", "http-body", "httparse", + "httpdate", "itoa", "pin-project-lite", "smallvec", @@ -4206,7 +4219,7 @@ checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8" [[package]] name = "nostr" version = "0.45.0-alpha.8" -source = "git+https://github.com/rust-nostr/nostr#83cb556fa59259eb30f3df63f153f42aab77519b" +source = "git+https://github.com/rust-nostr/nostr#d0a1d67d3c9e5cf9710807a6a414c155a5f47215" dependencies = [ "aes", "base64", @@ -4231,7 +4244,7 @@ dependencies = [ [[package]] name = "nostr-blossom" version = "0.45.0-alpha.8" -source = "git+https://github.com/rust-nostr/nostr#83cb556fa59259eb30f3df63f153f42aab77519b" +source = "git+https://github.com/rust-nostr/nostr#d0a1d67d3c9e5cf9710807a6a414c155a5f47215" dependencies = [ "base64", "bitcoin_hashes", @@ -4241,10 +4254,29 @@ dependencies = [ "serde", ] +[[package]] +name = "nostr-browser-signer-proxy" +version = "0.45.0-alpha.8" +source = "git+https://github.com/rust-nostr/nostr#d0a1d67d3c9e5cf9710807a6a414c155a5f47215" +dependencies = [ + "atomic-destructor", + "bytes", + "http-body-util", + "hyper", + "hyper-util", + "nostr", + "opaquerr", + "serde", + "serde_json", + "tokio", + "tracing", + "uuid", +] + [[package]] name = "nostr-connect" version = "0.45.0-alpha.8" -source = "git+https://github.com/rust-nostr/nostr#83cb556fa59259eb30f3df63f153f42aab77519b" +source = "git+https://github.com/rust-nostr/nostr#d0a1d67d3c9e5cf9710807a6a414c155a5f47215" dependencies = [ "async-utility", "futures-core", @@ -4258,7 +4290,7 @@ dependencies = [ [[package]] name = "nostr-database" version = "0.45.0-alpha.8" -source = "git+https://github.com/rust-nostr/nostr#83cb556fa59259eb30f3df63f153f42aab77519b" +source = "git+https://github.com/rust-nostr/nostr#d0a1d67d3c9e5cf9710807a6a414c155a5f47215" dependencies = [ "btreecap", "flatbuffers", @@ -4269,7 +4301,7 @@ dependencies = [ [[package]] name = "nostr-gossip" version = "0.45.0-alpha.8" -source = "git+https://github.com/rust-nostr/nostr#83cb556fa59259eb30f3df63f153f42aab77519b" +source = "git+https://github.com/rust-nostr/nostr#d0a1d67d3c9e5cf9710807a6a414c155a5f47215" dependencies = [ "nostr", "opaquerr", @@ -4278,7 +4310,7 @@ dependencies = [ [[package]] name = "nostr-gossip-memory" version = "0.45.0-alpha.8" -source = "git+https://github.com/rust-nostr/nostr#83cb556fa59259eb30f3df63f153f42aab77519b" +source = "git+https://github.com/rust-nostr/nostr#d0a1d67d3c9e5cf9710807a6a414c155a5f47215" dependencies = [ "indexmap", "lru", @@ -4290,7 +4322,7 @@ dependencies = [ [[package]] name = "nostr-lmdb" version = "0.45.0-alpha.8" -source = "git+https://github.com/rust-nostr/nostr#83cb556fa59259eb30f3df63f153f42aab77519b" +source = "git+https://github.com/rust-nostr/nostr#d0a1d67d3c9e5cf9710807a6a414c155a5f47215" dependencies = [ "async-utility", "flume 0.12.0", @@ -4304,7 +4336,7 @@ dependencies = [ [[package]] name = "nostr-memory" version = "0.45.0-alpha.8" -source = "git+https://github.com/rust-nostr/nostr#83cb556fa59259eb30f3df63f153f42aab77519b" +source = "git+https://github.com/rust-nostr/nostr#d0a1d67d3c9e5cf9710807a6a414c155a5f47215" dependencies = [ "btreecap", "nostr", @@ -4315,7 +4347,7 @@ dependencies = [ [[package]] name = "nostr-sdk" version = "0.45.0-alpha.8" -source = "git+https://github.com/rust-nostr/nostr#83cb556fa59259eb30f3df63f153f42aab77519b" +source = "git+https://github.com/rust-nostr/nostr#d0a1d67d3c9e5cf9710807a6a414c155a5f47215" dependencies = [ "async-utility", "async-wsocket", @@ -4363,7 +4395,7 @@ version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -5437,7 +5469,7 @@ dependencies = [ "once_cell", "socket2", "tracing", - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -5984,7 +6016,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys 0.12.1", - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -6692,6 +6724,7 @@ dependencies = [ "mime_guess", "nostr", "nostr-blossom", + "nostr-browser-signer-proxy", "nostr-connect", "nostr-gossip-memory", "nostr-lmdb", @@ -7015,7 +7048,7 @@ dependencies = [ "getrandom 0.4.3", "once_cell", "rustix 1.1.4", - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -8347,7 +8380,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.48.0", ] [[package]] @@ -9010,6 +9043,7 @@ dependencies = [ "gpui", "instant", "log", + "nostr-browser-signer-proxy", "nostr-connect", "nostr-sdk", "person", diff --git a/Cargo.toml b/Cargo.toml index 6d6016a..c9448bf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,7 @@ nostr-memory = { 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-connect = { git = "https://github.com/rust-nostr/nostr" } +nostr-browser-signer-proxy = { 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" ] } diff --git a/crates/state/Cargo.toml b/crates/state/Cargo.toml index 273dbe2..3721ce3 100644 --- a/crates/state/Cargo.toml +++ b/crates/state/Cargo.toml @@ -12,6 +12,7 @@ nostr-sdk.workspace = true nostr-gossip-memory.workspace = true nostr-blossom.workspace = true nostr-connect.workspace = true +nostr-browser-signer-proxy.workspace = true gpui.workspace = true instant.workspace = true diff --git a/crates/state/src/lib.rs b/crates/state/src/lib.rs index 210356a..4f7d5f6 100644 --- a/crates/state/src/lib.rs +++ b/crates/state/src/lib.rs @@ -3,7 +3,9 @@ use std::collections::HashMap; use anyhow::{Error, anyhow}; use common::config_dir; use gpui::{App, AppContext, Context, Entity, EventEmitter, Global, Task, Window}; +use gpui_tokio::Tokio; use instant::Duration; +use nostr_browser_signer_proxy::prelude::*; use nostr_connect::prelude::*; use nostr_gossip_memory::prelude::*; #[cfg(not(target_arch = "wasm32"))] @@ -307,6 +309,50 @@ impl NostrRegistry { }) } + /// Start the browser proxy + pub fn connect_proxy(&mut self, cx: &mut Context) { + let proxy = BrowserSignerProxy::new(BrowserSignerProxyOptions::default()); + let (tx, rx) = flume::bounded::(1); + + self.tasks.push(Tokio::spawn_result(cx, { + let proxy = proxy.clone(); + async move { + // Start the proxy and get the web url + proxy.start().await?; + // Notify GPUI + let url = proxy.url(); + tx.send(url).ok(); + Ok(()) + } + })); + + self.tasks.push(Tokio::spawn_result(cx, { + let proxy = proxy.clone(); + async move { + loop { + if proxy.is_session_active() { + break; + } + smol::Timer::after(Duration::from_secs(1)).await; + } + Ok(()) + } + })); + + self.tasks.push(cx.spawn({ + let proxy = proxy.clone(); + async move |this, cx| { + while let Ok(url) = rx.recv_async().await { + this.update(cx, |this, cx| { + cx.open_url(&url); + this.set_signer(proxy.clone(), cx); + })?; + } + Ok(()) + } + })); + } + /// Get the public key of a NIP-05 address pub fn query_address(&self, addr: Nip05Address, cx: &App) -> Task> { let client = self.client(); diff --git a/crates/ui/src/styled.rs b/crates/ui/src/styled.rs index 45d04b6..92c4246 100644 --- a/crates/ui/src/styled.rs +++ b/crates/ui/src/styled.rs @@ -14,7 +14,7 @@ pub fn v_flex() -> Div { /// Returns a `Div` as divider. pub fn divider(cx: &App) -> Div { - div().my_2().w_full().h_px().bg(cx.theme().border_variant) + div().my_1().w_full().h_px().bg(cx.theme().border_variant) } macro_rules! font_weight { diff --git a/crates/workspace/Cargo.toml b/crates/workspace/Cargo.toml index 61bb5c6..55f00db 100644 --- a/crates/workspace/Cargo.toml +++ b/crates/workspace/Cargo.toml @@ -19,6 +19,7 @@ gpui.workspace = true nostr-sdk.workspace = true instant.workspace = true nostr-connect.workspace = true +nostr-browser-signer-proxy.workspace = true anyhow.workspace = true serde.workspace = true diff --git a/crates/workspace/src/dialogs/import.rs b/crates/workspace/src/dialogs/import.rs index 06c64e2..b6fcb24 100644 --- a/crates/workspace/src/dialogs/import.rs +++ b/crates/workspace/src/dialogs/import.rs @@ -10,7 +10,7 @@ use state::{CoopAuthUrlHandler, NostrRegistry, USER_KEYRING}; use theme::ActiveTheme; use ui::button::{Button, ButtonVariants}; use ui::input::{Input, InputEvent, InputState}; -use ui::{Disableable, StyledExt, WindowExtension, v_flex}; +use ui::{Disableable, StyledExt, WindowExtension, divider, v_flex}; #[derive(Debug)] pub struct ImportIdentity { @@ -164,6 +164,13 @@ impl ImportIdentity { })); } + fn proxy(&mut self, cx: &mut Context) { + let nostr = NostrRegistry::global(cx); + nostr.update(cx, |this, cx| { + this.connect_proxy(cx); + }); + } + fn set_loading(&mut self, status: bool, cx: &mut Context) { self.loading = status; cx.notify(); @@ -199,10 +206,12 @@ impl ImportIdentity { impl Render for ImportIdentity { fn render(&mut self, _window: &mut gpui::Window, cx: &mut Context) -> impl IntoElement { - const MSG: &str = "Coop won't store your identity key on the local device. You need to re-login again in the next session. You can use Nostr Connect for persistent login."; + const BUNKER_WARN: &str = "Nostr Connect will usually take more time to get all your messages. Please keep your session open until you see all your messages."; + const KEY_WARN: &str = "Coop won't store your identity key on the local device. You need to re-login again in the next session. You can use Nostr Connect for persistent login."; let require_password = self.key_input.read(cx).value().starts_with("ncryptsec1"); let key_warning = self.key_input.read(cx).value().starts_with("nsec1") || require_password; + let bunker_warning = self.key_input.read(cx).value().starts_with("bunker://"); v_flex() .size_full() @@ -227,13 +236,20 @@ impl Render for ImportIdentity { .child(Input::new(&self.pass_input)), ) }) + .when(bunker_warning, |this| { + this.child( + div() + .text_xs() + .text_color(cx.theme().text_warning) + .child(div().child(BUNKER_WARN)), + ) + }) .when(key_warning, |this| { this.child( div() .text_xs() .text_color(cx.theme().text_warning) - .child(div().font_semibold().child("Warning")) - .child(div().child(MSG)), + .child(div().child(KEY_WARN)), ) }), ) @@ -248,6 +264,17 @@ impl Render for ImportIdentity { this.login(window, cx); })), ) + .child(divider(cx)) + .child( + Button::new("proxy") + .label("Connect via Web Extension (Experimental)") + .ghost_alt() + .loading(self.loading) + .disabled(self.loading) + .on_click(cx.listener(move |this, _ev, _window, cx| { + this.proxy(cx); + })), + ) .when_some(self.error.read(cx).as_ref(), |this, error| { this.child( div()