1use std::path::PathBuf;
2use std::fs;
3use crate::error::Result;
4use dirs;
5
6pub struct SshHelper;
8
9impl SshHelper {
10 pub fn has_ssh_keys() -> bool {
12 let ssh_dir = Self::ssh_dir();
13 if !ssh_dir.exists() {
14 return false;
15 }
16
17 let key_files = vec![
19 "id_rsa",
20 "id_ed25519",
21 "id_ecdsa",
22 "id_dsa",
23 ];
24
25 key_files.iter().any(|key| {
26 ssh_dir.join(key).exists()
27 })
28 }
29
30 pub fn ssh_dir() -> PathBuf {
32 dirs::home_dir()
33 .unwrap_or_else(|| PathBuf::from("."))
34 .join(".ssh")
35 }
36
37 pub fn list_keys() -> Vec<String> {
39 let ssh_dir = Self::ssh_dir();
40 if !ssh_dir.exists() {
41 return vec![];
42 }
43
44 let key_files = vec![
45 "id_rsa",
46 "id_ed25519",
47 "id_ecdsa",
48 "id_dsa",
49 ];
50
51 key_files
52 .iter()
53 .filter(|key| ssh_dir.join(key).exists())
54 .map(|s| s.to_string())
55 .collect()
56 }
57
58 #[allow(dead_code)]
60 pub fn get_public_key(key_name: &str) -> Result<String> {
61 let ssh_dir = Self::ssh_dir();
62 let pub_key_path = ssh_dir.join(format!("{}.pub", key_name));
63
64 if !pub_key_path.exists() {
65 return Ok(String::new());
66 }
67
68 Ok(fs::read_to_string(pub_key_path)?)
69 }
70
71 #[allow(dead_code)]
73 pub fn recommend_protocol() -> &'static str {
74 if Self::has_ssh_keys() {
75 "ssh"
76 } else {
77 "https"
78 }
79 }
80
81 #[allow(dead_code)]
83 pub fn get_setup_instructions() -> String {
84 let mut instructions = String::new();
85
86 instructions.push_str("📚 SSH Setup Instructions:\n\n");
87 instructions.push_str("1. Generate SSH key:\n");
88 instructions.push_str(" ssh-keygen -t ed25519 -C \"your_email@example.com\"\n\n");
89 instructions.push_str("2. Start SSH agent:\n");
90 instructions.push_str(" eval \"$(ssh-agent -s)\"\n");
91 instructions.push_str(" ssh-add ~/.ssh/id_ed25519\n\n");
92 instructions.push_str("3. Copy public key:\n");
93 instructions.push_str(" cat ~/.ssh/id_ed25519.pub\n\n");
94 instructions.push_str("4. Add to your platform:\n");
95 instructions.push_str(" • GitHub: https://github.com/settings/keys\n");
96 instructions.push_str(" • GitLab: https://gitlab.com/-/profile/keys\n");
97 instructions.push_str(" • Bitbucket: https://bitbucket.org/account/settings/ssh-keys/\n");
98
99 instructions
100 }
101}
102
103#[cfg(test)]
104mod tests {
105 use super::*;
106
107 #[test]
108 fn test_ssh_dir() {
109 let dir = SshHelper::ssh_dir();
110 assert!(dir.to_string_lossy().contains(".ssh"));
111 }
112
113 #[test]
114 fn test_recommend_protocol() {
115 let protocol = SshHelper::recommend_protocol();
116 assert!(protocol == "ssh" || protocol == "https");
117 }
118}