@vivinkv28/strapi-2fa-admin-plugin 0.1.13 → 0.1.15
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/README.md
CHANGED
|
@@ -10,6 +10,20 @@ This package adds the backend flow for:
|
|
|
10
10
|
- rate limiting for login, verify, and resend
|
|
11
11
|
- final Strapi admin session creation only after OTP verification
|
|
12
12
|
|
|
13
|
+
## UI Preview
|
|
14
|
+
|
|
15
|
+
### Login Screen
|
|
16
|
+
|
|
17
|
+

|
|
18
|
+
|
|
19
|
+
The first step collects the admin email and password before starting the OTP challenge flow.
|
|
20
|
+
|
|
21
|
+
### OTP Screen
|
|
22
|
+
|
|
23
|
+

|
|
24
|
+
|
|
25
|
+
The second step shows the OTP input, resend action, and inline validation feedback during verification.
|
|
26
|
+
|
|
13
27
|
## Important
|
|
14
28
|
|
|
15
29
|
This package does not automatically replace the default Strapi admin login UI.
|
package/dist/server/index.js
CHANGED
|
@@ -77,13 +77,23 @@ const getService = () => strapi.plugin("admin-2fa").service("auth");
|
|
|
77
77
|
const APPLICATION_ERROR_STATUS = {
|
|
78
78
|
ApplicationError: 400,
|
|
79
79
|
ValidationError: 400,
|
|
80
|
-
UnauthorizedError:
|
|
81
|
-
ForbiddenError:
|
|
80
|
+
UnauthorizedError: 400,
|
|
81
|
+
ForbiddenError: 400,
|
|
82
82
|
NotFoundError: 404,
|
|
83
83
|
PayloadTooLargeError: 413,
|
|
84
84
|
RateLimitError: 429,
|
|
85
85
|
NotImplementedError: 501
|
|
86
86
|
};
|
|
87
|
+
const deriveApplicationErrorStatus = (error2) => {
|
|
88
|
+
if (typeof error2?.status === "number" && error2.status >= 400 && error2.status < 500) {
|
|
89
|
+
return error2.status;
|
|
90
|
+
}
|
|
91
|
+
const message = typeof error2?.message === "string" ? error2.message.toLowerCase() : "";
|
|
92
|
+
if (message.includes("session not found") || message.includes("please log in again") || message.includes("otp expired") || message.includes("expired otp")) {
|
|
93
|
+
return 409;
|
|
94
|
+
}
|
|
95
|
+
return APPLICATION_ERROR_STATUS[error2?.name] ?? 400;
|
|
96
|
+
};
|
|
87
97
|
const setRefreshCookie = (ctx, refreshToken, cookieOptions) => {
|
|
88
98
|
ctx.cookies.set(sessionAuth$1.REFRESH_COOKIE_NAME, refreshToken, cookieOptions);
|
|
89
99
|
};
|
|
@@ -98,7 +108,7 @@ const getClientIp = (ctx) => {
|
|
|
98
108
|
return String(ctx.request.ip ?? ctx.ip ?? "").trim();
|
|
99
109
|
};
|
|
100
110
|
const sendApplicationError = (ctx, error2) => {
|
|
101
|
-
const derivedStatus =
|
|
111
|
+
const derivedStatus = deriveApplicationErrorStatus(error2);
|
|
102
112
|
ctx.status = derivedStatus;
|
|
103
113
|
ctx.body = {
|
|
104
114
|
data: null,
|
package/dist/server/index.mjs
CHANGED
|
@@ -63,13 +63,23 @@ const getService = () => strapi.plugin("admin-2fa").service("auth");
|
|
|
63
63
|
const APPLICATION_ERROR_STATUS = {
|
|
64
64
|
ApplicationError: 400,
|
|
65
65
|
ValidationError: 400,
|
|
66
|
-
UnauthorizedError:
|
|
67
|
-
ForbiddenError:
|
|
66
|
+
UnauthorizedError: 400,
|
|
67
|
+
ForbiddenError: 400,
|
|
68
68
|
NotFoundError: 404,
|
|
69
69
|
PayloadTooLargeError: 413,
|
|
70
70
|
RateLimitError: 429,
|
|
71
71
|
NotImplementedError: 501
|
|
72
72
|
};
|
|
73
|
+
const deriveApplicationErrorStatus = (error2) => {
|
|
74
|
+
if (typeof error2?.status === "number" && error2.status >= 400 && error2.status < 500) {
|
|
75
|
+
return error2.status;
|
|
76
|
+
}
|
|
77
|
+
const message = typeof error2?.message === "string" ? error2.message.toLowerCase() : "";
|
|
78
|
+
if (message.includes("session not found") || message.includes("please log in again") || message.includes("otp expired") || message.includes("expired otp")) {
|
|
79
|
+
return 409;
|
|
80
|
+
}
|
|
81
|
+
return APPLICATION_ERROR_STATUS[error2?.name] ?? 400;
|
|
82
|
+
};
|
|
73
83
|
const setRefreshCookie = (ctx, refreshToken, cookieOptions) => {
|
|
74
84
|
ctx.cookies.set(sessionAuth$1.REFRESH_COOKIE_NAME, refreshToken, cookieOptions);
|
|
75
85
|
};
|
|
@@ -84,7 +94,7 @@ const getClientIp = (ctx) => {
|
|
|
84
94
|
return String(ctx.request.ip ?? ctx.ip ?? "").trim();
|
|
85
95
|
};
|
|
86
96
|
const sendApplicationError = (ctx, error2) => {
|
|
87
|
-
const derivedStatus =
|
|
97
|
+
const derivedStatus = deriveApplicationErrorStatus(error2);
|
|
88
98
|
ctx.status = derivedStatus;
|
|
89
99
|
ctx.body = {
|
|
90
100
|
data: null,
|
|
@@ -226,17 +226,18 @@ const OtpField = ()=>{
|
|
|
226
226
|
}, index))
|
|
227
227
|
})
|
|
228
228
|
}),
|
|
229
|
-
errors.code ? /*#__PURE__*/ jsxRuntime.jsx(designSystem.Box, {
|
|
230
|
-
paddingTop: 3,
|
|
231
|
-
children: /*#__PURE__*/ jsxRuntime.jsx(designSystem.Typography, {
|
|
232
|
-
id: "otp-code-error",
|
|
233
|
-
variant: "pi",
|
|
234
|
-
textColor: "danger600",
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
229
|
+
errors.code ? /*#__PURE__*/ jsxRuntime.jsx(designSystem.Box, {
|
|
230
|
+
paddingTop: 3,
|
|
231
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(designSystem.Typography, {
|
|
232
|
+
id: "otp-code-error",
|
|
233
|
+
variant: "pi",
|
|
234
|
+
textColor: "danger600",
|
|
235
|
+
textAlign: "center",
|
|
236
|
+
children: errors.code
|
|
237
|
+
})
|
|
238
|
+
}) : null
|
|
239
|
+
]
|
|
240
|
+
});
|
|
240
241
|
};
|
|
241
242
|
const Login = ({ children })=>{
|
|
242
243
|
const [apiError, setApiError] = React__namespace.useState();
|
|
@@ -204,17 +204,18 @@ const OtpField = ()=>{
|
|
|
204
204
|
}, index))
|
|
205
205
|
})
|
|
206
206
|
}),
|
|
207
|
-
errors.code ? /*#__PURE__*/ jsx(Box, {
|
|
208
|
-
paddingTop: 3,
|
|
209
|
-
children: /*#__PURE__*/ jsx(Typography, {
|
|
210
|
-
id: "otp-code-error",
|
|
211
|
-
variant: "pi",
|
|
212
|
-
textColor: "danger600",
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
207
|
+
errors.code ? /*#__PURE__*/ jsx(Box, {
|
|
208
|
+
paddingTop: 3,
|
|
209
|
+
children: /*#__PURE__*/ jsx(Typography, {
|
|
210
|
+
id: "otp-code-error",
|
|
211
|
+
variant: "pi",
|
|
212
|
+
textColor: "danger600",
|
|
213
|
+
textAlign: "center",
|
|
214
|
+
children: errors.code
|
|
215
|
+
})
|
|
216
|
+
}) : null
|
|
217
|
+
]
|
|
218
|
+
});
|
|
218
219
|
};
|
|
219
220
|
const Login = ({ children })=>{
|
|
220
221
|
const [apiError, setApiError] = React.useState();
|