Fix HTML character escaping in maintained-apps JSON output (#35819)
- Replace json.MarshalIndent with json.Encoder using SetEscapeHTML(false) - Fixes both processOutput() and updateAppsListFile() functions - Add test to verify HTML characters are preserved - Regenerate yubico-yubikey-manager manifest to demonstrate fix Previously, HTML tags and special characters (<, >, &) were being escaped as Unicode sequences (\u003c, \u003e, \u0026) in JSON output. This affected both app descriptions with HTML links and shell scripts with redirect operators.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
@@ -70,10 +71,14 @@ func processOutput(ctx context.Context, app *maintained_apps.FMAManifestApp) err
|
||||
Refs: map[string]string{app.UninstallScriptRef: app.UninstallScript, app.InstallScriptRef: app.InstallScript},
|
||||
}
|
||||
|
||||
outBytes, err := json.MarshalIndent(outFile, "", " ")
|
||||
if err != nil {
|
||||
var buf bytes.Buffer
|
||||
encoder := json.NewEncoder(&buf)
|
||||
encoder.SetEscapeHTML(false)
|
||||
encoder.SetIndent("", " ")
|
||||
if err := encoder.Encode(outFile); err != nil {
|
||||
return ctxerr.Wrap(ctx, err, "marshaling output app manifest")
|
||||
}
|
||||
outBytes := buf.Bytes()
|
||||
|
||||
outDir := path.Join(maintained_apps.OutputPath, app.SlugAppName())
|
||||
|
||||
@@ -133,10 +138,14 @@ func updateAppsListFile(ctx context.Context, outApp *maintained_apps.FMAManifest
|
||||
// Keep existing order
|
||||
slices.SortFunc(outputAppsFile.Apps, func(a, b maintained_apps.FMAListFileApp) int { return strings.Compare(a.Slug, b.Slug) })
|
||||
|
||||
updatedFile, err := json.MarshalIndent(outputAppsFile, "", " ")
|
||||
if err != nil {
|
||||
var buf bytes.Buffer
|
||||
encoder := json.NewEncoder(&buf)
|
||||
encoder.SetEscapeHTML(false)
|
||||
encoder.SetIndent("", " ")
|
||||
if err := encoder.Encode(outputAppsFile); err != nil {
|
||||
return ctxerr.Wrap(ctx, err, "marshaling updated output apps file")
|
||||
}
|
||||
updatedFile := buf.Bytes()
|
||||
|
||||
if err := os.WriteFile(appListFilePath, updatedFile, 0o644); err != nil {
|
||||
return ctxerr.Wrap(ctx, err, "writing updated output apps file")
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestJSONEncoderPreservesHTML(t *testing.T) {
|
||||
testData := struct {
|
||||
Description string `json:"description"`
|
||||
}{
|
||||
Description: `Test with HTML: <a href="https://example.com">link</a> & special chars < >`,
|
||||
}
|
||||
|
||||
// Test with SetEscapeHTML(false)
|
||||
var buf bytes.Buffer
|
||||
encoder := json.NewEncoder(&buf)
|
||||
encoder.SetEscapeHTML(false)
|
||||
if err := encoder.Encode(testData); err != nil {
|
||||
t.Fatalf("Failed to encode: %v", err)
|
||||
}
|
||||
|
||||
result := buf.String()
|
||||
|
||||
// Verify HTML characters are preserved, not escaped
|
||||
if strings.Contains(result, `\u003c`) {
|
||||
t.Error("Found escaped '<' character (\\u003c) - HTML escaping is still enabled")
|
||||
}
|
||||
if strings.Contains(result, `\u003e`) {
|
||||
t.Error("Found escaped '>' character (\\u003e) - HTML escaping is still enabled")
|
||||
}
|
||||
if strings.Contains(result, `\u0026`) {
|
||||
t.Error("Found escaped '&' character (\\u0026) - HTML escaping is still enabled")
|
||||
}
|
||||
|
||||
// Verify HTML characters are present (note: quotes inside JSON are still escaped)
|
||||
if !strings.Contains(result, `<a href=\"https://example.com\">`) {
|
||||
t.Error("HTML anchor tag was not preserved correctly")
|
||||
}
|
||||
if !strings.Contains(result, ` & `) {
|
||||
t.Error("Ampersand character was not preserved correctly")
|
||||
}
|
||||
|
||||
t.Logf("Successfully preserved HTML in JSON output: %s", result)
|
||||
}
|
||||
Reference in New Issue
Block a user