[INJIMOB-3532] add sd jwt vp support (#2082)

* [INJIMOB-3513] add sd jwt vp support

Signed-off-by: Abhishek Paul <paul.apaul.abhishek.ap@gmail.com>

* [INJIMOB-3513] add bridge logic and sd-jwt signing for ovp

Signed-off-by: Abhishek Paul <paul.apaul.abhishek.ap@gmail.com>

* [INJIMOB-3532] add: support of OVP share in iOS

Signed-off-by: KiruthikaJeyashankar <kiruthikavjshankar@gmail.com>

* [INJIMOB-3532] add sd-jwt ovp ui

Signed-off-by: Abhishek Paul <paul.apaul.abhishek.ap@gmail.com>

* [INJIMOB-3532] refactor: optimize wallet_metadata creation logic

Signed-off-by: KiruthikaJeyashankar <kiruthikavjshankar@gmail.com>

* [INJIMOB-3532] refactor: fixed alignement issues and crash bug

Signed-off-by: Abhishek Paul <paul.apaul.abhishek.ap@gmail.com>

---------

Signed-off-by: Abhishek Paul <paul.apaul.abhishek.ap@gmail.com>
Signed-off-by: KiruthikaJeyashankar <kiruthikavjshankar@gmail.com>
Co-authored-by: KiruthikaJeyashankar <kiruthikavjshankar@gmail.com>
This commit is contained in:
abhip2565
2025-09-18 18:50:53 +05:30
committed by GitHub
parent 62b627242c
commit 0713bbb5c4
36 changed files with 1291 additions and 627 deletions

View File

@@ -3,6 +3,8 @@ package io.mosip.residentapp;
import static io.mosip.openID4VP.authorizationResponse.AuthorizationResponseUtilsKt.toJsonString;
import static io.mosip.openID4VP.constants.FormatType.LDP_VC;
import static io.mosip.openID4VP.constants.FormatType.MSO_MDOC;
import static io.mosip.openID4VP.constants.FormatType.VC_SD_JWT;
import static io.mosip.openID4VP.constants.FormatType.DC_SD_JWT;
import android.annotation.SuppressLint;
import android.util.Log;
@@ -57,6 +59,7 @@ import io.mosip.openID4VP.authorizationResponse.vpTokenSigningResult.VPTokenSign
import io.mosip.openID4VP.authorizationResponse.vpTokenSigningResult.types.ldp.LdpVPTokenSigningResult;
import io.mosip.openID4VP.authorizationResponse.vpTokenSigningResult.types.mdoc.DeviceAuthentication;
import io.mosip.openID4VP.authorizationResponse.vpTokenSigningResult.types.mdoc.MdocVPTokenSigningResult;
import io.mosip.openID4VP.authorizationResponse.vpTokenSigningResult.types.sdJwt.SdJwtVPTokenSigningResult;
import io.mosip.openID4VP.constants.FormatType;
import kotlinx.serialization.json.Json;
@@ -79,7 +82,7 @@ public class InjiOpenID4VPModule extends ReactContextBaseJavaModule {
@SuppressLint("LogNotTimber")
@ReactMethod
public void initSdk(String appId, ReadableMap walletMetadata ) {
public void initSdk(String appId, ReadableMap walletMetadata) {
Log.d(TAG, "Initializing InjiOpenID4VPModule with " + appId);
WalletMetadata metadata = parseWalletMetadata(walletMetadata);
@@ -93,17 +96,16 @@ public class InjiOpenID4VPModule extends ReactContextBaseJavaModule {
@ReactMethod
public void authenticateVerifier(String urlEncodedAuthorizationRequest,
ReadableArray trustedVerifiers,
Boolean shouldValidateClient,
Promise promise) {
ReadableArray trustedVerifiers,
Boolean shouldValidateClient,
Promise promise) {
try {
List<Verifier> verifierList = parseVerifiers(trustedVerifiers);
AuthorizationRequest authRequest = openID4VP.authenticateVerifier(
urlEncodedAuthorizationRequest,
verifierList,
shouldValidateClient
);
shouldValidateClient);
String authRequestJson = gson.toJson(authRequest, AuthorizationRequest.class);
promise.resolve(authRequestJson);
@@ -113,10 +115,12 @@ public class InjiOpenID4VPModule extends ReactContextBaseJavaModule {
}
@ReactMethod
public void constructUnsignedVPToken(ReadableMap selectedVCs, String holderId, String signatureSuite, Promise promise) {
public void constructUnsignedVPToken(ReadableMap selectedVCs, String holderId, String signatureSuite,
Promise promise) {
try {
Map<String, Map<FormatType, List<Object>>> selectedVCsMap = parseSelectedVCs(selectedVCs);
Map<FormatType, UnsignedVPToken> vpTokens = openID4VP.constructUnsignedVPToken(selectedVCsMap, holderId, signatureSuite);
Map<FormatType, UnsignedVPToken> vpTokens = openID4VP.constructUnsignedVPToken(selectedVCsMap, holderId,
signatureSuite);
promise.resolve(toJsonString(vpTokens));
} catch (Exception e) {
rejectWithOpenID4VPExceptions(e, promise);
@@ -170,15 +174,19 @@ public class InjiOpenID4VPModule extends ReactContextBaseJavaModule {
Map<VPFormatType, VPFormatSupported> vpFormatsSupportedMap = parseVpFormatsSupported(walletMetadata);
return new WalletMetadata(
return new WalletMetadata(
presentationDefinitionUriSupported,
vpFormatsSupportedMap,
convertReadableArrayToEnumList(walletMetadata, "client_id_schemes_supported", ClientIdScheme.Companion::fromValue),
convertReadableArrayToEnumList(walletMetadata, "request_object_signing_alg_values_supported", RequestSigningAlgorithm.Companion::fromValue),
convertReadableArrayToEnumList(walletMetadata, "authorization_encryption_alg_values_supported", KeyManagementAlgorithm.Companion::fromValue),
convertReadableArrayToEnumList(walletMetadata, "authorization_encryption_enc_values_supported", ContentEncryptionAlgorithm.Companion::fromValue),
convertReadableArrayToEnumList(walletMetadata, "response_type_supported", ResponseType.Companion::fromValue)
);
convertReadableArrayToEnumList(walletMetadata, "client_id_schemes_supported",
ClientIdScheme.Companion::fromValue),
convertReadableArrayToEnumList(walletMetadata, "request_object_signing_alg_values_supported",
RequestSigningAlgorithm.Companion::fromValue),
convertReadableArrayToEnumList(walletMetadata, "authorization_encryption_alg_values_supported",
KeyManagementAlgorithm.Companion::fromValue),
convertReadableArrayToEnumList(walletMetadata, "authorization_encryption_enc_values_supported",
ContentEncryptionAlgorithm.Companion::fromValue),
convertReadableArrayToEnumList(walletMetadata, "response_type_supported",
ResponseType.Companion::fromValue));
}
private Map<VPFormatType, VPFormatSupported> parseVpFormatsSupported(ReadableMap walletMetadata) {
@@ -188,13 +196,17 @@ public class InjiOpenID4VPModule extends ReactContextBaseJavaModule {
if (vpFormatsMap != null) {
addVpFormatSupported(vpFormatsMap, "ldp_vc", vpFormatsSupportedMap);
addVpFormatSupported(vpFormatsMap, "mso_mdoc", vpFormatsSupportedMap);
addVpFormatSupported(vpFormatsMap, "vc+sd-jwt", vpFormatsSupportedMap);
addVpFormatSupported(vpFormatsMap, "dc+sd-jwt", vpFormatsSupportedMap);
}
}
return vpFormatsSupportedMap;
}
private <T> List<T> convertReadableArrayToEnumList(ReadableMap readableMap, String key, Function<String, T> converter) {
if (!readableMap.hasKey(key)) return null;
private <T> List<T> convertReadableArrayToEnumList(ReadableMap readableMap, String key,
Function<String, T> converter) {
if (!readableMap.hasKey(key))
return null;
ReadableArray readableArray = readableMap.getArray(key);
List<T> list = new ArrayList<>();
for (int i = 0; i < Objects.requireNonNull(readableArray).size(); i++) {
@@ -203,8 +215,8 @@ public class InjiOpenID4VPModule extends ReactContextBaseJavaModule {
return list;
}
private void addVpFormatSupported(ReadableMap vpFormatsMap, String key, Map<VPFormatType, VPFormatSupported> vpFormatsSupportedMap) {
private void addVpFormatSupported(ReadableMap vpFormatsMap, String key,
Map<VPFormatType, VPFormatSupported> vpFormatsSupportedMap) {
if (vpFormatsMap.hasKey(key)) {
ReadableMap formatMap = vpFormatsMap.getMap(key);
if (formatMap != null && formatMap.hasKey("alg_values_supported")) {
@@ -215,8 +227,6 @@ public class InjiOpenID4VPModule extends ReactContextBaseJavaModule {
}
}
private List<Verifier> parseVerifiers(ReadableArray verifiersArray) {
List<Verifier> verifiers = new ArrayList();
@@ -230,21 +240,23 @@ public class InjiOpenID4VPModule extends ReactContextBaseJavaModule {
try {
ReadableMap metadataMap = verifierMap.getMap("client_metadata");
String metadataJsonString = readableMapToJson(metadataMap).toString();
clientMetadata = Json.Default.decodeFromString(ClientMetadataSerializer.INSTANCE, metadataJsonString);
clientMetadata = Json.Default.decodeFromString(ClientMetadataSerializer.INSTANCE,
metadataJsonString);
} catch (Exception e) {
e.printStackTrace();
}
}
verifiers.add(new Verifier(clientId, responseUriList, clientMetadata));
}
return verifiers;
}
private static JSONObject readableMapToJson(ReadableMap readableMap) {
JSONObject jsonObject = new JSONObject();
ReadableMapKeySetIterator iterator = readableMap.keySetIterator();
while (iterator.hasNextKey()) {
String key = iterator.nextKey();
ReadableType type = readableMap.getType(key);
@@ -273,10 +285,10 @@ public class InjiOpenID4VPModule extends ReactContextBaseJavaModule {
e.printStackTrace();
}
}
return jsonObject;
}
private static JSONArray readableArrayToJson(ReadableArray readableArray) {
JSONArray jsonArray = new JSONArray();
for (int i = 0; i < readableArray.size(); i++) {
@@ -308,7 +320,6 @@ public class InjiOpenID4VPModule extends ReactContextBaseJavaModule {
}
return jsonArray;
}
private Map<String, Map<FormatType, List<Object>>> parseSelectedVCs(ReadableMap selectedVCs) {
if (selectedVCs == null) {
@@ -370,10 +381,10 @@ public class InjiOpenID4VPModule extends ReactContextBaseJavaModule {
private VPTokenSigningResult createVPTokenSigningResult(FormatType formatType, ReadableMap metadata) {
switch (formatType) {
case LDP_VC: {
String jws =metadata.getString("jws");
String proofValue =metadata.getString("proofValue");
String signatureAlgorithm =metadata.getString("signatureAlgorithm");
return new LdpVPTokenSigningResult(jws, proofValue, signatureAlgorithm );
String jws = metadata.getString("jws");
String proofValue = metadata.getString("proofValue");
String signatureAlgorithm = metadata.getString("signatureAlgorithm");
return new LdpVPTokenSigningResult(jws, proofValue, signatureAlgorithm);
}
case MSO_MDOC: {
Map<String, DeviceAuthentication> signatureData = new HashMap<>();
@@ -386,13 +397,25 @@ public class InjiOpenID4VPModule extends ReactContextBaseJavaModule {
String algorithm = requireNonNullString(deviceAuthenticationMap, "mdocAuthenticationAlgorithm");
DeviceAuthentication deviceAuthentication = new DeviceAuthentication(
signature = signature,
algorithm = algorithm
);
algorithm = algorithm);
signatureData.put(docType, deviceAuthentication);
}
}
return new MdocVPTokenSigningResult(signatureData);
}
case VC_SD_JWT:
case DC_SD_JWT: {
Map<String, String> uuidToSignature = new HashMap<>();
ReadableMapKeySetIterator uuidIterator = metadata.keySetIterator();
while (uuidIterator.hasNextKey()) {
String uuid = uuidIterator.nextKey();
String signature = metadata.getString(uuid);
if (signature != null) {
uuidToSignature.put(uuid, signature);
}
}
return new SdJwtVPTokenSigningResult(uuidToSignature);
}
default:
return null;
}
@@ -417,6 +440,22 @@ public class InjiOpenID4VPModule extends ReactContextBaseJavaModule {
return mdocVcList;
}
case VC_SD_JWT: {
List<Object> vcSdJwtList = new ArrayList<>();
for (int i = 0; i < credentialList.size(); i++) {
String credential = credentialList.getString(i);
vcSdJwtList.add(credential);
}
return vcSdJwtList;
}
case DC_SD_JWT: {
List<Object> dcSdJwtList = new ArrayList<>();
for (int i = 0; i < credentialList.size(); i++) {
String credential = credentialList.getString(i);
dcSdJwtList.add(credential);
}
return dcSdJwtList;
}
default:
return null;
}
@@ -427,6 +466,10 @@ public class InjiOpenID4VPModule extends ReactContextBaseJavaModule {
return LDP_VC;
} else if (MSO_MDOC.getValue().equals(formatStr)) {
return MSO_MDOC;
} else if (VC_SD_JWT.getValue().equals(formatStr)) {
return VC_SD_JWT;
} else if (DC_SD_JWT.getValue().equals(formatStr)) {
return DC_SD_JWT;
}
throw new UnsupportedOperationException("Credential format '" + formatStr + "' is not supported");
}

View File

@@ -1,52 +1,54 @@
import React from 'react';
import {Modal, View, Text, Image, ScrollView} from 'react-native';
import {Button} from '../../components/ui';
import {Theme} from '../../components/ui/styleUtils';
import {useTranslation} from 'react-i18next';
import { Modal, View, Text, Image, ScrollView } from 'react-native';
import { Button } from './ui';
import { Theme } from './ui/styleUtils';
import { useTranslation } from 'react-i18next';
export const TrustIssuerModal = ({
isVisible,
issuerLogo,
issuerName,
onConfirm,
onCancel,
}: {
export const TrustModal = ({
isVisible,
logo,
name,
onConfirm,
onCancel,
flowType = 'issuer',
}: {
isVisible: boolean;
issuerLogo: any;
issuerName: string;
logo: any;
name: string;
onConfirm: () => void;
onCancel: () => void;
flowType?: 'issuer' | 'verifier';
}) => {
const {t} = useTranslation('trustScreen');
const { t } = useTranslation('trustScreen');
return (
<Modal transparent={true} visible={isVisible} animationType="fade">
<View style={Theme.TrustIssuerScreenStyle.modalOverlay}>
<View style={Theme.TrustIssuerScreenStyle.modalContainer}>
{(issuerLogo || issuerName) && (
{(logo || name) && (
<View style={Theme.TrustIssuerScreenStyle.issuerHeader}>
{issuerLogo && (
{logo && (
<Image
source={{uri: issuerLogo}}
source={{ uri: logo }}
style={Theme.TrustIssuerScreenStyle.issuerLogo}
/>
)}
{issuerName && (
{name && (
<Text style={Theme.TrustIssuerScreenStyle.issuerName}>
{issuerName}
{name}
</Text>
)}
</View>
)}
<ScrollView
style={{flex: 1, width: '100%'}}
contentContainerStyle={{alignItems: 'center', paddingBottom: 10}}
style={{ flex: 1, width: '100%' }}
contentContainerStyle={{ alignItems: 'center', paddingBottom: 10 }}
showsVerticalScrollIndicator={true}>
<Text style={Theme.TrustIssuerScreenStyle.description}>
{t('description')}
{t(flowType == 'issuer' ? 'description' : 'verifierDescription')}
</Text>
<View style={Theme.TrustIssuerScreenStyle.infoContainer}>
{t('infoPoints', {returnObjects: true}).map((point, index) => (
{t(flowType == 'issuer' ? 'infoPoints' : 'verifierInfoPoints', { returnObjects: true }).map((point, index) => (
<View key={index} style={Theme.TrustIssuerScreenStyle.infoItem}>
<Text style={Theme.TrustIssuerScreenStyle.info}></Text>
<Text style={Theme.TrustIssuerScreenStyle.infoText}>
@@ -57,7 +59,7 @@ export const TrustIssuerModal = ({
</View>
</ScrollView>
<View style={{width: '100%', paddingTop: 10, paddingBottom: 5}}>
<View style={{ width: '100%', paddingTop: 10, paddingBottom: 5 }}>
<Button
styles={{
marginBottom: 3,
@@ -66,14 +68,14 @@ export const TrustIssuerModal = ({
alignItems: 'center',
}}
type="gradient"
title={t('confirm')}
title={t(flowType == 'issuer' ? 'confirm' : 'verifierConfirm')}
onPress={onConfirm}
/>
<Button
styles={{
marginBottom: -10,
paddingBottom: 20,
minHeight: 80,
minHeight: 60,
justifyContent: 'center',
alignItems: 'center',
maxWidth: '100%',

View File

@@ -27,6 +27,7 @@ export const VCCardView: React.FC<VCItemProps> = ({
flow,
isInitialLaunch = false,
isTopCard = false,
onDisclosuresChange,
}) => {
const controller = useVcItemController(vcMetadata);
const {t} = useTranslation();
@@ -56,17 +57,16 @@ export const VCCardView: React.FC<VCItemProps> = ({
setVc(processedData);
}
}
loadVc();
}, [isDownloading, controller.credential]);
useEffect(() => {
if (!verifiableCredentialData || !verifiableCredentialData.vcMetadata) return;
const {
issuer,
credentialConfigurationId,
vcMetadata: { format },
} = verifiableCredentialData;
if (vcMetadata.issuerHost) {
getCredentialIssuersWellKnownConfig(
vcMetadata.issuerHost,
@@ -76,13 +76,13 @@ export const VCCardView: React.FC<VCItemProps> = ({
vcMetadata.issuerHost,
)
.then(response => {
if(response && response.matchingCredentialIssuerMetadata) {
setWellknown(response.matchingCredentialIssuerMetadata);
if (response && response.matchingCredentialIssuerMetadata) {
setWellknown(response.matchingCredentialIssuerMetadata);
}
setFields(response.fields);
})
.catch(error => {
setWellknown({"fallback":"true"});
setWellknown({fallback: 'true'});
console.error(
'Error occurred while fetching wellknown for viewing VC ',
error,
@@ -94,6 +94,7 @@ export const VCCardView: React.FC<VCItemProps> = ({
if (!isVCLoaded(controller.credential) || !wellknown || !vc) {
return <VCCardSkeleton />;
}
const CardViewContent = () => (
<VCCardViewContent
vcMetadata={vcMetadata}
@@ -111,6 +112,7 @@ export const VCCardView: React.FC<VCItemProps> = ({
DISMISS={controller.DISMISS}
KEBAB_POPUP={controller.KEBAB_POPUP}
isInitialLaunch={isInitialLaunch}
onDisclosuresChange={onDisclosuresChange}
/>
);
@@ -159,4 +161,5 @@ export interface VCItemProps {
flow?: string;
isInitialLaunch?: boolean;
isTopCard?: boolean;
}
onDisclosuresChange?: (paths: string[]) => void;
}

View File

@@ -1,29 +1,184 @@
import React from 'react';
import {ImageBackground, Pressable, View, Image, ImageBackgroundProps} from 'react-native';
import {VCMetadata} from '../../../shared/VCMetadata';
import {KebabPopUp} from '../../KebabPopUp';
import {Credential} from '../../../machines/VerifiableCredential/VCMetaMachine/vc';
import {Column, Row} from '../../ui';
import {Theme} from '../../ui/styleUtils';
import {CheckBox, Icon} from 'react-native-elements';
import {SvgImage} from '../../ui/svg';
import {VcItemContainerProfileImage} from '../../VcItemContainerProfileImage';
import {isVCLoaded, getCredentialType, Display} from '../common/VCUtils';
import {VCItemFieldValue} from '../common/VCItemField';
import {WalletBinding} from '../../../screens/Home/MyVcs/WalletBinding';
import {VCVerification} from '../../VCVerification';
import {isActivationNeeded} from '../../../shared/openId4VCI/Utils';
import {VCItemContainerFlowType} from '../../../shared/Utils';
import {RemoveVcWarningOverlay} from '../../../screens/Home/MyVcs/RemoveVcWarningOverlay';
import {HistoryTab} from '../../../screens/Home/MyVcs/HistoryTab';
import {useCopilot} from 'react-native-copilot';
import {useTranslation} from 'react-i18next';
import React, { useEffect, useState } from 'react';
import { ImageBackground, Pressable, View, Image, ImageBackgroundProps } from 'react-native';
import { VCMetadata } from '../../../shared/VCMetadata';
import { KebabPopUp } from '../../KebabPopUp';
import { Credential } from '../../../machines/VerifiableCredential/VCMetaMachine/vc';
import { Column, Row, Text } from '../../ui';
import { Theme } from '../../ui/styleUtils';
import { CheckBox, Icon } from 'react-native-elements';
import { SvgImage } from '../../ui/svg';
import { VcItemContainerProfileImage } from '../../VcItemContainerProfileImage';
import { isVCLoaded, getCredentialType, Display, formatKeyLabel } from '../common/VCUtils';
import { VCItemFieldValue } from '../common/VCItemField';
import { WalletBinding } from '../../../screens/Home/MyVcs/WalletBinding';
import { VCVerification } from '../../VCVerification';
import { isActivationNeeded } from '../../../shared/openId4VCI/Utils';
import { VCItemContainerFlowType } from '../../../shared/Utils';
import { RemoveVcWarningOverlay } from '../../../screens/Home/MyVcs/RemoveVcWarningOverlay';
import { HistoryTab } from '../../../screens/Home/MyVcs/HistoryTab';
import { useCopilot } from 'react-native-copilot';
import { useTranslation } from 'react-i18next';
import testIDProps from '../../../shared/commonUtil';
export const VCCardViewContent: React.FC<VCItemContentProps> = ({
isPinned = false,
credential,
verifiableCredentialData,
wellknown,
selectable,
selected,
service,
onPress,
flow,
walletBindingResponse,
KEBAB_POPUP,
DISMISS,
isKebabPopUp,
vcMetadata,
isInitialLaunch,
onDisclosuresChange,
}) => {
const [isExpanded, setIsExpanded] = useState(false);
const [selectedFields, setSelectedFields] = useState<Record<string, boolean>>({});
useEffect(() => {
if (flow === VCItemContainerFlowType.VP_SHARE) {
setIsExpanded(selected);
}
}, [selected]);
const toggleExpand = () => {
if (flow === VCItemContainerFlowType.VP_SHARE) {
setIsExpanded(prev => !prev);
}
};
const [expandedNodes, setExpandedNodes] = useState<Record<string, boolean>>({});
const areAllSelected = (): boolean => {
return credential.disclosedKeys.every(key => selectedFields[key]);
};
const toggleSelectAll = () => {
const updated: Record<string, boolean> = {};
if (areAllSelected()) {
credential.disclosedKeys.forEach(key => {
updated[key] = false;
});
} else {
credential.disclosedKeys.forEach(key => {
updated[key] = true;
});
}
setSelectedFields(updated);
const selectedPaths = Object.keys(updated).filter(k => updated[k]);
onDisclosuresChange?.(selectedPaths);
};
const DisclosureNode: React.FC<{
name: string;
node: any;
fullPath: string;
expandedNodes: Record<string, boolean>;
setExpandedNodes: React.Dispatch<React.SetStateAction<Record<string, boolean>>>;
}> = ({ name, node, fullPath, expandedNodes, setExpandedNodes }) => {
const isExpanded = expandedNodes[fullPath] || false;
const toggleExpand = () => {
setExpandedNodes(prev => ({
...prev,
[fullPath]: !prev[fullPath],
}));
};
const isChecked = selectedFields[fullPath] || false;
return (
<Column>
<Row crossAlign="center" style={{ justifyContent: "space-between", marginBottom: -10 }}>
<Row crossAlign="center">
{node.__self && (
<CheckBox
size={22}
checked={isChecked}
checkedIcon={SvgImage.selectedCheckBox()}
uncheckedIcon={
<Icon
name="check-box-outline-blank"
color={Theme.Colors.uncheckedIcon}
size={22}
/>
}
onPress={() => handleFieldToggle(fullPath)}
/>
)}
<Text weight="semibold" color={wellknownDisplayProperty.getTextColor(Theme.Colors.plainText)} style={{ marginLeft: 8 }}>
{formatKeyLabel(name)}
</Text>
</Row>
{/* Right side: expand/collapse icon */}
{Object.keys(node.children).length > 0 && (
<Pressable onPress={toggleExpand} style={{ marginLeft: 12 }}>
<Icon
name={isExpanded ? "expand-less" : "expand-more"}
color={Theme.Colors.Icon}
/>
</Pressable>
)}
</Row>
{isExpanded &&
Object.entries(node.children).map(([childName, childNode]) => (
<Column key={childName} margin="0 0 0 15">
<DisclosureNode
name={childName}
node={childNode}
fullPath={`${fullPath}.${childName}`}
expandedNodes={expandedNodes}
setExpandedNodes={setExpandedNodes}
/>
</Column>
))}
</Column>
);
};
const handleFieldToggle = (path: string) => {
setSelectedFields(prev => {
const updated = { ...prev, [path]: !prev[path] };
// If child selected → ensure all its parents are also selected
if (updated[path]) {
const parts = path.split('.');
while (parts.length > 1) {
parts.pop();
const parent = parts.join('.');
if (credential.disclosedKeys.includes(parent)) {
updated[parent] = true;
}
}
}
else {
Object.keys(updated).forEach(p => {
if (p.startsWith(path + '.') && updated[p]) {
updated[p] = false;
}
});
}
const selectedPaths = Object.keys(updated).filter(p => updated[p]);
onDisclosuresChange?.(selectedPaths);
return updated;
});
};
export const VCCardViewContent: React.FC<VCItemContentProps> = ({isPinned = false, credential, verifiableCredentialData, wellknown, selectable, selected, service, onPress, flow, walletBindingResponse, KEBAB_POPUP, DISMISS, isKebabPopUp, vcMetadata, isInitialLaunch}) => {
const wellknownDisplayProperty = new Display(wellknown);
const vcSelectableButton =
const vcSelectableButton =
selectable &&
(flow === VCItemContainerFlowType.VP_SHARE ? (
<CheckBox
@@ -55,8 +210,8 @@ export const VCCardViewContent: React.FC<VCItemContentProps> = ({isPinned = fals
));
const issuerLogo = verifiableCredentialData.issuerLogo;
const faceImage = verifiableCredentialData.face;
const {start} = useCopilot();
const {t} = useTranslation();
const { start } = useCopilot();
const { t } = useTranslation();
return (
<ImageBackground
@@ -69,12 +224,13 @@ export const VCCardViewContent: React.FC<VCItemContentProps> = ({isPinned = fals
]}>
<View
onLayout={
isInitialLaunch
? () => start(t('copilot:cardTitle'))
: undefined
isInitialLaunch ? () => start(t('copilot:cardTitle')) : undefined
}>
<Row crossAlign="center" padding="3 0 0 3">
<VcItemContainerProfileImage isPinned={isPinned} verifiableCredentialData={verifiableCredentialData} />
<VcItemContainerProfileImage
isPinned={isPinned}
verifiableCredentialData={verifiableCredentialData}
/>
<Column fill align={'space-around'} margin="0 10 0 10">
<VCItemFieldValue
key={'credentialType'}
@@ -106,7 +262,7 @@ export const VCCardViewContent: React.FC<VCItemContentProps> = ({isPinned = fals
<>
{!verifiableCredentialData?.vcMetadata.isExpired &&
(!walletBindingResponse &&
isActivationNeeded(verifiableCredentialData?.issuer)
isActivationNeeded(verifiableCredentialData?.issuer)
? SvgImage.walletUnActivatedIcon()
: SvgImage.walletActivatedIcon())}
<Pressable
@@ -129,7 +285,66 @@ export const VCCardViewContent: React.FC<VCItemContentProps> = ({isPinned = fals
</>
)}
{vcSelectableButton}
{flow === VCItemContainerFlowType.VP_SHARE && (credential?.disclosedKeys?.length > 0) && (
<Pressable onPress={toggleExpand}>
<Icon
name={isExpanded ? 'expand-less' : 'expand-more'}
color={Theme.Colors.Icon}
/>
</Pressable>
)}
</Row>
{/* Expanded section for SD-JWT disclosed keys */}
{flow === VCItemContainerFlowType.VP_SHARE &&
isExpanded &&
credential?.disclosedKeys?.length > 0 && (
<Column padding="8 0">
<View style={{ paddingHorizontal: 6, marginTop: 8 }}>
<View
style={{...Theme.Styles.horizontalSeparator, marginBottom: 12 }}
/>
<Column>
<Text
style={Theme.Styles.disclosureTitle}>
{t('SendVPScreen:selectedFieldsTitle')}
</Text>
<Text
style={Theme.Styles.disclosureSubtitle}>
{t('SendVPScreen:selectedFieldsSubtitle')}
</Text>
</Column>
<Row style={{ marginTop: 12 }} width='100%' align='flex-end'><Pressable onPress={toggleSelectAll}>
<Text
color={Theme.Colors.Icon}
style={Theme.Styles.disclosureSelectButton}>
{areAllSelected()
? t('SendVPScreen:unselectAll')
: t('SendVPScreen:selectAll')}
</Text>
</Pressable>
</Row>
<View
style={{ ...Theme.Styles.horizontalSeparator, marginTop: 12 }}
/>
</View>
{Object.entries(buildDisclosureTree(credential.disclosedKeys)).map(
([name, node]) => (
<DisclosureNode
key={name}
name={name}
node={node}
fullPath={name}
expandedNodes={expandedNodes}
setExpandedNodes={setExpandedNodes}
/>
)
)}
</Column>
)}
<WalletBinding service={service} vcMetadata={vcMetadata} />
@@ -145,6 +360,23 @@ export const VCCardViewContent: React.FC<VCItemContentProps> = ({isPinned = fals
);
};
function buildDisclosureTree(paths: string[]) {
const root: any = {};
paths.forEach(path => {
const parts = path.split(".");
let node = root;
parts.forEach((part, idx) => {
if (!node[part]) node[part] = { __self: false, children: {} };
if (idx === parts.length - 1) {
node[part].__self = true;
}
node = node[part].children;
});
});
return root;
}
export interface VCItemContentProps {
context: any;
credential: Credential;
@@ -165,4 +397,5 @@ export interface VCItemContentProps {
isKebabPopUp: boolean;
vcMetadata: VCMetadata;
isInitialLaunch?: boolean;
onDisclosuresChange?: (disclosures: string[]) => void;
}

View File

@@ -25,9 +25,9 @@ export class VCProcessor {
return parseJSON(decodedString);
}
if(vcFormat === VCFormat.vc_sd_jwt || vcFormat === VCFormat.dc_sd_jwt) {
const { fullResolvedPayload, disclosedKeys, publicKeys } =
const { fullResolvedPayload, disclosedKeys, publicKeys,pathToDisclosures } =
reconstructSdJwtFromCompact(vcData.credential.toString());
return {fullResolvedPayload,disclosedKeys,publicKeys};
return {fullResolvedPayload,disclosedKeys,publicKeys,pathToDisclosures};
}
return getVerifiableCredential(vcData);
}
@@ -61,13 +61,16 @@ export function reconstructSdJwtFromCompact(
sdJwtCompact: string,
): {
fullResolvedPayload: Record<string, any>;
disclosedKeys: Set<string>;
publicKeys: Set<string>;
disclosedKeys: string[];
publicKeys: string[];
pathToDisclosures: Record<string, string[]>; // Mapof{claimPath -> disclosure strings}
} {
const sdJwtPublicKeys = ["iss", "sub", "aud", "exp", "nbf", "iat", "jti"];
const disclosedKeys = new Set<string>();
const publicKeys = new Set<string>();
const digestToDisclosure: Record<string, any[]> = {};
const pathToDisclosures: Record<string, string[]> = {};
const digestToDisclosureB64: Record<string, string> = {};
// Split SD-JWT into parts: [jwt, disclosure1, disclosure2, ...]
const parts = sdJwtCompact.trim().split('~');
@@ -79,17 +82,23 @@ export function reconstructSdJwtFromCompact(
// Parse disclosures
for (const disclosureB64 of disclosures) {
if(disclosureB64.length > 0) {
const decodedB64 = disclosureB64.replace(/-/g, '+').replace(/_/g, '/');
const decoded = JSON.parse(Buffer.from(decodedB64, 'base64').toString('utf-8'));
const digestInput = disclosureB64
const digest = base64url(Buffer.from(hashDigest(sdAlg,digestInput)));
digestToDisclosure[digest] = decoded;
if (disclosureB64.length > 0) {
const decodedB64 = disclosureB64.replace(/-/g, '+').replace(/_/g, '/');
const decoded = JSON.parse(Buffer.from(decodedB64, 'base64').toString('utf-8'));
const digestInput = disclosureB64;
const digest = base64url(Buffer.from(hashDigest(sdAlg, digestInput)));
digestToDisclosure[digest] = decoded;
digestToDisclosureB64[digest] = disclosureB64;
}
}
//Parse the JWT payload
function resolveDisclosures(value: any, path: string = ''): any {
//Parse the JWT payload
function resolveDisclosures(
value: any,
path: string = '',
parentDisclosures: string[] = [],
): any {
if (Array.isArray(value)) {
return value.flatMap((item, index) => {
const currentPath = `${path}[${index}]`;
@@ -105,9 +114,11 @@ export function reconstructSdJwtFromCompact(
return [];
}
disclosedKeys.add(currentPath);
return [resolveDisclosures(disclosure[1], currentPath)];
const currentDisclosures = [...parentDisclosures, digestToDisclosureB64[digest]];
pathToDisclosures[currentPath] = currentDisclosures;
return [resolveDisclosures(disclosure[1], currentPath, currentDisclosures)];
} else {
return [resolveDisclosures(item, currentPath)];
return [resolveDisclosures(item, currentPath, parentDisclosures)];
}
});
}
@@ -126,13 +137,15 @@ export function reconstructSdJwtFromCompact(
if (claimName in value) throw new Error('Overwriting existing key');
const fullPath = path ? `${path}.${claimName}` : claimName;
disclosedKeys.add(fullPath);
result[claimName] = resolveDisclosures(claimValue, fullPath);
const currentDisclosures = [...parentDisclosures, digestToDisclosureB64[digest]];
pathToDisclosures[fullPath] = currentDisclosures;
result[claimName] = resolveDisclosures(claimValue, fullPath, currentDisclosures);
}
for (const [k, v] of Object.entries(value)) {
if (k === '_sd') continue;
const fullPath = path ? `${path}.${k}` : k;
result[k] = resolveDisclosures(v, fullPath);
result[k] = resolveDisclosures(v, fullPath, parentDisclosures);
}
return result;
@@ -143,12 +156,18 @@ export function reconstructSdJwtFromCompact(
// Track public (non-selectively-disclosable) claims
for (const key of Object.keys(payload)) {
if (key !== '_sd' && key !== '_sd_alg' && sdJwtPublicKeys.includes(key)) {
if (key !== '_sd' && key !== '_sd_alg' && sdJwtPublicKeys.includes(key)) {
publicKeys.add(key);
}
}
const fullResolvedPayload = resolveDisclosures(payload);
delete fullResolvedPayload['_sd_alg'];
return { fullResolvedPayload, disclosedKeys, publicKeys };
return {
fullResolvedPayload,
disclosedKeys: Array.from(disclosedKeys),
publicKeys: Array.from(publicKeys),
pathToDisclosures,
};
}

View File

@@ -286,7 +286,7 @@ function getFullAddress(credential: CredentialSubject) {
.filter(Boolean)
.join(', ');
}
const formatKeyLabel = (key: string): string => {
export const formatKeyLabel = (key: string): string => {
return key
.replace(/\[\d+\]/g, '') // Remove [0], [1], etc.
.replace(/([a-z])([A-Z])/g, '$1 $2') // camelCase → spaced
@@ -303,7 +303,7 @@ const renderFieldRecursively = (
parentKey = '',
depth = 0,
renderedFields: Set<string>,
disclosedKeys: Set<string> = new Set(),
disclosedKeys: string[],
): JSX.Element[] => {
const fullKey = parentKey ? `${parentKey}.${key}` : key;
let shortKey =
@@ -320,12 +320,12 @@ const renderFieldRecursively = (
if (Array.isArray(value)) {
const label = formatKeyLabel(key);
const arrayFullKey = fullKey;
const isArrayDisclosed = disclosedKeys.has(arrayFullKey);
const isArrayDisclosed = disclosedKeys.includes(arrayFullKey);
return value.flatMap((item, index) => {
const itemKey = `${key}[${index}]`;
const itemFullKey = parentKey ? `${parentKey}.${itemKey}` : itemKey;
const isItemDisclosed = disclosedKeys.has(itemFullKey);
const isItemDisclosed = disclosedKeys.includes(itemFullKey);
const showDisclosureIcon = isArrayDisclosed || isItemDisclosed;
return [
@@ -436,7 +436,7 @@ const renderFieldRecursively = (
shortKey = publicKeyLabelMap[shortKey];
}
const label = formatKeyLabel(shortKey);
const isDisclosed = disclosedKeys.has(fullKey);
const isDisclosed = disclosedKeys.includes(fullKey);
return [
<Row
key={`extra-${fullKey}`}
@@ -471,7 +471,7 @@ export const fieldItemIterator = (
): JSX.Element[] => {
const fieldNameColor = display.getTextColor(Theme.Colors.DetailsLabel);
const fieldValueColor = display.getTextColor(Theme.Colors.Details);
const disclosedKeys = verifiableCredential.disclosedKeys || new Set<string>();
const disclosedKeys = verifiableCredential.disclosedKeys || [];
const renderedFields = new Set<string>();
const renderedMainFields = fields.map(field => {
@@ -501,7 +501,7 @@ export const fieldItemIterator = (
return null;
}
const isDisclosed = disclosedKeys.has(field);
const isDisclosed = disclosedKeys.includes(field);
return (
<Row
key={field}

View File

@@ -769,6 +769,24 @@ export const DefaultTheme = {
flex: 1,
justifyContent: 'space-around',
},
horizontalSeparator:{
height: 1,
backgroundColor: '#DADADA',
},
disclosureTitle:{
fontFamily: 'Inter_700Bold',
fontSize: 15,
color: Colors.Black,
},
disclosureSubtitle:{
fontSize: 13,
color: '#747474',
marginTop: 4,
},
disclosureSelectButton:{
fontSize: 14,
fontFamily: 'Inter_700Bold',
}
}),
BannerStyles: StyleSheet.create({
container: {
@@ -1173,6 +1191,21 @@ export const DefaultTheme = {
borderColor: Colors.Orange,
borderRadius: 30,
},
sharedSuccessfullyVerifierInfo:{
alignSelf: 'center',
backgroundColor: '#F5F5F5',
borderRadius: 16,
paddingVertical: 12,
paddingHorizontal: 16,
flexDirection: 'row',
justifyContent: 'center',
},
sharedSuccessfullyVerifierLogo: {
width: 40,
height: 40,
borderRadius: 8,
marginRight: 12,
}
}),
AppMetaDataStyles: StyleSheet.create({
buttonContainer: {

View File

@@ -777,6 +777,25 @@ export const PurpleTheme = {
flex: 1,
justifyContent: 'space-around',
},
horizontalSeparator:{
height: 1,
backgroundColor: '#DADADA',
marginBottom: 12,
},
disclosureTitle:{
fontFamily: 'Inter_700Bold',
fontSize: 15,
color: Colors.Black,
},
disclosureSubtitle:{
fontSize: 13,
color: '#747474',
marginTop: 4,
},
disclosureSelectButton:{
fontSize: 14,
fontFamily: 'Inter_700Bold',
}
}),
BannerStyles: StyleSheet.create({
container: {
@@ -1178,6 +1197,21 @@ export const PurpleTheme = {
borderColor: Colors.Purple,
borderRadius: 30,
},
sharedSuccessfullyVerifierInfo:{
alignSelf: 'center',
backgroundColor: '#F5F5F5',
borderRadius: 16,
paddingVertical: 12,
paddingHorizontal: 16,
flexDirection: 'row',
justifyContent: 'center',
},
sharedSuccessfullyVerifierLogo: {
width: 40,
height: 40,
borderRadius: 8,
marginRight: 12,
}
}),
AppMetaDataStyles: StyleSheet.create({
buttonContainer: {

View File

@@ -881,7 +881,7 @@
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/mosip/inji-vci-client-ios-swift";
requirement = {
branch = "release-0.5.x";
branch = develop;
kind = branch;
};
};

View File

@@ -70,7 +70,7 @@
"location" : "https://github.com/mosip/inji-openid4vp-ios-swift.git",
"state" : {
"branch" : "develop",
"revision" : "ca4935478360f45dd20444eac5d6bae9affc6d36"
"revision" : "93d9cda26cf863888814813b63e1aa8250045a9e"
}
},
{
@@ -87,8 +87,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/mosip/inji-vci-client-ios-swift",
"state" : {
"branch" : "release-0.5.x",
"revision" : "839f5825dcfd6278da4983e5c56a858f6b51e9d4"
"branch" : "develop",
"revision" : "c64213b4598f65f887acc1b7a309d3cb1e895129"
}
},
{

View File

@@ -73,6 +73,10 @@ class RNOpenId4VpModule: NSObject, RCTBridgeModule {
result[.ldp_vc] = credentialsArray.map { AnyCodable($0) }
case .mso_mdoc:
result[.mso_mdoc] = credentialsArray.map { AnyCodable($0) }
case .dc_sd_jwt:
result[.dc_sd_jwt] = credentialsArray.map { AnyCodable($0) }
case .vc_sd_jwt:
result[.vc_sd_jwt] = credentialsArray.map { AnyCodable($0) }
default:
break
}
@@ -136,6 +140,19 @@ class RNOpenId4VpModule: NSObject, RCTBridgeModule {
docTypeToDeviceAuthentication[docType] = DeviceAuthentication(signature: signature, algorithm: algorithm)
}
formattedVPTokenSigningResults[.mso_mdoc] = MdocVPTokenSigningResult(docTypeToDeviceAuthentication: docTypeToDeviceAuthentication)
case FormatType.vc_sd_jwt.rawValue :
guard let vpResponse = vpTokenSigningResult as? [String:String] else {
reject("OPENID4VP", "Invalid VP token signing result format", nil)
return
}
formattedVPTokenSigningResults[.vc_sd_jwt] = SdJwtVpTokenSigningResult(uuidToKbJWTSignature: vpResponse)
case FormatType.dc_sd_jwt.rawValue :
guard let vpResponse = vpTokenSigningResult as? [String:String] else {
reject("OPENID4VP", "Invalid VP token signing result format", nil)
return
}
formattedVPTokenSigningResults[.dc_sd_jwt] = SdJwtVpTokenSigningResult(uuidToKbJWTSignature: vpResponse)
default:
let error = NSError(domain: "Credential format '\(credentialFormat)' is not supported", code: 0)
@@ -241,18 +258,20 @@ func getWalletMetadataFromDict(_ walletMetadata: Any,
}
var vpFormatsSupported: [VPFormatType: VPFormatSupported] = [:]
if let vpFormatsSupportedDict = metadata["vp_formats_supported"] as? [String: Any],
let ldpVcDict = vpFormatsSupportedDict["ldp_vc"] as? [String: Any] {
let algValuesSupported = ldpVcDict["alg_values_supported"] as? [String]
vpFormatsSupported[.ldp_vc] = VPFormatSupported(algValuesSupported: algValuesSupported)
if let mdocDict = vpFormatsSupportedDict["mso_mdoc"] as? [String: Any] {
let mdocAlgValuesSupported = mdocDict["alg_values_supported"] as? [String]
vpFormatsSupported[.mso_mdoc] = VPFormatSupported(algValuesSupported: mdocAlgValuesSupported)
if let vpFormatsSupportedDict = metadata["vp_formats_supported"] as? [String: Any] {
for (format, formatDict) in vpFormatsSupportedDict {
guard let formatType = VPFormatType.fromValue(format) else {
throw NSError(domain: "", code: -1, userInfo: [NSLocalizedDescriptionKey: "Unsupported VP format: \(format)"])
}
if let formatDetails = formatDict as? [String: Any] {
let algValuesSupported = formatDetails["alg_values_supported"] as? [String]
vpFormatsSupported[formatType] = VPFormatSupported(algValuesSupported: algValuesSupported)
} else {
vpFormatsSupported[formatType] = VPFormatSupported(algValuesSupported: nil)
}
}
} else {
vpFormatsSupported[.ldp_vc] = VPFormatSupported(algValuesSupported: nil)
}
let walletMetadataObject = try WalletMetadata(
presentationDefinitionURISupported: metadata["presentation_definition_uri_supported"] as? Bool ?? true,
vpFormatsSupported: vpFormatsSupported,

View File

@@ -687,7 +687,7 @@
"ScanScreen": {
"shareWithSelfie": "شارك مع صورة شخصية",
"shareWithSelfieQrLogin": "ريال قطري رمز الدخول",
"shareWithSelfieMessage": "لمشاركة بيانات الاعتماد التي يمكن التحقق منها، سنتحقق من هويتك بشكل آمن باستخدام التحقق من الوجه. من خلال المتابعة، فإنك توافق على استخدام INJI للكاميرا الخاصة بك لهذا الغرض. \n\n سيتم استخدام بيانات وجهك فقط للتحقق ولن تتم مشاركتها مع أي طرف ثالث.",
"shareWithSelfieMessage": "لمشاركة بيانات الاعتماد القابلة للتحقق، سنقوم بالتحقق من هويتك باستخدام التعرف على الوجه. من خلال المتابعة، فإنك توافق على استخدام Inji Wallet لكاميرا هاتفك لهذا الغرض. سيتم استخدام بيانات وجهك فقط للمصادقة ولن يتم تخزينها أو مشاركتها مع أي طرف ثالث.",
"shareWithSelfieMessageQrLogin": "من أجل الوصول إلى البوابة، ستحتاج إلى مشاركة بيانات الاعتماد التي يمكن التحقق منها والتحقق من هويتك بشكل آمن باستخدام التحقق من الوجه. من خلال المتابعة، فإنك توافق على استخدام Inji للكاميرا الخاصة بك لهذا الغرض. \n\n سيتم استخدام بيانات وجهك فقط للتحقق ولن تتم مشاركتها. بعد التحقق بنجاح، يمكنك اختيار التفاصيل التي تريد مشاركتها.",
"ConfirmButton": "أفهم",
"doNotAskMessage": "لا تسألني مرة أخرى",
@@ -699,6 +699,7 @@
"scanningGuide": "أمسك الهاتف بثبات وامسح رمز الاستجابة السريعة ضوئيًا لمشاركة بطاقتك.",
"invalidQR": "يرجى مسح QR صالح",
"sharingVc": "مشاركة بطاقة ",
"unknownVerifier": "مُحقق غير معروف",
"errors": {
"locationDisabled": {
"message": "للمتابعة، اسمح لجهازك بتشغيل الموقع",
@@ -859,6 +860,10 @@
"cardSelected": "card selected",
"unCheck": "البطاقة مختارة",
"checkAll": "تحقق من الكل",
"selectedFieldsTitle": "المعلومات التي تختار مشاركتها",
"selectedFieldsSubtitle": "تتضمن بطاقتك التفاصيل التالية التي يمكن مشاركتها بشكل اختياري.",
"unselectAll": "إلغاء تحديد الكل",
"selectAll": "تحديد الكل",
"consentDialog": {
"title": "الموافقة مطلوبة",
"message": "نحن نطلب موافقتك على مشاركة بيانات اعتمادك التي يمكن التحقق منها مع {{verifierName}}. وهذا سيمكننا من التحقق من هويتك وتلبية طلبات الخدمة الخاصة بك. اختر \"نعم، متابعة\" للموافقة أو \"رفض\" إذا كنت لا ترغب في مشاركة بيانات الاعتماد الخاصة بك مع {{verifierName}}.",
@@ -1108,12 +1113,19 @@
},
"trustScreen": {
"description": "تأكد من أنك تعرف أو تثق بهذا المصدر. بمجرد أن تثق بهذا المصدر:",
"verifierDescription": "تأكد من أنك تعرف هذا المُحقق أو تثق به. بمجرد القيام بذلك:",
"infoPoints": [
"سيتم حفظ البطاقة بأمان في محفظتك.",
"سيتم إضافة هذا المصدر إلى قائمتك الموثوقة.",
"لن تحتاج إلى مراجعة الثقة مرة أخرى عند التحميل منهم في المرة القادمة."
],
"verifierInfoPoints": [
"سيتم مشاركة البطاقة بأمان مع المُحقق.",
"سيُضاف المُحقق إلى قائمتك الموثوقة.",
"لن تحتاج إلى مراجعة الثقة مرة أخرى عند المشاركة معهم لاحقًا."
],
"confirm": "نعم، أنا أثق بهذا المصدر",
"verifierConfirm": "نعم، أُوثق بهذا المُحقق",
"cancel": "لا، أعدني إلى الخلف"
}
}

View File

@@ -695,7 +695,7 @@
"ScanScreen": {
"shareWithSelfie": "Share with Selfie",
"shareWithSelfieQrLogin": "QR Code Login",
"shareWithSelfieMessage": "To share your Verifiable Credentials, well securely verify your identity using face verification. By continuing, you consent to INJI using your camera for this purpose. \n\n Your facial data will only be used for verification and will not be shared with any third parties.",
"shareWithSelfieMessage": "To share your Verifiable Credentials, well verify your identity using face authentication. By continuing, you consent to Inji Wallet using your phone camera for this purpose. Your facial data will be used only for authentication and will not be stored or shared with any third parties.",
"shareWithSelfieMessageQrLogin": "In order to access the portal, youll need to share your Verifiable Credentials and verify your identity securely using face verification. By continuing, you consent to Inji using your camera for this purpose. \n\n Your facial data will only be used for verification and will not be shared. After successful verification, you can choose which details to share.",
"ConfirmButton": "I Understand",
"doNotAskMessage": "Don't ask me again",
@@ -707,6 +707,7 @@
"enableBluetoothButtonText": "Allow bluetooth permissions",
"scanningGuide": "Hold the phone steady and scan the QR code to share your card.",
"invalidQR": "Please scan a valid QR",
"unknownVerifier": "Unknown verifier",
"errors": {
"locationDisabled": {
"message": "To continue, let your device turn on location",
@@ -871,6 +872,10 @@
"cardSelected": "card selected",
"unCheck": "Uncheck",
"checkAll": "Check All",
"selectedFieldsTitle":"Information you choose to share",
"selectedFieldsSubtitle":"Your card includes the following selectively shareable details listed below.",
"unselectAll":"Unselect All",
"selectAll":"Select All",
"consentDialog": {
"title": "Consent Required",
"message": "We require your consent to share your verifiable credentials with {{verifierName}}. This will enable us to verify your identity and fulfil your service requests. Choose \"Yes, Proceed\" to consent or \"Decline\" if you do not wish to share your credentials with {{verifierName}}.",
@@ -1128,12 +1133,19 @@
},
"trustScreen": {
"description": "Make sure you recognize or trust this issuer. Once you trust this issuer:",
"verifierDescription": "Make sure you recognize or trust this verifier. Once you do:",
"infoPoints": [
"The card will be securely saved in your wallet.",
"This issuer will be added to your trusted list.",
"You won't need to review trust again when downloading from them next time."
],
"verifierInfoPoints":[
"The card will be securely shared with the verifier.",
"The verifier will be added to your trusted list.",
"You wont need to review trust again when sharing with them in the future."
],
"confirm": "Yes, I Trust This Issuer",
"verifierConfirm": "Yes, I Trust This Verifier",
"cancel": "No, Take Me Back"
}
}

View File

@@ -690,7 +690,7 @@
"ScanScreen": {
"shareWithSelfie": "Ibahagi sa Selfie",
"shareWithSelfieQrLogin": "Pag-login sa QR Code",
"shareWithSelfieMessage": "Para ibahagi ang iyong Mga Nabe-verify na Kredensyal, secure naming ive-verify ang iyong pagkakakilanlan gamit ang pag-verify sa mukha. Sa pagpapatuloy, pumapayag ka sa INJI na gamitin ang iyong camera para sa layuning ito. \n\n Gagamitin lang ang iyong facial data para sa pag-verify at hindi ibabahagi sa anumang third party.",
"shareWithSelfieMessage": "Para maibahagi ang iyong Verifiable Credentials, susuriin muna namin ang iyong pagkakakilanlan gamit ang facial authentication. Sa pagpapatuloy, sumasang-ayon ka na gamitin ng Inji Wallet ang camera ng iyong telepono para sa layuning ito. Ang iyong facial data ay gagamitin lamang para sa authentication at hindi ito itatago o ibabahagi sa kahit anong third party.",
"shareWithSelfieMessageQrLogin": "Upang ma-access ang portal, kakailanganin mong ibahagi ang iyong Mga Na-verify na Kredensyal at secure na i-verify ang iyong pagkakakilanlan gamit ang pag-verify sa mukha. Sa pagpapatuloy, pumapayag ka sa Inji na gamitin ang iyong camera para sa layuning ito. \n\n Gagamitin lang ang iyong facial data para sa pag-verify at hindi ibabahagi. Pagkatapos ng matagumpay na pag-verify, maaari mong piliin kung aling mga detalye ang ibabahagi.",
"ConfirmButton": "Naiintindihan ko",
"doNotAskMessage": "Huwag mo na akong tanungin",
@@ -702,6 +702,7 @@
"enableBluetoothButtonText": "Payagan ang mga pahintulot ng bluetooth",
"scanningGuide": "Panatilihin ang telepono at i-scan ang QR code upang ibahagi ang iyong card.",
"invalidQR": "Mangyaring mag-scan ng wastong QR",
"unknownVerifier": "Hindi kilalang verifier",
"errors": {
"locationDisabled": {
"message": "Para magpatuloy, hayaang i-on ng iyong device ang lokasyon",
@@ -862,6 +863,10 @@
"cardSelected": "card pinili",
"unCheck": "Alisin ang check",
"checkAll": "Suriin Lahat",
"selectedFieldsTitle": "Impormasyon na pinili mong ibahagi",
"selectedFieldsSubtitle": "Ang iyong card ay naglalaman ng mga sumusunod na detalyeng maaaring piliing ibahagi.",
"unselectAll": "Alisin ang lahat ng pagpili",
"selectAll": "Piliin lahat",
"consentDialog": {
"title": "Kinakailangan ang Pahintulot",
"message": "Hinihiling namin ang iyong pahintulot na ibahagi ang iyong mga nabe-verify na kredensyal sa {{verifierName}}. Ito ay magbibigay-daan sa amin na i-verify ang iyong pagkakakilanlan at matupad ang iyong mga kahilingan sa serbisyo. Piliin ang \"Oo, Magpatuloy\" upang pumayag o \"Tanggihan\" kung hindi mo gustong ibahagi ang iyong mga kredensyal sa {{verifierName}}.",
@@ -1111,12 +1116,19 @@
},
"trustScreen": {
"description": "Siguraduhin mong kilala mo o pinagkakatiwalaan mo ang issuer na ito. Kapag pinagkatiwalaan mo sila:",
"verifierDescription": "Tiyaking kilala mo o pinagkakatiwalaan mo ang verifier na ito. Kapag nagtiwala ka na:",
"infoPoints": [
"Ang card ay ligtas na mase-save sa iyong wallet.",
"Ang issuer na ito ay idagdag sa iyong trusted list.",
"Hindi mo na kailangang muling suriin ang tiwala kapag magda-download mula sa kanila sa susunod."
],
"verifierInfoPoints": [
"Ang card ay ligtas na ibabahagi sa verifier.",
"Ang verifier ay idaragdag sa iyong listahan ng pinagkakatiwalaan.",
"Hindi mo na kailangang suriin muli ang tiwala kapag muling nagbahagi sa kanila sa hinaharap."
],
"confirm": "Oo, Pinagkakatiwalaan Ko ang Issuer na Ito",
"verifierConfirm": "Oo, pinagkakatiwalaan ko ang verifier na ito",
"cancel": "Hindi, Ibalik Mo Ako"
}
}

View File

@@ -693,7 +693,7 @@
"ScanScreen": {
"shareWithSelfie": "सेल्फी के साथ साझा करें",
"shareWithSelfieQrLogin": "क्यूआर कोड लॉगिन",
"shareWithSelfieMessage": "आपके सत्यापन योग्य क्रेडेंशियल साझा करने के लिए, हम चेहरे के सत्यापन का उपयोग करके आपकी पहचान को सुरक्षित रूप से सत्यापित करेंगे। जारी रखर, आप इस उद्देश्य के लिए INJI को अपने कैमरे का उपयोग करने की सहमति देते हैं। \n\n आपक चेहरे का डेटा केवल सत्यापन के लिए उपयोग किया जाएगा और किसी तीसरे पक्ष के साथ साझा नहीं किया जाएगा।",
"shareWithSelfieMessage": "अपने वेरिफ़ायबल क्रेडेंशियल्स साझा करने के लिए, हम आपके चेहरे की पहचान के माध्यम से आपकी पहचान सत्यापित करेंगे। जारी रखने पर, आप इस उद्देश्य के लिए Inji Wallet को आपके फ़ोन के कैमरे का उपयोग करने की अनुमति देते हैं। आपक चेहरा डेटा केवल सत्यापन के लिए उपयोग किया जाएगा और किसी भी तीसरे पक्ष के साथ साझा या संग्रहीत नहीं किया जाएगा।",
"shareWithSelfieMessageQrLogin": "Iपोर्टल तक पहुंचने के लिए, आपको अपने सत्यापन योग्य क्रेडेंशियल साझा करने और चेहरे के सत्यापन का उपयोग करके अपनी पहचान को सुरक्षित रूप से सत्यापित करने की आवश्यकता होगी। जारी रखकर, आप इंजी को इस उद्देश्य के लिए अपने कैमरे का उपयोग करने के लिए सहमति देते हैं। \n\n आपके चेहरे का डेटा केवल सत्यापन के लिए उपयोग किया जाएगा और साझा नहीं किया जाएगा। सफल सत्यापन के बाद, आप चुन सकते हैं कि कौन सा विवरण साझा करना है।",
"ConfirmButton": "मैं समझता हूँ",
"doNotAskMessage": "मुझसे दोबारा मत पूछना",
@@ -705,6 +705,7 @@
"enableBluetoothButtonText": "ब्लूटूथ अनुमतियाँ दें",
"scanningGuide": "फ़ोन को स्थिर रखें और अपना कार्ड साझा करने के लिए QR कोड को स्कैन करें।",
"invalidQR": "कृपया एक वैध क्यूआर स्कैन करें",
"unknownVerifier": "अज्ञात सत्यापनकर्ता",
"errors": {
"locationDisabled": {
"message": "जारी रखने के लिए, अपने डिवाइस को स्थान चालू करने दें",
@@ -865,6 +866,10 @@
"cardSelected": "कार्ड चयनित",
"unCheck": "सही का निशान हटाएँ",
"checkAll": "सभी चेक करें",
"selectedFieldsTitle": "आप जो जानकारी साझा करना चाहते हैं",
"selectedFieldsSubtitle": "आपके कार्ड में नीचे दी गई चुनिंदा जानकारी शामिल है जिसे आप साझा कर सकते हैं।",
"unselectAll": "सभी चयन हटाएं",
"selectAll": "सभी का चयन करें",
"consentDialog": {
"title": "सहमति आवश्यक",
"message": "हमें आपके सत्यापन योग्य क्रेडेंशियल्स को {{verifierName}} के साथ साझा करने के लिए आपकी सहमति की आवश्यकता है। इससे हमें आपकी पहचान सत्यापित करने और आपके सेवा अनुरोधों को पूरा करने में मदद मिलेगी। यदि आप {{verifierName}} के साथ अपने क्रेडेंशियल साझा नहीं करना चाहते हैं तो सहमति के लिए \"हां, आगे बढ़ें\" या \"अस्वीकार करें\" चुनें।",
@@ -1112,12 +1117,19 @@
},
"trustScreen": {
"description": "सुनिश्चित करें कि आप इस जारीकर्ता को पहचानते हैं या उस पर भरोसा करते हैं। एक बार जब आप भरोसा कर लेते हैं:",
"verifierDescription": "सुनिश्चित करें कि आप इस सत्यापनकर्ता को पहचानते हैं या उस पर भरोसा करते हैं। एक बार जब आप ऐसा करें:",
"infoPoints": [
"कार्ड सुरक्षित रूप से आपके वॉलेट में सेव हो जाएगा।",
"यह जारीकर्ता आपकी विश्वसनीय सूची में जोड़ दिया जाएगा।",
"अगली बार उनसे डाउनलोड करते समय दोबारा ट्रस्ट की समीक्षा नहीं करनी होगी।"
],
"verifierInfoPoints": [
"कार्ड को सत्यापनकर्ता के साथ सुरक्षित रूप से साझा किया जाएगा।",
"सत्यापनकर्ता को आपकी विश्वसनीय सूची में जोड़ा जाएगा।",
"भविष्य में उनके साथ साझा करते समय दोबारा भरोसा जताने की आवश्यकता नहीं होगी।"
],
"confirm": "हाँ, मैं इस जारीकर्ता पर भरोसा करता हूँ",
"verifierConfirm": "हाँ, मुझे इस सत्यापनकर्ता पर भरोसा है",
"cancel": "नहीं, मुझे वापस ले चलें"
}
}

View File

@@ -691,7 +691,7 @@
"ScanScreen": {
"shareWithSelfie": "ಸೆಲ್ಫಿಯೊಂದಿಗೆ ಹಂಚಿಕೊಳ್ಳಿ",
"shareWithSelfieQrLogin": "QR ಕೋಡ್ ಲಾಗಿನ್",
"shareWithSelfieMessage": "ನಿಮ್ಮ ಪರಿಶೀಲಿಸಬಹುದಾದ ರುಜುವಾತುಗಳನ್ನು ಹಂಚಿಕೊಳ್ಳಲು, ಮುಖ ಪರಿಶೀಲನೆಯನ್ನು ಬಳಸಿಕೊಂಡು ನಿಮ್ಮ ಗುರುತನ್ನು ನಾವು ಸುರಕ್ಷಿತವಾಗಿ ಪರಿಶೀಲಿಸುತ್ತೇವೆ. ಮುಂದುವರಿಸುವ ಮೂಲಕ, ಈ ಉದ್ದೇಶಕ್ಕಾಗಿ ನಿಮ್ಮ ಕ್ಯಾಮರಾವನ್ನು ಬಳಸಲು INJI ಗೆ ನೀವು ಸಮ್ಮತಿಸುತ್ತೀರಿ. \n\n ನಿಮ್ಮ ಮುಖದ ಡೇಟಾವನ್ನು ಪರಿಶೀಲನೆಗಾಗಿ ಮಾತ್ರ ಬಳಸಲಾಗುತ್ತದೆ ಮತ್ತು ಯಾವುದೇ ಮೂರನೇ ವ್ಯಕ್ತಿಗಳೊಂದಿಗೆ ಹಂಚಿಕೊಳ್ಳಲಾಗುವುದಿಲ್ಲ.",
"shareWithSelfieMessage": "ನಿಮ್ಮ ಪರಿಶೀಲಿಸಬಹುದಾದ ಪ್ರಮಾಣಪತ್ರಗಳನ್ನು ಹಂಚಿಕೊಳ್ಳಲು, ಮುಖ ಗುರುತಿಸುವಿಕೆಯಿಂದ ನಿಮ್ಮ ಗುರುತನ್ನು ಪರಿಶೀಲಿಸಲಾಗುತ್ತೆ. ಮುಂದುವರಿದರೆ, ಈ ಉದ್ದೇಶಕ್ಕಾಗಿ ನಿಮ್ಮ ಫೋನ್ ಕ್ಯಾಮರಾವನ್ನು ಬಳಸಲು ನೀವು Inji Wallet ಗೆ ಒಪ್ಪಿಗೆಯುನ್ನಿಸುತ್ತೀರಿ. ನಿಮ್ಮ ಮುಖದ ಡೇಟಾವನ್ನು ಕೇವಲ ಗುರುತಿನ ಪರಿಶೀಲನೆಗಾಗಿ ಬಳಸಲಾಗುತ್ತದೆ ಮತ್ತು ಇದನ್ನು ಸಂಗ್ರಹಿಸಲ್ಲ ಅಥವಾ ಮೂರನೇ ವ್ಯಕ್ತಿಗಳೊಂದಿಗೆ ಹಂಚಿಕೊಳ್ಳಲಾಗುವುದಿಲ್ಲ",
"shareWithSelfieMessageQrLogin": "ಪೋರ್ಟಲ್ ಅನ್ನು ಪ್ರವೇಶಿಸಲು, ನೀವು ನಿಮ್ಮ ಪರಿಶೀಲಿಸಬಹುದಾದ ರುಜುವಾತುಗಳನ್ನು ಹಂಚಿಕೊಳ್ಳಬೇಕು ಮತ್ತು ಮುಖ ಪರಿಶೀಲನೆಯನ್ನು ಬಳಸಿಕೊಂಡು ನಿಮ್ಮ ಗುರುತನ್ನು ಸುರಕ್ಷಿತವಾಗಿ ಪರಿಶೀಲಿಸಬೇಕು. ಮುಂದುವರಿಯುವ ಮೂಲಕ, ಈ ಉದ್ದೇಶಕ್ಕಾಗಿ ನಿಮ್ಮ ಕ್ಯಾಮರಾವನ್ನು ಬಳಸಲು ನೀವು ಇಂಜಿಗೆ ಸಮ್ಮತಿಸುತ್ತೀರಿ. \n\n ನಿಮ್ಮ ಮುಖದ ಡೇಟಾವನ್ನು ಪರಿಶೀಲನೆಗಾಗಿ ಮಾತ್ರ ಬಳಸಲಾಗುತ್ತದೆ ಮತ್ತು ಹಂಚಿಕೊಳ್ಳಲಾಗುವುದಿಲ್ಲ. ಯಶಸ್ವಿ ಪರಿಶೀಲನೆಯ ನಂತರ, ಯಾವ ವಿವರಗಳನ್ನು ಹಂಚಿಕೊಳ್ಳಬೇಕೆಂದು ನೀವು ಆಯ್ಕೆ ಮಾಡಬಹುದು.",
"ConfirmButton": "ನಾನು ಅರ್ಥಮಾಡಿಕೊಂಡಿದ್ದೇನೆ",
"doNotAskMessage": "ಅಂತ ಮತ್ತೆ ಕೇಳಬೇಡ",
@@ -703,6 +703,7 @@
"enableBluetoothButtonText": "ಬ್ಲೂಟೂತ್ ಅನುಮತಿಗಳನ್ನು ಅನುಮತಿಸಿ",
"scanningGuide": "ಫೋನ್ ಅನ್ನು ಸ್ಥಿರವಾಗಿ ಹಿಡಿದುಕೊಳ್ಳಿ ಮತ್ತು ನಿಮ್ಮ ಕಾರ್ಡ್ ಅನ್ನು ಹಂಚಿಕೊಳ್ಳಲು QR ಕೋಡ್ ಅನ್ನು ಸ್ಕ್ಯಾನ್ ಮಾಡಿ.",
"invalidQR": "ದಯವಿಟ್ಟು ಮಾನ್ಯವಾದ QR ಅನ್ನು ಸ್ಕ್ಯಾನ್ ಮಾಡಿ",
"unknownVerifier": "ಅಜ್ಞಾತ ಪರಿಶೀಲಕ",
"errors": {
"locationDisabled": {
"message": "ಮುಂದುವರಿಸಲು, ನಿಮ್ಮ ಸಾಧನವು ಸ್ಥಳವನ್ನು ಆನ್ ಮಾಡಲು ಅನುಮತಿಸಿ",
@@ -863,6 +864,10 @@
"cardSelected": "ಕಾರ್ಡ್ ಆಯ್ಕೆಮಾಡಲಾಗಿದೆ",
"unCheck": "ಅನ್ಚೆಕ್ ಮಾಡಿ",
"checkAll": "ಎಲ್ಲವನ್ನೂ ಪರಿಶೀಲಿಸಿ",
"selectedFieldsTitle": "ನೀವು ಹಂಚಿಕೊಳ್ಳಲು ಆಯ್ದ ಮಾಹಿತಿಗಳು",
"selectedFieldsSubtitle": "ನಿಮ್ಮ ಕಾರ್ಡ್‌ನಲ್ಲಿ ಕೆಳಗೆ ಪಟ್ಟಿಮಾಡಲಾದ ಆಯ್ಕೆಮಾಡಬಹುದಾದ ವಿವರಗಳು ಸೇರಿವೆ.",
"unselectAll": "ಎಲ್ಲವನ್ನು ಅಚ್ಛುನಾಯಿಸಿ",
"selectAll": "ಎಲ್ಲಾ ಆಯ್ಕೆಮಾಡಿ",
"consentDialog": {
"title": "ಒಪ್ಪಿಗೆ ಅಗತ್ಯವಿದೆ",
"message": "ನಿಮ್ಮ ಪರಿಶೀಲಿಸಬಹುದಾದ ರುಜುವಾತುಗಳನ್ನು {{verifierName}} ಜೊತೆಗೆ ಹಂಚಿಕೊಳ್ಳಲು ನಿಮ್ಮ ಸಮ್ಮತಿಯ ಅಗತ್ಯವಿದೆ. ಇದು ನಿಮ್ಮ ಗುರುತನ್ನು ಪರಿಶೀಲಿಸಲು ಮತ್ತು ನಿಮ್ಮ ಸೇವಾ ವಿನಂತಿಗಳನ್ನು ಪೂರೈಸಲು ನಮಗೆ ಅನುವು ಮಾಡಿಕೊಡುತ್ತದೆ. ನಿಮ್ಮ ರುಜುವಾತುಗಳನ್ನು {{verifierName}} ಜೊತೆಗೆ ಹಂಚಿಕೊಳ್ಳಲು ನೀವು ಬಯಸದಿದ್ದರೆ, ಒಪ್ಪಿಗೆ ನೀಡಲು \"ಹೌದು, ಮುಂದುವರಿಯಿರಿ\" ಅಥವಾ \"ನಿರಾಕರಿಸಿ\" ಆಯ್ಕೆಮಾಡಿ.",
@@ -1112,12 +1117,19 @@
},
"trustScreen": {
"description": "ಈ ಹೊರಹೊಮ್ಮಿಸುವವರನ್ನು ನೀವು ಗುರುತಿಸುತ್ತೀರಾ ಅಥವಾ ನಂಬಿದೀರಾ ಎಂಬುದನ್ನು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಿ. ನೀವು ನಂಬಿದ ನಂತರ:",
"verifierDescription": "ಈ ಪರಿಶೀಲಕರನ್ನು ನೀವು ಗುರುತಿಸುತ್ತೀರಿ ಅಥವಾ ನಂಬಿಕೆಯುಳ್ಳವರೆಂದು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಿ. ನೀವು ನಂಬಿದ ಬಳಿಕ:",
"infoPoints": [
"ಕಾರ್ಡ್ ನಿಮ್ಮ ವಾಲೆಟ್‌ನಲ್ಲಿ ಸುರಕ್ಷಿತವಾಗಿ ಉಳಿಸಲಾಗುತ್ತದೆ.",
"ಈ ಹೊರಹೊಮ್ಮಿಸುವವರನ್ನು ನಿಮ್ಮ ನಂಬಲರ್ಹ ಪಟ್ಟಿಗೆ ಸೇರಿಸಲಾಗುತ್ತದೆ.",
"ಮುಂದಿನ ಬಾರಿಯದು ಡೌನ್‌ಲೋಡ್ ಮಾಡುವಾಗ ನಂಬಿಕೆಯನ್ನು ಮರುಪರಿಶೀಲಿಸುವ ಅಗತ್ಯವಿಲ್ಲ."
],
"verifierInfoPoints": [
"ಕಾರ್ಡ್ ಅನ್ನು ಪರಿಶೀಲಕರೊಂದಿಗೆ ಸುರಕ್ಷಿತವಾಗಿ ಹಂಚಲಾಗುತ್ತದೆ.",
"ಪರಿಶೀಲಕರನ್ನು ನಿಮ್ಮ ನಂಬಿಗಸ್ತರ ಪಟ್ಟಿಗೆ ಸೇರಿಸಲಾಗುತ್ತದೆ.",
"ಭವಿಷ್ಯದಲ್ಲಿ ಅವರೊಂದಿಗೆ ಹಂಚಿಕೊಳ್ಳುವಾಗ ಮತ್ತೊಮ್ಮೆ ನಂಬಿಕೆಯನ್ನು ಪರಿಶೀಲಿಸುವ ಅಗತ್ಯವಿಲ್ಲ."
],
"confirm": "ಹೌದು, ನಾನು ಈ ಹೊರಹೊಮ್ಮಿಸುವವರನ್ನು ನಂಬುತ್ತೇನೆ",
"verifierConfirm": "ಹೌದು, ನಾನು ಈ ಪರಿಶೀಲಕರ ಮೇಲೆ ನಂಬಿಕೆ ಇಡುತ್ತೇನೆ",
"cancel": "ಇಲ್ಲ, ನನನ್ನು ಹಿಂಪಡೆ"
}
}

View File

@@ -118,7 +118,6 @@
"disclosedFieldsDescription": "உங்கள் அட்டையில் கீழே பட்டியலிடப்பட்டுள்ள தெரிவுசெய்து பகிரக்கூடிய விவரங்கள் உள்ளன.",
"disclosedFieldsTitle": "நீங்கள் பகிர தேர்வு செய்த தகவல்",
"disclosureInfoNote": "இந்த சின்னத்திற்கு அருகிலுள்ள புலங்கள் தேர்ந்தெடுத்து பகிரக்கூடிய தகவல்களை示ிக்கின்றன."
},
"HomeScreenKebabPopUp": {
"title": "மேலும் விருப்பங்கள்",
@@ -692,7 +691,7 @@
"ScanScreen": {
"shareWithSelfie": "செல்ஃபியுடன் பகிரவும்",
"shareWithSelfieQrLogin": "QR குறியீடு உள்நுழைவு",
"shareWithSelfieMessage": "உங்களின் சரிபார்க்கக்கூடிய நற்சான்றிதழ்களைப் பகிர, முகச் சரிபார்ப்பைப் பயன்படுத்தி உங்கள் அடையாளத்தைப் பாதுகாப்பாகச் சரிபார்ப்போம். தொடரவதன் மூலம், இந்த நோக்கத்திற்காக உங்கள் கேமராவைப் பயன்படுத்த INJIஐ ஒப்புக்கொள்கிறீர்கள். \n\n உங்கள் முகத் தரவு சரிபார்ப்புக்க மட்டுமே பயன்படுத்தப்படும் மற்றும் எந்த மூன்றாம் தரப்பினருடனும் பகிரப்படாது.",
"shareWithSelfieMessage": "உங்கள் சரிபார்க்கக்கூடிய சான்றகளைப் பகிர்வதற்காக, முக அடையாளப் புரிதலைப் பயன்படுத்தி உங்கள் அடையாளத்தை நாங்கள் சரிபார்ப்போம். தொடரவதன் மூலம், இந்த நோக்கத்திற்காக உங்கள் தொலைபேசி கேமராவை பயன்படுத்த Inji Wallet-க்கு நீங்கள் ஒப்புதல் அளிக்கிறீர்கள். உங்கள் முகத் தரவு சரிபிகேஷனுக்காக மட்டுமே பயன்படுத்தப்படும்; இது சேமிக்கப்படாது அல்லது மூன்றாம் தரப்பினருடன் பகிரப்படாது.",
"shareWithSelfieMessageQrLogin": "போர்ட்டலை அணுக, உங்கள் சரிபார்க்கக்கூடிய சான்றுகளைப் பகிர வேண்டும் மற்றும் முகச் சரிபார்ப்பைப் பயன்படுத்தி உங்கள் அடையாளத்தைப் பாதுகாப்பாகச் சரிபார்க்க வேண்டும். தொடர்வதன் மூலம், இந்த நோக்கத்திற்காக உங்கள் கேமராவைப் பயன்படுத்துவதற்கு இன்ஜி ஒப்புக்கொள்கிறீர்கள். \n\n உங்கள் முகத் தரவு சரிபார்ப்புக்கு மட்டுமே பயன்படுத்தப்படும் மற்றும் பகிரப்படாது. வெற்றிகரமான சரிபார்ப்புக்குப் பிறகு, எந்த விவரங்களைப் பகிர வேண்டும் என்பதை நீங்கள் தேர்வு செய்யலாம்.",
"ConfirmButton": "எனக்கு புரிகிறது",
"doNotAskMessage": "மீண்டும் என்னிடம் கேட்காதே",
@@ -704,6 +703,7 @@
"enableBluetoothButtonText": "புளூடூத் அனுமதிகளை அனுமதிக்கவும்",
"scanningGuide": "உங்கள் கார்டைப் பகிர, மொபைலை நிலையாகப் பிடித்து, QR குறியீட்டை ஸ்கேன் செய்யவும்.",
"invalidQR": "ದಯವಿಟ್ಟು ಮಾನ್ಯವಾದ QR ಅನ್ನು ಸ್ಕ್ಯಾನ್ ಮಾಡಿ",
"unknownVerifier": "அறியப்படாத சரிபார்ப்பாளர்",
"errors": {
"locationDisabled": {
"message": "தொடர, இருப்பிடத்தை இயக்க உங்கள் சாதனத்தை அனுமதிக்கவும்",
@@ -864,6 +864,10 @@
"cardSelected": "அட்டை தேர்ந்தெடுக்கப்பட்டது",
"unCheck": "தேர்வுநீக்கவும்",
"checkAll": "அனைத்தையும் சரிபார்க்கவும்",
"selectedFieldsTitle": "நீங்கள் பகிர தேர்ந்த தகவல்கள்",
"selectedFieldsSubtitle": "உங்கள் அட்டையில் கீழே பட்டியலிடப்பட்ட தேர்ந்தெடுக்கக்கூடிய தகவல்கள் அடங்கும்.",
"unselectAll": "அனைத்தையும் தேர்வு நீக்கு",
"selectAll": "அனைத்தையும் தேர்வு செய்",
"consentDialog": {
"title": "ஒப்புதல் தேவை",
"message": "உங்கள் சரிபார்க்கக்கூடிய நற்சான்றிதழ்களை {{verifierName}} உடன் பகிர உங்கள் ஒப்புதல் தேவை. இது உங்கள் அடையாளத்தைச் சரிபார்க்கவும் உங்கள் சேவை கோரிக்கைகளை நிறைவேற்றவும் எங்களுக்கு உதவும். ஒப்புதல் அளிக்க \"ஆம், தொடரவும்\" என்பதைத் தேர்வு செய்யவும் அல்லது {{verifierName}} உடன் உங்கள் சான்றுகளைப் பகிர விரும்பவில்லை எனில் \"நிராகரி\" என்பதைத் தேர்ந்தெடுக்கவும்.",
@@ -1113,12 +1117,19 @@
},
"trustScreen": {
"description": "இந்த வெளியீட்டாளரை நீங்கள் அறிந்தவரா அல்லது நம்புகிறீர்களா என்பதை உறுதி செய்யவும். நீங்கள் வெளியீட்டாளரை நம்பினால்:",
"verifierDescription": "இந்த சரிபார்ப்பாளரை நீங்கள் அறிந்தவராகவோ நம்பத்தக்கவராகவோ இருக்க வேண்டும் என்பதை உறுதிசெய்க. ஒரு முறை நீங்கள் நம்பிக்கை வைத்த பிறகு:",
"infoPoints": [
"அட்டை பாதுகாப்பாக உங்கள் வாலட்டில் சேமிக்கப்படும்.",
"இந்த வெளியீட்டாளர் உங்கள் நம்பகமான பட்டியலில் சேர்க்கப்படுவார்.",
"அவர்களிடமிருந்து அடுத்தமுறை பதிவிறக்கும் போது மீண்டும் நம்பிக்கை சரிபார்க்க வேண்டியதில்லை."
],
"verifierInfoPoints": [
"கார்ட் இந்த சரிபார்ப்பாளருடன் பாதுகாப்பாக பகிரப்படும்.",
"இந்த சரிபார்ப்பாளர் உங்கள் நம்பகப்பட்ட பட்டியலில் சேர்க்கப்படுவார்.",
"எதிர்காலத்தில் அவருடன் பகிரும்போது மீண்டும் நம்பிக்கையை மதிப்பாய்வு செய்ய வேண்டியதில்லை."
],
"confirm": "ஆம், இந்த வெளியீட்டாளரை நம்புகிறேன்",
"verifierConfirm": "ஆம், இந்த சரிபார்ப்பாளரை நம்புகிறேன்",
"cancel": "இல்லை, எனை மீண்டும் கொண்டு செல்"
}
}

View File

@@ -0,0 +1,182 @@
// This file was automatically generated. Edits will be overwritten
export interface Typegen0 {
'@@xstate/typegen': true;
internalEvents: {
"done.invoke.issuersMachine.cachingCredentialOfferIssuerWellknown:invocation[0]": { type: "done.invoke.issuersMachine.cachingCredentialOfferIssuerWellknown:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." };
"done.invoke.issuersMachine.credentialDownloadFromOffer.checkingIssuerTrust:invocation[0]": { type: "done.invoke.issuersMachine.credentialDownloadFromOffer.checkingIssuerTrust:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." };
"done.invoke.issuersMachine.credentialDownloadFromOffer.keyManagement.generateKeyPair:invocation[0]": { type: "done.invoke.issuersMachine.credentialDownloadFromOffer.keyManagement.generateKeyPair:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." };
"done.invoke.issuersMachine.credentialDownloadFromOffer.keyManagement.getKeyPairFromKeystore:invocation[0]": { type: "done.invoke.issuersMachine.credentialDownloadFromOffer.keyManagement.getKeyPairFromKeystore:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." };
"done.invoke.issuersMachine.credentialDownloadFromOffer.keyManagement.setSelectedKey:invocation[0]": { type: "done.invoke.issuersMachine.credentialDownloadFromOffer.keyManagement.setSelectedKey:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." };
"done.invoke.issuersMachine.credentialDownloadFromOffer.sendConsentGiven.updatingTrustedIssuerList:invocation[0]": { type: "done.invoke.issuersMachine.credentialDownloadFromOffer.sendConsentGiven.updatingTrustedIssuerList:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." };
"done.invoke.issuersMachine.credentialDownloadFromOffer.sendConsentGiven:invocation[0]": { type: "done.invoke.issuersMachine.credentialDownloadFromOffer.sendConsentGiven:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." };
"done.invoke.issuersMachine.credentialDownloadFromOffer.tokenRequest:invocation[0]": { type: "done.invoke.issuersMachine.credentialDownloadFromOffer.tokenRequest:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." };
"done.invoke.issuersMachine.credentialDownloadFromOffer:invocation[0]": { type: "done.invoke.issuersMachine.credentialDownloadFromOffer:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." };
"done.invoke.issuersMachine.displayIssuers:invocation[0]": { type: "done.invoke.issuersMachine.displayIssuers:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." };
"done.invoke.issuersMachine.downloadCredentials.keyManagement.generateKeyPair:invocation[0]": { type: "done.invoke.issuersMachine.downloadCredentials.keyManagement.generateKeyPair:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." };
"done.invoke.issuersMachine.downloadCredentials.keyManagement.getKeyPairFromKeystore:invocation[0]": { type: "done.invoke.issuersMachine.downloadCredentials.keyManagement.getKeyPairFromKeystore:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." };
"done.invoke.issuersMachine.downloadCredentials.keyManagement.setSelectedKey:invocation[0]": { type: "done.invoke.issuersMachine.downloadCredentials.keyManagement.setSelectedKey:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." };
"done.invoke.issuersMachine.downloadCredentials.tokenRequest:invocation[0]": { type: "done.invoke.issuersMachine.downloadCredentials.tokenRequest:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." };
"done.invoke.issuersMachine.downloadCredentials:invocation[0]": { type: "done.invoke.issuersMachine.downloadCredentials:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." };
"done.invoke.issuersMachine.downloadIssuerWellknown:invocation[0]": { type: "done.invoke.issuersMachine.downloadIssuerWellknown:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." };
"done.invoke.issuersMachine.getCredentialTypes:invocation[0]": { type: "done.invoke.issuersMachine.getCredentialTypes:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." };
"done.invoke.issuersMachine.proccessingCredential:invocation[0]": { type: "done.invoke.issuersMachine.proccessingCredential:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." };
"done.invoke.issuersMachine.storing:invocation[0]": { type: "done.invoke.issuersMachine.storing:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." };
"done.invoke.issuersMachine.verifyingCredential:invocation[0]": { type: "done.invoke.issuersMachine.verifyingCredential:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." };
"error.platform.issuersMachine.cachingCredentialOfferIssuerWellknown:invocation[0]": { type: "error.platform.issuersMachine.cachingCredentialOfferIssuerWellknown:invocation[0]"; data: unknown };
"error.platform.issuersMachine.credentialDownloadFromOffer.keyManagement.constructProof:invocation[0]": { type: "error.platform.issuersMachine.credentialDownloadFromOffer.keyManagement.constructProof:invocation[0]"; data: unknown };
"error.platform.issuersMachine.credentialDownloadFromOffer.keyManagement.getKeyPairFromKeystore:invocation[0]": { type: "error.platform.issuersMachine.credentialDownloadFromOffer.keyManagement.getKeyPairFromKeystore:invocation[0]"; data: unknown };
"error.platform.issuersMachine.credentialDownloadFromOffer.keyManagement.setSelectedKey:invocation[0]": { type: "error.platform.issuersMachine.credentialDownloadFromOffer.keyManagement.setSelectedKey:invocation[0]"; data: unknown };
"error.platform.issuersMachine.credentialDownloadFromOffer.sendConsentGiven.updatingTrustedIssuerList:invocation[0]": { type: "error.platform.issuersMachine.credentialDownloadFromOffer.sendConsentGiven.updatingTrustedIssuerList:invocation[0]"; data: unknown };
"error.platform.issuersMachine.credentialDownloadFromOffer.sendConsentGiven:invocation[0]": { type: "error.platform.issuersMachine.credentialDownloadFromOffer.sendConsentGiven:invocation[0]"; data: unknown };
"error.platform.issuersMachine.credentialDownloadFromOffer.sendTokenResponse:invocation[0]": { type: "error.platform.issuersMachine.credentialDownloadFromOffer.sendTokenResponse:invocation[0]"; data: unknown };
"error.platform.issuersMachine.credentialDownloadFromOffer.sendTxCode:invocation[0]": { type: "error.platform.issuersMachine.credentialDownloadFromOffer.sendTxCode:invocation[0]"; data: unknown };
"error.platform.issuersMachine.credentialDownloadFromOffer.tokenRequest:invocation[0]": { type: "error.platform.issuersMachine.credentialDownloadFromOffer.tokenRequest:invocation[0]"; data: unknown };
"error.platform.issuersMachine.credentialDownloadFromOffer:invocation[0]": { type: "error.platform.issuersMachine.credentialDownloadFromOffer:invocation[0]"; data: unknown };
"error.platform.issuersMachine.displayIssuers:invocation[0]": { type: "error.platform.issuersMachine.displayIssuers:invocation[0]"; data: unknown };
"error.platform.issuersMachine.downloadCredentials.constructProof:invocation[0]": { type: "error.platform.issuersMachine.downloadCredentials.constructProof:invocation[0]"; data: unknown };
"error.platform.issuersMachine.downloadCredentials.keyManagement.generateKeyPair:invocation[0]": { type: "error.platform.issuersMachine.downloadCredentials.keyManagement.generateKeyPair:invocation[0]"; data: unknown };
"error.platform.issuersMachine.downloadCredentials.keyManagement.getKeyPairFromKeystore:invocation[0]": { type: "error.platform.issuersMachine.downloadCredentials.keyManagement.getKeyPairFromKeystore:invocation[0]"; data: unknown };
"error.platform.issuersMachine.downloadCredentials.keyManagement.setSelectedKey:invocation[0]": { type: "error.platform.issuersMachine.downloadCredentials.keyManagement.setSelectedKey:invocation[0]"; data: unknown };
"error.platform.issuersMachine.downloadCredentials.sendTokenResponse:invocation[0]": { type: "error.platform.issuersMachine.downloadCredentials.sendTokenResponse:invocation[0]"; data: unknown };
"error.platform.issuersMachine.downloadCredentials.tokenRequest:invocation[0]": { type: "error.platform.issuersMachine.downloadCredentials.tokenRequest:invocation[0]"; data: unknown };
"error.platform.issuersMachine.downloadCredentials:invocation[0]": { type: "error.platform.issuersMachine.downloadCredentials:invocation[0]"; data: unknown };
"error.platform.issuersMachine.downloadIssuerWellknown:invocation[0]": { type: "error.platform.issuersMachine.downloadIssuerWellknown:invocation[0]"; data: unknown };
"error.platform.issuersMachine.getCredentialTypes:invocation[0]": { type: "error.platform.issuersMachine.getCredentialTypes:invocation[0]"; data: unknown };
"error.platform.issuersMachine.verifyingCredential:invocation[0]": { type: "error.platform.issuersMachine.verifyingCredential:invocation[0]"; data: unknown };
"xstate.init": { type: "xstate.init" };
};
invokeSrcNameMap: {
"addIssuerToTrustedIssuers": "done.invoke.issuersMachine.credentialDownloadFromOffer.sendConsentGiven.addingIssuerToTrustedIssuers:invocation[0]";
"cacheIssuerWellknown": "done.invoke.issuersMachine.cachingCredentialOfferIssuerWellknown:invocation[0]";
"checkIssuerIdInStoredTrustedIssuers": "done.invoke.issuersMachine.credentialDownloadFromOffer.checkingIssuerTrust:invocation[0]" | "done.invoke.issuersMachine.credentialDownloadFromOffer.sendConsentGiven.updatingTrustedIssuerList:invocation[0]";
"constructAndSendProofForTrustedIssuers": "done.invoke.issuersMachine.downloadCredentials.constructProof:invocation[0]";
"constructProof": "done.invoke.issuersMachine.credentialDownloadFromOffer.keyManagement.constructProof:invocation[0]";
"downloadCredential": "done.invoke.issuersMachine.downloadCredentials:invocation[0]";
"downloadCredentialFromOffer": "done.invoke.issuersMachine.credentialDownloadFromOffer:invocation[0]";
"downloadIssuerWellknown": "done.invoke.issuersMachine.downloadIssuerWellknown:invocation[0]";
"downloadIssuersList": "done.invoke.issuersMachine.displayIssuers:invocation[0]";
"generateKeyPair": "done.invoke.issuersMachine.credentialDownloadFromOffer.keyManagement.generateKeyPair:invocation[0]" | "done.invoke.issuersMachine.downloadCredentials.keyManagement.generateKeyPair:invocation[0]";
"getCredentialTypes": "done.invoke.issuersMachine.getCredentialTypes:invocation[0]";
"getKeyOrderList": "done.invoke.issuersMachine.credentialDownloadFromOffer.keyManagement.setSelectedKey:invocation[0]" | "done.invoke.issuersMachine.downloadCredentials.keyManagement.setSelectedKey:invocation[0]";
"getKeyPair": "done.invoke.issuersMachine.credentialDownloadFromOffer.keyManagement.getKeyPairFromKeystore:invocation[0]" | "done.invoke.issuersMachine.downloadCredentials.keyManagement.getKeyPairFromKeystore:invocation[0]";
"isUserSignedAlready": "done.invoke.issuersMachine.storing:invocation[0]";
"sendConsentGiven": "done.invoke.issuersMachine.credentialDownloadFromOffer.sendConsentGiven:invocation[0]";
"sendConsentNotGiven": "done.invoke.issuersMachine.credentialDownloadFromOffer.sendConsentNotGiven:invocation[0]";
"sendTokenRequest": "done.invoke.issuersMachine.credentialDownloadFromOffer.tokenRequest:invocation[0]" | "done.invoke.issuersMachine.downloadCredentials.tokenRequest:invocation[0]";
"sendTokenResponse": "done.invoke.issuersMachine.credentialDownloadFromOffer.sendTokenResponse:invocation[0]" | "done.invoke.issuersMachine.downloadCredentials.sendTokenResponse:invocation[0]";
"sendTxCode": "done.invoke.issuersMachine.credentialDownloadFromOffer.sendTxCode:invocation[0]";
"updateCredential": "done.invoke.issuersMachine.proccessingCredential:invocation[0]";
"verifyCredential": "done.invoke.issuersMachine.verifyingCredential:invocation[0]";
};
missingImplementations: {
actions: "loadKeyPair" | "logDownloaded" | "resetCredentialOfferFlowType" | "resetError" | "resetLoadingReason" | "resetQrData" | "resetRequestConsentToTrustIssuer" | "resetRequestTxCode" | "resetSelectedCredentialType" | "resetSelectedIssuer" | "resetVerificationErrorMessage" | "resetVerificationResult" | "sendBackupEvent" | "sendDownloadingFailedToVcMeta" | "sendErrorEndEvent" | "sendImpressionEvent" | "sendSuccessEndEvent" | "setAccessToken" | "setCNonce" | "setCredential" | "setCredentialConfigurationId" | "setCredentialOfferCredentialType" | "setCredentialOfferFlowType" | "setCredentialOfferIssuer" | "setCredentialOfferIssuerWellknownResponse" | "setCredentialTypeListDownloadFailureError" | "setCredentialWrapper" | "setError" | "setIssuerDisplayDetails" | "setIssuers" | "setLoadingReasonAsDisplayIssuers" | "setLoadingReasonAsDownloadingCredentials" | "setLoadingReasonAsSettingUp" | "setMetadataInCredentialData" | "setPrivateKey" | "setPublicKey" | "setQrData" | "setRequestConsentToTrustIssuer" | "setRequestTxCode" | "setSelectedCredentialIssuer" | "setSelectedCredentialType" | "setSelectedIssuerId" | "setSelectedIssuers" | "setSelectedKey" | "setSupportedCredentialTypes" | "setTokenRequestObject" | "setTokenResponseObject" | "setTxCode" | "setTxCodeDisplayDetails" | "setVCMetadata" | "setVerifiableCredential" | "setVerificationResult" | "setWellknwonKeyTypes" | "storeKeyPair" | "storeVcMetaContext" | "storeVcsContext" | "storeVerifiableCredentialData" | "storeVerifiableCredentialMeta" | "updateIssuerFromWellknown" | "updateVerificationErrorMessage";
delays: never;
guards: "canSelectIssuerAgain" | "hasUserCancelledBiometric" | "isCredentialOfferFlow" | "isIssuerIdInTrustedIssuers" | "isKeyTypeNotFound" | "isSignedIn" | "isVerificationPendingBecauseOfNetworkIssue" | "shouldFetchIssuersAgain";
services: "addIssuerToTrustedIssuers" | "cacheIssuerWellknown" | "checkIssuerIdInStoredTrustedIssuers" | "constructAndSendProofForTrustedIssuers" | "constructProof" | "downloadCredential" | "downloadCredentialFromOffer" | "downloadIssuerWellknown" | "downloadIssuersList" | "generateKeyPair" | "getCredentialTypes" | "getKeyOrderList" | "getKeyPair" | "isUserSignedAlready" | "sendConsentGiven" | "sendConsentNotGiven" | "sendTokenRequest" | "sendTokenResponse" | "sendTxCode" | "updateCredential" | "verifyCredential";
};
eventsCausingActions: {
"loadKeyPair": "done.invoke.issuersMachine.credentialDownloadFromOffer.keyManagement.getKeyPairFromKeystore:invocation[0]" | "done.invoke.issuersMachine.downloadCredentials.keyManagement.getKeyPairFromKeystore:invocation[0]";
"logDownloaded": "done.invoke.issuersMachine.verifyingCredential:invocation[0]" | "error.platform.issuersMachine.verifyingCredential:invocation[0]";
"resetCredentialOfferFlowType": "RESET_ERROR" | "TRY_AGAIN" | "done.invoke.issuersMachine.verifyingCredential:invocation[0]";
"resetError": "RESET_ERROR" | "TRY_AGAIN";
"resetLoadingReason": "CANCEL" | "RESET_ERROR" | "done.invoke.issuersMachine.displayIssuers:invocation[0]" | "error.platform.issuersMachine.cachingCredentialOfferIssuerWellknown:invocation[0]" | "error.platform.issuersMachine.credentialDownloadFromOffer.keyManagement.constructProof:invocation[0]" | "error.platform.issuersMachine.credentialDownloadFromOffer.keyManagement.getKeyPairFromKeystore:invocation[0]" | "error.platform.issuersMachine.credentialDownloadFromOffer.keyManagement.setSelectedKey:invocation[0]" | "error.platform.issuersMachine.credentialDownloadFromOffer.sendConsentGiven:invocation[0]" | "error.platform.issuersMachine.credentialDownloadFromOffer.sendTokenResponse:invocation[0]" | "error.platform.issuersMachine.credentialDownloadFromOffer.sendTxCode:invocation[0]" | "error.platform.issuersMachine.credentialDownloadFromOffer.tokenRequest:invocation[0]" | "error.platform.issuersMachine.credentialDownloadFromOffer:invocation[0]" | "error.platform.issuersMachine.downloadCredentials.constructProof:invocation[0]" | "error.platform.issuersMachine.downloadCredentials.keyManagement.generateKeyPair:invocation[0]" | "error.platform.issuersMachine.downloadCredentials.keyManagement.getKeyPairFromKeystore:invocation[0]" | "error.platform.issuersMachine.downloadCredentials.keyManagement.setSelectedKey:invocation[0]" | "error.platform.issuersMachine.downloadCredentials.sendTokenResponse:invocation[0]" | "error.platform.issuersMachine.downloadCredentials.tokenRequest:invocation[0]" | "error.platform.issuersMachine.downloadCredentials:invocation[0]" | "error.platform.issuersMachine.downloadIssuerWellknown:invocation[0]" | "error.platform.issuersMachine.getCredentialTypes:invocation[0]" | "error.platform.issuersMachine.verifyingCredential:invocation[0]";
"resetQrData": "CANCEL";
"resetRequestConsentToTrustIssuer": "CANCEL" | "ON_CONSENT_GIVEN" | "error.platform.issuersMachine.credentialDownloadFromOffer.sendConsentGiven:invocation[0]" | "error.platform.issuersMachine.credentialDownloadFromOffer.tokenRequest:invocation[0]";
"resetRequestTxCode": "CANCEL" | "TX_CODE_RECEIVED" | "error.platform.issuersMachine.credentialDownloadFromOffer.sendTxCode:invocation[0]";
"resetSelectedCredentialType": "CANCEL";
"resetSelectedIssuer": "QR_CODE_SCANNED";
"resetVerificationErrorMessage": "RESET_VERIFY_ERROR";
"resetVerificationResult": "error.platform.issuersMachine.verifyingCredential:invocation[0]";
"sendBackupEvent": "done.invoke.issuersMachine.storing:invocation[0]";
"sendDownloadingFailedToVcMeta": "CANCEL" | "error.platform.issuersMachine.credentialDownloadFromOffer.keyManagement.constructProof:invocation[0]" | "error.platform.issuersMachine.credentialDownloadFromOffer.keyManagement.getKeyPairFromKeystore:invocation[0]" | "error.platform.issuersMachine.credentialDownloadFromOffer.keyManagement.setSelectedKey:invocation[0]" | "error.platform.issuersMachine.credentialDownloadFromOffer.sendTokenResponse:invocation[0]" | "error.platform.issuersMachine.credentialDownloadFromOffer.sendTxCode:invocation[0]" | "error.platform.issuersMachine.downloadCredentials.constructProof:invocation[0]" | "error.platform.issuersMachine.downloadCredentials.keyManagement.generateKeyPair:invocation[0]" | "error.platform.issuersMachine.downloadCredentials.keyManagement.getKeyPairFromKeystore:invocation[0]" | "error.platform.issuersMachine.downloadCredentials.keyManagement.setSelectedKey:invocation[0]";
"sendErrorEndEvent": "error.platform.issuersMachine.verifyingCredential:invocation[0]";
"sendImpressionEvent": "done.invoke.issuersMachine.displayIssuers:invocation[0]";
"sendSuccessEndEvent": "done.invoke.issuersMachine.verifyingCredential:invocation[0]";
"setAccessToken": "done.invoke.issuersMachine.downloadCredentials.tokenRequest:invocation[0]";
"setCNonce": "PROOF_REQUEST";
"setCredential": "done.invoke.issuersMachine.credentialDownloadFromOffer:invocation[0]";
"setCredentialConfigurationId": "done.invoke.issuersMachine.credentialDownloadFromOffer:invocation[0]";
"setCredentialOfferCredentialType": "done.invoke.issuersMachine.cachingCredentialOfferIssuerWellknown:invocation[0]";
"setCredentialOfferFlowType": "QR_CODE_SCANNED";
"setCredentialOfferIssuer": "done.invoke.issuersMachine.cachingCredentialOfferIssuerWellknown:invocation[0]";
"setCredentialOfferIssuerWellknownResponse": "done.invoke.issuersMachine.cachingCredentialOfferIssuerWellknown:invocation[0]";
"setCredentialTypeListDownloadFailureError": "error.platform.issuersMachine.getCredentialTypes:invocation[0]";
"setCredentialWrapper": "done.invoke.issuersMachine.downloadCredentials:invocation[0]" | "done.invoke.issuersMachine.proccessingCredential:invocation[0]";
"setError": "error.platform.issuersMachine.credentialDownloadFromOffer.keyManagement.constructProof:invocation[0]" | "error.platform.issuersMachine.credentialDownloadFromOffer.keyManagement.getKeyPairFromKeystore:invocation[0]" | "error.platform.issuersMachine.credentialDownloadFromOffer.keyManagement.setSelectedKey:invocation[0]" | "error.platform.issuersMachine.credentialDownloadFromOffer.sendConsentGiven:invocation[0]" | "error.platform.issuersMachine.credentialDownloadFromOffer.sendTokenResponse:invocation[0]" | "error.platform.issuersMachine.credentialDownloadFromOffer.sendTxCode:invocation[0]" | "error.platform.issuersMachine.credentialDownloadFromOffer.tokenRequest:invocation[0]" | "error.platform.issuersMachine.credentialDownloadFromOffer:invocation[0]" | "error.platform.issuersMachine.displayIssuers:invocation[0]" | "error.platform.issuersMachine.downloadCredentials.constructProof:invocation[0]" | "error.platform.issuersMachine.downloadCredentials.keyManagement.generateKeyPair:invocation[0]" | "error.platform.issuersMachine.downloadCredentials.keyManagement.getKeyPairFromKeystore:invocation[0]" | "error.platform.issuersMachine.downloadCredentials.keyManagement.setSelectedKey:invocation[0]" | "error.platform.issuersMachine.downloadCredentials.sendTokenResponse:invocation[0]" | "error.platform.issuersMachine.downloadCredentials.tokenRequest:invocation[0]" | "error.platform.issuersMachine.downloadCredentials:invocation[0]" | "error.platform.issuersMachine.downloadIssuerWellknown:invocation[0]";
"setIssuerDisplayDetails": "TRUST_ISSUER_CONSENT_REQUEST";
"setIssuers": "done.invoke.issuersMachine.displayIssuers:invocation[0]";
"setLoadingReasonAsDisplayIssuers": "TRY_AGAIN";
"setLoadingReasonAsDownloadingCredentials": "ON_CONSENT_GIVEN" | "QR_CODE_SCANNED" | "SELECTED_CREDENTIAL_TYPE" | "done.invoke.issuersMachine.credentialDownloadFromOffer.keyManagement.generateKeyPair:invocation[0]" | "done.invoke.issuersMachine.downloadCredentials.keyManagement.generateKeyPair:invocation[0]";
"setLoadingReasonAsSettingUp": "SELECTED_ISSUER" | "TRY_AGAIN";
"setMetadataInCredentialData": "done.invoke.issuersMachine.verifyingCredential:invocation[0]" | "error.platform.issuersMachine.verifyingCredential:invocation[0]";
"setPrivateKey": "done.invoke.issuersMachine.credentialDownloadFromOffer.keyManagement.generateKeyPair:invocation[0]" | "done.invoke.issuersMachine.downloadCredentials.keyManagement.generateKeyPair:invocation[0]";
"setPublicKey": "done.invoke.issuersMachine.credentialDownloadFromOffer.keyManagement.generateKeyPair:invocation[0]" | "done.invoke.issuersMachine.downloadCredentials.keyManagement.generateKeyPair:invocation[0]";
"setQrData": "QR_CODE_SCANNED";
"setRequestConsentToTrustIssuer": "done.invoke.issuersMachine.credentialDownloadFromOffer.checkingIssuerTrust:invocation[0]";
"setRequestTxCode": "TX_CODE_REQUEST";
"setSelectedCredentialIssuer": "PROOF_REQUEST" | "TRUST_ISSUER_CONSENT_REQUEST";
"setSelectedCredentialType": "SELECTED_CREDENTIAL_TYPE";
"setSelectedIssuerId": "SELECTED_ISSUER";
"setSelectedIssuers": "SELECTED_ISSUER";
"setSelectedKey": "done.invoke.issuersMachine.credentialDownloadFromOffer.keyManagement.setSelectedKey:invocation[0]" | "done.invoke.issuersMachine.downloadCredentials.keyManagement.setSelectedKey:invocation[0]";
"setSupportedCredentialTypes": "done.invoke.issuersMachine.getCredentialTypes:invocation[0]";
"setTokenRequestObject": "TOKEN_REQUEST";
"setTokenResponseObject": "done.invoke.issuersMachine.credentialDownloadFromOffer.tokenRequest:invocation[0]" | "done.invoke.issuersMachine.downloadCredentials.tokenRequest:invocation[0]";
"setTxCode": "TX_CODE_RECEIVED";
"setTxCodeDisplayDetails": "TX_CODE_REQUEST";
"setVCMetadata": "done.invoke.issuersMachine.verifyingCredential:invocation[0]" | "error.platform.issuersMachine.verifyingCredential:invocation[0]";
"setVerifiableCredential": "done.invoke.issuersMachine.downloadCredentials:invocation[0]" | "done.invoke.issuersMachine.proccessingCredential:invocation[0]";
"setVerificationResult": "done.invoke.issuersMachine.verifyingCredential:invocation[0]";
"setWellknwonKeyTypes": "PROOF_REQUEST";
"storeKeyPair": "done.invoke.issuersMachine.credentialDownloadFromOffer.keyManagement.generateKeyPair:invocation[0]" | "done.invoke.issuersMachine.downloadCredentials.keyManagement.generateKeyPair:invocation[0]";
"storeVcMetaContext": "done.invoke.issuersMachine.verifyingCredential:invocation[0]" | "error.platform.issuersMachine.verifyingCredential:invocation[0]";
"storeVcsContext": "done.invoke.issuersMachine.verifyingCredential:invocation[0]" | "error.platform.issuersMachine.verifyingCredential:invocation[0]";
"storeVerifiableCredentialData": "done.invoke.issuersMachine.verifyingCredential:invocation[0]" | "error.platform.issuersMachine.verifyingCredential:invocation[0]";
"storeVerifiableCredentialMeta": "done.invoke.issuersMachine.verifyingCredential:invocation[0]" | "error.platform.issuersMachine.verifyingCredential:invocation[0]";
"updateIssuerFromWellknown": "done.invoke.issuersMachine.downloadIssuerWellknown:invocation[0]";
"updateVerificationErrorMessage": "error.platform.issuersMachine.verifyingCredential:invocation[0]";
};
eventsCausingDelays: {
};
eventsCausingGuards: {
"canSelectIssuerAgain": "TRY_AGAIN";
"hasUserCancelledBiometric": "error.platform.issuersMachine.credentialDownloadFromOffer.keyManagement.getKeyPairFromKeystore:invocation[0]" | "error.platform.issuersMachine.downloadCredentials.constructProof:invocation[0]" | "error.platform.issuersMachine.downloadCredentials.keyManagement.getKeyPairFromKeystore:invocation[0]" | "error.platform.issuersMachine.downloadCredentials:invocation[0]";
"isCredentialOfferFlow": "TRY_AGAIN";
"isIssuerIdInTrustedIssuers": "done.invoke.issuersMachine.credentialDownloadFromOffer.checkingIssuerTrust:invocation[0]" | "done.invoke.issuersMachine.credentialDownloadFromOffer.sendConsentGiven.updatingTrustedIssuerList:invocation[0]";
"isKeyTypeNotFound": "error.platform.issuersMachine.credentialDownloadFromOffer.keyManagement.getKeyPairFromKeystore:invocation[0]" | "error.platform.issuersMachine.downloadCredentials.keyManagement.getKeyPairFromKeystore:invocation[0]";
"isSignedIn": "done.invoke.issuersMachine.storing:invocation[0]";
"isVerificationPendingBecauseOfNetworkIssue": "error.platform.issuersMachine.verifyingCredential:invocation[0]";
"shouldFetchIssuersAgain": "TRY_AGAIN";
};
eventsCausingServices: {
"addIssuerToTrustedIssuers": "done.invoke.issuersMachine.credentialDownloadFromOffer.sendConsentGiven.updatingTrustedIssuerList:invocation[0]" | "error.platform.issuersMachine.credentialDownloadFromOffer.sendConsentGiven.updatingTrustedIssuerList:invocation[0]";
"cacheIssuerWellknown": "done.invoke.issuersMachine.credentialDownloadFromOffer:invocation[0]";
"checkIssuerIdInStoredTrustedIssuers": "TRUST_ISSUER_CONSENT_REQUEST" | "done.invoke.issuersMachine.credentialDownloadFromOffer.sendConsentGiven:invocation[0]";
"constructAndSendProofForTrustedIssuers": "TRY_AGAIN" | "done.invoke.issuersMachine.downloadCredentials.keyManagement.generateKeyPair:invocation[0]" | "done.invoke.issuersMachine.downloadCredentials.keyManagement.getKeyPairFromKeystore:invocation[0]";
"constructProof": "done.invoke.issuersMachine.credentialDownloadFromOffer.keyManagement.generateKeyPair:invocation[0]" | "done.invoke.issuersMachine.credentialDownloadFromOffer.keyManagement.getKeyPairFromKeystore:invocation[0]";
"downloadCredential": "SELECTED_CREDENTIAL_TYPE";
"downloadCredentialFromOffer": "QR_CODE_SCANNED";
"downloadIssuerWellknown": "SELECTED_ISSUER" | "TRY_AGAIN";
"downloadIssuersList": "CANCEL" | "TRY_AGAIN" | "xstate.init";
"generateKeyPair": "error.platform.issuersMachine.credentialDownloadFromOffer.keyManagement.getKeyPairFromKeystore:invocation[0]" | "error.platform.issuersMachine.downloadCredentials.keyManagement.getKeyPairFromKeystore:invocation[0]";
"getCredentialTypes": "done.invoke.issuersMachine.downloadIssuerWellknown:invocation[0]";
"getKeyOrderList": "PROOF_REQUEST";
"getKeyPair": "TRY_AGAIN" | "done.invoke.issuersMachine.credentialDownloadFromOffer.keyManagement.setSelectedKey:invocation[0]" | "done.invoke.issuersMachine.downloadCredentials.keyManagement.setSelectedKey:invocation[0]";
"isUserSignedAlready": "done.invoke.issuersMachine.verifyingCredential:invocation[0]" | "error.platform.issuersMachine.verifyingCredential:invocation[0]";
"sendConsentGiven": "ON_CONSENT_GIVEN" | "done.invoke.issuersMachine.credentialDownloadFromOffer.checkingIssuerTrust:invocation[0]";
"sendConsentNotGiven": "CANCEL";
"sendTokenRequest": "TOKEN_REQUEST";
"sendTokenResponse": "done.invoke.issuersMachine.credentialDownloadFromOffer.tokenRequest:invocation[0]" | "done.invoke.issuersMachine.downloadCredentials.tokenRequest:invocation[0]";
"sendTxCode": "TX_CODE_RECEIVED";
"updateCredential": "done.invoke.issuersMachine.cachingCredentialOfferIssuerWellknown:invocation[0]";
"verifyCredential": "done.invoke.issuersMachine.downloadCredentials:invocation[0]" | "done.invoke.issuersMachine.proccessingCredential:invocation[0]";
};
matchesStates: "cachingCredentialOfferIssuerWellknown" | "credentialDownloadFromOffer" | "credentialDownloadFromOffer.checkingIssuerTrust" | "credentialDownloadFromOffer.credentialOfferDownloadConsent" | "credentialDownloadFromOffer.idle" | "credentialDownloadFromOffer.keyManagement" | "credentialDownloadFromOffer.keyManagement.constructProof" | "credentialDownloadFromOffer.keyManagement.generateKeyPair" | "credentialDownloadFromOffer.keyManagement.getKeyPairFromKeystore" | "credentialDownloadFromOffer.keyManagement.setSelectedKey" | "credentialDownloadFromOffer.keyManagement.userCancelledBiometric" | "credentialDownloadFromOffer.sendConsentGiven" | "credentialDownloadFromOffer.sendConsentGiven.addingIssuerToTrustedIssuers" | "credentialDownloadFromOffer.sendConsentGiven.updatingTrustedIssuerList" | "credentialDownloadFromOffer.sendConsentNotGiven" | "credentialDownloadFromOffer.sendTokenResponse" | "credentialDownloadFromOffer.sendTxCode" | "credentialDownloadFromOffer.tokenRequest" | "credentialDownloadFromOffer.waitingForTxCode" | "displayIssuers" | "done" | "downloadCredentials" | "downloadCredentials.constructProof" | "downloadCredentials.idle" | "downloadCredentials.keyManagement" | "downloadCredentials.keyManagement.generateKeyPair" | "downloadCredentials.keyManagement.getKeyPairFromKeystore" | "downloadCredentials.keyManagement.setSelectedKey" | "downloadCredentials.keyManagement.userCancelledBiometric" | "downloadCredentials.sendTokenResponse" | "downloadCredentials.tokenRequest" | "downloadCredentials.userCancelledBiometric" | "downloadIssuerWellknown" | "error" | "getCredentialTypes" | "handleVCVerificationFailure" | "idle" | "proccessingCredential" | "selectingCredentialType" | "selectingIssuer" | "storing" | "verifyingCredential" | "waitingForQrScan" | { "credentialDownloadFromOffer"?: "checkingIssuerTrust" | "credentialOfferDownloadConsent" | "idle" | "keyManagement" | "sendConsentGiven" | "sendConsentNotGiven" | "sendTokenResponse" | "sendTxCode" | "tokenRequest" | "waitingForTxCode" | { "keyManagement"?: "constructProof" | "generateKeyPair" | "getKeyPairFromKeystore" | "setSelectedKey" | "userCancelledBiometric";
"sendConsentGiven"?: "addingIssuerToTrustedIssuers" | "updatingTrustedIssuerList"; };
"downloadCredentials"?: "constructProof" | "idle" | "keyManagement" | "sendTokenResponse" | "tokenRequest" | "userCancelledBiometric" | { "keyManagement"?: "generateKeyPair" | "getKeyPairFromKeystore" | "setSelectedKey" | "userCancelledBiometric"; }; };
tags: never;
}

View File

@@ -1,130 +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.';
};
'done.invoke.QrLogin.sendingAuthenticate:invocation[0]': {
type: 'done.invoke.QrLogin.sendingAuthenticate: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.sendingAuthenticate:invocation[0]': {
type: 'error.platform.QrLogin.sendingAuthenticate: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]';
sendAuthenticate: 'done.invoke.QrLogin.sendingAuthenticate:invocation[0]';
sendConsent: 'done.invoke.QrLogin.sendingConsent:invocation[0]';
};
missingImplementations: {
actions:
| 'SetErrorMessage'
| 'expandLinkTransResp'
| 'forwardToParent'
| 'getFaceAuthConsent'
| 'loadMyVcs'
| 'loadThumbprint'
| 'resetFlowType'
| 'resetIsQrLoginViaDeepLink'
| 'resetLinkTransactionId'
| 'resetSelectedVc'
| 'resetSelectedVoluntaryClaims'
| 'setClaims'
| 'setConsentClaims'
| 'setLinkedTransactionId'
| 'setMyVcs'
| 'setScanData'
| 'setSelectedVc'
| 'setShowFaceAuthConsent'
| 'setThumbprint'
| 'setlinkTransactionResponse'
| 'storeShowFaceAuthConsent'
| 'updateShowFaceAuthConsent';
delays: never;
guards:
| 'isConsentAlreadyCaptured'
| 'isSimpleShareFlow'
| 'showFaceAuthConsentScreen';
services: 'linkTransaction' | 'sendAuthenticate' | 'sendConsent';
};
eventsCausingActions: {
SetErrorMessage:
| 'error.platform.QrLogin.linkTransaction:invocation[0]'
| 'error.platform.QrLogin.sendingAuthenticate:invocation[0]'
| 'error.platform.QrLogin.sendingConsent:invocation[0]';
expandLinkTransResp: 'done.invoke.QrLogin.linkTransaction:invocation[0]';
forwardToParent: 'CANCEL' | 'DISMISS';
getFaceAuthConsent: 'GET';
loadMyVcs: 'done.invoke.QrLogin.linkTransaction:invocation[0]';
loadThumbprint: 'FACE_VALID';
resetFlowType: 'xstate.init';
resetIsQrLoginViaDeepLink:
| 'error.platform.QrLogin.linkTransaction:invocation[0]'
| 'error.platform.QrLogin.sendingAuthenticate:invocation[0]'
| 'error.platform.QrLogin.sendingConsent:invocation[0]'
| 'xstate.init';
resetLinkTransactionId: 'GET';
resetSelectedVc: 'xstate.init';
resetSelectedVoluntaryClaims: 'GET';
setClaims: 'done.invoke.QrLogin.linkTransaction:invocation[0]';
setConsentClaims: 'TOGGLE_CONSENT_CLAIM';
setLinkedTransactionId: 'done.invoke.QrLogin.sendingAuthenticate:invocation[0]';
setMyVcs: 'STORE_RESPONSE';
setScanData: 'GET';
setSelectedVc: 'SELECT_VC';
setShowFaceAuthConsent: 'FACE_VERIFICATION_CONSENT';
setThumbprint: 'STORE_RESPONSE';
setlinkTransactionResponse: 'done.invoke.QrLogin.linkTransaction:invocation[0]';
storeShowFaceAuthConsent: 'FACE_VERIFICATION_CONSENT';
updateShowFaceAuthConsent: 'STORE_RESPONSE';
};
eventsCausingDelays: {};
eventsCausingGuards: {
isConsentAlreadyCaptured: 'done.invoke.QrLogin.sendingAuthenticate:invocation[0]';
isSimpleShareFlow:
| 'CANCEL'
| 'DISMISS'
| 'done.invoke.QrLogin.linkTransaction:invocation[0]';
showFaceAuthConsentScreen:
| 'VERIFY'
| 'done.invoke.QrLogin.linkTransaction:invocation[0]';
};
eventsCausingServices: {
linkTransaction: 'STORE_RESPONSE';
sendAuthenticate: 'STORE_RESPONSE';
sendConsent: 'CONFIRM';
};
matchesStates:
| 'ShowError'
| 'checkFaceAuthConsent'
| 'done'
| 'faceAuth'
| 'faceVerificationConsent'
| 'invalidIdentity'
| 'linkTransaction'
| 'loadMyVcs'
| 'loadingThumbprint'
| 'requestConsent'
| 'sendingAuthenticate'
| 'sendingConsent'
| 'showvcList'
| 'success'
| 'waitingForData';
tags: never;
}
// 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." };
"done.invoke.QrLogin.sendingAuthenticate:invocation[0]": { type: "done.invoke.QrLogin.sendingAuthenticate: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.sendingAuthenticate:invocation[0]": { type: "error.platform.QrLogin.sendingAuthenticate: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]";
"sendAuthenticate": "done.invoke.QrLogin.sendingAuthenticate:invocation[0]";
"sendConsent": "done.invoke.QrLogin.sendingConsent:invocation[0]";
};
missingImplementations: {
actions: "SetErrorMessage" | "expandLinkTransResp" | "forwardToParent" | "getFaceAuthConsent" | "loadMyVcs" | "loadThumbprint" | "resetFlowType" | "resetIsQrLoginViaDeepLink" | "resetLinkTransactionId" | "resetSelectedVc" | "resetSelectedVoluntaryClaims" | "setClaims" | "setConsentClaims" | "setLinkedTransactionId" | "setMyVcs" | "setScanData" | "setSelectedVc" | "setShowFaceAuthConsent" | "setThumbprint" | "setlinkTransactionResponse" | "storeShowFaceAuthConsent" | "updateShowFaceAuthConsent";
delays: never;
guards: "isConsentAlreadyCaptured" | "isSimpleShareFlow" | "showFaceAuthConsentScreen";
services: "linkTransaction" | "sendAuthenticate" | "sendConsent";
};
eventsCausingActions: {
"SetErrorMessage": "error.platform.QrLogin.linkTransaction:invocation[0]" | "error.platform.QrLogin.sendingAuthenticate:invocation[0]" | "error.platform.QrLogin.sendingConsent:invocation[0]";
"expandLinkTransResp": "done.invoke.QrLogin.linkTransaction:invocation[0]";
"forwardToParent": "CANCEL" | "DISMISS";
"getFaceAuthConsent": "GET";
"loadMyVcs": "done.invoke.QrLogin.linkTransaction:invocation[0]";
"loadThumbprint": "FACE_VALID";
"resetFlowType": "xstate.init";
"resetIsQrLoginViaDeepLink": "error.platform.QrLogin.linkTransaction:invocation[0]" | "error.platform.QrLogin.sendingAuthenticate:invocation[0]" | "error.platform.QrLogin.sendingConsent:invocation[0]" | "xstate.init";
"resetLinkTransactionId": "GET";
"resetSelectedVc": "xstate.init";
"resetSelectedVoluntaryClaims": "GET";
"setClaims": "done.invoke.QrLogin.linkTransaction:invocation[0]";
"setConsentClaims": "TOGGLE_CONSENT_CLAIM";
"setLinkedTransactionId": "done.invoke.QrLogin.sendingAuthenticate:invocation[0]";
"setMyVcs": "STORE_RESPONSE";
"setScanData": "GET";
"setSelectedVc": "SELECT_VC";
"setShowFaceAuthConsent": "FACE_VERIFICATION_CONSENT";
"setThumbprint": "STORE_RESPONSE";
"setlinkTransactionResponse": "done.invoke.QrLogin.linkTransaction:invocation[0]";
"storeShowFaceAuthConsent": "FACE_VERIFICATION_CONSENT";
"updateShowFaceAuthConsent": "STORE_RESPONSE";
};
eventsCausingDelays: {
};
eventsCausingGuards: {
"isConsentAlreadyCaptured": "done.invoke.QrLogin.sendingAuthenticate:invocation[0]";
"isSimpleShareFlow": "CANCEL" | "DISMISS" | "done.invoke.QrLogin.linkTransaction:invocation[0]";
"showFaceAuthConsentScreen": "VERIFY" | "done.invoke.QrLogin.linkTransaction:invocation[0]";
};
eventsCausingServices: {
"linkTransaction": "STORE_RESPONSE";
"sendAuthenticate": "STORE_RESPONSE";
"sendConsent": "CONFIRM";
};
matchesStates: "ShowError" | "checkFaceAuthConsent" | "done" | "faceAuth" | "faceVerificationConsent" | "invalidIdentity" | "linkTransaction" | "loadMyVcs" | "loadingThumbprint" | "requestConsent" | "sendingAuthenticate" | "sendingConsent" | "showvcList" | "success" | "waitingForData";
tags: never;
}

View File

@@ -27,15 +27,15 @@
"startConnection": "done.invoke.scan.connecting:invocation[0]";
};
missingImplementations: {
actions: "clearUri" | "enableLocation" | "getFaceAuthConsent" | "loadMetaDataToMemory" | "loadVCDataToMemory" | "logFailedVerification" | "logShared" | "openAppPermission" | "openBluetoothSettings" | "refreshVCs" | "registerLoggers" | "removeLoggers" | "resetFaceCaptureBannerStatus" | "resetFlowType" | "resetIsQrLoginViaDeepLink" | "resetLinkCode" | "resetOpenID4VPFlowType" | "resetSelectedVc" | "resetShowQuickShareSuccessBanner" | "sendBLEConnectionErrorEvent" | "sendScanData" | "sendVCShareFlowCancelEndEvent" | "sendVCShareFlowTimeoutEndEvent" | "sendVPScanData" | "sendVcShareSuccessEvent" | "sendVcSharingStartEvent" | "setBleError" | "setFlowType" | "setIsQrLoginViaDeepLink" | "setLinkCode" | "setLinkCodeFromDeepLink" | "setOpenId4VPFlowType" | "setOpenId4VPRef" | "setQrLoginRef" | "setQuickShareData" | "setReadyForBluetoothStateCheck" | "setReceiverInfo" | "setSelectedVc" | "setSenderInfo" | "setShareLogTypeUnverified" | "setShareLogTypeVerified" | "setShowFaceAuthConsent" | "setShowQuickShareSuccessBanner" | "setUri" | "storeLoginItem" | "storeShowFaceAuthConsent" | "storingActivityLog" | "updateFaceCaptureBannerStatus" | "updateShowFaceAuthConsent";
actions: "clearUri" | "enableLocation" | "getFaceAuthConsent" | "loadMetaDataToMemory" | "loadVCDataToMemory" | "logFailedVerification" | "logShared" | "openAppPermission" | "openBluetoothSettings" | "refreshVCs" | "registerLoggers" | "removeLoggers" | "resetAuthorizationRequest" | "resetBleError" | "resetFaceCaptureBannerStatus" | "resetFlowType" | "resetIsOVPViaDeepLink" | "resetIsQrLoginViaDeepLink" | "resetLinkCode" | "resetOpenID4VPFlowType" | "resetSelectedVc" | "resetShowQuickShareSuccessBanner" | "sendBLEConnectionErrorEvent" | "sendScanData" | "sendVCShareFlowCancelEndEvent" | "sendVCShareFlowTimeoutEndEvent" | "sendVPScanData" | "sendVcShareSuccessEvent" | "sendVcSharingStartEvent" | "setAuthRequestFromDeepLink" | "setBleError" | "setFlowType" | "setIsOVPViaDeepLink" | "setIsQrLoginViaDeepLink" | "setLinkCode" | "setLinkCodeFromDeepLink" | "setOpenId4VPFlowType" | "setOpenId4VPRef" | "setQrLoginRef" | "setQuickShareData" | "setReadyForBluetoothStateCheck" | "setReceiverInfo" | "setSelectedVc" | "setSenderInfo" | "setShareLogTypeUnverified" | "setShareLogTypeVerified" | "setShowFaceAuthConsent" | "setShowQuickShareSuccessBanner" | "setUri" | "storeLoginItem" | "storeShowFaceAuthConsent" | "storingActivityLog" | "updateFaceCaptureBannerStatus" | "updateShowFaceAuthConsent";
delays: never;
guards: "isFlowTypeMiniViewShare" | "isFlowTypeMiniViewShareWithSelfie" | "isFlowTypeSimpleShare" | "isIOS" | "isMinimumStorageRequiredForAuditEntryReached" | "isOnlineSharing" | "isOpenIdQr" | "isQrLogin" | "isQrLoginViaDeepLinking" | "isQuickShare" | "showFaceAuthConsentScreen" | "uptoAndroid11";
guards: "isFlowTypeDeepLink" | "isFlowTypeMiniViewShare" | "isFlowTypeMiniViewShareWithSelfie" | "isFlowTypeSimpleShare" | "isIOS" | "isMinimumStorageRequiredForAuditEntryReached" | "isOVPViaDeepLink" | "isOnlineSharing" | "isOpenIdQr" | "isQrLogin" | "isQrLoginViaDeepLinking" | "isQuickShare" | "showFaceAuthConsentScreen" | "uptoAndroid11";
services: "checkBluetoothPermission" | "checkBluetoothState" | "checkLocationPermission" | "checkLocationStatus" | "checkNearByDevicesPermission" | "checkStorageAvailability" | "disconnect" | "monitorConnection" | "requestBluetooth" | "requestNearByDevicesPermission" | "requestToEnableLocationPermission" | "sendVc" | "startConnection";
};
eventsCausingActions: {
"clearUri": "";
"enableLocation": "ALLOWED" | "LOCATION_REQUEST";
"getFaceAuthConsent": "DISCONNECT" | "DISMISS" | "xstate.after(DESTROY_TIMEOUT)#scan.clearingConnection";
"getFaceAuthConsent": "DISCONNECT" | "DISMISS" | "START_PERMISSION_CHECK" | "xstate.after(DESTROY_TIMEOUT)#scan.clearingConnection";
"loadMetaDataToMemory": "SCAN";
"loadVCDataToMemory": "STORE_RESPONSE";
"logFailedVerification": "FACE_INVALID";
@@ -44,28 +44,33 @@
"openBluetoothSettings": "GOTO_SETTINGS";
"refreshVCs": "STORE_RESPONSE";
"registerLoggers": "";
"removeLoggers": "" | "DISCONNECT" | "DISMISS" | "DISMISS_QUICK_SHARE_BANNER" | "QRLOGIN_VIA_DEEP_LINK" | "RESET" | "SCREEN_BLUR" | "xstate.init";
"removeLoggers": "" | "DISCONNECT" | "DISMISS" | "DISMISS_QUICK_SHARE_BANNER" | "OVP_VIA_DEEP_LINK" | "QRLOGIN_VIA_DEEP_LINK" | "RESET" | "SCREEN_BLUR" | "xstate.init";
"resetAuthorizationRequest": "RESET";
"resetBleError": "DISMISS";
"resetFaceCaptureBannerStatus": "" | "ACCEPT_REQUEST" | "CLOSE_BANNER";
"resetFlowType": "DISCONNECT" | "DISMISS" | "DISMISS_QUICK_SHARE_BANNER" | "GOTO_HISTORY" | "QRLOGIN_VIA_DEEP_LINK" | "RESET" | "SCREEN_BLUR" | "xstate.init";
"resetFlowType": "DISCONNECT" | "DISMISS" | "DISMISS_QUICK_SHARE_BANNER" | "GOTO_HISTORY" | "OVP_VIA_DEEP_LINK" | "QRLOGIN_VIA_DEEP_LINK" | "RESET" | "SCREEN_BLUR" | "xstate.init";
"resetIsOVPViaDeepLink": "DISMISS" | "RESET";
"resetIsQrLoginViaDeepLink": "DISMISS" | "RESET";
"resetLinkCode": "BLE_ERROR" | "DISMISS" | "DISMISS_QUICK_SHARE_BANNER" | "QRLOGIN_VIA_DEEP_LINK" | "RESET" | "SCREEN_BLUR" | "SCREEN_FOCUS" | "SELECT_VC" | "xstate.stop";
"resetOpenID4VPFlowType": "CANCEL" | "DISMISS" | "RETRY" | "SCREEN_BLUR";
"resetSelectedVc": "DISCONNECT" | "DISMISS" | "DISMISS_QUICK_SHARE_BANNER" | "GOTO_HISTORY" | "QRLOGIN_VIA_DEEP_LINK" | "RESET" | "SCREEN_BLUR" | "xstate.init";
"resetLinkCode": "BLE_ERROR" | "DISMISS" | "DISMISS_QUICK_SHARE_BANNER" | "OVP_VIA_DEEP_LINK" | "QRLOGIN_VIA_DEEP_LINK" | "RESET" | "SCREEN_BLUR" | "SCREEN_FOCUS" | "SELECT_VC" | "xstate.stop";
"resetOpenID4VPFlowType": "CANCEL" | "DISMISS" | "RESET" | "RETRY" | "SCREEN_BLUR";
"resetSelectedVc": "DISCONNECT" | "DISMISS" | "DISMISS_QUICK_SHARE_BANNER" | "GOTO_HISTORY" | "OVP_VIA_DEEP_LINK" | "QRLOGIN_VIA_DEEP_LINK" | "RESET" | "SCREEN_BLUR" | "xstate.init";
"resetShowQuickShareSuccessBanner": "DISMISS" | "DISMISS_QUICK_SHARE_BANNER";
"sendBLEConnectionErrorEvent": "BLE_ERROR";
"sendScanData": "" | "SCAN";
"sendVCShareFlowCancelEndEvent": "CANCEL";
"sendVCShareFlowTimeoutEndEvent": "CANCEL" | "RETRY";
"sendVPScanData": "SCAN";
"sendVPScanData": "" | "SCAN";
"sendVcShareSuccessEvent": "VC_ACCEPTED";
"sendVcSharingStartEvent": "SCAN";
"setAuthRequestFromDeepLink": "OVP_VIA_DEEP_LINK" | "SCAN";
"setBleError": "BLE_ERROR";
"setFlowType": "SELECT_VC";
"setIsOVPViaDeepLink": "OVP_VIA_DEEP_LINK";
"setIsQrLoginViaDeepLink": "QRLOGIN_VIA_DEEP_LINK";
"setLinkCode": "SCAN";
"setLinkCodeFromDeepLink": "QRLOGIN_VIA_DEEP_LINK";
"setOpenId4VPFlowType": "SCAN";
"setOpenId4VPRef": "CANCEL" | "DISCONNECT" | "DISMISS" | "DISMISS_QUICK_SHARE_BANNER" | "QRLOGIN_VIA_DEEP_LINK" | "RESET" | "RETRY" | "SCREEN_BLUR" | "SCREEN_FOCUS" | "SELECT_VC" | "xstate.init";
"setOpenId4VPFlowType": "" | "OVP_VIA_DEEP_LINK" | "SCAN";
"setOpenId4VPRef": "CANCEL" | "DISCONNECT" | "DISMISS" | "DISMISS_QUICK_SHARE_BANNER" | "OVP_VIA_DEEP_LINK" | "QRLOGIN_VIA_DEEP_LINK" | "RESET" | "RETRY" | "SCREEN_BLUR" | "SCREEN_FOCUS" | "SELECT_VC" | "xstate.init";
"setQrLoginRef": "QRLOGIN_VIA_DEEP_LINK" | "SCAN";
"setQuickShareData": "SCAN";
"setReadyForBluetoothStateCheck": "BLUETOOTH_PERMISSION_ENABLED";
@@ -89,11 +94,13 @@
"SHARING_TIMEOUT": "ACCEPT_REQUEST" | "CHECK_FLOW_TYPE" | "FACE_VALID";
};
eventsCausingGuards: {
"isFlowTypeMiniViewShare": "CHECK_FLOW_TYPE";
"isFlowTypeDeepLink": "START_PERMISSION_CHECK";
"isFlowTypeMiniViewShare": "CHECK_FLOW_TYPE";
"isFlowTypeMiniViewShareWithSelfie": "CHECK_FLOW_TYPE" | "DISMISS";
"isFlowTypeSimpleShare": "CANCEL" | "CHECK_FLOW_TYPE" | "DISMISS" | "RETRY";
"isIOS": "BLUETOOTH_STATE_DISABLED" | "START_PERMISSION_CHECK";
"isMinimumStorageRequiredForAuditEntryReached": "done.invoke.scan.checkStorage:invocation[0]";
"isOVPViaDeepLink": "";
"isOnlineSharing": "SCAN";
"isOpenIdQr": "SCAN";
"isQrLogin": "SCAN";
@@ -103,23 +110,23 @@
"uptoAndroid11": "" | "START_PERMISSION_CHECK";
};
eventsCausingServices: {
"OpenId4VP": "SCAN";
"OpenId4VP": "" | "SCAN";
"QrLogin": "" | "SCAN";
"checkBluetoothPermission": "" | "BLUETOOTH_STATE_DISABLED" | "NEARBY_ENABLED" | "START_PERMISSION_CHECK";
"checkBluetoothState": "" | "APP_ACTIVE";
"checkLocationPermission": "LOCATION_ENABLED";
"checkLocationStatus": "" | "APP_ACTIVE" | "LOCATION_REQUEST";
"checkNearByDevicesPermission": "APP_ACTIVE" | "START_PERMISSION_CHECK";
"checkStorageAvailability": "CANCEL" | "DISMISS" | "QRLOGIN_VIA_DEEP_LINK" | "RESET" | "RETRY" | "SCREEN_FOCUS" | "SELECT_VC";
"checkStorageAvailability": "CANCEL" | "DISMISS" | "OVP_VIA_DEEP_LINK" | "QRLOGIN_VIA_DEEP_LINK" | "RESET" | "RETRY" | "SCREEN_FOCUS" | "SELECT_VC";
"disconnect": "" | "DISMISS" | "LOCATION_ENABLED" | "RETRY" | "SCREEN_BLUR";
"monitorConnection": "DISMISS" | "QRLOGIN_VIA_DEEP_LINK" | "SCREEN_BLUR" | "xstate.init";
"monitorConnection": "DISMISS" | "OVP_VIA_DEEP_LINK" | "QRLOGIN_VIA_DEEP_LINK" | "SCREEN_BLUR" | "xstate.init";
"requestBluetooth": "BLUETOOTH_STATE_DISABLED";
"requestNearByDevicesPermission": "NEARBY_DISABLED";
"requestToEnableLocationPermission": "LOCATION_DISABLED";
"sendVc": "ACCEPT_REQUEST" | "CHECK_FLOW_TYPE" | "FACE_VALID";
"startConnection": "SCAN";
};
matchesStates: "bluetoothDenied" | "bluetoothPermissionDenied" | "checkBluetoothPermission" | "checkBluetoothPermission.checking" | "checkBluetoothPermission.enabled" | "checkBluetoothState" | "checkBluetoothState.checking" | "checkBluetoothState.enabled" | "checkBluetoothState.requesting" | "checkFaceAuthConsent" | "checkNearbyDevicesPermission" | "checkNearbyDevicesPermission.checking" | "checkNearbyDevicesPermission.enabled" | "checkNearbyDevicesPermission.requesting" | "checkQrLoginViaDeepLink" | "checkStorage" | "checkingLocationState" | "checkingLocationState.LocationPermissionRationale" | "checkingLocationState.checkLocationService" | "checkingLocationState.checkingPermissionStatus" | "checkingLocationState.denied" | "checkingLocationState.disabled" | "checkingLocationState.requestToEnableLocation" | "clearingConnection" | "connecting" | "connecting.inProgress" | "connecting.timeout" | "decodeQuickShareData" | "disconnectDevice" | "disconnected" | "findingConnection" | "handlingBleError" | "inactive" | "invalid" | "loadVCS" | "loadVCS.idle" | "loadVCS.navigatingToHome" | "nearByDevicesPermissionDenied" | "recheckBluetoothState" | "recheckBluetoothState.checking" | "recheckBluetoothState.enabled" | "restrictSharingVc" | "reviewing" | "reviewing.accepted" | "reviewing.cancelling" | "reviewing.checkFaceAuthConsentForMiniView" | "reviewing.disconnect" | "reviewing.faceVerificationConsent" | "reviewing.idle" | "reviewing.invalidIdentity" | "reviewing.navigateToHistory" | "reviewing.rejected" | "reviewing.selectingVc" | "reviewing.sendingVc" | "reviewing.sendingVc.inProgress" | "reviewing.sendingVc.sent" | "reviewing.sendingVc.timeout" | "reviewing.verifyingIdentity" | "showQrLogin" | "showQrLogin.idle" | "showQrLogin.navigatingToHistory" | "showQrLogin.navigatingToHome" | "showQrLogin.storing" | "startPermissionCheck" | "startVPSharing" | "startVPSharing.inProgress" | "startVPSharing.showError" | "startVPSharing.success" | "startVPSharing.timeout" | { "checkBluetoothPermission"?: "checking" | "enabled";
matchesStates: "bluetoothDenied" | "bluetoothPermissionDenied" | "checkBluetoothPermission" | "checkBluetoothPermission.checking" | "checkBluetoothPermission.enabled" | "checkBluetoothState" | "checkBluetoothState.checking" | "checkBluetoothState.enabled" | "checkBluetoothState.requesting" | "checkFaceAuthConsent" | "checkForDeepLinkFlow" | "checkNearbyDevicesPermission" | "checkNearbyDevicesPermission.checking" | "checkNearbyDevicesPermission.enabled" | "checkNearbyDevicesPermission.requesting" | "checkStorage" | "checkingLocationState" | "checkingLocationState.LocationPermissionRationale" | "checkingLocationState.checkLocationService" | "checkingLocationState.checkingPermissionStatus" | "checkingLocationState.denied" | "checkingLocationState.disabled" | "checkingLocationState.requestToEnableLocation" | "clearingConnection" | "connecting" | "connecting.inProgress" | "connecting.timeout" | "decodeQuickShareData" | "disconnectDevice" | "disconnected" | "findingConnection" | "handlingBleError" | "inactive" | "invalid" | "loadVCS" | "loadVCS.idle" | "loadVCS.navigatingToHome" | "nearByDevicesPermissionDenied" | "recheckBluetoothState" | "recheckBluetoothState.checking" | "recheckBluetoothState.enabled" | "restrictSharingVc" | "reviewing" | "reviewing.accepted" | "reviewing.cancelling" | "reviewing.checkFaceAuthConsentForMiniView" | "reviewing.disconnect" | "reviewing.faceVerificationConsent" | "reviewing.idle" | "reviewing.invalidIdentity" | "reviewing.navigateToHistory" | "reviewing.rejected" | "reviewing.selectingVc" | "reviewing.sendingVc" | "reviewing.sendingVc.inProgress" | "reviewing.sendingVc.sent" | "reviewing.sendingVc.timeout" | "reviewing.verifyingIdentity" | "showQrLogin" | "showQrLogin.idle" | "showQrLogin.navigatingToHistory" | "showQrLogin.navigatingToHome" | "showQrLogin.storing" | "startPermissionCheck" | "startVPSharing" | "startVPSharing.inProgress" | "startVPSharing.showError" | "startVPSharing.success" | "startVPSharing.timeout" | { "checkBluetoothPermission"?: "checking" | "enabled";
"checkBluetoothState"?: "checking" | "enabled" | "requesting";
"checkNearbyDevicesPermission"?: "checking" | "enabled" | "requesting";
"checkingLocationState"?: "LocationPermissionRationale" | "checkLocationService" | "checkingPermissionStatus" | "denied" | "disabled" | "requestToEnableLocation";

View File

@@ -53,6 +53,7 @@ export const openID4VPActions = (model: any) => {
setSelectedVCs: model.assign({
selectedVCs: (_, event) => event.selectedVCs,
selectedDisclosuresByVc: (_, event) => event.selectedDisclosuresByVc,
}),
compareAndStoreSelectedVC: model.assign({
@@ -166,6 +167,14 @@ export const openID4VPActions = (model: any) => {
},
}),
showTrustConsentModal: assign({
showTrustConsentModal: () => true,
}),
dismissTrustModal: assign({
showTrustConsentModal: () => false,
}),
setSendVPShareError: model.assign({
error: (_, event) => {
console.error('Error:', event.data.message, event.data.code);
@@ -329,7 +338,6 @@ function areVCFormatAndProofTypeMatchingRequest(
return false;
}
const vcFormatType = vc.format;
if (vcFormatType === VCFormat.ldp_vc) {
const vcProofType = vc?.verifiableCredential?.credential?.proof?.type;
return Object.entries(requestFormat).some(
@@ -361,6 +369,23 @@ function areVCFormatAndProofTypeMatchingRequest(
}
}
if (
vcFormatType === VCFormat.dc_sd_jwt ||
vcFormatType === VCFormat.vc_sd_jwt
) {
try {
const sdJwt = vc.verifiableCredential?.credential;
const alg = extractAlgFromSdJwt(sdJwt);
return Object.entries(requestFormat).some(
([type, value]) => type === vcFormatType && value["sd-jwt_alg_values"]?.includes(alg),
);
} catch (e) {
console.error('Error processing SD-JWT alg match:', e);
return false;
}
}
return false;
}
@@ -396,6 +421,29 @@ function isVCMatchingRequestConstraints(
});
});
}
function extractAlgFromSdJwt(sdJwtCompact: string): string {
const parts = sdJwtCompact.trim().split('~');
const jwt = parts[0];
const jwtParts = jwt.split('.');
if (jwtParts.length < 3) {
throw new Error('Invalid SD-JWT format');
}
const headerJson = JSON.parse(base64UrlDecode(jwtParts[0]));
if (!headerJson.alg) {
throw new Error('Missing alg in SD-JWT header');
}
return headerJson.alg;
}
function base64UrlDecode(input: string): string {
input = input.replace(/-/g, '+').replace(/_/g, '/');
while (input.length % 4) {
input += '=';
}
return Buffer.from(input, 'base64').toString('utf8');
}
function fetchCredentialBasedOnFormat(vc: any) {
const format = vc.format;
@@ -411,6 +459,11 @@ function fetchCredentialBasedOnFormat(vc: any) {
);
break;
}
case VCFormat.vc_sd_jwt || VCFormat.dc_sd_jwt: {
credential =
vc.verifiableCredential.processedCredential.fullResolvedPayload;
break;
}
}
return credential;
}

View File

@@ -120,7 +120,7 @@ export const openID4VPMachine = model.createMachine(
src: 'getAuthenticationResponse',
onDone: {
actions: 'setAuthenticationResponse',
target: 'getVCsSatisfyingAuthRequest',
target: 'checkVerifierTrust',
},
onError: {
actions: 'setAuthenticationError',
@@ -129,7 +129,65 @@ export const openID4VPMachine = model.createMachine(
},
exit: 'resetIsShowLoadingScreen',
},
checkVerifierTrust: {
invoke: {
src: 'isVerifierTrusted',
onDone: [
{
cond: (ctx, e) => e.data === true,
target: 'getVCsSatisfyingAuthRequest',
},
{
target: 'requestVerifierConsent',
},
],
onError: {
target: 'requestVerifierConsent',
},
},
},
requestVerifierConsent: {
entry: ['showTrustConsentModal'],
on: {
VERIFIER_TRUST_CONSENT_GIVEN: {
actions: 'dismissTrustModal',
target: 'storeTrustedVerifier',
},
CANCEL: {
actions: 'dismissTrustModal',
target: 'delayBeforeDismissToParent',
},
},
},
delayBeforeDismissToParent: {
after: {
200: 'sendDismissToParent',
},
},
sendDismissToParent: {
entry: sendParent('DISMISS'),
always: 'waitingForData',
},
storeTrustedVerifier: {
invoke: {
src: 'storeTrustedVerifier',
onDone: {
target: 'getVCsSatisfyingAuthRequest',
},
onError: {
actions: model.assign({
error: () => 'failed to update trusted verifier list',
}),
target: 'showError',
},
},
},
getVCsSatisfyingAuthRequest: {
entry:["dismissTrustModal"],
on: {
DOWNLOADED_VCS: [
{

View File

@@ -1,218 +0,0 @@
// This file was automatically generated. Edits will be overwritten
export interface Typegen0 {
'@@xstate/typegen': true;
internalEvents: {
'done.invoke.OpenID4VP.authenticateVerifier:invocation[0]': {
type: 'done.invoke.OpenID4VP.authenticateVerifier:invocation[0]';
data: unknown;
__tip: 'See the XState TS docs to learn how to strongly type this.';
};
'done.invoke.OpenID4VP.checkIfClientValidationIsRequired:invocation[0]': {
type: 'done.invoke.OpenID4VP.checkIfClientValidationIsRequired:invocation[0]';
data: unknown;
__tip: 'See the XState TS docs to learn how to strongly type this.';
};
'done.invoke.OpenID4VP.checkKeyPair:invocation[0]': {
type: 'done.invoke.OpenID4VP.checkKeyPair:invocation[0]';
data: unknown;
__tip: 'See the XState TS docs to learn how to strongly type this.';
};
'done.invoke.OpenID4VP.getKeyPairFromKeystore:invocation[0]': {
type: 'done.invoke.OpenID4VP.getKeyPairFromKeystore:invocation[0]';
data: unknown;
__tip: 'See the XState TS docs to learn how to strongly type this.';
};
'done.invoke.OpenID4VP.getTrustedVerifiersList:invocation[0]': {
type: 'done.invoke.OpenID4VP.getTrustedVerifiersList:invocation[0]';
data: unknown;
__tip: 'See the XState TS docs to learn how to strongly type this.';
};
'done.invoke.OpenID4VP.sendingVP:invocation[0]': {
type: 'done.invoke.OpenID4VP.sendingVP:invocation[0]';
data: unknown;
__tip: 'See the XState TS docs to learn how to strongly type this.';
};
'error.platform.OpenID4VP.authenticateVerifier:invocation[0]': {
type: 'error.platform.OpenID4VP.authenticateVerifier:invocation[0]';
data: unknown;
};
'error.platform.OpenID4VP.checkKeyPair:invocation[0]': {
type: 'error.platform.OpenID4VP.checkKeyPair:invocation[0]';
data: unknown;
};
'error.platform.OpenID4VP.getKeyPairFromKeystore:invocation[0]': {
type: 'error.platform.OpenID4VP.getKeyPairFromKeystore:invocation[0]';
data: unknown;
};
'error.platform.OpenID4VP.getTrustedVerifiersList:invocation[0]': {
type: 'error.platform.OpenID4VP.getTrustedVerifiersList:invocation[0]';
data: unknown;
};
'error.platform.OpenID4VP.sendingVP:invocation[0]': {
type: 'error.platform.OpenID4VP.sendingVP:invocation[0]';
data: unknown;
};
'xstate.init': {type: 'xstate.init'};
'xstate.stop': {type: 'xstate.stop'};
};
invokeSrcNameMap: {
fetchTrustedVerifiers: 'done.invoke.OpenID4VP.getTrustedVerifiersList:invocation[0]';
getAuthenticationResponse: 'done.invoke.OpenID4VP.authenticateVerifier:invocation[0]';
getKeyPair: 'done.invoke.OpenID4VP.getKeyPairFromKeystore:invocation[0]';
getSelectedKey: 'done.invoke.OpenID4VP.checkKeyPair:invocation[0]';
sendVP: 'done.invoke.OpenID4VP.sendingVP:invocation[0]';
shouldValidateClient: 'done.invoke.OpenID4VP.checkIfClientValidationIsRequired:invocation[0]';
};
missingImplementations: {
actions:
| 'compareAndStoreSelectedVC'
| 'forwardToParent'
| 'getFaceAuthConsent'
| 'getVcsMatchingAuthRequest'
| 'incrementOpenID4VPRetryCount'
| 'loadKeyPair'
| 'logActivity'
| 'resetError'
| 'resetFaceCaptureBannerStatus'
| 'resetIsFaceVerificationRetryAttempt'
| 'resetIsShareWithSelfie'
| 'resetIsShowLoadingScreen'
| 'resetOpenID4VPRetryCount'
| 'setAuthenticationError'
| 'setAuthenticationResponse'
| 'setError'
| 'setFlowType'
| 'setIsFaceVerificationRetryAttempt'
| 'setIsOVPViaDeepLink'
| 'setIsShareWithSelfie'
| 'setIsShowLoadingScreen'
| 'setMiniViewShareSelectedVC'
| 'setSelectedVCs'
| 'setSendVPShareError'
| 'setShareLogTypeUnverified'
| 'setShowFaceAuthConsent'
| 'setTrustedVerifiers'
| 'setTrustedVerifiersApiCallError'
| 'setUrlEncodedAuthorizationRequest'
| 'shareDeclineStatus'
| 'storeShowFaceAuthConsent'
| 'updateFaceCaptureBannerStatus'
| 'updateShowFaceAuthConsent';
delays: never;
guards:
| 'hasKeyPair'
| 'isAnyVCHasImage'
| 'isClientValidationRequred'
| 'isFaceVerificationRetryAttempt'
| 'isSelectedVCMatchingRequest'
| 'isShareWithSelfie'
| 'isSimpleOpenID4VPShare'
| 'showFaceAuthConsentScreen';
services:
| 'fetchTrustedVerifiers'
| 'getAuthenticationResponse'
| 'getKeyPair'
| 'getSelectedKey'
| 'sendVP'
| 'shouldValidateClient';
};
eventsCausingActions: {
compareAndStoreSelectedVC: 'SET_SELECTED_VC';
forwardToParent: 'CANCEL' | 'DISMISS_POPUP';
getFaceAuthConsent: 'AUTHENTICATE';
getVcsMatchingAuthRequest: 'DOWNLOADED_VCS';
incrementOpenID4VPRetryCount: 'RETRY';
loadKeyPair: 'done.invoke.OpenID4VP.getKeyPairFromKeystore:invocation[0]';
logActivity: 'LOG_ACTIVITY';
resetError: 'RESET_ERROR';
resetFaceCaptureBannerStatus: 'ACCEPT_REQUEST' | 'CLOSE_BANNER';
resetIsFaceVerificationRetryAttempt: 'DISMISS';
resetIsShareWithSelfie: 'CANCEL' | 'DISMISS_POPUP';
resetIsShowLoadingScreen:
| 'DISMISS_POPUP'
| 'done.invoke.OpenID4VP.authenticateVerifier:invocation[0]'
| 'error.platform.OpenID4VP.authenticateVerifier:invocation[0]'
| 'xstate.stop';
resetOpenID4VPRetryCount: 'RESET_RETRY_COUNT';
setAuthenticationError: 'error.platform.OpenID4VP.authenticateVerifier:invocation[0]';
setAuthenticationResponse: 'done.invoke.OpenID4VP.authenticateVerifier:invocation[0]';
setError:
| 'error.platform.OpenID4VP.checkKeyPair:invocation[0]'
| 'error.platform.OpenID4VP.getKeyPairFromKeystore:invocation[0]';
setFlowType: 'AUTHENTICATE';
setIsFaceVerificationRetryAttempt: 'FACE_INVALID';
setIsOVPViaDeepLink: 'AUTHENTICATE';
setIsShareWithSelfie: 'AUTHENTICATE';
setIsShowLoadingScreen: 'AUTHENTICATE';
setMiniViewShareSelectedVC: 'AUTHENTICATE';
setSelectedVCs: 'ACCEPT_REQUEST' | 'VERIFY_AND_ACCEPT_REQUEST';
setSendVPShareError: 'error.platform.OpenID4VP.sendingVP:invocation[0]';
setShareLogTypeUnverified: 'ACCEPT_REQUEST';
setShowFaceAuthConsent: 'FACE_VERIFICATION_CONSENT';
setTrustedVerifiers: 'done.invoke.OpenID4VP.getTrustedVerifiersList:invocation[0]';
setTrustedVerifiersApiCallError: 'error.platform.OpenID4VP.getTrustedVerifiersList:invocation[0]';
setUrlEncodedAuthorizationRequest: 'AUTHENTICATE';
shareDeclineStatus: 'CONFIRM';
storeShowFaceAuthConsent: 'FACE_VERIFICATION_CONSENT';
updateFaceCaptureBannerStatus: 'FACE_VALID';
updateShowFaceAuthConsent: 'done.invoke.OpenID4VP.checkIfClientValidationIsRequired:invocation[0]';
};
eventsCausingDelays: {
SHARING_TIMEOUT: 'CONFIRM' | 'FACE_VALID' | 'RETRY';
};
eventsCausingGuards: {
hasKeyPair:
| 'FACE_VALID'
| 'done.invoke.OpenID4VP.checkKeyPair:invocation[0]';
isAnyVCHasImage: 'CHECK_FOR_IMAGE';
isClientValidationRequred: 'done.invoke.OpenID4VP.checkIfClientValidationIsRequired:invocation[0]';
isFaceVerificationRetryAttempt: 'FACE_INVALID';
isSelectedVCMatchingRequest: 'CHECK_SELECTED_VC';
isShareWithSelfie:
| 'CONFIRM'
| 'done.invoke.OpenID4VP.sendingVP:invocation[0]';
isSimpleOpenID4VPShare:
| 'CANCEL'
| 'DISMISS'
| 'DISMISS_POPUP'
| 'DOWNLOADED_VCS'
| 'FACE_VERIFICATION_CONSENT';
showFaceAuthConsentScreen: 'CONFIRM';
};
eventsCausingServices: {
fetchTrustedVerifiers: 'done.invoke.OpenID4VP.checkIfClientValidationIsRequired:invocation[0]';
getAuthenticationResponse: 'done.invoke.OpenID4VP.checkKeyPair:invocation[0]';
getKeyPair:
| 'done.invoke.OpenID4VP.checkIfClientValidationIsRequired:invocation[0]'
| 'done.invoke.OpenID4VP.getTrustedVerifiersList:invocation[0]';
getSelectedKey:
| 'FACE_VALID'
| 'done.invoke.OpenID4VP.getKeyPairFromKeystore:invocation[0]';
sendVP: 'CONFIRM' | 'FACE_VALID' | 'RETRY';
shouldValidateClient: 'STORE_RESPONSE';
};
matchesStates:
| 'authenticateVerifier'
| 'checkFaceAuthConsent'
| 'checkIfAnySelectedVCHasImage'
| 'checkIfClientValidationIsRequired'
| 'checkIfMatchingVCsHasSelectedVC'
| 'checkKeyPair'
| 'faceVerificationConsent'
| 'getConsentForVPSharing'
| 'getKeyPairFromKeystore'
| 'getTrustedVerifiersList'
| 'getVCsSatisfyingAuthRequest'
| 'invalidIdentity'
| 'selectingVCs'
| 'sendingVP'
| 'setSelectedVC'
| 'shareVPDeclineStatusToVerifier'
| 'showConfirmationPopup'
| 'showError'
| 'success'
| 'verifyingIdentity'
| 'waitingForData';
tags: never;
}

View File

@@ -16,11 +16,14 @@ const openID4VPEvents = {
vcKey,
inputDescriptorId,
}),
ACCEPT_REQUEST: (selectedVCs: Record<string, VC[]>) => ({
ACCEPT_REQUEST: (selectedVCs: Record<string, VC[]>,selectedDisclosuresByVc: any) => ({
selectedVCs,
selectedDisclosuresByVc
}),
VERIFY_AND_ACCEPT_REQUEST: (selectedVCs: Record<string, VC[]>) => ({
VERIFIER_TRUST_CONSENT_GIVEN: () => ({}),
VERIFY_AND_ACCEPT_REQUEST: (selectedVCs: Record<string, VC[]>,selectedDisclosuresByVc) => ({
selectedVCs,
selectedDisclosuresByVc
}),
CONFIRM: () => ({}),
CANCEL: () => ({}),
@@ -52,6 +55,7 @@ export const openID4VPModel = createModel(
vcsMatchingAuthRequest: {} as Record<string, VC[]>,
checkedAll: false as boolean,
selectedVCs: {} as Record<string, VC[]>,
selectedDisclosuresByVc: {} as Record<string, string[]>,
isShareWithSelfie: false as boolean,
showFaceAuthConsent: true as boolean,
purpose: '' as string,
@@ -68,6 +72,7 @@ export const openID4VPModel = createModel(
requestedClaims: '' as string,
showLoadingScreen: false as boolean,
isOVPViaDeepLink: false,
showTrustConsentModal: false as boolean,
},
{events: openID4VPEvents},
);

View File

@@ -126,3 +126,19 @@ export function selectVerifierNameInVPSharing(state: State) {
export function selectRequestedClaimsByVerifier(state: State) {
return state.context.requestedClaims;
}
export function selectshowTrustConsentModal(state: State) {
return state.context.showTrustConsentModal;
}
export function selectVerifierNameInTrustModal(state: State) {
return (
state.context.authenticationResponse['client_metadata']?.['client_name']
);
}
export function selectVerifierLogoInTrustModal(state: State) {
return (
state.context.authenticationResponse['client_metadata']?.['logo_uri']
);
}

View File

@@ -9,12 +9,13 @@ import OpenID4VP from '../../shared/openID4VP/OpenID4VP';
import {VCFormat} from '../../shared/VCFormat';
import {KeyTypes} from '../../shared/cryptoutil/KeyTypes';
import {getMdocAuthenticationAlorithm} from '../../components/VC/common/VCUtils';
import {isIOS} from '../../shared/constants';
import {canonicalize} from '../../shared/Utils';
import {isIOS, JWT_ALG_TO_KEY_TYPE} from '../../shared/constants';
import {canonicalize, getVerifierKey} from '../../shared/Utils';
import {
constructDetachedJWT,
isClientValidationRequired,
} from '../../shared/openID4VP/OpenID4VPHelper';
import {NativeModules} from 'react-native';
const signatureSuite = 'JsonWebSignature2020';
@@ -35,6 +36,41 @@ export const openID4VPServices = () => {
);
},
isVerifierTrusted: (context: any) => async () => {
const {RNSecureKeystoreModule} = NativeModules;
const verifier = context.authenticationResponse?.client_id;
try {
return await RNSecureKeystoreModule.hasAlias(getVerifierKey(verifier));
} catch (error) {
console.error(
`Error while checking verifier client ID in trusted verifiers:`,
error,
);
return false;
}
},
storeTrustedVerifier: (context: any) => async () => {
const {RNSecureKeystoreModule} = NativeModules;
const verifier = context.authenticationResponse?.client_id;
const trustValue = JSON.stringify({
trusted: true,
createdAt: new Date().toISOString(),
});
try {
return await RNSecureKeystoreModule.storeData(
getVerifierKey(verifier),
trustValue,
);
} catch (error) {
console.error(
`Error while storing verifier client ID in trusted verifiers:`,
error,
);
return false;
}
},
getKeyPair: async (context: any) => {
if (!!(await hasKeyPair(context.keyType))) {
return await fetchKeyPair(context.keyType);
@@ -51,6 +87,7 @@ export const openID4VPServices = () => {
const unSignedVpTokens = await OpenID4VP.constructUnsignedVPToken(
context.selectedVCs,
context.selectedDisclosuresByVc,
holderId,
signatureSuite,
);
@@ -132,6 +169,32 @@ export const openID4VPServices = () => {
);
vpTokenSigningResultMap[formatType] = signedData;
} else if (
formatType === VCFormat.vc_sd_jwt.valueOf() ||
formatType === VCFormat.dc_sd_jwt.valueOf()
) {
const uuidToUnsignedKBJWT = credentials.uuidToUnsignedKBT;
const uuidToSignature: Record<string, string> = {};
for (const [uuid, unsignedKBJWT] of Object.entries(
uuidToUnsignedKBJWT,
)) {
const header = JSON.parse(atob(unsignedKBJWT.split('.')[0]));
const alg = header.alg;
const keyType = JWT_ALG_TO_KEY_TYPE[alg];
const signature = await createSignature(
context.privateKey,
unsignedKBJWT,
keyType,
);
if (signature) {
uuidToSignature[uuid] = signature;
} else {
throw new Error(`Failed to create signature for UUID: ${uuid}`);
}
}
vpTokenSigningResultMap[formatType] = uuidToSignature;
}
}
return await OpenID4VP.shareVerifiablePresentation(
@@ -140,3 +203,4 @@ export const openID4VPServices = () => {
},
};
};

View File

@@ -39,45 +39,4 @@
matchesStates: "idle" | "selectingNext" | "selectingPrev";
tags: never;
}
// This file was automatically generated. Edits will be overwritten
export interface Typegen0 {
'@@xstate/typegen': true;
internalEvents: {
"": { type: "" };
"xstate.after(INITIAL_FOCUS_DELAY)#pinInput.idle": { type: "xstate.after(INITIAL_FOCUS_DELAY)#pinInput.idle" };
"xstate.init": { type: "xstate.init" };
};
invokeSrcNameMap: {
};
missingImplementations: {
actions: never;
delays: never;
guards: never;
services: never;
};
eventsCausingActions: {
"clearInput": "KEY_PRESS";
"focusSelected": "KEY_PRESS" | "UPDATE_INPUT" | "xstate.after(INITIAL_FOCUS_DELAY)#pinInput.idle";
"selectInput": "FOCUS_INPUT";
"selectNextInput": "UPDATE_INPUT";
"selectPrevInput": "KEY_PRESS";
"updateInput": "UPDATE_INPUT";
};
eventsCausingDelays: {
"INITIAL_FOCUS_DELAY": "" | "xstate.init";
};
eventsCausingGuards: {
"canGoBack": "KEY_PRESS";
"hasNextInput": "UPDATE_INPUT";
"isBlank": "UPDATE_INPUT";
};
eventsCausingServices: {
};
matchesStates: "idle" | "selectingNext" | "selectingPrev";
tags: never;
}

View File

@@ -37,7 +37,7 @@ import { QrScanner } from '../../components/QrScanner';
import { IssuersModel } from '../../machines/Issuers/IssuersModel';
import { AUTH_ROUTES } from '../../routes/routesConstants';
import { TransactionCodeModal } from './TransactionCodeScreen';
import { TrustIssuerModal } from './TrustIssuerModal';
import { TrustModal } from '../../components/TrustModal';
import i18next from 'i18next';
export const IssuersScreen: React.FC<
HomeRouteProps | RootRouteProps
@@ -288,7 +288,7 @@ export const IssuersScreen: React.FC<
}
function issuerTrustConsentComponent() {
return <TrustIssuerModal isVisible={true} issuerLogo={controller.issuerLogo} issuerName={controller.issuerName} onConfirm={controller.ON_CONSENT_GIVEN} onCancel={controller.CANCEL} />
return <TrustModal isVisible={true} logo={controller.issuerLogo} name={controller.issuerName} onConfirm={controller.ON_CONSENT_GIVEN} onCancel={controller.CANCEL} />
}
return (

View File

@@ -17,12 +17,14 @@ import {Text} from './../../components/ui';
import {BannerStatusType} from '../../components/BannerNotification';
import {isIOS, LIVENESS_CHECK} from '../../shared/constants';
import {SendVPScreen} from './SendVPScreen';
import { useSendVPScreen } from './SendVPScreenController';
const ScanStack = createNativeStackNavigator();
export const ScanLayout: React.FC = () => {
const {t} = useTranslation('ScanScreen');
const controller = useScanLayout();
const sendVPScreenController = useSendVPScreen();
if (
controller.statusOverlay != null &&
!controller.isAccepted &&
@@ -161,7 +163,7 @@ export const ScanLayout: React.FC = () => {
/>
)}
</ScanStack.Navigator>
<SharingStatusModal
isVisible={controller.isAccepted || controller.isVPSharingSuccess}
testId={'sharingSuccessModal'}
@@ -178,6 +180,8 @@ export const ScanLayout: React.FC = () => {
image={SvgImage.SuccessLogo()}
goToHome={controller.GOTO_HOME}
goToHistory={controller.GOTO_HISTORY}
verifierLogo={controller.openID4VPFlowType == VCShareFlowType.OPENID4VP ? sendVPScreenController.verifierLogoInTrustModal ?? undefined : undefined}
verifierName={controller.openID4VPFlowType == VCShareFlowType.OPENID4VP ? sendVPScreenController.verifierNameInTrustModal ?? t('unknownVerifier') : undefined}
/>
{controller.errorStatusOverlay && (

View File

@@ -1,41 +1,42 @@
import {useFocusEffect} from '@react-navigation/native';
import React, {useContext, useEffect, useLayoutEffect, useState} from 'react';
import {useTranslation} from 'react-i18next';
import {BackHandler, I18nManager, View} from 'react-native';
import {Button, Column, Row, Text} from '../../components/ui';
import {Theme} from '../../components/ui/styleUtils';
import {VcItemContainer} from '../../components/VC/VcItemContainer';
import { useFocusEffect } from '@react-navigation/native';
import React, { useContext, useEffect, useLayoutEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { BackHandler, I18nManager, View } from 'react-native';
import { Button, Column, Row, Text } from '../../components/ui';
import { Theme } from '../../components/ui/styleUtils';
import { VcItemContainer } from '../../components/VC/VcItemContainer';
import {
isIOS,
LIVENESS_CHECK,
OVP_ERROR_MESSAGES,
OVP_ERROR_CODE,
} from '../../shared/constants';
import {TelemetryConstants} from '../../shared/telemetry/TelemetryConstants';
import { TelemetryConstants } from '../../shared/telemetry/TelemetryConstants';
import {
getImpressionEventData,
sendImpressionEvent,
} from '../../shared/telemetry/TelemetryUtils';
import {VCItemContainerFlowType} from '../../shared/Utils';
import {VCMetadata} from '../../shared/VCMetadata';
import {VerifyIdentityOverlay} from '../VerifyIdentityOverlay';
import {VPShareOverlay} from './VPShareOverlay';
import {FaceVerificationAlertOverlay} from './FaceVerificationAlertOverlay';
import {useSendVPScreen} from './SendVPScreenController';
import { VCItemContainerFlowType } from '../../shared/Utils';
import { VCMetadata } from '../../shared/VCMetadata';
import { VerifyIdentityOverlay } from '../VerifyIdentityOverlay';
import { VPShareOverlay } from './VPShareOverlay';
import { FaceVerificationAlertOverlay } from './FaceVerificationAlertOverlay';
import { useSendVPScreen } from './SendVPScreenController';
import LinearGradient from 'react-native-linear-gradient';
import {Error} from '../../components/ui/Error';
import {SvgImage} from '../../components/ui/svg';
import {Loader} from '../../components/ui/Loader';
import {Icon} from 'react-native-elements';
import {ScanLayoutProps} from '../../routes/routeTypes';
import { Error } from '../../components/ui/Error';
import { SvgImage } from '../../components/ui/svg';
import { Loader } from '../../components/ui/Loader';
import { Icon } from 'react-native-elements';
import { ScanLayoutProps } from '../../routes/routeTypes';
import OpenID4VP from '../../shared/openID4VP/OpenID4VP';
import {GlobalContext} from '../../shared/GlobalContext';
import {APP_EVENTS} from '../../machines/app';
import {useScanScreen} from './ScanScreenController';
import {useOvpErrorModal} from '../../shared/hooks/useOvpErrorModal';
import { GlobalContext } from '../../shared/GlobalContext';
import { APP_EVENTS } from '../../machines/app';
import { useScanScreen } from './ScanScreenController';
import { useOvpErrorModal } from '../../shared/hooks/useOvpErrorModal';
import { TrustModal } from '../../components/TrustModal';
export const SendVPScreen: React.FC<ScanLayoutProps> = props => {
const {t} = useTranslation('SendVPScreen');
const { t } = useTranslation('SendVPScreen');
const controller = useSendVPScreen();
const scanScreenController = useScanScreen();
@@ -50,8 +51,18 @@ export const SendVPScreen: React.FC<ScanLayoutProps> = props => {
const vcsMatchingAuthRequest = controller.vcsMatchingAuthRequest;
const {appService} = useContext(GlobalContext);
const { appService } = useContext(GlobalContext);
const [triggerExitFlow, setTriggerExitFlow] = useState(false);
const [selectedDisclosuresByVc, setSelectedDisclosuresByVc] =
useState<Record<string, string[]>>({});
const handleDisclosureChange = (vcKey: string, disclosures: string[]) => {
setSelectedDisclosuresByVc(prev => ({
...prev,
[vcKey]: disclosures,
}));
};
useEffect(() => {
if (errorModal.show && controller.isOVPViaDeepLink) {
@@ -270,10 +281,14 @@ export const SendVPScreen: React.FC<ScanLayoutProps> = props => {
return (
<React.Fragment>
{<TrustModal isVisible={controller.showTrustConsentModal}
logo={controller.verifierLogoInTrustModal} name={controller.verifierNameInTrustModal ?? t('ScanScreen:unknownVerifier')}
onConfirm={controller.VERIFIER_TRUST_CONSENT_GIVEN}
onCancel={controller.CANCEL} flowType='verifier'></TrustModal>}
{Object.keys(vcsMatchingAuthRequest).length > 0 && (
<>
{controller.purpose !== '' && (
<View style={{backgroundColor: Theme.Colors.whiteBackgroundColor}}>
<View style={{ backgroundColor: Theme.Colors.whiteBackgroundColor }}>
<Column
padding="14 12 14 12"
margin="20 20 20 20"
@@ -340,6 +355,9 @@ export const SendVPScreen: React.FC<ScanLayoutProps> = props => {
}
flow={VCItemContainerFlowType.VP_SHARE}
isPinned={vcData.vcMetadata.isPinned}
onDisclosuresChange={(disclosures) => {
handleDisclosureChange(getVcKey(vcData), disclosures)
}}
/>
)),
)}
@@ -347,40 +365,40 @@ export const SendVPScreen: React.FC<ScanLayoutProps> = props => {
<Column
style={[
Theme.SendVcScreenStyles.shareOptionButtonsContainer,
{position: 'relative'},
{ position: 'relative' },
]}
backgroundColor={Theme.Colors.whiteBackgroundColor}>
{!controller.checkIfAllVCsHasImage(
controller.vcsMatchingAuthRequest,
) && (
<Button
type="gradient"
styles={{marginTop: 12}}
title={t('SendVcScreen:acceptRequest')}
disabled={
Object.keys(controller.getSelectedVCs()).length === 0 ||
controller.checkIfAnyVCHasImage(controller.getSelectedVCs())
}
onPress={controller.ACCEPT_REQUEST}
/>
)}
<Button
type="gradient"
styles={{ marginTop: 12 }}
title={t('SendVcScreen:acceptRequest')}
disabled={
Object.keys(controller.getSelectedVCs()).length === 0 ||
controller.checkIfAnyVCHasImage(controller.getSelectedVCs())
}
onPress={() => controller.ACCEPT_REQUEST(selectedDisclosuresByVc)}
/>
)}
{/*If one of the selected vc has image, it needs to sent only after biometric authentication (Share with Selfie)*/}
{controller.checkIfAnyVCHasImage(
controller.vcsMatchingAuthRequest,
) && (
<Button
type="gradient"
title={t('SendVcScreen:acceptRequestAndVerify')}
styles={{marginTop: 12}}
disabled={
Object.keys(controller.getSelectedVCs()).length === 0 ||
!controller.checkIfAnyVCHasImage(
controller.getSelectedVCs(),
)
}
onPress={controller.VERIFY_AND_ACCEPT_REQUEST}
/>
)}
<Button
type="gradient"
title={t('SendVcScreen:acceptRequestAndVerify')}
styles={{ marginTop: 12 }}
disabled={
Object.keys(controller.getSelectedVCs()).length === 0 ||
!controller.checkIfAnyVCHasImage(
controller.getSelectedVCs(),
)
}
onPress={()=>controller.VERIFY_AND_ACCEPT_REQUEST(selectedDisclosuresByVc)}
/>
)}
<Button
type="clear"
@@ -451,8 +469,8 @@ export const SendVPScreen: React.FC<ScanLayoutProps> = props => {
textButtonTestID={'home'}
textButtonText={getTextButtonText()}
textButtonEvent={handleTextButtonEvent}
customImageStyles={{paddingBottom: 0, marginBottom: -6}}
customStyles={{marginTop: '30%'}}
customImageStyles={{ paddingBottom: 0, marginBottom: -6 }}
customStyles={{ marginTop: '30%' }}
exitAppWithTimer={controller.isOVPViaDeepLink}
testID={'vpShareError'}
/>

View File

@@ -28,8 +28,11 @@ import {
selectRequestedClaimsByVerifier,
selectSelectedVCs,
selectShowConfirmationPopup,
selectshowTrustConsentModal,
selectVCsMatchingAuthRequest,
selectVerifiableCredentialsData,
selectVerifierLogoInTrustModal,
selectVerifierNameInTrustModal,
selectVerifierNameInVPSharing,
} from '../../machines/openID4VP/openID4VPSelectors';
import {OpenID4VPEvents} from '../../machines/openID4VP/openID4VPMachine';
@@ -46,6 +49,7 @@ import {ActivityLogEvents} from '../../machines/activityLog';
import {VPShareActivityLog} from '../../components/VPShareActivityLogEvent';
import {SelectedCredentialsForVPSharing} from '../../machines/VerifiableCredential/VCMetaMachine/vc';
import {isIOS} from '../../shared/constants';
import { verifier } from '../../shared/tuvali';
type MyVcsTabNavigation = NavigationProp<RootRouteProps>;
@@ -218,6 +222,9 @@ export function useSendVPScreen() {
showLoadingScreen: useSelector(openID4VPService, selectIsShowLoadingScreen),
vpVerifierName,
flowType: useSelector(openID4VPService, selectFlowType),
showTrustConsentModal: useSelector(openID4VPService,selectshowTrustConsentModal),
verifierNameInTrustModal: useSelector(openID4VPService, selectVerifierNameInTrustModal),
verifierLogoInTrustModal: useSelector(openID4VPService, selectVerifierLogoInTrustModal),
showConfirmationPopup,
isSelectingVCs,
checkIfAnyVCHasImage,
@@ -302,13 +309,17 @@ export function useSendVPScreen() {
setSelectedVCKeys({...updatedVCsList});
},
ACCEPT_REQUEST: () => {
openID4VPService.send(OpenID4VPEvents.ACCEPT_REQUEST(getSelectedVCs()));
ACCEPT_REQUEST: (selectedDisclosuresByVc) => {
openID4VPService.send(OpenID4VPEvents.ACCEPT_REQUEST(getSelectedVCs(), selectedDisclosuresByVc));
},
VERIFY_AND_ACCEPT_REQUEST: () => {
VERIFIER_TRUST_CONSENT_GIVEN: () =>{
openID4VPService.send(OpenID4VPEvents.VERIFIER_TRUST_CONSENT_GIVEN());
},
VERIFY_AND_ACCEPT_REQUEST: (selectedDisclosuresByVc) => {
openID4VPService.send(
OpenID4VPEvents.VERIFY_AND_ACCEPT_REQUEST(getSelectedVCs()),
OpenID4VPEvents.VERIFY_AND_ACCEPT_REQUEST(getSelectedVCs(), selectedDisclosuresByVc),
);
},
CANCEL,

View File

@@ -1,15 +1,17 @@
import React, {useEffect} from 'react';
import {useTranslation} from 'react-i18next';
import {Theme} from '../../components/ui/styleUtils';
import {Modal} from '../../components/ui/Modal';
import {Pressable, Dimensions, BackHandler} from 'react-native';
import {Button, Column, Row, Text} from '../../components/ui';
import React, { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Theme } from '../../components/ui/styleUtils';
import { Modal } from '../../components/ui/Modal';
import { Pressable, Dimensions, BackHandler, View, Image } from 'react-native';
import { Button, Column, Row, Text } from '../../components/ui';
import testIDProps from '../../shared/commonUtil';
import {SvgImage} from '../../components/ui/svg';
import {isIOS} from '../../shared/constants';
import { SvgImage } from '../../components/ui/svg';
import { isIOS } from '../../shared/constants';
export const SharingStatusModal: React.FC<SharingStatusModalProps> = props => {
const {t} = useTranslation('ScanScreen');
const { t } = useTranslation('ScanScreen');
const [logoFailed, setLogoFailed] = useState(false);
const showLogo = !!props.verifierLogo && !logoFailed;
const resetAndExit = () => {
BackHandler.exitApp();
props.goToHome();
@@ -65,16 +67,45 @@ export const SharingStatusModal: React.FC<SharingStatusModalProps> = props => {
size={'large'}>
{props.additionalMessage}
</Text>
{(props.verifierLogo || props.verifierName) && <Row
align="center"
style={Theme.SelectVcOverlayStyles.sharedSuccessfullyVerifierInfo}
>
{showLogo && (
<Image
source={{ uri: props.verifierLogo }}
style={Theme.SelectVcOverlayStyles.sharedSuccessfullyVerifierLogo}
resizeMode="contain"
onError={() => setLogoFailed(true)}
/>
)}
<View style={{ alignItems: 'flex-start' }}>
<Text
style={Theme.TextStyles.bold}
>
{props.verifierName}
</Text>
<Text
style={{
fontSize: 13,
color: '#666',
marginTop: 2,
}}
>
{`Today at ${new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}`}
</Text>
</View>
</Row>}
</Column>
{props.buttonStatus === 'homeAndHistoryIcons' ? (
<Row
align="space-evenly"
style={{marginBottom: Dimensions.get('screen').height * 0.06}}>
style={{ marginBottom: Dimensions.get('screen').height * 0.06 }}>
<Column>
<Pressable
accessible={false}
testID="successfullyVcSharedHomeIcon"
style={{height: 75, justifyContent: 'space-between'}}
style={{ height: 75, justifyContent: 'space-between' }}
onPress={props.goToHome}>
{SvgImage.SuccessHomeIcon()}
<Text align="center" weight="bold">
@@ -87,7 +118,7 @@ export const SharingStatusModal: React.FC<SharingStatusModalProps> = props => {
<Pressable
accessible={false}
testID="successfullyVcSharedHistoryIcon"
style={{height: 75, justifyContent: 'space-between'}}
style={{ height: 75, justifyContent: 'space-between' }}
onPress={props.goToHistory}>
{SvgImage.SuccessHistoryIcon()}
<Text align="center" weight="bold">
@@ -99,7 +130,7 @@ export const SharingStatusModal: React.FC<SharingStatusModalProps> = props => {
) : null}
{props.gradientButtonTitle && (
<Column
style={{marginBottom: Dimensions.get('screen').height * 0.012}}>
style={{ marginBottom: Dimensions.get('screen').height * 0.012 }}>
<Button
testID="failedVcSharedRetryButton"
type="gradient"
@@ -113,7 +144,7 @@ export const SharingStatusModal: React.FC<SharingStatusModalProps> = props => {
<Button
testID="failedVcSharedHomeButton"
type="clear"
styles={{marginBottom: 9}}
styles={{ marginBottom: 9 }}
title={props.clearButtonTitle}
onPress={props.onClearButton}
/>
@@ -138,4 +169,6 @@ interface SharingStatusModalProps {
goToHistory?: () => void;
onGradientButton?: () => void;
onClearButton?: () => void;
verifierName?: string;
verifierLogo?: string;
}

View File

@@ -139,3 +139,7 @@ export const createCacheObject = (response: any) => {
export const isCacheExpired = (timestamp: number) => {
return Date.now() - timestamp >= CACHE_TTL;
};
export function getVerifierKey(verifier: string): string {
return `trusted_verifier_${verifier}`;
}

View File

@@ -153,6 +153,15 @@ export function useOvpErrorModal({
showRetryButton: true,
});
generateAndStoreLogMessage('SEND_VP_ERROR');
} else if (error.includes('failed to update trusted verifier list')) {
setErrorModal({
show: true,
title: t('errors.trustedVerifierListUpdateError.title'),
message: t('errors.trustedVerifierListUpdateError.message'),
additionalMessage,
showRetryButton: false,
});
generateAndStoreLogMessage('TRUSTED_VERIFIER_LIST_UPDATE_ERROR');
} else if (error !== '') {
setErrorModal({
show: true,

View File

@@ -7,6 +7,8 @@ import {
import {walletMetadata} from './walletMetadata';
import {getWalletMetadata, isClientValidationRequired} from './OpenID4VPHelper';
import {parseJSON} from '../Utils';
import {VCFormat} from '../VCFormat';
import {VCMetadata} from '../VCMetadata';
export const OpenID4VP_Proof_Sign_Algo = 'EdDSA';
@@ -45,12 +47,16 @@ class OpenID4VP {
static async constructUnsignedVPToken(
selectedVCs: Record<string, VC[]>,
selectedDisclosuresByVc: any,
holderId: string,
signatureAlgorithm: string,
) {
const openID4VP = await OpenID4VP.getInstance();
const updatedSelectedVCs = openID4VP.processSelectedVCs(selectedVCs);
const updatedSelectedVCs = openID4VP.processSelectedVCs(
selectedVCs,
selectedDisclosuresByVc,
);
const unSignedVpTokens =
await openID4VP.InjiOpenID4VP.constructUnsignedVPToken(
updatedSelectedVCs,
@@ -76,12 +82,21 @@ class OpenID4VP {
});
}
private processSelectedVCs(selectedVCs: Record<string, VC[]>) {
private processSelectedVCs(
selectedVCs: Record<string, VC[]>,
selectedDisclosuresByVc: any,
) {
const selectedVcsData: SelectedCredentialsForVPSharing = {};
Object.entries(selectedVCs).forEach(([inputDescriptorId, vcsArray]) => {
vcsArray.forEach(vcData => {
const credentialFormat = vcData.vcMetadata.format;
const credential = vcData.verifiableCredential.credential;
const credential = this.extractCredential(
vcData,
credentialFormat,
selectedDisclosuresByVc[
VCMetadata.fromVcMetadataString(vcData.vcMetadata).getVcKey()
],
);
if (!selectedVcsData[inputDescriptorId]) {
selectedVcsData[inputDescriptorId] = {};
}
@@ -93,6 +108,55 @@ class OpenID4VP {
});
return selectedVcsData;
}
private extractCredential(
vcData: VC,
credentialFormat: string,
selectedDisclosures: any,
) {
if (
credentialFormat === VCFormat.mso_mdoc ||
credentialFormat === VCFormat.ldp_vc
) {
return vcData.verifiableCredential.credential;
}
if (
credentialFormat === VCFormat.vc_sd_jwt ||
credentialFormat === VCFormat.dc_sd_jwt
) {
return this.processSdJwtVcForSharing(vcData, selectedDisclosures);
}
}
private processSdJwtVcForSharing(
vcData: VC,
selectedDisclosures: string[],
): string {
if (!vcData?.verifiableCredential?.credential) {
throw new Error('Invalid VC: missing credential');
}
const compact = vcData.verifiableCredential.credential;
const [jwt] = compact.split('~');
const pathToDisclosures: Record<string, string[]> =
vcData.verifiableCredential?.processedCredential.pathToDisclosures || {};
const disclosureSet = new Set<string>();
selectedDisclosures?.forEach(path => {
const disclosures = pathToDisclosures[path];
if (disclosures) {
disclosures.forEach(d => disclosureSet.add(d));
}
});
const finalSdJwt =
disclosureSet.size > 0
? [jwt, ...disclosureSet].join('~') + '~'
: jwt + '~';
return finalSdJwt;
}
}
export default OpenID4VP;

View File

@@ -12,6 +12,9 @@ export const walletMetadata = {
mso_mdoc: {
alg_values_supported: ['ES256'],
},
"vc+sd-jwt": {
alg_values_supported: ['EdDSA','ES256'],
},
},
client_id_schemes_supported: ['redirect_uri', 'did', 'pre-registered'],
request_object_signing_alg_values_supported: ['EdDSA'],