mirror of
				https://github.com/crypto-pro-web/crypto-pro-js.git
				synced 2025-10-31 06:13:22 +03:00 
			
		
		
		
	Merge remote-tracking branch 'cosign/master' into custom
# Conflicts: # dist/crypto-pro.d.ts # dist/crypto-pro.js # dist/crypto-pro.js.map # dist/crypto-pro.min.js # dist/crypto-pro.min.js.map # lib/crypto-pro.d.ts # lib/crypto-pro.js # lib/crypto-pro.js.map # package-lock.json # package.json
This commit is contained in:
		
						commit
						da4763661c
					
				
							
								
								
									
										8
									
								
								dist/api/addAttachedSignature.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								dist/api/addAttachedSignature.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | ||||
| /** | ||||
|  * Добавляет присоединенную подпись к подписанному сообщению по отпечатку сертификата | ||||
|  * | ||||
|  * @param thumbprint - отпечаток сертификата | ||||
|  * @param signedMessage - подписанное сообщение | ||||
|  * @returns подпись в формате PKCS#7 | ||||
|  */ | ||||
| export declare const addAttachedSignature: (thumbprint: string, signedMessage: string | ArrayBuffer) => Promise<string>; | ||||
							
								
								
									
										9
									
								
								dist/api/addDetachedSignature.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								dist/api/addDetachedSignature.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | ||||
| /** | ||||
|  * Добавляет отсоединенную подпись хеша к подписанному сообщению по отпечатку сертификата | ||||
|  * | ||||
|  * @param thumbprint - отпечаток сертификата | ||||
|  * @param signedMessage - подписанное сообщение | ||||
|  * @param messageHash - хеш подписываемого сообщения, сгенерированный по ГОСТ Р 34.11-2012 256 бит | ||||
|  * @returns подпись в формате PKCS#7 | ||||
|  */ | ||||
| export declare const addDetachedSignature: (thumbprint: string, signedMessage: string | ArrayBuffer, messageHash: string) => Promise<string>; | ||||
							
								
								
									
										2
									
								
								dist/api/index.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								dist/api/index.d.ts
									
									
									
									
										vendored
									
									
								
							| @ -5,6 +5,8 @@ export * from './isValidSystemSetup'; | ||||
| export * from './createSignature'; | ||||
| export * from './createXMLSignature'; | ||||
| export * from './createDetachedSignature'; | ||||
| export * from './addDetachedSignature'; | ||||
| export * from './createAttachedSignature'; | ||||
| export * from './addAttachedSignature'; | ||||
| export * from './createHash'; | ||||
| export * from './certificate'; | ||||
|  | ||||
							
								
								
									
										7
									
								
								dist/crypto-pro.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								dist/crypto-pro.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | ||||
| // Type definitions for crypto-pro 2.2.2
 | ||||
| // Project: crypto-pro
 | ||||
| // Definitions by: Vitalii Goma https://github.com/vgoma
 | ||||
| 
 | ||||
| export as namespace cryptoPro; | ||||
| 
 | ||||
| export * from './api'; | ||||
							
								
								
									
										5379
									
								
								dist/crypto-pro.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5379
									
								
								dist/crypto-pro.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1
									
								
								dist/crypto-pro.js.map
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								dist/crypto-pro.js.map
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										9
									
								
								dist/crypto-pro.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								dist/crypto-pro.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										1
									
								
								dist/crypto-pro.min.js.map
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								dist/crypto-pro.min.js.map
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										8
									
								
								lib/api/addAttachedSignature.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								lib/api/addAttachedSignature.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | ||||
| /** | ||||
|  * Добавляет присоединенную подпись к подписанному сообщению по отпечатку сертификата | ||||
|  * | ||||
|  * @param thumbprint - отпечаток сертификата | ||||
|  * @param signedMessage - подписанное сообщение | ||||
|  * @returns подпись в формате PKCS#7 | ||||
|  */ | ||||
| export declare const addAttachedSignature: (thumbprint: string, signedMessage: string | ArrayBuffer) => Promise<string>; | ||||
							
								
								
									
										9
									
								
								lib/api/addDetachedSignature.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								lib/api/addDetachedSignature.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | ||||
