@devlas/dte-sii 2.12.9 → 2.12.10
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/SiiSession.js +22 -3
- package/package.json +1 -1
- package/utils/pfx.js +57 -1
package/SiiSession.js
CHANGED
|
@@ -14,6 +14,8 @@ const {
|
|
|
14
14
|
loadPfxFromBuffer,
|
|
15
15
|
loadPfxFromFile,
|
|
16
16
|
createTlsOptions,
|
|
17
|
+
createTlsAgent,
|
|
18
|
+
createTlsAgentFromPem,
|
|
17
19
|
validateAmbiente,
|
|
18
20
|
getHost,
|
|
19
21
|
createScopedLogger,
|
|
@@ -44,6 +46,10 @@ class SiiSession {
|
|
|
44
46
|
this.baseHost = getHost(this.ambiente);
|
|
45
47
|
this.cookieJar = '';
|
|
46
48
|
this.tlsOptions = null;
|
|
49
|
+
// Agent nativo con el certificado + flags TLS legacy del SII. got no reenvía
|
|
50
|
+
// secureOptions/maxVersion a través de su opción `https` bajo ningún nombre de
|
|
51
|
+
// clave, así que estos flags solo se pueden aplicar vía un https.Agent nativo.
|
|
52
|
+
this.tlsAgent = null;
|
|
47
53
|
|
|
48
54
|
// Configurar TLS desde certificado
|
|
49
55
|
if (options.certificado) {
|
|
@@ -61,15 +67,19 @@ class SiiSession {
|
|
|
61
67
|
*/
|
|
62
68
|
_configureTlsFromCertificado(certificado) {
|
|
63
69
|
try {
|
|
70
|
+
const keyPem = certificado.getPrivateKeyPEM();
|
|
71
|
+
const certPem = certificado.getCertificatePEM();
|
|
64
72
|
this.tlsOptions = {
|
|
65
|
-
key:
|
|
66
|
-
cert:
|
|
67
|
-
certificate:
|
|
73
|
+
key: keyPem,
|
|
74
|
+
cert: certPem,
|
|
75
|
+
certificate: certPem,
|
|
68
76
|
rejectUnauthorized: false,
|
|
69
77
|
};
|
|
78
|
+
this.tlsAgent = createTlsAgentFromPem(keyPem, certPem);
|
|
70
79
|
} catch (error) {
|
|
71
80
|
log.error('Error configurando TLS desde certificado:', error.message);
|
|
72
81
|
this.tlsOptions = null;
|
|
82
|
+
this.tlsAgent = null;
|
|
73
83
|
}
|
|
74
84
|
}
|
|
75
85
|
|
|
@@ -81,9 +91,11 @@ class SiiSession {
|
|
|
81
91
|
try {
|
|
82
92
|
const pfxData = loadPfxFromBuffer(pfxBuffer, password);
|
|
83
93
|
this.tlsOptions = createTlsOptions(pfxData);
|
|
94
|
+
this.tlsAgent = createTlsAgent(pfxData);
|
|
84
95
|
} catch (error) {
|
|
85
96
|
log.error('Error configurando TLS desde PFX:', error.message);
|
|
86
97
|
this.tlsOptions = null;
|
|
98
|
+
this.tlsAgent = null;
|
|
87
99
|
}
|
|
88
100
|
}
|
|
89
101
|
|
|
@@ -95,9 +107,11 @@ class SiiSession {
|
|
|
95
107
|
try {
|
|
96
108
|
const pfxData = loadPfxFromFile(pfxPath, password);
|
|
97
109
|
this.tlsOptions = createTlsOptions(pfxData);
|
|
110
|
+
this.tlsAgent = createTlsAgent(pfxData);
|
|
98
111
|
} catch (error) {
|
|
99
112
|
log.error('Error configurando TLS desde archivo PFX:', error.message);
|
|
100
113
|
this.tlsOptions = null;
|
|
114
|
+
this.tlsAgent = null;
|
|
101
115
|
}
|
|
102
116
|
}
|
|
103
117
|
|
|
@@ -215,6 +229,11 @@ class SiiSession {
|
|
|
215
229
|
followRedirect: false,
|
|
216
230
|
throwHttpErrors: false,
|
|
217
231
|
https: this.tlsOptions || { rejectUnauthorized: false },
|
|
232
|
+
// got remapea `https` a un set fijo de claves y NO reenvía secureOptions/
|
|
233
|
+
// maxVersion bajo ningún nombre — sin el Agent nativo aquí, el certificado
|
|
234
|
+
// cliente se autentica con handshake TLS incompleto contra el SII (ver
|
|
235
|
+
// utils/pfx.js createTlsAgent).
|
|
236
|
+
...(this.tlsAgent ? { agent: { https: this.tlsAgent } } : {}),
|
|
218
237
|
responseType: 'buffer',
|
|
219
238
|
timeout: { request: options.timeoutMs ?? 20000 },
|
|
220
239
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@devlas/dte-sii",
|
|
3
|
-
"version": "2.12.
|
|
3
|
+
"version": "2.12.10",
|
|
4
4
|
"description": "Facturación y boletas electrónicas para el SII de Chile. Genera, timbra, firma y envía DTEs, libros electrónicos y automatiza la certificación.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "dte-sii.d.ts",
|
package/utils/pfx.js
CHANGED
|
@@ -10,9 +10,24 @@
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
const fs = require('fs');
|
|
13
|
+
const https = require('https');
|
|
14
|
+
const crypto = require('crypto');
|
|
13
15
|
const forge = require('node-forge');
|
|
14
16
|
const { certError, ERROR_CODES } = require('./error');
|
|
15
17
|
|
|
18
|
+
/**
|
|
19
|
+
* Flags TLS que la infraestructura legacy del SII requiere para completar la
|
|
20
|
+
* autenticación con certificado cliente (mismo set que SiiPortalAuth.SII_TLS_OPTS).
|
|
21
|
+
* Sin `maxVersion: 'TLSv1.2'` + renegociación insegura habilitada, el handshake
|
|
22
|
+
* de client-cert contra los servidores del SII no se completa correctamente.
|
|
23
|
+
*/
|
|
24
|
+
const SII_LEGACY_TLS_FLAGS = {
|
|
25
|
+
maxVersion: 'TLSv1.2',
|
|
26
|
+
secureOptions:
|
|
27
|
+
crypto.constants.SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION |
|
|
28
|
+
crypto.constants.SSL_OP_LEGACY_SERVER_CONNECT,
|
|
29
|
+
};
|
|
30
|
+
|
|
16
31
|
/**
|
|
17
32
|
* Resultado de cargar un PFX
|
|
18
33
|
* @typedef {Object} PfxData
|
|
@@ -217,17 +232,56 @@ function getDaysUntilExpiry(notAfter) {
|
|
|
217
232
|
|
|
218
233
|
/**
|
|
219
234
|
* Crear opciones TLS desde datos PFX
|
|
235
|
+
*
|
|
236
|
+
* IMPORTANTE: `got` (usado por SiiSession) remapea su opción `https` a un set
|
|
237
|
+
* fijo de claves y solo reconoce `certificate` para el certificado cliente —
|
|
238
|
+
* NO `cert` (ver got/dist/source/core/index.js, "HTTPS options remapping").
|
|
239
|
+
* Se incluyen ambas claves (`cert` para consumidores que usan `https` nativo,
|
|
240
|
+
* `certificate` para got) para que el certificado se envíe en ambos casos.
|
|
241
|
+
*
|
|
220
242
|
* @param {PfxData} pfxData - Datos del PFX
|
|
221
243
|
* @returns {Object} Opciones TLS para https/got
|
|
222
244
|
*/
|
|
223
245
|
function createTlsOptions(pfxData) {
|
|
246
|
+
const certPem = pfxData.certificateChainPem || pfxData.certificatePem;
|
|
224
247
|
return {
|
|
225
248
|
key: pfxData.privateKeyPem,
|
|
226
|
-
cert:
|
|
249
|
+
cert: certPem,
|
|
250
|
+
certificate: certPem,
|
|
227
251
|
rejectUnauthorized: false,
|
|
228
252
|
};
|
|
229
253
|
}
|
|
230
254
|
|
|
255
|
+
/**
|
|
256
|
+
* Crea un https.Agent nativo con el certificado cliente + los flags TLS legacy
|
|
257
|
+
* que el SII requiere. `got` no reenvía `secureOptions`/`maxVersion` a través de
|
|
258
|
+
* su opción `https` bajo ningún nombre de clave — la única forma de aplicarlos
|
|
259
|
+
* es con un Agent nativo pasado como `agent.https` en las opciones de got.
|
|
260
|
+
*
|
|
261
|
+
* @param {PfxData} pfxData - Datos del PFX
|
|
262
|
+
* @returns {https.Agent}
|
|
263
|
+
*/
|
|
264
|
+
function createTlsAgent(pfxData) {
|
|
265
|
+
return createTlsAgentFromPem(pfxData.privateKeyPem, pfxData.certificateChainPem || pfxData.certificatePem);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Crea un https.Agent nativo desde un par key/cert PEM ya extraído (ej. desde
|
|
270
|
+
* una instancia de Certificado), con los mismos flags legacy que createTlsAgent.
|
|
271
|
+
*
|
|
272
|
+
* @param {string} keyPem
|
|
273
|
+
* @param {string} certPem
|
|
274
|
+
* @returns {https.Agent}
|
|
275
|
+
*/
|
|
276
|
+
function createTlsAgentFromPem(keyPem, certPem) {
|
|
277
|
+
return new https.Agent({
|
|
278
|
+
...SII_LEGACY_TLS_FLAGS,
|
|
279
|
+
key: keyPem,
|
|
280
|
+
cert: certPem,
|
|
281
|
+
rejectUnauthorized: false,
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
|
|
231
285
|
module.exports = {
|
|
232
286
|
loadPfxFromBuffer,
|
|
233
287
|
loadPfxFromFile,
|
|
@@ -236,4 +290,6 @@ module.exports = {
|
|
|
236
290
|
isCertificateExpired,
|
|
237
291
|
getDaysUntilExpiry,
|
|
238
292
|
createTlsOptions,
|
|
293
|
+
createTlsAgent,
|
|
294
|
+
createTlsAgentFromPem,
|
|
239
295
|
};
|