@adminforth/two-factors-auth 3.3.3 → 3.3.5

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
@@ -16,5 +16,5 @@ custom/pnpm-lock.yaml
16
16
  custom/tsconfig.json
17
17
  custom/utils.js
18
18
 
19
- sent 285,623 bytes received 229 bytes 571,704.00 bytes/sec
20
- total size is 284,729 speedup is 1.00
19
+ sent 286,569 bytes received 229 bytes 573,596.00 bytes/sec
20
+ total size is 285,663 speedup is 1.00
@@ -164,7 +164,9 @@
164
164
  isAwaiting2FAResult.value = true;
165
165
  confirmationResult = await window.adminforthTwoFaModal.get2FaConfirmationResult();
166
166
  } catch (error) {
167
- console.error(t('Error during 2FA confirmation:', error));
167
+ if (!isTwoFaCancel(error)) {
168
+ console.error('[AdminForth 2FA] Error during 2FA confirmation', error);
169
+ }
168
170
  }
169
171
  isAwaiting2FAResult.value = false;
170
172
  try {
@@ -226,28 +228,41 @@
226
228
  let verifyFn: null | ((confirmationResult: string) => Promise<boolean> | boolean) = null;
227
229
  let rejectFn: ((err?: any) => void) | null = null;
228
230
 
231
+ function isTwoFaCancel(error: unknown) {
232
+ return error === 'Cancel';
233
+ }
234
+
229
235
 
230
236
  window.adminforthTwoFaModal = {
231
237
  get2FaConfirmationResult: (title?: string, verifyingCallback?: (confirmationResult: string) => Promise<boolean>) =>
232
- new Promise(async (resolve, reject) => {
233
- if (modelShow.value) throw new Error(t('Modal is already open'));
234
- const skipAllowModal = await checkIfSkipAllowModal();
235
- if (skipAllowModal) {
236
- resolve({ code: "123456" }); // dummy code
237
- return;
238
- }
239
- await checkIfUserHasPasskeys();
240
- if (title) {
241
- customDialogTitle.value = title;
242
- }
243
- modelShow.value = true;
244
- if (modalMode.value === 'totp') {
245
- await addEventListenerForOTPInput();
246
- }
247
- resolveFn = resolve;
248
- rejectFn = reject;
249
- verifyFn = verifyingCallback ?? null;
250
- }),
238
+ new Promise((resolve, reject) => {
239
+ (async () => {
240
+ if (modelShow.value) {
241
+ throw new Error(t('Modal is already open'));
242
+ }
243
+ const skipAllowModal = await checkIfSkipAllowModal();
244
+ if (skipAllowModal) {
245
+ resolve({ code: "123456" }); // dummy code
246
+ return;
247
+ }
248
+ await checkIfUserHasPasskeys();
249
+ if (title) {
250
+ customDialogTitle.value = title;
251
+ }
252
+ resolveFn = resolve;
253
+ rejectFn = reject;
254
+ verifyFn = verifyingCallback ?? null;
255
+ modelShow.value = true;
256
+ if (modalMode.value === 'totp') {
257
+ await addEventListenerForOTPInput();
258
+ }
259
+ })().catch((error) => {
260
+ if (!isTwoFaCancel(error)) {
261
+ console.error('[AdminForth 2FA] Failed to open 2FA modal', error);
262
+ }
263
+ reject(error);
264
+ });
265
+ }),
251
266
  };
252
267
 
253
268
  const { t } = useI18n();
@@ -471,4 +486,4 @@
471
486
  display: flex;
472
487
  gap: 0.75rem;
473
488
  }
474
- </style>
489
+ </style>
@@ -241,7 +241,23 @@
241
241
  return JSON.stringify((credential as PublicKeyCredential).toJSON());
242
242
  } catch (error) {
243
243
  console.error(t('Error creating WebAuthn credential:', error));
244
- adminforth.alert({ message: t('Error creating passkey.'), variant: 'warning' });
244
+
245
+ let message = t('Failed to create passkey.');
246
+
247
+ if (error?.name === 'InvalidStateError') {
248
+ message = t('A passkey for this account already exists on this device.');
249
+ }
250
+
251
+ if (error?.name === 'NotAllowedError') {
252
+ message = t('Passkey creation was cancelled.');
253
+ }
254
+
255
+ if (error?.name === 'NotSupportedError') {
256
+ message = t('Passkeys are not supported on this device or browser.');
257
+ }
258
+
259
+ adminforth.alert({ message, variant: 'danger'});
260
+
245
261
  return null;
246
262
  }
247
263
  }
package/custom/utils.js CHANGED
@@ -122,7 +122,7 @@
122
122
  codeError.value = t('A previous passkey attempt was still pending. Please try again.');
123
123
  return null;
