UNPKG

dte-signer-sv

Version:

Sign Digital Tax Documents (DTE) for El Salvador's Ministry of Finance

280 lines (211 loc) 7.1 kB
# dte-signer-sv [![npm version](https://badge.fury.io/js/dte-signer-sv.svg)](https://badge.fury.io/js/dte-signer-sv) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) A Node.js package for signing Digital Tax Documents (DTE) for El Salvador's Ministry of Finance (Ministerio de Hacienda). This package provides a simple interface to digitally sign DTEs using certificates issued by the government. ## Features - 🔐 Sign DTEs using government-issued certificates - 📝 Support for XML certificate format (.crt files) - 🔑 RSA-SHA512 (RS512) digital signatures - 📦 TypeScript support with full type definitions - ✅ Comprehensive test coverage - 🚀 Zero runtime dependencies (only `xml2js` and `node-jose`) ## Installation ```bash npm install dte-signer-sv ``` Or using yarn: ```bash yarn add dte-signer-sv ``` ## Usage ### Basic Example ```javascript import { signDTE } from 'dte-signer-sv'; // Your DTE object following MH specifications const dte = { identificacion: { version: 1, ambiente: "00", tipoDte: "01", numeroControl: "DTE-01-00000001-000000000000001", codigoGeneracion: "UUID-HERE", tipoModelo: 1, tipoOperacion: 1, tipoContingencia: null, motivoContigencia: null, fecEmi: "2024-01-01", horEmi: "10:30:00", tipoMoneda: "USD" }, // ... rest of your DTE structure }; // Sign the DTE const signedDTE = await signDTE({ dte: dte, privatePassword: "yourPrivateKeyPassword", certificate: "./path/to/certificate.crt", loadCertificateFromPath: true }); console.log(signedDTE); // JWS compact format string ``` ### Using Certificate Content Directly ```javascript import { signDTE } from 'dte-signer-sv'; import fs from 'fs'; // Read certificate content const certificateXML = fs.readFileSync('./certificate.crt', 'utf8'); // Sign the DTE const signedDTE = await signDTE({ dte: myDTEObject, privatePassword: "yourPrivateKeyPassword", certificate: certificateXML, loadCertificateFromPath: false // or omit this parameter }); ``` ## API Reference ### `signDTE(params: SignDTEParams): Promise<string>` Signs a DTE document and returns a JWS (JSON Web Signature) in compact format. #### Parameters | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | `dte` | `object` | Yes | The DTE object to be signed | | `privatePassword` | `string` | Yes | Password for the private key | | `certificate` | `string` | Yes | Certificate XML content or file path | | `loadCertificateFromPath` | `boolean` | No | If true, treats certificate as file path (default: false) | #### Returns Returns a `Promise<string>` that resolves to the signed DTE in JWS compact format (header.payload.signature). #### Throws - `Error("Invalid private password")` - If the provided password is incorrect - File system errors - If certificate file is not found (when using file path) - Parsing errors - If the certificate XML is invalid ## Certificate Format This package works with certificates in the XML format provided by El Salvador's Ministry of Finance. The certificate file (.crt) should contain: - Public key in X.509 format - Private key in PKCS#8 format - Password hash for validation ### Creating Test Certificates For development and testing, you can create test certificates using the script available at: [Create Test Certificate Script](https://gist.github.com/mcalero11/03af55c0e9872407b121dd77cc41f833) ## Integration with MH Systems The signed DTE can be sent to the Ministry of Finance's reception system. The signature is created using: - **Algorithm**: RS512 (RSA signature with SHA-512) - **Format**: JWS Compact Serialization - **Standard**: Compliant with RFC 7515 ## Development ### Prerequisites - Node.js >= 14 - npm or yarn ### Setup 1. Clone the repository: ```bash git clone https://github.com/mcalero11/dte-signer-sv.git cd dte-signer-sv ``` 2. Install dependencies: ```bash npm install ``` 3. Run tests: ```bash npm test ``` 4. Build the package: ```bash npm run build ``` ### Running Tests ```bash # Run all tests npm test # Run tests in watch mode npm test -- --watch # Run tests with coverage npm test -- --coverage ``` ## Examples ### Complete DTE Example ```javascript import { signDTE } from 'dte-signer-sv'; const dte = { identificacion: { version: 1, ambiente: "00", tipoDte: "01", numeroControl: "DTE-01-00000001-000000000000001", codigoGeneracion: "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX", tipoModelo: 1, tipoOperacion: 1, fecEmi: "2024-01-01", horEmi: "10:30:00", tipoMoneda: "USD" }, emisor: { nit: "06142803901234", nrc: "1234567", nombre: "EMPRESA DE PRUEBA S.A. DE C.V.", codActividad: "01234", descActividad: "Venta de productos", telefono: "2234-5678", correo: "info@empresa.com", // ... rest of emisor data }, receptor: { tipoDocumento: "36", numDocumento: "06142803901234", nombre: "CLIENTE DE PRUEBA", // ... rest of receptor data }, // ... rest of DTE structure }; try { const signedDTE = await signDTE({ dte: dte, privatePassword: "mySecurePassword", certificate: "./certificates/company.crt", loadCertificateFromPath: true }); console.log("Successfully signed DTE:", signedDTE); // Send to MH API // await sendToMH(signedDTE); } catch (error) { console.error("Error signing DTE:", error.message); } ``` ### Error Handling ```javascript try { const signedDTE = await signDTE({ dte: myDTE, privatePassword: password, certificate: certificatePath, loadCertificateFromPath: true }); } catch (error) { if (error.message === "Invalid private password") { console.error("The password for the certificate is incorrect"); } else if (error.code === 'ENOENT') { console.error("Certificate file not found"); } else { console.error("Unexpected error:", error); } } ``` ## Contributing Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change. 1. Fork the repository 2. Create your feature branch (`git checkout -b feature/AmazingFeature`) 3. Commit your changes (`git commit -m 'Add some AmazingFeature'`) 4. Push to the branch (`git push origin feature/AmazingFeature`) 5. Open a Pull Request ## License This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. ## Support If you encounter any problems or have questions, please: 1. Check the [issues](https://github.com/mcalero11/dte-signer-sv/issues) page 2. Create a new issue if your problem isn't already listed 3. Provide as much detail as possible ## Acknowledgments - Ministry of Finance of El Salvador for the DTE specifications - The original Java implementation that inspired this Node.js port ## Disclaimer This package is not officially affiliated with or endorsed by the Ministry of Finance of El Salvador. It is an independent implementation based on public specifications.