summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar bigfoot547 <[email protected]>2025-03-18 00:31:00 -0500
committerLibravatar bigfoot547 <[email protected]>2025-03-18 00:31:00 -0500
commit5fd29cf69032f0de9cbb111d17a5e218195a75c8 (patch)
treeeb8e42656c680eb1fbddb1e428bc2d86d2f65636
parentlint (diff)
wip: account login progressHEADmaster
-rw-r--r--ozone-cli/src/main.rs26
-rw-r--r--ozone/src/auth.rs43
-rw-r--r--ozone/src/util/progress.rs6
3 files changed, 59 insertions, 16 deletions
diff --git a/ozone-cli/src/main.rs b/ozone-cli/src/main.rs
index 05fef49..d4b70a5 100644
--- a/ozone-cli/src/main.rs
+++ b/ozone-cli/src/main.rs
@@ -377,7 +377,12 @@ async fn main_inner(cli: Cli, multi: MultiProgress) -> Result<ExitCode, Box<dyn
println!("Authentication success! Logging in...");
- match acct.log_in_silent(&client).await {
+ let progress = IndicatifProgress {
+ bar: multi.add(ProgressBar::no_length()
+ .with_style(ProgressStyle::with_template("{spinner} Step {pos} of {len}: {msg}").unwrap()))
+ };
+
+ match acct.log_in_silent(&client, &progress as &dyn ProgressIndication).await {
Ok(_) => (),
Err(e) => match e.kind() {
AuthErrorKind::NotOnXbox => {
@@ -405,6 +410,8 @@ async fn main_inner(cli: Cli, multi: MultiProgress) -> Result<ExitCode, Box<dyn
}
}
+ progress.bar.finish();
+
let key = accounts.add_account(acct.into()).expect("authentication succeeded but xuid missing????");
if !args.no_select {
accounts.set_selected_account(key);
@@ -453,10 +460,14 @@ async fn main_inner(cli: Cli, multi: MultiProgress) -> Result<ExitCode, Box<dyn
};
let client = MsaAccount::create_client();
+ let progress = IndicatifProgress {
+ bar: multi.add(ProgressBar::no_length()
+ .with_style(ProgressStyle::with_template("{spinner} Step {pos} of {len}: {msg}").unwrap()))
+ };
match account {
Account::MSA(msa_acct) => {
- msa_acct.log_in_silent(&client).await?;
+ msa_acct.log_in_silent(&client, &progress as &dyn ProgressIndication).await?;
println!("Successfully refreshed account: {}", account);
},
_ => {
@@ -465,6 +476,8 @@ async fn main_inner(cli: Cli, multi: MultiProgress) -> Result<ExitCode, Box<dyn
}
}
+ progress.bar.finish();
+
accounts.save(&accounts_path).await?;
}
}
@@ -490,8 +503,13 @@ async fn main_inner(cli: Cli, multi: MultiProgress) -> Result<ExitCode, Box<dyn
if let Account::MSA(msa_acct) = account {
let client = MsaAccount::create_client();
+ let progress = IndicatifProgress {
+ bar: multi.add(ProgressBar::no_length()
+ .with_style(ProgressStyle::with_template("{spinner} Step {pos} of {len}: {msg}").unwrap()))
+ };
+
println!("Looking up account information...");
- match msa_acct.log_in_silent(&client).await {
+ match msa_acct.log_in_silent(&client, &progress as &dyn ProgressIndication).await {
Ok(_) => (),
Err(e) if e.kind() == AuthErrorKind::InteractionRequired => {
eprintln!("This account requires interactive authentication: {}", account);
@@ -503,6 +521,8 @@ async fn main_inner(cli: Cli, multi: MultiProgress) -> Result<ExitCode, Box<dyn
return Ok(ExitCode::FAILURE);
}
}
+
+ progress.bar.finish();
}
accounts.save(&accounts_path).await?;
diff --git a/ozone/src/auth.rs b/ozone/src/auth.rs
index ca06e93..9b934cd 100644
--- a/ozone/src/auth.rs
+++ b/ozone/src/auth.rs
@@ -15,6 +15,7 @@ pub use types::*;
use crate::auth::error::{AuthError, AuthErrorKind};
use self::msa::{XSTS_RP_MINECRAFT_SERVICES, XSTS_RP_XBOX_LIVE};
use crate::util;
+use crate::util::progress::{Step, StepProgress};
impl Token {
fn is_expired(&self, now: DateTime<Utc>) -> bool {
@@ -72,7 +73,7 @@ impl MsaAccount {
// logs into xbox live using a refresh token
// (panics if no refresh token present)
- async fn xbl_login_refresh(&mut self, client: &reqwest::Client) -> Result<(), AuthError> {
+ async fn xbl_login_refresh(&mut self, client: &reqwest::Client, xbl_login: Step<'_, '_>) -> Result<(), AuthError> {
debug!("Using refresh token for XBL login");
let oauth_client = create_oauth_client!(self.is_azure_client_id, self.client_id.clone());
let refresh_token = self.refresh_token.as_ref().expect("refresh_access_token called with no refresh token");
@@ -80,7 +81,6 @@ impl MsaAccount {
let tokenres: BasicTokenResponse = oauth_client
.exchange_refresh_token(refresh_token)
.add_scopes(self.scopes_iter())
- .add_extra_param("response_type", "device_code")
.request_async(client)
.await.map_err(|e| match e {
RequestTokenError::ServerResponse(res)
@@ -91,6 +91,7 @@ impl MsaAccount {
self.refresh_token = tokenres.refresh_token().cloned();
+ xbl_login.make_current();
self.xbl_login(client, tokenres.access_token()).await
}
@@ -124,7 +125,7 @@ impl MsaAccount {
// - check if the XBL token is valid/not expired
// - if it is expired, try to use refresh token to get a new one
// - get rid of auth token if yeah
- async fn ensure_xbl(&mut self, client: &reqwest::Client, now: DateTime<Utc>) -> Result<(), AuthError> {
+ async fn ensure_xbl<'p>(&mut self, client: &reqwest::Client, now: DateTime<Utc>, xbl_refresh_step: Step<'p, '_>, xbl_login_step: Step<'p, '_>) -> Result<(), AuthError> {
if self.xbl_token.as_ref().is_some_and(|tok| !tok.is_expired(now)) {
debug!("XBL token valid. Using it.");
return Ok(())
@@ -135,7 +136,8 @@ impl MsaAccount {
}
debug!("XBL token expired. Trying to refresh it.");
- self.xbl_login_refresh(client).await?;
+ xbl_refresh_step.make_current();
+ self.xbl_login_refresh(client, xbl_login_step).await?;
self.mc_token = None;
@@ -146,12 +148,13 @@ impl MsaAccount {
// - if the minecraft services token invalid/expired/missing, do the following
// - get minecraftservices xsts token
// - use minecraftservices to get mojang token with that xsts token
- async fn ensure_mc_token(&mut self, client: &reqwest::Client, now: DateTime<Utc>) -> Result<(), AuthError> {
+ async fn ensure_mc_token<'p>(&mut self, client: &reqwest::Client, now: DateTime<Utc>, xsts_step: Step<'p, '_>, login_step: Step<'p, '_>) -> Result<(), AuthError> {
if self.mc_token.as_ref().is_some_and(|tok| !tok.is_expired(now)) {
debug!("Mojang token valid. Using it.");
return Ok(())
}
+ xsts_step.make_current();
debug!("Mojang token has expired. Must log in again.");
let xbl_token = self.xbl_token.as_ref().expect("ensure_mc_token requires xbl token").value.as_str();
let (user_hash, mc_xsts_tok) = match msa::xsts_request(client, xbl_token, XSTS_RP_MINECRAFT_SERVICES).await? {
@@ -163,6 +166,7 @@ impl MsaAccount {
msa::XSTSAuthResponse::Error(e) => return Err(e.into())
};
+ login_step.make_current();
debug!("Got MinecraftServices XSTS, logging in.");
self.mc_token = Some(mcservices::login_with_xbox(client, mc_xsts_tok.as_str(), user_hash.as_str()).await?);
@@ -190,18 +194,23 @@ impl MsaAccount {
Ok(())
}
- async fn load_profile(&mut self, client: &reqwest::Client) -> Result<(), AuthError> {
+ async fn load_profile(&mut self, client: &reqwest::Client, steps: [Step<'_, '_>; 4]) -> Result<(), AuthError> {
+ steps[0].make_current();
self.load_xbox_info(client).await?;
let mc_token = self.mc_token.as_ref().expect("minecraft token missing").value.as_str();
+ steps[1].make_current();
debug!("Checking if you own the game...");
if !mcservices::owns_the_game(client, mc_token).await? {
return Err(AuthErrorKind::NotEntitled.into());
}
debug!("Getting your profile info...");
+ steps[2].make_current();
let player_info = mcservices::get_player_info(client, mc_token).await?;
+
+ steps[3].make_current();
let player_profile = mcservices::get_player_profile(client, player_info.id).await
.map_err(|e| AuthError::internal_msg_src("looking up profile", e))?;
@@ -211,14 +220,28 @@ impl MsaAccount {
Ok(())
}
- pub async fn log_in_silent(&mut self, client: &reqwest::Client) -> Result<(), AuthError> {
+ pub async fn log_in_silent(&mut self, client: &reqwest::Client, progress: &dyn util::progress::ProgressIndication) -> Result<(), AuthError> {
+ let steps = StepProgress::from(progress);
+ let step_login = steps.step("Attempt non-interactive login");
+ let step_xbl_refresh = steps.step("Refresh Xbox Live token");
+ let step_xbl_login = steps.step("Log into Xbox Live");
+ let step_mc_xsts = steps.step("Request Minecraft XSTS token");
+ let step_mcs_login = steps.step("Log into Minecraft");
+ let step_xbl_profile = steps.step("Retrieve your Xbox profile");
+ let step_mc_entitlement = steps.step("Check if you own Minecraft");
+ let step_mc_profile_1 = steps.step("Look up your Minecraft profile (1)");
+ let step_mc_profile_2 = steps.step("Look up your Minecraft profile (2)");
+ steps.update_max();
+
+ step_login.make_current();
+
// see it's kind of funny that I call this variable "now" despite the fact that it's
// unconditionally 12 hours in the future - figboot
let now = Utc::now() + TimeDelta::hours(12);
- self.ensure_xbl(client, now).await?;
- self.ensure_mc_token(client, now).await?;
- self.load_profile(client).await?;
+ self.ensure_xbl(client, now, step_xbl_refresh, step_xbl_login).await?;
+ self.ensure_mc_token(client, now, step_mc_xsts, step_mcs_login).await?;
+ self.load_profile(client, [step_xbl_profile, step_mc_entitlement, step_mc_profile_1, step_mc_profile_2]).await?;
Ok(())
}
diff --git a/ozone/src/util/progress.rs b/ozone/src/util/progress.rs
index 4d2b5e3..ec444c5 100644
--- a/ozone/src/util/progress.rs
+++ b/ozone/src/util/progress.rs
@@ -31,10 +31,10 @@ pub(crate) struct StepProgress<'ind> {
curidx: AtomicUsize
}
-impl<'ind> Into<StepProgress<'ind>> for &'ind dyn ProgressIndication {
- fn into(self) -> StepProgress<'ind> {
+impl<'ind> From<&'ind dyn ProgressIndication> for StepProgress<'ind> {
+ fn from(ind: &'ind dyn ProgressIndication) -> StepProgress<'ind> {
StepProgress {
- inner: self,
+ inner: ind,
curidx: AtomicUsize::new(0)
}
}