put: report through the view and ask the host-key question through the Prompter
put() loses its MultiProgress parameter: the summary, pre-flight and connection spinners become view messages, the per-file SFTP transfer reports determinate progress through view.progress (upload_file takes a byte-count callback instead of an indicatif bar), and the display is released through view.suspend on every exit path. The hardcoded trust-on-first-use prompt in the SSH host-key verification becomes the Prompter::accept_host_key port (fail-closed by default; the terminal prompter prints the authenticity banner and confirms), so a remote frontend can surface its own host-key dialog.
This commit is contained in:
+9
-11
@@ -20,14 +20,13 @@ use std::net::{SocketAddr, TcpStream, ToSocketAddrs};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::time::Duration;
|
||||
|
||||
use indicatif::ProgressBar;
|
||||
use log::debug;
|
||||
use serde::Deserialize;
|
||||
use sha2::{Digest, Sha256};
|
||||
use ssh2::{CheckResult, HostKeyType, KnownHostFileKind, KnownHosts, Session};
|
||||
|
||||
use crate::data::embed_data;
|
||||
use crate::ui::prompt;
|
||||
use crate::report::Prompter;
|
||||
|
||||
/// Pinned SSH host key fingerprints, loaded from the bundled
|
||||
/// `host_keys.yml` data file (same pattern as `distro_info.yml`): data
|
||||
@@ -303,6 +302,7 @@ pub fn connect(
|
||||
port: u16,
|
||||
login: &str,
|
||||
config: &SshConfig,
|
||||
prompter: &dyn Prompter,
|
||||
) -> Result<Session, Box<dyn std::error::Error>> {
|
||||
let tcp = tcp_connect(host, port)?;
|
||||
|
||||
@@ -326,7 +326,7 @@ pub fn connect(
|
||||
let (key, key_type) = session
|
||||
.host_key()
|
||||
.ok_or_else(|| format!("{host} offered no host key"))?;
|
||||
verify_host_key(host, port, key, key_type)?;
|
||||
verify_host_key(host, port, key, key_type, prompter)?;
|
||||
|
||||
authenticate(&session, host, login, config)?;
|
||||
|
||||
@@ -353,6 +353,7 @@ fn verify_host_key(
|
||||
port: u16,
|
||||
key: &[u8],
|
||||
key_type: HostKeyType,
|
||||
prompter: &dyn Prompter,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let fingerprint = fingerprint(key);
|
||||
|
||||
@@ -387,12 +388,7 @@ fn verify_host_key(
|
||||
format!("[{host}]:{port}")
|
||||
};
|
||||
|
||||
// The banner is plain output: the confirmation prompt itself
|
||||
// must stay a single line for its redraw logic
|
||||
println!("The authenticity of host '{display}' can't be established.");
|
||||
println!("{key_type_desc} key fingerprint is {fingerprint}.");
|
||||
let accepted = prompt::confirm("Accept and store this host key?", false)?;
|
||||
if !accepted {
|
||||
if !prompter.accept_host_key(&display, key_type_desc, &fingerprint) {
|
||||
return Err(format!("Host key for {display} rejected, aborting upload").into());
|
||||
}
|
||||
if let Some(name) = key_type_name(key_type) {
|
||||
@@ -592,7 +588,7 @@ pub fn upload_file(
|
||||
local: &Path,
|
||||
remote: &str,
|
||||
host: &str,
|
||||
bar: &ProgressBar,
|
||||
on_progress: &dyn Fn(u64),
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let mut local_file =
|
||||
fs::File::open(local).map_err(|e| format!("cannot open '{}': {}", local.display(), e))?;
|
||||
@@ -602,6 +598,7 @@ pub fn upload_file(
|
||||
.map_err(|e| format!("cannot create remote file {remote} on {host}: {e}"))?;
|
||||
|
||||
let mut buf = [0u8; 32 * 1024];
|
||||
let mut uploaded: u64 = 0;
|
||||
loop {
|
||||
let n = local_file.read(&mut buf)?;
|
||||
if n == 0 {
|
||||
@@ -610,7 +607,8 @@ pub fn upload_file(
|
||||
remote_file
|
||||
.write_all(&buf[..n])
|
||||
.map_err(|e| format!("failed uploading to {remote} on {host}: {e}"))?;
|
||||
bar.inc(n as u64);
|
||||
uploaded += n as u64;
|
||||
on_progress(uploaded);
|
||||
}
|
||||
|
||||
// Close explicitly: quota-exceeded and similar failures only surface in
|
||||
|
||||
Reference in New Issue
Block a user