2
2
mirror of https://github.com/octoleo/restic.git synced 2024-11-25 22:27:35 +00:00

internal/restic: Fix ID.UnmarshalJSON, ParseID

ID.UnmarshalJSON accepted non-JSON input with ' as the string delimiter.
Also, the error message for non-hex input was less informative than it
could be and it performed too many checks.

Changed ParseID to keep the error messages consistent.
This commit is contained in:
greatroar 2022-10-15 14:12:45 +02:00
parent 0e155fd9a6
commit d03460010f

View File

@ -6,8 +6,6 @@ import (
"fmt" "fmt"
"io" "io"
"github.com/restic/restic/internal/errors"
"github.com/minio/sha256-simd" "github.com/minio/sha256-simd"
) )
@ -24,14 +22,13 @@ type ID [idSize]byte
// ParseID converts the given string to an ID. // ParseID converts the given string to an ID.
func ParseID(s string) (ID, error) { func ParseID(s string) (ID, error) {
b, err := hex.DecodeString(s) if len(s) != hex.EncodedLen(idSize) {
return ID{}, fmt.Errorf("invalid length for ID: %q", s)
if err != nil {
return ID{}, errors.Wrap(err, "hex.DecodeString")
} }
if len(b) != idSize { b, err := hex.DecodeString(s)
return ID{}, errors.New("invalid length for hash") if err != nil {
return ID{}, fmt.Errorf("invalid ID: %s", err)
} }
id := ID{} id := ID{}
@ -96,34 +93,21 @@ func (id ID) MarshalJSON() ([]byte, error) {
// UnmarshalJSON parses the JSON-encoded data and stores the result in id. // UnmarshalJSON parses the JSON-encoded data and stores the result in id.
func (id *ID) UnmarshalJSON(b []byte) error { func (id *ID) UnmarshalJSON(b []byte) error {
// check string length // check string length
if len(b) < 2 { if len(b) != len(`""`)+hex.EncodedLen(idSize) {
return fmt.Errorf("invalid ID: %q", b) return fmt.Errorf("invalid length for ID: %q", b)
} }
if len(b)%2 != 0 { if b[0] != '"' {
return fmt.Errorf("invalid ID length: %q", b)
}
// check string delimiters
if b[0] != '"' && b[0] != '\'' {
return fmt.Errorf("invalid start of string: %q", b[0]) return fmt.Errorf("invalid start of string: %q", b[0])
} }
last := len(b) - 1 // Strip JSON string delimiters. The json.Unmarshaler contract says we get
if b[0] != b[last] { // a valid JSON value, so we don't need to check that b[len(b)-1] == '"'.
return fmt.Errorf("starting string delimiter (%q) does not match end (%q)", b[0], b[last]) b = b[1 : len(b)-1]
}
// strip JSON string delimiters
b = b[1:last]
if len(b) != 2*len(id) {
return fmt.Errorf("invalid length for ID")
}
_, err := hex.Decode(id[:], b) _, err := hex.Decode(id[:], b)
if err != nil { if err != nil {
return errors.Wrap(err, "hex.Decode") return fmt.Errorf("invalid ID: %s", err)
} }
return nil return nil