Skip to content
Snippets Groups Projects
viamapi-iframe.js 83.4 KiB
Newer Older
  • Learn to ignore specific revisions
  • Sasha Ilieva's avatar
    Sasha Ilieva committed
          console.log("before checkAccountRecoveryStatus");
          console.log({ currentlyLoadedIdentity });
    
          const parsedIdentity = JSON.parse(currentlyLoadedIdentity);
          window.currentlyLoadedIdentity = parsedIdentity;
          const { publicKey } = parsedIdentity.authentication;
    
    Sasha Ilieva's avatar
    Sasha Ilieva committed
          console.log({ publicKey });
    
          window.loadedIdentities[publicKey] = parsedIdentity;
    
          window.viamAnonymousApi.setIdentity(publicKey);
    
          window.viamApi.setSessionData("", "");
          window.viamApi.setIdentity(publicKey);
    
    Sasha Ilieva's avatar
    Sasha Ilieva committed
          console.log("loadedIdentities", window.loadedIdentities);
    
    Sasha Ilieva's avatar
    Sasha Ilieva committed
          const timeout = ms => new Promise(resolve => setTimeout(resolve, ms));
    
          async function checkAccountRecoveryStatus() {
            const response = await executeRestfulFunction(
              "public",
              viamApi,
              viamApi.contactsCheckAccountRecoveryStatus,
              null
            );
    
    Sasha Ilieva's avatar
    Sasha Ilieva committed
            if (response.data === 0) {
              await timeout(1000);
              await checkAccountRecoveryStatus();
              return;
    
    Sasha Ilieva's avatar
    Sasha Ilieva committed
            const deviceHash = await createDeviceHash(publicKey);
            window.viamApi.setDeviceHash(deviceHash);
    
    
    Sasha Ilieva's avatar
    Sasha Ilieva committed
            const identityLoginResponse = await executeRestfulFunction(
              "public",
              window.viamApi,
              window.viamApi.identityLogin,
              null,
              "previousaddeddevice"
            );
    
    Sasha Ilieva's avatar
    Sasha Ilieva committed
            const { code, data } = identityLoginResponse;
    
            if (code === "200") {
    
              await setIdentityInLocalStorage(parsedIdentity);
    
    Sasha Ilieva's avatar
    Sasha Ilieva committed
              handleIdentityLogin(parsedIdentity, data.Uuid, data.Session);
    
    Sasha Ilieva's avatar
    Sasha Ilieva committed
              await getProfileData(parsedIdentity);
              localStorage.removeItem("currentlyLoadedIdentity");
    
    Sasha Ilieva's avatar
    Sasha Ilieva committed
            }
    
    Sasha Ilieva's avatar
    Sasha Ilieva committed
          }
    
    Sasha Ilieva's avatar
    Sasha Ilieva committed
          await checkAccountRecoveryStatus();
    
        contactsGetTrusteeContactsPublicKeys: async () => {
          try {
    
            const response = await executeRestfulFunction(
    
              "private",
              window.viamApi,
              window.viamApi.contactsGetTrusteeContactsPublicKeys,
              null
            );
    
    Sasha Ilieva's avatar
    Sasha Ilieva committed
    
    
            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
    
    
    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();
    
            let recoveryKeyShares = [recoveryKey];
    
            // Split the secret when sharesNumber is more than 1 because VereignPublicKey is always returned
            if (sharesNumber > 1) {
    
              recoveryKeyShares = getRecoveryKeyShares(recoveryKey, sharesNumber);
              const sanityCheckResponse = checkRecoveryKeyCombine(
                recoveryKey,
                recoveryKeyShares
              );
    
              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.code !== "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
        },
    
        /**
         * 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,
          signatureData = null,
          qrCodeUrl = null
    
          const authenticationPublicKey = localStorage.getItem(
            "authenticatedIdentity"
          );
    
          if (
            !authenticationPublicKey ||
            !window.loadedIdentities[authenticationPublicKey] ||
            !extendPinCodeTtl(authenticationPublicKey)
          ) {
            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") {
            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,
    
          );
          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;
    
    
          let qrCodeCoordinates = { fromL: -1, fromR: -1, toL: -1, toR: -1 };
    
          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;
          }
    
          if (
            vCardImageClaimValue &&
            "state" in vCardImageClaimValue &&
            vCardImageClaimValue.state === "disabled"
          ) {
    
          } else {
            const vCardImageResponse = await executeRestfulFunction(
              "private",
              window.viamApi,
              window.viamApi.passportGetVCardImage,
              null,
              passportUUID
            );
    
    Gospodin Bodurov's avatar
    Gospodin Bodurov committed
    
    
            if (vCardImageResponse.code !== "200") {
              return encodeResponse("400", "", vCardImageResponse.status);
            }
    
            vCardImageData = new ImageData(vCardImageResponse.data.Image);
    
            if (vCardImageData.contentType !== "image/png") {
    
                "Content type of vCard must 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();
    
          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