Change the Kicker activation method to ensure minified code works as well

This commit is contained in:
Bubka 2023-11-30 13:18:35 +01:00
parent 333b70e688
commit 3459a364a0
7 changed files with 73 additions and 60 deletions

View File

@ -1,17 +1,18 @@
<script setup> <script setup>
import { RouterView } from 'vue-router' import { RouterView } from 'vue-router'
const route = useRoute() const route = useRoute()
const kickUser = ref(null)
const kickUserAfter = ref(null) const kickUserAfter = ref(null)
const isProtectedRoute = ref(null) const isProtectedRoute = ref(route.meta.watchedByKicker)
watch( watch(
() => route.name, () => route.name,
() => { () => {
isProtectedRoute.value = protectedRoute(route) isProtectedRoute.value = route.meta.watchedByKicker
} }
) )
const kickInactiveUser = computed(() => kickUserAfter.value > 0 && isProtectedRoute.value) // const kickInactiveUser = computed(() => kickUser && kickUserAfter.value > 0 && isProtectedRoute.value)
onBeforeMount(async () => { onBeforeMount(async () => {
const { useUserStore } = await import('./stores/user.js') const { useUserStore } = await import('./stores/user.js')
@ -19,7 +20,7 @@
const user = useUserStore() const user = useUserStore()
kickUserAfter.value = parseInt(user.preferences.kickUserAfter) kickUserAfter.value = parseInt(user.preferences.kickUserAfter)
isProtectedRoute.value = protectedRoute(route) kickUser.value = user.isAuthenticated
watch( watch(
() => user.preferences.kickUserAfter, () => user.preferences.kickUserAfter,
@ -27,23 +28,17 @@
kickUserAfter.value = parseInt(user.preferences.kickUserAfter) kickUserAfter.value = parseInt(user.preferences.kickUserAfter)
} }
) )
watch(
() => user.isAuthenticated,
() => {
kickUser.value = user.isAuthenticated
}
)
watch(language, () => { watch(language, () => {
user.applyLanguage() user.applyLanguage()
}) })
}) })
function protectedRoute(route) {
let bool = false
route.meta.middlewares?.forEach(func => {
if (func instanceof Function && func.name == 'authGuard') {
bool = true
return
}
})
return bool
}
</script> </script>
<template> <template>
@ -59,5 +54,5 @@
<main class="main-section"> <main class="main-section">
<RouterView /> <RouterView />
</main> </main>
<kicker v-if="kickInactiveUser" :kickAfter="kickUserAfter"></kicker> <kicker v-if="kickUser && kickUserAfter > 0 && isProtectedRoute" :kickAfter="kickUserAfter"></kicker>
</template> </template>

View File

@ -2,7 +2,7 @@
import { useUserStore } from '@/stores/user' import { useUserStore } from '@/stores/user'
const user = useUserStore() const user = useUserStore()
const events = ref(['click', 'mousedown', 'scroll', 'keypress', 'load']) const events = ref(['mousedown', 'scroll', 'keypress'])
const logoutTimer = ref(null) const logoutTimer = ref(null)
// const elapsed = ref(0) // const elapsed = ref(0)
// const counter = ref(null) // const counter = ref(null)
@ -14,45 +14,54 @@
}, },
}) })
watch(
() => props.kickAfter,
() => {
restartTimer()
}
)
onMounted(() => { onMounted(() => {
events.value.forEach(function (event) { events.value.forEach(function (event) {
window.addEventListener(event, resetTimer) window.addEventListener(event, restartTimer)
}, this) }, this)
setTimer() startTimer()
}) })
onUnmounted(() => { onUnmounted(() => {
events.value.forEach(function (event) { events.value.forEach(function (event) {
window.removeEventListener(event, resetTimer) window.removeEventListener(event, restartTimer)
}, this) }, this)
clearTimeout(logoutTimer.value) stopTimer()
// clearInterval(counter.value)
}) })
function setTimer() { function startTimer() {
// elapsed.value = 0
// clearInterval(counter.value)
logoutTimer.value = setTimeout(logoutUser, props.kickAfter * 60 * 1000) logoutTimer.value = setTimeout(logoutUser, props.kickAfter * 60 * 1000)
// counter.value = setInterval(() => { // counter.value = setInterval(() => {
// elapsed.value += 1 // elapsed.value += 1
// console.log(elapsed.value + '/' + props.kickAfter * 60) // console.log(elapsed.value + '/' + props.kickAfter * 60)
// }, 1000); // }, 1000)
} }
// Triggers the user logout // Triggers the user logout
function logoutUser() { function logoutUser() {
clearTimeout(logoutTimer.value) clearTimeout(logoutTimer.value)
console.log('inativity detected, user kicked out')
user.logout({ kicked: true}) user.logout({ kicked: true})
} }
function resetTimer() { // Restarts the timer
function restartTimer() {
stopTimer()
startTimer()
}
// Stops the timer
function stopTimer() {
clearTimeout(logoutTimer.value) clearTimeout(logoutTimer.value)
setTimer() // elapsed.value = 0
// clearInterval(counter.value)
} }
</script> </script>

