Newer
Older
import { parseSMIME, prepareVCardParts } from "../utilities/emailUtilities";
import {
stringToUtf8ByteArray,
utf8ByteArrayToString,
stringToUtf8Base64,
utf8Base64ToString,
base64ToByteArray,
byteArrayToBase64
import { extractMessageID } from "../helpers/mailparser";
Markin Igor
committed
import {
createDeviceHash,
destroyIdentityFromLocalStorage,
encodeResponse,
} from "../utilities/appUtility";
import { LOGIN_MODES } from "../constants/authentication";
CertificateData,
createOneTimePassportCertificate,
createPassportCertificate,
decryptMessage,
encryptMessage,
parseCertificate,
} from "../utilities/signingUtilities";
import { signPdf } from "../utilities/pdfUtilities";
import CryptoData from "../CryptoData";
import Identity from "../Identity";
import {
STATUS_DEVICE_REVOKED,
STATUS_USER_BLOCKED
} from "../constants/statuses";
import generateQrCode from "../utilities/generateQrCode";
getRecoveryKeyShares,
checkRecoveryKeyCombine,
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 setKeyForUUID(uuid, key) {
const storedIdentityForUuid = localStorage.getItem("keyperuuid/" + uuid);
if (
storedIdentityForUuid !== key &&
storedIdentityForUuid != null &&
storedIdentityForUuid !== ""
) {
destroyIdentityFromLocalStorage(storedIdentityForUuid);
}
function getColorForIdentity(key) {
let storedColor = localStorage.getItem("colors/" + key);
}
function setIdentityInLocalStorage(identityToStore, extendKey = true) {
const serializedIdentity = JSON.stringify(identityToStore);
const key = identityToStore.authentication.publicKey;
if (pinCode == null || pinCode === "") {
pinCode = getPincode(key);
return encryptMessage(serializedIdentity, pinCode, "identity").then(
encryptedIdentity => {
if (extendKey === true) {
success = extendPinCodeTtl(key, pinCode);
}
if (success === true) {
localStorage.setItem(key, encryptedIdentity);
const serializedIdentitiesList = localStorage.getItem("identities");
const identities = JSON.parse(serializedIdentitiesList);
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 => {
listItem.identityColor = getColorForIdentity(
identity.authentication.publicKey
);
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) {
const now = new Date();
const nowMillis = now.getTime();
const ttl = window.sessionStorage.getItem("pincodettls/" + key);
if (ttl == null || ttl === "" || nowMillis >= parseInt(ttl)) {
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;
window.sessionStorage.removeItem("pincodettls/" + key);
const now = new Date();
const nowMillis = now.getTime();
const ttl = window.sessionStorage.getItem("pincodettls/" + key);
} else {
return window.sessionStorage.getItem("pincodes/" + key);
}
}
}
function createEvent(actionId, type, payloads) {
return {
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
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 { publicKey } = identity.authentication;
viamApi.setSessionData(uuid, token);
localStorage.setItem("uuid", uuid);
localStorage.setItem("token", token);
localStorage.setItem("authenticatedIdentity", publicKey);
window.lastTimeGetProfile = 0;
setKeyForUUID(uuid, publicKey);

Alexey Lunin
committed
async function executeRestfulFunction(type, that, fn, config, ...args) {
currentlyLoadedIdentity
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 = {
status: error.message
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 userNotActivated =
type === "private" &&
code === "400" &&
(status === STATUS_USER_NOT_ACTIVATED || status === STATUS_USER_BLOCKED);
if (userNotActivated) {
destroyIdentity();
iframeParent.onEvent(event);
return response.data;
}
const badSession =
type === "private" &&
identity &&
code === "400" &&
status === "Bad session";
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 => {
.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;
x509Certificate
}
status: "Identity loaded"
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);
createPassportCertificate(passportUUID).then(function (keys) {
cryptoData.setPublicKey(keys["publicKeyPEM"]);
cryptoData.setPrivateKey(keys["privateKeyPEM"]);
//download("passportCertificateBeforeSigning.crt", "text/plain", certificate)
//cryptoData.setx509Certificate(keys["certificate"])
executeRestfulFunction(
"private",
viamApi,
viamApi.signSignCertificate,
null,
btoa(certificate),
passportUUID
).then(executeResult => {
//download("passportCertificateAfterSigning.crt", "text/plain", signedCertificate)
const keyUUID = executeResult.data["CertificateUUID"];
const encodedChain = executeResult.data["Chain"];
//download("rootCertificate.crt", "text/plain", atob(encodedChain[0]))
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"
status: "Can not store certificate " + e
certificateResult(executeResult);
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) => {
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,
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;
localStorage.setItem(
"currentlyLoadedIdentity",
JSON.stringify(newIdentity)
);
const { publicKey, x509Certificate } = newIdentity.authentication;
extendPinCodeTtl(newIdentity.authentication.publicKey, pinCode);
window.viamAnonymousApi.setIdentity(
newIdentity.authentication.publicKey
);
data: {
authentication: {
publicKey,
x509Certificate
}
status: "Identity created"
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);
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" });
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);
});
});
},
finalizeEmployeeRegistration: async (identity, identifier) => {
viamApi.setIdentity(identity.authentication.publicKey);
return executeRestfulFunction(
"public",
viamApi,
viamApi.identityFinalizeEmployeeRegistration,
null,
identifier
);
},
agreeOnRegistration(registerIdentity) {
return new Penpal.Promise(result => {
viamApi.setIdentity(registerIdentity.authentication.publicKey);
executeRestfulFunction(
"public",
viamApi,
viamApi.identityAgreeOnRegistration,
null
).then(executeResult => {
if (executeResult.code === "200") {
sequence = sequence.then(() => {
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") {
handleIdentityLogin(loginIdentity, data.Uuid, data.Session);
await getProfileData(loginIdentity);
} else if (mode === LOGIN_MODES.NEW_DEVICE) {
Object.assign(responseToClient.data, { image: dataUrl });
}
}
return responseToClient;
return new Penpal.Promise(result => {
const authenticationPublicKey = localStorage.getItem(
"authenticatedIdentity"
);
if (authenticationPublicKey === null) {
status: "Identity not authenticated"
if (window.loadedIdentities[authenticationPublicKey] === null) {
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(async executeResult => {
const actionID = executeResult.data["ActionID"];
const QrCode = executeResult.data["QrCode"];
const dataUrl = await generateQrCode(actionID + "," + QrCode);
executeResult.data["image"] = dataUrl;
result(executeResult);
} else {
result(executeResult);
}
});
});
},
identityDestroyKeysForDevice(authenticationPublicKeyArg) {
return new Penpal.Promise(result => {
const authenticationPublicKey = localStorage.getItem(
"authenticatedIdentity"
);
if (authenticationPublicKey === null) {
status: "Identity not authenticated"
if (window.loadedIdentities[authenticationPublicKey] === null) {
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);
});
});
},
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
destroyAuthentication();
"private",
window.viamApi,
window.viamApi.identityLogout,
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);
});
contactsCheckAccountRecoveryStatus: async () => {
const currentlyLoadedIdentity = localStorage.getItem(
"currentlyLoadedIdentity"
);
const parsedIdentity = JSON.parse(currentlyLoadedIdentity);
window.currentlyLoadedIdentity = parsedIdentity;
const { publicKey } = parsedIdentity.authentication;
window.loadedIdentities[publicKey] = parsedIdentity;
window.viamAnonymousApi.setIdentity(publicKey);
window.viamApi.setSessionData("", "");
window.viamApi.setIdentity(publicKey);
const timeout = ms => new Promise(resolve => setTimeout(resolve, ms));
async function checkAccountRecoveryStatus() {
const response = await executeRestfulFunction(
"public",
viamApi,
viamApi.contactsCheckAccountRecoveryStatus,
null
);
if (response.data === 0) {
await timeout(1000);
await checkAccountRecoveryStatus();
return;
const deviceHash = await createDeviceHash(publicKey);
window.viamApi.setDeviceHash(deviceHash);
const identityLoginResponse = await executeRestfulFunction(
"public",
window.viamApi,
window.viamApi.identityLogin,
null,
"previousaddeddevice"
);
const { code, data } = identityLoginResponse;
if (code === "200") {
await setIdentityInLocalStorage(parsedIdentity);
handleIdentityLogin(parsedIdentity, data.Uuid, data.Session);
await getProfileData(parsedIdentity);
localStorage.removeItem("currentlyLoadedIdentity");
contactsGetTrusteeContactsPublicKeys: async () => {
try {
const response = await executeRestfulFunction(
"private",
window.viamApi,
window.viamApi.contactsGetTrusteeContactsPublicKeys,
null
);
if (response.code !== "200") {
return response;
}
const trusteesDevices = Object.values(responseData);
/** Check if there are new trustees without added secret part */
const deviceData = Object.values(device);
return deviceData.some(data => data.hasShamir === "0");
// Generate and split recovery key
const trusteesUuids = Object.keys(responseData);
const trusteesToDevices = Object.entries(responseData);
const sharesNumber = trusteesUuids.length;
const recoveryKey = generateRecoveryKey();
const recoveryKeyShares = getRecoveryKeyShares(
recoveryKey,
sharesNumber
);
const sanityCheckResponse = checkRecoveryKeyCombine(
if (sanityCheckResponse.code !== "200") {
return sanityCheckResponse;
// Encrypt each share with every publicKey of each contact device
const shamirPartsList = await Promise.all(
trusteesToDevices.map(async ([contactUuid, device], index) => {
const deviceIdsToPublicKeys = Object.entries(device);
// Encrypt secret shares in parallel
const deviceIdsToEncryptedPartsList = await Promise.all(
deviceIdsToPublicKeys.map(async ([deviceId, { content }]) => {
const encryptedShare = await encryptShare(
recoveryKeyShares[index],
);
return [deviceId, encryptedShare];
})
);
// Turn deviceIdsToEncryptedPartsList array to object
const deviceIdsToEncryptedParts = Object.fromEntries(
deviceIdsToEncryptedPartsList
return [contactUuid, deviceIdsToEncryptedParts];
const shamirParts = Object.fromEntries(shamirPartsList);
// Save Shamir parts to database
const saveShamirPartsResponse = await executeRestfulFunction(
"private",
window.viamApi,
window.viamApi.contactsSaveShamirParts,
null,
shamirParts
);
if (saveShamirPartsResponse !== "200") {
return saveShamirPartsResponse;
}
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"
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"
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"
certificateResult => {
const passportPrivateKey = certificateResult.data["privateKey"];
const passportChain = certificateResult.data["chain"];
createOneTimePassportCertificate(
makeid() + "-" + passportUUID,
emailArg,
passportPrivateKey,
passportCertificate
const publicKeyOneTime = keys["publicKeyPEM"];
const privateKeyOneTime = keys["privateKeyPEM"];
const certificateOneTime = keys["certificatePEM"];
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
);
certificatePEM: certificateOneTime
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
const keys = await createOneTimePassportCertificate(
makeid() + "-" + passportUUID,
null,
passportPrivateKey,
passportCertificate
);
certificatePEM: certificateOneTime
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);
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
) => {
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
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,
passportPrivateKey,
passportCertificate
);
const {
privateKeyPEM: privateKeyOneTime,
certificatePEM: certificateOneTime
passportChain.push(passportCertificate);
passportChain.push(certificateOneTime);
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
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:
// "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 = {
let vCardImageData;
let vCardImageClaimValue;
const vCardImageClaimName = "vCardImage";
const defaultTagName = "notag";
const vCardClaimResponse = await executeRestfulFunction(
vCardImageClaimName,
defaultTagName,
// if (vCardClaimResponse.code !== "200") {
// return encodeResponse("400", "", vCardClaimResponse.status);
// }
if (vCardClaimResponse.code === "200") {
vCardImageClaimValue = vCardClaimResponse.data;
}
let qrCodeCoordinates = { fromL: -1, fromR: -1, toL: -1, toR: -1 };
if (
vCardImageClaimValue &&
"state" in vCardImageClaimValue &&
vCardImageClaimValue.state === "disabled"
) {
vCardImageData = new ImageData({
contentType: "image/png",
"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=" //1x1px transparent pixel
});
} else {
const vCardImageResponse = await executeRestfulFunction(
"private",
window.viamApi,
window.viamApi.passportGetVCardImage,
null,
passportUUID
);
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) {
if (htmlBody) {
if (typeof htmlBody !== "string") {
throw new Error("htmlBody is not string"); // should not happen
}
"Content-Type": "text/html"
body: htmlBody
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
}
"Content-Type": "text/plain"
body: textBody
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,
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,
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
// };
const authenticationPublicKey = localStorage.getItem(
"authenticatedIdentity"
);
if (
!authenticationPublicKey ||
!window.loadedIdentities[authenticationPublicKey] ||
!extendPinCodeTtl(authenticationPublicKey)
) {
return encodeResponse("400", "", "Identity not authenticated");
}
const validateVMimeResponse = await executeRestfulFunction(
window.viamApi.signValidateVMime,
if (validateVMimeResponse.code !== "200") {
return encodeResponse("400", "", validateVMimeResponse.status);
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"
);
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,
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,
) => {
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: {
passportuuid: passportUUID,
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");
},
return new Penpal.Promise(result => {
const authenticationPublicKey = localStorage.getItem(
"authenticatedIdentity"
);
if (authenticationPublicKey === null) {
status: "Identity not authenticated"
if (window.loadedIdentities[authenticationPublicKey] === null) {
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 => {
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) {
return new Penpal.Promise(result => {
executeRestfulFunction(
"public",
viamApi,
viamApi.marketingExecuteEventForIdentificator,
null,
identificator,
pincode,
event
).then(executeResult => {
result(executeResult);
});
});
},
getCurrentlyAuthenticatedIdentity() {
x509Certificate
return encodeResponse(
"200",
{
authentication: {
publicKey,
x509Certificate
}
},
"Currently authenticated identity"
);
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) {
Loading
Loading full blame...