diff --git a/javascript/src/iframe/viamapi-iframe.js b/javascript/src/iframe/viamapi-iframe.js index 5b3e7eb4c4db7ffc53beac571610621cbaac1524..cdb6a46edff86b7068fa091309e22d4434a044dd 100644 --- a/javascript/src/iframe/viamapi-iframe.js +++ b/javascript/src/iframe/viamapi-iframe.js @@ -1539,7 +1539,7 @@ const connection = Penpal.connectToParent({ console.log("Text body is not passed to signVCard, its value is ", {text: textBody}); } - const count = prepareVCardParts(parts); + const count = await prepareVCardParts(parts); if (count.textParts === 0) { return encodeResponse("400", "", "No text parts passed to signVCard"); } diff --git a/javascript/src/utilities/emailUtilities.js b/javascript/src/utilities/emailUtilities.js index 988f879940b4bd1cac8eb118367d6e8f7ff05413..1a696a1b566be6ea55bab5d3788584327c41bd77 100644 --- a/javascript/src/utilities/emailUtilities.js +++ b/javascript/src/utilities/emailUtilities.js @@ -17,8 +17,10 @@ import { } from "./signingUtilities"; import { byteArrayToBase64, - stringToUtf8Base64 + stringToUtf8Base64, + stringToUtf8ByteArray } from "./stringUtilities"; +import {getCrypto} from "pkijs"; export const SIGNATURE_CONTENT_TYPE = "application/pkcs7-signature"; export const DEFAULT_ATTACHMENT_NAME = "attachment"; @@ -150,14 +152,52 @@ const capitalizeFirstLetter = (s) => { return s.charAt(0).toUpperCase() + s.slice(1); }; -export function prepareVCardParts(parts) { - if (!parts) { - return; +async function sha256(array) { + const cryptoLib = getCrypto(); + const digestTmpBuf = await cryptoLib.digest({ name: "SHA-256" }, array); + const digestTmpArray = new Uint8Array(digestTmpBuf); + return digestTmpArray; +} + +async function hashBody(part) { + const contentType = part.headers["Content-Type"]; + const origContentType = part.headers["Original-Content-Type"]; + + if (!origContentType && + !part.headers["Content-Type"].startsWith("application/hash") && + !part.headers["Content-Type"].startsWith("text/plain") && + !part.headers["Content-Type"].startsWith("text/html")) { + if (part.body) { + if (typeof part.body === "string") { + part.body = stringToUtf8ByteArray(part.body); + } + if (part.body instanceof ArrayBuffer) { + part.body = byteArrayToBase64(new Uint8Array(part.body)); + } + if (!(part.body instanceof Uint8Array)) { + throw new Error('part body is neither string, nor Uint8Array, nor ArrayBuffer'); // should not happen + } + + if (contentType) { + part.headers["Original-Content-Type"] = contentType; + } + part.headers["Content-Type"] = "application/hash; algorithm=SHA-256"; + + part.body = await sha256(part.body); + } } +} + +export async function prepareVCardParts(parts) { const count = { textParts: 0, htmlParts: 0 }; + + if (!parts) { + return count; + } + for (const part of parts) { if (!part.headers) { part.headers = { @@ -169,17 +209,18 @@ export function prepareVCardParts(parts) { capitalizedHeaders[capitalizeHeaderName(key)] = part.headers[key]; } part.headers = capitalizedHeaders; - try { + if (!part.headers["Content-Type"]) { + part.headers["Content-Type"] = "application/octet-stream"; + } else { if (part.headers["Content-Type"].startsWith("text/plain")) { count.textParts++; } else if (part.headers["Content-Type"].startsWith("text/html")) { count.htmlParts++; } - } catch (ignore) { - //ignore } } if (part.body) { + await hashBody(part); if (typeof part.body === "string") { part.body = stringToUtf8Base64(part.body); } else @@ -193,7 +234,7 @@ export function prepareVCardParts(parts) { } } if (part.parts) { - const subcount = prepareVCardParts(part.parts); + const subcount = await prepareVCardParts(part.parts); count.textParts += subcount.textParts; count.htmlParts += subcount.htmlParts; }