@adminforth/two-factors-auth 3.1.5 → 3.2.0
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/build.log +2 -2
- package/custom/TwoFAModal.vue +74 -49
- package/custom/TwoFactorsPasskeysSettings.vue +237 -333
- package/dist/custom/TwoFAModal.vue +74 -49
- package/dist/custom/TwoFactorsPasskeysSettings.vue +237 -333
- package/dist/index.js +1 -1
- package/index.ts +2 -2
- package/package.json +1 -1
|
@@ -1,46 +1,53 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="af-two-factors-modal fixed inset-0 z-[9999] flex items-center justify-center bg-black/50 top-0 bottom-0 left-0 right-0"
|
|
3
3
|
v-show ="modelShow && (isLoading === false)">
|
|
4
|
-
<div v-if="modalMode === 'totp'" class="af-two-factor-modal-totp flex flex-col
|
|
5
|
-
<
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
inputmode="numeric"
|
|
20
|
-
:should-auto-focus="true"
|
|
21
|
-
:should-focus-order="true"
|
|
22
|
-
v-model:value="bindValue"
|
|
23
|
-
@on-complete="handleOnComplete"
|
|
24
|
-
/>
|
|
4
|
+
<div v-if="modalMode === 'totp'" class="af-two-factor-modal-totp flex flex-col gap-4 relative bg-white dark:bg-gray-700 rounded-lg shadow p-6 w-full max-w-md">
|
|
5
|
+
<button
|
|
6
|
+
type="button"
|
|
7
|
+
class="af-2fa-close-btn text-lightDialogCloseButton bg-transparent hover:bg-lightDialogCloseButtonHoverBackground hover:text-lightDialogCloseButtonHover rounded-lg text-sm w-8 h-8 ms-auto inline-flex justify-center items-center dark:text-darkDialogCloseButton dark:hover:bg-darkDialogCloseButtonHoverBackground dark:hover:text-darkDialogCloseButtonHover"
|
|
8
|
+
@click="onCancel"
|
|
9
|
+
>
|
|
10
|
+
<svg class="w-3 h-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 14">
|
|
11
|
+
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6"/>
|
|
12
|
+
</svg>
|
|
13
|
+
<span class="sr-only">{{$t('Close modal')}}</span>
|
|
14
|
+
</button>
|
|
15
|
+
|
|
16
|
+
<div class="af-2fa-totp-header flex flex-col items-center justify-center gap-3">
|
|
17
|
+
<div class="af-2fa-icon-wrap w-14 h-14 shrink-0 flex items-center justify-center rounded-full bg-lightPrimary dark:bg-darkPrimary">
|
|
18
|
+
<IconShieldOutline class="af-2fa-shield-icon w-7 h-7 text-white" />
|
|
25
19
|
</div>
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
<p
|
|
29
|
-
<Button
|
|
30
|
-
class="px-4 py-2 rounded border"
|
|
31
|
-
@click="onCancel"
|
|
32
|
-
:disabled="inProgress"
|
|
33
|
-
>{{ $t('Cancel') }}</Button>
|
|
20
|
+
<div id="mfaCode-label" class="af-2fa-totp-title-wrap">
|
|
21
|
+
<p v-if="customDialogTitle" class="af-2fa-custom-title text-xl text-center font-medium text-gray-900 dark:text-white">{{ customDialogTitle }}</p>
|
|
22
|
+
<p class="af-2fa-totp-subtitle text-xs text-center text-gray-500 dark:text-gray-400 mt-1">{{ $t('Please enter your authenticator code') }}</p>
|
|
34
23
|
</div>
|
|
35
24
|
</div>
|
|
36
|
-
</div>
|
|
37
|
-
|
|
38
25
|
|
|
26
|
+
<div class="af-2fa-otp-root flex justify-center" ref="otpRoot">
|
|
27
|
+
<v-otp-input
|
|
28
|
+
ref="confirmationResult"
|
|
29
|
+
container-class="grid grid-cols-6 gap-3"
|
|
30
|
+
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-600 dark:border-gray-500 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
|
|
31
|
+
:num-inputs="6"
|
|
32
|
+
inputType="number"
|
|
33
|
+
inputmode="numeric"
|
|
34
|
+
:should-auto-focus="true"
|
|
35
|
+
:should-focus-order="true"
|
|
36
|
+
v-model:value="bindValue"
|
|
37
|
+
@on-complete="handleOnComplete"
|
|
38
|
+
/>
|
|
39
|
+
</div>
|
|
40
|
+
<p v-if="doesUserHavePasskeys" class="af-2fa-totp-footer text-center text-xs text-gray-500 dark:text-gray-400">
|
|
41
|
+
{{$t('Having trouble?')}}
|
|
42
|
+
<button type="button" class="af-2fa-switch-to-passkey text-lightPrimary dark:text-white hover:underline cursor-pointer" @click="modalMode = 'passkey'">{{$t('Use passkey instead')}}</button>
|
|
43
|
+
</p>
|
|
44
|
+
<p class="af-2fa-multiple-actions text-center text-red-500 text-xs" v-if="sessionsIdsToResolve.length > 1"> You are confirming {{ sessionsIdsToResolve.length }} actions</p>
|
|
45
|
+
</div>
|
|
39
46
|
|
|
40
|
-
<div v-else-if="modalMode === 'passkey'" class="af-two-factor-modal-passkeys flex flex-col
|
|
47
|
+
<div v-else-if="modalMode === 'passkey'" class="af-two-factor-modal-passkeys flex flex-col gap-4 relative bg-white dark:bg-gray-700 rounded-lg shadow p-6 w-full max-w-md">
|
|
41
48
|
<button
|
|
42
49
|
type="button"
|
|
43
|
-
class="text-lightDialogCloseButton bg-transparent hover:bg-lightDialogCloseButtonHoverBackground hover:text-lightDialogCloseButtonHover rounded-lg text-sm w-8 h-8 ms-auto inline-flex justify-center items-center dark:text-darkDialogCloseButton dark:hover:bg-darkDialogCloseButtonHoverBackground dark:hover:text-darkDialogCloseButtonHover"
|
|
50
|
+
class="af-2fa-close-btn text-lightDialogCloseButton bg-transparent hover:bg-lightDialogCloseButtonHoverBackground hover:text-lightDialogCloseButtonHover rounded-lg text-sm w-8 h-8 ms-auto inline-flex justify-center items-center dark:text-darkDialogCloseButton dark:hover:bg-darkDialogCloseButtonHoverBackground dark:hover:text-darkDialogCloseButtonHover"
|
|
44
51
|
@click="onCancel"
|
|
45
52
|
>
|
|
46
53
|
<svg class="w-3 h-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 14">
|
|
@@ -48,25 +55,41 @@
|
|
|
48
55
|
</svg>
|
|
49
56
|
<span class="sr-only">{{$t('Close modal')}}</span>
|
|
50
57
|
</button>
|
|
51
|
-
|
|
52
|
-
<
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
<
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
{{$t('Use passkey')}}
|
|
60
|
-
</Button>
|
|
61
|
-
<div v-if="modalMode === 'passkey'" class="af-2fa-passkey-issues-card max-w-sm px-6 pt-3 w-full bg-white border border-gray-200 rounded-lg shadow-sm dark:bg-gray-800 dark:border-gray-700">
|
|
62
|
-
<div class="mb-3 font-normal text-gray-700 dark:text-gray-400">
|
|
63
|
-
<p>{{$t('Have issues with passkey?')}}</p>
|
|
64
|
-
<p class="underline hover:no-underline text-lightPrimary whitespace-nowrap hover:cursor-pointer" @click="modalMode = 'totp'" >{{$t('use TOTP')}}</p>
|
|
58
|
+
|
|
59
|
+
<div class="af-2fa-passkey-header flex flex-col items-center justify-center gap-3">
|
|
60
|
+
<div class="af-2fa-icon-wrap w-14 h-14 shrink-0 flex items-center justify-center rounded-full bg-lightPrimary dark:bg-darkPrimary">
|
|
61
|
+
<IconShieldOutline class="af-2fa-shield-icon w-7 h-7 text-white" />
|
|
62
|
+
</div>
|
|
63
|
+
<div class="af-2fa-passkey-title-wrap">
|
|
64
|
+
<p class="af-2fa-passkey-title text-xl text-center font-medium text-gray-900 dark:text-white">{{$t('Verify to add passkey')}}</p>
|
|
65
|
+
<p class="af-2fa-passkey-subtitle text-xs text-center text-gray-500 dark:text-gray-400 mt-1">{{$t("Confirm it's you before registering a new passkey on this device.")}}</p>
|
|
65
66
|
</div>
|
|
66
67
|
</div>
|
|
67
68
|
|
|
69
|
+
<div class="af-2fa-passkey-steps flex flex-col gap-2 mt-2">
|
|
70
|
+
<div
|
|
71
|
+
v-for="(step, i) in [
|
|
72
|
+
$t('Click the button below to begin'),
|
|
73
|
+
$t('Authenticate with your device biometrics or PIN'),
|
|
74
|
+
$t('Your passkey will be saved automatically'),
|
|
75
|
+
]"
|
|
76
|
+
:key="i"
|
|
77
|
+
class="af-2fa-passkey-step flex items-center gap-2.5 px-3 py-2 rounded-lg bg-gray-50 dark:bg-gray-600/50 text-xs text-gray-600 dark:text-gray-300"
|
|
78
|
+
>
|
|
79
|
+
<span class="af-2fa-step-number shrink-0 w-5 h-5 flex items-center justify-center rounded-full bg-lightPrimary dark:bg-darkPrimary text-white font-semibold text-xs">{{ i + 1 }}</span>
|
|
80
|
+
{{ step }}
|
|
81
|
+
</div>
|
|
82
|
+
</div>
|
|
68
83
|
|
|
69
|
-
|
|
84
|
+
<Button @click="usePasskeyButtonClick" :disabled="isFetchingPasskey" :loader="isFetchingPasskey" class="af-2fa-passkey-btn w-full flex items-center justify-center gap-2 mt-2">
|
|
85
|
+
<IconShieldOutline class="w-4 h-4" />
|
|
86
|
+
{{$t('Use passkey to verify')}}
|
|
87
|
+
</Button>
|
|
88
|
+
<p class="af-2fa-passkey-footer text-center text-xs text-gray-500 dark:text-gray-400">
|
|
89
|
+
{{$t('Having trouble?')}}
|
|
90
|
+
<button type="button" class="af-2fa-switch-to-totp text-lightPrimary dark:text-white hover:underline cursor-pointer" @click="modalMode = 'totp'">{{$t('Use TOTP instead')}}</button>
|
|
91
|
+
</p>
|
|
92
|
+
<p class="af-2fa-multiple-actions text-center text-red-500 text-xs" v-if="sessionsIdsToResolve.length > 1"> You are confirming {{ sessionsIdsToResolve.length }} actions</p>
|
|
70
93
|
</div>
|
|
71
94
|
</div>
|
|
72
95
|
</template>
|
|
@@ -85,13 +108,15 @@
|
|
|
85
108
|
import websocket from '@/websocket';
|
|
86
109
|
import type { AdminUser } from '@/types/Common';
|
|
87
110
|
|
|
111
|
+
type TwoFaConfirmationResult = { mode: 'totp'; result: string } | { mode: 'passkey'; result: Record<string, any> };
|
|
112
|
+
|
|
88
113
|
declare global {
|
|
89
114
|
interface Window {
|
|
90
115
|
adminforthTwoFaModal: {
|
|
91
116
|
get2FaConfirmationResult: (
|
|
92
117
|
title?: string,
|
|
93
118
|
verifyingCallback?: (confirmationResult: string) => Promise<boolean>
|
|
94
|
-
) => Promise<
|
|
119
|
+
) => Promise<TwoFaConfirmationResult>;
|
|
95
120
|
};
|
|
96
121
|
}
|
|
97
122
|
}
|