chore: slight improvement of the encrypt feature to be more in line with others features

This commit is contained in:
Julien Neuhart
2025-05-28 15:21:41 +02:00
parent 99307befdd
commit ba944f9dc2
19 changed files with 318 additions and 797 deletions

View File

@@ -104,7 +104,7 @@ type PdfEngine interface {
// Flatten merges existing annotation appearances with page content,
// effectively deleting the original annotations. This process can flatten
// forms as well, as forms share a relationship with annotations. Note that
// forms as well as forms share a relationship with annotations. Note that
// this operation is irreversible.
Flatten(ctx context.Context, logger *zap.Logger, inputPath string) error

View File

@@ -264,6 +264,11 @@ func convertRoute(libreOffice libreofficeapi.Uno, engine gotenberg.PdfEngine) ap
}
}
err = pdfengines.EncryptPdfStub(ctx, engine, userPassword, ownerPassword, outputPaths)
if err != nil {
return fmt.Errorf("encrypt PDFs: %w", err)
}
if len(outputPaths) > 1 && splitMode == zeroValuedSplitMode {
// If .zip archive, document.docx -> document.docx.pdf.
for i, inputPath := range inputPaths {
@@ -278,11 +283,6 @@ func convertRoute(libreOffice libreofficeapi.Uno, engine gotenberg.PdfEngine) ap
}
}
err = pdfengines.EncryptPdfStub(ctx, engine, userPassword, ownerPassword, outputPaths)
if err != nil {
return fmt.Errorf("encrypt PDFs: %w", err)
}
err = ctx.AddOutputPaths(outputPaths...)
if err != nil {
return fmt.Errorf("add output paths: %w", err)

View File

@@ -177,17 +177,16 @@ func (engine *PdfCpu) Encrypt(ctx context.Context, logger *zap.Logger, inputPath
return errors.New("user password cannot be empty")
}
// If owner password is not provided, use the user password as owner password
if ownerPassword == "" {
ownerPassword = userPassword
}
var args []string
args = append(args, "encrypt")
args = append(args, "-mode", "aes") // Use AES encryption
args = append(args, "-mode", "aes")
args = append(args, "-upw", userPassword)
args = append(args, "-opw", ownerPassword)
args = append(args, "-perm", "all") // Grant all permissions with owner password
args = append(args, "-perm", "all")
args = append(args, inputPath, inputPath)
cmd, err := gotenberg.CommandContext(ctx, logger, engine.binPath, args...)

View File

@@ -41,8 +41,8 @@ func newMultiPdfEngines(
}
}
// Merge tries to merge the given PDFs into a unique PDF thanks to its
// children. If the context is done, it stops and returns an error.
// Merge combines multiple PDF files into a single document using the first
// available engine that supports PDF merging.
func (multi *multiPdfEngines) Merge(ctx context.Context, logger *zap.Logger, inputPaths []string, outputPath string) error {
var err error
errChan := make(chan error, 1)
@@ -71,8 +71,8 @@ type splitResult struct {
err error
}
// Split tries to split at intervals a given PDF thanks to its children. If the
// context is done, it stops and returns an error.
// Split divides the PDF into separate pages using the first available engine
// that supports PDF splitting.
func (multi *multiPdfEngines) Split(ctx context.Context, logger *zap.Logger, mode gotenberg.SplitMode, inputPath, outputDirPath string) ([]string, error) {
var err error
var mu sync.Mutex // to safely append errors.
@@ -102,8 +102,8 @@ func (multi *multiPdfEngines) Split(ctx context.Context, logger *zap.Logger, mod
return nil, fmt.Errorf("split PDF with multi PDF engines: %w", err)
}
// Flatten merges existing annotation appearances with page content, thanks to
// its children. If the context is done, it stops and returns an error
// Flatten merges existing annotation appearances with page content using the
// first available engine that supports flattening.
func (multi *multiPdfEngines) Flatten(ctx context.Context, logger *zap.Logger, inputPath string) error {
var err error
errChan := make(chan error, 1)
@@ -127,8 +127,8 @@ func (multi *multiPdfEngines) Flatten(ctx context.Context, logger *zap.Logger, i
return fmt.Errorf("flatten PDF with multi PDF engines: %w", err)
}
// Convert converts the given PDF to a specific PDF format, thanks to its
// children. If the context is done, it stops and returns an error.
// Convert transforms the given PDF to a specific PDF format using the first
// available engine that supports PDF conversion.
func (multi *multiPdfEngines) Convert(ctx context.Context, logger *zap.Logger, formats gotenberg.PdfFormats, inputPath, outputPath string) error {
var err error
errChan := make(chan error, 1)
@@ -157,6 +157,8 @@ type readMetadataResult struct {
err error
}
// ReadMetadata extracts metadata from a PDF file using the first available
// engine that supports metadata reading.
func (multi *multiPdfEngines) ReadMetadata(ctx context.Context, logger *zap.Logger, inputPath string) (map[string]interface{}, error) {
var err error
var mu sync.Mutex // to safely append errors.
@@ -186,6 +188,8 @@ func (multi *multiPdfEngines) ReadMetadata(ctx context.Context, logger *zap.Logg
return nil, fmt.Errorf("read PDF metadata with multi PDF engines: %w", err)
}
// WriteMetadata embeds metadata into a PDF file using the first available
// engine that supports metadata writing.
func (multi *multiPdfEngines) WriteMetadata(ctx context.Context, logger *zap.Logger, metadata map[string]interface{}, inputPath string) error {
var err error
errChan := make(chan error, 1)
@@ -209,8 +213,8 @@ 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.
// 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)

View File

@@ -210,7 +210,7 @@ func (mod *PdfEngines) SystemMessages() []string {
fmt.Sprintf("convert engines - %s", strings.Join(mod.convertNames[:], " ")),
fmt.Sprintf("read metadata engines - %s", strings.Join(mod.readMetadataNames[:], " ")),
fmt.Sprintf("write metadata engines - %s", strings.Join(mod.writeMetadataNames[:], " ")),
fmt.Sprintf("password protection engines - %s", strings.Join(mod.encryptNames[:], " ")),
fmt.Sprintf("encrypt engines - %s", strings.Join(mod.encryptNames[:], " ")),
}
}

View File

@@ -254,7 +254,6 @@ func WriteMetadataStub(ctx *api.Context, engine gotenberg.PdfEngine, metadata ma
return nil
}
// EncryptPdfStub adds password protection to PDF files.
// FormDataPdfEncrypt extracts encryption parameters from form data.
func FormDataPdfEncrypt(form *api.FormData) (userPassword, ownerPassword string) {
form.String("userPassword", &userPassword, "")
@@ -262,6 +261,7 @@ func FormDataPdfEncrypt(form *api.FormData) (userPassword, ownerPassword string)
return userPassword, ownerPassword
}
// EncryptPdfStub adds password protection to PDF files.
func EncryptPdfStub(ctx *api.Context, engine gotenberg.PdfEngine, userPassword, ownerPassword string, inputPaths []string) error {
if userPassword == "" {
return nil
@@ -459,7 +459,6 @@ func convertRoute(engine gotenberg.PdfEngine) api.Route {
form := ctx.FormData()
pdfFormats := FormDataPdfFormats(form)
userPassword, ownerPassword := FormDataPdfEncrypt(form)
var inputPaths []string
err := form.
@@ -496,11 +495,6 @@ func convertRoute(engine gotenberg.PdfEngine) api.Route {
}
}
err = EncryptPdfStub(ctx, engine, userPassword, ownerPassword, outputPaths)
if err != nil {
return fmt.Errorf("encrypt PDFs: %w", err)
}
err = ctx.AddOutputPaths(outputPaths...)
if err != nil {
return fmt.Errorf("add output paths: %w", err)

View File

@@ -151,7 +151,6 @@ func (engine *PdfTk) Encrypt(ctx context.Context, logger *zap.Logger, inputPath,
return errors.New("user password cannot be empty")
}
// If owner password is not provided, use the user password as owner password
if ownerPassword == "" {
ownerPassword = userPassword
}
@@ -160,14 +159,8 @@ func (engine *PdfTk) Encrypt(ctx context.Context, logger *zap.Logger, inputPath,
args = append(args, inputPath)
args = append(args, "output", inputPath)
args = append(args, "encrypt_128bit")
if userPassword != "" {
args = append(args, "user_pw", userPassword)
}
if ownerPassword != "" {
args = append(args, "owner_pw", ownerPassword)
}
args = append(args, "user_pw", userPassword)
args = append(args, "owner_pw", ownerPassword)
cmd, err := gotenberg.CommandContext(ctx, logger, engine.binPath, args...)
if err != nil {

View File

@@ -178,12 +178,10 @@ func (engine *QPdf) Encrypt(ctx context.Context, logger *zap.Logger, inputPath,
return errors.New("user password cannot be empty")
}
// If owner password is not provided, use the user password as owner password
if ownerPassword == "" {
ownerPassword = userPassword
}
// QPDF command to encrypt a PDF
var args []string
args = append(args, inputPath)
args = append(args, engine.globalArgs...)

View File

@@ -815,6 +815,28 @@ Feature: /forms/chromium/convert/html
Then there should be 1 PDF(s) in the response
Then the response PDF(s) should be flatten
Scenario: POST /forms/chromium/convert/html (Encrypt - user password only)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
| files | testdata/page-1-html/index.html | file |
| userPassword | foo | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then the response PDF(s) should be encrypted
Scenario: POST /forms/chromium/convert/html (Encrypt - both user and owner passwords)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
| files | testdata/page-1-html/index.html | file |
| userPassword | foo | field |
| ownerPassword | bar | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then the response PDF(s) should be encrypted
# FIXME: once decrypt is done, add encrypt and check after the content of the PDF.
Scenario: POST /forms/chromium/convert/html (PDF/A-1b & PDF/UA-1 & Metadata & Flatten)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
@@ -920,75 +942,3 @@ Feature: /forms/chromium/convert/html
| files | testdata/page-1-html/index.html | file |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Scenario: POST /forms/chromium/convert/html with encryption (user password only)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
| files | testdata/page-1-html/index.html | file |
| userPassword | test123 | field |
| Gotenberg-Output-Filename | encrypted | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| encrypted.pdf |
Then the "encrypted.pdf" PDF should be encrypted
Then the "encrypted.pdf" PDF should have 1 page(s)
Scenario: POST /forms/chromium/convert/html with encryption (user and owner passwords)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
| files | testdata/page-1-html/index.html | file |
| userPassword | user123 | field |
| ownerPassword | owner456 | field |
| Gotenberg-Output-Filename | encrypted | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| encrypted.pdf |
Then the "encrypted.pdf" PDF should be encrypted
Then the "encrypted.pdf" PDF should have 1 page(s)
Scenario: POST /forms/chromium/convert/html with encryption and PDF/A conversion
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
| files | testdata/page-1-html/index.html | file |
| userPassword | test123 | field |
| pdfa | PDF/A-1a | field |
| Gotenberg-Output-Filename | encrypted | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| encrypted.pdf |
Then the "encrypted.pdf" PDF should be encrypted
Then the "encrypted.pdf" PDF should have 1 page(s)
Scenario: POST /forms/chromium/convert/html with encryption and page splitting
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
| files | testdata/pages-12-html/index.html | file |
| userPassword | test123 | field |
| splitMode | intervals | field |
| splitSpan | 5 | field |
| Gotenberg-Output-Filename | encrypted | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/zip"
Then there should be the following file(s) in the response:
| encrypted.zip |
Then the "encrypted.zip" archive should contain encrypted PDF file(s)
Scenario: POST /forms/chromium/convert/html without encryption (empty password)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
| files | testdata/page-1-html/index.html | file |
| userPassword | | field |
| Gotenberg-Output-Filename | unencrypted | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| unencrypted.pdf |
Then the "unencrypted.pdf" PDF should NOT be encrypted
Then the "unencrypted.pdf" PDF should have 1 page(s)

View File

@@ -939,6 +939,30 @@ Feature: /forms/chromium/convert/markdown
Then there should be 1 PDF(s) in the response
Then the response PDF(s) should be flatten
Scenario: POST /forms/chromium/convert/markdown (Encrypt - user password only)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
| files | testdata/page-1-markdown/index.html | file |
| files | testdata/page-1-markdown/page_1.md | file |
| userPassword | foo | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then the response PDF(s) should be encrypted
Scenario: POST /forms/chromium/convert/markdown (Encrypt - both user and owner passwords)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
| files | testdata/page-1-markdown/index.html | file |
| files | testdata/page-1-markdown/page_1.md | file |
| userPassword | foo | field |
| ownerPassword | bar | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then the response PDF(s) should be encrypted
# FIXME: once decrypt is done, add encrypt and check after the content of the PDF.
Scenario: POST /forms/chromium/convert/markdown (PDF/A-1b & PDF/UA-1 & Metadata & Flatten)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
@@ -1051,81 +1075,3 @@ Feature: /forms/chromium/convert/markdown
| files | testdata/page-1-markdown/page_1.md | file |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Scenario: POST /forms/chromium/convert/markdown with encryption (user password only)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
| files | testdata/page-1-markdown/index.html | file |
| files | testdata/page-1-markdown/page_1.md | file |
| userPassword | test123 | field |
| Gotenberg-Output-Filename | encrypted | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| encrypted.pdf |
Then the "encrypted.pdf" PDF should be encrypted
Then the "encrypted.pdf" PDF should have 1 page(s)
Scenario: POST /forms/chromium/convert/markdown with encryption (user and owner passwords)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
| files | testdata/page-1-markdown/index.html | file |
| files | testdata/page-1-markdown/page_1.md | file |
| userPassword | user123 | field |
| ownerPassword | owner456 | field |
| Gotenberg-Output-Filename | encrypted | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| encrypted.pdf |
Then the "encrypted.pdf" PDF should be encrypted
Then the "encrypted.pdf" PDF should have 1 page(s)
Scenario: POST /forms/chromium/convert/markdown with encryption and PDF/A conversion
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
| files | testdata/page-1-markdown/index.html | file |
| files | testdata/page-1-markdown/page_1.md | file |
| userPassword | test123 | field |
| pdfa | PDF/A-1a | field |
| Gotenberg-Output-Filename | encrypted | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| encrypted.pdf |
Then the "encrypted.pdf" PDF should be encrypted
Then the "encrypted.pdf" PDF should have 1 page(s)
Scenario: POST /forms/chromium/convert/markdown with encryption and page splitting
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
| files | testdata/pages-12-markdown/index.html | file |
| files | testdata/pages-12-markdown/page_1.md | file |
| files | testdata/pages-12-markdown/page_2.md | file |
| userPassword | test123 | field |
| splitMode | intervals | field |
| splitSpan | 5 | field |
| Gotenberg-Output-Filename | encrypted | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/zip"
Then there should be the following file(s) in the response:
| encrypted.zip |
Then the "encrypted.zip" archive should contain encrypted PDF file(s)
Scenario: POST /forms/chromium/convert/markdown without encryption (empty password)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
| files | testdata/page-1-markdown/index.html | file |
| files | testdata/page-1-markdown/page_1.md | file |
| userPassword | | field |
| Gotenberg-Output-Filename | unencrypted | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| unencrypted.pdf |
Then the "unencrypted.pdf" PDF should NOT be encrypted
Then the "unencrypted.pdf" PDF should have 1 page(s)

View File

@@ -898,6 +898,30 @@ Feature: /forms/chromium/convert/url
Then there should be 1 PDF(s) in the response
Then the response PDF(s) should be flatten
Scenario: POST /forms/chromium/convert/url (Encrypt - user password only)
Given I have a default Gotenberg container
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/url" endpoint with the following form data and header(s):
| url | http://host.docker.internal:%d/html/testdata/page-1-html/index.html | field |
| userPassword | foo | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then the response PDF(s) should be encrypted
Scenario: POST /forms/chromium/convert/url (Encrypt - both user and owner passwords)
Given I have a default Gotenberg container
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/url" endpoint with the following form data and header(s):
| url | http://host.docker.internal:%d/html/testdata/page-1-html/index.html | field |
| userPassword | foo | field |
| ownerPassword | bar | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then the response PDF(s) should be encrypted
# FIXME: once decrypt is done, add encrypt and check after the content of the PDF.
Scenario: POST /forms/chromium/convert/url (PDF/A-1b & PDF/UA-1 & Metadata & Flatten)
Given I have a default Gotenberg container
Given I have a static server
@@ -999,80 +1023,3 @@ Feature: /forms/chromium/convert/url
| url | http://host.docker.internal:%d/html/testdata/page-1-html/index.html | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Scenario: POST /forms/chromium/convert/url with encryption (user password only)
Given I have a default Gotenberg container
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/url" endpoint with the following form data and header(s):
| url | http://host.docker.internal:%d/html/testdata/page-1-html/index.html | field |
| userPassword | test123 | field |
| Gotenberg-Output-Filename | encrypted | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| encrypted.pdf |
Then the "encrypted.pdf" PDF should be encrypted
Then the "encrypted.pdf" PDF should have 1 page(s)
Scenario: POST /forms/chromium/convert/url with encryption (user and owner passwords)
Given I have a default Gotenberg container
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/url" endpoint with the following form data and header(s):
| url | http://host.docker.internal:%d/html/testdata/page-1-html/index.html | field |
| userPassword | user123 | field |
| ownerPassword | owner456 | field |
| Gotenberg-Output-Filename | encrypted | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| encrypted.pdf |
Then the "encrypted.pdf" PDF should be encrypted
Then the "encrypted.pdf" PDF should have 1 page(s)
Scenario: POST /forms/chromium/convert/url with encryption and PDF/A conversion
Given I have a default Gotenberg container
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/url" endpoint with the following form data and header(s):
| url | http://host.docker.internal:%d/html/testdata/page-1-html/index.html | field |
| userPassword | test123 | field |
| pdfa | PDF/A-1a | field |
| Gotenberg-Output-Filename | encrypted | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| encrypted.pdf |
Then the "encrypted.pdf" PDF should be encrypted
Then the "encrypted.pdf" PDF should have 1 page(s)
Scenario: POST /forms/chromium/convert/url with encryption and page splitting
Given I have a default Gotenberg container
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/url" endpoint with the following form data and header(s):
| url | http://host.docker.internal:%d/html/testdata/pages-12-html/index.html | field |
| userPassword | test123 | field |
| splitMode | intervals | field |
| splitSpan | 5 | field |
| Gotenberg-Output-Filename | encrypted | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/zip"
Then there should be the following file(s) in the response:
| encrypted.zip |
Then the "encrypted.zip" archive should contain encrypted PDF file(s)
Scenario: POST /forms/chromium/convert/url without encryption (empty password)
Given I have a default Gotenberg container
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/url" endpoint with the following form data and header(s):
| url | http://host.docker.internal:%d/html/testdata/page-1-html/index.html | field |
| userPassword | | field |
| Gotenberg-Output-Filename | unencrypted | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| unencrypted.pdf |
Then the "unencrypted.pdf" PDF should NOT be encrypted
Then the "unencrypted.pdf" PDF should have 1 page(s)

View File

@@ -526,6 +526,28 @@ Feature: /forms/libreoffice/convert
Then there should be 1 PDF(s) in the response
Then the response PDF(s) should be flatten
Scenario: POST /forms/libreoffice/convert (Encrypt - user password only)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/libreoffice/convert" endpoint with the following form data and header(s):
| files | testdata/page_1.docx | file |
| userPassword | foo | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then the response PDF(s) should be encrypted
Scenario: POST /forms/libreoffice/convert (Encrypt - both user and owner passwords)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/libreoffice/convert" endpoint with the following form data and header(s):
| files | testdata/page_1.docx | file |
| userPassword | foo | field |
| ownerPassword | bar | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then the response PDF(s) should be encrypted
# FIXME: once decrypt is done, add encrypt and check after the content of the PDF.
Scenario: POST /forms/libreoffice/convert (PDF/A-1b & PDF/UA-1 & Metadata & Flatten)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/libreoffice/convert" endpoint with the following form data and header(s):
@@ -533,7 +555,6 @@ Feature: /forms/libreoffice/convert
| pdfa | PDF/A-1b | field |
| pdfua | true | field |
| metadata | {"Author":"Julien Neuhart","Copyright":"Julien Neuhart","CreateDate":"2006-09-18T16:27:50-04:00","Creator":"Gotenberg","Keywords":["first","second"],"Marked":true,"ModDate":"2006-09-18T16:27:50-04:00","PDFVersion":1.7,"Producer":"Gotenberg","Subject":"Sample","Title":"Sample","Trapped":"Unknown"} | field |
| flatten | true | field |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
@@ -631,90 +652,3 @@ Feature: /forms/libreoffice/convert
| files | testdata/page_1.docx | file |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Scenario: POST /forms/libreoffice/convert with encryption (user password only)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/libreoffice/convert" endpoint with the following form data and header(s):
| files | testdata/page_1.docx | file |
| userPassword | test123 | field |
| Gotenberg-Output-Filename | encrypted | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| encrypted.pdf |
Then the "encrypted.pdf" PDF should be encrypted
Then the "encrypted.pdf" PDF should have 1 page(s)
Scenario: POST /forms/libreoffice/convert with encryption (user and owner passwords)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/libreoffice/convert" endpoint with the following form data and header(s):
| files | testdata/page_1.docx | file |
| userPassword | user123 | field |
| ownerPassword | owner456 | field |
| Gotenberg-Output-Filename | encrypted | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| encrypted.pdf |
Then the "encrypted.pdf" PDF should be encrypted
Then the "encrypted.pdf" PDF should have 1 page(s)
Scenario: POST /forms/libreoffice/convert with encryption and PDF/A conversion
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/libreoffice/convert" endpoint with the following form data and header(s):
| files | testdata/page_1.docx | file |
| userPassword | test123 | field |
| pdfa | PDF/A-1a | field |
| Gotenberg-Output-Filename | encrypted | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| encrypted.pdf |
Then the "encrypted.pdf" PDF should be encrypted
Then the "encrypted.pdf" PDF should have 1 page(s)
Scenario: POST /forms/libreoffice/convert with encryption (multiple files)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/libreoffice/convert" endpoint with the following form data and header(s):
| files | testdata/page_1.docx | file |
| files | testdata/page_2.docx | file |
| userPassword | test123 | field |
| Gotenberg-Output-Filename | encrypted | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/zip"
Then there should be the following file(s) in the response:
| encrypted.zip |
Then the response PDF(s) should be encrypted
Then the "encrypted.zip" archive should contain encrypted PDF file(s)
Scenario: POST /forms/libreoffice/convert with encryption and flattening
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/libreoffice/convert" endpoint with the following form data and header(s):
| files | testdata/page_1.docx | file |
| userPassword | test123 | field |
| flatten | true | field |
| Gotenberg-Output-Filename | encrypted | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| encrypted.pdf |
Then the "encrypted.pdf" PDF should be encrypted
Then the "encrypted.pdf" PDF should have 1 page(s)
Scenario: POST /forms/libreoffice/convert without encryption (empty password)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/libreoffice/convert" endpoint with the following form data and header(s):
| files | testdata/page_1.docx | file |
| userPassword | | field |
| Gotenberg-Output-Filename | unencrypted | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| unencrypted.pdf |
Then the "unencrypted.pdf" PDF should NOT be encrypted
Then the "unencrypted.pdf" PDF should have 1 page(s)

View File

@@ -183,78 +183,3 @@ Feature: /forms/pdfengines/convert
| pdfa | PDF/A-1b | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Scenario: POST /forms/pdfengines/convert with encryption (user password only)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/convert" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| pdfa | PDF/A-1b | field |
| userPassword | test123 | field |
| Gotenberg-Output-Filename | encrypted | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| encrypted.pdf |
Then the "encrypted.pdf" PDF should be encrypted
Then the "encrypted.pdf" PDF should be valid "PDF/A-1b" with a tolerance of 1 failed rule(s)
Scenario: POST /forms/pdfengines/convert with encryption (user and owner passwords)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/convert" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| pdfa | PDF/A-1b | field |
| userPassword | user123 | field |
| ownerPassword | owner456 | field |
| Gotenberg-Output-Filename | encrypted | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| encrypted.pdf |
Then the "encrypted.pdf" PDF should be encrypted
Then the "encrypted.pdf" PDF should be valid "PDF/A-1b" with a tolerance of 1 failed rule(s)
Scenario: POST /forms/pdfengines/convert with encryption (multiple files)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/convert" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| files | testdata/page_2.pdf | file |
| pdfa | PDF/A-1b | field |
| userPassword | test123 | field |
| Gotenberg-Output-Filename | encrypted | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/zip"
Then there should be the following file(s) in the response:
| encrypted.zip |
Then the response PDF(s) should be encrypted
Then the "encrypted.zip" archive should contain encrypted PDF file(s)
Scenario: POST /forms/pdfengines/convert with encryption and PDF/UA
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/convert" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| pdfua | true | field |
| userPassword | test123 | field |
| Gotenberg-Output-Filename | encrypted | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| encrypted.pdf |
Then the "encrypted.pdf" PDF should be encrypted
Scenario: POST /forms/pdfengines/convert without encryption (empty password)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/convert" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| pdfa | PDF/A-1b | field |
| userPassword | | field |
| Gotenberg-Output-Filename | unencrypted | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| unencrypted.pdf |
Then the "unencrypted.pdf" PDF should NOT be encrypted
Then the "unencrypted.pdf" PDF should be valid "PDF/A-1b" with a tolerance of 1 failed rule(s)

View File

@@ -1,129 +1,152 @@
Feature: /forms/pdfengines/encrypt
Scenario: POST /forms/pdfengines/encrypt (default - QPDF)
Scenario: POST /forms/pdfengines/encrypt (default - QPDF - user password only)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/encrypt" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| userPassword | test123 | field |
| Gotenberg-Output-Filename | protected | header |
| files | testdata/page_1.pdf | file |
| userPassword | foo | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| protected.pdf |
Then the "protected.pdf" PDF should be encrypted
Then the response PDF(s) should be encrypted
Scenario: POST /forms/pdfengines/encrypt with user and owner passwords (QPDF)
Scenario: POST /forms/pdfengines/encrypt (default - QPDF - both user and owner passwords)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/encrypt" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| userPassword | user123 | field |
| ownerPassword | owner456 | field |
| Gotenberg-Output-Filename | protected | header |
| files | testdata/page_1.pdf | file |
| userPassword | foo | field |
| ownerPassword | bar | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| protected.pdf |
Then the "protected.pdf" PDF should be encrypted
Then the response PDF(s) should be encrypted
Scenario: POST /forms/pdfengines/encrypt (PDFtk)
Scenario: POST /forms/pdfengines/encrypt (PDFtk - user password only)
Given I have a Gotenberg container with the following environment variable(s):
| PDFENGINES_PASSWORD_ENGINES | pdftk |
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/encrypt" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| userPassword | test123 | field |
| Gotenberg-Output-Filename | protected | header |
| files | testdata/page_1.pdf | file |
| userPassword | foo | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| protected.pdf |
Then the "protected.pdf" PDF should be encrypted
Then the response PDF(s) should be encrypted
Scenario: POST /forms/pdfengines/encrypt (pdfcpu)
Scenario: POST /forms/pdfengines/encrypt (PDFtk - both user and owner passwords)
Given I have a Gotenberg container with the following environment variable(s):
| PDFENGINES_PASSWORD_ENGINES | pdftk |
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/encrypt" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| userPassword | foo | field |
| ownerPassword | bar | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then the response PDF(s) should be encrypted
Scenario: POST /forms/pdfengines/encrypt (pdfcpu - user password only)
Given I have a Gotenberg container with the following environment variable(s):
| PDFENGINES_PASSWORD_ENGINES | pdfcpu |
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/encrypt" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| userPassword | test123 | field |
| Gotenberg-Output-Filename | protected | header |
| files | testdata/page_1.pdf | file |
| userPassword | foo | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| protected.pdf |
Then the "protected.pdf" PDF should be encrypted
Then the response PDF(s) should be encrypted
Scenario: POST /forms/pdfengines/encrypt with multiple files
Scenario: POST /forms/pdfengines/encrypt (pdfcpu - both user and owner passwords)
Given I have a Gotenberg container with the following environment variable(s):
| PDFENGINES_PASSWORD_ENGINES | pdfcpu |
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/encrypt" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| userPassword | foo | field |
| ownerPassword | bar | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then the response PDF(s) should be encrypted
Scenario: POST /forms/pdfengines/encrypt (Many PDFs)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/encrypt" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| files | testdata/page_2.pdf | file |
| userPassword | test123 | field |
| Gotenberg-Output-Filename | protected | header |
| files | testdata/page_1.pdf | file |
| files | testdata/page_2.pdf | file |
| userPassword | foo | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/zip"
Then there should be the following file(s) in the response:
| protected.zip |
Then the "protected.zip" archive should contain 2 file(s)
Then the "protected.zip" archive should contain encrypted PDF file(s)
Then there should be 2 PDF(s) in the response
Then the response PDF(s) should be encrypted
Scenario: POST /forms/pdfengines/encrypt without required userPassword field
Scenario: POST /forms/pdfengines/encrypt (Bad Request)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/encrypt" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| Gotenberg-Output-Filename | protected | header |
| files | testdata/page_1.pdf | file |
Then the response status code should be 400
Then the response body should contain "userPassword"
Scenario: POST /forms/pdfengines/encrypt with password engines that don't support password protection
Given I have a Gotenberg container with the following environment variable(s):
| PDFENGINES_PASSWORD_ENGINES | exiftool |
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/encrypt" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| userPassword | test123 | field |
| Gotenberg-Output-Filename | protected | header |
Then the response status code should be 500
Then the response body should contain "password protection not supported"
Scenario: POST /forms/pdfengines/encrypt (Download From)
Given I have a default Gotenberg container
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/encrypt" endpoint with the following form data and header(s):
| downloadFrom | [{"url":"http://host.docker.internal:%d/static/testdata/page_1.pdf","extraHttpHeaders":{"X-Foo":"bar"}}] | field |
| userPassword | test123 | field |
| Gotenberg-Output-Filename | protected | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| protected.pdf |
Then the "protected.pdf" PDF should be encrypted
Scenario: POST /forms/pdfengines/encrypt (Webhook)
Given I have a default Gotenberg container
Given I have a webhook server
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/encrypt" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| Gotenberg-Output-Filename | foo | header |
| Gotenberg-Webhook-Url | http://host.docker.internal:%d/webhook | header |
| Gotenberg-Webhook-Error-Url | http://host.docker.internal:%d/webhook/error | header |
Then the response status code should be 204
When I wait for the asynchronous request to the webhook
Then the webhook request header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the webhook request
Then there should be the following file(s) in the webhook request:
| foo.pdf |
Then the "foo.pdf" PDF should have 1 page(s)
Then the "foo.pdf" PDF should have the following content at page 1:
Then the response body should match string:
"""
Page 1
Invalid form data: form field 'userPassword' is required
"""
Scenario: POST /forms/pdfengines/encrypt (Routes Disabled)
Given I have a Gotenberg container with the following environment variable(s):
| PDFENGINES_DISABLE_ROUTES | true |
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/encrypt" endpoint with the following form data and header(s):
| files | testdata/pages_3.pdf | file |
| files | testdata/page_1.pdf | file |
Then the response status code should be 404
Scenario: POST /forms/pdfengines/encrypt (Gotenberg Trace)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/encrypt" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| userPassword | foo | field |
| Gotenberg-Trace | forms_pdfengines_encrypt | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then the response header "Gotenberg-Trace" should be "forms_pdfengines_encrypt"
Then the Gotenberg container should log the following entries:
| "trace":"forms_pdfengines_encrypt" |
Scenario: POST /forms/pdfengines/encrypt (Download From)
Given I have a default Gotenberg container
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/encrypt" endpoint with the following form data and header(s):
| downloadFrom | [{"url":"http://host.docker.internal:%d/static/testdata/page_1.pdf","extraHttpHeaders":{"X-Foo":"bar"}}] | field |
| userPassword | foo | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then the response PDF(s) should be encrypted
Scenario: POST /forms/pdfengines/encrypt (Webhook)
Given I have a default Gotenberg container
Given I have a webhook server
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/encrypt" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| userPassword | foo | field |
| Gotenberg-Webhook-Url | http://host.docker.internal:%d/webhook | header |
| Gotenberg-Webhook-Error-Url | http://host.docker.internal:%d/webhook/error | header |
Then the response status code should be 204
When I wait for the asynchronous request to the webhook
Then the webhook request header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the webhook request
Then the response PDF(s) should be encrypted
Scenario: POST /forms/pdfengines/encrypt (Basic Auth)
Given I have a Gotenberg container with the following environment variable(s):
| API_ENABLE_BASIC_AUTH | true |
| GOTENBERG_API_BASIC_AUTH_USERNAME | foo |
| GOTENBERG_API_BASIC_AUTH_PASSWORD | bar |
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/encrypt" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
Then the response status code should be 401
Scenario: POST /foo/forms/pdfengines/encrypt (Root Path)
Given I have a Gotenberg container with the following environment variable(s):
| API_ENABLE_DEBUG_ROUTE | true |
| API_ROOT_PATH | /foo/ |
When I make a "POST" request to Gotenberg at the "/foo/forms/pdfengines/encrypt" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| userPassword | foo | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"

View File

@@ -79,6 +79,7 @@ Feature: /forms/pdfengines/flatten
Then the file request header "X-Foo" should be "bar"
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then the response PDF(s) should be flatten
Scenario: POST /forms/pdfengines/flatten (Webhook)
Given I have a default Gotenberg container

View File

@@ -199,6 +199,30 @@ Feature: /forms/pdfengines/merge
"""
Then the response PDF(s) should be flatten
Scenario: POST /forms/pdfengines/merge (Encrypt - user password only)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/merge" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| files | testdata/page_2.pdf | file |
| userPassword | foo | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then the response PDF(s) should be encrypted
Scenario: POST /forms/pdfengines/merge (Encrypt - both user and owner passwords)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/merge" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| files | testdata/page_2.pdf | file |
| userPassword | foo | field |
| ownerPassword | bar | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then the response PDF(s) should be encrypted
# FIXME: once decrypt is done, add encrypt and check after the content of the PDF.
Scenario: POST /forms/pdfengines/merge (PDF/A-1b & PDF/UA-1 & Metadata & Flatten)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/merge" endpoint with the following form data and header(s):
@@ -322,81 +346,3 @@ Feature: /forms/pdfengines/merge
| files | testdata/page_2.pdf | file |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Scenario: POST /forms/pdfengines/merge with encryption (user password only)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/merge" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| files | testdata/page_2.pdf | file |
| userPassword | test123 | field |
| Gotenberg-Output-Filename | encrypted | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| encrypted.pdf |
Then the "encrypted.pdf" PDF should be encrypted
Then the "encrypted.pdf" PDF should have 2 page(s)
Scenario: POST /forms/pdfengines/merge with encryption (user and owner passwords)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/merge" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| files | testdata/page_2.pdf | file |
| userPassword | user123 | field |
| ownerPassword | owner456 | field |
| Gotenberg-Output-Filename | encrypted | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| encrypted.pdf |
Then the "encrypted.pdf" PDF should be encrypted
Then the "encrypted.pdf" PDF should have 2 page(s)
Scenario: POST /forms/pdfengines/merge with encryption and PDF/A conversion
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/merge" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| files | testdata/page_2.pdf | file |
| userPassword | test123 | field |
| pdfa | PDF/A-1a | field |
| Gotenberg-Output-Filename | encrypted | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| encrypted.pdf |
Then the "encrypted.pdf" PDF should be encrypted
Then the "encrypted.pdf" PDF should have 2 page(s)
Scenario: POST /forms/pdfengines/merge with encryption and flattening
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/merge" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| files | testdata/page_2.pdf | file |
| userPassword | test123 | field |
| flatten | true | field |
| Gotenberg-Output-Filename | encrypted | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| encrypted.pdf |
Then the "encrypted.pdf" PDF should be encrypted
Then the "encrypted.pdf" PDF should have 2 page(s)
Scenario: POST /forms/pdfengines/merge without encryption (empty password)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/merge" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| files | testdata/page_2.pdf | file |
| userPassword | | field |
| Gotenberg-Output-Filename | unencrypted | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| unencrypted.pdf |
Then the "unencrypted.pdf" PDF should NOT be encrypted
Then the "unencrypted.pdf" PDF should have 2 page(s)

View File

@@ -284,61 +284,3 @@ Feature: /forms/pdfengines/{write|read}
| files | teststore/foo.pdf | file |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/json"
Scenario: POST /forms/pdfengines/metadata/write with encryption (user password only)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/metadata/write" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| metadata | {"Title":"Encrypted Sample","Author":"Test Author","Subject":"Test Subject"} | field |
| userPassword | test123 | field |
| Gotenberg-Output-Filename | encrypted | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| encrypted.pdf |
Then the "encrypted.pdf" PDF should be encrypted
Scenario: POST /forms/pdfengines/metadata/write with encryption (user and owner passwords)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/metadata/write" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| metadata | {"Title":"Encrypted Sample","Author":"Test Author","Subject":"Test Subject"} | field |
| userPassword | user123 | field |
| ownerPassword | owner456 | field |
| Gotenberg-Output-Filename | encrypted | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| encrypted.pdf |
Then the "encrypted.pdf" PDF should be encrypted
Scenario: POST /forms/pdfengines/metadata/write with encryption (multiple files)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/metadata/write" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| files | testdata/page_2.pdf | file |
| metadata | {"Title":"Encrypted Sample","Author":"Test Author","Subject":"Test Subject"} | field |
| userPassword | test123 | field |
| Gotenberg-Output-Filename | encrypted | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/zip"
Then there should be the following file(s) in the response:
| encrypted.zip |
Then the response PDF(s) should be encrypted
Then the "encrypted.zip" archive should contain encrypted PDF file(s)
Scenario: POST /forms/pdfengines/metadata/write without encryption (empty password)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/metadata/write" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| metadata | {"Title":"Unencrypted Sample","Author":"Test Author","Subject":"Test Subject"} | field |
| userPassword | | field |
| Gotenberg-Output-Filename | unencrypted | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| unencrypted.pdf |
Then the "unencrypted.pdf" PDF should NOT be encrypted

View File

@@ -365,6 +365,32 @@ Feature: /forms/pdfengines/split
"""
Then the response PDF(s) should be flatten
Scenario: POST /forms/pdfengines/split (Encrypt - user password only)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/split" endpoint with the following form data and header(s):
| files | testdata/pages_3.pdf | file |
| splitMode | intervals | field |
| splitSpan | 2 | field |
| userPassword | foo | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/zip"
Then there should be 2 PDF(s) in the response
Then the response PDF(s) should be encrypted
Scenario: POST /forms/pdfengines/split (Encrypt - both user and owner passwords)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/split" endpoint with the following form data and header(s):
| files | testdata/pages_3.pdf | file |
| splitMode | intervals | field |
| splitSpan | 2 | field |
| userPassword | foo | field |
| ownerPassword | bar | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/zip"
Then there should be 2 PDF(s) in the response
Then the response PDF(s) should be encrypted
# FIXME: once decrypt is done, add encrypt and check after the content of the PDFs.
Scenario: POST /forms/pdfengines/split (PDF/A-1b & PDF/UA-1 & Metadata & Flatten)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/split" endpoint with the following form data and header(s):
@@ -549,69 +575,3 @@ Feature: /forms/pdfengines/split
| splitSpan | 2 | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/zip"
Scenario: POST /forms/pdfengines/split with encryption (intervals)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/split" endpoint with the following form data and header(s):
| files | testdata/pages_3.pdf | file |
| splitMode | intervals | field |
| splitSpan | 2 | field |
| userPassword | test123 | field |
| Gotenberg-Output-Filename | encrypted | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/zip"
Then there should be 2 PDF(s) in the response
Then there should be the following file(s) in the response:
| encrypted.zip |
Then the response PDF(s) should be encrypted
Then the "encrypted.zip" archive should contain encrypted PDF file(s)
Scenario: POST /forms/pdfengines/split with encryption (pages)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/split" endpoint with the following form data and header(s):
| files | testdata/pages_3.pdf | file |
| splitMode | pages | field |
| splitSpan | 2- | field |
| userPassword | user123 | field |
| ownerPassword | owner456 | field |
| Gotenberg-Output-Filename | encrypted | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/zip"
Then there should be 2 PDF(s) in the response
Then there should be the following file(s) in the response:
| encrypted.zip |
Then the response PDF(s) should be encrypted
Then the "encrypted.zip" archive should contain encrypted PDF file(s)
Scenario: POST /forms/pdfengines/split with encryption and PDF/A conversion
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/split" endpoint with the following form data and header(s):
| files | testdata/pages_3.pdf | file |
| splitMode | intervals | field |
| splitSpan | 2 | field |
| userPassword | test123 | field |
| pdfa | PDF/A-1a | field |
| Gotenberg-Output-Filename | encrypted | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/zip"
Then there should be 2 PDF(s) in the response
Then there should be the following file(s) in the response:
| encrypted.zip |
Then the response PDF(s) should be encrypted
Then the "encrypted.zip" archive should contain encrypted PDF file(s)
Scenario: POST /forms/pdfengines/split without encryption (empty password)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/split" endpoint with the following form data and header(s):
| files | testdata/pages_3.pdf | file |
| splitMode | intervals | field |
| splitSpan | 2 | field |
| userPassword | | field |
| Gotenberg-Output-Filename | unencrypted | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/zip"
Then there should be 2 PDF(s) in the response
Then there should be the following file(s) in the response:
| unencrypted.zip |
Then the "unencrypted.zip" archive should contain 2 file(s)
Then the "unencrypted.zip" archive should NOT contain encrypted PDF file(s)

View File

@@ -580,6 +580,7 @@ func (s *scenario) thePdfsShouldBeValidWithAToleranceOf(ctx context.Context, kin
return fmt.Errorf("unknown %q", validate)
}
re := regexp.MustCompile(`failedRules="(\d+)"`)
for _, path := range paths {
cmd := []string{
"verapdf",
@@ -593,9 +594,7 @@ func (s *scenario) thePdfsShouldBeValidWithAToleranceOf(ctx context.Context, kin
return fmt.Errorf("exec %q: %w", cmd, err)
}
re := regexp.MustCompile(`failedRules="(\d+)"`)
matches := re.FindStringSubmatch(output)
if len(matches) < 2 {
return errors.New("expected failed rules")
}
@@ -812,6 +811,8 @@ func (s *scenario) thePdfsShouldBeFlatten(ctx context.Context, kind, should stri
return fmt.Errorf("walk %q: %w", s.workdir, err)
}
invert := should == "should NOT"
for _, path := range paths {
cmd := []string{
"verapdf",
@@ -826,7 +827,6 @@ func (s *scenario) thePdfsShouldBeFlatten(ctx context.Context, kind, should stri
return fmt.Errorf("exec %q: %w", cmd, err)
}
invert := should == "should NOT"
if invert && strings.Contains(output, "<featuresReport></featuresReport>") {
return fmt.Errorf("PDF %q is flatten", path)
}
@@ -839,93 +839,53 @@ func (s *scenario) thePdfsShouldBeFlatten(ctx context.Context, kind, should stri
return nil
}
// thePdfShouldBeEncrypted checks if a PDF file is encrypted or not encrypted based on condition.
func (s *scenario) thePdfShouldBeEncrypted(ctx context.Context, filename, should string) error {
filePath := fmt.Sprintf("%s/%s", s.workdir, filename)
func (s *scenario) thePdfsShouldBeEncrypted(ctx context.Context, kind string, should string) error {
dirPath := fmt.Sprintf("%s/%s", s.workdir, s.resp.Header().Get("Gotenberg-Trace"))
cmd := []string{
"qpdf",
"--check",
filepath.Base(filePath),
_, err := os.Stat(dirPath)
if os.IsNotExist(err) {
return fmt.Errorf("directory %q does not exist", dirPath)
}
output, err := execCommandInIntegrationToolsContainer(ctx, cmd, filePath)
invert := should == "should NOT"
isEncrypted := err != nil && (strings.Contains(output, "password") || strings.Contains(output, "encrypted"))
if invert && isEncrypted {
return fmt.Errorf("expected PDF %s to not be encrypted, but it is encrypted", filename)
}
if !invert && !isEncrypted {
return fmt.Errorf("expected PDF %s to be encrypted, but it is not", filename)
}
return nil
}
// theArchiveShouldContainEncryptedPdfFiles checks if a zip archive contains encrypted PDF files based on condition.
func (s *scenario) theArchiveShouldContainEncryptedPdfFiles(ctx context.Context, archiveFilename, should string) error {
archivePath := fmt.Sprintf("%s/%s", s.workdir, archiveFilename)
// First, extract the archive inside the container
extractCmd := []string{
"sh",
"-c",
fmt.Sprintf("mkdir -p /tmp/extract && unzip -o %s -d /tmp/extract", filepath.Base(archivePath)),
}
_, err := execCommandInIntegrationToolsContainer(ctx, extractCmd, archivePath)
if err != nil {
return fmt.Errorf("extract archive in container: %w", err)
}
// List PDF files in the extracted directory
listCmd := []string{
"sh",
"-c",
"find /tmp/extract -name '*.pdf' -type f",
}
output, err := execCommandInIntegrationToolsContainer(ctx, listCmd, archivePath)
if err != nil {
return fmt.Errorf("list PDFs in container: %w", err)
}
// No PDFs found
if output == "" {
return fmt.Errorf("no PDF files found in archive %s", archiveFilename)
}
// Check each PDF for password protection
pdfPaths := strings.Split(strings.TrimSpace(output), "\n")
foundProtectedPdf := false
for _, pdfPath := range pdfPaths {
checkCmd := []string{
"qpdf",
"--check",
pdfPath,
var paths []string
err = filepath.Walk(dirPath, func(path string, info os.FileInfo, pathErr error) error {
if pathErr != nil {
return pathErr
}
checkOutput, err := execCommandInIntegrationToolsContainer(ctx, checkCmd, archivePath)
// If we get a password error, we found a protected PDF
if err != nil && (strings.Contains(checkOutput, "password") || strings.Contains(checkOutput, "encrypted")) {
foundProtectedPdf = true
break
if strings.EqualFold(filepath.Ext(info.Name()), ".pdf") {
paths = append(paths, path)
}
return nil
})
if err != nil {
return fmt.Errorf("walk %q: %w", dirPath, err)
}
invert := should == "should NOT"
re := regexp.MustCompile(`CommandLineError:Incorrectpassword`)
if invert && foundProtectedPdf {
return fmt.Errorf("found encrypted PDF files in archive %s, but expected none", archiveFilename)
}
for _, path := range paths {
cmd := []string{
"pdfinfo",
filepath.Base(path),
}
if !invert && !foundProtectedPdf {
return fmt.Errorf("no encrypted PDF files found in archive %s", archiveFilename)
output, err := execCommandInIntegrationToolsContainer(ctx, cmd, path)
if err != nil {
return fmt.Errorf("exec %q: %w", cmd, err)
}
output = strings.ReplaceAll(output, " ", "")
output = strings.ReplaceAll(output, "\n", "")
matches := re.FindStringSubmatch(output)
isEncrypted := len(matches) >= 1 && matches[0] == "CommandLineError:Incorrectpassword"
if invert && isEncrypted {
return fmt.Errorf("PDF %q is encrypted", path)
}
if !invert && !isEncrypted {
return fmt.Errorf("PDF %q is not encrypted: %q", path, output)
}
}
return nil
@@ -963,11 +923,10 @@ func InitializeScenario(ctx *godog.ScenarioContext) {
ctx.Then(`^there should be the following file\(s\) in the (response|webhook request):$`, s.thereShouldBeTheFollowingFiles)
ctx.Then(`^the (response|webhook request) PDF\(s\) should be valid "([^"]*)" with a tolerance of (\d+) failed rule\(s\)$`, s.thePdfsShouldBeValidWithAToleranceOf)
ctx.Then(`^the (response|webhook request) PDF\(s\) (should|should NOT) be flatten$`, s.thePdfsShouldBeFlatten)
ctx.Then(`^the (response|webhook request) PDF\(s\) (should|should NOT) be encrypted`, s.thePdfsShouldBeEncrypted)
ctx.Then(`^the "([^"]*)" PDF should have (\d+) page\(s\)$`, s.thePdfShouldHavePages)
ctx.Then(`^the "([^"]*)" PDF (should|should NOT) be set to landscape orientation$`, s.thePdfShouldBeSetToLandscapeOrientation)
ctx.Then(`^the "([^"]*)" PDF (should|should NOT) have the following content at page (\d+):$`, s.thePdfShouldHaveTheFollowingContentAtPage)
ctx.Then(`^the "([^"]*)" PDF (should|should NOT) be encrypted$`, s.thePdfShouldBeEncrypted)
ctx.Then(`^the "([^"]*)" archive (should|should NOT) contain encrypted PDF file\(s\)$`, s.theArchiveShouldContainEncryptedPdfFiles)
ctx.After(func(ctx context.Context, sc *godog.Scenario, err error) (context.Context, error) {
if s.gotenbergContainer != nil {
errTerminate := s.gotenbergContainer.Terminate(ctx, testcontainers.StopTimeout(0))