mirror of
https://github.com/Bubka/2FAuth.git
synced 2024-11-25 09:44:04 +01:00
Add user preference to auto-close OTP after timeout
This commit is contained in:
parent
2f05f4993c
commit
570f3bb9bd
@ -126,6 +126,7 @@
|
|||||||
'notifyOnFailedLogin' => false,
|
'notifyOnFailedLogin' => false,
|
||||||
'timezone' => env('APP_TIMEZONE', 'UTC'),
|
'timezone' => env('APP_TIMEZONE', 'UTC'),
|
||||||
'sortCaseSensitive' => false,
|
'sortCaseSensitive' => false,
|
||||||
|
'autoCloseTimeout' => 2,
|
||||||
],
|
],
|
||||||
|
|
||||||
];
|
];
|
||||||
|
@ -53,6 +53,7 @@
|
|||||||
const dots = ref()
|
const dots = ref()
|
||||||
const totpLooper = ref()
|
const totpLooper = ref()
|
||||||
const otpSpanTag = ref()
|
const otpSpanTag = ref()
|
||||||
|
const autoCloseTimeout = ref(null)
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props.icon,
|
() => props.icon,
|
||||||
@ -121,6 +122,10 @@
|
|||||||
try {
|
try {
|
||||||
await getOtp()
|
await getOtp()
|
||||||
focusOnOTP()
|
focusOnOTP()
|
||||||
|
|
||||||
|
if (user.preferences.getOtpOnRequest && parseInt(user.preferences.autoCloseTimeout) > 0) {
|
||||||
|
startAutoCloseTimer()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch(error) {
|
catch(error) {
|
||||||
clearOTP()
|
clearOTP()
|
||||||
@ -191,6 +196,15 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Triggers the component closing
|
||||||
|
*/
|
||||||
|
function closeMe() {
|
||||||
|
emit("please-close-me");
|
||||||
|
revealPassword.value = false
|
||||||
|
clearOTP()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reset component's refs
|
* Reset component's refs
|
||||||
*/
|
*/
|
||||||
@ -199,6 +213,7 @@
|
|||||||
otpauthParams.value.service = otpauthParams.value.account = otpauthParams.value.icon = otpauthParams.value.otp_type = otpauthParams.value.secret = ''
|
otpauthParams.value.service = otpauthParams.value.account = otpauthParams.value.icon = otpauthParams.value.otp_type = otpauthParams.value.secret = ''
|
||||||
password.value = '... ...'
|
password.value = '... ...'
|
||||||
hasTOTP.value = false
|
hasTOTP.value = false
|
||||||
|
clearTimeout(autoCloseTimeout.value)
|
||||||
|
|
||||||
totpLooper.value?.clearLooper();
|
totpLooper.value?.clearLooper();
|
||||||
}
|
}
|
||||||
@ -226,9 +241,7 @@
|
|||||||
user.logout({ kicked: true})
|
user.logout({ kicked: true})
|
||||||
}
|
}
|
||||||
else if(user.preferences.closeOtpOnCopy && (permit_closing || false) === true) {
|
else if(user.preferences.closeOtpOnCopy && (permit_closing || false) === true) {
|
||||||
emit("please-close-me");
|
closeMe()
|
||||||
revealPassword.value = false
|
|
||||||
clearOTP()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(user.preferences.clearSearchOnCopy) {
|
if(user.preferences.clearSearchOnCopy) {
|
||||||
@ -274,6 +287,17 @@
|
|||||||
clearOTP
|
clearOTP
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts an auto close timer
|
||||||
|
*/
|
||||||
|
function startAutoCloseTimer() {
|
||||||
|
let duration = parseInt(user.preferences.autoCloseTimeout) // in minutes
|
||||||
|
|
||||||
|
autoCloseTimeout.value = setTimeout(function() {
|
||||||
|
closeMe()
|
||||||
|
}, duration * 60 * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -19,17 +19,23 @@
|
|||||||
type: String,
|
type: String,
|
||||||
default: ''
|
default: ''
|
||||||
},
|
},
|
||||||
|
isIndented: Boolean,
|
||||||
|
isDisabled: Boolean,
|
||||||
})
|
})
|
||||||
|
|
||||||
const selected = ref(props.modelValue)
|
const selected = ref(props.modelValue)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="field">
|
<div class="field is-flex">
|
||||||
<label class="label" v-html="$t(label)"></label>
|
<div v-if="isIndented" class="mx-2 pr-1" :style="{ 'opacity': isDisabled ? '0.5' : '1' }">
|
||||||
|
<FontAwesomeIcon class="has-text-grey" :icon="['fas', 'chevron-right']" transform="rotate-135"/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="label" v-html="$t(label)" :style="{ 'opacity': isDisabled ? '0.5' : '1' }"></label>
|
||||||
<div class="control">
|
<div class="control">
|
||||||
<div class="select">
|
<div class="select">
|
||||||
<select v-model="selected" v-on:change="$emit('update:modelValue', $event.target.value)">
|
<select v-model="selected" v-on:change="$emit('update:modelValue', $event.target.value)" :disabled="isDisabled">
|
||||||
<option v-for="option in options" :value="option.value">{{ $t(option.text) }}</option>
|
<option v-for="option in options" :value="option.value">{{ $t(option.text) }}</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
@ -37,4 +43,5 @@
|
|||||||
<FieldError v-if="fieldError != undefined" :error="fieldError" :field="fieldName" />
|
<FieldError v-if="fieldError != undefined" :error="fieldError" :field="fieldName" />
|
||||||
<p class="help" v-html="$t(help)" v-if="help"></p>
|
<p class="help" v-html="$t(help)" v-if="help"></p>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
@ -37,6 +37,12 @@
|
|||||||
{ text: 'settings.forms.1_hour', value: 60 },
|
{ text: 'settings.forms.1_hour', value: 60 },
|
||||||
{ text: 'settings.forms.1_day', value: 1440 },
|
{ 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([
|
const groupsList = ref([
|
||||||
{ text: 'groups.no_group', value: 0 },
|
{ text: 'groups.no_group', value: 0 },
|
||||||
{ text: 'groups.active_group', value: -1 },
|
{ text: 'groups.active_group', value: -1 },
|
||||||
@ -157,6 +163,8 @@
|
|||||||
<FormToggle v-model="user.preferences.getOtpOnRequest" @update:model-value="val => savePreference('getOtpOnRequest', val)" :choices="getOtpTriggers" fieldName="getOtpOnRequest" label="settings.forms.otp_generation.label" help="settings.forms.otp_generation.help"/>
|
<FormToggle v-model="user.preferences.getOtpOnRequest" @update:model-value="val => savePreference('getOtpOnRequest', val)" :choices="getOtpTriggers" fieldName="getOtpOnRequest" label="settings.forms.otp_generation.label" help="settings.forms.otp_generation.help"/>
|
||||||
<!-- close otp on copy -->
|
<!-- close otp on copy -->
|
||||||
<FormCheckbox v-model="user.preferences.closeOtpOnCopy" @update:model-value="val => savePreference('closeOtpOnCopy', val)" fieldName="closeOtpOnCopy" label="settings.forms.close_otp_on_copy.label" help="settings.forms.close_otp_on_copy.help" :isDisabled="!user.preferences.getOtpOnRequest" :isIndented="true" />
|
<FormCheckbox v-model="user.preferences.closeOtpOnCopy" @update:model-value="val => savePreference('closeOtpOnCopy', val)" fieldName="closeOtpOnCopy" label="settings.forms.close_otp_on_copy.label" help="settings.forms.close_otp_on_copy.help" :isDisabled="!user.preferences.getOtpOnRequest" :isIndented="true" />
|
||||||
|
<!-- auto-close timeout -->
|
||||||
|
<FormSelect v-model="user.preferences.autoCloseTimeout" @update:model-value="val => savePreference('autoCloseTimeout', val)" :options="autoCloseTimeout" fieldName="autoCloseTimeout" label="settings.forms.auto_close_timeout.label" help="settings.forms.auto_close_timeout.help" :isDisabled="!user.preferences.getOtpOnRequest" :isIndented="true" />
|
||||||
<!-- clear search on copy -->
|
<!-- clear search on copy -->
|
||||||
<FormCheckbox v-model="user.preferences.copyOtpOnDisplay" @update:model-value="val => savePreference('copyOtpOnDisplay', val)" fieldName="copyOtpOnDisplay" label="settings.forms.copy_otp_on_display.label" help="settings.forms.copy_otp_on_display.help" :isDisabled="!user.preferences.getOtpOnRequest" :isIndented="true" />
|
<FormCheckbox v-model="user.preferences.copyOtpOnDisplay" @update:model-value="val => savePreference('copyOtpOnDisplay', val)" fieldName="copyOtpOnDisplay" label="settings.forms.copy_otp_on_display.label" help="settings.forms.copy_otp_on_display.help" :isDisabled="!user.preferences.getOtpOnRequest" :isIndented="true" />
|
||||||
<!-- otp as dot -->
|
<!-- otp as dot -->
|
||||||
|
@ -67,7 +67,11 @@
|
|||||||
],
|
],
|
||||||
'close_otp_on_copy' => [
|
'close_otp_on_copy' => [
|
||||||
'label' => 'Close <abbr title="One-Time Password">OTP</abbr> after copy',
|
'label' => 'Close <abbr title="One-Time Password">OTP</abbr> 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 <abbr title="One-Time Password">OTP</abbr>',
|
||||||
|
'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' => [
|
'clear_search_on_copy' => [
|
||||||
'label' => 'Clear Search on copy',
|
'label' => 'Clear Search on copy',
|
||||||
@ -161,6 +165,7 @@
|
|||||||
'never' => 'Never',
|
'never' => 'Never',
|
||||||
'on_otp_copy' => 'On security code copy',
|
'on_otp_copy' => 'On security code copy',
|
||||||
'1_minutes' => 'After 1 minute',
|
'1_minutes' => 'After 1 minute',
|
||||||
|
'2_minutes' => 'After 2 minutes',
|
||||||
'5_minutes' => 'After 5 minutes',
|
'5_minutes' => 'After 5 minutes',
|
||||||
'10_minutes' => 'After 10 minutes',
|
'10_minutes' => 'After 10 minutes',
|
||||||
'15_minutes' => 'After 15 minutes',
|
'15_minutes' => 'After 15 minutes',
|
||||||
|
Loading…
Reference in New Issue
Block a user