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'); var identityColors = ["#994392", "#cb0767", "#e51d31", "#ec671b", "#fab610"]; function getNextColor() { var colorIndex = localStorage.getItem("colorIndex"); if (colorIndex == null || colorIndex === "") { colorIndex = 0 } var color = identityColors[colorIndex]; colorIndex++; colorIndex = colorIndex % identityColors.length; localStorage.setItem("colorIndex", colorIndex); return color } function setKeyForUUID(uuid, key) { var storedIdentityForUuid = localStorage.getItem("keyperuuid/" + uuid); if(storedIdentityForUuid !== key && storedIdentityForUuid != null && storedIdentityForUuid !== "") { destroyIdentityFromLocalStorage(storedIdentityForUuid) } localStorage.setItem("keyperuuid/" + uuid, key) } function getColorForIdentity(key) { var storedColor = localStorage.getItem("colors/" + key); if(storedColor == null || storedColor === "") { 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; if(pinCode == null || pinCode === "") { pinCode = getPincode(key) } if(pinCode == null || pinCode === "") { return null; } return encryptMessage(serializedIdentity, pinCode, "identity").then((encryptedIdentity) => { var success = true; if(extendKey === true) { success = extendPinCodeTtl(key, pinCode) } 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 { 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") { var 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 === "") { var now = new Date(); var nowMillis = now.getTime(); var ttl = window.sessionStorage.getItem("pincodettls/" + key); if (ttl == null || ttl === "" || nowMillis >= parseInt(ttl)) { clearPinCodeTtl(key); return false } else { 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) { 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); 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": 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); } }; 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; 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); 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); const { data } = await fn.apply(that, [config, ...args]); return 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 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; var passport = passportIdentity.getPassport(passportUUID); if(passport === undefined || passport === null) { createPassportCertificate(passportUUID).then(function(keys){ 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 => { if(executeResult.code === "200") { var signedCertificate = atob(executeResult.data["SignedCertificate"]); //download("passportCertificateAfterSigning.crt", "text/plain", signedCertificate) var keyUUID = executeResult.data["CertificateUUID"]; var encodedChain = executeResult.data["Chain"]; //download("rootCertificate.crt", "text/plain", atob(encodedChain[0])) var chain = []; for(var 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 { 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 + "/"; }, ...penpalMethods, createIdentity(pinCode) { return new Penpal.Promise(result => { createPassportCertificate(makeid()).then(function(keys){ 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); window.currentlyLoadedIdentity = newIdentity; window.loadedIdentities[newIdentity.authentication.publicKey] = newIdentity; extendPinCodeTtl(newIdentity.authentication.publicKey, pinCode); window.viamAnonymousApi.setIdentity(newIdentity.authentication.publicKey); result({"data" : newIdentity, "code" : "200", "status" : "Identity created" }) }); }) }, listIdentities() { return new Penpal.Promise(result => { var identities = listIdentitiesFromLocalStorage(); result({"data" : identities, "code" : "200", "status" : "Identities listed" }) }); }, loadIdentity(identityKey, pinCode) { return loadIdentityInternal(identityKey, pinCode) }, changeIdentityPinCode(key, oldPinCode, newPinCode) { return changeIdentityPinCodeInternal(key, oldPinCode, newPinCode) }, 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() { return new Penpal.Promise(result => { var identitiesTemp = listIdentitiesFromLocalStorage(); for(var i in identitiesTemp) { destroyIdentityFromLocalStorage(i) } result({"data" : "", "code" : "200", "status" : "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.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; }, identityPullAvatarFromGravatar: async () => { const authenticationPublicKey = localStorage.getItem("authenticatedIdentity"); if ( !authenticationPublicKey || !window.loadedIdentities[authenticationPublicKey] || !extendPinCodeTtl(authenticationPublicKey) ) { return encodeResponse("400", "", "Identity not authenticated"); } return await executeRestfulFunction("private", viamApi, viamApi.identityPullAvatarFromGravatar); }, 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" }) } var 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") { var actionID = executeResult.data["ActionID"]; var 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" }) } var 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 () => { const authenticationPublicKey = localStorage.getItem("authenticatedIdentity"); if (!authenticationPublicKey || !window.loadedIdentities[authenticationPublicKey]) { return { data: "", code: "400", status: "Identity not loaded" }; } const identityLogoutResponse = await executeRestfulFunction( "private", window.viamApi, window.viamApi.identityLogout, null ); destroyAuthentication(); return identityLogoutResponse; }, identityRestoreAccess(restoreAccessIdentity, identificator) { return new Penpal.Promise(result => { 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" } } var 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" } } var 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" } } var success = extendPinCodeTtl(authenticationPublicKey); if(success === false) { result({"data" : "", "code" : "400", "status" : "Identity not authenticated" }) } getCertificateForPassport(passportUUID, true).then(certificateResult => { if(certificateResult.code === "200") { var passportCertificate = certificateResult.data["x509Certificate"]; var passportPrivateKey = certificateResult.data["privateKey"]; var passportChain = certificateResult.data["chain"]; createOneTimePassportCertificate(makeid() + "-" + passportUUID, emailArg, passportPrivateKey, passportCertificate).then(function(keys){ var publicKeyOneTime = keys["publicKeyPEM"]; var privateKeyOneTime = keys["privateKeyPEM"]; var certificateOneTime = keys["certificatePEM"]; passportChain.push(passportCertificate); var 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" }) } }) }); }, 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"); }, documentCreateDocument: async (path, passportUUID, contenttype) => { const authenticationPublicKey = localStorage.getItem("authenticatedIdentity"); if ( !authenticationPublicKey || !window.loadedIdentities[authenticationPublicKey] || !extendPinCodeTtl(authenticationPublicKey) ) { return encodeResponse("400", "", "Identity not authenticated"); } const config = { headers: { path, passportuuid: passportUUID, contenttype } }; const response = await executeRestfulFunction("private", window.viamApi, window.viamApi.documentCreateDocument, config); return encodeResponse("200", response.data, "Document created"); }, documentPutDocument: async (passportUUID, resourceid, file) => { const authenticationPublicKey = localStorage.getItem("authenticatedIdentity"); if ( !authenticationPublicKey || !window.loadedIdentities[authenticationPublicKey] || !extendPinCodeTtl(authenticationPublicKey) ) { return encodeResponse("400", "", "Identity not authenticated"); } const config = { headers: { 'Content-Type': 'multipart/form-data', passportuuid: passportUUID, resourceid } }; const response = await executeRestfulFunction( "private", window.viamApi, window.viamApi.documentPutDocument, config, file); return encodeResponse("200", response.data, "Document created"); }, 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" }); } var 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" ); }, stringToUtf8ByteArray(str) { if (typeof str !== 'string') { str = str.toString() } let res = Buffer.from(str,'utf-8'); return new Penpal.Promise(result => { result(res) }) }, utf8ByteArrayToString(ba) { if (!Buffer.isBuffer(ba)) { ba = Buffer.from(ba) } let res = ba.toString('utf-8'); return new Penpal.Promise(result => { result(res) }) }, stringToUtf8Base64(str) { if (!Buffer.isBuffer(str)) { if (typeof str !== 'string') { str = str.toString() } str = Buffer.from(str, 'utf-8') } let res = str.toString('base64'); return new Penpal.Promise(result => { result(res) }) }, utf8Base64ToString(strBase64) { if (!Buffer.isBuffer(strBase64)) { if (typeof strBase64 !== 'string') { strBase64 = strBase64.toString() } strBase64 = Buffer.from(strBase64, 'base64') } let res = strBase64.toString('utf-8'); return new Penpal.Promise(result => { result(res) }) }, base64ToByteArray(strBase64) { if (typeof strBase64 !== 'string') { strBase64 = strBase64.toString() } let res = Buffer.from(strBase64, 'base64'); return new Penpal.Promise(result => { result(res) }) }, byteArrayToBase64(ba) { if (!Buffer.isBuffer(ba)) { ba = Buffer.from(ba) } let res = ba.toString('base64'); return new Penpal.Promise(result => { result(res) }) }, // Collabora APIs collaboraDiscovery() { return collaboraApi.discovery().then(apps => apps); }, // WOPI 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; }, wopiPutFile: async (path, 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(path, 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 ) { 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; 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; } } }, 50); setInterval(async () => { if (window.currentlyLoadedIdentity && !anynomousDeviceKeyEventsProcessing && !window.currentlyAuthenticatedIdentity) { 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 "Authenticated" : { const uuid = event.payloads[0]; const token = event.payloads[1]; handleIdentityLogin(window.currentlyLoadedIdentity, uuid, token); const identityToStore = window.currentlyAuthenticatedIdentity; event.payloads = [{fromQRCode: true}]; await setIdentityInLocalStorage(identityToStore); await getProfileData(identityToStore); 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; } if (window.currentlyAuthenticatedIdentity != null && eventsDeviceEventsProcessing === false) { 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; } if (window.currentlyAuthenticatedIdentity != null && eventsEntityEventsProcessing === false) { 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; } }, 1000); });