From c92e252adc9990fa4d147bad0a8bccafc19dfbb8 Mon Sep 17 00:00:00 2001 From: DanConwayDev Date: Wed, 27 Nov 2024 07:41:25 +0000 Subject: feat(export-keys): to use in other clients as part of the easy on-boaridng flow --- src/bin/ngit/cli.rs | 2 + src/bin/ngit/main.rs | 1 + src/bin/ngit/sub_commands/export_keys.rs | 89 ++++++++++++++++++++++++++++++++ src/bin/ngit/sub_commands/login.rs | 2 - src/bin/ngit/sub_commands/mod.rs | 1 + src/lib/login/existing.rs | 2 +- src/lib/login/fresh.rs | 8 +-- 7 files changed, 99 insertions(+), 6 deletions(-) create mode 100644 src/bin/ngit/sub_commands/export_keys.rs (limited to 'src') diff --git a/src/bin/ngit/cli.rs b/src/bin/ngit/cli.rs index b243f70..c5cbcfa 100644 --- a/src/bin/ngit/cli.rs +++ b/src/bin/ngit/cli.rs @@ -57,6 +57,8 @@ pub enum Commands { Fetch(sub_commands::fetch::SubCommandArgs), /// signal you are this repo's maintainer accepting proposals via nostr Init(sub_commands::init::SubCommandArgs), + /// export nostr keys to login to other nostr clients + ExportKeys, /// issue commits as a proposal Send(sub_commands::send::SubCommandArgs), /// list proposals; checkout, apply or download selected diff --git a/src/bin/ngit/main.rs b/src/bin/ngit/main.rs index 45cbef5..53fee06 100644 --- a/src/bin/ngit/main.rs +++ b/src/bin/ngit/main.rs @@ -18,6 +18,7 @@ async fn main() -> Result<()> { Commands::Fetch(args) => sub_commands::fetch::launch(&cli, args).await, Commands::Login(args) => sub_commands::login::launch(&cli, args).await, Commands::Init(args) => sub_commands::init::launch(&cli, args).await, + Commands::ExportKeys => sub_commands::export_keys::launch().await, Commands::Send(args) => sub_commands::send::launch(&cli, args, false).await, Commands::List => sub_commands::list::launch().await, Commands::Pull => sub_commands::pull::launch().await, diff --git a/src/bin/ngit/sub_commands/export_keys.rs b/src/bin/ngit/sub_commands/export_keys.rs new file mode 100644 index 0000000..12fc380 --- /dev/null +++ b/src/bin/ngit/sub_commands/export_keys.rs @@ -0,0 +1,89 @@ +use anyhow::{Context, Result}; +use ngit::{ + cli_interactor::{Interactor, InteractorPrompt, PromptChoiceParms}, + login::{ + existing::{get_signer_info, load_existing_login}, + fresh::generate_qr, + SignerInfo, SignerInfoSource, + }, +}; + +use crate::git::Repo; + +pub async fn launch() -> Result<()> { + let git_repo_result = Repo::discover().context("failed to find a git repository"); + let git_repo = { + match git_repo_result { + Ok(git_repo) => Some(git_repo), + Err(_) => None, + } + }; + + if let Ok((signer_info, source)) = get_signer_info(&git_repo.as_ref(), &None, &None, &None) { + if let Ok((_, user_ref, source)) = load_existing_login( + &git_repo.as_ref(), + &None, + &None, + &Some(source), + None, + true, + false, + ) + .await + { + let logged_in_msg = format!( + "logged in {}as {}", + if source == SignerInfoSource::GitLocal { + "to local git repository " + } else { + "" + }, + user_ref.metadata.name + ); + match signer_info { + SignerInfo::Bunker { + bunker_uri: _, + bunker_app_key: _, + npub: _, + } => { + eprintln!( + "failed: {logged_in_msg} using nostr connect so your keys are stored in a remote signer" + ); + return Ok(()); + } + SignerInfo::Nsec { + nsec, + password: _, + npub: _, + } => { + match Interactor::default().choice( + PromptChoiceParms::default() + .with_default(0) + .with_prompt(logged_in_msg) + .with_choices(vec![ + "print nsec".to_string(), + "show QR code of nsec".to_string(), + "cancel".to_string(), + ]), + )? { + 0 => { + println!("{nsec}"); + return Ok(()); + } + 1 => { + for line in generate_qr(&nsec)? { + println!("{line}"); + } + return Ok(()); + } + _ => { + return Ok(()); + } + } + } + } + } + } + eprintln!("not logged in so no keys are stored"); + Ok(()) +} diff --git a/src/bin/ngit/sub_commands/login.rs b/src/bin/ngit/sub_commands/login.rs index ff58ec6..afde145 100644 --- a/src/bin/ngit/sub_commands/login.rs +++ b/src/bin/ngit/sub_commands/login.rs @@ -25,8 +25,6 @@ pub struct SubCommandArgs { } pub async fn launch(args: &Cli, command_args: &SubCommandArgs) -> Result<()> { - // TODO show existing login on record, prompt to logout - let client = if command_args.offline { None } else { diff --git a/src/bin/ngit/sub_commands/mod.rs b/src/bin/ngit/sub_commands/mod.rs index 29a60f9..ac89d47 100644 --- a/src/bin/ngit/sub_commands/mod.rs +++ b/src/bin/ngit/sub_commands/mod.rs @@ -1,3 +1,4 @@ +pub mod export_keys; pub mod fetch; pub mod init; pub mod list; diff --git a/src/lib/login/existing.rs b/src/lib/login/existing.rs index 872e459..f5b93c7 100644 --- a/src/lib/login/existing.rs +++ b/src/lib/login/existing.rs @@ -60,7 +60,7 @@ pub async fn load_existing_login( } /// priority order: cli arguments, local git config, global git config -fn get_signer_info( +pub fn get_signer_info( git_repo: &Option<&Repo>, signer_info: &Option, password: &Option, diff --git a/src/lib/login/fresh.rs b/src/lib/login/fresh.rs index b874992..95c86a4 100644 --- a/src/lib/login/fresh.rs +++ b/src/lib/login/fresh.rs @@ -447,7 +447,7 @@ pub async fn listen_for_remote_signer( } } -fn generate_qr(data: &str) -> Result> { +pub 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")?; @@ -695,7 +695,7 @@ async fn signup( ) .context("failed to get display name input from interactor")?; if name.is_empty() { - show_prompt_error("emtpy display name", ""); + show_prompt_error("empty display name", ""); match Interactor::default().choice( PromptChoiceParms::default() .with_default(0) @@ -740,7 +740,9 @@ async fn signup( ) .await?; } - eprintln!("TODO: advice about using in other clients"); + eprintln!( + "to login to other nostr clients eg. gitworkshop.dev with this account run `ngit export-keys` at any time to reveal your nostr account secret" + ); break Ok(Some(( Arc::new(keys), public_key, -- cgit v1.2.3