Skip to content

Commit 49e4271

Browse files
chore: continue strict refactor implementation
Agent-Logs-Url: https://github.com/TeddyHuang-00/sshping/sessions/1a7844f0-cdd9-4e76-85c4-1ceb304eb220 Co-authored-by: TeddyHuang-00 <64199650+TeddyHuang-00@users.noreply.github.com>
1 parent 4fd720e commit 49e4271

1 file changed

Lines changed: 54 additions & 16 deletions

File tree

src/auth.rs

Lines changed: 54 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
use std::{
22
env,
3+
fmt,
34
io::{self, IsTerminal},
4-
path::PathBuf,
5+
path::{Path, PathBuf},
56
sync::Arc,
67
time::{Duration, Instant},
78
};
@@ -12,15 +13,52 @@ use russh::{
1213
keys::{decode_secret_key, PrivateKeyWithHashAlg},
1314
};
1415

16+
#[derive(Debug)]
17+
pub enum AuthError {
18+
ReadIdentityFile(String),
19+
DecodeSecretKey(String),
20+
RsaHash(String),
21+
PublicKeyTimeout(f64),
22+
PublicKeyFailed(String),
23+
PublicKeyRejected,
24+
PasswordTimeout(f64),
25+
PasswordFailed(String),
26+
PasswordRejected,
27+
AllMethodsFailed,
28+
}
29+
30+
impl fmt::Display for AuthError {
31+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
32+
match self {
33+
Self::ReadIdentityFile(msg) => write!(f, "Failed to read identity file: {msg}"),
34+
Self::DecodeSecretKey(msg) => write!(f, "Failed to decode secret key: {msg}"),
35+
Self::RsaHash(msg) => write!(f, "Failed to get RSA hash algorithm: {msg}"),
36+
Self::PublicKeyTimeout(timeout) => {
37+
write!(f, "Public key authentication timed out after {timeout} seconds")
38+
}
39+
Self::PublicKeyFailed(msg) => write!(f, "Public key authentication failed: {msg}"),
40+
Self::PublicKeyRejected => write!(f, "Public key authentication returned false"),
41+
Self::PasswordTimeout(timeout) => {
42+
write!(f, "Password authentication timed out after {timeout} seconds")
43+
}
44+
Self::PasswordFailed(msg) => write!(f, "Password authentication failed: {msg}"),
45+
Self::PasswordRejected => write!(f, "Password authentication returned false"),
46+
Self::AllMethodsFailed => write!(f, "All authentication methods failed"),
47+
}
48+
}
49+
}
50+
51+
impl std::error::Error for AuthError {}
52+
1553
async fn authenticate_publickey<H: client::Handler>(
1654
session: &mut client::Handle<H>,
1755
user: &str,
18-
identity: &PathBuf,
56+
identity: &Path,
1957
password: Option<&str>,
2058
timeout: f64,
21-
) -> Result<(), String> {
59+
) -> Result<(), AuthError> {
2260
let key_content = std::fs::read_to_string(identity)
23-
.map_err(|e| format!("Failed to read identity file: {e}"))?;
61+
.map_err(|e| AuthError::ReadIdentityFile(e.to_string()))?;
2462

2563
// Try to decode the key with the provided password first
2664
let mut key_result = decode_secret_key(&key_content, password);
@@ -35,25 +73,25 @@ async fn authenticate_publickey<H: client::Handler>(
3573
}
3674
}
3775

38-
let key = key_result.map_err(|e| format!("Failed to decode secret key: {e}"))?;
76+
let key = key_result.map_err(|e| AuthError::DecodeSecretKey(e.to_string()))?;
3977

4078
// Get the best supported RSA hash algorithm for the connection
4179
let rsa_hash = session
4280
.best_supported_rsa_hash()
4381
.await
44-
.map_err(|e| format!("Failed to get RSA hash algorithm: {e}"))?
82+
.map_err(|e| AuthError::RsaHash(e.to_string()))?
4583
.flatten();
4684

4785
let timeout_result = tokio::time::timeout(
4886
Duration::from_secs_f64(timeout),
4987
session.authenticate_publickey(user, PrivateKeyWithHashAlg::new(Arc::new(key), rsa_hash)),
5088
)
5189
.await
52-
.map_err(|_| format!("Public key authentication timed out after {timeout} seconds"))?;
90+
.map_err(|_| AuthError::PublicKeyTimeout(timeout))?;
5391
let auth_result =
54-
timeout_result.map_err(|e| format!("Public key authentication failed: {e}"))?;
92+
timeout_result.map_err(|e| AuthError::PublicKeyFailed(e.to_string()))?;
5593
if !auth_result.success() {
56-
return Err("Public key authentication returned false".to_string());
94+
return Err(AuthError::PublicKeyRejected);
5795
}
5896

5997
info!("Public key authentication succeeded");
@@ -85,16 +123,16 @@ async fn authenticate_password<H: client::Handler>(
85123
user: &str,
86124
password: &str,
87125
timeout: f64,
88-
) -> Result<(), String> {
126+
) -> Result<(), AuthError> {
89127
let timeout_result = tokio::time::timeout(
90128
Duration::from_secs_f64(timeout),
91129
session.authenticate_password(user, password),
92130
)
93131
.await
94-
.map_err(|_| format!("Password authentication timed out after {timeout} seconds"))?;
95-
let auth_result = timeout_result.map_err(|e| format!("Password authentication failed: {e}"))?;
132+
.map_err(|_| AuthError::PasswordTimeout(timeout))?;
133+
let auth_result = timeout_result.map_err(|e| AuthError::PasswordFailed(e.to_string()))?;
96134
if !auth_result.success() {
97-
return Err("Password authentication returned false".to_string());
135+
return Err(AuthError::PasswordRejected);
98136
}
99137

100138
info!("Password authentication succeeded");
@@ -106,9 +144,9 @@ pub async fn authenticate_all<H: client::Handler>(
106144
user: &str,
107145
host: &str,
108146
password: Option<&str>,
109-
identity: Option<&PathBuf>,
147+
identity: Option<&Path>,
110148
timeout: f64,
111-
) -> Result<Duration, &'static str> {
149+
) -> Result<Duration, AuthError> {
112150
let start = Instant::now();
113151

114152
// Try public key authentication if identity file is provided
@@ -165,5 +203,5 @@ pub async fn authenticate_all<H: client::Handler>(
165203
}
166204

167205
// Fails if all authentication methods fail
168-
Err("All authentication methods failed")
206+
Err(AuthError::AllMethodsFailed)
169207
}

0 commit comments

Comments
 (0)