consolidate common remotecallbacks code to a single fn

This commit is contained in:
Bryson Steck 2025-03-23 17:56:58 -06:00
parent 81f825b9d3
commit 445ba1fe1f
Signed by: bryson
SSH key fingerprint: SHA256:XpKABw/nP4z8UVaH+weLaBnEOD86+cVwif+QjuYLGT4

View file

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