Files
inji-wallet/machines/VerifiableCredential/VCItemMachine/VCItemServices.ts
KiruthikaJeyashankar 003cc156c2 [INJIMOB-1192] onboarding of new issuer is affecting the existing issuers (#1476)
* [INJIMOB-1192] : use wellknown response instead of mimoto issuer config.
-- Remove hardcoding for sunbird issuer in vc activation and verification flow.
-- Render idType from wellknown response
-- Remove UIN/VID from default add-on fields

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

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

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

* [INJIMOB-1192] : add credentialType in VcMetadata

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

* [INJIMOB-1192] refactor duplication and unused code

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

* [INJIMOB-1192] remove unused displayId in metadata

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

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

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

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

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

* [INJIMOB-1192] fix failing test cases

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

* [INJIMOB-1192] remove unused translations

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

---------

Signed-off-by: Swati Goel <meet2swati@gmail.com>
Signed-off-by: KiruthikaJeyashankar <81218987+KiruthikaJeyashankar@users.noreply.github.com>
Signed-off-by: PuBHARGAVI <46226958+PuBHARGAVI@users.noreply.github.com>
Co-authored-by: Swati Goel <meet2swati@gmail.com>
Co-authored-by: PuBHARGAVI <46226958+PuBHARGAVI@users.noreply.github.com>
2024-06-04 16:37:54 +05:30

223 lines
7.2 KiB
TypeScript

import {NativeModules} from 'react-native';
import Cloud from '../../../shared/CloudBackupAndRestoreUtils';
import {VCMetadata} from '../../../shared/VCMetadata';
import getAllConfigurations, {
API_URLS,
CACHED_API,
DownloadProps,
} from '../../../shared/api';
import {
generateKeys,
isHardwareKeystoreExists,
} from '../../../shared/cryptoutil/cryptoUtil';
import {
getBindingCertificateConstant,
savePrivateKey,
} from '../../../shared/keystore/SecureKeystore';
import {CredentialDownloadResponse, request} from '../../../shared/request';
import {WalletBindingResponse} from '../VCMetaMachine/vc';
import {verifyCredential} from '../../../shared/vcjs/verifyCredential';
import {getVerifiableCredential} from './VCItemSelectors';
import {getSelectedCredentialTypeDetails} from '../../../shared/openId4VCI/Utils';
import {getCredentialTypes} from '../../../components/VC/common/VCUtils';
const {RNSecureKeystoreModule} = NativeModules;
export const VCItemServices = model => {
return {
isUserSignedAlready: () => async () => {
return await Cloud.isSignedInAlready();
},
updatePrivateKey: async context => {
const hasSetPrivateKey: boolean = await savePrivateKey(
context.walletBindingResponse.walletBindingId,
context.privateKey,
);
if (!hasSetPrivateKey) {
throw new Error('Could not store private key in keystore.');
}
return '';
},
loadDownloadLimitConfig: async context => {
var resp = await getAllConfigurations();
const maxLimit: number = resp.vcDownloadMaxRetry;
const vcDownloadPoolInterval: number = resp.vcDownloadPoolInterval;
const downloadProps: DownloadProps = {
maxDownloadLimit: maxLimit,
downloadInterval: vcDownloadPoolInterval,
};
return downloadProps;
},
checkDownloadExpiryLimit: async context => {
if (context.downloadCounter > context.maxDownloadCount) {
throw new Error(
'Download limit expired for request id: ' +
context.vcMetadata.requestId,
);
}
},
addWalletBindingId: async context => {
const response = await request(
API_URLS.walletBinding.method,
API_URLS.walletBinding.buildURL(),
{
requestTime: String(new Date().toISOString()),
request: {
authFactorType: 'WLA',
format: 'jwt',
individualId: VCMetadata.fromVC(context.vcMetadata).id,
transactionId: context.bindingTransactionId,
publicKey: context.publicKey,
challengeList: [
{
authFactorType: 'OTP',
challenge: context.OTP,
format: 'alpha-numeric',
},
],
},
},
);
const certificate = response.response.certificate;
await savePrivateKey(
getBindingCertificateConstant(VCMetadata.fromVC(context.vcMetadata).id),
certificate,
);
const walletResponse: WalletBindingResponse = {
walletBindingId: response.response.encryptedWalletBindingId,
keyId: response.response.keyId,
thumbprint: response.response.thumbprint,
expireDateTime: response.response.expireDateTime,
};
return walletResponse;
},
generateKeyPair: async context => {
if (!isHardwareKeystoreExists) {
return await generateKeys();
}
const isBiometricsEnabled = RNSecureKeystoreModule.hasBiometricsEnabled();
return RNSecureKeystoreModule.generateKeyPair(
VCMetadata.fromVC(context.vcMetadata).id,
isBiometricsEnabled,
0,
);
},
requestBindingOTP: async context => {
const vc = getVerifiableCredential(context.verifiableCredential);
const response = await request(
API_URLS.bindingOtp.method,
API_URLS.bindingOtp.buildURL(),
{
requestTime: String(new Date().toISOString()),
request: {
individualId: VCMetadata.fromVC(context.vcMetadata).id,
otpChannels: ['EMAIL', 'PHONE'],
},
},
);
if (response.response == null) {
throw new Error('Could not process request');
}
return response;
},
fetchIssuerWellknown: async context => {
const wellknownResponse = await CACHED_API.fetchIssuerWellknownConfig(
context.vcMetadata.issuer,
context.verifiableCredential.wellKnown,
true,
);
const wellknownOfCredential = getSelectedCredentialTypeDetails(
wellknownResponse,
getCredentialTypes(context.verifiableCredential),
);
return wellknownOfCredential;
},
checkStatus: context => (callback, onReceive) => {
const pollInterval = setInterval(
() => callback(model.events.POLL()),
context.downloadInterval,
);
onReceive(async event => {
if (event.type === 'POLL_STATUS') {
try {
const response = await request(
API_URLS.credentialStatus.method,
API_URLS.credentialStatus.buildURL(context.vcMetadata.requestId),
);
switch (response.response?.statusCode) {
case 'NEW':
break;
case 'ISSUED':
case 'printing':
callback(model.events.DOWNLOAD_READY());
break;
case 'FAILED':
default:
callback(model.events.FAILED());
clearInterval(pollInterval);
break;
}
} catch (error) {
callback(model.events.FAILED());
clearInterval(pollInterval);
}
}
});
return () => clearInterval(pollInterval);
},
downloadCredential: context => (callback, onReceive) => {
const pollInterval = setInterval(
() => callback(model.events.POLL()),
context.downloadInterval,
);
onReceive(async event => {
if (event.type === 'POLL_DOWNLOAD') {
const response: CredentialDownloadResponse = await request(
API_URLS.credentialDownload.method,
API_URLS.credentialDownload.buildURL(),
{
individualId: context.vcMetadata.id,
requestId: context.vcMetadata.requestId,
},
);
callback(
model.events.CREDENTIAL_DOWNLOADED({
credential: response.credential,
verifiableCredential: response.verifiableCredential,
generatedOn: new Date(),
id: context.vcMetadata.id,
idType: context.vcMetadata.idType,
requestId: context.vcMetadata.requestId,
lastVerifiedOn: null,
walletBindingResponse: null,
credentialRegistry: '',
}),
);
}
});
return () => clearInterval(pollInterval);
},
verifyCredential: async context => {
if (context.verifiableCredential) {
const verificationResult = await verifyCredential(
getVerifiableCredential(context.verifiableCredential),
);
if (!verificationResult.isVerified) {
throw new Error(verificationResult.errorMessage);
}
}
},
};
};