diff --git a/encode.go b/encode.go index 371c364..20aace3 100644 --- a/encode.go +++ b/encode.go @@ -35,18 +35,22 @@ type BOMEncoder interface { // SetPretty toggles prettified output. SetPretty(pretty bool) BOMEncoder + + // SetEscapeHTML toggles escaped HTML output. + SetEscapeHTML(escapeHTML bool) BOMEncoder } func NewBOMEncoder(writer io.Writer, format BOMFileFormat) BOMEncoder { if format == BOMFileFormatJSON { - return &jsonBOMEncoder{writer: writer} + return &jsonBOMEncoder{writer: writer, escapeHTML: true} } return &xmlBOMEncoder{writer: writer} } type jsonBOMEncoder struct { - writer io.Writer - pretty bool + writer io.Writer + pretty bool + escapeHTML bool } // Encode implements the BOMEncoder interface. @@ -56,6 +60,7 @@ func (j jsonBOMEncoder) Encode(bom *BOM) error { } encoder := json.NewEncoder(j.writer) + encoder.SetEscapeHTML(j.escapeHTML) if j.pretty { encoder.SetIndent("", " ") } @@ -79,6 +84,12 @@ func (j *jsonBOMEncoder) SetPretty(pretty bool) BOMEncoder { return j } +// SetEscapeHTML implements the BOMEncoder interface. +func (j *jsonBOMEncoder) SetEscapeHTML(escapeHTML bool) BOMEncoder { + j.escapeHTML = escapeHTML + return j +} + type xmlBOMEncoder struct { writer io.Writer pretty bool @@ -113,3 +124,9 @@ func (x *xmlBOMEncoder) SetPretty(pretty bool) BOMEncoder { x.pretty = pretty return x } + +// SetEscapeHTML implements the BOMEncoder interface. +func (j *xmlBOMEncoder) SetEscapeHTML(escapeHTML bool) BOMEncoder { + // NOOP -- XML always needs to escape HTML + return j +} diff --git a/encode_test.go b/encode_test.go index f4546d4..89c6da2 100644 --- a/encode_test.go +++ b/encode_test.go @@ -65,6 +65,70 @@ func TestJsonBOMEncoder_SetPretty(t *testing.T) { `, buf.String()) } +func TestJsonBOMEncoder_SetEscapeHTML_true(t *testing.T) { + buf := new(bytes.Buffer) + encoder := NewBOMEncoder(buf, BOMFileFormatJSON) + encoder.SetPretty(true) + encoder.SetEscapeHTML(true) + + bom := NewBOM() + bom.Metadata = &Metadata{ + Authors: &[]OrganizationalContact{ + { + Name: "some&<\"Name", + }, + }, + } + + require.NoError(t, encoder.Encode(bom)) + + assert.Equal(t, `{ + "bomFormat": "CycloneDX", + "specVersion": "1.4", + "version": 1, + "metadata": { + "authors": [ + { + "name": "some\u0026\u003c\"Name" + } + ] + } +} +`, buf.String()) +} + +func TestJsonBOMEncoder_SetEscapeHTML_false(t *testing.T) { + buf := new(bytes.Buffer) + encoder := NewBOMEncoder(buf, BOMFileFormatJSON) + encoder.SetPretty(true) + encoder.SetEscapeHTML(false) + + bom := NewBOM() + bom.Metadata = &Metadata{ + Authors: &[]OrganizationalContact{ + { + Name: "some+<&\"Name", + }, + }, + } + + require.NoError(t, encoder.Encode(bom)) + + assert.Equal(t, `{ + "bomFormat": "CycloneDX", + "specVersion": "1.4", + "version": 1, + "metadata": { + "authors": [ + { + "name": "some+<&\"Name" + } + ] + } +} +`, buf.String()) +} + func TestXmlBOMEncoder_SetPretty(t *testing.T) { buf := new(bytes.Buffer) encoder := NewBOMEncoder(buf, BOMFileFormatXML)