| /** | ||||
|  * Добавляет отсоединенную подпись хеша к подписанному сообщению по отпечатку сертификата | ||||
|  * | ||||
|  * @param thumbprint - отпечаток сертификата | ||||
|  * @param signedMessage - подписанное сообщение | ||||
|  * @param messageHash - хеш подписываемого сообщения, сгенерированный по ГОСТ Р 34.11-2012 256 бит | ||||
|  * @returns подпись в формате PKCS#7 | ||||
|  */ | ||||
| export declare const addDetachedSignature: (thumbprint: string, signedMessage: string | ArrayBuffer, messageHash: string) => Promise<string>; | ||||
							
								
								
									
										2
									
								
								lib/api/index.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								lib/api/index.d.ts
									
									
									
									
										vendored
									
									
								
							| @ -5,6 +5,8 @@ export * from './isValidSystemSetup'; | ||||
| export * from './createSignature'; | ||||
| export * from './createXMLSignature'; | ||||
| export * from './createDetachedSignature'; | ||||
| export * from './addDetachedSignature'; | ||||
| export * from './createAttachedSignature'; | ||||
| export * from './addAttachedSignature'; | ||||
| export * from './createHash'; | ||||
| export * from './certificate'; | ||||
|  | ||||
							
								
								
									
										5
									
								
								lib/crypto-pro.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								lib/crypto-pro.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | ||||
| // Type definitions for crypto-pro 2.2.2
 | ||||
| // Project: crypto-pro
 | ||||
| // Definitions by: Vitalii Goma https://github.com/vgoma
 | ||||
| 
 | ||||
| export * from './api'; | ||||
							
								
								
									
										3000
									
								
								lib/crypto-pro.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3000
									
								
								lib/crypto-pro.js
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1
									
								
								lib/crypto-pro.js.map
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								lib/crypto-pro.js.map
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										89
									
								
								src/api/addAttachedSignature.test.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								src/api/addAttachedSignature.test.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,89 @@ | ||||
| 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'); | ||||
|   }); | ||||
| }); | ||||
							
								
								
									
										87
									
								
								src/api/addAttachedSignature.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								src/api/addAttachedSignature.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,87 @@ | ||||
| import { CADESCOM_AUTHENTICATED_ATTRIBUTE_SIGNING_TIME } from '../constants'; | ||||
| import { _afterPluginsLoaded } from '../helpers/_afterPluginsLoaded'; | ||||
| import { _extractMeaningfulErrorMessage } from '../helpers/_extractMeaningfulErrorMessage'; | ||||
| import { __cadesAsyncToken__, __createCadesPluginObject__, _generateCadesFn } from '../helpers/_generateCadesFn'; | ||||
| import { _getCadesCert } from '../helpers/_getCadesCert'; | ||||
| import { _getDateObj } from '../helpers/_getDateObj'; | ||||
| 
 | ||||
