1use std::{convert::TryFrom, fmt::Debug, path::PathBuf, sync::Arc};
2
3use tokio::net::TcpStream;
4use tokio_rustls::rustls::pki_types::ServerName;
5use tokio_rustls::{
6 rustls::{
7 self,
8 pki_types::{CertificateDer, PrivateKeyDer},
9 ClientConfig,
10 },
11 TlsConnector,
12};
13
14use crate::error::ClientError;
15
16use super::{
17 metrics::{MetricsCollector, NopMetricsCollector},
18 GenericTcpStream,
19};
20
21#[derive(Clone)]
22#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
23pub struct ClientOptions {
24 #[cfg_attr(feature = "serde", serde(default = "default_host"))]
25 pub(crate) host: String,
26 #[cfg_attr(feature = "serde", serde(default = "default_port"))]
27 pub(crate) port: u16,
28 #[cfg_attr(feature = "serde", serde(default = "default_user"))]
29 pub(crate) user: String,
30 #[cfg_attr(feature = "serde", serde(default = "default_password"))]
31 pub(crate) password: String,
32 #[cfg_attr(feature = "serde", serde(default = "default_v_host"))]
33 pub(crate) v_host: String,
34 #[cfg_attr(feature = "serde", serde(default = "default_heartbeat"))]
35 pub(crate) heartbeat: u32,
36 #[cfg_attr(feature = "serde", serde(default = "default_max_frame_size"))]
37 pub(crate) max_frame_size: u32,
38 #[cfg_attr(feature = "serde", serde(default = "default_load_balancer_mode"))]
39 pub(crate) load_balancer_mode: bool,
40 #[cfg_attr(feature = "serde", serde(default))]
41 pub(crate) tls: TlsConfiguration,
42 #[cfg_attr(feature = "serde", serde(skip, default = "default_collector"))]
43 pub(crate) collector: Arc<dyn MetricsCollector>,
44 #[cfg_attr(feature = "serde", serde(default = "default_client_provided_name"))]
45 pub(crate) client_provided_name: String,
46}
47
48impl Debug for ClientOptions {
49 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
50 f.debug_struct("ClientOptions")
51 .field("host", &self.host)
52 .field("port", &self.port)
53 .field("user", &self.user)
54 .field("password", &self.password)
55 .field("v_host", &self.v_host)
56 .field("heartbeat", &self.heartbeat)
57 .field("max_frame_size", &self.max_frame_size)
58 .field("client_provided_name", &self.client_provided_name)
59 .finish()
60 }
61}
62
63impl Default for ClientOptions {
64 fn default() -> Self {
65 ClientOptions {
66 host: default_host(),
67 port: default_port(),
68 user: default_user(),
69 password: default_password(),
70 v_host: default_v_host(),
71 heartbeat: default_heartbeat(),
72 max_frame_size: default_max_frame_size(),
73 load_balancer_mode: default_load_balancer_mode(),
74 collector: default_collector(),
75 tls: Default::default(),
76 client_provided_name: default_client_provided_name(),
77 }
78 }
79}
80
81fn default_host() -> String {
82 "localhost".to_owned()
83}
84fn default_port() -> u16 {
85 5552
86}
87fn default_user() -> String {
88 "guest".to_owned()
89}
90fn default_password() -> String {
91 "guest".to_owned()
92}
93fn default_v_host() -> String {
94 "/".to_owned()
95}
96fn default_heartbeat() -> u32 {
97 60
98}
99fn default_max_frame_size() -> u32 {
100 1048576
101}
102fn default_load_balancer_mode() -> bool {
103 false
104}
105fn default_collector() -> Arc<dyn MetricsCollector> {
106 Arc::new(NopMetricsCollector {})
107}
108fn default_client_provided_name() -> String {
109 "rust-stream".to_owned()
110}
111
112impl ClientOptions {
113 pub fn builder() -> ClientOptionsBuilder {
114 ClientOptionsBuilder(ClientOptions::default())
115 }
116
117 pub fn set_port(&mut self, port: u16) {
118 self.port = port;
119 }
120
121 pub fn set_client_provided_name(&mut self, name: &str) {
122 self.client_provided_name = name.to_owned();
123 }
124
125 pub(crate) async fn build_generic_tcp_stream(&self) -> Result<GenericTcpStream, ClientError> {
126 async fn create_tls_connection(
127 host: String,
128 port: u16,
129 config: ClientConfig,
130 ) -> Result<GenericTcpStream, ClientError> {
131 let stream = TcpStream::connect((host.clone(), port)).await?;
132 let domain = ServerName::try_from(host.clone()).unwrap();
133 let connector = TlsConnector::from(Arc::new(config));
134 let conn = connector.connect(domain, stream).await?;
135 Ok(GenericTcpStream::SecureTcp(Box::new(conn)))
136 }
137 match &self.tls {
138 TlsConfiguration::Trusted {
139 root_certificates_path,
140 client_certificates,
141 } => {
142 let roots = build_root_store(root_certificates_path).await?;
143
144 let builder = ClientConfig::builder().with_root_certificates(roots);
145 let config = match client_certificates {
146 Some(client_certificates) => {
147 let client_certs = match build_client_certificates(
148 &client_certificates.client_certificates_path,
149 ) {
150 Ok(certs) => certs,
151 Err(e) => return Err(ClientError::Io(e)),
152 };
153 let client_keys = match build_client_private_keys(
154 &client_certificates.client_private_key_path,
155 ) {
156 Ok(keys) => keys,
157 Err(e) => return Err(ClientError::Io(e)),
158 };
159 match builder.with_client_auth_cert(
160 client_certs,
161 client_keys.into_iter().next().unwrap(),
162 ) {
163 Ok(config) => config,
164 Err(e) => return Err(ClientError::GenericError(Box::new(e))),
165 }
166 }
167 None => builder.with_no_client_auth(),
168 };
169 create_tls_connection(self.host.clone(), self.port, config).await
170 }
171 TlsConfiguration::Untrusted => {
172 let config: ClientConfig = build_tls_client_configuration_untrusted().await?;
173 create_tls_connection(self.host.clone(), self.port, config).await
174 }
175 TlsConfiguration::Disabled => {
176 let stream = TcpStream::connect((self.host.as_str(), self.port)).await?;
177 Ok(GenericTcpStream::Tcp(stream))
178 }
179 }
180 }
181}
182
183pub struct ClientOptionsBuilder(ClientOptions);
184
185impl ClientOptionsBuilder {
186 pub fn host(mut self, host: &str) -> Self {
187 self.0.host = host.to_owned();
188 self
189 }
190
191 pub fn port(mut self, port: u16) -> Self {
192 self.0.port = port;
193 self
194 }
195
196 pub fn user(mut self, user: &str) -> Self {
197 self.0.user = user.to_owned();
198 self
199 }
200
201 pub fn password(mut self, password: &str) -> Self {
202 self.0.password = password.to_owned();
203 self
204 }
205
206 pub fn v_host(mut self, v_host: &str) -> Self {
207 self.0.v_host = v_host.to_owned();
208 self
209 }
210
211 pub fn heartbeat(mut self, heartbeat: u32) -> Self {
212 self.0.heartbeat = heartbeat;
213 self
214 }
215
216 pub fn max_frame_size(mut self, max_frame_size: u32) -> Self {
217 self.0.max_frame_size = max_frame_size;
218 self
219 }
220
221 pub fn tls(mut self, tls: TlsConfiguration) -> Self {
222 self.0.tls = tls;
223 self
224 }
225
226 pub fn client_provided_name(mut self, client_provided_name: String) -> Self {
227 self.0.client_provided_name = client_provided_name;
228 self
229 }
230
231 pub fn collector(mut self, collector: Arc<dyn MetricsCollector>) -> Self {
232 self.0.collector = collector;
233 self
234 }
235
236 pub fn load_balancer_mode(mut self, load_balancer_mode: bool) -> Self {
237 self.0.load_balancer_mode = load_balancer_mode;
238 self
239 }
240
241 pub fn build(self) -> ClientOptions {
242 self.0
243 }
244}
245
246#[derive(Clone, Default)]
248pub enum TlsConfiguration {
249 #[default]
250 Disabled,
251 Untrusted,
252 Trusted {
253 root_certificates_path: PathBuf,
254 client_certificates: Option<ClientTlsConfiguration>,
255 },
256}
257
258#[cfg(feature = "serde")]
259impl<'de> serde::Deserialize<'de> for TlsConfiguration {
260 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
261 where
262 D: serde::Deserializer<'de>,
263 {
264 use serde::Deserialize;
265
266 #[derive(Deserialize)]
267 struct DeserializableTlsConfiguration {
268 enabled: bool,
269 root_certificates_path: Option<PathBuf>,
270 client_certificates_path: Option<PathBuf>,
271 client_private_key_path: Option<PathBuf>,
272 }
273 let c = DeserializableTlsConfiguration::deserialize(deserializer)?;
274
275 let builder = TlsConfiguration::builder().enable(c.enabled);
276 let builder = if let Some(root_certificates_path) = c.root_certificates_path {
277 builder.add_root_certificates(root_certificates_path)
278 } else {
279 builder
280 };
281 let builder = if let Some(client_certificates_path) = c.client_certificates_path {
282 builder.add_client_certificates_path(client_certificates_path)
283 } else {
284 builder
285 };
286 let builder = if let Some(client_private_key_path) = c.client_private_key_path {
287 builder.add_client_private_key_path(client_private_key_path)
288 } else {
289 builder
290 };
291
292 builder.build().map_err(serde::de::Error::custom)
293 }
294}
295
296#[derive(Clone)]
297pub struct ClientTlsConfiguration {
298 pub(crate) client_certificates_path: PathBuf,
299 pub(crate) client_private_key_path: PathBuf,
300}
301
302impl TlsConfiguration {
303 pub fn builder() -> TlsConfigurationBuilder {
304 TlsConfigurationBuilder {
305 enabled: false,
306 root_certificates_path: None,
307 client_certificates_path: None,
308 client_private_key_path: None,
309 }
310 }
311}
312
313#[derive(Default)]
314pub struct TlsConfigurationBuilder {
315 enabled: bool,
316 root_certificates_path: Option<PathBuf>,
317 client_certificates_path: Option<PathBuf>,
318 client_private_key_path: Option<PathBuf>,
319}
320
321impl TlsConfigurationBuilder {
322 pub fn enable(mut self, enabled: bool) -> TlsConfigurationBuilder {
323 self.enabled = enabled;
324 self
325 }
326
327 pub fn add_root_certificates<T>(self, root_certificates_path: T) -> TlsConfigurationBuilder
328 where
329 T: Into<PathBuf>,
330 {
331 let mut s = self.enable(true);
332 s.root_certificates_path = Some(root_certificates_path.into());
333 s
334 }
335
336 #[cfg(feature = "serde")]
337 fn add_client_certificates_path<T>(self, client_certificates_path: T) -> TlsConfigurationBuilder
338 where
339 T: Into<PathBuf>,
340 {
341 let mut s = self.enable(true);
342 s.client_certificates_path = Some(client_certificates_path.into());
343 s
344 }
345
346 #[cfg(feature = "serde")]
347 fn add_client_private_key_path<T>(self, client_private_key_path: T) -> TlsConfigurationBuilder
348 where
349 T: Into<PathBuf>,
350 {
351 let mut s = self.enable(true);
352 s.client_private_key_path = Some(client_private_key_path.into());
353 s
354 }
355
356 pub fn add_client_certificates_keys<T1, T2>(
357 self,
358 client_certificates_path: T1,
359 client_private_key_path: T2,
360 ) -> TlsConfigurationBuilder
361 where
362 T1: Into<PathBuf>,
363 T2: Into<PathBuf>,
364 {
365 let mut s = self.enable(true);
366 s.client_certificates_path = Some(client_certificates_path.into());
367 s.client_private_key_path = Some(client_private_key_path.into());
368 s
369 }
370
371 pub fn build(self) -> Result<TlsConfiguration, &'static str> {
372 if self.enabled {
373 let root_certificates_path = match self.root_certificates_path {
374 Some(root_certificates_path) => root_certificates_path,
375 None => {
376 if self.client_certificates_path.is_some()
377 || self.client_private_key_path.is_some()
378 {
379 return Err("Root certificates path is required when client certificates are provided");
380 }
381 return Ok(TlsConfiguration::Untrusted);
382 }
383 };
384
385 let client_certificates =
386 match (self.client_certificates_path, self.client_private_key_path) {
387 (Some(client_certificates_path), Some(client_private_key_path)) => {
388 Some(ClientTlsConfiguration {
389 client_certificates_path,
390 client_private_key_path,
391 })
392 }
393 (None, None) => None,
394 _ => return Err("Both client certificates and private key paths are required"),
395 };
396
397 Ok(TlsConfiguration::Trusted {
398 root_certificates_path,
399 client_certificates,
400 })
401 } else {
402 Ok(TlsConfiguration::Disabled)
403 }
404 }
405}
406
407fn build_client_certificates(
408 client_cert: &PathBuf,
409) -> std::io::Result<Vec<CertificateDer<'static>>> {
410 let file = std::fs::File::open(client_cert)?;
411 let mut pem = std::io::BufReader::new(file);
412 rustls_pemfile::certs(&mut pem)
413 .map(|c| c.map(CertificateDer::into_owned))
414 .collect()
415}
416
417async fn build_tls_client_configuration_untrusted() -> Result<ClientConfig, ClientError> {
418 mod danger {
419 use rustls::client::danger::HandshakeSignatureValid;
420 use rustls::client::danger::ServerCertVerified;
421 use tokio_rustls::rustls::{
422 self, client::danger::ServerCertVerifier, pki_types::ServerName,
423 };
424
425 #[derive(Debug)]
426 pub struct NoCertificateVerification {}
427
428 impl ServerCertVerifier for NoCertificateVerification {
429 fn verify_tls12_signature(
430 &self,
431 _: &[u8],
432 _: &rustls::pki_types::CertificateDer<'_>,
433 _: &rustls::DigitallySignedStruct,
434 ) -> Result<HandshakeSignatureValid, rustls::Error> {
435 Ok(HandshakeSignatureValid::assertion())
436 }
437
438 fn verify_tls13_signature(
439 &self,
440 _: &[u8],
441 _: &rustls::pki_types::CertificateDer<'_>,
442 _: &rustls::DigitallySignedStruct,
443 ) -> Result<HandshakeSignatureValid, rustls::Error> {
444 Ok(HandshakeSignatureValid::assertion())
445 }
446
447 fn supported_verify_schemes(&self) -> Vec<rustls::SignatureScheme> {
448 use rustls::SignatureScheme;
449 vec![
451 SignatureScheme::RSA_PKCS1_SHA1,
452 SignatureScheme::ECDSA_SHA1_Legacy,
453 SignatureScheme::RSA_PKCS1_SHA256,
454 SignatureScheme::ECDSA_NISTP256_SHA256,
455 SignatureScheme::RSA_PKCS1_SHA384,
456 SignatureScheme::ECDSA_NISTP384_SHA384,
457 SignatureScheme::RSA_PKCS1_SHA512,
458 SignatureScheme::ECDSA_NISTP521_SHA512,
459 SignatureScheme::RSA_PSS_SHA256,
460 SignatureScheme::RSA_PSS_SHA384,
461 SignatureScheme::RSA_PSS_SHA512,
462 SignatureScheme::ED25519,
463 SignatureScheme::ED448,
464 ]
465 }
466
467 fn verify_server_cert(
468 &self,
469 _: &rustls::pki_types::CertificateDer<'_>,
470 _: &[rustls::pki_types::CertificateDer<'_>],
471 _: &ServerName<'_>,
472 _: &[u8],
473 _: rustls::pki_types::UnixTime,
474 ) -> Result<rustls::client::danger::ServerCertVerified, rustls::Error> {
475 Ok(ServerCertVerified::assertion())
476 }
477 }
478 }
479
480 let config = ClientConfig::builder()
481 .dangerous()
482 .with_custom_certificate_verifier(Arc::new(danger::NoCertificateVerification {}))
483 .with_no_client_auth();
484
485 Ok(config)
486}
487
488async fn build_root_store(root_ca_cert: &PathBuf) -> std::io::Result<rustls::RootCertStore> {
489 let mut roots = rustls::RootCertStore::empty();
490 let cert_bytes = std::fs::read(root_ca_cert)?;
491
492 let root_cert_store: Result<Vec<_>, _> =
493 rustls_pemfile::certs(&mut cert_bytes.as_ref()).collect();
494 let root_cert_store = root_cert_store?;
495
496 root_cert_store
497 .into_iter()
498 .for_each(|cert| roots.add(cert).unwrap());
499 Ok(roots)
500}
501
502fn build_client_private_keys(
503 client_private_key: &PathBuf,
504) -> std::io::Result<Vec<PrivateKeyDer<'static>>> {
505 let file = std::fs::File::open(client_private_key)?;
506 let mut pem = std::io::BufReader::new(file);
507 let keys: Result<Vec<_>, _> = rustls_pemfile::pkcs8_private_keys(&mut pem).collect();
508 let keys = keys?;
509 let keys = keys.into_iter().map(PrivateKeyDer::from).collect();
510 Ok(keys)
511}
512
513#[cfg(test)]
514mod tests {
515 use super::*;
516 use std::{path::Path, sync::Arc};
517
518 #[test]
519 fn test_tls_builder() {
520 let tls = TlsConfiguration::builder().build().unwrap();
521 assert!(matches!(tls, TlsConfiguration::Disabled));
522 let tls = TlsConfiguration::builder().enable(true).build().unwrap();
523 assert!(matches!(tls, TlsConfiguration::Untrusted));
524
525 let tls = TlsConfiguration::builder()
526 .enable(true)
527 .add_root_certificates("test")
528 .build()
529 .unwrap();
530 let TlsConfiguration::Trusted {
531 root_certificates_path,
532 client_certificates,
533 } = tls
534 else {
535 panic!("Expected Trusted configuration")
536 };
537 assert_eq!(root_certificates_path.as_path(), Path::new("test"));
538 assert!(client_certificates.is_none());
539
540 let tls = TlsConfiguration::builder()
541 .enable(true)
542 .add_root_certificates("test")
543 .add_client_certificates_keys("cert", "priv")
544 .build()
545 .unwrap();
546 let TlsConfiguration::Trusted {
547 root_certificates_path,
548 client_certificates,
549 } = tls
550 else {
551 panic!("Expected Trusted configuration")
552 };
553 assert_eq!(root_certificates_path.as_path(), Path::new("test"));
554 let Some(client_certificates) = client_certificates else {
555 panic!("Expected client certificates")
556 };
557 assert_eq!(
558 client_certificates.client_certificates_path,
559 Path::new("cert")
560 );
561 assert_eq!(
562 client_certificates.client_private_key_path,
563 Path::new("priv")
564 );
565
566 let tls = TlsConfiguration::builder()
567 .enable(true)
568 .add_client_certificates_keys("cert", "priv")
569 .build();
570 assert!(tls.is_err());
571 }
572
573 #[test]
574 fn test_client_options_builder() {
575 let options = ClientOptions::builder()
576 .host("test")
577 .port(8888)
578 .user("test_user")
579 .password("test_pass")
580 .v_host("/test_vhost")
581 .heartbeat(10000)
582 .max_frame_size(1)
583 .tls(TlsConfiguration::builder().enable(true).build().unwrap())
584 .collector(Arc::new(NopMetricsCollector {}))
585 .load_balancer_mode(true)
586 .build();
587 assert_eq!(options.host, "test");
588 assert_eq!(options.port, 8888);
589 assert_eq!(options.user, "test_user");
590 assert_eq!(options.password, "test_pass");
591 assert_eq!(options.v_host, "/test_vhost");
592 assert_eq!(options.heartbeat, 10000);
593 assert_eq!(options.max_frame_size, 1);
594 assert!(matches!(options.tls, TlsConfiguration::Untrusted));
595 assert!(options.load_balancer_mode);
596 }
597
598 #[cfg(feature = "serde")]
599 mod serde {
600 use super::*;
601
602 #[test]
603 fn test_tls_builder() {
604 let config = TlsConfiguration::builder().enable(true).build();
605 assert!(matches!(config, Ok(TlsConfiguration::Untrusted)));
606
607 let config = TlsConfiguration::builder()
608 .enable(true)
609 .add_client_certificates_path("cert")
610 .build();
611 assert!(matches!(config, Err(_)));
612
613 let config = TlsConfiguration::builder()
614 .enable(true)
615 .add_client_private_key_path("priv")
616 .build();
617 assert!(matches!(config, Err(_)));
618 }
619 }
620}
621
622#[cfg(all(feature = "serde", test))]
623mod serde_test {
624 use super::*;
625 use std::path::Path;
626
627 #[test]
628 fn deserialize_client() {
629 #[derive(serde::Deserialize)]
630 struct MyConfig {
631 #[serde(default)]
632 rabbit: ClientOptions,
633 }
634 let j = r#"{}"#;
635
636 let config: MyConfig = serde_json::from_str(j).unwrap();
637 assert_eq!(config.rabbit.host, default_host());
638 assert_eq!(config.rabbit.port, default_port());
639 assert_eq!(config.rabbit.user, default_user());
640 assert_eq!(config.rabbit.password, default_password());
641 assert_eq!(config.rabbit.v_host, default_v_host());
642 assert_eq!(config.rabbit.heartbeat, default_heartbeat());
643 assert_eq!(config.rabbit.max_frame_size, default_max_frame_size());
644 assert_eq!(
645 config.rabbit.load_balancer_mode,
646 default_load_balancer_mode()
647 );
648 assert_eq!(
649 config.rabbit.client_provided_name,
650 default_client_provided_name()
651 );
652 assert!(matches!(config.rabbit.tls, TlsConfiguration::Disabled));
653
654 let j = r#"{ "rabbit": {} }"#;
655 let config: MyConfig = serde_json::from_str(j).unwrap();
656 assert_eq!(config.rabbit.host, default_host());
657 assert_eq!(config.rabbit.port, default_port());
658 assert_eq!(config.rabbit.user, default_user());
659 assert_eq!(config.rabbit.password, default_password());
660 assert_eq!(config.rabbit.v_host, default_v_host());
661 assert_eq!(config.rabbit.heartbeat, default_heartbeat());
662 assert_eq!(config.rabbit.max_frame_size, default_max_frame_size());
663 assert_eq!(
664 config.rabbit.load_balancer_mode,
665 default_load_balancer_mode()
666 );
667 assert_eq!(
668 config.rabbit.client_provided_name,
669 default_client_provided_name()
670 );
671 assert!(matches!(config.rabbit.tls, TlsConfiguration::Disabled));
672
673 let j = r#"{ "rabbit": {"host": "example.org"} }"#;
674 let config: MyConfig = serde_json::from_str(j).unwrap();
675 assert_eq!(config.rabbit.host, "example.org".to_string());
676 assert_eq!(config.rabbit.port, default_port());
677 assert_eq!(config.rabbit.user, default_user());
678 assert_eq!(config.rabbit.password, default_password());
679 assert_eq!(config.rabbit.v_host, default_v_host());
680 assert_eq!(config.rabbit.heartbeat, default_heartbeat());
681 assert_eq!(config.rabbit.max_frame_size, default_max_frame_size());
682 assert_eq!(
683 config.rabbit.load_balancer_mode,
684 default_load_balancer_mode()
685 );
686 assert_eq!(
687 config.rabbit.client_provided_name,
688 default_client_provided_name()
689 );
690 assert!(matches!(config.rabbit.tls, TlsConfiguration::Disabled));
691
692 let j = r#"{ "rabbit": {"host": "example.org", "port": 5354} }"#;
693 let config: MyConfig = serde_json::from_str(j).unwrap();
694 assert_eq!(config.rabbit.host, "example.org".to_string());
695 assert_eq!(config.rabbit.port, 5354);
696 assert_eq!(config.rabbit.user, default_user());
697 assert_eq!(config.rabbit.password, default_password());
698 assert_eq!(config.rabbit.v_host, default_v_host());
699 assert_eq!(config.rabbit.heartbeat, default_heartbeat());
700 assert_eq!(config.rabbit.max_frame_size, default_max_frame_size());
701 assert_eq!(
702 config.rabbit.load_balancer_mode,
703 default_load_balancer_mode()
704 );
705 assert_eq!(
706 config.rabbit.client_provided_name,
707 default_client_provided_name()
708 );
709 assert!(matches!(config.rabbit.tls, TlsConfiguration::Disabled));
710
711 let j = r#"{ "rabbit": { "tls": {} } }"#;
712 let config = serde_json::from_str::<MyConfig>(j);
713 assert!(config.is_err());
714
715 let j = r#"{ "rabbit": { "tls": { "enabled": false } } }"#;
716 let config = serde_json::from_str::<MyConfig>(j).unwrap();
717 assert!(matches!(config.rabbit.tls, TlsConfiguration::Disabled));
718
719 let j = r#"{ "rabbit": { "tls": { "enabled": true } } }"#;
720 let config = serde_json::from_str::<MyConfig>(j).unwrap();
721 assert!(matches!(config.rabbit.tls, TlsConfiguration::Untrusted));
722
723 let j = r#"
724{
725 "rabbit": {
726 "tls": {
727 "enabled": true,
728 "root_certificates_path": "path"
729 }
730 }
731}"#;
732 let config = serde_json::from_str::<MyConfig>(j).unwrap();
733 assert!(matches!(
734 config.rabbit.tls,
735 TlsConfiguration::Trusted { .. }
736 ));
737 let TlsConfiguration::Trusted {
738 root_certificates_path,
739 client_certificates,
740 } = config.rabbit.tls
741 else {
742 panic!("Expected Trusted configuration")
743 };
744 assert_eq!(root_certificates_path.as_path(), Path::new("path"));
745 assert!(client_certificates.is_none());
746
747 let j = r#"
748{
749 "rabbit": {
750 "tls": {
751 "enabled": true,
752 "root_certificates_path": "path",
753 "client_certificates_path": "cert",
754 "client_private_key_path": "priv"
755 }
756 }
757}"#;
758 let config = serde_json::from_str::<MyConfig>(j).unwrap();
759 assert!(matches!(
760 config.rabbit.tls,
761 TlsConfiguration::Trusted { .. }
762 ));
763 let TlsConfiguration::Trusted {
764 root_certificates_path,
765 client_certificates,
766 } = config.rabbit.tls
767 else {
768 panic!("Expected Trusted configuration")
769 };
770 assert_eq!(root_certificates_path.as_path(), Path::new("path"));
771 let client_certificates = client_certificates.expect("Expected client certificates");
772 assert_eq!(
773 client_certificates.client_certificates_path.as_path(),
774 Path::new("cert")
775 );
776 assert_eq!(
777 client_certificates.client_private_key_path.as_path(),
778 Path::new("priv")
779 );
780 }
781
782 #[test]
783 fn test_tls_config() {
784 let j = r#"
785{}"#;
786 let config = serde_json::from_str::<TlsConfiguration>(j);
787 assert!(config.is_err());
788
789 let j = r#"
790{
791 "enabled": false
792}"#;
793 let config: TlsConfiguration = serde_json::from_str(j).unwrap();
794 assert!(matches!(config, TlsConfiguration::Disabled));
795
796 let j = r#"
797{
798 "enabled": true
799}"#;
800 let config: TlsConfiguration = serde_json::from_str(j).unwrap();
801 assert!(matches!(config, TlsConfiguration::Untrusted));
802
803 let j = r#"
804{
805 "enabled": true,
806 "root_certificates_path": "test"
807}"#;
808 let config: TlsConfiguration = serde_json::from_str(j).unwrap();
809 assert!(matches!(config, TlsConfiguration::Trusted { .. }));
810 let TlsConfiguration::Trusted {
811 root_certificates_path,
812 client_certificates,
813 } = config
814 else {
815 panic!("Expected Trusted configuration")
816 };
817 assert_eq!(root_certificates_path.as_path(), Path::new("test"));
818 assert!(client_certificates.is_none());
819
820 let j = r#"
821{
822 "enabled": true,
823 "root_certificates_path": "test",
824 "client_certificates_path": "cert"
825}"#;
826 let config = serde_json::from_str::<TlsConfiguration>(j);
827 assert!(config.is_err());
828
829 let j = r#"
830{
831 "enabled": true,
832 "root_certificates_path": "test",
833 "client_certificates_path": "cert",
834 "client_private_key_path": "priv"
835}"#;
836 let config: TlsConfiguration = serde_json::from_str(j).unwrap();
837 assert!(matches!(config, TlsConfiguration::Trusted { .. }));
838 let TlsConfiguration::Trusted {
839 root_certificates_path,
840 client_certificates,
841 } = config
842 else {
843 panic!("Expected Trusted configuration")
844 };
845 assert_eq!(root_certificates_path.as_path(), Path::new("test"));
846 let client_certificates = client_certificates.expect("Expected client certificates");
847 assert_eq!(
848 client_certificates.client_certificates_path.as_path(),
849 Path::new("cert")
850 );
851 assert_eq!(
852 client_certificates.client_private_key_path.as_path(),
853 Path::new("priv")
854 );
855 }
856}