Skip to content
Snippets Groups Projects
viamapi-iframe.js 47.7 KiB
Newer Older
import { parseSMIME } from '../utilities/emailUtilities';

const QRCode = require('qrcode');
const Penpal = require('penpal').default;
import {
  createDeviceHash,
  destroyIdentityFromLocalStorage,
  encodeResponse,
  listIdentitiesFromLocalStorage, makeid
} from '../utilities/appUtility';
import {LOGIN_MODES} from '../constants/authentication';
import {
  createOneTimePassportCertificate,
  createPassportCertificate,
  decryptMessage,
  encryptMessage, signEmail
} from '../utilities/signingUtilities';
import CryptoData from '../CryptoData';
import Identity from '../Identity';
import {STATUS_DEVICE_REVOKED} from '../constants/statuses';
const penpalMethods = require('../../temp/penpal-methods').default;
const WopiAPI = require('./wopiapi-iframe');
const CollaboraAPI = require('./collaboraapi-iframe');
const ViamAPI = require('../../temp/viamapi');
Markin Igor's avatar
Markin Igor committed
var identityColors = ["#994392", "#cb0767", "#e51d31", "#ec671b", "#fab610"];

function getNextColor() {
  var colorIndex = localStorage.getItem("colorIndex");
Markin Igor's avatar
Markin Igor committed
  if (colorIndex == null || colorIndex === "") {
    colorIndex = 0
  }

Markin Igor's avatar
Markin Igor committed
  var 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);

  return color
}

function setKeyForUUID(uuid, key) {
Markin Igor's avatar
Markin Igor committed
  var storedIdentityForUuid = localStorage.getItem("keyperuuid/" + uuid);
Markin Igor's avatar
Markin Igor committed
  if(storedIdentityForUuid !== key && storedIdentityForUuid != null && storedIdentityForUuid !== "") {
    destroyIdentityFromLocalStorage(storedIdentityForUuid)
  }

  localStorage.setItem("keyperuuid/" + uuid, key)
}

function getColorForIdentity(key) {
Markin Igor's avatar
Markin Igor committed
  var storedColor = localStorage.getItem("colors/" + key);
Markin Igor's avatar
Markin Igor committed
  if(storedColor == null || storedColor === "") {
Markin Igor's avatar
Markin Igor committed
    storedColor = getNextColor();
    localStorage.setItem("colors/" + key, storedColor)
  }

  return storedColor
}

function setIdentityInLocalStorage(identityToStore, extendKey = true) {
  var pinCode = identityToStore.pinCode;
  const serializedIdentity = JSON.stringify(identityToStore);
  const key = identityToStore.authentication.publicKey;

Markin Igor's avatar
Markin Igor committed
  if(pinCode == null || pinCode === "") {
    pinCode = getPincode(key)
  }

Markin Igor's avatar
Markin Igor committed
  if(pinCode == null || pinCode === "") {
    return null;
  }

  return encryptMessage(serializedIdentity, pinCode, "identity").then((encryptedIdentity) => {
Markin Igor's avatar
Markin Igor committed
    var success = true;
    if(extendKey === true) {
      success = extendPinCodeTtl(key, pinCode)
    }
Markin Igor's avatar
Markin Igor committed
    if (success === true) {
      localStorage.setItem(key, encryptedIdentity);
      let serializedIdentitiesList = localStorage.getItem("identities");
      let identities = JSON.parse(serializedIdentitiesList);
      identities[key] = true;

      localStorage.setItem("identities", JSON.stringify(identities))
    } else {
Markin Igor's avatar
Markin Igor committed
      console.log("Can not extend pincode ttl");
    }
  });
}