| /** | ||||
|  * Добавляет присоединенную подпись к подписанному сообщению по отпечатку сертификата | ||||
|  * | ||||
|  * @param thumbprint - отпечаток сертификата | ||||
|  * @param signedMessage - подписанное сообщение | ||||
|  * @returns подпись в формате PKCS#7 | ||||
|  */ | ||||
| export const addAttachedSignature = _afterPluginsLoaded( | ||||
|   async (thumbprint: string, signedMessage: string | ArrayBuffer): Promise<string> => { | ||||
|     const { cadesplugin } = window; | ||||
|     const cadesCertificate = await _getCadesCert(thumbprint); | ||||
| 
 | ||||
|     return eval( | ||||
|       _generateCadesFn(function addAttachedSignature(): string { | ||||
|         let cadesAttrs; | ||||
|         let cadesSignedData; | ||||
|         let cadesSigner; | ||||
| 
 | ||||
|         try { | ||||
|           cadesAttrs = __cadesAsyncToken__ + __createCadesPluginObject__('CADESCOM.CPAttribute'); | ||||
|           cadesSignedData = __cadesAsyncToken__ + __createCadesPluginObject__('CAdESCOM.CadesSignedData'); | ||||
|           cadesSigner = __cadesAsyncToken__ + __createCadesPluginObject__('CAdESCOM.CPSigner'); | ||||
|         } catch (error) { | ||||
|           console.error(error); | ||||
| 
 | ||||
|           throw new Error(_extractMeaningfulErrorMessage(error) || 'Ошибка при инициализации подписи'); | ||||
|         } | ||||
| 
 | ||||
|         const currentTime = _getDateObj(new Date()); | ||||
| 
 | ||||
|         try { | ||||
|           void (__cadesAsyncToken__ + cadesAttrs.propset_Name(CADESCOM_AUTHENTICATED_ATTRIBUTE_SIGNING_TIME)); | ||||
|           void (__cadesAsyncToken__ + cadesAttrs.propset_Value(currentTime)); | ||||
|         } catch (error) { | ||||
|           console.error(error); | ||||
| 
 | ||||
|           throw new Error(_extractMeaningfulErrorMessage(error) || 'Ошибка при установке времени подписи'); | ||||
|         } | ||||
| 
 | ||||
|         let messageBase64; | ||||
| 
 | ||||
|         try { | ||||
|           messageBase64 = Buffer.from(signedMessage).toString('base64'); | ||||
|         } catch (error) { | ||||
|           console.error(error); | ||||
| 
 | ||||
|           throw new Error('Ошибка при преобразовании сообщения в Base64'); | ||||
|         } | ||||
| 
 | ||||
|         let cadesAuthAttrs; | ||||
| 
 | ||||
|         try { | ||||
|           void (__cadesAsyncToken__ + cadesSigner.propset_Certificate(cadesCertificate)); | ||||
|           cadesAuthAttrs = __cadesAsyncToken__ + cadesSigner.AuthenticatedAttributes2; | ||||
|           void (__cadesAsyncToken__ + cadesAuthAttrs.Add(cadesAttrs)); | ||||
|           void (__cadesAsyncToken__ + cadesSignedData.propset_ContentEncoding(cadesplugin.CADESCOM_BASE64_TO_BINARY)); | ||||
|           void (__cadesAsyncToken__ + cadesSignedData.propset_Content(messageBase64)); | ||||
|           void (__cadesAsyncToken__ + cadesSigner.propset_Options(cadesplugin.CAPICOM_CERTIFICATE_INCLUDE_WHOLE_CHAIN)); | ||||
|         } catch (error) { | ||||
|           console.error(error); | ||||
| 
 | ||||
|           throw new Error(_extractMeaningfulErrorMessage(error) || 'Ошибка при указании данных для подписи'); | ||||
|         } | ||||
| 
 | ||||
|         let signature: string; | ||||
| 
 | ||||
|         try { | ||||
|           void (__cadesAsyncToken__ + cadesSignedData.VerifyCades(signedMessage, cadesplugin.CADESCOM_PKCS7_TYPE)); | ||||
|           signature = __cadesAsyncToken__ + cadesSignedData.CoSignCades(cadesSigner, cadesplugin.CADESCOM_PKCS7_TYPE); | ||||
|         } catch (error) { | ||||
|           console.error(error); | ||||
| 
 | ||||
|           throw new Error(_extractMeaningfulErrorMessage(error) || 'Ошибка при подписании данных'); | ||||
|         } | ||||
| 
 | ||||
|         return signature; | ||||
|       }), | ||||
|     ); | ||||
|   }, | ||||
| ); | ||||
							
								
								
									
										112
									
								
								src/api/addDetachedSignature.test.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								src/api/addDetachedSignature.test.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,112 @@ | ||||
| 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; | ||||
|   }); | ||||
| }); | ||||
							
								
								
									
										95
									
								
								src/api/addDetachedSignature.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								src/api/addDetachedSignature.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,95 @@ | ||||
