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/bin/git_remote_nostr/list.rs | 2 +- src/bin/git_remote_nostr/main.rs | 37 ++++++++----------------------------- src/bin/git_remote_nostr/push.rs | 25 +++++++++---------------- src/bin/git_remote_nostr/utils.rs | 4 ++-- src/bin/ngit/cli.rs | 26 ++++++++++++++++++++++++++ src/bin/ngit/sub_commands/init.rs | 17 +++++++---------- src/bin/ngit/sub_commands/list.rs | 6 +++--- src/bin/ngit/sub_commands/login.rs | 34 ++++++++++------------------------ src/bin/ngit/sub_commands/pull.rs | 2 +- src/bin/ngit/sub_commands/push.rs | 16 ++++++---------- src/bin/ngit/sub_commands/send.rs | 27 +++++++++++++-------------- 11 files changed, 86 insertions(+), 110 deletions(-) (limited to 'src/bin') diff --git a/src/bin/git_remote_nostr/list.rs b/src/bin/git_remote_nostr/list.rs index 92faa6b..daff1b6 100644 --- a/src/bin/git_remote_nostr/list.rs +++ b/src/bin/git_remote_nostr/list.rs @@ -35,7 +35,7 @@ pub async fn run_list( for_push: bool, ) -> Result>> { let nostr_state = - if let Ok(nostr_state) = get_state_from_cache(git_repo.get_path()?, repo_ref).await { + if let Ok(nostr_state) = get_state_from_cache(Some(git_repo.get_path()?), repo_ref).await { Some(nostr_state) } else { None diff --git a/src/bin/git_remote_nostr/main.rs b/src/bin/git_remote_nostr/main.rs index ed9fe9d..e4f97c7 100644 --- a/src/bin/git_remote_nostr/main.rs +++ b/src/bin/git_remote_nostr/main.rs @@ -15,7 +15,7 @@ use std::{ use anyhow::{bail, Context, Result}; use client::{consolidate_fetch_reports, get_repo_ref_from_cache, Connect}; use git::{nostr_url::NostrUrlDecoded, RepoActions}; -use ngit::{client, git, login}; +use ngit::{client, git, login::existing::load_existing_login}; use nostr::nips::nip01::Coordinate; use utils::read_line; @@ -36,38 +36,17 @@ async fn main() -> Result<()> { let mut client = Client::default(); - if git_repo - .get_git_config_item("nostr.npub", None) - .is_ok_and(|x| x.is_some()) - && (git_repo - .get_git_config_item("nostr.nsec", None) - .is_ok_and(|x| x.is_some()) - || (git_repo - .get_git_config_item("nostr.bunker-uri", None) - .is_ok_and(|x| x.is_some()) - && git_repo - .get_git_config_item("nostr.bunker-app-key", None) - .is_ok_and(|x| x.is_some()))) + if let Ok((signer, _, _)) = + load_existing_login(&Some(&git_repo), &None, &None, &None, None, true, false).await { - if let Ok((signer, _)) = login::launch( - &git_repo, - &None, - &None, - &None, - &None, - Some(&client), - false, - true, - ) - .await - { - client.set_signer(signer).await; - }; + // signer for to respond to relay auth request + client.set_signer(signer).await; } fetching_with_report_for_helper(git_repo_path, &client, &decoded_nostr_url.coordinates).await?; - let repo_ref = get_repo_ref_from_cache(git_repo_path, &decoded_nostr_url.coordinates).await?; + let repo_ref = + get_repo_ref_from_cache(Some(git_repo_path), &decoded_nostr_url.coordinates).await?; let stdin = io::stdin(); let mut line = String::new(); @@ -170,7 +149,7 @@ async fn fetching_with_report_for_helper( let term = console::Term::stderr(); term.write_line("nostr: fetching...")?; let (relay_reports, progress_reporter) = client - .fetch_all(git_repo_path, repo_coordinates, &HashSet::new()) + .fetch_all(Some(git_repo_path), repo_coordinates, &HashSet::new()) .await?; if !relay_reports.iter().any(std::result::Result::is_err) { let _ = progress_reporter.clear(); diff --git a/src/bin/git_remote_nostr/push.rs b/src/bin/git_remote_nostr/push.rs index 91c901a..7161c5d 100644 --- a/src/bin/git_remote_nostr/push.rs +++ b/src/bin/git_remote_nostr/push.rs @@ -8,7 +8,9 @@ use std::{ use anyhow::{anyhow, bail, Context, Result}; use auth_git2::GitAuthenticator; -use client::{get_events_from_cache, get_state_from_cache, send_events, sign_event, STATE_KIND}; +use client::{ + get_events_from_local_cache, get_state_from_cache, send_events, sign_event, STATE_KIND, +}; use console::Term; use git::{sha1_to_oid, RepoActions}; use git2::{Oid, Repository}; @@ -76,7 +78,7 @@ pub async fn run_push( _ => list_from_remotes(&term, git_repo, &repo_ref.git_server, decoded_nostr_url), }; - let nostr_state = get_state_from_cache(git_repo.get_path()?, repo_ref).await; + let nostr_state = get_state_from_cache(Some(git_repo.get_path()?), repo_ref).await; let existing_state = { // if no state events - create from first git server listed @@ -122,17 +124,8 @@ pub async fn run_push( return Ok(()); } - let (signer, user_ref) = login::launch( - git_repo, - &None, - &None, - &None, - &None, - Some(client), - false, - false, - ) - .await?; + let (signer, user_ref, _) = + login::login_or_signup(&Some(git_repo), &None, &None, Some(client)).await?; if !repo_ref.maintainers.contains(&user_ref.public_key) { for refspec in &git_server_refspecs { @@ -306,7 +299,7 @@ pub async fn run_push( term.write_line("broadcast to nostr relays:")?; send_events( client, - git_repo.get_path()?, + Some(git_repo.get_path()?), events, user_ref.relays.write(), repo_ref.relays.clone(), @@ -897,7 +890,7 @@ async fn get_merged_status_events( // merge commit for parent in commit.parents() { // lookup parent id - let commit_events = get_events_from_cache( + let commit_events = get_events_from_local_cache( git_repo.get_path()?, vec![ nostr::Filter::default() @@ -1045,7 +1038,7 @@ async fn get_proposal_and_revision_root_from_patch( .clone(), )?; - get_events_from_cache( + get_events_from_local_cache( git_repo.get_path()?, vec![nostr::Filter::default().id(proposal_or_revision_id)], ) diff --git a/src/bin/git_remote_nostr/utils.rs b/src/bin/git_remote_nostr/utils.rs index a8bbd6f..b54ce6b 100644 --- a/src/bin/git_remote_nostr/utils.rs +++ b/src/bin/git_remote_nostr/utils.rs @@ -10,7 +10,7 @@ use anyhow::{bail, Context, Result}; use git2::Repository; use ngit::{ client::{ - get_all_proposal_patch_events_from_cache, get_events_from_cache, + get_all_proposal_patch_events_from_cache, get_events_from_local_cache, get_proposals_and_revisions_from_cache, }, git::{ @@ -108,7 +108,7 @@ pub async fn get_open_proposals( .collect(); let statuses: Vec = { - let mut statuses = get_events_from_cache( + let mut statuses = get_events_from_local_cache( git_repo_path, vec![ nostr::Filter::default() diff --git a/src/bin/ngit/cli.rs b/src/bin/ngit/cli.rs index d0f934e..b243f70 100644 --- a/src/bin/ngit/cli.rs +++ b/src/bin/ngit/cli.rs @@ -1,4 +1,6 @@ +use anyhow::{bail, Result}; use clap::{Parser, Subcommand}; +use ngit::login::SignerInfo; use crate::sub_commands; @@ -25,6 +27,30 @@ pub struct Cli { pub disable_cli_spinners: bool, } +pub fn extract_signer_cli_arguments(args: &Cli) -> Result> { + if let Some(nsec) = &args.nsec { + Ok(Some(SignerInfo::Nsec { + nsec: nsec.to_string(), + password: None, + npub: None, + })) + } else if let Some(bunker_uri) = args.bunker_uri.clone() { + if let Some(bunker_app_key) = args.bunker_app_key.clone() { + Ok(Some(SignerInfo::Bunker { + bunker_uri, + bunker_app_key, + npub: None, + })) + } else { + bail!("cli argument bunker-app-key must be supplied when bunker-uri is") + } + } else if args.bunker_app_key.is_some() { + bail!("cli argument bunker-uri must be supplied when bunker-app-key is") + } else { + Ok(None) + } +} + #[derive(Subcommand)] pub enum Commands { /// update cache with latest updates from nostr diff --git a/src/bin/ngit/sub_commands/init.rs b/src/bin/ngit/sub_commands/init.rs index aa43106..146a29c 100644 --- a/src/bin/ngit/sub_commands/init.rs +++ b/src/bin/ngit/sub_commands/init.rs @@ -6,7 +6,7 @@ use nostr::{nips::nip01::Coordinate, FromBech32, PublicKey, ToBech32}; use nostr_sdk::Kind; use crate::{ - cli::Cli, + cli::{extract_signer_cli_arguments, Cli}, cli_interactor::{Interactor, InteractorPrompt, PromptInputParms}, client::{fetching_with_report, get_repo_ref_from_cache, send_events, Client, Connect}, git::{nostr_url::convert_clone_url_to_https, Repo, RepoActions}, @@ -69,7 +69,8 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> { let repo_ref = if let Some(repo_coordinates) = repo_coordinates.clone() { fetching_with_report(git_repo_path, &client, &repo_coordinates).await?; - if let Ok(repo_ref) = get_repo_ref_from_cache(git_repo_path, &repo_coordinates).await { + if let Ok(repo_ref) = get_repo_ref_from_cache(Some(git_repo_path), &repo_coordinates).await + { Some(repo_ref) } else { None @@ -78,15 +79,11 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> { None }; - let (signer, user_ref) = login::launch( - &git_repo, - &cli_args.bunker_uri, - &cli_args.bunker_app_key, - &cli_args.nsec, + let (signer, user_ref, _) = login::login_or_signup( + &Some(&git_repo), + &extract_signer_cli_arguments(cli_args).unwrap_or(None), &cli_args.password, Some(&client), - false, - false, ) .await?; @@ -381,7 +378,7 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> { send_events( &client, - git_repo_path, + Some(git_repo_path), vec![repo_event], user_ref.relays.write(), relays.clone(), diff --git a/src/bin/ngit/sub_commands/list.rs b/src/bin/ngit/sub_commands/list.rs index 351896a..7717dce 100644 --- a/src/bin/ngit/sub_commands/list.rs +++ b/src/bin/ngit/sub_commands/list.rs @@ -12,7 +12,7 @@ use nostr_sdk::Kind; use crate::{ cli_interactor::{Interactor, InteractorPrompt, PromptChoiceParms, PromptConfirmParms}, client::{ - fetching_with_report, get_events_from_cache, get_repo_ref_from_cache, Client, Connect, + fetching_with_report, get_events_from_local_cache, get_repo_ref_from_cache, Client, Connect, }, git::{str_to_sha1, Repo, RepoActions}, git_events::{ @@ -37,7 +37,7 @@ pub async fn launch() -> Result<()> { fetching_with_report(git_repo_path, &client, &repo_coordinates).await?; - let repo_ref = get_repo_ref_from_cache(git_repo_path, &repo_coordinates).await?; + let repo_ref = get_repo_ref_from_cache(Some(git_repo_path), &repo_coordinates).await?; let proposals_and_revisions: Vec = get_proposals_and_revisions_from_cache(git_repo_path, repo_ref.coordinates()).await?; @@ -47,7 +47,7 @@ pub async fn launch() -> Result<()> { } let statuses: Vec = { - let mut statuses = get_events_from_cache( + let mut statuses = get_events_from_local_cache( git_repo_path, vec![ nostr::Filter::default() diff --git a/src/bin/ngit/sub_commands/login.rs b/src/bin/ngit/sub_commands/login.rs index df7efa5..ae5efb1 100644 --- a/src/bin/ngit/sub_commands/login.rs +++ b/src/bin/ngit/sub_commands/login.rs @@ -5,45 +5,31 @@ use crate::{ cli::Cli, client::{Client, Connect}, git::Repo, - login, + login::fresh::fresh_login_or_signup, }; #[derive(clap::Args)] pub struct SubCommandArgs { + /// login to the local git repository only + #[arg(long, action)] + local: bool, + /// don't fetch user metadata and relay list from relays #[arg(long, action)] offline: bool, } -pub async fn launch(args: &Cli, command_args: &SubCommandArgs) -> Result<()> { +pub async fn launch(_args: &Cli, command_args: &SubCommandArgs) -> Result<()> { let git_repo = Repo::discover().context("cannot find a git repository")?; + // TODO show existing login on record, prompt to logout + // TODO use cli arguments to login if command_args.offline { - login::launch( - &git_repo, - &args.bunker_uri, - &args.bunker_app_key, - &args.nsec, - &args.password, - None, - true, - false, - ) - .await?; + fresh_login_or_signup(&Some(&git_repo), None, command_args.local).await?; Ok(()) } else { let client = Client::default(); + fresh_login_or_signup(&Some(&git_repo), Some(&client), command_args.local).await?; - login::launch( - &git_repo, - &args.bunker_uri, - &args.bunker_app_key, - &args.nsec, - &args.password, - Some(&client), - true, - false, - ) - .await?; client.disconnect().await?; Ok(()) } diff --git a/src/bin/ngit/sub_commands/pull.rs b/src/bin/ngit/sub_commands/pull.rs index d79b7b1..77a65e9 100644 --- a/src/bin/ngit/sub_commands/pull.rs +++ b/src/bin/ngit/sub_commands/pull.rs @@ -33,7 +33,7 @@ pub async fn launch() -> Result<()> { let repo_coordinates = get_repo_coordinates(&git_repo, &client).await?; fetching_with_report(git_repo_path, &client, &repo_coordinates).await?; - let repo_ref = get_repo_ref_from_cache(git_repo_path, &repo_coordinates).await?; + let repo_ref = get_repo_ref_from_cache(Some(git_repo_path), &repo_coordinates).await?; let logged_in_public_key = if let Ok(Some(npub)) = git_repo.get_git_config_item("nostr.npub", None) { diff --git a/src/bin/ngit/sub_commands/push.rs b/src/bin/ngit/sub_commands/push.rs index a77f356..aaf1009 100644 --- a/src/bin/ngit/sub_commands/push.rs +++ b/src/bin/ngit/sub_commands/push.rs @@ -6,7 +6,7 @@ use ngit::{ use nostr_sdk::PublicKey; use crate::{ - cli::Cli, + cli::{extract_signer_cli_arguments, Cli}, client::{ fetching_with_report, get_all_proposal_patch_events_from_cache, get_proposals_and_revisions_from_cache, get_repo_ref_from_cache, Client, Connect, @@ -53,7 +53,7 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> { fetching_with_report(git_repo_path, &client, &repo_coordinates).await?; - let repo_ref = get_repo_ref_from_cache(git_repo_path, &repo_coordinates).await?; + let repo_ref = get_repo_ref_from_cache(Some(git_repo_path), &repo_coordinates).await?; let logged_in_public_key = if let Ok(Some(npub)) = git_repo.get_git_config_item("nostr.npub", None) { @@ -166,15 +166,11 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> { ahead.len() ); - let (signer, user_ref) = login::launch( - &git_repo, - &cli_args.bunker_uri, - &cli_args.bunker_app_key, - &cli_args.nsec, + let (signer, user_ref, _) = login::login_or_signup( + &Some(&git_repo), + &extract_signer_cli_arguments(cli_args).unwrap_or(None), &cli_args.password, Some(&client), - false, - false, ) .await?; @@ -204,7 +200,7 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> { send_events( &client, - git_repo_path, + Some(git_repo_path), patch_events, user_ref.relays.write(), repo_ref.relays.clone(), diff --git a/src/bin/ngit/sub_commands/send.rs b/src/bin/ngit/sub_commands/send.rs index fe2952f..114a021 100644 --- a/src/bin/ngit/sub_commands/send.rs +++ b/src/bin/ngit/sub_commands/send.rs @@ -10,12 +10,12 @@ use nostr::{ use nostr_sdk::hashes::sha1::Hash as Sha1Hash; use crate::{ - cli::Cli, + cli::{extract_signer_cli_arguments, Cli}, cli_interactor::{ Interactor, InteractorPrompt, PromptConfirmParms, PromptInputParms, PromptMultiChoiceParms, }, client::{ - fetching_with_report, get_events_from_cache, get_repo_ref_from_cache, Client, Connect, + fetching_with_report, get_events_from_local_cache, get_repo_ref_from_cache, Client, Connect, }, git::{identify_ahead_behind, Repo, RepoActions}, git_events::{event_is_patch_set_root, event_tag_from_nip19_or_hex}, @@ -175,21 +175,18 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs, no_fetch: bool) -> Re } else { None }; - let (signer, user_ref) = login::launch( - &git_repo, - &cli_args.bunker_uri, - &cli_args.bunker_app_key, - &cli_args.nsec, + + let (signer, user_ref, _) = login::login_or_signup( + &Some(&git_repo), + &extract_signer_cli_arguments(cli_args).unwrap_or(None), &cli_args.password, Some(&client), - false, - false, ) .await?; client.set_signer(signer.clone()).await; - let repo_ref = get_repo_ref_from_cache(git_repo_path, &repo_coordinates).await?; + let repo_ref = get_repo_ref_from_cache(Some(git_repo_path), &repo_coordinates).await?; // oldest first commits.reverse(); @@ -228,7 +225,7 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs, no_fetch: bool) -> Re send_events( &client, - git_repo_path, + Some(git_repo_path), events.clone(), user_ref.relays.write(), repo_ref.relays.clone(), @@ -370,9 +367,11 @@ async fn get_root_proposal_id_and_mentions_from_in_reply_to( marker: _, public_key: _, }) => { - let events = - get_events_from_cache(git_repo_path, vec![nostr::Filter::new().id(*event_id)]) - .await?; + let events = get_events_from_local_cache( + git_repo_path, + vec![nostr::Filter::new().id(*event_id)], + ) + .await?; if let Some(first) = events.iter().find(|e| e.id.eq(event_id)) { if event_is_patch_set_root(first) { -- cgit v1.2.3