From ef8a72f3de8b76663100c935b15abd972268488a Mon Sep 17 00:00:00 2001 From: Mitchell Scott Date: Wed, 26 Aug 2026 10:07:49 -0600 Subject: [PATCH] fix: escape source URL in generated EPUB --- internal/converter/epub.go | 12 ++++++-- internal/converter/epub_test.go | 51 +++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 3 deletions(-) create mode 100644 internal/converter/epub_test.go diff --git a/internal/converter/epub.go b/internal/converter/epub.go index 8a203766..bf929f9f 100644 --- a/internal/converter/epub.go +++ b/internal/converter/epub.go @@ -5,6 +5,7 @@ package converter import ( "crypto/md5" "fmt" + "html" "net/url" "os" "path/filepath" @@ -123,9 +124,7 @@ func ConvertHTMLToEPUB(htmlContent string, outputPath string, options EPUBOption // Prepend source URL if provided if options.SourceURL != "" { - sourceHeader := fmt.Sprintf(`

Source: %s

`, - options.SourceURL, options.SourceURL) - processedHTML = sourceHeader + processedHTML + processedHTML = sourceHeaderHTML(options.SourceURL) + processedHTML } // Add the main content section @@ -144,6 +143,13 @@ func ConvertHTMLToEPUB(htmlContent string, outputPath string, options EPUBOption return nil } +// sourceHeaderHTML renders the attribution line linking back to the source. +func sourceHeaderHTML(sourceURL string) string { + escaped := html.EscapeString(sourceURL) + return fmt.Sprintf(`

Source: %s

`, + escaped, escaped) +} + // ConvertHTMLFileToEPUB reads an HTML file and converts it to EPUB. func ConvertHTMLFileToEPUB(htmlPath string, options EPUBOptions) (string, error) { logging.Logf("[EPUB] ConvertHTMLFileToEPUB: processing %s", htmlPath) diff --git a/internal/converter/epub_test.go b/internal/converter/epub_test.go new file mode 100644 index 00000000..48d9de00 --- /dev/null +++ b/internal/converter/epub_test.go @@ -0,0 +1,51 @@ +package converter + +import ( + "strings" + "testing" +) + +func TestSourceHeaderHTMLEscapesURL(t *testing.T) { + tests := []struct { + name string + sourceURL string + unwanted string + }{ + { + name: "quote closing the href attribute", + sourceURL: `https://example.com/x">`, + unwanted: "