Add user preference to automatically save accounts on QRcode submission

This commit is contained in:
Bubka 2024-06-21 14:25:39 +02:00
parent 570f3bb9bd
commit e49c1abe93
5 changed files with 81 additions and 14 deletions

View File

@ -127,6 +127,7 @@ return [
'timezone' => env('APP_TIMEZONE', 'UTC'), 'timezone' => env('APP_TIMEZONE', 'UTC'),
'sortCaseSensitive' => false, 'sortCaseSensitive' => false,
'autoCloseTimeout' => 2, 'autoCloseTimeout' => 2,
'AutoSaveQrcodedAccount' => false,
], ],
]; ];

View File

@ -19,6 +19,10 @@ export default {
return apiClient.post('/twofaccounts/preview', { uri: uri }, { ...config }) return apiClient.post('/twofaccounts/preview', { uri: uri }, { ...config })
}, },
storeFromUri(uri, config = {}) {
return apiClient.post('/twofaccounts', { uri: uri }, { ...config })
},
getLogo(service, config = {}) { getLogo(service, config = {}) {
return apiClient.post('/icons/default', { service: service }, { ...config }) return apiClient.post('/icons/default', { service: service }, { ...config })
}, },

View File

@ -179,6 +179,8 @@
<FormCheckbox v-model="user.preferences.notifyOnFailedLogin" @update:model-value="val => savePreference('notifyOnFailedLogin', val)" fieldName="notifyOnFailedLogin" label="settings.forms.notify_on_failed_login.label" help="settings.forms.notify_on_failed_login.help" /> <FormCheckbox v-model="user.preferences.notifyOnFailedLogin" @update:model-value="val => savePreference('notifyOnFailedLogin', val)" fieldName="notifyOnFailedLogin" label="settings.forms.notify_on_failed_login.label" help="settings.forms.notify_on_failed_login.help" />
<h4 class="title is-4 pt-4 has-text-grey-light">{{ $t('settings.data_input') }}</h4> <h4 class="title is-4 pt-4 has-text-grey-light">{{ $t('settings.data_input') }}</h4>
<!-- auto-save QrCoded account -->
<FormCheckbox v-model="user.preferences.AutoSaveQrcodedAccount" @update:model-value="val => savePreference('AutoSaveQrcodedAccount', val)" fieldName="AutoSaveQrcodedAccount" label="settings.forms.auto_save_qrcoded_account.label" help="settings.forms.auto_save_qrcoded_account.help" />
<!-- basic qrcode --> <!-- basic qrcode -->
<FormCheckbox v-model="user.preferences.useBasicQrcodeReader" @update:model-value="val => savePreference('useBasicQrcodeReader', val)" fieldName="useBasicQrcodeReader" label="settings.forms.use_basic_qrcode_reader.label" help="settings.forms.use_basic_qrcode_reader.help" /> <FormCheckbox v-model="user.preferences.useBasicQrcodeReader" @update:model-value="val => savePreference('useBasicQrcodeReader', val)" fieldName="useBasicQrcodeReader" label="settings.forms.use_basic_qrcode_reader.label" help="settings.forms.use_basic_qrcode_reader.help" />
<!-- direct capture --> <!-- direct capture -->

View File

