From e8a3c441be8f46df1c67aaef26cbe5ffca04347d Mon Sep 17 00:00:00 2001
From: Bubka <858858+Bubka@users.noreply.github.com>
Date: Fri, 17 Nov 2023 19:49:39 +0100
Subject: [PATCH] Fix Always On OTPs & Dots display and looping
---
.../js_vue3/services/twofaccountService.js | 8 +-
resources/js_vue3/stores/twofaccounts.js | 32 +++--
.../js_vue3/views/twofaccounts/Accounts.vue | 131 ++++++++++--------
3 files changed, 96 insertions(+), 75 deletions(-)
diff --git a/resources/js_vue3/services/twofaccountService.js b/resources/js_vue3/services/twofaccountService.js
index 532e6d67..f8ed4b6f 100644
--- a/resources/js_vue3/services/twofaccountService.js
+++ b/resources/js_vue3/services/twofaccountService.js
@@ -3,12 +3,12 @@ import { httpClientFactory } from '@/services/httpClientFactory'
const apiClient = httpClientFactory('api')
export default {
- getAll(withOtp = false) {
- return apiClient.get('/twofaccounts' + (withOtp ? '?withOtp=1' : ''))
+ getAll(withOtp = false, config = {}) {
+ return apiClient.get('/twofaccounts' + (withOtp ? '?withOtp=1' : ''), { ...config })
},
- getByIds(ids, withOtp = false) {
- return apiClient.get('/twofaccounts?ids=' + ids + (withOtp ? '&withOtp=1' : ''))
+ getByIds(ids, withOtp = false, config = {}) {
+ return apiClient.get('/twofaccounts?ids=' + ids + (withOtp ? '&withOtp=1' : ''), { ...config })
},
get(id, config = {}) {
diff --git a/resources/js_vue3/stores/twofaccounts.js b/resources/js_vue3/stores/twofaccounts.js
index a5d3be45..daa29e55 100644
--- a/resources/js_vue3/stores/twofaccounts.js
+++ b/resources/js_vue3/stores/twofaccounts.js
@@ -79,31 +79,33 @@ export const useTwofaccounts = defineStore({
/**
* Refreshes the accounts collection using the backend
*/
- async fetch() {
+ async fetch(force = false) {
// We do not want to fetch fresh data multiple times in the same 2s timespan
const age = Math.floor(Date.now() - this.fetchedOn)
- const isNotFresh = age > 2000
+ const isOutOfAge = age > 2000
- if (isNotFresh) {
+ if (isOutOfAge || force) {
this.fetchedOn = Date.now()
await twofaccountService.getAll(! useUserStore().preferences.getOtpOnRequest).then(response => {
// Defines if the store was up-to-date with the backend
- this.backendWasNewer = response.data.length !== this.items.length
-
- this.items.forEach((item) => {
- let matchingBackendItem = response.data.find(e => e.id === item.id)
- if (matchingBackendItem == undefined) {
- this.backendWasNewer = true
- return;
- }
- for (const field in item) {
- if (field !== 'otp' && item[field] != matchingBackendItem[field]) {
+ if (force) {
+ this.backendWasNewer = response.data.length !== this.items.length
+
+ this.items.forEach((item) => {
+ let matchingBackendItem = response.data.find(e => e.id === item.id)
+ if (matchingBackendItem == undefined) {
this.backendWasNewer = true
return;
}
- }
- })
+ for (const field in item) {
+ if (field !== 'otp' && item[field] != matchingBackendItem[field]) {
+ this.backendWasNewer = true
+ return;
+ }
+ }
+ })
+ }
// Updates the state
this.items = response.data
diff --git a/resources/js_vue3/views/twofaccounts/Accounts.vue b/resources/js_vue3/views/twofaccounts/Accounts.vue
index 22b9f159..007abbd1 100644
--- a/resources/js_vue3/views/twofaccounts/Accounts.vue
+++ b/resources/js_vue3/views/twofaccounts/Accounts.vue
@@ -32,9 +32,8 @@
const showGroupSwitch = ref(false)
const showDestinationGroupSelector = ref(false)
const isDragging = ref(false)
- const stepIndexesCache = ref({})
const isRenewingOTPs = ref(false)
- const renewedOTPs = ref(null)
+ const renewedPeriod = ref(null)
const otpDisplay = ref(null)
const otpDisplayProps = ref({
@@ -85,12 +84,17 @@
// This SFC is reached only if the user has some twofaccounts (see the starter middleware).
// This allows to display accounts without latency.
//
- // We sync the store with the backend again to
- twofaccounts.fetch().then(() => {
- if (twofaccounts.backendWasNewer) {
- notify.info({ text: trans('commons.data_refreshed_to_reflect_server_changes'), duration: 10000 })
- }
- })
+ // We sync the store with the backend again to
+ if (! user.preferences.getOtpOnRequest) {
+ updateTotps()
+ }
+ else {
+ twofaccounts.fetch().then(() => {
+ if (twofaccounts.backendWasNewer) {
+ notify.info({ text: trans('commons.data_refreshed_to_reflect_server_changes'), duration: 10000 })
+ }
+ })
+ }
groups.fetch()
})
@@ -207,59 +211,69 @@
twofaccounts.saveOrder()
}
-
- /**
- * Turns dots On at the current step and caches the state
- */
- function setCurrentStep(period, stepIndex) {
- stepIndexesCache.value[period] = stepIndex
- turnDotsOn(period, stepIndex)
- }
-
- /**
- * Turns dots On at the cached step index
- */
- function turnDotsOnFromCache(period, stepIndex) {
- if (stepIndexesCache.value[period] != undefined) {
- turnDotsOn(period, stepIndexesCache.value[period])
- }
- }
-
/**
* Turns dots On for all dots components that match the provided period
*/
function turnDotsOn(period, stepIndex) {
dotsRefs.value
- .filter((dots) => dots.props.period == period)
+ .filter((dots) => dots.props.period == period || period == undefined)
.forEach((dot) => {
dot.turnOn(stepIndex)
})
}
/**
- * Updates "Always On" OTPs for all TOTP accounts with the given period and restarts loopers
+ * Turns dots Off for all dots components that match the provided period
+ */
+ function turnDotsOff(period) {
+ dotsRefs.value
+ .filter((dots) => dots.props.period == period || period == undefined)
+ .forEach((dot) => {
+ dot.turnOff()
+ })
+ }
+
+ /**
+ * Updates "Always On" OTPs for all TOTP accounts and (re)starts loopers
*/
async function updateTotps(period) {
isRenewingOTPs.value = true
- renewedOTPs.value = period
-
- twofaccountService.getByIds(twofaccounts.accountIdsWithPeriod(period).join(','), true).then(response => {
+ turnDotsOff(period)
+ let fetchPromise
+
+ if (period == undefined) {
+ renewedPeriod.value = -1
+ fetchPromise = twofaccountService.getAll(true)
+ } else {
+ renewedPeriod.value = period
+ fetchPromise = twofaccountService.getByIds(twofaccounts.accountIdsWithPeriod(period).join(','), true)
+ }
+
+ fetchPromise.then(response => {
+ let generatedAt = 0
+
+ // twofaccounts OTP updates
response.data.forEach((account) => {
const index = twofaccounts.items.findIndex(acc => acc.id === account.id)
- twofaccounts.items[index].otp = account.otp
-
- looperRefs.value.forEach((looper) => {
- if (looper.props.period == period) {
- nextTick().then(() => {
- looper.startLoop(account.otp.generated_at)
- })
- }
- })
+ if (twofaccounts.items[index] == undefined) {
+ twofaccounts.items.push(account)
+ }
+ else twofaccounts.items[index].otp = account.otp
+ generatedAt = account.otp.generated_at
+ })
+
+ // Loopers restart at new timestamp
+ looperRefs.value.forEach((looper) => {
+ if (looper.props.period == period || period == undefined) {
+ nextTick().then(() => {
+ looper.startLoop(generatedAt)
+ })
+ }
})
})
.finally(() => {
isRenewingOTPs.value = false
- renewedOTPs.value = null
+ renewedPeriod.value = null
})
}
@@ -339,6 +353,20 @@
@please-close-me="showOtpInModal = false">
+
+
+