wip
Some checks failed
Rust / build (ubuntu-latest, stable) (push) Failing after 1m27s
Rust / build (ubuntu-latest, stable) (pull_request) Failing after 1m33s
Some checks failed
Rust / build (ubuntu-latest, stable) (push) Failing after 1m27s
Rust / build (ubuntu-latest, stable) (pull_request) Failing after 1m33s
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
use std::collections::HashSet;
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
use std::time::Duration;
|
||||
|
||||
use anyhow::Error;
|
||||
use anyhow::{anyhow, Error};
|
||||
use common::{config_dir, BOOTSTRAP_RELAYS, CLIENT_NAME, SEARCH_RELAYS};
|
||||
use gpui::{App, AppContext, Context, Entity, Global, Subscription, Task};
|
||||
use nostr_connect::prelude::*;
|
||||
@@ -173,6 +174,14 @@ impl NostrRegistry {
|
||||
}),
|
||||
);
|
||||
|
||||
cx.defer(|cx| {
|
||||
let nostr = NostrRegistry::global(cx);
|
||||
|
||||
nostr.update(cx, |this, cx| {
|
||||
this.get_identity(cx);
|
||||
});
|
||||
});
|
||||
|
||||
Self {
|
||||
client,
|
||||
app_keys,
|
||||
@@ -305,9 +314,15 @@ impl NostrRegistry {
|
||||
let keys = Keys::generate();
|
||||
let secret_key = keys.secret_key();
|
||||
|
||||
// Create directory and write secret key
|
||||
std::fs::create_dir_all(dir.parent().unwrap())?;
|
||||
std::fs::write(&dir, secret_key.to_secret_bytes())?;
|
||||
|
||||
// Set permissions to readonly
|
||||
let mut perms = std::fs::metadata(&dir)?.permissions();
|
||||
perms.set_mode(0o400);
|
||||
std::fs::set_permissions(&dir, perms)?;
|
||||
|
||||
return Ok(keys);
|
||||
}
|
||||
};
|
||||
@@ -390,7 +405,7 @@ impl NostrRegistry {
|
||||
}
|
||||
|
||||
/// Set the signer for the nostr client and verify the public key
|
||||
pub fn set_signer<T>(&mut self, signer: T, cx: &mut Context<Self>)
|
||||
pub fn set_signer<T>(&mut self, signer: T, owned: bool, cx: &mut Context<Self>)
|
||||
where
|
||||
T: NostrSigner + 'static,
|
||||
{
|
||||
@@ -414,6 +429,7 @@ impl NostrRegistry {
|
||||
Ok(public_key) => {
|
||||
identity.update(cx, |this, cx| {
|
||||
this.set_public_key(public_key);
|
||||
this.set_owned(owned);
|
||||
cx.notify();
|
||||
})?;
|
||||
}
|
||||
@@ -598,8 +614,102 @@ impl NostrRegistry {
|
||||
}));
|
||||
}
|
||||
|
||||
/// Store a connection for future uses
|
||||
pub fn persit_connection(&mut self, uri: NostrConnectUri, cx: &mut App) {
|
||||
/// Get local stored identity
|
||||
fn get_identity(&mut self, cx: &mut Context<Self>) {
|
||||
let read_credential = cx.read_credentials(CLIENT_NAME);
|
||||
|
||||
self.tasks.push(cx.spawn(async move |this, cx| {
|
||||
match read_credential.await {
|
||||
Ok(Some((_, secret))) => {
|
||||
let secret = SecretKey::from_slice(&secret)?;
|
||||
let keys = Keys::new(secret);
|
||||
|
||||
this.update(cx, |this, cx| {
|
||||
this.set_signer(keys, false, cx);
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
_ => {
|
||||
this.update(cx, |this, cx| {
|
||||
this.get_bunker(cx);
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}));
|
||||
}
|
||||
|
||||
/// Create a new identity
|
||||
fn create_identity(&mut self, cx: &mut Context<Self>) {
|
||||
let keys = Keys::generate();
|
||||
let write_credential = cx.write_credentials(
|
||||
CLIENT_NAME,
|
||||
&keys.public_key().to_hex(),
|
||||
&keys.secret_key().to_secret_bytes(),
|
||||
);
|
||||
|
||||
// Update the signer
|
||||
self.set_signer(keys, false, cx);
|
||||
|
||||
// Spawn a task to write the credentials
|
||||
cx.background_spawn(async move {
|
||||
if let Err(e) = write_credential.await {
|
||||
log::error!("Failed to write credentials: {}", e);
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
|
||||
/// Get local stored bunker connection
|
||||
fn get_bunker(&mut self, cx: &mut Context<Self>) {
|
||||
let client = self.client();
|
||||
let app_keys = self.app_keys().clone();
|
||||
let timeout = Duration::from_secs(NOSTR_CONNECT_TIMEOUT);
|
||||
|
||||
let task: Task<Result<NostrConnect, Error>> = cx.background_spawn(async move {
|
||||
log::info!("Getting bunker connection");
|
||||
|
||||
let filter = Filter::new()
|
||||
.kind(Kind::ApplicationSpecificData)
|
||||
.identifier("coop:account")
|
||||
.limit(1);
|
||||
|
||||
if let Some(event) = client.database().query(filter).await?.first_owned() {
|
||||
let uri = NostrConnectUri::parse(event.content)?;
|
||||
let signer = NostrConnect::new(uri.clone(), app_keys.clone(), timeout, None)?;
|
||||
|
||||
Ok(signer)
|
||||
} else {
|
||||
Err(anyhow!("No account found"))
|
||||
}
|
||||
});
|
||||
|
||||
self.tasks.push(cx.spawn(async move |this, cx| {
|
||||
match task.await {
|
||||
Ok(signer) => {
|
||||
this.update(cx, |this, cx| {
|
||||
this.set_signer(signer, true, cx);
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
Err(e) => {
|
||||
log::warn!("Failed to get bunker: {e}");
|
||||
// Create a new identity if no stored bunker exists
|
||||
this.update(cx, |this, cx| {
|
||||
this.create_identity(cx);
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}));
|
||||
}
|
||||
|
||||
/// Store the bunker connection for the next login
|
||||
pub fn persist_bunker(&mut self, uri: NostrConnectUri, cx: &mut App) {
|
||||
let client = self.client();
|
||||
let rng_keys = Keys::generate();
|
||||
|
||||
@@ -632,7 +742,10 @@ impl NostrRegistry {
|
||||
let uri = NostrConnectUri::client(app_keys.public_key(), vec![relay], CLIENT_NAME);
|
||||
|
||||
// Generate the nostr connect
|
||||
let signer = NostrConnect::new(uri.clone(), app_keys.clone(), timeout, None).unwrap();
|
||||
let mut signer = NostrConnect::new(uri.clone(), app_keys.clone(), timeout, None).unwrap();
|
||||
|
||||
// Handle the auth request
|
||||
signer.auth_url_handler(CoopAuthUrlHandler);
|
||||
|
||||
(signer, uri)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user