From 46f940d91c8ae438833c2cb49529e70cb08d60f7 Mon Sep 17 00:00:00 2001 From: Alex ORLUC <alex.orluc@maarch.org> Date: Thu, 10 Dec 2020 12:35:19 +0100 Subject: [PATCH] FEAT #14565 TIME 2:30 WIP front rgs sign --- .../controllers/DocumentController.php | 6 +- .../app/document/document.component.ts | 6 + src/frontend/app/service/actions.service.ts | 103 +++++++++++++++ .../signature-method-modal.component.ts | 125 ++++++++++++++---- 4 files changed, 211 insertions(+), 29 deletions(-) create mode 100644 src/frontend/app/service/actions.service.ts diff --git a/src/app/document/controllers/DocumentController.php b/src/app/document/controllers/DocumentController.php index b18661bfbf..8644ba4c12 100755 --- a/src/app/document/controllers/DocumentController.php +++ b/src/app/document/controllers/DocumentController.php @@ -770,9 +770,9 @@ class DocumentController } elseif ($workflow['signature_mode'] == 'rgs_2stars' && !empty($body['hashSignature'])) { $return = CertificateSignatureController::signDocument([ 'id' => $args['id'], - 'certificate' => $args['certificate'], - 'signatureContentLength' => $args['signatureContentLength'], - 'hashSignature' => $args['hashSignature'] + 'certificate' => $body['certificate'], + 'signatureContentLength' => $body['signatureContentLength'], + 'hashSignature' => $body['hashSignature'] ]); if (!empty($return['errors'])) { return $response->withStatus(400)->withJson($return); diff --git a/src/frontend/app/document/document.component.ts b/src/frontend/app/document/document.component.ts index 7174e44c7a..a5e0ea5c5d 100755 --- a/src/frontend/app/document/document.component.ts +++ b/src/frontend/app/document/document.component.ts @@ -692,6 +692,12 @@ export class DocumentComponent implements OnInit { load.present(); const res = await this.sendDocument({ 'note': data.paragraph, 'certInfo': certInfo }); if (res) { + if (this.signaturesService.documentsList[this.signaturesService.indexDocumentsList] !== undefined) { + this.signaturesService.documentsList.splice(this.signaturesService.indexDocumentsList, 1); + if (this.signaturesService.documentsListCount.current > 0) { + this.signaturesService.documentsListCount.current--; + } + } const config: MatBottomSheetConfig = { disableClose: true, direction: 'ltr' diff --git a/src/frontend/app/service/actions.service.ts b/src/frontend/app/service/actions.service.ts new file mode 100644 index 0000000000..216579d063 --- /dev/null +++ b/src/frontend/app/service/actions.service.ts @@ -0,0 +1,103 @@ +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import { LatinisePipe } from 'ngx-pipes'; +import { tap, exhaustMap, catchError } from 'rxjs/operators'; +import { SignaturesContentService } from './signatures.service'; +import { NotificationService } from '../service/notification.service'; +import { of } from 'rxjs'; + +@Injectable({ + providedIn: 'root' +}) +export class ActionsService { + + constructor( + public http: HttpClient, + public translate: TranslateService, + private latinisePipe: LatinisePipe, + public notificationService: NotificationService, + public signaturesService: SignaturesContentService, + ) { } + + sendDocument(eSignature: any = null) { + return new Promise(async (resolve) => { + 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((note: any) => { + signatures.push( + { + 'encodedImage': note.fullPath.replace('data:image/png;base64,', ''), + 'width': note.width, + 'positionX': note.positionX, + 'positionY': note.positionY, + 'type': 'PNG', + 'page': index, + } + ); + }); + } + } + let data: any = {}; + + data.signatures = signatures; + + if (eSignature !== null) { + data = {...data, ...eSignature } + } + + this.http.put('../rest/documents/' + this.signaturesService.mainDocumentId + '/actions/' + this.signaturesService.currentAction, data) + .pipe( + tap((res: any) => { + if (eSignature !== null) { + const objSignData = { + hashDocument : res.dataToSign, + signatureContentLength : res.signatureContentLength + } + resolve(objSignData); + } else { + resolve(true); + } + }), + catchError((err: any) => { + this.notificationService.handleErrors(err); + resolve(false); + return of(false); + }) + ).subscribe(); + } else { + resolve(false); + } + }); + } +} diff --git a/src/frontend/app/service/signature-method/signature-method-modal.component.ts b/src/frontend/app/service/signature-method/signature-method-modal.component.ts index 0ce6cac380..54014c2d50 100644 --- a/src/frontend/app/service/signature-method/signature-method-modal.component.ts +++ b/src/frontend/app/service/signature-method/signature-method-modal.component.ts @@ -1,9 +1,12 @@ import { Component, Input, OnInit } from '@angular/core'; -import { ModalController } from '@ionic/angular'; -import {catchError, exhaustMap, tap} from 'rxjs/operators'; -import {of} from 'rxjs'; -import {HttpClient} from '@angular/common/http'; -import {NotificationService} from '../notification.service'; +import { LoadingController, ModalController } from '@ionic/angular'; +import { catchError, exhaustMap, 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'; @Component({ selector: 'signature-method-modal', @@ -28,12 +31,21 @@ export class SignatureMethodModalComponent implements OnInit { onlyWithPrivateKey: true }; + provider: any = null; + cert: any = null; + certPem: any = null; + privateKey: any = null; + signature: string; constructor( public modalController: ModalController, public http: HttpClient, + public translate: TranslateService, public notificationService: NotificationService, + public loadingController: LoadingController, + public signaturesService: SignaturesContentService, + public actionsService: ActionsService, ) { } ngOnInit(): void { @@ -67,22 +79,29 @@ export class SignatureMethodModalComponent implements OnInit { } async continueSignature(certData: any) { - console.log(certData); - - const provider = await certData.detail.server.getCrypto(certData.detail.providerId); + this.loadingController.create({ + message: this.translate.instant('lang.processing'), + spinner: 'dots' + }).then(async (load: HTMLIonLoadingElement) => { + load.present(); - const cert = await provider.certStorage.getItem(certData.detail.certificateId); - const certPem = await provider.certStorage.exportCert('pem', cert); - const privateKey = await provider.keyStorage.getItem(certData.detail.privateKeyId); + 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); - console.log('cert = '); - console.log(cert); - console.log('certPem = '); - console.log(certPem); - console.log('privateKey = '); - console.log(privateKey); + const certificate = { + certificate: this.certPem + } - await this.modalController.dismiss({certificate: certPem, certData: certData, privateKey: privateKey}); + const res: any = await this.actionsService.sendDocument(certificate); + console.log('sendDocument', res); + + if (res !== false) { + await this.signDocument(res.hashDocument, res.signatureContentLength); + } + load.dismiss(); + }); // this.http.post('../rest/testFortify?action=start', {certificate: certPem}).pipe( // tap(async (dataToSign: any) => { @@ -105,17 +124,71 @@ export class SignatureMethodModalComponent implements OnInit { // ).subscribe(); } + signDocument(hashDocument: any, eSignatureLength: any) { + 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); + + + const hashSignature = await this.provider.subtle.sign(alg, this.privateKey, hashDocumentHex); + + console.log('hashSignature', hashSignature); + + + const objEsign = { + certificate: this.certPem, + hashSignature: this.toHex(hashSignature), + signatureContentLength: eSignatureLength + } + this.http.put('../rest/documents/' + this.signaturesService.mainDocumentId + '/actions/' + this.signaturesService.currentAction, objEsign) + .pipe( + tap((res: any) => { + resolve(true); + }), + catchError((err: any) => { + this.notificationService.handleErrors(err); + resolve(false); + return of(false); + }) + ).subscribe(); + + }); + } + cancelSign(data: any) { console.log(data); this.modalController.dismiss(false); } - // 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; - // } + toHex(buffer: any) { + let buf = new Uint8Array(buffer), + splitter = "", + res = [], + len = buf.length; + + for (let i = 0; i < len; i++) { + let 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; + } + } -- GitLab