@nibssplc/cams-sdk-react 0.0.1-beta.63 → 0.0.1-beta.65
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/dist/hooks/useOTPHandler.d.ts +2 -2
- package/dist/index.cjs.js +99 -27
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm.js +99 -27
- package/dist/index.esm.js.map +1 -1
- package/dist/utils/DeviceID.d.ts +1 -0
- package/package.json +1 -1
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
export declare const useOTPHandler: ({ provider, accessToken, idToken, appCode, authenticationType,
|
|
1
|
+
export declare const useOTPHandler: ({ provider, accessToken, idToken, appCode, authenticationType, MFAEndpoint, onAuthComplete, }: {
|
|
2
2
|
provider: string;
|
|
3
3
|
accessToken: string;
|
|
4
4
|
idToken: string;
|
|
5
5
|
appCode: string;
|
|
6
6
|
authenticationType: "AuthenticatorCode" | "EmailOTP" | null;
|
|
7
|
-
|
|
7
|
+
MFAEndpoint?: string;
|
|
8
8
|
onAuthComplete: (state: boolean, data: UserValidatedResponse | null) => void;
|
|
9
9
|
}) => {
|
|
10
10
|
handleSubmitOTP: (authenticationValue: string) => Promise<boolean>;
|
package/dist/index.cjs.js
CHANGED
|
@@ -1230,7 +1230,7 @@ function CAMSProviderCore(props) {
|
|
|
1230
1230
|
}, [mode, auth, userProfile]);
|
|
1231
1231
|
var value = React.useMemo(function () {
|
|
1232
1232
|
return (__assign(__assign({}, auth), { logout: enhancedLogout, userProfile: userProfile, setUserProfile: setUserProfile, authMode: mode }));
|
|
1233
|
-
}, [auth, userProfile, mode]);
|
|
1233
|
+
}, [auth, userProfile, mode, mode === "MSAL" && "requiresMFA" in auth ? auth.requiresMFA : null]);
|
|
1234
1234
|
return jsxRuntimeExports.jsx(CAMSContext.Provider, { value: value, children: children });
|
|
1235
1235
|
}
|
|
1236
1236
|
function UnifiedCAMSProvider(props) {
|
|
@@ -1592,8 +1592,48 @@ var AuthSuccessAnimation = function (_a) {
|
|
|
1592
1592
|
return (jsxRuntimeExports.jsxs(framerMotion.motion.div, { initial: { opacity: 0, scale: 0.8 }, animate: { opacity: 1, scale: 1 }, transition: { duration: 0.5, ease: "easeOut" }, className: "flex flex-col items-center justify-center space-y-6 p-8", onAnimationComplete: onComplete, children: [jsxRuntimeExports.jsx(framerMotion.motion.div, { initial: { scale: 0 }, animate: { scale: 1 }, transition: { delay: 0.2, duration: 0.6, type: "spring", stiffness: 200 }, children: jsxRuntimeExports.jsx(lucideReact.CheckCircle, { className: "w-20 h-20 text-green-500" }) }), jsxRuntimeExports.jsxs(framerMotion.motion.div, { initial: { y: 20, opacity: 0 }, animate: { y: 0, opacity: 1 }, transition: { delay: 0.4, duration: 0.5 }, className: "text-center space-y-2", children: [jsxRuntimeExports.jsx("h2", { className: "text-2xl font-bold text-green-600", children: "Authentication Successful!" }), jsxRuntimeExports.jsx("p", { className: "text-gray-600", children: "Redirecting you to the application..." })] }), jsxRuntimeExports.jsx(framerMotion.motion.div, { initial: { width: 0 }, animate: { width: "100%" }, transition: { delay: 0.8, duration: 2 }, className: "h-1 bg-green-500 rounded-full max-w-xs" })] }));
|
|
1593
1593
|
};
|
|
1594
1594
|
|
|
1595
|
+
// Function to parse userAgent and generate a device ID
|
|
1596
|
+
var GenerateDeviceId = function () {
|
|
1597
|
+
var _a;
|
|
1598
|
+
if (typeof window === "undefined" || !window.navigator) {
|
|
1599
|
+
return "unknown-device";
|
|
1600
|
+
}
|
|
1601
|
+
var userAgent = window.navigator.userAgent;
|
|
1602
|
+
var deviceId = "";
|
|
1603
|
+
// Parse browser, version, OS, and device type
|
|
1604
|
+
var browserMatch = Array.from(userAgent.matchAll(/(Chrome|Firefox|Safari|Edge|Opera)\/([\d.]+)/ig));
|
|
1605
|
+
var osMatch = Array.from(userAgent.matchAll(/\(([^)]+)\)/g));
|
|
1606
|
+
var isMobile = /Mobile|Android|iPhone|iPad/i.test(userAgent);
|
|
1607
|
+
// Browser info
|
|
1608
|
+
if (browserMatch.length > 0) {
|
|
1609
|
+
var _b = browserMatch[0], browserName = _b[1], browserVersion = _b[2];
|
|
1610
|
+
var majorVersion = browserVersion.split(".")[0];
|
|
1611
|
+
deviceId += "".concat(browserName, "-").concat(majorVersion);
|
|
1612
|
+
}
|
|
1613
|
+
else {
|
|
1614
|
+
deviceId += "UnknownBrowser";
|
|
1615
|
+
}
|
|
1616
|
+
// OS info
|
|
1617
|
+
if (osMatch.length > 0) {
|
|
1618
|
+
var osInfo = osMatch[0][1]
|
|
1619
|
+
.split(";")[0]
|
|
1620
|
+
.trim()
|
|
1621
|
+
.replace(/[\s/()]/g, "_");
|
|
1622
|
+
deviceId += "_".concat(osInfo);
|
|
1623
|
+
}
|
|
1624
|
+
else {
|
|
1625
|
+
deviceId += "_UnknownOS";
|
|
1626
|
+
}
|
|
1627
|
+
// Device type
|
|
1628
|
+
deviceId += isMobile ? "_Mobile" : "_Desktop";
|
|
1629
|
+
// Add a simple hash of userAgent for uniqueness
|
|
1630
|
+
var hash = btoa(userAgent).slice(0, 8);
|
|
1631
|
+
deviceId += "_".concat(hash);
|
|
1632
|
+
return (_a = deviceId.replace(/[^a-zA-Z0-9-_]/g, "_")) !== null && _a !== void 0 ? _a : "unknown-device";
|
|
1633
|
+
};
|
|
1634
|
+
|
|
1595
1635
|
var useOTPHandler = function (_a) {
|
|
1596
|
-
var provider = _a.provider, accessToken = _a.accessToken, idToken = _a.idToken, appCode = _a.appCode, authenticationType = _a.authenticationType,
|
|
1636
|
+
var provider = _a.provider, accessToken = _a.accessToken, idToken = _a.idToken, appCode = _a.appCode, authenticationType = _a.authenticationType, MFAEndpoint = _a.MFAEndpoint, onAuthComplete = _a.onAuthComplete;
|
|
1597
1637
|
var _b = React.useState(false), loading = _b[0], setLoading = _b[1];
|
|
1598
1638
|
var _c = React.useState(0), attemptCount = _c[0], setAttemptCount = _c[1];
|
|
1599
1639
|
var _d = React.useState(false), isMaxAttemptsReached = _d[0], setIsMaxAttemptsReached = _d[1];
|
|
@@ -1617,13 +1657,18 @@ var useOTPHandler = function (_a) {
|
|
|
1617
1657
|
setAttemptCount(currentAttempt);
|
|
1618
1658
|
if (authenticationType === null)
|
|
1619
1659
|
return [2 /*return*/, false];
|
|
1620
|
-
return [4 /*yield*/, axios.post(
|
|
1660
|
+
return [4 /*yield*/, axios.post(MFAEndpoint || "/api/auth/verify-mfa", {
|
|
1621
1661
|
provider: provider,
|
|
1622
1662
|
accessToken: accessToken,
|
|
1623
1663
|
idToken: idToken,
|
|
1624
1664
|
authenticationType: authenticationType,
|
|
1625
1665
|
MFACode: authenticationValue,
|
|
1626
1666
|
appCode: appCode,
|
|
1667
|
+
}, {
|
|
1668
|
+
headers: {
|
|
1669
|
+
"X-Device-ID": GenerateDeviceId(),
|
|
1670
|
+
},
|
|
1671
|
+
timeout: 605000,
|
|
1627
1672
|
})];
|
|
1628
1673
|
case 2:
|
|
1629
1674
|
response = (_a.sent()).data;
|
|
@@ -1667,7 +1712,7 @@ var useOTPHandler = function (_a) {
|
|
|
1667
1712
|
idToken,
|
|
1668
1713
|
authenticationType,
|
|
1669
1714
|
onAuthComplete,
|
|
1670
|
-
|
|
1715
|
+
MFAEndpoint,
|
|
1671
1716
|
attemptCount,
|
|
1672
1717
|
isMaxAttemptsReached,
|
|
1673
1718
|
]);
|
|
@@ -1692,33 +1737,54 @@ var MFAOptions = function (_a) {
|
|
|
1692
1737
|
var _d = React.useState(false), otpVisible = _d[0], setOtpVisible = _d[1];
|
|
1693
1738
|
var _e = React.useState(false), showSuccessAnimation = _e[0], setShowSuccessAnimation = _e[1];
|
|
1694
1739
|
var _f = React.useState(null), authType = _f[0], setAuthType = _f[1];
|
|
1740
|
+
var _g = React.useState(""), lastOTPCode = _g[0], setLastOTPCode = _g[1];
|
|
1695
1741
|
var context = useCAMSContext();
|
|
1696
|
-
var
|
|
1742
|
+
var _h = context.authMode === "MSAL" && "sendEmailOTP" in context
|
|
1697
1743
|
? context
|
|
1698
|
-
: { sendEmailOTP: null }
|
|
1744
|
+
: { sendEmailOTP: null, completeMFA: null }, sendEmailOTP = _h.sendEmailOTP, completeMFA = _h.completeMFA;
|
|
1699
1745
|
var accessToken = context.authMode === "MSAL" ? context.accessToken : "";
|
|
1700
1746
|
var idToken = context.authMode === "MSAL" ? context.idToken : "";
|
|
1701
|
-
var
|
|
1747
|
+
var _j = useOTPHandler({
|
|
1702
1748
|
accessToken: accessToken || "",
|
|
1703
1749
|
idToken: idToken || "",
|
|
1704
1750
|
provider: "MSAL",
|
|
1705
1751
|
appCode: context.appCode || "",
|
|
1706
1752
|
authenticationType: authType,
|
|
1707
|
-
|
|
1708
|
-
onAuthComplete: function (state, data) {
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1753
|
+
MFAEndpoint: MFAEndpoint,
|
|
1754
|
+
onAuthComplete: function (state, data) { return __awaiter(void 0, void 0, void 0, function () {
|
|
1755
|
+
var error_1;
|
|
1756
|
+
return __generator(this, function (_a) {
|
|
1757
|
+
switch (_a.label) {
|
|
1758
|
+
case 0:
|
|
1759
|
+
if (!state) return [3 /*break*/, 5];
|
|
1760
|
+
if (!(completeMFA && authType && lastOTPCode)) return [3 /*break*/, 4];
|
|
1761
|
+
_a.label = 1;
|
|
1762
|
+
case 1:
|
|
1763
|
+
_a.trys.push([1, 3, , 4]);
|
|
1764
|
+
return [4 /*yield*/, completeMFA(lastOTPCode, authType)];
|
|
1765
|
+
case 2:
|
|
1766
|
+
_a.sent();
|
|
1767
|
+
return [3 /*break*/, 4];
|
|
1768
|
+
case 3:
|
|
1769
|
+
error_1 = _a.sent();
|
|
1770
|
+
console.error("Failed to complete MFA:", error_1);
|
|
1771
|
+
return [3 /*break*/, 4];
|
|
1772
|
+
case 4:
|
|
1773
|
+
setShowSuccessAnimation(true);
|
|
1774
|
+
sonner.toast.success(jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 text-sm text-green-600 bg-green-50 p-3 rounded-lg", children: [jsxRuntimeExports.jsx(lucideReact.ShieldCheck, { className: "w-4 h-4" }), jsxRuntimeExports.jsx("span", { children: "Multi-Factor Authentication Successful" })] }));
|
|
1775
|
+
setTimeout(function () { return onComplete === null || onComplete === void 0 ? void 0 : onComplete(true); }, 2000);
|
|
1776
|
+
return [3 /*break*/, 6];
|
|
1777
|
+
case 5:
|
|
1778
|
+
sonner.toast.error(jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 text-sm text-red-600 bg-red-50 p-3 rounded-lg", children: [jsxRuntimeExports.jsx(lucideReact.ShieldClose, { className: "w-4 h-4" }), jsxRuntimeExports.jsx("span", { children: (data === null || data === void 0 ? void 0 : data.message) || "Invalid code. Please try again." })] }));
|
|
1779
|
+
if (isMaxAttemptsReached) {
|
|
1780
|
+
setTimeout(function () { return onComplete === null || onComplete === void 0 ? void 0 : onComplete(false); }, 1000);
|
|
1781
|
+
}
|
|
1782
|
+
_a.label = 6;
|
|
1783
|
+
case 6: return [2 /*return*/];
|
|
1718
1784
|
}
|
|
1719
|
-
}
|
|
1720
|
-
},
|
|
1721
|
-
}), handleSubmitOTP =
|
|
1785
|
+
});
|
|
1786
|
+
}); },
|
|
1787
|
+
}), handleSubmitOTP = _j.handleSubmitOTP, loading = _j.loading, setLoading = _j.setLoading, attemptCount = _j.attemptCount, remainingAttempts = _j.remainingAttempts, isMaxAttemptsReached = _j.isMaxAttemptsReached, resetAttempts = _j.resetAttempts;
|
|
1722
1788
|
var handleGoBack = function () {
|
|
1723
1789
|
setAuthType(null);
|
|
1724
1790
|
setOtpVisible(false);
|
|
@@ -1727,9 +1793,9 @@ var MFAOptions = function (_a) {
|
|
|
1727
1793
|
};
|
|
1728
1794
|
// Show success animation if authentication is successful
|
|
1729
1795
|
if (showSuccessAnimation) {
|
|
1730
|
-
return (jsxRuntimeExports.jsx(Card, { className: "mx-auto space-y-6 p-6 bg-white rounded-lg shadow-md", children: jsxRuntimeExports.jsx(AuthSuccessAnimation, { onComplete: function () {
|
|
1731
|
-
|
|
1732
|
-
|
|
1796
|
+
return (jsxRuntimeExports.jsx("div", { className: "flex justify-center items-center h-dvh", children: jsxRuntimeExports.jsx(Card, { className: "mx-auto space-y-6 p-6 bg-white rounded-lg shadow-md", children: jsxRuntimeExports.jsx(AuthSuccessAnimation, { onComplete: function () {
|
|
1797
|
+
// Animation completed, can add additional logic here if needed
|
|
1798
|
+
} }) }) }));
|
|
1733
1799
|
}
|
|
1734
1800
|
var content = jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, {});
|
|
1735
1801
|
if (!authType) {
|
|
@@ -1765,12 +1831,18 @@ var MFAOptions = function (_a) {
|
|
|
1765
1831
|
setAuthType(null);
|
|
1766
1832
|
setOtpVisible(false);
|
|
1767
1833
|
setValue("");
|
|
1768
|
-
}, children: [jsxRuntimeExports.jsx(DialogHeader, { children: jsxRuntimeExports.jsx(DialogTitle, { children: "Email OTP" }) }), jsxRuntimeExports.jsx(DialogContent, { className: "sm:max-w-[425px]", children: jsxRuntimeExports.jsxs("div", { className: "space-y-4", children: [jsxRuntimeExports.jsx(GenericOTPVerifier, { value: value, setValue: setValue, isDisabled: loading || isMaxAttemptsReached, onChangeOTP:
|
|
1834
|
+
}, children: [jsxRuntimeExports.jsx(DialogHeader, { children: jsxRuntimeExports.jsx(DialogTitle, { children: "Email OTP" }) }), jsxRuntimeExports.jsx(DialogContent, { className: "sm:max-w-[425px]", children: jsxRuntimeExports.jsxs("div", { className: "space-y-4", children: [jsxRuntimeExports.jsx(GenericOTPVerifier, { value: value, setValue: setValue, isDisabled: loading || isMaxAttemptsReached, onChangeOTP: function (code) {
|
|
1835
|
+
setLastOTPCode(code);
|
|
1836
|
+
return handleSubmitOTP(code);
|
|
1837
|
+
}, fieldName: "EmailOTP", attemptCount: attemptCount, remainingAttempts: remainingAttempts, isMaxAttemptsReached: isMaxAttemptsReached }), jsxRuntimeExports.jsx(Button, { variant: "ghost", className: "w-full text-sm", onClick: handleGoBack, children: "\u2190 Choose different method" })] }) })] }));
|
|
1769
1838
|
}
|
|
1770
1839
|
else if (authType === "AuthenticatorCode") {
|
|
1771
|
-
content = (jsxRuntimeExports.jsxs(Dialog, { open: otpVisible, onOpenChange: handleGoBack, children: [jsxRuntimeExports.jsx(DialogHeader, { children: jsxRuntimeExports.jsx(DialogTitle, { children: "Authenticator App" }) }), jsxRuntimeExports.jsx(DialogContent, { className: "sm:max-w-[425px]", children: loading ? (jsxRuntimeExports.jsx("div", { className: "p-3 flex justify-center items-center", children: jsxRuntimeExports.jsx(LoadingSpinner, {}) })) : (jsxRuntimeExports.jsxs("div", { className: "space-y-4", children: [jsxRuntimeExports.jsx("p", { className: "text-sm text-gray-600 text-center", children: "Enter the 6-digit Code from your Authenticator app" }), jsxRuntimeExports.jsx(GenericOTPVerifier, { value: value, setValue: setValue, isDisabled: loading || isMaxAttemptsReached, onChangeOTP:
|
|
1840
|
+
content = (jsxRuntimeExports.jsxs(Dialog, { open: otpVisible, onOpenChange: handleGoBack, children: [jsxRuntimeExports.jsx(DialogHeader, { children: jsxRuntimeExports.jsx(DialogTitle, { children: "Authenticator App" }) }), jsxRuntimeExports.jsx(DialogContent, { className: "sm:max-w-[425px]", children: loading ? (jsxRuntimeExports.jsx("div", { className: "p-3 flex justify-center items-center", children: jsxRuntimeExports.jsx(LoadingSpinner, {}) })) : (jsxRuntimeExports.jsxs("div", { className: "space-y-4", children: [jsxRuntimeExports.jsx("p", { className: "text-sm text-gray-600 text-center", children: "Enter the 6-digit Code from your Authenticator app" }), jsxRuntimeExports.jsx(GenericOTPVerifier, { value: value, setValue: setValue, isDisabled: loading || isMaxAttemptsReached, onChangeOTP: function (code) {
|
|
1841
|
+
setLastOTPCode(code);
|
|
1842
|
+
return handleSubmitOTP(code);
|
|
1843
|
+
}, fieldName: "AuthenticatorCode", attemptCount: attemptCount, remainingAttempts: remainingAttempts, isMaxAttemptsReached: isMaxAttemptsReached })] })) })] }));
|
|
1772
1844
|
}
|
|
1773
|
-
return (jsxRuntimeExports.jsx("div", { className: "flex justify-center items-center h-dvh", children: jsxRuntimeExports.jsxs(Card, { className: "mx-auto space-y-6 p-6 bg-white rounded-lg shadow-md", children: [jsxRuntimeExports.jsxs(CardHeader, { children: [jsxRuntimeExports.jsx("div", { className: "flex justify-center items", children: jsxRuntimeExports.jsx("img", { src: OTPAuthenticationImg, alt: "NIBSS Logo", width: 365, height: 365 }) }), jsxRuntimeExports.jsx(CardTitle, { className: "text-3xl font-bold mb-6 text-center", children: "Two-Factor Authentication" }), jsxRuntimeExports.jsx(CardTitle, { className: "text-gray-300 text-base -tracking-wide text-center", children: "Your Microsoft account has been validated. Please complete two-factor authentication to continue." })] }), jsxRuntimeExports.jsx(CardContent, { children: content }), jsxRuntimeExports.jsxs(CardFooter, { className: "flex items-center justify-center mt-6 space-x-2 text-gray-400 text-sm", children: [jsxRuntimeExports.jsx(lucideReact.ShieldCheck, { className: "w-4 h-4 text-[#506f4a] pulse-glow" }), jsxRuntimeExports.jsx("span", { children: "Powered By NIBSS" })] })] }) }));
|
|
1845
|
+
return (jsxRuntimeExports.jsx("div", { className: "flex justify-center items-center h-dvh", children: jsxRuntimeExports.jsxs(Card, { className: "mx-auto space-y-6 p-6 bg-white rounded-lg shadow-md", children: [jsxRuntimeExports.jsxs(CardHeader, { children: [jsxRuntimeExports.jsx("div", { className: "flex justify-center items", children: jsxRuntimeExports.jsx("img", { src: OTPAuthenticationImg, alt: "NIBSS Logo", width: 365, height: 365 }) }), jsxRuntimeExports.jsx(CardTitle, { className: "text-3xl font-bold mb-6 text-center", children: "Two-Factor Authentication" }), jsxRuntimeExports.jsx(CardTitle, { className: "text-gray-300 text-base -tracking-wide text-center", children: "Your Microsoft account has been validated. Please complete two-factor authentication to continue." })] }), jsxRuntimeExports.jsx(CardContent, { className: "max-w-[80%]", children: content }), jsxRuntimeExports.jsxs(CardFooter, { className: "flex items-center justify-center mt-6 space-x-2 text-gray-400 text-sm", children: [jsxRuntimeExports.jsx(lucideReact.ShieldCheck, { className: "w-4 h-4 text-[#506f4a] pulse-glow" }), jsxRuntimeExports.jsx("span", { children: "Powered By NIBSS" })] })] }) }));
|
|
1774
1846
|
};
|
|
1775
1847
|
|
|
1776
1848
|
var LoginButton = function () {
|