| import { CADESCOM_AUTHENTICATED_ATTRIBUTE_SIGNING_TIME } from '../constants'; | ||||
| import { _afterPluginsLoaded } from '../helpers/_afterPluginsLoaded'; | ||||
| import { _extractMeaningfulErrorMessage } from '../helpers/_extractMeaningfulErrorMessage'; | ||||
| import { __cadesAsyncToken__, __createCadesPluginObject__, _generateCadesFn } from '../helpers/_generateCadesFn'; | ||||
| import { _getCadesCert } from '../helpers/_getCadesCert'; | ||||
| import { _getDateObj } from '../helpers/_getDateObj'; | ||||
| 
 | ||||
| /** | ||||
|  * Добавляет отсоединенную подпись хеша к подписанному сообщению по отпечатку сертификата | ||||
|  * | ||||
|  * @param thumbprint - отпечаток сертификата | ||||
|  * @param signedMessage - подписанное сообщение | ||||
|  * @param messageHash - хеш подписываемого сообщения, сгенерированный по ГОСТ Р 34.11-2012 256 бит | ||||
|  * @returns подпись в формате PKCS#7 | ||||
|  */ | ||||
| export const addDetachedSignature = _afterPluginsLoaded( | ||||
|   async (thumbprint: string, signedMessage: string | ArrayBuffer, messageHash: string): Promise<string> => { | ||||
|     const { cadesplugin } = window; | ||||
|     const cadesCertificate = await _getCadesCert(thumbprint); | ||||
| 
 | ||||
|     return eval( | ||||
|       _generateCadesFn(function addDetachedSignature(): string { | ||||
|         let cadesAttrs; | ||||
|         let cadesHashedData; | ||||
|         let cadesSignedData; | ||||
|         let cadesSigner; | ||||
| 
 | ||||
|         try { | ||||
|           cadesAttrs = __cadesAsyncToken__ + __createCadesPluginObject__('CADESCOM.CPAttribute'); | ||||
|           cadesHashedData = __cadesAsyncToken__ + __createCadesPluginObject__('CAdESCOM.HashedData'); | ||||
|           cadesSignedData = __cadesAsyncToken__ + __createCadesPluginObject__('CAdESCOM.CadesSignedData'); | ||||
|           cadesSigner = __cadesAsyncToken__ + __createCadesPluginObject__('CAdESCOM.CPSigner'); | ||||
|         } catch (error) { | ||||
|           console.error(error); | ||||
| 
 | ||||
|           throw new Error(_extractMeaningfulErrorMessage(error) || 'Ошибка при инициализации подписи'); | ||||
|         } | ||||
| 
 | ||||
|         const currentTime = _getDateObj(new Date()); | ||||
| 
 | ||||
|         try { | ||||
|           void (__cadesAsyncToken__ + cadesAttrs.propset_Name(CADESCOM_AUTHENTICATED_ATTRIBUTE_SIGNING_TIME)); | ||||
|           void (__cadesAsyncToken__ + cadesAttrs.propset_Value(currentTime)); | ||||
|         } catch (error) { | ||||
|           console.error(error); | ||||
| 
 | ||||
|           throw new Error(_extractMeaningfulErrorMessage(error) || 'Ошибка при установке времени подписи'); | ||||
|         } | ||||
| 
 | ||||
|         let cadesAuthAttrs; | ||||
| 
 | ||||
|         try { | ||||
|           void (__cadesAsyncToken__ + cadesSigner.propset_Certificate(cadesCertificate)); | ||||
|           cadesAuthAttrs = __cadesAsyncToken__ + cadesSigner.AuthenticatedAttributes2; | ||||
|           void (__cadesAsyncToken__ + cadesAuthAttrs.Add(cadesAttrs)); | ||||
|           void (__cadesAsyncToken__ + cadesSigner.propset_Options(cadesplugin.CAPICOM_CERTIFICATE_INCLUDE_WHOLE_CHAIN)); | ||||
|         } catch (error) { | ||||
|           console.error(error); | ||||
| 
 | ||||
|           throw new Error(_extractMeaningfulErrorMessage(error) || 'Ошибка при установке сертификата'); | ||||
|         } | ||||
| 
 | ||||
|         try { | ||||
|           void ( | ||||
|             __cadesAsyncToken__ + | ||||
|             cadesHashedData.propset_Algorithm(cadesplugin.CADESCOM_HASH_ALGORITHM_CP_GOST_3411_2012_256) | ||||
|           ); | ||||
|           void (__cadesAsyncToken__ + cadesHashedData.SetHashValue(messageHash)); | ||||
|         } catch (error) { | ||||
|           console.error(error); | ||||
| 
 | ||||
|           throw new Error(_extractMeaningfulErrorMessage(error) || 'Ошибка при установке хеша'); | ||||
|         } | ||||
| 
 | ||||
|         let signature: string; | ||||
| 
 | ||||
|         try { | ||||
|           void ( | ||||
|             __cadesAsyncToken__ + | ||||
|             cadesSignedData.VerifyHash(cadesHashedData, signedMessage, cadesplugin.CADESCOM_PKCS7_TYPE) | ||||
|           ); | ||||
|           signature = | ||||
|             __cadesAsyncToken__ + | ||||
|             cadesSignedData.CoSignHash(cadesHashedData, cadesSigner, cadesplugin.CADESCOM_PKCS7_TYPE); | ||||
|         } catch (error) { | ||||
|           console.error(error); | ||||
| 
 | ||||
|           throw new Error(_extractMeaningfulErrorMessage(error) || 'Ошибка при подписании данных'); | ||||
|         } | ||||
| 
 | ||||
|         return signature; | ||||
|       }), | ||||
|     ); | ||||
|   }, | ||||
| ); | ||||
							
								
								
									
										60
									
								
								src/api/getAllUserCertificates.test.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								src/api/getAllUserCertificates.test.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,60 @@ | ||||
