@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/components/CoreFIDO.d.ts +20 -0
- package/dist/hooks/useFIDOAuth.d.ts +9 -0
- package/dist/index.cjs.js +220 -4
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.esm.js +218 -5
- package/dist/index.esm.js.map +1 -1
- package/dist/utils/FIDO.d.ts +10 -0
- package/package.json +2 -2
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Initiates the WebAuthn registration process.
|
|
3
|
+
* It takes server-provided options, converts them for the browser API,
|
|
4
|
+
* calls navigator.credentials.create(), and then converts the result
|
|
5
|
+
* back into a JSON-friendly format.
|
|
6
|
+
*
|
|
7
|
+
* @param options - The PublicKeyCredentialCreationOptions from the server.
|
|
8
|
+
* @returns A promise that resolves to a JSON-serializable representation of the PublicKeyCredential.
|
|
9
|
+
*/
|
|
10
|
+
export declare function register(options: PublicKeyCredentialCreationOptions): Promise<PublicKeyCredential>;
|
|
11
|
+
/**
|
|
12
|
+
* Initiates the WebAuthn authentication process.
|
|
13
|
+
* It takes server-provided options, converts them for the browser API,
|
|
14
|
+
* calls navigator.credentials.get(), and then converts the result
|
|
15
|
+
* back into a JSON-friendly format.
|
|
16
|
+
*
|
|
17
|
+
* @param options - The PublicKeyCredentialRequestOptions from the server.
|
|
18
|
+
* @returns A promise that resolves to a JSON-serializable representation of the PublicKeyCredential.
|
|
19
|
+
*/
|
|
20
|
+
export declare function authenticate(options: PublicKeyCredentialRequestOptions): Promise<PublicKeyCredential>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { register, authenticate } from '../components/CoreFIDO';
|
|
2
|
+
/**
|
|
3
|
+
* A React hook that provides access to the WebAuthn `register` and `authenticate` functions.
|
|
4
|
+
* @returns An object containing the `register` and `authenticate` functions.
|
|
5
|
+
*/
|
|
6
|
+
export declare const useWebAuthn: () => {
|
|
7
|
+
register: typeof register;
|
|
8
|
+
authenticate: typeof authenticate;
|
|
9
|
+
};
|
package/dist/index.cjs.js
CHANGED
|
@@ -535,6 +535,128 @@ function useCAMSMSALAuth(options) {
|
|
|
535
535
|
};
|
|
536
536
|
}
|
|
537
537
|
|
|
538
|
+
/**
|
|
539
|
+
* Converts a base64url-encoded string to an ArrayBuffer.
|
|
540
|
+
* @param base64url The base64url-encoded string
|
|
541
|
+
*/
|
|
542
|
+
function base64urlToArrayBuffer(base64url) {
|
|
543
|
+
var base64 = base64url.replace(/-/g, "+").replace(/_/g, "/");
|
|
544
|
+
var padLength = (4 - (base64.length % 4)) % 4;
|
|
545
|
+
var padded = base64 + "=".repeat(padLength);
|
|
546
|
+
var binaryStr = atob(padded);
|
|
547
|
+
var buffer = new ArrayBuffer(binaryStr.length);
|
|
548
|
+
var bytes = new Uint8Array(buffer);
|
|
549
|
+
for (var i = 0; i < binaryStr.length; i++) {
|
|
550
|
+
bytes[i] = binaryStr.charCodeAt(i);
|
|
551
|
+
}
|
|
552
|
+
return buffer;
|
|
553
|
+
}
|
|
554
|
+
/**
|
|
555
|
+
* Converts an ArrayBuffer to a base64url-encoded string.
|
|
556
|
+
* @param buffer The ArrayBuffer to convert
|
|
557
|
+
*/
|
|
558
|
+
function arrayBufferToBase64url(buffer) {
|
|
559
|
+
var bytes = new Uint8Array(buffer);
|
|
560
|
+
var binaryStr = String.fromCharCode.apply(null, bytes);
|
|
561
|
+
return btoa(binaryStr)
|
|
562
|
+
.replace(/\+/g, "-")
|
|
563
|
+
.replace(/\//g, "_")
|
|
564
|
+
.replace(/=/g, "");
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
/**
|
|
568
|
+
* Initiates the WebAuthn registration process.
|
|
569
|
+
* It takes server-provided options, converts them for the browser API,
|
|
570
|
+
* calls navigator.credentials.create(), and then converts the result
|
|
571
|
+
* back into a JSON-friendly format.
|
|
572
|
+
*
|
|
573
|
+
* @param options - The PublicKeyCredentialCreationOptions from the server.
|
|
574
|
+
* @returns A promise that resolves to a JSON-serializable representation of the PublicKeyCredential.
|
|
575
|
+
*/
|
|
576
|
+
function register(options) {
|
|
577
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
578
|
+
var createOptions, credential, publicKeyCredential, attestationResponse;
|
|
579
|
+
return __generator(this, function (_a) {
|
|
580
|
+
switch (_a.label) {
|
|
581
|
+
case 0:
|
|
582
|
+
createOptions = __assign(__assign({}, options), { challenge: base64urlToArrayBuffer(options.challenge), user: __assign(__assign({}, options.user), { id: base64urlToArrayBuffer(options.user.id) }) });
|
|
583
|
+
return [4 /*yield*/, navigator.credentials.create({
|
|
584
|
+
publicKey: createOptions,
|
|
585
|
+
})];
|
|
586
|
+
case 1:
|
|
587
|
+
credential = _a.sent();
|
|
588
|
+
if (!credential) {
|
|
589
|
+
throw new Error("Failed to create credential.");
|
|
590
|
+
}
|
|
591
|
+
publicKeyCredential = credential;
|
|
592
|
+
attestationResponse = publicKeyCredential.response;
|
|
593
|
+
return [2 /*return*/, {
|
|
594
|
+
id: publicKeyCredential.id,
|
|
595
|
+
rawId: arrayBufferToBase64url(publicKeyCredential.rawId),
|
|
596
|
+
type: credential.type,
|
|
597
|
+
response: {
|
|
598
|
+
clientDataJSON: arrayBufferToBase64url(attestationResponse.clientDataJSON),
|
|
599
|
+
attestationObject: arrayBufferToBase64url(attestationResponse.attestationObject),
|
|
600
|
+
},
|
|
601
|
+
}];
|
|
602
|
+
}
|
|
603
|
+
});
|
|
604
|
+
});
|
|
605
|
+
}
|
|
606
|
+
/**
|
|
607
|
+
* Initiates the WebAuthn authentication process.
|
|
608
|
+
* It takes server-provided options, converts them for the browser API,
|
|
609
|
+
* calls navigator.credentials.get(), and then converts the result
|
|
610
|
+
* back into a JSON-friendly format.
|
|
611
|
+
*
|
|
612
|
+
* @param options - The PublicKeyCredentialRequestOptions from the server.
|
|
613
|
+
* @returns A promise that resolves to a JSON-serializable representation of the PublicKeyCredential.
|
|
614
|
+
*/
|
|
615
|
+
function authenticate(options) {
|
|
616
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
617
|
+
var getOptions, credential, publicKeyCredential, assertionResponse;
|
|
618
|
+
var _a;
|
|
619
|
+
return __generator(this, function (_b) {
|
|
620
|
+
switch (_b.label) {
|
|
621
|
+
case 0:
|
|
622
|
+
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) })); }) });
|
|
623
|
+
return [4 /*yield*/, navigator.credentials.get({ publicKey: getOptions })];
|
|
624
|
+
case 1:
|
|
625
|
+
credential = _b.sent();
|
|
626
|
+
if (!credential) {
|
|
627
|
+
throw new Error("Failed to get credential.");
|
|
628
|
+
}
|
|
629
|
+
publicKeyCredential = credential;
|
|
630
|
+
assertionResponse = publicKeyCredential.response;
|
|
631
|
+
return [2 /*return*/, {
|
|
632
|
+
id: publicKeyCredential.id,
|
|
633
|
+
rawId: arrayBufferToBase64url(publicKeyCredential.rawId),
|
|
634
|
+
type: credential.type,
|
|
635
|
+
response: {
|
|
636
|
+
clientDataJSON: arrayBufferToBase64url(assertionResponse.clientDataJSON),
|
|
637
|
+
authenticatorData: arrayBufferToBase64url(assertionResponse.authenticatorData),
|
|
638
|
+
signature: arrayBufferToBase64url(assertionResponse.signature),
|
|
639
|
+
userHandle: assertionResponse.userHandle
|
|
640
|
+
? arrayBufferToBase64url(assertionResponse.userHandle)
|
|
641
|
+
: null,
|
|
642
|
+
},
|
|
643
|
+
}];
|
|
644
|
+
}
|
|
645
|
+
});
|
|
646
|
+
});
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
/**
|
|
650
|
+
* A React hook that provides access to the WebAuthn `register` and `authenticate` functions.
|
|
651
|
+
* @returns An object containing the `register` and `authenticate` functions.
|
|
652
|
+
*/
|
|
653
|
+
var useWebAuthn = function () {
|
|
654
|
+
return {
|
|
655
|
+
register: register,
|
|
656
|
+
authenticate: authenticate,
|
|
657
|
+
};
|
|
658
|
+
};
|
|
659
|
+
|
|
538
660
|
var jsxRuntime = {exports: {}};
|
|
539
661
|
|
|
540
662
|
var reactJsxRuntime_production = {};
|
|
@@ -1915,7 +2037,8 @@ var DefaultLoginPage = function () {
|
|
|
1915
2037
|
var context = useCAMSContext();
|
|
1916
2038
|
var login = context.login, isLoading = context.isLoading, authMode = context.authMode;
|
|
1917
2039
|
var _a = React.useState(false), showADModal = _a[0], setShowADModal = _a[1];
|
|
1918
|
-
var
|
|
2040
|
+
var _b = useWebAuthn(), register = _b.register, authenticate = _b.authenticate;
|
|
2041
|
+
var handleMSALLogin = function () {
|
|
1919
2042
|
if (authMode === "MSAL") {
|
|
1920
2043
|
login();
|
|
1921
2044
|
}
|
|
@@ -1934,15 +2057,105 @@ var DefaultLoginPage = function () {
|
|
|
1934
2057
|
},
|
|
1935
2058
|
exit: { opacity: 0, scale: 0.8, y: -50, transition: { duration: 0.3 } },
|
|
1936
2059
|
};
|
|
1937
|
-
|
|
2060
|
+
var handleRegister = function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
2061
|
+
var res, options, attestationResponse, error_1;
|
|
2062
|
+
return __generator(this, function (_a) {
|
|
2063
|
+
switch (_a.label) {
|
|
2064
|
+
case 0:
|
|
2065
|
+
_a.trys.push([0, 5, , 6]);
|
|
2066
|
+
// 1. Fetch challenge from your server
|
|
2067
|
+
console.log("Requesting registration challenge from server...");
|
|
2068
|
+
return [4 /*yield*/, fetch("/api/webauthn/register-challenge")];
|
|
2069
|
+
case 1:
|
|
2070
|
+
res = _a.sent();
|
|
2071
|
+
return [4 /*yield*/, res.json()];
|
|
2072
|
+
case 2:
|
|
2073
|
+
options = _a.sent();
|
|
2074
|
+
console.log("Received challenge:", options);
|
|
2075
|
+
// 2. Call the SDK to trigger the browser's passkey creation UI
|
|
2076
|
+
console.log("Calling SDK register function...");
|
|
2077
|
+
return [4 /*yield*/, register(options)];
|
|
2078
|
+
case 3:
|
|
2079
|
+
attestationResponse = _a.sent();
|
|
2080
|
+
console.log("Passkey created on client:", attestationResponse);
|
|
2081
|
+
// 3. Send the response back to the server for verification
|
|
2082
|
+
console.log("Sending attestation to server for verification...");
|
|
2083
|
+
return [4 /*yield*/, fetch("/api/webauthn/register-verify", {
|
|
2084
|
+
method: "POST",
|
|
2085
|
+
headers: { "Content-Type": "application/json" },
|
|
2086
|
+
body: JSON.stringify(attestationResponse),
|
|
2087
|
+
})];
|
|
2088
|
+
case 4:
|
|
2089
|
+
_a.sent();
|
|
2090
|
+
alert("✅ Registration successful! Passkey created.");
|
|
2091
|
+
return [3 /*break*/, 6];
|
|
2092
|
+
case 5:
|
|
2093
|
+
error_1 = _a.sent();
|
|
2094
|
+
console.error("Registration failed:", error_1);
|
|
2095
|
+
alert("❌ Could not create passkey.");
|
|
2096
|
+
return [3 /*break*/, 6];
|
|
2097
|
+
case 6: return [2 /*return*/];
|
|
2098
|
+
}
|
|
2099
|
+
});
|
|
2100
|
+
}); };
|
|
2101
|
+
var handleFIDOLogin = function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
2102
|
+
var res, options, assertionResponse, error_2;
|
|
2103
|
+
return __generator(this, function (_a) {
|
|
2104
|
+
switch (_a.label) {
|
|
2105
|
+
case 0:
|
|
2106
|
+
_a.trys.push([0, 5, , 6]);
|
|
2107
|
+
// 1. Fetch authentication challenge from your server
|
|
2108
|
+
console.log("Requesting authentication challenge from server...");
|
|
2109
|
+
return [4 /*yield*/, fetch("/api/webauthn/auth-challenge")];
|
|
2110
|
+
case 1:
|
|
2111
|
+
res = _a.sent();
|
|
2112
|
+
return [4 /*yield*/, res.json()];
|
|
2113
|
+
case 2:
|
|
2114
|
+
options = _a.sent();
|
|
2115
|
+
console.log("Received challenge:", options);
|
|
2116
|
+
// 2. Call the SDK to trigger the browser's passkey authentication UI
|
|
2117
|
+
console.log("Calling SDK authenticate function...");
|
|
2118
|
+
return [4 /*yield*/, authenticate(options)];
|
|
2119
|
+
case 3:
|
|
2120
|
+
assertionResponse = _a.sent();
|
|
2121
|
+
console.log("Authentication assertion received from client:", assertionResponse);
|
|
2122
|
+
// 3. Send the assertion back to the server for verification
|
|
2123
|
+
console.log("Sending assertion to server for verification...");
|
|
2124
|
+
return [4 /*yield*/, fetch("/api/webauthn/auth-verify", {
|
|
2125
|
+
method: "POST",
|
|
2126
|
+
headers: { "Content-Type": "application/json" },
|
|
2127
|
+
body: JSON.stringify(assertionResponse),
|
|
2128
|
+
})];
|
|
2129
|
+
case 4:
|
|
2130
|
+
_a.sent();
|
|
2131
|
+
alert("🔑 Sign-in successful!");
|
|
2132
|
+
return [3 /*break*/, 6];
|
|
2133
|
+
case 5:
|
|
2134
|
+
error_2 = _a.sent();
|
|
2135
|
+
console.error("Authentication failed:", error_2);
|
|
2136
|
+
alert("❌ Could not sign in.");
|
|
2137
|
+
return [3 /*break*/, 6];
|
|
2138
|
+
case 6: return [2 /*return*/];
|
|
2139
|
+
}
|
|
2140
|
+
});
|
|
2141
|
+
}); };
|
|
2142
|
+
return (jsxRuntimeExports.jsxs("main", { className: "min-h-screen bg-gray-50", children: [jsxRuntimeExports.jsx(framerMotion.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(framerMotion.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
|
|
2143
|
+
// variant="outline"
|
|
2144
|
+
, {
|
|
2145
|
+
// variant="outline"
|
|
2146
|
+
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
|
|
2147
|
+
// variant="outline"
|
|
2148
|
+
, {
|
|
2149
|
+
// variant="outline"
|
|
2150
|
+
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(lucideReact.KeyIcon, { className: "w-8 h-8 text-[#506f4a]" }), jsxRuntimeExports.jsx("span", { children: isLoading ? "Logging in..." : "Sign in with ActiveDirectory" })] }), jsxRuntimeExports.jsxs(Button
|
|
1938
2151
|
// variant="outline"
|
|
1939
2152
|
, {
|
|
1940
2153
|
// variant="outline"
|
|
1941
|
-
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:
|
|
2154
|
+
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(lucideReact.KeyIcon, { className: "w-8 h-8 text-[#506f4a]" }), jsxRuntimeExports.jsx("span", { children: "Create a Passkey" })] }), jsxRuntimeExports.jsxs(Button
|
|
1942
2155
|
// variant="outline"
|
|
1943
2156
|
, {
|
|
1944
2157
|
// variant="outline"
|
|
1945
|
-
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
|
|
2158
|
+
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(lucideReact.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(lucideReact.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) {
|
|
1946
2159
|
var username = _b.username, password = _b.password, MFACode = _b.MFACode;
|
|
1947
2160
|
return __generator(this, function (_c) {
|
|
1948
2161
|
// Implement your AD login logic here
|
|
@@ -2009,10 +2222,13 @@ exports.MFAGate = MFAGate;
|
|
|
2009
2222
|
exports.MFAOptions = MFAOptions;
|
|
2010
2223
|
exports.ProtectedRoute = ProtectedRoute;
|
|
2011
2224
|
exports.UnifiedCAMSProvider = UnifiedCAMSProvider;
|
|
2225
|
+
exports.authenticate = authenticate;
|
|
2226
|
+
exports.register = register;
|
|
2012
2227
|
exports.useCAMSAuth = useCAMSAuth;
|
|
2013
2228
|
exports.useCAMSContext = useCAMSContext;
|
|
2014
2229
|
exports.useCAMSMSALAuth = useCAMSMSALAuth;
|
|
2015
2230
|
exports.useCAMSMSALContext = useCAMSMSALContext;
|
|
2231
|
+
exports.useWebAuthn = useWebAuthn;
|
|
2016
2232
|
Object.keys(camsSdk).forEach(function (k) {
|
|
2017
2233
|
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
|
|
2018
2234
|
enumerable: true,
|