forked from mirror/jwt
Fixed integer overflow in NumericDate.MarshalJSON (#200)
This commit is contained in:
parent
8fb42696ff
commit
2da0bf7566
18
types.go
18
types.go
|
@ -53,9 +53,23 @@ func (date NumericDate) MarshalJSON() (b []byte, err error) {
|
||||||
if TimePrecision < time.Second {
|
if TimePrecision < time.Second {
|
||||||
prec = int(math.Log10(float64(time.Second) / float64(TimePrecision)))
|
prec = int(math.Log10(float64(time.Second) / float64(TimePrecision)))
|
||||||
}
|
}
|
||||||
f := float64(date.Truncate(TimePrecision).UnixNano()) / float64(time.Second)
|
truncatedDate := date.Truncate(TimePrecision)
|
||||||
|
|
||||||
return []byte(strconv.FormatFloat(f, 'f', prec, 64)), nil
|
// For very large timestamps, UnixNano would overflow an int64, but this
|
||||||
|
// function requires nanosecond level precision, so we have to use the
|
||||||
|
// following technique to get round the issue:
|
||||||
|
// 1. Take the normal unix timestamp to form the whole number part of the
|
||||||
|
// output,
|
||||||
|
// 2. Take the result of the Nanosecond function, which retuns the offset
|
||||||
|
// within the second of the particular unix time instance, to form the
|
||||||
|
// decimal part of the output
|
||||||
|
// 3. Concatenate them to produce the final result
|
||||||
|
seconds := strconv.FormatInt(truncatedDate.Unix(), 10)
|
||||||
|
nanosecondsOffset := strconv.FormatFloat(float64(truncatedDate.Nanosecond())/float64(time.Second), 'f', prec, 64)
|
||||||
|
|
||||||
|
output := append([]byte(seconds), []byte(nanosecondsOffset)[1:]...)
|
||||||
|
|
||||||
|
return output, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalJSON is an implementation of the json.RawMessage interface and deserializses a
|
// UnmarshalJSON is an implementation of the json.RawMessage interface and deserializses a
|
||||||
|
|
|
@ -2,6 +2,7 @@ package jwt_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"math"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -79,23 +80,38 @@ func TestNumericDate_MarshalJSON(t *testing.T) {
|
||||||
}{
|
}{
|
||||||
{time.Unix(5243700879, 0), "5243700879", time.Second},
|
{time.Unix(5243700879, 0), "5243700879", time.Second},
|
||||||
{time.Unix(5243700879, 0), "5243700879.000", time.Millisecond},
|
{time.Unix(5243700879, 0), "5243700879.000", time.Millisecond},
|
||||||
{time.Unix(5243700879, 0), "5243700879.000001", time.Microsecond},
|
{time.Unix(5243700879, 0), "5243700879.000000", time.Microsecond},
|
||||||
{time.Unix(5243700879, 0), "5243700879.000000954", time.Nanosecond},
|
{time.Unix(5243700879, 0), "5243700879.000000000", time.Nanosecond},
|
||||||
//
|
//
|
||||||
{time.Unix(4239425898, 0), "4239425898", time.Second},
|
{time.Unix(4239425898, 0), "4239425898", time.Second},
|
||||||
{time.Unix(4239425898, 0), "4239425898.000", time.Millisecond},
|
{time.Unix(4239425898, 0), "4239425898.000", time.Millisecond},
|
||||||
{time.Unix(4239425898, 0), "4239425898.000000", time.Microsecond},
|
{time.Unix(4239425898, 0), "4239425898.000000", time.Microsecond},
|
||||||
{time.Unix(4239425898, 0), "4239425898.000000000", time.Nanosecond},
|
{time.Unix(4239425898, 0), "4239425898.000000000", time.Nanosecond},
|
||||||
//
|
//
|
||||||
|
{time.Unix(253402271999, 0), "253402271999", time.Second},
|
||||||
|
{time.Unix(253402271999, 0), "253402271999.000", time.Millisecond},
|
||||||
|
{time.Unix(253402271999, 0), "253402271999.000000", time.Microsecond},
|
||||||
|
{time.Unix(253402271999, 0), "253402271999.000000000", time.Nanosecond},
|
||||||
|
//
|
||||||
{time.Unix(0, 1644285000210402000), "1644285000", time.Second},
|
{time.Unix(0, 1644285000210402000), "1644285000", time.Second},
|
||||||
{time.Unix(0, 1644285000210402000), "1644285000.210", time.Millisecond},
|
{time.Unix(0, 1644285000210402000), "1644285000.210", time.Millisecond},
|
||||||
{time.Unix(0, 1644285000210402000), "1644285000.210402", time.Microsecond},
|
{time.Unix(0, 1644285000210402000), "1644285000.210402", time.Microsecond},
|
||||||
{time.Unix(0, 1644285000210402000), "1644285000.210402012", time.Nanosecond},
|
{time.Unix(0, 1644285000210402000), "1644285000.210402000", time.Nanosecond},
|
||||||
//
|
//
|
||||||
{time.Unix(0, 1644285315063096000), "1644285315", time.Second},
|
{time.Unix(0, 1644285315063096000), "1644285315", time.Second},
|
||||||
{time.Unix(0, 1644285315063096000), "1644285315.063", time.Millisecond},
|
{time.Unix(0, 1644285315063096000), "1644285315.063", time.Millisecond},
|
||||||
{time.Unix(0, 1644285315063096000), "1644285315.063096", time.Microsecond},
|
{time.Unix(0, 1644285315063096000), "1644285315.063096", time.Microsecond},
|
||||||
{time.Unix(0, 1644285315063096000), "1644285315.063096046", time.Nanosecond},
|
{time.Unix(0, 1644285315063096000), "1644285315.063096000", time.Nanosecond},
|
||||||
|
// Maximum time that a go time.Time can represent
|
||||||
|
{time.Unix(math.MaxInt64, 999999999), "9223372036854775807", time.Second},
|
||||||
|
{time.Unix(math.MaxInt64, 999999999), "9223372036854775807.999", time.Millisecond},
|
||||||
|
{time.Unix(math.MaxInt64, 999999999), "9223372036854775807.999999", time.Microsecond},
|
||||||
|
{time.Unix(math.MaxInt64, 999999999), "9223372036854775807.999999999", time.Nanosecond},
|
||||||
|
// Strange precisions
|
||||||
|
{time.Unix(math.MaxInt64, 999999999), "9223372036854775807", time.Second},
|
||||||
|
{time.Unix(math.MaxInt64, 999999999), "9223372036854775756", time.Minute},
|
||||||
|
{time.Unix(math.MaxInt64, 999999999), "9223372036854774016", time.Hour},
|
||||||
|
{time.Unix(math.MaxInt64, 999999999), "9223372036854745216", 24 * time.Hour},
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, tc := range tt {
|
for i, tc := range tt {
|
||||||
|
|
Loading…
Reference in New Issue