feat: v1.1.0

This commit is contained in:
Sergey Shehovcov 2025-08-14 13:10:42 +03:00
parent abad92c50e
commit b450007dc4
36 changed files with 9169 additions and 7528 deletions

View File

@ -1,4 +1,4 @@
// Type definitions for crypto-pro-js-m 1.0.1
// Type definitions for crypto-pro-js-m 1.1.0
// Project: crypto-pro-js-m
// Definitions by: Serge Schekhovtsov https://github.com/schekhovtsov

1329
dist/crypto-pro-js-m.js vendored

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,4 +1,4 @@
// Type definitions for crypto-pro-js-m 1.0.1
// Type definitions for crypto-pro-js-m 1.1.0
// Project: crypto-pro-js-m
// Definitions by: Serge Schekhovtsov https://github.com/schekhovtsov

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

11450
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{
"name": "crypto-pro-js-m",
"version": "1.0.2",
"version": "1.1.0",
"description": "Асинхронный JavaScript API для работы с КриптоПРО ЭЦП Browser Plug-In. Forked from https://github.com/crypto-pro-web/crypto-pro-js",
"main": "./lib/crypto-pro-js-m.js",
"types": "./lib/crypto-pro-js-m.d.ts",

View File

@ -1,89 +0,0 @@
import 'cadesplugin';
import { rawCertificates, parsedCertificates } from '../__mocks__/certificates';
import { createAttachedSignature } from './createAttachedSignature';
import { _getCadesCert } from '../helpers/_getCadesCert';
import { addAttachedSignature } from './addAttachedSignature';
const [rawCertificateMock] = rawCertificates;
const [parsedCertificateMock] = parsedCertificates;
jest.mock('../helpers/_getCadesCert', () => ({ _getCadesCert: jest.fn(() => rawCertificateMock) }));
beforeEach(() => {
(_getCadesCert as jest.Mock).mockClear();
});
const executionSteps = [
Symbol('step 0'),
Symbol('step 1'),
Symbol('step 2'),
Symbol('step 3'),
Symbol('step 4'),
Symbol('step 5'),
];
const executionFlow = {
[executionSteps[0]]: {
propset_Name: jest.fn(),
propset_Value: jest.fn(),
},
[executionSteps[1]]: {
propset_ContentEncoding: jest.fn(),
propset_Content: jest.fn(),
SignCades: jest.fn(() => executionSteps[4]),
VerifyCades: jest.fn(),
CoSignCades: jest.fn(() => executionSteps[5]),
},
[executionSteps[2]]: {
propset_Certificate: jest.fn(),
AuthenticatedAttributes2: executionSteps[3],
propset_Options: jest.fn(),
},
[executionSteps[3]]: {
Add: jest.fn(),
},
[executionSteps[4]]: 'signature',
[executionSteps[5]]: 'newSignature',
};
window.cadesplugin.__defineExecutionFlow(executionFlow);
window.cadesplugin.CreateObjectAsync.mockImplementation((object) => {
switch (object) {
case 'CADESCOM.CPAttribute':
return executionSteps[0];
case 'CAdESCOM.CadesSignedData':
return executionSteps[1];
case 'CAdESCOM.CPSigner':
return executionSteps[2];
}
});
describe('addAttachedSignature', () => {
test('uses Buffer to encrypt the message', async () => {
const originalBufferFrom = global.Buffer.from;
(global.Buffer.from as jest.Mock) = jest.fn(() => ({
toString: jest.fn(),
}));
await createAttachedSignature(parsedCertificateMock.thumbprint, 'message');
await addAttachedSignature(parsedCertificateMock.thumbprint, 'message');
expect(global.Buffer.from).toHaveBeenCalledTimes(2);
global.Buffer.from = originalBufferFrom;
});
test('uses specified certificate', async () => {
await addAttachedSignature(parsedCertificateMock.thumbprint, 'message');
expect(_getCadesCert).toHaveBeenCalledWith(parsedCertificateMock.thumbprint);
});
test('returns new signature', async () => {
await createAttachedSignature(parsedCertificateMock.thumbprint, 'message');
const signature = await addAttachedSignature(parsedCertificateMock.thumbprint, 'message');
expect(signature).toEqual('newSignature');
});
});

View File

@ -1,112 +0,0 @@
import 'cadesplugin';
import { rawCertificates, parsedCertificates } from '../__mocks__/certificates';
import { createDetachedSignature } from './createDetachedSignature';
import { _getCadesCert } from '../helpers/_getCadesCert';
import { addDetachedSignature } from './addDetachedSignature';
import { createHash } from './createHash';
const [rawCertificateMock] = rawCertificates;
const [parsedCertificateMock] = parsedCertificates;
jest.mock('../helpers/_getCadesCert', () => ({ _getCadesCert: jest.fn(() => rawCertificateMock) }));
beforeEach(() => {
(_getCadesCert as jest.Mock).mockClear();
});
const executionSteps = [
Symbol('step 0'),
Symbol('step 1'),
Symbol('step 2'),
Symbol('step 3'),
Symbol('step 4'),
Symbol('step 5'),
Symbol('step 6'),
Symbol('step 7'),
];
const executionFlow = {
[executionSteps[0]]: {
propset_Name: jest.fn(),
propset_Value: jest.fn(),
},
[executionSteps[1]]: {
propset_ContentEncoding: jest.fn(),
propset_Content: jest.fn(),
SignHash: jest.fn(() => executionSteps[4]),
VerifyHash: jest.fn(),
CoSignHash: jest.fn(() => executionSteps[6]),
},
[executionSteps[2]]: {
propset_Certificate: jest.fn(),
AuthenticatedAttributes2: executionSteps[3],
propset_Options: jest.fn(),
},
[executionSteps[3]]: {
Add: jest.fn(),
},
[executionSteps[4]]: 'signature',
[executionSteps[5]]: {
propset_Algorithm: jest.fn(),
propset_DataEncoding: jest.fn(),
Hash: jest.fn(),
Value: executionSteps[7],
SetHashValue: jest.fn(),
},
[executionSteps[6]]: 'newSignature',
[executionSteps[7]]: 'hash',
};
window.cadesplugin.__defineExecutionFlow(executionFlow);
window.cadesplugin.CreateObjectAsync.mockImplementation((object) => {
switch (object) {
case 'CADESCOM.CPAttribute':
return executionSteps[0];
case 'CAdESCOM.CadesSignedData':
return executionSteps[1];
case 'CAdESCOM.CPSigner':
return executionSteps[2];
case 'CAdESCOM.HashedData':
return executionSteps[5];
}
});
describe('addDetachedSignature', () => {
test('uses specified certificate', async () => {
const originalBufferFrom = global.Buffer.from;
(global.Buffer.from as jest.Mock) = jest.fn(() => ({
toString: jest.fn(),
}));
const signature = await createDetachedSignature(parsedCertificateMock.thumbprint, 'message');
const signatureHash = await createHash(signature);
await addDetachedSignature(parsedCertificateMock.thumbprint, signature, signatureHash);
expect(_getCadesCert).toHaveBeenCalledWith(parsedCertificateMock.thumbprint);
expect(global.Buffer.from).toHaveBeenCalledTimes(1);
global.Buffer.from = originalBufferFrom;
});
test('returns new signature', async () => {
const originalBufferFrom = global.Buffer.from;
(global.Buffer.from as jest.Mock) = jest.fn(() => ({
toString: jest.fn(),
}));
let signature = await createDetachedSignature(parsedCertificateMock.thumbprint, 'message');
const signatureHash = await createHash(signature);
signature = await addDetachedSignature(parsedCertificateMock.thumbprint, signature, signatureHash);
expect(_getCadesCert).toHaveBeenCalledWith(parsedCertificateMock.thumbprint);
expect(global.Buffer.from).toHaveBeenCalledTimes(1);
expect(signature).toEqual('newSignature');
global.Buffer.from = originalBufferFrom;
});
});

View File

@ -1,70 +0,0 @@
import 'cadesplugin';
import { parsedCertificates } from '../../__mocks__/certificates';
import { ISSUER_TAGS_TRANSLATIONS, SUBJECT_TAGS_TRANSLATIONS } from '../../constants';
import { exportBase64 } from './exportBase64';
import { getAlgorithm } from './getAlgorithm';
import { getCadesProp } from './getCadesProp';
import { getDecodedExtendedKeyUsage } from './getDecodedExtendedKeyUsage';
import { getExtendedKeyUsage } from './getExtendedKeyUsage';
import { getInfo } from './getInfo';
import { hasExtendedKeyUsage } from './hasExtendedKeyUsage';
import { isValid } from './isValid';
import { Certificate } from './certificate';
const [parsedCertificateMock] = parsedCertificates;
const oidsMock = ['oid 1', 'oid 2'];
jest.mock('./isValid', () => ({ isValid: jest.fn(() => 'isValid') }));
jest.mock('./getCadesProp', () => ({ getCadesProp: jest.fn(() => 'getCadesProp') }));
jest.mock('./exportBase64', () => ({ exportBase64: jest.fn(() => 'exportBase64') }));
jest.mock('./getAlgorithm', () => ({ getAlgorithm: jest.fn(() => 'getAlgorithm') }));
jest.mock('./getInfo', () => ({ getInfo: jest.fn(() => 'getInfo') }));
jest.mock('./getExtendedKeyUsage', () => ({ getExtendedKeyUsage: jest.fn(() => 'getExtendedKeyUsage') }));
jest.mock('./getDecodedExtendedKeyUsage', () => ({
getDecodedExtendedKeyUsage: jest.fn(() => 'getDecodedExtendedKeyUsage'),
}));
jest.mock('./hasExtendedKeyUsage', () => ({ hasExtendedKeyUsage: jest.fn(() => 'hasExtendedKeyUsage') }));
beforeEach(() => {
(isValid as jest.Mock).mockClear();
(getCadesProp as jest.Mock).mockClear();
(exportBase64 as jest.Mock).mockClear();
(getAlgorithm as jest.Mock).mockClear();
(getInfo as jest.Mock).mockClear();
(getExtendedKeyUsage as jest.Mock).mockClear();
(getDecodedExtendedKeyUsage as jest.Mock).mockClear();
(hasExtendedKeyUsage as jest.Mock).mockClear();
});
const certificate = new Certificate(
null,
parsedCertificateMock.name,
parsedCertificateMock.issuerName,
parsedCertificateMock.subjectName,
parsedCertificateMock.thumbprint,
parsedCertificateMock.validFrom,
parsedCertificateMock.validTo,
);
describe('getInfo', () => {
test("calls external APIs for each method and passes it's results outside", async () => {
expect(certificate.isValid()).toEqual('isValid');
expect(isValid).toHaveBeenCalledTimes(1);
expect(certificate.getCadesProp('property name')).toEqual('getCadesProp');
expect(getCadesProp).toHaveBeenCalledWith('property name');
expect(certificate.exportBase64()).toEqual('exportBase64');
expect(exportBase64).toHaveBeenCalledTimes(1);
expect(certificate.getAlgorithm()).toEqual('getAlgorithm');
expect(getAlgorithm).toHaveBeenCalledTimes(1);
expect(certificate.getOwnerInfo()).toEqual('getInfo');
expect(getInfo).toHaveBeenCalledWith(SUBJECT_TAGS_TRANSLATIONS, 'SubjectName');
expect(certificate.getIssuerInfo()).toEqual('getInfo');
expect(getInfo).toHaveBeenCalledWith(ISSUER_TAGS_TRANSLATIONS, 'IssuerName');
expect(certificate.getExtendedKeyUsage()).toEqual('getExtendedKeyUsage');
expect(getExtendedKeyUsage).toHaveBeenCalledTimes(1);
expect(certificate.getDecodedExtendedKeyUsage()).toEqual('getDecodedExtendedKeyUsage');
expect(getDecodedExtendedKeyUsage).toHaveBeenCalledTimes(1);
expect(certificate.hasExtendedKeyUsage(oidsMock)).toEqual('hasExtendedKeyUsage');
expect(hasExtendedKeyUsage).toHaveBeenCalledWith(oidsMock);
});
});

View File

@ -1,24 +0,0 @@
import 'cadesplugin';
import { exportBase64 } from './exportBase64';
const exportedCertificateMock = 'certificate as base64';
const executionSteps = [Symbol('step 0')];
const executionFlow = {
[executionSteps[0]]: exportedCertificateMock,
};
window.cadesplugin.__defineExecutionFlow(executionFlow);
describe('exportBase64', () => {
test('returns exported certificate', async () => {
const certificateAsBase64 = await exportBase64.call({
_cadesCertificate: {
Export: jest.fn(() => executionSteps[0]),
},
});
expect(certificateAsBase64).toEqual(exportedCertificateMock);
});
});

View File

@ -1,33 +0,0 @@
import 'cadesplugin';
import { getAlgorithm } from './getAlgorithm';
const executionSteps = [Symbol('step 0'), Symbol('step 1'), Symbol('step 2'), Symbol('step 3')];
const executionFlow = {
[executionSteps[0]]: {
Algorithm: executionSteps[1],
},
[executionSteps[1]]: {
FriendlyName: executionSteps[2],
Value: executionSteps[3],
},
[executionSteps[2]]: 'algorithm',
[executionSteps[3]]: 'oid',
};
window.cadesplugin.__defineExecutionFlow(executionFlow);
describe('getAlgorithm', () => {
test('returns information about algorithm', async () => {
const algorithmInfo = await getAlgorithm.call({
_cadesCertificate: {
PublicKey: jest.fn(() => executionSteps[0]),
},
});
expect(algorithmInfo).toStrictEqual({
algorithm: 'algorithm',
oid: 'oid',
});
});
});

View File

@ -1,27 +0,0 @@
import 'cadesplugin';
import { getCadesProp } from './getCadesProp';
const cadesPropertyContentMock = 'content of a cades property';
const executionSteps = [Symbol('step 0')];
const executionFlow = {
[executionSteps[0]]: cadesPropertyContentMock,
};
window.cadesplugin.__defineExecutionFlow(executionFlow);
describe('getCadesProp', () => {
test('returns contents of a cades prop', async () => {
const cadesPropertyContent = await getCadesProp.call(
{
_cadesCertificate: {
cadesProperty: executionSteps[0],
},
},
'cadesProperty',
);
expect(cadesPropertyContent).toEqual(cadesPropertyContentMock);
});
});

View File

@ -1,18 +0,0 @@
import 'cadesplugin';
import { getDecodedExtendedKeyUsage } from './getDecodedExtendedKeyUsage';
const oidsMock = ['1.2.643.3.131.1.1', '1.2.643.6.3.1.3.1', '1.2.643.3.141.1.1'];
describe('getDecodedExtendedKeyUsage', () => {
test('returns translated info about existing oids of a certificate', async () => {
const getExtendedKeyUsageStub = jest.fn(() => oidsMock);
const certificateStub = { getExtendedKeyUsage: getExtendedKeyUsageStub };
expect(await getDecodedExtendedKeyUsage.call(certificateStub)).toEqual({
'1.2.643.3.131.1.1': 'ИНН',
'1.2.643.3.141.1.1': 'РНС ФСС',
'1.2.643.6.3.1.3.1': 'Участник размещения заказа',
});
expect(getExtendedKeyUsageStub).toBeCalledTimes(1);
});
});

View File

@ -1,35 +0,0 @@
import 'cadesplugin';
import { getExtendedKeyUsage } from './getExtendedKeyUsage';
const oidsMock = ['1.3.6.1.4.1.311.80.1'];
const executionSteps = [Symbol('step 0'), Symbol('step 1'), Symbol('step 2'), Symbol('step 3'), Symbol('step 4')];
const executionFlow = {
[executionSteps[0]]: {
EKUs: executionSteps[1],
},
[executionSteps[1]]: {
Count: executionSteps[2],
Item: jest.fn(() => executionSteps[3]),
},
[executionSteps[2]]: 1,
[executionSteps[3]]: {
OID: executionSteps[4],
},
[executionSteps[4]]: oidsMock[0],
};
window.cadesplugin.__defineExecutionFlow(executionFlow);
describe('getExtendedKeyUsage', () => {
test('returns info about oids', async () => {
const oids = await getExtendedKeyUsage.call({
_cadesCertificate: {
ExtendedKeyUsage: jest.fn(() => executionSteps[0]),
},
});
expect(oids).toStrictEqual(oidsMock);
});
});

View File

@ -1,35 +0,0 @@
import 'cadesplugin';
import { ISSUER_TAGS_TRANSLATIONS } from '../../constants';
import { getInfo } from './getInfo';
import { getCadesProp } from './getCadesProp';
import { _parseCertInfo } from '../../helpers/_parseCertInfo';
const entitiesPathMock = 'path to entities';
const entitiesMock = 'info about the entities';
const certificateInfoMock = [
{
description: 'description',
title: 'title',
isTranslated: true,
},
];
jest.mock('./getCadesProp', () => ({ getCadesProp: jest.fn(() => entitiesMock) }));
jest.mock('../../helpers/_parseCertInfo', () => ({ _parseCertInfo: jest.fn(() => certificateInfoMock) }));
beforeEach(() => {
(getCadesProp as jest.Mock).mockClear();
(_parseCertInfo as jest.Mock).mockClear();
});
describe('getInfo', () => {
test('calls external APIs to get information about the certificate', async () => {
const certificateInfo = await getInfo(ISSUER_TAGS_TRANSLATIONS, entitiesPathMock);
expect(getCadesProp).toHaveBeenCalledTimes(1);
expect(getCadesProp).toHaveBeenCalledWith(entitiesPathMock);
expect(_parseCertInfo).toHaveBeenCalledTimes(1);
expect(_parseCertInfo).toHaveBeenCalledWith(ISSUER_TAGS_TRANSLATIONS, entitiesMock);
expect(certificateInfo).toStrictEqual(certificateInfoMock);
});
});

View File

@ -1,18 +0,0 @@
import 'cadesplugin';
import { hasExtendedKeyUsage } from './hasExtendedKeyUsage';
const oidsMock = ['1.3.6.1.4.1.311.80.1', '1.3.6.1.5.5.7.3.2', '1.3.6.1.4.1.311.10.3.12'];
describe('hasExtendedKeyUsage', () => {
test('returns info about existing oids of a certificate', async () => {
const getExtendedKeyUsageStub = jest.fn(() => oidsMock);
const certificateStub = { getExtendedKeyUsage: getExtendedKeyUsageStub };
expect(await hasExtendedKeyUsage.call(certificateStub, '1.3.6.1.4.1.311.80.1')).toEqual(true);
expect(await hasExtendedKeyUsage.call(certificateStub, ['1.3.6.1.5.5.7.3.2', '1.3.6.1.4.1.311.10.3.12'])).toEqual(
true,
);
expect(await hasExtendedKeyUsage.call(certificateStub, 'non-existing oid')).toEqual(false);
expect(getExtendedKeyUsageStub).toBeCalledTimes(3);
});
});

View File

@ -1,25 +0,0 @@
import 'cadesplugin';
import { isValid } from './isValid';
const executionSteps = [Symbol('step 0'), Symbol('step 1')];
const executionFlow = {
[executionSteps[0]]: {
Result: executionSteps[1],
},
[executionSteps[1]]: true,
};
window.cadesplugin.__defineExecutionFlow(executionFlow);
describe('isValid', () => {
test('returns validity state of certificate', async () => {
const valid = await isValid.call({
_cadesCertificate: {
IsValid: jest.fn(() => executionSteps[0]),
},
});
expect(valid).toEqual(true);
});
});

View File

@ -1,76 +0,0 @@
import 'cadesplugin';
import { rawCertificates, parsedCertificates } from '../__mocks__/certificates';
import { createAttachedSignature } from './createAttachedSignature';
import { _getCadesCert } from '../helpers/_getCadesCert';
const [rawCertificateMock] = rawCertificates;
const [parsedCertificateMock] = parsedCertificates;
jest.mock('../helpers/_getCadesCert', () => ({ _getCadesCert: jest.fn(() => rawCertificateMock) }));
beforeEach(() => {
(_getCadesCert as jest.Mock).mockClear();
});
const executionSteps = [Symbol('step 0'), Symbol('step 1'), Symbol('step 2'), Symbol('step 3'), Symbol('step 4')];
const executionFlow = {
[executionSteps[0]]: {
propset_Name: jest.fn(),
propset_Value: jest.fn(),
},
[executionSteps[1]]: {
propset_ContentEncoding: jest.fn(),
propset_Content: jest.fn(),
SignCades: jest.fn(() => executionSteps[4]),
},
[executionSteps[2]]: {
propset_Certificate: jest.fn(),
AuthenticatedAttributes2: executionSteps[3],
propset_Options: jest.fn(),
},
[executionSteps[3]]: {
Add: jest.fn(),
},
[executionSteps[4]]: 'signature',
};
window.cadesplugin.__defineExecutionFlow(executionFlow);
window.cadesplugin.CreateObjectAsync.mockImplementation((object) => {
switch (object) {
case 'CADESCOM.CPAttribute':
return executionSteps[0];
case 'CAdESCOM.CadesSignedData':
return executionSteps[1];
case 'CAdESCOM.CPSigner':
return executionSteps[2];
}
});
describe('createAttachedSignature', () => {
test('uses Buffer to encrypt the message', async () => {
const originalBufferFrom = global.Buffer.from;
(global.Buffer.from as jest.Mock) = jest.fn(() => ({
toString: jest.fn(),
}));
await createAttachedSignature(parsedCertificateMock.thumbprint, 'message');
expect(global.Buffer.from).toHaveBeenCalledTimes(1);
global.Buffer.from = originalBufferFrom;
});
test('uses specified certificate', async () => {
await createAttachedSignature(parsedCertificateMock.thumbprint, 'message');
expect(_getCadesCert).toHaveBeenCalledWith(parsedCertificateMock.thumbprint);
});
test('returns signature', async () => {
const signature = await createAttachedSignature(parsedCertificateMock.thumbprint, 'message');
expect(signature).toEqual('signature');
});
});

View File

@ -1,75 +0,0 @@
import 'cadesplugin';
import { rawCertificates, parsedCertificates } from '../__mocks__/certificates';
import { createDetachedSignature } from './createDetachedSignature';
import { _getCadesCert } from '../helpers/_getCadesCert';
const [rawCertificateMock] = rawCertificates;
const [parsedCertificateMock] = parsedCertificates;
jest.mock('../helpers/_getCadesCert', () => ({ _getCadesCert: jest.fn(() => rawCertificateMock) }));
beforeEach(() => {
(_getCadesCert as jest.Mock).mockClear();
});
const executionSteps = [
Symbol('step 0'),
Symbol('step 1'),
Symbol('step 2'),
Symbol('step 3'),
Symbol('step 4'),
Symbol('step 5'),
];
const executionFlow = {
[executionSteps[0]]: {
propset_Name: jest.fn(),
propset_Value: jest.fn(),
},
[executionSteps[1]]: {
propset_ContentEncoding: jest.fn(),
propset_Content: jest.fn(),
SignHash: jest.fn(() => executionSteps[4]),
},
[executionSteps[2]]: {
propset_Certificate: jest.fn(),
AuthenticatedAttributes2: executionSteps[3],
propset_Options: jest.fn(),
},
[executionSteps[3]]: {
Add: jest.fn(),
},
[executionSteps[4]]: 'signature',
[executionSteps[5]]: {
propset_Algorithm: jest.fn(),
SetHashValue: jest.fn(),
},
};
window.cadesplugin.__defineExecutionFlow(executionFlow);
window.cadesplugin.CreateObjectAsync.mockImplementation((object) => {
switch (object) {
case 'CADESCOM.CPAttribute':
return executionSteps[0];
case 'CAdESCOM.CadesSignedData':
return executionSteps[1];
case 'CAdESCOM.CPSigner':
return executionSteps[2];
case 'CAdESCOM.HashedData':
return executionSteps[5];
}
});
describe('createDetachedSignature', () => {
test('uses specified certificate', async () => {
await createDetachedSignature(parsedCertificateMock.thumbprint, 'message');
expect(_getCadesCert).toHaveBeenCalledWith(parsedCertificateMock.thumbprint);
});
test('returns signature', async () => {
const signature = await createDetachedSignature(parsedCertificateMock.thumbprint, 'message');
expect(signature).toEqual('signature');
});
});

View File

@ -1,44 +0,0 @@
import 'cadesplugin';
import { createHash } from './createHash';
const executionSteps = [Symbol('step 0'), Symbol('step 1')];
const executionFlow = {
[executionSteps[0]]: {
propset_Algorithm: jest.fn(),
propset_DataEncoding: jest.fn(),
Hash: jest.fn(),
Value: executionSteps[1],
},
[executionSteps[1]]: 'hash',
};
window.cadesplugin.__defineExecutionFlow(executionFlow);
window.cadesplugin.CreateObjectAsync.mockImplementation((object) => {
switch (object) {
case 'CAdESCOM.HashedData':
return executionSteps[0];
}
});
describe('createHash', () => {
test('uses Buffer to encrypt the message', async () => {
const originalBufferFrom = global.Buffer.from;
(global.Buffer.from as jest.Mock) = jest.fn(() => ({
toString: jest.fn(),
}));
await createHash('message');
expect(global.Buffer.from).toHaveBeenCalledTimes(1);
global.Buffer.from = originalBufferFrom;
});
test('returns created hash', async () => {
const hash = await createHash('message');
expect(hash).toEqual('hash');
});
});

View File

@ -1,71 +0,0 @@
import 'cadesplugin';
import { rawCertificates, parsedCertificates } from '../__mocks__/certificates';
import { createXMLSignature } from './createXMLSignature';
import { _getCadesCert } from '../helpers/_getCadesCert';
const [rawCertificateMock] = rawCertificates;
const [parsedCertificateMock] = parsedCertificates;
jest.mock('../helpers/_getCadesCert', () => ({ _getCadesCert: jest.fn(() => rawCertificateMock) }));
beforeEach(() => {
(_getCadesCert as jest.Mock).mockClear();
});
const executionSteps = [Symbol('step 0'), Symbol('step 1'), Symbol('step 2')];
const executionFlow = {
[executionSteps[0]]: {
propset_Certificate: jest.fn(),
propset_CheckCertificate: jest.fn(),
},
[executionSteps[1]]: {
propset_Content: jest.fn(),
propset_SignatureType: jest.fn(),
propset_SignatureMethod: jest.fn(),
propset_DigestMethod: jest.fn(),
Sign: jest.fn(() => executionSteps[2]),
},
[executionSteps[2]]: 'signature',
};
window.cadesplugin.__defineExecutionFlow(executionFlow);
window.cadesplugin.CreateObjectAsync.mockImplementation((object) => {
switch (object) {
case 'CAdESCOM.CPSigner':
return executionSteps[0];
case 'CAdESCOM.SignedXML':
return executionSteps[1];
}
});
describe('createXMLSignature', () => {
test('uses specified certificate', async () => {
await createXMLSignature(parsedCertificateMock.thumbprint, 'message');
expect(_getCadesCert).toHaveBeenCalledWith(parsedCertificateMock.thumbprint);
});
test('returns signature', async () => {
const signature = await createXMLSignature(
parsedCertificateMock.thumbprint,
`
<?xml version="1.0" encoding="UTF-8"?>
<!--
Original XML doc file for sign example.
-->
<Envelope xmlns="urn:envelope">
<Data>
Hello, World!
</Data>
<Node xml:id="nodeID">
Hello, Node!
</Node>
</Envelope>
`,
);
expect(signature).toEqual('signature');
});
});

View File

@ -1,60 +0,0 @@
import 'cadesplugin';
import { rawCertificates, parsedCertificates } from '../__mocks__/certificates';
import { getAllContainerCertificates } from './getAllContainerCertificates';
const [rawCertificateMock] = rawCertificates;
const [parsedCertificateMock] = parsedCertificates;
const executionSteps = [
Symbol('step 0'),
Symbol('step 1'),
Symbol('step 2'),
Symbol('step 3'),
Symbol('step 4'),
Symbol('step 5'),
Symbol('step 6'),
Symbol('step 7'),
Symbol('step 8'),
];
const executionFlow = {
[executionSteps[0]]: {
Certificates: executionSteps[1],
Close: jest.fn(),
Open: jest.fn(),
},
[executionSteps[1]]: {
Count: executionSteps[2],
Item: jest.fn(() => executionSteps[3]),
},
[executionSteps[2]]: 1,
[executionSteps[3]]: {
IssuerName: executionSteps[6],
SubjectName: executionSteps[5],
Thumbprint: executionSteps[4],
ValidFromDate: executionSteps[7],
ValidToDate: executionSteps[8],
},
[executionSteps[6]]: rawCertificateMock.IssuerName,
[executionSteps[5]]: rawCertificateMock.SubjectName,
[executionSteps[4]]: rawCertificateMock.Thumbprint,
[executionSteps[7]]: rawCertificateMock.ValidFromDate,
[executionSteps[8]]: rawCertificateMock.ValidToDate,
};
window.cadesplugin.__defineExecutionFlow(executionFlow);
window.cadesplugin.CreateObjectAsync.mockImplementation(() => executionSteps[0]);
describe('getUserCertificates', () => {
test('returns certificates list', async () => {
const certificates = await getAllContainerCertificates();
expect(certificates.length).toBeGreaterThan(0);
});
test('returns certificates with correct fields', async () => {
const [certificate] = await getAllContainerCertificates();
expect(certificate).toMatchObject(parsedCertificateMock);
});
});

View File

@ -1,60 +0,0 @@
import 'cadesplugin';
import { rawCertificates, parsedCertificates } from '../__mocks__/certificates';
import { getAllUserCertificates } from './getAllUserCertificates';
const [rawCertificateMock] = rawCertificates;
const [parsedCertificateMock] = parsedCertificates;
const executionSteps = [
Symbol('step 0'),
Symbol('step 1'),
Symbol('step 2'),
Symbol('step 3'),
Symbol('step 4'),
Symbol('step 5'),
Symbol('step 6'),
Symbol('step 7'),
Symbol('step 8'),
];
const executionFlow = {
[executionSteps[0]]: {
Certificates: executionSteps[1],
Close: jest.fn(),
Open: jest.fn(),
},
[executionSteps[1]]: {
Count: executionSteps[2],
Item: jest.fn(() => executionSteps[3]),
},
[executionSteps[2]]: 1,
[executionSteps[3]]: {
IssuerName: executionSteps[6],
SubjectName: executionSteps[5],
Thumbprint: executionSteps[4],
ValidFromDate: executionSteps[7],
ValidToDate: executionSteps[8],
},
[executionSteps[6]]: rawCertificateMock.IssuerName,
[executionSteps[5]]: rawCertificateMock.SubjectName,
[executionSteps[4]]: rawCertificateMock.Thumbprint,
[executionSteps[7]]: rawCertificateMock.ValidFromDate,
[executionSteps[8]]: rawCertificateMock.ValidToDate,
};
window.cadesplugin.__defineExecutionFlow(executionFlow);
window.cadesplugin.CreateObjectAsync.mockImplementation(() => executionSteps[0]);
describe('getUserCertificates', () => {
test('returns certificates list', async () => {
const certificates = await getAllUserCertificates();
expect(certificates.length).toBeGreaterThan(0);
});
test('returns certificates with correct fields', async () => {
const [certificate] = await getAllUserCertificates();
expect(certificate).toMatchObject(parsedCertificateMock);
});
});

View File

@ -1,28 +0,0 @@
import 'cadesplugin';
import { parsedCertificates } from '../__mocks__/certificates';
import { getCertificate } from './getCertificate';
import { getUserCertificates } from './getUserCertificates';
jest.mock('./getUserCertificates', () => ({ getUserCertificates: jest.fn(() => parsedCertificates) }));
beforeEach(() => {
(getUserCertificates as jest.Mock).mockClear();
});
describe('getCertificate', () => {
const [sampleCertificate] = parsedCertificates;
test('calls getUserCertificates internally', async () => {
await getCertificate(sampleCertificate.thumbprint);
expect(getUserCertificates).toHaveBeenCalledTimes(1);
});
test('returns requested certificate', async () => {
expect(await getCertificate(sampleCertificate.thumbprint)).toStrictEqual(sampleCertificate);
});
test("throws error if certificate wasn't found", async () => {
await expect(getCertificate('some non-existing thumbprint')).rejects.toThrowError('не найден');
});
});

View File

@ -1,68 +0,0 @@
import 'cadesplugin';
import { rawCertificates, parsedCertificates } from '../__mocks__/certificates';
import { getContainerCertificates } from './getContainerCertificates';
const [rawCertificateMock] = rawCertificates;
const [parsedCertificateMock] = parsedCertificates;
const executionSteps = [
Symbol('step 0'),
Symbol('step 1'),
Symbol('step 2'),
Symbol('step 3'),
Symbol('step 4'),
Symbol('step 5'),
Symbol('step 6'),
Symbol('step 7'),
Symbol('step 8'),
Symbol('step 9'),
Symbol('step 10'),
];
const executionFlow = {
[executionSteps[0]]: {
Certificates: executionSteps[1],
Close: jest.fn(),
Open: jest.fn(),
},
[executionSteps[1]]: {
Find: jest.fn(() => executionSteps[2]),
},
[executionSteps[2]]: {
Find: jest.fn(() => executionSteps[3]),
},
[executionSteps[3]]: {
Count: executionSteps[4],
Item: jest.fn(() => executionSteps[5]),
},
[executionSteps[4]]: 1,
[executionSteps[5]]: {
IssuerName: executionSteps[8],
SubjectName: executionSteps[7],
Thumbprint: executionSteps[6],
ValidFromDate: executionSteps[9],
ValidToDate: executionSteps[10],
},
[executionSteps[8]]: rawCertificateMock.IssuerName,
[executionSteps[7]]: rawCertificateMock.SubjectName,
[executionSteps[6]]: rawCertificateMock.Thumbprint,
[executionSteps[9]]: rawCertificateMock.ValidFromDate,
[executionSteps[10]]: rawCertificateMock.ValidToDate,
};
window.cadesplugin.__defineExecutionFlow(executionFlow);
window.cadesplugin.CreateObjectAsync.mockImplementation(() => executionSteps[0]);
describe('getContainerCertificates', () => {
test('returns certificates list', async () => {
const certificates = await getContainerCertificates();
expect(certificates.length).toBeGreaterThan(0);
});
test('returns certificates with correct fields', async () => {
const [certificate] = await getContainerCertificates();
expect(certificate).toMatchObject(parsedCertificateMock);
});
});

View File

@ -1,26 +0,0 @@
import 'cadesplugin';
import { getCspVersion } from './getCspVersion';
const executionSteps = [Symbol('step 0'), Symbol('step 1'), Symbol('step 2')];
// "any" because of using toString on the literal
const executionFlow: any = {
[executionSteps[0]]: {
CSPVersion: jest.fn(() => executionSteps[1]),
},
[executionSteps[1]]: {
toString: jest.fn(() => executionSteps[2]),
},
[executionSteps[2]]: '4.0.9971',
};
window.cadesplugin.__defineExecutionFlow(executionFlow);
window.cadesplugin.CreateObjectAsync.mockImplementation(() => executionSteps[0]);
describe('getCspVersion', () => {
test('returns information about CSP', async () => {
const cspVersion = await getCspVersion();
expect(cspVersion).toStrictEqual('4.0.9971');
});
});

View File

@ -1,28 +0,0 @@
import 'cadesplugin';
import { getPluginVersion } from './getPluginVersion';
const executionSteps = [Symbol('step 0'), Symbol('step 1'), Symbol('step 2'), Symbol('step 3')];
// "any" because of using toString on the literal
const executionFlow: any = {
[executionSteps[0]]: {
PluginVersion: executionSteps[1],
Version: executionSteps[2],
},
[executionSteps[1]]: undefined,
[executionSteps[2]]: {
toString: jest.fn(() => executionSteps[3]),
},
[executionSteps[3]]: '2.0.13771',
};
window.cadesplugin.__defineExecutionFlow(executionFlow);
window.cadesplugin.CreateObjectAsync.mockImplementation(() => executionSteps[0]);
describe('getPluginVersion', () => {
test('returns information about plugin', async () => {
const pluginVersion = await getPluginVersion();
expect(pluginVersion).toStrictEqual('2.0.13771');
});
});

View File

@ -1,43 +0,0 @@
import 'cadesplugin';
import { getSystemInfo } from './getSystemInfo';
const executionSteps = [
Symbol('step 0'),
Symbol('step 1'),
Symbol('step 2'),
Symbol('step 3'),
Symbol('step 4'),
Symbol('step 5'),
];
// "any" because of using toString on the literal
const executionFlow: any = {
[executionSteps[0]]: {
PluginVersion: executionSteps[1],
Version: executionSteps[2],
CSPVersion: jest.fn(() => executionSteps[3]),
},
[executionSteps[1]]: undefined,
[executionSteps[2]]: {
toString: jest.fn(() => executionSteps[4]),
},
[executionSteps[3]]: {
toString: jest.fn(() => executionSteps[5]),
},
[executionSteps[4]]: '2.0.13771',
[executionSteps[5]]: '4.0.9971',
};
window.cadesplugin.__defineExecutionFlow(executionFlow);
window.cadesplugin.CreateObjectAsync.mockImplementation(() => executionSteps[0]);
describe('getSystemInfo', () => {
test('returns information about environment', async () => {
const systemInfo = await getSystemInfo();
expect(systemInfo).toStrictEqual({
cadesVersion: '2.0.13771',
cspVersion: '4.0.9971',
});
});
});

View File

@ -1,68 +0,0 @@
import 'cadesplugin';
import { rawCertificates, parsedCertificates } from '../__mocks__/certificates';
import { getUserCertificates } from './getUserCertificates';
const [rawCertificateMock] = rawCertificates;
const [parsedCertificateMock] = parsedCertificates;
const executionSteps = [
Symbol('step 0'),
Symbol('step 1'),
Symbol('step 2'),
Symbol('step 3'),
Symbol('step 4'),
Symbol('step 5'),
Symbol('step 6'),
Symbol('step 7'),
Symbol('step 8'),
Symbol('step 9'),
Symbol('step 10'),
];
const executionFlow = {
[executionSteps[0]]: {
Certificates: executionSteps[1],
Close: jest.fn(),
Open: jest.fn(),
},
[executionSteps[1]]: {
Find: jest.fn(() => executionSteps[2]),
},
[executionSteps[2]]: {
Find: jest.fn(() => executionSteps[3]),
},
[executionSteps[3]]: {
Count: executionSteps[4],
Item: jest.fn(() => executionSteps[5]),
},
[executionSteps[4]]: 1,
[executionSteps[5]]: {
IssuerName: executionSteps[8],
SubjectName: executionSteps[7],
Thumbprint: executionSteps[6],
ValidFromDate: executionSteps[9],
ValidToDate: executionSteps[10],
},
[executionSteps[8]]: rawCertificateMock.IssuerName,
[executionSteps[7]]: rawCertificateMock.SubjectName,
[executionSteps[6]]: rawCertificateMock.Thumbprint,
[executionSteps[9]]: rawCertificateMock.ValidFromDate,
[executionSteps[10]]: rawCertificateMock.ValidToDate,
};
window.cadesplugin.__defineExecutionFlow(executionFlow);
window.cadesplugin.CreateObjectAsync.mockImplementation(() => executionSteps[0]);
describe('getUserCertificates', () => {
test('returns certificates list', async () => {
const certificates = await getUserCertificates();
expect(certificates.length).toBeGreaterThan(0);
});
test('returns certificates with correct fields', async () => {
const [certificate] = await getUserCertificates();
expect(certificate).toMatchObject(parsedCertificateMock);
});
});

View File

@ -1,64 +0,0 @@
import 'cadesplugin';
import 'console-mock';
import { isValidSystemSetup } from './isValidSystemSetup';
import { getSystemInfo } from './getSystemInfo';
import { _isSupportedCadesVersion } from '../helpers/_isSupportedCadesVersion';
import { _isSupportedCSPVersion } from '../helpers/_isSupportedCSPVersion';
jest.mock('./getSystemInfo', () => ({ getSystemInfo: jest.fn() }));
jest.mock('../helpers/_isSupportedCadesVersion', () => ({ _isSupportedCadesVersion: jest.fn() }));
jest.mock('../helpers/_isSupportedCSPVersion', () => ({ _isSupportedCSPVersion: jest.fn() }));
beforeEach(() => {
(getSystemInfo as jest.Mock).mockClear();
(_isSupportedCadesVersion as jest.Mock).mockClear();
(_isSupportedCSPVersion as jest.Mock).mockClear();
});
describe('isValidSystemSetup', () => {
(getSystemInfo as jest.Mock).mockImplementation(() => ({
cadesVersion: '2.0.13771',
cspVersion: '4.0.9971',
}));
(_isSupportedCadesVersion as jest.Mock).mockImplementation(() => true);
(_isSupportedCSPVersion as jest.Mock).mockImplementation(() => true);
describe('positive scenario', () => {
test("calls getSystemInfo to verify that it's possible", async () => {
await isValidSystemSetup();
expect(getSystemInfo).toHaveBeenCalledTimes(1);
});
test('checks for validity using separate external helpers', async () => {
await isValidSystemSetup();
expect(_isSupportedCadesVersion).toHaveBeenCalledTimes(1);
expect(_isSupportedCSPVersion).toHaveBeenCalledTimes(1);
});
});
describe('negative scenario', () => {
test('throws error from getSystemInfo', async () => {
const errorMessage = 'Какая-то синтаксическая ошибка';
const vendorErrorMessage = 'Произошла ошибка из-за какой-то проблемы';
(getSystemInfo as jest.Mock).mockImplementationOnce(() => Promise.reject(new Error(errorMessage)));
(window.cadesplugin.getLastError as jest.Mock).mockImplementationOnce(() => new Error(vendorErrorMessage));
await expect(isValidSystemSetup()).rejects.toThrowError(vendorErrorMessage);
});
test('throws error if cades version is unsupported', async () => {
(_isSupportedCadesVersion as jest.Mock).mockImplementationOnce(() => false);
await expect(isValidSystemSetup()).rejects.toThrowError('Не поддерживаемая версия плагина');
});
test('throws error if CSP version is unsupported', async () => {
(_isSupportedCSPVersion as jest.Mock).mockImplementationOnce(() => false);
await expect(isValidSystemSetup()).rejects.toThrowError('Не поддерживаемая версия CSP');
});
});
});

View File

@ -1,45 +0,0 @@
import 'cadesplugin';
import 'console-mock';
import { _afterPluginsLoaded } from './_afterPluginsLoaded';
const cadesPluginMock = window.cadesplugin;
describe('_afterPluginsLoaded', () => {
beforeEach(() => {
window.cadesplugin = cadesPluginMock;
});
test('sets log level on a vendor library', async () => {
const wrappedMethod = _afterPluginsLoaded(jest.fn());
await wrappedMethod();
expect(window.cadesplugin.set_log_level).toBeCalled();
});
test("throws Error when Cades plugin isn't available", async () => {
const wrappedMethod = _afterPluginsLoaded(jest.fn());
window.cadesplugin = Promise.reject();
await expect(wrappedMethod()).rejects.toThrow();
});
test('throws Error from Cades plugin if it occurs', async () => {
const wrappedMethod = _afterPluginsLoaded(jest.fn());
const vendorErrorMessage = 'Что-то пошло не так, и об этом стоит знать пользователю';
window.cadesplugin = Promise.reject(new Error(vendorErrorMessage));
await expect(wrappedMethod()).rejects.toThrowError(vendorErrorMessage);
});
test('calls method body when invoked', async () => {
const methodBody = jest.fn();
const wrappedMethod = _afterPluginsLoaded(methodBody);
await wrappedMethod();
expect(methodBody).toBeCalled();
});
});

File diff suppressed because it is too large Load Diff