feat: add PDF encryption feature (#1217)

* Adding PDF encryption option

* LibreOffice
* QPDF
* PDFtk
* pdfcpu

* Update pkg/modules/pdfengines/pdfengines.go

Co-authored-by: Julien Neuhart <neuhart.julien@gmail.com>

* npx prettier

* go fmt

* PR comments

* Update test/integration/scenario/scenario.go

Co-authored-by: Julien Neuhart <neuhart.julien@gmail.com>

* renamed ProtectWithPassword to encrypt

* more clean up

* Use the same input path as requested

* This commit completes the encryption implementation

* Clean up. Added webhook, disable route and download from tests

---------

Co-authored-by: Julien Neuhart <neuhart.julien@gmail.com>
This commit is contained in:
Stevenson Michel
2025-05-27 08:49:24 -04:00
committed by Julien Neuhart
parent 638c4e6b23
commit 99307befdd
23 changed files with 1168 additions and 6 deletions

View File

@@ -18,6 +18,7 @@ type multiPdfEngines struct {
convertEngines []gotenberg.PdfEngine
readMetadataEngines []gotenberg.PdfEngine
writeMetadataEngines []gotenberg.PdfEngine
passwordEngines []gotenberg.PdfEngine
}
func newMultiPdfEngines(
@@ -26,7 +27,8 @@ func newMultiPdfEngines(
flattenEngines,
convertEngines,
readMetadataEngines,
writeMetadataEngines []gotenberg.PdfEngine,
writeMetadataEngines,
passwordEngines []gotenberg.PdfEngine,
) *multiPdfEngines {
return &multiPdfEngines{
mergeEngines: mergeEngines,
@@ -35,6 +37,7 @@ func newMultiPdfEngines(
convertEngines: convertEngines,
readMetadataEngines: readMetadataEngines,
writeMetadataEngines: writeMetadataEngines,
passwordEngines: passwordEngines,
}
}
@@ -206,6 +209,31 @@ func (multi *multiPdfEngines) WriteMetadata(ctx context.Context, logger *zap.Log
return fmt.Errorf("write PDF metadata with multi PDF engines: %w", err)
}
// Encrypt adds password protection to a PDF file using the first available engine
// that supports password protection.
func (multi *multiPdfEngines) Encrypt(ctx context.Context, logger *zap.Logger, inputPath, userPassword, ownerPassword string) error {
var err error
errChan := make(chan error, 1)
for _, engine := range multi.passwordEngines {
go func(engine gotenberg.PdfEngine) {
errChan <- engine.Encrypt(ctx, logger, inputPath, userPassword, ownerPassword)
}(engine)
select {
case protectErr := <-errChan:
errored := multierr.AppendInto(&err, protectErr)
if !errored {
return nil
}
case <-ctx.Done():
return ctx.Err()
}
}
return fmt.Errorf("encrypt PDF using multi PDF engines: %w", err)
}
// Interface guards.
var (
_ gotenberg.PdfEngine = (*multiPdfEngines)(nil)