From f79014235e85554e3661b3f2a02b8fa88bc192ff Mon Sep 17 00:00:00 2001 From: DanConwayDev Date: Thu, 21 Nov 2024 16:53:17 +0000 Subject: feat(login): overhaul login experience * simplify login menu, making it more accessable to newcomers and easier to select remote signer options * enable `ngit login` to work from anywhere (not just a git repo) * assume fresh login details saved to global git config but fallback to local repository * maintain local repository login via `ngit login --local` * maintain login via CLI arguments eg `ngit send --nsec nsec123` * nudge users to remember nsec when pasting in ncryptsec for a better UX, whilst maintaining the option to be prompted for password everytime * create placeholder menu items for help menu and create account --- src/lib/login/mod.rs | 883 ++++----------------------------------------------- 1 file changed, 56 insertions(+), 827 deletions(-) (limited to 'src/lib/login/mod.rs') diff --git a/src/lib/login/mod.rs b/src/lib/login/mod.rs index 0e00170..b45bc1d 100644 --- a/src/lib/login/mod.rs +++ b/src/lib/login/mod.rs @@ -1,129 +1,65 @@ -use std::{collections::HashSet, path::Path, str::FromStr, sync::Arc, time::Duration}; +use std::{path::Path, sync::Arc}; -use anyhow::{bail, Context, Result}; -use console::Style; -use dialoguer::theme::{ColorfulTheme, Theme}; -use nostr::{ - nips::{nip05, nip46::NostrConnectURI}, - PublicKey, -}; -use nostr_connect::client::NostrConnect; -use nostr_sdk::{ - Alphabet, FromBech32, JsonUtil, Keys, Kind, NostrSigner, SingleLetterTag, Timestamp, ToBech32, - Url, -}; -use qrcode::QrCode; -use tokio::sync::{oneshot, Mutex}; +use anyhow::Result; +use fresh::fresh_login_or_signup; +use nostr::PublicKey; +use nostr_sdk::{NostrSigner, Timestamp, ToBech32}; #[cfg(not(test))] use crate::client::Client; #[cfg(test)] use crate::client::MockConnect; -use crate::{ - cli_interactor::{ - Interactor, InteractorPrompt, Printer, PromptConfirmParms, PromptInputParms, - PromptPasswordParms, - }, - client::{fetch_public_key, get_event_from_global_cache, Connect}, - git::{Repo, RepoActions}, -}; +use crate::git::{Repo, RepoActions}; +pub mod existing; mod key_encryption; -use key_encryption::{decrypt_key, encrypt_key}; -mod user; -use user::{UserMetadata, UserRef, UserRelayRef, UserRelays}; - -/// handles the encrpytion and storage of key material -#[allow(clippy::too_many_arguments)] -pub async fn launch( - git_repo: &Repo, - bunker_uri: &Option, - bunker_app_key: &Option, - nsec: &Option, +use existing::load_existing_login; +pub mod user; +use user::UserRef; +pub mod fresh; + +pub async fn login_or_signup( + git_repo: &Option<&Repo>, + signer_info: &Option, password: &Option, #[cfg(test)] client: Option<&MockConnect>, #[cfg(not(test))] client: Option<&Client>, - change_user: bool, - silent: bool, -) -> Result<(Arc, UserRef)> { - if let Ok((signer, public_key)) = match get_signer_without_prompts( - git_repo, - bunker_uri, - bunker_app_key, - nsec, - password, - change_user, - ) - .await - { - Ok((signer, public_key)) => Ok((signer, public_key)), - Err(error) => { - if error - .to_string() - .eq("git config item nostr.nsec is an ncryptsec") - { - eprintln!( - "login as {}", - if let Ok(public_key) = PublicKey::from_bech32( - get_config_item(git_repo, "nostr.npub").unwrap_or("unknown".to_string()), - ) { - if let Ok(user_ref) = - get_user_details(&public_key, client, git_repo.get_path()?, silent) - .await - { - user_ref.metadata.name - } else { - "unknown ncryptsec".to_string() - } - } else { - "unknown ncryptsec".to_string() - } - ); - loop { - // prompt for password - let password = Interactor::default() - .password(PromptPasswordParms::default().with_prompt("password")) - .context("failed to get password input from interactor.password")?; - if let Ok(keys) = get_keys_with_password(git_repo, &password) { - break Ok((Arc::new(keys) as Arc, None)); - } - eprintln!("incorrect password"); - } - } else { - if nsec.is_some() { - bail!(error); - } - Err(error) - } - } - } { - let user_ref = get_user_details( - // Note: if rust-nostr NostrConnect::new() were updated to accept user public key as - // requested then the added complexity added in this commit can be undone - &(if let Some(public_key) = public_key { - public_key - } else { - signer - .get_public_key() - .await - .context("cannot get public key from signer")? - }), - client, - git_repo.get_path()?, - silent, - ) - .await?; - - if !silent { - print_logged_in_as(&user_ref, client.is_none())?; - } - Ok((signer, user_ref)) +) -> Result<(Arc, UserRef, SignerInfoSource)> { + let res = + load_existing_login(git_repo, signer_info, password, &None, client, false, true).await; + if res.is_ok() { + res } else { - fresh_login(git_repo, client, change_user).await + fresh_login_or_signup(git_repo, client, false).await } } -fn print_logged_in_as(user_ref: &UserRef, offline_mode: bool) -> Result<()> { +#[derive(Clone)] +pub enum SignerInfo { + Nsec { + nsec: String, + password: Option, + npub: Option, + }, + Bunker { + bunker_uri: String, + bunker_app_key: String, + npub: Option, + }, +} + +#[derive(PartialEq, Clone)] +pub enum SignerInfoSource { + GitLocal, + GitGlobal, + CommandLineArguments, +} + +fn print_logged_in_as( + user_ref: &UserRef, + offline_mode: bool, + source: &SignerInfoSource, +) -> Result<()> { if !offline_mode && user_ref.metadata.created_at.eq(&Timestamp::from(0)) { eprintln!("cannot find profile..."); } else if !offline_mode && user_ref.metadata.name.eq(&user_ref.public_key.to_bech32()?) { @@ -133,703 +69,21 @@ fn print_logged_in_as(user_ref: &UserRef, offline_mode: bool) -> Result<()> { "cannot find your relay list. consider using another nostr client to create one to enhance your nostr experience." ); } - eprintln!("logged in as {}", user_ref.metadata.name); - Ok(()) -} - -async fn get_signer_without_prompts( - git_repo: &Repo, - bunker_uri: &Option, - bunker_app_key: &Option, - nsec: &Option, - password: &Option, - save_local: bool, -) -> Result<(Arc, Option)> { - if let Some(nsec) = nsec { - Ok(( - Arc::new(get_keys_from_nsec(git_repo, nsec, password, save_local)?), - None, - )) - } else if let Some(password) = password { - Ok((Arc::new(get_keys_with_password(git_repo, password)?), None)) - } else if let Some(bunker_uri) = bunker_uri { - if let Some(bunker_app_key) = bunker_app_key { - let signer = get_nip46_signer_from_uri_and_key(bunker_uri, bunker_app_key) - .await - .context("failed to connect with remote signer")?; - if save_local { - save_to_git_config( - git_repo, - &signer.get_public_key().await?.to_bech32()?, - &None, - &Some((bunker_uri.to_string(),bunker_app_key.to_string())), - false, - ) - .context("failed to save bunker details local git config nostr.bunker-uri and nostr.bunker-app-key")?; - } - Ok((signer, None)) - } else { - bail!( - "bunker-app-key parameter must be provided alongside bunker-uri. if unknown, login interactively." - ) - } - } else if !save_local { - get_signer_with_git_config_nsec_or_bunker_without_prompts(git_repo).await - } else { - bail!("user wants prompts to specify new keys") - } -} - -fn get_keys_from_nsec( - git_repo: &Repo, - nsec: &String, - password: &Option, - save_local: bool, -) -> Result { - #[allow(unused_assignments)] - let mut s = String::new(); - let keys = if nsec.contains("ncryptsec") { - s = nsec.to_string(); - decrypt_key( - nsec, - password - .clone() - .context("password must be supplied when using ncryptsec as nsec parameter")? - .as_str(), - ) - .context("failed to decrypt key with provided password") - .context("failed to decrypt ncryptsec supplied as nsec with password")? - } else { - s = nsec.to_string(); - nostr::Keys::from_str(nsec).context("invalid nsec parameter")? - }; - if save_local { - if let Some(password) = password { - s = encrypt_key(&keys, password)?; - } - save_to_git_config( - git_repo, - &keys.public_key().to_bech32()?, - &Some(s), - &None, - false, - ) - .context("failed to save encrypted nsec in local git config nostr.nsec")?; - } - Ok(keys) -} - -fn save_to_git_config( - git_repo: &Repo, - npub: &str, - nsec: &Option, - bunker: &Option<(String, String)>, - global: bool, -) -> Result<()> { - if let Err(error) = silently_save_to_git_config(git_repo, npub, nsec, bunker, global) { - eprintln!( - "failed to save login details to {} git config", - if global { "global" } else { "local" } - ); - if let Some(nsec) = nsec { - if nsec.contains("ncryptsec") { - eprintln!("manually set git config nostr.nsec to: {nsec}"); - } else { - eprintln!("manually set git config nostr.nsec"); - } - } - if let Some(bunker) = bunker { - eprintln!("manually set git config as follows:"); - eprintln!("nostr.bunker-uri: {}", bunker.0); - eprintln!("nostr.bunker-app-key: {}", bunker.1); - } - Err(error) - } else { - eprintln!( - "saved login details to {} git config", - if global { "global" } else { "local" } - ); - Ok(()) - } -} -fn silently_save_to_git_config( - git_repo: &Repo, - npub: &str, - nsec: &Option, - bunker: &Option<(String, String)>, - global: bool, -) -> Result<()> { - // must do this first otherwise it might remove the global items just added - if global { - git_repo.remove_git_config_item("nostr.npub", false)?; - git_repo.remove_git_config_item("nostr.nsec", false)?; - git_repo.remove_git_config_item("nostr.bunker-uri", false)?; - git_repo.remove_git_config_item("nostr.bunker-app-key", false)?; - } - if let Some(bunker) = bunker { - git_repo.remove_git_config_item("nostr.nsec", global)?; - git_repo.save_git_config_item("nostr.bunker-uri", &bunker.0, global)?; - git_repo.save_git_config_item("nostr.bunker-app-key", &bunker.1, global)?; - } - if let Some(nsec) = nsec { - git_repo.save_git_config_item("nostr.nsec", nsec, global)?; - git_repo.remove_git_config_item("nostr.bunker-uri", global)?; - git_repo.remove_git_config_item("nostr.bunker-app-key", global)?; - } - git_repo.save_git_config_item("nostr.npub", npub, global) -} - -fn get_keys_with_password(git_repo: &Repo, password: &str) -> Result { - decrypt_key( - &git_repo - .get_git_config_item("nostr.nsec", None) - .context("failed get git config")? - .context("git config item nostr.nsec doesn't exist so cannot decrypt it")?, - password, - ) - .context("failed to decrypt stored nsec key with provided password") -} - -async fn get_nip46_signer_from_uri_and_key( - uri: &str, - app_key: &str, -) -> Result> { - let term = console::Term::stderr(); - term.write_line("connecting to remote signer...")?; - let uri = NostrConnectURI::parse(uri)?; - let signer = Arc::new(NostrConnect::new( - uri, - nostr::Keys::from_str(app_key).context("invalid app key")?, - Duration::from_secs(10 * 60), - None, - )?); - term.clear_last_lines(1)?; - Ok(signer) -} - -async fn get_signer_with_git_config_nsec_or_bunker_without_prompts( - git_repo: &Repo, -) -> Result<(Arc, Option)> { - if let Ok(local_nsec) = &git_repo - .get_git_config_item("nostr.nsec", Some(false)) - .context("failed get local git config")? - .context("git local config item nostr.nsec doesn't exist") - { - if local_nsec.contains("ncryptsec") { - bail!("git global config item nostr.nsec is an ncryptsec") - } - Ok(( - Arc::new(nostr::Keys::from_str(local_nsec).context("invalid nsec parameter")?), - None, - )) - } else if let Ok((uri, app_key, npub)) = - get_git_config_bunker_uri_and_app_key(git_repo, Some(false)) - { - Ok(( - get_nip46_signer_from_uri_and_key(&uri, &app_key).await?, - if let Ok(pubic_key) = PublicKey::parse(npub) { - Some(pubic_key) - } else { - None - }, - )) - } else if let Ok(global_nsec) = &git_repo - .get_git_config_item("nostr.nsec", Some(true)) - .context("failed get global git config")? - .context("git global config item nostr.nsec doesn't exist") - { - if global_nsec.contains("ncryptsec") { - bail!("git global config item nostr.nsec is an ncryptsec") - } - Ok(( - Arc::new(nostr::Keys::from_str(global_nsec).context("invalid nsec parameter")?), - None, - )) - } else if let Ok((uri, app_key, npub)) = - get_git_config_bunker_uri_and_app_key(git_repo, Some(true)) - { - Ok(( - get_nip46_signer_from_uri_and_key(&uri, &app_key).await?, - if let Ok(pubic_key) = PublicKey::parse(npub) { - Some(pubic_key) - } else { - None - }, - )) - } else { - bail!("cannot get nsec or bunker from git config") - } -} - -fn get_git_config_bunker_uri_and_app_key( - git_repo: &Repo, - global: Option, -) -> Result<(String, String, String)> { - Ok(( - git_repo - .get_git_config_item("nostr.bunker-uri", global) - .context("failed get local git config")? - .context("git local config item nostr.bunker-uri doesn't exist")? - .to_string(), - git_repo - .get_git_config_item("nostr.bunker-app-key", global) - .context("failed get local git config")? - .context("git local config item nostr.bunker-app-key doesn't exist")? - .to_string(), - git_repo - .get_git_config_item("nostr.npub", global) - .context("failed get local git config")? - .context("git local config item nostr.npub doesn't exist")? - .to_string(), - )) -} - -async fn fresh_login( - git_repo: &Repo, - #[cfg(test)] client: Option<&MockConnect>, - #[cfg(not(test))] client: Option<&Client>, - always_save: bool, -) -> Result<(Arc, UserRef)> { - let app_key = Keys::generate(); - let app_key_secret = app_key.secret_key().to_secret_hex(); - let relays = if let Some(client) = client { - client - .get_fallback_signer_relays() - .iter() - .flat_map(|s| Url::parse(s)) - .collect::>() - } else { - vec![] - }; - let offline = client.is_none(); - let nostr_connect_url = NostrConnectURI::client(app_key.public_key(), relays.clone(), "ngit"); - let qr = generate_qr(&nostr_connect_url.to_string())?; - - let printer = Arc::new(Mutex::new(Printer::default())); - if !offline { - let printer_clone = Arc::clone(&printer); - let mut printer_locked = printer_clone.lock().await; - printer_locked.printlns(qr); - printer_locked.println(format!( - "scan QR or paste into remote signer: {nostr_connect_url}" - )); - printer_locked.println_with_custom_formatting( - { - let mut s = String::new(); - let _ = ColorfulTheme::default().format_confirm_prompt( - &mut s, - "login with nsec / bunker url / nostr address instead", - Some(true), - ); - s - }, - "? login with nsec / bunker url / nostr address instead? (y/n) › yes".to_string(), - ); - } - - let (tx, rx) = oneshot::channel(); - let printer_clone = Arc::clone(&printer); - - let qr_listener = tokio::spawn(async move { - if offline { - return; - } - if let Ok(nostr_connect) = NostrConnect::new( - nostr_connect_url.clone(), - app_key.clone(), - Duration::from_secs(10 * 60), - None, - ) { - let signer: Arc = Arc::new(nostr_connect); - if let Ok(pub_key) = fetch_public_key(&signer).await { - let mut printer_locked = printer_clone.lock().await; - printer_locked.clear_all(); - - printer_locked.println_with_custom_formatting( - format!( - "{}", - Style::new().bold().apply_to("connected to remote signer"), - ), - "connected to remote signer".to_string(), - ); - printer_locked.println("press any key to continue...".to_string()); - let _ = tx.send(Some((signer, pub_key))); - } - } - }); - if !offline { - let _ = console::Term::stderr().read_char(); - } - qr_listener.abort(); - let printer_clone = Arc::clone(&printer); - let mut printer = printer_clone.lock().await; - printer.clear_all(); - - let (signer, public_key) = { - if let Ok(Some((signer, public_key))) = rx.await { - let bunker_url = NostrConnectURI::Bunker { - remote_signer_public_key: public_key, - relays: relays.clone(), - secret: None, - }; - if let Err(error) = save_bunker( - git_repo, - &public_key, - &bunker_url.to_string(), - &app_key_secret, - always_save, - ) { - eprintln!("{error}"); - } - (signer, public_key) - } else { - let mut public_key: Option = None; - // prompt for nsec - let mut prompt = "login with nsec / bunker url / nostr address"; - let signer: Arc = loop { - let input = Interactor::default() - .input(PromptInputParms::default().with_prompt(prompt)) - .context("failed to get nsec input from interactor")?; - if let Ok(keys) = nostr::Keys::from_str(&input) { - if let Err(error) = save_keys(git_repo, &keys, always_save) { - eprintln!("{error}"); - } - break Arc::new(keys); - } - let uri = if let Ok(uri) = NostrConnectURI::parse(&input) { - uri - } else if input.contains('@') { - if let Ok(uri) = fetch_nip46_uri_from_nip05(&input).await { - uri - } else { - prompt = "failed. try again with nostr address / bunker uri / nsec"; - continue; - } - } else { - prompt = "invalid. try again with nostr address / bunker uri / nsec"; - continue; - }; - match get_nip46_signer_from_uri_and_key(&uri.to_string(), &app_key_secret).await { - Ok(signer) => { - let pub_key = fetch_public_key(&signer).await?; - if let Err(error) = save_bunker( - git_repo, - &pub_key, - &uri.to_string(), - &app_key_secret, - always_save, - ) { - eprintln!("{error}"); - } - public_key = Some(pub_key); - break signer; - } - Err(_) => { - prompt = "failed. try again with nostr address / bunker uri / nsec"; - } - } - }; - let public_key = if let Some(public_key) = public_key { - public_key - } else { - signer.get_public_key().await? - }; - (signer, public_key) - } - }; - // lookup profile - let user_ref = get_user_details(&public_key, client, git_repo.get_path()?, false).await?; - print_logged_in_as(&user_ref, client.is_none())?; - Ok((signer, user_ref)) -} - -fn generate_qr(data: &str) -> Result> { - let mut lines = vec![]; - let qr = - QrCode::new(data.as_bytes()).context("failed to create QR of nostrconnect login url")?; - let colors = qr.to_colors(); - let rows: Vec<&[qrcode::Color]> = colors.chunks(qr.width()).collect(); - for (row, data) in rows.iter().enumerate() { - let odd = row % 2 != 0; - if odd { - continue; - } - let mut line = String::new(); - for (col, color) in data.iter().enumerate() { - let top = color; - let mut bottom = qrcode::Color::Light; - if let Some(next_row_data) = rows.get(row + 1) { - if let Some(color) = next_row_data.get(col) { - bottom = *color; - } - } - line.push(if *top == qrcode::Color::Dark { - if bottom == qrcode::Color::Dark { - '█' - } else { - '▀' - } - } else if bottom == qrcode::Color::Dark { - '▄' - } else { - ' ' - }); - } - lines.push(line); - } - Ok(lines) -} - -pub async fn fetch_nip46_uri_from_nip05(nip05: &str) -> Result { - let term = console::Term::stderr(); - term.write_line("contacting login service provider...")?; - let res = nip05::profile(&nip05, None).await; - term.clear_last_lines(1)?; - match res { - Ok(profile) => { - if profile.nip46.is_empty() { - eprintln!("nip05 provider isn't configured for remote login"); - bail!("nip05 provider isn't configured for remote login") - } - Ok(NostrConnectURI::Bunker { - remote_signer_public_key: profile.public_key, - relays: profile.nip46, - secret: None, - }) + eprintln!( + "logged in as {}{}", + user_ref.metadata.name, + match source { + SignerInfoSource::CommandLineArguments => " via cli arguments", + SignerInfoSource::GitLocal => " just to local repository", + SignerInfoSource::GitGlobal => "", } - Err(error) => { - eprintln!("error contacting login service provider: {error}"); - Err(error).context("error contacting login service provider") - } - } -} - -fn save_bunker( - git_repo: &Repo, - public_key: &PublicKey, - uri: &str, - app_key: &str, - always_save: bool, -) -> Result<()> { - if always_save - || Interactor::default() - .confirm(PromptConfirmParms::default().with_prompt("save login details?"))? - { - let global = !Interactor::default().confirm( - PromptConfirmParms::default() - .with_prompt("save login just for this repository?") - .with_default(false), - )?; - let npub = public_key.to_bech32()?; - if let Err(error) = save_to_git_config( - git_repo, - &npub, - &None, - &Some((uri.to_string(), app_key.to_string())), - global, - ) { - if global { - if Interactor::default().confirm( - PromptConfirmParms::default() - .with_prompt("save in repository git config?") - .with_default(true), - )? { - save_to_git_config( - git_repo, - &npub, - &None, - &Some((uri.to_string(), app_key.to_string())), - false, - )?; - } - } else { - Err(error)?; - } - }; - } - Ok(()) -} - -fn save_keys(git_repo: &Repo, keys: &nostr::Keys, always_save: bool) -> Result<()> { - if always_save - || Interactor::default() - .confirm(PromptConfirmParms::default().with_prompt("save login details?"))? - { - let global = !Interactor::default().confirm( - PromptConfirmParms::default() - .with_prompt("just for this repository?") - .with_default(false), - )?; - - let encrypt = Interactor::default().confirm( - PromptConfirmParms::default() - .with_prompt("require password?") - .with_default(false), - )?; - - let npub = keys.public_key().to_bech32()?; - let nsec_string = if encrypt { - let password = Interactor::default() - .password( - PromptPasswordParms::default() - .with_prompt("encrypt with password") - .with_confirm(), - ) - .context("failed to get password input from interactor.password")?; - encrypt_key(keys, &password)? - } else { - keys.secret_key().to_bech32()? - }; - - if let Err(error) = - save_to_git_config(git_repo, &npub, &Some(nsec_string.clone()), &None, global) - { - if global { - if Interactor::default().confirm( - PromptConfirmParms::default() - .with_prompt("save in repository git config?") - .with_default(true), - )? { - save_to_git_config(git_repo, &npub, &Some(nsec_string.clone()), &None, false)?; - } - } else { - eprintln!("{error}"); - Err(error)?; - } - }; - }; + ); Ok(()) } -fn get_config_item(git_repo: &Repo, name: &str) -> Result { - git_repo - .get_git_config_item(name, None) - .context("failed get git config")? - .context(format!("git config item {name} doesn't exist")) -} - -fn extract_user_metadata( - public_key: &nostr::PublicKey, - events: &[nostr::Event], -) -> Result { - let event = events - .iter() - .filter(|e| e.kind.eq(&nostr::Kind::Metadata) && e.pubkey.eq(public_key)) - .max_by_key(|e| e.created_at); - - let metadata: Option = if let Some(event) = event { - Some( - nostr::Metadata::from_json(event.content.clone()) - .context("metadata cannot be found in kind 0 event content")?, - ) - } else { - None - }; - - Ok(UserMetadata { - name: if let Some(metadata) = metadata { - if let Some(n) = metadata.name { - n - } else if let Some(n) = metadata.custom.get("displayName") { - // strip quote marks that custom.get() adds - let binding = n.to_string(); - let mut chars = binding.chars(); - chars.next(); - chars.next_back(); - chars.as_str().to_string() - } else if let Some(n) = metadata.display_name { - n - } else { - public_key.to_bech32()? - } - } else { - public_key.to_bech32()? - }, - created_at: if let Some(event) = event { - event.created_at - } else { - Timestamp::from(0) - }, - }) -} - -fn extract_user_relays(public_key: &nostr::PublicKey, events: &[nostr::Event]) -> UserRelays { - let event = events - .iter() - .filter(|e| e.kind.eq(&nostr::Kind::RelayList) && e.pubkey.eq(public_key)) - .max_by_key(|e| e.created_at); - - UserRelays { - relays: if let Some(event) = event { - event - .tags - .iter() - .filter(|t| { - t.kind() - .eq(&nostr::TagKind::SingleLetter(SingleLetterTag::lowercase( - Alphabet::R, - ))) - }) - .map(|t| UserRelayRef { - url: t.as_slice()[1].clone(), - read: t.as_slice().len() == 2 || t.as_slice()[2].eq("read"), - write: t.as_slice().len() == 2 || t.as_slice()[2].eq("write"), - }) - .collect() - } else { - vec![] - }, - created_at: if let Some(event) = event { - event.created_at - } else { - Timestamp::from(0) - }, - } -} - -async fn get_user_details( - public_key: &PublicKey, - #[cfg(test)] client: Option<&crate::client::MockConnect>, - #[cfg(not(test))] client: Option<&Client>, - git_repo_path: &Path, - cache_only: bool, -) -> Result { - if let Ok(user_ref) = get_user_ref_from_cache(git_repo_path, public_key).await { - Ok(user_ref) - } else { - let empty = UserRef { - public_key: public_key.to_owned(), - metadata: extract_user_metadata(public_key, &[])?, - relays: extract_user_relays(public_key, &[]), - }; - if cache_only { - Ok(empty) - } else if let Some(client) = client { - let term = console::Term::stderr(); - term.write_line("searching for profile...")?; - let (_, progress_reporter) = client - .fetch_all( - git_repo_path, - &HashSet::new(), - &HashSet::from_iter(vec![*public_key]), - ) - .await?; - if let Ok(user_ref) = get_user_ref_from_cache(git_repo_path, public_key).await { - progress_reporter.clear()?; - // if std::env::var("NGITTEST").is_err() {term.clear_last_lines(1)?;} - Ok(user_ref) - } else { - Ok(empty) - } - } else { - Ok(empty) - } - } -} - // None: in the edge case where the user is logged in via cli arguments rather // than from git config this may be wrong. TODO: fix this -pub async fn get_logged_in_user(git_repo_path: &Path) -> Result> { +pub async fn get_likely_logged_in_user(git_repo_path: &Path) -> Result> { let git_repo = Repo::from_path(&git_repo_path.to_path_buf())?; Ok( if let Some(npub) = git_repo.get_git_config_item("nostr.npub", None)? { @@ -844,31 +98,6 @@ pub async fn get_logged_in_user(git_repo_path: &Path) -> Result Result { - let filters = vec![ - nostr::Filter::default() - .author(*public_key) - .kind(Kind::Metadata), - nostr::Filter::default() - .author(*public_key) - .kind(Kind::RelayList), - ]; - - let events = get_event_from_global_cache(git_repo_path, filters.clone()).await?; - - if events.is_empty() { - bail!("no metadata and profile list in cache for selected public key"); - } - Ok(UserRef { - public_key: public_key.to_owned(), - metadata: extract_user_metadata(public_key, &events)?, - relays: extract_user_relays(public_key, &events), - }) -} - pub fn get_curent_user(git_repo: &Repo) -> Result> { Ok( if let Some(npub) = git_repo.get_git_config_item("nostr.npub", None)? { -- cgit v1.2.3