diff options
| -rw-r--r-- | src/bin/ngit/sub_commands/login.rs | 2 | ||||
| -rw-r--r-- | src/lib/login/existing.rs | 17 | ||||
| -rw-r--r-- | src/lib/login/fresh.rs | 18 | ||||
| -rw-r--r-- | test_utils/src/lib.rs | 70 | ||||
| -rw-r--r-- | tests/ngit_login.rs | 562 |
5 files changed, 179 insertions, 490 deletions
diff --git a/src/bin/ngit/sub_commands/login.rs b/src/bin/ngit/sub_commands/login.rs index 29b4e81..ff58ec6 100644 --- a/src/bin/ngit/sub_commands/login.rs +++ b/src/bin/ngit/sub_commands/login.rs | |||
| @@ -61,7 +61,7 @@ pub async fn launch(args: &Cli, command_args: &SubCommandArgs) -> Result<()> { | |||
| 61 | 61 | ||
| 62 | /// return ( bool - logged out, bool - log in to local git locally) | 62 | /// return ( bool - logged out, bool - log in to local git locally) |
| 63 | async fn logout(git_repo: Option<&Repo>, local_only: bool) -> Result<(bool, bool)> { | 63 | async fn logout(git_repo: Option<&Repo>, local_only: bool) -> Result<(bool, bool)> { |
| 64 | for source in if local_only { | 64 | for source in if local_only || std::env::var("NGITTEST").is_ok() { |
| 65 | vec![SignerInfoSource::GitLocal] | 65 | vec![SignerInfoSource::GitLocal] |
| 66 | } else { | 66 | } else { |
| 67 | vec![SignerInfoSource::GitLocal, SignerInfoSource::GitGlobal] | 67 | vec![SignerInfoSource::GitLocal, SignerInfoSource::GitGlobal] |
diff --git a/src/lib/login/existing.rs b/src/lib/login/existing.rs index 342f792..872e459 100644 --- a/src/lib/login/existing.rs +++ b/src/lib/login/existing.rs | |||
| @@ -69,11 +69,18 @@ fn get_signer_info( | |||
| 69 | Ok(match source { | 69 | Ok(match source { |
| 70 | None => { | 70 | None => { |
| 71 | let mut result = None; | 71 | let mut result = None; |
| 72 | for source in &[ | 72 | for source in if std::env::var("NGITTEST").is_ok() { |
| 73 | SignerInfoSource::CommandLineArguments, | 73 | vec![ |
| 74 | SignerInfoSource::GitLocal, | 74 | SignerInfoSource::CommandLineArguments, |
| 75 | SignerInfoSource::GitGlobal, | 75 | SignerInfoSource::GitLocal, |
| 76 | ] { | 76 | ] |
| 77 | } else { | ||
| 78 | vec![ | ||
| 79 | SignerInfoSource::CommandLineArguments, | ||
| 80 | SignerInfoSource::GitLocal, | ||
| 81 | SignerInfoSource::GitGlobal, | ||
| 82 | ] | ||
| 83 | } { | ||
| 77 | if let Ok(res) = | 84 | if let Ok(res) = |
| 78 | get_signer_info(git_repo, signer_info, password, &Some(source.clone())) | 85 | get_signer_info(git_repo, signer_info, password, &Some(source.clone())) |
| 79 | { | 86 | { |
diff --git a/src/lib/login/fresh.rs b/src/lib/login/fresh.rs index 59026bd..b874992 100644 --- a/src/lib/login/fresh.rs +++ b/src/lib/login/fresh.rs | |||
| @@ -25,7 +25,7 @@ use crate::{ | |||
| 25 | Interactor, InteractorPrompt, Printer, PromptChoiceParms, PromptConfirmParms, | 25 | Interactor, InteractorPrompt, Printer, PromptChoiceParms, PromptConfirmParms, |
| 26 | PromptInputParms, PromptPasswordParms, | 26 | PromptInputParms, PromptPasswordParms, |
| 27 | }, | 27 | }, |
| 28 | client::{fetch_public_key, send_events, Connect}, | 28 | client::{send_events, Connect}, |
| 29 | git::{remove_git_config_item, save_git_config_item, Repo, RepoActions}, | 29 | git::{remove_git_config_item, save_git_config_item, Repo, RepoActions}, |
| 30 | }; | 30 | }; |
| 31 | 31 | ||
| @@ -38,7 +38,7 @@ pub async fn fresh_login_or_signup( | |||
| 38 | ) -> Result<(Arc<dyn NostrSigner>, UserRef, SignerInfoSource)> { | 38 | ) -> Result<(Arc<dyn NostrSigner>, UserRef, SignerInfoSource)> { |
| 39 | let (signer, public_key, signer_info, source) = loop { | 39 | let (signer, public_key, signer_info, source) = loop { |
| 40 | if let Some(signer_info) = signer_info { | 40 | if let Some(signer_info) = signer_info { |
| 41 | let (signer, _user_ref, source) = load_existing_login( | 41 | let (signer, user_ref, source) = load_existing_login( |
| 42 | git_repo, | 42 | git_repo, |
| 43 | &Some(signer_info.clone()), | 43 | &Some(signer_info.clone()), |
| 44 | &None, | 44 | &None, |
| @@ -48,8 +48,7 @@ pub async fn fresh_login_or_signup( | |||
| 48 | true, | 48 | true, |
| 49 | ) | 49 | ) |
| 50 | .await?; | 50 | .await?; |
| 51 | let public_key = fetch_public_key(&signer).await?; | 51 | break (signer, user_ref.public_key, signer_info, source); |
| 52 | break (signer, public_key, signer_info, source); | ||
| 53 | } | 52 | } |
| 54 | match Interactor::default().choice( | 53 | match Interactor::default().choice( |
| 55 | PromptChoiceParms::default() | 54 | PromptChoiceParms::default() |
| @@ -176,7 +175,7 @@ pub async fn get_fresh_nsec_signer() -> Result< | |||
| 176 | (keys, signer_info) | 175 | (keys, signer_info) |
| 177 | } else if let Ok(keys) = nostr::Keys::from_str(&input) { | 176 | } else if let Ok(keys) = nostr::Keys::from_str(&input) { |
| 178 | let nsec = keys.secret_key().to_bech32()?; | 177 | let nsec = keys.secret_key().to_bech32()?; |
| 179 | show_prompt_success("nsec", &shorten_string(&nsec)); | 178 | show_prompt_success("nsec", &shorten_string(&input)); |
| 180 | let signer_info = SignerInfo::Nsec { | 179 | let signer_info = SignerInfo::Nsec { |
| 181 | nsec, | 180 | nsec, |
| 182 | password: None, | 181 | password: None, |
| @@ -223,11 +222,11 @@ fn show_prompt_error(label: &str, value: &str) { | |||
| 223 | let _ = ColorfulTheme::default().format_error( | 222 | let _ = ColorfulTheme::default().format_error( |
| 224 | &mut s, | 223 | &mut s, |
| 225 | &format!( | 224 | &format!( |
| 226 | "{label}: {}", | 225 | "{label}: \"{}\"", |
| 227 | if value.is_empty() { | 226 | if value.is_empty() { |
| 228 | "empty".to_string() | 227 | "empty".to_string() |
| 229 | } else { | 228 | } else { |
| 230 | shorten_string(&format!("\"{}\"", &value)) | 229 | shorten_string(value) |
| 231 | } | 230 | } |
| 232 | ), | 231 | ), |
| 233 | ); | 232 | ); |
| @@ -490,6 +489,11 @@ async fn save_to_git_config( | |||
| 490 | signer_info: &SignerInfo, | 489 | signer_info: &SignerInfo, |
| 491 | global: bool, | 490 | global: bool, |
| 492 | ) -> Result<()> { | 491 | ) -> Result<()> { |
| 492 | let global = if std::env::var("NGITTEST").is_ok() { | ||
| 493 | false | ||
| 494 | } else { | ||
| 495 | global | ||
| 496 | }; | ||
| 493 | let err_msg = format!( | 497 | let err_msg = format!( |
| 494 | "failed to save login details to {} git config", | 498 | "failed to save login details to {} git config", |
| 495 | if global { "global" } else { "local" } | 499 | if global { "global" } else { "local" } |
diff --git a/test_utils/src/lib.rs b/test_utils/src/lib.rs index 6ca0a43..6708c81 100644 --- a/test_utils/src/lib.rs +++ b/test_utils/src/lib.rs | |||
| @@ -336,6 +336,49 @@ impl CliTesterInputPrompt<'_> { | |||
| 336 | } | 336 | } |
| 337 | 337 | ||
| 338 | pub fn succeeds_with(&mut self, input: &str) -> Result<&mut Self> { | 338 | pub fn succeeds_with(&mut self, input: &str) -> Result<&mut Self> { |
| 339 | self.succeeds_with_optional_shortened_report(input, false) | ||
| 340 | } | ||
| 341 | |||
| 342 | pub fn succeeds_with_optional_shortened_report( | ||
| 343 | &mut self, | ||
| 344 | input: &str, | ||
| 345 | shorten_report_to_15_chars: bool, | ||
| 346 | ) -> Result<&mut Self> { | ||
| 347 | self.tester.send_line(input)?; | ||
| 348 | self.tester | ||
| 349 | .expect(input) | ||
| 350 | .context("expect input to be printed")?; | ||
| 351 | self.tester | ||
| 352 | .expect("\r") | ||
| 353 | .context("expect new line after input to be printed")?; | ||
| 354 | |||
| 355 | let mut s = String::new(); | ||
| 356 | let printed_input = if shorten_report_to_15_chars { | ||
| 357 | shorten_string(input) | ||
| 358 | } else { | ||
| 359 | input.to_string() | ||
| 360 | }; | ||
| 361 | self.tester | ||
| 362 | .formatter | ||
| 363 | .format_input_prompt_selection(&mut s, self.prompt.as_str(), &printed_input) | ||
| 364 | .expect("diagluer theme formatter should succeed"); | ||
| 365 | if !s.contains(self.prompt.as_str()) { | ||
| 366 | panic!("dialoguer must be broken as formatted prompt success doesnt contain prompt"); | ||
| 367 | } | ||
| 368 | let formatted_success = format!("{}\r\n", sanatize(s)); | ||
| 369 | |||
| 370 | self.tester | ||
| 371 | .expect(formatted_success.as_str()) | ||
| 372 | .context("expect immediate prompt success")?; | ||
| 373 | Ok(self) | ||
| 374 | } | ||
| 375 | |||
| 376 | pub fn fails_with_optional_shortened_report( | ||
| 377 | &mut self, | ||
| 378 | input: &str, | ||
| 379 | prefix: Option<&str>, | ||
| 380 | shorten_report_to_15_chars: bool, | ||
| 381 | ) -> Result<&mut Self> { | ||
| 339 | self.tester.send_line(input)?; | 382 | self.tester.send_line(input)?; |
| 340 | self.tester | 383 | self.tester |
| 341 | .expect(input) | 384 | .expect(input) |
| @@ -345,9 +388,26 @@ impl CliTesterInputPrompt<'_> { | |||
| 345 | .context("expect new line after input to be printed")?; | 388 | .context("expect new line after input to be printed")?; |
| 346 | 389 | ||
| 347 | let mut s = String::new(); | 390 | let mut s = String::new(); |
| 391 | let printed_input = if shorten_report_to_15_chars { | ||
| 392 | shorten_string(input) | ||
| 393 | } else { | ||
| 394 | input.to_string() | ||
| 395 | }; | ||
| 348 | self.tester | 396 | self.tester |
| 349 | .formatter | 397 | .formatter |
| 350 | .format_input_prompt_selection(&mut s, self.prompt.as_str(), input) | 398 | .format_error( |
| 399 | &mut s, | ||
| 400 | &format!( | ||
| 401 | "{}{}: {}", | ||
| 402 | prefix.unwrap_or_default(), | ||
| 403 | &self.prompt, | ||
| 404 | if input.is_empty() { | ||
| 405 | "empty".to_string() | ||
| 406 | } else { | ||
| 407 | format!("\"{printed_input}\"") | ||
| 408 | } | ||
| 409 | ), | ||
| 410 | ) | ||
| 351 | .expect("diagluer theme formatter should succeed"); | 411 | .expect("diagluer theme formatter should succeed"); |
| 352 | if !s.contains(self.prompt.as_str()) { | 412 | if !s.contains(self.prompt.as_str()) { |
| 353 | panic!("dialoguer must be broken as formatted prompt success doesnt contain prompt"); | 413 | panic!("dialoguer must be broken as formatted prompt success doesnt contain prompt"); |
| @@ -361,6 +421,14 @@ impl CliTesterInputPrompt<'_> { | |||
| 361 | } | 421 | } |
| 362 | } | 422 | } |
| 363 | 423 | ||
| 424 | fn shorten_string(s: &str) -> String { | ||
| 425 | if s.len() < 15 { | ||
| 426 | s.to_string() | ||
| 427 | } else { | ||
| 428 | format!("{}...", &s[..15]) | ||
| 429 | } | ||
| 430 | } | ||
| 431 | |||
| 364 | pub struct CliTesterPasswordPrompt<'a> { | 432 | pub struct CliTesterPasswordPrompt<'a> { |
| 365 | tester: &'a mut CliTester, | 433 | tester: &'a mut CliTester, |
| 366 | prompt: String, | 434 | prompt: String, |
diff --git a/tests/ngit_login.rs b/tests/ngit_login.rs index 4cfe4e6..0a8bc19 100644 --- a/tests/ngit_login.rs +++ b/tests/ngit_login.rs | |||
| @@ -3,44 +3,49 @@ use git::GitTestRepo; | |||
| 3 | use serial_test::serial; | 3 | use serial_test::serial; |
| 4 | use test_utils::*; | 4 | use test_utils::*; |
| 5 | 5 | ||
| 6 | static EXPECTED_NSEC_PROMPT: &str = "login with nsec / bunker url / nostr address"; | 6 | static EXPECTED_NSEC_PROMPT: &str = "nsec"; |
| 7 | static EXPECTED_LOCAL_REPOSITORY_PROMPT: &str = "just for this repository?"; | 7 | |
| 8 | static EXPECTED_REQUIRE_PASSWORD_PROMPT: &str = "require password?"; | 8 | fn show_first_time_login_choices(p: &mut CliTester) -> Result<CliTesterChoicePrompt> { |
| 9 | static EXPECTED_SET_PASSWORD_PROMPT: &str = "encrypt with password"; | 9 | p.expect_choice( |
| 10 | static EXPECTED_SET_PASSWORD_CONFIRM_PROMPT: &str = "confirm password"; | 10 | "login to nostr", |
| 11 | vec![ | ||
| 12 | "secret key (nsec / ncryptsec)".to_string(), | ||
| 13 | "nostr connect (remote signer)".to_string(), | ||
| 14 | "create account".to_string(), | ||
| 15 | "help".to_string(), | ||
| 16 | ], | ||
| 17 | ) | ||
| 18 | } | ||
| 11 | 19 | ||
| 12 | fn standard_first_time_login_encrypting_nsec() -> Result<CliTester> { | 20 | fn first_time_login_choices_succeeds_with_nsec(p: &mut CliTester, nsec: &str) -> Result<()> { |
| 21 | p.expect_choice( | ||
| 22 | "login to nostr", | ||
| 23 | vec![ | ||
| 24 | "secret key (nsec / ncryptsec)".to_string(), | ||
| 25 | "nostr connect (remote signer)".to_string(), | ||
| 26 | "create account".to_string(), | ||
| 27 | "help".to_string(), | ||
| 28 | ], | ||
| 29 | )? | ||
| 30 | .succeeds_with(0, false, Some(0))?; | ||
| 31 | |||
| 32 | p.expect_input(EXPECTED_NSEC_PROMPT)? | ||
| 33 | .succeeds_with_optional_shortened_report(nsec, true)?; | ||
| 34 | |||
| 35 | p.expect("saved login details to local git config. you are only logged in to this local repository.\r\n")?; | ||
| 36 | Ok(()) | ||
| 37 | } | ||
| 38 | |||
| 39 | fn standard_first_time_login_with_nsec() -> Result<CliTester> { | ||
| 13 | let test_repo = GitTestRepo::default(); | 40 | let test_repo = GitTestRepo::default(); |
| 14 | let mut p = CliTester::new_from_dir(&test_repo.dir, ["login", "--offline"]); | 41 | let mut p = CliTester::new_from_dir(&test_repo.dir, ["login", "--offline"]); |
| 15 | 42 | ||
| 16 | p.expect_input_eventually(EXPECTED_NSEC_PROMPT)? | 43 | first_time_login_choices_succeeds_with_nsec(&mut p, TEST_KEY_1_NSEC)?; |
| 17 | .succeeds_with(TEST_KEY_1_NSEC)?; | ||
| 18 | |||
| 19 | p.expect_confirm(EXPECTED_LOCAL_REPOSITORY_PROMPT, Some(false))? | ||
| 20 | .succeeds_with(Some(true))?; | ||
| 21 | |||
| 22 | p.expect_confirm(EXPECTED_REQUIRE_PASSWORD_PROMPT, Some(false))? | ||
| 23 | .succeeds_with(Some(true))?; | ||
| 24 | |||
| 25 | p.expect_password(EXPECTED_SET_PASSWORD_PROMPT)? | ||
| 26 | .with_confirmation(EXPECTED_SET_PASSWORD_CONFIRM_PROMPT)? | ||
| 27 | .succeeds_with(TEST_PASSWORD)?; | ||
| 28 | 44 | ||
| 29 | p.expect_end_eventually()?; | 45 | p.expect_end_eventually()?; |
| 30 | Ok(p) | 46 | Ok(p) |
| 31 | } | 47 | } |
| 32 | 48 | ||
| 33 | fn expect_qr_prompt_opt_for_other_methods(p: &mut CliTester) -> Result<()> { | ||
| 34 | p.expect_eventually("scan QR or paste into remote signer")?; | ||
| 35 | p.expect_eventually("\r\n")?; | ||
| 36 | p.expect_eventually("login with nsec / bunker url / nostr address instead")?; | ||
| 37 | p.expect_eventually("\r\n")?; | ||
| 38 | p.send_line("")?; | ||
| 39 | // p.expect_eventually("\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r")?; | ||
| 40 | // p.expect_eventually("\r\r\r\r\r\r\r\r\r\r\r\r\r")?; | ||
| 41 | |||
| 42 | Ok(()) | ||
| 43 | } | ||
| 44 | mod with_relays { | 49 | mod with_relays { |
| 45 | use anyhow::Ok; | 50 | use anyhow::Ok; |
| 46 | use futures::join; | 51 | use futures::join; |
| @@ -73,21 +78,12 @@ mod with_relays { | |||
| 73 | let cli_tester_handle = std::thread::spawn(move || -> Result<()> { | 78 | let cli_tester_handle = std::thread::spawn(move || -> Result<()> { |
| 74 | let test_repo = GitTestRepo::default(); | 79 | let test_repo = GitTestRepo::default(); |
| 75 | let mut p = CliTester::new_from_dir(&test_repo.dir, ["login"]); | 80 | let mut p = CliTester::new_from_dir(&test_repo.dir, ["login"]); |
| 76 | expect_qr_prompt_opt_for_other_methods(&mut p)?; | ||
| 77 | p.expect_input_eventually(EXPECTED_NSEC_PROMPT)? | ||
| 78 | .succeeds_with(TEST_KEY_1_NSEC)?; | ||
| 79 | |||
| 80 | p.expect_confirm(EXPECTED_LOCAL_REPOSITORY_PROMPT, Some(false))? | ||
| 81 | .succeeds_with(Some(true))?; | ||
| 82 | |||
| 83 | p.expect_confirm(EXPECTED_REQUIRE_PASSWORD_PROMPT, Some(false))? | ||
| 84 | .succeeds_with(Some(false))?; | ||
| 85 | 81 | ||
| 86 | p.expect("saved login details to local git config\r\n")?; | 82 | first_time_login_choices_succeeds_with_nsec(&mut p, TEST_KEY_1_NSEC)?; |
| 87 | 83 | ||
| 88 | p.expect("searching for profile...\r\n")?; | 84 | p.expect("searching for profile...\r\n")?; |
| 89 | 85 | ||
| 90 | p.expect_end_with("logged in as fred via cli arguments\r\n")?; | 86 | p.expect_end_with("logged in as fred\r\n")?; |
| 91 | for p in [51, 52] { | 87 | for p in [51, 52] { |
| 92 | shutdown_relay(8000 + p)?; | 88 | shutdown_relay(8000 + p)?; |
| 93 | } | 89 | } |
| @@ -114,17 +110,7 @@ mod with_relays { | |||
| 114 | let test_repo = GitTestRepo::default(); | 110 | let test_repo = GitTestRepo::default(); |
| 115 | let mut p = CliTester::new_from_dir(&test_repo.dir, ["login"]); | 111 | let mut p = CliTester::new_from_dir(&test_repo.dir, ["login"]); |
| 116 | 112 | ||
| 117 | expect_qr_prompt_opt_for_other_methods(&mut p)?; | 113 | first_time_login_choices_succeeds_with_nsec(&mut p, TEST_KEY_1_NSEC)?; |
| 118 | p.expect_input_eventually(EXPECTED_NSEC_PROMPT)? | ||
| 119 | .succeeds_with(TEST_KEY_1_NSEC)?; | ||
| 120 | |||
| 121 | p.expect_confirm(EXPECTED_LOCAL_REPOSITORY_PROMPT, Some(false))? | ||
| 122 | .succeeds_with(Some(true))?; | ||
| 123 | |||
| 124 | p.expect_confirm(EXPECTED_REQUIRE_PASSWORD_PROMPT, Some(false))? | ||
| 125 | .succeeds_with(Some(false))?; | ||
| 126 | |||
| 127 | p.expect("saved login details to local git config\r\n")?; | ||
| 128 | 114 | ||
| 129 | p.expect("searching for profile...\r\n")?; | 115 | p.expect("searching for profile...\r\n")?; |
| 130 | 116 | ||
| @@ -395,7 +381,7 @@ mod with_relays { | |||
| 395 | .await | 381 | .await |
| 396 | } | 382 | } |
| 397 | 383 | ||
| 398 | mod when_specifying_command_line_nsec_only { | 384 | mod when_specifying_command_line_nsec { |
| 399 | use super::*; | 385 | use super::*; |
| 400 | 386 | ||
| 401 | #[tokio::test] | 387 | #[tokio::test] |
| @@ -433,136 +419,7 @@ mod with_relays { | |||
| 433 | ["login", "--nsec", TEST_KEY_1_NSEC], | 419 | ["login", "--nsec", TEST_KEY_1_NSEC], |
| 434 | ); | 420 | ); |
| 435 | 421 | ||
| 436 | p.expect("saved login details to local git config\r\n")?; | 422 | p.expect("saved login details to local git config. you are only logged in to this local repository.\r\n")?; |
| 437 | |||
| 438 | p.expect("searching for profile...\r\n")?; | ||
| 439 | |||
| 440 | p.expect_end_with("logged in as fred via cli arguments\r\n")?; | ||
| 441 | for p in [51, 52] { | ||
| 442 | shutdown_relay(8000 + p)?; | ||
| 443 | } | ||
| 444 | Ok(()) | ||
| 445 | }); | ||
| 446 | |||
| 447 | // launch relay | ||
| 448 | let _ = join!(r51.listen_until_close(), r52.listen_until_close(),); | ||
| 449 | |||
| 450 | cli_tester_handle.join().unwrap()?; | ||
| 451 | Ok(()) | ||
| 452 | } | ||
| 453 | } | ||
| 454 | mod when_specifying_command_line_password_only { | ||
| 455 | use super::*; | ||
| 456 | |||
| 457 | #[tokio::test] | ||
| 458 | #[serial] | ||
| 459 | async fn displays_correct_name() -> Result<()> { | ||
| 460 | run_test_when_specifying_command_line_password_only_displays_correct_name( | ||
| 461 | Some(&|relay, client_id, subscription_id, _| -> Result<()> { | ||
| 462 | relay.respond_events( | ||
| 463 | client_id, | ||
| 464 | &subscription_id, | ||
| 465 | &vec![ | ||
| 466 | generate_test_key_1_metadata_event("fred"), | ||
| 467 | generate_test_key_1_relay_list_event_same_as_fallback(), | ||
| 468 | ], | ||
| 469 | )?; | ||
| 470 | Ok(()) | ||
| 471 | }), | ||
| 472 | None, | ||
| 473 | ) | ||
| 474 | .await | ||
| 475 | } | ||
| 476 | async fn run_test_when_specifying_command_line_password_only_displays_correct_name( | ||
| 477 | relay_listener1: Option<ListenerReqFunc<'_>>, | ||
| 478 | relay_listener2: Option<ListenerReqFunc<'_>>, | ||
| 479 | ) -> Result<()> { | ||
| 480 | let (mut r51, mut r52) = ( | ||
| 481 | Relay::new(8051, None, relay_listener1), | ||
| 482 | Relay::new(8052, None, relay_listener2), | ||
| 483 | ); | ||
| 484 | |||
| 485 | let cli_tester_handle = std::thread::spawn(move || -> Result<()> { | ||
| 486 | let test_repo = GitTestRepo::default(); | ||
| 487 | CliTester::new_from_dir( | ||
| 488 | &test_repo.dir, | ||
| 489 | [ | ||
| 490 | "login", | ||
| 491 | "--offline", | ||
| 492 | "--nsec", | ||
| 493 | TEST_KEY_1_NSEC, | ||
| 494 | "--password", | ||
| 495 | TEST_PASSWORD, | ||
| 496 | ], | ||
| 497 | ) | ||
| 498 | .expect_end_eventually()?; | ||
| 499 | |||
| 500 | let mut p = CliTester::new_from_dir( | ||
| 501 | &test_repo.dir, | ||
| 502 | ["login", "--password", TEST_PASSWORD], | ||
| 503 | ); | ||
| 504 | |||
| 505 | p.expect("searching for profile...\r\n")?; | ||
| 506 | |||
| 507 | p.expect_end_with("logged in as fred via cli arguments\r\n")?; | ||
| 508 | for p in [51, 52] { | ||
| 509 | shutdown_relay(8000 + p)?; | ||
| 510 | } | ||
| 511 | Ok(()) | ||
| 512 | }); | ||
| 513 | |||
| 514 | // launch relay | ||
| 515 | let _ = join!(r51.listen_until_close(), r52.listen_until_close(),); | ||
| 516 | |||
| 517 | cli_tester_handle.join().unwrap()?; | ||
| 518 | Ok(()) | ||
| 519 | } | ||
| 520 | } | ||
| 521 | |||
| 522 | mod when_specifying_command_line_nsec_and_password { | ||
| 523 | use super::*; | ||
| 524 | |||
| 525 | #[tokio::test] | ||
| 526 | #[serial] | ||
| 527 | async fn displays_correct_name() -> Result<()> { | ||
| 528 | run_test_when_specifying_command_line_nsec_and_password_displays_correct_name( | ||
| 529 | Some(&|relay, client_id, subscription_id, _| -> Result<()> { | ||
| 530 | relay.respond_events( | ||
| 531 | client_id, | ||
| 532 | &subscription_id, | ||
| 533 | &vec![ | ||
| 534 | generate_test_key_1_metadata_event("fred"), | ||
| 535 | generate_test_key_1_relay_list_event_same_as_fallback(), | ||
| 536 | ], | ||
| 537 | )?; | ||
| 538 | Ok(()) | ||
| 539 | }), | ||
| 540 | None, | ||
| 541 | ).await | ||
| 542 | } | ||
| 543 | async fn run_test_when_specifying_command_line_nsec_and_password_displays_correct_name( | ||
| 544 | relay_listener1: Option<ListenerReqFunc<'_>>, | ||
| 545 | relay_listener2: Option<ListenerReqFunc<'_>>, | ||
| 546 | ) -> Result<()> { | ||
| 547 | let (mut r51, mut r52) = ( | ||
| 548 | Relay::new(8051, None, relay_listener1), | ||
| 549 | Relay::new(8052, None, relay_listener2), | ||
| 550 | ); | ||
| 551 | |||
| 552 | let cli_tester_handle = std::thread::spawn(move || -> Result<()> { | ||
| 553 | let test_repo = GitTestRepo::default(); | ||
| 554 | let mut p = CliTester::new_from_dir( | ||
| 555 | &test_repo.dir, | ||
| 556 | [ | ||
| 557 | "login", | ||
| 558 | "--nsec", | ||
| 559 | TEST_KEY_1_NSEC, | ||
| 560 | "--password", | ||
| 561 | TEST_PASSWORD, | ||
| 562 | ], | ||
| 563 | ); | ||
| 564 | |||
| 565 | p.expect("saved login details to local git config\r\n")?; | ||
| 566 | 423 | ||
| 567 | p.expect("searching for profile...\r\n")?; | 424 | p.expect("searching for profile...\r\n")?; |
| 568 | 425 | ||
| @@ -581,7 +438,6 @@ mod with_relays { | |||
| 581 | } | 438 | } |
| 582 | } | 439 | } |
| 583 | } | 440 | } |
| 584 | |||
| 585 | mod when_no_metadata_found { | 441 | mod when_no_metadata_found { |
| 586 | use super::*; | 442 | use super::*; |
| 587 | 443 | ||
| @@ -604,17 +460,7 @@ mod with_relays { | |||
| 604 | let test_repo = GitTestRepo::default(); | 460 | let test_repo = GitTestRepo::default(); |
| 605 | let mut p = CliTester::new_from_dir(&test_repo.dir, ["login"]); | 461 | let mut p = CliTester::new_from_dir(&test_repo.dir, ["login"]); |
| 606 | 462 | ||
| 607 | expect_qr_prompt_opt_for_other_methods(&mut p)?; | 463 | first_time_login_choices_succeeds_with_nsec(&mut p, TEST_KEY_1_NSEC)?; |
| 608 | p.expect_input_eventually(EXPECTED_NSEC_PROMPT)? | ||
| 609 | .succeeds_with(TEST_KEY_1_NSEC)?; | ||
| 610 | |||
| 611 | p.expect_confirm(EXPECTED_LOCAL_REPOSITORY_PROMPT, Some(false))? | ||
| 612 | .succeeds_with(Some(true))?; | ||
| 613 | |||
| 614 | p.expect_confirm(EXPECTED_REQUIRE_PASSWORD_PROMPT, Some(false))? | ||
| 615 | .succeeds_with(Some(false))?; | ||
| 616 | |||
| 617 | p.expect("saved login details to local git config\r\n")?; | ||
| 618 | 464 | ||
| 619 | p.expect("searching for profile...\r\n")?; | 465 | p.expect("searching for profile...\r\n")?; |
| 620 | 466 | ||
| @@ -668,17 +514,7 @@ mod with_relays { | |||
| 668 | let test_repo = GitTestRepo::default(); | 514 | let test_repo = GitTestRepo::default(); |
| 669 | let mut p = CliTester::new_from_dir(&test_repo.dir, ["login"]); | 515 | let mut p = CliTester::new_from_dir(&test_repo.dir, ["login"]); |
| 670 | 516 | ||
| 671 | expect_qr_prompt_opt_for_other_methods(&mut p)?; | 517 | first_time_login_choices_succeeds_with_nsec(&mut p, TEST_KEY_1_NSEC)?; |
| 672 | p.expect_input_eventually(EXPECTED_NSEC_PROMPT)? | ||
| 673 | .succeeds_with(TEST_KEY_1_NSEC)?; | ||
| 674 | |||
| 675 | p.expect_confirm(EXPECTED_LOCAL_REPOSITORY_PROMPT, Some(false))? | ||
| 676 | .succeeds_with(Some(true))?; | ||
| 677 | |||
| 678 | p.expect_confirm(EXPECTED_REQUIRE_PASSWORD_PROMPT, Some(false))? | ||
| 679 | .succeeds_with(Some(false))?; | ||
| 680 | |||
| 681 | p.expect("saved login details to local git config\r\n")?; | ||
| 682 | 518 | ||
| 683 | p.expect("searching for profile...\r\n")?; | 519 | p.expect("searching for profile...\r\n")?; |
| 684 | 520 | ||
| @@ -699,79 +535,6 @@ mod with_relays { | |||
| 699 | } | 535 | } |
| 700 | } | 536 | } |
| 701 | } | 537 | } |
| 702 | |||
| 703 | mod when_second_time_login_and_details_already_fetched { | ||
| 704 | use super::*; | ||
| 705 | |||
| 706 | mod uses_cache_and_stores_and_retrieves_ncryptsec_from_local_git_config { | ||
| 707 | use super::*; | ||
| 708 | |||
| 709 | #[tokio::test] | ||
| 710 | #[serial] | ||
| 711 | async fn dislays_logged_in_with_correct_name() -> Result<()> { | ||
| 712 | run_test_dislays_logged_in_with_correct_name(Some( | ||
| 713 | &|relay, client_id, subscription_id, _| -> Result<()> { | ||
| 714 | relay.respond_events( | ||
| 715 | client_id, | ||
| 716 | &subscription_id, | ||
| 717 | &vec![ | ||
| 718 | generate_test_key_1_metadata_event("fred"), | ||
| 719 | generate_test_key_1_relay_list_event_same_as_fallback(), | ||
| 720 | ], | ||
| 721 | )?; | ||
| 722 | Ok(()) | ||
| 723 | }, | ||
| 724 | )) | ||
| 725 | .await | ||
| 726 | } | ||
| 727 | async fn run_test_dislays_logged_in_with_correct_name( | ||
| 728 | relay_listener: Option<ListenerReqFunc<'_>>, | ||
| 729 | ) -> Result<()> { | ||
| 730 | let (mut r51, mut r52) = ( | ||
| 731 | Relay::new(8051, None, relay_listener), | ||
| 732 | Relay::new(8052, None, None), | ||
| 733 | ); | ||
| 734 | |||
| 735 | let cli_tester_handle = std::thread::spawn(move || -> Result<()> { | ||
| 736 | let test_repo = GitTestRepo::default(); | ||
| 737 | let mut p = CliTester::new_from_dir( | ||
| 738 | &test_repo.dir, | ||
| 739 | [ | ||
| 740 | "login", | ||
| 741 | "--nsec", | ||
| 742 | TEST_KEY_1_NSEC, | ||
| 743 | "--password", | ||
| 744 | TEST_PASSWORD, | ||
| 745 | ], | ||
| 746 | ); | ||
| 747 | |||
| 748 | p.expect("saved login details to local git config\r\n")?; | ||
| 749 | |||
| 750 | p.expect_end_eventually_with("logged in as fred via cli arguments\r\n")?; | ||
| 751 | |||
| 752 | for p in [51, 52] { | ||
| 753 | shutdown_relay(8000 + p)?; | ||
| 754 | } | ||
| 755 | |||
| 756 | let mut p = CliTester::new_from_dir( | ||
| 757 | &test_repo.dir, | ||
| 758 | ["login", "--password", TEST_PASSWORD], | ||
| 759 | ); | ||
| 760 | |||
| 761 | p.expect_end_eventually_with("logged in as fred\r\n")?; | ||
| 762 | |||
| 763 | Ok(()) | ||
| 764 | }); | ||
| 765 | |||
| 766 | // launch relay | ||
| 767 | let _ = join!(r51.listen_until_close(), r52.listen_until_close(),); | ||
| 768 | |||
| 769 | cli_tester_handle.join().unwrap()?; | ||
| 770 | |||
| 771 | Ok(()) | ||
| 772 | } | ||
| 773 | } | ||
| 774 | } | ||
| 775 | } | 538 | } |
| 776 | mod when_user_relay_list_contains_write_relays_not_in_fallback_list { | 539 | mod when_user_relay_list_contains_write_relays_not_in_fallback_list { |
| 777 | use super::*; | 540 | use super::*; |
| @@ -792,17 +555,7 @@ mod with_relays { | |||
| 792 | let test_repo = GitTestRepo::default(); | 555 | let test_repo = GitTestRepo::default(); |
| 793 | let mut p = CliTester::new_from_dir(&test_repo.dir, ["login"]); | 556 | let mut p = CliTester::new_from_dir(&test_repo.dir, ["login"]); |
| 794 | 557 | ||
| 795 | expect_qr_prompt_opt_for_other_methods(&mut p)?; | 558 | first_time_login_choices_succeeds_with_nsec(&mut p, TEST_KEY_1_NSEC)?; |
| 796 | p.expect_input_eventually(EXPECTED_NSEC_PROMPT)? | ||
| 797 | .succeeds_with(TEST_KEY_1_NSEC)?; | ||
| 798 | |||
| 799 | p.expect_confirm(EXPECTED_LOCAL_REPOSITORY_PROMPT, Some(false))? | ||
| 800 | .succeeds_with(Some(true))?; | ||
| 801 | |||
| 802 | p.expect_confirm(EXPECTED_REQUIRE_PASSWORD_PROMPT, Some(false))? | ||
| 803 | .succeeds_with(Some(false))?; | ||
| 804 | |||
| 805 | p.expect("saved login details to local git config\r\n")?; | ||
| 806 | 559 | ||
| 807 | p.expect("searching for profile...\r\n")?; | 560 | p.expect("searching for profile...\r\n")?; |
| 808 | 561 | ||
| @@ -868,7 +621,7 @@ mod with_offline_flag { | |||
| 868 | 621 | ||
| 869 | #[test] | 622 | #[test] |
| 870 | fn prompts_for_nsec_and_password() -> Result<()> { | 623 | fn prompts_for_nsec_and_password() -> Result<()> { |
| 871 | standard_first_time_login_encrypting_nsec()?; | 624 | standard_first_time_login_with_nsec()?; |
| 872 | Ok(()) | 625 | Ok(()) |
| 873 | } | 626 | } |
| 874 | 627 | ||
| @@ -877,20 +630,12 @@ mod with_offline_flag { | |||
| 877 | let test_repo = GitTestRepo::default(); | 630 | let test_repo = GitTestRepo::default(); |
| 878 | let mut p = CliTester::new_from_dir(&test_repo.dir, ["login", "--offline"]); | 631 | let mut p = CliTester::new_from_dir(&test_repo.dir, ["login", "--offline"]); |
| 879 | 632 | ||
| 880 | p.expect_input(EXPECTED_NSEC_PROMPT)? | 633 | show_first_time_login_choices(&mut p)?.succeeds_with(0, false, Some(0))?; |
| 881 | .succeeds_with(TEST_KEY_1_NSEC)?; | ||
| 882 | |||
| 883 | p.expect_confirm(EXPECTED_LOCAL_REPOSITORY_PROMPT, Some(false))? | ||
| 884 | .succeeds_with(Some(true))?; | ||
| 885 | |||
| 886 | p.expect_confirm(EXPECTED_REQUIRE_PASSWORD_PROMPT, Some(false))? | ||
| 887 | .succeeds_with(Some(true))?; | ||
| 888 | 634 | ||
| 889 | p.expect_password(EXPECTED_SET_PASSWORD_PROMPT)? | 635 | p.expect_input(EXPECTED_NSEC_PROMPT)? |
| 890 | .with_confirmation(EXPECTED_SET_PASSWORD_CONFIRM_PROMPT)? | 636 | .succeeds_with_optional_shortened_report(TEST_KEY_1_NSEC, true)?; |
| 891 | .succeeds_with(TEST_PASSWORD)?; | ||
| 892 | 637 | ||
| 893 | p.expect("saved login details to local git config\r\n")?; | 638 | p.expect("saved login details to local git config. you are only logged in to this local repository.\r\n")?; |
| 894 | 639 | ||
| 895 | p.expect_end_with(format!("logged in as {}\r\n", TEST_KEY_1_NPUB).as_str()) | 640 | p.expect_end_with(format!("logged in as {}\r\n", TEST_KEY_1_NPUB).as_str()) |
| 896 | } | 641 | } |
| @@ -900,20 +645,12 @@ mod with_offline_flag { | |||
| 900 | let test_repo = GitTestRepo::default(); | 645 | let test_repo = GitTestRepo::default(); |
| 901 | let mut p = CliTester::new_from_dir(&test_repo.dir, ["login", "--offline"]); | 646 | let mut p = CliTester::new_from_dir(&test_repo.dir, ["login", "--offline"]); |
| 902 | 647 | ||
| 903 | p.expect_input(EXPECTED_NSEC_PROMPT)? | 648 | show_first_time_login_choices(&mut p)?.succeeds_with(0, false, Some(0))?; |
| 904 | .succeeds_with(TEST_KEY_1_SK_HEX)?; | ||
| 905 | |||
| 906 | p.expect_confirm(EXPECTED_LOCAL_REPOSITORY_PROMPT, Some(false))? | ||
| 907 | .succeeds_with(Some(true))?; | ||
| 908 | 649 | ||
| 909 | p.expect_confirm(EXPECTED_REQUIRE_PASSWORD_PROMPT, Some(false))? | 650 | p.expect_input(EXPECTED_NSEC_PROMPT)? |
| 910 | .succeeds_with(Some(true))?; | 651 | .succeeds_with_optional_shortened_report(TEST_KEY_1_SK_HEX, true)?; |
| 911 | |||
| 912 | p.expect_password(EXPECTED_SET_PASSWORD_PROMPT)? | ||
| 913 | .with_confirmation(EXPECTED_SET_PASSWORD_CONFIRM_PROMPT)? | ||
| 914 | .succeeds_with(TEST_PASSWORD)?; | ||
| 915 | 652 | ||
| 916 | p.expect("saved login details to local git config\r\n")?; | 653 | p.expect("saved login details to local git config. you are only logged in to this local repository.\r\n")?; |
| 917 | 654 | ||
| 918 | p.expect_end_with(format!("logged in as {}\r\n", TEST_KEY_1_NPUB).as_str()) | 655 | p.expect_end_with(format!("logged in as {}\r\n", TEST_KEY_1_NPUB).as_str()) |
| 919 | } | 656 | } |
| @@ -923,35 +660,30 @@ mod with_offline_flag { | |||
| 923 | 660 | ||
| 924 | #[test] | 661 | #[test] |
| 925 | fn prompts_for_nsec_until_valid() -> Result<()> { | 662 | fn prompts_for_nsec_until_valid() -> Result<()> { |
| 926 | let invalid_nsec_response = | ||
| 927 | "invalid. try again with nostr address / bunker uri / nsec"; | ||
| 928 | |||
| 929 | let test_repo = GitTestRepo::default(); | 663 | let test_repo = GitTestRepo::default(); |
| 930 | let mut p = CliTester::new_from_dir(&test_repo.dir, ["login", "--offline"]); | 664 | let mut p = CliTester::new_from_dir(&test_repo.dir, ["login", "--offline"]); |
| 931 | 665 | ||
| 932 | p.expect_input(EXPECTED_NSEC_PROMPT)? | 666 | show_first_time_login_choices(&mut p)?.succeeds_with(0, false, Some(0))?; |
| 933 | // this behaviour is intentional. rejecting the response with dialoguer | ||
| 934 | // hides the original input from the user so they | ||
| 935 | // failed to see the mistake they made. | ||
| 936 | .succeeds_with(TEST_INVALID_NSEC)?; | ||
| 937 | |||
| 938 | p.expect_input(invalid_nsec_response)? | ||
| 939 | .succeeds_with(TEST_INVALID_NSEC)?; | ||
| 940 | |||
| 941 | p.expect_input(invalid_nsec_response)? | ||
| 942 | .succeeds_with(TEST_KEY_1_NSEC)?; | ||
| 943 | 667 | ||
| 944 | p.expect_confirm(EXPECTED_LOCAL_REPOSITORY_PROMPT, Some(false))? | 668 | for _ in 0..2 { |
| 945 | .succeeds_with(Some(true))?; | 669 | p.expect_input(EXPECTED_NSEC_PROMPT)? |
| 670 | .fails_with_optional_shortened_report( | ||
| 671 | TEST_INVALID_NSEC, | ||
| 672 | Some("invalid "), | ||
| 673 | true, | ||
| 674 | )?; | ||
| 946 | 675 | ||
| 947 | p.expect_confirm(EXPECTED_REQUIRE_PASSWORD_PROMPT, Some(false))? | 676 | p.expect_choice( |
| 948 | .succeeds_with(Some(true))?; | 677 | "login to nostr", |
| 678 | vec!["try again with nsec".to_string(), "back".to_string()], | ||
| 679 | )? | ||
| 680 | .succeeds_with(0, false, Some(0))?; | ||
| 681 | } | ||
| 949 | 682 | ||
| 950 | p.expect_password(EXPECTED_SET_PASSWORD_PROMPT)? | 683 | p.expect_input(EXPECTED_NSEC_PROMPT)? |
| 951 | .with_confirmation(EXPECTED_SET_PASSWORD_CONFIRM_PROMPT)? | 684 | .succeeds_with_optional_shortened_report(TEST_KEY_1_NSEC, true)?; |
| 952 | .succeeds_with(TEST_PASSWORD)?; | ||
| 953 | 685 | ||
| 954 | p.expect("saved login details to local git config\r\n")?; | 686 | p.expect("saved login details to local git config. you are only logged in to this local repository.\r\n")?; |
| 955 | 687 | ||
| 956 | p.expect_end_with(format!("logged in as {}\r\n", TEST_KEY_1_NPUB).as_str()) | 688 | p.expect_end_with(format!("logged in as {}\r\n", TEST_KEY_1_NPUB).as_str()) |
| 957 | } | 689 | } |
| @@ -969,49 +701,14 @@ mod with_offline_flag { | |||
| 969 | ["login", "--offline", "--nsec", TEST_KEY_1_NSEC], | 701 | ["login", "--offline", "--nsec", TEST_KEY_1_NSEC], |
| 970 | ); | 702 | ); |
| 971 | 703 | ||
| 972 | p.expect("saved login details to local git config\r\n")?; | 704 | p.expect("saved login details to local git config. you are only logged in to this local repository.\r\n")?; |
| 973 | 705 | ||
| 974 | p.expect_end_with(format!("logged in as {}\r\n", TEST_KEY_1_NPUB).as_str()) | 706 | p.expect_end_with( |
| 707 | format!("logged in as {} via cli arguments\r\n", TEST_KEY_1_NPUB).as_str(), | ||
| 708 | ) | ||
| 975 | } | 709 | } |
| 976 | 710 | ||
| 977 | #[test] | 711 | #[test] |
| 978 | fn forgets_identity() -> Result<()> { | ||
| 979 | let test_repo = GitTestRepo::default(); | ||
| 980 | let mut p = CliTester::new_from_dir( | ||
| 981 | &test_repo.dir, | ||
| 982 | ["login", "--offline", "--nsec", TEST_KEY_1_NSEC], | ||
| 983 | ); | ||
| 984 | |||
| 985 | p.expect("saved login details to local git config\r\n")?; | ||
| 986 | |||
| 987 | p.expect_end_with(format!("logged in as {}\r\n", TEST_KEY_1_NPUB).as_str())?; | ||
| 988 | |||
| 989 | p = CliTester::new_from_dir(&test_repo.dir, ["login", "--offline"]); | ||
| 990 | |||
| 991 | p.expect_input(EXPECTED_NSEC_PROMPT)? | ||
| 992 | .succeeds_with(TEST_KEY_1_NSEC)?; | ||
| 993 | |||
| 994 | p.exit() | ||
| 995 | } | ||
| 996 | |||
| 997 | mod when_logging_in_as_different_nsec { | ||
| 998 | use super::*; | ||
| 999 | |||
| 1000 | #[test] | ||
| 1001 | fn valid_nsec_param_succeeds_without_prompts_and_logs_in() -> Result<()> { | ||
| 1002 | standard_first_time_login_encrypting_nsec()?.exit()?; | ||
| 1003 | let test_repo = GitTestRepo::default(); | ||
| 1004 | let mut p = CliTester::new_from_dir( | ||
| 1005 | &test_repo.dir, | ||
| 1006 | ["login", "--offline", "--nsec", TEST_KEY_2_NSEC], | ||
| 1007 | ); | ||
| 1008 | |||
| 1009 | p.expect("saved login details to local git config\r\n")?; | ||
| 1010 | |||
| 1011 | p.expect_end_with(format!("logged in as {}\r\n", TEST_KEY_2_NPUB).as_str()) | ||
| 1012 | } | ||
| 1013 | } | ||
| 1014 | #[test] | ||
| 1015 | fn invalid_nsec_param_fails_without_prompts() -> Result<()> { | 712 | fn invalid_nsec_param_fails_without_prompts() -> Result<()> { |
| 1016 | let test_repo = GitTestRepo::default(); | 713 | let test_repo = GitTestRepo::default(); |
| 1017 | let mut p = CliTester::new_from_dir( | 714 | let mut p = CliTester::new_from_dir( |
| @@ -1042,8 +739,11 @@ mod with_offline_flag { | |||
| 1042 | TEST_PASSWORD, | 739 | TEST_PASSWORD, |
| 1043 | ], | 740 | ], |
| 1044 | ); | 741 | ); |
| 1045 | p.expect("saved login details to local git config\r\n")?; | 742 | p.expect("saved login details to local git config. you are only logged in to this local repository.\r\n")?; |
| 1046 | p.expect_end_with(format!("logged in as {}\r\n", TEST_KEY_1_NPUB).as_str()) | 743 | |
| 744 | p.expect_end_with( | ||
| 745 | format!("logged in as {} via cli arguments\r\n", TEST_KEY_1_NPUB).as_str(), | ||
| 746 | ) | ||
| 1047 | } | 747 | } |
| 1048 | 748 | ||
| 1049 | #[test] | 749 | #[test] |
| @@ -1060,8 +760,11 @@ mod with_offline_flag { | |||
| 1060 | "--offline", | 760 | "--offline", |
| 1061 | ], | 761 | ], |
| 1062 | ); | 762 | ); |
| 1063 | p.expect("saved login details to local git config\r\n")?; | 763 | p.expect("saved login details to local git config. you are only logged in to this local repository.\r\n")?; |
| 1064 | p.expect_end_with(format!("logged in as {}\r\n", TEST_KEY_1_NPUB).as_str()) | 764 | |
| 765 | p.expect_end_with( | ||
| 766 | format!("logged in as {} via cli arguments\r\n", TEST_KEY_1_NPUB).as_str(), | ||
| 767 | ) | ||
| 1065 | } | 768 | } |
| 1066 | 769 | ||
| 1067 | mod when_logging_in_as_different_nsec { | 770 | mod when_logging_in_as_different_nsec { |
| @@ -1069,7 +772,7 @@ mod with_offline_flag { | |||
| 1069 | 772 | ||
| 1070 | #[test] | 773 | #[test] |
| 1071 | fn valid_nsec_param_succeeds_without_prompts_and_logs_in() -> Result<()> { | 774 | fn valid_nsec_param_succeeds_without_prompts_and_logs_in() -> Result<()> { |
| 1072 | standard_first_time_login_encrypting_nsec()?.exit()?; | 775 | standard_first_time_login_with_nsec()?.exit()?; |
| 1073 | let test_repo = GitTestRepo::default(); | 776 | let test_repo = GitTestRepo::default(); |
| 1074 | let mut p = CliTester::new_from_dir( | 777 | let mut p = CliTester::new_from_dir( |
| 1075 | &test_repo.dir, | 778 | &test_repo.dir, |
| @@ -1082,105 +785,12 @@ mod with_offline_flag { | |||
| 1082 | TEST_PASSWORD, | 785 | TEST_PASSWORD, |
| 1083 | ], | 786 | ], |
| 1084 | ); | 787 | ); |
| 1085 | p.expect("saved login details to local git config\r\n")?; | 788 | p.expect("saved login details to local git config. you are only logged in to this local repository.\r\n")?; |
| 1086 | p.expect_end_with(format!("logged in as {}\r\n", TEST_KEY_2_NPUB).as_str()) | ||
| 1087 | } | ||
| 1088 | } | ||
| 1089 | |||
| 1090 | mod when_provided_with_new_password { | ||
| 1091 | use super::*; | ||
| 1092 | |||
| 1093 | #[test] | ||
| 1094 | fn password_changes() -> Result<()> { | ||
| 1095 | standard_first_time_login_encrypting_nsec()?.exit()?; | ||
| 1096 | let test_repo = GitTestRepo::default(); | ||
| 1097 | let mut p = CliTester::new_from_dir( | ||
| 1098 | &test_repo.dir, | ||
| 1099 | [ | ||
| 1100 | "login", | ||
| 1101 | "--offline", | ||
| 1102 | "--nsec", | ||
| 1103 | TEST_KEY_1_NSEC, | ||
| 1104 | "--password", | ||
| 1105 | TEST_INVALID_PASSWORD, | ||
| 1106 | ], | ||
| 1107 | ); | ||
| 1108 | p.expect("saved login details to local git config\r\n")?; | ||
| 1109 | p.expect_end_with(format!("logged in as {}\r\n", TEST_KEY_1_NPUB).as_str())?; | ||
| 1110 | 789 | ||
| 1111 | CliTester::new_from_dir( | 790 | p.expect_end_with( |
| 1112 | &test_repo.dir, | 791 | format!("logged in as {} via cli arguments\r\n", TEST_KEY_2_NPUB).as_str(), |
| 1113 | ["--password", TEST_INVALID_PASSWORD, "login", "--offline"], | ||
| 1114 | ) | 792 | ) |
| 1115 | .expect_end_with(format!("logged in as {}\r\n", TEST_KEY_1_NPUB).as_str()) | ||
| 1116 | } | 793 | } |
| 1117 | } | 794 | } |
| 1118 | |||
| 1119 | #[test] | ||
| 1120 | fn invalid_nsec_param_fails_without_prompts() -> Result<()> { | ||
| 1121 | let test_repo = GitTestRepo::default(); | ||
| 1122 | let mut p = CliTester::new_from_dir( | ||
| 1123 | &test_repo.dir, | ||
| 1124 | [ | ||
| 1125 | "login", | ||
| 1126 | "--offline", | ||
| 1127 | "--nsec", | ||
| 1128 | TEST_INVALID_NSEC, | ||
| 1129 | "--password", | ||
| 1130 | TEST_PASSWORD, | ||
| 1131 | ], | ||
| 1132 | ); | ||
| 1133 | p.expect_end_with( | ||
| 1134 | "Error: invalid nsec parameter\r\n\r\nCaused by:\r\n Invalid secret key\r\n", | ||
| 1135 | ) | ||
| 1136 | } | ||
| 1137 | } | ||
| 1138 | |||
| 1139 | mod when_weak_password { | ||
| 1140 | use super::*; | ||
| 1141 | |||
| 1142 | #[test] | ||
| 1143 | #[serial] | ||
| 1144 | // combined into a single test as it is computationally expensive to run | ||
| 1145 | fn warns_it_might_take_a_few_seconds_then_succeeds_then_second_login_prompts_for_password_then_warns_again_then_succeeds() | ||
| 1146 | -> Result<()> { | ||
| 1147 | let test_repo = GitTestRepo::default(); | ||
| 1148 | let mut p = | ||
| 1149 | CliTester::new_with_timeout_from_dir(15000, &test_repo.dir, ["login", "--offline"]); | ||
| 1150 | |||
| 1151 | p.expect_input(EXPECTED_NSEC_PROMPT)? | ||
| 1152 | .succeeds_with(TEST_KEY_1_NSEC)?; | ||
| 1153 | |||
| 1154 | p.expect_confirm(EXPECTED_LOCAL_REPOSITORY_PROMPT, Some(false))? | ||
| 1155 | .succeeds_with(Some(true))?; | ||
| 1156 | |||
| 1157 | p.expect_confirm(EXPECTED_REQUIRE_PASSWORD_PROMPT, Some(false))? | ||
| 1158 | .succeeds_with(Some(true))?; | ||
| 1159 | |||
| 1160 | p.expect_password(EXPECTED_SET_PASSWORD_PROMPT)? | ||
| 1161 | .with_confirmation(EXPECTED_SET_PASSWORD_CONFIRM_PROMPT)? | ||
| 1162 | .succeeds_with(TEST_WEAK_PASSWORD)?; | ||
| 1163 | |||
| 1164 | p.expect("this may take a few seconds...\r\n")?; | ||
| 1165 | |||
| 1166 | p.expect("saved login details to local git config\r\n")?; | ||
| 1167 | |||
| 1168 | p.expect_end_with(format!("logged in as {}\r\n", TEST_KEY_1_NPUB).as_str()) | ||
| 1169 | |||
| 1170 | // commented out as 'login' command now assumes you want to | ||
| 1171 | // login as a new user | ||
| 1172 | // p = CliTester::new_with_timeout(10000, ["login", | ||
| 1173 | // "--offline"]); | ||
| 1174 | |||
| 1175 | // p.expect(format!("login as {}\r\n", | ||
| 1176 | // TEST_KEY_1_NPUB).as_str())? | ||
| 1177 | // .expect_password(EXPECTED_PASSWORD_PROMPT)? | ||
| 1178 | // .succeeds_with(TEST_WEAK_PASSWORD)?; | ||
| 1179 | |||
| 1180 | // p.expect("this may take a few seconds...\r\n")?; | ||
| 1181 | |||
| 1182 | // p.expect_end_with(format!("logged in as {}\r\n", | ||
| 1183 | // TEST_KEY_1_NPUB).as_str()) | ||
| 1184 | } | ||
| 1185 | } | 795 | } |
| 1186 | } | 796 | } |