You've already forked AstralRinth
forked from didirus/AstralRinth
Add auth servers unreachable warning to app (#4774)
* Add auth servers unreachable warning to app * Check auth status every 5 minutes * Use admonition in auth server warning * feat: tanstack * Fix auth server reachability query * Format * intl extract --------- Co-authored-by: Calum H. (IMB11) <contact@cal.engineer>
This commit is contained in:
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@@ -13,7 +13,7 @@
|
|||||||
},
|
},
|
||||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||||
"[vue]": {
|
"[vue]": {
|
||||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
"editor.defaultFormatter": "rvest.vs-code-prettier-eslint"
|
||||||
},
|
},
|
||||||
"[typescript]": {
|
"[typescript]": {
|
||||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import {
|
|||||||
XIcon,
|
XIcon,
|
||||||
} from '@modrinth/assets'
|
} from '@modrinth/assets'
|
||||||
import {
|
import {
|
||||||
|
Admonition,
|
||||||
Avatar,
|
Avatar,
|
||||||
Button,
|
Button,
|
||||||
ButtonStyled,
|
ButtonStyled,
|
||||||
@@ -36,8 +37,10 @@ import {
|
|||||||
ProgressSpinner,
|
ProgressSpinner,
|
||||||
provideModrinthClient,
|
provideModrinthClient,
|
||||||
provideNotificationManager,
|
provideNotificationManager,
|
||||||
|
useDebugLogger,
|
||||||
} from '@modrinth/ui'
|
} from '@modrinth/ui'
|
||||||
import { renderString } from '@modrinth/utils'
|
import { renderString } from '@modrinth/utils'
|
||||||
|
import { useQuery } from '@tanstack/vue-query'
|
||||||
import { getVersion } from '@tauri-apps/api/app'
|
import { getVersion } from '@tauri-apps/api/app'
|
||||||
import { invoke } from '@tauri-apps/api/core'
|
import { invoke } from '@tauri-apps/api/core'
|
||||||
import { getCurrentWindow } from '@tauri-apps/api/window'
|
import { getCurrentWindow } from '@tauri-apps/api/window'
|
||||||
@@ -71,6 +74,7 @@ import URLConfirmModal from '@/components/ui/URLConfirmModal.vue'
|
|||||||
import { useCheckDisableMouseover } from '@/composables/macCssFix.js'
|
import { useCheckDisableMouseover } from '@/composables/macCssFix.js'
|
||||||
import { hide_ads_window, init_ads_window, show_ads_window } from '@/helpers/ads.js'
|
import { hide_ads_window, init_ads_window, show_ads_window } from '@/helpers/ads.js'
|
||||||
import { debugAnalytics, initAnalytics, optOutAnalytics, trackEvent } from '@/helpers/analytics'
|
import { debugAnalytics, initAnalytics, optOutAnalytics, trackEvent } from '@/helpers/analytics'
|
||||||
|
import { check_reachable } from '@/helpers/auth.js'
|
||||||
import { get_user } from '@/helpers/cache.js'
|
import { get_user } from '@/helpers/cache.js'
|
||||||
import { command_listener, warning_listener } from '@/helpers/events.js'
|
import { command_listener, warning_listener } from '@/helpers/events.js'
|
||||||
import { useFetch } from '@/helpers/fetch.js'
|
import { useFetch } from '@/helpers/fetch.js'
|
||||||
@@ -139,6 +143,27 @@ const criticalErrorMessage = ref()
|
|||||||
|
|
||||||
const isMaximized = ref(false)
|
const isMaximized = ref(false)
|
||||||
|
|
||||||
|
const authUnreachableDebug = useDebugLogger('AuthReachableChecker')
|
||||||
|
const authServerQuery = useQuery({
|
||||||
|
queryKey: ['authServerReachability'],
|
||||||
|
queryFn: async () => {
|
||||||
|
await check_reachable()
|
||||||
|
authUnreachableDebug('Auth servers are reachable')
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
refetchInterval: 5 * 60 * 1000, // 5 minutes
|
||||||
|
retry: false,
|
||||||
|
refetchOnWindowFocus: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
const authUnreachable = computed(() => {
|
||||||
|
if (authServerQuery.isError.value && !authServerQuery.isLoading.value) {
|
||||||
|
console.warn('Failed to reach auth servers', authServerQuery.error.value)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await useCheckDisableMouseover()
|
await useCheckDisableMouseover()
|
||||||
|
|
||||||
@@ -177,6 +202,15 @@ const messages = defineMessages({
|
|||||||
id: 'app.update.downloading-update',
|
id: 'app.update.downloading-update',
|
||||||
defaultMessage: 'Downloading update ({percent}%)',
|
defaultMessage: 'Downloading update ({percent}%)',
|
||||||
},
|
},
|
||||||
|
authUnreachableHeader: {
|
||||||
|
id: 'app.auth-servers.unreachable.header',
|
||||||
|
defaultMessage: 'Cannot reach authentication servers',
|
||||||
|
},
|
||||||
|
authUnreachableBody: {
|
||||||
|
id: 'app.auth-servers.unreachable.body',
|
||||||
|
defaultMessage:
|
||||||
|
'Minecraft authentication servers may be down right now. Check your internet connection and try again later.',
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
async function setupApp() {
|
async function setupApp() {
|
||||||
@@ -325,7 +359,11 @@ const handleClose = async () => {
|
|||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
router.afterEach((to, from, failure) => {
|
router.afterEach((to, from, failure) => {
|
||||||
trackEvent('PageView', { path: to.path, fromPath: from.path, failed: failure })
|
trackEvent('PageView', {
|
||||||
|
path: to.path,
|
||||||
|
fromPath: from.path,
|
||||||
|
failed: failure,
|
||||||
|
})
|
||||||
})
|
})
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
|
|
||||||
@@ -989,16 +1027,25 @@ provideAppUpdateDownloadProgress(appUpdateDownload)
|
|||||||
width: 'calc(100% - var(--right-bar-width))',
|
width: 'calc(100% - var(--right-bar-width))',
|
||||||
}"
|
}"
|
||||||
></div>
|
></div>
|
||||||
<div
|
<Admonition
|
||||||
v-if="criticalErrorMessage"
|
v-if="criticalErrorMessage"
|
||||||
class="m-6 mb-0 flex flex-col border-red bg-bg-red rounded-2xl border-2 border-solid p-4 gap-1 font-semibold text-contrast"
|
type="critical"
|
||||||
|
:header="criticalErrorMessage.header"
|
||||||
|
class="m-6 mb-0"
|
||||||
>
|
>
|
||||||
<h1 class="m-0 text-lg font-extrabold">{{ criticalErrorMessage.header }}</h1>
|
|
||||||
<div
|
<div
|
||||||
class="markdown-body text-primary"
|
class="markdown-body text-primary"
|
||||||
v-html="renderString(criticalErrorMessage.body ?? '')"
|
v-html="renderString(criticalErrorMessage.body ?? '')"
|
||||||
></div>
|
></div>
|
||||||
</div>
|
</Admonition>
|
||||||
|
<Admonition
|
||||||
|
v-if="authUnreachable"
|
||||||
|
type="warning"
|
||||||
|
:header="formatMessage(messages.authUnreachableHeader)"
|
||||||
|
class="m-6 mb-0"
|
||||||
|
>
|
||||||
|
{{ formatMessage(messages.authUnreachableBody) }}
|
||||||
|
</Admonition>
|
||||||
<RouterView v-slot="{ Component }">
|
<RouterView v-slot="{ Component }">
|
||||||
<template v-if="Component">
|
<template v-if="Component">
|
||||||
<Suspense @pending="loading.startLoading()" @resolve="loading.stopLoading()">
|
<Suspense @pending="loading.startLoading()" @resolve="loading.stopLoading()">
|
||||||
|
|||||||
@@ -13,6 +13,14 @@ import { invoke } from '@tauri-apps/api/core'
|
|||||||
// await authenticate_await_completion()
|
// await authenticate_await_completion()
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the authentication servers are reachable, throwing an exception if
|
||||||
|
* not reachable.
|
||||||
|
*/
|
||||||
|
export async function check_reachable() {
|
||||||
|
await invoke('plugin:auth|check_reachable')
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Authenticate a user with Hydra - part 1.
|
* Authenticate a user with Hydra - part 1.
|
||||||
* This begins the authentication flow quasi-synchronously.
|
* This begins the authentication flow quasi-synchronously.
|
||||||
|
|||||||
@@ -1,4 +1,10 @@
|
|||||||
{
|
{
|
||||||
|
"app.auth-servers.unreachable.body": {
|
||||||
|
"message": "Minecraft authentication servers may be down right now. Check your internet connection and try again later."
|
||||||
|
},
|
||||||
|
"app.auth-servers.unreachable.header": {
|
||||||
|
"message": "Cannot reach authentication servers"
|
||||||
|
},
|
||||||
"app.settings.developer-mode-enabled": {
|
"app.settings.developer-mode-enabled": {
|
||||||
"message": "Developer mode enabled."
|
"message": "Developer mode enabled."
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ fn main() {
|
|||||||
"auth",
|
"auth",
|
||||||
InlinedPlugin::new()
|
InlinedPlugin::new()
|
||||||
.commands(&[
|
.commands(&[
|
||||||
|
"check_reachable",
|
||||||
"login",
|
"login",
|
||||||
"remove_user",
|
"remove_user",
|
||||||
"get_default_user",
|
"get_default_user",
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ use theseus::prelude::*;
|
|||||||
pub fn init<R: Runtime>() -> TauriPlugin<R> {
|
pub fn init<R: Runtime>() -> TauriPlugin<R> {
|
||||||
tauri::plugin::Builder::<R>::new("auth")
|
tauri::plugin::Builder::<R>::new("auth")
|
||||||
.invoke_handler(tauri::generate_handler![
|
.invoke_handler(tauri::generate_handler![
|
||||||
|
check_reachable,
|
||||||
login,
|
login,
|
||||||
remove_user,
|
remove_user,
|
||||||
get_default_user,
|
get_default_user,
|
||||||
@@ -16,6 +17,13 @@ pub fn init<R: Runtime>() -> TauriPlugin<R> {
|
|||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Checks if the authentication servers are reachable.
|
||||||
|
#[tauri::command]
|
||||||
|
pub async fn check_reachable() -> Result<()> {
|
||||||
|
minecraft_auth::check_reachable().await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Authenticate a user with Hydra - part 1
|
/// Authenticate a user with Hydra - part 1
|
||||||
/// This begins the authentication flow quasi-synchronously, returning a URL to visit (that the user will sign in at)
|
/// This begins the authentication flow quasi-synchronously, returning a URL to visit (that the user will sign in at)
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
|||||||
@@ -1,7 +1,23 @@
|
|||||||
//! Authentication flow interface
|
//! Authentication flow interface
|
||||||
|
|
||||||
|
use reqwest::StatusCode;
|
||||||
|
|
||||||
use crate::State;
|
use crate::State;
|
||||||
use crate::state::{Credentials, MinecraftLoginFlow};
|
use crate::state::{Credentials, MinecraftLoginFlow};
|
||||||
|
use crate::util::fetch::REQWEST_CLIENT;
|
||||||
|
|
||||||
|
#[tracing::instrument]
|
||||||
|
pub async fn check_reachable() -> crate::Result<()> {
|
||||||
|
let resp = REQWEST_CLIENT
|
||||||
|
.get("https://api.minecraftservices.com/entitlements/mcstore")
|
||||||
|
.send()
|
||||||
|
.await?;
|
||||||
|
if resp.status() == StatusCode::UNAUTHORIZED {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
resp.error_for_status()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[tracing::instrument]
|
#[tracing::instrument]
|
||||||
pub async fn begin_login() -> crate::Result<MinecraftLoginFlow> {
|
pub async fn begin_login() -> crate::Result<MinecraftLoginFlow> {
|
||||||
|
|||||||
Reference in New Issue
Block a user