Skip to content

Commit

Permalink
fix: let decode look for additional base32 padding
Browse files Browse the repository at this point in the history
Update FromString and XID.TextUnmarshal so that it looks for discarded
bits in the final source character. This fixes an issue where XIDs that
have been manually tampered with in a way that's ignored by base32
decode, will not pass as valid.
  • Loading branch information
smyrman committed Mar 10, 2022
1 parent f288272 commit a8755d3
Showing 1 changed file with 15 additions and 3 deletions.
18 changes: 15 additions & 3 deletions id.go
Expand Up @@ -238,7 +238,9 @@ func (id *ID) UnmarshalText(text []byte) error {
return ErrInvalidID
}
}
decode(id, text)
if !decode(id, text) {
return ErrInvalidID
}
return nil
}

Expand All @@ -256,8 +258,8 @@ func (id *ID) UnmarshalJSON(b []byte) error {
return id.UnmarshalText(b[1 : len(b)-1])
}

// decode by unrolling the stdlib base32 algorithm + removing all safe checks
func decode(id *ID, src []byte) {
// decode by unrolling the stdlib base32 algorithm + customized safe check.
func decode(id *ID, src []byte) bool {
_ = src[19]
_ = id[11]

Expand All @@ -273,6 +275,16 @@ func decode(id *ID, src []byte) {
id[2] = dec[src[3]]<<4 | dec[src[4]]>>1
id[1] = dec[src[1]]<<6 | dec[src[2]]<<1 | dec[src[3]]>>4
id[0] = dec[src[0]]<<3 | dec[src[1]]>>2

// Validate that there are no discarer bits (padding) in src that would
// cause the string-encoded id not to equal src.
var check [4]byte

check[3] = encoding[(id[11]<<4)&0x1F]
check[2] = encoding[(id[11]>>1)&0x1F]
check[1] = encoding[(id[11]>>6)&0x1F|(id[10]<<2)&0x1F]
check[0] = encoding[id[10]>>3]
return bytes.Equal([]byte(src[16:20]), check[:])
}

// Time returns the timestamp part of the id.
Expand Down

0 comments on commit a8755d3

Please sign in to comment.