Skip to content

Commit

Permalink
Fixes #31 Support ssh keys not named id_rsa
Browse files Browse the repository at this point in the history
  • Loading branch information
ncipollo committed Oct 11, 2023
1 parent 36ccc87 commit e5e5213
Showing 1 changed file with 58 additions and 10 deletions.
68 changes: 58 additions & 10 deletions src/repo/ssh.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,42 @@
use std::path::Path;
use std::fs;
use std::path::{Path, PathBuf};
use git2::{Cred, Error};
use crate::SheepError;

/// Returns the standard path to the user's ssh key.
pub fn default_ssh_key_path() -> String {
shellexpand::tilde("~/.ssh/id_rsa").to_string()
fn ssh_key_path() -> String {
find_best_ssh_key().expect("failed to find ssh key")
}

fn find_best_ssh_key() -> Result<String, SheepError> {
let ssh_dir = shellexpand::tilde("~/.ssh");
let ssh_dir_path = PathBuf::from(ssh_dir.as_ref());
let file_names = ssh_file_names(ssh_dir_path)?;

let best_file_name = find_best_key_name(file_names)?;
let mut base_path = PathBuf::from(ssh_dir.as_ref());
base_path.push(best_file_name);
Ok(base_path.to_string_lossy().to_string())
}

fn ssh_file_names(ssh_dir_path: PathBuf) -> Result<Vec<String>, SheepError> {
let names = fs::read_dir(ssh_dir_path)
?.map(|res| res.map(|e| e.file_name()))
.map({
|res| res.map_or("".to_string(),
|name| name.to_string_lossy().to_string())
})
.collect::<Vec<_>>();
Ok(names)
}

fn find_best_key_name(file_names: Vec<String>) -> Result<String, SheepError> {
file_names.iter()
.find(|name| {
!name.ends_with(".pub") && name.starts_with("id_")
})
.map(|name| name.to_string())
.ok_or(SheepError::new("failed to find ssh key"))
}

pub fn add_credentials_to_callbacks(remote_callbacks: &mut git2::RemoteCallbacks) {
Expand All @@ -16,20 +49,35 @@ pub fn create_ssh_key(username_from_url: &str) -> Result<Cred, Error> {
Cred::ssh_key(
username_from_url,
None,
Path::new(&default_ssh_key_path()),
Path::new(&ssh_key_path()),
None,
)
}

#[cfg(test)]
mod test {
use std::env;
use crate::repo::ssh::default_ssh_key_path;
use crate::repo::ssh::find_best_key_name;

#[test]
fn find_best_key_name_empty_names() {
let result = find_best_key_name(vec![]);
result.expect_err("should be an error");
}

#[test]
fn default_path_expands_tilde() {
let home = env::var("HOME").unwrap();
let expected = format!("{home}/.ssh/id_rsa");
assert_eq!(expected, default_ssh_key_path())
fn find_best_key_name_typical_ssh() {
let names = vec![
"config",
"id_rsa",
"id_rsa.pub",
"known_hosts",
];
let result = find_best_key_name(
names.iter()
.map(|n| n.to_string())
.collect()
);
let name = result.expect("failed to find file name");
assert_eq!("id_rsa", name)
}
}

0 comments on commit e5e5213

Please sign in to comment.