use std::time::Duration;
use super::allowlist::SshAllowlist;
pub const DEFAULT_TIMEOUT_SECS: u64 = 30;
pub const DEFAULT_MAX_RESPONSE_BYTES: usize = 10_000_000;
pub const DEFAULT_MAX_SESSIONS: usize = 5;
pub const DEFAULT_PORT: u16 = 22;
#[derive(Debug, Clone)]
pub struct SshConfig {
pub(crate) allowlist: SshAllowlist,
pub(crate) default_user: Option<String>,
pub(crate) default_password: Option<String>,
pub(crate) default_private_key: Option<String>,
pub(crate) timeout: Duration,
pub(crate) max_response_bytes: usize,
pub(crate) max_sessions: usize,
pub(crate) default_port: u16,
}
impl Default for SshConfig {
fn default() -> Self {
Self {
allowlist: SshAllowlist::new(),
default_user: None,
default_password: None,
default_private_key: None,
timeout: Duration::from_secs(DEFAULT_TIMEOUT_SECS),
max_response_bytes: DEFAULT_MAX_RESPONSE_BYTES,
max_sessions: DEFAULT_MAX_SESSIONS,
default_port: DEFAULT_PORT,
}
}
}
impl SshConfig {
pub fn new() -> Self {
Self::default()
}
pub fn allow(mut self, pattern: impl Into<String>) -> Self {
self.allowlist = self.allowlist.allow(pattern);
self
}
pub fn allow_many(mut self, patterns: impl IntoIterator<Item = impl Into<String>>) -> Self {
self.allowlist = self.allowlist.allow_many(patterns);
self
}
pub fn allow_port(mut self, port: u16) -> Self {
self.allowlist = self.allowlist.allow_port(port);
self
}
pub fn allow_all(mut self) -> Self {
self.allowlist = SshAllowlist::allow_all();
self
}
pub fn default_user(mut self, user: impl Into<String>) -> Self {
self.default_user = Some(user.into());
self
}
pub fn default_password(mut self, password: impl Into<String>) -> Self {
self.default_password = Some(password.into());
self
}
pub fn default_private_key(mut self, key: impl Into<String>) -> Self {
self.default_private_key = Some(key.into());
self
}
pub fn timeout(mut self, timeout: Duration) -> Self {
self.timeout = timeout;
self
}
pub fn max_response_bytes(mut self, max: usize) -> Self {
self.max_response_bytes = max;
self
}
pub fn max_sessions(mut self, max: usize) -> Self {
self.max_sessions = max;
self
}
pub fn default_port(mut self, port: u16) -> Self {
self.default_port = port;
self
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_config() {
let config = SshConfig::new();
assert!(!config.allowlist.is_enabled());
assert!(config.default_user.is_none());
assert_eq!(config.timeout, Duration::from_secs(30));
assert_eq!(config.max_response_bytes, 10_000_000);
assert_eq!(config.max_sessions, 5);
assert_eq!(config.default_port, 22);
}
#[test]
fn test_builder_chain() {
let config = SshConfig::new()
.allow("*.supabase.co")
.allow("bastion.example.com")
.allow_port(2222)
.default_user("deploy")
.timeout(Duration::from_secs(60))
.max_response_bytes(5_000_000)
.max_sessions(3)
.default_port(2222);
assert!(config.allowlist.is_enabled());
assert_eq!(config.default_user.as_deref(), Some("deploy"));
assert_eq!(config.timeout, Duration::from_secs(60));
assert_eq!(config.max_response_bytes, 5_000_000);
assert_eq!(config.max_sessions, 3);
assert_eq!(config.default_port, 2222);
}
#[test]
fn test_allowlist_integration() {
let config = SshConfig::new().allow("*.supabase.co").allow_port(22);
assert!(config.allowlist.is_allowed("db.supabase.co", 22));
assert!(!config.allowlist.is_allowed("evil.com", 22));
}
}