1
0

Launcher Auth (#450)

* Launcher Auth

* Finish auth

* final fixes
This commit is contained in:
Geometrically
2023-08-04 23:38:34 -07:00
committed by GitHub
parent a35dd67b77
commit 47e28d24c8
38 changed files with 1200 additions and 477 deletions

View File

@@ -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)
}
@@ -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?;
@@ -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)
@@ -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?;

View File

@@ -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;
@@ -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?;
@@ -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?;

View File

@@ -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;
@@ -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,
};
}

157
theseus/src/api/mr_auth.rs Normal file
View File

@@ -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())
}

View File

@@ -2,6 +2,7 @@ use std::path::PathBuf;
use serde::{Deserialize, Serialize};
use crate::state::CredentialsStore;
use crate::{
prelude::{ModLoader, ProfilePathId},
state::ProfileInstallStage,
@@ -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(

View File

@@ -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?;
@@ -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?;
@@ -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();

View File

@@ -168,6 +168,7 @@ pub async fn install_zipped_mrpack_files(
}
}
let creds = state.credentials.read().await;
let file = fetch_mirrors(
&project
.downloads
@@ -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();