Newer
Older
const QRCode = require("qrcode");
const Penpal = require("penpal").default;
Markin Igor
committed
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");
}
function setKeyForUUID(uuid, key) {
var storedIdentityForUuid = localStorage.getItem("keyperuuid/" + uuid);
if (
storedIdentityForUuid !== key &&
storedIdentityForUuid != null &&
storedIdentityForUuid !== ""
) {
destroyIdentityFromLocalStorage(storedIdentityForUuid);
}
function getColorForIdentity(key) {
var storedColor = localStorage.getItem("colors/" + key);
}
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);
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") {
listItem.identityColor = getColorForIdentity(
identity.authentication.publicKey
);
if (listItem.initials === null || listItem.initials === "") {
localStorage.setItem(
"profiles/" + identity.authentication.publicKey,
JSON.stringify(listItem)
);
executeResultUpper(listItem);
async function getIdentityFromLocalStorage(key, pinCode, extendTtl = true) {
const encryptedIdentity = localStorage.getItem(key);
if (!encryptedIdentity) {
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) {
var now = new Date();
var nowMillis = now.getTime();
var ttl = window.sessionStorage.getItem("pincodettls/" + key);
if (ttl == null || ttl === "" || nowMillis >= parseInt(ttl)) {
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;
window.sessionStorage.removeItem("pincodettls/" + key);
}
function getPincode(key) {
var now = new Date();
var nowMillis = now.getTime();
var ttl = window.sessionStorage.getItem("pincodettls/" + key);
} else {
return window.sessionStorage.getItem("pincodes/" + key);
}
}
}
function createEvent(actionId, type, payloads) {
return {
actionID: actionId,
type: type,
stamp: new Date().getTime(),
payloads: payloads
};
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
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.wopiAPI = new WopiAPI();
window.collaboraApi = new CollaboraAPI();
window.viamApi = new ViamAPI();
window.viamAnonymousApi = new ViamAPI();
window.currentlyAuthenticatedIdentity = null;
window.currentlyLoadedIdentity = null;
window.lastTimeGetProfile = 0;
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);

Alexey Lunin
committed
async function executeRestfulFunction(type, that, fn, config, ...args) {
const {
currentlyAuthenticatedIdentity,
viamApi,
currentlyLoadedIdentity
} = window;

Alexey Lunin
committed
const response = await fn.apply(that, [config, ...args]);
const identity = currentlyAuthenticatedIdentity || currentlyLoadedIdentity;

Alexey Lunin
committed
const { code, status } = response.data;
const deviceRevoked =
type === "private" && code === "401" && status === STATUS_DEVICE_REVOKED;

Alexey Lunin
committed
if (deviceRevoked) {
destroyIdentity();

Alexey Lunin
committed
const event = createEvent("", "DeviceRevoked");
iframeParent.onEvent(event);

Alexey Lunin
committed
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);

Alexey Lunin
committed
const { data } = await fn.apply(that, [config, ...args]);
}
window.executeRestfulFunction = executeRestfulFunction;
function loadIdentityInternal(identityKey, pinCode) {
return new Penpal.Promise(result => {
getIdentityFromLocalStorage(identityKey, pinCode)
.then(async loadedIdentity => {
if (loadedIdentity == null) {
result({
data: "",
code: "400",
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;
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]))
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
});
certificateResult(executeResult);
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) => {
Alexey Lunin
committed
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
Alexey Lunin
committed
}
window.API_HOST =
apiUrl.charAt(apiUrl.length - 1) === "/" ? apiUrl : apiUrl + "/";
window.WOPI_URL =
wopiUrl.charAt(wopiUrl.length - 1) === "/" ? wopiUrl : wopiUrl + "/";
window.COLLABORA_URL =
collaboraUrl.charAt(collaboraUrl.length - 1) === "/"
? collaboraUrl
: collaboraUrl + "/";
...penpalMethods,
createIdentity(pinCode) {
return new Penpal.Promise(result => {
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 => {
result({ data: identities, code: "200", status: "Identities listed" });
});
},
loadIdentity(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);
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" });
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) {
viamApi.setIdentity(registerIdentity.authentication.publicKey);
executeRestfulFunction(
"public",
viamApi,
viamApi.identityAgreeOnRegistration,
null
).then(executeResult => {
if (executeResult.code === "200") {
sequence = sequence.then(() => {
.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.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);
if (mode === LOGIN_MODES.SMS) {
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"
});
var success = extendPinCodeTtl(authenticationPublicKey);
if (success === false) {
result({
data: "",
code: "400",
status: "Identity not authenticated"
});
executeRestfulFunction(
"private",
viamApi,
viamApi.identityAddNewDevice,
null
).then(executeResult => {
var actionID = executeResult.data["ActionID"];
var QrCode = executeResult.data["QrCode"];
QRCode.toDataURL(actionID + "," + QrCode, function(err, url) {
} 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);
});
});
},
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();
"private",
window.viamApi,
window.viamApi.identityLogout,
}
},
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);
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"
});
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
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: {
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 => {
executeRestfulFunction(
"public",
viamApi,
viamApi.marketingSignUpIdentificator,
null,
identificator,
reference
).then(executeResult => {
result(executeResult);
});
});
},
marketingGetIdentificatorProfile(identificator, pincode) {
return new Penpal.Promise(result => {
executeRestfulFunction(
"public",
viamApi,
viamApi.marketingGetIdentificatorProfile,
null,
identificator,
pincode
).then(executeResult => {
result(executeResult);
});
});
},
marketingExecuteEventForIdentificator(identificator, pincode, event) {
executeRestfulFunction(
"public",
viamApi,
viamApi.marketingExecuteEventForIdentificator,
null,
identificator,
pincode,
event
).then(executeResult => {
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();
return new Penpal.Promise(result => {
},
utf8ByteArrayToString(ba) {
if (!Buffer.isBuffer(ba)) {
return new Penpal.Promise(result => {
},
stringToUtf8Base64(str) {
if (!Buffer.isBuffer(str)) {
if (typeof str !== "string") {
str = str.toString();
return new Penpal.Promise(result => {
},
utf8Base64ToString(strBase64) {
if (!Buffer.isBuffer(strBase64)) {
if (typeof strBase64 !== "string") {
strBase64 = strBase64.toString();
return new Penpal.Promise(result => {
},
base64ToByteArray(strBase64) {
if (typeof strBase64 !== "string") {
strBase64 = strBase64.toString();
return new Penpal.Promise(result => {
},
byteArrayToBase64(ba) {
if (!Buffer.isBuffer(ba)) {
return new Penpal.Promise(result => {
return collaboraApi.discovery().then(apps => apps);
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);
connection.promise.then(parent => {
if (!navigator.cookieEnabled) {
console.warn("Cookie disabled. Can't start library.");
return;
}
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");
const authenticationPublicKey = localStorage.getItem(
"authenticatedIdentity"
);
const pinCode = getPincode(authenticationPublicKey);
loadIdentityInternal(authenticationPublicKey, "00000000").then(result => {
if (result.code !== "200") {
const event = createEvent(
"CanNotGetPincodeForAuthenticatedIdentity",
"IdentityNotLoaded",
loadIdentityInternal(authenticationPublicKey, pinCode).then(result => {
if (result.code !== "200") {
const event = createEvent(
"CanNotLoadIdentity",
"ErrorDuringLoadingIdentity",
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;
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;
}
const authenticationPublicKey = localStorage.getItem(
"authenticatedIdentity"
);
const result = await loadIdentityInternal(
authenticationPublicKey,
"00000000"
);
const event = createEvent(
"CanNotGetPincodeForAuthenticatedIdentity",
"IdentityNotLoaded",
[authenticationPublicKey]
);
parent.onEvent(event);
clearPinCodeTtl(authenticationPublicKey);
window.currentlyAuthenticatedIdentity = null;
}
const pinCode = getPincode(
window.currentlyLoadedIdentity.authentication.publicKey
);
if (!pinCode) {
if (!identityLoadedEvent) {
const result = await loadIdentityInternal(
window.currentlyLoadedIdentity.authentication.publicKey,
"00000000"
);

Alexey Lunin
committed
if (window.currentlyLoadedIdentity && result.code !== "200") {
const event = createEvent(
"CanNotLoadPincodeForLoadedIdentity",
"IdentityNotLoaded",
[window.currentlyLoadedIdentity.authentication.publicKey]
);
parent.onEvent(event);
identityLoadedEvent = true;
}
if (window.currentlyAuthenticatedIdentity) {
const now = new Date().getTime();
if (now - window.lastTimeGetProfile > 30000) {
getProfileData(window.currentlyAuthenticatedIdentity);
const currentLocalStorageUUID = localStorage.getItem("uuid");
const currentLocalStorageToken = localStorage.getItem("token");
const currentLocalStorageIdentity = localStorage.getItem(
"authenticatedIdentity"
);
(!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;
}
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) {
await setIdentityInLocalStorage(window.currentlyLoadedIdentity);
parent.onEvent(event);
break;
const actionID = event["actionID"];
const QrCode = event["payloads"][1];
const eventCopy = JSON.parse(JSON.stringify(event));
QRCode.toDataURL(actionID + "," + QrCode, function(err, url) {
parent.onEvent(eventCopy);
});
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;
}
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);
});
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;
if (
window.currentlyLoadedIdentity &&
!anynomousDeviceKeyEventsProcessing &&
!window.currentlyAuthenticatedIdentity
) {
getNewEventsWithoutSession();
}
if (window.currentlyAuthenticatedIdentity) {
// These functions has to be executed at the same time.
!eventsDeviceEventsProcessing && getNewDeviceEvents();
!eventsEntityEventsProcessing && getNewEntityEvents();