@adminforth/two-factors-auth 1.0.21 → 1.0.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Changelog.md +5 -0
- package/custom/TwoFactorsConfirmation.vue +14 -19
- package/custom/TwoFactorsSetup.vue +26 -38
- package/dist/custom/TwoFactorsConfirmation.vue +14 -19
- package/dist/custom/TwoFactorsSetup.vue +26 -38
- package/package.json +1 -1
- package/custom/TwoFactorsOtp.vue +0 -0
- package/dist/custom/TwoFactorsOtp.vue +0 -0
package/Changelog.md
CHANGED
|
@@ -13,25 +13,22 @@
|
|
|
13
13
|
<!-- Modal content -->
|
|
14
14
|
<div class="relative bg-white rounded-lg shadow dark:bg-gray-700 dark:shadow-black text-gray-500" >
|
|
15
15
|
<div class="p-8 w-full max-w-md max-h-full" >
|
|
16
|
-
<div class="m-3"
|
|
16
|
+
<div class="m-3">Please enter your authenticator code </div>
|
|
17
17
|
<div class="my-4 flex justify-center items-center">
|
|
18
18
|
<v-otp-input
|
|
19
19
|
ref="code"
|
|
20
|
-
input-classes="
|
|
20
|
+
input-classes="bg-gray-50 text-center flex justify-center otp-input border leading-none border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-10 h-10 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
|
|
21
21
|
:conditionalClass="['one', 'two', 'three', 'four', 'five', 'six']"
|
|
22
22
|
inputType="number"
|
|
23
23
|
:num-inputs="6"
|
|
24
24
|
v-model:value="bindValue"
|
|
25
25
|
:should-auto-focus="true"
|
|
26
26
|
:should-focus-order="true"
|
|
27
|
-
@on-change="handleOnChange"
|
|
28
27
|
@on-complete="handleOnComplete"
|
|
29
28
|
/>
|
|
30
29
|
</div>
|
|
31
30
|
<!-- <Vue2FACodeInput v-model="code"/> -->
|
|
32
|
-
<
|
|
33
|
-
Cancel
|
|
34
|
-
</button>
|
|
31
|
+
<Button @click="() => {router.push('./login')}" class="w-full">Cancel</Button>
|
|
35
32
|
</div>
|
|
36
33
|
</div>
|
|
37
34
|
</div>
|
|
@@ -52,6 +49,7 @@
|
|
|
52
49
|
import { callAdminForthApi, loadFile } from '@/utils';
|
|
53
50
|
import { useRouter } from 'vue-router';
|
|
54
51
|
import { showErrorTost } from '@/composables/useFrontendApi';
|
|
52
|
+
import { Button } from '@/afcl';
|
|
55
53
|
import Vue2FACodeInput from '@loltech/vue3-2fa-code-input';
|
|
56
54
|
import VOtpInput from "vue3-otp-input";
|
|
57
55
|
|
|
@@ -99,13 +97,12 @@
|
|
|
99
97
|
|
|
100
98
|
onMounted(async () => {
|
|
101
99
|
coreStore.getPublicConfig();
|
|
102
|
-
window.addEventListener('
|
|
100
|
+
window.addEventListener('paste', handlePaste);
|
|
103
101
|
});
|
|
104
102
|
|
|
105
103
|
onBeforeUnmount(() => {
|
|
106
|
-
window.removeEventListener('
|
|
104
|
+
window.removeEventListener('paste', handlePaste);
|
|
107
105
|
});
|
|
108
|
-
|
|
109
106
|
|
|
110
107
|
async function sendCode (value) {
|
|
111
108
|
inProgress.value = true;
|
|
@@ -130,16 +127,14 @@
|
|
|
130
127
|
// }
|
|
131
128
|
// })
|
|
132
129
|
|
|
133
|
-
function
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
console.error('Failed to read clipboard contents: ', err);
|
|
142
|
-
});
|
|
130
|
+
function handlePaste(event) {
|
|
131
|
+
event.preventDefault();
|
|
132
|
+
if (event.target.classList.contains('otp-input')) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
const pastedText = event.clipboardData?.getData('text') || '';
|
|
136
|
+
if (pastedText.length === 6) {
|
|
137
|
+
code.value?.fillInput(pastedText);
|
|
143
138
|
}
|
|
144
139
|
}
|
|
145
140
|
</script>
|
|
@@ -22,15 +22,15 @@
|
|
|
22
22
|
<div class="w-full max-w-[46rem]">
|
|
23
23
|
<div class="relative">
|
|
24
24
|
<label for="npm-install-copy-text" class="sr-only">Label</label>
|
|
25
|
-
<input id="npm-install-copy-text" type="text" class="col-span-10 bg-gray-50 border border-gray-300 text-gray-500 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full px-2.5 py-4 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-gray-400 dark:focus:ring-blue-500 dark:focus:border-blue-500" :value="totp.newSecret"
|
|
26
|
-
<button data-copy-to-clipboard-target="npm-install-copy-text" class="absolute end-2.5 top-1/2 -translate-y-1/2 text-gray-900 dark:text-gray-400 hover:bg-gray-100 dark:bg-gray-800 dark:border-gray-600 dark:hover:bg-gray-700 rounded-lg py-2 px-2.5 inline-flex items-center justify-center bg-white border-gray-200 border">
|
|
27
|
-
<span id="default-message" class="inline-flex items-center">
|
|
25
|
+
<input id="npm-install-copy-text" type="text" class="col-span-10 bg-gray-50 border border-gray-300 text-gray-500 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full px-2.5 py-4 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-gray-400 dark:focus:ring-blue-500 dark:focus:border-blue-500 pr-20" :value="totp.newSecret" readonly>
|
|
26
|
+
<button @click="onCopyClick" data-copy-to-clipboard-target="npm-install-copy-text" class="absolute end-2.5 top-1/2 -translate-y-1/2 text-gray-900 dark:text-gray-400 hover:bg-gray-100 dark:bg-gray-800 dark:border-gray-600 dark:hover:bg-gray-700 rounded-lg py-2 px-2.5 inline-flex items-center justify-center bg-white border-gray-200 border">
|
|
27
|
+
<span v-if="isCopied === false" id="default-message" class="inline-flex items-center">
|
|
28
28
|
<svg class="w-3 h-3 me-1.5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 18 20">
|
|
29
29
|
<path d="M16 1h-3.278A1.992 1.992 0 0 0 11 0H7a1.993 1.993 0 0 0-1.722 1H2a2 2 0 0 0-2 2v15a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2Zm-3 14H5a1 1 0 0 1 0-2h8a1 1 0 0 1 0 2Zm0-4H5a1 1 0 0 1 0-2h8a1 1 0 1 1 0 2Zm0-5H5a1 1 0 0 1 0-2h2V2h4v2h2a1 1 0 1 1 0 2Z"/>
|
|
30
30
|
</svg>
|
|
31
|
-
<span
|
|
31
|
+
<span class="text-xs font-semibold">Copy</span>
|
|
32
32
|
</span>
|
|
33
|
-
<span id="success-message" class="
|
|
33
|
+
<span v-if="isCopied === true" id="success-message" class="inline-flex items-center">
|
|
34
34
|
<svg class="w-3 h-3 text-lightPrimary dark:text-darkPrimary me-1.5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 16 12">
|
|
35
35
|
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M1 5.917 5.724 10.5 15 1.5"/>
|
|
36
36
|
</svg>
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
<div class="my-4 flex justify-center items-center">
|
|
44
44
|
<v-otp-input
|
|
45
45
|
ref="code"
|
|
46
|
-
input-classes="
|
|
46
|
+
input-classes="bg-gray-50 text-center flex justify-center otp-input border leading-none border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-10 h-10 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
|
|
47
47
|
:conditionalClass="['one', 'two', 'three', 'four', 'five', 'six']"
|
|
48
48
|
inputType="number"
|
|
49
49
|
:num-inputs="6"
|
|
@@ -52,21 +52,21 @@
|
|
|
52
52
|
@on-complete="handleOnComplete"
|
|
53
53
|
/>
|
|
54
54
|
</div>
|
|
55
|
-
|
|
56
55
|
<!-- <Vue2FACodeInput v-model="code" autofocus /> -->
|
|
57
|
-
<
|
|
56
|
+
<Button @click="()=>{router.push('./login')}"
|
|
57
|
+
class="w-full">Cancel
|
|
58
|
+
</Button>
|
|
58
59
|
</div>
|
|
59
60
|
</div>
|
|
60
61
|
</div>
|
|
61
62
|
</div>
|
|
62
|
-
|
|
63
|
-
</div>
|
|
63
|
+
</div>
|
|
64
64
|
|
|
65
65
|
|
|
66
66
|
</template>
|
|
67
67
|
|
|
68
68
|
|
|
69
|
-
<script setup>
|
|
69
|
+
<script setup lang="ts">
|
|
70
70
|
|
|
71
71
|
import { onMounted, onBeforeUnmount, ref, watchEffect,computed,watch } from 'vue';
|
|
72
72
|
import { useCoreStore } from '@/stores/core';
|
|
@@ -75,18 +75,16 @@ import { IconEyeSolid, IconEyeSlashSolid } from '@iconify-prerendered/vue-flowbi
|
|
|
75
75
|
import { callAdminForthApi, loadFile } from '@/utils';
|
|
76
76
|
import { useRouter } from 'vue-router';
|
|
77
77
|
import { showErrorTost } from '@/composables/useFrontendApi';
|
|
78
|
+
import { Button } from '@/afcl';
|
|
78
79
|
import Vue2FACodeInput from '@loltech/vue3-2fa-code-input';
|
|
79
80
|
import VOtpInput from "vue3-otp-input";
|
|
80
81
|
|
|
81
82
|
const code = ref(null);
|
|
83
|
+
const isCopied = ref<boolean>(false);
|
|
82
84
|
const handleOnComplete = (value) => {
|
|
83
85
|
sendCode(value);
|
|
84
86
|
};
|
|
85
87
|
|
|
86
|
-
const fillInput = (value) => {
|
|
87
|
-
code.value?.fillInput(value);
|
|
88
|
-
};
|
|
89
|
-
|
|
90
88
|
const router = useRouter();
|
|
91
89
|
const inProgress = ref(false);
|
|
92
90
|
|
|
@@ -95,9 +93,6 @@ const user = useUserStore();
|
|
|
95
93
|
|
|
96
94
|
// use this simple function to automatically focus on the next input
|
|
97
95
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
96
|
const showPw = ref(false);
|
|
102
97
|
|
|
103
98
|
const error = ref(null);
|
|
@@ -127,16 +122,11 @@ function parseJwt(token) {
|
|
|
127
122
|
}
|
|
128
123
|
|
|
129
124
|
function onCopyClick(){
|
|
125
|
+
isCopied.value = true;
|
|
126
|
+
navigator.clipboard.writeText(totp.value.newSecret);
|
|
130
127
|
window.adminforth.alert({message: 'Copied to clipboard', variant: 'success'})
|
|
131
128
|
}
|
|
132
129
|
|
|
133
|
-
// watch(code, async (nv)=>{
|
|
134
|
-
// if (nv){
|
|
135
|
-
// console.log(code.value);
|
|
136
|
-
// sendCode();
|
|
137
|
-
// }
|
|
138
|
-
// })
|
|
139
|
-
|
|
140
130
|
onMounted(async () => {
|
|
141
131
|
coreStore.getPublicConfig()
|
|
142
132
|
const resp = await callAdminForthApi({
|
|
@@ -149,11 +139,12 @@ onMounted(async () => {
|
|
|
149
139
|
|
|
150
140
|
totp.value=parseJwt(totpJWT.value);
|
|
151
141
|
|
|
152
|
-
|
|
142
|
+
|
|
143
|
+
window.addEventListener('paste', handlePaste);
|
|
153
144
|
});
|
|
154
145
|
|
|
155
146
|
onBeforeUnmount(() => {
|
|
156
|
-
window.removeEventListener('
|
|
147
|
+
window.removeEventListener('paste', handlePaste);
|
|
157
148
|
});
|
|
158
149
|
|
|
159
150
|
async function sendCode (value) {
|
|
@@ -176,22 +167,19 @@ async function sendCode (value) {
|
|
|
176
167
|
}
|
|
177
168
|
|
|
178
169
|
|
|
179
|
-
function
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
console.error('Failed to read clipboard contents: ', err);
|
|
188
|
-
});
|
|
170
|
+
function handlePaste(event) {
|
|
171
|
+
event.preventDefault();
|
|
172
|
+
if (event.target.classList.contains('otp-input')) {
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
const pastedText = event.clipboardData?.getData('text') || '';
|
|
176
|
+
if (pastedText.length === 6) {
|
|
177
|
+
code.value?.fillInput(pastedText);
|
|
189
178
|
}
|
|
190
179
|
}
|
|
191
180
|
</script>
|
|
192
181
|
<style>
|
|
193
182
|
.otp-input {
|
|
194
183
|
margin: 0 5px;
|
|
195
|
-
|
|
196
184
|
}
|
|
197
185
|
</style>
|
|
@@ -13,25 +13,22 @@
|
|
|
13
13
|
<!-- Modal content -->
|
|
14
14
|
<div class="relative bg-white rounded-lg shadow dark:bg-gray-700 dark:shadow-black text-gray-500" >
|
|
15
15
|
<div class="p-8 w-full max-w-md max-h-full" >
|
|
16
|
-
<div class="m-3"
|
|
16
|
+
<div class="m-3">Please enter your authenticator code </div>
|
|
17
17
|
<div class="my-4 flex justify-center items-center">
|
|
18
18
|
<v-otp-input
|
|
19
19
|
ref="code"
|
|
20
|
-
input-classes="
|
|
20
|
+
input-classes="bg-gray-50 text-center flex justify-center otp-input border leading-none border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-10 h-10 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
|
|
21
21
|
:conditionalClass="['one', 'two', 'three', 'four', 'five', 'six']"
|
|
22
22
|
inputType="number"
|
|
23
23
|
:num-inputs="6"
|
|
24
24
|
v-model:value="bindValue"
|
|
25
25
|
:should-auto-focus="true"
|
|
26
26
|
:should-focus-order="true"
|
|
27
|
-
@on-change="handleOnChange"
|
|
28
27
|
@on-complete="handleOnComplete"
|
|
29
28
|
/>
|
|
30
29
|
</div>
|
|
31
30
|
<!-- <Vue2FACodeInput v-model="code"/> -->
|
|
32
|
-
<
|
|
33
|
-
Cancel
|
|
34
|
-
</button>
|
|
31
|
+
<Button @click="() => {router.push('./login')}" class="w-full">Cancel</Button>
|
|
35
32
|
</div>
|
|
36
33
|
</div>
|
|
37
34
|
</div>
|
|
@@ -52,6 +49,7 @@
|
|
|
52
49
|
import { callAdminForthApi, loadFile } from '@/utils';
|
|
53
50
|
import { useRouter } from 'vue-router';
|
|
54
51
|
import { showErrorTost } from '@/composables/useFrontendApi';
|
|
52
|
+
import { Button } from '@/afcl';
|
|
55
53
|
import Vue2FACodeInput from '@loltech/vue3-2fa-code-input';
|
|
56
54
|
import VOtpInput from "vue3-otp-input";
|
|
57
55
|
|
|
@@ -99,13 +97,12 @@
|
|
|
99
97
|
|
|
100
98
|
onMounted(async () => {
|
|
101
99
|
coreStore.getPublicConfig();
|
|
102
|
-
window.addEventListener('
|
|
100
|
+
window.addEventListener('paste', handlePaste);
|
|
103
101
|
});
|
|
104
102
|
|
|
105
103
|
onBeforeUnmount(() => {
|
|
106
|
-
window.removeEventListener('
|
|
104
|
+
window.removeEventListener('paste', handlePaste);
|
|
107
105
|
});
|
|
108
|
-
|
|
109
106
|
|
|
110
107
|
async function sendCode (value) {
|
|
111
108
|
inProgress.value = true;
|
|
@@ -130,16 +127,14 @@
|
|
|
130
127
|
// }
|
|
131
128
|
// })
|
|
132
129
|
|
|
133
|
-
function
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
console.error('Failed to read clipboard contents: ', err);
|
|
142
|
-
});
|
|
130
|
+
function handlePaste(event) {
|
|
131
|
+
event.preventDefault();
|
|
132
|
+
if (event.target.classList.contains('otp-input')) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
const pastedText = event.clipboardData?.getData('text') || '';
|
|
136
|
+
if (pastedText.length === 6) {
|
|
137
|
+
code.value?.fillInput(pastedText);
|
|
143
138
|
}
|
|
144
139
|
}
|
|
145
140
|
</script>
|
|
@@ -22,15 +22,15 @@
|
|
|
22
22
|
<div class="w-full max-w-[46rem]">
|
|
23
23
|
<div class="relative">
|
|
24
24
|
<label for="npm-install-copy-text" class="sr-only">Label</label>
|
|
25
|
-
<input id="npm-install-copy-text" type="text" class="col-span-10 bg-gray-50 border border-gray-300 text-gray-500 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full px-2.5 py-4 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-gray-400 dark:focus:ring-blue-500 dark:focus:border-blue-500" :value="totp.newSecret"
|
|
26
|
-
<button data-copy-to-clipboard-target="npm-install-copy-text" class="absolute end-2.5 top-1/2 -translate-y-1/2 text-gray-900 dark:text-gray-400 hover:bg-gray-100 dark:bg-gray-800 dark:border-gray-600 dark:hover:bg-gray-700 rounded-lg py-2 px-2.5 inline-flex items-center justify-center bg-white border-gray-200 border">
|
|
27
|
-
<span id="default-message" class="inline-flex items-center">
|
|
25
|
+
<input id="npm-install-copy-text" type="text" class="col-span-10 bg-gray-50 border border-gray-300 text-gray-500 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full px-2.5 py-4 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-gray-400 dark:focus:ring-blue-500 dark:focus:border-blue-500 pr-20" :value="totp.newSecret" readonly>
|
|
26
|
+
<button @click="onCopyClick" data-copy-to-clipboard-target="npm-install-copy-text" class="absolute end-2.5 top-1/2 -translate-y-1/2 text-gray-900 dark:text-gray-400 hover:bg-gray-100 dark:bg-gray-800 dark:border-gray-600 dark:hover:bg-gray-700 rounded-lg py-2 px-2.5 inline-flex items-center justify-center bg-white border-gray-200 border">
|
|
27
|
+
<span v-if="isCopied === false" id="default-message" class="inline-flex items-center">
|
|
28
28
|
<svg class="w-3 h-3 me-1.5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 18 20">
|
|
29
29
|
<path d="M16 1h-3.278A1.992 1.992 0 0 0 11 0H7a1.993 1.993 0 0 0-1.722 1H2a2 2 0 0 0-2 2v15a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2Zm-3 14H5a1 1 0 0 1 0-2h8a1 1 0 0 1 0 2Zm0-4H5a1 1 0 0 1 0-2h8a1 1 0 1 1 0 2Zm0-5H5a1 1 0 0 1 0-2h2V2h4v2h2a1 1 0 1 1 0 2Z"/>
|
|
30
30
|
</svg>
|
|
31
|
-
<span
|
|
31
|
+
<span class="text-xs font-semibold">Copy</span>
|
|
32
32
|
</span>
|
|
33
|
-
<span id="success-message" class="
|
|
33
|
+
<span v-if="isCopied === true" id="success-message" class="inline-flex items-center">
|
|
34
34
|
<svg class="w-3 h-3 text-lightPrimary dark:text-darkPrimary me-1.5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 16 12">
|
|
35
35
|
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M1 5.917 5.724 10.5 15 1.5"/>
|
|
36
36
|
</svg>
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
<div class="my-4 flex justify-center items-center">
|
|
44
44
|
<v-otp-input
|
|
45
45
|
ref="code"
|
|
46
|
-
input-classes="
|
|
46
|
+
input-classes="bg-gray-50 text-center flex justify-center otp-input border leading-none border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-10 h-10 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
|
|
47
47
|
:conditionalClass="['one', 'two', 'three', 'four', 'five', 'six']"
|
|
48
48
|
inputType="number"
|
|
49
49
|
:num-inputs="6"
|
|
@@ -52,21 +52,21 @@
|
|
|
52
52
|
@on-complete="handleOnComplete"
|
|
53
53
|
/>
|
|
54
54
|
</div>
|
|
55
|
-
|
|
56
55
|
<!-- <Vue2FACodeInput v-model="code" autofocus /> -->
|
|
57
|
-
<
|
|
56
|
+
<Button @click="()=>{router.push('./login')}"
|
|
57
|
+
class="w-full">Cancel
|
|
58
|
+
</Button>
|
|
58
59
|
</div>
|
|
59
60
|
</div>
|
|
60
61
|
</div>
|
|
61
62
|
</div>
|
|
62
|
-
|
|
63
|
-
</div>
|
|
63
|
+
</div>
|
|
64
64
|
|
|
65
65
|
|
|
66
66
|
</template>
|
|
67
67
|
|
|
68
68
|
|
|
69
|
-
<script setup>
|
|
69
|
+
<script setup lang="ts">
|
|
70
70
|
|
|
71
71
|
import { onMounted, onBeforeUnmount, ref, watchEffect,computed,watch } from 'vue';
|
|
72
72
|
import { useCoreStore } from '@/stores/core';
|
|
@@ -75,18 +75,16 @@ import { IconEyeSolid, IconEyeSlashSolid } from '@iconify-prerendered/vue-flowbi
|
|
|
75
75
|
import { callAdminForthApi, loadFile } from '@/utils';
|
|
76
76
|
import { useRouter } from 'vue-router';
|
|
77
77
|
import { showErrorTost } from '@/composables/useFrontendApi';
|
|
78
|
+
import { Button } from '@/afcl';
|
|
78
79
|
import Vue2FACodeInput from '@loltech/vue3-2fa-code-input';
|
|
79
80
|
import VOtpInput from "vue3-otp-input";
|
|
80
81
|
|
|
81
82
|
const code = ref(null);
|
|
83
|
+
const isCopied = ref<boolean>(false);
|
|
82
84
|
const handleOnComplete = (value) => {
|
|
83
85
|
sendCode(value);
|
|
84
86
|
};
|
|
85
87
|
|
|
86
|
-
const fillInput = (value) => {
|
|
87
|
-
code.value?.fillInput(value);
|
|
88
|
-
};
|
|
89
|
-
|
|
90
88
|
const router = useRouter();
|
|
91
89
|
const inProgress = ref(false);
|
|
92
90
|
|
|
@@ -95,9 +93,6 @@ const user = useUserStore();
|
|
|
95
93
|
|
|
96
94
|
// use this simple function to automatically focus on the next input
|
|
97
95
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
96
|
const showPw = ref(false);
|
|
102
97
|
|
|
103
98
|
const error = ref(null);
|
|
@@ -127,16 +122,11 @@ function parseJwt(token) {
|
|
|
127
122
|
}
|
|
128
123
|
|
|
129
124
|
function onCopyClick(){
|
|
125
|
+
isCopied.value = true;
|
|
126
|
+
navigator.clipboard.writeText(totp.value.newSecret);
|
|
130
127
|
window.adminforth.alert({message: 'Copied to clipboard', variant: 'success'})
|
|
131
128
|
}
|
|
132
129
|
|
|
133
|
-
// watch(code, async (nv)=>{
|
|
134
|
-
// if (nv){
|
|
135
|
-
// console.log(code.value);
|
|
136
|
-
// sendCode();
|
|
137
|
-
// }
|
|
138
|
-
// })
|
|
139
|
-
|
|
140
130
|
onMounted(async () => {
|
|
141
131
|
coreStore.getPublicConfig()
|
|
142
132
|
const resp = await callAdminForthApi({
|
|
@@ -149,11 +139,12 @@ onMounted(async () => {
|
|
|
149
139
|
|
|
150
140
|
totp.value=parseJwt(totpJWT.value);
|
|
151
141
|
|
|
152
|
-
|
|
142
|
+
|
|
143
|
+
window.addEventListener('paste', handlePaste);
|
|
153
144
|
});
|
|
154
145
|
|
|
155
146
|
onBeforeUnmount(() => {
|
|
156
|
-
window.removeEventListener('
|
|
147
|
+
window.removeEventListener('paste', handlePaste);
|
|
157
148
|
});
|
|
158
149
|
|
|
159
150
|
async function sendCode (value) {
|
|
@@ -176,22 +167,19 @@ async function sendCode (value) {
|
|
|
176
167
|
}
|
|
177
168
|
|
|
178
169
|
|
|
179
|
-
function
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
console.error('Failed to read clipboard contents: ', err);
|
|
188
|
-
});
|
|
170
|
+
function handlePaste(event) {
|
|
171
|
+
event.preventDefault();
|
|
172
|
+
if (event.target.classList.contains('otp-input')) {
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
const pastedText = event.clipboardData?.getData('text') || '';
|
|
176
|
+
if (pastedText.length === 6) {
|
|
177
|
+
code.value?.fillInput(pastedText);
|
|
189
178
|
}
|
|
190
179
|
}
|
|
191
180
|
</script>
|
|
192
181
|
<style>
|
|
193
182
|
.otp-input {
|
|
194
183
|
margin: 0 5px;
|
|
195
|
-
|
|
196
184
|
}
|
|
197
185
|
</style>
|
package/package.json
CHANGED
package/custom/TwoFactorsOtp.vue
DELETED
|
File without changes
|
|
File without changes
|