import { Component, Input, OnInit } from '@angular/core'; import { LoadingController, ModalController } from '@ionic/angular'; import { catchError, tap } from 'rxjs/operators'; import { of } from 'rxjs'; import { HttpClient } from '@angular/common/http'; import { NotificationService } from '../notification.service'; import { TranslateService } from '@ngx-translate/core'; import { ActionsService } from '../actions.service'; import { SignaturesContentService } from '../signatures.service'; import { AuthService } from '../auth.service'; import { FunctionsService } from '../functions.service'; @Component({ selector: 'signature-method-modal', templateUrl: 'signature-method-modal.component.html', styleUrls: ['./signature-method-modal.component.scss'] }) export class SignatureMethodModalComponent implements OnInit { filters: any = { // onlySmartcards: false, expired: false, // subjectDNMatch: 'apple', // subjectDNMatch: new RegExp(/apple/), // issuerDNMatch: 'demo', // issuerDNMatch: new RegExp(/demo/), // keyUsage: ['digitalSignature'], onlyWithPrivateKey: true }; provider: any = null; cert: any = null; certPem: any = null; privateKey: any = null; signature: string; certificate: any; signatureLength: any = null; @Input() note: string; @Input() signatureMode: string; constructor( public modalController: ModalController, public http: HttpClient, public translate: TranslateService, public notificationService: NotificationService, public loadingController: LoadingController, public signaturesService: SignaturesContentService, public actionsService: ActionsService, private functionsService: FunctionsService, public authService: AuthService ) { } ngOnInit(): void { const signatureModeData = this.authService.signatureRoles.filter((mode: any) => mode.id === this.signatureMode)[0]; if (!this.functionsService.empty(signatureModeData.issuer)) { this.filters.issuerDNMatch = new RegExp(signatureModeData.issuer, 'i'); } } async continueSignature(certData: any) { this.loadingController.create({ message: this.translate.instant('lang.processing'), spinner: 'dots' }).then(async (load: HTMLIonLoadingElement) => { load.present(); try { this.provider = await certData.detail.server.getCrypto(certData.detail.providerId); this.cert = await this.provider.certStorage.getItem(certData.detail.certificateId); this.certPem = await this.provider.certStorage.exportCert('pem', this.cert); this.privateKey = await this.provider.keyStorage.getItem(certData.detail.privateKeyId); } catch (e) { this.notificationService.error('lang.fortifyReadException'); load.dismiss(); this.modalController.dismiss(false); return; } this.certificate = { certificate: this.certPem }; const result = await this.sendAndSign(); load.dismiss(); this.modalController.dismiss(result); }); } signDocument(hashDocument: any, eSignatureLength: any, signatureFieldName: any, tmpUniqueId: string) { console.log(hashDocument); console.log(eSignatureLength); return new Promise(async (resolve) => { const alg = { name: this.privateKey.algorithm.name, hash: 'SHA-256', }; const hashDocumentHex = this.fromHex(hashDocument); console.log('hashDocumentHex', hashDocumentHex); let hashSignature: any; try { hashSignature = await this.provider.subtle.sign(alg, this.privateKey, hashDocumentHex); } catch (e) { this.notificationService.error('lang.fortifyReadException'); resolve(false); return of(false); } console.log('hashSignature', hashSignature); const signatures: any[] = []; if (this.signaturesService.currentAction > 0) { for (let index = 1; index <= this.signaturesService.totalPage; index++) { if (this.signaturesService.datesContent[index]) { this.signaturesService.datesContent[index].forEach((date: any) => { signatures.push( { 'encodedImage': date.content.replace('data:image/svg+xml;base64,', ''), 'width': date.width, 'positionX': date.positionX, 'positionY': date.positionY, 'type': 'SVG', 'page': index, } ); }); } if (this.signaturesService.signaturesContent[index]) { this.signaturesService.signaturesContent[index].forEach((signature: any) => { signatures.push( { 'encodedImage': signature.encodedSignature, 'width': signature.width, 'positionX': signature.positionX, 'positionY': signature.positionY, 'type': 'PNG', 'page': index, } ); }); } if (this.signaturesService.notesContent[index]) { this.signaturesService.notesContent[index].forEach((noteItem: any) => { signatures.push( { 'encodedImage': noteItem.fullPath.replace('data:image/png;base64,', ''), 'width': noteItem.width, 'positionX': noteItem.positionX, 'positionY': noteItem.positionY, 'type': 'PNG', 'page': index, } ); }); } } } const objEsign = { signatures : signatures, certificate: this.certPem, hashSignature: this.toHex(hashSignature), signatureContentLength: eSignatureLength, signatureFieldName: signatureFieldName, tmpUniqueId: tmpUniqueId, }; this.http.put('../rest/documents/' + this.signaturesService.mainDocumentId + '/actions/' + this.signaturesService.currentAction, objEsign) .pipe( tap(() => { resolve(true); }), catchError((err: any) => { if (err.error.newSignatureLength !== undefined) { this.signatureLength = err.error.newSignatureLength; resolve(false); } else { this.notificationService.handleErrors(err); resolve(null); } return of(false); }) ).subscribe(); }); } async sendAndSign() { let allSignaturesComplete: boolean = false; let res: any = {}; while (!allSignaturesComplete) { let signDocComplete: any = false; while (signDocComplete === false) { console.log('recupération hashDocument'); res = await this.actionsService.sendDocument(this.note, this.certificate, this.signatureLength, res.tmpUniqueId); console.log('res hashDocument', res); if (res === null) { return false; } else if (res !== false) { console.log('signature document'); signDocComplete = await this.signDocument(res.hashDocument, res.signatureContentLength, res.signatureFieldName, res.tmpUniqueId); if (signDocComplete) { this.signaturesService.signaturesContent.shift(); allSignaturesComplete = this.signaturesService.signaturesContent.length === 0; res = {}; } } } } return allSignaturesComplete; } cancelSign() { this.modalController.dismiss(false); } toHex(buffer: any) { const buf = new Uint8Array(buffer), splitter = '', res = [], len = buf.length; for (let i = 0; i < len; i++) { const char = buf[i].toString(16); res.push(char.length === 1 ? '0' + char : char); } return res.join(splitter); } fromHex(hexString: any) { const res = new Uint8Array(hexString.length / 2); for (let i = 0; i < hexString.length; i = i + 2) { const c = hexString.slice(i, i + 2); res[i / 2] = parseInt(c, 16); } return res.buffer; } }