diff --git a/src/refractr.rs b/src/refractr.rs index 7e60ce6..d28eef0 100644 --- a/src/refractr.rs +++ b/src/refractr.rs @@ -50,6 +50,33 @@ impl Refractr { Ok(work_dir.to_string_lossy().to_string()) } + fn set_up_ssh(&self, key_path: String, strict: bool) -> Result { + let mut cb = RemoteCallbacks::new(); + cb.credentials(move |_, _, _| Cred::ssh_key("git", None, Path::new(&key_path), None)); + cb.certificate_check(move |cert, url| { + let sha256 = hex::encode(cert.as_hostkey().unwrap().hash_sha256().unwrap().to_vec()); + if strict { + common::error( + format!( + "unknown host {} with sha256 host key {}, exiting", + url, sha256 + ), + ExitCode::RemoteError, + ); + } else { + common::warning(format!( + "unknown host {} with sha256 host key {}, implicitly trusting", + url, sha256 + )); + common::warning(format!( + "to suppress this warning in the future, add this host to your known_hosts file" + )); + } + Ok(CertificateCheckStatus::CertificateOk) + }); + Ok(cb) + } + fn get_refs(&self, branches: &Vec, tags: Option) -> Vec { let mut refs_branches = Vec::new(); for branch in branches { @@ -84,30 +111,22 @@ impl Refractr { branches: &Vec, ssh: bool, ssh_key: &String, + strict: bool, ) -> Result<(), Error> { - let mut cb = RemoteCallbacks::new(); let mut fo = FetchOptions::new(); if ssh { - let key_string: String = ssh_key.clone(); - cb.credentials(move |_, _, _| Cred::ssh_key("git", None, Path::new(&key_string), None)); - cb.certificate_check(|cert, url| { - let mut sha256 = String::new(); - for i in cert.as_hostkey().unwrap().hash_sha256().unwrap().to_vec() { - sha256.push_str(&hex::encode(i.to_string())); - } - common::warning(format!( - "implicitly trusting unknown host {} with sha256 host key {}", - url, - hex::encode(cert.as_hostkey().unwrap().hash_sha256().unwrap().to_vec()) - )); - common::warning(format!( - "to ignore this error in the future, add this host to your known_hosts file" - )); - Ok(CertificateCheckStatus::CertificateOk) - }); + match self.set_up_ssh(ssh_key.clone(), strict.clone()) { + Ok(cb) => { + fo.remote_callbacks(cb); + () + }, + Err(e) => common::error( + format!("error setting up ssh: {}", e), + ExitCode::ConfigError, + ), + }; } fo.download_tags(git2::AutotagOption::All); - fo.remote_callbacks(cb); repo .find_remote("origin")? .fetch(&branches, Some(&mut fo), None)?; @@ -170,41 +189,34 @@ impl Refractr { 1, format!("Pushing to remote: {}", remote.url().unwrap()), ); - let mut callbacks = RemoteCallbacks::new(); - callbacks.credentials(|_, _, _| { - Cred::ssh_key("git", None, &Path::new(&cfg.git.ssh_identity_file), None) - }); - callbacks.certificate_check(|cert, url| { - let mut sha256 = String::new(); - for i in cert.as_hostkey().unwrap().hash_sha256().unwrap().to_vec() { - sha256.push_str(&hex::encode(i.to_string())); - } - common::warning(format!( - "implicitly trusting unknown host {} with sha256 host key {}", - url, - hex::encode(cert.as_hostkey().unwrap().hash_sha256().unwrap().to_vec()) - )); - common::warning(format!( - "to ignore this error in the future, add this host to your known_hosts file" - )); - Ok(CertificateCheckStatus::CertificateOk) - }); - let mut push_options = PushOptions::new(); - push_options.remote_callbacks(callbacks); + let mut po = PushOptions::new(); + match self.set_up_ssh(cfg.git.ssh_identity_file.clone(), self.strict.clone()) { + Ok(cb) => { + po.remote_callbacks(cb); + () + }, + Err(e) => common::error( + format!("error setting up ssh: {}", e), + ExitCode::ConfigError, + ), + }; let mut refs = Vec::new(); let mut refs_str = String::new(); - let strings = self.get_refs(&cfg.branches, match cfg.push_tags { - true => Some(repo.tag_names(None).unwrap()), - false => None - }); + let strings = self.get_refs( + &cfg.branches, + match cfg.push_tags { + true => Some(repo.tag_names(None).unwrap()), + false => None, + }, + ); for branch in &strings { refs.push(branch.as_str()); refs_str.push_str(format!("{} ", branch).as_str()); } common::verbose(self.verbose, 4, format!("ref list: {}", refs_str)); - match remote.push::<&str>(&refs, Some(&mut push_options)) { + match remote.push::<&str>(&refs, Some(&mut po)) { Ok(_) => (), Err(e) => { if self.strict { @@ -330,31 +342,25 @@ impl Refractr { let ssh = cfg.config.from.starts_with("ssh://"); let mut builder = RepoBuilder::new(); - let mut cb = RemoteCallbacks::new(); let mut fo = FetchOptions::new(); // make initial clone if ssh { - let key_string = cfg.config.git.ssh_identity_file.clone(); - cb.credentials(move |_, _, _| Cred::ssh_key("git", None, Path::new(&key_string), None)); - cb.certificate_check(|cert, url| { - let mut sha256 = String::new(); - for i in cert.as_hostkey().unwrap().hash_sha256().unwrap().to_vec() { - sha256.push_str(&hex::encode(i.to_string())); - } - common::warning(format!( - "implicitly trusting unknown host {} with sha256 host key {}", - url, - hex::encode(cert.as_hostkey().unwrap().hash_sha256().unwrap().to_vec()) - )); - common::warning(format!( - "to ignore this error in the future, add this host to your known_hosts file" - )); - Ok(CertificateCheckStatus::CertificateOk) - }); + match self.set_up_ssh( + cfg.config.git.ssh_identity_file.clone(), + self.strict.clone(), + ) { + Ok(cb) => { + fo.remote_callbacks(cb); + () + }, + Err(e) => common::error( + format!("error setting up ssh: {}", e), + ExitCode::ConfigError, + ), + }; } fo.download_tags(git2::AutotagOption::All); - fo.remote_callbacks(cb); builder.fetch_options(fo); let repo_dir = format!("{}{}{}", &path_str, MAIN_SEPARATOR_STR, repo_name); @@ -403,6 +409,7 @@ impl Refractr { &cfg.config.branches, ssh, &cfg.config.git.ssh_identity_file, + self.strict.clone(), ) { common::error( format!("failed to fetch repo {}: {}", cfg.config.from, e),