migrate app lock settings page to composition API and typescript

This commit is contained in:
MaysWind
2025-01-16 22:37:35 +08:00
parent adebc96637
commit 4f21762533
7 changed files with 310 additions and 301 deletions
+136 -147
View File
@@ -1,33 +1,33 @@
<template>
<f7-page>
<f7-navbar>
<f7-nav-left :back-link="$t('Back')"></f7-nav-left>
<f7-nav-title :title="$t('Application Lock')"></f7-nav-title>
<f7-nav-left :back-link="tt('Back')"></f7-nav-left>
<f7-nav-title :title="tt('Application Lock')"></f7-nav-title>
</f7-navbar>
<f7-list strong inset dividers class="margin-top">
<f7-list-item :title="$t('Status')" :after="$t(isEnableApplicationLock ? 'Enabled' : 'Disabled')"></f7-list-item>
<f7-list-item :title="tt('Status')" :after="tt(isEnableApplicationLock ? 'Enabled' : 'Disabled')"></f7-list-item>
<f7-list-item v-if="isEnableApplicationLock">
<span>{{ $t('Unlock with PIN Code') }}</span>
<span>{{ tt('Unlock with PIN Code') }}</span>
<f7-toggle checked disabled></f7-toggle>
</f7-list-item>
<f7-list-item v-if="isEnableApplicationLock && isSupportedWebAuthn">
<span>{{ $t('Unlock with WebAuthn') }}</span>
<span>{{ tt('Unlock with WebAuthn') }}</span>
<f7-toggle :checked="isEnableApplicationLockWebAuthn" @toggle:change="isEnableApplicationLockWebAuthn = $event"></f7-toggle>
</f7-list-item>
<f7-list-button v-if="isEnableApplicationLock" @click="disable(null)">{{ $t('Disable') }}</f7-list-button>
<f7-list-button v-if="!isEnableApplicationLock" @click="enable(null)">{{ $t('Enable') }}</f7-list-button>
<f7-list-button v-if="isEnableApplicationLock" @click="disable(null)">{{ tt('Disable') }}</f7-list-button>
<f7-list-button v-if="!isEnableApplicationLock" @click="enable(null)">{{ tt('Enable') }}</f7-list-button>
</f7-list>
<pin-code-input-sheet :title="$t('PIN Code')"
:hint="$t('Please enter a new 6-digit PIN code. The PIN code would encrypt your local data, so you need to enter it every time you open this app. If this PIN code is lost, you will need to log in again.')"
<pin-code-input-sheet :title="tt('PIN Code')"
:hint="tt('Please enter a new 6-digit PIN code. The PIN code would encrypt your local data, so you need to enter it every time you open this app. If this PIN code is lost, you will need to log in again.')"
v-model:show="showInputPinCodeSheetForEnable"
v-model="currentPinCodeForEnable"
@pincode:confirm="enable">
</pin-code-input-sheet>
<pin-code-input-sheet :title="$t('PIN Code')"
:hint="$t('Your current PIN code is required to disable application lock.')"
<pin-code-input-sheet :title="tt('PIN Code')"
:hint="tt('Your current PIN code is required to disable application lock.')"
v-model:show="showInputPinCodeSheetForDisable"
v-model="currentPinCodeForDisable"
@pincode:confirm="disable">
@@ -35,16 +35,18 @@
</f7-page>
</template>
<script>
import { mapStores } from 'pinia';
<script setup lang="ts">
import { ref, watch, nextTick } from 'vue';
import { useI18n } from '@/locales/helpers.ts';
import { useI18nUIComponents, showLoading, hideLoading } from '@/lib/ui/mobile.ts';
import { useAppLockPageBase } from '@/views/base/settings/AppLockPageBase.ts';
import { useSettingsStore } from '@/stores/setting.ts';
import { useUserStore } from '@/stores/user.ts';
import { useTransactionsStore } from '@/stores/transaction.js';
import {
isWebAuthnCompletelySupported,
registerWebAuthnCredential
} from '@/lib/webauthn.ts';
import { registerWebAuthnCredential } from '@/lib/webauthn.ts';
import {
getUserAppLockState,
encryptToken,
@@ -55,140 +57,127 @@ import {
} from '@/lib/userstate.ts';
import logger from '@/lib/logger.ts';
export default {
data() {
return {
isSupportedWebAuthn: false,
currentPinCodeForEnable: '',
currentPinCodeForDisable: '',
showInputPinCodeSheetForEnable: false,
showInputPinCodeSheetForDisable: false
};
},
computed: {
...mapStores(useSettingsStore, useUserStore, useTransactionsStore),
isEnableApplicationLock: {
get: function () {
return this.settingsStore.appSettings.applicationLock;
},
set: function (value) {
this.settingsStore.setEnableApplicationLock(value);
}
},
isEnableApplicationLockWebAuthn: {
get: function () {
return this.settingsStore.appSettings.applicationLockWebAuthn;
},
set: function (value) {
this.settingsStore.setEnableApplicationLockWebAuthn(value);
}
}
},
watch: {
isEnableApplicationLockWebAuthn: function (newValue) {
const self = this;
const { tt } = useI18n();
const { showToast } = useI18nUIComponents();
if (newValue) {
self.$showLoading();
const { isSupportedWebAuthn, isEnableApplicationLock, isEnableApplicationLockWebAuthn } = useAppLockPageBase();
registerWebAuthnCredential(
getUserAppLockState(),
self.userStore.currentUserBasicInfo,
).then(({ id }) => {
self.$hideLoading();
const settingsStore = useSettingsStore();
const userStore = useUserStore();
const transactionsStore = useTransactionsStore();
saveWebAuthnConfig(id);
self.settingsStore.setEnableApplicationLockWebAuthn(true);
self.$toast('You have enabled WebAuthn successfully');
}).catch(error => {
logger.error('failed to enable WebAuthn', error);
const currentPinCodeForEnable = ref<string>('');
const currentPinCodeForDisable = ref<string>('');
const showInputPinCodeSheetForEnable = ref<boolean>(false);
const showInputPinCodeSheetForDisable = ref<boolean>(false);
self.$hideLoading();
if (error.notSupported) {
self.$toast('WebAuth is not supported on this device');
} else if (error.name === 'NotAllowedError') {
self.$toast('User has canceled authentication');
} else if (error.invalid) {
self.$toast('Failed to enable WebAuthn');
} else {
self.$toast('User has canceled or this device does not support WebAuthn');
}
self.isEnableApplicationLockWebAuthn = false;
self.settingsStore.setEnableApplicationLockWebAuthn(false);
clearWebAuthnConfig();
});
} else {
self.settingsStore.setEnableApplicationLockWebAuthn(false);
clearWebAuthnConfig();
}
}
},
created() {
const self = this;
isWebAuthnCompletelySupported().then(result => {
self.isSupportedWebAuthn = result;
});
},
methods: {
enable(pinCode) {
if (this.settingsStore.appSettings.applicationLock) {
this.$alert('Application lock has been enabled');
return;
}
if (!pinCode) {
this.showInputPinCodeSheetForEnable = true;
return;
}
if (!this.currentPinCodeForEnable || this.currentPinCodeForEnable.length !== 6) {
this.$alert('Invalid PIN code');
return;
}
const user = this.userStore.currentUserBasicInfo;
if (!user || !user.username) {
this.$alert('An error occurred');
return;
}
encryptToken(user.username, pinCode);
this.settingsStore.setEnableApplicationLock(true);
this.transactionsStore.saveTransactionDraft();
this.settingsStore.setEnableApplicationLockWebAuthn(false);
clearWebAuthnConfig();
this.showInputPinCodeSheetForEnable = false;
},
disable(pinCode) {
if (!this.settingsStore.appSettings.applicationLock) {
this.$alert('Application lock is not enabled');
return;
}
if (!pinCode) {
this.showInputPinCodeSheetForDisable = true;
return;
}
if (!isCorrectPinCode(pinCode)) {
this.$alert('Incorrect PIN code');
return;
}
decryptToken();
this.settingsStore.setEnableApplicationLock(false);
this.transactionsStore.saveTransactionDraft();
this.settingsStore.setEnableApplicationLockWebAuthn(false);
clearWebAuthnConfig();
this.showInputPinCodeSheetForDisable = false;
}
function enable(pinCode: string | null): void {
if (settingsStore.appSettings.applicationLock) {
showToast('Application lock has been enabled');
return;
}
if (!pinCode) {
currentPinCodeForEnable.value = '';
showInputPinCodeSheetForEnable.value = true;
return;
}
if (!currentPinCodeForEnable.value || currentPinCodeForEnable.value.length !== 6) {
nextTick(() => {
currentPinCodeForEnable.value = '';
});
showToast('Invalid PIN code');
return;
}
const user = userStore.currentUserBasicInfo;
if (!user || !user.username) {
nextTick(() => {
currentPinCodeForEnable.value = '';
});
showToast('An error occurred');
return;
}
encryptToken(user.username, pinCode);
settingsStore.setEnableApplicationLock(true);
transactionsStore.saveTransactionDraft();
settingsStore.setEnableApplicationLockWebAuthn(false);
clearWebAuthnConfig();
showInputPinCodeSheetForEnable.value = false;
}
function disable(pinCode: string | null): void {
if (!settingsStore.appSettings.applicationLock) {
showToast('Application lock is not enabled');
return;
}
if (!pinCode) {
currentPinCodeForDisable.value = '';
showInputPinCodeSheetForDisable.value = true;
return;
}
if (!isCorrectPinCode(pinCode)) {
nextTick(() => {
currentPinCodeForDisable.value = '';
});
showToast('Incorrect PIN code');
return;
}
decryptToken();
settingsStore.setEnableApplicationLock(false);
transactionsStore.saveTransactionDraft();
settingsStore.setEnableApplicationLockWebAuthn(false);
clearWebAuthnConfig();
showInputPinCodeSheetForDisable.value = false;
}
watch(isEnableApplicationLockWebAuthn, (newValue) => {
const userAppLockState = getUserAppLockState();
if (newValue && userAppLockState && userStore.currentUserBasicInfo) {
showLoading();
registerWebAuthnCredential(
userAppLockState,
userStore.currentUserBasicInfo,
).then(({ id }) => {
hideLoading();
saveWebAuthnConfig(id);
settingsStore.setEnableApplicationLockWebAuthn(true);
showToast('You have enabled WebAuthn successfully');
}).catch(error => {
logger.error('failed to enable WebAuthn', error);
hideLoading();
if (error.notSupported) {
showToast('WebAuth is not supported on this device');
} else if (error.name === 'NotAllowedError') {
showToast('User has canceled authentication');
} else if (error.invalid) {
showToast('Failed to enable WebAuthn');
} else {
showToast('User has canceled or this device does not support WebAuthn');
}
isEnableApplicationLockWebAuthn.value = false;
settingsStore.setEnableApplicationLockWebAuthn(false);
clearWebAuthnConfig();
});
} else {
settingsStore.setEnableApplicationLockWebAuthn(false);
clearWebAuthnConfig();
}
});
</script>