[INJIMOB-1078] use credentialConfigurationId instead of credentialDefinition's type

To identify matching issuer metadata details exposed by wellknown of the VC, previously credentialDefinition's type was used now it is getting replaced by credentialConfigurationId (this holds the keyValues of credential_configrations_supported object)

Signed-off-by: KiruthikaJeyashankar <81218987+KiruthikaJeyashankar@users.noreply.github.com>
This commit is contained in:
KiruthikaJeyashankar
2024-09-13 15:30:27 +05:30
parent 7b0e48a3a8
commit 7e0d180b05
20 changed files with 122 additions and 126 deletions

View File

@@ -20,7 +20,7 @@ export type ActivityLogType =
export class ActivityLog {
id: string;
idType: string[];
credentialConfigurationId: string;
_vcKey: string;
timestamp: number;
deviceName: string;
@@ -53,13 +53,20 @@ export class ActivityLog {
deviceName: '',
vcLabel: '',
issuer: '',
id: '',
credentialConfigurationId: '',
};
}
}
export function getActionText(activity: ActivityLog, t, wellknown: Object) {
if (activity.idType && activity.idType.length !== 0) {
const cardType = getIdType(wellknown, activity.idType);
console.log('getActionText ', JSON.stringify(activity, null, 2));
console.log('getActionText ', JSON.stringify(wellknown, null, 2));
if (!!activity.credentialConfigurationId) {
const cardType = getIdType(
wellknown,
activity.credentialConfigurationId,
);
return `${t(activity.type, {idType: cardType, id: activity.id})}`;
}
return `${t(activity.type, {idType: '', id: activity.id})}`;

View File

@@ -36,15 +36,15 @@ export const VCCardView: React.FC<VCItemProps> = props => {
const [wellknown, setWellknown] = useState(null);
useEffect(() => {
const {issuer, wellKnown, credentialTypes, credentialConfigurationId} =
const {issuer, wellKnown, credentialConfigurationId, vcMetadata: {format}} =
verifiableCredentialData;
console.log('issuer ', issuer);
if (wellKnown) {
getCredentialIssuersWellKnownConfig(
issuer,
credentialTypes,
CARD_VIEW_DEFAULT_FIELDS,
credentialConfigurationId,
format
)
.then(response => {
setWellknown(response.wellknown);

View File

@@ -16,10 +16,10 @@ import {MIMOTO_BASE_URL} from '../../../shared/constants';
import {VCItemDetailsProps} from '../Views/VCDetailView';
import {
getMatchingCredentialIssuerMetadata,
getSelectedCredentialTypeDetails,
iterateMsoMdocFor,
} from '../../../shared/openId4VCI/Utils';
import {parseJSON} from '../../../shared/Utils';
import {VCItemContentProps} from '../Views/VCCardViewContent';
export const CARD_VIEW_DEFAULT_FIELDS = ['fullName'];
export const DETAIL_VIEW_DEFAULT_FIELDS = [
@@ -37,6 +37,7 @@ export const DETAIL_VIEW_ADD_ON_FIELDS = [
'status',
'credentialRegistry',
'idType',
'issuing_country',
];
export const DETAIL_VIEW_BOTTOM_SECTION_FIELDS = [
@@ -264,9 +265,8 @@ export const getMosipLogo = () => {
*/
export const getIdType = (
wellknown: CredentialTypes | IssuerWellknownResponse,
idType?: string[],
credentialConfigurationId: string | undefined = undefined,
) => {
): string => {
if (wellknown && wellknown?.display) {
console.log('getIdType if case');
@@ -274,27 +274,37 @@ export const getIdType = (
return {language: displayProps.locale, value: displayProps.name};
});
return getLocalizedField(idTypeObj);
} else if (
wellknown &&
Object.keys(wellknown).length > 0 &&
idType !== undefined
) {
} else if (wellknown && Object.keys(wellknown).length > 0) {
let supportedCredentialsWellknown;
wellknown = parseJSON(wellknown) as unknown as Object[];
if (!!!wellknown['credential_configurations_supported']) {
return i18n.t('VcDetails:nationalCard');
}
console.log('getIdType else if case');
//TODO: Get supported credentials wellknown based on credentialConfigurationId rather than idType
if (credentialConfigurationId) {
supportedCredentialsWellknown = getMatchingCredentialIssuerMetadata(wellknown,credentialConfigurationId)
} else {
supportedCredentialsWellknown = getSelectedCredentialTypeDetails(
wellknown,
idType,
try {
if (!!credentialConfigurationId) {
console.log('credentialConfigurationId avl');
supportedCredentialsWellknown = getMatchingCredentialIssuerMetadata(
wellknown,
credentialConfigurationId,
);
} else {
console.error('credentialConfigurationId not available for fetching the ID type');
throw new Error(
`invalid credential credentialConfigurationId - ${credentialConfigurationId} passed`,
);
}
} catch (error) {
console.error(
`error occurred while getting supported credential's ${credentialConfigurationId} wellknown`,
);
return i18n.t('VcDetails:nationalCard');
}
console.log(
'supportedCredentialsWellknown ',
supportedCredentialsWellknown,
);
if (Object.keys(supportedCredentialsWellknown).length === 0) {
return i18n.t('VcDetails:nationalCard');
}
@@ -305,18 +315,7 @@ export const getIdType = (
}
};
export const getCredentialTypes = (
credential: Credential | VerifiableCredential,
): string[] => {
return (credential?.credentialTypes as string[]) ?? ['VerifiableCredential'];
};
export function DisplayName(
props: VCItemContentProps,
):
| string
| Object
| import('/Users/kiruthikajeyashankar/MyWorkspace/Projects/MOSIP/tw-mosip/inji/machines/VerifiableCredential/VCMetaMachine/vc').LocalizedField[] {
export function DisplayName(props: VCItemContentProps): string | Object {
console.log('display name ', JSON.stringify(props.credential, null, 2));
console.log(
'props.verifiableCredentialData.format ',

View File

@@ -225,6 +225,10 @@ export const IssuersActions = (model: any) => {
authorization_servers: event.data.authorization_servers,
}),
}),
updateSelectedIssuerWellknownResponse: model.assign({
selectedIssuerWellknownResponse: (_: any, event: any) => event.data,
}),
setSelectedIssuerId: model.assign({
selectedIssuerId: (_: any, event: any) => event.id,
}),
@@ -262,13 +266,12 @@ export const IssuersActions = (model: any) => {
_vcKey: vcMetadata.getVcKey(),
type: 'VC_DOWNLOADED',
id: vcMetadata.displayId,
idType:
context.credentialWrapper.verifiableCredential.credentialTypes,
timestamp: Date.now(),
deviceName: '',
issuer: context.selectedIssuerId,
credentialConfigurationId: context.selectedCredentialType.id,
},
context.selectedCredentialType,
context.selectedIssuerWellknownResponse,
);
},
{

View File

@@ -94,7 +94,7 @@ export const IssuersMachine = model.createMachine(
invoke: {
src: 'downloadIssuerWellknown',
onDone: {
actions: ['updateIssuerFromWellknown'],
actions: ['updateIssuerFromWellknown','updateSelectedIssuerWellknownResponse'],
target: 'downloadCredentialTypes',
},
onError: {

View File

@@ -148,6 +148,7 @@ export interface Typegen0 {
| 'storeVerifiableCredentialData'
| 'storeVerifiableCredentialMeta'
| 'updateIssuerFromWellknown'
| 'updateSelectedIssuerWellknownResponse'
| 'updateVerificationErrorMessage';
delays: never;
guards:
@@ -258,6 +259,7 @@ export interface Typegen0 {
| 'done.invoke.issuersMachine.verifyingCredential:invocation[0]'
| 'error.platform.issuersMachine.verifyingCredential:invocation[0]';
updateIssuerFromWellknown: 'done.invoke.issuersMachine.downloadIssuerWellknown:invocation[0]';
updateSelectedIssuerWellknownResponse: 'done.invoke.issuersMachine.downloadIssuerWellknown:invocation[0]';
updateVerificationErrorMessage: 'error.platform.issuersMachine.verifyingCredential:invocation[0]';
};
eventsCausingDelays: {};

View File

@@ -3,6 +3,7 @@ import {AuthorizeResult} from 'react-native-app-auth';
import {
CredentialTypes,
CredentialWrapper,
IssuerWellknownResponse,
VerifiableCredential,
} from '../VerifiableCredential/VCMetaMachine/vc';
import {AppServices} from '../../shared/GlobalContext';
@@ -15,6 +16,7 @@ export const IssuersModel = createModel(
issuers: [] as issuerType[],
selectedIssuerId: '' as string,
selectedIssuer: {} as issuerType,
selectedIssuerWellknownResponse: {} as IssuerWellknownResponse,
tokenResponse: {} as AuthorizeResult,
errorMessage: '' as string,
loadingReason: 'displayIssuers' as string,

View File

@@ -78,8 +78,6 @@ export function selectVerifiableCredentialData(state: State) {
?.credentialSubject?.face ||
state.context.selectedVc?.credential?.biometrics?.face,
wellKnown: state.context.selectedVc?.verifiableCredential?.wellKnown,
credentialTypes:
state.context.selectedVc?.verifiableCredential?.credentialTypes,
};
}

View File

@@ -3,11 +3,9 @@ import {CommunicationDetails} from '../../../shared/Utils';
import {StoreEvents} from '../../store';
import {VCMetadata} from '../../../shared/VCMetadata';
import {
API_CACHED_STORAGE_KEYS,
MIMOTO_BASE_URL,
MY_VCS_STORE_KEY,
} from '../../../shared/constants';
import {KeyPair} from 'react-native-rsa-native';
import i18n from '../../../i18n';
import {getHomeMachineService} from '../../../screens/Home/HomeScreenController';
import {DownloadProps} from '../../../shared/api';
@@ -31,7 +29,6 @@ import {BackupEvents} from '../../backupAndRestore/backup';
import {VcMetaEvents} from '../VCMetaMachine/VCMetaMachine';
import {WalletBindingResponse} from '../VCMetaMachine/vc';
import {BannerStatusType} from '../../../components/BannerNotification';
import {getCredentialTypes} from '../../../components/VC/common/VCUtils';
export const VCItemActions = model => {
return {
@@ -462,7 +459,7 @@ export const VCItemActions = model => {
type: 'VC_DOWNLOADED',
id: context.vcMetadata.displayId,
issuer: context.vcMetadata.issuer!!,
idType: getCredentialTypes(context.verifiableCredential),
credentialConfigurationId: context.verifiableCredential.credentialConfigurationId,
timestamp: Date.now(),
deviceName: '',
});
@@ -475,7 +472,7 @@ export const VCItemActions = model => {
(context: any, _) => {
const vcMetadata = VCMetadata.fromVC(context.vcMetadata);
return ActivityLogEvents.LOG_ACTIVITY({
idType: getCredentialTypes(context.verifiableCredential),
credentialConfigurationId: context.verifiableCredential.credentialConfigurationId,
issuer: vcMetadata.issuer!!,
id: vcMetadata.displayId,
_vcKey: vcMetadata.getVcKey(),
@@ -494,7 +491,7 @@ export const VCItemActions = model => {
return ActivityLogEvents.LOG_ACTIVITY({
_vcKey: vcMetadata.getVcKey(),
type: 'WALLET_BINDING_SUCCESSFULL',
idType: getCredentialTypes(context.verifiableCredential),
credentialConfigurationId: context.verifiableCredential.credentialConfigurationId,
issuer: vcMetadata.issuer!!,
id: vcMetadata.displayId,
timestamp: Date.now(),
@@ -513,7 +510,7 @@ export const VCItemActions = model => {
_vcKey: vcMetadata.getVcKey(),
type: 'WALLET_BINDING_FAILURE',
id: vcMetadata.displayId,
idType: getCredentialTypes(context.verifiableCredential),
credentialConfigurationId: context.verifiableCredential.credentialConfigurationId,
issuer: vcMetadata.issuer!!,
timestamp: Date.now(),
deviceName: '',

View File

@@ -56,7 +56,6 @@ export function selectVerifiableCredentialData(
wellKnown: state.context.verifiableCredential?.wellKnown,
credentialConfigurationId:
state.context.verifiableCredential?.credentialConfigurationId,
credentialTypes: state.context.verifiableCredential?.credentialTypes,
issuer: vcMetadata.issuer,
};
}

View File

@@ -36,7 +36,6 @@ import {
sendStartEvent,
} from '../../../shared/telemetry/TelemetryUtils';
import {TelemetryConstants} from '../../../shared/telemetry/TelemetryConstants';
import {getCredentialTypes} from '../../../components/VC/common/VCUtils';
import {EventTypes, VerificationStatus, verifier} from '../../../shared/tuvali';
@@ -619,9 +618,7 @@ export const requestMachine =
_vcKey: vcMetadata.getVcKey(),
type: context.receiveLogType,
id: vcMetadata.displayId,
idType: getCredentialTypes(
context.incomingVc.verifiableCredential,
),
credentialConfigurationId: context.incomingVc.verifiableCredential.credentialConfigurationId,
issuer: vcMetadata.issuer!!,
timestamp: Date.now(),
deviceName:

View File

@@ -30,8 +30,7 @@ export function selectVerifiableCredentialData(state: State) {
getMosipLogo(),
issuer: vcMetadata.issuer,
wellKnown: state.context.incomingVc?.verifiableCredential?.wellKnown,
credentialTypes:
state.context.incomingVc?.verifiableCredential?.credentialTypes,
credentialConfigurationId: state.context.verifiableCredential?.credentialConfigurationId,
};
}

View File

@@ -28,7 +28,6 @@ import {ActivityLogEvents} from '../../activityLog';
import {StoreEvents} from '../../store';
import BluetoothStateManager from 'react-native-bluetooth-state-manager';
import {NativeModules} from 'react-native';
import {getCredentialTypes} from '../../../components/VC/common/VCUtils';
import {wallet} from '../../../shared/tuvali';
@@ -201,7 +200,7 @@ export const ScanActions = (model: any, QR_LOGIN_REF_ID: any) => {
? context.shareLogType
: 'VC_SHARED_WITH_VERIFICATION_CONSENT',
id: vcMetadata.displayId,
idType: getCredentialTypes(context.selectedVc.verifiableCredential),
credentialConfigurationId: context.selectedVc.verifiableCredential.credentialConfigurationId,
issuer: vcMetadata.issuer!!,
timestamp: Date.now(),
deviceName:
@@ -218,7 +217,7 @@ export const ScanActions = (model: any, QR_LOGIN_REF_ID: any) => {
_vcKey: vcMetadata.getVcKey(),
type: 'PRESENCE_VERIFICATION_FAILED',
timestamp: Date.now(),
idType: getCredentialTypes(context.selectedVc.verifiableCredential),
credentialConfigurationId: context.selectedVc.verifiableCredential.credentialConfigurationId,
id: vcMetadata.displayId,
issuer: vcMetadata.issuer!!,
deviceName:
@@ -283,7 +282,7 @@ export const ScanActions = (model: any, QR_LOGIN_REF_ID: any) => {
_vcKey: '',
id: vcMetadata.displayId,
issuer: vcMetadata.issuer!!,
idType: getCredentialTypes(selectedVc.verifiableCredential),
credentialConfigurationId: selectedVc.verifiableCredential.credentialConfigurationId,
type: 'QRLOGIN_SUCCESFULL',
timestamp: Date.now(),
deviceName: '',

View File

@@ -37,8 +37,6 @@ export function selectVerifiableCredentialData(state: State) {
?.credentialSubject?.face ||
state.context.selectedVc?.credential?.biometrics?.face,
wellKnown: state.context.selectedVc?.verifiableCredential?.wellKnown,
credentialTypes:
state.context.selectedVc?.verifiableCredential?.credentialTypes,
};
}

View File

@@ -58,10 +58,10 @@ export const ViewVcModal: React.FC<ViewVcModalProps> = props => {
useEffect(() => {
getDetailedViewFields(
verifiableCredentialData?.issuer,
verifiableCredentialData?.credentialTypes,
verifiableCredentialData.issuer as string,
verifiableCredentialData.credentialConfigurationId,
DETAIL_VIEW_DEFAULT_FIELDS,
verifiableCredentialData.vcMetadata.format
).then(response => {
setWellknown(response.wellknown);
setFields(response.fields);

View File

@@ -27,8 +27,9 @@ export const ReceiveVcScreen: React.FC = () => {
useEffect(() => {
getDetailedViewFields(
verifiableCredentialData?.issuer,
verifiableCredentialData?.credentialTypes,
verifiableCredentialData.credentialConfigurationId,
DETAIL_VIEW_DEFAULT_FIELDS,
verifiableCredentialData.vcMetadata.format
).then(response => {
setWellknown(response.wellknown);
setFields(response.fields);

6
shared/VCFormat.ts Normal file
View File

@@ -0,0 +1,6 @@
//This enum exposes the supported vc formats of the app
export enum VCFormat {
ldp_vc = 'ldp_vc',
mso_mdoc = 'mso_mdoc',
}

View File

@@ -6,7 +6,6 @@ import {
} from '../machines/VerifiableCredential/VCMetaMachine/vc';
import {CredentialIdForMsoMdoc, Protocols} from './openId4VCI/Utils';
import {getMosipIdentifier} from './commonUtil';
import {format} from 'date-fns';
const VC_KEY_PREFIX = 'VC';
const VC_ITEM_STORE_KEY_REGEX = '^VC_[a-zA-Z0-9_-]+$';

View File

@@ -0,0 +1,6 @@
export class UnsupportedVcFormat extends Error {
constructor(format: string) {
super(format);
this.name = 'UnsupportedVcFormat';
}
}

View File

@@ -1,7 +1,6 @@
import jwtDecode from 'jwt-decode';
import jose from 'node-jose';
import {isIOS} from '../constants';
import pem2jwk from 'simple-pem2jwk';
import {displayType, issuerType} from '../../machines/Issuers/IssuersMachine';
import getAllConfigurations, {CACHED_API} from '../api';
import base64url from 'base64url';
@@ -17,7 +16,6 @@ import {
BOTTOM_SECTION_FIELDS_WITH_DETAILED_ADDRESS_FIELDS,
DETAIL_VIEW_ADD_ON_FIELDS,
getIdType,
getCredentialTypes,
} from '../../components/VC/common/VCUtils';
import {getVerifiableCredential} from '../../machines/VerifiableCredential/VCItemMachine/VCItemSelectors';
import {vcVerificationBannerDetails} from '../../components/BannerNotificationContainer';
@@ -25,6 +23,10 @@ import {getErrorEventData, sendErrorEvent} from '../telemetry/TelemetryUtils';
import {TelemetryConstants} from '../telemetry/TelemetryConstants';
import {NativeModules} from 'react-native';
import {KeyTypes} from '../cryptoutil/KeyTypes';
import {VCFormat} from '../VCFormat';
import {UnsupportedVcFormat} from '../error/UnsupportedVCFormat';
import {VCMetadata} from '../VCMetadata';
export const Protocols = {
OpenId4VCI: 'OpenId4VCI',
OTP: 'OTP',
@@ -38,14 +40,14 @@ export const Issuers = {
//
export function getVcVerificationDetails(
statusType,
vcMetadata,
vcMetadata: VCMetadata,
verifiableCredential,
wellknown: Object,
): vcVerificationBannerDetails {
//TODO: get id type from configId rather than credential types
const idType = getIdType(
wellknown,
getCredentialTypes(getVerifiableCredential(verifiableCredential)),
getVerifiableCredential(verifiableCredential).credentialConfigurationId,
);
return {
statusType: statusType,
@@ -115,7 +117,6 @@ export const updateCredentialInformation = (
...credential,
wellKnown: context.selectedIssuer['.well-known'],
credentialConfigurationId: context.selectedCredentialType.id,
credentialTypes: credential.credential.type ?? ['VerifiableCredential'],
issuerLogo: getDisplayObjectForCurrentLanguage(
context.selectedIssuer.display,
)?.logo,
@@ -163,75 +164,56 @@ export const constructAuthorizationConfiguration = (
};
};
export const getSelectedCredentialTypeDetails = (
wellknown: any,
vcCredentialTypes: Object[],
): Object => {
console.log(
'getSelectedCredentialTypeDetails wellknown ',
JSON.stringify(wellknown, null, 2),
);
console.log(
'getSelectedCredentialTypeDetails vcCredentialTypes',
JSON.stringify(vcCredentialTypes, null, 2),
);
for (let credential in wellknown.credential_configurations_supported) {
const credentialDetails =
wellknown.credential_configurations_supported[credential];
//TODO: What is t
if (
JSON.stringify(credentialDetails.credential_definition?.type) ===
JSON.stringify(vcCredentialTypes)
) {
return credentialDetails;
}
}
console.error(
'Selected credential type is not available in wellknown config supported credentials list',
);
sendErrorEvent(
getErrorEventData(
TelemetryConstants.FlowType.wellknownConfig,
TelemetryConstants.ErrorId.mismatch,
TelemetryConstants.ErrorMessage.wellknownConfigMismatch,
),
);
return {};
};
export const getCredentialIssuersWellKnownConfig = async (
issuer: string | undefined,
vcCredentialTypes: Object[] | undefined,
defaultFields: string[],
credentialConfigurationId?: string | undefined,
credentialConfigurationId: string,
format: string,
) => {
let fields: string[] = defaultFields;
let credentialDetails: any;
console.log('getCredentialIssuersWellKnownConfig ', issuer);
const response = await CACHED_API.fetchIssuerWellknownConfig(issuer!);
if (response) {
if (credentialConfigurationId) {
try {
if (response) {
credentialDetails = getMatchingCredentialIssuerMetadata(
response,
credentialConfigurationId,
);
} else {
console.log('no credentialConfigurationId is there');
credentialDetails = getSelectedCredentialTypeDetails(
response,
vcCredentialTypes!,
);
}
if (Object.keys(credentialDetails).includes('order')) {
fields = credentialDetails.order;
} else {
console.log('no order is there');
fields = Object.keys(
credentialDetails.credential_definition.credentialSubject,
);
if (Object.keys(credentialDetails).includes('order')) {
fields = credentialDetails.order;
} else {
console.log('no order is there');
if (format === VCFormat.mso_mdoc) {
fields = []
Object.keys(credentialDetails.claims).forEach(namespace => {
Object.keys(credentialDetails.claims[namespace]).forEach(claim => {
fields.concat(`${namespace}~${claim}`);
});
});
} else if (format === VCFormat.ldp_vc) {
fields = Object.keys(
credentialDetails.credential_definition.credentialSubject,
);
} else {
console.error(`Unsupported credential format - ${format} found`);
throw new UnsupportedVcFormat(format);
}
}
}
} catch (error) {
console.error(
`Error occurred while parsing well-known response of credential type - ${credentialConfigurationId} so returning default fields only. Error is `,
error.toString(),
);
return {
wellknown: credentialDetails,
fields: fields,
};
}
console.warn(
'Well-known response is not available for this credential so returning default fields only.',
);
return {
wellknown: credentialDetails,
fields: fields,
@@ -240,15 +222,15 @@ export const getCredentialIssuersWellKnownConfig = async (
export const getDetailedViewFields = async (
issuer: string,
vcCredentialTypes: Object[],
credentialConfigurationId: string,
defaultFields: string[],
format: string,
) => {
let response = await getCredentialIssuersWellKnownConfig(
issuer,
vcCredentialTypes,
defaultFields,
credentialConfigurationId,
format,
);
let updatedFieldsList = response.fields.concat(DETAIL_VIEW_ADD_ON_FIELDS);
@@ -479,5 +461,7 @@ export function getMatchingCredentialIssuerMetadata(
TelemetryConstants.ErrorMessage.wellknownConfigMismatch,
),
);
return {};
throw new Error(
`Selected credential type - ${credentialConfigurationId} is not available in wellknown config supported credentials list`,
);
}