This commit is contained in:
2026-02-26 15:09:27 +07:00
parent ff5ae8280c
commit e152154c3b
6 changed files with 127 additions and 54 deletions

View File

@@ -350,26 +350,23 @@ impl Room {
)); ));
} }
// Construct filters for inbox and announcement // Construct filters for inbox
let inbox_filter = Filter::new() let inbox = Filter::new()
.kind(Kind::InboxRelays) .kind(Kind::InboxRelays)
.author(member) .author(member)
.limit(1); .limit(1);
let announcement_filter = Filter::new()
// Construct filters for announcement
let announcement = Filter::new()
.kind(Kind::Custom(10044)) .kind(Kind::Custom(10044))
.author(member) .author(member)
.limit(1); .limit(1);
// Create subscription targets // Create subscription targets
let target = urls let target: HashMap<RelayUrl, Vec<Filter>> = urls
.into_iter() .into_iter()
.map(|relay| { .map(|relay| (relay, vec![inbox.clone(), announcement.clone()]))
( .collect();
relay,
vec![inbox_filter.clone(), announcement_filter.clone()],
)
})
.collect::<HashMap<_, _>>();
// Stream events from user's write relays // Stream events from user's write relays
let mut stream = client let mut stream = client

View File

@@ -36,6 +36,9 @@ pub struct EncryptionPanel {
/// Whether the panel is loading /// Whether the panel is loading
loading: bool, loading: bool,
/// Whether the encryption is resetting
resetting: bool,
/// Tasks /// Tasks
tasks: Vec<Task<Result<(), Error>>>, tasks: Vec<Task<Result<(), Error>>>,
} }
@@ -47,6 +50,7 @@ impl EncryptionPanel {
focus_handle: cx.focus_handle(), focus_handle: cx.focus_handle(),
public_key, public_key,
loading: false, loading: false,
resetting: false,
tasks: vec![], tasks: vec![],
} }
} }
@@ -91,6 +95,42 @@ impl EncryptionPanel {
})); }));
} }
fn set_resetting(&mut self, status: bool, cx: &mut Context<Self>) {
self.resetting = status;
cx.notify();
}
fn reset(&mut self, window: &mut Window, cx: &mut Context<Self>) {
let device = DeviceRegistry::global(cx);
let task = device.read(cx).create_encryption(cx);
// Update the reset status
self.set_resetting(true, cx);
self.tasks.push(cx.spawn_in(window, async move |this, cx| {
match task.await {
Ok(keys) => {
this.update_in(cx, |this, _window, cx| {
this.set_resetting(false, cx);
device.update(cx, |this, cx| {
this.set_signer(keys, cx);
this.listen_request(cx);
});
})?;
}
Err(e) => {
this.update_in(cx, |this, window, cx| {
this.set_resetting(false, cx);
window.push_notification(Notification::error(e.to_string()), cx);
})?;
}
}
Ok(())
}));
}
fn render_requests(&mut self, cx: &mut Context<Self>) -> Vec<impl IntoElement> { fn render_requests(&mut self, cx: &mut Context<Self>) -> Vec<impl IntoElement> {
const TITLE: &str = "You've requested for the Encryption Key from:"; const TITLE: &str = "You've requested for the Encryption Key from:";
@@ -269,8 +309,7 @@ impl Render for EncryptionPanel {
)), )),
) )
}) })
.when(state.set(), |this| { .child(
this.child(
v_flex() v_flex()
.gap_1() .gap_1()
.child( .child(
@@ -279,7 +318,10 @@ impl Render for EncryptionPanel {
.label("Reset") .label("Reset")
.warning() .warning()
.small() .small()
.font_semibold(), .font_semibold()
.on_click(
cx.listener(move |this, _ev, window, cx| this.reset(window, cx)),
),
) )
.child( .child(
div() div()
@@ -289,6 +331,5 @@ impl Render for EncryptionPanel {
.child(SharedString::from(NOTICE)), .child(SharedString::from(NOTICE)),
), ),
) )
})
} }
} }

