diff --git a/javascript/src/iframe/viamapi-iframe.js b/javascript/src/iframe/viamapi-iframe.js index 218922d5bc65e709999a692b114e23b2b5c8fc16..5b3e7eb4c4db7ffc53beac571610621cbaac1524 100644 --- a/javascript/src/iframe/viamapi-iframe.js +++ b/javascript/src/iframe/viamapi-iframe.js @@ -1410,6 +1410,9 @@ const connection = Penpal.connectToParent({ return encodeResponse("200", "", "Document signed"); }, // passportUUID - String - passport to sign the vCard + // senderEmail - the email address of the sender + // attribs - additional attributes, to be added to the vCard. Recognized attribs are: + // - emailService: "GMail", "Outlook 365", ... // text, html - String - the text and html part of the email, both optional // parts - array of objects, representing the MIME structure in format: // { @@ -1421,7 +1424,7 @@ const connection = Penpal.connectToParent({ // body: String if it is a text part (Content-Type = "text/...") or Uint8Array otherwise; filled for leaf MIME nodes // parts: array of instances of the same object; filled for container MIME nodes (Content-Type = "multipart/...") // } - signVCard: async (passportUUID, senderEmail, text, html, parts = null) => { + signVCard: async (passportUUID, senderEmail, attribs, textBody, htmlBody, parts) => { const authenticationPublicKey = localStorage.getItem( "authenticatedIdentity" ); @@ -1437,8 +1440,9 @@ const connection = Penpal.connectToParent({ const messageUUID = makeid(); const vCardAttribs = { - passportUUID: passportUUID, - messageUUID: messageUUID + ...attribs, + passportUUID, + messageUUID }; let vCardImageData; @@ -1501,31 +1505,47 @@ const connection = Penpal.connectToParent({ ); } - if (!parts) { + if (typeof parts === "undefined" || parts === null) { parts = []; } - if (html) { + if (htmlBody) { + if (typeof htmlBody !== "string") { + throw new Error("htmlBody is not string"); // should not happen + } const htmlPart = { headers: { "Content-Type": "text/html" }, - body: html + body: htmlBody }; parts.unshift(htmlPart); + } else { + console.log("Html body is not passed to signVCard, its value is ", {html: htmlBody}); } - if (text) { + if (textBody) { + if (typeof textBody !== "string") { + throw new Error("textBody is not string"); // should not happen + } const textPart = { headers: { "Content-Type": "text/plain" }, - body: text + body: textBody }; parts.unshift(textPart); + } else { + console.log("Text body is not passed to signVCard, its value is ", {text: textBody}); } - prepareVCardParts(parts); + const count = prepareVCardParts(parts); + if (count.textParts === 0) { + return encodeResponse("400", "", "No text parts passed to signVCard"); + } + if (count.htmlParts === 0) { + return encodeResponse("400", "", "No html parts passed to signVCard"); + } const certResponse = await getCertificateForPassport(passportUUID, true); diff --git a/javascript/src/utilities/emailUtilities.js b/javascript/src/utilities/emailUtilities.js index d9131fb2f095912e1ee65552d3bcaa756ea7b674..988f879940b4bd1cac8eb118367d6e8f7ff05413 100644 --- a/javascript/src/utilities/emailUtilities.js +++ b/javascript/src/utilities/emailUtilities.js @@ -136,11 +136,49 @@ export const extractHtmlBodyFromString = string => { .trim(); }; -export const prepareVCardParts = parts => { +const capitalizeHeaderName = str => { + if (!str || typeof str !== 'string') { return; } + const strChunks = splitBy(str,'-'); + return strChunks.map(capitalizeFirstLetter).join('-'); +}; +const splitBy = (string,separator) =>{ + if (typeof string !== 'string') { return; } + return string.split(separator); +}; +const capitalizeFirstLetter = (s) => { + if (typeof s !== 'string') { return; } + return s.charAt(0).toUpperCase() + s.slice(1); +}; + +export function prepareVCardParts(parts) { if (!parts) { return; } + const count = { + textParts: 0, + htmlParts: 0 + }; for (const part of parts) { + if (!part.headers) { + part.headers = { + "Content-Type": "application/octet-stream" + }; + } else { + const capitalizedHeaders = {}; + for (const key of Object.keys(part.headers)) { + capitalizedHeaders[capitalizeHeaderName(key)] = part.headers[key]; + } + part.headers = capitalizedHeaders; + try { + 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) { if (typeof part.body === "string") { part.body = stringToUtf8Base64(part.body); @@ -151,11 +189,14 @@ export const prepareVCardParts = parts => { if (part.body instanceof ArrayBuffer) { part.body = byteArrayToBase64(new Uint8Array(part.body)); } else { - throw new Error('part body is neither string, nor Uint8Array, nor ArrayBuffer'); + throw new Error('part body is neither string, nor Uint8Array, nor ArrayBuffer'); // should not happen } } if (part.parts) { - prepareVCardParts(part.parts); + const subcount = prepareVCardParts(part.parts); + count.textParts += subcount.textParts; + count.htmlParts += subcount.htmlParts; } } -}; + return count; +}