@nibssplc/cams-sdk-react 0.0.1-beta.89 → 0.0.1-beta.90

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/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export * from './hooks/useCAMSAuth';
2
2
  export * from './hooks/useCAMSMSALAuth';
3
+ export { useWebAuthn } from './hooks/useFIDOAuth';
3
4
  export * from './components/ProtectedRoute';
4
5
  export { CAMSMSALProvider, useCAMSMSALContext } from './components/CAMSMSALProvider';
5
6
  export * from './components/ClientOnly';
@@ -8,5 +9,6 @@ export { default as MFAOptions } from './components/MFAOptions';
8
9
  export { default as MFAGate } from './components/MFAGate';
9
10
  export { default as LoginButton } from './components/DefaultLoginPage';
10
11
  export { default as ClientOnly } from './components/ClientOnly';
12
+ export { register, authenticate } from './components/CoreFIDO';
11
13
  export { useCAMSContext } from './context/CAMSContext';
12
14
  export * from '@nibssplc/cams-sdk';
package/dist/index.esm.js CHANGED
@@ -514,6 +514,128 @@ function useCAMSMSALAuth(options) {
514
514
  };
515
515
  }
516
516
 
517
+ /**
518
+ * Converts a base64url-encoded string to an ArrayBuffer.
519
+ * @param base64url The base64url-encoded string
520
+ */
521
+ function base64urlToArrayBuffer(base64url) {
522
+ var base64 = base64url.replace(/-/g, "+").replace(/_/g, "/");
523
+ var padLength = (4 - (base64.length % 4)) % 4;
524
+ var padded = base64 + "=".repeat(padLength);
525
+ var binaryStr = atob(padded);
526
+ var buffer = new ArrayBuffer(binaryStr.length);
527
+ var bytes = new Uint8Array(buffer);
528
+ for (var i = 0; i < binaryStr.length; i++) {
529
+ bytes[i] = binaryStr.charCodeAt(i);
530
+ }
531
+ return buffer;
532
+ }
533
+ /**
534
+ * Converts an ArrayBuffer to a base64url-encoded string.
535
+ * @param buffer The ArrayBuffer to convert
536
+ */
537
+ function arrayBufferToBase64url(buffer) {
538
+ var bytes = new Uint8Array(buffer);
539
+ var binaryStr = String.fromCharCode.apply(null, bytes);
540
+ return btoa(binaryStr)
541
+ .replace(/\+/g, "-")
542
+ .replace(/\//g, "_")
543
+ .replace(/=/g, "");
544
+ }
545
+
546
+ /**
547
+ * Initiates the WebAuthn registration process.
548
+ * It takes server-provided options, converts them for the browser API,
549
+ * calls navigator.credentials.create(), and then converts the result
550
+ * back into a JSON-friendly format.
551
+ *
552
+ * @param options - The PublicKeyCredentialCreationOptions from the server.
553
+ * @returns A promise that resolves to a JSON-serializable representation of the PublicKeyCredential.
554
+ */
555
+ function register(options) {
556
+ return __awaiter(this, void 0, void 0, function () {
557
+ var createOptions, credential, publicKeyCredential, attestationResponse;
558
+ return __generator(this, function (_a) {
559
+ switch (_a.label) {
560
+ case 0:
561
+ createOptions = __assign(__assign({}, options), { challenge: base64urlToArrayBuffer(options.challenge), user: __assign(__assign({}, options.user), { id: base64urlToArrayBuffer(options.user.id) }) });
562
+ return [4 /*yield*/, navigator.credentials.create({
563
+ publicKey: createOptions,
564
+ })];
565
+ case 1:
566
+ credential = _a.sent();
567
+ if (!credential) {
568
+ throw new Error("Failed to create credential.");
569
+ }
570
+ publicKeyCredential = credential;
571
+ attestationResponse = publicKeyCredential.response;
572
+ return [2 /*return*/, {
573
+ id: publicKeyCredential.id,
574
+ rawId: arrayBufferToBase64url(publicKeyCredential.rawId),
575
+ type: credential.type,
576
+ response: {
577
+ clientDataJSON: arrayBufferToBase64url(attestationResponse.clientDataJSON),
578
+ attestationObject: arrayBufferToBase64url(attestationResponse.attestationObject),
579
+ },
580
+ }];
581
+ }
582
+ });
583
+ });
584
+ }
585
+ /**
586
+ * Initiates the WebAuthn authentication process.
587
+ * It takes server-provided options, converts them for the browser API,
588
+ * calls navigator.credentials.get(), and then converts the result
589
+ * back into a JSON-friendly format.
590
+ *
591
+ * @param options - The PublicKeyCredentialRequestOptions from the server.
592
+ * @returns A promise that resolves to a JSON-serializable representation of the PublicKeyCredential.
593
+ */
594
+ function authenticate(options) {
595
+ return __awaiter(this, void 0, void 0, function () {
596
+ var getOptions, credential, publicKeyCredential, assertionResponse;
597
+ var _a;
598
+ return __generator(this, function (_b) {
599
+ switch (_b.label) {
600
+ case 0:
601
+ getOptions = __assign(__assign({}, options), { challenge: base64urlToArrayBuffer(options.challenge), allowCredentials: (_a = options.allowCredentials) === null || _a === void 0 ? void 0 : _a.map(function (cred) { return (__assign(__assign({}, cred), { id: base64urlToArrayBuffer(cred.id) })); }) });
602
+ return [4 /*yield*/, navigator.credentials.get({ publicKey: getOptions })];
603
+ case 1:
604
+ credential = _b.sent();
605
+ if (!credential) {
606
+ throw new Error("Failed to get credential.");
607
+ }
608
+ publicKeyCredential = credential;
609
+ assertionResponse = publicKeyCredential.response;
610
+ return [2 /*return*/, {
611
+ id: publicKeyCredential.id,
612
+ rawId: arrayBufferToBase64url(publicKeyCredential.rawId),
613
+ type: credential.type,
614
+ response: {
615
+ clientDataJSON: arrayBufferToBase64url(assertionResponse.clientDataJSON),
616
+ authenticatorData: arrayBufferToBase64url(assertionResponse.authenticatorData),
617
+ signature: arrayBufferToBase64url(assertionResponse.signature),
618
+ userHandle: assertionResponse.userHandle
619
+ ? arrayBufferToBase64url(assertionResponse.userHandle)
620
+ : null,
621
+ },
622
+ }];
623
+ }
624
+ });
625
+ });
626
+ }
627
+
628
+ /**
629
+ * A React hook that provides access to the WebAuthn `register` and `authenticate` functions.
630
+ * @returns An object containing the `register` and `authenticate` functions.
631
+ */
632
+ var useWebAuthn = function () {
633
+ return {
634
+ register: register,
635
+ authenticate: authenticate,
636
+ };
637
+ };
638
+
517
639
  var jsxRuntime = {exports: {}};
518
640
 
519
641
  var reactJsxRuntime_production = {};
@@ -1894,7 +2016,8 @@ var DefaultLoginPage = function () {
1894
2016
  var context = useCAMSContext();
1895
2017
  var login = context.login, isLoading = context.isLoading, authMode = context.authMode;
1896
2018
  var _a = useState(false), showADModal = _a[0], setShowADModal = _a[1];
1897
- var handleLogin = function () {
2019
+ var _b = useWebAuthn(), register = _b.register, authenticate = _b.authenticate;
2020
+ var handleMSALLogin = function () {
1898
2021
  if (authMode === "MSAL") {
1899
2022
  login();
1900
2023
  }
@@ -1913,15 +2036,105 @@ var DefaultLoginPage = function () {
1913
2036
  },
1914
2037
  exit: { opacity: 0, scale: 0.8, y: -50, transition: { duration: 0.3 } },
1915
2038
  };
1916
- return (jsxRuntimeExports.jsxs("main", { className: "min-h-screen bg-gray-50", children: [jsxRuntimeExports.jsx(motion.div, { initial: { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0 }, transition: { duration: 0.5 }, children: jsxRuntimeExports.jsx("div", { className: "flex h-screen items-center justify-center", children: jsxRuntimeExports.jsxs(motion.div, { variants: cardVariants, initial: "hidden", animate: "visible", exit: "exit", className: "w-full max-w-md p-6 space-y-4 bg-gray-50 rounded-2xl shadow-2xl --dark:bg-gray-800", children: [jsxRuntimeExports.jsxs(CardHeader, { className: "text-center space-y-3", children: [jsxRuntimeExports.jsx("div", { className: "w-full flex items-center justify-center", children: jsxRuntimeExports.jsx("img", { src: NIBSSLogo, alt: "NIBSS Logo", width: 265, height: 265 }) }), jsxRuntimeExports.jsx(CardTitle, { className: "text-3xl font-bold --text-gray-900 --dark:text-white", children: "NIBSS CAMS" }), jsxRuntimeExports.jsx(CardTitle, { className: "text-gray-500 dark:text-gray-400 font-bold text-lg", children: "Centralized Authentication" })] }), jsxRuntimeExports.jsxs(CardAction, { className: "w-full flex flex-col items-center justify-center text-center text-gray-500 dark:text-gray-400 mb-4", children: [jsxRuntimeExports.jsx("img", { src: AuthLogo, alt: "Auth Logo", width: 365, height: 365 }), "Kindly use the below identity providers to authenticate"] }), jsxRuntimeExports.jsxs("div", { className: "space-y-4", children: [jsxRuntimeExports.jsxs(Button
2039
+ var handleRegister = function () { return __awaiter(void 0, void 0, void 0, function () {
2040
+ var res, options, attestationResponse, error_1;
2041
+ return __generator(this, function (_a) {
2042
+ switch (_a.label) {
2043
+ case 0:
2044
+ _a.trys.push([0, 5, , 6]);
2045
+ // 1. Fetch challenge from your server
2046
+ console.log("Requesting registration challenge from server...");
2047
+ return [4 /*yield*/, fetch("/api/webauthn/register-challenge")];
2048
+ case 1:
2049
+ res = _a.sent();
2050
+ return [4 /*yield*/, res.json()];
2051
+ case 2:
2052
+ options = _a.sent();
2053
+ console.log("Received challenge:", options);
2054
+ // 2. Call the SDK to trigger the browser's passkey creation UI
2055
+ console.log("Calling SDK register function...");
2056
+ return [4 /*yield*/, register(options)];
2057
+ case 3:
2058
+ attestationResponse = _a.sent();
2059
+ console.log("Passkey created on client:", attestationResponse);
2060
+ // 3. Send the response back to the server for verification
2061
+ console.log("Sending attestation to server for verification...");
2062
+ return [4 /*yield*/, fetch("/api/webauthn/register-verify", {
2063
+ method: "POST",
2064
+ headers: { "Content-Type": "application/json" },
2065
+ body: JSON.stringify(attestationResponse),
2066
+ })];
2067
+ case 4:
2068
+ _a.sent();
2069
+ alert("✅ Registration successful! Passkey created.");
2070
+ return [3 /*break*/, 6];
2071
+ case 5:
2072
+ error_1 = _a.sent();
2073
+ console.error("Registration failed:", error_1);
2074
+ alert("❌ Could not create passkey.");
2075
+ return [3 /*break*/, 6];
2076
+ case 6: return [2 /*return*/];
2077
+ }
2078
+ });
2079
+ }); };
2080
+ var handleFIDOLogin = function () { return __awaiter(void 0, void 0, void 0, function () {
2081
+ var res, options, assertionResponse, error_2;
2082
+ return __generator(this, function (_a) {
2083
+ switch (_a.label) {
2084
+ case 0:
2085
+ _a.trys.push([0, 5, , 6]);
2086
+ // 1. Fetch authentication challenge from your server
2087
+ console.log("Requesting authentication challenge from server...");
2088
+ return [4 /*yield*/, fetch("/api/webauthn/auth-challenge")];
2089
+ case 1:
2090
+ res = _a.sent();
2091
+ return [4 /*yield*/, res.json()];
2092
+ case 2:
2093
+ options = _a.sent();
2094
+ console.log("Received challenge:", options);
2095
+ // 2. Call the SDK to trigger the browser's passkey authentication UI
2096
+ console.log("Calling SDK authenticate function...");
2097
+ return [4 /*yield*/, authenticate(options)];
2098
+ case 3:
2099
+ assertionResponse = _a.sent();
2100
+ console.log("Authentication assertion received from client:", assertionResponse);
2101
+ // 3. Send the assertion back to the server for verification
2102
+ console.log("Sending assertion to server for verification...");
2103
+ return [4 /*yield*/, fetch("/api/webauthn/auth-verify", {
2104
+ method: "POST",
2105
+ headers: { "Content-Type": "application/json" },
2106
+ body: JSON.stringify(assertionResponse),
2107
+ })];
2108
+ case 4:
2109
+ _a.sent();
2110
+ alert("🔑 Sign-in successful!");
2111
+ return [3 /*break*/, 6];
2112
+ case 5:
2113
+ error_2 = _a.sent();
2114
+ console.error("Authentication failed:", error_2);
2115
+ alert("❌ Could not sign in.");
2116
+ return [3 /*break*/, 6];
2117
+ case 6: return [2 /*return*/];
2118
+ }
2119
+ });
2120
+ }); };
2121
+ return (jsxRuntimeExports.jsxs("main", { className: "min-h-screen bg-gray-50", children: [jsxRuntimeExports.jsx(motion.div, { initial: { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0 }, transition: { duration: 0.5 }, children: jsxRuntimeExports.jsx("div", { className: "flex h-screen items-center justify-center", children: jsxRuntimeExports.jsxs(motion.div, { variants: cardVariants, initial: "hidden", animate: "visible", exit: "exit", className: "w-full max-w-md p-6 space-y-4 bg-gray-50 rounded-2xl shadow-2xl --dark:bg-gray-800", children: [jsxRuntimeExports.jsxs(CardHeader, { className: "text-center space-y-3", children: [jsxRuntimeExports.jsx("div", { className: "w-full flex items-center justify-center", children: jsxRuntimeExports.jsx("img", { src: NIBSSLogo, alt: "NIBSS Logo", width: 265, height: 265 }) }), jsxRuntimeExports.jsx(CardTitle, { className: "text-3xl font-bold --text-gray-900 --dark:text-white", children: "NIBSS CAMS" }), jsxRuntimeExports.jsx(CardTitle, { className: "text-gray-500 dark:text-gray-400 font-bold text-lg", children: "Centralized Authentication" })] }), jsxRuntimeExports.jsxs(CardAction, { className: "w-full flex flex-col items-center justify-center text-center text-gray-500 dark:text-gray-400 mb-6", children: [jsxRuntimeExports.jsx("img", { src: AuthLogo, alt: "Auth Logo", width: 365, height: 365 }), "Kindly use the below identity providers to authenticate"] }), jsxRuntimeExports.jsxs("div", { className: "space-y-4", children: [jsxRuntimeExports.jsxs(Button
2122
+ // variant="outline"
2123
+ , {
2124
+ // variant="outline"
2125
+ className: "w-full flex items-center justify-center cursor-pointer bg-[#506f4a] hover:bg-[#506f4a] rounded-lg border border-transparent px-5 py-8 text-base font-medium transition-colors duration-250", onClick: handleMSALLogin, disabled: isLoading, children: [jsxRuntimeExports.jsx("img", { src: MicrosoftLogo, alt: "Microsoft Logo", width: 35, height: 35 }), jsxRuntimeExports.jsx("span", { children: isLoading ? "Logging in..." : "Sign in with Microsoft" })] }), jsxRuntimeExports.jsxs(Button
2126
+ // variant="outline"
2127
+ , {
2128
+ // variant="outline"
2129
+ className: "w-full flex items-center justify-center cursor-pointer bg-[#506f4a] hover:bg-[#506f4a] rounded-lg border border-transparent px-5 py-8 text-base font-medium transition-colors duration-250", onClick: function () { return setShowADModal(true); }, disabled: isLoading, children: [jsxRuntimeExports.jsx(KeyIcon, { className: "w-8 h-8 text-[#506f4a]" }), jsxRuntimeExports.jsx("span", { children: isLoading ? "Logging in..." : "Sign in with ActiveDirectory" })] }), jsxRuntimeExports.jsxs(Button
1917
2130
  // variant="outline"
1918
2131
  , {
1919
2132
  // variant="outline"
1920
- className: "w-full flex items-center justify-center cursor-pointer bg-[#506f4a] hover:bg-[#506f4a] rounded-lg border border-transparent px-5 py-8 text-base font-medium transition-colors duration-250", onClick: handleLogin, disabled: isLoading, children: [jsxRuntimeExports.jsx("img", { src: MicrosoftLogo, alt: "Microsoft Logo", width: 35, height: 35 }), jsxRuntimeExports.jsx("span", { children: isLoading ? "Logging in..." : "Sign in with Microsoft" })] }), jsxRuntimeExports.jsxs(Button
2133
+ className: "w-full flex items-center justify-center cursor-pointer bg-[#506f4a] hover:bg-[#506f4a] rounded-lg border border-transparent px-5 py-8 text-base font-medium transition-colors duration-250", onClick: function () { return handleRegister; }, disabled: isLoading, children: [jsxRuntimeExports.jsx(KeyIcon, { className: "w-8 h-8 text-[#506f4a]" }), jsxRuntimeExports.jsx("span", { children: "Create a Passkey" })] }), jsxRuntimeExports.jsxs(Button
1921
2134
  // variant="outline"
1922
2135
  , {
1923
2136
  // variant="outline"
1924
- className: "w-full flex items-center justify-center cursor-pointer bg-[#506f4a] hover:bg-[#506f4a] rounded-lg border border-transparent px-5 py-8 text-base font-medium transition-colors duration-250", onClick: function () { return setShowADModal(true); }, disabled: isLoading, children: [jsxRuntimeExports.jsx(KeyIcon, { className: "w-8 h-8 text-[#506f4a]" }), jsxRuntimeExports.jsx("span", { children: isLoading ? "Logging in..." : "Sign in with ActiveDirectory" })] })] }), jsxRuntimeExports.jsxs(CardFooter, { className: "flex items-center justify-center mt-6 space-x-2 text-gray-400 text-sm", children: [jsxRuntimeExports.jsx(ShieldCheck, { className: "w-4 h-4 text-[#506f4a] pulse-glow" }), jsxRuntimeExports.jsx("span", { children: "Powered By NIBSS" })] })] }) }) }, "landing"), jsxRuntimeExports.jsx(ADLoginModal, { open: showADModal, onOpenChange: setShowADModal, onLogin: function (_a) { return __awaiter(void 0, [_a], void 0, function (_b) {
2137
+ className: "w-full flex items-center justify-center cursor-pointer bg-[#506f4a] hover:bg-[#506f4a] rounded-lg border border-transparent px-5 py-8 text-base font-medium transition-colors duration-250", onClick: function () { return handleFIDOLogin; }, disabled: isLoading, children: [jsxRuntimeExports.jsx(KeyIcon, { className: "w-8 h-8 text-[#506f4a]" }), jsxRuntimeExports.jsx("span", { children: "Sign In with Passkey" })] })] }), jsxRuntimeExports.jsxs(CardFooter, { className: "flex items-center justify-center mt-6 space-x-2 text-gray-400 text-sm", children: [jsxRuntimeExports.jsx(ShieldCheck, { className: "w-4 h-4 text-[#506f4a] pulse-glow" }), jsxRuntimeExports.jsx("span", { children: "Powered By NIBSS" })] })] }) }) }, "landing"), jsxRuntimeExports.jsx(ADLoginModal, { open: showADModal, onOpenChange: setShowADModal, onLogin: function (_a) { return __awaiter(void 0, [_a], void 0, function (_b) {
1925
2138
  var username = _b.username, password = _b.password, MFACode = _b.MFACode;
1926
2139
  return __generator(this, function (_c) {
1927
2140
  // Implement your AD login logic here
@@ -1980,5 +2193,5 @@ var MFAGate = function (_a) {
1980
2193
  return jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, { children: children });
1981
2194
  };
1982
2195
 
1983
- export { CAMSMSALProvider, CAMSProvider, ClientOnly, DefaultLoginPage as LoginButton, MFAGate, MFAOptions, ProtectedRoute, UnifiedCAMSProvider, useCAMSAuth, useCAMSContext, useCAMSMSALAuth, useCAMSMSALContext };
2196
+ export { CAMSMSALProvider, CAMSProvider, ClientOnly, DefaultLoginPage as LoginButton, MFAGate, MFAOptions, ProtectedRoute, UnifiedCAMSProvider, authenticate, register, useCAMSAuth, useCAMSContext, useCAMSMSALAuth, useCAMSMSALContext, useWebAuthn };
1984
2197
  //# sourceMappingURL=index.esm.js.map