| 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); | ||||
|   }); | ||||
| }); | ||||
							
								
								
									
										99
									
								
								src/api/getAllUserCertificates.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								src/api/getAllUserCertificates.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,99 @@ | ||||
| import { CadesCertificate, Certificate } from './certificate'; | ||||
| import { _afterPluginsLoaded } from '../helpers/_afterPluginsLoaded'; | ||||
| import { _extractCommonName } from '../helpers/_extractCommonName'; | ||||
| import { _extractMeaningfulErrorMessage } from '../helpers/_extractMeaningfulErrorMessage'; | ||||
| import { __cadesAsyncToken__, __createCadesPluginObject__, _generateCadesFn } from '../helpers/_generateCadesFn'; | ||||
| 
 | ||||
| let certificatesCache: Certificate[]; | ||||
| 
 | ||||
| /** | ||||
|  * Возвращает все сертификаты без фильтрации по дате и наличию приватного ключа | ||||
|  * | ||||
|  * @param resetCache = false - позволяет сбросить кэш ранее полученных сертификатов | ||||
|  * @returns список сертификатов | ||||
|  */ | ||||
| export const getAllUserCertificates = _afterPluginsLoaded((resetCache: boolean = false): Certificate[] => { | ||||
|   const { cadesplugin } = window; | ||||
| 
 | ||||
|   if (!resetCache && certificatesCache) { | ||||
|     return certificatesCache; | ||||
|   } | ||||
| 
 | ||||
|   return eval( | ||||
|     _generateCadesFn(function getAllUserCertificates(): Certificate[] { | ||||
|       let cadesStore; | ||||
| 
 | ||||
|       try { | ||||
|         cadesStore = __cadesAsyncToken__ + __createCadesPluginObject__('CAdESCOM.Store'); | ||||
|       } catch (error) { | ||||
|         console.error(error); | ||||
| 
 | ||||
|         throw new Error(_extractMeaningfulErrorMessage(error) || 'Ошибка при попытке доступа к хранилищу'); | ||||
|       } | ||||
| 
 | ||||
|       try { | ||||
|         void ( | ||||
|           __cadesAsyncToken__ + | ||||
|           cadesStore.Open( | ||||
|             cadesplugin.CAPICOM_CURRENT_USER_STORE, | ||||
|             cadesplugin.CAPICOM_MY_STORE, | ||||
|             cadesplugin.CAPICOM_STORE_OPEN_MAXIMUM_ALLOWED, | ||||
|           ) | ||||
|         ); | ||||
|       } catch (error) { | ||||
|         console.error(error); | ||||
| 
 | ||||
|         throw new Error(_extractMeaningfulErrorMessage(error) || 'Ошибка при открытии хранилища'); | ||||
|       } | ||||
| 
 | ||||
|       let cadesCertificates; | ||||
|       let cadesCertificatesCount; | ||||
| 
 | ||||
|       try { | ||||
|         cadesCertificates = __cadesAsyncToken__ + cadesStore.Certificates; | ||||
|         cadesCertificatesCount = __cadesAsyncToken__ + cadesCertificates.Count; | ||||
|       } catch (error) { | ||||
|         console.error(error); | ||||
| 
 | ||||
|         throw new Error(_extractMeaningfulErrorMessage(error) || 'Ошибка получения списка сертификатов'); | ||||
|       } | ||||
| 
 | ||||
|       if (!cadesCertificatesCount) { | ||||
|         throw new Error('Нет доступных сертификатов'); | ||||
|       } | ||||
| 
 | ||||
|       const certificateList: Certificate[] = []; | ||||
| 
 | ||||
|       try { | ||||
|         while (cadesCertificatesCount) { | ||||
|           const cadesCertificate: CadesCertificate = | ||||
|             __cadesAsyncToken__ + cadesCertificates.Item(cadesCertificatesCount); | ||||
| 
 | ||||
|           certificateList.push( | ||||
|             new Certificate( | ||||
|               cadesCertificate, | ||||
|               _extractCommonName(__cadesAsyncToken__ + cadesCertificate.SubjectName), | ||||
|               __cadesAsyncToken__ + cadesCertificate.IssuerName, | ||||
|               __cadesAsyncToken__ + cadesCertificate.SubjectName, | ||||
|               __cadesAsyncToken__ + cadesCertificate.Thumbprint, | ||||
|               __cadesAsyncToken__ + cadesCertificate.ValidFromDate, | ||||
|               __cadesAsyncToken__ + cadesCertificate.ValidToDate, | ||||
|             ), | ||||
|           ); | ||||
| 
 | ||||
|           cadesCertificatesCount--; | ||||
|         } | ||||
|       } catch (error) { | ||||
|         console.error(error); | ||||
| 
 | ||||
|         throw new Error(_extractMeaningfulErrorMessage(error) || 'Ошибка обработки сертификатов'); | ||||
|       } | ||||
| 
 | ||||
|       cadesStore.Close(); | ||||
| 
 | ||||
|       certificatesCache = certificateList; | ||||
| 
 | ||||
|       return certificatesCache; | ||||
|     }), | ||||
|   ); | ||||
| }); | ||||
							
								
								
									
										26
									
								
								src/api/getCspVersion.test.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/api/getCspVersion.test.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,26 @@ | ||||
