Skip to content
Snippets Groups Projects
viamapi-iframe.js 70.8 KiB
Newer Older
  • Learn to ignore specific revisions
  • Sasha Ilieva's avatar
    Sasha Ilieva committed
    import "../lib/textencoder.polyfill";
    
    import { parseSMIME, prepareVCardParts } from "../utilities/emailUtilities";
    
    import {
      stringToUtf8ByteArray,
      utf8ByteArrayToString,
      stringToUtf8Base64,
      utf8Base64ToString,
      base64ToByteArray,
      byteArrayToBase64
    
    Alexey Lunin's avatar
    Alexey Lunin committed
    } from "../utilities/stringUtilities";
    
    import { extractMessageID } from "../helpers/mailparser";
    
    Alexey Lunin's avatar
    Alexey Lunin committed
    const QRCode = require("qrcode");
    const Penpal = require("penpal").default;
    
    import {
      createDeviceHash,
      destroyIdentityFromLocalStorage,
      encodeResponse,
    
    Alexey Lunin's avatar
    Alexey Lunin committed
      listIdentitiesFromLocalStorage,
      makeid
    } from "../utilities/appUtility";
    import { LOGIN_MODES } from "../constants/authentication";
    
    Damyan Mitev's avatar
    Damyan Mitev committed
      ImageData,
    
      createOneTimePassportCertificate,
      createPassportCertificate,
      decryptMessage,
    
      encryptMessage,
      parseCertificate,
    
      signEmail,
      verifySMIME
    
    Alexey Lunin's avatar
    Alexey Lunin committed
    } from "../utilities/signingUtilities";
    import { signPdf } from "../utilities/pdfUtilities";
    import CryptoData from "../CryptoData";
    import Identity from "../Identity";
    
    import {
      STATUS_DEVICE_REVOKED,
    
    Sasha Ilieva's avatar
    Sasha Ilieva committed
      STATUS_USER_NOT_ACTIVATED,
      STATUS_USER_BLOCKED
    
    } from "../constants/statuses";
    import generateQrCode from "../utilities/generateQrCode";
    
    Alexey Lunin's avatar
    Alexey Lunin committed
    
    const penpalMethods = require("../../temp/penpal-methods").default;
    const WopiAPI = require("./wopiapi-iframe");
    const CollaboraAPI = require("./collaboraapi-iframe");
    const ViamAPI = require("../../temp/viamapi");
    
    Zdravko Iliev's avatar
    Zdravko Iliev committed
    const identityColors = ["#994392", "#cb0767", "#e51d31", "#ec671b", "#fab610"];
    
    
    function getNextColor() {
    
    Alexey Lunin's avatar
    Alexey Lunin committed
      let colorIndex = localStorage.getItem("colorIndex");
    
    Markin Igor's avatar
    Markin Igor committed
      if (colorIndex == null || colorIndex === "") {
    
    Alexey Lunin's avatar
    Alexey Lunin committed
        colorIndex = 0;
    
    Zdravko Iliev's avatar
    Zdravko Iliev committed
      const color = identityColors[colorIndex];
    
    Markin Igor's avatar
    Markin Igor committed
      colorIndex = colorIndex % identityColors.length;
    
    Markin Igor's avatar
    Markin Igor committed
      localStorage.setItem("colorIndex", colorIndex);
    
    Alexey Lunin's avatar
    Alexey Lunin committed
      return color;
    
    }
    
    function setKeyForUUID(uuid, key) {
    
    Zdravko Iliev's avatar
    Zdravko Iliev committed
      const storedIdentityForUuid = localStorage.getItem("keyperuuid/" + uuid);
    
    Alexey Lunin's avatar
    Alexey Lunin committed
      if (
        storedIdentityForUuid !== key &&
        storedIdentityForUuid != null &&
        storedIdentityForUuid !== ""
      ) {
        destroyIdentityFromLocalStorage(storedIdentityForUuid);
    
    Alexey Lunin's avatar
    Alexey Lunin committed
      localStorage.setItem("keyperuuid/" + uuid, key);
    
    }
    
    function getColorForIdentity(key) {
    
    Alexey Lunin's avatar
    Alexey Lunin committed
      let storedColor = localStorage.getItem("colors/" + key);
    
    Alexey Lunin's avatar
    Alexey Lunin committed
      if (storedColor == null || storedColor === "") {
    
    Markin Igor's avatar
    Markin Igor committed
        storedColor = getNextColor();
    
    Alexey Lunin's avatar
    Alexey Lunin committed
        localStorage.setItem("colors/" + key, storedColor);
    
    Alexey Lunin's avatar
    Alexey Lunin committed
      return storedColor;
    
    }
    
    function setIdentityInLocalStorage(identityToStore, extendKey = true) {
    
    Alexey Lunin's avatar
    Alexey Lunin committed
      let pinCode = identityToStore.pinCode;
    
      const serializedIdentity = JSON.stringify(identityToStore);
      const key = identityToStore.authentication.publicKey;
    
    
    Alexey Lunin's avatar
    Alexey Lunin committed
      if (pinCode == null || pinCode === "") {
        pinCode = getPincode(key);
    
    Alexey Lunin's avatar
    Alexey Lunin committed
      if (pinCode == null || pinCode === "") {
    
    Alexey Lunin's avatar
    Alexey Lunin committed
      return encryptMessage(serializedIdentity, pinCode, "identity").then(
        encryptedIdentity => {
    
    Alexey Lunin's avatar
    Alexey Lunin committed
          let success = true;
    
    Alexey Lunin's avatar
    Alexey Lunin committed
          if (extendKey === true) {
            success = extendPinCodeTtl(key, pinCode);
          }
          if (success === true) {
            localStorage.setItem(key, encryptedIdentity);
    
    Zdravko Iliev's avatar
    Zdravko Iliev committed
            const serializedIdentitiesList = localStorage.getItem("identities");
            const identities = JSON.parse(serializedIdentitiesList);
    
    Alexey Lunin's avatar
    Alexey Lunin committed
            identities[key] = true;
    
    Alexey Lunin's avatar
    Alexey Lunin committed
            localStorage.setItem("identities", JSON.stringify(identities));
          } else {
            console.log("Can not extend pincode ttl");
          }
    
    Alexey Lunin's avatar
    Alexey Lunin committed
      );
    
    }
    
    function getProfileData(identity) {
      return new Penpal.Promise(executeResultUpper => {
    
    Alexey Lunin's avatar
    Alexey Lunin committed
        executeRestfulFunction(
          "private",
          viamApi,
          viamApi.identityGetIdentityProfileData,
          null
        ).then(executeResult => {
          if (executeResult.code === "200") {
    
    Zdravko Iliev's avatar
    Zdravko Iliev committed
            const listItem = {};
    
    Alexey Lunin's avatar
    Alexey Lunin committed
            listItem.identityColor = getColorForIdentity(
              identity.authentication.publicKey
            );
    
    Markin Igor's avatar
    Markin Igor committed
            listItem.initials = executeResult.data.initials;
    
    Alexey Lunin's avatar
    Alexey Lunin committed
            if (listItem.initials === null || listItem.initials === "") {
    
              listItem.initials = "JD";
            }
    
    Alexey Lunin's avatar
    Alexey Lunin committed
            localStorage.setItem(
              "profiles/" + identity.authentication.publicKey,
              JSON.stringify(listItem)
            );
            executeResultUpper(listItem);
    
          } else {
    
    Alexey Lunin's avatar
    Alexey Lunin committed
            executeResultUpper({});
    
    async function getIdentityFromLocalStorage(key, pinCode, extendTtl = true) {
    
      const encryptedIdentity = localStorage.getItem(key);
    
    Markin Igor's avatar
    Markin Igor committed
        console.log("No such identity for public key");
    
      const serializedIdentity = await decryptMessage(encryptedIdentity, pinCode);
    
      const identity = new Identity(serializedIdentity);
    
      if (extendTtl) {
        const success = extendPinCodeTtl(key, pinCode);
        if (!success) {
          console.log("Can not extend pincode ttl");
          return null;
        }
      }
    
    function extendPinCodeTtl(key, pinCode) {
    
    Alexey Lunin's avatar
    Alexey Lunin committed
      if (pinCode == null || pinCode === "") {
    
    Zdravko Iliev's avatar
    Zdravko Iliev committed
        const now = new Date();
        const nowMillis = now.getTime();
        const ttl = window.sessionStorage.getItem("pincodettls/" + key);
    
        if (ttl == null || ttl === "" || nowMillis >= parseInt(ttl)) {
    
    Markin Igor's avatar
    Markin Igor committed
          clearPinCodeTtl(key);
    
    Alexey Lunin's avatar
    Alexey Lunin committed
          return false;
    
    Zdravko Iliev's avatar
    Zdravko Iliev committed
          const ttl = now.getTime() + 4 * 60 * 60 * 1000;
    
          window.sessionStorage.setItem("pincodettls/" + key, ttl);
        }
      } else {
    
    Zdravko Iliev's avatar
    Zdravko Iliev committed
        const now = new Date();
        const ttl = now.getTime() + 4 * 60 * 60 * 1000;
    
        window.sessionStorage.setItem("pincodettls/" + key, ttl);
        window.sessionStorage.setItem("pincodes/" + key, pinCode);
      }
    
      return true;
    }
    
    window.extendPinCodeTtl = extendPinCodeTtl;
    
    
    function clearPinCodeTtl(key) {
    
    Markin Igor's avatar
    Markin Igor committed
      window.sessionStorage.removeItem("pincodettls/" + key);
    
    Alexey Lunin's avatar
    Alexey Lunin committed
      window.sessionStorage.removeItem("pincodes/" + key);
    
    }
    
    function getPincode(key) {
    
    Zdravko Iliev's avatar
    Zdravko Iliev committed
      const now = new Date();
      const nowMillis = now.getTime();
      const ttl = window.sessionStorage.getItem("pincodettls/" + key);
    
    Markin Igor's avatar
    Markin Igor committed
      if (ttl == null || ttl === "") {
    
    Alexey Lunin's avatar
    Alexey Lunin committed
        return null;
    
      } else {
    
    Alexey Lunin's avatar
    Alexey Lunin committed
        if (nowMillis >= parseInt(ttl)) {
    
    Markin Igor's avatar
    Markin Igor committed
          clearPinCodeTtl(key);
    
    Alexey Lunin's avatar
    Alexey Lunin committed
          return null;
    
        } else {
          return window.sessionStorage.getItem("pincodes/" + key);
        }
      }
    }
    
    function createEvent(actionId, type, payloads) {
      return {
    
    Alexey Lunin's avatar
    Alexey Lunin committed
        actionID: actionId,
    
    Zdravko Iliev's avatar
    Zdravko Iliev committed
        type,
    
    Alexey Lunin's avatar
    Alexey Lunin committed
        stamp: new Date().getTime(),
    
    Zdravko Iliev's avatar
    Zdravko Iliev committed
        payloads
    
    Alexey Lunin's avatar
    Alexey Lunin committed
      };
    
    const destroyAuthentication = () => {
      const authenticationPublicKey = localStorage.getItem("authenticatedIdentity");
    
      window.viamApi.setIdentity("");
      window.viamApi.setSessionData("", "");
    
      clearPinCodeTtl(authenticationPublicKey);
    
      localStorage.removeItem("uuid");
      localStorage.removeItem("token");
      localStorage.removeItem("authenticatedIdentity");
    
      window.currentlyAuthenticatedIdentity = null;
      window.lastTimeGetProfile = 0;
    };
    
    const destroyIdentity = () => {
      destroyAuthentication();
    
      if (window.currentlyLoadedIdentity) {
        const { publicKey } = window.currentlyLoadedIdentity.authentication;
    
        delete window.loadedIdentities[publicKey];
        window.currentlyLoadedIdentity = null;
        destroyIdentityFromLocalStorage(publicKey);
      }
    };
    
    
    Markin Igor's avatar
    Markin Igor committed
    window.loadedIdentities = {};
    
    window.wopiAPI = new WopiAPI();
    
    window.collaboraApi = new CollaboraAPI();
    
    window.viamApi = new ViamAPI();
    window.viamAnonymousApi = new ViamAPI();
    
    Markin Igor's avatar
    Markin Igor committed
    window.currentlyAuthenticatedIdentity = null;
    window.currentlyLoadedIdentity = null;
    window.lastTimeGetProfile = 0;
    
    let iframeParent = null;
    
    
    Markin Igor's avatar
    Markin Igor committed
    const handleIdentityLogin = (identity, uuid, token) => {
      const { loadedIdentities, viamApi } = window;
      const { publicKey } = identity.authentication;
    
      viamApi.setSessionData(uuid, token);
      localStorage.setItem("uuid", uuid);
      localStorage.setItem("token", token);
      localStorage.setItem("authenticatedIdentity", publicKey);
      window.currentlyAuthenticatedIdentity = loadedIdentities[publicKey];
      window.lastTimeGetProfile = 0;
      setKeyForUUID(uuid, publicKey);
    
    async function executeRestfulFunction(type, that, fn, config, ...args) {
    
    Alexey Lunin's avatar
    Alexey Lunin committed
      const {
        currentlyAuthenticatedIdentity,
        viamApi,
        currentlyLoadedIdentity
      } = window;
    
      let response;
      try {
        response = await fn.apply(that, [config, ...args]);
      } catch (error) {
        if (error.response) {
          //Resposnse with status code != 2xx still has valid response
          response = error.response;
        } else {
          //Connection error or similar
          const data = {
    
    Alexey Lunin's avatar
    Alexey Lunin committed
            data: "",
            code: "999",
            status: error.message
    
      const identity = currentlyAuthenticatedIdentity || currentlyLoadedIdentity;
    
    Sasha Ilieva's avatar
    Sasha Ilieva committed
      console.log({ response });
    
    Alexey Lunin's avatar
    Alexey Lunin committed
      const deviceRevoked =
        type === "private" && code === "401" && status === STATUS_DEVICE_REVOKED;
    
        const event = createEvent("", "DeviceRevoked");
        iframeParent.onEvent(event);
    
      const userNotActivated =
        type === "private" &&
        code === "400" &&
    
    Sasha Ilieva's avatar
    Sasha Ilieva committed
        (status === STATUS_USER_NOT_ACTIVATED || status === STATUS_USER_BLOCKED);
    
    
      if (userNotActivated) {
        destroyIdentity();
    
    
    Sasha Ilieva's avatar
    Sasha Ilieva committed
        const event = createEvent("", "UserBlocked");
    
        iframeParent.onEvent(event);
    
        return response.data;
      }
    
    
    Alexey Lunin's avatar
    Alexey Lunin committed
      const badSession =
        type === "private" &&
        identity &&
        code === "400" &&
        status === "Bad session";
    
    Sasha Ilieva's avatar
    Sasha Ilieva committed
      if (!badSession) {
        return response.data;
      }
    
    Alexey Lunin's avatar
    Alexey Lunin committed
      const loginResponse = await viamApi.identityLogin(
        null,
        "previousaddeddevice"
      );
    
    Sasha Ilieva's avatar
    Sasha Ilieva committed
      if (loginResponse.data.code !== "200") {
        return loginResponse.data;
      }
    
    
      const uuid = loginResponse.data.data["Uuid"];
      const token = loginResponse.data.data["Session"];
      handleIdentityLogin(identity, uuid, token);
    
      try {
        response = await fn.apply(that, [config, ...args]);
      } catch (error) {
        response = error.response;
      }
      return response.data;
    
    }
    
    window.executeRestfulFunction = executeRestfulFunction;
    
    
    function loadIdentityInternal(identityKey, pinCode) {
      return new Penpal.Promise(result => {
    
    Alexey Lunin's avatar
    Alexey Lunin committed
        getIdentityFromLocalStorage(identityKey, pinCode)
          .then(async loadedIdentity => {
            if (loadedIdentity == null) {
              result({
                data: "",
                code: "400",
                status:
                  "Please restore or authorize your account via another device."
              });
            }
            localStorage.removeItem("attempt");
    
            window.loadedIdentities[identityKey] = loadedIdentity;
            window.currentlyLoadedIdentity = loadedIdentity;
    
            if (identityKey === localStorage.getItem("authenticatedIdentity")) {
              window.currentlyAuthenticatedIdentity = loadedIdentity;
              const uuid = localStorage.getItem("uuid");
              const token = localStorage.getItem("token");
              const deviceHash = await createDeviceHash(identityKey);
              window.viamApi.setIdentity(identityKey);
              window.viamApi.setDeviceHash(deviceHash);
              window.viamApi.setSessionData(uuid, token);
            }
    
    Alexey Lunin's avatar
    Alexey Lunin committed
            window.viamAnonymousApi.setIdentity(
              window.currentlyLoadedIdentity.authentication.publicKey
            );
    
    Alexey Lunin's avatar
    Alexey Lunin committed
            const { publicKey, x509Certificate } = loadedIdentity.authentication;
    
    Alexey Lunin's avatar
    Alexey Lunin committed
            result({
              data: {
                authentication: {
                  publicKey,
                  x509Certificate
                }
              },
              code: "200",
              status: "Identity loaded"
            });
          })
          .catch(e => {
            result({
              data: "",
              code: "400",
              status: "" + e
            });
    
      });
    }
    
    function getCertificateForPassport(passportUUID, internal) {
      return new Penpal.Promise(certificateResult => {
    
        if (window.currentlyAuthenticatedIdentity === null) {
    
    Sasha Ilieva's avatar
    Sasha Ilieva committed
          return { data: "", code: "400", status: "Identity not authenticated" };
    
        const passportIdentity = window.currentlyAuthenticatedIdentity;
    
    Zdravko Iliev's avatar
    Zdravko Iliev committed
        const passport = passportIdentity.getPassport(passportUUID);
    
    Alexey Lunin's avatar
    Alexey Lunin committed
        if (passport === undefined || passport === null) {
    
    Sasha Ilieva's avatar
    Sasha Ilieva committed
          createPassportCertificate(passportUUID).then(function(keys) {
    
    Zdravko Iliev's avatar
    Zdravko Iliev committed
            const cryptoData = new CryptoData();
    
    Markin Igor's avatar
    Markin Igor committed
            cryptoData.setPublicKey(keys["publicKeyPEM"]);
            cryptoData.setPrivateKey(keys["privateKeyPEM"]);
    
    Zdravko Iliev's avatar
    Zdravko Iliev committed
            const certificate = keys["certificatePEM"];
    
            //download("passportCertificateBeforeSigning.crt", "text/plain", certificate)
            //cryptoData.setx509Certificate(keys["certificate"])
    
    Alexey Lunin's avatar
    Alexey Lunin committed
            executeRestfulFunction(
              "private",
              viamApi,
              viamApi.signSignCertificate,
              null,
              btoa(certificate),
              passportUUID
            ).then(executeResult => {
              if (executeResult.code === "200") {
    
    Zdravko Iliev's avatar
    Zdravko Iliev committed
                const signedCertificate = atob(
    
    Alexey Lunin's avatar
    Alexey Lunin committed
                  executeResult.data["SignedCertificate"]
                );
    
                //download("passportCertificateAfterSigning.crt", "text/plain", signedCertificate)
    
    Zdravko Iliev's avatar
    Zdravko Iliev committed
                const keyUUID = executeResult.data["CertificateUUID"];
                const encodedChain = executeResult.data["Chain"];
    
                //download("rootCertificate.crt", "text/plain", atob(encodedChain[0]))
    
    
    Zdravko Iliev's avatar
    Zdravko Iliev committed
                const chain = [];
    
    Alexey Lunin's avatar
    Alexey Lunin committed
                for (let i = 0; i < encodedChain.length; i++) {
    
    Alexey Lunin's avatar
    Alexey Lunin committed
                  chain.push(atob(encodedChain[i]));
    
    Markin Igor's avatar
    Markin Igor committed
                cryptoData.setx509Certificate(signedCertificate);
                cryptoData.setKeyUUID(keyUUID);
                cryptoData.setChain(chain);
    
    Markin Igor's avatar
    Markin Igor committed
                passportIdentity.setPassport(passportUUID, cryptoData);
    
    
                getProfileData(passportIdentity).then(executeResult1 => {
    
    Alexey Lunin's avatar
    Alexey Lunin committed
                  setIdentityInLocalStorage(passportIdentity)
                    .then(() => {
                      window.currentlyAuthenticatedIdentity = passportIdentity;
                      window.lastTimeGetProfile = 0;
                      window.currentlyLoadedIdentity = passportIdentity;
                      const copyOfCryptoData = JSON.parse(
                        JSON.stringify(cryptoData)
                      );
    
                      if (internal === false) {
                        copyOfCryptoData["privateKey"] = "";
                      }
    
                      certificateResult({
                        data: copyOfCryptoData,
                        code: "200",
                        status: "Certificate got"
                      });
                    })
                    .catch(e => {
                      certificateResult({
                        data: "",
                        code: "400",
                        status: "Can not store certificate " + e
                      });
    
                certificateResult(executeResult);
    
    Zdravko Iliev's avatar
    Zdravko Iliev committed
          const copyOfCryptoData = JSON.parse(JSON.stringify(passport));
    
    Alexey Lunin's avatar
    Alexey Lunin committed
          if (internal === false) {
            copyOfCryptoData["privateKey"] = "";
    
    Alexey Lunin's avatar
    Alexey Lunin committed
          certificateResult({
            data: copyOfCryptoData,
            code: "200",
            status: "Certificate got"
    
          });
        }
      });
    }
    
    const connection = Penpal.connectToParent({
      // Methods child is exposing to parent
      methods: {
    
        initialize: (apiUrl, wopiUrl, collaboraUrl) => {
    
          if (!apiUrl) {
            apiUrl = `${window.location.origin}/api/`;
            console.warn(`API host URL not specified. Fall back to ${apiUrl}`); // eslint-disable-line no-console
          }
    
          if (!wopiUrl) {
            wopiUrl = `${window.location.origin}/wopi/`;
            console.warn(`WOPI host URL not specified. Fall back to ${wopiUrl}`); // eslint-disable-line no-console
          }
    
          if (!collaboraUrl) {
            collaboraUrl = window.location.origin;
    
    Alexey Lunin's avatar
    Alexey Lunin committed
            console.warn(
              `Collabora host URL not specified. Fall back to ${collaboraUrl}`
            ); // eslint-disable-line no-console
    
    Alexey Lunin's avatar
    Alexey Lunin committed
          window.API_HOST =
            apiUrl.charAt(apiUrl.length - 1) === "/" ? apiUrl : apiUrl + "/";
          window.WOPI_URL =
            wopiUrl.charAt(wopiUrl.length - 1) === "/" ? wopiUrl : wopiUrl + "/";
          window.COLLABORA_URL =
    
    Sasha Ilieva's avatar
    Sasha Ilieva committed
            collaboraUrl.charAt(collaboraUrl.length - 1) === "/"
              ? collaboraUrl
              : collaboraUrl + "/";
    
        createIdentity(pinCode) {
          return new Penpal.Promise(result => {
    
    Sasha Ilieva's avatar
    Sasha Ilieva committed
            createPassportCertificate(makeid()).then(function(keys) {
    
    Zdravko Iliev's avatar
    Zdravko Iliev committed
              const newIdentity = new Identity();
              const cryptoData = new CryptoData();
    
    Markin Igor's avatar
    Markin Igor committed
              cryptoData.setPublicKey(keys["publicKeyPEM"]);
              cryptoData.setPrivateKey(keys["privateKeyPEM"]);
              cryptoData.setx509Certificate(keys["certificatePEM"]);
              newIdentity.setAuthentication(cryptoData);
              newIdentity.setPinCode(pinCode);
    
              window.currentlyLoadedIdentity = newIdentity;
    
              const { publicKey, x509Certificate } = newIdentity.authentication;
    
              window.loadedIdentities[publicKey] = newIdentity;
    
    Markin Igor's avatar
    Markin Igor committed
              extendPinCodeTtl(newIdentity.authentication.publicKey, pinCode);
    
    Alexey Lunin's avatar
    Alexey Lunin committed
              window.viamAnonymousApi.setIdentity(
                newIdentity.authentication.publicKey
              );
    
    Alexey Lunin's avatar
    Alexey Lunin committed
              result({
    
                data: {
                  authentication: {
                    publicKey,
                    x509Certificate
                  }
                },
    
    Alexey Lunin's avatar
    Alexey Lunin committed
                code: "200",
                status: "Identity created"
              });
    
    Alexey Lunin's avatar
    Alexey Lunin committed
          });
    
        },
        listIdentities() {
          return new Penpal.Promise(result => {
    
    Zdravko Iliev's avatar
    Zdravko Iliev committed
            const identities = listIdentitiesFromLocalStorage();
    
    Sasha Ilieva's avatar
    Sasha Ilieva committed
            result({ data: identities, code: "200", status: "Identities listed" });
    
          });
        },
        loadIdentity(identityKey, pinCode) {
    
    Alexey Lunin's avatar
    Alexey Lunin committed
          return loadIdentityInternal(identityKey, pinCode);
    
        checkIdentityPinCode: async (key, pinCode) => {
          try {
            const identity = await getIdentityFromLocalStorage(key, pinCode, false);
    
            if (identity) {
              return encodeResponse("200", null, "Pincode check successful");
            } else {
              return encodeResponse("400", null, "Pincode check failed");
            }
          } catch (e) {
            return encodeResponse("400", e, "Pincode check error");
          }
        },
        changeIdentityPinCode: async (key, oldPinCode, newPinCode) => {
          try {
    
    Alexey Lunin's avatar
    Alexey Lunin committed
            const identity = await getIdentityFromLocalStorage(
              key,
              oldPinCode,
              false
            );
    
    
            if (identity) {
              identity.pinCode = newPinCode;
              await setIdentityInLocalStorage(identity);
    
              window.currentlyAuthenticatedIdentity = identity;
              window.currentlyLoadedIdentity = identity;
    
    igorwork's avatar
    igorwork committed
              return encodeResponse("200", null, "Successfully changed pincode");
    
    igorwork's avatar
    igorwork committed
              return encodeResponse("400", null, "Identity not found");
    
    igorwork's avatar
    igorwork committed
            return encodeResponse("400", e.message, "Change pincode error");
    
        },
        getIdentityProfile(identityKey) {
          return new Penpal.Promise(result => {
    
    Alexey Lunin's avatar
    Alexey Lunin committed
            const serializedProfile = localStorage.getItem(
              "profiles/" + identityKey
            );
    
            if (serializedProfile === null || serializedProfile === "") {
    
    Sasha Ilieva's avatar
    Sasha Ilieva committed
              result({ data: "", code: "400", status: "Profile is empty" });
    
            } else {
    
    Alexey Lunin's avatar
    Alexey Lunin committed
              result({
                data: JSON.parse(serializedProfile),
                code: "200",
                status: "Identities cleared"
              });
    
        clearIdentities: async () => {
          destroyAuthentication();
    
          const identitiesTemp = listIdentitiesFromLocalStorage();
    
          for (const i in identitiesTemp) {
            destroyIdentityFromLocalStorage(i);
          }
          return encodeResponse("200", "", "Identities cleared");
    
        confirmIdentificator(identity, confirmationCodeArg) {
          return new Penpal.Promise(result => {
    
    Markin Igor's avatar
    Markin Igor committed
            viamApi.setIdentity(identity.authentication.publicKey);
    
    Alexey Lunin's avatar
    Alexey Lunin committed
            executeRestfulFunction(
              "public",
              viamApi,
              viamApi.identityConfirmIdentificator,
              null,
              confirmationCodeArg
            ).then(executeResult => {
    
              result(executeResult);
            });
          });
        },
        identityGetIdentificatorByRegisterToken(identity, tokenArg) {
          return new Penpal.Promise(result => {
    
    Markin Igor's avatar
    Markin Igor committed
            viamApi.setIdentity(identity.authentication.publicKey);
    
    Alexey Lunin's avatar
    Alexey Lunin committed
            executeRestfulFunction(
              "public",
              viamApi,
              viamApi.identityGetIdentificatorByRegisterToken,
              null,
              tokenArg
            ).then(executeResult => {
    
              result(executeResult);
            });
          });
        },
        submitIdentificator(identity, identificatorArg, registerToken) {
          return new Penpal.Promise(result => {
    
    Markin Igor's avatar
    Markin Igor committed
            viamApi.setIdentity(identity.authentication.publicKey);
    
    Alexey Lunin's avatar
    Alexey Lunin committed
            executeRestfulFunction(
              "public",
              viamApi,
              viamApi.identitySubmitIdentificator,
              null,
              identificatorArg,
              registerToken
            ).then(executeResult => {
    
    Alexey Lunin's avatar
    Alexey Lunin committed
        submitRegisterClaims(
          identity,
          givennameArg,
          familynameArg,
          emailArg,
          phonenumberArg
        ) {
    
          return new Penpal.Promise(result => {
    
    Markin Igor's avatar
    Markin Igor committed
            viamApi.setIdentity(identity.authentication.publicKey);
    
    Alexey Lunin's avatar
    Alexey Lunin committed
            executeRestfulFunction(
              "public",
              viamApi,
              viamApi.identitySubmitRegisterClaims,
              null,
              givennameArg,
              familynameArg,
              emailArg,
              phonenumberArg
            ).then(executeResult => {
    
              result(executeResult);
            });
          });
        },
        agreeOnRegistration(registerIdentity) {
    
          return new Penpal.Promise(result => {
    
    Markin Igor's avatar
    Markin Igor committed
            viamApi.setIdentity(registerIdentity.authentication.publicKey);
    
    Alexey Lunin's avatar
    Alexey Lunin committed
            executeRestfulFunction(
              "public",
              viamApi,
              viamApi.identityAgreeOnRegistration,
              null
            ).then(executeResult => {
    
    Markin Igor's avatar
    Markin Igor committed
              let sequence = Promise.resolve();
    
              if (executeResult.code === "200") {
                sequence = sequence.then(() => {
    
    Alexey Lunin's avatar
    Alexey Lunin committed
                  setIdentityInLocalStorage(registerIdentity);
                });
    
    Alexey Lunin's avatar
    Alexey Lunin committed
              sequence
                .then(() => {
                  result(executeResult);
    
    Alexey Lunin's avatar
    Alexey Lunin committed
                .catch(e => {
                  result({
                    data: "",
                    code: "400",
                    status: "Can not store identity: " + e
                  });
                });
    
            });
          });
        },
        resendConfirmationCode(identity, identificatorArg) {
          return new Penpal.Promise(result => {
    
    Markin Igor's avatar
    Markin Igor committed
            viamApi.setIdentity(identity.authentication.publicKey);
    
    Alexey Lunin's avatar
    Alexey Lunin committed
            executeRestfulFunction(
              "public",
              viamApi,
              viamApi.identityResendConfirmationCode,
              null,
              identificatorArg
            ).then(executeResult => {
    
              result(executeResult);
            });
          });
        },
    
    Markin Igor's avatar
    Markin Igor committed
        login: async (loginIdentity, mode, requestCode, requestActionID) => {
          if (!window.loadedIdentities[loginIdentity.authentication.publicKey]) {
            return {
              data: "",
              code: "400",
              status: "Identity not loaded"
            };
          }
    
    Alexey Lunin's avatar
    Alexey Lunin committed
          const deviceHash = await createDeviceHash(
            loginIdentity.authentication.publicKey
          );
    
          window.viamApi.setSessionData("", "");
    
    Markin Igor's avatar
    Markin Igor committed
          window.viamApi.setDeviceHash(deviceHash);
    
    Markin Igor's avatar
    Markin Igor committed
          window.viamApi.setIdentity(loginIdentity.authentication.publicKey);
    
    
    Alexey Lunin's avatar
    Alexey Lunin committed
          const identityLoginResponse = await executeRestfulFunction(
            "public",
            window.viamApi,
            window.viamApi.identityLogin,
            null,
            mode,
            requestCode,
            requestActionID
          );
    
    Markin Igor's avatar
    Markin Igor committed
    
          const { code, data } = identityLoginResponse;
          const responseToClient = Object.assign({}, identityLoginResponse);
    
          if (code === "200") {
    
    Alexey Lunin's avatar
    Alexey Lunin committed
            if (
              mode === LOGIN_MODES.SMS ||
              mode === LOGIN_MODES.PREVIOUSLY_ADDED_DEVICE
            ) {
    
    Markin Igor's avatar
    Markin Igor committed
              handleIdentityLogin(loginIdentity, data.Uuid, data.Session);
    
    Markin Igor's avatar
    Markin Igor committed
              await getProfileData(loginIdentity);
    
    
              if (mode === LOGIN_MODES.SMS) {
    
    Markin Igor's avatar
    Markin Igor committed
                await setIdentityInLocalStorage(loginIdentity);
    
    Markin Igor's avatar
    Markin Igor committed
            } else if (mode === LOGIN_MODES.NEW_DEVICE) {
    
    Alexey Lunin's avatar
    Alexey Lunin committed
              const dataUrl = await QRCode.toDataURL(
                `${data.ActionID},${data.QrCode}`
              );
    
    Markin Igor's avatar
    Markin Igor committed
              Object.assign(responseToClient.data, { image: dataUrl });
            }
          }
    
          return responseToClient;
    
        },
        identityAddNewDevice() {
          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
            executeRestfulFunction(
              "private",
              viamApi,
              viamApi.identityAddNewDevice,
              null
            ).then(executeResult => {
    
    Markin Igor's avatar
    Markin Igor committed
              if (executeResult.code === "200") {
    
    Zdravko Iliev's avatar
    Zdravko Iliev committed
                const actionID = executeResult.data["ActionID"];
                const QrCode = executeResult.data["QrCode"];
    
    Sasha Ilieva's avatar
    Sasha Ilieva committed
                QRCode.toDataURL(actionID + "," + QrCode, function(err, url) {
    
    Markin Igor's avatar
    Markin Igor committed
                  executeResult.data["image"] = url;
    
                  result(executeResult);
    
    Alexey Lunin's avatar
    Alexey Lunin committed
                });
    
              } else {
                result(executeResult);
              }
            });
          });
        },
        identityDestroyKeysForDevice(authenticationPublicKeyArg) {
          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
            executeRestfulFunction(
              "private",
              viamApi,
              viamApi.identityDestroyKeysForDevice,
              null,
              btoa(authenticationPublicKeyArg)
            ).then(executeResult => {
    
              result(executeResult);
            });
          });
        },
    
    Markin Igor's avatar
    Markin Igor committed
        logout: async () => {
    
    Alexey Lunin's avatar
    Alexey Lunin committed
            const authenticationPublicKey = localStorage.getItem(
              "authenticatedIdentity"
            );
            if (
              !authenticationPublicKey ||
              !window.loadedIdentities[authenticationPublicKey]
            ) {
    
              return {
                data: "",
                code: "400",
                status: "Identity not loaded"
              };
            }
    
    
    igorwork's avatar
    igorwork committed
            // Clone headers to be able destroy authentication first.
            // We need it because clients should be able reload page right after logout invocation and not wait until request completed
    
    Alexey Lunin's avatar
    Alexey Lunin committed
            const headers = { ...window.viamApi.getConfig().headers };
    
            return executeRestfulFunction(
    
              "private",
              window.viamApi,
              window.viamApi.identityLogout,
    
    Markin Igor's avatar
    Markin Igor committed
            return {
              data: "",
              code: "400",
    
              status: e.message
    
    Markin Igor's avatar
    Markin Igor committed
            };
    
          }
        },
        identityRestoreAccess(restoreAccessIdentity, identificator) {
          return new Penpal.Promise(result => {
    
            viamApi.setSessionData("", "");
    
    Markin Igor's avatar
    Markin Igor committed
            viamApi.setIdentity(restoreAccessIdentity.authentication.publicKey);
    
    Alexey Lunin's avatar
    Alexey Lunin committed
            executeRestfulFunction(
              "public",
              viamApi,
              viamApi.identityRestoreAccess,
              null,
              identificator
            ).then(executeResult => {
              result(executeResult);
    
        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
            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",
              status: "UUID loaded"
            });
    
          });
        },
        getCertificateByPassport(passportUUID) {
          return new Penpal.Promise(result => {
    
    Alexey Lunin's avatar
    Alexey Lunin committed
            const authenticationPublicKey = localStorage.getItem(
              "authenticatedIdentity"
            );
    
            if (authenticationPublicKey === null) {