Skip to content

Commit 47e28d2

Browse files
Launcher Auth (#450)
* Launcher Auth * Finish auth * final fixes
1 parent a35dd67 commit 47e28d2

38 files changed

Lines changed: 1200 additions & 477 deletions

Cargo.lock

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

theseus/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "theseus"
3-
version = "0.3.1"
3+
version = "0.4.0"
44
authors = ["Jai A <jaiagr+gpg@pm.me>"]
55
edition = "2018"
66

theseus/src/api/auth.rs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ pub async fn authenticate_begin_flow() -> crate::Result<url::Url> {
2020
/// This completes the authentication flow quasi-synchronously, returning the credentials
2121
/// This can be used in conjunction with 'authenticate_begin_flow'
2222
/// to call authenticate and call the flow from the frontend.
23-
pub async fn authenticate_await_complete_flow() -> crate::Result<Credentials> {
23+
pub async fn authenticate_await_complete_flow(
24+
) -> crate::Result<(Credentials, Option<String>)> {
2425
let credentials = AuthTask::await_auth_completion().await?;
2526
Ok(credentials)
2627
}
@@ -38,7 +39,7 @@ pub async fn cancel_flow() -> crate::Result<()> {
3839
#[theseus_macros::debug_pin]
3940
pub async fn authenticate(
4041
browser_url: oneshot::Sender<url::Url>,
41-
) -> crate::Result<Credentials> {
42+
) -> crate::Result<(Credentials, Option<String>)> {
4243
let mut flow = inner::HydraAuthFlow::new().await?;
4344
let state = State::get().await?;
4445

@@ -52,12 +53,12 @@ pub async fn authenticate(
5253
let credentials = flow.extract_credentials(&state.fetch_semaphore).await?;
5354
{
5455
let mut users = state.users.write().await;
55-
users.insert(&credentials).await?;
56+
users.insert(&credentials.0).await?;
5657
}
5758

5859
if state.settings.read().await.default_user.is_none() {
5960
let mut settings = state.settings.write().await;
60-
settings.default_user = Some(credentials.id);
61+
settings.default_user = Some(credentials.0.id);
6162
}
6263

6364
Ok(credentials)
@@ -79,8 +80,17 @@ pub async fn refresh(user: uuid::Uuid) -> crate::Result<Credentials> {
7980
})?;
8081

8182
let fetch_semaphore = &state.fetch_semaphore;
82-
if Utc::now() > credentials.expires {
83-
inner::refresh_credentials(&mut credentials, fetch_semaphore).await?;
83+
if Utc::now() > credentials.expires
84+
&& inner::refresh_credentials(&mut credentials, fetch_semaphore)
85+
.await
86+
.is_err()
87+
{
88+
users.remove(credentials.id).await?;
89+
90+
return Err(crate::ErrorKind::OtherError(
91+
"Please re-authenticate with your Minecraft account!".to_string(),
92+
)
93+
.as_error());
8494
}
8595
users.insert(&credentials).await?;
8696

theseus/src/api/jre.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use serde::Deserialize;
44
use std::path::PathBuf;
55

66
use crate::event::emit::{emit_loading, init_loading};
7+
use crate::state::CredentialsStore;
78
use crate::util::fetch::{fetch_advanced, fetch_json};
89
use crate::util::io;
910
use crate::util::jre::extract_java_majorminor_version;
@@ -97,6 +98,7 @@ pub async fn auto_install_java(java_version: u32) -> crate::Result<PathBuf> {
9798
None,
9899
None,
99100
&state.fetch_semaphore,
101+
&CredentialsStore(None),
100102
).await?;
101103
emit_loading(&loading_bar, 10.0, Some("Downloading java version")).await?;
102104

@@ -109,6 +111,7 @@ pub async fn auto_install_java(java_version: u32) -> crate::Result<PathBuf> {
109111
None,
110112
Some((&loading_bar, 80.0)),
111113
&state.fetch_semaphore,
114+
&CredentialsStore(None),
112115
)
113116
.await?;
114117

theseus/src/api/mod.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ pub mod handler;
44
pub mod jre;
55
pub mod logs;
66
pub mod metadata;
7+
pub mod mr_auth;
78
pub mod pack;
89
pub mod process;
910
pub mod profile;
@@ -14,9 +15,9 @@ pub mod tags;
1415
pub mod data {
1516
pub use crate::state::{
1617
DirectoryInfo, Hooks, JavaSettings, LinkedData, MemorySettings,
17-
ModLoader, ModrinthProject, ModrinthTeamMember, ModrinthUser,
18-
ModrinthVersion, ProfileMetadata, ProjectMetadata, Settings, Theme,
19-
WindowSize,
18+
ModLoader, ModrinthCredentials, ModrinthCredentialsResult,
19+
ModrinthProject, ModrinthTeamMember, ModrinthUser, ModrinthVersion,
20+
ProfileMetadata, ProjectMetadata, Settings, Theme, WindowSize,
2021
};
2122
}
2223

theseus/src/api/mr_auth.rs

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
use crate::state::{
2+
ModrinthAuthFlow, ModrinthCredentials, ModrinthCredentialsResult,
3+
};
4+
use crate::ErrorKind;
5+
6+
#[tracing::instrument]
7+
pub async fn authenticate_begin_flow(provider: &str) -> crate::Result<String> {
8+
let state = crate::State::get().await?;
9+
10+
let mut flow = ModrinthAuthFlow::new(provider).await?;
11+
let url = flow.prepare_login_url().await?;
12+
13+
let mut write = state.modrinth_auth_flow.write().await;
14+
*write = Some(flow);
15+
16+
Ok(url)
17+
}
18+
19+
#[tracing::instrument]
20+
pub async fn authenticate_await_complete_flow(
21+
) -> crate::Result<ModrinthCredentialsResult> {
22+
let state = crate::State::get().await?;
23+
24+
let mut write = state.modrinth_auth_flow.write().await;
25+
if let Some(ref mut flow) = *write {
26+
let creds = flow.extract_credentials(&state.fetch_semaphore).await?;
27+
28+
if let ModrinthCredentialsResult::Credentials(creds) = &creds {
29+
let mut write = state.credentials.write().await;
30+
write.login(creds.clone()).await?;
31+
}
32+
33+
Ok(creds)
34+
} else {
35+
Err(ErrorKind::OtherError(
36+
"No active Modrinth authenication flow!".to_string(),
37+
)
38+
.into())
39+
}
40+
}
41+
42+
#[tracing::instrument]
43+
pub async fn cancel_flow() -> crate::Result<()> {
44+
let state = crate::State::get().await?;
45+
let mut write = state.modrinth_auth_flow.write().await;
46+
if let Some(ref mut flow) = *write {
47+
flow.close().await?;
48+
}
49+
*write = None;
50+
Ok(())
51+
}
52+
53+
pub async fn login_password(
54+
username: &str,
55+
password: &str,
56+
challenge: &str,
57+
) -> crate::Result<ModrinthCredentialsResult> {
58+
let state = crate::State::get().await?;
59+
let creds = crate::state::login_password(
60+
username,
61+
password,
62+
challenge,
63+
&state.fetch_semaphore,
64+
)
65+
.await?;
66+
67+
if let ModrinthCredentialsResult::Credentials(creds) = &creds {
68+
let mut write = state.credentials.write().await;
69+
write.login(creds.clone()).await?;
70+
}
71+
72+
Ok(creds)
73+
}
74+
75+
#[tracing::instrument]
76+
pub async fn login_2fa(
77+
code: &str,
78+
flow: &str,
79+
) -> crate::Result<ModrinthCredentials> {
80+
let state = crate::State::get().await?;
81+
let creds =
82+
crate::state::login_2fa(code, flow, &state.fetch_semaphore).await?;
83+
84+
let mut write = state.credentials.write().await;
85+
write.login(creds.clone()).await?;
86+
87+
Ok(creds)
88+
}
89+
90+
#[tracing::instrument]
91+
pub async fn login_minecraft(
92+
flow: &str,
93+
) -> crate::Result<ModrinthCredentialsResult> {
94+
let state = crate::State::get().await?;
95+
let creds =
96+
crate::state::login_minecraft(flow, &state.fetch_semaphore).await?;
97+
98+
if let ModrinthCredentialsResult::Credentials(creds) = &creds {
99+
let mut write = state.credentials.write().await;
100+
write.login(creds.clone()).await?;
101+
}
102+
103+
Ok(creds)
104+
}
105+
106+
#[tracing::instrument]
107+
pub async fn create_account(
108+
username: &str,
109+
email: &str,
110+
password: &str,
111+
challenge: &str,
112+
sign_up_newsletter: bool,
113+
) -> crate::Result<ModrinthCredentials> {
114+
let state = crate::State::get().await?;
115+
let creds = crate::state::create_account(
116+
username,
117+
email,
118+
password,
119+
challenge,
120+
sign_up_newsletter,
121+
&state.fetch_semaphore,
122+
)
123+
.await?;
124+
125+
let mut write = state.credentials.write().await;
126+
write.login(creds.clone()).await?;
127+
128+
Ok(creds)
129+
}
130+
131+
#[tracing::instrument]
132+
pub async fn refresh() -> crate::Result<()> {
133+
let state = crate::State::get().await?;
134+
135+
let mut write = state.credentials.write().await;
136+
crate::state::refresh_credentials(&mut write, &state.fetch_semaphore)
137+
.await?;
138+
139+
Ok(())
140+
}
141+
142+
#[tracing::instrument]
143+
pub async fn logout() -> crate::Result<()> {
144+
let state = crate::State::get().await?;
145+
let mut write = state.credentials.write().await;
146+
write.logout().await?;
147+
148+
Ok(())
149+
}
150+
151+
#[tracing::instrument]
152+
pub async fn get_credentials() -> crate::Result<Option<ModrinthCredentials>> {
153+
let state = crate::State::get().await?;
154+
let read = state.credentials.read().await;
155+
156+
Ok(read.0.clone())
157+
}

theseus/src/api/pack/import/curseforge.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use std::path::PathBuf;
22

33
use serde::{Deserialize, Serialize};
44

5+
use crate::state::CredentialsStore;
56
use crate::{
67
prelude::{ModLoader, ProfilePathId},
78
state::ProfileInstallStage,
@@ -90,8 +91,13 @@ pub async fn import_curseforge(
9091
thumbnail_url: Some(thumbnail_url),
9192
}) = minecraft_instance.installed_modpack.clone()
9293
{
93-
let icon_bytes =
94-
fetch(&thumbnail_url, None, &state.fetch_semaphore).await?;
94+
let icon_bytes = fetch(
95+
&thumbnail_url,
96+
None,
97+
&state.fetch_semaphore,
98+
&CredentialsStore(None),
99+
)
100+
.await?;
95101
let filename = thumbnail_url.rsplit('/').last();
96102
if let Some(filename) = filename {
97103
icon = Some(

theseus/src/api/pack/install_from.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,12 +192,14 @@ pub async fn generate_pack_from_version_id(
192192
.await?;
193193

194194
emit_loading(&loading_bar, 0.0, Some("Fetching version")).await?;
195+
let creds = state.credentials.read().await;
195196
let version: ModrinthVersion = fetch_json(
196197
Method::GET,
197198
&format!("{}version/{}", MODRINTH_API_URL, version_id),
198199
None,
199200
None,
200201
&state.fetch_semaphore,
202+
&creds,
201203
)
202204
.await?;
203205
emit_loading(&loading_bar, 10.0, None).await?;
@@ -225,6 +227,7 @@ pub async fn generate_pack_from_version_id(
225227
None,
226228
Some((&loading_bar, 70.0)),
227229
&state.fetch_semaphore,
230+
&creds,
228231
)
229232
.await?;
230233
emit_loading(&loading_bar, 0.0, Some("Fetching project metadata")).await?;
@@ -235,13 +238,16 @@ pub async fn generate_pack_from_version_id(
235238
None,
236239
None,
237240
&state.fetch_semaphore,
241+
&creds,
238242
)
239243
.await?;
240244

241245
emit_loading(&loading_bar, 10.0, Some("Retrieving icon")).await?;
242246
let icon = if let Some(icon_url) = project.icon_url {
243247
let state = State::get().await?;
244-
let icon_bytes = fetch(&icon_url, None, &state.fetch_semaphore).await?;
248+
let icon_bytes =
249+
fetch(&icon_url, None, &state.fetch_semaphore, &creds).await?;
250+
drop(creds);
245251

246252
let filename = icon_url.rsplit('/').next();
247253

theseus/src/api/pack/install_mrpack.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ pub async fn install_zipped_mrpack_files(
168168
}
169169
}
170170

171+
let creds = state.credentials.read().await;
171172
let file = fetch_mirrors(
172173
&project
173174
.downloads
@@ -176,8 +177,10 @@ pub async fn install_zipped_mrpack_files(
176177
.collect::<Vec<&str>>(),
177178
project.hashes.get(&PackFileHash::Sha1).map(|x| &**x),
178179
&state.fetch_semaphore,
180+
&creds,
179181
)
180182
.await?;
183+
drop(creds);
181184

182185
let path =
183186
std::path::Path::new(&project.path).components().next();

0 commit comments

Comments
 (0)