mirror of
https://github.com/mosip/inji-wallet.git
synced 2026-01-09 13:38:01 -05:00
* [INJIMOB-3581] add revocation and reverification logic Signed-off-by: Abhishek Paul <paul.apaul.abhishek.ap@gmail.com> * [INJIMOB-3581] refactor readable array conversion to a shared utility Signed-off-by: Abhishek Paul <paul.apaul.abhishek.ap@gmail.com> --------- Signed-off-by: Abhishek Paul <paul.apaul.abhishek.ap@gmail.com>
488 lines
14 KiB
TypeScript
488 lines
14 KiB
TypeScript
import {
|
|
ErrorMessage,
|
|
getDisplayObjectForCurrentLanguage,
|
|
Issuers_Key_Ref,
|
|
OIDCErrors,
|
|
selectCredentialRequestKey,
|
|
} from '../../shared/openId4VCI/Utils';
|
|
import {
|
|
EXPIRED_VC_ERROR_CODE,
|
|
MY_VCS_STORE_KEY,
|
|
NO_INTERNET,
|
|
REQUEST_TIMEOUT,
|
|
isIOS,
|
|
} from '../../shared/constants';
|
|
import {assign, send} from 'xstate';
|
|
import {StoreEvents} from '../store';
|
|
import {BackupEvents} from '../backupAndRestore/backup/backupMachine';
|
|
import {getVCMetadata, VCMetadata} from '../../shared/VCMetadata';
|
|
import {isHardwareKeystoreExists} from '../../shared/cryptoutil/cryptoUtil';
|
|
import {ActivityLogEvents} from '../activityLog';
|
|
import {
|
|
getEndEventData,
|
|
getImpressionEventData,
|
|
sendEndEvent,
|
|
sendImpressionEvent,
|
|
} from '../../shared/telemetry/TelemetryUtils';
|
|
import {TelemetryConstants} from '../../shared/telemetry/TelemetryConstants';
|
|
import {NativeModules} from 'react-native';
|
|
import {VCActivityLog} from '../../components/ActivityLogEvent';
|
|
import {isNetworkError, parseJSON} from '../../shared/Utils';
|
|
import {issuerType} from './IssuersMachine';
|
|
|
|
const {RNSecureKeystoreModule} = NativeModules;
|
|
export const IssuersActions = (model: any) => {
|
|
return {
|
|
setVerificationResult: assign({
|
|
vcMetadata: (context: any, event: any) =>
|
|
new VCMetadata({
|
|
...context.vcMetadata,
|
|
isVerified: true,
|
|
isExpired: event.data.verificationErrorCode == EXPIRED_VC_ERROR_CODE,
|
|
isRevoked: event.data.isRevoked,
|
|
lastKnownStatusTimestamp: new Date().toISOString()
|
|
}),
|
|
}),
|
|
resetVerificationResult: assign({
|
|
vcMetadata: (context: any) =>
|
|
new VCMetadata({
|
|
...context.vcMetadata,
|
|
isVerified: false,
|
|
isExpired: false,
|
|
isRevoked: false,
|
|
}),
|
|
}),
|
|
setIssuers: model.assign({
|
|
issuers: (_: any, event: any) => event.data as issuerType[],
|
|
}),
|
|
setLoadingReasonAsDisplayIssuers: model.assign({
|
|
loadingReason: 'displayIssuers',
|
|
}),
|
|
setLoadingReasonAsDownloadingCredentials: model.assign({
|
|
loadingReason: 'downloadingCredentials',
|
|
}),
|
|
setLoadingReasonAsSettingUp: model.assign({
|
|
loadingReason: 'settingUp',
|
|
}),
|
|
resetLoadingReason: model.assign({
|
|
loadingReason: null,
|
|
}),
|
|
setSelectedCredentialType: model.assign({
|
|
selectedCredentialType: (_: any, event: any) => event.credType,
|
|
wellknownKeyTypes: (_: any, event: any) => {
|
|
const proofTypesSupported = event.credType.proof_types_supported;
|
|
if (proofTypesSupported?.jwt) {
|
|
return proofTypesSupported.jwt
|
|
.proof_signing_alg_values_supported as string[];
|
|
} else {
|
|
return [] as string[];
|
|
}
|
|
},
|
|
}),
|
|
setSupportedCredentialTypes: model.assign({
|
|
supportedCredentialTypes: (_: any, event: any) => event.data,
|
|
}),
|
|
resetSelectedCredentialType: model.assign({
|
|
selectedCredentialType: {},
|
|
}),
|
|
setCredentialTypeListDownloadFailureError: model.assign({
|
|
errorMessage: (_: any, event: any) => {
|
|
if (isNetworkError(event.data.message)) {
|
|
return ErrorMessage.NO_INTERNET;
|
|
}
|
|
return ErrorMessage.CREDENTIAL_TYPE_DOWNLOAD_FAILURE;
|
|
},
|
|
}),
|
|
|
|
setError: model.assign({
|
|
errorMessage: (_: any, event: any) => {
|
|
console.error(`Error occurred while ${event} -> `, event.data.message);
|
|
const error = event.data.message;
|
|
if (error.includes(NO_INTERNET)) {
|
|
return ErrorMessage.NO_INTERNET;
|
|
}
|
|
if (isNetworkError(error)) {
|
|
return ErrorMessage.NETWORK_REQUEST_FAILED;
|
|
}
|
|
if (error.includes(REQUEST_TIMEOUT)) {
|
|
return ErrorMessage.REQUEST_TIMEDOUT;
|
|
}
|
|
if (
|
|
error.includes(
|
|
OIDCErrors.AUTHORIZATION_ENDPOINT_DISCOVERY
|
|
.GRANT_TYPE_NOT_SUPPORTED,
|
|
)
|
|
) {
|
|
return ErrorMessage.AUTHORIZATION_GRANT_TYPE_NOT_SUPPORTED;
|
|
}
|
|
return ErrorMessage.GENERIC;
|
|
},
|
|
}),
|
|
resetError: model.assign({
|
|
errorMessage: '',
|
|
}),
|
|
|
|
loadKeyPair: assign({
|
|
publicKey: (_, event: any) => event.data?.publicKey as string,
|
|
privateKey: (context: any, event: any) =>
|
|
event.data?.privateKey
|
|
? event.data.privateKey
|
|
: (context.privateKey as string),
|
|
}),
|
|
getKeyPairFromStore: send(StoreEvents.GET(Issuers_Key_Ref), {
|
|
to: (context: any) => context.serviceRefs.store,
|
|
}),
|
|
sendBackupEvent: send(BackupEvents.DATA_BACKUP(true), {
|
|
to: (context: any) => context.serviceRefs.backup,
|
|
}),
|
|
storeKeyPair: async (context: any) => {
|
|
const keyType = context.keyType;
|
|
if ((keyType != 'ES256' && keyType != 'RS256') || isIOS())
|
|
await RNSecureKeystoreModule.storeGenericKey(
|
|
context.publicKey,
|
|
context.privateKey,
|
|
keyType,
|
|
);
|
|
},
|
|
|
|
storeVerifiableCredentialMeta: send(
|
|
context => StoreEvents.PREPEND(MY_VCS_STORE_KEY, context.vcMetadata),
|
|
{
|
|
to: (context: any) => context.serviceRefs.store,
|
|
},
|
|
),
|
|
|
|
setMetadataInCredentialData: (context: any) => {
|
|
context.credentialWrapper = {
|
|
...context.credentialWrapper,
|
|
vcMetadata: context.vcMetadata,
|
|
};
|
|
},
|
|
|
|
setVCMetadata: assign({
|
|
vcMetadata: (context: any) => {
|
|
return getVCMetadata(context, context.keyType);
|
|
},
|
|
}),
|
|
|
|
storeVerifiableCredentialData: send(
|
|
(context: any) => {
|
|
const vcMetadata = context.vcMetadata;
|
|
const credentialWrapper = context.credentialWrapper;
|
|
const storableData = {
|
|
...credentialWrapper,
|
|
verifiableCredential: {
|
|
...credentialWrapper.verifiableCredential,
|
|
},
|
|
};
|
|
return StoreEvents.SET(vcMetadata.getVcKey(), {
|
|
...storableData,
|
|
vcMetadata: vcMetadata,
|
|
});
|
|
},
|
|
{
|
|
to: (context: any) => context.serviceRefs.store,
|
|
},
|
|
),
|
|
|
|
storeVcMetaContext: send(
|
|
context => {
|
|
return {
|
|
type: 'VC_ADDED',
|
|
vcMetadata: context.vcMetadata,
|
|
};
|
|
},
|
|
{
|
|
to: (context: any) => context.serviceRefs.vcMeta,
|
|
},
|
|
),
|
|
|
|
storeVcsContext: send(
|
|
(context: any) => {
|
|
return {
|
|
type: 'VC_DOWNLOADED',
|
|
vcMetadata: context.vcMetadata,
|
|
vc: context.credentialWrapper,
|
|
};
|
|
},
|
|
{
|
|
to: context => context.serviceRefs.vcMeta,
|
|
},
|
|
),
|
|
|
|
setSelectedKey: model.assign({
|
|
keyType: (context: any, event: any) => {
|
|
const keyType = selectCredentialRequestKey(
|
|
context.wellknownKeyTypes,
|
|
event.data,
|
|
);
|
|
return keyType;
|
|
},
|
|
}),
|
|
|
|
setSelectedIssuers: model.assign({
|
|
selectedIssuer: (context: any, event: any) => {
|
|
return context.issuers.find(issuer => issuer.issuer_id === event.id);
|
|
},
|
|
}),
|
|
resetSelectedIssuer: model.assign({
|
|
selectedIssuer: () => ({} as issuerType),
|
|
}),
|
|
updateIssuerFromWellknown: model.assign({
|
|
selectedIssuer: (context: any, event: any) => ({
|
|
...context.selectedIssuer,
|
|
credential_endpoint: event.data.credential_endpoint,
|
|
credential_configurations_supported:
|
|
event.data.credential_configurations_supported,
|
|
display: event.data.display,
|
|
authorization_servers: event.data.authorization_servers,
|
|
}),
|
|
selectedIssuerWellknownResponse: (_: any, event: any) => {
|
|
return event.data;
|
|
},
|
|
}),
|
|
setCredential: model.assign({
|
|
credential: (_: any, event: any) => event.data.credential,
|
|
}),
|
|
setQrData: model.assign({
|
|
qrData: (_: any, event: any) => event.data,
|
|
}),
|
|
setCredentialOfferIssuer: model.assign({
|
|
selectedIssuer: (_: any, event: any) => {
|
|
return event.issuer;
|
|
},
|
|
}),
|
|
setAccessToken: model.assign({
|
|
accessToken: (_: any, event: any) => {
|
|
return event.data.access_token;
|
|
},
|
|
}),
|
|
setCNonce: model.assign({
|
|
cNonce: (_: any, event: any) => {
|
|
return event.cNonce;
|
|
},
|
|
}),
|
|
setCredentialConfigurationId: model.assign({
|
|
credentialConfigurationId: (_: any, event: any) => {
|
|
return event.data.credentialConfigurationId;
|
|
},
|
|
}),
|
|
setCredentialOfferCredentialType: model.assign({
|
|
selectedCredentialType: (context: any, event: any) => {
|
|
let credentialTypes: Array<{id: string; [key: string]: any}> = [];
|
|
const credentialConfigurationId = context.credentialConfigurationId;
|
|
const issuerMetadata = context.selectedIssuerWellknownResponse;
|
|
if (
|
|
issuerMetadata.credential_configurations_supported[
|
|
credentialConfigurationId
|
|
]
|
|
) {
|
|
credentialTypes.push({
|
|
id: credentialConfigurationId,
|
|
...issuerMetadata.credential_configurations_supported[
|
|
credentialConfigurationId
|
|
],
|
|
});
|
|
return credentialTypes[0];
|
|
}
|
|
},
|
|
}),
|
|
supportedCredentialTypes: (context: any, event: any) => {
|
|
return event.credentialTypes;
|
|
},
|
|
accessToken: (context: any, event: any) => {
|
|
return event.accessToken;
|
|
},
|
|
cNonce: (context: any, event: any) => {
|
|
return event.cNonce;
|
|
},
|
|
|
|
setRequestTxCode: model.assign({
|
|
isTransactionCodeRequested: (_: any, event: any) => {
|
|
return true;
|
|
},
|
|
}),
|
|
|
|
resetRequestTxCode: model.assign({
|
|
isTransactionCodeRequested: (_: any, event: any) => {
|
|
return false;
|
|
},
|
|
}),
|
|
setCredentialOfferIssuerWellknownResponse: model.assign({
|
|
selectedIssuer: (_: any, event: any) => {
|
|
return event.data;
|
|
},
|
|
selectedIssuerWellknownResponse: (_: any, event: any) => {
|
|
return event.data;
|
|
},
|
|
}),
|
|
setWellknwonKeyTypes: model.assign({
|
|
wellknownKeyTypes: (_: any, event: any) => {
|
|
return event.proofSigningAlgosSupported;
|
|
},
|
|
}),
|
|
setSelectedCredentialIssuer: model.assign({
|
|
credentialOfferCredentialIssuer: (_: any, event: any) => {
|
|
return event.issuer;
|
|
},
|
|
}),
|
|
setTokenRequestObject: model.assign({
|
|
tokenRequestObject: (_: any, event: any) => {
|
|
return parseJSON(event.tokenRequest);
|
|
},
|
|
}),
|
|
setTokenResponseObject: model.assign({
|
|
tokenResponse: (_: any, event: any) => {
|
|
return event.data;
|
|
},
|
|
}),
|
|
setSelectedIssuerId: model.assign({
|
|
selectedIssuerId: (_: any, event: any) => event.id,
|
|
}),
|
|
setTxCode: model.assign({
|
|
txCode: (_: any, event: any) => {
|
|
return event.txCode;
|
|
},
|
|
}),
|
|
setRequestConsentToTrustIssuer: model.assign({
|
|
isConsentRequested: (_: any, event: any) => {
|
|
return true;
|
|
},
|
|
}),
|
|
setTxCodeDisplayDetails: model.assign({
|
|
txCodeInputMode: (_: any, event: any) => event.inputMode,
|
|
txCodeDescription: (_: any, event: any) => event.description,
|
|
txCodeLength: (_: any, event: any) => event.length,
|
|
}),
|
|
setIssuerDisplayDetails: model.assign({
|
|
issuerLogo: (_: any, event: any) => {
|
|
const displayArray = event.issuerDisplay;
|
|
const display = displayArray
|
|
? getDisplayObjectForCurrentLanguage(displayArray)
|
|
: undefined;
|
|
|
|
return display?.logo?.url ?? '';
|
|
},
|
|
issuerName: (_: any, event: any) => {
|
|
const displayArray = event.issuerDisplay;
|
|
const display = displayArray
|
|
? getDisplayObjectForCurrentLanguage(displayArray)
|
|
: undefined;
|
|
return display?.name ?? '';
|
|
},
|
|
}),
|
|
|
|
setCredentialOfferFlowType: model.assign({
|
|
isCredentialOfferFlow: (_: any, event: any) => {
|
|
return true;
|
|
},
|
|
}),
|
|
|
|
resetCredentialOfferFlowType: model.assign({
|
|
isCredentialOfferFlow: (_: any, event: any) => {
|
|
return false;
|
|
},
|
|
}),
|
|
|
|
resetRequestConsentToTrustIssuer: model.assign({
|
|
isConsentRequested: (_: any, event: any) => {
|
|
return false;
|
|
},
|
|
}),
|
|
setVerifiableCredential: model.assign({
|
|
verifiableCredential: (_: any, event: any) => {
|
|
return event.data.verifiableCredential;
|
|
},
|
|
}),
|
|
setCredentialWrapper: model.assign({
|
|
credentialWrapper: (_: any, event: any) => {
|
|
return event.data;
|
|
},
|
|
}),
|
|
setPublicKey: assign({
|
|
publicKey: (_, event: any) => {
|
|
if (!isHardwareKeystoreExists) {
|
|
return event.data.publicKey as string;
|
|
}
|
|
return event.data.publicKey as string;
|
|
},
|
|
}),
|
|
|
|
setPrivateKey: assign({
|
|
privateKey: (_, event: any) => event.data.privateKey as string,
|
|
}),
|
|
|
|
logDownloaded: send(
|
|
context => {
|
|
const vcMetadata = context.vcMetadata;
|
|
return ActivityLogEvents.LOG_ACTIVITY(
|
|
VCActivityLog.getLogFromObject({
|
|
_vcKey: vcMetadata.getVcKey(),
|
|
type: 'VC_DOWNLOADED',
|
|
timestamp: Date.now(),
|
|
deviceName: '',
|
|
issuer:
|
|
context.selectedIssuer.credential_issuer_host ??
|
|
context.credentialOfferCredentialIssuer,
|
|
credentialConfigurationId: context.selectedCredentialType.id,
|
|
}),
|
|
context.selectedIssuerWellknownResponse,
|
|
);
|
|
},
|
|
{
|
|
to: (context: any) => context.serviceRefs.activityLog,
|
|
},
|
|
),
|
|
sendSuccessEndEvent: (context: any) => {
|
|
sendEndEvent(
|
|
getEndEventData(
|
|
TelemetryConstants.FlowType.vcDownload,
|
|
TelemetryConstants.EndEventStatus.success,
|
|
{'VC Key': context.keyType},
|
|
),
|
|
);
|
|
},
|
|
|
|
sendErrorEndEvent: (context: any) => {
|
|
sendEndEvent(
|
|
getEndEventData(
|
|
TelemetryConstants.FlowType.vcDownload,
|
|
TelemetryConstants.EndEventStatus.failure,
|
|
{'VC Key': context.keyType},
|
|
),
|
|
);
|
|
},
|
|
sendImpressionEvent: () => {
|
|
sendImpressionEvent(
|
|
getImpressionEventData(
|
|
TelemetryConstants.FlowType.vcDownload,
|
|
TelemetryConstants.Screens.issuerList,
|
|
),
|
|
);
|
|
},
|
|
|
|
updateVerificationErrorMessage: assign({
|
|
verificationErrorMessage: (_, event: any) => {
|
|
return (event.data as Error).message;
|
|
},
|
|
}),
|
|
|
|
resetVerificationErrorMessage: model.assign({
|
|
verificationErrorMessage: () => '',
|
|
}),
|
|
|
|
resetQrData: model.assign({
|
|
qrData: () => '',
|
|
}),
|
|
|
|
sendDownloadingFailedToVcMeta: send(
|
|
(_: any) => ({
|
|
type: 'VC_DOWNLOADING_FAILED',
|
|
}),
|
|
{
|
|
to: context => context.serviceRefs.vcMeta,
|
|
},
|
|
),
|
|
};
|
|
};
|