Skip to main content

veloren_client/
init.rs

1//! Code and utils for Initializing the connection to the server.
2use 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    ///provides a quick check to verify if a Auth Server is expected and
19    /// trusted This function is expected to return quickly.
20    fn auth_trusted(&self, auth_provider: &Option<String>) -> bool;
21
22    ///Called by the client once we are connected to the server and the server
23    /// is requiring us to provide Credentials.
24    /// This function is expected to trigger UI to wait for a result. So the
25    /// User might take a minute or so to log in.
26    /// Throw Error in case you want to abort login.
27    fn get_credentials(
28        &self,
29        auth_provider: &Option<String>,
30    ) -> impl std::future::Future<Output = Result<Credentials, ()>> + Send;
31}
32
33/// Use in case you already know your Auth provider Username and Password
34/// upfront.
35#[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    /// A connection to the server is being created
56    ConnectionEstablish,
57    /// Waiting for server version
58    WatingForServerVersion,
59    /// Server Version successfuly arrived, do a first PING
60    ServerVersionArrived(ServerInfo),
61    /// We're currently authenticating with the server
62    Authentication,
63    /// Loading map data, site information, recipe information and other
64    /// initialization data
65    LoadingInitData,
66    /// Prepare data received by the server to be used by the client (insert
67    /// data into the ECS, render map)
68    StartingClient,
69    /// Requesting Plugins from Server and downloading them
70    RequestingPlugins,
71}
72
73/// Use this to get the "token_or_username" which is required by a server, token
74/// if auth is used, username if it runs without auth.
75/// NOTE: only call it if you trust the auth_provider!
76pub(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}