diff options
Diffstat (limited to 'src/bin/client/repl.rs')
| -rw-r--r-- | src/bin/client/repl.rs | 57 |
1 files changed, 46 insertions, 11 deletions
diff --git a/src/bin/client/repl.rs b/src/bin/client/repl.rs index 9af4ea9..d973596 100644 --- a/src/bin/client/repl.rs +++ b/src/bin/client/repl.rs | |||
| @@ -245,7 +245,19 @@ impl ClientState { | |||
| 245 | Effect::ForgetHost(target) => { | 245 | Effect::ForgetHost(target) => { |
| 246 | self.commit_prompt_line(); | 246 | self.commit_prompt_line(); |
| 247 | match database::forget_host(&self.conn, &target) { | 247 | match database::forget_host(&self.conn, &target) { |
| 248 | Ok(_) => println!("Cleared trust and stored credentials for {}.", target), | 248 | Ok(outcome) if outcome.credentials_removed => println!( |
| 249 | "Cleared trust and stored credentials for {}.", | ||
| 250 | target | ||
| 251 | ), | ||
| 252 | Ok(outcome) => { | ||
| 253 | println!("Cleared trust for {}.", target); | ||
| 254 | if !outcome.siblings.is_empty() { | ||
| 255 | println!( | ||
| 256 | "Stored credentials kept: this server is still reachable as {}.", | ||
| 257 | outcome.siblings.join(", ") | ||
| 258 | ); | ||
| 259 | } | ||
| 260 | } | ||
| 249 | Err(error) => println!("Failed to forget host: {}", error), | 261 | Err(error) => println!("Failed to forget host: {}", error), |
| 250 | } | 262 | } |
| 251 | } | 263 | } |
| @@ -506,12 +518,17 @@ impl ClientState { | |||
| 506 | let response = response.trim(); | 518 | let response = response.trim(); |
| 507 | 519 | ||
| 508 | if response.starts_with("OK") { | 520 | if response.starts_with("OK") { |
| 509 | if let Some(addr) = &self.addr { | 521 | match self.trusted_identity() { |
| 510 | if let Err(error) = | 522 | Some(identity) => { |
| 511 | database::save_credentials(&self.conn, addr, &username, &hashed) | 523 | if let Err(error) = |
| 512 | { | 524 | database::save_credentials(&self.conn, &identity, &username, &hashed) |
| 513 | println!("Failed to save credentials: {}", error); | 525 | { |
| 526 | println!("Failed to save credentials: {}", error); | ||
| 527 | } | ||
| 514 | } | 528 | } |
| 529 | None => println!( | ||
| 530 | "Credentials not saved: no verified certificate identity for this host." | ||
| 531 | ), | ||
| 515 | } | 532 | } |
| 516 | self.core.set_logged_in(Some(username.clone())); | 533 | self.core.set_logged_in(Some(username.clone())); |
| 517 | println!("Logged in as {}", username); | 534 | println!("Logged in as {}", username); |
| @@ -567,14 +584,27 @@ impl ClientState { | |||
| 567 | return; | 584 | return; |
| 568 | } | 585 | } |
| 569 | let hashed = format!("{:x}", Sha256::digest(password.as_bytes())); | 586 | let hashed = format!("{:x}", Sha256::digest(password.as_bytes())); |
| 570 | if let Some(addr) = &self.addr { | 587 | let Some(identity) = self.trusted_identity() else { |
| 571 | match database::save_credentials(&self.conn, addr, &username, &hashed) { | 588 | println!( |
| 572 | Ok(_) => println!("Credentials saved for {}", addr), | 589 | "No verified certificate for this host. Connect first so its key can be trusted." |
| 573 | Err(error) => println!("Failed to save credentials: {}", error), | 590 | ); |
| 574 | } | 591 | return; |
| 592 | }; | ||
| 593 | match database::save_credentials(&self.conn, &identity, &username, &hashed) { | ||
| 594 | Ok(_) => println!( | ||
| 595 | "Credentials saved for server {} (every address with this key).", | ||
| 596 | short_fingerprint(&identity) | ||
| 597 | ), | ||
| 598 | Err(error) => println!("Failed to save credentials: {}", error), | ||
| 575 | } | 599 | } |
| 576 | } | 600 | } |
| 577 | 601 | ||
| 602 | /// Certificate identity of the current address, once it has been verified. | ||
| 603 | fn trusted_identity(&self) -> Option<String> { | ||
| 604 | let addr = self.addr.as_deref()?; | ||
| 605 | database::get_fingerprint(&self.conn, addr) | ||
| 606 | } | ||
| 607 | |||
| 578 | fn list_hosts(&mut self) { | 608 | fn list_hosts(&mut self) { |
| 579 | let hosts = database::get_all_hosts(&self.conn); | 609 | let hosts = database::get_all_hosts(&self.conn); |
| 580 | for line in host_lines(&hosts) { | 610 | for line in host_lines(&hosts) { |
| @@ -583,6 +613,11 @@ impl ClientState { | |||
| 583 | } | 613 | } |
| 584 | } | 614 | } |
| 585 | 615 | ||
| 616 | /// First few hex characters of a fingerprint, enough to tell servers apart. | ||
| 617 | fn short_fingerprint(fingerprint: &str) -> String { | ||
| 618 | fingerprint.chars().take(16).collect() | ||
| 619 | } | ||
| 620 | |||
| 586 | fn style_roulette_number(text: &str, number: u8) -> String { | 621 | fn style_roulette_number(text: &str, number: u8) -> String { |
| 587 | match roulette_color(number) { | 622 | match roulette_color(number) { |
| 588 | "red" => text.red().to_string(), | 623 | "red" => text.red().to_string(), |
