From d3871cf4d04e8a1b08e64604984233852cee2c0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Wernst=C3=A5l?= Date: Sat, 28 Mar 2020 17:18:18 +0100 Subject: [PATCH] fix: too short JSON string or invalid should result in error instead of panic --- marshal.go | 16 +++++++++++++++- marshal_test.go | 44 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/marshal.go b/marshal.go index 25e052b..7497a0b 100644 --- a/marshal.go +++ b/marshal.go @@ -4,6 +4,14 @@ import ( "bytes" ) +// ErrNotJSONString occurs when attempting to parse an UUID from a JSON string +// which is too short or is missing quotes. +type ErrNotJSONString struct{} + +func (e ErrNotJSONString) Error() string { + return "invalid UUID: invalid JSON string" +} + var nullByteString = []byte("null") // MarshalText returns the string-representation of the UUID as a byte-array. @@ -80,7 +88,13 @@ func (u *UUID) UnmarshalText(data []byte) error { // UnmarshalJSON reads an UUID from a JSON-string into the UUID instance. // If this fails the state of the UUID is undetermined. func (u *UUID) UnmarshalJSON(data []byte) error { - return u.ReadBytes(data[1 : len(data)-1]) + l := len(data) + + if l < 2 || data[0] != '"' || data[l-1] != '"' { + return &ErrNotJSONString{} + } + + return u.ReadBytes(data[1 : l-1]) } // MarshalJSON marshals a potentially null UUID into either a string- diff --git a/marshal_test.go b/marshal_test.go index 67df589..914686f 100644 --- a/marshal_test.go +++ b/marshal_test.go @@ -108,6 +108,50 @@ func TestUUIDUnmarshalJSON(t *testing.T) { } } +func TestUUIDUnmarshalJSONShortError(t *testing.T) { + list := [][]byte{ + []byte(""), + []byte("\""), + []byte("'"), + []byte("a"), + []byte("\"'"), + []byte("\"a"), + } + + for _, i := range list { + u := UUID{} + + if err := u.UnmarshalJSON([]byte("")); err != nil { + if err.Error() != (&ErrNotJSONString{}).Error() { + t.Errorf("Expected ErrNotJSONString, got %s for %s", err.Error(), i) + } + } else { + t.Errorf("%s resulted in successful parse", i) + } + + if !u.IsZero() { + t.Errorf("Modified UUID with invalid JSON string for %s", i) + } + } +} + +func TestUUIDUnmarshalJSONShort(t *testing.T) { + u := UUID{} + + if err := u.UnmarshalJSON([]byte("\"\"")); err != nil { + fmt.Print(err.Error()) + if err.Error() != (&ErrTooShort{0, 0, 0}).Error() { + t.Errorf("Expected ErrNotJSONString, got %s", err.Error()) + } + } else { + t.Error("Empty string resulted in successful parse") + } + + if !u.IsZero() { + t.Error("Modified UUID with invalid JSON string") + } +} + func BenchmarkUnmarshalText(b *testing.B) { u := UUID{}