From 7f5fc2884d230e761a286eedb41d03e0a6a540de Mon Sep 17 00:00:00 2001 From: root Date: Wed, 4 Sep 2024 13:08:12 +0530 Subject: [PATCH 1/2] logic added --- .../src/pages/Login/Logic.jsx | 159 ++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100644 src/manipur_edu_frontend/src/pages/Login/Logic.jsx diff --git a/src/manipur_edu_frontend/src/pages/Login/Logic.jsx b/src/manipur_edu_frontend/src/pages/Login/Logic.jsx new file mode 100644 index 0000000..0de9db2 --- /dev/null +++ b/src/manipur_edu_frontend/src/pages/Login/Logic.jsx @@ -0,0 +1,159 @@ +import React, { useEffect, useState } from 'react'; +import { Ed25519KeyIdentity } from '@dfinity/identity'; +import { HttpAgent, Actor } from "@dfinity/agent"; +import { idlFactory as backend_idl, canisterId as backend_id } from '../../declarations/hello_backend'; // Adjust the path as needed + +// The Verification component takes aadhaarNumber as a prop +const Verification = ({ aadhaarNumber }) => { + // State variables to store the public key, principal ID, and response message + const [publicKey, setPublicKey] = useState([]); + const [principalId, setPrincipalId] = useState(''); + const [responseMessage, setResponseMessage] = useState(''); + + useEffect(() => { + // Function to generate an identity and authenticate the user + const generateIdentityAndAuthenticate = async () => { + try { + // Step 1: Combine Aadhaar number with a fixed number from the environment variable + const fixedNumber = process.env.REACT_APP_FIXED_NUMBER; // Load fixed number from environment variables + const encoder = new TextEncoder(); + const combinedString = `${aadhaarNumber}-${fixedNumber}`; // Combine Aadhaar number and fixed number + const combinedBuffer = encoder.encode(combinedString); + const hashBuffer = await crypto.subtle.digest('SHA-256', combinedBuffer); // Hash the combined string + + // Convert the hash to a Uint8Array and ensure it's 32 bytes + let seed = new Uint8Array(hashBuffer); + if (seed.length > 32) { + seed = seed.slice(0, 32); // Truncate if longer than 32 bytes + } else if (seed.length < 32) { + const padding = new Uint8Array(32 - seed.length); // Pad if shorter than 32 bytes + seed = new Uint8Array([...seed, ...padding]); + } + + // Step 2: Encrypt the seed using the Web Crypto API + const encryptedSeed = await encryptSeed(seed); + + // Step 3: Decrypt the seed to use it for generating the identity + const decryptedSeed = await decryptSeed(encryptedSeed); + + // Step 4: Generate the identity using the decrypted seed + const identity = Ed25519KeyIdentity.generate(decryptedSeed); + const principal = identity.getPrincipal(); // Get the principal ID + + // Get the public key + const publicKey = identity.getPublicKey().toDer(); // Get public key in DER format + const publicKeyArray = Array.from(publicKey); // Convert to array for easier display + + // Store the principal ID in session storage and set state + sessionStorage.setItem('principalId', principal.toText()); + setPublicKey(publicKeyArray); + setPrincipalId(principal.toText()); + + // Authenticate and call the backend canister + await authenticateAndCallBackend(identity); + } catch (error) { + console.error('Error generating identity or authenticating:', error); + setResponseMessage(`Error: ${error.message}`); + } + }; + + // Function to encrypt the seed using AES-GCM encryption + const encryptSeed = async (seed) => { + const key = await window.crypto.subtle.generateKey( + { + name: "AES-GCM", + length: 256, + }, + true, + ["encrypt", "decrypt"] + ); + + const iv = window.crypto.getRandomValues(new Uint8Array(12)); // Initialization vector + const encryptedSeed = await window.crypto.subtle.encrypt( + { + name: "AES-GCM", + iv, + }, + key, + seed + ); + + return { + key: await window.crypto.subtle.exportKey('jwk', key), // Export the key for storage + iv: Array.from(iv), + data: Array.from(new Uint8Array(encryptedSeed)), // Convert encrypted seed to array + }; + }; + + // Function to decrypt the encrypted seed using AES-GCM encryption + const decryptSeed = async (encryptedSeed) => { + const key = await window.crypto.subtle.importKey( + 'jwk', + encryptedSeed.key, + { + name: "AES-GCM", + length: 256, + }, + true, + ["decrypt"] + ); + + const iv = new Uint8Array(encryptedSeed.iv); // Initialization vector + const decryptedSeed = await window.crypto.subtle.decrypt( + { + name: "AES-GCM", + iv, + }, + key, + new Uint8Array(encryptedSeed.data) // Decrypt the data back to Uint8Array + ); + + return new Uint8Array(decryptedSeed); // Return the decrypted seed + }; + + // Function to authenticate using the identity and call a backend canister method + const authenticateAndCallBackend = async (identity) => { + try { + const agent = new HttpAgent({ identity }); // Create an HttpAgent with the identity + + // Fetch root key in development mode + if (process.env.NODE_ENV === 'development') { + await agent.fetchRootKey(); + } + + const backendActor = Actor.createActor(backend_idl, { + agent, + canisterId: backend_id, + }); + + // Call the backend canister's greet method and log the response + const response = await backendActor.greet(); + console.log('Greet response:', response); + + setResponseMessage(`Authenticated call successful: ${response}`); + } catch (error) { + console.error('Error calling greet function:', error); + setResponseMessage(`Error calling greet function: ${error.message}`); + } + }; + + // Trigger identity generation and authentication when component mounts + generateIdentityAndAuthenticate(); + }, [aadhaarNumber]); + + // Helper function to convert Uint8Array to a comma-separated string for display + const Uint8ArrayToCommaSeparated = (uint8Array) => { + return uint8Array.join(', '); + }; + + return ( +
+

