@timbra-ec/sri 0.1.0-dev.20260403050717
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/.turbo/turbo-build.log +4 -0
- package/dist/clave-acceso.d.ts +31 -0
- package/dist/clave-acceso.d.ts.map +1 -0
- package/dist/clave-acceso.js +70 -0
- package/dist/clave-acceso.js.map +1 -0
- package/dist/errors.d.ts +22 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +26 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/signing/certificate.d.ts +27 -0
- package/dist/signing/certificate.d.ts.map +1 -0
- package/dist/signing/certificate.js +78 -0
- package/dist/signing/certificate.js.map +1 -0
- package/dist/signing/xades-bes.d.ts +10 -0
- package/dist/signing/xades-bes.d.ts.map +1 -0
- package/dist/signing/xades-bes.js +166 -0
- package/dist/signing/xades-bes.js.map +1 -0
- package/dist/soap/autorizacion.d.ts +21 -0
- package/dist/soap/autorizacion.d.ts.map +1 -0
- package/dist/soap/autorizacion.js +99 -0
- package/dist/soap/autorizacion.js.map +1 -0
- package/dist/soap/client.d.ts +6 -0
- package/dist/soap/client.d.ts.map +1 -0
- package/dist/soap/client.js +37 -0
- package/dist/soap/client.js.map +1 -0
- package/dist/soap/recepcion.d.ts +9 -0
- package/dist/soap/recepcion.d.ts.map +1 -0
- package/dist/soap/recepcion.js +60 -0
- package/dist/soap/recepcion.js.map +1 -0
- package/dist/xml/builder.d.ts +31 -0
- package/dist/xml/builder.d.ts.map +1 -0
- package/dist/xml/builder.js +287 -0
- package/dist/xml/builder.js.map +1 -0
- package/dist/xml/shared.d.ts +21 -0
- package/dist/xml/shared.d.ts.map +1 -0
- package/dist/xml/shared.js +93 -0
- package/dist/xml/shared.js.map +1 -0
- package/dist/xml/types.d.ts +179 -0
- package/dist/xml/types.d.ts.map +1 -0
- package/dist/xml/types.js +2 -0
- package/dist/xml/types.js.map +1 -0
- package/package.json +37 -0
- package/src/clave-acceso.ts +106 -0
- package/src/errors.ts +32 -0
- package/src/index.ts +49 -0
- package/src/signing/certificate.ts +103 -0
- package/src/signing/xades-bes.ts +188 -0
- package/src/soap/autorizacion.ts +139 -0
- package/src/soap/client.ts +45 -0
- package/src/soap/recepcion.ts +83 -0
- package/src/xml/builder.ts +344 -0
- package/src/xml/shared.ts +110 -0
- package/src/xml/types.ts +195 -0
- package/tsconfig.json +8 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { DocumentTypeCode, EmissionType, SriEnvironment } from '@timbra-ec/types';
|
|
2
|
+
export interface ClaveAccesoInput {
|
|
3
|
+
/** Date in dd/MM/yyyy format */
|
|
4
|
+
fechaEmision: string;
|
|
5
|
+
codDoc: DocumentTypeCode;
|
|
6
|
+
ruc: string;
|
|
7
|
+
ambiente: SriEnvironment;
|
|
8
|
+
estab: string;
|
|
9
|
+
ptoEmi: string;
|
|
10
|
+
/** 9 digits, zero-padded */
|
|
11
|
+
secuencial: string;
|
|
12
|
+
/** 8-digit random numeric code */
|
|
13
|
+
codigoNumerico: string;
|
|
14
|
+
tipoEmision: EmissionType;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Compute Modulo 11 check digit for SRI clave de acceso.
|
|
18
|
+
* Weights cycle 2,3,4,5,6,7 from right to left.
|
|
19
|
+
* Result: 11 - (sum % 11). If 11 → 0, if 10 → 1.
|
|
20
|
+
*/
|
|
21
|
+
export declare function computeModulo11(digits: string): number;
|
|
22
|
+
/**
|
|
23
|
+
* Generate the 49-digit clave de acceso for SRI electronic documents.
|
|
24
|
+
*
|
|
25
|
+
* Format (49 digits total):
|
|
26
|
+
* DDMMAAAA (8) + codDoc (2) + RUC (13) + ambiente (1) +
|
|
27
|
+
* estab (3) + ptoEmi (3) + secuencial (9) + codigoNumerico (8) +
|
|
28
|
+
* tipoEmision (1) + checkDigit (1)
|
|
29
|
+
*/
|
|
30
|
+
export declare function generateClaveAcceso(input: ClaveAccesoInput): string;
|
|
31
|
+
//# sourceMappingURL=clave-acceso.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clave-acceso.d.ts","sourceRoot":"","sources":["../src/clave-acceso.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AAGtF,MAAM,WAAW,gBAAgB;IAC/B,gCAAgC;IAChC,YAAY,EAAE,MAAM,CAAA;IACpB,MAAM,EAAE,gBAAgB,CAAA;IACxB,GAAG,EAAE,MAAM,CAAA;IACX,QAAQ,EAAE,cAAc,CAAA;IACxB,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,4BAA4B;IAC5B,UAAU,EAAE,MAAM,CAAA;IAClB,kCAAkC;IAClC,cAAc,EAAE,MAAM,CAAA;IACtB,WAAW,EAAE,YAAY,CAAA;CAC1B;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CActD;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,gBAAgB,GAAG,MAAM,CA0DnE"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { SriValidationError } from './errors.js';
|
|
2
|
+
/**
|
|
3
|
+
* Compute Modulo 11 check digit for SRI clave de acceso.
|
|
4
|
+
* Weights cycle 2,3,4,5,6,7 from right to left.
|
|
5
|
+
* Result: 11 - (sum % 11). If 11 → 0, if 10 → 1.
|
|
6
|
+
*/
|
|
7
|
+
export function computeModulo11(digits) {
|
|
8
|
+
const weights = [2, 3, 4, 5, 6, 7];
|
|
9
|
+
let sum = 0;
|
|
10
|
+
for (let i = digits.length - 1, w = 0; i >= 0; i--, w++) {
|
|
11
|
+
sum += parseInt(digits[i], 10) * weights[w % weights.length];
|
|
12
|
+
}
|
|
13
|
+
const remainder = sum % 11;
|
|
14
|
+
const check = 11 - remainder;
|
|
15
|
+
if (check === 11)
|
|
16
|
+
return 0;
|
|
17
|
+
if (check === 10)
|
|
18
|
+
return 1;
|
|
19
|
+
return check;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Generate the 49-digit clave de acceso for SRI electronic documents.
|
|
23
|
+
*
|
|
24
|
+
* Format (49 digits total):
|
|
25
|
+
* DDMMAAAA (8) + codDoc (2) + RUC (13) + ambiente (1) +
|
|
26
|
+
* estab (3) + ptoEmi (3) + secuencial (9) + codigoNumerico (8) +
|
|
27
|
+
* tipoEmision (1) + checkDigit (1)
|
|
28
|
+
*/
|
|
29
|
+
export function generateClaveAcceso(input) {
|
|
30
|
+
const { fechaEmision, codDoc, ruc, ambiente, estab, ptoEmi, secuencial, codigoNumerico, tipoEmision, } = input;
|
|
31
|
+
// Validate date format dd/MM/yyyy and convert to DDMMAAAA
|
|
32
|
+
const dateParts = fechaEmision.split('/');
|
|
33
|
+
if (dateParts.length !== 3 ||
|
|
34
|
+
dateParts[0].length !== 2 ||
|
|
35
|
+
dateParts[1].length !== 2 ||
|
|
36
|
+
dateParts[2].length !== 4) {
|
|
37
|
+
throw new SriValidationError('fechaEmision must be in dd/MM/yyyy format');
|
|
38
|
+
}
|
|
39
|
+
const dateDigits = dateParts[0] + dateParts[1] + dateParts[2];
|
|
40
|
+
if (ruc.length !== 13) {
|
|
41
|
+
throw new SriValidationError(`RUC must be 13 digits, got ${ruc.length}`);
|
|
42
|
+
}
|
|
43
|
+
if (estab.length !== 3) {
|
|
44
|
+
throw new SriValidationError(`estab must be 3 digits, got ${estab.length}`);
|
|
45
|
+
}
|
|
46
|
+
if (ptoEmi.length !== 3) {
|
|
47
|
+
throw new SriValidationError(`ptoEmi must be 3 digits, got ${ptoEmi.length}`);
|
|
48
|
+
}
|
|
49
|
+
if (secuencial.length !== 9) {
|
|
50
|
+
throw new SriValidationError(`secuencial must be 9 digits, got ${secuencial.length}`);
|
|
51
|
+
}
|
|
52
|
+
if (codigoNumerico.length !== 8) {
|
|
53
|
+
throw new SriValidationError(`codigoNumerico must be 8 digits, got ${codigoNumerico.length}`);
|
|
54
|
+
}
|
|
55
|
+
const base = dateDigits +
|
|
56
|
+
codDoc +
|
|
57
|
+
ruc +
|
|
58
|
+
ambiente +
|
|
59
|
+
estab +
|
|
60
|
+
ptoEmi +
|
|
61
|
+
secuencial +
|
|
62
|
+
codigoNumerico +
|
|
63
|
+
tipoEmision;
|
|
64
|
+
if (base.length !== 48) {
|
|
65
|
+
throw new SriValidationError(`Clave base must be 48 digits, got ${base.length}`);
|
|
66
|
+
}
|
|
67
|
+
const checkDigit = computeModulo11(base);
|
|
68
|
+
return base + checkDigit.toString();
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=clave-acceso.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clave-acceso.js","sourceRoot":"","sources":["../src/clave-acceso.ts"],"names":[],"mappings":"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"}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { SriMensaje } from '@timbra-ec/types';
|
|
2
|
+
export declare class SriError extends Error {
|
|
3
|
+
readonly code?: string | undefined;
|
|
4
|
+
readonly mensajes?: SriMensaje[] | undefined;
|
|
5
|
+
constructor(message: string, code?: string | undefined, mensajes?: SriMensaje[] | undefined);
|
|
6
|
+
}
|
|
7
|
+
export declare class SriValidationError extends SriError {
|
|
8
|
+
name: string;
|
|
9
|
+
}
|
|
10
|
+
export declare class SriCertificateError extends SriError {
|
|
11
|
+
name: string;
|
|
12
|
+
}
|
|
13
|
+
export declare class SriSigningError extends SriError {
|
|
14
|
+
name: string;
|
|
15
|
+
}
|
|
16
|
+
export declare class SriSoapError extends SriError {
|
|
17
|
+
name: string;
|
|
18
|
+
}
|
|
19
|
+
export declare class SriTimeoutError extends SriError {
|
|
20
|
+
name: string;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAElD,qBAAa,QAAS,SAAQ,KAAK;aAGf,IAAI,CAAC,EAAE,MAAM;aACb,QAAQ,CAAC,EAAE,UAAU,EAAE;gBAFvC,OAAO,EAAE,MAAM,EACC,IAAI,CAAC,EAAE,MAAM,YAAA,EACb,QAAQ,CAAC,EAAE,UAAU,EAAE,YAAA;CAK1C;AAED,qBAAa,kBAAmB,SAAQ,QAAQ;IACrC,IAAI,SAAuB;CACrC;AAED,qBAAa,mBAAoB,SAAQ,QAAQ;IACtC,IAAI,SAAwB;CACtC;AAED,qBAAa,eAAgB,SAAQ,QAAQ;IAClC,IAAI,SAAoB;CAClC;AAED,qBAAa,YAAa,SAAQ,QAAQ;IAC/B,IAAI,SAAiB;CAC/B;AAED,qBAAa,eAAgB,SAAQ,QAAQ;IAClC,IAAI,SAAoB;CAClC"}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export class SriError extends Error {
|
|
2
|
+
code;
|
|
3
|
+
mensajes;
|
|
4
|
+
constructor(message, code, mensajes) {
|
|
5
|
+
super(message);
|
|
6
|
+
this.code = code;
|
|
7
|
+
this.mensajes = mensajes;
|
|
8
|
+
this.name = 'SriError';
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
export class SriValidationError extends SriError {
|
|
12
|
+
name = 'SriValidationError';
|
|
13
|
+
}
|
|
14
|
+
export class SriCertificateError extends SriError {
|
|
15
|
+
name = 'SriCertificateError';
|
|
16
|
+
}
|
|
17
|
+
export class SriSigningError extends SriError {
|
|
18
|
+
name = 'SriSigningError';
|
|
19
|
+
}
|
|
20
|
+
export class SriSoapError extends SriError {
|
|
21
|
+
name = 'SriSoapError';
|
|
22
|
+
}
|
|
23
|
+
export class SriTimeoutError extends SriError {
|
|
24
|
+
name = 'SriTimeoutError';
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,QAAS,SAAQ,KAAK;IAGf;IACA;IAHlB,YACE,OAAe,EACC,IAAa,EACb,QAAuB;QAEvC,KAAK,CAAC,OAAO,CAAC,CAAA;QAHE,SAAI,GAAJ,IAAI,CAAS;QACb,aAAQ,GAAR,QAAQ,CAAe;QAGvC,IAAI,CAAC,IAAI,GAAG,UAAU,CAAA;IACxB,CAAC;CACF;AAED,MAAM,OAAO,kBAAmB,SAAQ,QAAQ;IACrC,IAAI,GAAG,oBAAoB,CAAA;CACrC;AAED,MAAM,OAAO,mBAAoB,SAAQ,QAAQ;IACtC,IAAI,GAAG,qBAAqB,CAAA;CACtC;AAED,MAAM,OAAO,eAAgB,SAAQ,QAAQ;IAClC,IAAI,GAAG,iBAAiB,CAAA;CAClC;AAED,MAAM,OAAO,YAAa,SAAQ,QAAQ;IAC/B,IAAI,GAAG,cAAc,CAAA;CAC/B;AAED,MAAM,OAAO,eAAgB,SAAQ,QAAQ;IAClC,IAAI,GAAG,iBAAiB,CAAA;CAClC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export { SRI_URLS } from '@timbra-ec/types';
|
|
2
|
+
export { generateClaveAcceso } from './clave-acceso.js';
|
|
3
|
+
export type { ClaveAccesoInput } from './clave-acceso.js';
|
|
4
|
+
export { buildFacturaXml, buildNotaCreditoXml, buildNotaDebitoXml, buildGuiaRemisionXml, buildRetencionXml, buildAtsXml, } from './xml/builder.js';
|
|
5
|
+
export type { InfoTributariaInput, NotaCreditoInput, NotaDebitoInput, MotivoDebito, GuiaRemisionInput, Destinatario, RetencionInput, RetencionDetalle, AtsInput, AtsCompra, AtsVenta, } from './xml/types.js';
|
|
6
|
+
export { parseCertificate, validateCertificate } from './signing/certificate.js';
|
|
7
|
+
export type { ParsedCertificate, CertificateMetadata } from './signing/certificate.js';
|
|
8
|
+
export { signXml } from './signing/xades-bes.js';
|
|
9
|
+
export { submitComprobante } from './soap/recepcion.js';
|
|
10
|
+
export { queryAutorizacion } from './soap/autorizacion.js';
|
|
11
|
+
export type { PollOptions } from './soap/autorizacion.js';
|
|
12
|
+
export { SriError, SriValidationError, SriCertificateError, SriSigningError, SriSoapError, SriTimeoutError, } from './errors.js';
|
|
13
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAE3C,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AACvD,YAAY,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AAEzD,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,kBAAkB,EAClB,oBAAoB,EACpB,iBAAiB,EACjB,WAAW,GACZ,MAAM,kBAAkB,CAAA;AAEzB,YAAY,EACV,mBAAmB,EACnB,gBAAgB,EAChB,eAAe,EACf,YAAY,EACZ,iBAAiB,EACjB,YAAY,EACZ,cAAc,EACd,gBAAgB,EAChB,QAAQ,EACR,SAAS,EACT,QAAQ,GACT,MAAM,gBAAgB,CAAA;AAEvB,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAA;AAChF,YAAY,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAA;AAEtF,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAA;AAEhD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAEvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAC1D,YAAY,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAA;AAEzD,OAAO,EACL,QAAQ,EACR,kBAAkB,EAClB,mBAAmB,EACnB,eAAe,EACf,YAAY,EACZ,eAAe,GAChB,MAAM,aAAa,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// @timbra-ec/sri — SRI SOAP integration
|
|
2
|
+
// XML generation, XAdES-BES signing, SOAP client, clave de acceso
|
|
3
|
+
export { SRI_URLS } from '@timbra-ec/types';
|
|
4
|
+
export { generateClaveAcceso } from './clave-acceso.js';
|
|
5
|
+
export { buildFacturaXml, buildNotaCreditoXml, buildNotaDebitoXml, buildGuiaRemisionXml, buildRetencionXml, buildAtsXml, } from './xml/builder.js';
|
|
6
|
+
export { parseCertificate, validateCertificate } from './signing/certificate.js';
|
|
7
|
+
export { signXml } from './signing/xades-bes.js';
|
|
8
|
+
export { submitComprobante } from './soap/recepcion.js';
|
|
9
|
+
export { queryAutorizacion } from './soap/autorizacion.js';
|
|
10
|
+
export { SriError, SriValidationError, SriCertificateError, SriSigningError, SriSoapError, SriTimeoutError, } from './errors.js';
|
|
11
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,wCAAwC;AACxC,kEAAkE;AAElE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAE3C,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AAGvD,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,kBAAkB,EAClB,oBAAoB,EACpB,iBAAiB,EACjB,WAAW,GACZ,MAAM,kBAAkB,CAAA;AAgBzB,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAA;AAGhF,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAA;AAEhD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAEvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAG1D,OAAO,EACL,QAAQ,EACR,kBAAkB,EAClB,mBAAmB,EACnB,eAAe,EACf,YAAY,EACZ,eAAe,GAChB,MAAM,aAAa,CAAA"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import forge from 'node-forge';
|
|
2
|
+
export interface CertificateMetadata {
|
|
3
|
+
commonName: string;
|
|
4
|
+
issuer: string;
|
|
5
|
+
serialNumber: string;
|
|
6
|
+
validFrom: Date;
|
|
7
|
+
validTo: Date;
|
|
8
|
+
/** RUC extracted from subject fields, if present */
|
|
9
|
+
ruc: string | null;
|
|
10
|
+
}
|
|
11
|
+
export interface ParsedCertificate {
|
|
12
|
+
privateKey: forge.pki.rsa.PrivateKey;
|
|
13
|
+
certificate: forge.pki.Certificate;
|
|
14
|
+
chain: forge.pki.Certificate[];
|
|
15
|
+
metadata: CertificateMetadata;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Parse a PKCS#12 (.p12) certificate file.
|
|
19
|
+
* Extracts private key, certificate, chain, and metadata.
|
|
20
|
+
*/
|
|
21
|
+
export declare function parseCertificate(p12Buffer: Buffer, password: string): ParsedCertificate;
|
|
22
|
+
/**
|
|
23
|
+
* Validate that a parsed certificate is not expired.
|
|
24
|
+
* Throws SriCertificateError if the certificate has expired.
|
|
25
|
+
*/
|
|
26
|
+
export declare function validateCertificate(cert: ParsedCertificate): void;
|
|
27
|
+
//# sourceMappingURL=certificate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"certificate.d.ts","sourceRoot":"","sources":["../../src/signing/certificate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,YAAY,CAAA;AAG9B,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAA;IAClB,MAAM,EAAE,MAAM,CAAA;IACd,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,IAAI,CAAA;IACf,OAAO,EAAE,IAAI,CAAA;IACb,oDAAoD;IACpD,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;CACnB;AAED,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,UAAU,CAAA;IACpC,WAAW,EAAE,KAAK,CAAC,GAAG,CAAC,WAAW,CAAA;IAClC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,WAAW,EAAE,CAAA;IAC9B,QAAQ,EAAE,mBAAmB,CAAA;CAC9B;AAiBD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,iBAAiB,CA+CvF;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,iBAAiB,GAAG,IAAI,CAUjE"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import forge from 'node-forge';
|
|
2
|
+
import { SriCertificateError } from '../errors.js';
|
|
3
|
+
/** Try to extract a 13-digit RUC from certificate subject fields */
|
|
4
|
+
function extractRuc(cert) {
|
|
5
|
+
const fields = cert.subject.attributes;
|
|
6
|
+
for (const field of fields) {
|
|
7
|
+
const value = String(field.value ?? '');
|
|
8
|
+
const match = value.match(/\d{13}/);
|
|
9
|
+
if (match)
|
|
10
|
+
return match[0];
|
|
11
|
+
}
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
function formatDN(attrs) {
|
|
15
|
+
return attrs.map((a) => `${a.shortName ?? a.name}=${a.value}`).join(', ');
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Parse a PKCS#12 (.p12) certificate file.
|
|
19
|
+
* Extracts private key, certificate, chain, and metadata.
|
|
20
|
+
*/
|
|
21
|
+
export function parseCertificate(p12Buffer, password) {
|
|
22
|
+
let p12Asn1;
|
|
23
|
+
try {
|
|
24
|
+
const p12Der = forge.util.decode64(p12Buffer.toString('base64'));
|
|
25
|
+
p12Asn1 = forge.asn1.fromDer(p12Der);
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
throw new SriCertificateError('Invalid PKCS#12 file format');
|
|
29
|
+
}
|
|
30
|
+
let p12;
|
|
31
|
+
try {
|
|
32
|
+
p12 = forge.pkcs12.pkcs12FromAsn1(p12Asn1, password);
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
throw new SriCertificateError('Wrong certificate password or corrupted PKCS#12 file');
|
|
36
|
+
}
|
|
37
|
+
// Extract private key
|
|
38
|
+
const keyBags = p12.getBags({ bagType: forge.pki.oids.pkcs8ShroudedKeyBag });
|
|
39
|
+
const keyBag = keyBags[forge.pki.oids.pkcs8ShroudedKeyBag];
|
|
40
|
+
if (!keyBag || keyBag.length === 0 || !keyBag[0]?.key) {
|
|
41
|
+
throw new SriCertificateError('No private key found in PKCS#12 file');
|
|
42
|
+
}
|
|
43
|
+
const privateKey = keyBag[0].key;
|
|
44
|
+
// Extract certificates
|
|
45
|
+
const certBags = p12.getBags({ bagType: forge.pki.oids.certBag });
|
|
46
|
+
const certs = certBags[forge.pki.oids.certBag];
|
|
47
|
+
if (!certs || certs.length === 0 || !certs[0]?.cert) {
|
|
48
|
+
throw new SriCertificateError('No certificate found in PKCS#12 file');
|
|
49
|
+
}
|
|
50
|
+
const certificate = certs[0].cert;
|
|
51
|
+
const chain = certs
|
|
52
|
+
.slice(1)
|
|
53
|
+
.filter((b) => b.cert != null)
|
|
54
|
+
.map((b) => b.cert);
|
|
55
|
+
const metadata = {
|
|
56
|
+
commonName: certificate.subject.getField('CN')?.value ?? '',
|
|
57
|
+
issuer: formatDN(certificate.issuer.attributes),
|
|
58
|
+
serialNumber: certificate.serialNumber,
|
|
59
|
+
validFrom: certificate.validity.notBefore,
|
|
60
|
+
validTo: certificate.validity.notAfter,
|
|
61
|
+
ruc: extractRuc(certificate),
|
|
62
|
+
};
|
|
63
|
+
return { privateKey, certificate, chain, metadata };
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Validate that a parsed certificate is not expired.
|
|
67
|
+
* Throws SriCertificateError if the certificate has expired.
|
|
68
|
+
*/
|
|
69
|
+
export function validateCertificate(cert) {
|
|
70
|
+
const now = new Date();
|
|
71
|
+
if (now > cert.metadata.validTo) {
|
|
72
|
+
throw new SriCertificateError(`Certificate expired on ${cert.metadata.validTo.toISOString()}`);
|
|
73
|
+
}
|
|
74
|
+
if (now < cert.metadata.validFrom) {
|
|
75
|
+
throw new SriCertificateError(`Certificate not yet valid, starts ${cert.metadata.validFrom.toISOString()}`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=certificate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"certificate.js","sourceRoot":"","sources":["../../src/signing/certificate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ParsedCertificate } from './certificate.js';
|
|
2
|
+
/**
|
|
3
|
+
* Sign an XML document using XAdES-BES as required by Ecuador's SRI.
|
|
4
|
+
*
|
|
5
|
+
* The XML must have `id="comprobante"` on its root element.
|
|
6
|
+
* Uses SHA-1 digest and RSA-SHA1 signature (SRI requirement).
|
|
7
|
+
* The `<ds:Signature>` is inserted as the last child of the root element.
|
|
8
|
+
*/
|
|
9
|
+
export declare function signXml(xml: string, certificate: ParsedCertificate): string;
|
|
10
|
+
//# sourceMappingURL=xades-bes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"xades-bes.d.ts","sourceRoot":"","sources":["../../src/signing/xades-bes.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AA0DzD;;;;;;GAMG;AACH,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,iBAAiB,GAAG,MAAM,CAuH3E"}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import forge from 'node-forge';
|
|
2
|
+
import { DOMParser, XMLSerializer } from '@xmldom/xmldom';
|
|
3
|
+
import * as xmlCrypto from 'xml-crypto';
|
|
4
|
+
import { SriSigningError } from '../errors.js';
|
|
5
|
+
const DS_NS = 'http://www.w3.org/2000/09/xmldsig#';
|
|
6
|
+
const ETSI_NS = 'http://uri.etsi.org/01903/v1.3.2#';
|
|
7
|
+
const C14N_ALGO = 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315';
|
|
8
|
+
const SHA1_ALGO = 'http://www.w3.org/2000/09/xmldsig#sha1';
|
|
9
|
+
const RSA_SHA1_ALGO = 'http://www.w3.org/2000/09/xmldsig#rsa-sha1';
|
|
10
|
+
const ENVELOPED_ALGO = 'http://www.w3.org/2000/09/xmldsig#enveloped-signature';
|
|
11
|
+
/** Compute SHA-1 digest and return base64-encoded result */
|
|
12
|
+
function sha1Base64(data) {
|
|
13
|
+
const md = forge.md.sha1.create();
|
|
14
|
+
md.update(data, 'utf8');
|
|
15
|
+
return forge.util.encode64(md.digest().getBytes());
|
|
16
|
+
}
|
|
17
|
+
/** Canonicalize an XML node using C14N 1.0 */
|
|
18
|
+
function canonicalize(node) {
|
|
19
|
+
const c14n = new xmlCrypto.C14nCanonicalization();
|
|
20
|
+
return c14n.process(node, { defaultNsForPrefix: {}, ancestorNamespaces: [] });
|
|
21
|
+
}
|
|
22
|
+
/** Get base64-encoded DER certificate */
|
|
23
|
+
function certToBase64(cert) {
|
|
24
|
+
const asn1 = forge.pki.certificateToAsn1(cert);
|
|
25
|
+
const der = forge.asn1.toDer(asn1).getBytes();
|
|
26
|
+
return forge.util.encode64(der);
|
|
27
|
+
}
|
|
28
|
+
/** Get RSA modulus as base64 */
|
|
29
|
+
function getModulus(key) {
|
|
30
|
+
const n = key.n;
|
|
31
|
+
return forge.util.encode64(forge.util.hexToBytes(n.toString(16)));
|
|
32
|
+
}
|
|
33
|
+
/** Get RSA public exponent as base64 */
|
|
34
|
+
function getExponent(key) {
|
|
35
|
+
const e = key.e;
|
|
36
|
+
return forge.util.encode64(forge.util.hexToBytes(e.toString(16)));
|
|
37
|
+
}
|
|
38
|
+
/** RSA-SHA1 sign data and return base64 signature */
|
|
39
|
+
function rsaSha1Sign(data, privateKey) {
|
|
40
|
+
const md = forge.md.sha1.create();
|
|
41
|
+
md.update(data, 'utf8');
|
|
42
|
+
const signature = privateKey.sign(md);
|
|
43
|
+
return forge.util.encode64(signature);
|
|
44
|
+
}
|
|
45
|
+
/** Format issuer DN in RFC 2253 format for XAdES */
|
|
46
|
+
function issuerDN(cert) {
|
|
47
|
+
return cert.issuer.attributes
|
|
48
|
+
.reverse()
|
|
49
|
+
.map((a) => `${a.shortName ?? a.name}=${a.value}`)
|
|
50
|
+
.join(',');
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Sign an XML document using XAdES-BES as required by Ecuador's SRI.
|
|
54
|
+
*
|
|
55
|
+
* The XML must have `id="comprobante"` on its root element.
|
|
56
|
+
* Uses SHA-1 digest and RSA-SHA1 signature (SRI requirement).
|
|
57
|
+
* The `<ds:Signature>` is inserted as the last child of the root element.
|
|
58
|
+
*/
|
|
59
|
+
export function signXml(xml, certificate) {
|
|
60
|
+
const { privateKey, certificate: cert } = certificate;
|
|
61
|
+
const parser = new DOMParser();
|
|
62
|
+
const doc = parser.parseFromString(xml, 'text/xml');
|
|
63
|
+
const root = doc.documentElement;
|
|
64
|
+
if (!root) {
|
|
65
|
+
throw new SriSigningError('Invalid XML: no root element');
|
|
66
|
+
}
|
|
67
|
+
const signingTime = new Date().toISOString().replace('Z', '-05:00');
|
|
68
|
+
const certBase64 = certToBase64(cert);
|
|
69
|
+
const certDigest = sha1Base64(forge.asn1.toDer(forge.pki.certificateToAsn1(cert)).getBytes());
|
|
70
|
+
const issuerName = issuerDN(cert);
|
|
71
|
+
const serialNumber = cert.serialNumber;
|
|
72
|
+
// --- Build QualifyingProperties ---
|
|
73
|
+
const signedPropsXml = [
|
|
74
|
+
`<etsi:SignedProperties xmlns:etsi="${ETSI_NS}" xmlns:ds="${DS_NS}" Id="SignedProperties">`,
|
|
75
|
+
`<etsi:SignedSignatureProperties>`,
|
|
76
|
+
`<etsi:SigningTime>${signingTime}</etsi:SigningTime>`,
|
|
77
|
+
`<etsi:SigningCertificate>`,
|
|
78
|
+
`<etsi:Cert>`,
|
|
79
|
+
`<etsi:CertDigest>`,
|
|
80
|
+
`<ds:DigestMethod Algorithm="${SHA1_ALGO}"/>`,
|
|
81
|
+
`<ds:DigestValue>${certDigest}</ds:DigestValue>`,
|
|
82
|
+
`</etsi:CertDigest>`,
|
|
83
|
+
`<etsi:IssuerSerial>`,
|
|
84
|
+
`<ds:X509IssuerName>${issuerName}</ds:X509IssuerName>`,
|
|
85
|
+
`<ds:X509SerialNumber>${parseInt(serialNumber, 16)}</ds:X509SerialNumber>`,
|
|
86
|
+
`</etsi:IssuerSerial>`,
|
|
87
|
+
`</etsi:Cert>`,
|
|
88
|
+
`</etsi:SigningCertificate>`,
|
|
89
|
+
`</etsi:SignedSignatureProperties>`,
|
|
90
|
+
`<etsi:SignedDataObjectProperties>`,
|
|
91
|
+
`<etsi:DataObjectFormat ObjectReference="#Reference-ID">`,
|
|
92
|
+
`<etsi:Description>contenido comprobante</etsi:Description>`,
|
|
93
|
+
`<etsi:MimeType>text/xml</etsi:MimeType>`,
|
|
94
|
+
`</etsi:DataObjectFormat>`,
|
|
95
|
+
`</etsi:SignedDataObjectProperties>`,
|
|
96
|
+
`</etsi:SignedProperties>`,
|
|
97
|
+
].join('');
|
|
98
|
+
// --- Build KeyInfo ---
|
|
99
|
+
const keyInfoXml = [
|
|
100
|
+
`<ds:KeyInfo xmlns:ds="${DS_NS}" Id="Certificate">`,
|
|
101
|
+
`<ds:X509Data>`,
|
|
102
|
+
`<ds:X509Certificate>${certBase64}</ds:X509Certificate>`,
|
|
103
|
+
`</ds:X509Data>`,
|
|
104
|
+
`<ds:KeyValue>`,
|
|
105
|
+
`<ds:RSAKeyValue>`,
|
|
106
|
+
`<ds:Modulus>${getModulus(privateKey)}</ds:Modulus>`,
|
|
107
|
+
`<ds:Exponent>${getExponent(privateKey)}</ds:Exponent>`,
|
|
108
|
+
`</ds:RSAKeyValue>`,
|
|
109
|
+
`</ds:KeyValue>`,
|
|
110
|
+
`</ds:KeyInfo>`,
|
|
111
|
+
].join('');
|
|
112
|
+
// --- Compute digests ---
|
|
113
|
+
// 1. Document digest (with enveloped-signature transform — digest the doc as-is since signature isn't inserted yet)
|
|
114
|
+
const docDigest = sha1Base64(canonicalize(root));
|
|
115
|
+
// 2. SignedProperties digest
|
|
116
|
+
const signedPropsDoc = parser.parseFromString(signedPropsXml, 'text/xml');
|
|
117
|
+
const signedPropsDigest = sha1Base64(canonicalize(signedPropsDoc));
|
|
118
|
+
// 3. KeyInfo digest
|
|
119
|
+
const keyInfoDoc = parser.parseFromString(keyInfoXml, 'text/xml');
|
|
120
|
+
const keyInfoDigest = sha1Base64(canonicalize(keyInfoDoc));
|
|
121
|
+
// --- Build SignedInfo ---
|
|
122
|
+
const signedInfoXml = [
|
|
123
|
+
`<ds:SignedInfo xmlns:ds="${DS_NS}" Id="SignedInfo">`,
|
|
124
|
+
`<ds:CanonicalizationMethod Algorithm="${C14N_ALGO}"/>`,
|
|
125
|
+
`<ds:SignatureMethod Algorithm="${RSA_SHA1_ALGO}"/>`,
|
|
126
|
+
`<ds:Reference Id="Reference-ID" URI="#comprobante">`,
|
|
127
|
+
`<ds:Transforms>`,
|
|
128
|
+
`<ds:Transform Algorithm="${ENVELOPED_ALGO}"/>`,
|
|
129
|
+
`</ds:Transforms>`,
|
|
130
|
+
`<ds:DigestMethod Algorithm="${SHA1_ALGO}"/>`,
|
|
131
|
+
`<ds:DigestValue>${docDigest}</ds:DigestValue>`,
|
|
132
|
+
`</ds:Reference>`,
|
|
133
|
+
`<ds:Reference URI="#SignedProperties" Type="http://uri.etsi.org/01903#SignedProperties">`,
|
|
134
|
+
`<ds:DigestMethod Algorithm="${SHA1_ALGO}"/>`,
|
|
135
|
+
`<ds:DigestValue>${signedPropsDigest}</ds:DigestValue>`,
|
|
136
|
+
`</ds:Reference>`,
|
|
137
|
+
`<ds:Reference URI="#Certificate">`,
|
|
138
|
+
`<ds:DigestMethod Algorithm="${SHA1_ALGO}"/>`,
|
|
139
|
+
`<ds:DigestValue>${keyInfoDigest}</ds:DigestValue>`,
|
|
140
|
+
`</ds:Reference>`,
|
|
141
|
+
`</ds:SignedInfo>`,
|
|
142
|
+
].join('');
|
|
143
|
+
// --- Sign ---
|
|
144
|
+
const signedInfoDoc = parser.parseFromString(signedInfoXml, 'text/xml');
|
|
145
|
+
const canonicalSignedInfo = canonicalize(signedInfoDoc);
|
|
146
|
+
const signatureValue = rsaSha1Sign(canonicalSignedInfo, privateKey);
|
|
147
|
+
// --- Assemble full Signature element ---
|
|
148
|
+
const signatureXml = [
|
|
149
|
+
`<ds:Signature xmlns:ds="${DS_NS}" xmlns:etsi="${ETSI_NS}" Id="Signature">`,
|
|
150
|
+
signedInfoXml,
|
|
151
|
+
`<ds:SignatureValue>${signatureValue}</ds:SignatureValue>`,
|
|
152
|
+
keyInfoXml,
|
|
153
|
+
`<ds:Object Id="XadesObjectId">`,
|
|
154
|
+
`<etsi:QualifyingProperties Target="#Signature">`,
|
|
155
|
+
signedPropsXml,
|
|
156
|
+
`</etsi:QualifyingProperties>`,
|
|
157
|
+
`</ds:Object>`,
|
|
158
|
+
`</ds:Signature>`,
|
|
159
|
+
].join('');
|
|
160
|
+
// --- Insert signature into document ---
|
|
161
|
+
const sigDoc = parser.parseFromString(signatureXml, 'text/xml');
|
|
162
|
+
const imported = doc.importNode(sigDoc.documentElement, true);
|
|
163
|
+
root.appendChild(imported);
|
|
164
|
+
return new XMLSerializer().serializeToString(doc);
|
|
165
|
+
}
|
|
166
|
+
//# sourceMappingURL=xades-bes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"xades-bes.js","sourceRoot":"","sources":["../../src/signing/xades-bes.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { SriEnvironment, SriAutorizacionResponse } from '@timbra-ec/types';
|
|
2
|
+
export interface PollOptions {
|
|
3
|
+
/** Maximum number of authorization queries (default: 10) */
|
|
4
|
+
maxAttempts?: number;
|
|
5
|
+
/** Milliseconds between retries (default: 2000) */
|
|
6
|
+
intervalMs?: number;
|
|
7
|
+
/** AbortSignal for cancellation */
|
|
8
|
+
signal?: AbortSignal;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Query SRI for the authorization status of a document.
|
|
12
|
+
*
|
|
13
|
+
* Polls the autorizacionComprobante service using the clave de acceso.
|
|
14
|
+
* Retries when status is EN PROCESO, up to maxAttempts times.
|
|
15
|
+
*
|
|
16
|
+
* Returns the authorization response when AUTORIZADO.
|
|
17
|
+
* Throws SriSoapError when NO AUTORIZADO.
|
|
18
|
+
* Throws SriTimeoutError when max attempts exhausted.
|
|
19
|
+
*/
|
|
20
|
+
export declare function queryAutorizacion(claveAcceso: string, environment: SriEnvironment, options?: PollOptions): Promise<SriAutorizacionResponse>;
|
|
21
|
+
//# sourceMappingURL=autorizacion.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"autorizacion.d.ts","sourceRoot":"","sources":["../../src/soap/autorizacion.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,uBAAuB,EAAc,MAAM,kBAAkB,CAAA;AAK3F,MAAM,WAAW,WAAW;IAC1B,4DAA4D;IAC5D,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,mDAAmD;IACnD,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,mCAAmC;IACnC,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB;AA4CD;;;;;;;;;GASG;AACH,wBAAsB,iBAAiB,CACrC,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,cAAc,EAC3B,OAAO,CAAC,EAAE,WAAW,GACpB,OAAO,CAAC,uBAAuB,CAAC,CAmElC"}
|