aboutsummaryrefslogtreecommitdiff
path: root/azalea-client/src/account/mod.rs
blob: 7b8192c34117cad6cf6f833f3a2d9aca023cc77c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
//! Connect to Minecraft servers.

#[cfg(feature = "online-mode")]
pub mod microsoft;
pub mod offline;
#[cfg(feature = "online-mode")]
pub mod yggdrasil;

use std::{fmt::Debug, ops::Deref, pin::Pin, sync::Arc};

#[cfg(feature = "online-mode")]
use azalea_auth::sessionserver::ClientSessionServerError;
use bevy_ecs::component::Component;
use uuid::Uuid;

/// Something that can join Minecraft servers.
///
/// By default, Azalea only supports either authentication with Microsoft
/// (online-mode), or no authentication at all (offline-mode). If you'd like to
/// do authentication in some other way, consider looking at [`AccountTrait`].
///
/// To join a server using this account, you can either use
/// [`StartJoinServerEvent`] or `azalea::ClientBuilder`.
///
/// Note that `Account` is also an ECS component that's present on our client
/// entities.
///
/// # Examples
///
/// ```rust,no_run
/// # use azalea_client::Account;
/// #
/// # #[tokio::main]
/// # async fn main() {
/// let account = Account::microsoft("example@example.com").await;
/// // or Account::offline("example");
/// # }
/// ```
///
/// [`StartJoinServerEvent`]: crate::join::StartJoinServerEvent
/// [`azalea::ClientBuilder`]: https://docs.rs/azalea/latest/azalea/struct.ClientBuilder.html
#[derive(Clone, Component, Debug)]
pub struct Account(Arc<dyn AccountTrait>);

impl Account {
    #[deprecated = "moved to `uuid()`."]
    pub fn uuid_or_offline(&self) -> Uuid {
        self.uuid()
    }
}

pub(crate) type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;

/// A trait that all types of accounts implement.
///
/// This can be used, for example, to join servers with a custom authentication
/// server.
///
/// Anything that implements [`AccountTrait`] can be converted to an [`Account`]
/// with `.into()`.
///
/// Consider reading the source code of
/// [`MicrosoftAccount`](microsoft::MicrosoftAccount) for an example of how to
/// implement this.
pub trait AccountTrait: Send + Sync + Debug {
    /// Returns the Minecraft username of the account.
    fn username(&self) -> &str;
    /// Returns the unique identifier for this player.
    ///
    /// For offline-mode accounts, this UUID is generated by calling
    /// [`azalea_crypto::offline::generate_uuid`].
    fn uuid(&self) -> Uuid;

    /// The access token for authentication.
    ///
    /// You can obtain one of these manually from `azalea-auth`.
    fn access_token(&self) -> Option<String>;

    /// Refreshes the access token for this account.
    #[cfg(feature = "online-mode")]
    fn refresh(&self) -> BoxFuture<'_, Result<(), azalea_auth::AuthError>> {
        Box::pin(async { Ok(()) })
    }
    /// Refreshes the access token for this account.
    ///
    /// The `online-mode` feature is disabled, so this won't do anything.
    #[cfg(not(feature = "online-mode"))]
    fn refresh(&self) -> BoxFuture<'_, Result<(), ()>> {
        Box::pin(async { Ok(()) })
    }

    #[cfg(feature = "online-mode")]
    fn certs(&self) -> Option<azalea_auth::certs::Certificates> {
        None
    }
    /// Override the chat signing certificates for this account.
    ///
    /// You can get the certificates needed for this from
    /// [`azalea_auth::certs::fetch_certificates`]. You typically don't need to
    /// call this yourself, as Azalea will do it for you.
    ///
    /// For accounts that don't support signing (i.e. offline-mode), this won't
    /// do anything.
    #[cfg(feature = "online-mode")]
    fn set_certs(&self, certs: azalea_auth::certs::Certificates) {
        let _ = certs;
    }

    fn certs_backend(&self) -> Option<&str> {
        None
    }

    /// Typically used to tell Mojang's sessionserver that we are going to join
    /// a server.
    ///
    /// This must be implemented for accounts that can join online-mode servers.
    ///
    /// This function is called internally by Azalea when the account tries to
    /// join a server, but only if [`AccountTrait::access_token`] is `Some`.
    #[cfg(feature = "online-mode")]
    fn join<'a>(
        &'a self,
        public_key: &'a [u8],
        private_key: &'a [u8; 16],
        server_id: &'a str,
        proxy: Option<reqwest::Proxy>,
    ) -> BoxFuture<'a, Result<(), ClientSessionServerError>> {
        let _ = (public_key, private_key, server_id, proxy);
        Box::pin(async { Ok(()) })
    }
    /// Typically used to tell Mojang's sessionserver that we are going to join
    /// a server.
    ///
    /// The `online-mode` feature is disabled, so this won't do anything.
    #[cfg(not(feature = "online-mode"))]
    fn join(
        &self,
        public_key: &[u8],
        private_key: &[u8; 16],
        server_id: &str,
        proxy: Option<()>,
    ) -> BoxFuture<'_, Result<(), ()>> {
        let _ = (public_key, private_key, server_id, proxy);
        Box::pin(async { Ok(()) })
    }
}
impl<T: AccountTrait + 'static> From<T> for Account {
    fn from(value: T) -> Self {
        Account(Arc::new(value))
    }
}
impl Deref for Account {
    type Target = dyn AccountTrait;

    fn deref(&self) -> &Self::Target {
        &*self.0
    }
}