fpavon-ee-shared 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dependency-injection/dependency-injection.ts +56 -0
- package/digitalSignature/application/digitalSignature.useCase.ts +171 -0
- package/digitalSignature/domain/PDFArrayCustom.ts +60 -0
- package/digitalSignature/domain/SignPDF.ts +112 -0
- package/digitalSignature/infrastructure/routes/digitalSignature.routes.ts +3 -0
- package/digitalSignature/infrastructure/template/marco.pdf +0 -0
- package/dist/dependency-injection/dependency-injection.js +46 -0
- package/dist/digitalSignature/application/digitalSignature.useCase.js +180 -0
- package/dist/digitalSignature/domain/PDFArrayCustom.js +59 -0
- package/dist/digitalSignature/domain/SignPDF.js +100 -0
- package/dist/digitalSignature/infrastructure/routes/digitalSignature.routes.js +1 -0
- package/dist/documentos/application/documentos.useCase.js +49 -0
- package/dist/documentos/application/streamConversor.js +14 -0
- package/dist/documentos/domain/documento.class.js +60 -0
- package/dist/documentos/domain/documento.interface.js +2 -0
- package/dist/documentos/domain/documento.repository.js +2 -0
- package/dist/documentos/domain/documentoFTP.js +11 -0
- package/dist/documentos/domain/value-object/uuid.js +21 -0
- package/dist/documentos/infrastructure/repository/documentos.ftp.repository.js +172 -0
- package/dist/estados/application/flujos.useCase.js +21 -0
- package/dist/estados/domain/estado.class.js +150 -0
- package/dist/estados/domain/flujos.repository.js +2 -0
- package/dist/estados/infrastructure/controller/flujos.controller.js +34 -0
- package/dist/estados/infrastructure/repositories/flujos.sql.repository.js +36 -0
- package/dist/estados/infrastructure/routes/flujo.route.js +50 -0
- package/dist/expediente-electronico/application/expediente-electronico.useCase.js +171 -0
- package/dist/expediente-electronico/domain/expediente-electronico.class.js +190 -0
- package/dist/expediente-electronico/domain/expediente-electronico.interface.js +2 -0
- package/dist/expediente-electronico/domain/expediente-electronico.repository.js +2 -0
- package/dist/expediente-electronico/domain/value-object/limited-string.class.js +19 -0
- package/dist/expediente-electronico/domain/value-object/notas.class.js +41 -0
- package/dist/expediente-electronico/infrastructure/controller/expediente-electronico.controller.js +306 -0
- package/dist/expediente-electronico/infrastructure/repositories/expediente-electronico.sql.repository.js +775 -0
- package/dist/expediente-electronico/infrastructure/routes/expediente-electronico.route.js +46 -0
- package/dist/infrastructure/bd/connection.sql.js +64 -0
- package/dist/infrastructure/bd/pagination.sql.js +15 -0
- package/dist/infrastructure/docs/swagger.js +37 -0
- package/dist/infrastructure/fileServer/fileServer.basic-ftp.js +220 -0
- package/dist/infrastructure/fileServer/fileServer.connection.js +94 -0
- package/dist/infrastructure/middlewares/middleware.apikey.js +15 -0
- package/dist/infrastructure/middlewares/middleware.auth.js +372 -0
- package/dist/infrastructure/middlewares/middleware.deslogueo.js +1 -0
- package/dist/infrastructure/middlewares/middleware.validarCampos.js +15 -0
- package/dist/infrastructure/middlewares/middleware.validarRol.js +19 -0
- package/dist/infrastructure/middlewares/validarNivel.js +37 -0
- package/dist/infrastructure/server/httpsServer.class.js +59 -0
- package/dist/infrastructure/server/server.class.js +54 -0
- package/dist/infrastructure/socket/socketIO.js +23 -0
- package/dist/infrastructure/stream-handler/stream-handler.js +137 -0
- package/dist/notificaciones/domain/datosNotificacion.class.js +11 -0
- package/dist/notificaciones/domain/datosNotificacion.interface.js +2 -0
- package/dist/notificaciones/domain/notificacion.class.js +19 -0
- package/dist/notificaciones/domain/notificacion.interface.js +2 -0
- package/dist/notificaciones/domain/notificacion.repository.js +2 -0
- package/dist/notificaciones/infrastructure/notificacion.controller.js +31 -0
- package/dist/usuarios/application/usuarios.useCase.js +22 -0
- package/dist/usuarios/domain/usuario.class.js +24 -0
- package/dist/usuarios/domain/usuario.interface.js +2 -0
- package/dist/usuarios/domain/usuarios.repository.js +2 -0
- package/dist/usuarios/infrastructure/controller/usuarios.controller.js +28 -0
- package/dist/usuarios/infrastructure/repository/usuarios.sql.repository.js +17 -0
- package/dist/usuarios/infrastructure/routes/usuarios.routes.js +19 -0
- package/documentos/application/documentos.useCase.ts +41 -0
- package/documentos/domain/documento.class.ts +101 -0
- package/documentos/domain/documento.interface.ts +9 -0
- package/documentos/domain/documento.repository.ts +12 -0
- package/documentos/domain/documentoFTP.ts +17 -0
- package/documentos/domain/value-object/uuid.ts +23 -0
- package/documentos/infrastructure/repository/documentos.ftp.repository.ts +169 -0
- package/estados/application/flujos.useCase.ts +13 -0
- package/estados/domain/estado.class.ts +213 -0
- package/estados/domain/flujos.repository.ts +8 -0
- package/estados/infrastructure/controller/flujos.controller.ts +21 -0
- package/estados/infrastructure/repositories/flujos.sql.repository.ts +29 -0
- package/estados/infrastructure/routes/flujo.route.ts +56 -0
- package/expediente-electronico/application/expediente-electronico.useCase.ts +154 -0
- package/expediente-electronico/domain/expediente-electronico.class.ts +223 -0
- package/expediente-electronico/domain/expediente-electronico.interface.ts +19 -0
- package/expediente-electronico/domain/expediente-electronico.repository.ts +22 -0
- package/expediente-electronico/domain/value-object/limited-string.class.ts +19 -0
- package/expediente-electronico/domain/value-object/notas.class.ts +51 -0
- package/expediente-electronico/infrastructure/controller/expediente-electronico.controller.ts +308 -0
- package/expediente-electronico/infrastructure/repositories/expediente-electronico.sql.repository.ts +799 -0
- package/expediente-electronico/infrastructure/routes/expediente-electronico.route.ts +64 -0
- package/infrastructure/bd/connection.sql.ts +49 -0
- package/infrastructure/bd/pagination.sql.ts +11 -0
- package/infrastructure/docs/swagger.ts +38 -0
- package/infrastructure/fileServer/fileServer.basic-ftp.ts +196 -0
- package/infrastructure/fileServer/fileServer.connection.ts +78 -0
- package/infrastructure/middlewares/middleware.apikey.ts +17 -0
- package/infrastructure/middlewares/middleware.auth.ts +409 -0
- package/infrastructure/middlewares/middleware.deslogueo.ts +0 -0
- package/infrastructure/middlewares/middleware.validarCampos.ts +15 -0
- package/infrastructure/middlewares/middleware.validarRol.ts +15 -0
- package/infrastructure/middlewares/validarNivel.ts +37 -0
- package/infrastructure/server/httpsServer.class.ts +69 -0
- package/infrastructure/server/server.class.ts +66 -0
- package/infrastructure/socket/socketIO.ts +22 -0
- package/infrastructure/stream-handler/stream-handler.ts +161 -0
- package/jest.config.js +8 -0
- package/notificaciones/domain/datosNotificacion.class.ts +13 -0
- package/notificaciones/domain/datosNotificacion.interface.ts +5 -0
- package/notificaciones/domain/notificacion.class.ts +23 -0
- package/notificaciones/domain/notificacion.interface.ts +15 -0
- package/notificaciones/domain/notificacion.repository.ts +8 -0
- package/notificaciones/infrastructure/notificacion.controller.ts +16 -0
- package/package.json +42 -0
- package/script.js +135 -0
- package/test/expediente-electronico/domain/expediente-electronico.class.test.ts +186 -0
- package/tsconfig.json +73 -0
- package/usuarios/application/usuarios.useCase.ts +12 -0
- package/usuarios/domain/usuario.class.ts +40 -0
- package/usuarios/domain/usuario.interface.ts +18 -0
- package/usuarios/domain/usuarios.repository.ts +3 -0
- package/usuarios/infrastructure/controller/usuarios.controller.ts +19 -0
- package/usuarios/infrastructure/repository/usuarios.sql.repository.ts +19 -0
- package/usuarios/infrastructure/routes/usuarios.routes.ts +20 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { ContainerBuilder } from 'node-dependency-injection';
|
|
2
|
+
import { ExpedienteElectronicoSqlRepository } from '../expediente-electronico/infrastructure/repositories/expediente-electronico.sql.repository';
|
|
3
|
+
import { ExpedienteElectronicoUseCase } from '../expediente-electronico/application/expediente-electronico.useCase';
|
|
4
|
+
import { ExpedienteElectronicoController } from '../expediente-electronico/infrastructure/controller/expediente-electronico.controller';
|
|
5
|
+
import { DocumentosUseCase } from '../documentos/application/documentos.useCase';
|
|
6
|
+
import { NotificacionController } from '../notificaciones/infrastructure/notificacion.controller';
|
|
7
|
+
import { FlujosController } from '../estados/infrastructure/controller/flujos.controller';
|
|
8
|
+
import { FlujosUseCase } from '../estados/application/flujos.useCase';
|
|
9
|
+
import { FlujosRepository } from '../estados/infrastructure/repositories/flujos.sql.repository';
|
|
10
|
+
import { DocumentosFTPRepository } from '../documentos/infrastructure/repository/documentos.ftp.repository';
|
|
11
|
+
import { FtpConnection } from '../infrastructure/fileServer/fileServer.basic-ftp';
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
let container = new ContainerBuilder();
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Notificaciones
|
|
18
|
+
*/
|
|
19
|
+
container.register('EE.Notificaciones.infrastructure.NotificacionesController', NotificacionController);
|
|
20
|
+
const notificacionCtrl = container.get('EE.Notificaciones.infrastructure.NotificacionesController');
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Flujos
|
|
24
|
+
*/
|
|
25
|
+
container.register('EE.Flujos.infrastructure.FlujosRepository', FlujosRepository);
|
|
26
|
+
const flujosRepo = container.get('EE.Flujos.infrastructure.FlujosRepository');
|
|
27
|
+
container.register('EE.Flujos.application.FlujosUseCase', FlujosUseCase).addArgument(flujosRepo);
|
|
28
|
+
const flujosUseCase = container.get('EE.Flujos.application.FlujosUseCase');
|
|
29
|
+
container.register('EE.Flujos.infrastructure.FlujosController', FlujosController).addArgument(flujosUseCase);
|
|
30
|
+
const flujosController = container.get('EE.Flujos.infrastructure.FlujosController');
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
container.register('EE.FTPConnection', FtpConnection);
|
|
34
|
+
const ftp = container.get('EE.FTPConnection');
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Documentos
|
|
38
|
+
*/
|
|
39
|
+
container.register('EE.Documentos.infrastructure.DocumentosRepository', DocumentosFTPRepository).addArgument(ftp);
|
|
40
|
+
const docRepo = container.get('EE.Documentos.infrastructure.DocumentosRepository')
|
|
41
|
+
container.register('EE.Documentos.application.DocumentosUseCase', DocumentosUseCase).addArgument(docRepo);
|
|
42
|
+
const docUseCase = container.get('EE.Documentos.application.DocumentosUseCase')
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Expediente Electronico
|
|
46
|
+
*/
|
|
47
|
+
|
|
48
|
+
container.register('EE.ExpedienteElectronico.infrastructure.ExpedienteElectronicoSqlRepository', ExpedienteElectronicoSqlRepository);
|
|
49
|
+
const expedienteRepo = container.get('EE.ExpedienteElectronico.infrastructure.ExpedienteElectronicoSqlRepository');
|
|
50
|
+
|
|
51
|
+
container.register('EE.ExpedienteElectronico.application.ExpedienteElectronicoUseCase', ExpedienteElectronicoUseCase).addArgument(expedienteRepo).addArgument(docRepo);
|
|
52
|
+
const expedienteUseCase = container.get('EE.ExpedienteElectronico.application.ExpedienteElectronicoUseCase');
|
|
53
|
+
|
|
54
|
+
container.register('EE.ExpedienteElectronico.infrastructure.ExpedienteElectronicoController', ExpedienteElectronicoController).addArgument(expedienteUseCase).addArgument(notificacionCtrl)
|
|
55
|
+
|
|
56
|
+
export default container;
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
import { PDFDocument, rgb, StandardFonts } from 'pdf-lib';
|
|
3
|
+
import * as crypto from 'crypto';
|
|
4
|
+
import moment from 'moment';
|
|
5
|
+
import PDFMerger from 'pdf-merger-js';
|
|
6
|
+
import SignPDF from '../domain/SignPDF';
|
|
7
|
+
import axios from 'axios';
|
|
8
|
+
import path from "node:path";
|
|
9
|
+
import FormData from 'form-data';
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
export async function obtenerFirmasDocumento(uuid: string): Promise<any[]> {
|
|
13
|
+
|
|
14
|
+
try {
|
|
15
|
+
const response = await axios.get(`${process.env.URL_FIRMAS_SERVICE}/detalle-firmas/${uuid}`);
|
|
16
|
+
return response.data; // Esto sería un array con las firmas y sus datos
|
|
17
|
+
} catch (error: any) {
|
|
18
|
+
if (error.response) {
|
|
19
|
+
console.error("Error obtenerFirmasDocumento: respuesta inválida del servidor");
|
|
20
|
+
if (error.response.data?.message == 'El documento no contiene firmas digitales') {
|
|
21
|
+
// devuelvo array con firmas vacías ya que el documento no tiene firmas
|
|
22
|
+
return [];
|
|
23
|
+
}
|
|
24
|
+
console.error(error.response.data);
|
|
25
|
+
console.error(error.response.status);
|
|
26
|
+
console.error(error.response.headers);
|
|
27
|
+
} else if (error.request) {
|
|
28
|
+
console.error("Error obtenerFirmasDocumento: No se recibió respuesta del servicio");
|
|
29
|
+
console.error(error.request);
|
|
30
|
+
} else {
|
|
31
|
+
console.error("Error obtenerFirmasDocumento: Error al preparar la solicitud", error.message);
|
|
32
|
+
}
|
|
33
|
+
throw new Error(`Error obtenerFirmasDocumento => ${error}`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export async function firmarDocumento(documento: Buffer, firma: any, usuario: any, clave:any): Promise<Buffer> {
|
|
38
|
+
|
|
39
|
+
const bytes = await addSignPage(usuario);
|
|
40
|
+
// Crear un PDF con la firma digital y el documento original
|
|
41
|
+
var merger = new PDFMerger();
|
|
42
|
+
await merger.add(documento);
|
|
43
|
+
await merger.add(await Buffer.from(bytes))
|
|
44
|
+
|
|
45
|
+
const documentoFirmado = await merger.saveAsBuffer();
|
|
46
|
+
// const documentoFirmado = bytes;
|
|
47
|
+
|
|
48
|
+
// return documentoFirmado;
|
|
49
|
+
const pdfBuffer = new SignPDF(
|
|
50
|
+
documentoFirmado,
|
|
51
|
+
path.resolve(firma.path)
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
const signedDocs = await pdfBuffer.signPDF(clave);
|
|
55
|
+
return signedDocs;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export async function firmarDocumento2(token:string, uuid:any, firma: any, clave:any, x1:any, y1:any, page:any): Promise<string> {
|
|
59
|
+
let form = new FormData;
|
|
60
|
+
console.log("UUID: ", uuid);
|
|
61
|
+
|
|
62
|
+
form.append('clave', clave);
|
|
63
|
+
form.append('certificado', fs.createReadStream(firma.path));
|
|
64
|
+
form.append('uuid', uuid);
|
|
65
|
+
form.append('x1', x1);
|
|
66
|
+
form.append('y1', y1);
|
|
67
|
+
form.append('page', page);
|
|
68
|
+
const headers = {
|
|
69
|
+
...form.getHeaders(),
|
|
70
|
+
'Authorization': `Bearer ${token}`
|
|
71
|
+
};
|
|
72
|
+
try {
|
|
73
|
+
|
|
74
|
+
const response = await axios.post(`${process.env.URL_FIRMAS_SERVICE}/firmar-documento`, form, {headers});
|
|
75
|
+
return response.data.uuid;
|
|
76
|
+
} catch (error:any) {
|
|
77
|
+
if (error.response) {
|
|
78
|
+
console.error("Error firmarDocumento2: La respuesta fue hecha y el servidor respondió con un código de estado que esta fuera del rango de 2xx");
|
|
79
|
+
console.error(error.response.data);
|
|
80
|
+
console.error(error.response.status);
|
|
81
|
+
console.error(error.response.headers);
|
|
82
|
+
} else if (error.request) {
|
|
83
|
+
console.error("Error firmarDocumento2: Es probable que esté caido el servicio de EE-Firmas. La petición fue hecha pero no se recibió respuesta `error.request` es una instancia de XMLHttpRequest en el navegador y una instancia de http.ClientRequest en node.js")
|
|
84
|
+
console.error(error.request);
|
|
85
|
+
} else {
|
|
86
|
+
// Algo paso al preparar la petición que lanzo un Error
|
|
87
|
+
console.error('Error firmarDocumento2: Algo paso al preparar la petición que lanzo un Error', error.message);
|
|
88
|
+
}
|
|
89
|
+
throw new Error(`Error firmarDocumento2=> ${error}`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
async function addSignPage(usuario:any){
|
|
93
|
+
const response = await axios.get(`http://serverfirmas.ccba.usr.bpba:6050/ListImg/SW3UIDbGetRecInfo.php?IDX_FIR=001%20000${usuario.documento}000%20%20%20%20%20%20&IDX_TYA=TIT&IDX_LOC=ONL&TIP_DOC1=000${usuario.documento}000`, { responseType: 'arraybuffer' });
|
|
94
|
+
const firmaElectronica = response.data;
|
|
95
|
+
// Crear un nuevo documento PDF con pdf-lib
|
|
96
|
+
|
|
97
|
+
const templatePdfBytes = fs.readFileSync('src/ee-shared/digitalSignature/infrastructure/template/marco.pdf');
|
|
98
|
+
const templatePdfDoc = await PDFDocument.load(templatePdfBytes);
|
|
99
|
+
// const pdfDoc = await PDFDocument.load(documento);
|
|
100
|
+
|
|
101
|
+
const timesRomanFont = await templatePdfDoc.embedFont(StandardFonts.TimesRoman)
|
|
102
|
+
|
|
103
|
+
// Add a blank page to the document
|
|
104
|
+
const page = templatePdfDoc.getPage(0);
|
|
105
|
+
// Get the width and height of the page
|
|
106
|
+
const { width, height } = page.getSize()
|
|
107
|
+
// Draw a string of text toward the top of the page
|
|
108
|
+
const fontSize = 12
|
|
109
|
+
|
|
110
|
+
// const page = pdfDoc.addPage([600, 800]);
|
|
111
|
+
let y = (height - 4 * fontSize);
|
|
112
|
+
page.drawText(`Firmado electronicamente por: `, {
|
|
113
|
+
x: 50,
|
|
114
|
+
y,
|
|
115
|
+
size: fontSize,
|
|
116
|
+
font: timesRomanFont,
|
|
117
|
+
color: rgb(0, 0, 0),
|
|
118
|
+
});
|
|
119
|
+
y -= fontSize + 5
|
|
120
|
+
page.drawText(`Afiliado: ${usuario.uid}`, {
|
|
121
|
+
x: 50,
|
|
122
|
+
y,
|
|
123
|
+
size: fontSize,
|
|
124
|
+
font: timesRomanFont,
|
|
125
|
+
color: rgb(0, 0, 0),
|
|
126
|
+
});
|
|
127
|
+
y -= fontSize + 5
|
|
128
|
+
page.drawText(`Nombre completo: ${usuario.nombreCompleto}`, {
|
|
129
|
+
x: 50,
|
|
130
|
+
y,
|
|
131
|
+
size: fontSize,
|
|
132
|
+
font: timesRomanFont,
|
|
133
|
+
color: rgb(0, 0, 0),
|
|
134
|
+
});
|
|
135
|
+
y -= fontSize + 5
|
|
136
|
+
page.drawText(`Cargo: ${usuario.cargo}`, {
|
|
137
|
+
x: 50,
|
|
138
|
+
y,
|
|
139
|
+
size: fontSize,
|
|
140
|
+
font: timesRomanFont,
|
|
141
|
+
color: rgb(0, 0, 0),
|
|
142
|
+
});
|
|
143
|
+
y -= fontSize + 5
|
|
144
|
+
page.drawText(`Fecha: ${moment().locale('es').format('LLLL')}`, {
|
|
145
|
+
x: 50,
|
|
146
|
+
y,
|
|
147
|
+
size: fontSize,
|
|
148
|
+
font: timesRomanFont,
|
|
149
|
+
color: rgb(0, 0, 0),
|
|
150
|
+
});
|
|
151
|
+
y -= fontSize + 5
|
|
152
|
+
page.drawText(`Firma electrónica: `, {
|
|
153
|
+
x: 50,
|
|
154
|
+
y,
|
|
155
|
+
size: fontSize,
|
|
156
|
+
font: timesRomanFont,
|
|
157
|
+
color: rgb(0, 0, 0),
|
|
158
|
+
});
|
|
159
|
+
const signatureImage = await templatePdfDoc.embedPng(firmaElectronica);
|
|
160
|
+
const { width: imgWidth, height: imgHeight } = signatureImage.scale(0.3); // Aquí puedes ajustar el escalamiento
|
|
161
|
+
|
|
162
|
+
y -= imgHeight + 5
|
|
163
|
+
page.drawImage(signatureImage, {
|
|
164
|
+
x: 50,
|
|
165
|
+
y,
|
|
166
|
+
width: imgWidth,
|
|
167
|
+
height: imgHeight
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
return await templatePdfDoc.save();
|
|
171
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { PDFArray, CharCodes } from "pdf-lib";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Extends PDFArray class in order to make ByteRange look like this:
|
|
5
|
+
* /ByteRange [0 /********** /********** /**********]
|
|
6
|
+
* Not this:
|
|
7
|
+
* /ByteRange [ 0 /********** /********** /********** ]
|
|
8
|
+
*
|
|
9
|
+
* @see https://github.com/Hopding/pdf-lib/issues/112#issuecomment-569085380
|
|
10
|
+
* @author https://github.com/Hopding
|
|
11
|
+
*/
|
|
12
|
+
// @ts-ignore
|
|
13
|
+
export default class PDFArrayCustom extends PDFArray {
|
|
14
|
+
static withContext(context) {
|
|
15
|
+
// @ts-ignore
|
|
16
|
+
return new PDFArrayCustom(context);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
clone(context) {
|
|
20
|
+
// @ts-ignore
|
|
21
|
+
const clone = PDFArrayCustom.withContext(context || this.context);
|
|
22
|
+
for (let idx = 0, len = this.size(); idx < len; idx++) {
|
|
23
|
+
// @ts-ignore
|
|
24
|
+
clone.push(this.array[idx]);
|
|
25
|
+
}
|
|
26
|
+
return clone;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
toString() {
|
|
30
|
+
let arrayString = "[";
|
|
31
|
+
for (let idx = 0, len = this.size(); idx < len; idx++) {
|
|
32
|
+
arrayString += this.get(idx).toString();
|
|
33
|
+
if (idx < len - 1) arrayString += " ";
|
|
34
|
+
}
|
|
35
|
+
arrayString += "]";
|
|
36
|
+
return arrayString;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
sizeInBytes() {
|
|
40
|
+
let size = 2;
|
|
41
|
+
for (let idx = 0, len = this.size(); idx < len; idx++) {
|
|
42
|
+
size += this.get(idx).sizeInBytes();
|
|
43
|
+
if (idx < len - 1) size += 1;
|
|
44
|
+
}
|
|
45
|
+
return size;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
copyBytesInto(buffer, offset) {
|
|
49
|
+
const initialOffset = offset;
|
|
50
|
+
|
|
51
|
+
buffer[offset++] = CharCodes.LeftSquareBracket;
|
|
52
|
+
for (let idx = 0, len = this.size(); idx < len; idx++) {
|
|
53
|
+
offset += this.get(idx).copyBytesInto(buffer, offset);
|
|
54
|
+
if (idx < len - 1) buffer[offset++] = CharCodes.Space;
|
|
55
|
+
}
|
|
56
|
+
buffer[offset++] = CharCodes.RightSquareBracket;
|
|
57
|
+
|
|
58
|
+
return offset - initialOffset;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import {
|
|
2
|
+
PDFDocument,
|
|
3
|
+
PDFName,
|
|
4
|
+
PDFNumber,
|
|
5
|
+
PDFHexString,
|
|
6
|
+
PDFString,
|
|
7
|
+
} from "pdf-lib";
|
|
8
|
+
import signer from "node-signpdf";
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
import fs from "fs";
|
|
12
|
+
|
|
13
|
+
import PDFArrayCustom from "./PDFArrayCustom";
|
|
14
|
+
|
|
15
|
+
export default class SignPDF {
|
|
16
|
+
pdfDoc: any;
|
|
17
|
+
certificate: any;
|
|
18
|
+
constructor(pdfFile:any, certFile:any) {
|
|
19
|
+
this.pdfDoc = pdfFile;
|
|
20
|
+
this.certificate = fs.readFileSync(certFile);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @return Promise<Buffer>
|
|
25
|
+
*/
|
|
26
|
+
async signPDF(clave:any) {
|
|
27
|
+
try {
|
|
28
|
+
let newPDF = await this._addPlaceholder();
|
|
29
|
+
newPDF = signer.sign(newPDF, this.certificate,{ passphrase: clave });
|
|
30
|
+
|
|
31
|
+
return newPDF;
|
|
32
|
+
} catch (error) {
|
|
33
|
+
console.error("Error en la firma: ", error)
|
|
34
|
+
throw new Error("Contraseña invalida");
|
|
35
|
+
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* @see https://github.com/Hopding/pdf-lib/issues/112#issuecomment-569085380
|
|
41
|
+
* @returns {Promise<Buffer>}
|
|
42
|
+
*/
|
|
43
|
+
async _addPlaceholder() {
|
|
44
|
+
const loadedPdf = await PDFDocument.load(this.pdfDoc);
|
|
45
|
+
const ByteRange = PDFArrayCustom.withContext(loadedPdf.context);
|
|
46
|
+
const DEFAULT_BYTE_RANGE_PLACEHOLDER = '**********';
|
|
47
|
+
const SIGNATURE_LENGTH = 8192;
|
|
48
|
+
const pages = loadedPdf.getPages();
|
|
49
|
+
|
|
50
|
+
ByteRange.push(PDFNumber.of(0));
|
|
51
|
+
ByteRange.push(PDFName.of(DEFAULT_BYTE_RANGE_PLACEHOLDER));
|
|
52
|
+
ByteRange.push(PDFName.of(DEFAULT_BYTE_RANGE_PLACEHOLDER));
|
|
53
|
+
ByteRange.push(PDFName.of(DEFAULT_BYTE_RANGE_PLACEHOLDER));
|
|
54
|
+
|
|
55
|
+
const signatureDict = loadedPdf.context.obj({
|
|
56
|
+
Type: 'Sig',
|
|
57
|
+
Filter: 'Adobe.PPKLite',
|
|
58
|
+
SubFilter: 'adbe.pkcs7.detached',
|
|
59
|
+
ByteRange,
|
|
60
|
+
Contents: PDFHexString.of('A'.repeat(SIGNATURE_LENGTH)),
|
|
61
|
+
Reason: PDFString.of('Firma electrónica'),
|
|
62
|
+
M: PDFString.fromDate(new Date()),
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
const signatureDictRef = loadedPdf.context.register(signatureDict);
|
|
68
|
+
|
|
69
|
+
const widgetDict = loadedPdf.context.obj({
|
|
70
|
+
Type: 'Annot',
|
|
71
|
+
Subtype: 'Widget',
|
|
72
|
+
FT: 'Sig',
|
|
73
|
+
Rect: [0, 0, 0, 0], // Signature rect size
|
|
74
|
+
V: signatureDictRef,
|
|
75
|
+
T: PDFString.of('test signature'),
|
|
76
|
+
F: 4,
|
|
77
|
+
P: pages[0].ref,
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
const widgetDictRef = loadedPdf.context.register(widgetDict);
|
|
81
|
+
|
|
82
|
+
// Add signature widget to the first page
|
|
83
|
+
pages[0].node.set(PDFName.of('Annots'), loadedPdf.context.obj([widgetDictRef]));
|
|
84
|
+
|
|
85
|
+
loadedPdf.catalog.set(
|
|
86
|
+
PDFName.of('AcroForm'),
|
|
87
|
+
loadedPdf.context.obj({
|
|
88
|
+
SigFlags: 3,
|
|
89
|
+
Fields: [widgetDictRef],
|
|
90
|
+
})
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
// Allows signatures on newer PDFs
|
|
94
|
+
// @see https://github.com/Hopding/pdf-lib/issues/541
|
|
95
|
+
const pdfBytes = await loadedPdf.save({ useObjectStreams: false });
|
|
96
|
+
|
|
97
|
+
return SignPDF.unit8ToBuffer(pdfBytes);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* @param {Uint8Array} unit8
|
|
102
|
+
*/
|
|
103
|
+
static unit8ToBuffer(unit8:any) {
|
|
104
|
+
let buf = Buffer.alloc(unit8.byteLength);
|
|
105
|
+
const view = new Uint8Array(unit8);
|
|
106
|
+
|
|
107
|
+
for (let i = 0; i < buf.length; ++i) {
|
|
108
|
+
buf[i] = view[i];
|
|
109
|
+
}
|
|
110
|
+
return buf;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const node_dependency_injection_1 = require("node-dependency-injection");
|
|
4
|
+
const expediente_electronico_sql_repository_1 = require("../expediente-electronico/infrastructure/repositories/expediente-electronico.sql.repository");
|
|
5
|
+
const expediente_electronico_useCase_1 = require("../expediente-electronico/application/expediente-electronico.useCase");
|
|
6
|
+
const expediente_electronico_controller_1 = require("../expediente-electronico/infrastructure/controller/expediente-electronico.controller");
|
|
7
|
+
const documentos_useCase_1 = require("../documentos/application/documentos.useCase");
|
|
8
|
+
const notificacion_controller_1 = require("../notificaciones/infrastructure/notificacion.controller");
|
|
9
|
+
const flujos_controller_1 = require("../estados/infrastructure/controller/flujos.controller");
|
|
10
|
+
const flujos_useCase_1 = require("../estados/application/flujos.useCase");
|
|
11
|
+
const flujos_sql_repository_1 = require("../estados/infrastructure/repositories/flujos.sql.repository");
|
|
12
|
+
const documentos_ftp_repository_1 = require("../documentos/infrastructure/repository/documentos.ftp.repository");
|
|
13
|
+
const fileServer_basic_ftp_1 = require("../infrastructure/fileServer/fileServer.basic-ftp");
|
|
14
|
+
let container = new node_dependency_injection_1.ContainerBuilder();
|
|
15
|
+
/**
|
|
16
|
+
* Notificaciones
|
|
17
|
+
*/
|
|
18
|
+
container.register('EE.Notificaciones.infrastructure.NotificacionesController', notificacion_controller_1.NotificacionController);
|
|
19
|
+
const notificacionCtrl = container.get('EE.Notificaciones.infrastructure.NotificacionesController');
|
|
20
|
+
/**
|
|
21
|
+
* Flujos
|
|
22
|
+
*/
|
|
23
|
+
container.register('EE.Flujos.infrastructure.FlujosRepository', flujos_sql_repository_1.FlujosRepository);
|
|
24
|
+
const flujosRepo = container.get('EE.Flujos.infrastructure.FlujosRepository');
|
|
25
|
+
container.register('EE.Flujos.application.FlujosUseCase', flujos_useCase_1.FlujosUseCase).addArgument(flujosRepo);
|
|
26
|
+
const flujosUseCase = container.get('EE.Flujos.application.FlujosUseCase');
|
|
27
|
+
container.register('EE.Flujos.infrastructure.FlujosController', flujos_controller_1.FlujosController).addArgument(flujosUseCase);
|
|
28
|
+
const flujosController = container.get('EE.Flujos.infrastructure.FlujosController');
|
|
29
|
+
container.register('EE.FTPConnection', fileServer_basic_ftp_1.FtpConnection);
|
|
30
|
+
const ftp = container.get('EE.FTPConnection');
|
|
31
|
+
/**
|
|
32
|
+
* Documentos
|
|
33
|
+
*/
|
|
34
|
+
container.register('EE.Documentos.infrastructure.DocumentosRepository', documentos_ftp_repository_1.DocumentosFTPRepository).addArgument(ftp);
|
|
35
|
+
const docRepo = container.get('EE.Documentos.infrastructure.DocumentosRepository');
|
|
36
|
+
container.register('EE.Documentos.application.DocumentosUseCase', documentos_useCase_1.DocumentosUseCase).addArgument(docRepo);
|
|
37
|
+
const docUseCase = container.get('EE.Documentos.application.DocumentosUseCase');
|
|
38
|
+
/**
|
|
39
|
+
* Expediente Electronico
|
|
40
|
+
*/
|
|
41
|
+
container.register('EE.ExpedienteElectronico.infrastructure.ExpedienteElectronicoSqlRepository', expediente_electronico_sql_repository_1.ExpedienteElectronicoSqlRepository);
|
|
42
|
+
const expedienteRepo = container.get('EE.ExpedienteElectronico.infrastructure.ExpedienteElectronicoSqlRepository');
|
|
43
|
+
container.register('EE.ExpedienteElectronico.application.ExpedienteElectronicoUseCase', expediente_electronico_useCase_1.ExpedienteElectronicoUseCase).addArgument(expedienteRepo).addArgument(docRepo);
|
|
44
|
+
const expedienteUseCase = container.get('EE.ExpedienteElectronico.application.ExpedienteElectronicoUseCase');
|
|
45
|
+
container.register('EE.ExpedienteElectronico.infrastructure.ExpedienteElectronicoController', expediente_electronico_controller_1.ExpedienteElectronicoController).addArgument(expedienteUseCase).addArgument(notificacionCtrl);
|
|
46
|
+
exports.default = container;
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.firmarDocumento2 = exports.firmarDocumento = exports.obtenerFirmasDocumento = void 0;
|
|
16
|
+
const fs = require('fs');
|
|
17
|
+
const pdf_lib_1 = require("pdf-lib");
|
|
18
|
+
const moment_1 = __importDefault(require("moment"));
|
|
19
|
+
const pdf_merger_js_1 = __importDefault(require("pdf-merger-js"));
|
|
20
|
+
const SignPDF_1 = __importDefault(require("../domain/SignPDF"));
|
|
21
|
+
const axios_1 = __importDefault(require("axios"));
|
|
22
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
23
|
+
const form_data_1 = __importDefault(require("form-data"));
|
|
24
|
+
function obtenerFirmasDocumento(uuid) {
|
|
25
|
+
var _a;
|
|
26
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
27
|
+
try {
|
|
28
|
+
const response = yield axios_1.default.get(`${process.env.URL_FIRMAS_SERVICE}/detalle-firmas/${uuid}`);
|
|
29
|
+
return response.data; // Esto sería un array con las firmas y sus datos
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
if (error.response) {
|
|
33
|
+
console.error("Error obtenerFirmasDocumento: respuesta inválida del servidor");
|
|
34
|
+
if (((_a = error.response.data) === null || _a === void 0 ? void 0 : _a.message) == 'El documento no contiene firmas digitales') {
|
|
35
|
+
// devuelvo array con firmas vacías ya que el documento no tiene firmas
|
|
36
|
+
return [];
|
|
37
|
+
}
|
|
38
|
+
console.error(error.response.data);
|
|
39
|
+
console.error(error.response.status);
|
|
40
|
+
console.error(error.response.headers);
|
|
41
|
+
}
|
|
42
|
+
else if (error.request) {
|
|
43
|
+
console.error("Error obtenerFirmasDocumento: No se recibió respuesta del servicio");
|
|
44
|
+
console.error(error.request);
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
console.error("Error obtenerFirmasDocumento: Error al preparar la solicitud", error.message);
|
|
48
|
+
}
|
|
49
|
+
throw new Error(`Error obtenerFirmasDocumento => ${error}`);
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
exports.obtenerFirmasDocumento = obtenerFirmasDocumento;
|
|
54
|
+
function firmarDocumento(documento, firma, usuario, clave) {
|
|
55
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
56
|
+
const bytes = yield addSignPage(usuario);
|
|
57
|
+
// Crear un PDF con la firma digital y el documento original
|
|
58
|
+
var merger = new pdf_merger_js_1.default();
|
|
59
|
+
yield merger.add(documento);
|
|
60
|
+
yield merger.add(yield Buffer.from(bytes));
|
|
61
|
+
const documentoFirmado = yield merger.saveAsBuffer();
|
|
62
|
+
// const documentoFirmado = bytes;
|
|
63
|
+
// return documentoFirmado;
|
|
64
|
+
const pdfBuffer = new SignPDF_1.default(documentoFirmado, node_path_1.default.resolve(firma.path));
|
|
65
|
+
const signedDocs = yield pdfBuffer.signPDF(clave);
|
|
66
|
+
return signedDocs;
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
exports.firmarDocumento = firmarDocumento;
|
|
70
|
+
function firmarDocumento2(token, uuid, firma, clave, x1, y1, page) {
|
|
71
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
72
|
+
let form = new form_data_1.default;
|
|
73
|
+
console.log("UUID: ", uuid);
|
|
74
|
+
form.append('clave', clave);
|
|
75
|
+
form.append('certificado', fs.createReadStream(firma.path));
|
|
76
|
+
form.append('uuid', uuid);
|
|
77
|
+
form.append('x1', x1);
|
|
78
|
+
form.append('y1', y1);
|
|
79
|
+
form.append('page', page);
|
|
80
|
+
const headers = Object.assign(Object.assign({}, form.getHeaders()), { 'Authorization': `Bearer ${token}` });
|
|
81
|
+
try {
|
|
82
|
+
const response = yield axios_1.default.post(`${process.env.URL_FIRMAS_SERVICE}/firmar-documento`, form, { headers });
|
|
83
|
+
return response.data.uuid;
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
if (error.response) {
|
|
87
|
+
console.error("Error firmarDocumento2: La respuesta fue hecha y el servidor respondió con un código de estado que esta fuera del rango de 2xx");
|
|
88
|
+
console.error(error.response.data);
|
|
89
|
+
console.error(error.response.status);
|
|
90
|
+
console.error(error.response.headers);
|
|
91
|
+
}
|
|
92
|
+
else if (error.request) {
|
|
93
|
+
console.error("Error firmarDocumento2: Es probable que esté caido el servicio de EE-Firmas. La petición fue hecha pero no se recibió respuesta `error.request` es una instancia de XMLHttpRequest en el navegador y una instancia de http.ClientRequest en node.js");
|
|
94
|
+
console.error(error.request);
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
// Algo paso al preparar la petición que lanzo un Error
|
|
98
|
+
console.error('Error firmarDocumento2: Algo paso al preparar la petición que lanzo un Error', error.message);
|
|
99
|
+
}
|
|
100
|
+
throw new Error(`Error firmarDocumento2=> ${error}`);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
exports.firmarDocumento2 = firmarDocumento2;
|
|
105
|
+
function addSignPage(usuario) {
|
|
106
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
107
|
+
const response = yield axios_1.default.get(`http://serverfirmas.ccba.usr.bpba:6050/ListImg/SW3UIDbGetRecInfo.php?IDX_FIR=001%20000${usuario.documento}000%20%20%20%20%20%20&IDX_TYA=TIT&IDX_LOC=ONL&TIP_DOC1=000${usuario.documento}000`, { responseType: 'arraybuffer' });
|
|
108
|
+
const firmaElectronica = response.data;
|
|
109
|
+
// Crear un nuevo documento PDF con pdf-lib
|
|
110
|
+
const templatePdfBytes = fs.readFileSync('src/ee-shared/digitalSignature/infrastructure/template/marco.pdf');
|
|
111
|
+
const templatePdfDoc = yield pdf_lib_1.PDFDocument.load(templatePdfBytes);
|
|
112
|
+
// const pdfDoc = await PDFDocument.load(documento);
|
|
113
|
+
const timesRomanFont = yield templatePdfDoc.embedFont(pdf_lib_1.StandardFonts.TimesRoman);
|
|
114
|
+
// Add a blank page to the document
|
|
115
|
+
const page = templatePdfDoc.getPage(0);
|
|
116
|
+
// Get the width and height of the page
|
|
117
|
+
const { width, height } = page.getSize();
|
|
118
|
+
// Draw a string of text toward the top of the page
|
|
119
|
+
const fontSize = 12;
|
|
120
|
+
// const page = pdfDoc.addPage([600, 800]);
|
|
121
|
+
let y = (height - 4 * fontSize);
|
|
122
|
+
page.drawText(`Firmado electronicamente por: `, {
|
|
123
|
+
x: 50,
|
|
124
|
+
y,
|
|
125
|
+
size: fontSize,
|
|
126
|
+
font: timesRomanFont,
|
|
127
|
+
color: (0, pdf_lib_1.rgb)(0, 0, 0),
|
|
128
|
+
});
|
|
129
|
+
y -= fontSize + 5;
|
|
130
|
+
page.drawText(`Afiliado: ${usuario.uid}`, {
|
|
131
|
+
x: 50,
|
|
132
|
+
y,
|
|
133
|
+
size: fontSize,
|
|
134
|
+
font: timesRomanFont,
|
|
135
|
+
color: (0, pdf_lib_1.rgb)(0, 0, 0),
|
|
136
|
+
});
|
|
137
|
+
y -= fontSize + 5;
|
|
138
|
+
page.drawText(`Nombre completo: ${usuario.nombreCompleto}`, {
|
|
139
|
+
x: 50,
|
|
140
|
+
y,
|
|
141
|
+
size: fontSize,
|
|
142
|
+
font: timesRomanFont,
|
|
143
|
+
color: (0, pdf_lib_1.rgb)(0, 0, 0),
|
|
144
|
+
});
|
|
145
|
+
y -= fontSize + 5;
|
|
146
|
+
page.drawText(`Cargo: ${usuario.cargo}`, {
|
|
147
|
+
x: 50,
|
|
148
|
+
y,
|
|
149
|
+
size: fontSize,
|
|
150
|
+
font: timesRomanFont,
|
|
151
|
+
color: (0, pdf_lib_1.rgb)(0, 0, 0),
|
|
152
|
+
});
|
|
153
|
+
y -= fontSize + 5;
|
|
154
|
+
page.drawText(`Fecha: ${(0, moment_1.default)().locale('es').format('LLLL')}`, {
|
|
155
|
+
x: 50,
|
|
156
|
+
y,
|
|
157
|
+
size: fontSize,
|
|
158
|
+
font: timesRomanFont,
|
|
159
|
+
color: (0, pdf_lib_1.rgb)(0, 0, 0),
|
|
160
|
+
});
|
|
161
|
+
y -= fontSize + 5;
|
|
162
|
+
page.drawText(`Firma electrónica: `, {
|
|
163
|
+
x: 50,
|
|
164
|
+
y,
|
|
165
|
+
size: fontSize,
|
|
166
|
+
font: timesRomanFont,
|
|
167
|
+
color: (0, pdf_lib_1.rgb)(0, 0, 0),
|
|
168
|
+
});
|
|
169
|
+
const signatureImage = yield templatePdfDoc.embedPng(firmaElectronica);
|
|
170
|
+
const { width: imgWidth, height: imgHeight } = signatureImage.scale(0.3); // Aquí puedes ajustar el escalamiento
|
|
171
|
+
y -= imgHeight + 5;
|
|
172
|
+
page.drawImage(signatureImage, {
|
|
173
|
+
x: 50,
|
|
174
|
+
y,
|
|
175
|
+
width: imgWidth,
|
|
176
|
+
height: imgHeight
|
|
177
|
+
});
|
|
178
|
+
return yield templatePdfDoc.save();
|
|
179
|
+
});
|
|
180
|
+
}
|