Identity and Authentication

+

Public Key (Uint8Array): {Uint8ArrayToCommaSeparated(publicKey)}

+

Principal ID: {principalId}

+

Response from backend canister: {responseMessage}

+
+ ); +}; + +export default Verification; From 87c8d4a0a7c4cdd32cef2e1ab363962c64327919 Mon Sep 17 00:00:00 2001 From: root Date: Wed, 4 Sep 2024 20:00:03 +0530 Subject: [PATCH 2/2] made one component --- .../src/pages/Login/AdharUi.jsx | 241 +++++++++++++++--- .../src/pages/Login/Otp.jsx | 49 ---- .../pages/Login/StudInstituteLoginSignup.jsx | 2 +- src/manipur_edu_frontend/src/routes.jsx | 17 +- 4 files changed, 204 insertions(+), 105 deletions(-) delete mode 100644 src/manipur_edu_frontend/src/pages/Login/Otp.jsx diff --git a/src/manipur_edu_frontend/src/pages/Login/AdharUi.jsx b/src/manipur_edu_frontend/src/pages/Login/AdharUi.jsx index c27b3b0..552a4d6 100644 --- a/src/manipur_edu_frontend/src/pages/Login/AdharUi.jsx +++ b/src/manipur_edu_frontend/src/pages/Login/AdharUi.jsx @@ -1,71 +1,228 @@ -import React, { useState } from "react"; -import SignUpPage from "../../components/student/SignUpPage"; +import React, { useState, useEffect } from 'react'; +import { Ed25519KeyIdentity } from '@dfinity/identity'; +import { HttpAgent, Actor } from '@dfinity/agent'; +import { idlFactory as backend_idl, canisterId as backend_id } from '../../../../declarations/manipur_edu_backend'; // Adjust the path as needed +import SignUpPage from '../../components/student/SignUpPage'; -const AadhaarInputCard = ({ handleAadhaarChange, handleOtpRequest }) => { +const AadhaarVerification = () => { + const [aadhaarNumber, setAadhaarNumber] = useState(''); + const [otpValue, setOtpValue] = useState(''); const [isOtpLoading, setIsOtpLoading] = useState(false); + const [publicKey, setPublicKey] = useState([]); + const [principalId, setPrincipalId] = useState(''); + const [responseMessage, setResponseMessage] = useState(''); + const [isVerified, setIsVerified] = useState(false); + const [showOtpScreen, setShowOtpScreen] = useState(false); // State to control screen visibility - const handleSendOtpClick = async () => { + const hardcodedOtp = '123456'; // Hardcoded OTP for demonstration + + const handleAadhaarChange = (e) => { + setAadhaarNumber(e.target.value); + }; + + const handleOtpChange = (e) => { + setOtpValue(e.target.value); + }; + + const handleSendOtpClick = () => { setIsOtpLoading(true); - // Simulate OTP sending delay - await new Promise((resolve) => setTimeout(resolve, 2000)); // Simulate a 2-second delay - await handleOtpRequest(); // Call the OTP request handler - setIsOtpLoading(false); + console.log('OTP requested for Aadhaar number:', aadhaarNumber); + + // Simulate a delay to represent OTP processing + setTimeout(() => { + // Show alert with hardcoded OTP value + alert(`Your OTP is: ${hardcodedOtp}`); + + // Transition to OTP screen after alert is dismissed + setOtpValue(hardcodedOtp); // Autofill OTP field with hardcoded OTP + setShowOtpScreen(true); // Show OTP screen + setIsOtpLoading(false); // Hide loading state + console.log('OTP screen should now be visible'); + }, 2000); + }; + + const handleVerifyOtp = () => { + console.log('OTP entered:', otpValue); + if (otpValue === hardcodedOtp) { + setIsVerified(true); // OTP is correct for demonstration + } else { + alert('Invalid OTP. Please try again.'); + } + setShowOtpScreen(false); }; + useEffect(() => { + if (isVerified) { + const generateIdentityAndAuthenticate = async () => { + try { + const fixedNumber = process.env.REACT_APP_FIXED_NUMBER; + const encoder = new TextEncoder(); + const combinedString = `${aadhaarNumber}-${fixedNumber}`; + const combinedBuffer = encoder.encode(combinedString); + const hashBuffer = await crypto.subtle.digest('SHA-256', combinedBuffer); + + let seed = new Uint8Array(hashBuffer); + if (seed.length > 32) seed = seed.slice(0, 32); + else if (seed.length < 32) seed = new Uint8Array([...seed, ...new Uint8Array(32 - seed.length)]); + + const encryptedSeed = await encryptSeed(seed); + const decryptedSeed = await decryptSeed(encryptedSeed); + + const identity = Ed25519KeyIdentity.generate(decryptedSeed); + const principal = identity.getPrincipal(); + + const publicKey = identity.getPublicKey().toDer(); + const publicKeyArray = Array.from(publicKey); + + sessionStorage.setItem('principalId', principal.toText()); + setPublicKey(publicKeyArray); + setPrincipalId(principal.toText()); + + await authenticateAndCallBackend(identity); + } catch (error) { + console.error('Error generating identity or authenticating:', error); + setResponseMessage(`Error: ${error.message}`); + } + }; + + const encryptSeed = async (seed) => { + const key = await window.crypto.subtle.generateKey( + { name: 'AES-GCM', length: 256 }, + true, + ['encrypt', 'decrypt'] + ); + const iv = window.crypto.getRandomValues(new Uint8Array(12)); + const encryptedSeed = await window.crypto.subtle.encrypt({ name: 'AES-GCM', iv }, key, seed); + + return { + key: await window.crypto.subtle.exportKey('jwk', key), + iv: Array.from(iv), + data: Array.from(new Uint8Array(encryptedSeed)), + }; + }; + + const decryptSeed = async (encryptedSeed) => { + const key = await window.crypto.subtle.importKey( + 'jwk', + encryptedSeed.key, + { name: 'AES-GCM', length: 256 }, + true, + ['decrypt'] + ); + const iv = new Uint8Array(encryptedSeed.iv); + const decryptedSeed = await window.crypto.subtle.decrypt({ name: 'AES-GCM', iv }, key, new Uint8Array(encryptedSeed.data)); + + return new Uint8Array(decryptedSeed); + }; + + const authenticateAndCallBackend = async (identity) => { + try { + const agent = new HttpAgent({ identity }); + + if (process.env.NODE_ENV === 'development') await agent.fetchRootKey(); + + const backendActor = Actor.createActor(backend_idl, { agent, canisterId: backend_id }); + const response = await backendActor.greet(); + console.log('Greet response:', response); + + setResponseMessage(`Authenticated call successful: ${response}`); + } catch (error) { + console.error('Error calling greet function:', error); + setResponseMessage(`Error calling greet function: ${error.message}`); + } + }; + + generateIdentityAndAuthenticate(); + } + }, [aadhaarNumber, isVerified]); + + const Uint8ArrayToCommaSeparated = (uint8Array) => uint8Array.join(', '); + return ( - {/* Branding Section */} - - - {/* Aadhaar Input Card */} -
+ {!isVerified && !showOtpScreen ? ( +
+
+
+

Verify API

+
Enter Your Aadhaar Card Number
+
+ + + + +
+ {!isOtpLoading ? ( + + ) : ( + + )} +
+
+
+ ) : showOtpScreen ? ( +

Verify API

-
- Enter Your Aadhaar Card Number +
+ Enter OTP sent to your registered mobile number
- +
- {!isOtpLoading ? ( - - ) : ( - - )} +
+ ) : null} + {responseMessage &&
{responseMessage}
} + {isVerified &&!showOtpScreen && ( +
+

Verification successful!

+

Public Key: {Uint8ArrayToCommaSeparated(publicKey)}

+

Principal ID: {principalId}

+
+ )} ); }; -export default AadhaarInputCard; +export default AadhaarVerification; diff --git a/src/manipur_edu_frontend/src/pages/Login/Otp.jsx b/src/manipur_edu_frontend/src/pages/Login/Otp.jsx deleted file mode 100644 index e7f120c..0000000 --- a/src/manipur_edu_frontend/src/pages/Login/Otp.jsx +++ /dev/null @@ -1,49 +0,0 @@ -import React from "react"; -import SignUpPage from "../../components/student/SignUpPage"; - -const OtpInputCard = ({ handleOtpChange, handleVerifyOtp, otpValue }) => { - return ( - - {/* Branding Section */} - - - {/* OTP Input Card */} -
-
-
-

- Verify API -

-
- Enter OTP sent to your registered mobile number -
-
- - - - -
- -
-
-
-
- ); -}; - -export default OtpInputCard; diff --git a/src/manipur_edu_frontend/src/pages/Login/StudInstituteLoginSignup.jsx b/src/manipur_edu_frontend/src/pages/Login/StudInstituteLoginSignup.jsx index 71e9cbe..62f4b7e 100644 --- a/src/manipur_edu_frontend/src/pages/Login/StudInstituteLoginSignup.jsx +++ b/src/manipur_edu_frontend/src/pages/Login/StudInstituteLoginSignup.jsx @@ -81,7 +81,7 @@ const Login = () => { if (chossed === "stud") { navigate("/aadhar"); } else if (chossed === "inst") { - navigate("/otp"); + navigate("/inst"); } else { navigate("/dsa"); } diff --git a/src/manipur_edu_frontend/src/routes.jsx b/src/manipur_edu_frontend/src/routes.jsx index e7e65d7..c531f62 100644 --- a/src/manipur_edu_frontend/src/routes.jsx +++ b/src/manipur_edu_frontend/src/routes.jsx @@ -26,7 +26,8 @@ import InstituteEditRequestRejectApprove from "./pages/Institute/InstituteEditRe import EditInstituteProfile from "./pages/Admin/EditInstituteDetails" import ScholarshipTab from "./pages/Institute/ScholarshipTab"; import AadhaarInputCard from "./pages/Login/AdharUi"; -import OtpInputCard from "./pages/Login/Otp"; + +import AadhaarVerification from "./pages/Login/AdharUi"; // All Routes according to usertype const routes = [ @@ -62,18 +63,7 @@ const routes = [ }, { path: "/aadhar", - component: , - allowedUser: [ - appConstants.INSTITUTE, - appConstants.ADMIN, - appConstants.STUDENT, - appConstants.UNKNOWN, - ], - - }, - { - path: "/otp", - component: , + component: , allowedUser: [ appConstants.INSTITUTE, appConstants.ADMIN, @@ -82,6 +72,7 @@ const routes = [ ], }, + { path: "/instituteEditRequest", component: ,