View File

@@ -2,6 +2,7 @@ use std::sync::Arc;
use ::settings::AppSettings; use ::settings::AppSettings;
use chat::{ChatEvent, ChatRegistry, InboxState}; use chat::{ChatEvent, ChatRegistry, InboxState};
use device::DeviceRegistry;
use gpui::prelude::FluentBuilder; use gpui::prelude::FluentBuilder;
use gpui::{ use gpui::{
div, px, rems, Action, App, AppContext, Axis, Context, Entity, InteractiveElement, IntoElement, div, px, rems, Action, App, AppContext, Axis, Context, Entity, InteractiveElement, IntoElement,
@@ -36,6 +37,7 @@ enum Command {
RefreshRelayList, RefreshRelayList,
RefreshMessagingRelays, RefreshMessagingRelays,
RefreshEncryption,
ShowRelayList, ShowRelayList,
ShowMessaging, ShowMessaging,
@@ -260,6 +262,12 @@ impl Workspace {
); );
}); });
} }
Command::RefreshEncryption => {
let device = DeviceRegistry::global(cx);
device.update(cx, |this, cx| {
this.get_announcement(cx);
});
}
Command::RefreshRelayList => { Command::RefreshRelayList => {
let nostr = NostrRegistry::global(cx); let nostr = NostrRegistry::global(cx);
nostr.update(cx, |this, cx| { nostr.update(cx, |this, cx| {
@@ -440,8 +448,19 @@ impl Workspace {
.tooltip("Decoupled encryption key") .tooltip("Decoupled encryption key")
.small() .small()
.ghost() .ghost()
.on_click(|_ev, window, cx| { .dropdown_menu(|this, _window, _cx| {
window.dispatch_action(Box::new(Command::ShowEncryption), cx); this.min_w(px(260.))
.label("Encryption")
.menu_with_icon(
"Reload",
IconName::Refresh,
Box::new(Command::RefreshEncryption),
)
.menu_with_icon(
"View encryption",
IconName::Settings,
Box::new(Command::ShowEncryption),
)
}), }),
) )
.child( .child(

View File

@@ -157,7 +157,7 @@ impl DeviceRegistry {
} }
/// Set the decoupled encryption key for the current user /// Set the decoupled encryption key for the current user
fn set_signer<S>(&mut self, new: S, cx: &mut Context<Self>) pub fn set_signer<S>(&mut self, new: S, cx: &mut Context<Self>)
where where
S: NostrSigner + 'static, S: NostrSigner + 'static,
{ {
@@ -248,7 +248,7 @@ impl DeviceRegistry {
} }
/// Get device announcement for current user /// Get device announcement for current user
fn get_announcement(&mut self, cx: &mut Context<Self>) { pub fn get_announcement(&mut self, cx: &mut Context<Self>) {
let nostr = NostrRegistry::global(cx); let nostr = NostrRegistry::global(cx);
let client = nostr.read(cx).client(); let client = nostr.read(cx).client();
@@ -309,8 +309,7 @@ impl DeviceRegistry {
})); }));
} }
/// Create a new device signer and announce it pub fn create_encryption(&self, cx: &App) -> Task<Result<Keys, Error>> {
fn announce(&mut self, cx: &mut Context<Self>) {
let nostr = NostrRegistry::global(cx); let nostr = NostrRegistry::global(cx);
let client = nostr.read(cx).client(); let client = nostr.read(cx).client();
@@ -325,7 +324,7 @@ impl DeviceRegistry {
let secret = keys.secret_key().to_secret_hex(); let secret = keys.secret_key().to_secret_hex();
let n = keys.public_key(); let n = keys.public_key();
let task: Task<Result<(), Error>> = cx.background_spawn(async move { cx.background_spawn(async move {
let urls = write_relays.await; let urls = write_relays.await;
// Construct an announcement event // Construct an announcement event
@@ -342,17 +341,26 @@ impl DeviceRegistry {
// Save device keys to the database // Save device keys to the database
set_keys(&client, &secret).await?; set_keys(&client, &secret).await?;
Ok(()) Ok(keys)
}); })
}
/// Create a new device signer and announce it
fn announce(&mut self, cx: &mut Context<Self>) {
let task = self.create_encryption(cx);
self.tasks.push(cx.spawn(async move |this, cx| { self.tasks.push(cx.spawn(async move |this, cx| {
if task.await.is_ok() { match task.await {
Ok(keys) => {
this.update(cx, |this, cx| { this.update(cx, |this, cx| {
this.set_signer(keys, cx); this.set_signer(keys, cx);
this.listen_request(cx); this.listen_request(cx);
})?; })?;
} }
Err(e) => {
log::error!("Failed to create encryption key: {}", e);
}
}
Ok(()) Ok(())
})); }));
} }
@@ -401,7 +409,7 @@ impl DeviceRegistry {
} }
/// Listen for device key requests on user's write relays /// Listen for device key requests on user's write relays
fn listen_request(&mut self, cx: &mut Context<Self>) { pub fn listen_request(&mut self, cx: &mut Context<Self>) {
let nostr = NostrRegistry::global(cx); let nostr = NostrRegistry::global(cx);
let client = nostr.read(cx).client(); let client = nostr.read(cx).client();
@@ -671,6 +679,8 @@ async fn get_keys(client: &Client) -> Result<Keys, Error> {
let secret = SecretKey::parse(&content)?; let secret = SecretKey::parse(&content)?;
let keys = Keys::new(secret); let keys = Keys::new(secret);
log::info!("Encryption keys retrieved successfully");
Ok(keys) Ok(keys)
} else { } else {
Err(anyhow!("Key not found")) Err(anyhow!("Key not found"))

View File

@@ -198,7 +198,7 @@ impl PersonRegistry {
loop { loop {
match flume::Selector::new() match flume::Selector::new()
.recv(rx, |result| result.ok()) .recv(rx, |result| result.ok())
.wait_timeout(Duration::from_secs(2)) .wait_timeout(Duration::from_secs(TIMEOUT))
{ {
Ok(Some(public_key)) => { Ok(Some(public_key)) => {
batch.insert(public_key); batch.insert(public_key);
@@ -307,16 +307,22 @@ where
.timeout(Some(Duration::from_secs(TIMEOUT))); .timeout(Some(Duration::from_secs(TIMEOUT)));
// Construct the filter for metadata // Construct the filter for metadata
let filter = Filter::new() let metadata = Filter::new()
.kind(Kind::Metadata) .kind(Kind::Metadata)
.authors(authors.clone())
.limit(limit);
// Construct the filter for relay list
let gossip = Filter::new()
.kind(Kind::RelayList)
.authors(authors) .authors(authors)
.limit(limit); .limit(limit);
// Construct target for subscription // Construct target for subscription
let target = BOOTSTRAP_RELAYS let target: HashMap<&str, Vec<Filter>> = BOOTSTRAP_RELAYS
.into_iter() .into_iter()
.map(|relay| (relay, vec![filter.clone()])) .map(|relay| (relay, vec![metadata.clone(), gossip.clone()]))
.collect::<HashMap<_, _>>(); .collect();
client.subscribe(target).close_on(opts).await?; client.subscribe(target).close_on(opts).await?;

View File

@@ -13,7 +13,7 @@ pub const APP_ID: &str = "su.reya.coop";
pub const KEYRING: &str = "Coop Safe Storage"; pub const KEYRING: &str = "Coop Safe Storage";
/// Default timeout for subscription /// Default timeout for subscription
pub const TIMEOUT: u64 = 3; pub const TIMEOUT: u64 = 2;
/// Default delay for searching /// Default delay for searching
pub const FIND_DELAY: u64 = 600; pub const FIND_DELAY: u64 = 600;