# html2pdf-secure
A Rust crate for converting HTML to password-protected PDF files using headless Chrome and robust encryption.
[](https://crates.io/crates/html2pdf-secure)
[](https://docs.rs/html2pdf-secure)
[](LICENSE)
## Features
- 🌐 **HTML to PDF Conversion**: Convert HTML content, files, or URLs to PDF using headless Chrome
- 🔒 **Password Protection**: Add user and owner passwords to generated PDFs
- 🛡️ **Multiple Encryption Levels**: Support for various encryption standards (40-bit, 128-bit, AES-128, AES-256)
- ⚙️ **Customizable PDF Options**: Control page format, orientation, margins, and more
- 🔧 **Flexible Permissions**: Fine-grained control over PDF permissions (printing, copying, editing, etc.)
- 🚀 **Async Support**: Built with async/await for non-blocking operations
- 🔗 **External Tool Integration**: Optional integration with qpdf for stronger encryption
## Quick Start
Add this to your `Cargo.toml`:
```toml
[dependencies]
html2pdf-secure = "0.1"
tokio = { version = "1.0", features = ["full"] }
```
### Basic Usage
```rust
use html2pdf_secure::{Html2PdfConverter, PdfOptions, PasswordOptions};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create converter
let converter = Html2PdfConverter::new().await?;
// HTML content
let html = "<html><body><h1>Hello, Secure World!</h1></body></html>";
// Configure password protection (uses AES-256 by default)
let password_options = PasswordOptions::new("user123", "owner456");
// Convert to protected PDF (requires qpdf)
let pdf_data = converter
.convert_html_to_protected_pdf(html, PdfOptions::default(), password_options)
.await?;
// Save to file
std::fs::write("secure_document.pdf", pdf_data)?;
Ok(())
}
```
## Installation Requirements
### Basic Requirements
- **Rust 1.85+**: Required for Rust 2024 edition features
- **Chrome/Chromium**: Automatically downloaded by headless_chrome crate
### Required: qpdf for Password Protection
**Important**: Password protection requires qpdf to be installed. Without qpdf, PDFs will be generated without encryption.
```bash
# Ubuntu/Debian
sudo apt-get install qpdf
# macOS
brew install qpdf
# Windows
# Download from https://qpdf.sourceforge.io/
```
To verify qpdf installation:
```bash
qpdf --version
```
## Examples
### Convert URL to Protected PDF
```rust
use html2pdf_secure::{Html2PdfConverter, PdfOptions, PasswordOptions, PageFormat};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let converter = Html2PdfConverter::new().await?;
let pdf_options = PdfOptions {
page_format: PageFormat::A4,
print_background: true,
..Default::default()
};
let password_options = PasswordOptions::new("secret", "admin");
let pdf_data = converter
.convert_url_to_protected_pdf(
"https://www.rust-lang.org/",
pdf_options,
password_options
)
.await?;
std::fs::write("rust_website.pdf", pdf_data)?;
Ok(())
}
```
### Advanced Configuration
```rust
use html2pdf_secure::{
Html2PdfConverter, PdfOptions, PasswordOptions,
EncryptionLevel, PdfPermissions, PageFormat, PageOrientation
};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let converter = Html2PdfConverter::new().await?;
// Advanced PDF options
let pdf_options = PdfOptions {
page_format: PageFormat::Letter,
orientation: PageOrientation::Landscape,
print_background: true,
scale: 0.8,
..Default::default()
};
// Strong encryption with restricted permissions
let password_options = PasswordOptions::new("user_pass", "owner_pass")
.with_encryption_level(EncryptionLevel::Aes256)
.with_permissions(PdfPermissions {
allow_printing: false,
allow_copy: false,
allow_modify_contents: false,
..Default::default()
});
let html = "<html><body><h1>Highly Secure Document</h1></body></html>";
// Use qpdf for strongest encryption (if available)
let pdf_data = converter
.convert_html_to_protected_pdf_with_qpdf(
html,
pdf_options,
password_options,
Some("/tmp")
)
.await?;
std::fs::write("highly_secure.pdf", pdf_data)?;
Ok(())
}
```
## API Reference
### Core Types
- **`Html2PdfConverter`**: Main converter for HTML to PDF operations
- **`PdfOptions`**: Configuration for PDF generation (page size, margins, etc.)
- **`PasswordOptions`**: Password and encryption configuration
- **`EncryptionLevel`**: Encryption strength options
- **`PdfPermissions`**: Fine-grained permission control
### Conversion Methods
- `convert_html_to_pdf()`: Convert HTML string to PDF
- `convert_html_file_to_pdf()`: Convert HTML file to PDF
- `convert_url_to_pdf()`: Convert web page to PDF
- `convert_html_to_protected_pdf()`: Convert HTML to password-protected PDF
- `convert_html_to_protected_pdf_with_qpdf()`: Convert with qpdf encryption
## Encryption Levels
| `Standard40` | RC4 40-bit | 40-bit | Basic |
| `Standard128` | RC4 128-bit | 128-bit | Good |
| `Aes128` | AES 128-bit | 128-bit | Strong |
| `Aes256` | AES 256-bit | 256-bit | Very Strong |
## Security Considerations
### Encryption Behavior
**Important**: This library requires qpdf for password protection:
- **With qpdf installed**: PDFs are properly encrypted with AES-256 by default
- **Without qpdf**: PDFs are generated **without encryption** and a warning is logged
- **Fallback behavior**: The library will attempt qpdf first, then fall back to unencrypted PDF
### Encryption Levels
The library supports multiple encryption levels when qpdf is available:
- **AES-256** (default): Strongest encryption, recommended for all use cases
- **AES-128**: Strong encryption, good for most applications
- **128-bit RC4**: Legacy encryption, requires `--allow-weak-crypto` flag
- **40-bit RC4**: Very weak encryption, requires `--allow-weak-crypto` flag
### Production Recommendations
For production use with sensitive data:
- **Always install qpdf** for proper encryption
- **Use AES-256** (default) or AES-128 encryption levels
- **Avoid RC4** encryption levels (weak and deprecated)
- **Test encryption** by verifying password requirements
## Error Handling
```rust
use html2pdf_secure::{Html2PdfConverter, Html2PdfError};
#[tokio::main]
async fn main() {
let converter = Html2PdfConverter::new().await.unwrap();
match converter.convert_html_to_pdf("<html></html>", Default::default()).await {
Ok(pdf_data) => println!("Success: {} bytes", pdf_data.len()),
Err(Html2PdfError::ChromeError(msg)) => eprintln!("Chrome error: {}", msg),
Err(Html2PdfError::EncryptionError(msg)) => eprintln!("Encryption error: {}", msg),
Err(e) => eprintln!("Other error: {}", e),
}
}
```
## Examples
Run the included examples:
```bash
# Basic usage
cargo run --example basic_usage
# qpdf encryption (requires qpdf installed)
cargo run --example qpdf_encryption
# URL to PDF conversion
cargo run --example url_to_pdf
```
## Testing
Run the test suite:
```bash
cargo test
```
## Performance
The crate is designed for efficiency:
- Reuses Chrome instances when possible
- Supports concurrent PDF generation
- Minimal memory footprint for PDF processing
## Troubleshooting
### Chrome/Chromium Issues
If you encounter Chrome-related errors:
1. Ensure sufficient system resources
2. Check Chrome installation
3. Verify network connectivity for URL conversions
### qpdf Integration
If qpdf encryption fails:
1. Verify qpdf installation: `qpdf --version`
2. Check file permissions in temp directory
3. Ensure sufficient disk space
### Common Issues
- **"Chrome browser error"**: Usually indicates Chrome startup issues
- **"Encryption error"**: Check password requirements and qpdf availability
- **"Invalid input"**: Verify HTML syntax and file paths
## Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
### Development Setup
```bash
git clone https://github.com/yourusername/html2pdf-secure
cd html2pdf-secure
cargo build
cargo test
```
## License
This project is licensed under either of
- Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
at your option.