migrate app lock settings page to composition API and typescript
This commit is contained in:
@@ -27,7 +27,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from 'vue';
|
||||
import { ref, computed, watch } from 'vue';
|
||||
|
||||
import { useI18n } from '@/locales/helpers.ts';
|
||||
|
||||
@@ -74,6 +74,12 @@ function onSheetOpen(): void {
|
||||
function onSheetClosed(): void {
|
||||
cancel();
|
||||
}
|
||||
|
||||
watch(() => props.modelValue, (newValue) => {
|
||||
if (newValue === '') {
|
||||
currentPinCode.value = '';
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
+1
-5
@@ -230,11 +230,7 @@ export function getTextAfter(fullText: string, text: string): string {
|
||||
return '';
|
||||
}
|
||||
|
||||
export function base64encode(arrayBuffer: ArrayBuffer): string | null {
|
||||
if (!arrayBuffer) {
|
||||
return null;
|
||||
}
|
||||
|
||||
export function base64encode(arrayBuffer: ArrayBuffer): string {
|
||||
return btoa(String.fromCharCode.apply(null, Array.from(new Uint8Array(arrayBuffer))));
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ export interface Framework7Dom {
|
||||
|
||||
type TranslateFunction = (message: string) => string;
|
||||
|
||||
export function showAlert(message: string, confirmCallback: (dialog: Dialog.Dialog, e: Event) => void, translateFn: TranslateFunction): void {
|
||||
export function showAlert(message: string, confirmCallback: ((dialog: Dialog.Dialog, e: Event) => void) | undefined, translateFn: TranslateFunction): void {
|
||||
f7ready((f7) => {
|
||||
f7.dialog.create({
|
||||
title: translateFn('global.app.title'),
|
||||
@@ -229,7 +229,7 @@ export function useI18nUIComponents() {
|
||||
}
|
||||
|
||||
return {
|
||||
showAlert: (message: string, confirmCallback: (dialog: Dialog.Dialog, e: Event) => void) => showAlert(message, confirmCallback, i18nGlobal.t),
|
||||
showAlert: (message: string, confirmCallback?: (dialog: Dialog.Dialog, e: Event) => void) => showAlert(message, confirmCallback, i18nGlobal.t),
|
||||
showConfirm: (message: string, confirmCallback: (dialog: Dialog.Dialog, e: Event) => void, cancelCallback?: (dialog: Dialog.Dialog, e: Event) => void): void => showConfirm(message, confirmCallback, cancelCallback, i18nGlobal.t),
|
||||
showToast: (message: string, timeout?: number): void => showToast(message, timeout, i18nGlobal.t),
|
||||
routeBackOnError
|
||||
|
||||
+2
-2
@@ -28,7 +28,7 @@ interface AttestationData {
|
||||
}
|
||||
|
||||
interface WebAuthnRegisterResponse {
|
||||
readonly id: string | null;
|
||||
readonly id: string;
|
||||
readonly clientData: ClientData;
|
||||
readonly publicKey: Uint8Array | null;
|
||||
readonly rawCredential: Credential;
|
||||
@@ -198,7 +198,7 @@ export function verifyWebAuthnCredential(userInfo: UserBasicInfo, credentialId:
|
||||
clientData && clientData.type === 'webauthn.get' && challengeFromClientData === challenge &&
|
||||
userIdParts && userIdParts.length === 2 && userIdParts[0] === userInfo.username) {
|
||||
const ret: WebAuthnVerifyResponse = {
|
||||
id: base64encode(rawCredential.rawId) as string,
|
||||
id: base64encode(rawCredential.rawId),
|
||||
userName: userIdParts[0],
|
||||
userSecret: userIdParts[1],
|
||||
clientData: clientData,
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
import { ref, computed } from 'vue';
|
||||
|
||||
import { useSettingsStore } from '@/stores/setting.ts';
|
||||
|
||||
import { isWebAuthnCompletelySupported } from '@/lib/webauthn.ts';
|
||||
|
||||
export function useAppLockPageBase() {
|
||||
const settingsStore = useSettingsStore();
|
||||
|
||||
const isSupportedWebAuthn = ref<boolean>(false);
|
||||
|
||||
const isEnableApplicationLock = computed<boolean>({
|
||||
get: () => settingsStore.appSettings.applicationLock,
|
||||
set: (value) => settingsStore.setEnableApplicationLock(value)
|
||||
});
|
||||
|
||||
const isEnableApplicationLockWebAuthn = computed<boolean>({
|
||||
get: () => settingsStore.appSettings.applicationLockWebAuthn,
|
||||
set: (value) => settingsStore.setEnableApplicationLockWebAuthn(value)
|
||||
});
|
||||
|
||||
isWebAuthnCompletelySupported().then(result => {
|
||||
isSupportedWebAuthn.value = result;
|
||||
});
|
||||
|
||||
return {
|
||||
// states
|
||||
isSupportedWebAuthn,
|
||||
// computed states
|
||||
isEnableApplicationLock,
|
||||
isEnableApplicationLockWebAuthn
|
||||
};
|
||||
}
|
||||
@@ -1,31 +1,32 @@
|
||||
<template>
|
||||
<v-row>
|
||||
<v-col cols="12">
|
||||
<v-card :title="$t('Application Lock')">
|
||||
<v-card :title="tt('Application Lock')">
|
||||
<v-card-text class="pb-0">
|
||||
<p class="text-body-1 font-weight-semibold" v-if="!isEnableApplicationLock">
|
||||
{{ $t('Application lock is not enabled') }}
|
||||
{{ tt('Application lock is not enabled') }}
|
||||
</p>
|
||||
<p class="text-body-1" v-if="isEnableApplicationLock">
|
||||
{{ $t('Application lock has been enabled') }}
|
||||
{{ tt('Application lock has been enabled') }}
|
||||
</p>
|
||||
</v-card-text>
|
||||
|
||||
<v-card-text v-if="isEnableApplicationLock">
|
||||
<v-switch :disabled="true"
|
||||
:label="$t('Unlock with PIN Code')"
|
||||
:label="tt('Unlock with PIN Code')"
|
||||
v-model="isEnableApplicationLock"/>
|
||||
<v-switch :label="$t('Unlock with WebAuthn')"
|
||||
<v-switch :label="tt('Unlock with WebAuthn')"
|
||||
:loading="enablingWebAuthn"
|
||||
v-model="isEnableApplicationLockWebAuthn"/>
|
||||
v-model="isEnableApplicationLockWebAuthn"
|
||||
v-if="isSupportedWebAuthn"/>
|
||||
</v-card-text>
|
||||
|
||||
<v-card-text class="pb-0">
|
||||
<p class="text-body-1 font-weight-semibold" v-if="!isEnableApplicationLock">
|
||||
{{ $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.') }}
|
||||
{{ 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.') }}
|
||||
</p>
|
||||
<p class="text-body-1 font-weight-semibold" v-if="isEnableApplicationLock">
|
||||
{{ $t('Your current PIN code is required to disable application lock.') }}
|
||||
{{ tt('Your current PIN code is required to disable application lock.') }}
|
||||
</p>
|
||||
</v-card-text>
|
||||
|
||||
@@ -44,11 +45,11 @@
|
||||
<v-col cols="12" class="d-flex flex-wrap gap-4">
|
||||
<v-btn :disabled="!pinCodeValid"
|
||||
v-if="!isEnableApplicationLock" @click="enable">
|
||||
{{ $t('Enable Application Lock') }}
|
||||
{{ tt('Enable Application Lock') }}
|
||||
</v-btn>
|
||||
<v-btn :disabled="!pinCodeValid"
|
||||
v-if="isEnableApplicationLock" @click="disable">
|
||||
{{ $t('Disable Application Lock') }}
|
||||
{{ tt('Disable Application Lock') }}
|
||||
</v-btn>
|
||||
</v-col>
|
||||
</v-row>
|
||||
@@ -60,16 +61,19 @@
|
||||
<snack-bar ref="snackbar" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapStores } from 'pinia';
|
||||
<script setup lang="ts">
|
||||
import SnackBar from '@/components/desktop/SnackBar.vue';
|
||||
|
||||
import { ref, computed, useTemplateRef, watch } from 'vue';
|
||||
|
||||
import { useI18n } from '@/locales/helpers.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,
|
||||
@@ -80,141 +84,122 @@ import {
|
||||
} from '@/lib/userstate.ts';
|
||||
import logger from '@/lib/logger.ts';
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
isSupportedWebAuthn: false,
|
||||
enablingWebAuthn: false,
|
||||
pinCode: ''
|
||||
};
|
||||
},
|
||||
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);
|
||||
}
|
||||
},
|
||||
pinCodeValid() {
|
||||
return this.pinCode && this.pinCode.length === 6;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
isEnableApplicationLockWebAuthn: function (newValue) {
|
||||
const self = this;
|
||||
type SnackBarType = InstanceType<typeof SnackBar>;
|
||||
|
||||
if (newValue) {
|
||||
self.enablingWebAuthn = true;
|
||||
const { tt } = useI18n();
|
||||
|
||||
registerWebAuthnCredential(
|
||||
getUserAppLockState(),
|
||||
self.userStore.currentUserBasicInfo,
|
||||
).then(({ id }) => {
|
||||
self.enablingWebAuthn = false;
|
||||
const { isSupportedWebAuthn, isEnableApplicationLock, isEnableApplicationLockWebAuthn } = useAppLockPageBase();
|
||||
|
||||
saveWebAuthnConfig(id);
|
||||
self.settingsStore.setEnableApplicationLockWebAuthn(true);
|
||||
self.$refs.snackbar.showMessage('You have enabled WebAuthn successfully');
|
||||
}).catch(error => {
|
||||
logger.error('failed to enable WebAuthn', error);
|
||||
const settingsStore = useSettingsStore();
|
||||
const userStore = useUserStore();
|
||||
|
||||
self.enablingWebAuthn = false;
|
||||
const snackbar = useTemplateRef<SnackBarType>('snackbar');
|
||||
|
||||
if (error.notSupported) {
|
||||
self.$refs.snackbar.showMessage('WebAuth is not supported on this device');
|
||||
} else if (error.name === 'NotAllowedError') {
|
||||
self.$refs.snackbar.showMessage('User has canceled authentication');
|
||||
} else if (error.invalid) {
|
||||
self.$refs.snackbar.showMessage('Failed to enable WebAuthn');
|
||||
} else {
|
||||
self.$refs.snackbar.showMessage('User has canceled or this device does not support WebAuthn');
|
||||
}
|
||||
const pinCode = ref<string>('');
|
||||
const enablingWebAuthn = ref<boolean>(false);
|
||||
const transactionsStore = useTransactionsStore();
|
||||
|
||||
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: {
|
||||
confirm() {
|
||||
if (this.isEnableApplicationLock) {
|
||||
this.disable();
|
||||
} else {
|
||||
this.enable();
|
||||
}
|
||||
},
|
||||
enable() {
|
||||
if (this.settingsStore.appSettings.applicationLock) {
|
||||
this.$refs.snackbar.showMessage('Application lock has been enabled');
|
||||
return;
|
||||
}
|
||||
const pinCodeValid = computed<boolean>(() => {
|
||||
return pinCode.value?.length === 6 || false;
|
||||
});
|
||||
|
||||
if (!this.pinCode || this.pinCode.length !== 6) {
|
||||
this.pinCode = '';
|
||||
this.$refs.snackbar.showMessage('Invalid PIN code');
|
||||
return;
|
||||
}
|
||||
|
||||
const user = this.userStore.currentUserBasicInfo;
|
||||
|
||||
if (!user || !user.username) {
|
||||
this.pinCode = '';
|
||||
this.$refs.snackbar.showMessage('An error occurred');
|
||||
return;
|
||||
}
|
||||
|
||||
encryptToken(user.username, this.pinCode);
|
||||
this.settingsStore.setEnableApplicationLock(true);
|
||||
this.transactionsStore.saveTransactionDraft();
|
||||
|
||||
this.settingsStore.setEnableApplicationLockWebAuthn(false);
|
||||
clearWebAuthnConfig();
|
||||
|
||||
this.pinCode = '';
|
||||
},
|
||||
disable() {
|
||||
if (!this.settingsStore.appSettings.applicationLock) {
|
||||
this.$refs.snackbar.showMessage('Application lock is not enabled');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isCorrectPinCode(this.pinCode)) {
|
||||
this.pinCode = '';
|
||||
this.$refs.snackbar.showMessage('Incorrect PIN code');
|
||||
return;
|
||||
}
|
||||
|
||||
this.pinCode = '';
|
||||
|
||||
decryptToken();
|
||||
this.settingsStore.setEnableApplicationLock(false);
|
||||
this.transactionsStore.saveTransactionDraft();
|
||||
|
||||
this.settingsStore.setEnableApplicationLockWebAuthn(false);
|
||||
clearWebAuthnConfig();
|
||||
}
|
||||
function confirm(): void {
|
||||
if (isEnableApplicationLock.value) {
|
||||
disable();
|
||||
} else {
|
||||
enable();
|
||||
}
|
||||
}
|
||||
|
||||
function enable(): void {
|
||||
if (settingsStore.appSettings.applicationLock) {
|
||||
snackbar.value?.showMessage('Application lock has been enabled');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!pinCode.value || pinCode.value.length !== 6) {
|
||||
pinCode.value = '';
|
||||
snackbar.value?.showMessage('Invalid PIN code');
|
||||
return;
|
||||
}
|
||||
|
||||
const user = userStore.currentUserBasicInfo;
|
||||
|
||||
if (!user || !user.username) {
|
||||
pinCode.value = '';
|
||||
snackbar.value?.showMessage('An error occurred');
|
||||
return;
|
||||
}
|
||||
|
||||
encryptToken(user.username, pinCode.value);
|
||||
settingsStore.setEnableApplicationLock(true);
|
||||
transactionsStore.saveTransactionDraft();
|
||||
|
||||
settingsStore.setEnableApplicationLockWebAuthn(false);
|
||||
clearWebAuthnConfig();
|
||||
|
||||
pinCode.value = '';
|
||||
}
|
||||
|
||||
function disable(): void {
|
||||
if (!settingsStore.appSettings.applicationLock) {
|
||||
snackbar.value?.showMessage('Application lock is not enabled');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isCorrectPinCode(pinCode.value)) {
|
||||
pinCode.value = '';
|
||||
snackbar.value?.showMessage('Incorrect PIN code');
|
||||
return;
|
||||
}
|
||||
|
||||
pinCode.value = '';
|
||||
|
||||
decryptToken();
|
||||
settingsStore.setEnableApplicationLock(false);
|
||||
transactionsStore.saveTransactionDraft();
|
||||
|
||||
settingsStore.setEnableApplicationLockWebAuthn(false);
|
||||
clearWebAuthnConfig();
|
||||
}
|
||||
|
||||
watch(isEnableApplicationLockWebAuthn, (newValue) => {
|
||||
const userAppLockState = getUserAppLockState();
|
||||
|
||||
if (newValue && userAppLockState && userStore.currentUserBasicInfo) {
|
||||
enablingWebAuthn.value = true;
|
||||
|
||||
registerWebAuthnCredential(
|
||||
userAppLockState,
|
||||
userStore.currentUserBasicInfo,
|
||||
).then(({ id }) => {
|
||||
enablingWebAuthn.value = false;
|
||||
|
||||
saveWebAuthnConfig(id);
|
||||
settingsStore.setEnableApplicationLockWebAuthn(true);
|
||||
snackbar.value?.showMessage('You have enabled WebAuthn successfully');
|
||||
}).catch(error => {
|
||||
logger.error('failed to enable WebAuthn', error);
|
||||
|
||||
enablingWebAuthn.value = false;
|
||||
|
||||
if (error.notSupported) {
|
||||
snackbar.value?.showMessage('WebAuth is not supported on this device');
|
||||
} else if (error.name === 'NotAllowedError') {
|
||||
snackbar.value?.showMessage('User has canceled authentication');
|
||||
} else if (error.invalid) {
|
||||
snackbar.value?.showMessage('Failed to enable WebAuthn');
|
||||
} else {
|
||||
snackbar.value?.showMessage('User has canceled or this device does not support WebAuthn');
|
||||
}
|
||||
|
||||
isEnableApplicationLockWebAuthn.value = false;
|
||||
settingsStore.setEnableApplicationLockWebAuthn(false);
|
||||
clearWebAuthnConfig();
|
||||
});
|
||||
} else {
|
||||
settingsStore.setEnableApplicationLockWebAuthn(false);
|
||||
clearWebAuthnConfig();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user