mirror of
https://github.com/mosip/inji-wallet.git
synced 2026-01-09 05:27:57 -05:00
Merge remote-tracking branch 'mosip/qa-develop' into develop
This commit is contained in:
2
.env
2
.env
@@ -1,7 +1,7 @@
|
||||
# after making changes to the env file, ensure to start the bundler (or the project) with a --reset-cache
|
||||
# eg . npm build android:newlogic --reset-cache
|
||||
|
||||
MIMOTO_HOST=https://api.qa4.mosip.net/residentmobileapp
|
||||
MIMOTO_HOST=https://api.qa-121.mosip.net/residentmobileapp
|
||||
#MIMOTO_HOST=http://mock.mimoto.newlogic.dev
|
||||
GOOGLE_NEARBY_MESSAGES_API_KEY=
|
||||
|
||||
|
||||
4
.github/workflows/android-custom-build.yml
vendored
4
.github/workflows/android-custom-build.yml
vendored
@@ -1,7 +1,7 @@
|
||||
name: ID PASS - MOSIP Resident Application Custom build
|
||||
|
||||
env:
|
||||
backendServiceDefaultUrl: https://api-internal.qa4.mosip.net/residentmobileapp
|
||||
backendServiceDefaultUrl: https://api.qa-121.mosip.net/residentmobileapp
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
@@ -9,7 +9,7 @@ on:
|
||||
backendServiceUrl:
|
||||
description: 'Backend service URL'
|
||||
required: true
|
||||
default: 'https://api-internal.qa4.mosip.net/residentmobileapp'
|
||||
default: 'https://api.qa-121.mosip.net/residentmobileapp'
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
|
||||
1
.github/workflows/android.yml
vendored
1
.github/workflows/android.yml
vendored
@@ -6,6 +6,7 @@ on:
|
||||
- main
|
||||
- develop
|
||||
- demobranch
|
||||
- qa-develop
|
||||
tags:
|
||||
- '*'
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
buildscript {
|
||||
ext {
|
||||
buildToolsVersion = "29.0.3"
|
||||
minSdkVersion = 21
|
||||
minSdkVersion = 23
|
||||
compileSdkVersion = 30
|
||||
targetSdkVersion = 30
|
||||
}
|
||||
@@ -14,7 +14,7 @@ buildscript {
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath("com.android.tools.build:gradle:4.1.0")
|
||||
classpath("com.android.tools.build:gradle:4.2.2")
|
||||
classpath 'com.google.gms:google-services:4.3.5'
|
||||
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.4.1'
|
||||
|
||||
@@ -43,6 +43,7 @@ allprojects {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
allprojects { repositories { maven { url "$rootDir/../node_modules/expo-camera/android/maven" } } }
|
||||
|
||||
|
||||
|
||||
BIN
assets/domain-warning.png
Normal file
BIN
assets/domain-warning.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.3 KiB |
BIN
assets/otp-mobile-logo.png
Normal file
BIN
assets/otp-mobile-logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.8 KiB |
BIN
assets/success-logo.png
Normal file
BIN
assets/success-logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.2 KiB |
BIN
assets/warningLogo.png
Normal file
BIN
assets/warningLogo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.9 KiB |
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"VC_SHARED": "shared",
|
||||
"VC_RECEIVED": "received",
|
||||
"VC_RECEIVED_NOT_SAVED": "received was not saved",
|
||||
"VC_DELETED": "deleted",
|
||||
"VC_DOWNLOADED": "downloaded",
|
||||
"VC_REVOKED": "revoked",
|
||||
@@ -8,5 +9,6 @@
|
||||
"VC_RECEIVED_WITH_PRESENCE_VERIFIED": "received. Presence verified",
|
||||
"VC_RECEIVED_BUT_PRESENCE_VERIFICATION_FAILED": "received. Presence verification failed",
|
||||
"PRESENCE_VERIFIED_AND_VC_SHARED": "verified and shared",
|
||||
"PRESENCE_VERIFICATION_FAILED": "verification failed"
|
||||
"PRESENCE_VERIFICATION_FAILED": "verification failed",
|
||||
"QRLOGIN_SUCCESFULL": "QRLogin sucessfull"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Dimensions } from 'react-native';
|
||||
import { ListItem, Overlay, Input } from 'react-native-elements';
|
||||
import { Icon, ListItem, Overlay, Input } from 'react-native-elements';
|
||||
import { Text, Column, Row, Button } from './ui';
|
||||
import { Theme } from './ui/styleUtils';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@@ -12,6 +12,13 @@ export const EditableListItem: React.FC<EditableListItemProps> = (props) => {
|
||||
|
||||
return (
|
||||
<ListItem bottomDivider onPress={() => setIsEditing(true)}>
|
||||
<Icon
|
||||
name={props.Icon}
|
||||
type="antdesign"
|
||||
size={20}
|
||||
style={Theme.Styles.profileIconBg}
|
||||
color={Theme.Colors.Icon}
|
||||
/>
|
||||
<ListItem.Content>
|
||||
<ListItem.Title>
|
||||
<Text color={Theme.Colors.profileLabel}>{props.label}</Text>
|
||||
@@ -48,5 +55,6 @@ export const EditableListItem: React.FC<EditableListItemProps> = (props) => {
|
||||
interface EditableListItemProps {
|
||||
label: string;
|
||||
value: string;
|
||||
Icon: string;
|
||||
onEdit: (newValue: string) => void;
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ export const Message: React.FC<MessageProps> = (props) => {
|
||||
const Progress: React.FC<Pick<MessageProps, 'progress'>> = (props) => {
|
||||
return typeof props.progress === 'boolean' ? (
|
||||
props.progress && (
|
||||
<LinearProgress variant="indeterminate" color={Colors.Orange} />
|
||||
<LinearProgress variant="indeterminate" color={Theme.Colors.Icon} />
|
||||
)
|
||||
) : (
|
||||
<LinearProgress variant="determinate" value={props.progress} />
|
||||
|
||||
@@ -46,7 +46,7 @@ export const QrScanner: React.FC<QrScannerProps> = (props) => {
|
||||
if (hasPermission === false) {
|
||||
return (
|
||||
<Column fill align="space-between">
|
||||
<Text align="center" margin="16 0" color={Theme.Colors.errorMessage}>
|
||||
<Text align="center" color={Theme.Colors.errorMessage}>
|
||||
{t('missingPermissionText')}
|
||||
</Text>
|
||||
<Button title={t('allowCameraButton')} onPress={openSettings} />
|
||||
@@ -56,6 +56,11 @@ export const QrScanner: React.FC<QrScannerProps> = (props) => {
|
||||
|
||||
return (
|
||||
<View>
|
||||
{props.title && (
|
||||
<Text align="center" margin="16 0" color={Theme.Colors.Details}>
|
||||
{props.title}
|
||||
</Text>
|
||||
)}
|
||||
<View style={Theme.Styles.scannerContainer}>
|
||||
<Camera
|
||||
style={Theme.Styles.scanner}
|
||||
@@ -94,4 +99,5 @@ export const QrScanner: React.FC<QrScannerProps> = (props) => {
|
||||
|
||||
interface QrScannerProps {
|
||||
onQrFound: (data: string) => void;
|
||||
title?: string;
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ const getDetails = (arg1, arg2, verifiableCredential) => {
|
||||
}
|
||||
return (
|
||||
<Column>
|
||||
<Text color={Theme.Colors.DetailsLabel} size="smaller">
|
||||
<Text color={Theme.Colors.DetailsLabel} size="smaller" align="left">
|
||||
{arg1}
|
||||
</Text>
|
||||
<Text
|
||||
@@ -162,7 +162,7 @@ export const SingleVcItem: React.FC<VcItemProps> = (props) => {
|
||||
style={Theme.Styles.closeCardImage}
|
||||
/>
|
||||
|
||||
<Column margin="0 0 0 10">
|
||||
<Column margin="0 0 0 10" style={{ alignItems: 'flex-start' }}>
|
||||
{getDetails(t('fullName'), fullName, verifiableCredential)}
|
||||
{getDetails(t('uin'), uin, verifiableCredential)}
|
||||
{getDetails(t('generatedOn'), generatedOn, verifiableCredential)}
|
||||
|
||||
@@ -14,5 +14,9 @@
|
||||
"id": "Id",
|
||||
"nationalCard": "National Card",
|
||||
"uin": "UIN",
|
||||
"vid": "VID"
|
||||
}
|
||||
"vid": "VID",
|
||||
"enableVerification": "Enable Verification",
|
||||
"profileAuthenticated": "Profile is authenticated!",
|
||||
"offlineAuthDisabledHeader": "Offline Authentication disabled!",
|
||||
"offlineAuthDisabledMessage": "Click 'Enable Authentication' to enable this credentials to be used for offline authentication."
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import { useTranslation } from 'react-i18next';
|
||||
import { Image, ImageBackground } from 'react-native';
|
||||
import { Icon } from 'react-native-elements';
|
||||
import { VC, CredentialSubject, LocalizedField } from '../types/vc';
|
||||
import { Column, Row, Text } from './ui';
|
||||
import { Button, Column, Row, Text } from './ui';
|
||||
import { Theme } from './ui/styleUtils';
|
||||
import { TextItem } from './ui/TextItem';
|
||||
import { VcItemTags } from './VcItemTags';
|
||||
@@ -255,11 +255,13 @@ export const VcDetails: React.FC<VcDetailsProps> = (props) => {
|
||||
</Row>
|
||||
<VcItemTags tag={props.vc?.tag} />
|
||||
</ImageBackground>
|
||||
|
||||
{props.vc?.reason?.length > 0 && (
|
||||
<Text margin="24 24 16 24" weight="semibold">
|
||||
{t('reasonForSharing')}
|
||||
</Text>
|
||||
)}
|
||||
|
||||
{props.vc?.reason?.map((reason, index) => (
|
||||
<TextItem
|
||||
key={index}
|
||||
@@ -271,12 +273,68 @@ export const VcDetails: React.FC<VcDetailsProps> = (props) => {
|
||||
text={reason.message}
|
||||
/>
|
||||
))}
|
||||
|
||||
{props.isBindingPending ? (
|
||||
<Column style={Theme.Styles.openCardBgContainer}>
|
||||
<Row margin={'0 0 5 0'}>
|
||||
<Icon
|
||||
name="shield-alert"
|
||||
color={Theme.Colors.Icon}
|
||||
size={30}
|
||||
type="material-community"
|
||||
/>
|
||||
</Row>
|
||||
|
||||
<Text
|
||||
style={{ flex: 1 }}
|
||||
weight="semibold"
|
||||
size="small"
|
||||
margin={'0 0 5 0'}
|
||||
color={Theme.Colors.Details}>
|
||||
{t('offlineAuthDisabledHeader')}
|
||||
</Text>
|
||||
<Text
|
||||
style={{ flex: 1 }}
|
||||
weight="regular"
|
||||
size="small"
|
||||
margin={'0 0 5 0'}
|
||||
color={Theme.Colors.Details}>
|
||||
{t('offlineAuthDisabledMessage')}
|
||||
</Text>
|
||||
|
||||
<Button
|
||||
title={t('enableVerification')}
|
||||
onPress={props.onBinding}
|
||||
type="radius"
|
||||
/>
|
||||
</Column>
|
||||
) : (
|
||||
<Column style={Theme.Styles.openCardBgContainer}>
|
||||
<Row crossAlign="center">
|
||||
<Icon
|
||||
name="verified-user"
|
||||
color={Theme.Colors.VerifiedIcon}
|
||||
size={28}
|
||||
containerStyle={{ marginStart: 4, bottom: 1 }}
|
||||
/>
|
||||
<Text
|
||||
numLines={1}
|
||||
color={Theme.Colors.Details}
|
||||
weight="bold"
|
||||
size="smaller"
|
||||
margin="10 10 10 10"
|
||||
children={t('profileAuthenticated')}></Text>
|
||||
</Row>
|
||||
</Column>
|
||||
)}
|
||||
</Column>
|
||||
);
|
||||
};
|
||||
|
||||
interface VcDetailsProps {
|
||||
vc: VC;
|
||||
isBindingPending: boolean;
|
||||
onBinding?: () => void;
|
||||
}
|
||||
|
||||
function getFullAddress(credential: CredentialSubject) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useContext, useRef } from 'react';
|
||||
import { useInterpret, useSelector } from '@xstate/react';
|
||||
import { Pressable, Image, ImageBackground } from 'react-native';
|
||||
import { Pressable, Image, ImageBackground, Dimensions } from 'react-native';
|
||||
import { CheckBox, Icon } from 'react-native-elements';
|
||||
import { ActorRefFrom } from 'xstate';
|
||||
import {
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
vcItemMachine,
|
||||
selectContext,
|
||||
selectTag,
|
||||
selectEmptyWalletBindingId,
|
||||
} from '../machines/vcItem';
|
||||
import { Column, Row, Text } from './ui';
|
||||
import { Theme } from './ui/styleUtils';
|
||||
@@ -81,6 +82,7 @@ const getDetails = (arg1, arg2, verifiableCredential) => {
|
||||
color={Theme.Colors.Details}
|
||||
weight="bold"
|
||||
size="smaller"
|
||||
align="left"
|
||||
style={
|
||||
!verifiableCredential
|
||||
? Theme.Styles.loadingTitle
|
||||
@@ -93,6 +95,29 @@ const getDetails = (arg1, arg2, verifiableCredential) => {
|
||||
}
|
||||
};
|
||||
|
||||
const WalletVerified: React.FC = () => {
|
||||
return (
|
||||
<Icon
|
||||
name="verified-user"
|
||||
color={Theme.Colors.VerifiedIcon}
|
||||
size={28}
|
||||
containerStyle={{ marginStart: 4, bottom: 1 }}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const WalletUnverified: React.FC = () => {
|
||||
return (
|
||||
<Icon
|
||||
name="shield-alert"
|
||||
color={Theme.Colors.Icon}
|
||||
size={28}
|
||||
type="material-community"
|
||||
containerStyle={{ marginStart: 4, bottom: 1 }}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const VcItem: React.FC<VcItemProps> = (props) => {
|
||||
const { appService } = useContext(GlobalContext);
|
||||
const { t } = useTranslation('VcDetails');
|
||||
@@ -106,6 +131,7 @@ export const VcItem: React.FC<VcItemProps> = (props) => {
|
||||
const service = useInterpret(machine.current, { devTools: __DEV__ });
|
||||
const context = useSelector(service, selectContext);
|
||||
const verifiableCredential = useSelector(service, selectVerifiableCredential);
|
||||
const emptyWalletBindingId = useSelector(service, selectEmptyWalletBindingId);
|
||||
|
||||
//Assigning the UIN and VID from the VC details to display the idtype label
|
||||
const uin = verifiableCredential?.credentialSubject.UIN;
|
||||
@@ -131,7 +157,11 @@ export const VcItem: React.FC<VcItemProps> = (props) => {
|
||||
<Pressable
|
||||
onPress={() => props.onPress(service)}
|
||||
disabled={!verifiableCredential}
|
||||
style={Theme.Styles.closeCardBgContainer}>
|
||||
style={
|
||||
props.selected
|
||||
? Theme.Styles.selectedBindedVc
|
||||
: Theme.Styles.closeCardBgContainer
|
||||
}>
|
||||
<ImageBackground
|
||||
source={!verifiableCredential ? null : Theme.CloseCard}
|
||||
resizeMode="stretch"
|
||||
@@ -211,6 +241,67 @@ export const VcItem: React.FC<VcItemProps> = (props) => {
|
||||
</Row>
|
||||
<VcItemTags tag={tag} />
|
||||
</ImageBackground>
|
||||
<Row>
|
||||
{emptyWalletBindingId ? (
|
||||
<Row
|
||||
width={Dimensions.get('screen').width * 0.8}
|
||||
align="space-between"
|
||||
crossAlign="center">
|
||||
<Row crossAlign="center" style={{ flex: 1 }}>
|
||||
{verifiableCredential && <WalletUnverified />}
|
||||
<Text
|
||||
color={Theme.Colors.Details}
|
||||
weight="semibold"
|
||||
size="small"
|
||||
margin="10 33 10 10"
|
||||
style={
|
||||
!verifiableCredential
|
||||
? Theme.Styles.loadingTitle
|
||||
: Theme.Styles.subtitle
|
||||
}
|
||||
children={t('offlineAuthDisabledHeader')}></Text>
|
||||
</Row>
|
||||
|
||||
<Pressable>
|
||||
<Icon
|
||||
name="dots-three-horizontal"
|
||||
type="entypo"
|
||||
color={Theme.Colors.GrayIcon}
|
||||
/>
|
||||
</Pressable>
|
||||
</Row>
|
||||
) : (
|
||||
<Row
|
||||
width={Dimensions.get('screen').width * 0.8}
|
||||
align="space-between"
|
||||
crossAlign="center">
|
||||
<Row crossAlign="center" style={{ flex: 1 }}>
|
||||
<WalletVerified />
|
||||
<Text
|
||||
color={Theme.Colors.Details}
|
||||
weight="semibold"
|
||||
size="smaller"
|
||||
margin="10 10 10 10"
|
||||
style={
|
||||
!verifiableCredential
|
||||
? Theme.Styles.loadingTitle
|
||||
: Theme.Styles.subtitle
|
||||
}
|
||||
children={t('profileAuthenticated')}></Text>
|
||||
</Row>
|
||||
|
||||
{props.showOnlyBindedVc ? null : (
|
||||
<Pressable>
|
||||
<Icon
|
||||
name="dots-three-horizontal"
|
||||
type="entypo"
|
||||
color={Theme.Colors.GrayIcon}
|
||||
/>
|
||||
</Pressable>
|
||||
)}
|
||||
</Row>
|
||||
)}
|
||||
</Row>
|
||||
</Pressable>
|
||||
);
|
||||
};
|
||||
@@ -220,6 +311,7 @@ interface VcItemProps {
|
||||
margin?: string;
|
||||
selectable?: boolean;
|
||||
selected?: boolean;
|
||||
showOnlyBindedVc?: boolean;
|
||||
onPress?: (vcRef?: ActorRefFrom<typeof vcItemMachine>) => void;
|
||||
onShow?: (vcRef?: ActorRefFrom<typeof vcItemMachine>) => void;
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ export const Button: React.FC<ButtonProps> = (props) => {
|
||||
weight="semibold"
|
||||
align="center"
|
||||
color={
|
||||
type === 'solid' || type === 'addId'
|
||||
type === 'solid' || type === 'addId' || type === 'radius'
|
||||
? Theme.Colors.whiteText
|
||||
: Theme.Colors.AddIdBtnTxt
|
||||
}>
|
||||
|
||||
@@ -12,13 +12,14 @@ export const Modal: React.FC<ModalProps> = (props) => {
|
||||
visible={props.isVisible}
|
||||
onShow={props.onShow}
|
||||
onRequestClose={props.onDismiss}>
|
||||
<Column fill safe>
|
||||
<Column fill safe align="center">
|
||||
<Row elevation={props.headerElevation}>
|
||||
<View
|
||||
style={{
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
marginHorizontal: 16,
|
||||
alignItems: 'center',
|
||||
marginHorizontal: 21,
|
||||
marginVertical: 16,
|
||||
}}>
|
||||
{props.headerRight ? (
|
||||
@@ -28,10 +29,18 @@ export const Modal: React.FC<ModalProps> = (props) => {
|
||||
color={Theme.Colors.Icon}
|
||||
/>
|
||||
) : null}
|
||||
<Row fill align="center">
|
||||
{props.arrowLeft ? (
|
||||
<Icon
|
||||
name="arrow-left"
|
||||
type="material-community"
|
||||
onPress={props.onDismiss}
|
||||
color={Theme.Colors.Details}
|
||||
/>
|
||||
) : null}
|
||||
<Row fill align="center" margin={'5 30 0 0'}>
|
||||
<Text weight="semibold">{props.headerTitle}</Text>
|
||||
</Row>
|
||||
{props.headerRight || (
|
||||
{props.headerRight || props.arrowLeft || (
|
||||
<Icon
|
||||
name="close"
|
||||
onPress={props.onDismiss}
|
||||
@@ -52,5 +61,6 @@ export interface ModalProps {
|
||||
headerTitle?: string;
|
||||
headerElevation?: ElevationLevel;
|
||||
headerRight?: React.ReactElement;
|
||||
arrowLeft?: React.ReactElement;
|
||||
onShow?: () => void;
|
||||
}
|
||||
|
||||
@@ -8,11 +8,13 @@ const Colors = {
|
||||
Grey5: '#E0E0E0',
|
||||
Grey6: '#F2F2F2',
|
||||
Orange: '#F2811D',
|
||||
LightGrey: '#FAF9FF',
|
||||
LightGrey: '#f7f5f0',
|
||||
White: '#FFFFFF',
|
||||
Red: '#EB5757',
|
||||
Green: '#219653',
|
||||
Transparent: 'transparent',
|
||||
Warning: '#f0ad4e',
|
||||
LightOrange: '#fce7e3',
|
||||
};
|
||||
|
||||
export type ElevationLevel = 0 | 1 | 2 | 3 | 4 | 5;
|
||||
@@ -30,6 +32,7 @@ export const DefaultTheme = {
|
||||
noUinText: Colors.Orange,
|
||||
IconBg: Colors.Orange,
|
||||
Icon: Colors.Orange,
|
||||
GrayIcon: Colors.Grey,
|
||||
borderBottomColor: Colors.Grey6,
|
||||
whiteBackgroundColor: Colors.White,
|
||||
lightGreyBackgroundColor: Colors.LightGrey,
|
||||
@@ -55,6 +58,8 @@ export const DefaultTheme = {
|
||||
checkCircleIcon: Colors.White,
|
||||
OnboardingCircleIcon: Colors.White,
|
||||
OnboardingCloseIcon: Colors.White,
|
||||
WarningIcon: Colors.Warning,
|
||||
ProfileIconBg: Colors.LightOrange,
|
||||
},
|
||||
Styles: StyleSheet.create({
|
||||
title: {
|
||||
@@ -110,10 +115,40 @@ export const DefaultTheme = {
|
||||
shadowRadius: 3,
|
||||
elevation: 4,
|
||||
},
|
||||
selectedBindedVc: {
|
||||
borderRadius: 10,
|
||||
margin: 5,
|
||||
borderWidth: 2,
|
||||
borderColor: Colors.Orange,
|
||||
},
|
||||
labelPartContainer: {
|
||||
marginLeft: 16,
|
||||
flex: 1,
|
||||
},
|
||||
urlContainer: {
|
||||
backgroundColor: Colors.White,
|
||||
padding: 10,
|
||||
borderRadius: 12,
|
||||
fontSize: 12,
|
||||
},
|
||||
lockDomainContainer: {
|
||||
backgroundColor: Colors.White,
|
||||
alignSelf: 'center',
|
||||
borderRadius: 15,
|
||||
width: 100,
|
||||
},
|
||||
bottomButtonsContainer: {
|
||||
height: 120,
|
||||
borderTopLeftRadius: 27,
|
||||
borderTopRightRadius: 27,
|
||||
padding: 6,
|
||||
backgroundColor: Colors.White,
|
||||
},
|
||||
consentPageTop: {
|
||||
backgroundColor: Colors.White,
|
||||
height: 160,
|
||||
borderRadius: 6,
|
||||
},
|
||||
labelPart: {
|
||||
marginTop: 10,
|
||||
alignItems: 'flex-start',
|
||||
@@ -132,6 +167,8 @@ export const DefaultTheme = {
|
||||
backgroundImageContainer: {
|
||||
flex: 1,
|
||||
padding: 10,
|
||||
borderBottomColor: Colors.Grey,
|
||||
borderBottomWidth: 1,
|
||||
},
|
||||
successTag: {
|
||||
backgroundColor: Colors.Green,
|
||||
@@ -169,6 +206,23 @@ export const DefaultTheme = {
|
||||
flex: 1,
|
||||
padding: 10,
|
||||
},
|
||||
profileIconBg: {
|
||||
padding: 8,
|
||||
width: 40,
|
||||
height: 40,
|
||||
borderRadius: 6,
|
||||
backgroundColor: Colors.LightOrange,
|
||||
},
|
||||
domainVerifiyIcon: {
|
||||
padding: 20,
|
||||
marginLeft: 120,
|
||||
width: 130,
|
||||
height: 130,
|
||||
borderRadius: 60,
|
||||
borderWidth: 10,
|
||||
borderColor: Colors.White,
|
||||
backgroundColor: Colors.LightOrange,
|
||||
},
|
||||
closeCardImage: {
|
||||
width: 105,
|
||||
height: 135,
|
||||
@@ -187,6 +241,7 @@ export const DefaultTheme = {
|
||||
height: 300,
|
||||
width: 300,
|
||||
overflow: 'hidden',
|
||||
marginLeft: 18,
|
||||
},
|
||||
scanner: {
|
||||
height: 400,
|
||||
@@ -325,6 +380,10 @@ export const DefaultTheme = {
|
||||
clearAddIdBtnBg: {
|
||||
backgroundColor: Colors.Transparent,
|
||||
},
|
||||
radius: {
|
||||
borderRadius: 10,
|
||||
backgroundColor: Colors.Orange,
|
||||
},
|
||||
}),
|
||||
OIDCAuthStyles: StyleSheet.create({
|
||||
viewContainer: {
|
||||
@@ -408,6 +467,18 @@ export const DefaultTheme = {
|
||||
borderTopRightRadius: 0,
|
||||
},
|
||||
}),
|
||||
BindingVcWarningOverlay: StyleSheet.create({
|
||||
overlay: {
|
||||
elevation: 5,
|
||||
backgroundColor: Colors.White,
|
||||
padding: 0,
|
||||
borderRadius: 15,
|
||||
},
|
||||
button: {
|
||||
borderTopLeftRadius: 0,
|
||||
borderTopRightRadius: 0,
|
||||
},
|
||||
}),
|
||||
RevokeStyles: StyleSheet.create({
|
||||
buttonContainer: {
|
||||
position: 'absolute',
|
||||
@@ -577,6 +648,11 @@ export const DefaultTheme = {
|
||||
CloseCard: require('../../../assets/ID-closed.png'),
|
||||
ProfileIcon: require('../../../assets/placeholder-photo.png'),
|
||||
MosipLogo: require('../../../assets/mosip-logo.png'),
|
||||
DomainWarningLogo: require('../../../assets/domain-warning.png'),
|
||||
WarningLogo: require('../../../assets/warningLogo.png'),
|
||||
OtpLogo: require('../../../assets/otp-mobile-logo.png'),
|
||||
SuccessLogo: require('../../../assets/success-logo.png'),
|
||||
|
||||
elevation(level: ElevationLevel): ViewStyle {
|
||||
// https://ethercreative.github.io/react-native-shadow-generator/
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ const Colors = {
|
||||
Green: '#219653',
|
||||
Purple: '#70308C',
|
||||
Transparent: 'transparent',
|
||||
Warning: '#f0ad4e',
|
||||
};
|
||||
|
||||
export type ElevationLevel = 0 | 1 | 2 | 3 | 4 | 5;
|
||||
@@ -30,6 +31,7 @@ export const PurpleTheme = {
|
||||
noUinText: Colors.Purple,
|
||||
IconBg: Colors.Purple,
|
||||
Icon: Colors.Purple,
|
||||
GrayIcon: Colors.Grey,
|
||||
Loading: Colors.Purple,
|
||||
borderBottomColor: Colors.Grey6,
|
||||
whiteBackgroundColor: Colors.White,
|
||||
@@ -56,6 +58,7 @@ export const PurpleTheme = {
|
||||
checkCircleIcon: Colors.White,
|
||||
OnboardingCircleIcon: Colors.White,
|
||||
OnboardingCloseIcon: Colors.White,
|
||||
WarningIcon: Colors.Warning,
|
||||
},
|
||||
Styles: StyleSheet.create({
|
||||
title: {
|
||||
@@ -133,6 +136,8 @@ export const PurpleTheme = {
|
||||
backgroundImageContainer: {
|
||||
flex: 1,
|
||||
padding: 10,
|
||||
borderBottomColor: Colors.Grey,
|
||||
borderBottomWidth: 1,
|
||||
},
|
||||
successTag: {
|
||||
backgroundColor: Colors.Green,
|
||||
@@ -326,6 +331,11 @@ export const PurpleTheme = {
|
||||
clearAddIdBtnBg: {
|
||||
backgroundColor: Colors.Transparent,
|
||||
},
|
||||
radius: {
|
||||
flex: 1,
|
||||
borderRadius: 10,
|
||||
backgroundColor: Colors.Orange,
|
||||
},
|
||||
}),
|
||||
OIDCAuthStyles: StyleSheet.create({
|
||||
viewContainer: {
|
||||
@@ -574,10 +584,25 @@ export const PurpleTheme = {
|
||||
zIndex: 1,
|
||||
},
|
||||
}),
|
||||
BindingVcWarningOverlay: StyleSheet.create({
|
||||
overlay: {
|
||||
elevation: 5,
|
||||
backgroundColor: Colors.White,
|
||||
padding: 0,
|
||||
borderRadius: 15,
|
||||
},
|
||||
button: {
|
||||
borderTopLeftRadius: 0,
|
||||
borderTopRightRadius: 0,
|
||||
},
|
||||
}),
|
||||
OpenCard: require('../../../purpleAassets/bg_cart_one.png'),
|
||||
CloseCard: require('../../../purpleAassets/cart_unsel.png'),
|
||||
ProfileIcon: require('../../../purpleAassets/profile_icon_unsel.png'),
|
||||
MosipLogo: require('../../../purpleAassets/logo.png'),
|
||||
WarningLogo: require('../../../assets/warningLogo.png'),
|
||||
OtpLogo: require('../../../assets/otp-mobile-logo.png'),
|
||||
SuccessLogo: require('../../../assets/success-logo.png'),
|
||||
elevation(level: ElevationLevel): ViewStyle {
|
||||
// https://ethercreative.github.io/react-native-shadow-generator/
|
||||
|
||||
|
||||
@@ -302,7 +302,7 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = MOSIPResidentApp/MOSIPResidentApp.entitlements;
|
||||
CURRENT_PROJECT_VERSION = 2;
|
||||
CURRENT_PROJECT_VERSION = 8;
|
||||
DEVELOPMENT_TEAM = 9L83VVTX8B;
|
||||
ENABLE_BITCODE = NO;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
@@ -335,7 +335,7 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = MOSIPResidentApp/MOSIPResidentApp.entitlements;
|
||||
CURRENT_PROJECT_VERSION = 2;
|
||||
CURRENT_PROJECT_VERSION = 8;
|
||||
DEVELOPMENT_TEAM = 9L83VVTX8B;
|
||||
INFOPLIST_FILE = MOSIPResidentApp/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
||||
|
||||
@@ -62,7 +62,7 @@ PODS:
|
||||
- GoogleSymbolUtilities (1.1.2)
|
||||
- GoogleUtilitiesLegacy (1.3.2):
|
||||
- GoogleSymbolUtilities (~> 1.1)
|
||||
- mosip-inji-face-sdk (0.1.1):
|
||||
- mosip-inji-face-sdk (0.1.7):
|
||||
- React-Core
|
||||
- NearbyMessages (1.1.1):
|
||||
- GoogleInterchangeUtilities (~> 1.2)
|
||||
@@ -348,6 +348,8 @@ PODS:
|
||||
- React-Core
|
||||
- RNDeviceInfo (8.7.1):
|
||||
- React-Core
|
||||
- RNFS (2.20.0):
|
||||
- React-Core
|
||||
- RNGestureHandler (2.1.3):
|
||||
- React-Core
|
||||
- RNKeychain (8.0.0):
|
||||
@@ -434,6 +436,7 @@ DEPENDENCIES:
|
||||
- "RNCAsyncStorage (from `../node_modules/@react-native-async-storage/async-storage`)"
|
||||
- "RNCPicker (from `../node_modules/@react-native-picker/picker`)"
|
||||
- RNDeviceInfo (from `../node_modules/react-native-device-info`)
|
||||
- RNFS (from `../node_modules/react-native-fs`)
|
||||
- RNGestureHandler (from `../node_modules/react-native-gesture-handler`)
|
||||
- RNKeychain (from `../node_modules/react-native-keychain`)
|
||||
- RNPermissions (from `../node_modules/react-native-permissions`)
|
||||
@@ -571,6 +574,8 @@ EXTERNAL SOURCES:
|
||||
:path: "../node_modules/@react-native-picker/picker"
|
||||
RNDeviceInfo:
|
||||
:path: "../node_modules/react-native-device-info"
|
||||
RNFS:
|
||||
:path: "../node_modules/react-native-fs"
|
||||
RNGestureHandler:
|
||||
:path: "../node_modules/react-native-gesture-handler"
|
||||
RNKeychain:
|
||||
@@ -613,13 +618,13 @@ SPEC CHECKSUMS:
|
||||
EXUpdates: a83e036243b0f6ece53a8c1cb883b6751c88a5f8
|
||||
EXUpdatesInterface: a9814f422d3cd6e7cfd260d13c27786148ece20e
|
||||
FBLazyVector: fa8275d5086566e22a26ddc385ab5772e7f9b1bd
|
||||
FBReactNativeSpec: 7ead992e0bbaf608b93d456361caa6ccf6745df5
|
||||
FBReactNativeSpec: c3dafd68550f3c95f009beee5c20ab07949ec4e4
|
||||
glog: 73c2498ac6884b13ede40eda8228cb1eee9d9d62
|
||||
GoogleInterchangeUtilities: d5bc4d88d5b661ab72f9d70c58d02ca8c27ad1f7
|
||||
GoogleNetworkingUtilities: 3edd3a8161347494f2da60ea0deddc8a472d94cb
|
||||
GoogleSymbolUtilities: 631ee17048aa5e9ab133470d768ea997a5ef9b96
|
||||
GoogleUtilitiesLegacy: 5501bedec1646bd284286eb5fc9453f7e23a12f4
|
||||
mosip-inji-face-sdk: f0e765373b50324243d904e45eb3ce899db951ac
|
||||
mosip-inji-face-sdk: a1355473a393f2cdd6d927c51af4363be6d97d9f
|
||||
NearbyMessages: bd9e88f2df7fbab78be58fed58580d5d5bd62cbf
|
||||
Permission-BluetoothPeripheral: 67708853584bb9208c76d36d0e0ea4eafb97ea5b
|
||||
Permission-Camera: bf6791b17c7f614b6826019fcfdcc286d3a107f6
|
||||
@@ -655,6 +660,7 @@ SPEC CHECKSUMS:
|
||||
RNCAsyncStorage: 6bd5a7ba3dde1c3facba418aa273f449bdc5437a
|
||||
RNCPicker: cb57c823d5ce8d2d0b5dfb45ad97b737260dc59e
|
||||
RNDeviceInfo: aad3c663b25752a52bf8fce93f2354001dd185aa
|
||||
RNFS: 4ac0f0ea233904cb798630b3c077808c06931688
|
||||
RNGestureHandler: e1099204721a17a89c81fcd1cc2e92143dc040fb
|
||||
RNKeychain: 4f63aada75ebafd26f4bc2c670199461eab85d94
|
||||
RNPermissions: dcdb7b99796bbeda6975a6e79ad519c41b251b1c
|
||||
@@ -666,6 +672,6 @@ SPEC CHECKSUMS:
|
||||
Yoga: d1fc3575b8b68891ff5ef3c276daa855e841eb32
|
||||
ZXingObjC: fdbb269f25dd2032da343e06f10224d62f537bdb
|
||||
|
||||
PODFILE CHECKSUM: 24c315d126fc2b5fef6a2828f16ec02b341154fe
|
||||
PODFILE CHECKSUM: aca728a65db3db54edf138095b290280c97a5389
|
||||
|
||||
COCOAPODS: 1.11.3
|
||||
|
||||
@@ -34,7 +34,18 @@
|
||||
"id": "Id",
|
||||
"nationalCard": "البطاقة الوطنية",
|
||||
"uin": "UIN",
|
||||
"vid": "VID"
|
||||
"enableVerification": "تفعيل",
|
||||
"profileAuthenticated": "تم تنشيطه لتسجيل الدخول عبر الإنترنت",
|
||||
"offlineAuthDisabledHeader": "التنشيط معلق لتسجيل الدخول عبر الإنترنت",
|
||||
"offlineAuthDisabledMessage": "الرجاء النقر فوق الزر أدناه لتفعيل بيانات الاعتماد هذه لاستخدامها في تسجيل الدخول عبر الإنترنت.",
|
||||
"vid": "VID",
|
||||
"verificationEnabledSuccess": "تم تنشيطه لتسجيل الدخول عبر الإنترنت",
|
||||
"goback": "عُد",
|
||||
"BindingWarning": "لقد قمت بالفعل بتنشيط تسجيل الدخول عبر الإنترنت لبيانات الاعتماد هذه على جهاز آخر. لن تتمكن بعد الآن من استخدام هذا الجهاز لتسجيل الدخول إذا قمت بتنشيطه مرة أخرى على هذا الجهاز.",
|
||||
"yes_confirm": "نعم ، أنا أؤكد",
|
||||
"no": "رقم",
|
||||
"Alert": "انذار",
|
||||
"ok": "تمام"
|
||||
},
|
||||
"AuthScreen": {
|
||||
"header": "هل ترغب في استخدام المقاييس الحيوية لفتح التطبيق؟",
|
||||
@@ -98,7 +109,8 @@
|
||||
"requestingOTP": "طلب OTP..."
|
||||
},
|
||||
"OtpVerificationModal": {
|
||||
"enterOtp": "أدخل رمز التحقق المكون من 6 أرقام الذي أرسلناه إليك"
|
||||
"enterOtp": "أدخل رمز التحقق المكون من 6 أرقام الذي أرسلناه إليك",
|
||||
"header": "التحقق من OTP"
|
||||
},
|
||||
"MyVcsTab": {
|
||||
"addVcButton": "{{vcLabel}} إضافة",
|
||||
@@ -129,6 +141,7 @@
|
||||
"requestingOtp": "جارٍ طلب OTP...",
|
||||
"editTag": "टتحرير العلامة",
|
||||
"redirecting": "إعادة توجيه...",
|
||||
"inProgress": "جار التحميل...",
|
||||
"success": {
|
||||
"unlocked": "تم إلغاء قفل {{vcLabel}} بنجاح",
|
||||
"locked": "تم قفل {{vcLabel}} بنجاح",
|
||||
@@ -166,6 +179,26 @@
|
||||
"revokeSuccessful": "تم إبطال VID بنجاح",
|
||||
"version": "الإصدار"
|
||||
},
|
||||
"QrScreen": {
|
||||
"title": "QR تسجيل الدخول",
|
||||
"alignQr": "قم بمحاذاة رمز الاستجابة السريعة داخل الإطار للمسح الضوئي",
|
||||
"confirmation": "تأكيد",
|
||||
"checkDomain": "تحقق أيضًا من وجود رمز قفل على شريط العناوين.",
|
||||
"domainHead": "https://",
|
||||
"selectId": "حدد المعرف",
|
||||
"noBindedVc": "لا يوجد {{vcLabel}} مرتبط متاح للتحقق",
|
||||
"back": "عُد",
|
||||
"confirm": "يتأكد",
|
||||
"verify": "تحقق",
|
||||
"faceAuth": "مصادقة الوجه",
|
||||
"consent": "موافقة",
|
||||
"loading": "جار التحميل...",
|
||||
"domainWarning": "يرجى تأكيد مجال موقع الويب الذي تقوم بمسح رمز الاستجابة السريعة منه على النحو التالي",
|
||||
"access": " يطلب الوصول إلى",
|
||||
"status": "حالة",
|
||||
"successMessage":"لقد قمت بتسجيل الدخول بنجاح ",
|
||||
"okay": "تمام"
|
||||
},
|
||||
"ReceiveVcScreen": {
|
||||
"header": "تفاصيل {{vcLabel}}",
|
||||
"acceptRequest": "قبول الطلب واستلام {{vcLabel}}",
|
||||
|
||||
BIN
locales/bkp-12-12-22.zip
Normal file
BIN
locales/bkp-12-12-22.zip
Normal file
Binary file not shown.
@@ -1,4 +1,18 @@
|
||||
{
|
||||
"ActivityLogText": {
|
||||
"VC_SHARED": "shared",
|
||||
"VC_RECEIVED": "received",
|
||||
"VC_RECEIVED_NOT_SAVED": "received was not saved",
|
||||
"VC_DELETED": "deleted",
|
||||
"VC_DOWNLOADED": "downloaded",
|
||||
"VC_REVOKED": "revoked",
|
||||
"VC_SHARED_WITH_VERIFICATION_CONSENT": "shared. Consent is given for presence verification",
|
||||
"VC_RECEIVED_WITH_PRESENCE_VERIFIED": "received. Presence verified",
|
||||
"VC_RECEIVED_BUT_PRESENCE_VERIFICATION_FAILED": "received. Presence verification failed",
|
||||
"PRESENCE_VERIFIED_AND_VC_SHARED": "verified and shared",
|
||||
"PRESENCE_VERIFICATION_FAILED": "verification failed",
|
||||
"QRLOGIN_SUCCESFULL": "QRLogin sucessfull"
|
||||
},
|
||||
"DeviceInfoList": {
|
||||
"requestedBy": "Requested by",
|
||||
"sentBy": "Sent by",
|
||||
@@ -34,7 +48,18 @@
|
||||
"id": "Id",
|
||||
"nationalCard": "National Card",
|
||||
"uin": "UIN",
|
||||
"vid": "VID"
|
||||
"enableVerification": "Activate",
|
||||
"profileAuthenticated": "Activated for online login",
|
||||
"offlineAuthDisabledHeader": "Activation pending for online login",
|
||||
"offlineAuthDisabledMessage": "Please click the button below to activate this credential to be used for online login.",
|
||||
"vid": "VID",
|
||||
"verificationEnabledSuccess": "Activated for online login",
|
||||
"goback": "GO BACK",
|
||||
"BindingWarning": "You have already activated online login for this credential on another device. You will no longer be able to use that device for login if you activate it again on this device.",
|
||||
"yes_confirm": "Yes, I Confirm",
|
||||
"no": "No",
|
||||
"Alert": "Alert",
|
||||
"ok": "Okay"
|
||||
},
|
||||
"AuthScreen": {
|
||||
"header": "Would you like to use biometrics to unlock the application?",
|
||||
@@ -98,7 +123,8 @@
|
||||
"requestingOTP": "Requesting OTP..."
|
||||
},
|
||||
"OtpVerificationModal": {
|
||||
"enterOtp": "Enter the 6-digit verification code we sent you"
|
||||
"enterOtp": "Enter the 6-digit verification code we sent you",
|
||||
"header": "OTP Verification"
|
||||
},
|
||||
"MyVcsTab": {
|
||||
"addVcButton": "Add {{vcLabel}}",
|
||||
@@ -129,6 +155,7 @@
|
||||
"requestingOtp": "Requesting OTP...",
|
||||
"editTag": "Rename",
|
||||
"redirecting": "Redirecting...",
|
||||
"inProgress": "Loading...",
|
||||
"success": {
|
||||
"unlocked": "{{vcLabel}} successfully unlocked",
|
||||
"locked": "{{vcLabel}} successfully locked",
|
||||
@@ -168,11 +195,31 @@
|
||||
"useBle": "Powered by BLE",
|
||||
"useGoogleNearby": "Powered by GoogleNearby"
|
||||
},
|
||||
"QrScreen": {
|
||||
"title": "QR Login",
|
||||
"alignQr": "Align the QR code within the frame to scan",
|
||||
"confirmation": "Confirmation",
|
||||
"checkDomain": "Also, check that there is a lock icon on the address bar.",
|
||||
"domainHead": "https://",
|
||||
"selectId": "Select ID",
|
||||
"noBindedVc": "No Binded {{vcLabel}} Available to Verify",
|
||||
"back": "Go Back",
|
||||
"confirm": "Confirm",
|
||||
"verify": "Verify",
|
||||
"faceAuth": "Face Authentication",
|
||||
"consent": "Consent",
|
||||
"loading": "Loading...",
|
||||
"domainWarning": "Please confirm the domain of the website you are scanning the QR code from is as below",
|
||||
"access": " is requesting access to",
|
||||
"status": "Status",
|
||||
"successMessage": "You Have Successfully Logged Into ",
|
||||
"okay": "Okay"
|
||||
},
|
||||
"ReceiveVcScreen": {
|
||||
"header": "{{vcLabel}} details",
|
||||
"acceptRequest": "Accept request and receive {{vcLabel}}",
|
||||
"acceptRequestAndVerify": "Accept request and verify",
|
||||
"reject": "Reject"
|
||||
"save": "Save {{vcLabel}}",
|
||||
"verifyAndSave": "Verify and save",
|
||||
"discard": "Discard"
|
||||
},
|
||||
"RequestScreen": {
|
||||
"bluetoothDenied": "Please enable Bluetooth to be able to request {{vcLabel}}",
|
||||
@@ -186,7 +233,7 @@
|
||||
},
|
||||
"rejected": {
|
||||
"title": "Notice",
|
||||
"message": "You rejected {{sender}}'s {{vcLabel}}"
|
||||
"message": "You discarded {{sender}}'s {{vcLabel}}"
|
||||
},
|
||||
"disconnected": {
|
||||
"title": "Disconnected",
|
||||
@@ -200,6 +247,9 @@
|
||||
"connected": {
|
||||
"message": "Connected to the device. Waiting for {{vcLabel}}...",
|
||||
"timeoutHint": "No data received yet. Is sending device still connected?"
|
||||
},
|
||||
"offline": {
|
||||
"message": "Please connect to the internet to enable Online sharing mode"
|
||||
}
|
||||
},
|
||||
"online": "Online",
|
||||
@@ -225,7 +275,10 @@
|
||||
"connectingTimeout": "It's taking a while to establish the connection. Is the other device open for connections?",
|
||||
"exchangingDeviceInfo": "Exchanging device info...",
|
||||
"exchangingDeviceInfoTimeout": "It's taking a while to exchange device info. You may have to reconnect.",
|
||||
"invalid": "Invalid QR Code"
|
||||
"invalid": "Invalid QR Code",
|
||||
"offline": "Please connect to the internet to scan QR codes using Online sharing mode",
|
||||
"sent": "{{ vcLabel }} has been sent...",
|
||||
"sentHint": "Waiting for receiver to save or discard your {{ vcLabel }}"
|
||||
}
|
||||
},
|
||||
"SelectVcOverlay": {
|
||||
@@ -251,7 +304,7 @@
|
||||
},
|
||||
"rejected": {
|
||||
"title": "Notice",
|
||||
"message": "Your {{vcLabel}} was rejected by {{receiver}}"
|
||||
"message": "Your {{vcLabel}} was discarded by {{receiver}}"
|
||||
}
|
||||
},
|
||||
"consentToPhotoVerification": "I give consent to have my photo taken for authentication"
|
||||
|
||||
@@ -1,4 +1,17 @@
|
||||
{
|
||||
"ActivityLogText": {
|
||||
"VC_SHARED": "ibinahagi",
|
||||
"VC_RECEIVED": "natanggap",
|
||||
"VC_RECEIVED_NOT_SAVED": "natanggap ngunit hindi na-save",
|
||||
"VC_DELETED": "tinanggal",
|
||||
"VC_DOWNLOADED": "na-download",
|
||||
"VC_REVOKED": "binawi",
|
||||
"VC_SHARED_WITH_VERIFICATION_CONSENT": "ibinahagi. Ibinibigay ang pahintulot para sa pag-verify ng presensya",
|
||||
"VC_RECEIVED_WITH_PRESENCE_VERIFIED": "natanggap. Na-verify ang presensya",
|
||||
"VC_RECEIVED_BUT_PRESENCE_VERIFICATION_FAILED": "natanggap. Nabigo ang pag-verify ng presensya",
|
||||
"PRESENCE_VERIFIED_AND_VC_SHARED": "na-verify at ibinahagi",
|
||||
"PRESENCE_VERIFICATION_FAILED": "nabigo ang pag-verify"
|
||||
},
|
||||
"DeviceInfoList": {
|
||||
"requestedBy": "Hiniling ni",
|
||||
"sentBy": "Ipinadala ni",
|
||||
@@ -34,7 +47,18 @@
|
||||
"id": "Id",
|
||||
"nationalCard": "Pambansang Kard",
|
||||
"uin": "UIN",
|
||||
"vid": "VID"
|
||||
"enableVerification": "I-activate",
|
||||
"profileAuthenticated": "Na-activate para sa online na pag-login",
|
||||
"offlineAuthDisabledHeader": "Nakabinbin ang pag-activate para sa online na pag-login",
|
||||
"offlineAuthDisabledMessage": "Mangyaring i-click ang pindutan sa ibaba upang i-activate ang kredensyal na ito upang magamit para sa online na pag-login.",
|
||||
"vid": "VID",
|
||||
"verificationEnabledSuccess": "Na-activate para sa online na pag-login",
|
||||
"goback": "BUMALIK KA",
|
||||
"BindingWarning": "Na-activate mo na ang isang online na pag-log in para sa kredensyal na ito sa isa pang device. Hindi mo na magagamit ang device na iyon para sa pag-login kung i-activate mo itong muli sa device na ito.",
|
||||
"yes_confirm": "Oo, Kinukumpirma ko",
|
||||
"no": "Hindi",
|
||||
"Alert": "Alerto",
|
||||
"ok": "Sige"
|
||||
},
|
||||
"AuthScreen": {
|
||||
"header": "Gusto mo bang gumamit ng biometrics upang i-unlock ang aplikasyon?",
|
||||
@@ -42,7 +66,7 @@
|
||||
"usePasscode": "Gumamit na lang ng passcode",
|
||||
"errors": {
|
||||
"unavailable": "Hindi sinusuportahan ng device ang Biometrics",
|
||||
"unenrolled": "Upang magamit ang Biometrics, mangyaring i-enroll ang iyong biometrics sa mga setting ng iyong device",
|
||||
"unenrolled": "Upang magamit ang Biometrics, mangyaring i-enroll ang iyong fingerprint sa mga setting ng iyong device",
|
||||
"failed": "Nabigong mag-authenticate gamit ang Biometrics",
|
||||
"generic": "May problema sa Biometrics authentication"
|
||||
}
|
||||
@@ -83,22 +107,14 @@
|
||||
"bodyText": "Maaaring tumagal ito ng ilang oras, ipapaalam namin sayo kung pwede na kunin ang iyong {{vcLabel}}",
|
||||
"backButton": "Bumalik"
|
||||
},
|
||||
"GetIdInputModal": {
|
||||
"header": "Upang makuha ang iyong UIN o VID, ilagay ang iyong Application {{vcLabel}} na numero",
|
||||
"getUIN": "Kumuha ng UIN/VID",
|
||||
"applicationId": "Numero ng application na {{vcLabel}}.",
|
||||
"requestingOTP": "Humihiling ng OTP...",
|
||||
"qstnMarkToolTip": "Ang numero ng aplikasyon {{vcLabel}} ay naka-print sa ibinigay na pagkilala pagkatapos ng pagpapatala"
|
||||
},
|
||||
"IdInputModal": {
|
||||
"header": "Ilagay ang UIN o VID na ibinigay ng MOSIP upang matanggap ang iyong {{vcLabel}}",
|
||||
"generateVc": "Gumawa ng {{vcLabel}}",
|
||||
"enterId": "Ilagay ang iyong {{idType}}",
|
||||
"noUIN/VID": "Wala ka bang UIN/VID? Kuhanin dito",
|
||||
"requestingOTP": "Humihiling ng OTP..."
|
||||
"enterId": "Ilagay ang iyong {{idType}}"
|
||||
},
|
||||
"OtpVerificationModal": {
|
||||
"enterOtp": "Ilagay ang 6 na numerong verification code na ipinadala namin sayo"
|
||||
"enterOtp": "Ilagay ang 6 na numerong verification code na ipinadala namin sayo",
|
||||
"header": "Pag-verify ng OTP"
|
||||
},
|
||||
"MyVcsTab": {
|
||||
"addVcButton": "Magdagdag ng {{vcLabel}}",
|
||||
@@ -129,6 +145,7 @@
|
||||
"requestingOtp": "Humihiling ng OTP...",
|
||||
"editTag": "Palitan ang pangalan",
|
||||
"redirecting": "Redirecting...",
|
||||
"inProgress": "Naglo-load...",
|
||||
"success": {
|
||||
"unlocked": "Ang {{vcLabel}} ay matagumpay na na-unlock",
|
||||
"locked": "Ang {{vcLabel}} ay matagumpay na na-lock",
|
||||
@@ -166,10 +183,29 @@
|
||||
"revokeSuccessful": "Matagumpay na nakansela ang VID",
|
||||
"version": "Bersyon"
|
||||
},
|
||||
"QrScreen": {
|
||||
"title": "QR Login",
|
||||
"alignQr": "I-align ang QR code sa loob ng frame para i-scan",
|
||||
"confirmation": "Kumpirmasyon",
|
||||
"checkDomain": "Gayundin, tingnan kung mayroong icon ng lock sa address bar.",
|
||||
"domainHead": "https://",
|
||||
"selectId": "Pumili ng ID",
|
||||
"noBindedVc": "Available sa Verifyct ID ang SeleNo Binded {{vcLabel}}",
|
||||
"back": "Bumalik ka",
|
||||
"confirm": "Kumpirmahin",
|
||||
"verify": "I-verify",
|
||||
"faceAuth": "Face Authentication",
|
||||
"consent": "Pagpayag",
|
||||
"loading": "Naglo-load...",
|
||||
"domainWarning": "Pakikumpirma ang domain ng website kung saan mo ini-scan ang QR code mula sa ibaba",
|
||||
"access": " ay humihiling ng access sa",
|
||||
"status": "Katayuan",
|
||||
"successMessage":"Ikaw ay Matagumpay na Naka-log In ",
|
||||
"okay": "Sige"
|
||||
},
|
||||
"ReceiveVcScreen": {
|
||||
"header": "Mga detalye ng {{vcLabel}}",
|
||||
"acceptRequest": "Tanggapin ang kahilingan at tumanggap ng {{vcLabel}}",
|
||||
"acceptRequestAndVerify": "Tanggapin ang kahilingan at magpatunay",
|
||||
"reject": "Tanggihan"
|
||||
},
|
||||
"RequestScreen": {
|
||||
@@ -184,7 +220,7 @@
|
||||
},
|
||||
"rejected": {
|
||||
"title": "Paunawa",
|
||||
"message": "Tinanggihan mo ang {{vcLabel}} ni {{sender}}"
|
||||
"message": "Iwinaksi ang {{vcLabel}} ni {{sender}}"
|
||||
},
|
||||
"disconnected": {
|
||||
"title": "Nadiskonekta",
|
||||
@@ -197,7 +233,7 @@
|
||||
},
|
||||
"connected": {
|
||||
"message": "Nakakonektang device. Naghihintay para sa {{vcLabel}}...",
|
||||
"timeoutHint": "Wala pang data na natanggap. Nakakonekta pa rin ba ang nagpapadala na device?"
|
||||
"timeoutHint": "Wala pang natanggap na VC. Nakakonekta pa rin ba ang pagpapadala ng device?"
|
||||
}
|
||||
},
|
||||
"online": "Online",
|
||||
@@ -223,7 +259,10 @@
|
||||
"connectingTimeout": "Medyo nagtatagal bago magtatag ng koneksyon. Bukas ba ang ibang device para sa mga koneksyon?",
|
||||
"exchangingDeviceInfo": "Nagpapalitan ng impormasyon ng device...",
|
||||
"exchangingDeviceInfoTimeout": "Medyo nagtatagal ang paglabas ng impormasyon ng device. Bukas ba ang ibang device para sa mga koneksyon?",
|
||||
"invalid": "Di-wasto ang QR Code"
|
||||
"invalid": "Di-wasto ang QR Code",
|
||||
"offline": "Mangyaring kumonekta sa internet upang makapag-scan ng QR codes na gumagamit ng Online sharing mode",
|
||||
"sent": "Naibahagi na ang {{vcLabel}}...",
|
||||
"sentHint": "Iniintay ang nakatanggap na itabi o iwaksi ang iyong {{vcLabel}}"
|
||||
}
|
||||
},
|
||||
"SelectVcOverlay": {
|
||||
@@ -235,13 +274,11 @@
|
||||
"SendVcScreen": {
|
||||
"reasonForSharing": "Dahilan ng pagbabahagi (opsyonal)",
|
||||
"acceptRequest": "Tanggapin ang kahilingan at piliin ang {{vcLabel}}",
|
||||
"acceptRequestAndVerify": "Tanggapin ang kahilingan at magpatunay",
|
||||
"reject": "Tanggihan",
|
||||
"status": {
|
||||
"sharing": {
|
||||
"title": "Pagbabahagi",
|
||||
"hint": "Pakihintay na tanggapin o tanggihan ng tumatanggap na device ang pagbabahagi.",
|
||||
"timeoutHint": "May katagalan ang pagbabahagi. Maaaring may problema sa koneksyon."
|
||||
"timeoutHint": "Medyo natatagal ang pagbabahagi ng VC. Maaaring may problema sa koneksyon."
|
||||
},
|
||||
"accepted": {
|
||||
"title": "Tagumpay!",
|
||||
@@ -261,8 +298,7 @@
|
||||
"errors": {
|
||||
"invalidIdentity": {
|
||||
"title": "Hindi ma-verify ang pagkakakilanlan",
|
||||
"message": "May naganap na error at hindi namin ma-scan ang iyong larawan. Subukang muli, tiyaking nakikita ang iyong mukha, walang anumang mga aksesorya.",
|
||||
"messageNoRetry": "May naganap na error at hindi namin ma-scan ang iyong portrait."
|
||||
"message": "May naganap na error at hindi namin ma-scan ang iyong portrait. Subukang muli, tiyaking nakikita ang iyong mukha, walang anumang mga accessory."
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -274,14 +310,7 @@
|
||||
"common": {
|
||||
"cancel": "Kanselahin",
|
||||
"save": "I-save",
|
||||
"dismiss": "I-dismiss",
|
||||
"editLabel": "Palitan ang {{label}}",
|
||||
"tryAgain": "Subukan muli",
|
||||
"camera": {
|
||||
"errors": {
|
||||
"missingPermission": "Ginagamit ng app na ito ang camera upang i-scan ang QR code ng isa pang device."
|
||||
},
|
||||
"allowAccess": "Payagan ang access sa camera"
|
||||
}
|
||||
"tryAgain": "Subukan muli"
|
||||
}
|
||||
}
|
||||
@@ -19,22 +19,33 @@
|
||||
"allowCameraButton": "कैमरे तक पहुंच की अनुमति दें"
|
||||
},
|
||||
"VcDetails": {
|
||||
"generatedOn": "जेनरेट ऑन",
|
||||
"status": "स्थिति",
|
||||
"generatedOn": "पर उत्पन्न हुआ",
|
||||
"status": "दर्जा",
|
||||
"valid": "वैध",
|
||||
"photo": "फोटो",
|
||||
"photo": "फ़ोटो",
|
||||
"fullName": "पूरा नाम",
|
||||
"gender": "लिंग",
|
||||
"dateOfBirth": "डेट ऑफ़ बर्थ",
|
||||
"dateOfBirth": "जन्म की तारीख",
|
||||
"phoneNumber": "फ़ोन नंबर",
|
||||
"email": "ईमेल",
|
||||
"address": "पता",
|
||||
"reasonForSharing": "साझा करने का कारण",
|
||||
"idType": "आईडी का प्रकार",
|
||||
"id": "Id",
|
||||
"idType": "पहचान का प्रकार",
|
||||
"id": "पहचान",
|
||||
"nationalCard": "राष्ट्रीय कार्ड",
|
||||
"uin": "UIN",
|
||||
"vid": "VID"
|
||||
"enableVerification": "सक्रिय",
|
||||
"profileAuthenticated": "ऑनलाइन लॉगिन के लिए सक्रिय",
|
||||
"offlineAuthDisabledHeader": "ऑनलाइन लॉगिन के लिए सक्रियता लंबित है",
|
||||
"offlineAuthDisabledMessage": "ऑनलाइन लॉगिन के लिए उपयोग किए जाने वाले इस क्रेडेंशियल को सक्रिय करने के लिए कृपया नीचे दिए गए बटन पर क्लिक करें।",
|
||||
"vid": "VID",
|
||||
"verificationEnabledSuccess": "ऑनलाइन लॉगिन के लिए सक्रिय",
|
||||
"goback": "वापस जाओ",
|
||||
"BindingWarning": "आप इस क्रेडेंशियल के लिए किसी दूसरे डिवाइस पर ऑनलाइन लॉगिन पहले ही सक्रिय कर चुके हैं. यदि आप इसे इस डिवाइस पर फिर से सक्रिय करते हैं तो आप लॉगिन के लिए उस डिवाइस का उपयोग नहीं कर पाएंगे।",
|
||||
"yes_confirm": "हां, मैं पुष्टि करता हूं",
|
||||
"no": "नहीं",
|
||||
"Alert": "चेतावनी",
|
||||
"ok": "ठीक"
|
||||
},
|
||||
"AuthScreen": {
|
||||
"header": "क्या आप एप्लिकेशन को अनलॉक करने के लिए बायोमेट्रिक्स का उपयोग करना चाहेंगे?",
|
||||
@@ -98,7 +109,8 @@
|
||||
"requestingOTP": "OTP का अनुरोध..."
|
||||
},
|
||||
"OtpVerificationModal": {
|
||||
"enterOtp": "हमारे द्वारा भेजा गया 6 अंकों का सत्यापन कोड दर्ज करें"
|
||||
"enterOtp": "हमारे द्वारा भेजा गया 6 अंकों का सत्यापन कोड दर्ज करें",
|
||||
"header": "ओटीपी सत्यापन"
|
||||
},
|
||||
"MyVcsTab": {
|
||||
"addVcButton": "{{vcLabel}} जोड़ें",
|
||||
@@ -129,6 +141,7 @@
|
||||
"requestingOtp": "OTP का अनुरोध...",
|
||||
"editTag": "टैग संपादित करें",
|
||||
"redirecting": "पुन: निर्देशित...",
|
||||
"inProgress": "लोड हो रहा है...",
|
||||
"success": {
|
||||
"unlocked": "{{vcLabel}} सफलतापूर्वक अनलॉक किया गया",
|
||||
"locked": "{{vcLabel}} सफलतापूर्वक लॉक हो गया",
|
||||
@@ -166,6 +179,26 @@
|
||||
"revokeSuccessful": "VID को सफलतापूर्वक निरस्त कर दिया गया",
|
||||
"version": "संस्करण"
|
||||
},
|
||||
"QrScreen": {
|
||||
"title": "क्यूआर लॉगिन",
|
||||
"alignQr": "स्कैन करने के लिए फ्रेम के भीतर क्यूआर कोड को संरेखित करें",
|
||||
"confirmation": "पुष्टीकरण",
|
||||
"checkDomain": "यह भी जांचें कि एड्रेस बार पर लॉक आइकन है।",
|
||||
"domainHead": "https://",
|
||||
"selectId": "आईडी चुनें",
|
||||
"noBindedVc": "सत्यापित करने के लिए कोई आबद्ध {{vcLabel}} उपलब्ध नहीं है",
|
||||
"back": "वापस जाओ",
|
||||
"confirm": "पुष्टि करें",
|
||||
"verify": "सत्यापित करना",
|
||||
"faceAuth": "चेहरा प्रमाणीकरण",
|
||||
"consent": "अनुमति",
|
||||
"loading": "लोड हो रहा है...",
|
||||
"domainWarning": "कृपया उस वेबसाइट के डोमेन की पुष्टि करें जिसे आप नीचे दिए गए क्यूआर कोड से स्कैन कर रहे हैं",
|
||||
"access": " तक पहुंच का अनुरोध कर रहा है",
|
||||
"status": "दर्जा",
|
||||
"successMessage":"आपने सफलतापूर्वक लॉग इन कर लिया है ",
|
||||
"okay": "ठीक"
|
||||
},
|
||||
"ReceiveVcScreen": {
|
||||
"header": "{{vcLabel}} विवरण",
|
||||
"acceptRequest": "अनुरोध स्वीकार करें और {{vcLabel}} प्राप्त करें",
|
||||
|
||||
@@ -34,7 +34,18 @@
|
||||
"id": "Id",
|
||||
"nationalCard": "ರಾಷ್ಟ್ರೀಯ ಕಾರ್ಡ್",
|
||||
"uin": "UIN",
|
||||
"vid": "VID"
|
||||
"enableVerification": "ಸಕ್ರಿಯಗೊಳಿಸಿ",
|
||||
"profileAuthenticated": "ಆನ್ಲೈನ್ ಲಾಗಿನ್ಗಾಗಿ ಸಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ",
|
||||
"offlineAuthDisabledHeader": "ಆನ್ಲೈನ್ ಲಾಗಿನ್ಗಾಗಿ ಸಕ್ರಿಯಗೊಳಿಸುವಿಕೆ ಬಾಕಿ ಉಳಿದಿದೆ",
|
||||
"offlineAuthDisabledMessage": "ಆನ್ಲೈನ್ ಲಾಗಿನ್ಗಾಗಿ ಬಳಸಲು ಈ ರುಜುವಾತುಗಳನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಲು ದಯವಿಟ್ಟು ಕೆಳಗಿನ ಬಟನ್ ಅನ್ನು ಕ್ಲಿಕ್ ಮಾಡಿ.",
|
||||
"vid": "VID",
|
||||
"verificationEnabledSuccess": "ಆನ್ಲೈನ್ ಲಾಗಿನ್ಗಾಗಿ ಸಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ",
|
||||
"goback": "ಹಿಂದೆ ಹೋಗು",
|
||||
"BindingWarning": "ನೀವು ಈಗಾಗಲೇ ಇನ್ನೊಂದು ಸಾಧನದಲ್ಲಿ ಈ ರುಜುವಾತುಗಳಿಗಾಗಿ ಆನ್ಲೈನ್ ಲಾಗಿನ್ ಅನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿದ್ದೀರಿ. ಈ ಸಾಧನದಲ್ಲಿ ನೀವು ಅದನ್ನು ಮತ್ತೆ ಸಕ್ರಿಯಗೊಳಿಸಿದರೆ ಲಾಗಿನ್ಗಾಗಿ ಆ ಸಾಧನವನ್ನು ಬಳಸಲು ನಿಮಗೆ ಇನ್ನು ಮುಂದೆ ಸಾಧ್ಯವಾಗುವುದಿಲ್ಲ.",
|
||||
"yes_confirm": "ಹೌದು, ನಾನು ದೃಢೀಕರಿಸುತ್ತೇನೆ",
|
||||
"no": "ಸಂ",
|
||||
"Alert": "ಎಚ್ಚರಿಕೆ",
|
||||
"ok": "ಸರಿ"
|
||||
},
|
||||
"AuthScreen": {
|
||||
"header": "ಅಪ್ಲಿಕೇಶನ್ ಅನ್ಲಾಕ್ ಮಾಡಲು ಬಯೋಮೆಟ್ರಿಕ್ಸ್ ಬಳಸಲು ನೀವು ಬಯಸುವಿರಾ?",
|
||||
@@ -98,7 +109,8 @@
|
||||
"requestingOTP": "OTP ಯನ್ನು ವಿನಂತಿಸಲಾಗುತ್ತಿದೆ..."
|
||||
},
|
||||
"OtpVerificationModal": {
|
||||
"enterOtp": "ನಾವು ನಿಮಗೆ ಕಳುಹಿಸಿದ 6-ಅಂಕಿಯ ಪರಿಶೀಲನೆ ಕೋಡ್ ಅನ್ನು ನಮೂದಿಸಿ"
|
||||
"enterOtp": "ನಾವು ನಿಮಗೆ ಕಳುಹಿಸಿದ 6-ಅಂಕಿಯ ಪರಿಶೀಲನೆ ಕೋಡ್ ಅನ್ನು ನಮೂದಿಸಿ",
|
||||
"header": "OTP ಪರಿಶೀಲನೆ"
|
||||
},
|
||||
"MyVcsTab": {
|
||||
"addVcButton": "ಸೇರಿಸಿ {{vcLabel}}",
|
||||
@@ -129,6 +141,7 @@
|
||||
"requestingOtp": "ಒಟಿಪಿಯನ್ನು ವಿನಂತಿಸಲಾಗುತ್ತಿದೆ...",
|
||||
"editTag": "ಟ್ಯಾಗ್ ಸಂಪಾದಿಸು",
|
||||
"redirecting": "Redirecting...",
|
||||
"inProgress": "ಲೋಡ್ ಆಗುತ್ತಿದೆ...",
|
||||
"success": {
|
||||
"unlocked": "{{vcLabel}} ಅನ್ನು ಯಶಸ್ವಿಯಾಗಿ ಅನ್ಲಾಕ್ ಮಾಡಲಾಗಿದೆ",
|
||||
"locked": "{{vcLabel}} successfully locked",
|
||||
@@ -166,6 +179,26 @@
|
||||
"revokeSuccessful": "VID ಯಶಸ್ವಿಯಾಗಿ ಹಿಂಪಡೆಯಲಾಗಿದೆ",
|
||||
"version": "ಆವೃತ್ತಿ"
|
||||
},
|
||||
"QrScreen": {
|
||||
"title": "QR ಲಾಗಿನ್",
|
||||
"alignQr": "ಸ್ಕ್ಯಾನ್ ಮಾಡಲು ಚೌಕಟ್ಟಿನೊಳಗೆ QR ಕೋಡ್ ಅನ್ನು ಹೊಂದಿಸಿ",
|
||||
"confirmation": "ದೃಢೀಕರಣ",
|
||||
"checkDomain": "ಅಲ್ಲದೆ, ವಿಳಾಸ ಪಟ್ಟಿಯಲ್ಲಿ ಲಾಕ್ ಐಕಾನ್ ಇದೆಯೇ ಎಂದು ಪರಿಶೀಲಿಸಿ.",
|
||||
"domainHead": "https://",
|
||||
"selectId": "ID ಆಯ್ಕೆಮಾಡಿ",
|
||||
"noBindedVc": "ಪರಿಶೀಲಿಸಲು ಯಾವುದೇ ಬೈಂಡೆಡ್ {{vcLabel}} ಲಭ್ಯವಿಲ್ಲ",
|
||||
"back": "ಹಿಂದೆ ಹೋಗು",
|
||||
"confirm": "ದೃಢೀಕರಿಸಿ",
|
||||
"verify": "ಪರಿಶೀಲಿಸಿ",
|
||||
"faceAuth": "ಮುಖದ ದೃಢೀಕರಣ",
|
||||
"consent": "ಒಪ್ಪಿಗೆ",
|
||||
"loading": "ಲೋಡ್ ಆಗುತ್ತಿದೆ...",
|
||||
"domainWarning": "ಕೆಳಗಿನಂತೆ ನೀವು QR ಕೋಡ್ ಅನ್ನು ಸ್ಕ್ಯಾನ್ ಮಾಡುತ್ತಿರುವ ವೆಬ್ಸೈಟ್ನ ಡೊಮೇನ್ ಅನ್ನು ದಯವಿಟ್ಟು ಖಚಿತಪಡಿಸಿ",
|
||||
"access": " ಗೆ ಪ್ರವೇಶವನ್ನು ವಿನಂತಿಸುತ್ತಿದೆ",
|
||||
"status": "ಸ್ಥಿತಿ",
|
||||
"successMessage":"ನೀವು ಯಶಸ್ವಿಯಾಗಿ ಲಾಗ್ ಇನ್ ಆಗಿರುವಿರಿ ",
|
||||
"okay": "ಸರಿ"
|
||||
},
|
||||
"ReceiveVcScreen": {
|
||||
"header": "{{vcLabel}} ವಿವರಗಳು",
|
||||
"acceptRequest": "ವಿನಂತಿಯನ್ನು ಸ್ವೀಕರಿಸಿ ಮತ್ತು {{vcLabel}} ಸ್ವೀಕರಿಸಿ",
|
||||
|
||||
@@ -34,7 +34,18 @@
|
||||
"id": "Id",
|
||||
"nationalCard": "தேசிய அட்டை್",
|
||||
"uin": "UIN",
|
||||
"vid": "VID"
|
||||
"enableVerification": "செயல்படுத்த",
|
||||
"profileAuthenticated": "ஆன்லைன் உள்நுழைவுக்காக செயல்படுத்தப்பட்டது",
|
||||
"offlineAuthDisabledHeader": "ஆன்லைன் உள்நுழைவுக்கான செயல்படுத்தல் நிலுவையில் உள்ளது",
|
||||
"offlineAuthDisabledMessage": "இந்த நற்சான்றிதழை ஆன்லைன் உள்நுழைவுக்குப் பயன்படுத்த, கீழே உள்ள பொத்தானைக் கிளிக் செய்யவும்.",
|
||||
"vid": "VID",
|
||||
"verificationEnabledSuccess": "ஆன்லைன் உள்நுழைவுக்காக செயல்படுத்தப்பட்டது",
|
||||
"goback": "திரும்பி செல்",
|
||||
"BindingWarning": "இந்த நற்சான்றிதழுக்கான ஆன்லைன் உள்நுழைவை வேறொரு சாதனத்தில் ஏற்கனவே செயல்படுத்தியுள்ளீர்கள். இந்தச் சாதனத்தில் மீண்டும் அதைச் செயல்படுத்தினால், உள்நுழைவதற்கு அந்தச் சாதனத்தை இனி உங்களால் பயன்படுத்த முடியாது.",
|
||||
"yes_confirm": "ஆம், நான் உறுதி செய்கிறேன்",
|
||||
"no": "இல்லை",
|
||||
"Alert": "எச்சரிக்கை",
|
||||
"ok": "சரி"
|
||||
},
|
||||
"AuthScreen": {
|
||||
"header": "பயன்பாட்டைத் திறக்க பயோமெட்ரிக்ஸைப் பயன்படுத்த விரும்புகிறீர்களா?",
|
||||
@@ -98,7 +109,8 @@
|
||||
"requestingOTP": "OTP ஐக் கோருகிறது..."
|
||||
},
|
||||
"OtpVerificationModal": {
|
||||
"enterOtp": "நாங்கள் உங்களுக்கு அனுப்பிய 6 இலக்க சரிபார்ப்புக் குறியீட்டை உள்ளிடவும்"
|
||||
"enterOtp": "நாங்கள் உங்களுக்கு அனுப்பிய 6 இலக்க சரிபார்ப்புக் குறியீட்டை உள்ளிடவும்",
|
||||
"header": "OTP சரிபார்ப்பு"
|
||||
},
|
||||
"MyVcsTab": {
|
||||
"addVcButton": "{{vcLabel}} சேர்",
|
||||
@@ -129,6 +141,7 @@
|
||||
"requestingOtp": "ஓடிபியைக் கோருகிறது...",
|
||||
"editTag": "திருத்து குறி",
|
||||
"redirecting": "வழிமாற்று...",
|
||||
"inProgress": "ஏற்றுகிறது...",
|
||||
"success": {
|
||||
"unlocked": "{{vcLabel}} வெற்றிகரமாக திறக்கப்பட்டது",
|
||||
"locked": "{{vcLabel}} வெற்றிகரமாக பூட்டப்பட்டது",
|
||||
@@ -166,6 +179,26 @@
|
||||
"revokeSuccessful": "VID வெற்றிகரமாக ரத்து செய்யப்பட்டது",
|
||||
"version": "பதிப்பு"
|
||||
},
|
||||
"QrScreen": {
|
||||
"title": "QR உள்நுழைவு",
|
||||
"alignQr": "ஸ்கேன் செய்ய ஃப்ரேமுக்குள் QR குறியீட்டை சீரமைக்கவும்",
|
||||
"confirmation": "உறுதிப்படுத்தல்",
|
||||
"checkDomain": "மேலும், முகவரிப் பட்டியில் பூட்டு ஐகான் உள்ளதா எனச் சரிபார்க்கவும்.",
|
||||
"domainHead": "https://",
|
||||
"selectId": "ஐடியைத் தேர்ந்தெடுக்கவும்",
|
||||
"noBindedVc": "சரிபார்க்க, பிணைக்கப்பட்ட {{vcLabel}} எதுவும் இல்லை",
|
||||
"back": "திரும்பி செல்",
|
||||
"confirm": "உறுதிப்படுத்தவும்",
|
||||
"verify": "சரிபார்க்கவும்",
|
||||
"faceAuth": "முக அங்கீகாரம்",
|
||||
"consent": "சம்மதம்",
|
||||
"loading": "ஏற்றுகிறது...",
|
||||
"domainWarning": "நீங்கள் QR குறியீட்டை ஸ்கேன் செய்யும் இணையதளத்தின் டொமைனை கீழே உள்ளவாறு உறுதிப்படுத்தவும்",
|
||||
"access": " அணுகலைக் கோருகிறது",
|
||||
"status": "நிலை",
|
||||
"successMessage":"நீங்கள் வெற்றிகரமாக உள்நுழைந்துள்ளீர்கள் ",
|
||||
"okay": "சரி"
|
||||
},
|
||||
"ReceiveVcScreen": {
|
||||
"header": "{{vcLabel}} விவரங்கள்",
|
||||
"acceptRequest": "கோரிக்கையை ஏற்று {{vcLabel}} ஐப் பெறவும்",
|
||||
|
||||
421
machines/QrLoginMachine.ts
Normal file
421
machines/QrLoginMachine.ts
Normal file
@@ -0,0 +1,421 @@
|
||||
import {
|
||||
ActorRefFrom,
|
||||
assign,
|
||||
ErrorPlatformEvent,
|
||||
EventFrom,
|
||||
send,
|
||||
StateFrom,
|
||||
sendParent,
|
||||
} from 'xstate';
|
||||
import { createModel } from 'xstate/lib/model';
|
||||
import { AppServices } from '../shared/GlobalContext';
|
||||
import { MY_VCS_STORE_KEY } from '../shared/constants';
|
||||
import { StoreEvents } from './store';
|
||||
import { linkTransactionResponse, VC } from '../types/vc';
|
||||
import { request } from '../shared/request';
|
||||
import { getJwt } from '../shared/cryptoutil/cryptoUtil';
|
||||
import { getPrivateKey } from '../shared/keystore/SecureKeystore';
|
||||
|
||||
const model = createModel(
|
||||
{
|
||||
serviceRefs: {} as AppServices,
|
||||
selectedVc: {} as VC,
|
||||
linkCode: '',
|
||||
myVcs: [] as string[],
|
||||
linkTransactionResponse: {} as linkTransactionResponse,
|
||||
authFactors: [],
|
||||
authorizeScopes: null,
|
||||
clientName: '',
|
||||
configs: {},
|
||||
essentialClaims: [],
|
||||
linkTransactionId: '',
|
||||
logoUrl: '',
|
||||
voluntaryClaims: [],
|
||||
selectedVoluntaryClaims: [],
|
||||
errorMessage: '',
|
||||
consentClaims: ['name', 'picture'],
|
||||
isSharing: {},
|
||||
},
|
||||
{
|
||||
events: {
|
||||
SELECT_VC: (vc: VC) => ({ vc }),
|
||||
SCANNING_DONE: (params: string) => ({ params }),
|
||||
STORE_RESPONSE: (response: unknown) => ({ response }),
|
||||
STORE_ERROR: (error: Error) => ({ error }),
|
||||
TOGGLE_CONSENT_CLAIM: (enable: boolean, claim: string) => ({
|
||||
enable,
|
||||
claim,
|
||||
}),
|
||||
DISMISS: () => ({}),
|
||||
CONFIRM: () => ({}),
|
||||
GET: (value: string) => ({ value }),
|
||||
VERIFY: () => ({}),
|
||||
CANCEL: () => ({}),
|
||||
FACE_VALID: () => ({}),
|
||||
FACE_INVALID: () => ({}),
|
||||
RETRY_VERIFICATION: () => ({}),
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
export const QrLoginEvents = model.events;
|
||||
export type QrLoginRef = ActorRefFrom<typeof qrLoginMachine>;
|
||||
|
||||
export const qrLoginMachine =
|
||||
/** @xstate-layout N4IgpgJg5mDOIC5QEUBOAZA9lAlgOwDocIAbMAYgGUBhAQQDl6BJegcQH0ARAeXoFEA2gAYAuolAAHTLBwAXHJjziQAD0QBGACzqATAQCs+nZv0BmABzqL50zoA0IAJ6IA7KaEFNATnPmv6oUMhHUMAX1CHNCxcQmIyck4mSgBZJMphMSQQKRl5RWU1BF1zFwIvHQrTFxdNCxcANgdnBH16j1NbdT8vfW8q9XDIjGx8AhJ8AGsAFVQAQzxYWYBjPLxyCEUwIjwAN0wJraiRwnG8abmF5dWEfD2l2dWMjOUcuQUlLMKtXQMjEwsrL5bE1EF4XOYCEJ6iEXF4ekIOppzIMQEcYmNJjN5osVu9yGBUKhMKgCBISA8AGbEgC2BDRo1O52xV3eN12mHuj1Ezyyr1WBQ0JQhmlhotMZmM+hcIIQNX0nnUhh65h06hcOhKKPphFgAAtMAB3ADqs1QeHwUHI1F4ADEmAAlZI8yTSN75T6IEIeHT+eo1Lyaeriwwy+pggiwtXw9SKjU6LXDdF6w0ms0Wq0Mah8dDO7Ku-kehBegg+9R+7yB4P6GV+dQRlwBIRqoTqjX1BPRUaUfUGviE4kZ+hZnOiF7594Coo9TSQtyqqUx9zApyINpeCNIoVaYzlUwd45jTCzCDJRwANSWsCoU249r47DvlAACrxKIJR7zx+7QIU-fLofoMaATYWjaKGLjylCOjQi4gSmJoOgNPuSY9jsSzoDgsCyFQ2Z8NQUzsGe1C5nyE6Fr4M4BkI3j6DYtEttWK4tDGEb1H6DbmEYAZschozJgaaEYVh5Bnnw9pMDaACaJFfh8P6uLRZRIoqKl0UI5gyiK9SQtobjUZu0KaLxOqoehmHYYkKRpDJuRkfJRTqRCpj1PoTYBj01QVKGPwVIBHT6AGqq1MZBAUssYC0AArrIurkDatBZoRtDoEwnA2W6cmqJ6rklr6-qVoYjHNP4kI2Jo1ENr01EBiFYVLBF0WxfFiUsGeyWpelBb2cWpbltxVahiKuVqmGXT1IG6heLV4VRTFg7Dp1dlZUWOW9flQaFTW2glrBYK0SqZaqiFtyzOMEBMBAYB4PIsiOAkSSpJQ6Qfi6tnfstf4EABQFdKYoHqKG1EECUrnmEIcJ+FC7YRKiiajCdZ0XVdN13XeUz2pJhFiRJTB0FMTC8It72FD1eUVhtIZMQF2mRjUHT1FYPTQ0MnaEKgYAAI6RXAsjUIosDI1atoOk6L15m9mW-hBX0hD9IGaGBTEIfKvTNoGOhVF4zOw6zBDs1zPN8wsgt0EO2ZE5Lq7S99ql-QrANMe4M6RqNDa6NC5hGTD2oEBseAUJZj3PZkr0ZZOAS+AQzmuZNNGefYSshAYunUdCmvaz7+vc1hFpGwL13rJs2x7AcdJw2znPZ-IeBQHnyNsncDzvE8YukcTq42GUYYtuNgFsQGMqqnWNjwSNiFeACe7e+XeuVzzuf84LBJEiSZKUjSZe61n8813X10NxyTeKC3Ifi2HhYR05LluXHrY1qYO2OanY1sciKJ4Jgl3wFk2pjhLk4AFpGhMQAfKOE4CIGQKnizA8cQwB-3PvZYoEJVT+FVCUaC-hNDeXlDYCoipwRCCIeKEKjIsSXFxO9NulsiguWdpYIMQZoK9F6DKOmX0FYQSITHHoU1p6634qmc0NcEFdWWghNh4MCBlnqGDLQ7EAxvxgeibsho+wr1EUtEmLYIQqmjvbeCKoiqrgCCWTc4JtzeA1qQo8J5zyXk0e3BAIph7jTYvBQIwQLDgWdv4Bo5UkTqjMCFfiglzKOJoX4bS4oGyIR9FUIhCdmgMz0EEqw4pApaGgTrA8dUGoxQiZOGoX0Si1CDFYAKCEkkaChKVUeHQNYNGosdXYp1iBI2unIZoocxGFCRHoKU40VT+H2n4QG8oqig3Bj4LwUIXAhW3lhPeshCmFiROucqhlYK6AXA7Zoxg6wTwgv09JHRfAhT9vAz8-9Cz+HXJUxUCIzBIiRJpaCOkRoNlMGCME8EFlzxzrvRe11Vn2RBtI1oDM-pGAsF4GsdZXJEI8n8Go41wjhCAA */
|
||||
model.createMachine(
|
||||
{
|
||||
predictableActionArguments: true,
|
||||
preserveActionOrder: true,
|
||||
tsTypes: {} as import('./QrLoginMachine.typegen').Typegen0,
|
||||
schema: {
|
||||
context: model.initialContext,
|
||||
events: {} as EventFrom<typeof model>,
|
||||
},
|
||||
id: 'QrLogin',
|
||||
initial: 'waitingForData',
|
||||
states: {
|
||||
waitingForData: {
|
||||
on: {
|
||||
GET: {
|
||||
actions: [
|
||||
'setScanData',
|
||||
'resetLinkTransactionId',
|
||||
'resetSelectedVoluntaryClaims',
|
||||
],
|
||||
target: 'linkTransaction',
|
||||
},
|
||||
},
|
||||
},
|
||||
linkTransaction: {
|
||||
invoke: {
|
||||
src: 'linkTransaction',
|
||||
onDone: [
|
||||
{
|
||||
actions: [
|
||||
'setlinkTransactionResponse',
|
||||
'expandLinkTransResp',
|
||||
'setClaims',
|
||||
],
|
||||
target: 'showWarning',
|
||||
},
|
||||
],
|
||||
onError: [
|
||||
{
|
||||
actions: 'SetErrorMessage',
|
||||
target: 'ShowError',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
showWarning: {
|
||||
on: {
|
||||
CONFIRM: {
|
||||
target: 'loadMyVcs',
|
||||
},
|
||||
DISMISS: {
|
||||
actions: 'forwardToParent',
|
||||
target: 'waitingForData',
|
||||
},
|
||||
},
|
||||
},
|
||||
ShowError: {
|
||||
on: {
|
||||
DISMISS: {
|
||||
actions: 'forwardToParent',
|
||||
target: 'waitingForData',
|
||||
},
|
||||
},
|
||||
},
|
||||
loadMyVcs: {
|
||||
entry: 'loadMyVcs',
|
||||
on: {
|
||||
STORE_RESPONSE: {
|
||||
actions: 'setMyVcs',
|
||||
target: 'showvcList',
|
||||
},
|
||||
},
|
||||
},
|
||||
showvcList: {
|
||||
on: {
|
||||
SELECT_VC: {
|
||||
actions: 'setSelectedVc',
|
||||
},
|
||||
VERIFY: {
|
||||
target: 'faceAuth',
|
||||
},
|
||||
DISMISS: {
|
||||
actions: 'forwardToParent',
|
||||
target: 'waitingForData',
|
||||
},
|
||||
},
|
||||
},
|
||||
faceAuth: {
|
||||
on: {
|
||||
FACE_VALID: {
|
||||
target: 'requestConsent',
|
||||
},
|
||||
FACE_INVALID: {
|
||||
target: 'invalidIdentity',
|
||||
},
|
||||
CANCEL: {
|
||||
target: 'showvcList',
|
||||
},
|
||||
},
|
||||
},
|
||||
invalidIdentity: {
|
||||
on: {
|
||||
DISMISS: {
|
||||
target: 'showvcList',
|
||||
},
|
||||
RETRY_VERIFICATION: {
|
||||
target: 'faceAuth',
|
||||
},
|
||||
},
|
||||
},
|
||||
requestConsent: {
|
||||
on: {
|
||||
CONFIRM: {
|
||||
target: 'sendingConsent',
|
||||
},
|
||||
TOGGLE_CONSENT_CLAIM: {
|
||||
actions: 'setConsentClaims',
|
||||
target: 'requestConsent',
|
||||
},
|
||||
DISMISS: {
|
||||
actions: 'forwardToParent',
|
||||
target: 'waitingForData',
|
||||
},
|
||||
},
|
||||
},
|
||||
sendingConsent: {
|
||||
invoke: {
|
||||
src: 'sendConsent',
|
||||
onDone: {
|
||||
target: 'success',
|
||||
},
|
||||
onError: [
|
||||
{
|
||||
actions: 'SetErrorMessage',
|
||||
target: 'ShowError',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
success: {
|
||||
on: {
|
||||
CONFIRM: {
|
||||
target: 'done',
|
||||
},
|
||||
},
|
||||
},
|
||||
done: {
|
||||
type: 'final',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
actions: {
|
||||
forwardToParent: sendParent('DISMISS'),
|
||||
|
||||
setScanData: assign({
|
||||
linkCode: (context, event) => event.value,
|
||||
}),
|
||||
|
||||
loadMyVcs: send(StoreEvents.GET(MY_VCS_STORE_KEY), {
|
||||
to: (context) => context.serviceRefs.store,
|
||||
}),
|
||||
|
||||
setMyVcs: model.assign({
|
||||
myVcs: (_context, event) => (event.response || []) as string[],
|
||||
}),
|
||||
|
||||
resetLinkTransactionId: model.assign({
|
||||
linkTransactionId: () => '',
|
||||
}),
|
||||
|
||||
resetSelectedVoluntaryClaims: model.assign({
|
||||
selectedVoluntaryClaims: () => [],
|
||||
}),
|
||||
|
||||
setSelectedVc: assign({
|
||||
selectedVc: (context, event) => {
|
||||
return { ...event.vc };
|
||||
},
|
||||
}),
|
||||
|
||||
setlinkTransactionResponse: assign({
|
||||
linkTransactionResponse: (context, event) =>
|
||||
event.data as linkTransactionResponse,
|
||||
}),
|
||||
|
||||
expandLinkTransResp: assign({
|
||||
authFactors: (context) => context.linkTransactionResponse.authFactors,
|
||||
|
||||
authorizeScopes: (context) =>
|
||||
context.linkTransactionResponse.authorizeScopes,
|
||||
|
||||
clientName: (context) => context.linkTransactionResponse.clientName,
|
||||
|
||||
configs: (context) => context.linkTransactionResponse.configs,
|
||||
|
||||
essentialClaims: (context) =>
|
||||
context.linkTransactionResponse.essentialClaims,
|
||||
|
||||
linkTransactionId: (context) =>
|
||||
context.linkTransactionResponse.linkTransactionId,
|
||||
|
||||
logoUrl: (context) => context.linkTransactionResponse.logoUrl,
|
||||
|
||||
voluntaryClaims: (context) =>
|
||||
context.linkTransactionResponse.voluntaryClaims,
|
||||
}),
|
||||
|
||||
setClaims: (context) => {
|
||||
context.voluntaryClaims.map((claim) => {
|
||||
context.isSharing[claim] = false;
|
||||
});
|
||||
},
|
||||
|
||||
SetErrorMessage: assign({
|
||||
errorMessage: (context, event) =>
|
||||
(event as ErrorPlatformEvent).data.message,
|
||||
}),
|
||||
|
||||
setConsentClaims: assign({
|
||||
isSharing: (context, event) => {
|
||||
context.selectedVoluntaryClaims.push(
|
||||
context.isSharing[event.claim]
|
||||
);
|
||||
context.isSharing[event.claim] = !event.enable;
|
||||
return { ...context.isSharing };
|
||||
},
|
||||
}),
|
||||
},
|
||||
services: {
|
||||
linkTransaction: async (context) => {
|
||||
const response = await request('POST', '/link-transaction', {
|
||||
linkCode: context.linkCode,
|
||||
requestTime: String(new Date().toISOString()),
|
||||
});
|
||||
return response.response;
|
||||
},
|
||||
|
||||
sendConsent: async (context) => {
|
||||
var privateKey = await getPrivateKey(
|
||||
context.selectedVc.walletBindingResponse?.walletBindingId
|
||||
);
|
||||
var walletBindingResponse = context.selectedVc.walletBindingResponse;
|
||||
var jwt = await getJwt(
|
||||
privateKey,
|
||||
context.selectedVc.id,
|
||||
walletBindingResponse?.keyId,
|
||||
walletBindingResponse?.thumbprint
|
||||
);
|
||||
|
||||
const resp = await request('POST', '/idp-auth-consent', {
|
||||
requestTime: String(new Date().toISOString()),
|
||||
request: {
|
||||
linkedTransactionId: context.linkTransactionId,
|
||||
individualId: context.selectedVc.id,
|
||||
acceptedClaims: context.essentialClaims.concat(
|
||||
context.selectedVoluntaryClaims
|
||||
),
|
||||
permittedAuthorizeScopes: context.authorizeScopes,
|
||||
challengeList: [
|
||||
{
|
||||
authFactorType: 'WLA',
|
||||
challenge: jwt,
|
||||
format: 'jwt',
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
console.log(resp.response.linkedTransactionId);
|
||||
},
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
export function createQrLoginMachine(serviceRefs: AppServices) {
|
||||
return qrLoginMachine.withContext({
|
||||
...qrLoginMachine.context,
|
||||
serviceRefs,
|
||||
});
|
||||
}
|
||||
|
||||
type State = StateFrom<typeof qrLoginMachine>;
|
||||
|
||||
export function selectMyVcs(state: State) {
|
||||
return state.context.myVcs;
|
||||
}
|
||||
export function selectIsWaitingForData(state: State) {
|
||||
return state.matches('waitingForData');
|
||||
}
|
||||
|
||||
export function selectIsShowWarning(state: State) {
|
||||
return state.matches('showWarning');
|
||||
}
|
||||
|
||||
export function selectIsLinkTransaction(state: State) {
|
||||
return state.matches('linkTransaction');
|
||||
}
|
||||
|
||||
export function selectIsloadMyVcs(state: State) {
|
||||
return state.matches('loadMyVcs');
|
||||
}
|
||||
|
||||
export function selectIsShowingVcList(state: State) {
|
||||
return state.matches('showvcList');
|
||||
}
|
||||
|
||||
export function selectIsisVerifyingIdentity(state: State) {
|
||||
return state.matches('faceAuth');
|
||||
}
|
||||
|
||||
export function selectIsInvalidIdentity(state: State) {
|
||||
return state.matches('invalidIdentity');
|
||||
}
|
||||
|
||||
export function selectIsShowError(state: State) {
|
||||
return state.matches('ShowError');
|
||||
}
|
||||
|
||||
export function selectIsRequestConsent(state: State) {
|
||||
return state.matches('requestConsent');
|
||||
}
|
||||
|
||||
export function selectIsSendingConsent(state: State) {
|
||||
return state.matches('sendingConsent');
|
||||
}
|
||||
|
||||
export function selectIsVerifyingSuccesful(state: State) {
|
||||
return state.matches('success');
|
||||
}
|
||||
|
||||
export function selectSelectedVc(state: State) {
|
||||
return state.context.selectedVc;
|
||||
}
|
||||
|
||||
export function selectLinkTransactionResponse(state: State) {
|
||||
return state.context.linkTransactionResponse;
|
||||
}
|
||||
|
||||
export function selectVoluntaryClaims(state: State) {
|
||||
return state.context.voluntaryClaims;
|
||||
}
|
||||
|
||||
export function selectLogoUrl(state: State) {
|
||||
return state.context.logoUrl;
|
||||
}
|
||||
|
||||
export function selectClientName(state: State) {
|
||||
return state.context.clientName;
|
||||
}
|
||||
|
||||
export function selectErrorMessage(state: State) {
|
||||
return state.context.errorMessage;
|
||||
}
|
||||
export function selectIsSharing(state: State) {
|
||||
return state.context.isSharing;
|
||||
}
|
||||
65
machines/QrLoginMachine.typegen.ts
Normal file
65
machines/QrLoginMachine.typegen.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
// This file was automatically generated. Edits will be overwritten
|
||||
|
||||
export interface Typegen0 {
|
||||
'@@xstate/typegen': true;
|
||||
'internalEvents': {
|
||||
'done.invoke.QrLogin.linkTransaction:invocation[0]': {
|
||||
type: 'done.invoke.QrLogin.linkTransaction:invocation[0]';
|
||||
data: unknown;
|
||||
__tip: 'See the XState TS docs to learn how to strongly type this.';
|
||||
};
|
||||
'error.platform.QrLogin.linkTransaction:invocation[0]': {
|
||||
type: 'error.platform.QrLogin.linkTransaction:invocation[0]';
|
||||
data: unknown;
|
||||
};
|
||||
'error.platform.QrLogin.sendingConsent:invocation[0]': {
|
||||
type: 'error.platform.QrLogin.sendingConsent:invocation[0]';
|
||||
data: unknown;
|
||||
};
|
||||
'xstate.init': { type: 'xstate.init' };
|
||||
};
|
||||
'invokeSrcNameMap': {
|
||||
linkTransaction: 'done.invoke.QrLogin.linkTransaction:invocation[0]';
|
||||
sendConsent: 'done.invoke.QrLogin.sendingConsent:invocation[0]';
|
||||
};
|
||||
'missingImplementations': {
|
||||
actions: never;
|
||||
delays: never;
|
||||
guards: never;
|
||||
services: never;
|
||||
};
|
||||
'eventsCausingActions': {
|
||||
SetErrorMessage:
|
||||
| 'error.platform.QrLogin.linkTransaction:invocation[0]'
|
||||
| 'error.platform.QrLogin.sendingConsent:invocation[0]';
|
||||
expandLinkTransResp: 'done.invoke.QrLogin.linkTransaction:invocation[0]';
|
||||
forwardToParent: 'DISMISS';
|
||||
loadMyVcs: 'CONFIRM';
|
||||
setClaims: 'done.invoke.QrLogin.linkTransaction:invocation[0]';
|
||||
setConsentClaims: 'TOGGLE_CONSENT_CLAIM';
|
||||
setMyVcs: 'STORE_RESPONSE';
|
||||
setScanData: 'GET';
|
||||
setSelectedVc: 'SELECT_VC';
|
||||
setlinkTransactionResponse: 'done.invoke.QrLogin.linkTransaction:invocation[0]';
|
||||
};
|
||||
'eventsCausingDelays': {};
|
||||
'eventsCausingGuards': {};
|
||||
'eventsCausingServices': {
|
||||
linkTransaction: 'GET';
|
||||
sendConsent: 'CONFIRM';
|
||||
};
|
||||
'matchesStates':
|
||||
| 'ShowError'
|
||||
| 'done'
|
||||
| 'faceAuth'
|
||||
| 'invalidIdentity'
|
||||
| 'linkTransaction'
|
||||
| 'loadMyVcs'
|
||||
| 'requestConsent'
|
||||
| 'sendingConsent'
|
||||
| 'showWarning'
|
||||
| 'showvcList'
|
||||
| 'success'
|
||||
| 'waitingForData';
|
||||
'tags': never;
|
||||
}
|
||||
@@ -121,6 +121,7 @@ export interface ActivityLog {
|
||||
export type ActivityLogType =
|
||||
| 'VC_SHARED'
|
||||
| 'VC_RECEIVED'
|
||||
| 'VC_RECEIVED_NOT_SAVED'
|
||||
| 'VC_DELETED'
|
||||
| 'VC_DOWNLOADED'
|
||||
| 'VC_REVOKED'
|
||||
@@ -128,7 +129,8 @@ export type ActivityLogType =
|
||||
| 'VC_RECEIVED_WITH_PRESENCE_VERIFIED'
|
||||
| 'VC_RECEIVED_BUT_PRESENCE_VERIFICATION_FAILED'
|
||||
| 'PRESENCE_VERIFIED_AND_VC_SHARED'
|
||||
| 'PRESENCE_VERIFICATION_FAILED';
|
||||
| 'PRESENCE_VERIFICATION_FAILED'
|
||||
| 'QRLOGIN_SUCCESFULL';
|
||||
|
||||
type State = StateFrom<typeof activityLogMachine>;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { init } from 'mosip-inji-face-sdk';
|
||||
import { ContextFrom, EventFrom, send, StateFrom } from 'xstate';
|
||||
import { createModel } from 'xstate/lib/model';
|
||||
import getAllProperties from '../shared/commonprops/commonProps';
|
||||
import getAllConfigurations from '../shared/commonprops/commonProps';
|
||||
import { AppServices } from '../shared/GlobalContext';
|
||||
import { StoreEvents, StoreResponseEvent } from './store';
|
||||
|
||||
@@ -11,7 +11,6 @@ const model = createModel(
|
||||
passcode: '',
|
||||
biometrics: '',
|
||||
canUseBiometrics: false,
|
||||
injiAppProperties: null,
|
||||
},
|
||||
{
|
||||
events: {
|
||||
@@ -88,7 +87,7 @@ export const authMachine = model.createMachine(
|
||||
invoke: {
|
||||
src: 'downloadFaceSdkModel',
|
||||
onDone: {
|
||||
actions: ['setInjiAppProperties', 'storeContext'],
|
||||
actions: ['storeContext'],
|
||||
},
|
||||
},
|
||||
on: {
|
||||
@@ -128,21 +127,13 @@ export const authMachine = model.createMachine(
|
||||
setBiometrics: model.assign({
|
||||
biometrics: (_, event: SetupBiometricsEvent) => event.biometrics,
|
||||
}),
|
||||
|
||||
setInjiAppProperties: model.assign({
|
||||
injiAppProperties: (_, event) => event.data as object,
|
||||
}),
|
||||
},
|
||||
|
||||
services: {
|
||||
downloadFaceSdkModel: (context) => async () => {
|
||||
downloadFaceSdkModel: () => async () => {
|
||||
var injiProp = null;
|
||||
try {
|
||||
if (context.injiAppProperties == null) {
|
||||
injiProp = await getAllProperties();
|
||||
} else {
|
||||
injiProp = context.injiAppProperties;
|
||||
}
|
||||
var injiProp = await getAllConfigurations();
|
||||
const resp: string =
|
||||
injiProp != null ? injiProp.faceSdkModelUrl : null;
|
||||
if (resp != null) {
|
||||
@@ -151,7 +142,6 @@ export const authMachine = model.createMachine(
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
return injiProp;
|
||||
},
|
||||
},
|
||||
|
||||
@@ -162,7 +152,7 @@ export const authMachine = model.createMachine(
|
||||
return context.passcode !== '';
|
||||
},
|
||||
hasBiometricSet: (context) => {
|
||||
return context.biometrics !== '';
|
||||
return context.biometrics !== '' && context.passcode !== '';
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -200,7 +190,3 @@ export function selectUnauthorized(state: State) {
|
||||
export function selectSettingUp(state: State) {
|
||||
return state.matches('settingUp');
|
||||
}
|
||||
|
||||
export function selectInjiAppProps(state: State) {
|
||||
return state.context.injiAppProperties;
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@ export interface Typegen0 {
|
||||
requestStoredContext: 'xstate.init';
|
||||
setBiometrics: 'SETUP_BIOMETRICS';
|
||||
setContext: 'STORE_RESPONSE';
|
||||
setInjiAppProperties: 'done.invoke.auth.authorized:invocation[0]';
|
||||
setPasscode: 'SETUP_PASSCODE';
|
||||
storeContext:
|
||||
| 'SETUP_BIOMETRICS'
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { createModel } from 'xstate/lib/model';
|
||||
import * as LocalAuthentication from 'expo-local-authentication';
|
||||
import { EventFrom, MetaObject, StateFrom } from 'xstate';
|
||||
import { Platform } from 'react-native';
|
||||
|
||||
// ----- CREATE MODEL ---------------------------------------------------------
|
||||
const model = createModel(
|
||||
@@ -97,6 +98,9 @@ export const biometricsMachine = model.createMachine(
|
||||
authenticating: {
|
||||
invoke: {
|
||||
src: () => async () => {
|
||||
if (Platform.OS === 'android') {
|
||||
await LocalAuthentication.cancelAuthenticate();
|
||||
}
|
||||
const res = await LocalAuthentication.authenticateAsync({
|
||||
promptMessage: 'Biometric Authentication',
|
||||
|
||||
@@ -112,6 +116,9 @@ export const biometricsMachine = model.createMachine(
|
||||
actions: ['setStatus'],
|
||||
},
|
||||
},
|
||||
on: {
|
||||
AUTHENTICATE: 'authenticating',
|
||||
},
|
||||
},
|
||||
|
||||
reauthenticating: {
|
||||
@@ -145,6 +152,7 @@ export const biometricsMachine = model.createMachine(
|
||||
SET_IS_AVAILABLE: {
|
||||
target: '#biometrics.available',
|
||||
},
|
||||
AUTHENTICATE: 'authenticating',
|
||||
},
|
||||
},
|
||||
|
||||
@@ -186,6 +194,9 @@ export const biometricsMachine = model.createMachine(
|
||||
},
|
||||
},
|
||||
},
|
||||
on: {
|
||||
AUTHENTICATE: 'authenticating',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -27,6 +27,7 @@ export interface Typegen0 {
|
||||
'invokeSrcNameMap': {
|
||||
advertiseDevice: 'done.invoke.request.waitingForConnection:invocation[0]';
|
||||
checkBluetoothService: 'done.invoke.request.checkingBluetoothService.checking:invocation[0]';
|
||||
checkNetwork: 'done.invoke.request.checkingNetwork:invocation[0]';
|
||||
exchangeDeviceInfo: 'done.invoke.request.exchangingDeviceInfo:invocation[0]';
|
||||
monitorConnection: 'done.invoke.request:invocation[0]';
|
||||
receiveVc: 'done.invoke.request.waitingForVc:invocation[0]';
|
||||
@@ -34,7 +35,8 @@ export interface Typegen0 {
|
||||
sendDisconnect: 'done.invoke.request.cancelling:invocation[0]';
|
||||
sendVcResponse:
|
||||
| 'done.invoke.request.reviewing.accepted:invocation[0]'
|
||||
| 'done.invoke.request.reviewing.rejected:invocation[0]';
|
||||
| 'done.invoke.request.reviewing.rejected:invocation[0]'
|
||||
| 'done.invoke.request.reviewing:invocation[0]';
|
||||
verifyVp: 'done.invoke.request.reviewing.verifyingVp:invocation[0]';
|
||||
};
|
||||
'missingImplementations': {
|
||||
@@ -66,7 +68,7 @@ export interface Typegen0 {
|
||||
generateConnectionParams:
|
||||
| 'DISMISS'
|
||||
| 'xstate.after(CLEAR_DELAY)#request.clearingConnection';
|
||||
logReceived: 'STORE_RESPONSE';
|
||||
logReceived: 'CANCEL' | 'REJECT' | 'STORE_RESPONSE';
|
||||
mergeIncomingVc: 'STORE_RESPONSE';
|
||||
openSettings: 'GOTO_SETTINGS';
|
||||
prependReceivedVc: 'VC_RESPONSE';
|
||||
@@ -85,8 +87,8 @@ export interface Typegen0 {
|
||||
| 'FACE_VALID'
|
||||
| 'done.invoke.request.reviewing.verifyingVp:invocation[0]';
|
||||
requestReceiverInfo: 'CONNECTED';
|
||||
sendVcReceived: 'STORE_RESPONSE';
|
||||
setIncomingVc: 'VC_RECEIVED';
|
||||
setReceiveLogTypeDiscarded: 'CANCEL' | 'REJECT';
|
||||
setReceiveLogTypeRegular: 'ACCEPT';
|
||||
setReceiveLogTypeUnverified: 'FACE_INVALID';
|
||||
setReceiveLogTypeVerified: 'FACE_VALID';
|
||||
@@ -94,6 +96,7 @@ export interface Typegen0 {
|
||||
setSenderInfo: 'EXCHANGE_DONE';
|
||||
storeVc: 'STORE_RESPONSE';
|
||||
switchProtocol: 'SWITCH_PROTOCOL';
|
||||
updateReceivedVcs: 'STORE_RESPONSE';
|
||||
};
|
||||
'eventsCausingDelays': {
|
||||
CANCEL_TIMEOUT: 'CANCEL';
|
||||
@@ -103,21 +106,24 @@ export interface Typegen0 {
|
||||
};
|
||||
'eventsCausingGuards': {
|
||||
hasExistingVc: 'VC_RESPONSE';
|
||||
isModeOnline: 'SCREEN_FOCUS' | 'SWITCH_PROTOCOL';
|
||||
};
|
||||
'eventsCausingServices': {
|
||||
advertiseDevice:
|
||||
| 'DISMISS'
|
||||
| 'xstate.after(CLEAR_DELAY)#request.clearingConnection';
|
||||
checkBluetoothService:
|
||||
| 'ONLINE'
|
||||
| 'SCREEN_FOCUS'
|
||||
| 'SWITCH_PROTOCOL'
|
||||
| 'xstate.after(CANCEL_TIMEOUT)#request.cancelling';
|
||||
checkNetwork: 'APP_ACTIVE' | 'SCREEN_FOCUS' | 'SWITCH_PROTOCOL';
|
||||
exchangeDeviceInfo: 'RECEIVE_DEVICE_INFO';
|
||||
monitorConnection: 'xstate.init';
|
||||
receiveVc: 'EXCHANGE_DONE';
|
||||
requestBluetooth: 'BLUETOOTH_DISABLED';
|
||||
sendDisconnect: 'CANCEL';
|
||||
sendVcResponse: 'CANCEL' | 'REJECT' | 'STORE_RESPONSE';
|
||||
sendVcResponse: 'CANCEL' | 'REJECT' | 'STORE_RESPONSE' | 'VC_RECEIVED';
|
||||
verifyVp: never;
|
||||
};
|
||||
'matchesStates':
|
||||
@@ -127,12 +133,14 @@ export interface Typegen0 {
|
||||
| 'checkingBluetoothService.checking'
|
||||
| 'checkingBluetoothService.enabled'
|
||||
| 'checkingBluetoothService.requesting'
|
||||
| 'checkingNetwork'
|
||||
| 'clearingConnection'
|
||||
| 'disconnected'
|
||||
| 'exchangingDeviceInfo'
|
||||
| 'exchangingDeviceInfo.inProgress'
|
||||
| 'exchangingDeviceInfo.timeout'
|
||||
| 'inactive'
|
||||
| 'offline'
|
||||
| 'preparingToExchangeInfo'
|
||||
| 'reviewing'
|
||||
| 'reviewing.accepted'
|
||||
|
||||
306
machines/scan.ts
306
machines/scan.ts
File diff suppressed because one or more lines are too long
@@ -3,12 +3,20 @@
|
||||
export interface Typegen0 {
|
||||
'@@xstate/typegen': true;
|
||||
'internalEvents': {
|
||||
'': { type: '' };
|
||||
'done.invoke.QrLogin': {
|
||||
type: 'done.invoke.QrLogin';
|
||||
data: unknown;
|
||||
__tip: 'See the XState TS docs to learn how to strongly type this.';
|
||||
};
|
||||
'done.invoke.scan.reviewing.creatingVp:invocation[0]': {
|
||||
type: 'done.invoke.scan.reviewing.creatingVp:invocation[0]';
|
||||
data: unknown;
|
||||
__tip: 'See the XState TS docs to learn how to strongly type this.';
|
||||
};
|
||||
'error.platform.scan.reviewing.creatingVp:invocation[0]': {
|
||||
type: 'error.platform.scan.reviewing.creatingVp:invocation[0]';
|
||||
data: unknown;
|
||||
};
|
||||
'xstate.after(CANCEL_TIMEOUT)#scan.reviewing.cancelling': {
|
||||
type: 'xstate.after(CANCEL_TIMEOUT)#scan.reviewing.cancelling';
|
||||
};
|
||||
@@ -28,14 +36,14 @@ export interface Typegen0 {
|
||||
'xstate.stop': { type: 'xstate.stop' };
|
||||
};
|
||||
'invokeSrcNameMap': {
|
||||
checkBluetoothService: 'done.invoke.scan.checkingBluetoothService.checking:invocation[0]';
|
||||
checkLocationPermission: 'done.invoke.scan.checkingLocationService.checkingPermission:invocation[0]';
|
||||
checkLocationStatus: 'done.invoke.scan.checkingLocationService.checkingStatus:invocation[0]';
|
||||
checkNetwork: 'done.invoke.scan.checkingNetwork:invocation[0]';
|
||||
createVp: 'done.invoke.scan.reviewing.creatingVp:invocation[0]';
|
||||
discoverDevice: 'done.invoke.scan.connecting:invocation[0]';
|
||||
exchangeDeviceInfo: 'done.invoke.scan.exchangingDeviceInfo:invocation[0]';
|
||||
monitorCancellation: 'done.invoke.scan.reviewing.selectingVc:invocation[0]';
|
||||
monitorConnection: 'done.invoke.scan:invocation[0]';
|
||||
requestBluetooth: 'done.invoke.scan.checkingBluetoothService.requesting:invocation[0]';
|
||||
sendDisconnect: 'done.invoke.scan.reviewing.cancelling:invocation[0]';
|
||||
sendVc: 'done.invoke.scan.reviewing.sendingVc:invocation[0]';
|
||||
};
|
||||
@@ -43,7 +51,7 @@ export interface Typegen0 {
|
||||
actions: never;
|
||||
delays: never;
|
||||
guards: never;
|
||||
services: never;
|
||||
services: 'QrLogin';
|
||||
};
|
||||
'eventsCausingActions': {
|
||||
clearCreatedVp:
|
||||
@@ -75,7 +83,14 @@ export interface Typegen0 {
|
||||
| 'xstate.stop';
|
||||
logFailedVerification: 'FACE_INVALID';
|
||||
logShared: 'VC_ACCEPTED';
|
||||
openBluetoothSettings: 'GOTO_SETTINGS';
|
||||
onlineUnsubscribe:
|
||||
| 'ACCEPT_REQUEST'
|
||||
| 'CANCEL'
|
||||
| 'DISCONNECT'
|
||||
| 'SCREEN_BLUR'
|
||||
| 'SCREEN_FOCUS'
|
||||
| 'VERIFY_AND_ACCEPT_REQUEST'
|
||||
| 'xstate.stop';
|
||||
openSettings: 'LOCATION_REQUEST';
|
||||
registerLoggers:
|
||||
| 'DISCONNECT'
|
||||
@@ -89,10 +104,18 @@ export interface Typegen0 {
|
||||
| 'xstate.after(CANCEL_TIMEOUT)#scan.reviewing.cancelling'
|
||||
| 'xstate.after(CLEAR_DELAY)#scan.clearingConnection'
|
||||
| 'xstate.init';
|
||||
requestSenderInfo: 'SCAN';
|
||||
requestSenderInfo: 'ONLINE' | 'SCAN';
|
||||
requestToEnableLocation: 'LOCATION_DISABLED' | 'LOCATION_REQUEST';
|
||||
resetShouldVerifyPresence: 'CANCEL' | 'EXCHANGE_DONE';
|
||||
sendScanData: 'SCAN';
|
||||
setChildRef:
|
||||
| 'DISCONNECT'
|
||||
| 'DISMISS'
|
||||
| 'xstate.after(CANCEL_TIMEOUT)#scan.reviewing.cancelling'
|
||||
| 'xstate.after(CLEAR_DELAY)#scan.clearingConnection';
|
||||
setConnectionParams: 'SCAN';
|
||||
setCreatedVp: 'done.invoke.scan.reviewing.creatingVp:invocation[0]';
|
||||
setLinkCode: 'SCAN';
|
||||
setReason: 'UPDATE_REASON';
|
||||
setReceiverInfo: 'EXCHANGE_DONE';
|
||||
setScannedQrParams: 'SCAN';
|
||||
@@ -100,6 +123,8 @@ export interface Typegen0 {
|
||||
setSenderInfo: 'RECEIVE_DEVICE_INFO';
|
||||
setShareLogTypeUnverified: 'ACCEPT_REQUEST';
|
||||
setShareLogTypeVerified: 'FACE_VALID';
|
||||
storeLoginItem: 'done.invoke.QrLogin';
|
||||
storingActivityLog: 'STORE_RESPONSE';
|
||||
toggleShouldVerifyPresence: 'TOGGLE_USER_CONSENT';
|
||||
};
|
||||
'eventsCausingDelays': {
|
||||
@@ -112,41 +137,45 @@ export interface Typegen0 {
|
||||
SHARING_TIMEOUT:
|
||||
| 'ACCEPT_REQUEST'
|
||||
| 'FACE_VALID'
|
||||
| 'VC_SENT'
|
||||
| 'done.invoke.scan.reviewing.creatingVp:invocation[0]';
|
||||
};
|
||||
'eventsCausingGuards': {
|
||||
isQrLogin: 'SCAN';
|
||||
isQrOffline: 'SCAN';
|
||||
isQrOnline: 'SCAN';
|
||||
};
|
||||
'eventsCausingServices': {
|
||||
checkBluetoothService: 'SCREEN_FOCUS';
|
||||
QrLogin: 'SCAN';
|
||||
checkLocationPermission: 'APP_ACTIVE' | 'LOCATION_ENABLED';
|
||||
checkLocationStatus: '';
|
||||
checkLocationStatus: 'SCREEN_FOCUS';
|
||||
checkNetwork: 'SCAN';
|
||||
createVp: never;
|
||||
discoverDevice: 'RECEIVE_DEVICE_INFO';
|
||||
exchangeDeviceInfo:
|
||||
| 'CONNECTED'
|
||||
| 'xstate.after(CONNECTION_TIMEOUT)#scan.exchangingDeviceInfo';
|
||||
monitorCancellation:
|
||||
| 'CANCEL'
|
||||
| 'DISMISS'
|
||||
| 'EXCHANGE_DONE'
|
||||
| 'error.platform.scan.reviewing.creatingVp:invocation[0]';
|
||||
monitorConnection: 'xstate.init';
|
||||
requestBluetooth: 'BLUETOOTH_DISABLED';
|
||||
sendDisconnect: 'CANCEL';
|
||||
sendVc:
|
||||
| 'ACCEPT_REQUEST'
|
||||
| 'FACE_VALID'
|
||||
| 'VC_SENT'
|
||||
| 'done.invoke.scan.reviewing.creatingVp:invocation[0]';
|
||||
};
|
||||
'matchesStates':
|
||||
| 'bluetoothDenied'
|
||||
| 'checkingBluetoothService'
|
||||
| 'checkingBluetoothService.checking'
|
||||
| 'checkingBluetoothService.enabled'
|
||||
| 'checkingBluetoothService.requesting'
|
||||
| 'checkingLocationService'
|
||||
| 'checkingLocationService.checkingPermission'
|
||||
| 'checkingLocationService.checkingStatus'
|
||||
| 'checkingLocationService.denied'
|
||||
| 'checkingLocationService.disabled'
|
||||
| 'checkingLocationService.requestingToEnable'
|
||||
| 'checkingNetwork'
|
||||
| 'clearingConnection'
|
||||
| 'connecting'
|
||||
| 'connecting.inProgress'
|
||||
@@ -158,6 +187,7 @@ export interface Typegen0 {
|
||||
| 'findingConnection'
|
||||
| 'inactive'
|
||||
| 'invalid'
|
||||
| 'offline'
|
||||
| 'preparingToConnect'
|
||||
| 'reviewing'
|
||||
| 'reviewing.accepted'
|
||||
@@ -169,10 +199,14 @@ export interface Typegen0 {
|
||||
| 'reviewing.selectingVc'
|
||||
| 'reviewing.sendingVc'
|
||||
| 'reviewing.sendingVc.inProgress'
|
||||
| 'reviewing.sendingVc.sent'
|
||||
| 'reviewing.sendingVc.timeout'
|
||||
| 'reviewing.verifyingIdentity'
|
||||
| 'showQrLogin'
|
||||
| 'showQrLogin.idle'
|
||||
| 'showQrLogin.navigatingToHome'
|
||||
| 'showQrLogin.storing'
|
||||
| {
|
||||
checkingBluetoothService?: 'checking' | 'enabled' | 'requesting';
|
||||
checkingLocationService?:
|
||||
| 'checkingPermission'
|
||||
| 'checkingStatus'
|
||||
@@ -191,7 +225,8 @@ export interface Typegen0 {
|
||||
| 'selectingVc'
|
||||
| 'sendingVc'
|
||||
| 'verifyingIdentity'
|
||||
| { sendingVc?: 'inProgress' | 'timeout' };
|
||||
| { sendingVc?: 'inProgress' | 'sent' | 'timeout' };
|
||||
showQrLogin?: 'idle' | 'navigatingToHome' | 'storing';
|
||||
};
|
||||
'tags': never;
|
||||
}
|
||||
|
||||
@@ -8,9 +8,9 @@ export interface Typegen0 {
|
||||
'invokeSrcNameMap': {};
|
||||
'missingImplementations': {
|
||||
actions: never;
|
||||
services: never;
|
||||
guards: never;
|
||||
delays: never;
|
||||
guards: never;
|
||||
services: never;
|
||||
};
|
||||
'eventsCausingActions': {
|
||||
requestStoredContext: 'xstate.init';
|
||||
@@ -24,11 +24,11 @@ export interface Typegen0 {
|
||||
updateName: 'UPDATE_NAME';
|
||||
updateVcLabel: 'UPDATE_VC_LABEL';
|
||||
};
|
||||
'eventsCausingServices': {};
|
||||
'eventsCausingDelays': {};
|
||||
'eventsCausingGuards': {
|
||||
hasData: 'STORE_RESPONSE';
|
||||
};
|
||||
'eventsCausingDelays': {};
|
||||
'eventsCausingServices': {};
|
||||
'matchesStates': 'idle' | 'init' | 'storingDefaults';
|
||||
'tags': never;
|
||||
}
|
||||
|
||||
@@ -239,3 +239,14 @@ export function selectIsRefreshingMyVcs(state: State) {
|
||||
export function selectIsRefreshingReceivedVcs(state: State) {
|
||||
return state.matches('ready.receivedVcs.refreshing');
|
||||
}
|
||||
|
||||
export function selectBindedVcs(state: State) {
|
||||
return (Object.keys(state.context.vcs) as Array<string>).filter((key) => {
|
||||
var walletBindingResponse = state.context.vcs[key].walletBindingResponse;
|
||||
return (
|
||||
walletBindingResponse !== null &&
|
||||
walletBindingResponse.walletBindingId !== null &&
|
||||
walletBindingResponse.walletBindingId !== ''
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
// 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;
|
||||
services: never;
|
||||
guards: never;
|
||||
delays: never;
|
||||
};
|
||||
'eventsCausingActions': {
|
||||
getReceivedVcsResponse: 'GET_RECEIVED_VCS';
|
||||
getVcItemResponse: 'GET_VC_ITEM';
|
||||
loadMyVcs: 'REFRESH_MY_VCS' | 'xstate.init';
|
||||
loadReceivedVcs: 'REFRESH_RECEIVED_VCS' | 'STORE_RESPONSE';
|
||||
moveExistingVcToTop: 'VC_RECEIVED';
|
||||
prependToMyVcs: 'VC_ADDED';
|
||||
prependToReceivedVcs: 'VC_RECEIVED';
|
||||
setDownloadedVc: 'VC_DOWNLOADED';
|
||||
setMyVcs: 'STORE_RESPONSE';
|
||||
setReceivedVcs: 'STORE_RESPONSE';
|
||||
};
|
||||
'eventsCausingServices': {};
|
||||
'eventsCausingGuards': {
|
||||
hasExistingReceivedVc: 'VC_RECEIVED';
|
||||
};
|
||||
'eventsCausingDelays': {};
|
||||
'matchesStates':
|
||||
| 'init'
|
||||
| 'init.myVcs'
|
||||
| 'init.receivedVcs'
|
||||
| 'ready'
|
||||
| 'ready.myVcs'
|
||||
| 'ready.myVcs.idle'
|
||||
| 'ready.myVcs.refreshing'
|
||||
| 'ready.receivedVcs'
|
||||
| 'ready.receivedVcs.idle'
|
||||
| 'ready.receivedVcs.refreshing'
|
||||
| {
|
||||
init?: 'myVcs' | 'receivedVcs';
|
||||
ready?:
|
||||
| 'myVcs'
|
||||
| 'receivedVcs'
|
||||
| {
|
||||
myVcs?: 'idle' | 'refreshing';
|
||||
receivedVcs?: 'idle' | 'refreshing';
|
||||
};
|
||||
};
|
||||
'tags': never;
|
||||
}
|
||||
|
||||
@@ -13,6 +13,18 @@ import { StoreEvents } from './store';
|
||||
import { ActivityLogEvents } from './activityLog';
|
||||
import { verifyCredential } from '../shared/vcjs/verifyCredential';
|
||||
import { log } from 'xstate/lib/actions';
|
||||
import {
|
||||
generateKeys,
|
||||
getJwt,
|
||||
WalletBindingResponse,
|
||||
} from '../shared/cryptoutil/cryptoUtil';
|
||||
import { KeyPair } from 'react-native-rsa-native';
|
||||
import {
|
||||
getBindingCertificateConstant,
|
||||
getPrivateKey,
|
||||
savePrivateKey,
|
||||
} from '../shared/keystore/SecureKeystore';
|
||||
import getAllConfigurations from '../shared/commonprops/commonProps';
|
||||
|
||||
const model = createModel(
|
||||
{
|
||||
@@ -31,11 +43,19 @@ const model = createModel(
|
||||
otpError: '',
|
||||
idError: '',
|
||||
transactionId: '',
|
||||
bindingTransactionId: '',
|
||||
revoked: false,
|
||||
downloadCounter: 0,
|
||||
maxDownloadCount: 10,
|
||||
walletBindingResponse: null as WalletBindingResponse,
|
||||
walletBindingError: '',
|
||||
publicKey: '',
|
||||
privateKey: '',
|
||||
},
|
||||
{
|
||||
events: {
|
||||
KEY_RECEIVED: (key: string) => ({ key }),
|
||||
KEY_ERROR: (error: Error) => ({ error }),
|
||||
EDIT_TAG: () => ({}),
|
||||
SAVE_TAG: (tag: string) => ({ tag }),
|
||||
STORE_READY: () => ({}),
|
||||
@@ -50,6 +70,10 @@ const model = createModel(
|
||||
INPUT_OTP: (otp: string) => ({ otp }),
|
||||
REFRESH: () => ({}),
|
||||
REVOKE_VC: () => ({}),
|
||||
ADD_WALLET_BINDING_ID: () => ({}),
|
||||
BINDING_DONE: () => ({}),
|
||||
CANCEL: () => ({}),
|
||||
CONFIRM: () => ({}),
|
||||
},
|
||||
}
|
||||
);
|
||||
@@ -57,7 +81,7 @@ const model = createModel(
|
||||
export const VcItemEvents = model.events;
|
||||
|
||||
export const vcItemMachine =
|
||||
/** @xstate-layout N4IgpgJg5mDOIC5QDcDGBaAlgFzAWwDpUALMVAa0wDsoA1VAYgHEBRAFQH1aBhDgJRYBlAAoB5AHKCWiUAAcA9rByZ5VGSAAeiAIwAWAAwFtANgAcAdl0BmAJwAmOxd0BWADQgAnoivHDpx6aBzubGwc6mAL4R7mhYuIQkZJQ0gtjyAE5gDIJsogL8QmKS0kggCkrYKmqlWgh6hiYWDnba4aFW7l4I5qbOBPohvdoW2jbDUTEYOPhEpBTUUIJg6cjLACIAhtgbs0kLqVsArrAMYgAyZ+rlyqrqtdrm2gRWds521vqmusZ2Nr2dOlGugIAXMb1+dn0NnCExAsWmCTmyUWy1W6U22128xS22wxwYa1EAHVxGdRABBNYFSkATSuihu1VAtQMfSsPlCumhVlGjwBdSsumBdh5Vmc1jGznszlh8PiWORSxW6y2Owg8gA7lQADbyDYQBbcTIQMBUSobbWnUQXekVKp3RA-YWtcz6YzQ4y6OzGfnaIEgwJghz2KEw6JwqbyxLYlHK9GqgjqrW6-WG42m82W7gCNYscRsACS5LOHEJJLJlJYa1tjIdCF0pmMz3Mrucgu+7R9nkQjb6Fh87Z5LcCssjM0wEG1WSrBc4bHJTBrlVuNR0bqeNk9A2Mrv0+mc4X5f3MBF0PRFPP8-kso7i48nWVoLD4BYAYnTStdl0zND3nA0rEbUx930OwQlCflTEAggbHMDkwKdfRtFvBECAnKcGDJbgAGkuG4Jd7VXOo2z6T5fDMHwbCQnpIOg2CfCgkJBjFFD5XQrIAFVSVEHC8IIldmR0axTCMYxRhsXRhmsd47H5QZ+mGHdQNGYxKNYmZIGUGg2A2KACQLQQAFkDMEfif3uYYT09XxGx6dk91k7sEGPU9z1CJD-HZKx1MITTKm03TsnJJ8OHnRdPwZb86z9VpTyosZ3TMAxHK6P1HiML1Xi9YwxIGSJwzlGZYDSdIFh0vScjyFgChECQpDM6LXjsAhTAk-RALguCrHMX1tBFAhLGGXoWj+drdB8gg0UwAAzDw00gDNMAtBh1SoMA0KoZB5HIdbCsIKbZvmk0zSW7UEGoLbUC2KoAG19AAXQaojtH0AwCClcxXihb0TAPfkXEMJDhl5d0eiFcaCrHfblhmuaaCNBaTuW5Z0gyAhZG1LZpoyfaocmmHDvh9MkbOi75Cu787seiK7QE39nNeFrnE9GxAJcSFvX5H5mvsb4+u0WxgNeibo2RWgCcwCmqgOPETiewS6hep4rDdaFglAz6eqc14myvQJ+YGfd2Qmi6LQnBgC3EYQOM4UQ2GEeX6chT1m0eA9wZVqDev-GDKJ3ST3SFfLJjvQhTe1c21gM4zBFMmna2el4bHe0xWm+F5PUA-k2yeAw7Mk8UWnMGwJsyABHQ44H8qBRGwWQVtUdayZ2ya8fLyvioWWvZHOzbyeu1Qqcd+5U6sfoHBykwQjeLWukSmCzxFODHHeCxS7ACuq67uuGBRtGMaxnHW9Dgh263mhu97y6B6oIf46i57U+BN5AlU75nF+3Rs-sAgxLBFWJKWFgnYCaGxUCoDALIau3cCxUFkIcbAFsrY2w4HbB299CIKweFyd6YEP6OHBO1NwTlYLJ3sIKewrR-zeUhifMBECoHb1kLA+BiCo5GRMsPHQ-5gQ-DFLYewcF7CmCPC0OKvwfBSihE4dem9O40DOOTcgDc1obS2i3Pap8N4d2rooigV9+6UwelwuowFk6NmsnuaEF4RFOT6rBd61gXo9FbIKWROiFh6OUXvdI6NMbYGxukXGJ8z7yKgF4gxUtB7GIwXTEeVEBrkNZAhbqX8SHFxgiKQuUppQPAmrqGM9Bsi5HyAIWqxQTGtG6kYcIfUWyhEcNCXqm4akSR+i2cUxtYRUHkCaeApRNGiwWPQExZhf6pIkl6GwYwvQdDsS2Iwe4hQ9GmQYawEMQ6oSGTiDIYATHQhBE6KigQeSTLmXPAY-RTk2WkcBYwIskT7FRCqTE2zFi4mOPsp4jwvjehcMzVSwxfQ8maiKAW0zegDA-sHCMJ83lKjRBiNUmodR6gNETRGmYTHhBEueAWrpPrBDSalFWhgwUclCEAv4Dy9gpGefGbYoyTw-Oyv8nKl5fRujHqCCiIQXAbNhahdilSHgbgPBRdODhLByUCDBOCOV9xfAlDCzRfkyq6UqVCYEm4pSOE+i0P0nLZWeRaDuRwKtzATWKhkdVUBKmQj6KpMwPQYoCy7KlX4hg2xeihMXWCXwZS0NQgdOGUAEbHSxbE8yiB6m-yJb0A8eq2z-Ryu9P0UF8VQh8CAoNUZHk0HFqVaaksb4y0+VGusHxnh6Fqf4RwZriWOndBlFsfUuR-H8CXXN45NpmwgAQeQdcTHOyeE-HoqlFWCmzn1X+fxWh7lTmJIUJte0R37QAIzATtKgEBh1G3epuV6rNMrEK6G0IwDwSLemAi9Ltmy2KronHu34B7fBckFA4U9iAJSztToEKC-DPjuPPjXIdFbnrfDIX8cUDZ-xukbN-ZqXpvgB03MMFooDwGQOgXXFhCDKnFyeJ6cCjw-SvTdHJaZ704NUR+DuJ1wGwleIIwk34TExRu0sF+xW0FrCg1ePwrJ+SlHDNQJUmeLVbCAU+LYAwoxfQEP6E4z4WVPpfB8iY6wA0pJ-PFYC2xc8TwvVen89c3wwRRCiEAA */
|
||||
/** @xstate-layout N4IgpgJg5mDOIC5QDcDGBaAlgFzAWwGIAlAUQDFSBlACQG0AGAXUVAAcB7WHTdgOxZAAPRABYATABoQAT0QBGABwBWAHT0FAZjEB2bSKUBOA9rliAvmalosuPCtQALMKgDWmXlABqqAgHESACoA+p4AwkFUAAoA8gBylCQMzEggHFzYPPwpwggKBiIqcvqaAGwGSvT0SnJSsgjicio69Np5GvTFSiIWVhg4+PZOru5ePv7BYREklDHxiXLJbJzcfAI5eQVFSqXlldW1iO2qmlpKhtpnGkbdliDW-XaOzm4elNjsAE5gBJQB0aRTGZxBJJARpFZZUA5OSmA4IMRyDQFDRKDQmMRiDRyAwKG69GwDJ7DV7vL4-P4AqLA+aLVLLDKrbLyJRiBRNAxybT0MRnQwKBSSGTyXFNERGPIwhFo-k9O59WyDZ4jShgD7IVUAEQAhtgtYriVA3jqAK6wAgxAAyFtBKXBDMhQkQPO0TTORQMJRZ2hKyjhihEbLkHRaXVRcmqCll9wVRJehtV6o+2t1+rjRuwpoIGuiAHVYhbogBBDVTYsATRtS3SmTWokMhWD9HyJRKRUxfuMYjUJQRBnaii6VSj8sJQzTCc1Or1EHYAHdeAAbdhaiAjUJfCBgXgZLUL83RK2VunVxlQxAKIMqETiCVo6pnBR+hQlDSFBTaMQlEQdL8dPFyglHjHZUJyTKcVBneclxXNcNy3Hc91CUgNRIWIAgASULC0gmzPMC2LEgNSPO0ayZBAg3yQoURMGjLg9DsxAKD88gxERsQDVph0AlRMAgBdvkI9DggCQtfGI+lSLPeERBdNiShMIMtDFb8lDhT9ORUNERDKZ9rw-JQuIeHi+O+TwSCIdCyArJgwQk09HXhT8ShUd8ujyFkMUMEo1LEFoVBZbl6BhBQQzRQyFV4-iCALUIAGkQlCcSTwdHIdA0V8kW01k5BKegexaNTvUad9r206of3MW5owGSLvlITxolikgEqSiFa1yQU6lZEKXL0JRPS5AMXwMqqRzsWqCGLEscywi1AiCAAhdDYg1ZbfCCdCiJs207JS+ROv28KBkgbgPACLUoCzdDKAAWWuyhWvtdrMVknKFPoJT8iqNT0voQp9By79TB7AwjrsE6MjOi6fkLMyghEsTtqrNqyMY175JhD7GK+1ShWk6pChbREBQMDpPzBlRYFJEZzsu35-maqk5keySHP645yhbDolMUbQ1IBwnWw0EmyZKCnE0wAAzaRYMgeDMF3AgZ14MAeN4ZB2BcVXqrsCXpdlzdtwVhcEHcDXUB1TIkhZ+zUqc3q3PKDEeXovHfNbFQvwqSoUSbF9xdVKWZY8dc5aNxXVQ+T4VFYBcdUlz5dbGlQ9eDqBQ8NhDTfV9gLfta2kePFGpM85zXIDJ3PNdupsR9T3n3KFFlDYnKKdjEZPEDyXMDzzJ00zG29vI5QDBc5QuSMfqPUUJ8KjfMogp5apurb4CPE7j4pZ7y2+H7s1aAWWzkvagdR-5JQJ856fHzdxRR69gMZP5FptAps3d14ghlsiABVYJogCJEQe7UtAujyjyHQRR5JiD7HCEQVxVBP2MHlPq-tRrcXfguT+q1br3WAWRUB3YIEmG0h+WBeNhZflFMYVsYoSGVXxEZL4ABHY0cBIZQGiNgVgSs+CqzNprbWycWFsKpiMLhrBs7mx3rwAutISK23kDCV8MDfLpX6pUD6cCuTOT7NoShbEL75ApiI9h4juEEEjtHWO8dE4p2EWAVhZiPASKkbnGRcij7FwcjCRE7I1Eolyj7OBQsVDGFJp6fQMCigUy1KgVAYBWAcIkehXgrBjTYC-rEX+-9AH4KkmUVQ4C3S4lKTiOBzQVDMQFEDC+SJYnxMSck7hqT0mZJwXdSgD1C4KKHqYJs9cQrtHKHoRicINAY38iTTQ1waIaAaQkpJIwiBgA1lrVpGSsk5KCAAoBPTdonzeoUIov1tBfRgbjGuiJjjpS0O0TQLIRqMIVHExZHCVlrLABs9p11OndPkQcsiRhGimH0GKAUXIsZwjIVebYPIfSIkfq-dBTDHGiI4RaXOLheEqzVp8+x3FTFiI8Ji1wbje58E8TtY+ZEfRFJ7CUx+eQb51CuM+KpXJzj3MUGLFFCoiUYqxZYj4UcPgxzjtgBOHwk6ErRc4qApKXDko8UwfJDlClEMZWUllog2L3w+n2KUDyhx8oGEuA03hyQM0BLMEE+yaVSV8SogwASNHBLxt+PyRgPTvhyuoF1Ji5XEqgB8wROL+E5y1gS1FTjg2hq1sq-Oqr7XeNSqTJo6g0TekxBeE54yfaC17PJF86hA2xveassNVixU2MlXYnWKgBXLMrQmgRFLZHJoBQ6hyhDimQNITAjQcCYSqACmKPKTt0qBrWR3Hw9NKTTFtYkFNT1aVnJcuUAUFQrifj0PmtEntGKtmbPJb8vLnlmvYFAKAzbPlXVwV0tV0IX5Xh9N6xEaJWQHQQO0A9PZtLsRbHoPKZb0UjAWu4VcLiLHKwjfihtTaPAQd4FBzh3DE1W07V41dUlf1hMgQ8oMRjv3A1UEGM9T8ijiCeQBGNYGkOQfMTw6t4rbHSujfyoNHDkOodcW2lVjAn2HA+vhkwhGqhnO-RURogVi1C36vAimsAHBzhICKz4BBQiFliKEEg1oV2sxyJ6ZypgKjPm9HkPKOqEAeWod6eBjFFJyAWU08DjHoM8O-n-HZeSDOKIQBcWSrQZk5UoeGP0S8qnRPDF+i4wsXNLIYyhpj96-lCYCxfK8wWrihefOFvGF8ux6G9byZ0sSIAQFimAaQkQtSYA+OGvFgiOMDBXJV6rtX6sYcpVh6lqalHyWOfA9oZzvwXIiyKLkJM2ItBkvo8r7Wat1Yayx2tUqZVGTa1VpbXX+NJsE35vpRyYTDZaOc8ofoya9TFIDdK4TkUXrsG1kYOZdz8WwDxkY6EICNYEVGhtz2PCvYXO9z7HhvvdY7Qdrt-Wf0aT7SQ6B5DWWFc0noeS6V9H9Xqaap7FWXtvbAB99zUBvvCtFaxut7GAf46B4T4nyXwcQEh1S5GOGe1+QR1AshQ6KFYk2IxVEAomwohow240rAICWw8JETeyAdRgG279yNQjuIS6lxw2XmB5e4G2yz3rbPDOIFaGRlETKZKYhfOMupmlyiDkChcEDuOVDq+l1ALXOvFfVfJ9YiV62Wt2Fd5ruXCu9d7cw9D7DRuAvKCom5JFlveesv0CZj6ehwxIlMA92jCplNzjB4aXUGYzRLRWmtHCcRl0w-Z9CXy99n7DIvuIEQ4yewyZJhMowPIQojVuLwdgm54ApB1lH-z6AJlwnQP0tQmjTBIgFFnhhOfRxKnXqgUfQ9bPexyuUD0YpDDjNj8V5sQUX4nFXqvwvnwwAb5PgiAomi-YIlZMUfmzlj-FFaF+zEF+DQqjVJOLqLfmRCdn6GUM5LlN+M+O0PJE7o9qmCBAAWBCmO3CSCaEPobv5jlCRvkKPOAr5OoKUoYGLsnKgfGEgcmNOHOIuMuKhhnPLLuMAQUnXEiFmnUqiLoDgVQlsMLPkK0L4uesvuNCZEwQ5NjA-pKKiEYPoroIVDyNdkNPkCOq3M7hDDTBdKIc+t+p+AMmKMYFiO+B6KDM7lTJ8OoVAJoYcLHuEkFMLJ+FiC6t5G7PoH9O5DoB6J+M+BiAHJvPrCHHBOHAuJYfCNyEVtiBiKwb5J+GpIDLbl0F+kYBMkvg2mQRvFvO2nvMEYiINufDRB+BZloDEcLC5KYHXopNsLiG-OrB-BAMEWxFeO+pUDApUB+nAkiH9MUHlNiPoiFMkcnJgrxCoOwNwsEXkA0cCk0aTLYUnrqjoGEtsFnl7MVlUfLlghACoAAEZxJawobBEupwJDSwpnJ8FVD8jZ4IZcZMbBGshUK5QsgTJBQXgi4hIDJTYIjchGB3EJbNKsDfKjHrpfhCzwJ5b6EVKaBhKhYuq6R0IkHcSvKuYeDxpfJpIZLBGBZZb8g5Yvh5aXJKKVBxE95iY3aRjO6IYKpYp1EfiFA8iIichcgnbfrwLlAZq5q+SYxBQUzmpxjeD-F-ThIyQfQwh6B5DjI4gFDeqFLcgfgwiCEXHlq3qCLBHyTDqmBRYN475jbTqayzp1EcgEl6IBjVC8z5pFCHr6BohJF5QdCclXo3qIkto359Y17njrriBiYupOxVC4k-otFmn9S6C4ifioigbyoF4SJ1EkaMR-RTZojTynHGImEqazhqairBFej+QtGFJ7675wi2Yf6-gCjySwmbaNKJZQBhkjFOnR4shsgnCmDKCVAmDlJ4ymZ-S3LNDBiwHGHwFbYdbLZ7FIiaRC6fh0Kfj7EtnZQQmejKDhjigmo9m05QDA6g4k7fZpl8weoQLzEL55TaTzLO5B4jAe6h7VZpn6ANh6ruHwIyTelNyvgnBVAejqBfgknwF56zgF6ZFVlYEFpQKKQchvStDW44hqDTaGl5AWAWBAA */
|
||||
model.createMachine(
|
||||
{
|
||||
predictableActionArguments: true,
|
||||
@@ -112,8 +136,20 @@ export const vcItemMachine =
|
||||
checkingServerData: {
|
||||
description:
|
||||
"Download VC data from the server. Uses polling method to check when it's available.",
|
||||
initial: 'checkingStatus',
|
||||
initial: 'verifyingDownloadLimitExpiry',
|
||||
states: {
|
||||
verifyingDownloadLimitExpiry: {
|
||||
invoke: {
|
||||
src: 'checkDownloadExpiryLimit',
|
||||
onDone: {
|
||||
target: 'checkingStatus',
|
||||
actions: 'setMaxDownloadCount',
|
||||
},
|
||||
onError: {
|
||||
actions: log((_, event) => (event.data as Error).message),
|
||||
},
|
||||
},
|
||||
},
|
||||
checkingStatus: {
|
||||
invoke: {
|
||||
src: 'checkStatus',
|
||||
@@ -121,10 +157,10 @@ export const vcItemMachine =
|
||||
},
|
||||
on: {
|
||||
POLL: {
|
||||
cond: 'isDownloadAllowed',
|
||||
actions: send('POLL_STATUS', { to: 'checkStatus' }),
|
||||
},
|
||||
DOWNLOAD_READY: {
|
||||
actions: 'resetDownloadCounter',
|
||||
target: 'downloadingCredential',
|
||||
},
|
||||
},
|
||||
@@ -172,6 +208,9 @@ export const vcItemMachine =
|
||||
REVOKE_VC: {
|
||||
target: 'acceptingRevokeInput',
|
||||
},
|
||||
ADD_WALLET_BINDING_ID: {
|
||||
target: 'showBindingWarning',
|
||||
},
|
||||
},
|
||||
},
|
||||
editingTag: {
|
||||
@@ -330,7 +369,10 @@ export const vcItemMachine =
|
||||
],
|
||||
onError: [
|
||||
{
|
||||
actions: [log('OTP error'), 'setOtpError'],
|
||||
actions: [
|
||||
log((_, event) => (event.data as Error).message),
|
||||
'setOtpError',
|
||||
],
|
||||
target: 'acceptingOtpInput',
|
||||
},
|
||||
],
|
||||
@@ -352,10 +394,136 @@ export const vcItemMachine =
|
||||
},
|
||||
},
|
||||
},
|
||||
showBindingWarning: {
|
||||
on: {
|
||||
CONFIRM: {
|
||||
target: 'requestingBindingOtp',
|
||||
},
|
||||
CANCEL: {
|
||||
target: 'idle',
|
||||
},
|
||||
},
|
||||
},
|
||||
requestingBindingOtp: {
|
||||
invoke: {
|
||||
src: 'requestBindingOtp',
|
||||
onDone: [
|
||||
{
|
||||
target: 'acceptingBindingOtp',
|
||||
},
|
||||
],
|
||||
onError: [
|
||||
{
|
||||
actions: 'setWalletBindingError',
|
||||
target: 'showingWalletBindingError',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
showingWalletBindingError: {
|
||||
on: {
|
||||
CANCEL: {
|
||||
target: 'idle',
|
||||
actions: 'setWalletBindingErrorEmpty',
|
||||
},
|
||||
},
|
||||
},
|
||||
acceptingBindingOtp: {
|
||||
entry: ['clearOtp'],
|
||||
on: {
|
||||
INPUT_OTP: {
|
||||
target: 'addKeyPair',
|
||||
actions: ['setOtp'],
|
||||
},
|
||||
DISMISS: {
|
||||
target: 'idle',
|
||||
actions: ['clearOtp', 'clearTransactionId'],
|
||||
},
|
||||
},
|
||||
},
|
||||
addKeyPair: {
|
||||
invoke: {
|
||||
src: 'generateKeyPair',
|
||||
onDone: {
|
||||
target: 'addingWalletBindingId',
|
||||
actions: ['setPublicKey', 'setPrivateKey'],
|
||||
},
|
||||
onError: [
|
||||
{
|
||||
actions: 'setWalletBindingError',
|
||||
target: 'showingWalletBindingError',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
addingWalletBindingId: {
|
||||
invoke: {
|
||||
src: 'addWalletBindnigId',
|
||||
onDone: [
|
||||
{
|
||||
target: 'updatingPrivateKey',
|
||||
actions: ['setWalletBindingId'],
|
||||
},
|
||||
],
|
||||
onError: [
|
||||
{
|
||||
actions: 'setWalletBindingError',
|
||||
target: 'showingWalletBindingError',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
updatingPrivateKey: {
|
||||
invoke: {
|
||||
src: 'updatePrivateKey',
|
||||
onDone: {
|
||||
target: 'showBindingStatus',
|
||||
actions: ['updatePrivateKey', 'updateVc'],
|
||||
},
|
||||
onError: {
|
||||
actions: 'setWalletBindingError',
|
||||
target: 'showingWalletBindingError',
|
||||
},
|
||||
},
|
||||
},
|
||||
showBindingStatus: {
|
||||
entry: 'storeContext',
|
||||
on: {
|
||||
BINDING_DONE: {
|
||||
target: 'idle',
|
||||
actions: 'setWalletBindingErrorEmpty',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
actions: {
|
||||
setWalletBindingError: assign({
|
||||
walletBindingError: (context, event) => (event.data as Error).message,
|
||||
}),
|
||||
|
||||
setWalletBindingErrorEmpty: assign({
|
||||
walletBindingError: () => '',
|
||||
}),
|
||||
|
||||
setPublicKey: assign({
|
||||
publicKey: (context, event) => (event.data as KeyPair).public,
|
||||
}),
|
||||
|
||||
setPrivateKey: assign({
|
||||
privateKey: (context, event) => (event.data as KeyPair).private,
|
||||
}),
|
||||
|
||||
updatePrivateKey: assign({
|
||||
privateKey: () => '',
|
||||
}),
|
||||
|
||||
setWalletBindingId: assign({
|
||||
walletBindingResponse: (context, event) =>
|
||||
event.data as WalletBindingResponse,
|
||||
}),
|
||||
|
||||
updateVc: send(
|
||||
(context) => {
|
||||
const { serviceRefs, ...vc } = context;
|
||||
@@ -397,14 +565,14 @@ export const vcItemMachine =
|
||||
tag: (_, event) => event.tag,
|
||||
}),
|
||||
|
||||
resetDownloadCounter: model.assign({
|
||||
downloadCounter: () => 0,
|
||||
}),
|
||||
|
||||
incrementDownloadCounter: model.assign({
|
||||
downloadCounter: ({ downloadCounter }) => downloadCounter + 1,
|
||||
}),
|
||||
|
||||
setMaxDownloadCount: model.assign({
|
||||
maxDownloadCount: (_context, event) => event.data as number,
|
||||
}),
|
||||
|
||||
storeTag: send(
|
||||
(context) => {
|
||||
const { serviceRefs, ...data } = context;
|
||||
@@ -506,6 +674,80 @@ export const vcItemMachine =
|
||||
},
|
||||
|
||||
services: {
|
||||
checkDownloadExpiryLimit: async (context) => {
|
||||
var resp = await getAllConfigurations();
|
||||
const maxLimit: number = resp.vcDownloadMaxRetry;
|
||||
console.log(maxLimit);
|
||||
if (maxLimit <= context.downloadCounter) {
|
||||
throw new Error(
|
||||
'Download limit expired for request id: ' + context.requestId
|
||||
);
|
||||
}
|
||||
return maxLimit;
|
||||
},
|
||||
|
||||
addWalletBindnigId: async (context) => {
|
||||
const response = await request('POST', '/wallet-binding', {
|
||||
requestTime: String(new Date().toISOString()),
|
||||
request: {
|
||||
authFactorType: 'WLA',
|
||||
format: 'jwt',
|
||||
individualId: context.id,
|
||||
transactionId: context.bindingTransactionId,
|
||||
publicKey: context.publicKey,
|
||||
challengeList: [
|
||||
{
|
||||
authFactorType: 'OTP',
|
||||
challenge: context.otp,
|
||||
format: 'alpha-numeric',
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
const certificate = response.response.certificate;
|
||||
await savePrivateKey(
|
||||
getBindingCertificateConstant(context.id),
|
||||
certificate
|
||||
);
|
||||
|
||||
const walletResponse: WalletBindingResponse = {
|
||||
walletBindingId: response.response.encryptedWalletBindingId,
|
||||
keyId: response.response.keyId,
|
||||
thumbprint: response.response.thumbprint,
|
||||
expireDateTime: response.response.expireDateTime,
|
||||
};
|
||||
return walletResponse;
|
||||
},
|
||||
|
||||
updatePrivateKey: async (context) => {
|
||||
const hasSetPrivateKey: boolean = await savePrivateKey(
|
||||
context.walletBindingResponse.walletBindingId,
|
||||
context.privateKey
|
||||
);
|
||||
if (!hasSetPrivateKey) {
|
||||
throw new Error('Could not store private key in keystore.');
|
||||
}
|
||||
return '';
|
||||
},
|
||||
|
||||
generateKeyPair: async (context) => {
|
||||
let keyPair: KeyPair = await generateKeys();
|
||||
return keyPair;
|
||||
},
|
||||
|
||||
requestBindingOtp: async (context) => {
|
||||
const response = await request('POST', '/binding-otp', {
|
||||
requestTime: String(new Date().toISOString()),
|
||||
request: {
|
||||
individualId: context.id,
|
||||
otpChannels: ['EMAIL'],
|
||||
},
|
||||
});
|
||||
if (response.response == null) {
|
||||
throw new Error('Could not process request');
|
||||
}
|
||||
},
|
||||
|
||||
checkStatus: (context) => (callback, onReceive) => {
|
||||
const pollInterval = setInterval(
|
||||
() => callback(model.events.POLL()),
|
||||
@@ -561,6 +803,7 @@ export const vcItemMachine =
|
||||
isVerified: false,
|
||||
lastVerifiedOn: null,
|
||||
locked: context.locked,
|
||||
walletBindingResponse: null,
|
||||
})
|
||||
);
|
||||
}
|
||||
@@ -633,7 +876,7 @@ export const vcItemMachine =
|
||||
},
|
||||
|
||||
isDownloadAllowed: (_context, event) => {
|
||||
return _context.downloadCounter < 10;
|
||||
return _context.downloadCounter <= _context.maxDownloadCount;
|
||||
},
|
||||
|
||||
isVcValid: (context) => {
|
||||
@@ -724,6 +967,46 @@ export function selectIsAcceptingRevokeInput(state: State) {
|
||||
return state.matches('acceptingRevokeInput');
|
||||
}
|
||||
|
||||
export function selectIsRequestingOtp(state: State) {
|
||||
return state.matches('requestingOtp');
|
||||
export function selectIsRequestBindingOtp(state: State) {
|
||||
return state.matches('requestingBindingOtp');
|
||||
}
|
||||
|
||||
export function selectWalletBindingId(state: State) {
|
||||
return state.context.walletBindingResponse;
|
||||
}
|
||||
|
||||
export function selectEmptyWalletBindingId(state: State) {
|
||||
var val = state.context.walletBindingResponse
|
||||
? state.context.walletBindingResponse.walletBindingId
|
||||
: undefined;
|
||||
return val === undefined || val == null || val.length <= 0 ? true : false;
|
||||
}
|
||||
|
||||
export function selectWalletBindingError(state: State) {
|
||||
return state.context.walletBindingError;
|
||||
}
|
||||
|
||||
export function selectAcceptingBindingOtp(state: State) {
|
||||
return state.matches('acceptingBindingOtp');
|
||||
}
|
||||
|
||||
export function selectShowBindingStatus(state: State) {
|
||||
return state.matches('showBindingStatus');
|
||||
}
|
||||
|
||||
export function selectShowWalletBindingError(state: State) {
|
||||
return state.matches('showingWalletBindingError');
|
||||
}
|
||||
|
||||
export function isWalletBindingInProgress(state: State) {
|
||||
return state.matches('requestingBindingOtp') ||
|
||||
state.matches('addingWalletBindingId') ||
|
||||
state.matches('addKeyPair') ||
|
||||
state.matches('updatingPrivateKey')
|
||||
? true
|
||||
: false;
|
||||
}
|
||||
|
||||
export function isShowingBindingWarning(state: State) {
|
||||
return state.matches('showBindingWarning');
|
||||
}
|
||||
|
||||
@@ -14,6 +14,26 @@ export interface Typegen0 {
|
||||
data: unknown;
|
||||
__tip: 'See the XState TS docs to learn how to strongly type this.';
|
||||
};
|
||||
'done.invoke.vc-item.addKeyPair:invocation[0]': {
|
||||
type: 'done.invoke.vc-item.addKeyPair:invocation[0]';
|
||||
data: unknown;
|
||||
__tip: 'See the XState TS docs to learn how to strongly type this.';
|
||||
};
|
||||
'done.invoke.vc-item.addingWalletBindingId:invocation[0]': {
|
||||
type: 'done.invoke.vc-item.addingWalletBindingId:invocation[0]';
|
||||
data: unknown;
|
||||
__tip: 'See the XState TS docs to learn how to strongly type this.';
|
||||
};
|
||||
'done.invoke.vc-item.checkingServerData.verifyingDownloadLimitExpiry:invocation[0]': {
|
||||
type: 'done.invoke.vc-item.checkingServerData.verifyingDownloadLimitExpiry:invocation[0]';
|
||||
data: unknown;
|
||||
__tip: 'See the XState TS docs to learn how to strongly type this.';
|
||||
};
|
||||
'done.invoke.vc-item.requestingBindingOtp:invocation[0]': {
|
||||
type: 'done.invoke.vc-item.requestingBindingOtp:invocation[0]';
|
||||
data: unknown;
|
||||
__tip: 'See the XState TS docs to learn how to strongly type this.';
|
||||
};
|
||||
'done.invoke.vc-item.requestingLock:invocation[0]': {
|
||||
type: 'done.invoke.vc-item.requestingLock:invocation[0]';
|
||||
data: unknown;
|
||||
@@ -29,6 +49,11 @@ export interface Typegen0 {
|
||||
data: unknown;
|
||||
__tip: 'See the XState TS docs to learn how to strongly type this.';
|
||||
};
|
||||
'done.invoke.vc-item.updatingPrivateKey:invocation[0]': {
|
||||
type: 'done.invoke.vc-item.updatingPrivateKey:invocation[0]';
|
||||
data: unknown;
|
||||
__tip: 'See the XState TS docs to learn how to strongly type this.';
|
||||
};
|
||||
'done.invoke.vc-item.verifyingCredential:invocation[0]': {
|
||||
type: 'done.invoke.vc-item.verifyingCredential:invocation[0]';
|
||||
data: unknown;
|
||||
@@ -42,6 +67,18 @@ export interface Typegen0 {
|
||||
type: 'error.platform.downloadCredential';
|
||||
data: unknown;
|
||||
};
|
||||
'error.platform.vc-item.addKeyPair:invocation[0]': {
|
||||
type: 'error.platform.vc-item.addKeyPair:invocation[0]';
|
||||
data: unknown;
|
||||
};
|
||||
'error.platform.vc-item.addingWalletBindingId:invocation[0]': {
|
||||
type: 'error.platform.vc-item.addingWalletBindingId:invocation[0]';
|
||||
data: unknown;
|
||||
};
|
||||
'error.platform.vc-item.requestingBindingOtp:invocation[0]': {
|
||||
type: 'error.platform.vc-item.requestingBindingOtp:invocation[0]';
|
||||
data: unknown;
|
||||
};
|
||||
'error.platform.vc-item.requestingLock:invocation[0]': {
|
||||
type: 'error.platform.vc-item.requestingLock:invocation[0]';
|
||||
data: unknown;
|
||||
@@ -50,6 +87,10 @@ export interface Typegen0 {
|
||||
type: 'error.platform.vc-item.requestingRevoke:invocation[0]';
|
||||
data: unknown;
|
||||
};
|
||||
'error.platform.vc-item.updatingPrivateKey:invocation[0]': {
|
||||
type: 'error.platform.vc-item.updatingPrivateKey:invocation[0]';
|
||||
data: unknown;
|
||||
};
|
||||
'error.platform.vc-item.verifyingCredential:invocation[0]': {
|
||||
type: 'error.platform.vc-item.verifyingCredential:invocation[0]';
|
||||
data: unknown;
|
||||
@@ -57,11 +98,16 @@ export interface Typegen0 {
|
||||
'xstate.init': { type: 'xstate.init' };
|
||||
};
|
||||
'invokeSrcNameMap': {
|
||||
addWalletBindnigId: 'done.invoke.vc-item.addingWalletBindingId:invocation[0]';
|
||||
checkDownloadExpiryLimit: 'done.invoke.vc-item.checkingServerData.verifyingDownloadLimitExpiry:invocation[0]';
|
||||
checkStatus: 'done.invoke.checkStatus';
|
||||
downloadCredential: 'done.invoke.downloadCredential';
|
||||
generateKeyPair: 'done.invoke.vc-item.addKeyPair:invocation[0]';
|
||||
requestBindingOtp: 'done.invoke.vc-item.requestingBindingOtp:invocation[0]';
|
||||
requestLock: 'done.invoke.vc-item.requestingLock:invocation[0]';
|
||||
requestOtp: 'done.invoke.vc-item.requestingOtp:invocation[0]';
|
||||
requestRevoke: 'done.invoke.vc-item.requestingRevoke:invocation[0]';
|
||||
updatePrivateKey: 'done.invoke.vc-item.updatingPrivateKey:invocation[0]';
|
||||
verifyCredential: 'done.invoke.vc-item.verifyingCredential:invocation[0]';
|
||||
};
|
||||
'missingImplementations': {
|
||||
@@ -73,9 +119,12 @@ export interface Typegen0 {
|
||||
'eventsCausingActions': {
|
||||
clearOtp:
|
||||
| ''
|
||||
| 'BINDING_DONE'
|
||||
| 'CANCEL'
|
||||
| 'DISMISS'
|
||||
| 'REVOKE_VC'
|
||||
| 'STORE_RESPONSE'
|
||||
| 'done.invoke.vc-item.requestingBindingOtp:invocation[0]'
|
||||
| 'done.invoke.vc-item.requestingOtp:invocation[0]'
|
||||
| 'done.invoke.vc-item.verifyingCredential:invocation[0]'
|
||||
| 'error.platform.vc-item.requestingLock:invocation[0]'
|
||||
@@ -83,6 +132,8 @@ export interface Typegen0 {
|
||||
| 'error.platform.vc-item.verifyingCredential:invocation[0]';
|
||||
clearTransactionId:
|
||||
| ''
|
||||
| 'BINDING_DONE'
|
||||
| 'CANCEL'
|
||||
| 'DISMISS'
|
||||
| 'STORE_RESPONSE'
|
||||
| 'done.invoke.vc-item.verifyingCredential:invocation[0]'
|
||||
@@ -93,17 +144,19 @@ export interface Typegen0 {
|
||||
markVcValid: 'done.invoke.vc-item.verifyingCredential:invocation[0]';
|
||||
requestStoredContext: 'GET_VC_RESPONSE' | 'REFRESH';
|
||||
requestVcContext: 'xstate.init';
|
||||
resetDownloadCounter: 'DOWNLOAD_READY';
|
||||
revokeVID: 'done.invoke.vc-item.requestingRevoke:invocation[0]';
|
||||
setCredential:
|
||||
| 'CREDENTIAL_DOWNLOADED'
|
||||
| 'GET_VC_RESPONSE'
|
||||
| 'STORE_RESPONSE';
|
||||
setLock: 'done.invoke.vc-item.requestingLock:invocation[0]';
|
||||
setMaxDownloadCount: 'done.invoke.vc-item.checkingServerData.verifyingDownloadLimitExpiry:invocation[0]';
|
||||
setOtp: 'INPUT_OTP';
|
||||
setOtpError:
|
||||
| 'error.platform.vc-item.requestingLock:invocation[0]'
|
||||
| 'error.platform.vc-item.requestingRevoke:invocation[0]';
|
||||
setPrivateKey: 'done.invoke.vc-item.addKeyPair:invocation[0]';
|
||||
setPublicKey: 'done.invoke.vc-item.addKeyPair:invocation[0]';
|
||||
setRevoke: 'done.invoke.vc-item.requestingRevoke:invocation[0]';
|
||||
setTag: 'SAVE_TAG';
|
||||
setTransactionId:
|
||||
@@ -112,14 +165,24 @@ export interface Typegen0 {
|
||||
| 'done.invoke.vc-item.requestingOtp:invocation[0]'
|
||||
| 'error.platform.vc-item.requestingLock:invocation[0]'
|
||||
| 'error.platform.vc-item.requestingRevoke:invocation[0]';
|
||||
setWalletBindingError:
|
||||
| 'error.platform.vc-item.addKeyPair:invocation[0]'
|
||||
| 'error.platform.vc-item.addingWalletBindingId:invocation[0]'
|
||||
| 'error.platform.vc-item.requestingBindingOtp:invocation[0]'
|
||||
| 'error.platform.vc-item.updatingPrivateKey:invocation[0]';
|
||||
setWalletBindingErrorEmpty: 'BINDING_DONE' | 'CANCEL';
|
||||
setWalletBindingId: 'done.invoke.vc-item.addingWalletBindingId:invocation[0]';
|
||||
storeContext:
|
||||
| 'CREDENTIAL_DOWNLOADED'
|
||||
| 'done.invoke.vc-item.updatingPrivateKey:invocation[0]'
|
||||
| 'done.invoke.vc-item.verifyingCredential:invocation[0]';
|
||||
storeLock: 'done.invoke.vc-item.requestingLock:invocation[0]';
|
||||
storeTag: 'SAVE_TAG';
|
||||
updatePrivateKey: 'done.invoke.vc-item.updatingPrivateKey:invocation[0]';
|
||||
updateVc:
|
||||
| 'CREDENTIAL_DOWNLOADED'
|
||||
| 'STORE_RESPONSE'
|
||||
| 'done.invoke.vc-item.updatingPrivateKey:invocation[0]'
|
||||
| 'done.invoke.vc-item.verifyingCredential:invocation[0]';
|
||||
};
|
||||
'eventsCausingDelays': {};
|
||||
@@ -129,19 +192,28 @@ export interface Typegen0 {
|
||||
isVcValid: '';
|
||||
};
|
||||
'eventsCausingServices': {
|
||||
checkStatus: 'STORE_RESPONSE';
|
||||
addWalletBindnigId: 'done.invoke.vc-item.addKeyPair:invocation[0]';
|
||||
checkDownloadExpiryLimit: 'STORE_RESPONSE';
|
||||
checkStatus: 'done.invoke.vc-item.checkingServerData.verifyingDownloadLimitExpiry:invocation[0]';
|
||||
downloadCredential: 'DOWNLOAD_READY';
|
||||
generateKeyPair: 'INPUT_OTP';
|
||||
requestBindingOtp: 'CONFIRM';
|
||||
requestLock: 'INPUT_OTP';
|
||||
requestOtp: 'LOCK_VC';
|
||||
requestRevoke: 'INPUT_OTP';
|
||||
updatePrivateKey: 'done.invoke.vc-item.addingWalletBindingId:invocation[0]';
|
||||
verifyCredential: '' | 'VERIFY';
|
||||
};
|
||||
'matchesStates':
|
||||
| 'acceptingBindingOtp'
|
||||
| 'acceptingOtpInput'
|
||||
| 'acceptingRevokeInput'
|
||||
| 'addKeyPair'
|
||||
| 'addingWalletBindingId'
|
||||
| 'checkingServerData'
|
||||
| 'checkingServerData.checkingStatus'
|
||||
| 'checkingServerData.downloadingCredential'
|
||||
| 'checkingServerData.verifyingDownloadLimitExpiry'
|
||||
| 'checkingStore'
|
||||
| 'checkingVc'
|
||||
| 'checkingVerificationStatus'
|
||||
@@ -152,14 +224,22 @@ export interface Typegen0 {
|
||||
| 'invalid.otp'
|
||||
| 'lockingVc'
|
||||
| 'loggingRevoke'
|
||||
| 'requestingBindingOtp'
|
||||
| 'requestingLock'
|
||||
| 'requestingOtp'
|
||||
| 'requestingRevoke'
|
||||
| 'revokingVc'
|
||||
| 'showBindingStatus'
|
||||
| 'showBindingWarning'
|
||||
| 'showingWalletBindingError'
|
||||
| 'storingTag'
|
||||
| 'updatingPrivateKey'
|
||||
| 'verifyingCredential'
|
||||
| {
|
||||
checkingServerData?: 'checkingStatus' | 'downloadingCredential';
|
||||
checkingServerData?:
|
||||
| 'checkingStatus'
|
||||
| 'downloadingCredential'
|
||||
| 'verifyingDownloadLimitExpiry';
|
||||
invalid?: 'backend' | 'otp';
|
||||
};
|
||||
'tags': never;
|
||||
|
||||
50
package-lock.json
generated
50
package-lock.json
generated
@@ -40,6 +40,7 @@
|
||||
"expo-updates": "~0.11.6",
|
||||
"i18next": "^21.6.16",
|
||||
"mosip-inji-face-sdk": "^0.1.7",
|
||||
"node-forge": "^1.3.1",
|
||||
"react": "17.0.1",
|
||||
"react-i18next": "^11.16.6",
|
||||
"react-native": "0.64.4",
|
||||
@@ -58,8 +59,10 @@
|
||||
"react-native-popable": "^0.4.3",
|
||||
"react-native-qrcode-svg": "^6.1.1",
|
||||
"react-native-restart": "^0.0.24",
|
||||
"react-native-rsa-native": "^2.0.5",
|
||||
"react-native-safe-area-context": "3.3.2",
|
||||
"react-native-screens": "~3.10.1",
|
||||
"react-native-secure-key-store": "^2.0.10",
|
||||
"react-native-securerandom": "^1.0.0",
|
||||
"react-native-simple-markdown": "^1.1.0",
|
||||
"react-native-svg": "12.1.1",
|
||||
@@ -1999,6 +2002,14 @@
|
||||
"node": ">=8.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@digitalbazaar/rsa-verification-key-2018/node_modules/node-forge": {
|
||||
"version": "0.9.2",
|
||||
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.9.2.tgz",
|
||||
"integrity": "sha512-naKSScof4Wn+aoHU6HBsifh92Zeicm1GDQKd1vp3Y/kOi8ub0DozCa9KpvYNCXslFHYRmLNiqRopGdTGwNLpNw==",
|
||||
"engines": {
|
||||
"node": ">= 4.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@digitalbazaar/rsa-verification-key-2018/node_modules/semver": {
|
||||
"version": "7.3.7",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
|
||||
@@ -18039,11 +18050,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/node-forge": {
|
||||
"version": "0.9.2",
|
||||
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.9.2.tgz",
|
||||
"integrity": "sha512-naKSScof4Wn+aoHU6HBsifh92Zeicm1GDQKd1vp3Y/kOi8ub0DozCa9KpvYNCXslFHYRmLNiqRopGdTGwNLpNw==",
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz",
|
||||
"integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==",
|
||||
"engines": {
|
||||
"node": ">= 4.5.0"
|
||||
"node": ">= 6.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/node-gyp-build": {
|
||||
@@ -21236,6 +21247,11 @@
|
||||
"react-native": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-rsa-native": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/react-native-rsa-native/-/react-native-rsa-native-2.0.5.tgz",
|
||||
"integrity": "sha512-gwwvFSwGW5WKrpDyBQ/eTf1UrVABeAvMcT4YWemzPSUo6aHZs1kbBm2rXmwN5okhUzJsry5zjjz/qdx5GXRugQ=="
|
||||
},
|
||||
"node_modules/react-native-safe-area-context": {
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-3.3.2.tgz",
|
||||
@@ -21258,6 +21274,11 @@
|
||||
"react-native": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-secure-key-store": {
|
||||
"version": "2.0.10",
|
||||
"resolved": "https://registry.npmjs.org/react-native-secure-key-store/-/react-native-secure-key-store-2.0.10.tgz",
|
||||
"integrity": "sha512-K7aVlIGxyklnjhCidVexVgZF3LsgUD9GIxMy2NB/xkQsS9E2SJWkD/fJ56e25L2I6a9Mp1zuJrKnCtfBs1CvAw=="
|
||||
},
|
||||
"node_modules/react-native-securerandom": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/react-native-securerandom/-/react-native-securerandom-1.0.1.tgz",
|
||||
@@ -28857,6 +28878,11 @@
|
||||
"resolved": "https://registry.npmjs.org/crypto-ld/-/crypto-ld-4.0.3.tgz",
|
||||
"integrity": "sha512-IeNCX1wv7kLjxhKrCV6Jee0CU84e2dSyVxTaM3SCuO8/fMbYzjsx1e1js+c7w8GlOslubOHJKvhJ1EI+aZ1MwQ=="
|
||||
},
|
||||
"node-forge": {
|
||||
"version": "0.9.2",
|
||||
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.9.2.tgz",
|
||||
"integrity": "sha512-naKSScof4Wn+aoHU6HBsifh92Zeicm1GDQKd1vp3Y/kOi8ub0DozCa9KpvYNCXslFHYRmLNiqRopGdTGwNLpNw=="
|
||||
},
|
||||
"semver": {
|
||||
"version": "7.3.7",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
|
||||
@@ -41592,9 +41618,9 @@
|
||||
}
|
||||
},
|
||||
"node-forge": {
|
||||
"version": "0.9.2",
|
||||
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.9.2.tgz",
|
||||
"integrity": "sha512-naKSScof4Wn+aoHU6HBsifh92Zeicm1GDQKd1vp3Y/kOi8ub0DozCa9KpvYNCXslFHYRmLNiqRopGdTGwNLpNw=="
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz",
|
||||
"integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA=="
|
||||
},
|
||||
"node-gyp-build": {
|
||||
"version": "4.4.0",
|
||||
@@ -44145,6 +44171,11 @@
|
||||
"integrity": "sha512-pvJNU3NwQk6bCG2gOWcQpZ4IxhtELB0K9gzmtixfsaTFbW1UXXHkJNjk1kHazcbH5hrD7QbUkR63fsAVh8X4VQ==",
|
||||
"requires": {}
|
||||
},
|
||||
"react-native-rsa-native": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/react-native-rsa-native/-/react-native-rsa-native-2.0.5.tgz",
|
||||
"integrity": "sha512-gwwvFSwGW5WKrpDyBQ/eTf1UrVABeAvMcT4YWemzPSUo6aHZs1kbBm2rXmwN5okhUzJsry5zjjz/qdx5GXRugQ=="
|
||||
},
|
||||
"react-native-safe-area-context": {
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-3.3.2.tgz",
|
||||
@@ -44160,6 +44191,11 @@
|
||||
"warn-once": "^0.1.0"
|
||||
}
|
||||
},
|
||||
"react-native-secure-key-store": {
|
||||
"version": "2.0.10",
|
||||
"resolved": "https://registry.npmjs.org/react-native-secure-key-store/-/react-native-secure-key-store-2.0.10.tgz",
|
||||
"integrity": "sha512-K7aVlIGxyklnjhCidVexVgZF3LsgUD9GIxMy2NB/xkQsS9E2SJWkD/fJ56e25L2I6a9Mp1zuJrKnCtfBs1CvAw=="
|
||||
},
|
||||
"react-native-securerandom": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/react-native-securerandom/-/react-native-securerandom-1.0.1.tgz",
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
"expo-updates": "~0.11.6",
|
||||
"i18next": "^21.6.16",
|
||||
"mosip-inji-face-sdk": "^0.1.7",
|
||||
"node-forge": "^1.3.1",
|
||||
"react": "17.0.1",
|
||||
"react-i18next": "^11.16.6",
|
||||
"react-native": "0.64.4",
|
||||
@@ -62,8 +63,10 @@
|
||||
"react-native-popable": "^0.4.3",
|
||||
"react-native-qrcode-svg": "^6.1.1",
|
||||
"react-native-restart": "^0.0.24",
|
||||
"react-native-rsa-native": "^2.0.5",
|
||||
"react-native-safe-area-context": "3.3.2",
|
||||
"react-native-screens": "~3.10.1",
|
||||
"react-native-secure-key-store": "^2.0.10",
|
||||
"react-native-securerandom": "^1.0.0",
|
||||
"react-native-simple-markdown": "^1.1.0",
|
||||
"react-native-svg": "12.1.1",
|
||||
|
||||
@@ -12,7 +12,7 @@ import i18n from '../i18n';
|
||||
import { Platform } from 'react-native';
|
||||
import { isBLEEnabled } from '../lib/smartshare';
|
||||
|
||||
var home: TabScreen = {
|
||||
const home: TabScreen = {
|
||||
name: 'Home',
|
||||
component: HomeScreen,
|
||||
icon: 'home',
|
||||
@@ -20,7 +20,7 @@ var home: TabScreen = {
|
||||
title: i18n.t('MainLayout:home'),
|
||||
},
|
||||
};
|
||||
var scan: TabScreen = {
|
||||
const scan: TabScreen = {
|
||||
name: 'Scan',
|
||||
component: ScanLayout,
|
||||
icon: 'qr-code-scanner',
|
||||
@@ -29,7 +29,7 @@ var scan: TabScreen = {
|
||||
headerShown: false,
|
||||
},
|
||||
};
|
||||
var request: TabScreen = {
|
||||
const request: TabScreen = {
|
||||
name: 'Request',
|
||||
component: RequestLayout,
|
||||
icon: 'file-download',
|
||||
@@ -38,7 +38,7 @@ var request: TabScreen = {
|
||||
headerShown: false,
|
||||
},
|
||||
};
|
||||
var profile: TabScreen = {
|
||||
const profile: TabScreen = {
|
||||
name: 'Profile',
|
||||
component: ProfileScreen,
|
||||
icon: 'person',
|
||||
|
||||
@@ -11,18 +11,18 @@ export interface Typegen0 {
|
||||
'invokeSrcNameMap': {};
|
||||
'missingImplementations': {
|
||||
actions: never;
|
||||
services: never;
|
||||
guards: never;
|
||||
delays: never;
|
||||
guards: never;
|
||||
services: never;
|
||||
};
|
||||
'eventsCausingActions': {
|
||||
resetSelectedVc: 'DISMISS_MODAL' | 'xstate.init';
|
||||
setSelectedVc: 'VIEW_VC';
|
||||
spawnTabActors: 'xstate.init';
|
||||
};
|
||||
'eventsCausingServices': {};
|
||||
'eventsCausingGuards': {};
|
||||
'eventsCausingDelays': {};
|
||||
'eventsCausingGuards': {};
|
||||
'eventsCausingServices': {};
|
||||
'matchesStates':
|
||||
| 'modals'
|
||||
| 'modals.none'
|
||||
|
||||
@@ -32,9 +32,9 @@ export interface Typegen0 {
|
||||
};
|
||||
'missingImplementations': {
|
||||
actions: never;
|
||||
services: never;
|
||||
guards: never;
|
||||
delays: never;
|
||||
guards: never;
|
||||
services: never;
|
||||
};
|
||||
'eventsCausingActions': {
|
||||
clearId: 'SELECT_ID_TYPE';
|
||||
@@ -69,16 +69,16 @@ export interface Typegen0 {
|
||||
| 'error.platform.AddVcModal.requestingCredential:invocation[0]'
|
||||
| 'xstate.init';
|
||||
};
|
||||
'eventsCausingServices': {
|
||||
requestCredential: 'INPUT_OTP';
|
||||
requestOtp: 'VALIDATE_INPUT';
|
||||
};
|
||||
'eventsCausingDelays': {};
|
||||
'eventsCausingGuards': {
|
||||
isEmptyId: 'VALIDATE_INPUT';
|
||||
isIdInvalid: 'error.platform.AddVcModal.requestingCredential:invocation[0]';
|
||||
isWrongIdFormat: 'VALIDATE_INPUT';
|
||||
};
|
||||
'eventsCausingDelays': {};
|
||||
'eventsCausingServices': {
|
||||
requestCredential: 'INPUT_OTP';
|
||||
requestOtp: 'VALIDATE_INPUT';
|
||||
};
|
||||
'matchesStates':
|
||||
| 'acceptingIdInput'
|
||||
| 'acceptingIdInput.focusing'
|
||||
|
||||
69
screens/Home/MyVcs/BindVcController.ts
Normal file
69
screens/Home/MyVcs/BindVcController.ts
Normal file
@@ -0,0 +1,69 @@
|
||||
import { useSelector } from '@xstate/react';
|
||||
import { useContext } from 'react';
|
||||
import { ActorRefFrom } from 'xstate';
|
||||
import {
|
||||
selectIsRefreshingMyVcs,
|
||||
selectMyVcs,
|
||||
VcEvents,
|
||||
} from '../../../machines/vc';
|
||||
import { GlobalContext } from '../../../shared/GlobalContext';
|
||||
import NetInfo from '@react-native-community/netinfo';
|
||||
import { selectVcLabel } from '../../../machines/settings';
|
||||
import {
|
||||
selectAcceptingBindingOtp,
|
||||
selectIsRequestBindingOtp,
|
||||
selectOtpError,
|
||||
selectShowBindingStatus,
|
||||
selectWalletBindingError,
|
||||
selectWalletBindingId,
|
||||
VcItemEvents,
|
||||
vcItemMachine,
|
||||
} from '../../../machines/vcItem';
|
||||
import { ModalProps } from '../../../components/ui/Modal';
|
||||
|
||||
export function useBindVcStatus(props: BindVcProps) {
|
||||
const { appService } = useContext(GlobalContext);
|
||||
const settingsService = appService.children.get('settings');
|
||||
const vcService = appService.children.get('vc');
|
||||
|
||||
const netInfoFetch = (otp: string) => {
|
||||
NetInfo.fetch().then((state) => {
|
||||
if (state.isConnected) {
|
||||
vcService.send(VcItemEvents.INPUT_OTP(otp));
|
||||
} else {
|
||||
vcService.send(VcItemEvents.DISMISS());
|
||||
showToast('Request network failed');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
vcKeys: useSelector(vcService, selectMyVcs),
|
||||
vcLabel: useSelector(settingsService, selectVcLabel),
|
||||
|
||||
isRefreshingVcs: useSelector(vcService, selectIsRefreshingMyVcs),
|
||||
isBindingOtp: useSelector(vcService, selectIsRequestBindingOtp),
|
||||
walletAddress: useSelector(vcService, selectWalletBindingId),
|
||||
isAcceptingBindingOtp: useSelector(vcService, selectAcceptingBindingOtp),
|
||||
showBindingStatus: useSelector(vcService, selectShowBindingStatus),
|
||||
walletBindingError: useSelector(vcService, selectWalletBindingError),
|
||||
|
||||
inputOtp: (otp: string) => {
|
||||
netInfoFetch(otp);
|
||||
},
|
||||
otpError: useSelector(vcService, selectOtpError),
|
||||
BINDING_DONE: () => vcService.send(VcItemEvents.BINDING_DONE()),
|
||||
INPUT_OTP: (otp: string) => vcService.send(VcItemEvents.INPUT_OTP(otp)),
|
||||
DISMISS: () => vcService.send(VcItemEvents.DISMISS()),
|
||||
|
||||
REFRESH: () => vcService.send(VcEvents.REFRESH_MY_VCS()),
|
||||
};
|
||||
}
|
||||
function showToast(arg0: string) {
|
||||
throw new Error('Function not implemented.');
|
||||
}
|
||||
|
||||
export interface BindVcProps extends ModalProps {
|
||||
bindingError: string;
|
||||
onDone: () => void;
|
||||
}
|
||||
55
screens/Home/MyVcs/BindVcStatus.tsx
Normal file
55
screens/Home/MyVcs/BindVcStatus.tsx
Normal file
@@ -0,0 +1,55 @@
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Column, Text, Button, Row } from '../../../components/ui';
|
||||
import { Theme } from '../../../components/ui/styleUtils';
|
||||
import { useBindVcStatus, BindVcProps } from './BindVcController';
|
||||
import { Image } from 'react-native';
|
||||
import { Modal } from '../../../components/ui/Modal';
|
||||
import { Icon } from 'react-native-elements';
|
||||
|
||||
export const BindStatus: React.FC<BindVcProps> = (props) => {
|
||||
const controller = useBindVcStatus(props);
|
||||
const { t, i18n } = useTranslation('VcDetails');
|
||||
var message: string = controller.walletBindingError;
|
||||
|
||||
return (
|
||||
<Modal
|
||||
isVisible={props.isVisible}
|
||||
onDismiss={props.onDismiss}
|
||||
headerElevation={2}
|
||||
headerTitle={t('status')}
|
||||
headerRight={<Icon name={''} />}>
|
||||
<Column fill align="space-around" crossAlign="center" padding={'10'}>
|
||||
<Column crossAlign="center">
|
||||
{!controller.walletBindingError ? (
|
||||
<Image source={Theme.SuccessLogo} resizeMethod="auto" />
|
||||
) : (
|
||||
<Row align="center" crossAlign="center" margin={'0 80 0 0'}>
|
||||
<Image source={Theme.WarningLogo} resizeMethod="auto" />
|
||||
<Text
|
||||
margin={'0 0 0 -80'}
|
||||
color={Theme.Colors.whiteText}
|
||||
weight="bold">
|
||||
!
|
||||
</Text>
|
||||
</Row>
|
||||
)}
|
||||
{controller.walletBindingError ? (
|
||||
<Text
|
||||
align="center"
|
||||
color={Theme.Colors.errorMessage}
|
||||
margin="16 0 0 0">
|
||||
{{ message }}
|
||||
</Text>
|
||||
) : (
|
||||
<Text align="center" margin="16 0 0 0">
|
||||
{t('verificationEnabledSuccess')}
|
||||
</Text>
|
||||
)}
|
||||
</Column>
|
||||
|
||||
<Button title={t('ok')} onPress={props.onDone} type="radius" />
|
||||
</Column>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
62
screens/Home/MyVcs/BindingVcWarningOverlay.tsx
Normal file
62
screens/Home/MyVcs/BindingVcWarningOverlay.tsx
Normal file
@@ -0,0 +1,62 @@
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Dimensions, Image } from 'react-native';
|
||||
import { Overlay } from 'react-native-elements';
|
||||
import { Button, Column, Text, Row } from '../../../components/ui';
|
||||
import { Theme } from '../../../components/ui/styleUtils';
|
||||
|
||||
export const BindingVcWarningOverlay: React.FC<QrLoginWarningProps> = (
|
||||
props
|
||||
) => {
|
||||
const { t } = useTranslation('VcDetails');
|
||||
|
||||
return (
|
||||
<Overlay
|
||||
isVisible={props.isVisible}
|
||||
overlayStyle={Theme.BindingVcWarningOverlay.overlay}>
|
||||
<Column
|
||||
align="space-between"
|
||||
crossAlign="center"
|
||||
padding={'10'}
|
||||
width={Dimensions.get('screen').width * 0.8}>
|
||||
<Row align="center" crossAlign="center" margin={'0 80 0 0'}>
|
||||
<Image source={Theme.WarningLogo} resizeMethod="auto" />
|
||||
<Text
|
||||
margin={'0 0 0 -80'}
|
||||
color={Theme.Colors.whiteText}
|
||||
weight="bold">
|
||||
!
|
||||
</Text>
|
||||
</Row>
|
||||
|
||||
<Text size="regular" weight="bold">
|
||||
{t('Alert')}
|
||||
</Text>
|
||||
|
||||
<Text align="center" size="smaller">
|
||||
{t('BindingWarning')}
|
||||
</Text>
|
||||
|
||||
<Button
|
||||
margin={'10 0 0 0'}
|
||||
type="radius"
|
||||
title={t('yes_confirm')}
|
||||
onPress={props.onConfirm}
|
||||
/>
|
||||
|
||||
<Button
|
||||
margin={'10 0 0 0'}
|
||||
type="clear"
|
||||
title={t('no')}
|
||||
onPress={props.onCancel}
|
||||
/>
|
||||
</Column>
|
||||
</Overlay>
|
||||
);
|
||||
};
|
||||
|
||||
interface QrLoginWarningProps {
|
||||
isVisible: boolean;
|
||||
onConfirm: () => void;
|
||||
onCancel: () => void;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"header": "To retrieve your UIN or VID, enter your Application {{vcLabel}} number",
|
||||
"header": "To retrieve your UIN or VID, enter your application {{vcLabel}} number",
|
||||
"getUIN": "Get UIN/VID",
|
||||
"applicationId": "Application {{vcLabel}} number",
|
||||
"requestingOTP": "Requesting OTP...",
|
||||
|
||||
@@ -6,7 +6,12 @@ import { Modal } from '../../../components/ui/Modal';
|
||||
import { Theme } from '../../../components/ui/styleUtils';
|
||||
import { IdInputModalProps, useIdInputModal } from './IdInputModalController';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { KeyboardAvoidingView, Platform, TextInput } from 'react-native';
|
||||
import {
|
||||
I18nManager,
|
||||
KeyboardAvoidingView,
|
||||
Platform,
|
||||
TextInput,
|
||||
} from 'react-native';
|
||||
import { TouchableOpacity } from 'react-native';
|
||||
import { individualId } from '../../../shared/constants';
|
||||
import { GET_INDIVIDUAL_ID } from '../../../shared/constants';
|
||||
@@ -71,6 +76,9 @@ export const IdInputModal: React.FC<IdInputModalProps> = (props) => {
|
||||
? Theme.Colors.errorMessage
|
||||
: Theme.Colors.textValue,
|
||||
}}
|
||||
inputStyle={{
|
||||
textAlign: I18nManager.isRTL ? 'right' : 'left',
|
||||
}}
|
||||
value={controller.id}
|
||||
keyboardType="number-pad"
|
||||
rightIcon={
|
||||
|
||||
@@ -1,27 +1,29 @@
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { View } from 'react-native';
|
||||
import { Icon } from 'react-native-elements';
|
||||
import { PinInput } from '../../../components/PinInput';
|
||||
import { Column, Text } from '../../../components/ui';
|
||||
import { ModalProps } from '../../../components/ui/Modal';
|
||||
import { ModalProps, Modal } from '../../../components/ui/Modal';
|
||||
import { Theme } from '../../../components/ui/styleUtils';
|
||||
import { Image } from 'react-native';
|
||||
import { Icon } from 'react-native-elements';
|
||||
|
||||
export const OtpVerification: React.FC<OtpVerificationModalProps> = (props) => {
|
||||
const { t } = useTranslation('OtpVerificationModal');
|
||||
|
||||
return (
|
||||
<View style={Theme.OtpVerificationStyles.viewContainer}>
|
||||
<Modal
|
||||
isVisible={props.isVisible}
|
||||
onDismiss={props.onDismiss}
|
||||
headerElevation={2}
|
||||
headerTitle={t('header')}
|
||||
headerRight={<Icon name={''} />}>
|
||||
<Column
|
||||
fill
|
||||
padding="32"
|
||||
backgroundColor={Theme.Colors.whiteBackgroundColor}>
|
||||
<View style={Theme.OtpVerificationStyles.close}>
|
||||
<Icon name="close" onPress={() => props.onDismiss()} />
|
||||
</View>
|
||||
<Icon name="lock" color={Theme.Colors.Icon} size={60} />
|
||||
<Column fill align="space-between">
|
||||
backgroundColor={Theme.Colors.lightGreyBackgroundColor}>
|
||||
<Column fill align="space-between" crossAlign="center">
|
||||
<Text align="center">{t('enterOtp')}</Text>
|
||||
<Image source={Theme.OtpLogo} resizeMethod="auto" />
|
||||
<Text
|
||||
align="center"
|
||||
color={Theme.Colors.errorMessage}
|
||||
@@ -32,7 +34,7 @@ export const OtpVerification: React.FC<OtpVerificationModalProps> = (props) => {
|
||||
</Column>
|
||||
<Column fill></Column>
|
||||
</Column>
|
||||
</View>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import { DropdownIcon } from '../../components/DropdownIcon';
|
||||
import { TextEditOverlay } from '../../components/TextEditOverlay';
|
||||
import { Column } from '../../components/ui';
|
||||
import { Column, Text } from '../../components/ui';
|
||||
import { Modal } from '../../components/ui/Modal';
|
||||
import { MessageOverlay } from '../../components/MessageOverlay';
|
||||
import { ToastItem } from '../../components/ui/ToastItem';
|
||||
@@ -10,8 +10,9 @@ import { OIDcAuthenticationModal } from '../../components/OIDcAuth';
|
||||
import { useViewVcModal, ViewVcModalProps } from './ViewVcModalController';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { VcDetails } from '../../components/VcDetails';
|
||||
|
||||
import { OtpVerification } from './MyVcs/OtpVerification';
|
||||
import { BindStatus } from './MyVcs/BindVcStatus';
|
||||
import { BindingVcWarningOverlay } from './MyVcs/BindingVcWarningOverlay';
|
||||
|
||||
export const ViewVcModal: React.FC<ViewVcModalProps> = (props) => {
|
||||
const { t } = useTranslation('ViewVcModal');
|
||||
@@ -35,7 +36,11 @@ export const ViewVcModal: React.FC<ViewVcModalProps> = (props) => {
|
||||
<Modal
|
||||
isVisible={props.isVisible}
|
||||
onDismiss={props.onDismiss}
|
||||
headerTitle={controller.vc.id}
|
||||
headerTitle={
|
||||
controller.vc.verifiableCredential.credentialSubject.UIN
|
||||
? controller.vc.verifiableCredential.credentialSubject.UIN
|
||||
: controller.vc.verifiableCredential.credentialSubject.VID
|
||||
}
|
||||
headerElevation={2}
|
||||
headerRight={
|
||||
<DropdownIcon
|
||||
@@ -46,7 +51,17 @@ export const ViewVcModal: React.FC<ViewVcModalProps> = (props) => {
|
||||
}>
|
||||
<Column scroll>
|
||||
<Column fill>
|
||||
<VcDetails vc={controller.vc} />
|
||||
<VcDetails
|
||||
vc={controller.vc}
|
||||
onBinding={controller.addtoWallet}
|
||||
isBindingPending={controller.isWalletBindingPending}
|
||||
/>
|
||||
|
||||
{controller.walletBindingError !== '' && (
|
||||
<Text style={{ color: 'red', fontSize: 20 }}>
|
||||
Error Occured : {controller.walletBindingError}
|
||||
</Text>
|
||||
)}
|
||||
</Column>
|
||||
</Column>
|
||||
{controller.isEditingTag && (
|
||||
@@ -79,9 +94,41 @@ export const ViewVcModal: React.FC<ViewVcModalProps> = (props) => {
|
||||
/>
|
||||
)}
|
||||
|
||||
{controller.isAcceptingBindingOtp && (
|
||||
<OtpVerification
|
||||
isVisible={controller.isAcceptingBindingOtp}
|
||||
onDismiss={controller.DISMISS}
|
||||
onInputDone={controller.inputOtp}
|
||||
error={controller.otpError}
|
||||
/>
|
||||
)}
|
||||
|
||||
{controller.showBindingStatus && (
|
||||
<BindStatus
|
||||
isVisible={controller.showBindingStatus}
|
||||
bindingError={controller.walletBindingError}
|
||||
onDismiss={controller.BINDING_DONE}
|
||||
onDone={controller.BINDING_DONE}
|
||||
/>
|
||||
)}
|
||||
|
||||
<BindingVcWarningOverlay
|
||||
isVisible={controller.isBindingWarning}
|
||||
onConfirm={controller.CONFIRM}
|
||||
onCancel={controller.CANCEL}
|
||||
/>
|
||||
|
||||
<MessageOverlay
|
||||
isVisible={controller.isRequestingOtp}
|
||||
title={t('requestingOtp')}
|
||||
isVisible={controller.isBindingError}
|
||||
title={controller.walletBindingError}
|
||||
onCancel={() => {
|
||||
controller.CANCEL();
|
||||
}}
|
||||
/>
|
||||
|
||||
<MessageOverlay
|
||||
isVisible={controller.isWalletBindingInProgress}
|
||||
title={t('inProgress')}
|
||||
progress
|
||||
/>
|
||||
|
||||
|
||||
@@ -11,12 +11,20 @@ import {
|
||||
selectIsAcceptingRevokeInput,
|
||||
selectIsEditingTag,
|
||||
selectIsLockingVc,
|
||||
selectIsRequestingOtp,
|
||||
selectIsRevokingVc,
|
||||
selectIsLoggingRevoke,
|
||||
selectVc,
|
||||
VcItemEvents,
|
||||
vcItemMachine,
|
||||
selectWalletBindingId,
|
||||
selectWalletBindingError,
|
||||
selectIsRequestBindingOtp,
|
||||
selectAcceptingBindingOtp,
|
||||
selectShowBindingStatus,
|
||||
selectEmptyWalletBindingId,
|
||||
isWalletBindingInProgress,
|
||||
selectShowWalletBindingError,
|
||||
isShowingBindingWarning,
|
||||
} from '../../machines/vcItem';
|
||||
import { selectPasscode } from '../../machines/auth';
|
||||
import { biometricsMachine, selectIsSuccess } from '../../machines/biometrics';
|
||||
@@ -123,8 +131,21 @@ export function useViewVcModal({
|
||||
vcItemActor,
|
||||
selectIsAcceptingRevokeInput
|
||||
),
|
||||
isRequestingOtp: useSelector(vcItemActor, selectIsRequestingOtp),
|
||||
storedPasscode: useSelector(authService, selectPasscode),
|
||||
isBindingOtp: useSelector(vcItemActor, selectIsRequestBindingOtp),
|
||||
isAcceptingBindingOtp: useSelector(vcItemActor, selectAcceptingBindingOtp),
|
||||
showBindingStatus: useSelector(vcItemActor, selectShowBindingStatus),
|
||||
walletBindingError: useSelector(vcItemActor, selectWalletBindingError),
|
||||
isWalletBindingPending: useSelector(
|
||||
vcItemActor,
|
||||
selectEmptyWalletBindingId
|
||||
),
|
||||
isWalletBindingInProgress: useSelector(
|
||||
vcItemActor,
|
||||
isWalletBindingInProgress
|
||||
),
|
||||
isBindingError: useSelector(vcItemActor, selectShowWalletBindingError),
|
||||
isBindingWarning: useSelector(vcItemActor, isShowingBindingWarning),
|
||||
|
||||
CONFIRM_REVOKE_VC: () => {
|
||||
setRevoking(true);
|
||||
@@ -136,6 +157,9 @@ export function useViewVcModal({
|
||||
setReAuthenticating,
|
||||
setRevoking,
|
||||
onError,
|
||||
addtoWallet: () => {
|
||||
vcItemActor.send(VcItemEvents.ADD_WALLET_BINDING_ID());
|
||||
},
|
||||
lockVc: () => {
|
||||
vcItemActor.send(VcItemEvents.LOCK_VC());
|
||||
},
|
||||
@@ -145,12 +169,16 @@ export function useViewVcModal({
|
||||
revokeVc: (otp: string) => {
|
||||
netInfoFetch(otp);
|
||||
},
|
||||
ADD_WALLET: () => vcItemActor.send(VcItemEvents.ADD_WALLET_BINDING_ID()),
|
||||
onSuccess,
|
||||
EDIT_TAG: () => vcItemActor.send(VcItemEvents.EDIT_TAG()),
|
||||
SAVE_TAG: (tag: string) => vcItemActor.send(VcItemEvents.SAVE_TAG(tag)),
|
||||
DISMISS: () => vcItemActor.send(VcItemEvents.DISMISS()),
|
||||
BINDING_DONE: () => vcItemActor.send(VcItemEvents.BINDING_DONE()),
|
||||
LOCK_VC: () => vcItemActor.send(VcItemEvents.LOCK_VC()),
|
||||
INPUT_OTP: (otp: string) => vcItemActor.send(VcItemEvents.INPUT_OTP(otp)),
|
||||
CANCEL: () => vcItemActor.send(VcItemEvents.CANCEL()),
|
||||
CONFIRM: () => vcItemActor.send(VcItemEvents.CONFIRM()),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import { useTranslation } from 'react-i18next';
|
||||
import { Image, SafeAreaView, View } from 'react-native';
|
||||
import { Divider, Icon, ListItem, Overlay } from 'react-native-elements';
|
||||
|
||||
import { Button, Text, Row } from '../../components/ui';
|
||||
import { Button, Text, Row, Column } from '../../components/ui';
|
||||
import { Theme } from '../../components/ui/styleUtils';
|
||||
import creditsContent from '../../Credits.md';
|
||||
|
||||
@@ -19,6 +19,11 @@ export const Credits: React.FC<CreditsProps> = (props) => {
|
||||
const markdownStyles = {
|
||||
heading1: {
|
||||
fontSize: 24,
|
||||
textAlign: 'left',
|
||||
},
|
||||
heading2: {
|
||||
fontSize: 24,
|
||||
textAlign: 'left',
|
||||
},
|
||||
image: {
|
||||
maxWidth: 150,
|
||||
@@ -42,6 +47,13 @@ export const Credits: React.FC<CreditsProps> = (props) => {
|
||||
|
||||
return (
|
||||
<ListItem bottomDivider onPress={() => setIsViewing(true)}>
|
||||
<Icon
|
||||
name="filetext1"
|
||||
type="antdesign"
|
||||
size={20}
|
||||
style={Theme.Styles.profileIconBg}
|
||||
color={Theme.Colors.Icon}
|
||||
/>
|
||||
<ListItem.Content>
|
||||
<ListItem.Title>
|
||||
<Text color={props.color}>{props.label}</Text>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import { View } from 'react-native';
|
||||
import { getVersion } from 'react-native-device-info';
|
||||
import { ListItem, Switch } from 'react-native-elements';
|
||||
import { Icon, ListItem, Switch } from 'react-native-elements';
|
||||
import { Column, Text } from '../../components/ui';
|
||||
import { Theme } from '../../components/ui/styleUtils';
|
||||
import { MainRouteProps } from '../../routes/main';
|
||||
@@ -14,6 +14,7 @@ import { useTranslation } from 'react-i18next';
|
||||
import { LanguageSelector } from '../../components/LanguageSelector';
|
||||
import i18next, { SUPPORTED_LANGUAGES } from '../../i18n';
|
||||
import { isBLEEnabled } from '../../lib/smartshare';
|
||||
import { ScrollView } from 'react-native-gesture-handler';
|
||||
|
||||
const LanguageSetting: React.FC = () => {
|
||||
const { t } = useTranslation('ProfileScreen');
|
||||
@@ -40,92 +41,118 @@ export const ProfileScreen: React.FC<MainRouteProps> = (props) => {
|
||||
const { t } = useTranslation('ProfileScreen');
|
||||
const controller = useProfileScreen(props);
|
||||
return (
|
||||
<Column
|
||||
fill
|
||||
padding="24 0"
|
||||
backgroundColor={Theme.Colors.lightGreyBackgroundColor}>
|
||||
<MessageOverlay
|
||||
isVisible={controller.alertMsg != ''}
|
||||
onBackdropPress={controller.hideAlert}
|
||||
title={controller.alertMsg}
|
||||
/>
|
||||
<EditableListItem
|
||||
label={t('name')}
|
||||
value={controller.name}
|
||||
onEdit={controller.UPDATE_NAME}
|
||||
/>
|
||||
<EditableListItem
|
||||
label={t('vcLabel')}
|
||||
value={controller.vcLabel.singular}
|
||||
onEdit={controller.UPDATE_VC_LABEL}
|
||||
/>
|
||||
<LanguageSetting />
|
||||
<Revoke label={t('revokeLabel')} />
|
||||
<ListItem bottomDivider disabled={!controller.canUseBiometrics}>
|
||||
<ListItem.Content>
|
||||
<ListItem.Title>
|
||||
<Text color={Theme.Colors.profileLabel}>{t('bioUnlock')}</Text>
|
||||
</ListItem.Title>
|
||||
</ListItem.Content>
|
||||
<Switch
|
||||
value={controller.isBiometricUnlockEnabled}
|
||||
onValueChange={controller.useBiometrics}
|
||||
color={Theme.Colors.profileValue}
|
||||
<ScrollView>
|
||||
<Column
|
||||
fill
|
||||
padding="24 0"
|
||||
backgroundColor={Theme.Colors.lightGreyBackgroundColor}>
|
||||
<MessageOverlay
|
||||
isVisible={controller.alertMsg != ''}
|
||||
onBackdropPress={controller.hideAlert}
|
||||
title={controller.alertMsg}
|
||||
/>
|
||||
</ListItem>
|
||||
<ListItem bottomDivider disabled>
|
||||
<ListItem.Content>
|
||||
<ListItem.Title>
|
||||
<Text color={Theme.Colors.profileAuthFactorUnlock}>
|
||||
{t('authFactorUnlock')}
|
||||
<EditableListItem
|
||||
label={t('name')}
|
||||
value={controller.name}
|
||||
onEdit={controller.UPDATE_NAME}
|
||||
Icon="user"
|
||||
/>
|
||||
<EditableListItem
|
||||
label={t('vcLabel')}
|
||||
value={controller.vcLabel.singular}
|
||||
onEdit={controller.UPDATE_VC_LABEL}
|
||||
Icon="star"
|
||||
/>
|
||||
<LanguageSetting />
|
||||
<Revoke label={t('revokeLabel')} Icon="rotate-left" />
|
||||
|
||||
<ListItem bottomDivider disabled={!controller.canUseBiometrics}>
|
||||
<Icon
|
||||
name="fingerprint"
|
||||
type="fontawesome"
|
||||
size={25}
|
||||
style={Theme.Styles.profileIconBg}
|
||||
color={Theme.Colors.Icon}
|
||||
/>
|
||||
<ListItem.Content>
|
||||
<ListItem.Title>
|
||||
<Text color={Theme.Colors.profileLabel}>{t('bioUnlock')}</Text>
|
||||
</ListItem.Title>
|
||||
</ListItem.Content>
|
||||
<Switch
|
||||
value={controller.isBiometricUnlockEnabled}
|
||||
onValueChange={controller.useBiometrics}
|
||||
color={Theme.Colors.profileValue}
|
||||
/>
|
||||
</ListItem>
|
||||
<ListItem bottomDivider disabled>
|
||||
<Icon
|
||||
name="unlock"
|
||||
size={20}
|
||||
type="antdesign"
|
||||
style={Theme.Styles.profileIconBg}
|
||||
color={Theme.Colors.Icon}
|
||||
/>
|
||||
<ListItem.Content>
|
||||
<ListItem.Title>
|
||||
<Text color={Theme.Colors.profileAuthFactorUnlock}>
|
||||
{t('authFactorUnlock')}
|
||||
</Text>
|
||||
</ListItem.Title>
|
||||
</ListItem.Content>
|
||||
</ListItem>
|
||||
<ListItem bottomDivider>
|
||||
<ListItem.Content>
|
||||
<ListItem.Title>
|
||||
<Text color={Theme.Colors.profileLabel}>
|
||||
{isBLEEnabled ? t('useBle') : t('useGoogleNearby')}
|
||||
</Text>
|
||||
</ListItem.Title>
|
||||
</ListItem.Content>
|
||||
</ListItem>
|
||||
<Credits label={t('credits')} color={Theme.Colors.profileLabel} />
|
||||
<ListItem bottomDivider onPress={controller.LOGOUT}>
|
||||
<Icon
|
||||
name="logout"
|
||||
type="fontawesome"
|
||||
size={20}
|
||||
style={Theme.Styles.profileIconBg}
|
||||
color={Theme.Colors.Icon}
|
||||
/>
|
||||
<ListItem.Content>
|
||||
<ListItem.Title>
|
||||
<Text color={Theme.Colors.profileLabel}>{t('logout')}</Text>
|
||||
</ListItem.Title>
|
||||
</ListItem.Content>
|
||||
</ListItem>
|
||||
<Text
|
||||
weight="semibold"
|
||||
margin="32 0 0 0"
|
||||
align="center"
|
||||
size="smaller"
|
||||
color={Theme.Colors.profileVersion}>
|
||||
{t('version')}: {getVersion()}
|
||||
</Text>
|
||||
{controller.backendInfo.application.name !== '' ? (
|
||||
<View>
|
||||
<Text
|
||||
weight="semibold"
|
||||
align="center"
|
||||
size="smaller"
|
||||
color={Theme.Colors.profileValue}>
|
||||
{controller.backendInfo.application.name}:{' '}
|
||||
{controller.backendInfo.application.version}
|
||||
</Text>
|
||||
</ListItem.Title>
|
||||
</ListItem.Content>
|
||||
</ListItem>
|
||||
<ListItem bottomDivider>
|
||||
<ListItem.Content>
|
||||
<ListItem.Title>
|
||||
<Text color={Theme.Colors.profileLabel}>
|
||||
{isBLEEnabled ? t('useBle') : t('useGoogleNearby')}
|
||||
<Text
|
||||
weight="semibold"
|
||||
align="center"
|
||||
size="smaller"
|
||||
color={Theme.Colors.profileValue}>
|
||||
MOSIP: {controller.backendInfo.config['mosip.host']}
|
||||
</Text>
|
||||
</ListItem.Title>
|
||||
</ListItem.Content>
|
||||
</ListItem>
|
||||
<Credits label={t('credits')} color={Theme.Colors.profileLabel} />
|
||||
<ListItem bottomDivider onPress={controller.LOGOUT}>
|
||||
<ListItem.Content>
|
||||
<ListItem.Title>
|
||||
<Text color={Theme.Colors.profileLabel}>{t('logout')}</Text>
|
||||
</ListItem.Title>
|
||||
</ListItem.Content>
|
||||
</ListItem>
|
||||
<Text
|
||||
weight="semibold"
|
||||
margin="32 0 0 0"
|
||||
align="center"
|
||||
size="smaller"
|
||||
color={Theme.Colors.profileVersion}>
|
||||
{t('version')}: {getVersion()}
|
||||
</Text>
|
||||
{controller.backendInfo.application.name !== '' ? (
|
||||
<View>
|
||||
<Text
|
||||
weight="semibold"
|
||||
align="center"
|
||||
size="smaller"
|
||||
color={Theme.Colors.profileValue}>
|
||||
{controller.backendInfo.application.name}:{' '}
|
||||
{controller.backendInfo.application.version}
|
||||
</Text>
|
||||
<Text
|
||||
weight="semibold"
|
||||
align="center"
|
||||
size="smaller"
|
||||
color={Theme.Colors.profileValue}>
|
||||
MOSIP: {controller.backendInfo.config['mosip.host']}
|
||||
</Text>
|
||||
</View>
|
||||
) : null}
|
||||
</Column>
|
||||
</View>
|
||||
) : null}
|
||||
</Column>
|
||||
</ScrollView>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -15,6 +15,13 @@ export const Revoke: React.FC<RevokeScreenProps> = (props) => {
|
||||
|
||||
return (
|
||||
<ListItem bottomDivider onPress={() => controller.setAuthenticating(true)}>
|
||||
<Icon
|
||||
name={props.Icon}
|
||||
type="font-awesome"
|
||||
size={20}
|
||||
style={Theme.Styles.profileIconBg}
|
||||
color={Theme.Colors.Icon}
|
||||
/>
|
||||
<ListItem.Content>
|
||||
<ListItem.Title>
|
||||
<Text>{props.label}</Text>
|
||||
@@ -151,4 +158,5 @@ export const Revoke: React.FC<RevokeScreenProps> = (props) => {
|
||||
|
||||
interface RevokeScreenProps {
|
||||
label: string;
|
||||
Icon: string;
|
||||
}
|
||||
|
||||
91
screens/QrLogin/MyBindedVcs.tsx
Normal file
91
screens/QrLogin/MyBindedVcs.tsx
Normal file
@@ -0,0 +1,91 @@
|
||||
import React from 'react';
|
||||
import { Button, Column, Text, Centered } from '../../components/ui';
|
||||
import { Theme } from '../../components/ui/styleUtils';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { VcItem } from '../../components/VcItem';
|
||||
import { useQrLogin } from './QrLoginController';
|
||||
import { QrLoginRef } from '../../machines/QrLoginMachine';
|
||||
import { Icon } from 'react-native-elements';
|
||||
import { Modal } from '../../components/ui/Modal';
|
||||
|
||||
export const MyBindedVcs: React.FC<MyBindedVcsProps> = (props) => {
|
||||
const controller = useQrLogin(props);
|
||||
const { t } = useTranslation('QrScreen');
|
||||
|
||||
return (
|
||||
<Modal
|
||||
isVisible={controller.isShowingVcList}
|
||||
arrowLeft={<Icon name={''} />}
|
||||
headerTitle={t('selectId')}
|
||||
headerElevation={5}
|
||||
onDismiss={() => {
|
||||
controller.setQrLogin(false), controller.DISMISS();
|
||||
}}>
|
||||
<React.Fragment>
|
||||
<Column fill style={{ display: props.isVisible ? 'flex' : 'none' }}>
|
||||
<Column fill>
|
||||
{controller.vcKeys.length > 0 && (
|
||||
<React.Fragment>
|
||||
<Column
|
||||
fill
|
||||
backgroundColor={Theme.Colors.lightGreyBackgroundColor}>
|
||||
<Column padding="16 0" scroll>
|
||||
<Column pX={14}>
|
||||
{controller.vcKeys.length > 0 &&
|
||||
controller.vcKeys.map((vcKey, index) => (
|
||||
<VcItem
|
||||
key={vcKey}
|
||||
vcKey={vcKey}
|
||||
margin="0 2 8 2"
|
||||
onPress={controller.SELECT_VC_ITEM(index)}
|
||||
showOnlyBindedVc
|
||||
selectable
|
||||
selected={index === controller.selectedIndex}
|
||||
/>
|
||||
))}
|
||||
</Column>
|
||||
</Column>
|
||||
<Column
|
||||
style={{
|
||||
borderTopRightRadius: 27,
|
||||
borderTopLeftRadius: 27,
|
||||
}}
|
||||
padding="16 24"
|
||||
margin="2 0 0 0"
|
||||
elevation={2}>
|
||||
<Button
|
||||
title={t('verify')}
|
||||
margin="0 0 12 0"
|
||||
styles={Theme.ButtonStyles.radius}
|
||||
disabled={controller.selectedIndex == null}
|
||||
onPress={controller.VERIFY}
|
||||
/>
|
||||
</Column>
|
||||
</Column>
|
||||
</React.Fragment>
|
||||
)}
|
||||
{controller.vcKeys.length === 0 && (
|
||||
<React.Fragment>
|
||||
<Centered fill>
|
||||
<Text weight="semibold" margin="0 0 8 0">
|
||||
{t('noBindedVc', { vcLabel: controller.vcLabel.plural })}
|
||||
</Text>
|
||||
</Centered>
|
||||
<Button
|
||||
type="solid"
|
||||
title={t('back')}
|
||||
onPress={controller.DISMISS}
|
||||
/>
|
||||
</React.Fragment>
|
||||
)}
|
||||
</Column>
|
||||
</Column>
|
||||
</React.Fragment>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
interface MyBindedVcsProps {
|
||||
isVisible: boolean;
|
||||
service: QrLoginRef;
|
||||
}
|
||||
132
screens/QrLogin/QrConsent.tsx
Normal file
132
screens/QrLogin/QrConsent.tsx
Normal file
@@ -0,0 +1,132 @@
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Button, Column, Row, Text } from '../../components/ui';
|
||||
import { Theme } from '../../components/ui/styleUtils';
|
||||
import { useQrLogin } from './QrLoginController';
|
||||
import { Image } from 'react-native';
|
||||
import { Icon, ListItem, Switch } from 'react-native-elements';
|
||||
import { Modal } from '../../components/ui/Modal';
|
||||
import { QrLoginRef } from '../../machines/QrLoginMachine';
|
||||
import { ScrollView } from 'react-native';
|
||||
|
||||
export const QrConsent: React.FC<QrConsentProps> = (props) => {
|
||||
const { t } = useTranslation('QrScreen');
|
||||
const controller = useQrLogin(props);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
isVisible={controller.isRequestConsent}
|
||||
arrowLeft={<Icon name={''} />}
|
||||
headerTitle={t('consent')}
|
||||
headerElevation={5}
|
||||
onDismiss={props.onCancel}>
|
||||
<Column
|
||||
fill
|
||||
align="space-between"
|
||||
padding="0 24 0 24"
|
||||
style={{ display: props.isVisible ? 'flex' : 'none' }}
|
||||
backgroundColor={Theme.Colors.lightGreyBackgroundColor}>
|
||||
<ScrollView>
|
||||
<Column
|
||||
align="space-evenly"
|
||||
crossAlign="center"
|
||||
margin={'15 0 0 0'}
|
||||
style={Theme.Styles.consentPageTop}
|
||||
elevation={3}>
|
||||
{controller.linkTransactionResponse && (
|
||||
<Row margin={'0 0 0 38'} crossAlign="center">
|
||||
<Icon name="mobile" type="font-awesome" size={60} />
|
||||
<Text
|
||||
color={'grey'}
|
||||
weight="semibold"
|
||||
style={Theme.TextStyles.small}>
|
||||
{' '}
|
||||
-----------------------{' '}
|
||||
</Text>
|
||||
<Image
|
||||
source={
|
||||
controller.logoUrl ? { uri: controller.logoUrl } : null
|
||||
}
|
||||
style={{ width: 60, height: 60 }}
|
||||
/>
|
||||
</Row>
|
||||
)}
|
||||
<Text
|
||||
style={Theme.TextStyles.small}
|
||||
weight="bold"
|
||||
margin={'0 0 10 6'}>
|
||||
{controller.clientName} {t('access')}
|
||||
</Text>
|
||||
</Column>
|
||||
|
||||
<Column scroll padding="10 0 0 0">
|
||||
<ListItem bottomDivider>
|
||||
<ListItem.Content>
|
||||
<ListItem.Title>
|
||||
<Text
|
||||
color={Theme.Colors.profileLabel}
|
||||
style={Theme.TextStyles.base}>
|
||||
{t('Name and Picture')}
|
||||
</Text>
|
||||
</ListItem.Title>
|
||||
</ListItem.Content>
|
||||
<Switch value={true} color={Theme.Colors.ProfileIconBg} />
|
||||
</ListItem>
|
||||
{controller.claims.map((claim, index) => {
|
||||
if (claim == 'name' || claim == 'picture') {
|
||||
return null;
|
||||
} else {
|
||||
return (
|
||||
<ListItem key={index} bottomDivider>
|
||||
<ListItem.Content>
|
||||
<ListItem.Title>
|
||||
<Text color={Theme.Colors.profileLabel}>
|
||||
{t(claim[0].toUpperCase() + claim.slice(1))}
|
||||
</Text>
|
||||
</ListItem.Title>
|
||||
</ListItem.Content>
|
||||
|
||||
<Switch
|
||||
value={controller.isShare[claim]}
|
||||
onValueChange={() =>
|
||||
controller.SELECT_CONSENT(
|
||||
controller.isShare[claim],
|
||||
claim
|
||||
)
|
||||
}
|
||||
color={Theme.Colors.Icon}
|
||||
/>
|
||||
</ListItem>
|
||||
);
|
||||
}
|
||||
})}
|
||||
</Column>
|
||||
</ScrollView>
|
||||
<Column
|
||||
margin={'0 -20 0 -20'}
|
||||
style={Theme.Styles.bottomButtonsContainer}
|
||||
elevation={5}>
|
||||
<Button
|
||||
margin={'6 10 0 10'}
|
||||
styles={Theme.ButtonStyles.radius}
|
||||
title={'Confirm'}
|
||||
onPress={props.onConfirm}
|
||||
/>
|
||||
<Button
|
||||
margin={'10 10 0 10'}
|
||||
type="clear"
|
||||
title={'Cancel'}
|
||||
onPress={props.onCancel}
|
||||
/>
|
||||
</Column>
|
||||
</Column>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
interface QrConsentProps {
|
||||
isVisible: boolean;
|
||||
onConfirm: () => void;
|
||||
onCancel: () => void;
|
||||
service: QrLoginRef;
|
||||
}
|
||||
104
screens/QrLogin/QrLogin.tsx
Normal file
104
screens/QrLogin/QrLogin.tsx
Normal file
@@ -0,0 +1,104 @@
|
||||
import React from 'react';
|
||||
import { Button, Column, Row } from '../../components/ui';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useQrLogin } from './QrLoginController';
|
||||
import { Modal } from '../../components/ui/Modal';
|
||||
import { VerifyIdentityOverlay } from '../VerifyIdentityOverlay';
|
||||
import { MessageOverlay } from '../../components/MessageOverlay';
|
||||
import { MyBindedVcs } from './MyBindedVcs';
|
||||
import { QrLoginWarning } from './QrLoginWarning';
|
||||
import { QrLoginSuccess } from './QrLoginSuccessMessage';
|
||||
import { QrConsent } from './QrConsent';
|
||||
import { QrLoginRef } from '../../machines/QrLoginMachine';
|
||||
import { Icon } from 'react-native-elements';
|
||||
|
||||
export const QrLogin: React.FC<QrLoginProps> = (props) => {
|
||||
const controller = useQrLogin(props);
|
||||
const { t } = useTranslation('QrScreen');
|
||||
|
||||
return (
|
||||
<Modal
|
||||
isVisible={props.isVisible}
|
||||
onDismiss={controller.DISMISS}
|
||||
headerTitle={t('title')}
|
||||
headerRight={<Icon name={''} />}>
|
||||
<Column fill>
|
||||
<QrLoginWarning
|
||||
isVisible={controller.isShowWarning}
|
||||
onConfirm={controller.CONFIRM}
|
||||
onCancel={controller.DISMISS}
|
||||
service={props.service}
|
||||
/>
|
||||
|
||||
<MessageOverlay
|
||||
isVisible={
|
||||
controller.isWaitingForData ||
|
||||
controller.isLoadingMyVcs ||
|
||||
controller.isLinkTransaction ||
|
||||
controller.isSendingConsent
|
||||
}
|
||||
title={t('loading')}
|
||||
progress
|
||||
/>
|
||||
|
||||
<MessageOverlay
|
||||
isVisible={controller.isShowingError}
|
||||
title={controller.error}
|
||||
onCancel={controller.DISMISS}
|
||||
/>
|
||||
|
||||
<MyBindedVcs
|
||||
isVisible={controller.isShowingVcList}
|
||||
service={props.service}
|
||||
/>
|
||||
|
||||
<VerifyIdentityOverlay
|
||||
isVisible={controller.isVerifyingIdentity}
|
||||
vc={controller.selectedVc}
|
||||
onCancel={controller.CANCEL}
|
||||
onFaceValid={controller.FACE_VALID}
|
||||
onFaceInvalid={controller.FACE_INVALID}
|
||||
/>
|
||||
|
||||
<MessageOverlay
|
||||
isVisible={controller.isInvalidIdentity}
|
||||
title={t('VerifyIdentityOverlay:errors.invalidIdentity.title')}
|
||||
message={t('VerifyIdentityOverlay:errors.invalidIdentity.message')}
|
||||
onBackdropPress={controller.DISMISS}>
|
||||
<Row>
|
||||
<Button
|
||||
fill
|
||||
type="clear"
|
||||
title={t('common:cancel')}
|
||||
onPress={controller.DISMISS}
|
||||
margin={[0, 8, 0, 0]}
|
||||
/>
|
||||
<Button
|
||||
fill
|
||||
title={t('common:tryAgain')}
|
||||
onPress={controller.RETRY_VERIFICATION}
|
||||
/>
|
||||
</Row>
|
||||
</MessageOverlay>
|
||||
|
||||
<QrConsent
|
||||
isVisible={controller.isRequestConsent}
|
||||
onConfirm={controller.CONFIRM}
|
||||
onCancel={controller.CANCEL}
|
||||
service={props.service}
|
||||
/>
|
||||
|
||||
<QrLoginSuccess
|
||||
isVisible={controller.isVerifyingSuccesful}
|
||||
onPress={controller.CONFIRM}
|
||||
service={props.service}
|
||||
/>
|
||||
</Column>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export interface QrLoginProps {
|
||||
isVisible: boolean;
|
||||
service: QrLoginRef;
|
||||
}
|
||||
94
screens/QrLogin/QrLoginController.ts
Normal file
94
screens/QrLogin/QrLoginController.ts
Normal file
@@ -0,0 +1,94 @@
|
||||
import { useSelector } from '@xstate/react';
|
||||
import { useContext, useState } from 'react';
|
||||
import { ActorRefFrom } from 'xstate';
|
||||
import {
|
||||
QrLoginEvents,
|
||||
selectClientName,
|
||||
selectErrorMessage,
|
||||
selectIsInvalidIdentity,
|
||||
selectIsisVerifyingIdentity,
|
||||
selectIsLinkTransaction,
|
||||
selectIsloadMyVcs,
|
||||
selectIsRequestConsent,
|
||||
selectIsSendingConsent,
|
||||
selectIsSharing,
|
||||
selectIsShowError,
|
||||
selectIsShowingVcList,
|
||||
selectIsShowWarning,
|
||||
selectIsVerifyingSuccesful,
|
||||
selectIsWaitingForData,
|
||||
selectLinkTransactionResponse,
|
||||
selectLogoUrl,
|
||||
selectSelectedVc,
|
||||
selectVoluntaryClaims,
|
||||
} from '../../machines/QrLoginMachine';
|
||||
import { selectVcLabel } from '../../machines/settings';
|
||||
import { selectBindedVcs } from '../../machines/vc';
|
||||
import { vcItemMachine } from '../../machines/vcItem';
|
||||
import { GlobalContext } from '../../shared/GlobalContext';
|
||||
import { VC } from '../../types/vc';
|
||||
import { QrLoginProps } from './QrLogin';
|
||||
|
||||
export function useQrLogin({ service }: QrLoginProps) {
|
||||
const { appService } = useContext(GlobalContext);
|
||||
const settingsService = appService.children.get('settings');
|
||||
|
||||
const vcService = appService.children.get('vc');
|
||||
const [selectedIndex, setSelectedIndex] = useState<number>(null);
|
||||
const SELECT_VC = (vc: VC) => service.send(QrLoginEvents.SELECT_VC(vc));
|
||||
|
||||
const SELECT_CONSENT = (value: boolean, claim: string) => {
|
||||
service.send(QrLoginEvents.TOGGLE_CONSENT_CLAIM(value, claim));
|
||||
};
|
||||
|
||||
const isShare = useSelector(service, selectIsSharing);
|
||||
|
||||
return {
|
||||
SELECT_VC_ITEM:
|
||||
(index: number) => (vcRef: ActorRefFrom<typeof vcItemMachine>) => {
|
||||
setSelectedIndex(index);
|
||||
const vcData = vcRef.getSnapshot().context;
|
||||
SELECT_VC(vcData);
|
||||
},
|
||||
|
||||
vcKeys: useSelector(vcService, selectBindedVcs),
|
||||
selectedVc: useSelector(service, selectSelectedVc),
|
||||
linkTransactionResponse: useSelector(
|
||||
service,
|
||||
selectLinkTransactionResponse
|
||||
),
|
||||
logoUrl: useSelector(service, selectLogoUrl),
|
||||
claims: useSelector(service, selectVoluntaryClaims),
|
||||
clientName: useSelector(service, selectClientName),
|
||||
error: useSelector(service, selectErrorMessage),
|
||||
|
||||
isShare,
|
||||
|
||||
selectedIndex,
|
||||
SELECT_VC,
|
||||
SELECT_CONSENT,
|
||||
isWaitingForData: useSelector(service, selectIsWaitingForData),
|
||||
isShowWarning: useSelector(service, selectIsShowWarning),
|
||||
isShowingVcList: useSelector(service, selectIsShowingVcList),
|
||||
isLinkTransaction: useSelector(service, selectIsLinkTransaction),
|
||||
isLoadingMyVcs: useSelector(service, selectIsloadMyVcs),
|
||||
isRequestConsent: useSelector(service, selectIsRequestConsent),
|
||||
isShowingError: useSelector(service, selectIsShowError),
|
||||
isSendingConsent: useSelector(service, selectIsSendingConsent),
|
||||
isVerifyingIdentity: useSelector(service, selectIsisVerifyingIdentity),
|
||||
isInvalidIdentity: useSelector(service, selectIsInvalidIdentity),
|
||||
isVerifyingSuccesful: useSelector(service, selectIsVerifyingSuccesful),
|
||||
vcLabel: useSelector(settingsService, selectVcLabel),
|
||||
|
||||
DISMISS: () => service.send(QrLoginEvents.DISMISS()),
|
||||
SCANNING_DONE: (qrCode: string) =>
|
||||
service.send(QrLoginEvents.SCANNING_DONE(qrCode)),
|
||||
CONFIRM: () => service.send(QrLoginEvents.CONFIRM()),
|
||||
VERIFY: () => service.send(QrLoginEvents.VERIFY()),
|
||||
CANCEL: () => service.send(QrLoginEvents.CANCEL()),
|
||||
|
||||
FACE_VALID: () => service.send(QrLoginEvents.FACE_VALID()),
|
||||
FACE_INVALID: () => service.send(QrLoginEvents.FACE_INVALID()),
|
||||
RETRY_VERIFICATION: () => service.send(QrLoginEvents.RETRY_VERIFICATION()),
|
||||
};
|
||||
}
|
||||
61
screens/QrLogin/QrLoginSuccessMessage.tsx
Normal file
61
screens/QrLogin/QrLoginSuccessMessage.tsx
Normal file
@@ -0,0 +1,61 @@
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Image } from 'react-native';
|
||||
import { Icon } from 'react-native-elements';
|
||||
import { Modal } from '../../components/ui/Modal';
|
||||
import { Centered, Button, Text, Column } from '../../components/ui';
|
||||
import { Theme } from '../../components/ui/styleUtils';
|
||||
import { useQrLogin } from './QrLoginController';
|
||||
import { QrLoginRef } from '../../machines/QrLoginMachine';
|
||||
|
||||
export const QrLoginSuccess: React.FC<QrLoginSuccessProps> = (props) => {
|
||||
const { t } = useTranslation('QrScreen');
|
||||
const controller = useQrLogin(props);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
isVisible={controller.isVerifyingSuccesful}
|
||||
arrowLeft={<Icon name={''} />}
|
||||
headerTitle={t('status')}
|
||||
headerElevation={5}
|
||||
onDismiss={controller.DISMISS}>
|
||||
<Column
|
||||
fill
|
||||
align="space-between"
|
||||
style={{ display: props.isVisible ? 'flex' : 'none' }}>
|
||||
<Centered padding={'60 25 0 25'} margin={'60 0'}>
|
||||
<Image
|
||||
source={controller.logoUrl ? { uri: controller.logoUrl } : null}
|
||||
style={{ width: 60, height: 60 }}
|
||||
/>
|
||||
<Text
|
||||
style={Theme.Styles.detailsText}
|
||||
weight="semibold"
|
||||
margin="20 0 0 0"
|
||||
align="center">
|
||||
{t('successMessage')}
|
||||
{controller.clientName}
|
||||
</Text>
|
||||
</Centered>
|
||||
<Column
|
||||
style={{ borderTopRightRadius: 27, borderTopLeftRadius: 27 }}
|
||||
padding="10 24"
|
||||
margin="2 0 0 0"
|
||||
elevation={2}>
|
||||
<Button
|
||||
title={t('okay')}
|
||||
margin="0 0 12 0"
|
||||
styles={Theme.ButtonStyles.radius}
|
||||
onPress={props.onPress}
|
||||
/>
|
||||
</Column>
|
||||
</Column>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
interface QrLoginSuccessProps {
|
||||
isVisible: boolean;
|
||||
onPress: () => void;
|
||||
service: QrLoginRef;
|
||||
}
|
||||
98
screens/QrLogin/QrLoginWarning.tsx
Normal file
98
screens/QrLogin/QrLoginWarning.tsx
Normal file
@@ -0,0 +1,98 @@
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Button, Column, Row } from '../../components/ui';
|
||||
import { Theme } from '../../components/ui/styleUtils';
|
||||
import { Text } from '../../components/ui';
|
||||
import { Icon } from 'react-native-elements';
|
||||
import { useQrLogin } from './QrLoginController';
|
||||
import { Modal } from '../../components/ui/Modal';
|
||||
import { Dimensions, Image } from 'react-native';
|
||||
import { QrLoginRef } from '../../machines/QrLoginMachine';
|
||||
|
||||
export const QrLoginWarning: React.FC<QrLoginWarningProps> = (props) => {
|
||||
const { t } = useTranslation('QrScreen');
|
||||
const controller = useQrLogin(props);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
isVisible={controller.isShowWarning}
|
||||
arrowLeft={<Icon name={''} />}
|
||||
headerTitle={t('confirmation')}
|
||||
headerElevation={5}
|
||||
onDismiss={props.onCancel}>
|
||||
<Column
|
||||
fill
|
||||
align="space-between"
|
||||
padding={'24 0 0 0'}
|
||||
style={{ display: props.isVisible ? 'flex' : 'none' }}
|
||||
backgroundColor={Theme.Colors.lightGreyBackgroundColor}>
|
||||
<Column align="space-evenly" crossAlign="center" padding={'16 16 0 16'}>
|
||||
<Image source={Theme.DomainWarningLogo} resizeMethod="auto" />
|
||||
<Text
|
||||
align="center"
|
||||
style={Theme.Styles.detailsText}
|
||||
margin="21 15 15 15">
|
||||
{t('domainWarning')}
|
||||
</Text>
|
||||
<Text
|
||||
align="center"
|
||||
margin={'30 15 0 10'}
|
||||
weight="regular"
|
||||
color={Theme.Colors.Icon}
|
||||
style={Theme.Styles.urlContainer}>
|
||||
{controller.logoUrl}
|
||||
</Text>
|
||||
</Column>
|
||||
|
||||
<Column padding={'0 14 14 14'}>
|
||||
<Text
|
||||
align="center"
|
||||
weight="semibold"
|
||||
style={Theme.TextStyles.smaller}
|
||||
margin="0 15 15 15">
|
||||
{t('checkDomain')}
|
||||
</Text>
|
||||
<Row
|
||||
align="space-evenly"
|
||||
padding={'9'}
|
||||
crossAlign="center"
|
||||
style={Theme.Styles.lockDomainContainer}>
|
||||
<Icon name="lock" size={20} color={'grey'} type="font-awesome" />
|
||||
<Text
|
||||
weight="semibold"
|
||||
style={Theme.TextStyles.smaller}
|
||||
color={Theme.Colors.GrayIcon}>
|
||||
{t('domainHead')}
|
||||
</Text>
|
||||
</Row>
|
||||
</Column>
|
||||
|
||||
<Column
|
||||
padding={'10'}
|
||||
width={Dimensions.get('screen').width * 0.98}
|
||||
style={Theme.Styles.bottomButtonsContainer}>
|
||||
<Button
|
||||
margin={'2 12 0 12'}
|
||||
title={t('confirm')}
|
||||
onPress={props.onConfirm}
|
||||
styles={Theme.ButtonStyles.radius}
|
||||
/>
|
||||
<Button
|
||||
margin={'16 12 0 12'}
|
||||
type="clear"
|
||||
title={t('common:cancel')}
|
||||
onPress={props.onCancel}
|
||||
styles={Theme.ButtonStyles.clear}
|
||||
/>
|
||||
</Column>
|
||||
</Column>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
interface QrLoginWarningProps {
|
||||
isVisible: boolean;
|
||||
onConfirm: () => void;
|
||||
onCancel: () => void;
|
||||
service: QrLoginRef;
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"header": "{{vcLabel}} details",
|
||||
"acceptRequest": "Accept request and receive {{vcLabel}}",
|
||||
"acceptRequestAndVerify": "Accept request and verify",
|
||||
"reject": "Reject"
|
||||
"save": "Save {{vcLabel}}",
|
||||
"verifyAndSave": "Verify and save",
|
||||
"discard": "Discard"
|
||||
}
|
||||
@@ -24,19 +24,19 @@ export const ReceiveVcScreen: React.FC = () => {
|
||||
<Text weight="semibold" margin="24 24 0 24">
|
||||
{t('header', { vcLabel: controller.vcLabel.singular })}
|
||||
</Text>
|
||||
<VcDetails vc={controller.incomingVc} />
|
||||
<VcDetails vc={controller.incomingVc} isBindingPending={false} />
|
||||
</Column>
|
||||
<Column padding="0 24" margin="32 0 0 0">
|
||||
{controller.incomingVc.shouldVerifyPresence ? (
|
||||
<Button
|
||||
type="outline"
|
||||
title={t('acceptRequestAndVerify')}
|
||||
title={t('verifyAndSave')}
|
||||
margin="12 0 12 0"
|
||||
onPress={controller.ACCEPT_AND_VERIFY}
|
||||
/>
|
||||
) : (
|
||||
<Button
|
||||
title={t('acceptRequest', {
|
||||
title={t('save', {
|
||||
vcLabel: controller.vcLabel.singular,
|
||||
})}
|
||||
margin="12 0 12 0"
|
||||
@@ -45,7 +45,7 @@ export const ReceiveVcScreen: React.FC = () => {
|
||||
)}
|
||||
<Button
|
||||
type="clear"
|
||||
title={t('reject')}
|
||||
title={t('discard')}
|
||||
margin="0 0 12 0"
|
||||
onPress={controller.REJECT}
|
||||
/>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
},
|
||||
"rejected": {
|
||||
"title": "Notice",
|
||||
"message": "You rejected {{sender}}'s {{vcLabel}}"
|
||||
"message": "You discarded {{sender}}'s {{vcLabel}}"
|
||||
},
|
||||
"disconnected": {
|
||||
"title": "Disconnected",
|
||||
@@ -22,8 +22,11 @@
|
||||
"timeoutHint": "It's taking too long to exchange device info..."
|
||||
},
|
||||
"connected": {
|
||||
"message": "Connected to device. Waiting for {{vcLabel}}...",
|
||||
"message": "Connected to the device. Waiting for {{vcLabel}}...",
|
||||
"timeoutHint": "No data received yet. Is sending device still connected?"
|
||||
},
|
||||
"offline": {
|
||||
"message": "Please connect to the internet to enable Online sharing mode"
|
||||
}
|
||||
},
|
||||
"online": "Online",
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
selectIsWaitingForVcTimeout,
|
||||
selectIsCheckingBluetoothService,
|
||||
selectIsCancelling,
|
||||
selectIsOffline,
|
||||
} from '../../machines/request';
|
||||
import { selectVcLabel } from '../../machines/settings';
|
||||
import { GlobalContext } from '../../shared/GlobalContext';
|
||||
@@ -51,6 +52,7 @@ export function useRequestScreen() {
|
||||
requestService,
|
||||
selectIsWaitingForVcTimeout
|
||||
);
|
||||
const isOffline = useSelector(requestService, selectIsOffline);
|
||||
|
||||
let statusMessage = '';
|
||||
let statusHint = '';
|
||||
@@ -59,6 +61,8 @@ export function useRequestScreen() {
|
||||
statusMessage = t('status.waitingConnection');
|
||||
} else if (isExchangingDeviceInfo) {
|
||||
statusMessage = t('status.exchangingDeviceInfo.message');
|
||||
} else if (isOffline) {
|
||||
statusMessage = t('status.offline.message');
|
||||
} else if (isExchangingDeviceInfoTimeout) {
|
||||
statusMessage = t('status.exchangingDeviceInfo.message');
|
||||
statusHint = t('status.exchangingDeviceInfo.timeoutHint');
|
||||
|
||||
@@ -10,6 +10,7 @@ import { useScanLayout } from './ScanLayoutController';
|
||||
import { LanguageSelector } from '../../components/LanguageSelector';
|
||||
import { ScanScreen } from './ScanScreen';
|
||||
import { I18nManager, Platform } from 'react-native';
|
||||
import { Message } from '../../components/Message';
|
||||
|
||||
const ScanStack = createNativeStackNavigator();
|
||||
|
||||
@@ -68,6 +69,14 @@ export const ScanLayout: React.FC = () => {
|
||||
progress={!controller.isInvalid}
|
||||
onBackdropPress={controller.DISMISS_INVALID}
|
||||
/>
|
||||
|
||||
{controller.isDisconnected && (
|
||||
<Message
|
||||
title={t('RequestScreen:status.disconnected.title')}
|
||||
message={t('RequestScreen:status.disconnected.message')}
|
||||
onBackdropPress={controller.DISMISS}
|
||||
/>
|
||||
)}
|
||||
</React.Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -15,6 +15,10 @@ import {
|
||||
selectIsDone,
|
||||
selectIsReviewing,
|
||||
selectIsScanning,
|
||||
selectIsQrLoginDone,
|
||||
selectIsOffline,
|
||||
selectIsSent,
|
||||
selectIsDisconnected,
|
||||
} from '../../machines/scan';
|
||||
import { selectVcLabel } from '../../machines/settings';
|
||||
import { MainBottomTabParamList } from '../../routes/main';
|
||||
@@ -29,6 +33,8 @@ type ScanLayoutNavigation = NavigationProp<
|
||||
ScanStackParamList & MainBottomTabParamList
|
||||
>;
|
||||
|
||||
// TODO: refactor
|
||||
// eslint-disable-next-line sonarjs/cognitive-complexity
|
||||
export function useScanLayout() {
|
||||
const { t } = useTranslation('ScanScreen');
|
||||
const { appService } = useContext(GlobalContext);
|
||||
@@ -63,6 +69,10 @@ export function useScanLayout() {
|
||||
scanService,
|
||||
selectIsExchangingDeviceInfoTimeout
|
||||
);
|
||||
const isOffline = useSelector(scanService, selectIsOffline);
|
||||
const isSent = useSelector(scanService, selectIsSent);
|
||||
|
||||
const vcLabel = useSelector(settingsService, selectVcLabel);
|
||||
|
||||
const onCancel = () => scanService.send(ScanEvents.CANCEL());
|
||||
let statusOverlay: Pick<
|
||||
@@ -89,10 +99,19 @@ export function useScanLayout() {
|
||||
hint: t('status.exchangingDeviceInfoTimeout'),
|
||||
onCancel,
|
||||
};
|
||||
} else if (isSent) {
|
||||
statusOverlay = {
|
||||
message: t('status.sent', { vcLabel: vcLabel.singular }),
|
||||
hint: t('status.sentHint', { vcLabel: vcLabel.singular }),
|
||||
};
|
||||
} else if (isInvalid) {
|
||||
statusOverlay = {
|
||||
message: t('status.invalid'),
|
||||
};
|
||||
} else if (isOffline) {
|
||||
statusOverlay = {
|
||||
message: t('status.offline'),
|
||||
};
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
@@ -113,6 +132,8 @@ export function useScanLayout() {
|
||||
const isDone = useSelector(scanService, selectIsDone);
|
||||
const isReviewing = useSelector(scanService, selectIsReviewing);
|
||||
const isScanning = useSelector(scanService, selectIsScanning);
|
||||
const isQrLoginDone = useSelector(scanService, selectIsQrLoginDone);
|
||||
|
||||
useEffect(() => {
|
||||
if (isDone) {
|
||||
navigation.navigate('Home', { activeTab: 0 });
|
||||
@@ -120,16 +141,20 @@ export function useScanLayout() {
|
||||
navigation.navigate('SendVcScreen');
|
||||
} else if (isScanning) {
|
||||
navigation.navigate('ScanScreen');
|
||||
} else if (isQrLoginDone) {
|
||||
navigation.navigate('Home', { activeTab: 2 });
|
||||
}
|
||||
}, [isDone, isReviewing, isScanning]);
|
||||
}, [isDone, isReviewing, isScanning, isQrLoginDone]);
|
||||
|
||||
return {
|
||||
vcLabel: useSelector(settingsService, selectVcLabel),
|
||||
vcLabel,
|
||||
|
||||
isInvalid,
|
||||
isDone,
|
||||
isDisconnected: useSelector(scanService, selectIsDisconnected),
|
||||
statusOverlay,
|
||||
|
||||
DISMISS: () => scanService.send(ScanEvents.DISMISS()),
|
||||
DISMISS_INVALID: () =>
|
||||
isInvalid ? scanService.send(ScanEvents.DISMISS()) : null,
|
||||
};
|
||||
|
||||
@@ -14,9 +14,12 @@
|
||||
},
|
||||
"status": {
|
||||
"connecting": "Connecting...",
|
||||
"connectingTimeout": "It's taking a while to establish connection. Is the other device open for connections?",
|
||||
"connectingTimeout": "It's taking a while to establish the connection. Is the other device open for connections?",
|
||||
"exchangingDeviceInfo": "Exchanging device info...",
|
||||
"exchangingDeviceInfoTimeout": "It's taking a while to exchange device info. You may have to reconnect.",
|
||||
"invalid": "Invalid QR Code"
|
||||
"invalid": "Invalid QR Code",
|
||||
"offline": "Please connect to the internet to scan QR codes using Online sharing mode",
|
||||
"sent": "{{ vcLabel }} has been sent...",
|
||||
"sentHint": "Waiting for receiver to save or discard your {{ vcLabel }}"
|
||||
}
|
||||
}
|
||||
@@ -1,29 +1,15 @@
|
||||
import React from 'react';
|
||||
import { TFunction, useTranslation } from 'react-i18next';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { MessageOverlay } from '../../components/MessageOverlay';
|
||||
import { QrScanner } from '../../components/QrScanner';
|
||||
import { Button, Centered, Column, Text } from '../../components/ui';
|
||||
import { Theme } from '../../components/ui/styleUtils';
|
||||
import { QrLogin } from '../QrLogin/QrLogin';
|
||||
import { useScanScreen } from './ScanScreenController';
|
||||
|
||||
export const ScanScreen: React.FC = () => {
|
||||
const { t } = useTranslation('ScanScreen');
|
||||
const controller = useScanScreen();
|
||||
const props: ScanScreenProps = { t, controller };
|
||||
|
||||
const BluetoothPrompt: React.FC<ScanScreenProps> = ({ t, controller }) => {
|
||||
return (
|
||||
<Centered fill>
|
||||
<Text color={Theme.Colors.errorMessage} align="center">
|
||||
{t('bluetoothDenied', { vcLabel: controller.vcLabel.singular })}
|
||||
</Text>
|
||||
<Button
|
||||
margin={[32, 0, 0, 0]}
|
||||
title={t('gotoSettings')}
|
||||
onPress={controller.GOTO_SETTINGS}
|
||||
/>
|
||||
</Centered>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Column
|
||||
@@ -36,8 +22,6 @@ export const ScanScreen: React.FC = () => {
|
||||
backgroundColor={Theme.Colors.lightGreyBackgroundColor}>
|
||||
<Text align="center">{t('header')}</Text>
|
||||
|
||||
{controller.isBluetoothDenied && <BluetoothPrompt {...props} />}
|
||||
|
||||
{controller.isLocationDisabled || controller.isLocationDenied ? (
|
||||
<Column align="space-between">
|
||||
<Text
|
||||
@@ -55,7 +39,7 @@ export const ScanScreen: React.FC = () => {
|
||||
|
||||
{!controller.isEmpty ? (
|
||||
controller.isScanning && (
|
||||
<Column crossAlign="center">
|
||||
<Column crossAlign="center" margin="0 0 0 -6">
|
||||
<QrScanner onQrFound={controller.SCAN} />
|
||||
</Column>
|
||||
)
|
||||
@@ -64,12 +48,18 @@ export const ScanScreen: React.FC = () => {
|
||||
{t('noShareableVcs', { vcLabel: controller.vcLabel.plural })}
|
||||
</Text>
|
||||
)}
|
||||
{controller.isQrLogin && (
|
||||
<QrLogin
|
||||
isVisible={controller.isQrLogin}
|
||||
service={controller.isQrRef}
|
||||
/>
|
||||
)}
|
||||
<MessageOverlay
|
||||
isVisible={controller.isQrLoginstoring}
|
||||
title={t('loading')}
|
||||
progress
|
||||
/>
|
||||
</Centered>
|
||||
</Column>
|
||||
);
|
||||
};
|
||||
|
||||
interface ScanScreenProps {
|
||||
t: TFunction;
|
||||
controller: ReturnType<typeof useScanScreen>;
|
||||
}
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
import { useSelector } from '@xstate/react';
|
||||
import { useContext, useEffect } from 'react';
|
||||
import { useContext } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { selectIsActive, selectIsFocused } from '../../machines/app';
|
||||
|
||||
import {
|
||||
ScanEvents,
|
||||
selectIsLocationDisabled,
|
||||
selectIsLocationDenied,
|
||||
selectIsScanning,
|
||||
selectIsBluetoothDenied,
|
||||
selectIsShowQrLogin,
|
||||
selectQrLoginRef,
|
||||
selectIsQrLoginStoring,
|
||||
} from '../../machines/scan';
|
||||
import { selectVcLabel } from '../../machines/settings';
|
||||
import { selectShareableVcs } from '../../machines/vc';
|
||||
import { GlobalContext } from '../../shared/GlobalContext';
|
||||
import BluetoothStateManager from 'react-native-bluetooth-state-manager';
|
||||
|
||||
export function useScanScreen() {
|
||||
const { t } = useTranslation('ScanScreen');
|
||||
@@ -23,17 +23,6 @@ export function useScanScreen() {
|
||||
const vcService = appService.children.get('vc');
|
||||
|
||||
const shareableVcs = useSelector(vcService, selectShareableVcs);
|
||||
const isActive = useSelector(appService, selectIsActive);
|
||||
const isFocused = useSelector(appService, selectIsFocused);
|
||||
const isBluetoothDenied = useSelector(scanService, selectIsBluetoothDenied);
|
||||
|
||||
useEffect(() => {
|
||||
BluetoothStateManager.getState().then((bluetoothState) => {
|
||||
if (bluetoothState === 'PoweredOn' && isBluetoothDenied) {
|
||||
scanService.send(ScanEvents.SCREEN_FOCUS());
|
||||
}
|
||||
});
|
||||
}, [isFocused, isActive]);
|
||||
|
||||
const isLocationDisabled = useSelector(scanService, selectIsLocationDisabled);
|
||||
const isLocationDenied = useSelector(scanService, selectIsLocationDenied);
|
||||
@@ -52,14 +41,14 @@ export function useScanScreen() {
|
||||
locationError,
|
||||
vcLabel: useSelector(settingsService, selectVcLabel),
|
||||
|
||||
isBluetoothDenied,
|
||||
isEmpty: !shareableVcs.length,
|
||||
isLocationDisabled,
|
||||
isLocationDenied,
|
||||
isScanning: useSelector(scanService, selectIsScanning),
|
||||
|
||||
isQrLogin: useSelector(scanService, selectIsShowQrLogin),
|
||||
isQrLoginstoring: useSelector(scanService, selectIsQrLoginStoring),
|
||||
isQrRef: useSelector(scanService, selectQrLoginRef),
|
||||
LOCATION_REQUEST: () => scanService.send(ScanEvents.LOCATION_REQUEST()),
|
||||
SCAN: (qrCode: string) => scanService.send(ScanEvents.SCAN(qrCode)),
|
||||
GOTO_SETTINGS: () => scanService.send(ScanEvents.GOTO_SETTINGS()),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
},
|
||||
"rejected": {
|
||||
"title": "Notice",
|
||||
"message": "Your {{vcLabel}} was rejected by {{receiver}}"
|
||||
"message": "Your {{vcLabel}} was discarded by {{receiver}}"
|
||||
}
|
||||
},
|
||||
"consentToPhotoVerification": "I give consent to have my photo taken for authentication"
|
||||
|
||||
@@ -10,6 +10,7 @@ import { useSendVcScreen } from './SendVcScreenController';
|
||||
import { VerifyIdentityOverlay } from '../VerifyIdentityOverlay';
|
||||
import { VcItem } from '../../components/VcItem';
|
||||
import { SingleVcItem } from '../../components/SingleVcItem';
|
||||
import { I18nManager } from 'react-native';
|
||||
|
||||
export const SendVcScreen: React.FC = () => {
|
||||
const { t } = useTranslation('SendVcScreen');
|
||||
@@ -32,8 +33,10 @@ export const SendVcScreen: React.FC = () => {
|
||||
value={controller.reason ? controller.reason : ''}
|
||||
placeholder={!controller.reason ? reasonLabel : ''}
|
||||
label={controller.reason ? reasonLabel : ''}
|
||||
labelStyle={{ textAlign: 'left' }}
|
||||
onChangeText={controller.UPDATE_REASON}
|
||||
containerStyle={{ marginBottom: 24 }}
|
||||
inputStyle={{ textAlign: I18nManager.isRTL ? 'right' : 'left' }}
|
||||
/>
|
||||
</Column>
|
||||
<Column>
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
"errors": {
|
||||
"invalidIdentity": {
|
||||
"title": "Unable to verify identity",
|
||||
"message": "An error occured and we couldn't scan your portrait. Try again, make sure your face is visible, devoid of any accessories.",
|
||||
"messageNoRetry": "An error occured and we couldn't scan your portrait."
|
||||
"message": "An error occurred and we couldn't scan your portrait. Try again, make sure your face is visible, devoid of any accessories.",
|
||||
"messageNoRetry": "An error occurred and we couldn't scan your portrait."
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,15 +5,18 @@ import { FaceScanner } from '../components/FaceScanner';
|
||||
import { Column, Row } from '../components/ui';
|
||||
import { Theme } from '../components/ui/styleUtils';
|
||||
import { VC } from '../types/vc';
|
||||
import { Modal } from '../components/ui/Modal';
|
||||
import { t } from 'i18next';
|
||||
|
||||
export const VerifyIdentityOverlay: React.FC<VerifyIdentityOverlayProps> = (
|
||||
props
|
||||
) => {
|
||||
return (
|
||||
<Overlay isVisible={props.isVisible}>
|
||||
<Row align="flex-end" padding="16">
|
||||
<Icon name="close" color={Theme.Colors.Icon} onPress={props.onCancel} />
|
||||
</Row>
|
||||
<Modal
|
||||
isVisible={props.isVisible}
|
||||
arrowLeft={<Icon name={''} />}
|
||||
headerTitle={t('faceAuth')}
|
||||
onDismiss={props.onCancel}>
|
||||
<Column
|
||||
fill
|
||||
style={Theme.VerifyIdentityOverlayStyles.content}
|
||||
@@ -26,7 +29,7 @@ export const VerifyIdentityOverlay: React.FC<VerifyIdentityOverlayProps> = (
|
||||
/>
|
||||
)}
|
||||
</Column>
|
||||
</Overlay>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import { settingsMachine } from '../machines/settings';
|
||||
import { storeMachine } from '../machines/store';
|
||||
import { vcMachine } from '../machines/vc';
|
||||
import { revokeVidsMachine } from '../machines/revoke';
|
||||
import { qrLoginMachine } from '../machines/QrLoginMachine';
|
||||
|
||||
export const GlobalContext = createContext({} as GlobalServices);
|
||||
|
||||
|
||||
@@ -8,6 +8,6 @@
|
||||
"errors": {
|
||||
"missingPermission": "This app uses the camera to scan the QR code of another device."
|
||||
},
|
||||
"allowAccess": "Allow access to camera"
|
||||
"allowAccess": "Allow access to the camera"
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,23 @@
|
||||
import { request } from '../request';
|
||||
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||
|
||||
export default async function getAllProperties() {
|
||||
const COMMON_PROPS_KEY: string =
|
||||
'CommonPropsKey-' + '6964d04a-9268-11ed-a1eb-0242ac120002';
|
||||
|
||||
export default async function getAllConfigurations() {
|
||||
try {
|
||||
const resp = await request('GET', '/allProperties');
|
||||
return resp.response;
|
||||
var response = await AsyncStorage.getItem(COMMON_PROPS_KEY);
|
||||
if (response) {
|
||||
return JSON.parse(response);
|
||||
} else {
|
||||
const resp = await request('GET', '/allProperties');
|
||||
const injiProps = resp.response;
|
||||
const injiPropsString = JSON.stringify(injiProps);
|
||||
await AsyncStorage.setItem(COMMON_PROPS_KEY, injiPropsString);
|
||||
return injiProps;
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@ export const MY_VCS_STORE_KEY = 'myVCs';
|
||||
|
||||
export const RECEIVED_VCS_STORE_KEY = 'receivedVCs';
|
||||
|
||||
export const MY_LOGIN_STORE_KEY = 'myLogins';
|
||||
|
||||
export const VC_ITEM_STORE_KEY = (vc: Partial<VC>) =>
|
||||
`vc:${vc.idType}:${vc.id}:${vc.requestId}`;
|
||||
|
||||
|
||||
68
shared/cryptoutil/cryptoUtil.ts
Normal file
68
shared/cryptoutil/cryptoUtil.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
import { KeyPair, RSA } from 'react-native-rsa-native';
|
||||
import forge from 'node-forge';
|
||||
import getAllConfigurations from '../commonprops/commonProps';
|
||||
|
||||
export function generateKeys(): Promise<KeyPair> {
|
||||
return Promise.resolve(RSA.generateKeys(4096));
|
||||
}
|
||||
|
||||
export async function getJwt(
|
||||
privateKey: string,
|
||||
individualId: string,
|
||||
keyId: string,
|
||||
thumbprint: string
|
||||
) {
|
||||
var token: string = null;
|
||||
try {
|
||||
var iat = Math.floor(new Date().getTime() / 1000);
|
||||
var exp = Math.floor(new Date().getTime() / 1000) + 18000;
|
||||
|
||||
var config = await getAllConfigurations();
|
||||
|
||||
const key = forge.pki.privateKeyFromPem(privateKey);
|
||||
const md = forge.md.sha256.create();
|
||||
const header = {
|
||||
'alg': 'RS256',
|
||||
//'kid': keyId,
|
||||
'x5t#S256': thumbprint,
|
||||
};
|
||||
var myJSON =
|
||||
'{"iss": "' +
|
||||
config.issuer +
|
||||
'", "aud": "' +
|
||||
config.audience +
|
||||
'", "sub": "' +
|
||||
individualId +
|
||||
'", "iat": ' +
|
||||
iat +
|
||||
', "exp": ' +
|
||||
exp +
|
||||
'}';
|
||||
var payload = JSON.parse(myJSON);
|
||||
const strHeader = JSON.stringify(header);
|
||||
const strPayload = JSON.stringify(payload);
|
||||
const header64 = encodeB64(strHeader);
|
||||
const payload64 = encodeB64(strPayload);
|
||||
const preHash = header64 + '.' + payload64;
|
||||
md.update(preHash, 'utf8');
|
||||
const signature = key.sign(md);
|
||||
const signature64 = encodeB64(signature);
|
||||
var token: string = header64 + '.' + payload64 + '.' + signature64;
|
||||
return token;
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
function encodeB64(str: string) {
|
||||
const encodedB64 = forge.util.encode64(str);
|
||||
return encodedB64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
|
||||
}
|
||||
|
||||
export interface WalletBindingResponse {
|
||||
walletBindingId: string;
|
||||
keyId: string;
|
||||
thumbprint: string;
|
||||
expireDateTime: string;
|
||||
}
|
||||
19
shared/keystore/SecureKeystore.ts
Normal file
19
shared/keystore/SecureKeystore.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import RNSecureKeyStore, { ACCESSIBLE } from 'react-native-secure-key-store';
|
||||
|
||||
const bindingCertificate = '-bindingCertificate';
|
||||
|
||||
export async function savePrivateKey(id: string, privateKey: string) {
|
||||
var result = await RNSecureKeyStore.set(id, privateKey, {
|
||||
accessible: ACCESSIBLE.ALWAYS_THIS_DEVICE_ONLY,
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
export async function getPrivateKey(id: string) {
|
||||
var result = await RNSecureKeyStore.get(id);
|
||||
return result;
|
||||
}
|
||||
|
||||
export function getBindingCertificateConstant(id: string) {
|
||||
return id + bindingCertificate;
|
||||
}
|
||||
@@ -24,6 +24,7 @@ export function onlineSubscribe<T extends SmartshareEventType>(
|
||||
}
|
||||
const response = SmartshareEvent.fromString<T>(foundMessage);
|
||||
if (response.type === 'disconnect') {
|
||||
GoogleNearbyMessages.unsubscribe();
|
||||
disconectCallback(response.data);
|
||||
} else if (response.type === eventType) {
|
||||
!config?.keepAlive && GoogleNearbyMessages.unsubscribe();
|
||||
@@ -35,7 +36,12 @@ export function onlineSubscribe<T extends SmartshareEventType>(
|
||||
console.log('\n[request] MESSAGE_LOST', lostMessage.slice(0, 100));
|
||||
}
|
||||
}
|
||||
);
|
||||
).catch((error: Error) => {
|
||||
if (error.message.includes('existing callback is already subscribed')) {
|
||||
console.log('Existing callback found. Unsubscribing then retrying...');
|
||||
return onlineSubscribe(eventType, callback, disconectCallback, config);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function onlineSend(event: SmartshareEvents) {
|
||||
@@ -114,7 +120,7 @@ export interface SendVcEvent {
|
||||
};
|
||||
}
|
||||
|
||||
export type SendVcStatus = 'ACCEPTED' | 'REJECTED';
|
||||
export type SendVcStatus = 'ACCEPTED' | 'REJECTED' | 'RECEIVED';
|
||||
export interface SendVcResponseEvent {
|
||||
type: 'send-vc:response';
|
||||
data: SendVcStatus | number;
|
||||
|
||||
14
types/vc.ts
14
types/vc.ts
@@ -1,3 +1,5 @@
|
||||
import { WalletBindingResponse } from '../shared/cryptoutil/cryptoUtil';
|
||||
|
||||
export interface VC {
|
||||
id: string;
|
||||
idType: VcIdType;
|
||||
@@ -12,6 +14,7 @@ export interface VC {
|
||||
locked: boolean;
|
||||
reason?: VCSharingReason[];
|
||||
shouldVerifyPresence?: boolean;
|
||||
walletBindingResponse?: WalletBindingResponse;
|
||||
}
|
||||
|
||||
export interface VCSharingReason {
|
||||
@@ -98,3 +101,14 @@ export interface LocalizedField {
|
||||
language: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface linkTransactionResponse {
|
||||
authFactors: Object[];
|
||||
authorizeScopes: null;
|
||||
clientName: string;
|
||||
configs: {};
|
||||
essentialClaims: string[];
|
||||
linkTransactionId: string;
|
||||
logoUrl: string;
|
||||
voluntaryClaims: string[];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user