@adminforth/two-factors-auth 3.1.1 → 3.1.3

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 282,653 bytes received 229 bytes 565,764.00 bytes/sec
20
- total size is 281,759 speedup is 1.00
19
+ sent 283,319 bytes received 229 bytes 567,096.00 bytes/sec
20
+ total size is 282,425 speedup is 1.00
@@ -4,6 +4,7 @@
4
4
  <div v-if="modalMode === 'totp'" class="af-two-factor-modal-totp flex flex-col items-center relative bg-white dark:bg-gray-700 rounded-lg shadow p-6 w-full max-w-md">
5
5
  <div id="mfaCode-label" class="mb-4 text-gray-700 dark:text-gray-100 text-center">
6
6
  <p> {{ customDialogTitle }} </p>
7
+ <p class="text-red-500 font-semibold text-xl" v-if="sessionsIdsToResolve.length > 1"> You are confirming {{ sessionsIdsToResolve.length }} actions</p>
7
8
  <p>{{ $t('Please enter your authenticator code') }}</p>
8
9
  </div>
9
10
 
@@ -51,6 +52,7 @@
51
52
  <p class="text-4xl font-semibold mb-4 text:gray-900 dark:text-gray-200 ">{{$t('Passkey')}}</p>
52
53
  <div class="mb-2 max-w-[300px] text:gray-900 dark:text-gray-200">
53
54
  <p class="mb-2">{{customDialogTitle}} </p>
55
+ <p class="text-red-500 font-semibold text-xl text-center mb-12" v-if="sessionsIdsToResolve.length > 1"> You are confirming {{ sessionsIdsToResolve.length }} actions</p>
54
56
  <p>{{$t('Authenticate yourself using the button below')}}</p>
55
57
  </div>
56
58
  <Button @click="usePasskeyButtonClick" :disabled="isFetchingPasskey" :loader="isFetchingPasskey" class="w-full mx-16">
@@ -100,23 +102,29 @@
100
102
 
101
103
  const { alert } = useAdminforth();
102
104
 
