Skip to content
Snippets Groups Projects
Commit e9e10317 authored by Alexey Lunin's avatar Alexey Lunin
Browse files

Merge branch 'master' into exchange-2016-support

# Conflicts:
#	javascript/src/iframe/viamapi-iframe.js
parents a67c64cb 3112ea9d
Branches
Tags
1 merge request!83Exchange 2016 support
export const STATUS_DEVICE_REVOKED = "Device revoked"; export const STATUS_DEVICE_REVOKED = "Device revoked";
export const STATUS_USER_NOT_ACTIVATED = 'User not activated';
import '../lib/textencoder.polyfill'; import '../lib/textencoder.polyfill';
import { import { parseSMIME, prepareVCardParts } from "../utilities/emailUtilities";
parseSMIME,
prepareVCardParts
} from "../utilities/emailUtilities";
import { import {
stringToUtf8ByteArray, stringToUtf8ByteArray,
utf8ByteArrayToString, utf8ByteArrayToString,
...@@ -30,15 +27,19 @@ import { ...@@ -30,15 +27,19 @@ import {
createOneTimePassportCertificate, createOneTimePassportCertificate,
createPassportCertificate, createPassportCertificate,
decryptMessage, decryptMessage,
encryptMessage, parseCertificate, encryptMessage,
parseCertificate,
signEmail, signEmail,
verifySMIME verifySMIME
} from "../utilities/signingUtilities"; } from "../utilities/signingUtilities";
import { signPdf } from "../utilities/pdfUtilities"; import { signPdf } from "../utilities/pdfUtilities";
import CryptoData from "../CryptoData"; import CryptoData from "../CryptoData";
import Identity from "../Identity"; import Identity from "../Identity";
import { STATUS_DEVICE_REVOKED } from "../constants/statuses"; import {
import generateQrCode from '../utilities/generateQrCode'; STATUS_DEVICE_REVOKED,
STATUS_USER_NOT_ACTIVATED
} from "../constants/statuses";
import generateQrCode from "../utilities/generateQrCode";
const penpalMethods = require("../../temp/penpal-methods").default; const penpalMethods = require("../../temp/penpal-methods").default;
const WopiAPI = require("./wopiapi-iframe"); const WopiAPI = require("./wopiapi-iframe");
...@@ -319,6 +320,20 @@ async function executeRestfulFunction(type, that, fn, config, ...args) { ...@@ -319,6 +320,20 @@ async function executeRestfulFunction(type, that, fn, config, ...args) {
return response.data; return response.data;
} }
const userNotActivated =
type === "private" &&
code === "400" &&
status === STATUS_USER_NOT_ACTIVATED;
if (userNotActivated) {
destroyIdentity();
const event = createEvent("", "UserNotActivated");
iframeParent.onEvent(event);
return response.data;
}
const badSession = const badSession =
type === "private" && type === "private" &&
identity && identity &&
...@@ -538,14 +553,9 @@ const connection = Penpal.connectToParent({ ...@@ -538,14 +553,9 @@ const connection = Penpal.connectToParent({
newIdentity.setPinCode(pinCode); newIdentity.setPinCode(pinCode);
window.currentlyLoadedIdentity = newIdentity; window.currentlyLoadedIdentity = newIdentity;
const { const { publicKey, x509Certificate } = newIdentity.authentication;
publicKey,
x509Certificate
} = newIdentity.authentication;
window.loadedIdentities[ window.loadedIdentities[publicKey] = newIdentity;
publicKey
] = newIdentity;
extendPinCodeTtl(newIdentity.authentication.publicKey, pinCode); extendPinCodeTtl(newIdentity.authentication.publicKey, pinCode);
window.viamAnonymousApi.setIdentity( window.viamAnonymousApi.setIdentity(
...@@ -1092,7 +1102,7 @@ const connection = Penpal.connectToParent({ ...@@ -1092,7 +1102,7 @@ const connection = Penpal.connectToParent({
); );
}); });
}, },
verifySMIME: async (smimeString) => { verifySMIME: async smimeString => {
const authenticationPublicKey = localStorage.getItem( const authenticationPublicKey = localStorage.getItem(
"authenticatedIdentity" "authenticatedIdentity"
); );
...@@ -1121,10 +1131,16 @@ const connection = Penpal.connectToParent({ ...@@ -1121,10 +1131,16 @@ const connection = Penpal.connectToParent({
const rootCaPem = rootCaResponse.data; const rootCaPem = rootCaResponse.data;
const verificationResult = await verifySMIME(smimeString, rootCaPem); const verificationResult = await verifySMIME(smimeString, rootCaPem);
return encodeResponse("200", verificationResult.verified, verificationResult.message); return encodeResponse(
"200",
verificationResult.verified,
verificationResult.message
);
}, },
validateDocument: async (documentUUID, contentType) => { validateDocument: async (documentUUID, contentType) => {
const authenticationPublicKey = localStorage.getItem("authenticatedIdentity"); const authenticationPublicKey = localStorage.getItem(
"authenticatedIdentity"
);
if ( if (
!authenticationPublicKey || !authenticationPublicKey ||
...@@ -1140,7 +1156,8 @@ const connection = Penpal.connectToParent({ ...@@ -1140,7 +1156,8 @@ const connection = Penpal.connectToParent({
window.viamApi.documentValidateDocumentByUUID, window.viamApi.documentValidateDocumentByUUID,
null, null,
documentUUID, documentUUID,
contentType); contentType
);
if (validateDocumentResponse.code !== "200") { if (validateDocumentResponse.code !== "200") {
return encodeResponse("400", "", validateDocumentResponse.status); return encodeResponse("400", "", validateDocumentResponse.status);
...@@ -1149,11 +1166,13 @@ const connection = Penpal.connectToParent({ ...@@ -1149,11 +1166,13 @@ const connection = Penpal.connectToParent({
const signatures = validateDocumentResponse.data; const signatures = validateDocumentResponse.data;
if (signatures) { if (signatures) {
for (const signature of signatures) { for (const signature of signatures) {
const certificateChain = signature.certificateChainPEM.map((certificatePEM) => { const certificateChain = signature.certificateChainPEM.map(
const certificate = parseCertificate(certificatePEM); certificatePEM => {
const certificateData = new CertificateData(certificate); const certificate = parseCertificate(certificatePEM);
return certificateData; const certificateData = new CertificateData(certificate);
}); return certificateData;
}
);
signature.certificateChain = certificateChain; signature.certificateChain = certificateChain;
} }
} }
...@@ -1352,7 +1371,11 @@ const connection = Penpal.connectToParent({ ...@@ -1352,7 +1371,11 @@ const connection = Penpal.connectToParent({
return encodeResponse("200", "", "Document signed"); return encodeResponse("200", "", "Document signed");
}, },
signDocumentJava: async (passportUUID, documentUUID, documentContentType) => { signDocumentJava: async (
passportUUID,
documentUUID,
documentContentType
) => {
const authenticationPublicKey = localStorage.getItem( const authenticationPublicKey = localStorage.getItem(
"authenticatedIdentity" "authenticatedIdentity"
); );
...@@ -1445,7 +1468,14 @@ const connection = Penpal.connectToParent({ ...@@ -1445,7 +1468,14 @@ const connection = Penpal.connectToParent({
// body: String if it is a text part (Content-Type = "text/...") or Uint8Array otherwise; filled for leaf MIME nodes // 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/...") // parts: array of instances of the same object; filled for container MIME nodes (Content-Type = "multipart/...")
// } // }
signVCard: async (passportUUID, senderEmail, attribs, textBody, htmlBody, parts) => { signVCard: async (
passportUUID,
senderEmail,
attribs,
textBody,
htmlBody,
parts
) => {
const authenticationPublicKey = localStorage.getItem( const authenticationPublicKey = localStorage.getItem(
"authenticatedIdentity" "authenticatedIdentity"
); );
...@@ -1490,15 +1520,17 @@ const connection = Penpal.connectToParent({ ...@@ -1490,15 +1520,17 @@ const connection = Penpal.connectToParent({
} }
let qrCodeImageData; let qrCodeImageData;
let qrCodeCoordinates = {fromL: -1, let qrCodeCoordinates = { fromL: -1, fromR: -1, toL: -1, toR: -1 };
fromR: -1,
toL: -1,
toR: -1};
if (vCardImageClaimValue && "state" in vCardImageClaimValue && vCardImageClaimValue.state === "disabled") { if (
vCardImageClaimValue &&
"state" in vCardImageClaimValue &&
vCardImageClaimValue.state === "disabled"
) {
vCardImageData = new ImageData({ vCardImageData = new ImageData({
contentType: "image/png", contentType: "image/png",
contentBase64: "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=" //1x1px transparent pixel contentBase64:
"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=" //1x1px transparent pixel
}); });
} else { } else {
const vCardImageResponse = await executeRestfulFunction( const vCardImageResponse = await executeRestfulFunction(
...@@ -1516,17 +1548,21 @@ const connection = Penpal.connectToParent({ ...@@ -1516,17 +1548,21 @@ const connection = Penpal.connectToParent({
} }
vCardImageData = new ImageData(vCardImageResponse.data.Image); vCardImageData = new ImageData(vCardImageResponse.data.Image);
if (vCardImageData.contentType !== "image/png") { if (vCardImageData.contentType !== "image/png") {
return encodeResponse("400", "", "Content type of vCard mmust be 'image/png'"); return encodeResponse(
"400",
"",
"Content type of vCard mmust be 'image/png'"
);
} }
qrCodeCoordinates = vCardImageResponse.data.QRCodeCoordinates; qrCodeCoordinates = vCardImageResponse.data.QRCodeCoordinates;
const qrCodeBase64Content = await generateQrCode("https://" + location.host + "/check/" + messageUUID); const qrCodeBase64Content = await generateQrCode(
qrCodeImageData = new ImageData( "https://" + location.host + "/check/" + messageUUID
{
contentType: "image/png",
content: qrCodeBase64Content
}
); );
qrCodeImageData = new ImageData({
contentType: "image/png",
content: qrCodeBase64Content
});
} }
if (typeof parts === "undefined" || parts === null) { if (typeof parts === "undefined" || parts === null) {
...@@ -1545,7 +1581,9 @@ const connection = Penpal.connectToParent({ ...@@ -1545,7 +1581,9 @@ const connection = Penpal.connectToParent({
}; };
parts.unshift(htmlPart); parts.unshift(htmlPart);
} else { } else {
console.log("Html body is not passed to signVCard, its value is ", {html: htmlBody}); console.log("Html body is not passed to signVCard, its value is ", {
html: htmlBody
});
} }
if (textBody) { if (textBody) {
...@@ -1560,10 +1598,12 @@ const connection = Penpal.connectToParent({ ...@@ -1560,10 +1598,12 @@ const connection = Penpal.connectToParent({
}; };
parts.unshift(textPart); parts.unshift(textPart);
} else { } else {
console.log("Text body is not passed to signVCard, its value is ", {text: textBody}); console.log("Text body is not passed to signVCard, its value is ", {
text: textBody
});
} }
const count = prepareVCardParts(parts); const count = await prepareVCardParts(parts);
if (count.textParts === 0) { if (count.textParts === 0) {
return encodeResponse("400", "", "No text parts passed to signVCard"); return encodeResponse("400", "", "No text parts passed to signVCard");
} }
...@@ -1616,17 +1656,21 @@ const connection = Penpal.connectToParent({ ...@@ -1616,17 +1656,21 @@ const connection = Penpal.connectToParent({
parts, parts,
vCardAttribs, vCardAttribs,
qrCodeImageData, qrCodeImageData,
qrCodeCoordinates, qrCodeCoordinates
); );
if (signVCardResponse.code !== "200") { if (signVCardResponse.code !== "200") {
return encodeResponse("400", "", signVCardResponse.status); return encodeResponse("400", "", signVCardResponse.status);
} }
const signedVCardImageData = new ImageData(signVCardResponse.data); const signedVCardImageData = new ImageData(signVCardResponse.data);
return encodeResponse("200", { return encodeResponse(
image: signedVCardImageData, "200",
messageUUID {
}, "vCard signed"); image: signedVCardImageData,
messageUUID: messageUUID
},
"vCard signed"
);
}, },
// mime - String - the MIME of the email message // mime - String - the MIME of the email message
// vCardAttribs - optional attributes for the verification procedure in format // vCardAttribs - optional attributes for the verification procedure in format
...@@ -1660,19 +1704,25 @@ const connection = Penpal.connectToParent({ ...@@ -1660,19 +1704,25 @@ const connection = Penpal.connectToParent({
} }
const validationResult = validateVMimeResponse.data; const validationResult = validateVMimeResponse.data;
const {signatures} = validationResult; const { signatures } = validationResult;
if (signatures) { if (signatures) {
for (const signature of signatures) { for (const signature of signatures) {
const certificateChain = signature.certificateChainPEM.map((certificatePEM) => { const certificateChain = signature.certificateChainPEM.map(
const certificate = parseCertificate(certificatePEM); certificatePEM => {
const certificateData = new CertificateData(certificate); const certificate = parseCertificate(certificatePEM);
return certificateData; const certificateData = new CertificateData(certificate);
}); return certificateData;
}
);
signature.certificateChain = certificateChain; signature.certificateChain = certificateChain;
} }
} }
return encodeResponse("200", validationResult, "Validation result retrieved"); return encodeResponse(
"200",
validationResult,
"Validation result retrieved"
);
}, },
generateQrCode, generateQrCode,
documentCreateDocument: async (passportUUID, path, contentType, title) => { documentCreateDocument: async (passportUUID, path, contentType, title) => {
...@@ -1980,7 +2030,10 @@ const connection = Penpal.connectToParent({ ...@@ -1980,7 +2030,10 @@ const connection = Penpal.connectToParent({
const resourceID = createDocumentResult.data; const resourceID = createDocumentResult.data;
const accessTokenResponse = await wopiAPI.getAccessToken(passportUUID, resourceID); const accessTokenResponse = await wopiAPI.getAccessToken(
passportUUID,
resourceID
);
if (accessTokenResponse.data.code !== "200") { if (accessTokenResponse.data.code !== "200") {
return accessTokenResponse.data; return accessTokenResponse.data;
...@@ -2009,7 +2062,11 @@ const connection = Penpal.connectToParent({ ...@@ -2009,7 +2062,11 @@ const connection = Penpal.connectToParent({
return encodeResponse("400", "", "Identity not authenticated"); return encodeResponse("400", "", "Identity not authenticated");
} }
const response = await wopiAPI.getAccessToken(passportUUID, resourceID, contentType); const response = await wopiAPI.getAccessToken(
passportUUID,
resourceID,
contentType
);
return response.data; return response.data;
}, },
......
...@@ -17,8 +17,10 @@ import { ...@@ -17,8 +17,10 @@ import {
} from "./signingUtilities"; } from "./signingUtilities";
import { import {
byteArrayToBase64, byteArrayToBase64,
stringToUtf8Base64 stringToUtf8Base64,
stringToUtf8ByteArray
} from "./stringUtilities"; } from "./stringUtilities";
import {getCrypto} from "pkijs";
export const SIGNATURE_CONTENT_TYPE = "application/pkcs7-signature"; export const SIGNATURE_CONTENT_TYPE = "application/pkcs7-signature";
export const DEFAULT_ATTACHMENT_NAME = "attachment"; export const DEFAULT_ATTACHMENT_NAME = "attachment";
...@@ -150,14 +152,52 @@ const capitalizeFirstLetter = (s) => { ...@@ -150,14 +152,52 @@ const capitalizeFirstLetter = (s) => {
return s.charAt(0).toUpperCase() + s.slice(1); return s.charAt(0).toUpperCase() + s.slice(1);
}; };
export function prepareVCardParts(parts) { async function sha256(array) {
if (!parts) { const cryptoLib = getCrypto();
return; const digestTmpBuf = await cryptoLib.digest({ name: "SHA-256" }, array);
const digestTmpArray = new Uint8Array(digestTmpBuf);
return digestTmpArray;
}
async function hashBody(part) {
const contentType = part.headers["Content-Type"];
const origContentType = part.headers["Original-Content-Type"];
if (!origContentType &&
!part.headers["Content-Type"].startsWith("application/hash") &&
!part.headers["Content-Type"].startsWith("text/plain") &&
!part.headers["Content-Type"].startsWith("text/html")) {
if (part.body) {
if (typeof part.body === "string") {
part.body = stringToUtf8ByteArray(part.body);
}
if (part.body instanceof ArrayBuffer) {
part.body = byteArrayToBase64(new Uint8Array(part.body));
}
if (!(part.body instanceof Uint8Array)) {
throw new Error('part body is neither string, nor Uint8Array, nor ArrayBuffer'); // should not happen
}
if (contentType) {
part.headers["Original-Content-Type"] = contentType;
}
part.headers["Content-Type"] = "application/hash; algorithm=SHA-256";
part.body = await sha256(part.body);
}
} }
}
export async function prepareVCardParts(parts) {
const count = { const count = {
textParts: 0, textParts: 0,
htmlParts: 0 htmlParts: 0
}; };
if (!parts) {
return count;
}
for (const part of parts) { for (const part of parts) {
if (!part.headers) { if (!part.headers) {
part.headers = { part.headers = {
...@@ -169,17 +209,18 @@ export function prepareVCardParts(parts) { ...@@ -169,17 +209,18 @@ export function prepareVCardParts(parts) {
capitalizedHeaders[capitalizeHeaderName(key)] = part.headers[key]; capitalizedHeaders[capitalizeHeaderName(key)] = part.headers[key];
} }
part.headers = capitalizedHeaders; part.headers = capitalizedHeaders;
try { if (!part.headers["Content-Type"]) {
part.headers["Content-Type"] = "application/octet-stream";
} else {
if (part.headers["Content-Type"].startsWith("text/plain")) { if (part.headers["Content-Type"].startsWith("text/plain")) {
count.textParts++; count.textParts++;
} else if (part.headers["Content-Type"].startsWith("text/html")) { } else if (part.headers["Content-Type"].startsWith("text/html")) {
count.htmlParts++; count.htmlParts++;
} }
} catch (ignore) {
//ignore
} }
} }
if (part.body) { if (part.body) {
await hashBody(part);
if (typeof part.body === "string") { if (typeof part.body === "string") {
part.body = stringToUtf8Base64(part.body); part.body = stringToUtf8Base64(part.body);
} else } else
...@@ -193,7 +234,7 @@ export function prepareVCardParts(parts) { ...@@ -193,7 +234,7 @@ export function prepareVCardParts(parts) {
} }
} }
if (part.parts) { if (part.parts) {
const subcount = prepareVCardParts(part.parts); const subcount = await prepareVCardParts(part.parts);
count.textParts += subcount.textParts; count.textParts += subcount.textParts;
count.htmlParts += subcount.htmlParts; count.htmlParts += subcount.htmlParts;
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment