1use std::sync::Arc;
3
4use common_net::msg::ServerInfo;
5use network::{ConnectAddr, Network};
6use rustls::client::danger::ServerCertVerified;
7use tracing::warn;
8
9use crate::{Error, addr};
10
11#[derive(Clone)]
12pub enum Credentials {
13 UsernamePassword(String, String),
14 Username(String),
15}
16
17pub trait CredentialProvider {
18 fn auth_trusted(&self, auth_provider: &Option<String>) -> bool;
21
22 fn get_credentials(
28 &self,
29 auth_provider: &Option<String>,
30 ) -> impl std::future::Future<Output = Result<Credentials, ()>> + Send;
31}
32
33#[derive(Default)]
36pub struct StaticCredentialProvider {
37 pub credentials_by_auth: std::collections::HashMap<Option<String>, Credentials>,
38}
39
40impl CredentialProvider for StaticCredentialProvider {
41 fn auth_trusted(&self, auth_provider: &Option<String>) -> bool {
42 self.credentials_by_auth.contains_key(auth_provider)
43 }
44
45 async fn get_credentials(&self, auth_provider: &Option<String>) -> Result<Credentials, ()> {
46 self.credentials_by_auth
47 .get(auth_provider)
48 .cloned()
49 .ok_or(())
50 }
51}
52
53#[derive(Debug)]
54pub enum ClientInitStage {
55 ConnectionEstablish,
57 WatingForServerVersion,
59 ServerVersionArrived(ServerInfo),
61 Authentication,
63 LoadingInitData,
66 StartingClient,
69 RequestingPlugins,
71}
72
73pub(crate) async fn resolve_token_or_username(
77 credentials: Credentials,
78 trusted_auth_provider: &Option<String>,
79) -> Result<String, Error> {
80 match credentials {
81 Credentials::Username(username) => Ok(username),
82 Credentials::UsernamePassword(username, password) => match &trusted_auth_provider {
83 Some(addr) => {
84 let (scheme, authority) = match addr.split_once("://") {
85 Some((s, a)) => (s, a),
86 None => return Err(Error::AuthServerUrlInvalid(addr.to_string())),
87 };
88
89 let scheme = match scheme.parse::<authc::Scheme>() {
90 Ok(s) => s,
91 Err(_) => return Err(Error::AuthServerUrlInvalid(addr.to_string())),
92 };
93
94 let authority = match authority.parse::<authc::Authority>() {
95 Ok(a) => a,
96 Err(_) => return Err(Error::AuthServerUrlInvalid(addr.to_string())),
97 };
98
99 Ok(authc::AuthClient::new(scheme, authority)?
100 .sign_in(username, password)
101 .await?
102 .serialize())
103 },
104 None => Ok(username),
105 },
106 }
107}
108
109pub(crate) async fn connect_quic(
110 network: &Network,
111 hostname: String,
112 override_port: Option<u16>,
113 prefer_ipv6: bool,
114 validate_tls: bool,
115) -> Result<network::Participant, crate::error::Error> {
116 let config = if validate_tls {
117 quinn::ClientConfig::try_with_platform_verifier()?
118 } else {
119 warn!(
120 "skipping validation of server identity. There is no guarantee that the server you're \
121 connected to is the one you expect to be connecting to."
122 );
123 #[derive(Debug)]
124 struct Verifier;
125 impl rustls::client::danger::ServerCertVerifier for Verifier {
126 fn verify_server_cert(
127 &self,
128 _end_entity: &rustls::pki_types::CertificateDer<'_>,
129 _intermediates: &[rustls::pki_types::CertificateDer<'_>],
130 _server_name: &rustls::pki_types::ServerName<'_>,
131 _ocsp_response: &[u8],
132 _now: rustls::pki_types::UnixTime,
133 ) -> Result<ServerCertVerified, rustls::Error> {
134 Ok(ServerCertVerified::assertion())
135 }
136
137 fn verify_tls12_signature(
138 &self,
139 _message: &[u8],
140 _cert: &rustls::pki_types::CertificateDer<'_>,
141 _dss: &rustls::DigitallySignedStruct,
142 ) -> Result<rustls::client::danger::HandshakeSignatureValid, rustls::Error>
143 {
144 Ok(rustls::client::danger::HandshakeSignatureValid::assertion())
145 }
146
147 fn verify_tls13_signature(
148 &self,
149 _message: &[u8],
150 _cert: &rustls::pki_types::CertificateDer<'_>,
151 _dss: &rustls::DigitallySignedStruct,
152 ) -> Result<rustls::client::danger::HandshakeSignatureValid, rustls::Error>
153 {
154 Ok(rustls::client::danger::HandshakeSignatureValid::assertion())
155 }
156
157 fn supported_verify_schemes(&self) -> Vec<rustls::SignatureScheme> {
158 vec![
159 rustls::SignatureScheme::RSA_PKCS1_SHA1,
160 rustls::SignatureScheme::ECDSA_SHA1_Legacy,
161 rustls::SignatureScheme::RSA_PKCS1_SHA256,
162 rustls::SignatureScheme::ECDSA_NISTP256_SHA256,
163 rustls::SignatureScheme::RSA_PKCS1_SHA384,
164 rustls::SignatureScheme::ECDSA_NISTP384_SHA384,
165 rustls::SignatureScheme::RSA_PKCS1_SHA512,
166 rustls::SignatureScheme::ECDSA_NISTP521_SHA512,
167 rustls::SignatureScheme::RSA_PSS_SHA256,
168 rustls::SignatureScheme::RSA_PSS_SHA384,
169 rustls::SignatureScheme::RSA_PSS_SHA512,
170 rustls::SignatureScheme::ED25519,
171 rustls::SignatureScheme::ED448,
172 ]
173 }
174 }
175
176 let mut cfg = rustls::ClientConfig::builder()
177 .dangerous()
178 .with_custom_certificate_verifier(Arc::new(Verifier))
179 .with_no_client_auth();
180 cfg.enable_early_data = true;
181
182 quinn::ClientConfig::new(Arc::new(
183 quinn::crypto::rustls::QuicClientConfig::try_from(cfg).unwrap(),
184 ))
185 };
186
187 addr::try_connect(network, &hostname, override_port, prefer_ipv6, |a| {
188 ConnectAddr::Quic(a, config.clone(), hostname.clone())
189 })
190 .await
191}