Skip to content

Commit

Permalink
Launcher Auth (#450)
Browse files Browse the repository at this point in the history
* Launcher Auth

* Finish auth

* final fixes
  • Loading branch information
Geometrically committed Aug 5, 2023
1 parent a35dd67 commit 47e28d2
Show file tree
Hide file tree
Showing 38 changed files with 1,200 additions and 477 deletions.
6 changes: 3 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion theseus/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "theseus"
version = "0.3.1"
version = "0.4.0"
authors = ["Jai A <[email protected]>"]
edition = "2018"

Expand Down
22 changes: 16 additions & 6 deletions theseus/src/api/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ pub async fn authenticate_begin_flow() -> crate::Result<url::Url> {
/// This completes the authentication flow quasi-synchronously, returning the credentials
/// This can be used in conjunction with 'authenticate_begin_flow'
/// to call authenticate and call the flow from the frontend.
pub async fn authenticate_await_complete_flow() -> crate::Result<Credentials> {
pub async fn authenticate_await_complete_flow(
) -> crate::Result<(Credentials, Option<String>)> {
let credentials = AuthTask::await_auth_completion().await?;
Ok(credentials)
}
Expand All @@ -38,7 +39,7 @@ pub async fn cancel_flow() -> crate::Result<()> {
#[theseus_macros::debug_pin]
pub async fn authenticate(
browser_url: oneshot::Sender<url::Url>,
) -> crate::Result<Credentials> {
) -> crate::Result<(Credentials, Option<String>)> {
let mut flow = inner::HydraAuthFlow::new().await?;
let state = State::get().await?;

Expand All @@ -52,12 +53,12 @@ pub async fn authenticate(
let credentials = flow.extract_credentials(&state.fetch_semaphore).await?;
{
let mut users = state.users.write().await;
users.insert(&credentials).await?;
users.insert(&credentials.0).await?;
}

if state.settings.read().await.default_user.is_none() {
let mut settings = state.settings.write().await;
settings.default_user = Some(credentials.id);
settings.default_user = Some(credentials.0.id);
}

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

let fetch_semaphore = &state.fetch_semaphore;
if Utc::now() > credentials.expires {
inner::refresh_credentials(&mut credentials, fetch_semaphore).await?;
if Utc::now() > credentials.expires
&& inner::refresh_credentials(&mut credentials, fetch_semaphore)
.await
.is_err()
{
users.remove(credentials.id).await?;

return Err(crate::ErrorKind::OtherError(
"Please re-authenticate with your Minecraft account!".to_string(),
)
.as_error());
}
users.insert(&credentials).await?;

Expand Down
3 changes: 3 additions & 0 deletions theseus/src/api/jre.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use serde::Deserialize;
use std::path::PathBuf;

use crate::event::emit::{emit_loading, init_loading};
use crate::state::CredentialsStore;
use crate::util::fetch::{fetch_advanced, fetch_json};
use crate::util::io;
use crate::util::jre::extract_java_majorminor_version;
Expand Down Expand Up @@ -97,6 +98,7 @@ pub async fn auto_install_java(java_version: u32) -> crate::Result<PathBuf> {
None,
None,
&state.fetch_semaphore,
&CredentialsStore(None),
).await?;
emit_loading(&loading_bar, 10.0, Some("Downloading java version")).await?;

Expand All @@ -109,6 +111,7 @@ pub async fn auto_install_java(java_version: u32) -> crate::Result<PathBuf> {
None,
Some((&loading_bar, 80.0)),
&state.fetch_semaphore,
&CredentialsStore(None),
)
.await?;

Expand Down
7 changes: 4 additions & 3 deletions theseus/src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pub mod handler;
pub mod jre;
pub mod logs;
pub mod metadata;
pub mod mr_auth;
pub mod pack;
pub mod process;
pub mod profile;
Expand All @@ -14,9 +15,9 @@ pub mod tags;
pub mod data {
pub use crate::state::{
DirectoryInfo, Hooks, JavaSettings, LinkedData, MemorySettings,
ModLoader, ModrinthProject, ModrinthTeamMember, ModrinthUser,
ModrinthVersion, ProfileMetadata, ProjectMetadata, Settings, Theme,
WindowSize,
ModLoader, ModrinthCredentials, ModrinthCredentialsResult,
ModrinthProject, ModrinthTeamMember, ModrinthUser, ModrinthVersion,
ProfileMetadata, ProjectMetadata, Settings, Theme, WindowSize,
};
}

Expand Down
157 changes: 157 additions & 0 deletions theseus/src/api/mr_auth.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
use crate::state::{
ModrinthAuthFlow, ModrinthCredentials, ModrinthCredentialsResult,
};
use crate::ErrorKind;

#[tracing::instrument]
pub async fn authenticate_begin_flow(provider: &str) -> crate::Result<String> {
let state = crate::State::get().await?;

let mut flow = ModrinthAuthFlow::new(provider).await?;
let url = flow.prepare_login_url().await?;

let mut write = state.modrinth_auth_flow.write().await;
*write = Some(flow);

Ok(url)
}

#[tracing::instrument]
pub async fn authenticate_await_complete_flow(
) -> crate::Result<ModrinthCredentialsResult> {
let state = crate::State::get().await?;

let mut write = state.modrinth_auth_flow.write().await;
if let Some(ref mut flow) = *write {
let creds = flow.extract_credentials(&state.fetch_semaphore).await?;

if let ModrinthCredentialsResult::Credentials(creds) = &creds {
let mut write = state.credentials.write().await;
write.login(creds.clone()).await?;
}

Ok(creds)
} else {
Err(ErrorKind::OtherError(
"No active Modrinth authenication flow!".to_string(),
)
.into())
}
}

#[tracing::instrument]
pub async fn cancel_flow() -> crate::Result<()> {
let state = crate::State::get().await?;
let mut write = state.modrinth_auth_flow.write().await;
if let Some(ref mut flow) = *write {
flow.close().await?;
}
*write = None;
Ok(())
}

pub async fn login_password(
username: &str,
password: &str,
challenge: &str,
) -> crate::Result<ModrinthCredentialsResult> {
let state = crate::State::get().await?;
let creds = crate::state::login_password(
username,
password,
challenge,
&state.fetch_semaphore,
)
.await?;

if let ModrinthCredentialsResult::Credentials(creds) = &creds {
let mut write = state.credentials.write().await;
write.login(creds.clone()).await?;
}

Ok(creds)
}

#[tracing::instrument]
pub async fn login_2fa(
code: &str,
flow: &str,
) -> crate::Result<ModrinthCredentials> {
let state = crate::State::get().await?;
let creds =
crate::state::login_2fa(code, flow, &state.fetch_semaphore).await?;

let mut write = state.credentials.write().await;
write.login(creds.clone()).await?;

Ok(creds)
}

#[tracing::instrument]
pub async fn login_minecraft(
flow: &str,
) -> crate::Result<ModrinthCredentialsResult> {
let state = crate::State::get().await?;
let creds =
crate::state::login_minecraft(flow, &state.fetch_semaphore).await?;

if let ModrinthCredentialsResult::Credentials(creds) = &creds {
let mut write = state.credentials.write().await;
write.login(creds.clone()).await?;
}

Ok(creds)
}

#[tracing::instrument]
pub async fn create_account(
username: &str,
email: &str,
password: &str,
challenge: &str,
sign_up_newsletter: bool,
) -> crate::Result<ModrinthCredentials> {
let state = crate::State::get().await?;
let creds = crate::state::create_account(
username,
email,
password,
challenge,
sign_up_newsletter,
&state.fetch_semaphore,
)
.await?;

let mut write = state.credentials.write().await;
write.login(creds.clone()).await?;

Ok(creds)
}

#[tracing::instrument]
pub async fn refresh() -> crate::Result<()> {
let state = crate::State::get().await?;

let mut write = state.credentials.write().await;
crate::state::refresh_credentials(&mut write, &state.fetch_semaphore)
.await?;

Ok(())
}

#[tracing::instrument]
pub async fn logout() -> crate::Result<()> {
let state = crate::State::get().await?;
let mut write = state.credentials.write().await;
write.logout().await?;

Ok(())
}

#[tracing::instrument]
pub async fn get_credentials() -> crate::Result<Option<ModrinthCredentials>> {
let state = crate::State::get().await?;
let read = state.credentials.read().await;

Ok(read.0.clone())
}
10 changes: 8 additions & 2 deletions theseus/src/api/pack/import/curseforge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use std::path::PathBuf;

use serde::{Deserialize, Serialize};

use crate::state::CredentialsStore;
use crate::{
prelude::{ModLoader, ProfilePathId},
state::ProfileInstallStage,
Expand Down Expand Up @@ -90,8 +91,13 @@ pub async fn import_curseforge(
thumbnail_url: Some(thumbnail_url),
}) = minecraft_instance.installed_modpack.clone()
{
let icon_bytes =
fetch(&thumbnail_url, None, &state.fetch_semaphore).await?;
let icon_bytes = fetch(
&thumbnail_url,
None,
&state.fetch_semaphore,
&CredentialsStore(None),
)
.await?;
let filename = thumbnail_url.rsplit('/').last();
if let Some(filename) = filename {
icon = Some(
Expand Down
8 changes: 7 additions & 1 deletion theseus/src/api/pack/install_from.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,12 +192,14 @@ pub async fn generate_pack_from_version_id(
.await?;

emit_loading(&loading_bar, 0.0, Some("Fetching version")).await?;
let creds = state.credentials.read().await;
let version: ModrinthVersion = fetch_json(
Method::GET,
&format!("{}version/{}", MODRINTH_API_URL, version_id),
None,
None,
&state.fetch_semaphore,
&creds,
)
.await?;
emit_loading(&loading_bar, 10.0, None).await?;
Expand Down Expand Up @@ -225,6 +227,7 @@ pub async fn generate_pack_from_version_id(
None,
Some((&loading_bar, 70.0)),
&state.fetch_semaphore,
&creds,
)
.await?;
emit_loading(&loading_bar, 0.0, Some("Fetching project metadata")).await?;
Expand All @@ -235,13 +238,16 @@ pub async fn generate_pack_from_version_id(
None,
None,
&state.fetch_semaphore,
&creds,
)
.await?;

emit_loading(&loading_bar, 10.0, Some("Retrieving icon")).await?;
let icon = if let Some(icon_url) = project.icon_url {
let state = State::get().await?;
let icon_bytes = fetch(&icon_url, None, &state.fetch_semaphore).await?;
let icon_bytes =
fetch(&icon_url, None, &state.fetch_semaphore, &creds).await?;
drop(creds);

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

Expand Down
3 changes: 3 additions & 0 deletions theseus/src/api/pack/install_mrpack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ pub async fn install_zipped_mrpack_files(
}
}

let creds = state.credentials.read().await;
let file = fetch_mirrors(
&project
.downloads
Expand All @@ -176,8 +177,10 @@ pub async fn install_zipped_mrpack_files(
.collect::<Vec<&str>>(),
project.hashes.get(&PackFileHash::Sha1).map(|x| &**x),
&state.fetch_semaphore,
&creds,
)
.await?;
drop(creds);

let path =
std::path::Path::new(&project.path).components().next();
Expand Down
Loading

0 comments on commit 47e28d2

Please sign in to comment.