mirror of
https://github.com/gotenberg/gotenberg.git
synced 2026-07-02 08:27:41 +08:00
fix(pdfengines): require uploaded stamp/watermark file for image or pdf source
This commit is contained in:
@@ -465,11 +465,13 @@ func convertUrlRoute(chromium Api, engine gotenberg.PdfEngine) api.Route {
|
||||
return fmt.Errorf("reject URL scheme: %w", err)
|
||||
}
|
||||
|
||||
if (watermark.Source == gotenberg.StampSourceImage || watermark.Source == gotenberg.StampSourcePDF) && watermarkFile != "" {
|
||||
watermark.Expression = watermarkFile
|
||||
err = pdfengines.EnsureWatermarkFile(&watermark, watermarkFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("validate watermark: %w", err)
|
||||
}
|
||||
if (stamp.Source == gotenberg.StampSourceImage || stamp.Source == gotenberg.StampSourcePDF) && stampFile != "" {
|
||||
stamp.Expression = stampFile
|
||||
err = pdfengines.EnsureStampFile(&stamp, stampFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("validate stamp: %w", err)
|
||||
}
|
||||
|
||||
err = convertUrl(ctx, chromium, engine, url, options, mode, pdfFormats, metadata, userPassword, ownerPassword, embedPaths, embedsMetadata, watermark, stamp, rotateAngle, rotatePages)
|
||||
@@ -546,11 +548,13 @@ func convertHtmlRoute(chromium Api, engine gotenberg.PdfEngine) api.Route {
|
||||
return fmt.Errorf("validate form data: %w", err)
|
||||
}
|
||||
|
||||
if (watermark.Source == gotenberg.StampSourceImage || watermark.Source == gotenberg.StampSourcePDF) && watermarkFile != "" {
|
||||
watermark.Expression = watermarkFile
|
||||
err = pdfengines.EnsureWatermarkFile(&watermark, watermarkFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("validate watermark: %w", err)
|
||||
}
|
||||
if (stamp.Source == gotenberg.StampSourceImage || stamp.Source == gotenberg.StampSourcePDF) && stampFile != "" {
|
||||
stamp.Expression = stampFile
|
||||
err = pdfengines.EnsureStampFile(&stamp, stampFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("validate stamp: %w", err)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("file://%s", inputPath)
|
||||
@@ -631,11 +635,13 @@ func convertMarkdownRoute(chromium Api, engine gotenberg.PdfEngine) api.Route {
|
||||
return fmt.Errorf("validate form data: %w", err)
|
||||
}
|
||||
|
||||
if (watermark.Source == gotenberg.StampSourceImage || watermark.Source == gotenberg.StampSourcePDF) && watermarkFile != "" {
|
||||
watermark.Expression = watermarkFile
|
||||
err = pdfengines.EnsureWatermarkFile(&watermark, watermarkFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("validate watermark: %w", err)
|
||||
}
|
||||
if (stamp.Source == gotenberg.StampSourceImage || stamp.Source == gotenberg.StampSourcePDF) && stampFile != "" {
|
||||
stamp.Expression = stampFile
|
||||
err = pdfengines.EnsureStampFile(&stamp, stampFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("validate stamp: %w", err)
|
||||
}
|
||||
|
||||
url, err := markdownToHtml(ctx, inputPath, markdownPaths)
|
||||
|
||||
@@ -304,11 +304,13 @@ func convertRoute(libreOffice libreofficeapi.Uno, engine gotenberg.PdfEngine) ap
|
||||
return fmt.Errorf("validate form data: %w", err)
|
||||
}
|
||||
|
||||
if (watermark.Source == gotenberg.StampSourceImage || watermark.Source == gotenberg.StampSourcePDF) && watermarkFile != "" {
|
||||
watermark.Expression = watermarkFile
|
||||
err = pdfengines.EnsureWatermarkFile(&watermark, watermarkFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("validate watermark: %w", err)
|
||||
}
|
||||
if (stamp.Source == gotenberg.StampSourceImage || stamp.Source == gotenberg.StampSourcePDF) && stampFile != "" {
|
||||
stamp.Expression = stampFile
|
||||
err = pdfengines.EnsureStampFile(&stamp, stampFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("validate stamp: %w", err)
|
||||
}
|
||||
|
||||
err = pdfengines.ValidatePdfFormatsCompat(pdfFormats, userPassword, embedPaths)
|
||||
|
||||
@@ -608,6 +608,50 @@ func FormDataPdfStampFile(form *api.FormData) string {
|
||||
return path
|
||||
}
|
||||
|
||||
// EnsureStampFile validates that, when stamp.Source is image or pdf, an
|
||||
// uploaded stamp file was supplied, and replaces stamp.Expression with
|
||||
// uploadedFile in that case. Returning an [api] HTTP 400 error prevents
|
||||
// an anonymous caller from passing an arbitrary filesystem path via
|
||||
// stampExpression and having pdfcpu read it. Source values of text or
|
||||
// empty are passed through unchanged.
|
||||
func EnsureStampFile(stamp *gotenberg.Stamp, uploadedFile string) error {
|
||||
if stamp.Source != gotenberg.StampSourceImage && stamp.Source != gotenberg.StampSourcePDF {
|
||||
return nil
|
||||
}
|
||||
if uploadedFile == "" {
|
||||
return api.WrapError(
|
||||
errors.New("no stamp file provided for image or pdf source"),
|
||||
api.NewSentinelHttpError(
|
||||
http.StatusBadRequest,
|
||||
"Invalid form data: a stamp file is required for image or pdf source",
|
||||
),
|
||||
)
|
||||
}
|
||||
stamp.Expression = uploadedFile
|
||||
return nil
|
||||
}
|
||||
|
||||
// EnsureWatermarkFile mirrors [EnsureStampFile] for a watermark. The
|
||||
// shape is identical: image or pdf sources must be accompanied by an
|
||||
// uploaded file, and the file path replaces watermark.Expression to
|
||||
// prevent pdfcpu from reading an attacker-controlled path.
|
||||
func EnsureWatermarkFile(watermark *gotenberg.Stamp, uploadedFile string) error {
|
||||
if watermark.Source != gotenberg.StampSourceImage && watermark.Source != gotenberg.StampSourcePDF {
|
||||
return nil
|
||||
}
|
||||
if uploadedFile == "" {
|
||||
return api.WrapError(
|
||||
errors.New("no watermark file provided for image or pdf source"),
|
||||
api.NewSentinelHttpError(
|
||||
http.StatusBadRequest,
|
||||
"Invalid form data: a watermark file is required for image or pdf source",
|
||||
),
|
||||
)
|
||||
}
|
||||
watermark.Expression = uploadedFile
|
||||
return nil
|
||||
}
|
||||
|
||||
// WatermarkStub applies a watermark to a list of PDF files. If the stamp has
|
||||
// no source, it does nothing.
|
||||
func WatermarkStub(ctx *api.Context, engine gotenberg.PdfEngine, stamp gotenberg.Stamp, inputPaths []string) error {
|
||||
@@ -676,11 +720,13 @@ func mergeRoute(engine gotenberg.PdfEngine) api.Route {
|
||||
return fmt.Errorf("validate form data: %w", err)
|
||||
}
|
||||
|
||||
if (watermark.Source == gotenberg.StampSourceImage || watermark.Source == gotenberg.StampSourcePDF) && watermarkFile != "" {
|
||||
watermark.Expression = watermarkFile
|
||||
err = EnsureWatermarkFile(&watermark, watermarkFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("validate watermark: %w", err)
|
||||
}
|
||||
if (stamp.Source == gotenberg.StampSourceImage || stamp.Source == gotenberg.StampSourcePDF) && stampFile != "" {
|
||||
stamp.Expression = stampFile
|
||||
err = EnsureStampFile(&stamp, stampFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("validate stamp: %w", err)
|
||||
}
|
||||
|
||||
err = ValidatePdfFormatsCompat(pdfFormats, userPassword, embedPaths)
|
||||
@@ -831,11 +877,13 @@ func splitRoute(engine gotenberg.PdfEngine) api.Route {
|
||||
return fmt.Errorf("validate form data: %w", err)
|
||||
}
|
||||
|
||||
if (watermark.Source == gotenberg.StampSourceImage || watermark.Source == gotenberg.StampSourcePDF) && watermarkFile != "" {
|
||||
watermark.Expression = watermarkFile
|
||||
err = EnsureWatermarkFile(&watermark, watermarkFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("validate watermark: %w", err)
|
||||
}
|
||||
if (stamp.Source == gotenberg.StampSourceImage || stamp.Source == gotenberg.StampSourcePDF) && stampFile != "" {
|
||||
stamp.Expression = stampFile
|
||||
err = EnsureStampFile(&stamp, stampFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("validate stamp: %w", err)
|
||||
}
|
||||
|
||||
err = ValidatePdfFormatsCompat(pdfFormats, userPassword, embedPaths)
|
||||
@@ -1268,17 +1316,9 @@ func watermarkRoute(engine gotenberg.PdfEngine) api.Route {
|
||||
return fmt.Errorf("validate form data: %w", err)
|
||||
}
|
||||
|
||||
if stamp.Source == gotenberg.StampSourceImage || stamp.Source == gotenberg.StampSourcePDF {
|
||||
if watermarkFile == "" {
|
||||
return api.WrapError(
|
||||
errors.New("no watermark file provided"),
|
||||
api.NewSentinelHttpError(
|
||||
http.StatusBadRequest,
|
||||
"Invalid form data: a watermark file is required for image or pdf source",
|
||||
),
|
||||
)
|
||||
}
|
||||
stamp.Expression = watermarkFile
|
||||
err = EnsureWatermarkFile(&stamp, watermarkFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("validate watermark: %w", err)
|
||||
}
|
||||
|
||||
err = WatermarkStub(ctx, engine, stamp, inputPaths)
|
||||
@@ -1319,17 +1359,9 @@ func stampRoute(engine gotenberg.PdfEngine) api.Route {
|
||||
return fmt.Errorf("validate form data: %w", err)
|
||||
}
|
||||
|
||||
if stamp.Source == gotenberg.StampSourceImage || stamp.Source == gotenberg.StampSourcePDF {
|
||||
if stampFile == "" {
|
||||
return api.WrapError(
|
||||
errors.New("no stamp file provided"),
|
||||
api.NewSentinelHttpError(
|
||||
http.StatusBadRequest,
|
||||
"Invalid form data: a stamp file is required for image or pdf source",
|
||||
),
|
||||
)
|
||||
}
|
||||
stamp.Expression = stampFile
|
||||
err = EnsureStampFile(&stamp, stampFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("validate stamp: %w", err)
|
||||
}
|
||||
|
||||
err = StampStub(ctx, engine, stamp, inputPaths)
|
||||
|
||||
@@ -1188,6 +1188,30 @@ Feature: /forms/chromium/convert/html
|
||||
Then the "foo.pdf" PDF should have 1 page(s)
|
||||
Then the "foo.pdf" PDF should have 1 image(s)
|
||||
|
||||
Scenario: POST /forms/chromium/convert/html (stampSource=pdf without uploaded stamp file => 400)
|
||||
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 |
|
||||
| stampSource | pdf | field |
|
||||
| stampExpression | /etc/hostname | field |
|
||||
Then the response status code should be 400
|
||||
Then the response body should match string:
|
||||
"""
|
||||
Invalid form data: a stamp file is required for image or pdf source
|
||||
"""
|
||||
|
||||
Scenario: POST /forms/chromium/convert/html (watermarkSource=pdf without uploaded watermark file => 400)
|
||||
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 |
|
||||
| watermarkSource | pdf | field |
|
||||
| watermarkExpression | /etc/hostname | field |
|
||||
Then the response status code should be 400
|
||||
Then the response body should match string:
|
||||
"""
|
||||
Invalid form data: a watermark file is required for image or pdf source
|
||||
"""
|
||||
|
||||
# See: https://github.com/gotenberg/gotenberg/issues/1500.
|
||||
Scenario: POST /forms/chromium/convert/html (Long Filename)
|
||||
Given I have a default Gotenberg container
|
||||
|
||||
@@ -1153,6 +1153,32 @@ Feature: /forms/chromium/convert/markdown
|
||||
Then the response status code should be 200
|
||||
Then the response header "Content-Type" should be "application/pdf"
|
||||
|
||||
Scenario: POST /forms/chromium/convert/markdown (stampSource=pdf without uploaded stamp file => 400)
|
||||
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 |
|
||||
| stampSource | pdf | field |
|
||||
| stampExpression | /etc/hostname | field |
|
||||
Then the response status code should be 400
|
||||
Then the response body should match string:
|
||||
"""
|
||||
Invalid form data: a stamp file is required for image or pdf source
|
||||
"""
|
||||
|
||||
Scenario: POST /forms/chromium/convert/markdown (watermarkSource=pdf without uploaded watermark file => 400)
|
||||
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 |
|
||||
| watermarkSource | pdf | field |
|
||||
| watermarkExpression | /etc/hostname | field |
|
||||
Then the response status code should be 400
|
||||
Then the response body should match string:
|
||||
"""
|
||||
Invalid form data: a watermark file is required for image or pdf source
|
||||
"""
|
||||
|
||||
# See: https://github.com/gotenberg/gotenberg/issues/1500.
|
||||
Scenario: POST /forms/chromium/convert/markdown (Long Filename)
|
||||
Given I have a default Gotenberg container
|
||||
|
||||
@@ -1269,6 +1269,32 @@ Feature: /forms/chromium/convert/url
|
||||
Then the response status code should be 200
|
||||
Then the response header "Content-Type" should be "application/pdf"
|
||||
|
||||
Scenario: POST /forms/chromium/convert/url (stampSource=pdf without uploaded stamp file => 400)
|
||||
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 |
|
||||
| stampSource | pdf | field |
|
||||
| stampExpression | /etc/hostname | field |
|
||||
Then the response status code should be 400
|
||||
Then the response body should match string:
|
||||
"""
|
||||
Invalid form data: a stamp file is required for image or pdf source
|
||||
"""
|
||||
|
||||
Scenario: POST /forms/chromium/convert/url (watermarkSource=pdf without uploaded watermark file => 400)
|
||||
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 |
|
||||
| watermarkSource | pdf | field |
|
||||
| watermarkExpression | /etc/hostname | field |
|
||||
Then the response status code should be 400
|
||||
Then the response body should match string:
|
||||
"""
|
||||
Invalid form data: a watermark file is required for image or pdf source
|
||||
"""
|
||||
|
||||
# See: https://github.com/gotenberg/gotenberg/issues/1500.
|
||||
Scenario: POST /forms/chromium/convert/url (Long Filename)
|
||||
Given I have a default Gotenberg container
|
||||
|
||||
@@ -817,6 +817,30 @@ Feature: /forms/libreoffice/convert
|
||||
Then the response status code should be 200
|
||||
Then the response header "Content-Type" should be "application/pdf"
|
||||
|
||||
Scenario: POST /forms/libreoffice/convert (stampSource=pdf without uploaded stamp file => 400)
|
||||
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 |
|
||||
| stampSource | pdf | field |
|
||||
| stampExpression | /etc/hostname | field |
|
||||
Then the response status code should be 400
|
||||
Then the response body should match string:
|
||||
"""
|
||||
Invalid form data: a stamp file is required for image or pdf source
|
||||
"""
|
||||
|
||||
Scenario: POST /forms/libreoffice/convert (watermarkSource=pdf without uploaded watermark file => 400)
|
||||
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 |
|
||||
| watermarkSource | pdf | field |
|
||||
| watermarkExpression | /etc/hostname | field |
|
||||
Then the response status code should be 400
|
||||
Then the response body should match string:
|
||||
"""
|
||||
Invalid form data: a watermark file is required for image or pdf source
|
||||
"""
|
||||
|
||||
# See: https://github.com/gotenberg/gotenberg/issues/1500.
|
||||
Scenario: POST /forms/libreoffice/convert (Long Filename)
|
||||
Given I have a default Gotenberg container
|
||||
|
||||
@@ -665,6 +665,32 @@ Feature: /forms/pdfengines/merge
|
||||
| embeds | testdata/embed_1.xml | file |
|
||||
Then the response status code should be 200
|
||||
|
||||
Scenario: POST /forms/pdfengines/merge (stampSource=pdf without uploaded stamp file => 400)
|
||||
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 |
|
||||
| stampSource | pdf | field |
|
||||
| stampExpression | /etc/hostname | field |
|
||||
Then the response status code should be 400
|
||||
Then the response body should match string:
|
||||
"""
|
||||
Invalid form data: a stamp file is required for image or pdf source
|
||||
"""
|
||||
|
||||
Scenario: POST /forms/pdfengines/merge (watermarkSource=pdf without uploaded watermark file => 400)
|
||||
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 |
|
||||
| watermarkSource | pdf | field |
|
||||
| watermarkExpression | /etc/hostname | field |
|
||||
Then the response status code should be 400
|
||||
Then the response body should match string:
|
||||
"""
|
||||
Invalid form data: a watermark file is required for image or pdf source
|
||||
"""
|
||||
|
||||
# See: https://github.com/gotenberg/gotenberg/issues/1500.
|
||||
Scenario: POST /forms/pdfengines/merge (Long Filename)
|
||||
Given I have a default Gotenberg container
|
||||
|
||||
@@ -767,6 +767,34 @@ Feature: /forms/pdfengines/split
|
||||
| embeds | testdata/embed_1.xml | file |
|
||||
Then the response status code should be 200
|
||||
|
||||
Scenario: POST /forms/pdfengines/split (stampSource=pdf without uploaded stamp file => 400)
|
||||
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 |
|
||||
| stampSource | pdf | field |
|
||||
| stampExpression | /etc/hostname | field |
|
||||
Then the response status code should be 400
|
||||
Then the response body should match string:
|
||||
"""
|
||||
Invalid form data: a stamp file is required for image or pdf source
|
||||
"""
|
||||
|
||||
Scenario: POST /forms/pdfengines/split (watermarkSource=pdf without uploaded watermark file => 400)
|
||||
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 |
|
||||
| watermarkSource | pdf | field |
|
||||
| watermarkExpression | /etc/hostname | field |
|
||||
Then the response status code should be 400
|
||||
Then the response body should match string:
|
||||
"""
|
||||
Invalid form data: a watermark file is required for image or pdf source
|
||||
"""
|
||||
|
||||
# See: https://github.com/gotenberg/gotenberg/issues/1500.
|
||||
Scenario: POST /forms/pdfengines/split (Long Filename)
|
||||
Given I have a default Gotenberg container
|
||||
|
||||
Reference in New Issue
Block a user