From b09cf3ef8bbb5d31e4c424ff28282f5029f95fb2 Mon Sep 17 00:00:00 2001 From: DanConwayDev Date: Mon, 25 Nov 2024 12:31:50 +0000 Subject: fix(login): handle git config save errors to guide the users how to login dispite the git config errors --- src/bin/ngit/sub_commands/login.rs | 56 +++++++++++++++++++++++-- src/lib/login/fresh.rs | 83 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 133 insertions(+), 6 deletions(-) diff --git a/src/bin/ngit/sub_commands/login.rs b/src/bin/ngit/sub_commands/login.rs index 1a70118..7bb0906 100644 --- a/src/bin/ngit/sub_commands/login.rs +++ b/src/bin/ngit/sub_commands/login.rs @@ -2,7 +2,7 @@ use anyhow::{Context, Result}; use clap; use ngit::{ cli_interactor::{Interactor, InteractorPrompt, PromptChoiceParms}, - git::remove_git_config_item, + git::{get_git_config_item, remove_git_config_item}, login::{existing::load_existing_login, SignerInfoSource}, }; @@ -101,14 +101,39 @@ async fn logout(git_repo: Option<&Repo>, local_only: bool) -> Result<(bool, bool "nostr.bunker-uri", "nostr.bunker-app-key", ] { - remove_git_config_item( + if let Err(error) = remove_git_config_item( if source == SignerInfoSource::GitLocal { &git_repo } else { &None }, item, - )?; + ) { + eprintln!("{error:?}"); + + eprintln!( + "consider manually removing {} git config items: {}", + if source == SignerInfoSource::GitGlobal { + "global" + } else { + "local" + }, + format_items_as_list(&get_global_login_config_items_set()) + ); + match Interactor::default().choice( + PromptChoiceParms::default().with_default(0).with_choices( + vec![ + "continue with global login to reveal what git config items to manually set".to_string(), + "login to this local repository with a different account".to_string(), + "cancel".to_string(), + ] + ), + )? { + 0 => return Ok((true, false)), + 1 => return Ok((true, true)), + _ => return Ok((false, local_only)), + } + } } } 1 => return Ok((false, local_only)), @@ -118,3 +143,28 @@ async fn logout(git_repo: Option<&Repo>, local_only: bool) -> Result<(bool, bool } Ok((true, local_only)) } + +fn get_global_login_config_items_set() -> Vec<&'static str> { + [ + "nostr.nsec", + "nostr.npub", + "nostr.bunker-uri", + "nostr.bunker-app-key", + ] + .iter() + .copied() + .filter(|item| get_git_config_item(&None, item).is_ok_and(|item| item.is_some())) + .collect::>() +} + +fn format_items_as_list(items: &[&str]) -> String { + match items.len() { + 0 => String::new(), + 1 => items[0].to_string(), + 2 => format!("{} and {}", items[0], items[1]), + _ => { + let all_but_last = items[..items.len() - 1].join(", "); + format!("{}, and {}", all_but_last, items[items.len() - 1]) + } + } +} diff --git a/src/lib/login/fresh.rs b/src/lib/login/fresh.rs index e8cfcb8..194f638 100644 --- a/src/lib/login/fresh.rs +++ b/src/lib/login/fresh.rs @@ -93,7 +93,7 @@ pub async fn fresh_login_or_signup( } } }; - let _ = save_to_git_config(git_repo, &signer_info, !save_local); + let _ = save_to_git_config(git_repo, &signer_info, !save_local).await; let user_ref = get_user_details( &public_key, client, @@ -483,7 +483,7 @@ fn generate_qr(data: &str) -> Result> { Ok(lines) } -fn save_to_git_config( +async fn save_to_git_config( git_repo: &Option<&Repo>, signer_info: &SignerInfo, global: bool, @@ -516,7 +516,64 @@ fn save_to_git_config( } } if global { - save_to_git_config(git_repo, signer_info, false)? + loop { + match Interactor::default().choice( + PromptChoiceParms::default() + .with_default(0) + .with_choices(vec![ + "i'll update global git config manually with above values".to_string(), + "only log into local git repository (save to local git config)" + .to_string(), + "one time login".to_string(), + ]), + )? { + 0 => { + // check + if let Ok((_, user_ref, _)) = load_existing_login( + git_repo, + &None, + &None, + &Some(SignerInfoSource::GitGlobal), + None, + true, + true, + ) + .await + { + if user_ref.public_key == get_pubkey_from_signer_info(signer_info)? { + return Ok(()); + } else { + eprintln!( + "global git config hasn't been updated with different npub" + ); + } + } else { + eprintln!( + "global git config hasn't been updated with nostr login values" + ); + } + } + 1 => { + if let Err(error) = + silently_save_to_git_config(git_repo, signer_info, false).context( + format!( + "failed to save login details to {} git config", + if global { "global" } else { "local" } + ), + ) + { + eprintln!("Error: {:?}", error); + eprintln!("login details were not saved"); + } else { + eprintln!( + "saved login details to local git config. you are only logged in to this local repository." + ); + } + return Ok(()); + } + _ => return Ok(()), + } + } } Err(error) } else { @@ -532,6 +589,26 @@ fn save_to_git_config( } } +fn get_pubkey_from_signer_info(signer_info: &SignerInfo) -> Result { + let npub = match signer_info { + SignerInfo::Bunker { + bunker_uri: _, + bunker_app_key: _, + npub, + } => npub, + SignerInfo::Nsec { + nsec: _, + password: _, + npub, + } => npub, + }; + if let Some(npub) = npub { + PublicKey::parse(npub).context("format of npub string in signer_info is invalid") + } else { + bail!("no npub in signer_info object"); + } +} + fn silently_save_to_git_config( git_repo: &Option<&Repo>, signer_info: &SignerInfo, -- cgit v1.2.3