Newer
Older
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
"private",
window.viamApi,
window.viamApi.contactsSaveShamirParts,
null,
shamirParts
);
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
) => {
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
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);
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
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"
);