# 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.
