diff --git a/pkg/event/factory.go b/pkg/event/factory.go index 598720aa..75a4b1f9 100644 --- a/pkg/event/factory.go +++ b/pkg/event/factory.go @@ -19,6 +19,9 @@ package event import ( "errors" + "fmt" + "math" + "reflect" "strings" "time" @@ -292,22 +295,76 @@ func getTagValue(eventTags map[string]interface{}) (float64, error) { return 0, errors.New("no event tag found for value") } +// Validates if the type of provided value is numeric. +func isNumericType(value interface{}) (float64, error) { + switch i := value.(type) { + case int: + return float64(i), nil + case int8: + return float64(i), nil + case int16: + return float64(i), nil + case int32: + return float64(i), nil + case int64: + return float64(i), nil + case uint: + return float64(i), nil + case uint8: + return float64(i), nil + case uint16: + return float64(i), nil + case uint32: + return float64(i), nil + case uint64: + return float64(i), nil + case uintptr: + return float64(i), nil + case float32: + return float64(i), nil + case float64: + return i, nil + default: + v := reflect.ValueOf(value) + v = reflect.Indirect(v) + return math.NaN(), fmt.Errorf("can't convert %v to float64", v.Type()) + } +} + +// Validates if the provided value is a valid numeric value. +func isValidNumericValue(value interface{}) bool { + if floatValue, err := isNumericType(value); err == nil { + if math.IsNaN(floatValue) { + return false + } + if math.IsInf(floatValue, 1) { + return false + } + if math.IsInf(floatValue, -1) { + return false + } + if math.IsInf(floatValue, 0) { + return false + } + if math.Abs(floatValue) > math.Pow(2, 53) { + return false + } + return true + } + return false +} + // check if attribute value is valid func isValidAttribute(value interface{}) bool { if value == nil { return false } - if _, ok := value.(string); ok { - return true - } - if _, ok := value.(float64); ok { - return true - } - if _, ok := value.(int); ok { - return true - } - if _, ok := value.(bool); ok { + + switch value.(type) { + // https://go.dev/tour/basics/11 + case bool, string: return true + default: + return isValidNumericValue(value) } - return false } diff --git a/pkg/event/factory_test.go b/pkg/event/factory_test.go index 929a4ec5..2ccc6079 100644 --- a/pkg/event/factory_test.go +++ b/pkg/event/factory_test.go @@ -19,6 +19,7 @@ package event import ( "context" + "math" "math/rand" "testing" "time" @@ -241,8 +242,36 @@ func TestIsValidAttribute(t *testing.T) { assert.False(t, isValidAttribute([]string{})) assert.False(t, isValidAttribute([]interface{}{})) assert.False(t, isValidAttribute(make(chan int))) - assert.True(t, isValidAttribute("123")) - assert.True(t, isValidAttribute(1.11)) - assert.True(t, isValidAttribute(1)) - assert.True(t, isValidAttribute(true)) + assert.False(t, isValidAttribute(complex64(1234.1231))) + assert.False(t, isValidAttribute(complex128(123446.123123))) + assert.False(t, isValidAttribute(math.Pow(2, 54))) + + assert.False(t, isValidAttribute(math.NaN())) + posInf := math.Inf(1) + assert.False(t, isValidAttribute(posInf)) + posInf += 12.2 // infinite value will still propagate after add operation + assert.False(t, isValidAttribute(posInf)) + negInf := math.Inf(-1) + assert.False(t, isValidAttribute(negInf)) + negInf /= negInf // will turn infinite into NaN + assert.False(t, isValidAttribute(negInf)) + assert.False(t, isValidAttribute(math.Inf(0))) + + assert.True(t, isValidAttribute(bool(true))) + assert.True(t, isValidAttribute(string("abcd"))) + assert.True(t, isValidAttribute(int(1))) + assert.True(t, isValidAttribute(int8(-12))) + assert.True(t, isValidAttribute(int16(-123))) + assert.True(t, isValidAttribute(int32(1234))) + assert.True(t, isValidAttribute(int64(123446))) + assert.True(t, isValidAttribute(uint(1))) + assert.True(t, isValidAttribute(uint8(12))) + assert.True(t, isValidAttribute(uint16(123))) + assert.True(t, isValidAttribute(uint32(1234))) + assert.True(t, isValidAttribute(uint64(123446))) + assert.True(t, isValidAttribute(uintptr(1))) + assert.True(t, isValidAttribute(float32(12.11))) + assert.True(t, isValidAttribute(float64(123.1231))) + assert.True(t, isValidAttribute(byte(134))) + assert.True(t, isValidAttribute(rune(123446))) }