View File

@ -14,24 +14,24 @@ import setReturnTo from './middlewares/setReturnTo'
const router = createRouter({ const router = createRouter({
history: createWebHistory('/'), history: createWebHistory('/'),
routes: [ routes: [
{ path: '/start', name: 'start', component: () => import('../views/Start.vue'), meta: { middlewares: [authGuard, setReturnTo] } }, { path: '/start', name: 'start', component: () => import('../views/Start.vue'), meta: { middlewares: [authGuard, setReturnTo], watchedByKicker: true } },
{ path: '/capture', name: 'capture', component: () => import('../views/twofaccounts/Capture.vue'), meta: { middlewares: [authGuard, setReturnTo] } }, { path: '/capture', name: 'capture', component: () => import('../views/twofaccounts/Capture.vue'), meta: { middlewares: [authGuard, setReturnTo], watchedByKicker: true } },
{ path: '/accounts', name: 'accounts', component: () => import('../views/twofaccounts/Accounts.vue'), meta: { middlewares: [authGuard, starter, setReturnTo] }, alias: '/' }, { path: '/accounts', name: 'accounts', component: () => import('../views/twofaccounts/Accounts.vue'), meta: { middlewares: [authGuard, starter, setReturnTo], watchedByKicker: true }, alias: '/' },
{ path: '/account/create', name: 'createAccount', component: () => import('../views/twofaccounts/CreateUpdate.vue'), meta: { middlewares: [authGuard, setReturnTo] } }, { path: '/account/create', name: 'createAccount', component: () => import('../views/twofaccounts/CreateUpdate.vue'), meta: { middlewares: [authGuard, setReturnTo], watchedByKicker: true } },
{ path: '/account/import', name: 'importAccounts', component: () => import('../views/twofaccounts/Import.vue'), meta: { middlewares: [authGuard, setReturnTo] } }, { path: '/account/import', name: 'importAccounts', component: () => import('../views/twofaccounts/Import.vue'), meta: { middlewares: [authGuard, setReturnTo], watchedByKicker: true } },
{ path: '/account/:twofaccountId/edit', name: 'editAccount', component: () => import('../views/twofaccounts/CreateUpdate.vue'), meta: { middlewares: [authGuard, setReturnTo] }, props: true }, { path: '/account/:twofaccountId/edit', name: 'editAccount', component: () => import('../views/twofaccounts/CreateUpdate.vue'), meta: { middlewares: [authGuard, setReturnTo], watchedByKicker: true }, props: true },
{ path: '/account/:twofaccountId/qrcode', name: 'showQRcode', component: () => import('../views/twofaccounts/QRcode.vue'), meta: { middlewares: [authGuard, setReturnTo] } }, { path: '/account/:twofaccountId/qrcode', name: 'showQRcode', component: () => import('../views/twofaccounts/QRcode.vue'), meta: { middlewares: [authGuard, setReturnTo], watchedByKicker: true } },
{ path: '/groups', name: 'groups', component: () => import('../views/groups/Groups.vue'), meta: { middlewares: [authGuard, setReturnTo] }, props: true }, { path: '/groups', name: 'groups', component: () => import('../views/groups/Groups.vue'), meta: { middlewares: [authGuard, setReturnTo], watchedByKicker: true }, props: true },
{ path: '/group/create', name: 'createGroup', component: () => import('../views/groups/CreateUpdate.vue'), meta: { middlewares: [authGuard, setReturnTo] } }, { path: '/group/create', name: 'createGroup', component: () => import('../views/groups/CreateUpdate.vue'), meta: { middlewares: [authGuard, setReturnTo], watchedByKicker: true } },
{ path: '/group/:groupId/edit', name: 'editGroup', component: () => import('../views/groups/CreateUpdate.vue'), meta: { middlewares: [authGuard, setReturnTo] }, props: true }, { path: '/group/:groupId/edit', name: 'editGroup', component: () => import('../views/groups/CreateUpdate.vue'), meta: { middlewares: [authGuard, setReturnTo], watchedByKicker: true }, props: true },
{ path: '/settings/options', name: 'settings.options', component: () => import('../views/settings/Options.vue'), meta: { middlewares: [authGuard], showAbout: true } }, { path: '/settings/options', name: 'settings.options', component: () => import('../views/settings/Options.vue'), meta: { middlewares: [authGuard], watchedByKicker: true, showAbout: true } },
{ path: '/settings/account', name: 'settings.account', component: () => import('../views/settings/Account.vue'), meta: { middlewares: [authGuard], showAbout: true } }, { path: '/settings/account', name: 'settings.account', component: () => import('../views/settings/Account.vue'), meta: { middlewares: [authGuard], watchedByKicker: true, showAbout: true } },
{ path: '/settings/oauth', name: 'settings.oauth.tokens', component: () => import('../views/settings/OAuth.vue'), meta: { middlewares: [authGuard], showAbout: true, props: true } }, { path: '/settings/oauth', name: 'settings.oauth.tokens', component: () => import('../views/settings/OAuth.vue'), meta: { middlewares: [authGuard], watchedByKicker: true, showAbout: true, props: true } },
{ path: '/settings/webauthn/:credentialId/edit', name: 'settings.webauthn.editCredential', component: () => import('../views/settings/Credentials/Edit.vue'), meta: { middlewares: [authGuard], showAbout: true }, props: true }, { path: '/settings/webauthn/:credentialId/edit', name: 'settings.webauthn.editCredential', component: () => import('../views/settings/Credentials/Edit.vue'), meta: { middlewares: [authGuard], watchedByKicker: true, showAbout: true }, props: true },
{ path: '/settings/webauthn', name: 'settings.webauthn.devices', component: () => import('../views/settings/WebAuthn.vue'), meta: { middlewares: [authGuard], showAbout: true } }, { path: '/settings/webauthn', name: 'settings.webauthn.devices', component: () => import('../views/settings/WebAuthn.vue'), meta: { middlewares: [authGuard], watchedByKicker: true, showAbout: true } },
{ path: '/login', name: 'login', component: () => import('../views/auth/Login.vue'), meta: { middlewares: [setReturnTo], disabledWithAuthProxy: true, showAbout: true } }, { path: '/login', name: 'login', component: () => import('../views/auth/Login.vue'), meta: { middlewares: [setReturnTo], disabledWithAuthProxy: true, showAbout: true } },
{ path: '/register', name: 'register', component: () => import('../views/auth/Register.vue'), meta: { middlewares: [noRegistration, setReturnTo], disabledWithAuthProxy: true, showAbout: true } }, { path: '/register', name: 'register', component: () => import('../views/auth/Register.vue'), meta: { middlewares: [noRegistration, setReturnTo], disabledWithAuthProxy: true, showAbout: true } },
@ -40,10 +40,10 @@ const router = createRouter({
{ path: '/webauthn/lost', name: 'webauthn.lost', component: () => import('../views/auth/RequestReset.vue'), meta: { middlewares: [setReturnTo], disabledWithAuthProxy: true, showAbout: true } }, { path: '/webauthn/lost', name: 'webauthn.lost', component: () => import('../views/auth/RequestReset.vue'), meta: { middlewares: [setReturnTo], disabledWithAuthProxy: true, showAbout: true } },
{ path: '/webauthn/recover', name: 'webauthn.recover', component: () => import('../views/auth/webauthn/Recover.vue'), meta: { middlewares: [setReturnTo], disabledWithAuthProxy: true, showAbout: true } }, { path: '/webauthn/recover', name: 'webauthn.recover', component: () => import('../views/auth/webauthn/Recover.vue'), meta: { middlewares: [setReturnTo], disabledWithAuthProxy: true, showAbout: true } },
{ path: '/about', name: 'about', component: () => import('../views/About.vue'), meta: { showAbout: true } }, { path: '/about', name: 'about', component: () => import('../views/About.vue'), meta: { showAbout: true, watchedByKicker: true } },
{ path: '/error', name: 'genericError', component: () => import('../views/Error.vue'), meta: { middlewares: [noEmptyError] } }, { path: '/error', name: 'genericError', component: () => import('../views/Error.vue'), meta: { middlewares: [noEmptyError], watchedByKicker: true } },
{ path: '/404', name: '404', component: () => import('../views/Error.vue'), props: true }, { path: '/404', name: '404', component: () => import('../views/Error.vue'), meta: { watchedByKicker: true }, props: true },
{ path: '/:pathMatch(.*)*', name: 'notFound', component: () => import('../views/Error.vue'), props: true }, { path: '/:pathMatch(.*)*', name: 'notFound', component: () => import('../views/Error.vue'), meta: { watchedByKicker: true }, props: true },
] ]
}) })

View File

@ -7,8 +7,8 @@ export default {
/** /**
* *
*/ */
logout() { logout(config = {}) {
return webClient.get('/user/logout') return webClient.get('/user/logout', { ...config })
}, },
/** /**

View File

@ -58,7 +58,7 @@ export const httpClientFactory = (endpoint = 'api') => {
if (error.response && [401].includes(error.response.status)) { if (error.response && [401].includes(error.response.status)) {
const user = useUserStore() const user = useUserStore()
user.reset() user.tossOut()
} }
// Always return the form validation errors // Always return the form validation errors

View File

@ -58,6 +58,7 @@ export const useUserStore = defineStore({
*/ */
logout(options = {}) { logout(options = {}) {
const { kicked } = options const { kicked } = options
const notify = useNotifyStore()
// async appLogout(evt) { // async appLogout(evt) {
if (this.$2fauth.config.proxyAuth) { if (this.$2fauth.config.proxyAuth) {
@ -67,21 +68,29 @@ export const useUserStore = defineStore({
else return false else return false
} }
else { else {
return authService.logout().then(() => { authService.logout({ returnError: true }).then(() => {
this.reset()
if (kicked) { if (kicked) {
const notify = useNotifyStore()
notify.clear() notify.clear()
notify.warn({ text: trans('auth.autolock_triggered_punchline'), duration:-1 }) notify.warn({ text: trans('auth.autolock_triggered_punchline'), duration:-1 })
} }
this.tossOut()
})
.catch(error => {
// The logout request will receive a 401 response when the
// backend has already detect inactivity on its side. In this case we
// don't want any error to be displayed.
if (error.response.status !== 401) {
notify.error(error)
}
else this.tossOut()
}) })
} }
}, },
/** /**
* Resets all user data * Resets all user data and push out
*/ */
reset() { tossOut() {
this.$reset() this.$reset()
this.initDataStores() this.initDataStores()
this.applyUserPrefs() this.applyUserPrefs()

View File

@ -27,7 +27,7 @@
'register' => 'Register', 'register' => 'Register',
'welcome_to_2fauth' => 'Welcome to 2FAuth', 'welcome_to_2fauth' => 'Welcome to 2FAuth',
'autolock_triggered' => 'Auto lock triggered', 'autolock_triggered' => 'Auto lock triggered',
'autolock_triggered_punchline' => 'Auto-lock triggered and logged you out', 'autolock_triggered_punchline' => 'Auto-lock triggered, you\'ve been logged out',
'already_authenticated' => 'Already authenticated, please log out first', 'already_authenticated' => 'Already authenticated, please log out first',
'authentication' => 'Authentication', 'authentication' => 'Authentication',
'maybe_later' => 'Maybe later', 'maybe_later' => 'Maybe later',