cobble_core/profile/
mod.rs1mod entitlements;
2mod microsoft;
3mod minecraft;
4mod minecraft_profile;
5mod xbl;
6mod xsts;
7
8use crate::error::{AuthError, AuthResult};
9pub use microsoft::DeviceCodeInfo;
10use time::OffsetDateTime;
11use uuid::Uuid;
12
13#[cfg_attr(doc_cfg, doc(cfg(feature = "auth")))]
33#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
34#[derive(Clone, Debug)]
35pub struct CobbleProfile {
36 pub uuid: Uuid,
38 pub profile_id: String,
40 pub player_name: String,
42 pub microsoft_refresh_token: String,
44 pub minecraft_token: String,
46 #[cfg_attr(feature = "serde", serde(with = "time::serde::rfc3339"))]
48 pub minecraft_token_exp: OffsetDateTime,
49}
50
51impl CobbleProfile {
52 pub fn access_token(&self) -> String {
54 self.minecraft_token.clone()
55 }
56
57 #[instrument(name = "setup_profile_authentication", level = "debug", skip_all)]
61 pub async fn setup_authentication(client_id: String) -> AuthResult<DeviceCodeInfo> {
62 microsoft::setup_authentication(client_id).await
63 }
64
65 #[instrument(name = "authenticate_profile", level = "debug", skip_all)]
68 pub async fn authenticate(info: DeviceCodeInfo) -> AuthResult<Self> {
69 let microsoft = info.finish_authentication().await?;
70 let xbl = xbl::authenticate(µsoft.access_token).await?;
71 let xsts = xsts::authenticate(&xbl.access_token).await?;
72 let minecraft = minecraft::authenticate(&xsts.access_token, &xbl.user_hash).await?;
73
74 let entitlements = entitlements::get_entitlements(&minecraft.access_token).await?;
75
76 let minecraft_entitlement = entitlements
77 .entitlements
78 .iter()
79 .find(|e| e.name == "product_minecraft");
80
81 if minecraft_entitlement.is_none() {
82 trace!("User does not have 'product_minecraft' entitlements");
83 return Err(AuthError::Unauthorized);
84 }
85
86 let profile = minecraft_profile::get_profile(&minecraft.access_token).await?;
87
88 Ok(CobbleProfile {
89 uuid: Uuid::new_v4(),
90 profile_id: profile.id,
91 player_name: profile.name,
92 microsoft_refresh_token: microsoft.refresh_token,
93 minecraft_token: minecraft.access_token,
94 minecraft_token_exp: minecraft.expiration,
95 })
96 }
97
98 #[instrument(name = "refresh_profile", level = "debug", skip_all)]
100 pub async fn refresh(&mut self, client_id: String) -> AuthResult<()> {
101 let microsoft =
102 microsoft::refresh_token(client_id, self.microsoft_refresh_token.clone()).await?;
103 let xbl = xbl::authenticate(µsoft.access_token).await?;
104 let xsts = xsts::authenticate(&xbl.access_token).await?;
105 let minecraft = minecraft::authenticate(&xsts.access_token, &xbl.user_hash).await?;
106
107 self.microsoft_refresh_token = microsoft.refresh_token;
108 self.minecraft_token = minecraft.access_token;
109 self.minecraft_token_exp = minecraft.expiration;
110
111 Ok(())
112 }
113}