mirror of
https://github.com/mosip/inji-wallet.git
synced 2026-01-08 21:18:14 -05:00
* [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>
307 lines
8.2 KiB
TypeScript
307 lines
8.2 KiB
TypeScript
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 i18next from 'i18next';
|
|
import {getJWT} from '../cryptoutil/cryptoUtil';
|
|
import i18n from '../../i18n';
|
|
import {
|
|
CredentialWrapper,
|
|
VerifiableCredential,
|
|
} from '../../machines/VerifiableCredential/VCMetaMachine/vc';
|
|
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';
|
|
import {getErrorEventData, sendErrorEvent} from '../telemetry/TelemetryUtils';
|
|
import {TelemetryConstants} from '../telemetry/TelemetryConstants';
|
|
|
|
export const Protocols = {
|
|
OpenId4VCI: 'OpenId4VCI',
|
|
OTP: 'OTP',
|
|
};
|
|
|
|
export const Issuers = {
|
|
MosipOtp: '',
|
|
Sunbird: 'Sunbird',
|
|
Mosip: 'Mosip',
|
|
};
|
|
|
|
export function getVcVerificationDetails(
|
|
statusType,
|
|
vcMetadata,
|
|
verifiableCredential,
|
|
wellknown: Object,
|
|
): vcVerificationBannerDetails {
|
|
const idType = getIdType(
|
|
wellknown,
|
|
getCredentialTypes(getVerifiableCredential(verifiableCredential)),
|
|
);
|
|
return {
|
|
statusType: statusType,
|
|
vcType: idType,
|
|
vcNumber: vcMetadata.id,
|
|
};
|
|
}
|
|
|
|
export const ACTIVATION_NEEDED = [Issuers.Mosip, Issuers.MosipOtp];
|
|
|
|
export const isActivationNeeded = (issuer: string) => {
|
|
return ACTIVATION_NEEDED.indexOf(issuer) !== -1;
|
|
};
|
|
|
|
export const Issuers_Key_Ref = 'OpenId4VCI_KeyPair';
|
|
|
|
export const getIdentifier = (context, credential: VerifiableCredential) => {
|
|
const credentialIdentifier = credential.credential.id;
|
|
const credId = credentialIdentifier.startsWith('did')
|
|
? credentialIdentifier.split(':')
|
|
: credentialIdentifier.split('/');
|
|
return (
|
|
context.selectedIssuer.credential_issuer +
|
|
':' +
|
|
context.selectedIssuer.protocol +
|
|
':' +
|
|
credId[credId.length - 1]
|
|
);
|
|
};
|
|
|
|
export const getCredentialRequestBody = async (
|
|
proofJWT: string,
|
|
credentialType: Array<string>,
|
|
) => {
|
|
return {
|
|
format: 'ldp_vc',
|
|
credential_definition: {
|
|
'@context': ['https://www.w3.org/2018/credentials/v1'],
|
|
type: credentialType,
|
|
},
|
|
proof: {
|
|
proof_type: 'jwt',
|
|
jwt: proofJWT,
|
|
},
|
|
};
|
|
};
|
|
|
|
export const updateCredentialInformation = (
|
|
context,
|
|
credential: VerifiableCredential,
|
|
): CredentialWrapper => {
|
|
return {
|
|
verifiableCredential: {
|
|
...credential,
|
|
wellKnown: context.selectedIssuer['.well-known'],
|
|
credentialTypes: credential.credential.type ?? ['VerifiableCredential'],
|
|
issuerLogo: getDisplayObjectForCurrentLanguage(
|
|
context.selectedIssuer.display,
|
|
)?.logo,
|
|
},
|
|
identifier: getIdentifier(context, credential),
|
|
generatedOn: new Date(),
|
|
vcMetadata: context.vcMetadata || {},
|
|
};
|
|
};
|
|
|
|
export const getDisplayObjectForCurrentLanguage = (
|
|
display: [displayType],
|
|
): displayType => {
|
|
const currentLanguage = i18next.language;
|
|
const languageKey = Object.keys(display[0]).includes('language')
|
|
? 'language'
|
|
: 'locale';
|
|
let displayType = display.filter(
|
|
obj => obj[languageKey] == currentLanguage,
|
|
)[0];
|
|
if (!displayType) {
|
|
displayType = display.filter(obj => obj[languageKey] === 'en')[0];
|
|
}
|
|
return displayType;
|
|
};
|
|
|
|
export const constructAuthorizationConfiguration = (
|
|
selectedIssuer: issuerType,
|
|
supportedScope: string,
|
|
) => {
|
|
return {
|
|
issuer: selectedIssuer.credential_issuer,
|
|
clientId: selectedIssuer.client_id,
|
|
scopes: [supportedScope],
|
|
additionalHeaders: selectedIssuer.additional_headers,
|
|
redirectUrl: selectedIssuer.redirect_uri,
|
|
additionalParameters: {ui_locales: i18n.language},
|
|
serviceConfiguration: {
|
|
authorizationEndpoint: selectedIssuer.authorization_endpoint,
|
|
tokenEndpoint: selectedIssuer.token_endpoint,
|
|
},
|
|
};
|
|
};
|
|
|
|
export const getJWK = async publicKey => {
|
|
try {
|
|
let publicKeyJWKString;
|
|
let publicKeyJWK;
|
|
if (isIOS()) {
|
|
publicKeyJWKString = await jose.JWK.asKey(publicKey, 'pem');
|
|
publicKeyJWK = publicKeyJWKString.toJSON();
|
|
} else {
|
|
publicKeyJWK = await pem2jwk(publicKey);
|
|
}
|
|
return {
|
|
...publicKeyJWK,
|
|
alg: 'RS256',
|
|
use: 'sig',
|
|
};
|
|
} catch (e) {
|
|
console.error(
|
|
'Exception occurred while constructing JWK from PEM : ' +
|
|
publicKey +
|
|
' Exception is ',
|
|
e,
|
|
);
|
|
}
|
|
};
|
|
|
|
export const getSelectedCredentialTypeDetails = (
|
|
wellknown: any,
|
|
vcCredentialTypes: Object[],
|
|
): Object => {
|
|
for (let credential in wellknown.credentials_supported) {
|
|
const credentialDetails = wellknown.credentials_supported[credential];
|
|
|
|
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,
|
|
wellknown: string,
|
|
vcCredentialTypes: Object[],
|
|
defaultFields: string[],
|
|
) => {
|
|
let fields: string[] = defaultFields;
|
|
let credentialDetails: any;
|
|
if (wellknown) {
|
|
const response = await CACHED_API.fetchIssuerWellknownConfig(
|
|
issuer,
|
|
wellknown,
|
|
);
|
|
if (response) {
|
|
credentialDetails = getSelectedCredentialTypeDetails(
|
|
response,
|
|
vcCredentialTypes,
|
|
);
|
|
if (Object.keys(credentialDetails).includes('order')) {
|
|
fields = credentialDetails.order;
|
|
} else {
|
|
fields = Object.keys(
|
|
credentialDetails.credential_definition.credentialSubject,
|
|
);
|
|
}
|
|
}
|
|
}
|
|
return {
|
|
wellknown: credentialDetails,
|
|
fields: fields,
|
|
};
|
|
};
|
|
|
|
export const getDetailedViewFields = async (
|
|
issuer: string,
|
|
wellknown: string,
|
|
vcCredentialTypes: Object[],
|
|
defaultFields: string[],
|
|
) => {
|
|
let response = await getCredentialIssuersWellKnownConfig(
|
|
issuer,
|
|
wellknown,
|
|
vcCredentialTypes,
|
|
defaultFields,
|
|
);
|
|
|
|
let updatedFieldsList = response.fields.concat(DETAIL_VIEW_ADD_ON_FIELDS);
|
|
|
|
updatedFieldsList = removeBottomSectionFields(updatedFieldsList);
|
|
|
|
return {
|
|
wellknown: response.wellknown,
|
|
fields: updatedFieldsList,
|
|
};
|
|
};
|
|
|
|
export const removeBottomSectionFields = fields => {
|
|
return fields.filter(
|
|
fieldName =>
|
|
!BOTTOM_SECTION_FIELDS_WITH_DETAILED_ADDRESS_FIELDS.includes(fieldName) &&
|
|
fieldName !== 'address',
|
|
);
|
|
};
|
|
|
|
export const vcDownloadTimeout = async (): Promise<number> => {
|
|
const response = await getAllConfigurations();
|
|
|
|
return Number(response['openId4VCIDownloadVCTimeout']) || 30000;
|
|
};
|
|
|
|
// OIDCErrors is a collection of external errors from the OpenID library or the issuer
|
|
export enum OIDCErrors {
|
|
OIDC_FLOW_CANCELLED_ANDROID = 'User cancelled flow',
|
|
OIDC_FLOW_CANCELLED_IOS = 'org.openid.appauth.general error -3',
|
|
|
|
INVALID_TOKEN_SPECIFIED = 'Invalid token specified',
|
|
OIDC_CONFIG_ERROR_PREFIX = 'Config error',
|
|
}
|
|
|
|
// ErrorMessage is the type of error message shown in the UI
|
|
export enum ErrorMessage {
|
|
NO_INTERNET = 'noInternetConnection',
|
|
GENERIC = 'generic',
|
|
REQUEST_TIMEDOUT = 'requestTimedOut',
|
|
BIOMETRIC_CANCELLED = 'biometricCancelled',
|
|
}
|
|
|
|
export async function constructProofJWT(
|
|
publicKey: string,
|
|
privateKey: string,
|
|
accessToken: string,
|
|
selectedIssuer: issuerType,
|
|
): Promise<string> {
|
|
const jwtHeader = {
|
|
alg: 'RS256',
|
|
jwk: await getJWK(publicKey),
|
|
typ: 'openid4vci-proof+jwt',
|
|
};
|
|
const decodedToken = jwtDecode(accessToken);
|
|
const jwtPayload = {
|
|
iss: selectedIssuer.client_id,
|
|
nonce: decodedToken.c_nonce,
|
|
aud: selectedIssuer.credential_audience,
|
|
iat: Math.floor(new Date().getTime() / 1000),
|
|
exp: Math.floor(new Date().getTime() / 1000) + 18000,
|
|
};
|
|
|
|
return await getJWT(jwtHeader, jwtPayload, Issuers_Key_Ref, privateKey);
|
|
}
|