diff --git a/config/2fauth.php b/config/2fauth.php index ae678975..a38e1fd2 100644 --- a/config/2fauth.php +++ b/config/2fauth.php @@ -126,6 +126,7 @@ 'notifyOnFailedLogin' => false, 'timezone' => env('APP_TIMEZONE', 'UTC'), 'sortCaseSensitive' => false, + 'autoCloseTimeout' => 2, ], ]; diff --git a/resources/js/components/OtpDisplay.vue b/resources/js/components/OtpDisplay.vue index bd121266..925255c2 100644 --- a/resources/js/components/OtpDisplay.vue +++ b/resources/js/components/OtpDisplay.vue @@ -53,6 +53,7 @@ const dots = ref() const totpLooper = ref() const otpSpanTag = ref() + const autoCloseTimeout = ref(null) watch( () => props.icon, @@ -121,6 +122,10 @@ try { await getOtp() focusOnOTP() + + if (user.preferences.getOtpOnRequest && parseInt(user.preferences.autoCloseTimeout) > 0) { + startAutoCloseTimer() + } } catch(error) { clearOTP() @@ -191,6 +196,15 @@ } } + /** + * Triggers the component closing + */ + function closeMe() { + emit("please-close-me"); + revealPassword.value = false + clearOTP() + } + /** * Reset component's refs */ @@ -199,6 +213,7 @@ otpauthParams.value.service = otpauthParams.value.account = otpauthParams.value.icon = otpauthParams.value.otp_type = otpauthParams.value.secret = '' password.value = '... ...' hasTOTP.value = false + clearTimeout(autoCloseTimeout.value) totpLooper.value?.clearLooper(); } @@ -226,9 +241,7 @@ user.logout({ kicked: true}) } else if(user.preferences.closeOtpOnCopy && (permit_closing || false) === true) { - emit("please-close-me"); - revealPassword.value = false - clearOTP() + closeMe() } if(user.preferences.clearSearchOnCopy) { @@ -273,6 +286,17 @@ show, clearOTP }) + + /** + * Starts an auto close timer + */ + function startAutoCloseTimer() { + let duration = parseInt(user.preferences.autoCloseTimeout) // in minutes + + autoCloseTimeout.value = setTimeout(function() { + closeMe() + }, duration * 60 * 1000); + } diff --git a/resources/js/components/formElements/FormSelect.vue b/resources/js/components/formElements/FormSelect.vue index 17273c62..7c5ffa9f 100644 --- a/resources/js/components/formElements/FormSelect.vue +++ b/resources/js/components/formElements/FormSelect.vue @@ -19,22 +19,29 @@ type: String, default: '' }, + isIndented: Boolean, + isDisabled: Boolean, }) const selected = ref(props.modelValue) \ No newline at end of file diff --git a/resources/js/views/settings/Options.vue b/resources/js/views/settings/Options.vue index 1564376f..2aaef006 100644 --- a/resources/js/views/settings/Options.vue +++ b/resources/js/views/settings/Options.vue @@ -37,6 +37,12 @@ { text: 'settings.forms.1_hour', value: 60 }, { text: 'settings.forms.1_day', value: 1440 }, ] + const autoCloseTimeout = [ + { text: 'settings.forms.never', value: 0 }, + { text: 'settings.forms.1_minutes', value: 1 }, + { text: 'settings.forms.2_minutes', value: 2 }, + { text: 'settings.forms.5_minutes', value: 5 }, + ] const groupsList = ref([ { text: 'groups.no_group', value: 0 }, { text: 'groups.active_group', value: -1 }, @@ -157,6 +163,8 @@ + + diff --git a/resources/lang/en/settings.php b/resources/lang/en/settings.php index 3aeb598c..a77d2385 100644 --- a/resources/lang/en/settings.php +++ b/resources/lang/en/settings.php @@ -67,7 +67,11 @@ ], 'close_otp_on_copy' => [ 'label' => 'Close OTP after copy', - 'help' => 'Clicking a generated password to copy it automatically hide it from the screen' + 'help' => 'Click on a generated password to copy it automatically hides it from the screen' + ], + 'auto_close_timeout' => [ + 'label' => 'Auto close OTP', + 'help' => 'Automatically hide on-screen password after a timeout. This avoids unnecessary requests for fresh passwords if you forget to close the password view.' ], 'clear_search_on_copy' => [ 'label' => 'Clear Search on copy', @@ -161,6 +165,7 @@ 'never' => 'Never', 'on_otp_copy' => 'On security code copy', '1_minutes' => 'After 1 minute', + '2_minutes' => 'After 2 minutes', '5_minutes' => 'After 5 minutes', '10_minutes' => 'After 10 minutes', '15_minutes' => 'After 15 minutes',