diff --git a/javascript/src/iframe/viamapi-iframe.js b/javascript/src/iframe/viamapi-iframe.js index f96df4b886d368a0c367c60f74d09178c170cc67..06421ddc10d4f098559a4e891b9a51e509d1e9f6 100644 --- a/javascript/src/iframe/viamapi-iframe.js +++ b/javascript/src/iframe/viamapi-iframe.js @@ -365,6 +365,12 @@ async function executeRestfulFunction(type, that, fn, config, ...args) { window.executeRestfulFunction = executeRestfulFunction; +const TRANSPARENT_PIXEL = new ImageData({ + contentType: "image/png", + contentBase64: + "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=" //1x1px transparent pixel +}); + function loadIdentityInternal(identityKey, pinCode) { return new Penpal.Promise(result => { getIdentityFromLocalStorage(identityKey, pinCode) @@ -1368,10 +1374,99 @@ const connection = Penpal.connectToParent({ return encodeResponse("200", "", "Document signed"); }, + /** + * Checks the state of the vCard. Current states are "disabled" and "enabled". + * @param passportUUID + * @returns {Promise<{code: *, data: *, status: *}>} + */ + async checkVCardState(passportUUID) { + const authenticationPublicKey = localStorage.getItem( + "authenticatedIdentity" + ); + + if ( + !authenticationPublicKey || + !window.loadedIdentities[authenticationPublicKey] || + !extendPinCodeTtl(authenticationPublicKey) + ) { + return encodeResponse("400", "", "Identity not authenticated"); + } + + let vCardImageClaimValue; + + const vCardImageClaimName = "vCardImage"; + const defaultTagName = "notag"; + + const vCardClaimResponse = await executeRestfulFunction( + "private", + window.viamApi, + window.viamApi.entityGetClaim, + null, + vCardImageClaimName, + defaultTagName, + passportUUID + ); + + // You may not have vCard image claim, but backend will still return blank image from passportGetVCardImage + + // if (vCardClaimResponse.code !== "200") { + // return encodeResponse("400", "", vCardClaimResponse.status); + // } + + if (vCardClaimResponse.code === "200") { + vCardImageClaimValue = vCardClaimResponse.data; + } + + if ( + vCardImageClaimValue && + "state" in vCardImageClaimValue + ) { + return encodeResponse("200", vCardImageClaimValue.state, "OK"); + } + + return encodeResponse("200", "enabled", "OK"); + }, + /** + * + * @param passportUUID + * @param documentUUID + * @param documentContentType + * @param signatureData - + * @returns {Promise<{code: *, data: *, status: *}>} + * +// Image position in pixels +message Position { + int32 left = 1; // x + int32 top = 2; // y +} + + // Image size in pixels + message Size { + uint32 width = 1; + uint32 height = 2; +} + + // Image size in pixels + message Bounds { + int32 left = 1; // x + int32 top = 2; // y + uint32 width = 3; + uint32 height = 4; +} +message SignatureData { + ImageData signatureImageData = 1; + Bounds signatureBounds = 2; + uint32 pageNumber = 3; + Size pageSize = 4; +} + * + */ signDocumentJava: async ( passportUUID, documentUUID, - documentContentType + documentContentType, + signatureData = null, + qrCodeUrl = null ) => { const authenticationPublicKey = localStorage.getItem( "authenticatedIdentity" @@ -1385,6 +1480,80 @@ const connection = Penpal.connectToParent({ return encodeResponse("400", "", "Identity not authenticated"); } + + // Get vCard and QR Code Coordinates + + let vCardImageData; + let vCardImageClaimValue; + + let qrCodeImageData; + let qrCodeCoordinates = {fromL: -1, fromR: -1, toL: -1, toR: -1}; + + if (signatureData) { + const vCardImageClaimName = "vCardImage"; + const defaultTagName = "notag"; + + const vCardClaimResponse = await executeRestfulFunction( + "private", + window.viamApi, + window.viamApi.entityGetClaim, + null, + vCardImageClaimName, + defaultTagName, + passportUUID + ); + // if (vCardClaimResponse.code !== "200") { + // return encodeResponse("400", "", vCardClaimResponse.status); + // } + + if (vCardClaimResponse.code === "200") { + vCardImageClaimValue = vCardClaimResponse.data; + } + + if ( + vCardImageClaimValue && + "state" in vCardImageClaimValue && + vCardImageClaimValue.state === "disabled" + ) { + vCardImageData = TRANSPARENT_PIXEL; + } else { + const vCardImageResponse = await executeRestfulFunction( + "private", + window.viamApi, + window.viamApi.passportGetVCardImage, + null, + passportUUID + ); + + if (vCardImageResponse.code !== "200") { + return encodeResponse("400", "", vCardImageResponse.status); + } + vCardImageData = new ImageData(vCardImageResponse.data.Image); + if (vCardImageData.contentType !== "image/png") { + return encodeResponse( + "400", + "", + "Content type of vCard must be 'image/png'" + ); + } + + if (qrCodeUrl) { + qrCodeCoordinates = vCardImageResponse.data.QRCodeCoordinates; + const qrCodeBase64Content = await generateQrCode(qrCodeUrl); + qrCodeImageData = new ImageData({ + contentType: "image/png", + content: qrCodeBase64Content + }); + } + } + + // Fill signature data onject + + signatureData.signatureImageData = vCardImageData; + } + + // Generate certificate chain + const certResponse = await getCertificateForPassport(passportUUID, true); if (certResponse.code !== "200") { @@ -1416,6 +1585,8 @@ const connection = Penpal.connectToParent({ passportChain.reverse(); + // eventually convert document + const pdfContentType = "application/pdf"; if (documentContentType !== pdfContentType) { @@ -1433,6 +1604,8 @@ const connection = Penpal.connectToParent({ } } + // Sign document + const signResponse = await executeRestfulFunction( "private", window.viamApi, @@ -1442,7 +1615,10 @@ const connection = Penpal.connectToParent({ passportChain, passportUUID, documentUUID, - pdfContentType + pdfContentType, + signatureData, + qrCodeImageData, + qrCodeCoordinates ); if (signResponse.code !== "200") { return encodeResponse("400", "", signResponse.status); @@ -1496,6 +1672,9 @@ const connection = Penpal.connectToParent({ let vCardImageData; let vCardImageClaimValue; + let qrCodeImageData; + let qrCodeCoordinates = {fromL: -1, fromR: -1, toL: -1, toR: -1}; + const vCardImageClaimName = "vCardImage"; const defaultTagName = "notag"; @@ -1516,19 +1695,12 @@ const connection = Penpal.connectToParent({ vCardImageClaimValue = vCardClaimResponse.data; } - let qrCodeImageData; - let qrCodeCoordinates = { fromL: -1, fromR: -1, toL: -1, toR: -1 }; - if ( vCardImageClaimValue && "state" in vCardImageClaimValue && vCardImageClaimValue.state === "disabled" ) { - vCardImageData = new ImageData({ - contentType: "image/png", - contentBase64: - "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=" //1x1px transparent pixel - }); + vCardImageData = TRANSPARENT_PIXEL; } else { const vCardImageResponse = await executeRestfulFunction( "private", @@ -1538,8 +1710,6 @@ const connection = Penpal.connectToParent({ passportUUID ); - console.log(vCardImageResponse); - if (vCardImageResponse.code !== "200") { return encodeResponse("400", "", vCardImageResponse.status); } @@ -1548,7 +1718,7 @@ const connection = Penpal.connectToParent({ return encodeResponse( "400", "", - "Content type of vCard mmust be 'image/png'" + "Content type of vCard must be 'image/png'" ); } @@ -1639,8 +1809,6 @@ const connection = Penpal.connectToParent({ passportChain.reverse(); - console.log(qrCodeImageData); - console.log(qrCodeCoordinates); const signVCardResponse = await executeRestfulFunction( "private", @@ -1759,6 +1927,76 @@ const connection = Penpal.connectToParent({ return encodeResponse("200", response.data, "Document created"); }, + getVcardWithQrCode: async (passportUUID, QRCodeContent = null) =>{ + //TODO: IMPLEMENT QR CODE backend method needed + const authenticationPublicKey = localStorage.getItem( + "authenticatedIdentity" + ); + + if ( + !authenticationPublicKey || + !window.loadedIdentities[authenticationPublicKey] || + !extendPinCodeTtl(authenticationPublicKey) + ) { + return encodeResponse("400", "", "Identity not authenticated"); + } + + let vCardImageData; + let vCardImageClaimValue; + + const vCardImageClaimName = "vCardImage"; + const defaultTagName = "notag"; + + const vCardClaimResponse = await executeRestfulFunction( + "private", + window.viamApi, + window.viamApi.entityGetClaim, + null, + vCardImageClaimName, + defaultTagName, + passportUUID + ); + + if (vCardClaimResponse.code === "200") { + vCardImageClaimValue = vCardClaimResponse.data; + } + + if ( + vCardImageClaimValue && + "state" in vCardImageClaimValue && + vCardImageClaimValue.state === "disabled" + ) { + //No image data if the user have disabled vCard for this profile. + vCardImageData = null; + + // vCardImageData = new ImageData({ + // contentType: "image/png", + // contentBase64: + // "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=" //1x1px transparent pixel + // }); + } else { + const vCardImageResponse = await executeRestfulFunction( + "private", + window.viamApi, + window.viamApi.passportGetVCardImage, + null, + passportUUID + ); + + if (vCardImageResponse.code !== "200") { + return encodeResponse("400", "", vCardImageResponse.status); + } + vCardImageData = new ImageData(vCardImageResponse.data.Image); + if (vCardImageData.contentType !== "image/png") { + return encodeResponse( + "400", + "", + "Content type of vCard mmust be 'image/png'" + ); + } + } + return encodeResponse("200",vCardImageData, 'vCard got'); + }, documentPutDocument: async ( passportUUID, resourceid, diff --git a/javascript/src/utilities/signingUtilities.js b/javascript/src/utilities/signingUtilities.js index ec255299e58fe5b77311be8f3a128bd646f22c31..20f64f0d273ceeb9fcc92c1542882b324fb6b699 100644 --- a/javascript/src/utilities/signingUtilities.js +++ b/javascript/src/utilities/signingUtilities.js @@ -1495,6 +1495,9 @@ export class ImageData { this.content = null; // Uint8Array: decoded content this.contentBase64 = null; // string: base64 encoded content + if (typeof parameters === "string" || parameters instanceof String) { + this.fromDataURL(parameters); + } else if (typeof parameters === "object") { this.fromParameters(parameters); } @@ -1517,13 +1520,24 @@ export class ImageData { this.getContentBase64(); } - //fromDataURL() + fromDataURL(dataURL) { + if (dataURL.startsWith("data:")) { + const idx = dataURL.indexOf(";base64,"); + if (idx > 0) { + this.contentType = dataURL.substring(5, idx); // 5 = len("data:") + this.contentBase64 = dataURL.substring(idx + 8); // 8 = len(";base64,") + } + } + } //fromContentTypeAndContentAsByteArray() toDataURL() { return "data:" + this.contentType + ";base64," + this.getContentBase64(); } + /** + * @returns {ByteArray} + */ getContent() { if (!this.content) { if (this.contentBase64) { @@ -1533,6 +1547,9 @@ export class ImageData { return this.content; } + /** + * @returns {String} + */ getContentBase64() { if (!this.contentBase64) { if (this.content) {