Skip to content

Commit

Permalink
Fix issue 25 (segmentio#26)
Browse files Browse the repository at this point in the history
* fix panic on parsing invalid KSUID representations

* more tests

* cleanup
  • Loading branch information
achille-roussel authored Nov 24, 2017
1 parent 40772cb commit 112f929
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 2 deletions.
13 changes: 12 additions & 1 deletion base62.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package ksuid

import "errors"

const (
// lexographic ordering (based on Unicode table) is 0-9A-Za-z
base62Characters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
Expand All @@ -8,6 +10,10 @@ const (
offsetLowercase = 36
)

var (
errShortBuffer = errors.New("the output buffer is too small to hold to decoded value")
)

// Converts a base 62 byte into the number value that it represents.
func base62Value(digit byte) byte {
switch {
Expand Down Expand Up @@ -102,7 +108,7 @@ func fastAppendEncodeBase62(dst []byte, src []byte) []byte {
// is 27 bytes long and dst is 20 bytes long.
//
// Any unused bytes in dst will be set to zero.
func fastDecodeBase62(dst []byte, src []byte) {
func fastDecodeBase62(dst []byte, src []byte) error {
const srcBase = 62
const dstBase = 4294967296

Expand Down Expand Up @@ -156,6 +162,10 @@ func fastDecodeBase62(dst []byte, src []byte) {
}
}

if n < 4 {
return errShortBuffer
}

dst[n-4] = byte(remainder >> 24)
dst[n-3] = byte(remainder >> 16)
dst[n-2] = byte(remainder >> 8)
Expand All @@ -166,6 +176,7 @@ func fastDecodeBase62(dst []byte, src []byte) {

var zero [20]byte
copy(dst[:n], zero[:])
return nil
}

// This function appends the base 62 decoded version of src into dst.
Expand Down
10 changes: 9 additions & 1 deletion ksuid.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ const (
// The length of a KSUID when string (base62) encoded
stringEncodedLength = 27

// A string-encoded minimum value for a KSUID
minStringEncoded = "000000000000000000000000000"

// A string-encoded maximum value for a KSUID
maxStringEncoded = "aWgEPTl1tmebfsQzFP4bxwgy80V"
)
Expand All @@ -46,6 +49,7 @@ var (

errSize = fmt.Errorf("Valid KSUIDs are %v bytes", byteLength)
errStrSize = fmt.Errorf("Valid encoded KSUIDs are %v characters", stringEncodedLength)
errStrValue = fmt.Errorf("Valid encoded KSUIDs are bounded by %s and %s", minStringEncoded, maxStringEncoded)
errPayloadSize = fmt.Errorf("Valid KSUID payloads are %v bytes", payloadLengthInBytes)

// Represents a completely empty (invalid) KSUID
Expand Down Expand Up @@ -179,7 +183,11 @@ func Parse(s string) (KSUID, error) {
dst := [byteLength]byte{}

copy(src[:], s[:])
fastDecodeBase62(dst[:], src[:])

if err := fastDecodeBase62(dst[:], src[:]); err != nil {
return Nil, errStrValue
}

return FromBytes(dst[:])
}

Expand Down
13 changes: 13 additions & 0 deletions ksuid_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,19 @@ func TestParse(t *testing.T) {
}
}

func TestIssue25(t *testing.T) {
// https://github.com/segmentio/ksuid/issues/25
for _, s := range []string{
"aaaaaaaaaaaaaaaaaaaaaaaaaaa",
"aWgEPTl1tmebfsQzFP4bxwgy80!",
} {
_, err := Parse(s)
if err != errStrValue {
t.Error("invalid KSUID representations cannot be successfully parsed, got err =", err)
}
}
}

func TestEncodeAndDecode(t *testing.T) {
x := New()
builtFromEncodedString, err := Parse(x.String())
Expand Down

0 comments on commit 112f929

Please sign in to comment.