function getProfileData(identity) {
  return new Penpal.Promise(executeResultUpper => {
    executeRestfulFunction("private", viamApi,
      viamApi.identityGetIdentityProfileData, null).then(executeResult => {
Markin Igor's avatar
Markin Igor committed
      if(executeResult.code === "200") {
        var listItem = {};

Markin Igor's avatar
Markin Igor committed
        listItem.identityColor = getColorForIdentity(identity.authentication.publicKey);
        listItem.initials = executeResult.data.initials;

        if(listItem.initials === null || listItem.initials === "") {
          listItem.initials = "JD";
        }
Markin Igor's avatar
Markin Igor committed
        localStorage.setItem("profiles/" + identity.authentication.publicKey, JSON.stringify(listItem));
        executeResultUpper(listItem)
      } else {
        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) {
  if(pinCode == null || pinCode === "") {
    var now = new Date();
    var nowMillis = now.getTime();
    var ttl = window.sessionStorage.getItem("pincodettls/" + key);
    if (ttl == null || ttl === "" || nowMillis >= parseInt(ttl)) {
Markin Igor's avatar
Markin Igor committed
      clearPinCodeTtl(key);
      var ttl = now.getTime() + 4 * 60 * 60 * 1000;
      window.sessionStorage.setItem("pincodettls/" + key, ttl);
    }
  } else {
    var now = new Date();
    var 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);
  window.sessionStorage.removeItem("pincodes/" + key)
}

function getPincode(key) {
  var now = new Date();
  var nowMillis = now.getTime();
  var ttl = window.sessionStorage.getItem("pincodettls/" + key);
Markin Igor's avatar
Markin Igor committed
  if (ttl == null || ttl === "") {
    return null
  } else {
    if(nowMillis >= parseInt(ttl)) {
Markin Igor's avatar
Markin Igor committed
      clearPinCodeTtl(key);
      return null
    } else {
      return window.sessionStorage.getItem("pincodes/" + key);
    }
  }
}

function createEvent(actionId, type, payloads) {
  return {
    "actionID": actionId,
    "type": type,
    "stamp": new Date().getTime(),
    "payloads" : payloads
  }
}

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) {
  const { currentlyAuthenticatedIdentity, viamApi, currentlyLoadedIdentity } = window;
  const response = await fn.apply(that, [config, ...args]);
  const identity = currentlyAuthenticatedIdentity || currentlyLoadedIdentity;
  const { code, status } = response.data;
  const deviceRevoked = type === "private" && code === "401" && status === STATUS_DEVICE_REVOKED;
  if (deviceRevoked) {
    destroyIdentity();
    const event = createEvent("", "DeviceRevoked");
    iframeParent.onEvent(event);
  const badSession = type === "private" && identity && code === "400" && status === "Bad session";
  if (!badSession) return response.data;
Igor Markin's avatar
Igor Markin committed
  const loginResponse = await viamApi.identityLogin(null, "previousaddeddevice");
  if (loginResponse.data.code !== "200") return loginResponse.data;

  const uuid = loginResponse.data.data["Uuid"];
  const token = loginResponse.data.data["Session"];
  handleIdentityLogin(identity, uuid, token);
  const { data } = await fn.apply(that, [config, ...args]);
}

window.executeRestfulFunction = executeRestfulFunction;

function loadIdentityInternal(identityKey, pinCode) {
  return new Penpal.Promise(result => {
    getIdentityFromLocalStorage(identityKey, pinCode).then(async (loadedIdentity) => {
      if (loadedIdentity == null) {
        result({
          "data": "",
          "code": "400",
Olgun Cengiz's avatar
Olgun Cengiz committed
          "status": "Please restore or authorize your account via another device."
Olgun Cengiz's avatar
Olgun Cengiz committed
      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);
Markin Igor's avatar
Markin Igor committed
        window.viamApi.setIdentity(identityKey);
        window.viamApi.setDeviceHash(deviceHash);
        window.viamApi.setSessionData(uuid, token);
      window.viamAnonymousApi.setIdentity(window.currentlyLoadedIdentity.authentication.publicKey);
      const { publicKey, x509Certificate } = loadedIdentity.authentication;
        "data": {
          authentication: {
            publicKey,
            x509Certificate
          }
        },
        "code": "200",
        "status": "Identity loaded"
    }).catch((e) => {
      result({
        "data": "",
        "code": "400",
Olgun Cengiz's avatar
Olgun Cengiz committed
        "status": "" + e
  });
}

function changeIdentityPinCodeInternal(key, oldPinCode, newPinCode) {

  return new Penpal.Promise(result => {
    getIdentityFromLocalStorage(key, oldPinCode, false).then((identity) => {

      identity.pinCode = newPinCode;

      setIdentityInLocalStorage(identity).then(() => {
        result({
          "data": "",
          "code": "200",
          "status": "Successfully changed pincode"
        });
      }).catch((e) => {
        result({
          "data": "",
          "code": "400",
          "status": "Cannot store identity " + e
        });
      });
    }).catch((e) => {
      result({
        "data": "",
        "code": "400",
        "status": "Cannot get identity " + e
      });
    });
  });
}

function getCertificateForPassport(passportUUID, internal) {

  return new Penpal.Promise(certificateResult => {
    if (window.currentlyAuthenticatedIdentity === null) {
      return {"data" : "",
        "code" : "400",
        "status" : "Identity not authenticated"
      }
    }

    const passportIdentity = window.currentlyAuthenticatedIdentity;
Markin Igor's avatar
Markin Igor committed
    var passport = passportIdentity.getPassport(passportUUID);
    if(passport === undefined || passport === null) {
      createPassportCertificate(passportUUID).then(function(keys){
Markin Igor's avatar
Markin Igor committed
        var cryptoData = new CryptoData();
        cryptoData.setPublicKey(keys["publicKeyPEM"]);
        cryptoData.setPrivateKey(keys["privateKeyPEM"]);
        var certificate = keys["certificatePEM"];
        //download("passportCertificateBeforeSigning.crt", "text/plain", certificate)
        //cryptoData.setx509Certificate(keys["certificate"])
        executeRestfulFunction("private", viamApi, viamApi.signSignCertificate, null, btoa(certificate), passportUUID).then(executeResult => {
Markin Igor's avatar
Markin Igor committed
          if(executeResult.code === "200") {
Markin Igor's avatar
Markin Igor committed
            var signedCertificate = atob(executeResult.data["SignedCertificate"]);
            //download("passportCertificateAfterSigning.crt", "text/plain", signedCertificate)
Markin Igor's avatar
Markin Igor committed
            var keyUUID = executeResult.data["CertificateUUID"];
            var encodedChain = executeResult.data["Chain"];
            //download("rootCertificate.crt", "text/plain", atob(encodedChain[0]))

Markin Igor's avatar
Markin Igor committed
            var chain = [];

            for(var i = 0; i < encodedChain.length; i++) {
              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 => {
              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
                });
              });
            });
          } else {
            certificateResult(executeResult);
Markin Igor's avatar
Markin Igor committed
      var copyOfCryptoData = JSON.parse(JSON.stringify(passport));

      if(internal === false) {
        copyOfCryptoData["privateKey"] = ""
      }

      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;
        console.warn(`Collabora host URL not specified. Fall back to ${collaboraUrl}`); // eslint-disable-line no-console
      }

      window.API_HOST = apiUrl.charAt(apiUrl.length - 1) === "/" ? apiUrl : apiUrl + "/";
      window.WOPI_URL = wopiUrl.charAt(wopiUrl.length - 1) === "/" ? wopiUrl : wopiUrl + "/";
      window.COLLABORA_URL = collaboraUrl.charAt(collaboraUrl.length - 1) === "/" ? collaboraUrl : collaboraUrl + "/";
    createIdentity(pinCode) {
      return new Penpal.Promise(result => {
        createPassportCertificate(makeid()).then(function(keys){
Markin Igor's avatar
Markin Igor committed
          var newIdentity = new Identity();
          var cryptoData = new CryptoData();
          cryptoData.setPublicKey(keys["publicKeyPEM"]);
          cryptoData.setPrivateKey(keys["privateKeyPEM"]);
          cryptoData.setx509Certificate(keys["certificatePEM"]);
          newIdentity.setAuthentication(cryptoData);
          newIdentity.setPinCode(pinCode);
Loading
Loading full blame...