103
- let currentSessionId: string | null = null;
105
+ let isAwaiting2FAResult = false;
106
+ const sessionsIdsToResolve = ref<string[]>([]);
104
107
  watch( props, () => {
105
108
  if (props.adminUser) {
106
109
  websocket.unsubscribeByPrefix(`/user2fa/`);
107
110
  websocket.subscribe(`/user2fa/${props.adminUser.pk}`, async (data: {sessionId: string}) => {
108
- currentSessionId = data.sessionId;
111
+ sessionsIdsToResolve.value.push(data.sessionId);
109
112
  let confirmationResult;
113
+ if (isAwaiting2FAResult) {
114
+ return;
115
+ }
110
116
  try {
117
+ isAwaiting2FAResult = true;
111
118
  confirmationResult = await window.adminforthTwoFaModal.get2FaConfirmationResult();
112
119
  } catch (error) {
113
120
  console.error('Error during 2FA confirmation:', error);
114
121
  }
122
+ isAwaiting2FAResult = false;
115
123
  try {
116
124
  const response = await callAdminForthApi({
117
125
  method: "POST",
118
126
  path: "/plugin/passkeys/resolveVerifyAuto",
119
- body: { confirmationResult, sessionId: data.sessionId }
127
+ body: { confirmationResult, sessionId: data.sessionId, sessionsIds: sessionsIdsToResolve.value }
120
128
  });
121
129
  if (!response.ok && response.error === 'No session ID or confirmation result'){
122
130
  alert({message: 'Verification session finished or cancelled.', variant: 'warning'});
@@ -125,15 +133,15 @@
125
133
  } else if (response.ok) {
126
134
  alert({message: 'Verification successful', variant: 'success'});
127
135
  }
136
+ sessionsIdsToResolve.value = [];
128
137
  } catch (error) {
129
138
  console.error('Error resolving automatic 2FA verification:', error);
130
139
  }
131
- currentSessionId = null;
132
140
  });
133
141
  websocket.subscribe(`/user2fa/${props.adminUser.pk}-resolve`, async (data: {sessionId: string}) => {
134
- if (currentSessionId === data.sessionId && rejectFn && modelShow.value) {
142
+ if (sessionsIdsToResolve.value.includes(data.sessionId) && rejectFn && modelShow.value) {
135
143
  onCancel();
136
- currentSessionId = null;
144
+ sessionsIdsToResolve.value = sessionsIdsToResolve.value.filter(id => id !== data.sessionId);
137
145
  }
138
146
  });
139
147
  }
@@ -4,6 +4,7 @@
4
4
  <div v-if="modalMode === 'totp'" class="af-two-factor-modal-totp flex flex-col items-center relative bg-white dark:bg-gray-700 rounded-lg shadow p-6 w-full max-w-md">
5
5
  <div id="mfaCode-label" class="mb-4 text-gray-700 dark:text-gray-100 text-center">
6
6
  <p> {{ customDialogTitle }} </p>
7
+ <p class="text-red-500 font-semibold text-xl" v-if="sessionsIdsToResolve.length > 1"> You are confirming {{ sessionsIdsToResolve.length }} actions</p>
7
8
  <p>{{ $t('Please enter your authenticator code') }}</p>
8
9
  </div>
9
10
 
@@ -51,6 +52,7 @@
51
52
  <p class="text-4xl font-semibold mb-4 text:gray-900 dark:text-gray-200 ">{{$t('Passkey')}}</p>
52
53
  <div class="mb-2 max-w-[300px] text:gray-900 dark:text-gray-200">
53
54
  <p class="mb-2">{{customDialogTitle}} </p>
55
+ <p class="text-red-500 font-semibold text-xl text-center mb-12" v-if="sessionsIdsToResolve.length > 1"> You are confirming {{ sessionsIdsToResolve.length }} actions</p>
54
56
  <p>{{$t('Authenticate yourself using the button below')}}</p>
55
57
  </div>
56
58
  <Button @click="usePasskeyButtonClick" :disabled="isFetchingPasskey" :loader="isFetchingPasskey" class="w-full mx-16">
@@ -100,23 +102,29 @@
100
102
 
101
103
  const { alert } = useAdminforth();
102
104
 
103
- let currentSessionId: string | null = null;
105
+ let isAwaiting2FAResult = false;
106
+ const sessionsIdsToResolve = ref<string[]>([]);
104
107
  watch( props, () => {
105
108
  if (props.adminUser) {
106
109
  websocket.unsubscribeByPrefix(`/user2fa/`);
107
110
  websocket.subscribe(`/user2fa/${props.adminUser.pk}`, async (data: {sessionId: string}) => {
108
- currentSessionId = data.sessionId;
111
+ sessionsIdsToResolve.value.push(data.sessionId);
109
112
  let confirmationResult;
113
+ if (isAwaiting2FAResult) {
114
+ return;
115
+ }
110
116
  try {
117
+ isAwaiting2FAResult = true;
111
118
  confirmationResult = await window.adminforthTwoFaModal.get2FaConfirmationResult();
112
119
  } catch (error) {
113
120
  console.error('Error during 2FA confirmation:', error);
114
121
  }
122
+ isAwaiting2FAResult = false;
115
123
  try {
116
124
  const response = await callAdminForthApi({
117
125
  method: "POST",
118
126
  path: "/plugin/passkeys/resolveVerifyAuto",
119
- body: { confirmationResult, sessionId: data.sessionId }
127
+ body: { confirmationResult, sessionId: data.sessionId, sessionsIds: sessionsIdsToResolve.value }
120
128
  });
121
129
  if (!response.ok && response.error === 'No session ID or confirmation result'){
122
130
  alert({message: 'Verification session finished or cancelled.', variant: 'warning'});
@@ -125,15 +133,15 @@
125
133
  } else if (response.ok) {
126
134
  alert({message: 'Verification successful', variant: 'success'});
127
135
  }
136
+ sessionsIdsToResolve.value = [];
128
137
  } catch (error) {
129
138
  console.error('Error resolving automatic 2FA verification:', error);
130
139
  }
131
- currentSessionId = null;
132
140
  });
133
141
  websocket.subscribe(`/user2fa/${props.adminUser.pk}-resolve`, async (data: {sessionId: string}) => {
134
- if (currentSessionId === data.sessionId && rejectFn && modelShow.value) {
142
+ if (sessionsIdsToResolve.value.includes(data.sessionId) && rejectFn && modelShow.value) {
135
143
  onCancel();
136
- currentSessionId = null;
144
+ sessionsIdsToResolve.value = sessionsIdsToResolve.value.filter(id => id !== data.sessionId);
137
145
  }
138
146
  });
139
147
  }
package/dist/index.js CHANGED
@@ -717,7 +717,7 @@ export default class TwoFactorsAuthPlugin extends AdminForthPlugin {
717
717
  method: 'POST',
718
718
  path: `/plugin/passkeys/registerPasskeyRequest`,
719
719
  noAuth: false,
720
- handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, response, cookies }) {
720
+ handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, response, cookies, headers }) {
721
721
  var _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
722
722
  const mode = body === null || body === void 0 ? void 0 : body.mode;
723
723
  const confirmationResult = body === null || body === void 0 ? void 0 : body.confirmationResult;
@@ -725,7 +725,10 @@ export default class TwoFactorsAuthPlugin extends AdminForthPlugin {
725
725
  adminUser: adminUser,
726
726
  userPk: adminUser.pk,
727
727
  cookies: cookies,
728
- response: response
728
+ response: response,
729
+ extra: {
730
+ headers,
731
+ }
729
732
  });
730
733
  if (!verificationResult || !('ok' in verificationResult)) {
731
734
  return { ok: false, error: 'Verification failed' };
@@ -1015,24 +1018,35 @@ export default class TwoFactorsAuthPlugin extends AdminForthPlugin {
1015
1018
  method: 'POST',
1016
1019
  path: `/plugin/passkeys/resolveVerifyAuto`,
1017
1020
  noAuth: false,
1018
- handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, response, cookies }) {
1021
+ handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, response, cookies, headers }) {
1019
1022
  const sessionId = body === null || body === void 0 ? void 0 : body.sessionId;
1023
+ const sessionsIds = body === null || body === void 0 ? void 0 : body.sessionsIds;
1020
1024
  const confirmationResult = body === null || body === void 0 ? void 0 : body.confirmationResult;
1021
- if (!sessionId || !confirmationResult) {
1022
- this.resolveResponse(sessionId, { ok: false, error: 'No session ID or confirmation result' });
1025
+ const idsToResolve = sessionsIds && Array.isArray(sessionsIds) ? sessionsIds : [sessionId];
1026
+ if (!(sessionId || sessionsIds) || !confirmationResult) {
1027
+ for (const id of idsToResolve) {
1028
+ this.resolveResponse(id, { ok: false, error: 'No session ID or confirmation result' });
1029
+ }
1023
1030
  return { ok: false, error: 'No session ID or confirmation result' };
1024
1031
  }
1025
1032
  const verificationResult = yield this.verify(confirmationResult, {
1026
1033
  adminUser: adminUser,
1027
1034
  userPk: adminUser.pk,
1028
1035
  cookies: cookies,
1029
- response: response
1036
+ response: response,
1037
+ extra: {
1038
+ headers: headers,
1039
+ }
1030
1040
  });
1031
1041
  if (!verificationResult || !('ok' in verificationResult)) {
1032
- this.resolveResponse(sessionId, { ok: false, error: 'Verification failed' });
1042
+ for (const id of idsToResolve) {
1043
+ this.resolveResponse(id, { ok: false, error: 'Verification failed' });
1044
+ }
1033
1045
  return { ok: false, error: 'Verification failed' };
1034
1046
  }
1035
- this.resolveResponse(sessionId, { ok: true, passkeyConfirmed: verificationResult });
1047
+ for (const id of idsToResolve) {
1048
+ this.resolveResponse(id, { ok: true, passkeyConfirmed: verificationResult });
1049
+ }
1036
1050
  return { ok: true };
1037
1051
  })
1038
1052
  });
package/index.ts CHANGED
@@ -777,7 +777,7 @@ export default class TwoFactorsAuthPlugin extends AdminForthPlugin {
777
777
  method: 'POST',
778
778
  path: `/plugin/passkeys/registerPasskeyRequest`,
779
779
  noAuth: false,
780
- handler: async ({ body, adminUser, response, cookies }) => {
780
+ handler: async ({ body, adminUser, response, cookies, headers }) => {
781
781
  const mode = body?.mode;
782
782
 
783
783
  const confirmationResult = body?.confirmationResult;
@@ -785,7 +785,10 @@ export default class TwoFactorsAuthPlugin extends AdminForthPlugin {
785
785
  adminUser: adminUser,
786
786
  userPk: adminUser.pk,
787
787
  cookies: cookies,
788
- response: response
788
+ response: response,
789
+ extra: {
790
+ headers,
791
+ } as HttpExtra
789
792
  });
790
793
  if ( !verificationResult || !('ok' in verificationResult) ) {
791
794
  return { ok: false, error: 'Verification failed' };
@@ -1076,24 +1079,35 @@ export default class TwoFactorsAuthPlugin extends AdminForthPlugin {
1076
1079
  method: 'POST',
1077
1080
  path: `/plugin/passkeys/resolveVerifyAuto`,
1078
1081
  noAuth: false,
1079
- handler: async ({ body, adminUser, response, cookies }) => {
1082
+ handler: async ({ body, adminUser, response, cookies, headers }) => {
1080
1083
  const sessionId = body?.sessionId;
1084
+ const sessionsIds = body?.sessionsIds;
1081
1085
  const confirmationResult = body?.confirmationResult;
1082
- if (!sessionId || !confirmationResult) {
1083
- this.resolveResponse(sessionId, { ok: false, error: 'No session ID or confirmation result' });
1086
+ const idsToResolve = sessionsIds && Array.isArray(sessionsIds) ? sessionsIds : [sessionId];
1087
+ if (!(sessionId || sessionsIds) || !confirmationResult) {
1088
+ for (const id of idsToResolve) {
1089
+ this.resolveResponse(id, { ok: false, error: 'No session ID or confirmation result' });
1090
+ }
1084
1091
  return { ok: false, error: 'No session ID or confirmation result' };
1085
1092
  }
1086
1093
  const verificationResult = await this.verify(confirmationResult, {
1087
1094
  adminUser: adminUser,
1088
1095
  userPk: adminUser.pk,
1089
1096
  cookies: cookies,
1090
- response: response
1097
+ response: response,
1098
+ extra: {
1099
+ headers: headers,
1100
+ } as HttpExtra
1091
1101
  });
1092
1102
  if ( !verificationResult || !('ok' in verificationResult) ) {
1093
- this.resolveResponse(sessionId, { ok: false, error: 'Verification failed' });
1103
+ for (const id of idsToResolve) {
1104
+ this.resolveResponse(id, { ok: false, error: 'Verification failed' });
1105
+ }
1094
1106
  return { ok: false, error: 'Verification failed' };
1095
1107
  }
1096
- this.resolveResponse(sessionId, { ok: true, passkeyConfirmed: verificationResult });
1108
+ for (const id of idsToResolve) {
1109
+ this.resolveResponse(id, { ok: true, passkeyConfirmed: verificationResult });
1110
+ }
1097
1111
  return { ok: true };
1098
1112
  }
1099
1113
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adminforth/two-factors-auth",
3
- "version": "3.1.1",
3
+ "version": "3.1.3",
4
4
  "description": "AdminForth plugin for two factors authentication",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",