wip
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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)),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -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"))
|
||||||
|
|||||||
@@ -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?;
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user