[INJIMOB-1192] onboarding of new issuer is affecting the existing issuers (#1476)

* [INJIMOB-1192] : use wellknown response instead of mimoto issuer config.
-- Remove hardcoding for sunbird issuer in vc activation and verification flow.
-- Render idType from wellknown response
-- Remove UIN/VID from default add-on fields

Signed-off-by: Swati Goel <meet2swati@gmail.com>

* [INJIMOB-1192] : fix propType and some refactoring

Signed-off-by: Swati Goel <meet2swati@gmail.com>

* [INJIMOB-1192] : add credentialType in VcMetadata

Signed-off-by: Swati Goel <meet2swati@gmail.com>

* [INJIMOB-1192] fix vc download via issuer flow due to credentialType mismatch

Co-authored-by: PuBHARGAVI <46226958+PuBHARGAVI@users.noreply.github.com>
Signed-off-by: KiruthikaJeyashankar <81218987+KiruthikaJeyashankar@users.noreply.github.com>

* [INJIMOB-1192] rename supported list of credential type in issuers model

Co-authored-by: PuBHARGAVI <46226958+PuBHARGAVI@users.noreply.github.com>
Signed-off-by: KiruthikaJeyashankar <81218987+KiruthikaJeyashankar@users.noreply.github.com>

* [INJIMOB-1192] display id type in history based on wellknown for issuers VC

Signed-off-by: KiruthikaJeyashankar <81218987+KiruthikaJeyashankar@users.noreply.github.com>

* [INJIMOB-1192] fix id type not shown for VC activation

Signed-off-by: KiruthikaJeyashankar <81218987+KiruthikaJeyashankar@users.noreply.github.com>

* [INJIMOB-1192] remove unused credentialType field from VCMetaData

Signed-off-by: KiruthikaJeyashankar <81218987+KiruthikaJeyashankar@users.noreply.github.com>

* [INJIMOB-1192] set default idType for logging activity

Signed-off-by: KiruthikaJeyashankar <81218987+KiruthikaJeyashankar@users.noreply.github.com>

* [INJIMOB-1192] move vc item machine events into model

Events should not be exported to other packages for direct use so that Xstate's createModel() can decorate the function appropriately

Signed-off-by: KiruthikaJeyashankar <81218987+KiruthikaJeyashankar@users.noreply.github.com>

* [INJIMOB-1192] show verify banner id type from wellknown

Signed-off-by: KiruthikaJeyashankar <81218987+KiruthikaJeyashankar@users.noreply.github.com>

* [INJIMOB-1192] refactor duplication and unused code

Co-authored-by: PuBHARGAVI <46226958+PuBHARGAVI@users.noreply.github.com>
Signed-off-by: KiruthikaJeyashankar <81218987+KiruthikaJeyashankar@users.noreply.github.com>

* [INJIMOB-1192] remove unused displayId in metadata

Signed-off-by: KiruthikaJeyashankar <81218987+KiruthikaJeyashankar@users.noreply.github.com>

* [INJIMOB-1192] revert the dimensions of camera scanner to old values to support face liveness verification

Co-authored-by: KiruthikaJeyashankar <81218987+KiruthikaJeyashankar@users.noreply.github.com>
Signed-off-by: PuBHARGAVI <46226958+PuBHARGAVI@users.noreply.github.com>

* [INJIMOB-1192] remove unused code & debug logs

Signed-off-by: KiruthikaJeyashankar <81218987+KiruthikaJeyashankar@users.noreply.github.com>

* [INJIMOB-1192] fix failing test cases

Co-authored-by: KiruthikaJeyashankar <81218987+KiruthikaJeyashankar@users.noreply.github.com>
Signed-off-by: PuBHARGAVI <46226958+PuBHARGAVI@users.noreply.github.com>

* [INJIMOB-1192] remove unused translations

Signed-off-by: KiruthikaJeyashankar <81218987+KiruthikaJeyashankar@users.noreply.github.com>

---------

Signed-off-by: Swati Goel <meet2swati@gmail.com>
Signed-off-by: KiruthikaJeyashankar <81218987+KiruthikaJeyashankar@users.noreply.github.com>
Signed-off-by: PuBHARGAVI <46226958+PuBHARGAVI@users.noreply.github.com>
Co-authored-by: Swati Goel <meet2swati@gmail.com>
Co-authored-by: PuBHARGAVI <46226958+PuBHARGAVI@users.noreply.github.com>
This commit is contained in:
KiruthikaJeyashankar
2024-06-04 16:37:54 +05:30
committed by GitHub
parent 339e08c462
commit 003cc156c2
62 changed files with 1040 additions and 773 deletions

View File

@@ -2,7 +2,7 @@ fileignoreconfig:
- filename: package.json
checksum: 5b4fcb5ddc7cc96cc2d1733b544d56ea66e88cdab995a1052fbf9ac0e9c2dc21
- filename: package-lock.json
checksum: 50254c7e3e84d59dceb77cde95ce71cb5d0625cb5ec84971a28b6fc4f95db7f1
checksum: 98f4ef19f06521bac3ea3033d82810203214bf55b0469790a1d8acc20933c581
- filename: lib/jsonld-signatures/suites/ed255192018/ed25519.ts
checksum: 493b6e31144116cb612c24d98b97d8adcad5609c0a52c865a6847ced0a0ddc3a
- filename: components/PasscodeVerify.tsx
@@ -38,7 +38,7 @@ fileignoreconfig:
- filename: screens/Home/MyVcs/GetIdInputModal.tsx
checksum: 5c736ed79a372d0ffa7c02eb33d0dc06edbbb08d120978ff287f5f06cd6c7746
- filename: shared/openId4VCI/Utils.ts
checksum: f8b53de9c07074dc3a73f9443ba140c7e86300b4a2beac1a84bfccafb55ecd6a
checksum: ee4db1768be8d51fac0eb876a7b16fd2ab1806abcc711f01056f672003d11f31
- filename: shared/cryptoutil/cryptoUtil.ts
checksum: 2efef1baca1eee0da60420c8d966a6d58589bc3ac74169ab1cdc19423b630dba
- filename: shared/telemetry/TelemetryConstants.js
@@ -63,8 +63,10 @@ fileignoreconfig:
checksum: 736b5a7ddb86bd4376229ce198dbf8a663e7ac89fc3311bd4f19afd4a2b36ffd
- filename: assets/Finger_Print_Icon.svg
checksum: 776d4fe4fc4b54d185ccf97daf0511b9fe2c0e0f7c1a809047020e5e8a100db6
- filename: screens/MainLayout.tsx
checksum: 53ead79279c9609e42a8993db1a66bdb4649e1ae3b909d462b45b00c507c416e
- filename: android/app/build.gradle
checksum: 9f9cdcd2ffb37338760d741694486cf5418a38834c3ca1bd9c573098ee10d997
checksum: 46a4054440361b25d13ecd75811bf239a6abb4830ce7f79b2b15ccd878758760
- filename: .github/workflows/push-triggers.yml
checksum: abc19ea38c8d7b79f15695d015709cc88a34a995181aaf12bc8344f940f3cbc4
- filename: android/fastlane/Fastfile
@@ -113,6 +115,16 @@ fileignoreconfig:
checksum: a4e3772dc67a07ecbcfc58be0d6d4f7fa799cec7ac25bd269ac29459c8669ca4
- filename: injitest/src/test/java/iosTestCases/CredentialRegistryTest.java
checksum: b0808e0c511412cde21fd169a9bbeaf3b77cb48f25418e12d341cc3ce1df5898
- filename: injitest/src/main/resources/Vids.json
checksum: 8bcffed7a6dd565ae695e1b29de0655e10bd5c5420af2718defd593a687b8817
- filename: injitest/src/main/java/inji/utils/UpdateNetworkSettings.java
checksum: e249ce3e6b7f47abc183fe5a3637bb39ccb06900ef75b9b2f08426d1535e22aa
- filename: injitest/src/test/java/androidTestCases/ShareVcTest.java
checksum: a7e3e579b6ac05f95932638b61272142774d0690c13717c890e87374782ea509
- filename: injitest/src/test/java/iosTestCases/ShareVcTest.java
checksum: 1cf9b61d3fcea9b63b2b9f7dffe9b5a1848e196c39f77790b6c9d83f201c6197
- filename: ios/RNPixelpassModule.swift
checksum: 822a2421798d5c0669f4ab1b983194eb770cbef2aa30bf212d06bd959738c4ca
- filename: components/BackupAndRestoreAllScreenBanner.tsx
checksum: 2c98e7e83959c9dac4dd12da32f81483c3d334bd05e279637cf465475fbf54b8
- filename: locales/en.json
@@ -144,7 +156,7 @@ fileignoreconfig:
- filename: shared/VCMetadata.ts
checksum: e93f988415bf91064e2cf5fbc09ff6c7226798baa5da721fa0715d5d0d6afddf
- filename: ios/Podfile.lock
checksum: 0b4ed806e0fbecf60fb1135072d0a629666723fedcd960b6470bac0bb42a3e68
checksum: b8c97d58a88207bae811db83074388cff249a83055a1f92ea7dee2f59b7a32c9
- filename: components/BackupAndRestoreBannerNotification.tsx
checksum: e465a9947727687d784d0cb9d8db1e28f765b0659bf4a3aa6d75643aa7b14102
- filename: components/ActivityLogEvent.ts
@@ -186,11 +198,11 @@ fileignoreconfig:
- filename: screens/Home/IntroSlidersScreen.tsx
checksum: 9880724461b194db7651737576ad2fd2db9cf3b4e732747f59be422a7ff4e4a1
- filename: .env
checksum: e4254ca79a1269161ac3e9d4870680a8650ac7dbdf61c39c084722a9e8925669
checksum: ac76b852842c44ff5dac96c1fa5061e569bea4f54b3080d869a9dc25abd17991
- filename: machines/VCItemMachine/VCItemMachine.typegen.ts
checksum: 850b5d02636bef9e286fc0fbc4ffffbd38068f332c319302a906496f4bc1c8a1
- filename: machines/VCItemMachine/VCItemEvents.ts
checksum: 04e5758d4fa8bc37e8b66f7f51627a9e71ccbca7a046aa64e914f5cf855aa48b
- filename: machines/VerifiableCredential/VCItemMachine/VCItemModel.ts
checksum: 2a22331fe5f20d44c210b8970be0b934bfdf39bc999009305a9ba8f18e4d5469
- filename: machines/VCItemMachine/VCItemGaurds.ts
checksum: 4f32814fc26a0edaa54a42dbc9f9e1d899144eb059ac8da211d1738887871829
- filename: machines/VCItemMachine/VCItemServices.ts
@@ -317,8 +329,14 @@ fileignoreconfig:
- filename: machines/VerifiableCredential/VCItemMachine/VCItemMachine.ts
checksum: fdc0c23a7107eb713d20f60fda675f9e9fe8ef29c981d798d90e581dfee340c8
checksum: 8ac74d2e5c6de179e460b86899eb048ad4c5bd67abc3d28c015e92335b8afe24
- filename: machines/VerifiableCredential/VCItemMachine/VCItemServices.ts
checksum: 1ce38602f148388940eec172a5c9be83de7a600adcae0ba9e8ac27e5ebc44641
- filename: ios/RNPixelpassModule.m
checksum: c91348eceec5edbffa03ba03f3f52a8e90ff7f942816c9609080d1647052fd66
- filename: android/app/src/main/java/io/mosip/residentapp/InjiVciClientModule.java
checksum: 17f55840bab193bc353034445ba4fce53e1ce466e95f616c15a1351f8d2f23bc
- filename: ios/Inji.xcworkspace/xcshareddata/swiftpm/Package.resolved
checksum: b168940c6b487dc96fd22f564f2e187dae46f4fa5e4a64cf81c4d810b1c1ae78
- filename: injitest/src/main/resources/Vids.json
checksum: 8bcffed7a6dd565ae695e1b29de0655e10bd5c5420af2718defd593a687b8817
- filename: injitest/src/main/java/inji/utils/UpdateNetworkSettings.java
@@ -347,4 +365,8 @@ fileignoreconfig:
checksum: b168940c6b487dc96fd22f564f2e187dae46f4fa5e4a64cf81c4d810b1c1ae78
- filename: ios/Inji.xcodeproj/project.pbxproj
checksum: 4359976ed4d1ac3206d76b87d3458d070027199c8569ba123436c4b5343aba74
- filename: components/FaceScanner/FaceCompare.tsx
checksum: 947b6d75543e2bf959ca2d95dd7224051e0b4ec2c28f7515f923701e22a932f0
- filename: components/FaceScanner/LivenessDetection.tsx
checksum: d4140a42ee9ca0f7c90e490f762d181a723fd9dd20db891cbbe53bfbd8f81632
version: ""

View File

@@ -145,12 +145,9 @@ jest.mock('react-native-gesture-handler', () => {
};
});
jest.mock('@mosip/secure-keystore', () => ({
sign: jest.fn(),
encryptData: input => (input ? String(input) : 'mockedString'),
decryptData: input => (input ? String(input) : 'mockedString'),
deviceSupportsHardware: () => true,
}));
jest.mock('@invertase/react-native-apple-authentication', () => {});
jest.mock('react-native-share', () => {});
jest.mock('../machines/store', () => ({
getItem: jest.fn(),

View File

@@ -17,6 +17,12 @@ jest.mock('react-native', () => {
SecureKeystore: {
deviceSupportsHardware: jest.fn(),
},
RNSecureKeystoreModule: {
sign: jest.fn(),
encryptData: input => (input ? String(input) : 'mockedString'),
decryptData: input => (input ? String(input) : 'mockedString'),
deviceSupportsHardware: () => true,
},
},
});

View File

@@ -23,7 +23,7 @@ describe('getActionText', () => {
mockIl18nfn = jest.fn();
activityLog = new ActivityLog({
id: 'mockId',
idType: 'mockIDtype',
idType: ['mockIDtype'] as string[],
_vcKey: 'mock_vc_key',
type: 'mockType',
timestamp: 1234,
@@ -38,18 +38,17 @@ describe('getActionText', () => {
return 'National ID';
}
});
getActionText(activityLog, mockIl18nfn);
expect(mockIl18nfn).toHaveBeenCalledWith(`VcDetails:mockIDtype`);
getActionText(activityLog, mockIl18nfn, {});
expect(mockIl18nfn).toHaveBeenCalledWith('mockType', {
idType: 'National ID',
idType: 'nationalCard',
id: 'mockId',
});
expect(mockIl18nfn).toHaveBeenCalledTimes(2);
expect(mockIl18nfn).toHaveBeenCalledTimes(1);
// TODO: assert the returned string
});
it('should not fetch id type from translation file mock', () => {
activityLog.idType = undefined;
getActionText(activityLog, mockIl18nfn);
getActionText(activityLog, mockIl18nfn, {});
expect(mockIl18nfn).toHaveBeenCalledWith('mockType', {
idType: '',
id: 'mockId',

View File

@@ -1,3 +1,5 @@
import {getIdType} from './VC/common/VCUtils';
export type ActivityLogType =
| '' // replacement for undefined
| 'VC_SHARED'
@@ -18,21 +20,23 @@ export type ActivityLogType =
export class ActivityLog {
id: string;
idType: string;
idType: string[];
_vcKey: string;
timestamp: number;
deviceName: string;
vcLabel: string;
type: ActivityLogType;
issuer: string;
constructor({
id = '',
idType = '',
idType = [],
_vcKey = '',
type = '',
timestamp = Date.now(),
deviceName = '',
vcLabel = '',
issuer = '',
} = {}) {
this.id = id;
this.idType = idType;
@@ -41,6 +45,7 @@ export class ActivityLog {
this.timestamp = timestamp;
this.deviceName = deviceName;
this.vcLabel = vcLabel;
this.issuer = issuer;
}
static logTamperedVCs() {
@@ -50,13 +55,14 @@ export class ActivityLog {
timestamp: Date.now(),
deviceName: '',
vcLabel: '',
issuer: '',
};
}
}
export function getActionText(activity: ActivityLog, t) {
if (activity.idType && activity.idType !== '') {
let cardType = t(`VcDetails:${activity.idType}`);
export function getActionText(activity: ActivityLog, t, wellknown: Object) {
if (activity.idType && activity.idType.length !== 0) {
const cardType = getIdType(wellknown, activity.idType);
return `${t(activity.type, {idType: cardType, id: activity.id})}`;
}
return `${t(activity.type, {idType: '', id: activity.id})}`;

View File

@@ -5,15 +5,21 @@ import {useTranslation} from 'react-i18next';
import * as DateFnsLocale from 'date-fns/locale';
import {TextItem} from './ui/TextItem';
import {ActivityLog, getActionText} from './ActivityLogEvent';
import {useHistoryTab} from '../screens/History/HistoryScreenController';
export const ActivityLogText: React.FC<{activity: ActivityLog}> = props => {
const {t, i18n} = useTranslation('ActivityLogText');
const historyController = useHistoryTab();
const {activity} = props;
return (
<TextItem
label={getActionLabel(activity, i18n.language)}
text={getActionText(activity, t)}
text={getActionText(
activity,
t,
historyController.getWellKnownIssuerMap(activity.issuer),
)}
divider
/>
);

View File

@@ -78,9 +78,7 @@ export const BannerNotificationContainer: React.FC<
<BannerNotification
type={verificationStatus.statusType}
message={t(`VcVerificationBanner:${verificationStatus?.statusType}`, {
vcDetails: `${t(`VcDetails:${verificationStatus.vcType}`)} ${
verificationStatus.vcNumber
}`,
vcDetails: `${verificationStatus.vcType} ${verificationStatus.vcNumber}`,
})}
onClosePress={bannerNotificationController.RESET_VERIFICATION_STATUS}
key={'reVerificationInProgress'}

View File

@@ -1,10 +1,10 @@
import React from 'react';
import { Camera, CameraType } from 'expo-camera';
import { View, TouchableOpacity } from 'react-native';
import {Camera, CameraType} from 'expo-camera';
import {View, TouchableOpacity} from 'react-native';
import {SvgImage} from '../ui/svg';
import { Text, Column, Row, Centered } from '../ui';
import {Text, Column, Row, Centered} from '../ui';
import {RotatingIcon} from '../RotatingIcon';
import { Theme } from '../ui/styleUtils';
import {Theme} from '../ui/styleUtils';
import testIDProps from '../../shared/commonUtil';
const FaceCompare: React.FC<FaceCompareProps> = ({
@@ -13,11 +13,11 @@ const FaceCompare: React.FC<FaceCompareProps> = ({
isCapturing,
isVerifying,
service,
t
t,
}) => {
return (
<Column fill align="space-between" style={{ backgroundColor: '#ffffff' }}>
<View style={{ flex: 2, marginTop: 15 }}>
<Column fill align="space-between" style={{backgroundColor: '#ffffff'}}>
<View style={{flex: 2, marginTop: 15}}>
<View style={Theme.CameraEnabledStyles.scannerContainer}>
<View>
<Camera
@@ -33,8 +33,7 @@ const FaceCompare: React.FC<FaceCompareProps> = ({
align="center"
weight="semibold"
style={Theme.TextStyles.base}
margin="80 57"
>
margin="80 57">
{t('imageCaptureGuide')}
</Text>
</View>
@@ -47,7 +46,9 @@ const FaceCompare: React.FC<FaceCompareProps> = ({
<TouchableOpacity onPress={() => service.send('CAPTURE')}>
{SvgImage.CameraCaptureIcon()}
</TouchableOpacity>
<Text testID="captureText" style={Theme.CameraEnabledStyles.iconText}>
<Text
testID="captureText"
style={Theme.CameraEnabledStyles.iconText}>
{t('capture')}
</Text>
</Centered>
@@ -55,7 +56,9 @@ const FaceCompare: React.FC<FaceCompareProps> = ({
<TouchableOpacity onPress={() => service.send('FLIP_CAMERA')}>
{SvgImage.FlipCameraIcon()}
</TouchableOpacity>
<Text testID="flipCameraText" style={Theme.CameraEnabledStyles.iconText}>
<Text
testID="flipCameraText"
style={Theme.CameraEnabledStyles.iconText}>
{t('flipCamera')}
</Text>
</Centered>
@@ -69,10 +72,10 @@ const FaceCompare: React.FC<FaceCompareProps> = ({
export default FaceCompare;
interface FaceCompareProps {
whichCamera: CameraType;
setCameraRef:(node: Camera) => void;
isCapturing: boolean;
isVerifying: boolean;
service: any;
t: (key: string) => string;
}
whichCamera: CameraType;
setCameraRef: (node: Camera) => void;
isCapturing: boolean;
isVerifying: boolean;
service: any;
t: (key: string) => string;
}

View File

@@ -45,7 +45,7 @@ export const imageCaptureConfig = {
imageType: ImageType.jpg,
};
export const faceDetectorConfig : FaceDetectorConfig= {
export const faceDetectorConfig: FaceDetectorConfig = {
mode: FaceDetector.FaceDetectorMode.accurate,
detectLandmarks: FaceDetector.FaceDetectorLandmarks.all,
runClassifications: FaceDetector.FaceDetectorClassifications.all,
@@ -258,7 +258,7 @@ export interface FaceDetectorConfig {
mode: FaceDetector.FaceDetectorMode;
detectLandmarks: FaceDetector.FaceDetectorLandmarks;
runClassifications: FaceDetector.FaceDetectorClassifications;
contourMode: FaceDetector.FaceDetectorClassifications;
contourMode: FaceDetector.FaceDetectorClassifications;
minDetectionInterval: number;
tracking: boolean;
};
}

View File

@@ -1,12 +1,12 @@
import React from 'react';
import { Camera, CameraType } from 'expo-camera';
import { View, TouchableOpacity } from 'react-native';
import {Camera, CameraType} from 'expo-camera';
import {View, TouchableOpacity} from 'react-native';
import Spinner from 'react-native-spinkit';
import { Column, Text } from '.././ui';
import { Theme } from '.././ui/styleUtils';
import Svg, { Defs, Mask, Rect, Ellipse } from 'react-native-svg';
import {Column, Text} from '.././ui';
import {Theme} from '.././ui/styleUtils';
import Svg, {Defs, Mask, Rect, Ellipse} from 'react-native-svg';
import testIDProps from '../../shared/commonUtil';
import { FaceDetectorConfig } from './FaceScannerHelper';
import {FaceDetectorConfig} from './FaceScannerHelper';
const LivenessDetection: React.FC<LivenessDetectionProps> = ({
screenColor,
@@ -18,19 +18,24 @@ const LivenessDetection: React.FC<LivenessDetectionProps> = ({
handleOnCancel,
opacity,
setOpacity,
t
t,
}) => {
return (
<Column fill align='space-between' style={{ backgroundColor: screenColor }}>
<Column fill align="space-between" style={{backgroundColor: screenColor}}>
<View style={Theme.CameraEnabledStyles.guideContainer}>
<View style={Theme.CameraEnabledStyles.guideContentContainer}>
<Spinner type="ThreeBounce" color={Theme.Colors.Loading} />
<Text testID="captureInfoText" size="small" weight="bold" color="black" align="center">
<Text
testID="captureInfoText"
size="small"
weight="bold"
color="black"
align="center">
{infoText}
</Text>
</View>
</View>
<View style={{ flex: 2, marginTop: 15 }}>
<View style={{flex: 2, marginTop: 15}}>
<View style={Theme.CameraEnabledStyles.scannerContainer}>
<View>
<Camera
@@ -41,14 +46,19 @@ const LivenessDetection: React.FC<LivenessDetectionProps> = ({
onFacesDetected={handleFacesDetected}
faceDetectorSettings={faceDetectorConfig}
/>
<Svg height="100%" width="100%" style={{ position: 'absolute' }}>
<Svg height="100%" width="100%" style={{position: 'absolute'}}>
<Defs>
<Mask id="mask" x="0" y="0" height="100%" width="100%">
<Rect height="100%" width="100%" fill="#fff" opacity="0.3" />
<Ellipse rx="38%" ry="45%" cx="50%" cy="50%" fill="black" />
</Mask>
</Defs>
<Rect height="100%" width="100%" fill="rgba(0, 0, 0, 0.8)" mask="url(#mask)" />
<Rect
height="100%"
width="100%"
fill="rgba(0, 0, 0, 0.8)"
mask="url(#mask)"
/>
</Svg>
</View>
</View>
@@ -56,12 +66,16 @@ const LivenessDetection: React.FC<LivenessDetectionProps> = ({
<View style={Theme.CameraEnabledStyles.buttonContainer}>
<TouchableOpacity
{...testIDProps('cancel')}
style={[Theme.CameraEnabledStyles.cancelButton, { opacity }]}
style={[Theme.CameraEnabledStyles.cancelButton, {opacity}]}
onPressIn={() => setOpacity(0.5)}
onPressOut={() => setOpacity(1)}
onPress={handleOnCancel}
>
<Text testID="cancelText" size="small" weight="bold" margin="8" color="black">
onPress={handleOnCancel}>
<Text
testID="cancelText"
size="small"
weight="bold"
margin="8"
color="black">
{t('cancel')}
</Text>
</TouchableOpacity>
@@ -73,14 +87,14 @@ const LivenessDetection: React.FC<LivenessDetectionProps> = ({
export default LivenessDetection;
interface LivenessDetectionProps {
screenColor: string;
infoText: string;
whichCamera: CameraType;
setCameraRef: (node: Camera) => void;
handleFacesDetected: (faces: any) => Promise<void>;
faceDetectorConfig: FaceDetectorConfig;
handleOnCancel: () => void;
opacity: number;
setOpacity: (opacity: number) => void;
t: (key: string) => string;
}
screenColor: string;
infoText: string;
whichCamera: CameraType;
setCameraRef: (node: Camera) => void;
handleFacesDetected: (faces: any) => Promise<void>;
faceDetectorConfig: FaceDetectorConfig;
handleOnCancel: () => void;
opacity: number;
setOpacity: (opacity: number) => void;
t: (key: string) => string;
}

View File

@@ -3,7 +3,7 @@ import {ImageBackground, Pressable, Image, View} from 'react-native';
import {getLocalizedField} from '../../../i18n';
import {VCMetadata} from '../../../shared/VCMetadata';
import {KebabPopUp} from '../../KebabPopUp';
import {VerifiableCredential} from '../../../machines/VerifiableCredential/VCMetaMachine/vc';
import {Credential} from '../../../machines/VerifiableCredential/VCMetaMachine/vc';
import {Column, Row} from '../../ui';
import {Theme} from '../../ui/styleUtils';
import {CheckBox, Icon} from 'react-native-elements';
@@ -13,7 +13,7 @@ import {isVCLoaded, getBackgroundColour} from '../common/VCUtils';
import {VCItemFieldValue} from '../common/VCItemField';
import {WalletBinding} from '../../../screens/Home/MyVcs/WalletBinding';
import {VCVerification} from '../../VCVerification';
import {Issuers} from '../../../shared/openId4VCI/Utils';
import {isActivationNeeded} from '../../../shared/openId4VCI/Utils';
import {VCItemContainerFlowType} from '../../../shared/Utils';
import {RemoveVcWarningOverlay} from '../../../screens/Home/MyVcs/RemoveVcWarningOverlay';
import {HistoryTab} from '../../../screens/Home/MyVcs/HistoryTab';
@@ -87,10 +87,10 @@ export const VCCardViewContent: React.FC<VCItemContentProps> = props => {
{!Object.values(VCItemContainerFlowType).includes(props.flow) && (
<>
{props.vcMetadata.issuer === Issuers.Sunbird ||
props.walletBindingResponse
? SvgImage.walletActivatedIcon()
: SvgImage.walletUnActivatedIcon()}
{!props.walletBindingResponse &&
isActivationNeeded(props.verifiableCredentialData?.issuer)
? SvgImage.walletUnActivatedIcon()
: SvgImage.walletActivatedIcon()}
<Pressable
onPress={props.KEBAB_POPUP}
accessible={false}
@@ -130,7 +130,7 @@ export const VCCardViewContent: React.FC<VCItemContentProps> = props => {
export interface VCItemContentProps {
context: any;
credential: VerifiableCredential;
credential: Credential;
verifiableCredentialData: any;
fields: [];
wellknown: {};

View File

@@ -2,6 +2,7 @@ import React from 'react';
import {useTranslation} from 'react-i18next';
import {Image, ImageBackground, View} from 'react-native';
import {
Credential,
VerifiableCredential,
WalletBindingResponse,
} from '../../../machines/VerifiableCredential/VCMetaMachine/vc';

View File

@@ -1,5 +1,8 @@
import {
Credential,
CredentialSubject,
CredentialTypes,
IssuerWellknownResponse,
VerifiableCredential,
} from '../../../machines/VerifiableCredential/VCMetaMachine/vc';
import i18n, {getLocalizedField} from '../../../i18n';
@@ -8,10 +11,10 @@ import {VCItemField} from './VCItemField';
import React from 'react';
import {Theme} from '../../ui/styleUtils';
import {CREDENTIAL_REGISTRY_EDIT} from 'react-native-dotenv';
import {getIDType} from '../../../shared/openId4VCI/Utils';
import {VCVerification} from '../../VCVerification';
import {MIMOTO_BASE_URL} from '../../../shared/constants';
import {useTranslation} from 'react-i18next';
import {VCItemDetailsProps} from '../Views/VCDetailView';
import {getSelectedCredentialTypeDetails} from '../../../shared/openId4VCI/Utils';
export const CARD_VIEW_DEFAULT_FIELDS = ['fullName'];
export const DETAIL_VIEW_DEFAULT_FIELDS = [
@@ -26,8 +29,6 @@ export const DETAIL_VIEW_DEFAULT_FIELDS = [
//todo UIN & VID to be removed once we get the fields in the wellknown endpoint
export const CARD_VIEW_ADD_ON_FIELDS = ['UIN', 'VID'];
export const DETAIL_VIEW_ADD_ON_FIELDS = [
'UIN',
'VID',
'status',
'credentialRegistry',
'idType',
@@ -46,18 +47,11 @@ export const BOTTOM_SECTION_FIELDS_WITH_DETAILED_ADDRESS_FIELDS = [
];
export const getFieldValue = (
verifiableCredential: VerifiableCredential,
verifiableCredential: Credential,
field: string,
wellknown: any,
props: any,
) => {
const {t} = useTranslation();
const date = new Date(
getLocalizedField(verifiableCredential?.credentialSubject[field]),
).toString();
if (date !== 'Invalid Date') {
return formattedDateTime(date);
}
switch (field) {
case 'status':
return (
@@ -67,7 +61,7 @@ export const getFieldValue = (
/>
);
case 'idType':
return t(`VcDetails:${getIDType(verifiableCredential)}`);
return getIdType(wellknown);
case 'credentialRegistry':
return props?.vc?.credentialRegistry;
case 'address':
@@ -77,51 +71,22 @@ export const getFieldValue = (
default: {
const fieldValue = verifiableCredential?.credentialSubject[field];
if (Array.isArray(fieldValue) && typeof fieldValue[0] !== 'object') {
return fieldValue;
return fieldValue.join(', ');
}
return getLocalizedField(fieldValue);
}
}
};
export const getCredentialDefinition = (
wellknown: any,
vcCredentialTypes: Object[],
) => {
if (Array.isArray(wellknown.credentials_supported)) {
return wellknown.credentials_supported[0].credential_definition;
} else {
for (const supportedCredential in wellknown.credentials_supported) {
const credentialDefinition =
wellknown.credentials_supported[supportedCredential]
.credential_definition;
if (
JSON.stringify(credentialDefinition.type) ===
JSON.stringify(vcCredentialTypes)
) {
return credentialDefinition;
}
}
return null;
}
};
export const getFieldName = (
field: string,
wellknown: any,
vcCredentialTypes: Object[],
) => {
if (wellknown && wellknown.credentials_supported) {
const credentialDefinition = getCredentialDefinition(
wellknown,
vcCredentialTypes,
);
export const getFieldName = (field: string, wellknown: any) => {
if (wellknown) {
const credentialDefinition = wellknown.credential_definition;
if (!credentialDefinition) {
console.error(
'Credential definition is not available for the selected credential type',
);
}
let fieldObj = credentialDefinition.credentialSubject[field];
let fieldObj = credentialDefinition?.credentialSubject[field];
if (fieldObj) {
const newFieldObj = fieldObj.display.map(obj => {
return {language: obj.locale, value: obj.name};
@@ -133,20 +98,11 @@ export const getFieldName = (
};
export const getBackgroundColour = (wellknown: any) => {
if (wellknown && wellknown.credentials_supported[0]?.display) {
return {
backgroundColor: wellknown.credentials_supported[0].display[0]
?.background_color
? wellknown.credentials_supported[0].display[0].background_color
: Theme.Colors.textValue,
};
}
return wellknown?.display[0]?.background_color ?? Theme.Colors.textValue;
};
export const getTextColor = (wellknown: any, defaultColor: string) => {
return (
wellknown?.credentials_supported[0]?.display[0]?.text_color ?? defaultColor
);
return wellknown?.display[0]?.text_color ?? defaultColor;
};
export function getAddressFields() {
@@ -174,26 +130,14 @@ function getFullAddress(credential: CredentialSubject) {
.join(', ');
}
function formattedDateTime(timeStamp: any) {
if (timeStamp) {
const options = {year: 'numeric', month: '2-digit', day: '2-digit'};
return new Date(timeStamp).toLocaleDateString('en-US', options);
}
return timeStamp;
}
export const fieldItemIterator = (
fields: any[],
verifiableCredential: any,
verifiableCredential: VerifiableCredential | Credential,
wellknown: any,
props: any,
props: VCItemDetailsProps,
) => {
return fields.map(field => {
const fieldName = getFieldName(
field,
wellknown,
props.verifiableCredentialData.vcCredentialTypes,
);
const fieldName = getFieldName(field, wellknown);
const fieldValue = getFieldValue(
verifiableCredential,
field,
@@ -225,7 +169,10 @@ export const fieldItemIterator = (
});
};
export const isVCLoaded = (verifiableCredential: any, fields: string[]) => {
export const isVCLoaded = (
verifiableCredential: Credential,
fields: string[],
) => {
return verifiableCredential != null && fields.length > 0;
};
@@ -235,3 +182,50 @@ export const getMosipLogo = () => {
alt_text: 'a square logo of mosip',
};
};
/**
*
* @param wellknown (either supportedCredential's wellknown or whole well known response of issuer)
* @param idType
* @returns id Type translations (Eg - National ID)
*
* supportedCredential's wellknown is passed from getActivityText after fresh download
* & all other consumers pass whole well known response of issuer
*/
export const getIdType = (
wellknown: CredentialTypes | IssuerWellknownResponse,
idType?: string[],
) => {
if (wellknown && wellknown?.display) {
const idTypeObj = wellknown.display.map((displayProps: any) => {
return {language: displayProps.locale, value: displayProps.name};
});
return getLocalizedField(idTypeObj);
} else if (
wellknown &&
Object.keys(wellknown).length > 0 &&
idType !== undefined
) {
let supportedCredentialsWellknown;
wellknown = JSON.parse(wellknown) as Object[];
if (!!!wellknown['credentials_supported']) {
return i18n.t('VcDetails:nationalCard');
}
supportedCredentialsWellknown = getSelectedCredentialTypeDetails(
wellknown,
idType,
);
if (Object.keys(supportedCredentialsWellknown).length === 0) {
return i18n.t('VcDetails:nationalCard');
}
return getIdType(supportedCredentialsWellknown);
} else {
return i18n.t('VcDetails:nationalCard');
}
};
export const getCredentialTypes = (
credential: Credential | VerifiableCredential,
): string[] => {
return (credential?.credentialTypes as string[]) ?? ['VerifiableCredential'];
};

View File

@@ -19,64 +19,65 @@ export const Modal: React.FC<ModalProps> = props => {
visible={props.isVisible}
onShow={props.onShow}
onRequestClose={props.onDismiss}>
<Column {...(props.showHeader ? { fill: true, safe: true } : { fill: true })}>
{ props.showHeader ? (
<Row elevation={props.headerElevation}>
<View style={props.modalStyle}>
{props.headerRight && !props.arrowLeft ? (
<Icon
{...testIDProps('closeModal')}
name={I18nManager.isRTL ? 'chevron-right' : 'chevron-left'}
onPress={props.onDismiss}
color={Theme.Colors.Icon}
/>
) : null}
{props.arrowLeft && props.onDismiss ? (
<BackButton onPress={props.onDismiss} />
) : null}
<Row
fill
align={props.headerLeft ? 'flex-start' : 'center'}
margin={props.arrowLeft ? '16 0 0 -15' : '16 0 0 10'}>
<Column>
<Text testID={props.testID} style={Theme.TextStyles.header}>
{props.headerTitle || props.headerLeft}
</Text>
{!props.requester ? (
<Text
weight="semibold"
style={Theme.TextStyles.small}
color={
props.headerLabelColor
? props.headerLabelColor
: Theme.Colors.textLabel
}>
{props.headerLabel}
</Text>
) : (
<Text
weight="semibold"
style={Theme.TextStyles.small}
color={Theme.Colors.IconBg}>
<DeviceInfoList deviceInfo={controller.receiverInfo} />
</Text>
)}
</Column>
</Row>
{props.headerRight != null ||
props.arrowLeft ||
(props.showClose && (
<Column {...(props.showHeader ? {fill: true, safe: true} : {fill: true})}>
{props.showHeader ? (
<Row elevation={props.headerElevation}>
<View style={props.modalStyle}>
{props.headerRight && !props.arrowLeft ? (
<Icon
{...testIDProps('close')}
name="close"
{...testIDProps('closeModal')}
name={I18nManager.isRTL ? 'chevron-right' : 'chevron-left'}
onPress={props.onDismiss}
color={Theme.Colors.Details}
size={27}
color={Theme.Colors.Icon}
/>
))}
{props.headerRight && props.headerRight}
</View>
</Row> ) : null}
) : null}
{props.arrowLeft && props.onDismiss ? (
<BackButton onPress={props.onDismiss} />
) : null}
<Row
fill
align={props.headerLeft ? 'flex-start' : 'center'}
margin={props.arrowLeft ? '16 0 0 -15' : '16 0 0 10'}>
<Column>
<Text testID={props.testID} style={Theme.TextStyles.header}>
{props.headerTitle || props.headerLeft}
</Text>
{!props.requester ? (
<Text
weight="semibold"
style={Theme.TextStyles.small}
color={
props.headerLabelColor
? props.headerLabelColor
: Theme.Colors.textLabel
}>
{props.headerLabel}
</Text>
) : (
<Text
weight="semibold"
style={Theme.TextStyles.small}
color={Theme.Colors.IconBg}>
<DeviceInfoList deviceInfo={controller.receiverInfo} />
</Text>
)}
</Column>
</Row>
{props.headerRight != null ||
props.arrowLeft ||
(props.showClose && (
<Icon
{...testIDProps('close')}
name="close"
onPress={props.onDismiss}
color={Theme.Colors.Details}
size={27}
/>
))}
{props.headerRight && props.headerRight}
</View>
</Row>
) : null}
{props.children}
</Column>
</RNModal>

View File

@@ -21,7 +21,7 @@ import ReceiveCard from '../../assets/Receive_Card.svg';
import ReceivedCards from '../../assets/Received_Cards.svg';
import ProgressIcon from '../../assets/Progress_Icon1.svg';
import testIDProps from '../../shared/commonUtil';
import Logo from '../../assets/Inji_Logo';
import Logo from '../../assets/Inji_Logo.svg';
import WarningLogo from '../../assets/Warning_Icon.svg';
import OtpVerificationIcon from '../../assets/Otp_Verification_Icon.svg';
import FlipCameraIcon from '../../assets/Flip_Camera_Icon.svg';

View File

@@ -1549,8 +1549,8 @@ export const DefaultTheme = {
},
scannerContainer: {
borderRadius: 24,
height: 320,
width: 300,
height: 350,
width: 320,
marginTop: 40,
backgroundColor: Colors.White,
borderWidth: 1,
@@ -1559,12 +1559,11 @@ export const DefaultTheme = {
}),
CameraEnabledStyles: StyleSheet.create({
container: {marginTop: 20, marginBottom: 20},
scannerContainer: {
borderRadius: 24,
alignSelf: 'center',
height: 320,
width: 300,
height: 350,
width: 320,
overflow: 'hidden',
},
scanner: {

View File

@@ -1549,8 +1549,8 @@ export const PurpleTheme = {
},
scannerContainer: {
borderRadius: 24,
height: 320,
width: 300,
height: 350,
width: 320,
marginTop: 40,
backgroundColor: Colors.White,
borderWidth: 1,
@@ -1558,12 +1558,11 @@ export const PurpleTheme = {
},
}),
CameraEnabledStyles: StyleSheet.create({
container: {marginTop: 20, marginBottom: 20},
scannerContainer: {
borderRadius: 24,
alignSelf: 'center',
height: 320,
width: 300,
height: 350,
width: 320,
overflow: 'hidden',
},
scanner: {

View File

@@ -1,9 +1,4 @@
import {
ErrorMessage,
getIdType,
Issuers_Key_Ref,
updateVCmetadataOfCredentialWrapper,
} from '../../shared/openId4VCI/Utils';
import {ErrorMessage, Issuers_Key_Ref} from '../../shared/openId4VCI/Utils';
import {
MY_VCS_STORE_KEY,
NETWORK_REQUEST_FAILED,
@@ -61,12 +56,12 @@ export const IssuersActions = (model: any) => {
setSelectedCredentialType: model.assign({
selectedCredentialType: (_: any, event: any) => event.credType,
}),
setSupportedCredentialTypes: model.assign({
supportedCredentialTypes: (_: any, event: any) => event.data,
}),
resetSelectedCredentialType: model.assign({
selectedCredentialType: {},
}),
setCredentialTypes: model.assign({
credentialTypes: (_: any, event: any) => event.data.supportedCredentials,
}),
setError: model.assign({
errorMessage: (_: any, event: any) => {
console.error('Error occurred ', event.data.message);
@@ -119,10 +114,10 @@ export const IssuersActions = (model: any) => {
),
setMetadataInCredentialData: (context: any) => {
return updateVCmetadataOfCredentialWrapper(
context,
context.credentialWrapper,
);
context.credentialWrapper = {
...context.credentialWrapper,
vcMetadata: context.vcMetadata,
};
},
setVCMetadata: assign({
@@ -132,11 +127,13 @@ export const IssuersActions = (model: any) => {
}),
storeVerifiableCredentialData: send(
(context: any) =>
StoreEvents.SET(getVCMetadata(context).getVcKey(), {
(context: any) => {
const vcMeatadata = getVCMetadata(context);
return StoreEvents.SET(vcMeatadata.getVcKey(), {
...context.credentialWrapper,
vcMetadata: getVCMetadata(context),
}),
vcMetadata: vcMeatadata,
});
},
{
to: (context: any) => context.serviceRefs.store,
},
@@ -201,15 +198,21 @@ export const IssuersActions = (model: any) => {
logDownloaded: send(
context => {
return ActivityLogEvents.LOG_ACTIVITY({
_vcKey: getVCMetadata(context).getVcKey(),
type: 'VC_DOWNLOADED',
id: getVCMetadata(context).id,
idType: getIdType(getVCMetadata(context).issuer),
timestamp: Date.now(),
deviceName: '',
vcLabel: getVCMetadata(context).id,
});
const vcMetadata = getVCMetadata(context);
return ActivityLogEvents.LOG_ACTIVITY(
{
_vcKey: vcMetadata.getVcKey(),
type: 'VC_DOWNLOADED',
id: vcMetadata.id,
idType:
context.credentialWrapper.verifiableCredential.credentialTypes,
timestamp: Date.now(),
deviceName: '',
vcLabel: vcMetadata.id,
issuer: context.selectedIssuerId,
},
context.selectedCredentialType,
);
},
{
to: (context: any) => context.serviceRefs.activityLog,

View File

@@ -1,8 +1,8 @@
import {isSignedInResult} from '../../shared/CloudBackupAndRestoreUtils';
import {ErrorMessage, Issuers, OIDCErrors} from '../../shared/openId4VCI/Utils';
import {ErrorMessage, OIDCErrors} from '../../shared/openId4VCI/Utils';
import {isHardwareKeystoreExists} from '../../shared/cryptoutil/cryptoUtil';
import {BiometricCancellationError} from '../../shared/error/BiometricCancellationError';
import {NETWORK_REQUEST_FAILED, REQUEST_TIMEOUT} from '../../shared/constants';
import {NETWORK_REQUEST_FAILED} from '../../shared/constants';
import {VerificationErrorType} from '../../shared/vcjs/verifyCredential';
export const IssuersGuards = () => {
@@ -12,9 +12,6 @@ export const IssuersGuards = () => {
isSignedIn: (_: any, event: any) =>
(event.data as isSignedInResult).isSignedIn,
hasKeyPair: (context: any) => !!context.publicKey,
isMultipleCredentialsSupported: (context: any, event: any) =>
event.data.supportedCredentials.length > 1 &&
context.selectedIssuer.credential_issuer === Issuers.Sunbird,
isInternetConnected: (_: any, event: any) => !!event.data.isConnected,
isOIDCflowCancelled: (_: any, event: any) => {
// iOS & Android have different error strings for user cancelled flow

View File

@@ -1,9 +1,9 @@
import {EventFrom, send, sendParent} from 'xstate';
import {log} from 'xstate/lib/actions';
import {IssuersModel} from './IssuersModel';
import {IssuersActions} from './IssuersActions';
import {IssuersService} from './IssuersService';
import {IssuersGuards} from './IssuersGuards';
import {CredentialTypes} from '../VerifiableCredential/VCMetaMachine/vc';
const model = IssuersModel;
@@ -106,8 +106,7 @@ export const IssuersMachine = model.createMachine(
src: 'downloadCredentialTypes',
onDone: [
{
actions: 'setCredentialTypes',
cond: 'isMultipleCredentialsSupported',
actions: 'setSupportedCredentialTypes',
target: 'selectingCredentialType',
},
{
@@ -126,10 +125,7 @@ export const IssuersMachine = model.createMachine(
target: 'displayIssuers',
},
SELECTED_CREDENTIAL_TYPE: {
actions: [
(_, event) => console.log('>>>>> event', event),
'setSelectedCredentialType',
],
actions: 'setSelectedCredentialType',
target: 'checkInternet',
},
},
@@ -413,9 +409,11 @@ export interface logoType {
export interface displayType {
name: string;
logo: logoType;
language: string;
locale: string;
language: string;
logo: logoType;
background_color: string;
text_color: string;
title: string;
description: string;
}
@@ -426,14 +424,12 @@ export interface issuerType {
client_id: string;
'.well-known': string;
redirect_uri: string;
scopes_supported: [string];
additional_headers: object;
authorization_endpoint: string;
authorization_alias: string;
token_endpoint: string;
proxy_token_endpoint: string;
credential_endpoint: string;
credential_type: [string];
credential_audience: string;
display: [displayType];
credentialTypes: [CredentialTypes];
}

View File

@@ -104,7 +104,6 @@ export interface Typegen0 {
| 'sendErrorEndEvent'
| 'sendImpressionEvent'
| 'sendSuccessEndEvent'
| 'setCredentialTypes'
| 'setCredentialWrapper'
| 'setError'
| 'setIsVerified'
@@ -120,6 +119,7 @@ export interface Typegen0 {
| 'setSelectedCredentialType'
| 'setSelectedIssuerId'
| 'setSelectedIssuers'
| 'setSupportedCredentialTypes'
| 'setTokenResponse'
| 'setVCMetadata'
| 'setVerifiableCredential'
@@ -137,7 +137,6 @@ export interface Typegen0 {
| 'isCustomSecureKeystore'
| 'isGenericError'
| 'isInternetConnected'
| 'isMultipleCredentialsSupported'
| 'isOIDCConfigError'
| 'isOIDCflowCancelled'
| 'isSignedIn'
@@ -186,7 +185,6 @@ export interface Typegen0 {
sendErrorEndEvent: 'error.platform.issuersMachine.verifyingCredential:invocation[0]';
sendImpressionEvent: 'done.invoke.issuersMachine.displayIssuers:invocation[0]';
sendSuccessEndEvent: 'done.invoke.issuersMachine.verifyingCredential:invocation[0]';
setCredentialTypes: 'done.invoke.issuersMachine.downloadCredentialTypes:invocation[0]';
setCredentialWrapper: 'done.invoke.issuersMachine.downloadCredentials:invocation[0]';
setError:
| 'error.platform.issuersMachine.displayIssuers:invocation[0]'
@@ -216,6 +214,7 @@ export interface Typegen0 {
setSelectedCredentialType: 'SELECTED_CREDENTIAL_TYPE';
setSelectedIssuerId: 'SELECTED_ISSUER';
setSelectedIssuers: 'done.invoke.issuersMachine.downloadIssuerConfig:invocation[0]';
setSupportedCredentialTypes: 'done.invoke.issuersMachine.downloadCredentialTypes:invocation[0]';
setTokenResponse: 'done.invoke.issuersMachine.performAuthorization:invocation[0]';
setVCMetadata:
| 'done.invoke.issuersMachine.verifyingCredential:invocation[0]'
@@ -244,7 +243,6 @@ export interface Typegen0 {
isCustomSecureKeystore: 'done.invoke.issuersMachine.generateKeyPair:invocation[0]';
isGenericError: 'error.platform.issuersMachine.downloadCredentials:invocation[0]';
isInternetConnected: 'done.invoke.checkInternet';
isMultipleCredentialsSupported: 'done.invoke.issuersMachine.downloadCredentialTypes:invocation[0]';
isOIDCConfigError: 'error.platform.issuersMachine.performAuthorization:invocation[0]';
isOIDCflowCancelled: 'error.platform.issuersMachine.performAuthorization:invocation[0]';
isSignedIn: 'done.invoke.issuersMachine.storing:invocation[0]';

View File

@@ -20,7 +20,7 @@ export const IssuersModel = createModel(
loadingReason: 'displayIssuers' as string,
verifiableCredential: null as VerifiableCredential | null,
selectedCredentialType: {} as CredentialTypes,
credentialTypes: [] as CredentialTypes[],
supportedCredentialTypes: [] as CredentialTypes[],
credentialWrapper: {} as CredentialWrapper,
serviceRefs: {} as AppServices,
verificationErrorMessage: '',

View File

@@ -54,6 +54,6 @@ export function selectSelectingCredentialType(state: State) {
return state.matches('selectingCredentialType');
}
export function selectCredentialTypes(state: State) {
return state.context.credentialTypes;
export function selectSupportedCredentialTypes(state: State) {
return state.context.supportedCredentialTypes;
}

View File

@@ -1,12 +1,9 @@
import Cloud from '../../shared/CloudBackupAndRestoreUtils';
import {API_URLS, CACHED_API} from '../../shared/api';
import {CACHED_API} from '../../shared/api';
import NetInfo from '@react-native-community/netinfo';
import {request} from '../../shared/request';
import {
constructAuthorizationConfiguration,
constructProofJWT,
getCredentialType,
Issuers,
Issuers_Key_Ref,
updateCredentialInformation,
vcDownloadTimeout,
@@ -17,7 +14,6 @@ import {
isHardwareKeystoreExists,
} from '../../shared/cryptoutil/cryptoUtil';
import {NativeModules} from 'react-native';
import {getVCMetadata, VCMetadata} from '../../shared/VCMetadata';
import {
VerificationErrorType,
verifyCredential,
@@ -27,6 +23,7 @@ import {
sendImpressionEvent,
} from '../../shared/telemetry/TelemetryUtils';
import {TelemetryConstants} from '../../shared/telemetry/TelemetryConstants';
import {isMosipVC} from '../../shared/Utils';
import {VciClient} from '../../shared/vciClient/VciClient';
const {RNSecureKeystoreModule} = NativeModules;
@@ -43,20 +40,18 @@ export const IssuersService = () => {
let issuersConfig = await CACHED_API.fetchIssuerConfig(
context.selectedIssuerId,
);
if (context.selectedIssuer['.well-known']) {
await CACHED_API.fetchIssuerWellknownConfig(
context.selectedIssuerId,
context.selectedIssuer['.well-known'],
);
}
const wellknownResponse = await CACHED_API.fetchIssuerWellknownConfig(
context.selectedIssuerId,
issuersConfig['.well-known'],
);
issuersConfig.credential_endpoint =
wellknownResponse?.credential_endpoint;
issuersConfig.credential_audience = wellknownResponse?.credential_issuer;
issuersConfig.credentialTypes = wellknownResponse?.credentials_supported;
return issuersConfig;
},
downloadCredentialTypes: async (context: any) => {
const response = await request(
API_URLS.credentialTypes.method,
API_URLS.credentialTypes.buildURL(context.selectedIssuerId),
);
return response?.response;
return context.selectedIssuer.credentialTypes;
},
downloadCredential: async (context: any) => {
const downloadTimeout = await vcDownloadTimeout();
@@ -65,7 +60,8 @@ export const IssuersService = () => {
credentialAudience: context.selectedIssuer.credential_audience,
credentialEndpoint: context.selectedIssuer.credential_endpoint,
downloadTimeoutInMilliSeconds: downloadTimeout,
credentialType: getCredentialType(context),
credentialType: context.selectedCredentialType?.credential_definition
.type ?? ['VerifiableCredential'],
credentialFormat: 'ldp_vc',
};
const proofJWT = await constructProofJWT(
@@ -81,8 +77,7 @@ export const IssuersService = () => {
);
console.info(`VC download via ${context.selectedIssuerId} is successful`);
credential = updateCredentialInformation(context, credential);
return credential;
return updateCredentialInformation(context, credential);
},
invokeAuthorization: async (context: any) => {
sendImpressionEvent(
@@ -92,16 +87,10 @@ export const IssuersService = () => {
TelemetryConstants.Screens.webViewPage,
),
);
let supportedScopes: [string];
if (Object.keys(context.selectedCredentialType).length === 0) {
supportedScopes = context.selectedIssuer.scopes_supported;
} else {
supportedScopes = [context.selectedCredentialType['scope']];
}
return await authorize(
constructAuthorizationConfiguration(
context.selectedIssuer,
supportedScopes,
context.selectedCredentialType.scope,
),
);
},
@@ -118,21 +107,19 @@ export const IssuersService = () => {
},
verifyCredential: async (context: any) => {
//this issuer specific check has to be removed once vc validation is done.
if (
VCMetadata.fromVcMetadataString(getVCMetadata(context)).issuer ===
Issuers.Sunbird
) {
if (isMosipVC(context.vcMetadata.issuer)) {
const verificationResult = await verifyCredential(
context.verifiableCredential?.credential,
);
if (!verificationResult.isVerified) {
throw new Error(verificationResult.errorMessage);
}
} else {
return {
isVerified: true,
errorMessage: VerificationErrorType.NO_ERROR,
};
}
const verificationResult = await verifyCredential(
context.verifiableCredential?.credential,
);
if (!verificationResult.isVerified) {
throw new Error(verificationResult.errorMessage);
}
},
};
};

View File

@@ -2,6 +2,7 @@ import {StateFrom} from 'xstate';
import {getMosipLogo} from '../../components/VC/common/VCUtils';
import {VCMetadata} from '../../shared/VCMetadata';
import {qrLoginMachine} from './QrLoginMachine';
import {Credential} from '../VerifiableCredential/VCMetaMachine/vc';
type State = StateFrom<typeof qrLoginMachine>;
@@ -57,31 +58,29 @@ export function selectIsVerifyingSuccesful(state: State) {
return state.matches('success');
}
export function selectCredential(state: State) {
return new VCMetadata(state.context.selectedVc?.vcMetadata).isFromOpenId4VCI()
? state.context.selectedVc?.verifiableCredential?.credential
: state.context.selectedVc?.credential;
export function selectCredential(state: State): Credential {
return (
state.context.selectedVc?.verifiableCredential?.credential ||
state.context.selectedVc?.credential
);
}
export function selectVerifiableCredentialData(state: State) {
const vcMetadata = new VCMetadata(state.context.selectedVc?.vcMetadata);
return vcMetadata.isFromOpenId4VCI()
? {
vcMetadata: vcMetadata,
face: state.context.selectedVc?.verifiableCredential?.credential
?.credentialSubject?.face,
issuerLogo: state.context.selectedVc?.verifiableCredential?.issuerLogo,
wellKnown: state.context.selectedVc?.verifiableCredential?.wellKnown,
credentialTypes:
state.context.selectedVc?.verifiableCredential?.credentialTypes,
issuer: vcMetadata.issuer,
}
: {
vcMetadata: vcMetadata,
issuer: vcMetadata.issuer,
face: state.context.selectedVc?.credential?.biometrics?.face,
issuerLogo: getMosipLogo(),
};
return {
vcMetadata: vcMetadata,
issuer: vcMetadata.issuer,
issuerLogo:
state.context.selectedVc?.verifiableCredential?.issuerLogo ||
getMosipLogo(),
face:
state.context.selectedVc?.verifiableCredential?.credential
?.credentialSubject?.face ||
state.context.selectedVc?.credential?.biometrics?.face,
wellKnown: state.context.selectedVc?.verifiableCredential?.wellKnown,
credentialTypes:
state.context.selectedVc?.verifiableCredential?.credentialTypes,
};
}
export function selectLinkTransactionResponse(state: State) {

View File

@@ -2,17 +2,18 @@ import {assign, send} from 'xstate';
import {CommunicationDetails} from '../../../shared/Utils';
import {StoreEvents} from '../../store';
import {VCMetadata} from '../../../shared/VCMetadata';
import {MIMOTO_BASE_URL, MY_VCS_STORE_KEY} from '../../../shared/constants';
import {
API_CACHED_STORAGE_KEYS,
MIMOTO_BASE_URL,
MY_VCS_STORE_KEY,
} from '../../../shared/constants';
import {KeyPair} from 'react-native-rsa-native';
import i18n from '../../../i18n';
import {getHomeMachineService} from '../../../screens/Home/HomeScreenController';
import {DownloadProps} from '../../../shared/api';
import {isHardwareKeystoreExists} from '../../../shared/cryptoutil/cryptoUtil';
import {getBindingCertificateConstant} from '../../../shared/keystore/SecureKeystore';
import {
getIdType,
getVcVerificationDetails,
} from '../../../shared/openId4VCI/Utils';
import {getVcVerificationDetails} from '../../../shared/openId4VCI/Utils';
import {TelemetryConstants} from '../../../shared/telemetry/TelemetryConstants';
import {
sendStartEvent,
@@ -30,6 +31,7 @@ import {BackupEvents} from '../../backupAndRestore/backup';
import {VcMetaEvents} from '../VCMetaMachine/VCMetaMachine';
import {WalletBindingResponse} from '../VCMetaMachine/vc';
import {BannerStatusType} from '../../../components/BannerNotification';
import {getCredentialTypes} from '../../../components/VC/common/VCUtils';
export const VCItemActions = model => {
return {
@@ -61,6 +63,7 @@ export const VCItemActions = model => {
statusType,
context.vcMetadata,
context.verifiableCredential,
context.wellknownResponse,
);
},
}),
@@ -124,10 +127,11 @@ export const VCItemActions = model => {
),
setContext: model.assign((context, event) => {
const vcMetadata = context.vcMetadata;
return {
...context,
...event.response,
vcMetadata: context.vcMetadata,
vcMetadata: VCMetadata.fromVC(vcMetadata),
};
}),
storeContext: send(
@@ -149,16 +153,22 @@ export const VCItemActions = model => {
to: context => context.serviceRefs.store,
},
),
setVcMetadata: assign({
vcMetadata: (_, event) => event.vcMetadata,
}),
updateWellknownResponse: assign({
wellknownResponse: (_, event) => event.data,
}),
storeVcInContext: send(
//todo : separate handling done for openid4vci , handle commonly from vc machine
(context: any) => {
const {serviceRefs, ...verifiableCredential} = context;
const {serviceRefs, wellknownResponse, ...data} = context;
return {
type: 'VC_DOWNLOADED',
vc: verifiableCredential,
vc: data,
vcMetadata: context.vcMetadata,
};
},
@@ -442,7 +452,8 @@ export const VCItemActions = model => {
_vcKey: context.vcMetadata.getVcKey(),
type: 'VC_DOWNLOADED',
id: context.vcMetadata.id,
idType: getIdType(context.vcMetadata.issuer),
issuer: context.vcMetadata.issuer!!,
idType: getCredentialTypes(context.verifiableCredential),
timestamp: Date.now(),
deviceName: '',
vcLabel: data.id,
@@ -453,47 +464,56 @@ export const VCItemActions = model => {
},
),
logRemovedVc: send(
(context: any, _) =>
ActivityLogEvents.LOG_ACTIVITY({
idType: getIdType(context.vcMetadata.issuer),
id: context.vcMetadata.id,
_vcKey: VCMetadata.fromVC(context.vcMetadata).getVcKey(),
(context: any, _) => {
const vcMetadata = VCMetadata.fromVC(context.vcMetadata);
return ActivityLogEvents.LOG_ACTIVITY({
idType: getCredentialTypes(context.verifiableCredential),
issuer: vcMetadata.issuer!!,
id: vcMetadata.id,
_vcKey: vcMetadata.getVcKey(),
type: 'VC_REMOVED',
timestamp: Date.now(),
deviceName: '',
vcLabel: VCMetadata.fromVC(context.vcMetadata).id,
}),
vcLabel: vcMetadata.id,
});
},
{
to: context => context.serviceRefs.activityLog,
},
),
logWalletBindingSuccess: send(
(context: any) =>
ActivityLogEvents.LOG_ACTIVITY({
_vcKey: VCMetadata.fromVC(context.vcMetadata).getVcKey(),
(context: any) => {
const vcMetadata = VCMetadata.fromVC(context.vcMetadata);
return ActivityLogEvents.LOG_ACTIVITY({
_vcKey: vcMetadata.getVcKey(),
type: 'WALLET_BINDING_SUCCESSFULL',
idType: getIdType(context.vcMetadata.issuer),
id: context.vcMetadata.id,
idType: getCredentialTypes(context.verifiableCredential),
issuer: vcMetadata.issuer!!,
id: vcMetadata.id,
timestamp: Date.now(),
deviceName: '',
vcLabel: VCMetadata.fromVC(context.vcMetadata).id,
}),
vcLabel: vcMetadata.id,
});
},
{
to: context => context.serviceRefs.activityLog,
},
),
logWalletBindingFailure: send(
(context: any) =>
ActivityLogEvents.LOG_ACTIVITY({
_vcKey: VCMetadata.fromVC(context.vcMetadata).getVcKey(),
(context: any) => {
const vcMetadata = VCMetadata.fromVC(context.vcMetadata);
return ActivityLogEvents.LOG_ACTIVITY({
_vcKey: vcMetadata.getVcKey(),
type: 'WALLET_BINDING_FAILURE',
id: context.vcMetadata.id,
idType: getIdType(context.vcMetadata.issuer),
id: vcMetadata.id,
idType: getCredentialTypes(context.verifiableCredential),
issuer: vcMetadata.issuer!!,
timestamp: Date.now(),
deviceName: '',
vcLabel: VCMetadata.fromVC(context.vcMetadata).id,
}),
vcLabel: vcMetadata.id,
});
},
{
to: context => context.serviceRefs.activityLog,
},

View File

@@ -1,32 +0,0 @@
import {VCMetadata} from '../../../shared/VCMetadata';
import {VC} from '../VCMetaMachine/vc';
export const VCItemEvents = {
DISMISS: () => ({}),
CREDENTIAL_DOWNLOADED: (response: VC) => ({response}),
STORE_RESPONSE: (response: VC) => ({response}),
STORE_ERROR: (error: Error) => ({error}),
POLL: () => ({}),
DOWNLOAD_READY: () => ({}),
FAILED: () => ({}),
GET_VC_RESPONSE: (response: VC) => ({response}),
INPUT_OTP: (OTP: string) => ({OTP}),
RESEND_OTP: () => ({}),
REFRESH: () => ({}),
ADD_WALLET_BINDING_ID: () => ({}),
CANCEL: () => ({}),
CONFIRM: () => ({}),
PIN_CARD: () => ({}),
KEBAB_POPUP: () => ({}),
SHOW_ACTIVITY: () => ({}),
CLOSE_VC_MODAL: () => ({}),
REMOVE: (vcMetadata: VCMetadata) => ({vcMetadata}),
UPDATE_VC_METADATA: (vcMetadata: VCMetadata) => ({vcMetadata}),
TAMPERED_VC: (key: string) => ({key}),
SHOW_BINDING_STATUS: () => ({}),
VERIFY: () => ({}),
SET_VERIFICATION_STATUS: (response: unknown) => ({response}),
RESET_VERIFICATION_STATUS: () => ({}),
REMOVE_VERIFICATION_STATUS_BANNER: () => ({}),
SHOW_VERIFICATION_STATUS_BANNER: (response: unknown) => ({response}),
};

View File

@@ -4,9 +4,16 @@ import {VerificationErrorType} from '../../../shared/vcjs/verifyCredential';
export const VCItemGaurds = () => {
return {
hasCredentialAndWellknown: (context, event) => {
const vc = event.response;
return (
vc?.verifiableCredential != null &&
!!context.verifiableCredential?.wellKnown
);
},
hasCredential: (_, event) => {
const vc = event.response;
return vc?.credential != null || vc?.verifiableCredential != null;
return vc?.verifiableCredential != null;
},
isSignedIn: (_context, event) =>
(event.data as isSignedInResult).isSignedIn,

View File

@@ -44,6 +44,11 @@ export const VCItemMachine = model.createMachine(
description: 'Fetch the VC data from the Memory.',
on: {
GET_VC_RESPONSE: [
{
actions: ['setContext'],
cond: 'hasCredentialAndWellknown',
target: '.fetchWellknown',
},
{
actions: ['setContext'],
cond: 'hasCredential',
@@ -58,6 +63,20 @@ export const VCItemMachine = model.createMachine(
target: '#vc-item-machine.vcUtilitiesState.idle',
},
},
initial: 'idle',
states: {
idle: {},
fetchWellknown: {
invoke: {
src: 'fetchIssuerWellknown',
onDone: {
actions: 'updateWellknownResponse',
target: `#vc-item-machine.vcUtilitiesState.idle`,
},
},
},
},
},
loadVcFromServer: {
description:
@@ -492,10 +511,10 @@ export const VCItemMachine = model.createMachine(
{
cond: 'isSignedIn',
actions: ['sendBackupEvent'],
target: '#vc-item-machine.vcUtilitiesState.idle',
target: `#vc-item-machine.vcUtilitiesState.idle`,
},
{
target: '#vc-item-machine.vcUtilitiesState.idle',
target: `#vc-item-machine.vcUtilitiesState.idle`,
},
],
},

View File

@@ -19,6 +19,11 @@ export interface Typegen0 {
data: unknown;
__tip: 'See the XState TS docs to learn how to strongly type this.';
};
'done.invoke.vc-item-machine.vcUtilitiesState.loadVc.loadVcFromContext.fetchWellknown:invocation[0]': {
type: 'done.invoke.vc-item-machine.vcUtilitiesState.loadVc.loadVcFromContext.fetchWellknown:invocation[0]';
data: unknown;
__tip: 'See the XState TS docs to learn how to strongly type this.';
};
'done.invoke.vc-item-machine.vcUtilitiesState.loadVc.loadVcFromServer.loadDownloadLimitConfig:invocation[0]': {
type: 'done.invoke.vc-item-machine.vcUtilitiesState.loadVc.loadVcFromServer.loadDownloadLimitConfig:invocation[0]';
data: unknown;
@@ -120,6 +125,7 @@ export interface Typegen0 {
checkDownloadExpiryLimit: 'done.invoke.vc-item-machine.vcUtilitiesState.loadVc.loadVcFromServer.verifyingDownloadLimitExpiry:invocation[0]';
checkStatus: 'done.invoke.checkStatus';
downloadCredential: 'done.invoke.downloadCredential';
fetchIssuerWellknown: 'done.invoke.vc-item-machine.vcUtilitiesState.loadVc.loadVcFromContext.fetchWellknown:invocation[0]';
generateKeyPair: 'done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.addKeyPair:invocation[0]';
isUserSignedAlready:
| 'done.invoke.vc-item-machine.vcUtilitiesState.kebabPopUp.triggerAutoBackup:invocation[0]'
@@ -186,10 +192,12 @@ export interface Typegen0 {
| 'unSetBindingTransactionId'
| 'unSetError'
| 'unSetOTP'
| 'updateVcMetadata';
| 'updateVcMetadata'
| 'updateWellknownResponse';
delays: never;
guards:
| 'hasCredential'
| 'hasCredentialAndWellknown'
| 'isCustomSecureKeystore'
| 'isDownloadAllowed'
| 'isSignedIn'
@@ -199,6 +207,7 @@ export interface Typegen0 {
| 'checkDownloadExpiryLimit'
| 'checkStatus'
| 'downloadCredential'
| 'fetchIssuerWellknown'
| 'generateKeyPair'
| 'isUserSignedAlready'
| 'loadDownloadLimitConfig'
@@ -334,10 +343,12 @@ export interface Typegen0 {
| 'DISMISS'
| 'done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.requestingBindingOTP:invocation[0]';
updateVcMetadata: 'PIN_CARD' | 'STORE_RESPONSE';
updateWellknownResponse: 'done.invoke.vc-item-machine.vcUtilitiesState.loadVc.loadVcFromContext.fetchWellknown:invocation[0]';
};
eventsCausingDelays: {};
eventsCausingGuards: {
hasCredential: 'GET_VC_RESPONSE';
hasCredentialAndWellknown: 'GET_VC_RESPONSE';
isCustomSecureKeystore:
| 'done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.addKeyPair:invocation[0]'
| 'done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.addingWalletBindingId:invocation[0]';
@@ -356,6 +367,7 @@ export interface Typegen0 {
| 'done.invoke.vc-item-machine.vcUtilitiesState.loadVc.loadVcFromServer.loadDownloadLimitConfig:invocation[0]';
checkStatus: 'done.invoke.vc-item-machine.vcUtilitiesState.loadVc.loadVcFromServer.verifyingDownloadLimitExpiry:invocation[0]';
downloadCredential: 'DOWNLOAD_READY';
fetchIssuerWellknown: 'GET_VC_RESPONSE';
generateKeyPair: 'INPUT_OTP';
isUserSignedAlready: 'STORE_RESPONSE';
loadDownloadLimitConfig: 'GET_VC_RESPONSE' | 'STORE_ERROR';
@@ -375,6 +387,8 @@ export interface Typegen0 {
| 'vcUtilitiesState.kebabPopUp.triggerAutoBackup'
| 'vcUtilitiesState.loadVc'
| 'vcUtilitiesState.loadVc.loadVcFromContext'
| 'vcUtilitiesState.loadVc.loadVcFromContext.fetchWellknown'
| 'vcUtilitiesState.loadVc.loadVcFromContext.idle'
| 'vcUtilitiesState.loadVc.loadVcFromServer'
| 'vcUtilitiesState.loadVc.loadVcFromServer.checkingStatus'
| 'vcUtilitiesState.loadVc.loadVcFromServer.downloadingCredential'
@@ -421,6 +435,7 @@ export interface Typegen0 {
| 'loadVcFromContext'
| 'loadVcFromServer'
| {
loadVcFromContext?: 'fetchWellknown' | 'idle';
loadVcFromServer?:
| 'checkingStatus'
| 'downloadingCredential'

View File

@@ -1,17 +1,52 @@
import {createModel} from 'xstate/lib/model';
import {AppServices} from '../../../shared/GlobalContext';
import {VCMetadata} from '../../../shared/VCMetadata';
import {VerifiableCredential, WalletBindingResponse} from '../VCMetaMachine/vc';
import {
Credential,
DecodedCredential,
VC,
WalletBindingResponse,
} from '../VCMetaMachine/vc';
import {CommunicationDetails} from '../../../shared/Utils';
import {VCItemEvents} from './VCItemEvents';
import {vcVerificationBannerDetails} from '../../../components/BannerNotificationContainer';
const VCItemEvents = {
DISMISS: () => ({}),
CREDENTIAL_DOWNLOADED: (response: VC) => ({response}),
STORE_RESPONSE: (response: VC) => ({response}),
STORE_ERROR: (error: Error) => ({error}),
POLL: () => ({}),
DOWNLOAD_READY: () => ({}),
FAILED: () => ({}),
GET_VC_RESPONSE: (response: VC) => ({response}),
INPUT_OTP: (OTP: string) => ({OTP}),
RESEND_OTP: () => ({}),
REFRESH: () => ({}),
ADD_WALLET_BINDING_ID: () => ({}),
CANCEL: () => ({}),
CONFIRM: () => ({}),
PIN_CARD: () => ({}),
KEBAB_POPUP: () => ({}),
SHOW_ACTIVITY: () => ({}),
CLOSE_VC_MODAL: () => ({}),
REMOVE: (vcMetadata: VCMetadata) => ({vcMetadata}),
UPDATE_VC_METADATA: (vcMetadata: VCMetadata) => ({vcMetadata}),
TAMPERED_VC: (key: string) => ({key}),
SHOW_BINDING_STATUS: () => ({}),
VERIFY: () => ({}),
SET_VERIFICATION_STATUS: (response: unknown) => ({response}),
RESET_VERIFICATION_STATUS: () => ({}),
REMOVE_VERIFICATION_STATUS_BANNER: () => ({}),
SHOW_VERIFICATION_STATUS_BANNER: (response: unknown) => ({response}),
};
export const VCItemModel = createModel(
{
serviceRefs: {} as AppServices,
vcMetadata: {} as VCMetadata,
generatedOn: new Date() as Date,
verifiableCredential: null as unknown as VerifiableCredential,
credential: null as unknown as DecodedCredential,
verifiableCredential: null as unknown as Credential,
hashedId: '',
publicKey: '',
privateKey: '',
@@ -27,6 +62,7 @@ export const VCItemModel = createModel(
communicationDetails: null as unknown as CommunicationDetails,
verificationStatus: null as vcVerificationBannerDetails | null,
showVerificationStatusBanner: false as boolean,
wellknownResponse: {} as Object,
},
{
events: VCItemEvents,

View File

@@ -2,6 +2,11 @@ import {StateFrom} from 'xstate';
import {VCMetadata} from '../../../shared/VCMetadata';
import {VCItemMachine} from './VCItemMachine';
import {getMosipLogo} from '../../../components/VC/common/VCUtils';
import {
Credential,
VerifiableCredential,
VerifiableCredentialData,
} from '../VCMetaMachine/vc';
type State = StateFrom<typeof VCItemMachine>;
@@ -26,39 +31,31 @@ export function selectVerifiableCredential(state: State) {
}
export function getVerifiableCredential(
vcMetadata: VCMetadata,
verifiableCredential,
) {
return VCMetadata.fromVC(vcMetadata).isFromOpenId4VCI()
? verifiableCredential?.credential
: verifiableCredential;
verifiableCredential: VerifiableCredential | Credential,
): Credential {
return verifiableCredential?.credential || verifiableCredential;
}
export function selectCredential(state: State) {
return getVerifiableCredential(
state.context.vcMetadata,
state.context.verifiableCredential,
);
export function selectCredential(state: State): Credential {
return getVerifiableCredential(state.context.verifiableCredential);
}
export function selectVerifiableCredentialData(state: State) {
export function selectVerifiableCredentialData(
state: State,
): VerifiableCredentialData {
const vcMetadata = new VCMetadata(state.context.vcMetadata);
return vcMetadata.isFromOpenId4VCI()
? {
vcMetadata: vcMetadata,
face: state.context.verifiableCredential?.credential?.credentialSubject
.face,
issuerLogo: state.context.verifiableCredential?.issuerLogo,
wellKnown: state.context.verifiableCredential?.wellKnown,
credentialTypes: state.context.verifiableCredential?.credentialTypes,
issuer: vcMetadata.issuer,
}
: {
vcMetadata: vcMetadata,
issuer: vcMetadata.issuer,
face: state.context.credential?.biometrics?.face,
issuerLogo: getMosipLogo(),
};
return {
vcMetadata: vcMetadata,
face:
state.context.verifiableCredential?.credential?.credentialSubject?.face ??
state.context.credential?.biometrics?.face,
issuerLogo:
state.context.verifiableCredential?.issuerLogo ?? getMosipLogo(),
wellKnown: state.context.verifiableCredential?.wellKnown,
credentialTypes: state.context.verifiableCredential?.credentialTypes,
issuer: vcMetadata.issuer,
};
}
export function selectKebabPopUp(state: State) {

View File

@@ -3,6 +3,7 @@ import Cloud from '../../../shared/CloudBackupAndRestoreUtils';
import {VCMetadata} from '../../../shared/VCMetadata';
import getAllConfigurations, {
API_URLS,
CACHED_API,
DownloadProps,
} from '../../../shared/api';
import {
@@ -16,8 +17,9 @@ import {
import {CredentialDownloadResponse, request} from '../../../shared/request';
import {WalletBindingResponse} from '../VCMetaMachine/vc';
import {verifyCredential} from '../../../shared/vcjs/verifyCredential';
import {getMosipIdentifier} from '../../../shared/commonUtil';
import {getVerifiableCredential} from './VCItemSelectors';
import {getSelectedCredentialTypeDetails} from '../../../shared/openId4VCI/Utils';
import {getCredentialTypes} from '../../../components/VC/common/VCUtils';
const {RNSecureKeystoreModule} = NativeModules;
export const VCItemServices = model => {
@@ -105,9 +107,7 @@ export const VCItemServices = model => {
);
},
requestBindingOTP: async context => {
const vc = VCMetadata.fromVC(context.vcMetadata).isFromOpenId4VCI()
? context.verifiableCredential.credential
: context.verifiableCredential;
const vc = getVerifiableCredential(context.verifiableCredential);
const response = await request(
API_URLS.bindingOtp.method,
API_URLS.bindingOtp.buildURL(),
@@ -124,6 +124,18 @@ export const VCItemServices = model => {
}
return response;
},
fetchIssuerWellknown: async context => {
const wellknownResponse = await CACHED_API.fetchIssuerWellknownConfig(
context.vcMetadata.issuer,
context.verifiableCredential.wellKnown,
true,
);
const wellknownOfCredential = getSelectedCredentialTypeDetails(
wellknownResponse,
getCredentialTypes(context.verifiableCredential),
);
return wellknownOfCredential;
},
checkStatus: context => (callback, onReceive) => {
const pollInterval = setInterval(
() => callback(model.events.POLL()),
@@ -199,10 +211,7 @@ export const VCItemServices = model => {
verifyCredential: async context => {
if (context.verifiableCredential) {
const verificationResult = await verifyCredential(
getVerifiableCredential(
context.vcMetadata,
context.verifiableCredential,
),
getVerifiableCredential(context.verifiableCredential),
);
if (!verificationResult.isVerified) {
throw new Error(verificationResult.errorMessage);

View File

@@ -15,7 +15,6 @@ export function selectMyVcsMetadata(state: State): VCMetadata[] {
export function selectShareableVcsMetadata(state: State): VCMetadata[] {
return state.context.myVcsMetadata.filter(
vcMetadata =>
state.context.myVcs[vcMetadata.getVcKey()]?.credential != null ||
state.context.myVcs[vcMetadata.getVcKey()]?.verifiableCredential != null,
);
}

View File

@@ -1,15 +1,17 @@
import {displayType, logoType} from '../../Issuers/IssuersMachine';
import {VCMetadata} from '../../../shared/VCMetadata';
export interface VC {
id?: string;
idType?: VcIdType;
credential?: DecodedCredential;
verifiableCredential: VerifiableCredential;
verifiableCredential: VerifiableCredential | Credential;
requestId?: string;
isVerified?: boolean;
lastVerifiedOn: number;
walletBindingResponse?: WalletBindingResponse;
hashedId?: string;
vcMetadata: VCMetadata;
}
export type VcIdType = 'UIN' | 'VID';
@@ -54,7 +56,8 @@ export interface Credential {
type: 'RsaSignature2018' | string;
verificationMethod: string;
};
type: VerifiableCredentialType[];
type: string[];
credentialTypes: string[];
}
export interface VerifiableCredential {
@@ -65,11 +68,20 @@ export interface VerifiableCredential {
credentialTypes: Object[];
}
export interface VerifiableCredentialData {
vcMetadata: VCMetadata;
face: string;
issuerLogo: logoType;
wellKnown?: string;
credentialTypes?: Object[];
issuer?: string;
}
export interface CredentialWrapper {
verifiableCredential: VerifiableCredential;
identifier: string;
generatedOn: Date;
issuerLogo: string;
vcMetadata: VCMetadata;
}
export interface CredentialTypes {
@@ -84,10 +96,11 @@ export interface CredentialTypes {
};
}
export type VerifiableCredentialType =
| 'VerifiableCredential'
| 'MOSIPVerfiableCredential'
| string;
export interface IssuerWellknownResponse {
credential_issuer: string;
credential_endpoint: string;
credentials_supported: Object[];
}
export interface VCLabel {
singular: string;
@@ -116,3 +129,16 @@ export interface WalletBindingResponse {
thumbprint: string;
expireDateTime: string;
}
//TODO: Check if Type word is needed in the naming
export interface VCMetadataType {
//TODO: requestId is not null at any point as its used for file names and all
isPinned: boolean;
requestId: string | null;
issuer: string;
protocol: string;
id: string;
timestamp: string;
isVerified: boolean;
credentialType: string;
}

View File

@@ -9,11 +9,15 @@ const model = createModel(
{
serviceRefs: {} as AppServices,
activities: [] as ActivityLog[],
wellKnownIssuerMap: {} as Record<string, Object>,
},
{
events: {
STORE_RESPONSE: (response: unknown) => ({response}),
LOG_ACTIVITY: (log: ActivityLog | ActivityLog[]) => ({log}),
LOG_ACTIVITY: (log: ActivityLog | ActivityLog[], wellknown?: any) => ({
log,
wellknown,
}),
REFRESH: () => ({}),
},
},
@@ -40,6 +44,15 @@ export const activityLogMachine =
on: {
STORE_RESPONSE: {
actions: ['setActivities', sendParent('READY')],
target: 'loadWellknownConfig',
},
},
},
loadWellknownConfig: {
entry: 'fetchAllWellKnownConfigResponse',
on: {
STORE_RESPONSE: {
actions: ['setAllWellknownConfigResponse'],
target: 'ready',
},
},
@@ -58,7 +71,7 @@ export const activityLogMachine =
},
},
logging: {
entry: 'storeActivity',
entry: ['loadWellknownIntoContext', 'storeActivity'],
on: {
STORE_RESPONSE: {
actions: 'prependActivity',
@@ -94,11 +107,41 @@ export const activityLogMachine =
{to: context => context.serviceRefs.store},
),
loadWellknownIntoContext: model.assign({
wellKnownIssuerMap: (context, event) => {
if (!!event.wellknown) {
const updatedWellKnownIssuerMap = {
...context.wellKnownIssuerMap,
};
updatedWellKnownIssuerMap[event.log.issuer] = event.wellknown;
return updatedWellKnownIssuerMap as unknown as Record<
string,
Object
>;
}
return context.wellKnownIssuerMap;
},
}),
prependActivity: model.assign({
activities: (context, event) =>
(Array.isArray(event.response)
? [...event.response, ...context.activities]
: [event.response, ...context.activities]) as ActivityLog[],
activities: (context, event) => {
return (
Array.isArray(event.response)
? [...event.response, ...context.activities]
: [event.response, ...context.activities]
) as ActivityLog[];
},
}),
fetchAllWellKnownConfigResponse: send(
() => StoreEvents.FETCH_ALL_WELLKNOWN_CONFIG(),
{to: context => context.serviceRefs.store},
),
setAllWellknownConfigResponse: model.assign({
wellKnownIssuerMap: (_, event) => {
return event.response as Record<string, Object>;
},
}),
},
},
@@ -134,6 +177,10 @@ export function selectActivities(state: State) {
return state.context.activities;
}
export function selectWellknownIssuerMap(state: State) {
return state.context.wellKnownIssuerMap;
}
export function selectIsRefreshing(state: State) {
return state.matches('ready.refreshing');
}

View File

@@ -1,36 +1,36 @@
// This file was automatically generated. Edits will be overwritten
// This file was automatically generated. Edits will be overwritten
export interface Typegen0 {
'@@xstate/typegen': true;
internalEvents: {
"xstate.init": { type: "xstate.init" };
};
invokeSrcNameMap: {
};
missingImplementations: {
actions: never;
delays: never;
guards: never;
services: never;
};
eventsCausingActions: {
"loadActivities": "REFRESH" | "xstate.init";
"prependActivity": "STORE_RESPONSE";
"setActivities": "STORE_RESPONSE";
"storeActivity": "LOG_ACTIVITY";
};
eventsCausingDelays: {
};
eventsCausingGuards: {
};
eventsCausingServices: {
};
matchesStates: "init" | "ready" | "ready.idle" | "ready.logging" | "ready.refreshing" | { "ready"?: "idle" | "logging" | "refreshing"; };
tags: never;
}
export interface Typegen0 {
'@@xstate/typegen': true;
internalEvents: {
'xstate.init': {type: 'xstate.init'};
};
invokeSrcNameMap: {};
missingImplementations: {
actions: never;
delays: never;
guards: never;
services: never;
};
eventsCausingActions: {
fetchAllWellKnownConfigResponse: 'STORE_RESPONSE';
loadActivities: 'REFRESH' | 'xstate.init';
loadWellknownIntoContext: 'LOG_ACTIVITY';
prependActivity: 'STORE_RESPONSE';
setActivities: 'STORE_RESPONSE';
setAllWellknownConfigResponse: 'STORE_RESPONSE';
storeActivity: 'LOG_ACTIVITY';
};
eventsCausingDelays: {};
eventsCausingGuards: {};
eventsCausingServices: {};
matchesStates:
| 'init'
| 'loadWellknownConfig'
| 'ready'
| 'ready.idle'
| 'ready.logging'
| 'ready.refreshing'
| {ready?: 'idle' | 'logging' | 'refreshing'};
tags: never;
}

View File

@@ -37,7 +37,7 @@ import {
sendStartEvent,
} from '../../../shared/telemetry/TelemetryUtils';
import {TelemetryConstants} from '../../../shared/telemetry/TelemetryConstants';
import {getIdType} from '../../../shared/openId4VCI/Utils';
import {getCredentialTypes} from '../../../components/VC/common/VCUtils';
const {verifier, EventTypes, VerificationStatus} = tuvali;
@@ -620,7 +620,10 @@ export const requestMachine =
_vcKey: vcMetadata.getVcKey(),
type: context.receiveLogType,
id: vcMetadata.id,
idType: getIdType(vcMetadata.issuer),
idType: getCredentialTypes(
context.incomingVc.verifiableCredential,
),
issuer: vcMetadata.issuer!!,
timestamp: Date.now(),
deviceName:
context.senderInfo.name || context.senderInfo.deviceName,

View File

@@ -2,6 +2,7 @@ import {StateFrom} from 'xstate';
import {requestMachine} from './requestMachine';
import {VCMetadata} from '../../../shared/VCMetadata';
import {getMosipLogo} from '../../../components/VC/common/VCUtils';
import {Credential} from '../../VerifiableCredential/VCMetaMachine/vc';
type State = StateFrom<typeof requestMachine>;
@@ -9,31 +10,29 @@ export function selectSenderInfo(state: State) {
return state.context.senderInfo;
}
export function selectCredential(state: State) {
return new VCMetadata(state.context.incomingVc?.vcMetadata).isFromOpenId4VCI()
? state.context.incomingVc?.verifiableCredential?.credential
: state.context.incomingVc?.verifiableCredential;
export function selectCredential(state: State): Credential {
return (
state.context.incomingVc?.verifiableCredential?.credential ||
state.context.incomingVc?.verifiableCredential
);
}
export function selectVerifiableCredentialData(state: State) {
const vcMetadata = new VCMetadata(state.context.incomingVc?.vcMetadata);
return vcMetadata.isFromOpenId4VCI()
? {
vcMetadata: vcMetadata,
face: state.context.incomingVc?.verifiableCredential.credential
.credentialSubject.face,
issuerLogo: state.context.incomingVc?.verifiableCredential?.issuerLogo,
wellKnown: state.context.incomingVc?.verifiableCredential?.wellKnown,
credentialTypes:
state.context.incomingVc?.verifiableCredential?.credentialTypes,
issuer: vcMetadata.issuer,
}
: {
vcMetadata: vcMetadata,
issuer: vcMetadata.issuer,
face: state.context.incomingVc?.credential?.biometrics?.face,
issuerLogo: getMosipLogo(),
};
return {
vcMetadata: vcMetadata,
face:
state.context.incomingVc?.verifiableCredential.credential
?.credentialSubject?.face ||
state.context.incomingVc?.credential?.biometrics?.face,
issuerLogo:
state.context.incomingVc?.verifiableCredential?.issuerLogo ||
getMosipLogo(),
issuer: vcMetadata.issuer,
wellKnown: state.context.incomingVc?.verifiableCredential?.wellKnown,
credentialTypes:
state.context.incomingVc?.verifiableCredential?.credentialTypes,
};
}
export function selectIsReviewingInIdle(state: State) {

View File

@@ -11,7 +11,6 @@ import {
MY_VCS_STORE_KEY,
MY_LOGIN_STORE_KEY,
} from '../../../shared/constants';
import {getIdType} from '../../../shared/openId4VCI/Utils';
import {TelemetryConstants} from '../../../shared/telemetry/TelemetryConstants';
import {
sendImpressionEvent,
@@ -30,6 +29,7 @@ import {StoreEvents} from '../../store';
import tuvali from '@mosip/tuvali';
import BluetoothStateManager from 'react-native-bluetooth-state-manager';
import {NativeModules} from 'react-native';
import {getCredentialTypes} from '../../../components/VC/common/VCUtils';
const {wallet, EventTypes, VerificationStatus} = tuvali;
export const ScanActions = (model: any, QR_LOGIN_REF_ID: any) => {
@@ -191,14 +191,16 @@ export const ScanActions = (model: any, QR_LOGIN_REF_ID: any) => {
logShared: send(
(context: any) => {
const vcMetadata = context.selectedVc?.vcMetadata;
const vcMetadata = VCMetadata.fromVC(context.selectedVc?.vcMetadata);
const selectedVc = context.QrLoginRef.getSnapshot().context.selectedVc;
return ActivityLogEvents.LOG_ACTIVITY({
_vcKey: VCMetadata.fromVC(vcMetadata).getVcKey(),
_vcKey: vcMetadata.getVcKey(),
type: context.shareLogType
? context.shareLogType
: 'VC_SHARED_WITH_VERIFICATION_CONSENT',
id: vcMetadata.id,
idType: getIdType(vcMetadata.issuer),
idType: getCredentialTypes(selectedVc.verifiableCredential),
issuer: vcMetadata.issuer!!,
timestamp: Date.now(),
deviceName:
context.receiverInfo.name || context.receiverInfo.deviceName,
@@ -209,17 +211,21 @@ export const ScanActions = (model: any, QR_LOGIN_REF_ID: any) => {
),
logFailedVerification: send(
context =>
ActivityLogEvents.LOG_ACTIVITY({
_vcKey: VCMetadata.fromVC(context.selectedVc).getVcKey(),
context => {
const vcMetadata = VCMetadata.fromVC(context.selectedVc);
const selectedVc = context.QrLoginRef.getSnapshot().context.selectedVc;
return ActivityLogEvents.LOG_ACTIVITY({
_vcKey: vcMetadata.getVcKey(),
type: 'PRESENCE_VERIFICATION_FAILED',
timestamp: Date.now(),
idType: getIdType(context.selectedVc.vcMetadata.issuer),
id: context.selectedVc.vcMetadata.id,
idType: getCredentialTypes(selectedVc.verifiableCredential),
id: vcMetadata.id,
issuer: vcMetadata.issuer!!,
deviceName:
context.receiverInfo.name || context.receiverInfo.deviceName,
vcLabel: context.selectedVc.vcMetadata.id,
}),
vcLabel: vcMetadata.id,
});
},
{to: context => context.serviceRefs.activityLog},
),
@@ -242,11 +248,8 @@ export const ScanActions = (model: any, QR_LOGIN_REF_ID: any) => {
),
loadVCDataToMemory: send(
(context: any) => {
let metadata = VCMetadata.fromVC(context.quickShareData?.meta);
let verifiableCredential = metadata.isFromOpenId4VCI()
? {credential: context.quickShareData?.verifiableCredential}
: context.quickShareData?.verifiableCredential;
const verifiableCredential =
context.quickShareData?.verifiableCredential;
return StoreEvents.SET(metadata.getVcKey(), {
verifiableCredential: verifiableCredential,
@@ -268,16 +271,22 @@ export const ScanActions = (model: any, QR_LOGIN_REF_ID: any) => {
),
storingActivityLog: send(
(_, event) =>
ActivityLogEvents.LOG_ACTIVITY({
(context, event) => {
const vcMetadata = event.response.selectedVc.vcMetadata;
const selectedVc = context.QrLoginRef.getSnapshot().context.selectedVc;
return ActivityLogEvents.LOG_ACTIVITY({
_vcKey: '',
id: event.response.selectedVc.vcMetadata.id,
idType: getIdType(event.response.selectedVc.vcMetadata.issuer),
id: vcMetadata.id,
issuer: vcMetadata.issuer!!,
idType: getCredentialTypes(selectedVc.verifiableCredential),
type: 'QRLOGIN_SUCCESFULL',
timestamp: Date.now(),
deviceName: '',
vcLabel: String(event.response.selectedVc.vcMetadata.id),
}),
vcLabel: String(vcMetadata.id),
});
},
{
to: (context: any) => context.serviceRefs.activityLog,
},

View File

@@ -18,30 +18,28 @@ export function selectVcName(state: State) {
}
export function selectCredential(state: State) {
return new VCMetadata(state.context.selectedVc?.vcMetadata).isFromOpenId4VCI()
? state.context.selectedVc?.verifiableCredential?.credential
: state.context.selectedVc?.verifiableCredential;
return (
state.context.selectedVc?.verifiableCredential?.credential ||
state.context.selectedVc?.verifiableCredential
);
}
export function selectVerifiableCredentialData(state: State) {
const vcMetadata = new VCMetadata(state.context.selectedVc?.vcMetadata);
return vcMetadata.isFromOpenId4VCI()
? {
vcMetadata: vcMetadata,
issuer: vcMetadata.issuer,
issuerLogo: state.context.selectedVc?.verifiableCredential?.issuerLogo,
wellKnown: state.context.selectedVc?.verifiableCredential?.wellKnown,
face: state.context.selectedVc?.verifiableCredential?.credential
.credentialSubject?.face,
credentialTypes:
state.context.selectedVc?.verifiableCredential?.credentialTypes,
}
: {
vcMetadata: vcMetadata,
issuer: vcMetadata.issuer,
face: state.context.selectedVc?.credential?.biometrics?.face,
issuerLogo: getMosipLogo(),
};
return {
vcMetadata: vcMetadata,
issuer: vcMetadata.issuer,
issuerLogo:
state.context.selectedVc?.verifiableCredential?.issuerLogo ||
getMosipLogo(),
face:
state.context.selectedVc?.verifiableCredential?.credential
?.credentialSubject?.face ||
state.context.selectedVc?.credential?.biometrics?.face,
wellKnown: state.context.selectedVc?.verifiableCredential?.wellKnown,
credentialTypes:
state.context.selectedVc?.verifiableCredential?.credentialTypes,
};
}
export function selectQrLoginRef(state: State) {

View File

@@ -1,47 +1,71 @@
// This file was automatically generated. Edits will be overwritten
// This file was automatically generated. Edits will be overwritten
export interface Typegen0 {
'@@xstate/typegen': true;
internalEvents: {
"done.invoke.faceScanner.capturing:invocation[0]": { type: "done.invoke.faceScanner.capturing:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." };
"done.invoke.faceScanner.verifying:invocation[0]": { type: "done.invoke.faceScanner.verifying:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." };
"error.platform.faceScanner.capturing:invocation[0]": { type: "error.platform.faceScanner.capturing:invocation[0]"; data: unknown };
"xstate.init": { type: "xstate.init" };
};
invokeSrcNameMap: {
"captureImage": "done.invoke.faceScanner.capturing:invocation[0]";
"checkPermission": "done.invoke.faceScanner.init.checkingPermission:invocation[0]";
"requestPermission": "done.invoke.faceScanner.init.requestingPermission:invocation[0]";
"verifyImage": "done.invoke.faceScanner.verifying:invocation[0]";
};
missingImplementations: {
actions: never;
delays: never;
guards: never;
services: never;
};
eventsCausingActions: {
"flipWhichCamera": "FLIP_CAMERA";
"openSettings": "OPEN_SETTINGS";
"setCameraRef": "READY";
"setCaptureError": "error.platform.faceScanner.capturing:invocation[0]";
"setCapturedImage": "done.invoke.faceScanner.capturing:invocation[0]";
};
eventsCausingDelays: {
};
eventsCausingGuards: {
"canRequestPermission": "DENIED";
"doesFaceMatch": "done.invoke.faceScanner.verifying:invocation[0]";
};
eventsCausingServices: {
"captureImage": "CAPTURE";
"checkPermission": "APP_FOCUSED" | "xstate.init";
"requestPermission": "DENIED";
"verifyImage": "done.invoke.faceScanner.capturing:invocation[0]";
};
matchesStates: "capturing" | "init" | "init.checkingPermission" | "init.permissionDenied" | "init.permissionGranted" | "init.requestingPermission" | "invalid" | "scanning" | "valid" | "verifying" | { "init"?: "checkingPermission" | "permissionDenied" | "permissionGranted" | "requestingPermission"; };
tags: never;
}
export interface Typegen0 {
'@@xstate/typegen': true;
internalEvents: {
'done.invoke.faceScanner.capturing:invocation[0]': {
type: 'done.invoke.faceScanner.capturing:invocation[0]';
data: unknown;
__tip: 'See the XState TS docs to learn how to strongly type this.';
};
'done.invoke.faceScanner.verifying:invocation[0]': {
type: 'done.invoke.faceScanner.verifying:invocation[0]';
data: unknown;
__tip: 'See the XState TS docs to learn how to strongly type this.';
};
'error.platform.faceScanner.capturing:invocation[0]': {
type: 'error.platform.faceScanner.capturing:invocation[0]';
data: unknown;
};
'xstate.init': {type: 'xstate.init'};
};
invokeSrcNameMap: {
captureImage: 'done.invoke.faceScanner.capturing:invocation[0]';
checkPermission: 'done.invoke.faceScanner.init.checkingPermission:invocation[0]';
requestPermission: 'done.invoke.faceScanner.init.requestingPermission:invocation[0]';
verifyImage: 'done.invoke.faceScanner.verifying:invocation[0]';
};
missingImplementations: {
actions: never;
delays: never;
guards: never;
services: never;
};
eventsCausingActions: {
flipWhichCamera: 'FLIP_CAMERA';
openSettings: 'OPEN_SETTINGS';
setCameraRef: 'READY';
setCaptureError: 'error.platform.faceScanner.capturing:invocation[0]';
setCapturedImage: 'done.invoke.faceScanner.capturing:invocation[0]';
};
eventsCausingDelays: {};
eventsCausingGuards: {
canRequestPermission: 'DENIED';
doesFaceMatch: 'done.invoke.faceScanner.verifying:invocation[0]';
};
eventsCausingServices: {
captureImage: 'CAPTURE';
checkPermission: 'APP_FOCUSED' | 'xstate.init';
requestPermission: 'DENIED';
verifyImage: 'done.invoke.faceScanner.capturing:invocation[0]';
};
matchesStates:
| 'capturing'
| 'init'
| 'init.checkingPermission'
| 'init.permissionDenied'
| 'init.permissionGranted'
| 'init.requestingPermission'
| 'invalid'
| 'scanning'
| 'valid'
| 'verifying'
| {
init?:
| 'checkingPermission'
| 'permissionDenied'
| 'permissionGranted'
| 'requestingPermission';
};
tags: never;
}

View File

@@ -390,4 +390,4 @@ export function selectIsPasscodeUnlock(state: State) {
return (
state.context.isBiometricToggled && !state.context.isBiometricUnlockEnabled
);
}
}

View File

@@ -1,53 +1,70 @@
// This file was automatically generated. Edits will be overwritten
// This file was automatically generated. Edits will be overwritten
export interface Typegen0 {
'@@xstate/typegen': true;
internalEvents: {
"done.invoke.settings.resetInjiProps:invocation[0]": { type: "done.invoke.settings.resetInjiProps:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." };
"error.platform.settings.resetInjiProps:invocation[0]": { type: "error.platform.settings.resetInjiProps:invocation[0]"; data: unknown };
"xstate.init": { type: "xstate.init" };
};
invokeSrcNameMap: {
"resetInjiProps": "done.invoke.settings.resetInjiProps:invocation[0]";
};
missingImplementations: {
actions: never;
delays: never;
guards: never;
services: never;
};
eventsCausingActions: {
"requestStoredContext": "xstate.init";
"resetCredentialRegistryResponse": "CANCEL" | "UPDATE_HOST";
"resetIsBiometricToggled": "DISMISS";
"setBackupAndRestoreOptionExplored": "SET_IS_BACKUP_AND_RESTORE_EXPLORED";
"setContext": "STORE_RESPONSE";
"setIsBiometricToggled": "TOGGLE_BIOMETRIC_UNLOCK";
"storeContext": "ACCEPT_HARDWARE_SUPPORT_NOT_EXISTS" | "SET_IS_BACKUP_AND_RESTORE_EXPLORED" | "SHOWN_ACCOUNT_SELECTION_CONFIRMATION" | "STORE_RESPONSE" | "TOGGLE_BIOMETRIC_UNLOCK" | "UPDATE_HOST" | "UPDATE_NAME" | "UPDATE_VC_LABEL" | "done.invoke.settings.resetInjiProps:invocation[0]";
"toggleBiometricUnlock": "TOGGLE_BIOMETRIC_UNLOCK";
"updateCredentialRegistry": "done.invoke.settings.resetInjiProps:invocation[0]";
"updateCredentialRegistryResponse": "error.platform.settings.resetInjiProps:invocation[0]";
"updateCredentialRegistrySuccess": "done.invoke.settings.resetInjiProps:invocation[0]";
"updateDefaults": "STORE_RESPONSE";
"updateEsignetHostUrl": "UPDATE_HOST";
"updateIsAccountSelectionConfirmationShown": "SHOWN_ACCOUNT_SELECTION_CONFIRMATION";
"updateName": "UPDATE_NAME";
"updatePartialDefaults": "STORE_RESPONSE";
"updateUserShownWithHardwareKeystoreNotExists": "ACCEPT_HARDWARE_SUPPORT_NOT_EXISTS";
"updateVcLabel": "UPDATE_VC_LABEL";
};
eventsCausingDelays: {
};
eventsCausingGuards: {
"hasData": "STORE_RESPONSE";
"hasPartialData": "STORE_RESPONSE";
};
eventsCausingServices: {
"resetInjiProps": "UPDATE_HOST";
};
matchesStates: "idle" | "init" | "resetInjiProps" | "showInjiTourGuide" | "storingDefaults";
tags: never;
}
export interface Typegen0 {
'@@xstate/typegen': true;
internalEvents: {
'done.invoke.settings.resetInjiProps:invocation[0]': {
type: 'done.invoke.settings.resetInjiProps:invocation[0]';
data: unknown;
__tip: 'See the XState TS docs to learn how to strongly type this.';
};
'error.platform.settings.resetInjiProps:invocation[0]': {
type: 'error.platform.settings.resetInjiProps:invocation[0]';
data: unknown;
};
'xstate.init': {type: 'xstate.init'};
};
invokeSrcNameMap: {
resetInjiProps: 'done.invoke.settings.resetInjiProps:invocation[0]';
};
missingImplementations: {
actions: never;
delays: never;
guards: never;
services: never;
};
eventsCausingActions: {
requestStoredContext: 'xstate.init';
resetCredentialRegistryResponse: 'CANCEL' | 'UPDATE_HOST';
resetIsBiometricToggled: 'DISMISS';
setBackupAndRestoreOptionExplored: 'SET_IS_BACKUP_AND_RESTORE_EXPLORED';
setContext: 'STORE_RESPONSE';
setIsBiometricToggled: 'TOGGLE_BIOMETRIC_UNLOCK';
storeContext:
| 'ACCEPT_HARDWARE_SUPPORT_NOT_EXISTS'
| 'SET_IS_BACKUP_AND_RESTORE_EXPLORED'
| 'SHOWN_ACCOUNT_SELECTION_CONFIRMATION'
| 'STORE_RESPONSE'
| 'TOGGLE_BIOMETRIC_UNLOCK'
| 'UPDATE_HOST'
| 'UPDATE_NAME'
| 'UPDATE_VC_LABEL'
| 'done.invoke.settings.resetInjiProps:invocation[0]';
toggleBiometricUnlock: 'TOGGLE_BIOMETRIC_UNLOCK';
updateCredentialRegistry: 'done.invoke.settings.resetInjiProps:invocation[0]';
updateCredentialRegistryResponse: 'error.platform.settings.resetInjiProps:invocation[0]';
updateCredentialRegistrySuccess: 'done.invoke.settings.resetInjiProps:invocation[0]';
updateDefaults: 'STORE_RESPONSE';
updateEsignetHostUrl: 'UPDATE_HOST';
updateIsAccountSelectionConfirmationShown: 'SHOWN_ACCOUNT_SELECTION_CONFIRMATION';
updateName: 'UPDATE_NAME';
updatePartialDefaults: 'STORE_RESPONSE';
updateUserShownWithHardwareKeystoreNotExists: 'ACCEPT_HARDWARE_SUPPORT_NOT_EXISTS';
updateVcLabel: 'UPDATE_VC_LABEL';
};
eventsCausingDelays: {};
eventsCausingGuards: {
hasData: 'STORE_RESPONSE';
hasPartialData: 'STORE_RESPONSE';
};
eventsCausingServices: {
resetInjiProps: 'UPDATE_HOST';
};
matchesStates:
| 'idle'
| 'init'
| 'resetInjiProps'
| 'showInjiTourGuide'
| 'storingDefaults';
tags: never;
}

View File

@@ -77,6 +77,7 @@ const model = createModel(
requester,
}),
STORE_ERROR: (error: Error, requester?: string) => ({error, requester}),
FETCH_ALL_WELLKNOWN_CONFIG: () => ({}),
},
},
);
@@ -233,6 +234,9 @@ export const storeMachine =
CLEAR: {
actions: 'forwardStoreRequest',
},
FETCH_ALL_WELLKNOWN_CONFIG: {
actions: 'forwardStoreRequest',
},
STORE_RESPONSE: {
actions: [
send(
@@ -442,6 +446,13 @@ export const storeMachine =
await clear();
break;
}
case 'FETCH_ALL_WELLKNOWN_CONFIG': {
response = await fetchAllWellknownConfig(
context.encryptionKey,
);
break;
}
default:
return;
}
@@ -586,6 +597,10 @@ export async function loadBackupData(data, encryptionKey) {
await Storage.loadBackupData(data, encryptionKey);
}
export async function fetchAllWellknownConfig(encryptionKey: string) {
return await Storage.fetchAllWellknownConfig(encryptionKey);
}
export async function getVCsData(key: string, encryptionKey: string) {
try {
let vcsData: Record<string, VC> = {};

View File

@@ -35,6 +35,7 @@ export interface Typegen0 {
| 'APPEND'
| 'CLEAR'
| 'EXPORT'
| 'FETCH_ALL_WELLKNOWN_CONFIG'
| 'GET'
| 'GET_VCS_DATA'
| 'PREPEND'

View File

@@ -1,21 +1,30 @@
import { useSelector } from '@xstate/react';
import { useContext } from 'react';
import {useSelector} from '@xstate/react';
import {useContext} from 'react';
import {
ActivityLogEvents,
selectActivities,
selectIsRefreshing,
selectWellknownIssuerMap,
} from '../../machines/activityLog';
import { GlobalContext } from '../../shared/GlobalContext';
import {GlobalContext} from '../../shared/GlobalContext';
export function useHistoryTab() {
const { appService } = useContext(GlobalContext);
const activityLogService = appService.children.get('activityLog');
const {appService} = useContext(GlobalContext);
const activityLogService = appService.children.get('activityLog')!!;
const wellknownIssuerMap = useSelector(
activityLogService,
selectWellknownIssuerMap,
);
return {
activities: useSelector(activityLogService, selectActivities),
isRefreshing: useSelector(activityLogService, selectIsRefreshing),
getWellKnownIssuerMap: (issuerName: string) => {
return wellknownIssuerMap[issuerName] ?? null;
},
REFRESH: () => activityLogService.send(ActivityLogEvents.REFRESH()),
};
}

View File

@@ -134,9 +134,7 @@ export const ViewVcModal: React.FC<ViewVcModalProps> = props => {
<BannerNotification
type={verificationStatus?.statusType as BannerStatus}
message={t(`VcVerificationBanner:${verificationStatus?.statusType}`, {
vcDetails: `${t(`VcDetails:${verificationStatus?.vcType}`)} ${
verificationStatus?.vcNumber
}`,
vcDetails: `${verificationStatus.vcType} ${verificationStatus?.vcNumber}`,
})}
onClosePress={controller.RESET_VERIFICATION_STATUS}
key={'reVerificationInProgress'}

View File

@@ -39,7 +39,7 @@ export const CredentialTypeSelectionScreen: React.FC<
</Text>
<View style={Theme.IssuersScreenStyles.issuersContainer}>
<FlatList
data={controller.credentialTypes}
data={controller.supportedCredentialTypes}
numColumns={1}
keyExtractor={item => item.id}
renderItem={({item}) => {

View File

@@ -1,6 +1,6 @@
import {useSelector} from '@xstate/react';
import {
selectCredentialTypes,
selectSupportedCredentialTypes,
selectErrorMessageType,
selectIsBiometricCancelled,
selectIsDone,
@@ -41,7 +41,10 @@ export function useIssuerScreenController({route, navigation}) {
service,
selectSelectingCredentialType,
),
credentialTypes: useSelector(service, selectCredentialTypes),
supportedCredentialTypes: useSelector(
service,
selectSupportedCredentialTypes,
),
verificationErrorMessage: useSelector(
service,
selectVerificationErrorMessage,

View File

@@ -12,7 +12,7 @@ import {Icon} from 'react-native-elements';
import {View} from 'react-native';
import {FaceVerificationAlertOverlay} from '../Scan/FaceVerificationAlertOverlay';
import {SvgImage} from '../../components/ui/svg';
import { LIVENESS_CHECK } from '../../shared/constants';
import {LIVENESS_CHECK} from '../../shared/constants';
export const QrLogin: React.FC<QrLoginProps> = props => {
const controller = useQrLogin(props);

View File

@@ -15,7 +15,7 @@ import {SvgImage} from '../../components/ui/svg';
import {View, I18nManager} from 'react-native';
import {Text} from './../../components/ui';
import {BannerStatusType} from '../../components/BannerNotification';
import { LIVENESS_CHECK } from '../../shared/constants';
import {LIVENESS_CHECK} from '../../shared/constants';
const ScanStack = createNativeStackNavigator();

View File

@@ -17,13 +17,13 @@ import {
import {TelemetryConstants} from '../../shared/telemetry/TelemetryConstants';
import {
getVCsOrderedByPinStatus,
isMosipVC,
VCItemContainerFlowType,
} from '../../shared/Utils';
import {Issuers} from '../../shared/openId4VCI/Utils';
import {FaceVerificationAlertOverlay} from './FaceVerificationAlertOverlay';
import {Error} from '../../components/ui/Error';
import {SvgImage} from '../../components/ui/svg';
import { LIVENESS_CHECK } from '../../shared/constants';
import {LIVENESS_CHECK} from '../../shared/constants';
export const SendVcScreen: React.FC = () => {
const {t} = useTranslation('SendVcScreen');
@@ -102,9 +102,7 @@ export const SendVcScreen: React.FC = () => {
<Column
style={Theme.SendVcScreenStyles.shareOptionButtonsContainer}
backgroundColor={Theme.Colors.whiteBackgroundColor}>
{[Issuers.MosipOtp, Issuers.Mosip].indexOf(
controller.verifiableCredentialData.issuer,
) !== -1 && (
{isMosipVC(controller.verifiableCredentialData.issuer) && (
<Button
type="gradient"
title={t('acceptRequestAndVerify')}

View File

@@ -21,22 +21,21 @@ export const VerifyIdentityOverlay: React.FC<
animationType: 'slide',
arrowLeft: true,
headerTitle: t('faceAuth'),
presentationStyle: "overFullScreen",
presentationStyle: 'overFullScreen',
showClose: true,
showHeader: true,
};
if (props.isLivenessEnabled) {
modalProps.arrowLeft = false;
modalProps.headerTitle = '';
modalProps.showClose = false;
modalProps.showHeader = false;
}
return (
<>
<Modal
{...modalProps}>
<Modal {...modalProps}>
<Column
fill
style={Theme.VerifyIdentityOverlayStyles.content}

View File

@@ -1,5 +1,6 @@
import {VCMetadata} from './VCMetadata';
import {groupBy} from './javascript';
import {Issuers} from './openId4VCI/Utils';
export const getVCsOrderedByPinStatus = (vcMetadatas: VCMetadata[]) => {
const [pinned, unpinned] = groupBy(
@@ -25,3 +26,7 @@ export interface CommunicationDetails {
phoneNumber: string;
emailId: string;
}
export const isMosipVC = (issuer: string) => {
return issuer === Issuers.Mosip || issuer === Issuers.MosipOtp;
};

View File

@@ -1,5 +1,5 @@
import {VC, VcIdType} from '../machines/VerifiableCredential/VCMetaMachine/vc';
import {Issuers, Protocols} from './openId4VCI/Utils';
import {Protocols} from './openId4VCI/Utils';
import {getMosipIdentifier} from './commonUtil';
const VC_KEY_PREFIX = 'VC';
@@ -87,28 +87,18 @@ export function parseMetadatas(metadataStrings: object[]) {
}
export const getVCMetadata = (context: object) => {
const [issuer, protocol, requestId] =
const [issuer, protocol, credentialId] =
context.credentialWrapper?.identifier.split(':');
// TODO(temp-solution): This is a temporary solution and will not work for every issuer
// This should be re-written in a more standards compliant way later.
if (issuer === Issuers.Sunbird) {
return VCMetadata.fromVC({
requestId: requestId ? requestId : null,
issuer: issuer,
protocol: protocol,
id: context.verifiableCredential?.credential.credentialSubject
.policyNumber,
timestamp: context.timestamp ?? '',
isVerified: context.vcMetadata.isVerified ?? false,
});
}
return VCMetadata.fromVC({
requestId: requestId ? requestId : null,
requestId: credentialId ?? null,
issuer: issuer,
protocol: protocol,
id: getMosipIdentifier(
context.verifiableCredential?.credential.credentialSubject,
),
id:
context.verifiableCredential?.credential.credentialSubject.policyNumber ||
getMosipIdentifier(
context.verifiableCredential?.credential.credentialSubject,
),
timestamp: context.timestamp ?? '',
isVerified: context.vcMetadata.isVerified ?? false,
});

View File

@@ -27,6 +27,7 @@ export const API_URLS: ApiUrls = {
buildURL: (issuerId: string): `/${string}` =>
`/residentmobileapp/issuers/${issuerId}`,
},
// TODO: Remove unused api
credentialTypes: {
method: 'GET',
buildURL: (issuerId: string): `/${string}` =>
@@ -145,8 +146,13 @@ export const CACHED_API = {
cacheKey: API_CACHED_STORAGE_KEYS.fetchIssuerConfig(issuerId),
fetchCall: API.fetchIssuerConfig.bind(null, issuerId),
}),
fetchIssuerWellknownConfig: (issuerId: string, requestUrl: string) =>
fetchIssuerWellknownConfig: (
issuerId: string,
requestUrl: string,
isCachePreferred: boolean = false,
) =>
generateCacheAPIFunction({
isCachePreferred,
cacheKey: API_CACHED_STORAGE_KEYS.fetchIssuerWellknownConfig(issuerId),
fetchCall: API.fetchIssuerWellknownConfig.bind(null, requestUrl),
}),

View File

@@ -35,7 +35,7 @@ export const getRandomInt = (min, max) => {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
}
};
export const generateBackupEncryptionKey = (
password: string,
salt: string,

View File

@@ -1,5 +1,10 @@
import {Dimensions, Platform} from 'react-native';
import {DEBUG_MODE, ESIGNET_HOST, MIMOTO_HOST, LIVENESS_DETECTION} from 'react-native-dotenv';
import {
DEBUG_MODE,
ESIGNET_HOST,
MIMOTO_HOST,
LIVENESS_DETECTION,
} from 'react-native-dotenv';
import {Argon2iConfig} from './commonUtil';
import {VcIdType} from '../machines/VerifiableCredential/VCMetaMachine/vc';

View File

@@ -15,10 +15,13 @@ import {
import {
BOTTOM_SECTION_FIELDS_WITH_DETAILED_ADDRESS_FIELDS,
DETAIL_VIEW_ADD_ON_FIELDS,
getCredentialDefinition,
getIdType,
getCredentialTypes,
} from '../../components/VC/common/VCUtils';
import {getVerifiableCredential} from '../../machines/VerifiableCredential/VCItemMachine/VCItemSelectors';
import {vcVerificationBannerDetails} from '../../components/BannerNotificationContainer';
import {getErrorEventData, sendErrorEvent} from '../telemetry/TelemetryUtils';
import {TelemetryConstants} from '../telemetry/TelemetryConstants';
export const Protocols = {
OpenId4VCI: 'OpenId4VCI',
@@ -31,44 +34,23 @@ export const Issuers = {
Mosip: 'Mosip',
};
/**
* @param issuer of the VC as per the VC metadata in MMKV
* @returns the ID-type to be used for further translation
*
* NOTE: This might be replaced by a more standards compliant way later.
*/
export function getIdType(issuer: string | undefined): string {
if (issuer === Issuers.MosipOtp || issuer === Issuers.Mosip) {
return 'nationalCard';
}
return 'insuranceCard';
}
export function getVcVerificationDetails(
statusType,
vcMetadata,
verifiableCredential,
wellknown: Object,
): vcVerificationBannerDetails {
const idType = getIdType(
wellknown,
getCredentialTypes(getVerifiableCredential(verifiableCredential)),
);
return {
statusType: statusType,
vcType: getIDType(
getVerifiableCredential(vcMetadata, verifiableCredential),
),
vcType: idType,
vcNumber: vcMetadata.id,
};
}
export const ID_TYPE = {
MOSIPVerifiableCredential: 'nationalCard',
InsuranceCredential: 'insuranceCard',
OpenG2PBeneficiaryVerifiableCredential: 'beneficiaryCard',
OpenG2PRegistryVerifiableCredential: 'socialRegistryCard',
};
export const getIDType = (verifiableCredential: VerifiableCredential) => {
return ID_TYPE[verifiableCredential.type[1]];
};
export const ACTIVATION_NEEDED = [Issuers.Mosip, Issuers.MosipOtp];
export const isActivationNeeded = (issuer: string) => {
@@ -77,7 +59,7 @@ export const isActivationNeeded = (issuer: string) => {
export const Issuers_Key_Ref = 'OpenId4VCI_KeyPair';
export const getIdentifier = (context, credential) => {
export const getIdentifier = (context, credential: VerifiableCredential) => {
const credentialIdentifier = credential.credential.id;
const credId = credentialIdentifier.startsWith('did')
? credentialIdentifier.split(':')
@@ -108,35 +90,23 @@ export const getCredentialRequestBody = async (
};
};
export const getCredentialType = (context: any) => {
return context.selectedCredentialType?.credential_definition?.type
? context.selectedCredentialType.credential_definition.type
: context.selectedIssuer?.credential_type
? context.selectedIssuer.credential_type
: ['VerifiableCredential', 'MOSIPVerifiableCredential'];
};
export const updateCredentialInformation = (context, credential) => {
let credentialWrapper: CredentialWrapper = {};
credentialWrapper.verifiableCredential = credential;
credentialWrapper.identifier = getIdentifier(context, credential);
credentialWrapper.generatedOn = new Date();
credentialWrapper.verifiableCredential.wellKnown =
context.selectedIssuer['.well-known'];
credentialWrapper.verifiableCredential.credentialTypes =
context.selectedIssuer['credential_type'];
credentialWrapper.verifiableCredential.issuerLogo =
getDisplayObjectForCurrentLanguage(context.selectedIssuer.display)?.logo;
credentialWrapper.vcMetadata = context.vcMetadata || {};
return credentialWrapper;
};
export const updateVCmetadataOfCredentialWrapper = (
export const updateCredentialInformation = (
context,
credentialWrapper: CredentialWrapper,
) => {
credentialWrapper.vcMetadata = context.vcMetadata;
return credentialWrapper;
credential: VerifiableCredential,
): CredentialWrapper => {
return {
verifiableCredential: {
...credential,
wellKnown: context.selectedIssuer['.well-known'],
credentialTypes: credential.credential.type ?? ['VerifiableCredential'],
issuerLogo: getDisplayObjectForCurrentLanguage(
context.selectedIssuer.display,
)?.logo,
},
identifier: getIdentifier(context, credential),
generatedOn: new Date(),
vcMetadata: context.vcMetadata || {},
};
};
export const getDisplayObjectForCurrentLanguage = (
@@ -157,11 +127,12 @@ export const getDisplayObjectForCurrentLanguage = (
export const constructAuthorizationConfiguration = (
selectedIssuer: issuerType,
supportedScopes: string,
supportedScope: string,
) => {
return {
issuer: selectedIssuer.credential_issuer,
clientId: selectedIssuer.client_id,
scopes: supportedScopes,
scopes: [supportedScope],
additionalHeaders: selectedIssuer.additional_headers,
redirectUrl: selectedIssuer.redirect_uri,
additionalParameters: {ui_locales: i18n.language},
@@ -197,37 +168,62 @@ export const getJWK = async publicKey => {
}
};
export const getSelectedCredentialTypeDetails = (
wellknown: any,
vcCredentialTypes: Object[],
): Object => {
for (let credential in wellknown.credentials_supported) {
const credentialDetails = wellknown.credentials_supported[credential];
if (
JSON.stringify(credentialDetails.credential_definition.type) ===
JSON.stringify(vcCredentialTypes)
) {
return credentialDetails;
}
}
console.error(
'Selected credential type is not available in wellknown config supported credentials list',
);
sendErrorEvent(
getErrorEventData(
TelemetryConstants.FlowType.wellknownConfig,
TelemetryConstants.ErrorId.mismatch,
TelemetryConstants.ErrorMessage.wellknownConfigMismatch,
),
);
return {};
};
export const getCredentialIssuersWellKnownConfig = async (
issuer: string,
wellknown: string,
vcCredentialTypes: Object[],
defaultFields: string[],
) => {
let fields: string[] = [];
let response = null;
if (issuer === Issuers.MosipOtp) {
fields = defaultFields;
} else if (wellknown) {
response = await CACHED_API.fetchIssuerWellknownConfig(issuer, wellknown);
let fields: string[] = defaultFields;
let credentialDetails: any;
if (wellknown) {
const response = await CACHED_API.fetchIssuerWellknownConfig(
issuer,
wellknown,
);
if (response) {
if (
Array.isArray(response.credentials_supported) &&
response?.credentials_supported[0].order
) {
fields = response?.credentials_supported[0].order;
credentialDetails = getSelectedCredentialTypeDetails(
response,
vcCredentialTypes,
);
if (Object.keys(credentialDetails).includes('order')) {
fields = credentialDetails.order;
} else {
const credentialDefinition = getCredentialDefinition(
response,
vcCredentialTypes,
fields = Object.keys(
credentialDetails.credential_definition.credentialSubject,
);
fields = credentialDefinition
? Object.keys(credentialDefinition.credentialSubject)
: [];
}
}
}
return {
wellknown: response,
wellknown: credentialDetails,
fields: fields,
};
};
@@ -235,13 +231,13 @@ export const getCredentialIssuersWellKnownConfig = async (
export const getDetailedViewFields = async (
issuer: string,
wellknown: string,
credentialTypes: Object[],
vcCredentialTypes: Object[],
defaultFields: string[],
) => {
let response = await getCredentialIssuersWellKnownConfig(
issuer,
wellknown,
credentialTypes,
vcCredentialTypes,
defaultFields,
);

View File

@@ -19,6 +19,7 @@ import {
MY_VCS_STORE_KEY,
SETTINGS_STORE_KEY,
ENOENT,
API_CACHED_STORAGE_KEYS,
} from './constants';
import FileStorage, {
getFilePath,
@@ -147,9 +148,30 @@ class Storage {
return true;
});
} catch (error) {
console.error('Error while loading backup data ', error);
return error;
}
};
static fetchAllWellknownConfig = async (encryptionKey: string) => {
let wellknownConfigData: Record<string, Object> = {};
const allKeysInDB = await MMKV.indexer.strings.getKeys();
const wellknownConfigCacheKey =
API_CACHED_STORAGE_KEYS.fetchIssuerWellknownConfig('');
const wellknownKeys = allKeysInDB.filter(key =>
key.includes(wellknownConfigCacheKey),
);
for (const wellknownKey of wellknownKeys) {
const configData = await this.getItem(wellknownKey, encryptionKey);
const decryptedConfigData = await decryptJson(encryptionKey, configData);
wellknownConfigData[
wellknownKey.substring(wellknownConfigCacheKey.length)
] = JSON.parse(JSON.stringify(decryptedConfigData));
}
return wellknownConfigData;
};
static isVCStorageInitialised = async (): Promise<boolean> => {
try {
const res = await FileStorage.getInfo(vcDirectoryPath);
@@ -315,7 +337,6 @@ class Storage {
encryptionKey,
JSON.stringify(vc),
);
const tmp = VCMetadata.fromVC(key);
// Save the VC to disk
await this.setItem(updatedVcKey, encryptedVC, encryptionKey);
});

View File

@@ -19,6 +19,7 @@ export const TelemetryConstants = {
remove: 'remove VC',
removeVcMetadata: 'VC metadata removed',
vcVerification: 'VC Verification',
wellknownConfig: 'Wellknown config',
}),
EndEventStatus: Object.freeze({
@@ -45,6 +46,8 @@ export const TelemetryConstants = {
'Tampered cards detected and removed for security reasons. Please download again',
privateKeyUpdationFailed: 'Failed to store private key in keystore',
vcVerificationFailed: 'VC verification Failed with Range Error - ',
wellknownConfigMismatch:
'Selected credential type is not available in wellknown config supported credentials list',
}),
ErrorId: Object.freeze({