@adminforth/two-factors-auth 2.5.2 → 2.5.4

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 CHANGED
@@ -15,5 +15,5 @@ custom/package.json
15
15
  custom/tsconfig.json
16
16
  custom/utils.js
17
17
 
18
- sent 271,370 bytes received 210 bytes 543,160.00 bytes/sec
19
- total size is 270,543 speedup is 1.00
18
+ sent 271,356 bytes received 210 bytes 543,132.00 bytes/sec
19
+ total size is 270,529 speedup is 1.00
@@ -76,6 +76,7 @@
76
76
  import { Link, Button } from '@/afcl';
77
77
  import { IconShieldOutline } from '@iconify-prerendered/vue-flowbite';
78
78
  import { getPasskey } from './utils.js'
79
+ import adminforth from '@/adminforth';
79
80
 
80
81
 
81
82
  declare global {
@@ -154,8 +155,22 @@
154
155
  let passkeyData;
155
156
  try {
156
157
  passkeyData = await getPasskey();
157
- } catch (e) {
158
- adminforth.alert({message: 'Failed to get passkey', variant: 'danger'});
158
+ } catch (error) {
159
+ const name = (error && (error.name || error.constructor?.name)) || '';
160
+ const message = (error && error.message) || '';
161
+ if (name === 'AbortError') {
162
+ // Aborted intentionally; no user-facing error needed
163
+ return null;
164
+ } else if (name === 'InvalidStateError' || name === 'OperationError' || /pending/i.test(message)) {
165
+ adminforth.alert({ message: t('Another security prompt is already open. Please try again.'), variant: 'warning' });
166
+ return null;
167
+ } else if (name === 'NotAllowedError') {
168
+ adminforth.alert({ message: `The operation either timed out or was not allowed`, variant: 'warning' });
169
+ return null;
170
+ } else {
171
+ adminforth.alert({message: `Error during authentication: ${error}`, variant: 'warning'});
172
+ return null;
173
+ }
159
174
  onCancel();
160
175
  }
161
176
  modelShow.value = false;
@@ -11,7 +11,7 @@
11
11
  <div v-if="isLoading===false" id="authentication-modal" tabindex="-1" class="af-two-factors-confirmation overflow-y-auto overflow-x-hidden z-50 min-w-[00px] justify-center items-center md:inset-0 h-[calc(100%-1rem)] max-h-full">
12
12
  <div class="relative p-4 w-full max-w-md max-h-full">
13
13
  <!-- Modal content -->
14
- <div class="relative bg-white rounded-lg shadow dark:bg-gray-700 dark:shadow-black text-gray-500" :class="codeError ? 'rounded-b-none' : ''">
14
+ <div class="af-login-popup relative bg-white rounded-lg shadow dark:bg-gray-700 dark:shadow-black text-gray-500" :class="codeError ? 'rounded-b-none' : ''">
15
15
  <div class="p-8 w-full max-w-md max-h-full custom-auth-wrapper" >
16
16
  <div v-if="confirmationMode === 'code'" class="af-totp-confirmation">
17
17
  <div id="mfaCode-label" class="mx-4">{{$t('Please enter your authenticator code')}} </div>
@@ -178,11 +178,8 @@
178
178
  await nextTick();
179
179
  await isCMAAvailable();
180
180
  tagOtpInputs();
181
- console.log("Checking if device supports passkeys:", isPasskeysSupported.value);
182
181
  if (isPasskeysSupported.value === true) {
183
- console.log("Device supports passkeys, checking if user has passkeys...");
184
182
  await checkIfUserHasPasskeys();
185
- console.log("Does user have passkeys:", doesUserHavePasskeys.value);
186
183
  }
187
184
  document.addEventListener('focusin', handleGlobalFocusIn, true);
188
185
  focusFirstAvailableOtpInput();
@@ -225,8 +222,6 @@
225
222
  async function sendCode (value: any, factorMode: 'TOTP' | 'passkey', passkeyOptions: any) {
226
223
  inProgress.value = true;
227
224
  const usePasskey = factorMode === 'passkey';
228
- console.log("Sending code with factorMode:", factorMode);
229
- console.log("Passkey options:", passkeyOptions);
230
225
  const resp = await callAdminForthApi({
231
226
  method: 'POST',
232
227
  path: '/plugin/twofa/confirmLogin',
@@ -237,15 +232,12 @@
237
232
  secret: null,
238
233
  }
239
234
  })
240
- console.log("Response from confirmLogin:", resp);
241
235
  if ( resp.allowedLogin ) {
242
236
  if ( route.meta.isPasskeysEnabled && !doesUserHavePasskeys.value ) {
243
237
  handlePasskeyAlert(route.meta.suggestionPeriod, router);
244
238
  }
245
- console.log("Login confirmed, finishing login...");
246
239
  await user.finishLogin();
247
240
  } else {
248
- console.log("Login not allowed, showing error:", resp.error);
249
241
  if (usePasskey) {
250
242
  showErrorTost(t(resp.error));
251
243
  codeError.value = resp.error || t('Passkey authentication failed');
@@ -324,18 +316,15 @@
324
316
 
325
317
  async function createSignInRequest() {
326
318
  let response;
327
- console.log("Creating sign-in request for passkey...");
328
319
  try {
329
320
  response = await callAdminForthApi({
330
321
  path: `/plugin/passkeys/signInRequest`,
331
322
  method: 'POST',
332
323
  });
333
324
  } catch (error) {
334
- console.log("Error creating sign-in request:", error);
335
325
  console.error('Error creating sign-in request:', error);
336
326
  return;
337
327
  }
338
- console.log("Sign-in request response:", response);
339
328
  if (response.ok === true) {
340
329
  return { _options: response.data, challengeId: response.challengeId };
341
330
  } else {
@@ -347,7 +336,6 @@
347
336
  let controller = new AbortController();
348
337
 
349
338
  async function authenticate(options) {
350
- console.log("Authenticating with options:", options);
351
339
  controller.abort();
352
340
  try {
353
341
  // Guard: prevent concurrent navigator.credentials.get calls
@@ -365,7 +353,6 @@
365
353
  signal: abortController.signal,
366
354
  // mediation can be set if using conditional UI, omitted here intentionally
367
355
  });
368
- console.log("Credential obtained:", credential);
369
356
  return credential;
370
357
  } catch (error) {
371
358
  console.error('Error during authentication:', error);
@@ -11,7 +11,7 @@
11
11
  <div id="authentication-modal" tabindex="-1" class="af-two-factors-setup overflow-y-auto overflow-x-hidden z-50 min-w-[00px] justify-center items-center md:inset-0 h-[calc(100%-1rem)] max-h-full">
12
12
  <div class="relative p-4 w-full max-w-md max-h-full">
13
13
  <!-- Modal content -->
14
- <div class="relative bg-white rounded-lg shadow dark:bg-gray-700 dark:shadow-black text-gray-500" >
14
+ <div class="af-login-popup relative bg-white rounded-lg shadow dark:bg-gray-700 dark:shadow-black text-gray-500" >
15
15
  <div class="p-10 w-full max-w-md max-h-full custom-auth-wrapper" >
16
16
  <div>{{$t('Scan this QR code with your authenticator app or open by')}} <a class="text-blue-600" :href="totpUri">{{$t('click')}}</a></div>
17
17
  <div class="flex justify-center m-3" >
@@ -76,6 +76,7 @@
76
76
  import { Link, Button } from '@/afcl';
77
77
  import { IconShieldOutline } from '@iconify-prerendered/vue-flowbite';
78
78
  import { getPasskey } from './utils.js'
79
+ import adminforth from '@/adminforth';
79
80
 
80
81
 
81
82
  declare global {
@@ -154,8 +155,22 @@
154
155
  let passkeyData;
155
156
  try {
156
157
  passkeyData = await getPasskey();
157
- } catch (e) {
158
- adminforth.alert({message: 'Failed to get passkey', variant: 'danger'});
158
+ } catch (error) {
159
+ const name = (error && (error.name || error.constructor?.name)) || '';
160
+ const message = (error && error.message) || '';
161
+ if (name === 'AbortError') {
162
+ // Aborted intentionally; no user-facing error needed
163
+ return null;
164
+ } else if (name === 'InvalidStateError' || name === 'OperationError' || /pending/i.test(message)) {
165
+ adminforth.alert({ message: t('Another security prompt is already open. Please try again.'), variant: 'warning' });
166
+ return null;
167
+ } else if (name === 'NotAllowedError') {
168
+ adminforth.alert({ message: `The operation either timed out or was not allowed`, variant: 'warning' });
169
+ return null;
170
+ } else {
171
+ adminforth.alert({message: `Error during authentication: ${error}`, variant: 'warning'});
172
+ return null;
173
+ }
159
174
  onCancel();
160
175
  }
161
176
  modelShow.value = false;
@@ -11,7 +11,7 @@
11
11
  <div v-if="isLoading===false" id="authentication-modal" tabindex="-1" class="af-two-factors-confirmation overflow-y-auto overflow-x-hidden z-50 min-w-[00px] justify-center items-center md:inset-0 h-[calc(100%-1rem)] max-h-full">
12
12
  <div class="relative p-4 w-full max-w-md max-h-full">
13
13
  <!-- Modal content -->
14
- <div class="relative bg-white rounded-lg shadow dark:bg-gray-700 dark:shadow-black text-gray-500" :class="codeError ? 'rounded-b-none' : ''">
14
+ <div class="af-login-popup relative bg-white rounded-lg shadow dark:bg-gray-700 dark:shadow-black text-gray-500" :class="codeError ? 'rounded-b-none' : ''">
15
15
  <div class="p-8 w-full max-w-md max-h-full custom-auth-wrapper" >
16
16
  <div v-if="confirmationMode === 'code'" class="af-totp-confirmation">
17
17
  <div id="mfaCode-label" class="mx-4">{{$t('Please enter your authenticator code')}} </div>
@@ -178,11 +178,8 @@
178
178
  await nextTick();
179
179
  await isCMAAvailable();
180
180
  tagOtpInputs();
181
- console.log("Checking if device supports passkeys:", isPasskeysSupported.value);
182
181
  if (isPasskeysSupported.value === true) {
183
- console.log("Device supports passkeys, checking if user has passkeys...");
184
182
  await checkIfUserHasPasskeys();
185
- console.log("Does user have passkeys:", doesUserHavePasskeys.value);
186
183
  }
187
184
  document.addEventListener('focusin', handleGlobalFocusIn, true);
188
185
  focusFirstAvailableOtpInput();
@@ -225,8 +222,6 @@
225
222
  async function sendCode (value: any, factorMode: 'TOTP' | 'passkey', passkeyOptions: any) {
226
223
  inProgress.value = true;
227
224
  const usePasskey = factorMode === 'passkey';
228
- console.log("Sending code with factorMode:", factorMode);
229
- console.log("Passkey options:", passkeyOptions);
230
225
  const resp = await callAdminForthApi({
231
226
  method: 'POST',
232
227
  path: '/plugin/twofa/confirmLogin',
@@ -237,15 +232,12 @@
237
232
  secret: null,
238
233
  }
239
234
  })
240
- console.log("Response from confirmLogin:", resp);
241
235
  if ( resp.allowedLogin ) {
242
236
  if ( route.meta.isPasskeysEnabled && !doesUserHavePasskeys.value ) {
243
237
  handlePasskeyAlert(route.meta.suggestionPeriod, router);
244
238
  }
245
- console.log("Login confirmed, finishing login...");
246
239
  await user.finishLogin();
247
240
  } else {
248
- console.log("Login not allowed, showing error:", resp.error);
249
241
  if (usePasskey) {
250
242
  showErrorTost(t(resp.error));
251
243
  codeError.value = resp.error || t('Passkey authentication failed');
@@ -324,18 +316,15 @@
324
316
 
325
317
  async function createSignInRequest() {
326
318
  let response;
327
- console.log("Creating sign-in request for passkey...");
328
319
  try {
329
320
  response = await callAdminForthApi({
330
321
  path: `/plugin/passkeys/signInRequest`,
331
322
  method: 'POST',
332
323
  });
333
324
  } catch (error) {
334
- console.log("Error creating sign-in request:", error);
335
325
  console.error('Error creating sign-in request:', error);
336
326
  return;
337
327
  }
338
- console.log("Sign-in request response:", response);
339
328
  if (response.ok === true) {
340
329
  return { _options: response.data, challengeId: response.challengeId };
341
330
  } else {
@@ -347,7 +336,6 @@
347
336
  let controller = new AbortController();
348
337
 
349
338
  async function authenticate(options) {
350
- console.log("Authenticating with options:", options);
351
339
  controller.abort();
352
340
  try {
353
341
  // Guard: prevent concurrent navigator.credentials.get calls
@@ -365,7 +353,6 @@
365
353
  signal: abortController.signal,
366
354
  // mediation can be set if using conditional UI, omitted here intentionally
367
355
  });
368
- console.log("Credential obtained:", credential);
369
356
  return credential;
370
357
  } catch (error) {
371
358
  console.error('Error during authentication:', error);
@@ -11,7 +11,7 @@
11
11
  <div id="authentication-modal" tabindex="-1" class="af-two-factors-setup overflow-y-auto overflow-x-hidden z-50 min-w-[00px] justify-center items-center md:inset-0 h-[calc(100%-1rem)] max-h-full">
12
12
  <div class="relative p-4 w-full max-w-md max-h-full">
13
13
  <!-- Modal content -->
14
- <div class="relative bg-white rounded-lg shadow dark:bg-gray-700 dark:shadow-black text-gray-500" >
14
+ <div class="af-login-popup relative bg-white rounded-lg shadow dark:bg-gray-700 dark:shadow-black text-gray-500" >
15
15
  <div class="p-10 w-full max-w-md max-h-full custom-auth-wrapper" >
16
16
  <div>{{$t('Scan this QR code with your authenticator app or open by')}} <a class="text-blue-600" :href="totpUri">{{$t('click')}}</a></div>
17
17
  <div class="flex justify-center m-3" >
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adminforth/two-factors-auth",
3
- "version": "2.5.2",
3
+ "version": "2.5.4",
4
4
  "description": "AdminForth plugin for two factors authentication",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",