gitui/asyncgit/src/sync/cred.rs
Stephan Dilly dad8e8d43d cargo fmt: use hardtabs
since it does not support hard-whitespaces its the only way to make whitespaces consisitent and checked
2021-08-17 14:24:25 +02:00

253 lines
5.6 KiB
Rust

//! credentials git helper
use super::remotes::get_default_remote_in_repo;
use crate::{
error::{Error, Result},
CWD,
};
use git2::{Config, CredentialHelper};
/// basic Authentication Credentials
#[derive(Debug, Clone, Default, PartialEq)]
pub struct BasicAuthCredential {
///
pub username: Option<String>,
///
pub password: Option<String>,
}
impl BasicAuthCredential {
///
pub const fn is_complete(&self) -> bool {
self.username.is_some() && self.password.is_some()
}
///
pub const fn new(
username: Option<String>,
password: Option<String>,
) -> Self {
Self { username, password }
}
}
/// know if username and password are needed for this url
pub fn need_username_password() -> Result<bool> {
let repo = crate::sync::utils::repo(CWD)?;
let url = repo
.find_remote(&get_default_remote_in_repo(&repo)?)?
.url()
.ok_or(Error::UnknownRemote)?
.to_owned();
let is_http = url.starts_with("http");
Ok(is_http)
}
/// extract username and password
pub fn extract_username_password() -> Result<BasicAuthCredential> {
let repo = crate::sync::utils::repo(CWD)?;
let url = repo
.find_remote(&get_default_remote_in_repo(&repo)?)?
.url()
.ok_or(Error::UnknownRemote)?
.to_owned();
let mut helper = CredentialHelper::new(&url);
if let Ok(config) = Config::open_default() {
helper.config(&config);
}
Ok(match helper.execute() {
Some((username, password)) => {
BasicAuthCredential::new(Some(username), Some(password))
}
None => extract_cred_from_url(&url),
})
}
/// extract credentials from url
pub fn extract_cred_from_url(url: &str) -> BasicAuthCredential {
if let Ok(url) = url::Url::parse(url) {
BasicAuthCredential::new(
if url.username() == "" {
None
} else {
Some(url.username().to_owned())
},
url.password().map(std::borrow::ToOwned::to_owned),
)
} else {
BasicAuthCredential::new(None, None)
}
}
#[cfg(test)]
mod tests {
use crate::sync::{
cred::{
extract_cred_from_url, extract_username_password,
need_username_password, BasicAuthCredential,
},
remotes::DEFAULT_REMOTE_NAME,
tests::repo_init,
};
use serial_test::serial;
use std::env;
#[test]
fn test_credential_complete() {
assert_eq!(
BasicAuthCredential::new(
Some("username".to_owned()),
Some("password".to_owned())
)
.is_complete(),
true
);
}
#[test]
fn test_credential_not_complete() {
assert_eq!(
BasicAuthCredential::new(
None,
Some("password".to_owned())
)
.is_complete(),
false
);
assert_eq!(
BasicAuthCredential::new(
Some("username".to_owned()),
None
)
.is_complete(),
false
);
assert_eq!(
BasicAuthCredential::new(None, None).is_complete(),
false
);
}
#[test]
fn test_extract_username_from_url() {
assert_eq!(
extract_cred_from_url("https://user@github.com"),
BasicAuthCredential::new(Some("user".to_owned()), None)
);
}
#[test]
fn test_extract_username_password_from_url() {
assert_eq!(
extract_cred_from_url("https://user:pwd@github.com"),
BasicAuthCredential::new(
Some("user".to_owned()),
Some("pwd".to_owned())
)
);
}
#[test]
fn test_extract_nothing_from_url() {
assert_eq!(
extract_cred_from_url("https://github.com"),
BasicAuthCredential::new(None, None)
);
}
#[test]
#[serial]
fn test_need_username_password_if_https() {
let (_td, repo) = repo_init().unwrap();
let root = repo.path().parent().unwrap();
let repo_path = root.as_os_str().to_str().unwrap();
env::set_current_dir(repo_path).unwrap();
repo.remote(DEFAULT_REMOTE_NAME, "http://user@github.com")
.unwrap();
assert_eq!(need_username_password().unwrap(), true);
}
#[test]
#[serial]
fn test_dont_need_username_password_if_ssh() {
let (_td, repo) = repo_init().unwrap();
let root = repo.path().parent().unwrap();
let repo_path = root.as_os_str().to_str().unwrap();
env::set_current_dir(repo_path).unwrap();
repo.remote(DEFAULT_REMOTE_NAME, "git@github.com:user/repo")
.unwrap();
assert_eq!(need_username_password().unwrap(), false);
}
#[test]
#[serial]
#[should_panic]
fn test_error_if_no_remote_when_trying_to_retrieve_if_need_username_password(
) {
let (_td, repo) = repo_init().unwrap();
let root = repo.path().parent().unwrap();
let repo_path = root.as_os_str().to_str().unwrap();
env::set_current_dir(repo_path).unwrap();
need_username_password().unwrap();
}
#[test]
#[serial]
fn test_extract_username_password_from_repo() {
let (_td, repo) = repo_init().unwrap();
let root = repo.path().parent().unwrap();
let repo_path = root.as_os_str().to_str().unwrap();
env::set_current_dir(repo_path).unwrap();
repo.remote(
DEFAULT_REMOTE_NAME,
"http://user:pass@github.com",
)
.unwrap();
assert_eq!(
extract_username_password().unwrap(),
BasicAuthCredential::new(
Some("user".to_owned()),
Some("pass".to_owned())
)
);
}
#[test]
#[serial]
fn test_extract_username_from_repo() {
let (_td, repo) = repo_init().unwrap();
let root = repo.path().parent().unwrap();
let repo_path = root.as_os_str().to_str().unwrap();
env::set_current_dir(repo_path).unwrap();
repo.remote(DEFAULT_REMOTE_NAME, "http://user@github.com")
.unwrap();
assert_eq!(
extract_username_password().unwrap(),
BasicAuthCredential::new(Some("user".to_owned()), None)
);
}
#[test]
#[serial]
#[should_panic]
fn test_error_if_no_remote_when_trying_to_extract_username_password(
) {
let (_td, repo) = repo_init().unwrap();
let root = repo.path().parent().unwrap();
let repo_path = root.as_os_str().to_str().unwrap();
env::set_current_dir(repo_path).unwrap();
extract_username_password().unwrap();
}
}