| 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'); | ||||
|   }); | ||||
| }); | ||||
							
								
								
									
										40
									
								
								src/api/getCspVersion.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								src/api/getCspVersion.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,40 @@ | ||||
| import { _afterPluginsLoaded } from '../helpers/_afterPluginsLoaded'; | ||||
| import { _extractMeaningfulErrorMessage } from '../helpers/_extractMeaningfulErrorMessage'; | ||||
| import { | ||||
|   __cadesAsyncToken__, | ||||
|   __createCadesPluginObject__, | ||||
|   _generateCadesFn, | ||||
| } from '../helpers/_generateCadesFn'; | ||||
| 
 | ||||
| /** | ||||
|  * Предоставляет информацию о системе | ||||
|  * | ||||
|  * @returns информацию о CSP | ||||
|  */ | ||||
| export const getCspVersion = _afterPluginsLoaded((): string => { | ||||
|   let cspVersion = null; | ||||
| 
 | ||||
|   return eval( | ||||
|     _generateCadesFn(function getCspVersion(): string { | ||||
|       let cadesAbout; | ||||
| 
 | ||||
|       try { | ||||
|         cadesAbout = | ||||
|           __cadesAsyncToken__ + __createCadesPluginObject__('CAdESCOM.About'); | ||||
| 
 | ||||
|         cspVersion = __cadesAsyncToken__ + cadesAbout.CSPVersion(); | ||||
| 
 | ||||
|         cspVersion = __cadesAsyncToken__ + cspVersion.toString(); | ||||
|       } catch (error) { | ||||
|         console.error(error); | ||||
| 
 | ||||
|         throw new Error( | ||||
|           _extractMeaningfulErrorMessage(error) || | ||||
|             'Ошибка при получении версии системы', | ||||
|         ); | ||||
|       } | ||||
| 
 | ||||
|       return cspVersion; | ||||
|     }), | ||||
|   ); | ||||
| }); | ||||
							
								
								
									
										35
									
								
								src/api/getPluginVersion.test.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								src/api/getPluginVersion.test.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,35 @@ | ||||
