@adminforth/two-factors-auth 3.1.2 → 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 +2 -2
- package/custom/TwoFAModal.vue +14 -6
- package/dist/custom/TwoFAModal.vue +14 -6
- package/dist/index.js +12 -4
- package/index.ts +12 -4
- package/package.json +1 -1
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
|
|
20
|
-
total size is
|
|
19
|
+
sent 283,319 bytes received 229 bytes 567,096.00 bytes/sec
|
|
20
|
+
total size is 282,425 speedup is 1.00
|
package/custom/TwoFAModal.vue
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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 (
|
|
142
|
+
if (sessionsIdsToResolve.value.includes(data.sessionId) && rejectFn && modelShow.value) {
|
|
135
143
|
onCancel();
|
|
136
|
-
|
|
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
|
|
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
|
-
|
|
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 (
|
|
142
|
+
if (sessionsIdsToResolve.value.includes(data.sessionId) && rejectFn && modelShow.value) {
|
|
135
143
|
onCancel();
|
|
136
|
-
|
|
144
|
+
sessionsIdsToResolve.value = sessionsIdsToResolve.value.filter(id => id !== data.sessionId);
|
|
137
145
|
}
|
|
138
146
|
});
|
|
139
147
|
}
|
package/dist/index.js
CHANGED
|
@@ -1020,9 +1020,13 @@ export default class TwoFactorsAuthPlugin extends AdminForthPlugin {
|
|
|
1020
1020
|
noAuth: false,
|
|
1021
1021
|
handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, response, cookies, headers }) {
|
|
1022
1022
|
const sessionId = body === null || body === void 0 ? void 0 : body.sessionId;
|
|
1023
|
+
const sessionsIds = body === null || body === void 0 ? void 0 : body.sessionsIds;
|
|
1023
1024
|
const confirmationResult = body === null || body === void 0 ? void 0 : body.confirmationResult;
|
|
1024
|
-
|
|
1025
|
-
|
|
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
|
+
}
|
|
1026
1030
|
return { ok: false, error: 'No session ID or confirmation result' };
|
|
1027
1031
|
}
|
|
1028
1032
|
const verificationResult = yield this.verify(confirmationResult, {
|
|
@@ -1035,10 +1039,14 @@ export default class TwoFactorsAuthPlugin extends AdminForthPlugin {
|
|
|
1035
1039
|
}
|
|
1036
1040
|
});
|
|
1037
1041
|
if (!verificationResult || !('ok' in verificationResult)) {
|
|
1038
|
-
|
|
1042
|
+
for (const id of idsToResolve) {
|
|
1043
|
+
this.resolveResponse(id, { ok: false, error: 'Verification failed' });
|
|
1044
|
+
}
|
|
1039
1045
|
return { ok: false, error: 'Verification failed' };
|
|
1040
1046
|
}
|
|
1041
|
-
|
|
1047
|
+
for (const id of idsToResolve) {
|
|
1048
|
+
this.resolveResponse(id, { ok: true, passkeyConfirmed: verificationResult });
|
|
1049
|
+
}
|
|
1042
1050
|
return { ok: true };
|
|
1043
1051
|
})
|
|
1044
1052
|
});
|
package/index.ts
CHANGED
|
@@ -1081,9 +1081,13 @@ export default class TwoFactorsAuthPlugin extends AdminForthPlugin {
|
|
|
1081
1081
|
noAuth: false,
|
|
1082
1082
|
handler: async ({ body, adminUser, response, cookies, headers }) => {
|
|
1083
1083
|
const sessionId = body?.sessionId;
|
|
1084
|
+
const sessionsIds = body?.sessionsIds;
|
|
1084
1085
|
const confirmationResult = body?.confirmationResult;
|
|
1085
|
-
|
|
1086
|
-
|
|
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
|
+
}
|
|
1087
1091
|
return { ok: false, error: 'No session ID or confirmation result' };
|
|
1088
1092
|
}
|
|
1089
1093
|
const verificationResult = await this.verify(confirmationResult, {
|
|
@@ -1096,10 +1100,14 @@ export default class TwoFactorsAuthPlugin extends AdminForthPlugin {
|
|
|
1096
1100
|
} as HttpExtra
|
|
1097
1101
|
});
|
|
1098
1102
|
if ( !verificationResult || !('ok' in verificationResult) ) {
|
|
1099
|
-
|
|
1103
|
+
for (const id of idsToResolve) {
|
|
1104
|
+
this.resolveResponse(id, { ok: false, error: 'Verification failed' });
|
|
1105
|
+
}
|
|
1100
1106
|
return { ok: false, error: 'Verification failed' };
|
|
1101
1107
|
}
|
|
1102
|
-
|
|
1108
|
+
for (const id of idsToResolve) {
|
|
1109
|
+
this.resolveResponse(id, { ok: true, passkeyConfirmed: verificationResult });
|
|
1110
|
+
}
|
|
1103
1111
|
return { ok: true };
|
|
1104
1112
|
}
|
|
1105
1113
|
});
|