124
124
  } else if (name === 'NotAllowedError') {
125
- adminforth.alert({ message: `The operation either timed out or was not allowed`, variant: 'warning' });
125
+ adminforth.alert({ message: `The operation either timed out or was not allowed`, variant: 'danger' });
126
126
  codeError.value = 'The operation either timed out or was not allowed.';
127
127
  return null;
128
128
  } else {
@@ -164,7 +164,9 @@
164
164
  isAwaiting2FAResult.value = true;
165
165
  confirmationResult = await window.adminforthTwoFaModal.get2FaConfirmationResult();
166
166
  } catch (error) {
167
- console.error(t('Error during 2FA confirmation:', error));
167
+ if (!isTwoFaCancel(error)) {
168
+ console.error('[AdminForth 2FA] Error during 2FA confirmation', error);
169
+ }
168
170
  }
169
171
  isAwaiting2FAResult.value = false;
170
172
  try {
@@ -226,28 +228,41 @@
226
228
  let verifyFn: null | ((confirmationResult: string) => Promise<boolean> | boolean) = null;
227
229
  let rejectFn: ((err?: any) => void) | null = null;
228
230
 
231
+ function isTwoFaCancel(error: unknown) {
232
+ return error === 'Cancel';
233
+ }
234
+
229
235
 
230
236
  window.adminforthTwoFaModal = {
231
237
  get2FaConfirmationResult: (title?: string, verifyingCallback?: (confirmationResult: string) => Promise<boolean>) =>
232
- new Promise(async (resolve, reject) => {
233
- if (modelShow.value) throw new Error(t('Modal is already open'));
234
- const skipAllowModal = await checkIfSkipAllowModal();
235
- if (skipAllowModal) {
236
- resolve({ code: "123456" }); // dummy code
237
- return;
238
- }
239
- await checkIfUserHasPasskeys();
240
- if (title) {
241
- customDialogTitle.value = title;
242
- }
243
- modelShow.value = true;
244
- if (modalMode.value === 'totp') {
245
- await addEventListenerForOTPInput();
246
- }
247
- resolveFn = resolve;
248
- rejectFn = reject;
249
- verifyFn = verifyingCallback ?? null;
250
- }),
238
+ new Promise((resolve, reject) => {
239
+ (async () => {
240
+ if (modelShow.value) {
241
+ throw new Error(t('Modal is already open'));
242
+ }
243
+ const skipAllowModal = await checkIfSkipAllowModal();
244
+ if (skipAllowModal) {
245
+ resolve({ code: "123456" }); // dummy code
246
+ return;
247
+ }
248
+ await checkIfUserHasPasskeys();
249
+ if (title) {
250
+ customDialogTitle.value = title;
251
+ }
252
+ resolveFn = resolve;
253
+ rejectFn = reject;
254
+ verifyFn = verifyingCallback ?? null;
255
+ modelShow.value = true;
256
+ if (modalMode.value === 'totp') {
257
+ await addEventListenerForOTPInput();
258
+ }
259
+ })().catch((error) => {
260
+ if (!isTwoFaCancel(error)) {
261
+ console.error('[AdminForth 2FA] Failed to open 2FA modal', error);
262
+ }
263
+ reject(error);
264
+ });
265
+ }),
251
266
  };
252
267
 
253
268
  const { t } = useI18n();
@@ -471,4 +486,4 @@
471
486
  display: flex;
472
487
  gap: 0.75rem;
473
488
  }
474
- </style>
489
+ </style>
@@ -241,7 +241,23 @@
241
241
  return JSON.stringify((credential as PublicKeyCredential).toJSON());
242
242
  } catch (error) {
243
243
  console.error(t('Error creating WebAuthn credential:', error));
244
- adminforth.alert({ message: t('Error creating passkey.'), variant: 'warning' });
244
+
245
+ let message = t('Failed to create passkey.');
246
+
247
+ if (error?.name === 'InvalidStateError') {
248
+ message = t('A passkey for this account already exists on this device.');
249
+ }
250
+
251
+ if (error?.name === 'NotAllowedError') {
252
+ message = t('Passkey creation was cancelled.');
253
+ }
254
+
255
+ if (error?.name === 'NotSupportedError') {
256
+ message = t('Passkeys are not supported on this device or browser.');
257
+ }
258
+
259
+ adminforth.alert({ message, variant: 'danger'});
260
+
245
261
  return null;
246
262
  }
247
263
  }
@@ -122,7 +122,7 @@
122
122
  codeError.value = t('A previous passkey attempt was still pending. Please try again.');
123
123
  return null;
