mirror of
https://github.com/mosip/inji-wallet.git
synced 2026-01-07 20:53:54 -05:00
[INJIMOB-3647] refactor: update isRevoked data type (#2149)
* [INJIMOB-3647] refactor: modify data type of isRevoked to EvaluationStatus Type representing any possible value of EvaluationStatus. - "TRUE" → Condition was evaluated and is positively true - "FALSE" → Condition was evaluated and is definitively false - "UNDETERMINED" → Condition could not be evaluated due to an error Signed-off-by: KiruthikaJeyashankar <kiruthikavjshankar@gmail.com> * [INJIMOB-3647] refactor: modify data type of isRevoked to EvaluationStatus Type representing any possible value of EvaluationStatus. - "TRUE" → Condition was evaluated and is positively true - "FALSE" → Condition was evaluated and is definitively false - "UNDETERMINED" → Condition could not be evaluated due to an error Signed-off-by: KiruthikaJeyashankar <kiruthikavjshankar@gmail.com> * [INJIMOB-3647] refactor: change statuslistVC type to record from string Signed-off-by: KiruthikaJeyashankar <kiruthikavjshankar@gmail.com> # Conflicts: # shared/vcjs/verifyCredential.ts * [INJIMOB-3647] refactor: update status revoke check to check for null status Signed-off-by: KiruthikaJeyashankar <kiruthikavjshankar@gmail.com> * [INJIMOB-3647] refactor: VCMetadat constructor isRevoked param Signed-off-by: KiruthikaJeyashankar <kiruthikavjshankar@gmail.com> * [INJIMOB-3647] refactor: rename EvaluationStatus to RevocationStatus Signed-off-by: KiruthikaJeyashankar <kiruthikavjshankar@gmail.com> * [INJIMOB-3647] refactor: modify revocation status logs Signed-off-by: KiruthikaJeyashankar <kiruthikavjshankar@gmail.com> --------- Signed-off-by: KiruthikaJeyashankar <kiruthikavjshankar@gmail.com>
This commit is contained in:
committed by
GitHub
parent
0e667bd46d
commit
9457ad0d9f
10
.talismanrc
10
.talismanrc
@@ -64,7 +64,7 @@ fileignoreconfig:
|
|||||||
- filename: assets/Finger_Print_Icon.svg
|
- filename: assets/Finger_Print_Icon.svg
|
||||||
checksum: 776d4fe4fc4b54d185ccf97daf0511b9fe2c0e0f7c1a809047020e5e8a100db6
|
checksum: 776d4fe4fc4b54d185ccf97daf0511b9fe2c0e0f7c1a809047020e5e8a100db6
|
||||||
- filename: screens/MainLayout.tsx
|
- filename: screens/MainLayout.tsx
|
||||||
checksum: dd31361997111c28461239e986112a30ee986e99432ac3016033508863b90ddd
|
checksum: 8909ef957c866221e864c6edaf93081af7f5968857200284bf7047631f525322
|
||||||
- filename: android/app/build.gradle
|
- filename: android/app/build.gradle
|
||||||
checksum: 8d5715e179a398518e6acff82c75b27077c9f893dc90b2972c77f9a09f10be95
|
checksum: 8d5715e179a398518e6acff82c75b27077c9f893dc90b2972c77f9a09f10be95
|
||||||
- filename: .github/workflows/push-triggers.yml
|
- filename: .github/workflows/push-triggers.yml
|
||||||
@@ -270,7 +270,7 @@ fileignoreconfig:
|
|||||||
- filename: machines/Issuers/IssuersService.ts
|
- filename: machines/Issuers/IssuersService.ts
|
||||||
checksum: e3832dff27687abc28609d2b281e570b4b0017995b7cfb56627a6b96949c469a
|
checksum: e3832dff27687abc28609d2b281e570b4b0017995b7cfb56627a6b96949c469a
|
||||||
- filename: screens/Home/ViewVcModal.tsx
|
- filename: screens/Home/ViewVcModal.tsx
|
||||||
checksum: cfb25d562185488432b76287c4ef93359c1c64d8e29f5755d4c0a726c1485442
|
checksum: 847d45d566b7fc86dd3ebbba74bf587399dd7754466e42ebdecd462a157705e9
|
||||||
- filename: injitest/src/main/resources/TestData.json
|
- filename: injitest/src/main/resources/TestData.json
|
||||||
checksum: 1b5af14c96b456898259b4cb7a5607b006404cf0360274bdc204d7d065698e3c
|
checksum: 1b5af14c96b456898259b4cb7a5607b006404cf0360274bdc204d7d065698e3c
|
||||||
- filename: injitest/src/test/java/androidTestCases/ActivateVcTest.java
|
- filename: injitest/src/test/java/androidTestCases/ActivateVcTest.java
|
||||||
@@ -385,7 +385,7 @@ fileignoreconfig:
|
|||||||
- filename: android/app/src/main/java/io/mosip/residentapp/InjiOpenId4VPModule.java
|
- filename: android/app/src/main/java/io/mosip/residentapp/InjiOpenId4VPModule.java
|
||||||
checksum: 6b315164dca5de95c11e0dc8cbb480207b19c312b1c9135adc39ef74a1ff7e35
|
checksum: 6b315164dca5de95c11e0dc8cbb480207b19c312b1c9135adc39ef74a1ff7e35
|
||||||
- filename: screens/Scan/SendVPScreenController.ts
|
- filename: screens/Scan/SendVPScreenController.ts
|
||||||
checksum: f898ac7f1ecfa1df17e33b327d675f57debf2d5bd56052fc047dd03577354590
|
checksum: aa228c43a01e653b9da6ee354a39c942bec25848aa9631650611d1b5f85623d7
|
||||||
- filename: screens/Scan/SendVPScreen.tsx
|
- filename: screens/Scan/SendVPScreen.tsx
|
||||||
checksum: de80cb9a932ed99e224438a8c373d117807101a39a440e97977654ef6935af6c
|
checksum: de80cb9a932ed99e224438a8c373d117807101a39a440e97977654ef6935af6c
|
||||||
- filename: machines/openID4VP/openID4VPMachine.typegen.ts
|
- filename: machines/openID4VP/openID4VPMachine.typegen.ts
|
||||||
@@ -416,4 +416,8 @@ fileignoreconfig:
|
|||||||
checksum: 669e85d1c8ff526b97fa4ed4b8ed33a100eaba9f2f41bceccd75dc7a85a12103
|
checksum: 669e85d1c8ff526b97fa4ed4b8ed33a100eaba9f2f41bceccd75dc7a85a12103
|
||||||
- filename: screens/Home/MyVcsTab.tsx
|
- filename: screens/Home/MyVcsTab.tsx
|
||||||
checksum: 68ff83c5d9062fbc077d008956fa654540253c52ce68d7105c175c51562b3dc9
|
checksum: 68ff83c5d9062fbc077d008956fa654540253c52ce68d7105c175c51562b3dc9
|
||||||
|
- filename: components/VC/common/VcStatustooTip.tsx
|
||||||
|
checksum: a48c88da719fadcb3d1aeb730a23735709c0c198351104203abd03445f6cc76f
|
||||||
|
- filename: screens/Settings/KeyManagementScreen.tsx
|
||||||
|
checksum: 6871fad16ecb5f019f502b2f7f715bc2a7b646ee08026b321aa1f8ce071dccc1
|
||||||
version: "1.0"
|
version: "1.0"
|
||||||
|
|||||||
3
App.tsx
3
App.tsx
@@ -59,7 +59,8 @@ const AppLayoutWrapper: React.FC = () => {
|
|||||||
const authService = appService.children.get('auth');
|
const authService = appService.children.get('auth');
|
||||||
const isAppSetupComplete = useSelector(authService, selectAppSetupComplete);
|
const isAppSetupComplete = useSelector(authService, selectAppSetupComplete);
|
||||||
|
|
||||||
const [isDeepLinkOverlayVisible, setDeepLinkOverlayVisible] = useState(isDeepLinkFlow);
|
const [isDeepLinkOverlayVisible, setDeepLinkOverlayVisible] =
|
||||||
|
useState(isDeepLinkFlow);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (AppState.currentState === 'active') {
|
if (AppState.currentState === 'active') {
|
||||||
|
|||||||
@@ -1,30 +1,28 @@
|
|||||||
import React from "react";
|
import React from 'react';
|
||||||
import { useTranslation } from "react-i18next";
|
import {useTranslation} from 'react-i18next';
|
||||||
import { View } from "react-native";
|
import {View} from 'react-native';
|
||||||
import { Column } from "../../ui";
|
import {Column} from '../../ui';
|
||||||
import { Theme } from "../../ui/styleUtils";
|
import {Theme} from '../../ui/styleUtils';
|
||||||
import { Text } from "../../ui";
|
import {Text} from '../../ui';
|
||||||
import { VC_STATUS_KEYS } from "./VCUtils";
|
import {VC_STATUS_KEYS} from './VCUtils';
|
||||||
|
|
||||||
export const StatusTooltipContent = () => {
|
export const StatusTooltipContent = () => {
|
||||||
const { t } = useTranslation('ViewVcModal');
|
const {t} = useTranslation('ViewVcModal');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Column align="center" style={{marginTop:20}}>
|
<Column align="center" style={{marginTop: 20}}>
|
||||||
{VC_STATUS_KEYS.map(key => (
|
{VC_STATUS_KEYS.map(key => (
|
||||||
<View key={key} style={{ marginBottom: 20 }}>
|
<View key={key} style={{marginBottom: 20}}>
|
||||||
<Text weight="semibold">{t(`statusToolTipContent.${key}.title`)}</Text>
|
<Text weight="semibold">
|
||||||
<Text
|
{t(`statusToolTipContent.${key}.title`)}
|
||||||
weight="regular"
|
</Text>
|
||||||
style={[
|
<Text
|
||||||
Theme.Styles.tooltipContentDescription,
|
weight="regular"
|
||||||
{ marginTop: 3 },
|
style={[Theme.Styles.tooltipContentDescription, {marginTop: 3}]}>
|
||||||
]}>
|
{t(`statusToolTipContent.${key}.description`)}
|
||||||
{t(`statusToolTipContent.${key}.description`)}
|
</Text>
|
||||||
</Text>
|
</View>
|
||||||
</View>
|
))}
|
||||||
))}
|
</Column>
|
||||||
</Column>
|
);
|
||||||
);
|
};
|
||||||
};
|
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import {Row, Text} from './ui';
|
|||||||
import {Theme} from './ui/styleUtils';
|
import {Theme} from './ui/styleUtils';
|
||||||
import {useTranslation} from 'react-i18next';
|
import {useTranslation} from 'react-i18next';
|
||||||
import {VCMetadata} from '../shared/VCMetadata';
|
import {VCMetadata} from '../shared/VCMetadata';
|
||||||
|
import {RevocationStatus} from '../shared/vcVerifier/VcVerifier';
|
||||||
|
|
||||||
export const VCVerification: React.FC<VCVerificationProps> = ({
|
export const VCVerification: React.FC<VCVerificationProps> = ({
|
||||||
vcMetadata,
|
vcMetadata,
|
||||||
@@ -20,12 +21,15 @@ export const VCVerification: React.FC<VCVerificationProps> = ({
|
|||||||
let statusIcon: JSX.Element;
|
let statusIcon: JSX.Element;
|
||||||
|
|
||||||
if (vcMetadata.isVerified) {
|
if (vcMetadata.isVerified) {
|
||||||
if (vcMetadata.isRevoked) {
|
if (vcMetadata.isRevoked === RevocationStatus.TRUE) {
|
||||||
statusText = t('revoked');
|
statusText = t('revoked');
|
||||||
statusIcon = <PendingIcon color="brown" />;
|
statusIcon = <PendingIcon color="brown" />;
|
||||||
} else if (vcMetadata.isExpired) {
|
} else if (vcMetadata.isExpired) {
|
||||||
statusText = t('expired');
|
statusText = t('expired');
|
||||||
statusIcon = <PendingIcon color="red" />;
|
statusIcon = <PendingIcon color="red" />;
|
||||||
|
} else if (vcMetadata.isRevoked === RevocationStatus.UNDETERMINED) {
|
||||||
|
statusText = t('pending');
|
||||||
|
statusIcon = <PendingIcon color="orange" />;
|
||||||
} else {
|
} else {
|
||||||
statusText = t('valid');
|
statusText = t('valid');
|
||||||
statusIcon = <VerifiedIcon />;
|
statusIcon = <VerifiedIcon />;
|
||||||
|
|||||||
@@ -69,7 +69,10 @@ final class LdpStatusChecker {
|
|||||||
var results: [String: CredentialStatusResult] = [:]
|
var results: [String: CredentialStatusResult] = [:]
|
||||||
|
|
||||||
for entry in filteredEntries {
|
for entry in filteredEntries {
|
||||||
let purpose = (entry["statusPurpose"] as? String)?.lowercased() ?? ""
|
guard let purpose = (entry["statusPurpose"] as? String)?.lowercased(), !purpose.isEmpty else {
|
||||||
|
print("Warning: Skipping entry with missing statusPurpose")
|
||||||
|
continue
|
||||||
|
}
|
||||||
do {
|
do {
|
||||||
let result = try await checkStatusEntry(entry: entry, purpose: purpose)
|
let result = try await checkStatusEntry(entry: entry, purpose: purpose)
|
||||||
results[purpose] = result
|
results[purpose] = result
|
||||||
@@ -175,7 +178,7 @@ final class LdpStatusChecker {
|
|||||||
throw StatusCheckException(message: "statusMessage count mismatch", errorCode: .statusVerificationError)
|
throw StatusCheckException(message: "statusMessage count mismatch", errorCode: .statusVerificationError)
|
||||||
}
|
}
|
||||||
|
|
||||||
print("Status message for purpose '\(purpose): $\(statusMessage)")
|
print("Status message for purpose '\(purpose): \(statusMessage)")
|
||||||
}
|
}
|
||||||
|
|
||||||
let bitSet = try decodeEncodedList(encodedList)
|
let bitSet = try decodeEncodedList(encodedList)
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
import {assign, send} from 'xstate';
|
import {assign, send} from 'xstate';
|
||||||
import {CommunicationDetails, UUID, VerificationStatus} from '../../../shared/Utils';
|
import {
|
||||||
|
CommunicationDetails,
|
||||||
|
UUID,
|
||||||
|
VerificationStatus,
|
||||||
|
} from '../../../shared/Utils';
|
||||||
import {StoreEvents} from '../../store';
|
import {StoreEvents} from '../../store';
|
||||||
import {VCMetadata} from '../../../shared/VCMetadata';
|
import {VCMetadata} from '../../../shared/VCMetadata';
|
||||||
import {
|
import {
|
||||||
@@ -31,6 +35,7 @@ import {VcMetaEvents} from '../VCMetaMachine/VCMetaMachine';
|
|||||||
import {WalletBindingResponse} from '../VCMetaMachine/vc';
|
import {WalletBindingResponse} from '../VCMetaMachine/vc';
|
||||||
import {BannerStatusType} from '../../../components/BannerNotification';
|
import {BannerStatusType} from '../../../components/BannerNotification';
|
||||||
import {VCActivityLog} from '../../../components/ActivityLogEvent';
|
import {VCActivityLog} from '../../../components/ActivityLogEvent';
|
||||||
|
import {RevocationStatus} from '../../../shared/vcVerifier/VcVerifier';
|
||||||
|
|
||||||
export const VCItemActions = model => {
|
export const VCItemActions = model => {
|
||||||
return {
|
return {
|
||||||
@@ -58,7 +63,7 @@ export const VCItemActions = model => {
|
|||||||
resetIsVerified: assign((context: any) => {
|
resetIsVerified: assign((context: any) => {
|
||||||
const previous = context.vcMetadata;
|
const previous = context.vcMetadata;
|
||||||
const statusChanged = previous.isVerified;
|
const statusChanged = previous.isVerified;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...context,
|
...context,
|
||||||
vcMetadata: new VCMetadata({
|
vcMetadata: new VCMetadata({
|
||||||
@@ -91,16 +96,21 @@ export const VCItemActions = model => {
|
|||||||
|
|
||||||
sendReverificationSuccessToVcMeta: send(
|
sendReverificationSuccessToVcMeta: send(
|
||||||
(context: any) => ({
|
(context: any) => ({
|
||||||
type: 'REVERIFY_VC_SUCCESS',
|
type:
|
||||||
statusValue: context.vcMetadata.isRevoked
|
context.vcMetadata.isRevoked === RevocationStatus.UNDETERMINED
|
||||||
? VerificationStatus.REVOKED
|
? 'REVERIFY_VC_FAILED'
|
||||||
: context.vcMetadata.isExpired
|
: 'REVERIFY_VC_SUCCESS',
|
||||||
? VerificationStatus.EXPIRED
|
statusValue:
|
||||||
: context.vcMetadata.isVerified
|
context.vcMetadata.isRevoked === RevocationStatus.TRUE
|
||||||
? VerificationStatus.VALID
|
? VerificationStatus.REVOKED
|
||||||
: VerificationStatus.PENDING,
|
: context.vcMetadata.isExpired
|
||||||
|
? VerificationStatus.EXPIRED
|
||||||
|
: context.vcMetadata.isVerified &&
|
||||||
|
context.vcMetadata.isRevoked === RevocationStatus.FALSE
|
||||||
|
? VerificationStatus.VALID
|
||||||
|
: VerificationStatus.PENDING,
|
||||||
vcKey: context.vcMetadata.getVcKey(),
|
vcKey: context.vcMetadata.getVcKey(),
|
||||||
vcType: context.vcMetadata.credentialType
|
vcType: context.vcMetadata.credentialType,
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
to: (context: any) => context.serviceRefs.vcMeta,
|
to: (context: any) => context.serviceRefs.vcMeta,
|
||||||
@@ -110,13 +120,13 @@ export const VCItemActions = model => {
|
|||||||
resetStatusChangedFlag: assign({
|
resetStatusChangedFlag: assign({
|
||||||
statusChangedDuringVerification: () => false,
|
statusChangedDuringVerification: () => false,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
sendReverificationFailureToVcMeta: send(
|
sendReverificationFailureToVcMeta: send(
|
||||||
(context:any) => ({
|
(context: any) => ({
|
||||||
type: 'REVERIFY_VC_FAILED',
|
type: 'REVERIFY_VC_FAILED',
|
||||||
statusValue: VerificationStatus.PENDING,
|
statusValue: VerificationStatus.PENDING,
|
||||||
vcKey: context.vcMetadata.getVcKey(),
|
vcKey: context.vcMetadata.getVcKey(),
|
||||||
vcType: context.vcMetadata.credentialType
|
vcType: context.vcMetadata.credentialType,
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
to: (context: any) => context.serviceRefs.vcMeta,
|
to: (context: any) => context.serviceRefs.vcMeta,
|
||||||
|
|||||||
@@ -30,8 +30,8 @@ export const baseRoutes: Screen[] = [
|
|||||||
component: KeyManagementScreen,
|
component: KeyManagementScreen,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name:'AuthView',
|
name: 'AuthView',
|
||||||
component:AuthWebViewScreen
|
component: AuthWebViewScreen,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Language',
|
name: 'Language',
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import {
|
|||||||
import {authRoutes, baseRoutes} from '../routes';
|
import {authRoutes, baseRoutes} from '../routes';
|
||||||
import {useAppLayout} from './AppLayoutController';
|
import {useAppLayout} from './AppLayoutController';
|
||||||
import {StatusBar} from 'react-native';
|
import {StatusBar} from 'react-native';
|
||||||
import {GestureHandlerRootView} from "react-native-gesture-handler";
|
import {GestureHandlerRootView} from 'react-native-gesture-handler';
|
||||||
|
|
||||||
const {Navigator, Screen} = createNativeStackNavigator();
|
const {Navigator, Screen} = createNativeStackNavigator();
|
||||||
export const AppLayout: React.FC = () => {
|
export const AppLayout: React.FC = () => {
|
||||||
@@ -25,17 +25,19 @@ export const AppLayout: React.FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<GestureHandlerRootView>
|
<GestureHandlerRootView>
|
||||||
<NavigationContainer ref={navigationRef}>
|
<NavigationContainer ref={navigationRef}>
|
||||||
<StatusBar animated={true} barStyle="dark-content" />
|
<StatusBar animated={true} barStyle="dark-content" />
|
||||||
<Navigator initialRouteName={baseRoutes[0].name} screenOptions={options}>
|
<Navigator
|
||||||
{baseRoutes.map(route => (
|
initialRouteName={baseRoutes[0].name}
|
||||||
<Screen key={route.name} {...route} />
|
screenOptions={options}>
|
||||||
))}
|
{baseRoutes.map(route => (
|
||||||
{controller.isAuthorized &&
|
<Screen key={route.name} {...route} />
|
||||||
authRoutes.map(route => <Screen key={route.name} {...route} />)}
|
))}
|
||||||
</Navigator>
|
{controller.isAuthorized &&
|
||||||
</NavigationContainer>
|
authRoutes.map(route => <Screen key={route.name} {...route} />)}
|
||||||
</GestureHandlerRootView>
|
</Navigator>
|
||||||
|
</NavigationContainer>
|
||||||
|
</GestureHandlerRootView>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -41,13 +41,13 @@ export const OnboardingOverlay: React.FC<OnboardingProps> = props => {
|
|||||||
const renderItem = ({item}) => {
|
const renderItem = ({item}) => {
|
||||||
return (
|
return (
|
||||||
<View style={Theme.OnboardingOverlayStyles.slide}>
|
<View style={Theme.OnboardingOverlayStyles.slide}>
|
||||||
<ScrollView showsVerticalScrollIndicator={true}>
|
<ScrollView showsVerticalScrollIndicator={true}>
|
||||||
<Text style={Theme.OnboardingOverlayStyles.sliderTitle}>
|
<Text style={Theme.OnboardingOverlayStyles.sliderTitle}>
|
||||||
{item.title}
|
{item.title}
|
||||||
</Text>
|
</Text>
|
||||||
<Text style={Theme.OnboardingOverlayStyles.text}>{item.text}</Text>
|
<Text style={Theme.OnboardingOverlayStyles.text}>{item.text}</Text>
|
||||||
{item.footer}
|
{item.footer}
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -40,7 +40,11 @@ export const ViewVcModal: React.FC<ViewVcModalProps> = props => {
|
|||||||
const controller = useViewVcModal(props);
|
const controller = useViewVcModal(props);
|
||||||
const profileImage = controller.verifiableCredentialData.face;
|
const profileImage = controller.verifiableCredentialData.face;
|
||||||
const verificationStatus = controller.verificationStatus;
|
const verificationStatus = controller.verificationStatus;
|
||||||
const verificationStatusMessage = controller.verificationStatus?.isRevoked ? "revoked" : controller.verificationStatus?.isExpired ? "expired" : controller.verificationStatus?.statusType;
|
const verificationStatusMessage = controller.verificationStatus?.isRevoked
|
||||||
|
? 'revoked'
|
||||||
|
: controller.verificationStatus?.isExpired
|
||||||
|
? 'expired'
|
||||||
|
: controller.verificationStatus?.statusType;
|
||||||
const [verifiableCredential, setVerifiableCredential] = useState(null);
|
const [verifiableCredential, setVerifiableCredential] = useState(null);
|
||||||
const [svgTemplate, setSvgTemplate] = useState<string[] | null>(null);
|
const [svgTemplate, setSvgTemplate] = useState<string[] | null>(null);
|
||||||
const [svgRendererError, setSvgRendererError] = useState<string[] | null>(
|
const [svgRendererError, setSvgRendererError] = useState<string[] | null>(
|
||||||
@@ -69,7 +73,7 @@ export const ViewVcModal: React.FC<ViewVcModalProps> = props => {
|
|||||||
!controller.verifiableCredentialData.vcMetadata.isVerified &&
|
!controller.verifiableCredentialData.vcMetadata.isVerified &&
|
||||||
!controller.isVerificationInProgress
|
!controller.isVerificationInProgress
|
||||||
) {
|
) {
|
||||||
props.vcItemActor.send({ type: 'VERIFY' });
|
props.vcItemActor.send({type: 'VERIFY'});
|
||||||
}
|
}
|
||||||
}, [controller.verifiableCredentialData.vcMetadata.isVerified]);
|
}, [controller.verifiableCredentialData.vcMetadata.isVerified]);
|
||||||
|
|
||||||
@@ -86,11 +90,12 @@ export const ViewVcModal: React.FC<ViewVcModalProps> = props => {
|
|||||||
setLoadingSvg(true);
|
setLoadingSvg(true);
|
||||||
|
|
||||||
const vcJsonString = JSON.stringify(controller.credential.credential);
|
const vcJsonString = JSON.stringify(controller.credential.credential);
|
||||||
const result = await VcRenderer.getInstance().generateCredentialDisplayContent(
|
const result =
|
||||||
controller.verifiableCredentialData.format,
|
await VcRenderer.getInstance().generateCredentialDisplayContent(
|
||||||
wellknown ?? null,
|
controller.verifiableCredentialData.format,
|
||||||
vcJsonString,
|
wellknown ?? null,
|
||||||
);
|
vcJsonString,
|
||||||
|
);
|
||||||
|
|
||||||
setSvgTemplate(result);
|
setSvgTemplate(result);
|
||||||
setSvgRendererError(null);
|
setSvgRendererError(null);
|
||||||
@@ -181,7 +186,9 @@ export const ViewVcModal: React.FC<ViewVcModalProps> = props => {
|
|||||||
<BannerNotification
|
<BannerNotification
|
||||||
type={verificationStatus?.statusType as BannerStatus}
|
type={verificationStatus?.statusType as BannerStatus}
|
||||||
message={t(`VcVerificationBanner:${verificationStatusMessage}`, {
|
message={t(`VcVerificationBanner:${verificationStatusMessage}`, {
|
||||||
vcDetails: `${verificationStatus?.vcType} ${verificationStatus?.vcNumber ?? ""}`,
|
vcDetails: `${verificationStatus?.vcType} ${
|
||||||
|
verificationStatus?.vcNumber ?? ''
|
||||||
|
}`,
|
||||||
})}
|
})}
|
||||||
onClosePress={controller.RESET_VERIFICATION_STATUS}
|
onClosePress={controller.RESET_VERIFICATION_STATUS}
|
||||||
key={'reVerificationInProgress'}
|
key={'reVerificationInProgress'}
|
||||||
@@ -239,7 +246,9 @@ export const ViewVcModal: React.FC<ViewVcModalProps> = props => {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<MessageOverlay
|
<MessageOverlay
|
||||||
isVisible={controller.isWalletBindingInProgress || controller.isReverifyingVc}
|
isVisible={
|
||||||
|
controller.isWalletBindingInProgress || controller.isReverifyingVc
|
||||||
|
}
|
||||||
title={t('inProgress')}
|
title={t('inProgress')}
|
||||||
progress
|
progress
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,20 +1,17 @@
|
|||||||
import React, { useEffect, useLayoutEffect, useState } from 'react';
|
import React, {useEffect, useLayoutEffect, useState} from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import {useTranslation} from 'react-i18next';
|
||||||
import { FlatList, Pressable, View } from 'react-native';
|
import {FlatList, Pressable, View} from 'react-native';
|
||||||
import { Issuer } from '../../components/openId4VCI/Issuer';
|
import {Issuer} from '../../components/openId4VCI/Issuer';
|
||||||
import { Error } from '../../components/ui/Error';
|
import {Error} from '../../components/ui/Error';
|
||||||
import { Header } from '../../components/ui/Header';
|
import {Header} from '../../components/ui/Header';
|
||||||
import { Button, Column, Row, Text } from '../../components/ui';
|
import {Button, Column, Row, Text} from '../../components/ui';
|
||||||
import { Theme } from '../../components/ui/styleUtils';
|
import {Theme} from '../../components/ui/styleUtils';
|
||||||
import { RootRouteProps } from '../../routes';
|
import {RootRouteProps} from '../../routes';
|
||||||
import { HomeRouteProps } from '../../routes/routeTypes';
|
import {HomeRouteProps} from '../../routes/routeTypes';
|
||||||
import { useIssuerScreenController } from './IssuerScreenController';
|
import {useIssuerScreenController} from './IssuerScreenController';
|
||||||
import { Loader } from '../../components/ui/Loader';
|
import {Loader} from '../../components/ui/Loader';
|
||||||
import ScanIcon from '../../assets/scanIcon.svg';
|
import ScanIcon from '../../assets/scanIcon.svg';
|
||||||
import {
|
import {isTranslationKeyFound, removeWhiteSpace} from '../../shared/commonUtil';
|
||||||
isTranslationKeyFound,
|
|
||||||
removeWhiteSpace,
|
|
||||||
} from '../../shared/commonUtil';
|
|
||||||
import {
|
import {
|
||||||
ErrorMessage,
|
ErrorMessage,
|
||||||
getDisplayObjectForCurrentLanguage,
|
getDisplayObjectForCurrentLanguage,
|
||||||
@@ -26,31 +23,31 @@ import {
|
|||||||
sendInteractEvent,
|
sendInteractEvent,
|
||||||
sendStartEvent,
|
sendStartEvent,
|
||||||
} from '../../shared/telemetry/TelemetryUtils';
|
} from '../../shared/telemetry/TelemetryUtils';
|
||||||
import { TelemetryConstants } from '../../shared/telemetry/TelemetryConstants';
|
import {TelemetryConstants} from '../../shared/telemetry/TelemetryConstants';
|
||||||
import { MessageOverlay } from '../../components/MessageOverlay';
|
import {MessageOverlay} from '../../components/MessageOverlay';
|
||||||
import { SearchBar } from '../../components/ui/SearchBar';
|
import {SearchBar} from '../../components/ui/SearchBar';
|
||||||
import { SvgImage } from '../../components/ui/svg';
|
import {SvgImage} from '../../components/ui/svg';
|
||||||
import { Icon } from 'react-native-elements';
|
import {Icon} from 'react-native-elements';
|
||||||
import { BannerNotificationContainer } from '../../components/BannerNotificationContainer';
|
import {BannerNotificationContainer} from '../../components/BannerNotificationContainer';
|
||||||
import { CredentialTypeSelectionScreen } from './CredentialTypeSelectionScreen';
|
import {CredentialTypeSelectionScreen} from './CredentialTypeSelectionScreen';
|
||||||
import { QrScanner } from '../../components/QrScanner';
|
import {QrScanner} from '../../components/QrScanner';
|
||||||
import { IssuersModel } from '../../machines/Issuers/IssuersModel';
|
import {IssuersModel} from '../../machines/Issuers/IssuersModel';
|
||||||
import { AUTH_ROUTES } from '../../routes/routesConstants';
|
import {AUTH_ROUTES} from '../../routes/routesConstants';
|
||||||
import { TransactionCodeModal } from './TransactionCodeScreen';
|
import {TransactionCodeModal} from './TransactionCodeScreen';
|
||||||
import { TrustModal } from '../../components/TrustModal';
|
import {TrustModal} from '../../components/TrustModal';
|
||||||
import i18next from 'i18next';
|
import i18next from 'i18next';
|
||||||
export const IssuersScreen: React.FC<
|
export const IssuersScreen: React.FC<
|
||||||
HomeRouteProps | RootRouteProps
|
HomeRouteProps | RootRouteProps
|
||||||
> = props => {
|
> = props => {
|
||||||
const model = IssuersModel;
|
const model = IssuersModel;
|
||||||
const controller = useIssuerScreenController(props);
|
const controller = useIssuerScreenController(props);
|
||||||
const { i18n, t } = useTranslation('IssuersScreen');
|
const {i18n, t} = useTranslation('IssuersScreen');
|
||||||
const issuers = controller.issuers;
|
const issuers = controller.issuers;
|
||||||
let [filteredSearchData, setFilteredSearchData] = useState(issuers);
|
let [filteredSearchData, setFilteredSearchData] = useState(issuers);
|
||||||
const [search, setSearch] = useState('');
|
const [search, setSearch] = useState('');
|
||||||
const [tapToSearch, setTapToSearch] = useState(false);
|
const [tapToSearch, setTapToSearch] = useState(false);
|
||||||
const [clearSearchIcon, setClearSearchIcon] = useState(false);
|
const [clearSearchIcon, setClearSearchIcon] = useState(false);
|
||||||
const showFullScreenError = controller.isError
|
const showFullScreenError = controller.isError;
|
||||||
|
|
||||||
const isVerificationFailed = controller.verificationErrorMessage !== '';
|
const isVerificationFailed = controller.verificationErrorMessage !== '';
|
||||||
|
|
||||||
@@ -58,8 +55,7 @@ export const IssuersScreen: React.FC<
|
|||||||
|
|
||||||
const verificationErrorMessage = isTranslationKeyFound(translationKey, t)
|
const verificationErrorMessage = isTranslationKeyFound(translationKey, t)
|
||||||
? t(translationKey)
|
? t(translationKey)
|
||||||
: t('errors.verificationFailed.ERR_GENERIC');
|
: t('errors.verificationFailed.ERR_GENERIC');
|
||||||
|
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
if (controller.loadingReason || showFullScreenError) {
|
if (controller.loadingReason || showFullScreenError) {
|
||||||
@@ -72,13 +68,12 @@ export const IssuersScreen: React.FC<
|
|||||||
header: props => (
|
header: props => (
|
||||||
<Header
|
<Header
|
||||||
goBack={props.navigation.goBack}
|
goBack={props.navigation.goBack}
|
||||||
title={ controller.isQrScanning?t('download'):t('title')}
|
title={controller.isQrScanning ? t('download') : t('title')}
|
||||||
testID="issuersScreenHeader"
|
testID="issuersScreenHeader"
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}, [
|
}, [
|
||||||
controller.loadingReason,
|
controller.loadingReason,
|
||||||
controller.errorMessageType,
|
controller.errorMessageType,
|
||||||
@@ -93,8 +88,10 @@ export const IssuersScreen: React.FC<
|
|||||||
if (controller.isAuthEndpointToOpen) {
|
if (controller.isAuthEndpointToOpen) {
|
||||||
(props.navigation as any).navigate(AUTH_ROUTES.AuthView, {
|
(props.navigation as any).navigate(AUTH_ROUTES.AuthView, {
|
||||||
authorizationURL: controller.authEndpount,
|
authorizationURL: controller.authEndpount,
|
||||||
clientId: controller.selectedIssuer.client_id ?? "wallet",
|
clientId: controller.selectedIssuer.client_id ?? 'wallet',
|
||||||
redirectUri: controller.selectedIssuer.redirect_uri ?? "io.mosip.residentapp.inji://oauthredirect",
|
redirectUri:
|
||||||
|
controller.selectedIssuer.redirect_uri ??
|
||||||
|
'io.mosip.residentapp.inji://oauthredirect',
|
||||||
controller: controller,
|
controller: controller,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -102,7 +99,7 @@ export const IssuersScreen: React.FC<
|
|||||||
|
|
||||||
const onPressHandler = (id: string, protocol: string) => {
|
const onPressHandler = (id: string, protocol: string) => {
|
||||||
sendStartEvent(
|
sendStartEvent(
|
||||||
getStartEventData(TelemetryConstants.FlowType.vcDownload, { id: id }),
|
getStartEventData(TelemetryConstants.FlowType.vcDownload, {id: id}),
|
||||||
);
|
);
|
||||||
sendInteractEvent(
|
sendInteractEvent(
|
||||||
getInteractEventData(
|
getInteractEventData(
|
||||||
@@ -124,9 +121,9 @@ export const IssuersScreen: React.FC<
|
|||||||
return (
|
return (
|
||||||
controller.errorMessageType === ErrorMessage.TECHNICAL_DIFFICULTIES ||
|
controller.errorMessageType === ErrorMessage.TECHNICAL_DIFFICULTIES ||
|
||||||
controller.errorMessageType ===
|
controller.errorMessageType ===
|
||||||
ErrorMessage.CREDENTIAL_TYPE_DOWNLOAD_FAILURE ||
|
ErrorMessage.CREDENTIAL_TYPE_DOWNLOAD_FAILURE ||
|
||||||
controller.errorMessageType ===
|
controller.errorMessageType ===
|
||||||
ErrorMessage.AUTHORIZATION_GRANT_TYPE_NOT_SUPPORTED ||
|
ErrorMessage.AUTHORIZATION_GRANT_TYPE_NOT_SUPPORTED ||
|
||||||
controller.errorMessageType === ErrorMessage.NETWORK_REQUEST_FAILED
|
controller.errorMessageType === ErrorMessage.NETWORK_REQUEST_FAILED
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -195,7 +192,7 @@ export const IssuersScreen: React.FC<
|
|||||||
primaryButtonText="goBack"
|
primaryButtonText="goBack"
|
||||||
primaryButtonEvent={controller.RESET_VERIFY_ERROR}
|
primaryButtonEvent={controller.RESET_VERIFY_ERROR}
|
||||||
primaryButtonTestID="goBack"
|
primaryButtonTestID="goBack"
|
||||||
customStyles={{ marginTop: '30%' }}
|
customStyles={{marginTop: '30%'}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -203,14 +200,16 @@ export const IssuersScreen: React.FC<
|
|||||||
return issuerTrustConsentComponent();
|
return issuerTrustConsentComponent();
|
||||||
}
|
}
|
||||||
if (controller.isTxCodeRequested) {
|
if (controller.isTxCodeRequested) {
|
||||||
return <TransactionCodeModal
|
return (
|
||||||
visible={controller.isTxCodeRequested}
|
<TransactionCodeModal
|
||||||
onDismiss={controller.CANCEL}
|
visible={controller.isTxCodeRequested}
|
||||||
onVerify={controller.TX_CODE_RECEIVED}
|
onDismiss={controller.CANCEL}
|
||||||
inputMode= {controller.txCodeDisplayDetails.inputMode}
|
onVerify={controller.TX_CODE_RECEIVED}
|
||||||
description={controller.txCodeDisplayDetails.description}
|
inputMode={controller.txCodeDisplayDetails.inputMode}
|
||||||
length={controller.txCodeDisplayDetails.length}
|
description={controller.txCodeDisplayDetails.description}
|
||||||
/>
|
length={controller.txCodeDisplayDetails.length}
|
||||||
|
/>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (controller.isBiometricsCancelled) {
|
if (controller.isBiometricsCancelled) {
|
||||||
@@ -253,7 +252,7 @@ export const IssuersScreen: React.FC<
|
|||||||
primaryButtonTestID="tryAgain"
|
primaryButtonTestID="tryAgain"
|
||||||
primaryButtonText={
|
primaryButtonText={
|
||||||
controller.errorMessageType != ErrorMessage.TECHNICAL_DIFFICULTIES &&
|
controller.errorMessageType != ErrorMessage.TECHNICAL_DIFFICULTIES &&
|
||||||
controller.errorMessageType !=
|
controller.errorMessageType !=
|
||||||
ErrorMessage.AUTHORIZATION_GRANT_TYPE_NOT_SUPPORTED
|
ErrorMessage.AUTHORIZATION_GRANT_TYPE_NOT_SUPPORTED
|
||||||
? 'tryAgain'
|
? 'tryAgain'
|
||||||
: undefined
|
: undefined
|
||||||
@@ -272,7 +271,6 @@ export const IssuersScreen: React.FC<
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (controller.isQrScanning) {
|
if (controller.isQrScanning) {
|
||||||
return qrScannerComponent();
|
return qrScannerComponent();
|
||||||
@@ -280,15 +278,21 @@ export const IssuersScreen: React.FC<
|
|||||||
function qrScannerComponent() {
|
function qrScannerComponent() {
|
||||||
return (
|
return (
|
||||||
<Column crossAlign="center">
|
<Column crossAlign="center">
|
||||||
<QrScanner
|
<QrScanner onQrFound={controller.QR_CODE_SCANNED} />
|
||||||
onQrFound={controller.QR_CODE_SCANNED}
|
|
||||||
/>
|
|
||||||
</Column>
|
</Column>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function issuerTrustConsentComponent() {
|
function issuerTrustConsentComponent() {
|
||||||
return <TrustModal isVisible={true} logo={controller.issuerLogo} name={controller.issuerName} onConfirm={controller.ON_CONSENT_GIVEN} onCancel={controller.CANCEL} />
|
return (
|
||||||
|
<TrustModal
|
||||||
|
isVisible={true}
|
||||||
|
logo={controller.issuerLogo}
|
||||||
|
name={controller.issuerName}
|
||||||
|
onConfirm={controller.ON_CONSENT_GIVEN}
|
||||||
|
onCancel={controller.CANCEL}
|
||||||
|
/>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -333,19 +337,26 @@ export const IssuersScreen: React.FC<
|
|||||||
}}>
|
}}>
|
||||||
{t('description')}
|
{t('description')}
|
||||||
</Text>
|
</Text>
|
||||||
{search === '' && <View style={{ height: 85 }}><Issuer defaultLogo={ScanIcon} displayDetails={{
|
{search === '' && (
|
||||||
title: t('offerTitle'),
|
<View style={{height: 85}}>
|
||||||
locale: i18n.language,
|
<Issuer
|
||||||
description: t('offerDescription'),
|
defaultLogo={ScanIcon}
|
||||||
}} onPress={
|
displayDetails={{
|
||||||
controller.SCAN_CREDENTIAL_OFFER_QR_CODE
|
title: t('offerTitle'),
|
||||||
} testID={'credentalOfferButton'} /></View>}
|
locale: i18n.language,
|
||||||
|
description: t('offerDescription'),
|
||||||
|
}}
|
||||||
|
onPress={controller.SCAN_CREDENTIAL_OFFER_QR_CODE}
|
||||||
|
testID={'credentalOfferButton'}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
|
||||||
<Column scroll style={Theme.IssuersScreenStyles.issuersContainer}>
|
<Column scroll style={Theme.IssuersScreenStyles.issuersContainer}>
|
||||||
{controller.issuers.length > 0 && (
|
{controller.issuers.length > 0 && (
|
||||||
<FlatList
|
<FlatList
|
||||||
data={filteredSearchData}
|
data={filteredSearchData}
|
||||||
renderItem={({ item }) => (
|
renderItem={({item}) => (
|
||||||
<Issuer
|
<Issuer
|
||||||
testID={removeWhiteSpace(item.issuer_id)}
|
testID={removeWhiteSpace(item.issuer_id)}
|
||||||
key={item.issuer_id}
|
key={item.issuer_id}
|
||||||
@@ -368,5 +379,3 @@ export const IssuersScreen: React.FC<
|
|||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -53,11 +53,12 @@ export const ReceiveVcScreen: React.FC = () => {
|
|||||||
setLoadingSvg(true);
|
setLoadingSvg(true);
|
||||||
|
|
||||||
const vcJsonString = JSON.stringify(controller.credential.credential);
|
const vcJsonString = JSON.stringify(controller.credential.credential);
|
||||||
const result = await VcRenderer.getInstance().generateCredentialDisplayContent(
|
const result =
|
||||||
verifiableCredentialData.vcMetadata.format,
|
await VcRenderer.getInstance().generateCredentialDisplayContent(
|
||||||
wellknown ?? null,
|
verifiableCredentialData.vcMetadata.format,
|
||||||
vcJsonString,
|
wellknown ?? null,
|
||||||
);
|
vcJsonString,
|
||||||
|
);
|
||||||
|
|
||||||
setSvgTemplate(result);
|
setSvgTemplate(result);
|
||||||
setSvgRendererError(null);
|
setSvgRendererError(null);
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ import {VPShareOverlayProps} from './VPShareOverlay';
|
|||||||
import {ActivityLogEvents} from '../../machines/activityLog';
|
import {ActivityLogEvents} from '../../machines/activityLog';
|
||||||
import {VPShareActivityLog} from '../../components/VPShareActivityLogEvent';
|
import {VPShareActivityLog} from '../../components/VPShareActivityLogEvent';
|
||||||
import {isIOS} from '../../shared/constants';
|
import {isIOS} from '../../shared/constants';
|
||||||
import { getFaceAttribute } from '../../components/VC/common/VCUtils';
|
import {getFaceAttribute} from '../../components/VC/common/VCUtils';
|
||||||
|
|
||||||
type MyVcsTabNavigation = NavigationProp<RootRouteProps>;
|
type MyVcsTabNavigation = NavigationProp<RootRouteProps>;
|
||||||
|
|
||||||
@@ -65,9 +65,10 @@ export function useSendVPScreen() {
|
|||||||
const navigation = useNavigation<MyVcsTabNavigation>();
|
const navigation = useNavigation<MyVcsTabNavigation>();
|
||||||
const openID4VPService = scanService.getSnapshot().context.OpenId4VPRef;
|
const openID4VPService = scanService.getSnapshot().context.OpenId4VPRef;
|
||||||
// input descriptor id to VCs mapping
|
// input descriptor id to VCs mapping
|
||||||
const [inputDescriptorIdToSelectedVcKeys, setInputDescriptorIdToSelectedVcKeys] = useState<Record<string, [string]>>(
|
const [
|
||||||
{},
|
inputDescriptorIdToSelectedVcKeys,
|
||||||
);
|
setInputDescriptorIdToSelectedVcKeys,
|
||||||
|
] = useState<Record<string, [string]>>({});
|
||||||
|
|
||||||
const hasLoggedErrorRef = useRef(false);
|
const hasLoggedErrorRef = useRef(false);
|
||||||
|
|
||||||
@@ -97,26 +98,31 @@ export function useSendVPScreen() {
|
|||||||
return Object.values(vcs)
|
return Object.values(vcs)
|
||||||
.flatMap(vc => vc)
|
.flatMap(vc => vc)
|
||||||
.some(vc => {
|
.some(vc => {
|
||||||
return getFaceAttribute(vc.verifiableCredential,vc.format) != null;
|
return getFaceAttribute(vc.verifiableCredential, vc.format) != null;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const checkIfAllVCsHasImage = vcs => {
|
const checkIfAllVCsHasImage = vcs => {
|
||||||
return Object.values(vcs)
|
return Object.values(vcs)
|
||||||
.flatMap(vc => vc)
|
.flatMap(vc => vc)
|
||||||
.every(vc => getFaceAttribute(vc.verifiableCredential,vc.format) != null);
|
.every(
|
||||||
|
vc => getFaceAttribute(vc.verifiableCredential, vc.format) != null,
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getSelectedVCs = (): Record<string, any[]> => {
|
const getSelectedVCs = (): Record<string, any[]> => {
|
||||||
let selectedVcsData: Record<string, any[]> = {}; // input_descriptor_id to VC[]
|
let selectedVcsData: Record<string, any[]> = {}; // input_descriptor_id to VC[]
|
||||||
Object.entries(inputDescriptorIdToSelectedVcKeys).forEach(([inputDescriptorId, vcKeys]) => {
|
Object.entries(inputDescriptorIdToSelectedVcKeys).forEach(
|
||||||
vcKeys.forEach((vcKey : string) => {
|
([inputDescriptorId, vcKeys]) => {
|
||||||
const vcData = myVcs[vcKey];
|
vcKeys.forEach((vcKey: string) => {
|
||||||
selectedVcsData[inputDescriptorId] = selectedVcsData[inputDescriptorId] || [];
|
const vcData = myVcs[vcKey];
|
||||||
selectedVcsData[inputDescriptorId].push(vcData);
|
selectedVcsData[inputDescriptorId] =
|
||||||
|
selectedVcsData[inputDescriptorId] || [];
|
||||||
|
selectedVcsData[inputDescriptorId].push(vcData);
|
||||||
});
|
});
|
||||||
});
|
},
|
||||||
return selectedVcsData
|
);
|
||||||
|
return selectedVcsData;
|
||||||
};
|
};
|
||||||
|
|
||||||
const showConfirmationPopup = useSelector(
|
const showConfirmationPopup = useSelector(
|
||||||
@@ -222,9 +228,18 @@ export function useSendVPScreen() {
|
|||||||
showLoadingScreen: useSelector(openID4VPService, selectIsShowLoadingScreen),
|
showLoadingScreen: useSelector(openID4VPService, selectIsShowLoadingScreen),
|
||||||
vpVerifierName,
|
vpVerifierName,
|
||||||
flowType: useSelector(openID4VPService, selectFlowType),
|
flowType: useSelector(openID4VPService, selectFlowType),
|
||||||
showTrustConsentModal: useSelector(openID4VPService,selectshowTrustConsentModal),
|
showTrustConsentModal: useSelector(
|
||||||
verifierNameInTrustModal: useSelector(openID4VPService, selectVerifierNameInTrustModal),
|
openID4VPService,
|
||||||
verifierLogoInTrustModal: useSelector(openID4VPService, selectVerifierLogoInTrustModal),
|
selectshowTrustConsentModal,
|
||||||
|
),
|
||||||
|
verifierNameInTrustModal: useSelector(
|
||||||
|
openID4VPService,
|
||||||
|
selectVerifierNameInTrustModal,
|
||||||
|
),
|
||||||
|
verifierLogoInTrustModal: useSelector(
|
||||||
|
openID4VPService,
|
||||||
|
selectVerifierLogoInTrustModal,
|
||||||
|
),
|
||||||
showConfirmationPopup,
|
showConfirmationPopup,
|
||||||
isSelectingVCs,
|
isSelectingVCs,
|
||||||
checkIfAnyVCHasImage,
|
checkIfAnyVCHasImage,
|
||||||
@@ -282,60 +297,80 @@ export function useSendVPScreen() {
|
|||||||
(vcRef: ActorRefFrom<typeof VCItemMachine>) => {
|
(vcRef: ActorRefFrom<typeof VCItemMachine>) => {
|
||||||
let descriptorMappingToVCs = {...inputDescriptorIdToSelectedVcKeys};
|
let descriptorMappingToVCs = {...inputDescriptorIdToSelectedVcKeys};
|
||||||
|
|
||||||
const isVCSelected = Object.keys(inputDescriptorIdToSelectedVcKeys)?.includes(inputDescriptorId) && inputDescriptorIdToSelectedVcKeys[inputDescriptorId]?.includes(vcKey) ? false : true;
|
const isVCSelected =
|
||||||
|
Object.keys(inputDescriptorIdToSelectedVcKeys)?.includes(
|
||||||
|
inputDescriptorId,
|
||||||
|
) &&
|
||||||
|
inputDescriptorIdToSelectedVcKeys[inputDescriptorId]?.includes(vcKey)
|
||||||
|
? false
|
||||||
|
: true;
|
||||||
if (isVCSelected) {
|
if (isVCSelected) {
|
||||||
if (descriptorMappingToVCs[inputDescriptorId]) {
|
if (descriptorMappingToVCs[inputDescriptorId]) {
|
||||||
if (!descriptorMappingToVCs[inputDescriptorId].includes(vcKey)) {
|
if (!descriptorMappingToVCs[inputDescriptorId].includes(vcKey)) {
|
||||||
descriptorMappingToVCs[inputDescriptorId].push(vcKey);
|
descriptorMappingToVCs[inputDescriptorId].push(vcKey);
|
||||||
}
|
|
||||||
} else {
|
|
||||||
descriptorMappingToVCs[inputDescriptorId] = [vcKey];
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
descriptorMappingToVCs[inputDescriptorId] = [vcKey];
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// remove vc key from the input descriptor mapping
|
// remove vc key from the input descriptor mapping
|
||||||
if (descriptorMappingToVCs[inputDescriptorId]) {
|
if (descriptorMappingToVCs[inputDescriptorId]) {
|
||||||
descriptorMappingToVCs[inputDescriptorId] = descriptorMappingToVCs[
|
descriptorMappingToVCs[inputDescriptorId] = descriptorMappingToVCs[
|
||||||
inputDescriptorId
|
inputDescriptorId
|
||||||
].filter(key => key !== vcKey); // remove the vcKey from the array
|
].filter(key => key !== vcKey); // remove the vcKey from the array
|
||||||
if (descriptorMappingToVCs[inputDescriptorId].length === 0) { // if the array is empty, remove the input descriptor id
|
if (descriptorMappingToVCs[inputDescriptorId].length === 0) {
|
||||||
delete descriptorMappingToVCs[inputDescriptorId];
|
// if the array is empty, remove the input descriptor id
|
||||||
}
|
delete descriptorMappingToVCs[inputDescriptorId];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
setInputDescriptorIdToSelectedVcKeys(descriptorMappingToVCs)
|
setInputDescriptorIdToSelectedVcKeys(descriptorMappingToVCs);
|
||||||
const {serviceRefs, wellknownResponse, ...vcData} =
|
const {serviceRefs, wellknownResponse, ...vcData} =
|
||||||
vcRef.getSnapshot().context;
|
vcRef.getSnapshot().context;
|
||||||
},
|
},
|
||||||
|
|
||||||
UNCHECK_ALL: () => {
|
UNCHECK_ALL: () => {
|
||||||
setInputDescriptorIdToSelectedVcKeys({})
|
setInputDescriptorIdToSelectedVcKeys({});
|
||||||
},
|
},
|
||||||
|
|
||||||
CHECK_ALL: () => {
|
CHECK_ALL: () => {
|
||||||
const updatedInputDescriptorToCredentialsMapping: Record<string, any[]> = {};
|
const updatedInputDescriptorToCredentialsMapping: Record<string, any[]> =
|
||||||
|
{};
|
||||||
Object.entries(vcsMatchingAuthRequest).map(([inputDescriptorId, vcs]) => {
|
Object.entries(vcsMatchingAuthRequest).map(([inputDescriptorId, vcs]) => {
|
||||||
updatedInputDescriptorToCredentialsMapping[inputDescriptorId] = [];
|
updatedInputDescriptorToCredentialsMapping[inputDescriptorId] = [];
|
||||||
vcs.map(vcData => {
|
vcs.map(vcData => {
|
||||||
const vcKey = VCMetadata.fromVcMetadataString(
|
const vcKey = VCMetadata.fromVcMetadataString(
|
||||||
vcData.vcMetadata,
|
vcData.vcMetadata,
|
||||||
).getVcKey();
|
).getVcKey();
|
||||||
updatedInputDescriptorToCredentialsMapping[inputDescriptorId].push(vcKey);
|
updatedInputDescriptorToCredentialsMapping[inputDescriptorId].push(
|
||||||
|
vcKey,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
setInputDescriptorIdToSelectedVcKeys({...updatedInputDescriptorToCredentialsMapping});
|
setInputDescriptorIdToSelectedVcKeys({
|
||||||
|
...updatedInputDescriptorToCredentialsMapping,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
ACCEPT_REQUEST: (selectedDisclosuresByVc) => {
|
ACCEPT_REQUEST: selectedDisclosuresByVc => {
|
||||||
openID4VPService.send(OpenID4VPEvents.ACCEPT_REQUEST(getSelectedVCs(), selectedDisclosuresByVc));
|
openID4VPService.send(
|
||||||
|
OpenID4VPEvents.ACCEPT_REQUEST(
|
||||||
|
getSelectedVCs(),
|
||||||
|
selectedDisclosuresByVc,
|
||||||
|
),
|
||||||
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
VERIFIER_TRUST_CONSENT_GIVEN: () =>{
|
VERIFIER_TRUST_CONSENT_GIVEN: () => {
|
||||||
openID4VPService.send(OpenID4VPEvents.VERIFIER_TRUST_CONSENT_GIVEN());
|
openID4VPService.send(OpenID4VPEvents.VERIFIER_TRUST_CONSENT_GIVEN());
|
||||||
},
|
},
|
||||||
|
|
||||||
VERIFY_AND_ACCEPT_REQUEST: (selectedDisclosuresByVc) => {
|
VERIFY_AND_ACCEPT_REQUEST: selectedDisclosuresByVc => {
|
||||||
openID4VPService.send(
|
openID4VPService.send(
|
||||||
OpenID4VPEvents.VERIFY_AND_ACCEPT_REQUEST(getSelectedVCs(), selectedDisclosuresByVc),
|
OpenID4VPEvents.VERIFY_AND_ACCEPT_REQUEST(
|
||||||
|
getSelectedVCs(),
|
||||||
|
selectedDisclosuresByVc,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
CANCEL,
|
CANCEL,
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import {TelemetryConstants} from '../../shared/telemetry/TelemetryConstants';
|
|||||||
import {SUPPORTED_KEY_TYPES} from '../../shared/constants';
|
import {SUPPORTED_KEY_TYPES} from '../../shared/constants';
|
||||||
import {SvgImage} from '../../components/ui/svg';
|
import {SvgImage} from '../../components/ui/svg';
|
||||||
import LinearGradient from 'react-native-linear-gradient';
|
import LinearGradient from 'react-native-linear-gradient';
|
||||||
import { HelpIcon } from '../../components/ui/HelpIcon';
|
import {HelpIcon} from '../../components/ui/HelpIcon';
|
||||||
|
|
||||||
const {RNSecureKeystoreModule} = NativeModules;
|
const {RNSecureKeystoreModule} = NativeModules;
|
||||||
|
|
||||||
@@ -129,10 +129,7 @@ export const KeyManagementScreen: React.FC<KeyManagementScreenProps> = () => {
|
|||||||
style={Theme.KeyManagementScreenStyle.heading}>
|
style={Theme.KeyManagementScreenStyle.heading}>
|
||||||
{t('header')}
|
{t('header')}
|
||||||
</Text>
|
</Text>
|
||||||
<HelpScreen
|
<HelpScreen source={'keyManagement'} triggerComponent={HelpIcon()} />
|
||||||
source={'keyManagement'}
|
|
||||||
triggerComponent={ HelpIcon() }
|
|
||||||
/>
|
|
||||||
</View>
|
</View>
|
||||||
<BannerNotificationContainer />
|
<BannerNotificationContainer />
|
||||||
<View style={Theme.KeyManagementScreenStyle.copilotViewStyle}>
|
<View style={Theme.KeyManagementScreenStyle.copilotViewStyle}>
|
||||||
|
|||||||
@@ -13,10 +13,7 @@ import {ProfileInfo} from '../../shared/CloudBackupAndRestoreUtils';
|
|||||||
import {useBackupScreen} from './BackupController';
|
import {useBackupScreen} from './BackupController';
|
||||||
import {BannerNotificationContainer} from '../../components/BannerNotificationContainer';
|
import {BannerNotificationContainer} from '../../components/BannerNotificationContainer';
|
||||||
import {useBackupRestoreScreen} from '../Settings/BackupRestoreController';
|
import {useBackupRestoreScreen} from '../Settings/BackupRestoreController';
|
||||||
import {
|
import {getAccountType, getDriveName} from '../../shared/commonUtil';
|
||||||
getAccountType,
|
|
||||||
getDriveName,
|
|
||||||
} from '../../shared/commonUtil';
|
|
||||||
import {HelpScreen} from '../../components/HelpScreen';
|
import {HelpScreen} from '../../components/HelpScreen';
|
||||||
import {isIOS} from '../../shared/constants';
|
import {isIOS} from '../../shared/constants';
|
||||||
import {HelpIcon} from '../../components/ui/HelpIcon';
|
import {HelpIcon} from '../../components/ui/HelpIcon';
|
||||||
@@ -222,11 +219,11 @@ const BackupAndRestoreScreen: React.FC<BackupAndRestoreProps> = props => {
|
|||||||
<LoaderAnimation testID="backupAndRestoreScreen" />
|
<LoaderAnimation testID="backupAndRestoreScreen" />
|
||||||
</Column>
|
</Column>
|
||||||
) : (
|
) : (
|
||||||
<ScrollView>
|
<ScrollView>
|
||||||
{LastBackupSection}
|
{LastBackupSection}
|
||||||
{AccountSection}
|
{AccountSection}
|
||||||
{RestoreSection}
|
{RestoreSection}
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import {getMosipIdentifier} from './commonUtil';
|
|||||||
import {VCFormat} from './VCFormat';
|
import {VCFormat} from './VCFormat';
|
||||||
import {isMosipVC, UUID} from './Utils';
|
import {isMosipVC, UUID} from './Utils';
|
||||||
import {getCredentialType} from '../components/VC/common/VCUtils';
|
import {getCredentialType} from '../components/VC/common/VCUtils';
|
||||||
|
import {RevocationStatus, RevocationStatusType} from './vcVerifier/VcVerifier';
|
||||||
|
|
||||||
const VC_KEY_PREFIX = 'VC';
|
const VC_KEY_PREFIX = 'VC';
|
||||||
const VC_ITEM_STORE_KEY_REGEX = '^VC_[a-zA-Z0-9_-]+$';
|
const VC_ITEM_STORE_KEY_REGEX = '^VC_[a-zA-Z0-9_-]+$';
|
||||||
@@ -31,7 +32,7 @@ export class VCMetadata {
|
|||||||
mosipIndividualId: string = '';
|
mosipIndividualId: string = '';
|
||||||
format: string = '';
|
format: string = '';
|
||||||
isExpired: boolean = false;
|
isExpired: boolean = false;
|
||||||
isRevoked: boolean = false;
|
isRevoked: RevocationStatusType = RevocationStatus.FALSE;
|
||||||
|
|
||||||
downloadKeyType: string = '';
|
downloadKeyType: string = '';
|
||||||
credentialType: string = '';
|
credentialType: string = '';
|
||||||
@@ -51,7 +52,7 @@ export class VCMetadata {
|
|||||||
format = '',
|
format = '',
|
||||||
downloadKeyType = '',
|
downloadKeyType = '',
|
||||||
isExpired = false,
|
isExpired = false,
|
||||||
isRevoked = false,
|
isRevoked = RevocationStatus.FALSE,
|
||||||
credentialType = '',
|
credentialType = '',
|
||||||
issuerHost = '',
|
issuerHost = '',
|
||||||
lastKnownStatusTimestamp = '',
|
lastKnownStatusTimestamp = '',
|
||||||
@@ -150,7 +151,7 @@ export const getVCMetadata = (context: object, keyType: string) => {
|
|||||||
try {
|
try {
|
||||||
const url = new URL(issuerHost);
|
const url = new URL(issuerHost);
|
||||||
return url.hostname.split('.')[0];
|
return url.hostname.split('.')[0];
|
||||||
}catch (error) {
|
} catch (error) {
|
||||||
// Fallback to issuerHost if URL parsing fails
|
// Fallback to issuerHost if URL parsing fails
|
||||||
return issuerHost;
|
return issuerHost;
|
||||||
}
|
}
|
||||||
@@ -165,7 +166,7 @@ export const getVCMetadata = (context: object, keyType: string) => {
|
|||||||
isVerified: context.vcMetadata.isVerified ?? false,
|
isVerified: context.vcMetadata.isVerified ?? false,
|
||||||
isExpired: context.vcMetadata.isExpired ?? false,
|
isExpired: context.vcMetadata.isExpired ?? false,
|
||||||
isRevoked: context.vcMetadata.isRevoked ?? false,
|
isRevoked: context.vcMetadata.isRevoked ?? false,
|
||||||
lastKnownStatusTimestamp:context.vcMetadata.lastKnownStatusTimestamp ?? '',
|
lastKnownStatusTimestamp: context.vcMetadata.lastKnownStatusTimestamp ?? '',
|
||||||
mosipIndividualId: getMosipIndividualId(
|
mosipIndividualId: getMosipIndividualId(
|
||||||
context['verifiableCredential'] as VerifiableCredential,
|
context['verifiableCredential'] as VerifiableCredential,
|
||||||
issuer,
|
issuer,
|
||||||
|
|||||||
@@ -1,15 +1,31 @@
|
|||||||
import {NativeModules} from 'react-native';
|
import {NativeModules} from 'react-native';
|
||||||
|
|
||||||
|
export const RevocationStatus = Object.freeze({
|
||||||
|
TRUE: 'TRUE',
|
||||||
|
FALSE: 'FALSE',
|
||||||
|
UNDETERMINED: 'UNDETERMINED',
|
||||||
|
} as const);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type representing any possible value of RevocationStatus.
|
||||||
|
*
|
||||||
|
* - "TRUE" → Condition was evaluated and is positively true
|
||||||
|
* - "FALSE" → Condition was evaluated and is definitively false
|
||||||
|
* - "UNDETERMINED" → Condition could not be evaluated due to an error
|
||||||
|
*/
|
||||||
|
export type RevocationStatusType =
|
||||||
|
(typeof RevocationStatus)[keyof typeof RevocationStatus];
|
||||||
|
|
||||||
export type CredentialStatusResult = {
|
export type CredentialStatusResult = {
|
||||||
isValid: boolean;
|
isValid: boolean;
|
||||||
error?: ErrorResult;
|
error?: ErrorResult;
|
||||||
statusListVC?: string; // Available only in iOS
|
statusListVC?: Record<string, any>; // Available only in iOS
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ErrorResult = {
|
export type ErrorResult = {
|
||||||
code: string;
|
code: string;
|
||||||
message: string;
|
message: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type VerificationSummaryResult = {
|
export type VerificationSummaryResult = {
|
||||||
verificationStatus: boolean;
|
verificationStatus: boolean;
|
||||||
@@ -39,8 +55,8 @@ class VCVerifier {
|
|||||||
): Promise<Record<string, CredentialStatusResult>> {
|
): Promise<Record<string, CredentialStatusResult>> {
|
||||||
try {
|
try {
|
||||||
return await this.vcVerifier.getCredentialStatus(
|
return await this.vcVerifier.getCredentialStatus(
|
||||||
JSON.stringify(credential),
|
JSON.stringify(credential),
|
||||||
format,
|
format,
|
||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new Error(`Failed to get credential status: ${error}`);
|
throw new Error(`Failed to get credential status: ${error}`);
|
||||||
@@ -53,9 +69,9 @@ class VCVerifier {
|
|||||||
): Promise<VerificationSummaryResult> {
|
): Promise<VerificationSummaryResult> {
|
||||||
try {
|
try {
|
||||||
return await this.vcVerifier.getVerificationSummary(
|
return await this.vcVerifier.getVerificationSummary(
|
||||||
credentialString,
|
credentialString,
|
||||||
credentialFormat,
|
credentialFormat,
|
||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new Error(`Failed to get verification summary: ${error}`);
|
throw new Error(`Failed to get verification summary: ${error}`);
|
||||||
|
|||||||
@@ -4,14 +4,22 @@ import {RsaSignature2018} from '../../lib/jsonld-signatures/suites/rsa2018/RsaSi
|
|||||||
import {Ed25519Signature2018} from '../../lib/jsonld-signatures/suites/ed255192018/Ed25519Signature2018';
|
import {Ed25519Signature2018} from '../../lib/jsonld-signatures/suites/ed255192018/Ed25519Signature2018';
|
||||||
import {AssertionProofPurpose} from '../../lib/jsonld-signatures/purposes/AssertionProofPurpose';
|
import {AssertionProofPurpose} from '../../lib/jsonld-signatures/purposes/AssertionProofPurpose';
|
||||||
import {PublicKeyProofPurpose} from '../../lib/jsonld-signatures/purposes/PublicKeyProofPurpose';
|
import {PublicKeyProofPurpose} from '../../lib/jsonld-signatures/purposes/PublicKeyProofPurpose';
|
||||||
import {Credential, VerifiableCredential,} from '../../machines/VerifiableCredential/VCMetaMachine/vc';
|
import {
|
||||||
|
Credential,
|
||||||
|
VerifiableCredential,
|
||||||
|
} from '../../machines/VerifiableCredential/VCMetaMachine/vc';
|
||||||
import {getErrorEventData, sendErrorEvent} from '../telemetry/TelemetryUtils';
|
import {getErrorEventData, sendErrorEvent} from '../telemetry/TelemetryUtils';
|
||||||
import {TelemetryConstants} from '../telemetry/TelemetryConstants';
|
import {TelemetryConstants} from '../telemetry/TelemetryConstants';
|
||||||
import {getMosipIdentifier} from '../commonUtil';
|
import {getMosipIdentifier} from '../commonUtil';
|
||||||
import {NativeModules} from 'react-native';
|
import {NativeModules} from 'react-native';
|
||||||
import {isAndroid, isIOS} from '../constants';
|
import {isAndroid, isIOS} from '../constants';
|
||||||
import {VCFormat} from '../VCFormat';
|
import {VCFormat} from '../VCFormat';
|
||||||
import VCVerifier, {CredentialStatusResult, VerificationSummaryResult} from '../vcVerifier/VcVerifier';
|
import VCVerifier, {
|
||||||
|
CredentialStatusResult,
|
||||||
|
RevocationStatus,
|
||||||
|
RevocationStatusType,
|
||||||
|
VerificationSummaryResult,
|
||||||
|
} from '../vcVerifier/VcVerifier';
|
||||||
|
|
||||||
// FIXME: Ed25519Signature2018 not fully supported yet.
|
// FIXME: Ed25519Signature2018 not fully supported yet.
|
||||||
// Ed25519Signature2018 proof type check is not tested with its real credential
|
// Ed25519Signature2018 proof type check is not tested with its real credential
|
||||||
@@ -59,10 +67,11 @@ async function verifyCredentialForAndroid(
|
|||||||
typeof verifiableCredential === 'string'
|
typeof verifiableCredential === 'string'
|
||||||
? verifiableCredential
|
? verifiableCredential
|
||||||
: JSON.stringify(verifiableCredential);
|
: JSON.stringify(verifiableCredential);
|
||||||
const vcVerifierResult = await VCVerifier.getInstance().getVerificationSummary(
|
const vcVerifierResult =
|
||||||
credentialString,
|
await VCVerifier.getInstance().getVerificationSummary(
|
||||||
credentialFormat,
|
credentialString,
|
||||||
);
|
credentialFormat,
|
||||||
|
);
|
||||||
return handleVcVerifierResponse(vcVerifierResult, verifiableCredential);
|
return handleVcVerifierResponse(vcVerifierResult, verifiableCredential);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,12 +90,13 @@ async function verifyCredentialForIos(
|
|||||||
Since Digital Bazaar library is not able to verify ProofType: "Ed25519Signature2020",
|
Since Digital Bazaar library is not able to verify ProofType: "Ed25519Signature2020",
|
||||||
defaulting it to return true until VcVerifier is implemented for iOS.
|
defaulting it to return true until VcVerifier is implemented for iOS.
|
||||||
*/
|
*/
|
||||||
let verificationResponse: VerificationResult;
|
let verificationResponse: VerificationResult;
|
||||||
if (verifiableCredential.proof.type === ProofType.ED25519_2020) {
|
if (verifiableCredential.proof.type === ProofType.ED25519_2020) {
|
||||||
verificationResponse = createSuccessfulVerificationResult();
|
verificationResponse = createSuccessfulVerificationResult();
|
||||||
}
|
} else {
|
||||||
else{
|
const purpose = getPurposeFromProof(
|
||||||
const purpose = getPurposeFromProof(verifiableCredential.proof.proofPurpose);
|
verifiableCredential.proof.proofPurpose,
|
||||||
|
);
|
||||||
const suite = selectVerificationSuite(verifiableCredential.proof);
|
const suite = selectVerificationSuite(verifiableCredential.proof);
|
||||||
const vcjsOptions = {
|
const vcjsOptions = {
|
||||||
purpose,
|
purpose,
|
||||||
@@ -94,12 +104,11 @@ async function verifyCredentialForIos(
|
|||||||
credential: verifiableCredential,
|
credential: verifiableCredential,
|
||||||
documentLoader: jsonld.documentLoaders.xhr(),
|
documentLoader: jsonld.documentLoaders.xhr(),
|
||||||
};
|
};
|
||||||
|
|
||||||
const result = await vcjs.verifyCredential(vcjsOptions);
|
const result = await vcjs.verifyCredential(vcjsOptions);
|
||||||
verificationResponse = handleResponse(result, verifiableCredential);
|
verificationResponse = handleResponse(result, verifiableCredential);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (verificationResponse.isVerified) {
|
if (verificationResponse.isVerified) {
|
||||||
const statusArray = await VCVerifier.getInstance().getCredentialStatus(
|
const statusArray = await VCVerifier.getInstance().getCredentialStatus(
|
||||||
verifiableCredential,
|
verifiableCredential,
|
||||||
@@ -188,7 +197,9 @@ async function handleVcVerifierResponse(
|
|||||||
verifiableCredential,
|
verifiableCredential,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const isRevoked = await checkIsStatusRevoked(verificationResult.credentialStatus)
|
const isRevoked = await checkIsStatusRevoked(
|
||||||
|
verificationResult.credentialStatus,
|
||||||
|
);
|
||||||
return {
|
return {
|
||||||
isVerified: verificationResult.verificationStatus,
|
isVerified: verificationResult.verificationStatus,
|
||||||
verificationMessage: verificationResult.verificationMessage,
|
verificationMessage: verificationResult.verificationMessage,
|
||||||
@@ -209,45 +220,51 @@ async function handleVcVerifierResponse(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleStatusListVCVerification = (status: CredentialStatusResult, type: "revoked" | "valid") => {
|
const handleStatusListVCVerification = (
|
||||||
|
status: CredentialStatusResult,
|
||||||
|
type: 'revoked' | 'valid',
|
||||||
|
) => {
|
||||||
const isValid = verifyStatusListVC(status.statusListVC);
|
const isValid = verifyStatusListVC(status.statusListVC);
|
||||||
if (!isValid) {
|
if (!isValid) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`StatusListVC verification failed for ${type} entry ${status.error}`,
|
`StatusListVC verification failed for ${type} entry ${status.error}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
export async function checkIsStatusRevoked(
|
export async function checkIsStatusRevoked(
|
||||||
vcStatus: Record<string, CredentialStatusResult>,
|
vcStatus: Record<string, CredentialStatusResult>,
|
||||||
): Promise<boolean> {
|
): Promise<RevocationStatusType> {
|
||||||
if (!Object.keys(vcStatus).length) return false;
|
if (!vcStatus || !Object.keys(vcStatus).length) return RevocationStatus.FALSE;
|
||||||
|
|
||||||
const revocationStatus = vcStatus["revocation"] as CredentialStatusResult;
|
const revocationStatus = vcStatus['revocation'] as CredentialStatusResult;
|
||||||
if (!revocationStatus) return false;
|
if (!revocationStatus) return RevocationStatus.FALSE;
|
||||||
|
|
||||||
const {isValid, error} = revocationStatus;
|
const {isValid, error} = revocationStatus;
|
||||||
|
|
||||||
if (isValid) {
|
if (isValid) {
|
||||||
// Validate the valid statuses statusList VC for iOS
|
// Validate the valid statuses statusList VC for iOS
|
||||||
if (isIOS()) {
|
if (isIOS()) {
|
||||||
handleStatusListVCVerification(revocationStatus, "valid")
|
handleStatusListVCVerification(revocationStatus, 'valid');
|
||||||
}
|
}
|
||||||
return false
|
return RevocationStatus.FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.error(`Credential is revoked. Error: ${error?.code}, Message: ${error?.message}`);
|
|
||||||
// if there is an error fetching revocation status itself, throw error (isValid = true, error = Error)
|
// if there is an error fetching revocation status itself, throw error (isValid = true, error = Error)
|
||||||
if (error) {
|
if (error) {
|
||||||
throw new Error(`Error fetching revocation status. Error: ${error.code}, Message: ${error.message}`);
|
console.error(
|
||||||
|
`Error fetching revocation status. Error: ${error.code}, Message: ${error.message}`,
|
||||||
|
);
|
||||||
|
return RevocationStatus.UNDETERMINED;
|
||||||
}
|
}
|
||||||
// There is no error fetching revocation status, but the status is invalid (isValid = false, error = undefined) - VC is revoked
|
// There is no error fetching revocation status, but the status is invalid (isValid = false, error = undefined) - VC is revoked
|
||||||
// Validate the valid statuses statusList VC for iOS
|
// Validate the valid statuses statusList VC for iOS
|
||||||
if (isIOS()) {
|
if (isIOS()) {
|
||||||
handleStatusListVCVerification(revocationStatus, "revoked");
|
handleStatusListVCVerification(revocationStatus, 'revoked');
|
||||||
}
|
}
|
||||||
|
console.error(`Credential is revoked`);
|
||||||
// If revocation status is invalid, the credential is revoked
|
// If revocation status is invalid, the credential is revoked
|
||||||
return true
|
return RevocationStatus.TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createSuccessfulVerificationResult(): VerificationResult {
|
function createSuccessfulVerificationResult(): VerificationResult {
|
||||||
@@ -298,12 +315,12 @@ export interface VerificationResult {
|
|||||||
isVerified: boolean;
|
isVerified: boolean;
|
||||||
verificationMessage: string;
|
verificationMessage: string;
|
||||||
verificationErrorCode: string;
|
verificationErrorCode: string;
|
||||||
isRevoked?: boolean;
|
isRevoked?: RevocationStatusType;
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: Implement status list VC verification for iOS.
|
//TODO: Implement status list VC verification for iOS.
|
||||||
//Currently Digital Bazaar library does not support VC 2.0 status list VC verification.
|
//Currently Digital Bazaar library does not support VC 2.0 status list VC verification.
|
||||||
function verifyStatusListVC(statusListVC: string | undefined) {
|
function verifyStatusListVC(statusListVC: Record<string, any> | undefined) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user