| 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'); | ||||
|   }); | ||||
| }); | ||||
							
								
								
									
										44
									
								
								src/api/getPluginVersion.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								src/api/getPluginVersion.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,44 @@ | ||||
| import { _afterPluginsLoaded } from '../helpers/_afterPluginsLoaded'; | ||||
| import { | ||||
|   __cadesAsyncToken__, | ||||
|   __createCadesPluginObject__, | ||||
|   _generateCadesFn, | ||||
| } from '../helpers/_generateCadesFn'; | ||||
| import { _extractMeaningfulErrorMessage } from '../helpers/_extractMeaningfulErrorMessage'; | ||||
| 
 | ||||
| /** | ||||
|  * Предоставляет информацию о системе | ||||
|  * | ||||
|  * @returns информацию о плагине | ||||
|  */ | ||||
| export const getPluginVersion = _afterPluginsLoaded((): string => { | ||||
|   let cadesVersion = null; | ||||
| 
 | ||||
|   return eval( | ||||
|     _generateCadesFn(function getPluginVersion(): string { | ||||
|       let cadesAbout; | ||||
| 
 | ||||
|       try { | ||||
|         cadesAbout = | ||||
|           __cadesAsyncToken__ + __createCadesPluginObject__('CAdESCOM.About'); | ||||
| 
 | ||||
|         cadesVersion = __cadesAsyncToken__ + cadesAbout.PluginVersion; | ||||
| 
 | ||||
|         if (!cadesVersion) { | ||||
|           cadesVersion = __cadesAsyncToken__ + cadesAbout.Version; | ||||
|         } | ||||
| 
 | ||||
|         cadesVersion = __cadesAsyncToken__ + cadesVersion.toString(); | ||||
|       } catch (error) { | ||||
|         console.error(error); | ||||
| 
 | ||||
|         throw new Error( | ||||
|           _extractMeaningfulErrorMessage(error) || | ||||
|             'Ошибка при получении информации о плагине', | ||||
|         ); | ||||
|       } | ||||
| 
 | ||||
|       return cadesVersion; | ||||
|     }), | ||||
|   ); | ||||
| }); | ||||
| @ -1,10 +1,15 @@ | ||||
| export * from './getCertificate'; | ||||
| export * from './getUserCertificates'; | ||||
| export * from './getAllUserCertificates'; | ||||
| export * from './getSystemInfo'; | ||||
| export * from './isValidSystemSetup'; | ||||
| export * from './createSignature'; | ||||
| export * from './createXMLSignature'; | ||||
| export * from './createDetachedSignature'; | ||||
| export * from './addDetachedSignature'; | ||||
| export * from './createAttachedSignature'; | ||||
| export * from './addAttachedSignature'; | ||||
| export * from './createHash'; | ||||
| export * from './certificate'; | ||||
| export * from './getCspVersion'; | ||||
| export * from './getPluginVersion'; | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user