import "../lib/textencoder.polyfill"; import { parseSMIME, prepareVCardParts } from "../utilities/emailUtilities"; import { stringToUtf8ByteArray, utf8ByteArrayToString, stringToUtf8Base64, utf8Base64ToString, base64ToByteArray, byteArrayToBase64 } from "../utilities/stringUtilities"; import { extractMessageID } from "../helpers/mailparser"; 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 { CertificateData, ImageData, createOneTimePassportCertificate, createPassportCertificate, decryptMessage, encryptMessage, parseCertificate, signEmail, verifySMIME } from "../utilities/signingUtilities"; import { signPdf } from "../utilities/pdfUtilities"; import CryptoData from "../CryptoData"; import Identity from "../Identity"; import { STATUS_DEVICE_REVOKED, STATUS_USER_NOT_ACTIVATED, STATUS_USER_BLOCKED } from "../constants/statuses"; import generateQrCode from "../utilities/generateQrCode"; const penpalMethods = require("../../temp/penpal-methods").default; const WopiAPI = require("./wopiapi-iframe"); const CollaboraAPI = require("./collaboraapi-iframe"); const ViamAPI = require("../../temp/viamapi"); const identityColors = ["#994392", "#cb0767", "#e51d31", "#ec671b", "#fab610"]; function getNextColor() { let colorIndex = localStorage.getItem("colorIndex"); if (colorIndex == null || colorIndex === "") { colorIndex = 0; } const color = identityColors[colorIndex]; colorIndex++; colorIndex = colorIndex % identityColors.length; localStorage.setItem("colorIndex", colorIndex); return color; } function setKeyForUUID(uuid, key) { const storedIdentityForUuid = localStorage.getItem("keyperuuid/" + uuid); if ( storedIdentityForUuid !== key && storedIdentityForUuid != null && storedIdentityForUuid !== "" ) { destroyIdentityFromLocalStorage(storedIdentityForUuid); } localStorage.setItem("keyperuuid/" + uuid, key); } function getColorForIdentity(key) { let storedColor = localStorage.getItem("colors/" + key); if (storedColor == null || storedColor === "") { storedColor = getNextColor(); localStorage.setItem("colors/" + key, storedColor); } return storedColor; } function setIdentityInLocalStorage(identityToStore, extendKey = true) { let pinCode = identityToStore.pinCode; const serializedIdentity = JSON.stringify(identityToStore); const key = identityToStore.authentication.publicKey; if (pinCode == null || pinCode === "") { pinCode = getPincode(key); } if (pinCode == null || pinCode === "") { return null; } return encryptMessage(serializedIdentity, pinCode, "identity").then( encryptedIdentity => { let success = true; if (extendKey === true) { success = extendPinCodeTtl(key, pinCode); } if (success === true) { localStorage.setItem(key, encryptedIdentity); const serializedIdentitiesList = localStorage.getItem("identities"); const identities = JSON.parse(serializedIdentitiesList); identities[key] = true; localStorage.setItem("identities", JSON.stringify(identities)); } else { console.log("Can not extend pincode ttl"); } } ); } function getProfileData(identity) { return new Penpal.Promise(executeResultUpper => { executeRestfulFunction( "private", viamApi, viamApi.identityGetIdentityProfileData, null ).then(executeResult => { if (executeResult.code === "200") { const listItem = {}; listItem.identityColor = getColorForIdentity( identity.authentication.publicKey ); listItem.initials = executeResult.data.initials; if (listItem.initials === null || listItem.initials === "") { listItem.initials = "JD"; } 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); if (!encryptedIdentity) { console.log("No such identity for public key"); return null; } 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; } } return identity; } function extendPinCodeTtl(key, pinCode) { if (pinCode == null || pinCode === "") { const now = new Date(); const nowMillis = now.getTime(); const ttl = window.sessionStorage.getItem("pincodettls/" + key); if (ttl == null || ttl === "" || nowMillis >= parseInt(ttl)) { clearPinCodeTtl(key); return false; } else { const ttl = now.getTime() + 4 * 60 * 60 * 1000; window.sessionStorage.setItem("pincodettls/" + key, ttl); } } else { 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) { window.sessionStorage.removeItem("pincodettls/" + key); window.sessionStorage.removeItem("pincodes/" + key); } function getPincode(key) { const now = new Date(); const nowMillis = now.getTime(); const ttl = window.sessionStorage.getItem("pincodettls/" + key); if (ttl == null || ttl === "") { return null; } else { if (nowMillis >= parseInt(ttl)) { clearPinCodeTtl(key); return null; } else { return window.sessionStorage.getItem("pincodes/" + key); } } } function createEvent(actionId, type, payloads) { return { actionID: actionId, type, stamp: new Date().getTime(), 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); } }; window.loadedIdentities = {}; window.wopiAPI = new WopiAPI(); window.collaboraApi = new CollaboraAPI(); window.viamApi = new ViamAPI(); window.viamAnonymousApi = new ViamAPI(); window.currentlyAuthenticatedIdentity = null; window.currentlyLoadedIdentity = null; window.lastTimeGetProfile = 0; let iframeParent = null; 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; 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 = { data: "", code: "999", status: error.message }; return data; } } const identity = currentlyAuthenticatedIdentity || currentlyLoadedIdentity; const { code, status } = response.data; console.log({ response }); const deviceRevoked = type === "private" && code === "401" && status === STATUS_DEVICE_REVOKED; if (deviceRevoked) { destroyIdentity(); const event = createEvent("", "DeviceRevoked"); iframeParent.onEvent(event); return response.data; } const userNotActivated = type === "private" && code === "400" && (status === STATUS_USER_NOT_ACTIVATED || status === STATUS_USER_BLOCKED); if (userNotActivated) { destroyIdentity(); const event = createEvent("", "UserBlocked"); iframeParent.onEvent(event); return response.data; } const badSession = type === "private" && identity && code === "400" && status === "Bad session"; if (!badSession) { return response.data; } 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); 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 => { 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); } window.viamAnonymousApi.setIdentity( window.currentlyLoadedIdentity.authentication.publicKey ); const { publicKey, x509Certificate } = loadedIdentity.authentication; 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) { return { data: "", code: "400", status: "Identity not authenticated" }; } const passportIdentity = window.currentlyAuthenticatedIdentity; const passport = passportIdentity.getPassport(passportUUID); if (passport === undefined || passport === null) { createPassportCertificate(passportUUID).then(function(keys) { const cryptoData = new CryptoData(); cryptoData.setPublicKey(keys["publicKeyPEM"]); cryptoData.setPrivateKey(keys["privateKeyPEM"]); const certificate = keys["certificatePEM"]; //download("passportCertificateBeforeSigning.crt", "text/plain", certificate) //cryptoData.setx509Certificate(keys["certificate"]) executeRestfulFunction( "private", viamApi, viamApi.signSignCertificate, null, btoa(certificate), passportUUID ).then(executeResult => { if (executeResult.code === "200") { const signedCertificate = atob( executeResult.data["SignedCertificate"] ); //download("passportCertificateAfterSigning.crt", "text/plain", signedCertificate) const keyUUID = executeResult.data["CertificateUUID"]; const encodedChain = executeResult.data["Chain"]; //download("rootCertificate.crt", "text/plain", atob(encodedChain[0])) const chain = []; for (let i = 0; i < encodedChain.length; i++) { chain.push(atob(encodedChain[i])); } cryptoData.setx509Certificate(signedCertificate); cryptoData.setKeyUUID(keyUUID); cryptoData.setChain(chain); 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); } }); }); } else { const 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 + "/"; }, ...penpalMethods, createIdentity(pinCode) { return new Penpal.Promise(result => { createPassportCertificate(makeid()).then(function(keys) { const newIdentity = new Identity(); const cryptoData = new CryptoData(); 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; extendPinCodeTtl(newIdentity.authentication.publicKey, pinCode); window.viamAnonymousApi.setIdentity( newIdentity.authentication.publicKey ); result({ data: { authentication: { publicKey, x509Certificate } }, code: "200", status: "Identity created" }); }); }); }, listIdentities() { return new Penpal.Promise(result => { const identities = listIdentitiesFromLocalStorage(); result({ data: identities, code: "200", status: "Identities listed" }); }); }, loadIdentity(identityKey, pinCode) { 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 { const identity = await getIdentityFromLocalStorage( key, oldPinCode, false ); if (identity) { identity.pinCode = newPinCode; await setIdentityInLocalStorage(identity); window.currentlyAuthenticatedIdentity = identity; window.currentlyLoadedIdentity = identity; return encodeResponse("200", null, "Successfully changed pincode"); } else { return encodeResponse("400", null, "Identity not found"); } } catch (e) { return encodeResponse("400", e.message, "Change pincode error"); } }, getIdentityProfile(identityKey) { return new Penpal.Promise(result => { const serializedProfile = localStorage.getItem( "profiles/" + identityKey ); if (serializedProfile === null || serializedProfile === "") { result({ data: "", code: "400", status: "Profile is empty" }); } else { 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 => { viamApi.setIdentity(identity.authentication.publicKey); executeRestfulFunction( "public", viamApi, viamApi.identityConfirmIdentificator, null, confirmationCodeArg ).then(executeResult => { result(executeResult); }); }); }, identityGetIdentificatorByRegisterToken(identity, tokenArg) { return new Penpal.Promise(result => { viamApi.setIdentity(identity.authentication.publicKey); executeRestfulFunction( "public", viamApi, viamApi.identityGetIdentificatorByRegisterToken, null, tokenArg ).then(executeResult => { result(executeResult); }); }); }, submitIdentificator(identity, identificatorArg, registerToken) { return new Penpal.Promise(result => { viamApi.setIdentity(identity.authentication.publicKey); executeRestfulFunction( "public", viamApi, viamApi.identitySubmitIdentificator, null, identificatorArg, registerToken ).then(executeResult => { result(executeResult); }); }); }, submitRegisterClaims( identity, givennameArg, familynameArg, emailArg, phonenumberArg ) { return new Penpal.Promise(result => { viamApi.setIdentity(identity.authentication.publicKey); executeRestfulFunction( "public", viamApi, viamApi.identitySubmitRegisterClaims, null, givennameArg, familynameArg, emailArg, phonenumberArg ).then(executeResult => { result(executeResult); }); }); }, agreeOnRegistration(registerIdentity) { return new Penpal.Promise(result => { viamApi.setIdentity(registerIdentity.authentication.publicKey); executeRestfulFunction( "public", viamApi, viamApi.identityAgreeOnRegistration, null ).then(executeResult => { let sequence = Promise.resolve(); if (executeResult.code === "200") { sequence = sequence.then(() => { setIdentityInLocalStorage(registerIdentity); }); } sequence .then(() => { result(executeResult); }) .catch(e => { result({ data: "", code: "400", status: "Can not store identity: " + e }); }); }); }); }, resendConfirmationCode(identity, identificatorArg) { return new Penpal.Promise(result => { viamApi.setIdentity(identity.authentication.publicKey); executeRestfulFunction( "public", viamApi, viamApi.identityResendConfirmationCode, null, identificatorArg ).then(executeResult => { result(executeResult); }); }); }, login: async (loginIdentity, mode, requestCode, requestActionID) => { if (!window.loadedIdentities[loginIdentity.authentication.publicKey]) { return { data: "", code: "400", status: "Identity not loaded" }; } const deviceHash = await createDeviceHash( loginIdentity.authentication.publicKey ); window.viamApi.setSessionData("", ""); window.viamApi.setDeviceHash(deviceHash); window.viamApi.setIdentity(loginIdentity.authentication.publicKey); const identityLoginResponse = await executeRestfulFunction( "public", window.viamApi, window.viamApi.identityLogin, null, mode, requestCode, requestActionID ); const { code, data } = identityLoginResponse; const responseToClient = Object.assign({}, identityLoginResponse); if (code === "200") { if ( mode === LOGIN_MODES.SMS || mode === LOGIN_MODES.PREVIOUSLY_ADDED_DEVICE ) { handleIdentityLogin(loginIdentity, data.Uuid, data.Session); await getProfileData(loginIdentity); if (mode === LOGIN_MODES.SMS) { await setIdentityInLocalStorage(loginIdentity); } } else if (mode === LOGIN_MODES.NEW_DEVICE) { const dataUrl = await QRCode.toDataURL( `${data.ActionID},${data.QrCode}` ); Object.assign(responseToClient.data, { image: dataUrl }); } } return responseToClient; }, identityAddNewDevice() { return new Penpal.Promise(result => { const authenticationPublicKey = localStorage.getItem( "authenticatedIdentity" ); if (authenticationPublicKey === null) { result({ data: "", code: "400", status: "Identity not authenticated" }); } if (window.loadedIdentities[authenticationPublicKey] === null) { result({ data: "", code: "400", status: "Identity not authenticated" }); } const success = extendPinCodeTtl(authenticationPublicKey); if (success === false) { result({ data: "", code: "400", status: "Identity not authenticated" }); } executeRestfulFunction( "private", viamApi, viamApi.identityAddNewDevice, null ).then(executeResult => { if (executeResult.code === "200") { const actionID = executeResult.data["ActionID"]; const QrCode = executeResult.data["QrCode"]; QRCode.toDataURL(actionID + "," + QrCode, function(err, url) { executeResult.data["image"] = url; result(executeResult); }); } else { result(executeResult); } }); }); }, identityDestroyKeysForDevice(authenticationPublicKeyArg) { return new Penpal.Promise(result => { const authenticationPublicKey = localStorage.getItem( "authenticatedIdentity" ); if (authenticationPublicKey === null) { result({ data: "", code: "400", status: "Identity not authenticated" }); } if (window.loadedIdentities[authenticationPublicKey] === null) { result({ data: "", code: "400", status: "Identity not authenticated" }); } const success = extendPinCodeTtl(authenticationPublicKey); if (success === false) { result({ data: "", code: "400", status: "Identity not authenticated" }); } executeRestfulFunction( "private", viamApi, viamApi.identityDestroyKeysForDevice, null, btoa(authenticationPublicKeyArg) ).then(executeResult => { result(executeResult); }); }); }, logout: async () => { try { const authenticationPublicKey = localStorage.getItem( "authenticatedIdentity" ); if ( !authenticationPublicKey || !window.loadedIdentities[authenticationPublicKey] ) { return { data: "", code: "400", status: "Identity not loaded" }; } // 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 const headers = { ...window.viamApi.getConfig().headers }; destroyAuthentication(); return executeRestfulFunction( "private", window.viamApi, window.viamApi.identityLogout, { headers } ); } catch (e) { return { data: "", code: "400", status: e.message }; } }, identityRestoreAccess(restoreAccessIdentity, identificator) { return new Penpal.Promise(result => { viamApi.setSessionData("", ""); viamApi.setIdentity(restoreAccessIdentity.authentication.publicKey); executeRestfulFunction( "public", viamApi, viamApi.identityRestoreAccess, null, identificator ).then(executeResult => { result(executeResult); }); }); }, parseSMIME, getCurrentlyLoggedInUUID() { return new Penpal.Promise(result => { const authenticationPublicKey = localStorage.getItem( "authenticatedIdentity" ); if (authenticationPublicKey === null) { return { data: "", code: "400", status: "Identity not loaded" }; } if (window.loadedIdentities[authenticationPublicKey] === null) { return { data: "", code: "400", status: "Identity not loaded" }; } const success = extendPinCodeTtl(authenticationPublicKey); if (success === false) { result({ data: "", code: "400", status: "Identity not authenticated" }); } if (localStorage.getItem("uuid") === null) { result({ data: "", code: "400", status: "Not logged in UUID" }); } result({ data: localStorage.getItem("uuid"), code: "200", status: "UUID loaded" }); }); }, getCertificateByPassport(passportUUID) { return new Penpal.Promise(result => { const authenticationPublicKey = localStorage.getItem( "authenticatedIdentity" ); if (authenticationPublicKey === null) { return { data: "", code: "400", status: "Identity not loaded" }; } if (window.loadedIdentities[authenticationPublicKey] === null) { return { data: "", code: "400", status: "Identity not loaded" }; } const success = extendPinCodeTtl(authenticationPublicKey); if (success === false) { result({ data: "", code: "400", status: "Identity not authenticated" }); } getCertificateForPassport(passportUUID, false).then( certificateResult => { result(certificateResult); } ); }); }, getOneTimeCertificateByPassport(passportUUID, emailArg) { return new Penpal.Promise(result => { const authenticationPublicKey = localStorage.getItem( "authenticatedIdentity" ); if (authenticationPublicKey === null) { return { data: "", code: "400", status: "Identity not loaded" }; } if (window.loadedIdentities[authenticationPublicKey] === null) { return { data: "", code: "400", status: "Identity not loaded" }; } const success = extendPinCodeTtl(authenticationPublicKey); if (success === false) { result({ data: "", code: "400", status: "Identity not authenticated" }); } getCertificateForPassport(passportUUID, true).then( certificateResult => { if (certificateResult.code === "200") { const passportCertificate = certificateResult.data["x509Certificate"]; const passportPrivateKey = certificateResult.data["privateKey"]; const passportChain = certificateResult.data["chain"]; createOneTimePassportCertificate( makeid() + "-" + passportUUID, emailArg, passportPrivateKey, passportCertificate ).then(function(keys) { const publicKeyOneTime = keys["publicKeyPEM"]; const privateKeyOneTime = keys["privateKeyPEM"]; const certificateOneTime = keys["certificatePEM"]; passportChain.push(passportCertificate); const oneTimeCryptoData = new CryptoData(); oneTimeCryptoData.setx509Certificate(certificateOneTime); oneTimeCryptoData.setPrivateKey(privateKeyOneTime); oneTimeCryptoData.setPublicKey(publicKeyOneTime); oneTimeCryptoData.setChain(passportChain); result({ data: oneTimeCryptoData, code: "200", status: "One time certificate generated" }); // Prints PEM formatted signed certificate // -----BEGIN CERTIFICATE-----MIID....7Hyg==-----END CERTIFICATE----- }); } else { result({ data: "", code: "400", status: "Can not generate one time certificate" }); } } ); }); }, verifySMIME: async smimeString => { const authenticationPublicKey = localStorage.getItem( "authenticatedIdentity" ); if ( !authenticationPublicKey || !window.loadedIdentities[authenticationPublicKey] || !extendPinCodeTtl(authenticationPublicKey) ) { return encodeResponse("400", "", "Identity not authenticated"); } //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; 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, contentType ); 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( certificatePEM => { const certificate = parseCertificate(certificatePEM); const certificateData = new CertificateData(certificate); return certificateData; } ); signature.certificateChain = certificateChain; } } return validateDocumentResponse; }, signEmail: async (passportUUID, emailArg, emailMessage) => { 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, chain: passportChain } = response.data; const keys = await createOneTimePassportCertificate( makeid() + "-" + passportUUID, emailArg, passportPrivateKey, passportCertificate ); const { privateKeyPEM: privateKeyOneTime, certificatePEM: certificateOneTime } = keys; passportChain.push(passportCertificate); response = await executeRestfulFunction( "private", window.viamApi, window.viamApi.passportGetEmailWithHeaderByPassport, null, passportUUID, emailMessage ); if (response.code !== "200") { return encodeResponse("400", "", response.status); } const signedEmail = await signEmail( response.data, certificateOneTime, passportChain, privateKeyOneTime ); response = await executeRestfulFunction( "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"); }, signDocument: async (passportUUID, documentUUID, documentContentType) => { const authenticationPublicKey = localStorage.getItem( "authenticatedIdentity" ); if ( !authenticationPublicKey || !window.loadedIdentities[authenticationPublicKey] || !extendPinCodeTtl(authenticationPublicKey) ) { return encodeResponse("400", "", "Identity not authenticated"); } const certResponse = await getCertificateForPassport(passportUUID, true); if (certResponse.code !== "200") { return encodeResponse("400", "", certResponse.status); } const { x509Certificate: passportCertificate, privateKey: passportPrivateKey, chain: passportChain } = certResponse.data; const keys = await createOneTimePassportCertificate( makeid() + "-" + passportUUID, null, passportPrivateKey, passportCertificate ); const { privateKeyPEM: privateKeyOneTime, certificatePEM: certificateOneTime } = keys; passportChain.reverse(); passportChain.push(passportCertificate); 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 downloadResponse = await executeRestfulFunction( "private", window.viamApi, window.viamApi.documentGetDocumentByUUID, null, documentUUID, pdfContentType ); if (downloadResponse.code !== "200") { return encodeResponse("400", "", downloadResponse.status); } const pdfRaw = base64ToByteArray(downloadResponse.data); let signedPdf; try { signedPdf = await signPdf( pdfRaw, certificateOneTime, passportChain, privateKeyOneTime ); } catch (err) { console.error(err); return encodeResponse("500", "", err.message); } const signedPdfB64 = byteArrayToBase64(signedPdf); const uploadResponse = await executeRestfulFunction( "private", window.viamApi, window.viamApi.documentPutDocumentByUUID, null, documentUUID, pdfContentType, signedPdfB64 ); if (uploadResponse.code !== "200") { return encodeResponse("400", "", uploadResponse.status); } const signResponse = await executeRestfulFunction( "private", window.viamApi, window.viamApi.documentSignDocumentByUUID, null, passportUUID, documentUUID, pdfContentType ); if (signResponse.code !== "200") { return encodeResponse("400", "", signResponse.status); } return encodeResponse("200", "", "Document signed"); }, signDocumentJava: async ( passportUUID, documentUUID, documentContentType ) => { const authenticationPublicKey = localStorage.getItem( "authenticatedIdentity" ); if ( !authenticationPublicKey || !window.loadedIdentities[authenticationPublicKey] || !extendPinCodeTtl(authenticationPublicKey) ) { return encodeResponse("400", "", "Identity not authenticated"); } const certResponse = await getCertificateForPassport(passportUUID, true); if (certResponse.code !== "200") { return encodeResponse("400", "", certResponse.status); } const { x509Certificate: passportCertificate, privateKey: passportPrivateKey, chain: passportChain } = certResponse.data; const keys = await createOneTimePassportCertificate( makeid() + "-" + passportUUID, null, passportPrivateKey, passportCertificate ); const { privateKeyPEM: privateKeyOneTime, certificatePEM: certificateOneTime } = keys; passportChain.reverse(); passportChain.push(passportCertificate); passportChain.push(certificateOneTime); passportChain.reverse(); const pdfContentType = "application/pdf"; if (documentContentType !== pdfContentType) { const convResponse = await executeRestfulFunction( "private", window.viamApi, window.viamApi.documentConvertDocumentByUUID, null, documentUUID, documentContentType, pdfContentType ); if (convResponse.code !== "200") { return encodeResponse("400", "", convResponse.status); } } const signResponse = await executeRestfulFunction( "private", window.viamApi, window.viamApi.documentSignDocumentJavaService, null, privateKeyOneTime, passportChain, passportUUID, documentUUID, pdfContentType ); if (signResponse.code !== "200") { return encodeResponse("400", "", signResponse.status); } return encodeResponse("200", "", "Document signed"); }, // passportUUID - String - passport to sign the vCard // senderEmail - the email address of the sender // attribs - additional attributes, to be added to the vCard. Recognized attribs are: // - emailService: "GMail", "Outlook 365", ... // text, html - String - the text and html part of the email, both optional // parts - array of objects, representing the MIME structure in format: // { // headers: { // "Content-Type": "image/jpeg", // "Content-Disposition": "inline" or "attachment" with additional attributes, // ... //other headers from MIME // }, // body: String if it is a text part (Content-Type = "text/...") or Uint8Array otherwise; filled for leaf MIME nodes // parts: array of instances of the same object; filled for container MIME nodes (Content-Type = "multipart/...") // } signVCard: async ( passportUUID, senderEmail, attribs, textBody, htmlBody, parts ) => { 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, messageUUID }; let vCardImageData; let vCardImageClaimValue; 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; } let qrCodeImageData; let qrCodeCoordinates = { fromL: -1, fromR: -1, toL: -1, toR: -1 }; if ( vCardImageClaimValue && "state" in vCardImageClaimValue && vCardImageClaimValue.state === "disabled" ) { vCardImageData = new ImageData({ contentType: "image/png", contentBase64: "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=" //1x1px transparent pixel }); } else { const vCardImageResponse = await executeRestfulFunction( "private", window.viamApi, window.viamApi.passportGetVCardImage, null, passportUUID ); console.log(vCardImageResponse); if (vCardImageResponse.code !== "200") { return encodeResponse("400", "", vCardImageResponse.status); } vCardImageData = new ImageData(vCardImageResponse.data.Image); if (vCardImageData.contentType !== "image/png") { return encodeResponse( "400", "", "Content type of vCard mmust be 'image/png'" ); } qrCodeCoordinates = vCardImageResponse.data.QRCodeCoordinates; const qrCodeBase64Content = await generateQrCode( "https://" + location.host + "/check/" + messageUUID ); qrCodeImageData = new ImageData({ contentType: "image/png", content: qrCodeBase64Content }); } if (typeof parts === "undefined" || parts === null) { parts = []; } if (htmlBody) { if (typeof htmlBody !== "string") { throw new Error("htmlBody is not string"); // should not happen } const htmlPart = { headers: { "Content-Type": "text/html" }, body: htmlBody }; parts.unshift(htmlPart); } else { console.log("Html body is not passed to signVCard, its value is ", { html: htmlBody }); } if (textBody) { if (typeof textBody !== "string") { throw new Error("textBody is not string"); // should not happen } const textPart = { headers: { "Content-Type": "text/plain" }, body: textBody }; parts.unshift(textPart); } else { console.log("Text body is not passed to signVCard, its value is ", { text: textBody }); } 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"); } const certResponse = await getCertificateForPassport(passportUUID, true); if (certResponse.code !== "200") { return encodeResponse("400", "", certResponse.status); } const { x509Certificate: passportCertificate, privateKey: passportPrivateKey, chain: passportChain } = certResponse.data; const keys = await createOneTimePassportCertificate( makeid() + "-" + passportUUID, senderEmail, passportPrivateKey, passportCertificate ); const { privateKeyPEM: privateKeyOneTime, certificatePEM: certificateOneTime } = keys; passportChain.reverse(); passportChain.push(passportCertificate); passportChain.push(certificateOneTime); passportChain.reverse(); console.log(qrCodeImageData); console.log(qrCodeCoordinates); const signVCardResponse = await executeRestfulFunction( "private", window.viamApi, window.viamApi.signSignVCardForChain, null, vCardImageData, privateKeyOneTime, passportChain, parts, vCardAttribs, qrCodeImageData, qrCodeCoordinates ); if (signVCardResponse.code !== "200") { return encodeResponse("400", "", signVCardResponse.status); } const signedVCardImageData = new ImageData(signVCardResponse.data); return encodeResponse( "200", { image: signedVCardImageData, messageUUID: messageUUID }, "vCard signed" ); }, // mime - String - the MIME of the email message // vCardAttribs - optional attributes for the verification procedure in format // { // passportUUID: passportUUID, // messageUUID: messageUUID // }; validateVMime: async (vMime, vCardAttribs = null) => { const authenticationPublicKey = localStorage.getItem( "authenticatedIdentity" ); if ( !authenticationPublicKey || !window.loadedIdentities[authenticationPublicKey] || !extendPinCodeTtl(authenticationPublicKey) ) { return encodeResponse("400", "", "Identity not authenticated"); } const validateVMimeResponse = await executeRestfulFunction( "private", window.viamApi, window.viamApi.signValidateVMime, null, vMime, vCardAttribs ); if (validateVMimeResponse.code !== "200") { return encodeResponse("400", "", validateVMimeResponse.status); } const validationResult = validateVMimeResponse.data; const { signatures } = validationResult; if (signatures) { for (const signature of signatures) { const certificateChain = signature.certificateChainPEM.map( certificatePEM => { const certificate = parseCertificate(certificatePEM); const certificateData = new CertificateData(certificate); return certificateData; } ); signature.certificateChain = certificateChain; } } return encodeResponse( "200", validationResult, "Validation result retrieved" ); }, generateQrCode, documentCreateDocument: async (passportUUID, path, contentType, title) => { const authenticationPublicKey = localStorage.getItem( "authenticatedIdentity" ); if ( !authenticationPublicKey || !window.loadedIdentities[authenticationPublicKey] || !extendPinCodeTtl(authenticationPublicKey) ) { return encodeResponse("400", "", "Identity not authenticated"); } path = encodeURI(path); contentType = encodeURI(contentType); title = encodeURI(title); const config = { headers: { path, passportuuid: passportUUID, contentType, title } }; const response = await executeRestfulFunction( "private", window.viamApi, window.viamApi.documentCreateDocument, config ); if (response.code !== "200") { return encodeResponse("400", "", response.status); } return encodeResponse("200", response.data, "Document created"); }, documentPutDocument: async ( passportUUID, resourceid, contentType, file, upload ) => { const authenticationPublicKey = localStorage.getItem( "authenticatedIdentity" ); if ( !authenticationPublicKey || !window.loadedIdentities[authenticationPublicKey] || !extendPinCodeTtl(authenticationPublicKey) ) { return encodeResponse("400", "", "Identity not authenticated"); } resourceid = encodeURI(resourceid); contentType = encodeURI(contentType); const config = { headers: { "Content-Type": "multipart/form-data", passportuuid: passportUUID, resourceid, contentType, upload } }; const response = await executeRestfulFunction( "private", window.viamApi, window.viamApi.documentPutDocument, config, file ); if (response.code !== "200") { return encodeResponse("400", "", response.status); } return encodeResponse("200", response.data, "Document stored"); }, hasSession() { return new Penpal.Promise(result => { const authenticationPublicKey = localStorage.getItem( "authenticatedIdentity" ); if (authenticationPublicKey === null) { result({ data: "", code: "400", status: "Identity not authenticated" }); } if (window.loadedIdentities[authenticationPublicKey] === null) { result({ data: "", code: "400", status: "Identity not authenticated" }); } const success = extendPinCodeTtl(authenticationPublicKey); if (success === false) { result({ data: "", code: "400", status: "Identity not authenticated" }); } executeRestfulFunction( "private", viamApi, viamApi.identityHasSession, null ).then(executeResult => { result(executeResult); }); }); }, marketingSignUpIdentificator(identificator, reference) { return new Penpal.Promise(result => { viamApi.setIdentity("marketingapppublickey"); executeRestfulFunction( "public", viamApi, viamApi.marketingSignUpIdentificator, null, identificator, reference ).then(executeResult => { viamApi.setIdentity(""); viamApi.setSessionData("", ""); result(executeResult); }); }); }, marketingGetIdentificatorProfile(identificator, pincode) { return new Penpal.Promise(result => { viamApi.setIdentity("marketingapppublickey"); executeRestfulFunction( "public", viamApi, viamApi.marketingGetIdentificatorProfile, null, identificator, pincode ).then(executeResult => { viamApi.setIdentity(""); viamApi.setSessionData("", ""); result(executeResult); }); }); }, marketingExecuteEventForIdentificator(identificator, pincode, event) { return new Penpal.Promise(result => { viamApi.setIdentity("marketingapppublickey"); executeRestfulFunction( "public", viamApi, viamApi.marketingExecuteEventForIdentificator, null, identificator, pincode, event ).then(executeResult => { viamApi.setIdentity(""); viamApi.setSessionData("", ""); result(executeResult); }); }); }, getCurrentlyAuthenticatedIdentity() { const { publicKey, x509Certificate } = window.currentlyAuthenticatedIdentity.authentication; return encodeResponse( "200", { authentication: { publicKey, x509Certificate } }, "Currently authenticated identity" ); }, extractMessageID(mime) { return new Penpal.Promise(result => { result(extractMessageID(mime)); }); }, stringToUtf8ByteArray(str) { return new Penpal.Promise(result => { result(stringToUtf8ByteArray(str)); }); }, utf8ByteArrayToString(ba) { return new Penpal.Promise(result => { result(utf8ByteArrayToString(ba)); }); }, stringToUtf8Base64(str) { return new Penpal.Promise(result => { result(stringToUtf8Base64(str)); }); }, utf8Base64ToString(strBase64) { return new Penpal.Promise(result => { result(utf8Base64ToString(strBase64)); }); }, base64ToByteArray(strBase64) { return new Penpal.Promise(result => { result(base64ToByteArray(strBase64)); }); }, byteArrayToBase64(ba) { return new Penpal.Promise(result => { result(byteArrayToBase64(ba)); }); }, // Collabora APIs collaboraDiscovery() { return collaboraApi.discovery().then(apps => apps); }, // WOPI getPassportsNewProtocol: async (resourceID, contentType) => { const authenticationPublicKey = localStorage.getItem( "authenticatedIdentity" ); if ( !authenticationPublicKey || !window.loadedIdentities[authenticationPublicKey] || !extendPinCodeTtl(authenticationPublicKey) ) { return encodeResponse("400", "", "Identity not authenticated"); } const response = await wopiAPI.getPassportsNewProtocol( resourceID, contentType ); return response.data; }, getPassports: async fileId => { const authenticationPublicKey = localStorage.getItem( "authenticatedIdentity" ); if ( !authenticationPublicKey || !window.loadedIdentities[authenticationPublicKey] || !extendPinCodeTtl(authenticationPublicKey) ) { return encodeResponse("400", "", "Identity not authenticated"); } const response = await wopiAPI.getPassports(fileId); return response.data; }, wopiCreateDocument: async (passportUUID, path, title) => { const authenticationPublicKey = localStorage.getItem( "authenticatedIdentity" ); if ( !authenticationPublicKey || !window.loadedIdentities[authenticationPublicKey] || !extendPinCodeTtl(authenticationPublicKey) ) { return encodeResponse("400", "", "Identity not authenticated"); } const config = { headers: { path, passportuuid: passportUUID, title } }; const createDocumentResult = await executeRestfulFunction( "private", window.viamApi, window.viamApi.documentCreateDocument, config ); if (createDocumentResult.code !== "200") { return createDocumentResult; } const resourceID = createDocumentResult.data; const accessTokenResponse = await wopiAPI.getAccessToken( passportUUID, resourceID ); if (accessTokenResponse.data.code !== "200") { return accessTokenResponse.data; } const accessToken = accessTokenResponse.data.data; const result = { resourceID, accessToken }; return encodeResponse("200", result, "ok"); }, wopiGetAccessToken: async (passportUUID, resourceID, contentType) => { const authenticationPublicKey = localStorage.getItem( "authenticatedIdentity" ); if ( !authenticationPublicKey || !window.loadedIdentities[authenticationPublicKey] || !extendPinCodeTtl(authenticationPublicKey) ) { return encodeResponse("400", "", "Identity not authenticated"); } const response = await wopiAPI.getAccessToken( passportUUID, resourceID, contentType ); return response.data; }, wopiPutFile: async (resourceID, accessToken, file) => { const authenticationPublicKey = localStorage.getItem( "authenticatedIdentity" ); if ( !authenticationPublicKey || !window.loadedIdentities[authenticationPublicKey] || !extendPinCodeTtl(authenticationPublicKey) ) { return encodeResponse("400", "", "Identity not authenticated"); } const response = await wopiAPI.putDocument(resourceID, accessToken, file); return response.data; } } }); connection.promise.then(parent => { iframeParent = parent; if (!navigator.cookieEnabled) { console.warn("Cookie disabled. Can't start library."); return; } window.addEventListener("storage", event => { if (event.key === "authenticatedIdentity" && event.newValue === null) { const publicKey = window.currentlyAuthenticatedIdentity.authentication.publicKey; window.currentlyLoadedIdentity = null; window.currentlyAuthenticatedIdentity = null; const event = createEvent("LogoutFromAnotherTab", "Logout", [publicKey]); parent.onEvent(event); } }); const identities = localStorage.getItem("identities"); console.log("Library loaded at: " + new Date().toISOString()); if (identities === "" || identities === null) { localStorage.setItem("identities", JSON.stringify({})); } if ( localStorage.getItem("uuid") === null || localStorage.getItem("token") === null || localStorage.getItem("authenticatedIdentity") === null ) { const event = createEvent("", "NotAuthenticated"); parent.onEvent(event); localStorage.removeItem("uuid"); localStorage.removeItem("token"); localStorage.removeItem("authenticatedIdentity"); } else { const authenticationPublicKey = localStorage.getItem( "authenticatedIdentity" ); const pinCode = getPincode(authenticationPublicKey); if (pinCode === "" || pinCode === null) { loadIdentityInternal(authenticationPublicKey, "00000000").then(result => { if (result.code !== "200") { const event = createEvent( "CanNotGetPincodeForAuthenticatedIdentity", "IdentityNotLoaded", [authenticationPublicKey] ); parent.onEvent(event); } }); } else { loadIdentityInternal(authenticationPublicKey, pinCode).then(result => { if (result.code !== "200") { const event = createEvent( "CanNotLoadIdentity", "ErrorDuringLoadingIdentity", [authenticationPublicKey] ); parent.onEvent(event); } }); } } let anynomousDeviceKeyEventsProcessing = false; let maxDeviceKeyAnonymousEventTime = 0; let eventsDeviceEventsProcessing = false; let maxDeviceKeyEventTime = 0; let eventsEntityEventsProcessing = false; let maxEntityEventTime = 0; let identityLoadedEvent = false; let identityAuthenticatedEvent = false; let previousLocalStorageUUID; let previousLocalStorageToken; let previousLocalStorageIdentity; setInterval(async function() { if (window.currentlyAuthenticatedIdentity) { const { authentication } = window.currentlyAuthenticatedIdentity; const pinCode = getPincode(authentication.publicKey); if (pinCode) { const identity = await getIdentityFromLocalStorage( authentication.publicKey, pinCode, false ); window.currentlyLoadedIdentity = identity; if (!identityAuthenticatedEvent && identity) { const event = createEvent("IdentityAuthenticated", "Authenticated", [ identity.authentication.publicKey ]); parent.onEvent(event); identityAuthenticatedEvent = true; } } else { const authenticationPublicKey = localStorage.getItem( "authenticatedIdentity" ); if (authenticationPublicKey) { const result = await loadIdentityInternal( authenticationPublicKey, "00000000" ); if (result.code !== "200") { const event = createEvent( "CanNotGetPincodeForAuthenticatedIdentity", "IdentityNotLoaded", [authenticationPublicKey] ); parent.onEvent(event); clearPinCodeTtl(authenticationPublicKey); window.currentlyAuthenticatedIdentity = null; } } identityAuthenticatedEvent = false; window.currentlyLoadedIdentity = null; } } if (window.currentlyLoadedIdentity) { const pinCode = getPincode( window.currentlyLoadedIdentity.authentication.publicKey ); if (!pinCode) { if (!identityLoadedEvent) { const result = await loadIdentityInternal( window.currentlyLoadedIdentity.authentication.publicKey, "00000000" ); if (window.currentlyLoadedIdentity && result.code !== "200") { const event = createEvent( "CanNotLoadPincodeForLoadedIdentity", "IdentityNotLoaded", [window.currentlyLoadedIdentity.authentication.publicKey] ); parent.onEvent(event); identityLoadedEvent = true; } } } else { identityLoadedEvent = false; } } if (window.currentlyAuthenticatedIdentity) { const now = new Date().getTime(); if (now - window.lastTimeGetProfile > 30000) { getProfileData(window.currentlyAuthenticatedIdentity); window.lastTimeGetProfile = now; } } const currentLocalStorageUUID = localStorage.getItem("uuid"); const currentLocalStorageToken = localStorage.getItem("token"); const currentLocalStorageIdentity = localStorage.getItem( "authenticatedIdentity" ); if ( (!currentLocalStorageUUID && previousLocalStorageUUID) || (!currentLocalStorageToken && previousLocalStorageToken) || (!currentLocalStorageIdentity && previousLocalStorageIdentity) ) { previousLocalStorageUUID = null; previousLocalStorageToken = null; previousLocalStorageIdentity = null; destroyAuthentication(); const event = createEvent("", "LogoutExternal"); parent.onEvent(event); } else { previousLocalStorageUUID = currentLocalStorageUUID; previousLocalStorageToken = currentLocalStorageToken; previousLocalStorageIdentity = currentLocalStorageIdentity; } }, 50); const getNewEventsWithoutSession = async () => { anynomousDeviceKeyEventsProcessing = true; try { const executeResult = await executeRestfulFunction( "public", viamAnonymousApi, viamAnonymousApi.eventGetNewEventsWithoutSession, null, "devicekey" ); if (executeResult.code === "200") { const eventsLen = executeResult.data.length; let changedMaxDeviceKeyAnonymousEventTime = false; for (let i = 0; i < eventsLen; i++) { const event = executeResult.data[i]; switch (event.type) { case "DeviceConfirmed": { await setIdentityInLocalStorage(window.currentlyLoadedIdentity); parent.onEvent(event); break; } case "QRCodeUpdated": { const actionID = event["actionID"]; const QrCode = event["payloads"][1]; const eventCopy = JSON.parse(JSON.stringify(event)); QRCode.toDataURL(actionID + "," + QrCode, function(err, url) { eventCopy["payloads"].push(url); parent.onEvent(eventCopy); }); break; } case "KeyDeleted": { const authenticationPublicKey = localStorage.getItem( "authenticatedIdentity" ); clearPinCodeTtl(authenticationPublicKey); localStorage.removeItem("uuid"); localStorage.removeItem("token"); localStorage.removeItem("authenticatedIdentity"); delete window.loadedIdentities[authenticationPublicKey]; window.currentlyLoadedIdentity = null; window.currentlyAuthenticatedIdentity = null; window.lastTimeGetProfile = 0; destroyIdentityFromLocalStorage(authenticationPublicKey); break; } default: { parent.onEvent(event); } } changedMaxDeviceKeyAnonymousEventTime = true; maxDeviceKeyAnonymousEventTime = Math.max( maxDeviceKeyAnonymousEventTime, event.stamp ); } if (changedMaxDeviceKeyAnonymousEventTime) { await executeRestfulFunction( "public", viamAnonymousApi, viamAnonymousApi.eventUpdateLastViewedWithoutSession, null, "devicekey", maxDeviceKeyAnonymousEventTime.toString() ); } } } catch (e) { console.warn(e); } anynomousDeviceKeyEventsProcessing = false; }; const getNewDeviceEvents = async () => { eventsDeviceEventsProcessing = true; try { const executeResult = await executeRestfulFunction( "private", viamApi, viamApi.eventGetNewEvents, null, "devicekey" ); if (executeResult.code === "200") { const eventsLen = executeResult.data.length; const changedMaxDeviceKeyEventTime = false; for (let i = 0; i < eventsLen; i++) { const event = executeResult.data[i]; if (event.type === "QRCodeUpdated") { const actionID = event["actionID"]; const QrCode = event["payloads"][1]; const eventCopy = JSON.parse(JSON.stringify(event)); QRCode.toDataURL(actionID + "," + QrCode, function(err, url) { eventCopy["payloads"].push(url); parent.onEvent(eventCopy); }); } else { parent.onEvent(event); } maxDeviceKeyEventTime = Math.max(maxDeviceKeyEventTime, event.stamp); } if (changedMaxDeviceKeyEventTime) { await executeRestfulFunction( "private", viamApi, viamApi.eventUpdateLastViewed, null, "devicekey", maxDeviceKeyEventTime.toString() ); } } } catch (e) { console.warn(e); } eventsDeviceEventsProcessing = false; }; const getNewEntityEvents = async () => { eventsEntityEventsProcessing = true; try { const executeResult = await executeRestfulFunction( "private", viamApi, viamApi.eventGetNewEvents, null, "entity" ); if (executeResult.code === "200") { const eventsLen = executeResult.data.length; let changedMaxEntityEventTime = false; for (let i = 0; i < eventsLen; i++) { const event = executeResult.data[i]; if (event.type === "QRCodeUpdated") { const actionID = event["actionID"]; const QrCode = event["payloads"][1]; const eventCopy = JSON.parse(JSON.stringify(event)); QRCode.toDataURL(actionID + "," + QrCode, function(err, url) { eventCopy["payloads"].push(url); parent.onEvent(eventCopy); }); continue; } parent.onEvent(event); changedMaxEntityEventTime = true; maxEntityEventTime = Math.max(maxEntityEventTime, event.stamp); } if (changedMaxEntityEventTime) { await executeRestfulFunction( "private", viamApi, viamApi.eventUpdateLastViewed, null, "entity", maxEntityEventTime.toString() ); } } } catch (e) { console.warn(e); } eventsEntityEventsProcessing = false; }; setInterval(() => { if ( window.currentlyLoadedIdentity && !anynomousDeviceKeyEventsProcessing && !window.currentlyAuthenticatedIdentity ) { getNewEventsWithoutSession(); } if (window.currentlyAuthenticatedIdentity) { // These functions has to be executed at the same time. !eventsDeviceEventsProcessing && getNewDeviceEvents(); !eventsEntityEventsProcessing && getNewEntityEvents(); } }, 1000); });