Skip to content

Commit 6097027

Browse files
committed
refactor(theseus): extend auth subsystem to fetch complete user profiles
1 parent 974676a commit 6097027

File tree

11 files changed

+497
-117
lines changed

11 files changed

+497
-117
lines changed

Cargo.lock

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

apps/app-frontend/src/components/ui/AccountsCard.vue

+13-13
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,12 @@
1010
size="36px"
1111
:src="
1212
selectedAccount
13-
? `https://mc-heads.net/avatar/${selectedAccount.id}/128`
13+
? `https://mc-heads.net/avatar/${selectedAccount.profile.id}/128`
1414
: 'https://launcher-files.modrinth.com/assets/steve_head.png'
1515
"
1616
/>
1717
<div class="flex flex-col w-full">
18-
<span>{{ selectedAccount ? selectedAccount.username : 'Select account' }}</span>
18+
<span>{{ selectedAccount ? selectedAccount.profile.name : 'Select account' }}</span>
1919
<span class="text-secondary text-xs">Minecraft account</span>
2020
</div>
2121
<DropdownIcon class="w-5 h-5 shrink-0" />
@@ -28,12 +28,12 @@
2828
:class="{ expanded: mode === 'expanded', isolated: mode === 'isolated' }"
2929
>
3030
<div v-if="selectedAccount" class="selected account">
31-
<Avatar size="xs" :src="`https://mc-heads.net/avatar/${selectedAccount.id}/128`" />
31+
<Avatar size="xs" :src="`https://mc-heads.net/avatar/${selectedAccount.profile.id}/128`" />
3232
<div>
33-
<h4>{{ selectedAccount.username }}</h4>
33+
<h4>{{ selectedAccount.profile.name }}</h4>
3434
<p>Selected</p>
3535
</div>
36-
<Button v-tooltip="'Log out'" icon-only color="raised" @click="logout(selectedAccount.id)">
36+
<Button v-tooltip="'Log out'" icon-only color="raised" @click="logout(selectedAccount.profile.id)">
3737
<TrashIcon />
3838
</Button>
3939
</div>
@@ -44,12 +44,12 @@
4444
</Button>
4545
</div>
4646
<div v-if="displayAccounts.length > 0" class="account-group">
47-
<div v-for="account in displayAccounts" :key="account.id" class="account-row">
47+
<div v-for="account in displayAccounts" :key="account.profile.id" class="account-row">
4848
<Button class="option account" @click="setAccount(account)">
49-
<Avatar :src="`https://mc-heads.net/avatar/${account.id}/128`" class="icon" />
50-
<p>{{ account.username }}</p>
49+
<Avatar :src="`https://mc-heads.net/avatar/${account.profile.id}/128`" class="icon" />
50+
<p>{{ account.profile.name }}</p>
5151
</Button>
52-
<Button v-tooltip="'Log out'" icon-only @click="logout(account.id)">
52+
<Button v-tooltip="'Log out'" icon-only @click="logout(account.profile.id)">
5353
<TrashIcon />
5454
</Button>
5555
</div>
@@ -101,16 +101,16 @@ defineExpose({
101101
await refreshValues()
102102
103103
const displayAccounts = computed(() =>
104-
accounts.value.filter((account) => defaultUser.value !== account.id),
104+
accounts.value.filter((account) => defaultUser.value !== account.profile.id),
105105
)
106106
107107
const selectedAccount = computed(() =>
108-
accounts.value.find((account) => account.id === defaultUser.value),
108+
accounts.value.find((account) => account.profile.id === defaultUser.value),
109109
)
110110
111111
async function setAccount(account) {
112-
defaultUser.value = account.id
113-
await set_default_user(account.id).catch(handleError)
112+
defaultUser.value = account.profile.id
113+
await set_default_user(account.profile.id).catch(handleError)
114114
emit('change')
115115
}
116116

apps/app-frontend/src/components/ui/ErrorModal.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ async function loginMinecraft() {
9292
const loggedIn = await login_flow()
9393
9494
if (loggedIn) {
95-
await set_default_user(loggedIn.id).catch(handleError)
95+
await set_default_user(loggedIn.profile.id).catch(handleError)
9696
}
9797
9898
await trackEvent('AccountLogIn', { source: 'ErrorModal' })

apps/app-playground/src/main.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,10 @@ pub async fn authenticate_run() -> theseus::Result<Credentials> {
2828

2929
let credentials = minecraft_auth::finish_login(&input, login).await?;
3030

31-
println!("Logged in user {}.", credentials.username);
31+
println!(
32+
"Logged in user {}.",
33+
credentials.maybe_online_profile().await.name
34+
);
3235
Ok(credentials)
3336
}
3437

packages/app-lib/Cargo.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ serde_json = "1.0"
1111
serde_ini = "0.2.0"
1212
sha1_smol = { version = "1.0.0", features = ["std"] }
1313
sha2 = "0.10.8"
14-
url = "2.2"
14+
url = { version = "2.2", features = ["serde"] }
1515
uuid = { version = "1.1", features = ["serde", "v4"] }
1616
zip = "0.6.5"
1717
async_zip = { version = "0.0.17", features = ["chrono", "tokio-fs", "deflate", "bzip2", "zstd", "deflate64"] }
@@ -33,6 +33,7 @@ tracing = "0.1.37"
3333
tracing-subscriber = { version = "0.3.18", features = ["chrono", "env-filter"] }
3434
tracing-error = "0.2.0"
3535

36+
heck = "0.5.0"
3637
paste = { version = "1.0" }
3738

3839
tauri = { version = "2.0.0-rc", optional = true }

packages/app-lib/src/api/logs.rs

+15-9
Original file line numberDiff line numberDiff line change
@@ -39,21 +39,27 @@ pub struct LatestLogCursor {
3939
#[serde(transparent)]
4040
pub struct CensoredString(String);
4141
impl CensoredString {
42-
pub fn censor(mut s: String, credentials_set: &Vec<Credentials>) -> Self {
42+
pub fn censor(mut s: String, credentials_list: &[Credentials]) -> Self {
4343
let username = whoami::username();
4444
s = s
45-
.replace(&format!("/{}/", username), "/{COMPUTER_USERNAME}/")
46-
.replace(&format!("\\{}\\", username), "\\{COMPUTER_USERNAME}\\");
47-
for credentials in credentials_set {
45+
.replace(&format!("/{username}/"), "/{COMPUTER_USERNAME}/")
46+
.replace(&format!("\\{username}\\"), "\\{COMPUTER_USERNAME}\\");
47+
for credentials in credentials_list {
48+
// Use the offline profile to guarantee that this function is does not cause
49+
// Mojang API request, and is never delayed by a network request. The offline
50+
// profile is optimistically updated on upsert from time to time anyway
4851
s = s
4952
.replace(&credentials.access_token, "{MINECRAFT_ACCESS_TOKEN}")
50-
.replace(&credentials.username, "{MINECRAFT_USERNAME}")
5153
.replace(
52-
&credentials.id.as_simple().to_string(),
54+
&credentials.offline_profile.name,
55+
"{MINECRAFT_USERNAME}",
56+
)
57+
.replace(
58+
&credentials.offline_profile.id.as_simple().to_string(),
5359
"{MINECRAFT_UUID}",
5460
)
5561
.replace(
56-
&credentials.id.as_hyphenated().to_string(),
62+
&credentials.offline_profile.id.as_hyphenated().to_string(),
5763
"{MINECRAFT_UUID}",
5864
);
5965
}
@@ -210,7 +216,7 @@ pub async fn get_output_by_filename(
210216
.await?
211217
.into_iter()
212218
.map(|x| x.1)
213-
.collect();
219+
.collect::<Vec<_>>();
214220

215221
// Load .gz file into String
216222
if let Some(ext) = path.extension() {
@@ -350,7 +356,7 @@ pub async fn get_generic_live_log_cursor(
350356
.await?
351357
.into_iter()
352358
.map(|x| x.1)
353-
.collect();
359+
.collect::<Vec<_>>();
354360
let output = CensoredString::censor(output, &credentials);
355361
Ok(LatestLogCursor {
356362
cursor,

packages/app-lib/src/api/minecraft_auth.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ pub async fn finish_login(
2323
#[tracing::instrument]
2424
pub async fn get_default_user() -> crate::Result<Option<uuid::Uuid>> {
2525
let state = State::get().await?;
26-
let users = Credentials::get_active(&state.pool).await?;
27-
Ok(users.map(|x| x.id))
26+
let user = Credentials::get_active(&state.pool).await?;
27+
Ok(user.map(|user| user.offline_profile.id))
2828
}
2929

3030
#[tracing::instrument]

packages/app-lib/src/launcher/args.rs

+10-7
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ fn parse_jvm_argument(
203203
}
204204

205205
#[allow(clippy::too_many_arguments)]
206-
pub fn get_minecraft_arguments(
206+
pub async fn get_minecraft_arguments(
207207
arguments: Option<&[Argument]>,
208208
legacy_arguments: Option<&str>,
209209
credentials: &Credentials,
@@ -215,6 +215,9 @@ pub fn get_minecraft_arguments(
215215
resolution: WindowSize,
216216
java_arch: &str,
217217
) -> crate::Result<Vec<String>> {
218+
let access_token = credentials.access_token.clone();
219+
let profile = credentials.maybe_online_profile().await;
220+
218221
if let Some(arguments) = arguments {
219222
let mut parsed_arguments = Vec::new();
220223

@@ -224,9 +227,9 @@ pub fn get_minecraft_arguments(
224227
|arg| {
225228
parse_minecraft_argument(
226229
arg,
227-
&credentials.access_token,
228-
&credentials.username,
229-
credentials.id,
230+
&access_token,
231+
&profile.name,
232+
profile.id,
230233
version,
231234
asset_index_name,
232235
game_directory,
@@ -244,9 +247,9 @@ pub fn get_minecraft_arguments(
244247
for x in legacy_arguments.split(' ') {
245248
parsed_arguments.push(parse_minecraft_argument(
246249
&x.replace(' ', TEMPORARY_REPLACE_CHAR),
247-
&credentials.access_token,
248-
&credentials.username,
249-
credentials.id,
250+
&access_token,
251+
&profile.name,
252+
profile.id,
250253
version,
251254
asset_index_name,
252255
game_directory,

packages/app-lib/src/launcher/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -602,7 +602,8 @@ pub async fn launch_minecraft(
602602
&version.type_,
603603
*resolution,
604604
&java_version.architecture,
605-
)?
605+
)
606+
.await?
606607
.into_iter()
607608
.collect::<Vec<_>>(),
608609
)

packages/app-lib/src/state/legacy_converter.rs

+11-6
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ use std::path::PathBuf;
1919
use tokio::sync::Semaphore;
2020
use uuid::Uuid;
2121

22+
use super::MinecraftProfile;
23+
2224
pub async fn migrate_legacy_data<'a, E>(exec: E) -> crate::Result<()>
2325
where
2426
E: sqlx::Executor<'a, Database = sqlx::Sqlite> + Copy,
@@ -119,13 +121,16 @@ where
119121
.await
120122
{
121123
let minecraft_users_len = minecraft_auth.users.len();
122-
for (uuid, credential) in minecraft_auth.users {
124+
for (uuid, legacy_credentials) in minecraft_auth.users {
123125
Credentials {
124-
id: credential.id,
125-
username: credential.username,
126-
access_token: credential.access_token,
127-
refresh_token: credential.refresh_token,
128-
expires: credential.expires,
126+
offline_profile: MinecraftProfile {
127+
id: legacy_credentials.id,
128+
name: legacy_credentials.username,
129+
..MinecraftProfile::default()
130+
},
131+
access_token: legacy_credentials.access_token,
132+
refresh_token: legacy_credentials.refresh_token,
133+
expires: legacy_credentials.expires,
129134
active: minecraft_auth.default_user == Some(uuid)
130135
|| minecraft_users_len == 1,
131136
}

0 commit comments

Comments
 (0)