diff --git a/inji-web/src/errors/CustomError.js b/inji-web/src/errors/CustomError.js new file mode 100644 index 00000000..b69cdcd2 --- /dev/null +++ b/inji-web/src/errors/CustomError.js @@ -0,0 +1,6 @@ +export class CustomError extends Error { + constructor(message, details) { + super(message); + this.details = details; + } +} diff --git a/inji-web/src/pages/Certificate/index.js b/inji-web/src/pages/Certificate/index.js index f1ccd3cd..a2804394 100644 --- a/inji-web/src/pages/Certificate/index.js +++ b/inji-web/src/pages/Certificate/index.js @@ -10,6 +10,7 @@ import Header from "./Header"; import {fetchAccessToken} from "../../utils/oauth-utils"; import {downloadCredentials} from "../../utils/misc"; import {DATA_KEY_IN_LOCAL_STORAGE} from "../../utils/config"; +import {CustomError} from "../../errors/CustomError"; const getCodeVerifierAndClientId = () => { let details = JSON.parse(localStorage.getItem(DATA_KEY_IN_LOCAL_STORAGE) || "{}"); @@ -19,6 +20,17 @@ const getCodeVerifierAndClientId = () => { return {clientId, codeVerifier}; } +const getDownloadErrorMessage = (error) => { + try { + if (error instanceof CustomError) { + let responseErrorObject = JSON.parse(error.details.error); + if (responseErrorObject?.errors) + return responseErrorObject.errors[0].errorMessage; + } + } catch (exception) {} + return 'Failed to download the credentials'; +}; + const ErrorComponent = () => { return (); }; @@ -58,20 +70,6 @@ const DisplayComponent = ({message, inProgress}) => { const {issuerId} = useParams(); const issuerDisplayName = useLocation().state?.issuerDisplayName; switch (message) { - case 'Invalid user credentials': - case 'Failed to verify the user credentials': - case 'Failed to download the credentials': - return (<> - - - - - {message} - - - - - ); case 'Verifying credentials': case 'Downloading credentials': return ( @@ -101,6 +99,22 @@ const DisplayComponent = ({message, inProgress}) => { ); + case 'Invalid user credentials': + case 'Failed to verify the user credentials': + case 'Failed to download the credentials': + default: + return (<> + + + + + {message} + + + + + ); + } } @@ -136,8 +150,8 @@ function Certificate(props) { setProgress(false); }) .catch(error => { - console.log(error) - setMessage('Failed to download the credentials'); + console.error("Error occurred while downloading the credential. Error message: ", error); + setMessage(getDownloadErrorMessage(error)); setProgress(false); }); }) diff --git a/inji-web/src/utils/config.js b/inji-web/src/utils/config.js index b9488b0b..51fc7104 100644 --- a/inji-web/src/utils/config.js +++ b/inji-web/src/utils/config.js @@ -18,11 +18,11 @@ export const getESignetRedirectURL = (scope, clientId, codeChallenge, state) => /* MIMOTO CONFIG */ export const MIMOTO_URL = process.env.REACT_APP_MIMOTO_URL || "/v1/mimoto"; -export const FETCH_ISSUERS_URL = `${MIMOTO_URL}/v2/issuers`; -export const getSearchIssuersUrl = (issuer) => `${MIMOTO_URL}/v2/issuers?search=${issuer}`; -export const getCredentialsSupportedUrl = (issuerId) => `${MIMOTO_URL}/v2/issuers/${issuerId}/credentials-supported`; +export const FETCH_ISSUERS_URL = `${MIMOTO_URL}/issuers`; +export const getSearchIssuersUrl = (issuer) => `${MIMOTO_URL}/issuers?search=${issuer}`; +export const getCredentialsSupportedUrl = (issuerId) => `${MIMOTO_URL}/issuers/${issuerId}/credentialTypes`; export const getFetchAccessTokenFromCodeApi = (issuer) => `${MIMOTO_URL}/get-token/${issuer}`; -export const getVcDownloadAPI = (issuerId, credentialId) => `${MIMOTO_URL}/v2/issuers/${issuerId}/credentials/${credentialId}/download`; +export const getVcDownloadAPI = (issuerId, credentialId) => `${MIMOTO_URL}/issuers/${issuerId}/credentials/${credentialId}/download`; /* MISC */ export const DATA_KEY_IN_LOCAL_STORAGE = "vcDownloadDetails"; diff --git a/inji-web/src/utils/misc.js b/inji-web/src/utils/misc.js index cbd2a257..2c012dda 100644 --- a/inji-web/src/utils/misc.js +++ b/inji-web/src/utils/misc.js @@ -1,5 +1,6 @@ import axios from "axios"; import {getVcDownloadAPI} from "./config"; +import {CustomError} from "../errors/CustomError"; export const getCertificatesAutoCompleteOptions = (credentialsList) => credentialsList.map(cred => { return {label: cred.display[0].name, value: cred.display[0].name} @@ -20,17 +21,39 @@ export const getUrlParamsMap = (searchString) => { return searchParamsMap; } +export const getFileName = (contentDispositionHeader) => { + if (!contentDispositionHeader) return null; + // sample header value => Content-Disposition: 'attachment; filename="x"' and we need "x" + const filenameMatch = contentDispositionHeader.match(/filename=(.*?)(;|$)/); + if (filenameMatch && filenameMatch.length > 1) { + return filenameMatch[1]; + } + return null; +}; + export const downloadCredentials = async (issuerId, certificateId, token) => { - const response = await axios.get(getVcDownloadAPI(issuerId, certificateId), { - headers: {/* + let response; + try { + response = await axios.get(getVcDownloadAPI(issuerId, certificateId), { + headers: {/* 'Authorization': 'Bearer ' + token,*/ - 'Bearer': token, - 'Cache-Control': 'no-cache, no-store, must-revalidate' - }, - responseType: 'blob' // Set the response type to 'arraybuffer' to receive binary data - }); + 'Bearer': token, + 'Cache-Control': 'no-cache, no-store, must-revalidate' + }, + responseType: 'blob' // Set the response type to 'arraybuffer' to receive binary data + }); + } catch (exception) { + response = exception.response; + } + const blob = new Blob([response.data], { type: response.headers['content-type'] }); + if (response.status === 500) { + let responseObject = await blob.text(); + throw new CustomError(responseObject, {error: responseObject}); + } + let fileName = getFileName(response.headers['content-disposition']) ?? `${certificateId}.pdf`; + // Create a temporary URL for the Blob const url = window.URL.createObjectURL(blob); @@ -39,7 +62,7 @@ export const downloadCredentials = async (issuerId, certificateId, token) => { link.href = url; // Set the filename for download - link.setAttribute('download', `${certificateId}.pdf`); + link.setAttribute('download', fileName); link.setAttribute('target', '_blank'); // Open the link in a new tab or window // Trigger a click event to download the file