124
124
  } else if (name === 'NotAllowedError') {
125
- adminforth.alert({ message: `The operation either timed out or was not allowed`, variant: 'warning' });
125
+ adminforth.alert({ message: `The operation either timed out or was not allowed`, variant: 'danger' });
126
126
  codeError.value = 'The operation either timed out or was not allowed.';
127
127
  return null;
128
128
  } else {
package/dist/index.js CHANGED
@@ -575,7 +575,8 @@ export default class TwoFactorsAuthPlugin extends AdminForthPlugin {
575
575
  return { status: 'ok', allowedLogin: true };
576
576
  }
577
577
  else {
578
- return { error: 'Verification failed' };
578
+ response.setStatus(403);
579
+ return { error: 'Wrong or expired TOTP code', };
579
580
  }
580
581
  }
581
582
  })
@@ -1034,42 +1035,49 @@ export default class TwoFactorsAuthPlugin extends AdminForthPlugin {
1034
1035
  handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, response, cookies, headers }) {
1035
1036
  const sessionsIds = body === null || body === void 0 ? void 0 : body.sessionsIds;
1036
1037
  const confirmationResult = body === null || body === void 0 ? void 0 : body.confirmationResult;
1037
- const idsToResolve = sessionsIds;
1038
+ const idsToResolve = Array.isArray(sessionsIds) ? sessionsIds : [];
1038
1039
  const resolveAllIdsAsFailed = (message) => {
1039
1040
  for (const id of idsToResolve) {
1040
1041
  this.resolveResponse(id, { ok: false, error: message });
1041
1042
  }
1042
1043
  return { ok: false, error: message };
1043
1044
  };
1044
- if (!(sessionsIds) || !confirmationResult) {
1045
- return (resolveAllIdsAsFailed('Confirmation window was closed or did not return required data'));
1046
- }
1047
- for (const id of idsToResolve) {
1048
- const validationResult = yield this.adminforth.auth.verify(id, 'auto2FA', false);
1049
- if (!validationResult) {
1050
- return (resolveAllIdsAsFailed('Invalid session ID or confirmation result'));
1045
+ try {
1046
+ if (!idsToResolve.length || !confirmationResult) {
1047
+ return (resolveAllIdsAsFailed('Confirmation window was closed or did not return required data'));
1051
1048
  }
1052
- if (validationResult.adminUserPk !== adminUser.pk) {
1053
- return (resolveAllIdsAsFailed('Session does not belong to the authenticated user'));
1049
+ for (const id of idsToResolve) {
1050
+ const validationResult = yield this.adminforth.auth.verify(id, 'auto2FA', false);
1051
+ if (!validationResult) {
1052
+ return (resolveAllIdsAsFailed('Invalid session ID or confirmation result'));
1053
+ }
1054
+ if (validationResult.adminUserPk !== adminUser.pk) {
1055
+ return (resolveAllIdsAsFailed('Session does not belong to the authenticated user'));
1056
+ }
1054
1057
  }
1055
- }
1056
- const verificationResult = yield this.verify(confirmationResult, {
1057
- adminUser: adminUser,
1058
- userPk: adminUser.pk,
1059
- cookies: cookies,
1060
- response: response,
1061
- extra: {
1062
- headers: headers,
1058
+ const verificationResult = yield this.verify(confirmationResult, {
1059
+ adminUser: adminUser,
1060
+ userPk: adminUser.pk,
1061
+ cookies: cookies,
1062
+ response: response,
1063
+ extra: {
1064
+ headers: headers,
1065
+ }
1066
+ });
1067
+ if (!verificationResult || !('ok' in verificationResult)) {
1068
+ return (resolveAllIdsAsFailed('Verification failed'));
1069
+ }
1070
+ if ('ok' in verificationResult && verificationResult.ok) {
1071
+ for (const id of idsToResolve) {
1072
+ this.resolveResponse(id, { ok: true, passkeyConfirmed: verificationResult });
1073
+ }
1074
+ return { ok: true };
1063
1075
  }
1064
- });
1065
- if (!verificationResult || !('ok' in verificationResult)) {
1066
1076
  return (resolveAllIdsAsFailed('Verification failed'));
1067
1077
  }
1068
- if ('ok' in verificationResult && verificationResult.ok) {
1069
- for (const id of idsToResolve) {
1070
- this.resolveResponse(id, { ok: true, passkeyConfirmed: verificationResult });
1071
- }
1072
- return { ok: true };
1078
+ catch (error) {
1079
+ console.error('[AdminForth 2FA] Error resolving automatic 2FA verification', error);
1080
+ return (resolveAllIdsAsFailed(error instanceof Error ? error.message : 'Verification failed'));
1073
1081
  }
1074
1082
  })
1075
1083
  });
package/index.ts CHANGED
@@ -617,7 +617,8 @@ export default class TwoFactorsAuthPlugin extends AdminForthPlugin {
617
617
  this.adminforth.auth.setAuthCookie({expireInDuration: decoded.sessionDuration, response, username:decoded.userName, pk:decoded.pk})
618
618
  return { status: 'ok', allowedLogin: true }
619
619
  } else {
620
- return {error: 'Verification failed'}
620
+ response.setStatus(403);
621
+ return {error: 'Wrong or expired TOTP code', }
621
622
  }
622
623
  }
623
624
  }
