From d1a9c15f06e719e7d9854d8ae40e299db5f7f3b9 Mon Sep 17 00:00:00 2001 From: Bernd Storath Date: Tue, 2 Jun 2026 15:37:01 +0200 Subject: [PATCH] move 2fa to its own page --- src/app/layouts/default.vue | 4 +- src/app/middleware/auth.global.ts | 6 +- src/app/pages/login.vue | 144 +----------------------------- src/app/pages/login/2fa.vue | 106 ++++++++++++++++++++++ src/app/pages/login/index.vue | 130 +++++++++++++++++++++++++++ src/app/pages/me.vue | 9 +- src/app/stores/login.ts | 36 ++++++++ 7 files changed, 285 insertions(+), 150 deletions(-) create mode 100644 src/app/pages/login/2fa.vue create mode 100644 src/app/pages/login/index.vue create mode 100644 src/app/stores/login.ts diff --git a/src/app/layouts/default.vue b/src/app/layouts/default.vue index 8ec4ed6a..304a1197 100644 --- a/src/app/layouts/default.vue +++ b/src/app/layouts/default.vue @@ -29,5 +29,7 @@ diff --git a/src/app/middleware/auth.global.ts b/src/app/middleware/auth.global.ts index 06029fd6..279ec968 100644 --- a/src/app/middleware/auth.global.ts +++ b/src/app/middleware/auth.global.ts @@ -9,8 +9,10 @@ export default defineNuxtRouteMiddleware(async (to) => { const authStore = useAuthStore(); authStore.userData = await authStore.getSession(event); - // skip login if already logged in - if (to.path === '/login') { + const isLoginRoute = to.path === '/login' || to.path === '/login/2fa'; + + // skip login pages if already logged in + if (isLoginRoute) { if (authStore.userData?.username) { return navigateTo('/', { redirectCode: 302 }); } diff --git a/src/app/pages/login.vue b/src/app/pages/login.vue index a938e416..02e3e70a 100644 --- a/src/app/pages/login.vue +++ b/src/app/pages/login.vue @@ -12,149 +12,7 @@ -
- - - -
-
- - {{ $t('login.or') }} - -
-
-
- - -
- - - - - - - - - - + - - diff --git a/src/app/pages/login/2fa.vue b/src/app/pages/login/2fa.vue new file mode 100644 index 00000000..bf606ef4 --- /dev/null +++ b/src/app/pages/login/2fa.vue @@ -0,0 +1,106 @@ + + + diff --git a/src/app/pages/login/index.vue b/src/app/pages/login/index.vue new file mode 100644 index 00000000..5521e4ac --- /dev/null +++ b/src/app/pages/login/index.vue @@ -0,0 +1,130 @@ + + + diff --git a/src/app/pages/me.vue b/src/app/pages/me.vue index f4b040e6..4aeb9216 100644 --- a/src/app/pages/me.vue +++ b/src/app/pages/me.vue @@ -317,10 +317,11 @@ async function disable2fa() { } const _unlinkOauth = useSubmit( - `/api/auth/unlink`, - { - method: 'post', - }, + (data) => + $fetch(`/api/auth/unlink`, { + method: 'post', + body: data, + }), { revert: async () => { return authStore.update(); diff --git a/src/app/stores/login.ts b/src/app/stores/login.ts new file mode 100644 index 00000000..ef300858 --- /dev/null +++ b/src/app/stores/login.ts @@ -0,0 +1,36 @@ +type PendingLoginChallenge = { + type: 'password'; + username: string; + password: string; + remember: boolean; +}; + +export const useLoginStore = defineStore('Login', () => { + const pendingChallenge = ref(null); + + const hasPendingLogin = computed(() => pendingChallenge.value !== null); + + function setPendingPasswordLogin( + username: string, + password: string, + remember: boolean + ) { + pendingChallenge.value = { + type: 'password', + username, + password, + remember, + }; + } + + function clearPendingLogin() { + pendingChallenge.value = null; + } + + return { + pendingChallenge, + hasPendingLogin, + setPendingPasswordLogin, + clearPendingLogin, + }; +});