@adminforth/two-factors-auth 3.1.3 → 3.1.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 +2 -2
- package/custom/TwoFAModal.vue +24 -5
- package/dist/custom/TwoFAModal.vue +24 -5
- package/dist/index.js +21 -12
- package/index.ts +26 -12
- 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 283,
|
|
20
|
-
total size is 282,
|
|
19
|
+
sent 283,900 bytes received 229 bytes 568,258.00 bytes/sec
|
|
20
|
+
total size is 282,994 speedup is 1.00
|
package/custom/TwoFAModal.vue
CHANGED
|
@@ -102,29 +102,47 @@
|
|
|
102
102
|
|
|
103
103
|
const { alert } = useAdminforth();
|
|
104
104
|
|
|
105
|
-
|
|
105
|
+
const isAwaiting2FAResult = ref(false);
|
|
106
|
+
let allowAddNewSessions = true;
|
|
107
|
+
const ALLOW_NEW_SESSIONS_PERIOD = 1000;
|
|
106
108
|
const sessionsIdsToResolve = ref<string[]>([]);
|
|
109
|
+
|
|
110
|
+
watch(isAwaiting2FAResult, (awaiting) => {
|
|
111
|
+
if (awaiting) {
|
|
112
|
+
allowAddNewSessions = true;
|
|
113
|
+
setTimeout(() => {
|
|
114
|
+
if (isAwaiting2FAResult.value) {
|
|
115
|
+
allowAddNewSessions = false;
|
|
116
|
+
}
|
|
117
|
+
}, ALLOW_NEW_SESSIONS_PERIOD);
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
|
|
107
121
|
watch( props, () => {
|
|
108
122
|
if (props.adminUser) {
|
|
109
123
|
websocket.unsubscribeByPrefix(`/user2fa/`);
|
|
110
124
|
websocket.subscribe(`/user2fa/${props.adminUser.pk}`, async (data: {sessionId: string}) => {
|
|
125
|
+
if (!allowAddNewSessions) {
|
|
126
|
+
alert({message: 'Some process or user tries to add new actions to confirm. Action was blocked', variant: 'warning'});
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
111
129
|
sessionsIdsToResolve.value.push(data.sessionId);
|
|
112
130
|
let confirmationResult;
|
|
113
|
-
if (isAwaiting2FAResult) {
|
|
131
|
+
if (isAwaiting2FAResult.value) {
|
|
114
132
|
return;
|
|
115
133
|
}
|
|
116
134
|
try {
|
|
117
|
-
isAwaiting2FAResult = true;
|
|
135
|
+
isAwaiting2FAResult.value = true;
|
|
118
136
|
confirmationResult = await window.adminforthTwoFaModal.get2FaConfirmationResult();
|
|
119
137
|
} catch (error) {
|
|
120
138
|
console.error('Error during 2FA confirmation:', error);
|
|
121
139
|
}
|
|
122
|
-
isAwaiting2FAResult = false;
|
|
140
|
+
isAwaiting2FAResult.value = false;
|
|
123
141
|
try {
|
|
124
142
|
const response = await callAdminForthApi({
|
|
125
143
|
method: "POST",
|
|
126
144
|
path: "/plugin/passkeys/resolveVerifyAuto",
|
|
127
|
-
body: { confirmationResult,
|
|
145
|
+
body: { confirmationResult, sessionsIds: sessionsIdsToResolve.value }
|
|
128
146
|
});
|
|
129
147
|
if (!response.ok && response.error === 'No session ID or confirmation result'){
|
|
130
148
|
alert({message: 'Verification session finished or cancelled.', variant: 'warning'});
|
|
@@ -137,6 +155,7 @@
|
|
|
137
155
|
} catch (error) {
|
|
138
156
|
console.error('Error resolving automatic 2FA verification:', error);
|
|
139
157
|
}
|
|
158
|
+
allowAddNewSessions = true;
|
|
140
159
|
});
|
|
141
160
|
websocket.subscribe(`/user2fa/${props.adminUser.pk}-resolve`, async (data: {sessionId: string}) => {
|
|
142
161
|
if (sessionsIdsToResolve.value.includes(data.sessionId) && rejectFn && modelShow.value) {
|
|
@@ -102,29 +102,47 @@
|
|
|
102
102
|
|
|
103
103
|
const { alert } = useAdminforth();
|
|
104
104
|
|
|
105
|
-
|
|
105
|
+
const isAwaiting2FAResult = ref(false);
|
|
106
|
+
let allowAddNewSessions = true;
|
|
107
|
+
const ALLOW_NEW_SESSIONS_PERIOD = 1000;
|
|
106
108
|
const sessionsIdsToResolve = ref<string[]>([]);
|
|
109
|
+
|
|
110
|
+
watch(isAwaiting2FAResult, (awaiting) => {
|
|
111
|
+
if (awaiting) {
|
|
112
|
+
allowAddNewSessions = true;
|
|
113
|
+
setTimeout(() => {
|
|
114
|
+
if (isAwaiting2FAResult.value) {
|
|
115
|
+
allowAddNewSessions = false;
|
|
116
|
+
}
|
|
117
|
+
}, ALLOW_NEW_SESSIONS_PERIOD);
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
|
|
107
121
|
watch( props, () => {
|
|
108
122
|
if (props.adminUser) {
|
|
109
123
|
websocket.unsubscribeByPrefix(`/user2fa/`);
|
|
110
124
|
websocket.subscribe(`/user2fa/${props.adminUser.pk}`, async (data: {sessionId: string}) => {
|
|
125
|
+
if (!allowAddNewSessions) {
|
|
126
|
+
alert({message: 'Some process or user tries to add new actions to confirm. Action was blocked', variant: 'warning'});
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
111
129
|
sessionsIdsToResolve.value.push(data.sessionId);
|
|
112
130
|
let confirmationResult;
|
|
113
|
-
if (isAwaiting2FAResult) {
|
|
131
|
+
if (isAwaiting2FAResult.value) {
|
|
114
132
|
return;
|
|
115
133
|
}
|
|
116
134
|
try {
|
|
117
|
-
isAwaiting2FAResult = true;
|
|
135
|
+
isAwaiting2FAResult.value = true;
|
|
118
136
|
confirmationResult = await window.adminforthTwoFaModal.get2FaConfirmationResult();
|
|
119
137
|
} catch (error) {
|
|
120
138
|
console.error('Error during 2FA confirmation:', error);
|
|
121
139
|
}
|
|
122
|
-
isAwaiting2FAResult = false;
|
|
140
|
+
isAwaiting2FAResult.value = false;
|
|
123
141
|
try {
|
|
124
142
|
const response = await callAdminForthApi({
|
|
125
143
|
method: "POST",
|
|
126
144
|
path: "/plugin/passkeys/resolveVerifyAuto",
|
|
127
|
-
body: { confirmationResult,
|
|
145
|
+
body: { confirmationResult, sessionsIds: sessionsIdsToResolve.value }
|
|
128
146
|
});
|
|
129
147
|
if (!response.ok && response.error === 'No session ID or confirmation result'){
|
|
130
148
|
alert({message: 'Verification session finished or cancelled.', variant: 'warning'});
|
|
@@ -137,6 +155,7 @@
|
|
|
137
155
|
} catch (error) {
|
|
138
156
|
console.error('Error resolving automatic 2FA verification:', error);
|
|
139
157
|
}
|
|
158
|
+
allowAddNewSessions = true;
|
|
140
159
|
});
|
|
141
160
|
websocket.subscribe(`/user2fa/${props.adminUser.pk}-resolve`, async (data: {sessionId: string}) => {
|
|
142
161
|
if (sessionsIdsToResolve.value.includes(data.sessionId) && rejectFn && modelShow.value) {
|
package/dist/index.js
CHANGED
|
@@ -149,9 +149,10 @@ export default class TwoFactorsAuthPlugin extends AdminForthPlugin {
|
|
|
149
149
|
verifyAuto(adminUser) {
|
|
150
150
|
return __awaiter(this, void 0, void 0, function* () {
|
|
151
151
|
const sessionId = crypto.randomUUID();
|
|
152
|
-
this.adminforth.
|
|
153
|
-
|
|
154
|
-
this.
|
|
152
|
+
const jwt = this.adminforth.auth.issueJWT({ sessionId, adminUserPk: adminUser.pk }, 'auto2FA', '5m');
|
|
153
|
+
this.adminforth.websocket.publish(`/user2fa/${adminUser.pk}`, { sessionId: jwt });
|
|
154
|
+
const result = yield this.waitForResponse(jwt);
|
|
155
|
+
this.adminforth.websocket.publish(`/user2fa/${adminUser.pk}-resolve`, { sessionId: jwt });
|
|
155
156
|
return result;
|
|
156
157
|
});
|
|
157
158
|
}
|
|
@@ -1019,15 +1020,26 @@ export default class TwoFactorsAuthPlugin extends AdminForthPlugin {
|
|
|
1019
1020
|
path: `/plugin/passkeys/resolveVerifyAuto`,
|
|
1020
1021
|
noAuth: false,
|
|
1021
1022
|
handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, response, cookies, headers }) {
|
|
1022
|
-
const sessionId = body === null || body === void 0 ? void 0 : body.sessionId;
|
|
1023
1023
|
const sessionsIds = body === null || body === void 0 ? void 0 : body.sessionsIds;
|
|
1024
1024
|
const confirmationResult = body === null || body === void 0 ? void 0 : body.confirmationResult;
|
|
1025
|
-
const idsToResolve = sessionsIds
|
|
1026
|
-
|
|
1025
|
+
const idsToResolve = sessionsIds;
|
|
1026
|
+
const resolveAllIdsAsFailed = (message) => {
|
|
1027
1027
|
for (const id of idsToResolve) {
|
|
1028
|
-
this.resolveResponse(id, { ok: false, error:
|
|
1028
|
+
this.resolveResponse(id, { ok: false, error: message });
|
|
1029
|
+
}
|
|
1030
|
+
return { ok: false, error: message };
|
|
1031
|
+
};
|
|
1032
|
+
if (!(sessionsIds) || !confirmationResult) {
|
|
1033
|
+
resolveAllIdsAsFailed('Confirmation window was closed or did not return required data');
|
|
1034
|
+
}
|
|
1035
|
+
for (const id of idsToResolve) {
|
|
1036
|
+
const validationResult = yield this.adminforth.auth.verify(id, 'auto2FA', false);
|
|
1037
|
+
if (!validationResult) {
|
|
1038
|
+
resolveAllIdsAsFailed('Invalid session ID or confirmation result');
|
|
1039
|
+
}
|
|
1040
|
+
if (validationResult.adminUserPk !== adminUser.pk) {
|
|
1041
|
+
resolveAllIdsAsFailed('Session does not belong to the authenticated user');
|
|
1029
1042
|
}
|
|
1030
|
-
return { ok: false, error: 'No session ID or confirmation result' };
|
|
1031
1043
|
}
|
|
1032
1044
|
const verificationResult = yield this.verify(confirmationResult, {
|
|
1033
1045
|
adminUser: adminUser,
|
|
@@ -1039,10 +1051,7 @@ export default class TwoFactorsAuthPlugin extends AdminForthPlugin {
|
|
|
1039
1051
|
}
|
|
1040
1052
|
});
|
|
1041
1053
|
if (!verificationResult || !('ok' in verificationResult)) {
|
|
1042
|
-
|
|
1043
|
-
this.resolveResponse(id, { ok: false, error: 'Verification failed' });
|
|
1044
|
-
}
|
|
1045
|
-
return { ok: false, error: 'Verification failed' };
|
|
1054
|
+
resolveAllIdsAsFailed('Verification failed');
|
|
1046
1055
|
}
|
|
1047
1056
|
for (const id of idsToResolve) {
|
|
1048
1057
|
this.resolveResponse(id, { ok: true, passkeyConfirmed: verificationResult });
|
package/index.ts
CHANGED
|
@@ -159,9 +159,10 @@ export default class TwoFactorsAuthPlugin extends AdminForthPlugin {
|
|
|
159
159
|
|
|
160
160
|
public async verifyAuto(adminUser: AdminUser) {
|
|
161
161
|
const sessionId = crypto.randomUUID();
|
|
162
|
-
this.adminforth.
|
|
163
|
-
|
|
164
|
-
this.
|
|
162
|
+
const jwt = this.adminforth.auth.issueJWT({sessionId, adminUserPk: adminUser.pk}, 'auto2FA', '5m');
|
|
163
|
+
this.adminforth.websocket.publish(`/user2fa/${adminUser.pk}`, { sessionId: jwt });
|
|
164
|
+
const result = await this.waitForResponse(jwt);
|
|
165
|
+
this.adminforth.websocket.publish(`/user2fa/${adminUser.pk}-resolve`, { sessionId: jwt });
|
|
165
166
|
return result;
|
|
166
167
|
}
|
|
167
168
|
|
|
@@ -1080,16 +1081,31 @@ export default class TwoFactorsAuthPlugin extends AdminForthPlugin {
|
|
|
1080
1081
|
path: `/plugin/passkeys/resolveVerifyAuto`,
|
|
1081
1082
|
noAuth: false,
|
|
1082
1083
|
handler: async ({ body, adminUser, response, cookies, headers }) => {
|
|
1083
|
-
const sessionId = body?.sessionId;
|
|
1084
1084
|
const sessionsIds = body?.sessionsIds;
|
|
1085
1085
|
const confirmationResult = body?.confirmationResult;
|
|
1086
|
-
const idsToResolve = sessionsIds
|
|
1087
|
-
|
|
1086
|
+
const idsToResolve = sessionsIds;
|
|
1087
|
+
|
|
1088
|
+
const resolveAllIdsAsFailed = (message) => {
|
|
1088
1089
|
for (const id of idsToResolve) {
|
|
1089
|
-
this.resolveResponse(id, { ok: false, error:
|
|
1090
|
+
this.resolveResponse(id, { ok: false, error: message });
|
|
1090
1091
|
}
|
|
1091
|
-
return { ok: false, error:
|
|
1092
|
+
return { ok: false, error: message };
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
if (!(sessionsIds) || !confirmationResult) {
|
|
1096
|
+
resolveAllIdsAsFailed('Confirmation window was closed or did not return required data');
|
|
1092
1097
|
}
|
|
1098
|
+
|
|
1099
|
+
for (const id of idsToResolve) {
|
|
1100
|
+
const validationResult = await this.adminforth.auth.verify(id, 'auto2FA', false);
|
|
1101
|
+
if (!validationResult) {
|
|
1102
|
+
resolveAllIdsAsFailed('Invalid session ID or confirmation result');
|
|
1103
|
+
}
|
|
1104
|
+
if (validationResult.adminUserPk !== adminUser.pk) {
|
|
1105
|
+
resolveAllIdsAsFailed('Session does not belong to the authenticated user');
|
|
1106
|
+
}
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1093
1109
|
const verificationResult = await this.verify(confirmationResult, {
|
|
1094
1110
|
adminUser: adminUser,
|
|
1095
1111
|
userPk: adminUser.pk,
|
|
@@ -1100,11 +1116,9 @@ export default class TwoFactorsAuthPlugin extends AdminForthPlugin {
|
|
|
1100
1116
|
} as HttpExtra
|
|
1101
1117
|
});
|
|
1102
1118
|
if ( !verificationResult || !('ok' in verificationResult) ) {
|
|
1103
|
-
|
|
1104
|
-
this.resolveResponse(id, { ok: false, error: 'Verification failed' });
|
|
1105
|
-
}
|
|
1106
|
-
return { ok: false, error: 'Verification failed' };
|
|
1119
|
+
resolveAllIdsAsFailed('Verification failed');
|
|
1107
1120
|
}
|
|
1121
|
+
|
|
1108
1122
|
for (const id of idsToResolve) {
|
|
1109
1123
|
this.resolveResponse(id, { ok: true, passkeyConfirmed: verificationResult });
|
|
1110
1124
|
}
|