@@ -1099,7 +1100,7 @@ export default class TwoFactorsAuthPlugin extends AdminForthPlugin {
1099
1100
  handler: async ({ body, adminUser, response, cookies, headers }) => {
1100
1101
  const sessionsIds = body?.sessionsIds;
1101
1102
  const confirmationResult = body?.confirmationResult;
1102
- const idsToResolve = sessionsIds;
1103
+ const idsToResolve = Array.isArray(sessionsIds) ? sessionsIds : [];
1103
1104
 
1104
1105
  const resolveAllIdsAsFailed = (message) => {
1105
1106
  for (const id of idsToResolve) {
@@ -1108,37 +1109,43 @@ export default class TwoFactorsAuthPlugin extends AdminForthPlugin {
1108
1109
  return { ok: false, error: message };
1109
1110
  }
1110
1111
 
1111
- if (!(sessionsIds) || !confirmationResult) {
1112
- return(resolveAllIdsAsFailed('Confirmation window was closed or did not return required data'));
1113
- }
1114
-
1115
- for (const id of idsToResolve) {
1116
- const validationResult = await this.adminforth.auth.verify(id, 'auto2FA', false);
1117
- if (!validationResult) {
1118
- return(resolveAllIdsAsFailed('Invalid session ID or confirmation result'));
1119
- }
1120
- if (validationResult.adminUserPk !== adminUser.pk) {
1121
- return(resolveAllIdsAsFailed('Session does not belong to the authenticated user'));
1112
+ try {
1113
+ if (!idsToResolve.length || !confirmationResult) {
1114
+ return(resolveAllIdsAsFailed('Confirmation window was closed or did not return required data'));
1122
1115
  }
1123
- }
1124
1116
 
1125
- const verificationResult = await this.verify(confirmationResult, {
1126
- adminUser: adminUser,
1127
- userPk: adminUser.pk,
1128
- cookies: cookies,
1129
- response: response,
1130
- extra: {
1131
- headers: headers,
1132
- } as HttpExtra
1133
- });
1134
- if ( !verificationResult || !('ok' in verificationResult) ) {
1135
- return(resolveAllIdsAsFailed('Verification failed'));
1136
- }
1137
- if ('ok' in verificationResult && verificationResult.ok){
1138
1117
  for (const id of idsToResolve) {
1139
- this.resolveResponse(id, { ok: true, passkeyConfirmed: verificationResult });
1118
+ const validationResult = await this.adminforth.auth.verify(id, 'auto2FA', false);
1119
+ if (!validationResult) {
1120
+ return(resolveAllIdsAsFailed('Invalid session ID or confirmation result'));
1121
+ }
1122
+ if (validationResult.adminUserPk !== adminUser.pk) {
1123
+ return(resolveAllIdsAsFailed('Session does not belong to the authenticated user'));
1124
+ }
1125
+ }
1126
+
1127
+ const verificationResult = await this.verify(confirmationResult, {
1128
+ adminUser: adminUser,
1129
+ userPk: adminUser.pk,
1130
+ cookies: cookies,
1131
+ response: response,
1132
+ extra: {
1133
+ headers: headers,
1134
+ } as HttpExtra
1135
+ });
1136
+ if ( !verificationResult || !('ok' in verificationResult) ) {
1137
+ return(resolveAllIdsAsFailed('Verification failed'));
1138
+ }
1139
+ if ('ok' in verificationResult && verificationResult.ok){
1140
+ for (const id of idsToResolve) {
1141
+ this.resolveResponse(id, { ok: true, passkeyConfirmed: verificationResult });
1142
+ }
1143
+ return { ok: true };
1140
1144
  }
1141
- return { ok: true };
1145
+ return(resolveAllIdsAsFailed('Verification failed'));
1146
+ } catch (error) {
1147
+ console.error('[AdminForth 2FA] Error resolving automatic 2FA verification', error);
1148
+ return(resolveAllIdsAsFailed(error instanceof Error ? error.message : 'Verification failed'));
1142
1149
  }
1143
1150
  }
1144
1151
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adminforth/two-factors-auth",
3
- "version": "3.3.3",
3
+ "version": "3.3.5",
4
4
  "description": "AdminForth plugin for two factors authentication",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -32,7 +32,7 @@
32
32
  },
33
33
  "devDependencies": {
34
34
  "@types/node": "^22.10.7",
35
- "adminforth": "^2.50.1",
35
+ "adminforth": "^2.66.0",
36
36
  "semantic-release": "^24.2.1",
37
37
  "semantic-release-slack-bot": "^4.0.2",
38
38
  "typescript": "^5.7.3"