1use std::path::{Path, PathBuf};
27
28#[derive(Debug, Clone, Default)]
30pub struct TlsClientConfig {
31 pub ca_cert_path: Option<PathBuf>,
33 pub client_cert_path: Option<PathBuf>,
35 pub client_key_path: Option<PathBuf>,
37 pub server_name: Option<String>,
39 pub danger_accept_invalid_certs: bool,
41}
42
43impl TlsClientConfig {
44 pub fn new() -> Self {
48 Self::default()
49 }
50
51 pub fn with_ca_cert(mut self, path: impl AsRef<Path>) -> Self {
53 self.ca_cert_path = Some(path.as_ref().to_path_buf());
54 self
55 }
56
57 pub fn with_client_cert(
59 mut self,
60 cert_path: impl AsRef<Path>,
61 key_path: impl AsRef<Path>,
62 ) -> Self {
63 self.client_cert_path = Some(cert_path.as_ref().to_path_buf());
64 self.client_key_path = Some(key_path.as_ref().to_path_buf());
65 self
66 }
67
68 pub fn with_server_name(mut self, name: impl Into<String>) -> Self {
72 self.server_name = Some(name.into());
73 self
74 }
75
76 #[cfg(any(test, feature = "dangerous-testing"))]
81 pub fn danger_accept_invalid_certs(mut self) -> Self {
82 self.danger_accept_invalid_certs = true;
83 self
84 }
85
86 pub fn is_mtls(&self) -> bool {
88 self.client_cert_path.is_some() && self.client_key_path.is_some()
89 }
90
91 pub fn to_network_config(&self) -> lnc_network::TlsConfig {
93 if self.is_mtls() {
94 lnc_network::TlsConfig::mtls(
95 self.client_cert_path
96 .as_ref()
97 .map(|p| p.to_string_lossy().to_string())
98 .unwrap_or_default(),
99 self.client_key_path
100 .as_ref()
101 .map(|p| p.to_string_lossy().to_string())
102 .unwrap_or_default(),
103 self.ca_cert_path
104 .as_ref()
105 .map(|p| p.to_string_lossy().to_string())
106 .unwrap_or_default(),
107 )
108 } else if let Some(ref ca_path) = self.ca_cert_path {
109 lnc_network::TlsConfig::client(Some(ca_path.to_string_lossy().to_string()))
110 } else {
111 lnc_network::TlsConfig::client(None::<String>)
112 }
113 }
114}
115
116#[cfg(test)]
117#[allow(clippy::unwrap_used)]
118mod tests {
119 use super::*;
120
121 #[test]
122 fn test_tls_config_default() {
123 let config = TlsClientConfig::new();
124 assert!(config.ca_cert_path.is_none());
125 assert!(config.client_cert_path.is_none());
126 assert!(!config.is_mtls());
127 }
128
129 #[test]
130 fn test_tls_config_with_ca() {
131 let config = TlsClientConfig::new().with_ca_cert("/path/to/ca.pem");
132
133 assert_eq!(
134 config.ca_cert_path.as_ref().map(|p| p.to_str()),
135 Some(Some("/path/to/ca.pem"))
136 );
137 assert!(!config.is_mtls());
138 }
139
140 #[test]
141 fn test_tls_config_mtls() {
142 let config = TlsClientConfig::new()
143 .with_ca_cert("/path/to/ca.pem")
144 .with_client_cert("/path/to/cert.pem", "/path/to/key.pem");
145
146 assert!(config.is_mtls());
147 }
148
149 #[test]
150 fn test_tls_config_with_server_name() {
151 let config = TlsClientConfig::new().with_server_name("lance.example.com");
152
153 assert_eq!(config.server_name, Some("lance.example.com".to_string()));
154 }
155
156 #[test]
157 fn test_client_config_with_tls() {
158 use crate::ClientConfig;
159
160 let tls = TlsClientConfig::new().with_server_name("lance.example.com");
161
162 let config = ClientConfig::new("127.0.0.1:1992").with_tls(tls);
163
164 assert!(config.is_tls_enabled());
165 assert!(config.tls.is_some());
166 assert_eq!(
167 config.tls.as_ref().unwrap().server_name,
168 Some("lance.example.com".to_string())
169 );
170 }
171
172 #[test]
173 fn test_client_config_without_tls() {
174 use crate::ClientConfig;
175
176 let config = ClientConfig::new("127.0.0.1:1992");
177
178 assert!(!config.is_tls_enabled());
179 assert!(config.tls.is_none());
180 }
181}