@adminforth/two-factors-auth 2.0.6 → 2.1.1
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 +88 -6
- package/custom/TwoFactorsConfirmation.vue +0 -13
- package/custom/TwoFactorsPasskeysSettings.vue +1 -0
- package/dist/custom/TwoFAModal.vue +88 -6
- package/dist/custom/TwoFactorsConfirmation.vue +0 -13
- package/dist/custom/TwoFactorsPasskeysSettings.vue +1 -0
- package/dist/index.js +0 -6
- package/index.ts +0 -6
- package/package.json +1 -1
package/build.log
CHANGED
|
@@ -13,5 +13,5 @@ custom/package.json
|
|
|
13
13
|
custom/tsconfig.json
|
|
14
14
|
custom/utils.js
|
|
15
15
|
|
|
16
|
-
sent
|
|
17
|
-
total size is
|
|
16
|
+
sent 71,446 bytes received 172 bytes 143,236.00 bytes/sec
|
|
17
|
+
total size is 70,806 speedup is 0.99
|
package/custom/TwoFAModal.vue
CHANGED
|
@@ -24,11 +24,11 @@
|
|
|
24
24
|
|
|
25
25
|
<div class="mt-6 flex justify-center items-center gap-32 w-full">
|
|
26
26
|
<p v-if="doesUserHavePasskeys===true" class="underline hover:no-underline text-lightPrimary whitespace-nowrap hover:cursor-pointer" @click="modalMode = 'passkey'" >use passkey</p>
|
|
27
|
-
<
|
|
28
|
-
class="px-4 py-2 rounded border
|
|
27
|
+
<Button
|
|
28
|
+
class="px-4 py-2 rounded border"
|
|
29
29
|
@click="onCancel"
|
|
30
30
|
:disabled="inProgress"
|
|
31
|
-
>{{ $t('Cancel') }}</
|
|
31
|
+
>{{ $t('Cancel') }}</Button>
|
|
32
32
|
</div>
|
|
33
33
|
</div>
|
|
34
34
|
|
|
@@ -97,6 +97,25 @@
|
|
|
97
97
|
(e: 'closed'): void
|
|
98
98
|
}>();
|
|
99
99
|
|
|
100
|
+
function removeListeners() {
|
|
101
|
+
window.removeEventListener('paste', handlePaste);
|
|
102
|
+
document.removeEventListener('focusin', handleGlobalFocusIn, true);
|
|
103
|
+
const rootEl = otpRoot.value;
|
|
104
|
+
rootEl && rootEl.removeEventListener('focusout', handleFocusOut, true);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
async function addListeners() {
|
|
108
|
+
document.addEventListener('focusin', handleGlobalFocusIn, true);
|
|
109
|
+
|
|
110
|
+
// Wait for DOM to be ready and OTP inputs to be rendered
|
|
111
|
+
await nextTick();
|
|
112
|
+
await new Promise(resolve => setTimeout(resolve, 100)); // Small delay for v-otp-input to render
|
|
113
|
+
|
|
114
|
+
focusFirstAvailableOtpInput();
|
|
115
|
+
const rootEl = otpRoot.value;
|
|
116
|
+
rootEl && rootEl.addEventListener('focusout', handleFocusOut, true);
|
|
117
|
+
}
|
|
118
|
+
|
|
100
119
|
const modelShow = ref(false);
|
|
101
120
|
let resolveFn: ((confirmationResult: string) => void) | null = null;
|
|
102
121
|
let verifyingCallback: ((confirmationResult: string) => boolean) | null = null;
|
|
@@ -113,6 +132,7 @@
|
|
|
113
132
|
customDialogTitle.value = title;
|
|
114
133
|
}
|
|
115
134
|
modelShow.value = true;
|
|
135
|
+
await addListeners();
|
|
116
136
|
resolveFn = resolve;
|
|
117
137
|
rejectFn = reject;
|
|
118
138
|
verifyFn = verifyingCallback ?? null;
|
|
@@ -144,6 +164,7 @@
|
|
|
144
164
|
result: passkeyData
|
|
145
165
|
}
|
|
146
166
|
customDialogTitle.value = "";
|
|
167
|
+
removeListeners();
|
|
147
168
|
resolveFn(dataToReturn);
|
|
148
169
|
}
|
|
149
170
|
|
|
@@ -195,6 +216,7 @@
|
|
|
195
216
|
result: value
|
|
196
217
|
}
|
|
197
218
|
customDialogTitle.value = "";
|
|
219
|
+
removeListeners();
|
|
198
220
|
resolveFn(dataToReturn);
|
|
199
221
|
}
|
|
200
222
|
|
|
@@ -203,11 +225,22 @@
|
|
|
203
225
|
modelShow.value = false;
|
|
204
226
|
bindValue.value = '';
|
|
205
227
|
confirmationResult.value?.clearInput();
|
|
228
|
+
removeListeners();
|
|
206
229
|
rejectFn("Cancel");
|
|
207
230
|
emit('rejected', new Error('cancelled'));
|
|
208
231
|
emit('closed');
|
|
209
232
|
}
|
|
210
233
|
|
|
234
|
+
watch(modalMode, async (newMode) => {
|
|
235
|
+
if (newMode === 'totp' && modelShow.value && !isLoading.value) {
|
|
236
|
+
await nextTick();
|
|
237
|
+
setTimeout(() => {
|
|
238
|
+
tagOtpInputs();
|
|
239
|
+
focusFirstAvailableOtpInput();
|
|
240
|
+
}, 100);
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
|
|
211
244
|
watch(modelShow, async (open) => {
|
|
212
245
|
if (open) {
|
|
213
246
|
await nextTick();
|
|
@@ -215,8 +248,17 @@
|
|
|
215
248
|
if (htmlRef) {
|
|
216
249
|
htmlRef.style.overflow = 'hidden';
|
|
217
250
|
}
|
|
218
|
-
|
|
219
|
-
|
|
251
|
+
|
|
252
|
+
// Wait for conditional rendering to complete
|
|
253
|
+
if (modalMode.value === 'totp' && !isLoading.value) {
|
|
254
|
+
await nextTick();
|
|
255
|
+
setTimeout(() => {
|
|
256
|
+
tagOtpInputs();
|
|
257
|
+
window.addEventListener('paste', handlePaste);
|
|
258
|
+
}, 100);
|
|
259
|
+
} else {
|
|
260
|
+
window.addEventListener('paste', handlePaste);
|
|
261
|
+
}
|
|
220
262
|
} else {
|
|
221
263
|
window.removeEventListener('paste', handlePaste);
|
|
222
264
|
const htmlRef = document.querySelector('html');
|
|
@@ -248,7 +290,47 @@
|
|
|
248
290
|
});
|
|
249
291
|
}
|
|
250
292
|
|
|
251
|
-
|
|
293
|
+
function getOtpInputs() {
|
|
294
|
+
const root = otpRoot.value;
|
|
295
|
+
if (!root) return [];
|
|
296
|
+
return Array.from(root.querySelectorAll('input.otp-input'));
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
function focusFirstAvailableOtpInput() {
|
|
300
|
+
const inputs = getOtpInputs();
|
|
301
|
+
if (!inputs.length) {
|
|
302
|
+
// Retry after a short delay if inputs aren't ready yet
|
|
303
|
+
setTimeout(() => focusFirstAvailableOtpInput(), 50);
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
const firstEmpty = inputs.find((i) => !(i as HTMLInputElement).value);
|
|
307
|
+
((firstEmpty || inputs[0]) as HTMLInputElement).focus();
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
function handleGlobalFocusIn(event) {
|
|
311
|
+
const inputs = getOtpInputs();
|
|
312
|
+
if (!inputs.length) return;
|
|
313
|
+
const target = event.target;
|
|
314
|
+
if (!target) return;
|
|
315
|
+
if (!inputs.includes(target)) {
|
|
316
|
+
requestAnimationFrame(() => {
|
|
317
|
+
focusFirstAvailableOtpInput();
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
function handleFocusOut() {
|
|
323
|
+
requestAnimationFrame(() => {
|
|
324
|
+
const inputs = getOtpInputs();
|
|
325
|
+
if (!inputs.length) return;
|
|
326
|
+
const active = document.activeElement;
|
|
327
|
+
if (!active || !inputs.includes(active)) {
|
|
328
|
+
focusFirstAvailableOtpInput();
|
|
329
|
+
}
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
</script>
|
|
252
334
|
|
|
253
335
|
<style scoped>
|
|
254
336
|
:deep(.otp-input-container) {
|
|
@@ -150,11 +150,8 @@
|
|
|
150
150
|
await nextTick();
|
|
151
151
|
await isCMAAvailable();
|
|
152
152
|
tagOtpInputs();
|
|
153
|
-
console.log("Checking if device supports passkeys:", isPasskeysSupported.value);
|
|
154
153
|
if (isPasskeysSupported.value === true) {
|
|
155
|
-
console.log("Device supports passkeys, checking if user has passkeys...");
|
|
156
154
|
await checkIfUserHasPasskeys();
|
|
157
|
-
console.log("Does user have passkeys:", doesUserHavePasskeys.value);
|
|
158
155
|
}
|
|
159
156
|
document.addEventListener('focusin', handleGlobalFocusIn, true);
|
|
160
157
|
focusFirstAvailableOtpInput();
|
|
@@ -193,8 +190,6 @@
|
|
|
193
190
|
async function sendCode (value: any, factorMode: 'TOTP' | 'passkey', passkeyOptions: any) {
|
|
194
191
|
inProgress.value = true;
|
|
195
192
|
const usePasskey = factorMode === 'passkey';
|
|
196
|
-
console.log("Sending code with factorMode:", factorMode);
|
|
197
|
-
console.log("Passkey options:", passkeyOptions);
|
|
198
193
|
const resp = await callAdminForthApi({
|
|
199
194
|
method: 'POST',
|
|
200
195
|
path: '/plugin/twofa/confirmLogin',
|
|
@@ -205,15 +200,12 @@
|
|
|
205
200
|
secret: null,
|
|
206
201
|
}
|
|
207
202
|
})
|
|
208
|
-
console.log("Response from confirmLogin:", resp);
|
|
209
203
|
if ( resp.allowedLogin ) {
|
|
210
204
|
if ( route.meta.isPasskeysEnabled && !doesUserHavePasskeys.value ) {
|
|
211
205
|
handlePasskeyAlert(route.meta.suggestionPeriod, router);
|
|
212
206
|
}
|
|
213
|
-
console.log("Login confirmed, finishing login...");
|
|
214
207
|
await user.finishLogin();
|
|
215
208
|
} else {
|
|
216
|
-
console.log("Login not allowed, showing error:", resp.error);
|
|
217
209
|
if (usePasskey) {
|
|
218
210
|
showErrorTost(t(resp.error));
|
|
219
211
|
codeError.value = resp.error || t('Passkey authentication failed');
|
|
@@ -277,18 +269,15 @@
|
|
|
277
269
|
|
|
278
270
|
async function createSignInRequest() {
|
|
279
271
|
let response;
|
|
280
|
-
console.log("Creating sign-in request for passkey...");
|
|
281
272
|
try {
|
|
282
273
|
response = await callAdminForthApi({
|
|
283
274
|
path: `/plugin/passkeys/signInRequest`,
|
|
284
275
|
method: 'POST',
|
|
285
276
|
});
|
|
286
277
|
} catch (error) {
|
|
287
|
-
console.log("Error creating sign-in request:", error);
|
|
288
278
|
console.error('Error creating sign-in request:', error);
|
|
289
279
|
return;
|
|
290
280
|
}
|
|
291
|
-
console.log("Sign-in request response:", response);
|
|
292
281
|
if (response.ok === true) {
|
|
293
282
|
return { _options: response.data, challengeId: response.challengeId };
|
|
294
283
|
} else {
|
|
@@ -298,14 +287,12 @@
|
|
|
298
287
|
}
|
|
299
288
|
|
|
300
289
|
async function authenticate(options) {
|
|
301
|
-
console.log("Authenticating with options:", options);
|
|
302
290
|
try {
|
|
303
291
|
const abortController = new AbortController();
|
|
304
292
|
const credential = await navigator.credentials.get({
|
|
305
293
|
publicKey: options,
|
|
306
294
|
signal: abortController.signal,
|
|
307
295
|
});
|
|
308
|
-
console.log("Credential obtained:", credential);
|
|
309
296
|
return credential;
|
|
310
297
|
} catch (error) {
|
|
311
298
|
console.error('Error during authentication:', error);
|
|
@@ -24,11 +24,11 @@
|
|
|
24
24
|
|
|
25
25
|
<div class="mt-6 flex justify-center items-center gap-32 w-full">
|
|
26
26
|
<p v-if="doesUserHavePasskeys===true" class="underline hover:no-underline text-lightPrimary whitespace-nowrap hover:cursor-pointer" @click="modalMode = 'passkey'" >use passkey</p>
|
|
27
|
-
<
|
|
28
|
-
class="px-4 py-2 rounded border
|
|
27
|
+
<Button
|
|
28
|
+
class="px-4 py-2 rounded border"
|
|
29
29
|
@click="onCancel"
|
|
30
30
|
:disabled="inProgress"
|
|
31
|
-
>{{ $t('Cancel') }}</
|
|
31
|
+
>{{ $t('Cancel') }}</Button>
|
|
32
32
|
</div>
|
|
33
33
|
</div>
|
|
34
34
|
|
|
@@ -97,6 +97,25 @@
|
|
|
97
97
|
(e: 'closed'): void
|
|
98
98
|
}>();
|
|
99
99
|
|
|
100
|
+
function removeListeners() {
|
|
101
|
+
window.removeEventListener('paste', handlePaste);
|
|
102
|
+
document.removeEventListener('focusin', handleGlobalFocusIn, true);
|
|
103
|
+
const rootEl = otpRoot.value;
|
|
104
|
+
rootEl && rootEl.removeEventListener('focusout', handleFocusOut, true);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
async function addListeners() {
|
|
108
|
+
document.addEventListener('focusin', handleGlobalFocusIn, true);
|
|
109
|
+
|
|
110
|
+
// Wait for DOM to be ready and OTP inputs to be rendered
|
|
111
|
+
await nextTick();
|
|
112
|
+
await new Promise(resolve => setTimeout(resolve, 100)); // Small delay for v-otp-input to render
|
|
113
|
+
|
|
114
|
+
focusFirstAvailableOtpInput();
|
|
115
|
+
const rootEl = otpRoot.value;
|
|
116
|
+
rootEl && rootEl.addEventListener('focusout', handleFocusOut, true);
|
|
117
|
+
}
|
|
118
|
+
|
|
100
119
|
const modelShow = ref(false);
|
|
101
120
|
let resolveFn: ((confirmationResult: string) => void) | null = null;
|
|
102
121
|
let verifyingCallback: ((confirmationResult: string) => boolean) | null = null;
|
|
@@ -113,6 +132,7 @@
|
|
|
113
132
|
customDialogTitle.value = title;
|
|
114
133
|
}
|
|
115
134
|
modelShow.value = true;
|
|
135
|
+
await addListeners();
|
|
116
136
|
resolveFn = resolve;
|
|
117
137
|
rejectFn = reject;
|
|
118
138
|
verifyFn = verifyingCallback ?? null;
|
|
@@ -144,6 +164,7 @@
|
|
|
144
164
|
result: passkeyData
|
|
145
165
|
}
|
|
146
166
|
customDialogTitle.value = "";
|
|
167
|
+
removeListeners();
|
|
147
168
|
resolveFn(dataToReturn);
|
|
148
169
|
}
|
|
149
170
|
|
|
@@ -195,6 +216,7 @@
|
|
|
195
216
|
result: value
|
|
196
217
|
}
|
|
197
218
|
customDialogTitle.value = "";
|
|
219
|
+
removeListeners();
|
|
198
220
|
resolveFn(dataToReturn);
|
|
199
221
|
}
|
|
200
222
|
|
|
@@ -203,11 +225,22 @@
|
|
|
203
225
|
modelShow.value = false;
|
|
204
226
|
bindValue.value = '';
|
|
205
227
|
confirmationResult.value?.clearInput();
|
|
228
|
+
removeListeners();
|
|
206
229
|
rejectFn("Cancel");
|
|
207
230
|
emit('rejected', new Error('cancelled'));
|
|
208
231
|
emit('closed');
|
|
209
232
|
}
|
|
210
233
|
|
|
234
|
+
watch(modalMode, async (newMode) => {
|
|
235
|
+
if (newMode === 'totp' && modelShow.value && !isLoading.value) {
|
|
236
|
+
await nextTick();
|
|
237
|
+
setTimeout(() => {
|
|
238
|
+
tagOtpInputs();
|
|
239
|
+
focusFirstAvailableOtpInput();
|
|
240
|
+
}, 100);
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
|
|
211
244
|
watch(modelShow, async (open) => {
|
|
212
245
|
if (open) {
|
|
213
246
|
await nextTick();
|
|
@@ -215,8 +248,17 @@
|
|
|
215
248
|
if (htmlRef) {
|
|
216
249
|
htmlRef.style.overflow = 'hidden';
|
|
217
250
|
}
|
|
218
|
-
|
|
219
|
-
|
|
251
|
+
|
|
252
|
+
// Wait for conditional rendering to complete
|
|
253
|
+
if (modalMode.value === 'totp' && !isLoading.value) {
|
|
254
|
+
await nextTick();
|
|
255
|
+
setTimeout(() => {
|
|
256
|
+
tagOtpInputs();
|
|
257
|
+
window.addEventListener('paste', handlePaste);
|
|
258
|
+
}, 100);
|
|
259
|
+
} else {
|
|
260
|
+
window.addEventListener('paste', handlePaste);
|
|
261
|
+
}
|
|
220
262
|
} else {
|
|
221
263
|
window.removeEventListener('paste', handlePaste);
|
|
222
264
|
const htmlRef = document.querySelector('html');
|
|
@@ -248,7 +290,47 @@
|
|
|
248
290
|
});
|
|
249
291
|
}
|
|
250
292
|
|
|
251
|
-
|
|
293
|
+
function getOtpInputs() {
|
|
294
|
+
const root = otpRoot.value;
|
|
295
|
+
if (!root) return [];
|
|
296
|
+
return Array.from(root.querySelectorAll('input.otp-input'));
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
function focusFirstAvailableOtpInput() {
|
|
300
|
+
const inputs = getOtpInputs();
|
|
301
|
+
if (!inputs.length) {
|
|
302
|
+
// Retry after a short delay if inputs aren't ready yet
|
|
303
|
+
setTimeout(() => focusFirstAvailableOtpInput(), 50);
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
const firstEmpty = inputs.find((i) => !(i as HTMLInputElement).value);
|
|
307
|
+
((firstEmpty || inputs[0]) as HTMLInputElement).focus();
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
function handleGlobalFocusIn(event) {
|
|
311
|
+
const inputs = getOtpInputs();
|
|
312
|
+
if (!inputs.length) return;
|
|
313
|
+
const target = event.target;
|
|
314
|
+
if (!target) return;
|
|
315
|
+
if (!inputs.includes(target)) {
|
|
316
|
+
requestAnimationFrame(() => {
|
|
317
|
+
focusFirstAvailableOtpInput();
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
function handleFocusOut() {
|
|
323
|
+
requestAnimationFrame(() => {
|
|
324
|
+
const inputs = getOtpInputs();
|
|
325
|
+
if (!inputs.length) return;
|
|
326
|
+
const active = document.activeElement;
|
|
327
|
+
if (!active || !inputs.includes(active)) {
|
|
328
|
+
focusFirstAvailableOtpInput();
|
|
329
|
+
}
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
</script>
|
|
252
334
|
|
|
253
335
|
<style scoped>
|
|
254
336
|
:deep(.otp-input-container) {
|
|
@@ -150,11 +150,8 @@
|
|
|
150
150
|
await nextTick();
|
|
151
151
|
await isCMAAvailable();
|
|
152
152
|
tagOtpInputs();
|
|
153
|
-
console.log("Checking if device supports passkeys:", isPasskeysSupported.value);
|
|
154
153
|
if (isPasskeysSupported.value === true) {
|
|
155
|
-
console.log("Device supports passkeys, checking if user has passkeys...");
|
|
156
154
|
await checkIfUserHasPasskeys();
|
|
157
|
-
console.log("Does user have passkeys:", doesUserHavePasskeys.value);
|
|
158
155
|
}
|
|
159
156
|
document.addEventListener('focusin', handleGlobalFocusIn, true);
|
|
160
157
|
focusFirstAvailableOtpInput();
|
|
@@ -193,8 +190,6 @@
|
|
|
193
190
|
async function sendCode (value: any, factorMode: 'TOTP' | 'passkey', passkeyOptions: any) {
|
|
194
191
|
inProgress.value = true;
|
|
195
192
|
const usePasskey = factorMode === 'passkey';
|
|
196
|
-
console.log("Sending code with factorMode:", factorMode);
|
|
197
|
-
console.log("Passkey options:", passkeyOptions);
|
|
198
193
|
const resp = await callAdminForthApi({
|
|
199
194
|
method: 'POST',
|
|
200
195
|
path: '/plugin/twofa/confirmLogin',
|
|
@@ -205,15 +200,12 @@
|
|
|
205
200
|
secret: null,
|
|
206
201
|
}
|
|
207
202
|
})
|
|
208
|
-
console.log("Response from confirmLogin:", resp);
|
|
209
203
|
if ( resp.allowedLogin ) {
|
|
210
204
|
if ( route.meta.isPasskeysEnabled && !doesUserHavePasskeys.value ) {
|
|
211
205
|
handlePasskeyAlert(route.meta.suggestionPeriod, router);
|
|
212
206
|
}
|
|
213
|
-
console.log("Login confirmed, finishing login...");
|
|
214
207
|
await user.finishLogin();
|
|
215
208
|
} else {
|
|
216
|
-
console.log("Login not allowed, showing error:", resp.error);
|
|
217
209
|
if (usePasskey) {
|
|
218
210
|
showErrorTost(t(resp.error));
|
|
219
211
|
codeError.value = resp.error || t('Passkey authentication failed');
|
|
@@ -277,18 +269,15 @@
|
|
|
277
269
|
|
|
278
270
|
async function createSignInRequest() {
|
|
279
271
|
let response;
|
|
280
|
-
console.log("Creating sign-in request for passkey...");
|
|
281
272
|
try {
|
|
282
273
|
response = await callAdminForthApi({
|
|
283
274
|
path: `/plugin/passkeys/signInRequest`,
|
|
284
275
|
method: 'POST',
|
|
285
276
|
});
|
|
286
277
|
} catch (error) {
|
|
287
|
-
console.log("Error creating sign-in request:", error);
|
|
288
278
|
console.error('Error creating sign-in request:', error);
|
|
289
279
|
return;
|
|
290
280
|
}
|
|
291
|
-
console.log("Sign-in request response:", response);
|
|
292
281
|
if (response.ok === true) {
|
|
293
282
|
return { _options: response.data, challengeId: response.challengeId };
|
|
294
283
|
} else {
|
|
@@ -298,14 +287,12 @@
|
|
|
298
287
|
}
|
|
299
288
|
|
|
300
289
|
async function authenticate(options) {
|
|
301
|
-
console.log("Authenticating with options:", options);
|
|
302
290
|
try {
|
|
303
291
|
const abortController = new AbortController();
|
|
304
292
|
const credential = await navigator.credentials.get({
|
|
305
293
|
publicKey: options,
|
|
306
294
|
signal: abortController.signal,
|
|
307
295
|
});
|
|
308
|
-
console.log("Credential obtained:", credential);
|
|
309
296
|
return credential;
|
|
310
297
|
} catch (error) {
|
|
311
298
|
console.error('Error during authentication:', error);
|
package/dist/index.js
CHANGED
|
@@ -343,21 +343,15 @@ export default class TwoFactorsAuthPlugin extends AdminForthPlugin {
|
|
|
343
343
|
let verified = null;
|
|
344
344
|
if (body.usePasskey && this.options.passkeys) {
|
|
345
345
|
// passkeys are enabled and user wants to use them
|
|
346
|
-
console.log("Using passkey for 2FA verification");
|
|
347
346
|
const passkeysCookies = this.adminforth.auth.getCustomCookie({ cookies: cookies, name: `passkeyLoginTemporaryJWT` });
|
|
348
|
-
console.log("Passkey cookies:", passkeysCookies);
|
|
349
347
|
if (!passkeysCookies) {
|
|
350
348
|
return { error: 'Passkey token is required' };
|
|
351
349
|
}
|
|
352
|
-
console.log("Verifying passkey cookies");
|
|
353
350
|
const decodedPasskeysCookies = yield this.adminforth.auth.verify(passkeysCookies, 'tempLoginPasskeyChallenge', false);
|
|
354
351
|
if (!decodedPasskeysCookies) {
|
|
355
352
|
return { error: 'Invalid passkey' };
|
|
356
353
|
}
|
|
357
|
-
console.log("Passkey cookies decoded:", decodedPasskeysCookies);
|
|
358
|
-
console.log("Verifying passkey response");
|
|
359
354
|
const res = yield this.verifyPasskeyResponse(body.passkeyOptions, decoded.pk, decodedPasskeysCookies);
|
|
360
|
-
console.log("Passkey response verification result:", res);
|
|
361
355
|
if (res.ok && res.passkeyConfirmed) {
|
|
362
356
|
verified = true;
|
|
363
357
|
}
|
package/index.ts
CHANGED
|
@@ -383,21 +383,15 @@ export default class TwoFactorsAuthPlugin extends AdminForthPlugin {
|
|
|
383
383
|
let verified = null;
|
|
384
384
|
if (body.usePasskey && this.options.passkeys) {
|
|
385
385
|
// passkeys are enabled and user wants to use them
|
|
386
|
-
console.log("Using passkey for 2FA verification");
|
|
387
386
|
const passkeysCookies = this.adminforth.auth.getCustomCookie({cookies: cookies, name: `passkeyLoginTemporaryJWT`});
|
|
388
|
-
console.log("Passkey cookies:", passkeysCookies);
|
|
389
387
|
if (!passkeysCookies) {
|
|
390
388
|
return { error: 'Passkey token is required' };
|
|
391
389
|
}
|
|
392
|
-
console.log("Verifying passkey cookies");
|
|
393
390
|
const decodedPasskeysCookies = await this.adminforth.auth.verify(passkeysCookies, 'tempLoginPasskeyChallenge', false);
|
|
394
391
|
if (!decodedPasskeysCookies) {
|
|
395
392
|
return { error: 'Invalid passkey' };
|
|
396
393
|
}
|
|
397
|
-
console.log("Passkey cookies decoded:", decodedPasskeysCookies);
|
|
398
|
-
console.log("Verifying passkey response");
|
|
399
394
|
const res = await this.verifyPasskeyResponse(body.passkeyOptions, decoded.pk, decodedPasskeysCookies);
|
|
400
|
-
console.log("Passkey response verification result:", res);
|
|
401
395
|
if (res.ok && res.passkeyConfirmed) {
|
|
402
396
|
verified = true;
|
|
403
397
|
}
|