feat: add auth screens

This commit is contained in:
reya
2024-07-25 10:59:36 +07:00
parent d206f1d2aa
commit 005cbeab72
12 changed files with 571 additions and 69 deletions

View File

@@ -1,9 +1,8 @@
use itertools::Itertools;
use keyring::Entry;
use keyring_search::{Limit, List, Search};
use nostr_sdk::prelude::*;
use serde::Serialize;
use std::collections::HashSet;
use std::{collections::HashSet, time::Duration};
use tauri::{Emitter, Manager, State};
use crate::Nostr;
@@ -28,7 +27,7 @@ pub fn get_accounts() -> Vec<String> {
#[tauri::command]
#[specta::specta]
pub async fn get_profile(id: String, state: State<'_, Nostr>) -> Result<String, String> {
pub async fn get_metadata(id: String, state: State<'_, Nostr>) -> Result<String, String> {
let client = &state.client;
let public_key = PublicKey::parse(&id).map_err(|e| e.to_string())?;
let filter = Filter::new().author(public_key).kind(Kind::Metadata).limit(1);
@@ -45,10 +44,108 @@ pub async fn get_profile(id: String, state: State<'_, Nostr>) -> Result<String,
}
}
#[tauri::command]
#[specta::specta]
pub async fn create_account(
name: String,
picture: String,
state: State<'_, Nostr>,
) -> Result<(), String> {
let client = &state.client;
let keys = Keys::generate();
let npub = keys.public_key().to_bech32().map_err(|e| e.to_string())?;
let nsec = keys.secret_key().unwrap().to_bech32().map_err(|e| e.to_string())?;
// Save account
let keyring = Entry::new(&npub, "nostr_secret").unwrap();
let _ = keyring.set_password(&nsec);
let signer = NostrSigner::Keys(keys);
// Update signer
client.set_signer(Some(signer)).await;
// Update metadata
let url = Url::parse(&picture).map_err(|e| e.to_string())?;
let metadata = Metadata::new().display_name(name).picture(url);
match client.set_metadata(&metadata).await {
Ok(_) => Ok(()),
Err(e) => Err(e.to_string()),
}
}
#[tauri::command]
#[specta::specta]
pub async fn import_key(
nsec: &str,
password: &str,
state: State<'_, Nostr>,
) -> Result<String, String> {
let secret_key = if nsec.starts_with("ncryptsec") {
let encrypted_key = EncryptedSecretKey::from_bech32(nsec).unwrap();
encrypted_key.to_secret_key(password).map_err(|err| err.to_string())
} else {
SecretKey::from_bech32(nsec).map_err(|err| err.to_string())
};
match secret_key {
Ok(val) => {
let nostr_keys = Keys::new(val);
let npub = nostr_keys.public_key().to_bech32().unwrap();
let nsec = nostr_keys.secret_key().unwrap().to_bech32().unwrap();
let keyring = Entry::new(&npub, "nostr_secret").unwrap();
let _ = keyring.set_password(&nsec);
let signer = NostrSigner::Keys(nostr_keys);
let client = &state.client;
// Update client's signer
client.set_signer(Some(signer)).await;
Ok(npub)
}
Err(msg) => Err(msg),
}
}
#[tauri::command]
#[specta::specta]
pub async fn connect_account(uri: &str, state: State<'_, Nostr>) -> Result<String, String> {
let client = &state.client;
match NostrConnectURI::parse(uri) {
Ok(bunker_uri) => {
let app_keys = Keys::generate();
let app_secret = app_keys.secret_key().unwrap().to_string();
// Get remote user
let remote_user = bunker_uri.signer_public_key().unwrap();
let remote_npub = remote_user.to_bech32().unwrap();
match Nip46Signer::new(bunker_uri, app_keys, Duration::from_secs(120), None).await {
Ok(signer) => {
let keyring = Entry::new(&remote_npub, "nostr_secret").unwrap();
let _ = keyring.set_password(&app_secret);
// Update signer
let _ = client.set_signer(Some(signer.into())).await;
Ok(remote_npub)
}
Err(err) => Err(err.to_string()),
}
}
Err(err) => Err(err.to_string()),
}
}
#[tauri::command]
#[specta::specta]
pub async fn login(
id: String,
bunker: Option<String>,
state: State<'_, Nostr>,
handle: tauri::AppHandle,
) -> Result<String, String> {
@@ -61,12 +158,33 @@ pub async fn login(
Err(_) => return Err("Cancelled".into()),
};
let keys = Keys::parse(password).expect("Secret Key is modified, please check again.");
let signer = NostrSigner::Keys(keys);
match bunker {
Some(uri) => {
let app_keys =
Keys::parse(password).expect("Secret Key is modified, please check again.");
// Set signer
client.set_signer(Some(signer)).await;
match NostrConnectURI::parse(uri) {
Ok(bunker_uri) => {
match Nip46Signer::new(bunker_uri, app_keys, Duration::from_secs(30), None)
.await
{
Ok(signer) => client.set_signer(Some(signer.into())).await,
Err(err) => return Err(err.to_string()),
}
}
Err(err) => return Err(err.to_string()),
}
}
None => {
let keys = Keys::parse(password).expect("Secret Key is modified, please check again.");
let signer = NostrSigner::Keys(keys);
// Update signer
client.set_signer(Some(signer)).await;
}
}
let hex = public_key.to_hex();
let inbox = Filter::new().kind(Kind::Custom(10050)).author(public_key).limit(1);
if let Ok(events) = client.get_events_of(vec![inbox], None).await {
@@ -92,33 +210,11 @@ pub async fn login(
let state = window.state::<Nostr>();
let client = &state.client;
let old = Filter::new().kind(Kind::GiftWrap).pubkey(public_key).until(Timestamp::now());
let old = Filter::new().kind(Kind::GiftWrap).pubkey(public_key);
let new = Filter::new().kind(Kind::GiftWrap).pubkey(public_key).limit(0);
if let Ok(report) = client.reconcile(old, NegentropyOptions::default()).await {
let receives = report.received.clone();
let ids = receives.into_iter().collect::<Vec<_>>();
if let Ok(events) =
client.database().query(vec![Filter::new().ids(ids)], Order::Desc).await
{
let pubkeys = events
.into_iter()
.unique_by(|ev| ev.pubkey)
.map(|ev| ev.pubkey)
.collect::<Vec<_>>();
if client
.reconcile(
Filter::new().kind(Kind::GiftWrap).pubkeys(pubkeys),
NegentropyOptions::default(),
)
.await
.is_ok()
{
println!("Sync done.")
}
}
if client.reconcile(old, NegentropyOptions::default()).await.is_ok() {
println!("Sync done.")
};
if client.subscribe(vec![new], None).await.is_ok() {
@@ -169,7 +265,5 @@ pub async fn login(
.await
});
let hex = public_key.to_hex();
Ok(hex)
}

View File

@@ -8,13 +8,7 @@ use std::{fs, sync::Mutex, time::Duration};
use tauri::Manager;
use tauri_plugin_decorum::WebviewWindowExt;
use commands::{
account::{get_accounts, get_profile, login},
chat::{
drop_inbox, get_chat_messages, get_chats, get_inboxes, send_message, subscribe_to,
unsubscribe,
},
};
use commands::{account::*, chat::*};
mod commands;
mod common;
@@ -30,8 +24,11 @@ fn main() {
let invoke_handler = {
let builder = tauri_specta::ts::builder().commands(tauri_specta::collect_commands![
login,
create_account,
import_key,
connect_account,
get_accounts,
get_profile,
get_metadata,
get_inboxes,
get_chats,
get_chat_messages,