use crate::auth::secure_string::SecureString;
use crate::auth::ssh;
use crate::auth::token;
use tracing::debug;
pub fn build_git2_callbacks(
explicit_token: Option<&SecureString>,
ssh_key_path: Option<&std::path::Path>,
host: Option<String>,
) -> git2::RemoteCallbacks<'static> {
let token = explicit_token.cloned();
let ssh_key = ssh_key_path.map(|p| p.to_path_buf());
let tried_ssh = std::cell::Cell::new(false);
let tried_token = std::cell::Cell::new(false);
let mut callbacks = git2::RemoteCallbacks::new();
callbacks.credentials(move |_url, username_from_url, allowed_types| {
let username = username_from_url.unwrap_or("git");
if allowed_types.contains(git2::CredentialType::USER_PASS_PLAINTEXT) && !tried_token.get() {
tried_token.set(true);
if let Some(ref tok) = token {
debug!("Attempting token authentication");
return git2::Cred::userpass_plaintext(username, tok.as_str());
}
if let Some((env_tok, source)) = token::discover_token() {
debug!("Attempting token authentication from {}", source);
return git2::Cred::userpass_plaintext(username, env_tok.as_str());
}
if let Some(ref h) = host {
if let Some(stored_tok) = token::token_for_host(h) {
debug!("Attempting stored credential for host {}", h);
return git2::Cred::userpass_plaintext(username, stored_tok.as_str());
}
}
}
if allowed_types.contains(git2::CredentialType::SSH_KEY) && !tried_ssh.get() {
tried_ssh.set(true);
if let Some(ref key_path) = ssh_key {
debug!("Attempting SSH key authentication: {}", key_path.display());
let pub_key = ssh::public_key_for(key_path);
return git2::Cred::ssh_key(
username,
pub_key.as_deref(),
key_path,
None, );
}
if let Some(key_path) = ssh::discover_ssh_key() {
debug!("Attempting auto-discovered SSH key: {}", key_path.display());
let pub_key = ssh::public_key_for(&key_path);
return git2::Cred::ssh_key(username, pub_key.as_deref(), &key_path, None);
}
}
if allowed_types.contains(git2::CredentialType::SSH_KEY) {
debug!("Attempting SSH agent authentication");
return git2::Cred::ssh_key_from_agent(username);
}
if allowed_types.contains(git2::CredentialType::DEFAULT) {
return git2::Cred::default();
}
Err(git2::Error::from_str("no authentication method available"))
});
callbacks
}
pub fn build_http_headers(
explicit_token: Option<&SecureString>,
host: &str,
) -> reqwest::header::HeaderMap {
let mut headers = reqwest::header::HeaderMap::new();
let tok = explicit_token
.cloned()
.or_else(|| token::token_for_host(host));
if let Some(tok) = tok {
if let Ok(val) = reqwest::header::HeaderValue::from_str(&format!("token {}", tok.as_str()))
{
headers.insert(reqwest::header::AUTHORIZATION, val);
}
}
headers
}