From 38df94094fd3cfa7b121c363b8607c80bae9e080 Mon Sep 17 00:00:00 2001 From: bhavanakarwade Date: Thu, 12 Oct 2023 21:04:18 +0530 Subject: [PATCH 01/16] feat: refactor api for passkey module Signed-off-by: bhavanakarwade --- src/api/Fido.ts | 27 +- src/commonComponents/DeviceDetailsCard.tsx | 5 +- src/components/Authentication/SignInUser.tsx | 377 ++++++++++-------- .../Authentication/SignInUserPasskey.tsx | 9 +- .../Authentication/SignUpUserPasskey.tsx | 25 +- .../Authentication/SignUpUserPassword.tsx | 2 +- src/components/Profile/AddPasskey.tsx | 14 +- src/components/Profile/interfaces/index.ts | 2 +- src/config/apiRoutes.ts | 19 +- 9 files changed, 249 insertions(+), 231 deletions(-) diff --git a/src/api/Fido.ts b/src/api/Fido.ts index 2c21c6dde..88db0477c 100644 --- a/src/api/Fido.ts +++ b/src/api/Fido.ts @@ -5,9 +5,10 @@ import { axiosDelete, axiosGet, axiosPost, axiosPut } from "../services/apiReque import { getFromLocalStorage } from "./Auth" export const generateRegistrationOption = async (payload: RegistrationOptionInterface) => { + const email = payload.userName; const token = await getFromLocalStorage(storageKeys.TOKEN) const details = { - url: `${apiRoutes.fido.generateRegistration}`, + url: `${apiRoutes.auth.generateRegistration}/${email}`, payload, config: { headers: { @@ -27,10 +28,10 @@ export const generateRegistrationOption = async (payload: RegistrationOptionInte } } -export const verifyRegistration = async (payload:verifyRegistrationObjInterface, userEmail:string) => { +export const verifyRegistration = async (payload:verifyRegistrationObjInterface, email:string) => { const token = await getFromLocalStorage(storageKeys.TOKEN) const details = { - url: `${apiRoutes.fido.verifyRegistration}${userEmail}`, + url: `${apiRoutes.auth.verifyRegistration}${email}`, payload, config: { headers: { @@ -51,9 +52,10 @@ export const verifyRegistration = async (payload:verifyRegistrationObjInterface, } export const addDeviceDetails = async (payload: IdeviceBody) => { + const credentialId = payload.credentialId; const token = await getFromLocalStorage(storageKeys.TOKEN) const details = { - url: `${apiRoutes.fido.userUpdate}`, + url: `${apiRoutes.auth.userUpdate}/${credentialId}`, payload, config: { headers: { @@ -73,10 +75,10 @@ export const addDeviceDetails = async (payload: IdeviceBody) => { } } -export const getUserDeviceDetails = async(userEmail:string) => { +export const getUserDeviceDetails = async(email:string) => { const token = await getFromLocalStorage(storageKeys.TOKEN) const details = { - url: `${apiRoutes.fido.getDeviceList}${userEmail}`, + url: `${apiRoutes.auth.getDeviceList}${email}`, config: { headers: { 'Content-type': 'application/json', @@ -95,10 +97,10 @@ export const getUserDeviceDetails = async(userEmail:string) => { } } -export const deleteDeviceById = async(enCodedUrl:string) => { +export const deleteDeviceById = async(credentialId:string) => { const token = await getFromLocalStorage(storageKeys.TOKEN) const details = { - url: `${apiRoutes.fido.fidoDevice}?credentialId=${enCodedUrl}`, + url: `${apiRoutes.auth.fidoDevice}/${credentialId}`, config: { headers: { 'Content-type': 'application/json', @@ -120,7 +122,7 @@ export const deleteDeviceById = async(enCodedUrl:string) => { export const generateAuthenticationOption = async (payload:UserEmail) => { const token = await getFromLocalStorage(storageKeys.TOKEN) const details = { - url: `${apiRoutes.fido.fidoAuthentication}`, + url: `${apiRoutes.auth.fidoAuthentication}`, payload, config: { headers: { @@ -140,11 +142,10 @@ export const generateAuthenticationOption = async (payload:UserEmail) => { } } -export const verifyAuthentication = async (payload: any, userEmail:UserEmail) => { - console.log("userEmail", userEmail) +export const verifyAuthentication = async (payload: any, email: { userName: string }) => { const token = await getFromLocalStorage(storageKeys.TOKEN) const details = { - url: `${apiRoutes.fido.fidoVerifyAuthentication}${userEmail?.userName}`, + url: `${apiRoutes.auth.fidoVerifyAuthentication}${email.userName}`, payload, config: { headers: { @@ -167,7 +168,7 @@ export const verifyAuthentication = async (payload: any, userEmail:UserEmail) => export const editDeviceDetails = async (payload:DeviceDetails) => { const token = await getFromLocalStorage(storageKeys.TOKEN) const details = { - url: `${apiRoutes.fido.updateDeviceName}?credentialId=${payload.enCodedUrl}&deviceName=${payload.updatedDeviceName}`, + url: `${apiRoutes.auth.updateDeviceName}/${payload.enCodedUrl}?deviceName=${payload.updatedDeviceName}`, payload, config: { headers: { diff --git a/src/commonComponents/DeviceDetailsCard.tsx b/src/commonComponents/DeviceDetailsCard.tsx index 5088e82f1..6d7d5e0f0 100644 --- a/src/commonComponents/DeviceDetailsCard.tsx +++ b/src/commonComponents/DeviceDetailsCard.tsx @@ -1,13 +1,10 @@ -import { useEffect, useState } from "react" +import { useState } from "react" import { deleteDeviceById, editDeviceDetails } from "../api/Fido" import DeleteModal from "./DeletePopup" import EditModal from "./EditPopup"; import { Alert } from "flowbite-react"; import type { AxiosResponse } from "axios"; import { apiStatusCodes } from "../config/CommonConstant"; -import BreadCrumbs from "../components/BreadCrumbs"; -import editIcon from '/images/edit.svg'; -import React from "react"; import { dateConversion } from "../utils/DateConversion"; import DateTooltip from "../components/Tooltip"; diff --git a/src/components/Authentication/SignInUser.tsx b/src/components/Authentication/SignInUser.tsx index c5cda6154..6c2dc8022 100644 --- a/src/components/Authentication/SignInUser.tsx +++ b/src/components/Authentication/SignInUser.tsx @@ -1,34 +1,30 @@ -import './global.css' +import './global.css'; import * as yup from 'yup'; import { Button, Label, Navbar } from 'flowbite-react'; -import { - Field, - Form, - Formik, -} from 'formik'; +import { Field, Form, Formik } from 'formik'; import { getFromLocalStorage, setToLocalStorage } from '../../api/Auth'; import { useEffect, useRef, useState } from 'react'; -import NavBar from "./NavBar" +import NavBar from './NavBar'; import { Alert } from 'flowbite-react'; import React from 'react'; -import RegistrationSuccess from './RegistrationSuccess' +import RegistrationSuccess from './RegistrationSuccess'; import SignInUserPasskey from './SignInUserPasskey'; import { storageKeys } from '../../config/CommonConstant'; -import FooterBar from "./FooterBar"; +import FooterBar from './FooterBar'; interface emailValue { email: string | null; } -const resetPasswordSuccess = '?isPasswordSet=true' +const resetPasswordSuccess = '?isPasswordSet=true'; const SignInUser = () => { - const [email, setEmail] = useState(null) - const [fidoUserError, setFidoUserError] = useState("") - const [success, setSuccess] = useState(null) - const [failure, setFailur] = useState(null) - const [loading, setLoading] = useState(false) + const [email, setEmail] = useState(null); + const [fidoUserError, setFidoUserError] = useState(''); + const [success, setSuccess] = useState(null); + const [failure, setFailur] = useState(null); + const [loading, setLoading] = useState(false); const [currentComponent, setCurrentComponent] = useState('email'); const [isEmailValid, setIsEmailValid] = useState(false); const [isPasskeySuccess, setIsPasskeySuccess] = useState(false); @@ -36,12 +32,13 @@ const SignInUser = () => { const nextButtonRef = useRef(null); useEffect(() => { - const fetchData = async () => { try { - const storedEmail = await getFromLocalStorage(storageKeys.LOGIN_USER_EMAIL); + const storedEmail = await getFromLocalStorage( + storageKeys.LOGIN_USER_EMAIL, + ); - const searchParam = new URLSearchParams(window?.location?.search) + const searchParam = new URLSearchParams(window?.location?.search); const userEmail = searchParam.get('email'); const signUpStatus = searchParam.get('signup'); const fidoFlag = searchParam.get('fidoFlag'); @@ -50,39 +47,51 @@ const SignInUser = () => { setUserLoginEmail(storedEmail || userEmail); setEmail({ email: storedEmail || '' }); - const entries = performance.getEntriesByType('navigation') as PerformanceNavigationTiming[];; - const isRefreshPage = entries.length > 0 && entries[0].type === 'reload'; + const entries = performance.getEntriesByType( + 'navigation', + ) as PerformanceNavigationTiming[]; + const isRefreshPage = + entries.length > 0 && entries[0].type === 'reload'; if (isRefreshPage) { await setToLocalStorage(storageKeys.LOGIN_USER_EMAIL, ''); } - if (signUpStatus === 'true' && fidoFlag === 'false' && loginMethod === 'password') { - setSuccess('Congratulations!! πŸŽ‰ You have successfully registered on CREDEBL πŸš€'); - } else if (signUpStatus === 'true' && fidoFlag === 'true' && loginMethod === 'passkey') { + if ( + signUpStatus === 'true' && + fidoFlag === 'false' && + loginMethod === 'password' + ) { + setSuccess( + 'Congratulations!! πŸŽ‰ You have successfully registered on CREDEBL πŸš€', + ); + } else if ( + signUpStatus === 'true' && + fidoFlag === 'true' && + loginMethod === 'passkey' + ) { setIsPasskeySuccess(true); } else if (resetPasswordSuccess === window?.location?.search) { setSuccess('Congratulations!! πŸŽ‰ Your new password set successfully'); } } catch (err) { - console.log("ERROR-LOGIN::", err) + console.log('ERROR-LOGIN::', err); } }; fetchData(); }, []); - const saveEmail = async (values: emailValue) => { - setEmail(values) + setEmail(values); setCurrentComponent('password'); await setToLocalStorage(storageKeys.LOGIN_USER_EMAIL, values.email); setIsPasskeySuccess(true); - } + }; const redirectLandingPage = () => { - window.location.href = '/' - } + window.location.href = '/'; + }; useEffect(() => { if (nextButtonRef.current) { @@ -92,165 +101,181 @@ const SignInUser = () => { return (
- {currentComponent === 'email' && isPasskeySuccess ? () - : currentComponent === 'password' ? ( - - ) : ( -
- -
-
-
- img -
-
- -
-
- { - (success || failure || fidoUserError) && - setSuccess(null)} - > - -

- {success || failure || fidoUserError} -

-
-
- } - -
- - - -
- -

- Login -

- -

- Enter your Email to login -

- -
- -
- -
- + {currentComponent === 'email' && isPasskeySuccess ? ( + + ) : ( +
+ {!(currentComponent === 'email' && isPasskeySuccess) && + currentComponent === 'password' ? ( + + ) : ( +
+ +
+
+
img + alt="img" + />
+
- saveEmail(values) - } - > - - {(formikHandlers): JSX.Element => ( -
-
+
+
+ {(success || failure || fidoUserError) && ( + setSuccess(null)} + > + +

{success || failure || fidoUserError}

+
+
+ )} -
-
+
+ + +
+

+ Login +

+ +

+ Enter your Email to login +

+
+
-
+
+ img +
- - saveEmail(values)} + > + {(formikHandlers): JSX.Element => ( +
+
+
+
+ +
+ + + + + +
+ {!isEmailValid && formikHandlers.touched.email && ( + + {formikHandlers.errors.email} + + )}
- {!isEmailValid && formikHandlers.touched.email && ( - - {formikHandlers.errors.email} - - )} - -
-
- - - -
-
- Don't have an account yet? -   - {` Create an account`} - -
- - )} - +
+ +
+
+ Don't have an account yet?   + + {` Create an account`} + +
+ + )} + +
+
- - -
- )} + )} +
+ )}
); }; diff --git a/src/components/Authentication/SignInUserPasskey.tsx b/src/components/Authentication/SignInUserPasskey.tsx index 94e1921fb..fce505fda 100644 --- a/src/components/Authentication/SignInUserPasskey.tsx +++ b/src/components/Authentication/SignInUserPasskey.tsx @@ -9,7 +9,6 @@ import type { AxiosResponse } from 'axios'; import SignInUser from './SignInUser'; import { startAuthentication } from '@simplewebauthn/browser'; import { useState } from 'react'; -import React from 'react'; import SignInUserPassword from './SignInUserPassword'; import { pathRoutes } from '../../config/pathRoutes'; import NavBar from "./NavBar"; @@ -80,13 +79,10 @@ const SignInUserPasskey = (signInUserProps: signInUserProps) => { try { setFidoLoader(true) - const obj = { userName: email } - const generateAuthenticationResponse: any = await generateAuthenticationOption(obj); const challangeId: string = generateAuthenticationResponse?.data?.data?.challenge; - setFidoUserError(generateAuthenticationResponse?.data?.error); const opts = generateAuthenticationResponse?.data?.data; @@ -95,14 +91,15 @@ const SignInUserPasskey = (signInUserProps: signInUserProps) => { ...attResp, challangeId }; - const verificationResp = await verifyAuthenticationMethod(verifyAuthenticationObj, { userName: email }); + + const verificationResp = await verifyAuthenticationMethod(verifyAuthenticationObj, obj); + const { data } = verificationResp as AxiosResponse if (data?.data.verified) { const payload: UserSignInData = { email: email, isPasskey: true }; - const loginRsp = await loginUser(payload); const { data } = loginRsp as AxiosResponse; if (data?.statusCode === apiStatusCodes.API_STATUS_SUCCESS) { diff --git a/src/components/Authentication/SignUpUserPasskey.tsx b/src/components/Authentication/SignUpUserPasskey.tsx index 112199503..3479cdd07 100644 --- a/src/components/Authentication/SignUpUserPasskey.tsx +++ b/src/components/Authentication/SignUpUserPasskey.tsx @@ -10,7 +10,6 @@ import { useEffect, useState } from 'react'; import SignUpUserPassword from './SignUpUserPassword.jsx'; import { startRegistration } from '@simplewebauthn/browser'; -import React from 'react'; import SignUpUserName from './SignUpUserName.js'; import { v4 as uuidv4 } from 'uuid'; import NavBar from './NavBar.js'; @@ -22,13 +21,13 @@ interface passwordValues { confirmPassword: string } -const SignUpUserPasskey = ({ email,firstName, lastName }: { email:string,firstName: string; lastName: string }) => { +const SignUpUserPasskey = ({ email, firstName, lastName }: { email: string, firstName: string; lastName: string }) => { const [loading, setLoading] = useState(false) const [erroMsg, setErrMsg] = useState(null) const [verificationSuccess, setVerificationSuccess] = useState('') const [addSuccess, setAddSuccess] = useState(null) - const [addfailure, setAddFailur] = useState(null) + const [addfailure, setAddFailure] = useState(null) const [emailAutoFill, setEmailAutoFill] = useState('') const [fidoError, setFidoError] = useState("") const [currentComponent, setCurrentComponent] = useState('email'); @@ -59,7 +58,7 @@ const SignUpUserPasskey = ({ email,firstName, lastName }: { email:string,firstNa } } - const submit = async (fidoFlag: boolean, passwordDetails?: passwordValues,) => { + const submit = async (fidoFlag: boolean, passwordDetails?: passwordValues) => { const userEmail = await getFromLocalStorage(storageKeys.USER_EMAIL) const password: string = uuidv4(); let payload: AddPasswordDetails = { @@ -70,12 +69,13 @@ const SignUpUserPasskey = ({ email,firstName, lastName }: { email:string,firstNa password: passwordEncryption(password) }; if (!fidoFlag) { - payload.password = passwordDetails?.password; } + setLoading(true) const userRsp = await addPasswordDetails(payload) + const { data } = userRsp as AxiosResponse setLoading(false) if (data?.statusCode === apiStatusCodes.API_STATUS_CREATED) { @@ -95,7 +95,7 @@ const SignUpUserPasskey = ({ email,firstName, lastName }: { email:string,firstNa } const generateRegistrationResponse = await generateRegistrationOption(RegistrationOption) const { data } = generateRegistrationResponse as AxiosResponse - if (data?.statusCode === apiStatusCodes.API_STATUS_SUCCESS) { + if (data?.statusCode === apiStatusCodes.API_STATUS_CREATED) { const opts = data?.data const challangeId = data?.data?.challenge @@ -121,12 +121,13 @@ const SignUpUserPasskey = ({ email,firstName, lastName }: { email:string,firstNa showFidoError(error) } } + + let credentialID = ''; const verifyRegistrationMethod = async (verifyRegistrationObj: any, OrgUserEmail: string) => { try { const verificationRegisterResp = await verifyRegistration(verifyRegistrationObj, OrgUserEmail) const { data } = verificationRegisterResp as AxiosResponse - - const credentialID = data?.data?.newDevice?.credentialID + credentialID = encodeURIComponent(data?.data?.newDevice?.credentialID) if (data?.data?.verified) { let platformDeviceName = '' @@ -158,11 +159,11 @@ const SignUpUserPasskey = ({ email,firstName, lastName }: { email:string,firstNa if (data?.statusCode === apiStatusCodes.API_STATUS_SUCCESS) { submit(true) } else { - setAddFailur(deviceDetailsResp as string) + setAddFailure(deviceDetailsResp as string) } setTimeout(() => { setAddSuccess('') - setAddFailur('') + setAddFailure('') }); } catch (error) { showFidoError(error) @@ -313,13 +314,13 @@ const SignUpUserPasskey = ({ email,firstName, lastName }: { email:string,firstNa
- +
} { currentComponent === 'password' && ( diff --git a/src/components/Authentication/SignUpUserPassword.tsx b/src/components/Authentication/SignUpUserPassword.tsx index d8d5a07d8..f05af2990 100644 --- a/src/components/Authentication/SignUpUserPassword.tsx +++ b/src/components/Authentication/SignUpUserPassword.tsx @@ -62,7 +62,7 @@ const SignUpUserPassword = ({ const { data } = userRsp as AxiosResponse; setLoading(false); if (data?.statusCode === apiStatusCodes.API_STATUS_CREATED) { - window.location.href = `/authentication/sign-in?signup=true?fidoFlag=${fidoFlag}`; + window.location.href = `/authentication/sign-in?signup=true?fidoFlag=${fidoFlag}&method=password`; } else { setErrMsg(userRsp as string); } diff --git a/src/components/Profile/AddPasskey.tsx b/src/components/Profile/AddPasskey.tsx index 59b2211d2..e2c1ce65b 100644 --- a/src/components/Profile/AddPasskey.tsx +++ b/src/components/Profile/AddPasskey.tsx @@ -1,15 +1,15 @@ import { Alert, Button } from 'flowbite-react' -import React, { useEffect, useState } from 'react' -import { IDeviceData, IdeviceBody, RegistrationOptionInterface } from './interfaces' +import { useEffect, useState } from 'react' import DeviceDetails from '../../commonComponents/DeviceDetailsCard' import PasskeyAddDevice from '../../commonComponents/PasseyAddDevicePopup' -import { AxiosError, AxiosResponse } from 'axios' import { addDeviceDetails, generateRegistrationOption, getUserDeviceDetails, verifyRegistration } from '../../api/Fido' import { apiStatusCodes, storageKeys } from '../../config/CommonConstant' import { apiRoutes } from '../../config/apiRoutes' import { startRegistration } from '@simplewebauthn/browser' import { getFromLocalStorage } from '../../api/Auth' import CustomSpinner from '../CustomSpinner' +import type { IDeviceData, IdeviceBody, RegistrationOptionInterface, verifyRegistrationObjInterface } from './interfaces' +import type { AxiosError, AxiosResponse } from 'axios' const AddPasskey = () => { @@ -18,7 +18,7 @@ const AddPasskey = () => { const [OrgUserEmail, setOrgUserEmail] = useState('') const [deviceList, setDeviceList] = useState([]) const [addSuccess, setAddSuccess] = useState(null) - const [addfailure, setAddFailur] = useState(null) + const [addfailure, setAddFailure] = useState(null) const [disableFlag, setDisableFlag] = useState(false) @@ -115,7 +115,7 @@ const AddPasskey = () => { userDeviceDetails() window.location.href = `${apiRoutes.auth.profile}` } else { - setAddFailur(deviceDetailsResp as string) + setAddFailure(deviceDetailsResp as string) } } catch (error) { showFidoError(error) @@ -143,7 +143,7 @@ const AddPasskey = () => { setDeviceList(deviceDetails) } } catch (error) { - setAddFailur("Error while fetching the device details") + setAddFailure("Error while fetching the device details") setFidoLoader(false) } } @@ -200,7 +200,7 @@ const AddPasskey = () => { onDismiss={() => { setAddSuccess(null) setFidoError('') - setAddFailur('') + setAddFailure('') }} > diff --git a/src/components/Profile/interfaces/index.ts b/src/components/Profile/interfaces/index.ts index 72cc41132..9be70237d 100644 --- a/src/components/Profile/interfaces/index.ts +++ b/src/components/Profile/interfaces/index.ts @@ -43,7 +43,7 @@ export interface DeviceDetails { } export interface UserEmail { - userName: string + email: string } export interface UserProfile { diff --git a/src/config/apiRoutes.ts b/src/config/apiRoutes.ts index 44dd0faa2..f15e44a63 100644 --- a/src/config/apiRoutes.ts +++ b/src/config/apiRoutes.ts @@ -6,6 +6,14 @@ export const apiRoutes = { addDetails: '/auth/signup', passkeyUserDetails: '/users/password/', profile: '/profile', + generateRegistration: 'auth/passkey/generate-registration', + verifyRegistration: 'auth/passkey/verify-registration/', + getDeviceList: 'auth/passkey/', + updateDeviceName: 'passkey', + userUpdate: 'auth/passkey/user-details', + fidoDevice: 'passkey', + fidoAuthentication: 'auth/passkey/authentication-options', + fidoVerifyAuthentication: 'auth/passkey/verify-authentication/' }, users: { userProfile: '/users/profile', @@ -37,17 +45,6 @@ export const apiRoutes = { createCredentialDefinition: '/cred-defs', getCredDefBySchemaId: '/schemas', }, - fido: { - generateRegistration: 'fido/generate-registration-options', - verifyRegistration: 'fido/verify-registration/', - getDeviceList: 'fido/user-details/', - updateDeviceName: 'fido/device-name', - userUpdate: 'fido/user-update', - fidoDevice: 'fido/device', - fidoAuthentication: 'Fido/generate-authentication-options', - fidoVerifyAuthentication: 'Fido/verify-authentication/' - - }, Issuance: { getIssuedCredentials: '/credentials', getAllConnections: '/connections', From 318340f86a31f9bf6494810c861f4858b0bacfdb Mon Sep 17 00:00:00 2001 From: bhavanakarwade Date: Fri, 13 Oct 2023 16:07:38 +0530 Subject: [PATCH 02/16] feat: refactor api for passkey module Signed-off-by: bhavanakarwade --- .../Authentication/RegistrationSuccess.tsx | 152 +++++++++--------- src/components/Authentication/SignInUser.tsx | 16 +- .../Authentication/SignUpUserPasskey.tsx | 3 +- .../Authentication/SignUpUserPassword.tsx | 3 +- 4 files changed, 94 insertions(+), 80 deletions(-) diff --git a/src/components/Authentication/RegistrationSuccess.tsx b/src/components/Authentication/RegistrationSuccess.tsx index b3e358b5d..2b21f2eaf 100644 --- a/src/components/Authentication/RegistrationSuccess.tsx +++ b/src/components/Authentication/RegistrationSuccess.tsx @@ -1,72 +1,80 @@ -import { Button } from "flowbite-react"; -import React from "react"; -import NavBar from "./NavBar"; -import FooterBar from "./FooterBar"; - -const RegistrationSuccess = () => { - - const redirectSignInPage = () => { - window.location.href = '/authentication/sign-in' - } - - return ( -
- - - -
-
-
- - img - -
-
- -
- -
- -
- Congratulations! -
- -
- - - - - -
-

- Passkey created successfully -

- -
- -
- - -
-
-
- - -
- ) -} - -export default RegistrationSuccess; \ No newline at end of file +import { Button } from 'flowbite-react'; +import NavBar from './NavBar'; +import FooterBar from './FooterBar'; + +const RegistrationSuccess = (props) => { + const redirectSignInPage = () => { + + window.location.href = `/authentication/sign-in?email=${props.email.email}&showmsg=true`; + }; + return ( +
+ + +
+
+
+ img +
+
+ +
+
+
+ Congratulations! +
+ +
+ + + + +
+

+ Passkey created successfully +

+ +
+ +
+
+
+
+ +
+ ); +}; + +export default RegistrationSuccess; diff --git a/src/components/Authentication/SignInUser.tsx b/src/components/Authentication/SignInUser.tsx index 08a191139..83061d711 100644 --- a/src/components/Authentication/SignInUser.tsx +++ b/src/components/Authentication/SignInUser.tsx @@ -1,14 +1,12 @@ import './global.css'; import * as yup from 'yup'; - import { Button, Label, Navbar } from 'flowbite-react'; import { Field, Form, Formik } from 'formik'; import { getFromLocalStorage, setToLocalStorage } from '../../api/Auth'; import { useEffect, useRef, useState } from 'react'; import NavBar from './NavBar'; import { Alert } from 'flowbite-react'; -import React from 'react'; import RegistrationSuccess from './RegistrationSuccess'; import SignInUserPasskey from './SignInUserPasskey'; import { storageKeys } from '../../config/CommonConstant'; @@ -31,22 +29,25 @@ const SignInUser = () => { const [userLoginEmail, setUserLoginEmail] = useState(null); const nextButtonRef = useRef(null); + + useEffect(() => { const fetchData = async () => { try { const storedEmail = await getFromLocalStorage( storageKeys.LOGIN_USER_EMAIL, ); - const searchParam = new URLSearchParams(window?.location?.search); const userEmail = searchParam.get('email'); const signUpStatus = searchParam.get('signup'); const fidoFlag = searchParam.get('fidoFlag'); const loginMethod = searchParam.get('method'); + const showMsg = searchParam.get('showmsg'); setUserLoginEmail(storedEmail || userEmail); setEmail({ email: storedEmail || '' }); +console.log('email::', email); const entries = performance.getEntriesByType( 'navigation', ) as PerformanceNavigationTiming[]; @@ -56,7 +57,6 @@ const SignInUser = () => { if (isRefreshPage) { await setToLocalStorage(storageKeys.LOGIN_USER_EMAIL, ''); } - if ( signUpStatus === 'true' && fidoFlag === 'false' && @@ -65,6 +65,10 @@ const SignInUser = () => { setSuccess( 'Congratulations!! πŸŽ‰ You have successfully registered on CREDEBL πŸš€', ); + } else if (showMsg === 'true') { + setSuccess( + 'Congratulations!! πŸŽ‰ You have successfully registered on CREDEBL πŸš€', + ); } else if ( signUpStatus === 'true' && fidoFlag === 'true' && @@ -83,7 +87,7 @@ const SignInUser = () => { }, []); const saveEmail = async (values: emailValue) => { - setEmail(values) + setEmail(values); await localStorage.clear(); setCurrentComponent('password'); await setToLocalStorage(storageKeys.LOGIN_USER_EMAIL, values.email); @@ -103,7 +107,7 @@ const SignInUser = () => { return (
{currentComponent === 'email' && isPasskeySuccess ? ( - + ) : (
{!(currentComponent === 'email' && isPasskeySuccess) && diff --git a/src/components/Authentication/SignUpUserPasskey.tsx b/src/components/Authentication/SignUpUserPasskey.tsx index 3479cdd07..cbc131369 100644 --- a/src/components/Authentication/SignUpUserPasskey.tsx +++ b/src/components/Authentication/SignUpUserPasskey.tsx @@ -69,7 +69,7 @@ const SignUpUserPasskey = ({ email, firstName, lastName }: { email: string, firs password: passwordEncryption(password) }; if (!fidoFlag) { - payload.password = passwordDetails?.password; + payload.password = passwordDetails?.password || ''; } setLoading(true) @@ -80,6 +80,7 @@ const SignUpUserPasskey = ({ email, firstName, lastName }: { email: string, firs setLoading(false) if (data?.statusCode === apiStatusCodes.API_STATUS_CREATED) { window.location.href = `/authentication/sign-in?signup=true&fidoFlag=${fidoFlag}&method=passkey` + } else { setErrMsg(userRsp as string) } diff --git a/src/components/Authentication/SignUpUserPassword.tsx b/src/components/Authentication/SignUpUserPassword.tsx index f05af2990..6f117f794 100644 --- a/src/components/Authentication/SignUpUserPassword.tsx +++ b/src/components/Authentication/SignUpUserPassword.tsx @@ -62,7 +62,8 @@ const SignUpUserPassword = ({ const { data } = userRsp as AxiosResponse; setLoading(false); if (data?.statusCode === apiStatusCodes.API_STATUS_CREATED) { - window.location.href = `/authentication/sign-in?signup=true?fidoFlag=${fidoFlag}&method=password`; + window.location.href = `/authentication/sign-in?signup=true&email=${userEmail}&fidoFlag=${fidoFlag}&method=password` + } else { setErrMsg(userRsp as string); } From 37d9d69d767642ac05ed1240c4f604e6f7fefc4c Mon Sep 17 00:00:00 2001 From: bhavanakarwade Date: Fri, 13 Oct 2023 16:42:48 +0530 Subject: [PATCH 03/16] feat: standardized API for passkey module Signed-off-by: bhavanakarwade --- src/components/Authentication/SignInUser.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/Authentication/SignInUser.tsx b/src/components/Authentication/SignInUser.tsx index 83061d711..eac7454ec 100644 --- a/src/components/Authentication/SignInUser.tsx +++ b/src/components/Authentication/SignInUser.tsx @@ -37,6 +37,7 @@ const SignInUser = () => { const storedEmail = await getFromLocalStorage( storageKeys.LOGIN_USER_EMAIL, ); + const newEmail = await getFromLocalStorage(storageKeys.USER_EMAIL) const searchParam = new URLSearchParams(window?.location?.search); const userEmail = searchParam.get('email'); const signUpStatus = searchParam.get('signup'); @@ -45,9 +46,8 @@ const SignInUser = () => { const showMsg = searchParam.get('showmsg'); setUserLoginEmail(storedEmail || userEmail); - setEmail({ email: storedEmail || '' }); + setEmail({ email: storedEmail || newEmail }); -console.log('email::', email); const entries = performance.getEntriesByType( 'navigation', ) as PerformanceNavigationTiming[]; From 1a0700a5293c235d584098f4225e5c5b7c5ad80b Mon Sep 17 00:00:00 2001 From: bhavanakarwade Date: Fri, 13 Oct 2023 17:27:31 +0530 Subject: [PATCH 04/16] add interface Signed-off-by: bhavanakarwade --- src/api/Fido.ts | 4 ++-- .../Authentication/SignInUserPasskey.tsx | 3 ++- .../Authentication/SignUpUserPasskey.tsx | 9 ++++----- src/components/Profile/AddPasskey.tsx | 4 ++-- src/components/Profile/interfaces/index.ts | 20 ++++++------------- 5 files changed, 16 insertions(+), 24 deletions(-) diff --git a/src/api/Fido.ts b/src/api/Fido.ts index 88db0477c..632461e77 100644 --- a/src/api/Fido.ts +++ b/src/api/Fido.ts @@ -1,4 +1,4 @@ -import type { DeviceDetails, IdeviceBody, RegistrationOptionInterface, UserEmail, verifyRegistrationObjInterface } from "../components/Profile/interfaces" +import type { DeviceDetails, IdeviceBody, RegistrationOptionInterface, UserEmail, VerifyRegistrationObjInterface } from "../components/Profile/interfaces" import { storageKeys } from "../config/CommonConstant" import { apiRoutes } from "../config/apiRoutes" import { axiosDelete, axiosGet, axiosPost, axiosPut } from "../services/apiRequests" @@ -28,7 +28,7 @@ export const generateRegistrationOption = async (payload: RegistrationOptionInte } } -export const verifyRegistration = async (payload:verifyRegistrationObjInterface, email:string) => { +export const verifyRegistration = async (payload:VerifyRegistrationObjInterface, email:string) => { const token = await getFromLocalStorage(storageKeys.TOKEN) const details = { url: `${apiRoutes.auth.verifyRegistration}${email}`, diff --git a/src/components/Authentication/SignInUserPasskey.tsx b/src/components/Authentication/SignInUserPasskey.tsx index fce505fda..6912106a8 100644 --- a/src/components/Authentication/SignInUserPasskey.tsx +++ b/src/components/Authentication/SignInUserPasskey.tsx @@ -1,7 +1,7 @@ import './global.css' import { Alert, Button } from 'flowbite-react'; -import { UserSignInData, getUserProfile, loginUser, passwordEncryption, setToLocalStorage } from '../../api/Auth'; +import { UserSignInData, getUserProfile, loginUser, setToLocalStorage } from '../../api/Auth'; import { apiStatusCodes, storageKeys } from '../../config/CommonConstant'; import { generateAuthenticationOption, verifyAuthentication } from '../../api/Fido'; @@ -13,6 +13,7 @@ import SignInUserPassword from './SignInUserPassword'; import { pathRoutes } from '../../config/pathRoutes'; import NavBar from "./NavBar"; import FooterBar from './FooterBar'; + interface signInUserProps { email: string } diff --git a/src/components/Authentication/SignUpUserPasskey.tsx b/src/components/Authentication/SignUpUserPasskey.tsx index cbc131369..519e1e1fa 100644 --- a/src/components/Authentication/SignUpUserPasskey.tsx +++ b/src/components/Authentication/SignUpUserPasskey.tsx @@ -2,19 +2,18 @@ import 'react-toastify/dist/ReactToastify.css'; import { Alert, Button } from 'flowbite-react'; import type { AxiosError, AxiosResponse } from 'axios'; -import type { IdeviceBody, RegistrationOptionInterface } from '../Profile/interfaces/index.js'; +import type { IdeviceBody, RegistrationOptionInterface, VerifyRegistrationObjInterface} from '../Profile/interfaces/index.js'; import { addDeviceDetails, generateRegistrationOption, verifyRegistration } from '../../api/Fido.js'; import { AddPasswordDetails, addPasswordDetails, getFromLocalStorage, passwordEncryption } from '../../api/Auth.js'; import { apiStatusCodes, storageKeys } from '../../config/CommonConstant.js'; import { useEffect, useState } from 'react'; - import SignUpUserPassword from './SignUpUserPassword.jsx'; import { startRegistration } from '@simplewebauthn/browser'; import SignUpUserName from './SignUpUserName.js'; import { v4 as uuidv4 } from 'uuid'; import NavBar from './NavBar.js'; import FooterBar from './FooterBar.js'; - + interface passwordValues { password: string, @@ -109,7 +108,7 @@ const SignUpUserPasskey = ({ email, firstName, lastName }: { email: string, firs } setLoading(false) const attResp = await startRegistration(opts) - const verifyRegistrationObj = { + const verifyRegistrationObj: VerifyRegistrationObjInterface = { ...attResp, challangeId } @@ -124,7 +123,7 @@ const SignUpUserPasskey = ({ email, firstName, lastName }: { email: string, firs } let credentialID = ''; - const verifyRegistrationMethod = async (verifyRegistrationObj: any, OrgUserEmail: string) => { + const verifyRegistrationMethod = async (verifyRegistrationObj: VerifyRegistrationObjInterface, OrgUserEmail: string) => { try { const verificationRegisterResp = await verifyRegistration(verifyRegistrationObj, OrgUserEmail) const { data } = verificationRegisterResp as AxiosResponse diff --git a/src/components/Profile/AddPasskey.tsx b/src/components/Profile/AddPasskey.tsx index e2c1ce65b..dd2970920 100644 --- a/src/components/Profile/AddPasskey.tsx +++ b/src/components/Profile/AddPasskey.tsx @@ -8,7 +8,7 @@ import { apiRoutes } from '../../config/apiRoutes' import { startRegistration } from '@simplewebauthn/browser' import { getFromLocalStorage } from '../../api/Auth' import CustomSpinner from '../CustomSpinner' -import type { IDeviceData, IdeviceBody, RegistrationOptionInterface, verifyRegistrationObjInterface } from './interfaces' +import type { IDeviceData, IdeviceBody, RegistrationOptionInterface, VerifyRegistrationObjInterface} from './interfaces' import type { AxiosError, AxiosResponse } from 'axios' const AddPasskey = () => { @@ -79,7 +79,7 @@ const AddPasskey = () => { } } - const verifyRegistrationMethod = async (verifyRegistrationObj, OrgUserEmail: string) => { + const verifyRegistrationMethod = async (verifyRegistrationObj: VerifyRegistrationObjInterface, OrgUserEmail: string) => { try { const verificationRegisterResp = await verifyRegistration(verifyRegistrationObj, OrgUserEmail) const { data } = verificationRegisterResp as AxiosResponse diff --git a/src/components/Profile/interfaces/index.ts b/src/components/Profile/interfaces/index.ts index 9be70237d..6ed2fa620 100644 --- a/src/components/Profile/interfaces/index.ts +++ b/src/components/Profile/interfaces/index.ts @@ -7,23 +7,15 @@ export interface RegistrationOptionInterface { export interface AddPassword { password: string, } -export interface verifyRegistrationObjInterface { +export interface VerifyRegistrationObjInterface{ id: string; rawId: string; - response: { - attestationObject: string; - clientDataJSON: string; - transports: string[]; - }; - type: string; - clientExtensionResults: { - credProps: { - rk: boolean; - }; - }; - authenticatorAttachment: string; + response: object; + authenticatorAttachment?: AuthenticatorAttachment; + clientExtensionResults: AuthenticationExtensionsClientOutputs; + type: PublicKeyCredentialType; challangeId: string; -} +}; export interface IDeviceData { createDateTime: string From 21bea37480a40d950a5edfe7a6fa88fbd3b2aebb Mon Sep 17 00:00:00 2001 From: bhavanakarwade Date: Fri, 13 Oct 2023 17:49:25 +0530 Subject: [PATCH 05/16] fix: sonarlint checks Signed-off-by: bhavanakarwade --- src/components/Issuance/Issuance.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Issuance/Issuance.tsx b/src/components/Issuance/Issuance.tsx index 53472124d..02a62af59 100644 --- a/src/components/Issuance/Issuance.tsx +++ b/src/components/Issuance/Issuance.tsx @@ -147,7 +147,7 @@ const IssueCred = () => { } else if (dataType === 'number') { return typeof value === 'number'; } else if (dataType === 'date') { - return !isNaN(Date.parse(value)); + return !isNaN(Date.parse(value as string)); } return true; }, From a13da45d2baf1973940e897b3d2c7c4a503bc770 Mon Sep 17 00:00:00 2001 From: bhavanakarwade Date: Sat, 14 Oct 2023 13:02:41 +0530 Subject: [PATCH 06/16] changed loader condition Signed-off-by: bhavanakarwade --- src/components/Authentication/SignUpUserPasskey.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Authentication/SignUpUserPasskey.tsx b/src/components/Authentication/SignUpUserPasskey.tsx index 519e1e1fa..ddcff8622 100644 --- a/src/components/Authentication/SignUpUserPasskey.tsx +++ b/src/components/Authentication/SignUpUserPasskey.tsx @@ -281,7 +281,7 @@ const SignUpUserPasskey = ({ email, firstName, lastName }: { email: string, firs - { - (addSuccess || addfailure || fidoError) && -
- { - setAddSuccess(null) - setFidoError('') - setAddFailure('') - }} - > - -

- {addSuccess || addfailure || fidoError} -

-
-
-
- } - -
- - -
- - } -
- - - - - ) -} - -export default AddPasskey \ No newline at end of file + const [openModel, setOpenModel] = useState(false); + + const props = { openModel, setOpenModel }; + const setProfile = async () => { + const UserEmail = await getFromLocalStorage(storageKeys.USER_EMAIL); + setOrgUserEmail(UserEmail); + return UserEmail; + }; + + const showFidoError = (error: unknown): void => { + const err = error as AxiosError; + if ( + err.message.includes('The operation either timed out or was not allowed') + ) { + const [errorMsg] = err.message.split('.'); + setFidoError(errorMsg); + } else { + setFidoError(err.message); + } + }; + + const addDevice = async (): Promise => { + try { + setOpenModel(true); + } catch (error) { + setFidoLoader(false); + } + }; + + const registerWithPasskey = async (flag: boolean): Promise => { + try { + const RegistrationOption: RegistrationOptionInterface = { + userName: OrgUserEmail, + deviceFlag: flag, + }; + // Generate Registration Option + const generateRegistrationResponse = await generateRegistrationOption( + RegistrationOption, + ); + const { data } = generateRegistrationResponse as AxiosResponse; + const opts = data?.data; + const challangeId = data?.data?.challenge; + if (opts) { + opts.authenticatorSelection = { + residentKey: 'preferred', + requireResidentKey: false, + userVerification: 'preferred', + }; + } + setOpenModel(false); + const attResp = await startRegistration(opts); + + const verifyRegistrationObj = { + ...attResp, + challangeId, + }; + await verifyRegistrationMethod(verifyRegistrationObj, OrgUserEmail); + } catch (error) { + showFidoError(error); + } + }; + + const verifyRegistrationMethod = async ( + verifyRegistrationObj: VerifyRegistrationObjInterface, + OrgUserEmail: string, + ) => { + try { + const verificationRegisterResp = await verifyRegistration( + verifyRegistrationObj, + OrgUserEmail, + ); + const { data } = verificationRegisterResp as AxiosResponse; + const credentialID = data?.data?.newDevice?.credentialID; + + if (data?.data?.verified) { + let platformDeviceName = ''; + + if ( + verifyRegistrationObj?.authenticatorAttachment === 'cross-platform' + ) { + platformDeviceName = 'Passkey'; + } else { + platformDeviceName = navigator.platform; + } + + const deviceBody: IdeviceBody = { + userName: OrgUserEmail, + credentialId: encodeURIComponent(credentialID), + deviceFriendlyName: platformDeviceName, + }; + await addDeviceDetailsMethod(deviceBody); + } + } catch (error) { + showFidoError(error); + } + }; + + const addDeviceDetailsMethod = async (deviceBody: IdeviceBody) => { + try { + const deviceDetailsResp = await addDeviceDetails(deviceBody); + const { data } = deviceDetailsResp as AxiosResponse; + if (data?.statusCode === apiStatusCodes.API_STATUS_SUCCESS) { + setAddSuccess('Device added successfully'); + userDeviceDetails(); + } else { + setAddFailure(deviceDetailsResp as string); + } + } catch (error) { + showFidoError(error); + } + }; + + //userDeviceDetails on page reload + const userDeviceDetails = async (): Promise => { + try { + setFidoLoader(true); + + const userDeviceDetailsResp = await getUserDeviceDetails(OrgUserEmail); + const { data } = userDeviceDetailsResp as AxiosResponse; + setFidoLoader(false); + if (userDeviceDetailsResp) { + const deviceDetails = + Object.keys(data)?.length > 0 + ? userDeviceDetailsResp?.data?.data.map((data) => { + data.lastChangedDateTime = data.lastChangedDateTime + ? data.lastChangedDateTime + : '-'; + return data; + }) + : []; + if (data?.data?.length === 1) { + setDisableFlag(true); + } + setDeviceList(deviceDetails); + } + } catch (error) { + setAddFailure('Error while fetching the device details'); + setFidoLoader(false); + } + }; + useEffect(() => { + if (OrgUserEmail) { + userDeviceDetails(); + } else { + setProfile(); + } + }, [OrgUserEmail]); + + return ( +
+ {(addSuccess || addfailure || fidoError) && ( +
+ { + setAddSuccess(null); + setFidoError(''); + setAddFailure(''); + }} + > + +

{addSuccess || addfailure || fidoError}

+
+
+
+ )} +
+
+
+ {fidoLoader ? ( +
+ +
+ ) : ( +
+
+
+

+ Add Passkey +

+

+ With Passkey, no complex passwords to remember. +

+
+ + {deviceList && + deviceList.length > 0 && + deviceList.map((element, key) => ( + + ))} + +
+ +
+ + +
+
+ )} +
+
+
+
+ ); +}; + +export default AddPasskey; From 822315ef49697f3d31904bbe46e1e1cfbcd95027 Mon Sep 17 00:00:00 2001 From: bhavanakarwade Date: Tue, 17 Oct 2023 15:26:19 +0530 Subject: [PATCH 09/16] resolved dark mode changes Signed-off-by: bhavanakarwade --- src/components/Authentication/SignUpUserName.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/Authentication/SignUpUserName.tsx b/src/components/Authentication/SignUpUserName.tsx index 49fde1863..c91195775 100644 --- a/src/components/Authentication/SignUpUserName.tsx +++ b/src/components/Authentication/SignUpUserName.tsx @@ -156,7 +156,7 @@ const SignUpUserName = () => {
-
{
-
Date: Wed, 18 Oct 2023 00:18:00 +0530 Subject: [PATCH 10/16] worked on alert box messages Signed-off-by: bhavanakarwade --- .../Authentication/SignInUserPasskey.tsx | 24 ++++++------- .../Authentication/SignUpUserPasskey.tsx | 36 +++++++++---------- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/src/components/Authentication/SignInUserPasskey.tsx b/src/components/Authentication/SignInUserPasskey.tsx index d89e15644..1c4a0b0ab 100644 --- a/src/components/Authentication/SignInUserPasskey.tsx +++ b/src/components/Authentication/SignInUserPasskey.tsx @@ -5,7 +5,7 @@ import { UserSignInData, getUserProfile, loginUser, setToLocalStorage } from '.. import { apiStatusCodes, storageKeys } from '../../config/CommonConstant'; import { generateAuthenticationOption, verifyAuthentication } from '../../api/Fido'; -import type { AxiosResponse } from 'axios'; +import type { AxiosError, AxiosResponse } from 'axios'; import SignInUser from './SignInUser'; import { startAuthentication } from '@simplewebauthn/browser'; import { useState } from 'react'; @@ -65,16 +65,17 @@ const SignInUserPasskey = (signInUserProps: signInUserProps) => { } const showFidoError = (error: unknown): void => { - const err = error as string - if (err.includes("The operation either timed out or was not allowed")) { - const [errorMsg] = err.split('.') - setFidoUserError(errorMsg) + const err = error as AxiosError; + if ( + err.message.includes('The operation either timed out or was not allowed') + ) { + const [errorMsg] = err.message.split('.'); + setFidoUserError(errorMsg); + } else { + setFidoUserError(err.message); + } + }; - } else { - setFidoUserError(err) - - } - } const authenticateWithPasskey = async (email: string): Promise => { try { @@ -152,8 +153,6 @@ const SignInUserPasskey = (signInUserProps: signInUserProps) => { src="/images/choose-password-passkey.svg" alt="img" />
- -
@@ -166,6 +165,7 @@ const SignInUserPasskey = (signInUserProps: signInUserProps) => { onDismiss={() => { setSuccess(null) setFailure(null) + setFidoUserError('') }} > diff --git a/src/components/Authentication/SignUpUserPasskey.tsx b/src/components/Authentication/SignUpUserPasskey.tsx index ddcff8622..7db3d1a92 100644 --- a/src/components/Authentication/SignUpUserPasskey.tsx +++ b/src/components/Authentication/SignUpUserPasskey.tsx @@ -42,20 +42,17 @@ const SignUpUserPasskey = ({ email, firstName, lastName }: { email: string, firs }, []) const showFidoError = (error: unknown): void => { - const err = error as AxiosError - if (err.message.includes("The operation either timed out or was not allowed")) { - const [errorMsg] = err.message.split('.') - setFidoError(errorMsg) - setTimeout(() => { - setFidoError("") - }) - } else { - setFidoError(err.message) - setTimeout(() => { - setFidoError("") - }) - } - } + const err = error as AxiosError; + if ( + err.message.includes('The operation either timed out or was not allowed') + ) { + const [errorMsg] = err.message.split('.'); + setFidoError(errorMsg); + } else { + setFidoError(err.message); + } + }; + const submit = async (fidoFlag: boolean, passwordDetails?: passwordValues) => { const userEmail = await getFromLocalStorage(storageKeys.USER_EMAIL) @@ -141,7 +138,6 @@ const SignUpUserPasskey = ({ email, firstName, lastName }: { email: string, firs userName: OrgUserEmail, credentialId: credentialID, deviceFriendlyName: platformDeviceName - } await addDeviceDetailsMethod(deviceBody) } @@ -197,14 +193,18 @@ const SignUpUserPasskey = ({ email, firstName, lastName }: { email: string, firs
{ - (verificationSuccess || erroMsg) && + (verificationSuccess || erroMsg || fidoError) && setErrMsg(null)} + onDismiss={() => { + setAddSuccess(null) + setFidoError('') + setErrMsg('') + }} >

- {verificationSuccess || erroMsg} + {verificationSuccess || erroMsg || fidoError}

From 6aea1b30ca58e4d9e7f5e1f532cc327ad59d39ea Mon Sep 17 00:00:00 2001 From: bhavanakarwade Date: Wed, 18 Oct 2023 11:55:53 +0530 Subject: [PATCH 11/16] handle alert box conditions Signed-off-by: bhavanakarwade --- src/commonComponents/DeviceDetailsCard.tsx | 1 + .../Authentication/SignInUserPasskey.tsx | 557 ++++++++++-------- 2 files changed, 311 insertions(+), 247 deletions(-) diff --git a/src/commonComponents/DeviceDetailsCard.tsx b/src/commonComponents/DeviceDetailsCard.tsx index babaf1cad..bda00c9c3 100644 --- a/src/commonComponents/DeviceDetailsCard.tsx +++ b/src/commonComponents/DeviceDetailsCard.tsx @@ -87,6 +87,7 @@ const DeviceDetails = (props: { deviceFriendlyName: string, createDateTime: stri className="p-1 border border-gray-400 rounded hover:bg-gray-100 dark:hover:bg-black dark:text-white dark:hover:text-white" onClick={(e) => { e.preventDefault(); + props.refreshList() setOpenEditModel(true) }} > diff --git a/src/components/Authentication/SignInUserPasskey.tsx b/src/components/Authentication/SignInUserPasskey.tsx index 1c4a0b0ab..722b61f02 100644 --- a/src/components/Authentication/SignInUserPasskey.tsx +++ b/src/components/Authentication/SignInUserPasskey.tsx @@ -1,9 +1,17 @@ -import './global.css' +import './global.css'; import { Alert, Button } from 'flowbite-react'; -import { UserSignInData, getUserProfile, loginUser, setToLocalStorage } from '../../api/Auth'; +import { + UserSignInData, + getUserProfile, + loginUser, + setToLocalStorage, +} from '../../api/Auth'; import { apiStatusCodes, storageKeys } from '../../config/CommonConstant'; -import { generateAuthenticationOption, verifyAuthentication } from '../../api/Fido'; +import { + generateAuthenticationOption, + verifyAuthentication, +} from '../../api/Fido'; import type { AxiosError, AxiosResponse } from 'axios'; import SignInUser from './SignInUser'; @@ -11,60 +19,65 @@ import { startAuthentication } from '@simplewebauthn/browser'; import { useState } from 'react'; import SignInUserPassword from './SignInUserPassword'; import { pathRoutes } from '../../config/pathRoutes'; -import NavBar from "./NavBar"; +import NavBar from './NavBar'; import FooterBar from './FooterBar'; interface signInUserProps { - email: string + email: string; } const SignInUserPasskey = (signInUserProps: signInUserProps) => { - const [loading, setLoading] = useState(false) - const [showSignInUser, setShowSignInUser] = useState(true); - const [showSignInUserPassword, setShowSignInUserPassword] = useState(false); - const [fidoLoader, setFidoLoader] = useState(false) - const [fidoUserError, setFidoUserError] = useState("") - const [failure, setFailure] = useState(null) - const [success, setSuccess] = useState(null) - - - const handleSvgClick = () => { - window.history.pushState(null, '', pathRoutes.auth.sinIn); - setShowSignInUser(!showSignInUser); - }; - - const handlePasswordButtonClick = () => { - setShowSignInUserPassword(true); - setShowSignInUser(false); - }; - - const verifyAuthenticationMethod = async (verifyAuthenticationObj: unknown, userData: { userName: string }): Promise => { - try { - return await verifyAuthentication(verifyAuthenticationObj, userData); - } catch (error) { - setFidoLoader(false) - throw error; - } - }; + const [loading, setLoading] = useState(false); + const [showSignInUser, setShowSignInUser] = useState(true); + const [showSignInUserPassword, setShowSignInUserPassword] = useState(false); + const [fidoLoader, setFidoLoader] = useState(false); + const [fidoUserError, setFidoUserError] = useState(''); + const [failure, setFailure] = useState(null); + const [success, setSuccess] = useState(null); + + const handleSvgClick = () => { + window.history.pushState(null, '', pathRoutes.auth.sinIn); + setShowSignInUser(!showSignInUser); + }; - const getUserDetails = async (access_token: string) => { - const userDetails = await getUserProfile(access_token); - const { data } = userDetails as AxiosResponse - if (data?.data?.userOrgRoles?.length > 0) { - const permissionArray: number | string[] = [] - data?.data?.userOrgRoles?.forEach((element: { orgRole: { name: string } }) => permissionArray.push(element?.orgRole?.name)); - await setToLocalStorage(storageKeys.PERMISSIONS, permissionArray) - await setToLocalStorage(storageKeys.USER_PROFILE, data?.data) - await setToLocalStorage(storageKeys.USER_EMAIL, data?.data?.email) + const handlePasswordButtonClick = () => { + setShowSignInUserPassword(true); + setShowSignInUser(false); + }; - window.location.href = '/dashboard' + const verifyAuthenticationMethod = async ( + verifyAuthenticationObj: unknown, + userData: { userName: string }, + ): Promise => { + try { + const res = verifyAuthentication(verifyAuthenticationObj, userData); + return await res; + } catch (error) { + setFidoLoader(false); + throw error; + } + }; - } else { - setFailure(userDetails as string) - } - setLoading(false) - } + const getUserDetails = async (access_token: string) => { + const userDetails = await getUserProfile(access_token); + const { data } = userDetails as AxiosResponse; + if (data?.data?.userOrgRoles?.length > 0) { + const permissionArray: number | string[] = []; + data?.data?.userOrgRoles?.forEach( + (element: { orgRole: { name: string } }) => + permissionArray.push(element?.orgRole?.name), + ); + await setToLocalStorage(storageKeys.PERMISSIONS, permissionArray); + await setToLocalStorage(storageKeys.USER_PROFILE, data?.data); + await setToLocalStorage(storageKeys.USER_EMAIL, data?.data?.email); + + window.location.href = '/dashboard'; + } else { + setFailure(userDetails as string); + } + setLoading(false); + }; - const showFidoError = (error: unknown): void => { + const showFidoError = (error: unknown): void => { const err = error as AxiosError; if ( err.message.includes('The operation either timed out or was not allowed') @@ -76,204 +89,254 @@ const SignInUserPasskey = (signInUserProps: signInUserProps) => { } }; - - const authenticateWithPasskey = async (email: string): Promise => { - try { - setFidoLoader(true) - - const obj = { userName: email } - - const generateAuthenticationResponse: any = await generateAuthenticationOption(obj); - const challangeId: string = generateAuthenticationResponse?.data?.data?.challenge; - setFidoUserError(generateAuthenticationResponse?.data?.error); - - const opts = generateAuthenticationResponse?.data?.data; - const attResp = await startAuthentication(opts); - const verifyAuthenticationObj = { - ...attResp, - challangeId - }; - - const verificationResp = await verifyAuthenticationMethod(verifyAuthenticationObj, obj); - - const { data } = verificationResp as AxiosResponse - if (data?.data.verified) { - const payload: UserSignInData = { - email: email, - isPasskey: true - }; - const loginRsp = await loginUser(payload); - const { data } = loginRsp as AxiosResponse; - if (data?.statusCode === apiStatusCodes.API_STATUS_SUCCESS) { - await setToLocalStorage(storageKeys.TOKEN, data?.data?.access_token); - const response = await fetch('/api/auth/signin', { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify(data), - }); - - if (response.redirected) { - getUserDetails(data?.data?.access_token) - } - - } else if (data?.error) { - setFidoLoader(false) - setFidoUserError(data?.error); - - } - } - } catch (error) { - if (error instanceof DOMException) { - setFidoLoader(false) - setFidoUserError('The operation either timed out or was not allowed.'); - } else { - setFidoLoader(false) - showFidoError(error); - } - } - finally { - setLoading(false); - } - }; - - return ( -
- {showSignInUser ? ( - -
- -
-
-
- - img -
-
-
-
- - - -
- ) : ( - - showSignInUserPassword ? : - - )} -
- ); + const authenticateWithPasskey = async (email: string): Promise => { + try { + setFidoLoader(true); + + const obj = { userName: email }; + + const generateAuthenticationResponse: any = + await generateAuthenticationOption(obj); + const challangeId: string = + generateAuthenticationResponse?.data?.data?.challenge; + setFidoUserError(generateAuthenticationResponse?.data?.error); + + const opts = generateAuthenticationResponse?.data?.data; + const attResp = await startAuthentication(opts); + const verifyAuthenticationObj = { + ...attResp, + challangeId, + }; + + const verificationResp = await verifyAuthenticationMethod( + verifyAuthenticationObj, + obj, + ); + const { data } = verificationResp as AxiosResponse; + + if (data?.data.verified) { + const payload: UserSignInData = { + email: email, + isPasskey: true, + }; + const loginRsp = await loginUser(payload); + const { data } = loginRsp as AxiosResponse; + + if (data?.statusCode === apiStatusCodes.API_STATUS_SUCCESS) { + await setToLocalStorage(storageKeys.TOKEN, data?.data?.access_token); + const response = await fetch('/api/auth/signin', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(data), + }); + + if (response.redirected) { + getUserDetails(data?.data?.access_token); + } + } else if (data?.error) { + } + } else { + setFidoLoader(false); + setFidoUserError(verificationResp as string); + } + } catch (error) { + if (error instanceof DOMException) { + setFidoLoader(false); + setFidoUserError('The operation either timed out or was not allowed.'); + } else { + setFidoLoader(false); + showFidoError(error); + } + } finally { + setLoading(false); + } + }; + return ( +
+ {showSignInUser ? ( + + ) : showSignInUserPassword ? ( + + ) : ( + + )} +
+ ); }; -export default SignInUserPasskey; \ No newline at end of file +export default SignInUserPasskey; From 5df0dd99265e85e99645ad37e6600ed615cd9a7b Mon Sep 17 00:00:00 2001 From: Moulika Kulkarni Date: Wed, 18 Oct 2023 18:46:47 +0530 Subject: [PATCH 12/16] fix: dark mode issues Signed-off-by: Moulika Kulkarni --- src/components/User/UserDashBoard.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/User/UserDashBoard.tsx b/src/components/User/UserDashBoard.tsx index 5ac4bc454..3b2a005b9 100644 --- a/src/components/User/UserDashBoard.tsx +++ b/src/components/User/UserDashBoard.tsx @@ -275,7 +275,7 @@ const UserDashBoard = () => { Recent Activity {activityList && activityList?.length === 0 && ( -
+
Looks like there are no activities to display at the moment.
)} From 0d61041a2397a08198bcd48a9348269fafd27f07 Mon Sep 17 00:00:00 2001 From: Moulika Kulkarni Date: Wed, 18 Oct 2023 19:23:03 +0530 Subject: [PATCH 13/16] fix: dark mode issues Signed-off-by: Moulika Kulkarni --- src/components/User/UserDashBoard.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/User/UserDashBoard.tsx b/src/components/User/UserDashBoard.tsx index 3b2a005b9..74d7af343 100644 --- a/src/components/User/UserDashBoard.tsx +++ b/src/components/User/UserDashBoard.tsx @@ -270,13 +270,13 @@ const UserDashBoard = () => {
-
+

Recent Activity

{activityList && activityList?.length === 0 && ( -
- Looks like there are no activities to display at the moment. +
+ Looks like there is no activity to display at the moment.
)}
From 48bbdb2b933efe0ea3dc15f37d3e8f9494bca59f Mon Sep 17 00:00:00 2001 From: bhavanakarwade Date: Thu, 19 Oct 2023 12:13:24 +0530 Subject: [PATCH 14/16] handle condition for edit passkey button Signed-off-by: bhavanakarwade --- src/commonComponents/DeviceDetailsCard.tsx | 3 +-- src/components/Profile/AddPasskey.tsx | 2 ++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/commonComponents/DeviceDetailsCard.tsx b/src/commonComponents/DeviceDetailsCard.tsx index bda00c9c3..2da699973 100644 --- a/src/commonComponents/DeviceDetailsCard.tsx +++ b/src/commonComponents/DeviceDetailsCard.tsx @@ -87,7 +87,6 @@ const DeviceDetails = (props: { deviceFriendlyName: string, createDateTime: stri className="p-1 border border-gray-400 rounded hover:bg-gray-100 dark:hover:bg-black dark:text-white dark:hover:text-white" onClick={(e) => { e.preventDefault(); - props.refreshList() setOpenEditModel(true) }} > @@ -115,7 +114,7 @@ const DeviceDetails = (props: { deviceFriendlyName: string, createDateTime: stri handleDeleteModel(true) }} > - Revoke + Revoke {props.disableRevoke}
diff --git a/src/components/Profile/AddPasskey.tsx b/src/components/Profile/AddPasskey.tsx index 154b2bb5e..05c582106 100644 --- a/src/components/Profile/AddPasskey.tsx +++ b/src/components/Profile/AddPasskey.tsx @@ -162,6 +162,8 @@ const AddPasskey = () => { : []; if (data?.data?.length === 1) { setDisableFlag(true); + } else { + setDisableFlag(false); } setDeviceList(deviceDetails); } From 0ab132c3321941b980c5ad5b2ef5d21f9efefa98 Mon Sep 17 00:00:00 2001 From: bhavanakarwade Date: Thu, 19 Oct 2023 12:35:19 +0530 Subject: [PATCH 15/16] remove unnecessary code Signed-off-by: bhavanakarwade --- src/commonComponents/DeviceDetailsCard.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commonComponents/DeviceDetailsCard.tsx b/src/commonComponents/DeviceDetailsCard.tsx index 2da699973..babaf1cad 100644 --- a/src/commonComponents/DeviceDetailsCard.tsx +++ b/src/commonComponents/DeviceDetailsCard.tsx @@ -114,7 +114,7 @@ const DeviceDetails = (props: { deviceFriendlyName: string, createDateTime: stri handleDeleteModel(true) }} > - Revoke {props.disableRevoke} + Revoke
From 1acb4c98c14c633b9fbeb3f2e1472ba9f625a5cf Mon Sep 17 00:00:00 2001 From: tipusinghaw Date: Thu, 19 Oct 2023 12:50:54 +0530 Subject: [PATCH 16/16] feat: implemented get credential definition based on schema Id Signed-off-by: tipusinghaw --- src/api/verification.ts | 2 +- src/components/Verification/CredDefSelection.tsx | 8 ++++---- src/config/apiRoutes.ts | 1 + 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/api/verification.ts b/src/api/verification.ts index f962fff52..177185d36 100644 --- a/src/api/verification.ts +++ b/src/api/verification.ts @@ -89,7 +89,7 @@ export const getProofAttributes=async (proofId:string)=>{ export const getCredentialDefinitionsForVerification = async (schemaId: string) => { const orgId = await getFromLocalStorage(storageKeys.ORG_ID); - const url= `${apiRoutes.organizations.root}/${orgId}${apiRoutes.schema.getCredDefBySchemaId}/${schemaId}/cred-defs`; + const url= `${apiRoutes.Verification.verificationCredDef}/${schemaId}`; const axiosPayload = { url, diff --git a/src/components/Verification/CredDefSelection.tsx b/src/components/Verification/CredDefSelection.tsx index c70005aff..a52a4950e 100644 --- a/src/components/Verification/CredDefSelection.tsx +++ b/src/components/Verification/CredDefSelection.tsx @@ -66,12 +66,11 @@ const CredDefSelection = () => { const getCredDefs = async (schemaId: string) => { setLoading(true) - const response = await getCredentialDefinitionsForVerification(schemaId,31); + const response = await getCredentialDefinitionsForVerification(schemaId); const { data } = response as AxiosResponse - if (data?.statusCode === apiStatusCodes.API_STATUS_SUCCESS) { - const credDefs = data?.data?.data.map((ele: CredDefData) => { + const credDefs = data?.data?.map((ele: CredDefData) => { return { data: [{ data: ele?.tag ? ele?.tag : 'Not available' }, { data: ele?.credentialDefinitionId ? ele?.credentialDefinitionId : 'Not available' }, { data: ele?.revocable === true ? Yes : No }, @@ -99,9 +98,10 @@ const CredDefSelection = () => { if (credDefs?.length === 0) { setError('No Data Found') } - + setLoading(false) setCredDefList(credDefs) } else { + setLoading(false) setError(response as string) } diff --git a/src/config/apiRoutes.ts b/src/config/apiRoutes.ts index fedc98ff3..a58a16acc 100644 --- a/src/config/apiRoutes.ts +++ b/src/config/apiRoutes.ts @@ -54,6 +54,7 @@ export const apiRoutes = { verifyCredential: '/proofs', presentationVerification: '/proofs', proofRequestAttributesVerification: '/proofs', + verificationCredDef: '/verifiation/cred-defs' }, Agent: { checkAgentHealth: '/agents/health',