cloudpub_common/
config.rs1use anyhow::{anyhow, Result};
2use serde::{Deserialize, Serialize};
3use std::fmt::{Debug, Formatter};
4use std::ops::Deref;
5use url::Url;
6
7pub use crate::protocol::Protocol;
8
9#[derive(Serialize, Deserialize, Default, PartialEq, Eq, Clone)]
12pub struct MaskedString(pub String);
13
14impl Debug for MaskedString {
15 fn fmt(&self, f: &mut Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
16 if self.0.is_empty() {
17 f.write_str("EMPTY")
18 } else {
19 #[cfg(debug_assertions)]
20 f.write_str(&self.0)?;
21 #[cfg(not(debug_assertions))]
22 f.write_str("MASKED")?;
23 Ok(())
24 }
25 }
26}
27
28impl Deref for MaskedString {
29 type Target = str;
30 fn deref(&self) -> &Self::Target {
31 &self.0
32 }
33}
34
35impl From<&str> for MaskedString {
36 fn from(s: &str) -> MaskedString {
37 MaskedString(String::from(s))
38 }
39}
40
41#[derive(Debug, Serialize, Deserialize, Copy, Clone, PartialEq, Eq, Default)]
42pub enum TransportType {
43 #[serde(rename = "websocket")]
44 #[default]
45 Websocket,
46 #[serde(rename = "tcp")]
47 Tcp,
48 #[cfg(feature = "rustls")]
49 #[serde(rename = "tls")]
50 Tls,
51}
52
53#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
54#[serde(deny_unknown_fields)]
55#[derive(Default)]
56pub struct TlsConfig {
57 pub hostname: Option<String>,
58 pub trusted_root: Option<String>,
59 pub pkcs12: Option<String>,
60 pub pkcs12_password: Option<MaskedString>,
61 pub danger_ignore_certificate_verification: Option<bool>,
62}
63
64#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
65#[serde(deny_unknown_fields)]
66pub struct WebsocketConfig {
67 pub tls: bool,
68}
69
70impl Default for WebsocketConfig {
71 fn default() -> Self {
72 Self { tls: true }
73 }
74}
75
76#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Default)]
77pub struct TcpConfig {
78 pub proxy: Option<Url>,
79}
80
81#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
82#[serde(deny_unknown_fields)]
83pub struct TransportConfig {
84 #[serde(rename = "type")]
85 pub transport_type: TransportType,
86 pub tcp: TcpConfig,
87 pub tls: Option<TlsConfig>,
88 pub websocket: Option<WebsocketConfig>,
89}
90
91impl Default for TransportConfig {
92 fn default() -> Self {
93 Self {
94 transport_type: TransportType::Websocket,
95 tcp: TcpConfig::default(),
96 tls: TlsConfig::default().into(),
97 websocket: WebsocketConfig::default().into(),
98 }
99 }
100}
101
102impl TransportConfig {
103 pub fn validate(config: &TransportConfig, _is_server: bool) -> Result<()> {
104 config
105 .tcp
106 .proxy
107 .as_ref()
108 .map_or(Ok(()), |u| match u.scheme() {
109 "socks5" => Ok(()),
110 "http" => Ok(()),
111 _ => Err(anyhow!(format!("Unknown proxy scheme: {}", u.scheme()))),
112 })?;
113 match config.transport_type {
114 TransportType::Tcp => Ok(()),
115 #[cfg(feature = "rustls")]
116 TransportType::Tls => {
117 let tls_config = config
118 .tls
119 .as_ref()
120 .ok_or_else(|| anyhow!("Missing TLS configuration"))?;
121 if _is_server {
122 tls_config
123 .pkcs12
124 .as_ref()
125 .and(tls_config.pkcs12_password.as_ref())
126 .ok_or_else(|| anyhow!("Missing `pkcs12` or `pkcs12_password`"))?;
127 }
128 Ok(())
129 }
130 TransportType::Websocket => Ok(()),
131 }
132 }
133
134 pub fn notls() -> Self {
135 Self {
136 transport_type: TransportType::Websocket,
137 tcp: TcpConfig::default(),
138 tls: None,
139 websocket: WebsocketConfig { tls: false }.into(),
140 }
141 }
142}