@ -35,6 +35,12 @@
const iconForm = reactive(new Form({ const iconForm = reactive(new Form({
icon: null icon: null
})) }))
const otpDisplayProps = ref({
otp_type: '',
account : '',
service : '',
icon : '',
})
const otp_types = [ const otp_types = [
{ text: 'TOTP', value: 'totp' }, { text: 'TOTP', value: 'totp' },
{ text: 'HOTP', value: 'hotp' }, { text: 'HOTP', value: 'hotp' },
@ -57,12 +63,14 @@
const tempIcon = ref('') const tempIcon = ref('')
const showQuickForm = ref(false) const showQuickForm = ref(false)
const showAlternatives = ref(false) const showAlternatives = ref(false)
const showOtpInModal = ref(false)
const showAdvancedForm = ref(false) const showAdvancedForm = ref(false)
const ShowTwofaccountInModal = ref(false) const ShowTwofaccountInModal = ref(false)
const fetchingLogo = ref(false) const fetchingLogo = ref(false)
// $refs // $refs
const iconInput = ref(null) const iconInput = ref(null)
const OtpDisplayForAutoSave = ref(null)
const OtpDisplayForQuickForm = ref(null) const OtpDisplayForQuickForm = ref(null)
const OtpDisplayForAdvancedForm = ref(null) const OtpDisplayForAdvancedForm = ref(null)
const qrcodeInputLabel = ref(null) const qrcodeInputLabel = ref(null)
@ -88,24 +96,40 @@
}) })
} }
else if( bus.decodedUri ) { else if( bus.decodedUri ) {
// the Start view provided an uri via the bus store so we parse it and prefill the quick form // The Start|Capture view provided an uri via the bus store.
uri.value = bus.decodedUri uri.value = bus.decodedUri
bus.decodedUri = null bus.decodedUri = null
twofaccountService.preview(uri.value).then(response => { if (user.preferences.AutoSaveQrcodedAccount) {
form.fill(response.data) // The user wants the account to be saved automatically.
tempIcon.value = response.data.icon ? response.data.icon : '' // We save it now and we show him a fresh otp
showQuickForm.value = true twofaccountService.storeFromUri(uri.value).then(response => {
nextTick().then(() => { showOTP(response.data)
OtpDisplayForQuickForm.value.show()
}) })
}) .catch(error => {
.catch(error => { if( error.response.data.errors.uri ) {
if( error.response.data.errors.uri ) { showAlternatives.value = true
showAlternatives.value = true showAdvancedForm.value = true
showAdvancedForm.value = true }
} })
}) }
else {
// We prefill and show the quick form
twofaccountService.preview(uri.value).then(response => {
form.fill(response.data)
tempIcon.value = response.data.icon ? response.data.icon : ''
showQuickForm.value = true
nextTick().then(() => {
OtpDisplayForQuickForm.value.show()
})
})
.catch(error => {
if( error.response.data.errors.uri ) {
showAlternatives.value = true
showAdvancedForm.value = true
}
})
}
} else { } else {
showAdvancedForm.value = true showAdvancedForm.value = true
} }
@ -126,6 +150,13 @@
} }
}) })
watch(showOtpInModal, (val) => {
if (val == false) {
OtpDisplayForAutoSave.value?.clearOTP()
router.push({ name: 'accounts' })
}
})
watch( watch(
() => form.otp_type, () => form.otp_type,
(to, from) => { (to, from) => {
@ -197,6 +228,23 @@
OtpDisplayForAdvancedForm.value.show() OtpDisplayForAdvancedForm.value.show()
} }
/**
* Shows rotating OTP for the provided account
*/
function showOTP(otp) {
// Data that should be displayed quickly by the OtpDisplay
// component are passed using props.
otpDisplayProps.value.otp_type = otp.otp_type
otpDisplayProps.value.service = otp.service
otpDisplayProps.value.account = otp.account
otpDisplayProps.value.icon = otp.icon
nextTick().then(() => {
showOtpInModal.value = true
OtpDisplayForAutoSave.value.show(otp.id);
})
}
/** /**
* Exits the view with user confirmation * Exits the view with user confirmation
*/ */
@ -351,6 +399,14 @@
<template> <template>
<div> <div>
<!-- otp display modal -->
<Modal v-if="user.preferences.AutoSaveQrcodedAccount" v-model="showOtpInModal">
<OtpDisplay
ref="OtpDisplayForAutoSave"
v-bind="otpDisplayProps"
@please-close-me="router.push({ name: 'accounts' })">
</OtpDisplay>
</Modal>
<!-- Quick form --> <!-- Quick form -->
<form @submit.prevent="createAccount" @keydown="form.onKeydown($event)" v-if="!isEditMode && showQuickForm"> <form @submit.prevent="createAccount" @keydown="form.onKeydown($event)" v-if="!isEditMode && showQuickForm">
<div class="container preview has-text-centered"> <div class="container preview has-text-centered">

View File

@ -132,6 +132,10 @@ return [
'label' => 'View default group on copy', 'label' => 'View default group on copy',
'help' => 'Always return to the default group when an OTP is copied', 'help' => 'Always return to the default group when an OTP is copied',
], ],
'auto_save_qrcoded_account' => [
'label' => 'Auto-save accounts',
'help' => 'New accounts are automatically registered after scanning or uploading a QR code, no need to click a Save button',
],
'useDirectCapture' => [ 'useDirectCapture' => [
'label' => 'Direct input', 'label' => 'Direct input',
'help' => 'Choose whether you want to be prompted to choose an input mode among those available or if you want to directly use the default input mode', 'help' => 'Choose whether you want to be prompted to choose an input mode among those available or if you want to directly use the default input mode',