aboutsummaryrefslogtreecommitdiff
path: root/azalea-client/src
diff options
context:
space:
mode:
authormat <27899617+mat-1@users.noreply.github.com>2025-11-30 21:04:12 -0600
committerGitHub <noreply@github.com>2025-11-30 21:04:12 -0600
commit6c110f2731c3893af397cc6a660f374ff705c99b (patch)
treed3441af29cf40b49d474fc04aa1f426ad4292fa0 /azalea-client/src
parent6930966aabf9b49fb6a0dc8b61076fa3f1abc298 (diff)
downloadazalea-drasl-6c110f2731c3893af397cc6a660f374ff705c99b.tar.xz
Add `online-mode` Cargo feature (#281)
* Add `online-mode` cargo feature * fix bad formatting in Cargo.toml
Diffstat (limited to 'azalea-client/src')
-rw-r--r--azalea-client/src/account.rs30
-rw-r--r--azalea-client/src/plugins/chat/handler.rs13
-rw-r--r--azalea-client/src/plugins/chat_signing.rs4
-rw-r--r--azalea-client/src/plugins/disconnect.rs7
-rw-r--r--azalea-client/src/plugins/login.rs94
-rw-r--r--azalea-client/src/plugins/mod.rs8
6 files changed, 100 insertions, 56 deletions
diff --git a/azalea-client/src/account.rs b/azalea-client/src/account.rs
index ab8e8e65..847029c9 100644
--- a/azalea-client/src/account.rs
+++ b/azalea-client/src/account.rs
@@ -2,14 +2,14 @@
use std::sync::Arc;
-use azalea_auth::{
- AccessTokenResponse,
- certs::{Certificates, FetchCertificatesError},
-};
+#[cfg(feature = "online-mode")]
+use azalea_auth::AccessTokenResponse;
+#[cfg(feature = "online-mode")]
+use azalea_auth::certs::{Certificates, FetchCertificatesError};
use bevy_ecs::component::Component;
use parking_lot::Mutex;
+#[cfg(feature = "online-mode")]
use thiserror::Error;
-use tracing::trace;
use uuid::Uuid;
/// Something that can join Minecraft servers.
@@ -58,6 +58,7 @@ pub struct Account {
///
/// This is set when you call [`Self::request_certs`], but you only
/// need to if the servers you're joining require it.
+ #[cfg(feature = "online-mode")]
pub certs: Arc<Mutex<Option<Certificates>>>,
}
@@ -67,9 +68,11 @@ pub enum AccountOpts {
Offline {
username: String,
},
+ #[cfg(feature = "online-mode")]
Microsoft {
email: String,
},
+ #[cfg(feature = "online-mode")]
MicrosoftWithAccessToken {
msa: Arc<Mutex<azalea_auth::cache::ExpiringValue<AccessTokenResponse>>>,
},
@@ -88,6 +91,7 @@ impl Account {
account_opts: AccountOpts::Offline {
username: username.to_string(),
},
+ #[cfg(feature = "online-mode")]
certs: Arc::new(Mutex::new(None)),
}
}
@@ -97,6 +101,7 @@ impl Account {
///
/// The cache key is used for avoiding having to log in every time. This is
/// typically set to the account email, but it can be any string.
+ #[cfg(feature = "online-mode")]
pub async fn microsoft(cache_key: &str) -> Result<Self, azalea_auth::AuthError> {
Self::microsoft_with_custom_client_id_and_scope(cache_key, None, None).await
}
@@ -105,6 +110,7 @@ impl Account {
/// and `scope`.
///
/// Pass `None` if you want to use default ones.
+ #[cfg(feature = "online-mode")]
pub async fn microsoft_with_custom_client_id_and_scope(
cache_key: &str,
client_id: Option<&str>,
@@ -162,6 +168,7 @@ impl Account {
/// # Ok(())
/// # }
/// ```
+ #[cfg(feature = "online-mode")]
pub async fn with_microsoft_access_token(
msa: azalea_auth::cache::ExpiringValue<AccessTokenResponse>,
) -> Result<Self, azalea_auth::AuthError> {
@@ -170,6 +177,7 @@ impl Account {
/// Similar to [`Account::with_microsoft_access_token`] but you can use
/// custom `client_id` and `scope`.
+ #[cfg(feature = "online-mode")]
pub async fn with_microsoft_access_token_and_custom_client_id_and_scope(
mut msa: azalea_auth::cache::ExpiringValue<AccessTokenResponse>,
client_id: Option<&str>,
@@ -178,6 +186,8 @@ impl Account {
let client = reqwest::Client::new();
if msa.is_expired() {
+ use tracing::trace;
+
trace!("refreshing Microsoft auth token");
msa = azalea_auth::refresh_ms_auth_token(
&client,
@@ -209,6 +219,7 @@ impl Account {
/// This requires the `auth_opts` field to be set correctly (which is done
/// by default if you used the constructor functions). Note that if the
/// Account is offline-mode then this function won't do anything.
+ #[cfg(feature = "online-mode")]
pub async fn refresh(&self) -> Result<(), azalea_auth::AuthError> {
match &self.account_opts {
// offline mode doesn't need to refresh so just don't do anything lol
@@ -240,6 +251,13 @@ impl Account {
}
}
+ /// Stub function that does nothing when the `online-mode` feature is
+ /// disabled.
+ #[cfg(not(feature = "online-mode"))]
+ pub async fn refresh(&self) -> Result<(), ()> {
+ Ok(())
+ }
+
/// Get the UUID of this account.
///
/// If the `uuid` field is None, the UUID will be determined by using
@@ -250,6 +268,7 @@ impl Account {
}
}
+#[cfg(feature = "online-mode")]
#[derive(Error, Debug)]
pub enum RequestCertError {
#[error("Failed to fetch certificates")]
@@ -261,6 +280,7 @@ pub enum RequestCertError {
impl Account {
/// Request the certificates used for chat signing and set it in
/// [`Self::certs`].
+ #[cfg(feature = "online-mode")]
pub async fn request_certs(&mut self) -> Result<(), RequestCertError> {
let access_token = self
.access_token
diff --git a/azalea-client/src/plugins/chat/handler.rs b/azalea-client/src/plugins/chat/handler.rs
index 5a2a065c..49f27209 100644
--- a/azalea-client/src/plugins/chat/handler.rs
+++ b/azalea-client/src/plugins/chat/handler.rs
@@ -1,6 +1,5 @@
use std::time::{SystemTime, UNIX_EPOCH};
-use azalea_crypto::SignChatMessageOptions;
use azalea_protocol::packets::{
Packet,
game::{ServerboundChat, ServerboundChatCommand, s_chat::LastSeenMessagesUpdate},
@@ -8,7 +7,9 @@ use azalea_protocol::packets::{
use bevy_ecs::prelude::*;
use super::ChatKind;
-use crate::{Account, chat_signing::ChatSigningSession, packet::game::SendGamePacketEvent};
+use crate::packet::game::SendGamePacketEvent;
+#[cfg(feature = "online-mode")]
+use crate::{Account, chat_signing::ChatSigningSession};
/// Send a chat packet to the server of a specific kind (chat message or
/// command). Usually you just want [`SendChatEvent`] instead.
@@ -31,7 +32,7 @@ pub struct SendChatKindEvent {
pub fn handle_send_chat_kind_event(
mut events: MessageReader<SendChatKindEvent>,
mut commands: Commands,
- mut query: Query<(&Account, &mut ChatSigningSession)>,
+ #[cfg(feature = "online-mode")] mut query: Query<(&Account, &mut ChatSigningSession)>,
) {
for event in events.read() {
let content = event
@@ -47,6 +48,7 @@ pub fn handle_send_chat_kind_event(
ChatKind::Message => {
let salt = azalea_crypto::make_salt();
+ #[cfg(feature = "online-mode")]
let signature = if let Ok((account, mut chat_session)) = query.get_mut(event.entity)
{
Some(create_signature(
@@ -59,6 +61,8 @@ pub fn handle_send_chat_kind_event(
} else {
None
};
+ #[cfg(not(feature = "online-mode"))]
+ let signature = None;
ServerboundChat {
message: content,
@@ -85,6 +89,7 @@ pub fn handle_send_chat_kind_event(
}
}
+#[cfg(feature = "online-mode")]
pub fn create_signature(
account: &Account,
chat_session: &mut ChatSigningSession,
@@ -92,6 +97,8 @@ pub fn create_signature(
timestamp: SystemTime,
message: &str,
) -> azalea_crypto::MessageSignature {
+ use azalea_crypto::SignChatMessageOptions;
+
let certs = account.certs.lock();
let certs = certs.as_ref().expect("certs shouldn't be set back to None");
diff --git a/azalea-client/src/plugins/chat_signing.rs b/azalea-client/src/plugins/chat_signing.rs
index 612383c2..8e612f5b 100644
--- a/azalea-client/src/plugins/chat_signing.rs
+++ b/azalea-client/src/plugins/chat_signing.rs
@@ -43,8 +43,8 @@ pub struct RequestCertsTask(pub Task<Result<Certificates, FetchCertificatesError
pub struct OnlyRefreshCertsAfter {
pub refresh_at: Instant,
}
-/// A component that's present when that this client has sent its certificates
-/// to the server.
+/// A component that's present when this client has sent its certificates to the
+/// server.
///
/// This should be removed if you want to re-send the certs.
///
diff --git a/azalea-client/src/plugins/disconnect.rs b/azalea-client/src/plugins/disconnect.rs
index 95950ae9..08fe3807 100644
--- a/azalea-client/src/plugins/disconnect.rs
+++ b/azalea-client/src/plugins/disconnect.rs
@@ -11,9 +11,11 @@ use derive_more::Deref;
use tracing::info;
use super::login::IsAuthenticated;
+#[cfg(feature = "online-mode")]
+use crate::chat_signing;
use crate::{
- chat_signing, client::JoinedClientBundle, connection::RawConnection,
- local_player::InstanceHolder, tick_counter::TicksConnected,
+ client::JoinedClientBundle, connection::RawConnection, local_player::InstanceHolder,
+ tick_counter::TicksConnected,
};
pub struct DisconnectPlugin;
@@ -69,6 +71,7 @@ pub struct RemoveOnDisconnectBundle {
/// This makes it not send [`DisconnectEvent`] again.
pub is_connection_alive: IsConnectionAlive,
/// Resend our chat signing certs next time.
+ #[cfg(feature = "online-mode")]
pub chat_signing_session: chat_signing::ChatSigningSession,
/// They're not authenticated anymore if they disconnected.
pub is_authenticated: IsAuthenticated,
diff --git a/azalea-client/src/plugins/login.rs b/azalea-client/src/plugins/login.rs
index 25919c8c..46ff8ea9 100644
--- a/azalea-client/src/plugins/login.rs
+++ b/azalea-client/src/plugins/login.rs
@@ -1,3 +1,4 @@
+#[cfg(feature = "online-mode")]
use azalea_auth::sessionserver::ClientSessionServerError;
use azalea_protocol::packets::login::{
ClientboundHello, ServerboundCustomQueryAnswer, ServerboundKey,
@@ -80,8 +81,10 @@ pub struct AuthTask(Task<Result<(ServerboundKey, PrivateKey), AuthWithAccountErr
pub enum AuthWithAccountError {
#[error("Failed to encrypt the challenge from the server for {0:?}")]
Encryption(ClientboundHello),
+ #[cfg(feature = "online-mode")]
#[error("{0}")]
SessionServer(#[from] ClientSessionServerError),
+ #[cfg(feature = "online-mode")]
#[error("Couldn't refresh access token: {0}")]
Auth(#[from] azalea_auth::AuthError),
}
@@ -99,49 +102,56 @@ pub async fn auth_with_account(
};
let private_key = encrypt_res.secret_key;
- let Some(access_token) = &account.access_token else {
- // offline mode account, no need to do auth
- return Ok((key_packet, private_key));
- };
-
- // keep track of the number of times we tried authenticating so we can give up
- // after too many
- let mut attempts: usize = 1;
-
- while let Err(err) = {
- let access_token = access_token.lock().clone();
-
- let uuid = &account
- .uuid
- .expect("Uuid must be present if access token is present.");
-
- // this is necessary since reqwest usually depends on tokio and we're using
- // `futures` here
- async_compat::Compat::new(azalea_auth::sessionserver::join(
- &access_token,
- &packet.public_key,
- &private_key,
- uuid,
- &packet.server_id,
- ))
- .await
- } {
- if attempts >= 2 {
- // if this is the second attempt and we failed
- // both times, give up
- return Err(err.into());
- }
- if matches!(
- err,
- ClientSessionServerError::InvalidSession | ClientSessionServerError::ForbiddenOperation
- ) {
- // uh oh, we got an invalid session and have
- // to reauthenticate now
- async_compat::Compat::new(account.refresh()).await?;
- } else {
- return Err(err.into());
+ #[cfg(not(feature = "online-mode"))]
+ let _ = account;
+
+ #[cfg(feature = "online-mode")]
+ if packet.should_authenticate {
+ let Some(access_token) = &account.access_token else {
+ // offline mode account, no need to do auth
+ return Ok((key_packet, private_key));
+ };
+
+ // keep track of the number of times we tried authenticating so we can give up
+ // after too many
+ let mut attempts: usize = 1;
+
+ while let Err(err) = {
+ let access_token = access_token.lock().clone();
+
+ let uuid = &account
+ .uuid
+ .expect("Uuid must be present if access token is present.");
+
+ // this is necessary since reqwest usually depends on tokio and we're using
+ // `futures` here
+ async_compat::Compat::new(azalea_auth::sessionserver::join(
+ &access_token,
+ &packet.public_key,
+ &private_key,
+ uuid,
+ &packet.server_id,
+ ))
+ .await
+ } {
+ if attempts >= 2 {
+ // if this is the second attempt and we failed
+ // both times, give up
+ return Err(err.into());
+ }
+ if matches!(
+ err,
+ ClientSessionServerError::InvalidSession
+ | ClientSessionServerError::ForbiddenOperation
+ ) {
+ // uh oh, we got an invalid session and have
+ // to reauthenticate now
+ async_compat::Compat::new(account.refresh()).await?;
+ } else {
+ return Err(err.into());
+ }
+ attempts += 1;
}
- attempts += 1;
}
Ok((key_packet, private_key))
diff --git a/azalea-client/src/plugins/mod.rs b/azalea-client/src/plugins/mod.rs
index a12d69cb..54f577e3 100644
--- a/azalea-client/src/plugins/mod.rs
+++ b/azalea-client/src/plugins/mod.rs
@@ -5,6 +5,7 @@ pub mod auto_reconnect;
pub mod block_update;
pub mod brand;
pub mod chat;
+#[cfg(feature = "online-mode")]
pub mod chat_signing;
pub mod chunks;
pub mod client_information;
@@ -62,8 +63,11 @@ impl PluginGroup for DefaultPlugins {
.add(connection::ConnectionPlugin)
.add(login::LoginPlugin)
.add(join::JoinPlugin)
- .add(auto_reconnect::AutoReconnectPlugin)
- .add(chat_signing::ChatSigningPlugin);
+ .add(auto_reconnect::AutoReconnectPlugin);
+ #[cfg(feature = "online-mode")]
+ {
+ group = group.add(chat_signing::ChatSigningPlugin);
+ }
#[cfg(feature = "log")]
{
group = group.add(bevy_log::LogPlugin::default());