Skip to content
Snippets Groups Projects
viamapi-iframe.js 75 KiB
Newer Older
  • Learn to ignore specific revisions
  • Sasha Ilieva's avatar
    Sasha Ilieva committed
            );
            if (response.data === 1) {
              const event = createEvent("", "Recovered");
              parent.onEvent(event);
              return;
            }
    
            await timeout(1000);
            await checkAccountRecoveryStatus();
          }
    
    Sasha Ilieva's avatar
    Sasha Ilieva committed
          await checkAccountRecoveryStatus();
    
        contactsGetTrusteeContactsPublicKeys: async () => {
          try {
    
            const response = await executeRestfulFunction(
    
              "private",
              window.viamApi,
              window.viamApi.contactsGetTrusteeContactsPublicKeys,
              null
            );
    
            if (response.code !== "200") {
              return response;
            }
    
    
    Sasha Ilieva's avatar
    Sasha Ilieva committed
            const responseData = response.data;
    
    Sasha Ilieva's avatar
    Sasha Ilieva committed
            const trusteesDevices = Object.values(responseData);
    
    Sasha Ilieva's avatar
    Sasha Ilieva committed
            /** Check if there are new trustees without added secret part */
    
    Sasha Ilieva's avatar
    Sasha Ilieva committed
            const hasNewTrustees = trusteesDevices.some(device => {
    
              const deviceData = Object.values(device);
              return deviceData.some(data => data.hasShamir === "0");
    
    Sasha Ilieva's avatar
    Sasha Ilieva committed
            });
    
    Sasha Ilieva's avatar
    Sasha Ilieva committed
            if (!hasNewTrustees) {
              return response;
    
    Sasha Ilieva's avatar
    Sasha Ilieva committed
            }
    
            // Generate and split recovery key
    
    Sasha Ilieva's avatar
    Sasha Ilieva committed
            const trusteesUuids = Object.keys(responseData);
            const trusteesToDevices = Object.entries(responseData);
            const sharesNumber = trusteesUuids.length;
            const recoveryKey = generateRecoveryKey();
            const recoveryKeyShares = getRecoveryKeyShares(
              recoveryKey,
              sharesNumber
            );
            const sanityCheckResponse = checkRecoveryKeyCombine(
    
    Sasha Ilieva's avatar
    Sasha Ilieva committed
              recoveryKeyShares
    
    Sasha Ilieva's avatar
    Sasha Ilieva committed
            if (sanityCheckResponse.code !== "200") {
              return sanityCheckResponse;
    
            // Encrypt each share with every publicKey of each contact device
            const shamirPartsList = await Promise.all(
    
    Sasha Ilieva's avatar
    Sasha Ilieva committed
              trusteesToDevices.map(async ([contactUuid, device], index) => {
    
                const deviceIdsToPublicKeys = Object.entries(device);
    
    Sasha Ilieva's avatar
    Sasha Ilieva committed
                // Encrypt secret shares in parallel
                const deviceIdsToEncryptedPartsList = await Promise.all(
    
                  deviceIdsToPublicKeys.map(async ([deviceId, { content }]) => {
    
                    const encryptedShare = await encryptShare(
                      recoveryKeyShares[index],
    
                    );
    
                    return [deviceId, encryptedShare];
                  })
                );
    
    Sasha Ilieva's avatar
    Sasha Ilieva committed
                // Turn deviceIdsToEncryptedPartsList array to object
                const deviceIdsToEncryptedParts = Object.fromEntries(
                  deviceIdsToEncryptedPartsList
    
    Sasha Ilieva's avatar
    Sasha Ilieva committed
                return [contactUuid, deviceIdsToEncryptedParts];
    
    Sasha Ilieva's avatar
    Sasha Ilieva committed
            // Turn shamirPartsList array to object
    
            const shamirParts = Object.fromEntries(shamirPartsList);
    
            // Save Shamir parts to database
    
            const saveShamirPartsResponse = await executeRestfulFunction(
    
              "private",
              window.viamApi,
              window.viamApi.contactsSaveShamirParts,
              null,
              shamirParts
            );
    
            if (saveShamirPartsResponse !== "200") {
              return saveShamirPartsResponse;
            }
    
    
    Sasha Ilieva's avatar
    Sasha Ilieva committed
            return response;
    
          } catch (error) {
    
    Sasha Ilieva's avatar
    Sasha Ilieva committed
            return encodeResponse("400", "", error.message);
    
        getCurrentlyLoggedInUUID() {
    
          return new Penpal.Promise(result => {
    
    Alexey Lunin's avatar
    Alexey Lunin committed
            const authenticationPublicKey = localStorage.getItem(
              "authenticatedIdentity"
            );
    
            if (authenticationPublicKey === null) {
    
    Sasha Ilieva's avatar
    Sasha Ilieva committed
              return { data: "", code: "400", status: "Identity not loaded" };
    
            if (window.loadedIdentities[authenticationPublicKey] === null) {
    
    Sasha Ilieva's avatar
    Sasha Ilieva committed
              return { data: "", code: "400", status: "Identity not loaded" };
    
    Zdravko Iliev's avatar
    Zdravko Iliev committed
            const success = extendPinCodeTtl(authenticationPublicKey);
    
    Alexey Lunin's avatar
    Alexey Lunin committed
            if (success === false) {
              result({
                data: "",
                code: "400",
    
                status: "Identity not authenticated"
    
    Alexey Lunin's avatar
    Alexey Lunin committed
              });
    
    Alexey Lunin's avatar
    Alexey Lunin committed
            if (localStorage.getItem("uuid") === null) {
    
    Sasha Ilieva's avatar
    Sasha Ilieva committed
              result({ data: "", code: "400", status: "Not logged in UUID" });
    
    Alexey Lunin's avatar
    Alexey Lunin committed
            result({
              data: localStorage.getItem("uuid"),
              code: "200",
    
    Alexey Lunin's avatar
    Alexey Lunin committed
            });
    
          });
        },
        getCertificateByPassport(passportUUID) {
    
          return new Penpal.Promise(result => {
    
    Alexey Lunin's avatar
    Alexey Lunin committed
            const authenticationPublicKey = localStorage.getItem(
              "authenticatedIdentity"
            );
    
            if (authenticationPublicKey === null) {
    
    Sasha Ilieva's avatar
    Sasha Ilieva committed
              return { data: "", code: "400", status: "Identity not loaded" };
    
            if (window.loadedIdentities[authenticationPublicKey] === null) {
    
    Sasha Ilieva's avatar
    Sasha Ilieva committed
              return { data: "", code: "400", status: "Identity not loaded" };
    
    Zdravko Iliev's avatar
    Zdravko Iliev committed
            const success = extendPinCodeTtl(authenticationPublicKey);
    
    Alexey Lunin's avatar
    Alexey Lunin committed
            if (success === false) {
              result({
                data: "",
                code: "400",
    
                status: "Identity not authenticated"
    
    Alexey Lunin's avatar
    Alexey Lunin committed
              });
    
    Alexey Lunin's avatar
    Alexey Lunin committed
            getCertificateForPassport(passportUUID, false).then(
    
    Alexey Lunin's avatar
    Alexey Lunin committed
                result(certificateResult);
              }
            );
    
          });
        },
        getOneTimeCertificateByPassport(passportUUID, emailArg) {
    
          return new Penpal.Promise(result => {
    
    Alexey Lunin's avatar
    Alexey Lunin committed
            const authenticationPublicKey = localStorage.getItem(
              "authenticatedIdentity"
            );
    
            if (authenticationPublicKey === null) {
    
    Sasha Ilieva's avatar
    Sasha Ilieva committed
              return { data: "", code: "400", status: "Identity not loaded" };
    
            if (window.loadedIdentities[authenticationPublicKey] === null) {
    
    Sasha Ilieva's avatar
    Sasha Ilieva committed
              return { data: "", code: "400", status: "Identity not loaded" };
    
    Zdravko Iliev's avatar
    Zdravko Iliev committed
            const success = extendPinCodeTtl(authenticationPublicKey);
    
    Alexey Lunin's avatar
    Alexey Lunin committed
            if (success === false) {
              result({
                data: "",
                code: "400",
    
                status: "Identity not authenticated"
    
    Alexey Lunin's avatar
    Alexey Lunin committed
              });
    
    Alexey Lunin's avatar
    Alexey Lunin committed
            getCertificateForPassport(passportUUID, true).then(
    
    Alexey Lunin's avatar
    Alexey Lunin committed
                if (certificateResult.code === "200") {
    
    Zdravko Iliev's avatar
    Zdravko Iliev committed
                  const passportCertificate =
    
    Alexey Lunin's avatar
    Alexey Lunin committed
                    certificateResult.data["x509Certificate"];
    
    Zdravko Iliev's avatar
    Zdravko Iliev committed
                  const passportPrivateKey = certificateResult.data["privateKey"];
                  const passportChain = certificateResult.data["chain"];
    
    Alexey Lunin's avatar
    Alexey Lunin committed
    
                  createOneTimePassportCertificate(
                    makeid() + "-" + passportUUID,
                    emailArg,
                    passportPrivateKey,
                    passportCertificate
    
    Sasha Ilieva's avatar
    Sasha Ilieva committed
                  ).then(function (keys) {
    
    Zdravko Iliev's avatar
    Zdravko Iliev committed
                    const publicKeyOneTime = keys["publicKeyPEM"];
                    const privateKeyOneTime = keys["privateKeyPEM"];
                    const certificateOneTime = keys["certificatePEM"];
    
    Alexey Lunin's avatar
    Alexey Lunin committed
                    passportChain.push(passportCertificate);
    
    
    Zdravko Iliev's avatar
    Zdravko Iliev committed
                    const oneTimeCryptoData = new CryptoData();
    
    Alexey Lunin's avatar
    Alexey Lunin committed
                    oneTimeCryptoData.setx509Certificate(certificateOneTime);
                    oneTimeCryptoData.setPrivateKey(privateKeyOneTime);
                    oneTimeCryptoData.setPublicKey(publicKeyOneTime);
                    oneTimeCryptoData.setChain(passportChain);
    
                    result({
                      data: oneTimeCryptoData,
                      code: "200",
    
                      status: "One time certificate generated"
    
    Alexey Lunin's avatar
    Alexey Lunin committed
                    });
                    // Prints PEM formatted signed certificate
                    // -----BEGIN CERTIFICATE-----MIID....7Hyg==-----END CERTIFICATE-----
                  });
                } else {
                  result({
                    data: "",
                    code: "400",
    
                    status: "Can not generate one time certificate"
    
    Alexey Lunin's avatar
    Alexey Lunin committed
                  });
                }
    
    Alexey Lunin's avatar
    Alexey Lunin committed
            );
    
        verifySMIME: async smimeString => {
    
          const authenticationPublicKey = localStorage.getItem(
            "authenticatedIdentity"
          );
    
          if (
            !authenticationPublicKey ||
            !window.loadedIdentities[authenticationPublicKey] ||
            !extendPinCodeTtl(authenticationPublicKey)
          ) {
            return encodeResponse("400", "", "Identity not authenticated");
          }
    
    
    Damyan Mitev's avatar
    Damyan Mitev committed
          //TODO cache (for some time) the root certificate
          // either as PEM or as certificate object (preferred)
    
          const rootCaResponse = await executeRestfulFunction(
            "private",
            window.viamApi,
            window.viamApi.signRetrieveRootCertificate,
            null
          );
    
          if (rootCaResponse.code !== "200") {
            return encodeResponse("400", "", rootCaResponse.status);
          }
    
          const rootCaPem = rootCaResponse.data;
    
    Damyan Mitev's avatar
    Damyan Mitev committed
          const verificationResult = await verifySMIME(smimeString, rootCaPem);
    
          return encodeResponse(
            "200",
            verificationResult.verified,
            verificationResult.message
          );
    
        validateDocument: async (documentUUID, contentType) => {
    
          const authenticationPublicKey = localStorage.getItem(
            "authenticatedIdentity"
          );
    
    
          if (
            !authenticationPublicKey ||
            !window.loadedIdentities[authenticationPublicKey] ||
            !extendPinCodeTtl(authenticationPublicKey)
          ) {
            return encodeResponse("400", "", "Identity not authenticated");
          }
    
          const validateDocumentResponse = await executeRestfulFunction(
            "private",
            window.viamApi,
            window.viamApi.documentValidateDocumentByUUID,
            null,
            documentUUID,
    
    
          if (validateDocumentResponse.code !== "200") {
            return encodeResponse("400", "", validateDocumentResponse.status);
          }
    
          const signatures = validateDocumentResponse.data;
    
          if (signatures) {
            for (const signature of signatures) {
    
              const certificateChain = signature.certificateChainPEM.map(
    
                  const certificate = parseCertificate(certificatePEM);
                  const certificateData = new CertificateData(certificate);
                  return certificateData;
                }
              );
    
              signature.certificateChain = certificateChain;
            }
    
        signEmail: async (passportUUID, emailArg, emailMessage) => {
    
    Alexey Lunin's avatar
    Alexey Lunin committed
          const authenticationPublicKey = localStorage.getItem(
            "authenticatedIdentity"
          );
    
          if (
            !authenticationPublicKey ||
            !window.loadedIdentities[authenticationPublicKey] ||
            !extendPinCodeTtl(authenticationPublicKey)
          ) {
            return encodeResponse("400", "", "Identity not authenticated");
          }
    
          let response = await getCertificateForPassport(passportUUID, true);
    
          if (response.code !== "200") {
            return encodeResponse("400", "", response.status);
          }
    
          const {
            x509Certificate: passportCertificate,
            privateKey: passportPrivateKey,
    
    Alexey Lunin's avatar
    Alexey Lunin committed
          const keys = await createOneTimePassportCertificate(
            makeid() + "-" + passportUUID,
            emailArg,
            passportPrivateKey,
            passportCertificate
          );
    
    Alexey Lunin's avatar
    Alexey Lunin committed
          const {
            privateKeyPEM: privateKeyOneTime,
    
            certificatePEM: certificateOneTime
    
    Alexey Lunin's avatar
    Alexey Lunin committed
          } = keys;
    
          passportChain.push(passportCertificate);
    
          response = await executeRestfulFunction(
    
    Alexey Lunin's avatar
    Alexey Lunin committed
            "private",
            window.viamApi,
            window.viamApi.passportGetEmailWithHeaderByPassport,
            null,
            passportUUID,
            emailMessage
          );
    
    
          if (response.code !== "200") {
            return encodeResponse("400", "", response.status);
          }
    
    
    Alexey Lunin's avatar
    Alexey Lunin committed
          const signedEmail = await signEmail(
            response.data,
            certificateOneTime,
            passportChain,
            privateKeyOneTime
          );
    
    
          response = await executeRestfulFunction(
    
    Alexey Lunin's avatar
    Alexey Lunin committed
            "private",
            window.viamApi,
            window.viamApi.signResignEmail,
            null,
            passportUUID,
            signedEmail
          );
    
    
          if (response.code !== "200") {
            return encodeResponse("400", "", response.status);
          }
    
          return encodeResponse("200", response.data, "Email signed");
    
    Damyan Mitev's avatar
    Damyan Mitev committed
        signDocument: async (passportUUID, documentUUID, documentContentType) => {
    
    Alexey Lunin's avatar
    Alexey Lunin committed
          const authenticationPublicKey = localStorage.getItem(
            "authenticatedIdentity"
          );
    
    Damyan Mitev's avatar
    Damyan Mitev committed
    
          if (
            !authenticationPublicKey ||
            !window.loadedIdentities[authenticationPublicKey] ||
            !extendPinCodeTtl(authenticationPublicKey)
          ) {
            return encodeResponse("400", "", "Identity not authenticated");
          }
    
    
          const certResponse = await getCertificateForPassport(passportUUID, true);
    
    Damyan Mitev's avatar
    Damyan Mitev committed
    
    
          if (certResponse.code !== "200") {
            return encodeResponse("400", "", certResponse.status);
    
    Damyan Mitev's avatar
    Damyan Mitev committed
          }
    
          const {
            x509Certificate: passportCertificate,
            privateKey: passportPrivateKey,
    
          } = certResponse.data;
    
    Damyan Mitev's avatar
    Damyan Mitev committed
    
    
    Alexey Lunin's avatar
    Alexey Lunin committed
          const keys = await createOneTimePassportCertificate(
            makeid() + "-" + passportUUID,
            null,
            passportPrivateKey,
            passportCertificate
          );
    
    Damyan Mitev's avatar
    Damyan Mitev committed
    
    
    Alexey Lunin's avatar
    Alexey Lunin committed
          const {
            privateKeyPEM: privateKeyOneTime,
    
            certificatePEM: certificateOneTime
    
    Alexey Lunin's avatar
    Alexey Lunin committed
          } = keys;
    
    Damyan Mitev's avatar
    Damyan Mitev committed
    
    
    Gospodin Bodurov's avatar
    Gospodin Bodurov committed
          passportChain.reverse();
    
    
    Damyan Mitev's avatar
    Damyan Mitev committed
          passportChain.push(passportCertificate);
    
    
    Gospodin Bodurov's avatar
    Gospodin Bodurov committed
          passportChain.reverse();
    
    
    Alexey Lunin's avatar
    Alexey Lunin committed
          const pdfContentType = "application/pdf";
    
    Damyan Mitev's avatar
    Damyan Mitev committed
    
          if (documentContentType !== pdfContentType) {
            const convResponse = await executeRestfulFunction(
    
    Alexey Lunin's avatar
    Alexey Lunin committed
              "private",
              window.viamApi,
              window.viamApi.documentConvertDocumentByUUID,
              null,
              documentUUID,
              documentContentType,
              pdfContentType
            );
    
    Damyan Mitev's avatar
    Damyan Mitev committed
            if (convResponse.code !== "200") {
              return encodeResponse("400", "", convResponse.status);
            }
          }
    
          const downloadResponse = await executeRestfulFunction(
    
    Alexey Lunin's avatar
    Alexey Lunin committed
            "private",
            window.viamApi,
            window.viamApi.documentGetDocumentByUUID,
            null,
            documentUUID,
            pdfContentType
          );
    
    Damyan Mitev's avatar
    Damyan Mitev committed
    
          if (downloadResponse.code !== "200") {
            return encodeResponse("400", "", downloadResponse.status);
          }
    
    
          const pdfRaw = base64ToByteArray(downloadResponse.data);
    
    Damyan Mitev's avatar
    Damyan Mitev committed
    
    
          let signedPdf;
          try {
    
    Alexey Lunin's avatar
    Alexey Lunin committed
            signedPdf = await signPdf(
              pdfRaw,
              certificateOneTime,
              passportChain,
              privateKeyOneTime
            );
    
          } catch (err) {
            console.error(err);
            return encodeResponse("500", "", err.message);
          }
    
    Damyan Mitev's avatar
    Damyan Mitev committed
    
    
          const signedPdfB64 = byteArrayToBase64(signedPdf);
    
    
          const uploadResponse = await executeRestfulFunction(
    
    Alexey Lunin's avatar
    Alexey Lunin committed
            "private",
            window.viamApi,
            window.viamApi.documentPutDocumentByUUID,
            null,
            documentUUID,
            pdfContentType,
            signedPdfB64
          );
    
          if (uploadResponse.code !== "200") {
            return encodeResponse("400", "", uploadResponse.status);
          }
    
          const signResponse = await executeRestfulFunction(
    
    Alexey Lunin's avatar
    Alexey Lunin committed
            "private",
            window.viamApi,
            window.viamApi.documentSignDocumentByUUID,
            null,
            passportUUID,
            documentUUID,
            pdfContentType
          );
    
          if (signResponse.code !== "200") {
            return encodeResponse("400", "", signResponse.status);
          }
    
          return encodeResponse("200", "", "Document signed");
    
    Damyan Mitev's avatar
    Damyan Mitev committed
        },
    
        signDocumentJava: async (
          passportUUID,
          documentUUID,
          documentContentType
        ) => {
    
          const authenticationPublicKey = localStorage.getItem(
            "authenticatedIdentity"
          );
    
          if (
            !authenticationPublicKey ||
            !window.loadedIdentities[authenticationPublicKey] ||
            !extendPinCodeTtl(authenticationPublicKey)
          ) {
            return encodeResponse("400", "", "Identity not authenticated");
          }
    
          const certResponse = await getCertificateForPassport(passportUUID, true);
    
          if (certResponse.code !== "200") {
            return encodeResponse("400", "", certResponse.status);
          }
    
          const {
            x509Certificate: passportCertificate,
            privateKey: passportPrivateKey,
    
          } = certResponse.data;
    
          const keys = await createOneTimePassportCertificate(
            makeid() + "-" + passportUUID,
    
            passportPrivateKey,
            passportCertificate
          );
    
          const {
            privateKeyPEM: privateKeyOneTime,
    
            certificatePEM: certificateOneTime
    
    Gospodin Bodurov's avatar
    Gospodin Bodurov committed
          passportChain.reverse();
    
    
          passportChain.push(passportCertificate);
          passportChain.push(certificateOneTime);
    
    
    Gospodin Bodurov's avatar
    Gospodin Bodurov committed
          passportChain.reverse();
    
    
          const pdfContentType = "application/pdf";
    
          if (documentContentType !== pdfContentType) {
            const convResponse = await executeRestfulFunction(
              "private",
              window.viamApi,
              window.viamApi.documentConvertDocumentByUUID,
              null,
              documentUUID,
              documentContentType,
              pdfContentType
            );
            if (convResponse.code !== "200") {
              return encodeResponse("400", "", convResponse.status);
            }
          }
    
          const signResponse = await executeRestfulFunction(
            "private",
            window.viamApi,
            window.viamApi.documentSignDocumentJavaService,
            null,
            privateKeyOneTime,
            passportChain,
            passportUUID,
            documentUUID,
            pdfContentType
          );
          if (signResponse.code !== "200") {
            return encodeResponse("400", "", signResponse.status);
          }
    
          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:
    
    Damyan Mitev's avatar
    Damyan Mitev committed
        // {
        //   headers: {
    
        //     "Content-Type": "image/jpeg",
        //     "Content-Disposition": "inline" or "attachment" with additional attributes,
        //     ... //other headers from MIME
    
    Damyan Mitev's avatar
    Damyan Mitev committed
        //   },
    
        //   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/...")
    
    Damyan Mitev's avatar
    Damyan Mitev committed
        // }
    
        signVCard: async (
          passportUUID,
          senderEmail,
          attribs,
          textBody,
          htmlBody,
          parts
        ) => {
    
    Damyan Mitev's avatar
    Damyan Mitev committed
          const authenticationPublicKey = localStorage.getItem(
            "authenticatedIdentity"
          );
    
          if (
            !authenticationPublicKey ||
            !window.loadedIdentities[authenticationPublicKey] ||
            !extendPinCodeTtl(authenticationPublicKey)
          ) {
            return encodeResponse("400", "", "Identity not authenticated");
          }
    
    
          const messageUUID = makeid();
    
          const vCardAttribs = {
    
            ...attribs,
            passportUUID,
    
          let vCardImageData;
          let vCardImageClaimValue;
    
    
          const vCardImageClaimName = "vCardImage";
          const defaultTagName = "notag";
    
          const vCardClaimResponse = await executeRestfulFunction(
    
    Damyan Mitev's avatar
    Damyan Mitev committed
            "private",
            window.viamApi,
    
            window.viamApi.entityGetClaim,
    
    Damyan Mitev's avatar
    Damyan Mitev committed
            null,
    
            vCardImageClaimName,
            defaultTagName,
    
    Damyan Mitev's avatar
    Damyan Mitev committed
            passportUUID
          );
    
          // if (vCardClaimResponse.code !== "200") {
          //   return encodeResponse("400", "", vCardClaimResponse.status);
          // }
    
          if (vCardClaimResponse.code === "200") {
            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",
    
                "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=" //1x1px transparent pixel
    
            });
          } else {
            const vCardImageResponse = await executeRestfulFunction(
              "private",
              window.viamApi,
              window.viamApi.passportGetVCardImage,
              null,
              passportUUID
            );
    
    Gospodin Bodurov's avatar
    Gospodin Bodurov committed
    
            console.log(vCardImageResponse);
    
    
            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'"
              );
    
            qrCodeCoordinates = vCardImageResponse.data.QRCodeCoordinates;
    
            const qrCodeBase64Content = await generateQrCode(
              "https://" + location.host + "/check/" + messageUUID
    
            qrCodeImageData = new ImageData({
              contentType: "image/png",
    
              content: qrCodeBase64Content
    
    Damyan Mitev's avatar
    Damyan Mitev committed
          if (typeof parts === "undefined" || parts === null) {
    
    Damyan Mitev's avatar
    Damyan Mitev committed
            parts = [];
          }
    
    
          if (htmlBody) {
            if (typeof htmlBody !== "string") {
              throw new Error("htmlBody is not string"); // should not happen
            }
    
    Damyan Mitev's avatar
    Damyan Mitev committed
            const htmlPart = {
              headers: {
    
                "Content-Type": "text/html"
    
    Damyan Mitev's avatar
    Damyan Mitev committed
              },
    
    Damyan Mitev's avatar
    Damyan Mitev committed
            };
            parts.unshift(htmlPart);
    
          } else {
    
            console.log("Html body is not passed to signVCard, its value is ", {
    
          if (textBody) {
            if (typeof textBody !== "string") {
              throw new Error("textBody is not string"); // should not happen
            }
    
    Damyan Mitev's avatar
    Damyan Mitev committed
            const textPart = {
              headers: {
    
                "Content-Type": "text/plain"
    
    Damyan Mitev's avatar
    Damyan Mitev committed
              },
    
    Damyan Mitev's avatar
    Damyan Mitev committed
            };
            parts.unshift(textPart);
    
          } else {
    
            console.log("Text body is not passed to signVCard, its value is ", {
    
          const count = await 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");
          }
    
    Damyan Mitev's avatar
    Damyan Mitev committed
          const certResponse = await getCertificateForPassport(passportUUID, true);
    
          if (certResponse.code !== "200") {
            return encodeResponse("400", "", certResponse.status);
          }
    
          const {
            x509Certificate: passportCertificate,
            privateKey: passportPrivateKey,
    
    Damyan Mitev's avatar
    Damyan Mitev committed
          } = certResponse.data;
    
          const keys = await createOneTimePassportCertificate(
            makeid() + "-" + passportUUID,
    
            senderEmail,
    
    Damyan Mitev's avatar
    Damyan Mitev committed
            passportPrivateKey,
            passportCertificate
          );
    
          const {
            privateKeyPEM: privateKeyOneTime,
    
            certificatePEM: certificateOneTime
    
    Damyan Mitev's avatar
    Damyan Mitev committed
          } = keys;
    
          passportChain.reverse();
    
          passportChain.push(passportCertificate);
          passportChain.push(certificateOneTime);
    
          passportChain.reverse();
    
    
          console.log(qrCodeImageData);
          console.log(qrCodeCoordinates);
    
    Gospodin Bodurov's avatar
    Gospodin Bodurov committed
    
    
    Damyan Mitev's avatar
    Damyan Mitev committed
          const signVCardResponse = await executeRestfulFunction(
            "private",
            window.viamApi,
            window.viamApi.signSignVCardForChain,
            null,
            vCardImageData,
            privateKeyOneTime,
            passportChain,
    
            vCardAttribs,
            qrCodeImageData,
    
    Damyan Mitev's avatar
    Damyan Mitev committed
          );
          if (signVCardResponse.code !== "200") {
            return encodeResponse("400", "", signVCardResponse.status);
          }
    
    
    Damyan Mitev's avatar
    Damyan Mitev committed
          const signedVCardImageData = new ImageData(signVCardResponse.data);
    
          return encodeResponse(
            "200",
            {
              image: signedVCardImageData,
    
    Damyan Mitev's avatar
    Damyan Mitev committed
        },
    
        // mime - String - the MIME of the email message
        // vCardAttribs - optional attributes for the verification procedure in format
    
    Damyan Mitev's avatar
    Damyan Mitev committed
        // {
    
        //   passportUUID: passportUUID,
        //   messageUUID: messageUUID
        // };
    
    Damyan Mitev's avatar
    Damyan Mitev committed
        validateVMime: async (vMime, vCardAttribs = null) => {
    
    Damyan Mitev's avatar
    Damyan Mitev committed
          const authenticationPublicKey = localStorage.getItem(
            "authenticatedIdentity"
          );
    
          if (
            !authenticationPublicKey ||
            !window.loadedIdentities[authenticationPublicKey] ||
            !extendPinCodeTtl(authenticationPublicKey)
          ) {
            return encodeResponse("400", "", "Identity not authenticated");
          }
    
    
          const validateVMimeResponse = await executeRestfulFunction(
    
    Damyan Mitev's avatar
    Damyan Mitev committed
            "private",
            window.viamApi,
    
            window.viamApi.signValidateVMime,
    
    Damyan Mitev's avatar
    Damyan Mitev committed
            null,
    
    Damyan Mitev's avatar
    Damyan Mitev committed
            vMime,
    
    Damyan Mitev's avatar
    Damyan Mitev committed
          );
    
          if (validateVMimeResponse.code !== "200") {
            return encodeResponse("400", "", validateVMimeResponse.status);
    
    Damyan Mitev's avatar
    Damyan Mitev committed
          const validationResult = validateVMimeResponse.data;
    
          const { signatures } = validationResult;
    
          if (signatures) {
            for (const signature of signatures) {
    
              const certificateChain = signature.certificateChainPEM.map(
    
                  const certificate = parseCertificate(certificatePEM);
                  const certificateData = new CertificateData(certificate);
                  return certificateData;
                }
              );
    
              signature.certificateChain = certificateChain;
    
          return encodeResponse(
            "200",
            validationResult,
            "Validation result retrieved"
          );
    
    Damyan Mitev's avatar
    Damyan Mitev committed
        },
    
        generateQrCode,
    
        documentCreateDocument: async (passportUUID, path, contentType, title) => {
    
    Alexey Lunin's avatar
    Alexey Lunin committed
          const authenticationPublicKey = localStorage.getItem(
            "authenticatedIdentity"
          );
    
          if (
            !authenticationPublicKey ||
            !window.loadedIdentities[authenticationPublicKey] ||
            !extendPinCodeTtl(authenticationPublicKey)
          ) {
            return encodeResponse("400", "", "Identity not authenticated");
          }
    
    
          path = encodeURI(path);
          contentType = encodeURI(contentType);
          title = encodeURI(title);
    
    
          const config = {
            headers: {
              path,
              passportuuid: passportUUID,
    
    Alexey Lunin's avatar
    Alexey Lunin committed
          const response = await executeRestfulFunction(
            "private",
            window.viamApi,
            window.viamApi.documentCreateDocument,
            config
          );
    
          if (response.code !== "200") {
            return encodeResponse("400", "", response.status);
          }
    
    
          return encodeResponse("200", response.data, "Document created");
        },
    
    Alexey Lunin's avatar
    Alexey Lunin committed
        documentPutDocument: async (
          passportUUID,
          resourceid,
          contentType,
    
    Alexey Lunin's avatar
    Alexey Lunin committed
          file,
          upload
    
    Alexey Lunin's avatar
    Alexey Lunin committed
        ) => {
          const authenticationPublicKey = localStorage.getItem(
            "authenticatedIdentity"
          );
    
          if (
            !authenticationPublicKey ||
            !window.loadedIdentities[authenticationPublicKey] ||
            !extendPinCodeTtl(authenticationPublicKey)
          ) {
            return encodeResponse("400", "", "Identity not authenticated");
          }
    
    
          resourceid = encodeURI(resourceid);
          contentType = encodeURI(contentType);
    
    
    Alexey Lunin's avatar
    Alexey Lunin committed
              "Content-Type": "multipart/form-data",
    
              contentType,
    
    
          const response = await executeRestfulFunction(
    
    Alexey Lunin's avatar
    Alexey Lunin committed
            "private",
            window.viamApi,
            window.viamApi.documentPutDocument,
            config,
            file
          );
    
          if (response.code !== "200") {
            return encodeResponse("400", "", response.status);
          }
    
    
          return encodeResponse("200", response.data, "Document stored");
        },
    
        hasSession() {
    
          return new Penpal.Promise(result => {
    
    Alexey Lunin's avatar
    Alexey Lunin committed
            const authenticationPublicKey = localStorage.getItem(
              "authenticatedIdentity"
            );
    
            if (authenticationPublicKey === null) {
    
    Alexey Lunin's avatar
    Alexey Lunin committed
              result({
                data: "",
                code: "400",
    
                status: "Identity not authenticated"
    
            if (window.loadedIdentities[authenticationPublicKey] === null) {
    
    Alexey Lunin's avatar
    Alexey Lunin committed
              result({
                data: "",
                code: "400",
    
                status: "Identity not authenticated"
    
    Zdravko Iliev's avatar
    Zdravko Iliev committed
            const success = extendPinCodeTtl(authenticationPublicKey);
    
    Alexey Lunin's avatar
    Alexey Lunin committed
            if (success === false) {
              result({
                data: "",
                code: "400",
    
                status: "Identity not authenticated"
    
    Alexey Lunin's avatar
    Alexey Lunin committed
              });
    
    Alexey Lunin's avatar
    Alexey Lunin committed
            executeRestfulFunction(
              "private",
              viamApi,
              viamApi.identityHasSession,
              null
    
              result(executeResult);
            });
          });
        },
        marketingSignUpIdentificator(identificator, reference) {
    
          return new Penpal.Promise(result => {
    
    Markin Igor's avatar
    Markin Igor committed
            viamApi.setIdentity("marketingapppublickey");
    
    Alexey Lunin's avatar
    Alexey Lunin committed
            executeRestfulFunction(
              "public",
              viamApi,
              viamApi.marketingSignUpIdentificator,
              null,
              identificator,
              reference
    
    Markin Igor's avatar
    Markin Igor committed
              viamApi.setIdentity("");
    
    Markin Igor's avatar
    Markin Igor committed
              viamApi.setSessionData("", "");
    
              result(executeResult);
            });
          });
        },
        marketingGetIdentificatorProfile(identificator, pincode) {
    
          return new Penpal.Promise(result => {
    
    Markin Igor's avatar
    Markin Igor committed
            viamApi.setIdentity("marketingapppublickey");
    
    Alexey Lunin's avatar
    Alexey Lunin committed
            executeRestfulFunction(
              "public",
              viamApi,
              viamApi.marketingGetIdentificatorProfile,